diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a682c63..36814852 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ set(CMAKE_CXX_EXTENSIONS Off) add_definitions( -DLINUX + -DRETRODEBUGGER -DIMGUI_IMPL_OPENGL_LOADER_GL3W -DENABLE_IMGUI_TEST_ENGINE ) diff --git a/assets/template/reset_basic.snap b/assets/template/reset_basic.snap index be41d283..f8cd0f42 100644 Binary files a/assets/template/reset_basic.snap and b/assets/template/reset_basic.snap differ diff --git a/assets/template/reset_basic.snap.zlib b/assets/template/reset_basic.snap.zlib index b9897f5a..a2b2ffe8 100644 Binary files a/assets/template/reset_basic.snap.zlib and b/assets/template/reset_basic.snap.zlib differ diff --git a/assets/template/reset_basic_snap_zlib.h b/assets/template/reset_basic_snap_zlib.h index 29dae9de..73292487 100644 --- a/assets/template/reset_basic_snap_zlib.h +++ b/assets/template/reset_basic_snap_zlib.h @@ -1,434 +1,7416 @@ // Embedded file name: reset_basic.snap.zlib // #include "reset_basic_snap_zlib.h" // RES_AddEmbeddedDataToDeploy("/gfx/reset_basic", DEPLOY_FILE_TYPE_GFX, reset_basic_snap_zlib, reset_basic_snap_zlib_length); -int reset_basic_snap_zlib_length = 6822; -uint8 reset_basic_snap_zlib[6822] = { - 0x5a, 0x4c, 0x00, 0x07, 0x32, 0x77, 0x00, 0x00, 0x1a, 0x9c, 0x78, 0xda, 0xed, 0xdd, 0x7f, 0x6c, - 0x1b, 0xf7, 0x7d, 0xc6, 0xf1, 0x3b, 0xfd, 0xa0, 0x15, 0x27, 0xa6, 0x63, 0xd9, 0x71, 0xaa, 0x0c, - 0x58, 0x55, 0xb7, 0x97, 0x86, 0x46, 0xe8, 0x58, 0x89, 0x4f, 0x09, 0x8d, 0xd1, 0xb5, 0x22, 0x6b, - 0x0e, 0xe5, 0xd0, 0xf6, 0x64, 0x9d, 0x5c, 0x7a, 0x60, 0x90, 0xa1, 0x39, 0x77, 0x74, 0x46, 0x67, - 0x48, 0x46, 0x07, 0x74, 0xd7, 0xd4, 0xcb, 0x8f, 0x6e, 0xc0, 0x56, 0x14, 0xc1, 0x2a, 0x6c, 0x69, - 0x07, 0x4c, 0x40, 0xcb, 0x66, 0xf4, 0xc6, 0x61, 0x59, 0xc0, 0x3f, 0x54, 0x60, 0xc0, 0xfe, 0xeb, - 0xd8, 0x41, 0x5b, 0x03, 0x4c, 0x5b, 0x36, 0x14, 0x43, 0x87, 0x4e, 0x01, 0x92, 0x34, 0x98, 0x7f, - 0x54, 0xc5, 0x32, 0x64, 0xe2, 0x8e, 0x22, 0x25, 0x91, 0x14, 0x29, 0xcb, 0x56, 0xf4, 0x78, 0xa2, - 0xdf, 0x4f, 0x2a, 0xca, 0x92, 0x48, 0x7e, 0xa4, 0xd7, 0x9d, 0x4e, 0xd4, 0xf7, 0x39, 0xaa, 0x63, - 0x91, 0xc1, 0xa1, 0xde, 0x13, 0x67, 0x7f, 0xed, 0x37, 0x9f, 0xfb, 0xf5, 0x67, 0x7e, 0xab, 0xf7, - 0x97, 0x13, 0xbf, 0xe1, 0xde, 0x63, 0x9a, 0x83, 0xfd, 0xfb, 0x4e, 0x0c, 0x1a, 0x4b, 0x19, 0x2b, - 0x5d, 0x69, 0xcc, 0x7d, 0xf6, 0xb9, 0xc4, 0x33, 0x67, 0xef, 0x69, 0x37, 0xcb, 0xef, 0x8c, 0x0e, - 0x44, 0x8e, 0x0e, 0x1e, 0x77, 0x16, 0xaf, 0x64, 0x9a, 0xbf, 0xe2, 0x5d, 0x7e, 0x54, 0x7c, 0xcd, - 0x34, 0xcc, 0x1d, 0x57, 0xa6, 0x66, 0x76, 0x5d, 0xaa, 0x5c, 0xf1, 0x5f, 0xde, 0x7e, 0x6d, 0xfe, - 0x5f, 0xd3, 0xff, 0xfa, 0x9a, 0x69, 0x34, 0xc8, 0xbd, 0x96, 0x61, 0xfc, 0x7d, 0xe1, 0xa5, 0xd2, - 0xd4, 0xe8, 0x50, 0xb4, 0xea, 0x03, 0x66, 0xc0, 0x30, 0x8d, 0x87, 0x1f, 0x30, 0x8c, 0x62, 0xd1, - 0xb8, 0xf8, 0xc6, 0xab, 0x6f, 0xee, 0xda, 0x65, 0x18, 0x8f, 0x1b, 0x45, 0xa3, 0xad, 0xfc, 0xe1, - 0x9e, 0x9d, 0xc6, 0xe6, 0x73, 0xdf, 0x2e, 0xff, 0xfb, 0xae, 0xae, 0x37, 0xff, 0xa6, 0x7c, 0x9b, - 0xae, 0xbb, 0xe7, 0xff, 0x33, 0x26, 0xe6, 0xff, 0x2b, 0x56, 0xee, 0xaa, 0xab, 0x74, 0xf1, 0x99, - 0xf2, 0x2b, 0xef, 0x96, 0x86, 0xd1, 0xfe, 0x78, 0xf5, 0xa7, 0xe0, 0xdd, 0x4f, 0xcf, 0xd2, 0x5b, - 0xe7, 0x8c, 0x0b, 0xdf, 0x7e, 0xe7, 0xfc, 0x0f, 0xdb, 0xde, 0xf9, 0x52, 0xce, 0xe8, 0x2a, 0xec, - 0xff, 0xab, 0xcd, 0x85, 0xde, 0x4b, 0xff, 0xf5, 0xc8, 0xbb, 0x7b, 0x1f, 0x79, 0xf7, 0x87, 0x4f, - 0x5e, 0x38, 0xf6, 0xfd, 0x91, 0xcf, 0x1f, 0xf4, 0xee, 0xf6, 0xe0, 0xfc, 0x5d, 0xb7, 0x1b, 0xc6, - 0x05, 0xef, 0x55, 0xe7, 0x47, 0x07, 0x97, 0x6e, 0xee, 0x0d, 0x37, 0x7e, 0xa9, 0xbd, 0xf4, 0xb9, - 0x18, 0x4f, 0x76, 0x15, 0xff, 0x74, 0xfe, 0x7d, 0x13, 0x66, 0x97, 0x77, 0x8d, 0xdb, 0x6e, 0x37, - 0x0e, 0x1a, 0xdd, 0xbd, 0xa6, 0x71, 0xa9, 0xc3, 0x30, 0x3e, 0xeb, 0xdb, 0x61, 0xbc, 0x5c, 0xce, - 0x2b, 0xf3, 0xf9, 0x6a, 0x39, 0xbf, 0x3b, 0x9f, 0x4b, 0x6f, 0xff, 0xce, 0xfb, 0x0b, 0x77, 0xd8, - 0xfb, 0xd0, 0x23, 0xa1, 0xbe, 0x3e, 0x63, 0xaf, 0x17, 0xe3, 0x86, 0x52, 0x5c, 0x63, 0x8c, 0x35, - 0x66, 0x55, 0x43, 0xbe, 0xfc, 0xde, 0xed, 0xfe, 0xaf, 0x78, 0x97, 0x3b, 0x4c, 0x63, 0xd7, 0x3f, - 0xce, 0x78, 0xfb, 0xd0, 0x7f, 0x3c, 0x95, 0x79, 0xe5, 0x3b, 0xaf, 0xa7, 0xbf, 0xfb, 0x27, 0x3f, - 0xf9, 0xc3, 0x5d, 0xbb, 0x77, 0xdd, 0xff, 0x88, 0x71, 0xbf, 0x71, 0xd3, 0x52, 0xda, 0x9f, 0xfc, - 0x73, 0x1d, 0x9b, 0x8d, 0xf6, 0x2d, 0x86, 0xf1, 0xd8, 0xfb, 0x0d, 0xaf, 0x63, 0xae, 0xdb, 0xf4, - 0xdf, 0xff, 0xc9, 0x4b, 0xdf, 0xf9, 0xed, 0xcc, 0x3d, 0xaf, 0xff, 0xe7, 0xeb, 0x5f, 0xfd, 0xcb, - 0xd2, 0xdb, 0x8f, 0x3f, 0xf6, 0xd7, 0x46, 0xdf, 0x7b, 0xa7, 0xe7, 0x0e, 0xcf, 0x0d, 0x5f, 0x7d, - 0xf5, 0x8a, 0xff, 0xca, 0xf1, 0x2b, 0x0f, 0x5d, 0x3d, 0x79, 0xf9, 0x07, 0x97, 0x3f, 0xf8, 0xf9, - 0x81, 0xcb, 0x0f, 0x5c, 0x3d, 0x3d, 0x97, 0xf9, 0xd9, 0x07, 0xb3, 0x46, 0x0b, 0xa5, 0xf7, 0x3a, - 0xb2, 0xdb, 0x4b, 0x6f, 0xfb, 0xd6, 0x2d, 0x5b, 0xb6, 0x76, 0x6c, 0xed, 0xee, 0xec, 0xed, 0xdf, - 0xd7, 0xdb, 0x66, 0x6e, 0xbf, 0xad, 0xbd, 0x77, 0xe7, 0x83, 0xe5, 0x0f, 0x5d, 0x57, 0xfa, 0xf7, - 0xdd, 0xde, 0xdb, 0x6d, 0x6e, 0xe9, 0xdd, 0xde, 0xb3, 0x7d, 0x47, 0xe7, 0x96, 0xde, 0xf2, 0x37, - 0x62, 0xe5, 0x0e, 0xdb, 0x7a, 0x76, 0x74, 0x6e, 0xef, 0xf5, 0x75, 0x77, 0x76, 0xae, 0xfa, 0xee, - 0xba, 0x3b, 0xcd, 0x8e, 0x9e, 0x3d, 0xd7, 0xbe, 0xde, 0x44, 0x2f, 0x21, 0xb7, 0x5e, 0x6e, 0xea, - 0xcf, 0x9f, 0x9b, 0xfd, 0xf3, 0x8f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, - 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, - 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, - 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, - 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, - 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, - 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, - 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, - 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, - 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, - 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, - 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, - 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, - 0xf3, 0x99, 0x7f, 0xab, 0xcd, 0xdf, 0xed, 0xe0, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, - 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, - 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, - 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, - 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, - 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, - 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, - 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, - 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0xff, 0x26, 0xcd, 0xef, 0x7b, 0xef, 0xf4, 0xdc, 0xe1, 0xb9, 0xe1, - 0xab, 0xaf, 0x5e, 0xf1, 0x5f, 0x39, 0x7e, 0xe5, 0xa1, 0xab, 0x27, 0x2f, 0xff, 0xe0, 0xf2, 0x07, - 0x3f, 0x3f, 0x70, 0xf9, 0x81, 0xab, 0xa7, 0xe7, 0x32, 0x3f, 0xfb, 0x60, 0x16, 0x7f, 0xe6, 0x6f, - 0xa4, 0xf9, 0x0f, 0x3f, 0xfc, 0x40, 0xf5, 0xdd, 0x0d, 0xf6, 0xef, 0x1b, 0x1c, 0x18, 0x19, 0x5d, - 0x7a, 0x87, 0x79, 0xf7, 0xfc, 0xbb, 0x23, 0x03, 0x7d, 0xd5, 0x57, 0x6b, 0x6b, 0x1b, 0xf4, 0x2e, - 0xbf, 0x62, 0x78, 0x9f, 0x7e, 0x4f, 0xb1, 0xa3, 0x74, 0x35, 0xc3, 0x34, 0x6f, 0xb3, 0x0e, 0x7a, - 0xff, 0xbe, 0x50, 0xb9, 0x46, 0xe9, 0x9d, 0x5f, 0xfb, 0xb4, 0x61, 0x7c, 0xa1, 0xeb, 0xbe, 0x6d, - 0x95, 0xbb, 0x78, 0x70, 0xf9, 0x5d, 0x7c, 0xdf, 0xf8, 0x9c, 0x51, 0x61, 0x30, 0x0d, 0xa3, 0xab, - 0xab, 0x9a, 0x64, 0xfe, 0x2e, 0xbe, 0xee, 0xdd, 0xc5, 0x7d, 0xdb, 0xca, 0x77, 0x71, 0x22, 0x72, - 0xa8, 0xe6, 0x6b, 0x37, 0xdb, 0x43, 0xf3, 0xaf, 0x36, 0x5d, 0x0b, 0xc9, 0xbb, 0xe1, 0xd0, 0xe7, - 0x47, 0x87, 0x8e, 0x1e, 0x1a, 0x3a, 0x54, 0xb9, 0xe1, 0x4e, 0xef, 0xf2, 0xd0, 0x48, 0x64, 0x6c, - 0xa8, 0xfa, 0xee, 0x3a, 0xee, 0x30, 0xe7, 0x3f, 0x8d, 0xca, 0x9b, 0xbb, 0xaa, 0xef, 0xe2, 0xcd, - 0xd2, 0xa7, 0xd5, 0xee, 0xbd, 0xf8, 0x7c, 0x86, 0xf1, 0x6f, 0x01, 0xc3, 0x78, 0xf7, 0xf9, 0x37, - 0x16, 0xaf, 0xfb, 0x45, 0xf3, 0xb4, 0x51, 0xf9, 0xf0, 0xc2, 0x4b, 0x09, 0xa5, 0x74, 0x77, 0x9f, - 0xad, 0xba, 0x8f, 0x0a, 0x8d, 0x71, 0xf1, 0x47, 0x8f, 0xfc, 0x43, 0xe9, 0x75, 0x6f, 0x67, 0x7f, - 0x67, 0xcd, 0xd7, 0x63, 0x7e, 0xa6, 0xe6, 0xd3, 0x5e, 0xeb, 0xff, 0x37, 0x43, 0x55, 0xa6, 0xfe, - 0x7c, 0x5f, 0x77, 0xf3, 0x8f, 0x9a, 0x65, 0x8b, 0xc1, 0xe3, 0xce, 0xde, 0xc5, 0x4f, 0xc5, 0xe9, - 0xf2, 0xb6, 0xed, 0xa7, 0x27, 0x4c, 0xc3, 0x5f, 0x1c, 0xda, 0xf1, 0xd3, 0x4f, 0x7d, 0xd7, 0x7b, - 0xe7, 0x47, 0xc5, 0xd7, 0xcc, 0x3f, 0xfb, 0xf7, 0xf2, 0x15, 0x4a, 0x1f, 0xba, 0xb0, 0x7d, 0x62, - 0x5e, 0xe0, 0x7b, 0x95, 0xd7, 0x95, 0x5b, 0x6e, 0x2d, 0xbd, 0xb1, 0xcd, 0xe8, 0x36, 0xbb, 0x8d, - 0xd2, 0xcc, 0xbe, 0xbe, 0xd2, 0xcb, 0x36, 0xa3, 0xb4, 0x09, 0xef, 0x9c, 0xff, 0xc8, 0xc8, 0x58, - 0x3e, 0xf0, 0xf4, 0x37, 0xdf, 0xc9, 0x07, 0x86, 0x3d, 0xa6, 0x8e, 0x2e, 0x6f, 0x2f, 0x2a, 0x1a, - 0x9b, 0xba, 0xdc, 0xd2, 0xde, 0x6c, 0x6e, 0x33, 0x8b, 0x77, 0x79, 0x4e, 0x9b, 0x8c, 0xb0, 0x71, - 0xaa, 0xf3, 0x4e, 0xf3, 0x7b, 0xde, 0x87, 0xbc, 0x0f, 0x6c, 0xde, 0xbc, 0x73, 0xeb, 0x66, 0x2f, - 0x1d, 0x1e, 0x6b, 0xe7, 0xff, 0xfc, 0xdd, 0xae, 0xf7, 0xbd, 0x77, 0x75, 0xbe, 0xe7, 0xdd, 0xca, - 0xbb, 0x8d, 0xbf, 0x34, 0xf4, 0xbe, 0xc7, 0xe6, 0x87, 0x97, 0x66, 0x98, 0xdd, 0x3f, 0xfe, 0x5c, - 0xed, 0x97, 0xd7, 0xd6, 0x59, 0xde, 0x3a, 0x1d, 0x6d, 0x9d, 0x6d, 0xbe, 0xb6, 0x4d, 0x46, 0xdb, - 0x3f, 0xb7, 0x95, 0xf6, 0xb3, 0x4e, 0xdf, 0x4b, 0xe5, 0xef, 0x81, 0x97, 0x4d, 0x73, 0xa5, 0x6f, - 0xae, 0x0a, 0x51, 0x65, 0x8f, 0x2c, 0x6f, 0xc5, 0x17, 0xe7, 0xdf, 0xec, 0x58, 0xfc, 0xa2, 0x7f, - 0xef, 0x82, 0xf7, 0x1d, 0xd0, 0xd6, 0xee, 0x33, 0x8a, 0x03, 0xab, 0xd8, 0x1a, 0x5f, 0xf8, 0x70, - 0xff, 0xec, 0x9d, 0x1f, 0x96, 0x2f, 0x9f, 0xff, 0xf0, 0x85, 0xb9, 0x36, 0xb3, 0xaf, 0xef, 0xad, - 0xbe, 0xb7, 0x52, 0x73, 0x2f, 0xcc, 0x15, 0xdb, 0x8a, 0x9f, 0xda, 0x71, 0xc9, 0xb8, 0x09, 0xf9, - 0x46, 0x26, 0x30, 0x3c, 0xb2, 0x96, 0x8b, 0xbf, 0x98, 0x0d, 0x0c, 0x5f, 0xbc, 0xf1, 0x43, 0xd7, - 0xcb, 0x9d, 0xc5, 0xe2, 0x8b, 0x25, 0xec, 0xbd, 0xc5, 0x1e, 0xef, 0xf2, 0xc7, 0x6d, 0xa6, 0x47, - 0xfd, 0xdf, 0x65, 0xfd, 0xad, 0xe5, 0xef, 0x9f, 0x0b, 0x6f, 0x5c, 0xa8, 0x7c, 0xcf, 0xb5, 0xd5, - 0xec, 0xbe, 0x5f, 0x33, 0xcd, 0x85, 0xef, 0xdc, 0x6d, 0x75, 0xdf, 0x6d, 0xa5, 0x77, 0x7a, 0x1b, - 0x7d, 0x6d, 0x34, 0x7b, 0xf7, 0xde, 0xdf, 0x7b, 0xec, 0xc8, 0xfd, 0xde, 0xab, 0xbd, 0x7b, 0x1f, - 0xdc, 0xd3, 0xdf, 0xdb, 0x67, 0xef, 0xeb, 0x2b, 0xbf, 0x55, 0x75, 0xa5, 0x3f, 0x32, 0xda, 0x0c, - 0x62, 0xf4, 0x98, 0x5d, 0x77, 0x75, 0x7d, 0xb3, 0xed, 0xeb, 0xbd, 0x23, 0x43, 0xa3, 0x23, 0xc7, - 0x0e, 0x0d, 0x3d, 0xea, 0x1c, 0x3e, 0x3c, 0x34, 0x72, 0xeb, 0x7c, 0xfd, 0xc5, 0x17, 0xbd, 0x03, - 0x5c, 0xf5, 0x97, 0x3e, 0x31, 0x31, 0x51, 0x75, 0xa0, 0x25, 0xad, 0x9d, 0x6e, 0x73, 0xc0, 0xb8, - 0xab, 0x58, 0xfc, 0xe4, 0x5a, 0x5e, 0x76, 0xcc, 0x15, 0x3f, 0xb9, 0xed, 0xa3, 0xe2, 0xa6, 0xed, - 0xc5, 0xc6, 0x2f, 0xdd, 0xc5, 0x62, 0x7b, 0xa3, 0x97, 0x6d, 0x45, 0xef, 0xe7, 0x67, 0xdd, 0x4b, - 0xfd, 0xae, 0x38, 0x31, 0xd1, 0xd7, 0x37, 0xf1, 0xe0, 0xc0, 0x44, 0xf5, 0x5e, 0xb9, 0x5e, 0x29, - 0x1d, 0x26, 0xc7, 0xbc, 0x47, 0x8e, 0x87, 0x2a, 0x87, 0xc9, 0x36, 0x73, 0xfe, 0xb1, 0x66, 0xd1, - 0xb8, 0xa7, 0x68, 0x26, 0xe7, 0x0f, 0xff, 0xef, 0xff, 0xa8, 0xf4, 0x4d, 0x71, 0xd0, 0x3b, 0x70, - 0xfe, 0xad, 0x61, 0x78, 0x57, 0x7d, 0xf0, 0x50, 0xd5, 0x11, 0xb5, 0x72, 0x75, 0xe3, 0xd2, 0x33, - 0xc6, 0xfe, 0xff, 0xdd, 0x5d, 0xbe, 0xfa, 0x05, 0x63, 0xe0, 0xa7, 0xc6, 0x41, 0xc3, 0x38, 0x78, - 0xf1, 0xd2, 0xe1, 0xc1, 0x91, 0x48, 0x74, 0xe0, 0xf0, 0xd0, 0xc2, 0x2d, 0xda, 0xcd, 0x6f, 0xbc, - 0xd2, 0x61, 0xfc, 0x41, 0xe9, 0x71, 0xd7, 0x2f, 0x56, 0x7e, 0xb8, 0x8c, 0x8c, 0xe6, 0x03, 0x47, - 0xbc, 0x07, 0x1a, 0xce, 0x52, 0xe6, 0xdf, 0xef, 0xfc, 0xd3, 0x5a, 0x7f, 0xd6, 0x71, 0x31, 0x5c, - 0x23, 0x3a, 0x32, 0x9a, 0x09, 0x22, 0x2d, 0x91, 0x76, 0xec, 0x08, 0xd2, 0x1a, 0x69, 0x2b, 0x8a, - 0xb4, 0xe6, 0xe8, 0x31, 0x1b, 0x42, 0x5a, 0x23, 0x3d, 0x13, 0x46, 0x5a, 0x73, 0xf4, 0x48, 0xc5, - 0x90, 0xd6, 0x48, 0xbb, 0x71, 0xa4, 0x35, 0xd2, 0xe3, 0x16, 0xd2, 0x9a, 0xe3, 0xf4, 0xb8, 0x8b, - 0xb4, 0x66, 0x9f, 0xce, 0x27, 0x90, 0xd6, 0x48, 0x67, 0x92, 0x48, 0x6b, 0xa4, 0xa7, 0x6d, 0xa4, - 0x35, 0xc7, 0xe9, 0xe9, 0x14, 0xd2, 0x9a, 0x7d, 0xda, 0x49, 0x23, 0xad, 0x91, 0x9e, 0x71, 0x90, - 0x96, 0x48, 0x8f, 0xe5, 0xb3, 0x48, 0x6b, 0xa4, 0x33, 0x39, 0xa4, 0x25, 0xd2, 0x27, 0xed, 0x02, - 0xd2, 0x1a, 0x69, 0x6b, 0x0a, 0x69, 0xcd, 0xd1, 0x63, 0x76, 0x12, 0xe9, 0x75, 0x96, 0x5e, 0xbf, - 0x18, 0x35, 0x9d, 0xb0, 0x63, 0x05, 0x46, 0xd8, 0x96, 0x9a, 0xa6, 0x32, 0x88, 0xb4, 0xa8, 0x7d, - 0x8f, 0x20, 0xad, 0x91, 0xce, 0x47, 0x91, 0x16, 0xb5, 0x3a, 0x21, 0xa4, 0x45, 0x4d, 0x65, 0x18, - 0x69, 0x51, 0xfb, 0x1e, 0x43, 0x5a, 0x74, 0x46, 0x49, 0x1c, 0x69, 0x51, 0xab, 0x63, 0x21, 0x2d, - 0x6a, 0x2a, 0x5d, 0xa4, 0x45, 0xed, 0x7b, 0x02, 0x69, 0xd1, 0x19, 0x25, 0x49, 0xa4, 0x45, 0xad, - 0x8e, 0x8d, 0xb4, 0xa8, 0xa9, 0x4c, 0x21, 0x2d, 0x6a, 0xdf, 0xd3, 0x48, 0x8b, 0xce, 0x28, 0x71, - 0x90, 0x16, 0xb5, 0x3a, 0x59, 0xa4, 0x45, 0x4d, 0x65, 0x0e, 0x69, 0x51, 0xfb, 0x5e, 0x40, 0x5a, - 0x74, 0x46, 0xc9, 0x14, 0xd2, 0x9a, 0xa3, 0x87, 0x3b, 0x89, 0x74, 0xab, 0x74, 0xc2, 0x76, 0xe0, - 0x04, 0xdb, 0x52, 0xf3, 0x9c, 0xca, 0x20, 0xd2, 0xa2, 0xa6, 0x32, 0x82, 0xb4, 0xa8, 0x7d, 0x8f, - 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, 0x30, 0xd2, 0xa2, 0xa6, 0x32, 0x86, 0xb4, - 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, 0x45, 0xed, 0xbb, 0x8b, 0xb4, 0xa8, 0xa9, - 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, 0x4a, 0x1b, 0x69, 0x51, 0xfb, 0x9e, 0x42, - 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, 0xd2, 0xa2, 0xa6, 0x32, 0x8b, 0xb4, 0xa8, - 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, 0xda, 0xf7, 0x29, 0xa4, 0x35, 0x47, 0x8f, - 0xd4, 0x24, 0xd2, 0x2d, 0xd2, 0x09, 0x8f, 0xce, 0x04, 0x8e, 0xb2, 0x2d, 0x35, 0x2b, 0xe0, 0x41, - 0xa4, 0x45, 0xad, 0x4e, 0x04, 0x69, 0x51, 0x53, 0x19, 0x45, 0x5a, 0xd4, 0xbe, 0x87, 0x90, 0x16, - 0x9d, 0x51, 0x12, 0x46, 0x5a, 0x74, 0x96, 0x54, 0x0c, 0x69, 0xd1, 0xdf, 0x28, 0x89, 0x23, 0x2d, - 0x5a, 0x2d, 0xb4, 0x90, 0x16, 0xad, 0x80, 0xbb, 0x48, 0x8b, 0x5a, 0x9d, 0x04, 0xd2, 0xa2, 0xa6, - 0x32, 0x89, 0xb4, 0xa8, 0x7d, 0xb7, 0x91, 0x16, 0x9d, 0x51, 0x92, 0x42, 0x5a, 0x74, 0x96, 0x54, - 0x1a, 0x69, 0xd1, 0x99, 0x7f, 0x0e, 0xd2, 0x9a, 0x56, 0x67, 0x26, 0x8b, 0xb4, 0xe8, 0xaf, 0xbf, - 0xe6, 0x90, 0x16, 0x3d, 0xa7, 0xb2, 0x80, 0xb4, 0xa8, 0xa9, 0x9c, 0x42, 0x5a, 0xd4, 0xbe, 0x4f, - 0x22, 0xdd, 0x2a, 0x9d, 0xf0, 0x6c, 0xe0, 0x18, 0xdb, 0x52, 0xf3, 0x5c, 0x9d, 0x20, 0xd2, 0xa2, - 0xa6, 0x32, 0x82, 0xb4, 0xa8, 0x7d, 0x8f, 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, - 0x30, 0xd2, 0xa2, 0xa6, 0x32, 0x86, 0xb4, 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, - 0x45, 0xed, 0xbb, 0x8b, 0xb4, 0xa8, 0xa9, 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, - 0x4a, 0x1b, 0x69, 0x51, 0xfb, 0x9e, 0x42, 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, - 0xd2, 0xa2, 0xa6, 0x32, 0x8b, 0xb4, 0xa8, 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, - 0xda, 0xf7, 0x29, 0xa4, 0x45, 0xcf, 0x7d, 0x9f, 0x44, 0xba, 0x55, 0xfe, 0x76, 0xb4, 0x1b, 0x18, - 0x63, 0x5b, 0x6a, 0x9a, 0xca, 0x20, 0xd2, 0xa2, 0xf6, 0x3d, 0x82, 0xb4, 0xe8, 0xb9, 0xef, 0x51, - 0xa4, 0x45, 0xad, 0x4e, 0x08, 0x69, 0x51, 0x53, 0x19, 0x46, 0x5a, 0xd4, 0xbe, 0xc7, 0x90, 0x16, - 0x9d, 0x51, 0x12, 0x47, 0x5a, 0xd4, 0xea, 0x58, 0x48, 0x8b, 0x9a, 0x4a, 0x17, 0x69, 0x51, 0xfb, - 0x9e, 0x40, 0x5a, 0x74, 0x46, 0x49, 0x12, 0x69, 0x51, 0xab, 0x63, 0x23, 0x2d, 0x6a, 0x2a, 0x53, - 0x48, 0x8b, 0xda, 0xf7, 0x34, 0xd2, 0xa2, 0x33, 0x4a, 0x1c, 0xa4, 0x45, 0xad, 0x4e, 0x16, 0x69, - 0x51, 0x53, 0x99, 0x43, 0x5a, 0xd4, 0xbe, 0x17, 0x90, 0x16, 0x9d, 0x51, 0x32, 0x85, 0xb4, 0xe6, - 0xe8, 0x61, 0x4d, 0x22, 0xdd, 0x2a, 0x9d, 0x70, 0x2a, 0x70, 0x92, 0x6d, 0xa9, 0x79, 0x4e, 0x65, - 0x10, 0x69, 0x51, 0x53, 0x19, 0x41, 0x5a, 0xd4, 0xbe, 0x47, 0x91, 0x16, 0x35, 0x95, 0x21, 0xa4, - 0x45, 0xed, 0x7b, 0x18, 0x69, 0x51, 0x53, 0x19, 0x43, 0x5a, 0xd4, 0xbe, 0xc7, 0x91, 0x16, 0x35, - 0x95, 0x16, 0xd2, 0xa2, 0xf6, 0xdd, 0x45, 0x5a, 0xd4, 0x54, 0x26, 0x90, 0x16, 0xb5, 0xef, 0x49, - 0xa4, 0x45, 0x4d, 0xa5, 0x8d, 0xb4, 0xa8, 0x7d, 0x4f, 0x21, 0x2d, 0x6a, 0x2a, 0xd3, 0x48, 0x8b, - 0xda, 0x77, 0x07, 0x69, 0x51, 0x53, 0x99, 0x45, 0x5a, 0xd4, 0xbe, 0xe7, 0x90, 0x16, 0x35, 0x95, - 0x05, 0xa4, 0x45, 0xed, 0xfb, 0x14, 0xd2, 0x9a, 0xa3, 0x87, 0x3d, 0x89, 0x74, 0xab, 0xfc, 0xed, - 0xe8, 0xf1, 0x40, 0x84, 0x6d, 0xa9, 0x79, 0xc4, 0x1e, 0x44, 0x5a, 0xf4, 0x5b, 0x68, 0x04, 0x69, - 0xd1, 0xca, 0x4a, 0x14, 0x69, 0xd1, 0x6a, 0x61, 0x08, 0x69, 0xd1, 0x0a, 0x78, 0x18, 0x69, 0x51, - 0xab, 0x13, 0x43, 0x5a, 0xd4, 0x54, 0xc6, 0x91, 0x16, 0xb5, 0xef, 0x16, 0xd2, 0xa2, 0x33, 0x4a, - 0x5c, 0xa4, 0x45, 0x67, 0x49, 0x25, 0x90, 0x16, 0x9d, 0xf9, 0x97, 0x44, 0x5a, 0x74, 0x36, 0xab, - 0x8d, 0xb4, 0xe8, 0x0c, 0xed, 0x14, 0xd2, 0xa2, 0x67, 0x1d, 0xa4, 0x91, 0x16, 0xfd, 0xcd, 0x3f, - 0x07, 0x69, 0x4d, 0xab, 0x33, 0x9e, 0x45, 0x5a, 0xd3, 0xea, 0x8c, 0xe7, 0x90, 0xd6, 0x48, 0x67, - 0x0a, 0x48, 0x6b, 0xa4, 0xf3, 0x53, 0x48, 0x6b, 0x8e, 0xd3, 0xd3, 0x93, 0x48, 0xb7, 0xca, 0xf3, - 0x84, 0xc7, 0x03, 0x31, 0xb6, 0xa5, 0xe6, 0xdc, 0xc2, 0x20, 0xd2, 0xa2, 0xa6, 0x32, 0x82, 0xb4, - 0xa8, 0x7d, 0x8f, 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, 0x30, 0xd2, 0xa2, 0xa6, - 0x32, 0x86, 0xb4, 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, 0x45, 0xed, 0xbb, 0x8b, - 0xb4, 0xa8, 0xa9, 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, 0x4a, 0x1b, 0x69, 0x51, - 0xfb, 0x9e, 0x42, 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, 0xd2, 0xa2, 0xa6, 0x32, - 0x8b, 0xb4, 0xa8, 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, 0xda, 0xf7, 0x29, 0xa4, - 0x35, 0xd2, 0xd3, 0x93, 0x48, 0xb7, 0x4a, 0x27, 0x9c, 0x09, 0x9c, 0x62, 0x5b, 0x6a, 0x9a, 0xca, - 0x20, 0xd2, 0xa2, 0xf6, 0x3d, 0x82, 0xb4, 0xe8, 0xb9, 0xef, 0x51, 0xa4, 0x45, 0xad, 0x4e, 0x08, - 0x69, 0x51, 0x53, 0x19, 0x46, 0x5a, 0xd4, 0xbe, 0xc7, 0x90, 0x16, 0x9d, 0x51, 0x12, 0x47, 0x5a, - 0xd4, 0xea, 0x58, 0x48, 0x8b, 0x9a, 0x4a, 0x17, 0x69, 0x51, 0xfb, 0x9e, 0x40, 0x5a, 0x74, 0x46, - 0x49, 0x12, 0x69, 0x51, 0xab, 0x63, 0x23, 0x2d, 0x6a, 0x2a, 0x53, 0x48, 0x8b, 0xda, 0xf7, 0x34, - 0xd2, 0xa2, 0x33, 0x4a, 0x1c, 0xa4, 0x45, 0xad, 0x4e, 0x16, 0x69, 0x51, 0x53, 0x99, 0x43, 0x5a, - 0xd4, 0xbe, 0x17, 0x90, 0x16, 0x9d, 0x51, 0x32, 0x85, 0xb4, 0x46, 0x7a, 0x66, 0x12, 0xe9, 0x56, - 0xe9, 0x84, 0xf3, 0x81, 0x5f, 0x65, 0x5b, 0x6a, 0x9e, 0x53, 0x19, 0x44, 0x5a, 0xd4, 0x54, 0x46, - 0x90, 0x16, 0xb5, 0xef, 0x51, 0xa4, 0x45, 0x4d, 0x65, 0x08, 0x69, 0x51, 0xfb, 0x1e, 0x46, 0x5a, - 0xd4, 0x54, 0xc6, 0x90, 0x16, 0xb5, 0xef, 0x71, 0xa4, 0x45, 0x4d, 0xa5, 0x85, 0xb4, 0xa8, 0x7d, - 0x77, 0x91, 0x16, 0x35, 0x95, 0x09, 0xa4, 0x45, 0xed, 0x7b, 0x12, 0x69, 0x51, 0x53, 0x69, 0x23, - 0x2d, 0x6a, 0xdf, 0x53, 0x48, 0x8b, 0x9a, 0xca, 0x34, 0xd2, 0xa2, 0xf6, 0xdd, 0x41, 0x5a, 0xd4, - 0x54, 0x66, 0x91, 0x16, 0xb5, 0xef, 0x39, 0xa4, 0x45, 0x4d, 0x65, 0x01, 0x69, 0x51, 0xfb, 0x3e, - 0x85, 0xb4, 0x66, 0x9f, 0x76, 0x26, 0x91, 0x6e, 0x91, 0x4e, 0x78, 0x74, 0x3a, 0x10, 0x65, 0x5b, - 0x6a, 0x56, 0xc0, 0x83, 0x48, 0x8b, 0x5a, 0x9d, 0x08, 0xd2, 0xa2, 0xa6, 0x32, 0x8a, 0xb4, 0xa8, - 0x7d, 0x0f, 0x21, 0x2d, 0x3a, 0xa3, 0x24, 0x8c, 0xb4, 0xe8, 0x2c, 0xa9, 0x18, 0xd2, 0xa2, 0xbf, - 0x51, 0x12, 0x47, 0x5a, 0xb4, 0x5a, 0x68, 0x21, 0x2d, 0x5a, 0x01, 0x77, 0x91, 0x16, 0xb5, 0x3a, - 0x09, 0xa4, 0x45, 0x4d, 0x65, 0x12, 0x69, 0x51, 0xfb, 0x6e, 0x23, 0x2d, 0x3a, 0xa3, 0x24, 0x85, - 0xb4, 0xe8, 0x2c, 0xa9, 0x34, 0xd2, 0xa2, 0x33, 0xff, 0x1c, 0xa4, 0x35, 0xad, 0xce, 0x74, 0x16, - 0x69, 0xd1, 0x5f, 0x7f, 0xcd, 0x21, 0x2d, 0x7a, 0x4e, 0x65, 0x01, 0x69, 0x51, 0x53, 0x39, 0x85, - 0xb4, 0xa8, 0x7d, 0x9f, 0x44, 0xba, 0x55, 0x9e, 0x27, 0x3c, 0x1d, 0x88, 0xb3, 0x2d, 0x35, 0xcf, - 0xd5, 0x09, 0x22, 0x2d, 0x6a, 0x2a, 0x23, 0x48, 0x8b, 0xda, 0xf7, 0x28, 0xd2, 0xa2, 0xa6, 0x32, - 0x84, 0xb4, 0xa8, 0x7d, 0x0f, 0x23, 0x2d, 0x6a, 0x2a, 0x63, 0x48, 0x8b, 0xda, 0xf7, 0x38, 0xd2, - 0xa2, 0xa6, 0xd2, 0x42, 0x5a, 0xd4, 0xbe, 0xbb, 0x48, 0x8b, 0x9a, 0xca, 0x04, 0xd2, 0xa2, 0xf6, - 0x3d, 0x89, 0xb4, 0xa8, 0xa9, 0xb4, 0x91, 0x16, 0xb5, 0xef, 0x29, 0xa4, 0x45, 0x4d, 0x65, 0x1a, - 0x69, 0x51, 0xfb, 0xee, 0x20, 0x2d, 0x6a, 0x2a, 0xb3, 0x48, 0x8b, 0xda, 0xf7, 0x1c, 0xd2, 0xa2, - 0xa6, 0xb2, 0x80, 0xb4, 0xa8, 0x7d, 0x9f, 0x42, 0x5a, 0xf4, 0xdc, 0xf7, 0x49, 0xa4, 0x5b, 0xa5, - 0x13, 0x9e, 0x09, 0x3c, 0xc1, 0xb6, 0xd4, 0x34, 0x95, 0x41, 0xa4, 0x45, 0xed, 0x7b, 0x04, 0x69, - 0xd1, 0x73, 0xdf, 0xa3, 0x48, 0x8b, 0x5a, 0x9d, 0x10, 0xd2, 0xa2, 0xa6, 0x32, 0x8c, 0xb4, 0xa8, - 0x7d, 0x8f, 0x21, 0x2d, 0x3a, 0xa3, 0x24, 0x8e, 0xb4, 0xa8, 0xd5, 0xb1, 0x90, 0x16, 0x35, 0x95, - 0x2e, 0xd2, 0xa2, 0xf6, 0x3d, 0x81, 0xb4, 0xe8, 0x8c, 0x92, 0x24, 0xd2, 0xa2, 0x56, 0xc7, 0x46, - 0x5a, 0xd4, 0x54, 0xa6, 0x90, 0x16, 0xb5, 0xef, 0x69, 0xa4, 0x45, 0x67, 0x94, 0x38, 0x48, 0x8b, - 0x5a, 0x9d, 0x2c, 0xd2, 0xa2, 0xa6, 0x32, 0x87, 0xb4, 0xa8, 0x7d, 0x2f, 0x20, 0x2d, 0x3a, 0xa3, - 0x64, 0x0a, 0x69, 0x8d, 0x74, 0x66, 0x12, 0xe9, 0x56, 0xe9, 0x84, 0x9d, 0x80, 0xc3, 0xb6, 0xd4, - 0x3c, 0xa7, 0x32, 0x88, 0xb4, 0xa8, 0xa9, 0x8c, 0x20, 0x2d, 0x6a, 0xdf, 0xa3, 0x48, 0x8b, 0x9a, - 0xca, 0x10, 0xd2, 0xa2, 0xf6, 0x3d, 0x8c, 0xb4, 0xa8, 0xa9, 0x8c, 0x21, 0x2d, 0x6a, 0xdf, 0xe3, - 0x48, 0x8b, 0x9a, 0x4a, 0x0b, 0x69, 0x51, 0xfb, 0xee, 0x22, 0x2d, 0x6a, 0x2a, 0x13, 0x48, 0x8b, - 0xda, 0xf7, 0x24, 0xd2, 0xa2, 0xa6, 0xd2, 0x46, 0x5a, 0xd4, 0xbe, 0xa7, 0x90, 0x16, 0x35, 0x95, - 0x69, 0xa4, 0x45, 0xed, 0xbb, 0x83, 0xb4, 0xa8, 0xa9, 0xcc, 0x22, 0x2d, 0x6a, 0xdf, 0x73, 0x48, - 0x8b, 0x9a, 0xca, 0x02, 0xd2, 0xa2, 0xf6, 0x7d, 0x0a, 0x69, 0xcd, 0x3e, 0x9d, 0x9f, 0x44, 0xba, - 0x45, 0x3a, 0xe1, 0xb1, 0x4c, 0xe0, 0x0c, 0xdb, 0x52, 0x72, 0x7c, 0xca, 0x07, 0x91, 0xd6, 0x1c, - 0x9f, 0xac, 0x08, 0xd2, 0x1a, 0x69, 0x3b, 0x8a, 0xb4, 0xe6, 0xe8, 0x31, 0x13, 0x42, 0x5a, 0x23, - 0x3d, 0x1b, 0x46, 0x5a, 0x73, 0xf4, 0x70, 0x63, 0x48, 0x6b, 0xa4, 0x53, 0x71, 0xa4, 0x35, 0x47, - 0x8f, 0x71, 0x0b, 0x69, 0xd1, 0x5f, 0xab, 0x72, 0x91, 0x16, 0x9d, 0x03, 0x9e, 0x40, 0x5a, 0xb4, - 0xb2, 0x92, 0x44, 0x5a, 0xb4, 0x5a, 0x68, 0x23, 0x2d, 0x5a, 0x01, 0x4f, 0x21, 0x2d, 0x6a, 0x75, - 0xd2, 0x48, 0x8b, 0x9a, 0x4a, 0x07, 0x69, 0x51, 0xfb, 0x9e, 0x45, 0x5a, 0x74, 0x46, 0x49, 0x0e, - 0x69, 0xd1, 0x59, 0x52, 0x05, 0xa4, 0x45, 0x67, 0xfe, 0x4d, 0x21, 0x2d, 0x3a, 0x9b, 0x75, 0x12, - 0xe9, 0x56, 0xe9, 0x84, 0xf3, 0x81, 0xa7, 0x6b, 0xb6, 0xe5, 0xee, 0xf9, 0xf7, 0x17, 0x2f, 0xbe, - 0xc7, 0xd6, 0x58, 0xf3, 0x45, 0xed, 0x6f, 0xa1, 0x99, 0xe0, 0xd3, 0x7c, 0xd7, 0x68, 0x9a, 0xca, - 0x08, 0xd2, 0xa2, 0xf6, 0x3d, 0x8a, 0xb4, 0xa8, 0xa9, 0x0c, 0x21, 0x2d, 0x6a, 0xdf, 0xc3, 0x48, - 0x8b, 0x9a, 0xca, 0x18, 0xd2, 0xa2, 0xf6, 0x3d, 0x8e, 0xb4, 0xa8, 0xa9, 0xb4, 0x90, 0x16, 0xb5, - 0xef, 0x2e, 0xd2, 0xa2, 0xa6, 0x32, 0x81, 0xb4, 0xa8, 0x7d, 0x4f, 0x22, 0x2d, 0x6a, 0x2a, 0x6d, - 0xa4, 0x45, 0xed, 0x7b, 0x0a, 0x69, 0x51, 0x53, 0x99, 0x46, 0x5a, 0xd4, 0xbe, 0x3b, 0x48, 0x8b, - 0x9a, 0xca, 0x2c, 0xd2, 0xa2, 0xf6, 0x3d, 0x87, 0xb4, 0xa8, 0xa9, 0x2c, 0x20, 0x2d, 0x6a, 0xdf, - 0xa7, 0x90, 0x16, 0xfd, 0x2d, 0xa9, 0x49, 0xa4, 0x37, 0x74, 0x27, 0xfc, 0xce, 0x2f, 0x2c, 0x74, - 0xc2, 0x27, 0xad, 0xc0, 0xb3, 0x0d, 0xb6, 0x25, 0x1b, 0x73, 0x3d, 0x36, 0xe6, 0x42, 0x65, 0x19, - 0xac, 0x21, 0x1f, 0x1b, 0x83, 0x7c, 0x9d, 0xc9, 0xc7, 0x32, 0x91, 0x67, 0x39, 0x62, 0x89, 0x8e, - 0x58, 0x0b, 0x27, 0x9b, 0x44, 0x21, 0xd7, 0x92, 0x9f, 0x74, 0x43, 0x90, 0x8b, 0xc9, 0x53, 0x61, - 0xc8, 0xc5, 0x07, 0x96, 0x99, 0x18, 0xe4, 0x62, 0xf2, 0xd9, 0x38, 0xe4, 0xe2, 0x03, 0x4b, 0xc6, - 0x82, 0x5c, 0x4c, 0x9e, 0x77, 0x21, 0x17, 0x1f, 0x58, 0xc6, 0x13, 0x90, 0x8b, 0xf7, 0xf2, 0xf1, - 0x24, 0xe4, 0x62, 0xf2, 0x19, 0x1b, 0x72, 0x31, 0xb9, 0x93, 0x82, 0x5c, 0x7c, 0x2c, 0x9f, 0x4e, - 0x43, 0x2e, 0xde, 0xcb, 0xa7, 0x1d, 0xc8, 0xb5, 0xe4, 0x8e, 0x95, 0x85, 0x5c, 0x4c, 0x6e, 0xe7, - 0x20, 0xd7, 0x92, 0x8f, 0x66, 0x0a, 0x90, 0x6f, 0xd8, 0x86, 0x6f, 0x85, 0xb6, 0xcf, 0x0e, 0x3c, - 0xc7, 0x76, 0xd5, 0xfe, 0x8c, 0xb6, 0x82, 0x90, 0xab, 0xab, 0xa7, 0x08, 0xe4, 0x62, 0xf2, 0x4c, - 0x14, 0x72, 0x75, 0xf5, 0x14, 0x82, 0x5c, 0x5d, 0xb0, 0x86, 0x21, 0x57, 0x57, 0x4f, 0x31, 0xc8, - 0xd5, 0x05, 0x6b, 0x1c, 0x72, 0x75, 0xf5, 0x64, 0x41, 0xae, 0x2e, 0x58, 0x5d, 0xc8, 0xd5, 0xd5, - 0x53, 0x02, 0x72, 0x75, 0xc1, 0x9a, 0x84, 0x5c, 0x5d, 0x3d, 0xd9, 0x90, 0xab, 0x0b, 0xd6, 0x14, - 0xe4, 0xea, 0xea, 0x29, 0x0d, 0xb9, 0xba, 0x60, 0x75, 0x20, 0x57, 0x57, 0x4f, 0x59, 0xc8, 0xd5, - 0x05, 0x6b, 0x0e, 0x72, 0x71, 0xdb, 0x97, 0x2f, 0x40, 0xde, 0x82, 0x6d, 0xdf, 0xd8, 0x4c, 0xe0, - 0x2c, 0xdb, 0x55, 0xbc, 0x5c, 0x19, 0x84, 0x5c, 0xbd, 0x28, 0x1f, 0x81, 0x5c, 0x5d, 0x3d, 0x45, - 0x21, 0x57, 0x17, 0xac, 0x21, 0xc8, 0xd5, 0xa7, 0x11, 0x84, 0x21, 0x57, 0x9f, 0x2c, 0x13, 0x83, - 0x5c, 0x4c, 0x6e, 0xc7, 0x21, 0x57, 0x2f, 0xe4, 0x58, 0x90, 0xab, 0x97, 0x2b, 0x5d, 0xc8, 0xd5, - 0x8b, 0xf2, 0x09, 0xc8, 0xd5, 0xd5, 0x53, 0x12, 0x72, 0x75, 0xc1, 0x6a, 0x43, 0xae, 0x3e, 0x8d, - 0x20, 0x05, 0xb9, 0xfa, 0x64, 0x99, 0x34, 0xe4, 0xea, 0x53, 0xc2, 0x1c, 0xc8, 0xc5, 0x3d, 0xc8, - 0x4c, 0x16, 0x72, 0x31, 0xf9, 0x6c, 0x0e, 0x72, 0x71, 0xc1, 0xea, 0x16, 0x20, 0x6f, 0xc5, 0xb6, - 0x6f, 0x36, 0xf0, 0x0c, 0xdb, 0x55, 0x7c, 0xa6, 0x7c, 0x10, 0x72, 0x75, 0xf5, 0x14, 0x81, 0x5c, - 0x5d, 0xb0, 0x46, 0x21, 0x57, 0x57, 0x4f, 0x21, 0xc8, 0xd5, 0x05, 0x6b, 0x18, 0x72, 0x75, 0xf5, - 0x14, 0x83, 0x5c, 0x5d, 0xb0, 0xc6, 0x21, 0x57, 0x57, 0x4f, 0x16, 0xe4, 0xea, 0x82, 0xd5, 0x85, - 0x5c, 0x5d, 0x3d, 0x25, 0x20, 0x57, 0x17, 0xac, 0x49, 0xc8, 0xd5, 0xd5, 0x93, 0x0d, 0xb9, 0xba, - 0x60, 0x4d, 0x41, 0xae, 0xae, 0x9e, 0xd2, 0x90, 0xab, 0x0b, 0x56, 0x07, 0x72, 0x75, 0xf5, 0x94, - 0x85, 0x5c, 0x5d, 0xb0, 0xe6, 0x20, 0x17, 0xb7, 0x7d, 0xa9, 0x02, 0xe4, 0xad, 0xf8, 0x97, 0x3c, - 0xdd, 0xc0, 0x39, 0xb6, 0xab, 0xb8, 0x7a, 0x0a, 0x42, 0xae, 0x2e, 0x58, 0x23, 0x90, 0xab, 0x9f, - 0xc1, 0x1a, 0x85, 0x5c, 0xbd, 0x28, 0x1f, 0x82, 0x5c, 0x5d, 0x3d, 0x85, 0x21, 0x57, 0x17, 0xac, - 0x31, 0xc8, 0xd5, 0xa7, 0x11, 0xc4, 0x21, 0x57, 0x2f, 0xca, 0x5b, 0x90, 0xab, 0xab, 0x27, 0x17, - 0x72, 0x75, 0xc1, 0x9a, 0x80, 0x5c, 0x7d, 0x1a, 0x41, 0x12, 0x72, 0xf5, 0xa2, 0xbc, 0x0d, 0xb9, - 0xba, 0x7a, 0x4a, 0x41, 0xae, 0x2e, 0x58, 0xd3, 0x90, 0xab, 0x4f, 0x23, 0x70, 0x20, 0x57, 0x3f, - 0xeb, 0x29, 0x0b, 0xb9, 0xba, 0x7a, 0xca, 0x41, 0xae, 0x2e, 0x58, 0x0b, 0x90, 0xb7, 0x62, 0xdb, - 0x97, 0x0a, 0x3c, 0xcf, 0x76, 0x15, 0x3f, 0xeb, 0x29, 0x08, 0xb9, 0xba, 0x7a, 0x8a, 0x40, 0xae, - 0x2e, 0x58, 0xa3, 0x90, 0xab, 0xab, 0xa7, 0x10, 0xe4, 0xea, 0x82, 0x35, 0x0c, 0xb9, 0xba, 0x7a, - 0x8a, 0x41, 0xae, 0x2e, 0x58, 0xe3, 0x90, 0xab, 0xab, 0x27, 0x0b, 0x72, 0x75, 0xc1, 0xea, 0x42, - 0xae, 0xae, 0x9e, 0x12, 0x90, 0xab, 0x0b, 0xd6, 0x24, 0xe4, 0xea, 0xea, 0xc9, 0x86, 0x5c, 0x5d, - 0xb0, 0xa6, 0x20, 0x57, 0x57, 0x4f, 0x69, 0xc8, 0xd5, 0x05, 0xab, 0x03, 0xb9, 0xba, 0x7a, 0xca, - 0x42, 0xae, 0x2e, 0x58, 0x73, 0x90, 0xab, 0x9f, 0xc1, 0x5a, 0x80, 0xbc, 0x15, 0xff, 0x92, 0xe7, - 0x78, 0x20, 0xc1, 0x76, 0x15, 0x3f, 0x2c, 0x0a, 0x42, 0xae, 0x7e, 0xf0, 0x1f, 0x81, 0x5c, 0xfd, - 0x2b, 0x6e, 0x14, 0x72, 0xf5, 0x42, 0x4e, 0x08, 0x72, 0xf5, 0x72, 0x65, 0x18, 0x72, 0xf5, 0xa2, - 0x7c, 0x0c, 0x72, 0x75, 0xf5, 0x14, 0x87, 0x5c, 0x5d, 0xb0, 0x5a, 0x90, 0xab, 0x4f, 0x23, 0x70, - 0x21, 0x57, 0x9f, 0x2c, 0x93, 0x80, 0x5c, 0x7d, 0x4a, 0x58, 0x12, 0x72, 0xf5, 0x89, 0x8f, 0x36, - 0xe4, 0xea, 0xd3, 0x7b, 0x53, 0x90, 0xab, 0x4f, 0x62, 0x4f, 0x43, 0xae, 0xfe, 0x2b, 0x61, 0x0e, - 0xe4, 0xe2, 0x1e, 0x64, 0x3c, 0x0b, 0xb9, 0xb8, 0xed, 0x1b, 0xcf, 0x41, 0x2e, 0x26, 0xcf, 0x14, - 0x20, 0x6f, 0x99, 0xb6, 0x6f, 0xf3, 0x3d, 0x8b, 0xcf, 0xed, 0x1b, 0x0f, 0xa4, 0xd9, 0xae, 0xeb, - 0xbf, 0x5d, 0x17, 0xba, 0xd5, 0x20, 0xda, 0x32, 0xed, 0x93, 0xf9, 0x08, 0xda, 0x3a, 0xed, 0x4c, - 0x14, 0x6d, 0x9d, 0xf6, 0x74, 0x08, 0x6d, 0xdd, 0x71, 0x7b, 0x3a, 0x8c, 0xb6, 0x6e, 0xdf, 0x76, - 0x62, 0x68, 0xeb, 0xb4, 0x67, 0xe2, 0x68, 0xeb, 0x8e, 0x24, 0x79, 0x0b, 0x6d, 0x9d, 0x76, 0xc6, - 0x45, 0x5b, 0x77, 0x24, 0xb1, 0x13, 0x68, 0xeb, 0xb4, 0xad, 0x24, 0xda, 0xba, 0x23, 0xc9, 0xac, - 0x8d, 0xb6, 0x4e, 0x7b, 0x26, 0x85, 0xb6, 0xee, 0x48, 0x92, 0x4a, 0xa3, 0xad, 0xd3, 0x76, 0x1d, - 0xb4, 0x65, 0xda, 0xce, 0x78, 0x16, 0x6d, 0x99, 0xf6, 0xe8, 0x78, 0x0e, 0xed, 0x0d, 0xd7, 0x12, - 0xd5, 0x35, 0x42, 0x99, 0xc0, 0x79, 0xb6, 0xa1, 0xae, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0xdf, 0x22, - 0x68, 0xeb, 0xf6, 0xed, 0xf1, 0x28, 0xda, 0xc2, 0x75, 0xdc, 0x10, 0xda, 0xc2, 0x8e, 0x22, 0x8c, - 0xb6, 0xb0, 0x7f, 0x8b, 0xa1, 0x2d, 0xec, 0x96, 0xe3, 0x68, 0x0b, 0xd7, 0x71, 0x2d, 0xb4, 0x85, - 0x1d, 0x85, 0x8b, 0xb6, 0xb0, 0x7f, 0x4b, 0xa0, 0x2d, 0xec, 0x96, 0x93, 0x68, 0x0b, 0xd7, 0x71, - 0x6d, 0xb4, 0x85, 0x1d, 0x45, 0x0a, 0x6d, 0x61, 0xff, 0x96, 0x46, 0x5b, 0xd8, 0x2d, 0x3b, 0x68, - 0xeb, 0x1a, 0xa1, 0x4c, 0x16, 0x6d, 0x9d, 0x76, 0x3e, 0x87, 0xf6, 0x46, 0x6f, 0x84, 0xf2, 0x81, - 0x2f, 0xb1, 0x0d, 0x75, 0xcf, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0x28, 0x22, 0x68, 0x0b, 0xfb, 0xb7, - 0x28, 0xda, 0xc2, 0x8e, 0x22, 0x84, 0xb6, 0xb0, 0x7f, 0x0b, 0xa3, 0x2d, 0xec, 0x28, 0x62, 0x68, - 0x0b, 0xfb, 0xb7, 0x38, 0xda, 0xc2, 0x8e, 0xc2, 0x42, 0x5b, 0xd8, 0xbf, 0xb9, 0x68, 0x0b, 0x3b, - 0x8a, 0x04, 0xda, 0xc2, 0xfe, 0x2d, 0x89, 0xb6, 0xb0, 0xa3, 0xb0, 0xd1, 0x16, 0xf6, 0x6f, 0x29, - 0xb4, 0x85, 0x1d, 0x45, 0x1a, 0x6d, 0x61, 0xff, 0xe6, 0xa0, 0x2d, 0xec, 0x28, 0xb2, 0x68, 0x0b, - 0xfb, 0xb7, 0x1c, 0xda, 0x1b, 0xbc, 0x11, 0x1a, 0x9b, 0x0e, 0x24, 0xd9, 0x86, 0xba, 0xb5, 0xae, - 0x20, 0xda, 0xc2, 0x75, 0xdc, 0x08, 0xda, 0xc2, 0x8e, 0x22, 0x8a, 0xb6, 0xb0, 0x7f, 0x0b, 0xa1, - 0x2d, 0xec, 0x96, 0xc3, 0x68, 0x0b, 0xcf, 0x9b, 0x88, 0xa1, 0x2d, 0x7c, 0xde, 0x72, 0x1c, 0x6d, - 0xe1, 0x7a, 0x80, 0x85, 0xb6, 0x70, 0xad, 0xcb, 0x45, 0x5b, 0xb8, 0x8e, 0x9b, 0x40, 0x5b, 0xd8, - 0x51, 0x24, 0xd1, 0x16, 0xf6, 0x6f, 0x36, 0xda, 0xc2, 0x6e, 0x39, 0x85, 0xb6, 0xf0, 0xbc, 0x89, - 0x34, 0xda, 0xc2, 0x73, 0x82, 0x1c, 0xb4, 0x75, 0x7f, 0xc7, 0x6c, 0x3a, 0x8b, 0xb6, 0xae, 0x11, - 0x9a, 0xce, 0xa1, 0xbd, 0xd1, 0x9f, 0x23, 0x34, 0x1d, 0xf8, 0x32, 0xdb, 0x50, 0x77, 0x3e, 0x6e, - 0x10, 0x6d, 0x61, 0x47, 0x11, 0x41, 0x5b, 0xd8, 0xbf, 0x45, 0xd1, 0x16, 0x76, 0x14, 0x21, 0xb4, - 0x85, 0xfd, 0x5b, 0x18, 0x6d, 0x61, 0x47, 0x11, 0x43, 0x5b, 0xd8, 0xbf, 0xc5, 0xd1, 0x16, 0x76, - 0x14, 0x16, 0xda, 0xc2, 0xfe, 0xcd, 0x45, 0x5b, 0xd8, 0x51, 0x24, 0xd0, 0x16, 0xf6, 0x6f, 0x49, - 0xb4, 0x85, 0x1d, 0x85, 0x8d, 0xb6, 0xb0, 0x7f, 0x4b, 0xa1, 0x2d, 0xec, 0x28, 0xd2, 0x68, 0x0b, - 0xfb, 0x37, 0x07, 0x6d, 0x61, 0x47, 0x91, 0x45, 0x5b, 0xd8, 0xbf, 0xe5, 0xd0, 0xde, 0xe8, 0x8d, - 0xd0, 0x4c, 0xe0, 0x05, 0xb6, 0xa1, 0xae, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0xdf, 0x22, 0x68, 0x0b, - 0x9f, 0xff, 0x16, 0x45, 0x5b, 0xb8, 0x8e, 0x1b, 0x42, 0x5b, 0xd8, 0x51, 0x84, 0xd1, 0x16, 0xf6, - 0x6f, 0x31, 0xb4, 0x85, 0xdd, 0x72, 0x1c, 0x6d, 0xe1, 0x3a, 0xae, 0x85, 0xb6, 0xb0, 0xa3, 0x70, - 0xd1, 0x16, 0xf6, 0x6f, 0x09, 0xb4, 0x85, 0xdd, 0x72, 0x12, 0x6d, 0xe1, 0x3a, 0xae, 0x8d, 0xb6, - 0xb0, 0xa3, 0x48, 0xa1, 0x2d, 0xec, 0xdf, 0xd2, 0x68, 0x0b, 0xbb, 0x65, 0x07, 0x6d, 0x5d, 0x23, - 0x34, 0x93, 0x45, 0x5b, 0xa7, 0xed, 0xe4, 0xd0, 0xde, 0x90, 0x8d, 0xd0, 0x99, 0x4f, 0x2c, 0x36, - 0x42, 0x4e, 0x20, 0xc5, 0x36, 0x5c, 0xe7, 0x6d, 0xb8, 0x50, 0xbe, 0x05, 0xa1, 0x16, 0x51, 0x4f, - 0x47, 0xa0, 0xd6, 0x50, 0x8f, 0x4d, 0x47, 0xa1, 0x16, 0xed, 0xd5, 0xf9, 0x10, 0xd4, 0x22, 0xea, - 0x4c, 0x18, 0x6a, 0x11, 0xf5, 0x78, 0x0c, 0x6a, 0xd1, 0xb1, 0x7a, 0x3c, 0x0e, 0xb5, 0x68, 0xaf, - 0x4e, 0x59, 0x50, 0x8b, 0xa8, 0x5d, 0x17, 0x6a, 0xd1, 0x01, 0x64, 0x36, 0x01, 0xb5, 0x88, 0x7a, - 0x26, 0x09, 0xb5, 0xe8, 0x00, 0x62, 0xdb, 0x50, 0x8b, 0xa8, 0xad, 0x14, 0xd4, 0xa2, 0x03, 0x48, - 0x3e, 0x0d, 0xb5, 0x88, 0x3a, 0xe3, 0x40, 0xad, 0xa1, 0x76, 0x9c, 0x2c, 0xd4, 0x1b, 0xac, 0x73, - 0xa8, 0x6d, 0x1c, 0x9e, 0xca, 0xec, 0x1e, 0x66, 0x0b, 0x4a, 0xbe, 0x59, 0x9e, 0xca, 0xef, 0x81, - 0x5a, 0x43, 0xed, 0x5a, 0xc3, 0x50, 0x8b, 0xa8, 0xed, 0xa3, 0x50, 0x8b, 0x0e, 0x20, 0x33, 0xfb, - 0xa1, 0x16, 0x51, 0xcf, 0x1e, 0x80, 0x5a, 0x74, 0x00, 0x71, 0x4f, 0x41, 0x2d, 0xa2, 0x4e, 0x3d, - 0x01, 0xb5, 0xe8, 0x00, 0x32, 0x7e, 0x2f, 0xd4, 0xa2, 0xbd, 0x7a, 0xfc, 0x34, 0xd4, 0x22, 0xea, - 0xcc, 0x19, 0xa8, 0x45, 0xd4, 0xf9, 0xb3, 0x50, 0x8b, 0x8e, 0xd5, 0xd3, 0xfd, 0x50, 0x8b, 0xf6, - 0xea, 0xe9, 0x73, 0x50, 0x8b, 0xa8, 0x67, 0xce, 0x43, 0x2d, 0xa2, 0x76, 0xc6, 0xa0, 0xd6, 0x50, - 0x9f, 0xce, 0x5c, 0x84, 0x7a, 0x63, 0x37, 0x0e, 0xf9, 0xdd, 0x47, 0xd8, 0x82, 0x9a, 0x07, 0x36, - 0x99, 0x3d, 0x50, 0xab, 0x96, 0xc1, 0x87, 0xa1, 0x56, 0x95, 0x3b, 0x47, 0xa1, 0x56, 0x2d, 0x83, - 0xef, 0x87, 0x5a, 0x55, 0xee, 0x1c, 0x80, 0x5a, 0xb5, 0x0c, 0x7e, 0x0a, 0x6a, 0x55, 0xb9, 0xf3, - 0x04, 0xd4, 0xaa, 0x65, 0xf0, 0x7b, 0xa1, 0x56, 0x95, 0x3b, 0xa7, 0xa1, 0x56, 0x2d, 0x83, 0x9f, - 0x81, 0x5a, 0x55, 0xee, 0x9c, 0x85, 0x5a, 0xb5, 0x0c, 0xde, 0x0f, 0xb5, 0xaa, 0xdc, 0x39, 0x07, - 0xb5, 0x6a, 0x19, 0xfc, 0x3c, 0xd4, 0xaa, 0x72, 0x67, 0x0c, 0x6a, 0x51, 0xe3, 0x90, 0xbf, 0x08, - 0xf5, 0x86, 0x6e, 0x1c, 0x5c, 0x6b, 0xf7, 0x08, 0x5b, 0x50, 0xb4, 0x0c, 0xbe, 0x07, 0x6a, 0x55, - 0xb9, 0x33, 0x0c, 0xb5, 0xea, 0x99, 0x3b, 0x47, 0xa1, 0x56, 0x2d, 0x18, 0xee, 0x87, 0x5a, 0xb5, - 0x0c, 0x7e, 0x00, 0x6a, 0x55, 0xb9, 0x73, 0x0a, 0x6a, 0x55, 0x65, 0xf9, 0x04, 0xd4, 0xaa, 0x05, - 0xc3, 0x7b, 0xa1, 0x56, 0x2d, 0x83, 0x9f, 0x86, 0x5a, 0x55, 0xee, 0x9c, 0x81, 0x5a, 0x55, 0x59, - 0x9e, 0x85, 0x5a, 0xb5, 0x60, 0xd8, 0x0f, 0xb5, 0x6a, 0x19, 0xfc, 0x1c, 0xd4, 0xaa, 0x72, 0xe7, - 0x3c, 0xd4, 0xaa, 0xca, 0x72, 0x0c, 0x6a, 0x0d, 0xf5, 0x17, 0xad, 0x8b, 0x50, 0x6f, 0xec, 0xc6, - 0xc1, 0xde, 0x7d, 0x82, 0x2d, 0x28, 0x3a, 0x1b, 0x7c, 0x0f, 0xd4, 0xaa, 0x65, 0xf0, 0x61, 0xa8, - 0x55, 0xe5, 0xce, 0x51, 0xa8, 0x55, 0xcb, 0xe0, 0xfb, 0xa1, 0x56, 0x95, 0x3b, 0x07, 0xa0, 0x56, - 0x2d, 0x83, 0x9f, 0x82, 0x5a, 0x55, 0xee, 0x3c, 0x01, 0xb5, 0x6a, 0x19, 0xfc, 0x5e, 0xa8, 0x55, - 0xe5, 0xce, 0x69, 0xa8, 0x55, 0xcb, 0xe0, 0x67, 0xa0, 0x56, 0x95, 0x3b, 0x67, 0xa1, 0x56, 0x2d, - 0x83, 0xf7, 0x43, 0xad, 0x2a, 0x77, 0xce, 0x41, 0xad, 0x5a, 0x06, 0x3f, 0x0f, 0xb5, 0xaa, 0xdc, - 0x19, 0x83, 0x5a, 0xd4, 0x38, 0xd8, 0x17, 0xa1, 0xde, 0xa0, 0x8d, 0x83, 0x43, 0x08, 0x21, 0x84, - 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x72, 0xc3, 0xa1, 0x71, 0x20, - 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0xc8, 0xda, 0x43, - 0xe3, 0x40, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x90, - 0xb5, 0x87, 0xc6, 0x81, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, - 0x08, 0x21, 0x6b, 0x0f, 0x8d, 0x03, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0xd6, 0x1e, 0x1a, 0x07, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, - 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0xac, 0x3d, 0x34, 0x0e, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, - 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x59, 0x7b, 0x8c, 0x5b, 0x20, 0x47, 0x8f, 0x45, - 0xa2, 0x03, 0x87, 0x87, 0xfa, 0x16, 0xde, 0x36, 0x8d, 0x9d, 0xde, 0xe5, 0x58, 0x64, 0x30, 0x18, - 0x89, 0x2c, 0x5d, 0xcb, 0x34, 0x7b, 0xba, 0x1a, 0xdd, 0xfa, 0x5b, 0x0f, 0x7b, 0x17, 0x5d, 0xc6, - 0x8e, 0xca, 0x9b, 0x7e, 0x9f, 0xd9, 0xd6, 0xde, 0x61, 0x94, 0x2e, 0x3a, 0x7d, 0x9b, 0xee, 0x58, - 0x76, 0xf5, 0x0e, 0xef, 0xe5, 0xc9, 0xb1, 0xfe, 0xf2, 0x1b, 0xb7, 0x3d, 0x6c, 0x7a, 0x97, 0xbd, - 0xab, 0x8c, 0x7f, 0x95, 0x29, 0xf6, 0x96, 0x3e, 0x0f, 0x72, 0x4b, 0xa6, 0x7e, 0x7f, 0x6b, 0x5f, - 0xdc, 0xa9, 0x97, 0xb2, 0xa9, 0xe6, 0x1a, 0x6f, 0x55, 0x5e, 0xb7, 0x79, 0x2f, 0x45, 0x2f, 0xdf, - 0xea, 0x58, 0xf8, 0x48, 0xd1, 0x5f, 0x2c, 0x9a, 0xa6, 0x59, 0x44, 0x95, 0x90, 0x5b, 0xef, 0xd8, - 0xb1, 0x78, 0x1c, 0x28, 0x16, 0x4b, 0x97, 0xe6, 0x7a, 0xfd, 0xdb, 0xf0, 0xf7, 0x96, 0xfe, 0x57, - 0x3e, 0x4c, 0x55, 0xfe, 0x71, 0xed, 0x94, 0xee, 0x61, 0xa5, 0x97, 0xaa, 0x1f, 0xdd, 0x0b, 0x3f, - 0x41, 0x17, 0xde, 0xe1, 0x5f, 0x78, 0xbb, 0xf2, 0x63, 0xba, 0xeb, 0xb6, 0xcd, 0xb7, 0xdf, 0xb1, - 0xc5, 0xbf, 0xb5, 0x7e, 0x44, 0xdd, 0x0f, 0xf3, 0xa2, 0xbf, 0xf4, 0x93, 0xfb, 0xf0, 0xe3, 0xce, - 0x50, 0xf5, 0x95, 0x4c, 0xa3, 0xa7, 0xfc, 0x8f, 0xc1, 0xfe, 0x7d, 0xd1, 0xa1, 0xe8, 0x63, 0x03, - 0x83, 0x47, 0x4e, 0x54, 0x3e, 0x74, 0x77, 0xe9, 0x62, 0x74, 0xe0, 0xf8, 0xd0, 0xf1, 0x63, 0x23, - 0xa3, 0x4b, 0xb7, 0xf8, 0xc4, 0xfc, 0xad, 0x8e, 0x0c, 0xc5, 0x1e, 0x3d, 0x36, 0x30, 0x72, 0x68, - 0xe9, 0x7e, 0xce, 0x09, 0x1e, 0xec, 0x0c, 0x1f, 0x8b, 0x95, 0x3e, 0x99, 0xbd, 0x4b, 0xef, 0x29, - 0x7d, 0x92, 0xa6, 0xf7, 0xee, 0x13, 0xa3, 0x91, 0xc1, 0x23, 0x7b, 0x17, 0x1f, 0xed, 0xdc, 0x5d, - 0x75, 0xed, 0xbe, 0x26, 0xd7, 0xee, 0xab, 0xbd, 0xb6, 0x73, 0x62, 0x68, 0xa4, 0xf6, 0x2b, 0xed, - 0x29, 0xff, 0xe4, 0x39, 0x34, 0xf4, 0xa8, 0x73, 0xf8, 0xf0, 0xd0, 0xc8, 0x92, 0xd9, 0xae, 0x3f, - 0x36, 0x8d, 0x3b, 0xde, 0x7e, 0xcd, 0x3c, 0xd9, 0xe9, 0xbd, 0x71, 0xa7, 0x69, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0xa4, 0xe5, 0x42, 0xf7, 0x46, - 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0xb9, - 0xd1, 0xf8, 0xc8, 0x9a, 0x82, 0x3f, 0xfe, 0xf8, 0xe3, 0x8f, 0x3f, 0xfe, 0xf8, 0xe3, 0x8f, 0x3f, - 0xfe, 0xb7, 0xa6, 0xff, 0xc2, 0xbd, 0x55, 0x5e, 0x2f, 0x5c, 0x2c, 0xbe, 0xb1, 0xf8, 0xfe, 0xca, - 0xd0, 0xaa, 0xb7, 0x17, 0x5f, 0xfb, 0x1b, 0xdc, 0xdf, 0xc2, 0x7d, 0x55, 0x7f, 0xc1, 0xd5, 0xef, - 0xad, 0x9b, 0xeb, 0x5b, 0x76, 0x37, 0x8b, 0x9f, 0xcb, 0x7a, 0xec, 0x6d, 0xeb, 0xee, 0xbf, 0xf0, - 0xf9, 0x37, 0x7b, 0x69, 0x7e, 0x3d, 0x7f, 0xdd, 0xcb, 0xe2, 0xc7, 0xaa, 0x36, 0x49, 0xe3, 0xfb, - 0xaa, 0x71, 0x2b, 0xdf, 0x55, 0x53, 0xcf, 0xa5, 0xeb, 0x2d, 0x5d, 0xae, 0xf4, 0x79, 0x5d, 0xef, - 0xd7, 0x75, 0xd3, 0xf7, 0xff, 0x66, 0xfb, 0x57, 0x83, 0xfd, 0xac, 0xf6, 0xeb, 0x2a, 0xdf, 0xff, - 0xd2, 0xeb, 0xeb, 0xfb, 0x9a, 0x97, 0xde, 0xf6, 0xfb, 0xaf, 0xe5, 0x56, 0x7d, 0x8b, 0x15, 0xb6, - 0xa3, 0xaf, 0xe1, 0xf7, 0xd7, 0x35, 0xbe, 0xae, 0x9b, 0xec, 0xbf, 0xea, 0xdb, 0x2f, 0xf7, 0xf7, - 0xf9, 0x2b, 0x3b, 0xfb, 0xc2, 0xeb, 0x26, 0x2f, 0xfe, 0x86, 0x87, 0x07, 0xff, 0xb2, 0xfd, 0xbb, - 0xfe, 0xfd, 0xcb, 0x0f, 0x68, 0xd7, 0xf0, 0x5f, 0x76, 0x37, 0x1f, 0xc3, 0x71, 0xf9, 0xff, 0xf1, - 0xfe, 0x5f, 0x7b, 0xfc, 0x5f, 0xc9, 0x7f, 0x25, 0xb7, 0x46, 0xdb, 0xb9, 0x7e, 0xdf, 0xaf, 0x3f, - 0xfe, 0xf8, 0x1a, 0x1f, 0xff, 0x6f, 0xe8, 0xeb, 0xda, 0xb8, 0xc7, 0xff, 0xa6, 0xfe, 0xf5, 0xc7, - 0xff, 0x26, 0x3c, 0x8d, 0x8f, 0x1b, 0xcd, 0x3f, 0x8f, 0xc6, 0xc7, 0xff, 0x9a, 0xc7, 0x03, 0xbe, - 0x0d, 0x78, 0xfc, 0x5f, 0xf7, 0xc7, 0x3f, 0xd5, 0xfb, 0xf9, 0xea, 0x1f, 0xff, 0x2c, 0x7b, 0x5c, - 0xd3, 0x74, 0xff, 0x5d, 0x7a, 0xf7, 0x3a, 0x3c, 0x00, 0xe2, 0xf1, 0x3f, 0x8f, 0xff, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0xff, 0x8d, 0xe6, 0x5f, 0xf7, - 0xfb, 0x66, 0xb3, 0x75, 0xaf, 0x9a, 0xdf, 0xf6, 0x1b, 0xdc, 0x7e, 0xf9, 0xfa, 0x70, 0xf9, 0x1f, - 0x4b, 0xaf, 0x7d, 0x8d, 0x7f, 0xc1, 0x6f, 0xfa, 0x7b, 0x6c, 0xc3, 0xd5, 0xcb, 0x1b, 0xe8, 0x01, - 0x1a, 0xff, 0xbe, 0xed, 0x6f, 0xb2, 0x00, 0x58, 0xf3, 0xf1, 0x06, 0x5f, 0xc7, 0xc7, 0xed, 0x5f, - 0xbf, 0xde, 0xbe, 0xb0, 0x74, 0xd0, 0x7c, 0xdd, 0xdd, 0xef, 0x5b, 0x69, 0x5d, 0xac, 0xd1, 0xba, - 0x8c, 0xaf, 0xc1, 0xed, 0x56, 0x7b, 0xfb, 0xe5, 0xfe, 0x6b, 0xed, 0x01, 0x96, 0xdf, 0x7b, 0xfd, - 0xf5, 0x1b, 0xed, 0x8b, 0xcb, 0x16, 0x37, 0x3e, 0x46, 0xff, 0xea, 0x1d, 0x71, 0xf9, 0x7a, 0x70, - 0x83, 0x75, 0xe3, 0x95, 0xd7, 0x9f, 0x1b, 0xae, 0xcb, 0xaf, 0x74, 0xdc, 0x6b, 0xb2, 0x86, 0xd7, - 0xa0, 0x85, 0xb9, 0xf1, 0x1e, 0x60, 0x25, 0x7f, 0x9f, 0xef, 0x66, 0xfa, 0x2f, 0xfb, 0xfe, 0xf4, - 0x35, 0x5e, 0x8f, 0x5f, 0x3c, 0x8e, 0xf8, 0x1b, 0x1d, 0x7f, 0x9a, 0x1d, 0x3f, 0xaa, 0xd6, 0x99, - 0xfd, 0x8d, 0x17, 0x18, 0x1b, 0xdc, 0xde, 0x7f, 0xed, 0xe3, 0xcf, 0xea, 0x7b, 0x80, 0x95, 0x3f, - 0x2f, 0x5f, 0x93, 0xe5, 0xbf, 0xfa, 0xbb, 0x6f, 0x78, 0x98, 0xfa, 0x18, 0x8f, 0x3f, 0xd5, 0xbd, - 0x55, 0xe3, 0xc3, 0x73, 0xf3, 0x35, 0xf5, 0xfa, 0xaf, 0xbc, 0xe9, 0x7e, 0xb6, 0x8a, 0xfd, 0xff, - 0x5a, 0x7b, 0xe8, 0x0d, 0xf7, 0x00, 0x4d, 0xee, 0xbd, 0xd9, 0xbf, 0x57, 0xde, 0x0b, 0xd6, 0xe5, - 0xf8, 0xef, 0x6b, 0x72, 0xfc, 0x5f, 0xd6, 0xdb, 0xfa, 0x1a, 0xde, 0xbe, 0xfe, 0xf8, 0xbb, 0x3a, - 0xff, 0x1b, 0x3d, 0xfe, 0xaf, 0xb6, 0x07, 0xb8, 0x96, 0xff, 0x0a, 0xc7, 0xff, 0x9a, 0x4f, 0x79, - 0xbd, 0xfc, 0xaf, 0xfd, 0xf8, 0xa7, 0x71, 0xbf, 0xb2, 0xfc, 0xf6, 0xf5, 0xdf, 0xcf, 0xb5, 0xeb, - 0xef, 0xd7, 0xfb, 0xf8, 0xa7, 0xc9, 0xe3, 0x8e, 0xeb, 0xee, 0x01, 0xfc, 0x4d, 0x1e, 0x4f, 0x35, - 0x7f, 0xfc, 0xd3, 0xe8, 0xb8, 0xb0, 0x7e, 0x8f, 0x7f, 0x08, 0xbf, 0x7f, 0xe1, 0x4f, 0xf0, 0xc7, - 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0xb2, 0xbe, 0xfe, 0xcb, 0xcf, 0xbf, 0x5f, 0xb6, 0x5e, - 0xe6, 0x63, 0x33, 0xad, 0xa7, 0x7f, 0x9d, 0xf1, 0xd2, 0xef, 0xf5, 0x0d, 0xcf, 0x3f, 0x26, 0xeb, - 0xeb, 0xbf, 0xc6, 0xf3, 0x51, 0xf1, 0x5f, 0xc3, 0xf1, 0xa7, 0x7e, 0x9d, 0x6c, 0x1d, 0x9f, 0xb7, - 0x83, 0x7f, 0xdd, 0x3a, 0x7f, 0xb3, 0xfd, 0x9f, 0xbd, 0x7f, 0xdd, 0x8f, 0x3f, 0xcb, 0xd6, 0xb7, - 0x6b, 0xd7, 0xff, 0x9b, 0x35, 0x74, 0xe4, 0xe3, 0x3d, 0xfe, 0xd7, 0x1e, 0x77, 0x96, 0x0e, 0x3b, - 0xf8, 0xf3, 0xf8, 0xbf, 0x65, 0xfd, 0xd9, 0x0e, 0xf8, 0xe3, 0x8f, 0x3f, 0xfe, 0xf8, 0x13, 0xfc, - 0xf1, 0x27, 0xf8, 0xf3, 0xfb, 0x17, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, - 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, 0xf0, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, - 0xfc, 0xf1, 0x47, 0x10, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, - 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0x11, 0xc4, 0x1f, 0x7f, - 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0xf1, - 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0x04, 0xf1, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, - 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0xfc, 0x09, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0xb2, 0xbe, 0x31, - 0xfe, 0x0f, 0x12, 0x0a, 0x67, 0x72 +int reset_basic_snap_zlib_length = 118534; +uint8 reset_basic_snap_zlib[118534] = { + 0x5a, 0x4c, 0x00, 0x0d, 0x94, 0x2f, 0x00, 0x01, 0xce, 0xfc, 0x78, 0xda, 0xec, 0xbd, 0x7f, 0x54, + 0x62, 0x59, 0x9e, 0x27, 0x68, 0x44, 0x46, 0xd6, 0x64, 0xd7, 0x4e, 0x77, 0xe5, 0x54, 0xf5, 0xe9, + 0xdd, 0xee, 0xb3, 0x3b, 0x27, 0xb6, 0x36, 0x4d, 0x1b, 0x2d, 0x23, 0xaa, 0x22, 0xd2, 0xb0, 0xd5, + 0x34, 0xcc, 0xda, 0xaa, 0xda, 0x6e, 0x20, 0xd1, 0x3e, 0xc0, 0x83, 0x01, 0x04, 0x66, 0xcf, 0x84, + 0xba, 0x80, 0xc0, 0x1e, 0x15, 0x38, 0x82, 0x10, 0x71, 0xce, 0xce, 0xcc, 0xce, 0x39, 0xbb, 0xfd, + 0x47, 0xab, 0xc8, 0x84, 0x08, 0xf4, 0xe9, 0x0e, 0x64, 0x78, 0xcf, 0x07, 0x3b, 0xe0, 0x83, 0x01, + 0x7c, 0xd0, 0xff, 0xcd, 0x8a, 0x89, 0xf4, 0x88, 0xef, 0xb1, 0x80, 0xc0, 0xec, 0x99, 0x40, 0x16, + 0x10, 0xa8, 0x52, 0x81, 0xa3, 0x04, 0xc6, 0x1a, 0x11, 0xf5, 0x23, 0xab, 0x22, 0x23, 0x7f, 0x1a, + 0x91, 0x1a, 0xc9, 0x07, 0xe5, 0xfb, 0xde, 0xe3, 0xbe, 0xfb, 0xee, 0xfd, 0xde, 0x5f, 0xdf, 0xef, + 0xf7, 0x7e, 0xef, 0x7d, 0x0c, 0xe2, 0x4f, 0x7e, 0x76, 0x95, 0x26, 0xf9, 0x9f, 0xff, 0xd7, 0xc9, + 0xff, 0x45, 0x3a, 0x75, 0xf5, 0x7f, 0x12, 0x8c, 0x8f, 0xfc, 0xc9, 0xe5, 0x96, 0x9f, 0xdc, 0x7a, + 0x8f, 0xf6, 0x93, 0x96, 0xdf, 0x80, 0xf1, 0x24, 0x10, 0x63, 0x64, 0x62, 0x52, 0x20, 0x95, 0xfc, + 0xc9, 0x1b, 0xdf, 0x7e, 0x76, 0x91, 0xf2, 0x63, 0xe2, 0xe0, 0x4f, 0xfe, 0x12, 0xf8, 0x75, 0xa0, + 0x4b, 0x57, 0xd4, 0xa7, 0xdf, 0xdf, 0xf3, 0xfc, 0xed, 0xa5, 0x67, 0xe7, 0xdf, 0x3e, 0x08, 0x65, + 0xbe, 0xff, 0xf3, 0x4b, 0x2d, 0xcf, 0x61, 0x4b, 0xfb, 0xb7, 0xbf, 0x75, 0x35, 0xbc, 0xf0, 0xb7, + 0x9f, 0x10, 0xea, 0x37, 0x78, 0xeb, 0xf4, 0xff, 0x8f, 0xbe, 0xff, 0xec, 0xf8, 0xdf, 0xfe, 0xfb, + 0xbf, 0x7a, 0x1a, 0xf6, 0x34, 0x85, 0x94, 0x9f, 0x51, 0x3e, 0x16, 0xe8, 0x12, 0xa1, 0xe5, 0x52, + 0x4b, 0xf7, 0xf5, 0xa7, 0xc7, 0xe0, 0xbf, 0xff, 0x6b, 0xe7, 0xf7, 0x9f, 0xde, 0xf0, 0xf8, 0x57, + 0x3f, 0xff, 0xf1, 0x1f, 0xb5, 0x7c, 0x5b, 0xfe, 0x77, 0xcf, 0x8e, 0xe5, 0x7f, 0xe7, 0x44, 0x9f, + 0xdd, 0xf3, 0xd6, 0x1b, 0x4f, 0x3f, 0x2d, 0x7f, 0x73, 0x7a, 0xf2, 0x37, 0xbf, 0xf5, 0xbc, 0x96, + 0x77, 0x3e, 0x16, 0xf7, 0x1b, 0x1f, 0xfe, 0xea, 0xe8, 0xd1, 0x93, 0x7c, 0xc9, 0xff, 0xee, 0x8f, + 0x5b, 0xae, 0xb6, 0xb4, 0xdc, 0x3b, 0x3d, 0xbe, 0xd2, 0x22, 0x6f, 0xb9, 0xf7, 0x77, 0xbb, 0xca, + 0x7f, 0xb8, 0xbc, 0xab, 0x82, 0x5b, 0xde, 0x5a, 0xef, 0xfd, 0xbf, 0xbe, 0xbd, 0x7e, 0xf5, 0xe7, + 0xe5, 0x3f, 0xcb, 0xfd, 0xf0, 0xcf, 0x72, 0xff, 0xf0, 0xcf, 0xef, 0x0d, 0xfd, 0x47, 0xea, 0x3f, + 0xfb, 0x4d, 0x1a, 0xde, 0x78, 0x76, 0xcf, 0xb7, 0xbe, 0xfd, 0x3b, 0xf9, 0x7b, 0xff, 0x8d, 0xdf, + 0x3e, 0xff, 0x9b, 0x1f, 0x36, 0x3e, 0x78, 0x12, 0xae, 0xe5, 0x83, 0x96, 0x4b, 0x57, 0x2f, 0xb5, + 0xfc, 0xfc, 0x4a, 0x4b, 0x4b, 0xdb, 0xe9, 0x4d, 0xff, 0xf2, 0x19, 0xfe, 0xd5, 0x53, 0xfc, 0xeb, + 0x67, 0xf8, 0xdf, 0x9f, 0xe2, 0xe7, 0xff, 0xcf, 0x6f, 0x6e, 0xbe, 0x7a, 0xf3, 0xcf, 0x7a, 0x7e, + 0xf4, 0xa3, 0x96, 0x1f, 0x9e, 0xe2, 0xf1, 0x29, 0x9e, 0x32, 0xe1, 0x3c, 0xd2, 0x4b, 0x6f, 0x7f, + 0x95, 0xfb, 0xd5, 0xf9, 0x27, 0x9f, 0xab, 0xea, 0xfc, 0x29, 0x2f, 0xbf, 0xff, 0x9f, 0x32, 0x2d, + 0xdf, 0xfe, 0xc3, 0xff, 0xf7, 0x8e, 0xf9, 0x5f, 0x3d, 0x98, 0x5e, 0x5e, 0xfa, 0x2f, 0x2d, 0x5f, + 0x3b, 0x9e, 0xd4, 0xa7, 0x3f, 0xf8, 0x83, 0x2b, 0xdf, 0x6e, 0x39, 0xfd, 0x6b, 0xf9, 0x8b, 0xc2, + 0x27, 0x86, 0xb9, 0xf4, 0xd2, 0x9e, 0xfe, 0x7f, 0xfc, 0x97, 0xff, 0xed, 0xc1, 0x8c, 0xf9, 0x4f, + 0x2c, 0x0f, 0x2d, 0xff, 0xda, 0xf6, 0xe4, 0xfc, 0xc3, 0xbf, 0x70, 0xb4, 0xfc, 0x28, 0x3f, 0x7a, + 0xf2, 0xe7, 0x27, 0xa4, 0x83, 0xbf, 0xde, 0xff, 0x83, 0xfd, 0xbf, 0xdc, 0xbf, 0x79, 0xc0, 0xfc, + 0x45, 0xf0, 0x17, 0xc5, 0xea, 0xed, 0x5f, 0x5c, 0x3f, 0x18, 0x3d, 0x31, 0x1f, 0x16, 0x2b, 0x2d, + 0xaf, 0x11, 0xae, 0x7e, 0x01, 0xb4, 0x9f, 0xe2, 0xea, 0x1b, 0xdf, 0xf9, 0xfd, 0xdf, 0xff, 0xce, + 0x95, 0xef, 0x7c, 0xf7, 0xcd, 0xab, 0xb7, 0xde, 0xbb, 0x7a, 0xf9, 0xd2, 0xf7, 0x7e, 0xef, 0x8d, + 0xab, 0x7f, 0x74, 0xe3, 0xd9, 0x4f, 0x5f, 0x08, 0xb7, 0xde, 0xfb, 0xaf, 0xae, 0x7e, 0xf7, 0xd2, + 0xef, 0x5f, 0xfd, 0xde, 0x1f, 0x7f, 0xef, 0x0f, 0xdf, 0xfc, 0xfd, 0xab, 0xcf, 0x1a, 0xe2, 0x2f, + 0x23, 0xbc, 0xfc, 0xc7, 0x7f, 0xf8, 0xe6, 0xf7, 0xae, 0x7e, 0xeb, 0xbb, 0x6f, 0xbe, 0xf9, 0xb9, + 0xa3, 0xfb, 0xee, 0x9b, 0x97, 0xae, 0xfc, 0xf1, 0xb5, 0xcf, 0x0e, 0xf7, 0x37, 0x57, 0x9b, 0x68, + 0xe2, 0x9b, 0x87, 0x17, 0x8f, 0x0f, 0x2d, 0xdf, 0x6e, 0x31, 0xde, 0xf8, 0xe1, 0xad, 0xf7, 0x9e, + 0xf5, 0x07, 0xd6, 0xab, 0x7f, 0xdb, 0x62, 0x68, 0xb9, 0x62, 0x68, 0x79, 0xd3, 0xd0, 0xf2, 0x2d, + 0x43, 0xcb, 0x3f, 0xfa, 0xff, 0xfe, 0xe1, 0x17, 0x56, 0xf0, 0xaf, 0x5a, 0xfe, 0xde, 0xea, 0xfb, + 0xab, 0x4b, 0x7f, 0x6f, 0xfd, 0xe8, 0xaf, 0x2e, 0xff, 0xbd, 0x35, 0xf9, 0x57, 0x6f, 0xfc, 0xfd, + 0x87, 0xdd, 0x6f, 0x7d, 0xea, 0xb8, 0x73, 0xef, 0x15, 0x8f, 0x8f, 0x57, 0xcf, 0xe9, 0xb8, 0x7d, + 0x46, 0xf4, 0xde, 0x6b, 0x97, 0xaf, 0xab, 0xaf, 0x75, 0x79, 0x9d, 0x63, 0x7a, 0xf9, 0x73, 0x85, + 0xbb, 0xfc, 0xdb, 0xe7, 0x57, 0x5e, 0x1c, 0xfe, 0x52, 0x93, 0xaf, 0x5f, 0x90, 0xde, 0xfd, 0xba, + 0x9e, 0x5f, 0x7f, 0x5d, 0xf8, 0x58, 0x3e, 0x67, 0xe9, 0x69, 0xbc, 0xd4, 0xf4, 0x97, 0x1f, 0x9f, + 0x9c, 0xcf, 0x72, 0x48, 0xbf, 0xaa, 0xfb, 0x9f, 0xe5, 0x3f, 0xdd, 0xec, 0x3f, 0x3e, 0x8d, 0xa6, + 0x4f, 0x3b, 0x96, 0xdf, 0xbd, 0xfe, 0xc1, 0x59, 0xc5, 0x7f, 0xe5, 0x6b, 0xc9, 0x57, 0xe0, 0xdc, + 0x8f, 0x93, 0x2f, 0x57, 0x9e, 0xfd, 0xdd, 0x7e, 0xa2, 0xfe, 0x5b, 0xe7, 0x27, 0x67, 0xf2, 0xbc, + 0x7b, 0x9f, 0x19, 0xae, 0x71, 0xe6, 0xf9, 0xab, 0x9f, 0x41, 0x3c, 0x1f, 0x9c, 0x4d, 0x7a, 0xde, + 0x6e, 0xf6, 0x1f, 0x5f, 0x7f, 0x3b, 0x3f, 0xb7, 0xfa, 0xd3, 0xab, 0xd0, 0xbb, 0xee, 0x7e, 0x56, + 0xb8, 0x74, 0x53, 0x5f, 0x6b, 0xd2, 0x97, 0x45, 0xef, 0x7d, 0xe2, 0xf5, 0x0f, 0x3e, 0x8f, 0x3c, + 0xd6, 0xe4, 0xdf, 0x57, 0xa7, 0xf7, 0x2e, 0x42, 0x3a, 0xef, 0x7e, 0xea, 0xef, 0x8d, 0x0b, 0xc9, + 0xff, 0xb7, 0xce, 0x71, 0xfa, 0x6a, 0x9f, 0xc7, 0xee, 0x72, 0xbe, 0xe9, 0xd5, 0xa6, 0xfd, 0xf4, + 0xeb, 0xa4, 0x97, 0x9a, 0xfd, 0xeb, 0x59, 0xd5, 0xd7, 0x17, 0xea, 0x81, 0x81, 0x57, 0x96, 0xbe, + 0xc6, 0xb9, 0xe0, 0x53, 0xe0, 0x15, 0x3f, 0xef, 0xe4, 0xf3, 0x87, 0x4f, 0x7f, 0x96, 0x3c, 0x73, + 0x06, 0xf4, 0x6a, 0xb3, 0x9d, 0xfc, 0x2e, 0x3d, 0xf9, 0xd2, 0xf7, 0x5f, 0xbd, 0xe8, 0x7a, 0xe4, + 0xd7, 0x23, 0xb7, 0xd5, 0x9b, 0xf5, 0xee, 0xd5, 0xd3, 0xbb, 0x5f, 0xa0, 0x3e, 0x5f, 0x7a, 0xb5, + 0xf2, 0x46, 0xfa, 0x0b, 0x85, 0xaf, 0x9d, 0x4b, 0x39, 0xeb, 0x5e, 0xb3, 0x9e, 0x5d, 0xbc, 0xfa, + 0x7e, 0xc6, 0xf4, 0xab, 0xda, 0x13, 0x6a, 0xe7, 0x5e, 0xee, 0xbe, 0xf4, 0xea, 0xc7, 0xe1, 0xbb, + 0x17, 0xa8, 0xde, 0x7d, 0x70, 0x76, 0xf1, 0xbd, 0x75, 0xc1, 0xdb, 0xdf, 0xcb, 0xe9, 0x0f, 0x2f, + 0x7f, 0xb3, 0xed, 0x99, 0x9f, 0x9f, 0x7e, 0xd0, 0x1c, 0x07, 0xce, 0x11, 0x1f, 0xee, 0x35, 0xc7, + 0xe3, 0xd7, 0x98, 0x36, 0xbe, 0x99, 0xf9, 0x6e, 0xbc, 0xac, 0xf8, 0x3f, 0xd3, 0xbf, 0x2b, 0xf0, + 0x4d, 0xaf, 0x77, 0x97, 0xbf, 0x48, 0xf8, 0xf4, 0xcb, 0x9b, 0xdf, 0xf9, 0x52, 0x76, 0xfd, 0xbb, + 0x17, 0x97, 0xef, 0x6f, 0x35, 0xed, 0x6c, 0x5f, 0xc5, 0x5f, 0xb0, 0x49, 0xbf, 0x9a, 0x7d, 0xf8, + 0xa2, 0xd3, 0xbb, 0xcd, 0x7a, 0xfb, 0xcd, 0xf4, 0x5b, 0xfa, 0xa2, 0xfe, 0x70, 0x67, 0x29, 0x2f, + 0xa7, 0x9b, 0xfd, 0xcc, 0x85, 0xa2, 0xb5, 0x2f, 0x55, 0xae, 0x67, 0x3a, 0x5f, 0xf6, 0x92, 0xe5, + 0xcb, 0x7a, 0xb3, 0x9c, 0xbf, 0xe2, 0xbc, 0xdb, 0xf3, 0xf4, 0x42, 0xf3, 0xe2, 0xd2, 0xc5, 0x5b, + 0x03, 0xd8, 0x78, 0x2d, 0xea, 0xde, 0xa7, 0xca, 0x5e, 0x97, 0x5e, 0xa1, 0x0d, 0xb4, 0x7c, 0xae, + 0x6c, 0xc2, 0xf7, 0xea, 0x17, 0xa9, 0xbd, 0x5c, 0x18, 0x7a, 0xa5, 0xe9, 0x63, 0xff, 0x05, 0x69, + 0xe3, 0x6b, 0x4b, 0x7f, 0xed, 0xfc, 0xfa, 0x54, 0xde, 0xfb, 0x74, 0x9f, 0xa6, 0x97, 0xe6, 0x33, + 0xf7, 0xc1, 0x99, 0xf9, 0x4a, 0xbe, 0xfd, 0xb2, 0x6c, 0x57, 0xf5, 0x6f, 0xb8, 0x4c, 0x95, 0xae, + 0x9d, 0x61, 0x3d, 0xfb, 0xb2, 0xf7, 0xbf, 0xdd, 0x94, 0x6d, 0x5f, 0xdd, 0x5a, 0xd4, 0xbb, 0x67, + 0xd3, 0xce, 0x5e, 0x89, 0x2f, 0xee, 0x5b, 0xaf, 0x67, 0xb9, 0x9d, 0xe7, 0x39, 0xe9, 0xf4, 0x6b, + 0x61, 0x4b, 0x7f, 0xad, 0xe6, 0x82, 0xcf, 0xaf, 0xcf, 0xc0, 0x19, 0xd2, 0xf2, 0xab, 0x79, 0x4e, + 0xf9, 0x25, 0xd8, 0x76, 0x2f, 0xc6, 0x5a, 0x95, 0x72, 0x73, 0xbc, 0x7c, 0x5d, 0xe9, 0x07, 0x5f, + 0x71, 0x3c, 0x7f, 0xeb, 0x95, 0x8e, 0xbf, 0xe5, 0xf3, 0xa0, 0xd7, 0xd6, 0xcf, 0x4a, 0xdf, 0x68, + 0xd2, 0x26, 0xfd, 0x86, 0xad, 0x05, 0x79, 0x35, 0x34, 0x70, 0xb6, 0xfa, 0x7b, 0xe3, 0xc2, 0xae, + 0xed, 0xaf, 0xbd, 0x68, 0xce, 0xf3, 0x82, 0x96, 0x6f, 0xe0, 0x4c, 0x7c, 0xb4, 0xd3, 0xcd, 0x76, + 0xf2, 0xa5, 0x7c, 0xed, 0x1a, 0xaf, 0x6f, 0xbe, 0xdf, 0xbe, 0x28, 0xe9, 0xfd, 0x62, 0xf6, 0xae, + 0xc6, 0xe7, 0x97, 0xd7, 0x2e, 0xa8, 0xfd, 0xe2, 0x33, 0xd7, 0x14, 0x5e, 0xba, 0xf0, 0x7b, 0x53, + 0x7c, 0x25, 0x9f, 0x92, 0x57, 0x51, 0xde, 0xb5, 0x57, 0x59, 0x8f, 0xae, 0x5e, 0xc0, 0xf6, 0xfb, + 0x59, 0xf3, 0xd7, 0x67, 0xe9, 0xa3, 0x71, 0xe9, 0xca, 0x39, 0xf4, 0xd1, 0x4e, 0x7f, 0x89, 0x7c, + 0x7c, 0x6d, 0xbe, 0xd7, 0x67, 0xe7, 0xc3, 0x75, 0x72, 0x7e, 0xe7, 0x23, 0x5f, 0x17, 0xfb, 0xfa, + 0x73, 0xf6, 0x8b, 0xcb, 0x17, 0x7a, 0x5e, 0xbc, 0xa9, 0xd7, 0x7d, 0x09, 0x3b, 0xf3, 0x57, 0xda, + 0xd3, 0xf1, 0xa5, 0xec, 0x65, 0xf8, 0x05, 0x7d, 0x8f, 0x2f, 0x9a, 0x7d, 0xb5, 0xfe, 0x2a, 0xf5, + 0xd5, 0x26, 0xfd, 0xca, 0x7b, 0x06, 0x5f, 0x64, 0x9f, 0xf1, 0xe6, 0x1e, 0x8a, 0x17, 0x71, 0x6d, + 0x7a, 0x93, 0x9e, 0x17, 0x5f, 0xe5, 0x0b, 0x4c, 0x03, 0x2f, 0x71, 0x8f, 0x97, 0xb7, 0xcf, 0xb0, + 0x1d, 0xd6, 0xbf, 0x7a, 0x7e, 0xaf, 0x9c, 0x4d, 0xbf, 0xfc, 0xca, 0xd7, 0x3c, 0x9d, 0xa3, 0xb5, + 0xe6, 0x57, 0x2e, 0x46, 0x7b, 0xbb, 0xf4, 0x4d, 0x6c, 0xcf, 0x5f, 0x5e, 0xae, 0x7b, 0xa9, 0xfe, + 0x7d, 0xe5, 0x33, 0xae, 0x47, 0xaf, 0x7c, 0x0f, 0x9f, 0xd7, 0x6a, 0xef, 0xc2, 0x0b, 0xb7, 0x36, + 0xfb, 0x22, 0xcc, 0x87, 0x7c, 0x70, 0xae, 0xd2, 0x53, 0x7e, 0x19, 0xeb, 0x5f, 0x4e, 0xbe, 0xbe, + 0xf6, 0x7b, 0xb6, 0xfe, 0x67, 0x81, 0x33, 0x8a, 0xe7, 0x4c, 0xe7, 0x37, 0xbf, 0x88, 0xbd, 0xec, + 0x6e, 0xb3, 0x7f, 0xb8, 0x68, 0xfa, 0xfc, 0xb9, 0xa5, 0x97, 0xbf, 0xc9, 0xf9, 0x3f, 0xcf, 0x7b, + 0xce, 0x5c, 0x79, 0x36, 0x9f, 0x75, 0xef, 0x7c, 0xec, 0xb5, 0x7a, 0xe5, 0x15, 0x8c, 0xf3, 0x5f, + 0xff, 0x7a, 0xb3, 0xf4, 0xd9, 0x3f, 0xff, 0x55, 0xda, 0xd5, 0x02, 0x9f, 0x33, 0x5c, 0xed, 0x6b, + 0xb1, 0x2b, 0xbc, 0xac, 0x79, 0xb6, 0xf2, 0x37, 0xb1, 0xff, 0x3a, 0x6f, 0xeb, 0x53, 0xee, 0xbd, + 0x0c, 0x79, 0xab, 0x39, 0x76, 0x9e, 0x23, 0x7a, 0x31, 0xde, 0xab, 0x53, 0x7b, 0x7d, 0x6d, 0x4a, + 0x1f, 0xbc, 0x54, 0x1f, 0x8a, 0x0b, 0x3d, 0xb7, 0x74, 0xf5, 0x65, 0xad, 0x4d, 0x7a, 0x39, 0xb6, + 0x99, 0xaf, 0x7b, 0xcd, 0xda, 0x07, 0x17, 0x6b, 0xce, 0xfc, 0x15, 0xf8, 0xd6, 0x3d, 0x91, 0x4d, + 0x2e, 0x7f, 0xf1, 0xfb, 0x3e, 0xdf, 0x1a, 0x94, 0xab, 0x17, 0xa3, 0x9f, 0xbf, 0xf7, 0xe5, 0x7c, + 0x2b, 0x6b, 0x67, 0xe1, 0x8b, 0x79, 0xf7, 0xe2, 0xd8, 0xd6, 0x5e, 0xc7, 0x7d, 0xc9, 0xbf, 0x06, + 0x1d, 0xe4, 0xeb, 0xdf, 0x73, 0xe3, 0x1c, 0xfb, 0x80, 0xdd, 0x7b, 0x75, 0xf2, 0x4f, 0xf9, 0x6b, + 0x19, 0x6f, 0x5e, 0xf2, 0x9c, 0xc7, 0x57, 0xb2, 0x4d, 0x5f, 0x6e, 0xf6, 0x2f, 0xaf, 0xcd, 0xda, + 0xb3, 0xb3, 0xb0, 0x39, 0x35, 0x7d, 0x45, 0x5f, 0xcf, 0xf7, 0x31, 0x5e, 0xc0, 0x76, 0x7e, 0xb9, + 0x59, 0x5f, 0xce, 0x77, 0x79, 0x7f, 0xed, 0x6b, 0x09, 0xea, 0xcd, 0x72, 0xfe, 0x06, 0xd0, 0x0f, + 0xce, 0x67, 0x3d, 0x7e, 0xab, 0x59, 0x3e, 0x4d, 0xda, 0xa4, 0x67, 0xa9, 0xcf, 0xbd, 0x7a, 0xfa, + 0x6a, 0xe6, 0x96, 0x03, 0x67, 0xb0, 0x07, 0xec, 0xd5, 0x2f, 0x68, 0xd7, 0x3a, 0x5f, 0xbe, 0xd3, + 0xcd, 0x3d, 0xc6, 0xce, 0xb9, 0xaf, 0xc7, 0x5b, 0x2f, 0x6d, 0x8f, 0xa1, 0x7b, 0x57, 0x9a, 0x6b, + 0x4d, 0x9a, 0xb4, 0xa9, 0x6f, 0x7e, 0x16, 0x05, 0x2e, 0xe0, 0x5e, 0x22, 0x9a, 0xd7, 0xa2, 0xfc, + 0x1b, 0xaf, 0x4d, 0x3d, 0x2e, 0x9f, 0x4b, 0x9f, 0x99, 0x73, 0xb1, 0xa7, 0xf5, 0x8f, 0xbf, 0x9a, + 0x8f, 0xd8, 0xa5, 0x66, 0xff, 0xf8, 0x2a, 0xdf, 0x53, 0x74, 0xde, 0xfc, 0x6f, 0xee, 0x36, 0xcb, + 0xf7, 0x42, 0xca, 0xe7, 0xe9, 0xf3, 0x91, 0xaf, 0xbb, 0x5f, 0x47, 0x3c, 0x57, 0xce, 0x6f, 0x39, + 0x07, 0xbe, 0xf4, 0xfc, 0xfe, 0x59, 0xea, 0xb7, 0xb5, 0x0b, 0xdc, 0x4e, 0x9a, 0xe3, 0x51, 0x93, + 0x9e, 0x33, 0x7f, 0xab, 0xb7, 0xbe, 0xf8, 0xda, 0xae, 0xa6, 0x8f, 0xfc, 0xe7, 0xa2, 0x27, 0x67, + 0x1c, 0xee, 0xfc, 0xfa, 0x37, 0x07, 0x5e, 0x8e, 0xdc, 0x78, 0xe6, 0x7e, 0x5a, 0x67, 0x2d, 0x57, + 0x94, 0xcf, 0x70, 0x7e, 0xec, 0xea, 0xd9, 0x8e, 0xa3, 0x97, 0xce, 0x87, 0x3e, 0xfb, 0xda, 0xfa, + 0xe1, 0x7f, 0xf0, 0x55, 0xf7, 0x1c, 0xbb, 0xf7, 0x4d, 0x1e, 0xff, 0xee, 0x35, 0xe5, 0x80, 0x4f, + 0x7f, 0xc7, 0xe2, 0x97, 0xda, 0xeb, 0xe2, 0x1c, 0xbd, 0xdf, 0xf5, 0xf2, 0x27, 0xb7, 0xb3, 0xb3, + 0xf0, 0x07, 0xbe, 0xfb, 0xb8, 0x39, 0x0f, 0x75, 0x91, 0xe9, 0x85, 0xd0, 0xdf, 0xbe, 0x9c, 0x3f, + 0x7f, 0xed, 0xdc, 0xd9, 0x4f, 0xcf, 0x09, 0x7d, 0xbb, 0xc9, 0x87, 0xf3, 0xbc, 0x47, 0xda, 0x37, + 0x44, 0x7e, 0x39, 0x33, 0xb9, 0xb4, 0xfe, 0x79, 0xc6, 0xe1, 0xda, 0xe7, 0xec, 0x27, 0x2e, 0x1a, + 0xfd, 0x6a, 0x7a, 0xfa, 0x45, 0xf0, 0xbf, 0x0b, 0x34, 0xfb, 0x93, 0x57, 0x4b, 0xcb, 0x67, 0x22, + 0x3f, 0x34, 0xbe, 0xb4, 0xbc, 0xfd, 0x15, 0xe6, 0x89, 0xbe, 0x52, 0xde, 0x3f, 0x9f, 0xef, 0xce, + 0xbd, 0x8b, 0x5d, 0xc6, 0x57, 0xcf, 0xae, 0xed, 0x5f, 0x7a, 0x5d, 0xea, 0xfc, 0xe7, 0xef, 0x43, + 0x9b, 0xfb, 0xbf, 0x7e, 0xed, 0x3a, 0xef, 0x07, 0xe7, 0xca, 0xa6, 0x5f, 0x3e, 0x37, 0xfc, 0x3f, + 0xbf, 0xfd, 0xd2, 0xbd, 0xb3, 0xd7, 0x5d, 0xca, 0xaf, 0xf3, 0x1c, 0xd0, 0x37, 0x57, 0xd7, 0xa9, + 0x5d, 0xd0, 0xfc, 0x9f, 0xfd, 0x1a, 0xaa, 0xf4, 0x6b, 0x59, 0x4f, 0x4e, 0xce, 0x55, 0x7a, 0x5e, + 0xfa, 0x9a, 0xa8, 0xf4, 0xc5, 0x2f, 0xb7, 0x97, 0x57, 0x0f, 0xcf, 0xd4, 0xb7, 0xf2, 0xcb, 0xca, + 0x65, 0x8d, 0xcf, 0x11, 0xee, 0xf2, 0xc5, 0xe2, 0xeb, 0x79, 0x9d, 0x83, 0x78, 0x45, 0x3a, 0xff, + 0xa5, 0xa6, 0x9c, 0xfd, 0xfa, 0x8f, 0xb7, 0xdf, 0xf4, 0x35, 0x11, 0xe9, 0x57, 0xe8, 0x1b, 0xfc, + 0xd6, 0x85, 0xa9, 0x57, 0x1f, 0x34, 0xe5, 0xa2, 0x8b, 0xb0, 0xf6, 0xf0, 0xf2, 0x2b, 0xb6, 0x71, + 0x5f, 0x00, 0x5f, 0xf6, 0x2f, 0xda, 0x9e, 0x2f, 0xd0, 0xfb, 0x9e, 0xbf, 0xc0, 0x78, 0xfc, 0xd6, + 0x6b, 0xda, 0xff, 0xbf, 0xfd, 0xba, 0x8f, 0x73, 0xaf, 0xca, 0x07, 0x24, 0xf0, 0x35, 0xe6, 0xf3, + 0xca, 0x4b, 0x7f, 0xce, 0xb9, 0x7f, 0xff, 0xd0, 0xdb, 0x5f, 0xf7, 0x1a, 0xbf, 0xaf, 0x65, 0x1c, + 0xb8, 0xfc, 0x7a, 0xb4, 0xd3, 0x6f, 0x84, 0x5e, 0x14, 0x68, 0xea, 0x1b, 0xaf, 0x1d, 0xbd, 0xf2, + 0x12, 0x7c, 0x46, 0x5e, 0xaa, 0xfc, 0xd4, 0xdc, 0xd3, 0xa8, 0x49, 0x9b, 0x7b, 0xba, 0x34, 0xe9, + 0xf9, 0x9b, 0xc7, 0xf9, 0x82, 0xf2, 0xf3, 0xab, 0xf4, 0x29, 0xfc, 0x52, 0x3e, 0x78, 0x27, 0x5f, + 0xc8, 0xdf, 0xe5, 0x1b, 0x4d, 0x3f, 0xdb, 0x5e, 0x71, 0xf5, 0x77, 0xec, 0x82, 0xe7, 0xc4, 0x9f, + 0xe0, 0x93, 0x7d, 0x95, 0xcf, 0xc5, 0x7b, 0xda, 0xae, 0x7c, 0xce, 0x79, 0xa4, 0xcf, 0x68, 0x47, + 0x6f, 0x9f, 0xb7, 0xfa, 0x72, 0xb5, 0xd9, 0x5e, 0x9a, 0xf4, 0xdc, 0xda, 0xb7, 0x2f, 0x7f, 0xfc, + 0xfd, 0x97, 0x27, 0xe7, 0x64, 0x2d, 0x4b, 0xed, 0x82, 0x95, 0x4b, 0xe3, 0x1b, 0x53, 0xff, 0x3e, + 0xf8, 0x86, 0x3f, 0xff, 0x8b, 0xd0, 0x46, 0x53, 0xff, 0x78, 0x45, 0xf6, 0x84, 0xda, 0xab, 0x19, + 0xaf, 0x2f, 0xc8, 0xfc, 0xfe, 0xe7, 0xeb, 0xb7, 0x2f, 0x7d, 0x85, 0xf7, 0x1f, 0x9f, 0x07, 0x7f, + 0xfb, 0x8b, 0xb7, 0xf6, 0xba, 0xb9, 0x66, 0xf2, 0x8b, 0xfa, 0x75, 0x34, 0xdf, 0x1f, 0x7d, 0xc1, + 0xfd, 0x6e, 0x9b, 0xf4, 0xb5, 0xf6, 0xa7, 0xaa, 0x37, 0xf9, 0xf7, 0xaa, 0xe8, 0x5b, 0xe7, 0x2e, + 0x5d, 0xf7, 0x9a, 0xe5, 0x72, 0x11, 0xfd, 0xd4, 0x2f, 0x37, 0xf7, 0xae, 0x79, 0x75, 0xfe, 0x91, + 0x81, 0x8b, 0x9b, 0xbf, 0x0f, 0x9a, 0xe5, 0xfc, 0x85, 0xed, 0xb8, 0x3f, 0xca, 0x8f, 0x9e, 0xfc, + 0xf9, 0x09, 0xe9, 0xe0, 0xaf, 0xf7, 0xff, 0x60, 0xff, 0x2f, 0xf7, 0x6f, 0x1e, 0x30, 0x7f, 0x11, + 0xfc, 0x45, 0xb1, 0x7a, 0xfb, 0x17, 0xd7, 0x0f, 0x46, 0x4f, 0xcc, 0x87, 0xc5, 0xca, 0xeb, 0xcf, + 0xa7, 0xd7, 0x7b, 0x7e, 0xe8, 0xee, 0x57, 0xb5, 0xaf, 0xbc, 0xfa, 0xfe, 0xe0, 0xca, 0x57, 0xf1, + 0x9f, 0x6d, 0xeb, 0xbe, 0xde, 0xf2, 0x31, 0xfc, 0xe4, 0xd6, 0x7b, 0x3f, 0xf9, 0x31, 0x95, 0xfe, + 0x9b, 0x0b, 0x97, 0xfe, 0xeb, 0xa7, 0x97, 0x89, 0x3f, 0xfe, 0xd1, 0xc7, 0x83, 0x5d, 0x7e, 0xf3, + 0x5f, 0x3c, 0xf1, 0x62, 0x6c, 0x79, 0xdc, 0xf2, 0xf0, 0xbf, 0x7d, 0xb6, 0xb2, 0xbd, 0xe5, 0xd2, + 0xa5, 0xb7, 0x5a, 0x3f, 0x78, 0x16, 0xeb, 0xd3, 0x10, 0x4f, 0x2e, 0x2e, 0x7f, 0xff, 0xd9, 0xc9, + 0xbf, 0x78, 0xeb, 0x4f, 0xff, 0xc9, 0xb3, 0xa3, 0xbf, 0x6f, 0xf9, 0xf9, 0x93, 0x7e, 0xe7, 0x13, + 0x70, 0xfa, 0x88, 0x1b, 0xcf, 0x3f, 0x42, 0xd7, 0x32, 0xf0, 0xeb, 0xc5, 0xf3, 0x2d, 0x2d, 0x6f, + 0xfd, 0xda, 0xe1, 0xf5, 0xd7, 0x8f, 0x98, 0xf8, 0xe5, 0x23, 0xfe, 0xf4, 0x9f, 0x7c, 0xf6, 0x23, + 0x68, 0xc4, 0x9f, 0xfe, 0xd6, 0xf9, 0xa5, 0x37, 0x7b, 0x9f, 0x92, 0x4b, 0x2d, 0x9f, 0x85, 0xd3, + 0x3b, 0x7f, 0xf6, 0xcf, 0xe8, 0x3f, 0x1b, 0xfc, 0xe9, 0xcf, 0x9e, 0xc5, 0x70, 0xe9, 0x8a, 0xfe, + 0xd3, 0x82, 0xff, 0x3a, 0x8d, 0xff, 0x5d, 0x4b, 0x0b, 0x00, 0x00, 0xbf, 0xfe, 0x3f, 0x79, 0x7c, + 0xf7, 0xd7, 0xff, 0x57, 0x9e, 0x7e, 0x7e, 0x93, 0xdd, 0xcb, 0x97, 0x2f, 0x9d, 0xb2, 0xb0, 0xe5, + 0xc9, 0xe7, 0xd2, 0xd3, 0xcf, 0xa7, 0xe3, 0xf1, 0x77, 0x9e, 0x7c, 0x5a, 0xfe, 0x9b, 0xc7, 0x3f, + 0xa5, 0x12, 0x19, 0x3f, 0xfb, 0xb3, 0x8f, 0x45, 0xd4, 0x62, 0x79, 0x9a, 0xa7, 0xdf, 0x8a, 0xe0, + 0x52, 0xeb, 0x6f, 0x0e, 0xc3, 0xa7, 0x5f, 0x74, 0xe0, 0xf4, 0xeb, 0x8d, 0xd3, 0xff, 0x6f, 0x7d, + 0xab, 0xa5, 0xe5, 0xdf, 0x26, 0xdf, 0x6c, 0xf9, 0xf9, 0x5f, 0x7e, 0xe7, 0xb7, 0xa2, 0xa7, 0x5f, + 0x7a, 0x5a, 0x07, 0xde, 0xf8, 0xe5, 0xff, 0x67, 0x21, 0x04, 0xbd, 0xf7, 0xdd, 0x4f, 0x0f, 0xf1, + 0x34, 0x99, 0x3d, 0x9f, 0x9e, 0xcc, 0x4b, 0x97, 0xde, 0xf9, 0xcd, 0xf1, 0xd3, 0x6f, 0xa0, 0xe5, + 0x4c, 0xf1, 0x59, 0xc9, 0xbc, 0xf4, 0x2c, 0x99, 0x3f, 0xfa, 0xe1, 0xc5, 0x48, 0xe6, 0x8f, 0x2e, + 0x44, 0x32, 0x7f, 0xf2, 0x97, 0xc0, 0xaf, 0xf8, 0x79, 0xe9, 0x0d, 0xcd, 0xa9, 0x92, 0x63, 0x68, + 0xfc, 0xbb, 0xa7, 0xe9, 0x79, 0xfc, 0xad, 0xc7, 0x3f, 0xfb, 0xee, 0xde, 0x7f, 0xff, 0xf6, 0xe9, + 0xc9, 0xf7, 0x3c, 0x7f, 0xfb, 0xf4, 0xd2, 0x7f, 0xfa, 0xa7, 0xbf, 0x1d, 0xc5, 0xd2, 0x2f, 0x83, + 0xfe, 0xcd, 0xdd, 0x47, 0xff, 0xee, 0xb7, 0x2a, 0xf4, 0x7f, 0xf8, 0x9d, 0xf3, 0xcf, 0x83, 0x4b, + 0x97, 0xde, 0x7e, 0xf1, 0x8f, 0x6f, 0x3d, 0x4d, 0xd1, 0xaf, 0xce, 0xfe, 0x51, 0x4b, 0xff, 0xaf, + 0xda, 0xd9, 0xc7, 0x03, 0x5d, 0x39, 0x6d, 0xb0, 0x6f, 0x1e, 0xff, 0xdf, 0xdf, 0x2f, 0xb4, 0xb4, + 0x7c, 0xfb, 0xcd, 0xfc, 0xb3, 0x9f, 0xde, 0x7c, 0x12, 0xf3, 0x9f, 0xfe, 0xc5, 0x67, 0x3e, 0xfd, + 0x8d, 0xd3, 0xd6, 0xfe, 0x66, 0xcb, 0xb7, 0x4e, 0xa3, 0xbe, 0x8c, 0x3f, 0xd5, 0xc7, 0xdf, 0xfc, + 0xd6, 0xe3, 0x5f, 0xe2, 0xc5, 0xdd, 0xc8, 0xa7, 0xfd, 0xfa, 0xf1, 0x9c, 0xfd, 0x9b, 0x27, 0x5f, + 0x97, 0xdf, 0xf8, 0xd6, 0x57, 0x29, 0x4e, 0x45, 0xf6, 0x1d, 0xcd, 0xc9, 0xe3, 0xdf, 0x7b, 0xfc, + 0x3f, 0x74, 0xec, 0xb5, 0x7c, 0x13, 0xf0, 0xf8, 0xb7, 0xf1, 0x2f, 0xdf, 0xfc, 0x25, 0xab, 0xbb, + 0x9f, 0x7e, 0x97, 0x9e, 0x7e, 0xff, 0xe7, 0x67, 0x97, 0xbe, 0xf3, 0xf5, 0xa6, 0xb4, 0xfb, 0xe6, + 0x0f, 0x7e, 0xf2, 0x3f, 0x52, 0xae, 0xfe, 0x74, 0x88, 0x76, 0x95, 0x71, 0xe3, 0xda, 0xad, 0xab, + 0x3f, 0xea, 0x7a, 0xef, 0x47, 0x3f, 0xf8, 0xe1, 0x0f, 0x4f, 0xff, 0x5a, 0x9a, 0x68, 0xa2, 0x89, + 0x26, 0x9a, 0x78, 0x1e, 0x4f, 0xba, 0x49, 0xc6, 0xa9, 0xe2, 0xf2, 0xd3, 0x1f, 0xfe, 0x4a, 0xc4, + 0x7e, 0xaa, 0x60, 0x3c, 0xbe, 0xf2, 0x27, 0x8f, 0x1f, 0xbf, 0xfd, 0xd4, 0x15, 0x4d, 0xf0, 0x54, + 0x85, 0x68, 0xb9, 0x7c, 0xef, 0xed, 0xff, 0xfc, 0x34, 0xc4, 0x69, 0xe8, 0x1b, 0x3f, 0xfd, 0xe1, + 0xc7, 0x85, 0xf2, 0x67, 0x2a, 0xc9, 0xcf, 0xa5, 0x2d, 0xbd, 0x8a, 0x9e, 0x67, 0x77, 0xdc, 0x6b, + 0xf9, 0xf1, 0xde, 0xa9, 0x7a, 0xf1, 0xf6, 0x3f, 0x7f, 0xfa, 0xcb, 0x9f, 0xff, 0x84, 0x4a, 0xa4, + 0xfc, 0xf8, 0xcf, 0x7f, 0xf6, 0xab, 0x9b, 0xde, 0xb8, 0x94, 0x7a, 0xeb, 0xf7, 0x5a, 0xfe, 0xcf, + 0xd3, 0xa3, 0x7f, 0x7c, 0x2a, 0xca, 0xbc, 0xb7, 0x49, 0xdb, 0x8e, 0xdc, 0x67, 0xfb, 0x7c, 0x90, + 0xe8, 0xda, 0xf1, 0x92, 0x7d, 0x27, 0x40, 0xd0, 0xc0, 0x6d, 0xa2, 0x9b, 0x2e, 0x93, 0x3b, 0x19, + 0xd7, 0xa7, 0x77, 0xb3, 0xb4, 0xc0, 0x9d, 0xe5, 0x38, 0xfa, 0x51, 0x42, 0x24, 0x22, 0xe3, 0x2b, + 0x79, 0x3b, 0x43, 0x26, 0x75, 0xf7, 0x70, 0x14, 0x70, 0x6c, 0x1a, 0xd2, 0xd0, 0x2c, 0xb7, 0xca, + 0x05, 0x99, 0x99, 0x24, 0xd5, 0xe3, 0x27, 0x01, 0x24, 0x14, 0x85, 0xe5, 0x3e, 0x4a, 0xed, 0x4e, + 0x4c, 0x4e, 0x69, 0x74, 0x71, 0xa7, 0x25, 0xbe, 0xae, 0xa2, 0x4c, 0xcd, 0x07, 0xb0, 0x14, 0x53, + 0xc7, 0x2c, 0x50, 0x8b, 0x45, 0x91, 0x32, 0x91, 0x42, 0x32, 0x6c, 0xb9, 0x1e, 0xaf, 0x10, 0x48, + 0xc0, 0x2f, 0xf1, 0x74, 0x58, 0xa3, 0x02, 0xd8, 0x34, 0x79, 0xd1, 0xd2, 0x0a, 0xfc, 0x06, 0x4f, + 0xaf, 0x03, 0xdb, 0x48, 0xa7, 0x9d, 0xba, 0x0d, 0x0b, 0x82, 0xf8, 0x98, 0x5d, 0x34, 0x28, 0x16, + 0xb9, 0xdd, 0x1d, 0xca, 0xb4, 0xdb, 0xed, 0x24, 0xa5, 0xc7, 0xfa, 0xcb, 0xce, 0x9a, 0x61, 0x7a, + 0x7f, 0x01, 0xed, 0x2c, 0x03, 0x2e, 0xb8, 0xa0, 0x52, 0xa6, 0x6a, 0x68, 0x54, 0xa6, 0x31, 0x8d, + 0xf9, 0x1b, 0x28, 0x9f, 0x53, 0x45, 0x21, 0xfb, 0xfb, 0x10, 0x78, 0x00, 0xe6, 0x77, 0xd1, 0x15, + 0x58, 0x6d, 0x1b, 0x94, 0x70, 0x45, 0x98, 0x34, 0xe2, 0xce, 0x8e, 0xdc, 0xa6, 0x3b, 0xe0, 0xfe, + 0x2a, 0x73, 0xc1, 0x23, 0x62, 0x27, 0x27, 0xdf, 0x2f, 0xa8, 0xe7, 0x0a, 0x78, 0x69, 0xfa, 0xee, + 0x98, 0x7c, 0xbd, 0x9d, 0x63, 0x1a, 0x41, 0xc9, 0x32, 0xd3, 0x48, 0x8e, 0x2a, 0x34, 0x41, 0x92, + 0x44, 0x01, 0xe6, 0x30, 0xd9, 0x51, 0x13, 0xe6, 0x27, 0xe6, 0x4d, 0xee, 0x62, 0x85, 0x49, 0x35, + 0x0b, 0x20, 0x67, 0x45, 0x9c, 0xe0, 0x54, 0x21, 0x68, 0xac, 0x07, 0x33, 0xa9, 0x6b, 0x4a, 0x1b, + 0x64, 0x21, 0xb4, 0x07, 0x1d, 0xf6, 0x8e, 0xe0, 0x01, 0x78, 0x9f, 0x9b, 0xe4, 0x64, 0xc4, 0x4c, + 0x7b, 0xf1, 0xb0, 0xc2, 0x5d, 0x0f, 0x4f, 0x15, 0x0b, 0xde, 0x90, 0x53, 0x3c, 0x1a, 0xd7, 0x98, + 0xfa, 0xaa, 0xd5, 0x61, 0x47, 0x63, 0x00, 0x28, 0xd1, 0x33, 0xb1, 0xb2, 0xe4, 0x51, 0xae, 0x5b, + 0x26, 0x99, 0xb2, 0xc0, 0x2c, 0xe5, 0x2c, 0x18, 0x1d, 0x2a, 0xea, 0x75, 0xd7, 0x6f, 0xb9, 0xe7, + 0x33, 0x2c, 0xaa, 0x9c, 0x6f, 0xcd, 0x34, 0x1c, 0x32, 0x2e, 0x93, 0x85, 0x9b, 0x90, 0x21, 0x71, + 0x92, 0xef, 0x93, 0xa4, 0x92, 0x8a, 0x3c, 0xc6, 0x58, 0xe4, 0x8f, 0xa1, 0x7e, 0x12, 0x02, 0x73, + 0x6e, 0xb9, 0x78, 0x27, 0x01, 0xf4, 0xae, 0xf2, 0x18, 0x2d, 0x2b, 0x79, 0x95, 0x6a, 0x15, 0xb5, + 0xd5, 0xd1, 0x06, 0x75, 0x3e, 0xd3, 0xcb, 0xfc, 0x68, 0xce, 0xed, 0xbe, 0x69, 0x4c, 0xc5, 0xcb, + 0xd7, 0x7d, 0x6e, 0xeb, 0x2e, 0x8d, 0xb1, 0x5f, 0x4d, 0xae, 0x6b, 0xb4, 0x33, 0x56, 0x95, 0xed, + 0x0e, 0xf6, 0xbb, 0x9c, 0xa6, 0x63, 0xc0, 0x0b, 0x38, 0x4d, 0x54, 0x52, 0xb3, 0xb1, 0xe5, 0x04, + 0x32, 0xb9, 0x56, 0xbe, 0x85, 0xf9, 0x38, 0x68, 0xcc, 0x2d, 0x4d, 0x05, 0xa4, 0x07, 0x8f, 0x6a, + 0xc9, 0xca, 0x87, 0xf3, 0xf5, 0x56, 0x1e, 0x02, 0x75, 0xc0, 0xf1, 0x89, 0x45, 0xb8, 0x83, 0xb4, + 0x8f, 0x88, 0xf1, 0xd4, 0x56, 0x7a, 0xbc, 0xca, 0xc4, 0x18, 0x66, 0xa4, 0x2c, 0x7b, 0x50, 0x18, + 0xf1, 0x61, 0x11, 0x51, 0x7f, 0x6d, 0x8b, 0x6f, 0xc9, 0xb2, 0x42, 0x90, 0xd1, 0x77, 0x1d, 0x17, + 0x9b, 0xe4, 0xce, 0x4d, 0xf5, 0x0f, 0x3c, 0x3d, 0xce, 0x7a, 0x9a, 0xbb, 0xee, 0x80, 0xd1, 0xeb, + 0x60, 0x42, 0x6e, 0x9e, 0x8e, 0x45, 0x26, 0x7b, 0x04, 0xed, 0xdc, 0x0c, 0x12, 0x53, 0x6a, 0xec, + 0x05, 0x55, 0x5c, 0x33, 0x9e, 0xe8, 0x0d, 0xa1, 0xab, 0xfa, 0xd6, 0x5c, 0x90, 0x77, 0x18, 0x0e, + 0x6f, 0x89, 0x08, 0x22, 0xee, 0x06, 0x67, 0x4c, 0x12, 0x3a, 0x84, 0x59, 0xfd, 0x83, 0x32, 0x9b, + 0x27, 0x96, 0xe4, 0x29, 0xb2, 0x5c, 0x49, 0x72, 0x15, 0xb9, 0x1d, 0x0b, 0x70, 0xee, 0x0b, 0x79, + 0x3c, 0x2d, 0x42, 0xa9, 0xee, 0xd8, 0x3d, 0x55, 0xbf, 0x5d, 0x68, 0x27, 0x6b, 0xf6, 0x56, 0x1f, + 0x5a, 0x8f, 0x19, 0x0d, 0xeb, 0x75, 0x95, 0x8c, 0x7a, 0x44, 0xd8, 0xa2, 0x2e, 0x83, 0xae, 0xfa, + 0x84, 0x56, 0x61, 0x8d, 0x4a, 0x55, 0x86, 0xd6, 0x0e, 0xfa, 0xca, 0x76, 0x8c, 0xc3, 0x39, 0xc8, + 0x90, 0xa9, 0x33, 0xc6, 0xe5, 0x04, 0x6d, 0xdc, 0x22, 0xe0, 0x43, 0xe3, 0xdb, 0xd1, 0x81, 0x9b, + 0x45, 0x73, 0x51, 0x3a, 0x28, 0x5b, 0x31, 0x75, 0x4f, 0x7e, 0x88, 0xbd, 0xb7, 0x29, 0x39, 0x10, + 0xdd, 0x6f, 0x63, 0x03, 0x2e, 0xb3, 0x07, 0x3c, 0x44, 0xdb, 0xad, 0xd4, 0x2d, 0xae, 0xb9, 0x78, + 0x30, 0xa5, 0x1d, 0x59, 0xdf, 0xa2, 0xd7, 0x62, 0x82, 0x9a, 0xc1, 0x9d, 0x63, 0xdb, 0x2b, 0x22, + 0x88, 0x49, 0xf5, 0xa6, 0xb2, 0x38, 0x1a, 0x8c, 0x88, 0x5a, 0xf3, 0x1f, 0x69, 0x47, 0x28, 0xa5, + 0xd2, 0x68, 0x2a, 0x8c, 0xc1, 0x32, 0x8e, 0x2a, 0xec, 0xb0, 0x3d, 0xc7, 0x69, 0x66, 0x97, 0xf5, + 0x05, 0x9c, 0xa6, 0xac, 0x83, 0x23, 0xba, 0xe5, 0xe0, 0xac, 0x45, 0x3b, 0x28, 0xa8, 0x02, 0xef, + 0x05, 0x5c, 0x6b, 0x8d, 0x77, 0x02, 0x6e, 0xb2, 0xf7, 0x61, 0xc2, 0xbe, 0xa5, 0xed, 0xb4, 0xdb, + 0x36, 0x95, 0x08, 0x81, 0xc0, 0xe1, 0xcf, 0xc0, 0x02, 0x1c, 0xe8, 0x1b, 0xb0, 0x91, 0x8f, 0xf7, + 0xac, 0xd4, 0x8a, 0xb7, 0xc2, 0x81, 0xf2, 0xda, 0x9e, 0x0e, 0x9c, 0x3e, 0xaf, 0x03, 0x6e, 0x7c, + 0xb4, 0x6f, 0x16, 0xdc, 0xb8, 0x4b, 0xcb, 0x09, 0x84, 0xb5, 0x3b, 0x06, 0x90, 0x4d, 0x3e, 0xb6, + 0x5a, 0x86, 0x8a, 0x6b, 0x27, 0x56, 0x34, 0x52, 0xbf, 0x3b, 0x22, 0xa5, 0x56, 0xad, 0x23, 0x91, + 0x39, 0x6d, 0x3f, 0x81, 0x24, 0x59, 0x5b, 0xb2, 0x3b, 0x84, 0xec, 0x12, 0x04, 0xc2, 0x95, 0x56, + 0x12, 0x89, 0x83, 0xdd, 0x5a, 0x06, 0x53, 0xa3, 0x06, 0x48, 0xed, 0xa2, 0x43, 0xbc, 0xc8, 0xe4, + 0x48, 0x17, 0x85, 0x2d, 0xd3, 0x6b, 0x87, 0x6e, 0x6c, 0x28, 0xe7, 0x03, 0x9e, 0x05, 0x63, 0x59, + 0x40, 0x9c, 0xa9, 0xc0, 0x2e, 0x11, 0x3d, 0xd2, 0x15, 0x25, 0x68, 0xbd, 0xf7, 0x39, 0x1e, 0x92, + 0x12, 0x5c, 0xef, 0x95, 0x98, 0xb5, 0x83, 0x20, 0x55, 0x2d, 0x31, 0xe7, 0xb7, 0x51, 0x49, 0x16, + 0xdc, 0x8f, 0x42, 0x43, 0x8e, 0x83, 0x63, 0xdd, 0xfa, 0xad, 0x48, 0x7d, 0x60, 0xc0, 0x73, 0xe0, + 0xf2, 0x5b, 0x22, 0x4c, 0x57, 0xac, 0x35, 0xf5, 0xa1, 0x49, 0x80, 0x50, 0x27, 0x26, 0x74, 0xad, + 0x51, 0xf9, 0x8a, 0x76, 0xc0, 0x0d, 0xce, 0x1f, 0xc6, 0xac, 0x40, 0xc4, 0xd2, 0x86, 0xe3, 0xdc, + 0x4e, 0xc1, 0xe4, 0xa6, 0xd2, 0x4c, 0x74, 0x15, 0x13, 0x92, 0x04, 0xbe, 0x87, 0x4a, 0x7c, 0x20, + 0x9b, 0x76, 0xdf, 0xdc, 0xef, 0x57, 0xfa, 0xda, 0x88, 0x8e, 0x71, 0xb3, 0x85, 0xe0, 0xab, 0xff, + 0x20, 0xe0, 0x90, 0x2b, 0xda, 0x13, 0x4e, 0x09, 0x04, 0xf8, 0x1d, 0x55, 0xbd, 0x9e, 0x42, 0x63, + 0x8f, 0x9f, 0x24, 0x90, 0x79, 0xe4, 0x1d, 0xc8, 0xed, 0x98, 0xcf, 0x10, 0x83, 0xb4, 0x52, 0xd1, + 0x6a, 0x85, 0xb9, 0xad, 0xcf, 0x71, 0xba, 0x15, 0x7e, 0x01, 0xa7, 0x7b, 0x61, 0x68, 0x3c, 0x41, + 0x29, 0x3a, 0x27, 0x4c, 0x6d, 0x09, 0xad, 0xa9, 0x95, 0x70, 0x73, 0xe1, 0x01, 0x22, 0x13, 0xeb, + 0x6d, 0x90, 0x3f, 0xa6, 0x33, 0x59, 0xc4, 0x1c, 0x5e, 0x92, 0x29, 0x74, 0xed, 0x39, 0xcc, 0xdd, + 0x54, 0xe9, 0x8a, 0xae, 0x78, 0x5c, 0x13, 0x0b, 0x84, 0x13, 0x62, 0xae, 0x56, 0x1e, 0xe6, 0xa4, + 0xf6, 0x72, 0x65, 0x7d, 0xb1, 0x20, 0x65, 0x6f, 0x3a, 0xf4, 0x23, 0x09, 0xe1, 0x8a, 0xbe, 0xf5, + 0x80, 0x02, 0x74, 0x11, 0x68, 0xfb, 0x8a, 0x38, 0x1c, 0xe7, 0x9b, 0xdc, 0x2c, 0xc6, 0x70, 0xaa, + 0xd8, 0x76, 0x1d, 0x47, 0xb8, 0xaa, 0x78, 0x15, 0x9b, 0xae, 0x92, 0xa9, 0x74, 0x5d, 0xeb, 0x8d, + 0x71, 0x63, 0xc3, 0x33, 0xe4, 0xca, 0x58, 0x05, 0x6c, 0xd8, 0x80, 0x96, 0x21, 0x8a, 0x28, 0x66, + 0x1b, 0x4c, 0xee, 0x3c, 0x6e, 0xe5, 0x31, 0xb2, 0x1e, 0x51, 0x5c, 0xe3, 0x34, 0x0f, 0x30, 0x5c, + 0x88, 0x17, 0x4b, 0xd2, 0x64, 0xdc, 0x32, 0x86, 0xcd, 0xd7, 0x76, 0x73, 0xb3, 0x07, 0x4b, 0xbe, + 0x1e, 0xe7, 0xc1, 0xcc, 0x86, 0xa6, 0x5a, 0x68, 0xf5, 0xe2, 0x1a, 0xcc, 0x33, 0x8a, 0x23, 0x15, + 0x54, 0x19, 0xe7, 0x4c, 0x1c, 0xc5, 0x7d, 0x3a, 0x7e, 0x5b, 0xd0, 0xb1, 0x62, 0x6a, 0xed, 0x58, + 0x07, 0x7d, 0xc9, 0x70, 0x7f, 0x6d, 0x4c, 0x20, 0x5b, 0x57, 0xee, 0xef, 0x41, 0xed, 0x5b, 0x36, + 0xe3, 0x32, 0x69, 0x2f, 0x3a, 0xc2, 0x62, 0xcc, 0xb1, 0xd3, 0xbd, 0x22, 0xd9, 0x8e, 0x8e, 0xb0, + 0x2e, 0xa4, 0xc7, 0x6e, 0x6d, 0x3a, 0x57, 0xea, 0x3d, 0x65, 0xd1, 0xda, 0x23, 0x74, 0x9a, 0xa7, + 0x33, 0x4f, 0x33, 0xc7, 0xe7, 0x32, 0xdc, 0x94, 0xd2, 0xb5, 0x0c, 0x16, 0xa9, 0x2b, 0x3b, 0x89, + 0x5e, 0x1a, 0x26, 0x58, 0x87, 0x4c, 0x9c, 0x62, 0x9d, 0xed, 0x98, 0x5a, 0x0a, 0x95, 0x52, 0x0b, + 0x2b, 0xeb, 0x52, 0x40, 0x7b, 0x6d, 0x19, 0x9f, 0x5f, 0xb4, 0x4b, 0x68, 0xfc, 0x31, 0x21, 0x0c, + 0x01, 0xa3, 0x09, 0x7e, 0x17, 0x2a, 0x4a, 0x04, 0xe4, 0x9b, 0xc8, 0xc8, 0xef, 0x72, 0x9a, 0x81, + 0xac, 0xbf, 0x80, 0xd3, 0xfd, 0x2a, 0xf9, 0x42, 0x25, 0x57, 0x95, 0x69, 0x5b, 0x59, 0x93, 0x2e, + 0x64, 0xc9, 0x8f, 0xba, 0x12, 0x46, 0x9c, 0x04, 0xdb, 0xee, 0x4f, 0x5f, 0xb7, 0xb9, 0xad, 0x52, + 0x4f, 0xc9, 0x51, 0xf7, 0x37, 0x56, 0x71, 0x6b, 0x0f, 0x89, 0x03, 0xa9, 0x92, 0x3e, 0x6d, 0x51, + 0x07, 0xb1, 0xaa, 0x90, 0x37, 0x97, 0x9f, 0xc0, 0xee, 0x13, 0xdb, 0xf7, 0xc1, 0xc5, 0xba, 0xc6, + 0x66, 0x48, 0x8a, 0x8f, 0x23, 0xca, 0x4a, 0x26, 0x2e, 0xa7, 0x1e, 0xae, 0xdf, 0x10, 0x1e, 0xfb, + 0x6d, 0x76, 0xbf, 0xd4, 0x5a, 0x0a, 0xa9, 0xa8, 0x58, 0x67, 0x14, 0xcf, 0xf4, 0x48, 0x81, 0xe4, + 0x58, 0x8e, 0xb9, 0x19, 0x99, 0x5a, 0xc9, 0x69, 0xe6, 0x96, 0xcc, 0x76, 0x46, 0x59, 0x8e, 0x12, + 0x8e, 0xc6, 0xc1, 0x4a, 0x2d, 0x51, 0x45, 0x50, 0x20, 0xbf, 0x12, 0x1d, 0x89, 0x49, 0xd8, 0x0c, + 0x2d, 0x48, 0x12, 0x17, 0xe9, 0xa7, 0xbd, 0x02, 0x90, 0x91, 0xb0, 0x35, 0x52, 0x96, 0xd2, 0x16, + 0xe2, 0x9d, 0xb8, 0x6c, 0xca, 0xb9, 0xf7, 0xa0, 0xe8, 0x42, 0x72, 0xd7, 0x25, 0x11, 0xcd, 0x31, + 0x13, 0xce, 0x64, 0x19, 0x09, 0x71, 0xa5, 0xf6, 0x64, 0x39, 0xe1, 0x53, 0x59, 0xc6, 0x7a, 0x39, + 0xb8, 0xc5, 0x47, 0xdc, 0x33, 0xba, 0x61, 0x91, 0x6c, 0xd5, 0x0c, 0x87, 0xd9, 0x49, 0x7b, 0xff, + 0x74, 0x31, 0x69, 0x36, 0x4f, 0xf3, 0xf8, 0x05, 0x5e, 0xa2, 0x9a, 0x6f, 0x04, 0xd4, 0xf8, 0x7e, + 0x0c, 0xe7, 0xa9, 0xc6, 0xeb, 0xac, 0xb2, 0x3a, 0x15, 0xdd, 0x4d, 0x42, 0x5e, 0x4b, 0x47, 0x5f, + 0x55, 0x6c, 0xb1, 0x06, 0x0f, 0xeb, 0xca, 0xb4, 0x83, 0x67, 0x81, 0x46, 0x23, 0xb0, 0x94, 0x7b, + 0xcd, 0x1e, 0x62, 0xae, 0x59, 0xaf, 0xe7, 0xa9, 0xf7, 0x37, 0x49, 0x0e, 0xc3, 0x3b, 0xa1, 0x2a, + 0x10, 0xed, 0x5e, 0xdf, 0x67, 0x97, 0xf5, 0xd0, 0x50, 0xf1, 0x4e, 0x83, 0x0f, 0xd4, 0xdc, 0xd9, + 0xfc, 0x3a, 0x83, 0x93, 0xeb, 0x00, 0x83, 0xb5, 0x6e, 0x2b, 0x95, 0x2a, 0x41, 0x5d, 0x4e, 0x46, + 0xd2, 0xfc, 0x1c, 0xa7, 0xcd, 0xa1, 0x17, 0x70, 0x9a, 0x25, 0xf1, 0x1a, 0x3c, 0xed, 0xd4, 0x64, + 0xd1, 0x30, 0xd2, 0x5e, 0x31, 0xbc, 0x07, 0x4e, 0x48, 0x46, 0x46, 0xb8, 0x71, 0xdb, 0x9d, 0x05, + 0x68, 0x33, 0x2f, 0x03, 0x7c, 0xe0, 0xe4, 0x0e, 0x02, 0x4b, 0x7c, 0x52, 0x00, 0x24, 0xa6, 0x1d, + 0xd9, 0x1e, 0xdb, 0xdd, 0x29, 0xaf, 0xa5, 0x6b, 0x6e, 0x3b, 0xd0, 0x3e, 0x44, 0x4b, 0xbf, 0xb7, + 0x9b, 0x3f, 0x58, 0xd0, 0xae, 0xd7, 0x68, 0x7a, 0x6b, 0xd9, 0xc1, 0xdd, 0x31, 0xe4, 0xc4, 0x79, + 0xd0, 0x1f, 0xed, 0x88, 0x38, 0xcc, 0x99, 0x1b, 0x68, 0x1d, 0xb6, 0x59, 0x0f, 0xd8, 0x15, 0xfe, + 0xb4, 0x57, 0x58, 0xcb, 0xc9, 0xdd, 0x48, 0x87, 0xdf, 0x4e, 0x35, 0x45, 0xf1, 0x8d, 0xd5, 0xa2, + 0xe8, 0xdd, 0xb8, 0x53, 0xcc, 0xb1, 0x1d, 0xf8, 0xca, 0xaa, 0xdd, 0x62, 0x60, 0xf6, 0xc1, 0xfa, + 0x35, 0xca, 0xec, 0x7c, 0xae, 0x73, 0xc8, 0xb1, 0x62, 0xbf, 0xb9, 0x71, 0x30, 0x63, 0xe9, 0xdd, + 0x98, 0xdc, 0x89, 0x92, 0x4e, 0xeb, 0xc0, 0x00, 0x03, 0xab, 0x18, 0x44, 0x9c, 0x88, 0x2c, 0xa9, + 0x02, 0xe2, 0x2e, 0x74, 0x63, 0x62, 0xa7, 0x5a, 0xf4, 0x49, 0x93, 0x4e, 0x75, 0x92, 0xb4, 0x0f, + 0xc2, 0x68, 0xe7, 0x70, 0xad, 0xab, 0x06, 0xc7, 0xab, 0x30, 0x93, 0x17, 0x9d, 0x4a, 0x4a, 0xd9, + 0xb8, 0x4c, 0xcd, 0x19, 0xda, 0xae, 0x74, 0x76, 0x74, 0x85, 0x27, 0x76, 0x0a, 0x84, 0xd0, 0xfe, + 0xa3, 0x70, 0x47, 0x70, 0xee, 0x21, 0xd2, 0x4b, 0xa2, 0xdd, 0xf1, 0xdc, 0x20, 0xd9, 0x0b, 0xae, + 0x23, 0xb4, 0x54, 0xdf, 0x2c, 0x20, 0xe3, 0x09, 0xe1, 0x3a, 0x02, 0xf7, 0x75, 0x56, 0xee, 0xf2, + 0x2d, 0xe6, 0xaa, 0xca, 0xe8, 0x06, 0x92, 0xf2, 0x1d, 0x1d, 0x6b, 0x73, 0x6a, 0xc9, 0x7a, 0xac, + 0x32, 0x8e, 0x4d, 0xfb, 0x27, 0x17, 0x33, 0x2c, 0x39, 0x67, 0x61, 0x64, 0x9a, 0x3d, 0x38, 0xff, + 0xc0, 0x8c, 0xa9, 0x79, 0x51, 0xb3, 0x59, 0xc1, 0xc1, 0x33, 0xeb, 0x22, 0xb6, 0x36, 0x23, 0xa3, + 0x30, 0x30, 0xf3, 0x08, 0x11, 0xc0, 0x46, 0xfa, 0x87, 0x68, 0xae, 0xe7, 0x64, 0x0f, 0xa6, 0xcc, + 0xf3, 0x02, 0x4e, 0xf3, 0x26, 0xa9, 0x5b, 0x87, 0x76, 0x12, 0x05, 0x8a, 0xa9, 0x6e, 0x18, 0x2b, + 0x63, 0x62, 0xcd, 0x47, 0x73, 0xfc, 0x36, 0xe8, 0xae, 0x38, 0x2b, 0x98, 0x9e, 0xcb, 0x4c, 0xf3, + 0x86, 0xe6, 0x0e, 0x8a, 0x9b, 0x61, 0xa4, 0xce, 0x73, 0xc1, 0xdc, 0xba, 0x1f, 0x0c, 0x92, 0x56, + 0x6a, 0x04, 0xb2, 0x36, 0x4d, 0x00, 0x64, 0xa1, 0x03, 0x0e, 0xa1, 0xaf, 0x64, 0x78, 0x3f, 0x0d, + 0xea, 0xbd, 0xbb, 0xcb, 0x11, 0x7a, 0xfa, 0x41, 0x10, 0xdf, 0x73, 0x6b, 0x45, 0x2a, 0x71, 0x71, + 0x9a, 0x3c, 0xe9, 0x1a, 0xaf, 0x0f, 0xf4, 0x56, 0x26, 0xaa, 0x6e, 0xbf, 0x8e, 0xa1, 0x25, 0x1e, + 0x1f, 0x98, 0x0b, 0x99, 0x0a, 0x32, 0x0e, 0x43, 0x42, 0x8c, 0x6f, 0x83, 0x86, 0x22, 0x59, 0xe3, + 0xd1, 0xc1, 0x06, 0xba, 0x98, 0x21, 0x6d, 0x3c, 0xac, 0x59, 0xa7, 0x79, 0x74, 0x6d, 0x97, 0x78, + 0x6e, 0x54, 0x6f, 0x0e, 0x2e, 0xa8, 0x2d, 0xf6, 0xf8, 0x70, 0xea, 0x88, 0xb1, 0x99, 0x9c, 0x58, + 0xda, 0x8d, 0x91, 0xa8, 0x27, 0x61, 0x8f, 0x7f, 0xcc, 0x02, 0xe1, 0x1c, 0x26, 0xd2, 0x79, 0x0c, + 0xe8, 0xc6, 0x42, 0x51, 0x2e, 0xcc, 0x2c, 0x5f, 0x2f, 0x65, 0xb8, 0xfd, 0x43, 0x0b, 0x8c, 0x87, + 0x5e, 0x12, 0xc9, 0x05, 0xda, 0xc2, 0x9a, 0xe2, 0x4c, 0xc2, 0xba, 0x15, 0xb5, 0xb2, 0xa6, 0x5d, + 0x3a, 0x16, 0xb7, 0xdf, 0x85, 0xb8, 0x05, 0xca, 0x12, 0xb4, 0x1c, 0xb3, 0xdb, 0x45, 0xd7, 0x82, + 0x21, 0xf7, 0xc4, 0xfd, 0x8e, 0x1e, 0xcd, 0x81, 0x3e, 0x58, 0xd7, 0xe7, 0xcb, 0x32, 0x86, 0x77, + 0x2f, 0xc3, 0x05, 0xf8, 0x96, 0x62, 0x94, 0xb5, 0xf0, 0x50, 0xef, 0x6f, 0x04, 0x86, 0x1b, 0x47, + 0x8c, 0x88, 0x41, 0xab, 0x18, 0xfc, 0xd0, 0xa0, 0xea, 0x0b, 0x69, 0xeb, 0xfd, 0x9b, 0x07, 0x80, + 0x08, 0x40, 0x81, 0x35, 0xe3, 0x49, 0xae, 0x33, 0x64, 0xf6, 0x57, 0x20, 0xfa, 0x2a, 0x18, 0x8d, + 0x61, 0xa9, 0x55, 0x6b, 0xf5, 0xa3, 0x82, 0x4f, 0x35, 0x89, 0xdf, 0xb9, 0xdf, 0xb5, 0xb1, 0xa6, + 0xcd, 0x4c, 0x03, 0xa7, 0xec, 0xfe, 0x0d, 0xa7, 0x5f, 0x1e, 0x7e, 0x29, 0x3f, 0x76, 0x11, 0x5e, + 0x50, 0x86, 0xad, 0x64, 0x2a, 0x80, 0xb4, 0x92, 0xa8, 0xce, 0x5c, 0x50, 0x68, 0x58, 0x46, 0x08, + 0x24, 0xaa, 0xcd, 0x30, 0x2a, 0x21, 0x6f, 0xa3, 0x24, 0x55, 0x9a, 0x09, 0xb4, 0x5d, 0x07, 0xf4, + 0x66, 0xd0, 0x3a, 0x49, 0xd7, 0x76, 0x88, 0x49, 0xa7, 0x39, 0x99, 0x56, 0xd3, 0x66, 0x32, 0x24, + 0x98, 0x6a, 0x04, 0xdd, 0x71, 0x6c, 0x0d, 0xe6, 0x89, 0xb5, 0x8c, 0x18, 0x25, 0xb2, 0x8d, 0x67, + 0x88, 0x71, 0x54, 0x9d, 0xa9, 0x53, 0x27, 0xef, 0x7b, 0x68, 0x42, 0x25, 0x98, 0x26, 0xd1, 0x5d, + 0x08, 0xa7, 0x87, 0xbe, 0xfd, 0xc0, 0x2c, 0x04, 0x19, 0x86, 0x11, 0x9a, 0x13, 0xbb, 0x83, 0x32, + 0x82, 0xda, 0xeb, 0x2c, 0xe6, 0xe4, 0x68, 0x66, 0x90, 0x14, 0x07, 0xba, 0xda, 0x58, 0xd4, 0x87, + 0xb0, 0x99, 0x16, 0xd4, 0x0a, 0x3a, 0x04, 0xf4, 0x8c, 0x19, 0xb4, 0xcf, 0xca, 0xcd, 0xe6, 0xeb, + 0xf4, 0x55, 0x73, 0x87, 0x08, 0x70, 0x20, 0x3d, 0x56, 0x91, 0xf6, 0x1a, 0xe8, 0xde, 0xd6, 0x12, + 0x3a, 0x50, 0x7a, 0x7c, 0x11, 0x72, 0x2f, 0xca, 0x6d, 0xa9, 0x18, 0x15, 0xb4, 0x74, 0x5d, 0xa7, + 0x9f, 0x0e, 0xc7, 0x2c, 0xea, 0x6c, 0xa5, 0xf5, 0x3a, 0x63, 0xc4, 0xfa, 0xe4, 0xde, 0xa7, 0x5f, + 0xb0, 0x48, 0x7c, 0x00, 0xf4, 0x3c, 0x39, 0x1a, 0x79, 0x97, 0xc1, 0x38, 0x4d, 0x9f, 0x6b, 0x50, + 0x6f, 0x1d, 0xa1, 0x81, 0xf3, 0x26, 0x16, 0x31, 0x8f, 0x9a, 0x58, 0xac, 0xfc, 0xda, 0x91, 0x65, + 0x88, 0xb6, 0x76, 0x7a, 0x1b, 0x75, 0xaa, 0x32, 0x10, 0x66, 0x50, 0x2b, 0x63, 0x22, 0xea, 0xc4, + 0xaf, 0x1f, 0x34, 0x6f, 0x3d, 0x7d, 0xd0, 0xee, 0x03, 0x1f, 0xcb, 0xb0, 0x55, 0xe9, 0xcc, 0x4d, + 0xd2, 0xcd, 0x23, 0x0c, 0xfa, 0xb1, 0x95, 0xb0, 0x1e, 0x1c, 0x36, 0x10, 0x48, 0x71, 0x4c, 0xca, + 0x62, 0xe4, 0x9f, 0xa4, 0x7e, 0x71, 0xe4, 0x01, 0x4a, 0xc3, 0xe9, 0x8f, 0x59, 0x64, 0xf2, 0x1d, + 0x9b, 0xb5, 0x73, 0xb6, 0x01, 0x3c, 0x27, 0xa9, 0xb7, 0x76, 0xbe, 0x80, 0xd3, 0xa3, 0x54, 0xc6, + 0x8e, 0x99, 0xb5, 0x4e, 0x37, 0x03, 0x25, 0x09, 0x97, 0x57, 0x94, 0xb2, 0x27, 0x30, 0x8f, 0x94, + 0x36, 0x98, 0xe9, 0xb3, 0x38, 0xb0, 0x95, 0x25, 0xcb, 0xa0, 0xd3, 0xb8, 0xe7, 0x63, 0xaa, 0x0f, + 0x8b, 0x08, 0xf3, 0x2e, 0xe3, 0xb8, 0x36, 0xe4, 0x86, 0x09, 0x5c, 0x5a, 0xda, 0x3b, 0x5f, 0x8a, + 0xe7, 0xc5, 0x59, 0x8b, 0xc3, 0xc8, 0x1c, 0x23, 0x0c, 0x31, 0x7d, 0xad, 0x49, 0x05, 0xc2, 0x2d, + 0xe5, 0x4a, 0x22, 0x19, 0x5a, 0x8a, 0x97, 0x86, 0x4f, 0x0a, 0x9e, 0xb8, 0x59, 0x5f, 0xc1, 0x23, + 0x7b, 0x0d, 0xd1, 0x0d, 0x97, 0xdb, 0x4c, 0x38, 0x72, 0xcf, 0x5a, 0x6a, 0xee, 0x42, 0xea, 0x51, + 0xa5, 0x0c, 0x15, 0x14, 0x95, 0x46, 0x60, 0xbc, 0x66, 0x19, 0x8a, 0x14, 0xb5, 0x22, 0xc2, 0x94, + 0xa1, 0x8d, 0x00, 0x32, 0x97, 0x3c, 0xee, 0x76, 0x55, 0xcd, 0x98, 0x92, 0xcd, 0xd7, 0xb8, 0x31, + 0xd9, 0xf0, 0x9e, 0x3b, 0x06, 0xcd, 0xed, 0x5b, 0x6f, 0x25, 0x26, 0x76, 0x90, 0x7e, 0x09, 0x63, + 0x49, 0xeb, 0xc9, 0x4f, 0x69, 0x6d, 0xb6, 0xc8, 0xcc, 0xfc, 0x2a, 0x6a, 0x87, 0x68, 0x92, 0x5d, + 0xaa, 0x31, 0x2d, 0xe8, 0x61, 0xa7, 0xbd, 0x8b, 0x05, 0xd5, 0xac, 0xae, 0x95, 0xd8, 0x2e, 0x9a, + 0x47, 0x58, 0x2a, 0x35, 0x77, 0x0c, 0xde, 0xa4, 0x9a, 0x40, 0x74, 0xb0, 0xe4, 0x5d, 0xb2, 0x92, + 0xf4, 0x7c, 0x54, 0xcc, 0x5e, 0x4a, 0xb0, 0x5c, 0x93, 0x52, 0x48, 0xb6, 0x1b, 0x8c, 0x38, 0xb2, + 0x5e, 0x04, 0x8e, 0xe6, 0x0a, 0x2e, 0xa8, 0xd2, 0x9d, 0xb8, 0xbe, 0x89, 0xbc, 0x63, 0x1d, 0x24, + 0xcf, 0x7a, 0x52, 0x5b, 0xd5, 0xdd, 0xc3, 0xac, 0x7d, 0x92, 0x2b, 0x88, 0xd1, 0x60, 0x95, 0x25, + 0xea, 0x26, 0xcd, 0x1f, 0x26, 0x7b, 0x26, 0x56, 0x2b, 0x02, 0x9f, 0x0b, 0x95, 0xc4, 0x5d, 0x45, + 0xc7, 0xa3, 0xb4, 0x4b, 0xc3, 0xbf, 0xef, 0x0f, 0x2e, 0xa1, 0xa6, 0xd1, 0x58, 0x9a, 0xa3, 0x95, + 0xe5, 0x70, 0x73, 0x36, 0x73, 0xac, 0xe1, 0x55, 0xbc, 0x71, 0xcd, 0x8c, 0xf6, 0x39, 0x49, 0x1d, + 0x21, 0xbe, 0x80, 0xd3, 0x42, 0xcc, 0x0d, 0x67, 0x8b, 0x75, 0x0d, 0x5c, 0x9c, 0xde, 0x9c, 0xdf, + 0xb1, 0x8e, 0x92, 0x7c, 0x99, 0x3b, 0xa9, 0x75, 0xb1, 0x32, 0xfd, 0x2e, 0x8e, 0x58, 0xc6, 0xc3, + 0x12, 0xd4, 0x3e, 0x56, 0x08, 0xc9, 0x7c, 0x9d, 0xbe, 0xeb, 0x9b, 0x70, 0x7b, 0x1c, 0xc7, 0x8b, + 0x66, 0x4a, 0x67, 0xd5, 0x64, 0x08, 0x28, 0x42, 0xfc, 0x69, 0x20, 0x82, 0x15, 0x3b, 0x49, 0x52, + 0x5f, 0xaa, 0xf2, 0xae, 0x7d, 0x21, 0x2d, 0x09, 0x91, 0x37, 0x9d, 0x1c, 0x60, 0x1a, 0x9b, 0xc2, + 0xcb, 0xd3, 0x76, 0x28, 0xd7, 0xb9, 0xae, 0xb6, 0x25, 0x8e, 0xfd, 0x80, 0xc3, 0xec, 0x99, 0xe6, + 0x2e, 0x1c, 0x8d, 0xd0, 0x8a, 0x95, 0x77, 0xc3, 0xdc, 0x9d, 0x48, 0xa0, 0x3b, 0x6a, 0x42, 0xed, + 0x14, 0xea, 0x9c, 0xd1, 0x3d, 0x80, 0xba, 0x99, 0xee, 0xd6, 0x60, 0x4a, 0xec, 0x1b, 0xd4, 0xd0, + 0x46, 0xb1, 0x3e, 0x7c, 0xc7, 0xfe, 0x6e, 0xa5, 0x8b, 0x9a, 0x4a, 0x61, 0xa9, 0x78, 0x81, 0x65, + 0x06, 0x45, 0x22, 0x45, 0xcf, 0x3e, 0x15, 0xea, 0x92, 0x48, 0x55, 0x51, 0xb7, 0x58, 0x0e, 0x38, + 0x62, 0xd3, 0xfd, 0xfe, 0xf1, 0x04, 0x24, 0x4e, 0x08, 0x4d, 0xef, 0xc2, 0xdb, 0x3a, 0xa8, 0x63, + 0xeb, 0xa3, 0xe3, 0x93, 0x00, 0x91, 0xa9, 0xef, 0xad, 0x79, 0x1c, 0xba, 0xb6, 0x50, 0x44, 0x06, + 0x20, 0x82, 0x30, 0x60, 0x12, 0x73, 0xd8, 0xc9, 0x71, 0x4b, 0xb1, 0xb2, 0x49, 0x53, 0x13, 0xe3, + 0x8c, 0x65, 0x78, 0xfd, 0xe6, 0x8c, 0x11, 0xe2, 0x4e, 0xc6, 0x85, 0x29, 0xbf, 0xc0, 0xfb, 0x00, + 0x93, 0x93, 0x49, 0x49, 0xed, 0x08, 0x1b, 0x31, 0x62, 0xf1, 0x21, 0x04, 0x89, 0xc5, 0x7a, 0x38, + 0x93, 0x46, 0xab, 0x78, 0xc3, 0xd7, 0x11, 0x8b, 0x7f, 0xe4, 0x75, 0x97, 0xf0, 0xb0, 0x65, 0x7e, + 0xd9, 0xe5, 0x74, 0xcf, 0x2c, 0x47, 0x97, 0x6a, 0x60, 0x39, 0xf1, 0xa1, 0x7e, 0x29, 0x10, 0xd4, + 0xdb, 0x3b, 0x7b, 0xea, 0x78, 0x8d, 0x5b, 0x88, 0xdb, 0x50, 0x3e, 0x53, 0x2a, 0x8f, 0x30, 0x93, + 0x25, 0x25, 0xff, 0x79, 0x9d, 0xc8, 0x4c, 0x79, 0x01, 0xa7, 0xc5, 0xfd, 0x4e, 0x48, 0xc7, 0x61, + 0xd3, 0x13, 0xda, 0x76, 0xc0, 0x90, 0x90, 0x51, 0x4e, 0x6b, 0xf7, 0x3b, 0x55, 0x1f, 0x63, 0xf8, + 0x41, 0xd5, 0x3b, 0xb8, 0x90, 0x6b, 0x25, 0x82, 0xda, 0x77, 0xe2, 0x02, 0xce, 0x54, 0xf6, 0xd6, + 0x11, 0xc5, 0x00, 0xd9, 0xc0, 0xa9, 0x07, 0xb0, 0x67, 0x12, 0xdc, 0x3f, 0x22, 0x50, 0x87, 0xd4, + 0xc8, 0x20, 0x18, 0x91, 0xcf, 0xbb, 0x79, 0xb6, 0x28, 0xc2, 0xe1, 0x7e, 0x08, 0x27, 0x6d, 0x13, + 0x5b, 0xfb, 0xe6, 0xa1, 0x94, 0x2d, 0xe5, 0x19, 0x05, 0x81, 0x5d, 0x0c, 0x02, 0x69, 0xf5, 0x29, + 0xe4, 0xc8, 0x30, 0xe7, 0x47, 0xd9, 0x2e, 0xba, 0xaf, 0x83, 0xc4, 0x96, 0xb5, 0xf6, 0x74, 0x4e, + 0x44, 0xb2, 0xd7, 0xa7, 0xb7, 0xe7, 0xe7, 0x8f, 0x22, 0xae, 0xa9, 0xd3, 0xf1, 0x87, 0x33, 0x8b, + 0x41, 0x71, 0x12, 0x6d, 0xc9, 0x4c, 0xde, 0x2f, 0x55, 0xd0, 0xb8, 0x7c, 0xd1, 0x24, 0x14, 0x29, + 0xd8, 0xab, 0x96, 0x78, 0x75, 0x69, 0x71, 0x39, 0x28, 0xb4, 0x61, 0x36, 0xeb, 0xe1, 0x3c, 0x0e, + 0x72, 0x45, 0x75, 0x10, 0x65, 0x51, 0x9d, 0x5a, 0xf3, 0x60, 0x70, 0x31, 0xd1, 0x2e, 0x70, 0x21, + 0x90, 0x48, 0x4e, 0x82, 0x2d, 0xc2, 0xfc, 0xaa, 0x8f, 0x9e, 0x8b, 0xe7, 0x51, 0x88, 0x50, 0x59, + 0x75, 0x73, 0x58, 0xb7, 0xec, 0xa0, 0x55, 0x00, 0x29, 0xe7, 0xb1, 0x7e, 0xf2, 0xf0, 0xf6, 0x11, + 0x81, 0xc5, 0x34, 0x62, 0xeb, 0x92, 0xd9, 0xa5, 0x4a, 0x0f, 0x93, 0xad, 0xc0, 0x00, 0xc6, 0xec, + 0x52, 0x66, 0x64, 0x12, 0x88, 0xb6, 0x76, 0xd2, 0x68, 0xf9, 0x47, 0x49, 0x32, 0x4d, 0xaf, 0xb3, + 0x72, 0x66, 0x97, 0x3d, 0xb7, 0x48, 0xc3, 0x98, 0xb6, 0x2f, 0x14, 0x1e, 0xf6, 0x10, 0x1a, 0xd4, + 0x02, 0x1b, 0x61, 0x06, 0xd8, 0xb1, 0x77, 0x11, 0x98, 0xee, 0xc5, 0x61, 0xa0, 0xc0, 0xb6, 0xca, + 0x60, 0x36, 0x84, 0x23, 0x4f, 0x7f, 0x80, 0x85, 0x66, 0x1c, 0x11, 0xda, 0xd9, 0x18, 0x19, 0x16, + 0x62, 0x3c, 0x04, 0x5c, 0x78, 0x5e, 0xcf, 0x97, 0xf5, 0xbc, 0x80, 0xd3, 0xb7, 0x62, 0x45, 0x7d, + 0x61, 0xba, 0x9d, 0xe4, 0x05, 0xad, 0x5b, 0xd4, 0x24, 0x3b, 0x34, 0x49, 0x81, 0x87, 0xd3, 0x2e, + 0x93, 0x7b, 0xcd, 0x2f, 0xa7, 0x15, 0x3b, 0x09, 0x79, 0x25, 0xcf, 0xc4, 0xb6, 0x97, 0xe9, 0xb5, + 0xce, 0x0d, 0xf6, 0x82, 0x99, 0x98, 0xa8, 0xf0, 0xdc, 0x84, 0x41, 0xb6, 0x3c, 0x0f, 0x41, 0xc2, + 0xdd, 0xd5, 0x20, 0x08, 0x4c, 0x15, 0x7a, 0x71, 0xba, 0x16, 0x93, 0x0a, 0x4b, 0x93, 0xef, 0xba, + 0x39, 0xea, 0xa5, 0x63, 0x04, 0x5d, 0x33, 0x16, 0xa1, 0xcd, 0x9a, 0x14, 0x95, 0x3a, 0x5c, 0xc3, + 0x95, 0x91, 0x21, 0x20, 0x33, 0xdd, 0x5f, 0xa4, 0x57, 0x58, 0x98, 0x0b, 0x96, 0x68, 0x47, 0xf1, + 0x80, 0xd2, 0x9b, 0xf7, 0x61, 0xe2, 0xf1, 0x7c, 0x02, 0xaf, 0x15, 0xeb, 0xf1, 0x9a, 0xb1, 0x81, + 0x73, 0xd5, 0x88, 0xf8, 0xb6, 0xb0, 0xc2, 0x1d, 0x4f, 0x56, 0xc2, 0x6e, 0xeb, 0xad, 0xf2, 0x69, + 0x95, 0xd9, 0xb5, 0xc3, 0x90, 0x08, 0x2d, 0xab, 0xf9, 0xcc, 0x62, 0xe2, 0xc3, 0x72, 0x8f, 0x5b, + 0x9c, 0xa0, 0x5b, 0x28, 0x12, 0x79, 0xd2, 0x85, 0x25, 0xe8, 0xa5, 0xfb, 0xd3, 0xeb, 0x52, 0xb9, + 0xde, 0x22, 0x29, 0x4c, 0xd5, 0xc7, 0xc2, 0x71, 0x9d, 0x81, 0x73, 0xeb, 0x23, 0x44, 0x6d, 0x63, + 0x4f, 0x44, 0x5a, 0x7b, 0xa7, 0x49, 0xe9, 0xd5, 0x2a, 0x8b, 0xa1, 0x6d, 0x23, 0xc6, 0xa7, 0x50, + 0x97, 0x9b, 0xe9, 0x3a, 0x74, 0xbb, 0xd8, 0x0b, 0x19, 0x73, 0x4e, 0xc5, 0xe5, 0xba, 0x85, 0xde, + 0x92, 0xa9, 0x74, 0xec, 0x2a, 0x1b, 0x6b, 0xe6, 0xfd, 0x82, 0xa1, 0x6d, 0xcc, 0x5e, 0x1c, 0x6b, + 0x3d, 0xca, 0x6d, 0x67, 0x62, 0x49, 0x80, 0xe9, 0xf6, 0x0d, 0x4e, 0x0c, 0xf9, 0xec, 0x42, 0x95, + 0x78, 0x58, 0x67, 0x07, 0x41, 0x61, 0xf1, 0x98, 0x35, 0xb7, 0x60, 0xbe, 0x8e, 0xb0, 0xe9, 0x59, + 0x3b, 0x7b, 0x70, 0xaf, 0xc1, 0xc1, 0x17, 0x2c, 0xb9, 0xfc, 0x90, 0xc1, 0xb4, 0x54, 0x2d, 0x82, + 0xea, 0x07, 0xe0, 0xba, 0x2d, 0x75, 0x02, 0x17, 0x36, 0xb6, 0x9f, 0x93, 0x1f, 0x81, 0x91, 0xfe, + 0x17, 0x70, 0x5a, 0x16, 0x07, 0x74, 0xd0, 0xf4, 0x34, 0x2d, 0x12, 0xdb, 0x60, 0x2f, 0x22, 0x5c, + 0xde, 0x10, 0x36, 0x09, 0xa4, 0xa2, 0xf8, 0xf8, 0x5e, 0xb6, 0x6f, 0x4e, 0x15, 0xcf, 0x75, 0xba, + 0x32, 0x7c, 0xe9, 0xcd, 0x60, 0x6a, 0x05, 0xea, 0x24, 0x9d, 0xaa, 0x03, 0x2a, 0x39, 0xaf, 0x4c, + 0x9a, 0xdc, 0xde, 0x2b, 0x8e, 0x49, 0xa0, 0xed, 0x23, 0x05, 0x79, 0xf0, 0xe1, 0x7d, 0xc2, 0x4d, + 0x80, 0x96, 0x93, 0xe1, 0x07, 0x93, 0x45, 0xa9, 0x9c, 0x71, 0x68, 0x8e, 0x35, 0x36, 0xaa, 0x60, + 0x1c, 0xb5, 0xdb, 0xc1, 0x3a, 0x5c, 0x5c, 0xcb, 0x00, 0x05, 0xb9, 0xc5, 0x96, 0x42, 0x50, 0x7e, + 0x86, 0xe8, 0x18, 0x4c, 0xa6, 0x55, 0x51, 0x85, 0x85, 0x85, 0x6d, 0x41, 0xc6, 0xca, 0x80, 0x6f, + 0x1e, 0xda, 0x3b, 0x16, 0x38, 0x75, 0x06, 0x26, 0x22, 0x3f, 0xf6, 0xe7, 0xe3, 0x13, 0x3c, 0x43, + 0x0e, 0xd9, 0x4e, 0x8f, 0xf4, 0xb3, 0x3f, 0x5c, 0x85, 0x85, 0x07, 0x46, 0x8b, 0x98, 0x50, 0xde, + 0x3a, 0x40, 0xfa, 0x45, 0x4a, 0x44, 0x65, 0x17, 0x68, 0x9c, 0x8a, 0xdd, 0xcd, 0xe0, 0xac, 0xb9, + 0x4b, 0x4a, 0x5a, 0x40, 0x6b, 0x5d, 0x8a, 0xd1, 0xba, 0xe7, 0xb6, 0xbc, 0x01, 0x09, 0x51, 0x5b, + 0xe4, 0x07, 0xc5, 0x7d, 0x8d, 0x51, 0xb7, 0x4e, 0xa3, 0x2d, 0xdd, 0xef, 0x93, 0x6f, 0x6e, 0x67, + 0xaf, 0xc5, 0x57, 0x8a, 0x1e, 0x8b, 0x40, 0xa3, 0x32, 0x06, 0xc2, 0x0b, 0xaa, 0x11, 0x3b, 0x6e, + 0x18, 0x8e, 0x2f, 0x17, 0x55, 0xc3, 0xcb, 0x15, 0x1e, 0xc5, 0x51, 0x90, 0x93, 0x68, 0xf3, 0x9e, + 0xce, 0x89, 0xc1, 0x29, 0x4c, 0x20, 0xdf, 0x28, 0xe4, 0x92, 0x60, 0x11, 0x3c, 0xae, 0x34, 0x5c, + 0x46, 0x63, 0xc1, 0xe6, 0xe0, 0x19, 0xa1, 0x20, 0x57, 0x67, 0x0d, 0xd0, 0xee, 0x3a, 0xf5, 0x01, + 0x74, 0x23, 0x05, 0x41, 0xed, 0x3b, 0xb5, 0xee, 0xc2, 0xad, 0x22, 0xea, 0x4e, 0x56, 0xfd, 0x26, + 0x91, 0x12, 0x4f, 0x8e, 0x1f, 0xa6, 0x6f, 0xef, 0x8b, 0xb5, 0x41, 0x49, 0xa9, 0xe2, 0x11, 0x0f, + 0x1e, 0x2e, 0x3e, 0x57, 0xa7, 0x4f, 0xeb, 0xd4, 0x0b, 0x38, 0x3d, 0x4d, 0xa3, 0x63, 0xa7, 0xc3, + 0x65, 0x75, 0x24, 0x07, 0xe6, 0xe8, 0x86, 0x91, 0x91, 0xc1, 0x21, 0xb7, 0x96, 0xc5, 0xa4, 0x02, + 0x5a, 0x01, 0x87, 0x06, 0x60, 0xd3, 0x42, 0x76, 0xb4, 0xd5, 0x23, 0xe5, 0xe2, 0xda, 0x9c, 0x8a, + 0xcf, 0x64, 0xb5, 0x53, 0xe7, 0xcc, 0x02, 0x1e, 0x6b, 0x21, 0x13, 0x63, 0x88, 0x96, 0x76, 0x8f, + 0x52, 0xd3, 0xc6, 0x6c, 0x96, 0xb0, 0x35, 0x69, 0x18, 0x6b, 0x4d, 0x28, 0xb8, 0x4c, 0xb8, 0xa4, + 0x36, 0xea, 0x72, 0x0d, 0x58, 0x58, 0x68, 0x77, 0x2f, 0xd4, 0xd9, 0xd1, 0xa0, 0x41, 0x44, 0x07, + 0x11, 0xbb, 0xb6, 0x17, 0xb7, 0x02, 0x22, 0x7e, 0xbb, 0x0c, 0xa6, 0x82, 0xb8, 0x9f, 0x5e, 0x60, + 0x9b, 0x01, 0x78, 0xc6, 0x8a, 0x23, 0x24, 0x88, 0x7d, 0x44, 0x83, 0x85, 0x5a, 0x06, 0xb2, 0x6f, + 0x61, 0x63, 0xed, 0xb0, 0x28, 0x33, 0x88, 0x80, 0xc0, 0xe7, 0xba, 0x8d, 0x8a, 0xa6, 0xea, 0xed, + 0x83, 0xaa, 0xf9, 0x25, 0x38, 0x3f, 0xb1, 0x83, 0x76, 0x20, 0x34, 0x1d, 0x46, 0xb8, 0xc6, 0x1e, + 0xb6, 0xb0, 0xc9, 0xd0, 0x4a, 0x56, 0xa4, 0xd1, 0xeb, 0x10, 0xb4, 0x4c, 0x8b, 0xcf, 0x87, 0xc8, + 0x3b, 0xb3, 0x1e, 0xc2, 0x06, 0x35, 0xda, 0x16, 0x90, 0xc5, 0x2d, 0xf9, 0x2a, 0x2d, 0x6f, 0xb4, + 0x78, 0xa6, 0x27, 0x90, 0xf7, 0x32, 0xc1, 0x42, 0x12, 0x22, 0x90, 0x27, 0xb7, 0xcd, 0x03, 0xa9, + 0x95, 0x82, 0x4e, 0x50, 0x55, 0x9b, 0x2c, 0x85, 0x44, 0x04, 0xc9, 0x8e, 0x2a, 0x0f, 0x20, 0x7c, + 0x97, 0x44, 0xc5, 0x2d, 0xad, 0x24, 0x5a, 0xb4, 0x64, 0x2d, 0x4c, 0xec, 0xb9, 0x87, 0x04, 0xca, + 0x05, 0x4b, 0x67, 0xd9, 0x05, 0x5b, 0x3a, 0x62, 0x12, 0xa7, 0x02, 0x92, 0x88, 0x56, 0x77, 0x43, + 0xed, 0x13, 0xf4, 0x1c, 0xa5, 0x12, 0x31, 0x3f, 0x3f, 0x22, 0x66, 0xb8, 0x2f, 0xe0, 0x34, 0xc0, + 0x74, 0x8e, 0x8d, 0xd5, 0x79, 0x51, 0x59, 0x72, 0x44, 0xc2, 0x99, 0xb7, 0x84, 0xd7, 0x71, 0x51, + 0x29, 0x74, 0xcd, 0x6f, 0x7f, 0x08, 0xc6, 0xf6, 0x97, 0x6c, 0xb9, 0x4d, 0xf2, 0xb0, 0xed, 0xc8, + 0xa3, 0xaf, 0xb4, 0x0d, 0x0e, 0xda, 0x80, 0x87, 0x90, 0xb3, 0x54, 0xef, 0x14, 0x31, 0x30, 0xe4, + 0xb4, 0xc5, 0xaa, 0x32, 0x86, 0x21, 0x77, 0x61, 0x3f, 0x8b, 0x54, 0x5d, 0x26, 0xa3, 0xdf, 0x5e, + 0xdc, 0x71, 0x6d, 0xc6, 0x51, 0x2f, 0x5a, 0x57, 0xca, 0x0f, 0xfa, 0x00, 0x1e, 0xe6, 0x48, 0x58, + 0x49, 0xae, 0x78, 0x83, 0x17, 0x8e, 0xaf, 0xee, 0x1e, 0x33, 0x30, 0x69, 0xdb, 0x08, 0x87, 0x97, + 0x94, 0x04, 0x37, 0x23, 0xf3, 0x6b, 0x09, 0xb9, 0xd4, 0x80, 0xc2, 0x54, 0x29, 0x3b, 0x71, 0x6b, + 0x82, 0xa2, 0x6a, 0xdb, 0x0c, 0x82, 0x12, 0x1c, 0x9c, 0x50, 0xef, 0x2c, 0xf9, 0xae, 0x91, 0x15, + 0xef, 0x55, 0x04, 0x9b, 0xc5, 0x55, 0xab, 0x1f, 0x3b, 0x50, 0xc4, 0x88, 0x49, 0x53, 0xcf, 0x6d, + 0x74, 0xd6, 0x76, 0xc4, 0xc0, 0x83, 0x2e, 0x2f, 0x76, 0x80, 0x38, 0xac, 0xdd, 0x5d, 0xb0, 0x88, + 0x1d, 0xa5, 0xba, 0x4d, 0x1c, 0xd4, 0x95, 0x42, 0xdd, 0xf9, 0x75, 0xcc, 0x51, 0xab, 0x36, 0xd4, + 0x46, 0x6d, 0x5d, 0x10, 0xf2, 0x49, 0x85, 0xca, 0xa5, 0x04, 0xa3, 0xe4, 0x2d, 0xe2, 0x7a, 0x41, + 0xca, 0x10, 0xc7, 0x84, 0x6e, 0xdb, 0x2e, 0x24, 0x09, 0x8f, 0x6f, 0xaf, 0x2e, 0xb3, 0xa9, 0xf4, + 0xe5, 0x10, 0x79, 0x06, 0xc9, 0x50, 0x92, 0x5b, 0x53, 0x0f, 0x40, 0x95, 0x4e, 0xea, 0xeb, 0x39, + 0x95, 0x23, 0xe8, 0xb9, 0x7e, 0xbe, 0x7b, 0x0f, 0xc3, 0x0f, 0x0e, 0x0d, 0xf1, 0x49, 0x5c, 0x86, + 0x76, 0x10, 0xd8, 0xbb, 0x96, 0x02, 0xb1, 0xa6, 0xf3, 0xc0, 0x88, 0x09, 0xf2, 0x60, 0xa5, 0x83, + 0x91, 0xb6, 0xba, 0xb7, 0x24, 0xac, 0xa0, 0x43, 0xa4, 0x43, 0xb4, 0x83, 0x18, 0x17, 0x46, 0x47, + 0x54, 0x6b, 0x0e, 0xc8, 0x5a, 0x62, 0x22, 0x82, 0x1e, 0x39, 0x4a, 0x7d, 0xbe, 0x9f, 0x3e, 0x95, + 0x9b, 0x3f, 0x99, 0xd3, 0x10, 0x28, 0x9e, 0xff, 0xb5, 0xc9, 0x66, 0x7b, 0x0f, 0x1d, 0x0c, 0x6a, + 0xdb, 0x63, 0x43, 0x92, 0x53, 0x29, 0xda, 0xf1, 0xc4, 0x46, 0x43, 0xa5, 0xcf, 0x57, 0x4e, 0xbf, + 0xd2, 0x99, 0x4e, 0xa2, 0xe1, 0x57, 0x72, 0xf7, 0xe4, 0xe2, 0x72, 0xa6, 0x43, 0x49, 0x77, 0xe5, + 0xba, 0x44, 0xf9, 0x05, 0xb0, 0xc8, 0x8e, 0x2f, 0x83, 0x65, 0x16, 0x2f, 0x92, 0x48, 0x81, 0x38, + 0xfd, 0x41, 0x95, 0x94, 0x9f, 0x8b, 0x5d, 0x07, 0xb7, 0x17, 0x96, 0x2a, 0xa4, 0xc2, 0x69, 0x2c, + 0xde, 0xd9, 0xb9, 0xd6, 0xd1, 0x1c, 0x3e, 0x7a, 0x88, 0x92, 0xa3, 0x74, 0x5b, 0x95, 0x05, 0xd1, + 0x62, 0x02, 0xdb, 0xf6, 0x3c, 0x5c, 0x21, 0x31, 0x5c, 0x66, 0x92, 0x90, 0x81, 0x6b, 0x29, 0x14, + 0x60, 0x3e, 0x41, 0x18, 0x4c, 0x0f, 0x9f, 0x36, 0xf1, 0x89, 0xf9, 0x72, 0x1b, 0x78, 0xb0, 0x83, + 0x8a, 0x82, 0xf9, 0x51, 0x5b, 0x46, 0x50, 0x9a, 0x4f, 0x95, 0xc8, 0x8b, 0x42, 0x74, 0x84, 0x1c, + 0xa6, 0xda, 0x76, 0xc9, 0x4e, 0x08, 0x1e, 0x55, 0x0c, 0x31, 0xb4, 0xcb, 0x90, 0x9e, 0x86, 0x91, + 0x51, 0x5c, 0xee, 0xe9, 0x98, 0x9e, 0x95, 0xe9, 0x8b, 0x3e, 0x61, 0xf2, 0x21, 0x1c, 0xa2, 0xa2, + 0x86, 0x11, 0xe2, 0xac, 0xcb, 0x1b, 0x65, 0x21, 0x77, 0x56, 0x42, 0x27, 0xf2, 0x3b, 0xf0, 0xbb, + 0xc8, 0x2c, 0x92, 0x8f, 0x52, 0xe4, 0x51, 0xd3, 0x18, 0x8f, 0x01, 0xc0, 0x96, 0xf5, 0x7d, 0xf3, + 0x12, 0x78, 0x2a, 0xd1, 0x41, 0xd6, 0xa4, 0x6e, 0xb8, 0x22, 0xa3, 0x0e, 0x6b, 0x51, 0x22, 0x30, + 0x3c, 0x8f, 0xad, 0xb3, 0xb6, 0xb5, 0xea, 0xca, 0x10, 0xdd, 0x51, 0x61, 0x55, 0xfd, 0x42, 0x03, + 0x91, 0x86, 0x53, 0x57, 0x50, 0x12, 0x73, 0xd5, 0x88, 0x92, 0xf2, 0x60, 0xac, 0x92, 0x58, 0xd9, + 0x49, 0x8f, 0x0c, 0xe2, 0x0c, 0xed, 0xd1, 0xfa, 0x2c, 0x04, 0x0c, 0xae, 0xb3, 0x17, 0x2c, 0xbd, + 0x47, 0xc0, 0xf0, 0xe9, 0x88, 0xe2, 0x57, 0x3f, 0x67, 0x51, 0x01, 0xcc, 0x23, 0x2f, 0xe0, 0xb4, + 0xbd, 0x7b, 0x73, 0x5c, 0xcf, 0x8e, 0x23, 0xce, 0xb1, 0xb8, 0x74, 0xdf, 0x19, 0xc5, 0x2b, 0x01, + 0x55, 0xb4, 0x3d, 0x38, 0x2b, 0x81, 0xd6, 0x99, 0x73, 0x66, 0x15, 0x91, 0xe9, 0x00, 0x66, 0x96, + 0x8b, 0xd5, 0x22, 0xa1, 0xdc, 0x1b, 0x9f, 0xcb, 0xac, 0xbb, 0xb8, 0xc3, 0x2b, 0xb5, 0x1b, 0x13, + 0x58, 0x2b, 0x91, 0xb2, 0x08, 0xdc, 0xe7, 0xf4, 0xe2, 0x8d, 0xa2, 0x25, 0xba, 0xb8, 0xd7, 0x00, + 0x22, 0x4a, 0xdc, 0x70, 0x4b, 0x48, 0x2d, 0x13, 0x82, 0x79, 0xa5, 0xfd, 0xb6, 0xd9, 0xa3, 0x9a, + 0x89, 0x0d, 0x0c, 0xe1, 0x98, 0x40, 0xc4, 0x4e, 0x43, 0xf6, 0x9e, 0x30, 0xd7, 0xb4, 0x84, 0xde, + 0x62, 0x57, 0x4c, 0x02, 0x12, 0x63, 0x29, 0xa7, 0xf0, 0x4d, 0x19, 0xba, 0x05, 0x71, 0x0d, 0x9e, + 0xf5, 0x6e, 0x6e, 0x21, 0xdd, 0xe1, 0xf6, 0x88, 0x69, 0xed, 0x08, 0xa7, 0xcd, 0x3f, 0x40, 0x9c, + 0xca, 0x54, 0xb2, 0x03, 0xe0, 0x3c, 0x3c, 0x12, 0xa8, 0xb8, 0x66, 0xb8, 0x46, 0xe1, 0x9a, 0xcc, + 0xbb, 0x32, 0x4e, 0x16, 0xb8, 0x2d, 0xa3, 0x00, 0xee, 0x8e, 0x3e, 0xd0, 0xb8, 0xe8, 0x06, 0xf7, + 0x17, 0x8e, 0xda, 0x26, 0x16, 0x46, 0xee, 0x0b, 0x62, 0xd0, 0xc3, 0x0a, 0x07, 0x28, 0x81, 0x29, + 0x9b, 0x88, 0x1a, 0xb9, 0x9d, 0x75, 0x4d, 0xd8, 0xad, 0xb7, 0x4e, 0x02, 0x30, 0x5c, 0x11, 0x15, + 0x8e, 0x1b, 0x14, 0xa7, 0x6f, 0xa7, 0x31, 0x16, 0x26, 0x21, 0x62, 0xc1, 0x51, 0x91, 0xdf, 0xcd, + 0x21, 0x6e, 0xca, 0x16, 0x76, 0x55, 0x2a, 0x73, 0xab, 0x8f, 0x83, 0x29, 0x2c, 0xbb, 0xf1, 0xf8, + 0xa4, 0x8c, 0x8d, 0x52, 0xe1, 0x2e, 0x81, 0x6b, 0xfb, 0xe0, 0xfd, 0xd0, 0xc1, 0xcc, 0x36, 0x6e, + 0x89, 0xce, 0x61, 0xd9, 0xa3, 0x3a, 0x1d, 0xa1, 0x47, 0x5d, 0xe3, 0x49, 0x34, 0xed, 0xa8, 0x1e, + 0xc0, 0x70, 0x81, 0x3a, 0x0b, 0x77, 0x10, 0xa7, 0xd0, 0x85, 0x18, 0x95, 0x61, 0x19, 0xb6, 0x08, + 0x50, 0xbb, 0xb9, 0x9d, 0xca, 0x29, 0x6b, 0x09, 0xfb, 0x7b, 0xbe, 0xde, 0xcd, 0xa2, 0x77, 0xed, + 0xb9, 0xde, 0xe3, 0xb4, 0xdb, 0x7d, 0x01, 0xa7, 0xd7, 0x8b, 0x1b, 0x7c, 0xa4, 0x28, 0xa7, 0x6d, + 0xbb, 0x71, 0xb2, 0x4d, 0x3b, 0xc0, 0x20, 0xae, 0xec, 0x66, 0x03, 0xdd, 0x15, 0xc8, 0x5a, 0x0e, + 0x51, 0xe1, 0x87, 0xd6, 0x44, 0xa1, 0xe4, 0x91, 0x51, 0xfd, 0x7b, 0x75, 0xec, 0xda, 0xc4, 0xce, + 0x4a, 0x3e, 0x38, 0x81, 0x4a, 0x07, 0x12, 0xfc, 0x3b, 0x8d, 0x34, 0x16, 0x9d, 0xaa, 0xb0, 0xd7, + 0x7d, 0x99, 0xee, 0xdd, 0x75, 0x6c, 0x39, 0x2d, 0x66, 0x96, 0xea, 0xab, 0x75, 0xdb, 0x54, 0xb1, + 0x14, 0x14, 0xab, 0x74, 0x2b, 0xde, 0xd4, 0x92, 0xd1, 0xed, 0x09, 0xe2, 0xae, 0x47, 0x89, 0x30, + 0x9e, 0x5a, 0x82, 0xd9, 0x2a, 0x64, 0x9a, 0xd8, 0xab, 0x4c, 0x19, 0xde, 0x0d, 0x02, 0xe8, 0x52, + 0xde, 0x1a, 0x31, 0x74, 0x75, 0x51, 0x35, 0x8b, 0x0f, 0xd0, 0xe9, 0x12, 0xaf, 0xd1, 0x45, 0x9e, + 0xd8, 0x7b, 0xb0, 0xde, 0x41, 0x5f, 0xce, 0xd4, 0x45, 0xd8, 0xfe, 0x5e, 0x9a, 0x83, 0x33, 0x25, + 0xcb, 0x28, 0x15, 0x11, 0x51, 0x22, 0xf1, 0x82, 0x31, 0xea, 0xdd, 0xce, 0xb0, 0x24, 0x6a, 0x93, + 0x8c, 0xcf, 0xa8, 0xa8, 0x76, 0x6d, 0x59, 0xe2, 0x86, 0x63, 0x21, 0x76, 0x3c, 0x81, 0x32, 0xbb, + 0x63, 0x01, 0x47, 0xa5, 0xca, 0x8e, 0xd2, 0x16, 0xdd, 0xd7, 0x6c, 0x80, 0xb2, 0x08, 0xf2, 0x1a, + 0xc3, 0x48, 0x95, 0x6b, 0xac, 0xf5, 0x87, 0x39, 0x98, 0xa0, 0x17, 0x17, 0x49, 0xb9, 0x94, 0x23, + 0xdc, 0x84, 0x65, 0xa3, 0x28, 0x3f, 0xc9, 0x4c, 0xda, 0x61, 0xbd, 0x30, 0x29, 0xc4, 0xf4, 0xd2, + 0x6b, 0xf2, 0xb9, 0xf7, 0xeb, 0xb7, 0x43, 0xfc, 0x1d, 0x17, 0xae, 0x11, 0x8f, 0x17, 0xd8, 0xf8, + 0x01, 0x04, 0x4e, 0x62, 0x07, 0x05, 0x0b, 0x51, 0xb5, 0x02, 0xc3, 0x1d, 0xe3, 0x2b, 0xcb, 0x79, + 0x29, 0xcf, 0x6c, 0x44, 0xa7, 0x95, 0xe3, 0xb1, 0xb6, 0x9b, 0x71, 0xfd, 0xfb, 0x21, 0xd5, 0x7c, + 0xcd, 0xc3, 0x54, 0x6e, 0x1e, 0xa7, 0x50, 0xe7, 0x92, 0x63, 0xd9, 0xec, 0x29, 0x71, 0x0a, 0x48, + 0x70, 0x0a, 0x11, 0xe3, 0xb6, 0x0f, 0x97, 0x32, 0xcf, 0xf5, 0xd3, 0x5a, 0xf1, 0x0b, 0x38, 0x1d, + 0xfa, 0x14, 0x69, 0x51, 0xc7, 0xc6, 0x40, 0x54, 0x04, 0x5c, 0x43, 0x20, 0x40, 0xf9, 0x44, 0xa6, + 0x65, 0x80, 0x95, 0xcf, 0x23, 0x64, 0x7e, 0xa1, 0xdb, 0x96, 0x2c, 0xed, 0x9b, 0x42, 0x6d, 0x1a, + 0xf0, 0xe4, 0xb5, 0xd7, 0x72, 0x37, 0xa8, 0xc7, 0x16, 0x42, 0x7b, 0x29, 0x6f, 0x18, 0x22, 0xf8, + 0xb4, 0xe2, 0x4e, 0x55, 0x70, 0xde, 0xcc, 0x27, 0xd2, 0x23, 0xd0, 0xbb, 0x42, 0xc0, 0x60, 0x49, + 0x0e, 0xb2, 0x97, 0x4a, 0xe8, 0x24, 0x65, 0x3e, 0xdb, 0x5e, 0x9a, 0x98, 0x81, 0xac, 0x94, 0xfc, + 0x5a, 0xc9, 0x3a, 0x39, 0xbb, 0x5d, 0xf0, 0x92, 0xd8, 0x63, 0x23, 0xc7, 0xe8, 0xf0, 0x7e, 0xae, + 0x9f, 0x41, 0x9b, 0xd7, 0xf5, 0x70, 0xd9, 0xdc, 0x4c, 0xaa, 0x44, 0x02, 0x6d, 0x9b, 0xeb, 0x5c, + 0x2a, 0x0e, 0xca, 0x84, 0x7c, 0xaf, 0x57, 0x18, 0x1f, 0x9b, 0xb7, 0x86, 0x25, 0xf3, 0xd6, 0x31, + 0xc5, 0x01, 0xd4, 0xda, 0x2f, 0xa4, 0xf2, 0xcc, 0x08, 0x89, 0x71, 0xa7, 0x88, 0xe0, 0x5e, 0xdf, + 0xd8, 0x80, 0xc7, 0x1f, 0xed, 0xbe, 0x86, 0x96, 0xd4, 0x8b, 0xb9, 0xa0, 0xd6, 0x9b, 0x21, 0x6c, + 0x08, 0x75, 0x1e, 0xab, 0xc6, 0x76, 0x27, 0xc9, 0x49, 0x52, 0xb7, 0x7c, 0xed, 0x31, 0xb2, 0x2e, + 0xe6, 0x27, 0x33, 0x1e, 0xc1, 0xef, 0xda, 0x8c, 0xb2, 0x45, 0x2c, 0x08, 0x40, 0xdb, 0x9e, 0x9b, + 0x4c, 0xaf, 0xb5, 0x37, 0x1f, 0xb2, 0x3f, 0x67, 0xf9, 0x06, 0x80, 0xae, 0x17, 0x70, 0xda, 0x33, + 0xc4, 0x00, 0x92, 0x39, 0x2b, 0x30, 0xd6, 0x75, 0x2b, 0x8e, 0x79, 0x1f, 0x0f, 0xb0, 0x36, 0x2a, + 0xd2, 0xd6, 0xb2, 0x66, 0xaf, 0x00, 0x85, 0xa7, 0x30, 0x16, 0x16, 0x67, 0x98, 0xad, 0x5e, 0x62, + 0x61, 0xf1, 0x54, 0x0f, 0x9b, 0x64, 0xe6, 0x8f, 0x3a, 0xa5, 0xe6, 0x2e, 0xd6, 0xe0, 0xec, 0xe8, + 0x7d, 0xb3, 0x32, 0xbc, 0xb6, 0x6a, 0x8f, 0x6c, 0x29, 0x92, 0xc7, 0x88, 0xcb, 0x67, 0x45, 0xd1, + 0xf8, 0xda, 0x82, 0x35, 0x58, 0xcd, 0x37, 0x18, 0x39, 0x9f, 0xad, 0x90, 0xb8, 0xbe, 0x67, 0x87, + 0x88, 0xd3, 0x0b, 0x85, 0x4e, 0x52, 0xe2, 0x54, 0xad, 0xe9, 0x27, 0xe0, 0x32, 0x77, 0xff, 0x74, + 0x11, 0x46, 0xeb, 0x37, 0x49, 0x6a, 0xc3, 0x00, 0x77, 0xcd, 0x72, 0xa7, 0xd0, 0x5b, 0x5a, 0x7b, + 0x04, 0x1f, 0x45, 0x2c, 0x06, 0x8e, 0x5d, 0xc4, 0xab, 0x5f, 0x23, 0x96, 0x98, 0x7a, 0x56, 0x63, + 0x75, 0x07, 0x26, 0xd6, 0x60, 0xc0, 0x20, 0xdf, 0x08, 0xad, 0xc0, 0x61, 0x76, 0xb5, 0xe0, 0xdf, + 0x80, 0x4f, 0xc7, 0x0c, 0x01, 0xdb, 0x68, 0xb1, 0x5a, 0xeb, 0xf9, 0xe5, 0xc6, 0x48, 0x0e, 0x57, + 0x41, 0xa3, 0x55, 0x05, 0xb3, 0x00, 0xd3, 0x92, 0x06, 0x6c, 0xba, 0xcb, 0xb9, 0xda, 0xe8, 0x11, + 0x4e, 0x68, 0x5b, 0x89, 0x34, 0x46, 0xa6, 0xab, 0x33, 0xb8, 0x56, 0xcd, 0xf0, 0x88, 0x1c, 0x9b, + 0xb6, 0x23, 0x8a, 0xe9, 0x3b, 0x88, 0x79, 0xe5, 0x36, 0x92, 0xdd, 0xd0, 0x70, 0xcd, 0xc9, 0x9a, + 0xda, 0x2e, 0xc4, 0xd1, 0x9a, 0x0c, 0xb1, 0x86, 0xf6, 0x0f, 0xcc, 0x9d, 0xf8, 0x26, 0x6a, 0x46, + 0x37, 0x3e, 0xf4, 0x2d, 0x43, 0x34, 0x10, 0xcc, 0x9b, 0x87, 0xe6, 0x0f, 0xee, 0xbf, 0x4b, 0x65, + 0xcc, 0x66, 0x7a, 0x8e, 0x84, 0x65, 0x7d, 0x82, 0x5d, 0xba, 0x73, 0x8c, 0x06, 0xe3, 0x0e, 0x0b, + 0x52, 0x42, 0x2a, 0x63, 0xa8, 0x92, 0x6f, 0xca, 0xc4, 0xf0, 0x61, 0xec, 0x3d, 0x4f, 0x59, 0xae, + 0x68, 0x93, 0xfa, 0x0e, 0x0a, 0xa6, 0x77, 0x83, 0x5b, 0xb3, 0xab, 0xf0, 0xf1, 0x64, 0xf1, 0x39, + 0x1d, 0x11, 0xc8, 0xc8, 0x3e, 0x91, 0xd3, 0x58, 0x6b, 0xab, 0x3f, 0xd2, 0x30, 0x8d, 0xf9, 0xbd, + 0x66, 0xfb, 0xc0, 0x50, 0x15, 0x5a, 0xcc, 0xe2, 0x43, 0x42, 0x88, 0x2c, 0x94, 0x27, 0xde, 0xc9, + 0xa3, 0xd4, 0x31, 0x75, 0x58, 0x70, 0x30, 0x59, 0x48, 0x89, 0x27, 0x7c, 0xef, 0xf8, 0x36, 0xf8, + 0xfa, 0x82, 0x28, 0x44, 0xe2, 0x7b, 0x94, 0xd5, 0x60, 0x01, 0x22, 0xb0, 0xc6, 0x11, 0xdc, 0x45, + 0xa2, 0xc1, 0x08, 0x07, 0x8c, 0xec, 0x67, 0x6b, 0x34, 0x49, 0xda, 0x3c, 0xcd, 0x03, 0x2c, 0x76, + 0xd1, 0xba, 0x1f, 0x79, 0x3f, 0xcd, 0xe2, 0xaf, 0x04, 0x06, 0xe0, 0x10, 0x24, 0xf0, 0x34, 0x42, + 0x11, 0x51, 0x2e, 0xb4, 0x93, 0xcd, 0x1d, 0xf3, 0x78, 0xa9, 0x0c, 0xd9, 0x11, 0x30, 0x89, 0xf8, + 0x41, 0x19, 0x0e, 0x29, 0x0b, 0xab, 0x66, 0x0c, 0x28, 0xb9, 0xdd, 0x9c, 0x0d, 0x3b, 0x92, 0x76, + 0x5b, 0x28, 0xc1, 0x43, 0x7b, 0xaf, 0x6d, 0xdf, 0x61, 0x21, 0xdc, 0xa4, 0x71, 0x4a, 0xc9, 0x69, + 0xfd, 0xa8, 0xb9, 0x3d, 0x5e, 0x85, 0xd8, 0x6e, 0xa2, 0xdf, 0x0e, 0x60, 0x5b, 0x53, 0xc9, 0x5b, + 0xeb, 0xc1, 0x71, 0x83, 0x9b, 0xd9, 0x95, 0x96, 0x59, 0x76, 0xc3, 0x07, 0x98, 0xb6, 0x1d, 0x9c, + 0xd8, 0x5a, 0xb3, 0x6f, 0xec, 0x1f, 0xae, 0xc1, 0x64, 0x0c, 0xe8, 0xec, 0x21, 0xcf, 0x63, 0xff, + 0xf8, 0x9f, 0x36, 0x67, 0xe4, 0x9b, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, + 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, + 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x5e, 0x47, 0x3c, 0x99, 0x0f, 0xfe, 0xf8, 0x5c, + 0xb7, 0xca, 0xca, 0x9b, 0x5d, 0x3a, 0x22, 0x85, 0x57, 0xef, 0x07, 0x6e, 0x18, 0xab, 0x35, 0xcf, + 0xc1, 0x86, 0x25, 0xad, 0x48, 0xee, 0xec, 0xd4, 0x3c, 0x55, 0xbf, 0xb9, 0x4d, 0x74, 0x7b, 0xfc, + 0xe1, 0x76, 0x68, 0x3f, 0xe1, 0x6a, 0xd4, 0xd5, 0x0a, 0xc8, 0x22, 0x42, 0xf6, 0x2d, 0xb0, 0xac, + 0x4f, 0x5d, 0xf8, 0xb8, 0xa3, 0x21, 0xcf, 0x37, 0xd9, 0xc9, 0xb4, 0x1a, 0x24, 0x3b, 0xee, 0x4e, + 0xce, 0xc4, 0x0e, 0x06, 0x82, 0xa2, 0x0c, 0x06, 0xf0, 0x6d, 0x71, 0xb3, 0x0c, 0x95, 0x1b, 0x40, + 0x41, 0x7c, 0x2c, 0x71, 0x7a, 0x0d, 0xbc, 0xef, 0x12, 0x7b, 0x85, 0x76, 0x02, 0x8f, 0x3f, 0xa6, + 0xcf, 0x97, 0xc0, 0x35, 0x53, 0xeb, 0x8d, 0x38, 0xf3, 0xc9, 0x9a, 0x92, 0x3d, 0x6f, 0x10, 0x84, + 0xc0, 0x02, 0xb8, 0xef, 0x5f, 0x32, 0x5b, 0x89, 0x34, 0x3a, 0xc6, 0x62, 0x38, 0xb4, 0x68, 0x36, + 0xce, 0x59, 0xd6, 0x2f, 0x8b, 0xa9, 0x4b, 0x09, 0x73, 0xc7, 0xd4, 0x0a, 0x68, 0xf5, 0x06, 0x4b, + 0x85, 0x60, 0x6e, 0x51, 0xaa, 0xc1, 0x48, 0x71, 0x06, 0xe4, 0x0b, 0x82, 0x36, 0x28, 0x17, 0xf3, + 0x8e, 0x00, 0x5c, 0x8d, 0xce, 0x99, 0x71, 0x89, 0x19, 0x6b, 0x19, 0x0c, 0xd3, 0x02, 0x00, 0xc6, + 0x04, 0xb0, 0x01, 0x42, 0xbb, 0x89, 0x6a, 0x41, 0xd9, 0x06, 0x06, 0x86, 0x68, 0x42, 0xcc, 0xec, + 0xb1, 0x58, 0xa2, 0xeb, 0x59, 0x16, 0x70, 0x26, 0x33, 0x50, 0x10, 0xe4, 0x77, 0x2b, 0x73, 0x26, + 0x13, 0xe0, 0x76, 0x00, 0x40, 0xae, 0x0c, 0xef, 0xdb, 0xee, 0xef, 0x8a, 0x4d, 0xcc, 0xec, 0x48, + 0x78, 0x78, 0xdb, 0xd0, 0x7d, 0x1b, 0x12, 0x5a, 0x8f, 0xc4, 0xb4, 0x94, 0xb9, 0x2a, 0x43, 0xc7, + 0x32, 0xdc, 0x6e, 0x85, 0xa5, 0xb0, 0x3e, 0x2d, 0x9c, 0x7f, 0xe0, 0x15, 0x1f, 0xae, 0x16, 0xf1, + 0x8a, 0x01, 0xb8, 0x7e, 0xbb, 0x90, 0x07, 0xba, 0x18, 0x7e, 0x10, 0x50, 0x50, 0x82, 0xd4, 0x65, + 0x73, 0x05, 0xa0, 0x47, 0xbb, 0x9e, 0xf7, 0x87, 0xe6, 0x52, 0x3f, 0xd9, 0xab, 0x00, 0x50, 0x32, + 0x75, 0xdc, 0x69, 0x31, 0xd7, 0x22, 0x88, 0xbb, 0x7c, 0xc7, 0xf5, 0x7e, 0xea, 0x8e, 0xde, 0x74, + 0x6d, 0x6b, 0xd5, 0xd4, 0xb6, 0x9c, 0x42, 0xc4, 0xee, 0x77, 0xe3, 0x9a, 0xba, 0xc6, 0x1f, 0x5b, + 0x29, 0x9a, 0xc9, 0x20, 0xb6, 0xf2, 0x78, 0xc0, 0x0e, 0x6d, 0x2f, 0x62, 0xeb, 0xca, 0xf4, 0x5a, + 0x81, 0x81, 0xf8, 0x7c, 0xc4, 0x32, 0x5c, 0x49, 0x59, 0x3a, 0x5c, 0xaa, 0x1e, 0x0b, 0x2f, 0x09, + 0x8c, 0xae, 0x4f, 0x7f, 0xe8, 0x7d, 0x88, 0x6a, 0x92, 0xf2, 0xb8, 0x35, 0x38, 0x38, 0x69, 0x95, + 0x0c, 0x91, 0xd3, 0x51, 0x6e, 0x69, 0x43, 0x07, 0xb1, 0xf6, 0x8b, 0x00, 0x82, 0x0d, 0x2d, 0x6d, + 0xeb, 0x93, 0x13, 0x8e, 0x24, 0x32, 0x2d, 0x31, 0x8e, 0xac, 0xa2, 0x21, 0xd5, 0x41, 0x22, 0x56, + 0x75, 0x3a, 0xc7, 0xab, 0x95, 0xd5, 0x59, 0x03, 0x79, 0x3d, 0xfe, 0x60, 0xd5, 0x46, 0x76, 0xf9, + 0xe6, 0x41, 0xe9, 0x56, 0x7a, 0x38, 0x14, 0xe6, 0xac, 0x34, 0xfa, 0xbc, 0x83, 0xbe, 0x32, 0x93, + 0x03, 0x68, 0xb1, 0x4e, 0x1a, 0x75, 0x11, 0xf6, 0x17, 0x75, 0x96, 0xce, 0x91, 0x23, 0xa5, 0xac, + 0x9f, 0x01, 0xcc, 0x98, 0x20, 0x95, 0x6c, 0x09, 0x8f, 0x57, 0x6d, 0x4c, 0xe7, 0x58, 0x28, 0x81, + 0x9b, 0xa1, 0xe5, 0x7d, 0xa3, 0xfb, 0x41, 0x35, 0x32, 0xf5, 0xf0, 0xbe, 0x64, 0x02, 0x51, 0x14, + 0x44, 0x2e, 0x5e, 0xc6, 0x8a, 0x0e, 0xa9, 0xed, 0xcb, 0x99, 0x8d, 0xb4, 0x2b, 0x31, 0xb8, 0x15, + 0x31, 0x26, 0xdb, 0x83, 0x2a, 0x3e, 0xd3, 0x7c, 0x3c, 0xf1, 0xc0, 0xe8, 0x57, 0x6f, 0x4d, 0x20, + 0xfd, 0x41, 0x51, 0x23, 0xdb, 0x2d, 0x01, 0x45, 0xe9, 0x81, 0x5e, 0x4e, 0x2a, 0xdb, 0x63, 0x5f, + 0x34, 0x44, 0x5b, 0x27, 0x0a, 0xfc, 0xb6, 0xf5, 0x83, 0x99, 0x74, 0x07, 0xa3, 0xb4, 0xf7, 0x50, + 0x2f, 0x02, 0xa2, 0x60, 0x9d, 0x1d, 0x9c, 0x98, 0x59, 0x36, 0x53, 0x54, 0x79, 0x8f, 0x80, 0x40, + 0x7d, 0x84, 0xe7, 0x43, 0x0b, 0x23, 0x5a, 0xb4, 0x7b, 0x0f, 0x59, 0x8a, 0x9d, 0xcc, 0xbb, 0xbb, + 0x9e, 0xf7, 0x49, 0x6a, 0x7d, 0x01, 0xa7, 0xad, 0x28, 0xca, 0xe7, 0xf0, 0x3d, 0x1a, 0x67, 0xa7, + 0xb7, 0xea, 0x33, 0x2e, 0x84, 0xa6, 0xfd, 0x73, 0xad, 0xa3, 0x43, 0x0b, 0x93, 0xa2, 0x58, 0x8e, + 0x53, 0xd4, 0x65, 0x3b, 0x67, 0xb6, 0x2a, 0x08, 0xa0, 0xe1, 0x8f, 0x5a, 0x4f, 0x2b, 0x4d, 0x97, + 0x50, 0x38, 0x3f, 0xe7, 0x01, 0x38, 0x6e, 0x2f, 0xc2, 0x3b, 0xae, 0x8a, 0x16, 0x8e, 0x27, 0xa4, + 0xda, 0x6c, 0xc7, 0x35, 0xd8, 0x5b, 0xcb, 0x7a, 0x8b, 0xab, 0x35, 0x8f, 0x84, 0x36, 0x5b, 0x85, + 0x3b, 0x48, 0x71, 0x9f, 0xdc, 0xcd, 0xa7, 0x1f, 0xda, 0x8e, 0xbc, 0xa9, 0x04, 0xf3, 0xe6, 0xcc, + 0x4e, 0xc6, 0x93, 0x67, 0xcf, 0x17, 0xfa, 0x06, 0x23, 0xca, 0x98, 0x95, 0x46, 0x1b, 0xeb, 0xb2, + 0x36, 0x02, 0x74, 0x7b, 0xdf, 0x60, 0xc1, 0x39, 0xe2, 0x02, 0x70, 0x4c, 0xe4, 0xde, 0x94, 0xcb, + 0xf4, 0x2e, 0x80, 0x16, 0xe1, 0x5a, 0x26, 0x65, 0x5a, 0x99, 0xb8, 0xe4, 0x2f, 0x0a, 0xed, 0x58, + 0x7e, 0xd4, 0xc2, 0xf4, 0x1b, 0x16, 0xb2, 0xc4, 0xa0, 0x50, 0xff, 0x0e, 0x78, 0x60, 0x9c, 0x1b, + 0xcb, 0x1d, 0xa3, 0xc6, 0x47, 0xd9, 0xae, 0x71, 0x77, 0x77, 0xf6, 0x56, 0xa5, 0x1c, 0x0d, 0x1d, + 0x6f, 0xc2, 0x96, 0xac, 0xad, 0x00, 0xa9, 0xbc, 0x91, 0x89, 0xf4, 0x68, 0x5e, 0x43, 0xdf, 0xbe, + 0x4f, 0x64, 0x4f, 0x24, 0x0c, 0xfd, 0xc7, 0x88, 0xb8, 0x20, 0x50, 0x15, 0xa3, 0xef, 0x17, 0xdb, + 0x23, 0x6e, 0xf0, 0xd8, 0x3b, 0x61, 0x21, 0x24, 0x34, 0x36, 0x74, 0x25, 0x74, 0x1d, 0xc4, 0x44, + 0x22, 0xa0, 0xa2, 0x36, 0xe7, 0x39, 0xa9, 0x06, 0xbb, 0xe4, 0xc5, 0x57, 0xb3, 0xf1, 0xea, 0x9c, + 0x37, 0x6b, 0x76, 0x2f, 0x55, 0x1f, 0x0f, 0x84, 0x82, 0x92, 0x23, 0x22, 0x59, 0x59, 0x94, 0x04, + 0xd6, 0x8b, 0xa2, 0x51, 0x5c, 0x69, 0x37, 0xac, 0xfa, 0xda, 0x23, 0x87, 0x7b, 0x90, 0x06, 0x15, + 0xdf, 0xb7, 0x73, 0x56, 0xd0, 0xee, 0x50, 0x6a, 0xe8, 0xce, 0x42, 0x2a, 0x25, 0x15, 0x77, 0xc2, + 0xed, 0x73, 0xdc, 0xee, 0x5b, 0x21, 0x79, 0xe2, 0xf9, 0x3a, 0xad, 0x1d, 0x79, 0x01, 0xa7, 0x61, + 0x4a, 0x64, 0x1b, 0xea, 0xea, 0xa0, 0xf1, 0xcc, 0x9c, 0x41, 0x1f, 0xf0, 0x3e, 0xd4, 0x37, 0x61, + 0x01, 0x2b, 0x91, 0x05, 0x60, 0x1c, 0xba, 0xbe, 0xb4, 0x02, 0x59, 0x8b, 0xde, 0x79, 0x4b, 0x87, + 0x50, 0x38, 0xd7, 0x37, 0x32, 0x48, 0xc2, 0x08, 0x52, 0x84, 0xca, 0xb3, 0xc0, 0x64, 0x17, 0x52, + 0x9c, 0x16, 0x29, 0x0f, 0x1f, 0x0f, 0x84, 0xed, 0x10, 0xfb, 0xa8, 0x57, 0xb2, 0xb3, 0x06, 0x91, + 0x12, 0x85, 0x24, 0x26, 0x64, 0x2f, 0xad, 0xa0, 0x61, 0xe5, 0x2a, 0x4c, 0x20, 0x85, 0xf9, 0x0f, + 0x2b, 0x1b, 0x4a, 0xb3, 0x8e, 0x43, 0x29, 0xcd, 0x67, 0xad, 0xd6, 0x41, 0x67, 0x2b, 0x8b, 0x8a, + 0x1c, 0xef, 0xc0, 0xc5, 0xd9, 0x59, 0x98, 0x19, 0x97, 0xec, 0x54, 0xfa, 0xf3, 0x0a, 0xef, 0x22, + 0xb2, 0xc1, 0x1e, 0x85, 0x4b, 0x64, 0xbd, 0x33, 0xe6, 0x61, 0x6c, 0xa0, 0xb0, 0x80, 0x86, 0xfb, + 0x3a, 0xe4, 0xc2, 0xc9, 0x9d, 0xc3, 0x2c, 0x81, 0x56, 0xcd, 0x6e, 0x72, 0xd5, 0xa6, 0xf1, 0x0a, + 0x95, 0x97, 0x89, 0xf9, 0xd9, 0xdc, 0x31, 0x33, 0x8b, 0xa3, 0x86, 0xc6, 0x12, 0x6c, 0x9d, 0xc1, + 0x52, 0x60, 0x3b, 0xd8, 0xa6, 0xf6, 0xf5, 0x19, 0xd0, 0xb8, 0x5e, 0x02, 0x78, 0x45, 0xd2, 0x90, + 0xdb, 0x64, 0x31, 0xe7, 0x54, 0xbc, 0xa8, 0x87, 0xac, 0xca, 0xf4, 0x8d, 0x69, 0x60, 0x05, 0xf7, + 0xf8, 0x28, 0x60, 0x77, 0x6f, 0x9c, 0xf6, 0x64, 0x60, 0xc2, 0x06, 0x41, 0x05, 0xf9, 0x11, 0x5d, + 0x2b, 0x13, 0x00, 0xbc, 0xa8, 0xbb, 0xc0, 0xa8, 0xa2, 0x60, 0xb9, 0x6f, 0x70, 0x4e, 0x2f, 0xed, + 0xab, 0x88, 0xb8, 0xf9, 0x78, 0xaa, 0xc0, 0x95, 0x79, 0x83, 0x2b, 0xfa, 0x91, 0xaa, 0xb3, 0xa8, + 0x6b, 0x67, 0xcc, 0x25, 0x16, 0x6c, 0x4a, 0x98, 0x8f, 0x75, 0x51, 0xa9, 0x69, 0xb8, 0x1d, 0x25, + 0x81, 0x51, 0x9c, 0x02, 0xcc, 0xfa, 0x8f, 0x82, 0x6c, 0x61, 0x99, 0x00, 0x92, 0x0c, 0x6d, 0x7e, + 0xe9, 0x38, 0xe4, 0xee, 0x91, 0xb2, 0xd3, 0x90, 0x24, 0xc1, 0x45, 0x9f, 0xf7, 0xf1, 0x37, 0x0b, + 0x5e, 0xc0, 0xe9, 0xa0, 0x82, 0xeb, 0xee, 0xbb, 0xad, 0x4a, 0x1b, 0x75, 0x9e, 0x13, 0xda, 0x76, + 0xae, 0x73, 0x7f, 0x63, 0xa1, 0x2e, 0x26, 0xb3, 0xd7, 0x5c, 0x99, 0x24, 0xbe, 0x77, 0x84, 0x92, + 0x28, 0xc3, 0xd5, 0x98, 0x5c, 0x88, 0x1a, 0x86, 0xd4, 0x00, 0x2d, 0x57, 0xe8, 0x41, 0xcc, 0x1e, + 0x49, 0x7d, 0x50, 0xd6, 0x2f, 0x49, 0xc8, 0x74, 0x86, 0xe9, 0x13, 0x17, 0xb4, 0x8c, 0x0b, 0xdd, + 0xf0, 0x5e, 0xba, 0xeb, 0x2e, 0xac, 0x8b, 0x45, 0xf5, 0x2b, 0xb1, 0x58, 0xd9, 0xa7, 0x50, 0xf4, + 0x59, 0x01, 0xb3, 0x8e, 0x20, 0x25, 0xab, 0x6d, 0x71, 0x17, 0xe4, 0x83, 0x2a, 0xc7, 0x3b, 0x59, + 0x94, 0xbd, 0x19, 0x34, 0x94, 0x2c, 0xd7, 0xab, 0x49, 0x38, 0xdc, 0x1f, 0x64, 0x22, 0x38, 0x60, + 0x18, 0x63, 0x75, 0x74, 0xed, 0x19, 0xba, 0x7d, 0x6a, 0x2e, 0x04, 0x5b, 0x22, 0x7a, 0x97, 0x7b, + 0x70, 0x10, 0x59, 0x34, 0x8d, 0xa8, 0x37, 0x44, 0x5e, 0x1c, 0x73, 0x72, 0x96, 0xb3, 0xc4, 0xc8, + 0x14, 0x0c, 0xc6, 0x79, 0x8c, 0x9a, 0x45, 0x69, 0x52, 0x6b, 0x25, 0x52, 0xe7, 0x6a, 0x2e, 0x31, + 0x8d, 0xa3, 0x96, 0x2e, 0x69, 0x71, 0xdc, 0x68, 0x2b, 0x25, 0x96, 0xa0, 0x90, 0x74, 0x2e, 0x69, + 0x44, 0x58, 0x53, 0x8e, 0x64, 0x72, 0x12, 0x78, 0x00, 0x29, 0xa4, 0xf9, 0x35, 0x6d, 0x80, 0x60, + 0x5a, 0xad, 0xd9, 0xc2, 0x93, 0x8f, 0x8e, 0xb1, 0x6e, 0x0d, 0x3d, 0x9f, 0xb8, 0xc5, 0x35, 0xc8, + 0xcb, 0x13, 0x95, 0x03, 0x6d, 0x9d, 0xc7, 0x36, 0x8f, 0x07, 0xda, 0xc9, 0xe3, 0x10, 0x7f, 0x28, + 0x3f, 0x33, 0x9f, 0x81, 0x90, 0xf9, 0x40, 0x2f, 0x92, 0xbc, 0xe3, 0x0e, 0x6c, 0x96, 0x66, 0xe6, + 0x31, 0x0e, 0x9e, 0x34, 0x94, 0xd8, 0x32, 0xba, 0xe1, 0xb6, 0x87, 0xc4, 0x6c, 0x6b, 0x0f, 0x6e, + 0x99, 0xb3, 0xdd, 0xed, 0x71, 0x77, 0x57, 0x91, 0xaa, 0x41, 0x5c, 0x31, 0xa9, 0x9e, 0xc6, 0xc6, + 0x8f, 0x37, 0x78, 0xf9, 0x64, 0x29, 0x22, 0x5b, 0x29, 0xf7, 0x89, 0x46, 0x8b, 0x10, 0xb7, 0x6a, + 0x79, 0x9e, 0xd3, 0x88, 0xf8, 0x05, 0x9c, 0x0e, 0x87, 0xab, 0xd9, 0x68, 0xcf, 0x66, 0x74, 0xd5, + 0x67, 0x2b, 0xa0, 0xb4, 0x6c, 0xae, 0x1c, 0x5a, 0xb0, 0xf7, 0x25, 0x36, 0x10, 0x53, 0x5b, 0x2c, + 0x59, 0xaa, 0xa3, 0x61, 0xe3, 0x5a, 0x29, 0x3f, 0x84, 0xef, 0x3c, 0x32, 0x77, 0xda, 0x20, 0x15, + 0x5e, 0x81, 0x2b, 0x9e, 0xe3, 0x78, 0x7c, 0xb7, 0xdc, 0x13, 0x56, 0xa0, 0x30, 0xd2, 0x29, 0x4a, + 0xcf, 0xf8, 0xe3, 0x09, 0xa4, 0xbf, 0x87, 0x74, 0x60, 0x26, 0x1c, 0xe5, 0xb6, 0x26, 0x16, 0xf2, + 0x5e, 0x94, 0x66, 0x6e, 0xb5, 0x92, 0x78, 0x8d, 0xa0, 0x70, 0x27, 0x99, 0x15, 0xc7, 0xfd, 0x0f, + 0x8a, 0x48, 0x8d, 0x9b, 0x9e, 0x46, 0x4b, 0x89, 0xc3, 0xda, 0x74, 0x8a, 0xcb, 0xf3, 0x11, 0xc2, + 0xb3, 0x34, 0xc4, 0xef, 0x8d, 0xd0, 0xfa, 0x5b, 0xa9, 0xb4, 0x82, 0x7d, 0x4c, 0xa2, 0x4d, 0xdf, + 0x42, 0xed, 0x09, 0x43, 0x77, 0x3d, 0x92, 0x28, 0xf7, 0xd4, 0xc3, 0x07, 0x99, 0xd6, 0x3c, 0x31, + 0xa1, 0x78, 0x1f, 0x5f, 0xc7, 0x77, 0x2c, 0xfd, 0x07, 0x33, 0x05, 0x65, 0x9a, 0x12, 0xa1, 0x79, + 0x8e, 0x25, 0x2b, 0x0b, 0xb9, 0xb2, 0xfd, 0xa3, 0xac, 0xbb, 0x78, 0xa2, 0x72, 0x59, 0x8e, 0x25, + 0x0a, 0xdb, 0x51, 0xe6, 0x36, 0x1b, 0x7b, 0x27, 0x13, 0x9b, 0x77, 0xdf, 0xef, 0x9c, 0x98, 0xcb, + 0xaa, 0xbc, 0x70, 0x89, 0xb3, 0xbc, 0xcc, 0xa3, 0x4d, 0x99, 0xa4, 0x9a, 0x6a, 0xb5, 0x46, 0x51, + 0x4f, 0x25, 0x51, 0xbe, 0x2b, 0xd1, 0x18, 0xe8, 0xd3, 0xa4, 0x91, 0xde, 0x4a, 0xdf, 0x87, 0x08, + 0xc3, 0x9b, 0x98, 0x9b, 0x5f, 0x59, 0x7f, 0xb2, 0xc0, 0x28, 0x4e, 0x0c, 0xba, 0x96, 0xec, 0x2e, + 0x9a, 0x22, 0x9b, 0x4e, 0x95, 0xe4, 0xb9, 0x00, 0xc4, 0x57, 0x27, 0xd1, 0x93, 0xbb, 0xa6, 0x81, + 0x8e, 0x78, 0x75, 0x26, 0x03, 0xb1, 0x1d, 0x8e, 0x62, 0xdf, 0x8d, 0x4d, 0xfd, 0x92, 0xf5, 0xda, + 0x24, 0x87, 0x81, 0x59, 0xc9, 0xec, 0xa5, 0xf5, 0x5e, 0x93, 0x79, 0x35, 0x2b, 0x99, 0x79, 0x54, + 0x13, 0x1f, 0xac, 0x45, 0x53, 0x9b, 0x52, 0xcd, 0x01, 0xf2, 0xfc, 0xfe, 0x14, 0x5d, 0x2f, 0xe0, + 0xb4, 0x2f, 0x16, 0x69, 0x2c, 0xe6, 0xca, 0x41, 0x5a, 0xb1, 0xeb, 0x86, 0x24, 0xf1, 0x20, 0x34, + 0x14, 0x99, 0x1c, 0xcb, 0x1f, 0x57, 0x21, 0xe8, 0xa8, 0xc7, 0xa6, 0x5d, 0x2e, 0x43, 0x1f, 0x95, + 0x17, 0xb3, 0x40, 0x52, 0xca, 0x0e, 0x0c, 0x69, 0x8a, 0xf0, 0xae, 0x67, 0xa3, 0x08, 0x4b, 0x95, + 0xaa, 0x8a, 0x81, 0xcb, 0x3e, 0x70, 0x2a, 0x6a, 0xf6, 0x62, 0x5a, 0xe4, 0xb7, 0x97, 0xf8, 0xb6, + 0x84, 0x1d, 0x85, 0xd3, 0x0a, 0x09, 0xe8, 0xb5, 0xf8, 0x6e, 0x1a, 0xf6, 0x1f, 0x8b, 0x48, 0x7c, + 0xf9, 0xea, 0x32, 0x6b, 0x61, 0x2b, 0x0a, 0x94, 0x34, 0xf9, 0x82, 0x7f, 0xdd, 0xb6, 0x96, 0x6c, + 0x4d, 0xc8, 0x93, 0xa7, 0x7d, 0xf5, 0x5a, 0xb9, 0x3b, 0xe4, 0x26, 0x47, 0x7d, 0x23, 0xe5, 0x12, + 0x5f, 0x5f, 0x60, 0x2f, 0x9a, 0xa0, 0x68, 0x1c, 0x2d, 0xc5, 0xd3, 0x32, 0xbb, 0x1a, 0xe8, 0x59, + 0x17, 0x7a, 0x2d, 0x16, 0x5b, 0xd1, 0x27, 0x20, 0x4b, 0x54, 0x3a, 0x2b, 0x9b, 0xb5, 0x00, 0x6f, + 0x87, 0xa9, 0x5b, 0x53, 0x7b, 0x6e, 0xe1, 0x60, 0x83, 0xc3, 0xad, 0x94, 0x47, 0x64, 0x19, 0x16, + 0x62, 0xd2, 0x33, 0x6f, 0x6e, 0x98, 0x14, 0x99, 0xfc, 0xc2, 0xf6, 0x4e, 0x8c, 0xc1, 0xe0, 0x8c, + 0x08, 0x5c, 0x36, 0xf9, 0x23, 0x7f, 0x69, 0x02, 0x5e, 0xde, 0x3d, 0x01, 0x67, 0xd6, 0xd0, 0x09, + 0x97, 0x9b, 0x8d, 0x5c, 0xd7, 0x48, 0x01, 0xb7, 0xd2, 0x30, 0xa6, 0x16, 0x77, 0x41, 0x33, 0x86, + 0x5e, 0x18, 0x2b, 0x76, 0xb4, 0x79, 0x7d, 0x0e, 0x2b, 0xe5, 0xe6, 0xfc, 0xd6, 0x11, 0x1a, 0x64, + 0x2c, 0xc2, 0x3d, 0x6a, 0x64, 0xed, 0x71, 0x5f, 0x68, 0x22, 0x29, 0x1a, 0x71, 0x50, 0x31, 0xb8, + 0xce, 0xaa, 0x8a, 0xee, 0xf7, 0x0f, 0x6d, 0x70, 0x7a, 0xfa, 0x85, 0x55, 0x3c, 0x59, 0xb4, 0xea, + 0x16, 0xfd, 0x95, 0x82, 0x5c, 0x36, 0x7d, 0x2a, 0x4d, 0x8c, 0xc8, 0x46, 0x6e, 0x90, 0xf8, 0x7a, + 0x30, 0xb4, 0x66, 0x5a, 0xf4, 0xc7, 0x52, 0xe2, 0x2c, 0xd6, 0xcb, 0xf5, 0xc2, 0x5d, 0xd5, 0x3c, + 0x13, 0x79, 0x7e, 0xcf, 0x15, 0xd9, 0x0b, 0x38, 0x4d, 0xe8, 0xdc, 0xd0, 0xb5, 0xc6, 0x83, 0xf3, + 0x48, 0x92, 0x89, 0x00, 0xf2, 0x04, 0xe8, 0xa8, 0xad, 0x9a, 0x08, 0x60, 0x40, 0xaf, 0xa3, 0x60, + 0xc3, 0x0f, 0x62, 0x83, 0x6c, 0x17, 0x02, 0x96, 0x15, 0x2a, 0x21, 0x8c, 0x25, 0x36, 0xa7, 0x1e, + 0x33, 0x53, 0xd4, 0xb1, 0x7e, 0xe6, 0xe0, 0xa6, 0x13, 0x96, 0xac, 0x3b, 0xf6, 0xf4, 0xcc, 0x1b, + 0x78, 0x1c, 0x39, 0x0e, 0xbb, 0x60, 0x9d, 0xd9, 0x39, 0xc8, 0xdd, 0xf3, 0x29, 0xf6, 0x7d, 0x2b, + 0xe6, 0x1a, 0x75, 0xd1, 0x8a, 0x97, 0x0f, 0x13, 0x03, 0xfd, 0x45, 0x1b, 0x6c, 0xe0, 0xc7, 0xe5, + 0x5a, 0x81, 0x50, 0x69, 0x74, 0x7a, 0xc2, 0xdd, 0x0c, 0xef, 0x76, 0xf5, 0xa4, 0x26, 0xb9, 0xef, + 0x02, 0xc5, 0xe9, 0x3c, 0xe6, 0x87, 0xe6, 0xb6, 0xd1, 0x41, 0x5c, 0x54, 0x14, 0xab, 0x45, 0x7c, + 0x4e, 0x9e, 0xbd, 0x53, 0x34, 0x66, 0x86, 0xf0, 0xe8, 0xda, 0xae, 0x7d, 0x81, 0xb7, 0x98, 0xed, + 0x47, 0xd2, 0x6a, 0xee, 0x11, 0xd5, 0x94, 0x0c, 0x6c, 0xec, 0xa5, 0x6c, 0xeb, 0x12, 0x3f, 0xc4, + 0xc3, 0x0e, 0x4a, 0x0d, 0x95, 0x4b, 0xee, 0x5e, 0xf5, 0x96, 0x72, 0xa4, 0x59, 0x38, 0xd4, 0xa5, + 0x59, 0xd6, 0x05, 0x20, 0x6a, 0xa5, 0x58, 0x9e, 0xc4, 0x27, 0x63, 0xf1, 0x98, 0xa3, 0xb1, 0x13, + 0x62, 0x38, 0xca, 0x22, 0xf8, 0x98, 0xca, 0x5d, 0x8a, 0x75, 0xdc, 0x15, 0x2d, 0xad, 0xbb, 0x8b, + 0xc5, 0xbe, 0x5c, 0xdc, 0xa1, 0x03, 0xfd, 0xce, 0x92, 0x21, 0xc6, 0x93, 0xeb, 0x00, 0x1d, 0xc1, + 0x4e, 0x91, 0x98, 0xc3, 0x83, 0xaa, 0xc4, 0xe9, 0x00, 0x43, 0xf5, 0x31, 0x19, 0xa8, 0xdd, 0xfd, + 0xd0, 0x36, 0xb9, 0x38, 0x5e, 0x1f, 0x91, 0xb2, 0x97, 0x2c, 0xfd, 0x92, 0x09, 0x63, 0xd6, 0x33, + 0xb8, 0xa1, 0xf6, 0xe2, 0x0a, 0x4e, 0x71, 0xdb, 0xab, 0x16, 0xd1, 0x73, 0xd2, 0xc9, 0x89, 0x28, + 0x44, 0xe9, 0xfa, 0x70, 0xb9, 0x60, 0x8b, 0x0e, 0xda, 0x7d, 0x43, 0x42, 0x07, 0x66, 0xce, 0x57, + 0x60, 0x91, 0x68, 0xc3, 0x8f, 0x2f, 0x66, 0x9e, 0xf7, 0x1d, 0x9d, 0x7e, 0x01, 0xa7, 0xaf, 0x59, + 0x19, 0x49, 0xd1, 0x72, 0x1e, 0x5c, 0x3e, 0x6a, 0x63, 0x8b, 0xc0, 0xf8, 0x66, 0xde, 0x6b, 0x67, + 0x2f, 0xc3, 0x43, 0xda, 0x56, 0xc2, 0xc6, 0xec, 0xac, 0x96, 0xc0, 0xe4, 0x4a, 0x8b, 0xde, 0x0a, + 0x97, 0x3f, 0x20, 0x21, 0x4b, 0xe7, 0x33, 0xad, 0xa4, 0xd9, 0xf9, 0xc7, 0xbd, 0xa8, 0x1d, 0x2a, + 0xa4, 0x0e, 0xd0, 0xb2, 0x81, 0x20, 0xe0, 0x00, 0x25, 0xe4, 0x3a, 0x25, 0xa2, 0x8c, 0x23, 0xe2, + 0xc8, 0x0c, 0x12, 0x94, 0x6b, 0x1f, 0xe6, 0x00, 0xea, 0xd6, 0x03, 0x18, 0x14, 0x6e, 0x9b, 0x59, + 0x93, 0xda, 0x8c, 0x6c, 0xb0, 0x36, 0x6b, 0x6f, 0x6b, 0x05, 0x85, 0x0f, 0xee, 0xbf, 0x5b, 0x49, + 0x50, 0x8b, 0xbe, 0xcd, 0xc2, 0x69, 0xe2, 0xa8, 0x0e, 0xb1, 0x70, 0x83, 0xc8, 0xb6, 0xe9, 0xf1, + 0x7d, 0x7a, 0x1e, 0x42, 0x34, 0x00, 0xc0, 0x42, 0xae, 0xf9, 0x69, 0xef, 0xec, 0x16, 0x13, 0x40, + 0xa2, 0x37, 0x27, 0x4e, 0xdc, 0xe5, 0x61, 0x64, 0xb6, 0x15, 0xe3, 0x51, 0xcb, 0xef, 0x2d, 0xc7, + 0xbc, 0x3b, 0x8f, 0xc9, 0xc1, 0x03, 0x70, 0x29, 0xb9, 0x3e, 0xa7, 0x95, 0x92, 0xa3, 0x86, 0x64, + 0x0a, 0xae, 0x24, 0x66, 0xf3, 0xeb, 0x61, 0x1f, 0x70, 0x27, 0x53, 0x93, 0xcf, 0xbd, 0x63, 0xbd, + 0x49, 0x9e, 0x7d, 0x80, 0xde, 0x22, 0xcd, 0x4d, 0x99, 0xdb, 0x07, 0x69, 0x0f, 0xac, 0x7d, 0x64, + 0xea, 0x83, 0xca, 0x6d, 0xd2, 0x9a, 0x39, 0xe0, 0xa5, 0x4c, 0x3c, 0x80, 0x3a, 0x3e, 0x9a, 0x5d, + 0x09, 0x5f, 0x23, 0x39, 0x1e, 0xc5, 0xda, 0x43, 0xfb, 0xf3, 0x50, 0xcf, 0xe6, 0xec, 0x4a, 0xb9, + 0x93, 0x04, 0x9d, 0x3e, 0xd1, 0x85, 0xec, 0xd4, 0x6e, 0x93, 0x9c, 0x5c, 0xc2, 0x4d, 0xdd, 0x14, + 0x4a, 0x6c, 0xdf, 0x3e, 0x7c, 0x18, 0x1f, 0x8a, 0x54, 0x44, 0x59, 0x76, 0x12, 0x51, 0xb7, 0xb6, + 0xe3, 0x32, 0x73, 0xb7, 0x1c, 0x3f, 0xdc, 0x86, 0xb8, 0xd1, 0x05, 0x63, 0x00, 0x88, 0xcf, 0xda, + 0x9e, 0x39, 0x7c, 0x9f, 0x88, 0x8a, 0xbd, 0x38, 0xc8, 0xab, 0xac, 0xa0, 0x6a, 0xaa, 0xe1, 0xf9, + 0xd5, 0xc9, 0x00, 0xf0, 0x02, 0x4e, 0x13, 0x4b, 0x72, 0xad, 0xcc, 0x0c, 0x8a, 0x81, 0x8c, 0x52, + 0xc9, 0x5d, 0xb3, 0x12, 0xe4, 0x9b, 0xf5, 0x6c, 0xa6, 0xae, 0x9e, 0x64, 0xe4, 0x30, 0x91, 0x4c, + 0x2f, 0xa8, 0x3a, 0xc7, 0xa3, 0x48, 0x5d, 0x73, 0xb0, 0x56, 0x88, 0xbb, 0x60, 0x5f, 0x49, 0x45, + 0x15, 0x8f, 0xe4, 0xd8, 0x2e, 0x07, 0xac, 0xb8, 0xe5, 0x2b, 0xef, 0xd4, 0xae, 0x2f, 0x6a, 0x15, + 0x16, 0xd6, 0x26, 0xdf, 0x34, 0x18, 0x89, 0xcc, 0xfb, 0xa3, 0xb0, 0xc6, 0x5d, 0x8a, 0x35, 0x34, + 0x7c, 0x98, 0xc3, 0x51, 0x4d, 0xde, 0x9d, 0xa6, 0x68, 0x4a, 0xb5, 0x92, 0x6f, 0x3c, 0xbe, 0x0c, + 0x82, 0xae, 0x25, 0xff, 0x7a, 0x42, 0xfd, 0x70, 0x37, 0xe1, 0xc9, 0x5b, 0x62, 0xb1, 0x49, 0x3a, + 0xd6, 0x2a, 0x54, 0xba, 0x20, 0x04, 0x1e, 0x9c, 0x5a, 0xf1, 0xe5, 0x36, 0x94, 0x63, 0xdd, 0xb9, + 0xaa, 0xab, 0x11, 0x60, 0x34, 0x5c, 0x19, 0x56, 0x45, 0x36, 0x61, 0x00, 0x53, 0x14, 0x3c, 0x6e, + 0x3c, 0xd5, 0x34, 0x0c, 0xba, 0x91, 0xb0, 0x4c, 0x6b, 0xf5, 0x2b, 0xb5, 0xf0, 0x5e, 0x8d, 0x1c, + 0x96, 0x25, 0xc7, 0x86, 0x12, 0xe9, 0x28, 0xbf, 0x3d, 0x78, 0xe8, 0xcd, 0xf5, 0x47, 0x98, 0x60, + 0xde, 0x65, 0xf7, 0xa5, 0x82, 0x76, 0x71, 0x9d, 0x99, 0xdf, 0x77, 0xe9, 0x51, 0x86, 0x72, 0x01, + 0x8b, 0xe6, 0x86, 0x4a, 0xc3, 0x06, 0x5b, 0x03, 0x3a, 0xae, 0xb7, 0x07, 0xcb, 0xea, 0x71, 0xcb, + 0xe0, 0x96, 0x1a, 0x32, 0x4f, 0xe2, 0x16, 0x80, 0x48, 0x39, 0xdc, 0x71, 0xef, 0xc6, 0x9d, 0xe5, + 0x78, 0xc2, 0xab, 0xe1, 0xcf, 0x60, 0x39, 0x78, 0xcd, 0xd0, 0xdd, 0x57, 0x92, 0x64, 0x8b, 0x89, + 0xc9, 0x44, 0x4e, 0x16, 0xa4, 0xd1, 0x2d, 0x94, 0xbc, 0xcb, 0x82, 0x5a, 0x25, 0x06, 0x80, 0xb1, + 0x19, 0x44, 0x45, 0xed, 0x6e, 0x97, 0x3a, 0xcd, 0xae, 0xa9, 0x67, 0x74, 0x9d, 0xb0, 0x6c, 0xdc, + 0xde, 0xda, 0x8d, 0x6d, 0x99, 0xf4, 0x92, 0x84, 0x0a, 0x2c, 0x21, 0x25, 0x15, 0xc3, 0xd2, 0xe3, + 0x4b, 0x24, 0x9f, 0xdf, 0x09, 0xc4, 0x6c, 0x7d, 0x01, 0xa7, 0x29, 0x64, 0xce, 0x9d, 0x84, 0xec, + 0xd8, 0xb9, 0xb0, 0x07, 0x06, 0x87, 0x4b, 0x8d, 0xcd, 0xc8, 0x5d, 0x93, 0x49, 0x99, 0x5f, 0x4a, + 0x2b, 0xac, 0x1b, 0x6a, 0x9d, 0xd0, 0x85, 0xb8, 0x56, 0x8f, 0x02, 0xb6, 0x38, 0x34, 0x7c, 0x8c, + 0xef, 0xdb, 0x09, 0x78, 0xc1, 0xbb, 0xe5, 0x0d, 0xf5, 0x6d, 0x4c, 0x54, 0x63, 0x6c, 0x92, 0xb6, + 0xb5, 0xd3, 0x5f, 0x16, 0x62, 0xdc, 0xca, 0x01, 0xd3, 0x1a, 0x13, 0xc1, 0xc2, 0x02, 0xcf, 0x9d, + 0x14, 0xb5, 0xe3, 0x30, 0x50, 0xad, 0x5a, 0xdc, 0xce, 0x65, 0xf3, 0x2d, 0x34, 0xcc, 0x8b, 0x0e, + 0x4d, 0x9f, 0xca, 0x3d, 0x5c, 0xf2, 0xa9, 0xf6, 0xe6, 0xe5, 0x05, 0xb4, 0x3d, 0xc4, 0xdb, 0x34, + 0x40, 0x26, 0xbd, 0x85, 0x46, 0xf4, 0x3c, 0x5a, 0x0d, 0x40, 0x28, 0x83, 0x36, 0x7e, 0x31, 0x44, + 0x61, 0xcc, 0x9b, 0x01, 0x00, 0x55, 0x8c, 0x54, 0xf7, 0x0d, 0xe6, 0x31, 0x98, 0x48, 0x6d, 0x2c, + 0x57, 0x38, 0x4c, 0x00, 0x84, 0x27, 0xe6, 0xb4, 0x46, 0xc4, 0xa9, 0x9a, 0x5f, 0x58, 0x07, 0x19, + 0x99, 0x8c, 0x99, 0xca, 0xc0, 0xcc, 0x62, 0x26, 0x73, 0xd9, 0xac, 0x74, 0x70, 0x6b, 0x32, 0x06, + 0x95, 0xca, 0xdc, 0x3b, 0x86, 0xfd, 0x7a, 0xcf, 0xb4, 0x82, 0x31, 0x5f, 0xe9, 0xe2, 0xd0, 0xb4, + 0xaa, 0xe9, 0xdb, 0xb0, 0xe1, 0x56, 0x55, 0x20, 0xa9, 0x5c, 0x67, 0x90, 0x20, 0xbd, 0x82, 0xb0, + 0xc9, 0xb4, 0xf3, 0x39, 0x52, 0x87, 0x56, 0x76, 0x1c, 0x2d, 0x34, 0x1e, 0x62, 0x42, 0x7a, 0x69, + 0xcf, 0xd2, 0x09, 0xd0, 0x75, 0xaa, 0xc8, 0xe4, 0x3e, 0x22, 0x1b, 0xa4, 0x2d, 0x65, 0x2a, 0x43, + 0x73, 0xf3, 0x5a, 0x25, 0x39, 0xcc, 0x61, 0xae, 0x63, 0xb3, 0x3c, 0xb3, 0x80, 0x7c, 0xb0, 0x53, + 0x1f, 0xa1, 0x32, 0xb8, 0x3a, 0x34, 0x75, 0xa0, 0xed, 0xee, 0xf1, 0xae, 0xf9, 0x86, 0x2b, 0x9d, + 0xa7, 0x1a, 0xa8, 0x98, 0x49, 0x1b, 0xdd, 0x5b, 0x1e, 0x04, 0x12, 0xf3, 0x71, 0x01, 0xe0, 0x6e, + 0x8f, 0xaf, 0x0b, 0x5d, 0x5a, 0xae, 0x9c, 0xcd, 0x07, 0x9e, 0xdf, 0x73, 0x05, 0x7e, 0x01, 0xa7, + 0x7b, 0xe4, 0x9a, 0x22, 0xb7, 0xcc, 0xc1, 0x44, 0x9c, 0x01, 0x3b, 0x9c, 0xd6, 0xf8, 0x91, 0x22, + 0xaf, 0x56, 0xf0, 0x96, 0x8c, 0xf5, 0x6a, 0xe3, 0xae, 0x88, 0x5e, 0xe5, 0x6d, 0x29, 0xf2, 0xc7, + 0x7e, 0x55, 0xc5, 0x56, 0x1f, 0xb2, 0x41, 0xb0, 0x2a, 0xae, 0x36, 0x2d, 0x6d, 0x86, 0xfd, 0x2a, + 0xa1, 0xdf, 0xae, 0x74, 0x3c, 0xf0, 0x59, 0x35, 0xfc, 0xc4, 0x58, 0x8c, 0x9b, 0xe9, 0xea, 0x11, + 0xf0, 0x25, 0x56, 0x78, 0xd0, 0xc5, 0x4c, 0x10, 0x78, 0xa0, 0xee, 0x61, 0xc8, 0x4e, 0xa5, 0xe7, + 0x28, 0x4a, 0xa3, 0x79, 0x27, 0xa9, 0x64, 0x8c, 0xc9, 0xba, 0x48, 0x0b, 0xb5, 0xe1, 0x4c, 0xbf, + 0x10, 0xc3, 0xc6, 0x44, 0x29, 0xa0, 0x33, 0x29, 0x5b, 0x35, 0x69, 0x5c, 0x45, 0x25, 0xb7, 0xf5, + 0xb6, 0x4c, 0x9f, 0x65, 0x61, 0xe4, 0x8f, 0x40, 0xcb, 0x32, 0xac, 0x82, 0x72, 0xe4, 0xd8, 0x87, + 0xda, 0xe4, 0x90, 0xdc, 0xef, 0x5e, 0x46, 0x30, 0x99, 0xa1, 0xbb, 0xb3, 0x30, 0x55, 0x84, 0xa2, + 0xa7, 0x1d, 0x3a, 0x5c, 0x47, 0x02, 0xc6, 0x62, 0x5f, 0xd7, 0x5d, 0xde, 0x49, 0x14, 0xb5, 0x73, + 0x47, 0x88, 0xd4, 0x00, 0xbc, 0xe4, 0xbb, 0xb6, 0x95, 0x11, 0x86, 0x48, 0x68, 0x7d, 0x29, 0xa6, + 0x70, 0x15, 0x0b, 0xc7, 0x1a, 0xa3, 0xd9, 0xaa, 0x54, 0x2a, 0xc7, 0x93, 0xad, 0x39, 0xd5, 0x8a, + 0xa1, 0x8d, 0xc2, 0xd5, 0xd9, 0xf2, 0xf6, 0x22, 0x0c, 0x09, 0x8e, 0x5d, 0xb2, 0x99, 0x34, 0x51, + 0x01, 0x16, 0xbb, 0x69, 0x5b, 0xb0, 0x2d, 0xef, 0x0a, 0x18, 0xdd, 0x04, 0xa2, 0x7c, 0xa5, 0x31, + 0xc6, 0x48, 0xb9, 0x0b, 0x80, 0x0c, 0x30, 0x42, 0xbd, 0xeb, 0xb8, 0x1a, 0xdc, 0xf5, 0x54, 0xe1, + 0x6b, 0xf5, 0x89, 0xf1, 0x59, 0x9b, 0xcb, 0x65, 0xd0, 0xbf, 0xbb, 0x1c, 0x27, 0xd9, 0xe1, 0x56, + 0x91, 0xcb, 0xb2, 0x00, 0x96, 0xb7, 0x1e, 0x1c, 0x96, 0x38, 0xb3, 0x46, 0x68, 0x7d, 0x4b, 0x3e, + 0xbf, 0xe6, 0xa9, 0xab, 0xcd, 0xf7, 0x37, 0x18, 0x6e, 0xa4, 0xdc, 0x1f, 0xc6, 0xb7, 0xcc, 0xcf, + 0xef, 0x23, 0xb4, 0xfe, 0x02, 0x4e, 0xdf, 0xf6, 0xd7, 0x60, 0x45, 0x5d, 0x13, 0x45, 0x7c, 0xca, + 0x38, 0x37, 0x99, 0x2b, 0xb3, 0x30, 0xe7, 0x58, 0xfe, 0xc4, 0x0e, 0xe6, 0x73, 0x09, 0x1a, 0x5f, + 0x34, 0xe0, 0xdd, 0x33, 0x8f, 0xf9, 0xcb, 0xf6, 0x61, 0x2d, 0x6a, 0xd5, 0x99, 0xcc, 0x5e, 0xbb, + 0x2a, 0xd9, 0x1e, 0xea, 0xfd, 0xa8, 0xe2, 0xab, 0x6b, 0x10, 0xf1, 0x88, 0x94, 0xb8, 0xc5, 0xf6, + 0xf4, 0x6c, 0xd0, 0x0e, 0xa6, 0xa3, 0xa4, 0xb9, 0x87, 0x7a, 0x3e, 0xca, 0xb9, 0x13, 0xbd, 0xcd, + 0x56, 0x39, 0x15, 0x31, 0x94, 0xae, 0x55, 0x54, 0xf7, 0x19, 0x35, 0x4e, 0x30, 0x38, 0xc9, 0x5b, + 0xd8, 0x95, 0xec, 0x6f, 0xad, 0xc4, 0xa3, 0xc3, 0xb3, 0xf3, 0x21, 0xca, 0x52, 0xa2, 0xe7, 0xfa, + 0xe0, 0xec, 0xec, 0x7d, 0x52, 0x5e, 0xa5, 0x1d, 0x8d, 0xd9, 0xa5, 0x9c, 0xdd, 0x20, 0x04, 0xa6, + 0xcc, 0xe4, 0xde, 0x88, 0x5b, 0xa6, 0x74, 0x8a, 0xa2, 0x3b, 0xa9, 0xcd, 0x2d, 0x77, 0x4f, 0x1b, + 0x97, 0x6a, 0xf8, 0x81, 0x6d, 0x53, 0xc9, 0xc8, 0xc0, 0x54, 0x99, 0xbb, 0x8b, 0xe9, 0x0e, 0xe9, + 0xdc, 0x82, 0x7e, 0xa5, 0xbb, 0xe8, 0x23, 0xda, 0x1f, 0x78, 0x83, 0x93, 0xc9, 0x87, 0x70, 0x46, + 0x82, 0x39, 0xdc, 0x44, 0x37, 0x0d, 0x68, 0x93, 0x6d, 0xec, 0x24, 0xa6, 0x05, 0xb7, 0x22, 0x32, + 0x68, 0x00, 0x08, 0xf1, 0xe5, 0xe0, 0xa0, 0xba, 0x38, 0xb3, 0x4b, 0x52, 0x6f, 0x41, 0xac, 0xc6, + 0x06, 0x98, 0x5f, 0xf7, 0xc6, 0x7d, 0x3d, 0x3e, 0x01, 0x4f, 0xac, 0xeb, 0x39, 0x4a, 0x23, 0x9c, + 0x31, 0x76, 0x0a, 0x4a, 0x4a, 0x9c, 0x0c, 0xd1, 0xbb, 0x1e, 0x00, 0x41, 0xfb, 0x78, 0x5e, 0x3b, + 0x64, 0x0d, 0x12, 0xc3, 0xd2, 0x04, 0xde, 0x58, 0x71, 0x2f, 0x6e, 0xf4, 0x3a, 0xe9, 0x0d, 0x2c, + 0x55, 0x16, 0xfa, 0x6e, 0x7b, 0xb9, 0x88, 0x9a, 0x75, 0x92, 0x14, 0xdb, 0xdf, 0xb5, 0xa6, 0x10, + 0x3b, 0x23, 0x29, 0x86, 0xfd, 0x9b, 0xe1, 0x3c, 0x0f, 0x2d, 0xa2, 0xec, 0xb9, 0xfb, 0x89, 0x58, + 0x7c, 0xe9, 0x51, 0xc6, 0x7b, 0xf7, 0xf9, 0xbd, 0x0d, 0x98, 0x5d, 0xa1, 0x17, 0x70, 0x9a, 0xb5, + 0xb1, 0x6a, 0xea, 0x1f, 0x1a, 0x8a, 0xa8, 0x97, 0xbd, 0x36, 0x51, 0x75, 0x37, 0x69, 0x25, 0xc7, + 0xf7, 0x3c, 0x21, 0xd1, 0xe2, 0x82, 0xd9, 0xf1, 0x91, 0x19, 0x66, 0x46, 0x6a, 0x3a, 0x29, 0x45, + 0x6e, 0xc8, 0xaa, 0x6c, 0x65, 0x4d, 0x04, 0xf3, 0xc7, 0xaa, 0x59, 0xd5, 0xa6, 0xd4, 0x6d, 0x40, + 0x11, 0xef, 0x01, 0x23, 0x03, 0x52, 0xc8, 0x53, 0x70, 0x85, 0x94, 0x58, 0x8a, 0xde, 0x82, 0xc5, + 0x5c, 0x42, 0x8f, 0x77, 0xdb, 0x52, 0xa4, 0x38, 0x34, 0x16, 0xf4, 0xe8, 0x44, 0x8e, 0x5d, 0x97, + 0x70, 0xa6, 0xd6, 0xca, 0xec, 0x98, 0x54, 0x27, 0x40, 0x37, 0x49, 0x23, 0xf7, 0x47, 0xa4, 0x22, + 0xd7, 0xae, 0x85, 0x68, 0x9b, 0x23, 0xf4, 0xb0, 0x4c, 0xde, 0x32, 0x31, 0xbe, 0xf0, 0x30, 0x37, + 0x40, 0xe2, 0x18, 0xca, 0xfd, 0x0c, 0x0c, 0x2e, 0xb3, 0x62, 0x22, 0x03, 0x84, 0x4a, 0xd4, 0x66, + 0x43, 0x56, 0x10, 0xa7, 0xad, 0x96, 0x05, 0x36, 0x54, 0x44, 0x50, 0x73, 0x7c, 0x02, 0xc2, 0x96, + 0xd8, 0xb6, 0xeb, 0x09, 0x39, 0x7c, 0x30, 0xf1, 0x54, 0x19, 0x39, 0x0a, 0x08, 0x15, 0xa8, 0xa0, + 0x47, 0x90, 0x2f, 0xfb, 0xe3, 0xa2, 0x83, 0xc9, 0xce, 0x5d, 0x62, 0x6a, 0x65, 0xa5, 0x94, 0x32, + 0xcd, 0x42, 0xb0, 0x37, 0xc2, 0x41, 0x3d, 0x75, 0x51, 0x12, 0x06, 0x0e, 0x8c, 0xe9, 0xa2, 0xbb, + 0xdd, 0xc9, 0xce, 0xe3, 0x8e, 0x59, 0xf3, 0x7c, 0x49, 0xe2, 0x80, 0x8b, 0xa0, 0x77, 0xc1, 0x6e, + 0x80, 0xe2, 0xfb, 0x6a, 0xf1, 0xa6, 0x54, 0x35, 0x99, 0x19, 0x3c, 0xd0, 0x4e, 0x14, 0x8f, 0x15, + 0x91, 0x74, 0x71, 0x34, 0x17, 0xdf, 0x73, 0x7b, 0x62, 0x1b, 0x86, 0x5d, 0xfb, 0xc6, 0xe2, 0xca, + 0x5a, 0x96, 0xe8, 0x4c, 0x77, 0x25, 0xb6, 0xd4, 0xf9, 0x4a, 0x3a, 0xba, 0x6f, 0x42, 0xaf, 0xb1, + 0x15, 0xa6, 0xdd, 0x3a, 0x45, 0x32, 0x61, 0xef, 0xc9, 0xaf, 0xa1, 0x9d, 0x90, 0x32, 0x92, 0x9d, + 0xf6, 0x4b, 0x67, 0xd2, 0xec, 0xe2, 0x89, 0xb2, 0x88, 0xd6, 0x15, 0x86, 0xda, 0x73, 0xda, 0x38, + 0x23, 0xe3, 0x79, 0x01, 0xa7, 0x79, 0x28, 0x2c, 0xe5, 0x7a, 0xc2, 0x08, 0x20, 0xa6, 0xe0, 0x21, + 0x74, 0xf1, 0x28, 0x34, 0xcb, 0xa8, 0xa3, 0x76, 0x6d, 0xc5, 0xe3, 0x9b, 0x0e, 0x88, 0x0a, 0x4c, + 0x25, 0x2f, 0x2d, 0xcc, 0xca, 0x82, 0xb8, 0xae, 0xd0, 0xbb, 0x35, 0xbb, 0x13, 0x60, 0xfa, 0xd9, + 0x49, 0x7f, 0x50, 0x59, 0x88, 0xe7, 0x2b, 0xb3, 0x7c, 0x43, 0x56, 0xe3, 0xca, 0x7a, 0xfa, 0xed, + 0x9b, 0xcb, 0x99, 0x58, 0x97, 0xa6, 0xb8, 0x96, 0x0f, 0x07, 0xf7, 0x6b, 0x90, 0x5f, 0x9e, 0x2a, + 0x96, 0x55, 0x72, 0x66, 0x34, 0x34, 0x49, 0xd7, 0x66, 0x58, 0x71, 0x3a, 0x56, 0x68, 0x0d, 0x6e, + 0x28, 0xa2, 0x49, 0xa8, 0xf0, 0x30, 0x8b, 0xec, 0xf3, 0xf9, 0x63, 0x44, 0x8e, 0x0e, 0x5e, 0x29, + 0x92, 0x78, 0x8a, 0x7c, 0xd0, 0x5a, 0x5e, 0xf1, 0xb5, 0xc3, 0x1a, 0x9a, 0x94, 0x3c, 0x0d, 0x89, + 0x8a, 0x40, 0x62, 0x0a, 0x6e, 0x2f, 0x0e, 0xc1, 0x5e, 0xc8, 0x22, 0xd8, 0xd6, 0x15, 0xfb, 0x6b, + 0x25, 0xa6, 0x15, 0xe5, 0xca, 0x0d, 0x63, 0x12, 0xc6, 0x5d, 0x53, 0x09, 0xab, 0x15, 0x0f, 0x7d, + 0xac, 0x2e, 0x83, 0x25, 0xd7, 0xb7, 0x4e, 0x8d, 0xbb, 0xd1, 0xcd, 0x29, 0x93, 0xf5, 0x54, 0x4f, + 0xda, 0x89, 0x0a, 0xba, 0xb7, 0xa6, 0x56, 0x63, 0x54, 0x95, 0xa9, 0xc3, 0x42, 0xdd, 0xc1, 0x8b, + 0x0c, 0xbf, 0x5f, 0x67, 0xf5, 0x01, 0x18, 0x47, 0x34, 0x60, 0x67, 0x4f, 0xea, 0x58, 0x38, 0x39, + 0xd9, 0xb6, 0x41, 0x0d, 0x3e, 0x8a, 0x6f, 0x62, 0x18, 0x68, 0xa8, 0x71, 0xa2, 0xd0, 0x62, 0xf6, + 0xba, 0x2a, 0xfb, 0x10, 0x0a, 0xc6, 0x67, 0xf0, 0xe5, 0x2d, 0x44, 0xbf, 0xb7, 0xcb, 0x71, 0xd1, + 0x6c, 0x05, 0x1a, 0x30, 0x7f, 0x14, 0x53, 0x72, 0xc1, 0xa3, 0xac, 0x8b, 0xa7, 0x1b, 0xb6, 0xa8, + 0x9c, 0x53, 0x49, 0x10, 0x04, 0x57, 0x56, 0x2c, 0xb8, 0x2d, 0x1f, 0xb3, 0x92, 0x17, 0x53, 0x8d, + 0x38, 0x6f, 0xc1, 0x8c, 0x60, 0xfb, 0x13, 0xb3, 0xcb, 0xd6, 0x4d, 0x99, 0xa5, 0x18, 0x2a, 0xf2, + 0xf6, 0x2b, 0xaf, 0x6e, 0x77, 0x1b, 0xba, 0x99, 0xf0, 0xc9, 0x65, 0xd8, 0x65, 0x6d, 0x50, 0x46, + 0x76, 0x77, 0xc3, 0x2a, 0xa7, 0xb0, 0x60, 0xdd, 0xe0, 0x1a, 0x33, 0xe2, 0x9a, 0xdd, 0x85, 0x83, + 0x89, 0xda, 0x2d, 0x8b, 0xed, 0xa3, 0xda, 0x76, 0xa1, 0xc3, 0x59, 0xbe, 0x6f, 0x17, 0x1d, 0xac, + 0x58, 0x20, 0x21, 0x2f, 0xf9, 0xfe, 0xfa, 0x20, 0x0d, 0xce, 0x43, 0x54, 0x4e, 0xca, 0xec, 0x11, + 0x16, 0xe8, 0x96, 0xeb, 0x5e, 0xe3, 0xbe, 0x17, 0xa7, 0x19, 0x18, 0x0f, 0xc3, 0x7d, 0xc2, 0x85, + 0x42, 0xca, 0xbb, 0xc5, 0x17, 0x73, 0xd8, 0x1c, 0x4b, 0xb4, 0x16, 0x9d, 0xd8, 0x59, 0xf1, 0x5d, + 0xd3, 0x4c, 0x68, 0xc7, 0xf0, 0x6a, 0x14, 0xe6, 0x8b, 0x52, 0xd0, 0x02, 0xba, 0x55, 0x88, 0x4e, + 0xb3, 0x86, 0x38, 0xfb, 0x47, 0x3e, 0xa8, 0x06, 0x89, 0x53, 0xb0, 0x84, 0xcb, 0xed, 0xa6, 0xca, + 0xc4, 0x86, 0x11, 0x7c, 0xc5, 0x58, 0x67, 0xc5, 0x03, 0x4c, 0x75, 0xa8, 0x41, 0x66, 0x67, 0x86, + 0x26, 0x51, 0x75, 0x6a, 0x77, 0xc3, 0xe0, 0xb6, 0x94, 0x7b, 0x0e, 0x60, 0x8e, 0x40, 0x96, 0xa6, + 0x3e, 0x88, 0xbb, 0x53, 0x77, 0x20, 0x82, 0x6a, 0x52, 0x6a, 0x2e, 0x9c, 0xf6, 0xec, 0x23, 0xfd, + 0x84, 0x05, 0x7d, 0xd1, 0x0d, 0x31, 0xc4, 0x66, 0x89, 0x20, 0xe4, 0x38, 0xea, 0x67, 0x32, 0xf0, + 0x6a, 0xf8, 0xfa, 0x4e, 0xd1, 0x30, 0xc0, 0x46, 0x87, 0xf3, 0xf8, 0xc9, 0x87, 0x0e, 0x10, 0x47, + 0x2a, 0x6b, 0x81, 0x81, 0x98, 0x5d, 0x14, 0xdf, 0xf5, 0x72, 0xb3, 0xa2, 0x60, 0xc4, 0xb9, 0x7f, + 0x9c, 0x91, 0x7b, 0x65, 0xdd, 0x04, 0x57, 0xc4, 0x51, 0xa9, 0xf4, 0x54, 0x10, 0xe6, 0x68, 0x01, + 0x80, 0xee, 0x76, 0xca, 0xc7, 0x1f, 0x5a, 0x95, 0xf8, 0x9c, 0x03, 0x62, 0xf6, 0x4c, 0x46, 0xee, + 0x8a, 0xdc, 0x1a, 0x63, 0xb1, 0x5b, 0x1c, 0x99, 0x32, 0x58, 0xd6, 0xb7, 0xa4, 0xf9, 0x04, 0x05, + 0xe3, 0xca, 0xae, 0x79, 0xf7, 0x8e, 0x93, 0xfd, 0x79, 0x5e, 0x7e, 0x2d, 0x00, 0xd9, 0x8d, 0x50, + 0x1f, 0x73, 0x65, 0x2f, 0x33, 0x6d, 0x77, 0xd1, 0x8b, 0x7c, 0xca, 0x60, 0xf6, 0x13, 0xf6, 0x5c, + 0xe9, 0x7c, 0x41, 0x6b, 0x19, 0x0d, 0xaa, 0x1a, 0xf6, 0x56, 0x36, 0xcd, 0xb4, 0x66, 0x21, 0xab, + 0x57, 0xa2, 0xfe, 0x10, 0xad, 0x2c, 0x4f, 0x29, 0xc7, 0x41, 0x33, 0x50, 0x9e, 0xc3, 0xb0, 0xce, + 0x9b, 0x64, 0xb6, 0xc5, 0x1a, 0x9c, 0x5f, 0x3e, 0x22, 0xb0, 0xa8, 0x0b, 0x51, 0x72, 0x70, 0x47, + 0xdb, 0xd5, 0x66, 0x55, 0xbb, 0x41, 0x73, 0xa8, 0xb4, 0x62, 0xa1, 0x78, 0xa8, 0x66, 0x03, 0x81, + 0x85, 0x16, 0x92, 0x04, 0x6a, 0x41, 0xab, 0x27, 0x16, 0x11, 0x59, 0xcf, 0x06, 0xb2, 0xf1, 0xf0, + 0x10, 0xb5, 0x95, 0xe8, 0x5e, 0x24, 0xe8, 0xb4, 0xb3, 0xad, 0x5b, 0x45, 0x57, 0x8d, 0x92, 0x57, + 0x19, 0x6b, 0x25, 0x76, 0x71, 0xfe, 0x10, 0x0c, 0x2a, 0x97, 0xf4, 0x51, 0x19, 0x2c, 0x6c, 0x20, + 0x43, 0xb4, 0xed, 0xec, 0xf5, 0x8e, 0x38, 0xec, 0x71, 0x93, 0xa9, 0x29, 0xb7, 0x35, 0x4f, 0x7d, + 0x68, 0x97, 0x94, 0x95, 0xb5, 0x56, 0xeb, 0x35, 0xe5, 0x42, 0xc6, 0x47, 0xde, 0x72, 0xc4, 0xb8, + 0xf6, 0x38, 0x67, 0xe5, 0x38, 0x6e, 0x44, 0xef, 0xaa, 0x42, 0x21, 0x6c, 0x19, 0x95, 0xd2, 0x0e, + 0x04, 0xbd, 0xe1, 0xbb, 0x7c, 0x66, 0x6a, 0xdf, 0x8b, 0x69, 0x6f, 0x4d, 0xab, 0xf1, 0x4c, 0x8f, + 0x95, 0xb4, 0xb4, 0x62, 0x66, 0x6b, 0x94, 0x27, 0xa8, 0x94, 0xeb, 0xd2, 0xe5, 0x83, 0xce, 0xd1, + 0x23, 0x39, 0x93, 0x53, 0x7a, 0x58, 0x65, 0xa9, 0x8c, 0xd9, 0x56, 0x06, 0x69, 0xbe, 0x72, 0xed, + 0xc8, 0x74, 0xaa, 0xa5, 0x57, 0xf9, 0xb6, 0x68, 0x60, 0x93, 0x97, 0x61, 0x1d, 0xab, 0x4c, 0x06, + 0xf5, 0x34, 0x1e, 0x79, 0x54, 0xcc, 0x86, 0x71, 0x58, 0x2c, 0x8a, 0x3b, 0x66, 0x3d, 0x9d, 0x1d, + 0x87, 0x79, 0x0b, 0xb8, 0x35, 0x95, 0xd4, 0x91, 0x82, 0x4a, 0xfe, 0x48, 0x56, 0x69, 0x87, 0x2c, + 0xbd, 0x13, 0x36, 0x77, 0x57, 0x7b, 0x3c, 0x85, 0xe8, 0x07, 0xd8, 0x36, 0xb5, 0x61, 0x34, 0xa4, + 0x16, 0xf7, 0x13, 0x8a, 0x33, 0xfb, 0x09, 0x20, 0xce, 0xd0, 0x42, 0xfd, 0xc4, 0xf0, 0xa9, 0x7a, + 0xc5, 0x9b, 0x88, 0x3c, 0xbf, 0x9e, 0xae, 0x95, 0xf8, 0x02, 0x4e, 0x0b, 0xd5, 0x1f, 0x3e, 0x34, + 0x0f, 0xd2, 0xa8, 0x66, 0x76, 0x52, 0xa0, 0xba, 0x73, 0xa4, 0xa4, 0x29, 0x99, 0x02, 0xbf, 0x53, + 0x56, 0x1b, 0x01, 0x00, 0x97, 0xcd, 0x37, 0xd0, 0x77, 0x68, 0x3c, 0xb6, 0xca, 0x35, 0x26, 0x17, + 0x06, 0x50, 0xc1, 0xa8, 0x9b, 0xa9, 0x71, 0x4a, 0x62, 0xb9, 0x52, 0x16, 0xe1, 0x22, 0xf2, 0x79, + 0xad, 0x80, 0x3b, 0x97, 0xcc, 0xa8, 0xd6, 0xd9, 0x62, 0xf3, 0xb2, 0x53, 0x2d, 0xf6, 0x8d, 0xf5, + 0x6c, 0xca, 0xc4, 0xec, 0x92, 0x46, 0x6d, 0xc9, 0xb2, 0x24, 0x58, 0xdf, 0x98, 0xec, 0xc3, 0xa2, + 0x96, 0x44, 0x2d, 0x9a, 0xc4, 0x42, 0x98, 0x63, 0x7c, 0x60, 0x21, 0x8d, 0x57, 0x8b, 0x03, 0x83, + 0x09, 0xbb, 0x64, 0x3d, 0xe5, 0x5a, 0x3b, 0xb1, 0x70, 0xb8, 0xc7, 0x65, 0x51, 0x7c, 0x13, 0x87, + 0x5a, 0xbd, 0xf0, 0x18, 0x96, 0x03, 0x18, 0x49, 0x26, 0x77, 0x63, 0x2a, 0xb5, 0x8a, 0x8a, 0x22, + 0xe3, 0x89, 0x36, 0x0e, 0x0e, 0x75, 0x05, 0xfa, 0x53, 0xe5, 0x2c, 0xee, 0x4f, 0xb9, 0x99, 0x39, + 0x4c, 0x61, 0xf3, 0xdb, 0x8e, 0x03, 0x4e, 0x63, 0x80, 0x37, 0x24, 0xe2, 0xa0, 0x20, 0x9b, 0x3f, + 0x1d, 0xeb, 0x8c, 0x8c, 0x83, 0xa1, 0x62, 0xdc, 0xad, 0xab, 0x75, 0xd2, 0xb5, 0x3d, 0x9b, 0xa4, + 0xfd, 0x35, 0x83, 0x70, 0x43, 0x8e, 0x8a, 0x8f, 0x6d, 0xc1, 0x94, 0xb5, 0x87, 0xa8, 0x11, 0xbf, + 0x93, 0xa7, 0x4a, 0xd0, 0x77, 0x6d, 0x35, 0xde, 0x78, 0xc6, 0x1a, 0x01, 0xc6, 0xd8, 0x78, 0x75, + 0x7f, 0xcc, 0xcc, 0xa5, 0x90, 0xbc, 0x71, 0x73, 0xce, 0x31, 0x8b, 0xf4, 0x0b, 0xa9, 0x09, 0x06, + 0xaa, 0x62, 0xcf, 0x16, 0x37, 0x65, 0x42, 0x7d, 0x21, 0x19, 0xc5, 0x57, 0x2c, 0xcb, 0x6c, 0x4c, + 0xdc, 0x66, 0x6b, 0xdc, 0xe5, 0x9b, 0xb3, 0x89, 0x0f, 0x11, 0x06, 0x68, 0x83, 0x75, 0x5e, 0x4b, + 0x67, 0xc8, 0x19, 0x60, 0x68, 0xe8, 0x3b, 0xd0, 0xb5, 0x44, 0xde, 0x11, 0x75, 0x05, 0x77, 0xf2, + 0xb1, 0x24, 0x99, 0x4a, 0x7d, 0x94, 0x2c, 0x25, 0x7d, 0xcf, 0xdb, 0x63, 0xbb, 0x28, 0x2f, 0xe0, + 0xb4, 0xd4, 0x57, 0xd2, 0xe5, 0x7a, 0x28, 0x80, 0x98, 0x79, 0x5c, 0x36, 0x19, 0xb8, 0x58, 0xd4, + 0x81, 0x65, 0x8a, 0x35, 0x50, 0xbb, 0xe6, 0x0d, 0x3b, 0xa8, 0xd1, 0xc2, 0xba, 0xcd, 0x71, 0xb2, + 0xce, 0xa4, 0x8e, 0xf4, 0xaf, 0xa7, 0xb6, 0xb5, 0xda, 0x56, 0xae, 0x11, 0x58, 0xab, 0x33, 0xfc, + 0x89, 0x24, 0x99, 0x40, 0xc5, 0x32, 0x31, 0x9e, 0x02, 0xb0, 0x82, 0x31, 0xd9, 0x96, 0x31, 0xdc, + 0xa9, 0x18, 0xc5, 0x62, 0x94, 0xc1, 0x83, 0x15, 0x7b, 0x6f, 0xe8, 0x01, 0x56, 0xb8, 0x1d, 0x71, + 0xc6, 0x58, 0xbc, 0xc1, 0x3d, 0x33, 0xd1, 0x31, 0x01, 0xe8, 0xbc, 0x11, 0x9a, 0x9b, 0xd9, 0x1f, + 0x22, 0xef, 0x42, 0xd6, 0x7d, 0x83, 0x6b, 0xef, 0xc8, 0x1a, 0xdf, 0x41, 0xbc, 0xb4, 0x84, 0x65, + 0x15, 0x96, 0xd0, 0xa0, 0x9c, 0x6b, 0x22, 0xc4, 0x45, 0x97, 0xc5, 0x4c, 0xf7, 0x7d, 0x7b, 0xcc, + 0x10, 0x8d, 0x1d, 0xe1, 0x7a, 0x69, 0xc9, 0x0b, 0x31, 0xb2, 0xec, 0x74, 0x3b, 0x6e, 0x2f, 0x80, + 0x00, 0xd3, 0xab, 0xa5, 0x1c, 0x4c, 0xa2, 0x1c, 0xca, 0x50, 0xc8, 0x9d, 0xcc, 0x78, 0x55, 0xdb, + 0xc8, 0x20, 0x47, 0xe1, 0x6a, 0x30, 0xbb, 0xf0, 0x28, 0x10, 0x9b, 0xde, 0x43, 0x32, 0x6d, 0x68, + 0x10, 0x72, 0x77, 0xf5, 0xd8, 0xef, 0x64, 0x64, 0xbc, 0x4d, 0xd9, 0x3b, 0x05, 0x32, 0x0c, 0xfb, + 0x06, 0xdd, 0x5e, 0x53, 0x02, 0x43, 0x7c, 0x06, 0x02, 0xcc, 0xa5, 0xa7, 0x76, 0x41, 0x64, 0x05, + 0x7b, 0x27, 0xeb, 0x4e, 0xf2, 0x6c, 0xc9, 0x3a, 0xdb, 0x7c, 0xbd, 0xdd, 0x47, 0x3d, 0xae, 0x84, + 0xa2, 0x87, 0x69, 0x6d, 0xf7, 0x60, 0xd0, 0x71, 0xaa, 0x8c, 0x02, 0x8a, 0x56, 0x77, 0xa4, 0x72, + 0xc7, 0x6f, 0x91, 0x88, 0x1c, 0x59, 0x96, 0x75, 0x2d, 0x5b, 0xec, 0xea, 0x5e, 0x3b, 0x20, 0xf4, + 0x01, 0x86, 0x44, 0x7f, 0x8e, 0x10, 0x18, 0x3f, 0xb4, 0x27, 0x4b, 0xa2, 0x69, 0xe9, 0xf4, 0xac, + 0x8c, 0x9d, 0x54, 0xa0, 0x22, 0xa8, 0x77, 0x7a, 0x71, 0xf1, 0x70, 0xe3, 0xfa, 0x81, 0x53, 0xf6, + 0xfc, 0xfe, 0x14, 0x3d, 0x2f, 0xe0, 0xf4, 0xad, 0xf8, 0x20, 0xd2, 0xc1, 0x82, 0x54, 0x73, 0xf0, + 0x72, 0x04, 0x16, 0x31, 0x73, 0xe2, 0x71, 0xdf, 0x0f, 0x32, 0x65, 0x68, 0x27, 0xc3, 0x0e, 0x6b, + 0xa0, 0xee, 0xd1, 0xb0, 0x2a, 0xbb, 0x64, 0x39, 0x55, 0x7e, 0xe1, 0x98, 0x1d, 0x11, 0x73, 0xa3, + 0x43, 0x1a, 0x99, 0x3b, 0xef, 0xad, 0x79, 0x2d, 0x69, 0x94, 0xd3, 0xf0, 0x16, 0x10, 0x07, 0x42, + 0x20, 0x93, 0xb6, 0x51, 0x08, 0x2b, 0x53, 0x80, 0xec, 0xfa, 0x06, 0x75, 0x07, 0xee, 0xbb, 0xee, + 0x12, 0x29, 0x3a, 0xbc, 0x46, 0x51, 0xe6, 0xba, 0xd4, 0x3d, 0x91, 0x61, 0xf1, 0x78, 0x73, 0xda, + 0xfc, 0x49, 0x02, 0x78, 0x60, 0x9e, 0x5e, 0x18, 0x3d, 0x8a, 0xb1, 0x69, 0x89, 0x85, 0x82, 0xc0, + 0xb9, 0x73, 0xd4, 0xed, 0x29, 0x42, 0xd2, 0xdb, 0x1b, 0xa4, 0x6a, 0x51, 0xec, 0xdd, 0x9a, 0x59, + 0xcc, 0xed, 0x2b, 0xd3, 0xdd, 0xd6, 0x62, 0x61, 0x21, 0xe7, 0x0b, 0x3b, 0xf7, 0x1f, 0x25, 0x86, + 0xaa, 0x16, 0x5d, 0xc7, 0x46, 0x48, 0x26, 0x0b, 0x28, 0x86, 0xa8, 0x48, 0x20, 0xec, 0x94, 0x24, + 0xd3, 0xee, 0xb4, 0x1b, 0xe2, 0x6e, 0x72, 0x67, 0x4f, 0x0a, 0x1b, 0xde, 0x99, 0x68, 0xdd, 0xa5, + 0x5d, 0x3e, 0xf2, 0x4f, 0xab, 0x64, 0x9d, 0xeb, 0x39, 0x57, 0xda, 0x9d, 0x3c, 0x1e, 0x44, 0x51, + 0x40, 0xea, 0xf2, 0x21, 0x49, 0x05, 0x77, 0x8c, 0x69, 0xf1, 0xce, 0x18, 0x6d, 0xcb, 0xfb, 0x76, + 0xc6, 0xa3, 0xcc, 0x90, 0xf6, 0x54, 0xf7, 0x67, 0x85, 0x4e, 0x39, 0xbc, 0x41, 0xd2, 0x8a, 0x54, + 0x32, 0xdb, 0x84, 0xb9, 0x1d, 0x8f, 0x14, 0x75, 0xf9, 0x10, 0xa8, 0xef, 0x01, 0xc3, 0xe4, 0xa4, + 0xfa, 0x08, 0x59, 0xda, 0x86, 0x60, 0x7f, 0x54, 0xe2, 0x82, 0xd5, 0xe2, 0x62, 0xb6, 0x76, 0x2d, + 0xb2, 0x57, 0x51, 0x0c, 0x86, 0x39, 0xfe, 0xb4, 0x24, 0xcc, 0x73, 0x2f, 0x47, 0xe4, 0xf0, 0xbb, + 0xee, 0x38, 0x93, 0xea, 0xe1, 0xca, 0x50, 0x69, 0xc6, 0x26, 0xdd, 0xa9, 0xc0, 0x4a, 0xbf, 0xba, + 0xae, 0x70, 0x0f, 0x56, 0xb9, 0xc0, 0xf3, 0x7b, 0xae, 0xf4, 0xbf, 0x80, 0xd3, 0x72, 0xa9, 0x7e, + 0xff, 0x04, 0xc5, 0x80, 0x72, 0xbf, 0x4d, 0x93, 0x48, 0xcb, 0x64, 0xea, 0xc9, 0xec, 0xad, 0xa0, + 0x7c, 0x06, 0xf5, 0x04, 0xc3, 0xb5, 0x07, 0xf1, 0x0a, 0x9b, 0x7c, 0x98, 0x6e, 0xf7, 0x95, 0xec, + 0xfd, 0x59, 0x71, 0x55, 0x31, 0x42, 0x64, 0xf8, 0xa5, 0x8a, 0x21, 0xe2, 0x47, 0xd1, 0x40, 0x1f, + 0xb1, 0x30, 0xc7, 0x29, 0x6c, 0x8a, 0xd4, 0x19, 0xe6, 0xa4, 0x26, 0xf9, 0xa0, 0xee, 0x24, 0x89, + 0xfd, 0x81, 0x2d, 0xbf, 0x6f, 0x80, 0x20, 0x07, 0xf9, 0xa7, 0x69, 0xb8, 0xab, 0x10, 0xdd, 0xda, + 0x44, 0xc5, 0x86, 0x5d, 0x0f, 0x30, 0x71, 0x88, 0x53, 0x6b, 0x8c, 0xa8, 0x4d, 0x46, 0x2f, 0x8e, + 0xe5, 0x6b, 0x07, 0x4e, 0xcf, 0x35, 0x24, 0xaa, 0x15, 0xc9, 0xea, 0x45, 0xd9, 0xa9, 0xa6, 0x3d, + 0x55, 0x41, 0x2b, 0x61, 0x1c, 0x29, 0xab, 0x38, 0xf9, 0xfd, 0xfb, 0x52, 0xbf, 0xce, 0xe1, 0x4b, + 0x56, 0x98, 0x92, 0x7c, 0xd0, 0x6b, 0xcc, 0x70, 0x55, 0x58, 0xf5, 0x58, 0xbf, 0xa1, 0x71, 0x4c, + 0x1c, 0x2e, 0xd7, 0xb7, 0x4c, 0x9d, 0x2a, 0xa5, 0x37, 0xb5, 0x5c, 0xc3, 0x0f, 0x2a, 0x16, 0x18, + 0xdf, 0xa2, 0xef, 0x25, 0xfb, 0x23, 0x73, 0x5c, 0x3e, 0xba, 0xb6, 0x16, 0xcd, 0x25, 0xd7, 0x1e, + 0xfa, 0xb0, 0x4a, 0x85, 0xcf, 0x3a, 0xb2, 0xcd, 0x47, 0xa2, 0x09, 0x6c, 0xae, 0x30, 0x0d, 0x0b, + 0x6c, 0x35, 0xb1, 0x5c, 0xe0, 0xcf, 0x88, 0x6e, 0x0f, 0x06, 0xe0, 0x0e, 0xa9, 0x1c, 0xe1, 0x0e, + 0x50, 0x98, 0x42, 0x49, 0xd4, 0x5a, 0xb5, 0x4f, 0x35, 0x72, 0x4c, 0xa9, 0x14, 0xde, 0x94, 0x80, + 0x6b, 0x25, 0xec, 0xc8, 0xa7, 0x63, 0x52, 0xe0, 0x1a, 0xcf, 0x93, 0x18, 0xe4, 0xda, 0xb9, 0x35, + 0x12, 0xdd, 0x68, 0x17, 0x00, 0x93, 0x5b, 0x85, 0x51, 0x97, 0x81, 0x9a, 0x23, 0x1e, 0xe3, 0x6a, + 0xeb, 0x35, 0xbb, 0x51, 0xab, 0xad, 0xe2, 0xca, 0xd9, 0x54, 0x12, 0x98, 0x75, 0x55, 0x2c, 0x43, + 0x77, 0x97, 0xe2, 0x18, 0xe0, 0x12, 0xd9, 0xf2, 0x3e, 0x4c, 0xfe, 0x09, 0xfb, 0x08, 0xb1, 0x3e, + 0xc6, 0xe9, 0xe6, 0xfa, 0xe0, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, + 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, + 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0xd7, 0x13, 0x4f, 0xe6, 0x83, 0x0b, 0x41, 0x48, + 0x69, 0x7a, 0x07, 0xe9, 0x72, 0xab, 0x86, 0xcb, 0x4e, 0x93, 0xaa, 0xc7, 0xe3, 0x59, 0x3d, 0xf4, + 0xa4, 0x28, 0x77, 0x01, 0xb4, 0x9b, 0xa9, 0x31, 0xf5, 0xa0, 0x07, 0x77, 0x4d, 0x9e, 0xfa, 0xe6, + 0x61, 0x16, 0x25, 0x69, 0x18, 0xb6, 0x84, 0xbf, 0xac, 0xe4, 0xbf, 0x53, 0x41, 0x16, 0x12, 0x2a, + 0x97, 0x1b, 0x15, 0xc9, 0x7d, 0x9d, 0xdb, 0xe6, 0x7e, 0xc2, 0xe4, 0x81, 0xc9, 0x95, 0xcf, 0x7d, + 0x68, 0xca, 0x05, 0xc2, 0x8a, 0xe5, 0x0c, 0x14, 0xd1, 0x27, 0x51, 0x7f, 0x42, 0x8e, 0x01, 0xd6, + 0x9a, 0x6a, 0xe4, 0x39, 0xcf, 0x21, 0x46, 0xc5, 0x43, 0xfb, 0x64, 0x6f, 0x38, 0xae, 0x5c, 0xcd, + 0xa7, 0x5b, 0xd9, 0xb3, 0x5a, 0xfd, 0xed, 0x94, 0x63, 0x15, 0x6e, 0x5f, 0x57, 0x8e, 0xeb, 0x09, + 0x41, 0xce, 0xb6, 0x3f, 0x9d, 0x10, 0xd7, 0x21, 0x26, 0xe6, 0x1c, 0x46, 0xc7, 0x14, 0xb4, 0xaa, + 0x6d, 0xf7, 0x78, 0x2d, 0xfb, 0x5e, 0xfe, 0x40, 0xc9, 0x5f, 0xca, 0x95, 0x6b, 0x2a, 0xae, 0x7f, + 0x93, 0xbe, 0xec, 0x53, 0x01, 0xb8, 0xb3, 0x35, 0x7e, 0xec, 0x86, 0x39, 0x63, 0xa8, 0x6b, 0xa9, + 0x12, 0x70, 0xf3, 0x97, 0x2c, 0xe2, 0x84, 0xab, 0x9e, 0xed, 0x93, 0xac, 0xe9, 0xcc, 0x1b, 0x3c, + 0xb9, 0xf8, 0x8e, 0xd9, 0x21, 0x95, 0xd4, 0x8e, 0xe4, 0x0e, 0xbc, 0x9e, 0xd9, 0x72, 0xf3, 0x65, + 0xf2, 0x12, 0x02, 0x8b, 0xd3, 0x72, 0x8d, 0xe9, 0x81, 0x3f, 0x81, 0xef, 0xfb, 0x44, 0xd4, 0x85, + 0xbd, 0x78, 0x39, 0x85, 0xef, 0xd5, 0x85, 0x43, 0x7b, 0x28, 0x17, 0xa8, 0xb8, 0x5c, 0x0b, 0x3e, + 0x0d, 0xb5, 0x3c, 0x9f, 0x01, 0xb6, 0x26, 0xb2, 0x9b, 0x07, 0xce, 0x03, 0x03, 0x87, 0xa7, 0x77, + 0xee, 0x04, 0xd8, 0x25, 0x13, 0x2c, 0x45, 0x70, 0x59, 0x76, 0xd7, 0x15, 0x85, 0x58, 0x88, 0xf0, + 0x23, 0x83, 0x45, 0x48, 0x9a, 0x33, 0x5b, 0x45, 0x37, 0xf9, 0xb0, 0x21, 0x70, 0x8b, 0x12, 0x85, + 0x7c, 0xe0, 0xc2, 0x8a, 0x75, 0x9a, 0x4a, 0xd2, 0xb5, 0x82, 0xb1, 0x14, 0x24, 0xae, 0xfb, 0xb6, + 0x96, 0xfc, 0x25, 0xd6, 0x70, 0x43, 0x96, 0x46, 0x37, 0x57, 0x2a, 0x68, 0xe4, 0x94, 0x33, 0x7d, + 0xbd, 0xd2, 0xf1, 0xc6, 0x98, 0xda, 0x2e, 0x7a, 0x78, 0x44, 0x02, 0x0e, 0xef, 0xf3, 0x86, 0xe6, + 0x52, 0x5a, 0x8e, 0x95, 0xcd, 0xec, 0xee, 0xe8, 0x5d, 0x18, 0x69, 0xcd, 0x94, 0x17, 0x2a, 0xe5, + 0x7e, 0x12, 0x2a, 0x39, 0x41, 0xc3, 0x15, 0xad, 0x24, 0x61, 0x45, 0xcd, 0x77, 0x25, 0xf9, 0xc8, + 0x6a, 0x71, 0x20, 0x4c, 0xc3, 0xf2, 0xbb, 0xb4, 0x80, 0x1e, 0xa0, 0xec, 0x3b, 0xec, 0x7d, 0x62, + 0x5f, 0xbe, 0x60, 0x0c, 0xf8, 0xf3, 0x93, 0xd3, 0xcb, 0x09, 0xa3, 0xf9, 0x15, 0xbe, 0xaf, 0x8f, + 0x8e, 0x10, 0x5e, 0x50, 0x86, 0xad, 0xc5, 0x49, 0x03, 0x98, 0x0c, 0x8e, 0x43, 0xb6, 0x4c, 0x5e, + 0xbd, 0x63, 0x96, 0x31, 0x45, 0xdb, 0x51, 0x6f, 0x62, 0xc9, 0x90, 0xcb, 0xd4, 0x49, 0x3e, 0x20, + 0x03, 0x00, 0xd5, 0xf9, 0x40, 0x72, 0xf1, 0x61, 0x3d, 0x97, 0x92, 0xd2, 0x6d, 0x39, 0x0e, 0x50, + 0xcf, 0x87, 0x6e, 0xce, 0x02, 0xf3, 0x66, 0xd0, 0x0d, 0xf8, 0x92, 0x37, 0xd9, 0x99, 0x76, 0x5c, + 0x2a, 0xe6, 0x7b, 0x43, 0x00, 0x97, 0x36, 0x06, 0x93, 0xe8, 0xf6, 0x05, 0x2f, 0x30, 0xc7, 0xd1, + 0x0a, 0xc8, 0xfa, 0x28, 0x52, 0x73, 0x4b, 0x8c, 0x19, 0x0a, 0x87, 0x37, 0xe2, 0xae, 0x2b, 0x07, + 0x01, 0x84, 0xe9, 0x63, 0xef, 0x1a, 0x73, 0x5b, 0x34, 0x20, 0x9e, 0x90, 0x0f, 0xe9, 0x31, 0x19, + 0x97, 0x91, 0xbe, 0x2f, 0x09, 0xaf, 0x20, 0x22, 0x05, 0x73, 0x1c, 0xd5, 0xf5, 0x53, 0x00, 0x7a, + 0xb9, 0x9f, 0x38, 0x59, 0x76, 0x1f, 0x17, 0xa3, 0xa0, 0xae, 0x87, 0x08, 0xd4, 0xba, 0x86, 0x6c, + 0x2b, 0x3b, 0xda, 0x69, 0x1e, 0x75, 0x15, 0x82, 0x07, 0x29, 0x75, 0x2d, 0xd7, 0x5f, 0x10, 0x5b, + 0xf3, 0x52, 0xc4, 0x6b, 0x16, 0xf4, 0x6c, 0x68, 0xbb, 0x64, 0x6c, 0x86, 0xd7, 0x9b, 0x8f, 0x88, + 0x52, 0x95, 0x9c, 0xd2, 0xaf, 0x7e, 0x6f, 0x9d, 0x43, 0xc3, 0x14, 0x62, 0x1e, 0xcd, 0xeb, 0xee, + 0x61, 0x4d, 0x1d, 0x62, 0x5d, 0x4c, 0x1a, 0x5f, 0xb4, 0x4e, 0xa6, 0xd1, 0x2b, 0x3d, 0x2c, 0x9a, + 0xf7, 0x41, 0xae, 0x8e, 0xbb, 0xcd, 0x5d, 0xfb, 0x20, 0xb7, 0x2f, 0x9f, 0x5a, 0x9a, 0x37, 0x58, + 0x89, 0x93, 0xb3, 0x5a, 0x31, 0x51, 0xa6, 0xf4, 0x5d, 0xb7, 0x21, 0x75, 0x5d, 0x97, 0xb5, 0x3a, + 0xa9, 0x0b, 0xa6, 0x0c, 0x46, 0xf3, 0x34, 0x10, 0xa5, 0xd7, 0x76, 0x87, 0xe8, 0x8b, 0x49, 0x37, + 0x73, 0x47, 0xeb, 0x19, 0xa4, 0xe8, 0xbc, 0xdb, 0x81, 0xce, 0xa8, 0x7e, 0x2f, 0x81, 0x46, 0x17, + 0x63, 0x04, 0xa2, 0x78, 0xa4, 0xdb, 0xcf, 0x50, 0x9a, 0x44, 0x83, 0xd1, 0xb9, 0x19, 0xab, 0x4c, + 0x70, 0x57, 0x64, 0x7e, 0xfe, 0xdd, 0x66, 0x9d, 0x2f, 0xe0, 0xf4, 0x18, 0x09, 0x74, 0x54, 0x94, + 0x3e, 0xdb, 0x88, 0x76, 0xa0, 0x7b, 0xbe, 0x8e, 0x83, 0x4c, 0xea, 0x76, 0xa1, 0xaf, 0x4f, 0xf3, + 0xe4, 0xe5, 0xb5, 0x74, 0x6d, 0x9b, 0x60, 0x4b, 0x3d, 0xef, 0xaf, 0x22, 0x5a, 0x77, 0x9b, 0x04, + 0xe4, 0xab, 0xa6, 0xfb, 0x82, 0x34, 0x9f, 0x82, 0x45, 0xa6, 0xe2, 0x28, 0xe1, 0x26, 0x1b, 0xea, + 0x22, 0x08, 0x71, 0x73, 0x7f, 0xde, 0x05, 0xe5, 0x53, 0x41, 0x67, 0x0d, 0x2d, 0x56, 0x94, 0x36, + 0x93, 0xbb, 0xbb, 0x23, 0x0e, 0xa4, 0x72, 0x43, 0x9c, 0x28, 0xa4, 0xac, 0xa8, 0x8c, 0x19, 0x2b, + 0x99, 0x6b, 0x82, 0x45, 0x9c, 0x71, 0xf7, 0x6a, 0x34, 0xa4, 0x11, 0x8b, 0xc7, 0x94, 0xb5, 0x05, + 0x77, 0x4f, 0x61, 0xe3, 0xb0, 0x91, 0x4d, 0xd9, 0x6a, 0x1c, 0x45, 0x9f, 0x92, 0x57, 0x1f, 0x63, + 0xd5, 0xe6, 0x2d, 0xdd, 0x52, 0xf6, 0x64, 0xd6, 0x0f, 0x29, 0xec, 0x7a, 0xd7, 0x31, 0x64, 0xd6, + 0xc6, 0xe4, 0x80, 0x56, 0x84, 0x56, 0xe7, 0x4d, 0x99, 0xeb, 0xf6, 0x15, 0x43, 0x82, 0x20, 0xa4, + 0x61, 0x6b, 0xb9, 0xf0, 0xc4, 0x8e, 0x6f, 0x34, 0xa6, 0x5e, 0x46, 0x4b, 0x93, 0x9a, 0xb4, 0x8f, + 0x71, 0x92, 0x52, 0x08, 0xf3, 0x08, 0xcc, 0xd7, 0xf7, 0x97, 0x43, 0xe0, 0xe3, 0xce, 0x23, 0x97, + 0xb1, 0x96, 0xb8, 0x55, 0x41, 0x04, 0x49, 0x78, 0x76, 0xaa, 0x31, 0xc6, 0x72, 0x0d, 0x5b, 0x62, + 0x65, 0xc7, 0x8a, 0xb1, 0xe0, 0x2d, 0xe4, 0x1b, 0x21, 0xce, 0xe1, 0x9c, 0x11, 0x81, 0xfc, 0xee, + 0xc2, 0x51, 0x99, 0xbd, 0x5d, 0x0b, 0x38, 0x76, 0x8a, 0x7e, 0xdb, 0x06, 0xdf, 0x5d, 0x1c, 0xd9, + 0x08, 0x00, 0x0f, 0xad, 0x83, 0xbe, 0xf8, 0x5e, 0xe8, 0x06, 0xfb, 0x60, 0x17, 0xd9, 0xa8, 0xd6, + 0xca, 0xe4, 0x70, 0x08, 0x6b, 0x23, 0x46, 0x81, 0xf4, 0x58, 0x0e, 0x75, 0xc3, 0x28, 0x13, 0x70, + 0xe1, 0x0f, 0xed, 0xbc, 0x49, 0x44, 0xdc, 0x5f, 0x9f, 0x90, 0xd4, 0x6b, 0x72, 0x4e, 0xd5, 0x86, + 0x36, 0x9c, 0x07, 0xc9, 0xda, 0xf5, 0xd0, 0xf2, 0xf3, 0xeb, 0xe9, 0xba, 0x88, 0x2f, 0xe0, 0xb4, + 0x50, 0x5e, 0xe6, 0x14, 0xbb, 0x27, 0x96, 0xd6, 0xb2, 0xb5, 0x7e, 0xe7, 0x4c, 0xb9, 0x17, 0x04, + 0x6d, 0x36, 0x6b, 0x5e, 0x2c, 0x6e, 0xaf, 0x77, 0xef, 0xe4, 0xf3, 0x56, 0x50, 0x03, 0x73, 0xad, + 0xe0, 0x7c, 0xb9, 0x2b, 0x27, 0x1e, 0x4f, 0x26, 0x63, 0x32, 0x98, 0x51, 0x6b, 0xb5, 0xa9, 0xeb, + 0x05, 0xb2, 0x5b, 0x25, 0x03, 0x3c, 0xdc, 0xc1, 0x4c, 0x6c, 0x79, 0xbf, 0x88, 0x68, 0xf1, 0xd0, + 0x56, 0xdd, 0xca, 0xb7, 0x7d, 0xe8, 0x6e, 0xb3, 0x10, 0x93, 0x90, 0xb0, 0x10, 0x4f, 0x41, 0x6e, + 0xc2, 0x89, 0x77, 0x7f, 0x05, 0xdc, 0x2c, 0x29, 0xb1, 0x2c, 0x93, 0x51, 0xc4, 0x32, 0x72, 0xad, + 0x79, 0x44, 0xd4, 0x5d, 0x65, 0x62, 0x1c, 0x7b, 0xe1, 0xe1, 0xfd, 0x01, 0x46, 0x55, 0x6f, 0xe6, + 0xdf, 0xd8, 0xa8, 0xe8, 0xc2, 0x5c, 0x14, 0x01, 0xb1, 0xce, 0xd9, 0x95, 0x4a, 0x1f, 0x5a, 0x84, + 0xee, 0xdf, 0x16, 0xaa, 0x1a, 0xcc, 0xdd, 0xa8, 0x9a, 0x8b, 0xb1, 0x83, 0x43, 0x16, 0xf1, 0x06, + 0x5e, 0x50, 0x2e, 0xae, 0x7b, 0x87, 0x9d, 0x5d, 0x9d, 0x61, 0x7d, 0xc4, 0xdd, 0x3d, 0xe9, 0x44, + 0x52, 0x3e, 0xa7, 0x98, 0x8d, 0x98, 0x5d, 0x7b, 0xdb, 0xf7, 0x11, 0x97, 0x78, 0x18, 0xe3, 0x4d, + 0x28, 0x66, 0xa1, 0xdc, 0x11, 0x2a, 0xe5, 0xdc, 0xce, 0x31, 0x27, 0xc5, 0xa1, 0x68, 0x18, 0x81, + 0x43, 0x1c, 0x55, 0x64, 0xd7, 0xd2, 0xb7, 0x68, 0xef, 0x57, 0x78, 0x2b, 0xee, 0x8c, 0xf5, 0xc8, + 0xc5, 0xd9, 0x3e, 0xa6, 0x6d, 0x1a, 0x32, 0xb2, 0xa3, 0x38, 0xb6, 0xe3, 0x8d, 0x4b, 0x4d, 0x10, + 0x2f, 0x1e, 0x70, 0x17, 0xae, 0x95, 0xfc, 0x10, 0xa7, 0xdc, 0x3e, 0x47, 0x5f, 0x0d, 0x08, 0x23, + 0x32, 0x4b, 0x5b, 0x08, 0xa5, 0xc1, 0xb7, 0x12, 0xb0, 0x0d, 0xb2, 0xf2, 0x34, 0x3a, 0x7e, 0xd7, + 0x84, 0xdb, 0x3e, 0x26, 0x67, 0xbb, 0xcc, 0x9d, 0x7e, 0x29, 0x58, 0xaa, 0x7b, 0x83, 0x61, 0x31, + 0x8e, 0x53, 0x26, 0x54, 0x6d, 0x60, 0xd4, 0x45, 0xcf, 0xc6, 0xa6, 0xb7, 0xa1, 0x4f, 0xf0, 0x1d, + 0xa5, 0xbc, 0x80, 0xd3, 0x92, 0xad, 0x85, 0xd5, 0x62, 0x2b, 0x75, 0x41, 0xef, 0x9e, 0x0e, 0x4f, + 0x6e, 0xaf, 0x6e, 0x90, 0xd4, 0xf3, 0x19, 0x96, 0x74, 0x22, 0x65, 0xb3, 0x10, 0x0f, 0x5c, 0x76, + 0xc0, 0xb5, 0x92, 0x49, 0xe4, 0x1d, 0x8c, 0xbd, 0x5c, 0x14, 0x73, 0x89, 0x34, 0x6e, 0xd0, 0x61, + 0xf2, 0xac, 0xbb, 0x31, 0x69, 0x29, 0x11, 0xdf, 0x71, 0x97, 0xa5, 0x21, 0xd0, 0xc2, 0xb2, 0x96, + 0x27, 0xd3, 0xff, 0x3f, 0x7b, 0xe7, 0xd3, 0x93, 0xc8, 0xb6, 0x3d, 0xec, 0x2f, 0x73, 0x6d, 0x83, + 0x1e, 0x34, 0xe9, 0x73, 0xd1, 0xa0, 0x57, 0x7b, 0x2c, 0x1e, 0x30, 0x01, 0x0b, 0x02, 0x34, 0x30, + 0x39, 0x68, 0x00, 0x81, 0x04, 0x04, 0x22, 0x25, 0xf4, 0x77, 0x50, 0xfe, 0x44, 0x11, 0x99, 0x08, + 0x04, 0xca, 0x82, 0x04, 0xac, 0x22, 0x80, 0x05, 0x63, 0xa1, 0xc1, 0x04, 0xac, 0xaa, 0x40, 0x09, + 0x4c, 0x1a, 0x09, 0x60, 0x41, 0x22, 0x02, 0x41, 0xda, 0xbe, 0xaf, 0x77, 0xdc, 0xc7, 0xe9, 0x3b, + 0xf8, 0xc5, 0xe7, 0x13, 0xc0, 0xc3, 0xae, 0xb5, 0xf7, 0xa2, 0xf6, 0x5a, 0xcb, 0x7d, 0x13, 0x92, + 0x06, 0x67, 0xa3, 0xf2, 0x3c, 0xf2, 0xf6, 0x70, 0xe5, 0xef, 0xe0, 0xc8, 0x84, 0xef, 0x64, 0x7c, + 0xe2, 0xe5, 0xf4, 0x33, 0x5f, 0x16, 0x21, 0xc2, 0x33, 0xd6, 0x3b, 0x05, 0xe2, 0xae, 0x8c, 0xa3, + 0x97, 0x72, 0x78, 0x1c, 0xf9, 0x8f, 0x50, 0x5c, 0x2a, 0x27, 0x67, 0x72, 0xe1, 0xd1, 0xd9, 0x70, + 0x62, 0x3e, 0xac, 0x36, 0x97, 0xa5, 0x5f, 0x11, 0x76, 0x59, 0x74, 0x58, 0xd1, 0x6b, 0x81, 0xbf, + 0x13, 0xa1, 0xcf, 0x86, 0xcb, 0xf1, 0x22, 0x4b, 0x0e, 0x65, 0xcd, 0xbc, 0xaf, 0x67, 0x2d, 0xf6, + 0x0d, 0xec, 0xb3, 0xd0, 0xc3, 0xfc, 0x76, 0x3b, 0x19, 0x2e, 0x59, 0x2e, 0xc2, 0xfd, 0xaa, 0x97, + 0x0c, 0xd7, 0x74, 0x42, 0xda, 0xb2, 0x29, 0x7d, 0x48, 0xdd, 0xa4, 0xea, 0xb5, 0xc4, 0x2a, 0x04, + 0xd4, 0x2b, 0x7d, 0xfd, 0x08, 0x5c, 0xd3, 0xa6, 0x8f, 0x01, 0x4b, 0x56, 0x3a, 0x06, 0x64, 0x13, + 0xec, 0x0c, 0x57, 0xe8, 0x6b, 0xce, 0x48, 0xbd, 0xb9, 0xbe, 0x89, 0x25, 0xe9, 0x03, 0x85, 0x6c, + 0x1e, 0xfe, 0xd3, 0xfe, 0x84, 0x10, 0xf8, 0x66, 0xff, 0x8b, 0x98, 0xa1, 0x30, 0x84, 0x91, 0x61, + 0x6d, 0x84, 0x16, 0xed, 0x91, 0xea, 0x45, 0x48, 0x9c, 0xf0, 0x33, 0x11, 0x0e, 0xdf, 0x4c, 0xad, + 0x4b, 0x44, 0x00, 0xb2, 0xbc, 0x90, 0xe0, 0x27, 0x59, 0x1b, 0xf6, 0x01, 0x23, 0x82, 0x7c, 0x4b, + 0x64, 0x45, 0xfa, 0x1c, 0x80, 0x9b, 0x36, 0xab, 0xb1, 0x49, 0xb0, 0x92, 0x7f, 0x0d, 0xfa, 0xdf, + 0xe2, 0x1c, 0xbe, 0x44, 0xdc, 0x5f, 0xa7, 0xc5, 0x02, 0x6f, 0xe2, 0xf7, 0xe8, 0x31, 0x64, 0xbf, + 0x63, 0x9a, 0x85, 0x35, 0xc2, 0x4e, 0xb9, 0x91, 0xa7, 0x50, 0x63, 0xc4, 0x61, 0xff, 0x9b, 0xa5, + 0x32, 0xd0, 0xd4, 0x32, 0xf4, 0xa8, 0xd7, 0x09, 0xe6, 0x4a, 0x1e, 0xd1, 0x30, 0x24, 0x87, 0xd3, + 0x42, 0x1c, 0xd3, 0x0a, 0x03, 0xa3, 0xdc, 0x75, 0xff, 0x53, 0x32, 0x42, 0xbc, 0xee, 0x4a, 0x9c, + 0xde, 0xaa, 0x5f, 0x22, 0x84, 0x94, 0xb4, 0xe9, 0xdb, 0x31, 0x81, 0x5a, 0xbd, 0x32, 0x6c, 0x51, + 0x8e, 0x0a, 0xb3, 0xf3, 0xe5, 0x6a, 0x63, 0x36, 0x57, 0xf1, 0xc9, 0x9b, 0x37, 0xe3, 0xe1, 0x10, + 0xd3, 0xd8, 0x63, 0x2e, 0x07, 0x25, 0x24, 0xb0, 0x70, 0xd7, 0x0a, 0xf8, 0xfd, 0x5a, 0x7e, 0x03, + 0x68, 0x1e, 0x88, 0x63, 0xfc, 0x8b, 0x10, 0xa3, 0x61, 0xda, 0x1e, 0xf6, 0xac, 0x7a, 0x59, 0x1a, + 0xeb, 0xfe, 0xe8, 0xe1, 0x53, 0x39, 0x26, 0xf2, 0x0b, 0x0c, 0xb5, 0x5d, 0xd9, 0x58, 0x48, 0x9d, + 0x35, 0x96, 0x11, 0xa5, 0x28, 0x43, 0xe2, 0x4f, 0xc3, 0x69, 0xa8, 0xde, 0x9c, 0x49, 0x1c, 0x44, + 0x0e, 0x7f, 0xc2, 0x39, 0x24, 0xf6, 0x8c, 0xdd, 0xd2, 0x51, 0xdd, 0x4b, 0x74, 0xa4, 0x58, 0xb4, + 0xda, 0x47, 0xb6, 0xda, 0xd4, 0x24, 0x77, 0xfb, 0xd9, 0x13, 0x73, 0x79, 0xad, 0x63, 0x42, 0xfd, + 0x9d, 0x8e, 0x0e, 0x85, 0xd3, 0x0a, 0xe9, 0x5e, 0x3a, 0x53, 0xed, 0x77, 0xfb, 0x5d, 0x89, 0x4a, + 0xfe, 0xe0, 0x3b, 0xb0, 0x1e, 0xc7, 0xcf, 0x86, 0x26, 0xfb, 0x5e, 0x97, 0xfd, 0xa2, 0xa1, 0xc4, + 0x0d, 0xbd, 0xd9, 0xbd, 0xda, 0x35, 0x74, 0xfb, 0x33, 0x7a, 0x29, 0x57, 0x18, 0x64, 0x77, 0xf2, + 0x57, 0xaf, 0xea, 0x27, 0xed, 0xf1, 0xac, 0x56, 0xea, 0xea, 0xaa, 0x16, 0xa8, 0xc2, 0x73, 0x5f, + 0x84, 0x8f, 0x86, 0x32, 0xa2, 0x6e, 0x87, 0x67, 0x1e, 0x88, 0x4b, 0xda, 0x91, 0x41, 0x47, 0x35, + 0xdf, 0x5c, 0x24, 0xac, 0x76, 0x77, 0xd5, 0x77, 0xcd, 0x90, 0xf2, 0xc0, 0xe5, 0x65, 0x57, 0x04, + 0x23, 0xc0, 0x5a, 0xd4, 0xf4, 0x91, 0xb5, 0xe6, 0x1a, 0xff, 0xc7, 0xef, 0x33, 0x28, 0x9b, 0x6b, + 0xef, 0x98, 0x36, 0x65, 0x7a, 0xa4, 0x14, 0xb4, 0x48, 0xf4, 0x9e, 0x15, 0xdd, 0xf6, 0x8b, 0x3b, + 0x20, 0x26, 0xcf, 0xa6, 0x0f, 0xc3, 0x06, 0x1a, 0x12, 0x4f, 0x04, 0xfa, 0x33, 0x1a, 0xbd, 0xea, + 0x36, 0xa4, 0x52, 0x78, 0x57, 0x94, 0x5d, 0x07, 0xb1, 0xf3, 0x4c, 0x3f, 0x3f, 0x68, 0x7f, 0x2a, + 0xd6, 0xb0, 0xe6, 0xaa, 0x4e, 0x73, 0x37, 0x44, 0xba, 0x60, 0xf7, 0x3f, 0x01, 0x40, 0x04, 0x49, + 0x21, 0xea, 0x0a, 0x59, 0xeb, 0xa4, 0x22, 0xb0, 0x2a, 0xd0, 0x75, 0xc5, 0x57, 0xc6, 0x09, 0x59, + 0x04, 0xdf, 0x58, 0x8b, 0x42, 0xf2, 0x5a, 0xc7, 0xa6, 0xb7, 0xd4, 0x5e, 0x9f, 0x5a, 0xc9, 0x00, + 0xad, 0x0e, 0x2e, 0x11, 0x43, 0xd0, 0xd0, 0xbe, 0x09, 0xc1, 0x7b, 0x27, 0x2d, 0xb4, 0x30, 0x3e, + 0x09, 0x65, 0x8e, 0xfc, 0xa1, 0x2c, 0xf3, 0x7f, 0x63, 0xc3, 0xe4, 0xe0, 0x30, 0x78, 0xa0, 0xf6, + 0x52, 0x3f, 0x72, 0xa0, 0xc3, 0xd3, 0x8c, 0xd0, 0xbe, 0xb4, 0x73, 0xa1, 0x58, 0xdb, 0xf9, 0x85, + 0x1f, 0x28, 0x5c, 0x5e, 0xa0, 0xae, 0xde, 0x73, 0x47, 0x36, 0x52, 0x32, 0x5b, 0x96, 0xdc, 0xc7, + 0xff, 0xd5, 0x46, 0xb3, 0xe9, 0x6f, 0xe0, 0xfa, 0x93, 0x7b, 0x77, 0x83, 0x1f, 0x03, 0x98, 0x90, + 0x30, 0x02, 0xa5, 0x5e, 0x32, 0x47, 0xe6, 0xc7, 0x86, 0x08, 0x57, 0x88, 0xba, 0xa5, 0xd3, 0x1f, + 0xb4, 0x76, 0xba, 0x95, 0x78, 0xc8, 0x0a, 0x8b, 0xaf, 0x59, 0xad, 0xc9, 0x76, 0xfd, 0x23, 0x6f, + 0x2c, 0x3d, 0xb5, 0xfc, 0x2f, 0x57, 0x58, 0x0f, 0xef, 0x0a, 0x2e, 0x4e, 0xd4, 0x3d, 0xe4, 0xb2, + 0x99, 0x58, 0x75, 0x1c, 0xcf, 0x1c, 0xac, 0x42, 0x5e, 0x47, 0x90, 0x97, 0xe5, 0x63, 0x99, 0x54, + 0x39, 0x28, 0x21, 0xe2, 0x7c, 0xcf, 0xbf, 0x72, 0xb1, 0xee, 0xf5, 0x7f, 0x55, 0x2b, 0x9b, 0x60, + 0x22, 0xb8, 0x8c, 0xc6, 0x61, 0xac, 0x97, 0xdb, 0x83, 0x37, 0x56, 0x38, 0x17, 0x27, 0x33, 0xb9, + 0xb3, 0xd6, 0xe9, 0xb4, 0x42, 0xbd, 0xfa, 0x25, 0xd5, 0xa8, 0x34, 0xc4, 0xd1, 0x77, 0xe9, 0xdf, + 0x27, 0x6e, 0x99, 0xc4, 0xef, 0x98, 0x06, 0x21, 0x85, 0x14, 0x43, 0x10, 0x13, 0x38, 0x87, 0x44, + 0x74, 0x38, 0x44, 0xf4, 0xec, 0x8d, 0xe5, 0xdb, 0xdb, 0x27, 0x41, 0xe8, 0xe0, 0xd7, 0xe0, 0x7e, + 0x9c, 0xac, 0x1f, 0xef, 0xb5, 0x6e, 0xfa, 0x67, 0x41, 0x53, 0xad, 0x97, 0x2e, 0x4d, 0xd6, 0x5e, + 0xbb, 0x6f, 0xbf, 0x3a, 0x8d, 0xa9, 0xab, 0xc9, 0x48, 0xee, 0xe2, 0xd2, 0xbf, 0x32, 0x72, 0xdd, + 0x57, 0x5e, 0xef, 0xcb, 0x17, 0x37, 0x65, 0x9f, 0xb7, 0xdd, 0xae, 0x82, 0x3e, 0x72, 0x38, 0x05, + 0xaf, 0xa7, 0xcc, 0xc8, 0xe6, 0x0e, 0x3e, 0xd6, 0x44, 0xad, 0xa9, 0xf4, 0x92, 0xda, 0x00, 0x91, + 0xa5, 0xa3, 0x47, 0x4f, 0xde, 0xbe, 0x75, 0x34, 0x46, 0x9f, 0x9e, 0x5a, 0xa6, 0x64, 0x7d, 0x80, + 0xb0, 0x3b, 0x7a, 0xca, 0x47, 0xe6, 0xf2, 0x1d, 0x8b, 0x27, 0xdc, 0xce, 0x99, 0x89, 0x21, 0x52, + 0x9d, 0xca, 0x09, 0xac, 0x64, 0xf0, 0x02, 0xa9, 0x88, 0x96, 0xcd, 0x33, 0x46, 0x76, 0xc6, 0xfe, + 0x35, 0x4f, 0x8b, 0xc2, 0xaa, 0x65, 0x6f, 0xb0, 0xde, 0xab, 0xf5, 0xda, 0xec, 0xd2, 0x7e, 0xd4, + 0x93, 0x99, 0x50, 0x66, 0x34, 0xaa, 0x6d, 0x80, 0x6f, 0xcf, 0x4a, 0xe4, 0xf8, 0xcc, 0x4f, 0x34, + 0xe2, 0xf3, 0xd8, 0x13, 0x28, 0x71, 0x8c, 0x6c, 0xdd, 0xbe, 0x8d, 0xe8, 0xbe, 0xed, 0x5f, 0x2b, + 0x9d, 0x34, 0x7e, 0x11, 0x5d, 0x34, 0x35, 0xbc, 0x28, 0x24, 0xdb, 0xc5, 0x76, 0x61, 0x1d, 0x22, + 0x69, 0x83, 0x12, 0x81, 0x3d, 0x57, 0xba, 0x3f, 0xaf, 0xcd, 0x2c, 0x6e, 0x79, 0xab, 0xc3, 0xc5, + 0x53, 0x07, 0x14, 0x56, 0xf1, 0x86, 0x7e, 0xda, 0xd8, 0xdb, 0x21, 0x59, 0x11, 0xcb, 0xbe, 0x2b, + 0x59, 0xe0, 0x9b, 0x92, 0xed, 0xb6, 0xda, 0x96, 0xca, 0x00, 0x09, 0x05, 0x3e, 0x5c, 0x04, 0xa3, + 0xf3, 0xf3, 0x25, 0x27, 0xa9, 0x9f, 0xd3, 0x46, 0xe4, 0x63, 0x59, 0xc4, 0x5c, 0xc3, 0x92, 0xab, + 0x6a, 0xc1, 0x55, 0x7f, 0x15, 0xb7, 0xd6, 0x96, 0x19, 0x6f, 0x87, 0xa1, 0xa2, 0x74, 0xe0, 0xf8, + 0xbd, 0xee, 0x59, 0x29, 0x7b, 0xc7, 0x34, 0x60, 0x15, 0x39, 0x95, 0xbc, 0x0a, 0x0e, 0x5b, 0x24, + 0x69, 0x62, 0x98, 0xd5, 0xbd, 0x28, 0xe0, 0xcb, 0x2c, 0x3a, 0xea, 0xca, 0x88, 0xf1, 0x31, 0x6d, + 0x93, 0x71, 0x88, 0xda, 0x59, 0xbd, 0x1a, 0xe9, 0xa6, 0x3a, 0x43, 0x1b, 0x28, 0x1d, 0x02, 0xf9, + 0xd7, 0xb9, 0xa6, 0x64, 0xaf, 0xa6, 0xff, 0xa2, 0xa7, 0x6b, 0x52, 0x2d, 0x42, 0xc5, 0xf7, 0xa8, + 0x95, 0xba, 0xe6, 0xef, 0x66, 0x6f, 0x2c, 0x58, 0xfc, 0xa4, 0xb1, 0x91, 0x91, 0x62, 0x38, 0xfe, + 0xfc, 0xb3, 0x13, 0x19, 0xc0, 0xf3, 0x5f, 0x56, 0x8a, 0xc6, 0xd3, 0xf1, 0x2a, 0x31, 0x5c, 0x53, + 0xf0, 0x9c, 0x81, 0x4b, 0x48, 0x93, 0x26, 0x61, 0x88, 0x3a, 0x73, 0x27, 0x75, 0x2f, 0x75, 0x5f, + 0x18, 0xeb, 0x7e, 0xd3, 0x4d, 0xeb, 0xa3, 0xec, 0x65, 0x30, 0x18, 0x52, 0x87, 0xff, 0xbb, 0x1c, + 0xb3, 0x7e, 0xf5, 0x6f, 0x14, 0x64, 0x4e, 0xe1, 0xe4, 0x4f, 0x77, 0xc2, 0xbb, 0x56, 0x28, 0xb4, + 0x0e, 0x82, 0xc2, 0x47, 0xaf, 0x3b, 0x7f, 0x23, 0x75, 0x9f, 0xe8, 0x00, 0xf7, 0xe5, 0xc5, 0x48, + 0x8e, 0x78, 0x12, 0x42, 0x2e, 0x14, 0x18, 0x8e, 0x97, 0x81, 0xa0, 0x8a, 0xd2, 0xd6, 0x83, 0x24, + 0x1a, 0x36, 0x02, 0x5d, 0xf3, 0x4d, 0x3c, 0xf6, 0x18, 0xb8, 0x21, 0x5e, 0xf7, 0xc3, 0xaf, 0x47, + 0xba, 0xf1, 0x7c, 0x71, 0x48, 0x2a, 0xe1, 0xa1, 0xe9, 0xf8, 0xdf, 0x05, 0x41, 0xfc, 0xe7, 0x59, + 0xaa, 0x60, 0xb1, 0x06, 0x13, 0x62, 0xd9, 0x5d, 0x2b, 0x52, 0x4b, 0x98, 0x6a, 0x22, 0x2c, 0x6e, + 0xa2, 0xd6, 0x71, 0xdd, 0xae, 0xbf, 0x02, 0x5f, 0xb5, 0x90, 0xcd, 0xba, 0xfe, 0x3a, 0x98, 0x25, + 0xcb, 0xea, 0x57, 0x2c, 0x52, 0xc3, 0xce, 0xfb, 0x9a, 0xad, 0xf4, 0xdc, 0xb4, 0xfe, 0x1d, 0x93, + 0x56, 0xa1, 0xbf, 0xd2, 0x88, 0x5f, 0x2b, 0x90, 0x91, 0x11, 0x2b, 0xf8, 0x23, 0x10, 0xee, 0xa4, + 0xe5, 0x24, 0x3e, 0x22, 0x82, 0x92, 0xa4, 0x40, 0x04, 0x87, 0x5e, 0xea, 0x59, 0x3d, 0xa3, 0x73, + 0x50, 0x6f, 0xfd, 0x3e, 0x07, 0xca, 0x39, 0xf3, 0x8f, 0xa6, 0xef, 0x9a, 0x5b, 0xc9, 0x32, 0x7f, + 0xc8, 0x12, 0x1f, 0x83, 0xae, 0xca, 0x2b, 0x84, 0xb6, 0x92, 0x9b, 0x8e, 0xf4, 0xca, 0x70, 0xc5, + 0x7e, 0xea, 0xb8, 0x11, 0xf3, 0x7e, 0x20, 0xec, 0x7c, 0x26, 0xf6, 0x5c, 0x23, 0xca, 0x57, 0x18, + 0xbb, 0xdd, 0xd9, 0x95, 0xcd, 0x30, 0x49, 0xcb, 0x49, 0xf1, 0x69, 0x9f, 0x34, 0xe9, 0x6f, 0xb3, + 0xc1, 0x4e, 0x66, 0x03, 0xa9, 0x69, 0xc7, 0xe8, 0x5e, 0x00, 0x9e, 0xb7, 0xab, 0x23, 0x2f, 0x11, + 0x19, 0x25, 0x09, 0xea, 0x79, 0x65, 0x64, 0x46, 0x98, 0xd6, 0x51, 0x1e, 0x46, 0x35, 0x7a, 0x91, + 0x2a, 0x2c, 0x97, 0x62, 0xfe, 0x17, 0xd2, 0x36, 0x4e, 0x2e, 0xf5, 0x73, 0x28, 0xda, 0xdd, 0xf8, + 0x1e, 0x67, 0xa8, 0xb9, 0x47, 0x46, 0x86, 0xe5, 0x2d, 0x0b, 0xac, 0x99, 0x5f, 0x8e, 0x64, 0xe1, + 0x4c, 0x0a, 0x57, 0x9e, 0x85, 0x43, 0xd5, 0xe9, 0x6e, 0x43, 0xfa, 0x4d, 0x10, 0x1e, 0xa5, 0xa0, + 0xa1, 0xa4, 0x7b, 0x70, 0xe9, 0xb7, 0x60, 0xa0, 0x2c, 0x78, 0x11, 0x18, 0x9b, 0x7f, 0x78, 0x85, + 0x09, 0x4c, 0x2f, 0x13, 0xf1, 0x4a, 0x82, 0xa0, 0xaa, 0x5a, 0x76, 0x60, 0x9f, 0x6c, 0x76, 0x85, + 0x58, 0x0f, 0x48, 0x8f, 0xa5, 0x6f, 0x8b, 0xd8, 0x74, 0xd6, 0xe3, 0xe2, 0x82, 0xa0, 0xb6, 0x9a, + 0x72, 0xb8, 0x19, 0x40, 0x4f, 0xf1, 0x08, 0x31, 0x4a, 0xca, 0x70, 0x44, 0xec, 0x8a, 0xa4, 0x61, + 0x0b, 0x2e, 0xb8, 0x82, 0x39, 0x75, 0x83, 0x87, 0x6b, 0x3e, 0x4c, 0x1c, 0x2c, 0x46, 0x88, 0xe7, + 0xd7, 0x55, 0xdd, 0xe5, 0x45, 0x7a, 0xe5, 0xed, 0xe0, 0x2e, 0x6b, 0xe8, 0xac, 0xae, 0xf1, 0x72, + 0x46, 0x36, 0x64, 0x08, 0x47, 0x55, 0xef, 0x32, 0x50, 0x94, 0x08, 0xcc, 0x49, 0xc2, 0xf2, 0x75, + 0x82, 0xdc, 0x3a, 0x30, 0x9a, 0x4b, 0x71, 0xe4, 0x0f, 0x01, 0x6e, 0xaa, 0x66, 0x59, 0xb6, 0x7e, + 0x3f, 0xbb, 0xa3, 0x45, 0xbc, 0xa8, 0x6c, 0xf6, 0xf3, 0x5f, 0x08, 0xab, 0x81, 0x67, 0xde, 0x12, + 0x3a, 0xf9, 0xe8, 0x6a, 0x5c, 0xd4, 0x1f, 0x2b, 0xff, 0xa1, 0x8f, 0x90, 0xf2, 0x9d, 0x35, 0x1d, + 0xa9, 0xa2, 0xa2, 0x90, 0x89, 0x53, 0x3c, 0x6e, 0x48, 0x41, 0x8d, 0x0e, 0xdb, 0x5d, 0x21, 0x90, + 0xbd, 0x6a, 0x4e, 0x6e, 0x4e, 0xf8, 0xdb, 0xb4, 0x17, 0xc9, 0xd8, 0x63, 0xca, 0xb3, 0x5b, 0xa9, + 0x74, 0x10, 0x26, 0x62, 0x08, 0xc8, 0x5e, 0x1f, 0x42, 0x09, 0x08, 0xdf, 0x00, 0x5d, 0xe3, 0x8a, + 0x05, 0xc0, 0x11, 0xda, 0x2c, 0x9f, 0x5a, 0x9a, 0x49, 0xbd, 0xcf, 0xd2, 0x9c, 0xa0, 0xda, 0xdd, + 0xea, 0xd8, 0x38, 0x96, 0xfb, 0x57, 0x91, 0xab, 0xf1, 0x3a, 0xaf, 0x90, 0xde, 0x0b, 0xa9, 0x0b, + 0xd0, 0xbf, 0xd2, 0x6b, 0x20, 0x9d, 0xe8, 0x6e, 0x79, 0x86, 0x90, 0x78, 0x5a, 0xbd, 0x0e, 0xee, + 0x8a, 0x6a, 0xba, 0x90, 0x59, 0x67, 0x8f, 0xc3, 0x52, 0xb1, 0x6b, 0xd7, 0xfd, 0xe9, 0x97, 0xfa, + 0xac, 0x5b, 0x21, 0x71, 0xd9, 0xbf, 0xa1, 0xf0, 0xd3, 0xdb, 0x8e, 0xa6, 0x92, 0xfe, 0x68, 0xb6, + 0x93, 0xc4, 0x73, 0xe8, 0xcb, 0x96, 0x4e, 0xeb, 0x51, 0xc1, 0x45, 0x0a, 0x56, 0xe5, 0x2d, 0xbb, + 0x49, 0x02, 0x96, 0x5c, 0x62, 0x2a, 0x9d, 0xd3, 0x81, 0x69, 0xc2, 0x3e, 0x47, 0x76, 0x0e, 0x2e, + 0xea, 0xb2, 0x33, 0x5b, 0x1a, 0x9f, 0x46, 0x23, 0x2e, 0x3f, 0xbf, 0x4a, 0x54, 0xc7, 0x63, 0x5a, + 0x23, 0xd9, 0x1e, 0xd2, 0xc2, 0xad, 0x4d, 0x0b, 0xd4, 0x90, 0xd6, 0x1c, 0xc3, 0xca, 0x68, 0xfb, + 0xd8, 0x5d, 0x9b, 0xde, 0xbd, 0x45, 0x6c, 0x6e, 0x7d, 0x2c, 0x21, 0x26, 0xf1, 0xa9, 0x46, 0x52, + 0x1d, 0xe9, 0xa6, 0x5f, 0x78, 0x57, 0x2f, 0xe3, 0x45, 0xc8, 0xf6, 0xb6, 0xfb, 0xe4, 0x37, 0x1b, + 0x4c, 0x22, 0x53, 0x87, 0x17, 0x37, 0x6f, 0x22, 0x69, 0x11, 0xf1, 0x2b, 0xf5, 0xd5, 0xc9, 0xd0, + 0x49, 0xbc, 0xb3, 0xd1, 0x3f, 0x81, 0xf8, 0xbf, 0x23, 0x13, 0x84, 0xb6, 0xd7, 0x2d, 0x00, 0xb0, + 0x14, 0xe2, 0xc4, 0xb5, 0xe4, 0x94, 0x5b, 0x56, 0x24, 0x6a, 0xe6, 0xc7, 0xd3, 0x7a, 0x73, 0xb3, + 0xc1, 0xbf, 0x82, 0x21, 0x2c, 0x3e, 0xaf, 0x59, 0xe9, 0x0c, 0x7e, 0x8f, 0xd3, 0x88, 0xea, 0x1d, + 0xd3, 0x37, 0x63, 0x4f, 0xad, 0xb1, 0xf4, 0xb4, 0xf9, 0x78, 0xde, 0xae, 0x97, 0x0c, 0x6d, 0x6b, + 0xbf, 0x8e, 0x39, 0x11, 0x20, 0xae, 0xa7, 0xb4, 0xa8, 0x51, 0x1b, 0xa2, 0x59, 0x4f, 0x5d, 0xb7, + 0x32, 0x7f, 0x98, 0x9e, 0x9d, 0x3c, 0x9d, 0x3b, 0x03, 0x58, 0x14, 0xdb, 0x09, 0xa3, 0xa5, 0x43, + 0x48, 0xb5, 0x82, 0xf6, 0x8e, 0x30, 0x76, 0x2f, 0x1e, 0x7b, 0xcd, 0xeb, 0x1e, 0x9b, 0x8b, 0x26, + 0x4d, 0x2f, 0xad, 0x02, 0x58, 0x88, 0x05, 0x48, 0x15, 0xcb, 0xae, 0x51, 0x5a, 0x25, 0xef, 0x77, + 0xad, 0x75, 0xb7, 0xfb, 0xa1, 0xd6, 0xb5, 0x5f, 0x4e, 0x6b, 0xb1, 0x91, 0x47, 0x8c, 0xa2, 0xb0, + 0x17, 0x9a, 0x0d, 0x77, 0xac, 0x9d, 0xe1, 0x18, 0xe9, 0xde, 0x4f, 0x78, 0x52, 0x8c, 0x8d, 0xcc, + 0x5f, 0xd7, 0xba, 0x1b, 0x75, 0x4f, 0x29, 0xb4, 0xb5, 0x96, 0x35, 0x37, 0xa4, 0xd6, 0x4c, 0x2f, + 0x73, 0xf3, 0x67, 0x2c, 0x40, 0x37, 0x56, 0x08, 0x72, 0x4d, 0xd7, 0x13, 0x99, 0x2b, 0x22, 0xf9, + 0xb9, 0x8f, 0x2d, 0x5d, 0xca, 0x2b, 0xea, 0x18, 0x81, 0xdc, 0x4d, 0x0b, 0x62, 0x22, 0x80, 0x84, + 0xf4, 0x88, 0x9b, 0x0a, 0xc2, 0xe3, 0xa3, 0x1a, 0x59, 0xad, 0xd1, 0x36, 0xd2, 0x84, 0xba, 0xbf, + 0xb0, 0xe5, 0x44, 0x09, 0xcf, 0x58, 0x2f, 0xef, 0x28, 0x29, 0x23, 0x3d, 0x95, 0xaa, 0x50, 0x54, + 0xa3, 0x02, 0x97, 0x6a, 0x0f, 0xe3, 0x8d, 0xda, 0x96, 0xe0, 0x47, 0x9b, 0x8d, 0x8c, 0xc1, 0xf5, + 0x83, 0x32, 0xe6, 0x40, 0x25, 0xa7, 0x80, 0x3f, 0x0b, 0x6f, 0x53, 0xcc, 0xf4, 0xe7, 0xd1, 0xae, + 0x9f, 0xf3, 0x54, 0xd2, 0x7e, 0xed, 0x6f, 0x81, 0x02, 0x1b, 0x3b, 0x4c, 0x50, 0xb5, 0x2f, 0xa4, + 0xa0, 0x21, 0x87, 0x57, 0xfe, 0x3a, 0x9e, 0x95, 0xda, 0xe5, 0xfb, 0x8f, 0xa1, 0xdc, 0xb3, 0xd3, + 0x09, 0x70, 0xbc, 0x7b, 0x49, 0xb1, 0xce, 0x65, 0x4a, 0xde, 0x8c, 0xd2, 0x81, 0x76, 0x48, 0xdd, + 0x25, 0x9d, 0x73, 0x95, 0xfd, 0x23, 0xbc, 0x2e, 0x12, 0x1c, 0xff, 0x9e, 0xb9, 0xbc, 0x45, 0x9c, + 0x7f, 0x36, 0x7d, 0xbb, 0x6c, 0xab, 0x36, 0x59, 0x5d, 0x37, 0xc0, 0xe2, 0xca, 0xf9, 0xce, 0x2e, + 0xaf, 0x22, 0xc0, 0xc9, 0xb9, 0xad, 0xed, 0xa7, 0x74, 0xd0, 0x78, 0x2b, 0x74, 0xaa, 0x24, 0x7c, + 0x64, 0xe6, 0x66, 0xeb, 0x49, 0x34, 0x8f, 0x73, 0x05, 0x17, 0x43, 0x36, 0xb7, 0x0a, 0x00, 0xa6, + 0x0d, 0x2d, 0xea, 0x64, 0xcc, 0x71, 0xb7, 0xdb, 0x4b, 0xd0, 0xd7, 0x18, 0xc2, 0x12, 0xd9, 0xe4, + 0x63, 0x25, 0x14, 0x53, 0x9a, 0x78, 0x25, 0xc5, 0x71, 0x8b, 0x2d, 0xb3, 0xe2, 0xfe, 0x35, 0xee, + 0xf1, 0xf6, 0x8f, 0xe0, 0x52, 0x6c, 0xcf, 0x79, 0x90, 0xb3, 0xa2, 0x8e, 0xc6, 0x26, 0xfa, 0x96, + 0xce, 0x0b, 0xd5, 0xe0, 0x5c, 0xb2, 0x5c, 0xe8, 0x21, 0xb2, 0xcf, 0x03, 0xfc, 0xac, 0xa2, 0xb7, + 0xef, 0xfe, 0xf0, 0x8b, 0xf2, 0x4e, 0xc6, 0xf0, 0xed, 0x10, 0x18, 0xc4, 0x96, 0x87, 0x06, 0x72, + 0x46, 0x5a, 0x82, 0x67, 0xb4, 0x9b, 0x00, 0x88, 0x17, 0x9e, 0x2c, 0x69, 0xd1, 0x66, 0xd1, 0x81, + 0x03, 0xb2, 0x9b, 0x6d, 0x7c, 0x5e, 0xbf, 0x30, 0x72, 0x62, 0x39, 0x01, 0x97, 0x64, 0x81, 0x45, + 0x52, 0x71, 0x99, 0xdf, 0x92, 0xa6, 0x99, 0xec, 0xfa, 0x7d, 0x07, 0x97, 0x8b, 0x4a, 0xdb, 0x4e, + 0xd3, 0x96, 0xd0, 0xd9, 0x8c, 0x4a, 0x9e, 0x5b, 0x38, 0x63, 0x7e, 0xfb, 0xda, 0xdd, 0x66, 0x87, + 0xa9, 0xfb, 0x28, 0x82, 0x28, 0xc3, 0x6f, 0x66, 0x22, 0x8f, 0xa1, 0xa7, 0xee, 0xd4, 0x55, 0xb1, + 0xe7, 0x7f, 0x36, 0xfd, 0x56, 0xf9, 0x69, 0x67, 0xd4, 0xef, 0x3c, 0xb6, 0x19, 0x92, 0x23, 0x20, + 0xca, 0x1d, 0xde, 0x45, 0xdb, 0xbd, 0x0d, 0xb8, 0x31, 0x8f, 0x15, 0x1c, 0x8e, 0xe1, 0xfc, 0xa2, + 0xc0, 0xf1, 0xbf, 0xae, 0x35, 0x4f, 0x88, 0x92, 0x89, 0x8e, 0xae, 0x82, 0x85, 0xef, 0xe3, 0xc7, + 0xe4, 0x6a, 0xb9, 0x33, 0x39, 0xa8, 0x9f, 0x06, 0x2b, 0x91, 0xb7, 0x0c, 0xf4, 0x13, 0x91, 0xaa, + 0x96, 0x70, 0xf6, 0x2d, 0xb6, 0x3d, 0x14, 0xcf, 0x09, 0x5f, 0xd7, 0x86, 0x30, 0x37, 0xfe, 0xfb, + 0x8e, 0x88, 0xb3, 0xde, 0x31, 0x9d, 0x94, 0x8c, 0x76, 0xb0, 0x91, 0x04, 0xc2, 0xd6, 0x0a, 0x11, + 0x3b, 0xda, 0xda, 0x28, 0x59, 0x3c, 0x4d, 0x95, 0xf4, 0xbc, 0x25, 0x55, 0x15, 0x3b, 0xe6, 0x84, + 0x56, 0x15, 0x07, 0xfd, 0x1b, 0x4b, 0x11, 0x28, 0x02, 0x8b, 0xcb, 0x43, 0xd6, 0x81, 0x59, 0xbe, + 0xe7, 0x99, 0xe5, 0x64, 0x00, 0x8b, 0xa4, 0x2b, 0x57, 0x9c, 0x08, 0x6d, 0x99, 0xc4, 0x89, 0x24, + 0xe1, 0x04, 0xb4, 0x96, 0x90, 0x4f, 0x51, 0x4b, 0xe4, 0xb5, 0x41, 0x67, 0x46, 0xe6, 0x56, 0xec, + 0x8c, 0x4a, 0x67, 0x8f, 0xd4, 0x32, 0x17, 0x26, 0xbf, 0xc9, 0x36, 0x0d, 0x52, 0x61, 0xc8, 0xea, + 0xd3, 0x7b, 0xb1, 0xd1, 0x37, 0x5f, 0xeb, 0xa0, 0x6e, 0x6a, 0x88, 0x5e, 0x08, 0xe2, 0x72, 0x5a, + 0xb0, 0xcb, 0x88, 0x13, 0x50, 0xbe, 0x95, 0x8e, 0xb4, 0xa2, 0x43, 0x68, 0x79, 0x08, 0x13, 0x03, + 0x48, 0xcf, 0xe4, 0x99, 0xae, 0xb2, 0x1b, 0x76, 0x4c, 0x5b, 0xbd, 0x45, 0xae, 0xdc, 0x0f, 0x25, + 0x9f, 0xe9, 0xac, 0x35, 0xa7, 0x97, 0x61, 0x84, 0xa0, 0x0f, 0x3b, 0x50, 0x7d, 0x9e, 0x0c, 0xa7, + 0xa2, 0x79, 0xa3, 0x57, 0xb3, 0x52, 0x40, 0xc2, 0xb5, 0x09, 0xd5, 0x57, 0x75, 0xaa, 0xa7, 0x4f, + 0x1e, 0x60, 0x5a, 0x74, 0x8a, 0xc0, 0xcf, 0xc6, 0x21, 0xab, 0xa1, 0x3a, 0x1d, 0xfa, 0xa4, 0x15, + 0x03, 0xa5, 0xab, 0x46, 0xbf, 0x81, 0x12, 0x22, 0x51, 0xf3, 0x5e, 0x75, 0x4c, 0xdd, 0xae, 0xbc, + 0x91, 0xd8, 0xf6, 0x63, 0xb2, 0x45, 0xd3, 0xc8, 0xa9, 0x4a, 0xe9, 0xbc, 0x41, 0x71, 0xb5, 0x70, + 0x0c, 0x2b, 0x5f, 0xb7, 0x4e, 0x9b, 0x34, 0xce, 0xbd, 0x23, 0x37, 0x84, 0xd4, 0x2e, 0xfb, 0xd3, + 0xaf, 0xde, 0xdf, 0x95, 0xc5, 0x1a, 0xb0, 0xdf, 0x02, 0xf5, 0xd6, 0xfa, 0x75, 0x53, 0xfb, 0x9d, + 0xe8, 0xf6, 0xa3, 0xb2, 0xf3, 0xe0, 0x06, 0x9f, 0x4f, 0xfe, 0x3b, 0x39, 0xc9, 0x04, 0x7a, 0x63, + 0x46, 0x03, 0x5a, 0x15, 0x0f, 0xf6, 0x6b, 0x7f, 0xc0, 0x1c, 0x9b, 0x57, 0xdc, 0x62, 0x64, 0xe2, + 0xbf, 0x67, 0x2e, 0xb8, 0xe9, 0x1d, 0xd3, 0x73, 0x95, 0xcc, 0x4b, 0xa2, 0xb9, 0x80, 0x98, 0x42, + 0x28, 0xff, 0xce, 0xf1, 0x9c, 0x09, 0xe1, 0x06, 0xa2, 0x21, 0x80, 0xaa, 0xa1, 0x7e, 0xad, 0x67, + 0x03, 0xb5, 0xc6, 0x6f, 0x22, 0x0b, 0x48, 0xf0, 0xbb, 0x1e, 0xab, 0x11, 0x85, 0x99, 0xa3, 0xca, + 0x35, 0x31, 0x46, 0x0e, 0x46, 0x5f, 0xa1, 0x16, 0xeb, 0x31, 0x0e, 0x4b, 0x5e, 0xd0, 0xc7, 0x73, + 0xac, 0x94, 0x8f, 0x5b, 0x64, 0x29, 0xef, 0x0f, 0x4a, 0x46, 0xd1, 0xc7, 0xf0, 0x52, 0x11, 0x8c, + 0x0d, 0x33, 0x3c, 0x00, 0x49, 0x84, 0xf2, 0xd6, 0x9f, 0x69, 0x39, 0xfd, 0x14, 0x0b, 0x32, 0x73, + 0xe7, 0xdb, 0xed, 0xe8, 0x52, 0xaf, 0xbc, 0x8d, 0x20, 0xda, 0x9a, 0x58, 0xc2, 0x4b, 0x80, 0x6b, + 0x5f, 0x64, 0x55, 0xf2, 0x9b, 0xa9, 0x27, 0x4d, 0x0d, 0x31, 0x9b, 0x07, 0xff, 0x4f, 0x37, 0x77, + 0xa4, 0xdd, 0x7d, 0xf9, 0xd5, 0x00, 0xdd, 0x1d, 0xd9, 0xb6, 0xcf, 0xbb, 0x64, 0x03, 0x07, 0xe9, + 0xb9, 0x9b, 0x98, 0x25, 0x5d, 0x08, 0x6b, 0xf4, 0x69, 0x25, 0xeb, 0x1b, 0x22, 0x7b, 0x90, 0x14, + 0xdf, 0x52, 0xc6, 0x02, 0xdc, 0xaa, 0xa7, 0x17, 0x36, 0x45, 0xca, 0xac, 0x88, 0xa3, 0x0b, 0x76, + 0xd7, 0xbe, 0xe9, 0x41, 0xec, 0x85, 0x68, 0x79, 0xa4, 0xf9, 0x62, 0x30, 0xcb, 0x94, 0x3e, 0xf9, + 0x52, 0x0f, 0x49, 0x62, 0xcf, 0xdb, 0xf8, 0x5c, 0xbf, 0xf3, 0x88, 0xb7, 0xd2, 0xd6, 0x5f, 0xc3, + 0xd7, 0x23, 0xdf, 0x59, 0x0d, 0x8d, 0xec, 0x38, 0x26, 0x9d, 0x6f, 0x18, 0x10, 0x0d, 0x5d, 0xb9, + 0x59, 0x29, 0x22, 0xb1, 0x33, 0x42, 0x0a, 0x44, 0xa0, 0x7d, 0xb0, 0x21, 0x73, 0x3b, 0xe1, 0x91, + 0xbc, 0x29, 0x4b, 0xb3, 0x0d, 0x53, 0x4d, 0x65, 0xd4, 0x03, 0x3c, 0x52, 0x61, 0xb5, 0x7f, 0xe1, + 0x0f, 0x09, 0x65, 0xdf, 0x84, 0x91, 0x9a, 0x51, 0xd7, 0x06, 0xa3, 0x9a, 0x1f, 0xd8, 0x8a, 0x4c, + 0x83, 0x53, 0xb6, 0xc3, 0xd7, 0xbb, 0x51, 0xff, 0xe9, 0x7f, 0xe3, 0x36, 0x9d, 0x77, 0xee, 0xce, + 0x96, 0xd0, 0xf3, 0xfb, 0x5c, 0x55, 0xe0, 0xe0, 0x1d, 0xd3, 0x8b, 0x1c, 0xf0, 0xf8, 0x30, 0xab, + 0x33, 0x8f, 0x35, 0x3a, 0xaa, 0xe6, 0x9c, 0x9f, 0x3d, 0x28, 0x8e, 0xa9, 0x2d, 0xbb, 0x11, 0x5e, + 0x0d, 0x8d, 0x39, 0xe5, 0xcb, 0xda, 0xab, 0xd1, 0x32, 0xd3, 0x2f, 0x39, 0x8e, 0x4f, 0x43, 0x80, + 0xe0, 0xe1, 0x2c, 0xc4, 0x18, 0x81, 0x5e, 0xdd, 0x26, 0x74, 0x96, 0x9d, 0x59, 0x13, 0x06, 0x2a, + 0x5a, 0x66, 0xe3, 0xc8, 0xd1, 0xb3, 0xdc, 0xdf, 0x85, 0x87, 0x13, 0x49, 0x99, 0x62, 0xad, 0xd4, + 0x2e, 0xd2, 0x1b, 0xea, 0x22, 0xbe, 0xde, 0x19, 0x39, 0xbd, 0xee, 0x60, 0x12, 0x90, 0x40, 0xc9, + 0x15, 0xad, 0x48, 0xd3, 0x6c, 0x17, 0x5b, 0x30, 0x68, 0x6c, 0xa0, 0x5d, 0x6a, 0x9d, 0xff, 0xe4, + 0x91, 0x43, 0x92, 0xd1, 0x45, 0xb8, 0x7d, 0x8b, 0x9c, 0xf5, 0xd7, 0xbd, 0xfd, 0x2f, 0x5b, 0xc5, + 0xba, 0x01, 0x9e, 0xb3, 0x9e, 0x96, 0x1d, 0x0f, 0x82, 0x0e, 0x2e, 0x49, 0x2e, 0x0d, 0x9a, 0xd7, + 0x2d, 0xfb, 0xb0, 0xbf, 0x5a, 0x04, 0xeb, 0xfa, 0xe5, 0x4c, 0x37, 0xb7, 0x8b, 0xfa, 0x59, 0x65, + 0xba, 0xd6, 0xa3, 0x39, 0xfa, 0xc5, 0x1d, 0xbb, 0xb7, 0x85, 0x85, 0x38, 0x3c, 0xc8, 0xa3, 0x92, + 0x5e, 0xfa, 0x7d, 0x62, 0xcb, 0xe5, 0xe3, 0x55, 0x33, 0xe4, 0x35, 0xd3, 0x6b, 0xa1, 0x5a, 0x29, + 0x3b, 0x07, 0x70, 0x35, 0xb5, 0x80, 0xd1, 0x10, 0xbc, 0x0a, 0xb2, 0xf8, 0x36, 0x79, 0x50, 0x8d, + 0x69, 0x44, 0x8c, 0x4d, 0x5b, 0x94, 0xcc, 0xe6, 0xdc, 0xf2, 0x56, 0x28, 0xf7, 0xd7, 0xb3, 0x3f, + 0x08, 0x78, 0x44, 0xcd, 0x76, 0x87, 0xef, 0x9d, 0x67, 0x6c, 0xf2, 0x03, 0x6e, 0x32, 0x6c, 0x6a, + 0xce, 0xf8, 0xf5, 0x82, 0xbb, 0x84, 0x04, 0xd1, 0x61, 0x0f, 0xd8, 0x81, 0xf9, 0x6b, 0x68, 0x91, + 0x3a, 0xc7, 0x92, 0x38, 0x67, 0x70, 0xd5, 0xc3, 0xc7, 0xc7, 0xbb, 0x92, 0x7c, 0x89, 0x26, 0xa6, + 0x91, 0xf4, 0xa3, 0xcf, 0x3a, 0xda, 0xda, 0xec, 0x47, 0x1a, 0xe6, 0xef, 0x9e, 0xd5, 0x9d, 0xa2, + 0x59, 0xf7, 0x5f, 0xd9, 0xcb, 0xf6, 0xd3, 0xef, 0x53, 0x99, 0x9b, 0xc0, 0x3b, 0xa6, 0x37, 0xe7, + 0xed, 0xd5, 0x7a, 0xdd, 0xc8, 0x31, 0xc9, 0x76, 0x8a, 0xc4, 0x2b, 0xb4, 0xf0, 0x3a, 0x1c, 0x77, + 0xc5, 0x37, 0x64, 0x3c, 0xb8, 0xcc, 0xfe, 0x3e, 0xed, 0x4a, 0x97, 0xe8, 0x68, 0x54, 0x93, 0xec, + 0xc5, 0xe7, 0x91, 0x91, 0x42, 0x5f, 0x4d, 0x7e, 0x3e, 0x8b, 0x9f, 0x50, 0x15, 0x5e, 0xab, 0x5d, + 0x30, 0xa5, 0x1a, 0xed, 0x3c, 0x37, 0xa5, 0x9d, 0xdd, 0x88, 0xf3, 0xa6, 0x27, 0x29, 0xc0, 0x55, + 0x47, 0x8b, 0x7d, 0x1b, 0x4d, 0xdf, 0x68, 0xb1, 0xb1, 0xbd, 0x3b, 0x67, 0xdb, 0x4b, 0x53, 0x37, + 0x31, 0x25, 0xde, 0xe5, 0xde, 0xd7, 0x03, 0xa1, 0xba, 0xc8, 0xf9, 0xf5, 0xc6, 0x24, 0x93, 0x57, + 0xa7, 0xa5, 0x4c, 0x63, 0x51, 0x54, 0x89, 0x8c, 0x5b, 0x52, 0xcc, 0x24, 0x0d, 0x99, 0xa4, 0x84, + 0x10, 0x91, 0xfd, 0x79, 0x36, 0x16, 0xe2, 0x61, 0x23, 0x5d, 0xed, 0x84, 0xba, 0xa9, 0x56, 0x68, + 0xe3, 0xf2, 0x9e, 0x64, 0xa1, 0xa5, 0xd7, 0xbd, 0x69, 0xa6, 0x8f, 0xb5, 0xad, 0xb7, 0x60, 0x3c, + 0xd3, 0x9f, 0xe3, 0xc5, 0xb5, 0xe2, 0xf4, 0x29, 0x42, 0xce, 0xf4, 0x33, 0x36, 0x95, 0xbe, 0x3c, + 0x68, 0xde, 0xdf, 0x88, 0xb6, 0xfd, 0x6d, 0x96, 0xc5, 0x3a, 0x90, 0x89, 0xb8, 0xe0, 0x53, 0x94, + 0xb5, 0xb8, 0x89, 0xe3, 0x52, 0xa6, 0x13, 0x90, 0x31, 0x57, 0x81, 0xcb, 0x93, 0x03, 0x5e, 0x2e, + 0xe6, 0x44, 0x87, 0x08, 0x56, 0x25, 0x4a, 0xd6, 0xa7, 0xb3, 0x7c, 0x2d, 0x13, 0xd4, 0x15, 0x44, + 0x71, 0x5b, 0xbb, 0x5d, 0x18, 0xb6, 0xd4, 0x54, 0x25, 0x7e, 0x7d, 0xc2, 0x9e, 0x44, 0x25, 0x14, + 0x52, 0xb4, 0x05, 0x12, 0x79, 0x59, 0x49, 0x19, 0x18, 0xe3, 0x47, 0x87, 0x91, 0x2e, 0x2b, 0xe1, + 0x23, 0xc5, 0xa3, 0xcb, 0x1e, 0x72, 0x2b, 0xe6, 0x08, 0x87, 0x93, 0x7e, 0x09, 0xa3, 0xad, 0x76, + 0xe4, 0x74, 0xac, 0xd0, 0x0d, 0x0d, 0x15, 0x14, 0xa5, 0xad, 0x8f, 0xb9, 0x18, 0xfe, 0x3c, 0x5d, + 0x9b, 0x16, 0x69, 0x77, 0xad, 0x48, 0xf5, 0x9c, 0xbf, 0xf7, 0x5c, 0x09, 0xbd, 0x63, 0x9a, 0xdb, + 0xe6, 0x48, 0x2e, 0xe1, 0x69, 0xe4, 0x47, 0xea, 0x45, 0x4a, 0xa6, 0x3c, 0x6c, 0xb0, 0x43, 0x46, + 0xa0, 0x5c, 0xce, 0xe9, 0xa7, 0x78, 0x55, 0x61, 0xef, 0x2d, 0xc1, 0x0e, 0x2a, 0x39, 0x62, 0xb4, + 0xee, 0x6d, 0x25, 0x4a, 0x9a, 0x40, 0xb0, 0x52, 0x1e, 0x7b, 0x5b, 0xd5, 0x51, 0xeb, 0x30, 0x55, + 0xee, 0x59, 0x5f, 0x28, 0x8d, 0x2d, 0x98, 0x94, 0x54, 0xc2, 0xd6, 0x66, 0x6a, 0x03, 0x10, 0xc2, + 0x69, 0xb6, 0x3e, 0x7e, 0xd1, 0xdc, 0xba, 0x7e, 0x05, 0x69, 0xe3, 0xd7, 0xa7, 0x9f, 0x95, 0x01, + 0x2f, 0x1c, 0xfc, 0x54, 0xc2, 0x21, 0xf3, 0xe4, 0x06, 0x7d, 0xe9, 0xce, 0x84, 0xed, 0xb1, 0x16, + 0xbb, 0x37, 0x8e, 0x83, 0xb2, 0x42, 0xbe, 0xb5, 0x33, 0x29, 0xf1, 0x34, 0x7b, 0x37, 0xf6, 0xd2, + 0xfe, 0x7f, 0x77, 0xf8, 0x54, 0x9d, 0xf4, 0x8f, 0x63, 0x47, 0x50, 0x25, 0x06, 0x35, 0x3c, 0x3b, + 0x75, 0x97, 0x1b, 0xa1, 0xa5, 0x42, 0x7c, 0xa6, 0xa2, 0xaf, 0xfa, 0x5a, 0x2f, 0x19, 0xa9, 0x71, + 0xad, 0x6e, 0x74, 0x22, 0x1a, 0x35, 0xda, 0x40, 0x42, 0x0b, 0x85, 0x98, 0x22, 0x88, 0x0f, 0x33, + 0x30, 0xd4, 0xae, 0x8c, 0x9c, 0xb6, 0x39, 0x1b, 0x68, 0x81, 0xb5, 0x05, 0x81, 0xab, 0xb9, 0x26, + 0x04, 0x3b, 0xfd, 0xd9, 0xd2, 0xe0, 0xeb, 0x58, 0xd6, 0xcb, 0xf9, 0xdc, 0x4d, 0xab, 0x3d, 0xbe, + 0x9b, 0xbd, 0x09, 0xcb, 0xfd, 0x0b, 0x45, 0x8d, 0x40, 0x4c, 0x5b, 0xe5, 0x7b, 0xc3, 0xcc, 0x8d, + 0x55, 0xde, 0x14, 0xdd, 0x62, 0x9d, 0x4c, 0x36, 0x66, 0xb0, 0x49, 0xa5, 0x6f, 0x49, 0xd5, 0x1f, + 0x0f, 0x62, 0xfb, 0xb8, 0x4b, 0x25, 0x4b, 0xd7, 0xd1, 0x8d, 0x94, 0x46, 0x1e, 0x49, 0x45, 0x6e, + 0x77, 0xa6, 0xc5, 0x74, 0x9f, 0xdf, 0x42, 0x20, 0xbd, 0x5f, 0x0c, 0x8b, 0x01, 0xf8, 0xec, 0x65, + 0xa0, 0x50, 0x1c, 0x46, 0x26, 0xc5, 0x3a, 0x15, 0x9a, 0x43, 0xdd, 0x6b, 0xdd, 0xf4, 0x91, 0x22, + 0x38, 0xb3, 0xe6, 0x4a, 0x24, 0x49, 0xf6, 0x1e, 0xed, 0xff, 0xbd, 0x8f, 0x10, 0xfc, 0x8e, 0x69, + 0xf6, 0x9f, 0xa8, 0x52, 0xba, 0x58, 0x37, 0x08, 0x22, 0x79, 0xfd, 0x5d, 0x6b, 0x29, 0xcc, 0x8b, + 0x97, 0x10, 0xcd, 0xa2, 0x50, 0x1b, 0x6c, 0xd2, 0xdc, 0x69, 0x65, 0xc4, 0x23, 0x15, 0x41, 0xd6, + 0x2f, 0xc7, 0x50, 0x9d, 0x48, 0x16, 0x9a, 0x4a, 0x93, 0xca, 0x40, 0xf9, 0xa4, 0x51, 0xbe, 0xe3, + 0x79, 0xf4, 0x7a, 0x8c, 0xef, 0xf2, 0xb0, 0xbf, 0x5e, 0xda, 0xa4, 0xec, 0x7b, 0xcc, 0xbf, 0xb1, + 0x65, 0x00, 0xfc, 0x9f, 0x36, 0xec, 0xb8, 0x2e, 0xd7, 0x96, 0x5f, 0x06, 0x7a, 0x46, 0x04, 0xaa, + 0x66, 0xd1, 0xfc, 0xe5, 0x38, 0x78, 0x80, 0x23, 0x62, 0xfd, 0x96, 0xd0, 0x04, 0xe9, 0xaa, 0x65, + 0xda, 0xfb, 0x45, 0x54, 0x30, 0x4a, 0x51, 0x1a, 0xde, 0xbb, 0x08, 0x71, 0xb6, 0x9d, 0x07, 0x68, + 0x78, 0x2f, 0xbe, 0xd4, 0xec, 0x50, 0xd7, 0x63, 0x4e, 0x57, 0xb2, 0x4d, 0x6f, 0xca, 0x00, 0x22, + 0x13, 0x0e, 0x9f, 0xba, 0xfc, 0x8c, 0x3c, 0x67, 0x94, 0x64, 0x94, 0x01, 0x40, 0x52, 0xe5, 0xf2, + 0x7d, 0x99, 0x2a, 0xdf, 0x7d, 0x75, 0x12, 0xa8, 0xfe, 0xd5, 0x67, 0xf8, 0xdb, 0x82, 0x7b, 0x64, + 0x4b, 0x58, 0x56, 0x43, 0xa0, 0x58, 0x11, 0x5c, 0x0e, 0xc3, 0x05, 0xf7, 0x63, 0xae, 0x1c, 0xf9, + 0x11, 0x86, 0xf3, 0xc2, 0xfd, 0xca, 0x9c, 0xea, 0x2d, 0x66, 0x75, 0x00, 0xcb, 0xd9, 0xdd, 0x70, + 0xae, 0x90, 0xf8, 0xa3, 0x70, 0x63, 0x7e, 0x3b, 0xb1, 0x8e, 0x74, 0x10, 0xa5, 0xd9, 0x78, 0xda, + 0xa7, 0xdb, 0x55, 0xe1, 0x69, 0x0b, 0xf9, 0x5f, 0x5f, 0x4c, 0xd2, 0x3e, 0x78, 0x79, 0x0c, 0xcd, + 0xd9, 0xfb, 0x57, 0xed, 0x50, 0xd4, 0xc9, 0x9a, 0xd3, 0xe6, 0xf7, 0x12, 0x5f, 0xe6, 0xaa, 0xbd, + 0x07, 0x3a, 0x0a, 0x1e, 0xdb, 0x0a, 0x15, 0xea, 0x8a, 0x36, 0xc7, 0xdc, 0x10, 0xb0, 0xd1, 0x3d, + 0x84, 0x4e, 0x36, 0xad, 0x19, 0xaf, 0x42, 0x22, 0xf8, 0x8a, 0xef, 0xee, 0x12, 0xf1, 0x86, 0x9b, + 0xe2, 0x39, 0xbd, 0x7f, 0xb4, 0xb6, 0x4e, 0x7b, 0x7d, 0x4d, 0xdd, 0x33, 0x42, 0x7e, 0xef, 0xb9, + 0x72, 0xf3, 0x8e, 0xe9, 0x2f, 0xaa, 0xe7, 0x56, 0x83, 0x35, 0x21, 0xc6, 0x58, 0xdf, 0x64, 0xf3, + 0x8b, 0xf1, 0x02, 0x61, 0xf1, 0x76, 0x25, 0x23, 0xb9, 0x27, 0xd0, 0x4e, 0x61, 0x9f, 0x3a, 0x12, + 0xe2, 0x65, 0xac, 0xb3, 0x9f, 0x05, 0xff, 0xe8, 0x16, 0xf7, 0x7f, 0xa4, 0xa3, 0x29, 0x57, 0x50, + 0x79, 0xb0, 0x5e, 0x14, 0xd4, 0xab, 0xb7, 0xa7, 0xa7, 0x43, 0xed, 0x7a, 0x4e, 0xa0, 0xab, 0x70, + 0xac, 0xf2, 0x50, 0x7e, 0xee, 0x7b, 0x93, 0xa8, 0xd2, 0xd8, 0xc0, 0xbf, 0x99, 0xd8, 0xc2, 0xd2, + 0xf0, 0x7c, 0xcd, 0x3d, 0x93, 0x04, 0x1e, 0x8f, 0xa1, 0xa4, 0x55, 0x6f, 0x13, 0xc9, 0xb5, 0xf5, + 0xe7, 0x5e, 0x8d, 0x3e, 0x32, 0x59, 0x1a, 0xe6, 0x23, 0x39, 0xfd, 0x85, 0x61, 0x18, 0xac, 0x82, + 0x60, 0x58, 0xa4, 0xee, 0x64, 0x22, 0xe7, 0xfe, 0x61, 0x5a, 0xe6, 0x0e, 0x84, 0xc7, 0xb2, 0x12, + 0x54, 0x23, 0x91, 0x60, 0x5f, 0x2c, 0x40, 0xfd, 0x7b, 0xad, 0x45, 0x74, 0xff, 0x27, 0xbd, 0x35, + 0xd8, 0xa7, 0x22, 0x70, 0xb9, 0xef, 0xa0, 0x97, 0xb8, 0x71, 0x75, 0xf3, 0x4f, 0x44, 0x99, 0x78, + 0x5b, 0xeb, 0x01, 0x0a, 0x94, 0xef, 0x9f, 0x87, 0x33, 0x48, 0xa4, 0x0c, 0xe9, 0x6c, 0xa3, 0x7b, + 0x8c, 0x4e, 0xf6, 0x9c, 0xa7, 0x89, 0x39, 0xdc, 0x6b, 0x7a, 0x19, 0xa5, 0x9e, 0xc7, 0x16, 0x43, + 0xf9, 0x22, 0x8c, 0xe7, 0x36, 0x2f, 0xe1, 0x79, 0x4b, 0xdc, 0x81, 0x57, 0x46, 0x65, 0x0f, 0xd9, + 0xe7, 0x3e, 0x3a, 0xdd, 0x73, 0x15, 0x5e, 0x93, 0x09, 0xac, 0x3f, 0x36, 0x52, 0x09, 0x99, 0xc2, + 0xf0, 0x78, 0x9b, 0x12, 0xec, 0x4a, 0x90, 0x11, 0x1d, 0x18, 0x9a, 0x16, 0x7a, 0x3e, 0x70, 0xa7, + 0xc4, 0x57, 0x13, 0x93, 0xd7, 0xdb, 0x73, 0xef, 0xdc, 0xad, 0x04, 0x10, 0x13, 0x5a, 0x93, 0x63, + 0x2c, 0x5d, 0xeb, 0xe8, 0x19, 0x6b, 0x15, 0x40, 0xe1, 0xdd, 0x65, 0xf3, 0xc2, 0x8f, 0xdd, 0xfa, + 0xb9, 0x93, 0xd1, 0xe2, 0x96, 0x4d, 0x74, 0x9f, 0x6b, 0xf5, 0x8b, 0x94, 0x73, 0xce, 0x3b, 0xfc, + 0xf7, 0x3e, 0x42, 0x85, 0x77, 0x4c, 0x4b, 0x20, 0xea, 0xa7, 0xbf, 0x20, 0x74, 0x75, 0xa6, 0x5d, + 0x64, 0xc8, 0x77, 0x0c, 0x49, 0x1b, 0xf4, 0x1f, 0x32, 0xb2, 0xdf, 0x0f, 0x8d, 0xc6, 0xd6, 0xd1, + 0x4b, 0xbb, 0x44, 0x99, 0x24, 0xd5, 0x03, 0xc3, 0x6b, 0x88, 0x33, 0x2c, 0x8e, 0x2f, 0x1b, 0x48, + 0x2e, 0xad, 0xa2, 0xd9, 0x1d, 0xf5, 0x14, 0xcf, 0xe7, 0x25, 0x50, 0x41, 0x53, 0x33, 0xcd, 0x4c, + 0xe2, 0x98, 0x92, 0x29, 0xe2, 0x72, 0xa9, 0xb4, 0x62, 0x63, 0x04, 0xdd, 0x67, 0x57, 0x09, 0x41, + 0x74, 0x91, 0x2c, 0xd9, 0xb6, 0x43, 0x39, 0xeb, 0xdf, 0xad, 0x96, 0xae, 0x26, 0xc0, 0x5b, 0xf3, + 0x87, 0xf5, 0x16, 0x1d, 0x3f, 0x1b, 0x5f, 0x53, 0x8c, 0xfc, 0x53, 0x20, 0xf4, 0xb4, 0xd9, 0x38, + 0x59, 0x29, 0x53, 0x5f, 0x31, 0xab, 0xc9, 0xd6, 0xb2, 0x4c, 0x26, 0xf9, 0x06, 0x99, 0xd6, 0xf3, + 0xf4, 0x9a, 0x5a, 0x0c, 0x3d, 0xbb, 0xc8, 0x7e, 0xce, 0x1b, 0xda, 0xc2, 0x4e, 0x2e, 0xf6, 0xe3, + 0x81, 0x42, 0x5f, 0x93, 0xdd, 0xb9, 0xfc, 0xd0, 0x8f, 0x5b, 0xae, 0xc9, 0x16, 0xfd, 0x6a, 0xae, + 0xb5, 0xc0, 0xf8, 0xe8, 0xa8, 0x26, 0x1e, 0xdb, 0xea, 0x21, 0x52, 0xeb, 0x94, 0x4a, 0x50, 0x78, + 0x8f, 0x5a, 0x6a, 0xbe, 0x94, 0xce, 0x26, 0x33, 0x1c, 0x1e, 0x7f, 0x1c, 0xac, 0x7c, 0x8f, 0x77, + 0x33, 0x16, 0xaa, 0x81, 0x15, 0xf5, 0xcf, 0x77, 0x75, 0xa8, 0x3c, 0x68, 0x7c, 0xd4, 0x07, 0x7f, + 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, + 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, + 0x07, 0x1f, 0xfc, 0xdf, 0xe4, 0x7f, 0xef, 0x83, 0xeb, 0xaf, 0x52, 0x09, 0x74, 0x7f, 0x09, 0x6d, + 0x34, 0x10, 0x5a, 0xc7, 0x3b, 0x9e, 0x3a, 0x23, 0x11, 0xce, 0x19, 0xc4, 0xe8, 0x20, 0x7a, 0xe9, + 0xf4, 0x40, 0x76, 0x31, 0x5c, 0x13, 0xdb, 0xd3, 0x50, 0xea, 0x57, 0x54, 0x63, 0x1d, 0x32, 0x84, + 0xc1, 0x7a, 0x36, 0xe1, 0x05, 0x84, 0x18, 0x9a, 0x8a, 0x5f, 0xf4, 0xc4, 0x45, 0x9b, 0x3a, 0xbb, + 0x71, 0x7c, 0xcc, 0xde, 0x21, 0xc2, 0x4e, 0x50, 0x1e, 0x1d, 0xb6, 0xa4, 0x3b, 0x48, 0x56, 0x4f, + 0x65, 0x17, 0x73, 0xdb, 0xd0, 0x5a, 0xff, 0xb9, 0xb5, 0xfd, 0x02, 0x22, 0x16, 0x60, 0x49, 0x1b, + 0xbb, 0x84, 0x43, 0x71, 0x51, 0x30, 0xba, 0x26, 0x38, 0x6d, 0x98, 0x26, 0xaf, 0x8f, 0xc8, 0xe9, + 0xa4, 0xba, 0xef, 0x59, 0xc8, 0x87, 0xad, 0x67, 0x69, 0x65, 0xbe, 0x7c, 0xed, 0x89, 0xb2, 0x48, + 0xb7, 0x77, 0x69, 0xd3, 0xe5, 0x11, 0xeb, 0x0b, 0xb9, 0x63, 0x61, 0x33, 0x5e, 0x3a, 0x22, 0x5e, + 0x12, 0x98, 0xed, 0x64, 0x51, 0x28, 0xc7, 0x7f, 0x20, 0x12, 0xd7, 0xfe, 0x98, 0xb1, 0x25, 0x87, + 0x21, 0xbd, 0x34, 0x81, 0x00, 0x8b, 0x15, 0xbd, 0xfe, 0x6b, 0x54, 0x3c, 0xbe, 0x42, 0x54, 0x6b, + 0xb9, 0xbf, 0x2f, 0x82, 0x9c, 0xd8, 0x61, 0x30, 0xd9, 0xde, 0x8f, 0xb3, 0x70, 0xfb, 0x95, 0x77, + 0x99, 0x4b, 0xc9, 0x7c, 0x87, 0x7d, 0x09, 0x69, 0xf2, 0x66, 0x75, 0xf6, 0x4b, 0xcf, 0x3c, 0xa8, + 0xe5, 0x5f, 0x14, 0x81, 0x7b, 0xef, 0x0c, 0x83, 0x27, 0x39, 0x6f, 0x45, 0x23, 0x79, 0x1f, 0x24, + 0x4d, 0xc9, 0x82, 0x4e, 0x40, 0x26, 0x3a, 0x0f, 0xfa, 0xe9, 0x81, 0x85, 0xa6, 0x50, 0xda, 0x3b, + 0x1b, 0x86, 0x3d, 0xbb, 0x8a, 0x0d, 0x13, 0x77, 0xc7, 0xbb, 0x5c, 0x39, 0x7e, 0x18, 0x1e, 0xc4, + 0xd5, 0xbe, 0xc7, 0xc4, 0x72, 0xfd, 0x9c, 0x96, 0x8a, 0x91, 0xb3, 0x47, 0xbf, 0x8a, 0xd0, 0xfd, + 0x77, 0x53, 0xbe, 0x65, 0xf3, 0x29, 0x0b, 0x9c, 0x1e, 0xb4, 0xc6, 0x18, 0x05, 0xff, 0xe1, 0x3e, + 0xb4, 0x89, 0xf7, 0xcf, 0x77, 0xfc, 0xe7, 0xd1, 0xaf, 0xe9, 0xf9, 0x6c, 0x06, 0x76, 0xfe, 0x81, + 0x51, 0xe6, 0x0e, 0x62, 0x1d, 0x53, 0xce, 0xee, 0x81, 0xd4, 0x35, 0xba, 0xf0, 0xab, 0x4d, 0xce, + 0x1f, 0x37, 0x7c, 0x2a, 0x4a, 0x6f, 0x5a, 0xcf, 0x1e, 0x93, 0xe8, 0xd8, 0x4a, 0xfe, 0xab, 0x58, + 0x44, 0x1f, 0xdb, 0xc8, 0x13, 0x85, 0xb6, 0x58, 0x05, 0x43, 0xa0, 0xb5, 0xf4, 0xeb, 0x3b, 0xd2, + 0x1e, 0x56, 0x4a, 0xb2, 0x20, 0xb7, 0x6c, 0x11, 0x79, 0xb5, 0xf5, 0xe7, 0x57, 0x36, 0x67, 0xe2, + 0xbb, 0xaa, 0x4d, 0xed, 0x16, 0x2f, 0x96, 0xd0, 0x6a, 0xa5, 0x42, 0x9a, 0x06, 0x87, 0x28, 0x09, + 0x75, 0xa6, 0xb2, 0xae, 0xce, 0x1c, 0x4b, 0x91, 0xe4, 0x63, 0xab, 0xd2, 0xa7, 0xbc, 0xad, 0x6f, + 0xbc, 0xa2, 0x37, 0x6e, 0xd2, 0x97, 0x47, 0xaf, 0x6b, 0x69, 0xaa, 0x2a, 0x4d, 0x25, 0xd4, 0x26, + 0xa0, 0xd9, 0x1e, 0x1c, 0x8e, 0x82, 0x7a, 0x04, 0x1a, 0x1c, 0x68, 0x0b, 0x3e, 0x51, 0xa5, 0xaf, + 0x03, 0xcf, 0x42, 0xf5, 0x41, 0xfc, 0xec, 0xaa, 0x16, 0xd9, 0x6f, 0x61, 0x15, 0xc2, 0x58, 0x7a, + 0x4e, 0xa8, 0xaa, 0x68, 0x20, 0x79, 0x7b, 0x58, 0x77, 0x4e, 0x16, 0x8d, 0x0f, 0xd3, 0x64, 0xdc, + 0x07, 0x44, 0xbf, 0xe8, 0x0f, 0xef, 0x27, 0x75, 0xbb, 0x99, 0xd6, 0x15, 0x31, 0xd0, 0xb7, 0xfa, + 0xa2, 0xdb, 0x6f, 0xed, 0x23, 0x2b, 0x55, 0xb3, 0x03, 0x1b, 0x78, 0x1b, 0xcb, 0x5b, 0xd6, 0xbb, + 0xfe, 0x72, 0x21, 0xee, 0xd9, 0x79, 0xc5, 0xa6, 0x60, 0x62, 0xb5, 0x38, 0xc8, 0x8c, 0xe8, 0xca, + 0x24, 0x7e, 0x11, 0x7a, 0x49, 0x6c, 0xb9, 0xc1, 0x42, 0xf9, 0xdc, 0xb3, 0xfc, 0xb6, 0x54, 0x76, + 0x4d, 0x8d, 0x79, 0xeb, 0x43, 0x72, 0x5c, 0xf3, 0x0a, 0x12, 0x89, 0x90, 0x6f, 0xa7, 0x1e, 0xcd, + 0x3c, 0xbe, 0xb2, 0xa7, 0xc5, 0x78, 0x7c, 0xed, 0x06, 0x02, 0xdd, 0xd9, 0xe5, 0x78, 0x17, 0x6d, + 0x7e, 0xa9, 0x79, 0x22, 0x48, 0x7d, 0xfa, 0x4d, 0x8a, 0x85, 0xec, 0x9c, 0xfe, 0x7d, 0xd3, 0xf8, + 0xb5, 0xff, 0x7b, 0x1f, 0x7f, 0xe7, 0xc1, 0x3b, 0xa6, 0x99, 0x79, 0x7a, 0x1b, 0x66, 0x08, 0xb7, + 0x83, 0x6c, 0x00, 0x11, 0xfe, 0x38, 0x45, 0x46, 0xf6, 0xfd, 0xb6, 0x44, 0x82, 0x79, 0x6b, 0x2b, + 0x80, 0xeb, 0x92, 0xde, 0x05, 0xa3, 0x50, 0x16, 0xd0, 0xbb, 0x9c, 0xd2, 0xc9, 0x9b, 0xb2, 0xdd, + 0x1e, 0x59, 0xde, 0x87, 0x0b, 0xb8, 0x56, 0x2a, 0xc6, 0xd5, 0x06, 0x57, 0x90, 0x19, 0x46, 0xf1, + 0xfb, 0x30, 0x3d, 0x0a, 0x3b, 0xc2, 0xd5, 0x7b, 0xf7, 0xd7, 0x16, 0xea, 0xb9, 0x1b, 0xaa, 0xe4, + 0x22, 0x5f, 0xba, 0x9f, 0xb6, 0x35, 0x34, 0x1a, 0x90, 0x70, 0x21, 0x1b, 0x61, 0xc3, 0xd1, 0xd5, + 0x4d, 0x4e, 0xfa, 0xe3, 0x11, 0x83, 0xee, 0x53, 0x68, 0x8f, 0xd0, 0xc9, 0x18, 0xf3, 0xff, 0xab, + 0x13, 0xaa, 0x12, 0xf9, 0x63, 0x6a, 0x0a, 0x66, 0xf0, 0x50, 0x7e, 0x23, 0xbf, 0x4f, 0xc2, 0x06, + 0xc3, 0xdb, 0x53, 0xc4, 0xdf, 0xf6, 0x2f, 0x72, 0x63, 0xb6, 0xbf, 0x4f, 0x58, 0x7f, 0xee, 0x97, + 0x57, 0x09, 0x43, 0x78, 0x7b, 0x2c, 0x6e, 0x67, 0xd2, 0xbb, 0x15, 0x4d, 0xcc, 0x85, 0xac, 0x08, + 0x1c, 0x4e, 0xa5, 0xb8, 0x2c, 0x0f, 0xbc, 0xdc, 0x2c, 0x8d, 0x7c, 0xbb, 0xf5, 0x90, 0xed, 0xfe, + 0x55, 0x8f, 0xd7, 0x87, 0x40, 0x9b, 0xe7, 0x42, 0x52, 0x69, 0x4e, 0x1d, 0x10, 0x75, 0x42, 0x25, + 0x6d, 0xc8, 0x0a, 0x7a, 0x77, 0x9b, 0xb8, 0x1c, 0x10, 0x90, 0x68, 0xd8, 0x9a, 0x6a, 0xa8, 0xc7, + 0xb9, 0x28, 0xa9, 0x8b, 0x1e, 0x27, 0x58, 0x33, 0x1b, 0x91, 0xb1, 0x98, 0x1e, 0xe9, 0x0d, 0x99, + 0x10, 0xc7, 0x65, 0x52, 0x72, 0x4b, 0xdb, 0x74, 0xe0, 0x86, 0x09, 0xd4, 0xaf, 0x33, 0xb7, 0x4f, + 0x3e, 0x7a, 0x3d, 0x19, 0xd1, 0x42, 0x16, 0x73, 0x0f, 0x86, 0xa5, 0x4b, 0x19, 0xaf, 0xbf, 0x82, + 0xdb, 0xcd, 0x17, 0x34, 0x61, 0x18, 0xfa, 0xfd, 0x5b, 0xb6, 0x9f, 0x89, 0xb9, 0x74, 0x1c, 0x90, + 0xc3, 0x9b, 0xdb, 0xd7, 0xb4, 0xe6, 0xcf, 0xd3, 0x40, 0x38, 0x55, 0xbd, 0x45, 0x43, 0x6d, 0xa6, + 0xd9, 0xf1, 0x7b, 0x77, 0x79, 0x27, 0xf0, 0x8e, 0x69, 0x4e, 0x27, 0xbd, 0x1d, 0xd2, 0xc8, 0x64, + 0x34, 0xce, 0xe6, 0x49, 0xc9, 0x65, 0xbf, 0x58, 0x40, 0x4c, 0xb4, 0x7a, 0x57, 0x5c, 0x4a, 0x66, + 0x50, 0x97, 0x53, 0xfc, 0xf9, 0x49, 0x7e, 0x5e, 0xa1, 0xf6, 0xea, 0xc8, 0xcc, 0x82, 0xc1, 0xb9, + 0x77, 0x93, 0x33, 0x38, 0x82, 0xac, 0x15, 0x2f, 0x9d, 0x56, 0x57, 0x6c, 0xfe, 0x9d, 0x40, 0xf8, + 0x2f, 0xdc, 0x3d, 0x27, 0xc0, 0xb5, 0xf3, 0x19, 0xa1, 0xc3, 0x81, 0xb0, 0x51, 0x14, 0xb8, 0xa8, + 0x70, 0x0c, 0x03, 0xcd, 0x4a, 0x3a, 0xd2, 0xf5, 0x27, 0xe7, 0x90, 0xd7, 0x19, 0xc9, 0x98, 0x34, + 0xb8, 0xc3, 0x1b, 0x0e, 0xe7, 0xbf, 0x0a, 0x7d, 0xde, 0x74, 0xa6, 0x2d, 0x4d, 0xe8, 0x26, 0x6a, + 0xf2, 0x09, 0xc0, 0x6e, 0x45, 0x23, 0x44, 0xc9, 0xd0, 0x79, 0xca, 0x00, 0x6b, 0x99, 0xf7, 0x83, + 0xac, 0xbc, 0x22, 0x0a, 0x4f, 0xa6, 0x0b, 0xe1, 0xe2, 0x74, 0xae, 0x2c, 0x50, 0xf2, 0x44, 0x02, + 0x11, 0xc2, 0x7c, 0xcd, 0xa6, 0x6d, 0x72, 0x9b, 0x4f, 0x11, 0x6c, 0x4e, 0x50, 0x01, 0xbc, 0xf1, + 0x99, 0xef, 0x63, 0x68, 0xe4, 0x7a, 0x39, 0x14, 0xee, 0xa5, 0xe1, 0xbd, 0xbe, 0xb0, 0x18, 0xdf, + 0xeb, 0xca, 0xeb, 0x3e, 0xbd, 0x6e, 0x52, 0x7e, 0x7e, 0xcd, 0xde, 0xa6, 0x89, 0x20, 0xa3, 0xed, + 0xb8, 0x7f, 0x8c, 0x62, 0x08, 0xb0, 0x84, 0x17, 0x72, 0xf4, 0x59, 0x47, 0x73, 0x9c, 0x0e, 0x91, + 0x05, 0x2b, 0x1a, 0x1c, 0xca, 0xc2, 0x26, 0xe6, 0x27, 0x75, 0x4e, 0xe6, 0x55, 0xa9, 0xb9, 0x83, + 0x7f, 0xe3, 0x16, 0x39, 0xd9, 0xb6, 0x52, 0x88, 0xbe, 0xb5, 0x65, 0xc2, 0xb4, 0x21, 0x66, 0x3b, + 0xec, 0x18, 0x16, 0xc2, 0x9c, 0xed, 0x93, 0x59, 0x9b, 0x9d, 0xef, 0x6f, 0xde, 0x4a, 0xc3, 0x81, + 0x56, 0x78, 0x8f, 0x5a, 0x45, 0x4d, 0xb1, 0x61, 0x4d, 0x4c, 0x0b, 0xdc, 0x9a, 0x0d, 0x58, 0x98, + 0x66, 0x75, 0x24, 0x2e, 0x6d, 0x82, 0x5e, 0x35, 0x91, 0xa2, 0x1e, 0x45, 0xc0, 0x50, 0x67, 0xd8, + 0x0d, 0xfe, 0x36, 0x31, 0x41, 0xa4, 0x0c, 0xfd, 0xb3, 0xe9, 0xa1, 0x5e, 0xf2, 0x9d, 0xb2, 0x6c, + 0xe4, 0x10, 0x79, 0xbb, 0x69, 0xbf, 0x05, 0xbc, 0x4b, 0xd5, 0x91, 0xfb, 0x04, 0x13, 0x89, 0x14, + 0xd5, 0x24, 0xb5, 0x7f, 0x86, 0xb1, 0x3a, 0x46, 0x57, 0x24, 0xbf, 0x75, 0xdc, 0xa0, 0x3b, 0x12, + 0xbe, 0x91, 0x1d, 0xca, 0x1d, 0xf1, 0x9b, 0xa1, 0xe2, 0x21, 0x11, 0x6c, 0x57, 0xcd, 0xbb, 0x64, + 0x70, 0x55, 0x1b, 0x64, 0xc1, 0x7c, 0xa0, 0x71, 0x46, 0xb2, 0x05, 0xb0, 0x9f, 0xf9, 0x82, 0x7a, + 0xb5, 0xb3, 0x1b, 0x42, 0x65, 0x73, 0x81, 0x4a, 0xc0, 0x18, 0xa8, 0xaa, 0x57, 0xe9, 0x3e, 0x1e, + 0xbb, 0x0e, 0xce, 0x97, 0x9e, 0xd3, 0xce, 0x76, 0xd9, 0xea, 0x0d, 0x8a, 0x37, 0xe5, 0x2d, 0x27, + 0xd3, 0x80, 0x00, 0x98, 0x99, 0xc8, 0x37, 0xee, 0x09, 0x91, 0xb0, 0xa6, 0x64, 0x6f, 0x6a, 0x91, + 0x1f, 0xfe, 0x45, 0xf5, 0xcb, 0x65, 0x68, 0x6a, 0x6f, 0x58, 0x6a, 0xa4, 0x0c, 0xb2, 0x8c, 0x17, + 0xad, 0x86, 0x47, 0x6a, 0xed, 0xd6, 0x78, 0xd8, 0x10, 0x9d, 0x1d, 0xaf, 0x2e, 0x09, 0x8b, 0x0f, + 0xf7, 0xe9, 0x5b, 0xe9, 0x45, 0x28, 0x54, 0xa2, 0x02, 0x09, 0xb5, 0xe6, 0xe8, 0xec, 0x6a, 0xc4, + 0x2f, 0x6d, 0x07, 0x13, 0xd5, 0xb0, 0x13, 0x5f, 0x09, 0x37, 0xa2, 0x1d, 0x4c, 0x54, 0x8e, 0xcf, + 0x64, 0x6b, 0xde, 0x60, 0x63, 0x49, 0x10, 0xf3, 0xed, 0xb6, 0x27, 0x68, 0xed, 0x8a, 0xfe, 0xdc, + 0x51, 0xb8, 0xb3, 0x6c, 0xa1, 0xfc, 0x39, 0xc9, 0x8c, 0xbf, 0x56, 0xeb, 0x3c, 0x52, 0xf0, 0xd8, + 0x64, 0x9c, 0x5f, 0x21, 0x62, 0xd0, 0xa6, 0xef, 0x75, 0x08, 0x3b, 0xdc, 0x5d, 0xef, 0x62, 0x2f, + 0xd3, 0x06, 0x62, 0x6b, 0x50, 0x1a, 0x49, 0x7d, 0xd8, 0x2a, 0xf2, 0xa3, 0x58, 0x92, 0xb6, 0x72, + 0xbc, 0x21, 0xf8, 0xd6, 0x78, 0x35, 0x96, 0x71, 0xb6, 0x53, 0x4e, 0xe9, 0x62, 0xe3, 0xa8, 0xd2, + 0x5e, 0xb5, 0x26, 0x1a, 0x22, 0xbb, 0xda, 0xf5, 0xa3, 0xd2, 0xfd, 0xcb, 0xc3, 0xc0, 0xea, 0xe6, + 0xd3, 0x90, 0x70, 0x5a, 0x93, 0xfc, 0x3e, 0xdb, 0xcc, 0x04, 0xbf, 0xb3, 0xa6, 0xd9, 0xbf, 0x12, + 0x4a, 0xb1, 0x78, 0x82, 0xbb, 0xcf, 0xa2, 0x73, 0xb6, 0x74, 0x92, 0x39, 0xe5, 0x78, 0xae, 0xea, + 0xa9, 0xd1, 0x5e, 0x2d, 0xa1, 0x81, 0xa6, 0x76, 0x62, 0x68, 0x3b, 0x3c, 0xd9, 0xc5, 0xac, 0xa3, + 0x06, 0xa3, 0x1f, 0x1f, 0x40, 0xbb, 0x4c, 0x03, 0x06, 0x14, 0xe3, 0x9b, 0x06, 0xa2, 0x68, 0xd2, + 0xee, 0x2e, 0x85, 0x11, 0xab, 0x5f, 0x46, 0x52, 0xf5, 0x2e, 0xf3, 0x53, 0x65, 0x04, 0x05, 0x5f, + 0x48, 0xd4, 0xa9, 0x9c, 0x1b, 0xee, 0x9f, 0xff, 0xca, 0xc4, 0x65, 0x9a, 0xc3, 0x61, 0xff, 0xc8, + 0x26, 0x6e, 0x2c, 0xa7, 0x1e, 0xcf, 0x33, 0x51, 0x5b, 0x43, 0x84, 0xcf, 0x4b, 0xa7, 0xec, 0x15, + 0x2d, 0x36, 0xa5, 0xea, 0x18, 0x80, 0xd0, 0xf4, 0x8a, 0x1d, 0x8a, 0x0a, 0x33, 0xb1, 0x92, 0x57, + 0x39, 0x1e, 0x8e, 0xa6, 0x0f, 0x39, 0xfe, 0x65, 0x0b, 0xca, 0x9d, 0x1d, 0x25, 0xe4, 0x12, 0x22, + 0xe8, 0xa1, 0x2b, 0x5b, 0xba, 0xd7, 0x88, 0xba, 0xd7, 0xc2, 0x66, 0xa8, 0xe1, 0x8e, 0x57, 0x45, + 0xf5, 0xf7, 0x7d, 0x4c, 0x1e, 0x38, 0xcc, 0xce, 0x1b, 0x60, 0xed, 0x09, 0xb3, 0x18, 0xb6, 0xd2, + 0xc5, 0x72, 0xdc, 0xab, 0x5a, 0x40, 0x8d, 0x5e, 0x07, 0xda, 0xb1, 0x35, 0x0e, 0x83, 0x95, 0x3d, + 0x22, 0xba, 0x10, 0xe7, 0xe0, 0x89, 0x6a, 0x4e, 0x10, 0x94, 0xc1, 0x96, 0x3e, 0xb6, 0xcb, 0x3d, + 0xd8, 0x83, 0xdc, 0x8c, 0x82, 0x17, 0x64, 0x6a, 0xc4, 0x68, 0xf7, 0xb0, 0xbd, 0x06, 0x1e, 0x7f, + 0x9a, 0x6c, 0x72, 0xae, 0xe0, 0x65, 0x13, 0x30, 0x3a, 0x99, 0x33, 0xf3, 0xb6, 0x29, 0x46, 0x45, + 0x2a, 0x81, 0x83, 0x32, 0x09, 0x7c, 0xd5, 0x79, 0xe1, 0x2a, 0xaf, 0x7a, 0xf2, 0x92, 0xc5, 0xb3, + 0x19, 0xb1, 0xfa, 0x7b, 0xbd, 0xdb, 0xc2, 0xd7, 0x48, 0x22, 0xcc, 0xf5, 0xd7, 0xde, 0x76, 0x53, + 0x83, 0x33, 0x33, 0xd2, 0x68, 0x77, 0x77, 0x2a, 0xb8, 0xec, 0x21, 0x29, 0xb5, 0x3a, 0x9c, 0xed, + 0xcd, 0xeb, 0xe7, 0xf1, 0x83, 0x10, 0xfd, 0x39, 0xfc, 0x7d, 0xb6, 0xd9, 0xcd, 0x3b, 0xa6, 0xd7, + 0x46, 0x06, 0x93, 0x57, 0x89, 0x3c, 0x0e, 0x81, 0xc0, 0x04, 0x47, 0xe0, 0xdd, 0x9c, 0x75, 0xcf, + 0xb3, 0x1a, 0x8b, 0x08, 0xbd, 0x42, 0xd4, 0xb2, 0x07, 0xcd, 0x70, 0xf8, 0xf2, 0xcb, 0xa9, 0x7e, + 0x13, 0x89, 0xb4, 0x6e, 0x90, 0xf0, 0xe4, 0x41, 0x98, 0xee, 0xd4, 0x8b, 0x52, 0x47, 0x5f, 0x5b, + 0xb7, 0x28, 0x24, 0x4e, 0x31, 0x93, 0xb8, 0x08, 0x9a, 0x6f, 0x4a, 0x1e, 0x02, 0x21, 0x40, 0xa7, + 0xa4, 0x52, 0xba, 0xa7, 0x94, 0x0c, 0x30, 0x8a, 0x5d, 0x14, 0x52, 0x25, 0x81, 0x3f, 0x64, 0x43, + 0xc6, 0x78, 0xab, 0x9a, 0xf1, 0xba, 0x71, 0xe6, 0x30, 0x11, 0x9e, 0x44, 0xa5, 0x94, 0xb6, 0x53, + 0x2d, 0x0e, 0x53, 0x7d, 0xb0, 0x3e, 0xf4, 0xb2, 0x27, 0x67, 0xfe, 0xb5, 0xc9, 0x84, 0x87, 0xf5, + 0x0a, 0x82, 0xa8, 0xc5, 0x22, 0x16, 0x49, 0x47, 0x28, 0xc4, 0x4e, 0x9f, 0x67, 0x77, 0x2b, 0xd1, + 0xab, 0xe1, 0x0c, 0xb2, 0x15, 0x9c, 0x99, 0x8d, 0x03, 0x91, 0x6e, 0x68, 0x1a, 0x7f, 0x5b, 0x5c, + 0x9f, 0x21, 0xc3, 0x69, 0x23, 0x02, 0x50, 0xed, 0x39, 0xf8, 0xee, 0xac, 0xad, 0x5a, 0x95, 0x0b, + 0x9b, 0xe6, 0x9c, 0xa1, 0x13, 0x94, 0x02, 0xd6, 0xa8, 0x04, 0x0f, 0x3f, 0xc9, 0xc7, 0x9f, 0x10, + 0x08, 0xf8, 0xb6, 0x1c, 0xf3, 0xf4, 0xef, 0x22, 0x9b, 0x85, 0x16, 0x54, 0xcb, 0x15, 0x47, 0x8e, + 0x36, 0x2e, 0x78, 0xfb, 0xa6, 0xdc, 0xae, 0x08, 0x31, 0xc9, 0x00, 0xbd, 0x14, 0xf9, 0x2c, 0xda, + 0x4e, 0x24, 0x05, 0x00, 0x6e, 0x02, 0x37, 0xb8, 0xd7, 0x6d, 0x6d, 0xb1, 0x7b, 0x39, 0x96, 0x49, + 0xa5, 0xc7, 0x95, 0x65, 0x9e, 0x00, 0x6f, 0x6c, 0x40, 0xe7, 0xd5, 0x8a, 0x58, 0x50, 0xc3, 0x5b, + 0xc9, 0x2d, 0x91, 0xa3, 0xa9, 0xdd, 0x04, 0x6a, 0xab, 0x32, 0x3d, 0xe7, 0xae, 0xd5, 0xb3, 0x9c, + 0x36, 0x67, 0xf4, 0x84, 0xad, 0x39, 0x33, 0xab, 0x71, 0x84, 0x3d, 0xd9, 0xd5, 0x63, 0x1c, 0xe7, + 0xf2, 0x1e, 0x07, 0xfd, 0x8d, 0x98, 0x45, 0xd6, 0xfc, 0xbd, 0xe7, 0x4a, 0xe1, 0x1d, 0xd3, 0x62, + 0xf1, 0xf6, 0x51, 0xd0, 0xdf, 0xcb, 0xfa, 0xfc, 0xf3, 0xe2, 0x42, 0x84, 0xb6, 0x88, 0x4d, 0x57, + 0x3f, 0x1a, 0x29, 0x17, 0xea, 0x65, 0xe4, 0x28, 0xc9, 0xb0, 0x36, 0x04, 0x7b, 0x53, 0xb1, 0x1e, + 0x1c, 0xc2, 0x7a, 0x39, 0x78, 0x37, 0x64, 0xe4, 0x04, 0x57, 0xd7, 0xdd, 0x5b, 0xaf, 0xdf, 0xad, + 0xdd, 0x2c, 0x1d, 0xf9, 0x38, 0x46, 0xc2, 0x83, 0x06, 0xea, 0x86, 0xf3, 0xc7, 0x82, 0x84, 0xeb, + 0x9c, 0xd1, 0x49, 0xad, 0x4e, 0x13, 0x7b, 0x33, 0x91, 0xa0, 0xa7, 0x26, 0x41, 0xd3, 0xef, 0xef, + 0xd4, 0x35, 0x9d, 0x4e, 0xca, 0x0e, 0x9f, 0x28, 0x0f, 0x9e, 0xc2, 0xa7, 0x93, 0xba, 0xfa, 0x6c, + 0x8a, 0x48, 0x3b, 0xcd, 0x13, 0x65, 0x9e, 0x07, 0x9c, 0xac, 0xe9, 0x4b, 0xa6, 0xe5, 0xf9, 0xb9, + 0xb8, 0xcf, 0xc9, 0x29, 0x48, 0x7f, 0x4e, 0x56, 0x4a, 0xf1, 0xd7, 0x5a, 0xc7, 0x7c, 0x76, 0xf7, + 0x16, 0x3c, 0xee, 0x62, 0x63, 0x06, 0xd8, 0x38, 0xf7, 0x6c, 0xac, 0x3a, 0x15, 0x41, 0x2d, 0xcb, + 0x7d, 0xed, 0x5f, 0x63, 0x1b, 0x7e, 0x46, 0xc2, 0xe1, 0x4b, 0xe8, 0x13, 0xfe, 0x6a, 0x06, 0x94, + 0xed, 0x17, 0xc4, 0x27, 0x55, 0x5a, 0x41, 0x5a, 0xb3, 0x2b, 0x2c, 0x9a, 0x42, 0x93, 0x5c, 0x39, + 0xf2, 0xb3, 0x25, 0x26, 0x91, 0xda, 0x70, 0x0b, 0x47, 0xc7, 0x8b, 0xa5, 0x4e, 0xf8, 0xd4, 0xdf, + 0xbf, 0x47, 0x4f, 0xdb, 0x7a, 0xfb, 0xae, 0x37, 0x05, 0xa6, 0x5e, 0xf0, 0x0d, 0xcc, 0xe4, 0xfd, + 0xbb, 0x32, 0x70, 0xc1, 0x50, 0x86, 0xfc, 0x9e, 0x0a, 0xa7, 0x22, 0x61, 0x40, 0x99, 0xec, 0x1d, + 0xc6, 0xff, 0x45, 0xaf, 0x02, 0xdb, 0xc3, 0x76, 0xd1, 0x45, 0x79, 0xf4, 0x6b, 0xa8, 0x76, 0xb7, + 0x39, 0xca, 0x77, 0xcf, 0x2a, 0x5d, 0x03, 0xec, 0x51, 0xf6, 0xe1, 0xb7, 0x58, 0x66, 0x1a, 0xee, + 0x25, 0x60, 0xf6, 0x51, 0x99, 0xc9, 0x98, 0x3b, 0x3a, 0x4b, 0xac, 0x73, 0x4f, 0x41, 0x9b, 0x10, + 0xb4, 0xc5, 0x3d, 0x7a, 0xb9, 0xf1, 0xbc, 0x4a, 0xe2, 0x8d, 0xf8, 0xef, 0xd1, 0x63, 0x26, 0xf9, + 0x8e, 0x69, 0x19, 0x53, 0x88, 0xfb, 0x55, 0x5b, 0x02, 0x07, 0x34, 0x3f, 0xe7, 0x3c, 0xf7, 0xb3, + 0x55, 0x12, 0xb9, 0x2b, 0x34, 0x40, 0x6b, 0x74, 0xaf, 0xc4, 0x3d, 0xfe, 0x03, 0x07, 0xf8, 0xea, + 0x96, 0x52, 0x0f, 0xa6, 0xd0, 0x90, 0xb5, 0xa7, 0x7d, 0x78, 0x48, 0x9f, 0x0b, 0x2b, 0xd4, 0x12, + 0x5f, 0xa1, 0xb2, 0x6c, 0x91, 0x98, 0x2c, 0x8c, 0x9b, 0xf9, 0x59, 0xc6, 0x53, 0x2c, 0x3d, 0x0b, + 0x77, 0x63, 0x44, 0x54, 0x6c, 0x4e, 0xfd, 0x70, 0x84, 0x73, 0x56, 0xe3, 0x1f, 0xcd, 0x08, 0x1a, + 0x6c, 0xea, 0xd5, 0x31, 0x85, 0xe7, 0x25, 0x56, 0x23, 0x9b, 0xfe, 0x35, 0x7a, 0xca, 0x4c, 0x8d, + 0x13, 0x89, 0xb6, 0x3f, 0xfc, 0xfd, 0xe1, 0xb4, 0x50, 0x55, 0xff, 0x4c, 0xb5, 0x2b, 0xa8, 0x8b, + 0x18, 0xcb, 0xf2, 0xf4, 0xdb, 0x79, 0xe2, 0xf8, 0xc7, 0x6b, 0xe6, 0xd5, 0x8e, 0x90, 0x53, 0xd9, + 0x20, 0xf6, 0x08, 0xcd, 0xa1, 0x43, 0x11, 0x93, 0xcf, 0x75, 0x75, 0xe5, 0xd6, 0x63, 0x93, 0x4f, + 0x73, 0x90, 0xf1, 0x43, 0xf5, 0xf2, 0x60, 0xcf, 0x13, 0x6e, 0x5b, 0x75, 0x6e, 0x36, 0x2d, 0xa0, + 0x9d, 0x9c, 0xb0, 0xdc, 0x9f, 0xd4, 0x5a, 0xed, 0x8f, 0xbe, 0xd9, 0x9b, 0xa7, 0x4b, 0x98, 0x61, + 0xf5, 0x45, 0x92, 0xf2, 0x2d, 0xb7, 0xf2, 0xdb, 0xec, 0xe2, 0xde, 0x13, 0xae, 0xd6, 0xed, 0x1f, + 0x3d, 0x63, 0x0b, 0xdc, 0xf3, 0xd0, 0xbc, 0xd1, 0xe7, 0x9e, 0x91, 0xe8, 0x5d, 0x32, 0xfd, 0x16, + 0x83, 0xee, 0xdb, 0xbb, 0x52, 0x4f, 0x2d, 0x01, 0x48, 0xe3, 0x82, 0x6d, 0xa4, 0x63, 0x71, 0xab, + 0x87, 0x5c, 0xa7, 0x96, 0xde, 0x60, 0x20, 0x0a, 0x4b, 0x6b, 0x43, 0x00, 0x87, 0x20, 0x0d, 0xac, + 0x49, 0xb6, 0xe5, 0xdb, 0x3f, 0xd2, 0xca, 0x5b, 0xc9, 0x59, 0xa2, 0x32, 0xc9, 0x9b, 0x47, 0x53, + 0xa9, 0x57, 0x08, 0xad, 0x26, 0xb3, 0x97, 0x5e, 0x30, 0x99, 0x22, 0xba, 0xa8, 0x4a, 0x72, 0xdf, + 0x84, 0x6f, 0x41, 0x52, 0x13, 0x52, 0x03, 0xd0, 0x42, 0x11, 0xc7, 0x81, 0x99, 0xff, 0x7f, 0xdd, + 0x6d, 0x00, 0x25, 0xe3, 0x9d, 0xdf, 0x70, 0x36, 0x3e, 0xde, 0x49, 0x4f, 0xff, 0x14, 0x9a, 0x49, + 0xad, 0x06, 0x44, 0x44, 0xdd, 0x45, 0x62, 0x28, 0x82, 0x51, 0x8b, 0xd7, 0xa2, 0x8f, 0x17, 0x8f, + 0x2d, 0xe9, 0x72, 0x6d, 0x84, 0x45, 0xc4, 0xb9, 0xd1, 0xb0, 0xc1, 0x77, 0xd5, 0x5b, 0x2b, 0x5c, + 0xef, 0xa8, 0xc5, 0xe1, 0x1e, 0x96, 0x61, 0x76, 0xe8, 0xbe, 0x46, 0xaa, 0x26, 0xe9, 0xd7, 0x83, + 0x17, 0x3d, 0x18, 0xc1, 0xb7, 0x24, 0x87, 0x63, 0x78, 0xd4, 0xb3, 0xd7, 0x92, 0xeb, 0x06, 0xaa, + 0x85, 0x17, 0xca, 0x8a, 0xdd, 0xda, 0x54, 0x7d, 0x64, 0x62, 0xd4, 0x74, 0xe4, 0xc5, 0x98, 0xcb, + 0x37, 0xde, 0x23, 0x0d, 0x76, 0x55, 0x60, 0x9a, 0x55, 0x69, 0x76, 0x13, 0x45, 0x83, 0xa9, 0x97, + 0xb9, 0x85, 0xec, 0xb5, 0xb5, 0xa2, 0xf6, 0x6b, 0x2a, 0xc1, 0xfe, 0xac, 0xeb, 0xa5, 0x8b, 0x56, + 0x4a, 0x71, 0xb0, 0x62, 0xb1, 0xdf, 0x07, 0xbf, 0x48, 0xea, 0xc7, 0x57, 0x59, 0x9d, 0x25, 0x71, + 0xd8, 0x9c, 0x1c, 0xa1, 0x93, 0x6c, 0xbc, 0x3b, 0x66, 0x47, 0xf4, 0xc6, 0x32, 0x93, 0x90, 0x0e, + 0x1e, 0x48, 0x8a, 0x4f, 0x8c, 0xc2, 0x51, 0x46, 0x37, 0x11, 0xd4, 0x4e, 0xa9, 0x21, 0xe3, 0x0b, + 0xf9, 0xed, 0xdc, 0xdd, 0x37, 0x8e, 0xc6, 0xff, 0xce, 0x2e, 0x0a, 0x2f, 0xa6, 0xab, 0xf1, 0xf3, + 0xd1, 0x5d, 0x56, 0x8d, 0xfb, 0xbf, 0xac, 0x77, 0xca, 0x57, 0x13, 0x7f, 0x92, 0xbe, 0x0c, 0xed, + 0xe8, 0xcc, 0xc1, 0x83, 0xf4, 0xfc, 0x76, 0x83, 0xa5, 0xe2, 0x8f, 0x9e, 0x9f, 0xfd, 0x23, 0x33, + 0xff, 0xa4, 0xc6, 0x3b, 0x7c, 0x82, 0x82, 0x46, 0x23, 0xec, 0xd3, 0xbe, 0xc4, 0x6c, 0x4c, 0x4d, + 0x7a, 0x13, 0xc2, 0x78, 0x1b, 0x66, 0x8d, 0xbb, 0x6b, 0x82, 0x60, 0x34, 0x65, 0xf0, 0x8e, 0xd7, + 0x26, 0xab, 0x8f, 0xd8, 0x09, 0xc0, 0xf7, 0x81, 0x22, 0xe0, 0xd6, 0xd8, 0x00, 0x8b, 0xfa, 0x2a, + 0x22, 0x19, 0x0e, 0xa2, 0xbb, 0x87, 0xe9, 0x85, 0xce, 0xb1, 0x68, 0x6d, 0x05, 0x8c, 0xf4, 0xd9, + 0x2a, 0x8d, 0xe5, 0xf7, 0x4e, 0x20, 0x26, 0xe6, 0x3b, 0xa6, 0x77, 0xa3, 0x88, 0x5f, 0xd4, 0xa9, + 0x93, 0xc6, 0xda, 0xee, 0x5a, 0x7c, 0xcf, 0x3d, 0x46, 0xfa, 0x8e, 0xc4, 0x48, 0x97, 0x35, 0x90, + 0xf0, 0x7c, 0xee, 0x09, 0x6d, 0xab, 0x7a, 0x3d, 0x5a, 0x53, 0x8e, 0x39, 0x55, 0xcd, 0x5c, 0xf7, + 0xc7, 0x74, 0x77, 0xf9, 0x9b, 0x85, 0xc2, 0xfa, 0x48, 0x23, 0x59, 0xe7, 0x74, 0x88, 0x5e, 0xa8, + 0xf7, 0x1d, 0x5e, 0x14, 0x56, 0x9f, 0x64, 0xca, 0x5e, 0x95, 0xba, 0xbb, 0xa7, 0xcb, 0xe9, 0xfd, + 0xae, 0x66, 0x05, 0xa7, 0x2d, 0x24, 0x13, 0xda, 0x86, 0xb8, 0x65, 0x2e, 0x20, 0xc6, 0xf9, 0x79, + 0xe7, 0xb2, 0x92, 0xbf, 0x59, 0x4b, 0x70, 0xbb, 0x7b, 0xc3, 0x2f, 0x07, 0xa6, 0x4e, 0x2a, 0x15, + 0x9a, 0xc4, 0x9f, 0x7f, 0xd1, 0x26, 0x84, 0xc4, 0x65, 0xf9, 0xd8, 0x11, 0x8d, 0x5a, 0x10, 0xa0, + 0xaf, 0x59, 0xa8, 0x59, 0xa4, 0x81, 0x5a, 0xb5, 0x37, 0xf9, 0x64, 0x2c, 0xdc, 0xbf, 0xae, 0x2e, + 0x83, 0xf2, 0x1a, 0x55, 0x19, 0xfa, 0xd8, 0x53, 0xc9, 0x9d, 0x23, 0x11, 0x94, 0x52, 0x20, 0x11, + 0xb6, 0x12, 0xf0, 0xfc, 0x02, 0x6e, 0x7c, 0xbe, 0xea, 0x6c, 0x95, 0x86, 0xcc, 0xf9, 0x8d, 0x38, + 0x09, 0xef, 0x6e, 0x15, 0x7c, 0x10, 0x64, 0x8c, 0xa5, 0xaa, 0x0d, 0x3c, 0x42, 0xef, 0x92, 0x0c, + 0xd8, 0xea, 0xe8, 0x54, 0xbb, 0x7d, 0x12, 0x4a, 0xd8, 0x48, 0x08, 0x94, 0xd6, 0x13, 0xd8, 0xc1, + 0xe7, 0xbb, 0x46, 0xa2, 0x2f, 0x2d, 0x07, 0xf1, 0x3a, 0xdd, 0x30, 0x90, 0x5d, 0x76, 0x79, 0xec, + 0x7d, 0xa8, 0x23, 0x4a, 0x11, 0xb3, 0xeb, 0x3b, 0x9a, 0xa6, 0xc5, 0xf5, 0x44, 0x77, 0x3e, 0x9c, + 0x3f, 0xa7, 0x93, 0xda, 0x41, 0xf7, 0x72, 0x54, 0x39, 0x1f, 0xff, 0x68, 0xf2, 0xf5, 0xc6, 0xfd, + 0x16, 0x20, 0x75, 0x75, 0xd7, 0x2b, 0x23, 0x9b, 0x1f, 0x58, 0x92, 0x93, 0x08, 0x6e, 0x7a, 0x73, + 0xa6, 0x95, 0xbf, 0x6d, 0x8f, 0xda, 0x29, 0x4a, 0x67, 0xd5, 0x21, 0x24, 0xda, 0xed, 0xbc, 0x7c, + 0xd3, 0xfd, 0x43, 0x7f, 0x8a, 0x8d, 0x77, 0x4c, 0x6b, 0xc4, 0x09, 0xb8, 0x45, 0xe4, 0xae, 0x60, + 0x88, 0x53, 0xf2, 0x7a, 0x61, 0x25, 0xac, 0xf3, 0xb0, 0x0f, 0xf8, 0x1d, 0x77, 0x84, 0x5a, 0x26, + 0x9e, 0xf1, 0x83, 0xc1, 0x48, 0xdd, 0xfe, 0x54, 0xd4, 0x2b, 0x98, 0x2a, 0xfc, 0x7f, 0xe5, 0x33, + 0xfc, 0x6d, 0xef, 0xa7, 0x5b, 0x3d, 0x36, 0x48, 0x32, 0xe7, 0xba, 0x17, 0x94, 0x8e, 0x44, 0xfa, + 0x04, 0x2c, 0xe6, 0xdf, 0x4d, 0xe7, 0xac, 0xb7, 0x6a, 0x7c, 0xa6, 0x84, 0x8c, 0xda, 0x08, 0xe2, + 0x73, 0xbc, 0xbe, 0xf0, 0x3d, 0xc0, 0x55, 0x84, 0x78, 0x42, 0xe1, 0x40, 0x1d, 0x7f, 0xfe, 0xd5, + 0xa2, 0x3a, 0x41, 0x4f, 0x9f, 0x82, 0xb7, 0x27, 0x3b, 0x12, 0xc4, 0x87, 0xe9, 0xed, 0x51, 0xed, + 0xcc, 0x42, 0x7d, 0xcf, 0xe3, 0xd7, 0xe8, 0x8a, 0xd0, 0x6a, 0x68, 0xa5, 0xf7, 0xd5, 0xa9, 0x92, + 0x0a, 0xe0, 0x3d, 0x44, 0xdb, 0xd7, 0x3c, 0x16, 0xc6, 0x7d, 0x49, 0x15, 0x67, 0xc9, 0x3d, 0xc1, + 0x69, 0x45, 0xe6, 0x57, 0x2a, 0x39, 0xea, 0x20, 0xc0, 0x9a, 0xe3, 0x13, 0x99, 0x89, 0xda, 0xe1, + 0x56, 0x36, 0x18, 0x57, 0x57, 0xf4, 0x6a, 0xe4, 0xf0, 0x38, 0x91, 0x9c, 0x20, 0x3e, 0xaf, 0xf2, + 0xd6, 0xe5, 0xf4, 0x33, 0xa6, 0x98, 0xb6, 0xa1, 0x0c, 0x37, 0x74, 0x2e, 0x72, 0xd5, 0xee, 0x08, + 0xcd, 0x85, 0x24, 0x8a, 0xcb, 0x0e, 0x31, 0x0a, 0xfa, 0x79, 0x7d, 0x32, 0x18, 0x7c, 0xe8, 0x1a, + 0x2c, 0xad, 0xb5, 0x7e, 0x6a, 0x80, 0xe5, 0x17, 0x4d, 0x3d, 0x52, 0x67, 0x76, 0xfa, 0x55, 0x6b, + 0x99, 0xab, 0x96, 0x49, 0xaa, 0x8b, 0xf0, 0xa3, 0xd6, 0x8c, 0xc4, 0xec, 0x9c, 0xb9, 0x31, 0xf0, + 0x7f, 0x84, 0xd4, 0x51, 0x5d, 0x63, 0x59, 0xce, 0x2b, 0x39, 0x33, 0x65, 0x7e, 0x1c, 0x53, 0x0a, + 0x0d, 0xf5, 0x84, 0x78, 0x69, 0x1b, 0xd7, 0x65, 0xb1, 0xbe, 0x96, 0xcd, 0x78, 0xd9, 0x1b, 0x44, + 0x2d, 0xea, 0xef, 0x4d, 0x2d, 0x46, 0xbb, 0x5a, 0xab, 0x7a, 0x31, 0xc7, 0x14, 0x9a, 0x45, 0x70, + 0x29, 0xf2, 0x7b, 0xcf, 0x15, 0xee, 0x3b, 0xa6, 0x75, 0x55, 0xef, 0xf9, 0x33, 0xfd, 0x39, 0x92, + 0x80, 0xeb, 0x43, 0xe3, 0xfd, 0xa4, 0x66, 0x71, 0x5d, 0x4c, 0x8b, 0x7a, 0xa3, 0x86, 0x62, 0xb5, + 0xab, 0x35, 0x4c, 0xcf, 0x89, 0xd5, 0xb2, 0xec, 0x7a, 0xc3, 0x3a, 0xf2, 0x2f, 0xe7, 0x11, 0x59, + 0x9b, 0x85, 0xef, 0x4c, 0x32, 0x96, 0x70, 0x74, 0x39, 0xd0, 0xc5, 0xa5, 0x4c, 0x61, 0x7f, 0xf3, + 0xcc, 0x9f, 0x64, 0xd7, 0x03, 0x59, 0x50, 0x30, 0x08, 0x62, 0xb7, 0xd0, 0x7e, 0xad, 0xcd, 0x31, + 0x9c, 0x9b, 0xee, 0x3b, 0x40, 0x04, 0x59, 0xc0, 0x34, 0x7c, 0x10, 0x9f, 0x6a, 0xa5, 0x88, 0x24, + 0x78, 0x40, 0x79, 0xa8, 0x50, 0x8a, 0xda, 0x3e, 0x59, 0x18, 0x58, 0x2e, 0x13, 0x6a, 0x9b, 0xa7, + 0x45, 0x6b, 0x43, 0x85, 0xd7, 0x13, 0x0d, 0xdf, 0x95, 0x5e, 0x2f, 0xc4, 0x9f, 0x3d, 0x96, 0x54, + 0x0a, 0xee, 0x74, 0xea, 0x29, 0xde, 0xc0, 0x3f, 0x86, 0xf8, 0xe7, 0x4d, 0x48, 0x9a, 0xd9, 0x19, + 0xaf, 0x0f, 0xee, 0x86, 0xcb, 0x29, 0x3d, 0x75, 0xe7, 0x2f, 0x96, 0xbf, 0x96, 0xee, 0xfd, 0x88, + 0x67, 0x87, 0xb8, 0xe5, 0x4a, 0xa3, 0xa7, 0x70, 0x01, 0x32, 0xc3, 0xcd, 0x4a, 0xd9, 0x2b, 0xb3, + 0x72, 0xf8, 0xde, 0xe5, 0x62, 0xfe, 0x11, 0x9b, 0x6d, 0xe8, 0xa8, 0x87, 0x3e, 0x6f, 0x50, 0x4d, + 0xff, 0x01, 0x97, 0xca, 0xb2, 0x1d, 0x7f, 0x08, 0xb0, 0x6c, 0x23, 0x21, 0x1d, 0x46, 0xee, 0xa4, + 0xaa, 0x0e, 0x38, 0x69, 0xa8, 0x9f, 0x07, 0xda, 0x5c, 0x73, 0xe3, 0x20, 0x6b, 0xe0, 0x37, 0x58, + 0xca, 0x29, 0x45, 0xe9, 0x86, 0x4c, 0x0e, 0x9f, 0xf0, 0x6f, 0x1d, 0xd6, 0xd3, 0x75, 0xa2, 0x24, + 0x0b, 0x04, 0x3f, 0xd7, 0x64, 0x09, 0x6b, 0xc1, 0xd8, 0x04, 0x2a, 0xba, 0xd4, 0x33, 0x9c, 0x19, + 0x78, 0x5b, 0x60, 0x46, 0x23, 0x7b, 0x98, 0x22, 0x6d, 0x1d, 0x7e, 0x7d, 0xc3, 0x3c, 0x12, 0x30, + 0x94, 0x9f, 0x79, 0x57, 0x5e, 0x7f, 0x24, 0x67, 0xbd, 0x87, 0xc4, 0xb7, 0x31, 0xe7, 0x8c, 0xf4, + 0xfc, 0xe1, 0xf7, 0x6a, 0xdc, 0x19, 0xf6, 0x3b, 0xa6, 0x97, 0xb7, 0xce, 0x83, 0xac, 0x59, 0x49, + 0x51, 0x39, 0x47, 0xbe, 0xa5, 0x7d, 0x41, 0x44, 0x6d, 0xbe, 0x0c, 0xcd, 0x74, 0xe1, 0xc3, 0xec, + 0xdb, 0xe3, 0xea, 0x70, 0xd0, 0xf4, 0xf7, 0x51, 0xbd, 0x4e, 0xc2, 0x29, 0xaa, 0x67, 0x51, 0x80, + 0xab, 0x78, 0xc9, 0xb9, 0xef, 0x9d, 0x89, 0xf6, 0x85, 0xd5, 0xec, 0xe2, 0xe8, 0xee, 0x64, 0x63, + 0xc3, 0x78, 0x97, 0x5c, 0x54, 0x51, 0x16, 0x98, 0xcb, 0x8a, 0x2b, 0xc9, 0x3e, 0x9a, 0xd7, 0xf9, + 0xf3, 0x2b, 0x71, 0x8f, 0x29, 0x4b, 0x40, 0xe7, 0x2f, 0x7d, 0x36, 0xff, 0xe7, 0x4f, 0x28, 0xae, + 0x90, 0x25, 0x12, 0xb9, 0x12, 0x0c, 0xcf, 0xa8, 0x41, 0xa5, 0x72, 0x91, 0x95, 0x13, 0x5e, 0xb6, + 0x05, 0x63, 0x45, 0x3b, 0x8d, 0x9c, 0x9e, 0xbf, 0x2a, 0x43, 0x3d, 0x93, 0xfb, 0x06, 0x8e, 0xa3, + 0x99, 0x0c, 0xa2, 0x99, 0x52, 0x98, 0xee, 0xd0, 0xb9, 0x8c, 0x2d, 0x18, 0xa6, 0xcd, 0xf5, 0x83, + 0x2a, 0xda, 0x6c, 0xcb, 0xff, 0x4a, 0xcf, 0x50, 0x37, 0xd6, 0xbd, 0xcb, 0xda, 0xc1, 0x5f, 0xae, + 0x93, 0xae, 0xaa, 0xb0, 0xd7, 0xac, 0xd6, 0xef, 0x9b, 0x92, 0x6a, 0xff, 0xd6, 0x13, 0xa8, 0xf0, + 0xe5, 0xf4, 0x61, 0x6d, 0x8c, 0xf5, 0x41, 0x62, 0x68, 0x4d, 0x0d, 0xb3, 0x42, 0x1a, 0xda, 0xcd, + 0xea, 0x0b, 0xd8, 0x27, 0x5a, 0x4f, 0x61, 0x09, 0x8d, 0x76, 0x14, 0x5c, 0x6d, 0x70, 0xaa, 0x3e, + 0x5d, 0xa5, 0x5f, 0xff, 0x0a, 0x63, 0x1a, 0xbb, 0xec, 0xb1, 0x1f, 0x8f, 0x4f, 0xaf, 0x6a, 0x99, + 0xa3, 0x27, 0x9f, 0x15, 0xd0, 0xef, 0x07, 0xa5, 0x69, 0x75, 0x7f, 0xa1, 0xa1, 0x2a, 0xaa, 0x5f, + 0x83, 0xf3, 0x70, 0x5c, 0xd5, 0x05, 0xc9, 0x28, 0xad, 0x11, 0x1a, 0xc1, 0x13, 0xd9, 0xdc, 0xe1, + 0x0f, 0x3f, 0xd7, 0xc2, 0xd9, 0x7b, 0x5b, 0x6d, 0x39, 0x7d, 0x68, 0x13, 0x74, 0xd6, 0x4f, 0xb0, + 0xf5, 0x4d, 0x65, 0x48, 0x53, 0x73, 0x99, 0x9c, 0xa6, 0xe5, 0xbf, 0x1c, 0x69, 0x09, 0x32, 0x6a, + 0x82, 0xd2, 0xb7, 0x64, 0xe3, 0xf7, 0x38, 0xcd, 0x5a, 0x7b, 0xc7, 0xb4, 0x69, 0x9d, 0x0f, 0x5c, + 0x23, 0x4c, 0xee, 0x40, 0x12, 0xb6, 0xbe, 0x85, 0x73, 0x56, 0x4e, 0x70, 0xd7, 0x9a, 0x31, 0x44, + 0x83, 0xa2, 0x9d, 0x08, 0xe7, 0xdc, 0xa7, 0x7c, 0xe1, 0x03, 0x7e, 0xae, 0x44, 0x40, 0x6e, 0xb7, + 0xd7, 0xca, 0x28, 0xbe, 0xb5, 0xfe, 0x7d, 0x38, 0xb3, 0xb6, 0x05, 0x78, 0x11, 0x31, 0x6f, 0xcb, + 0x18, 0x1a, 0xaf, 0xea, 0xac, 0xf7, 0xe9, 0xd0, 0xb1, 0x33, 0xb9, 0x9c, 0xd7, 0x5d, 0xa4, 0x99, + 0x1b, 0xfc, 0x6d, 0x9c, 0x25, 0xb3, 0x1a, 0xae, 0xa8, 0x0c, 0xe7, 0xfc, 0x1e, 0xc3, 0xba, 0x41, + 0x25, 0x2b, 0x5f, 0xd4, 0x1c, 0x2c, 0xf5, 0x1d, 0xaf, 0x21, 0xdd, 0x2b, 0x5c, 0x7a, 0x89, 0xea, + 0xf2, 0xea, 0x64, 0x36, 0x5c, 0x8f, 0x62, 0x32, 0x98, 0xd3, 0xa2, 0x39, 0xe0, 0x5d, 0xb3, 0xb9, + 0xca, 0x13, 0x08, 0x7a, 0x6f, 0x07, 0xef, 0x9f, 0x4e, 0x3d, 0x75, 0x7a, 0x86, 0xd7, 0xb6, 0xe2, + 0x41, 0x72, 0x37, 0xd2, 0x10, 0x11, 0xdd, 0x58, 0xbe, 0xd4, 0xca, 0xd7, 0x79, 0xaf, 0x4e, 0xe0, + 0xb3, 0x71, 0xf7, 0x3a, 0xf7, 0x02, 0x9e, 0x9e, 0x61, 0xed, 0xd3, 0x96, 0x72, 0xad, 0x3c, 0xf0, + 0xa0, 0xc9, 0xa8, 0xed, 0xb0, 0x9d, 0xae, 0x20, 0x43, 0x5c, 0x6d, 0x50, 0x5c, 0xff, 0x68, 0xf1, + 0xcd, 0xee, 0xfb, 0xea, 0x56, 0xe6, 0xfc, 0x7a, 0xac, 0xe1, 0x0f, 0xd6, 0x43, 0x3c, 0x47, 0x35, + 0xcb, 0xe1, 0x6b, 0x60, 0xaf, 0x8c, 0xd8, 0x0e, 0x20, 0x33, 0xf2, 0xd3, 0x6d, 0x47, 0x30, 0x75, + 0xfc, 0x1c, 0x64, 0x2d, 0xe6, 0xbd, 0xe4, 0x97, 0xb5, 0x6f, 0xd7, 0xf8, 0xdc, 0x86, 0xb0, 0xbb, + 0x02, 0xbf, 0xe6, 0x84, 0x08, 0x6c, 0x33, 0x07, 0x67, 0xa1, 0xd0, 0xf9, 0xae, 0x26, 0xad, 0xd3, + 0xb9, 0x4f, 0x98, 0x93, 0xe3, 0xfb, 0x90, 0x52, 0x24, 0x34, 0xf8, 0xf1, 0xea, 0x39, 0xfc, 0x80, + 0x89, 0x1e, 0x5b, 0x81, 0x1c, 0x7c, 0x7d, 0x7e, 0x86, 0xc5, 0xe2, 0xbb, 0x49, 0x8d, 0x36, 0x43, + 0xad, 0xe4, 0xab, 0x60, 0xed, 0x30, 0x29, 0xb2, 0xfd, 0xc3, 0x64, 0x44, 0xbf, 0xf8, 0x1d, 0xd3, + 0xe0, 0x01, 0x72, 0x89, 0xe8, 0x4d, 0x30, 0x40, 0x0b, 0x35, 0x9e, 0x58, 0x7f, 0xb3, 0x3a, 0x42, + 0xc2, 0x99, 0x89, 0x42, 0xf7, 0xd0, 0x2b, 0xe1, 0xca, 0x44, 0x0b, 0xed, 0xd6, 0x66, 0x6f, 0x3a, + 0x60, 0xaa, 0x15, 0x8d, 0x5a, 0xeb, 0x41, 0xb8, 0x64, 0x72, 0x2a, 0x55, 0xa0, 0x6b, 0x68, 0x8a, + 0x50, 0x36, 0x1a, 0xd4, 0xfe, 0xca, 0xe8, 0x5e, 0x4d, 0x30, 0x06, 0x09, 0xc3, 0xb9, 0x52, 0x1c, + 0xe9, 0x54, 0x33, 0x7b, 0x4d, 0xf1, 0x0b, 0x01, 0xef, 0x3d, 0x1c, 0x9c, 0x5d, 0xe0, 0x6b, 0x8b, + 0xea, 0x9f, 0x61, 0x68, 0xab, 0x2f, 0xf2, 0xcd, 0xa8, 0xa5, 0x6e, 0xa7, 0x72, 0xcb, 0x58, 0x9b, + 0xc9, 0x51, 0x72, 0xfc, 0x60, 0xcd, 0xea, 0x75, 0xbd, 0x7e, 0xd9, 0x42, 0xc7, 0x00, 0x5d, 0xf8, + 0xda, 0x38, 0xb9, 0x59, 0xc0, 0x31, 0x58, 0x78, 0x6b, 0x8b, 0x5e, 0x3e, 0xdc, 0x82, 0x53, 0x30, + 0x2b, 0xc9, 0xd3, 0x7b, 0x5d, 0x31, 0xfe, 0x44, 0xa1, 0xe1, 0x2a, 0x3c, 0xcf, 0x5d, 0x25, 0xfc, + 0x26, 0x5d, 0xfe, 0x5b, 0xf8, 0x64, 0x2e, 0x17, 0x3b, 0xf2, 0x6f, 0x48, 0x00, 0xf7, 0xde, 0x44, + 0xc8, 0xaf, 0x86, 0x42, 0xe1, 0xbf, 0x5e, 0xf0, 0xa5, 0x4a, 0x79, 0x60, 0xc1, 0x4d, 0x87, 0x70, + 0x26, 0xb9, 0x15, 0x47, 0x4f, 0xd1, 0xe4, 0xc8, 0x02, 0x6b, 0xaa, 0xa8, 0xdf, 0xbf, 0xd1, 0x97, + 0x43, 0xe1, 0x14, 0xd7, 0xf0, 0x98, 0xc6, 0x7e, 0x1d, 0x5e, 0x0d, 0x27, 0xed, 0xf8, 0x15, 0xad, + 0x58, 0xb6, 0x6b, 0xa1, 0x2f, 0x86, 0xd2, 0xf6, 0x64, 0x7d, 0xcb, 0xa5, 0x54, 0x2a, 0x53, 0x3a, + 0xad, 0x88, 0xd4, 0x52, 0x3a, 0x2a, 0xdc, 0x09, 0xc7, 0x22, 0x6d, 0x9e, 0xb4, 0xe9, 0x59, 0x28, + 0x38, 0x50, 0xbc, 0x23, 0xac, 0xdb, 0x94, 0xaa, 0x4d, 0x4e, 0x29, 0xc1, 0xe0, 0x48, 0x1e, 0xee, + 0x2a, 0xa5, 0xe3, 0x3a, 0xb4, 0x2b, 0x23, 0xad, 0xa3, 0xcc, 0x84, 0x9a, 0x82, 0xa3, 0x42, 0x0a, + 0xbd, 0x08, 0xc5, 0xd5, 0x4e, 0x96, 0x48, 0xed, 0x71, 0xfd, 0x1e, 0xa7, 0x11, 0xd9, 0x3b, 0xa6, + 0x45, 0x00, 0x31, 0xa4, 0x19, 0x0b, 0x09, 0xc3, 0x23, 0x8c, 0x19, 0xb5, 0x30, 0x10, 0xe6, 0x3b, + 0x75, 0xcd, 0xa8, 0x7d, 0xb7, 0xc9, 0x10, 0x08, 0x6c, 0x80, 0x35, 0x17, 0x57, 0xa0, 0x15, 0xc9, + 0xbd, 0xa7, 0x4d, 0x9a, 0xbe, 0xba, 0x90, 0xa8, 0x2e, 0x23, 0x55, 0xca, 0xa9, 0xd3, 0x86, 0xd4, + 0x0a, 0xda, 0x1a, 0xc9, 0xc9, 0x24, 0x0b, 0x7d, 0xed, 0x86, 0x3c, 0xd8, 0xb2, 0x46, 0x90, 0x3f, + 0xf4, 0xa6, 0x86, 0x90, 0x3a, 0x72, 0x6b, 0xd6, 0x19, 0x48, 0x16, 0xe7, 0xaa, 0xe1, 0x99, 0xe3, + 0x7c, 0x25, 0xad, 0x11, 0x13, 0x72, 0x89, 0x29, 0x99, 0xc0, 0x7d, 0x35, 0xb2, 0x21, 0x83, 0xee, + 0x10, 0xa2, 0x5e, 0x73, 0x10, 0x07, 0xc7, 0x8d, 0xb6, 0xd0, 0x84, 0xd1, 0xee, 0xfe, 0x32, 0x3e, + 0x3c, 0x44, 0xe8, 0xbc, 0x31, 0x35, 0x4d, 0xfa, 0xe2, 0x6c, 0x06, 0xa7, 0xe7, 0x20, 0x03, 0x52, + 0x8f, 0xdb, 0x33, 0x15, 0xcb, 0xe3, 0xcc, 0x83, 0x0c, 0x00, 0x28, 0x65, 0x8b, 0x48, 0xfd, 0x31, + 0x39, 0x2d, 0x36, 0x54, 0x2a, 0x69, 0x5f, 0x90, 0x78, 0xa8, 0x92, 0xa6, 0xfb, 0x21, 0xf3, 0x0e, + 0xb9, 0x1a, 0x49, 0xce, 0xbf, 0x36, 0x43, 0xc5, 0x44, 0x38, 0x91, 0xb3, 0x9e, 0x27, 0xc0, 0x2c, + 0x0b, 0x78, 0x84, 0x82, 0xac, 0x54, 0xbd, 0xcf, 0x23, 0x8a, 0x22, 0x1d, 0x81, 0x17, 0xbd, 0xeb, + 0x19, 0x5e, 0x79, 0x18, 0xa4, 0x32, 0x61, 0x9d, 0x07, 0xca, 0x7d, 0x75, 0x44, 0x75, 0x76, 0x14, + 0x30, 0x69, 0x4d, 0x4e, 0x3d, 0x64, 0xb1, 0xd5, 0xc0, 0xed, 0xb6, 0x41, 0x63, 0xed, 0xb2, 0x7b, + 0xc8, 0xe5, 0x4b, 0xa8, 0xa2, 0x77, 0xae, 0xc3, 0x65, 0x0d, 0x1f, 0xad, 0x41, 0x9d, 0xab, 0x60, + 0xdb, 0xaa, 0x00, 0x2a, 0x2a, 0xa6, 0x8e, 0x70, 0x57, 0x5f, 0x62, 0x74, 0x57, 0x57, 0x37, 0xc9, + 0xbe, 0x42, 0x0b, 0x83, 0xeb, 0x97, 0x4c, 0xd4, 0xa0, 0x7b, 0x69, 0xe6, 0x90, 0x9d, 0x11, 0xc2, + 0x2c, 0x3c, 0x52, 0x6b, 0x4f, 0x29, 0xcf, 0xef, 0xff, 0x7c, 0x37, 0x67, 0xde, 0x31, 0x1d, 0xca, + 0xfb, 0x14, 0xff, 0x89, 0xa8, 0x41, 0x44, 0x07, 0xdb, 0xa0, 0x04, 0x34, 0x0f, 0x10, 0xf2, 0xc6, + 0x3a, 0x6e, 0x2b, 0x45, 0x45, 0x15, 0x98, 0x38, 0x41, 0x38, 0xb1, 0xf3, 0x5f, 0x15, 0x7e, 0x0e, + 0x71, 0x27, 0x3b, 0xd6, 0x3a, 0x02, 0xa9, 0x05, 0x77, 0x21, 0xec, 0x25, 0xa3, 0x6f, 0xa6, 0x19, + 0x86, 0x7a, 0xa8, 0xcb, 0x68, 0x20, 0x30, 0x6b, 0x64, 0xf3, 0xfe, 0x81, 0xde, 0x16, 0x4d, 0xf0, + 0x0c, 0x21, 0x7b, 0x1a, 0x65, 0x84, 0x9c, 0xb7, 0x6c, 0xa3, 0xfd, 0xb6, 0xfc, 0xb6, 0x54, 0x06, + 0x87, 0x9f, 0xa1, 0xab, 0x6b, 0xda, 0x0b, 0x6a, 0xe9, 0xdd, 0xf0, 0x45, 0xfd, 0x9c, 0x1a, 0xf6, + 0x6f, 0x0d, 0xce, 0x59, 0x25, 0x73, 0x1c, 0x48, 0xaa, 0x43, 0xa8, 0x80, 0xc5, 0xe4, 0x54, 0x2f, + 0x4f, 0x54, 0x1d, 0x5a, 0x8d, 0xb3, 0xbb, 0x9c, 0x33, 0x77, 0x68, 0x0b, 0x84, 0x67, 0xe1, 0x89, + 0x3d, 0xd2, 0x7b, 0xc1, 0x06, 0x75, 0xf2, 0xa1, 0x5a, 0x44, 0xd2, 0x42, 0x93, 0x53, 0xf1, 0xaf, + 0xf6, 0xaa, 0x21, 0x06, 0xcf, 0x17, 0xc3, 0x1a, 0x12, 0x2e, 0xa6, 0x64, 0x8b, 0xac, 0xfe, 0x31, + 0x30, 0xd3, 0x16, 0x12, 0x3a, 0x27, 0x50, 0x35, 0x5e, 0x0c, 0x95, 0xe3, 0xac, 0xf7, 0x64, 0x95, + 0x03, 0x06, 0x5e, 0x55, 0xd2, 0x4c, 0x04, 0x57, 0xcb, 0xeb, 0x8e, 0x21, 0xa6, 0xf9, 0x76, 0xde, + 0x15, 0xa6, 0xc0, 0xe7, 0x89, 0x8a, 0x71, 0x8d, 0xad, 0x25, 0xe7, 0xd4, 0x57, 0x8f, 0xa3, 0x9b, + 0xe3, 0x1f, 0x43, 0x6c, 0xa9, 0x17, 0xf5, 0xe2, 0xb7, 0x4f, 0xc1, 0xf3, 0x9a, 0xaa, 0x74, 0xed, + 0x9d, 0xb5, 0xda, 0xa7, 0xea, 0x2a, 0x06, 0xef, 0xb2, 0x84, 0xc6, 0x48, 0x1a, 0x5e, 0xa9, 0xa1, + 0x8d, 0x44, 0xfb, 0xe9, 0xec, 0x2e, 0xc1, 0x9c, 0xe3, 0x07, 0xee, 0xab, 0x20, 0x74, 0xdf, 0x0b, + 0x68, 0x0c, 0x6e, 0xa4, 0x99, 0xab, 0xbe, 0x5c, 0x15, 0xf3, 0xe8, 0xdf, 0x27, 0x0c, 0x8d, 0xb7, + 0xe3, 0xc7, 0x47, 0xbc, 0x86, 0x30, 0x21, 0x3f, 0x7f, 0xfe, 0x87, 0x5a, 0x7e, 0xe5, 0x3b, 0xa6, + 0xe1, 0xd5, 0x86, 0x9b, 0x52, 0x2c, 0xe4, 0xaf, 0xfe, 0xfb, 0xe5, 0xa0, 0xe3, 0x66, 0x25, 0x65, + 0x88, 0x77, 0xb6, 0x5f, 0xbf, 0x76, 0xaf, 0x17, 0x0e, 0x9c, 0x0a, 0x39, 0x49, 0x44, 0x1a, 0x27, + 0x07, 0x8b, 0x4e, 0xa4, 0x76, 0xf0, 0xab, 0x76, 0xe9, 0xe7, 0xce, 0x4b, 0x44, 0xce, 0x9a, 0x5d, + 0x7e, 0x11, 0xb2, 0xda, 0xf1, 0x78, 0x56, 0x03, 0x46, 0x2e, 0xdf, 0x3e, 0x63, 0x54, 0x3e, 0x9e, + 0xce, 0x29, 0x7c, 0xe1, 0x6c, 0x34, 0xdd, 0xa0, 0xea, 0xaf, 0x68, 0x14, 0xcf, 0x6f, 0x8e, 0x5e, + 0x81, 0xcd, 0x84, 0xf0, 0xb5, 0x5a, 0xbb, 0x4d, 0x43, 0x75, 0x12, 0xb3, 0x5a, 0xbb, 0xda, 0x3f, + 0x79, 0xcd, 0xbb, 0x4e, 0x0e, 0xf6, 0x29, 0x49, 0xd9, 0x55, 0x3d, 0xc8, 0xee, 0xf0, 0x7d, 0xda, + 0xf6, 0xed, 0x68, 0x37, 0x32, 0x66, 0xa3, 0x67, 0x9d, 0x97, 0x50, 0xc9, 0x11, 0x9a, 0x89, 0x3d, + 0xe9, 0x92, 0xb3, 0x50, 0x4c, 0x29, 0xd5, 0xab, 0xc6, 0x32, 0x0d, 0xab, 0x68, 0xad, 0xf7, 0x2a, + 0xd3, 0x6d, 0x27, 0x4b, 0x2b, 0x42, 0x2f, 0x9d, 0x7d, 0xc9, 0x10, 0x41, 0x9a, 0x66, 0xaf, 0xc7, + 0x3b, 0x25, 0x85, 0x65, 0x37, 0x1c, 0x53, 0x1f, 0x03, 0x0d, 0xde, 0xb1, 0xc5, 0x9b, 0x15, 0x22, + 0x6e, 0x25, 0x5a, 0xb5, 0x49, 0xe1, 0xdb, 0x64, 0xcf, 0x3a, 0x55, 0x57, 0x8a, 0xc6, 0xbd, 0x06, + 0x0b, 0x31, 0x53, 0x4b, 0x74, 0x35, 0x1c, 0x08, 0xc5, 0x73, 0x22, 0x27, 0x6d, 0x15, 0x7a, 0xd2, + 0xdc, 0x3c, 0xa7, 0x6c, 0xc1, 0x18, 0x24, 0x7a, 0x4e, 0x65, 0xbe, 0x1d, 0xf6, 0x17, 0x97, 0x8b, + 0xb2, 0x55, 0x49, 0x68, 0x20, 0x38, 0x9c, 0x4c, 0x88, 0xf8, 0xa7, 0x76, 0x01, 0x47, 0x32, 0x81, + 0x58, 0x97, 0xd4, 0xee, 0x72, 0xa9, 0xeb, 0x8b, 0x90, 0x04, 0xec, 0x35, 0x15, 0xe0, 0xf8, 0xb8, + 0x0b, 0x87, 0xed, 0x89, 0xa8, 0x35, 0xf5, 0xdc, 0x9a, 0x31, 0x01, 0xe7, 0x63, 0xb1, 0x92, 0x40, + 0x7d, 0x4d, 0x5a, 0x18, 0x0b, 0xfe, 0x87, 0x5a, 0x21, 0x30, 0xe5, 0xef, 0xfd, 0x29, 0x54, 0xef, + 0x98, 0xce, 0xd9, 0x0b, 0x71, 0xed, 0x03, 0x0f, 0xf7, 0xef, 0x4e, 0xb7, 0xac, 0x53, 0xbd, 0x3a, + 0x15, 0x3d, 0xbd, 0x0e, 0xe4, 0x3c, 0x50, 0x10, 0x80, 0x9f, 0xac, 0xa7, 0xb5, 0x42, 0x0e, 0x21, + 0x57, 0x0d, 0x3d, 0xd9, 0x0c, 0x17, 0xf0, 0xbc, 0x4c, 0x0b, 0x72, 0xec, 0x75, 0x0f, 0x2d, 0x28, + 0xb0, 0x48, 0xa8, 0x3d, 0x42, 0x58, 0x98, 0x59, 0x80, 0x5b, 0x23, 0x6a, 0x3e, 0x3f, 0x12, 0xc2, + 0xee, 0x22, 0x2f, 0xc4, 0xf0, 0xea, 0x22, 0xf1, 0x92, 0xba, 0xaa, 0xff, 0xc4, 0x05, 0x9b, 0xe4, + 0x49, 0x46, 0xa4, 0x0e, 0x87, 0xf1, 0xbe, 0xf3, 0xef, 0xac, 0x22, 0x73, 0xe7, 0x7a, 0x4c, 0xa8, + 0xd5, 0xce, 0x55, 0x5e, 0xea, 0xba, 0x0b, 0x64, 0x3a, 0x6e, 0x73, 0x05, 0x67, 0x89, 0x82, 0xc8, + 0x81, 0x7c, 0xfb, 0x14, 0x2d, 0x84, 0x1d, 0xd8, 0x6c, 0x7a, 0x09, 0x87, 0xc1, 0x4f, 0x07, 0x55, + 0xe7, 0xb7, 0xf5, 0x9a, 0x30, 0xee, 0x64, 0x92, 0x86, 0xd8, 0x6b, 0x1d, 0x29, 0x27, 0xc8, 0x40, + 0x5f, 0xdb, 0x80, 0x2d, 0x1b, 0xe5, 0x54, 0x92, 0x61, 0x28, 0x12, 0xcd, 0x10, 0x67, 0xff, 0xe8, + 0x8c, 0xbe, 0x7d, 0x32, 0x2d, 0x9b, 0x36, 0x1e, 0x9d, 0xfe, 0xee, 0x6a, 0xa9, 0x5f, 0x63, 0x2d, + 0xe4, 0xc6, 0x7a, 0x61, 0xfb, 0xb9, 0xe3, 0x16, 0xc3, 0x82, 0xa6, 0x69, 0x63, 0x53, 0x5d, 0x85, + 0x0b, 0x65, 0x5b, 0x54, 0xc1, 0x92, 0x5a, 0x07, 0x5e, 0x2c, 0xef, 0x86, 0x96, 0x82, 0xe5, 0xb2, + 0xfb, 0x3f, 0xd1, 0x83, 0xd1, 0xd1, 0x59, 0x12, 0xe1, 0xc9, 0xfe, 0x93, 0x29, 0x13, 0x83, 0xb3, + 0xe1, 0x06, 0x72, 0x88, 0x36, 0xc1, 0x0c, 0xdd, 0x07, 0xab, 0xa3, 0xab, 0xe9, 0xa4, 0x96, 0x3e, + 0x74, 0xc1, 0x44, 0x7c, 0x1f, 0x0e, 0xcd, 0x1d, 0x29, 0x59, 0x80, 0xe6, 0xfe, 0x27, 0x5e, 0x49, + 0x13, 0x0a, 0x90, 0xcd, 0x8f, 0x47, 0x3f, 0xb5, 0x75, 0xa7, 0x01, 0x22, 0x9b, 0xcc, 0x2a, 0xcc, + 0x45, 0x49, 0xd4, 0xd1, 0xe0, 0x3d, 0xed, 0xbd, 0xce, 0xf5, 0x3a, 0xea, 0xde, 0xef, 0xef, 0x18, + 0x70, 0xed, 0x3b, 0xa6, 0x8b, 0x95, 0x7c, 0x63, 0x6d, 0xce, 0x42, 0x9e, 0x3a, 0x1e, 0x24, 0xae, + 0x56, 0x68, 0x57, 0x70, 0xa4, 0x3c, 0x09, 0x6c, 0x94, 0x6a, 0x5e, 0x7d, 0xd2, 0xfa, 0x14, 0x2c, + 0x70, 0xef, 0x7c, 0x89, 0x4e, 0xc4, 0xe6, 0xf9, 0xa2, 0xd3, 0x72, 0x63, 0x8e, 0xf6, 0x67, 0xaf, + 0x9e, 0x6a, 0x58, 0x8e, 0x64, 0xcc, 0x54, 0x65, 0x13, 0xe9, 0x65, 0x78, 0x2e, 0x93, 0x4f, 0xd7, + 0xb7, 0x9a, 0x5b, 0xaa, 0xdb, 0x23, 0xfe, 0x75, 0x88, 0x03, 0x3b, 0xd3, 0x2b, 0x3c, 0xb3, 0x16, + 0xf5, 0xcf, 0xb9, 0xa0, 0x0a, 0x2b, 0x75, 0xe9, 0x39, 0x1c, 0xa6, 0x1d, 0x71, 0xac, 0xb9, 0x15, + 0xf5, 0xce, 0x8b, 0x34, 0x26, 0xb5, 0x23, 0xc4, 0x89, 0x05, 0x45, 0x99, 0xcc, 0x76, 0x57, 0xe2, + 0x17, 0xdb, 0x4e, 0x11, 0xc5, 0x22, 0xe8, 0xa5, 0x88, 0xcc, 0x77, 0xbc, 0xc9, 0x1c, 0xd9, 0x7d, + 0x90, 0xba, 0x4a, 0x04, 0x3c, 0x2a, 0x51, 0x5f, 0x3d, 0xad, 0x4b, 0xcb, 0x1d, 0x6f, 0x30, 0xf2, + 0x9d, 0xc4, 0x44, 0x12, 0xef, 0x29, 0x1a, 0xe2, 0x78, 0xfe, 0x4e, 0xa8, 0x16, 0x85, 0x80, 0x73, + 0x01, 0x2e, 0x0e, 0x3d, 0x19, 0x99, 0x2d, 0xbe, 0x47, 0x2d, 0x3e, 0x9d, 0x77, 0x95, 0x3a, 0x1b, + 0x7e, 0x81, 0xab, 0xca, 0xdd, 0xeb, 0xba, 0xc9, 0xbc, 0x73, 0x55, 0xec, 0x7c, 0xfb, 0x3a, 0x2c, + 0x6c, 0x3e, 0xa5, 0xef, 0x6b, 0x52, 0x43, 0xbd, 0xe5, 0xef, 0xc4, 0xbc, 0x33, 0xba, 0xa1, 0x94, + 0x18, 0xae, 0x6d, 0x19, 0x9e, 0x26, 0x93, 0xc1, 0x5f, 0x3f, 0x86, 0xd2, 0xe2, 0xf0, 0x68, 0xac, + 0xce, 0x19, 0x9d, 0x41, 0x13, 0x6f, 0x3b, 0x72, 0x07, 0x45, 0x23, 0xe7, 0xd8, 0x4b, 0xdc, 0x7a, + 0x74, 0x01, 0xcd, 0x95, 0xae, 0xe0, 0x15, 0xd0, 0xf6, 0x84, 0x33, 0xa3, 0x9e, 0xb7, 0x13, 0xec, + 0x0a, 0x81, 0xb6, 0x6e, 0xc4, 0xa7, 0xfe, 0x39, 0xbc, 0xc6, 0x6d, 0xc0, 0xcc, 0x4d, 0x41, 0x6b, + 0xbf, 0xd9, 0x03, 0x5e, 0x9c, 0xaa, 0x17, 0xce, 0x55, 0xd4, 0x2c, 0xc1, 0x2d, 0x52, 0xbc, 0x7f, + 0xfc, 0x0f, 0xfd, 0x29, 0xfc, 0xac, 0x77, 0x4c, 0xa7, 0xf0, 0x86, 0xc8, 0x32, 0xd7, 0xef, 0x7e, + 0xd4, 0x07, 0x7f, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, + 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, + 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0xfc, 0xdf, 0xe4, 0x7f, 0xef, 0x83, 0x5b, 0x2f, 0xf5, 0x5e, 0xc3, + 0x34, 0x35, 0xe7, 0x77, 0x49, 0xc6, 0xbc, 0xd5, 0xb8, 0x97, 0x11, 0x39, 0x5b, 0x8b, 0xda, 0x27, + 0x89, 0xa3, 0xb9, 0x96, 0x8f, 0xc7, 0xf7, 0x8a, 0x99, 0xc4, 0xf1, 0xde, 0x34, 0x9a, 0x85, 0xcc, + 0x74, 0x3b, 0x37, 0x0d, 0x4d, 0x81, 0xbf, 0xee, 0xa3, 0xeb, 0xa4, 0x3c, 0x91, 0x0c, 0x60, 0x7d, + 0x8d, 0x65, 0x24, 0x88, 0x3b, 0x86, 0xc3, 0xf0, 0x33, 0xbd, 0x3c, 0x67, 0xea, 0x01, 0x49, 0xad, + 0xe1, 0xfc, 0xac, 0x7b, 0x10, 0x3a, 0x35, 0x21, 0x07, 0xa9, 0x4d, 0x2b, 0xa9, 0x8a, 0x1c, 0xc7, + 0x1e, 0x93, 0x9a, 0xdc, 0x35, 0xc9, 0x36, 0x6e, 0x4e, 0x71, 0x22, 0x66, 0x3f, 0xf3, 0xf8, 0xad, + 0x3a, 0x9b, 0x49, 0xcc, 0x93, 0x92, 0x1e, 0xe0, 0x96, 0xff, 0xaa, 0x9f, 0xe3, 0x02, 0xde, 0xd9, + 0x68, 0x34, 0x6f, 0xbc, 0xa0, 0xc2, 0xbc, 0x3b, 0xff, 0xc1, 0xfc, 0x79, 0xda, 0x64, 0xb5, 0xe4, + 0x9f, 0xa7, 0x92, 0xa8, 0xd7, 0x40, 0x40, 0xe2, 0xed, 0xab, 0x56, 0x06, 0xd1, 0x00, 0xbf, 0xdf, + 0x2a, 0x98, 0x59, 0xdb, 0xfa, 0xe7, 0x7a, 0x3a, 0x13, 0x6c, 0xdf, 0x6e, 0xf9, 0x9f, 0x38, 0xfb, + 0x97, 0xf9, 0x1b, 0x3e, 0x3f, 0x3a, 0x13, 0x91, 0x05, 0x35, 0x40, 0x0d, 0x3e, 0x1f, 0xef, 0x2e, + 0x6a, 0xa1, 0x40, 0xaa, 0x1f, 0x7f, 0xf4, 0xcf, 0x8a, 0xd5, 0xee, 0x24, 0xac, 0xe3, 0xe3, 0x27, + 0x0b, 0xd6, 0x58, 0x37, 0xa4, 0xe4, 0x1c, 0x41, 0x16, 0xc5, 0x46, 0x79, 0x8f, 0x9a, 0x2f, 0x9d, + 0xb9, 0xa1, 0x65, 0xe9, 0x29, 0x9d, 0xd5, 0x80, 0xa7, 0x7c, 0xb2, 0x63, 0xae, 0x5a, 0x0e, 0xd8, + 0x50, 0x2c, 0xe8, 0x4a, 0xc7, 0xa1, 0x91, 0x3f, 0xd3, 0xbf, 0xf5, 0x34, 0xeb, 0x56, 0x7b, 0xac, + 0x92, 0x7c, 0xdd, 0x7e, 0x48, 0xb4, 0x3b, 0xf6, 0xf3, 0x04, 0x14, 0x96, 0x3a, 0x6a, 0x21, 0x23, + 0xa0, 0x35, 0xad, 0xcb, 0x4e, 0x7d, 0xf0, 0xcc, 0xdc, 0xa9, 0xe6, 0x7a, 0x0a, 0xab, 0x6b, 0xc9, + 0xd6, 0x9c, 0xf3, 0x14, 0x6e, 0x94, 0x21, 0xc5, 0x61, 0x60, 0x73, 0x74, 0xd9, 0x23, 0x3f, 0x83, + 0xf0, 0x76, 0x7b, 0x64, 0x6b, 0x01, 0x73, 0x55, 0x42, 0xef, 0xb8, 0x59, 0x4b, 0xab, 0xfd, 0x5c, + 0x00, 0xbf, 0x48, 0xaf, 0x86, 0xee, 0xfa, 0x52, 0x44, 0xd0, 0xd7, 0xce, 0x30, 0x92, 0x97, 0x4f, + 0x3f, 0x13, 0x89, 0x5e, 0xc0, 0xcb, 0xbe, 0xf5, 0x40, 0xe8, 0xb0, 0xdf, 0xc3, 0x7c, 0x1a, 0x6d, + 0x79, 0x3b, 0x10, 0xea, 0x5b, 0xef, 0xd2, 0x80, 0xe5, 0x9a, 0xae, 0x31, 0x6e, 0x60, 0xa8, 0x1e, + 0xdd, 0x42, 0x68, 0xca, 0x5a, 0x47, 0x2c, 0xd2, 0x5b, 0x75, 0x15, 0x4e, 0x2e, 0x0b, 0x8a, 0xaf, + 0x22, 0xf1, 0x81, 0x57, 0xdb, 0xed, 0x45, 0x89, 0x7b, 0x7f, 0x6d, 0x8b, 0x4f, 0x04, 0x3b, 0x07, + 0xea, 0xe6, 0xbf, 0x5e, 0x30, 0x1b, 0xb2, 0xd7, 0xb1, 0x98, 0x06, 0x17, 0xa3, 0x31, 0xd2, 0x07, + 0x65, 0xc0, 0xe9, 0x65, 0xad, 0xc0, 0x8a, 0x9d, 0x79, 0x18, 0x2b, 0x75, 0x99, 0x97, 0x94, 0x4a, + 0x88, 0x11, 0x81, 0x66, 0x94, 0xe0, 0x83, 0x4c, 0xdd, 0x3d, 0x49, 0x46, 0x23, 0x53, 0x31, 0x6b, + 0x0a, 0x81, 0xbf, 0x57, 0xe3, 0x22, 0xe2, 0x77, 0x4c, 0x83, 0x61, 0x97, 0x33, 0xd8, 0x5a, 0xb1, + 0x39, 0x3c, 0xca, 0xad, 0x91, 0x96, 0x9c, 0xac, 0x16, 0xa6, 0xcc, 0x85, 0xde, 0xa6, 0x9f, 0xc9, + 0xbe, 0xcd, 0xfd, 0x84, 0x03, 0x75, 0xf9, 0x5e, 0x97, 0x9d, 0x49, 0x09, 0xaf, 0xb3, 0x7a, 0xad, + 0x6f, 0x7e, 0xd3, 0x78, 0x3f, 0x58, 0x96, 0x89, 0xa8, 0xf3, 0xa9, 0x94, 0x7d, 0x1f, 0xd7, 0x8e, + 0x0c, 0x89, 0x04, 0x46, 0x6e, 0xf0, 0xd5, 0xfe, 0xe5, 0x8d, 0xab, 0x23, 0x2f, 0xb2, 0x2c, 0xbc, + 0xf7, 0xc9, 0xc7, 0xdf, 0x5b, 0x01, 0x72, 0x69, 0x7c, 0x49, 0x2d, 0xbd, 0x12, 0x58, 0xbb, 0x11, + 0x0e, 0x9f, 0xfe, 0x68, 0x6a, 0xce, 0x5e, 0xfc, 0xc9, 0x7e, 0xf4, 0x72, 0xb8, 0xb9, 0x25, 0x75, + 0x35, 0xd9, 0xbc, 0xfb, 0xb2, 0xac, 0x29, 0x16, 0xb9, 0xc6, 0x11, 0x23, 0xfa, 0xba, 0x4c, 0x8f, + 0x0a, 0xaf, 0x07, 0x34, 0x7c, 0xff, 0x78, 0x4f, 0xe7, 0xad, 0xf7, 0x08, 0x9c, 0x1f, 0xa4, 0xeb, + 0x8d, 0xb5, 0xc2, 0x69, 0x97, 0xf1, 0x99, 0xa7, 0x49, 0x61, 0x0b, 0xd2, 0xc4, 0x8f, 0xd0, 0x81, + 0xf3, 0xd8, 0x92, 0xa9, 0xf4, 0x75, 0x91, 0x5c, 0x91, 0xa0, 0x53, 0xf9, 0x0d, 0x45, 0x14, 0xd6, + 0xb0, 0xfb, 0x1e, 0xe6, 0x5a, 0x31, 0x43, 0xb4, 0x08, 0x1e, 0xa6, 0x3d, 0xac, 0x93, 0x05, 0x5d, + 0x35, 0x14, 0x06, 0xb6, 0x87, 0x4a, 0x31, 0x1f, 0x5f, 0xb8, 0x61, 0x68, 0x0c, 0x9e, 0x4f, 0xb9, + 0x41, 0xa4, 0x19, 0x69, 0x53, 0xfb, 0x10, 0xc5, 0x8e, 0x7d, 0x85, 0x92, 0x12, 0xcf, 0x7d, 0x3a, + 0x2f, 0xa9, 0x6e, 0x5f, 0x17, 0x40, 0x7e, 0xc3, 0xbd, 0x38, 0x97, 0x17, 0x86, 0x3a, 0x06, 0x39, + 0x9c, 0x48, 0xaa, 0x0a, 0x43, 0x3c, 0x08, 0xd0, 0x5a, 0x6b, 0xc4, 0xe6, 0xd9, 0x1e, 0x51, 0xaa, + 0xea, 0x25, 0x14, 0xee, 0x8c, 0x3a, 0x44, 0xa8, 0xe2, 0x12, 0x26, 0xd8, 0x73, 0x56, 0xe0, 0x2a, + 0x0b, 0x0b, 0x45, 0x10, 0x68, 0x1d, 0x27, 0x3c, 0xc5, 0x4a, 0x4d, 0x20, 0xef, 0x54, 0x10, 0xd8, + 0x63, 0x7a, 0xb2, 0x02, 0xff, 0x30, 0x2b, 0x58, 0xf6, 0x8e, 0x69, 0xc0, 0x60, 0xf4, 0xd8, 0x98, + 0xaa, 0xec, 0x99, 0xb7, 0xb1, 0x12, 0x4f, 0xa8, 0x7a, 0x72, 0x3b, 0xbe, 0x9a, 0x00, 0xb9, 0xda, + 0xb4, 0x94, 0x8d, 0x23, 0xc1, 0x6e, 0x64, 0xf3, 0x3c, 0xd3, 0x7b, 0x85, 0x5f, 0x46, 0xb5, 0x82, + 0x4d, 0x4b, 0xb7, 0x91, 0x7d, 0x0c, 0x59, 0x34, 0x9a, 0x12, 0x4c, 0x46, 0x8f, 0x40, 0xd2, 0x0c, + 0x3a, 0x0e, 0x31, 0xea, 0x38, 0x4a, 0x5a, 0x94, 0x73, 0xd5, 0xe8, 0x7d, 0x9d, 0xe0, 0xe3, 0x08, + 0x66, 0x16, 0x09, 0x1a, 0x66, 0x6c, 0x90, 0x5e, 0xcd, 0x96, 0xe3, 0xc3, 0xe5, 0x1e, 0x1a, 0x99, + 0x02, 0x81, 0x5f, 0xdc, 0x5e, 0x4b, 0xba, 0xc1, 0xf9, 0x09, 0x09, 0x01, 0x19, 0xe0, 0x57, 0x11, + 0xb9, 0x61, 0x14, 0x58, 0x1f, 0x48, 0xb5, 0x26, 0x10, 0xd6, 0x48, 0xe0, 0xb0, 0xbd, 0x31, 0x4b, + 0x73, 0xae, 0x52, 0xde, 0x95, 0x2a, 0xae, 0xc1, 0x43, 0x50, 0xc4, 0x74, 0x16, 0x4e, 0x8e, 0xce, + 0xda, 0xa6, 0x49, 0x4e, 0xd4, 0xec, 0x01, 0x88, 0xb6, 0xbb, 0xcb, 0xb3, 0x46, 0x29, 0xff, 0x67, + 0xa4, 0xc1, 0xd0, 0x69, 0x21, 0xcd, 0xfc, 0x2c, 0x27, 0xae, 0xbc, 0x0c, 0x58, 0x06, 0xb2, 0x70, + 0xa4, 0x6f, 0xd7, 0xce, 0x83, 0xd8, 0xed, 0x11, 0x49, 0xd9, 0x53, 0xf2, 0xc0, 0x4b, 0xf1, 0x74, + 0xf7, 0x44, 0xdb, 0x8d, 0xfb, 0x9d, 0x4d, 0x31, 0x0f, 0x0c, 0x1e, 0xf4, 0x9d, 0x24, 0x42, 0xd8, + 0xec, 0xbe, 0xd3, 0x24, 0x5c, 0xbe, 0xae, 0x85, 0x46, 0x88, 0xc7, 0x66, 0x9e, 0x44, 0xa4, 0x6d, + 0x22, 0xd7, 0xd1, 0x68, 0xc6, 0x08, 0x0c, 0x52, 0x8d, 0x02, 0xce, 0xaf, 0x68, 0x57, 0xaf, 0xea, + 0x1e, 0xf1, 0xc4, 0x7e, 0xe9, 0x9d, 0xe5, 0xdf, 0x95, 0x11, 0x21, 0x5e, 0x45, 0xf6, 0x28, 0x09, + 0x0e, 0x6b, 0x56, 0x23, 0x72, 0xad, 0x2a, 0x9d, 0xb6, 0x8e, 0x45, 0x59, 0x76, 0x1c, 0xff, 0xfb, + 0x21, 0xca, 0x19, 0x2c, 0x77, 0xd1, 0x9e, 0x82, 0x6d, 0x49, 0xd2, 0xe9, 0x70, 0x1b, 0xa8, 0x5a, + 0xff, 0xe1, 0x9e, 0xdd, 0xcc, 0x3b, 0xa6, 0x43, 0x44, 0x7a, 0x9a, 0x5d, 0xe3, 0xf4, 0x41, 0x46, + 0x27, 0x99, 0x3f, 0xd6, 0xcc, 0x98, 0xaf, 0x1b, 0x27, 0x5d, 0x5b, 0x44, 0x8b, 0x91, 0x2c, 0xbd, + 0x89, 0x0a, 0x9a, 0x63, 0x32, 0x6f, 0x83, 0xb2, 0x0d, 0x4e, 0x61, 0xee, 0xa0, 0xd9, 0xd6, 0x96, + 0x24, 0xca, 0xff, 0x44, 0xb5, 0xfb, 0x63, 0x73, 0x70, 0xce, 0xb9, 0x3f, 0xba, 0x8d, 0x99, 0x60, + 0x34, 0x68, 0x34, 0x7c, 0xcd, 0x14, 0xc6, 0xdd, 0xb2, 0x52, 0xd5, 0x97, 0x48, 0x4e, 0xa2, 0x6b, + 0x7b, 0x2e, 0x77, 0xfb, 0xf6, 0x91, 0x6a, 0x99, 0x73, 0xc7, 0x2e, 0x57, 0x33, 0x1a, 0xee, 0x9f, + 0xdc, 0x96, 0x21, 0xff, 0x45, 0x17, 0x06, 0x9a, 0x27, 0xf0, 0xdb, 0x5a, 0xf1, 0x67, 0x53, 0x46, + 0xe7, 0x69, 0x87, 0x53, 0x02, 0x56, 0x19, 0xa8, 0x01, 0x98, 0x49, 0xf5, 0xf7, 0x06, 0x0f, 0x95, + 0xb6, 0xed, 0x31, 0x3b, 0xf3, 0x54, 0x36, 0xb2, 0x1e, 0x84, 0xe7, 0x0a, 0xcf, 0x2a, 0x27, 0x77, + 0xf5, 0x5f, 0x0d, 0xcf, 0x7a, 0x9e, 0x60, 0x9a, 0xf3, 0x68, 0x37, 0xd0, 0xb1, 0xc2, 0xff, 0xba, + 0xd1, 0xc9, 0xb5, 0xc1, 0x96, 0x24, 0x7d, 0xdc, 0x9c, 0x7b, 0xf9, 0xea, 0x53, 0xa7, 0x93, 0x8f, + 0x5e, 0xd3, 0xcc, 0xa6, 0xed, 0xea, 0x2e, 0x44, 0x12, 0xda, 0xbf, 0x03, 0xc5, 0x1c, 0xdf, 0x75, + 0xa3, 0x7d, 0x92, 0x56, 0xda, 0xb5, 0x3c, 0x6e, 0x0d, 0x0d, 0xf9, 0xd6, 0xd4, 0x43, 0x98, 0xab, + 0xd0, 0x15, 0xc1, 0x27, 0xf2, 0x1c, 0x35, 0x99, 0x4e, 0xeb, 0x89, 0x5c, 0x21, 0x98, 0x5d, 0xe9, + 0x95, 0x1d, 0xc4, 0xd4, 0xbe, 0x69, 0x4e, 0x16, 0x39, 0x02, 0x43, 0x66, 0x08, 0x9e, 0x83, 0x22, + 0x99, 0x95, 0x2f, 0x25, 0x09, 0x73, 0xfe, 0x61, 0x12, 0xd5, 0x95, 0x5e, 0xdc, 0x92, 0x22, 0x52, + 0xc5, 0xd8, 0xc9, 0xda, 0xfd, 0xcf, 0x97, 0x62, 0xe6, 0xf9, 0x0a, 0xf9, 0xec, 0xac, 0x4f, 0x64, + 0xc8, 0x9e, 0x5f, 0x3e, 0x0e, 0x5b, 0xd2, 0xcb, 0x78, 0x49, 0x2a, 0x52, 0x8a, 0xa1, 0x70, 0xb8, + 0x4a, 0x14, 0xcb, 0xd1, 0xdf, 0x6f, 0x9e, 0x37, 0x95, 0xef, 0x98, 0x86, 0xf9, 0xa2, 0xaf, 0x14, + 0xb7, 0x98, 0xaf, 0xb9, 0x0a, 0x7d, 0xc5, 0xb1, 0x76, 0x37, 0x9c, 0x0e, 0x62, 0x42, 0x09, 0x10, + 0xf1, 0x92, 0x6a, 0x41, 0x79, 0x1f, 0x5b, 0xe4, 0x89, 0x98, 0xb0, 0xd8, 0x6e, 0x9d, 0x22, 0x25, + 0x22, 0x58, 0xcd, 0x46, 0xe1, 0x2e, 0xd0, 0x86, 0x1c, 0x89, 0x50, 0xea, 0x26, 0xeb, 0xd3, 0x3c, + 0x14, 0xca, 0x68, 0x04, 0xa6, 0x4c, 0x80, 0x3c, 0x58, 0xd8, 0xf3, 0x2c, 0x15, 0xcb, 0x26, 0xd8, + 0xb3, 0x86, 0x3b, 0x9b, 0x5e, 0xb8, 0x8f, 0xdc, 0x4d, 0x02, 0xa3, 0x23, 0xd7, 0x09, 0x53, 0x65, + 0xbd, 0xa7, 0x79, 0xd4, 0xf1, 0xd4, 0x5f, 0x59, 0x91, 0x3b, 0xff, 0xdd, 0x8a, 0x37, 0xe4, 0x43, + 0xfd, 0xd2, 0xd3, 0xab, 0x2a, 0x53, 0xa5, 0xc3, 0xd3, 0xd1, 0x00, 0xdc, 0xf3, 0xcf, 0x8c, 0xb4, + 0xd7, 0x27, 0x5f, 0xfe, 0x74, 0x39, 0x5c, 0x37, 0xa3, 0x6f, 0x1a, 0x06, 0xda, 0x07, 0x7f, 0xe2, + 0x8b, 0xcb, 0x9b, 0x2f, 0x58, 0xba, 0x58, 0x3a, 0xf4, 0xcc, 0xa6, 0x28, 0x77, 0x73, 0xad, 0xd4, + 0x09, 0xff, 0x80, 0x24, 0xf7, 0x55, 0x84, 0x11, 0xa6, 0xb7, 0x9b, 0xac, 0x91, 0xf1, 0x12, 0xdb, + 0xf8, 0xa5, 0x1d, 0xa0, 0xd5, 0xb8, 0xc5, 0x34, 0xb3, 0x52, 0x01, 0x89, 0xcb, 0x82, 0x4e, 0x70, + 0x3f, 0x95, 0x54, 0x7b, 0x3b, 0xd3, 0xde, 0xc0, 0x1d, 0x08, 0xf6, 0x17, 0xc3, 0xad, 0x34, 0x38, + 0x47, 0xe3, 0xb2, 0xca, 0xaa, 0xed, 0xfc, 0x2c, 0x33, 0x39, 0xe2, 0xfb, 0x37, 0x36, 0x64, 0xbe, + 0x20, 0x6d, 0x92, 0x6d, 0x0f, 0xa3, 0xb8, 0xd0, 0x8b, 0xcd, 0x6e, 0x50, 0xe1, 0x47, 0x8a, 0x87, + 0x92, 0xfe, 0xca, 0x96, 0xda, 0x7c, 0x9d, 0x4f, 0xa2, 0x9d, 0xb3, 0x8c, 0xc4, 0xd1, 0x12, 0x26, + 0xf4, 0xb8, 0x4f, 0xa3, 0xe7, 0xde, 0x77, 0x2a, 0xaa, 0x8c, 0xc7, 0xed, 0xcc, 0x88, 0x64, 0xa4, + 0x09, 0x4b, 0x0d, 0xca, 0x4c, 0x19, 0xbf, 0xea, 0x65, 0x41, 0xcb, 0x47, 0x57, 0x24, 0x3b, 0x6f, + 0x38, 0x9f, 0xa8, 0x0a, 0x76, 0xf4, 0x77, 0xd3, 0xb8, 0xea, 0x1d, 0xd3, 0x79, 0x6c, 0x9c, 0xaa, + 0x13, 0x66, 0x85, 0x87, 0xb2, 0x12, 0x2e, 0x64, 0x75, 0xf2, 0xea, 0x13, 0xd0, 0xba, 0x9e, 0x33, + 0xee, 0x04, 0xfa, 0xdd, 0xbd, 0x5f, 0xe3, 0xcf, 0x8f, 0x2f, 0xfd, 0x2f, 0x5b, 0xa8, 0xa4, 0x61, + 0xba, 0x75, 0x3a, 0x2d, 0x84, 0xee, 0xc8, 0xfc, 0xda, 0xb8, 0xad, 0x76, 0x1b, 0x7a, 0x73, 0x01, + 0xa7, 0x6a, 0xcb, 0x48, 0x6a, 0xdc, 0x5d, 0xa9, 0xd7, 0x6b, 0x91, 0xc1, 0x5d, 0x7c, 0x19, 0xbe, + 0x35, 0xdc, 0x4f, 0x99, 0x72, 0x8d, 0x89, 0xdd, 0x65, 0x9b, 0x01, 0x60, 0x2b, 0xfe, 0xfd, 0xa1, + 0x85, 0x0d, 0x61, 0xdb, 0x43, 0x41, 0x68, 0xfc, 0xdf, 0x8c, 0xb2, 0x2d, 0xef, 0xea, 0xa7, 0x27, + 0xa0, 0xf9, 0x75, 0x34, 0x8e, 0xaa, 0xa7, 0x1b, 0x39, 0x61, 0x50, 0x52, 0xad, 0x0d, 0xe8, 0xd0, + 0x0e, 0x34, 0x6a, 0x75, 0xc5, 0x07, 0xd0, 0x65, 0xa5, 0xda, 0xe7, 0x62, 0xce, 0xe5, 0xa2, 0x81, + 0xc0, 0x12, 0x91, 0x63, 0x8b, 0x90, 0xbc, 0xd9, 0xc2, 0xae, 0xf0, 0x17, 0x84, 0xb6, 0x7d, 0x11, + 0x15, 0xf6, 0x42, 0xd9, 0x34, 0x57, 0x3f, 0x53, 0xe7, 0x27, 0x7c, 0x9a, 0x95, 0x70, 0xf8, 0x2c, + 0xba, 0xba, 0xa8, 0xd7, 0x88, 0x27, 0x39, 0xb3, 0x09, 0x5e, 0x63, 0x6a, 0xce, 0x5e, 0x89, 0xa4, + 0x57, 0xb3, 0xd4, 0x29, 0x0a, 0x88, 0xff, 0xea, 0xd7, 0x87, 0xe1, 0xf6, 0x01, 0xc1, 0xf7, 0xfe, + 0x07, 0x92, 0x6f, 0x19, 0x29, 0xbc, 0x1f, 0x33, 0x5d, 0xdf, 0x30, 0x0c, 0x3f, 0xbd, 0x37, 0x62, + 0xd9, 0xab, 0x02, 0xe8, 0x57, 0xb1, 0x76, 0xd2, 0x9e, 0x0d, 0x7a, 0xb0, 0x75, 0x14, 0x4e, 0xd7, + 0x36, 0xeb, 0x2d, 0x2f, 0x30, 0xed, 0xa9, 0x5f, 0x5a, 0x09, 0xbb, 0xde, 0xde, 0xab, 0xc4, 0xea, + 0x11, 0x7f, 0x07, 0x8b, 0x37, 0x3f, 0x19, 0x06, 0x78, 0xf8, 0x76, 0x59, 0x11, 0x80, 0xa2, 0xeb, + 0xf6, 0xe7, 0xea, 0x4b, 0xda, 0x07, 0x5f, 0xf6, 0xcb, 0x47, 0x83, 0x9d, 0x71, 0x75, 0x3b, 0x5c, + 0x4b, 0x2c, 0xdb, 0xb5, 0xda, 0xd9, 0x05, 0x69, 0xe3, 0x1f, 0xee, 0x8e, 0x6a, 0xdf, 0x31, 0x7d, + 0x8b, 0x83, 0x48, 0xb8, 0x2b, 0x69, 0x9c, 0x0f, 0xa3, 0x92, 0xef, 0x91, 0x7a, 0x10, 0xa5, 0x53, + 0x63, 0x4a, 0xa0, 0x1b, 0xaa, 0x94, 0xa9, 0x06, 0x22, 0xd3, 0x4b, 0xe3, 0x7d, 0xa6, 0x35, 0x71, + 0x75, 0x89, 0x2d, 0x50, 0xf8, 0xd0, 0xd4, 0xad, 0xd8, 0x22, 0xbf, 0x46, 0xe3, 0xbe, 0x46, 0x54, + 0x25, 0x88, 0x78, 0x90, 0x73, 0x03, 0x6b, 0xe4, 0x91, 0x84, 0xe4, 0xba, 0xbf, 0x6b, 0x1d, 0x21, + 0x5e, 0x71, 0x3c, 0x47, 0x04, 0xd3, 0x8b, 0x65, 0xcc, 0xab, 0xc6, 0x75, 0x68, 0x17, 0xb7, 0x7e, + 0x87, 0xce, 0x1f, 0x42, 0x51, 0x4c, 0xd6, 0xee, 0x58, 0x0d, 0x27, 0x6c, 0xc9, 0x5f, 0x97, 0x41, + 0x3f, 0xe7, 0x2f, 0xb7, 0x23, 0x37, 0x78, 0x72, 0x2a, 0x65, 0x5d, 0x93, 0xdb, 0xf3, 0x65, 0xab, + 0xfc, 0xf4, 0xba, 0x5e, 0x2a, 0xed, 0x5f, 0x04, 0x78, 0x47, 0x47, 0x30, 0x37, 0xf6, 0xbd, 0x99, + 0xe9, 0x9a, 0x7b, 0xe7, 0xcd, 0x50, 0xce, 0xbc, 0x4f, 0xf2, 0x72, 0x1e, 0xe9, 0xee, 0x16, 0xf0, + 0x35, 0xda, 0x8a, 0xf2, 0x78, 0x96, 0x13, 0x06, 0x6d, 0xf6, 0x21, 0x2f, 0x60, 0x56, 0x7b, 0x11, + 0xae, 0x5a, 0x9b, 0x7d, 0x4d, 0xd5, 0x6c, 0x42, 0x43, 0xfa, 0x27, 0xb9, 0xdb, 0x3f, 0x30, 0x3b, + 0x4f, 0x76, 0x0e, 0xa8, 0xae, 0x9a, 0x2a, 0xa1, 0xb4, 0x14, 0x58, 0x24, 0xb1, 0x7f, 0x93, 0x80, + 0x53, 0xa0, 0x62, 0x54, 0x8f, 0x68, 0x17, 0x1c, 0xcb, 0x37, 0xc1, 0x65, 0x71, 0xd1, 0x78, 0xd1, + 0x86, 0xb7, 0x9c, 0x24, 0xa7, 0x4b, 0xbb, 0x35, 0x9d, 0xe4, 0xd0, 0xe7, 0xe9, 0x97, 0xbf, 0x93, + 0x5a, 0x49, 0x14, 0xea, 0xba, 0x1f, 0x04, 0x71, 0xe2, 0x31, 0x8b, 0xde, 0xbf, 0xb4, 0xbb, 0x5c, + 0x38, 0xf2, 0x93, 0xe4, 0xb8, 0x12, 0x6b, 0xea, 0x0a, 0x3a, 0xb5, 0x12, 0xf4, 0x25, 0x55, 0xcd, + 0xe4, 0x62, 0x67, 0xe1, 0x4e, 0xd8, 0xea, 0x1a, 0x73, 0xb4, 0x42, 0xf2, 0x7f, 0x57, 0xe6, 0x2d, + 0xd0, 0x2e, 0x57, 0x1d, 0x17, 0xeb, 0xf4, 0xc5, 0xdf, 0xbb, 0x26, 0x00, 0x08, 0xeb, 0x1d, 0xd3, + 0xc9, 0xd1, 0x9e, 0xdf, 0x27, 0x95, 0xd6, 0xe4, 0x5e, 0x9c, 0x85, 0x98, 0x6b, 0xa1, 0x34, 0x4a, + 0xb7, 0x48, 0xa1, 0x81, 0xef, 0xc4, 0x7b, 0xd7, 0x75, 0xe4, 0xa1, 0x38, 0x78, 0xa2, 0x5f, 0xfa, + 0x08, 0xac, 0x64, 0xaf, 0x9b, 0x8f, 0x7b, 0xa3, 0xb2, 0xec, 0x47, 0x50, 0xf2, 0x24, 0x81, 0xa9, + 0xf9, 0x3f, 0x11, 0x8d, 0xc8, 0x0a, 0xeb, 0xfd, 0x0b, 0x49, 0x9e, 0xe1, 0x2e, 0xdd, 0x99, 0xa8, + 0xf7, 0x5f, 0x4d, 0x7d, 0xa3, 0xcf, 0x23, 0xc2, 0x4d, 0xbb, 0xea, 0x7a, 0x34, 0x16, 0xd7, 0x04, + 0x44, 0x2e, 0xdf, 0xf9, 0x64, 0xb3, 0xd6, 0x64, 0xad, 0x77, 0x12, 0x00, 0x7d, 0xfb, 0x59, 0x1f, + 0x4d, 0xe8, 0xe7, 0xf3, 0x0a, 0x09, 0x26, 0x7f, 0x24, 0xc9, 0x87, 0x8d, 0xf8, 0x55, 0x7f, 0x3e, + 0xcc, 0x39, 0x83, 0xc6, 0xa5, 0xfb, 0x26, 0xa4, 0x3e, 0xb8, 0x3c, 0x9b, 0xca, 0xac, 0x5a, 0xa3, + 0x27, 0x1a, 0x45, 0xe2, 0xeb, 0x84, 0x25, 0x8b, 0xf6, 0x37, 0x13, 0xd4, 0x79, 0xd0, 0x3f, 0xbc, + 0x8b, 0xab, 0xb4, 0x84, 0xd5, 0xd5, 0x6b, 0x48, 0x5c, 0xfd, 0x99, 0x95, 0xaa, 0x5c, 0x52, 0x99, + 0x74, 0xa0, 0x5d, 0x4b, 0x5a, 0x68, 0x6b, 0x1c, 0xe0, 0xd2, 0xa7, 0x9f, 0xff, 0xdd, 0x5d, 0x20, + 0x2d, 0x32, 0x62, 0x68, 0x77, 0xff, 0x8d, 0x19, 0xee, 0x1e, 0x5b, 0xed, 0xdb, 0xb8, 0x49, 0x86, + 0xc6, 0x05, 0x32, 0xfb, 0x50, 0x67, 0x15, 0x21, 0x2f, 0x56, 0x5f, 0x30, 0x89, 0x9b, 0x80, 0xc7, + 0x9f, 0x95, 0x7e, 0xfd, 0xbe, 0xda, 0xaf, 0x13, 0xa9, 0x5f, 0x15, 0xf5, 0x38, 0xa8, 0xb0, 0x66, + 0xc6, 0xc1, 0x04, 0xab, 0xcc, 0xa1, 0x32, 0x85, 0x79, 0x43, 0x2f, 0x81, 0x15, 0xc8, 0x00, 0x3c, + 0xd9, 0x94, 0xdc, 0x25, 0xd6, 0x34, 0x20, 0xfd, 0x9f, 0xf0, 0x4d, 0x42, 0xf7, 0xd3, 0x2f, 0x92, + 0x53, 0xd2, 0x6e, 0x55, 0x4e, 0xc3, 0x44, 0x14, 0x36, 0x3a, 0xa1, 0xc4, 0x5f, 0x17, 0xdd, 0xdd, + 0xa5, 0x78, 0xfd, 0x92, 0xb2, 0xcb, 0xdd, 0x0e, 0x2a, 0x1f, 0xb6, 0xfc, 0x3e, 0xc1, 0xd6, 0x6f, + 0x7a, 0xc7, 0xf4, 0x9c, 0x15, 0x8d, 0xe3, 0xf3, 0xcb, 0xf8, 0xeb, 0x2e, 0xf3, 0x4f, 0x74, 0xec, + 0x11, 0xa6, 0xf8, 0x3e, 0x9b, 0x9f, 0xe7, 0xc4, 0x4f, 0x54, 0x1b, 0xc5, 0x60, 0xa7, 0xa8, 0x4b, + 0x47, 0xe7, 0xe0, 0xd8, 0xa5, 0x67, 0x66, 0x63, 0x12, 0x3b, 0x4b, 0x47, 0x52, 0x46, 0x5b, 0x54, + 0xb5, 0x68, 0x0c, 0x9f, 0xac, 0xae, 0x64, 0xa3, 0x77, 0x01, 0x99, 0xd0, 0x9d, 0x26, 0x10, 0x44, + 0xe9, 0xdd, 0x5c, 0x6d, 0x98, 0x5f, 0xd3, 0x61, 0x40, 0xef, 0x6f, 0x76, 0xcb, 0x66, 0x68, 0xae, + 0x54, 0xf0, 0x86, 0xe0, 0xcf, 0xdb, 0xce, 0xd0, 0x34, 0xb3, 0xd9, 0xc5, 0x64, 0x94, 0x4e, 0xe9, + 0x59, 0x5c, 0x46, 0xc2, 0x91, 0xa4, 0x80, 0xf2, 0xea, 0x67, 0xe6, 0xac, 0xe7, 0xee, 0xb5, 0xa5, + 0xd3, 0x7b, 0x5a, 0xc5, 0xef, 0xba, 0xc6, 0x1d, 0x89, 0xde, 0x3d, 0x37, 0x55, 0x29, 0x8c, 0xd0, + 0xa7, 0x5f, 0x4f, 0xee, 0x6a, 0xf2, 0xb6, 0xbb, 0xed, 0x56, 0xaa, 0xc1, 0xd3, 0xab, 0x2a, 0xf7, + 0x8c, 0xbe, 0x43, 0xb1, 0xa2, 0xd1, 0x11, 0x9a, 0xe7, 0x97, 0xb5, 0x08, 0xc3, 0x85, 0x87, 0x36, + 0x24, 0x86, 0x33, 0x44, 0x6c, 0xab, 0xef, 0xbf, 0xdc, 0x4c, 0xb7, 0xbb, 0x2c, 0x64, 0x5e, 0xf2, + 0xd3, 0x23, 0xd6, 0xf5, 0x12, 0xc1, 0xa5, 0x5e, 0xef, 0x95, 0x85, 0x89, 0x39, 0x47, 0xf4, 0x5a, + 0xcf, 0x3a, 0x3e, 0xbd, 0xa1, 0x8c, 0x44, 0x82, 0xf9, 0xb9, 0x0a, 0x8a, 0xd7, 0xd4, 0x16, 0x51, + 0xd4, 0x1a, 0xf7, 0x04, 0xaf, 0xfa, 0x0b, 0xc5, 0xfd, 0x89, 0xaa, 0x5f, 0x1c, 0x7b, 0x28, 0x39, + 0xae, 0xae, 0x88, 0xf9, 0x26, 0x85, 0x05, 0x0f, 0x21, 0x7f, 0x9f, 0x7c, 0xe1, 0x64, 0xca, 0xcc, + 0xa5, 0x22, 0xe0, 0x43, 0xa6, 0x15, 0x2d, 0x72, 0xd8, 0xe7, 0xf1, 0xc8, 0x4f, 0x75, 0x3e, 0xac, + 0x5f, 0x9d, 0xd7, 0x6d, 0xc6, 0x4d, 0xc1, 0xca, 0xb9, 0xf3, 0x01, 0x8e, 0x01, 0xd7, 0x6d, 0xe5, + 0x5a, 0x51, 0x96, 0x96, 0xc7, 0x20, 0x03, 0x39, 0xd2, 0xc5, 0x4e, 0xfd, 0xcb, 0xaa, 0xe7, 0xe8, + 0xef, 0x55, 0x6f, 0xce, 0x83, 0x77, 0x4c, 0x33, 0x5f, 0xae, 0xe1, 0x59, 0x55, 0x95, 0xe7, 0x87, + 0x2b, 0xa6, 0xbe, 0xc0, 0xc9, 0xb6, 0x0e, 0xb4, 0x27, 0x6a, 0xa9, 0x9c, 0x4c, 0x68, 0x49, 0x13, + 0x7d, 0x32, 0x33, 0xe9, 0xbd, 0xa6, 0x7a, 0x99, 0xa8, 0x03, 0x3b, 0x40, 0xca, 0x57, 0x5e, 0x50, + 0xac, 0xb3, 0x88, 0x57, 0x8c, 0x52, 0x51, 0x74, 0x81, 0x88, 0xbb, 0x49, 0xd3, 0xeb, 0x26, 0x30, + 0x8f, 0xf5, 0xe4, 0x81, 0x74, 0x96, 0xd0, 0x9f, 0x61, 0x10, 0x17, 0x31, 0xb8, 0x51, 0x6e, 0xc4, + 0x46, 0x77, 0xea, 0x2e, 0x89, 0x53, 0xc1, 0x16, 0xe0, 0xbb, 0x52, 0x28, 0x9f, 0x1a, 0x37, 0xc7, + 0x57, 0xe9, 0xe5, 0xa5, 0x4a, 0x64, 0x57, 0xbf, 0x9c, 0xcc, 0x27, 0x64, 0x22, 0x68, 0xeb, 0xc2, + 0x29, 0x16, 0x9e, 0x83, 0x5e, 0xc5, 0x32, 0x4f, 0xfa, 0x47, 0x5e, 0x26, 0x1c, 0xb7, 0x22, 0x18, + 0x79, 0xe5, 0x59, 0x0e, 0x99, 0x50, 0x6a, 0x56, 0x8c, 0x6a, 0xd4, 0x0f, 0xa9, 0xba, 0x56, 0xd9, + 0xdc, 0x32, 0x38, 0x77, 0x0a, 0x5c, 0x1c, 0x7d, 0x46, 0xd6, 0xed, 0xda, 0x5d, 0x50, 0x6a, 0x3a, + 0xff, 0x59, 0x7b, 0x75, 0xee, 0x05, 0x99, 0xa3, 0xb7, 0x1d, 0x32, 0x5c, 0xc4, 0xaa, 0xad, 0x8d, + 0x85, 0x6e, 0x2c, 0x92, 0x2e, 0xca, 0x8d, 0x30, 0x6f, 0x24, 0x95, 0xf9, 0x99, 0x66, 0x0f, 0x59, + 0x21, 0x88, 0xac, 0x7a, 0xaa, 0x80, 0xef, 0xfb, 0xd4, 0x68, 0x58, 0xbe, 0x20, 0x43, 0xdd, 0x08, + 0x14, 0x9d, 0x09, 0xe9, 0x45, 0xf3, 0x69, 0x63, 0xa7, 0xa9, 0x0b, 0xeb, 0x8e, 0x9b, 0x1e, 0x66, + 0x79, 0x1c, 0xf0, 0xb4, 0x6e, 0xad, 0x60, 0xb0, 0x93, 0xe2, 0x78, 0x17, 0xfc, 0xf6, 0xce, 0xfe, + 0x34, 0x5c, 0x8d, 0xd7, 0x6c, 0xd3, 0x68, 0xf8, 0xed, 0x58, 0x57, 0xdd, 0x34, 0xc3, 0x16, 0xa9, + 0xc1, 0x3d, 0xbb, 0x21, 0xf8, 0x5a, 0x72, 0x2b, 0xcb, 0x68, 0x5c, 0x9b, 0x3b, 0xa8, 0x27, 0x82, + 0x9b, 0x88, 0x26, 0x21, 0x21, 0x17, 0xba, 0x26, 0x10, 0x88, 0x0e, 0xe3, 0x95, 0x15, 0x8d, 0x6b, + 0x7f, 0xf8, 0x7b, 0x1f, 0x21, 0xe0, 0x1d, 0xd3, 0x1b, 0x6c, 0xfc, 0xf4, 0x57, 0xbb, 0x66, 0x3d, + 0xcf, 0xee, 0x46, 0xf6, 0x7d, 0xb3, 0x1c, 0xca, 0xaa, 0xed, 0xe5, 0xb0, 0x2c, 0x48, 0x61, 0x7d, + 0x99, 0x6b, 0x82, 0xe9, 0x15, 0x3b, 0xc3, 0x91, 0xa5, 0x50, 0xa2, 0xa8, 0xb8, 0x1d, 0x24, 0x87, + 0xa3, 0xac, 0xbe, 0x61, 0x8e, 0x19, 0xd2, 0xd5, 0xae, 0xb8, 0x8f, 0x91, 0x32, 0x1b, 0xd2, 0x10, + 0x65, 0x59, 0x94, 0x3a, 0x00, 0x71, 0xb7, 0xa1, 0xa4, 0x36, 0x75, 0x0b, 0xfb, 0xbe, 0xdc, 0xe6, + 0xfb, 0x5a, 0xc6, 0x22, 0x1a, 0x6d, 0xcc, 0xe2, 0x10, 0x28, 0x25, 0xf9, 0x7f, 0xd1, 0x4d, 0xd9, + 0x12, 0x11, 0xf0, 0x48, 0x79, 0xe7, 0xa6, 0xc5, 0x35, 0x4d, 0x4f, 0xdb, 0x0c, 0x0a, 0xc7, 0x22, + 0xed, 0xb2, 0xca, 0x1d, 0x0b, 0x2e, 0x15, 0x33, 0x0a, 0x21, 0x21, 0x90, 0x3c, 0xfe, 0xd7, 0x82, + 0x3d, 0x37, 0x59, 0x1b, 0x52, 0xb3, 0x9e, 0x75, 0x2b, 0x4d, 0xf8, 0x2b, 0x33, 0x84, 0xd3, 0xad, + 0x9a, 0x30, 0xdf, 0xf6, 0x02, 0xd9, 0x88, 0x88, 0xb3, 0x96, 0x32, 0x9b, 0xa7, 0x38, 0xfb, 0x20, + 0x7c, 0x38, 0xc6, 0xec, 0xe8, 0xde, 0x09, 0x9a, 0xb2, 0xc6, 0xee, 0xd3, 0xa2, 0x42, 0x7d, 0x02, + 0xda, 0xce, 0x5a, 0xe2, 0x2f, 0xb5, 0xbd, 0xd3, 0x54, 0xe8, 0xe9, 0xb0, 0xbf, 0xac, 0xc5, 0xf5, + 0x17, 0x27, 0x9b, 0xa1, 0xac, 0xa9, 0x53, 0x3f, 0xc8, 0xc4, 0xef, 0xea, 0xd8, 0x9b, 0xea, 0xde, + 0xd6, 0x66, 0xcd, 0xb3, 0x03, 0x39, 0x7d, 0x33, 0x0c, 0xb6, 0x94, 0xa4, 0xb9, 0xe5, 0x43, 0x3a, + 0xaa, 0xd5, 0x28, 0x8c, 0xb2, 0xae, 0xbc, 0x3e, 0x14, 0x05, 0x9e, 0x3a, 0xe6, 0x86, 0xa6, 0x74, + 0x87, 0xcc, 0x60, 0xeb, 0x25, 0x43, 0x2a, 0x1c, 0xa1, 0x4e, 0x13, 0x8a, 0x88, 0xdc, 0xab, 0x4b, + 0x75, 0xd3, 0xf7, 0x67, 0x45, 0xa2, 0xe7, 0xe8, 0xef, 0xa4, 0xae, 0x6b, 0x04, 0xc6, 0x43, 0xd4, + 0x81, 0x89, 0x46, 0xea, 0xf3, 0xe8, 0x8b, 0x42, 0x85, 0x2d, 0xf1, 0xe7, 0x60, 0x9f, 0x80, 0x80, + 0xf8, 0xae, 0xff, 0xf7, 0x9e, 0x2b, 0xa1, 0x77, 0x4c, 0x73, 0x63, 0x8f, 0x48, 0x17, 0xb7, 0x85, + 0x7d, 0xa7, 0x0f, 0xc3, 0x2b, 0xe4, 0xdf, 0xd8, 0xa2, 0xb5, 0x31, 0x2b, 0xa3, 0x00, 0x00, 0xd6, + 0xc8, 0xe2, 0xe7, 0x5d, 0x5d, 0xa1, 0xea, 0x61, 0x09, 0x91, 0xfd, 0x63, 0x48, 0xbb, 0x04, 0x3d, + 0x9d, 0xe4, 0xcb, 0x86, 0xfb, 0xe0, 0xaa, 0x78, 0xeb, 0x6b, 0x02, 0xdb, 0xf2, 0x1c, 0x5b, 0x70, + 0x8b, 0x29, 0x2d, 0xdd, 0xe1, 0xdb, 0x69, 0x7f, 0x26, 0x56, 0x4c, 0x21, 0x9b, 0x2b, 0xa9, 0xa3, + 0x09, 0x18, 0x8a, 0x7a, 0x2f, 0x1f, 0x26, 0xda, 0xe8, 0x79, 0x2a, 0xa5, 0x16, 0x06, 0x02, 0xe6, + 0xaf, 0x70, 0x74, 0xbd, 0x57, 0x8c, 0x9f, 0x84, 0x2a, 0xf1, 0xb1, 0xbc, 0xce, 0x29, 0x0b, 0x03, + 0x53, 0xfe, 0x19, 0x6c, 0xcd, 0x83, 0xdb, 0x35, 0x3a, 0x01, 0x5e, 0x05, 0xe7, 0x82, 0x38, 0xc1, + 0x0f, 0x90, 0x7a, 0x07, 0x84, 0xcc, 0xac, 0x82, 0x96, 0xbf, 0x93, 0x13, 0x6f, 0x4b, 0x15, 0xd6, + 0x14, 0x45, 0x69, 0x8d, 0xb5, 0x08, 0xb5, 0xe5, 0xa8, 0xa4, 0x3b, 0xab, 0x61, 0x68, 0x11, 0xef, + 0x5c, 0xb1, 0x8a, 0xf9, 0xe9, 0xb6, 0x44, 0xcf, 0x5e, 0xa8, 0x77, 0x1a, 0xe9, 0x5d, 0x28, 0xbf, + 0xeb, 0xd6, 0xda, 0xad, 0xf8, 0x8f, 0xcc, 0x01, 0xc7, 0xfd, 0xe3, 0x46, 0x5a, 0x74, 0x9c, 0xe7, + 0x64, 0xba, 0xc4, 0x6e, 0x11, 0xe5, 0xef, 0x5c, 0x36, 0x55, 0xa9, 0x31, 0x22, 0xe4, 0x0c, 0xac, + 0xae, 0x8a, 0xf0, 0xaf, 0xa0, 0x76, 0x2b, 0xe5, 0x8e, 0x0c, 0x57, 0x5e, 0x6a, 0xb0, 0xaa, 0x17, + 0x2f, 0x1e, 0x51, 0x9d, 0xcc, 0x76, 0xcc, 0x7f, 0x20, 0x70, 0x01, 0x99, 0x4a, 0xce, 0x83, 0x03, + 0x8a, 0x2d, 0xa9, 0xcd, 0xc9, 0xe4, 0x9e, 0xf6, 0xe7, 0x35, 0x6b, 0xee, 0x44, 0x92, 0x88, 0x7d, + 0x6d, 0xed, 0x37, 0x07, 0x02, 0xe7, 0x0c, 0x53, 0xc4, 0x17, 0xcc, 0x86, 0x04, 0x92, 0x06, 0x3e, + 0x91, 0xbb, 0xb6, 0x33, 0x4d, 0xc3, 0xf5, 0xdd, 0x89, 0x3e, 0xa4, 0xf0, 0xa9, 0x98, 0x3c, 0x7e, + 0xef, 0x67, 0x48, 0x0a, 0x80, 0xbf, 0x4f, 0x91, 0x53, 0xc2, 0xef, 0x98, 0x5e, 0x35, 0xdd, 0xee, + 0xbf, 0xaa, 0x7a, 0xdf, 0xce, 0xa3, 0x33, 0xfd, 0x0c, 0x3f, 0xc8, 0x16, 0x26, 0xe0, 0xd9, 0xb6, + 0x4c, 0xbf, 0x9d, 0xe8, 0xbc, 0x58, 0x44, 0xe9, 0x61, 0x06, 0xd6, 0x7a, 0xe7, 0xac, 0xb4, 0xf4, + 0x21, 0x88, 0x71, 0x7f, 0x0c, 0x0f, 0xec, 0x19, 0x0d, 0xf4, 0x65, 0x4b, 0x5a, 0x3d, 0xf5, 0xaf, + 0x3d, 0x62, 0xdd, 0x1a, 0x59, 0xdc, 0x4f, 0xce, 0xe5, 0xbe, 0xc2, 0x33, 0x1b, 0x36, 0xe0, 0x82, + 0x98, 0xf4, 0x0a, 0xca, 0xd0, 0x17, 0xa6, 0x7d, 0xef, 0x67, 0xcd, 0x54, 0xd0, 0x5b, 0x44, 0x14, + 0x58, 0xff, 0x05, 0x0f, 0xbd, 0xbe, 0xb4, 0x8c, 0xae, 0x9e, 0x42, 0x5c, 0x68, 0x0b, 0xc0, 0xe5, + 0x16, 0xef, 0x74, 0x97, 0x51, 0x32, 0xc8, 0x66, 0xe6, 0xf8, 0xfc, 0xbf, 0x83, 0x5d, 0xe3, 0xb9, + 0xf1, 0x8b, 0x10, 0xcd, 0x59, 0xbb, 0xdd, 0x3f, 0x39, 0xb1, 0xa0, 0x1a, 0x02, 0x04, 0x38, 0x63, + 0x30, 0x94, 0x39, 0xfd, 0x52, 0x21, 0x6e, 0xe2, 0x0a, 0x45, 0x32, 0x51, 0xfe, 0xc6, 0x7c, 0x7e, + 0x55, 0xaf, 0x49, 0x28, 0x2c, 0x2b, 0xbd, 0x74, 0xff, 0x2b, 0x81, 0xd2, 0x3e, 0xaa, 0x46, 0xd9, + 0x65, 0xfe, 0x1b, 0x9e, 0xba, 0x1a, 0x98, 0x08, 0x88, 0xa6, 0x32, 0x55, 0xf0, 0xe8, 0xfc, 0x4b, + 0x62, 0x93, 0xc2, 0x1a, 0x21, 0xed, 0x8f, 0xbf, 0x1e, 0x84, 0xf2, 0xa0, 0x73, 0x2d, 0x7c, 0xd6, + 0x80, 0xa8, 0x9b, 0xc8, 0xd9, 0x65, 0x0b, 0xec, 0x76, 0xba, 0xcc, 0xa2, 0x61, 0xe7, 0xba, 0xc9, + 0x8a, 0x79, 0x2b, 0x50, 0xce, 0x00, 0xec, 0x2e, 0x58, 0xbc, 0xd7, 0x70, 0x5e, 0x26, 0xc1, 0x42, + 0xf4, 0x2b, 0xc7, 0x41, 0xcd, 0xf2, 0x39, 0x12, 0xea, 0x46, 0x70, 0x35, 0x58, 0xa5, 0xa3, 0x46, + 0x7f, 0x4b, 0x25, 0x94, 0xdd, 0x3d, 0x63, 0xb7, 0x16, 0xd9, 0x36, 0xbd, 0xfa, 0x17, 0xde, 0x37, + 0x8d, 0x8a, 0xc3, 0xff, 0xc7, 0xde, 0x1b, 0xf4, 0xa4, 0x92, 0x75, 0x01, 0xbb, 0x7f, 0xa6, 0x39, + 0x06, 0x7d, 0xd5, 0xa4, 0xfb, 0x55, 0x83, 0x36, 0xe7, 0x8c, 0x2d, 0x1a, 0x48, 0x0a, 0xaa, 0x08, + 0x20, 0x38, 0x11, 0x0d, 0x20, 0x90, 0x80, 0x40, 0x04, 0xb1, 0xff, 0x03, 0x52, 0x10, 0x41, 0x64, + 0x62, 0x41, 0xaa, 0xca, 0x82, 0x04, 0x2c, 0x08, 0x60, 0xe1, 0x18, 0x6c, 0x34, 0x01, 0x0b, 0x02, + 0x08, 0x4c, 0x44, 0x02, 0x08, 0x24, 0x2a, 0x10, 0xf5, 0xd8, 0xef, 0xb5, 0xef, 0xe0, 0x4e, 0x4e, + 0x9f, 0xe9, 0x97, 0xdc, 0x2f, 0x3e, 0x03, 0x62, 0x62, 0x08, 0xe4, 0xa9, 0xcd, 0xda, 0x6b, 0x57, + 0xad, 0xbd, 0x36, 0x6d, 0xb0, 0x45, 0xb7, 0x7d, 0x9d, 0xbf, 0xfb, 0xda, 0x29, 0x43, 0xcd, 0x75, + 0xfc, 0x4e, 0x5c, 0x5b, 0x74, 0x72, 0xf5, 0xfc, 0x1f, 0xbd, 0x1f, 0xcf, 0xa0, 0x1c, 0x65, 0x7f, + 0x62, 0x9a, 0x3b, 0x56, 0x98, 0xda, 0xd7, 0x69, 0xe8, 0xa8, 0xdc, 0x5f, 0x38, 0x2e, 0x90, 0x73, + 0xb5, 0x9b, 0xf8, 0xb8, 0xb3, 0x1c, 0xd1, 0xee, 0x2a, 0x45, 0x86, 0xc8, 0x66, 0xe8, 0x37, 0x44, + 0x47, 0x48, 0xaa, 0x1e, 0x7f, 0x6d, 0x4c, 0x6b, 0xdc, 0xe3, 0xa0, 0x94, 0xec, 0xaf, 0x2f, 0x9a, + 0xdc, 0x01, 0x34, 0x69, 0x97, 0x78, 0xcc, 0xeb, 0xe9, 0xfc, 0xe8, 0x77, 0xea, 0xc5, 0xeb, 0x31, + 0x67, 0xd5, 0x31, 0x77, 0x68, 0x55, 0x04, 0x33, 0xea, 0x8e, 0xad, 0x1f, 0x48, 0x12, 0xb2, 0xf8, + 0xba, 0x66, 0xb0, 0x0b, 0x29, 0xeb, 0x4b, 0x3a, 0x6a, 0xa4, 0x80, 0x16, 0x24, 0x08, 0xb5, 0x2b, + 0xf3, 0x2a, 0x29, 0x5a, 0xe0, 0xb6, 0x0e, 0x77, 0x5f, 0x32, 0x5b, 0xe5, 0xf6, 0xae, 0x71, 0xe7, + 0xe5, 0x4d, 0x10, 0x8e, 0xd8, 0xdb, 0x15, 0xb9, 0xee, 0x28, 0x61, 0xd6, 0x3c, 0x74, 0x16, 0x4a, + 0x71, 0x53, 0x68, 0x51, 0x54, 0xea, 0x2b, 0x60, 0xd3, 0x65, 0xc0, 0xd5, 0x66, 0x23, 0x10, 0x64, + 0x68, 0xdc, 0x34, 0x7c, 0x2b, 0x66, 0x81, 0xd6, 0x7a, 0x65, 0xe2, 0x47, 0x28, 0x09, 0x47, 0xd0, + 0x5b, 0x87, 0x64, 0xa3, 0xfb, 0xd1, 0xd2, 0xd2, 0x9f, 0xeb, 0x96, 0x48, 0x21, 0x57, 0x20, 0x46, + 0xaf, 0x56, 0xdd, 0xd1, 0xe8, 0x2b, 0x05, 0x7e, 0x24, 0x33, 0x8e, 0x90, 0x4e, 0x65, 0x50, 0x9e, + 0x8f, 0xee, 0x0d, 0x22, 0x86, 0xe1, 0x8f, 0x8b, 0xad, 0xa3, 0x57, 0x6b, 0xb7, 0xa6, 0x6d, 0xa6, + 0x7d, 0xa2, 0xba, 0xdc, 0xbc, 0x46, 0xcc, 0x36, 0x46, 0xf9, 0xad, 0xdf, 0x47, 0x93, 0x0b, 0xad, + 0x5c, 0xfa, 0xfa, 0x70, 0x37, 0x4a, 0x48, 0x46, 0x23, 0x6b, 0x07, 0x04, 0x22, 0xfa, 0x97, 0xe5, + 0x48, 0x84, 0x59, 0x8a, 0x65, 0x86, 0xf2, 0x91, 0x2e, 0xdd, 0xfa, 0x6f, 0x64, 0xfa, 0x29, 0xe1, + 0xc6, 0x06, 0x57, 0x4d, 0x29, 0xdf, 0x12, 0x7e, 0x4a, 0x5c, 0x00, 0xee, 0x08, 0xf9, 0x9a, 0x9a, + 0xd0, 0x04, 0x5c, 0xb4, 0x4b, 0xb6, 0xf0, 0x3e, 0x15, 0xd9, 0x27, 0xf5, 0x47, 0x3e, 0xea, 0xc7, + 0x3e, 0x42, 0xf9, 0x9f, 0x98, 0x96, 0xcf, 0xef, 0x13, 0x5b, 0x94, 0x21, 0x6e, 0x95, 0xbd, 0xc9, + 0xa2, 0x43, 0x9a, 0x67, 0x73, 0xf9, 0xb7, 0x18, 0x8d, 0xbb, 0x5a, 0xfb, 0x06, 0x97, 0x62, 0xe7, + 0xc3, 0xd5, 0xa7, 0x9d, 0x9a, 0x01, 0xaa, 0x6b, 0x93, 0x71, 0x8d, 0xc6, 0x4b, 0xe8, 0x24, 0x36, + 0x74, 0x11, 0x4d, 0x1a, 0xbf, 0x1f, 0x75, 0x61, 0x83, 0xe1, 0xb4, 0xa5, 0xa3, 0x34, 0xa3, 0xb7, + 0x15, 0x2d, 0x89, 0xf6, 0x61, 0x66, 0x4b, 0x27, 0x95, 0xe2, 0x34, 0x59, 0x2b, 0x53, 0x8f, 0xb5, + 0xd2, 0x88, 0xd0, 0x54, 0xf1, 0x98, 0xb2, 0x6e, 0x8e, 0xc8, 0xd3, 0x31, 0xcf, 0xfa, 0x9c, 0x72, + 0x7d, 0x7f, 0x24, 0x41, 0xec, 0x0b, 0x2c, 0x7e, 0xdc, 0x77, 0xdc, 0x01, 0x52, 0xca, 0x72, 0x99, + 0xa2, 0x8e, 0x5f, 0x33, 0xf4, 0x68, 0xe3, 0x5d, 0xbd, 0x1f, 0x0b, 0x6c, 0x5f, 0x2c, 0x96, 0xe8, + 0x10, 0xad, 0x7b, 0x92, 0x10, 0x89, 0xb9, 0xaa, 0xe3, 0x64, 0x52, 0xa1, 0xb6, 0xab, 0x18, 0x20, + 0x66, 0x5a, 0x3a, 0x19, 0x78, 0xd3, 0xab, 0x14, 0xfe, 0x8a, 0x86, 0xd2, 0x33, 0xf6, 0x2e, 0x91, + 0x5e, 0x90, 0x1d, 0x5d, 0x48, 0x25, 0x32, 0x71, 0x4f, 0x9f, 0xfb, 0xab, 0x84, 0x42, 0x90, 0xc4, + 0x51, 0xc3, 0x06, 0xd4, 0xb1, 0x2b, 0x2b, 0xf7, 0x98, 0x2b, 0xfd, 0xa1, 0x7b, 0xa3, 0xbe, 0x1c, + 0x75, 0x34, 0xaa, 0xbd, 0x55, 0x83, 0x62, 0x2f, 0x6b, 0x81, 0x10, 0xb4, 0x6b, 0xbb, 0x20, 0x1d, + 0xea, 0x74, 0xf1, 0xac, 0x2f, 0x11, 0x15, 0xe2, 0x54, 0x48, 0x56, 0xd2, 0xf5, 0x16, 0x0c, 0xe9, + 0xb7, 0x76, 0x6d, 0xce, 0xe6, 0x3c, 0x21, 0x0b, 0xe6, 0x26, 0x6b, 0x77, 0xd6, 0x13, 0xa9, 0xc6, + 0x93, 0x16, 0x85, 0x5f, 0x26, 0x90, 0xc7, 0xfb, 0x41, 0xcc, 0x6f, 0xa7, 0xe6, 0xd3, 0x83, 0x77, + 0xc6, 0xdc, 0xdb, 0x0b, 0x84, 0xd0, 0x41, 0x43, 0xdc, 0x68, 0x26, 0xc8, 0x68, 0xf8, 0x62, 0xee, + 0x02, 0xda, 0x68, 0x2d, 0x5b, 0xc8, 0x29, 0x42, 0x7f, 0xb1, 0x55, 0x26, 0xe2, 0xb7, 0x91, 0x1f, + 0xe3, 0xf4, 0x42, 0xf2, 0x27, 0xa6, 0xd7, 0x77, 0xcb, 0x54, 0xa8, 0xff, 0x77, 0x5e, 0xa7, 0xb0, + 0x4a, 0xcd, 0x31, 0x66, 0xb7, 0x9f, 0xdf, 0x09, 0xf5, 0xc0, 0xa6, 0x79, 0xeb, 0x45, 0x1b, 0x6b, + 0xee, 0x25, 0xa6, 0x2f, 0x42, 0xda, 0x45, 0x5b, 0x9f, 0xa8, 0x43, 0xc0, 0xa3, 0x76, 0x90, 0x7d, + 0xb3, 0x2a, 0x90, 0x65, 0xdb, 0x24, 0xea, 0x99, 0x81, 0xbc, 0xeb, 0xb5, 0xc5, 0x41, 0xea, 0x38, + 0x91, 0x2f, 0x42, 0x1e, 0x4c, 0xdf, 0x28, 0x27, 0xfa, 0xaf, 0x94, 0x23, 0xa4, 0xdd, 0x7c, 0x49, + 0xf7, 0x90, 0xe6, 0xac, 0x73, 0x7d, 0x90, 0x94, 0x45, 0x48, 0x87, 0x5c, 0x18, 0x1b, 0xba, 0xca, + 0x70, 0xb5, 0x38, 0x55, 0xe3, 0x22, 0xaa, 0x6e, 0x26, 0xb5, 0x6f, 0xfe, 0xa5, 0x91, 0x05, 0x87, + 0x4b, 0xd5, 0xfc, 0x4d, 0x6c, 0x3f, 0x0c, 0x9a, 0x1a, 0x89, 0xd9, 0x3c, 0x10, 0x9b, 0xea, 0x5e, + 0xcb, 0xca, 0x2a, 0x2c, 0x92, 0xf1, 0xc9, 0x39, 0x30, 0xfc, 0xe6, 0x8e, 0x4b, 0xf3, 0x31, 0xfd, + 0x47, 0xba, 0x4a, 0xc0, 0x75, 0x5a, 0x98, 0x58, 0x61, 0x2a, 0xc5, 0x1d, 0xa4, 0xbf, 0x7a, 0x1b, + 0x2b, 0x4d, 0xa4, 0x37, 0x67, 0x3e, 0x20, 0x0b, 0xfa, 0x16, 0xd1, 0x4b, 0xc3, 0xda, 0xf7, 0x46, + 0x65, 0x10, 0x52, 0x7d, 0x33, 0xac, 0x6b, 0x0f, 0x71, 0x53, 0x21, 0x31, 0xc5, 0xab, 0xbb, 0x07, + 0x88, 0x99, 0xa7, 0x45, 0xd8, 0x59, 0x3b, 0xb5, 0x35, 0xf7, 0x1a, 0xb5, 0x91, 0xf6, 0x95, 0x18, + 0x25, 0xa1, 0xa4, 0xef, 0x5a, 0x64, 0xe3, 0x72, 0x19, 0x50, 0x35, 0xb7, 0xaa, 0x65, 0x5a, 0xa1, + 0x37, 0x1a, 0x95, 0xd4, 0x6e, 0x2c, 0x85, 0x57, 0x52, 0x6a, 0x47, 0x93, 0x30, 0xc8, 0x47, 0x5b, + 0x70, 0xdb, 0x64, 0x7c, 0x5b, 0x67, 0xc5, 0xeb, 0x7b, 0x13, 0xe5, 0x04, 0x3c, 0xed, 0x64, 0x2a, + 0x54, 0x8d, 0x5c, 0x99, 0x37, 0x32, 0x2c, 0xfe, 0xa4, 0xf4, 0x74, 0xda, 0x49, 0x08, 0x34, 0xb4, + 0xc4, 0x1c, 0xa6, 0xf1, 0x9e, 0xdd, 0x11, 0x48, 0xc3, 0x0c, 0x6d, 0x55, 0xc4, 0x49, 0x79, 0x99, + 0xfa, 0x3f, 0xd8, 0xdd, 0xc6, 0xcc, 0xfe, 0xc9, 0x35, 0x64, 0xf1, 0xfd, 0x94, 0x6c, 0xc0, 0xcb, + 0x6f, 0xdc, 0xc7, 0x4d, 0x22, 0xdd, 0x5a, 0x7c, 0x64, 0xd7, 0xca, 0x22, 0x56, 0x9d, 0x8b, 0xc1, + 0x2e, 0x65, 0x67, 0xc1, 0xcc, 0x7e, 0xd5, 0x5d, 0x5f, 0xb4, 0x5c, 0x49, 0xca, 0xb4, 0x0d, 0xd9, + 0xa2, 0x35, 0xe3, 0x82, 0xbf, 0x37, 0x6d, 0x84, 0x8e, 0xfb, 0x2b, 0x1c, 0xf0, 0x36, 0x7d, 0xc1, + 0x95, 0x91, 0x06, 0x41, 0x92, 0xdf, 0xde, 0xe2, 0x7c, 0xed, 0x2b, 0xee, 0x3b, 0xa0, 0x3b, 0xf2, + 0xa5, 0xa6, 0x57, 0x1a, 0xbc, 0x69, 0xdc, 0x48, 0x78, 0x87, 0x06, 0x41, 0xc8, 0xbe, 0x52, 0x1f, + 0x2a, 0x0f, 0x93, 0x5c, 0xa1, 0xf8, 0x8e, 0x56, 0x18, 0xd7, 0xbe, 0x47, 0x56, 0x45, 0xdf, 0xfd, + 0x5f, 0x56, 0xed, 0x1e, 0x89, 0x8e, 0xb9, 0x92, 0xb3, 0x2f, 0x68, 0x73, 0xa3, 0xaf, 0x9e, 0x66, + 0x8e, 0xc8, 0x15, 0xde, 0x50, 0x36, 0x52, 0x56, 0x7b, 0xaf, 0xae, 0xdc, 0xab, 0x19, 0x5d, 0xc8, + 0x49, 0x13, 0xa7, 0x37, 0x91, 0xcb, 0x70, 0x84, 0x7b, 0x71, 0x59, 0x93, 0xab, 0xeb, 0x8d, 0xcb, + 0x50, 0x44, 0x99, 0x75, 0xf4, 0x5b, 0xdd, 0x88, 0x28, 0x7d, 0x43, 0x08, 0x60, 0xf1, 0xe8, 0xab, + 0x70, 0xfb, 0x5d, 0x8e, 0x3f, 0x3e, 0x6d, 0x11, 0x5c, 0x60, 0xbf, 0xe1, 0x1a, 0xcd, 0x02, 0xfd, + 0x6d, 0x8c, 0xe3, 0x38, 0xc8, 0x64, 0x47, 0xa6, 0x6a, 0x75, 0xb2, 0x62, 0xb4, 0x64, 0x5e, 0x0c, + 0xb6, 0xf2, 0x0d, 0x16, 0x61, 0x82, 0xa4, 0x79, 0xf7, 0x60, 0xa3, 0x22, 0x2c, 0x51, 0xb2, 0x73, + 0x92, 0x50, 0xa6, 0xd7, 0xed, 0xf9, 0x41, 0xfa, 0xe1, 0xfa, 0xb7, 0xc2, 0x81, 0xae, 0x23, 0xd4, + 0x98, 0xdb, 0x90, 0x21, 0x7c, 0x4a, 0x68, 0xa0, 0xb0, 0xf1, 0x3c, 0xf7, 0x74, 0x40, 0x37, 0x77, + 0x75, 0x80, 0x3c, 0x3d, 0xa8, 0x68, 0x9f, 0x6a, 0x7c, 0x18, 0x3a, 0x63, 0xfa, 0x6a, 0x9b, 0xe3, + 0x06, 0xbf, 0x2c, 0xc8, 0x39, 0x6d, 0x40, 0x4b, 0xf7, 0x57, 0x16, 0xc2, 0xb5, 0x96, 0xb5, 0x52, + 0xf8, 0x8e, 0x7e, 0xed, 0x3d, 0x8c, 0x7e, 0x7c, 0xc6, 0xa0, 0x9a, 0xfd, 0x89, 0xe9, 0xcd, 0x17, + 0x9a, 0x4c, 0xd3, 0x43, 0xbd, 0x92, 0x54, 0x3f, 0xca, 0x75, 0x98, 0x1d, 0xa4, 0x9a, 0x76, 0xe8, + 0xdd, 0x39, 0x76, 0x5f, 0x08, 0xe3, 0x66, 0xfa, 0x4b, 0xc2, 0x6c, 0xe2, 0x96, 0x93, 0x96, 0x75, + 0x48, 0x9a, 0x8b, 0x1f, 0x63, 0x6a, 0xde, 0x5e, 0x60, 0x2a, 0x12, 0xde, 0xe9, 0xbe, 0xd0, 0xe3, + 0xb3, 0xe3, 0xfe, 0x75, 0xe4, 0xe0, 0xe6, 0x4d, 0x0b, 0xdb, 0x15, 0xba, 0x8e, 0xfe, 0x60, 0x24, + 0xa9, 0x4d, 0x3f, 0x05, 0x4a, 0x61, 0x3a, 0x63, 0xe9, 0x5b, 0xed, 0xa5, 0x51, 0x6b, 0x98, 0xb6, + 0xc4, 0x29, 0xf6, 0xb4, 0x0f, 0xed, 0x90, 0x36, 0xf3, 0xf1, 0x79, 0x92, 0x48, 0xf7, 0xcd, 0x7d, + 0xc9, 0xbe, 0xc9, 0x5f, 0x29, 0xda, 0x65, 0x38, 0x56, 0xca, 0x7d, 0xef, 0x06, 0x29, 0x7a, 0x9d, + 0x69, 0x0c, 0x1f, 0x12, 0xf3, 0x9a, 0x5d, 0x89, 0xe2, 0x77, 0xfc, 0xca, 0xde, 0x24, 0xe4, 0xa5, + 0x86, 0xbe, 0xc3, 0x94, 0xd3, 0xc7, 0x7d, 0x9e, 0x84, 0x5f, 0xa4, 0xe6, 0x12, 0xeb, 0xeb, 0xc1, + 0x74, 0xac, 0x6e, 0xed, 0x77, 0xf6, 0x91, 0xea, 0xd1, 0x05, 0x54, 0xa2, 0xce, 0xfb, 0x42, 0x8f, + 0xa9, 0x56, 0x4b, 0xc5, 0x63, 0x84, 0x7a, 0xdc, 0xd3, 0x13, 0x40, 0x55, 0x40, 0x25, 0xda, 0xf1, + 0xb5, 0x68, 0xfa, 0x22, 0x4e, 0x37, 0xa5, 0xb0, 0xc8, 0x55, 0x9e, 0x4d, 0xd5, 0x6d, 0x83, 0xe3, + 0xb7, 0xfa, 0x98, 0x58, 0x62, 0x46, 0x17, 0xe0, 0x6b, 0x7d, 0xd1, 0x6b, 0xb0, 0x8e, 0x26, 0xf1, + 0x8f, 0x55, 0xbd, 0xb6, 0x68, 0x77, 0x74, 0xaa, 0xf9, 0x71, 0xab, 0x31, 0xe0, 0x47, 0xe9, 0x14, + 0xb9, 0x6f, 0xf4, 0x32, 0x2f, 0x7f, 0x24, 0x1a, 0x55, 0xcb, 0x3e, 0xa1, 0xb0, 0xa5, 0xc3, 0x04, + 0xad, 0x85, 0xf7, 0x43, 0xdb, 0xd7, 0xd6, 0xbf, 0x9c, 0x3e, 0xe8, 0x29, 0xf5, 0xe0, 0xe3, 0x81, + 0x7f, 0x14, 0x29, 0x5d, 0xc7, 0xe9, 0x50, 0x94, 0xe8, 0x88, 0x19, 0xdb, 0x52, 0xda, 0xac, 0x43, + 0xb3, 0x1a, 0x70, 0x92, 0x4b, 0xec, 0xb0, 0xea, 0xc7, 0xee, 0x36, 0xa3, 0xd5, 0x9f, 0x98, 0xd6, + 0x54, 0x1a, 0x3b, 0x2d, 0x3a, 0x12, 0xf6, 0x1c, 0x72, 0x6d, 0x0a, 0x8f, 0x5f, 0xa3, 0x1f, 0xa1, + 0x75, 0xf9, 0x92, 0xe3, 0xc9, 0x71, 0x55, 0x34, 0x7e, 0x4c, 0xde, 0xf6, 0xd3, 0xf7, 0x32, 0x31, + 0xc7, 0xb3, 0x73, 0xb5, 0xa0, 0x20, 0x76, 0x87, 0x19, 0x72, 0x56, 0x8e, 0x4c, 0x2a, 0x30, 0xed, + 0xbd, 0x95, 0x10, 0x34, 0xb9, 0x2b, 0x3b, 0x7d, 0x6e, 0x74, 0x08, 0x73, 0xf8, 0xa5, 0xa7, 0x7c, + 0x6e, 0x3a, 0x18, 0x20, 0xb5, 0xae, 0x9d, 0xc9, 0x3d, 0x9f, 0xa1, 0x73, 0xc5, 0xed, 0x60, 0x4b, + 0x21, 0xb1, 0xee, 0xb4, 0xe0, 0x46, 0xa9, 0x41, 0x57, 0x1c, 0x26, 0x2a, 0x51, 0x4b, 0xed, 0x1f, + 0xac, 0x0c, 0xde, 0xa2, 0xe6, 0xa9, 0x6c, 0xee, 0xb1, 0xce, 0x55, 0x8d, 0x63, 0xa5, 0x8e, 0x46, + 0x7b, 0xd0, 0xf6, 0xd2, 0x43, 0x7e, 0x82, 0x26, 0xaf, 0x12, 0xca, 0x88, 0xea, 0xaa, 0x0b, 0xad, + 0xc0, 0xe0, 0x4d, 0xea, 0xa5, 0x61, 0x86, 0xc4, 0x8c, 0xa0, 0x9e, 0xaf, 0x6f, 0x75, 0xc9, 0xd3, + 0x6a, 0x05, 0x07, 0x14, 0xd5, 0xbf, 0x2f, 0x61, 0x37, 0x8a, 0x75, 0x6d, 0x02, 0xb0, 0xbe, 0x25, + 0x2f, 0x0d, 0xfc, 0xd7, 0xcb, 0x29, 0xf1, 0xc5, 0x17, 0xc1, 0x8e, 0x2b, 0xd8, 0x90, 0x38, 0x12, + 0xff, 0x45, 0xb1, 0x74, 0x69, 0xdc, 0xe8, 0x2b, 0x7a, 0x9d, 0x5c, 0x1f, 0x7c, 0xf0, 0xcc, 0xa4, + 0xba, 0x0e, 0x33, 0x57, 0xef, 0x6c, 0x4d, 0xad, 0x56, 0x27, 0xb6, 0xc3, 0x71, 0xfe, 0x69, 0x6b, + 0xf3, 0xe5, 0x63, 0x29, 0xd2, 0x63, 0x19, 0xc5, 0xc8, 0x31, 0x59, 0xa0, 0x28, 0xc2, 0xb0, 0x52, + 0xea, 0xd3, 0x12, 0xbb, 0xed, 0x34, 0x3d, 0x53, 0xdf, 0x79, 0x40, 0xe7, 0x4c, 0x8d, 0x54, 0x73, + 0x2b, 0x95, 0x57, 0x6c, 0xd1, 0xec, 0xd1, 0x4d, 0x25, 0xcd, 0x4b, 0x49, 0xfe, 0x3b, 0x29, 0x85, + 0xb5, 0x7f, 0x7e, 0x24, 0x58, 0xce, 0xd2, 0xa4, 0x76, 0x69, 0x20, 0xaa, 0x63, 0x07, 0xa1, 0xc9, + 0x64, 0xcb, 0xa7, 0xd5, 0x61, 0xc6, 0x6e, 0x47, 0x17, 0x16, 0xe9, 0xfa, 0x8f, 0xcf, 0x18, 0x5a, + 0xfc, 0x7f, 0x35, 0xcd, 0xa8, 0xf2, 0x90, 0x1d, 0x46, 0x95, 0x97, 0xdd, 0x21, 0x4c, 0x82, 0xb0, + 0x95, 0x90, 0x0a, 0xc5, 0xb1, 0x84, 0x59, 0x20, 0x2e, 0xce, 0x2e, 0x11, 0x22, 0xc4, 0x0c, 0xad, + 0xc2, 0x4f, 0x6e, 0x54, 0x26, 0x6f, 0xaa, 0x76, 0xe5, 0x70, 0x51, 0x9a, 0x95, 0x17, 0x46, 0x2c, + 0x8e, 0x12, 0xba, 0x61, 0xcc, 0x9c, 0x3d, 0x17, 0xc3, 0xf9, 0x5b, 0xb7, 0xd1, 0x7f, 0x5b, 0xd9, + 0x43, 0x16, 0x16, 0x25, 0x4f, 0xcd, 0x6d, 0x4c, 0x07, 0x3f, 0xb4, 0x2f, 0xb5, 0xa2, 0xf2, 0x2f, + 0x49, 0x10, 0xea, 0x36, 0xae, 0x6c, 0xca, 0x61, 0x79, 0xc2, 0x96, 0x40, 0x04, 0x63, 0x86, 0x43, + 0x56, 0xf6, 0xa3, 0x16, 0x7f, 0xd1, 0xb1, 0x25, 0xfe, 0xff, 0xa4, 0x81, 0x6d, 0xe6, 0x7e, 0x24, + 0x78, 0xa4, 0x7a, 0x7a, 0x0d, 0x0c, 0xb1, 0xcc, 0x36, 0x25, 0x43, 0xc9, 0x56, 0x21, 0xa4, 0xc3, + 0x91, 0xe4, 0x1e, 0x9b, 0x0b, 0x26, 0xa7, 0x6b, 0xc4, 0x51, 0x9c, 0x32, 0x56, 0x96, 0x34, 0x5a, + 0xa7, 0x16, 0xf8, 0x11, 0xe7, 0x6b, 0xa5, 0xb0, 0x7f, 0x72, 0x1e, 0x16, 0xfc, 0xe1, 0xea, 0x85, + 0x6d, 0x16, 0x28, 0x31, 0x6b, 0x70, 0xcb, 0x7a, 0xab, 0x16, 0xe0, 0xd4, 0x27, 0x04, 0x08, 0xeb, + 0x9f, 0x9c, 0xba, 0x96, 0xae, 0x84, 0xae, 0xe8, 0xef, 0xed, 0x85, 0x74, 0xcc, 0x38, 0x4a, 0x54, + 0x4a, 0x84, 0x5a, 0x10, 0x0b, 0xec, 0xdd, 0xfc, 0xd3, 0xe4, 0x01, 0x4f, 0xc0, 0x0f, 0x1f, 0xd9, + 0xee, 0xeb, 0x93, 0xbf, 0xb3, 0x75, 0x35, 0x44, 0x38, 0x2c, 0x8d, 0xa8, 0x56, 0x81, 0xa3, 0xba, + 0xf0, 0x80, 0x84, 0x3e, 0x56, 0xcc, 0x33, 0x84, 0x00, 0xfa, 0x8a, 0x2b, 0x8f, 0x46, 0x6d, 0x81, + 0xda, 0x1d, 0x6e, 0xee, 0xd6, 0x63, 0xc4, 0x4c, 0x27, 0xfa, 0x27, 0x7c, 0xfc, 0xb6, 0xaa, 0x78, + 0x4e, 0x24, 0x18, 0xcb, 0x69, 0x8b, 0xf3, 0xf2, 0xb4, 0xfd, 0xda, 0x5e, 0x75, 0xdd, 0x4c, 0x16, + 0x56, 0xba, 0x3e, 0x96, 0x90, 0xbb, 0xf6, 0x3d, 0xc9, 0xd2, 0x8b, 0x98, 0x10, 0xd7, 0x76, 0xf4, + 0xfe, 0x63, 0xf4, 0x58, 0xe0, 0xfc, 0x64, 0x4c, 0x2f, 0xe4, 0x7d, 0x43, 0x7d, 0x46, 0x71, 0xda, + 0x1a, 0x2e, 0x8f, 0x2f, 0x90, 0x5f, 0xe2, 0xaf, 0xb8, 0x82, 0x1b, 0xb6, 0xd6, 0x23, 0x2a, 0xc6, + 0x10, 0xde, 0x9e, 0x2c, 0xe6, 0x47, 0x6b, 0x2f, 0xcd, 0xc6, 0x28, 0x5a, 0xbf, 0xd0, 0x5e, 0x6c, + 0xfd, 0x12, 0x07, 0x00, 0x27, 0xc2, 0x26, 0xf6, 0x62, 0x6a, 0xae, 0x14, 0x3c, 0x3e, 0xa1, 0xf0, + 0x9e, 0xed, 0x65, 0xd0, 0x13, 0x95, 0x3c, 0x43, 0x88, 0x10, 0x93, 0x73, 0x95, 0x63, 0x6f, 0x9f, + 0x3f, 0x03, 0xde, 0x51, 0x7c, 0x01, 0x13, 0x70, 0x61, 0x95, 0x52, 0xfc, 0x3e, 0xd3, 0x79, 0x3c, + 0x2e, 0xb5, 0xa2, 0xb1, 0x72, 0x4b, 0x0b, 0x3a, 0xa2, 0xc7, 0x44, 0x16, 0x3e, 0xf1, 0xb3, 0x41, + 0xf0, 0xb6, 0xbd, 0x5a, 0xba, 0xf4, 0x49, 0xba, 0x7f, 0xeb, 0xfb, 0xb6, 0xd4, 0x38, 0xb6, 0xbe, + 0xc2, 0x30, 0xa4, 0x38, 0xb4, 0x6a, 0xdc, 0x61, 0x96, 0x74, 0x72, 0xc8, 0x2a, 0x5f, 0x50, 0xd0, + 0xb5, 0xcf, 0xfd, 0xc1, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, + 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, + 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0xff, 0x77, 0xf2, 0xcf, 0xf3, 0x60, 0x5b, 0x6b, 0x57, + 0xa9, 0x1d, 0xbc, 0x74, 0x5e, 0xfe, 0x44, 0x10, 0x05, 0x28, 0x62, 0x58, 0xbb, 0x72, 0x08, 0x62, + 0xad, 0xf2, 0xaf, 0xec, 0x1d, 0x5a, 0x00, 0xbb, 0x70, 0x06, 0x28, 0xae, 0x95, 0x9b, 0x0d, 0xd3, + 0x4e, 0x6b, 0xe1, 0x0a, 0x42, 0x7e, 0x27, 0xbb, 0x0e, 0x47, 0x79, 0x91, 0x94, 0x41, 0x73, 0x6d, + 0xe0, 0xb8, 0x8c, 0xd5, 0xdf, 0x47, 0xfa, 0x49, 0x2b, 0x9b, 0x5b, 0xf3, 0x73, 0x79, 0x46, 0xf3, + 0x21, 0x3d, 0x1f, 0xf3, 0xcc, 0x5e, 0x69, 0x3d, 0x41, 0xff, 0x66, 0x47, 0x08, 0x1f, 0x13, 0xca, + 0x51, 0x6f, 0x76, 0x24, 0xb9, 0xa6, 0x6e, 0x7b, 0x8e, 0x83, 0xde, 0x92, 0x34, 0x37, 0x89, 0x9c, + 0xf4, 0x1a, 0x4a, 0x1b, 0x69, 0xe5, 0x5d, 0x2b, 0x0f, 0xa7, 0x05, 0xe3, 0xd8, 0x94, 0x32, 0x66, + 0x39, 0x3b, 0x9c, 0xce, 0xe3, 0xdb, 0xbe, 0x55, 0x5d, 0x74, 0x33, 0xd8, 0x94, 0x45, 0xd7, 0x42, + 0x92, 0x39, 0x07, 0xb2, 0xd4, 0xb2, 0x14, 0x6c, 0xe4, 0x57, 0x58, 0x28, 0xce, 0x60, 0x5c, 0xf1, + 0x0d, 0xc3, 0x85, 0x25, 0x88, 0x35, 0x2c, 0x11, 0x42, 0xc7, 0x04, 0x2e, 0x4e, 0x45, 0xa4, 0xbf, + 0x59, 0x20, 0x25, 0x6e, 0xe9, 0x89, 0xeb, 0x56, 0x36, 0x2e, 0x62, 0xd8, 0xb6, 0x5b, 0xd7, 0x31, + 0xa6, 0x8e, 0x6f, 0xe2, 0x75, 0xce, 0x3e, 0x12, 0xc6, 0x4b, 0x22, 0x18, 0xa1, 0x1d, 0xf1, 0x0d, + 0x74, 0x57, 0xe0, 0x13, 0x57, 0x7a, 0x57, 0x5e, 0x44, 0x4b, 0x2a, 0xa1, 0x96, 0x8e, 0xcb, 0xd7, + 0x12, 0xc8, 0x48, 0x28, 0x32, 0x49, 0xc3, 0xa6, 0x62, 0x59, 0xfe, 0x6d, 0xa1, 0xa7, 0xf1, 0x94, + 0x2a, 0xe2, 0x83, 0x6a, 0x8b, 0x30, 0x69, 0xd1, 0x0c, 0x2f, 0xdc, 0x94, 0xcb, 0xa4, 0x42, 0x4d, + 0x29, 0xbf, 0x1a, 0x91, 0x6c, 0x07, 0xbb, 0x1e, 0x91, 0x8f, 0x33, 0xe2, 0xa5, 0x55, 0x3f, 0xd6, + 0x43, 0xe7, 0xe1, 0x7f, 0xaf, 0xb2, 0x90, 0x69, 0x21, 0xc5, 0x5e, 0x72, 0x52, 0x78, 0x1f, 0x6a, + 0x76, 0x6b, 0x1e, 0x66, 0x41, 0x0d, 0x8a, 0x91, 0x85, 0xf8, 0xc0, 0x45, 0xa9, 0x95, 0x12, 0x5b, + 0xa8, 0x25, 0x5c, 0x0f, 0x24, 0xd8, 0xfc, 0x2b, 0xc3, 0xf2, 0xc5, 0xaf, 0x47, 0xa9, 0xe7, 0x78, + 0xd2, 0xb7, 0xb5, 0xb2, 0x42, 0x5e, 0xca, 0x59, 0xb0, 0xa1, 0xea, 0xef, 0x09, 0xb3, 0xb5, 0x00, + 0x6b, 0xea, 0x2b, 0x2e, 0x72, 0x87, 0x74, 0x4e, 0xa4, 0x45, 0x8a, 0xc0, 0xf3, 0x6e, 0x0a, 0x14, + 0x47, 0x42, 0x11, 0xcd, 0xa8, 0xac, 0xc0, 0x2d, 0xbe, 0xc0, 0x8c, 0xdc, 0xb8, 0xee, 0x3d, 0xc5, + 0x78, 0x7f, 0xdc, 0x35, 0x72, 0x57, 0xfd, 0xb5, 0xa3, 0xcb, 0x86, 0xef, 0xe4, 0x8d, 0x95, 0xcc, + 0x97, 0xd9, 0x49, 0xa3, 0x05, 0xaa, 0x94, 0xc2, 0xb6, 0xd1, 0x03, 0x29, 0xca, 0x3f, 0x21, 0xcb, + 0x29, 0xbb, 0x0d, 0xa3, 0xaf, 0x0c, 0xca, 0xef, 0x8c, 0x82, 0x76, 0x70, 0xaf, 0x56, 0xd3, 0xed, + 0x99, 0x2f, 0x99, 0x53, 0xd4, 0xa3, 0x37, 0xf5, 0x8f, 0xee, 0xa9, 0x89, 0xbd, 0x07, 0x69, 0xe1, + 0x53, 0x64, 0x37, 0x63, 0x78, 0x82, 0x3b, 0x69, 0x76, 0xf8, 0xa8, 0x6d, 0x87, 0x27, 0xf1, 0xc6, + 0xf8, 0x4d, 0xd4, 0x1b, 0x24, 0xd2, 0xe0, 0x3b, 0x5e, 0xd1, 0x67, 0x1c, 0x7b, 0x8d, 0x17, 0x37, + 0x51, 0x21, 0x56, 0xfb, 0x92, 0xad, 0x16, 0x58, 0x6c, 0x42, 0x97, 0x2b, 0x37, 0x48, 0x3a, 0xbb, + 0xcb, 0x13, 0x53, 0x39, 0x39, 0xac, 0x75, 0x75, 0x99, 0xf3, 0x08, 0xf7, 0x0b, 0x3e, 0x4e, 0x2c, + 0xf0, 0x09, 0x00, 0xed, 0xa1, 0xa6, 0x1e, 0x32, 0x1b, 0x01, 0x19, 0xd5, 0xde, 0xf0, 0x57, 0x8b, + 0x28, 0x69, 0x98, 0x53, 0xca, 0x43, 0x21, 0x23, 0x68, 0xe5, 0xac, 0x6b, 0xdd, 0x8f, 0xdf, 0x23, + 0x90, 0xfc, 0xcd, 0xca, 0x9a, 0x20, 0xef, 0xeb, 0x8a, 0x09, 0x30, 0x26, 0xdb, 0x5f, 0xc7, 0x65, + 0xcb, 0x40, 0xe4, 0xac, 0xcf, 0xa6, 0xf7, 0xcf, 0x5b, 0x14, 0x2e, 0xaf, 0x22, 0xfd, 0x2b, 0x93, + 0x29, 0xf6, 0x83, 0x69, 0x18, 0x4d, 0xfe, 0xc4, 0xb4, 0xa2, 0x03, 0xde, 0xa0, 0x02, 0x20, 0x72, + 0x82, 0x2d, 0xf3, 0x9c, 0x8c, 0x7a, 0x26, 0xe7, 0x04, 0x07, 0x24, 0x70, 0x20, 0x76, 0xd5, 0x56, + 0xed, 0x47, 0x28, 0x67, 0x95, 0xdc, 0xc0, 0xd8, 0x7c, 0x59, 0xb1, 0xce, 0x5e, 0x05, 0x75, 0x27, + 0x49, 0x81, 0xe3, 0x08, 0x5d, 0x5d, 0x15, 0x3f, 0xdc, 0x10, 0x2b, 0x62, 0xf4, 0x84, 0x90, 0xf9, + 0xe3, 0x08, 0x87, 0x27, 0x77, 0xa3, 0xd3, 0x35, 0xd7, 0xc1, 0x0c, 0x5a, 0xe6, 0x21, 0x54, 0x4b, + 0x63, 0xdc, 0x0b, 0x8e, 0x0a, 0x40, 0x00, 0x4d, 0x0a, 0x4a, 0x37, 0x9e, 0x81, 0x16, 0xf4, 0xa8, + 0x04, 0x7d, 0xc4, 0x4d, 0x61, 0x36, 0xd1, 0xc3, 0x49, 0xab, 0xa3, 0x3c, 0x4a, 0xec, 0xb2, 0x3f, + 0x86, 0x55, 0x7c, 0xf5, 0xe0, 0x9f, 0xd2, 0x0f, 0x08, 0x31, 0x9b, 0xe5, 0xb8, 0x98, 0x02, 0x00, + 0x70, 0x6f, 0x9c, 0x95, 0xc2, 0xce, 0xd1, 0xc2, 0x92, 0x08, 0x44, 0x16, 0x96, 0x45, 0x12, 0xba, + 0x06, 0x00, 0x92, 0x93, 0x0a, 0x00, 0x94, 0x49, 0xd6, 0xb4, 0xf2, 0xec, 0x84, 0x74, 0x48, 0x60, + 0x1f, 0x5b, 0x47, 0x4a, 0x7e, 0xbf, 0x8e, 0xf2, 0x5c, 0xa8, 0xa6, 0xa7, 0xa4, 0xcc, 0x9d, 0x05, + 0xf0, 0x60, 0x2b, 0x1e, 0x3d, 0x16, 0xb9, 0xb2, 0xb6, 0x75, 0xd9, 0x4d, 0x56, 0xa7, 0xf4, 0x97, + 0x53, 0xa3, 0x9b, 0x42, 0x52, 0x1a, 0xe1, 0x0f, 0xef, 0xf2, 0x8f, 0x14, 0x74, 0x28, 0x5b, 0xe5, + 0xa1, 0xee, 0xcc, 0xdf, 0xc0, 0xe0, 0x50, 0x07, 0xf0, 0xd0, 0x12, 0x3d, 0x7f, 0x71, 0xc6, 0xb4, + 0x61, 0xbb, 0xa8, 0x35, 0xc3, 0x03, 0xee, 0xee, 0x2b, 0xb6, 0xda, 0x70, 0x0d, 0x87, 0x81, 0x48, + 0x8b, 0xe4, 0xdd, 0xdc, 0xc6, 0x53, 0x0a, 0xe0, 0x3e, 0x48, 0xb3, 0x2f, 0x62, 0xad, 0x57, 0x85, + 0x38, 0xc4, 0x96, 0x83, 0x88, 0x7b, 0x7c, 0x39, 0xbd, 0x6e, 0xc4, 0xe6, 0xa7, 0x0f, 0xd2, 0x67, + 0xb5, 0x69, 0xb7, 0x11, 0xb3, 0x4e, 0x7b, 0xfd, 0x9c, 0x9c, 0xd0, 0x09, 0xf5, 0x56, 0x80, 0x61, + 0x1c, 0xfd, 0x3f, 0x57, 0xd1, 0x28, 0x6e, 0xb1, 0x7f, 0x72, 0x0d, 0x59, 0xd3, 0xc5, 0xe3, 0xe7, + 0x96, 0x46, 0x74, 0x1f, 0x50, 0x61, 0x6b, 0xe8, 0x46, 0xae, 0xb7, 0xee, 0x39, 0xbe, 0x64, 0x3b, + 0xad, 0x8d, 0x7b, 0x39, 0xd5, 0xf2, 0x6f, 0x02, 0xe0, 0x84, 0xa2, 0xa4, 0x25, 0x31, 0x33, 0x61, + 0x32, 0x32, 0xff, 0x57, 0x81, 0x7e, 0xa3, 0x8f, 0x99, 0x1e, 0xad, 0xff, 0xed, 0x54, 0x4b, 0xd0, + 0x36, 0xc6, 0xeb, 0x21, 0x9e, 0x25, 0x3e, 0x7e, 0xd7, 0xa5, 0x26, 0x4a, 0xa3, 0xab, 0x5b, 0x78, + 0x94, 0x21, 0xa8, 0x03, 0xb6, 0x11, 0x55, 0x3b, 0x44, 0xff, 0xb7, 0x9c, 0xa5, 0x1f, 0xef, 0x2b, + 0xf6, 0xbd, 0x96, 0x43, 0xa5, 0xc9, 0xa7, 0xb5, 0x1d, 0x4c, 0x81, 0xae, 0xeb, 0xf5, 0xa2, 0xa0, + 0xaf, 0xc3, 0x19, 0x43, 0xe1, 0x0e, 0x37, 0x7d, 0x14, 0xbe, 0x5e, 0x14, 0x88, 0xd6, 0x86, 0xa9, + 0x03, 0x47, 0xb0, 0x32, 0x6b, 0xdc, 0xf8, 0x9f, 0x52, 0x44, 0x9e, 0x76, 0x6b, 0xfb, 0xbe, 0xfb, + 0x3b, 0xea, 0x7a, 0xd0, 0xf4, 0x5b, 0x44, 0x07, 0x38, 0xc6, 0xaf, 0xd7, 0xee, 0xde, 0x31, 0xbb, + 0xa2, 0x47, 0x73, 0x14, 0xca, 0x37, 0x68, 0xdd, 0xec, 0xd7, 0x25, 0x66, 0x0b, 0x7a, 0xd5, 0x39, + 0x26, 0xf4, 0x1f, 0x87, 0x19, 0xc7, 0xfe, 0xe6, 0xcb, 0xa2, 0xb1, 0x7a, 0x5c, 0xc1, 0x73, 0x35, + 0x2b, 0x51, 0xc5, 0x81, 0x62, 0x79, 0xd1, 0x78, 0x4a, 0xb8, 0xb3, 0x7f, 0x0b, 0x8e, 0x9b, 0x52, + 0xa0, 0x1c, 0x62, 0x7f, 0x59, 0xf5, 0x6e, 0x7a, 0x58, 0x59, 0xfc, 0x7b, 0x05, 0xd7, 0x18, 0x8f, + 0x42, 0xff, 0x14, 0x15, 0xa7, 0xcb, 0xf9, 0xb1, 0x99, 0xd1, 0xd9, 0xcc, 0x9e, 0xed, 0x2c, 0x2f, + 0x7a, 0x1e, 0x91, 0xea, 0x12, 0x50, 0x15, 0x83, 0xfc, 0x81, 0x15, 0x95, 0x15, 0x0f, 0xd1, 0xb9, + 0xaa, 0x70, 0x5d, 0x3b, 0x0d, 0xe8, 0x63, 0xfe, 0xd4, 0xdf, 0x7d, 0x49, 0xbc, 0x17, 0x33, 0xf5, + 0x56, 0x66, 0x2b, 0x39, 0xa5, 0xc7, 0xc0, 0x69, 0x52, 0xec, 0x72, 0xc3, 0xe4, 0x53, 0x59, 0x2a, + 0xce, 0xa3, 0x54, 0x3a, 0x07, 0xee, 0x21, 0x3f, 0xd6, 0xd9, 0xcd, 0xfe, 0xc4, 0xf4, 0xd6, 0xfe, + 0xc1, 0x89, 0x6b, 0x68, 0x38, 0x10, 0xb7, 0x79, 0x99, 0x80, 0xef, 0xeb, 0xdb, 0xd5, 0x93, 0x9f, + 0x36, 0x98, 0xbb, 0x2d, 0xc5, 0x25, 0x7f, 0xbb, 0x26, 0xa3, 0xae, 0xd6, 0xbe, 0x23, 0x84, 0xf6, + 0x7c, 0x74, 0x7a, 0xcf, 0xaf, 0xea, 0x96, 0xe6, 0x2f, 0x73, 0xe7, 0xe4, 0x9b, 0xe5, 0x36, 0x81, + 0x77, 0x6a, 0x99, 0x90, 0x22, 0x3d, 0x47, 0x6d, 0xcd, 0x00, 0xb9, 0xc0, 0x56, 0xaf, 0x6c, 0xf5, + 0x3f, 0x7d, 0x49, 0x4a, 0x4c, 0x93, 0xdd, 0x97, 0x86, 0xc6, 0x9c, 0xbc, 0x88, 0xf9, 0xce, 0x2f, + 0x94, 0xfb, 0x96, 0x22, 0x9a, 0x07, 0xe2, 0xe5, 0xed, 0xab, 0x88, 0xec, 0xce, 0x7f, 0x5f, 0xd3, + 0x6d, 0x3f, 0x0c, 0x94, 0x75, 0x07, 0x87, 0x56, 0x3e, 0x85, 0xfa, 0x5f, 0x22, 0x55, 0x6f, 0x66, + 0x60, 0x87, 0x82, 0x0f, 0x4c, 0x35, 0x7c, 0x87, 0x37, 0x34, 0x17, 0x12, 0xf2, 0x3e, 0xbd, 0x7f, + 0x53, 0x9b, 0x59, 0xcc, 0x05, 0x92, 0x33, 0xbf, 0xca, 0x5c, 0x28, 0x35, 0x01, 0xef, 0x2b, 0xaa, + 0x99, 0x7e, 0x20, 0xb0, 0x12, 0x17, 0x93, 0xc9, 0x15, 0x4d, 0x34, 0x64, 0xb7, 0xce, 0x9d, 0x45, + 0xcf, 0x89, 0x69, 0x30, 0x8e, 0x96, 0xd5, 0x7f, 0xe0, 0xc8, 0xee, 0xa3, 0x73, 0x93, 0xbc, 0xd8, + 0x05, 0xea, 0xb3, 0xad, 0x59, 0x85, 0x4a, 0x13, 0xb2, 0x3c, 0x7b, 0xa4, 0x53, 0x0d, 0x20, 0x7c, + 0xfe, 0xb6, 0x5b, 0x6b, 0xee, 0x0d, 0xe7, 0x7b, 0x93, 0x23, 0x62, 0x25, 0x17, 0x63, 0x85, 0xcd, + 0x74, 0x63, 0xb2, 0xbe, 0x12, 0x3e, 0x7e, 0x78, 0xc9, 0x26, 0x5c, 0x99, 0x97, 0xcb, 0x91, 0xcd, + 0x8f, 0x8f, 0x48, 0x31, 0x65, 0x55, 0x17, 0x6f, 0x28, 0x7e, 0x47, 0x24, 0xba, 0xa9, 0x71, 0x44, + 0x4c, 0x6b, 0xa5, 0x60, 0xba, 0x89, 0x4c, 0xaf, 0x42, 0x48, 0xaa, 0x52, 0x14, 0x95, 0x1a, 0xcd, + 0x5f, 0xe9, 0x36, 0xa1, 0xc7, 0x15, 0xd5, 0x88, 0x2c, 0xd3, 0x45, 0xe6, 0x65, 0x94, 0xe1, 0x2c, + 0xc2, 0xd5, 0xc0, 0x14, 0xc2, 0xe5, 0x4e, 0x5c, 0x1e, 0x15, 0x4f, 0x08, 0xff, 0xb8, 0xc3, 0x5c, + 0xb5, 0xfa, 0x13, 0xd3, 0x6a, 0xbb, 0xe4, 0x63, 0x04, 0xe4, 0x44, 0x09, 0xc7, 0xbd, 0x40, 0xe0, + 0x47, 0x05, 0xfd, 0xc1, 0xe9, 0x2d, 0x91, 0x7f, 0x40, 0x3c, 0x53, 0xdc, 0x31, 0x53, 0xff, 0x92, + 0x55, 0xae, 0x1f, 0x8d, 0x00, 0xd3, 0xf7, 0x63, 0x3c, 0xca, 0xdb, 0x70, 0x8d, 0x22, 0x67, 0x81, + 0x6f, 0x3a, 0xae, 0x8e, 0xf8, 0x1d, 0x17, 0x94, 0x4e, 0x5a, 0xcb, 0x39, 0x5e, 0xb9, 0xda, 0x93, + 0xc2, 0xb2, 0xef, 0x35, 0x3d, 0x61, 0x3e, 0x64, 0x47, 0x22, 0xae, 0xe6, 0xd4, 0xb4, 0x50, 0x65, + 0x30, 0x48, 0xcb, 0xa2, 0x7a, 0x9a, 0x31, 0x29, 0x16, 0x56, 0xd4, 0xb2, 0x2a, 0x32, 0x1f, 0xbb, + 0x42, 0x97, 0xd2, 0x0a, 0xc4, 0x11, 0xd9, 0x85, 0xfd, 0x10, 0x1a, 0xd7, 0x98, 0x1c, 0xa8, 0x7c, + 0x1e, 0xb7, 0x56, 0xc8, 0x62, 0x1e, 0x77, 0xbd, 0xaa, 0xf9, 0x0f, 0x21, 0x2d, 0x38, 0x39, 0x1e, + 0x50, 0x26, 0x3b, 0x89, 0x29, 0x04, 0xc2, 0x8d, 0x34, 0xdb, 0x52, 0x0a, 0x59, 0x5a, 0xa2, 0x1c, + 0xd2, 0x54, 0x89, 0xf4, 0x9b, 0xae, 0x56, 0x6f, 0xbc, 0xb5, 0xd9, 0x12, 0xe6, 0x5c, 0xe9, 0x19, + 0x99, 0x71, 0xc7, 0x3f, 0x5a, 0xee, 0x3b, 0xb6, 0x9b, 0x91, 0x27, 0x49, 0x04, 0xe2, 0x9a, 0x68, + 0xc5, 0x2a, 0x76, 0xad, 0x55, 0x36, 0xb9, 0xba, 0xd7, 0xa3, 0xd1, 0xc2, 0x40, 0x1e, 0xc6, 0xc3, + 0xe9, 0x9a, 0x8e, 0x0d, 0x35, 0x45, 0xca, 0x32, 0x27, 0xfa, 0x1c, 0x60, 0xb1, 0x65, 0xc4, 0x56, + 0x4d, 0xe2, 0x1b, 0x63, 0x33, 0xa6, 0x31, 0xc5, 0x9a, 0x7d, 0x72, 0x8a, 0x27, 0x80, 0xb4, 0xbc, + 0xfe, 0x25, 0xc2, 0xbd, 0x4a, 0xfb, 0xcd, 0x06, 0x20, 0x56, 0xc2, 0x2c, 0xd1, 0x33, 0x0c, 0xb3, + 0xca, 0xcc, 0x0b, 0x0b, 0xb0, 0x0c, 0xe2, 0x4a, 0x79, 0x4a, 0x90, 0x54, 0xe1, 0xca, 0x53, 0x72, + 0x51, 0xa3, 0x2c, 0x7b, 0xd8, 0xd0, 0x80, 0x62, 0x28, 0x7c, 0xed, 0x14, 0x1d, 0x6b, 0xe4, 0x25, + 0xe4, 0x85, 0x0f, 0xb9, 0x11, 0xbe, 0x19, 0x2c, 0x9f, 0xe1, 0x80, 0x26, 0xf4, 0xe3, 0xce, 0x45, + 0x33, 0xff, 0x27, 0xa6, 0x75, 0x02, 0x11, 0xa2, 0x62, 0x99, 0xbd, 0x8a, 0x2d, 0x55, 0xcd, 0xa8, + 0xb0, 0x4a, 0xaf, 0xfc, 0x21, 0xb6, 0x92, 0x89, 0x45, 0x93, 0x21, 0xdd, 0x95, 0xf3, 0x06, 0xe5, + 0xe6, 0x9f, 0x4e, 0xdb, 0x8b, 0xbc, 0x41, 0x8d, 0x4b, 0x91, 0xe3, 0x72, 0xfe, 0xd1, 0xac, 0x0c, + 0x8d, 0xea, 0xc6, 0x70, 0x1a, 0xd5, 0xcb, 0x11, 0x84, 0x23, 0x84, 0xdd, 0x2f, 0x73, 0x26, 0xa3, + 0x7f, 0x2f, 0x95, 0xb0, 0x37, 0x42, 0xb9, 0xcb, 0xe8, 0xd3, 0x4a, 0xeb, 0xab, 0xbb, 0x8d, 0x62, + 0xbb, 0x07, 0x77, 0x15, 0xa9, 0x03, 0x39, 0xc2, 0x5a, 0xc3, 0xf5, 0xad, 0xb2, 0xd2, 0xa6, 0xad, + 0x97, 0x83, 0x97, 0x8a, 0x41, 0x6f, 0x3a, 0x9f, 0xda, 0xf6, 0x34, 0xea, 0xb4, 0xb1, 0x57, 0x1a, + 0xf3, 0x0a, 0x37, 0xe4, 0x8c, 0x42, 0x82, 0xd2, 0xfb, 0x90, 0x98, 0x89, 0x8b, 0x0e, 0xda, 0x6c, + 0xcb, 0xee, 0xd1, 0xc9, 0xe1, 0x6e, 0x76, 0xa7, 0xed, 0x61, 0x4d, 0xac, 0xa1, 0x04, 0x3a, 0x3e, + 0x0b, 0x10, 0x9b, 0xb5, 0xf8, 0x47, 0x3a, 0xc1, 0x9c, 0x0f, 0x6f, 0xb2, 0xdc, 0xbf, 0x0e, 0xaa, + 0x59, 0x62, 0x88, 0x1e, 0x86, 0x15, 0x07, 0xe8, 0x6e, 0xb6, 0xb0, 0x73, 0xdb, 0x9e, 0x53, 0xfb, + 0x1a, 0x6d, 0xdd, 0xb5, 0x69, 0xdd, 0xa3, 0x78, 0xa7, 0x02, 0xe5, 0xc6, 0x55, 0x54, 0xdf, 0xd3, + 0x3c, 0x5d, 0x07, 0xeb, 0xf6, 0x32, 0x0f, 0x55, 0xcf, 0x81, 0x72, 0xc9, 0x3f, 0x07, 0x8f, 0x87, + 0x76, 0x35, 0x50, 0x60, 0xb3, 0x63, 0x2e, 0x07, 0xb6, 0x3c, 0x2a, 0xc6, 0x52, 0xaf, 0x8c, 0x86, + 0x7b, 0x4d, 0xfb, 0xec, 0x1b, 0x15, 0x0e, 0x95, 0x8a, 0x40, 0xbf, 0xa7, 0x1f, 0x5d, 0x88, 0xf6, + 0xb2, 0xb3, 0x3c, 0xe4, 0xb4, 0x22, 0x81, 0xc5, 0xe1, 0x01, 0x58, 0x0e, 0x7b, 0x2c, 0xab, 0x4e, + 0x66, 0x61, 0x56, 0x04, 0xbb, 0x3b, 0x32, 0xb3, 0xa3, 0xf0, 0xbd, 0x29, 0x6a, 0x38, 0x93, 0xf9, + 0xce, 0xf3, 0x99, 0x8b, 0x99, 0x3d, 0x3f, 0x6d, 0x0b, 0x8c, 0x32, 0x88, 0x61, 0xad, 0x8a, 0x6f, + 0xff, 0xa5, 0x3f, 0x05, 0xe7, 0x27, 0xa6, 0x97, 0xd8, 0xee, 0x07, 0x6f, 0x29, 0xfc, 0x57, 0x6f, + 0x13, 0xbb, 0xa6, 0x22, 0xdf, 0x38, 0x99, 0x2e, 0x3d, 0x4b, 0xe4, 0xf8, 0x47, 0x8d, 0x5a, 0x11, + 0xd8, 0xec, 0x11, 0xc5, 0xbd, 0x90, 0xf9, 0xb2, 0x02, 0x38, 0x2b, 0x6f, 0x6c, 0xd0, 0xfc, 0xb5, + 0x59, 0xb4, 0x29, 0x23, 0xeb, 0x85, 0x44, 0xc2, 0x85, 0x2d, 0x9f, 0x17, 0xfe, 0xc7, 0xe7, 0xad, + 0x7d, 0x4f, 0xca, 0xc3, 0xe3, 0xf7, 0xff, 0x8e, 0xf6, 0x4d, 0x3b, 0xd8, 0xb4, 0xc6, 0x52, 0x0e, + 0x2d, 0x3c, 0x3d, 0xdd, 0xf4, 0x14, 0xa4, 0xe6, 0xe8, 0x6d, 0x8a, 0x7c, 0xbe, 0x2d, 0x6f, 0x15, + 0x3d, 0xe6, 0xba, 0xe5, 0xf1, 0xa9, 0x70, 0x42, 0xcd, 0xaf, 0x7b, 0x51, 0x43, 0xb1, 0xa8, 0xbd, + 0xc7, 0x4a, 0x97, 0xdf, 0x5b, 0x91, 0x72, 0x3c, 0xb2, 0x70, 0x9d, 0x17, 0xf9, 0x0d, 0x0a, 0x3d, + 0xd3, 0xfc, 0xf3, 0xab, 0x46, 0xf6, 0x84, 0x59, 0x2e, 0x8b, 0x8a, 0x79, 0xae, 0xc5, 0xa8, 0x6f, + 0x72, 0xdf, 0xf6, 0x6f, 0x28, 0x6a, 0xe6, 0x1a, 0x3c, 0xb9, 0xc7, 0xe5, 0xdd, 0xce, 0xd4, 0x3c, + 0x4c, 0x73, 0x30, 0xad, 0x85, 0x36, 0x08, 0x72, 0xae, 0xd8, 0x56, 0xed, 0xca, 0xdb, 0x53, 0x01, + 0xfa, 0xab, 0xed, 0x70, 0xc3, 0xfc, 0x24, 0xab, 0x7f, 0x53, 0x02, 0xef, 0x48, 0xef, 0xda, 0x84, + 0x98, 0x75, 0xb9, 0xf0, 0x79, 0x3f, 0xa5, 0xd5, 0x6e, 0x2d, 0x57, 0x64, 0x4e, 0x6d, 0x8d, 0x59, + 0xe2, 0xd9, 0x30, 0x95, 0x3e, 0x45, 0x59, 0xd7, 0xf3, 0x42, 0x5f, 0x88, 0x7d, 0x35, 0xa2, 0x50, + 0x8d, 0x25, 0x11, 0x48, 0x87, 0xa6, 0x9f, 0x8a, 0x58, 0x36, 0x0f, 0x7e, 0x1f, 0x6d, 0x0a, 0xfa, + 0x07, 0x37, 0x91, 0xeb, 0x9c, 0x64, 0x29, 0x27, 0xb0, 0x3f, 0xdf, 0xd5, 0xae, 0x35, 0xd4, 0xe1, + 0xe6, 0xe0, 0x29, 0xc2, 0xba, 0xd4, 0x3d, 0xa5, 0x77, 0xe7, 0x1c, 0x99, 0xbd, 0x5e, 0xd6, 0x18, + 0xff, 0xfe, 0xf2, 0xed, 0x37, 0xea, 0xfc, 0x8d, 0x3d, 0xb8, 0xaa, 0xfd, 0xc9, 0x01, 0x4b, 0x81, + 0x6f, 0x0b, 0xb2, 0xa2, 0xa6, 0xf3, 0x11, 0x8c, 0xca, 0xff, 0x72, 0xb6, 0x19, 0xf7, 0x27, 0xa6, + 0xad, 0x0a, 0x93, 0x7d, 0xb8, 0xdb, 0x0b, 0x3f, 0x4e, 0x18, 0xf3, 0xed, 0xa8, 0x2c, 0xdf, 0x97, + 0xa5, 0xab, 0xd7, 0x8e, 0xbe, 0x96, 0x83, 0x0b, 0x0d, 0xe9, 0x6e, 0x5e, 0xe3, 0x3c, 0xa8, 0xb0, + 0x23, 0xce, 0x56, 0x5f, 0x90, 0x3c, 0x1d, 0xb1, 0x94, 0xbd, 0xdb, 0x33, 0x2c, 0x9e, 0x12, 0x7a, + 0x1a, 0x44, 0x56, 0xe8, 0xbe, 0xad, 0x96, 0xdd, 0x9b, 0x4d, 0x9b, 0xc2, 0x6d, 0x1e, 0x7e, 0x89, + 0x0a, 0xf1, 0x04, 0x59, 0xe9, 0x95, 0x5b, 0x78, 0x45, 0xa7, 0xb3, 0x24, 0xd3, 0xee, 0x54, 0xe2, + 0xa5, 0xa0, 0x11, 0x97, 0x69, 0x8d, 0x33, 0x50, 0xe1, 0x55, 0x05, 0xe9, 0x85, 0x4d, 0xb9, 0x35, + 0x7e, 0x9f, 0x22, 0xf6, 0x27, 0x87, 0xdf, 0xb4, 0xfb, 0x47, 0xaf, 0xf1, 0x46, 0x04, 0x3e, 0xad, + 0x39, 0xc6, 0x5a, 0xb6, 0x6a, 0xe1, 0x92, 0x4c, 0xa7, 0xc1, 0xfd, 0xb5, 0x74, 0x67, 0x66, 0xec, + 0xdf, 0x02, 0xec, 0xae, 0x08, 0x67, 0x09, 0x54, 0x44, 0x5f, 0x04, 0x92, 0x8b, 0xd4, 0xd9, 0xb5, + 0xa8, 0xa7, 0x42, 0x2e, 0x34, 0x66, 0x15, 0xfb, 0xfa, 0x37, 0x5b, 0x7b, 0x37, 0x5d, 0xb3, 0xd8, + 0xdb, 0x42, 0x8e, 0x4c, 0xdc, 0xab, 0xa6, 0x8c, 0x83, 0x77, 0x20, 0x9c, 0xdb, 0xbe, 0xd0, 0x46, + 0x79, 0x0f, 0xdd, 0x91, 0xf5, 0x78, 0xbb, 0xb5, 0xae, 0x18, 0xa9, 0xf6, 0x71, 0x9e, 0x76, 0xb3, + 0x5b, 0x89, 0x3e, 0x6e, 0x9e, 0xf4, 0xb8, 0x1e, 0x6a, 0x0e, 0xcb, 0x97, 0x1d, 0x0a, 0x95, 0xf1, + 0x92, 0xba, 0x49, 0xef, 0x37, 0x14, 0xc7, 0x57, 0x11, 0x4f, 0x40, 0xc7, 0x0d, 0x3f, 0x30, 0xbf, + 0xf4, 0x67, 0x1c, 0xa6, 0xba, 0x39, 0x36, 0x92, 0x23, 0xf3, 0xd3, 0xe2, 0x6e, 0xa8, 0x9b, 0x2b, + 0x7b, 0x87, 0x92, 0x86, 0x36, 0x6d, 0xf8, 0x98, 0xe3, 0x83, 0x58, 0x02, 0x57, 0x9a, 0x5d, 0xd8, + 0xbc, 0x73, 0x52, 0x8b, 0xe3, 0x3c, 0x8f, 0x7f, 0xc4, 0xc6, 0x5d, 0x01, 0x1e, 0xf7, 0x31, 0x66, + 0x0b, 0x39, 0xaa, 0x9a, 0x93, 0x09, 0x5b, 0x13, 0xed, 0xb1, 0xe3, 0xc5, 0x8d, 0x7f, 0x39, 0x83, + 0x52, 0xfa, 0x13, 0xd3, 0x36, 0x1b, 0x2e, 0x5f, 0x8e, 0x0b, 0x9c, 0xfe, 0x25, 0xe1, 0xca, 0xe8, + 0xdd, 0x16, 0xd7, 0x95, 0x06, 0x54, 0x93, 0x69, 0x9e, 0xd3, 0x57, 0xf6, 0xda, 0x78, 0xd2, 0x9f, + 0xb8, 0x26, 0xbf, 0xb4, 0x64, 0x07, 0xfe, 0xf9, 0x29, 0xb6, 0x60, 0x1d, 0x99, 0xe6, 0x97, 0xbd, + 0xa1, 0x85, 0xb0, 0x4e, 0x31, 0xa5, 0xb4, 0xee, 0xb4, 0xa9, 0xc6, 0x53, 0x5d, 0x4e, 0xa7, 0x52, + 0x8c, 0x75, 0x5d, 0x52, 0x7c, 0x6e, 0xf7, 0xdf, 0x84, 0xbc, 0xc7, 0xa4, 0xbd, 0x70, 0x80, 0x7e, + 0x13, 0xa4, 0x14, 0xe8, 0x52, 0x28, 0x73, 0xe0, 0xbd, 0x4f, 0xe6, 0x77, 0xea, 0x0e, 0xed, 0xaa, + 0xc5, 0xc3, 0xa6, 0xdf, 0xf6, 0xda, 0x7b, 0xcd, 0x42, 0x33, 0xde, 0x5f, 0xd1, 0x8c, 0xc7, 0xfd, + 0x54, 0x82, 0x7c, 0x5f, 0x37, 0xd4, 0x1a, 0x71, 0x7f, 0x90, 0xf7, 0x31, 0xa9, 0xbf, 0xcd, 0x74, + 0xdf, 0x38, 0xd9, 0x68, 0x4d, 0x05, 0x5f, 0x49, 0xcc, 0x75, 0xce, 0x04, 0xda, 0x69, 0x93, 0x57, + 0x56, 0xad, 0xbf, 0x7f, 0xb1, 0xdf, 0xf4, 0xd3, 0x2b, 0x36, 0xd9, 0x6b, 0xc8, 0x50, 0xbb, 0x6d, + 0x97, 0x07, 0x5a, 0xff, 0x84, 0x9b, 0x77, 0x8c, 0x4a, 0xaf, 0x54, 0xfc, 0xaf, 0x70, 0x72, 0xc4, + 0x3b, 0xf6, 0xab, 0x15, 0xd6, 0x54, 0xa9, 0x14, 0x89, 0x35, 0xce, 0xda, 0x42, 0x51, 0xd1, 0xaf, + 0xed, 0x47, 0xc7, 0x75, 0x12, 0x7e, 0x4d, 0x0d, 0xdb, 0xf6, 0x05, 0xf8, 0x6d, 0x69, 0x78, 0x79, + 0xdc, 0x1e, 0x0a, 0x1c, 0x0f, 0xb5, 0x54, 0x63, 0x44, 0xb6, 0xd9, 0x2a, 0x25, 0x0f, 0xed, 0x4b, + 0x8c, 0xeb, 0x36, 0x6a, 0x42, 0x3e, 0xbf, 0xa7, 0x57, 0xe0, 0xe8, 0x69, 0x44, 0x23, 0xda, 0xf1, + 0xf7, 0x99, 0xaa, 0x2b, 0xd0, 0xce, 0x27, 0x40, 0x6b, 0xa7, 0xf1, 0x77, 0x93, 0x96, 0xbe, 0x2a, + 0x9d, 0xf1, 0xd2, 0x80, 0x50, 0x4e, 0x8e, 0xb2, 0xc6, 0xbf, 0xd0, 0xa9, 0xb8, 0xfd, 0xfc, 0xbe, + 0x16, 0xce, 0xc7, 0x27, 0xa1, 0x70, 0x23, 0x40, 0xeb, 0x2e, 0xaa, 0xf0, 0xf3, 0xed, 0xbd, 0xf5, + 0xbc, 0xf6, 0xe3, 0x5e, 0xfe, 0x05, 0xc5, 0x4f, 0x4c, 0xc3, 0x22, 0x67, 0xf0, 0x1c, 0xd7, 0xff, + 0xc1, 0xf8, 0xd9, 0x8b, 0x17, 0x51, 0xfc, 0xc5, 0xb6, 0xfd, 0x88, 0xd1, 0x33, 0x03, 0x67, 0xef, + 0x65, 0xc9, 0xa9, 0x3b, 0xcc, 0xbd, 0x5f, 0xda, 0x5c, 0x57, 0x46, 0x5a, 0xef, 0xce, 0xf7, 0x60, + 0xef, 0x90, 0x07, 0xca, 0x0f, 0xf6, 0xc3, 0x96, 0xc7, 0x96, 0x2b, 0x2c, 0xe7, 0xb5, 0x4a, 0xd7, + 0x97, 0xc6, 0x22, 0x35, 0x03, 0x02, 0xa5, 0x96, 0x0c, 0x04, 0x89, 0x96, 0xb9, 0x6e, 0x0f, 0x94, + 0x42, 0xbb, 0x86, 0x23, 0x1f, 0x3a, 0xed, 0x0d, 0xfd, 0x92, 0xd3, 0x6f, 0x17, 0x5e, 0x07, 0x02, + 0xa3, 0xb9, 0x15, 0xd6, 0xdf, 0x14, 0x39, 0x74, 0x44, 0x60, 0xbc, 0xbb, 0xda, 0xf5, 0x19, 0x24, + 0xad, 0x39, 0xc5, 0x81, 0xbb, 0x2b, 0x95, 0x49, 0xc4, 0xa4, 0xfa, 0xd9, 0xed, 0x59, 0x61, 0x6e, + 0x7c, 0xfd, 0x19, 0x8b, 0xf3, 0xee, 0x2e, 0xdc, 0xcd, 0x88, 0xa4, 0x0b, 0x26, 0xfd, 0x01, 0xd5, + 0x21, 0xfe, 0x88, 0xdc, 0x67, 0xa7, 0xe3, 0x6b, 0xfe, 0xd9, 0xb9, 0x80, 0xf7, 0xbd, 0x1e, 0xb1, + 0xdf, 0x74, 0x54, 0xbf, 0xf9, 0xe4, 0xff, 0x4d, 0x81, 0x16, 0x59, 0x47, 0xa8, 0xf5, 0x97, 0x55, + 0xac, 0x08, 0xf0, 0xb4, 0xd2, 0x5d, 0x15, 0x15, 0xaa, 0xf4, 0x8b, 0xc2, 0x95, 0x54, 0xf0, 0xbc, + 0xe2, 0x84, 0x8e, 0xe7, 0x10, 0xa7, 0xf3, 0x3c, 0x81, 0x8b, 0x9e, 0xe5, 0x35, 0x28, 0xb8, 0x67, + 0xf7, 0x8a, 0x53, 0x18, 0x4f, 0x82, 0xb0, 0xcd, 0xa0, 0x15, 0x99, 0x21, 0xc1, 0x3c, 0x32, 0x3b, + 0x02, 0x47, 0x0c, 0x2b, 0x2f, 0xda, 0x41, 0x56, 0x92, 0xa2, 0x12, 0xf4, 0x8d, 0x2d, 0x52, 0xde, + 0xb4, 0x3b, 0x82, 0xab, 0x9b, 0xe1, 0xaa, 0xe0, 0x40, 0xfc, 0xd6, 0x17, 0x1a, 0x5c, 0x2f, 0x0a, + 0x98, 0xc7, 0x18, 0x58, 0xb0, 0x8d, 0xb1, 0x90, 0x12, 0xff, 0x8d, 0x3f, 0xb9, 0xea, 0x67, 0xdc, + 0x49, 0xa9, 0x83, 0xc1, 0x69, 0xd9, 0x25, 0x94, 0xd8, 0xe5, 0xc3, 0x10, 0x33, 0xa1, 0xcd, 0xe6, + 0x85, 0xdd, 0x5f, 0x21, 0xd1, 0x8f, 0x71, 0x9a, 0x61, 0xfd, 0xc4, 0x34, 0x51, 0x0b, 0xa7, 0x13, + 0x49, 0xae, 0x4d, 0x6b, 0xb0, 0xf5, 0x26, 0xa2, 0x07, 0x3c, 0x47, 0x8c, 0xd4, 0xf3, 0x0d, 0x01, + 0x4c, 0x9a, 0xaf, 0x15, 0x91, 0xa4, 0x74, 0xa6, 0xbc, 0x76, 0x9f, 0xed, 0xd4, 0x37, 0x4e, 0xf2, + 0xab, 0xc3, 0xc4, 0x7f, 0x92, 0x99, 0xc2, 0xce, 0x77, 0xba, 0x00, 0x1b, 0xb4, 0xdf, 0xea, 0x50, + 0xf4, 0xc5, 0x5e, 0x95, 0xa7, 0x5d, 0xe9, 0x5f, 0xbb, 0x10, 0xc3, 0x17, 0x4a, 0x08, 0x69, 0x98, + 0x3a, 0x8e, 0xa7, 0xd9, 0x12, 0x08, 0xc2, 0x3b, 0x26, 0x91, 0xab, 0x47, 0x7c, 0x95, 0x1b, 0x11, + 0x25, 0xa5, 0x71, 0x95, 0x79, 0x98, 0x06, 0x4a, 0xf2, 0xf1, 0xc0, 0xc7, 0xd4, 0x04, 0x83, 0x88, + 0x92, 0x54, 0x0e, 0x5d, 0xc8, 0xaa, 0x54, 0x70, 0x80, 0x4a, 0x27, 0xfb, 0x0f, 0x3e, 0x94, 0xbe, + 0x0e, 0xf4, 0x47, 0x26, 0xc2, 0xf9, 0x36, 0xef, 0x90, 0x23, 0xc1, 0x70, 0xbd, 0x09, 0x4f, 0x82, + 0xc5, 0xa6, 0x44, 0xad, 0x13, 0xc6, 0x26, 0x4c, 0x23, 0x97, 0x48, 0x30, 0x21, 0x7e, 0x2c, 0xc1, + 0xb4, 0x0c, 0x7f, 0x90, 0xf4, 0xc8, 0x56, 0x25, 0x75, 0x23, 0xfb, 0x7e, 0x0b, 0x9d, 0x16, 0x14, + 0x75, 0x8e, 0xb1, 0x50, 0x5e, 0x9c, 0x91, 0x38, 0x90, 0x38, 0xa1, 0x75, 0x20, 0x4d, 0xed, 0x92, + 0xc3, 0x09, 0x05, 0xc3, 0xd9, 0xa6, 0xca, 0x13, 0x2c, 0x34, 0x55, 0x98, 0x36, 0x1d, 0x37, 0xb3, + 0x24, 0x86, 0xa8, 0x33, 0xa2, 0xd0, 0x5c, 0x0e, 0x82, 0x1d, 0x0d, 0x31, 0xba, 0xa9, 0x95, 0x06, + 0x8c, 0xfb, 0x35, 0xec, 0x8f, 0xbf, 0xcc, 0xa4, 0xf7, 0x9f, 0xc9, 0xa0, 0x2c, 0xa1, 0x79, 0x4d, + 0x43, 0xdb, 0x11, 0x59, 0x5c, 0xbe, 0x57, 0x5c, 0xc8, 0x74, 0x63, 0x9b, 0x27, 0x78, 0xde, 0x09, + 0x76, 0xea, 0xf5, 0x6a, 0xf5, 0x2c, 0xa2, 0x29, 0x38, 0xff, 0x1e, 0x5b, 0xf4, 0xcc, 0x46, 0x36, + 0xfa, 0x47, 0x51, 0x9b, 0x4e, 0xfb, 0xe4, 0x7e, 0xab, 0x25, 0xe3, 0x61, 0xb1, 0xe7, 0xce, 0xef, + 0xda, 0x2b, 0xc2, 0x28, 0xf1, 0xe3, 0x98, 0xfe, 0x18, 0xbc, 0xff, 0x6e, 0x9a, 0xe4, 0x3f, 0x52, + 0xe5, 0x7b, 0x1c, 0xae, 0x21, 0x3c, 0x3c, 0x57, 0xcf, 0x60, 0x00, 0x8e, 0xb4, 0x97, 0x8c, 0x8f, + 0xb5, 0x56, 0x39, 0xe7, 0x45, 0x96, 0xf8, 0x1a, 0xd3, 0xc6, 0xff, 0xe6, 0xb9, 0xde, 0x83, 0x7a, + 0x39, 0x57, 0x70, 0x7d, 0xfc, 0xf8, 0x46, 0xa8, 0x0b, 0xc7, 0x25, 0xfa, 0xb7, 0x2f, 0x23, 0xf8, + 0xa0, 0x22, 0xbf, 0xd4, 0x80, 0x95, 0x5a, 0xce, 0xc7, 0xd4, 0xa7, 0x76, 0x2d, 0xae, 0x67, 0x1a, + 0x6c, 0x98, 0x19, 0xb5, 0x88, 0x67, 0xa1, 0x56, 0x35, 0xb1, 0xbe, 0x3e, 0x9d, 0xc3, 0x03, 0x3a, + 0xcb, 0xdf, 0xb8, 0x67, 0x63, 0xac, 0xf9, 0xab, 0x0f, 0x09, 0x6c, 0x8f, 0xc5, 0xb2, 0xb6, 0x20, + 0x5c, 0x63, 0xe6, 0x26, 0x45, 0xc3, 0x3a, 0x80, 0x8b, 0xdf, 0x7b, 0x54, 0xaf, 0xa4, 0x15, 0x8f, + 0xe5, 0xa2, 0xb3, 0xd3, 0x50, 0xae, 0x81, 0x5a, 0xd3, 0xd0, 0xb3, 0xcf, 0xfb, 0x8a, 0x8b, 0x46, + 0xde, 0x97, 0xb9, 0x4b, 0xba, 0xdd, 0xcb, 0x15, 0xa1, 0xdd, 0xb6, 0x54, 0x6f, 0x50, 0x62, 0xb6, + 0xb5, 0xbb, 0x44, 0x27, 0xe7, 0x3f, 0x89, 0xb0, 0xc2, 0x7b, 0x3e, 0x6f, 0x19, 0x07, 0x25, 0xbf, + 0xc4, 0x2f, 0x4d, 0xa2, 0x6f, 0xab, 0xd2, 0x2e, 0x02, 0x45, 0x72, 0x8c, 0xf1, 0x25, 0x0f, 0x09, + 0xad, 0x7f, 0x02, 0xf8, 0xb3, 0xf3, 0x7b, 0x43, 0x50, 0x42, 0x03, 0xec, 0x24, 0x90, 0x42, 0xb3, + 0xcb, 0x6e, 0x18, 0x5d, 0x58, 0xfc, 0xcb, 0x7b, 0x58, 0x86, 0xf2, 0xb5, 0xa9, 0x7b, 0x93, 0x60, + 0x27, 0x8c, 0xe9, 0x05, 0x08, 0xaa, 0x9e, 0x5f, 0x0b, 0xfe, 0x6f, 0x3e, 0x9a, 0xf7, 0xcf, 0x4b, + 0xb9, 0xbc, 0xcd, 0x33, 0xb4, 0xbc, 0x16, 0x52, 0x4c, 0xed, 0x03, 0x8e, 0x8d, 0xd7, 0xe2, 0x41, + 0xa2, 0x3a, 0xbc, 0x0e, 0xef, 0xb5, 0x66, 0x6b, 0x7f, 0x42, 0x5f, 0xb3, 0xa5, 0x67, 0x2f, 0x32, + 0x65, 0xfb, 0xab, 0xfa, 0x4a, 0xf3, 0x53, 0x01, 0xf6, 0xaa, 0xf0, 0xf2, 0xbe, 0xc3, 0x44, 0x79, + 0x1e, 0xf8, 0x55, 0x5a, 0x57, 0xdc, 0x95, 0x93, 0xeb, 0xf6, 0x7f, 0x39, 0x83, 0x52, 0xfd, 0x13, + 0xd3, 0xd9, 0xfd, 0xe8, 0x49, 0x12, 0xe7, 0xc9, 0x54, 0xac, 0x05, 0xf8, 0x00, 0xe1, 0x08, 0xac, + 0xc8, 0x1b, 0x31, 0x53, 0x83, 0xd7, 0x21, 0xbd, 0xf2, 0xf1, 0xf4, 0xe4, 0xd5, 0x4c, 0xf8, 0x08, + 0xe0, 0xc5, 0x88, 0xf7, 0xd5, 0xea, 0xe6, 0x56, 0x2a, 0x3d, 0x0b, 0x38, 0xd2, 0x9b, 0xfa, 0xb4, + 0x37, 0xb1, 0xf8, 0x2e, 0xaf, 0xde, 0xd4, 0x6a, 0x02, 0xff, 0x47, 0x3e, 0x1f, 0x3b, 0x1d, 0xe7, + 0xc9, 0x84, 0xbb, 0x57, 0x27, 0xec, 0x25, 0x17, 0x51, 0x2b, 0x10, 0xe4, 0x2b, 0xe5, 0x98, 0x54, + 0x5e, 0xe0, 0xab, 0xed, 0xfa, 0x6b, 0xd2, 0xa6, 0x52, 0xb5, 0x35, 0x4d, 0x62, 0xa9, 0xcd, 0xa6, + 0x12, 0x43, 0xf3, 0xeb, 0xf6, 0xe9, 0x79, 0x92, 0xdd, 0x4d, 0xfb, 0x77, 0x2f, 0x85, 0xd6, 0xca, + 0x38, 0xec, 0x3e, 0x21, 0xed, 0x5a, 0x9c, 0xaa, 0x49, 0xc3, 0xb9, 0xb5, 0xf6, 0x6e, 0xf6, 0xb8, + 0xf9, 0x9f, 0xe1, 0x3e, 0x98, 0x3a, 0x04, 0x2e, 0x79, 0x55, 0xbf, 0x42, 0x1d, 0x7d, 0x3b, 0x22, + 0x52, 0xa2, 0xcd, 0x70, 0x07, 0x8b, 0xc1, 0xfe, 0x6f, 0x80, 0xcc, 0x3a, 0x64, 0x49, 0x64, 0x7b, + 0xbe, 0xda, 0x92, 0x99, 0x99, 0xfd, 0xa2, 0x09, 0x8f, 0x3a, 0x0c, 0x4e, 0x9d, 0x9c, 0xc4, 0x53, + 0xd1, 0xa3, 0xe7, 0x76, 0x55, 0x07, 0x8e, 0x56, 0xfe, 0xb9, 0x51, 0xf0, 0x0d, 0x04, 0xcd, 0xc7, + 0xf7, 0xa5, 0xdc, 0xcd, 0x3d, 0xba, 0xe4, 0xa7, 0x55, 0xdc, 0x54, 0xce, 0xe0, 0x9b, 0x32, 0x8e, + 0x43, 0xfa, 0x4c, 0x6a, 0x74, 0x44, 0x2f, 0x98, 0x3f, 0x2e, 0x6e, 0x06, 0xd4, 0xc9, 0xc6, 0xad, + 0x79, 0xd7, 0x5d, 0x38, 0x8e, 0x97, 0xb4, 0xee, 0x91, 0xb1, 0x1b, 0xf1, 0xe0, 0x4f, 0x42, 0x2d, + 0xb7, 0x22, 0x30, 0xa1, 0x49, 0x5e, 0xac, 0x4a, 0xa4, 0x83, 0x97, 0xc4, 0x63, 0xf5, 0x95, 0x2a, + 0x39, 0x6e, 0x46, 0xfb, 0x45, 0x8a, 0x6d, 0x77, 0x44, 0xc7, 0xff, 0x9b, 0xc7, 0x9f, 0x6a, 0x78, + 0x53, 0x4a, 0x8b, 0x18, 0x2b, 0x19, 0x45, 0xbf, 0x06, 0xa5, 0x4d, 0x07, 0xf5, 0x63, 0x6f, 0x2c, + 0xdd, 0xbf, 0x9b, 0x36, 0x4b, 0xa5, 0xca, 0xd0, 0xd2, 0x66, 0xb1, 0x17, 0xed, 0x2f, 0x39, 0xf0, + 0xea, 0xdb, 0x37, 0x75, 0xa1, 0xe0, 0x63, 0x5d, 0x2a, 0x20, 0x88, 0x23, 0x3a, 0xa2, 0x2a, 0x95, + 0xee, 0x79, 0xc1, 0x3f, 0x6f, 0x17, 0x1c, 0x4c, 0xcd, 0x17, 0xf9, 0x90, 0x5a, 0x9a, 0xdd, 0xf7, + 0x73, 0xf4, 0xbb, 0xa6, 0xe3, 0x11, 0xab, 0xee, 0x6b, 0x25, 0xe9, 0xa1, 0x11, 0xed, 0x2c, 0x9a, + 0xad, 0xc1, 0x0a, 0xac, 0x74, 0xaf, 0xa5, 0xf9, 0xb5, 0xe7, 0xdb, 0xb6, 0x6d, 0xdf, 0xb9, 0x15, + 0x9a, 0x36, 0xc4, 0x8d, 0x47, 0x11, 0x5e, 0x49, 0xd4, 0x43, 0x39, 0xd7, 0x91, 0x9b, 0xd1, 0xd7, + 0x44, 0xf8, 0x88, 0x11, 0xe5, 0xfb, 0x6b, 0x65, 0xed, 0xa5, 0x68, 0xe5, 0x6b, 0x3d, 0x33, 0xe4, + 0xae, 0x73, 0x73, 0xd4, 0x69, 0xe6, 0x15, 0xd0, 0x7f, 0x44, 0xe2, 0x6b, 0xe7, 0xdd, 0x98, 0x2f, + 0x6b, 0x25, 0x95, 0xfd, 0x7e, 0x8d, 0x9b, 0x57, 0x1e, 0x1d, 0xb5, 0x5e, 0x76, 0x8d, 0x65, 0xaa, + 0x0a, 0xef, 0xdc, 0x96, 0x37, 0x8d, 0xe2, 0xd4, 0x38, 0x25, 0x37, 0xa2, 0x52, 0xba, 0x60, 0x55, + 0x95, 0xb9, 0x6f, 0xc7, 0xca, 0x5e, 0x7b, 0x29, 0x16, 0xb9, 0x25, 0xfb, 0xf9, 0x33, 0x12, 0x06, + 0xfe, 0x28, 0x9e, 0xb7, 0x66, 0xf7, 0x95, 0x35, 0x7a, 0xda, 0xa6, 0x3b, 0xed, 0x2d, 0xed, 0x17, + 0x6b, 0xb6, 0xdc, 0x05, 0xb9, 0x96, 0x96, 0x2b, 0xdd, 0x2f, 0xf1, 0x77, 0xde, 0xa0, 0x37, 0xee, + 0x53, 0x07, 0xc9, 0x6b, 0xcd, 0x44, 0xc1, 0xaa, 0xfc, 0x73, 0x5b, 0x8e, 0x2f, 0x38, 0x1b, 0x7e, + 0xe9, 0x08, 0x21, 0x44, 0xa5, 0x90, 0xec, 0x1c, 0xf5, 0xef, 0x23, 0x0a, 0x88, 0x32, 0xc8, 0x33, + 0x9e, 0x6a, 0x6f, 0x37, 0x47, 0xdb, 0xdb, 0x82, 0xbf, 0x9e, 0x52, 0x21, 0xee, 0x41, 0x91, 0xf3, + 0x9a, 0x74, 0x46, 0xba, 0x9d, 0x37, 0x91, 0x76, 0x61, 0x5e, 0xa8, 0x50, 0x20, 0xb3, 0xf3, 0x8a, + 0x2d, 0xbc, 0x82, 0xed, 0xef, 0x44, 0x58, 0x20, 0x78, 0x3a, 0xb9, 0x54, 0x5e, 0xe2, 0xfe, 0x11, + 0xb0, 0xf3, 0xc4, 0xfa, 0xb1, 0x3f, 0xc5, 0xc2, 0x4f, 0xc6, 0x74, 0x3a, 0x0f, 0xdb, 0x59, 0xdf, + 0xc2, 0xa6, 0x68, 0x89, 0x98, 0x16, 0xa5, 0x10, 0x62, 0xd9, 0xa6, 0xb2, 0x4b, 0x05, 0x47, 0x45, + 0x3d, 0xaa, 0x19, 0x27, 0xe6, 0x15, 0x24, 0xa8, 0x9b, 0xe2, 0xd5, 0xaf, 0x11, 0x98, 0x5a, 0xdd, + 0xe9, 0xd3, 0xfc, 0x82, 0xf6, 0x7b, 0x0b, 0x1d, 0xc7, 0x4f, 0x29, 0x0a, 0xe7, 0x1f, 0xa5, 0xf2, + 0xa0, 0x02, 0x5d, 0xbc, 0x7f, 0x8f, 0x46, 0xb6, 0x98, 0x3e, 0xef, 0x69, 0x6b, 0x9d, 0x20, 0x09, + 0x95, 0x9c, 0x1d, 0xd1, 0x52, 0xfc, 0xab, 0xf0, 0xf7, 0x6e, 0x6b, 0xe6, 0x26, 0x90, 0x48, 0x5c, + 0x8b, 0xeb, 0xda, 0xf9, 0xeb, 0xa2, 0x2a, 0x0d, 0x18, 0xb7, 0xeb, 0x78, 0x85, 0x43, 0x78, 0xc3, + 0xd9, 0xf4, 0x7e, 0xe9, 0xa5, 0xc6, 0x31, 0xfa, 0x3a, 0x11, 0x45, 0xfe, 0xc9, 0x15, 0x81, 0x1d, + 0xf7, 0x7e, 0xbd, 0xe6, 0x63, 0xe9, 0xdd, 0x8d, 0xad, 0xb5, 0x89, 0x29, 0x99, 0xc0, 0x54, 0x6b, + 0x0d, 0x7b, 0x77, 0xd8, 0xb7, 0x99, 0x9c, 0xf8, 0x14, 0xe5, 0xd9, 0x20, 0x37, 0x99, 0x17, 0xbb, + 0x5b, 0x42, 0x58, 0x14, 0x7e, 0xab, 0xcf, 0x9c, 0x06, 0x6b, 0xc9, 0x45, 0x4d, 0xfc, 0xa8, 0xad, + 0xb9, 0x08, 0x8f, 0xb8, 0x96, 0x9b, 0x01, 0xba, 0x29, 0x03, 0xdc, 0x01, 0x0b, 0x21, 0x94, 0x98, + 0x0d, 0x57, 0x3c, 0x59, 0x39, 0x69, 0xbd, 0xdc, 0x46, 0x85, 0xf2, 0x01, 0x8d, 0x60, 0x57, 0x19, + 0xf3, 0x62, 0x33, 0x31, 0xf2, 0xe2, 0xe1, 0xd4, 0xc8, 0x1f, 0x51, 0x4c, 0x1b, 0x5d, 0x95, 0x61, + 0xf2, 0xf2, 0xae, 0xc7, 0xf0, 0x61, 0x71, 0xbf, 0x4d, 0x15, 0xed, 0xf2, 0x32, 0xc0, 0x9c, 0xf5, + 0x81, 0x91, 0xf1, 0x3b, 0xa6, 0x2a, 0x9b, 0x8b, 0x2c, 0x0c, 0x70, 0xbf, 0x22, 0x59, 0xab, 0xdc, + 0x99, 0x98, 0x9d, 0x96, 0xed, 0x20, 0xdc, 0x77, 0x33, 0x01, 0xcd, 0x08, 0x4a, 0x21, 0x15, 0x5b, + 0x40, 0x6a, 0x10, 0xf6, 0x2a, 0xe8, 0x25, 0x37, 0x73, 0x24, 0x88, 0x72, 0xf5, 0x60, 0x94, 0x02, + 0xba, 0x3b, 0xbe, 0x1f, 0xe3, 0x34, 0x62, 0xfe, 0x89, 0x69, 0x36, 0x5c, 0x40, 0x16, 0xeb, 0x3c, + 0xed, 0xc1, 0x7f, 0x5a, 0x9a, 0xae, 0xc7, 0x7d, 0xbd, 0x8c, 0x9b, 0x3d, 0x28, 0x57, 0x5b, 0xe8, + 0x76, 0xcb, 0x51, 0xaa, 0xb3, 0x62, 0xd1, 0x4a, 0xda, 0xab, 0xa4, 0x81, 0x62, 0x92, 0x45, 0x67, + 0x9f, 0x19, 0x01, 0xde, 0xe7, 0x17, 0xa0, 0xfe, 0x97, 0xff, 0x96, 0xc9, 0x1d, 0xec, 0x21, 0x18, + 0x68, 0xd3, 0xf9, 0xbe, 0x8a, 0xdc, 0x90, 0x7d, 0xd1, 0x5e, 0x88, 0x13, 0xd6, 0x3a, 0x4f, 0x92, + 0xc8, 0x80, 0xd4, 0x63, 0x6d, 0x35, 0x7b, 0x4e, 0x24, 0x64, 0x75, 0x8d, 0x43, 0xb2, 0x2a, 0x2d, + 0xcb, 0xad, 0xac, 0xe4, 0x48, 0x4e, 0x61, 0x99, 0xb8, 0x7f, 0x1f, 0x13, 0x06, 0x82, 0x44, 0x9f, + 0x69, 0x42, 0x33, 0x55, 0xbe, 0x5f, 0x3c, 0xc8, 0x5a, 0x65, 0x67, 0xd8, 0x4c, 0x4e, 0x92, 0xa6, + 0x33, 0x3a, 0x10, 0x7f, 0x0d, 0xc6, 0xd7, 0x42, 0x43, 0x9b, 0x89, 0x04, 0x93, 0xe9, 0x70, 0x57, + 0x46, 0xaa, 0x38, 0xfe, 0x03, 0x2e, 0x9b, 0xe3, 0xa4, 0xfe, 0x53, 0xb1, 0x1d, 0x11, 0x2d, 0xc8, + 0x32, 0x10, 0x6d, 0x0f, 0x0c, 0x71, 0xba, 0x6e, 0xee, 0x58, 0xb6, 0xd1, 0xb8, 0xdc, 0xb2, 0xe3, + 0x5f, 0x05, 0xae, 0x0f, 0x52, 0x98, 0x26, 0xac, 0xda, 0xbe, 0x17, 0xe6, 0x7c, 0xbf, 0xdf, 0x6b, + 0x8a, 0x3b, 0x54, 0x9b, 0x73, 0x7d, 0xe0, 0x9b, 0x56, 0x13, 0xb4, 0xa7, 0x5b, 0xf5, 0x6e, 0xdc, + 0x65, 0x60, 0xd0, 0x78, 0x21, 0x35, 0xf0, 0x5a, 0xbb, 0x53, 0x42, 0xd7, 0xfb, 0xe1, 0x8c, 0xe8, + 0xe0, 0xf1, 0x24, 0x91, 0x11, 0xdf, 0x36, 0xe2, 0x84, 0xc9, 0xe0, 0xcd, 0x3d, 0x29, 0xbd, 0xf7, + 0xf7, 0xb1, 0x2a, 0x12, 0x60, 0x25, 0xae, 0xe2, 0xe8, 0x4a, 0x0e, 0x7a, 0xc4, 0xaf, 0x73, 0x8f, + 0x43, 0x71, 0x76, 0x51, 0x76, 0x54, 0xbf, 0x8a, 0x2a, 0xf5, 0x13, 0xc2, 0xf1, 0x48, 0x7c, 0x69, + 0x7d, 0xcc, 0x5f, 0x68, 0x48, 0x8a, 0x54, 0x11, 0x8d, 0xcd, 0xa4, 0x7c, 0x25, 0xd5, 0x90, 0xb1, + 0x7f, 0x8d, 0x43, 0xf2, 0x1f, 0xbb, 0x90, 0xa1, 0xbb, 0x3f, 0x31, 0x3d, 0x67, 0x3f, 0x90, 0x27, + 0x74, 0x91, 0x00, 0x2d, 0x7b, 0xab, 0x3d, 0xd1, 0x34, 0x96, 0xde, 0x69, 0x3b, 0xee, 0xfb, 0x36, + 0x91, 0x2f, 0x79, 0xf9, 0x1c, 0x7c, 0xa7, 0x12, 0xba, 0x31, 0x9d, 0x36, 0x24, 0x36, 0x92, 0x3a, + 0x7e, 0xed, 0x7e, 0x92, 0x7f, 0xf2, 0xd5, 0x02, 0x5f, 0x93, 0xb5, 0xf1, 0x1d, 0xd9, 0xab, 0xd7, + 0xdb, 0x06, 0x0d, 0x0c, 0x91, 0xc9, 0x95, 0x62, 0x99, 0x9c, 0x59, 0x49, 0x0d, 0xe9, 0x9e, 0xde, + 0xf2, 0xb1, 0x0a, 0x16, 0x94, 0x88, 0xe4, 0x55, 0xc1, 0x7f, 0x9f, 0xbe, 0x36, 0xea, 0x3d, 0x8d, + 0xa1, 0x84, 0x9c, 0x28, 0xbe, 0x68, 0xf7, 0xcf, 0xd3, 0x57, 0xaf, 0x36, 0xe3, 0x6b, 0xf2, 0xca, + 0x86, 0x90, 0x3c, 0xc3, 0xd5, 0x98, 0x6e, 0xea, 0x6b, 0xeb, 0xb2, 0x1e, 0x48, 0x07, 0x16, 0x1a, + 0x86, 0x5a, 0xb0, 0x9c, 0xa0, 0x32, 0x38, 0xd5, 0xa4, 0x8a, 0x91, 0x8e, 0x5e, 0xdd, 0xb0, 0x72, + 0xde, 0x4c, 0xde, 0xc9, 0x22, 0x2a, 0x28, 0x99, 0xbe, 0x4c, 0xe6, 0x2e, 0x9f, 0xce, 0xda, 0x70, + 0xf1, 0xac, 0x5f, 0xc9, 0x9e, 0x7a, 0xfb, 0x76, 0x70, 0xa7, 0x3a, 0x2e, 0x25, 0x34, 0xbd, 0xb5, + 0x01, 0x1d, 0xd9, 0x19, 0x0a, 0x44, 0xd5, 0xa7, 0xd3, 0xb4, 0x86, 0x3e, 0x68, 0x75, 0x85, 0x7a, + 0xd5, 0x51, 0x6a, 0xac, 0x73, 0x75, 0x86, 0xba, 0x7d, 0x55, 0x48, 0x31, 0xef, 0xaf, 0x97, 0x77, + 0x53, 0xb7, 0xfe, 0x38, 0x8a, 0xe9, 0xe4, 0xd4, 0x78, 0x54, 0x1a, 0x0f, 0x92, 0xfd, 0xda, 0xd1, + 0xe4, 0xdb, 0xbe, 0x3d, 0x40, 0xd3, 0x4f, 0x82, 0xa7, 0x59, 0xfa, 0x5a, 0x16, 0xfb, 0x6f, 0x87, + 0xac, 0xaf, 0xd5, 0x93, 0xf3, 0x81, 0x8d, 0x43, 0x00, 0x7b, 0xaa, 0xbe, 0xa7, 0x8d, 0x3c, 0xb0, + 0x14, 0xd2, 0x30, 0x66, 0xc5, 0x5b, 0xe6, 0xe1, 0xfd, 0x2b, 0x55, 0xa6, 0x8d, 0x81, 0xf9, 0xa2, + 0xa5, 0x78, 0xd6, 0x7d, 0x14, 0x4c, 0x76, 0x17, 0x45, 0x3e, 0x4b, 0x75, 0x4c, 0x1a, 0x1b, 0xc9, + 0xcc, 0xfe, 0xc3, 0xf7, 0xbb, 0x37, 0xf9, 0xfa, 0xc9, 0x8f, 0xa7, 0x7d, 0x52, 0xd0, 0x4f, 0x4c, + 0x03, 0x0d, 0xd9, 0x29, 0x12, 0x6e, 0xac, 0x39, 0x91, 0x6b, 0x48, 0x4e, 0x53, 0x99, 0x5d, 0xc5, + 0x23, 0x83, 0x9a, 0x94, 0x67, 0x54, 0xbf, 0xb4, 0x2e, 0x6e, 0x95, 0x49, 0xe7, 0x47, 0x42, 0x4a, + 0x1e, 0xb8, 0x31, 0xc5, 0xdf, 0x6e, 0xbb, 0x5a, 0xff, 0xe8, 0x09, 0x1e, 0x86, 0x61, 0x9f, 0x9f, + 0x5d, 0x9f, 0x3d, 0x76, 0x1d, 0xbe, 0xa9, 0x8d, 0xcf, 0xa1, 0x6f, 0x6a, 0xcb, 0x46, 0xc8, 0xae, + 0xdb, 0x3b, 0x2b, 0x37, 0xaf, 0xec, 0x7a, 0x62, 0x35, 0x1f, 0x05, 0x7b, 0xbb, 0xea, 0x74, 0x89, + 0x88, 0x77, 0xff, 0xb8, 0x3d, 0x19, 0x74, 0xff, 0xba, 0x3d, 0x8d, 0x77, 0x8a, 0x0d, 0x3f, 0x84, + 0x35, 0xf6, 0x82, 0x69, 0x76, 0xd7, 0x75, 0x3c, 0xd6, 0x8c, 0x4f, 0xf0, 0xa0, 0x32, 0xa2, 0x95, + 0x95, 0x61, 0x7d, 0xcf, 0xd5, 0x51, 0x3c, 0xd7, 0x4f, 0xba, 0x98, 0x93, 0xfe, 0x53, 0x0f, 0xf8, + 0x68, 0x72, 0xe6, 0xf2, 0xd1, 0x98, 0x9c, 0xbe, 0x26, 0x36, 0x42, 0x82, 0x88, 0xfd, 0x3e, 0x69, + 0xaf, 0x22, 0xa1, 0x59, 0x9e, 0xa0, 0xba, 0xe6, 0x37, 0xc3, 0xa3, 0x2e, 0x3e, 0x04, 0xec, 0xe6, + 0xd9, 0xa4, 0xec, 0xcf, 0x33, 0x3c, 0xb9, 0x74, 0x3a, 0xf2, 0xb0, 0xb9, 0x25, 0x62, 0x31, 0x94, + 0xbd, 0xa9, 0x26, 0xb2, 0xc5, 0xd3, 0x82, 0x2b, 0x24, 0xcf, 0x98, 0x15, 0x29, 0x40, 0x1c, 0x60, + 0xb2, 0x1d, 0x5b, 0xdd, 0x56, 0x36, 0x1f, 0xc0, 0xe7, 0xd4, 0xb5, 0x24, 0xd4, 0x47, 0xfb, 0x43, + 0xb3, 0x1b, 0xe5, 0xca, 0x68, 0xc5, 0xa6, 0x49, 0x08, 0x8f, 0xd4, 0x84, 0xb2, 0xc8, 0xe8, 0xca, + 0x6b, 0x8f, 0x21, 0x9e, 0xc6, 0x5e, 0xac, 0xa3, 0x43, 0x8d, 0xe3, 0x64, 0xb2, 0x3b, 0xda, 0x39, + 0x1d, 0x82, 0xda, 0x9a, 0x6a, 0x96, 0x30, 0xbf, 0xab, 0x66, 0x97, 0x9c, 0xef, 0x61, 0x6c, 0x36, + 0x20, 0x3f, 0xbc, 0xc6, 0x0e, 0xbc, 0xb5, 0xa9, 0xdf, 0x44, 0x5b, 0xe9, 0x10, 0xf7, 0x29, 0xe6, + 0x59, 0xff, 0x35, 0x46, 0x2c, 0x6d, 0xc6, 0x8a, 0xdb, 0x21, 0x79, 0x5a, 0x18, 0xf8, 0xb1, 0x13, + 0x48, 0x0b, 0xfb, 0x89, 0x69, 0x61, 0x69, 0xb0, 0x76, 0x12, 0xa4, 0xfd, 0x3e, 0xe4, 0x6b, 0xe4, + 0x8f, 0x03, 0xef, 0x55, 0x5e, 0x28, 0x7e, 0xce, 0x2e, 0x9f, 0x3e, 0xd4, 0x28, 0xeb, 0xa0, 0xbf, + 0x4c, 0xc4, 0x1e, 0xa1, 0xd2, 0x04, 0x3a, 0x30, 0x6f, 0x53, 0x6f, 0x6e, 0xcd, 0xc9, 0xc5, 0x72, + 0xfa, 0xb6, 0x25, 0x04, 0xfa, 0xe9, 0x5f, 0xd2, 0x61, 0x5e, 0x7a, 0xfb, 0x3e, 0xdf, 0x28, 0xef, + 0x5f, 0x4b, 0x01, 0xf0, 0xef, 0x0b, 0x50, 0x3c, 0xce, 0xe4, 0xa4, 0x90, 0x31, 0x93, 0x5e, 0x24, + 0xdf, 0xf5, 0xd7, 0xa5, 0x5e, 0x83, 0x58, 0xc4, 0x4b, 0x60, 0x5b, 0xfb, 0x5b, 0xf1, 0x8c, 0xc1, + 0x3b, 0xfd, 0x6e, 0xa7, 0xb1, 0x2a, 0x8b, 0x66, 0x6a, 0xfc, 0x18, 0x2d, 0xcd, 0x5a, 0x46, 0x69, + 0x73, 0xaf, 0x54, 0x52, 0x1e, 0xae, 0xae, 0x7e, 0x78, 0x6b, 0x29, 0x6e, 0xdd, 0xe7, 0x91, 0x28, + 0xa0, 0xf5, 0x67, 0xd9, 0xa7, 0x67, 0x11, 0x0e, 0xfe, 0xb8, 0x16, 0xaa, 0x47, 0xf5, 0xba, 0xff, + 0x8c, 0xde, 0xd7, 0x62, 0xf5, 0x29, 0xee, 0x5f, 0xb7, 0x0f, 0xa3, 0x25, 0xe7, 0x13, 0x1e, 0x29, + 0x1f, 0xb5, 0xe6, 0x25, 0x0a, 0xa3, 0xdb, 0x8b, 0xd9, 0x0c, 0x68, 0xb5, 0xc6, 0xf6, 0xdd, 0x8e, + 0x42, 0x8a, 0x7d, 0x42, 0x37, 0xae, 0x7a, 0x6c, 0x2f, 0xd6, 0xc6, 0xbe, 0x56, 0x05, 0x25, 0xc4, + 0x54, 0xab, 0x06, 0x48, 0x12, 0xe5, 0x46, 0x22, 0x93, 0xfe, 0x6f, 0x4a, 0x7e, 0x25, 0xce, 0x10, + 0x8e, 0xfd, 0x9e, 0x8a, 0x25, 0xbb, 0xd2, 0x39, 0x78, 0x16, 0xc4, 0x73, 0xf1, 0x31, 0x85, 0xc1, + 0x91, 0x75, 0xa1, 0xf2, 0xf5, 0x3d, 0x3b, 0xb6, 0x27, 0xca, 0x57, 0x98, 0x50, 0xe3, 0x19, 0x3a, + 0x1c, 0x2e, 0x46, 0x96, 0x14, 0x37, 0x91, 0xb9, 0x14, 0x70, 0x5c, 0xc2, 0xd3, 0xd1, 0x80, 0x14, + 0x27, 0x65, 0xba, 0x8f, 0x74, 0x2c, 0x02, 0xad, 0x70, 0x79, 0x11, 0x27, 0xc1, 0x4a, 0x92, 0xeb, + 0x54, 0x1b, 0x96, 0xdb, 0xa7, 0xbe, 0x5a, 0xd6, 0x6d, 0x11, 0x6d, 0x79, 0xe8, 0x22, 0xed, 0x5f, + 0x45, 0xcc, 0x8f, 0x4f, 0x73, 0x46, 0xe4, 0x4f, 0x4c, 0x73, 0xe6, 0x4c, 0x37, 0xfe, 0x69, 0xc5, + 0x73, 0xc2, 0x23, 0xcb, 0x09, 0x83, 0x21, 0xc5, 0x6e, 0x34, 0xf1, 0x6d, 0x5e, 0xd6, 0x54, 0x45, + 0xd4, 0x95, 0xf0, 0x77, 0x7a, 0x2c, 0x97, 0x1d, 0xfc, 0x32, 0x51, 0xc3, 0x2a, 0x64, 0x3d, 0x22, + 0xc0, 0x51, 0x16, 0xb7, 0xf8, 0xce, 0xde, 0xc4, 0x85, 0xa6, 0x1b, 0x32, 0xeb, 0x6b, 0x2d, 0xc8, + 0x0b, 0x05, 0x79, 0x59, 0x51, 0xc1, 0x11, 0xd6, 0x85, 0x1c, 0x41, 0x1a, 0x49, 0xae, 0x3c, 0xd5, + 0x6e, 0x29, 0x64, 0x6b, 0x17, 0x32, 0x66, 0x6d, 0x78, 0x5b, 0x2f, 0x52, 0x88, 0x6b, 0x24, 0x97, + 0x45, 0xa9, 0xcb, 0xf0, 0xf8, 0xd4, 0x95, 0xea, 0xeb, 0x46, 0x2c, 0x76, 0xe6, 0x52, 0x94, 0xb4, + 0x08, 0x9a, 0x1b, 0xe5, 0x0b, 0xb6, 0x6d, 0xbd, 0x3c, 0xab, 0x59, 0x0b, 0xfa, 0x2d, 0xbc, 0x89, + 0x02, 0x5a, 0x5f, 0xad, 0x22, 0x8b, 0x6f, 0xc2, 0xf4, 0x29, 0xb2, 0x52, 0x90, 0x29, 0x0e, 0xe7, + 0x2a, 0xa0, 0xfb, 0x1c, 0x5b, 0x8c, 0x9e, 0xfd, 0x6f, 0xe1, 0x37, 0x8b, 0xdf, 0x3f, 0xbc, 0xf6, + 0xba, 0x4f, 0x43, 0x02, 0x59, 0xe2, 0xb8, 0x77, 0x9d, 0x01, 0xfb, 0x2c, 0xb9, 0xf7, 0xb8, 0xc5, + 0x91, 0x99, 0x54, 0xbb, 0xd2, 0xea, 0x13, 0x82, 0x6e, 0x02, 0xb5, 0x8f, 0x44, 0x5b, 0x6d, 0x81, + 0x5c, 0x41, 0x85, 0xf3, 0xe4, 0x82, 0xb5, 0xf8, 0xd7, 0xfb, 0xec, 0xa2, 0xfc, 0x3c, 0x48, 0x9a, + 0x5f, 0x53, 0x6d, 0xdf, 0x6c, 0xf8, 0xf8, 0x40, 0xcc, 0x5c, 0x2b, 0xa1, 0xfa, 0x98, 0x7c, 0xba, + 0x7b, 0x9b, 0xfd, 0xfa, 0x10, 0x2d, 0xbd, 0xc0, 0xfc, 0x51, 0xad, 0x01, 0x5f, 0x68, 0x23, 0x5f, + 0xaf, 0x45, 0xc7, 0xdf, 0x93, 0xfc, 0x0b, 0x6d, 0x80, 0x9b, 0x8a, 0x9a, 0x8e, 0xf3, 0xd7, 0xf6, + 0xa3, 0xa6, 0x2e, 0x55, 0x3e, 0xeb, 0x2f, 0x9b, 0x05, 0x45, 0x64, 0x3d, 0x2c, 0x78, 0x6e, 0xd9, + 0xc3, 0x8a, 0x28, 0x3a, 0x15, 0xb6, 0x31, 0x62, 0x5a, 0x06, 0xef, 0x20, 0x58, 0x14, 0x64, 0x50, + 0x8e, 0x56, 0x16, 0xed, 0x6c, 0x52, 0xc2, 0x2d, 0xf3, 0x8f, 0x7d, 0x84, 0xb2, 0x3f, 0x31, 0xfd, + 0x75, 0xc4, 0xeb, 0xdd, 0x65, 0x28, 0xdb, 0x76, 0x28, 0x19, 0xb3, 0x40, 0xbf, 0x0c, 0x34, 0x7b, + 0xb5, 0x5f, 0x48, 0x20, 0x25, 0xa6, 0xe6, 0x62, 0xd0, 0xe7, 0xfe, 0xe0, 0x4f, 0x3e, 0xf9, 0xe4, + 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, + 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0xff, + 0x3b, 0xf9, 0xe7, 0x79, 0xb0, 0x79, 0x41, 0xd9, 0x8b, 0x4e, 0x72, 0x23, 0xa0, 0x14, 0x9a, 0x05, + 0x81, 0x46, 0x68, 0x36, 0x07, 0xb8, 0x3c, 0xb3, 0x32, 0xfb, 0x4d, 0x79, 0x96, 0xe7, 0x45, 0xda, + 0x98, 0x69, 0xdd, 0x3f, 0xa5, 0x10, 0xca, 0xe1, 0xc4, 0xac, 0x19, 0xb8, 0xa1, 0xbf, 0x8a, 0x8c, + 0x05, 0x32, 0x05, 0x8b, 0x5c, 0xcf, 0xd5, 0xa1, 0xcc, 0xc9, 0xb0, 0xe6, 0xa8, 0x01, 0xba, 0x48, + 0x81, 0x61, 0x74, 0x29, 0x77, 0xe6, 0x69, 0xa5, 0x80, 0x27, 0xf9, 0x5e, 0xa4, 0x6a, 0x0d, 0xc6, + 0x73, 0x00, 0x29, 0x4e, 0xe3, 0x80, 0x9c, 0x3a, 0x9c, 0x06, 0x0c, 0x86, 0x93, 0x7e, 0xae, 0xb4, + 0x86, 0x97, 0x00, 0xa7, 0xcb, 0x75, 0x09, 0x30, 0xd5, 0x16, 0x7b, 0x6c, 0x3c, 0x46, 0x52, 0x94, + 0xf7, 0x04, 0x0d, 0x82, 0x7b, 0x67, 0x68, 0xf2, 0xda, 0x7f, 0xee, 0xc2, 0x2e, 0x85, 0x32, 0x44, + 0x9a, 0x75, 0x7a, 0xcc, 0x3f, 0xd6, 0x8e, 0xea, 0x24, 0xff, 0x5e, 0xd1, 0x98, 0xd7, 0x90, 0x16, + 0x64, 0x51, 0xaf, 0x40, 0xa4, 0xe5, 0x1c, 0x64, 0x95, 0x24, 0xb8, 0x07, 0xaf, 0xe7, 0xb8, 0x39, + 0x75, 0x8e, 0x85, 0x47, 0xb4, 0x6f, 0x69, 0x4a, 0x13, 0x45, 0x38, 0xd8, 0x6a, 0x2e, 0xec, 0x65, + 0xf6, 0x47, 0xc6, 0x70, 0x27, 0x51, 0x33, 0x5b, 0xef, 0x1d, 0xe9, 0x98, 0x9c, 0x6b, 0xb6, 0x68, + 0x92, 0xc2, 0x5c, 0x40, 0xb5, 0xdf, 0x31, 0x8a, 0x7a, 0x8a, 0x99, 0x4a, 0x20, 0xb0, 0x18, 0x9a, + 0x75, 0xfb, 0xf6, 0x69, 0xde, 0x76, 0x4f, 0xca, 0xfc, 0xa6, 0x07, 0x7d, 0x0c, 0x2f, 0xd7, 0x78, + 0x63, 0xcf, 0x90, 0x86, 0xb3, 0x70, 0x2c, 0x53, 0x5c, 0x0c, 0x27, 0xf9, 0x45, 0x59, 0x6b, 0x41, + 0xd7, 0x3d, 0x2f, 0x17, 0xe3, 0xce, 0xe0, 0x15, 0xa1, 0x90, 0x5d, 0xcc, 0x99, 0x1f, 0x0b, 0x99, + 0xe4, 0x6f, 0xb4, 0xe6, 0x24, 0x0b, 0x03, 0x88, 0x7d, 0x82, 0x13, 0x7a, 0xb4, 0x63, 0x95, 0xdd, + 0x04, 0xa9, 0x69, 0x91, 0x55, 0x31, 0xad, 0xe9, 0xeb, 0xdd, 0x0c, 0x5f, 0xc7, 0x6c, 0x61, 0x4b, + 0x47, 0xce, 0x54, 0x07, 0xe8, 0x6b, 0x6e, 0xc3, 0x34, 0x18, 0x9b, 0xc6, 0x07, 0x7f, 0x3a, 0xab, + 0xaf, 0x54, 0xbe, 0xe4, 0x2d, 0xd1, 0x10, 0x7a, 0xd2, 0xe8, 0xf5, 0x9b, 0xd4, 0xcc, 0x92, 0xb6, + 0xb8, 0x17, 0xa6, 0xba, 0x2d, 0xce, 0x3c, 0x65, 0xf5, 0xa3, 0x72, 0x6d, 0xe6, 0x96, 0xa8, 0x48, + 0xba, 0x22, 0x66, 0x7d, 0x0e, 0xa6, 0xe6, 0x37, 0x29, 0xe0, 0x8d, 0xfd, 0x02, 0x3f, 0x27, 0x90, + 0x5c, 0x18, 0x6a, 0xf9, 0x96, 0xf3, 0x1a, 0xed, 0x9f, 0x40, 0x5f, 0xb7, 0xdd, 0x46, 0xa9, 0x7c, + 0xf5, 0xbe, 0xbc, 0xaf, 0x7d, 0x97, 0x95, 0xcb, 0xa6, 0x9b, 0x54, 0x93, 0x22, 0xb5, 0xbf, 0xe3, + 0x49, 0x99, 0x69, 0xad, 0xb3, 0x5a, 0x37, 0xd5, 0x96, 0x33, 0x17, 0x09, 0x65, 0x47, 0x5d, 0xd7, + 0xf4, 0xe7, 0x23, 0xa5, 0x56, 0x3c, 0x32, 0xcd, 0x87, 0x7d, 0x4c, 0xc6, 0xfe, 0xe8, 0x2b, 0xf5, + 0xfd, 0x92, 0x14, 0xa5, 0x39, 0xf2, 0x2c, 0xfc, 0x58, 0x67, 0xb7, 0xf0, 0x13, 0xd3, 0x49, 0xa5, + 0x69, 0xbb, 0x95, 0xce, 0xac, 0x05, 0x51, 0xfe, 0xaa, 0xed, 0xb6, 0xdc, 0x31, 0x35, 0xb7, 0x38, + 0xac, 0xf9, 0xf0, 0xa4, 0x2e, 0xd5, 0x13, 0xa2, 0xf2, 0x3c, 0x17, 0x34, 0x53, 0x97, 0xda, 0x70, + 0x09, 0x85, 0x64, 0xd7, 0x12, 0x28, 0x98, 0x41, 0xbc, 0xdd, 0x37, 0xd8, 0xb8, 0xc5, 0x52, 0xcf, + 0x17, 0xac, 0x3e, 0xd4, 0x66, 0x4e, 0x1c, 0x8d, 0x6c, 0x6e, 0x54, 0x47, 0xc5, 0x8d, 0xbe, 0xda, + 0x6e, 0x84, 0x70, 0xa7, 0x70, 0xa9, 0xde, 0xd0, 0xc5, 0x6c, 0xd7, 0x1b, 0xa3, 0x90, 0xa3, 0xf7, + 0x48, 0x71, 0xdf, 0x9c, 0xb1, 0xca, 0x14, 0xd0, 0x55, 0x52, 0x3a, 0xa1, 0x4f, 0x45, 0xa1, 0xf9, + 0xfd, 0x52, 0xea, 0xcd, 0xf1, 0xd7, 0xab, 0xb7, 0xcc, 0xf5, 0x04, 0x7c, 0xd9, 0xf9, 0xaa, 0x95, + 0xe9, 0x68, 0xf4, 0xda, 0x2e, 0x36, 0x01, 0xb5, 0xed, 0xa4, 0xe1, 0xf8, 0xd4, 0xaf, 0x78, 0xd4, + 0x1b, 0x94, 0xb8, 0xd9, 0x35, 0xfa, 0x12, 0x5a, 0x7d, 0x0a, 0x2c, 0x04, 0x2b, 0xe0, 0xd3, 0xcd, + 0x1b, 0x10, 0x17, 0xb9, 0x5f, 0x49, 0xe3, 0x99, 0xb7, 0x8c, 0x8b, 0xac, 0xf5, 0xdc, 0x95, 0xc0, + 0xda, 0xcf, 0x75, 0x8b, 0xe7, 0x77, 0x35, 0x5c, 0xe2, 0xbe, 0xbd, 0x6a, 0x18, 0x2d, 0x75, 0xda, + 0x7a, 0x25, 0x1e, 0xa4, 0x1e, 0x01, 0x6b, 0x7d, 0xc4, 0x76, 0x1d, 0x24, 0x3a, 0x4a, 0xd3, 0xa4, + 0xd4, 0xd2, 0xaf, 0xb9, 0x0f, 0x17, 0x76, 0xed, 0x62, 0xa6, 0xc7, 0x11, 0xbd, 0x3e, 0x8c, 0xf5, + 0x32, 0x33, 0x63, 0x36, 0xc2, 0x90, 0x2a, 0x6c, 0x05, 0xf4, 0xe4, 0x82, 0xc5, 0x0c, 0x7b, 0xb1, + 0xd5, 0x92, 0x82, 0xad, 0xcb, 0x0e, 0xca, 0xd6, 0x05, 0xa1, 0x7c, 0xd4, 0x67, 0x65, 0xdd, 0x7b, + 0xc1, 0xd6, 0x74, 0xd7, 0xb3, 0xf2, 0x05, 0x90, 0x45, 0x13, 0xaa, 0x70, 0x54, 0x85, 0x48, 0xb8, + 0x5a, 0xc9, 0xce, 0x18, 0x2e, 0xb5, 0x92, 0xbb, 0x5a, 0xfd, 0x3f, 0x05, 0xd5, 0x51, 0x08, 0x55, + 0xeb, 0x5d, 0x6e, 0x4f, 0x32, 0x6d, 0x53, 0xfc, 0x4b, 0xed, 0xa8, 0xf9, 0x27, 0xa6, 0xd9, 0x03, + 0xd7, 0xcd, 0x49, 0x28, 0x8a, 0x80, 0x2f, 0xf7, 0x02, 0x63, 0x9b, 0xea, 0x88, 0xb6, 0x4f, 0xb0, + 0xae, 0xce, 0xbc, 0xd7, 0xa1, 0x13, 0x96, 0x8d, 0x24, 0x57, 0xc8, 0x3f, 0x58, 0xd8, 0x35, 0xea, + 0x98, 0xa1, 0x7d, 0xd9, 0x7b, 0x90, 0xc4, 0xa2, 0x40, 0xb9, 0x81, 0xf3, 0xf8, 0x8f, 0x0f, 0x9d, + 0x9c, 0x6c, 0x23, 0x39, 0xad, 0x11, 0x99, 0x15, 0x53, 0xb3, 0x88, 0xbf, 0xb9, 0xca, 0xb7, 0x4d, + 0x16, 0xb3, 0x31, 0x5d, 0x21, 0x09, 0x8d, 0xcf, 0x3c, 0x3b, 0xa4, 0x24, 0xb6, 0xf9, 0x4c, 0x2b, + 0x14, 0xd6, 0xc3, 0x71, 0x51, 0x00, 0x86, 0xa6, 0x71, 0xbe, 0xef, 0x77, 0x4c, 0x0a, 0xc7, 0xc2, + 0x98, 0xa5, 0xe0, 0xd1, 0xaa, 0x49, 0xd7, 0x19, 0xaa, 0x9e, 0x11, 0x99, 0x87, 0x2b, 0x71, 0x09, + 0x72, 0xb8, 0x5c, 0x92, 0x80, 0xef, 0xa8, 0x30, 0xba, 0x83, 0xf4, 0x04, 0x81, 0xa3, 0xd1, 0x57, + 0xc0, 0xac, 0x20, 0xd7, 0x01, 0xab, 0x32, 0x01, 0x0d, 0xec, 0x47, 0x9e, 0x29, 0xd8, 0x18, 0xac, + 0x50, 0xfd, 0xf1, 0xe6, 0x0b, 0x2d, 0x74, 0x6f, 0x1c, 0x6e, 0x4a, 0x11, 0x71, 0x64, 0x46, 0x78, + 0x1d, 0x62, 0x0f, 0xec, 0x3b, 0x75, 0x0e, 0xfd, 0xeb, 0xa5, 0x3f, 0x94, 0x7f, 0xda, 0x73, 0x12, + 0xe8, 0x00, 0x38, 0xc2, 0xee, 0xd5, 0x4e, 0x15, 0xc3, 0x9b, 0xa7, 0xcd, 0xd6, 0x1a, 0xfb, 0x2a, + 0xa6, 0x0b, 0x57, 0x98, 0xf6, 0x1e, 0xbe, 0x0b, 0xa0, 0x9c, 0xb4, 0xa1, 0xbb, 0xc5, 0xe8, 0x0d, + 0xb9, 0xc0, 0xe1, 0xba, 0xbe, 0xee, 0x3e, 0x1c, 0x5f, 0xfa, 0xa2, 0x18, 0x3d, 0xed, 0x8b, 0x84, + 0x06, 0xfc, 0x75, 0x8a, 0x7d, 0x39, 0xed, 0xf3, 0xfd, 0x17, 0x8b, 0x8a, 0x0b, 0xf4, 0x5b, 0x56, + 0xd7, 0x65, 0x34, 0xbb, 0x07, 0xe4, 0xdc, 0xb8, 0x57, 0xea, 0x57, 0x58, 0x04, 0x30, 0xbc, 0x23, + 0xc2, 0x56, 0x09, 0x52, 0x03, 0x15, 0x1e, 0x64, 0x22, 0x5a, 0x0f, 0x22, 0x21, 0xcd, 0x04, 0x3e, + 0x26, 0x23, 0x8a, 0xe2, 0xee, 0x17, 0x38, 0x17, 0xfa, 0xb1, 0x8f, 0x3f, 0xb5, 0xfb, 0x13, 0xd3, + 0x73, 0x36, 0xa7, 0x05, 0xbd, 0x57, 0xf7, 0xce, 0x27, 0xbb, 0x73, 0x32, 0xa8, 0x6c, 0xd7, 0x32, + 0xc6, 0x9e, 0x5a, 0x1d, 0x2b, 0xcf, 0x4e, 0x81, 0x85, 0xa0, 0x67, 0x71, 0x10, 0x3e, 0x1b, 0xb5, + 0xaa, 0xca, 0x8f, 0x2f, 0xa2, 0x76, 0x46, 0x58, 0x8c, 0x4c, 0x10, 0xf4, 0x4d, 0xbf, 0x5d, 0x18, + 0x5f, 0x34, 0xe6, 0x2e, 0x32, 0xbb, 0x9a, 0xcb, 0xd5, 0x31, 0x36, 0xae, 0xdc, 0x26, 0xd0, 0x0f, + 0x3d, 0x2a, 0xb6, 0x5c, 0xf6, 0xd6, 0x9a, 0x2e, 0x99, 0xc8, 0xe4, 0x1b, 0x98, 0x36, 0xdd, 0x64, + 0xab, 0xa6, 0xdb, 0x84, 0x81, 0x0b, 0xdc, 0x56, 0xd8, 0xf9, 0x9c, 0xbf, 0xcc, 0x6a, 0x1c, 0xf8, + 0x5b, 0x59, 0xa9, 0x59, 0xdc, 0xc6, 0x7e, 0xb5, 0x1d, 0x87, 0x3e, 0xe2, 0x67, 0x51, 0x8d, 0x49, + 0x1e, 0x43, 0x0d, 0x22, 0xbe, 0x96, 0x5e, 0xec, 0x4d, 0xaf, 0xf5, 0xfe, 0x9b, 0x95, 0x42, 0xf4, + 0x2f, 0x2d, 0x89, 0x6c, 0x0f, 0x59, 0xe1, 0x36, 0x3d, 0x7e, 0xae, 0xf0, 0xda, 0x40, 0x2f, 0x01, + 0x90, 0x15, 0x69, 0x90, 0x7f, 0xf4, 0xd7, 0x2a, 0x1d, 0x7c, 0x67, 0x24, 0x07, 0xc0, 0x3a, 0xba, + 0x02, 0x40, 0x81, 0x59, 0xae, 0xa4, 0x80, 0xb0, 0xd4, 0x1f, 0x71, 0x91, 0xd2, 0x2d, 0xbb, 0x21, + 0xc7, 0xd4, 0xee, 0x9f, 0x9a, 0x3a, 0x5b, 0x20, 0x82, 0x5d, 0xc1, 0x8a, 0x2c, 0xec, 0x9f, 0x5a, + 0xf6, 0xdd, 0x5d, 0x7c, 0x19, 0x77, 0x11, 0x2a, 0xa8, 0xb9, 0x21, 0xdd, 0x18, 0x6f, 0x3b, 0xd8, + 0xb9, 0xd4, 0x47, 0xa3, 0xa4, 0x55, 0xaa, 0x21, 0xff, 0x43, 0xef, 0xe6, 0x2c, 0x87, 0xec, 0x8f, + 0xa0, 0x88, 0xa8, 0x7e, 0x15, 0x31, 0xd4, 0xdc, 0x70, 0xe0, 0xa9, 0x6f, 0xb1, 0x95, 0xb4, 0x6a, + 0x05, 0x47, 0xde, 0x76, 0x2e, 0x85, 0x30, 0xa5, 0x32, 0xd0, 0x1e, 0xcd, 0x2d, 0xbe, 0x3b, 0xdc, + 0xf2, 0x63, 0xb2, 0xe1, 0xda, 0x84, 0x4e, 0x21, 0xf6, 0x72, 0x98, 0xac, 0xa2, 0x24, 0x5b, 0xd8, + 0x50, 0x59, 0xde, 0xf6, 0xcf, 0x1f, 0x83, 0xc1, 0x55, 0xd0, 0xf6, 0x63, 0xe5, 0x39, 0x0a, 0xfd, + 0xc4, 0x34, 0xc0, 0x13, 0x99, 0x76, 0xda, 0x0a, 0xf9, 0x43, 0xb7, 0x3b, 0xf6, 0x06, 0x43, 0xc4, + 0xbc, 0x35, 0xda, 0xe9, 0x6b, 0x9e, 0x18, 0x24, 0xdb, 0xdb, 0xa9, 0x53, 0x6a, 0x12, 0x42, 0x48, + 0x36, 0xcf, 0x64, 0x32, 0xd3, 0xea, 0x0b, 0x3b, 0xba, 0x2a, 0xeb, 0xc7, 0x2a, 0xfd, 0x59, 0x9e, + 0x76, 0xfb, 0x72, 0xfa, 0xd9, 0xa3, 0xb5, 0xfe, 0xd6, 0x73, 0x4f, 0xb6, 0x56, 0x9f, 0xcb, 0xba, + 0x4d, 0x2d, 0x5f, 0x94, 0x7a, 0xa9, 0x39, 0xed, 0xac, 0x66, 0x06, 0x3e, 0x9d, 0xf0, 0xa5, 0x4d, + 0xcd, 0xf7, 0x34, 0x56, 0x9d, 0x70, 0xd1, 0x18, 0x55, 0xe7, 0x60, 0x95, 0xa6, 0x64, 0xcb, 0x9e, + 0x57, 0xb6, 0x15, 0x32, 0xbb, 0x90, 0x64, 0xbe, 0xcd, 0x80, 0xa5, 0x0a, 0xc7, 0x54, 0x1f, 0x74, + 0x12, 0xd3, 0x64, 0xe9, 0x3d, 0xd7, 0xf1, 0x6a, 0xeb, 0x61, 0x5a, 0xd0, 0x57, 0x03, 0x89, 0xa7, + 0x37, 0x49, 0xeb, 0x72, 0xef, 0xec, 0xa6, 0x5f, 0xf0, 0xc7, 0x24, 0x78, 0x21, 0x6a, 0x60, 0xa8, + 0x27, 0x1a, 0x1f, 0xb2, 0xf2, 0x83, 0xf1, 0xf7, 0x88, 0x43, 0xe3, 0xa2, 0x73, 0xb1, 0x61, 0xba, + 0xd3, 0x2f, 0x4b, 0x12, 0x95, 0x29, 0x91, 0x45, 0x7c, 0x7e, 0xc1, 0x5f, 0x9b, 0xf8, 0x06, 0x5a, + 0x79, 0x35, 0x83, 0xc6, 0x1b, 0x22, 0xed, 0x17, 0xf8, 0x09, 0x5d, 0x08, 0x27, 0x7c, 0x27, 0x6f, + 0x93, 0xb2, 0xb7, 0xdc, 0x21, 0xdf, 0xe3, 0x1e, 0x4d, 0x48, 0x1b, 0x51, 0xcc, 0x75, 0x35, 0x31, + 0x04, 0x0a, 0x1a, 0xa1, 0x18, 0x5b, 0xaf, 0x05, 0xaa, 0xe5, 0x89, 0x69, 0x3d, 0x55, 0x27, 0x2d, + 0xc7, 0xeb, 0xfe, 0xca, 0xac, 0x38, 0xd5, 0xdb, 0x5d, 0x34, 0x23, 0x5f, 0x93, 0xe6, 0x3e, 0x33, + 0xc5, 0xb1, 0xf4, 0x62, 0x3d, 0xb9, 0x01, 0x91, 0x2f, 0xcc, 0xf2, 0xca, 0x10, 0x99, 0x2c, 0x28, + 0x7d, 0x6b, 0x03, 0xf3, 0xe3, 0xe8, 0x34, 0xe5, 0xa0, 0xb4, 0x5b, 0x7d, 0x50, 0x4f, 0xaa, 0xd3, + 0xb9, 0x1e, 0x1c, 0xd9, 0xbd, 0x92, 0x99, 0x3b, 0xf4, 0xf5, 0xe3, 0x51, 0xeb, 0xc7, 0x3a, 0x3b, + 0xec, 0x27, 0xa6, 0x85, 0x22, 0x2a, 0xb0, 0x46, 0x94, 0x0f, 0x54, 0x83, 0xb0, 0xf9, 0x4f, 0x94, + 0x4e, 0x2b, 0xb6, 0xcb, 0x6d, 0x55, 0xcd, 0x79, 0x8f, 0x95, 0x88, 0x40, 0xb4, 0xff, 0x4d, 0x13, + 0x36, 0x91, 0x2b, 0x5a, 0xbe, 0x8a, 0x99, 0xc9, 0x29, 0xba, 0x13, 0xd4, 0x4c, 0xca, 0x88, 0x12, + 0x05, 0xf6, 0x64, 0x94, 0x84, 0xd4, 0xa0, 0x17, 0x80, 0x4f, 0xa7, 0x7d, 0x2d, 0x51, 0xce, 0x5e, + 0xbc, 0x04, 0xc4, 0x3b, 0x33, 0x58, 0x94, 0x54, 0x53, 0x73, 0xc2, 0x1d, 0xea, 0x9b, 0xfa, 0xe2, + 0x94, 0x88, 0xe7, 0x2e, 0x4e, 0x08, 0x36, 0x26, 0x3a, 0x25, 0xec, 0x20, 0x48, 0x6e, 0xb6, 0xbe, + 0x7a, 0x9f, 0xba, 0x97, 0x2b, 0x17, 0x3e, 0x8c, 0xe5, 0xe0, 0x6d, 0x69, 0x6d, 0x9d, 0x44, 0x10, + 0x9d, 0xcb, 0x75, 0xef, 0x93, 0x86, 0x02, 0x53, 0xe8, 0xcc, 0x8d, 0x2f, 0xd0, 0xdf, 0x93, 0xda, + 0x61, 0x10, 0x0b, 0x5f, 0x16, 0x18, 0x57, 0x70, 0xbf, 0xca, 0x30, 0xa4, 0xdc, 0xd6, 0xee, 0x4d, + 0xeb, 0xa0, 0x70, 0x8d, 0x9c, 0xce, 0x6c, 0x5e, 0xac, 0x16, 0xff, 0xf8, 0xee, 0x11, 0xae, 0x1c, + 0xbb, 0x8e, 0x7a, 0x3a, 0xd9, 0x5d, 0x2d, 0x7b, 0x69, 0x12, 0x33, 0x41, 0xcd, 0xc5, 0x59, 0xe8, + 0x2a, 0x7f, 0x71, 0x5a, 0xb3, 0x29, 0xe5, 0x64, 0xef, 0x75, 0xec, 0x33, 0x41, 0x99, 0x8a, 0x2c, + 0x82, 0xad, 0x18, 0x70, 0x0d, 0x82, 0x02, 0xc5, 0x32, 0x54, 0xce, 0xd6, 0x4d, 0x4d, 0xa0, 0x74, + 0x35, 0xf6, 0xaf, 0x13, 0xb0, 0x9c, 0x02, 0x28, 0xb1, 0xf7, 0x3e, 0xac, 0x5b, 0xff, 0x88, 0x00, + 0x57, 0x67, 0xa4, 0x8a, 0x58, 0x39, 0xea, 0x7f, 0x5b, 0x92, 0x6e, 0xd7, 0xd7, 0xde, 0x56, 0xf7, + 0x99, 0x95, 0x64, 0x17, 0x74, 0xdd, 0x76, 0xe0, 0x03, 0x17, 0x86, 0xbf, 0xca, 0x51, 0x36, 0x47, + 0x7d, 0x76, 0x82, 0x71, 0x66, 0x85, 0xb6, 0x2a, 0x41, 0x9a, 0xc9, 0xaf, 0xc3, 0x82, 0x72, 0x8f, + 0x61, 0xc1, 0x00, 0xaa, 0x92, 0x88, 0xcc, 0xa5, 0x17, 0x40, 0x6d, 0x19, 0xb1, 0x7e, 0xac, 0x1d, + 0x25, 0x7f, 0x62, 0x9a, 0xc3, 0xfb, 0x08, 0x2d, 0x2c, 0x00, 0x8c, 0x75, 0x72, 0x1a, 0x7f, 0xf0, + 0xe3, 0xc7, 0x00, 0x86, 0xfd, 0x9b, 0x7a, 0xde, 0x0d, 0x0d, 0xd8, 0x9b, 0x12, 0x68, 0x6a, 0x1e, + 0xf2, 0xa1, 0x38, 0x66, 0x12, 0x23, 0x33, 0xb4, 0xee, 0x19, 0x2f, 0xef, 0x06, 0x8e, 0x4e, 0x5b, + 0x00, 0x09, 0x1e, 0xe3, 0x89, 0x2a, 0x73, 0x4e, 0x2a, 0x75, 0x08, 0x5c, 0xe1, 0x17, 0x6f, 0x4a, + 0xad, 0xd5, 0x2a, 0xed, 0x68, 0xbd, 0x81, 0xa6, 0xc3, 0xa4, 0x48, 0x63, 0xc3, 0x9b, 0x80, 0x38, + 0x4e, 0xc9, 0x39, 0xe2, 0x9b, 0x13, 0x54, 0x83, 0xc3, 0x7e, 0x95, 0x28, 0xc6, 0x6c, 0xd0, 0x70, + 0x0e, 0x99, 0x97, 0x4a, 0x4c, 0x9b, 0x2d, 0x01, 0x50, 0x85, 0x16, 0xa6, 0xa4, 0xe0, 0x1d, 0x89, + 0x8a, 0x72, 0x88, 0x7a, 0x46, 0x2d, 0x6e, 0xa1, 0x78, 0xe4, 0x23, 0x88, 0xa1, 0xf3, 0xe2, 0x33, + 0x74, 0x46, 0x0b, 0x45, 0x29, 0x0e, 0xa6, 0x45, 0xe6, 0xf0, 0xc4, 0x0d, 0xc2, 0x9e, 0xa1, 0xc5, + 0x55, 0x2f, 0x91, 0xf0, 0x5a, 0xc2, 0x8d, 0x0a, 0x88, 0x87, 0x16, 0xe6, 0xc5, 0x3e, 0x44, 0x28, + 0x05, 0x9d, 0x23, 0xd6, 0x3c, 0xac, 0xc2, 0xfe, 0x79, 0xef, 0xff, 0xfb, 0x42, 0x6a, 0x75, 0x4f, + 0x10, 0xe7, 0x9f, 0xbf, 0x54, 0x5f, 0x60, 0xf8, 0xe3, 0xfb, 0xc5, 0x05, 0x3e, 0x4c, 0x25, 0xc2, + 0x5d, 0x01, 0xe9, 0x6a, 0x97, 0x0e, 0x48, 0xa5, 0xdd, 0xf3, 0x97, 0x90, 0x50, 0x74, 0xfe, 0xf1, + 0x36, 0x70, 0x67, 0xf4, 0xed, 0x1a, 0x06, 0x47, 0x5b, 0x5a, 0xd0, 0xf8, 0xff, 0x7d, 0x90, 0x0b, + 0xfb, 0xf8, 0xa0, 0xfb, 0x93, 0xb4, 0xd4, 0x5f, 0x18, 0xcd, 0x76, 0x4c, 0x62, 0x2c, 0x0b, 0x8b, + 0x5f, 0x31, 0xf6, 0x3f, 0x1d, 0x63, 0xd8, 0x40, 0x95, 0x31, 0x48, 0xe1, 0xee, 0x3f, 0xdf, 0xde, + 0xab, 0x3a, 0xa1, 0x45, 0x25, 0xf1, 0xff, 0xa4, 0x3c, 0xe1, 0x46, 0x18, 0x9b, 0x75, 0x06, 0x5a, + 0x3f, 0xf6, 0x5c, 0xc9, 0xfe, 0xc4, 0x34, 0x57, 0x63, 0x54, 0xa6, 0xa7, 0x07, 0x82, 0xb4, 0x3b, + 0x67, 0x84, 0x6e, 0xcb, 0xb3, 0x32, 0xdb, 0x51, 0x2f, 0xc9, 0x35, 0x42, 0xec, 0x4d, 0xd0, 0xb8, + 0xc1, 0xe0, 0x00, 0x02, 0x13, 0xe1, 0x47, 0x90, 0x9c, 0xa6, 0x0d, 0x9a, 0xa6, 0x27, 0xc4, 0x7e, + 0x2a, 0x10, 0xba, 0xdc, 0xe5, 0x63, 0x8b, 0xbd, 0x0f, 0xa2, 0x9b, 0x55, 0x70, 0xcd, 0x95, 0x66, + 0xcd, 0x29, 0x4f, 0x32, 0x14, 0xf9, 0x58, 0x4c, 0x2b, 0xd4, 0xeb, 0xc8, 0x2f, 0x28, 0x41, 0x25, + 0x4e, 0x83, 0x8c, 0xf3, 0x26, 0xa4, 0x8b, 0x3e, 0x36, 0xa1, 0x37, 0xbc, 0x07, 0x86, 0x48, 0x9d, + 0xec, 0x04, 0x93, 0xa6, 0xe3, 0x91, 0x80, 0x3d, 0xc7, 0x33, 0x1b, 0x76, 0xe9, 0x33, 0x37, 0xb1, + 0x9a, 0xd3, 0x96, 0x82, 0xb4, 0x41, 0xe7, 0x0e, 0x56, 0x0c, 0x67, 0x2e, 0x32, 0x41, 0x2b, 0xcb, + 0x1b, 0x09, 0x2a, 0x1f, 0xdb, 0xc9, 0x49, 0x61, 0x08, 0x81, 0x20, 0x70, 0x74, 0x87, 0xd9, 0x00, + 0xf8, 0x26, 0xaf, 0x13, 0xb8, 0x6f, 0x28, 0x1d, 0xef, 0xee, 0x2c, 0xce, 0x13, 0x9e, 0x9c, 0xe1, + 0x02, 0x12, 0x44, 0x9b, 0xf3, 0xe0, 0xcd, 0xc8, 0x2c, 0x81, 0x6f, 0x98, 0x05, 0xa3, 0xfc, 0x04, + 0x19, 0xed, 0x2b, 0x36, 0x42, 0x7c, 0x9e, 0x4c, 0x45, 0xb0, 0x61, 0x89, 0x0b, 0x51, 0x6b, 0x64, + 0xe5, 0x85, 0x8c, 0xfc, 0xb9, 0xec, 0x42, 0xed, 0x7f, 0x94, 0xcf, 0x3a, 0x76, 0x9e, 0xe4, 0x2c, + 0x03, 0xf2, 0x54, 0xbf, 0xbc, 0x82, 0x00, 0xba, 0xcc, 0x44, 0xb5, 0x6f, 0xd5, 0x10, 0xc1, 0x3f, + 0x88, 0x18, 0xf6, 0xbb, 0xe1, 0x80, 0x39, 0xc7, 0x3b, 0x2f, 0xf3, 0xd8, 0x12, 0xc3, 0x5c, 0x30, + 0x6a, 0x69, 0x8a, 0xdf, 0x3e, 0x32, 0x2e, 0xf5, 0xb7, 0x25, 0x5d, 0x6f, 0x97, 0x35, 0xe6, 0x8f, + 0x03, 0x1c, 0xfe, 0x41, 0x19, 0x55, 0xd9, 0x41, 0x27, 0x4a, 0xf5, 0xd6, 0x25, 0xcc, 0x0a, 0xee, + 0x70, 0x65, 0x06, 0xef, 0xe7, 0x27, 0xd4, 0x9c, 0xc6, 0xe5, 0x51, 0x0b, 0x44, 0x40, 0xe2, 0x47, + 0xd3, 0xaa, 0xfc, 0xbf, 0x9a, 0xbe, 0x41, 0x76, 0x97, 0xfe, 0x2a, 0x64, 0x5a, 0xaf, 0x16, 0x9f, + 0x32, 0xff, 0xe4, 0x83, 0x94, 0xe8, 0xea, 0x45, 0xec, 0xf7, 0xf8, 0x3e, 0xa5, 0x95, 0xc6, 0x21, + 0xb2, 0x10, 0x6c, 0x63, 0xfb, 0xce, 0x6e, 0x5e, 0x5d, 0x7c, 0x5f, 0x2e, 0xa5, 0x75, 0xa5, 0xb7, + 0x4c, 0x65, 0xfc, 0xea, 0xa5, 0x80, 0xaa, 0xac, 0x4a, 0x29, 0x35, 0x68, 0xb9, 0xc9, 0xb7, 0x68, + 0x3b, 0xeb, 0x71, 0x4b, 0x90, 0x59, 0x9f, 0xdf, 0x6e, 0xa0, 0x2f, 0x93, 0xc8, 0x46, 0xef, 0xe2, + 0xd7, 0x14, 0xa9, 0x19, 0x19, 0xed, 0xa8, 0xb4, 0xc2, 0xf7, 0x6f, 0x62, 0x25, 0xdc, 0x23, 0x41, + 0xc2, 0x22, 0xbd, 0x89, 0x95, 0x77, 0xfc, 0x81, 0x6e, 0x87, 0x96, 0x6e, 0x12, 0xd5, 0xa1, 0x0e, + 0x7c, 0xff, 0x93, 0xf3, 0x1b, 0x68, 0x3c, 0x9c, 0x53, 0xfb, 0xc2, 0x87, 0x92, 0x92, 0x9f, 0x40, + 0xbe, 0x92, 0xd0, 0xb8, 0xb3, 0x14, 0xd7, 0xd6, 0xa5, 0x73, 0x92, 0x9c, 0xfc, 0xcf, 0xaf, 0x9d, + 0xc7, 0x88, 0x4a, 0x8f, 0x1f, 0xb7, 0xa7, 0x93, 0xb0, 0xcd, 0x46, 0x24, 0x2a, 0x57, 0xdb, 0xdf, + 0xaf, 0xba, 0x7e, 0xa6, 0xd1, 0xd4, 0x08, 0xf6, 0x3c, 0xac, 0xdc, 0xda, 0xd0, 0x95, 0xcf, 0x14, + 0x82, 0x75, 0x42, 0x6d, 0x79, 0x38, 0x8a, 0xcb, 0x23, 0xd1, 0xf0, 0xcb, 0xee, 0xf5, 0x11, 0x31, + 0x33, 0xeb, 0x4d, 0x31, 0xed, 0xbc, 0xf1, 0xf4, 0x15, 0x9d, 0x19, 0xc7, 0x90, 0xa9, 0x46, 0x24, + 0x1d, 0x6a, 0x68, 0xe2, 0x2a, 0x4d, 0x30, 0x7f, 0x5c, 0x08, 0x0e, 0x73, 0x00, 0xb1, 0xb4, 0x5c, + 0x37, 0x9e, 0x3e, 0x63, 0x33, 0xa3, 0x90, 0x86, 0x11, 0xf5, 0x06, 0x23, 0x45, 0xb2, 0x64, 0x62, + 0xae, 0xa7, 0x65, 0x14, 0x13, 0xc1, 0xbd, 0x44, 0x52, 0x3d, 0x27, 0x23, 0xe8, 0x55, 0x89, 0xfc, + 0xf5, 0x64, 0x0c, 0x74, 0x0f, 0x2a, 0xf3, 0xf8, 0xb5, 0x6a, 0x1f, 0x4b, 0xc9, 0x08, 0x72, 0x53, + 0xf6, 0x4f, 0xef, 0x23, 0xa9, 0xb2, 0x78, 0x1b, 0xca, 0x3a, 0xdd, 0x95, 0x54, 0xa7, 0xf4, 0x91, + 0x5c, 0xf1, 0x4a, 0xeb, 0x3f, 0xd6, 0x43, 0x53, 0xc9, 0x9f, 0x8c, 0x69, 0x85, 0x54, 0x69, 0xaa, + 0x74, 0xd4, 0xda, 0x33, 0x57, 0xca, 0x0c, 0x7b, 0xd0, 0x05, 0xb9, 0xd1, 0xe4, 0xf9, 0x52, 0xbc, + 0x7c, 0xc4, 0xb1, 0xa4, 0x37, 0x8e, 0x0e, 0xa4, 0xce, 0x18, 0x53, 0xc1, 0xe1, 0x41, 0x0b, 0x35, + 0xd9, 0x54, 0x94, 0x55, 0x2f, 0x73, 0x7b, 0x80, 0x61, 0x42, 0xc7, 0xdd, 0x2d, 0x8b, 0x8a, 0x96, + 0x4e, 0x32, 0x9a, 0xc2, 0xb2, 0xc3, 0x5e, 0xf8, 0x0d, 0xb8, 0xd4, 0xde, 0x1d, 0x6e, 0x62, 0xd7, + 0x7b, 0x9d, 0xd9, 0x2c, 0xf4, 0xd4, 0x54, 0x58, 0x99, 0xda, 0x76, 0x8e, 0x37, 0xf4, 0x58, 0xd3, + 0x97, 0x8a, 0x47, 0x32, 0x51, 0xb5, 0x3d, 0x44, 0x2c, 0x5a, 0x1c, 0x49, 0x5a, 0x80, 0x35, 0x9f, + 0x8f, 0xc0, 0x73, 0xa9, 0x4e, 0x4e, 0xdb, 0x3c, 0x47, 0x84, 0xe1, 0xed, 0xb3, 0x9b, 0x2a, 0x6e, + 0xda, 0x68, 0x71, 0xd4, 0xfe, 0xc7, 0xd0, 0x34, 0x5f, 0xab, 0xec, 0xe6, 0xad, 0x48, 0x6b, 0x5e, + 0xad, 0xf6, 0xf7, 0x5d, 0x04, 0x97, 0x84, 0xb6, 0x82, 0xa3, 0x6b, 0xed, 0x66, 0xf6, 0xea, 0x71, + 0xeb, 0x36, 0x52, 0x30, 0xae, 0xb5, 0xb5, 0xdc, 0xb0, 0xe2, 0x4b, 0x8e, 0x14, 0x24, 0xb6, 0x09, + 0x1c, 0x16, 0x21, 0x9a, 0xde, 0x13, 0x5d, 0x16, 0xe4, 0x7d, 0x88, 0x63, 0x26, 0x5a, 0x3d, 0x58, + 0xa1, 0xde, 0x18, 0x2f, 0x89, 0xfd, 0x76, 0x05, 0x55, 0xda, 0x79, 0xb7, 0x67, 0xad, 0xb7, 0xa8, + 0xd1, 0xcd, 0x85, 0x38, 0x12, 0x4f, 0x60, 0x3e, 0x67, 0x1e, 0x24, 0xd4, 0xc0, 0x53, 0x60, 0x8b, + 0xd5, 0x55, 0xb6, 0x17, 0x96, 0x61, 0x5b, 0x39, 0x59, 0xe9, 0xe1, 0xfe, 0xa3, 0xc6, 0x1b, 0x44, + 0x9f, 0x75, 0x44, 0xd0, 0x06, 0x22, 0x77, 0x58, 0x35, 0xdd, 0x96, 0xe8, 0xe0, 0x86, 0x4a, 0x4e, + 0x2b, 0x64, 0x68, 0x23, 0x2f, 0x44, 0x16, 0x31, 0xb3, 0x11, 0xfd, 0x82, 0x39, 0xb4, 0xc6, 0xc4, + 0x6a, 0x6c, 0x70, 0x4a, 0xc9, 0xb9, 0x4a, 0x68, 0x21, 0x6e, 0xd3, 0x56, 0x6b, 0xca, 0xea, 0x41, + 0x51, 0x56, 0xb5, 0xfd, 0x85, 0xfe, 0x1f, 0x3c, 0xaf, 0x4f, 0x3c, 0x62, 0xff, 0xe4, 0x1a, 0x7e, + 0x59, 0xdd, 0x1e, 0xe0, 0x63, 0x8d, 0x6c, 0xa3, 0x6e, 0xb7, 0xd4, 0xee, 0xd2, 0xd2, 0x62, 0xee, + 0xe8, 0x19, 0x97, 0x17, 0x3d, 0xaa, 0x96, 0xae, 0x7a, 0x74, 0x8e, 0x15, 0x01, 0x34, 0x60, 0x5d, + 0xec, 0xbb, 0xce, 0xca, 0xd3, 0x8f, 0xc8, 0x2e, 0xcb, 0xa2, 0x28, 0xdf, 0x0c, 0x72, 0xda, 0x5a, + 0x13, 0xce, 0x1d, 0x9b, 0x54, 0x02, 0xa9, 0x05, 0x22, 0x55, 0x39, 0xd8, 0xb7, 0x33, 0xe6, 0x83, + 0x2d, 0xd6, 0x56, 0xb2, 0xf0, 0xd8, 0xd7, 0x67, 0xaa, 0x1e, 0x9f, 0x9d, 0x67, 0x3c, 0x23, 0x65, + 0x70, 0x7d, 0xe2, 0xb3, 0xd4, 0x9f, 0x0e, 0x2c, 0x59, 0x9b, 0x24, 0xb1, 0xa0, 0x53, 0x3e, 0x6e, + 0x6d, 0x41, 0x8b, 0x7f, 0xb5, 0x2a, 0xd7, 0x9c, 0x9a, 0xbb, 0xbc, 0xbc, 0x6a, 0x35, 0xa1, 0xfd, + 0xc7, 0xde, 0x19, 0x12, 0xbc, 0xfa, 0xf3, 0xf8, 0x7c, 0xac, 0x79, 0x3e, 0xa7, 0xab, 0xc5, 0x04, + 0x98, 0x80, 0x14, 0x05, 0xb0, 0x44, 0x8e, 0xaa, 0xf4, 0x1c, 0x5e, 0x35, 0xad, 0x95, 0x68, 0x7b, + 0xb8, 0x44, 0x2d, 0xef, 0x17, 0x8c, 0x3e, 0x2a, 0x96, 0x40, 0x92, 0x76, 0xc1, 0x1f, 0xe5, 0x85, + 0xa0, 0xae, 0xe4, 0x2c, 0xd3, 0xb6, 0xd2, 0x49, 0x72, 0x45, 0x0e, 0xee, 0xf9, 0xcd, 0xbf, 0x21, + 0xde, 0xb3, 0xc1, 0xdf, 0x25, 0x67, 0xe7, 0x23, 0xb3, 0x36, 0xdc, 0xa1, 0x3d, 0xa7, 0xe8, 0xf7, + 0x57, 0x59, 0xef, 0xa0, 0xf7, 0x32, 0x07, 0x1e, 0x70, 0x2c, 0x1a, 0x7a, 0xa7, 0x94, 0x4c, 0x2b, + 0xee, 0xfc, 0x8b, 0x46, 0x3d, 0xc9, 0xbe, 0xd7, 0x03, 0x5b, 0xb3, 0x6c, 0x61, 0x51, 0xf3, 0xde, + 0x2c, 0xe8, 0x37, 0x3b, 0x58, 0xde, 0xb8, 0x56, 0x49, 0xbe, 0x79, 0x5d, 0x9e, 0x9c, 0x1d, 0x08, + 0x25, 0xb3, 0x16, 0x63, 0xbb, 0x33, 0x18, 0x1b, 0xa3, 0xed, 0x59, 0xab, 0xeb, 0xe4, 0xb0, 0x33, + 0x7d, 0x1c, 0x1a, 0xf4, 0x75, 0xf2, 0xd0, 0xd2, 0xfc, 0xb5, 0x33, 0x74, 0x68, 0x15, 0x78, 0xc0, + 0xb4, 0x35, 0xe5, 0xa4, 0x4e, 0xae, 0x97, 0x5d, 0xb7, 0x77, 0x39, 0x8d, 0xe9, 0xe6, 0xc7, 0xf3, + 0x9e, 0x5b, 0xb3, 0x3f, 0x31, 0xad, 0x5a, 0x49, 0x05, 0x29, 0x95, 0xf0, 0xb9, 0xd0, 0x92, 0x9b, + 0x78, 0xa3, 0x6f, 0x1f, 0x73, 0x4a, 0x20, 0xa4, 0xeb, 0xba, 0xb7, 0xe0, 0x7b, 0xdd, 0x91, 0xf3, + 0x14, 0x83, 0x47, 0xc8, 0x51, 0xad, 0xe2, 0x87, 0x7d, 0x2a, 0x91, 0xe9, 0x34, 0x20, 0x95, 0xfd, + 0xf1, 0xb6, 0xd9, 0xc2, 0x73, 0xb1, 0x64, 0x50, 0xe0, 0xa4, 0x91, 0x2f, 0x78, 0xf1, 0x11, 0xe3, + 0x1b, 0xad, 0x70, 0x62, 0x55, 0x24, 0x07, 0x3d, 0x40, 0x25, 0xbd, 0x31, 0xe4, 0x72, 0x44, 0xd5, + 0x96, 0x41, 0x08, 0xd7, 0x90, 0x25, 0x8d, 0xf8, 0xb6, 0x5c, 0x4d, 0x5f, 0x3d, 0x19, 0xb4, 0xcb, + 0x7a, 0x18, 0x55, 0x84, 0xbd, 0x76, 0x49, 0x9b, 0xbb, 0x76, 0x94, 0x5e, 0xd9, 0x55, 0x98, 0x6f, + 0xeb, 0xa6, 0xb8, 0xae, 0x0c, 0x9b, 0xba, 0x74, 0x6d, 0x3a, 0x7b, 0x89, 0x84, 0x54, 0xc0, 0x15, + 0x14, 0x61, 0x2d, 0xc7, 0x4a, 0x7e, 0x2d, 0x3b, 0x56, 0xf6, 0xb3, 0xea, 0xa0, 0x7f, 0x7b, 0xa4, + 0xb0, 0x6c, 0x20, 0x15, 0x99, 0x28, 0xe6, 0xee, 0x29, 0xc4, 0x2e, 0x04, 0x07, 0xbc, 0xa2, 0xfe, + 0x0c, 0xbf, 0x7a, 0xd4, 0xe9, 0xee, 0xdf, 0x52, 0xfd, 0x95, 0xc5, 0x34, 0x58, 0xc9, 0x3c, 0x66, + 0x22, 0x5b, 0x7c, 0xa0, 0xe6, 0x61, 0x16, 0x6d, 0x5e, 0x67, 0x68, 0x1a, 0x90, 0xb9, 0x10, 0x0e, + 0x08, 0x16, 0x06, 0xc9, 0xc5, 0x5e, 0xdd, 0xb7, 0xa5, 0xed, 0xc5, 0x8e, 0x49, 0x60, 0xed, 0xa1, + 0x44, 0xbd, 0x8a, 0x1f, 0xfe, 0x4e, 0xce, 0xf7, 0x42, 0xb7, 0x17, 0xdc, 0x1e, 0xa3, 0x8f, 0xe0, + 0xe2, 0x3b, 0xf4, 0x8a, 0x06, 0x45, 0x81, 0x19, 0xd9, 0x59, 0x37, 0xa4, 0x37, 0xb9, 0xdd, 0x11, + 0x4b, 0x5c, 0x07, 0x66, 0x70, 0xa5, 0xd6, 0x91, 0xb0, 0xce, 0x3c, 0x78, 0xdd, 0x69, 0x7c, 0xad, + 0x6c, 0xce, 0x82, 0xce, 0x13, 0xef, 0x08, 0xc3, 0x7d, 0xc9, 0x90, 0x46, 0x67, 0x45, 0xaf, 0xf0, + 0xb4, 0x2a, 0xa4, 0x87, 0xcf, 0xa2, 0x8d, 0xca, 0x7c, 0xbf, 0x15, 0xd2, 0x54, 0x41, 0xc5, 0x8f, + 0xfb, 0xe9, 0xcc, 0xab, 0x3f, 0x31, 0xad, 0xe6, 0x75, 0x5d, 0xef, 0xab, 0x80, 0xf0, 0xa8, 0x85, + 0xd9, 0x4d, 0x37, 0xfd, 0xcc, 0x15, 0xe4, 0x47, 0x84, 0x16, 0xf0, 0xf6, 0xf4, 0xfe, 0x5a, 0x4e, + 0xdd, 0x64, 0x8a, 0x12, 0xd3, 0xd7, 0xc6, 0xd5, 0x47, 0xf4, 0x4b, 0xe5, 0xfe, 0x75, 0xc3, 0xbc, + 0x67, 0x56, 0x22, 0x02, 0xbb, 0xe8, 0xac, 0x52, 0x8c, 0x32, 0xab, 0x0d, 0x71, 0x98, 0xe2, 0x2d, + 0x8a, 0x13, 0x0c, 0xaf, 0x2c, 0xf6, 0x2c, 0xf0, 0x0b, 0xe2, 0x41, 0x4b, 0x28, 0x15, 0x7f, 0x47, + 0xf9, 0x76, 0x51, 0x00, 0x5d, 0x59, 0x11, 0xd1, 0xac, 0x65, 0xbe, 0x68, 0x48, 0x71, 0x33, 0xa2, + 0x96, 0x59, 0x3a, 0x0f, 0x9d, 0x23, 0xd2, 0x1e, 0xf4, 0x31, 0x97, 0x58, 0x41, 0x4b, 0xeb, 0x8b, + 0x15, 0x96, 0xb5, 0x54, 0x13, 0x18, 0x1f, 0x69, 0x67, 0xe1, 0x7a, 0x6b, 0x41, 0x2a, 0xb1, 0xa1, + 0x56, 0x91, 0xe4, 0x80, 0x05, 0x37, 0x46, 0x26, 0x3b, 0xa5, 0x4d, 0x78, 0x7e, 0x41, 0x4d, 0x0c, + 0x3c, 0xd4, 0x19, 0x8e, 0x25, 0x7b, 0x94, 0x7a, 0xad, 0x4c, 0xce, 0xda, 0xcd, 0x1e, 0x86, 0x63, + 0xee, 0x6d, 0x84, 0x71, 0xb0, 0xb7, 0xd1, 0xc2, 0x25, 0x7f, 0xa2, 0xc7, 0x55, 0xf9, 0x39, 0xda, + 0x09, 0x6a, 0x91, 0x60, 0x1b, 0xb0, 0xf2, 0xb6, 0xd0, 0x2f, 0xfb, 0xd5, 0x35, 0x9a, 0x7d, 0x5d, + 0x55, 0x1c, 0xb2, 0x1b, 0xb5, 0xf5, 0xd9, 0x85, 0xc9, 0xd3, 0x71, 0x0d, 0x2f, 0x98, 0xb6, 0x5d, + 0xa9, 0x86, 0x4c, 0x3f, 0xc2, 0xfb, 0xa9, 0x83, 0x25, 0xf6, 0x4a, 0x2a, 0xb6, 0x34, 0x33, 0x9b, + 0xda, 0x99, 0x84, 0x20, 0x8d, 0x35, 0xc0, 0x0e, 0xe7, 0xf4, 0x54, 0x4f, 0x33, 0xdc, 0x8c, 0x68, + 0x00, 0x5c, 0xd5, 0x1d, 0x01, 0xb6, 0xd2, 0x68, 0x9a, 0x77, 0xd0, 0xf2, 0x10, 0xb9, 0x58, 0x1f, + 0x99, 0x05, 0x45, 0x44, 0x77, 0x9c, 0x06, 0x11, 0xb3, 0x7d, 0x75, 0x20, 0x3e, 0x0b, 0xd7, 0x4b, + 0xd6, 0x1f, 0x4d, 0xab, 0xf8, 0x3f, 0x31, 0x6d, 0x10, 0x81, 0xc8, 0x46, 0xc8, 0x22, 0x7b, 0x3c, + 0xbb, 0xaa, 0x00, 0x0f, 0x68, 0x2d, 0x76, 0x76, 0x14, 0xf9, 0xd2, 0x93, 0xdd, 0x13, 0xac, 0x69, + 0x4d, 0x08, 0xfb, 0xa2, 0x51, 0x1c, 0xb0, 0x80, 0x7d, 0x7e, 0x4b, 0x91, 0x35, 0x3d, 0xc9, 0x0d, + 0xd2, 0x44, 0x59, 0xd9, 0xca, 0xa9, 0x45, 0x1b, 0x04, 0x3d, 0xb8, 0xf5, 0xde, 0x61, 0x92, 0xbc, + 0x61, 0x85, 0xc5, 0x7f, 0x3c, 0xc3, 0x72, 0x38, 0x40, 0x4c, 0xad, 0x1a, 0x53, 0xd0, 0xcc, 0xb4, + 0xee, 0x8f, 0x26, 0x2a, 0x64, 0x1e, 0xea, 0x27, 0x98, 0x28, 0xef, 0xc5, 0x4a, 0x57, 0xe2, 0x6e, + 0x25, 0x94, 0x1b, 0x39, 0x54, 0x5f, 0x5e, 0xc2, 0x3e, 0x84, 0xc8, 0x65, 0x24, 0x77, 0x5d, 0xa0, + 0x74, 0x57, 0xdf, 0xca, 0x30, 0x25, 0x54, 0x89, 0x7b, 0x3f, 0xd2, 0xb2, 0x30, 0x18, 0x75, 0x63, + 0xda, 0x1c, 0x48, 0x01, 0x7f, 0xf3, 0xc5, 0xa9, 0x97, 0x69, 0x52, 0x16, 0x51, 0x66, 0x47, 0x20, + 0xc6, 0xc1, 0x81, 0x34, 0x5a, 0xa2, 0x1e, 0x9d, 0xc1, 0xee, 0xc7, 0x18, 0xf4, 0xa2, 0x7c, 0x02, + 0xd2, 0xc2, 0x99, 0xe7, 0xc4, 0x85, 0x95, 0xd3, 0x47, 0x98, 0x05, 0x2b, 0xe8, 0x09, 0x7d, 0x79, + 0x24, 0xa1, 0xdf, 0xc9, 0x38, 0x09, 0xbe, 0x4c, 0x51, 0x20, 0xd2, 0x2d, 0x87, 0x73, 0x3d, 0x64, + 0x76, 0x25, 0xac, 0x79, 0x0b, 0xee, 0x82, 0xe7, 0x3e, 0x92, 0xa7, 0x09, 0x2d, 0xf0, 0xf1, 0x0b, + 0xc4, 0xf2, 0xf2, 0x4f, 0x8c, 0x67, 0x94, 0xd7, 0x5b, 0xdb, 0xdd, 0xa4, 0x77, 0x6b, 0x27, 0x72, + 0x45, 0xbc, 0xb6, 0xd6, 0xcd, 0xb5, 0xc4, 0x12, 0xc7, 0x11, 0xee, 0x3f, 0xd4, 0xca, 0x1f, 0x53, + 0x0d, 0x1b, 0x8a, 0xf5, 0x76, 0xae, 0xba, 0x3e, 0x57, 0xaa, 0x5e, 0x19, 0xdf, 0x12, 0x0d, 0x4a, + 0x1c, 0x91, 0xbd, 0x56, 0x8d, 0xc8, 0x4a, 0x89, 0x84, 0xf4, 0x13, 0x09, 0x10, 0x08, 0xde, 0xa2, + 0x92, 0x51, 0xb9, 0x2c, 0x89, 0x54, 0xb5, 0xd0, 0x22, 0x51, 0x08, 0x92, 0x04, 0xfb, 0xa6, 0xf7, + 0x2f, 0x3d, 0x57, 0x38, 0x3f, 0x31, 0xbd, 0x84, 0xeb, 0x5c, 0xe9, 0xa9, 0xd5, 0xe8, 0x36, 0x1a, + 0x62, 0xa7, 0x6f, 0x1e, 0x68, 0x41, 0x0e, 0x99, 0xae, 0x08, 0xf5, 0x1f, 0xf9, 0x79, 0x34, 0xea, + 0x6a, 0xad, 0x82, 0x62, 0xd7, 0xe8, 0xe3, 0xe5, 0x16, 0x65, 0xaf, 0xa6, 0x5c, 0x28, 0x4c, 0x3d, + 0x86, 0x64, 0xcc, 0x34, 0xa9, 0x6d, 0x09, 0x28, 0x1c, 0x92, 0x95, 0x73, 0x7e, 0xad, 0x18, 0xa7, + 0x22, 0xc8, 0x72, 0x09, 0x83, 0xab, 0xa1, 0x85, 0x9c, 0xec, 0xa8, 0x94, 0xd5, 0x80, 0x4d, 0x71, + 0x0b, 0x02, 0x6f, 0x22, 0xbc, 0xc2, 0x93, 0xab, 0xc5, 0xe9, 0x13, 0x5b, 0xad, 0x5d, 0x9b, 0x15, + 0xf6, 0x4c, 0x67, 0xe4, 0x93, 0x36, 0xab, 0xe3, 0x74, 0x61, 0x6c, 0xdc, 0x5e, 0xa5, 0x55, 0x40, + 0xc1, 0x7c, 0x32, 0xba, 0x92, 0x59, 0x3d, 0x98, 0xfa, 0xda, 0xbc, 0xd0, 0xe4, 0x96, 0x24, 0x8e, + 0x56, 0xcf, 0x49, 0x6d, 0x67, 0xb2, 0x45, 0x89, 0x05, 0xc5, 0x1e, 0xf7, 0x50, 0x21, 0x3e, 0x7a, + 0x78, 0xc3, 0xb8, 0x35, 0x89, 0xc3, 0x02, 0xc8, 0x70, 0xcc, 0x00, 0x8a, 0x63, 0x54, 0x8f, 0x07, + 0x97, 0xb0, 0x09, 0x64, 0xac, 0x52, 0x52, 0x8d, 0xde, 0x8d, 0x87, 0xf9, 0xfc, 0xed, 0x16, 0x66, + 0xb8, 0x71, 0x91, 0xad, 0x47, 0x99, 0x3c, 0x94, 0x7c, 0x92, 0x29, 0x92, 0xea, 0x5f, 0x27, 0x3b, + 0xe8, 0x0c, 0xfb, 0x4a, 0x1c, 0x4e, 0x62, 0x1a, 0xcf, 0x3e, 0x8e, 0x15, 0x4c, 0x48, 0x52, 0x63, + 0xbc, 0xa9, 0xd8, 0x35, 0x05, 0xf7, 0x43, 0xdb, 0xa1, 0x28, 0x20, 0x78, 0xaa, 0x24, 0x3e, 0x1b, + 0xc1, 0x32, 0x33, 0xc2, 0xe7, 0x36, 0xca, 0x0e, 0x15, 0x24, 0x84, 0x10, 0x3c, 0x67, 0x88, 0x8e, + 0x48, 0xcd, 0xda, 0x33, 0x23, 0x5f, 0xde, 0x89, 0x33, 0xe8, 0xb4, 0x21, 0xda, 0xc2, 0x84, 0x37, + 0xc8, 0x5d, 0x3d, 0xdc, 0xdc, 0x68, 0xce, 0xe3, 0xe2, 0xdb, 0x8f, 0xf5, 0x6a, 0x59, 0x52, 0xc6, + 0x71, 0x91, 0x1c, 0xe1, 0xe1, 0x12, 0x6b, 0x89, 0xa9, 0x6e, 0xa3, 0x3f, 0x9e, 0xf6, 0x89, 0x72, + 0x7f, 0x62, 0xda, 0x52, 0xce, 0x24, 0xb8, 0xaa, 0xdf, 0x24, 0x67, 0x67, 0x98, 0xed, 0x06, 0xe9, + 0xb3, 0xc7, 0x67, 0x5e, 0xca, 0xc2, 0xac, 0x21, 0xf5, 0xd5, 0xdd, 0x82, 0xc7, 0x9d, 0xfb, 0x7b, + 0x1d, 0xda, 0xc8, 0xf2, 0x6f, 0x9c, 0xe8, 0x12, 0x4f, 0x66, 0x66, 0x85, 0x00, 0x11, 0xec, 0xef, + 0xc8, 0xe1, 0xe7, 0x13, 0xcc, 0x51, 0x60, 0xe8, 0x55, 0x6b, 0xc1, 0x49, 0x95, 0x46, 0x0d, 0xf7, + 0x9b, 0xe0, 0x6f, 0x68, 0xc4, 0xba, 0xe6, 0x1d, 0x9f, 0x8c, 0xd6, 0x81, 0xb8, 0xc1, 0xcc, 0x9f, + 0x59, 0x2b, 0x91, 0xb3, 0x26, 0xfe, 0x01, 0x97, 0x6d, 0xab, 0xaf, 0xb5, 0x66, 0x1d, 0x32, 0x57, + 0x9d, 0x3f, 0x8d, 0x78, 0x50, 0x4b, 0x09, 0xa4, 0xce, 0x48, 0x1b, 0xe0, 0x53, 0xcc, 0x88, 0x3c, + 0x76, 0x8e, 0x59, 0x11, 0x2d, 0xbb, 0xb0, 0xdd, 0x02, 0x7a, 0x7c, 0x25, 0x95, 0xc8, 0xdc, 0x7d, + 0x9b, 0x64, 0x13, 0xc3, 0x35, 0x3d, 0x23, 0x69, 0xcb, 0x6d, 0xdf, 0x90, 0xdc, 0x19, 0xff, 0x4d, + 0x48, 0x2d, 0x07, 0x42, 0xbb, 0xf5, 0xf0, 0xc7, 0xca, 0xdb, 0xdc, 0xa5, 0x77, 0xee, 0x70, 0x63, + 0xdd, 0xa3, 0xce, 0xa6, 0xca, 0x27, 0xb7, 0x84, 0xe0, 0x58, 0x77, 0xd8, 0x82, 0x4f, 0x7d, 0x58, + 0xca, 0xa0, 0x3c, 0x4a, 0x5e, 0xe8, 0x6e, 0x0f, 0x18, 0x99, 0x2e, 0x17, 0xac, 0xc1, 0xfc, 0x2b, + 0xef, 0x68, 0x06, 0xbe, 0xf5, 0xba, 0x2b, 0x96, 0x3f, 0xbd, 0xa3, 0xe1, 0x95, 0x28, 0xde, 0xd3, + 0x39, 0xc6, 0x62, 0xcc, 0x0c, 0x3e, 0x6d, 0x1c, 0x72, 0x64, 0xa6, 0x8d, 0xf6, 0x17, 0x9e, 0x44, + 0x45, 0xcd, 0xe1, 0xf6, 0x03, 0x1d, 0x7b, 0x06, 0x01, 0x31, 0xe8, 0xf1, 0xc8, 0xf5, 0xbd, 0xfd, + 0x2b, 0x10, 0x1c, 0x69, 0x5e, 0x10, 0x55, 0xc7, 0x66, 0xf4, 0xb5, 0x2a, 0xe6, 0x5f, 0xaf, 0x43, + 0xb7, 0x18, 0x10, 0x40, 0xd3, 0xec, 0x4b, 0xf0, 0xe8, 0x9d, 0x5d, 0xb5, 0xd5, 0xeb, 0x21, 0x4d, + 0x79, 0x0d, 0x61, 0xe7, 0xd6, 0xe1, 0x4e, 0x7f, 0xa1, 0x64, 0xff, 0xbd, 0x0e, 0xb8, 0x9a, 0x3f, + 0xf6, 0xc6, 0xfa, 0x08, 0x7c, 0xff, 0x6e, 0x7a, 0xb7, 0xca, 0xbb, 0x27, 0x47, 0xb9, 0x9d, 0xc2, + 0x4b, 0xcf, 0x71, 0xc4, 0xa4, 0xe7, 0x8c, 0x4d, 0xc3, 0x8a, 0x45, 0xd7, 0xd4, 0xa9, 0xbe, 0x69, + 0x7c, 0x89, 0xba, 0xdc, 0x12, 0x48, 0xdc, 0xb6, 0x7e, 0xed, 0x6e, 0xe9, 0x26, 0xc9, 0xfd, 0xdb, + 0xc4, 0x8c, 0x43, 0xbb, 0x5d, 0x09, 0x39, 0x44, 0xaa, 0xe6, 0x6c, 0xa1, 0x26, 0xf1, 0x08, 0x77, + 0x41, 0xe2, 0x7e, 0xac, 0xad, 0xad, 0xbb, 0xd2, 0x52, 0x5e, 0x9b, 0xa6, 0xf2, 0x67, 0x68, 0xe5, + 0x5a, 0xc7, 0x53, 0xb0, 0x2d, 0x8e, 0x9a, 0x41, 0x0e, 0x28, 0x7c, 0xe3, 0x3a, 0x53, 0xf0, 0x6c, + 0x29, 0x12, 0xc6, 0x8f, 0x7f, 0x34, 0x75, 0xa7, 0x7e, 0xb6, 0xf9, 0xb2, 0xb6, 0xf7, 0x06, 0x28, + 0x8e, 0x2d, 0x15, 0x6e, 0xc1, 0x55, 0x5f, 0x19, 0x0d, 0xfe, 0xea, 0xfa, 0xac, 0xf3, 0x31, 0x4b, + 0x25, 0x2b, 0x2d, 0x1b, 0x5b, 0x2b, 0x8b, 0xdb, 0xcd, 0x6f, 0xdf, 0x7e, 0x75, 0x53, 0x2a, 0xad, + 0x00, 0x4e, 0xf4, 0x80, 0x64, 0xed, 0xfe, 0x84, 0xd6, 0xd4, 0xda, 0x27, 0xb4, 0xb1, 0x49, 0x2e, + 0x54, 0x2e, 0xe5, 0xe4, 0x49, 0xcb, 0xe2, 0x24, 0xab, 0xad, 0x38, 0xec, 0x8e, 0xcc, 0x97, 0x18, + 0x5d, 0xc4, 0xae, 0x8c, 0xa7, 0xfb, 0xd9, 0x91, 0x28, 0xe8, 0xe7, 0xea, 0x9f, 0x4a, 0x24, 0xa6, + 0x67, 0xdc, 0x24, 0x47, 0xcf, 0x73, 0x9f, 0x54, 0x95, 0x5e, 0xc9, 0x2c, 0xc7, 0xc2, 0xf3, 0xfc, + 0x52, 0xb1, 0x58, 0xb4, 0xf2, 0xad, 0xe8, 0xed, 0xf1, 0x77, 0x6a, 0x5e, 0x49, 0xa9, 0xd2, 0x0e, + 0x12, 0x76, 0xd1, 0x82, 0xf5, 0x33, 0xa6, 0x35, 0x2f, 0x7a, 0x46, 0xa7, 0xa4, 0xd1, 0x8f, 0xb5, + 0xee, 0x5b, 0xa9, 0x6d, 0xe6, 0xef, 0x0a, 0xf5, 0xaf, 0x3d, 0x47, 0xf4, 0x24, 0x5d, 0x4d, 0x69, + 0xaa, 0x4c, 0xed, 0x7a, 0xcd, 0xe5, 0xc7, 0x04, 0xb9, 0x87, 0x91, 0x7a, 0x5e, 0x69, 0xed, 0x5b, + 0x64, 0xda, 0xf2, 0x29, 0x06, 0x3e, 0x95, 0x31, 0xe9, 0x2e, 0x29, 0x7e, 0xa0, 0x64, 0x6b, 0x11, + 0x08, 0x25, 0xdc, 0x07, 0x3f, 0xde, 0xbb, 0x62, 0x29, 0x7e, 0x62, 0x1a, 0xd2, 0x03, 0x01, 0x75, + 0x95, 0xf7, 0x44, 0x27, 0x2f, 0xae, 0x2f, 0xcc, 0xbb, 0x90, 0xb4, 0xe0, 0x27, 0x08, 0xa1, 0x06, + 0xe9, 0x10, 0xea, 0xdc, 0x13, 0x4b, 0xb7, 0x6b, 0x39, 0xc3, 0xc6, 0x8f, 0x51, 0x08, 0x6d, 0x87, + 0xf7, 0x7c, 0x87, 0xba, 0x25, 0xf8, 0x80, 0x65, 0x2e, 0x6c, 0x97, 0x3d, 0x5f, 0x1c, 0xe7, 0x21, + 0xa2, 0x5f, 0x49, 0x04, 0x9a, 0xbc, 0x65, 0x5b, 0x60, 0x1a, 0x97, 0x08, 0xc5, 0x2f, 0x70, 0x14, + 0xb2, 0x2e, 0xb4, 0xb8, 0x62, 0xf4, 0xf0, 0x02, 0x66, 0x62, 0xbf, 0x67, 0xb1, 0x27, 0x04, 0xc5, + 0xad, 0x2e, 0x4f, 0x1d, 0xea, 0x88, 0x6e, 0x3c, 0x09, 0xbc, 0x60, 0x65, 0xd5, 0xa5, 0xf8, 0x01, + 0xd3, 0x0c, 0x0b, 0x55, 0x6b, 0xd9, 0x0a, 0x28, 0x39, 0xdc, 0x5d, 0xec, 0xb7, 0xed, 0x2c, 0xe3, + 0xc1, 0xdb, 0x6d, 0x5b, 0xe1, 0x9b, 0x54, 0x7a, 0xe5, 0x07, 0xba, 0xd1, 0x9a, 0xde, 0x67, 0x90, + 0xe9, 0x71, 0x09, 0xda, 0x1d, 0xd5, 0x1a, 0xa7, 0x99, 0xe4, 0xf2, 0x90, 0xd0, 0xb7, 0x67, 0x0e, + 0x2c, 0xd5, 0xab, 0xa8, 0xe3, 0x9d, 0x0a, 0x56, 0x1d, 0xad, 0x76, 0x55, 0x43, 0x8a, 0x32, 0x2d, + 0x43, 0x53, 0xeb, 0xef, 0xe6, 0x33, 0x0e, 0x04, 0xcd, 0xf2, 0x55, 0x1a, 0x4a, 0xf3, 0xa7, 0x32, + 0x91, 0xcd, 0xc8, 0xdd, 0x13, 0x58, 0x1d, 0x86, 0x5f, 0x22, 0x95, 0xfd, 0x27, 0xa6, 0xb3, 0x3c, + 0xb0, 0x4a, 0xdb, 0x26, 0x91, 0xf3, 0xfe, 0x45, 0x94, 0xae, 0x25, 0x15, 0xb6, 0x22, 0xf4, 0x9f, + 0x96, 0xc8, 0xf9, 0xa6, 0xdb, 0xac, 0x1f, 0x50, 0x27, 0xa3, 0xc5, 0xc2, 0x51, 0x7f, 0xa4, 0x56, + 0xbe, 0x9e, 0x5c, 0x9a, 0xdd, 0x84, 0x47, 0x95, 0xc3, 0x43, 0x8a, 0xb8, 0x56, 0x7c, 0x4a, 0x4e, + 0xbf, 0x3f, 0x53, 0xba, 0xd6, 0x57, 0xd9, 0xba, 0xaf, 0x96, 0x78, 0x7a, 0x6c, 0x2b, 0x20, 0x79, + 0xbd, 0x4a, 0xf2, 0x73, 0x5b, 0x2d, 0x8c, 0x34, 0x7b, 0x11, 0x75, 0x41, 0xeb, 0x41, 0xa7, 0x96, + 0x0a, 0x6f, 0x2c, 0x48, 0x63, 0x7b, 0xfa, 0x97, 0x9e, 0x2b, 0xac, 0x9f, 0x98, 0xc6, 0x6a, 0xdb, + 0x28, 0xd5, 0xd1, 0x6a, 0x18, 0x84, 0x1d, 0x4f, 0x38, 0xdd, 0x13, 0x4e, 0x03, 0xc9, 0xb4, 0x97, + 0x8d, 0xb7, 0x04, 0x37, 0x77, 0x65, 0x45, 0xf5, 0xb0, 0xef, 0xe1, 0xa5, 0x62, 0x1b, 0x98, 0x60, + 0x52, 0xfb, 0x07, 0xd2, 0xb1, 0x63, 0x0d, 0x4b, 0xb8, 0x5b, 0xb2, 0x20, 0x77, 0x99, 0xdc, 0xf1, + 0xc1, 0x49, 0x16, 0xb0, 0x6e, 0xdc, 0xe4, 0x01, 0x57, 0x71, 0x65, 0x6b, 0xce, 0x08, 0xb5, 0xb8, + 0xf3, 0xa0, 0x07, 0xb5, 0x63, 0xb2, 0x01, 0x3a, 0x52, 0x8e, 0xfc, 0xdd, 0x16, 0x87, 0x39, 0x49, + 0xe8, 0xea, 0xb1, 0x46, 0xba, 0x6d, 0x76, 0x3e, 0x77, 0xb0, 0x01, 0x2d, 0x4b, 0x63, 0xf1, 0x66, + 0xa8, 0x09, 0x64, 0xdd, 0x14, 0x93, 0x9d, 0x39, 0xd6, 0x86, 0x9b, 0x7a, 0x58, 0xa5, 0x53, 0x19, + 0x0a, 0x88, 0x7f, 0xce, 0x68, 0x2f, 0xea, 0x26, 0x7c, 0xc0, 0xdd, 0x36, 0xab, 0xa3, 0x60, 0x1f, + 0xba, 0xb6, 0x84, 0xd4, 0xd9, 0x3a, 0x8d, 0xdc, 0x51, 0xd3, 0xeb, 0x41, 0xb4, 0x37, 0xbb, 0x6e, + 0x5a, 0x51, 0x08, 0x46, 0xe0, 0xeb, 0x40, 0x46, 0x52, 0xd2, 0x4b, 0x9e, 0xcd, 0xe7, 0x67, 0xdb, + 0x78, 0xa9, 0x93, 0x8a, 0x7c, 0x67, 0xc4, 0xea, 0x90, 0x8e, 0xef, 0xe9, 0x41, 0xd6, 0x9b, 0xe8, + 0x2c, 0xf3, 0xf5, 0x3a, 0x75, 0x27, 0xca, 0x7b, 0x08, 0x07, 0xb5, 0x51, 0xa3, 0x0b, 0x8b, 0x3c, + 0x1a, 0x38, 0x1d, 0x89, 0x76, 0x6b, 0x77, 0x41, 0x57, 0xfa, 0x7e, 0x12, 0x9a, 0xe1, 0x45, 0xd4, + 0x58, 0xf7, 0x78, 0xf3, 0xf0, 0xe2, 0x0a, 0x7e, 0xc2, 0xd0, 0xb8, 0xec, 0xd5, 0x1d, 0xb6, 0x1a, + 0x09, 0xfb, 0xc2, 0xe2, 0x1f, 0xee, 0x8f, 0xe8, 0x2f, 0xf2, 0xfa, 0x96, 0x8d, 0xb6, 0xbd, 0x6e, + 0xf2, 0xd1, 0x27, 0xdf, 0xb9, 0xfa, 0x9b, 0x54, 0xc1, 0x25, 0xb5, 0xbe, 0xc7, 0xee, 0x27, 0xc5, + 0xa1, 0x8e, 0x24, 0x16, 0xf0, 0xb1, 0x34, 0x1a, 0xe3, 0x79, 0xe5, 0x52, 0x1a, 0x90, 0xff, 0x92, + 0xfa, 0x98, 0xbb, 0x4f, 0xea, 0x40, 0x54, 0xf3, 0x63, 0x9c, 0x66, 0x54, 0xff, 0xbe, 0xce, 0x27, + 0xf8, 0x4f, 0xa5, 0x78, 0xa5, 0x41, 0xff, 0x51, 0x66, 0xaa, 0x70, 0x1f, 0xd5, 0xd7, 0xd9, 0x5d, + 0xe2, 0x97, 0x4e, 0xca, 0x0d, 0x2d, 0x13, 0x45, 0xfd, 0x9b, 0x9e, 0xb8, 0x1e, 0xa5, 0xf7, 0x89, + 0xcb, 0x54, 0xb1, 0x71, 0x79, 0xdd, 0xf7, 0xa3, 0x43, 0xe1, 0xc3, 0xf7, 0xbf, 0x9b, 0xbf, 0x56, + 0xdf, 0x36, 0x28, 0xe5, 0x43, 0x62, 0x01, 0x55, 0x98, 0x0c, 0xdd, 0xb8, 0x5d, 0x4e, 0xeb, 0xf2, + 0xd9, 0x51, 0x6a, 0x80, 0x09, 0x8a, 0xc1, 0x43, 0xf5, 0x7c, 0xf7, 0x9d, 0x9a, 0x5c, 0x45, 0xdd, + 0x47, 0xc1, 0xe1, 0x43, 0xf4, 0xef, 0x2c, 0xf6, 0xd0, 0xd3, 0xe7, 0x53, 0x56, 0x57, 0x9a, 0x5d, + 0xd0, 0xc4, 0x16, 0xbe, 0x0a, 0xf6, 0x6e, 0x48, 0x2d, 0xf0, 0xff, 0x4e, 0xa4, 0xa4, 0x18, 0x65, + 0x03, 0xa0, 0xeb, 0xff, 0xd7, 0x2f, 0x07, 0x3f, 0x76, 0x4d, 0x80, 0xd4, 0x3f, 0x19, 0xd3, 0x39, + 0x8d, 0x4c, 0x7c, 0x87, 0x89, 0xaa, 0xbe, 0xad, 0xd9, 0x4b, 0xfb, 0xc8, 0xbf, 0x19, 0x33, 0x22, + 0x2c, 0xbe, 0xc0, 0x79, 0x84, 0x86, 0xf6, 0x4d, 0xcf, 0x6e, 0xec, 0x23, 0x7b, 0x83, 0xb8, 0x5c, + 0x91, 0x8b, 0x59, 0x61, 0x76, 0x98, 0x0e, 0x06, 0x78, 0x5d, 0x2d, 0x96, 0x00, 0x8e, 0x99, 0x17, + 0x2f, 0x45, 0x6e, 0x74, 0x56, 0xe4, 0x44, 0xca, 0xe6, 0xd1, 0x69, 0x73, 0x23, 0x11, 0xc9, 0xdf, + 0xbf, 0x45, 0x2e, 0x1b, 0x66, 0x7a, 0x75, 0xe9, 0x23, 0x33, 0x99, 0xe5, 0x5d, 0xde, 0x22, 0x10, + 0xe0, 0x14, 0x87, 0x72, 0xab, 0x48, 0x80, 0x4d, 0x7e, 0x85, 0x6e, 0x5a, 0xf2, 0xd5, 0x9e, 0x16, + 0xe5, 0x68, 0x80, 0xe3, 0xef, 0x39, 0xd2, 0x27, 0xa6, 0x5e, 0x6c, 0x3b, 0xe5, 0x50, 0xc5, 0x26, + 0xf4, 0xb1, 0xbf, 0x0c, 0x8d, 0x69, 0xf9, 0x08, 0xa0, 0x45, 0x89, 0x19, 0xe9, 0x85, 0x5d, 0xce, + 0x00, 0x26, 0x31, 0xa3, 0x00, 0xe5, 0x48, 0x90, 0x1c, 0x57, 0xcf, 0xea, 0x5b, 0x92, 0xe2, 0x49, + 0x7a, 0x3e, 0x7c, 0xe1, 0x62, 0x74, 0xb5, 0x83, 0xcf, 0xfd, 0xc1, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, + 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, + 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0xff, 0x97, + 0xf2, 0xcf, 0xf3, 0xe0, 0x1f, 0xf7, 0x88, 0xf2, 0x57, 0xff, 0x7d, 0xf7, 0x80, 0xbe, 0x7b, 0x3c, + 0xe8, 0x96, 0xd9, 0xc5, 0x40, 0x2a, 0x92, 0xcc, 0x19, 0xb6, 0xaa, 0x0a, 0x6f, 0x9b, 0x8d, 0x36, + 0xf2, 0x5b, 0xe7, 0x6f, 0x5f, 0x4f, 0x7d, 0x96, 0x96, 0xc9, 0xa0, 0x2c, 0xdf, 0x5f, 0x3d, 0xbd, + 0xd1, 0x63, 0xfe, 0xe0, 0x01, 0xc5, 0xb4, 0xb5, 0x42, 0x7d, 0x46, 0xa7, 0x77, 0x70, 0xd6, 0x53, + 0x7b, 0x9e, 0xc3, 0x05, 0x7d, 0x5c, 0xb4, 0x5b, 0x4b, 0x89, 0x09, 0x17, 0x5d, 0xb2, 0x51, 0x6b, + 0xa9, 0x54, 0xd4, 0x72, 0x8e, 0x3e, 0x5e, 0x43, 0x9d, 0xce, 0xb0, 0x6f, 0x49, 0x94, 0xd3, 0x29, + 0xf1, 0x4d, 0x33, 0xd9, 0x2f, 0xb7, 0xe7, 0x6a, 0x8d, 0x70, 0xef, 0xcb, 0x6b, 0x34, 0x78, 0x21, + 0xe7, 0x05, 0x4e, 0xd1, 0xa1, 0x51, 0x59, 0x46, 0x47, 0xf3, 0x0a, 0x83, 0xe7, 0xeb, 0x35, 0x00, + 0x47, 0xe6, 0xf9, 0x42, 0x49, 0x28, 0x68, 0x36, 0xc4, 0x0f, 0x17, 0xc6, 0x01, 0xf1, 0xf9, 0x4b, + 0x89, 0xea, 0x7e, 0x0f, 0x8e, 0x26, 0x11, 0xd5, 0x05, 0x66, 0x88, 0x6c, 0x76, 0x77, 0x1f, 0xcd, + 0xd6, 0x2f, 0x1a, 0xa8, 0xb6, 0x77, 0x8f, 0x2b, 0x99, 0x4a, 0xb3, 0x8e, 0x58, 0x1f, 0xe2, 0x05, + 0x3a, 0x3d, 0xd5, 0xcd, 0xf3, 0xcd, 0x7e, 0xd4, 0xb8, 0xdf, 0x3a, 0xb4, 0x13, 0x0d, 0xfc, 0xef, + 0xe4, 0x92, 0x63, 0x9b, 0x59, 0x2f, 0xcb, 0x24, 0x47, 0xf1, 0x31, 0xd5, 0xfe, 0x6f, 0x24, 0xbf, + 0xee, 0xad, 0xad, 0x97, 0xf5, 0x08, 0x85, 0xc1, 0x17, 0xa9, 0x43, 0x6b, 0x29, 0xd7, 0xeb, 0x7d, + 0x5b, 0xa9, 0xa7, 0x09, 0xf4, 0x4a, 0x99, 0xc6, 0xe0, 0xeb, 0xb5, 0xda, 0xa1, 0xf9, 0xeb, 0x7e, + 0xb5, 0x72, 0x21, 0xab, 0xdb, 0x4f, 0x2e, 0x4b, 0xf4, 0xfa, 0x6d, 0xc6, 0x72, 0xd3, 0x5e, 0x2b, + 0xd3, 0xf1, 0xc8, 0x97, 0x4a, 0x67, 0x6c, 0x62, 0xe7, 0x77, 0xed, 0x05, 0xba, 0x0a, 0xc9, 0xeb, + 0x5b, 0x49, 0xf9, 0x58, 0xd7, 0x5e, 0x4a, 0x47, 0xcc, 0x9c, 0x25, 0x2a, 0xfc, 0x5e, 0x87, 0x1b, + 0x80, 0x63, 0xed, 0x82, 0xab, 0x43, 0xb4, 0x53, 0x42, 0xa6, 0xfd, 0xe3, 0xce, 0xc5, 0x16, 0xe7, + 0x27, 0xa6, 0x17, 0x56, 0xad, 0xc6, 0x1a, 0x95, 0x42, 0x90, 0x44, 0xa4, 0x60, 0x83, 0x4f, 0x73, + 0x31, 0xad, 0x01, 0x9f, 0x28, 0x8c, 0x88, 0xeb, 0xbe, 0xb7, 0xae, 0xb8, 0xbd, 0xa6, 0xe4, 0xc6, + 0x73, 0x12, 0x96, 0x89, 0x7b, 0xcb, 0x5a, 0x41, 0xed, 0x2c, 0x7b, 0xad, 0x78, 0xb2, 0xf3, 0x63, + 0x7a, 0x93, 0x8a, 0x34, 0xc0, 0x5b, 0x83, 0x37, 0x13, 0x13, 0x92, 0xb6, 0x67, 0x46, 0x51, 0x6f, + 0x65, 0xc0, 0xf7, 0x90, 0xa4, 0x8d, 0x38, 0x47, 0x09, 0x85, 0xd1, 0xbe, 0x4d, 0x71, 0xc0, 0x75, + 0xf3, 0xeb, 0xeb, 0x4e, 0x1f, 0x15, 0x1a, 0xff, 0xdc, 0x6a, 0x65, 0xf5, 0x4f, 0x37, 0xb7, 0x54, + 0x4f, 0x8c, 0xde, 0x86, 0x92, 0xb1, 0x28, 0xda, 0x81, 0x22, 0x96, 0x6e, 0xfd, 0xf5, 0x08, 0xed, + 0x84, 0x8d, 0x6e, 0x73, 0x59, 0xa6, 0xcf, 0xbd, 0x11, 0x2b, 0xcc, 0x83, 0x5f, 0xc1, 0x17, 0xca, + 0xd3, 0x2c, 0x40, 0x03, 0xb9, 0x7b, 0xf9, 0x6c, 0xac, 0x1d, 0x26, 0x29, 0xf7, 0x96, 0x0e, 0x15, + 0x1c, 0x18, 0x89, 0x51, 0x29, 0x43, 0x44, 0x38, 0x33, 0x16, 0x08, 0xd1, 0xeb, 0x8b, 0x43, 0xb4, + 0x99, 0x0d, 0xbf, 0xf9, 0x96, 0x0b, 0x1a, 0x64, 0x23, 0xcd, 0x77, 0x50, 0xc4, 0xc2, 0xd7, 0x9e, + 0x1b, 0xa5, 0xc1, 0xd3, 0x83, 0x20, 0xd5, 0x3b, 0x73, 0xdf, 0xbd, 0x5d, 0xfb, 0x74, 0x52, 0x65, + 0x2a, 0xb5, 0x41, 0x41, 0x26, 0x33, 0xed, 0x7e, 0xa1, 0x21, 0x9f, 0x6e, 0x15, 0x72, 0x9e, 0x8d, + 0x3a, 0xc2, 0x35, 0x8f, 0xbb, 0xc5, 0x2b, 0xf5, 0x55, 0xdf, 0x74, 0x86, 0xe3, 0x26, 0xcb, 0x61, + 0xdc, 0x1e, 0xd5, 0x4d, 0xc7, 0xeb, 0xeb, 0x8b, 0xbb, 0xd5, 0x7e, 0x5b, 0x41, 0xee, 0xf7, 0x3a, + 0xc2, 0x38, 0xf2, 0xdd, 0x43, 0xbe, 0x5b, 0xa0, 0x85, 0x8c, 0x85, 0x27, 0xab, 0x2d, 0x3f, 0x5e, + 0x47, 0xe6, 0xe8, 0x92, 0xb7, 0x74, 0x18, 0x56, 0xec, 0x25, 0x16, 0x50, 0xa1, 0x68, 0x23, 0xf0, + 0xc5, 0x76, 0x33, 0x0a, 0xf0, 0x7e, 0x25, 0x53, 0xbe, 0x4a, 0xd8, 0xdd, 0xfc, 0x71, 0xdf, 0x33, + 0xc4, 0xfd, 0x89, 0x69, 0x33, 0x08, 0xa7, 0xfa, 0xe6, 0xff, 0x87, 0xbd, 0xf7, 0xfb, 0x49, 0x9c, + 0x5d, 0x1f, 0x7e, 0xff, 0x99, 0xe5, 0x4c, 0xd0, 0xa5, 0x26, 0xcf, 0x2c, 0x34, 0xe8, 0x83, 0x73, + 0x2c, 0x3c, 0x40, 0x02, 0x16, 0x02, 0x58, 0x3c, 0x19, 0x24, 0x82, 0x40, 0x02, 0x02, 0x01, 0xc4, + 0xf9, 0x1f, 0xd4, 0x42, 0x14, 0xc1, 0x13, 0x91, 0x40, 0x2d, 0x24, 0x60, 0x21, 0x80, 0xc5, 0x63, + 0x71, 0x80, 0x44, 0x69, 0x1b, 0xa8, 0x85, 0x13, 0x81, 0x00, 0x02, 0x89, 0x58, 0x08, 0x32, 0xce, + 0x7a, 0x67, 0x7d, 0xdf, 0x64, 0xef, 0xfd, 0xee, 0x79, 0x26, 0x7b, 0x9f, 0xec, 0xef, 0xc1, 0xbb, + 0xfd, 0x1c, 0x10, 0x4d, 0xa8, 0x2d, 0x9f, 0xde, 0xbd, 0x7f, 0xc8, 0x75, 0xdd, 0x17, 0xed, 0x8f, + 0xa4, 0x6f, 0x23, 0x28, 0x1e, 0xce, 0x39, 0x8e, 0x0f, 0x51, 0x1e, 0xf9, 0xf0, 0xfc, 0x23, 0x80, + 0xe6, 0x54, 0x54, 0x6a, 0x69, 0x1d, 0xda, 0xa3, 0x53, 0xe8, 0x66, 0xdd, 0x19, 0xdf, 0x7d, 0xac, + 0x26, 0x73, 0xd2, 0xe7, 0x61, 0x2b, 0x26, 0xd1, 0x1e, 0x89, 0x66, 0xb2, 0xe2, 0x40, 0xc4, 0xe1, + 0x1d, 0xb9, 0x93, 0xf8, 0xbd, 0xa9, 0x5a, 0x68, 0xdb, 0x0e, 0x5a, 0x4b, 0x82, 0x0a, 0xac, 0xc9, + 0x52, 0xe9, 0x13, 0x2c, 0x37, 0x38, 0xb9, 0xaf, 0x39, 0x04, 0x27, 0xee, 0x8c, 0x7c, 0x1c, 0x95, + 0x9c, 0xb2, 0x59, 0x71, 0x99, 0x4f, 0x73, 0x77, 0x95, 0x6e, 0x8e, 0xcb, 0x6e, 0x65, 0x53, 0xad, + 0x5c, 0x1f, 0xb6, 0x74, 0xc4, 0xd3, 0x23, 0x1a, 0xb0, 0xaf, 0xfb, 0x28, 0x07, 0xd9, 0x0b, 0x58, + 0xec, 0xfc, 0xdd, 0x7e, 0xb8, 0x2a, 0x03, 0x27, 0x57, 0xf5, 0x65, 0x85, 0x7a, 0x27, 0x63, 0x0d, + 0x2b, 0xb9, 0xea, 0x1c, 0x40, 0x85, 0xd0, 0x4f, 0x2a, 0x97, 0x9f, 0x8c, 0xbd, 0x3c, 0x94, 0xc2, + 0x66, 0x5d, 0x9b, 0xb8, 0x96, 0x59, 0xb1, 0x6c, 0x8f, 0x4a, 0xb8, 0xe8, 0x09, 0x92, 0xd3, 0xb9, + 0x1b, 0xd5, 0x5e, 0x2c, 0x43, 0xcd, 0x65, 0x11, 0x0e, 0x29, 0xf5, 0xe9, 0xae, 0xea, 0xf0, 0x50, + 0x36, 0xdb, 0x0d, 0x5f, 0xc3, 0xa7, 0x02, 0xd4, 0x17, 0xcc, 0x96, 0x05, 0x0e, 0x78, 0xae, 0x68, + 0xd8, 0x4b, 0x7e, 0xcc, 0x9b, 0x3a, 0xd5, 0xab, 0x8c, 0xb4, 0x6d, 0x43, 0x5b, 0x0b, 0x0a, 0x68, + 0xb1, 0x5b, 0xc6, 0x4b, 0xd5, 0x76, 0xd5, 0xdd, 0xd1, 0xf5, 0x26, 0x7d, 0x5b, 0x1b, 0xd3, 0x6a, + 0x35, 0x60, 0x67, 0xd1, 0xa7, 0x07, 0x3e, 0x58, 0x89, 0x51, 0x15, 0xcf, 0xee, 0xf5, 0x50, 0x39, + 0x82, 0xd6, 0xbb, 0x29, 0x67, 0xe4, 0xcc, 0xab, 0x09, 0x03, 0x83, 0xe0, 0x52, 0x2f, 0xff, 0x53, + 0xfc, 0xe4, 0xa0, 0x86, 0x0e, 0x7b, 0x17, 0xf5, 0x7f, 0x24, 0x62, 0x12, 0xe3, 0xe1, 0xf9, 0x0f, + 0x26, 0xf9, 0x6b, 0xde, 0x33, 0x2e, 0xff, 0x5b, 0xd3, 0x38, 0x34, 0x1f, 0xfb, 0x86, 0x3d, 0x30, + 0xd9, 0xde, 0x43, 0xbb, 0x09, 0xb8, 0xd6, 0xcf, 0x92, 0x19, 0x69, 0x73, 0xa5, 0x11, 0xdf, 0xd7, + 0x35, 0xa3, 0xd5, 0x4b, 0x06, 0xe3, 0x19, 0x0e, 0x6c, 0x5b, 0x2b, 0x29, 0xde, 0xc4, 0x80, 0x9b, + 0xd0, 0xc1, 0x53, 0xe3, 0xed, 0xf6, 0x10, 0x12, 0x08, 0xdc, 0xb6, 0x2f, 0x5d, 0xab, 0x53, 0x67, + 0xbf, 0x76, 0x60, 0x1b, 0xce, 0x4c, 0xb5, 0x08, 0xcd, 0xdb, 0x44, 0xdb, 0x51, 0x88, 0x2d, 0x6c, + 0x33, 0xba, 0xe6, 0xd2, 0x65, 0x73, 0xaf, 0x13, 0x1a, 0x9e, 0x6a, 0x6c, 0xd6, 0x4c, 0xf2, 0x33, + 0xc7, 0xe8, 0x0c, 0xc2, 0x1c, 0x5e, 0x4c, 0xe6, 0x15, 0x88, 0xda, 0x1a, 0x6d, 0x4d, 0xe0, 0x47, + 0xd4, 0xf3, 0x98, 0x1e, 0x0f, 0x4d, 0x5b, 0xcc, 0x4e, 0x2c, 0x97, 0xd7, 0x6d, 0xa8, 0x17, 0xd3, + 0xdd, 0x51, 0x29, 0x25, 0xc5, 0xc3, 0xfd, 0x25, 0x47, 0x3b, 0xb3, 0xc4, 0x84, 0xfd, 0x51, 0x76, + 0x1f, 0x14, 0x88, 0x43, 0xb7, 0x11, 0x77, 0x83, 0x66, 0xe8, 0x61, 0x90, 0x4d, 0x2b, 0x4f, 0x86, + 0x34, 0x29, 0x3a, 0x00, 0x8c, 0x72, 0x43, 0xdf, 0x74, 0x42, 0xb4, 0x4a, 0xa7, 0x1c, 0xf6, 0x4a, + 0x16, 0x75, 0x4f, 0x5c, 0x30, 0xb6, 0x86, 0x4f, 0xee, 0xd4, 0xbd, 0x6e, 0x9c, 0xf2, 0xfa, 0xcb, + 0x08, 0x5d, 0x5b, 0x44, 0x04, 0xba, 0x20, 0xb8, 0x59, 0xbd, 0x8a, 0xba, 0x68, 0x6e, 0xef, 0x3c, + 0x4d, 0xc9, 0x0b, 0xd5, 0x17, 0x14, 0xf5, 0x24, 0x3c, 0x53, 0xca, 0xfb, 0xb7, 0x47, 0xa2, 0xd7, + 0xed, 0x64, 0x8a, 0x72, 0x4a, 0xf1, 0xe3, 0x66, 0x65, 0xe4, 0x68, 0xea, 0xed, 0x07, 0xdb, 0xcd, + 0xa8, 0x8c, 0x8a, 0x9f, 0x24, 0x81, 0x44, 0xfb, 0x22, 0xbf, 0xe5, 0x91, 0x71, 0xba, 0x02, 0x19, + 0xf0, 0x67, 0x38, 0xd9, 0x73, 0x56, 0x6e, 0x2d, 0xbb, 0xb5, 0x4e, 0xef, 0x16, 0x45, 0x9b, 0xbd, + 0xd4, 0x5f, 0x83, 0x6a, 0x50, 0xa2, 0xc8, 0x28, 0x32, 0x2a, 0x55, 0xff, 0xa8, 0x68, 0xdd, 0x6d, + 0x36, 0xa7, 0xf3, 0xda, 0xcc, 0xaf, 0xbb, 0x26, 0xe0, 0xe0, 0x6f, 0xda, 0x34, 0x60, 0x07, 0xd4, + 0xa4, 0xc8, 0x3e, 0x02, 0xd0, 0x25, 0x30, 0xee, 0xf1, 0x63, 0x0b, 0x16, 0xb5, 0x3a, 0x60, 0xc9, + 0xef, 0x53, 0x72, 0x21, 0xb5, 0xff, 0x42, 0x29, 0x5c, 0x35, 0xce, 0xad, 0x01, 0xc4, 0x37, 0x14, + 0xe6, 0xaa, 0x59, 0x35, 0xb6, 0xe8, 0xef, 0xbb, 0xfa, 0x31, 0x69, 0x18, 0x4f, 0x91, 0x79, 0x3a, + 0x33, 0xe1, 0x47, 0x91, 0x13, 0x32, 0x21, 0x48, 0xb2, 0xb7, 0x44, 0xb1, 0xe8, 0x55, 0x77, 0x0f, + 0x83, 0x48, 0xc6, 0xe1, 0x4d, 0xbf, 0x09, 0xe8, 0x8b, 0x4e, 0x63, 0x68, 0xae, 0x94, 0xaa, 0x37, + 0xce, 0x41, 0xd4, 0x17, 0x7a, 0xde, 0x1d, 0x8e, 0x5a, 0x3f, 0x8c, 0x92, 0xb3, 0xba, 0xe9, 0x70, + 0x44, 0xf7, 0xe9, 0x81, 0x39, 0xc5, 0x76, 0xe5, 0xde, 0x9a, 0x40, 0xaa, 0x30, 0x89, 0xce, 0xa7, + 0x13, 0x03, 0x78, 0x76, 0x5e, 0x8c, 0x47, 0xb5, 0x42, 0xe9, 0x46, 0x83, 0x61, 0xa8, 0x53, 0xed, + 0x50, 0xf5, 0x82, 0x78, 0x6f, 0xc2, 0x91, 0xd7, 0xb1, 0x72, 0xd6, 0xa8, 0x33, 0x2e, 0x73, 0xfe, + 0xa2, 0xc9, 0xca, 0xfd, 0xbd, 0xe9, 0xfb, 0xb0, 0x77, 0x75, 0x55, 0x9b, 0x4b, 0xb4, 0x29, 0x7b, + 0x05, 0x7b, 0xc0, 0x52, 0x76, 0x03, 0x6e, 0xf6, 0xa0, 0xad, 0x4a, 0x0c, 0x6f, 0x89, 0xfa, 0x07, + 0xbb, 0xcd, 0xd4, 0xfa, 0x80, 0x53, 0x10, 0xf4, 0xf4, 0x4e, 0x9e, 0xec, 0xc0, 0xb8, 0x35, 0x34, + 0x69, 0x21, 0xc8, 0xa1, 0x97, 0x0e, 0xfc, 0x64, 0x64, 0x40, 0xaf, 0xe7, 0x6d, 0x96, 0x37, 0x7a, + 0xa6, 0x58, 0xf0, 0x1f, 0xe3, 0xd1, 0x9a, 0x4d, 0xd6, 0x20, 0xaa, 0x9e, 0xa5, 0x3a, 0xb7, 0xa2, + 0x6e, 0x02, 0xd9, 0x6b, 0x2d, 0x22, 0x5f, 0x31, 0x5b, 0xab, 0x75, 0xdc, 0x83, 0xc9, 0x57, 0x85, + 0x74, 0x52, 0x3b, 0x8e, 0x98, 0x3c, 0xff, 0x6c, 0xf3, 0x06, 0xf1, 0xbd, 0x9c, 0x64, 0x70, 0xd8, + 0xe8, 0xa5, 0xf0, 0x78, 0x3a, 0x35, 0xee, 0xaf, 0x9f, 0xe5, 0x4d, 0x5e, 0x45, 0x87, 0xfa, 0xe4, + 0x91, 0x36, 0xe5, 0x2a, 0xa8, 0xfe, 0x37, 0x35, 0x28, 0xa7, 0x7e, 0x63, 0x1a, 0x2e, 0x22, 0x91, + 0xab, 0xfa, 0x8c, 0x7f, 0xad, 0x05, 0x83, 0x39, 0x4a, 0xbd, 0x99, 0xbb, 0xbc, 0x9f, 0x4b, 0x66, + 0xef, 0xe0, 0x0e, 0x00, 0xe7, 0xdf, 0x16, 0x2d, 0x03, 0xea, 0x3b, 0x9e, 0x88, 0x03, 0x8f, 0x04, + 0x8d, 0x67, 0x9a, 0x5a, 0x3c, 0x6b, 0x94, 0xb4, 0xac, 0xf4, 0xf3, 0x04, 0x8c, 0x88, 0x3c, 0xc1, + 0xe3, 0x42, 0x15, 0x71, 0x75, 0x86, 0x7b, 0x51, 0x40, 0x3a, 0x5a, 0xfa, 0xd9, 0xd0, 0x6c, 0x5a, + 0x9e, 0x17, 0x0a, 0x1b, 0x14, 0x48, 0xea, 0x76, 0xa6, 0xd7, 0xe1, 0xd8, 0xf6, 0x6c, 0x58, 0xc7, + 0x5e, 0x96, 0x99, 0x4a, 0x29, 0xf8, 0x6b, 0xbc, 0xf3, 0xc1, 0xd2, 0xf1, 0x36, 0xae, 0xf7, 0xb4, + 0x2f, 0x78, 0x93, 0x23, 0xec, 0xea, 0xfa, 0x99, 0x82, 0xb6, 0xaf, 0x5e, 0x61, 0xcc, 0xde, 0x6a, + 0x8a, 0x69, 0xda, 0x16, 0x68, 0x28, 0x2e, 0x2b, 0x2b, 0xfd, 0xc1, 0x99, 0xa5, 0x48, 0xe5, 0xcd, + 0xe8, 0xe4, 0x74, 0xc1, 0x30, 0x43, 0xc0, 0x70, 0x48, 0xb6, 0x97, 0x9e, 0xa0, 0x0e, 0xcc, 0x87, + 0xf6, 0xf2, 0x26, 0xa3, 0x06, 0x57, 0x23, 0x6e, 0x2d, 0x5a, 0xdb, 0xdb, 0x79, 0xeb, 0x65, 0xee, + 0x0a, 0x98, 0x5c, 0xa7, 0x7b, 0x7a, 0x7c, 0x20, 0x94, 0xde, 0x86, 0x3f, 0x19, 0x7b, 0xf8, 0x4e, + 0x01, 0x36, 0xbf, 0xe9, 0xb1, 0x32, 0xa6, 0x77, 0xbe, 0xf7, 0xe0, 0xea, 0xdd, 0x49, 0x62, 0xdc, + 0xd6, 0x96, 0x31, 0x45, 0x3a, 0x00, 0x2a, 0x57, 0x0a, 0xe0, 0x74, 0x31, 0xc6, 0x0f, 0x1c, 0x2d, + 0xba, 0x4a, 0x1e, 0x55, 0x60, 0x32, 0xdc, 0x0d, 0x28, 0x18, 0xdf, 0x9b, 0xa5, 0x65, 0xb9, 0x1a, + 0x26, 0x82, 0x8e, 0xb8, 0xf7, 0x0a, 0x9e, 0xf6, 0x04, 0x9a, 0x14, 0xe7, 0x96, 0x44, 0x3f, 0x0c, + 0x9d, 0xce, 0x6e, 0xd5, 0xe8, 0x71, 0x2d, 0xf7, 0x8a, 0xe9, 0xfd, 0xd6, 0x9c, 0xc5, 0x6c, 0xdb, + 0x2d, 0xd3, 0x59, 0x13, 0x24, 0xfd, 0xb1, 0xdf, 0x1b, 0x95, 0x69, 0xff, 0xbd, 0x7d, 0x85, 0xa6, + 0xce, 0xff, 0x6d, 0x5b, 0x80, 0xb5, 0xbf, 0xd6, 0xcc, 0x61, 0xab, 0x7f, 0x63, 0x1a, 0xe9, 0x39, + 0x54, 0xd4, 0x74, 0x21, 0xb6, 0x4d, 0x85, 0x7b, 0x69, 0x43, 0x29, 0x34, 0xc7, 0x13, 0x3f, 0xc0, + 0x73, 0x39, 0x13, 0x3d, 0x23, 0x44, 0x5c, 0x1b, 0xce, 0x90, 0x4f, 0x07, 0xcc, 0xa1, 0x30, 0xe0, + 0x20, 0xc2, 0xa0, 0x4e, 0xfa, 0x9f, 0x92, 0xd1, 0x69, 0x02, 0x01, 0x3a, 0x8a, 0xd0, 0xff, 0x99, + 0x01, 0x2d, 0xdc, 0x47, 0xdb, 0xff, 0xf9, 0x35, 0x88, 0x55, 0x24, 0xa5, 0x3a, 0x28, 0xda, 0x87, + 0x00, 0x05, 0x4f, 0x02, 0x41, 0x79, 0xd9, 0xfa, 0x21, 0x2a, 0x10, 0x11, 0x67, 0xa4, 0x03, 0xe4, + 0x45, 0x15, 0xf5, 0xee, 0x8b, 0x67, 0x8a, 0x2b, 0x90, 0x94, 0xd0, 0x7c, 0xdf, 0xf9, 0x25, 0x30, + 0x6b, 0xd8, 0x77, 0x1f, 0x59, 0x4d, 0xc7, 0xe7, 0xa1, 0xa0, 0xf3, 0x1e, 0xd1, 0xfe, 0xcf, 0x3f, + 0xaa, 0x03, 0x99, 0x59, 0xb6, 0x04, 0x00, 0xaa, 0x1d, 0x83, 0x12, 0x02, 0xe4, 0x32, 0xf1, 0x76, + 0xc0, 0x0e, 0x28, 0x2f, 0x21, 0xb9, 0xfc, 0x29, 0xce, 0x9a, 0x05, 0x68, 0xb2, 0x09, 0x2c, 0x3b, + 0x4a, 0x65, 0x96, 0x58, 0xc2, 0xe8, 0x00, 0xee, 0xda, 0x21, 0xca, 0x11, 0xa8, 0xbe, 0x04, 0xf2, + 0x86, 0x75, 0x37, 0x23, 0x30, 0x28, 0xc9, 0x8f, 0x9f, 0x61, 0xa5, 0x87, 0xc5, 0x4e, 0x28, 0x99, + 0x2d, 0xc4, 0xfe, 0xf3, 0xf6, 0x0b, 0xb4, 0x08, 0x4a, 0x73, 0x44, 0x32, 0x55, 0x93, 0xcd, 0x15, + 0xe3, 0xf5, 0x54, 0x01, 0xae, 0xa4, 0x6e, 0xe4, 0x80, 0x34, 0x35, 0x65, 0x3b, 0x58, 0x2f, 0x05, + 0x79, 0x66, 0x77, 0x4b, 0xc5, 0xaf, 0xe0, 0x01, 0xcc, 0xec, 0x85, 0x38, 0x85, 0x7b, 0x9f, 0xa7, + 0xbf, 0xda, 0x53, 0x04, 0xba, 0xce, 0xaa, 0x7f, 0x32, 0xc3, 0xad, 0x7c, 0x95, 0xf4, 0x70, 0xc3, + 0x7a, 0x33, 0xca, 0x21, 0x68, 0xfd, 0x3f, 0x7b, 0xb9, 0xbb, 0xb5, 0x6e, 0x35, 0x76, 0xbc, 0x83, + 0xe7, 0xe5, 0x00, 0xde, 0x9a, 0x31, 0x24, 0xa8, 0x0f, 0x21, 0x41, 0xcc, 0xc7, 0xfe, 0x35, 0xc6, + 0x7f, 0xeb, 0x37, 0xa6, 0x73, 0x44, 0xbc, 0xff, 0x67, 0x7b, 0x7c, 0x00, 0xb1, 0x31, 0xd6, 0xe9, + 0xce, 0x13, 0xf5, 0x49, 0x35, 0xf2, 0x07, 0x10, 0xc4, 0xc8, 0xea, 0x61, 0x55, 0xc4, 0xe6, 0xb0, + 0xf8, 0x0f, 0xab, 0xdd, 0x99, 0xa2, 0x77, 0x1b, 0xa7, 0xc3, 0x5f, 0x8e, 0x7a, 0x46, 0xfd, 0x84, + 0xa5, 0x23, 0x92, 0xda, 0xfa, 0x2a, 0x2e, 0x5d, 0xf3, 0x95, 0x0b, 0x58, 0x32, 0xdd, 0x62, 0x19, + 0xbd, 0x7d, 0x3e, 0xbe, 0x47, 0x11, 0xaf, 0xaa, 0x9c, 0xb8, 0x52, 0xe9, 0x75, 0x2e, 0x27, 0x68, + 0x59, 0x3c, 0x7c, 0x6a, 0x95, 0x21, 0x40, 0x6f, 0x5f, 0xa0, 0x83, 0xa1, 0x76, 0xfb, 0x65, 0x14, + 0x9d, 0x52, 0xe1, 0xb5, 0xa9, 0xfa, 0x3c, 0x19, 0x29, 0x17, 0x15, 0x05, 0x93, 0xb7, 0x4a, 0x14, + 0x6c, 0xff, 0x18, 0xe3, 0x6e, 0x9a, 0x93, 0x42, 0x84, 0xf4, 0xd3, 0x30, 0x62, 0xcb, 0x5c, 0xa4, + 0x0d, 0x9e, 0x53, 0x2e, 0xa2, 0x7d, 0xaa, 0x40, 0x68, 0xb8, 0xd7, 0xad, 0xb1, 0x95, 0xde, 0xee, + 0x5c, 0x4d, 0xea, 0x0a, 0x12, 0x0c, 0x46, 0x04, 0x61, 0x0b, 0x37, 0x11, 0xff, 0xd8, 0xb3, 0xee, + 0x27, 0x5a, 0xc9, 0xc4, 0xb7, 0x87, 0x66, 0xa5, 0xfc, 0xd7, 0x24, 0x3a, 0xd7, 0xeb, 0x67, 0xd8, + 0x65, 0x3d, 0x22, 0x6b, 0x84, 0x26, 0x77, 0x5a, 0x02, 0x8d, 0xc1, 0x58, 0x23, 0x32, 0x39, 0x86, + 0x6a, 0x5a, 0x51, 0x1b, 0x70, 0xd2, 0x9f, 0xfa, 0x92, 0xcd, 0xeb, 0xac, 0xff, 0x2c, 0x54, 0xd8, + 0x02, 0x94, 0xdd, 0x2c, 0x92, 0x7d, 0x38, 0xe9, 0x51, 0x14, 0x73, 0xca, 0x29, 0xea, 0x5f, 0x53, + 0xaf, 0x05, 0x9b, 0xc3, 0x73, 0xbb, 0x78, 0xfc, 0x25, 0x30, 0xa7, 0x3a, 0x26, 0xb9, 0x81, 0xf8, + 0x03, 0x74, 0x9c, 0xca, 0xae, 0x11, 0xe1, 0x1e, 0xf1, 0x72, 0xaf, 0x6f, 0x47, 0x22, 0x57, 0xe3, + 0x44, 0x1c, 0xbd, 0xa7, 0x8a, 0x76, 0xbd, 0x8e, 0x13, 0x10, 0xa8, 0x9e, 0x71, 0x51, 0x26, 0x1d, + 0xc3, 0xe7, 0x54, 0xcf, 0xa8, 0x3c, 0xf4, 0x7c, 0x31, 0xfc, 0x3e, 0x92, 0x59, 0xf6, 0xeb, 0xbf, + 0xe6, 0xad, 0xe8, 0x7f, 0x63, 0xba, 0x68, 0xe9, 0x59, 0x40, 0x6a, 0xfa, 0xe4, 0xad, 0x9b, 0xb3, + 0xc7, 0x9b, 0x7d, 0x85, 0x8d, 0x57, 0x7f, 0x24, 0xac, 0x0a, 0x2f, 0x14, 0xb5, 0xf1, 0xfa, 0x65, + 0xca, 0xb0, 0x7d, 0xff, 0x75, 0x61, 0x1c, 0xdd, 0x40, 0xf5, 0x74, 0xe4, 0xe1, 0x31, 0x2b, 0x5b, + 0x73, 0x87, 0x2c, 0xda, 0xa2, 0x4d, 0xdd, 0xa0, 0xf9, 0x9d, 0x8f, 0x43, 0x83, 0x27, 0x81, 0x51, + 0x3a, 0x67, 0x1d, 0xb5, 0x0a, 0xb0, 0xb3, 0x2b, 0x9c, 0xc5, 0x20, 0xd3, 0xcd, 0x55, 0xba, 0x66, + 0xb3, 0xe5, 0xd1, 0x64, 0xa3, 0xc1, 0x54, 0x8e, 0xdd, 0xc9, 0xf2, 0x45, 0x37, 0x89, 0xea, 0xf0, + 0xa6, 0x66, 0xdc, 0x2e, 0x05, 0x9e, 0x5e, 0x63, 0x43, 0x89, 0x5a, 0xb9, 0x7c, 0xf9, 0x16, 0x54, + 0x73, 0x2d, 0x6b, 0x74, 0x5e, 0x27, 0xd2, 0x78, 0x3e, 0x66, 0xa0, 0xed, 0xba, 0x5c, 0x0b, 0x1f, + 0x46, 0x6e, 0x5e, 0xb1, 0x12, 0xf5, 0x4a, 0x8d, 0x20, 0xb9, 0x8d, 0x12, 0x9a, 0x1d, 0x3d, 0x83, + 0x95, 0xda, 0x2c, 0xf7, 0x45, 0x51, 0x6a, 0x43, 0xd6, 0x23, 0x7d, 0x41, 0x76, 0x5c, 0x33, 0x9b, + 0xb2, 0xe0, 0xf8, 0x72, 0xeb, 0x87, 0xf4, 0x01, 0xce, 0xcf, 0x8e, 0x36, 0xc7, 0x64, 0x26, 0x92, + 0x09, 0x2e, 0x66, 0xc3, 0x12, 0xa5, 0x9c, 0x49, 0xae, 0x63, 0xa0, 0xd8, 0x8f, 0x05, 0xe6, 0xe9, + 0x8d, 0x44, 0x23, 0xf8, 0x69, 0x17, 0x59, 0xd6, 0x91, 0x23, 0x99, 0x06, 0x2f, 0x08, 0x4b, 0x47, + 0x52, 0x3a, 0xd3, 0x5f, 0xe4, 0xef, 0x31, 0xc1, 0xcd, 0xa4, 0xeb, 0xa1, 0x83, 0xc8, 0xe7, 0x64, + 0x00, 0x6b, 0xbe, 0xe0, 0x7a, 0xc3, 0xe6, 0x53, 0xa8, 0x4b, 0x9d, 0xd6, 0x79, 0x49, 0xe7, 0x06, + 0x79, 0x59, 0xcd, 0x06, 0xe2, 0x48, 0x22, 0x35, 0x91, 0xd0, 0x3b, 0x13, 0xc5, 0x9d, 0x96, 0x9e, + 0x25, 0x7a, 0x42, 0x8b, 0x66, 0x03, 0xfb, 0x6b, 0xd0, 0x91, 0x5a, 0xac, 0x23, 0xbd, 0x3e, 0xab, + 0x8a, 0x7e, 0x95, 0x81, 0x0f, 0x68, 0x2f, 0x89, 0xc3, 0xb1, 0xee, 0xa2, 0x7e, 0x78, 0xf2, 0x37, + 0x35, 0xdd, 0xd9, 0xbf, 0x31, 0x9d, 0x52, 0xed, 0xeb, 0xbb, 0xaa, 0xd8, 0x33, 0x72, 0x54, 0x70, + 0xf0, 0x5e, 0xd3, 0xad, 0xfc, 0x3a, 0x74, 0x14, 0x8e, 0x7c, 0x3b, 0x85, 0x57, 0x64, 0x03, 0xa8, + 0xac, 0x37, 0x13, 0xe2, 0x0e, 0xf9, 0x89, 0x26, 0x4f, 0x3f, 0x28, 0xf7, 0xbd, 0x8a, 0x1b, 0x03, + 0xa1, 0xa9, 0x64, 0xf9, 0x16, 0x1f, 0xdc, 0xa3, 0x2f, 0xdc, 0x38, 0x62, 0xad, 0x99, 0xbd, 0x85, + 0x14, 0xaf, 0xbe, 0xd9, 0x02, 0x36, 0xd2, 0x87, 0xb5, 0x98, 0x49, 0xc7, 0xaa, 0xf2, 0x8c, 0x12, + 0xf5, 0x78, 0x6b, 0xa0, 0x2a, 0x2b, 0x7e, 0xdc, 0x21, 0x47, 0x6d, 0xf9, 0x9d, 0xf7, 0xa9, 0x3e, + 0x6b, 0x51, 0xe2, 0xb3, 0xc6, 0xf5, 0x07, 0xbc, 0x97, 0xd0, 0x7b, 0x38, 0x9a, 0xea, 0x1a, 0x75, + 0x18, 0x65, 0xed, 0x57, 0xdf, 0x0c, 0x03, 0x59, 0xc0, 0x92, 0x7e, 0x33, 0xe1, 0x8f, 0x51, 0x6b, + 0xc1, 0x58, 0x62, 0x24, 0x40, 0x93, 0x15, 0x71, 0x94, 0x7c, 0x50, 0x55, 0x7b, 0x1b, 0x40, 0x9b, + 0xc2, 0x78, 0xa2, 0xac, 0x92, 0xa1, 0x6a, 0x7b, 0x65, 0x0c, 0x33, 0x87, 0x94, 0x4d, 0x0c, 0xc9, + 0x16, 0x43, 0x46, 0x65, 0xc8, 0x7a, 0xbb, 0xa1, 0x8c, 0xa0, 0x99, 0x83, 0x7a, 0x68, 0xb9, 0x02, + 0x9f, 0x6e, 0x6d, 0x2d, 0x74, 0xbc, 0xa1, 0x3c, 0x7f, 0xef, 0xf1, 0x82, 0x04, 0xcc, 0x4a, 0x34, + 0x39, 0xa3, 0x70, 0x5f, 0xe4, 0x52, 0x82, 0xd8, 0x9b, 0x13, 0x7d, 0xba, 0x1a, 0x3b, 0x0c, 0x1e, + 0x64, 0xa5, 0x28, 0x15, 0x6b, 0x92, 0x72, 0xd7, 0xf1, 0x59, 0x76, 0x1c, 0x8d, 0x1e, 0x80, 0xf9, + 0x3f, 0xa2, 0xc9, 0x08, 0xc3, 0x73, 0xf7, 0x7f, 0xbe, 0xeb, 0x84, 0x60, 0xe0, 0x2c, 0x11, 0x9d, + 0x9f, 0x1d, 0x57, 0x06, 0x21, 0x63, 0xea, 0x2e, 0x88, 0xca, 0x5f, 0x77, 0x2b, 0x78, 0x42, 0xe8, + 0x55, 0xb4, 0xa4, 0x80, 0x97, 0xa6, 0x2c, 0x4b, 0x99, 0x37, 0xaf, 0x5c, 0xac, 0xdd, 0x7f, 0x93, + 0xcb, 0x24, 0x44, 0x87, 0x87, 0xc6, 0x7c, 0x50, 0x84, 0xbe, 0x67, 0x2e, 0x1a, 0x76, 0xfc, 0xe9, + 0xd7, 0x7e, 0xda, 0x62, 0xf9, 0x8d, 0xe9, 0x99, 0xc5, 0x0d, 0x31, 0xa5, 0x1a, 0x5e, 0x31, 0x6a, + 0x66, 0x4c, 0x6f, 0xd0, 0x84, 0x5c, 0xe1, 0x6e, 0xe6, 0x01, 0x70, 0xe7, 0x8c, 0x4c, 0x02, 0x07, + 0x53, 0x5c, 0x31, 0xf2, 0xec, 0xef, 0xcc, 0xa8, 0xbe, 0xbc, 0x25, 0x85, 0x0a, 0x8d, 0xb4, 0x4e, + 0xa6, 0x6d, 0x60, 0x9d, 0x8c, 0xb9, 0xca, 0x43, 0x2c, 0xde, 0x68, 0x60, 0x8c, 0x05, 0x76, 0x7e, + 0xbe, 0xed, 0x1e, 0x5c, 0xb3, 0x69, 0x18, 0xfe, 0x67, 0x41, 0x3b, 0xda, 0xb9, 0x40, 0x11, 0xe0, + 0x05, 0x57, 0xa6, 0x0e, 0xba, 0xd9, 0x90, 0xe4, 0x36, 0x1e, 0xaa, 0x1a, 0xb4, 0xc8, 0xe7, 0xcf, + 0x84, 0x19, 0x97, 0x47, 0xab, 0xed, 0x9a, 0x9d, 0x79, 0xdd, 0x1d, 0x68, 0x64, 0x45, 0xd4, 0xf2, + 0x8f, 0x49, 0x51, 0x72, 0x96, 0xd2, 0xb0, 0x2e, 0xbb, 0xf4, 0x02, 0x93, 0x1f, 0xd9, 0xd8, 0x8a, + 0x87, 0x61, 0x26, 0x81, 0x10, 0x19, 0xb6, 0xc5, 0xe2, 0x37, 0x1e, 0xa5, 0xe2, 0x4c, 0x05, 0x12, + 0xae, 0x62, 0xc1, 0x70, 0x93, 0x3d, 0xb8, 0xeb, 0xf5, 0xd3, 0x23, 0xe4, 0xb0, 0x5a, 0xdd, 0x6f, + 0xb7, 0x99, 0x8c, 0xd5, 0xa8, 0xea, 0x4b, 0x6c, 0x6a, 0x75, 0xd1, 0xf6, 0x55, 0x31, 0x79, 0x9d, + 0x78, 0x24, 0x2e, 0x8a, 0xe3, 0xcb, 0x38, 0x0b, 0xc0, 0xfd, 0xbd, 0xa1, 0x9f, 0x1a, 0x99, 0x97, + 0x1d, 0xb9, 0xcb, 0x27, 0xa4, 0x72, 0x1f, 0x79, 0x7e, 0x48, 0x94, 0x85, 0x93, 0x0e, 0x87, 0xf7, + 0xad, 0x5e, 0xa6, 0x05, 0x1d, 0xe5, 0x67, 0xb0, 0x5b, 0x81, 0xab, 0xfd, 0xc5, 0x1c, 0x6c, 0x4f, + 0x8f, 0xa4, 0xc0, 0x32, 0x2c, 0x53, 0xd9, 0x2a, 0x54, 0x06, 0x93, 0x12, 0x3d, 0xe7, 0xad, 0x0e, + 0xb1, 0x96, 0xa3, 0x5f, 0x92, 0xe0, 0x70, 0xa4, 0x84, 0xac, 0xb9, 0x64, 0x72, 0xab, 0xc1, 0x88, + 0x02, 0x72, 0xb6, 0x85, 0xef, 0xa8, 0x26, 0x28, 0xaf, 0x81, 0x40, 0x75, 0x99, 0xe6, 0x0a, 0x5c, + 0x55, 0x8e, 0x2e, 0xeb, 0x63, 0x3d, 0xb9, 0x1e, 0xf8, 0xe4, 0x0b, 0x50, 0xcb, 0x19, 0xe5, 0xda, + 0xaf, 0x31, 0xfe, 0x75, 0xfb, 0x6f, 0x4c, 0xcf, 0xf2, 0x45, 0x32, 0x4f, 0x68, 0x55, 0x85, 0x9e, + 0x0f, 0x19, 0x11, 0x50, 0x4d, 0xca, 0xf7, 0x19, 0x56, 0x9e, 0x8b, 0xcb, 0xce, 0xc6, 0xe1, 0x0b, + 0xd4, 0xd3, 0xe2, 0xae, 0xa7, 0x83, 0x41, 0xb1, 0xd8, 0x5f, 0x5f, 0xe2, 0xad, 0x37, 0xb9, 0x23, + 0x93, 0xd7, 0xeb, 0x65, 0x3b, 0xd7, 0xf1, 0xb3, 0x11, 0xee, 0xd4, 0x1d, 0x15, 0x6f, 0xcc, 0xaa, + 0x50, 0x4e, 0x12, 0x8b, 0x75, 0x37, 0x79, 0x82, 0xcc, 0xd6, 0x34, 0x73, 0x72, 0x16, 0x41, 0xa4, + 0x52, 0x20, 0xd9, 0xa9, 0x9e, 0x9c, 0x50, 0x61, 0xd3, 0xb1, 0xbb, 0x3e, 0x67, 0x20, 0xd6, 0x4a, + 0x15, 0x82, 0x22, 0x11, 0x86, 0xe7, 0xa5, 0xdc, 0x01, 0x52, 0xbc, 0x76, 0xd8, 0xa2, 0x32, 0x07, + 0x47, 0xb7, 0xab, 0x7c, 0x4b, 0xf9, 0x66, 0xf6, 0xa1, 0xf9, 0x21, 0x30, 0x5b, 0x15, 0xa3, 0x45, + 0xcb, 0xc9, 0x59, 0x20, 0x24, 0x28, 0xca, 0x02, 0x4a, 0x57, 0x04, 0x5a, 0x6a, 0x6b, 0x61, 0xe8, + 0x61, 0x68, 0x14, 0x8f, 0x6a, 0x76, 0x55, 0xd1, 0x5a, 0xfb, 0x98, 0x8b, 0xa4, 0xa3, 0xa2, 0xaa, + 0x30, 0x52, 0xe6, 0x39, 0x2a, 0x17, 0x67, 0x81, 0xb9, 0xfb, 0xf3, 0xc7, 0xd6, 0x1f, 0x40, 0x20, + 0x80, 0xc9, 0x9f, 0x82, 0x33, 0x2c, 0x6e, 0x5e, 0xf3, 0xd9, 0x19, 0x8b, 0x43, 0x33, 0x73, 0x52, + 0xb3, 0x23, 0x79, 0x3b, 0x4b, 0x34, 0x93, 0x1a, 0xe7, 0xc6, 0xe6, 0xa9, 0x74, 0x28, 0x70, 0x76, + 0x2d, 0xfc, 0x8e, 0x1a, 0x82, 0xc3, 0x11, 0x35, 0x67, 0xd6, 0x79, 0xd2, 0xc4, 0x57, 0xe7, 0xa3, + 0x9a, 0xd0, 0x54, 0x34, 0xea, 0x08, 0xb7, 0x73, 0xfc, 0xd2, 0x63, 0x59, 0xc4, 0x87, 0xf4, 0xb6, + 0x88, 0x61, 0x3b, 0xa4, 0x58, 0xbd, 0xbb, 0x28, 0x4f, 0x57, 0xf2, 0xaf, 0x18, 0x2c, 0xbe, 0x42, + 0xbf, 0xa4, 0x0d, 0x90, 0x6f, 0x66, 0x21, 0xcf, 0x7b, 0x84, 0xe9, 0xfb, 0x98, 0xb5, 0xbb, 0x2a, + 0xb4, 0x59, 0x53, 0x2c, 0x89, 0x02, 0xf9, 0x67, 0xca, 0x7a, 0x12, 0xdf, 0x5a, 0xde, 0xba, 0x93, + 0x1c, 0xcd, 0xf3, 0x4e, 0xee, 0x7f, 0xed, 0xa7, 0x19, 0xe0, 0x37, 0xa6, 0x57, 0xfb, 0x51, 0x8b, + 0xff, 0x55, 0x4f, 0xc4, 0xed, 0x98, 0xe0, 0xf0, 0xd0, 0x8d, 0x0a, 0x72, 0x9b, 0x93, 0x45, 0xe0, + 0x02, 0x9e, 0xff, 0x2c, 0xf3, 0xff, 0x1c, 0xf3, 0x12, 0x71, 0x4b, 0x10, 0x91, 0xf5, 0x5c, 0x86, + 0xdc, 0x58, 0xdf, 0xd4, 0xb1, 0xf1, 0x2a, 0x6a, 0x09, 0x83, 0xc7, 0xd2, 0xa3, 0x54, 0x06, 0x64, + 0x7c, 0x42, 0xc7, 0xd7, 0xcd, 0xd0, 0xa6, 0x2d, 0x07, 0x4f, 0xf5, 0xb2, 0xe9, 0xfd, 0xc7, 0x86, + 0x02, 0x9c, 0xcc, 0xe6, 0x06, 0x6b, 0x1d, 0x3a, 0xcf, 0x1b, 0x49, 0x58, 0xdc, 0x67, 0x37, 0xd2, + 0x40, 0x2d, 0xc7, 0x6b, 0x29, 0xa3, 0x7d, 0x4f, 0x3b, 0xbe, 0x09, 0xb5, 0x4b, 0x6f, 0xab, 0xb2, + 0x87, 0xc3, 0xf3, 0x61, 0x18, 0x39, 0x78, 0x6a, 0x10, 0x17, 0x49, 0x0d, 0x9f, 0x18, 0x78, 0xe6, + 0x98, 0x69, 0x89, 0xfb, 0xa9, 0x93, 0x86, 0x86, 0x3d, 0xec, 0x93, 0x01, 0xc0, 0x2c, 0xf3, 0x08, + 0x32, 0x5d, 0xc8, 0xf9, 0x10, 0xa3, 0x9a, 0xf4, 0xde, 0x57, 0xfb, 0x92, 0xa1, 0x8c, 0xbe, 0x96, + 0xe8, 0x63, 0xb8, 0xa1, 0x28, 0x16, 0xbf, 0xd5, 0x89, 0xed, 0x78, 0x63, 0x64, 0xa1, 0x46, 0x0d, + 0xb4, 0x8f, 0x74, 0x52, 0xf2, 0x67, 0x6f, 0x12, 0x7f, 0x35, 0x8e, 0xce, 0x5b, 0x76, 0x6e, 0x85, + 0x9e, 0x67, 0xab, 0x06, 0x5f, 0x8e, 0x5a, 0x78, 0xd4, 0xd0, 0x5a, 0x64, 0xab, 0x0e, 0xdb, 0xc5, + 0x44, 0x77, 0xa7, 0x25, 0x67, 0xee, 0x88, 0x31, 0xfd, 0x46, 0xa8, 0xea, 0xe5, 0x1c, 0x1a, 0x94, + 0xd6, 0xf9, 0x9e, 0xf3, 0x40, 0x34, 0xae, 0x3a, 0x00, 0x73, 0xd8, 0xb7, 0x28, 0xa7, 0x6f, 0x92, + 0xe9, 0xcf, 0x8a, 0xe1, 0xcb, 0xee, 0x49, 0x74, 0x69, 0x1f, 0xb1, 0xcc, 0x38, 0x92, 0xae, 0x95, + 0x84, 0x08, 0x3b, 0x1f, 0xd5, 0xa7, 0x07, 0x0d, 0x2a, 0x85, 0x3f, 0x9d, 0x50, 0x72, 0x5e, 0xb5, + 0xe3, 0x18, 0xb1, 0x63, 0x23, 0x6c, 0x73, 0x70, 0x51, 0x5b, 0x40, 0x93, 0x7f, 0x05, 0xc0, 0xdb, + 0x8a, 0xd1, 0x51, 0x69, 0xe9, 0x13, 0xca, 0x5f, 0x72, 0xb1, 0x64, 0x81, 0xd0, 0x6f, 0x4c, 0x0b, + 0x60, 0x7c, 0x83, 0xa3, 0xda, 0x2a, 0x7a, 0xcf, 0x7a, 0x92, 0x1e, 0x60, 0xc9, 0x38, 0x2e, 0xdf, + 0x3e, 0x83, 0x86, 0xb0, 0x59, 0x7a, 0x9e, 0xca, 0xbd, 0xc9, 0x1d, 0x96, 0xac, 0xf3, 0xe4, 0x5c, + 0x38, 0xb4, 0xa4, 0xaa, 0xad, 0x88, 0x83, 0x9c, 0x2f, 0xeb, 0x64, 0x32, 0xa5, 0x73, 0x3f, 0xf8, + 0x0f, 0x98, 0x3c, 0x30, 0xfa, 0xf2, 0x6c, 0x9b, 0xb3, 0x81, 0xde, 0x27, 0x9d, 0xdd, 0x64, 0x18, + 0x25, 0x22, 0xaf, 0x04, 0xcc, 0xd0, 0xe7, 0xdd, 0xed, 0xc1, 0x13, 0x1a, 0x2a, 0xa8, 0x3b, 0xe5, + 0xe5, 0x5e, 0x17, 0xb9, 0xb9, 0x39, 0x90, 0xac, 0x04, 0x6c, 0xf7, 0x25, 0xfc, 0x9a, 0x27, 0x0a, + 0xbf, 0x44, 0xa3, 0xf1, 0xb5, 0x31, 0x5d, 0xa5, 0xbe, 0x10, 0x19, 0x13, 0xf4, 0x84, 0x6f, 0xc4, + 0x8f, 0xd5, 0xbe, 0xa9, 0xc5, 0x9e, 0xf2, 0xa4, 0x7b, 0x8b, 0x76, 0x6c, 0x11, 0xa9, 0x74, 0x04, + 0x8d, 0x92, 0xae, 0xc9, 0x3f, 0x6b, 0x5a, 0xdf, 0x64, 0x19, 0x00, 0x8f, 0x37, 0xb4, 0x45, 0x15, + 0xa5, 0x5c, 0x2f, 0xc8, 0x5d, 0xaa, 0x87, 0xa1, 0x10, 0x37, 0x85, 0x9c, 0x2b, 0xd9, 0xaa, 0x6f, + 0x64, 0x5e, 0xf7, 0x42, 0xfd, 0x54, 0x05, 0xd9, 0xad, 0xb9, 0x0c, 0x67, 0x8c, 0xa8, 0x7c, 0x8b, + 0x18, 0x6a, 0x9f, 0xf0, 0x58, 0x25, 0x30, 0x52, 0x24, 0x65, 0xcd, 0xa4, 0xd6, 0x84, 0x11, 0xbd, + 0xf0, 0xc0, 0x50, 0x00, 0xd0, 0xda, 0x21, 0xb9, 0x55, 0x0b, 0x84, 0x28, 0xf8, 0xb2, 0xcf, 0xb9, + 0x5d, 0xe9, 0xdc, 0x43, 0x6c, 0x9d, 0xb2, 0xef, 0x49, 0x4c, 0x64, 0xc1, 0x72, 0xe1, 0xae, 0x13, + 0x7e, 0xc9, 0xd3, 0x91, 0xa0, 0xe1, 0x06, 0xdf, 0xc5, 0x17, 0x19, 0x44, 0xdb, 0x68, 0x2e, 0x12, + 0x7e, 0xf8, 0x30, 0x30, 0x6f, 0xdb, 0x58, 0xa9, 0xfe, 0x00, 0x36, 0x02, 0x15, 0xa4, 0x40, 0x2e, + 0xdc, 0x80, 0x60, 0x0d, 0x1e, 0xcf, 0xb7, 0x8d, 0x4a, 0x6e, 0x4e, 0x07, 0xc8, 0x83, 0x40, 0xd7, + 0x4c, 0x81, 0x78, 0xc1, 0xd4, 0x1d, 0xbe, 0x31, 0x07, 0xbf, 0xfc, 0x87, 0x49, 0x86, 0x22, 0xbf, + 0x31, 0xbd, 0xb4, 0x2a, 0x05, 0x00, 0x3b, 0xbf, 0xea, 0x83, 0x40, 0x87, 0xbb, 0x5f, 0x5e, 0x95, + 0xac, 0x93, 0x8d, 0x90, 0x53, 0x52, 0x0b, 0x4c, 0x49, 0x24, 0xb6, 0x48, 0x34, 0x24, 0xdb, 0x46, + 0xb9, 0x22, 0xe5, 0x23, 0x7e, 0xde, 0xed, 0x0d, 0x53, 0x39, 0xab, 0xd6, 0x68, 0x9f, 0x12, 0x4b, + 0xd6, 0xd0, 0x96, 0x68, 0x3d, 0xec, 0xa6, 0xc0, 0x03, 0xfa, 0x88, 0x2b, 0xc2, 0xea, 0xce, 0x0d, + 0x89, 0xa5, 0xe2, 0x03, 0x66, 0xb3, 0xf5, 0x74, 0xd3, 0xd0, 0x05, 0xa0, 0x1b, 0x61, 0x14, 0x0d, + 0x97, 0x15, 0x9d, 0xae, 0x6e, 0xe6, 0x0f, 0x2f, 0xbe, 0x3e, 0x89, 0x3c, 0x93, 0x5c, 0x0d, 0xf6, + 0x17, 0xf1, 0x66, 0x68, 0x59, 0x3d, 0x73, 0xd8, 0xd2, 0x57, 0x05, 0xae, 0x04, 0xbf, 0x2a, 0xa0, + 0x6b, 0xd6, 0xe1, 0x0b, 0xaa, 0x56, 0xb9, 0x1a, 0xc1, 0xd7, 0x9f, 0x57, 0x01, 0x6d, 0x89, 0x7e, + 0xce, 0xb6, 0x05, 0xab, 0x28, 0xa4, 0x96, 0x8b, 0x7a, 0xdb, 0x99, 0x71, 0xcc, 0xb7, 0x8e, 0x87, + 0x7b, 0xfc, 0x3e, 0xb9, 0x42, 0xf4, 0x25, 0x88, 0x45, 0x29, 0x21, 0xa1, 0x82, 0x0a, 0xab, 0x1c, + 0xe6, 0xb9, 0x05, 0xf2, 0xb2, 0x0c, 0x94, 0xc8, 0xd4, 0x07, 0xeb, 0x45, 0xdd, 0xc7, 0x5e, 0x64, + 0xe8, 0xc7, 0x40, 0x76, 0x7b, 0x88, 0xe7, 0xe3, 0x44, 0x80, 0x25, 0xd2, 0x22, 0xcf, 0x49, 0x8b, + 0xcc, 0xd9, 0x0d, 0x2d, 0x08, 0x9e, 0xde, 0x1a, 0xa9, 0xaa, 0x1e, 0x48, 0xcd, 0x24, 0x2e, 0x4f, + 0x26, 0x29, 0x55, 0xcc, 0x99, 0x02, 0xe6, 0x00, 0xfd, 0x39, 0x5a, 0x01, 0xdc, 0x3f, 0x6a, 0x59, + 0xaa, 0xc2, 0xdc, 0xf2, 0x09, 0x50, 0x97, 0xd1, 0x39, 0x24, 0x5d, 0x7b, 0xe5, 0x05, 0x42, 0x67, + 0x5b, 0x85, 0xb7, 0xf2, 0xa6, 0xee, 0x6a, 0xb4, 0x5d, 0x2c, 0x2b, 0x20, 0x1f, 0x32, 0x8d, 0x6b, + 0x02, 0xce, 0xbc, 0x63, 0x1b, 0xb7, 0x80, 0xb2, 0x8c, 0xef, 0x73, 0x2c, 0xae, 0x91, 0xcf, 0xdd, + 0x56, 0xea, 0x7f, 0x06, 0xe1, 0x67, 0x5f, 0x46, 0x7b, 0x6b, 0xbc, 0xfc, 0xb5, 0x06, 0x25, 0x74, + 0xf3, 0x1b, 0xd3, 0xdc, 0x9b, 0xbe, 0x46, 0x07, 0x22, 0x1b, 0x26, 0x14, 0xd0, 0x5a, 0x8c, 0x2e, + 0x6e, 0x41, 0xa6, 0xb8, 0xa0, 0xf1, 0x9a, 0xb8, 0x6e, 0x8c, 0x92, 0xb6, 0x9d, 0xea, 0x08, 0x7a, + 0x2d, 0x2f, 0xe7, 0x05, 0x2e, 0x77, 0x5f, 0xae, 0x1b, 0x18, 0xd0, 0xd1, 0x50, 0x31, 0x72, 0x22, + 0xbb, 0x17, 0xed, 0x54, 0x16, 0x14, 0x1f, 0xd9, 0xcd, 0xd9, 0x57, 0x72, 0x3c, 0x77, 0x50, 0x27, + 0xa5, 0x5a, 0xef, 0xf0, 0x54, 0x56, 0xdd, 0x79, 0xa1, 0x6e, 0x79, 0x45, 0xb0, 0x35, 0xb2, 0xc2, + 0x98, 0x8c, 0xfb, 0xa3, 0xb8, 0xe1, 0x94, 0xb7, 0xbf, 0x3a, 0x29, 0x79, 0xdf, 0xe2, 0x3e, 0x8a, + 0x18, 0xf1, 0xcb, 0x1f, 0xaf, 0xfd, 0x84, 0xbf, 0xb5, 0x90, 0x2d, 0x74, 0xc9, 0x88, 0x39, 0xb6, + 0x56, 0x82, 0x63, 0x51, 0xa4, 0x6f, 0x24, 0x2c, 0x30, 0x6c, 0xd1, 0xee, 0x97, 0xca, 0xf5, 0xb8, + 0xff, 0xb8, 0xa6, 0x8d, 0x32, 0x2f, 0xd5, 0x46, 0xe7, 0x8a, 0x52, 0x8f, 0x5d, 0xbd, 0xa0, 0xf6, + 0x9a, 0xea, 0xc4, 0x97, 0x98, 0x59, 0x20, 0x7e, 0x54, 0x21, 0x99, 0xda, 0x3f, 0x2a, 0x38, 0xff, + 0xd9, 0x37, 0x2a, 0xe7, 0x37, 0xf4, 0xaa, 0xe8, 0xe9, 0x85, 0xbf, 0x63, 0xf3, 0x9d, 0xd7, 0xcf, + 0xcd, 0x27, 0x01, 0x79, 0xa5, 0x25, 0x98, 0xb4, 0xdb, 0x04, 0xb6, 0xe1, 0x9b, 0x5f, 0x68, 0xd3, + 0x4a, 0xd2, 0x84, 0x3a, 0x7a, 0x48, 0xdc, 0x16, 0xc0, 0xc6, 0x29, 0xcb, 0xa6, 0x6f, 0x03, 0x73, + 0x43, 0x5b, 0xbc, 0x9f, 0x0d, 0xaa, 0xb6, 0x6a, 0xc3, 0xa4, 0xd0, 0xd2, 0x88, 0xdc, 0x99, 0xd8, + 0x53, 0xa3, 0xcc, 0x23, 0x8d, 0x6c, 0x77, 0xb4, 0xdd, 0xbb, 0xdb, 0x20, 0xa7, 0x2f, 0x56, 0x6d, + 0x70, 0xd9, 0xec, 0x1e, 0xdd, 0x26, 0xe7, 0x23, 0xb6, 0xc4, 0x70, 0xd8, 0x36, 0x3c, 0x75, 0x75, + 0xca, 0xc7, 0xe6, 0x38, 0x7b, 0xd1, 0x5c, 0x9c, 0x45, 0x6e, 0x77, 0xf0, 0xa2, 0x56, 0xda, 0x64, + 0x45, 0x4d, 0x2a, 0x4d, 0x7d, 0x09, 0xcc, 0x9d, 0xa6, 0x6e, 0xb6, 0x4c, 0x9b, 0xbf, 0xf6, 0x1e, + 0x50, 0xfe, 0x37, 0xa6, 0xe5, 0x83, 0xf5, 0xd3, 0x23, 0xde, 0xe4, 0xf6, 0x0d, 0xcf, 0x66, 0x63, + 0xd1, 0xab, 0xa0, 0xca, 0xb9, 0xe3, 0x6e, 0x1b, 0x14, 0x9b, 0x49, 0x3d, 0x5a, 0x39, 0x2e, 0xab, + 0x53, 0x03, 0x30, 0x93, 0x49, 0xe5, 0x6b, 0xa9, 0x59, 0xae, 0x0d, 0x5c, 0x8e, 0xf2, 0x0b, 0x6f, + 0x4d, 0xfe, 0x6d, 0x51, 0xbd, 0x5b, 0xe3, 0x02, 0x46, 0x75, 0xc8, 0x81, 0x81, 0xaa, 0xc0, 0x74, + 0x42, 0x37, 0xfd, 0xfa, 0xb6, 0x61, 0xf8, 0xf1, 0xfa, 0x1c, 0x7b, 0x23, 0x6e, 0x6d, 0x26, 0xcd, + 0x54, 0x98, 0xce, 0x5d, 0xe0, 0x05, 0x17, 0x74, 0x5e, 0x65, 0x32, 0xc4, 0xe3, 0x4f, 0xbf, 0x0f, + 0x95, 0xc3, 0x61, 0x15, 0x8d, 0x30, 0x88, 0xc3, 0xf9, 0x42, 0x05, 0xef, 0xbf, 0xf9, 0x1a, 0x23, + 0xd3, 0x55, 0x17, 0x68, 0x58, 0xe2, 0xd6, 0x50, 0x8d, 0x27, 0xae, 0xb7, 0x72, 0xd1, 0x9a, 0xc6, + 0x96, 0xcd, 0x9f, 0x30, 0x65, 0x22, 0x4e, 0xc5, 0x6a, 0x5b, 0xce, 0x03, 0x8f, 0x2a, 0xfb, 0x4a, + 0xf9, 0x42, 0x1a, 0x82, 0xef, 0xe9, 0x70, 0x24, 0xb4, 0xff, 0x64, 0x4c, 0x79, 0x32, 0x75, 0xb6, + 0xbc, 0x6f, 0x53, 0x6e, 0x38, 0x9c, 0xdd, 0x93, 0xfa, 0xec, 0x6e, 0x50, 0x4b, 0x2d, 0x16, 0x23, + 0x41, 0xe7, 0xc2, 0xf1, 0x79, 0xb6, 0xbb, 0xf8, 0xf4, 0xb6, 0x32, 0x81, 0x5d, 0x23, 0x37, 0xc3, + 0xee, 0xf5, 0x9b, 0x13, 0x6e, 0xb6, 0xfb, 0x79, 0x8e, 0x87, 0x0e, 0x14, 0xad, 0x71, 0xd1, 0x0f, + 0xbd, 0xaa, 0x3a, 0x1b, 0xe0, 0x8a, 0x2c, 0xd1, 0x05, 0x15, 0xb2, 0xec, 0xc5, 0x38, 0xf4, 0xbc, + 0x76, 0x7a, 0x6a, 0x9b, 0xb1, 0x5c, 0x24, 0x2d, 0x99, 0xb8, 0x6d, 0x4a, 0x00, 0xde, 0x3d, 0x1d, + 0xf1, 0x4d, 0xc9, 0xd3, 0x48, 0xde, 0x4a, 0xf8, 0xf4, 0x79, 0x9e, 0x0c, 0x76, 0x34, 0xb0, 0xdb, + 0xed, 0x71, 0x9a, 0x58, 0x1b, 0x79, 0xab, 0x7b, 0x1d, 0xdd, 0x42, 0x27, 0x89, 0x67, 0x66, 0x99, + 0xb0, 0x47, 0x3a, 0x1c, 0xa1, 0x89, 0x4d, 0xac, 0xc9, 0xc3, 0xba, 0xb3, 0x22, 0xa3, 0xb0, 0xfd, + 0x6b, 0xef, 0x51, 0x4f, 0xfd, 0xc6, 0x34, 0x98, 0x17, 0x4e, 0x32, 0x33, 0xe9, 0x6f, 0x75, 0x3c, + 0xdf, 0x11, 0xc2, 0x3d, 0x74, 0xa6, 0xa7, 0x99, 0xcd, 0xff, 0xf0, 0xc4, 0xaa, 0x23, 0xe0, 0xc0, + 0xc0, 0x18, 0x86, 0x1e, 0x27, 0xad, 0x48, 0xe4, 0x5c, 0x7d, 0xcd, 0x27, 0xc1, 0x6b, 0xa3, 0xb0, + 0xfa, 0x97, 0x3b, 0x00, 0xf2, 0x0f, 0x64, 0x2b, 0x44, 0xde, 0xb1, 0xf9, 0xbd, 0x69, 0xb1, 0x90, + 0x64, 0x0f, 0x20, 0x77, 0x4e, 0xb0, 0xe7, 0xec, 0x86, 0x32, 0x51, 0xc4, 0x4e, 0xc2, 0x04, 0xb9, + 0x67, 0xd9, 0xe2, 0x5a, 0x5f, 0x90, 0x52, 0xbd, 0xe3, 0x09, 0x2e, 0x8c, 0xa6, 0xa5, 0x6b, 0xa4, + 0xe1, 0xee, 0xc0, 0xf8, 0x75, 0x91, 0xb3, 0x53, 0xf2, 0x2a, 0xe1, 0x38, 0xc3, 0xca, 0x6a, 0x0f, + 0x46, 0x4a, 0xf6, 0x8f, 0x8c, 0xd8, 0xbb, 0xe9, 0x74, 0xab, 0x46, 0x0b, 0xb2, 0x8b, 0x67, 0xfc, + 0xc6, 0x7a, 0xba, 0x0b, 0xd5, 0xf2, 0x87, 0x74, 0xea, 0xd6, 0x8a, 0x8d, 0x32, 0x4b, 0xa2, 0x3c, + 0xcd, 0x59, 0x76, 0xf1, 0x88, 0x5e, 0x3f, 0x0a, 0x3c, 0xd1, 0x55, 0x80, 0x97, 0xd4, 0xf7, 0x8b, + 0xde, 0x4a, 0x90, 0x6e, 0x39, 0x9c, 0x41, 0x8e, 0x0a, 0xf2, 0xad, 0xb4, 0x27, 0xb9, 0x7a, 0x69, + 0x64, 0x4d, 0xaa, 0xb7, 0x5a, 0xaa, 0xec, 0x7f, 0x56, 0x03, 0x90, 0xac, 0x94, 0x4a, 0xad, 0xd5, + 0x5b, 0x91, 0x81, 0xd6, 0xf9, 0xd0, 0x10, 0x9a, 0x33, 0xd5, 0x4a, 0x5e, 0x19, 0x0b, 0xe7, 0xda, + 0x23, 0x5b, 0x9a, 0x8a, 0x00, 0x9b, 0xf5, 0xcf, 0x31, 0x6d, 0x17, 0xbf, 0x36, 0xde, 0x6d, 0x13, + 0x48, 0x2f, 0xe7, 0x5a, 0xe8, 0x98, 0x7b, 0x13, 0xd7, 0xaa, 0x52, 0x0a, 0x68, 0x84, 0x32, 0x71, + 0xff, 0xe1, 0x46, 0x17, 0xb9, 0xf0, 0x44, 0xff, 0x20, 0x2a, 0xb5, 0x15, 0x70, 0xfd, 0xea, 0x81, + 0x30, 0x18, 0x6a, 0x5c, 0x38, 0xfe, 0x84, 0xe8, 0x14, 0x15, 0x95, 0xe2, 0x72, 0x7c, 0x97, 0x95, + 0x44, 0x68, 0xa1, 0x94, 0xfc, 0xb3, 0x9e, 0x44, 0xdc, 0x9d, 0x8c, 0x39, 0x3d, 0xf8, 0x92, 0xf8, + 0x51, 0x34, 0xfe, 0x37, 0xee, 0x6e, 0x03, 0x04, 0x58, 0xbf, 0xb9, 0x87, 0x53, 0x88, 0x0f, 0x36, + 0xaa, 0xee, 0x1f, 0xf0, 0xf9, 0xcd, 0xb7, 0x8e, 0x4e, 0x51, 0xef, 0xda, 0xce, 0x3b, 0xf9, 0xb7, + 0x9c, 0x7e, 0x99, 0x2e, 0x47, 0x64, 0xc7, 0x19, 0x49, 0x2d, 0x02, 0x3b, 0xba, 0x27, 0x6f, 0xb6, + 0xf2, 0x4c, 0x5c, 0x4f, 0xa7, 0x26, 0x89, 0xee, 0x4a, 0x55, 0x79, 0x6c, 0x9b, 0x67, 0x0f, 0x60, + 0x6f, 0x53, 0xc5, 0x93, 0x65, 0x94, 0xaf, 0xf4, 0x2d, 0x5e, 0x93, 0x71, 0x6f, 0xa1, 0x2d, 0x43, + 0x64, 0xf4, 0x05, 0x62, 0x13, 0x57, 0xc1, 0xa7, 0x60, 0x18, 0x7b, 0xeb, 0xd2, 0xaf, 0x89, 0x2e, + 0x3a, 0x1b, 0x8a, 0x19, 0x3b, 0xbc, 0xc8, 0xc9, 0x55, 0xcd, 0x01, 0xef, 0x59, 0x96, 0x49, 0x23, + 0xb2, 0x76, 0xa4, 0x1a, 0xaf, 0x27, 0x7a, 0x79, 0xc6, 0x96, 0xac, 0x20, 0x0c, 0xd3, 0x59, 0x41, + 0xff, 0x78, 0xea, 0xfe, 0x73, 0x28, 0x13, 0x20, 0x21, 0x92, 0x38, 0x96, 0x05, 0x57, 0x18, 0x8b, + 0xb9, 0x55, 0x67, 0xa7, 0x21, 0xdd, 0xb5, 0x62, 0x8f, 0x0c, 0x2e, 0xbd, 0x79, 0x4b, 0xd5, 0x96, + 0x22, 0x13, 0xf1, 0xe7, 0xdb, 0x80, 0x35, 0x24, 0xc3, 0xaf, 0x75, 0x6c, 0x51, 0xd5, 0xe9, 0x82, + 0xf8, 0xf2, 0x6f, 0xd8, 0x67, 0xe9, 0x6a, 0xed, 0xf2, 0x8d, 0x4e, 0x65, 0x3b, 0xd0, 0xb9, 0x19, + 0xd3, 0x3f, 0xde, 0x72, 0x4a, 0x64, 0x73, 0xeb, 0xe7, 0xd8, 0xe8, 0x6d, 0x3f, 0x83, 0x7d, 0x7d, + 0x6a, 0x0c, 0x9c, 0x3f, 0x75, 0xec, 0x6e, 0x54, 0xc6, 0x4a, 0x39, 0x07, 0x7f, 0xe6, 0x4d, 0xd7, + 0x52, 0x8c, 0x10, 0x75, 0xac, 0x93, 0x2d, 0x59, 0x1a, 0xf5, 0x4c, 0xac, 0x46, 0xcc, 0x10, 0x79, + 0x75, 0x6b, 0xab, 0x23, 0xb1, 0xf3, 0xad, 0xfc, 0x6a, 0xcf, 0xbf, 0x52, 0xa2, 0xb8, 0x28, 0x5a, + 0x93, 0x59, 0xb7, 0x3d, 0x97, 0x89, 0x6e, 0xa4, 0xce, 0xb9, 0x75, 0x15, 0x11, 0xb2, 0x98, 0xd6, + 0xfa, 0xfb, 0x96, 0x16, 0x78, 0xf6, 0x00, 0x3b, 0x62, 0x7d, 0xdd, 0x94, 0x31, 0x6b, 0xdb, 0x4b, + 0xc9, 0x41, 0x08, 0xbc, 0xdd, 0x7a, 0x8a, 0xfc, 0x9a, 0x61, 0x8e, 0xce, 0xfe, 0xc6, 0xb4, 0x46, + 0x79, 0xe8, 0x9b, 0x45, 0x51, 0xfe, 0xb1, 0x2f, 0x94, 0xd7, 0x1e, 0x7b, 0x57, 0xc3, 0x25, 0xb7, + 0x3f, 0x34, 0xa7, 0x73, 0xbc, 0x54, 0x56, 0x75, 0x07, 0x9a, 0x65, 0x31, 0xd4, 0xf5, 0xa4, 0xf2, + 0x6d, 0x73, 0x79, 0x4a, 0xe0, 0x80, 0xd4, 0xc2, 0x96, 0xf8, 0xe5, 0x2c, 0x14, 0xd2, 0x86, 0xe1, + 0x2d, 0x89, 0xc2, 0x79, 0xc2, 0xe4, 0xc4, 0x4f, 0x87, 0xf0, 0xb4, 0x36, 0xe1, 0x9d, 0xc9, 0x79, + 0x4b, 0xe8, 0xc7, 0x74, 0x71, 0xf3, 0x2c, 0xd4, 0xd2, 0xee, 0xc3, 0x33, 0xab, 0xc7, 0xe9, 0xc0, + 0x79, 0x48, 0xb6, 0x1e, 0x9a, 0xc9, 0x14, 0xd7, 0xbd, 0xd3, 0xed, 0xe3, 0x18, 0xd4, 0xd6, 0x69, + 0x33, 0xe9, 0xa4, 0x09, 0x6e, 0x92, 0xf3, 0x62, 0xe9, 0xc6, 0x15, 0x26, 0x4a, 0x60, 0xda, 0x21, + 0xcf, 0xd1, 0x68, 0xe6, 0xf8, 0xb6, 0xd8, 0x65, 0x11, 0xdc, 0x9f, 0xec, 0xf4, 0x45, 0x12, 0x54, + 0xfd, 0x59, 0x08, 0x9c, 0x20, 0x9b, 0xa8, 0x48, 0x3a, 0x0c, 0xb8, 0xda, 0x89, 0xe0, 0xc7, 0x70, + 0x61, 0xad, 0x8e, 0x8a, 0xc1, 0x7a, 0x2a, 0xc0, 0x53, 0x84, 0x03, 0x1f, 0xc3, 0x0a, 0xfd, 0x51, + 0x88, 0xbb, 0x16, 0xab, 0xeb, 0xc2, 0x7f, 0x1d, 0xa2, 0x1c, 0xa9, 0x44, 0x1a, 0x98, 0x92, 0xee, + 0xe1, 0xbd, 0x70, 0x8e, 0xd8, 0xf1, 0xf0, 0x52, 0xe1, 0x1d, 0x7a, 0x49, 0x62, 0x7e, 0x09, 0xf2, + 0x44, 0xd2, 0x33, 0x0f, 0x4d, 0xad, 0x9f, 0x7e, 0x41, 0xf9, 0xed, 0xfd, 0xff, 0x54, 0x87, 0x2f, + 0x8d, 0x66, 0x65, 0xed, 0xcb, 0xc0, 0x66, 0x5b, 0x4a, 0x40, 0x16, 0x01, 0x20, 0x4b, 0x1a, 0x72, + 0xd2, 0x06, 0x0a, 0xf0, 0xef, 0xd6, 0xae, 0x86, 0x29, 0x69, 0x09, 0x07, 0x74, 0xf1, 0x7d, 0x48, + 0x0f, 0xf0, 0xcf, 0xc2, 0x5d, 0xa5, 0x6f, 0x50, 0x97, 0xe6, 0x24, 0x87, 0x38, 0x57, 0x22, 0x5b, + 0xab, 0x09, 0xf8, 0x00, 0x0e, 0xd8, 0x05, 0x92, 0x63, 0x34, 0x25, 0x07, 0xa0, 0x34, 0xa9, 0xc2, + 0x0f, 0x71, 0x76, 0xce, 0x7c, 0xe2, 0xc7, 0x44, 0x17, 0xcc, 0xaf, 0x33, 0x75, 0x68, 0xf5, 0x37, + 0xa6, 0xb5, 0x2a, 0x2c, 0x8d, 0x81, 0x79, 0x91, 0xb5, 0x71, 0xae, 0x1c, 0xca, 0xae, 0x97, 0x61, + 0xad, 0xc6, 0x05, 0x12, 0x4a, 0x53, 0xa4, 0xd7, 0xb9, 0xa8, 0xb7, 0xda, 0xd9, 0x9a, 0x39, 0xcb, + 0xcc, 0x0f, 0x25, 0xde, 0x0a, 0x11, 0xab, 0x3b, 0x68, 0xdc, 0x05, 0x53, 0x9c, 0x81, 0x0e, 0x24, + 0xb7, 0xec, 0xe9, 0xee, 0x43, 0x19, 0x2f, 0x35, 0x77, 0x51, 0xce, 0xc8, 0x55, 0x4a, 0x25, 0xbf, + 0x51, 0xe7, 0xcd, 0x4f, 0x1e, 0xbd, 0x6e, 0xe3, 0x3e, 0xef, 0xa4, 0xc3, 0xe0, 0x05, 0x73, 0x99, + 0x12, 0x7b, 0x24, 0xb2, 0xd1, 0xaa, 0x3b, 0x6e, 0xcf, 0xaa, 0xbc, 0x81, 0x53, 0xe7, 0x8a, 0x57, + 0xc9, 0x9e, 0x32, 0xe0, 0x4f, 0x58, 0xc0, 0x69, 0xdd, 0x78, 0xa8, 0x9b, 0x25, 0x00, 0xc5, 0x0e, + 0x47, 0xc4, 0xa1, 0x49, 0x36, 0x96, 0xf6, 0x8d, 0xe4, 0x69, 0xcd, 0x74, 0x8d, 0xbc, 0x53, 0x79, + 0xab, 0xb6, 0xe3, 0x09, 0x67, 0xe5, 0x47, 0x47, 0x63, 0xc5, 0xb9, 0xde, 0x46, 0x2a, 0xa8, 0x03, + 0x8e, 0xbb, 0x43, 0x53, 0x31, 0xe9, 0x35, 0x98, 0x0b, 0x6f, 0x6b, 0xbd, 0x9b, 0x67, 0xcd, 0x9f, + 0x5d, 0x09, 0x73, 0x58, 0x6d, 0xca, 0xf7, 0x71, 0x99, 0x65, 0xf9, 0xa2, 0x57, 0xd7, 0x53, 0xd9, + 0xa8, 0xee, 0xc3, 0xbd, 0xff, 0xfc, 0x1c, 0xe5, 0x1c, 0xf8, 0xc0, 0xd6, 0xdc, 0xf0, 0x22, 0xd9, + 0x1a, 0x8f, 0x8c, 0x3a, 0x05, 0xc8, 0x77, 0x96, 0xeb, 0x78, 0xb8, 0xc3, 0x2d, 0x8b, 0xc8, 0xcd, + 0x94, 0xc3, 0xf8, 0xad, 0x09, 0x0b, 0x6c, 0x06, 0x67, 0xaf, 0x0e, 0x50, 0xf7, 0x65, 0xbd, 0x2d, + 0xf6, 0x86, 0x2d, 0x91, 0x17, 0xd1, 0x8e, 0x8d, 0x65, 0x49, 0xae, 0x8f, 0x39, 0xa3, 0x68, 0x54, + 0x43, 0xdc, 0x6f, 0x8f, 0xab, 0xcf, 0xf1, 0xfe, 0x49, 0x4b, 0xbc, 0x5b, 0xb7, 0x14, 0x9e, 0x8d, + 0x9a, 0x23, 0xea, 0x46, 0x6a, 0x3e, 0x6a, 0x8a, 0x00, 0xfc, 0x08, 0xc3, 0x9f, 0xdc, 0xc7, 0x34, + 0xb7, 0xa8, 0x76, 0x51, 0x56, 0xef, 0x61, 0x76, 0xb4, 0xec, 0xea, 0x41, 0xef, 0xf9, 0xc1, 0xef, + 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, + 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, + 0xce, 0x3b, 0xff, 0x7b, 0xf2, 0x9f, 0xef, 0x83, 0xd3, 0xb9, 0xe2, 0xba, 0x57, 0xd1, 0xb0, 0x79, + 0x8d, 0xd5, 0xcc, 0x4d, 0xb6, 0x39, 0x9d, 0xc9, 0x0f, 0xad, 0x6d, 0xcc, 0x24, 0x0a, 0xc8, 0xec, + 0x76, 0x31, 0x25, 0xdb, 0x9c, 0x38, 0xd4, 0xe5, 0x42, 0x39, 0x3f, 0x42, 0x16, 0xe8, 0xf5, 0x7a, + 0x17, 0xc8, 0x1e, 0xf6, 0x0d, 0xe9, 0x7b, 0xdb, 0x05, 0x9c, 0xa7, 0xee, 0x95, 0xdd, 0xce, 0xd2, + 0xd5, 0x63, 0x40, 0xea, 0xea, 0x2a, 0xd9, 0x4d, 0x53, 0x41, 0xe6, 0x66, 0x68, 0xaa, 0x99, 0xa1, + 0xf8, 0xf7, 0xeb, 0xb8, 0x63, 0x35, 0x71, 0x7f, 0x1e, 0x58, 0xcc, 0xab, 0x33, 0x34, 0xeb, 0x01, + 0xeb, 0x4d, 0x38, 0x6d, 0x2f, 0x59, 0xa1, 0x0b, 0x6f, 0x4e, 0x0d, 0x2d, 0x92, 0x04, 0xb8, 0x65, + 0x95, 0xfa, 0x21, 0x9f, 0xc0, 0x54, 0x7f, 0x13, 0x3b, 0x8a, 0xc8, 0xff, 0x3e, 0xbf, 0x90, 0xf3, + 0x1c, 0x8d, 0x0c, 0x29, 0xbc, 0x10, 0x5d, 0x94, 0xe1, 0x50, 0x60, 0xbb, 0x9b, 0x1b, 0x5a, 0x27, + 0xb5, 0x90, 0x05, 0x39, 0xa9, 0x0f, 0x77, 0xae, 0x68, 0x8d, 0x29, 0x9e, 0xb8, 0x0a, 0x9a, 0x63, + 0x62, 0xf7, 0x35, 0x26, 0xec, 0x70, 0x9c, 0xb0, 0x74, 0x34, 0x43, 0xe6, 0x2f, 0x23, 0x4f, 0xd1, + 0x94, 0x27, 0x1e, 0x58, 0xb5, 0x4a, 0xf5, 0xd0, 0x67, 0x98, 0xd6, 0xd0, 0x37, 0xe1, 0x88, 0xf5, + 0x7a, 0xd1, 0x82, 0x37, 0xe0, 0x71, 0x79, 0xc3, 0x7b, 0x81, 0x0f, 0x9c, 0x86, 0x9a, 0x1d, 0x7f, + 0x56, 0x73, 0x2b, 0x0a, 0x7f, 0xbf, 0x36, 0xcf, 0xba, 0x35, 0xda, 0x22, 0x58, 0x2f, 0x3d, 0x16, + 0x54, 0xaf, 0x37, 0x7c, 0xf9, 0xbe, 0xe1, 0xb5, 0x92, 0x9f, 0xfe, 0xaa, 0xe1, 0xcc, 0x47, 0x78, + 0x9d, 0xcc, 0x94, 0xf6, 0x5b, 0xdd, 0x42, 0x09, 0x84, 0xfe, 0x74, 0x2e, 0xf7, 0xd5, 0xb3, 0xac, + 0x1f, 0xc5, 0x47, 0x20, 0xaf, 0x72, 0x75, 0xd7, 0xcb, 0xc9, 0x90, 0x52, 0x8d, 0x63, 0xd3, 0x53, + 0x8b, 0x34, 0xbd, 0x73, 0xde, 0x68, 0x7d, 0x3a, 0xbc, 0x9a, 0xa8, 0xc6, 0x1b, 0x51, 0x7b, 0xa4, + 0x88, 0x8c, 0xa6, 0x61, 0x49, 0x47, 0x79, 0x24, 0x12, 0xf9, 0xe3, 0x29, 0x83, 0x49, 0x5a, 0xef, + 0x8d, 0x63, 0xfb, 0x17, 0xde, 0x48, 0x9e, 0x8c, 0x6b, 0x74, 0xdc, 0x08, 0x83, 0xd4, 0xa5, 0xd1, + 0xd3, 0xe4, 0x79, 0x8f, 0x6f, 0x22, 0x7b, 0xda, 0xdc, 0x64, 0x91, 0x74, 0x0e, 0x87, 0x8d, 0x86, + 0xde, 0x8d, 0x9e, 0xe1, 0xc0, 0xdd, 0x86, 0xa1, 0x29, 0xa2, 0x82, 0xac, 0xac, 0x35, 0x7d, 0x7a, + 0x1e, 0x36, 0x82, 0xfb, 0x50, 0xf6, 0x16, 0xdd, 0xf7, 0x32, 0x5a, 0xdf, 0xc0, 0x08, 0xb2, 0x7c, + 0x4e, 0x84, 0xad, 0xdb, 0x27, 0x5d, 0x1c, 0xfe, 0x00, 0x76, 0x6a, 0xa6, 0xf7, 0x65, 0xb6, 0x31, + 0x4c, 0xa9, 0x8f, 0xfa, 0x22, 0x6f, 0x50, 0x9d, 0xcb, 0x64, 0x6c, 0x7f, 0x86, 0x87, 0xfd, 0x20, + 0x25, 0x23, 0xa3, 0xa6, 0x93, 0x57, 0xb1, 0x37, 0x82, 0xff, 0x1a, 0x67, 0x77, 0xf3, 0x1b, 0xd3, + 0x5c, 0xbb, 0x25, 0x72, 0xea, 0xe4, 0x5f, 0x45, 0xbf, 0xca, 0x4d, 0xe0, 0x65, 0xbb, 0x29, 0xd0, + 0x63, 0x6a, 0xb9, 0x63, 0xfd, 0x32, 0x25, 0x54, 0x11, 0x4f, 0xa3, 0x69, 0x1e, 0x78, 0x52, 0x9b, + 0x97, 0x55, 0x21, 0x15, 0x35, 0x1b, 0x79, 0xea, 0xcf, 0xb3, 0xda, 0xbb, 0x2d, 0x3d, 0xe6, 0xeb, + 0xcc, 0x64, 0x89, 0x67, 0x3d, 0x54, 0x06, 0xe8, 0x0c, 0x2d, 0xd2, 0x23, 0x1b, 0x5f, 0xb7, 0x8a, + 0x55, 0x49, 0x89, 0xbe, 0x29, 0xd8, 0xec, 0xbd, 0xca, 0xc8, 0x98, 0x46, 0xc3, 0x48, 0xf3, 0x5f, + 0x13, 0xce, 0x43, 0x9d, 0x9c, 0xa4, 0xb7, 0x19, 0x2e, 0xc5, 0x36, 0x63, 0x87, 0x34, 0x19, 0x83, + 0x4f, 0x82, 0x9c, 0x88, 0x72, 0x87, 0xe4, 0xec, 0xc6, 0x51, 0x60, 0x8b, 0x00, 0x80, 0xd4, 0x88, + 0xbf, 0xed, 0xbb, 0xde, 0x72, 0xd5, 0xd5, 0x15, 0x3c, 0x7e, 0x1a, 0x62, 0x5b, 0x12, 0x9a, 0x50, + 0x17, 0x03, 0x6d, 0xba, 0x64, 0x46, 0x07, 0x26, 0x9d, 0x46, 0xbf, 0xad, 0x6f, 0x89, 0x54, 0xaa, + 0x4d, 0x36, 0x88, 0x18, 0x95, 0xf9, 0xad, 0xe2, 0x55, 0x53, 0x68, 0x2b, 0x26, 0x83, 0x5a, 0x5a, + 0x06, 0x95, 0x47, 0xb3, 0x42, 0x8d, 0x73, 0xf1, 0x36, 0xd2, 0x9f, 0x43, 0x64, 0x92, 0xf6, 0xa9, + 0x33, 0xb3, 0xdf, 0x2d, 0x87, 0xcb, 0x43, 0x0d, 0x2d, 0xe7, 0x6f, 0x5c, 0x04, 0xe6, 0xad, 0xfb, + 0xd2, 0x12, 0xf9, 0xf3, 0x34, 0x60, 0xe1, 0xad, 0x62, 0x4e, 0xe6, 0xcc, 0xe8, 0x6b, 0xf8, 0x46, + 0x85, 0xfb, 0x34, 0xcc, 0x42, 0xa7, 0xfd, 0xbd, 0x53, 0xd6, 0x9d, 0xea, 0x9d, 0xa1, 0x03, 0x3f, + 0xf6, 0x59, 0xb5, 0xe7, 0xda, 0x00, 0x9f, 0x93, 0x7a, 0x88, 0x04, 0x0b, 0x2e, 0x8d, 0x7e, 0xaf, + 0x3b, 0x5a, 0xec, 0x2e, 0xc2, 0x12, 0xac, 0x57, 0xc1, 0x26, 0x72, 0x21, 0x39, 0x18, 0xc1, 0xcb, + 0xf6, 0xf8, 0xa4, 0xa3, 0x28, 0x7a, 0xbc, 0xe1, 0xa6, 0xbe, 0xe8, 0xd3, 0xc8, 0x5c, 0x31, 0x92, + 0xcd, 0x27, 0xaf, 0x50, 0x55, 0x04, 0x50, 0x50, 0xbf, 0x56, 0xfb, 0x84, 0xf2, 0xbf, 0x31, 0x2d, + 0x47, 0x0c, 0x2e, 0x90, 0x83, 0x65, 0xac, 0x4f, 0x75, 0x97, 0xfb, 0x7b, 0x07, 0x8d, 0x76, 0x1b, + 0x17, 0xa3, 0x6a, 0x07, 0x40, 0x15, 0xbd, 0xdc, 0xdb, 0x76, 0x6b, 0x9c, 0xb0, 0x25, 0x83, 0xdc, + 0xea, 0x36, 0xc2, 0x47, 0x7a, 0x7a, 0x76, 0x38, 0x7d, 0x89, 0x54, 0x83, 0x28, 0x76, 0x3c, 0xc6, + 0xec, 0x8c, 0x27, 0x5c, 0x57, 0xad, 0x43, 0x90, 0x4a, 0x7c, 0x02, 0xbb, 0x1b, 0x0e, 0xc2, 0x42, + 0x4e, 0xf0, 0xb8, 0xff, 0x1a, 0xc4, 0x5c, 0x27, 0x5e, 0x85, 0xa2, 0xaa, 0x2b, 0x2b, 0x2a, 0xb7, + 0x35, 0xaa, 0x5e, 0x3e, 0x79, 0x4c, 0x4a, 0x75, 0x0a, 0x17, 0x1e, 0x06, 0xbf, 0xd5, 0xd5, 0xd8, + 0x4d, 0x56, 0xe6, 0xd4, 0xc9, 0x8e, 0x3d, 0x09, 0x54, 0x44, 0xa8, 0x17, 0x8b, 0x0b, 0xb0, 0xb2, + 0x54, 0x50, 0xe8, 0x06, 0x1f, 0x19, 0xeb, 0x05, 0xae, 0x9f, 0x6c, 0xe5, 0x8c, 0x0b, 0x63, 0xe6, + 0x2a, 0xfc, 0xca, 0x2c, 0x9f, 0xc6, 0x59, 0x74, 0x35, 0xf2, 0x9d, 0x0c, 0xea, 0xf3, 0xb6, 0x95, + 0x3a, 0xb2, 0x96, 0x3c, 0x8b, 0xd0, 0xbd, 0x8c, 0x62, 0xc2, 0xc2, 0x5d, 0x17, 0xb0, 0x72, 0xaf, + 0xf6, 0x71, 0x48, 0x33, 0x4a, 0x78, 0xfa, 0x79, 0x3f, 0xca, 0xe6, 0xf4, 0x4f, 0x31, 0xb9, 0xc1, + 0xa9, 0x9f, 0x2c, 0xb7, 0x66, 0x07, 0x24, 0x48, 0x2a, 0xf5, 0x5f, 0x8e, 0xa9, 0x70, 0xf5, 0xe1, + 0xa5, 0x16, 0xfb, 0xab, 0xc6, 0x65, 0xb0, 0x98, 0x72, 0x25, 0x90, 0x19, 0x2a, 0xd5, 0xe4, 0x92, + 0xb9, 0x4f, 0x14, 0x86, 0xb6, 0x68, 0x63, 0x18, 0x17, 0xbf, 0xf9, 0xca, 0xd2, 0xce, 0xda, 0xa4, + 0x72, 0x5b, 0x8d, 0x7e, 0xb6, 0x25, 0x98, 0x06, 0xa2, 0x34, 0x40, 0x83, 0xbd, 0x5e, 0xb1, 0x3d, + 0xa8, 0x4e, 0x08, 0xfe, 0x55, 0x5d, 0x10, 0x5f, 0xaf, 0xe9, 0x73, 0x99, 0xc2, 0x6e, 0xba, 0x9e, + 0xf5, 0x31, 0x49, 0x76, 0xb5, 0x2b, 0x4b, 0xf5, 0x5d, 0x3a, 0x7d, 0x3a, 0x42, 0x12, 0x92, 0x80, + 0x14, 0xb7, 0xd8, 0xb6, 0x54, 0xaf, 0xae, 0xd3, 0x5f, 0x72, 0x66, 0x65, 0x40, 0xea, 0x37, 0xa6, + 0x55, 0x96, 0x4e, 0x37, 0x23, 0xbd, 0x3f, 0xa9, 0x29, 0x92, 0xa2, 0xaf, 0x27, 0xc9, 0x25, 0xab, + 0xf7, 0xaa, 0xae, 0x8f, 0x24, 0xe3, 0x5b, 0xe5, 0x30, 0x31, 0x48, 0x5f, 0xb3, 0xa2, 0x91, 0xa0, + 0x48, 0x2e, 0x3b, 0xaf, 0xad, 0xf0, 0x94, 0x23, 0x3b, 0x6a, 0x17, 0x76, 0x89, 0x82, 0x63, 0xb7, + 0x86, 0xe7, 0xb0, 0x6d, 0x9f, 0x53, 0x4a, 0xb7, 0x01, 0x8a, 0xdb, 0x8a, 0x94, 0xb2, 0x43, 0x05, + 0xe4, 0x28, 0xab, 0xee, 0xb6, 0xdf, 0x9a, 0x8b, 0xce, 0x78, 0x50, 0x5d, 0xe6, 0x4b, 0x55, 0x47, + 0xa9, 0xc5, 0x4e, 0x1f, 0xbb, 0x9e, 0x31, 0x0c, 0x1e, 0x22, 0xf7, 0xd6, 0x9a, 0xaf, 0xcf, 0x79, + 0x46, 0xe8, 0xd5, 0x9f, 0xcd, 0x6c, 0xb7, 0x09, 0x63, 0x2f, 0x49, 0xab, 0xea, 0x38, 0xe8, 0xa5, + 0xb2, 0xf9, 0x2f, 0x6f, 0xe5, 0x5b, 0xd1, 0x7e, 0x33, 0x19, 0xd3, 0x9b, 0xb0, 0x4a, 0x44, 0xf0, + 0xe0, 0xaf, 0x13, 0xa0, 0x81, 0xea, 0x3b, 0x68, 0x1c, 0x6a, 0x38, 0x12, 0xe7, 0xad, 0x45, 0xc2, + 0xd1, 0x3f, 0x9a, 0x1b, 0x7c, 0xf3, 0x35, 0xe8, 0xe5, 0xe3, 0xa7, 0xda, 0xa6, 0x93, 0xb4, 0x69, + 0x5e, 0x8b, 0x07, 0x9b, 0x75, 0x05, 0x99, 0x3d, 0x89, 0xdc, 0x58, 0xe2, 0x7a, 0xae, 0x7c, 0x9c, + 0xed, 0x2e, 0x6b, 0x58, 0xce, 0xae, 0x5a, 0x94, 0xb9, 0xc4, 0x76, 0x47, 0xb6, 0xb6, 0x38, 0xf5, + 0xda, 0xcb, 0xc1, 0x97, 0x34, 0x58, 0x81, 0x30, 0xf5, 0x0a, 0xbd, 0x41, 0x57, 0x01, 0xd7, 0x04, + 0x15, 0xc6, 0x81, 0xfb, 0xf3, 0x49, 0xc2, 0x11, 0x9d, 0x21, 0xc0, 0xae, 0x7e, 0x85, 0x9c, 0xd3, + 0x37, 0xc3, 0x30, 0x5e, 0xdc, 0x84, 0x81, 0x65, 0x99, 0xda, 0xa2, 0x4a, 0x9b, 0x99, 0x46, 0x0e, + 0xb8, 0x9b, 0x3c, 0xf5, 0x75, 0x23, 0x4b, 0x53, 0xfe, 0x23, 0x63, 0x01, 0xca, 0xd3, 0x43, 0xdb, + 0x67, 0x45, 0x5b, 0xc0, 0xec, 0x95, 0x99, 0xab, 0x97, 0x2b, 0xc6, 0x9a, 0x48, 0x06, 0x44, 0x1c, + 0x77, 0xf4, 0xcb, 0xad, 0x25, 0x5e, 0x5f, 0x0f, 0x4c, 0x92, 0x1a, 0xfc, 0xbf, 0x31, 0xa2, 0x11, + 0x65, 0xfd, 0xe6, 0x1e, 0x7e, 0xa0, 0x99, 0x07, 0x74, 0x34, 0x47, 0xc7, 0x88, 0xca, 0x08, 0x88, + 0x1f, 0x8e, 0xd8, 0xc4, 0x43, 0xc0, 0x19, 0xba, 0x3a, 0x48, 0x75, 0xf5, 0xb5, 0x2f, 0xaf, 0x74, + 0x51, 0xe2, 0x5c, 0xc6, 0x9d, 0x45, 0xc9, 0x31, 0x36, 0x4d, 0x75, 0x34, 0x53, 0x76, 0xba, 0x72, + 0xd8, 0x4d, 0xed, 0x12, 0xd0, 0x4a, 0x3e, 0xf6, 0xa6, 0x17, 0xda, 0x0d, 0x3a, 0x56, 0x02, 0x54, + 0x1d, 0xc8, 0x3b, 0x0b, 0xc7, 0x8f, 0x65, 0x9b, 0x49, 0x89, 0xfa, 0x93, 0xe9, 0xbf, 0xea, 0x47, + 0x0c, 0xfd, 0x82, 0xb2, 0x33, 0x84, 0x0c, 0x33, 0x10, 0xfc, 0x2e, 0xa2, 0x3e, 0x37, 0x00, 0x67, + 0x65, 0xc7, 0xa0, 0x3a, 0x60, 0x65, 0xb5, 0x8a, 0xcd, 0x54, 0x65, 0x4b, 0xd0, 0xf9, 0x52, 0x16, + 0xfa, 0x5e, 0x3a, 0x02, 0xc1, 0x5a, 0xff, 0xb3, 0xa6, 0xec, 0xd2, 0x2c, 0x8e, 0xaa, 0x3b, 0x87, + 0x50, 0xe0, 0x53, 0xde, 0xa5, 0x5e, 0x05, 0x31, 0xe5, 0x57, 0xb9, 0xc2, 0xd9, 0xb7, 0x77, 0x0d, + 0x00, 0x75, 0x48, 0x48, 0x2a, 0x38, 0x96, 0x4d, 0x3f, 0xbd, 0xa4, 0xd0, 0x30, 0x33, 0xea, 0x1a, + 0xad, 0x1b, 0x07, 0xf6, 0x74, 0xf6, 0x05, 0x6f, 0x53, 0xd9, 0xa8, 0xe9, 0xfb, 0xf8, 0xae, 0x9a, + 0x24, 0xf0, 0x16, 0x4e, 0x93, 0xf6, 0xb7, 0x0c, 0x96, 0x21, 0x74, 0xc2, 0xcc, 0x22, 0x77, 0x45, + 0x3b, 0x5a, 0x96, 0x99, 0x1e, 0x5e, 0xca, 0x49, 0xbb, 0xca, 0xc4, 0x8c, 0x99, 0xe4, 0x45, 0x46, + 0x01, 0x67, 0x4f, 0x3a, 0xe3, 0x3c, 0x56, 0x2b, 0xb7, 0xef, 0xef, 0x5f, 0x71, 0xee, 0x00, 0xbf, + 0x98, 0x30, 0x69, 0xdb, 0xd5, 0x5b, 0x35, 0x69, 0x0a, 0x06, 0x45, 0xb3, 0x51, 0x89, 0x35, 0x48, + 0x13, 0x36, 0xe7, 0x64, 0x3e, 0xfb, 0x70, 0x12, 0x35, 0xa8, 0x32, 0xff, 0x68, 0x60, 0xa6, 0xe6, + 0x3f, 0x27, 0xa6, 0xb5, 0x00, 0x0e, 0xb3, 0x8c, 0x1e, 0x7b, 0x66, 0xc1, 0xa7, 0xe7, 0x8c, 0x38, + 0xcf, 0xfa, 0x43, 0x46, 0xb6, 0x3b, 0x3a, 0xcb, 0x68, 0x7d, 0xdb, 0x94, 0xf0, 0x39, 0xfe, 0xf4, + 0x6b, 0x3e, 0x5d, 0x60, 0xf6, 0x37, 0xa6, 0x35, 0x9f, 0x6c, 0x71, 0x57, 0x2f, 0x83, 0xdb, 0x22, + 0x89, 0x8c, 0x44, 0x4f, 0x2e, 0x64, 0xf7, 0xbd, 0x29, 0xc7, 0x44, 0xf1, 0x80, 0xaa, 0x57, 0x0f, + 0xf4, 0x9d, 0x85, 0x41, 0xd8, 0xd5, 0x0b, 0x4b, 0xfb, 0x49, 0x52, 0x96, 0xf0, 0x1f, 0x9f, 0x37, + 0x17, 0xf6, 0x32, 0xf3, 0x4e, 0x96, 0xdf, 0xe8, 0x2f, 0x4b, 0x93, 0x67, 0x3f, 0x1a, 0xbc, 0x8e, + 0x3a, 0x9b, 0x48, 0x62, 0xd0, 0x76, 0x45, 0x62, 0x1d, 0xb6, 0x54, 0x37, 0x7d, 0x34, 0xdb, 0xbc, + 0xd9, 0xad, 0xa6, 0xac, 0xaf, 0x77, 0xee, 0x71, 0x61, 0x70, 0xba, 0x46, 0x8d, 0xcd, 0x52, 0x33, + 0x3b, 0x59, 0x11, 0x43, 0x4e, 0x01, 0xc6, 0x9b, 0xc0, 0x33, 0xb0, 0xc0, 0x5c, 0x0e, 0xf3, 0x07, + 0xea, 0x72, 0x51, 0x98, 0x20, 0xb5, 0xa9, 0xb7, 0xac, 0x0a, 0x2d, 0x38, 0xdd, 0x26, 0x6a, 0xa1, + 0xac, 0xc3, 0x7a, 0x4d, 0x64, 0xef, 0x2e, 0x68, 0x91, 0xad, 0x85, 0x1b, 0xaf, 0x26, 0xdd, 0x23, + 0x6a, 0x9f, 0xef, 0x06, 0xd3, 0xa3, 0xf9, 0x7b, 0x92, 0x52, 0x99, 0xb3, 0xb6, 0xe8, 0x26, 0xa8, + 0xd7, 0x1e, 0x15, 0x4d, 0x5f, 0xf7, 0xc9, 0xf6, 0xc8, 0x6f, 0xd9, 0xee, 0x8d, 0xf5, 0x3e, 0xa5, + 0xbc, 0x9c, 0xb3, 0xcc, 0xc1, 0x04, 0x36, 0x79, 0x48, 0xb4, 0x87, 0xea, 0x46, 0x43, 0x25, 0xc4, + 0x77, 0x3b, 0x02, 0x86, 0xc9, 0xd6, 0x57, 0x8c, 0xc0, 0x3c, 0x18, 0x57, 0x4d, 0xfe, 0x99, 0x9f, + 0x0c, 0xc4, 0x35, 0xd1, 0x22, 0x0a, 0x2e, 0x6a, 0x15, 0xd6, 0x3e, 0x4b, 0xc7, 0x69, 0x77, 0x5d, + 0xd2, 0xcc, 0x57, 0x88, 0xec, 0xaa, 0xf8, 0x66, 0x79, 0x23, 0x11, 0xc7, 0x61, 0xfb, 0xd6, 0x93, + 0xe7, 0xb3, 0xb6, 0xf8, 0x17, 0x73, 0xad, 0xe0, 0x75, 0x2f, 0xbb, 0x1c, 0xbb, 0xc7, 0x39, 0xc3, + 0x01, 0x99, 0xee, 0xa2, 0x50, 0xc7, 0x03, 0x52, 0xb7, 0xc2, 0x70, 0x87, 0xbd, 0x69, 0xa9, 0x74, + 0x16, 0x46, 0x60, 0x16, 0xd6, 0xd5, 0x31, 0x4f, 0xbc, 0x44, 0x95, 0xbd, 0x49, 0x28, 0x0a, 0x27, + 0xa1, 0x5f, 0x63, 0x47, 0xa1, 0xd5, 0xdf, 0x98, 0xd6, 0xde, 0x1f, 0xa7, 0xa3, 0x5b, 0xf7, 0x6d, + 0x4d, 0x3d, 0x6d, 0xed, 0x0c, 0x92, 0x56, 0x07, 0xec, 0x5a, 0x6a, 0x59, 0xcc, 0x46, 0x56, 0x61, + 0x2f, 0x52, 0xd7, 0xb5, 0x53, 0x49, 0x5b, 0x8a, 0x64, 0xc5, 0xdf, 0xd4, 0xe3, 0xe1, 0xad, 0x18, + 0xd7, 0x50, 0x3e, 0x0f, 0x57, 0xdb, 0x3b, 0x7c, 0x8e, 0x0a, 0xcd, 0xdb, 0xdf, 0x6b, 0x4e, 0x81, + 0x56, 0xa9, 0x34, 0xde, 0x40, 0x2f, 0x19, 0xa7, 0x04, 0xed, 0xb6, 0x0c, 0xba, 0xaf, 0xce, 0xe3, + 0x7e, 0xd8, 0x87, 0x78, 0xfb, 0xb2, 0xde, 0x46, 0x90, 0xf3, 0xe6, 0x1c, 0x5e, 0x04, 0xe3, 0xd7, + 0xc6, 0x72, 0x74, 0x76, 0xa0, 0xd4, 0xb5, 0x94, 0xd8, 0xc9, 0x38, 0x58, 0x89, 0x1c, 0x2c, 0x6b, + 0x1c, 0xc5, 0x88, 0x3b, 0xba, 0xdc, 0xd5, 0x4f, 0xe5, 0x2b, 0xa7, 0x16, 0xbd, 0x36, 0x93, 0x9e, + 0xec, 0xb6, 0x9d, 0x4f, 0x64, 0x2f, 0x8a, 0xc7, 0x34, 0xff, 0xc0, 0x64, 0x62, 0xb2, 0x9c, 0xcf, + 0xe3, 0xc7, 0x44, 0xc1, 0x34, 0x24, 0xd9, 0xe1, 0xb6, 0x81, 0x39, 0x26, 0x44, 0x99, 0x5a, 0x6d, + 0x9a, 0x96, 0xf9, 0x8e, 0xd4, 0x99, 0x13, 0x24, 0x9b, 0xbf, 0x3f, 0x3d, 0xc7, 0x6e, 0x16, 0x2b, + 0xd1, 0x3f, 0x87, 0xce, 0x81, 0x99, 0xae, 0xa6, 0xb5, 0xe2, 0xef, 0xcc, 0xdb, 0x25, 0x2d, 0x7d, + 0xed, 0x57, 0xc9, 0x00, 0xa9, 0xfb, 0x46, 0x21, 0xf3, 0x44, 0x3f, 0x19, 0x0a, 0xea, 0x6d, 0x2e, + 0xc8, 0xe0, 0x40, 0xf5, 0xa5, 0x5a, 0x94, 0x37, 0xd2, 0x59, 0x85, 0x4a, 0x8f, 0xbf, 0x90, 0xf4, + 0xa9, 0x53, 0x6a, 0x33, 0xe5, 0xdc, 0xc5, 0x71, 0x14, 0x79, 0x60, 0x22, 0xa2, 0x33, 0x8c, 0x4a, + 0x80, 0x6a, 0x90, 0x28, 0xae, 0xbf, 0x5e, 0x55, 0xdf, 0xee, 0x47, 0xbd, 0x11, 0x98, 0x58, 0xf7, + 0xf5, 0xa3, 0x2a, 0x32, 0x5d, 0x9c, 0xb7, 0xa5, 0x3d, 0xd2, 0xfc, 0x5e, 0x70, 0x4a, 0x43, 0x80, + 0x2a, 0x4f, 0xf5, 0xb9, 0x03, 0x06, 0xf2, 0x40, 0x06, 0xf0, 0x71, 0xc3, 0x77, 0x96, 0x44, 0x76, + 0xb0, 0xfe, 0xeb, 0xae, 0x09, 0x6b, 0x90, 0xe0, 0x37, 0xa6, 0xf5, 0x0b, 0xd6, 0x47, 0x4a, 0x96, + 0x94, 0x36, 0xd5, 0x00, 0xed, 0x56, 0x3f, 0xc1, 0x0b, 0x39, 0x18, 0x0b, 0xfc, 0xf1, 0x54, 0x19, + 0x8f, 0xcc, 0xed, 0xf8, 0x21, 0xee, 0xc8, 0xc4, 0xe9, 0xe5, 0x54, 0xaf, 0x79, 0x85, 0x86, 0x2e, + 0xd3, 0x9e, 0x71, 0xe8, 0x34, 0x1d, 0xb4, 0x98, 0x54, 0xfd, 0x8f, 0x9a, 0x59, 0xc3, 0x21, 0xce, + 0xdb, 0x63, 0x14, 0xd4, 0x8d, 0x19, 0x25, 0x7a, 0xed, 0x72, 0xcd, 0x72, 0x98, 0x95, 0xc6, 0x69, + 0xac, 0xff, 0xe9, 0xf0, 0xe7, 0xe0, 0xcf, 0x1b, 0xd9, 0x9a, 0xd1, 0x7c, 0xd1, 0xc8, 0x05, 0x50, + 0xff, 0xe0, 0xeb, 0x62, 0xfc, 0x8a, 0x20, 0x52, 0x80, 0x2a, 0x0d, 0x55, 0x69, 0x2f, 0xbc, 0x52, + 0xdf, 0x13, 0x5a, 0x3d, 0x7c, 0x22, 0x1a, 0xef, 0x32, 0x18, 0x8d, 0x2d, 0x92, 0x96, 0x8a, 0x4b, + 0x29, 0x1f, 0xac, 0xe1, 0x1e, 0xa7, 0xeb, 0xa4, 0xb6, 0xc0, 0xe0, 0x09, 0x5a, 0x26, 0x9b, 0xbf, + 0x82, 0x32, 0x2b, 0xfd, 0x01, 0xb8, 0xd4, 0x95, 0x1a, 0x77, 0xd2, 0xe4, 0x02, 0xa2, 0xef, 0x58, + 0x95, 0x04, 0x02, 0xb1, 0x8d, 0x7e, 0x4b, 0xaa, 0x06, 0x97, 0xde, 0xf0, 0x05, 0xb3, 0x6f, 0x14, + 0x29, 0x87, 0x8c, 0xeb, 0xfe, 0x46, 0xd4, 0x82, 0x1c, 0x5e, 0x2f, 0x7a, 0xa1, 0xa3, 0xa5, 0x61, + 0xb5, 0xe6, 0xc7, 0x16, 0x1d, 0x6f, 0x01, 0x06, 0x7b, 0x89, 0xb2, 0x67, 0x33, 0x82, 0xe0, 0x4c, + 0x62, 0x64, 0x4d, 0x9e, 0xe3, 0x3f, 0x86, 0x1e, 0xb9, 0x21, 0x09, 0xb8, 0xba, 0xc4, 0xeb, 0x01, + 0xf2, 0x51, 0x85, 0xa3, 0xbb, 0x65, 0x11, 0x9d, 0xfd, 0x92, 0x54, 0x4b, 0x7e, 0xce, 0x92, 0xe7, + 0x79, 0x45, 0x2f, 0x56, 0xcb, 0xbf, 0x44, 0xd1, 0x46, 0xf6, 0x22, 0x51, 0x17, 0x5a, 0x87, 0x8e, + 0xef, 0xd5, 0x37, 0xe7, 0x73, 0xa2, 0x9a, 0xdf, 0xd0, 0x70, 0xe6, 0x94, 0x16, 0xeb, 0x0f, 0x86, + 0x3f, 0x70, 0x19, 0x35, 0x6c, 0x9b, 0xe9, 0x6d, 0x92, 0x85, 0x34, 0xff, 0xa2, 0x64, 0x89, 0xe3, + 0x91, 0x5d, 0xab, 0x8c, 0xfd, 0xda, 0xa6, 0x01, 0xce, 0x6f, 0x4c, 0x2f, 0x72, 0xb1, 0x68, 0xb6, + 0x31, 0xc8, 0xa9, 0x8d, 0xe0, 0x72, 0x6f, 0xfd, 0xb5, 0x4a, 0x08, 0x01, 0xfd, 0x87, 0xac, 0xc5, + 0x1a, 0x98, 0x17, 0xee, 0x79, 0x10, 0x6b, 0x79, 0x1b, 0x79, 0xec, 0xa1, 0x77, 0x35, 0xa5, 0x3c, + 0x7a, 0xef, 0x0e, 0xb6, 0x65, 0xc7, 0x8d, 0x54, 0x58, 0x14, 0xc3, 0x7d, 0xf2, 0x4e, 0x66, 0xc7, + 0x4d, 0xb8, 0x60, 0x67, 0x13, 0xcc, 0x76, 0x2e, 0x99, 0x69, 0xc7, 0xd3, 0x0b, 0xb6, 0xe8, 0xfa, + 0x2a, 0x7e, 0x53, 0xdc, 0xe6, 0x99, 0xbd, 0x8c, 0x8b, 0x47, 0x2b, 0x3b, 0x16, 0xe6, 0xed, 0x23, + 0x13, 0x71, 0x92, 0x8e, 0xfc, 0x5d, 0x67, 0xbf, 0x36, 0xc3, 0x2e, 0xc0, 0xb6, 0x0f, 0xc5, 0xa8, + 0xd2, 0x4f, 0x54, 0xf0, 0xa7, 0xe8, 0x7c, 0x3a, 0xbf, 0xfb, 0x26, 0x40, 0x78, 0x10, 0xf4, 0x59, + 0xc1, 0x44, 0x29, 0x23, 0x82, 0x7c, 0x19, 0xcf, 0xf1, 0x1f, 0x2e, 0x91, 0xac, 0xf2, 0x00, 0x72, + 0xe6, 0xca, 0xf4, 0xcb, 0x11, 0x47, 0x10, 0x81, 0x64, 0xec, 0x36, 0x7a, 0xd6, 0x5a, 0x15, 0xb8, + 0xc2, 0x3f, 0x27, 0xc6, 0x87, 0x1e, 0x19, 0x90, 0xcc, 0x6a, 0x5b, 0x05, 0x33, 0x34, 0x99, 0x79, + 0xfd, 0x39, 0x20, 0xae, 0x47, 0x15, 0x7d, 0x73, 0xe7, 0xba, 0xcc, 0xaf, 0x7e, 0x0f, 0x1a, 0xae, + 0x46, 0xae, 0xe6, 0x5e, 0x62, 0xf8, 0x83, 0x5c, 0xba, 0x8a, 0x2f, 0xe6, 0xee, 0x30, 0xf7, 0x53, + 0xbb, 0xd0, 0x39, 0xc1, 0xc3, 0xbc, 0x87, 0x37, 0x00, 0xb0, 0xf6, 0x2e, 0x2a, 0x7d, 0xb9, 0xe3, + 0xbc, 0x97, 0xb0, 0x9c, 0x6a, 0xbb, 0xc5, 0x85, 0xe7, 0x0b, 0xe2, 0xf5, 0xde, 0xb6, 0x59, 0xce, + 0x50, 0x68, 0xed, 0x5a, 0x81, 0x88, 0xfc, 0x0f, 0x45, 0xfc, 0x00, 0x75, 0x93, 0x3a, 0x95, 0x6c, + 0x4a, 0x07, 0x18, 0x37, 0xc0, 0x99, 0x6a, 0x3c, 0x3c, 0x1c, 0x03, 0x50, 0xe0, 0xa9, 0x4d, 0xeb, + 0x4f, 0x17, 0xeb, 0x06, 0xdf, 0xa9, 0xef, 0x35, 0x79, 0xf2, 0x78, 0x7c, 0xf3, 0x47, 0xc2, 0x49, + 0xb4, 0xf9, 0x9e, 0x40, 0xd3, 0x99, 0x74, 0xbf, 0xfd, 0x5a, 0x71, 0xab, 0xce, 0xfd, 0x8d, 0x69, + 0x5b, 0x94, 0xd7, 0x5c, 0xae, 0x86, 0x2f, 0xdd, 0x67, 0xaf, 0x51, 0x9b, 0x38, 0x94, 0x29, 0x62, + 0xb6, 0x2f, 0xfd, 0xb8, 0x4f, 0x5f, 0x0e, 0xdd, 0xdc, 0x05, 0x20, 0xd5, 0x5e, 0x5b, 0x89, 0x0b, + 0xcd, 0xf9, 0x33, 0xea, 0xe6, 0x35, 0xde, 0xad, 0x94, 0x6d, 0x4f, 0x4d, 0xe9, 0xc8, 0xbe, 0x7b, + 0x9c, 0xcd, 0x65, 0xb3, 0xcc, 0x57, 0x55, 0xa5, 0xbf, 0x73, 0xf2, 0x73, 0xc4, 0x39, 0xa6, 0x65, + 0x96, 0x8b, 0xb7, 0x7a, 0xa5, 0xd7, 0x61, 0xb8, 0x0c, 0xd7, 0x30, 0xc8, 0x06, 0x46, 0xbb, 0x8f, + 0x8f, 0xa4, 0x4c, 0x1a, 0x3d, 0xc1, 0x8d, 0xdb, 0x17, 0x4c, 0xba, 0x8f, 0xff, 0x74, 0x90, 0x1a, + 0xee, 0xc2, 0x94, 0xcc, 0x27, 0x73, 0xf6, 0x7f, 0x76, 0xd6, 0x1b, 0x8a, 0x7b, 0x3e, 0xf0, 0x67, + 0x4e, 0x09, 0x61, 0xbb, 0x30, 0x60, 0xd1, 0x06, 0xad, 0x2a, 0xad, 0xe3, 0x4d, 0x3a, 0xc9, 0x58, + 0xae, 0x48, 0x1e, 0x5a, 0xc3, 0x9a, 0x7f, 0x20, 0xbd, 0x94, 0xa1, 0x33, 0x7c, 0x80, 0xe8, 0x9f, + 0x73, 0x54, 0xff, 0xf9, 0x6d, 0x67, 0xd0, 0x09, 0x15, 0x09, 0x47, 0xdd, 0xbe, 0x7c, 0x20, 0xfb, + 0xb3, 0x3a, 0xb0, 0x9d, 0x87, 0x9a, 0xf2, 0x2b, 0x28, 0xd8, 0x05, 0xd7, 0x07, 0x9a, 0x8e, 0x48, + 0xa7, 0x09, 0xe5, 0xf5, 0x09, 0xf3, 0x26, 0xc5, 0x3e, 0xf1, 0xcc, 0x2f, 0x10, 0xd4, 0x0b, 0xb3, + 0xc1, 0x52, 0xed, 0xa2, 0x84, 0x56, 0x17, 0x0c, 0xc8, 0x6c, 0x64, 0x3c, 0x08, 0x80, 0xc7, 0x07, + 0xbd, 0x22, 0xb7, 0x06, 0x1f, 0xf5, 0x4c, 0x07, 0xde, 0xe4, 0x3c, 0x92, 0x4e, 0x53, 0x34, 0xdb, + 0x7a, 0x3a, 0xd7, 0x15, 0x16, 0x33, 0x53, 0x3a, 0x79, 0xa4, 0xd9, 0x1a, 0x5a, 0x09, 0x45, 0x39, + 0x07, 0x4a, 0x15, 0x2d, 0x55, 0xae, 0x6b, 0xd9, 0xab, 0xbc, 0x3a, 0x4a, 0x95, 0x2e, 0x1e, 0x53, + 0x65, 0x87, 0x58, 0xcc, 0x66, 0x6d, 0x2d, 0x1b, 0x02, 0xee, 0x9a, 0x3d, 0x6a, 0x03, 0x97, 0x54, + 0xd4, 0x69, 0xb5, 0xa8, 0x3c, 0xd0, 0xbe, 0xa9, 0xc1, 0x35, 0xcf, 0xaf, 0x6d, 0x1a, 0x97, 0xff, + 0xad, 0xe9, 0x12, 0x72, 0x2b, 0x68, 0x1f, 0x70, 0x53, 0x37, 0x5a, 0xf5, 0xfa, 0x70, 0x15, 0x6b, + 0x6e, 0xd5, 0x39, 0xc8, 0x53, 0xf7, 0x3a, 0x31, 0x7c, 0xc1, 0xaa, 0xfc, 0x8c, 0x6e, 0x8d, 0x2e, + 0x0b, 0x06, 0xee, 0x0a, 0x71, 0xb0, 0x9e, 0xb2, 0x2b, 0x2b, 0xe7, 0xbd, 0xfe, 0x1f, 0x51, 0xdf, + 0x57, 0x9e, 0x32, 0x6e, 0x71, 0x21, 0x0c, 0x92, 0xa4, 0x1a, 0x44, 0xf5, 0x38, 0x63, 0x9b, 0xf6, + 0xc5, 0x1f, 0x73, 0x91, 0xd3, 0x63, 0xaa, 0x37, 0x50, 0xbd, 0xd6, 0xf3, 0xab, 0x38, 0x0e, 0x8d, + 0xdf, 0xbc, 0x26, 0x78, 0x38, 0x08, 0x27, 0x35, 0x53, 0x82, 0xe2, 0x0e, 0xce, 0x31, 0xae, 0xbd, + 0x06, 0x81, 0x1f, 0x5a, 0x6a, 0xf1, 0xa3, 0x0c, 0x27, 0xb2, 0x43, 0xdb, 0x03, 0x23, 0xd7, 0xbe, + 0x41, 0xee, 0x8b, 0xf6, 0xeb, 0x4e, 0x9d, 0x6e, 0xe9, 0x8c, 0xa6, 0xd6, 0xeb, 0x2d, 0x8a, 0x44, + 0x46, 0xf6, 0x2e, 0x72, 0x49, 0x24, 0x80, 0xe6, 0x11, 0x61, 0x18, 0xd0, 0x49, 0xf6, 0x2b, 0xe2, + 0x4d, 0xad, 0xc6, 0xad, 0x17, 0xee, 0x86, 0xae, 0x28, 0x9b, 0xc9, 0xdc, 0xc3, 0xb5, 0xfa, 0x12, + 0x88, 0x1f, 0x43, 0x23, 0xa1, 0xf2, 0xbe, 0xa5, 0x56, 0x79, 0x54, 0xff, 0xfe, 0xbc, 0x10, 0xaf, + 0x92, 0x05, 0x9d, 0xbb, 0xa9, 0x22, 0xf8, 0xb9, 0x52, 0x60, 0xfa, 0x7f, 0xd6, 0xc3, 0x04, 0x74, + 0x1b, 0xd3, 0x16, 0x44, 0x1c, 0x26, 0xd0, 0xff, 0xaf, 0x2b, 0x6e, 0xfd, 0x4d, 0x3f, 0x8d, 0x83, + 0xbf, 0x69, 0xd3, 0x80, 0xf4, 0x81, 0x3e, 0x21, 0x78, 0xc5, 0x8c, 0xef, 0xb6, 0x4c, 0xd7, 0x3a, + 0x01, 0x59, 0x2c, 0xa9, 0x59, 0xca, 0xdf, 0xd5, 0xd8, 0x76, 0xd1, 0x48, 0xd1, 0x2a, 0x54, 0xdc, + 0xfd, 0x7f, 0xd4, 0x55, 0x02, 0xda, 0xd0, 0x8c, 0x30, 0x57, 0xee, 0x94, 0x72, 0xbb, 0x96, 0x4a, + 0x24, 0x0c, 0x66, 0x50, 0xae, 0x3b, 0x95, 0xb0, 0x2a, 0xb9, 0x0d, 0xf3, 0x53, 0xca, 0x25, 0xe9, + 0xc3, 0xf3, 0xe5, 0xa1, 0xb7, 0xf3, 0xc1, 0x85, 0x27, 0x17, 0x19, 0x9e, 0xff, 0x5e, 0xdd, 0x45, + 0x72, 0x10, 0xce, 0x1b, 0x39, 0x0c, 0x74, 0x4a, 0xa4, 0xb2, 0xa9, 0x60, 0x3d, 0xb4, 0x19, 0xe2, + 0x65, 0x0e, 0x00, 0xb8, 0x2f, 0x8c, 0xbc, 0x21, 0xdd, 0x3d, 0x11, 0xa6, 0x11, 0xe2, 0x17, 0xfd, + 0xcd, 0xda, 0xa7, 0xca, 0xe9, 0xe9, 0x42, 0xe6, 0x82, 0xd6, 0x77, 0x49, 0xea, 0xf8, 0xc8, 0x40, + 0xc7, 0x0c, 0x6f, 0xa3, 0x74, 0xbb, 0x06, 0xae, 0x2e, 0xfa, 0xa5, 0xe7, 0xe8, 0xfc, 0x41, 0xa9, + 0x5a, 0x53, 0xdc, 0x45, 0xd9, 0x5a, 0xfc, 0xd0, 0x47, 0x09, 0x8d, 0x3f, 0xbb, 0x2e, 0x07, 0x72, + 0x1f, 0x2c, 0x6f, 0x76, 0x5c, 0x83, 0xfe, 0xaa, 0x19, 0xcc, 0x9c, 0x4d, 0xa8, 0x8b, 0xc7, 0x50, + 0xed, 0x0f, 0xfd, 0x30, 0xb8, 0x78, 0x03, 0xb8, 0x1c, 0x39, 0x57, 0x51, 0xf5, 0xa6, 0x4a, 0xa7, + 0xa3, 0x27, 0xc3, 0x11, 0x12, 0xcd, 0x36, 0xa3, 0xc9, 0xd8, 0x51, 0xbb, 0xf0, 0xf4, 0x32, 0xde, + 0xd4, 0x4b, 0x9b, 0xb3, 0xf2, 0xad, 0xfd, 0xd7, 0x80, 0x31, 0xaf, 0xd0, 0xa5, 0xc7, 0x16, 0xef, + 0xc9, 0xbf, 0xd9, 0x2a, 0xff, 0x4b, 0xb7, 0x1f, 0xb7, 0xe2, 0x99, 0x25, 0xb8, 0xf7, 0x1d, 0x6e, + 0x46, 0x31, 0xa4, 0x12, 0x98, 0xa8, 0xcc, 0x8a, 0xc9, 0x5c, 0x41, 0xa2, 0x91, 0x73, 0x61, 0xdd, + 0x87, 0x9e, 0xad, 0x52, 0xf1, 0xd6, 0xcc, 0x91, 0x46, 0x1a, 0xcd, 0xd6, 0x8c, 0x6c, 0x1e, 0x4d, + 0xf4, 0x6d, 0xd4, 0x6c, 0xe7, 0x34, 0x69, 0x1f, 0x54, 0x3d, 0x9f, 0x2d, 0xb3, 0xd1, 0x5f, 0xd7, + 0xf9, 0x00, 0x7b, 0xea, 0x37, 0xa6, 0xc3, 0x23, 0xbe, 0xf3, 0xa8, 0xd0, 0xdb, 0xf3, 0xc2, 0x63, + 0x4a, 0x98, 0xb1, 0x26, 0x28, 0x78, 0xa4, 0x03, 0x31, 0xd9, 0x95, 0x97, 0x65, 0x28, 0x04, 0xfd, + 0x61, 0xa3, 0xb0, 0x79, 0xc4, 0xcb, 0x8c, 0xf4, 0x21, 0x7e, 0xb5, 0x07, 0x40, 0x7c, 0x56, 0xf7, + 0xb5, 0x92, 0x28, 0x7e, 0x4d, 0x44, 0xba, 0xda, 0xdb, 0xe8, 0x9f, 0x93, 0x90, 0x50, 0xda, 0x55, + 0x31, 0x15, 0xac, 0xda, 0xff, 0xe3, 0xe7, 0x05, 0x16, 0x74, 0xc7, 0xe8, 0xdc, 0x50, 0xeb, 0xca, + 0x4c, 0x55, 0x49, 0xa0, 0xe1, 0x4b, 0x21, 0x97, 0x1e, 0xb6, 0x43, 0xd6, 0x3f, 0xa1, 0x94, 0x73, + 0xbe, 0x83, 0xe4, 0x75, 0x16, 0x43, 0x5b, 0x02, 0xa9, 0x59, 0x02, 0x44, 0xed, 0x89, 0xfd, 0xba, + 0x03, 0xef, 0x11, 0xcd, 0x21, 0xe5, 0x83, 0xd5, 0x1f, 0x8a, 0xfb, 0xaf, 0x04, 0x36, 0x7d, 0xe0, + 0x38, 0x6c, 0x97, 0x3b, 0x75, 0x1b, 0x9f, 0x3e, 0xd5, 0x9e, 0x27, 0x74, 0x56, 0xd9, 0x3f, 0xc7, + 0x2a, 0x57, 0xb2, 0xbc, 0x94, 0xb5, 0x49, 0x58, 0x8b, 0xb3, 0x06, 0xb5, 0x1d, 0x14, 0x52, 0xf7, + 0x0b, 0x43, 0x21, 0xbc, 0x8f, 0x34, 0x26, 0x61, 0x70, 0x1b, 0x8d, 0x5d, 0x75, 0x5d, 0xcb, 0x96, + 0xb6, 0xe4, 0xab, 0x3a, 0x46, 0x5e, 0x84, 0xeb, 0x0b, 0x17, 0xfd, 0xb9, 0x2e, 0x7f, 0xe0, 0x4d, + 0xf2, 0x9c, 0xe8, 0xf0, 0x21, 0x6a, 0x6d, 0xf7, 0xf5, 0x1f, 0xc6, 0xba, 0xbe, 0x93, 0xd5, 0xa1, + 0xe1, 0x54, 0xef, 0xae, 0x33, 0x08, 0x74, 0x52, 0xe2, 0x97, 0x36, 0x8c, 0x26, 0x40, 0xee, 0x2a, + 0x7e, 0xec, 0xfc, 0x6c, 0xed, 0x3e, 0x74, 0xc1, 0x55, 0x7b, 0x57, 0x51, 0xd3, 0xac, 0xfa, 0x26, + 0xf5, 0x4c, 0x41, 0xa2, 0xc0, 0x13, 0x99, 0xc1, 0x90, 0xaa, 0x0c, 0x95, 0xfd, 0x76, 0x5e, 0x89, + 0xbd, 0x30, 0x8a, 0xe7, 0x84, 0xf3, 0x1f, 0x55, 0xdb, 0xdd, 0x84, 0xdd, 0x73, 0xd1, 0xdf, 0xcf, + 0x99, 0xf8, 0x95, 0x27, 0x90, 0xd7, 0x7a, 0xbd, 0x65, 0xf8, 0xc6, 0xa0, 0x76, 0x29, 0xef, 0xf7, + 0x14, 0xbf, 0x9a, 0x9e, 0x52, 0xff, 0xc6, 0x74, 0xd4, 0xf6, 0xe0, 0x59, 0xcf, 0x4b, 0xd7, 0xe2, + 0x24, 0xdb, 0xf2, 0x80, 0x03, 0x23, 0x39, 0x7e, 0xe1, 0xb3, 0x4d, 0xd3, 0x93, 0xbe, 0x53, 0x62, + 0x96, 0xa5, 0x78, 0xcf, 0xb0, 0xcb, 0xf2, 0x73, 0xee, 0x34, 0xd2, 0x8c, 0x96, 0x4c, 0xa7, 0xbd, + 0x30, 0x10, 0x07, 0x2b, 0x69, 0xd8, 0xb7, 0x5e, 0x7e, 0x1d, 0xc2, 0xea, 0x6b, 0x87, 0xc1, 0x4f, + 0x44, 0x6d, 0xa6, 0x6b, 0x47, 0x7f, 0x39, 0xa7, 0xc8, 0x60, 0xaf, 0xa3, 0xf0, 0x29, 0x3d, 0x53, + 0xd4, 0xc6, 0x35, 0xaa, 0x6a, 0x42, 0xb7, 0x01, 0x0a, 0x23, 0x1b, 0xfa, 0x1e, 0xa2, 0x04, 0x33, + 0x1f, 0x24, 0xc7, 0x78, 0x37, 0x55, 0xdd, 0xc6, 0x69, 0x98, 0xfd, 0xdc, 0xeb, 0x35, 0xc9, 0xa7, + 0x24, 0xdc, 0xee, 0x38, 0x47, 0x9e, 0x0d, 0xd3, 0x10, 0xb1, 0x47, 0xed, 0x84, 0xd7, 0xd0, 0xa7, + 0xac, 0x83, 0xe6, 0x34, 0x78, 0x0c, 0xfb, 0x53, 0x89, 0x6d, 0x52, 0xc3, 0xdc, 0x50, 0xda, 0x37, + 0x20, 0x1f, 0x1e, 0x2d, 0x63, 0xfa, 0xe1, 0x65, 0x20, 0x08, 0x17, 0x86, 0xc3, 0x6b, 0x7e, 0x4d, + 0x63, 0x5b, 0x4c, 0x15, 0xac, 0xe7, 0x89, 0xb0, 0xf0, 0x38, 0x60, 0x74, 0x54, 0xd5, 0x5c, 0x35, + 0xf8, 0xac, 0xb1, 0xd7, 0x7f, 0x18, 0x35, 0x5c, 0x14, 0x15, 0x50, 0x1d, 0xa1, 0x39, 0x41, 0xe3, + 0x15, 0xc2, 0xb3, 0x3b, 0xa6, 0x69, 0xd2, 0xf8, 0x05, 0x71, 0x5c, 0x0e, 0x7f, 0xd0, 0x7c, 0x3f, + 0x00, 0xd4, 0x90, 0x7e, 0x26, 0xd5, 0xc6, 0x12, 0xa3, 0xb3, 0x4e, 0xdc, 0x23, 0x99, 0xae, 0x2f, + 0x0b, 0x90, 0x5d, 0x92, 0xc8, 0x19, 0x4f, 0xd9, 0x38, 0xa4, 0xd3, 0x5e, 0x67, 0x0c, 0x17, 0xe9, + 0xf4, 0x6a, 0x3f, 0xfc, 0x8a, 0x57, 0x95, 0x41, 0x56, 0xa4, 0x0c, 0x3b, 0x95, 0x5b, 0x46, 0x3a, + 0x60, 0x69, 0xae, 0x22, 0x86, 0x4c, 0xb6, 0xe8, 0xea, 0x72, 0x44, 0x0a, 0x3c, 0xd2, 0x6e, 0xc6, + 0x3c, 0x17, 0x44, 0x9f, 0x2b, 0xf2, 0xff, 0xa8, 0xe4, 0x99, 0xce, 0x56, 0x54, 0xe4, 0xb7, 0xfe, + 0xba, 0x6b, 0x02, 0xba, 0xf5, 0x1b, 0xd3, 0x37, 0x8a, 0xcb, 0x80, 0x45, 0x48, 0x3d, 0x9c, 0xd3, + 0x45, 0xf8, 0xaa, 0x81, 0xac, 0x22, 0x78, 0x92, 0x3d, 0xdc, 0xa3, 0xa3, 0xc9, 0xb1, 0xc0, 0x8c, + 0xa8, 0x23, 0x76, 0x8f, 0x31, 0xd3, 0xe1, 0x42, 0xf7, 0xa9, 0xb4, 0xf0, 0xb8, 0xb9, 0xdb, 0xe1, + 0x3d, 0x5b, 0xe4, 0x0d, 0xde, 0x13, 0x4e, 0x92, 0x66, 0x43, 0x06, 0x9d, 0xff, 0xb4, 0x3f, 0x5a, + 0xef, 0x00, 0x83, 0x87, 0x71, 0x45, 0x90, 0xeb, 0x78, 0x84, 0x3d, 0xe3, 0xa9, 0xfd, 0xc3, 0x5e, + 0x5b, 0x1a, 0x0c, 0x98, 0xfb, 0xa6, 0x89, 0x6a, 0xcf, 0xaf, 0xdb, 0xac, 0xdc, 0xa5, 0x5f, 0x43, + 0x00, 0xae, 0xd8, 0x6c, 0x9c, 0x8b, 0x0f, 0xd6, 0x7c, 0x54, 0x74, 0xcf, 0xd4, 0x54, 0xb2, 0x54, + 0xe9, 0xc3, 0x68, 0x26, 0xef, 0x0a, 0xaa, 0xf9, 0x92, 0x9d, 0x46, 0x05, 0xc4, 0x9b, 0x27, 0xa8, + 0xea, 0x32, 0xe3, 0xe2, 0xdc, 0x19, 0xc4, 0x29, 0x6a, 0x59, 0x11, 0x4c, 0x24, 0xf5, 0xf9, 0x68, + 0xa7, 0x0a, 0xc6, 0x3d, 0xd6, 0xb2, 0xc4, 0x86, 0x85, 0x32, 0x60, 0xa1, 0x77, 0x55, 0xb3, 0x63, + 0x86, 0x0e, 0x49, 0x77, 0xbd, 0x4a, 0xc1, 0x7d, 0xce, 0x7c, 0x6a, 0x23, 0x0a, 0x40, 0x0a, 0x73, + 0x1a, 0x92, 0x5f, 0xe5, 0x7b, 0xae, 0x6d, 0xa4, 0xc9, 0xd1, 0x19, 0x17, 0xf5, 0x3a, 0x7f, 0x12, + 0x9e, 0x9d, 0x69, 0x5b, 0x4f, 0xd5, 0x30, 0x34, 0x28, 0xe5, 0x05, 0x80, 0xb3, 0x9a, 0x1f, 0x47, + 0xb7, 0x89, 0x5b, 0xd0, 0xcd, 0xe8, 0xd8, 0x33, 0x79, 0xdf, 0x11, 0xc7, 0x24, 0xdb, 0xbf, 0x6a, + 0x17, 0x86, 0x93, 0x46, 0xa2, 0xfc, 0xd3, 0xf2, 0x34, 0x5c, 0xd8, 0x08, 0xa4, 0xec, 0xdb, 0x49, + 0xb9, 0x00, 0xe8, 0xa5, 0xbd, 0x65, 0x5b, 0xda, 0xf4, 0x10, 0x1e, 0x80, 0xf5, 0x32, 0x91, 0xc2, + 0xf7, 0xd1, 0xd5, 0xdc, 0x50, 0x07, 0x92, 0x19, 0xc4, 0xa8, 0xd7, 0x16, 0xd6, 0xe8, 0x4e, 0xb9, + 0x1d, 0xd5, 0x83, 0x5d, 0x4b, 0xd4, 0xab, 0xdf, 0xd8, 0xb2, 0xd4, 0xd5, 0xb7, 0x09, 0xed, 0xe4, + 0x6f, 0xf6, 0x11, 0xd2, 0xff, 0xc6, 0x74, 0xfe, 0xee, 0xc0, 0xf1, 0xda, 0xd5, 0x81, 0x1e, 0xb2, + 0x2b, 0xc2, 0x47, 0x8a, 0x6c, 0x94, 0x27, 0xa1, 0xad, 0x09, 0xdb, 0xd9, 0xc9, 0x18, 0xbe, 0x68, + 0x2e, 0x4d, 0x62, 0x07, 0x97, 0xf5, 0x73, 0xde, 0xc5, 0x44, 0x43, 0xea, 0xf4, 0xa3, 0x65, 0x32, + 0x03, 0x57, 0x88, 0xe2, 0x9c, 0xf4, 0x3e, 0x74, 0x23, 0xf8, 0xaa, 0xad, 0x5e, 0x0b, 0x0f, 0x5c, + 0x2c, 0x03, 0x68, 0x1e, 0xd1, 0x1d, 0x3c, 0xd3, 0xdd, 0xab, 0x54, 0x0c, 0x9a, 0x72, 0x75, 0x7c, + 0x47, 0x97, 0x49, 0x64, 0xb4, 0x5d, 0xb6, 0xcf, 0x3e, 0x51, 0x2b, 0x0d, 0x9b, 0x4f, 0xdf, 0xe8, + 0x8e, 0x79, 0xc6, 0xc6, 0x70, 0x82, 0xba, 0x9c, 0xd6, 0x3b, 0x9d, 0x26, 0x5c, 0x78, 0x8e, 0x5a, + 0x33, 0xd7, 0x55, 0xd7, 0x79, 0xaf, 0x78, 0x7f, 0x8c, 0x9d, 0xfe, 0xec, 0x2f, 0xe9, 0x47, 0x26, + 0xef, 0xb7, 0x65, 0x03, 0xaf, 0x3c, 0x25, 0x35, 0x43, 0xc3, 0x95, 0xd2, 0x6b, 0xdc, 0x41, 0x96, + 0x2b, 0x95, 0x91, 0xe6, 0xb8, 0xeb, 0x12, 0xe9, 0xd7, 0x93, 0x66, 0xbf, 0xaf, 0xbf, 0xb1, 0xb8, + 0xdb, 0x75, 0x37, 0x65, 0xbb, 0x1d, 0x4d, 0x1f, 0xa4, 0xbc, 0x4a, 0xa9, 0x7e, 0x6f, 0xc4, 0x01, + 0xab, 0x89, 0x0d, 0xce, 0x9c, 0xdc, 0xad, 0x31, 0x6e, 0x64, 0x48, 0x7d, 0x6b, 0x25, 0x79, 0xd5, + 0x51, 0x25, 0x42, 0x6b, 0x23, 0x4b, 0x26, 0x53, 0xb9, 0x20, 0xe0, 0x30, 0x44, 0xfb, 0xdb, 0x15, + 0xc1, 0xce, 0x6b, 0x25, 0x2e, 0xc4, 0xa6, 0xaa, 0xcf, 0xa8, 0x33, 0x74, 0x4e, 0x84, 0x6d, 0x41, + 0x0e, 0x5d, 0x3a, 0x1c, 0xcd, 0x3e, 0x9b, 0xdf, 0x92, 0xf5, 0x99, 0x5a, 0xec, 0xaa, 0x27, 0x3c, + 0xa0, 0x97, 0xe8, 0x72, 0xf6, 0x22, 0x39, 0x2f, 0x5d, 0x9b, 0x1c, 0x69, 0xad, 0x5a, 0xc0, 0xd5, + 0x1a, 0x42, 0x01, 0xdb, 0xb2, 0xd1, 0x7a, 0x7f, 0x38, 0x89, 0xef, 0xbb, 0x9f, 0xa2, 0x77, 0x06, + 0x0d, 0xcb, 0x3a, 0xd6, 0xc6, 0xb7, 0xce, 0x05, 0x4c, 0xb2, 0x41, 0xdf, 0xad, 0x65, 0xfa, 0xaa, + 0xfe, 0x1d, 0xf9, 0xeb, 0xdc, 0xc3, 0xc2, 0xfe, 0x8d, 0xe9, 0xb4, 0x28, 0xef, 0xf5, 0x6c, 0xe5, + 0xf3, 0x41, 0xed, 0xb5, 0x65, 0x77, 0x64, 0x1d, 0x65, 0xb7, 0xfb, 0x4e, 0xfd, 0xcc, 0x37, 0x7c, + 0x56, 0x63, 0x78, 0x19, 0x24, 0x7b, 0x6f, 0xae, 0x2f, 0xb0, 0x32, 0xb4, 0xff, 0xa6, 0xfe, 0xb8, + 0xe2, 0x72, 0x76, 0x0c, 0x89, 0x87, 0x91, 0xb6, 0x9b, 0xf6, 0x5d, 0x9e, 0x6a, 0x58, 0x96, 0x38, + 0xae, 0x4a, 0x15, 0x64, 0x6b, 0xf5, 0x37, 0xeb, 0x66, 0x3a, 0x5d, 0x79, 0xc2, 0x41, 0x9b, 0x56, + 0x31, 0x99, 0xc9, 0x77, 0x77, 0x18, 0xa3, 0x34, 0x9d, 0x05, 0x97, 0xb9, 0x85, 0xae, 0x5a, 0xda, + 0x4c, 0x99, 0xc2, 0xb5, 0x99, 0xa4, 0xd1, 0x39, 0xdb, 0x81, 0x87, 0xdb, 0x6f, 0xdd, 0x3f, 0xba, + 0x9a, 0x45, 0x0e, 0xf2, 0xd7, 0x43, 0x3d, 0x14, 0x32, 0xab, 0x37, 0x14, 0x31, 0x54, 0x5f, 0x2d, + 0x13, 0x71, 0x78, 0xa1, 0xbe, 0x5c, 0x18, 0x6d, 0x36, 0x8c, 0x50, 0x20, 0xb4, 0x38, 0xdd, 0xdd, + 0x3f, 0xdd, 0x4c, 0x0f, 0x69, 0x79, 0x1a, 0xf4, 0xd6, 0xcb, 0x7a, 0xc1, 0xda, 0x00, 0x6c, 0x99, + 0xf6, 0x9b, 0x51, 0x45, 0xea, 0xa2, 0x7f, 0xb4, 0x28, 0xb6, 0x9d, 0x92, 0xdd, 0x1b, 0xe4, 0xea, + 0xaa, 0x68, 0x42, 0x76, 0x0f, 0xf3, 0x83, 0x2b, 0x26, 0x79, 0x23, 0x90, 0x04, 0xca, 0x52, 0xfc, + 0x5b, 0x70, 0x63, 0xc1, 0x7a, 0x7d, 0xe5, 0x01, 0x91, 0xca, 0x79, 0x57, 0x67, 0x17, 0x9d, 0x56, + 0x98, 0x88, 0x72, 0x3f, 0x90, 0x18, 0x9a, 0x95, 0x41, 0xab, 0x0c, 0x2b, 0x75, 0xd5, 0x2a, 0x65, + 0xd7, 0x63, 0x4c, 0xae, 0xd5, 0x3e, 0x54, 0x5a, 0x84, 0x93, 0x1d, 0xc5, 0x1e, 0xbc, 0xd5, 0xae, + 0x64, 0xb7, 0xae, 0x9c, 0xf9, 0x94, 0xef, 0x2c, 0x15, 0x13, 0x80, 0x5e, 0x56, 0x31, 0x81, 0xb0, + 0x4e, 0xed, 0x92, 0xfd, 0x7c, 0x3e, 0xd8, 0x8a, 0xe0, 0x45, 0x27, 0x94, 0xb0, 0x25, 0xb3, 0xcf, + 0x4c, 0xac, 0xcb, 0xb8, 0xfe, 0xb3, 0x7d, 0x04, 0xdd, 0x56, 0x9f, 0x04, 0xc2, 0xc9, 0xdd, 0x94, + 0x73, 0x59, 0x8c, 0x9d, 0x1a, 0xc1, 0x6e, 0xf4, 0x6f, 0x6a, 0xba, 0x5b, 0x7e, 0x63, 0x9a, 0x05, + 0xec, 0xab, 0xf1, 0x62, 0x51, 0xe2, 0xf4, 0x74, 0x91, 0x53, 0x18, 0xc3, 0xc4, 0xca, 0xae, 0x0f, + 0x64, 0x5f, 0x7b, 0xbb, 0x82, 0xea, 0x5a, 0x90, 0x6d, 0x79, 0x3e, 0x7e, 0x2d, 0xf3, 0xcb, 0xbc, + 0xb7, 0x26, 0xa9, 0xba, 0x0b, 0x5e, 0x34, 0x67, 0xa2, 0xe2, 0xfa, 0xac, 0xd6, 0xbf, 0xf1, 0xf0, + 0xea, 0xca, 0x26, 0x5e, 0x7b, 0x49, 0x8f, 0x17, 0x02, 0x81, 0xfd, 0x80, 0xab, 0x33, 0x5b, 0x41, + 0xbc, 0x49, 0xe7, 0x61, 0xbd, 0x2c, 0xb4, 0x16, 0x64, 0x33, 0xcb, 0xa1, 0x5e, 0x1f, 0x99, 0x54, + 0xa4, 0x34, 0x98, 0xcc, 0xef, 0x60, 0x91, 0x66, 0xb6, 0xa0, 0xd3, 0x4c, 0x99, 0x40, 0x8f, 0x7b, + 0x6c, 0x47, 0x9a, 0x9e, 0x5e, 0x46, 0x02, 0x74, 0x0b, 0x6f, 0x9d, 0x2f, 0x8f, 0xd7, 0x52, 0x4f, + 0xc6, 0xe6, 0x18, 0x7a, 0x3d, 0x27, 0xc3, 0x6a, 0x61, 0x93, 0xe2, 0xa6, 0xf5, 0x8e, 0xf3, 0x44, + 0x4e, 0x58, 0x29, 0x17, 0x0b, 0x7f, 0xb9, 0xdf, 0x3a, 0xa9, 0xc3, 0x8e, 0x5a, 0x91, 0xbe, 0x8c, + 0x2b, 0x8b, 0xaa, 0xbe, 0xb8, 0x52, 0xff, 0x24, 0xc8, 0x10, 0xe9, 0xf2, 0xd7, 0xa8, 0x4e, 0x5a, + 0x4e, 0x9c, 0x77, 0xa4, 0xc4, 0xa0, 0x0f, 0x83, 0xf6, 0x8c, 0xda, 0x30, 0xd1, 0x61, 0xbd, 0x6c, + 0x4d, 0x84, 0xf8, 0x0c, 0x41, 0x79, 0x84, 0x0a, 0x2d, 0xa2, 0x97, 0xcd, 0xa9, 0x5a, 0x65, 0xbb, + 0xda, 0xa9, 0xb4, 0xf2, 0x87, 0xe9, 0x57, 0x59, 0xdf, 0xd6, 0x08, 0xc2, 0xc2, 0x28, 0x07, 0xcc, + 0x2a, 0x1d, 0x19, 0xbe, 0xd3, 0x83, 0x34, 0x82, 0x94, 0xae, 0x43, 0xde, 0xa2, 0x49, 0xdd, 0x0e, + 0x35, 0x87, 0xae, 0xd3, 0x3d, 0x87, 0xca, 0x65, 0x4b, 0xbd, 0x75, 0x07, 0x4a, 0xe1, 0x00, 0x0f, + 0x4f, 0x5a, 0xaf, 0x7b, 0x44, 0x40, 0x6e, 0xaa, 0xea, 0xb7, 0xf4, 0xa2, 0xf5, 0x91, 0x9e, 0xc1, + 0xcc, 0x01, 0x3f, 0x9d, 0xb7, 0x25, 0x17, 0x57, 0xbb, 0xfa, 0x68, 0x4a, 0x98, 0x55, 0xd8, 0x34, + 0x60, 0xd9, 0x6d, 0x3e, 0x1a, 0xa7, 0xf2, 0x55, 0xe6, 0xd7, 0x3d, 0x57, 0xec, 0x7f, 0x6f, 0x3a, + 0xa0, 0xe6, 0x8b, 0x01, 0x74, 0x8a, 0x27, 0x8e, 0xb7, 0x72, 0x5a, 0xdf, 0xf9, 0xcf, 0x87, 0x41, + 0x1c, 0xf1, 0x6d, 0x1a, 0xf8, 0x25, 0x8c, 0xe7, 0xac, 0xc9, 0x80, 0x8f, 0xf3, 0x80, 0x37, 0x10, + 0x0e, 0x99, 0xd7, 0x20, 0x56, 0x28, 0x7c, 0x19, 0x26, 0xed, 0xbb, 0xe4, 0x6e, 0x9d, 0x87, 0x88, + 0xfd, 0xe1, 0x64, 0x05, 0xbf, 0x42, 0x54, 0x7a, 0x48, 0x5a, 0x16, 0xdc, 0x97, 0x88, 0xfa, 0x6a, + 0x05, 0x73, 0xd5, 0x27, 0x62, 0xf3, 0x51, 0x4a, 0xa2, 0x75, 0x84, 0x6b, 0xbc, 0xb5, 0x04, 0xaa, + 0xe4, 0xac, 0x95, 0xce, 0x02, 0xda, 0xb0, 0xd4, 0xa7, 0x96, 0xc4, 0xf1, 0x2f, 0x98, 0x34, 0x07, + 0xcd, 0xcb, 0x65, 0xe6, 0xcd, 0xba, 0x90, 0x57, 0x01, 0xd8, 0x1f, 0xe5, 0xe2, 0x47, 0x24, 0x20, + 0xc9, 0x41, 0x5b, 0x33, 0x5b, 0x6b, 0xf5, 0x40, 0x38, 0xba, 0x6f, 0x0d, 0x04, 0xe6, 0xd7, 0x2e, + 0x03, 0x33, 0x3a, 0x20, 0x86, 0x72, 0x42, 0x3a, 0x68, 0x2e, 0x9c, 0x2c, 0x41, 0xac, 0x19, 0x6c, + 0xad, 0x72, 0x0c, 0x27, 0x8f, 0xad, 0x91, 0x6a, 0x59, 0x1c, 0x0e, 0xb2, 0xe7, 0xd7, 0xbc, 0x90, + 0x48, 0x2e, 0xde, 0x67, 0xa6, 0xe6, 0xa5, 0xea, 0xd0, 0x7f, 0x8e, 0xfd, 0xaf, 0x17, 0x44, 0xa7, + 0x1f, 0x00, 0x9c, 0xff, 0xfc, 0xa4, 0xfe, 0x20, 0x95, 0xfe, 0xbc, 0xbe, 0x84, 0xd0, 0x1b, 0x52, + 0x4b, 0xc2, 0x87, 0xa7, 0xf2, 0xd5, 0x36, 0x76, 0x2a, 0x97, 0xb7, 0xaf, 0xc6, 0x41, 0x91, 0xe4, + 0xea, 0xe7, 0x61, 0xe2, 0x1d, 0xe6, 0x73, 0x51, 0x2a, 0x66, 0x34, 0x3a, 0xb1, 0xe9, 0xff, 0x38, + 0xd1, 0x61, 0xe8, 0xe7, 0x89, 0x1a, 0x67, 0x19, 0xb9, 0xef, 0x8e, 0x99, 0x6d, 0x99, 0x01, 0x7c, + 0x4a, 0xba, 0xf6, 0x1a, 0x62, 0xdd, 0xe4, 0xd6, 0x7d, 0x2c, 0x5e, 0x05, 0x37, 0xca, 0xa5, 0xed, + 0xff, 0x5c, 0xfd, 0xb1, 0xfa, 0x0c, 0x93, 0x10, 0x6b, 0xff, 0x96, 0xf3, 0x45, 0x5f, 0x22, 0xa1, + 0xd9, 0xfd, 0x5f, 0xb3, 0x93, 0xd7, 0xea, 0xc0, 0x6f, 0xda, 0xf4, 0x6a, 0xae, 0xe7, 0xaf, 0x69, + 0xee, 0x23, 0xaf, 0x50, 0xa1, 0x9a, 0xbe, 0xbb, 0x9a, 0xdc, 0xed, 0xd6, 0xa1, 0x0d, 0x87, 0xf6, + 0xfb, 0x61, 0x28, 0x0f, 0x4c, 0x5a, 0xa9, 0x4c, 0xfe, 0x4b, 0xb2, 0x72, 0x0f, 0xd9, 0x6c, 0xc9, + 0x74, 0xd2, 0xfd, 0xbd, 0x3f, 0x83, 0x05, 0x1c, 0xe7, 0x03, 0x9d, 0x53, 0x5b, 0xfc, 0xa4, 0x53, + 0x84, 0xaa, 0xba, 0xd3, 0x0c, 0x96, 0x29, 0xca, 0xd4, 0xe5, 0x8a, 0x61, 0xbd, 0x7f, 0x98, 0x4d, + 0x16, 0xd2, 0xfe, 0xfa, 0x56, 0xe1, 0x90, 0x09, 0x8d, 0xb1, 0x73, 0x92, 0x36, 0x30, 0x87, 0x99, + 0xba, 0xbc, 0x0a, 0xc3, 0x1c, 0x86, 0x8c, 0xa1, 0xf4, 0x1f, 0xe1, 0xda, 0xcf, 0xc5, 0xe1, 0xd7, + 0xb5, 0xf1, 0xa2, 0xbc, 0x7f, 0x32, 0x9a, 0x96, 0x09, 0x9e, 0x8f, 0xce, 0x47, 0x85, 0x78, 0xe4, + 0x55, 0x8e, 0xc0, 0xae, 0xdc, 0x28, 0x11, 0xcc, 0x2c, 0xe0, 0x71, 0x8d, 0x67, 0x19, 0xbb, 0xed, + 0x36, 0xd5, 0xcb, 0xdb, 0xf5, 0x74, 0x41, 0xd7, 0xd5, 0xa4, 0xe6, 0x85, 0x7b, 0xde, 0xa4, 0x6a, + 0x2b, 0x29, 0x9b, 0x4d, 0x86, 0xc0, 0xc6, 0x11, 0x9c, 0xbf, 0xec, 0x65, 0xb1, 0x41, 0x81, 0xc9, + 0xf0, 0xe7, 0x6b, 0xd1, 0x2e, 0xd2, 0xd2, 0xb9, 0x7f, 0x14, 0x26, 0xd9, 0x81, 0x77, 0x21, 0x0e, + 0x69, 0xfe, 0xd5, 0x8f, 0x5b, 0xbe, 0x53, 0x93, 0x28, 0x4c, 0x9f, 0xaa, 0x5a, 0x05, 0x53, 0x13, + 0x1c, 0xda, 0x76, 0x1e, 0x08, 0xfe, 0xc3, 0x45, 0x82, 0x8e, 0x38, 0x80, 0x87, 0x04, 0xdc, 0x23, + 0x3c, 0x5b, 0x06, 0xb7, 0xb3, 0xd5, 0x20, 0x18, 0x99, 0x4f, 0x3b, 0xcc, 0x29, 0x9d, 0x72, 0xf9, + 0x45, 0x5c, 0x33, 0xb5, 0x6c, 0x82, 0x53, 0x8b, 0x4a, 0xa0, 0x8f, 0xd9, 0xef, 0x00, 0x74, 0xf3, + 0xd5, 0x38, 0x7c, 0x40, 0x5b, 0xb4, 0xd1, 0x66, 0xcd, 0x00, 0xbd, 0xcb, 0xf2, 0x58, 0xca, 0xf8, + 0xba, 0x9d, 0x4c, 0xa9, 0xb3, 0xd9, 0x91, 0x48, 0x89, 0xf2, 0xb5, 0xfe, 0x2e, 0x93, 0x6e, 0x83, + 0xfb, 0xcd, 0x66, 0x67, 0x6f, 0x3b, 0x00, 0xfd, 0xba, 0xe7, 0x4a, 0xe8, 0x37, 0xa6, 0x05, 0x15, + 0x6a, 0xf7, 0xdf, 0x46, 0x9e, 0x2c, 0xfe, 0xd8, 0x89, 0xa1, 0xd5, 0x2a, 0x61, 0xb2, 0x66, 0xd0, + 0xbc, 0x7d, 0x00, 0xad, 0x93, 0xe2, 0xa1, 0xa4, 0xa6, 0xfc, 0x64, 0x19, 0x41, 0xcd, 0xea, 0xc0, + 0xda, 0x6b, 0xd9, 0x0c, 0x8f, 0x30, 0xdb, 0xb4, 0x1d, 0xdc, 0x6c, 0x3a, 0xdd, 0xdd, 0x56, 0xd8, + 0x9a, 0x44, 0xb6, 0x34, 0x89, 0x6c, 0x47, 0xb3, 0xac, 0xc3, 0x60, 0x5b, 0x12, 0x8b, 0x64, 0x10, + 0xd0, 0xbc, 0xfe, 0x4a, 0x3b, 0xe5, 0x7b, 0x46, 0x3a, 0xaa, 0xec, 0xef, 0x7a, 0x37, 0x73, 0x48, + 0x35, 0xb9, 0x51, 0xa5, 0x93, 0xc0, 0xcf, 0x41, 0xa9, 0xc6, 0xcd, 0x8e, 0xf0, 0xb0, 0xbf, 0x47, + 0x5f, 0xd5, 0x92, 0xcd, 0x05, 0xd7, 0x69, 0x0a, 0x91, 0x96, 0x06, 0x30, 0x2f, 0x49, 0x8d, 0xfc, + 0x45, 0x96, 0xb5, 0x3a, 0x29, 0x2e, 0xf6, 0xf0, 0xa3, 0x42, 0x9e, 0xdc, 0x3c, 0xe5, 0x57, 0x3d, + 0xb6, 0x95, 0x2c, 0x4f, 0x85, 0xee, 0x26, 0x0a, 0x92, 0x7a, 0xa9, 0xab, 0xcd, 0x5c, 0x51, 0x05, + 0xeb, 0xb3, 0x32, 0x1d, 0xc9, 0x99, 0x64, 0x5c, 0x1d, 0x5d, 0x18, 0x7a, 0x8d, 0xe8, 0xbd, 0x7e, + 0x3b, 0x4d, 0x0d, 0x64, 0xba, 0xca, 0xf3, 0xb7, 0xb3, 0xf7, 0xfc, 0xe0, 0x77, 0xde, 0x79, 0xe7, + 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, + 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0xff, + 0x3d, 0xf9, 0xcf, 0xf7, 0xc1, 0x7f, 0x1f, 0xbf, 0x11, 0x0d, 0xeb, 0x0f, 0x33, 0x1f, 0x57, 0x63, + 0xdb, 0x81, 0x20, 0x2b, 0x53, 0x7a, 0xc2, 0x84, 0x39, 0x68, 0xba, 0x2c, 0x32, 0x78, 0x03, 0xe1, + 0x58, 0xec, 0xb0, 0xbe, 0x2a, 0x5e, 0x3b, 0x64, 0x7e, 0xbe, 0x54, 0xa1, 0xd9, 0x55, 0x2d, 0xf4, + 0x7f, 0x89, 0xf3, 0x98, 0x56, 0x85, 0x1f, 0x03, 0x2c, 0xf9, 0x31, 0x8c, 0xad, 0xf2, 0x44, 0x9e, + 0x48, 0x28, 0x25, 0x6e, 0x07, 0xd8, 0xa9, 0xb5, 0x70, 0x20, 0x94, 0x5a, 0x6b, 0x07, 0x52, 0x29, + 0x49, 0x38, 0x70, 0xce, 0x3b, 0x7e, 0x4a, 0xc1, 0xb7, 0x66, 0xd9, 0xd4, 0x14, 0xa8, 0x38, 0x8f, + 0xd4, 0xe7, 0x24, 0x38, 0x57, 0x04, 0x8b, 0xd7, 0xea, 0x72, 0xb1, 0x41, 0x6d, 0xb3, 0x26, 0x9f, + 0x4f, 0x35, 0x6c, 0xb9, 0x74, 0xbd, 0xc4, 0x48, 0x9f, 0x37, 0xd8, 0x9b, 0x2d, 0x42, 0xb3, 0x83, + 0xf1, 0xf7, 0xf7, 0xd3, 0x04, 0x8f, 0x0f, 0x51, 0xa9, 0x25, 0xc4, 0x02, 0xb1, 0xb8, 0x1e, 0x28, + 0x35, 0xfd, 0x26, 0xf9, 0x12, 0x5d, 0x42, 0x0d, 0x5f, 0x22, 0x21, 0x51, 0xe9, 0xf0, 0x72, 0xbc, + 0x97, 0xf3, 0x42, 0x96, 0xf2, 0xda, 0xfe, 0x53, 0x88, 0xb1, 0x02, 0xff, 0xca, 0x4c, 0x9b, 0x40, + 0x88, 0x33, 0x47, 0x49, 0x7b, 0x21, 0xc9, 0x7e, 0x2c, 0xa0, 0x03, 0xdd, 0x96, 0x74, 0x08, 0x8b, + 0x79, 0x11, 0x3e, 0x77, 0x60, 0x41, 0xc2, 0x16, 0x49, 0x2c, 0x8c, 0xe3, 0xd0, 0x41, 0x76, 0x24, + 0x8e, 0x49, 0x2a, 0xaf, 0xd2, 0x7b, 0x75, 0x27, 0x11, 0x5e, 0xf7, 0x7a, 0x0a, 0xe1, 0x43, 0xaf, + 0x67, 0x29, 0xec, 0xf1, 0x7a, 0x0c, 0xe1, 0xe3, 0xe4, 0x9f, 0x48, 0xfc, 0x2e, 0xe8, 0x5a, 0x05, + 0xf7, 0x51, 0xb2, 0x63, 0x18, 0x42, 0x5d, 0x16, 0xaf, 0xe4, 0x0f, 0x4d, 0x5b, 0xa5, 0x77, 0x3e, + 0x0d, 0xcf, 0x82, 0xfd, 0xa3, 0xc1, 0x23, 0xc4, 0x47, 0x0a, 0x9e, 0x11, 0xa8, 0xe4, 0xe4, 0x87, + 0x1e, 0xb6, 0x74, 0x35, 0x16, 0x20, 0x11, 0xd3, 0x8e, 0x1b, 0xd2, 0x26, 0xf6, 0x06, 0xbf, 0xc6, + 0x24, 0x4d, 0x6d, 0x29, 0xfe, 0xde, 0xf4, 0x8d, 0x04, 0x51, 0xaa, 0xc1, 0x7b, 0x6d, 0xa9, 0xce, + 0xe5, 0x87, 0xf7, 0xc3, 0xa9, 0xd8, 0xb3, 0x3b, 0x00, 0x17, 0x78, 0xe9, 0xb3, 0x94, 0xa8, 0x13, + 0x4d, 0xa0, 0x80, 0x0e, 0xef, 0xab, 0x8d, 0xeb, 0x8f, 0x17, 0x68, 0x66, 0xed, 0x7b, 0xf0, 0x56, + 0xa6, 0xda, 0x67, 0xec, 0x15, 0xb1, 0x98, 0xd1, 0x6c, 0x69, 0x9f, 0x18, 0x75, 0x85, 0xf1, 0x58, + 0x88, 0x8a, 0x05, 0xf2, 0x6a, 0x57, 0x73, 0x89, 0xea, 0x8d, 0x90, 0x5f, 0x3a, 0x72, 0x10, 0x80, + 0xff, 0xb2, 0x65, 0x60, 0x20, 0xe8, 0xbc, 0xf8, 0x1c, 0x63, 0xf4, 0x8a, 0x7b, 0xdc, 0xab, 0xe6, + 0x49, 0xb7, 0xcf, 0xb2, 0x72, 0x14, 0x82, 0xa7, 0xcb, 0x6e, 0xe0, 0x4f, 0xa4, 0x02, 0x43, 0x9e, + 0xc0, 0xbc, 0xf4, 0x85, 0xd9, 0x9a, 0x97, 0xec, 0x30, 0x06, 0x39, 0x80, 0x7b, 0x42, 0xf3, 0xb2, + 0x6d, 0x44, 0xae, 0xea, 0x8a, 0xc7, 0xf2, 0xf9, 0x7d, 0xf4, 0x54, 0xa0, 0xc8, 0xc4, 0xce, 0xb2, + 0x62, 0x1f, 0x02, 0x33, 0xb7, 0xa4, 0xa7, 0x3c, 0xaf, 0x93, 0x88, 0xc7, 0x22, 0xdd, 0xd3, 0x59, + 0x23, 0x20, 0x3a, 0x3e, 0x1b, 0x15, 0xa4, 0x12, 0xa2, 0xa5, 0x12, 0xe7, 0x20, 0xee, 0x8a, 0xd0, + 0xe2, 0x6e, 0x27, 0x85, 0xc4, 0xe5, 0x98, 0x4b, 0x48, 0xc8, 0x59, 0xf9, 0x3c, 0x60, 0x1d, 0xcf, + 0x60, 0xc7, 0x34, 0x2d, 0x07, 0x94, 0x8f, 0x48, 0xfd, 0x93, 0x30, 0x53, 0x0f, 0x8a, 0x24, 0xc8, + 0xd1, 0x07, 0xd9, 0xc6, 0x4e, 0x9d, 0x4b, 0xde, 0x07, 0x34, 0x72, 0x91, 0x56, 0xdb, 0x02, 0x09, + 0x5e, 0x62, 0x98, 0x6e, 0x1d, 0x6f, 0xc8, 0xf9, 0xe5, 0xd3, 0xb4, 0xbb, 0x9c, 0x90, 0x3c, 0x85, + 0xae, 0x85, 0x62, 0xfd, 0x61, 0x01, 0x93, 0x7a, 0xec, 0xb7, 0x84, 0x14, 0x53, 0x2f, 0x86, 0x25, + 0x98, 0xda, 0x48, 0xc8, 0x14, 0x81, 0x65, 0xf1, 0xb6, 0xff, 0x2a, 0x6d, 0x96, 0x1c, 0x07, 0xb2, + 0x36, 0x33, 0x0d, 0xa7, 0x16, 0xb4, 0x2a, 0x5c, 0x0e, 0xe2, 0xf7, 0x1a, 0xf6, 0x8a, 0xf2, 0xfe, + 0xd7, 0x38, 0x3b, 0xb6, 0xfe, 0x37, 0xa6, 0xf3, 0xbf, 0xc6, 0x24, 0x1d, 0xb1, 0x92, 0x57, 0x6f, + 0xc8, 0xff, 0x3d, 0x26, 0xa9, 0x77, 0xfb, 0x12, 0x26, 0xed, 0xfa, 0xfe, 0x3f, 0xff, 0xff, 0x10, + 0x93, 0x64, 0x3a, 0x47, 0xff, 0x1f, 0x62, 0x92, 0x0e, 0x64, 0x2b, 0x61, 0xc1, 0x7a, 0xf5, 0x6f, + 0x6a, 0x9b, 0xb1, 0x7f, 0x63, 0x3a, 0xc3, 0xf3, 0x3e, 0x26, 0x1a, 0xe8, 0x86, 0x79, 0x0b, 0x5e, + 0xbd, 0x38, 0x3e, 0x09, 0xdc, 0x98, 0x48, 0xcf, 0x54, 0xae, 0x8d, 0xc2, 0x53, 0x15, 0x69, 0x80, + 0x3b, 0xb5, 0xa5, 0x87, 0x95, 0x1f, 0x57, 0xe3, 0xcc, 0xbf, 0xb2, 0xb9, 0x5c, 0x9c, 0x3d, 0xa5, + 0x2a, 0x3c, 0x31, 0xf9, 0x88, 0x75, 0x63, 0xd1, 0xe8, 0x2c, 0x9e, 0x8c, 0xec, 0x7d, 0x44, 0x7b, + 0x2d, 0x10, 0x3f, 0xc4, 0x8e, 0xf1, 0x7b, 0x9d, 0x26, 0x92, 0xeb, 0x5a, 0xd6, 0x93, 0x4b, 0x3c, + 0xad, 0x72, 0x21, 0xc7, 0x73, 0xf8, 0x3c, 0x42, 0xd4, 0x9c, 0xe1, 0xcc, 0xc8, 0x9f, 0x1e, 0x92, + 0xe5, 0xa2, 0xe3, 0x20, 0x10, 0x2a, 0xea, 0x90, 0x4d, 0x0c, 0xde, 0x3d, 0x19, 0x09, 0x7a, 0x96, + 0x8d, 0x8f, 0x0d, 0xd4, 0xe2, 0x4d, 0xb4, 0x8d, 0x06, 0x90, 0x0c, 0xe1, 0xb6, 0xb5, 0x32, 0x2b, + 0x33, 0x58, 0x27, 0x67, 0x79, 0x7f, 0xed, 0x93, 0x1f, 0x79, 0x0f, 0xc1, 0x52, 0xbd, 0x6c, 0x5e, + 0x9f, 0x24, 0x2c, 0xdf, 0x26, 0x80, 0x2c, 0x55, 0x35, 0x60, 0xdd, 0xbe, 0x89, 0xf6, 0x38, 0x97, + 0x85, 0x8f, 0xb0, 0x28, 0xe6, 0xa4, 0x7b, 0x85, 0x9c, 0x23, 0x81, 0xb1, 0xa7, 0xf7, 0xf6, 0x7b, + 0xf9, 0xb6, 0x89, 0xe6, 0x28, 0xe7, 0xba, 0x3e, 0x0f, 0x77, 0x54, 0xea, 0xd7, 0x78, 0xfd, 0xa7, + 0x93, 0x51, 0xaa, 0xbf, 0xeb, 0xab, 0xdf, 0xce, 0xe9, 0x1e, 0x9a, 0xea, 0xde, 0xc1, 0xc1, 0x42, + 0x99, 0xc9, 0x3c, 0x66, 0x2c, 0xbd, 0xd2, 0xf1, 0x51, 0x6b, 0x12, 0x7f, 0x18, 0xb1, 0xdb, 0x45, + 0x74, 0x71, 0x96, 0x34, 0xd7, 0xd8, 0x63, 0xbe, 0xee, 0x80, 0xd3, 0x2a, 0x3e, 0x5b, 0xc7, 0x37, + 0xb7, 0xbb, 0x41, 0xcb, 0x58, 0xe8, 0xee, 0xbd, 0x21, 0xf9, 0xfd, 0x53, 0x17, 0xd6, 0x36, 0x7d, + 0x09, 0xdc, 0x86, 0xbf, 0x9d, 0x24, 0x43, 0xc5, 0x6f, 0xd0, 0xa2, 0xcc, 0x99, 0x70, 0x5d, 0xdc, + 0x54, 0xad, 0x4d, 0x60, 0x1a, 0x3d, 0x50, 0xee, 0x06, 0xee, 0x2d, 0xeb, 0x0f, 0x37, 0x26, 0x7f, + 0x9c, 0x33, 0xf3, 0x47, 0x1b, 0x01, 0x7e, 0x8d, 0xb3, 0xb3, 0xfc, 0xc6, 0x34, 0x2b, 0x66, 0x08, + 0x10, 0x9d, 0x32, 0x76, 0x0a, 0xcd, 0x19, 0x0b, 0x8a, 0x0c, 0x6b, 0xba, 0x8a, 0x1c, 0x76, 0x53, + 0xd4, 0xce, 0x0b, 0x63, 0xb7, 0xae, 0x61, 0xd9, 0xbe, 0x61, 0x63, 0x59, 0xa3, 0xf0, 0xa1, 0xbe, + 0xe9, 0x57, 0x33, 0x86, 0x4f, 0xd1, 0xa2, 0x20, 0x9a, 0x2b, 0xab, 0x6c, 0x5b, 0xd9, 0x64, 0x26, + 0x9d, 0xea, 0x52, 0x44, 0xf2, 0xa1, 0xcd, 0xc7, 0x3a, 0x9a, 0xcd, 0x89, 0xa4, 0x8b, 0x0e, 0x09, + 0x45, 0xa9, 0x3e, 0x5a, 0x50, 0x19, 0x10, 0x8c, 0xd5, 0x0e, 0x3f, 0x56, 0xca, 0x68, 0x07, 0xe5, + 0x21, 0xdb, 0xde, 0x8f, 0x30, 0x88, 0x49, 0x03, 0x65, 0xfb, 0x6d, 0xb8, 0x65, 0xb4, 0x8a, 0xcd, + 0xb0, 0x08, 0x4b, 0x2b, 0x7d, 0xa1, 0x7c, 0x36, 0x5d, 0x0f, 0x4e, 0xdf, 0x5f, 0x20, 0x0a, 0xfb, + 0x76, 0x17, 0x4f, 0x0b, 0xd6, 0xa2, 0xe7, 0x8d, 0x42, 0x0e, 0x5a, 0x08, 0x96, 0xe3, 0x17, 0xaf, + 0xb9, 0x5b, 0x17, 0x15, 0x9c, 0x36, 0xe5, 0x20, 0xeb, 0xb9, 0x69, 0x3d, 0x1d, 0xba, 0x49, 0x29, + 0x63, 0x01, 0x4e, 0x4e, 0x09, 0x3b, 0xd9, 0xb9, 0xde, 0x64, 0x63, 0x7a, 0xb2, 0x16, 0x46, 0xc3, + 0xda, 0x3b, 0xc0, 0x22, 0x78, 0xdd, 0xa1, 0x82, 0x7c, 0xe3, 0x43, 0x7c, 0x76, 0x18, 0xed, 0x81, + 0xde, 0x19, 0x8b, 0xfb, 0x0b, 0xce, 0x5d, 0x20, 0x5e, 0xdf, 0x52, 0x37, 0x39, 0xa9, 0x77, 0x53, + 0xeb, 0x1a, 0x36, 0x7a, 0x80, 0x27, 0xee, 0x9a, 0x09, 0xbb, 0x0e, 0x1f, 0x3b, 0xa0, 0x11, 0x80, + 0x36, 0x14, 0x14, 0x15, 0x6c, 0xe8, 0xf8, 0x25, 0x8c, 0x25, 0xa3, 0x91, 0x07, 0x86, 0x55, 0x0b, + 0xce, 0xa5, 0xa5, 0xc8, 0xc8, 0xd9, 0xc4, 0x86, 0x6b, 0x13, 0x0b, 0xfb, 0xf6, 0x38, 0xc0, 0x42, + 0xb4, 0xfb, 0x89, 0x08, 0xea, 0x9e, 0xb4, 0x42, 0x82, 0xb5, 0xa6, 0x94, 0x88, 0xc3, 0xc6, 0xb5, + 0x10, 0xcf, 0x04, 0xe9, 0x2a, 0x4c, 0x2f, 0xa0, 0xf8, 0x5f, 0x0a, 0xcc, 0x56, 0x7e, 0xad, 0xe9, + 0xae, 0xb6, 0xff, 0xc6, 0xf4, 0xac, 0x54, 0x04, 0x2d, 0xaa, 0x04, 0x0f, 0x38, 0xa2, 0x73, 0xb9, + 0x3d, 0xe4, 0x66, 0x46, 0x9a, 0x2c, 0x1b, 0xc4, 0x8a, 0x03, 0x3a, 0x70, 0xeb, 0xfe, 0x12, 0xee, + 0xe8, 0xc2, 0x87, 0x87, 0x23, 0x91, 0xb4, 0x7e, 0x1c, 0xe2, 0x16, 0x55, 0xc1, 0x0f, 0xd2, 0x7b, + 0x48, 0x6d, 0xe8, 0x8b, 0x95, 0xb5, 0x4d, 0x71, 0x18, 0x9a, 0xcd, 0x16, 0x64, 0x8e, 0x47, 0xc6, + 0xd0, 0xf1, 0xa6, 0xe6, 0x25, 0x26, 0x1c, 0xb0, 0xdd, 0xed, 0x92, 0x2b, 0xa9, 0x7b, 0x14, 0x3a, + 0x64, 0x94, 0x8a, 0x18, 0x7a, 0x1b, 0x19, 0x5e, 0x1c, 0xa6, 0xbb, 0x7a, 0x66, 0x8a, 0x95, 0xbd, + 0x95, 0xa4, 0xac, 0xc2, 0xda, 0x17, 0xf2, 0x9a, 0xe5, 0xd8, 0x20, 0x67, 0xb5, 0xeb, 0xe7, 0x3e, + 0x2b, 0x7f, 0x04, 0x02, 0x1b, 0xab, 0x15, 0x68, 0x61, 0x22, 0xca, 0x5c, 0x40, 0x1c, 0xa5, 0x02, + 0x3c, 0x9a, 0x2b, 0x8b, 0xdd, 0x57, 0xa1, 0x85, 0xd8, 0xe5, 0xbf, 0xd9, 0x9f, 0xac, 0x3e, 0x5f, + 0x57, 0x75, 0xec, 0xbe, 0x08, 0x0a, 0x15, 0x49, 0x7f, 0x4b, 0x95, 0x15, 0x77, 0xa7, 0x94, 0xc7, + 0x3e, 0xf5, 0x92, 0x84, 0x1f, 0xb0, 0xd6, 0xbb, 0xd2, 0xfd, 0x14, 0xc7, 0x7a, 0x7a, 0x08, 0x05, + 0x38, 0xfb, 0x77, 0x47, 0x9f, 0x85, 0xbe, 0x35, 0x28, 0x14, 0xfd, 0x86, 0x63, 0x0b, 0x55, 0x0b, + 0x84, 0x59, 0xaa, 0xd0, 0x63, 0xf9, 0xdc, 0x91, 0xfb, 0x8e, 0x59, 0x49, 0x34, 0x59, 0x41, 0x55, + 0x56, 0x95, 0x57, 0x64, 0xc0, 0x4b, 0x89, 0x09, 0x9f, 0x34, 0x5a, 0x9b, 0x9c, 0x6b, 0x5d, 0xc0, + 0x7e, 0xab, 0x7c, 0x62, 0x84, 0xa6, 0x6b, 0x1d, 0xe4, 0x5c, 0x82, 0x22, 0x3d, 0xa4, 0xbf, 0xde, + 0x0c, 0xdf, 0x2a, 0x09, 0xf5, 0x11, 0x21, 0x7e, 0x41, 0xa6, 0x36, 0x22, 0x43, 0xa0, 0x97, 0x12, + 0xdd, 0x1f, 0xfa, 0x53, 0x86, 0x18, 0x2e, 0x5b, 0x95, 0x13, 0xe7, 0x81, 0xd0, 0xb4, 0xf4, 0x04, + 0x45, 0x84, 0x07, 0xf5, 0x63, 0x42, 0x82, 0x42, 0x91, 0xb6, 0x25, 0xfa, 0xa5, 0x3d, 0xd2, 0x2a, + 0x1e, 0x7e, 0xad, 0xca, 0x6c, 0x01, 0x7e, 0x63, 0x9a, 0x5f, 0x38, 0x76, 0x67, 0x66, 0xc3, 0x20, + 0xd5, 0x3c, 0xbf, 0xdd, 0x08, 0x40, 0xea, 0xec, 0xed, 0x65, 0x3d, 0xc0, 0xb1, 0x79, 0x3e, 0xe0, + 0x20, 0xf0, 0x74, 0x64, 0xb4, 0xe9, 0x9f, 0xbc, 0xd4, 0xbc, 0xc9, 0xa3, 0x5e, 0x42, 0x9d, 0x1d, + 0x68, 0xc9, 0xa8, 0xec, 0xfa, 0xd4, 0x21, 0x85, 0xf5, 0xb0, 0x3f, 0xdf, 0xb3, 0x34, 0x53, 0x3a, + 0x73, 0x73, 0x0e, 0xc5, 0x76, 0x3d, 0x3b, 0xf9, 0x6e, 0x1b, 0xa2, 0xed, 0x7d, 0x05, 0xd5, 0x2c, + 0xff, 0xbc, 0x37, 0x23, 0x69, 0x8e, 0x8c, 0x3c, 0x8e, 0x87, 0x87, 0x97, 0xcd, 0xbc, 0xce, 0xe8, + 0x4e, 0xce, 0xae, 0xae, 0x95, 0x10, 0xab, 0xdc, 0xbd, 0x96, 0xca, 0xf6, 0xcc, 0x3b, 0x50, 0x64, + 0x75, 0xcd, 0x3d, 0xb1, 0x64, 0xff, 0xda, 0x87, 0x96, 0x56, 0x23, 0x2f, 0xc8, 0xea, 0xaa, 0xf4, + 0xe4, 0x48, 0x60, 0x72, 0xc3, 0x7a, 0x24, 0xf5, 0xed, 0xb2, 0x2e, 0xfa, 0x74, 0xe9, 0xf6, 0x4e, + 0x97, 0x7f, 0x0e, 0x01, 0x22, 0xf6, 0xb3, 0x84, 0x2e, 0x96, 0x8f, 0x9f, 0x53, 0x5b, 0x5c, 0xc5, + 0xe9, 0x94, 0xd3, 0xa8, 0xd2, 0x2f, 0x6f, 0x9a, 0x44, 0x8e, 0x0c, 0x4b, 0x74, 0xaf, 0x84, 0x3e, + 0x4f, 0x03, 0x6f, 0x27, 0xf8, 0x1c, 0x75, 0xd7, 0x40, 0xed, 0xf7, 0x36, 0x5b, 0x40, 0x29, 0x7d, + 0x3e, 0x0a, 0x65, 0x95, 0x07, 0xcd, 0x85, 0x90, 0x80, 0x0c, 0xcc, 0x72, 0xef, 0x46, 0x38, 0xa2, + 0x70, 0xd4, 0xb1, 0x90, 0x2c, 0x21, 0x0d, 0x72, 0xf4, 0x3b, 0x03, 0x77, 0x58, 0x1a, 0x3e, 0x2c, + 0x07, 0xcb, 0xe0, 0x49, 0xdf, 0xde, 0xca, 0x6f, 0xa0, 0x6d, 0x60, 0xe4, 0xcf, 0xa8, 0x6d, 0x3b, + 0x9d, 0xd4, 0x42, 0xcc, 0x04, 0x7f, 0x48, 0x5a, 0x4b, 0xde, 0xd6, 0xcd, 0xf4, 0x76, 0x72, 0x33, + 0x57, 0x7c, 0x20, 0xff, 0xc4, 0x9d, 0x3d, 0x69, 0x70, 0x45, 0x52, 0x84, 0x88, 0xeb, 0xd9, 0xca, + 0x03, 0x2c, 0xdf, 0xdb, 0x73, 0xb1, 0xec, 0xd3, 0x2f, 0xdd, 0xce, 0xe7, 0x05, 0xad, 0xda, 0x55, + 0x84, 0xc1, 0x4b, 0x7a, 0xc5, 0xe6, 0xb6, 0xa0, 0xbf, 0xee, 0x4f, 0x11, 0xfa, 0x8d, 0x69, 0x21, + 0x1a, 0x06, 0x14, 0x64, 0xce, 0xa7, 0xfb, 0xf9, 0x40, 0xfe, 0xaf, 0x29, 0x63, 0xd9, 0xb5, 0x8e, + 0x22, 0x00, 0x20, 0xbb, 0x21, 0x02, 0xe5, 0xc1, 0x8a, 0xb1, 0x04, 0xd1, 0x42, 0x52, 0xf4, 0x39, + 0xa8, 0xc0, 0xa7, 0x11, 0x5d, 0xfd, 0xfd, 0xb0, 0xff, 0x3a, 0xcc, 0xc2, 0xfe, 0x75, 0xcf, 0x15, + 0xe4, 0x37, 0xa6, 0x97, 0xb6, 0x6a, 0xeb, 0x30, 0xc9, 0x15, 0xfb, 0x21, 0x76, 0x77, 0x1d, 0xfa, + 0x12, 0xe2, 0xef, 0x49, 0x3e, 0x32, 0x39, 0x5e, 0x25, 0xd8, 0xd6, 0x7e, 0x3d, 0x39, 0xbc, 0xd9, + 0xda, 0xc3, 0xf5, 0x6c, 0xe6, 0xd9, 0x11, 0x69, 0xba, 0xf6, 0x25, 0x1c, 0x35, 0x70, 0xa0, 0x0a, + 0xc8, 0x95, 0xce, 0xf3, 0xb3, 0x8c, 0xd6, 0x41, 0x78, 0xb2, 0x02, 0x3e, 0xf5, 0x21, 0xf4, 0x1c, + 0x3b, 0xd5, 0xe7, 0x17, 0xa4, 0xa5, 0x64, 0x7e, 0xde, 0xd5, 0x66, 0x36, 0x60, 0x52, 0x7a, 0x56, + 0x35, 0x95, 0xce, 0xaf, 0x18, 0xd0, 0x41, 0x05, 0xc2, 0xe9, 0xd8, 0x81, 0x5a, 0x9b, 0x38, 0x6e, + 0xb2, 0x0a, 0x06, 0x6f, 0x73, 0xab, 0xba, 0xe5, 0xa8, 0xd9, 0xb8, 0xcf, 0xce, 0x53, 0x0f, 0x56, + 0x36, 0xed, 0x44, 0x2a, 0xad, 0x8c, 0x7f, 0xbc, 0x12, 0x1e, 0xd6, 0xdc, 0xf5, 0x76, 0x18, 0xa2, + 0x57, 0x47, 0x94, 0xef, 0x38, 0x24, 0x13, 0x06, 0x22, 0x35, 0xca, 0xac, 0xb6, 0xe8, 0x57, 0xae, + 0x21, 0x64, 0x3a, 0xaa, 0xf0, 0xa5, 0x42, 0x40, 0x5f, 0x1c, 0xd0, 0x85, 0xc3, 0xb8, 0xa2, 0x98, + 0x1a, 0x84, 0x87, 0x61, 0x83, 0x6b, 0x30, 0xc5, 0x95, 0x31, 0x28, 0x09, 0x4b, 0xf6, 0x25, 0x14, + 0xae, 0x00, 0xef, 0x5e, 0x52, 0x42, 0x42, 0x75, 0x86, 0x89, 0x48, 0x5b, 0x72, 0x46, 0xfc, 0x5f, + 0x73, 0x8a, 0x36, 0x7c, 0x2d, 0x17, 0x19, 0xd2, 0xe1, 0xb2, 0x02, 0xc2, 0x29, 0xde, 0x0d, 0x69, + 0x6c, 0xa1, 0x96, 0x7b, 0x0d, 0xae, 0xe4, 0xf9, 0x36, 0x1f, 0x03, 0xda, 0xc8, 0x03, 0xc5, 0x88, + 0xbf, 0xa1, 0xc7, 0x78, 0x55, 0x77, 0xe1, 0x9d, 0x8e, 0xe6, 0x4f, 0x1e, 0x13, 0x86, 0xab, 0x40, + 0xf9, 0x5a, 0x74, 0x30, 0xda, 0x10, 0xf2, 0x74, 0x80, 0xeb, 0x56, 0xa1, 0x7c, 0x40, 0xe7, 0xa5, + 0xd5, 0xcb, 0x90, 0x1e, 0xa9, 0xc2, 0xa0, 0xd5, 0x2c, 0x65, 0x3e, 0xca, 0x78, 0x92, 0x47, 0x64, + 0xf8, 0x8c, 0x1e, 0x87, 0x49, 0xf1, 0xe9, 0x7e, 0x83, 0xda, 0x72, 0x7a, 0xeb, 0xbf, 0xee, 0x23, + 0x74, 0xf3, 0x1b, 0xd3, 0xdc, 0x94, 0xf6, 0xbc, 0xc4, 0xf4, 0x7d, 0x58, 0x60, 0x6b, 0xbe, 0x77, + 0x39, 0xf9, 0x18, 0x23, 0x77, 0xc6, 0x1d, 0xeb, 0x4e, 0xe0, 0xb8, 0x2f, 0x48, 0xaf, 0x95, 0x27, + 0xf2, 0x7b, 0xaa, 0x4e, 0x00, 0x10, 0xa6, 0xb6, 0xbf, 0x82, 0xd5, 0x8b, 0x32, 0xeb, 0x60, 0x13, + 0x62, 0xc0, 0xe1, 0x7a, 0x25, 0x48, 0xee, 0xe0, 0x47, 0xe7, 0x95, 0x38, 0xf6, 0x73, 0x9c, 0x40, + 0x31, 0x88, 0xa5, 0x3d, 0xd6, 0x97, 0xc8, 0xc2, 0xc0, 0xf8, 0x98, 0x34, 0x21, 0x77, 0xf4, 0x6d, + 0x3e, 0xe7, 0x91, 0xc9, 0xcb, 0x1b, 0xe9, 0xab, 0xbc, 0x85, 0x52, 0xfa, 0x51, 0x2e, 0xed, 0x4f, + 0x7d, 0xe4, 0x82, 0xe8, 0x94, 0x48, 0x79, 0x0b, 0xb9, 0x61, 0xae, 0xce, 0x7c, 0x92, 0x9f, 0x45, + 0x0e, 0x3e, 0xce, 0xce, 0xaa, 0x24, 0x41, 0x36, 0x57, 0x77, 0xa0, 0x9c, 0x66, 0x46, 0x08, 0x81, + 0xfe, 0xe1, 0xd4, 0x4c, 0x51, 0xa2, 0xe3, 0xc0, 0x11, 0xeb, 0x8f, 0xdd, 0x03, 0x75, 0x45, 0x82, + 0xea, 0x16, 0x37, 0xe3, 0x60, 0x52, 0xdb, 0xca, 0xc8, 0x64, 0x8e, 0x10, 0x3f, 0x16, 0x4f, 0x45, + 0x98, 0xe1, 0x3a, 0xcd, 0x02, 0x4e, 0x4d, 0x78, 0x33, 0x63, 0x68, 0xc3, 0x1f, 0x57, 0x75, 0x67, + 0xc3, 0x8a, 0xeb, 0xce, 0x03, 0x71, 0x81, 0x5c, 0xe9, 0x88, 0x85, 0x80, 0xe7, 0xbe, 0xe4, 0xb4, + 0xc4, 0x8a, 0x2e, 0xc9, 0xc3, 0x50, 0x29, 0x22, 0x00, 0x2e, 0x3c, 0xec, 0x3f, 0xc0, 0x44, 0x4d, + 0xcd, 0xf5, 0x28, 0x7c, 0xe5, 0x82, 0x35, 0xce, 0x52, 0x14, 0xa8, 0x09, 0xa4, 0x1f, 0xab, 0xf6, + 0xf1, 0x73, 0x3a, 0xf2, 0x05, 0xd3, 0x22, 0x2f, 0x74, 0xaa, 0x68, 0x7d, 0x81, 0x4b, 0x29, 0xf4, + 0x32, 0xba, 0xc8, 0x7b, 0x05, 0x25, 0x8d, 0x84, 0xcc, 0x4b, 0x64, 0x7a, 0x77, 0xf9, 0x6e, 0x90, + 0x62, 0xe1, 0x5d, 0x35, 0x95, 0x8e, 0x27, 0xbd, 0x1a, 0x97, 0xe9, 0xfb, 0xbf, 0xc1, 0x70, 0x8e, + 0x3c, 0xc9, 0x8a, 0xbf, 0xe1, 0xea, 0x25, 0x85, 0x14, 0x98, 0x19, 0xa7, 0x9f, 0xd5, 0x7f, 0x13, + 0x0f, 0x9d, 0xff, 0x8d, 0x69, 0xe5, 0xff, 0xab, 0x35, 0xe2, 0x43, 0x68, 0xbc, 0x3a, 0xba, 0x84, + 0xca, 0x7c, 0xa8, 0x94, 0x0a, 0xf0, 0xad, 0xa5, 0x24, 0xce, 0xbf, 0x2a, 0x5d, 0xb6, 0xf8, 0x77, + 0x25, 0xac, 0xc5, 0xef, 0x1c, 0xa6, 0x43, 0x7c, 0x19, 0xc4, 0xb2, 0x88, 0x6d, 0xd0, 0x0c, 0x22, + 0xce, 0x43, 0xb3, 0x8c, 0x98, 0xc1, 0xa7, 0xf2, 0x92, 0x1d, 0x68, 0x39, 0x25, 0x21, 0x80, 0xcf, + 0x2c, 0x89, 0xaa, 0xd4, 0x6c, 0x09, 0x0b, 0xa5, 0xfe, 0xaa, 0xf0, 0x60, 0x6d, 0xd2, 0x15, 0x19, + 0x0f, 0xc7, 0xa0, 0x94, 0x8f, 0x1b, 0xa7, 0xa4, 0x0e, 0xdc, 0x8a, 0xc8, 0x7c, 0x25, 0x5f, 0x6a, + 0xd5, 0x87, 0xbb, 0x53, 0x72, 0x17, 0x1e, 0xc6, 0x14, 0xb7, 0x40, 0xd2, 0x2e, 0x90, 0x02, 0xd5, + 0x10, 0x58, 0xc2, 0x1f, 0x6f, 0x80, 0xa4, 0x1b, 0x9e, 0xd2, 0x25, 0x3d, 0xff, 0x08, 0x98, 0x71, + 0x69, 0x5f, 0x6f, 0xf4, 0xcb, 0x76, 0xd1, 0xad, 0x75, 0x12, 0x99, 0x75, 0x5a, 0x3c, 0x38, 0xc7, + 0xd2, 0xf9, 0x12, 0x09, 0x8b, 0x3b, 0x5f, 0xea, 0x61, 0xd9, 0xd7, 0x80, 0xbf, 0xa2, 0xbc, 0x0a, + 0xb4, 0xce, 0x75, 0xd0, 0x79, 0x93, 0x67, 0xe3, 0x6b, 0x02, 0x1f, 0xf6, 0x2a, 0xeb, 0x18, 0xab, + 0x58, 0x01, 0x8f, 0x58, 0x55, 0x6a, 0x63, 0x96, 0x3d, 0x1a, 0xf8, 0xa9, 0xf0, 0x9d, 0x79, 0xfb, + 0x30, 0x5d, 0x55, 0x18, 0x98, 0x70, 0x37, 0x7d, 0xb0, 0xc8, 0x5a, 0x4e, 0xc7, 0x17, 0x67, 0x66, + 0xd3, 0x3b, 0xa3, 0x20, 0xa0, 0xb5, 0x9d, 0xb2, 0x22, 0x39, 0x47, 0xe0, 0x23, 0x76, 0x8c, 0x85, + 0xa6, 0x43, 0x1e, 0xb8, 0x42, 0xa0, 0x0c, 0xdc, 0x0b, 0x89, 0x19, 0x58, 0x3a, 0xe1, 0xc9, 0xdc, + 0x01, 0x9d, 0x5c, 0x72, 0x5f, 0xee, 0x49, 0xac, 0x6b, 0x97, 0x0c, 0x8f, 0x04, 0x67, 0x1b, 0x61, + 0xe9, 0xe8, 0xd7, 0x7e, 0x1a, 0x4f, 0xfd, 0xc6, 0x34, 0xc8, 0xe4, 0x49, 0x24, 0x65, 0x33, 0x43, + 0x1f, 0x9a, 0x5b, 0xe8, 0xc3, 0x44, 0x27, 0xb6, 0x81, 0x32, 0x4e, 0xf1, 0xe0, 0x4b, 0x10, 0x1b, + 0x14, 0xe3, 0xd8, 0xac, 0xc4, 0x12, 0xa9, 0x4d, 0xcb, 0x5c, 0x77, 0x23, 0x2e, 0xb9, 0xef, 0x4b, + 0x72, 0xc7, 0xbb, 0xf5, 0x96, 0x23, 0xa2, 0x3b, 0x4f, 0x59, 0xb7, 0x90, 0x74, 0xca, 0x92, 0xfa, + 0xe6, 0xdd, 0x1e, 0xca, 0x77, 0x22, 0xfe, 0xfa, 0x62, 0x02, 0x08, 0x06, 0xe2, 0xa7, 0x26, 0xf7, + 0xad, 0xb4, 0xe3, 0x4b, 0x82, 0xcf, 0x96, 0x8d, 0x4d, 0xba, 0x20, 0xfb, 0x82, 0x95, 0x93, 0x07, + 0xdd, 0x95, 0x14, 0x6e, 0xa1, 0x6d, 0x0b, 0x69, 0xc4, 0x6b, 0xbb, 0x29, 0x9b, 0x61, 0x39, 0x1d, + 0xdf, 0x3d, 0x5d, 0xcc, 0x81, 0x8e, 0xb5, 0x72, 0x4b, 0x6c, 0x5e, 0x4f, 0x16, 0xe3, 0x95, 0x73, + 0x34, 0x8c, 0x4a, 0xb7, 0x3d, 0x73, 0xf7, 0xd4, 0xbe, 0xa7, 0x8e, 0x09, 0x2f, 0xa8, 0xad, 0xdb, + 0xbd, 0x2f, 0x24, 0x9c, 0xf2, 0xfd, 0x5c, 0x54, 0x0d, 0x5e, 0x22, 0x87, 0xa4, 0xce, 0xbd, 0x3d, + 0x52, 0xa0, 0x52, 0xef, 0xe2, 0x07, 0x6a, 0x27, 0xd6, 0xcd, 0x29, 0x6c, 0x1b, 0x2c, 0xfb, 0xbd, + 0x8f, 0x56, 0xab, 0x57, 0x0a, 0xa5, 0x90, 0xfd, 0x66, 0x87, 0x66, 0x2d, 0xf3, 0x00, 0xcb, 0xe1, + 0xcd, 0xcc, 0xe9, 0xc6, 0x54, 0x88, 0x1b, 0x7b, 0x68, 0xa7, 0x24, 0xb5, 0x5d, 0xc6, 0xc9, 0xdd, + 0x2b, 0x0d, 0x8b, 0x7f, 0x30, 0x6a, 0x3d, 0x83, 0x4b, 0xba, 0x57, 0xc5, 0xe9, 0xca, 0x21, 0xa3, + 0xce, 0x15, 0xc1, 0xb5, 0x73, 0xf8, 0x09, 0xd9, 0x44, 0xb8, 0x96, 0x6d, 0x5f, 0xb7, 0xa0, 0x40, + 0x21, 0xe9, 0xc0, 0xec, 0xf6, 0xaa, 0xf9, 0xd9, 0x53, 0xdf, 0x56, 0x5a, 0x2c, 0x65, 0x56, 0xf5, + 0x06, 0xc5, 0x45, 0x48, 0xec, 0xb6, 0x81, 0x3c, 0xf9, 0x86, 0x2b, 0x33, 0x43, 0x3c, 0xdd, 0x53, + 0x21, 0x40, 0xec, 0xef, 0xd8, 0x81, 0x7c, 0xad, 0x91, 0xef, 0x14, 0x76, 0x3c, 0xb0, 0x70, 0x00, + 0x5d, 0x9d, 0x3b, 0xbe, 0xa6, 0xff, 0x1b, 0x77, 0xb7, 0xf9, 0xb9, 0x7a, 0xfc, 0xcd, 0x3d, 0xfc, + 0x80, 0x86, 0x3d, 0x0a, 0x3c, 0x9c, 0x99, 0x68, 0xb1, 0x19, 0x87, 0xa9, 0xcc, 0xe3, 0xf1, 0xce, + 0x42, 0x2c, 0xdd, 0x3e, 0x4a, 0x3a, 0x5e, 0xab, 0x89, 0x16, 0x5b, 0xd7, 0x76, 0x87, 0xbb, 0x8a, + 0xe2, 0x66, 0xb8, 0xef, 0x82, 0xea, 0xf6, 0x91, 0xf0, 0x02, 0x53, 0x06, 0xab, 0x7b, 0xf5, 0xb9, + 0x5c, 0xcf, 0xf1, 0x18, 0xdd, 0xf8, 0xf9, 0x49, 0x58, 0xa4, 0x7c, 0xa8, 0xd7, 0x05, 0x2d, 0x51, + 0x97, 0x77, 0x0e, 0x5c, 0x43, 0xab, 0x01, 0x5e, 0x6c, 0x0d, 0x9d, 0xeb, 0xa5, 0x83, 0xff, 0x64, + 0xe6, 0x25, 0xd0, 0x5c, 0x5f, 0x79, 0x5f, 0xe7, 0x6a, 0x42, 0x7c, 0xdc, 0x62, 0xbb, 0xa9, 0x7e, + 0x41, 0xd4, 0x6d, 0x91, 0x2d, 0x34, 0x2d, 0x7f, 0xae, 0x87, 0xe6, 0xe5, 0xce, 0x83, 0xb2, 0x81, + 0xff, 0xd5, 0xca, 0x74, 0x0c, 0x7c, 0xa8, 0xab, 0xe1, 0xe5, 0x4a, 0x8d, 0xa0, 0x48, 0x06, 0x5d, + 0x8d, 0x9c, 0x1e, 0xdf, 0x14, 0xab, 0xed, 0x06, 0xa4, 0x98, 0xaa, 0xed, 0xe1, 0xaa, 0x67, 0xa5, + 0x27, 0x81, 0xc0, 0x52, 0x1c, 0xd7, 0xde, 0xa4, 0x4d, 0x17, 0xcc, 0x06, 0x0e, 0x5e, 0x9d, 0x4e, + 0xaf, 0xe6, 0x32, 0x1b, 0x72, 0xd5, 0xad, 0x12, 0x82, 0xa7, 0x0d, 0x84, 0xcf, 0x92, 0x93, 0xea, + 0x8f, 0xa6, 0xac, 0xf7, 0xa6, 0x80, 0xa8, 0xca, 0xab, 0xd6, 0x83, 0xac, 0x78, 0xa9, 0xaf, 0x12, + 0x58, 0x91, 0xfa, 0xb2, 0xbd, 0xfd, 0x98, 0xbc, 0xd9, 0x0b, 0xef, 0x04, 0xe6, 0x45, 0x00, 0x80, + 0xe8, 0x66, 0x19, 0xda, 0x49, 0xab, 0xee, 0x4b, 0xdf, 0x43, 0x8e, 0x87, 0x87, 0x66, 0x06, 0x30, + 0xca, 0xe0, 0x0d, 0xb1, 0x52, 0xf2, 0x67, 0x10, 0xc6, 0xbd, 0x94, 0x9c, 0x0b, 0x1c, 0xd6, 0x15, + 0xaf, 0xb7, 0x95, 0x0c, 0x57, 0xe6, 0x18, 0x7a, 0xd1, 0xdb, 0xe4, 0x39, 0x93, 0xb1, 0x53, 0xa6, + 0x00, 0xda, 0x53, 0x0e, 0x93, 0x19, 0x02, 0x50, 0xd3, 0x5a, 0x95, 0x41, 0xe6, 0x0b, 0x49, 0xcc, + 0x3b, 0x47, 0x33, 0xbc, 0xf4, 0xc5, 0xc5, 0x44, 0x1f, 0xbb, 0xfc, 0x35, 0x1b, 0x17, 0x9a, 0xfd, + 0x7b, 0xd3, 0x28, 0x32, 0xbe, 0xc2, 0x89, 0x49, 0x58, 0xfa, 0x52, 0x3e, 0xe7, 0x97, 0x4e, 0xaa, + 0x65, 0x81, 0xec, 0x4b, 0x27, 0x24, 0x30, 0xd5, 0x4f, 0x42, 0xd3, 0x7c, 0xcd, 0x53, 0x60, 0xb5, + 0xf4, 0x73, 0x9d, 0xd0, 0x72, 0x60, 0x16, 0x43, 0xb5, 0x2a, 0x3e, 0x6b, 0x0f, 0xf8, 0x25, 0x7c, + 0xd6, 0xfc, 0x5c, 0x37, 0x64, 0x28, 0x89, 0x04, 0x1f, 0xff, 0x0f, 0xf6, 0xde, 0xa6, 0x27, 0x91, + 0xae, 0x6d, 0xd4, 0xfe, 0x33, 0x17, 0x6d, 0x80, 0x1b, 0x4d, 0xba, 0x2f, 0x34, 0xea, 0xa3, 0x3d, + 0x06, 0x1a, 0x48, 0x8a, 0xaf, 0x50, 0x58, 0x38, 0x11, 0x0d, 0x20, 0x90, 0xf0, 0x19, 0x40, 0xed, + 0xff, 0x00, 0x14, 0x44, 0x01, 0x9d, 0x50, 0x92, 0x2a, 0x2c, 0x48, 0xd0, 0x82, 0x00, 0x82, 0x63, + 0xe0, 0x02, 0x13, 0xa0, 0x20, 0x80, 0xe0, 0x44, 0x24, 0x80, 0x60, 0xa2, 0x02, 0x51, 0xdb, 0xbe, + 0xb7, 0xf7, 0xde, 0x6f, 0xde, 0x49, 0x77, 0x4f, 0x76, 0xf6, 0xbb, 0xf3, 0xe6, 0x89, 0xc7, 0x80, + 0x09, 0x29, 0x02, 0xc7, 0x5a, 0xac, 0x75, 0xae, 0xaa, 0x75, 0x9e, 0xab, 0x50, 0x0a, 0xa0, 0x68, + 0x53, 0xee, 0xab, 0x15, 0xe4, 0x02, 0xdc, 0x4c, 0x60, 0x86, 0xbb, 0x43, 0x82, 0x6b, 0x80, 0xe0, + 0x79, 0xa8, 0x66, 0x6a, 0x66, 0xe5, 0x6c, 0x47, 0x25, 0xbd, 0xa7, 0x82, 0x89, 0x05, 0x6e, 0xe4, + 0x20, 0x28, 0x9b, 0x7b, 0x74, 0x5f, 0xc8, 0x1b, 0xe7, 0xb5, 0xaf, 0x4c, 0x9e, 0x29, 0x6d, 0x4a, + 0x49, 0x76, 0xc9, 0x1e, 0xaa, 0x2e, 0x22, 0xcd, 0x39, 0xae, 0x11, 0xee, 0xd4, 0xb3, 0x29, 0x51, + 0x77, 0xf8, 0x0a, 0x54, 0x2b, 0x91, 0x15, 0xb6, 0xf3, 0x20, 0x34, 0x87, 0x3b, 0x91, 0x34, 0xf7, + 0xc0, 0x1d, 0x57, 0x57, 0x05, 0xdb, 0x28, 0x67, 0x7e, 0x17, 0xae, 0x87, 0x63, 0xc2, 0xe3, 0xbb, + 0xdb, 0xdc, 0xb0, 0xbb, 0xce, 0xc4, 0xcb, 0xe3, 0x9b, 0x48, 0x5d, 0x0e, 0x77, 0x17, 0x25, 0xe2, + 0x2b, 0xac, 0x07, 0x35, 0x8f, 0x63, 0x31, 0x03, 0x0e, 0xa3, 0x9f, 0xd2, 0x69, 0x81, 0x31, 0x8e, + 0xb9, 0xc5, 0x83, 0x90, 0xc4, 0xf4, 0xa3, 0xf2, 0x9c, 0xd4, 0xfb, 0x3a, 0x12, 0x50, 0x1c, 0x54, + 0x5b, 0x5f, 0x93, 0x7a, 0xc4, 0xba, 0xe4, 0xf3, 0x91, 0x0c, 0xb9, 0x78, 0x63, 0x54, 0x5f, 0x61, + 0x93, 0x77, 0x88, 0x61, 0x27, 0xd0, 0xbd, 0xe0, 0x71, 0xe1, 0xdb, 0x90, 0xd4, 0xad, 0xed, 0x98, + 0x1f, 0xd6, 0x62, 0xa4, 0x25, 0xee, 0xe8, 0x36, 0x3b, 0xd0, 0xb9, 0x87, 0xae, 0x91, 0x3b, 0x1f, + 0x97, 0xa5, 0xf2, 0xe8, 0xe1, 0xdd, 0x30, 0x2e, 0x11, 0x31, 0x94, 0x8f, 0x8f, 0x22, 0x7c, 0x3e, + 0xec, 0x4c, 0xf6, 0xee, 0x0b, 0x62, 0x3b, 0xe5, 0x6b, 0xd8, 0x10, 0xad, 0x86, 0x68, 0x82, 0x90, + 0xe2, 0xd7, 0x3a, 0x42, 0xac, 0x3f, 0xf4, 0x69, 0x25, 0xad, 0xef, 0xf2, 0xaf, 0xaa, 0xdd, 0x86, + 0x84, 0x46, 0xb9, 0x2e, 0xa9, 0x25, 0xf6, 0x24, 0x38, 0x73, 0x82, 0xb9, 0x41, 0xbc, 0xdd, 0xab, + 0xbc, 0x52, 0xa4, 0x99, 0x0b, 0x0f, 0xd9, 0xe5, 0xad, 0x1f, 0x9c, 0x45, 0xcc, 0x0e, 0x49, 0x67, + 0xaa, 0x6f, 0x93, 0xf6, 0x39, 0x48, 0x66, 0x3e, 0x4b, 0x64, 0x87, 0x4f, 0x44, 0xa7, 0xcf, 0x01, + 0xd1, 0x04, 0x43, 0xad, 0x36, 0x65, 0x19, 0x7c, 0x43, 0x93, 0x8f, 0xe9, 0x05, 0xbd, 0xc5, 0xd5, + 0x52, 0x34, 0x40, 0x36, 0x73, 0xe5, 0xf5, 0x99, 0x5c, 0x32, 0x8a, 0xa5, 0x7f, 0x1e, 0xae, 0x79, + 0xd3, 0x02, 0x71, 0xb9, 0xfd, 0x0c, 0xe6, 0xdc, 0x83, 0x4f, 0xb6, 0x32, 0xe1, 0x45, 0xe7, 0x04, + 0x84, 0x8b, 0x9c, 0x13, 0xbc, 0x10, 0xa6, 0x9a, 0x28, 0x70, 0xd2, 0xd1, 0x12, 0x07, 0x69, 0xd1, + 0x7b, 0x48, 0xfc, 0x6f, 0xa9, 0xb8, 0x4c, 0x6e, 0x76, 0xc0, 0x5c, 0x5a, 0x46, 0x49, 0xf2, 0xd5, + 0xd0, 0xa4, 0xcf, 0xc7, 0x2d, 0xdc, 0x55, 0x6d, 0xbc, 0x8d, 0x47, 0x93, 0x24, 0x3e, 0x58, 0xd0, + 0xb7, 0xe8, 0xd9, 0x5d, 0x7d, 0xf3, 0x2f, 0x62, 0x7a, 0x36, 0x09, 0xe5, 0x77, 0x81, 0xf8, 0x7b, + 0xc4, 0x21, 0x3c, 0x4e, 0xf1, 0x6c, 0x4f, 0xb1, 0x9b, 0xb8, 0xc9, 0x7d, 0x8f, 0xf0, 0x20, 0x47, + 0xb4, 0x73, 0x09, 0x38, 0x04, 0xff, 0x42, 0xfa, 0x6e, 0xad, 0x2b, 0x4f, 0x2d, 0x21, 0x6e, 0x04, + 0x18, 0xc0, 0xd2, 0x2a, 0x64, 0x09, 0xf8, 0x1b, 0x38, 0xf7, 0xe9, 0x36, 0xc7, 0xab, 0xc4, 0xc8, + 0xf5, 0x52, 0x73, 0x6d, 0xbf, 0x06, 0x89, 0x9e, 0xc6, 0x50, 0x42, 0xa0, 0xff, 0xb7, 0x2a, 0x5b, + 0x42, 0x56, 0xc6, 0xbc, 0x12, 0x90, 0x9e, 0x84, 0xd9, 0xd8, 0x71, 0xbe, 0x68, 0x91, 0x5f, 0x50, + 0x57, 0xae, 0x6d, 0x3d, 0xeb, 0x52, 0x3f, 0x9a, 0xe6, 0x52, 0xc1, 0xf3, 0x5e, 0x97, 0xe6, 0xba, + 0xc1, 0x12, 0x03, 0x73, 0xf9, 0x5f, 0xc7, 0x8f, 0x6e, 0xc3, 0x59, 0x9e, 0xba, 0xdd, 0x39, 0xd2, + 0x00, 0x13, 0xc5, 0xaf, 0x7d, 0x9a, 0xe0, 0xfe, 0xd6, 0x74, 0x25, 0x94, 0xf9, 0xdf, 0x0d, 0x5f, + 0xc5, 0x65, 0xea, 0x8b, 0xc1, 0xd7, 0xed, 0x61, 0x2a, 0x70, 0x4b, 0x8a, 0x69, 0x0e, 0xb6, 0xa4, + 0x8c, 0x92, 0xaf, 0x9b, 0xa8, 0x5a, 0xd6, 0x3d, 0xfb, 0x14, 0xa5, 0x64, 0xe3, 0x80, 0xa4, 0x0b, + 0x42, 0xd0, 0x0c, 0x0d, 0x38, 0x8e, 0x50, 0xa8, 0x7a, 0x49, 0xaf, 0xc0, 0x5b, 0x77, 0x87, 0x58, + 0x26, 0x41, 0x4d, 0x44, 0x61, 0xfb, 0xd5, 0x5d, 0x5a, 0x83, 0x07, 0x37, 0x90, 0x2a, 0xae, 0xde, + 0x7f, 0x95, 0xa4, 0x01, 0x84, 0x9a, 0x03, 0x7e, 0x1c, 0x93, 0x13, 0x5b, 0x04, 0x24, 0xd9, 0xff, + 0x5f, 0x17, 0x95, 0xf8, 0x3f, 0xf8, 0x92, 0xfe, 0xf5, 0x0c, 0x4a, 0x72, 0xf1, 0x0f, 0x7d, 0x9a, + 0x79, 0x8a, 0x03, 0xae, 0xf6, 0x65, 0xf9, 0x01, 0x43, 0x05, 0x07, 0x66, 0xf4, 0xbd, 0x27, 0xbf, + 0x4f, 0xbf, 0x2d, 0x81, 0x0e, 0xa5, 0x0a, 0x4e, 0x43, 0x96, 0xe3, 0xe8, 0xae, 0x78, 0xc8, 0x91, + 0x0b, 0x3b, 0x0c, 0x26, 0x3e, 0xb8, 0xeb, 0x71, 0x38, 0x07, 0xe4, 0x59, 0x4c, 0x2f, 0xbe, 0x75, + 0x0d, 0x5a, 0x82, 0x46, 0x60, 0x22, 0x12, 0x3f, 0x1c, 0x99, 0x75, 0x13, 0xbf, 0x12, 0x95, 0x81, + 0xdb, 0x21, 0xb1, 0xbe, 0x55, 0xdd, 0x1f, 0xb7, 0xab, 0xbe, 0xd7, 0xce, 0xbc, 0x60, 0x0c, 0x2f, + 0x03, 0xe7, 0x67, 0xa1, 0x2a, 0xbb, 0xaf, 0x5e, 0x4b, 0xa4, 0x87, 0x26, 0x8a, 0x4d, 0x30, 0x8c, + 0x1d, 0x20, 0x21, 0xb7, 0x6f, 0xc8, 0xa9, 0x97, 0xe0, 0x61, 0x5a, 0xea, 0x54, 0xaf, 0x7c, 0xb5, + 0x39, 0x62, 0x37, 0xb5, 0x64, 0x7b, 0xe3, 0xa4, 0xc1, 0x81, 0x8c, 0x81, 0x0b, 0x5a, 0x09, 0xfe, + 0x3b, 0x69, 0x77, 0x9c, 0xbd, 0x90, 0x73, 0x5e, 0xe3, 0x5d, 0x08, 0x83, 0xf5, 0xa4, 0x9d, 0xe5, + 0x30, 0xf6, 0x86, 0xd4, 0x7e, 0xda, 0x0f, 0x6a, 0x74, 0x0a, 0xeb, 0xdc, 0x6e, 0x75, 0x03, 0xa5, + 0x47, 0xf1, 0x6d, 0x5c, 0xca, 0x28, 0x7b, 0x18, 0x2a, 0x4c, 0xe4, 0xc1, 0xd1, 0x82, 0xb3, 0xd2, + 0x52, 0x40, 0x3c, 0x44, 0x96, 0x05, 0xfa, 0x5e, 0x25, 0xb5, 0x84, 0x9f, 0xda, 0x6e, 0x79, 0x98, + 0xab, 0x5f, 0x1d, 0x86, 0xee, 0x02, 0xf7, 0xe5, 0x6f, 0x4f, 0x83, 0x38, 0x5f, 0x4e, 0x7c, 0x5f, + 0x96, 0x70, 0x89, 0xa1, 0xd4, 0x52, 0x5a, 0xf3, 0x67, 0x13, 0x50, 0xfb, 0x48, 0x55, 0x8d, 0xf8, + 0x6d, 0xcf, 0x8d, 0x93, 0x87, 0x64, 0x56, 0x7e, 0x72, 0x88, 0xe5, 0x0c, 0x27, 0xd7, 0x36, 0x3c, + 0x89, 0xbd, 0x35, 0x1a, 0x7b, 0x58, 0x07, 0xbc, 0xa4, 0xe7, 0x36, 0xe2, 0x43, 0x7d, 0xb3, 0x5c, + 0x9f, 0xc3, 0x4a, 0x87, 0xcf, 0x5b, 0xf4, 0xe8, 0x61, 0xa0, 0x38, 0x1a, 0x99, 0x28, 0xf3, 0x6c, + 0x87, 0xb0, 0xf2, 0xc2, 0xe9, 0x77, 0x4f, 0xc8, 0x85, 0x46, 0xeb, 0xd7, 0x3e, 0x4d, 0xae, 0xfc, + 0xc1, 0xb4, 0xf9, 0xf2, 0x91, 0x0c, 0x2d, 0xb1, 0xa2, 0x44, 0x4f, 0xce, 0x6f, 0x49, 0xbe, 0x2f, + 0xb1, 0x31, 0x37, 0xae, 0xb8, 0x7f, 0x0c, 0x24, 0x51, 0xb0, 0x6a, 0x8a, 0x2c, 0x01, 0xd8, 0x61, + 0xbf, 0x56, 0x74, 0xdd, 0x9d, 0x1c, 0xf3, 0x9b, 0x0a, 0x57, 0x06, 0xe4, 0x74, 0xd2, 0x0a, 0xc1, + 0x28, 0x3c, 0xce, 0x8b, 0x45, 0x93, 0xe7, 0x65, 0xa8, 0x58, 0x1d, 0x67, 0x73, 0xa6, 0x23, 0x38, + 0x44, 0xc7, 0x03, 0x3e, 0x64, 0x19, 0x52, 0x7f, 0xaa, 0x4b, 0xc0, 0xb4, 0xba, 0x0f, 0xd8, 0xd2, + 0x92, 0xd5, 0x67, 0xdb, 0xd5, 0x2d, 0x2a, 0x68, 0xb8, 0x9e, 0x72, 0x76, 0x95, 0x80, 0x90, 0xeb, + 0x87, 0x01, 0xff, 0xd7, 0xc5, 0x98, 0xc8, 0xbf, 0x0a, 0xfe, 0x93, 0xda, 0xd7, 0xea, 0x6d, 0x2f, + 0x37, 0xb7, 0x6f, 0xec, 0xce, 0x5d, 0x58, 0x2b, 0xf6, 0x0d, 0xda, 0xad, 0xdc, 0x76, 0xe8, 0x35, + 0xa4, 0xa9, 0xa5, 0x7b, 0x2a, 0x07, 0x51, 0xc5, 0xb9, 0xf2, 0x9d, 0xe3, 0x74, 0xb8, 0x02, 0xef, + 0xd2, 0x32, 0x1c, 0x61, 0x38, 0x4e, 0x3d, 0x50, 0xa0, 0xcb, 0x62, 0xe0, 0xe5, 0x2a, 0xa3, 0x1a, + 0x36, 0xb7, 0xa0, 0x44, 0xd3, 0xdc, 0x99, 0xc5, 0x92, 0x26, 0x0a, 0x43, 0xd5, 0x74, 0x1d, 0x60, + 0xfd, 0x8a, 0x0b, 0xc6, 0xc2, 0x7a, 0x2c, 0x34, 0x03, 0x08, 0xcf, 0x9e, 0x1b, 0xaa, 0x83, 0x3b, + 0x3c, 0x27, 0x10, 0x6c, 0x76, 0x83, 0x80, 0x58, 0x8c, 0xa3, 0xef, 0x3f, 0x01, 0x67, 0x81, 0x9c, + 0xb5, 0xe0, 0x54, 0xd5, 0xaf, 0x0c, 0x57, 0x75, 0x80, 0x77, 0x86, 0x0e, 0x08, 0x6e, 0x09, 0x6a, + 0xf4, 0xc0, 0x44, 0xd1, 0xaa, 0x01, 0x2f, 0x35, 0x04, 0x08, 0x36, 0x09, 0xea, 0xaa, 0xc3, 0x44, + 0x9f, 0x00, 0x5e, 0x17, 0x4a, 0x2d, 0xe6, 0xaa, 0x2e, 0x2c, 0x0b, 0x9a, 0x28, 0x66, 0xc1, 0x91, + 0x7c, 0x3a, 0x07, 0x48, 0xdc, 0x2e, 0xf4, 0x05, 0x30, 0x51, 0x24, 0x7c, 0xdf, 0xdd, 0x3e, 0xb2, + 0x28, 0x72, 0xf6, 0x46, 0x3a, 0xff, 0x43, 0x22, 0x85, 0x65, 0x52, 0xbf, 0xa9, 0x23, 0x24, 0xfd, + 0x83, 0x69, 0x6b, 0x42, 0x98, 0x44, 0x96, 0xa5, 0x00, 0x86, 0x58, 0x0b, 0x57, 0xf0, 0xf1, 0xb3, + 0x49, 0xbc, 0x89, 0x70, 0x79, 0x07, 0x57, 0xf5, 0x15, 0x50, 0x6c, 0xff, 0x7b, 0x6a, 0x12, 0x1b, + 0x11, 0xba, 0x35, 0x27, 0x92, 0x2a, 0x68, 0x18, 0x4c, 0x42, 0x93, 0xb4, 0x28, 0x30, 0x11, 0x8b, + 0x0f, 0x5c, 0x31, 0xb3, 0x58, 0xb0, 0x10, 0x62, 0xb5, 0x6d, 0x43, 0xea, 0x9c, 0x30, 0xee, 0x37, + 0xf5, 0x85, 0x4f, 0xee, 0xa6, 0x5a, 0xe8, 0x0e, 0xa6, 0xf1, 0x01, 0x7c, 0x80, 0xf1, 0xb5, 0xba, + 0x3e, 0x6a, 0xe6, 0x6f, 0x9e, 0x0c, 0x65, 0x87, 0x4e, 0x84, 0xdb, 0x10, 0x97, 0x6b, 0x4c, 0x4e, + 0xfa, 0xa9, 0x49, 0xca, 0x30, 0xf8, 0xab, 0x6d, 0x68, 0x1b, 0x1f, 0x90, 0x2b, 0xee, 0xca, 0x90, + 0x4e, 0x15, 0x5b, 0x50, 0x48, 0x4d, 0x2a, 0xc2, 0x58, 0x06, 0x73, 0xbd, 0x6d, 0x66, 0xfe, 0x71, + 0x44, 0xac, 0x2f, 0x62, 0xe3, 0xb5, 0x5c, 0xe7, 0xf2, 0x7a, 0x6b, 0x98, 0xfc, 0xa4, 0xdb, 0x67, + 0x09, 0x82, 0x8a, 0xb1, 0x92, 0x2d, 0x3b, 0xa8, 0x2d, 0x63, 0xd1, 0x01, 0x97, 0x65, 0x10, 0x30, + 0x35, 0xd9, 0x3e, 0x2c, 0x24, 0x79, 0xa4, 0x09, 0x16, 0xad, 0xb4, 0xc8, 0x73, 0x72, 0x56, 0x7c, + 0xd3, 0xea, 0x82, 0xee, 0x9d, 0xe3, 0x0e, 0xad, 0xef, 0xf9, 0xab, 0x2f, 0x05, 0x03, 0xa1, 0x25, + 0x6d, 0xc1, 0xf7, 0x5c, 0x1d, 0x5e, 0x9f, 0xd5, 0x3a, 0x52, 0xad, 0x31, 0x8c, 0x6a, 0x79, 0x30, + 0xa2, 0x5c, 0xb1, 0xdd, 0x8e, 0x55, 0x90, 0xc0, 0xff, 0x57, 0x96, 0xa1, 0x39, 0x26, 0x66, 0x4a, + 0x7e, 0xa3, 0xff, 0x99, 0x2a, 0x12, 0x74, 0xe7, 0x8b, 0xd7, 0x6a, 0xc2, 0xce, 0xf4, 0xbe, 0xc7, + 0x4a, 0xcd, 0x52, 0x24, 0xd8, 0xa9, 0x8a, 0x2b, 0x44, 0xeb, 0x21, 0x69, 0x19, 0x32, 0x56, 0xc5, + 0x3e, 0x94, 0xa3, 0x27, 0x9d, 0x36, 0xa4, 0x0f, 0x19, 0xdc, 0x17, 0x26, 0xb7, 0x2d, 0x39, 0x12, + 0x34, 0x7c, 0x4f, 0xb8, 0xd6, 0x23, 0x4a, 0x77, 0xaa, 0x02, 0xc1, 0xaf, 0x33, 0xa2, 0x08, 0xfa, + 0x83, 0x69, 0x71, 0xff, 0xa4, 0x1f, 0x64, 0x25, 0x64, 0x18, 0x0a, 0x25, 0xf8, 0xeb, 0x3b, 0xd5, + 0x90, 0x76, 0x1b, 0x0f, 0xb5, 0xb4, 0x0a, 0x5a, 0xa8, 0x5e, 0x25, 0x60, 0xba, 0x1a, 0x88, 0x21, + 0x91, 0x76, 0x3c, 0x7a, 0x32, 0xa6, 0x9e, 0x39, 0x03, 0xc7, 0x99, 0xed, 0x03, 0x4f, 0xa6, 0x99, + 0x24, 0x6a, 0x2b, 0x03, 0x0c, 0xbe, 0x7d, 0x69, 0xaf, 0xb9, 0xfd, 0x4a, 0x93, 0xba, 0xef, 0x0f, + 0xe9, 0xf5, 0xe7, 0xc4, 0x6a, 0x6e, 0xed, 0x34, 0x34, 0x47, 0xc8, 0x5c, 0xd3, 0x85, 0xc8, 0x49, + 0x4b, 0xc1, 0xfc, 0xa2, 0x75, 0x54, 0x86, 0x56, 0xbe, 0xb9, 0x83, 0xb1, 0x65, 0x6e, 0x84, 0x92, + 0x07, 0x89, 0x4a, 0x8f, 0x89, 0x85, 0x52, 0x74, 0xe8, 0xaa, 0xe6, 0x67, 0xb1, 0x77, 0x5c, 0x19, + 0x84, 0x36, 0x02, 0xc3, 0xfd, 0x86, 0x2e, 0x75, 0x31, 0x83, 0x61, 0xe3, 0x83, 0xf1, 0x0a, 0x26, + 0x90, 0x36, 0x6a, 0xd7, 0xc6, 0x4e, 0x37, 0xf7, 0x4f, 0x5c, 0xa2, 0x2b, 0x45, 0xaf, 0x9e, 0xc6, + 0x56, 0xc7, 0xd1, 0x56, 0x08, 0x5a, 0xab, 0x0e, 0x15, 0x58, 0x05, 0xd9, 0x19, 0x63, 0xdc, 0xad, + 0xbf, 0x1a, 0x0f, 0x0e, 0xd7, 0xb8, 0xc1, 0x96, 0xd5, 0xd4, 0x94, 0x76, 0x79, 0xf3, 0x29, 0xcd, + 0xa9, 0x09, 0xc3, 0x13, 0x69, 0x48, 0x40, 0xa6, 0x73, 0xd5, 0xad, 0x9b, 0x31, 0x50, 0xf5, 0xfb, + 0xd3, 0x2b, 0x91, 0x10, 0x94, 0x34, 0xe1, 0xa2, 0xda, 0x92, 0xfc, 0x1a, 0x18, 0xa3, 0xe2, 0xd3, + 0x17, 0xa4, 0x87, 0xa5, 0x05, 0xa4, 0x05, 0xaf, 0xd9, 0xba, 0xc7, 0x39, 0xb6, 0x03, 0x3b, 0x8e, + 0x39, 0x83, 0x89, 0xea, 0x03, 0xf0, 0x02, 0xd3, 0x94, 0x40, 0x25, 0x19, 0x6e, 0xe9, 0x9f, 0x6a, + 0x94, 0x25, 0xfd, 0x6e, 0x48, 0xc6, 0x07, 0xae, 0xdc, 0xc4, 0x5c, 0x94, 0x38, 0x44, 0x56, 0xa0, + 0x24, 0xbe, 0x19, 0xe5, 0x4b, 0x18, 0x52, 0xe9, 0x59, 0x94, 0xc0, 0x97, 0x46, 0xbb, 0x9d, 0x2e, + 0x96, 0x0c, 0xf8, 0xcd, 0xa3, 0xbe, 0x47, 0x36, 0x26, 0x8d, 0x5d, 0xe4, 0xd7, 0xfa, 0x14, 0x94, + 0x3f, 0x98, 0x0e, 0x35, 0x4a, 0x61, 0x17, 0xa1, 0xec, 0x9f, 0xa1, 0x24, 0x03, 0xac, 0x0e, 0x28, + 0x51, 0xf6, 0x56, 0x42, 0x59, 0x88, 0x95, 0xde, 0x87, 0xa7, 0xea, 0xfa, 0x77, 0xe5, 0xfd, 0x64, + 0x27, 0x70, 0x91, 0xe7, 0xa6, 0x19, 0x9b, 0x52, 0xcb, 0x51, 0xc4, 0xaa, 0xef, 0xa7, 0xa4, 0x72, + 0x4b, 0xfb, 0xf0, 0x48, 0x89, 0x79, 0x1c, 0xd3, 0x79, 0xb1, 0xeb, 0x14, 0x67, 0xb1, 0xb4, 0x49, + 0x6c, 0x2a, 0x06, 0x88, 0x26, 0x35, 0x2d, 0x8f, 0x62, 0x28, 0xbb, 0x02, 0xa7, 0xa6, 0xf3, 0x71, + 0x05, 0x63, 0x33, 0x29, 0x7a, 0x6a, 0x63, 0xa9, 0xea, 0xd6, 0xdf, 0xe3, 0xe5, 0x35, 0x82, 0xa2, + 0xd0, 0x6a, 0x8f, 0xe3, 0x20, 0xe4, 0x70, 0xec, 0x73, 0x5a, 0xc3, 0xad, 0x39, 0x5a, 0xad, 0xb6, + 0x81, 0x70, 0xec, 0xfe, 0x70, 0xf0, 0x75, 0x9e, 0x0f, 0x41, 0xe6, 0xb2, 0xc3, 0x59, 0x2f, 0xfc, + 0x2c, 0x9f, 0xe3, 0x5f, 0xf3, 0x64, 0x7a, 0x86, 0x2e, 0x4f, 0xc6, 0x52, 0xeb, 0xc4, 0xff, 0xef, + 0x6f, 0x65, 0xfd, 0xa6, 0x12, 0x08, 0xa1, 0x00, 0x3f, 0xf2, 0x83, 0x3f, 0xf8, 0xe0, 0x83, 0x0f, + 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, + 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0xfe, 0x7b, + 0xf2, 0x9f, 0xe7, 0xc1, 0x0b, 0x5c, 0x4c, 0x20, 0x49, 0xd3, 0x55, 0xb8, 0xb0, 0x43, 0xa5, 0x09, + 0x5d, 0x0d, 0x92, 0x26, 0x70, 0x23, 0xd4, 0x2c, 0xf7, 0x1c, 0x23, 0xb5, 0xdf, 0x60, 0x0a, 0x21, + 0x10, 0xb8, 0xf6, 0xa9, 0x6c, 0xb6, 0x3c, 0x88, 0x11, 0xce, 0x50, 0x05, 0xa5, 0x3b, 0x45, 0x94, + 0xf4, 0xac, 0x43, 0x34, 0x8f, 0x02, 0x5e, 0xac, 0x46, 0xe5, 0x1d, 0x28, 0x3a, 0x14, 0x9e, 0xd7, + 0x15, 0xa2, 0x02, 0xfa, 0x10, 0x44, 0xe5, 0x19, 0x70, 0xe6, 0x62, 0x2e, 0x24, 0x9b, 0xb1, 0x66, + 0xd9, 0xa4, 0xa2, 0x4f, 0x38, 0x02, 0x21, 0x34, 0x6b, 0x39, 0x43, 0x3e, 0x49, 0xef, 0x45, 0x0b, + 0xa3, 0x9c, 0xfa, 0x30, 0x58, 0xed, 0x27, 0xcd, 0x9d, 0x39, 0x0b, 0x1b, 0x36, 0x2d, 0x13, 0xbc, + 0x52, 0x17, 0x13, 0x03, 0x9b, 0x41, 0x68, 0xd1, 0x7b, 0x8b, 0x2c, 0xf3, 0xb8, 0x24, 0xc2, 0x64, + 0x3d, 0x24, 0x6f, 0x50, 0xbe, 0xc4, 0x4f, 0x61, 0x8a, 0x85, 0x67, 0x2e, 0x54, 0x2c, 0x11, 0x13, + 0xeb, 0x52, 0x8e, 0x7c, 0x1a, 0xa7, 0xbb, 0xcf, 0x6e, 0x51, 0xf6, 0x81, 0xef, 0x76, 0x00, 0x3a, + 0x03, 0x08, 0x93, 0xb6, 0xeb, 0x0b, 0xd2, 0xa4, 0x1c, 0x0f, 0x41, 0x2b, 0x9e, 0x5d, 0xff, 0xba, + 0x53, 0x86, 0x60, 0xc9, 0x7e, 0xbf, 0x77, 0x54, 0xa9, 0xd5, 0x90, 0x0c, 0xae, 0xc8, 0x83, 0xb5, + 0xee, 0xf5, 0x97, 0x40, 0xa0, 0x93, 0x04, 0x65, 0x9d, 0xe5, 0x2a, 0xaf, 0x95, 0xb2, 0xd3, 0x55, + 0xaf, 0xa6, 0x20, 0x0d, 0xb4, 0x68, 0x2e, 0x92, 0x2a, 0xd1, 0x5e, 0x3b, 0x7b, 0xe5, 0xc4, 0x6e, + 0xdf, 0xdc, 0x5e, 0x45, 0xfd, 0xad, 0x4c, 0x90, 0xd7, 0xf1, 0xd8, 0x39, 0x96, 0x55, 0x6a, 0x82, + 0xbb, 0xf9, 0x45, 0x30, 0x8a, 0x34, 0x2e, 0xe1, 0xb2, 0x0e, 0x4a, 0x1b, 0x1b, 0x1d, 0xb2, 0x01, + 0x12, 0x78, 0x68, 0xa5, 0x7f, 0x77, 0x3e, 0x15, 0x84, 0x3d, 0x3a, 0x4d, 0xae, 0x78, 0x86, 0x1c, + 0xb7, 0xb0, 0xc3, 0x3b, 0x42, 0x79, 0x6f, 0x0c, 0x25, 0x47, 0x20, 0x50, 0x8f, 0x49, 0x5d, 0xe3, + 0xbb, 0xd0, 0xf2, 0xae, 0x79, 0x40, 0x28, 0x87, 0x6f, 0xf5, 0xaf, 0x51, 0x50, 0x9d, 0x6e, 0xd1, + 0x40, 0xe3, 0x8f, 0x4e, 0x33, 0x59, 0xf5, 0x74, 0x67, 0xdd, 0xd5, 0x83, 0x8b, 0x45, 0xf3, 0x2e, + 0x72, 0x5c, 0xdd, 0x39, 0x1f, 0x07, 0xe3, 0x8f, 0xb2, 0xcd, 0x5e, 0xf8, 0xc2, 0x7d, 0x78, 0xdd, + 0xe6, 0xeb, 0x86, 0xd5, 0x67, 0x9d, 0x60, 0x6b, 0x51, 0xcf, 0x8b, 0x2c, 0x90, 0xcc, 0xcc, 0x35, + 0xad, 0xd9, 0x34, 0xc8, 0x32, 0x61, 0x0b, 0x6c, 0xdf, 0xd7, 0x09, 0xf4, 0xc8, 0x5e, 0x6a, 0x37, + 0x0c, 0xbc, 0xf2, 0x99, 0x1c, 0x45, 0x4f, 0x72, 0x19, 0x71, 0x90, 0xea, 0x56, 0x1f, 0x4a, 0x88, + 0xb1, 0x49, 0xc4, 0xce, 0x7e, 0x01, 0xc5, 0x70, 0x7d, 0x18, 0x52, 0xfc, 0x57, 0x3b, 0xa9, 0x6f, + 0xec, 0xf7, 0x27, 0x55, 0x8b, 0x7c, 0x0c, 0x5e, 0xc7, 0xc5, 0x5d, 0x0e, 0x68, 0xa7, 0x55, 0xf9, + 0x7d, 0xb7, 0x5f, 0x7c, 0x2a, 0x7b, 0xff, 0xbd, 0x5c, 0xef, 0x01, 0xce, 0xb1, 0x99, 0xc2, 0x4d, + 0x13, 0xf5, 0x02, 0xee, 0xd8, 0xc3, 0x53, 0xc7, 0xdb, 0x98, 0x0d, 0x28, 0x90, 0x56, 0xa6, 0xba, + 0x95, 0x56, 0xee, 0x7a, 0xe2, 0x77, 0xe3, 0x5a, 0xcc, 0xf6, 0x6c, 0x5f, 0xb1, 0x0d, 0x0f, 0x53, + 0x90, 0xf9, 0xd7, 0x8c, 0x18, 0x11, 0xc2, 0xfd, 0x83, 0x69, 0x1d, 0xcf, 0xe1, 0x42, 0x3a, 0x3c, + 0x10, 0x20, 0x9e, 0x69, 0xf2, 0xb3, 0x27, 0x5c, 0x29, 0x77, 0x84, 0x42, 0x76, 0x43, 0xe0, 0x1c, + 0xe3, 0x55, 0xa2, 0x48, 0x93, 0x05, 0x9d, 0xf5, 0xa8, 0x6c, 0x50, 0xfc, 0x73, 0x60, 0x0e, 0x6d, + 0x99, 0xe2, 0x5a, 0xf0, 0x2c, 0x4d, 0x51, 0x02, 0x6e, 0x98, 0x4a, 0x2f, 0x12, 0xb7, 0x97, 0x59, + 0xff, 0xe3, 0xbf, 0xee, 0x59, 0x2a, 0x99, 0xa2, 0x01, 0x80, 0x81, 0xe1, 0x26, 0xe0, 0x0c, 0xbc, + 0x6d, 0xb5, 0xab, 0xeb, 0x32, 0x29, 0xad, 0x32, 0x79, 0x36, 0xa9, 0xc4, 0x47, 0xfb, 0x45, 0x43, + 0x5f, 0x3f, 0xe6, 0xae, 0x3c, 0x6e, 0xbc, 0x99, 0xdb, 0x19, 0x93, 0xe6, 0x92, 0x01, 0x37, 0xfb, + 0x55, 0xfe, 0xd9, 0x28, 0xc8, 0x6d, 0x1b, 0xd4, 0x52, 0xd9, 0xea, 0x9a, 0xb3, 0x07, 0x4e, 0xe3, + 0xa7, 0xb1, 0x89, 0x48, 0xb7, 0x49, 0x4a, 0x32, 0x31, 0x0b, 0x4c, 0x93, 0xa8, 0x00, 0xb2, 0x21, + 0x16, 0x25, 0x6b, 0xb7, 0x3a, 0x02, 0xff, 0xbe, 0x45, 0x78, 0xd6, 0xe7, 0x27, 0x3a, 0x98, 0xe8, + 0x81, 0x98, 0x0c, 0x37, 0x93, 0x36, 0x41, 0x99, 0x54, 0x49, 0xfa, 0xf0, 0x57, 0xdb, 0xa9, 0xda, + 0x8c, 0xac, 0x62, 0x39, 0xdc, 0x2a, 0x7d, 0xdd, 0x1b, 0x5f, 0x8d, 0x58, 0xbe, 0xf3, 0xfa, 0x32, + 0x7b, 0x1a, 0x44, 0x65, 0xdc, 0x23, 0x48, 0x9a, 0x8d, 0x1e, 0x3a, 0x90, 0x7a, 0xbe, 0x3f, 0xfc, + 0xbe, 0xbe, 0x98, 0x2c, 0xd5, 0x98, 0x34, 0x87, 0x62, 0xc6, 0x1a, 0x4e, 0xd9, 0xce, 0x5f, 0x2e, + 0xcb, 0x67, 0xe8, 0x27, 0x6e, 0xf1, 0xe9, 0x79, 0x46, 0x35, 0x1c, 0x53, 0xa1, 0x15, 0xd3, 0x8d, + 0x6b, 0x5c, 0x77, 0x88, 0x2c, 0xc3, 0xf4, 0x29, 0x10, 0x9e, 0x56, 0x1b, 0x35, 0xb8, 0xf5, 0xb8, + 0x73, 0xd8, 0xbb, 0x15, 0x9f, 0x5c, 0xc3, 0x59, 0x11, 0x3c, 0xfe, 0x57, 0x2c, 0xed, 0x71, 0x36, + 0xab, 0xea, 0x4b, 0x3c, 0x4e, 0x61, 0x6d, 0x77, 0x64, 0x91, 0x55, 0xbd, 0x88, 0xb1, 0xb5, 0xd2, + 0xd6, 0x50, 0xaa, 0xa3, 0x7f, 0x22, 0xbf, 0x9a, 0x26, 0x17, 0xff, 0x60, 0x9a, 0x29, 0x76, 0x78, + 0x3a, 0x9f, 0x58, 0x16, 0x21, 0xca, 0x64, 0x81, 0x9a, 0x00, 0x3e, 0xd2, 0xbb, 0x3a, 0x9f, 0xde, + 0xff, 0x7a, 0x08, 0x53, 0x59, 0x72, 0xc1, 0x33, 0xb1, 0x92, 0xb0, 0x5b, 0xcf, 0x09, 0x5d, 0x30, + 0xaf, 0xc0, 0xf6, 0xfb, 0x31, 0xa0, 0x24, 0x5a, 0x51, 0x35, 0xbf, 0xb9, 0x3a, 0x0c, 0x2d, 0xe8, + 0x0a, 0x69, 0x59, 0x70, 0x69, 0x80, 0xe4, 0xe4, 0x66, 0x62, 0x39, 0xa7, 0x03, 0x7a, 0x14, 0x7e, + 0xc9, 0xdd, 0x59, 0x96, 0x71, 0xc6, 0x54, 0x9c, 0x0d, 0xc1, 0xcb, 0xb1, 0xd2, 0xe5, 0x5a, 0xa7, + 0xa7, 0xfb, 0x16, 0x78, 0x65, 0xd8, 0x04, 0x5d, 0x94, 0xcb, 0x05, 0xc5, 0xf5, 0x4f, 0x5c, 0x61, + 0xa5, 0xb3, 0x22, 0x16, 0x91, 0xa4, 0x2e, 0x07, 0x54, 0x60, 0xca, 0x97, 0x1c, 0x09, 0x2b, 0x51, + 0x81, 0xe0, 0xbd, 0x6f, 0x8c, 0xdc, 0x08, 0x73, 0x7e, 0x6a, 0x0c, 0x20, 0x36, 0xae, 0x2b, 0x80, + 0xdb, 0x4a, 0x00, 0x32, 0x60, 0xb3, 0x6b, 0x95, 0x42, 0xf5, 0xfd, 0x32, 0x32, 0xfc, 0x88, 0xdd, + 0x24, 0xd8, 0xdf, 0xa2, 0xe4, 0x40, 0x22, 0x77, 0x8a, 0xa8, 0xf3, 0xbb, 0xb7, 0x95, 0x97, 0xd2, + 0x37, 0x0f, 0x32, 0x79, 0x5c, 0x2b, 0x53, 0x08, 0x9b, 0xbd, 0x3a, 0xa8, 0x09, 0xd8, 0x9d, 0xcd, + 0xf4, 0xc2, 0x85, 0xf3, 0xbf, 0x86, 0x51, 0x38, 0xe0, 0x4a, 0x4a, 0xd5, 0xf7, 0x37, 0xf8, 0x4f, + 0x77, 0x25, 0x90, 0x84, 0xd4, 0xa5, 0xd7, 0x17, 0x99, 0x88, 0xd8, 0x6a, 0x89, 0xf9, 0x2e, 0x9c, + 0x41, 0x77, 0x7a, 0x35, 0xe6, 0x71, 0x0e, 0xd9, 0xc0, 0x7e, 0x1a, 0x7c, 0x38, 0xb7, 0x9f, 0xec, + 0x54, 0xc2, 0x2a, 0x75, 0xc9, 0xfb, 0x22, 0xe1, 0x76, 0x2a, 0x98, 0x9e, 0x67, 0x74, 0x75, 0xe6, + 0x92, 0x51, 0x64, 0x4a, 0x73, 0x3c, 0xa0, 0xcb, 0xe6, 0x87, 0x07, 0x74, 0x8b, 0xe6, 0xd1, 0xa3, + 0x21, 0x9a, 0xcf, 0xeb, 0x51, 0x0a, 0x8a, 0x1b, 0xfb, 0x2d, 0xaa, 0x4a, 0x78, 0x85, 0x69, 0xbf, + 0xb5, 0xe8, 0x94, 0xf9, 0x0b, 0xdf, 0xaf, 0x67, 0x31, 0x90, 0x2b, 0x7f, 0x30, 0x6d, 0xda, 0xe3, + 0xa6, 0x57, 0x07, 0xec, 0xa7, 0x0e, 0x61, 0x9d, 0xc7, 0x74, 0x56, 0x99, 0xd2, 0x17, 0x81, 0x3e, + 0x41, 0x15, 0x77, 0x82, 0x32, 0xbb, 0x1e, 0x80, 0x47, 0x61, 0x63, 0x88, 0x1a, 0xa7, 0xba, 0x65, + 0x1b, 0xe1, 0x31, 0x37, 0xba, 0xaf, 0xc9, 0xbb, 0x7f, 0xa4, 0x7b, 0x8b, 0xa9, 0xdd, 0xe3, 0x34, + 0x08, 0x39, 0x02, 0xb8, 0x19, 0x12, 0xd0, 0x9e, 0x21, 0xbd, 0xd8, 0x85, 0x2e, 0xb2, 0x41, 0xbc, + 0x07, 0xdd, 0x47, 0x5f, 0xb2, 0xc9, 0xa8, 0xd1, 0x85, 0x95, 0x1c, 0x12, 0x05, 0x61, 0x6d, 0x6e, + 0x8e, 0x41, 0x00, 0x54, 0xf5, 0xc6, 0x06, 0x50, 0xe5, 0x67, 0x5f, 0x3e, 0x3c, 0x0d, 0x21, 0x48, + 0xfc, 0x10, 0xb1, 0x26, 0x46, 0xdb, 0xad, 0x55, 0xfb, 0x3f, 0xf0, 0xc9, 0xb0, 0xf4, 0xad, 0x82, + 0xa6, 0xf9, 0x4f, 0x21, 0xf3, 0x60, 0xb1, 0x14, 0x6b, 0x6d, 0x36, 0xfc, 0x2e, 0xb2, 0x26, 0x66, + 0x97, 0x17, 0x34, 0xda, 0x66, 0x99, 0xa4, 0x46, 0xd9, 0xee, 0x18, 0xc6, 0x4f, 0xeb, 0x98, 0x33, + 0x36, 0x1c, 0xe9, 0x31, 0x38, 0xf8, 0x6d, 0x00, 0xf9, 0xe2, 0xf1, 0x20, 0x8c, 0x52, 0xda, 0xe4, + 0xee, 0xcc, 0x4a, 0x22, 0x78, 0x5d, 0x97, 0x1b, 0xa4, 0xc7, 0x73, 0xf1, 0x13, 0x5c, 0xb9, 0xc4, + 0x26, 0x87, 0x9a, 0xfb, 0x83, 0xb3, 0x76, 0x8e, 0x35, 0x2e, 0xcf, 0xf6, 0x42, 0x3c, 0x47, 0x22, + 0x89, 0xa6, 0x1b, 0xe9, 0x90, 0xb8, 0x10, 0x92, 0x32, 0x26, 0x7e, 0xa1, 0x2b, 0x87, 0x0f, 0xdc, + 0x89, 0x45, 0x56, 0xf5, 0xa8, 0x46, 0xa1, 0x09, 0x1d, 0x04, 0xaa, 0x02, 0x27, 0x81, 0xac, 0x3c, + 0x5a, 0xde, 0xba, 0x96, 0x89, 0xd3, 0xf6, 0x94, 0xf5, 0xb0, 0x0c, 0xcb, 0xed, 0x39, 0xd8, 0x44, + 0xd5, 0xdc, 0x1b, 0x03, 0x9d, 0x98, 0xb1, 0x02, 0xab, 0x9e, 0xbd, 0xdb, 0xc7, 0x9d, 0xcf, 0x7c, + 0x62, 0xcb, 0xba, 0x64, 0x3a, 0xc0, 0x53, 0xb4, 0x32, 0x51, 0x09, 0xcb, 0x2a, 0x57, 0xe9, 0x10, + 0x57, 0x36, 0x5e, 0x20, 0x94, 0x12, 0xd7, 0x6f, 0xce, 0xa0, 0x94, 0xfe, 0xc1, 0xb4, 0xfd, 0x72, + 0x20, 0x80, 0xd5, 0xad, 0xe4, 0x96, 0xd4, 0x9e, 0x0b, 0x8f, 0x06, 0x9f, 0x1a, 0x6e, 0xb7, 0x47, + 0x99, 0xb0, 0xbf, 0x0f, 0x68, 0x0f, 0xfa, 0x66, 0xba, 0xbb, 0x7b, 0x1e, 0xce, 0x64, 0x22, 0x5a, + 0x28, 0x30, 0x02, 0xed, 0x06, 0xc8, 0x66, 0xdb, 0x3b, 0xaf, 0xab, 0xcb, 0x8d, 0x7e, 0x42, 0xcd, + 0xdd, 0xa9, 0xc6, 0x1b, 0xd5, 0x12, 0x72, 0x61, 0x67, 0x9a, 0xcb, 0x6b, 0xd9, 0x72, 0x2d, 0xd8, + 0x94, 0x24, 0x08, 0x91, 0xd2, 0x0e, 0x49, 0x62, 0x07, 0x69, 0x42, 0xd6, 0x6e, 0xdc, 0x0e, 0x26, + 0x53, 0x25, 0x38, 0xea, 0xb7, 0xc7, 0x45, 0xdb, 0x83, 0x29, 0x3c, 0x28, 0x0f, 0x08, 0x49, 0xef, + 0x14, 0x10, 0x3e, 0xa3, 0xd2, 0x1d, 0xf8, 0xa4, 0xb5, 0x57, 0x35, 0xa3, 0xcf, 0xd5, 0x23, 0x67, + 0xaf, 0xb6, 0xb0, 0xae, 0xd9, 0x3e, 0xe6, 0xea, 0x3c, 0xa8, 0x66, 0xf9, 0xc1, 0xb9, 0xc5, 0xb4, + 0x39, 0x01, 0x78, 0x59, 0xea, 0x7e, 0x38, 0xc9, 0x98, 0x4d, 0xb7, 0x41, 0x71, 0x0f, 0xb2, 0xd0, + 0x87, 0x55, 0xf9, 0x4d, 0xe3, 0x96, 0x7d, 0xd0, 0xc9, 0x4c, 0x1e, 0xa6, 0x26, 0xf3, 0xad, 0xcc, + 0x93, 0x0a, 0x6a, 0xf9, 0x4e, 0x8b, 0xf5, 0xe2, 0x72, 0x44, 0x4a, 0xa9, 0xd2, 0x6f, 0x08, 0xf1, + 0x55, 0x57, 0x03, 0x7a, 0x16, 0xf9, 0xbd, 0x67, 0x26, 0xd4, 0xb6, 0x77, 0xd2, 0xcc, 0xbd, 0xf2, + 0xeb, 0xfb, 0xcc, 0x00, 0xdc, 0x12, 0xeb, 0xf3, 0xe9, 0xf5, 0x16, 0x12, 0x33, 0x68, 0xf6, 0x2d, + 0x97, 0xa3, 0x47, 0x34, 0xdf, 0x22, 0x9d, 0xfb, 0x26, 0x5c, 0x5e, 0x66, 0x28, 0x8b, 0xf0, 0x46, + 0x65, 0xa2, 0xf2, 0x08, 0xea, 0xb9, 0xf7, 0xef, 0xfc, 0x73, 0x88, 0x4a, 0xec, 0xf6, 0x79, 0x2d, + 0x6f, 0xec, 0xdf, 0x04, 0xed, 0x48, 0x7c, 0xaa, 0x75, 0x07, 0x5a, 0x5f, 0x53, 0x07, 0xba, 0x14, + 0x37, 0xd5, 0x2a, 0x23, 0xc3, 0x06, 0x76, 0xbd, 0x38, 0x7a, 0x50, 0x1f, 0xd5, 0xab, 0xfc, 0xd3, + 0x0e, 0x89, 0xda, 0xa2, 0x11, 0x61, 0x32, 0x44, 0x76, 0x7e, 0xcd, 0xc6, 0xed, 0x40, 0x7f, 0x30, + 0x2d, 0x32, 0xfc, 0x3f, 0x09, 0xc7, 0x55, 0xe2, 0x41, 0xff, 0xa3, 0x9a, 0x36, 0x44, 0x6b, 0xbe, + 0x0e, 0xad, 0xe8, 0x78, 0xff, 0xbf, 0x94, 0x04, 0x76, 0x29, 0x90, 0x7f, 0x20, 0x2f, 0x0d, 0xc0, + 0x53, 0x70, 0x39, 0xb7, 0x36, 0xdd, 0x22, 0xf1, 0xc7, 0xda, 0x0a, 0xf3, 0xf1, 0xd1, 0x4f, 0x6c, + 0x86, 0xd7, 0xde, 0x6e, 0x87, 0x4b, 0xce, 0x40, 0x50, 0x09, 0xfc, 0xf3, 0x18, 0x1a, 0x97, 0xe5, + 0x01, 0x22, 0x04, 0x3d, 0xb6, 0x90, 0x74, 0x53, 0x7e, 0x72, 0x1b, 0xd2, 0x44, 0x63, 0x95, 0x71, + 0x42, 0xd4, 0x02, 0x5b, 0x8f, 0x1e, 0x3f, 0x33, 0x68, 0x16, 0x96, 0x13, 0xe9, 0x25, 0x59, 0xb3, + 0x23, 0xd2, 0x5e, 0x55, 0x7a, 0xd2, 0x42, 0xc4, 0x7c, 0xd6, 0x15, 0xcb, 0x02, 0xc1, 0xdb, 0xa1, + 0x41, 0x64, 0x9d, 0x0d, 0xab, 0xc2, 0x44, 0x3f, 0x23, 0x4b, 0xba, 0x8a, 0x62, 0x59, 0x78, 0x42, + 0x48, 0x64, 0xf1, 0x4e, 0x12, 0x93, 0x69, 0x52, 0xcb, 0xda, 0x7e, 0x99, 0xa4, 0xe8, 0x54, 0x5e, + 0x93, 0x74, 0x45, 0xb2, 0xae, 0xa6, 0x68, 0xa7, 0xc1, 0xc3, 0x41, 0xdd, 0xd0, 0x4e, 0x81, 0x63, + 0x28, 0xa5, 0x31, 0xd7, 0xa1, 0x83, 0x93, 0x82, 0xd4, 0xb1, 0xdb, 0x55, 0x6a, 0xcb, 0x22, 0x49, + 0x01, 0xd0, 0xfb, 0x71, 0xaa, 0x0a, 0x8e, 0x78, 0xdb, 0x31, 0x41, 0xf4, 0x8c, 0x28, 0xd8, 0x3c, + 0x4a, 0x4e, 0xa8, 0x0c, 0x99, 0xc7, 0x56, 0x76, 0x87, 0x6e, 0xee, 0x41, 0xd1, 0x57, 0x26, 0x4b, + 0xaf, 0x23, 0x1b, 0xb5, 0xbd, 0x4a, 0x92, 0xa0, 0xdd, 0xeb, 0x08, 0x8a, 0xe5, 0x2a, 0xea, 0xcb, + 0xd6, 0x65, 0x84, 0x82, 0x5f, 0x5f, 0x73, 0x4f, 0x99, 0x12, 0x1d, 0x4e, 0x04, 0xf5, 0xc4, 0xe3, + 0xdf, 0xb7, 0x6a, 0xe8, 0x24, 0x33, 0xde, 0x3d, 0xb8, 0x96, 0xcc, 0x2a, 0xa1, 0xb3, 0x54, 0x96, + 0xd5, 0x57, 0xbb, 0xb3, 0x74, 0xe7, 0x91, 0xbf, 0x91, 0x76, 0x8a, 0xfc, 0xe0, 0x69, 0xa5, 0xab, + 0x45, 0xd8, 0x25, 0x7b, 0xe7, 0xc2, 0xaa, 0xb5, 0xfc, 0x3a, 0x7a, 0x10, 0x94, 0x3f, 0x98, 0x0e, + 0x65, 0xd8, 0xfa, 0xfd, 0x79, 0x6e, 0x13, 0x98, 0x26, 0x59, 0x90, 0x25, 0x49, 0x4c, 0xce, 0x3a, + 0xc7, 0xb9, 0xa6, 0x2f, 0xb8, 0xd3, 0x8d, 0x3e, 0x76, 0x6f, 0xe2, 0x74, 0x68, 0xa8, 0xb8, 0xd8, + 0xe5, 0x75, 0xf0, 0xf0, 0xf3, 0xfa, 0x46, 0x8f, 0xad, 0xe1, 0x47, 0x3b, 0xd9, 0x46, 0x4d, 0x3e, + 0x68, 0x03, 0x9c, 0xeb, 0xc5, 0xe3, 0x84, 0xfa, 0xea, 0x48, 0x31, 0x95, 0xf7, 0x43, 0x73, 0xd4, + 0x07, 0xac, 0xc9, 0xc6, 0x2e, 0x6c, 0xc7, 0x4d, 0xab, 0x60, 0xa3, 0x1b, 0x89, 0x01, 0x3e, 0x78, + 0x11, 0x75, 0x3d, 0x4c, 0xa9, 0x12, 0xc7, 0xf9, 0x60, 0x01, 0x88, 0xee, 0xa2, 0xe9, 0x89, 0x08, + 0xc6, 0xa9, 0x1c, 0x83, 0x49, 0xca, 0x52, 0x5e, 0xac, 0x5f, 0x2f, 0x82, 0xf7, 0x7e, 0x7f, 0x8b, + 0xd1, 0x40, 0xfe, 0x7e, 0x0d, 0x3d, 0xe1, 0x5f, 0x45, 0xf5, 0x46, 0x67, 0xe5, 0x5e, 0x7c, 0x70, + 0xd0, 0x4a, 0xc9, 0x1e, 0x4f, 0xbd, 0x1d, 0x6d, 0x3e, 0xd0, 0xfb, 0xd4, 0xf0, 0x79, 0xbc, 0x76, + 0xbd, 0x8f, 0x34, 0x86, 0xd4, 0xfc, 0xf8, 0x1c, 0x0d, 0x70, 0xfa, 0x3d, 0xa6, 0xe5, 0x8c, 0x0a, + 0xe5, 0xe9, 0x45, 0x47, 0x3b, 0xb9, 0xa1, 0x49, 0xb5, 0x5f, 0xf8, 0x6c, 0x68, 0x05, 0x67, 0xc0, + 0x14, 0x3c, 0x9b, 0xc8, 0xe6, 0x0e, 0x60, 0x7e, 0xf8, 0xbb, 0x73, 0x8b, 0xc5, 0x1e, 0x24, 0x7b, + 0x28, 0x07, 0x34, 0xed, 0x64, 0x6d, 0xa0, 0xe9, 0x24, 0x12, 0x03, 0x75, 0x5e, 0x46, 0xa8, 0x4d, + 0xd4, 0x14, 0xc9, 0xc6, 0xe1, 0xfe, 0x12, 0xfb, 0xd1, 0xdb, 0x7e, 0xad, 0xb1, 0x2b, 0x43, 0xe8, + 0xd9, 0x3f, 0x58, 0xbe, 0xe5, 0x4c, 0x4f, 0xe7, 0x38, 0x50, 0xdc, 0xbe, 0x7c, 0x5b, 0x03, 0x4e, + 0x10, 0xea, 0x22, 0xd7, 0xb0, 0xb8, 0x5c, 0x90, 0xeb, 0x28, 0x0c, 0x40, 0x10, 0xea, 0x4f, 0x52, + 0x00, 0x6c, 0xb2, 0xb2, 0xc3, 0xa5, 0x10, 0x65, 0x31, 0x17, 0xb8, 0xa9, 0xf2, 0x4e, 0xfc, 0x24, + 0x4b, 0x52, 0x0e, 0x34, 0x7b, 0x3f, 0x85, 0x8f, 0xbb, 0x96, 0x44, 0x28, 0xf8, 0x9b, 0xbd, 0xa3, + 0x8a, 0xdf, 0x9a, 0xae, 0x90, 0x8b, 0x72, 0xc7, 0xed, 0x40, 0x4a, 0xe3, 0x9d, 0xc0, 0x63, 0x36, + 0x07, 0x61, 0xa2, 0xf5, 0x07, 0xa4, 0xc6, 0x80, 0x5c, 0x2f, 0xe1, 0x71, 0x5e, 0xb2, 0xd9, 0x61, + 0x2c, 0xeb, 0xab, 0x43, 0xa4, 0x77, 0xe8, 0xa7, 0x50, 0x00, 0x9e, 0x8e, 0x42, 0x51, 0xc9, 0x82, + 0xa6, 0xd9, 0x12, 0xc7, 0x83, 0x12, 0x02, 0xb7, 0x33, 0xd0, 0xd8, 0x53, 0x79, 0xfd, 0x0c, 0x7e, + 0xae, 0xc5, 0x64, 0xd7, 0xd9, 0xee, 0x09, 0xaa, 0x8c, 0x6e, 0x2d, 0x33, 0x73, 0xe0, 0x71, 0x07, + 0xa9, 0xab, 0x1d, 0x27, 0x75, 0x49, 0x59, 0xeb, 0x49, 0x18, 0x1e, 0xdd, 0x9d, 0x63, 0xee, 0xc1, + 0x71, 0xed, 0x13, 0x8f, 0x43, 0x52, 0xb8, 0x54, 0x21, 0xb2, 0x11, 0x2f, 0x15, 0x60, 0x0f, 0x75, + 0x4e, 0x40, 0x6e, 0x1c, 0xe7, 0x38, 0x9b, 0xc4, 0xca, 0x6a, 0x14, 0xb6, 0x25, 0x58, 0x62, 0xe1, + 0xb0, 0x45, 0x05, 0x04, 0x88, 0x82, 0x21, 0xfc, 0x11, 0x94, 0xce, 0x01, 0x82, 0x5d, 0x6a, 0xfa, + 0x3d, 0x7e, 0xc5, 0x00, 0x00, 0x80, 0x49, 0x26, 0x20, 0x11, 0x0e, 0x8a, 0xcd, 0xcd, 0x09, 0x42, + 0xe3, 0x9f, 0x9c, 0xb5, 0x24, 0x0d, 0x11, 0x15, 0x02, 0x1c, 0xc2, 0xf1, 0x5c, 0xc4, 0xfe, 0x84, + 0xae, 0x70, 0x41, 0x37, 0x91, 0xb5, 0x00, 0x15, 0xd2, 0x2a, 0x12, 0x49, 0x14, 0x2d, 0x48, 0x9c, + 0x9e, 0xe9, 0xf3, 0xe4, 0x12, 0x84, 0xb0, 0x9f, 0xdd, 0x2b, 0xc3, 0xa0, 0x7c, 0xad, 0xbe, 0x02, + 0xad, 0x55, 0x3b, 0xab, 0x05, 0x89, 0xe8, 0x86, 0xd0, 0x89, 0x44, 0x5e, 0x2b, 0x55, 0x56, 0x46, + 0x44, 0x0c, 0x51, 0x23, 0x30, 0x9e, 0x93, 0x95, 0xed, 0x0c, 0xa6, 0x4d, 0x94, 0x60, 0xe8, 0x5c, + 0x25, 0x64, 0xbc, 0x27, 0xc3, 0x51, 0x2a, 0xc3, 0x41, 0x84, 0x9e, 0x1f, 0x2a, 0x70, 0x87, 0x2a, + 0x17, 0x0e, 0xfd, 0x69, 0x79, 0x5a, 0x76, 0x3c, 0xfc, 0x52, 0x71, 0x20, 0x76, 0x8e, 0x84, 0x98, + 0x8f, 0x70, 0x6c, 0xdd, 0xe3, 0x22, 0xe6, 0x84, 0xa0, 0xb9, 0xc2, 0xda, 0xdd, 0x6f, 0xce, 0xa0, + 0x54, 0xfe, 0xa1, 0x4f, 0xe7, 0x73, 0x76, 0x59, 0xb3, 0xaa, 0x1a, 0x81, 0xae, 0x42, 0x62, 0xef, + 0x2e, 0x5d, 0xd4, 0xad, 0xa7, 0xd6, 0x50, 0x55, 0xcd, 0x22, 0xe5, 0x2b, 0xa3, 0xf0, 0x7c, 0xbe, + 0xb6, 0x2e, 0x1f, 0xc4, 0xb9, 0xed, 0x34, 0xca, 0x98, 0xe6, 0x1a, 0x24, 0xcf, 0x96, 0x24, 0xf6, + 0xae, 0x5b, 0xa2, 0x4d, 0xef, 0x16, 0x47, 0x65, 0x6b, 0xd5, 0xe2, 0x25, 0x49, 0x3d, 0xa7, 0x8b, + 0x9e, 0xae, 0x14, 0xd2, 0x63, 0x0f, 0xd2, 0xb3, 0x0b, 0xdc, 0x15, 0xb4, 0xb1, 0x2e, 0x4c, 0x30, + 0xf7, 0x04, 0x1e, 0x10, 0xd5, 0x45, 0x09, 0x11, 0x95, 0x0b, 0x44, 0x20, 0x8e, 0xac, 0x64, 0x9c, + 0xdc, 0xc7, 0xc4, 0x95, 0x66, 0xcd, 0x52, 0xb5, 0x0f, 0x6a, 0x99, 0x1a, 0xe1, 0x5f, 0xcf, 0x39, + 0xee, 0x29, 0x4c, 0x65, 0x1a, 0x88, 0x33, 0xf2, 0x7a, 0xf8, 0x6f, 0x5c, 0x0d, 0x54, 0xc6, 0x0a, + 0xb6, 0xc0, 0x1e, 0x40, 0x55, 0xec, 0x21, 0x18, 0xcf, 0x01, 0xb5, 0x0d, 0x3c, 0xc7, 0xf6, 0x04, + 0xda, 0xe2, 0xf5, 0xf7, 0x75, 0x0d, 0x07, 0x50, 0xaf, 0x9b, 0x1a, 0x16, 0x68, 0xeb, 0xbd, 0x2d, + 0x42, 0x1b, 0x1d, 0xd6, 0x75, 0xea, 0xbf, 0x0a, 0x3c, 0x60, 0x2d, 0x90, 0x60, 0x01, 0x3a, 0x0f, + 0x6b, 0x24, 0xf3, 0x05, 0x30, 0x36, 0x5b, 0xd8, 0xa5, 0xdc, 0x97, 0xda, 0x1d, 0x94, 0xdd, 0x70, + 0x20, 0xcb, 0xb3, 0x80, 0xca, 0x3d, 0xfe, 0x5c, 0x74, 0x8d, 0x67, 0x95, 0xf0, 0xdd, 0x6b, 0xba, + 0x21, 0xae, 0xa4, 0x10, 0xf6, 0x41, 0xa5, 0x93, 0x60, 0x03, 0x6b, 0x04, 0x45, 0x29, 0xae, 0x99, + 0xf8, 0x3a, 0xe0, 0x90, 0x98, 0x41, 0x25, 0xae, 0xe1, 0x35, 0x07, 0x7e, 0xf1, 0xe7, 0x17, 0x85, + 0xa3, 0xfd, 0x90, 0xf8, 0x00, 0x26, 0x16, 0x17, 0x1d, 0xd7, 0x16, 0x0a, 0x90, 0x96, 0x9f, 0x1c, + 0x8b, 0x39, 0xae, 0xe0, 0x0c, 0x50, 0x09, 0x04, 0x17, 0x63, 0xb2, 0x63, 0x84, 0x60, 0x1b, 0xdd, + 0x09, 0x79, 0x5e, 0x78, 0x78, 0x83, 0xcc, 0xed, 0xb9, 0xc9, 0x45, 0xfe, 0x59, 0xec, 0xd7, 0x71, + 0x9a, 0xa2, 0xf9, 0x83, 0xe9, 0xe2, 0xd0, 0x01, 0xc0, 0xd6, 0xc5, 0x47, 0x64, 0x11, 0x2a, 0xa6, + 0xc4, 0x1d, 0x32, 0xb4, 0x83, 0x28, 0x21, 0xfe, 0x81, 0x7f, 0x65, 0x96, 0x38, 0x15, 0x05, 0x5e, + 0xec, 0x95, 0xe6, 0x16, 0xc4, 0x77, 0x84, 0xa4, 0x76, 0x50, 0xec, 0x6e, 0xe0, 0xd2, 0xd2, 0x69, + 0xcf, 0xb4, 0x74, 0x3a, 0x56, 0xaa, 0x58, 0x6d, 0x21, 0x2a, 0x1a, 0xc6, 0x6e, 0xee, 0x8a, 0x50, + 0x5b, 0x98, 0x10, 0x15, 0x64, 0xf0, 0x49, 0x5d, 0x25, 0xf4, 0x1e, 0x07, 0x57, 0xe0, 0x31, 0x3e, + 0xcd, 0xab, 0x86, 0x47, 0xab, 0x92, 0xeb, 0x5d, 0xaa, 0xbd, 0x8c, 0x11, 0xd4, 0x59, 0xe9, 0x03, + 0x72, 0x0f, 0x01, 0x86, 0x68, 0x6f, 0x46, 0xc5, 0xd5, 0x28, 0x94, 0x02, 0x9e, 0x0a, 0x95, 0xb3, + 0x41, 0xd9, 0x55, 0x2a, 0x8a, 0xc1, 0xd4, 0x08, 0x5d, 0x94, 0xec, 0x6a, 0xb2, 0x2a, 0x55, 0xdd, + 0xae, 0x33, 0xdb, 0x3a, 0x19, 0x83, 0x4e, 0xc7, 0x5c, 0x7a, 0xae, 0x9d, 0xb8, 0x22, 0x2b, 0x97, + 0x78, 0xec, 0xd9, 0xba, 0x2e, 0xee, 0x2d, 0xef, 0x3e, 0x75, 0x86, 0xca, 0xe5, 0xbc, 0x42, 0xfe, + 0xd2, 0x30, 0x38, 0xfe, 0x6d, 0xd6, 0x40, 0x86, 0x81, 0x52, 0x92, 0xf7, 0xeb, 0x6c, 0x12, 0x10, + 0xb8, 0xcb, 0xbd, 0xcf, 0x32, 0xb1, 0xaa, 0xce, 0xe9, 0xa1, 0x20, 0x25, 0x12, 0x46, 0x6d, 0xaa, + 0x91, 0x26, 0xa1, 0x10, 0xb5, 0x21, 0xa9, 0x8d, 0x73, 0xfa, 0x90, 0x48, 0xbe, 0x71, 0x42, 0xaa, + 0x02, 0x53, 0x6c, 0x7f, 0x1f, 0xac, 0x1f, 0xc8, 0x7e, 0x61, 0xe5, 0x70, 0xa3, 0x37, 0x53, 0x83, + 0xb6, 0xdf, 0xbe, 0x66, 0x38, 0xc6, 0xa7, 0x0c, 0xab, 0xb9, 0xf3, 0xca, 0x5a, 0x72, 0x18, 0x5b, + 0x6d, 0x81, 0xe0, 0xf1, 0xc8, 0x64, 0x28, 0x44, 0x13, 0x72, 0x5b, 0xe5, 0xec, 0xb5, 0xcb, 0x75, + 0xf9, 0x7d, 0x6d, 0xf9, 0x3f, 0xad, 0xc8, 0xd6, 0xbc, 0x07, 0xd9, 0xa2, 0x66, 0x24, 0xa2, 0xa1, + 0x79, 0x64, 0xd0, 0x5d, 0x65, 0xe4, 0xdb, 0x2e, 0xbf, 0x86, 0x25, 0xd7, 0x5d, 0x25, 0xe5, 0x9c, + 0xf3, 0xdf, 0x9c, 0x6d, 0xc6, 0xfc, 0x83, 0xe9, 0x14, 0xcd, 0x2f, 0xd0, 0x84, 0x68, 0xde, 0x52, + 0xb2, 0x3e, 0x7b, 0xe1, 0x34, 0xf6, 0x6c, 0x06, 0x83, 0x4c, 0x6e, 0xfe, 0xd6, 0xa5, 0x93, 0x7b, + 0x32, 0xef, 0x02, 0x2b, 0xdc, 0x30, 0xfd, 0x95, 0xe1, 0x84, 0xfc, 0xad, 0x63, 0x29, 0xbb, 0x73, + 0x96, 0x81, 0xb6, 0x47, 0x1e, 0x74, 0x19, 0x20, 0xfe, 0xc2, 0x2f, 0x81, 0x12, 0x4c, 0x37, 0x7d, + 0xbb, 0x5e, 0x48, 0x5b, 0xce, 0x91, 0xc1, 0xe5, 0xe7, 0x75, 0x07, 0x8a, 0xe9, 0xbf, 0x1d, 0xdf, + 0x16, 0xe6, 0x8e, 0xbc, 0x70, 0x4e, 0xc6, 0x39, 0x1e, 0x72, 0xbf, 0x78, 0x1b, 0x4f, 0xb7, 0x97, + 0x90, 0x73, 0xf1, 0x56, 0x93, 0xde, 0x26, 0x1a, 0xc0, 0xb9, 0x13, 0x41, 0x4c, 0xec, 0xaa, 0x17, + 0x51, 0xe6, 0xba, 0x17, 0x33, 0x86, 0x92, 0xe2, 0x2a, 0xc6, 0x71, 0x3a, 0x88, 0xe7, 0x26, 0x57, + 0xd8, 0xcf, 0x2e, 0xcb, 0x0f, 0xce, 0x72, 0x3f, 0xb7, 0x1d, 0x27, 0xbd, 0x87, 0x52, 0xa9, 0xf7, + 0x1c, 0xf1, 0xa8, 0xe2, 0xe9, 0xbc, 0xd8, 0xe7, 0x2a, 0x6a, 0xb6, 0x4b, 0x77, 0xd9, 0xac, 0xfa, + 0xbc, 0xb6, 0x6a, 0xf9, 0x16, 0xb8, 0x4d, 0xd3, 0xef, 0x9d, 0xc8, 0x22, 0xa3, 0x15, 0x14, 0x62, + 0xc3, 0xa1, 0xef, 0x9c, 0xd0, 0xc8, 0xc5, 0x58, 0x48, 0x05, 0x4c, 0xeb, 0x43, 0x1b, 0xdf, 0xf4, + 0x57, 0xbf, 0xe9, 0x90, 0x51, 0x09, 0x75, 0x4d, 0x67, 0xcd, 0x97, 0x33, 0x2e, 0xa2, 0x90, 0xd9, + 0xa9, 0x26, 0x50, 0x01, 0xa0, 0xf1, 0x30, 0x87, 0x6b, 0x8e, 0x94, 0xb2, 0xf0, 0xe4, 0x8e, 0xd3, + 0x4f, 0x77, 0x6a, 0xa1, 0x95, 0x38, 0x7b, 0x90, 0xb0, 0x69, 0xbf, 0x4b, 0xe8, 0x79, 0x40, 0x3f, + 0x44, 0x22, 0x16, 0x79, 0xb3, 0x46, 0x99, 0x13, 0xa6, 0xe7, 0xb3, 0x56, 0xf2, 0xb0, 0xa9, 0x2c, + 0xe0, 0xe2, 0x24, 0xaa, 0x6d, 0xd8, 0x15, 0x2b, 0x2b, 0x44, 0x6d, 0x16, 0x1b, 0xa5, 0xec, 0x3b, + 0xb7, 0x75, 0xa7, 0x86, 0x92, 0x2d, 0xb4, 0xab, 0x09, 0xeb, 0xdc, 0x3f, 0x21, 0xc5, 0x65, 0x22, + 0xb6, 0x9d, 0x58, 0xe1, 0x4c, 0x7f, 0x53, 0xdd, 0xa6, 0x63, 0xfa, 0x83, 0x69, 0x2a, 0xed, 0xd1, + 0xf9, 0x5f, 0x11, 0x2e, 0xbb, 0xfa, 0x66, 0x96, 0x57, 0x6e, 0xd0, 0x2d, 0xee, 0xc1, 0xfa, 0xfe, + 0xdc, 0xdc, 0xc1, 0xbb, 0xb7, 0x9c, 0x18, 0x5f, 0xdc, 0x92, 0x44, 0xcf, 0x47, 0x17, 0x5f, 0x00, + 0xa2, 0x73, 0x01, 0xc8, 0x6e, 0xba, 0x56, 0xd6, 0x95, 0xe7, 0xaa, 0xc3, 0x06, 0x4d, 0x1d, 0x48, + 0xad, 0xef, 0x6e, 0x8e, 0xcd, 0x35, 0xc2, 0x18, 0x04, 0x25, 0xae, 0x1e, 0xa3, 0x2f, 0x77, 0x75, + 0xd6, 0x79, 0x86, 0x70, 0x88, 0xc9, 0x28, 0x0b, 0x5b, 0x4a, 0xae, 0x88, 0x8c, 0x50, 0x0c, 0xa2, + 0xab, 0x01, 0xad, 0xed, 0x3b, 0x65, 0xaa, 0xc1, 0xbd, 0x7e, 0x5d, 0xc7, 0x36, 0x48, 0x48, 0x9c, + 0xde, 0xf0, 0xca, 0x9f, 0x95, 0x5e, 0xb0, 0xce, 0x55, 0x89, 0x09, 0x78, 0x65, 0x05, 0xda, 0xac, + 0xcf, 0x4f, 0x04, 0x1b, 0x38, 0x0b, 0xb8, 0x06, 0xf7, 0xf9, 0x98, 0xf0, 0xaa, 0xae, 0x12, 0xd4, + 0x36, 0x12, 0x4b, 0x98, 0xc0, 0x9e, 0x4c, 0xd7, 0x25, 0x96, 0x66, 0x43, 0xd0, 0x1a, 0x30, 0x29, + 0x16, 0x57, 0xaa, 0xfb, 0x49, 0x25, 0xbc, 0xb9, 0x60, 0x15, 0xa2, 0x81, 0xf4, 0xb8, 0xed, 0x2a, + 0x4d, 0xfa, 0x2d, 0x5b, 0x67, 0xe5, 0x3a, 0x9c, 0x33, 0x34, 0xe5, 0x82, 0xe2, 0xe8, 0x02, 0x2a, + 0xc5, 0x64, 0x75, 0x9e, 0x39, 0x14, 0xc8, 0xd4, 0x27, 0x4d, 0x4d, 0x9d, 0x2f, 0xbe, 0x8f, 0xdd, + 0x0d, 0xbe, 0x60, 0x81, 0x81, 0x68, 0x0a, 0xba, 0x7f, 0x4c, 0x57, 0x5d, 0xd3, 0x66, 0xcc, 0x20, + 0xa8, 0xe0, 0x93, 0xb1, 0x5d, 0x94, 0x56, 0xb0, 0x2f, 0x8d, 0x09, 0x6e, 0xe1, 0x5b, 0x00, 0x7b, + 0x31, 0x94, 0x4c, 0x07, 0xb5, 0x95, 0x72, 0xe0, 0xaa, 0xf3, 0xf9, 0xb1, 0x32, 0xec, 0x0b, 0x5a, + 0x29, 0x08, 0xc9, 0x46, 0x82, 0xdf, 0x59, 0xcb, 0x16, 0x8b, 0xe4, 0x93, 0x89, 0xef, 0x4c, 0xf0, + 0x59, 0xfa, 0x56, 0xe7, 0xb8, 0x0e, 0x3c, 0xd6, 0xd3, 0x9f, 0x63, 0x0a, 0x6b, 0xf3, 0x52, 0x66, + 0xab, 0xe3, 0x25, 0x81, 0xa5, 0x96, 0x14, 0x18, 0xe0, 0x5f, 0xef, 0x7b, 0x98, 0xac, 0x7f, 0x30, + 0x3d, 0x17, 0xdd, 0x29, 0xff, 0xab, 0x97, 0x3f, 0x78, 0xd8, 0x67, 0xf6, 0xe5, 0xd1, 0xca, 0x85, + 0x74, 0xdd, 0x76, 0xc1, 0x13, 0xb0, 0x5d, 0xa9, 0xa4, 0x74, 0xed, 0x71, 0x8e, 0xf5, 0x50, 0xdc, + 0xa8, 0x5e, 0xf2, 0x1f, 0x6e, 0x5a, 0xf3, 0xb6, 0xcc, 0x69, 0x8f, 0x79, 0x5a, 0x8e, 0xd4, 0x2d, + 0xaa, 0x89, 0x76, 0xdf, 0x2c, 0x12, 0x94, 0xbc, 0x20, 0xb7, 0x29, 0x1e, 0x6c, 0xd6, 0xb9, 0x43, + 0x75, 0x22, 0x3b, 0xf0, 0xaf, 0xb5, 0x3e, 0x27, 0x03, 0xa3, 0xa4, 0x4e, 0xdb, 0x08, 0x69, 0xf4, + 0xaa, 0x13, 0xaf, 0x72, 0x5c, 0x28, 0xd3, 0xb1, 0x28, 0x86, 0xe3, 0x9c, 0x9a, 0xb6, 0x41, 0x64, + 0xb5, 0x53, 0x55, 0xe8, 0xf9, 0x27, 0x10, 0xb9, 0x9e, 0xc1, 0x26, 0x01, 0x32, 0x38, 0x97, 0x7f, + 0xf1, 0xc8, 0x45, 0x02, 0xe7, 0xd2, 0x6d, 0xef, 0xe0, 0xe5, 0xe5, 0x22, 0x67, 0x12, 0xd5, 0x2d, + 0x8b, 0xce, 0xb3, 0x57, 0x1b, 0x44, 0x4a, 0x98, 0x99, 0x47, 0x8f, 0xb1, 0xd5, 0x51, 0x3a, 0x05, + 0x33, 0x33, 0x4c, 0x73, 0xe3, 0x47, 0x76, 0x4c, 0x4a, 0xb6, 0x36, 0x73, 0x3a, 0xb7, 0xdf, 0x62, + 0x0d, 0x63, 0xf1, 0xf6, 0xc8, 0x7e, 0x6f, 0xff, 0x5a, 0x22, 0xd7, 0x7c, 0xdd, 0x53, 0x43, 0xbb, + 0xbb, 0xd0, 0xac, 0x10, 0xb1, 0x61, 0x38, 0x46, 0xde, 0xbc, 0xe4, 0x44, 0x26, 0x05, 0x0a, 0xee, + 0xb8, 0x93, 0xf8, 0xbd, 0x09, 0x36, 0x23, 0xa9, 0x7e, 0x53, 0xc4, 0x8e, 0x9e, 0x9e, 0x2e, 0x33, + 0x50, 0x28, 0xd0, 0x0c, 0xa5, 0x06, 0xd0, 0x4a, 0x32, 0xc4, 0x97, 0x58, 0x25, 0x8b, 0xed, 0xb4, + 0xa2, 0xb6, 0x08, 0xd9, 0x5e, 0x8e, 0x73, 0xc2, 0xd2, 0x1d, 0x8a, 0xe9, 0x92, 0x63, 0x16, 0x04, + 0x5f, 0x79, 0xc1, 0x17, 0xde, 0x23, 0x3e, 0xa7, 0x6d, 0xbd, 0x12, 0xef, 0xcb, 0x66, 0x47, 0xa0, + 0xc9, 0x55, 0xd9, 0x15, 0x34, 0xd5, 0x6e, 0x29, 0xdd, 0x8f, 0x82, 0x81, 0x84, 0xb8, 0x94, 0x2e, + 0x57, 0x5e, 0xc5, 0xdb, 0xcd, 0x8b, 0xf7, 0x56, 0x3f, 0xac, 0xe3, 0x40, 0xf2, 0xfc, 0x37, 0x75, + 0x84, 0x44, 0x7f, 0x30, 0xcd, 0xb2, 0xfa, 0x8f, 0x88, 0x3a, 0x7b, 0x22, 0x20, 0xd2, 0x8d, 0xed, + 0xbb, 0x41, 0x33, 0xc2, 0xe9, 0x5e, 0xa1, 0x3a, 0xdb, 0x3a, 0xbd, 0x60, 0xde, 0x75, 0x87, 0xec, + 0x2c, 0x36, 0x38, 0xbe, 0x8d, 0xea, 0xb4, 0xb5, 0x7a, 0xaf, 0x80, 0x13, 0x17, 0xa7, 0x86, 0x81, + 0xe4, 0x95, 0x31, 0xd0, 0x2c, 0x32, 0xac, 0xbc, 0xa0, 0xa9, 0x85, 0x1a, 0x5e, 0xc8, 0x49, 0x64, + 0xb2, 0xd9, 0x0d, 0x73, 0xb5, 0x65, 0x6b, 0xbc, 0x95, 0xc4, 0xa6, 0x9d, 0xb9, 0xc7, 0xe6, 0xdf, + 0x9d, 0x14, 0xb7, 0xbc, 0x94, 0xcf, 0x73, 0xef, 0x17, 0x64, 0xb8, 0xac, 0xea, 0x4a, 0x71, 0x07, + 0x32, 0xea, 0x6d, 0xff, 0xd1, 0xdd, 0x3a, 0x2e, 0x55, 0x5c, 0xa8, 0x4d, 0x63, 0xd7, 0xdd, 0x24, + 0x09, 0xbb, 0xb6, 0xc3, 0x35, 0x87, 0x9a, 0xd6, 0xb4, 0x52, 0x05, 0xc5, 0x3b, 0x66, 0xbb, 0x40, + 0x4d, 0x35, 0x97, 0x15, 0xa1, 0x1c, 0x8b, 0xb8, 0xc6, 0xf9, 0x19, 0x0f, 0xe1, 0x0e, 0x41, 0xa2, + 0x68, 0x07, 0xe5, 0x73, 0xae, 0x25, 0xe3, 0x67, 0x42, 0x31, 0xb4, 0xf1, 0x8c, 0xc4, 0xb5, 0xf4, + 0x6d, 0x4f, 0x10, 0xec, 0x88, 0x0f, 0xae, 0x32, 0xbd, 0x66, 0xd4, 0x2f, 0x09, 0xe9, 0x38, 0x48, + 0x65, 0x3c, 0x94, 0xb9, 0xe1, 0x51, 0xfd, 0xdb, 0x2d, 0x29, 0x61, 0x40, 0x03, 0x77, 0x28, 0x96, + 0x17, 0x1f, 0x29, 0x42, 0xe9, 0x28, 0x19, 0xaa, 0xab, 0x42, 0xb6, 0x8b, 0xf4, 0xde, 0xc6, 0x18, + 0xc9, 0x70, 0x24, 0x9a, 0xaf, 0x4a, 0xc7, 0x78, 0x66, 0x61, 0x05, 0xaa, 0x3c, 0x2f, 0x09, 0xa0, + 0x57, 0xe9, 0x16, 0x33, 0x7d, 0x97, 0x4c, 0xd9, 0x4b, 0x86, 0xce, 0x75, 0x74, 0x40, 0x30, 0xeb, + 0xf6, 0xda, 0x51, 0x3b, 0xa9, 0x84, 0x7e, 0xfc, 0x1c, 0xb7, 0x4a, 0x12, 0x7b, 0x6b, 0xe2, 0x54, + 0x83, 0x64, 0xe1, 0xb1, 0xe5, 0xbf, 0x5c, 0xfd, 0x6e, 0x7b, 0x0e, 0x09, 0xa0, 0xab, 0x46, 0xdc, + 0x76, 0x81, 0x90, 0xc7, 0xd3, 0xe4, 0x29, 0x75, 0xab, 0xad, 0x69, 0xec, 0x8f, 0x9b, 0xed, 0xf8, + 0x6f, 0x6a, 0xae, 0xa0, 0x7f, 0x30, 0xcd, 0x95, 0x7a, 0x83, 0xcd, 0x08, 0xdf, 0xe9, 0x08, 0xce, + 0xf3, 0x05, 0xcd, 0xf7, 0x06, 0x8c, 0x1e, 0x23, 0x74, 0xac, 0x15, 0x0a, 0x59, 0x41, 0x60, 0x20, + 0xbb, 0xcc, 0x3d, 0x28, 0x16, 0xb9, 0x32, 0x81, 0x46, 0x3c, 0x66, 0xe5, 0x22, 0x24, 0x8d, 0x9d, + 0x96, 0x58, 0xaf, 0x51, 0x7b, 0x67, 0x03, 0xcf, 0xb3, 0x5d, 0x4f, 0x61, 0x95, 0x9e, 0x74, 0xe1, + 0x7d, 0xb1, 0x90, 0xb0, 0x8e, 0xf4, 0xb0, 0xaa, 0xcf, 0x3b, 0x70, 0x1d, 0x5e, 0xaa, 0xde, 0x97, + 0x9c, 0xf1, 0xcc, 0x50, 0x3e, 0xcd, 0xd2, 0xf5, 0x4e, 0xca, 0x22, 0xb0, 0x2b, 0x0c, 0x86, 0x49, + 0xee, 0x5a, 0x44, 0x9a, 0xbe, 0x3f, 0xe9, 0x51, 0xf5, 0xc9, 0x93, 0xda, 0x6c, 0xd6, 0xa2, 0x0e, + 0x31, 0x26, 0xe9, 0x4a, 0x08, 0x67, 0xcb, 0x0e, 0xa7, 0x75, 0x1b, 0x46, 0xc2, 0x13, 0xa9, 0xe0, + 0xb0, 0x45, 0x2c, 0xaf, 0xc1, 0xcc, 0x39, 0x8b, 0xef, 0xfe, 0xae, 0x37, 0x74, 0xf9, 0x4d, 0x3c, + 0x0b, 0xd6, 0xaa, 0x12, 0xf8, 0x35, 0x9c, 0xce, 0xca, 0x45, 0xc2, 0x10, 0x5b, 0x75, 0x76, 0x82, + 0x30, 0x24, 0xa2, 0x0a, 0xbc, 0x49, 0x08, 0xe4, 0x08, 0x8f, 0x10, 0xb9, 0x9e, 0xe7, 0xd8, 0x77, + 0x9d, 0x16, 0xcb, 0x20, 0x38, 0x92, 0x4a, 0x75, 0x64, 0xd5, 0x5b, 0xe3, 0x7c, 0xab, 0x1d, 0xa3, + 0xb3, 0x17, 0x07, 0x67, 0xd8, 0x4f, 0x4e, 0x05, 0x67, 0x7d, 0x96, 0x81, 0x81, 0xe2, 0x4f, 0x2e, + 0xae, 0x13, 0x81, 0x32, 0x80, 0x18, 0x63, 0x3c, 0xdd, 0xcd, 0x70, 0xe2, 0x78, 0x7a, 0x66, 0xd0, + 0x1d, 0x63, 0xea, 0x32, 0x9f, 0x7d, 0xf8, 0xaa, 0x34, 0x57, 0x10, 0x35, 0x49, 0x13, 0x0b, 0x7c, + 0x83, 0xdd, 0x3b, 0xb8, 0x8a, 0xce, 0x5d, 0x04, 0x69, 0xc5, 0x07, 0x48, 0x18, 0xc8, 0x71, 0x54, + 0x4e, 0xb5, 0xd9, 0x66, 0x00, 0x7e, 0xbe, 0xe8, 0x4e, 0xdf, 0x48, 0x29, 0xd9, 0x7e, 0xf2, 0x0f, + 0x5f, 0x48, 0x07, 0x82, 0x2c, 0x01, 0x41, 0x02, 0x1b, 0x93, 0x63, 0x6d, 0x88, 0x25, 0xf7, 0x22, + 0xbf, 0xd6, 0x11, 0xc2, 0xff, 0x60, 0x7a, 0x19, 0x05, 0x4f, 0x83, 0xc7, 0x12, 0xc2, 0xd5, 0x2b, + 0xcc, 0xf7, 0xc5, 0x11, 0xb5, 0x7e, 0xdc, 0x20, 0x3f, 0x95, 0x8c, 0xe9, 0xab, 0x67, 0x91, 0x5a, + 0xe8, 0xe1, 0x35, 0x2b, 0xad, 0x4f, 0x69, 0x08, 0x5c, 0x57, 0xab, 0xf2, 0xef, 0xdf, 0xba, 0x9e, + 0x3f, 0x21, 0x29, 0x0d, 0x81, 0x56, 0xd7, 0xa4, 0x4d, 0x76, 0xe5, 0x95, 0x8b, 0x79, 0xd3, 0x4b, + 0xb2, 0x11, 0x13, 0x45, 0x0f, 0x26, 0x29, 0xe1, 0x55, 0x7f, 0x08, 0x85, 0x81, 0x34, 0xeb, 0xd5, + 0x2e, 0xea, 0x70, 0xab, 0x51, 0x72, 0x38, 0x2f, 0x3b, 0x0b, 0x7e, 0x2a, 0x34, 0x70, 0xe7, 0x41, + 0x02, 0xbb, 0xf3, 0xc6, 0x87, 0x3a, 0xff, 0xa9, 0x87, 0x9a, 0x39, 0x18, 0x5f, 0x5d, 0x2f, 0xb2, + 0xc7, 0x5b, 0x6d, 0x65, 0xf5, 0x36, 0x62, 0x9a, 0xd5, 0x86, 0x98, 0x45, 0x5b, 0xd4, 0x14, 0xe8, + 0xae, 0x64, 0xe4, 0x3f, 0x33, 0x6c, 0xe7, 0xc3, 0x39, 0xc2, 0xce, 0x09, 0xe3, 0x88, 0x54, 0x75, + 0x45, 0xb2, 0xb4, 0xc2, 0xb1, 0x62, 0xe9, 0x3e, 0x5d, 0x4a, 0xe6, 0x34, 0x29, 0xe7, 0x66, 0x48, + 0x59, 0x34, 0x87, 0x5e, 0xee, 0x05, 0x35, 0x0d, 0xbb, 0x2f, 0xb6, 0xc0, 0x5c, 0x65, 0x13, 0x3b, + 0x1b, 0x5b, 0x60, 0x03, 0xb5, 0xa8, 0xb6, 0x1d, 0xfe, 0xc8, 0xe4, 0x84, 0xe3, 0xcc, 0xa0, 0x0e, + 0xfa, 0x06, 0x5d, 0x81, 0xe6, 0xf5, 0x3b, 0xa7, 0x85, 0x0d, 0x10, 0x91, 0x08, 0x3f, 0x43, 0x50, + 0xae, 0x58, 0x18, 0x42, 0x41, 0x7d, 0x44, 0xb4, 0x40, 0x33, 0x3f, 0x8e, 0x6a, 0xdc, 0xa1, 0x0e, + 0xa2, 0x8b, 0xcb, 0x04, 0x9d, 0xcc, 0x0b, 0xa3, 0x1e, 0xa8, 0xe6, 0xa8, 0x20, 0x9c, 0xdd, 0x35, + 0x8f, 0x29, 0x41, 0xd7, 0x97, 0xde, 0x35, 0x72, 0x2a, 0x3f, 0x93, 0x04, 0x80, 0x07, 0xd5, 0x02, + 0xc0, 0xd5, 0xaf, 0xa2, 0x80, 0x0b, 0xa6, 0x62, 0xb1, 0x53, 0x15, 0x49, 0x13, 0x54, 0x3b, 0x54, + 0x29, 0x18, 0x18, 0x60, 0xfc, 0x6f, 0x2e, 0x82, 0x2a, 0x70, 0x84, 0x3a, 0x6c, 0xde, 0x5a, 0xf0, + 0xd7, 0x3e, 0x4d, 0x64, 0xff, 0x60, 0x7a, 0x35, 0x37, 0x26, 0xbf, 0x2f, 0xf2, 0x81, 0x93, 0x63, + 0x2c, 0x07, 0x9c, 0x05, 0xe9, 0xec, 0xe2, 0x15, 0x42, 0xcb, 0xd8, 0x1c, 0x88, 0x14, 0x74, 0xba, + 0x89, 0xc6, 0xb3, 0xd1, 0xf5, 0x4c, 0xe5, 0x89, 0x6a, 0x94, 0x31, 0xcf, 0xec, 0x46, 0xa9, 0xb4, + 0x1d, 0x84, 0x3a, 0xcb, 0xde, 0xf3, 0x98, 0x7a, 0xe2, 0xbc, 0x82, 0x9a, 0xd6, 0xcb, 0xc8, 0xbf, + 0x43, 0x34, 0x40, 0x74, 0x9c, 0xdd, 0x13, 0x88, 0x48, 0xa6, 0x1c, 0xdb, 0x52, 0x8c, 0x4a, 0xa0, + 0x84, 0x98, 0xa3, 0x0a, 0xdf, 0x2f, 0x33, 0xc8, 0x0e, 0x11, 0x05, 0x17, 0x76, 0xa5, 0x5b, 0x6f, + 0x5c, 0x92, 0x50, 0x8a, 0xb0, 0x93, 0xfa, 0x82, 0x5e, 0x2e, 0x26, 0xd9, 0x44, 0xe5, 0xd5, 0xb3, + 0x18, 0xba, 0x38, 0x39, 0x29, 0x8a, 0xd9, 0xe5, 0x95, 0x78, 0x0e, 0x57, 0x79, 0x66, 0x79, 0xfe, + 0x09, 0x89, 0x28, 0xdf, 0x17, 0xa8, 0x09, 0x5e, 0xa9, 0x3a, 0x64, 0xd9, 0x04, 0x76, 0xa9, 0x94, + 0x5d, 0x39, 0x49, 0x17, 0x25, 0x12, 0xf1, 0xfe, 0xb2, 0xb4, 0x92, 0xae, 0xbc, 0xf0, 0x4a, 0x9e, + 0x60, 0x8f, 0x1f, 0x11, 0x68, 0xe3, 0x3a, 0x63, 0xa5, 0x43, 0x82, 0xa3, 0x8d, 0x54, 0x8d, 0xe7, + 0x39, 0x1b, 0xae, 0xf2, 0x24, 0x2e, 0x04, 0xfa, 0xdc, 0x6c, 0x24, 0x18, 0xdc, 0xa8, 0xb0, 0xc5, + 0xa4, 0xc6, 0xc6, 0x8a, 0x01, 0x1f, 0x54, 0x77, 0xda, 0xd1, 0x43, 0x0b, 0x43, 0xaa, 0x2c, 0x5f, + 0x1d, 0x17, 0x55, 0xdf, 0xc8, 0xd1, 0x33, 0x13, 0x70, 0x22, 0x74, 0xde, 0x37, 0xd7, 0x35, 0xbb, + 0x07, 0x3b, 0x5c, 0xc8, 0x1b, 0x58, 0xbb, 0xa0, 0x9b, 0xd6, 0x5e, 0x61, 0x6d, 0x2f, 0x7d, 0x15, + 0x31, 0x01, 0x11, 0xef, 0x72, 0x86, 0x13, 0x3f, 0xbb, 0xeb, 0x43, 0xe4, 0x0d, 0x7a, 0x91, 0x6f, + 0xbf, 0xd2, 0x67, 0x24, 0xe5, 0xd3, 0xc8, 0xb2, 0x4e, 0x07, 0xed, 0xcb, 0x38, 0x12, 0xff, 0x72, + 0x24, 0x6d, 0x0b, 0x27, 0x28, 0x0b, 0xc6, 0x51, 0xbd, 0x5f, 0x7c, 0x78, 0x0d, 0x74, 0x05, 0x6e, + 0x0b, 0xf2, 0x6b, 0x1d, 0xa1, 0xc2, 0x1f, 0x4c, 0xcb, 0x42, 0xbe, 0xf1, 0xc6, 0x80, 0x55, 0xb4, + 0xef, 0xa4, 0xdf, 0xec, 0x07, 0xe8, 0xd7, 0x79, 0x9e, 0x6e, 0xe7, 0x45, 0x0c, 0x90, 0x21, 0x2a, + 0x50, 0x26, 0x17, 0xc7, 0xf6, 0xea, 0x84, 0x94, 0xd0, 0x9f, 0x5a, 0xb0, 0xa5, 0xc5, 0x26, 0x3e, + 0x8d, 0x95, 0x6e, 0xef, 0xb0, 0xc8, 0x3a, 0x3d, 0x20, 0x4c, 0x85, 0x82, 0x02, 0x46, 0x75, 0xdc, + 0x87, 0xc8, 0x26, 0xe8, 0x3e, 0x0e, 0x23, 0x6c, 0x67, 0xab, 0xb7, 0xa5, 0x02, 0x62, 0xc1, 0xa4, + 0x34, 0x27, 0x0c, 0xaa, 0x62, 0x25, 0xf9, 0xfe, 0x02, 0xcf, 0xbd, 0x46, 0xca, 0xa5, 0x50, 0x4a, + 0x63, 0x02, 0xdc, 0x0d, 0x84, 0x55, 0xe2, 0x8a, 0x47, 0x7d, 0xde, 0x3a, 0xa1, 0xa0, 0x02, 0x23, + 0x27, 0x4c, 0x49, 0x1e, 0x84, 0xfd, 0xc5, 0x53, 0xc0, 0x15, 0xeb, 0xff, 0x24, 0xdf, 0xac, 0x2a, + 0x15, 0x70, 0x8a, 0x16, 0xd8, 0x02, 0xd8, 0xaa, 0x99, 0xe3, 0x08, 0xc9, 0xf4, 0x03, 0xa9, 0x70, + 0x4d, 0xe5, 0x6e, 0x67, 0x0b, 0x03, 0x1d, 0xe1, 0x37, 0x94, 0xad, 0x79, 0xb4, 0x53, 0xd9, 0x86, + 0xc9, 0x28, 0x15, 0xce, 0xbf, 0xee, 0x7f, 0x52, 0x01, 0xd1, 0x61, 0x02, 0x03, 0x42, 0x17, 0x0c, + 0xe6, 0x81, 0xeb, 0x38, 0x0d, 0x55, 0xdd, 0x7e, 0x45, 0xc4, 0x1f, 0xa8, 0xf1, 0x53, 0x27, 0x47, + 0x47, 0x3c, 0x10, 0x78, 0x89, 0x5d, 0x53, 0xb9, 0x8e, 0x7d, 0x34, 0xab, 0x7a, 0x78, 0x3e, 0xc6, + 0x4a, 0xd3, 0x65, 0x04, 0xf4, 0x20, 0xbb, 0xec, 0xb4, 0xf9, 0x35, 0x14, 0xb6, 0x94, 0xa3, 0x09, + 0xb5, 0xbd, 0x90, 0xba, 0x4b, 0x82, 0x0d, 0xdc, 0x3b, 0x0b, 0xc6, 0xc8, 0x6d, 0x62, 0xcf, 0x1d, + 0x0b, 0x25, 0x35, 0xe6, 0x0e, 0x22, 0x5b, 0xc2, 0x91, 0x88, 0x4d, 0x7c, 0xaa, 0xc0, 0xef, 0x67, + 0x77, 0x8d, 0x3f, 0x89, 0xba, 0xc4, 0xd6, 0x99, 0xd1, 0x4f, 0xfd, 0xcc, 0x7c, 0x18, 0xdc, 0xfe, + 0x19, 0xd3, 0x89, 0x5f, 0xea, 0xa9, 0xac, 0xdb, 0x9b, 0xbe, 0x55, 0x66, 0x74, 0xd6, 0xf4, 0xe0, + 0xbc, 0xf9, 0xab, 0x69, 0x32, 0xf1, 0x07, 0xd3, 0xd0, 0x2a, 0xf8, 0x74, 0xad, 0xba, 0x2c, 0xbb, + 0x6f, 0x9e, 0x81, 0x18, 0x7c, 0x33, 0x32, 0xf9, 0x52, 0x7f, 0xc5, 0xea, 0x06, 0x3b, 0x51, 0x58, + 0xb0, 0xd5, 0x4c, 0x91, 0x1c, 0x1e, 0x6d, 0x67, 0x35, 0x6b, 0xa5, 0x37, 0xb3, 0x41, 0x45, 0xc4, + 0x79, 0x83, 0x35, 0x67, 0x8b, 0x30, 0x8c, 0x52, 0x5e, 0x73, 0x51, 0xf8, 0xa3, 0x55, 0xa7, 0xa6, + 0xe3, 0x3b, 0xdd, 0x28, 0x5f, 0x9c, 0x96, 0xbe, 0xea, 0xb7, 0xc9, 0xfc, 0xac, 0xed, 0xa0, 0xd3, + 0x5d, 0x79, 0x28, 0x55, 0x47, 0x4d, 0xef, 0x43, 0x4b, 0xb9, 0x58, 0x2e, 0x37, 0xd0, 0xc4, 0xc3, + 0xf1, 0x55, 0x61, 0xc5, 0x30, 0xdd, 0x8f, 0x0d, 0x44, 0x63, 0x8a, 0x6c, 0xc1, 0xe0, 0x22, 0xee, + 0x4b, 0xbe, 0x1a, 0xbc, 0xb5, 0xbc, 0x36, 0x9d, 0x9b, 0xcb, 0x91, 0xa7, 0x26, 0x55, 0xf6, 0xdb, + 0x8b, 0x77, 0x4e, 0x69, 0x3c, 0x5a, 0x1e, 0x6a, 0x9f, 0xe2, 0x12, 0x8a, 0x86, 0xab, 0xf8, 0xd4, + 0x53, 0xd9, 0x22, 0xc4, 0xa5, 0x55, 0xb5, 0x89, 0xce, 0xd0, 0x6c, 0xf1, 0xd6, 0x27, 0xdb, 0xdd, + 0x08, 0xb9, 0xdc, 0xad, 0x4a, 0xf6, 0x65, 0x39, 0x0f, 0x34, 0x73, 0x29, 0x91, 0x2b, 0x74, 0xcb, + 0xe4, 0xda, 0xe3, 0x7e, 0x8b, 0x3f, 0xf1, 0x1d, 0x37, 0x5e, 0xf5, 0x95, 0x24, 0xc6, 0xe3, 0x42, + 0x4c, 0xd4, 0x7a, 0xed, 0x35, 0x75, 0x77, 0x8b, 0xaf, 0xbe, 0x63, 0xb6, 0xe0, 0xc6, 0x17, 0x33, + 0x00, 0xa4, 0x31, 0xb8, 0x22, 0x3f, 0xe9, 0xf0, 0x57, 0xdf, 0xdb, 0xb6, 0xf0, 0xb9, 0xe2, 0x6d, + 0x7e, 0x7d, 0x8f, 0x89, 0x87, 0x6a, 0xeb, 0x76, 0xcd, 0x17, 0xac, 0x3d, 0x1e, 0xf5, 0xa4, 0x4b, + 0x87, 0x41, 0xf8, 0x78, 0x4f, 0x3b, 0x39, 0x8c, 0x87, 0x78, 0x40, 0x8b, 0xc5, 0xd3, 0x85, 0xd3, + 0x5b, 0xd8, 0xfa, 0xda, 0x70, 0xac, 0x8c, 0x7b, 0xe3, 0x4c, 0x7c, 0xc7, 0x29, 0x4b, 0xe0, 0x36, + 0x02, 0x57, 0xd3, 0xe4, 0xe5, 0x64, 0xa3, 0x94, 0xeb, 0x5c, 0x5b, 0x4e, 0x65, 0xe4, 0x77, 0xb0, + 0xf4, 0x2d, 0x2d, 0xea, 0x67, 0x33, 0xdb, 0xe3, 0xff, 0x7b, 0xd5, 0x6d, 0x44, 0x30, 0xf5, 0x0f, + 0x6d, 0x38, 0x93, 0xe1, 0x1c, 0x59, 0xb9, 0x75, 0xed, 0x59, 0x00, 0x91, 0xe7, 0xc8, 0x6a, 0xb0, + 0x09, 0xdf, 0xa1, 0xfc, 0x45, 0x41, 0xb2, 0x7b, 0xcb, 0x26, 0xae, 0xba, 0x4b, 0xc0, 0x9e, 0x93, + 0xd1, 0x9b, 0x4d, 0x9e, 0x93, 0x59, 0xa5, 0xdb, 0x73, 0xcd, 0xf8, 0xe2, 0x3c, 0x85, 0xbf, 0x86, + 0x2f, 0x4d, 0x56, 0xea, 0x6c, 0x0e, 0xde, 0x9a, 0x01, 0x39, 0xeb, 0x73, 0x62, 0xc0, 0x38, 0x9c, + 0x99, 0x59, 0x2e, 0xde, 0x20, 0xc5, 0xec, 0x37, 0x77, 0x90, 0xab, 0xab, 0xdc, 0xed, 0x2b, 0x44, + 0x97, 0xba, 0x15, 0x69, 0xcb, 0xb2, 0x8e, 0xd2, 0xad, 0xed, 0xed, 0xfd, 0x55, 0x81, 0xdb, 0x70, + 0x35, 0x12, 0x18, 0x6e, 0xf7, 0x33, 0xbc, 0x4b, 0x53, 0x93, 0x35, 0x02, 0x84, 0x84, 0x48, 0x8c, + 0x29, 0xfe, 0x9e, 0xe6, 0x5c, 0xf1, 0x83, 0x9e, 0xea, 0x61, 0x02, 0xcf, 0x01, 0x51, 0x9b, 0x97, + 0xec, 0xab, 0x45, 0xc6, 0x69, 0x9c, 0xed, 0x78, 0x1e, 0xc8, 0x4c, 0xf2, 0x36, 0x22, 0xb8, 0x74, + 0xa5, 0xaf, 0x55, 0x7d, 0x1c, 0x09, 0x2e, 0x0b, 0x44, 0x9a, 0xb1, 0xe0, 0xbc, 0x9a, 0x6a, 0x44, + 0xf4, 0x92, 0xba, 0xe6, 0x73, 0x53, 0xf4, 0xfe, 0xc9, 0x87, 0xed, 0xe9, 0x1c, 0xd5, 0xf5, 0x03, + 0x99, 0xc5, 0x44, 0xf1, 0xfd, 0x5e, 0xe9, 0xac, 0x15, 0xc4, 0x53, 0xae, 0x6e, 0x6d, 0xcc, 0x11, + 0x78, 0xcf, 0x73, 0x96, 0xa4, 0x11, 0x07, 0x31, 0xc8, 0x79, 0xd5, 0x16, 0xe7, 0x3d, 0xb5, 0xbe, + 0x98, 0xb7, 0xb9, 0xbf, 0x24, 0xf2, 0x0a, 0xbb, 0x72, 0xa5, 0xab, 0x96, 0xa6, 0xaf, 0x24, 0x31, + 0xb4, 0x13, 0xfd, 0xa7, 0xf4, 0xcc, 0x9d, 0x0f, 0x05, 0xba, 0x9f, 0x20, 0xe7, 0x63, 0x65, 0xc4, + 0x56, 0x39, 0xbb, 0x20, 0x7b, 0x3d, 0xb4, 0x1f, 0xa7, 0x7f, 0x7b, 0x19, 0xd4, 0x56, 0xd8, 0x8a, + 0xf9, 0x98, 0xd6, 0x1b, 0xb8, 0x0b, 0x3f, 0xea, 0x2d, 0xf3, 0xc5, 0xe8, 0xda, 0xd3, 0x68, 0x0a, + 0x25, 0x11, 0xcd, 0x14, 0xca, 0xdd, 0x07, 0xc1, 0x17, 0x00, 0x21, 0x37, 0x79, 0xfd, 0xd7, 0x5f, + 0xef, 0x5d, 0xc1, 0x8c, 0x3f, 0x98, 0xde, 0xd4, 0x8b, 0xb7, 0x16, 0x68, 0x7c, 0xef, 0x09, 0xda, + 0xb5, 0xfb, 0x35, 0xa3, 0xeb, 0x54, 0x5b, 0x15, 0x64, 0xca, 0xbe, 0x55, 0x3b, 0x14, 0xb1, 0x00, + 0xa6, 0x88, 0x68, 0x3c, 0x61, 0xcb, 0xfc, 0xb3, 0x98, 0x82, 0x51, 0x89, 0x58, 0x48, 0xd2, 0x69, + 0x6b, 0xa4, 0x97, 0x6c, 0x3d, 0x00, 0x7e, 0x25, 0xf5, 0xe1, 0x7c, 0x44, 0x16, 0x89, 0xd0, 0xdf, + 0xc3, 0x96, 0xd0, 0x11, 0x47, 0xf3, 0xa2, 0x34, 0x42, 0x01, 0xc1, 0x3b, 0x22, 0x21, 0x62, 0xb7, + 0xc7, 0x59, 0x96, 0xfe, 0x0a, 0x59, 0x7d, 0x04, 0x37, 0x88, 0xe1, 0xbd, 0xbd, 0xd6, 0xc1, 0x75, + 0x8e, 0xab, 0x0b, 0xaa, 0xca, 0x55, 0x0b, 0xce, 0xea, 0xd8, 0x95, 0x7a, 0x8f, 0xee, 0x95, 0x0c, + 0x78, 0x75, 0x7d, 0xed, 0x23, 0x3f, 0xf8, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, + 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, + 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0xbf, 0x27, 0xff, 0x79, 0x1e, 0x5c, + 0x21, 0x59, 0x8c, 0x81, 0x6e, 0xe3, 0x72, 0x45, 0xf5, 0x36, 0xa0, 0x96, 0x2e, 0xcd, 0x47, 0xbc, + 0x4b, 0x20, 0x89, 0x82, 0xc0, 0xf9, 0x53, 0xa2, 0x43, 0x38, 0xbc, 0x76, 0x16, 0x59, 0x09, 0xee, + 0x23, 0xf4, 0x24, 0xe9, 0xe7, 0x59, 0x4d, 0x5b, 0xc4, 0xfc, 0x63, 0xc6, 0x8f, 0xd3, 0x8a, 0x7d, + 0xf8, 0xef, 0x26, 0xf6, 0x00, 0x53, 0xe3, 0x73, 0xfa, 0xb1, 0xaf, 0xa8, 0xfc, 0x27, 0xed, 0x7b, + 0xb1, 0xba, 0x5e, 0xef, 0x22, 0x65, 0xee, 0x8f, 0xae, 0x34, 0x7b, 0x6f, 0x6f, 0x20, 0xc0, 0xf5, + 0x4e, 0x6a, 0xc2, 0xf3, 0x76, 0x21, 0x15, 0x47, 0x6c, 0x80, 0x97, 0xc3, 0x86, 0xed, 0x5e, 0x30, + 0xa3, 0x26, 0x11, 0x8c, 0xdb, 0x34, 0x3f, 0x75, 0x56, 0x0e, 0x0d, 0x23, 0x72, 0x35, 0x05, 0xe0, + 0x75, 0xeb, 0xc8, 0x94, 0x1e, 0x03, 0xa7, 0xcd, 0x93, 0xb4, 0x59, 0xd5, 0x5a, 0xc4, 0x75, 0xd7, + 0x96, 0xb3, 0xce, 0x62, 0x46, 0x90, 0xe8, 0xa8, 0x1f, 0xe3, 0x43, 0xb6, 0xde, 0x3e, 0xd4, 0x2c, + 0x0d, 0xfd, 0x9d, 0x93, 0x17, 0x65, 0x58, 0x11, 0xe4, 0xd4, 0x1b, 0x76, 0x61, 0x01, 0x55, 0x4b, + 0x3a, 0x84, 0xf8, 0x02, 0x68, 0xe5, 0xad, 0xc6, 0xae, 0xb7, 0xab, 0xba, 0xf0, 0xa1, 0x0c, 0x54, + 0x66, 0x4a, 0x33, 0x24, 0xa2, 0x9b, 0xde, 0x8a, 0xc1, 0x74, 0x7d, 0xd2, 0xe4, 0xfe, 0xaf, 0x04, + 0x19, 0x73, 0xaf, 0xa5, 0xbc, 0x00, 0x43, 0x59, 0x30, 0xe9, 0x1f, 0x0d, 0x19, 0x0f, 0xc7, 0xae, + 0x10, 0x0b, 0x7b, 0x5c, 0x16, 0xf3, 0x1e, 0x6e, 0x8f, 0x68, 0x22, 0x50, 0xa3, 0x5b, 0xbc, 0x3f, + 0xf1, 0xb5, 0x14, 0x85, 0x27, 0xac, 0x09, 0x55, 0xc5, 0x16, 0x92, 0xd5, 0x93, 0x95, 0xb1, 0x38, + 0xc7, 0x5b, 0xad, 0x66, 0xcb, 0x4d, 0x15, 0x3a, 0x5f, 0xd4, 0x20, 0x68, 0xb8, 0x75, 0x28, 0x0b, + 0x59, 0xa2, 0xb9, 0x26, 0xd1, 0xa9, 0xf3, 0xd4, 0x0a, 0xd6, 0x20, 0xd6, 0x75, 0xbd, 0x86, 0x76, + 0x83, 0x89, 0xe2, 0x73, 0x2c, 0x08, 0x57, 0xb9, 0x03, 0xfb, 0x2f, 0x19, 0x42, 0x92, 0x0e, 0xca, + 0xfd, 0x7d, 0xde, 0x0a, 0xef, 0x85, 0xc4, 0x12, 0xf3, 0x62, 0x20, 0xa2, 0xa4, 0xb2, 0xbe, 0x79, + 0x3a, 0x8b, 0x2a, 0x99, 0x1b, 0x26, 0x38, 0xb2, 0x4a, 0x1f, 0xd1, 0x8b, 0x45, 0xb0, 0x46, 0x26, + 0x81, 0x3b, 0x5c, 0x0b, 0x34, 0x10, 0xa2, 0x80, 0x8c, 0xf4, 0xd5, 0x0d, 0x80, 0x10, 0x56, 0xd7, + 0xdf, 0x2f, 0x5f, 0x54, 0x7e, 0x73, 0xbb, 0x0a, 0x4a, 0x4e, 0xd5, 0x45, 0x58, 0x79, 0x1e, 0x57, + 0xcb, 0x2a, 0x0f, 0x09, 0x09, 0x33, 0x40, 0xfc, 0x8d, 0xea, 0x53, 0xd5, 0x8e, 0x09, 0x02, 0xdd, + 0xc4, 0x52, 0x98, 0x53, 0xdb, 0x68, 0x99, 0xd9, 0x92, 0x8d, 0x9e, 0x54, 0x76, 0xb4, 0x41, 0xa8, + 0x8a, 0xb5, 0x64, 0xf5, 0x61, 0xed, 0x5d, 0xe5, 0xa4, 0xe4, 0x20, 0x0a, 0x34, 0xf8, 0xac, 0x12, + 0x16, 0x97, 0xe0, 0xd6, 0x27, 0xa9, 0x6d, 0x8b, 0x52, 0x14, 0xaf, 0xdd, 0xb8, 0x70, 0x1d, 0xdb, + 0xdd, 0xcc, 0xe6, 0x1c, 0x4f, 0x11, 0xaa, 0xee, 0x9b, 0xbb, 0x92, 0x55, 0xcb, 0x00, 0x62, 0xe5, + 0x8b, 0xeb, 0x10, 0xe5, 0xb0, 0xfd, 0x67, 0xf8, 0x6a, 0xc1, 0xe3, 0x51, 0xb2, 0xcc, 0x8e, 0x12, + 0x81, 0xd0, 0x9c, 0x6e, 0x04, 0xa1, 0xe7, 0x8d, 0x4f, 0x39, 0x8e, 0x33, 0x02, 0x81, 0x7b, 0x45, + 0x63, 0x9c, 0xc8, 0xb9, 0x5f, 0x45, 0xcc, 0xac, 0xdb, 0x98, 0xee, 0x85, 0x74, 0x1b, 0xc8, 0x05, + 0xa7, 0x30, 0xdc, 0x9f, 0xe1, 0x14, 0xc2, 0xee, 0xa2, 0xbc, 0xd4, 0x19, 0x15, 0xf5, 0xa5, 0x66, + 0x3a, 0xa9, 0x2a, 0x4d, 0x13, 0xf6, 0x82, 0xa6, 0xb6, 0x81, 0x35, 0xa3, 0x8e, 0x44, 0x46, 0xaf, + 0xdd, 0xec, 0xa1, 0x02, 0xc1, 0xd6, 0xa7, 0x82, 0xa1, 0xdc, 0x8c, 0x50, 0xe5, 0x65, 0x85, 0xc6, + 0xc6, 0x73, 0x9e, 0x8d, 0xab, 0x1c, 0x79, 0xf4, 0x8d, 0xce, 0x97, 0x04, 0x08, 0xbb, 0x5c, 0x2d, + 0x1e, 0xd6, 0xd5, 0xeb, 0xe2, 0xf4, 0x3c, 0xcf, 0x77, 0x3b, 0x4c, 0x72, 0x54, 0xf7, 0x9d, 0x58, + 0xb1, 0x16, 0x20, 0xc2, 0x6c, 0xe1, 0x03, 0x32, 0x90, 0xb0, 0xc3, 0xbf, 0xec, 0xf1, 0x97, 0x88, + 0xf0, 0xdf, 0x9a, 0x26, 0x49, 0x26, 0x9a, 0x7c, 0xdc, 0x6b, 0x6b, 0xb8, 0x0d, 0xd7, 0x74, 0x61, + 0xe0, 0x1a, 0x5d, 0x87, 0xd9, 0xb6, 0x84, 0xa4, 0x39, 0x19, 0xf7, 0x16, 0x34, 0xd7, 0x71, 0xa9, + 0x45, 0x73, 0x1d, 0x4b, 0xcc, 0xb5, 0x4c, 0xa2, 0xef, 0xab, 0x11, 0xc9, 0x69, 0xc2, 0x1c, 0xb1, + 0x55, 0x61, 0xc5, 0x33, 0x51, 0x1a, 0xe4, 0x92, 0xaa, 0x8d, 0xd8, 0x2b, 0x33, 0xf6, 0x86, 0x66, + 0x04, 0xd0, 0x01, 0xbe, 0x60, 0x69, 0x8b, 0x0e, 0x71, 0x94, 0x23, 0xb9, 0x17, 0x8d, 0xd5, 0xba, + 0xc1, 0x64, 0xbc, 0x86, 0xc4, 0xf3, 0x0b, 0x27, 0xc3, 0xe4, 0x05, 0x35, 0x69, 0xd8, 0xca, 0x9b, + 0x0c, 0xfa, 0x78, 0x9e, 0x6b, 0x3f, 0xef, 0x86, 0xd8, 0x6d, 0x82, 0x3e, 0x11, 0x0d, 0x1e, 0x9e, + 0x1b, 0x92, 0xd8, 0x66, 0xe2, 0x53, 0x5b, 0x60, 0x6a, 0xd2, 0xda, 0xbb, 0xc6, 0xab, 0x20, 0x7d, + 0x17, 0x0e, 0x0e, 0xe6, 0xfe, 0xe9, 0xa0, 0xff, 0x6f, 0x46, 0x22, 0x96, 0x4b, 0xaf, 0xb9, 0x22, + 0x12, 0x1c, 0x02, 0xe3, 0x4c, 0x40, 0x06, 0xaf, 0xac, 0x26, 0xab, 0x25, 0x52, 0x42, 0x1f, 0x3e, + 0x75, 0x9e, 0xf9, 0x6a, 0x6f, 0xa5, 0x60, 0x28, 0x49, 0x94, 0x96, 0xa5, 0x24, 0x0c, 0x8b, 0x75, + 0x92, 0x24, 0x86, 0xaf, 0x40, 0xd3, 0xee, 0x0c, 0x43, 0xed, 0xb4, 0x5e, 0x9a, 0xed, 0x27, 0x08, + 0x6f, 0x94, 0x7f, 0xf2, 0x5b, 0xc3, 0x3b, 0x8d, 0x60, 0x8a, 0x10, 0xe8, 0x20, 0xc9, 0x6a, 0x79, + 0xe3, 0x6d, 0x81, 0x38, 0x5a, 0x5f, 0x84, 0xe8, 0x55, 0xdc, 0x03, 0xf1, 0x8e, 0xe4, 0x28, 0xc4, + 0x22, 0xd3, 0xa6, 0x05, 0xd2, 0xa2, 0x5e, 0xcd, 0xeb, 0xc1, 0x08, 0x52, 0x27, 0x05, 0xbe, 0xdb, + 0x0e, 0x6b, 0xb2, 0x05, 0xcf, 0xef, 0xc2, 0xbb, 0x92, 0xcd, 0xd3, 0xbb, 0x90, 0x87, 0xaf, 0x69, + 0x29, 0x18, 0x98, 0x89, 0xd8, 0xba, 0xb0, 0x2c, 0x99, 0x5d, 0x37, 0xa3, 0x67, 0x7e, 0xb2, 0x23, + 0x65, 0x67, 0x42, 0x4b, 0x53, 0xae, 0xd8, 0x15, 0x3c, 0xe6, 0x98, 0x8d, 0xf0, 0xaf, 0x67, 0x9b, + 0x65, 0xff, 0xd0, 0xa7, 0x57, 0x4d, 0x47, 0x7a, 0x17, 0x31, 0xb7, 0x7e, 0x80, 0xa8, 0xec, 0x65, + 0xd5, 0xf3, 0x84, 0x0d, 0x88, 0xd0, 0x84, 0xd9, 0xf6, 0xd4, 0x9c, 0xd6, 0xca, 0xee, 0xb3, 0x71, + 0xc1, 0x19, 0xac, 0x0f, 0xc7, 0x2e, 0x58, 0xfa, 0x92, 0xd5, 0xac, 0xc1, 0xd9, 0xe2, 0x91, 0x64, + 0x8b, 0x52, 0x3f, 0x5a, 0x8f, 0xdf, 0x87, 0xec, 0x40, 0x78, 0x9a, 0xad, 0xee, 0x8a, 0x32, 0x61, + 0x87, 0x7e, 0xbc, 0x69, 0x3f, 0x12, 0x4f, 0x97, 0x2f, 0x0f, 0x9f, 0xfc, 0x99, 0xac, 0xb1, 0x5c, + 0x6f, 0x68, 0x38, 0xba, 0x5d, 0x0e, 0xe8, 0x8c, 0xdf, 0x4b, 0xcb, 0x7c, 0x5c, 0x33, 0xe1, 0x1b, + 0xcb, 0x6b, 0x29, 0x29, 0xd0, 0x3a, 0x19, 0x03, 0xb6, 0x37, 0x6b, 0xdc, 0x64, 0x3e, 0x4c, 0x8c, + 0x57, 0x1c, 0x41, 0xd2, 0x14, 0xb6, 0x79, 0xad, 0x31, 0x48, 0xa4, 0x5b, 0x5c, 0x3c, 0xdd, 0x76, + 0x62, 0x31, 0x4e, 0x52, 0x7e, 0x5c, 0xb3, 0x70, 0x86, 0xfb, 0x5b, 0xa1, 0x70, 0x67, 0x05, 0x2b, + 0xa4, 0x0e, 0x8f, 0x5f, 0x34, 0x6d, 0x4d, 0x3d, 0x1b, 0xb2, 0x1f, 0xb7, 0xd4, 0xbb, 0x86, 0x83, + 0x3b, 0x42, 0xfe, 0xcf, 0xd5, 0x94, 0x8b, 0x3b, 0x8e, 0x3c, 0xac, 0x47, 0x63, 0x6b, 0x3e, 0x26, + 0xcb, 0xab, 0x17, 0x99, 0x3a, 0xf1, 0xd6, 0xe2, 0xd4, 0x1a, 0x27, 0xfc, 0x72, 0xcd, 0x3a, 0xf4, + 0x69, 0x62, 0x3b, 0x79, 0x49, 0xf7, 0x1f, 0x72, 0x8f, 0x74, 0xa8, 0x9c, 0x54, 0x5c, 0xa1, 0xa7, + 0x63, 0x68, 0x73, 0xc2, 0x97, 0xe8, 0x56, 0x23, 0xd6, 0xed, 0x96, 0x44, 0x9a, 0x34, 0x9d, 0xb5, + 0x3a, 0xd1, 0xc8, 0xce, 0x21, 0x91, 0x9d, 0xae, 0xcf, 0x87, 0x13, 0x0f, 0xb6, 0xfd, 0xe3, 0x51, + 0xd4, 0xf8, 0x4c, 0x28, 0xcd, 0x1b, 0x29, 0x05, 0x5b, 0xa6, 0x1a, 0x58, 0xf3, 0x63, 0x48, 0x5b, + 0x20, 0x8c, 0xa7, 0x37, 0x53, 0x5e, 0x18, 0xa2, 0xa7, 0x55, 0x25, 0x81, 0xbd, 0x6f, 0x2e, 0x80, + 0xfb, 0xb1, 0x5d, 0x79, 0x2b, 0xb1, 0xb9, 0x9b, 0x09, 0x6e, 0x66, 0xe4, 0x47, 0xc6, 0xa6, 0xb5, + 0x2a, 0xee, 0x8a, 0x7e, 0xdd, 0x67, 0x57, 0xf8, 0x83, 0x69, 0x50, 0x32, 0xb0, 0x93, 0xf6, 0x05, + 0xcf, 0x06, 0xc1, 0x8d, 0xfe, 0x73, 0x43, 0x7c, 0x02, 0x01, 0xe8, 0x06, 0xfb, 0x19, 0xad, 0x24, + 0x06, 0xa9, 0x42, 0x14, 0xcd, 0x6a, 0x9c, 0x3b, 0x77, 0x28, 0x0d, 0xbc, 0x79, 0x0b, 0xe6, 0xdd, + 0x16, 0xba, 0x0e, 0x75, 0x75, 0xbd, 0x35, 0x80, 0x8d, 0x87, 0x5f, 0x93, 0xe1, 0xfe, 0x7e, 0x23, + 0xbf, 0x37, 0x39, 0xce, 0x48, 0xd2, 0xc6, 0x4a, 0x01, 0x4c, 0x3b, 0x4f, 0xb2, 0x91, 0x8b, 0x28, + 0x52, 0xf8, 0x7c, 0x71, 0x70, 0xd6, 0x02, 0x0b, 0x70, 0xe7, 0x75, 0x19, 0x14, 0x30, 0x9e, 0x07, + 0x1c, 0xef, 0x46, 0x5e, 0x82, 0xfb, 0x7b, 0x39, 0x31, 0x1b, 0xab, 0xcb, 0xf0, 0x4a, 0x97, 0x21, + 0xe7, 0x7f, 0x8b, 0x7f, 0xe7, 0x94, 0x49, 0xe3, 0xeb, 0x75, 0x75, 0x2c, 0xc9, 0xe4, 0xeb, 0x8f, + 0xd3, 0x7b, 0xcd, 0x62, 0x54, 0xfe, 0xb6, 0xbc, 0x6b, 0xbf, 0xbd, 0xbd, 0x4c, 0xd5, 0x1c, 0x04, + 0x01, 0x7e, 0xdf, 0xf8, 0xd1, 0x7a, 0x78, 0x3c, 0x1d, 0x0e, 0x16, 0x9c, 0xad, 0xe0, 0x28, 0xe7, + 0x2c, 0x7f, 0x35, 0x2d, 0xdc, 0x61, 0xa1, 0x55, 0xa8, 0x7d, 0xba, 0xc0, 0xe4, 0x9a, 0x15, 0x7f, + 0xb5, 0x33, 0xf6, 0x1f, 0x87, 0x13, 0x35, 0x70, 0x40, 0x50, 0x2d, 0x26, 0x35, 0x31, 0x2b, 0x6f, + 0x1f, 0xfe, 0x0c, 0x3f, 0x98, 0x8e, 0x12, 0x9f, 0x0a, 0x6a, 0x64, 0xb6, 0x58, 0x68, 0x1d, 0xb9, + 0x90, 0xda, 0xb0, 0x95, 0x90, 0x4f, 0xa2, 0x81, 0xd7, 0xec, 0xf8, 0xfd, 0x65, 0x99, 0xc8, 0x89, + 0x60, 0xc6, 0x6e, 0x9b, 0xec, 0x58, 0xad, 0x2d, 0x78, 0xab, 0xd1, 0x7b, 0x04, 0xb0, 0x4e, 0xbe, + 0x41, 0x76, 0x67, 0x1b, 0x63, 0x78, 0xa6, 0xa3, 0x75, 0x68, 0x16, 0x74, 0x9c, 0x07, 0xbc, 0x65, + 0x37, 0x47, 0x7d, 0x35, 0xaa, 0xa6, 0x80, 0xab, 0xb2, 0x9f, 0xf9, 0x66, 0x34, 0x6d, 0x37, 0x8e, + 0x32, 0x04, 0x24, 0x96, 0xc4, 0x6e, 0xd3, 0x0d, 0x24, 0x93, 0x80, 0x5a, 0xf0, 0x41, 0xf7, 0x8b, + 0x28, 0xb9, 0xbf, 0xde, 0x8c, 0xfa, 0x7e, 0xb3, 0x77, 0x34, 0xf1, 0x07, 0xd3, 0x72, 0x0b, 0xe1, + 0x42, 0xb1, 0x28, 0x31, 0x3c, 0xeb, 0x2c, 0xa5, 0x07, 0x75, 0x14, 0x74, 0x92, 0xfe, 0x98, 0x8c, + 0x7b, 0x2d, 0x0d, 0x59, 0x2e, 0x77, 0x6a, 0x50, 0xc1, 0x43, 0x68, 0xbb, 0xfa, 0x7b, 0xd8, 0xd7, + 0xcc, 0x78, 0x36, 0x43, 0x5c, 0xdc, 0x15, 0xee, 0x69, 0xe6, 0xfb, 0x0f, 0x08, 0x6b, 0xce, 0xf9, + 0x44, 0xf0, 0x43, 0x82, 0xb3, 0xe7, 0xd5, 0x1a, 0xc7, 0xc3, 0xec, 0x2d, 0x97, 0x81, 0x44, 0x9e, + 0x46, 0x74, 0xee, 0x7a, 0xe2, 0x5c, 0x60, 0x28, 0xa5, 0x5d, 0x95, 0x9a, 0x9a, 0xd9, 0xef, 0xce, + 0xb8, 0x12, 0xdd, 0x49, 0xf9, 0x9f, 0x41, 0xd8, 0xf7, 0xef, 0x39, 0x51, 0xdc, 0x54, 0x5f, 0xfc, + 0x02, 0x47, 0xa0, 0x7a, 0xdd, 0x0e, 0xb9, 0x5a, 0xf7, 0xd1, 0xbb, 0x16, 0x42, 0x6e, 0x07, 0xbd, + 0xe8, 0x8b, 0x79, 0x63, 0x5f, 0x31, 0x39, 0x70, 0xba, 0x8e, 0x65, 0x65, 0xef, 0x3e, 0x2b, 0x91, + 0x72, 0x6a, 0xd3, 0xfc, 0xf1, 0x64, 0x7c, 0x49, 0x93, 0x39, 0x90, 0x82, 0x5a, 0x74, 0x7e, 0xdc, + 0x97, 0x11, 0x30, 0x45, 0xc1, 0x75, 0xbe, 0x78, 0x3e, 0xa9, 0x78, 0x81, 0xa7, 0xa1, 0xea, 0x9b, + 0x3b, 0xd1, 0xd9, 0xd5, 0x78, 0xe7, 0xc3, 0x6a, 0xb1, 0xd7, 0xd8, 0x01, 0xcc, 0xe6, 0xd0, 0x68, + 0xd7, 0x0e, 0x43, 0xc7, 0x3c, 0xae, 0x2c, 0x98, 0x58, 0x2d, 0x7a, 0x68, 0x84, 0x24, 0xd3, 0x80, + 0x17, 0xc1, 0x43, 0x43, 0x97, 0xc6, 0x16, 0x94, 0x9b, 0xb1, 0xa8, 0x64, 0x9b, 0x98, 0xd7, 0x55, + 0x60, 0x86, 0xa9, 0x61, 0x51, 0x21, 0xcc, 0x84, 0xf0, 0x68, 0x36, 0x2f, 0x3e, 0xd0, 0x8c, 0xd0, + 0xa8, 0x6c, 0x6b, 0xef, 0x59, 0x7f, 0x00, 0x33, 0x29, 0x3f, 0x0d, 0x50, 0xbd, 0xb9, 0xcb, 0x39, + 0x76, 0xa5, 0x81, 0x6b, 0x81, 0x35, 0x98, 0x2a, 0x13, 0xbe, 0xe0, 0x4a, 0xe1, 0x76, 0xbf, 0xd5, + 0xd2, 0x69, 0xb6, 0xb3, 0xb2, 0x43, 0xcd, 0x90, 0x98, 0x5d, 0xeb, 0x7a, 0x9a, 0x9a, 0xcb, 0x4d, + 0xbf, 0xac, 0x39, 0xf1, 0x37, 0x92, 0x3a, 0xcc, 0x49, 0xfc, 0x5f, 0xdc, 0xd1, 0xd8, 0xa1, 0xfe, + 0xa1, 0x0d, 0x3f, 0xed, 0xb9, 0xe5, 0xfb, 0xa4, 0x38, 0xef, 0xb7, 0xb0, 0xca, 0xd1, 0x1a, 0xd2, + 0xad, 0xba, 0x7c, 0x11, 0x66, 0xbe, 0x3c, 0x60, 0xa2, 0x1a, 0xaf, 0x5d, 0xf2, 0x1c, 0x3d, 0x2d, + 0xaf, 0x53, 0x52, 0xb9, 0xd1, 0xdb, 0x6d, 0xc3, 0x38, 0xc6, 0xe3, 0x29, 0xbd, 0x23, 0xc8, 0x5a, + 0xd2, 0xaa, 0xa6, 0xb3, 0x22, 0xd9, 0x69, 0x6a, 0x2e, 0x64, 0x0c, 0xd2, 0xf3, 0xa7, 0x19, 0xf7, + 0x00, 0x29, 0x0d, 0xa7, 0xfb, 0x9b, 0x0d, 0xfd, 0xdd, 0x34, 0xaf, 0xd7, 0x3f, 0x6e, 0x35, 0x63, + 0xdf, 0xae, 0x32, 0xf5, 0x7b, 0xd7, 0x91, 0x84, 0xf5, 0xec, 0xbd, 0x0e, 0x72, 0xda, 0x16, 0x4b, + 0x6d, 0xf6, 0xb5, 0xba, 0x3e, 0x7b, 0xd9, 0xe6, 0x6c, 0x8c, 0x12, 0x0b, 0x97, 0xba, 0xf3, 0x2c, + 0x7f, 0xe0, 0x1b, 0x2e, 0xec, 0xaa, 0x5d, 0xc3, 0x69, 0xf8, 0xe9, 0x25, 0x51, 0x15, 0xa5, 0xce, + 0xd3, 0x17, 0xed, 0xc1, 0xdd, 0xa4, 0xb6, 0xd0, 0x0e, 0xdc, 0x9b, 0xa5, 0x0f, 0x58, 0x6b, 0x1c, + 0xda, 0xb5, 0xa5, 0xe7, 0xec, 0xfa, 0xea, 0xbe, 0x56, 0xde, 0x70, 0x76, 0x5f, 0xeb, 0xa2, 0x66, + 0x86, 0xc0, 0x5d, 0x4d, 0xef, 0x58, 0xa4, 0x2d, 0xfd, 0x08, 0xa9, 0xc1, 0x86, 0x2b, 0x16, 0xc3, + 0x5d, 0xe8, 0x7f, 0x8e, 0x31, 0x42, 0x52, 0xa4, 0x7e, 0xac, 0xa0, 0x99, 0x76, 0x55, 0x5d, 0xb4, + 0xd4, 0x1c, 0xc8, 0x58, 0xf7, 0xc6, 0xb3, 0x96, 0x1c, 0xe0, 0xdc, 0x8d, 0x48, 0xc3, 0x44, 0xb7, + 0xbe, 0x20, 0x6f, 0xb4, 0x64, 0x5b, 0x9f, 0x85, 0xcd, 0x4e, 0x10, 0x72, 0xbe, 0xda, 0x9e, 0x43, + 0x39, 0x13, 0x01, 0x3e, 0xe0, 0xb6, 0x7d, 0xd2, 0x70, 0x78, 0xe2, 0x57, 0x2e, 0x5e, 0x6a, 0xbb, + 0x99, 0xe7, 0xb4, 0x8c, 0xa4, 0x3d, 0x0b, 0x84, 0x44, 0x02, 0x50, 0xb5, 0x10, 0xee, 0x38, 0x1c, + 0x77, 0x63, 0x89, 0x75, 0x4b, 0x90, 0x9d, 0xb3, 0xaf, 0xb5, 0x8f, 0xed, 0x86, 0x33, 0xa4, 0xa9, + 0x4f, 0x9e, 0xa6, 0x73, 0x93, 0xb1, 0xde, 0x53, 0xe5, 0xed, 0xe2, 0xd4, 0xeb, 0xc5, 0xbb, 0x32, + 0xfc, 0x6b, 0x2e, 0x3f, 0xe3, 0x0f, 0xa6, 0xb7, 0x92, 0x35, 0xa1, 0x27, 0x14, 0xdf, 0xf6, 0xff, + 0x45, 0xea, 0xb4, 0x6e, 0xf2, 0x95, 0x8f, 0xb9, 0x27, 0xbd, 0x1c, 0xe9, 0xbb, 0x58, 0x8d, 0x0f, + 0x1b, 0x38, 0x98, 0xdb, 0x8e, 0xcc, 0x99, 0x48, 0x0c, 0x22, 0x6f, 0x87, 0x20, 0x5c, 0xc3, 0xee, + 0x0f, 0xc4, 0xc1, 0x90, 0xb9, 0xd9, 0x3f, 0x46, 0xa0, 0xf7, 0x77, 0x45, 0x4b, 0x61, 0x5d, 0x5d, + 0x99, 0xb0, 0xac, 0x8b, 0x96, 0xf9, 0x96, 0xb3, 0x17, 0x4c, 0x19, 0xc2, 0xbf, 0xea, 0xf2, 0x7a, + 0xfb, 0xbe, 0x5a, 0x7d, 0x72, 0x37, 0xc9, 0x80, 0x29, 0x18, 0xce, 0xab, 0x1a, 0xe7, 0x84, 0x99, + 0x35, 0x81, 0x84, 0xcd, 0x66, 0xed, 0xf4, 0x1c, 0x25, 0xd5, 0x47, 0x83, 0x65, 0x2a, 0x47, 0x9e, + 0x26, 0x8a, 0xb0, 0x08, 0x41, 0x98, 0xeb, 0xc8, 0xbe, 0xa2, 0xcd, 0xb5, 0xc3, 0xe3, 0x39, 0x77, + 0x44, 0x3a, 0xcb, 0x2b, 0xb4, 0xa0, 0xe7, 0x11, 0xfb, 0x68, 0x46, 0x82, 0x39, 0xaf, 0x2d, 0x62, + 0x48, 0x50, 0xc2, 0xa5, 0xe4, 0xb5, 0xff, 0x80, 0x20, 0xd7, 0x9d, 0x30, 0xa3, 0x4f, 0x1a, 0xe8, + 0xda, 0xa2, 0x69, 0x67, 0x0a, 0x99, 0x4b, 0xc3, 0xa3, 0xc5, 0x3d, 0xa3, 0xab, 0xf5, 0xfc, 0xfc, + 0xe8, 0xec, 0x72, 0x9a, 0x36, 0xa2, 0xbb, 0xde, 0x7c, 0x3c, 0x9d, 0xb3, 0x92, 0x72, 0x75, 0x33, + 0xae, 0x53, 0x3f, 0xee, 0xb4, 0x52, 0x50, 0x50, 0x33, 0x5b, 0x1a, 0xcb, 0x2e, 0x56, 0xf4, 0xb2, + 0x74, 0x03, 0xfb, 0xb9, 0xbb, 0x41, 0xcc, 0x96, 0x9c, 0x27, 0x41, 0xb1, 0x20, 0xff, 0x28, 0x9a, + 0xb9, 0x3c, 0x89, 0x06, 0xb9, 0x99, 0xa3, 0x94, 0x19, 0xd1, 0xc4, 0xdc, 0xaf, 0x24, 0x6b, 0x9a, + 0x4a, 0xf5, 0xd1, 0xa7, 0xd7, 0xef, 0xba, 0x52, 0x41, 0x1f, 0x17, 0x8b, 0x78, 0x47, 0x58, 0x96, + 0xc4, 0xcc, 0xc9, 0x16, 0x59, 0x5e, 0x27, 0x22, 0x0b, 0xb2, 0x68, 0x1c, 0xdb, 0x9d, 0x68, 0x9b, + 0x4c, 0x46, 0xb9, 0x53, 0x5f, 0xdd, 0xcd, 0x2b, 0x18, 0x0d, 0x09, 0x29, 0x1a, 0xbe, 0xe8, 0xc6, + 0x2a, 0xf2, 0xd7, 0xfa, 0x14, 0xac, 0x3f, 0x98, 0x56, 0xb3, 0x47, 0xdd, 0x4f, 0xa9, 0x5d, 0xd1, + 0x5a, 0x2c, 0x19, 0xdb, 0x85, 0xe0, 0x84, 0x1e, 0xbc, 0x6f, 0x86, 0xc7, 0xf9, 0x5b, 0x9c, 0xa9, + 0x12, 0x8e, 0xa5, 0x29, 0x3d, 0xcf, 0xb4, 0x37, 0xc0, 0x0d, 0xf0, 0x6c, 0xf2, 0x54, 0x00, 0x8c, + 0xf9, 0xe1, 0xfe, 0x76, 0x87, 0x1e, 0x76, 0xca, 0x98, 0x0c, 0x0e, 0xcf, 0x6e, 0xb5, 0xe7, 0x79, + 0x76, 0x54, 0xcd, 0x29, 0xed, 0xd4, 0x27, 0x97, 0xb8, 0x1f, 0xcf, 0x26, 0xa3, 0xb7, 0x77, 0x09, + 0x8b, 0xf7, 0xc7, 0x49, 0x77, 0x09, 0x34, 0xc1, 0x4b, 0xf1, 0x3c, 0x62, 0x3d, 0xde, 0x95, 0x11, + 0x8d, 0x26, 0x03, 0xda, 0xf4, 0x52, 0xd9, 0xc3, 0xd4, 0xf5, 0x92, 0x55, 0x74, 0x77, 0xdc, 0x9f, + 0xfe, 0xcf, 0xbc, 0xed, 0x3e, 0x4c, 0xb6, 0x9e, 0xcf, 0x10, 0x6a, 0x57, 0xa2, 0x25, 0x29, 0x90, + 0x40, 0xf8, 0x06, 0x5b, 0xed, 0xb0, 0xbc, 0xf9, 0xfc, 0x99, 0x1b, 0xdc, 0xef, 0x71, 0x74, 0xb0, + 0x10, 0xb5, 0xc4, 0xfc, 0x43, 0x0e, 0xab, 0x3c, 0xa6, 0x84, 0x3e, 0x97, 0x84, 0x21, 0x74, 0x29, + 0x4e, 0xc0, 0xb8, 0x5e, 0x20, 0x0a, 0xc7, 0xec, 0x84, 0xb7, 0x4e, 0xf0, 0x6d, 0x11, 0x09, 0x23, + 0x0f, 0x5c, 0xc5, 0xb9, 0x3c, 0x90, 0x0c, 0x5a, 0x55, 0xa0, 0x7b, 0xdc, 0x33, 0xb3, 0xe1, 0x41, + 0x48, 0x3f, 0xaa, 0x31, 0x19, 0xba, 0x6f, 0x8d, 0xeb, 0xd9, 0xba, 0x53, 0x52, 0x83, 0x78, 0x90, + 0x8d, 0x1c, 0x55, 0x71, 0xb0, 0x33, 0x43, 0x84, 0x15, 0x0a, 0x26, 0x3b, 0x64, 0x77, 0x47, 0x3e, + 0x6f, 0xbb, 0x11, 0x1a, 0x5b, 0xe8, 0x86, 0x51, 0x9e, 0x0c, 0x9a, 0x31, 0xf1, 0x40, 0x35, 0x34, + 0x1a, 0xc7, 0xcf, 0x51, 0x0a, 0x77, 0x20, 0xda, 0xef, 0x4c, 0xd9, 0x4e, 0x0a, 0x05, 0x88, 0x59, + 0xbe, 0xb3, 0xa4, 0x82, 0xe0, 0x76, 0x82, 0x0f, 0x1c, 0x92, 0x58, 0x8b, 0x6f, 0xdf, 0xae, 0xab, + 0x84, 0x95, 0xf3, 0xe7, 0xd9, 0x6d, 0x8f, 0x82, 0xc4, 0xd5, 0x00, 0x02, 0x7d, 0xde, 0x73, 0x52, + 0x7e, 0xad, 0xb9, 0xc2, 0xfd, 0x83, 0x69, 0xed, 0x5e, 0xb9, 0xb3, 0x45, 0xe7, 0xa7, 0xfc, 0x69, + 0xb9, 0x46, 0x7d, 0x9c, 0x52, 0xc8, 0x45, 0xe2, 0x14, 0xe5, 0xb2, 0x7c, 0xd3, 0xe3, 0x29, 0x5b, + 0xfe, 0x34, 0x54, 0x56, 0x07, 0xcf, 0x62, 0xec, 0xd2, 0x58, 0xaa, 0x1d, 0x82, 0x25, 0xa2, 0x2f, + 0xf6, 0x39, 0x09, 0x62, 0xe1, 0x40, 0xb3, 0x5d, 0x48, 0xb2, 0x1d, 0x89, 0x4f, 0xd3, 0x52, 0x4b, + 0x1c, 0x96, 0x8e, 0x37, 0x52, 0x39, 0x95, 0xec, 0x86, 0x18, 0xa2, 0xbb, 0x26, 0xd8, 0xd2, 0x10, + 0x5c, 0x0d, 0x29, 0x9f, 0xe5, 0xc4, 0x11, 0x2b, 0x54, 0xf5, 0xe0, 0x3a, 0xd4, 0x79, 0xe6, 0x0a, + 0x2b, 0xd9, 0x81, 0xc4, 0xac, 0xb8, 0x5a, 0xe9, 0xd0, 0x59, 0xfa, 0x13, 0xbf, 0x42, 0x7d, 0x64, + 0x46, 0xb7, 0xa4, 0xeb, 0xb6, 0x31, 0x53, 0x5d, 0x05, 0x12, 0x8b, 0x2c, 0x17, 0x42, 0x0d, 0x17, + 0x4b, 0x1b, 0x69, 0x85, 0x09, 0x12, 0xc5, 0xea, 0x0c, 0x08, 0xdf, 0x87, 0xcc, 0xeb, 0x1b, 0x21, + 0x06, 0x4d, 0x48, 0x56, 0xeb, 0x0d, 0xad, 0xc4, 0x98, 0xb5, 0x80, 0xdb, 0x89, 0x88, 0x14, 0x04, + 0xde, 0xe6, 0x58, 0x6c, 0xb7, 0x5f, 0xcb, 0xfb, 0x27, 0xd0, 0x99, 0x8f, 0xba, 0x9f, 0x5a, 0x0c, + 0x79, 0xc5, 0x83, 0xcf, 0x41, 0xd5, 0xd3, 0xd4, 0xf1, 0x5b, 0xb2, 0x69, 0xca, 0xee, 0xba, 0xce, + 0x86, 0x0c, 0xb5, 0x6c, 0x7b, 0x7f, 0x8e, 0xc5, 0x73, 0xa7, 0xe7, 0x16, 0xa2, 0x83, 0xfd, 0xc5, + 0x59, 0xd2, 0x17, 0x0b, 0xea, 0x21, 0xb8, 0x4b, 0xd9, 0x75, 0x9e, 0x06, 0x59, 0xe6, 0x12, 0xa9, + 0x90, 0x60, 0x13, 0xc4, 0xd4, 0x14, 0x57, 0x37, 0xdf, 0x98, 0xf9, 0x52, 0xd5, 0xd7, 0xcf, 0xeb, + 0x09, 0xc5, 0x71, 0xbf, 0xbf, 0x25, 0xe2, 0x36, 0xfb, 0xd1, 0xe7, 0xd5, 0xcb, 0xdc, 0x59, 0xab, + 0xae, 0xac, 0x4a, 0x56, 0x54, 0x4a, 0xb7, 0x89, 0x19, 0x61, 0xad, 0x95, 0xf7, 0xeb, 0x7b, 0x3b, + 0x8f, 0x7e, 0x0d, 0xd5, 0x74, 0xed, 0x95, 0xf3, 0x6d, 0x27, 0xfe, 0x05, 0xea, 0x89, 0x47, 0x1b, + 0x4c, 0xed, 0x3a, 0x7f, 0x1d, 0x3d, 0x90, 0xc5, 0x3f, 0x98, 0x5e, 0x60, 0x54, 0x1e, 0xfc, 0xac, + 0xd9, 0xa8, 0xc8, 0xb3, 0xa0, 0xc5, 0xbd, 0xdb, 0x19, 0x10, 0x68, 0x9c, 0xbd, 0xfc, 0x74, 0xaf, + 0x3d, 0x45, 0x56, 0x54, 0x9a, 0xc6, 0xf1, 0xe4, 0xc9, 0x49, 0xdc, 0xb3, 0xe5, 0xb1, 0x9b, 0x34, + 0xfb, 0x09, 0xbf, 0xa0, 0x63, 0xd5, 0x76, 0x2c, 0xfb, 0xf9, 0xc2, 0xfb, 0x77, 0xb1, 0xa8, 0x7e, + 0x7a, 0x42, 0x6d, 0xf9, 0xb2, 0x5f, 0x6a, 0x2b, 0x97, 0x88, 0x01, 0x9d, 0xf4, 0x04, 0xd3, 0x35, + 0x15, 0xf0, 0xc6, 0x80, 0x9c, 0xf7, 0x10, 0xe3, 0x59, 0xe8, 0x43, 0x06, 0xea, 0xb1, 0x2b, 0x14, + 0x93, 0x36, 0x4a, 0xa8, 0x34, 0x6e, 0x89, 0x58, 0xe7, 0xa3, 0xe6, 0x20, 0x85, 0x0a, 0xb4, 0xee, + 0x5a, 0x45, 0x91, 0x6a, 0xad, 0x52, 0x67, 0x97, 0xa1, 0x19, 0xca, 0x67, 0xc0, 0x33, 0xc3, 0x00, + 0x4b, 0xc6, 0xe3, 0xe4, 0xb4, 0x11, 0xbb, 0x41, 0xb3, 0xdb, 0x65, 0xf5, 0xf3, 0x97, 0x50, 0x67, + 0x91, 0x11, 0xe6, 0xbb, 0xc2, 0x05, 0xc6, 0x5a, 0xe9, 0xfc, 0xb9, 0x20, 0xde, 0x92, 0x32, 0x74, + 0x5c, 0x57, 0x85, 0x94, 0x78, 0x37, 0xea, 0x9d, 0x08, 0xfb, 0xfe, 0x26, 0x51, 0x12, 0xde, 0x5e, + 0x43, 0x35, 0xac, 0xf9, 0x29, 0x7b, 0x4f, 0xea, 0x76, 0x69, 0xb2, 0xed, 0xc8, 0x0d, 0x6e, 0x62, + 0x23, 0x5e, 0x50, 0xf6, 0xed, 0x66, 0x98, 0x35, 0x88, 0x3b, 0xca, 0xe7, 0x98, 0x60, 0x0d, 0xed, + 0xe4, 0xab, 0x01, 0x62, 0x41, 0xea, 0xd9, 0x76, 0x37, 0x7e, 0x3e, 0xde, 0x6f, 0x71, 0x69, 0x7a, + 0xf8, 0xa6, 0x0b, 0x1a, 0x2b, 0xaf, 0x2b, 0x0d, 0xc0, 0xe7, 0x4e, 0x7f, 0x76, 0xf9, 0x8d, 0x97, + 0xf8, 0xd5, 0x94, 0x51, 0xf8, 0xf2, 0x94, 0x4e, 0xd1, 0x8b, 0x46, 0x52, 0x38, 0xae, 0x56, 0x4b, + 0xa8, 0xc5, 0x60, 0x38, 0xc6, 0xb9, 0xd5, 0xc3, 0xab, 0x9f, 0x03, 0xba, 0x47, 0x88, 0x90, 0x11, + 0xf2, 0x7e, 0xd1, 0x2a, 0x3e, 0xf3, 0xff, 0x5d, 0x54, 0xb5, 0xbc, 0x4a, 0xa5, 0x16, 0x3e, 0x0b, + 0x35, 0x65, 0xb6, 0xc6, 0x0f, 0x74, 0x64, 0x2b, 0xff, 0xa6, 0x36, 0xd6, 0xca, 0x1f, 0x4c, 0x9b, + 0x77, 0xd7, 0x10, 0xfb, 0x65, 0xa8, 0x89, 0x6c, 0xf1, 0x8a, 0xeb, 0x0a, 0xfa, 0xa6, 0xa4, 0x6c, + 0x73, 0x15, 0x8a, 0x35, 0x31, 0x1c, 0x8f, 0x5e, 0x6c, 0x74, 0xb9, 0xa4, 0x78, 0xdc, 0xea, 0x2e, + 0x5c, 0x28, 0x16, 0xf8, 0x3c, 0xc3, 0xae, 0x9f, 0x03, 0xc2, 0xe1, 0x9f, 0xf8, 0x7d, 0xfb, 0xf4, + 0x66, 0x92, 0xfa, 0xee, 0xf8, 0x31, 0x48, 0x1d, 0x79, 0xbb, 0xed, 0xdd, 0x64, 0x99, 0xd2, 0x2b, + 0x7c, 0xdf, 0xea, 0x51, 0xf5, 0x58, 0xb7, 0xc6, 0x1e, 0x85, 0x5b, 0xab, 0xd7, 0x02, 0x61, 0xff, + 0xdf, 0x94, 0xea, 0xf7, 0xe0, 0x5d, 0x8c, 0x17, 0x0f, 0x92, 0xf7, 0xb2, 0xef, 0x8e, 0x0e, 0xb8, + 0xf7, 0xf8, 0x63, 0x3f, 0x97, 0x8d, 0xaf, 0xd3, 0x73, 0x7b, 0x7c, 0xdd, 0x22, 0xb9, 0x92, 0xea, + 0x4a, 0x9e, 0x17, 0x47, 0x1d, 0x09, 0xad, 0xcc, 0x4e, 0x1e, 0xf7, 0x77, 0xbf, 0x2b, 0xf6, 0x57, + 0xe2, 0x7e, 0x93, 0x44, 0xaa, 0x37, 0xbc, 0xdd, 0x65, 0x6b, 0xa2, 0xb1, 0xb7, 0x07, 0xfc, 0xe3, + 0x08, 0x59, 0xf3, 0xfd, 0xfb, 0xeb, 0xaf, 0x59, 0x50, 0xd3, 0xc9, 0x33, 0xca, 0x5b, 0xd0, 0xd8, + 0x60, 0x3a, 0xba, 0x49, 0xe0, 0x7e, 0xe0, 0x47, 0x3e, 0xe4, 0x97, 0x68, 0x9b, 0xbb, 0x72, 0x61, + 0xba, 0x1f, 0x06, 0xef, 0x2d, 0x55, 0x51, 0xf9, 0x21, 0x31, 0x7e, 0xef, 0x92, 0x03, 0xf3, 0xde, + 0xb5, 0x68, 0xf7, 0x99, 0x7b, 0xa1, 0x43, 0x15, 0x76, 0xe7, 0xb5, 0xf2, 0xa5, 0x50, 0x36, 0x4e, + 0xad, 0x74, 0x17, 0x2e, 0xa9, 0x73, 0x4a, 0x67, 0x6f, 0x9f, 0x4c, 0x60, 0xaa, 0x79, 0xfd, 0xc5, + 0xb4, 0x25, 0x79, 0xcd, 0x88, 0x4f, 0x82, 0x3a, 0x3e, 0xc7, 0x8d, 0xc7, 0x58, 0xbb, 0xad, 0x56, + 0xd2, 0x1c, 0x55, 0x61, 0x53, 0x7a, 0x5f, 0x93, 0xe8, 0x8b, 0x77, 0x83, 0xd0, 0x58, 0x3a, 0xd8, + 0xea, 0x6a, 0xf6, 0x0a, 0x81, 0x5e, 0x4d, 0x3d, 0xd9, 0x49, 0xbc, 0x36, 0xd7, 0x4f, 0x3f, 0x61, + 0x26, 0xcd, 0x58, 0x33, 0x32, 0x5d, 0x8b, 0xf6, 0xc5, 0x26, 0x72, 0x6d, 0x3c, 0xa9, 0x67, 0xce, + 0x7f, 0xad, 0x04, 0x02, 0x4b, 0xff, 0x60, 0xda, 0xc6, 0x6f, 0x1c, 0xdd, 0xa2, 0x0d, 0xf9, 0x0f, + 0x72, 0x91, 0x09, 0xb8, 0x52, 0xf1, 0x6a, 0x24, 0x89, 0x70, 0xaa, 0xb8, 0x6c, 0x54, 0x78, 0x00, + 0x61, 0x5c, 0xc1, 0xe7, 0x8b, 0xee, 0xa9, 0x75, 0xa0, 0x7c, 0xcd, 0x6c, 0xd4, 0x04, 0xd5, 0x17, + 0xf6, 0x7a, 0x44, 0xc2, 0xcc, 0xe0, 0x10, 0x8a, 0x0a, 0xbe, 0x79, 0x82, 0x4c, 0xbe, 0x41, 0x13, + 0x1b, 0x7c, 0x29, 0x42, 0x29, 0xdd, 0xec, 0xe9, 0xd1, 0xea, 0x78, 0x36, 0x1a, 0xb9, 0x9f, 0xe7, + 0xa8, 0x44, 0x5b, 0xcc, 0xf7, 0x75, 0xe8, 0x96, 0x56, 0x27, 0x31, 0xfa, 0x3b, 0xcf, 0x6a, 0x62, + 0x26, 0x85, 0xee, 0xa4, 0x67, 0xc2, 0xd6, 0x9a, 0x3f, 0x96, 0xe2, 0x80, 0xa7, 0xcb, 0xea, 0x2f, + 0x72, 0x5f, 0x65, 0x22, 0xb0, 0x08, 0xea, 0x2b, 0x2d, 0x1e, 0x74, 0x18, 0x94, 0xe6, 0x75, 0x61, + 0xd4, 0xa6, 0xbf, 0x9f, 0xd1, 0xb6, 0x6a, 0x3a, 0x8b, 0xb9, 0xed, 0xbc, 0x3d, 0xc9, 0xd2, 0xa6, + 0xc1, 0xa0, 0x8e, 0x1b, 0xba, 0xf5, 0x25, 0xc0, 0x43, 0x17, 0x51, 0x97, 0x18, 0x06, 0x3b, 0x44, + 0xc3, 0x14, 0xb4, 0x30, 0x87, 0x96, 0x4d, 0x5f, 0x6a, 0xc9, 0x57, 0xf6, 0x2c, 0x0d, 0x2d, 0xc0, + 0x8f, 0x2c, 0xdd, 0xf2, 0xae, 0xbb, 0xb4, 0x73, 0x83, 0xb6, 0x07, 0x8e, 0xb5, 0x71, 0x75, 0x78, + 0x1d, 0x7d, 0xee, 0x34, 0x0f, 0xf4, 0xdd, 0x45, 0x9d, 0xc1, 0xe8, 0x97, 0x4b, 0x76, 0xca, 0x4d, + 0x16, 0x37, 0x06, 0x0e, 0x79, 0x3c, 0xcb, 0xfa, 0xdf, 0x2f, 0xd5, 0x6b, 0x55, 0x2d, 0x5b, 0xf7, + 0x35, 0xe0, 0xb9, 0x39, 0x9f, 0xeb, 0x76, 0xac, 0x2d, 0x8b, 0x16, 0xd0, 0xa6, 0x0d, 0xaa, 0xcf, + 0xa9, 0x78, 0x6a, 0x91, 0xa6, 0x8f, 0x77, 0x67, 0xe6, 0x53, 0x8e, 0x8d, 0x56, 0xd6, 0xc2, 0xb1, + 0xab, 0x42, 0x8b, 0xe5, 0x2e, 0x5a, 0x2d, 0xa6, 0x7d, 0xcf, 0x9a, 0xc7, 0x24, 0x18, 0xb7, 0x58, + 0x9d, 0x86, 0x0d, 0xb4, 0x50, 0x8d, 0x93, 0x22, 0x79, 0xf3, 0x60, 0xba, 0xb0, 0x0b, 0x1e, 0x7d, + 0xa5, 0xce, 0x7e, 0x3b, 0xf8, 0xcd, 0x59, 0xc1, 0xd0, 0x1f, 0x4c, 0x8b, 0x79, 0xc3, 0x57, 0x63, + 0x56, 0x77, 0x29, 0xeb, 0x05, 0x77, 0xcb, 0x9b, 0x87, 0x28, 0xfb, 0xda, 0x04, 0x59, 0xad, 0xe2, + 0x31, 0x4c, 0x5f, 0xe9, 0xdf, 0x7a, 0xe6, 0x5f, 0xbc, 0x83, 0x51, 0x4a, 0x8a, 0x1b, 0xda, 0x09, + 0xb3, 0xfe, 0x21, 0x95, 0xfd, 0xbc, 0xf7, 0x86, 0x1e, 0x4f, 0x42, 0x1b, 0x9d, 0x51, 0x06, 0xbb, + 0x7a, 0x93, 0xb5, 0x1e, 0x91, 0x1a, 0x74, 0x99, 0x7b, 0xf2, 0xd3, 0x25, 0xa0, 0x06, 0x9e, 0x5b, + 0x91, 0x1f, 0xa4, 0x14, 0x86, 0xe2, 0xfd, 0x5f, 0x2f, 0xed, 0x90, 0x91, 0x58, 0xd8, 0xe5, 0x1d, + 0xef, 0xb3, 0x49, 0xa3, 0xb3, 0x7e, 0xcc, 0x3b, 0x38, 0x35, 0x26, 0x58, 0x2e, 0x82, 0xf9, 0xb5, + 0x21, 0x36, 0x9e, 0x44, 0x30, 0xd0, 0x7c, 0x85, 0x29, 0x6b, 0xb2, 0x5e, 0x77, 0x51, 0xf0, 0x72, + 0x37, 0x8d, 0xeb, 0x65, 0xd2, 0x45, 0xf1, 0x5a, 0x20, 0xd3, 0x0f, 0xbb, 0x37, 0x7d, 0x21, 0x9a, + 0xde, 0xa4, 0x0a, 0x67, 0xd7, 0xee, 0xf6, 0xa9, 0xaa, 0x5c, 0xe4, 0x7d, 0x80, 0x70, 0x8b, 0xd6, + 0xa6, 0x82, 0xe1, 0xe3, 0xbf, 0x0a, 0x0f, 0xde, 0xa1, 0x08, 0x29, 0x44, 0xc1, 0x5a, 0x77, 0x45, + 0x7b, 0xeb, 0x99, 0x95, 0x16, 0xb6, 0x7c, 0xd3, 0xf4, 0x76, 0x8d, 0xc1, 0x52, 0xf9, 0x45, 0x21, + 0x79, 0x4d, 0x6c, 0xf4, 0x4d, 0xb0, 0x03, 0x8b, 0x97, 0x09, 0x9c, 0x54, 0x3b, 0xa1, 0x25, 0xec, + 0x6d, 0x91, 0xca, 0xc6, 0x9d, 0xc7, 0xc9, 0x04, 0x7e, 0x02, 0xcf, 0x16, 0x9c, 0x1b, 0xb8, 0x8a, + 0x1c, 0x63, 0xee, 0x67, 0xe5, 0xb8, 0x42, 0xca, 0x42, 0xc2, 0x47, 0x84, 0x91, 0x62, 0xa7, 0xab, + 0xef, 0x6b, 0x0d, 0x62, 0x8b, 0x6a, 0x33, 0xbd, 0x79, 0xa4, 0x0b, 0xcd, 0xdd, 0x1a, 0x9d, 0xff, + 0x20, 0xda, 0x44, 0xb2, 0xa5, 0xe0, 0x21, 0x21, 0x0d, 0x09, 0x02, 0x49, 0xe2, 0x60, 0xe7, 0x7f, + 0xa6, 0xc5, 0xf8, 0x17, 0x47, 0xcd, 0x5b, 0x18, 0x5a, 0x69, 0x3a, 0xd1, 0x4e, 0x9d, 0xaf, 0x3a, + 0x99, 0xda, 0x4d, 0x3f, 0xf0, 0xe7, 0x9e, 0x68, 0xfa, 0xeb, 0x8c, 0xa8, 0xa0, 0xfc, 0xc1, 0x34, + 0xb6, 0xc7, 0xbb, 0x43, 0x78, 0x26, 0x63, 0x6b, 0xe7, 0x25, 0x21, 0xd8, 0x1a, 0x8c, 0x93, 0xde, + 0xeb, 0x11, 0xf1, 0x56, 0x56, 0xe0, 0x1a, 0x89, 0xf3, 0x76, 0xba, 0xce, 0xd4, 0x9c, 0x23, 0x0c, + 0xad, 0xfb, 0xce, 0xb3, 0x88, 0xe9, 0xd7, 0xc6, 0x2b, 0x0f, 0x26, 0xbf, 0x47, 0xd1, 0x30, 0xf9, + 0x2d, 0x50, 0x56, 0xe5, 0xf3, 0x28, 0x24, 0xfe, 0xda, 0x42, 0x9e, 0xa8, 0xbd, 0x2f, 0xb0, 0xdb, + 0x0e, 0x7f, 0x8b, 0x19, 0x7d, 0x68, 0xf8, 0x45, 0x50, 0x69, 0xec, 0x97, 0x09, 0x84, 0x11, 0x72, + 0xb1, 0x5e, 0xd3, 0xb5, 0x6e, 0x01, 0xbd, 0x8b, 0x64, 0xce, 0x03, 0xc9, 0xda, 0x2d, 0x9b, 0x7d, + 0x15, 0xcf, 0x4a, 0xe2, 0xee, 0x96, 0x42, 0xe6, 0xb8, 0x22, 0xac, 0x74, 0x53, 0xf5, 0x2c, 0x62, + 0x01, 0xdb, 0x70, 0x8b, 0x0e, 0xfa, 0x88, 0xe1, 0xa3, 0xbe, 0x1d, 0xc0, 0xd8, 0x8f, 0x81, 0x0e, + 0xe5, 0xd1, 0xa1, 0x3d, 0xcf, 0xf6, 0xe3, 0xc1, 0x4f, 0x79, 0x95, 0xc0, 0x55, 0x2f, 0x0e, 0xfe, + 0x49, 0x85, 0x6c, 0xfa, 0x6b, 0xfd, 0x01, 0xa9, 0xc5, 0xd5, 0x34, 0x52, 0x09, 0xb8, 0x31, 0x52, + 0xd3, 0xaa, 0xed, 0x5b, 0x1f, 0xe3, 0xc1, 0x19, 0x93, 0x58, 0x23, 0xef, 0xae, 0xe6, 0x84, 0xae, + 0xfa, 0x12, 0xf4, 0x9f, 0x32, 0x24, 0x39, 0xa0, 0xd2, 0xeb, 0x00, 0x32, 0x11, 0x5d, 0x49, 0x93, + 0xb5, 0xaa, 0xbd, 0xba, 0xd9, 0xec, 0x59, 0xa0, 0x0b, 0x8e, 0x56, 0xda, 0x03, 0x08, 0x66, 0x2e, + 0xa2, 0x25, 0xa7, 0x42, 0xc1, 0x36, 0x3f, 0x9d, 0xb5, 0xb4, 0x12, 0xd1, 0x5f, 0x3d, 0x1a, 0x54, + 0x19, 0x2a, 0xcd, 0x30, 0xac, 0x2c, 0x8e, 0x04, 0xb7, 0x04, 0x62, 0x10, 0xe0, 0x81, 0x36, 0x20, + 0x73, 0x23, 0x2b, 0x29, 0x36, 0x6c, 0x8c, 0x88, 0xe5, 0xa2, 0x4f, 0xc1, 0xc6, 0xc1, 0x46, 0x02, + 0x65, 0xe3, 0xa5, 0xf1, 0x22, 0x7b, 0x5d, 0x18, 0x94, 0xaa, 0xa2, 0x4e, 0xba, 0x89, 0x57, 0x4c, + 0x05, 0x93, 0x6c, 0x97, 0xeb, 0x66, 0x50, 0x52, 0x1d, 0xfd, 0x9a, 0x61, 0x6e, 0x52, 0xfc, 0xc1, + 0x34, 0xae, 0xfb, 0x1e, 0xf2, 0xc6, 0x9a, 0x38, 0xa2, 0x4e, 0x85, 0xec, 0xb5, 0xc5, 0x41, 0xb6, + 0x1a, 0xa2, 0x05, 0xc5, 0xa2, 0x97, 0xbb, 0x6b, 0x86, 0x0c, 0x76, 0xe3, 0xef, 0xb1, 0x45, 0xb3, + 0xc8, 0x56, 0x8b, 0xd6, 0xf0, 0xd3, 0xca, 0xe0, 0xfb, 0x6a, 0x68, 0xcf, 0xb4, 0x85, 0x67, 0x1c, + 0x87, 0xf8, 0x27, 0xa5, 0x63, 0x32, 0x65, 0xea, 0x6d, 0xa3, 0xc4, 0x62, 0xdf, 0xd7, 0x89, 0x87, + 0x16, 0x52, 0x5d, 0xff, 0xb0, 0x9f, 0xbe, 0x22, 0x91, 0x85, 0x1d, 0x64, 0x06, 0x5f, 0xb1, 0x9c, + 0x10, 0xac, 0xe6, 0x4e, 0x3c, 0x81, 0xbf, 0xec, 0xdd, 0x5d, 0x2f, 0x64, 0x72, 0x11, 0x09, 0xfa, + 0xba, 0x47, 0xb4, 0x58, 0x0f, 0xd3, 0xf3, 0xff, 0xd4, 0x75, 0xf0, 0x5b, 0x42, 0xdc, 0xc9, 0x51, + 0x1b, 0xad, 0x95, 0xdc, 0x68, 0x3b, 0xf7, 0xb0, 0x75, 0xa1, 0xb3, 0x1d, 0x04, 0x4d, 0x66, 0x2b, + 0xf7, 0x9a, 0xde, 0xae, 0x72, 0x2c, 0xe9, 0x2d, 0xc9, 0x0e, 0x9c, 0x58, 0xe6, 0xee, 0x20, 0x2d, + 0xf3, 0x34, 0xf9, 0xe3, 0x67, 0x7b, 0x04, 0x97, 0xff, 0x53, 0x40, 0xd1, 0xbf, 0x85, 0xbe, 0x0d, + 0x3c, 0xb5, 0x08, 0xff, 0x7e, 0xd3, 0x75, 0x5b, 0x9e, 0x4c, 0xe3, 0x33, 0x11, 0x9d, 0x6c, 0x6d, + 0xc4, 0x9a, 0xac, 0xaf, 0x50, 0xb3, 0xe6, 0xe3, 0xc1, 0x50, 0x9c, 0x77, 0x2e, 0x64, 0xcb, 0xa7, + 0xaf, 0x2b, 0x73, 0xab, 0x67, 0xee, 0xfd, 0x4f, 0x52, 0xaf, 0xaf, 0x03, 0x81, 0x6b, 0x37, 0x41, + 0xba, 0xb8, 0x32, 0x40, 0xf3, 0xc5, 0xef, 0xeb, 0x54, 0xc5, 0x63, 0x15, 0x46, 0xe6, 0xf4, 0xf7, + 0xc9, 0xbb, 0xc4, 0x03, 0xcf, 0x71, 0x9e, 0x53, 0xef, 0x1c, 0x0d, 0x6f, 0x75, 0xa4, 0xb3, 0x85, + 0x3f, 0xd8, 0xc2, 0x37, 0x43, 0xdd, 0xd9, 0x91, 0x27, 0x27, 0xaa, 0x29, 0xee, 0x12, 0x83, 0x26, + 0x7e, 0xc4, 0x1c, 0xc4, 0x5a, 0xdb, 0x79, 0xa9, 0xed, 0x25, 0x43, 0x54, 0xc1, 0x75, 0x86, 0xed, + 0xd1, 0x7b, 0x4d, 0x4b, 0xb7, 0xc2, 0xf2, 0xd4, 0xa4, 0x6e, 0x4c, 0x76, 0x27, 0x9a, 0xcc, 0xfa, + 0xaf, 0xb9, 0x58, 0x1d, 0xe5, 0x1f, 0x4c, 0x67, 0x75, 0xc2, 0xb3, 0xbb, 0x61, 0xc4, 0x5d, 0x23, + 0x5b, 0x3c, 0x41, 0x09, 0x59, 0xa4, 0x81, 0x0e, 0x24, 0xa5, 0x5a, 0x8b, 0x22, 0xb3, 0x84, 0xa8, + 0x02, 0x27, 0x95, 0xc2, 0x96, 0xa5, 0x07, 0xe0, 0x40, 0xea, 0x39, 0x74, 0x8a, 0xb5, 0xa4, 0x9a, + 0x6f, 0x9e, 0x2a, 0x9e, 0x08, 0x6b, 0xdc, 0xd9, 0x2f, 0x80, 0x67, 0x33, 0xf2, 0xe5, 0x84, 0xec, + 0xa4, 0x95, 0xaa, 0x6b, 0x05, 0xa2, 0xcc, 0xb9, 0x2a, 0x28, 0x17, 0x34, 0x76, 0x82, 0x8b, 0x64, + 0xbc, 0xd2, 0x61, 0x97, 0x4b, 0xe8, 0xe2, 0x67, 0xe0, 0xf8, 0xb6, 0x06, 0xe6, 0x2b, 0x95, 0x1c, + 0x67, 0xbb, 0x74, 0x9b, 0xa0, 0x69, 0x1f, 0xf7, 0xd1, 0x2f, 0x4e, 0xe2, 0xaf, 0x46, 0x36, 0x79, + 0x92, 0x00, 0xc5, 0xdf, 0x52, 0xff, 0x95, 0x64, 0x35, 0x08, 0x05, 0x5d, 0xf0, 0xed, 0x3d, 0xfa, + 0x43, 0x55, 0x5d, 0xb5, 0xec, 0x12, 0x00, 0x12, 0xe6, 0x5c, 0x2e, 0xf5, 0x57, 0x58, 0x25, 0x3a, + 0x18, 0x68, 0xb4, 0xbe, 0xf7, 0x20, 0x27, 0xf1, 0x1e, 0xe0, 0x61, 0xd6, 0x32, 0x78, 0x97, 0x4a, + 0xb8, 0xcb, 0x54, 0xb3, 0x7a, 0xe4, 0x4c, 0x35, 0xee, 0x23, 0xe6, 0x51, 0x9d, 0x17, 0xaa, 0x41, + 0x53, 0xea, 0x7d, 0xfc, 0x0a, 0xf9, 0xbc, 0xf3, 0x68, 0x61, 0xab, 0x01, 0x6d, 0x95, 0xc8, 0x73, + 0x62, 0xf5, 0x01, 0x14, 0x8f, 0xa0, 0x6a, 0xc3, 0xce, 0x6d, 0xf5, 0x99, 0x38, 0xf4, 0x1d, 0xa0, + 0x65, 0x8b, 0xaf, 0x9d, 0xb1, 0x97, 0x5f, 0xe9, 0x9b, 0xf6, 0x74, 0xec, 0x6e, 0x68, 0x31, 0x24, + 0xe3, 0x84, 0xe8, 0xde, 0x89, 0x77, 0x63, 0x87, 0x0d, 0x57, 0xbc, 0x7a, 0x08, 0x6b, 0x47, 0xf7, + 0xde, 0xa1, 0x9a, 0x53, 0xbf, 0x6a, 0xcd, 0x5c, 0x86, 0xec, 0x1d, 0xf5, 0x8b, 0x1d, 0xf3, 0xc8, + 0x58, 0x69, 0xd0, 0x79, 0x4d, 0xff, 0x12, 0x6b, 0x7e, 0x57, 0xd9, 0xf9, 0xbb, 0x09, 0x62, 0x65, + 0xba, 0xd9, 0x40, 0x05, 0xd3, 0x93, 0x46, 0x82, 0x1e, 0xb5, 0x27, 0x86, 0x05, 0x63, 0x30, 0x61, + 0x81, 0x6a, 0x5b, 0xbf, 0xae, 0x5c, 0xc6, 0x9a, 0x3f, 0x98, 0x2e, 0x14, 0xc4, 0xc4, 0xbe, 0xc2, + 0x66, 0xf3, 0x25, 0x96, 0x65, 0xa1, 0x7b, 0x3a, 0xc3, 0x96, 0x91, 0x34, 0x97, 0x30, 0xc7, 0x50, + 0x51, 0xcd, 0x3a, 0x9e, 0xe0, 0x9e, 0x65, 0xed, 0xe5, 0xcd, 0xfe, 0x19, 0x26, 0xf0, 0x95, 0xf0, + 0x99, 0x33, 0x70, 0xaf, 0x3e, 0x5a, 0xbf, 0x8a, 0xaf, 0xaa, 0x4c, 0x7e, 0x56, 0xc3, 0x78, 0x90, + 0x8c, 0x28, 0x7d, 0x1d, 0x86, 0xd8, 0x52, 0xdb, 0xf2, 0x50, 0x25, 0x15, 0xec, 0x38, 0x07, 0x9c, + 0x0a, 0xb6, 0xc3, 0xf5, 0xab, 0x26, 0x85, 0x26, 0x36, 0x8e, 0x95, 0xd7, 0x90, 0x45, 0xc2, 0x54, + 0xdd, 0xc3, 0x2d, 0x24, 0xfd, 0x28, 0xd9, 0xd8, 0xa7, 0xf3, 0x21, 0x9c, 0xc1, 0x2a, 0x5a, 0x3c, + 0xbe, 0xac, 0xdd, 0x11, 0x9a, 0x59, 0xe6, 0xc8, 0x5d, 0xbd, 0xfa, 0xa5, 0x4a, 0xd3, 0xc5, 0xb2, + 0x7a, 0xa4, 0x96, 0x50, 0x15, 0x25, 0xbb, 0x38, 0xbd, 0x7f, 0x4f, 0xd4, 0xad, 0xd0, 0xc0, 0x85, + 0x87, 0xb8, 0x04, 0x03, 0x55, 0x82, 0x1a, 0x75, 0x5a, 0x2f, 0xf2, 0x88, 0xee, 0xb9, 0xc2, 0xe6, + 0xcd, 0x58, 0xb0, 0x37, 0x4a, 0x50, 0xa7, 0xfa, 0x20, 0x75, 0x49, 0x17, 0xd7, 0x28, 0x96, 0x05, + 0x82, 0xcd, 0x34, 0xd6, 0xf0, 0x3b, 0x37, 0x2f, 0xb5, 0x3b, 0x57, 0x18, 0x4a, 0x17, 0xc7, 0x89, + 0xd5, 0xd3, 0xe4, 0xe6, 0x10, 0x51, 0x7a, 0x4b, 0xcf, 0x66, 0x80, 0x27, 0xaa, 0x77, 0x69, 0x79, + 0x8f, 0x7b, 0x9a, 0xd0, 0x79, 0x65, 0x79, 0x2e, 0xbb, 0x45, 0x4d, 0x16, 0xbc, 0x9b, 0xe3, 0xfb, + 0x9c, 0x5d, 0x53, 0x1b, 0x62, 0x6a, 0x19, 0xfd, 0xf9, 0x4b, 0xbf, 0x51, 0xd3, 0x00, 0xb2, 0xc6, + 0x8f, 0xb6, 0x2e, 0x9d, 0x0c, 0x64, 0x75, 0x6a, 0x47, 0x05, 0x55, 0x55, 0xee, 0xff, 0xca, 0xf3, + 0x2b, 0x55, 0xcf, 0x50, 0x5c, 0x6c, 0xed, 0x23, 0x74, 0x87, 0xb0, 0x4b, 0x91, 0x3a, 0x84, 0xa8, + 0x4e, 0x12, 0x8d, 0xcf, 0xcc, 0x4a, 0x85, 0x67, 0x3f, 0x53, 0x05, 0xb9, 0x8f, 0x24, 0x73, 0xee, + 0x32, 0xe5, 0x2b, 0xdf, 0x6c, 0xf8, 0xb5, 0xb2, 0x1e, 0x85, 0xf9, 0x07, 0xd3, 0x89, 0xe2, 0x00, + 0xde, 0x9f, 0xe1, 0x95, 0x37, 0xba, 0xac, 0x39, 0x50, 0xd1, 0x55, 0x98, 0x45, 0x2d, 0xef, 0x22, + 0xdf, 0x36, 0xae, 0x34, 0xf6, 0xd8, 0x22, 0x93, 0x4e, 0x9e, 0x6b, 0xce, 0xb7, 0x56, 0x2e, 0xa2, + 0x08, 0x11, 0xf7, 0x5d, 0xff, 0xdd, 0x63, 0x93, 0xa6, 0xab, 0xf4, 0xa5, 0xa6, 0xe4, 0x7d, 0x66, + 0x00, 0x8e, 0xc4, 0x9c, 0xca, 0x76, 0x83, 0x53, 0xe9, 0xce, 0x30, 0xba, 0x0c, 0x81, 0xee, 0x84, + 0x4c, 0xad, 0x32, 0x06, 0x72, 0x3c, 0x4d, 0xe9, 0x35, 0x5e, 0xb8, 0xab, 0x22, 0xac, 0xf8, 0x60, + 0xd7, 0x63, 0xce, 0xe5, 0xcf, 0x6f, 0xf0, 0x05, 0x00, 0x0e, 0xa0, 0x3c, 0x2d, 0xee, 0x6a, 0x88, + 0x89, 0xd2, 0xb3, 0x4c, 0xe5, 0x24, 0xa4, 0x8a, 0xf8, 0xb7, 0xdb, 0x3a, 0x25, 0x0e, 0xc4, 0xd0, + 0x2d, 0x91, 0xf3, 0xa8, 0x53, 0x60, 0x9c, 0x76, 0xff, 0x22, 0xe2, 0xa2, 0xb5, 0x9e, 0x4e, 0xd5, + 0x2c, 0x9f, 0x25, 0xa5, 0x69, 0xc8, 0x97, 0x90, 0xec, 0x78, 0x60, 0xa6, 0x32, 0x87, 0xdc, 0x5c, + 0x52, 0x61, 0x45, 0xbd, 0x6b, 0x33, 0x1d, 0xbc, 0x4c, 0xb4, 0x07, 0x7a, 0x74, 0x86, 0xe6, 0x06, + 0x50, 0xca, 0x82, 0xb1, 0xb3, 0xf1, 0x62, 0x20, 0x5e, 0xbb, 0x09, 0xb1, 0x0b, 0x5e, 0xa4, 0xf1, + 0x7c, 0xd3, 0x70, 0x37, 0xc2, 0xeb, 0x30, 0x69, 0xe2, 0xa6, 0x73, 0x97, 0x6d, 0xde, 0x03, 0x86, + 0xf8, 0x4f, 0xf0, 0xd1, 0x58, 0xe4, 0x6b, 0xde, 0xba, 0x5c, 0xf5, 0x37, 0xf7, 0xfb, 0xaa, 0xe1, + 0xc2, 0xdf, 0xcd, 0x01, 0x8d, 0x40, 0x5a, 0x94, 0x28, 0x1e, 0xc7, 0xda, 0x79, 0x48, 0x63, 0xda, + 0x04, 0x64, 0x5b, 0xb0, 0xb5, 0xe8, 0xc2, 0x17, 0x72, 0x11, 0xcd, 0x8f, 0x31, 0x38, 0xb8, 0xf2, + 0xe0, 0xcc, 0xac, 0x4a, 0x37, 0x88, 0xac, 0x7a, 0xc5, 0x95, 0xa4, 0xaa, 0xfa, 0x58, 0xa7, 0x64, + 0x34, 0xe9, 0x4f, 0xf7, 0x32, 0xb3, 0x3c, 0x9d, 0xab, 0x69, 0xbd, 0xae, 0x30, 0x84, 0x75, 0x57, + 0x8b, 0x7a, 0xd9, 0x21, 0x31, 0xf8, 0x5c, 0xad, 0x99, 0x7e, 0xad, 0x8d, 0x65, 0xfa, 0x83, 0x69, + 0xaa, 0x5e, 0x62, 0xeb, 0xb2, 0xe5, 0xd7, 0x22, 0x78, 0x21, 0xec, 0x28, 0x6f, 0x3d, 0x7f, 0x11, + 0x5f, 0xdf, 0x5c, 0x42, 0xc6, 0x76, 0x6b, 0x6c, 0xe0, 0xa6, 0x76, 0xb9, 0xf7, 0x85, 0x6e, 0xf7, + 0x99, 0x9a, 0x4b, 0xb7, 0xa0, 0x2f, 0x27, 0x58, 0x07, 0xc2, 0x4c, 0x48, 0x9d, 0x54, 0x72, 0xce, + 0x5a, 0x89, 0xe8, 0xa1, 0x0e, 0x5d, 0x34, 0x69, 0x5f, 0xce, 0x5e, 0x45, 0x24, 0x44, 0x27, 0xfa, + 0x7e, 0x0b, 0xb9, 0xa5, 0xf6, 0x6b, 0x32, 0x68, 0xa4, 0x15, 0x84, 0xe6, 0xdb, 0x26, 0x38, 0x96, + 0xd6, 0xc3, 0xaf, 0xb4, 0xc4, 0xb3, 0xe8, 0x2e, 0x2e, 0x8b, 0x26, 0x65, 0x1d, 0x50, 0x5e, 0xd3, + 0x0d, 0xc7, 0xba, 0x7b, 0xf1, 0x74, 0x9a, 0xc8, 0x20, 0x99, 0x9c, 0x38, 0x95, 0x8c, 0xa7, 0x0d, + 0x87, 0xe7, 0x7e, 0x55, 0x34, 0xe4, 0x41, 0xd6, 0xab, 0x39, 0xe1, 0xbe, 0xaa, 0x20, 0xb6, 0x0d, + 0x92, 0xa3, 0x6b, 0xf1, 0x14, 0xa7, 0x9f, 0x04, 0x69, 0xc9, 0xc7, 0x90, 0x85, 0xd4, 0x6a, 0x63, + 0x6b, 0xb1, 0x57, 0xc2, 0xbf, 0xcb, 0x5c, 0xd2, 0x1a, 0x6c, 0x71, 0x6a, 0xce, 0x79, 0x32, 0xa5, + 0xce, 0x3e, 0xfe, 0x68, 0xe6, 0x1b, 0xf0, 0x7d, 0x90, 0x26, 0x2f, 0xbd, 0x9a, 0xb0, 0x08, 0x19, + 0xdc, 0xa2, 0xa9, 0x8c, 0x27, 0x75, 0x45, 0xc9, 0x73, 0x76, 0x7b, 0xb1, 0x60, 0xbb, 0x3b, 0xcc, + 0xe6, 0x0c, 0x5b, 0x5d, 0x1a, 0x54, 0x33, 0x35, 0xa5, 0xa5, 0xd4, 0x4d, 0xef, 0x53, 0x4c, 0xe4, + 0xc3, 0x99, 0x92, 0xaa, 0x76, 0xcc, 0x12, 0x03, 0x6a, 0xcd, 0x27, 0xf6, 0x7f, 0xa6, 0x06, 0x16, + 0xac, 0xde, 0x4a, 0x34, 0x8d, 0xe7, 0x3f, 0xdf, 0xa3, 0xc6, 0x34, 0xba, 0xd4, 0x34, 0x06, 0xae, + 0xb0, 0xbe, 0x31, 0xae, 0xb9, 0x08, 0x6b, 0x1e, 0x2d, 0xe3, 0xd2, 0x18, 0xb9, 0xa0, 0x0c, 0x8e, + 0x84, 0x53, 0xda, 0xbd, 0x73, 0xbb, 0xa7, 0xc8, 0xa5, 0x6a, 0x33, 0xcc, 0xbc, 0x26, 0x38, 0x1c, + 0xcc, 0xf2, 0x0d, 0x33, 0x43, 0x93, 0xdf, 0xd7, 0x5c, 0xe4, 0x3d, 0x6a, 0x7e, 0xad, 0x23, 0x84, + 0x58, 0xff, 0x60, 0x9a, 0xa1, 0x92, 0xc0, 0xdd, 0xcd, 0xbe, 0x05, 0x8c, 0x7c, 0x6a, 0xda, 0x5c, + 0xcf, 0x16, 0xde, 0x9d, 0xaf, 0x59, 0x60, 0xe9, 0xec, 0xfb, 0x9b, 0x98, 0x30, 0x3d, 0x3f, 0xb1, + 0xe8, 0x65, 0xfb, 0xd2, 0x47, 0xaf, 0xc0, 0x8c, 0x3c, 0xe7, 0xb7, 0x88, 0xa1, 0x9e, 0x3b, 0x5c, + 0x18, 0x97, 0x65, 0x04, 0x85, 0x2e, 0x91, 0x9c, 0x8c, 0x23, 0x89, 0xd3, 0x97, 0xfa, 0x2d, 0xde, + 0xf2, 0xd2, 0xc6, 0xa7, 0xf9, 0xb5, 0x23, 0xd3, 0xa3, 0x6a, 0xe0, 0xbe, 0x64, 0xfc, 0x33, 0x5c, + 0x50, 0x96, 0x0c, 0x62, 0xcf, 0x66, 0x1d, 0x70, 0x1d, 0x41, 0xf2, 0x73, 0x38, 0x44, 0xc9, 0x7c, + 0x73, 0xb5, 0x96, 0x33, 0x3b, 0xc7, 0xc8, 0x34, 0x3f, 0x78, 0x80, 0xb7, 0xda, 0x77, 0xc9, 0xb3, + 0xe2, 0xf0, 0x61, 0x4a, 0xe6, 0x0b, 0x3b, 0xc7, 0xaf, 0xb2, 0xbc, 0xe4, 0x3c, 0x3d, 0xd9, 0x03, + 0xfc, 0xcd, 0x06, 0xbb, 0x78, 0x17, 0x37, 0x2d, 0xc8, 0x76, 0xd5, 0x38, 0x68, 0x31, 0xb6, 0x09, + 0x86, 0x5e, 0x3b, 0xb5, 0x30, 0x07, 0x3b, 0xb1, 0xb4, 0x35, 0xb2, 0x4e, 0x69, 0xe7, 0xb9, 0xa7, + 0xff, 0xea, 0xcd, 0x3d, 0x24, 0x71, 0x53, 0xff, 0xd1, 0x9b, 0x9a, 0xa4, 0x76, 0x52, 0xa8, 0x7a, + 0xb7, 0xa8, 0x6b, 0xf4, 0x1e, 0x2e, 0x7c, 0xb7, 0xaf, 0x4b, 0x6e, 0x82, 0x0e, 0xbd, 0xc9, 0xae, + 0xab, 0x05, 0xe6, 0x79, 0x23, 0x43, 0xec, 0x82, 0xb0, 0xd4, 0xb2, 0x94, 0x17, 0x77, 0x22, 0x12, + 0xc9, 0xf1, 0xab, 0x82, 0x7e, 0x72, 0x7c, 0xa4, 0x30, 0x45, 0x4c, 0xc2, 0x6c, 0x1a, 0x6c, 0x89, + 0x9f, 0x99, 0x96, 0xb5, 0x63, 0x1c, 0x32, 0xe8, 0xa7, 0x56, 0x95, 0x58, 0xe1, 0xb1, 0x71, 0x4a, + 0xd7, 0x0b, 0xba, 0xbc, 0xc8, 0xf8, 0x82, 0x56, 0x0b, 0xfe, 0x21, 0x8d, 0x4d, 0xfa, 0xdb, 0x93, + 0x07, 0x4c, 0x61, 0x7d, 0x6e, 0xc3, 0x40, 0xfa, 0x7d, 0xb0, 0x3e, 0x65, 0x28, 0xdb, 0x7c, 0x73, + 0x57, 0xb4, 0xd2, 0xf2, 0x83, 0x48, 0x7b, 0xa4, 0x25, 0x9b, 0xcb, 0x16, 0x1f, 0xc9, 0x6a, 0x7f, + 0x3b, 0x81, 0x7f, 0xad, 0x61, 0x28, 0xfa, 0xad, 0xe9, 0x8f, 0xfc, 0xe0, 0x0f, 0x3e, 0xf8, 0xe0, + 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, + 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0xff, + 0x9e, 0xfc, 0xe7, 0x79, 0xb0, 0x2b, 0x8b, 0x61, 0x1d, 0x8f, 0x6a, 0x74, 0x71, 0x70, 0xb4, 0xf0, + 0x45, 0x73, 0xd8, 0x94, 0xf2, 0x72, 0x72, 0x5f, 0x2b, 0xa9, 0x82, 0x67, 0x82, 0xf3, 0xec, 0x9b, + 0x69, 0xab, 0xc7, 0xdb, 0xad, 0x14, 0x56, 0x6c, 0xda, 0xab, 0x5c, 0xda, 0xb6, 0x45, 0x16, 0x80, + 0xbd, 0x75, 0xe9, 0x52, 0xd1, 0x66, 0x37, 0xf7, 0x56, 0xbd, 0x76, 0x57, 0x91, 0x23, 0x3a, 0x92, + 0x2e, 0x44, 0x8c, 0x37, 0xa9, 0xeb, 0xd4, 0x41, 0xe0, 0x5e, 0xd4, 0xe3, 0x46, 0x24, 0x55, 0x28, + 0x79, 0xf7, 0xef, 0xd5, 0xa8, 0xba, 0xdc, 0xa2, 0xf4, 0xda, 0x03, 0x5a, 0xa7, 0xc8, 0x79, 0xab, + 0x13, 0xa6, 0x42, 0x03, 0x66, 0xf5, 0x78, 0xdb, 0x41, 0x84, 0xf5, 0x38, 0x34, 0xe7, 0xac, 0x29, + 0x63, 0x07, 0xcd, 0x68, 0x2c, 0xcd, 0x38, 0x6b, 0x74, 0x8f, 0xdd, 0x3e, 0x8e, 0xde, 0x2e, 0x96, + 0x99, 0xff, 0x1c, 0xee, 0x4b, 0x3e, 0xef, 0x85, 0x16, 0x8e, 0x13, 0x07, 0x7d, 0x4f, 0x90, 0xbb, + 0xf7, 0x70, 0xd6, 0x91, 0xec, 0x49, 0x96, 0x5e, 0x17, 0xb4, 0x07, 0x87, 0xbd, 0xc7, 0xbb, 0xc3, + 0x6e, 0x27, 0xec, 0x3a, 0xfe, 0xf5, 0xc4, 0x2d, 0x13, 0x05, 0xfa, 0x7d, 0x8e, 0x28, 0x76, 0x99, + 0x7a, 0x3b, 0x1c, 0x59, 0xbe, 0xbb, 0x51, 0xa5, 0x4d, 0xfc, 0x48, 0xe7, 0x03, 0xb2, 0x53, 0xf5, + 0x57, 0xf3, 0xe4, 0xc5, 0xa3, 0xc8, 0x4d, 0x8f, 0x42, 0x7c, 0x6e, 0x06, 0x1f, 0x12, 0x45, 0xb9, + 0xde, 0xd3, 0xeb, 0x03, 0x5b, 0xca, 0xbe, 0xe8, 0x6a, 0xf4, 0xef, 0x45, 0x09, 0x1b, 0xb8, 0xaa, + 0x17, 0x32, 0x77, 0xff, 0x96, 0x35, 0xaf, 0xba, 0x03, 0xbb, 0x2d, 0xf7, 0x98, 0x5a, 0x91, 0xe7, + 0xce, 0x42, 0x5f, 0xcd, 0xad, 0x74, 0xba, 0xc3, 0xc9, 0x8c, 0x7e, 0xe6, 0xf6, 0xdc, 0x4f, 0x2f, + 0x89, 0xe7, 0xb3, 0xb1, 0x7f, 0xd0, 0x70, 0xde, 0x0e, 0x96, 0x74, 0x07, 0xc2, 0x01, 0x73, 0x85, + 0x3d, 0x5c, 0xb0, 0xc4, 0xf7, 0x4c, 0x74, 0xe6, 0xaa, 0x2b, 0xce, 0x98, 0xee, 0xc6, 0xae, 0x7c, + 0xcf, 0x45, 0x60, 0xbc, 0x83, 0x01, 0x51, 0xe3, 0x14, 0x23, 0xe5, 0x47, 0xde, 0xf6, 0xa5, 0x04, + 0xe8, 0x52, 0xf6, 0xd4, 0x5e, 0x75, 0xfb, 0x85, 0xdb, 0x88, 0x6b, 0x9a, 0x8e, 0xfb, 0x18, 0xd2, + 0x38, 0x15, 0x0f, 0x83, 0x4c, 0xd3, 0x4b, 0xe5, 0x95, 0x05, 0x6c, 0xb7, 0xec, 0xe8, 0xe9, 0x14, + 0xde, 0xd4, 0xab, 0x0c, 0xb2, 0x65, 0xf0, 0xda, 0x46, 0xae, 0xd6, 0x1f, 0x4f, 0x86, 0xd3, 0x74, + 0x6c, 0x6a, 0xa7, 0x73, 0x1c, 0x29, 0x22, 0xfe, 0x85, 0xbb, 0xfd, 0x6a, 0xa5, 0xf1, 0xce, 0x90, + 0x04, 0xb8, 0x86, 0xa5, 0x96, 0xac, 0x1c, 0x6f, 0xd3, 0x52, 0xe3, 0xaa, 0x46, 0x13, 0x81, 0x13, + 0x5e, 0x5e, 0x68, 0xb5, 0x6f, 0x52, 0xeb, 0x19, 0xbf, 0x21, 0x44, 0x28, 0xc3, 0x96, 0x83, 0xec, + 0xdb, 0x3d, 0x4e, 0xd4, 0xdf, 0xda, 0x6a, 0xf3, 0xa8, 0x00, 0xdb, 0xcf, 0xc9, 0xff, 0xd5, 0x04, + 0xc5, 0x47, 0x11, 0xc4, 0x84, 0xd2, 0xcd, 0x45, 0x25, 0xe7, 0x94, 0xae, 0x60, 0x83, 0xcd, 0x6a, + 0x8d, 0x27, 0xf3, 0x0e, 0xe7, 0x30, 0xf9, 0xd6, 0x7e, 0xbb, 0xa9, 0xd9, 0x3e, 0xc0, 0x63, 0x29, + 0xc9, 0x85, 0xac, 0x06, 0xe8, 0xbc, 0x3a, 0x7a, 0xb5, 0xf5, 0xeb, 0x9e, 0x24, 0x85, 0xe2, 0x0f, + 0xa6, 0xc3, 0x00, 0x88, 0xd3, 0x88, 0x85, 0xfb, 0x40, 0x5a, 0x9a, 0x97, 0xd7, 0xb4, 0x44, 0x84, + 0x4d, 0xba, 0xb2, 0x52, 0xc9, 0x91, 0xb5, 0x35, 0xe0, 0xb4, 0x13, 0x6d, 0x8b, 0x6d, 0xcb, 0x4e, + 0x4b, 0x90, 0xa1, 0xea, 0x20, 0x7d, 0xd0, 0xa5, 0x16, 0xb5, 0xde, 0xae, 0xb2, 0xad, 0x3c, 0x94, + 0x7b, 0xea, 0x4b, 0x22, 0xe0, 0xf8, 0x98, 0x00, 0x1e, 0x7a, 0xcf, 0x02, 0xa7, 0x8a, 0x04, 0x4b, + 0x98, 0xb0, 0x7d, 0xcd, 0x12, 0xbd, 0xfc, 0xdb, 0xd4, 0x93, 0xcb, 0xbd, 0xd5, 0x31, 0x7f, 0x4b, + 0x26, 0x0f, 0x45, 0xbd, 0xa1, 0x5e, 0x98, 0xad, 0x51, 0xeb, 0x48, 0x8f, 0xc9, 0xaf, 0x3b, 0xcd, + 0x34, 0xef, 0x62, 0x56, 0x19, 0x51, 0x1b, 0xcb, 0x64, 0xe6, 0xf7, 0x06, 0xd9, 0x8b, 0x0d, 0x28, + 0x11, 0xf7, 0xb5, 0x85, 0x93, 0x8a, 0x19, 0x33, 0xb1, 0xcc, 0xba, 0x67, 0xbe, 0x90, 0xda, 0x5d, + 0xf7, 0x9a, 0xd3, 0x55, 0xdd, 0x76, 0x50, 0xf9, 0x30, 0x14, 0x06, 0xdb, 0xd0, 0x41, 0x98, 0x94, + 0x8d, 0x6e, 0x08, 0x93, 0x3c, 0x2e, 0x20, 0xeb, 0x32, 0xce, 0x1b, 0xa5, 0xcf, 0x23, 0xbd, 0x9e, + 0x59, 0xa5, 0x7c, 0x03, 0x59, 0x7d, 0xb1, 0x10, 0xd4, 0x2d, 0xcd, 0xe3, 0x91, 0x3d, 0xc2, 0x4f, + 0x5e, 0x5b, 0xae, 0x6d, 0xaa, 0xa9, 0xa4, 0x1a, 0x55, 0x25, 0xc7, 0xb3, 0xe9, 0x88, 0xc5, 0x8e, + 0xb3, 0xc5, 0xe7, 0x21, 0x16, 0xeb, 0xda, 0xc9, 0x20, 0xff, 0x07, 0x7b, 0xe7, 0xf7, 0x5b, 0xca, + 0xda, 0xf7, 0xff, 0x7f, 0x66, 0x5b, 0x0d, 0xb6, 0x36, 0x59, 0x7b, 0x6b, 0xa3, 0xbd, 0x75, 0x1d, + 0x77, 0x2c, 0x24, 0xc3, 0x10, 0x94, 0x9e, 0x2c, 0x6d, 0x50, 0x24, 0x5a, 0xa4, 0x54, 0xf7, 0xff, + 0x80, 0x21, 0xf5, 0xa3, 0x3d, 0x31, 0x15, 0xa3, 0x43, 0xa2, 0x86, 0xa0, 0xf4, 0x18, 0x9b, 0x26, + 0x18, 0x82, 0xe2, 0xa4, 0x2a, 0x28, 0x4d, 0xda, 0x85, 0xb4, 0x5d, 0x5d, 0xfb, 0xdb, 0x75, 0xdf, + 0x77, 0x9e, 0xe7, 0x7e, 0x9e, 0xb5, 0x7b, 0xf0, 0x3d, 0xf9, 0x1e, 0x7c, 0xd3, 0xd7, 0x81, 0x54, + 0xaf, 0xb9, 0x06, 0x6f, 0x73, 0x5d, 0xd7, 0xe7, 0x1a, 0x9f, 0x1f, 0x5c, 0xd4, 0x43, 0xac, 0xe5, + 0xa0, 0xeb, 0xae, 0x08, 0xd4, 0xd9, 0x1f, 0x19, 0x1c, 0xfe, 0xf4, 0x78, 0x25, 0xc6, 0x3f, 0x96, + 0xab, 0x41, 0x33, 0x51, 0x41, 0xe3, 0x95, 0xda, 0x49, 0xa0, 0x29, 0x98, 0x22, 0x59, 0x36, 0xcf, + 0x35, 0xab, 0x7f, 0x6c, 0x6c, 0x74, 0x39, 0x89, 0xe1, 0xec, 0x1f, 0xc4, 0xd4, 0xb0, 0x6f, 0x3f, + 0xc1, 0xf8, 0xdf, 0x1a, 0x17, 0x97, 0xd2, 0xe8, 0xa1, 0x3a, 0x98, 0x36, 0x52, 0xdb, 0x77, 0x9a, + 0x1d, 0x8b, 0xf9, 0x8c, 0x3f, 0xbe, 0x2d, 0xa6, 0x72, 0x2d, 0xf3, 0x9d, 0xa4, 0xa3, 0xff, 0x1b, + 0x3f, 0x3b, 0xc5, 0x1b, 0x4a, 0x67, 0x95, 0x98, 0x0c, 0xfd, 0xe1, 0x00, 0xeb, 0x22, 0x14, 0xd8, + 0x3e, 0x4a, 0xa8, 0xc1, 0xed, 0x7a, 0x9c, 0xb3, 0x7f, 0x85, 0x88, 0xd6, 0xc6, 0x5f, 0x91, 0xa5, + 0x95, 0xa4, 0x56, 0x33, 0xb1, 0xb4, 0x4a, 0x08, 0x3d, 0x7b, 0x6e, 0xef, 0xc6, 0x72, 0x3a, 0x3b, + 0xbe, 0xd8, 0x16, 0xf3, 0xf4, 0xb8, 0x06, 0xd4, 0x5a, 0x02, 0xcb, 0x00, 0xac, 0x67, 0xb0, 0x24, + 0x76, 0x5f, 0x00, 0xd0, 0x55, 0x2b, 0x89, 0x81, 0x59, 0xba, 0x98, 0x00, 0x6b, 0x20, 0x42, 0x01, + 0x40, 0x5f, 0x17, 0x30, 0x6d, 0x3b, 0x49, 0xf3, 0x8a, 0x62, 0xb9, 0x2f, 0x07, 0x20, 0x9b, 0x3d, + 0xc0, 0xab, 0x0a, 0x60, 0x36, 0x68, 0xf1, 0x56, 0xbb, 0x66, 0xa9, 0x7d, 0x3a, 0x58, 0x93, 0xd8, + 0xbb, 0x72, 0x50, 0xc9, 0xb3, 0xe3, 0xca, 0xcf, 0x76, 0xb4, 0x05, 0xde, 0x7b, 0xe9, 0x24, 0x29, + 0xe8, 0x55, 0xcc, 0xe7, 0x78, 0xf6, 0xeb, 0x96, 0x52, 0xf2, 0xe5, 0x34, 0xab, 0xe3, 0x61, 0xb7, + 0x48, 0x00, 0xe4, 0x1f, 0x2e, 0x03, 0x65, 0x9c, 0x4a, 0x2b, 0x5a, 0x2b, 0xdd, 0x80, 0xc6, 0x11, + 0xf5, 0xa1, 0xc0, 0x06, 0x1f, 0x4f, 0x3f, 0xf2, 0x61, 0x3a, 0x83, 0x0b, 0x39, 0x49, 0xd8, 0xce, + 0xba, 0xa3, 0x9b, 0x36, 0xfc, 0x08, 0x83, 0x67, 0x6f, 0x9c, 0x62, 0x8a, 0x9c, 0xc0, 0x4a, 0xa8, + 0x97, 0x04, 0x25, 0x58, 0xbd, 0xcc, 0x82, 0xa2, 0x84, 0xc4, 0x6e, 0xaf, 0xe0, 0x02, 0x93, 0xf5, + 0x31, 0x5b, 0xe6, 0xc2, 0xa9, 0xf4, 0xfc, 0xc4, 0x0a, 0x23, 0x34, 0x31, 0x38, 0x41, 0xd8, 0x3a, + 0x9b, 0x01, 0x59, 0xb6, 0xde, 0xba, 0x03, 0x6b, 0x00, 0x0c, 0x13, 0x6b, 0x02, 0xe1, 0x02, 0x89, + 0x2d, 0x84, 0xba, 0x90, 0x0c, 0xaa, 0xc1, 0x7d, 0xb3, 0x44, 0x25, 0xfd, 0x11, 0x7f, 0x63, 0x0f, + 0x98, 0xaa, 0x4e, 0x4c, 0x6d, 0xf9, 0x7c, 0x3d, 0x22, 0x51, 0x3f, 0x5b, 0x91, 0x9c, 0xa0, 0x5a, + 0x45, 0x44, 0x40, 0xc3, 0xd1, 0x92, 0xab, 0x30, 0xcf, 0xdf, 0xf8, 0x8e, 0xaa, 0xdf, 0x50, 0xba, + 0xf0, 0x9d, 0x93, 0x76, 0x4f, 0xc5, 0x99, 0x6d, 0x27, 0xa1, 0x31, 0x63, 0xde, 0xd5, 0xa0, 0x4b, + 0x1c, 0xe4, 0x36, 0xbf, 0x5e, 0x79, 0x6f, 0xc4, 0xc9, 0x41, 0xea, 0x93, 0xc5, 0xa1, 0xec, 0x92, + 0x6a, 0x9f, 0x47, 0x88, 0x22, 0x58, 0x9e, 0x36, 0x15, 0xca, 0x3b, 0xad, 0xe3, 0xa4, 0xac, 0x8a, + 0x5e, 0xec, 0x89, 0x23, 0xc7, 0xd2, 0xd5, 0xa6, 0x38, 0x56, 0xff, 0xa0, 0x37, 0xf2, 0xe6, 0xfd, + 0xbf, 0xdd, 0xab, 0xce, 0xc3, 0xe1, 0x63, 0x48, 0xb5, 0x54, 0x9e, 0x62, 0xe2, 0x4c, 0x43, 0xba, + 0x41, 0x55, 0x36, 0x22, 0xb0, 0xe7, 0x69, 0xaf, 0x9c, 0x0e, 0x2a, 0x92, 0xb8, 0x14, 0x22, 0x1e, + 0x66, 0xea, 0x20, 0x59, 0x9d, 0x4f, 0x0d, 0xb7, 0x8c, 0x1c, 0xf9, 0x8a, 0xa2, 0x99, 0x91, 0xf6, + 0xc5, 0x75, 0xa5, 0x1f, 0x5e, 0x0a, 0xc5, 0x8e, 0x37, 0xfb, 0xcc, 0xd8, 0xf1, 0x0d, 0x2e, 0xe1, + 0xaa, 0x7d, 0xe8, 0x9d, 0x23, 0x78, 0xcc, 0x6d, 0xef, 0x3e, 0x55, 0x51, 0xf3, 0xd1, 0x68, 0xd3, + 0xbf, 0x84, 0x95, 0xa5, 0xa2, 0x20, 0xc7, 0x79, 0x8a, 0x08, 0x63, 0xee, 0x84, 0x40, 0x29, 0x0c, + 0xba, 0x8d, 0x55, 0xf0, 0xe9, 0x5f, 0x71, 0xef, 0x22, 0x96, 0xf2, 0xe9, 0xe6, 0x82, 0x65, 0x53, + 0x23, 0x27, 0x12, 0x0f, 0xea, 0x7b, 0xca, 0x6d, 0x7c, 0xf1, 0xd5, 0x33, 0x17, 0x9b, 0x88, 0x39, + 0xa5, 0x7e, 0x6a, 0x0d, 0xf7, 0x04, 0xfb, 0x95, 0x1e, 0xef, 0x6e, 0x9f, 0x58, 0x55, 0x85, 0x54, + 0xf2, 0x35, 0xc6, 0x19, 0x86, 0x16, 0x58, 0x3b, 0xae, 0x67, 0x95, 0x81, 0x6f, 0xad, 0x0e, 0x1a, + 0xe5, 0x0d, 0xed, 0x72, 0x6e, 0x6c, 0x68, 0x02, 0x2f, 0x2e, 0xc7, 0x28, 0x7f, 0xa0, 0xea, 0xd4, + 0x45, 0x2f, 0x42, 0x57, 0x34, 0x2e, 0x95, 0x9c, 0x13, 0xab, 0x6c, 0x59, 0x19, 0x43, 0x89, 0xd7, + 0x86, 0xc0, 0x22, 0x1c, 0x1a, 0x63, 0x77, 0xeb, 0xbd, 0xf0, 0x9c, 0x78, 0xa4, 0x86, 0xaa, 0xf7, + 0x67, 0xa3, 0xd3, 0xa7, 0x83, 0x07, 0x5b, 0x0c, 0x27, 0x3c, 0xa3, 0x9f, 0x3d, 0xcf, 0xe9, 0xf4, + 0x37, 0x94, 0x4e, 0x70, 0xc4, 0x76, 0x7c, 0xe1, 0x72, 0xdb, 0x56, 0xc9, 0x82, 0x9f, 0x89, 0x0f, + 0xfd, 0x17, 0xb1, 0x95, 0x58, 0x5b, 0xe6, 0xdb, 0xf4, 0x6b, 0x14, 0xfe, 0x90, 0x8f, 0x70, 0x38, + 0xf6, 0x6b, 0x9c, 0xc3, 0xb5, 0x5f, 0x13, 0x9c, 0xdc, 0xdd, 0xaf, 0x09, 0x2e, 0x6f, 0xf8, 0xc3, + 0xa9, 0xce, 0x4d, 0xeb, 0xe9, 0x09, 0x42, 0x36, 0x9e, 0xe8, 0xad, 0xc3, 0xc7, 0xc5, 0x4b, 0x43, + 0x53, 0xb5, 0x12, 0xc2, 0x94, 0xfe, 0x35, 0x99, 0xad, 0xb7, 0x59, 0xaf, 0x94, 0x10, 0xf3, 0x01, + 0x1c, 0x9a, 0x76, 0x98, 0xea, 0x12, 0x62, 0x3a, 0x8b, 0x7d, 0x23, 0xaa, 0x3c, 0x27, 0x98, 0x10, + 0x6b, 0x3d, 0xd1, 0xfe, 0x1d, 0x0a, 0x4f, 0x7e, 0xcf, 0x5c, 0x96, 0x63, 0xf5, 0x45, 0x6c, 0x0c, + 0x26, 0xb6, 0x88, 0x83, 0x19, 0x7d, 0x59, 0x7f, 0x26, 0xf6, 0x65, 0x1f, 0x6a, 0x5b, 0x96, 0x46, + 0xce, 0xd4, 0x9e, 0x3e, 0xe1, 0xfb, 0x4f, 0xc9, 0x13, 0x56, 0xcb, 0x43, 0x30, 0xef, 0x54, 0xfc, + 0x5e, 0x0a, 0xaa, 0xf2, 0xe2, 0xb3, 0x9d, 0x81, 0x0b, 0x1d, 0x14, 0x94, 0xde, 0xda, 0x05, 0x19, + 0x94, 0xf5, 0xeb, 0xa9, 0x23, 0x7d, 0x02, 0x7b, 0x30, 0x38, 0xfc, 0xf1, 0x94, 0xcb, 0xd9, 0x4b, + 0x25, 0x80, 0xa3, 0xef, 0x63, 0xe5, 0xb1, 0xec, 0xeb, 0x94, 0x67, 0xb1, 0xd5, 0x99, 0x53, 0x57, + 0xe7, 0x1f, 0x33, 0x33, 0x0e, 0x23, 0xec, 0xec, 0xf9, 0x51, 0xdf, 0x28, 0xad, 0x69, 0x8d, 0xf5, + 0xe5, 0xcb, 0x1f, 0x45, 0x84, 0x8f, 0x8e, 0x46, 0xf4, 0x83, 0x96, 0x8b, 0xc8, 0x52, 0xa4, 0x9e, + 0x4c, 0xe8, 0x65, 0xa0, 0x3f, 0x42, 0x0f, 0x3c, 0x67, 0x71, 0xfa, 0xc8, 0x12, 0xf1, 0xca, 0xd3, + 0x1b, 0x46, 0x3a, 0x6d, 0xda, 0x3a, 0x0d, 0xd0, 0xa6, 0xf1, 0xed, 0x5a, 0x32, 0xc2, 0x1f, 0x79, + 0x0b, 0x02, 0xc7, 0xb7, 0xa7, 0xe4, 0x9e, 0x19, 0x6f, 0x15, 0x00, 0xf3, 0xfd, 0x24, 0x71, 0x66, + 0xe6, 0x35, 0x59, 0x79, 0xee, 0x66, 0xbc, 0x58, 0x3c, 0xda, 0xa8, 0x3c, 0xd2, 0x06, 0xa5, 0xbf, + 0xf1, 0x1d, 0xd5, 0xbf, 0xa1, 0x34, 0xf9, 0xa3, 0xd6, 0x6d, 0xa4, 0x51, 0x72, 0x5d, 0x7a, 0x5f, + 0x7f, 0x7e, 0xf6, 0x07, 0x05, 0xf0, 0x20, 0x72, 0xc5, 0x9e, 0xcc, 0xf7, 0x42, 0xaa, 0x81, 0x1d, + 0x67, 0x9a, 0x7c, 0xd0, 0xfa, 0x47, 0xd6, 0xe0, 0x26, 0xc8, 0x14, 0x8d, 0xd5, 0x4f, 0x16, 0x89, + 0x65, 0x4e, 0x85, 0x70, 0x4d, 0x5f, 0x49, 0x2c, 0x4b, 0xa5, 0xde, 0xf9, 0x6e, 0x32, 0xe7, 0x64, + 0xa4, 0x55, 0x6e, 0x3b, 0x3e, 0xaf, 0x73, 0x1d, 0x21, 0x85, 0xcc, 0x4c, 0x4a, 0x46, 0x44, 0x0e, + 0x39, 0x51, 0xa0, 0x7e, 0xf6, 0x46, 0xd1, 0xbd, 0x1c, 0x44, 0xee, 0xb0, 0x74, 0xeb, 0x44, 0x92, + 0x05, 0x0c, 0xf9, 0x37, 0xd9, 0xa9, 0x61, 0xb6, 0x37, 0x6d, 0x11, 0x50, 0x30, 0x11, 0xe3, 0x1f, + 0xb6, 0xd6, 0xdc, 0xaf, 0x0b, 0xc2, 0x22, 0x50, 0xfa, 0x51, 0x72, 0xee, 0xf8, 0xcb, 0x20, 0x26, + 0x38, 0xa3, 0x5d, 0xec, 0xa0, 0x9e, 0x7e, 0x97, 0xc3, 0xf3, 0x1b, 0xb0, 0x12, 0xd0, 0xd2, 0x34, + 0xb8, 0xbc, 0x6b, 0x64, 0x64, 0xe4, 0xf5, 0x9c, 0xbd, 0x15, 0x6f, 0xf5, 0xb0, 0x75, 0xc9, 0xbb, + 0xed, 0x2c, 0x0a, 0x04, 0x91, 0xd3, 0x2c, 0x13, 0xf4, 0xaa, 0x47, 0xa6, 0x75, 0x3f, 0x8d, 0x7e, + 0x77, 0x54, 0x3b, 0xea, 0x49, 0x9d, 0x5b, 0xbf, 0xf8, 0x95, 0xdb, 0xd6, 0x53, 0x9c, 0x0b, 0xfb, + 0x5e, 0x56, 0xa5, 0x5f, 0x3b, 0xa4, 0x96, 0x40, 0xd2, 0x55, 0xef, 0x71, 0xe0, 0xaf, 0xcf, 0x92, + 0x35, 0x76, 0x6f, 0x61, 0xb9, 0x70, 0xe9, 0xb2, 0x27, 0x35, 0xca, 0x1f, 0x31, 0x65, 0x8e, 0x9b, + 0x44, 0x62, 0xde, 0x4d, 0x30, 0xc6, 0x2f, 0x0d, 0x37, 0x42, 0xac, 0x0d, 0x46, 0xbf, 0xcc, 0x28, + 0x6e, 0x30, 0xf8, 0x74, 0xdf, 0x38, 0xbd, 0xce, 0xcf, 0x67, 0xba, 0x6a, 0x83, 0x4a, 0x73, 0xdb, + 0x6f, 0x05, 0x21, 0x41, 0x2a, 0xb8, 0x28, 0x6e, 0xce, 0x69, 0xcb, 0x80, 0x3e, 0x48, 0xbf, 0x2c, + 0xc2, 0xe4, 0xbc, 0xc1, 0x81, 0xb4, 0x3e, 0x19, 0x1a, 0xfe, 0x1e, 0x39, 0x69, 0xb0, 0xce, 0x68, + 0x41, 0xd6, 0xdf, 0x54, 0x1a, 0xc7, 0xf7, 0xde, 0x50, 0x9a, 0x56, 0xfc, 0xda, 0x3e, 0x45, 0x3e, + 0x16, 0xac, 0x23, 0x73, 0xe4, 0xc0, 0x1a, 0x60, 0x10, 0x66, 0x5b, 0x5f, 0xc1, 0x30, 0x95, 0x90, + 0xa6, 0xf2, 0x0a, 0xf6, 0xee, 0x95, 0x84, 0x31, 0x3f, 0xbd, 0x7c, 0x55, 0xd6, 0x53, 0x79, 0x42, + 0x21, 0x39, 0xa9, 0x4d, 0x61, 0x34, 0xf1, 0x9e, 0xbb, 0x11, 0x4d, 0x5d, 0x16, 0xe3, 0x57, 0x29, + 0x9e, 0xfb, 0x6b, 0x3f, 0x53, 0x72, 0x6d, 0xf6, 0x1f, 0xcf, 0x06, 0xca, 0xc9, 0x54, 0x59, 0xb9, + 0x19, 0x12, 0x05, 0x18, 0x97, 0xac, 0x01, 0xba, 0x19, 0x49, 0x15, 0x21, 0x52, 0xd2, 0x38, 0x34, + 0xf8, 0x52, 0xb9, 0xdb, 0x91, 0x6a, 0x6e, 0x33, 0x31, 0xf0, 0xa4, 0xbe, 0x20, 0xb3, 0x5e, 0xa7, + 0xb3, 0xda, 0x5a, 0xb4, 0x8f, 0xb2, 0x0d, 0x18, 0x69, 0x28, 0xdb, 0xed, 0x12, 0x9f, 0xb8, 0x02, + 0xde, 0xdd, 0x8a, 0x7e, 0xb4, 0x1e, 0x4c, 0x84, 0x32, 0xfa, 0x80, 0x49, 0xa6, 0xb2, 0xc7, 0x1b, + 0x1c, 0x96, 0xef, 0x26, 0x59, 0xe4, 0x45, 0xbb, 0xcb, 0x45, 0x62, 0x17, 0x5b, 0x0b, 0xa1, 0xb1, + 0xeb, 0x44, 0x51, 0x30, 0x20, 0xb2, 0x1a, 0x56, 0xb4, 0xb3, 0x2c, 0x09, 0x56, 0x12, 0x5a, 0x1a, + 0xd8, 0x83, 0xe4, 0xac, 0x88, 0xf3, 0x50, 0xbe, 0x57, 0x9e, 0xac, 0x50, 0xb8, 0x79, 0x13, 0xa2, + 0xd2, 0x06, 0x65, 0x8d, 0x38, 0xcd, 0x6d, 0x6a, 0xc6, 0x31, 0x37, 0x7f, 0xc6, 0x91, 0x0e, 0x65, + 0x44, 0x1c, 0xcb, 0xcb, 0x0e, 0x97, 0x45, 0x43, 0xed, 0x16, 0xdd, 0x12, 0xbc, 0x0d, 0xa8, 0x70, + 0xf3, 0x74, 0x96, 0x09, 0xe7, 0x6f, 0xbe, 0x67, 0xb4, 0xf9, 0xca, 0x8c, 0xd3, 0x14, 0xdc, 0x47, + 0xc7, 0xda, 0xab, 0xb0, 0xb9, 0x5d, 0x2f, 0x4c, 0xce, 0x0b, 0x3c, 0xc3, 0x17, 0x37, 0x15, 0x3d, + 0x7a, 0xf8, 0xb5, 0x78, 0x6f, 0xdd, 0x31, 0x24, 0x80, 0xe9, 0x10, 0x9e, 0x9f, 0xee, 0x37, 0xe5, + 0x4f, 0xc5, 0x83, 0x9d, 0x3a, 0x43, 0x51, 0xc4, 0xf1, 0xfa, 0x77, 0x67, 0xd2, 0x6f, 0x92, 0x1d, + 0x20, 0xdd, 0x81, 0x6c, 0xec, 0xfc, 0x79, 0x45, 0x44, 0xa0, 0x37, 0x94, 0x66, 0x19, 0x39, 0xe8, + 0x85, 0xf6, 0xd2, 0x22, 0x88, 0x67, 0x82, 0x85, 0x26, 0x56, 0x03, 0xf1, 0x16, 0x91, 0x1e, 0x7a, + 0x26, 0xd7, 0x43, 0xe9, 0x45, 0xca, 0xde, 0x8e, 0x84, 0xbe, 0x54, 0x03, 0x4f, 0x5a, 0x5f, 0xbc, + 0x17, 0xb2, 0x09, 0x42, 0x58, 0x01, 0xee, 0x20, 0xe4, 0xe5, 0x76, 0x07, 0xce, 0xff, 0x96, 0x8a, + 0xf7, 0xd0, 0xa4, 0xe5, 0x4b, 0x9f, 0xf4, 0x14, 0x73, 0x92, 0x0c, 0x8a, 0x03, 0xf3, 0x9e, 0xf0, + 0xe3, 0x79, 0xd2, 0x7f, 0x93, 0x90, 0x6d, 0x91, 0x9b, 0x22, 0xf7, 0x86, 0x6f, 0xda, 0x38, 0x28, + 0x37, 0xe9, 0xcf, 0xb0, 0xee, 0xce, 0xb8, 0xa4, 0x94, 0xd7, 0x28, 0xf5, 0xfc, 0x31, 0xfc, 0x49, + 0x5b, 0x33, 0xf6, 0xee, 0xa0, 0xc2, 0x3f, 0xeb, 0x81, 0x6f, 0x78, 0xe9, 0x07, 0xe5, 0x21, 0x49, + 0x31, 0x02, 0x6f, 0xe0, 0x8d, 0xa5, 0xbb, 0x63, 0x91, 0xc2, 0xd4, 0x38, 0x4d, 0xf4, 0x78, 0x07, + 0xe3, 0x96, 0x88, 0xd6, 0xf1, 0x3a, 0x0a, 0xcf, 0x62, 0xc2, 0x81, 0x3c, 0x0b, 0x46, 0xf1, 0x2a, + 0x1b, 0x48, 0x35, 0x71, 0xb2, 0x6e, 0xb2, 0xde, 0x89, 0x1c, 0x74, 0xbc, 0xab, 0x11, 0x83, 0xdf, + 0xd8, 0x9f, 0xd8, 0x27, 0xbf, 0x37, 0x0e, 0x3a, 0x47, 0xd7, 0xb3, 0x8f, 0xd5, 0x9a, 0xa8, 0x3e, + 0xda, 0x8f, 0x3e, 0x2e, 0x55, 0xed, 0x83, 0x11, 0x9d, 0x57, 0x68, 0x9d, 0x12, 0xcf, 0xd6, 0x19, + 0x9a, 0x50, 0xe9, 0x6d, 0x4e, 0x2e, 0x26, 0xf1, 0x7e, 0xc0, 0x1a, 0x46, 0x5f, 0x0a, 0x19, 0x58, + 0x1f, 0xe2, 0x9f, 0xcc, 0x0e, 0x53, 0x72, 0xcc, 0xbb, 0x0a, 0xc7, 0xd2, 0x23, 0xfc, 0xeb, 0x18, + 0x79, 0x1e, 0xf7, 0xea, 0x8c, 0xd6, 0x41, 0x03, 0x69, 0x1b, 0x92, 0x5e, 0xc7, 0xe4, 0x39, 0x9f, + 0xbe, 0x1d, 0x5b, 0xe0, 0xa4, 0x7f, 0x84, 0x1e, 0x7f, 0x99, 0x62, 0x4f, 0x1d, 0x71, 0x4b, 0xbd, + 0x7c, 0xd0, 0xc9, 0x0c, 0x86, 0xb2, 0x63, 0xe4, 0x6e, 0xbe, 0x74, 0x1c, 0xbd, 0xe1, 0x5c, 0x1d, + 0xa7, 0x94, 0x99, 0xb3, 0x9a, 0x8a, 0xfe, 0xcc, 0xef, 0xfc, 0x9c, 0x35, 0x01, 0x0a, 0xbc, 0xa1, + 0x34, 0xc7, 0x08, 0x6a, 0xb5, 0x52, 0x91, 0x74, 0xfb, 0xa9, 0xf8, 0xc0, 0xb2, 0xbe, 0xda, 0xc4, + 0x93, 0x4a, 0xe5, 0x75, 0x22, 0x7d, 0x5d, 0x2b, 0x4a, 0x3b, 0x91, 0xe1, 0x6a, 0x66, 0x92, 0xd6, + 0xcf, 0x1d, 0xc4, 0x1a, 0x5e, 0x35, 0xdb, 0x1d, 0x19, 0x27, 0x21, 0xc8, 0x66, 0x31, 0x10, 0x70, + 0xb8, 0x15, 0x6b, 0xfe, 0x91, 0x8c, 0x5f, 0x14, 0x34, 0x77, 0xad, 0x71, 0xf3, 0xf4, 0xbf, 0x63, + 0x5e, 0x52, 0x35, 0x48, 0x1f, 0xd6, 0x4b, 0xfa, 0x69, 0x58, 0x6d, 0x78, 0x96, 0x9d, 0xf5, 0x04, + 0x98, 0x74, 0xc7, 0xb8, 0x22, 0x52, 0x0a, 0xa4, 0x66, 0x31, 0xab, 0xd4, 0x14, 0x6a, 0x71, 0x68, + 0xf7, 0x2f, 0xa8, 0xda, 0xc4, 0xb6, 0x6b, 0x80, 0xea, 0xf6, 0xfb, 0xf4, 0x1e, 0x9b, 0x18, 0x63, + 0x55, 0x58, 0x1b, 0x34, 0x1f, 0xe0, 0xa7, 0xb7, 0x4f, 0x55, 0xae, 0x79, 0x45, 0xca, 0x1c, 0x8e, + 0xf6, 0x3b, 0x07, 0x69, 0x77, 0xe6, 0x59, 0xd3, 0x56, 0x6f, 0x2d, 0xb2, 0x70, 0xa7, 0xa6, 0x29, + 0x85, 0x6f, 0xbd, 0xd3, 0x88, 0x24, 0x74, 0xbc, 0xb5, 0x76, 0x8f, 0x3e, 0x0a, 0xfa, 0x53, 0x3d, + 0xb2, 0x16, 0x86, 0xe4, 0xd2, 0xa6, 0x25, 0xe8, 0x5f, 0xa1, 0x9a, 0xce, 0xed, 0xcd, 0x0f, 0x71, + 0x95, 0xca, 0x7d, 0x17, 0xb1, 0x6d, 0x1f, 0x2e, 0x44, 0x5c, 0xb7, 0x70, 0x33, 0xd6, 0x51, 0xc1, + 0xf3, 0x4f, 0xd8, 0x7d, 0x6c, 0xf2, 0x02, 0xef, 0xfe, 0xf5, 0xe1, 0xd2, 0xf0, 0x7c, 0xdb, 0x3f, + 0xc3, 0x83, 0x07, 0xa9, 0x3a, 0x3e, 0xa2, 0x13, 0xdf, 0x43, 0x9e, 0x69, 0xf7, 0x81, 0xcd, 0x4b, + 0x18, 0xeb, 0xfa, 0x5d, 0x3f, 0x19, 0xcf, 0x77, 0xe4, 0x94, 0x2c, 0x97, 0xef, 0x9e, 0x03, 0x65, + 0x93, 0x51, 0x96, 0x4b, 0xa8, 0x2d, 0x0b, 0xed, 0xb3, 0x88, 0x57, 0x3d, 0x1c, 0x7b, 0xfa, 0x90, + 0x58, 0xac, 0xef, 0xc6, 0x44, 0xfa, 0xde, 0x75, 0x6d, 0x6f, 0x63, 0x83, 0x24, 0x2b, 0x24, 0x95, + 0x57, 0x43, 0x03, 0x3e, 0xf0, 0xae, 0x2a, 0xf1, 0x12, 0xfc, 0x73, 0x1e, 0x21, 0xec, 0x0d, 0xa5, + 0x97, 0x5f, 0xac, 0x88, 0x68, 0x33, 0x5e, 0x71, 0x4b, 0x97, 0xab, 0xc3, 0x27, 0xef, 0x25, 0x1a, + 0x86, 0x88, 0xc5, 0x34, 0x2f, 0x48, 0x30, 0x75, 0x03, 0x58, 0x39, 0x11, 0x86, 0xf9, 0x70, 0x62, + 0x71, 0x00, 0xa3, 0x13, 0x89, 0xd8, 0x5e, 0x53, 0x67, 0xc3, 0x50, 0x77, 0x33, 0x0b, 0xa9, 0x08, + 0x34, 0x2d, 0x26, 0xdc, 0x24, 0x5d, 0x58, 0xb8, 0x3c, 0xd1, 0x08, 0xb6, 0xe1, 0x4c, 0x5a, 0x1a, + 0x24, 0x5a, 0xa2, 0x88, 0xc0, 0x35, 0xd9, 0x0b, 0x0b, 0x91, 0xcd, 0xac, 0x6c, 0x48, 0xc4, 0xd2, + 0x1b, 0x90, 0x9b, 0x74, 0x10, 0x16, 0x8a, 0xa7, 0x80, 0x40, 0xab, 0x98, 0x4f, 0xdb, 0x51, 0x44, + 0x9d, 0xe0, 0x27, 0x91, 0x15, 0x11, 0x88, 0x22, 0x7b, 0x05, 0xf6, 0xd1, 0xc9, 0xa3, 0x5e, 0xbf, + 0x89, 0xb0, 0x3f, 0x8a, 0xd7, 0x09, 0x6c, 0xc0, 0xc2, 0x11, 0x26, 0xb3, 0xdc, 0x92, 0x92, 0x81, + 0xb6, 0xa6, 0xe7, 0x5f, 0x6b, 0x9b, 0x9d, 0xf5, 0x05, 0x7e, 0xdc, 0x35, 0x10, 0xf2, 0x6f, 0x30, + 0x12, 0x28, 0x3e, 0x8a, 0xc7, 0x4d, 0x7a, 0x25, 0x42, 0x24, 0x2e, 0x50, 0x24, 0xc0, 0x94, 0x36, + 0xdc, 0x17, 0x65, 0x6b, 0xdb, 0x37, 0x5d, 0x33, 0x95, 0xeb, 0x8a, 0x21, 0x0a, 0x7f, 0xda, 0xd3, + 0xb1, 0x71, 0x17, 0xc1, 0x5c, 0x47, 0x87, 0x8f, 0xc4, 0xe7, 0xe4, 0xcb, 0x82, 0x34, 0x25, 0x8b, + 0xdd, 0x64, 0x50, 0xfb, 0xcb, 0x66, 0xc6, 0x56, 0xb9, 0xd8, 0xab, 0xea, 0x77, 0xab, 0x33, 0xf1, + 0x8e, 0xdb, 0x5d, 0x43, 0x65, 0x11, 0xa7, 0xe8, 0xc7, 0x36, 0x0c, 0xed, 0x77, 0x8e, 0x3f, 0xdc, + 0xe0, 0x03, 0x3b, 0x9c, 0xa5, 0x45, 0xae, 0x9a, 0xb4, 0xa1, 0xc0, 0x84, 0x40, 0xaa, 0xfb, 0xd0, + 0x55, 0x86, 0x05, 0xf1, 0x2a, 0xd8, 0xf0, 0xcc, 0xb6, 0x85, 0x2d, 0x14, 0xba, 0x4c, 0xa5, 0xe8, + 0xde, 0x6d, 0x0f, 0xa2, 0xeb, 0xb6, 0x80, 0x5c, 0xa9, 0x71, 0xfa, 0x35, 0x20, 0x1c, 0xef, 0x55, + 0x9f, 0x76, 0x5a, 0x82, 0x1e, 0x30, 0xf0, 0xff, 0x9c, 0xb1, 0x89, 0xc8, 0xbe, 0xa1, 0xf4, 0xaa, + 0xa8, 0x2a, 0xac, 0x16, 0xee, 0x20, 0x47, 0x5a, 0x4e, 0xb5, 0x59, 0x03, 0xcb, 0xa0, 0xdd, 0xe7, + 0xfd, 0xc0, 0xaa, 0x0a, 0x05, 0xc1, 0x9c, 0xe4, 0x7e, 0x14, 0x5a, 0xab, 0x0a, 0x5e, 0x94, 0x4a, + 0xc7, 0x96, 0x3c, 0xad, 0x47, 0x9f, 0x49, 0x14, 0x96, 0xbb, 0xec, 0x25, 0xed, 0x54, 0xe5, 0x88, + 0xfa, 0xa3, 0xd4, 0x1a, 0x60, 0x69, 0xd0, 0x6b, 0xbc, 0x6e, 0x61, 0x7d, 0x4d, 0x93, 0x28, 0x62, + 0x7d, 0x62, 0xe5, 0xa3, 0xcd, 0x5e, 0x5b, 0x9e, 0x94, 0x9c, 0x23, 0x2a, 0xeb, 0x68, 0xf3, 0x51, + 0x6c, 0x04, 0x6a, 0x81, 0xae, 0xb6, 0xe2, 0x3f, 0x4c, 0xae, 0x55, 0x3d, 0xbe, 0x22, 0x0b, 0xe8, + 0xd2, 0xe6, 0x4d, 0xc7, 0x08, 0x55, 0x4b, 0xd5, 0x39, 0xbc, 0xc0, 0xeb, 0xfe, 0xe6, 0x50, 0xa3, + 0x11, 0x6f, 0x91, 0x82, 0x4a, 0x69, 0x34, 0xf1, 0xa4, 0xb5, 0xfb, 0x77, 0x31, 0xcb, 0x91, 0x53, + 0x0d, 0xa8, 0xdd, 0xdd, 0xf4, 0x54, 0x2a, 0x16, 0xa4, 0xe7, 0xd5, 0x2e, 0x07, 0xbe, 0xc0, 0xf2, + 0x56, 0xd3, 0xf2, 0x79, 0x97, 0xb3, 0xde, 0xa3, 0xba, 0x89, 0xeb, 0x84, 0xa2, 0xf4, 0x4c, 0x47, + 0x78, 0xc5, 0x4a, 0x20, 0x85, 0x09, 0xad, 0xc3, 0x9b, 0x11, 0xbf, 0xdb, 0xa4, 0x99, 0x2a, 0xfe, + 0xfe, 0xf2, 0x81, 0x0c, 0x74, 0x63, 0x3b, 0x82, 0xdd, 0x40, 0x56, 0xef, 0xbd, 0x46, 0x42, 0xa6, + 0xf5, 0x09, 0x79, 0xa0, 0xcd, 0x23, 0x09, 0xe3, 0x4e, 0x05, 0x33, 0x24, 0x0f, 0xd4, 0x82, 0x40, + 0x0a, 0xda, 0xff, 0xe6, 0x9d, 0x57, 0xe4, 0xaa, 0xf5, 0xb1, 0x46, 0xb2, 0x09, 0xc7, 0xc1, 0xed, + 0xd3, 0x0c, 0x96, 0x93, 0xd4, 0xd2, 0x06, 0x8d, 0xb5, 0x77, 0x98, 0xd5, 0x5a, 0xc3, 0x87, 0x53, + 0x20, 0x13, 0xb4, 0xa3, 0x2c, 0xc9, 0x35, 0x7e, 0xc2, 0x11, 0x6b, 0xf9, 0x45, 0x85, 0xb2, 0xac, + 0x7a, 0x04, 0x80, 0x9e, 0x23, 0xf4, 0xbd, 0x7c, 0xe2, 0xe5, 0x98, 0xf9, 0x5d, 0x44, 0xb3, 0x57, + 0xe9, 0x8d, 0x96, 0xcd, 0x95, 0x32, 0xe3, 0xa9, 0x0a, 0xd4, 0x48, 0x3f, 0xe7, 0x11, 0x2a, 0xbc, + 0xa1, 0xb4, 0xd8, 0x02, 0x75, 0xa8, 0x64, 0x1e, 0x4f, 0xf0, 0x88, 0x8d, 0x93, 0x65, 0xcb, 0x8a, + 0xb8, 0xf5, 0x94, 0xc4, 0xd6, 0x24, 0x72, 0x32, 0x54, 0x4d, 0x9e, 0x59, 0xf0, 0xb3, 0xd1, 0xa8, + 0x15, 0xd0, 0xc5, 0xa3, 0xc8, 0x64, 0x8a, 0x3e, 0x18, 0x29, 0xad, 0x6a, 0xd4, 0x2b, 0xe2, 0x44, + 0x82, 0xea, 0x9a, 0xaa, 0xc6, 0xa3, 0xc7, 0x39, 0x95, 0x28, 0xc6, 0xe2, 0xa4, 0xc5, 0xa3, 0x8b, + 0x94, 0x72, 0x0b, 0xfe, 0xc0, 0xfd, 0xfc, 0x84, 0x84, 0xc4, 0xbb, 0xf6, 0x5e, 0x46, 0x36, 0x80, + 0x9d, 0x64, 0xa0, 0xba, 0xb5, 0x1b, 0x52, 0x03, 0x95, 0xe7, 0xad, 0x4b, 0x81, 0x2e, 0x10, 0x67, + 0xed, 0x44, 0x11, 0x26, 0x50, 0xb8, 0x45, 0x56, 0xbf, 0x9f, 0x5a, 0x5f, 0x16, 0x0f, 0x40, 0x7f, + 0x80, 0x3d, 0x73, 0xef, 0x26, 0xa4, 0xdc, 0x3c, 0x52, 0x67, 0xac, 0xc5, 0x52, 0x83, 0xec, 0x62, + 0x52, 0x8a, 0xaf, 0xcd, 0x67, 0xa4, 0x2b, 0x97, 0x8b, 0x9f, 0x9d, 0x01, 0x29, 0xa8, 0xb1, 0x91, + 0xc4, 0xec, 0xb3, 0xd7, 0x09, 0x41, 0xe1, 0xb2, 0x07, 0x10, 0x4a, 0xc6, 0x63, 0x0f, 0x70, 0x50, + 0x14, 0xa1, 0xa8, 0x33, 0x3b, 0x1f, 0x26, 0x0a, 0x09, 0xd8, 0x91, 0xde, 0xb9, 0xac, 0x13, 0xc5, + 0x92, 0xc0, 0x0a, 0x2b, 0x28, 0x3c, 0x10, 0x66, 0x2f, 0xf3, 0xcb, 0x10, 0x7b, 0x89, 0x5f, 0x36, + 0xa4, 0x69, 0x7c, 0x82, 0xce, 0xd4, 0xb0, 0xaa, 0xbe, 0x96, 0x12, 0x10, 0xf8, 0xfa, 0x4a, 0xd6, + 0xc6, 0x48, 0x91, 0x63, 0x41, 0xb0, 0x7c, 0x41, 0xc0, 0xd3, 0xcb, 0xc9, 0x02, 0x10, 0x51, 0x93, + 0x79, 0x36, 0x84, 0x41, 0xcf, 0x7f, 0xc9, 0xd4, 0x69, 0xaf, 0x9b, 0xa5, 0xb4, 0x80, 0x4d, 0x7c, + 0x41, 0x04, 0x1c, 0x78, 0x37, 0xad, 0x65, 0x57, 0xbf, 0x22, 0x5a, 0x8e, 0xe3, 0x2b, 0xae, 0xc2, + 0xf8, 0x78, 0x16, 0xe4, 0xa5, 0xe8, 0x05, 0xa9, 0x50, 0xdc, 0x78, 0x04, 0xf3, 0xc1, 0xd7, 0x77, + 0x2b, 0xe1, 0xa9, 0x80, 0x72, 0x2e, 0x7a, 0x1d, 0xd2, 0x55, 0xee, 0xf4, 0x3f, 0xd7, 0xa0, 0x4c, + 0xbc, 0xa1, 0xf4, 0x86, 0x25, 0x25, 0x6b, 0x14, 0x07, 0x42, 0x8f, 0xdf, 0x1c, 0x78, 0xd8, 0x50, + 0x29, 0x8b, 0xb2, 0x63, 0x27, 0x32, 0x15, 0x9a, 0x13, 0xdc, 0xfc, 0x99, 0xda, 0x5c, 0xc7, 0xa0, + 0xa3, 0xef, 0xdd, 0xdf, 0xce, 0x10, 0xa8, 0x27, 0xbd, 0x7f, 0xf8, 0xd7, 0x8d, 0x1f, 0xfa, 0xb2, + 0xba, 0xdd, 0xc0, 0x7e, 0xb3, 0xc4, 0x1d, 0x27, 0x3c, 0xe0, 0xe8, 0x99, 0x01, 0x14, 0x5f, 0x52, + 0xfa, 0xb0, 0x79, 0x76, 0x85, 0x8f, 0x3e, 0x4f, 0x48, 0x0b, 0xcb, 0x1a, 0x8d, 0xbf, 0x69, 0x10, + 0x44, 0xba, 0xb4, 0x44, 0xcc, 0x3c, 0x97, 0x56, 0x6f, 0xbb, 0xeb, 0xcd, 0xd0, 0x98, 0x37, 0x27, + 0xaa, 0x6f, 0x1f, 0xb5, 0x94, 0xdf, 0x77, 0xdd, 0x35, 0x23, 0xf9, 0xc8, 0xe1, 0xea, 0x32, 0x34, + 0x3b, 0xcd, 0xfa, 0x63, 0x1a, 0xd9, 0xab, 0x4a, 0x1b, 0x71, 0x09, 0xf0, 0xb0, 0xee, 0xb8, 0x33, + 0xa0, 0xe9, 0xed, 0x6a, 0x48, 0xd1, 0x74, 0xf7, 0xd2, 0x0a, 0xdb, 0xa8, 0xbb, 0xa7, 0x52, 0x49, + 0x87, 0x0c, 0x8d, 0xd6, 0x36, 0x1f, 0xd8, 0x3b, 0xde, 0x9a, 0x8b, 0xef, 0xf0, 0xca, 0xc4, 0x89, + 0x51, 0xb5, 0x5e, 0x45, 0xa6, 0x58, 0xb4, 0x1d, 0x63, 0x11, 0x2e, 0x42, 0x3a, 0x9d, 0xe9, 0xe0, + 0xbd, 0xe9, 0xab, 0x41, 0x9e, 0x9e, 0x96, 0xd5, 0x3d, 0x31, 0x27, 0xd5, 0xd9, 0x12, 0xb6, 0xa3, + 0x98, 0x2f, 0xf6, 0x62, 0xe6, 0xa5, 0x03, 0x67, 0x06, 0x69, 0x0d, 0x40, 0xa3, 0x78, 0x47, 0x68, + 0x92, 0xd4, 0xcc, 0xa3, 0x51, 0xf3, 0xe8, 0x79, 0xac, 0xbb, 0xd0, 0xfa, 0x63, 0x18, 0x67, 0xa7, + 0x9e, 0xb8, 0xdb, 0x71, 0x8f, 0x06, 0xe2, 0x56, 0x67, 0x45, 0xc4, 0xee, 0x38, 0x33, 0x63, 0xa5, + 0x55, 0xe6, 0x78, 0xa4, 0x5b, 0x92, 0x5d, 0xba, 0x72, 0x7c, 0x75, 0x95, 0x9e, 0xe1, 0xf0, 0x52, + 0xbb, 0xa0, 0xfc, 0xfa, 0x14, 0x40, 0x43, 0xa7, 0xd5, 0x40, 0xcb, 0x72, 0x0f, 0xd3, 0xa6, 0xed, + 0x94, 0xa1, 0xf0, 0xfc, 0xda, 0xd0, 0x79, 0xb5, 0xe3, 0xe3, 0xed, 0x2a, 0x54, 0x45, 0xfe, 0x1f, + 0x66, 0xb7, 0x81, 0xc8, 0x6f, 0x7c, 0x87, 0x1f, 0xda, 0xf7, 0xf7, 0x7e, 0x2a, 0x45, 0x57, 0x9e, + 0x5b, 0x55, 0x2b, 0xaf, 0xeb, 0x8c, 0x8f, 0xbb, 0x37, 0x9e, 0xec, 0x47, 0x9d, 0x8d, 0x90, 0x92, + 0x61, 0xef, 0x76, 0xa0, 0x6c, 0x9f, 0x6c, 0x62, 0x94, 0x6d, 0x04, 0x0e, 0xe4, 0xd3, 0xe2, 0x3b, + 0x29, 0x59, 0xe5, 0xfe, 0x3d, 0xc4, 0xe1, 0x6d, 0x5d, 0x17, 0x96, 0x35, 0x31, 0x5f, 0x76, 0x5e, + 0x37, 0x4e, 0xd1, 0xc3, 0xbb, 0xf7, 0x7e, 0x66, 0x69, 0xb7, 0x47, 0x0a, 0xe4, 0xc1, 0xe4, 0x6c, + 0x05, 0xe4, 0xe8, 0x6e, 0xf0, 0x8f, 0xc9, 0x1a, 0x52, 0x88, 0xec, 0x7c, 0xf5, 0x14, 0x96, 0x79, + 0x57, 0x98, 0xdc, 0x50, 0xed, 0xaa, 0x95, 0xa2, 0xaa, 0x7c, 0x33, 0x2f, 0xba, 0x6a, 0x92, 0x98, + 0x0a, 0xa8, 0x84, 0x9f, 0xe8, 0x42, 0x47, 0x37, 0x33, 0x88, 0x7f, 0x7d, 0xdb, 0x4c, 0xca, 0x70, + 0x85, 0x7c, 0x2f, 0xe9, 0x83, 0xa9, 0x5c, 0x87, 0x5e, 0x21, 0x16, 0x44, 0x46, 0xbf, 0x17, 0xa8, + 0x1b, 0x66, 0x0d, 0xc6, 0x92, 0xc8, 0xdb, 0xf1, 0x84, 0x45, 0x5c, 0xbd, 0x50, 0x97, 0x11, 0x9a, + 0x0c, 0x94, 0x3a, 0xbe, 0x8d, 0x14, 0x65, 0xdf, 0xa0, 0x8a, 0xfe, 0xb1, 0x83, 0xa5, 0xf6, 0x4c, + 0x3c, 0x18, 0xb7, 0xb8, 0x77, 0x1d, 0x88, 0xcc, 0x51, 0x7d, 0x79, 0x3c, 0x68, 0x55, 0xbf, 0xb6, + 0x0c, 0xac, 0xaa, 0x73, 0xd0, 0x1c, 0xbf, 0x78, 0x1e, 0xef, 0x42, 0x77, 0x30, 0x75, 0x9e, 0xa7, + 0x4e, 0x66, 0xc1, 0x0d, 0x68, 0x4e, 0xce, 0x2a, 0x61, 0x4c, 0x3d, 0x53, 0x6b, 0xde, 0x7f, 0x5e, + 0x3d, 0x73, 0x77, 0xab, 0x65, 0x17, 0xfc, 0x7b, 0xd6, 0xb4, 0xf3, 0x65, 0xb8, 0x5c, 0x3f, 0x38, + 0x63, 0x9e, 0x94, 0x4d, 0x9b, 0x83, 0x58, 0x61, 0x3c, 0x91, 0x50, 0xbe, 0xff, 0xd8, 0x5e, 0x73, + 0xcf, 0x5c, 0xf6, 0x98, 0x21, 0x7a, 0x33, 0x31, 0xae, 0xb5, 0x37, 0xbc, 0x83, 0x88, 0xd9, 0x97, + 0xd2, 0xa6, 0x33, 0x5b, 0x8e, 0x69, 0xb9, 0x8d, 0x26, 0x84, 0xbf, 0xc5, 0xce, 0x18, 0x37, 0x45, + 0xae, 0x94, 0xca, 0x64, 0xee, 0x04, 0x7f, 0x8e, 0xf2, 0xea, 0xd2, 0xde, 0x50, 0x7a, 0x53, 0x56, + 0xc4, 0x47, 0x01, 0x7a, 0xc3, 0x7a, 0xf2, 0xc8, 0xd2, 0x98, 0x30, 0x43, 0x04, 0x98, 0x66, 0xb2, + 0x4c, 0xa8, 0x7d, 0x94, 0x60, 0x0a, 0x11, 0xfc, 0x53, 0x8c, 0xcb, 0x4f, 0x51, 0x03, 0x5c, 0xbe, + 0x77, 0x29, 0xc9, 0x85, 0xa0, 0x34, 0x79, 0xc8, 0x23, 0x58, 0x39, 0x7e, 0x59, 0xf3, 0xc8, 0x14, + 0x08, 0x10, 0x92, 0x38, 0xf2, 0xcd, 0x37, 0x51, 0x82, 0x8e, 0x68, 0xb3, 0xc4, 0xe5, 0x77, 0x15, + 0xc1, 0x07, 0x1b, 0xa1, 0xee, 0x4f, 0x6c, 0x44, 0x4e, 0xc2, 0xfb, 0x66, 0x9f, 0x08, 0x22, 0x69, + 0xdf, 0x44, 0x5a, 0x3e, 0xef, 0xd0, 0x13, 0x30, 0xee, 0x0a, 0x9a, 0x63, 0xb3, 0x63, 0x71, 0x66, + 0x00, 0x2f, 0x88, 0xf1, 0x99, 0x2f, 0x75, 0x89, 0x6e, 0xa4, 0x35, 0xe1, 0xea, 0xed, 0x8b, 0xe6, + 0xa2, 0x3a, 0x7a, 0xd1, 0xf4, 0xaa, 0xe3, 0x17, 0xcd, 0xac, 0x3a, 0xb2, 0x68, 0x17, 0xaa, 0x5f, + 0x5f, 0xb4, 0x9f, 0xaa, 0x93, 0x17, 0xed, 0x56, 0x75, 0xfa, 0xa2, 0x35, 0xe4, 0x2e, 0xc4, 0x35, + 0x44, 0xe3, 0xda, 0x10, 0x56, 0x65, 0x67, 0xe3, 0x8b, 0x35, 0xd4, 0x11, 0xf2, 0x8b, 0x68, 0x62, + 0xa9, 0xdc, 0xc8, 0x50, 0x77, 0xaf, 0x83, 0x6d, 0xa5, 0x50, 0xb1, 0x27, 0x0a, 0x4e, 0xfa, 0x6c, + 0x0d, 0x20, 0x08, 0x90, 0xc9, 0xf7, 0xce, 0x46, 0xcb, 0x08, 0x35, 0xbb, 0x54, 0xd1, 0x20, 0xea, + 0xa7, 0xa2, 0x4a, 0x7f, 0x14, 0x49, 0x8f, 0xa1, 0xdf, 0x47, 0xcc, 0x64, 0xd5, 0x2b, 0xdb, 0x3b, + 0x3f, 0xef, 0x77, 0x81, 0xaf, 0x47, 0xb5, 0x61, 0x4e, 0x72, 0x03, 0x17, 0x05, 0x3b, 0x42, 0xba, + 0x6c, 0x28, 0x33, 0x26, 0x28, 0xc3, 0xe4, 0xeb, 0x09, 0x38, 0x11, 0xd9, 0x10, 0xcd, 0x0a, 0x7d, + 0xd3, 0xc7, 0x05, 0x70, 0x62, 0x4c, 0xe4, 0xc4, 0xe7, 0xc8, 0x24, 0x84, 0x9f, 0x57, 0xb0, 0xb0, + 0x3a, 0x66, 0x8f, 0x63, 0x67, 0x96, 0x41, 0x5c, 0x11, 0xbc, 0xa3, 0x21, 0x06, 0x27, 0xdc, 0xf6, + 0x37, 0xa7, 0x35, 0xd5, 0x1c, 0x18, 0x8d, 0xfc, 0x7c, 0x3f, 0x96, 0x58, 0x7b, 0x43, 0x69, 0x55, + 0xdd, 0xd2, 0xbc, 0x7a, 0xd6, 0x6d, 0xbc, 0xae, 0x67, 0x89, 0x6a, 0xb7, 0xb7, 0xa2, 0x6f, 0x85, + 0x03, 0x29, 0x8e, 0x29, 0x88, 0x53, 0xd2, 0xc9, 0xdb, 0xbf, 0x44, 0x2c, 0x4c, 0xde, 0xc2, 0xd1, + 0xe3, 0x7f, 0xe6, 0x50, 0x0a, 0xc6, 0x3b, 0x85, 0x87, 0x48, 0xad, 0x0f, 0x1d, 0x54, 0xe1, 0xfc, + 0x8e, 0xa7, 0x72, 0x2c, 0x62, 0x9d, 0xda, 0x1d, 0x4f, 0xb5, 0xdb, 0x0a, 0x3a, 0x33, 0x64, 0xdc, + 0x69, 0x23, 0xe5, 0xd2, 0xe5, 0x55, 0x5a, 0x86, 0x62, 0x7f, 0x87, 0x5e, 0xd8, 0x0e, 0xa8, 0xe8, + 0xfa, 0x4e, 0x22, 0xa0, 0x35, 0x7c, 0x75, 0x8e, 0x73, 0x0e, 0xd7, 0x8b, 0xfe, 0xb9, 0xbc, 0x5d, + 0x13, 0x8d, 0x6e, 0x3b, 0xfd, 0xd0, 0x41, 0x0e, 0x0a, 0xdd, 0xe4, 0xa3, 0xf8, 0x6d, 0x51, 0xc6, + 0xbe, 0x3d, 0x69, 0x4a, 0x05, 0x61, 0x39, 0xcb, 0x20, 0x14, 0xcf, 0x4e, 0x8c, 0xaf, 0x0d, 0x48, + 0x79, 0xbd, 0x17, 0x9c, 0x13, 0x73, 0x76, 0x9a, 0x89, 0x3b, 0xdc, 0xb8, 0x59, 0x63, 0x78, 0x62, + 0x33, 0x23, 0xdd, 0xe3, 0xf9, 0x4b, 0x2c, 0x6c, 0xef, 0xdc, 0xe6, 0xcd, 0xa6, 0x53, 0x84, 0x4b, + 0x17, 0xf8, 0xe7, 0xba, 0x14, 0xe2, 0x99, 0xc4, 0x31, 0xc6, 0xbe, 0xbe, 0xf4, 0xd2, 0x3c, 0x44, + 0x78, 0xd3, 0xcc, 0xc5, 0xbe, 0xf7, 0x01, 0xd8, 0xd3, 0x5c, 0x61, 0x6c, 0xa7, 0x21, 0x3c, 0x9b, + 0x7c, 0xb0, 0xcc, 0x52, 0x7f, 0x6c, 0x74, 0xe5, 0x13, 0x9d, 0xef, 0x99, 0x4c, 0x29, 0x9c, 0xe2, + 0x6b, 0x83, 0x28, 0x0c, 0x6b, 0x0c, 0x4d, 0xcc, 0xbb, 0x25, 0xa8, 0x4c, 0x5f, 0x6e, 0x5e, 0xf8, + 0x88, 0xda, 0xf0, 0x32, 0x0e, 0xce, 0xb1, 0x1f, 0x78, 0x10, 0x2c, 0xe2, 0xad, 0x5f, 0x23, 0xf4, + 0xbe, 0xc7, 0x93, 0x32, 0xce, 0xeb, 0x3c, 0x09, 0xb5, 0xf8, 0x75, 0xe0, 0x05, 0xf2, 0x82, 0x5b, + 0x67, 0x80, 0x22, 0xf6, 0xd7, 0x03, 0x1a, 0x5d, 0x4d, 0xde, 0xa7, 0xba, 0xe0, 0xd7, 0xa1, 0x01, + 0xb4, 0x1f, 0xd7, 0x1e, 0xe2, 0xf6, 0x59, 0x9e, 0x8c, 0x69, 0x7f, 0x8e, 0xa7, 0x23, 0xd8, 0x6f, + 0x28, 0xad, 0x61, 0x87, 0x8e, 0x83, 0x99, 0x9a, 0x5a, 0xaf, 0xc8, 0xd5, 0x3a, 0x08, 0x3c, 0xce, + 0x6e, 0xd8, 0x0e, 0x29, 0x59, 0x82, 0x17, 0x54, 0x7f, 0xc4, 0x5f, 0x96, 0xa4, 0x07, 0x49, 0xd5, + 0x55, 0xe0, 0x37, 0x98, 0x37, 0x6c, 0xa6, 0x72, 0xf1, 0x18, 0xa1, 0x2f, 0x63, 0xd7, 0x8d, 0xa7, + 0x42, 0xd3, 0x58, 0x7f, 0xcc, 0x68, 0x9a, 0xa1, 0x72, 0x0c, 0xee, 0x9b, 0xb0, 0xce, 0xc9, 0xbf, + 0x13, 0x28, 0x06, 0x85, 0xbe, 0xc0, 0xe6, 0x77, 0xbc, 0x72, 0xbc, 0x5a, 0xdd, 0xf6, 0xbb, 0x63, + 0x45, 0xb1, 0xfb, 0xa6, 0x66, 0x49, 0x6d, 0x1f, 0xdd, 0x45, 0x50, 0xcb, 0xea, 0x5d, 0xf3, 0xeb, + 0x59, 0x0b, 0xad, 0xc1, 0xbc, 0xde, 0xc9, 0x7d, 0xc4, 0x6c, 0x48, 0x2f, 0x4b, 0x4f, 0xbd, 0x4b, + 0x01, 0x96, 0xc1, 0xbb, 0x9c, 0xe5, 0xa8, 0x84, 0xda, 0xf2, 0xd9, 0xe9, 0xe3, 0x56, 0xdd, 0xe1, + 0xeb, 0xd0, 0x54, 0xc3, 0xab, 0xe7, 0x93, 0x30, 0xda, 0x74, 0xa2, 0x50, 0x0d, 0x6c, 0x3d, 0x69, + 0xc3, 0x42, 0xc6, 0x20, 0x5b, 0xb5, 0x79, 0xa6, 0x63, 0xf3, 0x28, 0xd9, 0xa2, 0x8f, 0x76, 0x0c, + 0x99, 0xea, 0x9d, 0xda, 0xf1, 0xa4, 0x8f, 0xec, 0x86, 0xc9, 0x8b, 0x3b, 0xeb, 0x43, 0x39, 0x99, + 0x97, 0x74, 0xcf, 0x51, 0x06, 0x51, 0xef, 0x6a, 0x90, 0xfd, 0x4c, 0xf1, 0xf3, 0x76, 0x46, 0xce, + 0xc0, 0xc0, 0x72, 0xea, 0x36, 0x4b, 0x53, 0xea, 0x5e, 0x71, 0x2f, 0xa2, 0xa9, 0xd1, 0x89, 0x62, + 0xbb, 0x77, 0x53, 0xe7, 0xf2, 0xcc, 0x0a, 0x26, 0x47, 0x7d, 0xda, 0x8a, 0xa5, 0xdd, 0x17, 0x00, + 0x60, 0x38, 0x19, 0xe5, 0xb2, 0xd2, 0x96, 0x7f, 0x2b, 0x15, 0xc3, 0x2e, 0xd8, 0xf3, 0xb9, 0x97, + 0x61, 0x7f, 0xa8, 0x7c, 0xf1, 0x13, 0xca, 0x4c, 0x14, 0x09, 0x4c, 0x33, 0xda, 0x56, 0x26, 0x58, + 0x7a, 0xc0, 0x3f, 0x9d, 0x29, 0xb1, 0xd7, 0x1e, 0x78, 0xf3, 0x82, 0x45, 0xbd, 0xc7, 0x10, 0x33, + 0xe5, 0x61, 0x84, 0x35, 0xb5, 0x68, 0x03, 0xd6, 0xc6, 0x55, 0xee, 0x9f, 0xef, 0x5d, 0xe1, 0x8c, + 0xbf, 0x57, 0xba, 0x9b, 0xd0, 0x70, 0x3c, 0xce, 0x3a, 0x53, 0x22, 0xf3, 0x2b, 0x96, 0x4d, 0xfa, + 0x5a, 0x8b, 0x19, 0x93, 0x28, 0x68, 0x6a, 0xef, 0xae, 0xf7, 0x89, 0x67, 0xe2, 0xf5, 0x48, 0x58, + 0x47, 0xbd, 0xd5, 0xf9, 0x88, 0x3f, 0x90, 0x68, 0x3f, 0x6e, 0xc5, 0x7e, 0x48, 0x6b, 0xd2, 0x74, + 0x06, 0xe5, 0xd5, 0x88, 0x1e, 0xdc, 0x6d, 0xec, 0x23, 0x98, 0x34, 0x3d, 0x20, 0x64, 0x53, 0x5d, + 0x12, 0x46, 0xee, 0x04, 0x91, 0xf3, 0xfa, 0x1a, 0xd1, 0x35, 0x9a, 0x8d, 0x25, 0xb3, 0x24, 0x34, + 0x48, 0xda, 0x27, 0x2a, 0x9a, 0xdd, 0xf3, 0x75, 0x0c, 0xf2, 0xa7, 0xf6, 0x78, 0x3a, 0x77, 0xe2, + 0xf5, 0x87, 0x73, 0x0f, 0x5b, 0x43, 0xa3, 0xf3, 0x88, 0x68, 0x01, 0x33, 0x7f, 0x26, 0x61, 0x72, + 0x9f, 0xc2, 0xc3, 0xdc, 0x86, 0x78, 0x28, 0x29, 0x00, 0x8d, 0x69, 0x93, 0xcd, 0x32, 0x0c, 0xeb, + 0xcb, 0x5c, 0x07, 0x4e, 0x0b, 0xb5, 0xa1, 0x4d, 0x54, 0x33, 0x8d, 0x5c, 0xc5, 0x84, 0xff, 0xd5, + 0x37, 0x2e, 0x7e, 0x88, 0xce, 0x98, 0xa3, 0x1d, 0xfd, 0xb3, 0xc4, 0x42, 0x9c, 0x77, 0x0c, 0x42, + 0xd3, 0xb1, 0x26, 0x18, 0x5f, 0x0f, 0x30, 0x78, 0xfc, 0x41, 0xa5, 0x93, 0xb1, 0x4e, 0xb6, 0x68, + 0x26, 0x69, 0xb2, 0x1d, 0x78, 0xba, 0x57, 0x22, 0x46, 0x4a, 0xb3, 0x02, 0x4b, 0x05, 0x50, 0xc5, + 0xdd, 0xe2, 0xe1, 0x4e, 0xdf, 0x60, 0xcf, 0x16, 0xaf, 0xb4, 0x66, 0xb3, 0x75, 0xff, 0xa5, 0xb8, + 0x03, 0xfe, 0xa5, 0x88, 0x98, 0x37, 0x98, 0x93, 0x45, 0x4b, 0xd7, 0x4d, 0x30, 0x65, 0x82, 0x68, + 0x62, 0xa6, 0xe1, 0x9d, 0xa3, 0x28, 0xc8, 0x23, 0xa4, 0x63, 0x87, 0xd2, 0x37, 0x01, 0xcd, 0x71, + 0x5f, 0x56, 0xb9, 0x7e, 0xe2, 0xd5, 0x97, 0x66, 0x3b, 0x5d, 0x41, 0xa9, 0x01, 0x2f, 0x3e, 0x36, + 0x77, 0x3d, 0x4d, 0xe6, 0x83, 0x53, 0xe0, 0x96, 0x03, 0x20, 0xef, 0x36, 0x28, 0xcb, 0x79, 0x17, + 0x9f, 0x0e, 0xa2, 0x5d, 0xad, 0x5c, 0x6d, 0xf9, 0x79, 0xf7, 0x09, 0x21, 0xcc, 0x37, 0xae, 0x69, + 0x3d, 0xa0, 0xf3, 0xab, 0x3f, 0x1c, 0x54, 0x4a, 0x89, 0x47, 0x85, 0xce, 0x87, 0x85, 0x2c, 0xca, + 0x32, 0x95, 0x76, 0xe9, 0xdc, 0x0c, 0xd6, 0x04, 0xfb, 0xee, 0x34, 0xdd, 0x42, 0xcc, 0x2a, 0x29, + 0xae, 0xf4, 0x4b, 0x1a, 0xa3, 0x6e, 0xec, 0xfe, 0xb5, 0x0a, 0x08, 0xf1, 0x03, 0xdc, 0x50, 0xc0, + 0xe5, 0x53, 0xdd, 0xd0, 0x97, 0x58, 0x66, 0x79, 0x22, 0xc4, 0x44, 0xe5, 0x29, 0x3b, 0xe5, 0x6b, + 0x52, 0x89, 0x06, 0x51, 0xc3, 0x3e, 0x7b, 0xa0, 0x2c, 0x55, 0xcb, 0x33, 0xc6, 0xcf, 0x29, 0x9a, + 0xc8, 0xa0, 0x59, 0x9f, 0x14, 0x41, 0xc7, 0x97, 0xd1, 0x22, 0xfb, 0xcf, 0x48, 0x97, 0x50, 0x78, + 0x5a, 0xbf, 0xe2, 0x81, 0xfd, 0x49, 0x3d, 0x27, 0x25, 0x5c, 0xa9, 0x0f, 0xda, 0x2a, 0x5e, 0x47, + 0xa5, 0xbc, 0x0e, 0x26, 0x66, 0xd5, 0x36, 0xfb, 0x46, 0xe0, 0xc0, 0xbc, 0x15, 0x00, 0x9d, 0xae, + 0x63, 0x25, 0xd7, 0x31, 0x91, 0xfb, 0xa5, 0x76, 0xbc, 0x46, 0xe1, 0xae, 0x5b, 0x03, 0x06, 0x01, + 0x50, 0xd6, 0x4b, 0xe6, 0xed, 0x0f, 0x64, 0xf1, 0xc4, 0xb6, 0x43, 0xde, 0x14, 0x00, 0xae, 0xee, + 0x54, 0x5b, 0xf2, 0x9f, 0xa2, 0x05, 0xc7, 0x35, 0x9c, 0x66, 0x0b, 0x10, 0x86, 0x5c, 0x6c, 0xfd, + 0xd2, 0x5d, 0x7c, 0x04, 0x05, 0x81, 0x79, 0xc5, 0x86, 0x2f, 0xc1, 0xa6, 0x49, 0xed, 0xc4, 0x09, + 0x7b, 0x74, 0xee, 0xe5, 0xfe, 0x96, 0x6b, 0xfe, 0x92, 0x5a, 0x30, 0x80, 0xfd, 0x01, 0x27, 0x67, + 0x63, 0x22, 0x09, 0xb7, 0x7c, 0x69, 0x60, 0xaa, 0xf4, 0x10, 0xd1, 0xd0, 0xad, 0x67, 0xb4, 0x3e, + 0x26, 0x0d, 0xd1, 0xf1, 0xf7, 0xcf, 0x8e, 0xfe, 0x90, 0x53, 0xf1, 0x1d, 0xde, 0x14, 0xdc, 0xb7, + 0xc1, 0x4d, 0xe3, 0xfe, 0xf1, 0x75, 0xc6, 0x68, 0x84, 0x2a, 0x39, 0x4d, 0x75, 0x90, 0x98, 0xd7, + 0x2a, 0x47, 0x09, 0xe4, 0xc9, 0xe3, 0x8a, 0xa6, 0x0b, 0x07, 0xfb, 0x78, 0xe1, 0xb7, 0x0b, 0xdf, + 0x23, 0xfd, 0xc1, 0xd6, 0x13, 0x25, 0xa8, 0xd6, 0x2f, 0x38, 0x7d, 0xa5, 0xb6, 0xf9, 0xb3, 0xd2, + 0xb0, 0xe8, 0x0d, 0xa5, 0xf7, 0x3e, 0x7a, 0x30, 0x1a, 0x63, 0x15, 0xb4, 0x06, 0x3a, 0x14, 0x97, + 0x2e, 0xd0, 0xc9, 0xab, 0x4e, 0xbe, 0xe3, 0x0f, 0x7f, 0x96, 0x2a, 0xa9, 0x85, 0x48, 0x09, 0x37, + 0x8b, 0x00, 0x64, 0x1b, 0xd5, 0x55, 0xad, 0x88, 0x3a, 0x2f, 0x8b, 0xc2, 0x7b, 0xa6, 0xaa, 0x6e, + 0x9c, 0x0d, 0xc9, 0x22, 0xc8, 0x9e, 0x5a, 0x2a, 0x24, 0x36, 0xab, 0x66, 0x7c, 0xf3, 0x42, 0x79, + 0x64, 0xc0, 0x3f, 0x65, 0x6b, 0xf2, 0x96, 0x49, 0x50, 0xfb, 0x92, 0x0e, 0x50, 0x8f, 0xf4, 0x90, + 0xc9, 0x24, 0xc1, 0x6f, 0xe3, 0x74, 0xad, 0xe3, 0x79, 0xa8, 0xf9, 0x6c, 0x3f, 0xc1, 0x18, 0x60, + 0xc4, 0x9e, 0x10, 0xad, 0x7b, 0xa2, 0x27, 0x6b, 0x02, 0x7e, 0x90, 0x3b, 0x2f, 0xbd, 0x82, 0xa9, + 0x32, 0x53, 0x3b, 0x9d, 0x6d, 0xd4, 0xbc, 0x7e, 0x95, 0x6e, 0x67, 0xd2, 0x7f, 0x3a, 0xb8, 0xf2, + 0x7b, 0x4d, 0x3a, 0x4f, 0x9c, 0x46, 0x63, 0x5f, 0x85, 0xba, 0x89, 0xb6, 0xc7, 0xde, 0x1b, 0xf2, + 0x00, 0x7f, 0x9f, 0x21, 0x62, 0x0b, 0x6f, 0xb3, 0x2b, 0xa0, 0xb5, 0x5e, 0xa7, 0x1c, 0x6d, 0x1d, + 0xaa, 0x1b, 0xe8, 0xe9, 0xcb, 0xab, 0xb9, 0x1e, 0x1b, 0x19, 0xf6, 0x76, 0x9d, 0xab, 0x21, 0xd6, + 0xa5, 0xcd, 0x8e, 0x4a, 0x0b, 0xfb, 0xfd, 0xac, 0x41, 0xec, 0x3f, 0x96, 0xbf, 0xd8, 0x7c, 0xe7, + 0x01, 0x63, 0x39, 0x45, 0x1a, 0x08, 0x72, 0x55, 0x6f, 0xa0, 0x54, 0xf2, 0x5b, 0x72, 0xda, 0x88, + 0x9e, 0xf1, 0x81, 0xe5, 0xf8, 0xd2, 0xd7, 0x08, 0x1a, 0x44, 0x57, 0xaa, 0x9b, 0x39, 0x49, 0x27, + 0x92, 0xea, 0xe6, 0x29, 0xaa, 0x1e, 0x7f, 0xb9, 0x4e, 0x03, 0xe2, 0xb4, 0x91, 0xb8, 0xbf, 0x83, + 0x0d, 0xf5, 0x33, 0x4e, 0xfc, 0xf7, 0xec, 0xd4, 0x60, 0x4d, 0x3c, 0x61, 0xb0, 0xb3, 0x5a, 0xa8, + 0x0a, 0x71, 0x3d, 0x47, 0x70, 0xe0, 0xbf, 0xc6, 0x1a, 0xe8, 0xdd, 0x17, 0x0c, 0xb8, 0x22, 0x20, + 0x75, 0xc9, 0x66, 0x0f, 0xcb, 0xa6, 0x85, 0x93, 0x00, 0x27, 0x67, 0xb0, 0xfb, 0x9b, 0xd8, 0x51, + 0x9c, 0xf4, 0x73, 0x1e, 0x21, 0xe9, 0x1b, 0x4a, 0x0b, 0xb9, 0x96, 0x72, 0x2b, 0xdd, 0xe7, 0x1a, + 0x8d, 0x27, 0xe8, 0xa5, 0x31, 0x25, 0xe2, 0x5a, 0x8f, 0x8d, 0x74, 0xd0, 0x32, 0x53, 0xeb, 0x45, + 0x07, 0xaa, 0x4d, 0x5c, 0xf5, 0xd5, 0x8d, 0xb1, 0x7f, 0x1b, 0xa5, 0xec, 0x79, 0x31, 0x1f, 0x97, + 0x0b, 0xa0, 0xa6, 0xb1, 0x9b, 0xd4, 0x46, 0xdc, 0xd4, 0x7c, 0xdb, 0xa4, 0x74, 0xea, 0x0d, 0xa5, + 0xa3, 0xae, 0xfc, 0xb1, 0x94, 0x72, 0x76, 0x25, 0xb1, 0x0e, 0x44, 0xa7, 0x8c, 0x4f, 0xab, 0xd8, + 0x8f, 0x6c, 0x7b, 0xea, 0x84, 0xe5, 0xd5, 0xb8, 0xbd, 0xb7, 0x0c, 0xe0, 0x58, 0xc8, 0x35, 0x78, + 0x0a, 0x72, 0xce, 0x74, 0xb3, 0x93, 0xc4, 0x4c, 0x77, 0xb8, 0x29, 0xf4, 0x9c, 0xa4, 0x57, 0x73, + 0x5f, 0x9d, 0xfe, 0x70, 0xc3, 0x04, 0xd5, 0xa6, 0x7b, 0x7f, 0x3e, 0xbc, 0xee, 0x9c, 0x31, 0xcb, + 0x96, 0x9e, 0xfa, 0x87, 0x91, 0x2e, 0x0a, 0xfc, 0x91, 0x7a, 0x8f, 0x0f, 0x7e, 0xe7, 0x9d, 0x77, + 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, + 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0xf9, + 0xff, 0x93, 0x1f, 0xbf, 0x07, 0xff, 0xdf, 0x79, 0x34, 0xf2, 0x09, 0xb2, 0xec, 0xef, 0x3d, 0x65, + 0x48, 0x3f, 0x7c, 0x33, 0xe3, 0xe2, 0xa9, 0xd5, 0xff, 0x81, 0x4b, 0x44, 0x10, 0x6a, 0xc8, 0xc1, + 0x8f, 0xe6, 0xc9, 0x7c, 0x04, 0x66, 0x83, 0x15, 0xc4, 0x55, 0x5b, 0x53, 0x06, 0xe1, 0x9b, 0x31, + 0x37, 0x3c, 0x46, 0x80, 0xf2, 0xc6, 0x08, 0xca, 0xdc, 0xe3, 0xed, 0xb4, 0x5a, 0x9c, 0x8c, 0x2f, + 0xe5, 0x6a, 0xf6, 0xd3, 0x1c, 0x51, 0x73, 0xfe, 0x23, 0x81, 0x2a, 0x61, 0x39, 0x51, 0x00, 0x8f, + 0x2e, 0x16, 0x64, 0x55, 0x9f, 0xab, 0x23, 0xf5, 0xb6, 0xab, 0x01, 0xee, 0x11, 0x4f, 0xba, 0x47, + 0x11, 0x78, 0x3a, 0x5a, 0x19, 0x88, 0xa9, 0x71, 0x94, 0x77, 0x7b, 0x21, 0x91, 0xed, 0xac, 0x7b, + 0x4d, 0x53, 0x81, 0x6f, 0xa6, 0x52, 0x36, 0xec, 0xe7, 0x41, 0xde, 0x40, 0x98, 0x36, 0xb3, 0x37, + 0x70, 0x39, 0x85, 0x25, 0xab, 0x0c, 0x5a, 0x77, 0x6e, 0xe3, 0xf2, 0x08, 0x10, 0x0f, 0xcd, 0x55, + 0x21, 0x6c, 0x08, 0x04, 0x58, 0x45, 0xa4, 0x16, 0xd6, 0x44, 0x0c, 0xa1, 0xf6, 0xd9, 0x67, 0xdc, + 0xbf, 0x1c, 0xae, 0xd9, 0x1a, 0x4d, 0x88, 0xab, 0xf4, 0x42, 0xb2, 0x96, 0x3d, 0xd0, 0x65, 0xb5, + 0x2b, 0x48, 0x2e, 0xe9, 0x8c, 0xba, 0xa7, 0x62, 0x19, 0x3e, 0x24, 0x83, 0x79, 0x14, 0xdb, 0x43, + 0x79, 0xd7, 0xb5, 0x05, 0x28, 0xda, 0x20, 0x28, 0xc3, 0xdd, 0x91, 0xef, 0x49, 0x9c, 0x6c, 0x55, + 0x46, 0xda, 0xb2, 0x9c, 0x19, 0x60, 0x3a, 0xa6, 0xbe, 0x60, 0x41, 0xa6, 0x39, 0x7d, 0xd2, 0x84, + 0x08, 0xe9, 0x9e, 0x26, 0x02, 0x5b, 0xc4, 0x11, 0xc1, 0x49, 0x98, 0xc2, 0xc1, 0x65, 0x99, 0xc9, + 0x81, 0x23, 0x3c, 0x7f, 0xd9, 0xe0, 0x79, 0xdb, 0x3d, 0x28, 0xb9, 0x33, 0x57, 0x83, 0x0a, 0xbe, + 0x47, 0xa3, 0x90, 0x50, 0xcf, 0x15, 0x8b, 0x84, 0x59, 0xb1, 0xca, 0xdd, 0x9d, 0xfa, 0xba, 0xf5, + 0xe3, 0x58, 0xd0, 0xcf, 0xde, 0xbd, 0x79, 0x11, 0x96, 0x2a, 0xad, 0x3a, 0xa4, 0xd3, 0x41, 0xed, + 0x04, 0x31, 0x2a, 0x1f, 0x32, 0xd8, 0x43, 0xeb, 0xcf, 0x35, 0x73, 0x08, 0xda, 0x1b, 0x4a, 0x6f, + 0x59, 0x88, 0x72, 0xa5, 0x2b, 0xea, 0xe8, 0x02, 0x9b, 0xb1, 0x8e, 0x9c, 0xd1, 0xa4, 0xfe, 0x59, + 0xfe, 0x63, 0x79, 0x47, 0x67, 0x6e, 0x22, 0x4b, 0x3b, 0xc6, 0x26, 0x32, 0xd1, 0x59, 0x8c, 0xc6, + 0x86, 0x0a, 0xf2, 0x74, 0x39, 0x43, 0x4f, 0x63, 0xa8, 0xbe, 0x3b, 0x3a, 0x41, 0x4b, 0x36, 0x43, + 0xcd, 0xc8, 0x9a, 0x4a, 0xf5, 0x1b, 0x65, 0x7d, 0xad, 0x51, 0x87, 0x0e, 0x76, 0xa4, 0xb1, 0xb3, + 0x42, 0xd7, 0x85, 0x3f, 0x5a, 0x2a, 0xc4, 0x85, 0x65, 0xbf, 0x31, 0x6e, 0x3c, 0x4e, 0x66, 0x75, + 0x46, 0xed, 0xcf, 0x63, 0xd5, 0x63, 0xdd, 0x7c, 0xe7, 0x4b, 0x0a, 0x9a, 0x1b, 0xd8, 0xbc, 0x3a, + 0x24, 0xbb, 0x93, 0x2f, 0x24, 0x67, 0xd0, 0x06, 0x55, 0x77, 0xfd, 0xa2, 0xb2, 0x78, 0x47, 0xf0, + 0xc6, 0x5e, 0xdb, 0x69, 0x26, 0x4d, 0x8f, 0x6c, 0x70, 0x42, 0x20, 0x88, 0x22, 0xf3, 0x97, 0x15, + 0x9b, 0x17, 0x57, 0x5c, 0xf0, 0x28, 0x59, 0x43, 0x5b, 0x4d, 0x84, 0x5a, 0x2c, 0x6d, 0x7a, 0x66, + 0xd6, 0x38, 0xf7, 0xa7, 0x23, 0xc0, 0x2f, 0x68, 0x4c, 0x0c, 0xc3, 0x39, 0x5a, 0xe9, 0x38, 0xde, + 0x7e, 0x5e, 0x0a, 0x4b, 0x57, 0x9b, 0xe1, 0xe4, 0x91, 0xfd, 0xb1, 0x1e, 0x71, 0xc7, 0xa1, 0xc2, + 0xee, 0xb4, 0x32, 0x06, 0x55, 0x70, 0xbc, 0xbb, 0xd7, 0x96, 0xb4, 0x26, 0x8c, 0xdb, 0xde, 0x6d, + 0x31, 0x63, 0x92, 0x20, 0x8c, 0x5a, 0x6e, 0x12, 0xc0, 0x52, 0x1d, 0x69, 0x40, 0x11, 0xb6, 0x85, + 0x1d, 0xc3, 0x90, 0x15, 0xaf, 0x51, 0x62, 0xfb, 0x76, 0xef, 0xc4, 0xc0, 0xba, 0xed, 0xf5, 0xd9, + 0x7f, 0xfa, 0x0e, 0x97, 0x5f, 0xec, 0x69, 0x4a, 0x55, 0xa4, 0xf3, 0x24, 0xc8, 0x45, 0xe8, 0xd4, + 0xb9, 0xd1, 0x34, 0x6e, 0x7e, 0x0b, 0x30, 0xf8, 0xc9, 0xdb, 0xfa, 0x9e, 0x80, 0x58, 0x4d, 0x29, + 0x95, 0xfc, 0x50, 0xe2, 0x91, 0x0d, 0xd3, 0x69, 0xba, 0xf3, 0xe3, 0xc5, 0x82, 0x2e, 0xd5, 0x8a, + 0xb3, 0x87, 0x83, 0xad, 0x6a, 0x8f, 0xfd, 0x67, 0x7a, 0x73, 0x58, 0x53, 0x7a, 0x7f, 0xf6, 0xfe, + 0xea, 0xae, 0xbd, 0xa1, 0xb4, 0x62, 0xc1, 0xe9, 0xed, 0x12, 0xdf, 0x6b, 0x06, 0xe7, 0x13, 0xca, + 0xbf, 0xba, 0x7a, 0x9c, 0x98, 0xce, 0xba, 0x40, 0x8d, 0xfb, 0xe5, 0x99, 0xba, 0xc7, 0xaf, 0x74, + 0xb6, 0xe8, 0x16, 0x3d, 0x36, 0x8b, 0xe1, 0xb6, 0x0e, 0x63, 0xd2, 0x31, 0x9b, 0xc5, 0x7b, 0x05, + 0xfb, 0x88, 0xc6, 0x1b, 0x3e, 0xfc, 0x52, 0xcd, 0x9d, 0x5f, 0x77, 0x13, 0xcb, 0x7c, 0xfb, 0x75, + 0xbe, 0x88, 0x76, 0xa4, 0x37, 0x19, 0xdc, 0x5d, 0xc1, 0x26, 0x28, 0x3c, 0x17, 0x5e, 0x93, 0x24, + 0xaf, 0x67, 0x80, 0x1e, 0x46, 0xa7, 0xc0, 0xfa, 0xfd, 0xf9, 0x08, 0x74, 0x40, 0xf6, 0x89, 0x6e, + 0x78, 0xd2, 0x18, 0x3f, 0xa5, 0xb6, 0xfd, 0x8b, 0xcf, 0x11, 0x9c, 0x44, 0xa5, 0x05, 0x7d, 0xdf, + 0x4f, 0xaa, 0x83, 0xdb, 0xef, 0xb1, 0x50, 0xca, 0xb8, 0x99, 0x4b, 0xab, 0xd7, 0x7b, 0x73, 0xad, + 0xfd, 0x46, 0xb2, 0x8b, 0xeb, 0x6c, 0x92, 0x50, 0x76, 0xb6, 0x01, 0x21, 0x75, 0xeb, 0x08, 0x26, + 0xab, 0x27, 0x93, 0x39, 0x5a, 0x4b, 0x1b, 0xc5, 0x17, 0x7e, 0x73, 0x8d, 0xb6, 0x63, 0x21, 0xd3, + 0x8c, 0x5a, 0x0f, 0xb4, 0x75, 0xcf, 0xc3, 0x86, 0x60, 0x28, 0x8e, 0x41, 0x98, 0x12, 0x9b, 0x8c, + 0x55, 0x9d, 0x03, 0x82, 0x3b, 0xd1, 0x79, 0xd1, 0xf6, 0x3d, 0x64, 0x89, 0x7d, 0x77, 0xc1, 0xce, + 0xac, 0x98, 0xd7, 0x61, 0x6c, 0xe2, 0x5c, 0x08, 0x5f, 0x54, 0xf2, 0x64, 0x7f, 0xc9, 0xa5, 0x43, + 0x9c, 0x58, 0xac, 0xa2, 0x70, 0xac, 0x0b, 0x0e, 0xec, 0x77, 0xd2, 0x46, 0x13, 0xee, 0x2d, 0xa5, + 0xcf, 0xdc, 0xfd, 0x1f, 0xae, 0xba, 0xf4, 0x60, 0x70, 0x67, 0x7d, 0xc8, 0x00, 0xfe, 0x7c, 0x72, + 0xb3, 0xd9, 0x96, 0x6b, 0x0c, 0xa8, 0x39, 0x40, 0x34, 0x20, 0xcd, 0x3c, 0x18, 0x33, 0x80, 0xc0, + 0x56, 0x5b, 0x2d, 0x2a, 0xc1, 0x5a, 0xa3, 0x3c, 0x8c, 0x7a, 0x6f, 0xb4, 0x56, 0x70, 0xc2, 0xda, + 0xdb, 0x70, 0x74, 0x39, 0x62, 0xab, 0x01, 0x5f, 0x53, 0xf2, 0xbf, 0x3d, 0x66, 0x0a, 0xd1, 0xc6, + 0xcf, 0xbe, 0xa3, 0x10, 0xfb, 0x0d, 0xa5, 0xb5, 0x78, 0x15, 0xb7, 0x30, 0xd0, 0xd1, 0x16, 0x89, + 0x2e, 0x4c, 0xe2, 0x69, 0x52, 0xac, 0xa4, 0x85, 0xc8, 0xd9, 0xa2, 0xe3, 0x6b, 0x96, 0x03, 0xf2, + 0x3b, 0x14, 0x41, 0x0d, 0xc7, 0x44, 0x81, 0x8d, 0xf5, 0x5e, 0x3d, 0x26, 0xb1, 0xe2, 0x64, 0xaa, + 0x98, 0xa0, 0xe9, 0x95, 0x90, 0x35, 0x1a, 0x10, 0x01, 0x57, 0x71, 0x9a, 0x94, 0x8f, 0xc4, 0xc9, + 0x14, 0xc0, 0xc9, 0xa0, 0xe5, 0xa5, 0x0e, 0x1c, 0xb9, 0x73, 0xc0, 0xc4, 0x24, 0x2f, 0x15, 0x5c, + 0x50, 0x24, 0xba, 0xee, 0x2e, 0x66, 0x74, 0x58, 0x71, 0xfd, 0x9d, 0xcb, 0x8a, 0x2f, 0xea, 0xdc, + 0x95, 0x44, 0x4b, 0x0a, 0x0e, 0xa5, 0xb1, 0x1c, 0xdf, 0xee, 0xaa, 0x01, 0x3c, 0x7b, 0x1d, 0x78, + 0xb1, 0xd8, 0x71, 0x32, 0x28, 0x09, 0x5e, 0x07, 0x38, 0x62, 0x3e, 0x4e, 0xfa, 0x4d, 0x62, 0xef, + 0x86, 0x80, 0xa0, 0x60, 0x44, 0xe1, 0xf0, 0x3c, 0xdf, 0xc6, 0x00, 0xe8, 0x41, 0x00, 0xb6, 0x2b, + 0x86, 0xac, 0x2a, 0xc1, 0x13, 0x84, 0xb9, 0xa0, 0x03, 0xd1, 0xaa, 0x06, 0x3c, 0x42, 0x28, 0x0a, + 0x50, 0x19, 0x64, 0x3f, 0x9a, 0x6c, 0x54, 0x36, 0xc7, 0xea, 0x43, 0xe8, 0x83, 0x92, 0xdd, 0x8e, + 0x02, 0x67, 0x56, 0x6f, 0x9d, 0xc7, 0x83, 0x19, 0x08, 0x65, 0xa0, 0x67, 0x0c, 0x7f, 0xbb, 0xaf, + 0x31, 0x15, 0x03, 0xb0, 0xbb, 0xc4, 0x1e, 0x80, 0xd0, 0x0a, 0xb3, 0x6c, 0x82, 0x71, 0x89, 0x78, + 0xb7, 0x02, 0x0b, 0xd3, 0x77, 0x82, 0x00, 0xa5, 0xbc, 0xeb, 0x98, 0xcc, 0xbf, 0x88, 0xbf, 0xc4, + 0xea, 0x20, 0x0a, 0x22, 0x4c, 0x25, 0x08, 0x5b, 0x98, 0x60, 0x44, 0x80, 0xd0, 0x4d, 0x7c, 0x5f, + 0x8f, 0x1c, 0xe2, 0x3f, 0x75, 0x09, 0xb0, 0x04, 0x22, 0x34, 0x0e, 0x58, 0x8d, 0x7f, 0x08, 0x58, + 0x09, 0x98, 0x51, 0x85, 0xac, 0x81, 0x00, 0x59, 0x09, 0x22, 0xf5, 0x7e, 0xec, 0x1a, 0x67, 0xcd, + 0xdb, 0x60, 0x84, 0xa4, 0x88, 0x3a, 0xfa, 0x6c, 0x8e, 0x12, 0xf9, 0xd9, 0x77, 0x14, 0x66, 0xbc, + 0xa1, 0x34, 0x9d, 0xcd, 0x76, 0x9c, 0xa6, 0x74, 0xea, 0x17, 0xc8, 0x20, 0xc0, 0x1b, 0x71, 0xb1, + 0x78, 0x7d, 0xf4, 0x21, 0xbc, 0x37, 0xe8, 0xcc, 0xd7, 0xd1, 0x23, 0xeb, 0xcd, 0xf4, 0x6e, 0x52, + 0xfe, 0x47, 0xea, 0xd2, 0x7e, 0x7d, 0xd3, 0x8f, 0x3f, 0xa8, 0xf7, 0x68, 0x4b, 0x77, 0x70, 0xb7, + 0x3f, 0x96, 0x45, 0x5f, 0xd6, 0x00, 0xb7, 0xf0, 0x50, 0xa5, 0xbd, 0x4a, 0xe1, 0x9a, 0xf8, 0xe7, + 0x9b, 0x7f, 0xf9, 0x8e, 0x4a, 0x7f, 0xb3, 0x8e, 0x0c, 0x17, 0xac, 0x5b, 0x17, 0x72, 0xc2, 0x89, + 0xf1, 0x7d, 0xc9, 0x07, 0xe5, 0x03, 0xbc, 0xaa, 0xd1, 0xda, 0xe4, 0x8a, 0xb6, 0xc4, 0x6d, 0x3e, + 0x31, 0xe8, 0x5b, 0x4e, 0x43, 0x29, 0x42, 0x0c, 0xd0, 0x96, 0x77, 0x68, 0x08, 0xfc, 0x96, 0x14, + 0x7e, 0x82, 0x84, 0xfb, 0x47, 0x8e, 0x70, 0x46, 0x18, 0x8b, 0x4f, 0x82, 0xe5, 0x8d, 0x73, 0xec, + 0xe3, 0x99, 0xe4, 0xf7, 0x1e, 0x86, 0x86, 0x26, 0x2d, 0xaa, 0x9a, 0xa8, 0x24, 0x93, 0x06, 0x33, + 0xa2, 0xf8, 0x4d, 0x3a, 0xa9, 0x67, 0x57, 0xc4, 0xda, 0x26, 0x11, 0x6f, 0x21, 0xd8, 0xe8, 0xf1, + 0x42, 0x7b, 0xd3, 0x7e, 0x54, 0xb9, 0x6f, 0x07, 0xe2, 0x0a, 0x66, 0x9c, 0x68, 0x0f, 0x26, 0xc7, + 0x54, 0xa2, 0xf9, 0x62, 0x64, 0x88, 0xb7, 0x9f, 0xfa, 0x89, 0xe0, 0x88, 0xdf, 0x4f, 0x14, 0x58, + 0x92, 0x39, 0x0a, 0xc7, 0xea, 0xfe, 0x25, 0x75, 0x79, 0x21, 0x17, 0xc5, 0x0e, 0x0a, 0x0f, 0x44, + 0x9f, 0xb9, 0x8d, 0x5d, 0x5f, 0x32, 0x95, 0xe3, 0xe9, 0x28, 0x93, 0xdf, 0x9c, 0xe6, 0xd5, 0x93, + 0x33, 0xa3, 0x11, 0x28, 0x35, 0xc9, 0x19, 0xee, 0x76, 0xb9, 0xc5, 0x3e, 0x9b, 0x3c, 0xb4, 0x72, + 0x67, 0xb5, 0x9d, 0x0f, 0xd9, 0x42, 0x48, 0x8c, 0x7f, 0xd2, 0xd6, 0x94, 0xd3, 0x4b, 0xe8, 0xd8, + 0x39, 0xf7, 0xa9, 0xad, 0x6c, 0xe9, 0x37, 0x44, 0x19, 0xc9, 0x07, 0x8c, 0x72, 0xb9, 0xfe, 0xa3, + 0x00, 0xea, 0xfd, 0xd5, 0x34, 0x77, 0x10, 0x9e, 0xef, 0x9f, 0x9d, 0x36, 0x89, 0x9b, 0xc7, 0xdb, + 0xf6, 0xcf, 0xd1, 0xb8, 0x30, 0xf3, 0x0d, 0xa5, 0x8d, 0xb9, 0x8e, 0xf9, 0x90, 0xab, 0x6f, 0xf9, + 0x08, 0x88, 0x3a, 0x09, 0x8e, 0x03, 0xe0, 0x24, 0x28, 0x78, 0x2e, 0x5d, 0x39, 0x10, 0x95, 0x88, + 0x57, 0x6e, 0xe3, 0x75, 0xb0, 0x5c, 0x5f, 0x92, 0xd4, 0x04, 0xd8, 0x5e, 0xfe, 0xdf, 0xe3, 0x6f, + 0x24, 0x07, 0xd0, 0xd7, 0xf1, 0x87, 0x95, 0x25, 0xfd, 0x9a, 0xe4, 0x75, 0xfc, 0xd1, 0x0b, 0xde, + 0xdd, 0x1a, 0x30, 0xe6, 0x4a, 0x46, 0x5a, 0x00, 0x8c, 0x7b, 0x3a, 0x9a, 0x7f, 0x8e, 0x3f, 0xe5, + 0xd3, 0x0b, 0x65, 0xf2, 0x3a, 0xfe, 0xa8, 0xec, 0xd7, 0xf1, 0xd7, 0x94, 0xfc, 0xf7, 0xf8, 0x0b, + 0xff, 0x18, 0x7f, 0xae, 0xe9, 0xeb, 0xf8, 0xcb, 0x7f, 0xbb, 0x33, 0x4b, 0x50, 0xc7, 0xcd, 0xcd, + 0x77, 0xd4, 0xa9, 0xc6, 0x1a, 0x65, 0x13, 0xc2, 0x6d, 0xd7, 0xa4, 0xcc, 0xd7, 0x71, 0xbf, 0x3e, + 0xcd, 0x4a, 0x88, 0x49, 0x7a, 0xfe, 0x52, 0x20, 0xf6, 0xea, 0x13, 0x61, 0xaf, 0x77, 0x33, 0x23, + 0xf8, 0x72, 0x6c, 0x7a, 0xaa, 0x7e, 0x25, 0x4c, 0xa5, 0xfd, 0x7f, 0x46, 0x6a, 0x9d, 0x9c, 0xe4, + 0x9e, 0x80, 0xe3, 0xad, 0x85, 0x20, 0x1e, 0xbd, 0xf9, 0x11, 0xa9, 0x75, 0xc8, 0x54, 0x6c, 0x7b, + 0x5a, 0x46, 0xa9, 0xed, 0xbc, 0x26, 0xfd, 0xa8, 0x94, 0x75, 0x21, 0xa6, 0x56, 0x5f, 0x49, 0xd3, + 0x6e, 0x1d, 0xb3, 0xec, 0xb8, 0xcc, 0x6b, 0xa6, 0xa4, 0x5c, 0xad, 0xda, 0x00, 0x58, 0xae, 0x47, + 0xff, 0x19, 0xb3, 0x05, 0xd9, 0xb6, 0xd3, 0xe4, 0x03, 0xe3, 0xe9, 0x70, 0xe1, 0xcf, 0xb0, 0x57, + 0x9d, 0x28, 0x25, 0x91, 0xc4, 0xb2, 0x00, 0x0e, 0xf5, 0xb3, 0xfa, 0x5d, 0x62, 0x2e, 0x76, 0x55, + 0x6e, 0x55, 0x55, 0xc0, 0x7a, 0x80, 0xa0, 0xb0, 0xef, 0xb1, 0xc4, 0xde, 0x03, 0xfc, 0xcb, 0x90, + 0x31, 0x7e, 0x50, 0x2c, 0xb0, 0x42, 0x5f, 0x5a, 0x5b, 0x52, 0xc0, 0x15, 0x4b, 0x0c, 0xe0, 0xee, + 0xcf, 0xf3, 0x34, 0x22, 0x7a, 0x43, 0x69, 0xd3, 0xe5, 0x04, 0x87, 0xa7, 0xda, 0x81, 0xd6, 0xc8, + 0x65, 0x73, 0x8e, 0x0e, 0x35, 0xb9, 0xb1, 0xe7, 0x2b, 0xae, 0xca, 0x8d, 0x96, 0xf1, 0x56, 0x4c, + 0x58, 0x67, 0xad, 0x85, 0xbf, 0x1c, 0x1a, 0x25, 0xb2, 0x16, 0xd6, 0xfd, 0xe8, 0x39, 0x71, 0x9f, + 0x98, 0x2f, 0xfc, 0x5e, 0xe6, 0xe8, 0x5e, 0xbb, 0x9d, 0x94, 0x55, 0x89, 0x6a, 0x6b, 0x99, 0x27, + 0xeb, 0xee, 0x49, 0x31, 0xf9, 0x97, 0x8e, 0x48, 0x80, 0xc4, 0x1e, 0x65, 0xd6, 0xea, 0xcb, 0xb2, + 0xa0, 0x2a, 0x0c, 0x18, 0x58, 0x1e, 0x44, 0x71, 0x23, 0x2d, 0xfb, 0x47, 0x9b, 0xba, 0x9d, 0xde, + 0xe1, 0xda, 0xfc, 0x7d, 0x87, 0xc4, 0x60, 0xd8, 0x42, 0x17, 0xf2, 0x7b, 0x56, 0x47, 0x5f, 0xa7, + 0x08, 0xe3, 0x8c, 0xbc, 0x12, 0xe8, 0x8d, 0x72, 0xba, 0xab, 0xe7, 0xeb, 0x5c, 0xf1, 0xb6, 0xe6, + 0xbb, 0x58, 0x3e, 0x8e, 0x33, 0x44, 0x46, 0xbe, 0x33, 0xc0, 0x08, 0xb3, 0x23, 0xc3, 0x5a, 0x69, + 0xac, 0x6b, 0x71, 0xf6, 0x54, 0xad, 0xf5, 0xc2, 0xce, 0x99, 0xc4, 0x52, 0x35, 0xa3, 0xde, 0xd3, + 0x99, 0x25, 0xfd, 0x0d, 0x17, 0x32, 0xd1, 0x2f, 0xad, 0xf8, 0x5e, 0x05, 0xa6, 0x19, 0x44, 0x86, + 0x7f, 0x16, 0x6e, 0xc6, 0x55, 0xd9, 0xd6, 0xd1, 0xac, 0x95, 0x50, 0xa8, 0xe3, 0x99, 0xc7, 0x92, + 0xee, 0x06, 0x61, 0x4b, 0xc6, 0x57, 0xc4, 0x86, 0xb9, 0x23, 0xc4, 0x26, 0x0b, 0xfc, 0x38, 0x31, + 0xb3, 0x9c, 0xc9, 0x1e, 0x25, 0xe4, 0xcb, 0x2f, 0xad, 0x59, 0xc2, 0xe9, 0x24, 0x41, 0xe2, 0x4b, + 0x35, 0x73, 0x9a, 0x11, 0x9b, 0x10, 0x4e, 0x26, 0xe7, 0x38, 0x41, 0xc6, 0x25, 0xa3, 0xe7, 0xd9, + 0x52, 0x1c, 0xdf, 0x86, 0x39, 0xa0, 0x69, 0x14, 0xd3, 0x75, 0xcc, 0x69, 0x79, 0xbd, 0x31, 0x43, + 0x51, 0x4e, 0xab, 0xf3, 0x7b, 0x5a, 0x7b, 0xa9, 0xf6, 0xce, 0x2c, 0xba, 0x07, 0x39, 0xd5, 0xb2, + 0x03, 0x63, 0x88, 0xa4, 0xca, 0x3f, 0x9d, 0x16, 0x3a, 0xeb, 0xf5, 0x9e, 0x29, 0x1c, 0xde, 0x0a, + 0x8a, 0xb0, 0xad, 0x9f, 0xab, 0x7d, 0xe2, 0xd2, 0x37, 0x94, 0x16, 0xaa, 0xa5, 0x60, 0x3c, 0x03, + 0x82, 0x76, 0x94, 0x90, 0xde, 0xb7, 0x91, 0xb5, 0x35, 0xcc, 0x80, 0x30, 0xd8, 0xd2, 0xd3, 0x47, + 0xd5, 0x19, 0x18, 0x71, 0x11, 0x3f, 0x65, 0xaf, 0xe0, 0x5d, 0xd7, 0x1f, 0x74, 0xb0, 0xe2, 0x83, + 0xd2, 0x1a, 0x45, 0xe8, 0x97, 0x02, 0x1f, 0x42, 0x12, 0x44, 0x6c, 0x48, 0xf6, 0x32, 0x02, 0x93, + 0xe8, 0x06, 0x9e, 0xa3, 0x49, 0xce, 0x81, 0x65, 0x12, 0x02, 0x4a, 0x04, 0x77, 0x34, 0x19, 0x66, + 0xf3, 0x05, 0x84, 0x3c, 0x3b, 0x9e, 0x00, 0xc4, 0x76, 0x98, 0xa2, 0x94, 0xf0, 0x10, 0x35, 0x39, + 0x09, 0xd1, 0xf4, 0x14, 0xd0, 0x87, 0x50, 0x38, 0xc0, 0xd1, 0x61, 0xbf, 0xbc, 0x53, 0x49, 0x20, + 0x94, 0x3f, 0x93, 0x48, 0xe0, 0x47, 0x0a, 0x0b, 0xd4, 0x34, 0xae, 0xfe, 0x48, 0x61, 0x61, 0x3d, + 0x4d, 0x19, 0xa4, 0xf6, 0x69, 0x3f, 0x29, 0x20, 0xf0, 0x2c, 0xa8, 0x94, 0x2b, 0x02, 0x25, 0x90, + 0x8f, 0xb6, 0x30, 0x7e, 0xf2, 0x7b, 0x36, 0x64, 0xbb, 0x7d, 0xf9, 0x74, 0x09, 0x63, 0x6a, 0x89, + 0x60, 0x82, 0x98, 0x37, 0x84, 0x93, 0x6b, 0xf7, 0xdc, 0xda, 0xbd, 0xdc, 0xbd, 0x29, 0xba, 0xdf, + 0x75, 0x7f, 0x58, 0x9b, 0x4c, 0xcc, 0x32, 0xe1, 0x04, 0x57, 0x89, 0x05, 0x0f, 0x5f, 0x9f, 0x99, + 0x01, 0xaf, 0x76, 0x6b, 0xbe, 0x6d, 0x0d, 0x9a, 0x97, 0x39, 0xd5, 0xb0, 0x56, 0x76, 0x1f, 0xd1, + 0x9a, 0xb9, 0x49, 0xab, 0x4a, 0xc5, 0x69, 0xbb, 0x06, 0xbd, 0x5c, 0xa1, 0xfc, 0x14, 0x37, 0xee, + 0xc0, 0xaa, 0xa3, 0x99, 0x42, 0xf3, 0x54, 0x6b, 0x24, 0x8f, 0x9a, 0xd8, 0xa7, 0xe2, 0x1f, 0x3b, + 0x9a, 0x5c, 0x5d, 0x15, 0x24, 0xb4, 0x16, 0xa5, 0x9e, 0x39, 0xd1, 0xd4, 0xd4, 0x99, 0xd9, 0x92, + 0x6c, 0x28, 0x5c, 0xb2, 0x98, 0x08, 0x4b, 0x0a, 0x6a, 0x78, 0x1c, 0xa9, 0xe2, 0xd0, 0x7c, 0x68, + 0x04, 0x2d, 0xdb, 0x37, 0xcd, 0xa2, 0xd7, 0xfd, 0x37, 0xf9, 0x29, 0x48, 0x6f, 0x28, 0x8d, 0x6a, + 0x35, 0x8d, 0x9e, 0x5a, 0xa2, 0x1a, 0x6d, 0xf5, 0x94, 0xd6, 0xbb, 0xde, 0x93, 0x68, 0x7b, 0x14, + 0xbb, 0x10, 0x6b, 0x1e, 0x44, 0x90, 0x46, 0x67, 0xa9, 0x15, 0x82, 0x21, 0x8d, 0xbd, 0x50, 0xae, + 0xb4, 0x68, 0x41, 0x48, 0xbc, 0xb1, 0xd5, 0xce, 0x4b, 0x0c, 0xb5, 0x2c, 0xd4, 0x7c, 0x59, 0x90, + 0xce, 0x5e, 0x0d, 0xca, 0xe7, 0x33, 0x62, 0xa3, 0xbf, 0xac, 0x69, 0xc4, 0xfe, 0x02, 0x4a, 0x47, + 0x06, 0x6c, 0xc9, 0x68, 0xaf, 0xcc, 0x48, 0x8c, 0xf5, 0x17, 0xb7, 0x5f, 0x67, 0x18, 0xfc, 0xc5, + 0x92, 0xc5, 0x6e, 0x46, 0xe4, 0x70, 0xed, 0x75, 0x44, 0xac, 0xd8, 0x50, 0xcc, 0x68, 0xbe, 0x42, + 0xe3, 0x9d, 0xff, 0xa8, 0x19, 0x3a, 0x2a, 0xa7, 0x57, 0x85, 0x66, 0x2d, 0x9d, 0xc4, 0xfd, 0xa7, + 0xc1, 0x50, 0x28, 0x63, 0x4a, 0xe5, 0xb1, 0x77, 0xeb, 0x71, 0x35, 0xbd, 0xb3, 0x7b, 0x53, 0x55, + 0x4f, 0x63, 0x4f, 0xa5, 0xc6, 0x99, 0x9b, 0xbc, 0xb8, 0x23, 0x1d, 0x85, 0x58, 0x66, 0xad, 0x7f, + 0x4e, 0x69, 0x3c, 0xfe, 0x63, 0x53, 0x76, 0x7e, 0x8c, 0xce, 0x94, 0x93, 0x36, 0xcc, 0x68, 0x36, + 0x1e, 0xea, 0xda, 0xe4, 0xf1, 0x36, 0x82, 0x07, 0x3e, 0xc7, 0xd5, 0xc1, 0xac, 0x56, 0xde, 0x0a, + 0xeb, 0xce, 0xa7, 0xa7, 0xb9, 0xb5, 0x99, 0xcd, 0xf9, 0xc1, 0x62, 0xb8, 0x27, 0x12, 0x0c, 0x7e, + 0x18, 0xa6, 0x5b, 0xc0, 0x61, 0xb3, 0xb0, 0x90, 0x31, 0xdd, 0xc6, 0x17, 0xaf, 0xe2, 0x47, 0x85, + 0xaa, 0x79, 0x7f, 0xd4, 0xd4, 0xb1, 0x4a, 0xad, 0x91, 0x16, 0x3f, 0x1e, 0x61, 0xcc, 0x3f, 0x8c, + 0xa4, 0x67, 0xea, 0x15, 0xcc, 0x34, 0x3c, 0x34, 0xbe, 0x7d, 0x6f, 0x2b, 0xa2, 0xe5, 0xf4, 0x96, + 0xc8, 0x61, 0xf5, 0x06, 0x46, 0x0f, 0xc7, 0xde, 0x30, 0x57, 0x7b, 0xe2, 0x55, 0x96, 0x35, 0x0f, + 0x95, 0xbe, 0x59, 0x3f, 0x8d, 0x17, 0xcd, 0xe7, 0xae, 0xeb, 0x81, 0xde, 0xf6, 0x40, 0xcb, 0x2a, + 0x65, 0xc2, 0x8d, 0x0f, 0xcf, 0x9c, 0xfd, 0xee, 0xcf, 0x39, 0x57, 0xe4, 0x6f, 0x28, 0x1d, 0xde, + 0x23, 0xd0, 0x0b, 0xba, 0xa2, 0xca, 0x1f, 0x67, 0xd8, 0xc5, 0xa1, 0x77, 0xaa, 0xac, 0x49, 0x56, + 0xa7, 0x46, 0x62, 0x1c, 0x24, 0x03, 0xae, 0xf5, 0x5e, 0xf8, 0x40, 0xe8, 0x3a, 0x4f, 0x00, 0xaf, + 0xc7, 0x51, 0x92, 0xf7, 0x4e, 0x0b, 0x9b, 0x67, 0x0e, 0x7d, 0x7d, 0x66, 0x5d, 0x35, 0xf9, 0x1d, + 0x5a, 0xd1, 0xd8, 0xa5, 0x1e, 0x08, 0xbf, 0x60, 0x4d, 0x93, 0xb9, 0x59, 0xcd, 0xc6, 0x34, 0x61, + 0x11, 0x2d, 0x0f, 0x96, 0xf0, 0x16, 0xa7, 0x69, 0xc2, 0xe5, 0x1f, 0xf3, 0xf0, 0xf8, 0x69, 0x7c, + 0x1f, 0x5e, 0x7a, 0x6a, 0x87, 0x70, 0x22, 0x01, 0x28, 0xed, 0x13, 0x14, 0xd7, 0xd9, 0x27, 0x8b, + 0x46, 0x56, 0x57, 0x7e, 0x82, 0x12, 0xd5, 0x3b, 0x23, 0xbe, 0x0f, 0x93, 0x57, 0x56, 0x2a, 0xb1, + 0x09, 0x35, 0x3d, 0xb6, 0xf6, 0x45, 0xac, 0x94, 0xe0, 0xfc, 0x2e, 0xff, 0xe7, 0xd7, 0x66, 0xf1, + 0x80, 0xe7, 0xba, 0x46, 0x28, 0x50, 0xbb, 0xfd, 0xd4, 0xcf, 0xed, 0xfa, 0x0a, 0x82, 0xcf, 0x30, + 0xac, 0x35, 0x95, 0xb7, 0xf6, 0xc8, 0x06, 0x10, 0x84, 0x19, 0x1c, 0x0e, 0xbc, 0x1b, 0x5e, 0x05, + 0xec, 0x4f, 0x04, 0x99, 0x0f, 0xff, 0xde, 0x17, 0x36, 0x4e, 0xd1, 0xda, 0xea, 0x54, 0x25, 0x5d, + 0xa3, 0x78, 0x22, 0x81, 0x14, 0xc5, 0x5d, 0x5e, 0x79, 0x8c, 0xb0, 0x6f, 0x5e, 0x1e, 0xa7, 0xca, + 0x32, 0x89, 0x0a, 0xba, 0xdd, 0xd4, 0x47, 0x8a, 0xcb, 0x11, 0x2a, 0xcc, 0x3b, 0x9a, 0x73, 0xb1, + 0x86, 0x5b, 0xda, 0x5a, 0x5b, 0x24, 0x60, 0x1a, 0x6d, 0x15, 0xb4, 0x3e, 0x8a, 0xe6, 0x1d, 0xe2, + 0x68, 0xfd, 0xc1, 0xfd, 0xd0, 0xd3, 0x47, 0x80, 0xaf, 0x57, 0x79, 0xac, 0x64, 0x0d, 0xd0, 0xb4, + 0xb0, 0xdb, 0x7b, 0x72, 0x40, 0x78, 0x2b, 0x83, 0x42, 0x1a, 0xf4, 0x63, 0x97, 0x79, 0x5e, 0xff, + 0xe9, 0x92, 0x25, 0x78, 0x14, 0x7d, 0xaf, 0x94, 0x70, 0x33, 0x07, 0x80, 0x47, 0x12, 0x20, 0x8a, + 0xef, 0x86, 0x59, 0x91, 0x2a, 0xc6, 0xa4, 0xb2, 0x1d, 0x3f, 0xef, 0x5c, 0xe4, 0x8a, 0x37, 0x94, + 0xce, 0xa1, 0x52, 0x89, 0xfb, 0x09, 0x15, 0xdb, 0x6a, 0xc2, 0x15, 0xcb, 0xb1, 0x9b, 0xc1, 0x64, + 0xdf, 0x7e, 0x9d, 0x30, 0xce, 0x06, 0xc1, 0x5c, 0xe8, 0x41, 0x4e, 0x93, 0x0f, 0x0d, 0xf6, 0xf4, + 0x8a, 0x2e, 0x5a, 0x53, 0x1b, 0xa5, 0xe3, 0xdb, 0xe9, 0xbf, 0x03, 0x89, 0xff, 0xb9, 0x3c, 0x45, + 0x5f, 0x97, 0xa7, 0xd6, 0xbf, 0x96, 0xa7, 0x2f, 0x37, 0xff, 0x5e, 0x9e, 0x52, 0x86, 0x1f, 0xcb, + 0x13, 0xbc, 0x7b, 0x52, 0x6c, 0x7a, 0xaa, 0xe8, 0xa5, 0xfa, 0x88, 0x80, 0xc8, 0xf7, 0xa9, 0xb8, + 0x8a, 0x0a, 0xf1, 0x3a, 0x94, 0x4b, 0x61, 0x24, 0xbc, 0x7a, 0x79, 0x75, 0xfe, 0x3f, 0x16, 0x25, + 0x20, 0x16, 0xca, 0x3e, 0xdf, 0x6d, 0x0c, 0x19, 0x39, 0x00, 0x86, 0xb1, 0xfc, 0x10, 0x9a, 0x9b, + 0xe4, 0xc0, 0x60, 0x7a, 0xae, 0x88, 0xd5, 0x12, 0x43, 0xc9, 0xd1, 0xe0, 0xf9, 0x66, 0x18, 0x8a, + 0x22, 0x93, 0xc7, 0xab, 0xa1, 0xf8, 0xf2, 0x37, 0xd6, 0x4b, 0x1a, 0x7f, 0x76, 0x9b, 0xe2, 0x0a, + 0x8a, 0x2e, 0x08, 0xb1, 0x08, 0x87, 0xf7, 0xf0, 0xf9, 0x92, 0x6b, 0x23, 0x67, 0x1e, 0x34, 0x35, + 0xd2, 0xea, 0x63, 0xd4, 0xd5, 0x67, 0xac, 0x45, 0xf8, 0x61, 0x2a, 0x65, 0x1b, 0x26, 0xc8, 0x55, + 0x70, 0x3b, 0x48, 0xe3, 0xf0, 0x6c, 0x7a, 0x19, 0x00, 0x3b, 0x49, 0xcb, 0x4f, 0x2e, 0x1f, 0x4e, + 0x5a, 0xbb, 0xbf, 0x86, 0xd7, 0xe6, 0x73, 0xfc, 0x3a, 0xcd, 0x04, 0xaa, 0x7f, 0x84, 0xa0, 0xda, + 0xdd, 0x4a, 0x36, 0x18, 0x85, 0x3f, 0xb4, 0x5d, 0xf6, 0xc0, 0x09, 0x20, 0xf0, 0xc0, 0xa4, 0xb1, + 0x9b, 0xdf, 0x0d, 0x68, 0xc4, 0x82, 0x0a, 0x2e, 0xe1, 0x27, 0x7d, 0x2d, 0x09, 0xe0, 0x67, 0x32, + 0xa4, 0x2c, 0x88, 0xce, 0xa6, 0xf3, 0xcb, 0x08, 0x7b, 0x81, 0x5f, 0xd6, 0xb3, 0x0d, 0x2d, 0x3e, + 0xce, 0xa4, 0x88, 0xcb, 0x24, 0xec, 0x37, 0xf1, 0xe4, 0x6f, 0x6a, 0x50, 0xaa, 0xdf, 0x50, 0xba, + 0x20, 0xd4, 0x19, 0xd2, 0xec, 0xa0, 0xf0, 0x0b, 0xb1, 0x22, 0xd2, 0x11, 0xf5, 0x2c, 0x60, 0x50, + 0x7f, 0xc9, 0x0e, 0x55, 0xe2, 0x3a, 0x39, 0xe9, 0xfd, 0x16, 0x56, 0xdf, 0xd9, 0x2b, 0x5d, 0xa0, + 0xbe, 0xe3, 0x40, 0x62, 0x6b, 0x6e, 0x97, 0x27, 0xa0, 0x11, 0x42, 0x18, 0x9d, 0x26, 0xe4, 0x41, + 0xfa, 0x05, 0x21, 0x08, 0xeb, 0x97, 0x85, 0x3c, 0xbd, 0x9e, 0x22, 0x84, 0xa1, 0xec, 0x8e, 0xf8, + 0x1b, 0xd2, 0x52, 0x48, 0xac, 0x44, 0xdf, 0xc4, 0xbe, 0xf5, 0x9d, 0x18, 0xef, 0x79, 0x48, 0xdf, + 0x8c, 0x81, 0x44, 0x82, 0x22, 0x28, 0xeb, 0xe9, 0x34, 0xde, 0x0e, 0x7d, 0x89, 0x2c, 0xbe, 0x3b, + 0xc7, 0xd8, 0x79, 0xfb, 0x55, 0x9d, 0x5d, 0xa8, 0x54, 0x02, 0x4a, 0x31, 0x41, 0xad, 0x6b, 0xa5, + 0x76, 0x3b, 0xbe, 0xc7, 0xae, 0xd9, 0x91, 0x3d, 0x8e, 0xa3, 0x41, 0xb0, 0x4a, 0xfc, 0x09, 0x19, + 0xe4, 0x3f, 0x6f, 0x89, 0x58, 0x56, 0xfb, 0xe4, 0x82, 0x0c, 0xc1, 0x7a, 0x9a, 0x48, 0xe0, 0x41, + 0xf1, 0x8f, 0x42, 0xa7, 0x2f, 0x24, 0xf8, 0xec, 0x27, 0x3f, 0x52, 0x0d, 0xb6, 0xb9, 0x7a, 0x03, + 0xe8, 0xf5, 0xb7, 0xc8, 0xb0, 0x15, 0x1f, 0xa0, 0x65, 0xe8, 0x9a, 0x00, 0xd8, 0x15, 0x6c, 0x8d, + 0x22, 0x8b, 0x26, 0x5a, 0xbf, 0x45, 0x7a, 0x95, 0x0c, 0x50, 0xe9, 0x7e, 0x79, 0xb5, 0xed, 0xad, + 0x01, 0x09, 0x28, 0x73, 0xf8, 0x5a, 0x8b, 0xdb, 0xce, 0x8d, 0x35, 0xde, 0x81, 0x94, 0x1a, 0xe6, + 0xf0, 0x67, 0xd7, 0xc9, 0xbd, 0xdd, 0xfb, 0xc0, 0x5e, 0x2e, 0xd9, 0xeb, 0x0e, 0x04, 0x06, 0xa7, + 0x5f, 0x29, 0xb9, 0x8d, 0xc5, 0x1b, 0x68, 0x26, 0xea, 0xae, 0x71, 0x59, 0xdd, 0xcd, 0xe4, 0xf7, + 0xcf, 0x15, 0x4c, 0x34, 0x6f, 0x15, 0x5f, 0xe7, 0xbe, 0xb3, 0x2a, 0xc1, 0xe5, 0xbe, 0x15, 0xec, + 0xcb, 0x43, 0x9c, 0xf0, 0x75, 0xeb, 0x1e, 0xe8, 0x12, 0xe4, 0x10, 0x50, 0x3a, 0x0c, 0x98, 0xb4, + 0x46, 0x7d, 0xf7, 0x37, 0x8f, 0x2b, 0xda, 0xf8, 0xce, 0x3a, 0xfb, 0x79, 0x9e, 0x46, 0xe8, 0x7f, + 0xaf, 0x34, 0x24, 0x4b, 0x6e, 0x77, 0x94, 0xd9, 0x33, 0x69, 0x4a, 0x1d, 0x4b, 0x80, 0x33, 0xf4, + 0x92, 0x4a, 0x1c, 0x8b, 0x84, 0x5c, 0xa5, 0x2b, 0xae, 0xce, 0xe4, 0x23, 0xd5, 0x57, 0xc3, 0xf3, + 0x85, 0x58, 0x7c, 0xc9, 0x58, 0xe0, 0x31, 0xd7, 0xe2, 0x1f, 0x2e, 0x49, 0x94, 0x90, 0x03, 0x6f, + 0x58, 0xbc, 0x9b, 0x8f, 0x67, 0x56, 0xc1, 0x4d, 0xa1, 0x9c, 0x6a, 0xf6, 0x39, 0x2f, 0xeb, 0x36, + 0xcb, 0x89, 0x28, 0xc3, 0xfb, 0x35, 0xb5, 0xb3, 0x7b, 0x8e, 0x69, 0x20, 0x1b, 0x04, 0x25, 0x01, + 0xa2, 0xf5, 0x07, 0x7d, 0x55, 0xe5, 0x1e, 0x85, 0x8a, 0xdb, 0xd3, 0x46, 0x03, 0x97, 0xb8, 0x99, + 0x39, 0x91, 0xc9, 0xbd, 0xa2, 0x01, 0x2f, 0xe1, 0xea, 0xa5, 0xce, 0x61, 0xb9, 0x29, 0xb2, 0x39, + 0xde, 0x0b, 0xf9, 0x99, 0x5a, 0x4d, 0x92, 0x9f, 0x11, 0x5b, 0xc4, 0xab, 0xe1, 0x7e, 0x7f, 0xdd, + 0x0b, 0x81, 0x46, 0xf4, 0x92, 0xc3, 0x33, 0x5d, 0xd7, 0x0d, 0xc5, 0x66, 0x6f, 0xfa, 0xa8, 0x35, + 0xe3, 0x86, 0xef, 0x4d, 0x15, 0xb6, 0x64, 0x38, 0x0d, 0x2e, 0x26, 0x16, 0x66, 0x9b, 0x44, 0x6d, + 0x29, 0x6f, 0xe9, 0xfb, 0x35, 0x07, 0x12, 0xfa, 0x09, 0xf7, 0xac, 0xdc, 0xc5, 0x52, 0xda, 0x93, + 0x0b, 0x53, 0x0c, 0x1f, 0x8c, 0x62, 0xd8, 0x54, 0x85, 0x5e, 0x0a, 0x2f, 0xdc, 0x8b, 0xa3, 0x4c, + 0x21, 0x25, 0xb8, 0x54, 0x3f, 0xec, 0xdf, 0x5c, 0xb2, 0x2d, 0xe7, 0x43, 0xca, 0x59, 0x23, 0x4d, + 0x9d, 0x42, 0xc7, 0x9a, 0x50, 0xce, 0xf0, 0x67, 0xf8, 0x4b, 0x1e, 0x50, 0x4d, 0xaa, 0xb3, 0xf8, + 0x65, 0x3c, 0xc5, 0x92, 0xb4, 0x52, 0x2b, 0x78, 0x50, 0xf8, 0x9f, 0x75, 0x4e, 0x2f, 0x97, 0xa1, + 0x17, 0x39, 0xb2, 0xf6, 0xba, 0xaf, 0xcd, 0x2f, 0x0b, 0x82, 0x9f, 0xc4, 0x7a, 0x97, 0x50, 0xc4, + 0x11, 0xea, 0xbb, 0x82, 0x51, 0x86, 0x63, 0x38, 0xb9, 0x58, 0x53, 0x61, 0xde, 0xc7, 0xb5, 0xc8, + 0x3a, 0x51, 0x08, 0x03, 0x5e, 0xaf, 0x34, 0x24, 0xd0, 0xd3, 0x7f, 0xce, 0xb9, 0xa2, 0x7f, 0xe3, + 0x9a, 0x26, 0x17, 0x53, 0x82, 0x1e, 0x3d, 0x68, 0x54, 0xcb, 0x11, 0x2c, 0xe9, 0x3b, 0x24, 0xda, + 0xbb, 0xee, 0xeb, 0xe7, 0x2c, 0x7a, 0x1f, 0xc3, 0xb2, 0x0f, 0x71, 0xa6, 0x42, 0xcc, 0x6b, 0x1c, + 0x6e, 0xa2, 0x5c, 0x49, 0x3a, 0xbb, 0x2c, 0x53, 0xcf, 0x75, 0xa4, 0xed, 0xfd, 0x97, 0x62, 0x93, + 0xc3, 0xab, 0x06, 0x75, 0x6d, 0x8b, 0xba, 0xb0, 0xc3, 0x23, 0x3e, 0x14, 0xe6, 0x27, 0x1d, 0x5a, + 0x30, 0x5d, 0xd6, 0x63, 0x93, 0x64, 0xea, 0x61, 0xef, 0x93, 0xb4, 0x23, 0x49, 0x17, 0x5e, 0x58, + 0x48, 0x60, 0x8b, 0xdd, 0x91, 0x78, 0x8b, 0xda, 0x0a, 0x8a, 0x90, 0x98, 0xca, 0x49, 0xcd, 0xaf, + 0xf6, 0x54, 0xee, 0xe6, 0x42, 0x2e, 0xfc, 0x2a, 0xc0, 0xd6, 0x4a, 0x83, 0x9b, 0x28, 0xdf, 0xe1, + 0x40, 0x04, 0xc3, 0xe8, 0x0b, 0x03, 0xb8, 0x2f, 0x5d, 0xf5, 0xb9, 0x43, 0x24, 0x40, 0x17, 0x71, + 0xf9, 0xe3, 0x94, 0x48, 0xd5, 0x62, 0xee, 0x15, 0x27, 0x38, 0x89, 0x9c, 0x71, 0x6d, 0x0f, 0x93, + 0x0d, 0x5b, 0xbc, 0x1a, 0x5f, 0x6b, 0x5b, 0x16, 0x14, 0x22, 0xb1, 0x93, 0xec, 0x97, 0x0a, 0xd2, + 0xcd, 0x13, 0xcb, 0xee, 0x14, 0x61, 0x67, 0x94, 0x93, 0x25, 0x40, 0x56, 0xfb, 0x57, 0xb9, 0x3a, + 0x7b, 0x9c, 0x62, 0x84, 0x0d, 0xa1, 0xa2, 0xe3, 0x98, 0x74, 0xb7, 0xe3, 0x72, 0xf8, 0x4d, 0x53, + 0x71, 0xdc, 0x99, 0xc8, 0x94, 0xa2, 0xf6, 0x90, 0xc6, 0xca, 0xef, 0x2a, 0x0a, 0xa6, 0xab, 0xab, + 0x74, 0x40, 0xe0, 0x9c, 0x9b, 0xcf, 0x1e, 0xdb, 0x61, 0xff, 0xc7, 0xf5, 0x38, 0x59, 0x91, 0xf7, + 0xf2, 0xe1, 0x25, 0x63, 0x6d, 0xb7, 0xd6, 0x2c, 0x46, 0xdc, 0x6a, 0x7f, 0xe9, 0xdc, 0x65, 0xbf, + 0x31, 0x49, 0x85, 0xd7, 0xfd, 0xba, 0xd0, 0x78, 0x15, 0xdc, 0x89, 0xaf, 0xdb, 0x11, 0xfa, 0x55, + 0xc3, 0x3f, 0x0c, 0xac, 0x87, 0x95, 0x41, 0xd6, 0x39, 0xa6, 0x9a, 0xac, 0x5e, 0x11, 0x9b, 0xe9, + 0xbe, 0xcc, 0xd5, 0x9c, 0x30, 0xaf, 0x6a, 0xbf, 0xf7, 0x98, 0xee, 0xbf, 0xa9, 0xe9, 0x4e, 0xda, + 0x7b, 0x43, 0xe9, 0x05, 0x26, 0xbe, 0xe1, 0x0c, 0x2c, 0xa8, 0xc4, 0x2f, 0x33, 0x43, 0x28, 0x82, + 0x91, 0x0c, 0xb8, 0x78, 0xd2, 0x5c, 0xb9, 0x10, 0x24, 0xf4, 0x16, 0xa9, 0x57, 0xfd, 0x21, 0x99, + 0x17, 0xb8, 0xe5, 0xac, 0x4b, 0xed, 0x2f, 0xc9, 0xba, 0x31, 0x34, 0x53, 0xee, 0x35, 0xa4, 0xbe, + 0x04, 0xbb, 0xf3, 0x05, 0x9b, 0x30, 0x3a, 0xfc, 0x43, 0xae, 0x25, 0xe7, 0x26, 0xd3, 0x95, 0x76, + 0x9f, 0x0f, 0x5f, 0x90, 0x20, 0x7b, 0x19, 0x83, 0x34, 0x56, 0x17, 0x95, 0xf4, 0x42, 0x42, 0xf8, + 0xa3, 0xda, 0xf2, 0xf4, 0xbe, 0x63, 0x3a, 0xed, 0x0a, 0x74, 0xa1, 0xaf, 0xad, 0xfb, 0x96, 0xa1, + 0xc6, 0xd6, 0xe9, 0x76, 0xa2, 0x03, 0x60, 0xfd, 0xd6, 0x9e, 0x55, 0xee, 0xba, 0x5e, 0x38, 0x3f, + 0xaa, 0x2d, 0x4f, 0x15, 0x16, 0x6f, 0x4d, 0xaf, 0x6a, 0xc7, 0xbc, 0x9a, 0xb5, 0x08, 0x84, 0xa8, + 0x34, 0x78, 0xbc, 0x16, 0x00, 0xb1, 0x4a, 0xff, 0xa4, 0x1f, 0x39, 0xf5, 0xcc, 0x9a, 0x4d, 0x7e, + 0x6b, 0x8e, 0xc9, 0x99, 0xb5, 0xba, 0xd8, 0x4e, 0xd5, 0xf7, 0xd4, 0x87, 0x79, 0x5b, 0x73, 0xd5, + 0x10, 0xb1, 0x8d, 0x91, 0xf3, 0x27, 0xc8, 0x02, 0xaa, 0x7a, 0x58, 0x9d, 0x99, 0x3a, 0x1b, 0x8a, + 0xa6, 0xe8, 0xc8, 0x61, 0xcf, 0xb2, 0x5f, 0xe7, 0x35, 0x76, 0x03, 0xbc, 0xad, 0xa0, 0x90, 0x12, + 0x53, 0x91, 0xc9, 0xae, 0x13, 0xf8, 0xc4, 0x9c, 0x83, 0x4f, 0x73, 0xa6, 0x83, 0xdd, 0x34, 0x4e, + 0xbe, 0x57, 0xd5, 0xc9, 0xd4, 0xc8, 0x19, 0xc5, 0x6f, 0xf1, 0x36, 0xce, 0xdb, 0x8d, 0xcf, 0x67, + 0xd8, 0x2c, 0x07, 0x0e, 0x10, 0xc9, 0x5e, 0x10, 0x74, 0xea, 0x21, 0x59, 0xe3, 0x58, 0x62, 0xf9, + 0xf3, 0x19, 0x0d, 0x32, 0xf7, 0xcb, 0xe2, 0xc0, 0xb4, 0xe1, 0xb9, 0x98, 0x6b, 0x01, 0x67, 0xb5, + 0xae, 0xb0, 0x71, 0xb7, 0x3e, 0x19, 0x24, 0x67, 0x24, 0x2a, 0x6a, 0xbd, 0x4f, 0xdc, 0x24, 0x3a, + 0x96, 0x7f, 0x04, 0x26, 0xae, 0xae, 0x69, 0x68, 0x61, 0xad, 0x23, 0xd2, 0xf9, 0xd0, 0xdf, 0xd4, + 0x74, 0xa7, 0x43, 0x6f, 0x28, 0x0d, 0x64, 0xfe, 0x48, 0xa3, 0x13, 0xa0, 0x63, 0x4b, 0x57, 0xf7, + 0x3c, 0xc8, 0x86, 0x36, 0x6b, 0xe3, 0x7b, 0x07, 0xa8, 0xf4, 0xca, 0x81, 0x2d, 0x5e, 0xd8, 0x7d, + 0xa1, 0x3d, 0xe5, 0xdd, 0x68, 0xd9, 0x58, 0xe9, 0xe9, 0x7b, 0xc0, 0x91, 0x9e, 0x91, 0x12, 0x7c, + 0xbe, 0x99, 0x62, 0x0b, 0x85, 0x6f, 0x87, 0x89, 0x1f, 0x13, 0x55, 0xe6, 0x3b, 0x50, 0x09, 0xe0, + 0xc1, 0xcf, 0x77, 0xc3, 0x9a, 0x14, 0xb8, 0x4e, 0xd3, 0x29, 0x6e, 0xa4, 0x12, 0x5a, 0xb3, 0xd6, + 0xdc, 0x43, 0xe9, 0x67, 0x5f, 0x62, 0x79, 0x52, 0xb2, 0x22, 0x43, 0x96, 0xec, 0x64, 0x02, 0x00, + 0x6e, 0x5f, 0x20, 0xc7, 0xb1, 0x60, 0x4d, 0xd2, 0xb8, 0x82, 0xfc, 0x1e, 0xfc, 0xe8, 0x14, 0x06, + 0x68, 0x63, 0x69, 0x14, 0x6f, 0x68, 0x01, 0xeb, 0x61, 0x62, 0xcd, 0x03, 0xdb, 0xf3, 0x80, 0x01, + 0xff, 0x25, 0x39, 0x58, 0xf7, 0xf4, 0xf5, 0x06, 0x47, 0x04, 0xb9, 0x64, 0xad, 0xdf, 0x4c, 0x42, + 0x1a, 0xb0, 0x92, 0xc8, 0x81, 0x57, 0xdd, 0xed, 0x57, 0xa3, 0xa6, 0x4a, 0x30, 0x16, 0x9c, 0xc2, + 0x25, 0x8c, 0x0a, 0x19, 0x7c, 0xe8, 0x9e, 0xcc, 0x17, 0x68, 0x69, 0x05, 0x5e, 0x2a, 0x95, 0x05, + 0x10, 0x62, 0xbc, 0x79, 0xb9, 0x45, 0xa2, 0x29, 0xc4, 0xae, 0x6e, 0xba, 0x0c, 0x3a, 0xbe, 0x9e, + 0x18, 0xc1, 0xcd, 0x89, 0xfc, 0x63, 0x19, 0xa1, 0xad, 0xe9, 0xc6, 0xc8, 0xde, 0x5c, 0x4d, 0x3d, + 0xd9, 0x6d, 0x25, 0x79, 0x5e, 0xe3, 0x86, 0x02, 0xde, 0x3f, 0xba, 0x2c, 0x00, 0xcf, 0x46, 0x6c, + 0x0f, 0x53, 0xc1, 0x37, 0x78, 0x48, 0xe8, 0x9d, 0x7f, 0x98, 0xbc, 0x90, 0x56, 0x6b, 0x30, 0xf1, + 0x87, 0x28, 0xa6, 0xf6, 0x8b, 0xab, 0x62, 0xf7, 0xd5, 0xa8, 0x1a, 0x8c, 0x9b, 0xeb, 0xa1, 0x5c, + 0xca, 0xd6, 0x14, 0xe4, 0xb8, 0x5a, 0x33, 0xb5, 0x7d, 0x70, 0xdc, 0xa3, 0x3f, 0xfe, 0x11, 0xa9, + 0x2d, 0x73, 0x36, 0x4e, 0x11, 0x65, 0xae, 0x80, 0xcb, 0xfb, 0xe2, 0x9c, 0x37, 0x5e, 0x15, 0x1d, + 0x23, 0xfa, 0x9f, 0xf3, 0x53, 0x04, 0xde, 0x50, 0x9a, 0x2b, 0xf0, 0xce, 0x3e, 0xf4, 0x96, 0xec, + 0x47, 0x77, 0xec, 0x08, 0x0b, 0x9b, 0x1f, 0xac, 0xdd, 0xed, 0x5c, 0x8f, 0x13, 0x92, 0xe6, 0x27, + 0x71, 0x42, 0xe7, 0xb9, 0xca, 0x47, 0x94, 0x86, 0xf3, 0x74, 0xd0, 0x29, 0xc0, 0xb2, 0xa3, 0xf5, + 0x66, 0x2b, 0xbc, 0xb0, 0x6d, 0xdb, 0xed, 0xe9, 0xcc, 0x42, 0xda, 0x27, 0x9d, 0x79, 0x27, 0xf5, + 0x28, 0xbd, 0x0a, 0x53, 0xe7, 0xf4, 0x86, 0x87, 0x5f, 0xb3, 0x9a, 0xa1, 0x23, 0x95, 0x4e, 0x18, + 0x84, 0xab, 0x09, 0xb6, 0xe7, 0xfc, 0xb6, 0xaf, 0x7b, 0x38, 0x3b, 0x6d, 0x69, 0xcf, 0x9a, 0x9e, + 0x98, 0xa1, 0xbd, 0x85, 0x2d, 0xed, 0x9d, 0x9e, 0xdf, 0xfc, 0x7b, 0x9a, 0xb5, 0xe1, 0x81, 0x81, + 0x46, 0x66, 0x24, 0xbd, 0x4e, 0xb3, 0xf8, 0xeb, 0x34, 0xfb, 0xe7, 0x35, 0x3a, 0x1a, 0x5d, 0x86, + 0x9e, 0xa7, 0xf7, 0xfb, 0x7e, 0x2c, 0xbf, 0x04, 0xbf, 0x44, 0x9f, 0x17, 0x8b, 0x33, 0x9a, 0xbf, + 0x50, 0x8a, 0xd3, 0xe8, 0xe3, 0x87, 0x23, 0x4c, 0x08, 0x45, 0xc3, 0x75, 0xd3, 0x81, 0x01, 0x1a, + 0x9d, 0x24, 0xec, 0x8d, 0x93, 0xa7, 0x52, 0x6d, 0x3f, 0xac, 0xa6, 0x9b, 0x95, 0xf1, 0x34, 0x5e, + 0xa8, 0x8d, 0xc6, 0xa5, 0xff, 0x4a, 0x7b, 0x04, 0x39, 0xfd, 0xb0, 0x59, 0x1a, 0x21, 0x20, 0xd6, + 0xd9, 0xa4, 0xf2, 0x28, 0x57, 0x25, 0x5f, 0x4e, 0x47, 0xbc, 0x07, 0xec, 0xd3, 0x5c, 0x19, 0xb8, + 0x3b, 0xcc, 0x09, 0x95, 0x21, 0xa4, 0xfe, 0xe4, 0x1a, 0x23, 0xf2, 0x90, 0x18, 0x1a, 0xa3, 0x41, + 0xae, 0xd0, 0xf2, 0x54, 0x55, 0xdd, 0xbb, 0xc3, 0xc5, 0x8b, 0x0d, 0x37, 0x99, 0x07, 0x39, 0xea, + 0xd0, 0x52, 0x3c, 0xfa, 0x3d, 0x14, 0x17, 0xd7, 0xfa, 0xfd, 0x51, 0x26, 0xe2, 0x6d, 0xa0, 0x8e, + 0xd3, 0xdb, 0xe7, 0x9a, 0xcb, 0x3f, 0xf4, 0xbf, 0x6e, 0x11, 0xb7, 0x42, 0xb5, 0x94, 0xe1, 0x6b, + 0x90, 0xd6, 0x82, 0xe7, 0xa8, 0x46, 0x38, 0x06, 0xaf, 0xe5, 0xda, 0xf2, 0x1e, 0x19, 0x48, 0x4b, + 0xff, 0x26, 0xe7, 0x0a, 0xf6, 0x86, 0xd2, 0x8c, 0x1d, 0xa1, 0x23, 0x8a, 0x28, 0x04, 0x93, 0x0f, + 0x59, 0x86, 0xed, 0xfe, 0x69, 0xaa, 0xcb, 0x79, 0x43, 0x44, 0xec, 0xec, 0x1a, 0x17, 0x32, 0x74, + 0x9b, 0xe1, 0xa5, 0x83, 0x1a, 0xaf, 0xfa, 0x84, 0x5b, 0x6c, 0x8b, 0x81, 0x0c, 0x66, 0x1c, 0x7e, + 0x6a, 0x83, 0x6a, 0x27, 0xfd, 0x75, 0xbd, 0x6c, 0x67, 0xdb, 0x45, 0xe3, 0x7a, 0x33, 0xc1, 0x75, + 0x1d, 0xca, 0xe3, 0x36, 0x98, 0x10, 0x10, 0x7f, 0x46, 0xbb, 0x0a, 0x26, 0xe4, 0x3a, 0x41, 0x68, + 0xd2, 0x38, 0x34, 0x6e, 0x94, 0x93, 0xd7, 0x8f, 0x0b, 0x7c, 0x2c, 0xa0, 0x88, 0x25, 0xe5, 0xb4, + 0x15, 0x59, 0x4b, 0x89, 0x10, 0xc9, 0x0d, 0x23, 0x29, 0xc0, 0x14, 0x63, 0x04, 0xcd, 0xa4, 0x8c, + 0x3a, 0x30, 0xa6, 0x44, 0x7c, 0xb1, 0x9a, 0x9b, 0x9d, 0xd7, 0x84, 0x22, 0xc9, 0x2e, 0x6c, 0x00, + 0xce, 0xe3, 0xd2, 0xa6, 0x34, 0xee, 0x4a, 0xd7, 0x07, 0x26, 0xa9, 0x93, 0xda, 0x3e, 0x8a, 0x4b, + 0x17, 0x9f, 0x2e, 0xe1, 0xee, 0xaa, 0x09, 0x74, 0x7e, 0xb9, 0x04, 0x43, 0x4d, 0x48, 0xc6, 0x93, + 0x79, 0x5e, 0xb7, 0x52, 0x29, 0x57, 0x8f, 0x01, 0xa5, 0x4c, 0xe7, 0x8f, 0x32, 0x5b, 0x78, 0x31, + 0xc4, 0xce, 0x85, 0x1c, 0x61, 0x43, 0xab, 0x4c, 0xee, 0xb2, 0xda, 0x0d, 0x3c, 0xab, 0xff, 0x67, + 0x7e, 0xb6, 0x96, 0xfe, 0x98, 0xbc, 0x6c, 0xab, 0x4e, 0x03, 0x97, 0x2e, 0x49, 0xac, 0xc5, 0xc4, + 0x31, 0x26, 0xae, 0x32, 0xcd, 0x7a, 0xdd, 0x00, 0x17, 0x61, 0xe4, 0x2d, 0x80, 0xdb, 0xb8, 0xb5, + 0x6a, 0xe0, 0xe3, 0xf3, 0x7b, 0x1c, 0xe9, 0x49, 0xa0, 0xe6, 0xf6, 0x0a, 0xc2, 0x3a, 0x59, 0xc5, + 0x83, 0xc6, 0x9a, 0x84, 0xa4, 0xc8, 0x39, 0x75, 0xff, 0x32, 0x60, 0x5b, 0xc7, 0xee, 0x13, 0xbc, + 0x55, 0xfa, 0x76, 0x23, 0x1a, 0x0c, 0x13, 0x5c, 0xa5, 0x5a, 0xd3, 0x43, 0xd3, 0xca, 0xf8, 0x11, + 0xaa, 0x3b, 0xb2, 0xde, 0x04, 0x15, 0x57, 0xc4, 0x28, 0x91, 0x50, 0xc6, 0x5b, 0x89, 0xf8, 0x84, + 0xf7, 0x73, 0x26, 0x90, 0x6e, 0xf6, 0x0d, 0xa5, 0x99, 0x0b, 0xe2, 0xd7, 0xc5, 0x8c, 0x2c, 0x2e, + 0x23, 0xd8, 0x8a, 0xb8, 0x44, 0x60, 0xaa, 0x57, 0xd3, 0x4c, 0x99, 0x65, 0x13, 0xbe, 0xc0, 0xde, + 0x01, 0xbf, 0x82, 0xbf, 0x5a, 0xa4, 0x10, 0x63, 0x99, 0x67, 0x9d, 0x8c, 0x40, 0xde, 0x79, 0xa6, + 0x95, 0x86, 0x6c, 0x7a, 0x11, 0x19, 0xb2, 0x21, 0x24, 0xca, 0xba, 0x8d, 0x94, 0xfd, 0x6d, 0xdd, + 0x3a, 0xc9, 0x2e, 0xad, 0x5b, 0xe1, 0xec, 0xf2, 0xba, 0x2d, 0xf1, 0x41, 0x5b, 0x9e, 0xcd, 0x21, + 0x79, 0x33, 0x11, 0x97, 0x8f, 0xcd, 0xb0, 0x5b, 0x9b, 0xdb, 0x30, 0xc3, 0xec, 0x70, 0xf3, 0x76, + 0x28, 0x29, 0x41, 0x4f, 0xb5, 0xd8, 0x24, 0x7c, 0xd4, 0xac, 0x66, 0xcc, 0x9a, 0xef, 0x97, 0x01, + 0xaf, 0x35, 0x55, 0x55, 0x71, 0xd0, 0x1e, 0x07, 0x17, 0xa7, 0x2a, 0xe3, 0xac, 0xbd, 0x23, 0xa1, + 0x18, 0x4d, 0xda, 0xd1, 0x23, 0x6f, 0xbf, 0x73, 0x9e, 0xac, 0x9d, 0xdb, 0xcc, 0x26, 0xec, 0x60, + 0x28, 0x0e, 0x11, 0x98, 0xf8, 0x05, 0x59, 0x65, 0x4d, 0xed, 0xd5, 0xd2, 0xfe, 0xe0, 0xf5, 0x02, + 0xd6, 0x05, 0x45, 0x1c, 0x83, 0x74, 0xda, 0x3a, 0xc1, 0x55, 0xb2, 0xc3, 0x2a, 0x1e, 0x75, 0x85, + 0x32, 0xc9, 0x50, 0xdc, 0x9f, 0x66, 0x55, 0x46, 0xe2, 0xb4, 0xf9, 0x68, 0x9a, 0xd2, 0xdf, 0x15, + 0x6a, 0x58, 0x0d, 0x3c, 0xc6, 0xd1, 0x3e, 0xa3, 0xf1, 0xa5, 0x7e, 0x82, 0x6e, 0xc8, 0xbe, 0x8e, + 0xab, 0xbc, 0xe3, 0x74, 0x9f, 0x15, 0xd6, 0xf2, 0x47, 0xbc, 0x3f, 0xcc, 0xa1, 0x61, 0x02, 0x8c, + 0x7c, 0xaf, 0x53, 0x66, 0x2e, 0x38, 0x9b, 0x68, 0x38, 0xdb, 0xdd, 0xbd, 0x10, 0xd2, 0xaf, 0xe2, + 0xce, 0xd7, 0x89, 0x43, 0x06, 0x4a, 0xe4, 0x92, 0x48, 0x47, 0x36, 0x7c, 0xfd, 0xf8, 0xa9, 0xca, + 0xe8, 0x40, 0x0d, 0xff, 0x03, 0x51, 0xc5, 0xcf, 0x61, 0x59, 0xfc, 0x0f, 0x1f, 0x71, 0x37, 0x8f, + 0xdf, 0x51, 0x39, 0xed, 0xe6, 0x46, 0xb2, 0x1a, 0xc4, 0x55, 0x82, 0x0b, 0xcb, 0x83, 0x5f, 0xda, + 0x65, 0x5e, 0xda, 0x7e, 0xbe, 0xa6, 0xa1, 0xc2, 0x1b, 0x4a, 0x4b, 0xf2, 0x0e, 0xef, 0x79, 0x0e, + 0xcc, 0x75, 0x71, 0xf2, 0x6f, 0x4e, 0xc8, 0x59, 0x08, 0x7e, 0x46, 0x90, 0x04, 0xe3, 0xfc, 0xa6, + 0x1a, 0x43, 0x8f, 0x8f, 0x15, 0x4f, 0x02, 0x61, 0x58, 0x2a, 0x59, 0xcc, 0xf9, 0x3c, 0xa8, 0xc2, + 0x63, 0x33, 0x3f, 0x2e, 0xf3, 0x8f, 0xa2, 0xb9, 0x35, 0xd0, 0x77, 0x3d, 0x62, 0xb2, 0xae, 0x63, + 0x09, 0x95, 0xa7, 0x2b, 0x68, 0x69, 0x80, 0xbb, 0x1b, 0x6c, 0x81, 0xfd, 0x75, 0x3c, 0xae, 0xef, + 0x7c, 0x19, 0x6d, 0xb0, 0x4a, 0x6a, 0x85, 0x3a, 0x04, 0xf8, 0x62, 0xfd, 0x06, 0x8c, 0xef, 0x16, + 0x64, 0x25, 0x6d, 0xa5, 0x28, 0x52, 0x96, 0x57, 0x9e, 0x85, 0x83, 0xb0, 0x65, 0xa1, 0xb4, 0xed, + 0x1c, 0xe3, 0x96, 0xd2, 0xb7, 0xee, 0x50, 0x24, 0x69, 0xa4, 0xf1, 0x76, 0x64, 0x0b, 0x19, 0x17, + 0xef, 0xf1, 0xc0, 0x1c, 0x3b, 0x5a, 0x49, 0xab, 0x73, 0x03, 0x5e, 0xff, 0x4e, 0x2c, 0xf4, 0x74, + 0xc3, 0xec, 0x74, 0xad, 0x1a, 0xd6, 0x43, 0xb7, 0x9e, 0x81, 0x6e, 0xbd, 0x47, 0x1a, 0x85, 0xf0, + 0x69, 0x98, 0x6c, 0xd0, 0x21, 0x87, 0xa3, 0xdf, 0x92, 0xe7, 0x08, 0x92, 0x73, 0xf4, 0xa2, 0xc5, + 0xfb, 0x88, 0xbe, 0x26, 0x65, 0xd6, 0xac, 0x89, 0x5c, 0x4e, 0xd9, 0xa4, 0x53, 0xa5, 0x0f, 0x9b, + 0xf0, 0x44, 0x29, 0x3c, 0x09, 0x53, 0xf1, 0xcf, 0xd3, 0x9e, 0x5e, 0x25, 0x85, 0x2a, 0x61, 0xb5, + 0x3e, 0x8c, 0xbf, 0x5e, 0xb9, 0x30, 0xe3, 0x42, 0xe1, 0x7d, 0x1d, 0xbe, 0x0a, 0x7e, 0xcf, 0x72, + 0xa2, 0xda, 0xbe, 0xf5, 0xa0, 0x4f, 0x84, 0xb0, 0xce, 0x82, 0x80, 0x63, 0x66, 0xe8, 0xd9, 0xfc, + 0x65, 0x86, 0x2d, 0x11, 0x7a, 0x52, 0x62, 0xde, 0x72, 0x7d, 0x7d, 0x53, 0x97, 0x34, 0x31, 0xa8, + 0x78, 0xb9, 0x3e, 0x7a, 0x56, 0x18, 0x5e, 0x37, 0x73, 0xd0, 0xce, 0x10, 0xfe, 0x20, 0x52, 0x45, + 0x8f, 0x57, 0xa0, 0x20, 0x46, 0xef, 0x41, 0x35, 0xc9, 0x69, 0x50, 0xdb, 0x72, 0x55, 0xeb, 0x2b, + 0x17, 0x41, 0x52, 0x37, 0x1c, 0xd3, 0xfc, 0xb4, 0x1b, 0x17, 0xc0, 0x89, 0x37, 0x94, 0x96, 0x29, + 0x37, 0x24, 0xee, 0x19, 0x2a, 0xb0, 0x0c, 0xe5, 0x0f, 0x4a, 0xde, 0x76, 0x41, 0x29, 0x19, 0xc9, + 0x83, 0x7b, 0x3a, 0x4f, 0x3a, 0x0b, 0x94, 0xd6, 0x4f, 0x67, 0x31, 0x1e, 0xec, 0x5f, 0x5a, 0xda, + 0x2f, 0xbb, 0xd7, 0xc4, 0xbc, 0x88, 0xbf, 0x78, 0x50, 0xf8, 0xe2, 0x6c, 0x04, 0xf6, 0x67, 0x87, + 0x35, 0xfa, 0x67, 0x87, 0x6b, 0xf2, 0x50, 0xd6, 0x57, 0x91, 0x10, 0x4f, 0x76, 0x7d, 0x83, 0xa9, + 0x9f, 0x5b, 0xcb, 0xa6, 0x8a, 0x1d, 0xe1, 0x94, 0x84, 0xc6, 0xa6, 0x54, 0xd1, 0x8e, 0x0c, 0x46, + 0x3b, 0x92, 0x6a, 0x1a, 0x7f, 0xd0, 0xc6, 0x6a, 0xd4, 0xda, 0xb9, 0x27, 0x35, 0xbd, 0x2c, 0xa5, + 0x2d, 0x4c, 0xce, 0x64, 0x63, 0x65, 0x5a, 0xfc, 0x9c, 0x96, 0x48, 0x5b, 0x92, 0x76, 0xe2, 0x52, + 0xc6, 0x89, 0xd6, 0xe8, 0x2c, 0x5b, 0xd7, 0x91, 0x0a, 0x01, 0x2d, 0x98, 0xb4, 0xc2, 0x2b, 0xd7, + 0xab, 0x97, 0x91, 0xdb, 0x93, 0xc1, 0xeb, 0x57, 0xbc, 0x22, 0x6e, 0x4e, 0xe4, 0xad, 0x2d, 0xc9, + 0xed, 0x1d, 0xce, 0x94, 0x48, 0xab, 0x23, 0xfd, 0x8b, 0xa0, 0x4a, 0x90, 0xc0, 0x3b, 0x7b, 0x97, + 0xa4, 0xc2, 0x47, 0x61, 0xd2, 0xf3, 0x6c, 0xf3, 0x76, 0x24, 0x10, 0x0a, 0x43, 0x27, 0x8f, 0xb1, + 0x97, 0x84, 0x51, 0xdf, 0xec, 0x8e, 0x0b, 0x46, 0x89, 0xbc, 0x81, 0x59, 0xb6, 0x93, 0xf0, 0x5d, + 0x3e, 0x73, 0xdb, 0x5f, 0x60, 0x69, 0x0d, 0xe9, 0xb5, 0x60, 0x32, 0x56, 0x63, 0x17, 0xf3, 0xa9, + 0xc3, 0x0f, 0x42, 0x99, 0xb4, 0x4b, 0x6d, 0x4f, 0x79, 0x38, 0xed, 0x05, 0xc4, 0x85, 0x64, 0x09, + 0x4f, 0x2b, 0x15, 0x8a, 0x08, 0x9c, 0x4e, 0x99, 0x8c, 0xb4, 0x95, 0xb8, 0xf4, 0xc2, 0x0c, 0x25, + 0xd8, 0xd6, 0x09, 0x4c, 0x17, 0x41, 0xf0, 0xef, 0x3d, 0x0a, 0xef, 0x0b, 0x31, 0x44, 0x75, 0x57, + 0x38, 0x8d, 0xaa, 0x23, 0x4e, 0xb2, 0x42, 0xa0, 0xea, 0xa7, 0x49, 0x8a, 0x47, 0xbe, 0x80, 0x12, + 0x5a, 0x27, 0x12, 0x79, 0x5e, 0x99, 0xd4, 0xa7, 0xba, 0xfe, 0xb3, 0x56, 0xf0, 0xff, 0x3d, 0xef, + 0xf1, 0xc1, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, + 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, + 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xff, 0x7f, 0xf2, 0xe3, 0xf7, 0xe0, 0x5e, 0x62, 0xad, 0xe2, 0x4d, + 0x91, 0x1f, 0x47, 0x26, 0x44, 0x9e, 0x43, 0x79, 0xe2, 0x5a, 0xce, 0xab, 0xe2, 0xa3, 0x78, 0x18, + 0x5e, 0xae, 0x06, 0x20, 0xd5, 0x06, 0x45, 0x8f, 0x81, 0x68, 0x35, 0xc3, 0x1f, 0x8a, 0x11, 0x08, + 0xdb, 0x0f, 0x54, 0x71, 0x20, 0x28, 0x7e, 0xe4, 0x61, 0x4a, 0x58, 0x80, 0xdf, 0xfb, 0xc5, 0x04, + 0x05, 0x53, 0x75, 0x39, 0x38, 0x0a, 0xbd, 0x76, 0x83, 0xc1, 0x8b, 0x7f, 0x57, 0xc7, 0xd0, 0xfa, + 0xee, 0x98, 0x4a, 0x01, 0x0e, 0x33, 0x99, 0x43, 0x29, 0x4c, 0x63, 0xf2, 0xf6, 0x31, 0xbd, 0xb2, + 0xe6, 0x49, 0x06, 0x24, 0x1a, 0x68, 0x3e, 0xc0, 0xa9, 0xf2, 0xd1, 0x80, 0x6c, 0x67, 0xb7, 0x43, + 0xcb, 0x48, 0xf7, 0x03, 0x01, 0x1e, 0x6f, 0xbd, 0xfe, 0x29, 0xbf, 0x1b, 0xba, 0x9e, 0xe9, 0xef, + 0xa3, 0x08, 0x75, 0xaf, 0xf1, 0xed, 0x51, 0x4e, 0x41, 0xe1, 0x6a, 0x38, 0x5c, 0x0a, 0xfd, 0x1c, + 0x5f, 0x48, 0xdf, 0x83, 0xfe, 0xde, 0x4b, 0x77, 0xfe, 0x72, 0xe2, 0x08, 0x88, 0x4c, 0xba, 0xf2, + 0x9d, 0xa6, 0x55, 0x33, 0x5e, 0x18, 0x9a, 0x5a, 0xf0, 0x36, 0xd5, 0xb6, 0xa4, 0xd3, 0x74, 0x61, + 0xf0, 0x45, 0x8d, 0x1c, 0x98, 0xec, 0x87, 0x39, 0x75, 0x27, 0x85, 0x16, 0x06, 0xda, 0xdd, 0xee, + 0x16, 0x30, 0x93, 0xc4, 0xa6, 0x3b, 0x0f, 0x2f, 0x5b, 0x24, 0x74, 0xc6, 0x33, 0x92, 0xc2, 0xb3, + 0x8d, 0xf8, 0xe0, 0xec, 0xcc, 0xfe, 0x97, 0x1a, 0xdb, 0xe9, 0x05, 0x53, 0x07, 0xf9, 0xf6, 0x5f, + 0x1a, 0xc8, 0x83, 0x25, 0x82, 0x05, 0xed, 0x76, 0x47, 0xba, 0x78, 0x1c, 0x6b, 0x27, 0x56, 0xfe, + 0xc4, 0xf5, 0x84, 0xc1, 0xdc, 0xf9, 0x95, 0xc8, 0x01, 0x23, 0x86, 0x82, 0x92, 0x4f, 0xfd, 0x1a, + 0x6f, 0x01, 0xea, 0xd1, 0x68, 0x7e, 0x77, 0x44, 0xe5, 0x98, 0x1b, 0xb2, 0x0b, 0x2a, 0x57, 0x7f, + 0x8f, 0x4d, 0xce, 0xcc, 0x3d, 0xb9, 0x4a, 0xa3, 0xd7, 0x7f, 0xda, 0xab, 0x1d, 0xc0, 0xca, 0xd1, + 0xf7, 0x54, 0xf2, 0x2f, 0x63, 0xf2, 0xf4, 0x6b, 0x4f, 0xd5, 0x6a, 0x6d, 0x79, 0xcd, 0x8d, 0x1d, + 0x49, 0xd8, 0xc8, 0x0a, 0xa6, 0xf6, 0xa7, 0x06, 0xad, 0x85, 0xa0, 0x8a, 0x3a, 0xe7, 0x2d, 0xc3, + 0x4b, 0xc3, 0xf5, 0x97, 0x41, 0x7a, 0xb1, 0xe9, 0x89, 0x17, 0x9a, 0x83, 0x1b, 0x7c, 0x6f, 0xb6, + 0x5b, 0x69, 0x1b, 0x66, 0x7c, 0x4c, 0xae, 0x9c, 0x19, 0x90, 0x4f, 0xdc, 0xc2, 0xe6, 0x5f, 0xd2, + 0xc0, 0xe7, 0x7b, 0x98, 0x55, 0x2d, 0x3d, 0xc3, 0xc5, 0xcc, 0xe8, 0xbe, 0xb5, 0x10, 0xdc, 0xff, + 0x46, 0xcc, 0xdf, 0x1d, 0xa8, 0x3b, 0x22, 0xa0, 0x71, 0x7d, 0xa1, 0x27, 0xa0, 0x17, 0x39, 0x95, + 0xd5, 0x74, 0xbd, 0xd0, 0xd8, 0x33, 0xc1, 0xa1, 0x66, 0x07, 0xb5, 0x0d, 0xc9, 0x12, 0xab, 0x6d, + 0xf3, 0xe9, 0xc5, 0x65, 0xff, 0xfe, 0xfa, 0x0e, 0x8c, 0x89, 0xae, 0xf8, 0x81, 0xd7, 0xe2, 0xa6, + 0x55, 0x90, 0xe2, 0x26, 0x81, 0xc1, 0x74, 0x79, 0x71, 0xa6, 0xa2, 0xd3, 0xe6, 0xcb, 0x2f, 0x2d, + 0x11, 0x4f, 0xda, 0x92, 0x2e, 0xb4, 0xca, 0xf2, 0xbf, 0xa9, 0x41, 0x09, 0xbd, 0xa1, 0x34, 0x0b, + 0xdd, 0xf6, 0xdb, 0x51, 0xcd, 0x67, 0xa7, 0xe3, 0x29, 0xa6, 0x74, 0x7a, 0x4e, 0x78, 0x1a, 0x6d, + 0x7d, 0x63, 0x29, 0x76, 0x1d, 0x9f, 0x51, 0x87, 0xe1, 0x74, 0x97, 0xa2, 0xde, 0x12, 0x3d, 0xa2, + 0x67, 0xbd, 0x7e, 0x2b, 0x16, 0xf1, 0xff, 0x7a, 0x47, 0x56, 0xdb, 0xcf, 0xf1, 0x90, 0x98, 0x38, + 0x69, 0xb2, 0x87, 0x20, 0xd1, 0x61, 0x97, 0xa5, 0x52, 0x11, 0xcf, 0x7b, 0xec, 0xf7, 0xef, 0x94, + 0xdd, 0xd2, 0x85, 0x80, 0x6b, 0x52, 0x29, 0x58, 0x00, 0x77, 0xa5, 0x18, 0xb4, 0xc0, 0x1b, 0xaf, + 0x0d, 0xce, 0x0f, 0x89, 0x4c, 0x11, 0xc1, 0x80, 0xda, 0x1f, 0x82, 0xd9, 0x53, 0xce, 0x83, 0xe1, + 0x14, 0x2c, 0x62, 0x4f, 0x33, 0x40, 0x41, 0x4b, 0x3d, 0xc8, 0x79, 0x3a, 0x46, 0x44, 0x6f, 0x9f, + 0x09, 0x49, 0x23, 0x41, 0xd9, 0x33, 0x12, 0x96, 0xd5, 0x08, 0xd3, 0x90, 0x0f, 0x85, 0xf0, 0xe7, + 0x56, 0xf7, 0x26, 0x97, 0xb0, 0x07, 0xe9, 0x85, 0x82, 0x36, 0xe8, 0x6a, 0xe4, 0xf8, 0x5f, 0x2f, + 0xe6, 0xc1, 0x28, 0x3e, 0x9f, 0xc3, 0x1d, 0xeb, 0x6e, 0xc9, 0xe2, 0xf6, 0xa0, 0x4f, 0x7a, 0x64, + 0xed, 0x3a, 0x86, 0x97, 0x41, 0xfe, 0x23, 0x3b, 0x6f, 0xbe, 0x7d, 0x9e, 0x04, 0x22, 0x3b, 0xfa, + 0xf9, 0x35, 0x8d, 0xfd, 0xe6, 0x4e, 0xb9, 0xee, 0xaa, 0x04, 0xea, 0x23, 0xe3, 0x56, 0x96, 0x7a, + 0xa1, 0x57, 0xcd, 0xf0, 0x3c, 0x8c, 0x2f, 0x4e, 0x46, 0x56, 0xbc, 0x19, 0x29, 0xe3, 0x5e, 0x09, + 0x60, 0x47, 0xa3, 0x09, 0x0e, 0x28, 0xbc, 0x13, 0xb1, 0x05, 0x76, 0x98, 0x01, 0x82, 0xa9, 0x58, + 0x51, 0xab, 0x3e, 0x96, 0x4b, 0xd9, 0xeb, 0x55, 0xb8, 0xc0, 0x86, 0xee, 0xf8, 0xe1, 0x95, 0xf4, + 0xd7, 0x5a, 0x20, 0xaf, 0xb3, 0x22, 0x32, 0xae, 0xf2, 0x0a, 0x57, 0x53, 0xf5, 0x2d, 0x3d, 0xa4, + 0xe0, 0x8d, 0x08, 0xcc, 0x00, 0xd4, 0xf4, 0x3d, 0x63, 0xe8, 0x14, 0x79, 0xcc, 0x7b, 0x70, 0xd2, + 0x1e, 0xcb, 0xea, 0xed, 0xcb, 0xf3, 0xe0, 0xe8, 0xe7, 0x7a, 0x7d, 0x44, 0xe0, 0x0d, 0xa5, 0xb9, + 0x65, 0xd4, 0x71, 0x83, 0x8a, 0xc7, 0x1d, 0xf5, 0x56, 0x79, 0x70, 0xec, 0x2a, 0x7c, 0xb7, 0xe8, + 0x5e, 0xa8, 0x9c, 0xaf, 0x57, 0xf5, 0x70, 0xb9, 0x85, 0x37, 0x9a, 0xc5, 0xe6, 0xd0, 0x13, 0xe4, + 0x0d, 0xf8, 0x77, 0x5c, 0xf6, 0x46, 0xf4, 0xa9, 0xbb, 0xc6, 0x43, 0x16, 0xc8, 0x67, 0x0f, 0x0f, + 0xeb, 0x9d, 0xea, 0xe7, 0x6f, 0x44, 0xbf, 0x3d, 0xfe, 0xd6, 0xab, 0x31, 0x2a, 0x5d, 0x41, 0xbf, + 0x18, 0xfa, 0xd6, 0x5b, 0x2b, 0x81, 0xe7, 0xdf, 0x87, 0xf1, 0x49, 0x4d, 0x32, 0xfd, 0xae, 0x33, + 0x32, 0x85, 0xac, 0x1d, 0xf8, 0x13, 0x77, 0xe9, 0x01, 0x1e, 0xad, 0x26, 0x0c, 0xf8, 0x1d, 0x7b, + 0x92, 0x77, 0x1e, 0xaf, 0xb0, 0xb8, 0xd6, 0xeb, 0x94, 0x5a, 0xaf, 0xa6, 0x71, 0x95, 0xee, 0x7d, + 0x4c, 0x84, 0x5a, 0xe5, 0x82, 0x1b, 0x95, 0x49, 0x2e, 0x49, 0x64, 0x95, 0x20, 0xb6, 0xdc, 0x7f, + 0x98, 0x20, 0x0a, 0xde, 0xd9, 0xd5, 0x73, 0x90, 0xf3, 0x50, 0x46, 0x96, 0x3e, 0x6e, 0x7f, 0x1b, + 0x14, 0x12, 0x35, 0x5f, 0x74, 0xc2, 0x7d, 0x98, 0xb9, 0x87, 0x97, 0xa8, 0x1e, 0xa7, 0x31, 0x1f, + 0xc6, 0xed, 0x9c, 0xf1, 0xe1, 0x6c, 0x2b, 0x24, 0x4d, 0xed, 0x0f, 0x99, 0x3b, 0x47, 0xfb, 0xe3, + 0xfa, 0xd0, 0x9e, 0xde, 0x60, 0x3c, 0xba, 0x5f, 0xc2, 0xcb, 0x67, 0x46, 0xde, 0xf1, 0xf2, 0xe8, + 0xde, 0x18, 0xd7, 0x56, 0xff, 0x84, 0x35, 0x09, 0xc9, 0xd9, 0xe0, 0xf4, 0x91, 0x31, 0x84, 0x0f, + 0x0d, 0x96, 0xaa, 0x64, 0x34, 0xa9, 0x0f, 0xf7, 0xfb, 0x34, 0x62, 0x34, 0x89, 0x5f, 0x2c, 0xde, + 0x1d, 0x8f, 0xe6, 0x28, 0x33, 0xfd, 0x6e, 0x31, 0x12, 0x24, 0xfe, 0x80, 0x0c, 0xac, 0x6f, 0x5d, + 0x64, 0xbe, 0xbc, 0x13, 0xcb, 0xed, 0x65, 0x6c, 0x5a, 0xc1, 0xce, 0x8e, 0x2a, 0xfe, 0x2c, 0xb0, + 0x37, 0xdd, 0x93, 0x17, 0x99, 0x5a, 0x9a, 0xd5, 0x0e, 0x0c, 0xf1, 0x0d, 0x73, 0x61, 0xb8, 0x5f, + 0xa3, 0x5b, 0x4c, 0xa3, 0x59, 0x31, 0xa4, 0x15, 0xe6, 0x73, 0x0f, 0x29, 0x53, 0x7a, 0xf9, 0xa1, + 0x87, 0xfc, 0xec, 0x3b, 0x8a, 0xbd, 0xa1, 0xf4, 0xca, 0x4e, 0xe4, 0xee, 0x24, 0xbf, 0xf0, 0x15, + 0xdf, 0x5b, 0xa0, 0xc8, 0x22, 0x01, 0x16, 0x45, 0xa2, 0x0b, 0xac, 0x50, 0x36, 0x74, 0x01, 0x09, + 0x45, 0xaa, 0x0b, 0xcc, 0x51, 0xc4, 0x5d, 0x58, 0xae, 0x74, 0x3c, 0x90, 0x01, 0x69, 0x2e, 0x32, + 0x93, 0x80, 0x9f, 0x61, 0x12, 0xf3, 0x37, 0xa8, 0x4c, 0xda, 0xfa, 0xd8, 0xd8, 0xb5, 0xe7, 0x64, + 0xaa, 0xb2, 0xf9, 0xa9, 0xaa, 0x77, 0xef, 0xe6, 0xd8, 0x56, 0xd7, 0x84, 0x9c, 0xda, 0x7d, 0xe8, + 0xab, 0x3f, 0x3a, 0xc5, 0x5f, 0x07, 0xdf, 0x01, 0xeb, 0x68, 0x63, 0x2f, 0x79, 0x7b, 0xb8, 0x47, + 0xbd, 0x70, 0x3d, 0x3f, 0x36, 0xf6, 0x89, 0x84, 0x7c, 0xd9, 0xc4, 0x63, 0xa8, 0xc3, 0x1c, 0x93, + 0xaf, 0x50, 0x02, 0xc1, 0x8b, 0x79, 0xc9, 0x06, 0x8f, 0x4c, 0x0a, 0x03, 0x47, 0xc1, 0xb5, 0x85, + 0xcf, 0xe1, 0x9b, 0xc4, 0xa2, 0x97, 0x38, 0x24, 0x7d, 0x84, 0x5d, 0x5f, 0x33, 0xdf, 0x43, 0x20, + 0x32, 0x2a, 0xaa, 0x6c, 0x2b, 0x8f, 0x54, 0x9b, 0xf9, 0x90, 0xac, 0x80, 0xf9, 0x87, 0x79, 0x4a, + 0x64, 0xf3, 0x1c, 0xd5, 0xe5, 0xec, 0xf6, 0x04, 0xdb, 0xed, 0x27, 0x63, 0x25, 0x41, 0x25, 0x88, + 0x7f, 0x2c, 0x7b, 0xbf, 0x60, 0xb2, 0x6a, 0xab, 0x6b, 0x02, 0x1b, 0x5d, 0x35, 0x42, 0x3d, 0x8e, + 0x9d, 0x5f, 0x2c, 0x36, 0xb6, 0x68, 0x21, 0x9d, 0xc7, 0x2d, 0x37, 0x42, 0x4e, 0x98, 0x68, 0x72, + 0xae, 0xac, 0x7e, 0xe6, 0xe5, 0x7a, 0x5c, 0x9d, 0x3b, 0x00, 0xfc, 0x87, 0x5d, 0x95, 0x05, 0x57, + 0x23, 0xb9, 0x96, 0x7f, 0x58, 0x83, 0xb8, 0x96, 0x38, 0x29, 0xc8, 0xe2, 0x63, 0x69, 0x0a, 0x2a, + 0x17, 0xa4, 0x01, 0x62, 0x7d, 0x26, 0x0c, 0xd5, 0xe4, 0xf3, 0xa9, 0x34, 0x6f, 0xf7, 0x2b, 0xaa, + 0x89, 0xde, 0x4f, 0xf6, 0x8a, 0x20, 0xf6, 0x6b, 0x5b, 0x93, 0x06, 0x03, 0x69, 0xb1, 0x49, 0xde, + 0x08, 0x82, 0x80, 0xb0, 0x1b, 0x52, 0x6b, 0xf9, 0x7e, 0x84, 0xf9, 0xb9, 0xfc, 0xcb, 0x25, 0x03, + 0x90, 0x30, 0x44, 0x34, 0xcf, 0x13, 0xf1, 0xb3, 0x9f, 0x5d, 0xf6, 0x0d, 0xa5, 0x3f, 0x1d, 0xa4, + 0x09, 0x6c, 0x8e, 0xe1, 0x12, 0x62, 0xd2, 0xc8, 0xfd, 0x83, 0x68, 0x55, 0x23, 0xb3, 0xd0, 0x0b, + 0xf9, 0xcb, 0x93, 0x54, 0x88, 0x2b, 0xde, 0x10, 0xb1, 0x8a, 0x5c, 0x1b, 0x9f, 0xd0, 0x25, 0x3b, + 0x27, 0x37, 0x96, 0x82, 0x30, 0xb1, 0x8c, 0xa5, 0x20, 0x35, 0xfd, 0x52, 0xc3, 0xa3, 0x93, 0xcf, + 0x00, 0xfe, 0x09, 0xb6, 0x08, 0xba, 0x7f, 0xe9, 0x6b, 0x80, 0xd2, 0x88, 0xb4, 0x04, 0xc6, 0x07, + 0xd9, 0x86, 0xe3, 0xe4, 0xf1, 0xc3, 0xa4, 0x0a, 0xe2, 0x66, 0x31, 0x8c, 0x93, 0xd8, 0x3c, 0x31, + 0x1e, 0xe7, 0x8c, 0xaa, 0x3d, 0x1a, 0x87, 0x15, 0x11, 0x8f, 0x56, 0x6b, 0xe7, 0x47, 0xb0, 0x99, + 0xe5, 0x1d, 0xdf, 0xad, 0xa2, 0xbb, 0xc4, 0x88, 0x55, 0x64, 0x6b, 0xa9, 0x7a, 0x8e, 0x50, 0xaf, + 0x1f, 0x9a, 0xe0, 0x87, 0xed, 0x70, 0xa2, 0xe0, 0x69, 0xd1, 0x26, 0xb2, 0x06, 0x4c, 0xfb, 0x28, + 0x26, 0x18, 0x86, 0x88, 0x45, 0x10, 0x40, 0x8d, 0x1b, 0x48, 0x22, 0x67, 0x41, 0xf1, 0xeb, 0xea, + 0x33, 0x3c, 0xf9, 0xf5, 0x44, 0x02, 0x22, 0x57, 0xf8, 0x8c, 0xe5, 0xdc, 0x5b, 0x91, 0x95, 0xc4, + 0xb1, 0x74, 0xb1, 0x01, 0xf7, 0x0b, 0xb1, 0x8c, 0xe7, 0xe5, 0x52, 0xa5, 0xb7, 0x26, 0xb2, 0x41, + 0xce, 0xed, 0x38, 0x90, 0x75, 0x1d, 0xdb, 0x3b, 0x62, 0x6b, 0x79, 0x4b, 0xa0, 0xe2, 0x86, 0xaf, + 0xc7, 0x2c, 0xae, 0x9e, 0x8f, 0x1e, 0xac, 0xbb, 0xd2, 0x98, 0x4a, 0xc8, 0x33, 0x3f, 0x2e, 0x7a, + 0x4e, 0x1c, 0xb1, 0x81, 0x65, 0xdb, 0xbf, 0x72, 0x59, 0xb1, 0xfb, 0x9e, 0xee, 0xb4, 0xc6, 0x46, + 0x37, 0xcd, 0x1a, 0x8e, 0x26, 0x62, 0xad, 0xf5, 0xa9, 0x0a, 0xb0, 0xdd, 0x2d, 0xf9, 0x33, 0x57, + 0x90, 0x09, 0x8a, 0xa4, 0x36, 0xc2, 0xcf, 0x16, 0xf3, 0x88, 0xba, 0xa6, 0xd0, 0x23, 0xdd, 0xa5, + 0x01, 0xb9, 0x26, 0xc0, 0xb4, 0x12, 0x72, 0x0e, 0x08, 0x76, 0x99, 0x7d, 0x9e, 0x2d, 0x89, 0xad, + 0xa9, 0x3a, 0xdb, 0xd5, 0x67, 0x66, 0x2a, 0xfa, 0xb3, 0xd2, 0xdd, 0xc2, 0x1b, 0x4a, 0x4b, 0x74, + 0x63, 0x22, 0x59, 0x37, 0xe6, 0xfe, 0xbd, 0x42, 0xb4, 0xa8, 0x69, 0xd7, 0xcb, 0x42, 0x7e, 0x52, + 0x3d, 0xd4, 0xe4, 0x5c, 0xb6, 0xe1, 0xfc, 0xa3, 0x15, 0xdf, 0x7c, 0x5e, 0x00, 0x5a, 0x87, 0x1b, + 0x6d, 0x95, 0xdc, 0xff, 0xa1, 0x38, 0xdd, 0xad, 0x2d, 0xb2, 0x06, 0xb2, 0x91, 0x54, 0x70, 0x2f, + 0xae, 0x2b, 0xee, 0xf1, 0x6f, 0x47, 0xc8, 0xb8, 0x71, 0xdb, 0x99, 0x63, 0x1f, 0xdc, 0x47, 0x73, + 0xcf, 0xdb, 0xe5, 0x23, 0x3c, 0x2d, 0x13, 0x5a, 0x56, 0xda, 0x42, 0x70, 0xd0, 0xaf, 0x8f, 0x61, + 0x5f, 0xa1, 0x5c, 0xdb, 0xd8, 0x2e, 0xca, 0x2e, 0xf4, 0x0b, 0xe6, 0x40, 0x35, 0xdd, 0x5c, 0x7d, + 0x29, 0xbd, 0xdc, 0x49, 0x77, 0x8e, 0x4e, 0xbd, 0x0a, 0xc6, 0xa5, 0xa6, 0x97, 0x69, 0xb1, 0x7b, + 0x12, 0x11, 0xb5, 0x85, 0x99, 0x07, 0xd5, 0xe4, 0x8b, 0x4a, 0x62, 0xc2, 0x4f, 0xbf, 0x85, 0x7f, + 0xd3, 0xed, 0xff, 0x65, 0x78, 0xcc, 0x55, 0x8f, 0x95, 0x5a, 0xe1, 0xfe, 0x61, 0x3d, 0xc8, 0x5b, + 0xbf, 0x1a, 0xd6, 0x77, 0xe3, 0xe4, 0xa5, 0x7a, 0xee, 0xac, 0x9e, 0x09, 0x4f, 0x2c, 0x9b, 0x68, + 0x3a, 0xa3, 0x3b, 0xbf, 0xab, 0x13, 0x6e, 0xef, 0x52, 0x16, 0x4a, 0x87, 0x3a, 0x8c, 0x23, 0xe9, + 0xa7, 0xcd, 0xd7, 0xb9, 0xfb, 0xdb, 0x28, 0x47, 0x58, 0xdc, 0x8a, 0xe6, 0xd4, 0xd6, 0x0a, 0x37, + 0xb4, 0x5b, 0xa9, 0x4f, 0xd5, 0x83, 0x68, 0x58, 0x5e, 0x00, 0x2d, 0xb0, 0xa6, 0x59, 0x83, 0x3e, + 0xa9, 0xbf, 0xc7, 0xa0, 0x40, 0x1c, 0x35, 0x87, 0x82, 0xc3, 0xa5, 0x9c, 0xc9, 0x9f, 0x66, 0x95, + 0x21, 0xe3, 0x6a, 0xac, 0xf0, 0xe0, 0x6b, 0x14, 0x04, 0xde, 0xbb, 0xb9, 0xc6, 0x1f, 0x98, 0xa7, + 0x0a, 0x79, 0x4e, 0x89, 0xb9, 0x66, 0x88, 0x7f, 0xac, 0x7e, 0x3e, 0x08, 0xae, 0x30, 0xb8, 0xd3, + 0x46, 0xed, 0x93, 0x26, 0x15, 0xbf, 0x4d, 0xe3, 0xf7, 0x72, 0x51, 0xf6, 0xbe, 0x9a, 0x76, 0x15, + 0xd4, 0xa1, 0x9b, 0xe4, 0x45, 0xb5, 0x7c, 0x74, 0x95, 0x51, 0xa0, 0xfb, 0x93, 0x9f, 0x94, 0x86, + 0x13, 0x7f, 0xab, 0x74, 0x15, 0x81, 0x00, 0x93, 0xfd, 0x75, 0xb2, 0x01, 0xff, 0xe7, 0x03, 0x04, + 0xcb, 0xf7, 0x7e, 0xfc, 0xb5, 0xc7, 0xe5, 0xf1, 0xff, 0xab, 0x01, 0x26, 0x91, 0x41, 0xfe, 0xeb, + 0xc3, 0xff, 0x3e, 0xf8, 0xc7, 0x03, 0x8b, 0x67, 0xc7, 0xd5, 0xaf, 0x7f, 0x75, 0x19, 0x02, 0x41, + 0xe5, 0xbf, 0x7b, 0xc8, 0xd5, 0x7f, 0xdb, 0xe3, 0xf5, 0xf4, 0x64, 0x48, 0xf8, 0xef, 0xa7, 0x22, + 0x01, 0x8f, 0x90, 0x8b, 0x24, 0x82, 0x7f, 0xbe, 0x10, 0x8c, 0xef, 0x71, 0x5e, 0xbb, 0xfc, 0xaf, + 0x1e, 0x22, 0x01, 0x64, 0xc7, 0x69, 0x42, 0xe8, 0xf5, 0x38, 0x80, 0x67, 0xef, 0xee, 0x09, 0x7e, + 0x34, 0x88, 0xfe, 0xd9, 0xe3, 0xc7, 0xa9, 0x80, 0xff, 0xd5, 0x03, 0xfa, 0x57, 0x0f, 0xe4, 0x6f, + 0xdf, 0x29, 0xf0, 0x7a, 0x16, 0x32, 0x97, 0x57, 0x99, 0xfc, 0xc7, 0xff, 0x04, 0xaf, 0x67, 0x11, + 0x09, 0x79, 0xff, 0x79, 0xdc, 0x3f, 0xb5, 0xfa, 0xf7, 0x53, 0xde, 0xeb, 0x6b, 0x70, 0xa0, 0xff, + 0xee, 0xf1, 0x7a, 0xf0, 0x8f, 0xd3, 0x8b, 0x7e, 0x24, 0x60, 0xf8, 0x7f, 0x58, 0xaf, 0x8f, 0x20, + 0xbf, 0x31, 0x5a, 0x3e, 0x4c, 0x04, 0xb6, 0xba, 0x24, 0xaf, 0x04, 0xeb, 0xcd, 0xdc, 0x7f, 0x47, + 0xdc, 0xc3, 0xff, 0x1d, 0x71, 0x7f, 0xb7, 0x9a, 0xca, 0xa1, 0xbe, 0xe9, 0x8f, 0x88, 0xfb, 0x2f, + 0x53, 0x25, 0x9c, 0xea, 0x0f, 0xf3, 0x5c, 0xe9, 0xa7, 0x35, 0xe6, 0xce, 0xeb, 0x38, 0x1d, 0x98, + 0x34, 0xc7, 0x00, 0xca, 0x7f, 0x19, 0xf8, 0xc1, 0xaa, 0x8a, 0x3f, 0x95, 0x08, 0xd6, 0xcf, 0xfd, + 0xb9, 0x94, 0x77, 0xb4, 0xb5, 0xf6, 0xd5, 0xed, 0x7a, 0x42, 0x79, 0x13, 0xd7, 0xa3, 0xc8, 0x6a, + 0xe9, 0x0d, 0x73, 0x65, 0x68, 0x58, 0xb8, 0xd7, 0x68, 0x65, 0x01, 0x13, 0xec, 0x9d, 0xeb, 0x53, + 0xbc, 0x9e, 0x0c, 0x46, 0xae, 0xb8, 0x5d, 0x35, 0x14, 0x84, 0xaa, 0xf5, 0xdf, 0xd6, 0x3d, 0xcd, + 0x78, 0xe9, 0xcf, 0x24, 0x22, 0xe0, 0x29, 0xbf, 0x1e, 0x2a, 0x8a, 0x10, 0xaf, 0x15, 0x2c, 0xed, + 0x7a, 0x69, 0xfe, 0x92, 0xe6, 0x81, 0xf6, 0x3f, 0x62, 0xef, 0xbd, 0x4b, 0x9b, 0x45, 0xef, 0x86, + 0xe1, 0x2e, 0x7f, 0x20, 0x74, 0xa4, 0x80, 0x81, 0xe3, 0xba, 0x2f, 0x16, 0xb8, 0x7f, 0xb9, 0xd1, + 0xde, 0x8f, 0x9c, 0x9a, 0xe9, 0x43, 0xb9, 0x52, 0x57, 0xa8, 0x90, 0xdf, 0x6f, 0xf4, 0x25, 0xe3, + 0x6d, 0xfc, 0x92, 0x7b, 0x72, 0x9e, 0xb7, 0xe8, 0xf7, 0x9f, 0x63, 0x11, 0x5b, 0x25, 0x4d, 0xa7, + 0x9e, 0x5e, 0x5d, 0x00, 0x45, 0x08, 0x4e, 0xac, 0xe9, 0x43, 0x36, 0xc5, 0x89, 0x48, 0x56, 0xfe, + 0xb5, 0x5e, 0xf0, 0x4a, 0x54, 0x5b, 0xb4, 0xd6, 0xc6, 0xaf, 0x13, 0xfd, 0x95, 0x3f, 0x01, 0x3c, + 0x3e, 0x4c, 0x9b, 0xd4, 0x52, 0x5b, 0x1b, 0x1b, 0x09, 0x6b, 0xfb, 0x69, 0x95, 0xe5, 0x8f, 0x63, + 0x4a, 0x3e, 0xdf, 0xd9, 0x10, 0x7e, 0xe0, 0x70, 0xf5, 0x50, 0x20, 0xfb, 0xc7, 0x16, 0x6d, 0x11, + 0x05, 0x79, 0x57, 0xcf, 0x25, 0x87, 0xd2, 0x37, 0x5b, 0x34, 0xc3, 0xee, 0xb8, 0x08, 0x33, 0x4d, + 0x7e, 0xae, 0x6d, 0x46, 0x7b, 0x43, 0x69, 0xf9, 0x73, 0xee, 0x01, 0xf6, 0x83, 0x17, 0x9b, 0x88, + 0x5f, 0xa7, 0x75, 0x7d, 0x9b, 0x0a, 0x2e, 0xa0, 0x1b, 0x8c, 0x56, 0x13, 0x1c, 0xd3, 0x05, 0x36, + 0x21, 0x7f, 0xa8, 0x4c, 0xbf, 0x36, 0x28, 0x0b, 0xff, 0x51, 0x67, 0x58, 0xa2, 0x67, 0x9c, 0x63, + 0x66, 0xd5, 0xca, 0xfa, 0xf9, 0xf5, 0x08, 0xdb, 0x51, 0x31, 0x46, 0xf1, 0x83, 0x6d, 0x84, 0x6d, + 0x76, 0xad, 0x3b, 0xef, 0x54, 0xed, 0x17, 0x7d, 0xeb, 0xf2, 0x02, 0x17, 0x3c, 0xa5, 0x64, 0xbd, + 0x5e, 0x7c, 0x0f, 0x95, 0xba, 0xe3, 0x2b, 0x25, 0x7d, 0x5a, 0x2d, 0x31, 0x09, 0x12, 0xfa, 0xc7, + 0xb3, 0x01, 0xb2, 0x19, 0xd4, 0x21, 0xca, 0x2c, 0x68, 0x52, 0xd1, 0x37, 0x43, 0x60, 0x3a, 0x34, + 0x86, 0x5c, 0x7c, 0x42, 0xb1, 0x06, 0xd9, 0xbb, 0x80, 0xce, 0xc1, 0x87, 0xd5, 0x6c, 0x9b, 0x3e, + 0x38, 0xc3, 0x1d, 0xf6, 0xc7, 0xec, 0x8f, 0x4b, 0xb2, 0x95, 0x5f, 0xef, 0xea, 0x57, 0xa8, 0xde, + 0xd9, 0x97, 0x1b, 0xa9, 0x2b, 0xd6, 0x83, 0xe6, 0xc5, 0xc2, 0x39, 0x9a, 0xc9, 0x11, 0xeb, 0x4e, + 0xa8, 0xba, 0x2b, 0x1f, 0x0a, 0xea, 0x5a, 0x46, 0x9a, 0x60, 0xfb, 0xfa, 0x3a, 0x34, 0xb0, 0x38, + 0x10, 0x94, 0xe5, 0x2a, 0xe1, 0x43, 0x86, 0xbb, 0x84, 0x8b, 0xbf, 0x1f, 0xa5, 0x42, 0x58, 0x09, + 0xbc, 0x42, 0xd6, 0x34, 0xeb, 0x95, 0x2e, 0x53, 0x01, 0x76, 0xe4, 0x09, 0x20, 0x02, 0x93, 0x29, + 0xb8, 0xd2, 0xfe, 0xb8, 0xcc, 0xe1, 0xdb, 0x27, 0xa3, 0x1c, 0xf6, 0xc5, 0x6d, 0x04, 0xcc, 0xd0, + 0xfc, 0x28, 0xcf, 0xe2, 0x3f, 0x93, 0xe7, 0x25, 0x38, 0x1a, 0x58, 0x03, 0x60, 0x12, 0x7b, 0x0d, + 0x75, 0x07, 0xc9, 0x9c, 0x18, 0xdf, 0x5f, 0x6c, 0xe9, 0xf1, 0x68, 0x80, 0x4b, 0xa4, 0x7c, 0x19, + 0x41, 0x2b, 0xd9, 0x43, 0x58, 0x6a, 0x2b, 0xc2, 0x46, 0x77, 0xdb, 0x08, 0x13, 0xb0, 0x78, 0x57, + 0x18, 0x32, 0x50, 0x12, 0x5f, 0xfb, 0x08, 0x22, 0x3f, 0x5b, 0xea, 0xd0, 0xda, 0x1b, 0x4a, 0x2b, + 0xf7, 0x6c, 0x06, 0x2f, 0x6d, 0xad, 0x55, 0xa9, 0x4e, 0xc2, 0x3c, 0x3b, 0xbc, 0x88, 0xf2, 0x1d, + 0x83, 0x47, 0x80, 0x57, 0x85, 0xd7, 0x4a, 0x12, 0xac, 0x17, 0x68, 0x59, 0x5d, 0xf0, 0x26, 0xa7, + 0x0d, 0x91, 0x00, 0x00, 0x3c, 0x3a, 0xfc, 0x80, 0x3f, 0xf0, 0x03, 0x74, 0xc6, 0x86, 0xf9, 0xbc, + 0xa1, 0xdd, 0x1d, 0x23, 0x6b, 0x2d, 0x0d, 0x41, 0xff, 0x00, 0x4a, 0xed, 0xd7, 0xc1, 0xaa, 0x3a, + 0x66, 0x0f, 0x70, 0x8b, 0x77, 0x04, 0x02, 0xe8, 0xb1, 0xee, 0xab, 0x0d, 0xeb, 0xfd, 0xe5, 0x19, + 0x1b, 0xdc, 0x12, 0xdc, 0x22, 0x00, 0xd3, 0x29, 0xf9, 0x96, 0xeb, 0x3a, 0xc0, 0xc1, 0x6c, 0x30, + 0xf0, 0xd4, 0xba, 0xaa, 0x05, 0x94, 0x02, 0x7e, 0x00, 0xa9, 0x3a, 0x11, 0xd2, 0x87, 0xa9, 0xdd, + 0x75, 0x94, 0x31, 0x08, 0xa1, 0x2f, 0x08, 0xe5, 0xd6, 0x47, 0x60, 0xbc, 0xf1, 0xed, 0x49, 0xba, + 0x38, 0xc4, 0x5a, 0x73, 0x61, 0x9b, 0x70, 0x39, 0x50, 0x3e, 0x73, 0xe2, 0x94, 0x36, 0xe0, 0x38, + 0x49, 0xa1, 0xc6, 0xf5, 0x49, 0x36, 0x2b, 0x74, 0x20, 0x1f, 0x52, 0x80, 0x3d, 0x8a, 0xe2, 0x7f, + 0xc2, 0x1f, 0x46, 0x0c, 0x4e, 0x0b, 0x66, 0x24, 0xe3, 0x3c, 0x3b, 0xca, 0xde, 0xb1, 0xc6, 0x15, + 0xa9, 0x7c, 0xb5, 0x4f, 0xe7, 0x88, 0x1d, 0xf5, 0x0f, 0x6c, 0x97, 0x95, 0xc0, 0x80, 0x12, 0x88, + 0x24, 0x68, 0xeb, 0xd8, 0x22, 0xba, 0xc6, 0x87, 0x7f, 0x49, 0x0e, 0xec, 0x71, 0xf8, 0x04, 0x17, + 0x3b, 0x26, 0x75, 0xe3, 0x7a, 0x8d, 0xce, 0xe4, 0x42, 0xb0, 0x9e, 0x24, 0x62, 0xf1, 0xed, 0x81, + 0xbd, 0x6d, 0xbf, 0x7e, 0x21, 0xa0, 0xdb, 0xed, 0xea, 0xa5, 0x42, 0x18, 0x9a, 0x93, 0xca, 0x82, + 0x52, 0x32, 0x55, 0x86, 0xff, 0x12, 0x30, 0x95, 0x9e, 0xf9, 0x05, 0x55, 0x7a, 0xdd, 0xbf, 0xc0, + 0xd3, 0x09, 0x31, 0x46, 0x9e, 0x6d, 0x4b, 0x9e, 0x68, 0x80, 0x6a, 0xac, 0xa8, 0xc4, 0xba, 0x64, + 0xf6, 0xeb, 0xdb, 0x68, 0x9f, 0xc4, 0xae, 0xf0, 0x9f, 0xa3, 0x71, 0xbb, 0xec, 0x37, 0x94, 0xd6, + 0x16, 0xcb, 0xa6, 0x0a, 0x6e, 0x0c, 0x5a, 0xa3, 0x3d, 0xa1, 0xf5, 0xfa, 0x45, 0x12, 0x37, 0x99, + 0xe9, 0x34, 0xae, 0x0b, 0x9e, 0xcb, 0xf2, 0x0a, 0xf1, 0xd3, 0xaa, 0xf2, 0xd8, 0xfb, 0x8f, 0x47, + 0x32, 0x2a, 0x54, 0xa5, 0x83, 0x57, 0x37, 0x70, 0x43, 0x2a, 0xd6, 0x20, 0x72, 0x1a, 0x54, 0x75, + 0x7f, 0x08, 0x72, 0x85, 0xc6, 0x2a, 0x18, 0x3f, 0x4d, 0xa7, 0x64, 0xba, 0x53, 0x84, 0x6b, 0xb8, + 0xfd, 0xf6, 0x17, 0x13, 0x80, 0x2a, 0x44, 0x41, 0xb1, 0x5e, 0x21, 0xa4, 0x40, 0xda, 0x2c, 0x99, + 0x2c, 0x27, 0x05, 0xf0, 0xe2, 0x44, 0x47, 0xa4, 0x0b, 0xc0, 0x0f, 0x87, 0x70, 0x36, 0xd0, 0x9e, + 0xa5, 0x95, 0x3f, 0xd2, 0x33, 0x00, 0x4e, 0x19, 0x4e, 0xe6, 0x98, 0x36, 0x09, 0xf2, 0xda, 0x8f, + 0x39, 0x94, 0x0d, 0x6e, 0x38, 0xeb, 0xc0, 0x8e, 0xc7, 0x97, 0x5d, 0xc3, 0x36, 0x03, 0xaf, 0x4f, + 0x77, 0xd3, 0xaf, 0x0d, 0x04, 0x19, 0x23, 0x03, 0xf6, 0x54, 0xad, 0xc9, 0xc6, 0x7e, 0x0f, 0x08, + 0xad, 0x76, 0x24, 0x20, 0x43, 0x5d, 0x15, 0xd4, 0xe0, 0x72, 0x74, 0x29, 0xb9, 0xa0, 0xd5, 0xd7, + 0xe7, 0x80, 0xc8, 0xeb, 0xbe, 0x66, 0xd7, 0x11, 0x60, 0x94, 0x0e, 0xf8, 0x68, 0x01, 0xe8, 0xf0, + 0xbb, 0x24, 0x36, 0x8b, 0x1f, 0x25, 0x58, 0x00, 0x3f, 0xda, 0x67, 0xdd, 0x13, 0x18, 0x8a, 0x03, + 0xf0, 0x2f, 0x2d, 0x10, 0xd3, 0xff, 0x12, 0x90, 0x55, 0x88, 0x2e, 0x15, 0x14, 0x46, 0xbb, 0x7d, + 0xd3, 0x7e, 0x14, 0x61, 0xd2, 0x95, 0xf7, 0x87, 0x4c, 0x55, 0x19, 0x91, 0xdf, 0xe5, 0x4b, 0xa5, + 0xc0, 0x63, 0x90, 0xad, 0x1d, 0x3e, 0x46, 0xd8, 0xe1, 0x6b, 0x04, 0xd8, 0x2e, 0x77, 0xd9, 0xdf, + 0xb5, 0xeb, 0x89, 0xad, 0xc2, 0x6c, 0xc7, 0x97, 0x3c, 0xc0, 0xa3, 0x27, 0x39, 0xec, 0x61, 0x52, + 0x6f, 0x2b, 0x89, 0x63, 0x4f, 0xbe, 0xa6, 0x85, 0x37, 0x24, 0x07, 0x83, 0x2f, 0xe9, 0x7a, 0x41, + 0x92, 0x36, 0x2a, 0x42, 0x13, 0xf8, 0xe7, 0xc8, 0x45, 0x98, 0xf1, 0x86, 0xd2, 0xf4, 0x8f, 0x7c, + 0x6b, 0x17, 0x59, 0x82, 0x65, 0xf8, 0x89, 0xc8, 0x3b, 0xee, 0xdf, 0x4c, 0x64, 0xb2, 0x1e, 0x32, + 0xc9, 0xb5, 0xbd, 0x4b, 0x1a, 0x8b, 0x27, 0xb8, 0x25, 0x06, 0x3c, 0x38, 0x32, 0x76, 0xf3, 0x03, + 0x69, 0x20, 0x1f, 0x5e, 0xfa, 0xd0, 0xfa, 0xf3, 0xe9, 0x50, 0x34, 0x30, 0x80, 0x09, 0x03, 0xa0, + 0xf3, 0xff, 0x3a, 0xee, 0xe7, 0x7b, 0x52, 0x39, 0x4d, 0xe8, 0xfe, 0x05, 0x15, 0x34, 0x76, 0x9b, + 0xd2, 0xcb, 0xb4, 0x1e, 0x8b, 0x2b, 0x5a, 0x37, 0x2f, 0x4a, 0x6d, 0xeb, 0x66, 0xa4, 0xd4, 0xb4, + 0x7a, 0xa4, 0x82, 0xc0, 0x76, 0xe2, 0x67, 0x87, 0xa4, 0xb6, 0xc5, 0x13, 0x4d, 0xe9, 0x81, 0x29, + 0x6a, 0x44, 0x22, 0xb8, 0x7f, 0x0d, 0xe8, 0xde, 0xb6, 0xc8, 0x47, 0x26, 0x7c, 0x6e, 0xcd, 0x79, + 0xda, 0x4f, 0x88, 0xef, 0xbb, 0xd7, 0xa8, 0xa9, 0xd5, 0xc3, 0xe6, 0x54, 0x3a, 0x7d, 0xa0, 0x67, + 0x3c, 0xda, 0xba, 0xae, 0x05, 0x4a, 0xf2, 0xb4, 0x4a, 0xb6, 0xd3, 0x6d, 0x62, 0x14, 0x81, 0xf4, + 0x10, 0x6b, 0x98, 0xfc, 0x96, 0xb6, 0x11, 0x88, 0x24, 0x5a, 0x60, 0xd5, 0xbb, 0xa7, 0xbf, 0x6c, + 0x5d, 0xbd, 0x28, 0xca, 0xad, 0xd6, 0x72, 0x6c, 0xd0, 0xaa, 0xe2, 0x39, 0x51, 0x35, 0x3a, 0x91, + 0x24, 0x8e, 0xf5, 0x73, 0x84, 0x29, 0x3f, 0xa3, 0xe7, 0xd1, 0x56, 0x29, 0x91, 0x91, 0x00, 0x37, + 0x7e, 0xaa, 0x51, 0x87, 0x07, 0xf0, 0x92, 0x5b, 0x3e, 0x1f, 0xc8, 0x95, 0xbe, 0x78, 0x15, 0x79, + 0xab, 0x6d, 0xc5, 0xa8, 0x95, 0xbc, 0x9a, 0x10, 0xc2, 0x5d, 0x62, 0x89, 0x2d, 0xd0, 0x0d, 0x1e, + 0xe7, 0xc4, 0xac, 0x2b, 0xdf, 0x25, 0x7d, 0xa8, 0x1d, 0x6a, 0x0e, 0x54, 0xdd, 0x8b, 0x15, 0x6a, + 0xab, 0x37, 0x68, 0x9b, 0x8d, 0x38, 0xb9, 0x3f, 0x30, 0xf4, 0xf6, 0xb2, 0x74, 0x87, 0x7d, 0x9a, + 0x58, 0x10, 0x9b, 0x29, 0x71, 0xa3, 0xdd, 0xe5, 0xac, 0x5a, 0xda, 0xdb, 0x4e, 0x66, 0x8e, 0x73, + 0x76, 0xb8, 0xf8, 0xfa, 0x29, 0x61, 0x28, 0x9b, 0xfb, 0x9b, 0x1a, 0x94, 0x30, 0xf3, 0x0d, 0xa5, + 0xf5, 0xdc, 0x4b, 0x71, 0x2f, 0xa0, 0x81, 0xe2, 0xcd, 0xa7, 0x12, 0x70, 0x4f, 0x7c, 0xb2, 0xe4, + 0x22, 0x77, 0x74, 0x6e, 0x15, 0xa2, 0xd7, 0xd7, 0xc6, 0xb2, 0xa3, 0x6e, 0x52, 0x9c, 0x6a, 0x19, + 0xd0, 0xdc, 0x09, 0x3a, 0x16, 0x97, 0x1d, 0xe8, 0xb8, 0x5f, 0xdd, 0xfc, 0x9a, 0x66, 0x55, 0x4d, + 0x0d, 0x3f, 0x56, 0x3c, 0xae, 0xb4, 0xf6, 0xc4, 0x35, 0x84, 0x6b, 0x86, 0x36, 0x5b, 0x6b, 0xe9, + 0x92, 0xd5, 0x37, 0xcd, 0x60, 0xbc, 0x41, 0x15, 0x67, 0x09, 0xe7, 0xd2, 0xd2, 0xf3, 0x72, 0x63, + 0x80, 0x57, 0x25, 0x95, 0x69, 0x0a, 0xd3, 0x93, 0x66, 0x16, 0xa3, 0xfb, 0xf6, 0xe2, 0xff, 0xb0, + 0xf7, 0x76, 0x3f, 0x89, 0x64, 0x5d, 0xdf, 0xf0, 0xf3, 0x7f, 0xbc, 0xa7, 0x97, 0xd3, 0x01, 0x2f, + 0xdb, 0x64, 0xee, 0xc7, 0x9e, 0xd0, 0x1d, 0xbb, 0x8f, 0xc1, 0x51, 0x12, 0xa0, 0x20, 0x40, 0xa3, + 0x27, 0x83, 0x44, 0x10, 0x4c, 0xb0, 0xc1, 0x20, 0x8d, 0xfd, 0x3f, 0x28, 0x68, 0x5a, 0x45, 0x4f, + 0x2c, 0x09, 0x14, 0x05, 0x09, 0x74, 0x15, 0x51, 0xba, 0xe4, 0x58, 0xbc, 0xd4, 0x44, 0xad, 0x22, + 0x50, 0x0d, 0x9c, 0x0c, 0x12, 0xa1, 0x91, 0x44, 0x1b, 0x88, 0xa2, 0xce, 0xbb, 0x77, 0x81, 0xdf, + 0xd2, 0x33, 0xf7, 0xd5, 0xf7, 0x3d, 0xcf, 0xfb, 0xdc, 0x2f, 0xeb, 0xa0, 0x42, 0x7d, 0xec, 0xaa, + 0x5d, 0xab, 0xd6, 0xc7, 0x6f, 0x6d, 0xf6, 0xda, 0xcb, 0x57, 0xd3, 0xbb, 0xb5, 0xc2, 0x9d, 0x8b, + 0x9c, 0x29, 0xb5, 0xb8, 0x34, 0xf7, 0xc2, 0x36, 0x79, 0x8c, 0x0a, 0x5e, 0x48, 0xf7, 0x72, 0x6a, + 0x4d, 0x9a, 0x60, 0x72, 0x3f, 0x17, 0x30, 0xb7, 0x50, 0x65, 0x5a, 0xf7, 0xd5, 0x12, 0x4c, 0xe6, + 0x88, 0x27, 0x1a, 0x4f, 0x8c, 0x89, 0x8e, 0xc7, 0x7e, 0xf3, 0x9f, 0x51, 0x13, 0x73, 0x9d, 0xf9, + 0x01, 0x84, 0xd0, 0xbe, 0x11, 0x4b, 0x09, 0xda, 0x67, 0x32, 0x13, 0x1d, 0x5d, 0xbf, 0x98, 0xbe, + 0xcc, 0x6e, 0x6c, 0xf8, 0x9c, 0x51, 0xde, 0xcf, 0x71, 0xd5, 0x39, 0xbd, 0x37, 0x30, 0x47, 0x9e, + 0xf5, 0x3a, 0x4e, 0xbc, 0x3d, 0xfd, 0xc8, 0xd2, 0xdc, 0xb0, 0x63, 0x8c, 0xfc, 0x7d, 0xb5, 0x3c, + 0xb0, 0x94, 0x47, 0xa8, 0x10, 0x41, 0x77, 0x8c, 0x17, 0x42, 0x65, 0xfb, 0xc0, 0x18, 0x41, 0xab, + 0x9f, 0x9b, 0x74, 0xcf, 0x73, 0xa1, 0x19, 0xfa, 0x83, 0x5d, 0xfa, 0x6b, 0xe5, 0x45, 0xc1, 0x88, + 0x20, 0x0e, 0xb1, 0xfe, 0x60, 0xa1, 0x34, 0x39, 0xb6, 0x55, 0x63, 0xf9, 0x35, 0xb1, 0xd1, 0xeb, + 0x13, 0x0d, 0x0e, 0x61, 0x46, 0x39, 0xa3, 0x5b, 0xa9, 0x6e, 0x23, 0x44, 0xa9, 0xbf, 0x5b, 0x8e, + 0xd3, 0x6b, 0xc5, 0x88, 0xcb, 0x28, 0x1c, 0x58, 0xac, 0xfd, 0xb3, 0x9a, 0x3a, 0x0e, 0xe4, 0x07, + 0xd6, 0x43, 0x1e, 0x83, 0xd6, 0x94, 0x98, 0x66, 0x79, 0xa2, 0xf5, 0x60, 0xcf, 0xe3, 0x35, 0x57, + 0x94, 0x2d, 0x38, 0x6d, 0x37, 0x33, 0xa1, 0xa3, 0xa3, 0x01, 0xb9, 0x25, 0x12, 0xc5, 0x91, 0x50, + 0xf9, 0x55, 0xea, 0xdd, 0x71, 0xb5, 0x2a, 0x1d, 0x48, 0x13, 0x79, 0xea, 0xd7, 0x20, 0xa2, 0x17, + 0xea, 0xf7, 0xaa, 0x78, 0xf5, 0xc3, 0xa4, 0x8b, 0x54, 0xce, 0x79, 0x60, 0x61, 0x7a, 0xcd, 0x9b, + 0x09, 0x09, 0x79, 0xda, 0x3d, 0x82, 0xff, 0x6b, 0x6e, 0x79, 0xc4, 0x1b, 0xfe, 0x7c, 0x34, 0x91, + 0x0a, 0xcf, 0xf5, 0x94, 0x53, 0xdb, 0xee, 0xee, 0x61, 0x49, 0x75, 0xd9, 0xf5, 0x32, 0x52, 0x8d, + 0xbe, 0x3f, 0x1c, 0x23, 0x2f, 0x83, 0x6a, 0x29, 0x3d, 0x7c, 0x45, 0x79, 0xc7, 0x4f, 0xdf, 0x1f, + 0x9b, 0xd8, 0xf9, 0x85, 0xee, 0xf5, 0x4a, 0xe1, 0x0f, 0x65, 0xb2, 0xea, 0x40, 0xad, 0x57, 0xac, + 0x9d, 0x4b, 0x1a, 0xff, 0x45, 0xd0, 0xc8, 0x66, 0x8c, 0xeb, 0x93, 0x1e, 0x13, 0x71, 0x89, 0xc2, + 0xa4, 0x71, 0x2d, 0x1e, 0x35, 0x0c, 0xaf, 0x93, 0x21, 0xa2, 0x50, 0x8a, 0xc0, 0xa4, 0xf1, 0x1d, + 0x45, 0x9f, 0x63, 0xb5, 0x84, 0x6f, 0x53, 0x59, 0x83, 0xd1, 0x60, 0xe8, 0x36, 0xf4, 0x3b, 0xe6, + 0x8b, 0xbd, 0xa4, 0xc8, 0x11, 0x9b, 0x54, 0x7c, 0xc5, 0x7e, 0x49, 0x6b, 0x9c, 0xa5, 0x8f, 0x83, + 0x9b, 0xb3, 0xce, 0xb4, 0xa5, 0x54, 0x1e, 0x73, 0x8f, 0x59, 0x67, 0x23, 0xd1, 0x78, 0xd8, 0x71, + 0x92, 0xf8, 0x25, 0x79, 0x40, 0x78, 0x55, 0xe5, 0x42, 0xe6, 0x2a, 0xfb, 0x8a, 0x4d, 0x65, 0xb6, + 0x4b, 0x91, 0xe1, 0x6a, 0x30, 0x3c, 0x75, 0xa9, 0x8c, 0xd9, 0xbf, 0x66, 0x3f, 0x55, 0xc7, 0xd8, + 0x42, 0x9a, 0xf0, 0x66, 0xdf, 0x7f, 0x39, 0x7a, 0x51, 0x3d, 0x8d, 0xf2, 0x5e, 0x8c, 0xff, 0x16, + 0x7c, 0xd1, 0x37, 0xa5, 0xd0, 0x3d, 0x63, 0x27, 0x96, 0x7f, 0xf2, 0x85, 0xdf, 0x5d, 0x2e, 0xe4, + 0x3b, 0xa7, 0x2f, 0xd2, 0x4a, 0xef, 0x22, 0xb5, 0x96, 0x2e, 0xb1, 0xea, 0xd9, 0x3c, 0x4b, 0xb2, + 0xac, 0x3d, 0xe1, 0x5a, 0x5f, 0x8b, 0x6d, 0xa7, 0x2c, 0x9e, 0xb1, 0xb4, 0xd8, 0xb8, 0x6c, 0xa1, + 0x96, 0xca, 0x4f, 0xac, 0x23, 0xa4, 0x69, 0xc1, 0x69, 0x64, 0x3d, 0xb4, 0x5c, 0x5c, 0xbd, 0x62, + 0x0d, 0xc6, 0xb5, 0x5e, 0x43, 0x7e, 0xe2, 0xf9, 0x80, 0x21, 0x12, 0x7c, 0x93, 0x98, 0x20, 0x99, + 0xb5, 0xab, 0xcf, 0x89, 0x23, 0x75, 0x70, 0xe6, 0xf7, 0x59, 0xaa, 0x77, 0x6a, 0xe1, 0xb7, 0x4a, + 0xc9, 0x48, 0xbd, 0xaf, 0x99, 0xfd, 0x7b, 0xae, 0x9c, 0x66, 0x7a, 0x7a, 0x35, 0x6a, 0x4d, 0x58, + 0x0e, 0xd9, 0xb1, 0x0a, 0xfb, 0x6c, 0x44, 0x5a, 0x5b, 0x9c, 0x8d, 0xf6, 0x17, 0xc9, 0x6c, 0xd7, + 0xa6, 0x79, 0xe5, 0x88, 0x1f, 0x0a, 0x5c, 0x92, 0xf4, 0x48, 0xf1, 0xed, 0x97, 0x6d, 0x92, 0x35, + 0xfc, 0xf2, 0x46, 0x8e, 0xe3, 0x1d, 0x5e, 0xf2, 0x8b, 0xbb, 0x0b, 0x25, 0x8f, 0xa3, 0xef, 0x19, + 0x91, 0x3b, 0x5b, 0x8c, 0x6b, 0x66, 0x2f, 0xce, 0xd7, 0x12, 0x06, 0x62, 0x21, 0x1f, 0x72, 0xa6, + 0x2e, 0xb2, 0x5d, 0xff, 0xba, 0xf8, 0x94, 0x40, 0x96, 0xb5, 0xaf, 0x5e, 0xa9, 0x8c, 0xec, 0x97, + 0x8d, 0x63, 0x66, 0xd2, 0x2b, 0xa8, 0x5a, 0xe7, 0x57, 0x32, 0xa6, 0x7e, 0xb5, 0x71, 0xd3, 0x2e, + 0x31, 0xaf, 0x25, 0x05, 0xef, 0xce, 0xe9, 0x0d, 0xeb, 0xe2, 0x82, 0xa1, 0xf3, 0xd5, 0x74, 0xd9, + 0xa3, 0x39, 0x0d, 0x59, 0x1c, 0xaf, 0x27, 0xdd, 0xa3, 0xc5, 0x54, 0x66, 0x4c, 0xed, 0xd0, 0x67, + 0xc6, 0xd7, 0x57, 0x51, 0x72, 0xc0, 0xf3, 0xcc, 0xe4, 0x30, 0xfa, 0x2e, 0x4a, 0x3d, 0x33, 0x11, + 0x26, 0xb9, 0xee, 0x4a, 0x33, 0x47, 0xe3, 0xfa, 0x05, 0x03, 0xaf, 0x7f, 0x8b, 0x24, 0x63, 0x56, + 0xb9, 0x61, 0x98, 0x62, 0x43, 0xe9, 0x23, 0x4d, 0x70, 0x4e, 0x72, 0xb6, 0x6d, 0x30, 0xae, 0x7c, + 0x29, 0x4b, 0x8c, 0x4e, 0x4c, 0x20, 0x35, 0xae, 0xbb, 0xfa, 0x4f, 0xc6, 0x42, 0xae, 0x81, 0x01, + 0x64, 0xfd, 0xf7, 0x55, 0x87, 0xc8, 0xf3, 0xac, 0x43, 0x5c, 0x0c, 0xbf, 0x45, 0xa5, 0x83, 0x07, + 0x39, 0xfe, 0xfe, 0xd6, 0x62, 0x4d, 0xa1, 0x47, 0xd6, 0xeb, 0x6f, 0x26, 0xe2, 0x48, 0x53, 0x30, + 0x78, 0x32, 0xda, 0xa1, 0xb1, 0xe2, 0xaa, 0x0a, 0xfa, 0x7c, 0x7f, 0xf8, 0x31, 0xca, 0xab, 0x74, + 0xb4, 0xe0, 0x34, 0xb6, 0xa5, 0x96, 0xfe, 0x54, 0x35, 0x99, 0xf5, 0x68, 0x9f, 0x62, 0x0a, 0xc9, + 0xac, 0xf5, 0xaa, 0xd7, 0x8f, 0xd2, 0x6b, 0xd3, 0xa6, 0x3f, 0x7a, 0xc3, 0x2a, 0x73, 0x6e, 0x37, + 0x50, 0x98, 0xff, 0xb4, 0xa6, 0x14, 0x23, 0x6b, 0x02, 0x73, 0x31, 0xf8, 0xbe, 0x70, 0xa9, 0xfe, + 0xad, 0x24, 0x14, 0x0d, 0xb8, 0x92, 0xaf, 0x1c, 0xa1, 0xa5, 0x8b, 0x4c, 0x68, 0xd9, 0x8c, 0xf6, + 0x98, 0xe7, 0x2d, 0xc9, 0x57, 0xe9, 0xd9, 0xf7, 0x3e, 0x0a, 0x44, 0xe9, 0x2f, 0xea, 0xaf, 0xe7, + 0x0c, 0xb1, 0xae, 0x11, 0xf9, 0x6f, 0x45, 0xad, 0xc8, 0xb9, 0xea, 0xc7, 0x54, 0xe6, 0x34, 0x53, + 0x47, 0xa4, 0xeb, 0x47, 0xba, 0xdd, 0xf9, 0x59, 0xff, 0xf6, 0xd8, 0x01, 0x83, 0x1f, 0xda, 0x4d, + 0x64, 0x4c, 0xa0, 0x64, 0xd4, 0x1d, 0x02, 0x15, 0x10, 0x26, 0xe1, 0x88, 0x09, 0x41, 0x85, 0x9b, + 0x73, 0xba, 0x5c, 0xc7, 0xc8, 0xdb, 0x99, 0x7f, 0xe0, 0x29, 0xb3, 0x0e, 0xf9, 0xa9, 0x6f, 0x60, + 0x3a, 0xdb, 0x07, 0x47, 0x22, 0x59, 0x79, 0xd8, 0x9d, 0x47, 0x25, 0x4b, 0x33, 0xea, 0x5e, 0x9b, + 0x62, 0x22, 0x81, 0xed, 0x6a, 0xbe, 0x46, 0xd8, 0x9f, 0x7f, 0x9d, 0xe9, 0xea, 0xf4, 0x25, 0x4c, + 0x41, 0x01, 0x1e, 0xd3, 0x94, 0xdf, 0x08, 0x06, 0x22, 0x9d, 0x6f, 0x04, 0x31, 0x4d, 0xf6, 0xb5, + 0xe5, 0xba, 0xce, 0x70, 0xae, 0x5c, 0x0c, 0x7c, 0x4c, 0x74, 0x46, 0x64, 0xae, 0xa1, 0x40, 0x75, + 0x71, 0xcd, 0xdb, 0xab, 0x58, 0x2f, 0x6a, 0x85, 0x45, 0xe7, 0x17, 0x14, 0x01, 0x90, 0x7e, 0x64, + 0x5b, 0xb5, 0x82, 0x8e, 0xe8, 0xcd, 0x0c, 0x31, 0xac, 0xc4, 0xdf, 0x2e, 0xa5, 0x7f, 0x4e, 0xcf, + 0x0c, 0xd2, 0x49, 0xd7, 0x28, 0xdd, 0xf7, 0xc2, 0xfd, 0xf9, 0xf0, 0x6c, 0xed, 0x1b, 0x1e, 0x48, + 0x0a, 0x43, 0x6f, 0xbf, 0xd4, 0xf7, 0x7f, 0x4d, 0xcf, 0x79, 0xf6, 0x55, 0x6e, 0x9c, 0x1f, 0x57, + 0xd3, 0x1a, 0x65, 0x9f, 0x79, 0x7c, 0x48, 0x1c, 0xdc, 0xff, 0x1c, 0x14, 0xda, 0x13, 0x7e, 0x34, + 0x3a, 0x10, 0x19, 0x26, 0x1e, 0xaf, 0x23, 0xa4, 0x6d, 0xc1, 0x69, 0xdc, 0x5c, 0x88, 0x26, 0x3b, + 0xb6, 0xcc, 0x07, 0xb9, 0xa3, 0x81, 0x9d, 0x83, 0x35, 0x7e, 0x5f, 0x9f, 0x9c, 0xe6, 0x7b, 0x65, + 0x8b, 0x5e, 0xeb, 0x9e, 0x46, 0x56, 0xd4, 0x8a, 0xa7, 0x7f, 0x47, 0x7d, 0x03, 0x03, 0x8e, 0x7f, + 0x6c, 0x9a, 0x54, 0x28, 0xc1, 0x8f, 0xee, 0x9c, 0x76, 0xbc, 0xd4, 0xf7, 0x3b, 0xb1, 0x23, 0x7e, + 0xbc, 0x8c, 0x75, 0x64, 0x24, 0x6e, 0xe2, 0x27, 0x51, 0x42, 0xea, 0xee, 0x16, 0xce, 0xf8, 0xf0, + 0x9e, 0xbd, 0x90, 0x33, 0x91, 0x03, 0x51, 0xcf, 0x91, 0x71, 0x60, 0x40, 0xe2, 0xe9, 0x7f, 0x1e, + 0x5c, 0xa4, 0x49, 0xd5, 0xb8, 0xeb, 0x99, 0x5e, 0x38, 0x9e, 0x46, 0xd7, 0x26, 0x65, 0xf3, 0x34, + 0x36, 0xb0, 0x98, 0x75, 0x3d, 0x7b, 0xe1, 0xf4, 0x2c, 0x62, 0x03, 0xea, 0x95, 0x5c, 0x9f, 0x30, + 0xb4, 0xea, 0x12, 0x8c, 0x2c, 0x1e, 0xac, 0x24, 0xf9, 0x03, 0x95, 0x67, 0xc3, 0x13, 0x99, 0x0b, + 0xd4, 0xdb, 0x63, 0xcf, 0x25, 0x3b, 0xba, 0x34, 0xfb, 0x68, 0xba, 0x5b, 0xb2, 0xef, 0x20, 0x45, + 0x43, 0xb2, 0xfa, 0xa6, 0x18, 0x44, 0x94, 0xb4, 0x72, 0xc0, 0xe5, 0x24, 0x94, 0x7d, 0x07, 0x79, + 0xf4, 0xb5, 0x5c, 0x6a, 0x21, 0xba, 0x9d, 0xee, 0x0e, 0x2d, 0xef, 0x83, 0x73, 0x2e, 0x3d, 0xa2, + 0x98, 0x46, 0x29, 0x2b, 0x2e, 0x41, 0xd1, 0x97, 0x2a, 0x09, 0x9a, 0xb3, 0x81, 0x68, 0x51, 0x23, + 0x97, 0x20, 0x81, 0xb3, 0x3d, 0x85, 0xf1, 0x13, 0x6a, 0x93, 0x25, 0x5c, 0x25, 0xbd, 0x2a, 0xd1, + 0xb1, 0x6d, 0x52, 0x2f, 0x20, 0xc2, 0x01, 0x44, 0xc7, 0x5a, 0xb1, 0x49, 0x74, 0x44, 0xa5, 0x9e, + 0xfc, 0x54, 0x39, 0x9a, 0x74, 0xe0, 0x6f, 0x29, 0x0c, 0x4b, 0xa7, 0xf0, 0xf2, 0x5e, 0xe5, 0x37, + 0x9f, 0x5c, 0xbf, 0xaf, 0xed, 0xec, 0x13, 0x7d, 0xa9, 0xbf, 0x31, 0xf4, 0x8d, 0xfd, 0x4e, 0x8b, + 0x44, 0x3a, 0xdb, 0xcb, 0x3e, 0xfd, 0x7e, 0x07, 0x2f, 0x34, 0x50, 0xea, 0x14, 0x99, 0x45, 0x07, + 0x2b, 0x9b, 0x72, 0xc9, 0x9c, 0xf7, 0x97, 0x41, 0x17, 0xc2, 0xa3, 0x26, 0x25, 0xd4, 0xe3, 0xff, + 0x18, 0x2c, 0x23, 0x2d, 0x38, 0xbd, 0xb9, 0xbf, 0xb5, 0x42, 0x6c, 0x3b, 0xf4, 0x73, 0xbd, 0x5d, + 0xe3, 0xfb, 0x73, 0xbd, 0x7d, 0x58, 0x54, 0xe1, 0xe9, 0x13, 0x1d, 0x23, 0x40, 0xe9, 0xe2, 0xfe, + 0x4f, 0x5e, 0x7b, 0x7c, 0x8e, 0xf0, 0xac, 0xc9, 0x55, 0x47, 0x29, 0xc7, 0x80, 0x13, 0x65, 0xe3, + 0x27, 0x73, 0xc6, 0x2e, 0xeb, 0xfe, 0x9c, 0x51, 0xb4, 0x99, 0x75, 0x25, 0xbb, 0xd8, 0xb7, 0xce, + 0xbc, 0x32, 0xec, 0xa2, 0xdf, 0x25, 0x47, 0x0e, 0x18, 0x77, 0xd7, 0xc8, 0xfe, 0x2c, 0xe0, 0x9b, + 0x68, 0x74, 0xf9, 0xa7, 0xab, 0x69, 0xfa, 0x20, 0x2a, 0x18, 0x1c, 0xd3, 0xbc, 0x96, 0xcc, 0xcf, + 0x47, 0xcf, 0x44, 0xe3, 0xd3, 0x04, 0xcf, 0xfc, 0xab, 0x13, 0x8d, 0x6c, 0xcd, 0x0f, 0x11, 0x46, + 0xa3, 0x64, 0xee, 0x20, 0xba, 0xf5, 0x29, 0x41, 0x5b, 0xfa, 0x46, 0x71, 0x17, 0x1d, 0x92, 0x5e, + 0x44, 0xf8, 0x95, 0xfd, 0xb7, 0xb9, 0xd4, 0xc9, 0x07, 0x19, 0x9a, 0xda, 0x89, 0xa0, 0x3d, 0x45, + 0xb9, 0xe6, 0xd3, 0x37, 0x4f, 0xf2, 0xe0, 0xa0, 0x8e, 0xf6, 0xe8, 0xf7, 0x68, 0x8f, 0x78, 0x68, + 0xf0, 0x0b, 0x6a, 0xfb, 0x75, 0xb6, 0x82, 0xda, 0x45, 0xd2, 0x0e, 0xea, 0x25, 0xe0, 0xc2, 0xf6, + 0xe6, 0xc0, 0x58, 0xb1, 0xf7, 0x38, 0x3e, 0xfb, 0xc5, 0xeb, 0xf8, 0x35, 0x78, 0x88, 0xf7, 0x4c, + 0xaf, 0xb0, 0x67, 0x9d, 0xd3, 0xcc, 0x99, 0xe0, 0x2a, 0x1d, 0x39, 0x38, 0x06, 0x2c, 0xa3, 0xf1, + 0x2d, 0x91, 0xec, 0xb2, 0xcb, 0xd2, 0xbf, 0x42, 0xf5, 0x3f, 0x9f, 0x4e, 0xe5, 0x26, 0xd5, 0x72, + 0xed, 0xc7, 0xe1, 0x0a, 0xbd, 0xe7, 0x55, 0x5a, 0xc7, 0x51, 0x83, 0x37, 0x70, 0xec, 0xab, 0xa4, + 0x95, 0xa3, 0x0b, 0x23, 0x3f, 0x9d, 0x18, 0xd8, 0x4e, 0xcc, 0x30, 0x6b, 0xfd, 0xbc, 0x1a, 0x19, + 0xd7, 0x92, 0x71, 0x44, 0x5d, 0xef, 0xf2, 0x49, 0x3e, 0x10, 0x3d, 0x22, 0x49, 0x35, 0xf7, 0x0a, + 0x1f, 0x29, 0x12, 0x23, 0x7d, 0x0a, 0x4b, 0x9a, 0x5e, 0x55, 0x1b, 0x82, 0xb9, 0x17, 0x7b, 0x33, + 0x84, 0x4d, 0xc7, 0x0c, 0x20, 0x39, 0xd4, 0x30, 0x37, 0xf1, 0xc4, 0x3a, 0x42, 0xc6, 0x16, 0x9c, + 0xde, 0xed, 0x61, 0x64, 0xf3, 0x98, 0x9e, 0x9e, 0xf7, 0x55, 0xba, 0x17, 0x57, 0x89, 0x58, 0x62, + 0xe9, 0x37, 0xaf, 0x9a, 0x39, 0x3e, 0x60, 0xd5, 0xfd, 0xa3, 0xe1, 0x8f, 0x15, 0x65, 0x6d, 0xfa, + 0x8c, 0x12, 0x88, 0x1d, 0x7a, 0xaf, 0x65, 0x9e, 0x30, 0x26, 0x77, 0x34, 0x6a, 0xf7, 0xba, 0xb2, + 0x42, 0x1b, 0x5f, 0x6d, 0x8a, 0xb5, 0xb1, 0x0e, 0x6a, 0x36, 0x38, 0x4c, 0xf6, 0x8f, 0xcf, 0xa1, + 0x6a, 0xfe, 0xaf, 0x94, 0xae, 0x54, 0x4f, 0x8c, 0x65, 0x3b, 0xd4, 0xc0, 0xc0, 0x74, 0x66, 0xac, + 0x94, 0xf1, 0x85, 0x63, 0x9e, 0x5c, 0x13, 0xda, 0xc6, 0x35, 0xde, 0x8e, 0x01, 0xd7, 0x1c, 0x9d, + 0x5d, 0xeb, 0xdb, 0xf7, 0x28, 0x15, 0x22, 0x4d, 0x74, 0x7b, 0xfb, 0xd3, 0x67, 0x97, 0x51, 0xb9, + 0x3d, 0x8c, 0x7b, 0x37, 0x7f, 0xfd, 0xec, 0x4c, 0x6f, 0xf6, 0x5f, 0xcc, 0x95, 0xea, 0xf2, 0x83, + 0x03, 0xcc, 0xd1, 0xb7, 0xb7, 0x66, 0x1b, 0xfb, 0x8a, 0x79, 0xd6, 0x92, 0x95, 0x85, 0x64, 0xaf, + 0x79, 0x86, 0x7a, 0x5f, 0xec, 0xaa, 0x52, 0xbf, 0x57, 0xcb, 0xf3, 0x15, 0xc3, 0x70, 0x7f, 0xca, + 0x21, 0xab, 0x77, 0x4e, 0x45, 0xd2, 0xe2, 0xcc, 0x32, 0x7a, 0x00, 0x00, 0xfd, 0x34, 0x21, 0x12, + 0xdb, 0x0f, 0x22, 0xac, 0xf8, 0xc3, 0xe7, 0x45, 0x8c, 0xfa, 0x40, 0x7e, 0xca, 0x75, 0xd5, 0x22, + 0xbf, 0x10, 0xa6, 0xa5, 0x4a, 0x47, 0x4a, 0x3d, 0x5f, 0x4c, 0x2b, 0xb1, 0x3d, 0xcd, 0xfc, 0xfa, + 0xa5, 0xde, 0x81, 0xd6, 0x32, 0x6a, 0x67, 0xf6, 0x99, 0xad, 0x22, 0x3b, 0xa8, 0xfd, 0x47, 0xa5, + 0xa6, 0xed, 0xdf, 0x48, 0x4c, 0x2e, 0x0f, 0x39, 0x8c, 0x8e, 0x23, 0x1f, 0x23, 0x0d, 0x9d, 0xf5, + 0x52, 0xb5, 0x55, 0x4c, 0x99, 0xa4, 0x3e, 0x3b, 0x77, 0xf4, 0xeb, 0x99, 0xbc, 0xca, 0x57, 0x23, + 0x46, 0x83, 0x89, 0x22, 0xfa, 0xa2, 0x36, 0x38, 0x8a, 0x09, 0x36, 0x27, 0xe9, 0x9c, 0xeb, 0x50, + 0x5e, 0x75, 0xe4, 0x5f, 0x9f, 0x49, 0xb5, 0xb9, 0x5f, 0xa2, 0x0b, 0xf8, 0xab, 0xfe, 0x7d, 0xc7, + 0x30, 0x4e, 0xaa, 0x0a, 0x9f, 0x1e, 0xaf, 0x8d, 0x45, 0xf4, 0x3c, 0xc9, 0xe9, 0x03, 0x7c, 0x53, + 0x3f, 0x6f, 0x8e, 0xbc, 0x31, 0x2d, 0xd5, 0x6c, 0xa5, 0xbd, 0x3e, 0xc9, 0xef, 0x11, 0x5b, 0xda, + 0xbe, 0x7a, 0x2e, 0x1f, 0x90, 0xf9, 0xbd, 0x23, 0xdf, 0xea, 0xbc, 0xb3, 0xbe, 0x45, 0xd4, 0x10, + 0xd7, 0x38, 0xcb, 0x73, 0x62, 0x5f, 0x89, 0x58, 0xf8, 0xa5, 0xeb, 0x54, 0x6b, 0x51, 0x92, 0x33, + 0x9f, 0x0b, 0xc5, 0x5f, 0x24, 0x33, 0xea, 0xf3, 0xad, 0x93, 0x45, 0xba, 0x30, 0x71, 0x52, 0xea, + 0x7a, 0x81, 0x15, 0xdc, 0x87, 0xd1, 0xb4, 0x7e, 0x30, 0xbd, 0xc6, 0x97, 0x85, 0x50, 0x1d, 0x5f, + 0x11, 0x42, 0x63, 0xfc, 0xfd, 0xca, 0x1b, 0xe3, 0xbe, 0x5c, 0xca, 0xdb, 0x56, 0xcb, 0x15, 0xcf, + 0x9e, 0xfd, 0xc7, 0xdb, 0xa0, 0x26, 0xb0, 0x65, 0x5c, 0xfd, 0x68, 0x4d, 0x5b, 0x64, 0xde, 0x9c, + 0x28, 0xed, 0x9a, 0x53, 0x1b, 0x66, 0xf5, 0x7f, 0xf4, 0x66, 0x24, 0xc3, 0x09, 0xbe, 0x70, 0x27, + 0xb1, 0x20, 0xaa, 0x55, 0xbe, 0xb9, 0x15, 0x9a, 0x9a, 0xa6, 0x50, 0x31, 0x4d, 0xfd, 0xc6, 0x9a, + 0x54, 0x19, 0x47, 0xa4, 0x5f, 0x1a, 0xce, 0xb9, 0xdf, 0xec, 0xfc, 0x4a, 0x17, 0x15, 0xdd, 0x96, + 0xf1, 0x95, 0xcc, 0x40, 0x50, 0x9a, 0x08, 0xda, 0x0c, 0x46, 0xdc, 0x5b, 0x8d, 0x4f, 0xd6, 0xc4, + 0xcc, 0x42, 0xda, 0xc2, 0xa7, 0x24, 0x98, 0x2a, 0xa1, 0x94, 0xcc, 0x24, 0x3b, 0x7d, 0xe2, 0xdf, + 0x36, 0xbc, 0xbd, 0xaa, 0x73, 0x7c, 0xd8, 0xd4, 0x77, 0x10, 0x7d, 0x7a, 0xec, 0xea, 0xbf, 0x72, + 0x33, 0xfd, 0xc4, 0x3a, 0x42, 0x96, 0x16, 0x32, 0xcd, 0x17, 0xcd, 0xcb, 0xbd, 0xde, 0x4d, 0x89, + 0x79, 0xd6, 0x13, 0x4f, 0x91, 0x98, 0xcf, 0x97, 0x72, 0x12, 0x3c, 0xa5, 0x46, 0xcb, 0x2b, 0x4c, + 0x8d, 0x6b, 0xd4, 0xcf, 0x13, 0x24, 0x2e, 0xa3, 0x78, 0xf1, 0x71, 0xca, 0x28, 0xa2, 0xe5, 0xcb, + 0x9d, 0x9b, 0xd2, 0xcf, 0xab, 0x64, 0x44, 0x4f, 0xae, 0x1e, 0x07, 0x7d, 0x58, 0x8f, 0xd6, 0x30, + 0xbd, 0x72, 0xb6, 0x31, 0x69, 0x5d, 0x7e, 0x35, 0x70, 0xfa, 0xa9, 0x42, 0xe5, 0xa7, 0x4e, 0x3e, + 0x57, 0x2b, 0x62, 0x29, 0x92, 0x33, 0xc4, 0x81, 0xa5, 0x78, 0x5d, 0x94, 0x04, 0x72, 0xfc, 0x23, + 0x49, 0xe0, 0x4b, 0x5e, 0x30, 0xf5, 0x3b, 0x93, 0x2e, 0xcf, 0x4e, 0xd3, 0x9d, 0x7c, 0x49, 0x28, + 0xd7, 0xc9, 0x93, 0x84, 0xe8, 0x4e, 0x91, 0xe4, 0x53, 0xae, 0x53, 0x18, 0x9a, 0xf7, 0x50, 0x9b, + 0xe3, 0x5f, 0xf2, 0x9a, 0xdd, 0x90, 0x5b, 0xa1, 0x8a, 0x8f, 0xbb, 0xe7, 0xb6, 0x13, 0xef, 0x17, + 0x23, 0xfd, 0xbb, 0x13, 0xc8, 0x2f, 0x6b, 0x9b, 0x4b, 0x43, 0xbf, 0x20, 0xe5, 0x89, 0xc5, 0x76, + 0x7e, 0x70, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, + 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, + 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xfd, 0xcf, 0x24, 0xf8, 0x7f, 0xb0, 0x80, 0xcb, + 0x1e, 0x41, 0xa4, 0x73, 0x8f, 0xe6, 0x8e, 0xca, 0x73, 0x4a, 0xfd, 0xd3, 0x19, 0x31, 0x36, 0x91, + 0xd9, 0xe9, 0xe9, 0x36, 0x91, 0x5f, 0x99, 0x74, 0xa4, 0xf9, 0x77, 0xb9, 0x9f, 0x7d, 0x95, 0x99, + 0x70, 0xe7, 0x4d, 0x19, 0x2b, 0xca, 0x57, 0x4a, 0xdc, 0x0a, 0xe3, 0x5a, 0xe3, 0x44, 0xc4, 0xad, + 0x7b, 0xfe, 0x2f, 0x62, 0x31, 0x1e, 0x0f, 0x39, 0x3d, 0x26, 0xd6, 0x9a, 0xb6, 0xe3, 0x13, 0xd7, + 0x2d, 0xca, 0xaf, 0x76, 0xaa, 0xa5, 0xa8, 0x29, 0x0d, 0x77, 0x2d, 0x4e, 0x0c, 0xa1, 0xc3, 0x6f, + 0x59, 0x7d, 0x51, 0x5d, 0x41, 0x12, 0x0a, 0x4d, 0xe9, 0xab, 0x2f, 0x29, 0x71, 0x62, 0xc3, 0xac, + 0x85, 0x42, 0xd2, 0x77, 0x5b, 0x9c, 0x52, 0x51, 0x53, 0x98, 0xdb, 0xf5, 0x7b, 0x10, 0xd3, 0xb8, + 0x46, 0x67, 0xd4, 0xab, 0x66, 0x51, 0x8c, 0x21, 0x4a, 0xd1, 0x61, 0x56, 0x12, 0x41, 0xf8, 0x6c, + 0x2c, 0x10, 0x0d, 0x14, 0x9b, 0x2d, 0xf0, 0xbc, 0x2d, 0x63, 0x2d, 0xad, 0xb1, 0x96, 0xc6, 0xae, + 0xc7, 0x68, 0x31, 0x1f, 0x60, 0x3c, 0x5a, 0xf3, 0x25, 0xa2, 0x36, 0x59, 0xab, 0xa5, 0xd4, 0x4e, + 0x68, 0x4e, 0x6d, 0xda, 0x39, 0x9d, 0xb3, 0x78, 0xf5, 0xb7, 0x2d, 0x58, 0x12, 0xb4, 0x98, 0x70, + 0xfa, 0xbd, 0x60, 0x17, 0xa3, 0x7b, 0x34, 0xa3, 0x68, 0x27, 0xa3, 0xd1, 0x94, 0xd6, 0x32, 0x78, + 0x62, 0xc8, 0x18, 0x30, 0x25, 0x52, 0x04, 0xa1, 0x91, 0xa3, 0xb7, 0x2d, 0xa2, 0x26, 0x96, 0x3c, + 0x58, 0x0b, 0x8c, 0xb9, 0xb5, 0xdc, 0xbc, 0x01, 0x7e, 0x40, 0x33, 0xa1, 0xc9, 0xdb, 0xc2, 0x91, + 0xfc, 0xe4, 0x06, 0x5e, 0x88, 0x30, 0x41, 0x2c, 0x91, 0xc2, 0x2b, 0x05, 0xe6, 0xa6, 0x45, 0xf0, + 0xd1, 0x7c, 0x68, 0x79, 0x45, 0xf3, 0x34, 0xa7, 0x09, 0xa1, 0x75, 0x16, 0x75, 0x15, 0x5f, 0x66, + 0xa2, 0x58, 0xf1, 0x75, 0x3a, 0x5a, 0x32, 0xec, 0xb2, 0x99, 0x3a, 0x5d, 0x76, 0x2c, 0x47, 0x35, + 0x3f, 0x34, 0xb3, 0x41, 0xea, 0x24, 0x94, 0xb6, 0xf0, 0x9c, 0x4b, 0x29, 0x92, 0xce, 0x2d, 0x08, + 0x6c, 0x88, 0x33, 0xa2, 0xb4, 0x81, 0x5f, 0x6a, 0x81, 0xc5, 0x19, 0xe1, 0xf5, 0x21, 0xe0, 0x17, + 0xb5, 0x75, 0x69, 0x2c, 0x53, 0x54, 0x3d, 0x9d, 0xbe, 0xda, 0xbe, 0xb8, 0xd8, 0x60, 0x76, 0x8c, + 0xa3, 0xf9, 0x0d, 0x47, 0xa6, 0xfe, 0x26, 0xb3, 0x93, 0x1d, 0x8d, 0x31, 0x99, 0xcb, 0x62, 0x39, + 0x9d, 0xb9, 0x2c, 0x65, 0x83, 0x8e, 0x7a, 0xc9, 0xb3, 0x3d, 0xb9, 0x88, 0xf2, 0x14, 0x1f, 0x8c, + 0x1a, 0x98, 0xdf, 0xe4, 0x01, 0xcf, 0x58, 0x5c, 0xf1, 0xfe, 0x48, 0xff, 0xfa, 0x60, 0x9e, 0x11, + 0xc7, 0x2d, 0x09, 0x90, 0x42, 0x9f, 0xc8, 0xbc, 0xe8, 0xe1, 0x35, 0xef, 0x7c, 0x7d, 0x89, 0x54, + 0xe1, 0x59, 0xd6, 0xc2, 0x63, 0x6b, 0xe5, 0xad, 0x6f, 0xe7, 0x15, 0x78, 0xac, 0x53, 0x14, 0x1a, + 0xc2, 0x94, 0x77, 0x6f, 0xe5, 0x79, 0x9c, 0x4f, 0x87, 0x76, 0xb4, 0x90, 0xe9, 0xef, 0x77, 0xb8, + 0x93, 0xbf, 0x1d, 0x1e, 0x65, 0x5f, 0x80, 0x4d, 0x52, 0x54, 0x2d, 0x17, 0x5f, 0xc6, 0x25, 0x7e, + 0xec, 0x95, 0x29, 0xec, 0xbf, 0xbe, 0x84, 0xac, 0x19, 0x37, 0x59, 0x6b, 0x35, 0x77, 0xaf, 0x45, + 0xc8, 0x0f, 0x5b, 0x18, 0x8c, 0x19, 0xcd, 0x68, 0xf1, 0x25, 0x90, 0xaa, 0xa8, 0x91, 0xb5, 0xdc, + 0xb4, 0x08, 0xf9, 0xf2, 0xbf, 0x00, 0xc1, 0xb9, 0x6d, 0xe1, 0xc7, 0xf8, 0x71, 0xf8, 0x8c, 0x9d, + 0x93, 0x5c, 0xe7, 0x14, 0x9e, 0xe6, 0x84, 0xc9, 0xb7, 0x1e, 0xb0, 0x60, 0x91, 0xc9, 0x1d, 0x92, + 0x4b, 0x18, 0xf3, 0xe7, 0x95, 0xd1, 0x71, 0x55, 0xbe, 0xd9, 0x22, 0xde, 0xec, 0x10, 0x50, 0x8a, + 0x93, 0x3c, 0x62, 0xca, 0x92, 0xf9, 0x31, 0x2b, 0x59, 0x8a, 0x18, 0x59, 0xf8, 0x70, 0xf0, 0x0b, + 0x48, 0x99, 0x35, 0x4d, 0xf0, 0xb6, 0xc7, 0x55, 0xd7, 0xcf, 0xe0, 0x5e, 0x61, 0xa7, 0xe4, 0xce, + 0xdb, 0xb6, 0x6e, 0xbb, 0x81, 0x47, 0xc1, 0xad, 0xb8, 0x1e, 0xe0, 0xa0, 0x05, 0xf6, 0xb9, 0x74, + 0x18, 0xa5, 0xc6, 0x90, 0x3b, 0x2d, 0x6c, 0x50, 0xaf, 0xad, 0x95, 0x51, 0x2f, 0x3f, 0xde, 0x68, + 0xe1, 0xf4, 0xc7, 0x8f, 0xe8, 0xfd, 0x45, 0xc0, 0x30, 0xf8, 0x59, 0xf0, 0x54, 0xfe, 0x45, 0x10, + 0x1b, 0x7e, 0x9c, 0xf7, 0x4c, 0x68, 0x5b, 0x70, 0x3a, 0xc0, 0x66, 0x26, 0x16, 0x89, 0x80, 0x61, + 0xfe, 0xd0, 0xfb, 0xdf, 0x3a, 0x83, 0x87, 0xb8, 0x16, 0xf6, 0x90, 0x07, 0x48, 0xd4, 0x2c, 0x77, + 0x2c, 0xa2, 0x16, 0x84, 0x67, 0x51, 0x41, 0x9f, 0x24, 0xbc, 0xf0, 0x8a, 0x0f, 0x14, 0x00, 0x5a, + 0x3f, 0xa0, 0x0a, 0x08, 0xdc, 0x10, 0x21, 0x4f, 0x27, 0x38, 0x36, 0xa7, 0xee, 0x34, 0x03, 0xcd, + 0xb0, 0x11, 0x61, 0xa0, 0x0f, 0x60, 0xf3, 0x86, 0x17, 0x0e, 0x79, 0xbc, 0x7c, 0x73, 0xf3, 0xce, + 0x42, 0x25, 0x02, 0x3f, 0xc6, 0x92, 0x91, 0x62, 0x08, 0x5c, 0x86, 0xf2, 0x2d, 0x5b, 0x99, 0x5a, + 0xb2, 0xea, 0x80, 0x02, 0x7b, 0x7a, 0x4e, 0x26, 0x7f, 0xb1, 0xc2, 0xb3, 0x66, 0xdc, 0xd3, 0x5b, + 0x68, 0xb4, 0x58, 0xc4, 0xb5, 0x7d, 0x8d, 0x0e, 0x1d, 0x00, 0x09, 0xdd, 0x71, 0x29, 0xa3, 0x7c, + 0x89, 0xab, 0xc7, 0x22, 0x4a, 0x81, 0x63, 0x8a, 0x69, 0x33, 0x3c, 0x31, 0x17, 0x14, 0x34, 0x58, + 0x2b, 0x59, 0xfa, 0xf3, 0xd7, 0x22, 0xe8, 0xc7, 0xb5, 0x18, 0x46, 0x5a, 0x70, 0x7a, 0x93, 0x6b, + 0xd3, 0x0f, 0x8e, 0xf4, 0xf4, 0x37, 0xf3, 0xf2, 0xe8, 0x9b, 0x9b, 0xe5, 0xfa, 0xd5, 0x12, 0x17, + 0xd2, 0x4c, 0x1e, 0x04, 0x1b, 0xa3, 0xf8, 0xe6, 0x29, 0x8a, 0x96, 0x8f, 0x97, 0xd3, 0x39, 0x68, + 0x3d, 0x1a, 0xbb, 0xbd, 0x2d, 0x6c, 0xcb, 0xa3, 0x63, 0x4a, 0xb0, 0x41, 0xc0, 0x2f, 0xfa, 0xe1, + 0x09, 0x05, 0xe8, 0x81, 0x60, 0x50, 0x2a, 0xa3, 0x9f, 0x7c, 0x9a, 0x5c, 0xfa, 0xb8, 0x05, 0x38, + 0x86, 0x6a, 0x95, 0x12, 0x97, 0x56, 0x2b, 0x7f, 0xdc, 0x42, 0x39, 0x20, 0x3f, 0x40, 0x7b, 0xc5, + 0x77, 0xba, 0x8b, 0x68, 0xb9, 0x77, 0xd3, 0xc2, 0xf4, 0x45, 0xed, 0x6d, 0x66, 0xe5, 0x6d, 0x0b, + 0xd1, 0xfd, 0x34, 0xc7, 0xbb, 0x1b, 0x57, 0xc7, 0xe3, 0x1c, 0x51, 0x63, 0x0b, 0x4e, 0xef, 0x24, + 0x70, 0x60, 0xf9, 0xd9, 0x10, 0x5e, 0x34, 0x8a, 0x32, 0xd6, 0x14, 0x19, 0x6c, 0xdc, 0xc2, 0x87, + 0x31, 0x11, 0xe0, 0x1e, 0xf0, 0x09, 0x4d, 0xc2, 0x92, 0x9e, 0xd0, 0x30, 0x34, 0x3f, 0x19, 0x82, + 0x27, 0x22, 0x78, 0x51, 0x30, 0x15, 0xc5, 0x4b, 0x5e, 0x51, 0x8a, 0x84, 0x3e, 0xca, 0xec, 0x23, + 0xa9, 0xe6, 0x93, 0x31, 0x9a, 0xc0, 0x8f, 0xa3, 0xcd, 0x16, 0x2a, 0x58, 0x9d, 0x91, 0x7c, 0x0b, + 0x4e, 0xfc, 0x2b, 0x04, 0xfc, 0x51, 0xd0, 0xad, 0x05, 0x9a, 0x7d, 0x02, 0x76, 0x33, 0x13, 0xb3, + 0x74, 0xf0, 0xba, 0x05, 0x53, 0x5c, 0xbf, 0x6e, 0xa1, 0x1f, 0xf2, 0x73, 0x2c, 0xf3, 0xa8, 0xe2, + 0xd7, 0x6f, 0xc2, 0xcf, 0x80, 0x4b, 0x60, 0xaf, 0x0e, 0xa9, 0xa0, 0xbe, 0xd9, 0x22, 0xc0, 0xb5, + 0x30, 0xa9, 0x67, 0x73, 0xcc, 0xb1, 0xc5, 0x7d, 0xad, 0x28, 0xf1, 0x3b, 0x0c, 0xf0, 0x63, 0x36, + 0xf2, 0xeb, 0x21, 0x15, 0xb8, 0xbe, 0x0b, 0xec, 0x0b, 0x5a, 0xb3, 0xa5, 0x35, 0x54, 0x8a, 0x4d, + 0x91, 0xa5, 0x86, 0x55, 0xb0, 0xdd, 0x65, 0x19, 0x9e, 0x7f, 0x65, 0x98, 0xaf, 0xae, 0xdd, 0xb6, + 0xd0, 0x87, 0x6a, 0x6e, 0xce, 0xff, 0x46, 0xe1, 0xc5, 0x5c, 0x8b, 0xc3, 0x64, 0x66, 0xe2, 0x26, + 0x0f, 0x35, 0x04, 0xde, 0x1c, 0x18, 0x01, 0xd0, 0x62, 0x2e, 0xf7, 0x38, 0xef, 0xb9, 0xa7, 0x05, + 0xa7, 0xa3, 0xc0, 0x29, 0xb1, 0xe5, 0x14, 0x53, 0x49, 0x67, 0x43, 0xf6, 0x73, 0x8f, 0xa0, 0x30, + 0x3e, 0xeb, 0xe1, 0x04, 0x11, 0xa8, 0xd5, 0xa9, 0x9a, 0x86, 0xbf, 0xca, 0xdd, 0xf6, 0x4c, 0x8d, + 0x82, 0x2f, 0x91, 0xd5, 0xec, 0xbf, 0x2b, 0xad, 0xc1, 0x37, 0xfe, 0x49, 0xc5, 0x58, 0x63, 0x1c, + 0xd6, 0xe1, 0x15, 0x12, 0x37, 0xa6, 0x41, 0x12, 0x71, 0x1d, 0xdd, 0xf4, 0x5f, 0x70, 0x63, 0x38, + 0x46, 0x24, 0x8a, 0xe1, 0x33, 0xd5, 0xf1, 0xf1, 0x68, 0x4d, 0x70, 0x1e, 0x9e, 0x48, 0x65, 0xe2, + 0xef, 0x68, 0x6d, 0x5e, 0x19, 0x1b, 0x45, 0xf9, 0x8a, 0xe0, 0x28, 0xca, 0x2b, 0x33, 0x4e, 0x1f, + 0x51, 0xce, 0x1c, 0xa0, 0xfc, 0x53, 0xf2, 0x80, 0xe0, 0x6f, 0x3b, 0x5c, 0xb9, 0xce, 0xa4, 0x63, + 0xdc, 0x4e, 0x21, 0xfa, 0x10, 0x26, 0x10, 0xe9, 0x49, 0x7f, 0x84, 0xbf, 0x87, 0x10, 0xb6, 0xbf, + 0x6a, 0xab, 0x10, 0xb9, 0x82, 0x26, 0xc5, 0xe1, 0xd5, 0x7a, 0xef, 0xd8, 0xee, 0xc4, 0x02, 0x2f, + 0x6e, 0x9e, 0x5e, 0xf1, 0xa5, 0x28, 0x83, 0x2a, 0x11, 0x2c, 0x9e, 0x5c, 0x50, 0x97, 0x54, 0xc5, + 0x3d, 0xa6, 0x9a, 0x02, 0x08, 0x80, 0xd8, 0x76, 0xa4, 0x2b, 0x65, 0x47, 0xd6, 0x91, 0xfe, 0xf7, + 0x67, 0x34, 0x3e, 0x91, 0xcb, 0x6f, 0x69, 0xc1, 0x69, 0x70, 0xa5, 0x0c, 0xe5, 0x0d, 0x40, 0xeb, + 0x01, 0x93, 0x81, 0x7b, 0x45, 0x52, 0x3a, 0xf7, 0xf0, 0x8e, 0x1a, 0x4e, 0x7d, 0xa4, 0xe0, 0x12, + 0x25, 0xe2, 0xa4, 0xc1, 0xa5, 0xa0, 0x45, 0xbf, 0xfc, 0x80, 0x46, 0x06, 0xe4, 0x34, 0xd2, 0x35, + 0x20, 0xe5, 0x38, 0x7d, 0x63, 0x74, 0x90, 0x83, 0x4a, 0x4f, 0x3f, 0x30, 0x9f, 0x88, 0x46, 0xe2, + 0xb2, 0xf4, 0xf4, 0xc3, 0xb6, 0x88, 0x14, 0xd8, 0xa0, 0x7e, 0x04, 0x58, 0x00, 0x70, 0x03, 0x60, + 0x24, 0xe4, 0x08, 0xd2, 0x75, 0xef, 0x19, 0xb4, 0x46, 0xa4, 0x68, 0xa6, 0x19, 0x0b, 0x06, 0x10, + 0x19, 0x34, 0x3f, 0xc0, 0x66, 0x40, 0xcd, 0x86, 0xaa, 0x6c, 0xb1, 0x29, 0x81, 0x6a, 0x0b, 0x34, + 0xf7, 0x5a, 0x70, 0x1b, 0xd8, 0x17, 0x42, 0xa3, 0xbc, 0x39, 0xd6, 0x30, 0x17, 0x0a, 0x17, 0x38, + 0xce, 0x19, 0xc5, 0xdb, 0x16, 0x0a, 0x59, 0xa5, 0x17, 0x1c, 0xb5, 0x80, 0x13, 0x07, 0x68, 0x97, + 0x48, 0xde, 0x4c, 0xe7, 0xb6, 0x29, 0xe4, 0x34, 0xd7, 0x7b, 0x42, 0xd0, 0xcc, 0x80, 0xbe, 0xc9, + 0xf3, 0x96, 0xde, 0xf0, 0x0a, 0xd8, 0x2f, 0xcb, 0x8d, 0x21, 0x12, 0x28, 0xc0, 0xbb, 0x19, 0x1b, + 0x9f, 0x54, 0x32, 0xa7, 0x7d, 0xbc, 0x3e, 0x85, 0xad, 0x05, 0xa7, 0xbb, 0x44, 0x6c, 0x44, 0x91, + 0x35, 0xb1, 0xaa, 0xc3, 0xb5, 0x4c, 0x24, 0xe2, 0xea, 0xe4, 0x67, 0x26, 0x52, 0x15, 0x9a, 0xb5, + 0xe2, 0x51, 0xa3, 0x61, 0xbe, 0xb0, 0xb6, 0x6d, 0x58, 0x50, 0x11, 0x41, 0x4c, 0x4f, 0x78, 0xf5, + 0xaa, 0xb9, 0x6b, 0x5e, 0xe2, 0xc5, 0xc9, 0x4c, 0x24, 0x80, 0xb1, 0xb5, 0x08, 0xa5, 0x26, 0xa2, + 0x26, 0x60, 0x10, 0x4a, 0x01, 0x03, 0xc0, 0x18, 0x26, 0x0c, 0x03, 0x1a, 0x37, 0x2e, 0x4f, 0x27, + 0x8c, 0xac, 0x1a, 0xf1, 0xea, 0x87, 0x14, 0xd7, 0xce, 0x1c, 0x2b, 0x4e, 0x6e, 0x04, 0xb1, 0x32, + 0x5b, 0x8d, 0x50, 0x06, 0x9a, 0x09, 0x18, 0xd5, 0x54, 0xc4, 0x68, 0xd4, 0x00, 0x3c, 0x0d, 0x9a, + 0xe5, 0x4d, 0xa7, 0x73, 0xf6, 0xc9, 0x24, 0x59, 0x4d, 0x11, 0xfa, 0x21, 0xfb, 0x4d, 0x8b, 0xc2, + 0xf9, 0x46, 0x04, 0x2f, 0xb3, 0x4c, 0x05, 0x2f, 0xf8, 0x48, 0xdc, 0xb0, 0x40, 0x45, 0xf4, 0x81, + 0x6a, 0x3a, 0x62, 0x63, 0x23, 0xee, 0xc3, 0xf8, 0x10, 0x5e, 0x4a, 0xb1, 0x64, 0x6d, 0xf4, 0x38, + 0x1a, 0xd4, 0x5f, 0x73, 0xc6, 0x31, 0xa4, 0x3a, 0x0f, 0xe2, 0x45, 0x6b, 0x3a, 0x62, 0x2c, 0x4e, + 0x12, 0xac, 0xb5, 0xb6, 0x88, 0xf1, 0x33, 0x1a, 0x6a, 0x2d, 0x03, 0xcc, 0x1e, 0x3f, 0x9e, 0xa6, + 0xa2, 0x2f, 0x33, 0x10, 0x9e, 0x3c, 0xc7, 0x8a, 0xf4, 0x4d, 0xaf, 0xac, 0x4c, 0x29, 0xaa, 0x96, + 0xa7, 0x23, 0xc0, 0xec, 0x91, 0x71, 0xeb, 0xd7, 0x06, 0xee, 0x7e, 0xc5, 0xc4, 0x3e, 0x43, 0xee, + 0xfb, 0x8b, 0xb6, 0x86, 0x35, 0xb2, 0x16, 0xce, 0x9b, 0x70, 0x01, 0x63, 0xad, 0x19, 0xf0, 0x9e, + 0x4c, 0x86, 0x33, 0x62, 0x11, 0x09, 0xfe, 0xc4, 0x9a, 0x2b, 0x48, 0x0b, 0x4e, 0x0b, 0x81, 0x07, + 0xd3, 0x1a, 0xaf, 0xb3, 0xdc, 0x11, 0x9e, 0xf0, 0xfa, 0xdb, 0xd9, 0x80, 0x4f, 0xb1, 0xf4, 0xf6, + 0xdd, 0x4d, 0xa7, 0xcf, 0xf1, 0x84, 0x8d, 0xfc, 0x79, 0x27, 0x27, 0xd3, 0x00, 0x8c, 0x02, 0x31, + 0x17, 0x88, 0x25, 0x88, 0x85, 0x03, 0x99, 0x5a, 0x28, 0x7e, 0x77, 0x13, 0xf0, 0x25, 0x4e, 0x57, + 0xc7, 0xcd, 0xfd, 0x94, 0x6a, 0xa8, 0x00, 0x40, 0x7a, 0x10, 0x64, 0x40, 0x7a, 0x9d, 0xee, 0xaf, + 0x94, 0xba, 0x90, 0xfb, 0x29, 0xfb, 0xb9, 0x0e, 0xa1, 0xe2, 0x06, 0xf5, 0xc2, 0x63, 0xd0, 0xf5, + 0x0a, 0x80, 0x63, 0x76, 0x01, 0xa7, 0xe9, 0x42, 0x80, 0xdf, 0x3a, 0x40, 0xef, 0x79, 0x2b, 0xf8, + 0x0c, 0xd0, 0xc2, 0xd6, 0x6c, 0x71, 0x00, 0x37, 0x34, 0x61, 0x53, 0x23, 0x08, 0x5c, 0x16, 0xc0, + 0x85, 0xf4, 0x0c, 0xc8, 0x1f, 0xea, 0x3d, 0xdd, 0x73, 0xd3, 0x2b, 0x81, 0x50, 0x7e, 0xc0, 0xd9, + 0x5a, 0xc2, 0x38, 0x08, 0xd4, 0xc3, 0x28, 0x85, 0xba, 0x89, 0xdc, 0x57, 0x69, 0x21, 0x5c, 0x8f, + 0x60, 0xf0, 0x66, 0x77, 0x80, 0xeb, 0xb3, 0xd4, 0x99, 0x43, 0x10, 0xc5, 0xdc, 0xe3, 0x39, 0xfe, + 0x1d, 0xde, 0x16, 0x9c, 0xee, 0x7f, 0x10, 0x19, 0x02, 0xf3, 0x0f, 0x34, 0x62, 0x3c, 0xad, 0x7e, + 0xc5, 0x07, 0x9f, 0xb7, 0x93, 0xbf, 0x13, 0x5e, 0xd9, 0xfa, 0x79, 0xd6, 0xcc, 0x01, 0x4a, 0x7c, + 0x9d, 0x4d, 0x93, 0x4c, 0xba, 0xf6, 0x44, 0x9c, 0xf7, 0xb3, 0xa9, 0x14, 0x51, 0x5b, 0x2d, 0x4e, + 0xef, 0xf0, 0xfa, 0x80, 0xc6, 0x45, 0x0b, 0x28, 0x8b, 0xd2, 0x08, 0x62, 0x49, 0x3c, 0xc5, 0x06, + 0xdd, 0xb9, 0xf4, 0xd3, 0xb1, 0xa4, 0x1f, 0xa3, 0x2d, 0xe4, 0x62, 0x3a, 0x09, 0xb4, 0xe5, 0xdd, + 0xd1, 0x78, 0xa8, 0xe4, 0xe2, 0x27, 0x25, 0xf8, 0xc2, 0x30, 0x1b, 0x9c, 0xb3, 0xdc, 0xb4, 0x80, + 0x5e, 0x77, 0xc2, 0x7d, 0x13, 0x19, 0xa2, 0x3c, 0xda, 0xe2, 0xc4, 0x09, 0x0b, 0x70, 0x72, 0x99, + 0x44, 0x1a, 0x87, 0xb1, 0x64, 0x10, 0xc0, 0xf5, 0xe0, 0x13, 0xb1, 0x64, 0xd8, 0x89, 0x41, 0x83, + 0x10, 0x54, 0x05, 0x2c, 0x00, 0xfe, 0x65, 0xf0, 0x14, 0x15, 0xdd, 0x39, 0xfd, 0x5c, 0x8a, 0x5a, + 0x59, 0x45, 0xc4, 0x78, 0x3f, 0x32, 0xc4, 0x4c, 0x30, 0x96, 0xdc, 0x1e, 0x1f, 0xe5, 0x76, 0xbd, + 0x67, 0x96, 0x21, 0xdf, 0x67, 0x5f, 0xb2, 0xe2, 0x2e, 0xbf, 0x8c, 0x68, 0x8a, 0x1f, 0xfa, 0x09, + 0x7f, 0x42, 0x15, 0xd9, 0xf5, 0x31, 0x0f, 0x62, 0x49, 0xe0, 0x11, 0x0d, 0xb3, 0x4f, 0xac, 0x8d, + 0x85, 0xb7, 0xe0, 0xb4, 0xe0, 0xcf, 0x82, 0xa9, 0x03, 0xce, 0x82, 0x79, 0x0e, 0xe9, 0x9d, 0xac, + 0xee, 0xb5, 0x06, 0xa1, 0x5d, 0x63, 0xd8, 0x7e, 0x69, 0xa1, 0x2c, 0x08, 0x9f, 0x2e, 0xa8, 0x83, + 0xd4, 0xb2, 0x8e, 0xb5, 0x6f, 0x9d, 0x3a, 0x0c, 0x83, 0x53, 0x59, 0x4f, 0xdd, 0x42, 0x4c, 0x0c, + 0xc6, 0xba, 0x77, 0xea, 0xa5, 0x32, 0x5d, 0x71, 0x68, 0x14, 0x08, 0x55, 0x57, 0x27, 0xff, 0xfb, + 0x40, 0x3a, 0x94, 0xf8, 0x2e, 0xf9, 0x20, 0x30, 0xea, 0x03, 0x83, 0xa3, 0x5f, 0xbd, 0x71, 0x88, + 0xc5, 0x1b, 0xc0, 0xdd, 0x1c, 0x8a, 0x2a, 0xc1, 0x06, 0x13, 0x00, 0x54, 0x1e, 0xe1, 0xd9, 0x60, + 0x44, 0x2a, 0x08, 0x83, 0x63, 0x7d, 0x96, 0xf0, 0xc2, 0x2d, 0x34, 0x7f, 0x05, 0xa0, 0x39, 0xc6, + 0x21, 0x35, 0xa5, 0xc6, 0xbd, 0x92, 0xf6, 0xda, 0x89, 0x31, 0x55, 0xdd, 0x2b, 0x02, 0x77, 0x2e, + 0xdb, 0x4b, 0x24, 0x67, 0x2e, 0xf8, 0x1b, 0xd5, 0xc1, 0xa6, 0xb7, 0x9f, 0x0c, 0x30, 0xcd, 0x5f, + 0x85, 0x9d, 0xc1, 0x26, 0xe8, 0xeb, 0xb3, 0xd7, 0x5d, 0x8f, 0xe7, 0xf8, 0x6f, 0xb6, 0xe0, 0x74, + 0xef, 0x9f, 0xbd, 0xce, 0x41, 0x43, 0x31, 0xb5, 0x77, 0x4e, 0x28, 0x5c, 0x39, 0x61, 0xab, 0x35, + 0x41, 0x84, 0xb7, 0xaa, 0x07, 0xbc, 0x83, 0x05, 0xb9, 0xde, 0xcd, 0xf5, 0x48, 0xe4, 0x07, 0xae, + 0x47, 0xd0, 0x17, 0x18, 0xa2, 0x2e, 0x91, 0xec, 0x80, 0x16, 0x0c, 0x40, 0x83, 0x25, 0x57, 0xb8, + 0x08, 0xa5, 0xbc, 0xe9, 0xad, 0x72, 0x3c, 0xf5, 0xc3, 0x35, 0x41, 0xb8, 0x25, 0x38, 0x90, 0x27, + 0x20, 0xbc, 0x8c, 0x5b, 0xaf, 0x03, 0xba, 0x72, 0xc4, 0xf2, 0x70, 0x85, 0x0f, 0xf9, 0x7d, 0xf4, + 0xae, 0x94, 0xdf, 0x41, 0xfe, 0x04, 0x78, 0xc6, 0x83, 0x0e, 0x81, 0x16, 0xd0, 0xc3, 0x0a, 0x6f, + 0x4e, 0x00, 0xa3, 0x88, 0x5c, 0xbf, 0x2a, 0x82, 0x68, 0x05, 0xc8, 0x1d, 0x78, 0x3d, 0xf7, 0x44, + 0xde, 0xca, 0x76, 0x0b, 0x4e, 0x2b, 0xff, 0xa2, 0x08, 0x75, 0xf2, 0xe3, 0x8d, 0x28, 0x7b, 0x34, + 0x49, 0x46, 0xe6, 0xec, 0x30, 0xca, 0x5e, 0x7b, 0x79, 0x63, 0xee, 0x40, 0x40, 0x1d, 0x71, 0xac, + 0x3d, 0x88, 0xcb, 0x5f, 0x34, 0x23, 0x79, 0x43, 0x9d, 0xb9, 0xb9, 0xae, 0x1c, 0xf3, 0xe7, 0x4d, + 0x3b, 0x4d, 0x48, 0xa8, 0x33, 0xb2, 0x77, 0x62, 0xe6, 0xe6, 0xed, 0x59, 0x10, 0x65, 0x7b, 0xb4, + 0x13, 0xa1, 0x12, 0xd4, 0xd0, 0x34, 0xc5, 0x4e, 0x59, 0x96, 0xca, 0xaf, 0x1a, 0xf6, 0x46, 0x82, + 0x47, 0x94, 0xcc, 0x83, 0x28, 0x7b, 0x3b, 0xfc, 0xb9, 0xfc, 0x6a, 0x3b, 0x38, 0xd7, 0x7c, 0x8f, + 0x10, 0x0c, 0xee, 0x39, 0xe4, 0xcf, 0xc5, 0xe5, 0xe4, 0xd7, 0x1c, 0x88, 0xcb, 0xd5, 0x8f, 0xa2, + 0x6c, 0x5b, 0xd8, 0x48, 0xdc, 0xc4, 0xe5, 0x44, 0xa7, 0x70, 0x5a, 0x0b, 0x3f, 0xe9, 0x22, 0xda, + 0x69, 0xc3, 0x16, 0xd3, 0xeb, 0xc1, 0x27, 0xe2, 0xf2, 0xad, 0xac, 0xd3, 0xf3, 0x62, 0x27, 0xdd, + 0x88, 0xcb, 0x7d, 0xab, 0x45, 0x4d, 0x61, 0x71, 0x8b, 0x2f, 0x89, 0x3e, 0x5e, 0x45, 0x42, 0xbb, + 0xd6, 0x82, 0xd3, 0x9a, 0x66, 0xa4, 0xbc, 0xe8, 0x07, 0xfa, 0x07, 0x23, 0x65, 0xa0, 0x6b, 0x4a, + 0x03, 0x30, 0x17, 0x9d, 0xfc, 0x71, 0xb0, 0xe9, 0x24, 0x40, 0x2c, 0x0c, 0x8e, 0x81, 0x48, 0xd9, + 0xbc, 0x88, 0xf5, 0x09, 0x88, 0xdb, 0xd0, 0x38, 0xca, 0xb2, 0x10, 0x8b, 0xb3, 0xeb, 0x64, 0x18, + 0x6b, 0xfc, 0xea, 0xa5, 0x2b, 0xee, 0xa1, 0xd7, 0x1b, 0x51, 0x36, 0xda, 0x0b, 0x94, 0xf5, 0xcd, + 0x2f, 0x1f, 0xe6, 0x74, 0x05, 0x35, 0x61, 0xae, 0xd5, 0xe3, 0xa2, 0x88, 0x8a, 0x21, 0x02, 0xa3, + 0xf0, 0x75, 0x96, 0x6a, 0x99, 0x75, 0x11, 0xc7, 0xb7, 0xcf, 0x9f, 0xa9, 0x72, 0x33, 0xa8, 0x7d, + 0x4b, 0xee, 0x36, 0x3f, 0xc6, 0x2a, 0xd6, 0xc4, 0x6c, 0xa8, 0x5b, 0xd9, 0x3c, 0x8b, 0x53, 0x06, + 0xfb, 0x38, 0xe7, 0xe9, 0xc2, 0xa5, 0xc9, 0xe8, 0xe4, 0x01, 0x1c, 0x07, 0xfa, 0x7d, 0x25, 0x5e, + 0xb6, 0x1f, 0xc0, 0x8e, 0x87, 0x56, 0xbc, 0xa2, 0xb0, 0xfc, 0x46, 0xca, 0x16, 0x51, 0xfc, 0x69, + 0x61, 0x59, 0xa9, 0x74, 0x49, 0x9b, 0x9a, 0xf1, 0xbf, 0x31, 0xfe, 0xf4, 0x2a, 0x50, 0x32, 0xc9, + 0xc1, 0x8a, 0x4f, 0xa4, 0x5a, 0x41, 0x3b, 0x44, 0xa2, 0xa7, 0xc5, 0xab, 0x1f, 0xa8, 0x1b, 0x21, + 0x94, 0xca, 0x2e, 0xd9, 0xc9, 0xcc, 0xc6, 0xc9, 0xb1, 0xe7, 0x79, 0xe1, 0x76, 0xad, 0x9f, 0x39, + 0x6d, 0x4a, 0xa5, 0x59, 0x46, 0xfe, 0xbe, 0xd5, 0x6d, 0x14, 0x1d, 0xbc, 0x16, 0xdf, 0xb0, 0x43, + 0x74, 0x1f, 0x04, 0x2b, 0xee, 0xa1, 0x86, 0x1b, 0x83, 0xe0, 0x02, 0x1f, 0xd7, 0x95, 0xb3, 0x29, + 0x39, 0x24, 0x01, 0x43, 0x72, 0xf1, 0xdd, 0xb3, 0xc8, 0x7d, 0x00, 0x7d, 0xa7, 0x99, 0xf2, 0xda, + 0xa6, 0x3d, 0x0e, 0xd3, 0x1b, 0x98, 0xf8, 0xe0, 0x4e, 0x9c, 0x7f, 0xff, 0x92, 0x87, 0x01, 0x83, + 0x06, 0x98, 0x38, 0xda, 0x08, 0xf0, 0x0d, 0xf1, 0x14, 0xbb, 0x1b, 0xe6, 0x47, 0x7c, 0xff, 0x18, + 0xbc, 0x0b, 0x17, 0xec, 0x37, 0x61, 0xf8, 0xbd, 0xb3, 0x5a, 0x35, 0x17, 0x99, 0x3c, 0x58, 0xd8, + 0x08, 0xf6, 0x59, 0x89, 0xdc, 0x5b, 0x4b, 0xe9, 0xf6, 0x65, 0xe0, 0x33, 0xee, 0x19, 0xf2, 0xd9, + 0x47, 0x1e, 0x40, 0xd1, 0xd3, 0xd5, 0x82, 0xd3, 0xb0, 0x00, 0x38, 0x68, 0x53, 0xc1, 0x55, 0xe7, + 0xbe, 0x18, 0x09, 0x0c, 0x8c, 0x64, 0xf6, 0x2b, 0x66, 0x4b, 0x93, 0xa9, 0xe3, 0xe0, 0x6d, 0xfc, + 0x6e, 0x34, 0x45, 0x71, 0x7d, 0x23, 0xe2, 0x4f, 0x00, 0x0b, 0x4b, 0x42, 0x1e, 0x85, 0xd1, 0xcf, + 0xbe, 0x2b, 0xbc, 0x44, 0xad, 0xef, 0x40, 0x24, 0xc1, 0x8f, 0x47, 0xe6, 0xd6, 0xf1, 0x66, 0x0b, + 0x5f, 0xe6, 0x36, 0x7e, 0x07, 0x1b, 0x6d, 0x73, 0x28, 0x4e, 0x12, 0x82, 0x67, 0xdd, 0x11, 0x1b, + 0x70, 0x8b, 0x58, 0x94, 0xff, 0x44, 0xfc, 0x0e, 0x5b, 0x78, 0xf5, 0x13, 0xcb, 0x9c, 0x15, 0xc7, + 0xf8, 0xdb, 0xf7, 0x2d, 0xa3, 0x2d, 0xa3, 0x26, 0xd7, 0x82, 0xb7, 0xf1, 0xbb, 0x26, 0x31, 0x85, + 0x9b, 0x00, 0x30, 0xef, 0xd9, 0x36, 0xbb, 0xb5, 0x4f, 0x70, 0x1f, 0xe0, 0x1b, 0x53, 0xea, 0x7e, + 0xc4, 0x1f, 0xa2, 0x20, 0xe6, 0x49, 0x83, 0xf8, 0xdd, 0xda, 0xc0, 0x4b, 0x60, 0x23, 0xbb, 0xd3, + 0x82, 0x7d, 0xde, 0x88, 0xdf, 0x9b, 0xbd, 0xc2, 0x2d, 0x8d, 0x4b, 0x40, 0xfc, 0x61, 0xcd, 0x4c, + 0x2c, 0xc2, 0x11, 0x7c, 0x14, 0xc6, 0x32, 0xe0, 0x65, 0x52, 0x24, 0x1c, 0x5f, 0xf8, 0xf4, 0x78, + 0xcd, 0x3e, 0x54, 0xd8, 0x82, 0xd3, 0x23, 0x83, 0xf0, 0xcb, 0x8a, 0x9f, 0x18, 0x5c, 0x1a, 0x80, + 0xe1, 0xe6, 0x20, 0x00, 0xe4, 0x5a, 0x25, 0x02, 0xe4, 0x08, 0x81, 0xd0, 0x1c, 0x44, 0x9a, 0x68, + 0x0f, 0xb4, 0x64, 0x3d, 0x22, 0xe9, 0xc1, 0x23, 0xd9, 0xea, 0x97, 0xd2, 0xb4, 0x05, 0x44, 0x91, + 0xb4, 0x0d, 0x91, 0xd3, 0x2e, 0x23, 0x78, 0x0a, 0x01, 0x51, 0x2f, 0x10, 0x67, 0x39, 0xe7, 0xb1, + 0x5d, 0x30, 0x56, 0xbf, 0x51, 0x00, 0xa0, 0x3c, 0x3d, 0x0a, 0x6e, 0xc4, 0x0a, 0x34, 0xb1, 0x70, + 0x03, 0x44, 0x6a, 0xa9, 0x8b, 0x40, 0x40, 0xd8, 0xe7, 0x52, 0x42, 0xa0, 0xdd, 0x90, 0xe4, 0x3e, + 0xc5, 0x1d, 0x56, 0xa0, 0x36, 0xf1, 0x75, 0x64, 0xd8, 0x85, 0x48, 0x65, 0x50, 0x92, 0x01, 0xc6, + 0x56, 0x5f, 0xaf, 0xa6, 0x85, 0x70, 0x78, 0x7a, 0xe0, 0xce, 0x7b, 0xc8, 0xe8, 0x1e, 0x18, 0x04, + 0x73, 0xaf, 0xdc, 0x73, 0xa3, 0x37, 0xb6, 0x81, 0xeb, 0x20, 0xd3, 0xc6, 0x5d, 0xac, 0x54, 0xdc, + 0x89, 0x39, 0x2d, 0xd7, 0x2c, 0x92, 0xa1, 0x5d, 0xb7, 0x23, 0x74, 0x6a, 0xe4, 0x3a, 0x2a, 0xe7, + 0x8e, 0x0d, 0x34, 0xd6, 0x16, 0x7b, 0x2c, 0xd3, 0x72, 0xa2, 0xbf, 0x05, 0xa7, 0xc7, 0x18, 0xee, + 0x3b, 0x49, 0xe6, 0x10, 0x7a, 0x0b, 0x7c, 0xbb, 0xbc, 0x95, 0x35, 0x31, 0x0c, 0x6e, 0xd4, 0x33, + 0x34, 0xe1, 0xe0, 0x62, 0xce, 0xd9, 0xeb, 0x3e, 0xe0, 0x65, 0x35, 0x13, 0xb1, 0xbc, 0x4d, 0x58, + 0x2f, 0x83, 0x11, 0x80, 0x9d, 0x33, 0x66, 0x86, 0xde, 0xc6, 0x48, 0x10, 0xa5, 0x9a, 0x52, 0x3e, + 0x10, 0xa5, 0xb2, 0xaa, 0x74, 0x10, 0x33, 0xd0, 0x20, 0xe6, 0x94, 0xa3, 0xb7, 0x51, 0xea, 0x46, + 0x30, 0x80, 0x4d, 0x66, 0xb1, 0x98, 0x3e, 0x93, 0x00, 0x91, 0x66, 0x8a, 0x08, 0x8c, 0xeb, 0x4b, + 0x6b, 0x01, 0xfc, 0x18, 0x78, 0xd2, 0x89, 0x40, 0xb4, 0x6c, 0x63, 0x17, 0x90, 0x8a, 0x63, 0x48, + 0x41, 0xdf, 0x89, 0x39, 0x83, 0xa5, 0x72, 0x26, 0x10, 0xc1, 0xeb, 0x56, 0x06, 0xc7, 0x54, 0x87, + 0x3e, 0x1c, 0xd3, 0xa7, 0x23, 0x10, 0x4a, 0x1f, 0xee, 0x84, 0xe7, 0xd4, 0xc0, 0x10, 0x91, 0x38, + 0x49, 0xf9, 0x6e, 0x22, 0x48, 0x87, 0xfe, 0x3c, 0x13, 0x09, 0x1a, 0x58, 0x26, 0x82, 0x27, 0x52, + 0x95, 0x80, 0x15, 0x8e, 0x3a, 0xb1, 0xf3, 0x87, 0xd1, 0xd7, 0x1c, 0x02, 0xc8, 0x06, 0xa3, 0x2f, + 0xd9, 0x90, 0xd3, 0xc3, 0x5f, 0x0b, 0x1a, 0x6e, 0x5a, 0x0c, 0x29, 0x98, 0x20, 0x5e, 0x60, 0x60, + 0x18, 0xb9, 0x0e, 0x1c, 0x7a, 0x28, 0xc7, 0x45, 0x9a, 0x2f, 0x33, 0x59, 0x3f, 0x54, 0xe9, 0x88, + 0xc1, 0x44, 0xc3, 0x98, 0xd3, 0x84, 0xe9, 0xaf, 0xdd, 0x0a, 0xc6, 0xca, 0xc1, 0xc5, 0x6a, 0xa0, + 0x3e, 0xeb, 0xc7, 0x1b, 0x99, 0xed, 0x38, 0xbe, 0xc8, 0x45, 0xa9, 0xba, 0xad, 0x30, 0xfa, 0x78, + 0x44, 0x45, 0x2b, 0x68, 0xc1, 0xe9, 0x17, 0xa9, 0xa6, 0x43, 0x1b, 0x2d, 0xb0, 0xd7, 0xae, 0xcd, + 0x6e, 0x6f, 0xfc, 0x22, 0x31, 0x63, 0xd9, 0x08, 0xbe, 0xb6, 0xa6, 0x02, 0x7b, 0x5d, 0x71, 0x06, + 0xa8, 0xf3, 0x34, 0xfc, 0xf8, 0xe3, 0xcb, 0xbe, 0x84, 0x6a, 0xbc, 0x31, 0xfe, 0xef, 0x4b, 0x55, + 0xf6, 0x0f, 0xae, 0x81, 0xcf, 0xe9, 0x5f, 0x05, 0xda, 0xb3, 0x37, 0xfa, 0x40, 0xcd, 0x1f, 0xc1, + 0xb0, 0xaf, 0x5f, 0x2a, 0x1f, 0x7f, 0xcb, 0xec, 0x86, 0x8b, 0x89, 0x84, 0x92, 0x5e, 0xba, 0x4a, + 0x55, 0x1d, 0x11, 0x7c, 0x32, 0x45, 0x2e, 0xe7, 0x59, 0x15, 0xe3, 0x3b, 0xa7, 0xca, 0x53, 0xe1, + 0x52, 0xbd, 0x87, 0x21, 0x4a, 0x09, 0x64, 0xea, 0xe0, 0xbf, 0x02, 0xe5, 0x37, 0x2d, 0x31, 0x21, + 0xe8, 0xe3, 0x86, 0xc4, 0xcd, 0x70, 0x91, 0x00, 0xf8, 0x4b, 0x6f, 0xe6, 0x00, 0x06, 0x84, 0x1f, + 0x52, 0x00, 0x3a, 0x04, 0xb2, 0x30, 0xfc, 0x2f, 0x6a, 0x6e, 0x41, 0x28, 0x70, 0x71, 0xff, 0x4f, + 0x35, 0x51, 0x3e, 0xd8, 0xcc, 0xb1, 0xd9, 0x0d, 0x6a, 0xff, 0xd1, 0x3f, 0x94, 0x0a, 0x4b, 0x6f, + 0x0b, 0x4e, 0x5b, 0x1a, 0xab, 0xcf, 0x35, 0x9e, 0x0c, 0x70, 0xb2, 0xfa, 0xd6, 0xa3, 0x83, 0x30, + 0xbd, 0xe1, 0x58, 0x80, 0x87, 0x20, 0x7a, 0xef, 0xf8, 0x19, 0x70, 0x71, 0x33, 0x7e, 0x07, 0x3a, + 0x24, 0x80, 0x6e, 0x02, 0x78, 0x2b, 0xc4, 0xd2, 0x81, 0x48, 0xae, 0xe3, 0x7c, 0x25, 0x82, 0xdc, + 0x8b, 0xf8, 0x81, 0x63, 0xb9, 0x8d, 0xf8, 0x39, 0x43, 0x84, 0x34, 0x43, 0x2e, 0x2e, 0x7e, 0x07, + 0xde, 0x6f, 0x10, 0x91, 0xa1, 0xf7, 0xc7, 0x08, 0xd0, 0x3b, 0x2d, 0x38, 0x6d, 0xef, 0x83, 0xfa, + 0xcc, 0x8d, 0x4f, 0xab, 0xe1, 0xe2, 0x80, 0x6a, 0xc9, 0xbd, 0x88, 0x7f, 0x80, 0x1b, 0x55, 0xb8, + 0xf6, 0x65, 0xca, 0x3e, 0xa8, 0xde, 0x0a, 0x60, 0x65, 0x6c, 0xa0, 0x57, 0x39, 0x8d, 0x1a, 0x91, + 0xd1, 0xc6, 0x41, 0xe9, 0xc3, 0xaf, 0x94, 0xeb, 0x69, 0x02, 0xfc, 0xe6, 0xb2, 0x83, 0x3c, 0xb9, + 0x9c, 0x06, 0xe1, 0xbb, 0x84, 0xce, 0xd9, 0x80, 0xe1, 0x41, 0x1e, 0x7e, 0xa0, 0x01, 0x6e, 0x44, + 0x0d, 0xd8, 0xc3, 0x76, 0x7e, 0x70, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, + 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xfd, 0xcf, 0x24, 0xf8, + 0x7f, 0xf0, 0xcd, 0x1f, 0xc5, 0x98, 0xea, 0xec, 0xdc, 0xb1, 0x54, 0x7f, 0xbd, 0xeb, 0xc0, 0x3d, + 0x47, 0x55, 0x72, 0xc8, 0x30, 0x72, 0x6e, 0xff, 0x76, 0x41, 0x95, 0xed, 0xa7, 0x1e, 0xb6, 0xdb, + 0x5e, 0x71, 0xe8, 0x54, 0x0c, 0x31, 0x0a, 0x76, 0xb3, 0x6f, 0xb3, 0x63, 0x4c, 0x96, 0xcd, 0x52, + 0x8e, 0x93, 0xcb, 0x37, 0xca, 0x8a, 0x5d, 0x57, 0x24, 0x1d, 0xcb, 0x8a, 0x74, 0x85, 0x21, 0xdc, + 0x86, 0x97, 0x8e, 0xe8, 0xd0, 0xd0, 0x9a, 0x83, 0xc0, 0xf5, 0xa9, 0xa9, 0xe5, 0xb7, 0xa5, 0xba, + 0x03, 0x2f, 0x1a, 0xcf, 0xa7, 0x70, 0xcf, 0x2a, 0x33, 0x65, 0x0c, 0xea, 0x99, 0x29, 0xd9, 0xaa, + 0x57, 0x34, 0x3a, 0x83, 0x4f, 0x8c, 0xb1, 0x6c, 0x4f, 0xff, 0xa0, 0xf5, 0xf4, 0x4b, 0x4c, 0xbc, + 0x55, 0x5b, 0x50, 0xf7, 0x3a, 0x16, 0x9e, 0x58, 0xc7, 0x7f, 0xcd, 0xf0, 0x74, 0xce, 0xec, 0xbf, + 0x95, 0x1a, 0x4b, 0xe0, 0x3a, 0xf9, 0xd6, 0xb7, 0xcb, 0xe1, 0xd4, 0x54, 0x24, 0x95, 0xa1, 0xa8, + 0xba, 0x23, 0x96, 0xce, 0xd4, 0x82, 0xea, 0xde, 0x68, 0x2d, 0x36, 0x59, 0xa1, 0x2d, 0xee, 0xa1, + 0x5e, 0x98, 0x53, 0x54, 0x76, 0x60, 0x2c, 0xd8, 0x2c, 0x2f, 0xf4, 0x96, 0x1d, 0x44, 0xc9, 0x94, + 0x9a, 0x5a, 0x02, 0xc7, 0xec, 0x15, 0x5c, 0xa7, 0xda, 0x21, 0xf0, 0xe1, 0x5d, 0x66, 0xb0, 0x46, + 0x55, 0xb7, 0xc0, 0x75, 0xd5, 0x29, 0xff, 0x45, 0x4c, 0xce, 0xc0, 0xb3, 0x5b, 0x25, 0xdc, 0x20, + 0xdf, 0xca, 0x2e, 0x8c, 0x00, 0xe6, 0x01, 0x6e, 0x4d, 0x0d, 0xe9, 0x62, 0xdd, 0xf6, 0xaf, 0x3e, + 0x6f, 0x61, 0x72, 0xc9, 0x0f, 0x36, 0x77, 0xe6, 0x27, 0xa2, 0x1d, 0x37, 0x1d, 0x12, 0x70, 0x53, + 0xe7, 0x84, 0xd3, 0x7f, 0xde, 0xf1, 0xc9, 0x95, 0x1c, 0xaa, 0x94, 0x9b, 0x31, 0xdf, 0x80, 0x5a, + 0x96, 0xeb, 0x91, 0xca, 0x2a, 0x8a, 0x92, 0xb5, 0x91, 0x75, 0x33, 0x8d, 0xf1, 0x4a, 0xdb, 0x39, + 0x8b, 0x56, 0x22, 0x71, 0xb9, 0x84, 0x22, 0xc9, 0xfc, 0x0a, 0xc6, 0xb7, 0xaf, 0xfb, 0xa2, 0xb6, + 0x41, 0x17, 0xd1, 0xcc, 0xb0, 0x31, 0xaf, 0xfb, 0x50, 0xfb, 0xcd, 0xe4, 0x01, 0x6e, 0xc1, 0x72, + 0x91, 0x64, 0x39, 0xf7, 0x37, 0xce, 0x68, 0xec, 0xe1, 0xb5, 0xf8, 0x86, 0xcf, 0xd4, 0xcc, 0xbb, + 0x52, 0xd4, 0x60, 0x58, 0xaa, 0x6d, 0xec, 0x89, 0xb4, 0xff, 0x58, 0xd5, 0x17, 0x8d, 0xef, 0x89, + 0x46, 0xaf, 0x45, 0xce, 0x15, 0x14, 0xbc, 0x53, 0x47, 0x97, 0x54, 0x2a, 0xcb, 0x75, 0xdc, 0xe5, + 0x07, 0xfa, 0x4f, 0xaf, 0x61, 0x79, 0x6c, 0x41, 0x2b, 0x11, 0x5d, 0x4f, 0xb7, 0xee, 0x53, 0x0c, + 0x13, 0x4a, 0x2b, 0x92, 0xb0, 0x8c, 0x05, 0xb7, 0x97, 0x75, 0xa9, 0x2b, 0x2a, 0x58, 0x64, 0xc9, + 0xed, 0xd0, 0x45, 0x2a, 0x39, 0x65, 0x71, 0xeb, 0x53, 0xe4, 0xf2, 0x68, 0xb2, 0x4c, 0xe2, 0x6e, + 0x6d, 0xd5, 0xf1, 0xe9, 0xb2, 0xf7, 0x9c, 0x31, 0x2e, 0x68, 0x7f, 0x60, 0xa2, 0x4b, 0xe7, 0x6e, + 0xc6, 0x98, 0x2f, 0x55, 0xb7, 0x2e, 0x2e, 0x62, 0xdd, 0x53, 0xc6, 0x52, 0x39, 0x93, 0x19, 0xad, + 0x51, 0xf5, 0xc8, 0xf2, 0xe2, 0xc6, 0xee, 0xd4, 0x60, 0x2d, 0xd6, 0xed, 0xc8, 0xaa, 0xe9, 0x33, + 0x20, 0x45, 0xb1, 0xee, 0xd3, 0xda, 0x82, 0xad, 0xee, 0x58, 0xaa, 0xc5, 0x14, 0xbb, 0x16, 0xc7, + 0x70, 0xea, 0x78, 0xec, 0x7d, 0x35, 0xae, 0xff, 0xbc, 0xea, 0x8b, 0x87, 0x96, 0x3c, 0xff, 0x7e, + 0x4e, 0xac, 0xab, 0xe3, 0x39, 0x95, 0x8d, 0x14, 0x13, 0x41, 0x75, 0xe9, 0xf1, 0x9c, 0xa4, 0x8e, + 0xae, 0x16, 0x9c, 0xfe, 0xab, 0x6f, 0xdc, 0xa9, 0xd8, 0xcf, 0x40, 0x6d, 0x3f, 0xa9, 0x25, 0xab, + 0xf6, 0xac, 0x2e, 0x59, 0x27, 0x89, 0x52, 0xf9, 0xa5, 0x23, 0xf4, 0xc7, 0x9b, 0xee, 0xed, 0xd3, + 0x89, 0xc4, 0x2f, 0x8e, 0xac, 0xbd, 0x72, 0x4e, 0xbe, 0xbb, 0x88, 0x01, 0x33, 0x80, 0x0f, 0xd3, + 0x0e, 0xf0, 0xc6, 0x2f, 0xc9, 0x65, 0x60, 0x1a, 0xe8, 0x70, 0xd4, 0x58, 0xdb, 0x2e, 0x29, 0xb2, + 0x2a, 0x26, 0xec, 0x01, 0x6d, 0x01, 0x03, 0x94, 0xfb, 0xc0, 0x34, 0x88, 0x13, 0x46, 0x8d, 0x4e, + 0xcc, 0x58, 0xfc, 0xf9, 0x20, 0x56, 0x2c, 0xd0, 0x65, 0xa8, 0x5f, 0xf5, 0xa9, 0x6c, 0xa4, 0x6c, + 0xdb, 0x30, 0xb2, 0x16, 0x60, 0x47, 0x0c, 0xca, 0x73, 0x32, 0x8b, 0x19, 0x2b, 0x54, 0x18, 0xd7, + 0x96, 0x89, 0xd3, 0x05, 0xed, 0xa5, 0x3d, 0xbb, 0xa0, 0x5e, 0xdf, 0x20, 0xf0, 0x23, 0x78, 0x71, + 0x4c, 0xcc, 0xdd, 0x8a, 0xb1, 0x94, 0x1a, 0x6d, 0xcf, 0x1d, 0xd9, 0x89, 0x58, 0x37, 0xfb, 0xed, + 0x72, 0xa2, 0x7b, 0xbf, 0xb2, 0x6c, 0xa9, 0x6e, 0x9d, 0x5f, 0xc5, 0xba, 0x8b, 0x17, 0x7f, 0xbc, + 0xd1, 0x30, 0x8e, 0x68, 0xf9, 0x45, 0x38, 0xab, 0x03, 0xda, 0x67, 0xd4, 0x79, 0x26, 0x19, 0xe3, + 0x6f, 0x87, 0x09, 0xbd, 0x13, 0xe5, 0x27, 0xb6, 0xb2, 0x07, 0x69, 0xf5, 0x9c, 0xc7, 0xcb, 0xdb, + 0x1b, 0x25, 0x62, 0x76, 0x38, 0x09, 0x98, 0x7f, 0x15, 0x78, 0x4b, 0x74, 0x71, 0x69, 0x40, 0xb0, + 0x2f, 0xc7, 0xb6, 0x80, 0x63, 0xb9, 0xb7, 0xea, 0x58, 0x9e, 0x58, 0x0d, 0x9e, 0xae, 0x7f, 0xf5, + 0xee, 0x35, 0xa6, 0xea, 0xa3, 0x5c, 0x4e, 0x21, 0xe4, 0x4b, 0xd8, 0xf2, 0x78, 0x9e, 0x9d, 0xb0, + 0x05, 0xa7, 0x47, 0x1e, 0x71, 0x75, 0x11, 0x4e, 0x3f, 0x76, 0xe6, 0x04, 0x7d, 0x8f, 0x3f, 0xa5, + 0x56, 0x25, 0x71, 0x12, 0x5d, 0x52, 0xb9, 0x61, 0xfe, 0xd0, 0xb6, 0x50, 0x65, 0x23, 0x46, 0xa6, + 0xc4, 0x2a, 0x34, 0xb4, 0x0c, 0x1d, 0x96, 0x03, 0x61, 0xa2, 0x0a, 0xa2, 0x88, 0x26, 0xeb, 0x60, + 0xcf, 0xff, 0xe8, 0x1d, 0x9b, 0xb9, 0xb8, 0x8c, 0xed, 0x32, 0x84, 0xe7, 0xe8, 0x7c, 0x2a, 0xb2, + 0x0c, 0x8c, 0x30, 0x9c, 0x7e, 0xbe, 0xf5, 0x23, 0xf3, 0xb6, 0x66, 0x17, 0x78, 0x7c, 0x2e, 0x11, + 0xc8, 0x15, 0xfe, 0xa8, 0x54, 0xce, 0x84, 0xbc, 0x02, 0xa5, 0x2b, 0x14, 0xbd, 0x4e, 0x92, 0xa6, + 0x4a, 0xd9, 0x60, 0xfa, 0xb2, 0x94, 0xdf, 0xcd, 0x0c, 0x5e, 0xb0, 0xbb, 0xc0, 0xb0, 0xd9, 0xed, + 0x91, 0xc8, 0x32, 0xd8, 0x2c, 0xcf, 0xc5, 0x5e, 0x9c, 0xd6, 0xb2, 0x6f, 0x6c, 0x40, 0xe2, 0x63, + 0xbb, 0x99, 0xca, 0x42, 0xf7, 0x7f, 0xbc, 0x63, 0x7f, 0xda, 0xec, 0x93, 0x94, 0xde, 0x47, 0xf8, + 0xa9, 0x69, 0x6e, 0x59, 0x80, 0x7b, 0x0f, 0x32, 0xaf, 0xa2, 0xe4, 0x44, 0x23, 0x1b, 0xc1, 0x49, + 0x08, 0xa5, 0xcd, 0x04, 0xeb, 0x15, 0x6f, 0xfc, 0xa9, 0x72, 0xab, 0x4f, 0x54, 0x46, 0x94, 0xa3, + 0xfd, 0x2d, 0x38, 0x6d, 0xfc, 0xce, 0xdb, 0x71, 0x16, 0x3b, 0xab, 0x3b, 0x82, 0x82, 0xb8, 0xb1, + 0xcb, 0x58, 0x70, 0x9d, 0x78, 0xeb, 0xa4, 0xde, 0x7b, 0x06, 0xac, 0xf3, 0xc6, 0xae, 0xbd, 0x82, + 0x19, 0x81, 0x9d, 0xae, 0xa5, 0x2b, 0x31, 0x6a, 0xbe, 0xb0, 0x91, 0xb6, 0x68, 0x4c, 0xcc, 0x8e, + 0xe9, 0x2a, 0x79, 0x4e, 0x0e, 0x79, 0x92, 0xe5, 0xad, 0x53, 0x37, 0xf0, 0x0f, 0x58, 0xf1, 0xec, + 0xaa, 0x04, 0x6e, 0x15, 0x37, 0x2f, 0x7a, 0x3a, 0xe3, 0x85, 0xbf, 0x9e, 0x8e, 0x2e, 0x6c, 0x4e, + 0x3f, 0x5f, 0x9a, 0x5b, 0xab, 0x39, 0x82, 0x9a, 0x84, 0x45, 0x63, 0xbe, 0xa2, 0xc6, 0x66, 0x0e, + 0xab, 0x94, 0x20, 0xa6, 0xf2, 0xf0, 0xe2, 0xa2, 0xf5, 0xe0, 0xf3, 0x20, 0x06, 0xbf, 0x9c, 0x14, + 0xfd, 0xe7, 0x21, 0xc3, 0xcd, 0x6e, 0x9f, 0x9e, 0x76, 0xf3, 0x33, 0xdb, 0xd5, 0x8b, 0x9a, 0x78, + 0x56, 0xa1, 0xed, 0xdd, 0x2a, 0x10, 0xba, 0xa3, 0x4b, 0xca, 0x5c, 0xef, 0xbd, 0x72, 0x60, 0x89, + 0x8d, 0xe4, 0x0e, 0x3e, 0x97, 0xab, 0x55, 0x97, 0x4d, 0x79, 0x12, 0xab, 0x38, 0xde, 0x08, 0x08, + 0xca, 0xfd, 0xa6, 0x7b, 0xab, 0xa8, 0x62, 0x32, 0xfb, 0xc5, 0xc2, 0x39, 0x15, 0xb0, 0xa4, 0x99, + 0xa0, 0xbd, 0xa6, 0x26, 0x8a, 0x69, 0x7c, 0xb4, 0x50, 0x2d, 0x43, 0x93, 0xc4, 0x2c, 0xb3, 0x31, + 0x8a, 0x0a, 0x41, 0x1e, 0x64, 0x6a, 0xd5, 0xf2, 0x8e, 0xf9, 0x32, 0x36, 0xb6, 0x0f, 0x67, 0x5c, + 0x06, 0x8c, 0xc0, 0xa7, 0xd9, 0x33, 0xc0, 0x74, 0x6d, 0x9d, 0x13, 0x8f, 0xe7, 0xd9, 0x09, 0x5a, + 0x70, 0xfa, 0x45, 0xb8, 0xf1, 0x29, 0xf1, 0xc5, 0xd5, 0x9d, 0x49, 0xf3, 0xf2, 0x4f, 0x7a, 0x29, + 0x4c, 0xff, 0x90, 0x42, 0x0f, 0x76, 0x93, 0x49, 0x32, 0xd0, 0xc2, 0x5a, 0x5d, 0xe7, 0x79, 0x86, + 0x82, 0x2f, 0xcf, 0xe6, 0x14, 0x88, 0x51, 0x21, 0xa1, 0xb5, 0xfd, 0x7d, 0xe6, 0x4f, 0xd8, 0xb3, + 0x75, 0x2a, 0x84, 0xbf, 0x72, 0xc4, 0x56, 0xce, 0x28, 0x0d, 0x97, 0x1d, 0x67, 0x9e, 0xf7, 0x74, + 0xea, 0xe3, 0x4f, 0xa4, 0xf6, 0xdf, 0xd9, 0x84, 0x3e, 0xe1, 0x4a, 0x29, 0xad, 0xad, 0x38, 0xec, + 0xd6, 0x8b, 0xd8, 0x7f, 0x0c, 0xd0, 0xae, 0xd5, 0x81, 0x79, 0xdf, 0x8a, 0x37, 0xfe, 0x67, 0x09, + 0x48, 0x5c, 0x8a, 0xe7, 0x4f, 0xe7, 0x0e, 0xac, 0xb6, 0xfc, 0xc6, 0x36, 0x03, 0xad, 0xf3, 0xee, + 0x98, 0x3a, 0x61, 0x49, 0x0f, 0x72, 0x8b, 0x5e, 0xe8, 0x72, 0x65, 0xfb, 0x8f, 0xe8, 0x92, 0xff, + 0xf2, 0x90, 0x9e, 0xca, 0x4e, 0x54, 0xcb, 0xc5, 0x4a, 0xc9, 0xa0, 0x22, 0xb1, 0xc2, 0x31, 0x59, + 0x2c, 0x16, 0xb2, 0xbb, 0x19, 0xc7, 0x28, 0x55, 0xb3, 0x3f, 0xae, 0x61, 0x0e, 0x3e, 0x72, 0x0b, + 0x4e, 0x5b, 0x1e, 0x98, 0xe3, 0x35, 0x32, 0xba, 0x90, 0xa5, 0xa8, 0x28, 0x00, 0x5a, 0x54, 0x7d, + 0xc1, 0x20, 0x67, 0x2c, 0x98, 0x61, 0x8d, 0x24, 0x00, 0x50, 0xa1, 0x71, 0xdc, 0xa0, 0x62, 0x2a, + 0x6a, 0x23, 0xf8, 0x9e, 0x75, 0x00, 0x54, 0x42, 0x97, 0x6f, 0xba, 0x81, 0xe5, 0xb4, 0x77, 0x57, + 0x22, 0x51, 0x5b, 0x3d, 0x62, 0xbd, 0x8a, 0xf1, 0x53, 0x24, 0xe0, 0x8c, 0x79, 0xfa, 0xe9, 0x55, + 0x3a, 0x24, 0x37, 0x33, 0x10, 0x7d, 0x22, 0xbf, 0x9f, 0x18, 0x59, 0x40, 0xb5, 0x36, 0x15, 0x72, + 0xcd, 0xf3, 0x91, 0x19, 0xd7, 0x48, 0xaf, 0x5c, 0xe1, 0xd2, 0xaa, 0x7b, 0x91, 0x03, 0x42, 0x28, + 0xd2, 0xc3, 0xb5, 0x3e, 0xf4, 0x01, 0xdf, 0xea, 0xd9, 0x90, 0xcb, 0x42, 0x5f, 0xa7, 0x19, 0x7b, + 0xbc, 0x12, 0x99, 0x93, 0x80, 0x69, 0xf7, 0x16, 0x0d, 0x82, 0x3b, 0xdc, 0xaf, 0xc9, 0x63, 0xd0, + 0xab, 0x9f, 0xa7, 0xd6, 0xcf, 0x29, 0xe8, 0xf8, 0x28, 0x91, 0xc8, 0x1f, 0x58, 0xbd, 0x9a, 0xfa, + 0xfa, 0xc7, 0xf0, 0xa4, 0x6b, 0x1d, 0xb8, 0x15, 0x07, 0xb1, 0x9e, 0x88, 0x17, 0x26, 0xe7, 0xd9, + 0xdd, 0x74, 0x56, 0x97, 0x9a, 0x0a, 0x44, 0xe7, 0x62, 0x5c, 0x12, 0x77, 0x99, 0xc1, 0xd6, 0xab, + 0x6b, 0xd8, 0xe7, 0x4f, 0x6b, 0x71, 0xd1, 0x3c, 0x00, 0x87, 0xe6, 0xeb, 0x19, 0x8d, 0x7d, 0x5c, + 0x7a, 0xfe, 0x13, 0x6b, 0x0d, 0x98, 0x67, 0x74, 0x1d, 0x7c, 0x70, 0xf6, 0x1f, 0x5e, 0x89, 0x84, + 0xee, 0x10, 0x4a, 0x14, 0xae, 0x0e, 0xeb, 0x7a, 0x60, 0xfe, 0x89, 0x35, 0x57, 0x94, 0x2d, 0x38, + 0xcd, 0xb9, 0xe6, 0x8d, 0xab, 0x72, 0x50, 0x95, 0xe8, 0x26, 0x32, 0xb5, 0x3c, 0x70, 0x68, 0xd8, + 0x48, 0x65, 0x7b, 0xdc, 0x3e, 0x44, 0x94, 0x0c, 0xeb, 0x99, 0x35, 0xe0, 0xad, 0x2a, 0x15, 0xe0, + 0x1c, 0x52, 0x1b, 0xc1, 0x31, 0x75, 0xc3, 0xf7, 0x94, 0xb7, 0xbe, 0x5e, 0x50, 0x55, 0xe0, 0x1b, + 0x73, 0x65, 0x60, 0x9d, 0x53, 0xe7, 0x0e, 0xa0, 0x5c, 0xbb, 0xdb, 0x38, 0x66, 0x2c, 0x17, 0x4f, + 0xb3, 0x63, 0x49, 0x08, 0x09, 0x39, 0x97, 0x15, 0x24, 0x8d, 0x0b, 0x3a, 0x02, 0x2f, 0xaa, 0x0a, + 0xeb, 0xc7, 0xf6, 0x05, 0x83, 0x92, 0x5e, 0xc6, 0x46, 0xca, 0x54, 0x7d, 0x68, 0x12, 0xe0, 0xdf, + 0xd1, 0x98, 0x6a, 0x27, 0xca, 0x26, 0xab, 0x53, 0xcb, 0x51, 0xc5, 0x18, 0x76, 0x72, 0x45, 0x81, + 0x47, 0xbe, 0x4d, 0xec, 0x9e, 0x5e, 0xfc, 0xd1, 0x5b, 0x9d, 0x1a, 0xbd, 0x88, 0xd9, 0x3f, 0x2c, + 0x27, 0xb2, 0xbd, 0x6c, 0x25, 0x6d, 0x50, 0x55, 0x31, 0x2c, 0x5d, 0x27, 0x8c, 0x0a, 0x86, 0x05, + 0xb2, 0x95, 0x6c, 0xf4, 0xe0, 0xf1, 0x26, 0x77, 0xb6, 0xff, 0xb5, 0xc6, 0xb9, 0xca, 0x8d, 0x32, + 0x5e, 0x9f, 0x48, 0xff, 0xc8, 0x1c, 0x5e, 0xd0, 0xab, 0xb9, 0x23, 0xd8, 0xa1, 0x6c, 0xb7, 0xfd, + 0x04, 0x18, 0x89, 0xfd, 0x6f, 0x17, 0x69, 0x80, 0x83, 0x47, 0xa1, 0x05, 0x2d, 0x8d, 0x01, 0x40, + 0xe3, 0x36, 0x65, 0x32, 0x97, 0x69, 0xea, 0x32, 0x5a, 0x7f, 0x6c, 0xa7, 0x73, 0x9a, 0x16, 0x9c, + 0x6e, 0xcc, 0x96, 0xbd, 0x55, 0x51, 0xb5, 0x02, 0xfd, 0x68, 0xb7, 0xcf, 0x4d, 0x7f, 0xec, 0xeb, + 0x26, 0x42, 0xb3, 0x9c, 0xee, 0xf2, 0x6f, 0x52, 0x73, 0x38, 0x73, 0x81, 0x09, 0x66, 0x4e, 0xea, + 0xaf, 0xc5, 0x33, 0xcc, 0x1f, 0x6f, 0x2c, 0xe9, 0xd3, 0x34, 0x87, 0xb6, 0xab, 0xb5, 0xf2, 0x58, + 0xcc, 0xf6, 0x43, 0x6f, 0x07, 0xd0, 0xbb, 0xee, 0x25, 0x83, 0x7b, 0x8a, 0x3d, 0x99, 0xcb, 0x14, + 0x5d, 0x9e, 0x1a, 0xad, 0xc5, 0x5e, 0x4c, 0xe1, 0xf8, 0x08, 0x78, 0x45, 0x0c, 0x02, 0xf7, 0x1a, + 0x75, 0x06, 0xa3, 0x99, 0x97, 0x0c, 0x01, 0x91, 0x3f, 0x38, 0x06, 0xf8, 0x31, 0x1a, 0x13, 0x33, + 0x46, 0xa0, 0x69, 0x74, 0xe8, 0xf2, 0x75, 0x12, 0x5c, 0x3c, 0x9c, 0x02, 0x72, 0x02, 0x9c, 0x49, + 0x56, 0x57, 0x04, 0xa8, 0x06, 0x46, 0x38, 0x83, 0x97, 0xaf, 0x77, 0x99, 0x77, 0x50, 0xba, 0x97, + 0x3d, 0xdc, 0x57, 0x02, 0x7c, 0x3b, 0x01, 0xbe, 0x7b, 0x92, 0xcb, 0x06, 0x5b, 0x5c, 0x7d, 0x52, + 0xfb, 0x84, 0xd7, 0xf3, 0x93, 0x1b, 0x79, 0x35, 0x77, 0x77, 0x1f, 0x68, 0xe9, 0xc5, 0xe3, 0xbc, + 0x15, 0xa2, 0xa3, 0x05, 0xa7, 0x7d, 0xe2, 0x05, 0x5a, 0x2b, 0x10, 0x8e, 0x2f, 0xae, 0x46, 0xf9, + 0xf1, 0xbb, 0x39, 0x82, 0x96, 0x3e, 0x19, 0x97, 0x2f, 0xb1, 0x74, 0x05, 0x1c, 0x01, 0xe8, 0xdb, + 0x15, 0x31, 0xd8, 0x94, 0xd5, 0xee, 0xd3, 0x4c, 0x23, 0xb8, 0x01, 0xc6, 0x04, 0xc6, 0x35, 0x8e, + 0xc2, 0x55, 0x2a, 0x19, 0xfe, 0x76, 0x11, 0x8b, 0x38, 0xec, 0xba, 0x43, 0x86, 0x19, 0x87, 0x0e, + 0xa3, 0x52, 0x2c, 0x0a, 0xc2, 0xa5, 0xf7, 0xd5, 0xc4, 0xee, 0x58, 0x3a, 0x5d, 0x0e, 0xe7, 0xfe, + 0xb1, 0xba, 0x17, 0x9f, 0xc0, 0xd4, 0x02, 0xc2, 0x79, 0xb8, 0xba, 0x73, 0xe2, 0xf7, 0x61, 0xbe, + 0xdb, 0xcc, 0x2a, 0x73, 0x78, 0x34, 0x65, 0x4d, 0xa3, 0xb6, 0x41, 0x85, 0xeb, 0x60, 0xd5, 0xbb, + 0x2f, 0x5a, 0xfa, 0xe4, 0x2d, 0x9e, 0xea, 0x5c, 0xc3, 0x0e, 0xf9, 0x5c, 0xce, 0x26, 0x47, 0x96, + 0x75, 0xec, 0x2b, 0x32, 0x1b, 0x01, 0x41, 0x61, 0x16, 0x62, 0x99, 0x25, 0x88, 0x33, 0x2b, 0x6e, + 0xf0, 0x70, 0xce, 0x63, 0xc3, 0x28, 0x8a, 0xe6, 0x7e, 0xfd, 0x88, 0x39, 0x5e, 0xd6, 0x1d, 0x67, + 0x32, 0xef, 0x2f, 0xc0, 0xc7, 0xc8, 0xc2, 0x50, 0x15, 0x7c, 0x52, 0x80, 0xca, 0xbf, 0x64, 0x76, + 0x81, 0xa1, 0x7c, 0xa3, 0xdc, 0xcf, 0xd4, 0x92, 0x50, 0xf5, 0x93, 0xf5, 0x08, 0x40, 0xb5, 0xb6, + 0x5a, 0x24, 0xa8, 0x06, 0x48, 0x12, 0xc6, 0xb5, 0x92, 0xc7, 0xeb, 0x53, 0xa0, 0xda, 0x16, 0x9c, + 0xc6, 0x35, 0x9a, 0x06, 0x6b, 0x05, 0x99, 0x7d, 0x33, 0xe8, 0xb0, 0x58, 0x82, 0xc9, 0xce, 0x6d, + 0x7a, 0x1c, 0x98, 0x5e, 0x29, 0xfd, 0x6c, 0x6b, 0xe0, 0x83, 0xa1, 0x50, 0x4c, 0x32, 0xc1, 0x2f, + 0x09, 0x0d, 0x7d, 0x59, 0x4c, 0x50, 0xd1, 0x13, 0xc0, 0xe9, 0xf0, 0xa9, 0x1b, 0x78, 0xef, 0x1f, + 0x7e, 0xbb, 0x4f, 0x97, 0xa0, 0xaf, 0x20, 0xe6, 0x38, 0x23, 0xc3, 0x50, 0xde, 0x4a, 0x9e, 0x42, + 0xd5, 0x71, 0x8a, 0xf7, 0x96, 0x3f, 0x00, 0x37, 0x06, 0x8d, 0x53, 0xa5, 0xf6, 0x61, 0x10, 0x4a, + 0xb2, 0xbf, 0x0e, 0x42, 0x9f, 0xa1, 0x39, 0xaa, 0x1c, 0xfe, 0xca, 0xb9, 0x06, 0x10, 0xa1, 0x53, + 0xe6, 0x4b, 0xb5, 0x8a, 0xc1, 0xbe, 0xc6, 0xa0, 0xfc, 0x1e, 0x32, 0x3b, 0x8e, 0xd2, 0x61, 0x66, + 0xaa, 0x84, 0xab, 0x76, 0x33, 0x63, 0x13, 0xc7, 0x74, 0xa6, 0x58, 0x28, 0xac, 0x57, 0x2d, 0x0a, + 0x00, 0x9a, 0x4e, 0xfe, 0x78, 0xb3, 0x7b, 0x5a, 0xd4, 0x83, 0x98, 0x3e, 0xba, 0xc4, 0xae, 0xd1, + 0xb8, 0xc1, 0xf0, 0x8a, 0x7e, 0x0f, 0xc0, 0x3c, 0xd0, 0x02, 0xb5, 0x00, 0x7e, 0xa0, 0x33, 0x62, + 0x69, 0x01, 0xa8, 0x74, 0xa8, 0xae, 0xb6, 0x3b, 0x39, 0xbc, 0xb7, 0x54, 0x7f, 0x23, 0xa8, 0x35, + 0x42, 0x4b, 0x68, 0xab, 0x7e, 0xff, 0x96, 0x03, 0xbf, 0x14, 0xe5, 0x57, 0xdb, 0xe1, 0x2f, 0x59, + 0xb1, 0xfc, 0xfd, 0xf9, 0x21, 0x15, 0x5c, 0xba, 0x58, 0xe3, 0x8b, 0xd6, 0x03, 0x5e, 0x7e, 0x3c, + 0xf8, 0x18, 0x7b, 0xb8, 0x46, 0x5a, 0x70, 0x7a, 0xf3, 0x5e, 0xe6, 0x2d, 0xf1, 0xd0, 0x1b, 0xf4, + 0x49, 0x13, 0x5a, 0xd3, 0x64, 0xd5, 0xb0, 0xac, 0x53, 0xd3, 0xd6, 0xab, 0x8d, 0xd4, 0x0e, 0xee, + 0xc9, 0xef, 0x66, 0x2d, 0x1a, 0x00, 0xf0, 0x96, 0xb1, 0xb1, 0x97, 0xc4, 0x72, 0x20, 0x09, 0x20, + 0xbe, 0xa7, 0x04, 0x71, 0x1c, 0xaf, 0x20, 0x5a, 0xf2, 0xaf, 0x3d, 0x85, 0x2e, 0xee, 0x41, 0x73, + 0x0f, 0x4f, 0x64, 0xbe, 0xf7, 0x0c, 0xb1, 0x5c, 0xf7, 0xb1, 0x04, 0x04, 0x9a, 0xae, 0xfd, 0x1c, + 0x8a, 0x74, 0x6e, 0xfe, 0xfc, 0x2e, 0x15, 0xe9, 0x17, 0x99, 0x81, 0x47, 0xc4, 0x44, 0xd3, 0x9f, + 0xa8, 0xb1, 0x53, 0xe6, 0x6a, 0xa3, 0x42, 0xe2, 0xd8, 0x59, 0xd9, 0x61, 0x54, 0x25, 0x54, 0xe4, + 0xe5, 0xc2, 0x58, 0x8a, 0xaa, 0xa7, 0x87, 0x34, 0xc4, 0x25, 0x3b, 0xf2, 0x23, 0x91, 0x26, 0xef, + 0x53, 0x78, 0x4e, 0xd9, 0x58, 0xa7, 0x0b, 0xe6, 0x5d, 0xae, 0x11, 0x60, 0xc3, 0x2d, 0xcc, 0x05, + 0x42, 0x50, 0x18, 0x78, 0xbe, 0x87, 0xde, 0x08, 0x84, 0x6b, 0x40, 0x9c, 0x2f, 0xc0, 0x31, 0x60, + 0xce, 0xba, 0x9b, 0x5e, 0xa1, 0xfe, 0x9a, 0xb1, 0x0f, 0x26, 0xd0, 0xa3, 0xc9, 0x60, 0xc7, 0xe3, + 0x75, 0x84, 0x8c, 0x2d, 0x38, 0xbd, 0x1b, 0x2c, 0x65, 0x55, 0xe5, 0x17, 0xdb, 0x61, 0x60, 0xd5, + 0xc0, 0xeb, 0x80, 0x0d, 0x01, 0x6c, 0x63, 0x0b, 0xb7, 0xd3, 0xd8, 0xfc, 0x88, 0x39, 0x06, 0x61, + 0x1a, 0x44, 0xe5, 0xdf, 0x2e, 0xb5, 0x70, 0xa5, 0x33, 0x5b, 0xc5, 0x91, 0x2d, 0x02, 0x4b, 0x1c, + 0xfa, 0xe3, 0x35, 0x81, 0x8f, 0x3b, 0x0c, 0xaa, 0x1a, 0x80, 0x31, 0xe7, 0x60, 0x57, 0x95, 0xd9, + 0x79, 0xf7, 0x87, 0x8e, 0xa0, 0x0c, 0xaa, 0xb3, 0xa6, 0x39, 0xb6, 0xe0, 0x06, 0xb8, 0x19, 0xde, + 0x85, 0xea, 0x5d, 0x98, 0x1c, 0xcc, 0xb3, 0x49, 0x12, 0xf7, 0xe4, 0x9a, 0xe6, 0x67, 0xde, 0xdf, + 0x34, 0xb8, 0x00, 0xd5, 0xa0, 0xf7, 0x1f, 0xd9, 0x35, 0x00, 0xd3, 0x53, 0xb8, 0x54, 0x60, 0x61, + 0x3f, 0xea, 0x9e, 0x14, 0x2f, 0xe4, 0x3f, 0xe6, 0xaa, 0x1f, 0x96, 0x27, 0x32, 0x97, 0x11, 0x20, + 0xab, 0x6a, 0x07, 0x17, 0x69, 0x3a, 0xd6, 0xeb, 0x2a, 0x12, 0xf7, 0x1f, 0x35, 0x06, 0x71, 0x8a, + 0x20, 0xf8, 0x82, 0x91, 0x44, 0xe3, 0x7d, 0xab, 0xe1, 0xec, 0x12, 0x55, 0x05, 0xf1, 0xe5, 0xa1, + 0xd2, 0x1a, 0x9d, 0xa8, 0xd6, 0x2a, 0x86, 0xa0, 0x1d, 0x01, 0xc6, 0xb3, 0xae, 0xb0, 0xa7, 0x1f, + 0xe7, 0xad, 0x20, 0x3d, 0x2d, 0x38, 0x1d, 0x5d, 0x27, 0x09, 0xca, 0xae, 0x8c, 0x00, 0xdb, 0x63, + 0xa9, 0x8c, 0xab, 0x01, 0xb6, 0x0b, 0xc7, 0x46, 0xca, 0xc5, 0x8b, 0xcb, 0x7c, 0xf7, 0xe9, 0x09, + 0x00, 0x25, 0x69, 0x63, 0x3e, 0x57, 0xdd, 0x01, 0x36, 0x39, 0xb3, 0x83, 0xe3, 0xc5, 0x20, 0x74, + 0x45, 0xe5, 0xb2, 0xa9, 0x96, 0x84, 0xb6, 0x0c, 0x84, 0xcb, 0xef, 0x80, 0x05, 0x20, 0x2b, 0xb8, + 0x5a, 0x4d, 0x4f, 0x0c, 0x6e, 0x50, 0xd8, 0xa9, 0x7b, 0x24, 0x2e, 0x9a, 0x5e, 0xf5, 0x02, 0xbc, + 0x07, 0xde, 0xfd, 0x0e, 0x20, 0x97, 0xe5, 0x7e, 0x1a, 0x90, 0xfc, 0x06, 0x07, 0x9c, 0xfe, 0xaa, + 0xbd, 0x59, 0x41, 0x3b, 0x06, 0xe5, 0x07, 0x44, 0xdf, 0xda, 0xa0, 0x47, 0xab, 0x54, 0x20, 0xee, + 0x7f, 0xe0, 0x3f, 0xc7, 0xcf, 0x83, 0xaf, 0x7c, 0xbe, 0xa5, 0xe2, 0xc4, 0x76, 0x60, 0x08, 0xb5, + 0xf5, 0x5d, 0x23, 0x3f, 0x7e, 0x7c, 0xd2, 0x6e, 0xa3, 0xee, 0xa8, 0xcc, 0x4d, 0x96, 0xb5, 0x48, + 0x35, 0xdb, 0xd4, 0xa0, 0xc2, 0x1d, 0x35, 0xa2, 0x89, 0x73, 0xf9, 0x56, 0x68, 0x19, 0x9c, 0x98, + 0xf6, 0xdc, 0x3a, 0x7a, 0xe0, 0xdf, 0x68, 0x37, 0xcc, 0xce, 0xc1, 0x85, 0x40, 0x08, 0x02, 0xb4, + 0x55, 0x33, 0xb4, 0x00, 0x6d, 0x95, 0x2d, 0xb2, 0x0b, 0x63, 0xfa, 0x31, 0xf6, 0xf0, 0x0c, 0xc8, + 0x74, 0x09, 0x18, 0xb6, 0xe2, 0xf1, 0x8d, 0xb4, 0xcd, 0x3c, 0xc6, 0xd3, 0x39, 0x4b, 0x0b, 0x4e, + 0xf3, 0xd7, 0x02, 0x96, 0xb7, 0x89, 0x1e, 0x6a, 0x4c, 0xc3, 0x54, 0xd2, 0x63, 0x6a, 0xb0, 0xb1, + 0x00, 0x99, 0xde, 0xff, 0x06, 0x6c, 0x99, 0x23, 0xec, 0x2f, 0x02, 0x57, 0x8f, 0xbf, 0x11, 0x33, + 0x3f, 0x92, 0xfa, 0x04, 0xa0, 0x79, 0x2f, 0x15, 0xc5, 0x74, 0x0a, 0xd2, 0xbe, 0x00, 0x50, 0x39, + 0x01, 0x10, 0xc2, 0x31, 0x81, 0x19, 0x54, 0x3b, 0x41, 0x53, 0xb5, 0xb6, 0x3b, 0x01, 0x87, 0x80, + 0xe0, 0x40, 0xe8, 0x71, 0x24, 0xa6, 0x86, 0x23, 0x42, 0x40, 0x98, 0xaa, 0x7f, 0x4c, 0x80, 0x38, + 0x3a, 0x92, 0x2c, 0x3b, 0x40, 0x18, 0x2c, 0x12, 0x01, 0x3b, 0xc2, 0x17, 0xfd, 0xc9, 0x98, 0x8f, + 0x4b, 0x28, 0xb9, 0x67, 0x9c, 0xa0, 0x88, 0x13, 0xc0, 0xa9, 0x83, 0xf0, 0xaa, 0x4f, 0x72, 0x8c, + 0xf9, 0xe2, 0x93, 0x4b, 0x1e, 0xb4, 0x64, 0x77, 0x69, 0xe1, 0x7a, 0x01, 0xc0, 0xcd, 0x2a, 0x46, + 0x3d, 0xd1, 0xb5, 0xfe, 0xa5, 0x28, 0x8f, 0x2f, 0x72, 0x7d, 0x4a, 0xab, 0xad, 0xfb, 0xaf, 0xfa, + 0xed, 0xae, 0xa7, 0x74, 0x18, 0xc4, 0x0f, 0x55, 0x07, 0xe7, 0x92, 0x80, 0x97, 0x94, 0x57, 0x38, + 0x54, 0x50, 0x5c, 0x06, 0x9f, 0x00, 0xc4, 0x97, 0x14, 0xbe, 0xfc, 0x58, 0xa6, 0x69, 0x5b, 0x0b, + 0x4e, 0x77, 0xc1, 0x41, 0x23, 0xaa, 0x1c, 0x1b, 0x52, 0x2b, 0x94, 0xcc, 0xb2, 0xae, 0x90, 0xa2, + 0x29, 0xdf, 0x31, 0xb1, 0x01, 0x1d, 0x1f, 0x0d, 0x87, 0x6c, 0x88, 0xe2, 0x5b, 0xf8, 0x3c, 0x8d, + 0x62, 0x90, 0x19, 0xbd, 0x04, 0x41, 0x12, 0x1e, 0x28, 0x06, 0x8b, 0x75, 0xe0, 0x9e, 0xa6, 0x26, + 0x2f, 0x8a, 0xeb, 0x45, 0xf0, 0xf8, 0xdd, 0xea, 0xbb, 0xab, 0xd8, 0x6e, 0xb1, 0xec, 0xd9, 0x80, + 0x7d, 0x18, 0x5a, 0xdb, 0x3a, 0xbe, 0x8a, 0x69, 0x32, 0x43, 0xef, 0x63, 0x62, 0x7a, 0xd9, 0xb4, + 0x51, 0x2e, 0x5e, 0xce, 0x17, 0xd6, 0x83, 0x30, 0x51, 0x8c, 0xc1, 0x00, 0x08, 0xa3, 0x26, 0xd4, + 0x0c, 0x4d, 0x1b, 0x15, 0x89, 0x57, 0xdb, 0xb5, 0x52, 0x56, 0x9c, 0x30, 0xaa, 0x8d, 0x57, 0x53, + 0x85, 0xf3, 0x73, 0x2a, 0x3d, 0x08, 0x15, 0x25, 0x3b, 0x07, 0x36, 0x95, 0xf7, 0x79, 0x05, 0x63, + 0xcc, 0x33, 0x70, 0x04, 0x37, 0x79, 0xce, 0x98, 0x6a, 0x2c, 0x70, 0x08, 0x45, 0x66, 0xbd, 0x16, + 0x19, 0x1b, 0xde, 0xdd, 0xfa, 0x76, 0xb1, 0xb1, 0x0b, 0x80, 0x65, 0x6a, 0x37, 0x3e, 0x0a, 0xc7, + 0x72, 0xed, 0x0a, 0x7e, 0x58, 0x1e, 0x2d, 0x14, 0xd7, 0x1d, 0x73, 0x8b, 0xf9, 0x64, 0xc0, 0x08, + 0xad, 0x60, 0x08, 0x80, 0xe0, 0xed, 0x60, 0x67, 0x61, 0x2f, 0xb4, 0xbe, 0x82, 0xf1, 0xcd, 0xd0, + 0xc9, 0x71, 0x19, 0x62, 0x33, 0x20, 0x74, 0xd8, 0xdd, 0x19, 0x0e, 0x9a, 0x7c, 0x92, 0xa8, 0xbe, + 0x4a, 0x05, 0x01, 0xdf, 0xd4, 0x6a, 0x88, 0xa6, 0x8a, 0x65, 0x4d, 0xa2, 0xc7, 0x71, 0x6d, 0x2e, + 0x1a, 0x2c, 0xe1, 0x0c, 0x87, 0x63, 0x39, 0x72, 0x54, 0xff, 0x80, 0x8f, 0x1e, 0xa6, 0x76, 0xfe, + 0xe2, 0x7a, 0x6f, 0x34, 0xf2, 0x24, 0xa7, 0x13, 0x3d, 0x77, 0x7d, 0x8a, 0x79, 0xf6, 0xa1, 0xfe, + 0xdd, 0x8c, 0xa4, 0xb8, 0x6c, 0xcd, 0x91, 0x88, 0xe9, 0x20, 0xdf, 0xbb, 0x8b, 0xb8, 0xfa, 0x9b, + 0x27, 0x48, 0x0f, 0x39, 0x86, 0xbc, 0x73, 0x35, 0x57, 0xc1, 0x01, 0xc2, 0xd4, 0x19, 0x57, 0xdf, + 0x05, 0xdf, 0x37, 0x42, 0xd7, 0xa3, 0x1f, 0x73, 0xdd, 0xaa, 0xb7, 0xcb, 0xa5, 0x57, 0x22, 0xa8, + 0xeb, 0xb5, 0x52, 0x7a, 0xd2, 0xf0, 0x33, 0xc9, 0xaa, 0xa3, 0xac, 0x06, 0xa8, 0x7c, 0x14, 0x84, + 0x43, 0xf6, 0xca, 0xe8, 0x21, 0xb3, 0x05, 0xd1, 0xd6, 0x8e, 0xec, 0x07, 0x74, 0x89, 0x70, 0xbf, + 0x69, 0x78, 0xb0, 0x06, 0x16, 0x87, 0xec, 0x76, 0x10, 0x0d, 0x68, 0x9e, 0x04, 0xbe, 0xa0, 0xc6, + 0x76, 0x03, 0x8c, 0xcd, 0x0a, 0xf6, 0x2b, 0xee, 0x37, 0x4a, 0x38, 0xcc, 0x78, 0x4e, 0x12, 0x7e, + 0x6e, 0x88, 0xe7, 0x30, 0x05, 0x1c, 0xc2, 0x08, 0xfc, 0x45, 0x9d, 0xb1, 0xb0, 0x1b, 0x0e, 0x3f, + 0x64, 0xfc, 0xd7, 0x5a, 0x51, 0xfc, 0x50, 0xe2, 0xeb, 0x8f, 0x57, 0xb7, 0xe9, 0xf1, 0xb6, 0x90, + 0xe9, 0x01, 0x70, 0xdb, 0xf7, 0xb5, 0x81, 0x14, 0x59, 0x5a, 0xdf, 0xb1, 0x2f, 0x47, 0x4a, 0xb7, + 0x7d, 0xd5, 0xcf, 0xac, 0x1e, 0x09, 0x0c, 0xd2, 0x07, 0x2c, 0x7b, 0x6a, 0xe8, 0x81, 0x76, 0x75, + 0x01, 0x28, 0x4c, 0x5b, 0x10, 0x0b, 0x1b, 0x1b, 0x0b, 0x9d, 0x14, 0xd6, 0xa3, 0x5b, 0xbe, 0xc2, + 0x79, 0xae, 0x06, 0x85, 0xe4, 0x29, 0xf3, 0x49, 0x13, 0x0a, 0xa4, 0xa4, 0x06, 0x21, 0x75, 0x1f, + 0x5b, 0x2d, 0xfa, 0x72, 0x75, 0xc2, 0xa2, 0x51, 0x28, 0xb6, 0xc7, 0xd4, 0xb5, 0x17, 0xfb, 0xc7, + 0x17, 0x95, 0xea, 0x54, 0x6d, 0xbd, 0x40, 0x56, 0x8d, 0xba, 0x98, 0x2a, 0x03, 0x38, 0x53, 0x76, + 0xe0, 0xd1, 0x84, 0x2a, 0x11, 0x59, 0x84, 0x83, 0x9e, 0x46, 0x03, 0x42, 0x66, 0x3d, 0x6c, 0x86, + 0x79, 0x07, 0xde, 0x73, 0x1b, 0xff, 0x00, 0xd7, 0x89, 0x0a, 0xa0, 0x3e, 0xb3, 0xeb, 0x1f, 0x81, + 0xc9, 0xea, 0x6f, 0x57, 0x54, 0x9f, 0x94, 0xa9, 0x15, 0x21, 0x7f, 0x13, 0x13, 0x69, 0xf0, 0x78, + 0xa6, 0xf2, 0xf9, 0x0a, 0xa8, 0xd6, 0xa7, 0xcb, 0xa1, 0x24, 0x40, 0xf9, 0xc3, 0xa4, 0x03, 0x9f, + 0x3b, 0xaa, 0xef, 0xe0, 0x94, 0xa2, 0x17, 0x04, 0xa3, 0x6f, 0x76, 0xc3, 0xe7, 0x57, 0xd4, 0x8f, + 0x39, 0xff, 0xc7, 0x6b, 0xcd, 0x22, 0x1d, 0x78, 0x0b, 0x4e, 0xbf, 0xea, 0x3f, 0x51, 0xb8, 0xb4, + 0x4f, 0xf0, 0x83, 0xf7, 0x00, 0xfe, 0xc1, 0xb1, 0x9c, 0xe7, 0x74, 0x64, 0x6c, 0x61, 0xa3, 0x30, + 0xf9, 0x76, 0x05, 0x1b, 0xef, 0x47, 0x68, 0xed, 0xa0, 0x54, 0xee, 0xc2, 0xf4, 0x85, 0xfd, 0x67, + 0xc3, 0x6a, 0x92, 0x48, 0x77, 0x9c, 0xed, 0xbd, 0x23, 0xd7, 0x8a, 0xe3, 0xcc, 0xc2, 0x1a, 0x5c, + 0xc0, 0xf6, 0xa9, 0xd5, 0x68, 0x1a, 0xf0, 0x4a, 0x2c, 0xd6, 0xd2, 0x5a, 0x05, 0xb0, 0xa1, 0x7d, + 0xdd, 0x40, 0x52, 0xb8, 0x77, 0x4a, 0xed, 0x42, 0xc3, 0x71, 0x66, 0xbf, 0xf3, 0x6d, 0xfe, 0x1d, + 0xe0, 0xa6, 0x4c, 0x4c, 0x4c, 0xe5, 0xbb, 0x01, 0x0c, 0xcf, 0xf7, 0x12, 0xd9, 0x44, 0x96, 0x80, + 0x2b, 0xaa, 0xa6, 0x18, 0x07, 0x56, 0xdf, 0xd8, 0xa0, 0xf0, 0xe1, 0xf2, 0x07, 0x73, 0x6d, 0x83, + 0xc0, 0x4f, 0xd9, 0xe4, 0xd9, 0x56, 0xe6, 0x22, 0x46, 0x50, 0xe1, 0xf4, 0x90, 0x9a, 0x5c, 0xd6, + 0x15, 0xc7, 0x6a, 0xd6, 0xab, 0x64, 0x75, 0x0a, 0x2f, 0x1d, 0xa7, 0x1d, 0xf6, 0x89, 0x84, 0x92, + 0x8c, 0x52, 0xc9, 0x2b, 0x47, 0xbd, 0x54, 0x8c, 0x46, 0x22, 0x31, 0xcb, 0xf9, 0x4e, 0x49, 0x63, + 0x22, 0x70, 0x83, 0x9a, 0x93, 0xfd, 0x14, 0x49, 0x2d, 0xeb, 0xd2, 0x55, 0xfb, 0xf9, 0xd5, 0x46, + 0xa2, 0x28, 0xed, 0x78, 0xbc, 0xe6, 0xca, 0x66, 0x0b, 0x4e, 0xf7, 0x16, 0xd6, 0x5d, 0x1d, 0xc2, + 0x16, 0x5d, 0xf7, 0xf2, 0x84, 0x88, 0x2b, 0x27, 0x6c, 0xf2, 0x68, 0x1e, 0xc3, 0xf4, 0x71, 0x7f, + 0xf2, 0xc5, 0x84, 0x74, 0x98, 0x46, 0x15, 0x70, 0xa4, 0x47, 0xb2, 0xc8, 0xad, 0x7b, 0xf9, 0x19, + 0xc3, 0xbc, 0xa5, 0x16, 0x0c, 0xd0, 0xdf, 0xc0, 0xeb, 0xe6, 0x5d, 0x80, 0xe1, 0x2b, 0x37, 0xc6, + 0x7a, 0xb1, 0xaf, 0x6b, 0xdc, 0xa0, 0x37, 0x38, 0xe6, 0xe2, 0xc6, 0x06, 0x55, 0x9a, 0xb9, 0x09, + 0xb4, 0xb7, 0x4f, 0xed, 0xcc, 0x0b, 0xb6, 0xe2, 0x9f, 0xb0, 0x67, 0x12, 0x66, 0x96, 0xe8, 0xb5, + 0x0e, 0x3a, 0x23, 0xbc, 0xa2, 0xbd, 0x52, 0x2a, 0x10, 0xf8, 0x41, 0x53, 0x1c, 0xe2, 0xa2, 0xdb, + 0xcf, 0x37, 0x0b, 0x9f, 0x31, 0xfb, 0xc0, 0xd8, 0x25, 0xad, 0xca, 0x69, 0x05, 0x81, 0x5a, 0x66, + 0x34, 0x3f, 0xe1, 0x7b, 0x7a, 0xfa, 0x27, 0x5c, 0x22, 0xf9, 0x12, 0x19, 0x49, 0x8e, 0xd7, 0x9c, + 0x85, 0x35, 0xb6, 0xac, 0x66, 0x58, 0xb2, 0x04, 0x97, 0x69, 0xaa, 0x2c, 0x16, 0x27, 0x77, 0x87, + 0xde, 0x26, 0xba, 0xe1, 0xff, 0x75, 0x2a, 0xa6, 0xe2, 0xd6, 0xa9, 0xa6, 0xfe, 0x53, 0x1f, 0x77, + 0xe9, 0xf1, 0xea, 0x36, 0xe8, 0x76, 0x0b, 0x4e, 0xab, 0x18, 0x7b, 0xe6, 0xd2, 0x30, 0x45, 0x1b, + 0x14, 0x19, 0x76, 0xc7, 0x50, 0xd2, 0xa7, 0x98, 0x89, 0xa2, 0x89, 0x76, 0x0c, 0x4d, 0xd4, 0x93, + 0x53, 0xcb, 0x94, 0x7d, 0x92, 0xc1, 0x35, 0x4c, 0xa4, 0x3c, 0x36, 0x51, 0xa9, 0xed, 0x8e, 0xab, + 0xcf, 0xa3, 0xb5, 0xc0, 0x55, 0xfa, 0x72, 0x23, 0xb8, 0x71, 0x5e, 0xfe, 0x30, 0x01, 0x3a, 0x47, + 0x46, 0x82, 0x93, 0xb5, 0xf2, 0x10, 0x08, 0xd3, 0xec, 0x15, 0xcc, 0xf0, 0x92, 0xc4, 0x4c, 0xf9, + 0x6e, 0x2c, 0xab, 0x03, 0x56, 0x17, 0xc3, 0x8e, 0x9a, 0x3e, 0x3b, 0xf3, 0xdd, 0x0d, 0xb8, 0xf8, + 0xdf, 0x8a, 0x34, 0xdb, 0xf9, 0xc1, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, + 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, + 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xf4, 0x3f, 0x93, 0x0e, + 0xff, 0x9f, 0xff, 0xf5, 0xbf, 0xfe, 0x8d, 0x79, 0x10, 0xd8, 0x53, 0x45, 0x33, 0xae, 0x67, 0xb0, + 0x1b, 0xcd, 0x4f, 0xfd, 0x67, 0x7e, 0xe0, 0xa3, 0xff, 0x5b, 0x6b, 0x85, 0xfe, 0x4f, 0xdf, 0x7c, + 0x87, 0xe5, 0x72, 0xba, 0xe7, 0x69, 0x96, 0x9f, 0xf9, 0xd4, 0x72, 0x02, 0xaf, 0x0d, 0x4a, 0xf7, + 0x2a, 0x6a, 0x07, 0x2d, 0xfb, 0x46, 0x29, 0x18, 0x59, 0xce, 0x22, 0x52, 0x4b, 0x69, 0x9e, 0x91, + 0x79, 0xbf, 0x42, 0x89, 0x26, 0xdf, 0x55, 0xf8, 0x7a, 0xcc, 0xe4, 0xee, 0x15, 0xfa, 0x16, 0x0e, + 0x28, 0xf9, 0x3e, 0xed, 0xa4, 0x14, 0xe3, 0x0a, 0xcb, 0x6b, 0x25, 0x25, 0xf9, 0xc6, 0x2a, 0xdf, + 0x12, 0x1d, 0xbc, 0x6e, 0xc5, 0x8c, 0x56, 0xa1, 0x94, 0x22, 0xa0, 0x85, 0x58, 0x86, 0x92, 0xa2, + 0x98, 0xec, 0xd2, 0x4a, 0x20, 0xa9, 0x6f, 0xac, 0x0f, 0x27, 0x5c, 0xbe, 0x7e, 0xc9, 0xac, 0xcb, + 0x17, 0x05, 0x27, 0x3c, 0x4a, 0xc9, 0x0a, 0xcd, 0x1b, 0x99, 0xc7, 0x3e, 0x55, 0x44, 0x2a, 0x4b, + 0x87, 0xf2, 0x05, 0xf2, 0x1b, 0x56, 0x11, 0x1f, 0x38, 0xf1, 0x8a, 0x08, 0x39, 0x4d, 0xdb, 0xc4, + 0x27, 0x93, 0xbe, 0xf4, 0xb6, 0xdf, 0x59, 0xea, 0xb5, 0xf6, 0x25, 0xba, 0x7a, 0x27, 0xfa, 0x12, + 0xbd, 0x5a, 0x7e, 0xdf, 0x41, 0xde, 0x23, 0x96, 0xae, 0xfa, 0xc8, 0x23, 0x93, 0x6c, 0x03, 0x4b, + 0x85, 0x08, 0x27, 0x26, 0x3c, 0x98, 0xf5, 0xf6, 0x88, 0x54, 0x72, 0x5f, 0xe9, 0xb5, 0x64, 0xd6, + 0x2d, 0x14, 0xcd, 0xc8, 0xd0, 0x55, 0x7d, 0xa0, 0x02, 0xee, 0x2c, 0x76, 0xa2, 0x68, 0xca, 0xea, + 0xf6, 0xaf, 0xa6, 0xe2, 0x9f, 0xa3, 0x9d, 0x12, 0x09, 0x31, 0x9f, 0xe8, 0x95, 0xb8, 0xba, 0x9f, + 0xc5, 0x83, 0xeb, 0x3e, 0x8f, 0x44, 0x33, 0xc1, 0xf8, 0xbc, 0xf3, 0xb3, 0x07, 0xd4, 0x8b, 0x59, + 0xbd, 0x47, 0xf9, 0x22, 0xe5, 0xea, 0xd0, 0x0a, 0x2d, 0x33, 0x46, 0xaf, 0x44, 0x8e, 0x3c, 0x6b, + 0xec, 0x0e, 0x34, 0x76, 0x65, 0x9f, 0x2b, 0x22, 0x59, 0x38, 0xc9, 0x93, 0xec, 0xbe, 0x45, 0xfb, + 0x7a, 0x43, 0xae, 0x9f, 0x8e, 0xf4, 0x05, 0xa2, 0x83, 0x7e, 0x29, 0x77, 0xe1, 0xcf, 0x1c, 0x12, + 0x17, 0x2f, 0xd7, 0x29, 0x0b, 0x3b, 0x71, 0x49, 0x1c, 0x41, 0x47, 0x54, 0x7d, 0x59, 0xa2, 0xb5, + 0x94, 0xd3, 0x96, 0xb6, 0x94, 0xff, 0xbd, 0x52, 0xae, 0xc8, 0xd9, 0xda, 0x2c, 0xff, 0x9b, 0x59, + 0x8e, 0x20, 0x4f, 0xb2, 0x9c, 0xe6, 0x01, 0x25, 0x1d, 0xf6, 0x95, 0x7a, 0x81, 0xfa, 0x8f, 0x28, + 0x55, 0x91, 0xdf, 0xbd, 0x7d, 0x40, 0x53, 0x51, 0x7d, 0x60, 0x1f, 0x68, 0xaa, 0x1e, 0x53, 0xf9, + 0x4c, 0x59, 0x09, 0x21, 0x02, 0xc6, 0xe1, 0x23, 0x67, 0x1c, 0x50, 0x95, 0x5c, 0x8e, 0x9f, 0x57, + 0x24, 0xbf, 0x83, 0xb3, 0x2a, 0xce, 0x42, 0x4c, 0xd0, 0x3c, 0x49, 0x43, 0xb7, 0x61, 0x0b, 0xb9, + 0xcb, 0x85, 0x4d, 0x51, 0x88, 0xad, 0xa1, 0xf9, 0xe0, 0xa6, 0xb3, 0x3e, 0xc2, 0xe7, 0x2f, 0x01, + 0x4d, 0xbd, 0xb5, 0x29, 0x08, 0xaa, 0xd5, 0x67, 0x9d, 0xe8, 0xe0, 0x8d, 0xc5, 0x41, 0x79, 0x59, + 0x19, 0xfa, 0xf0, 0x19, 0x57, 0xc8, 0xca, 0xcd, 0x33, 0x54, 0x3e, 0xc6, 0x37, 0x37, 0x71, 0x40, + 0x3c, 0x7c, 0x90, 0xc4, 0x75, 0xfb, 0x20, 0x77, 0xa5, 0x53, 0x16, 0x29, 0xd2, 0x8a, 0x7b, 0x97, + 0x78, 0xb7, 0x0b, 0x48, 0xaf, 0x56, 0x74, 0x7b, 0x8c, 0x31, 0xd8, 0x9a, 0x46, 0x93, 0x9e, 0x31, + 0x12, 0x22, 0x59, 0x68, 0xde, 0x2b, 0x61, 0x0c, 0x6f, 0xf3, 0x5b, 0xb2, 0x6f, 0x95, 0x8e, 0x20, + 0xb2, 0x8e, 0x0e, 0x89, 0xe5, 0x92, 0x8a, 0x66, 0x5b, 0xea, 0xea, 0x15, 0x8a, 0x76, 0x08, 0x57, + 0xd7, 0x36, 0x69, 0xf8, 0xd8, 0x39, 0x28, 0x3d, 0x76, 0x0f, 0x8b, 0xc4, 0x88, 0x25, 0xa2, 0xc4, + 0x25, 0x67, 0x75, 0xa5, 0x3f, 0x77, 0x6d, 0x43, 0xfb, 0xde, 0xa2, 0x2d, 0x59, 0x2e, 0x43, 0xbd, + 0x6d, 0x29, 0xff, 0x7b, 0xa5, 0x5c, 0x46, 0xe0, 0x6d, 0x96, 0xff, 0xbd, 0x2c, 0x47, 0x3a, 0x36, + 0x9f, 0x64, 0x79, 0x6d, 0xa5, 0xbe, 0x27, 0x25, 0xf8, 0x89, 0x97, 0xd3, 0x2e, 0x1f, 0x55, 0x08, + 0x92, 0x6e, 0x4b, 0x9f, 0xda, 0xe2, 0xea, 0x14, 0x89, 0xa6, 0xbf, 0x25, 0x9b, 0xbb, 0x1a, 0xff, + 0x61, 0x05, 0x41, 0x17, 0x78, 0xe2, 0xfe, 0xf0, 0xc2, 0x99, 0x7c, 0x12, 0x2b, 0x79, 0x34, 0x12, + 0xe6, 0x60, 0x55, 0xef, 0xae, 0x60, 0x23, 0xa9, 0x59, 0xd3, 0x97, 0x1c, 0x1f, 0xc9, 0xf8, 0xea, + 0x23, 0x09, 0x19, 0x41, 0x6c, 0xca, 0x51, 0x97, 0xb2, 0xbb, 0x7f, 0xc6, 0x3b, 0xb2, 0xd9, 0xbc, + 0xee, 0x0b, 0x68, 0x9b, 0x5b, 0x06, 0x6d, 0xa7, 0x17, 0x73, 0x7d, 0x37, 0xd7, 0xa5, 0x76, 0x64, + 0xe8, 0xa0, 0x6a, 0x16, 0xb1, 0x60, 0x9a, 0x03, 0xec, 0x6d, 0x51, 0x44, 0x4d, 0x38, 0xbd, 0x7d, + 0xb3, 0xa6, 0xc4, 0x33, 0x1b, 0x25, 0x5b, 0xd3, 0x5a, 0xcc, 0x13, 0x0b, 0xb4, 0x62, 0x56, 0xf1, + 0x16, 0xb4, 0xdd, 0x73, 0xe7, 0x44, 0x48, 0x6e, 0x21, 0x22, 0x90, 0xb8, 0xde, 0xa1, 0xfa, 0x13, + 0x22, 0x45, 0x2b, 0xac, 0x6e, 0xfc, 0x99, 0x06, 0x47, 0x46, 0xb4, 0x16, 0x26, 0x32, 0xeb, 0xf3, + 0x0e, 0xbd, 0xf3, 0xa1, 0xdd, 0x12, 0x4b, 0x8a, 0xee, 0x83, 0x27, 0x06, 0x83, 0x4e, 0x2a, 0xe7, + 0xf3, 0x29, 0xd2, 0x7c, 0x6f, 0x1f, 0x0d, 0xf0, 0xcc, 0xfe, 0xc1, 0x92, 0x57, 0xbf, 0x4f, 0x7f, + 0xd4, 0x4a, 0x19, 0x12, 0x98, 0xc0, 0x7d, 0x7a, 0x6e, 0x24, 0x49, 0x8d, 0x2f, 0x77, 0x49, 0xfb, + 0x67, 0x8c, 0x5a, 0xa1, 0x42, 0x86, 0x12, 0xc0, 0x28, 0xa5, 0x79, 0xfc, 0x6c, 0x10, 0x19, 0x52, + 0xaa, 0xee, 0xd8, 0x32, 0x94, 0xef, 0x23, 0x6b, 0x07, 0xf8, 0x63, 0xa3, 0x39, 0x72, 0x63, 0xcb, + 0x9c, 0x1e, 0x87, 0xc4, 0x63, 0xf9, 0x3b, 0x96, 0x7e, 0x79, 0x02, 0x81, 0xa2, 0xbc, 0x27, 0xbf, + 0x67, 0xa2, 0xa3, 0x6b, 0xeb, 0xbf, 0x47, 0xb8, 0x5c, 0x29, 0x32, 0x2d, 0xbb, 0x33, 0x01, 0x36, + 0xf7, 0x72, 0x40, 0x3a, 0xf7, 0x92, 0x21, 0x90, 0xc4, 0xed, 0x86, 0xcf, 0x10, 0xb2, 0x96, 0x1b, + 0x66, 0x9d, 0x21, 0x24, 0x4f, 0x6d, 0x72, 0x49, 0xde, 0x9e, 0x45, 0xa3, 0x38, 0xda, 0x9d, 0x5e, + 0xcc, 0xf7, 0x9e, 0x5a, 0x35, 0x13, 0x93, 0xa2, 0xb9, 0x77, 0x38, 0xdf, 0x3c, 0xbf, 0xea, 0x5d, + 0xed, 0xdb, 0xfb, 0x84, 0x77, 0xfe, 0x7d, 0x2a, 0x34, 0x1f, 0xa6, 0x5b, 0x83, 0x7e, 0xa2, 0xab, + 0x05, 0xcb, 0x05, 0xbe, 0xb7, 0xce, 0x55, 0xaf, 0x4f, 0x3f, 0xff, 0x60, 0xf3, 0xe8, 0xfe, 0x21, + 0xc9, 0x81, 0xa7, 0x77, 0xc7, 0xf2, 0xe5, 0x8c, 0x47, 0x5b, 0x56, 0x3c, 0x82, 0xe4, 0xfb, 0xf4, + 0xc4, 0xe6, 0xd6, 0xbb, 0x2f, 0x95, 0x3b, 0x97, 0xfc, 0xcc, 0x2d, 0x22, 0xf0, 0xd6, 0xe9, 0xe5, + 0x8b, 0xa6, 0x57, 0x1e, 0x6c, 0x1e, 0xdd, 0xef, 0xe6, 0x3a, 0xde, 0x8e, 0x75, 0xe8, 0x17, 0x93, + 0x68, 0xbe, 0xf5, 0x75, 0x7f, 0xad, 0x7f, 0x08, 0x13, 0xb1, 0xd1, 0xf6, 0xc5, 0xd6, 0xfd, 0xe3, + 0x4f, 0xfe, 0xa7, 0xee, 0x27, 0x77, 0xad, 0xf1, 0x35, 0xd3, 0xcb, 0xbf, 0x20, 0xe5, 0x89, 0xc5, + 0xfc, 0xda, 0x89, 0x39, 0x0d, 0x3a, 0x39, 0xf7, 0xdb, 0x9d, 0x4b, 0xf8, 0x69, 0x49, 0xf4, 0x3b, + 0x70, 0xa8, 0x43, 0xd8, 0x76, 0x14, 0x7f, 0x33, 0x02, 0xed, 0xe9, 0x6f, 0xb3, 0xfc, 0x6f, 0x1e, + 0x4d, 0xc8, 0x09, 0x5a, 0xb1, 0xfc, 0xaf, 0x2b, 0x1a, 0x92, 0xef, 0xd8, 0x7f, 0x87, 0x26, 0x7a, + 0x77, 0xac, 0x83, 0x79, 0xe4, 0x64, 0x7a, 0x79, 0xc4, 0x37, 0x38, 0xbf, 0x7a, 0xd7, 0xb0, 0x18, + 0xae, 0x0d, 0x86, 0x55, 0x33, 0xa7, 0x4d, 0xde, 0xdf, 0xd0, 0x8f, 0x0d, 0x81, 0x3c, 0x6f, 0xdc, + 0x9d, 0xd0, 0xcc, 0x19, 0xb7, 0xc6, 0x7f, 0x6b, 0x98, 0x18, 0xdb, 0xe6, 0xbb, 0xf4, 0x9d, 0x8a, + 0xcc, 0x7c, 0x2e, 0x35, 0x25, 0xf4, 0xf6, 0x20, 0xa1, 0x04, 0xd7, 0x3d, 0x43, 0x8e, 0xaf, 0x0d, + 0xd5, 0x93, 0xd7, 0xfd, 0xd5, 0xf7, 0xf8, 0x2f, 0xdd, 0xcc, 0xe4, 0x5a, 0xb3, 0xbc, 0xd2, 0xdb, + 0x96, 0xf2, 0xbf, 0xd9, 0xb0, 0x68, 0x95, 0x6d, 0x96, 0xff, 0xcd, 0x2c, 0xb7, 0x68, 0xda, 0x2c, + 0xff, 0x9b, 0x6d, 0xb9, 0xab, 0xa3, 0xcd, 0xf2, 0xbf, 0x59, 0xca, 0x5d, 0xda, 0x27, 0x59, 0xbe, + 0xff, 0xdb, 0x51, 0xca, 0x0a, 0xe2, 0x51, 0x71, 0xff, 0x27, 0x77, 0x45, 0x24, 0xf3, 0xb8, 0x78, + 0x12, 0x10, 0x76, 0x0a, 0x5f, 0x5a, 0xdd, 0x5e, 0xad, 0xa2, 0x6f, 0x7f, 0x74, 0x55, 0x19, 0x72, + 0x7e, 0x63, 0x85, 0x70, 0x50, 0xcb, 0xd6, 0x87, 0xfc, 0x33, 0xd7, 0x25, 0x5b, 0x40, 0xbd, 0x61, + 0x46, 0xf7, 0x0e, 0x5c, 0x4c, 0x2c, 0x58, 0x7a, 0x25, 0x74, 0x97, 0x6e, 0x40, 0x8c, 0x74, 0xf4, + 0x29, 0x25, 0x33, 0x74, 0xbf, 0x24, 0xf4, 0xff, 0x37, 0x96, 0x47, 0x3b, 0x5a, 0xb3, 0x1c, 0x1d, + 0x69, 0x4b, 0xf9, 0x9f, 0x6d, 0xe0, 0x3f, 0x7d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, + 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xfe, 0x6f, 0x23, + 0xf8, 0x4f, 0xdf, 0xe3, 0x19, 0x46, 0x82, 0xf1, 0x27, 0xff, 0x22, 0x0d, 0x6c, 0xab, 0xe4, 0x48, + 0x63, 0x82, 0x54, 0x77, 0xe6, 0x60, 0x9a, 0x9b, 0x5a, 0x8b, 0x97, 0x44, 0xa2, 0xcf, 0x1f, 0x57, + 0x07, 0x97, 0x2e, 0x4b, 0xa5, 0xef, 0xfe, 0xab, 0x78, 0x5d, 0xfe, 0x66, 0x36, 0xff, 0xfd, 0x25, + 0x95, 0x61, 0x5d, 0x06, 0x82, 0x3f, 0xae, 0x77, 0xf5, 0xf0, 0x07, 0x33, 0x16, 0x58, 0xde, 0xa2, + 0x52, 0x32, 0x96, 0xa7, 0x46, 0x61, 0x81, 0xae, 0xcb, 0xd2, 0x6a, 0x62, 0xeb, 0xf7, 0x33, 0x2d, + 0xfb, 0xc1, 0x65, 0x19, 0xd8, 0xdd, 0xfe, 0x7a, 0x91, 0xab, 0x6e, 0x95, 0x46, 0x0f, 0x61, 0xe5, + 0xae, 0x0d, 0xb8, 0x7b, 0xc8, 0x4c, 0x0d, 0x35, 0x76, 0x73, 0xff, 0x1f, 0xfc, 0x67, 0x95, 0x44, + 0xbf, 0x33, 0x8f, 0xae, 0x77, 0xfc, 0xe9, 0x45, 0xde, 0x27, 0x18, 0xb2, 0xae, 0x3f, 0x8f, 0x87, + 0x16, 0x59, 0xc1, 0xda, 0x74, 0xfa, 0x59, 0x97, 0xe9, 0x66, 0x69, 0xec, 0xed, 0x71, 0x55, 0x95, + 0xc1, 0x31, 0x43, 0xaa, 0x62, 0xd1, 0xb0, 0xca, 0x67, 0x3f, 0xcf, 0x6a, 0x17, 0xbd, 0x4c, 0xda, + 0xb7, 0x8e, 0xdb, 0x25, 0x78, 0x71, 0x92, 0x25, 0xbf, 0x26, 0x7a, 0x92, 0x2e, 0xcd, 0x33, 0xe1, + 0x56, 0xb3, 0xae, 0xa8, 0xc7, 0x08, 0x5a, 0x1c, 0xae, 0x37, 0x5a, 0x04, 0x82, 0x72, 0xda, 0xfb, + 0x2b, 0xfa, 0x71, 0x98, 0xd6, 0x28, 0x10, 0xda, 0x22, 0xf1, 0x63, 0xc3, 0x49, 0xd2, 0x38, 0xbb, + 0x96, 0x79, 0xe7, 0x06, 0x2d, 0xcc, 0xd7, 0x2d, 0x58, 0xd0, 0x62, 0x2d, 0x80, 0xe9, 0x53, 0x15, + 0x87, 0x46, 0x45, 0xd2, 0x5e, 0xbd, 0xf4, 0x9f, 0x71, 0xdc, 0xa8, 0x46, 0xc0, 0x2e, 0xbe, 0xc4, + 0x6c, 0x87, 0xfc, 0x81, 0x35, 0x86, 0x4c, 0x77, 0xd0, 0x37, 0xbd, 0x32, 0xb2, 0xd6, 0x14, 0x68, + 0x61, 0xd7, 0xa7, 0x08, 0x4b, 0xc9, 0x8e, 0x50, 0x84, 0xde, 0x3c, 0x8f, 0x13, 0x43, 0x0a, 0xd0, + 0x54, 0x6d, 0x24, 0x98, 0x50, 0x78, 0xfd, 0xab, 0x37, 0xc0, 0xce, 0x1f, 0xe2, 0xd7, 0x2d, 0xfc, + 0xe5, 0x57, 0xd6, 0x74, 0x04, 0x74, 0xed, 0x2d, 0xc3, 0xe0, 0x41, 0x43, 0x26, 0x41, 0x60, 0x6a, + 0x9a, 0xb0, 0xa8, 0x66, 0x51, 0xaf, 0xbe, 0x34, 0x4a, 0xac, 0xa6, 0x42, 0x4e, 0x3c, 0xc5, 0x92, + 0xe0, 0xa6, 0xd8, 0x6d, 0x8b, 0x9d, 0x46, 0x8b, 0xc4, 0x0b, 0xbc, 0xa4, 0x18, 0x4c, 0xc0, 0xdb, + 0x57, 0x1c, 0x85, 0xf3, 0x68, 0xc0, 0x80, 0xe3, 0x94, 0xc7, 0x4a, 0x96, 0x88, 0x4e, 0xbe, 0xc4, + 0x3d, 0x5c, 0x0a, 0x48, 0x88, 0xef, 0xcd, 0x30, 0x52, 0xb6, 0x60, 0xf9, 0xa3, 0xe2, 0x52, 0x52, + 0x04, 0x96, 0x16, 0x83, 0x0b, 0x84, 0xcb, 0x9c, 0x68, 0xbf, 0x44, 0xe1, 0xe2, 0xaa, 0xc8, 0xe5, + 0xe0, 0x86, 0x50, 0x82, 0x0d, 0xca, 0xd5, 0xa0, 0xed, 0x52, 0x3c, 0x2c, 0xed, 0x24, 0x73, 0xf5, + 0x6a, 0xa4, 0x2e, 0x6d, 0x07, 0x57, 0x12, 0x4f, 0x02, 0x6b, 0xdb, 0x69, 0xae, 0x0b, 0x31, 0xf5, + 0x2b, 0xae, 0xeb, 0xe2, 0xdd, 0x9f, 0xa9, 0x8e, 0x58, 0x06, 0xa5, 0xce, 0x9c, 0x12, 0xb6, 0xd0, + 0x6a, 0xa4, 0x74, 0x8f, 0x11, 0x74, 0x3f, 0xc7, 0x1b, 0x84, 0xf5, 0x61, 0x45, 0x08, 0x78, 0x86, + 0xe6, 0x91, 0x64, 0xd1, 0x4a, 0xf8, 0xcb, 0x78, 0x53, 0xe2, 0xc9, 0xd8, 0x77, 0xf3, 0x4b, 0x0c, + 0x5a, 0x28, 0xe5, 0xc8, 0xc3, 0xd9, 0xf0, 0x08, 0xfc, 0xe5, 0x02, 0x7a, 0xe6, 0x6a, 0x4e, 0x9e, + 0xd4, 0x70, 0x97, 0xc0, 0xda, 0x8c, 0x4a, 0xf9, 0x93, 0xcb, 0xf6, 0xdf, 0x54, 0xdb, 0x71, 0x69, + 0x1b, 0xd7, 0xdd, 0xbf, 0x04, 0x41, 0xee, 0xd6, 0x93, 0xfc, 0x4e, 0x22, 0xa4, 0x56, 0xd3, 0x82, + 0xe5, 0xf2, 0xdd, 0xa9, 0x21, 0xd3, 0x8f, 0xe8, 0x6c, 0xa7, 0xb8, 0x51, 0x88, 0x17, 0xc7, 0xb5, + 0x5c, 0x5d, 0x43, 0xf1, 0xfe, 0xdd, 0x45, 0xb0, 0xd7, 0xe0, 0x26, 0x0a, 0x6b, 0x8b, 0x3d, 0x8f, + 0x73, 0xb2, 0x2d, 0x27, 0x4a, 0xe0, 0x69, 0x2e, 0xef, 0x84, 0x6a, 0x07, 0x18, 0x16, 0xbb, 0x3c, + 0xa1, 0x4b, 0x96, 0xb7, 0xbe, 0xd6, 0xa8, 0xf3, 0x9d, 0xb0, 0x41, 0xdd, 0x9b, 0x2e, 0xd9, 0xad, + 0x97, 0xf8, 0xd0, 0xc4, 0x46, 0xd9, 0x9e, 0x7d, 0x1f, 0x53, 0x55, 0x23, 0x41, 0x5b, 0xd9, 0xe1, + 0xbf, 0xcc, 0x5d, 0xdf, 0xef, 0x62, 0x23, 0xe9, 0x88, 0x36, 0x4a, 0x3b, 0x6c, 0xd4, 0x63, 0xcb, + 0x8a, 0x5a, 0xd0, 0xb1, 0x54, 0xcb, 0x33, 0x3b, 0x17, 0x17, 0x5c, 0xed, 0x57, 0x4a, 0xb4, 0x67, + 0x1c, 0xcd, 0x71, 0xc5, 0x62, 0x44, 0x22, 0x74, 0x8e, 0x2a, 0x03, 0x7b, 0x44, 0x89, 0x5c, 0xf8, + 0xe2, 0xea, 0xe6, 0xa4, 0x1f, 0x87, 0x85, 0x31, 0xfd, 0xa8, 0x44, 0x46, 0x77, 0x5c, 0x17, 0x62, + 0x70, 0xe2, 0x3f, 0x68, 0x58, 0x42, 0xb9, 0xef, 0xcc, 0x30, 0xea, 0x68, 0xc1, 0x72, 0xdf, 0x75, + 0xb2, 0x45, 0x20, 0xe8, 0x2b, 0xd9, 0x55, 0x35, 0x82, 0x2c, 0x2d, 0xf0, 0xd9, 0x90, 0x9f, 0x3b, + 0xe6, 0x4b, 0xed, 0x90, 0x32, 0xbf, 0x2f, 0x29, 0x09, 0x71, 0xf7, 0x77, 0xe6, 0xc7, 0x08, 0xe3, + 0xc2, 0x70, 0xf2, 0xa6, 0x05, 0x56, 0xa8, 0xab, 0x2a, 0x16, 0x8b, 0x86, 0x62, 0xa7, 0xb8, 0x63, + 0xa4, 0x91, 0x4a, 0xb2, 0x12, 0x9c, 0x4a, 0xed, 0x48, 0xfc, 0x50, 0x3f, 0x4f, 0x5c, 0x40, 0x03, + 0xc3, 0x06, 0xed, 0xda, 0x9d, 0x16, 0xe7, 0x1b, 0xb4, 0xa3, 0x34, 0xfe, 0x4f, 0xce, 0x0f, 0x74, + 0xbe, 0xea, 0x07, 0x97, 0x11, 0x95, 0xd1, 0xa2, 0xd1, 0x34, 0xe4, 0x84, 0x05, 0xd2, 0xc0, 0x75, + 0x11, 0xb5, 0x62, 0x4c, 0xb5, 0x75, 0xaf, 0x45, 0x10, 0xa3, 0x7e, 0x5b, 0xdc, 0xfa, 0xb9, 0x51, + 0xc3, 0x0c, 0xa7, 0x92, 0x4c, 0xda, 0x9d, 0xda, 0x64, 0xbe, 0x24, 0x5e, 0x19, 0x7d, 0x5b, 0xea, + 0x51, 0xb2, 0xc8, 0xcd, 0x02, 0x7e, 0xd0, 0x42, 0xb3, 0x97, 0x7c, 0xf6, 0xf3, 0xbf, 0x42, 0xb0, + 0xfc, 0x4f, 0xc4, 0x30, 0xa6, 0x07, 0x46, 0x49, 0x69, 0x97, 0x38, 0x83, 0xaa, 0xed, 0x2d, 0xf5, + 0x70, 0xe2, 0x17, 0xd8, 0xc2, 0x77, 0xdd, 0x02, 0x6b, 0xb4, 0x28, 0x9a, 0x48, 0xd4, 0x1b, 0x6f, + 0x76, 0x8d, 0x27, 0x4a, 0x51, 0xd1, 0xce, 0xa9, 0x90, 0x13, 0xe5, 0x6f, 0x9b, 0xd4, 0x8b, 0x5b, + 0xfc, 0xf5, 0x84, 0x2b, 0x67, 0xbb, 0x6e, 0x91, 0xf0, 0x15, 0xd6, 0xe1, 0x83, 0xe8, 0xef, 0xcd, + 0xa3, 0xd3, 0xb6, 0x60, 0x39, 0x0e, 0x55, 0xd8, 0x26, 0x97, 0xca, 0x50, 0xad, 0xf2, 0x89, 0x0f, + 0xd9, 0x2f, 0x73, 0x21, 0x3d, 0xb7, 0xbb, 0x72, 0x29, 0xb0, 0x33, 0x6a, 0xf9, 0x01, 0xda, 0x23, + 0x97, 0x22, 0x1d, 0x4f, 0x17, 0xee, 0x55, 0x20, 0x96, 0x9e, 0x9b, 0xda, 0x30, 0x5a, 0xa0, 0xa4, + 0xb9, 0x86, 0x92, 0xf6, 0x03, 0xc3, 0x72, 0x4f, 0x2b, 0x9d, 0xa8, 0x45, 0xc4, 0x55, 0xcd, 0x92, + 0xbb, 0xd0, 0xdb, 0x45, 0xff, 0x05, 0x72, 0x79, 0x33, 0x2d, 0x46, 0xd0, 0xaf, 0x40, 0x5c, 0xa0, + 0xc5, 0xc1, 0x75, 0x35, 0x2c, 0xe9, 0x41, 0xa5, 0xb7, 0xf1, 0x0b, 0x41, 0x50, 0x44, 0x78, 0x9d, + 0x39, 0x63, 0x94, 0x23, 0xae, 0x1c, 0xb4, 0x38, 0xb9, 0x9e, 0x7e, 0xb9, 0x8c, 0xe6, 0xc1, 0xd2, + 0x33, 0x37, 0x2d, 0xd0, 0x5e, 0xf1, 0x75, 0xaf, 0x6e, 0x2a, 0x35, 0xe7, 0x04, 0x03, 0x08, 0xe8, + 0x90, 0x06, 0x3c, 0x48, 0x28, 0x41, 0x64, 0xb4, 0x70, 0x00, 0x91, 0xdd, 0x56, 0xdc, 0xaa, 0xf4, + 0x8a, 0x9b, 0x15, 0xa9, 0x89, 0xeb, 0xee, 0xba, 0x10, 0x81, 0x08, 0x91, 0x01, 0x9b, 0x07, 0x2d, + 0x8e, 0x44, 0x2a, 0xcb, 0x09, 0xfa, 0x1b, 0xcf, 0x70, 0xa1, 0xdf, 0x59, 0x47, 0x60, 0xa4, 0x05, + 0xcb, 0x37, 0xcb, 0xf6, 0x53, 0x03, 0xbb, 0x8f, 0x17, 0x96, 0xb5, 0x7c, 0xf3, 0x62, 0xa3, 0x64, + 0xd1, 0x5f, 0xd6, 0x2c, 0xbd, 0xd4, 0xd5, 0xd1, 0x71, 0x5d, 0x27, 0xc2, 0xd3, 0xc9, 0xd7, 0xaf, + 0xa2, 0xfd, 0xff, 0x25, 0x60, 0x80, 0xbf, 0x2d, 0xfd, 0x4e, 0x79, 0x14, 0xbe, 0x46, 0xf5, 0xe0, + 0xac, 0xeb, 0xa3, 0x52, 0x29, 0xfd, 0xfd, 0xac, 0x77, 0x0c, 0x16, 0x14, 0xac, 0x3a, 0xb2, 0x91, + 0xb2, 0x22, 0x61, 0xbd, 0xa8, 0xc0, 0xc2, 0x26, 0xb9, 0x32, 0x67, 0xf8, 0xb8, 0xf2, 0xb6, 0x53, + 0x43, 0x3f, 0x54, 0xae, 0x82, 0x77, 0x06, 0x2b, 0x88, 0xc2, 0xe2, 0x5a, 0xb0, 0x86, 0x21, 0x66, + 0x90, 0x33, 0xe4, 0x77, 0x6c, 0x39, 0x6a, 0x6c, 0xc1, 0x72, 0xae, 0xa2, 0xe8, 0x4d, 0x9d, 0xa2, + 0xa6, 0x28, 0x89, 0x15, 0x32, 0xb4, 0xab, 0x0f, 0x08, 0x46, 0xb3, 0xf4, 0x23, 0xf4, 0x38, 0x72, + 0xce, 0x9d, 0x70, 0x62, 0x08, 0xbf, 0xb0, 0xe4, 0x9e, 0x8f, 0x42, 0xa0, 0x60, 0x74, 0xf5, 0x21, + 0xd7, 0x9c, 0x50, 0x02, 0xd1, 0xec, 0xea, 0x03, 0x6c, 0xb3, 0x29, 0x81, 0xa8, 0x0b, 0x34, 0xe0, + 0x81, 0xf7, 0x5a, 0x40, 0x2f, 0x04, 0x1e, 0xc4, 0xb5, 0xed, 0xe2, 0xb4, 0xa1, 0x5f, 0x8a, 0x20, + 0x9c, 0xd3, 0xb4, 0x40, 0x4f, 0xd7, 0x05, 0xd4, 0xee, 0x6e, 0xa5, 0xb7, 0x7e, 0xae, 0xa0, 0x5b, + 0xa3, 0x05, 0xe7, 0xbb, 0x81, 0xf2, 0xf5, 0x5f, 0xd7, 0x61, 0xb4, 0x71, 0xc2, 0xd7, 0x2f, 0x75, + 0x12, 0x5d, 0xfd, 0xd7, 0x2d, 0x94, 0xf2, 0x46, 0xf1, 0x62, 0xf8, 0x32, 0x0f, 0x78, 0x27, 0xa7, + 0x3b, 0x6e, 0x4b, 0x2c, 0xde, 0x29, 0xef, 0x0c, 0x74, 0xc5, 0xc5, 0x53, 0x73, 0x7a, 0x71, 0x53, + 0x77, 0x5d, 0x04, 0xd0, 0x16, 0x57, 0x71, 0x5a, 0x28, 0xbf, 0xae, 0xd0, 0xa5, 0xec, 0xbf, 0x5b, + 0x2c, 0xe5, 0x3b, 0xb6, 0x9c, 0xee, 0x69, 0xc1, 0xf2, 0x2e, 0x51, 0xb3, 0x88, 0x32, 0x0d, 0xac, + 0x01, 0xe0, 0xa5, 0x48, 0x0a, 0xec, 0x13, 0x60, 0x79, 0xc5, 0x06, 0x80, 0x44, 0x0e, 0x3e, 0x2e, + 0x87, 0x40, 0x4e, 0x70, 0xaf, 0xc4, 0xbb, 0x83, 0x53, 0x00, 0x3f, 0x1b, 0xc8, 0x46, 0x83, 0xb8, + 0x3a, 0x6c, 0x72, 0x78, 0x4c, 0x0a, 0xdf, 0x41, 0xc4, 0x15, 0x48, 0x93, 0x72, 0x1f, 0xc9, 0xd9, + 0x80, 0x37, 0xf7, 0x91, 0x0d, 0xcd, 0x93, 0x02, 0xf3, 0xa4, 0x85, 0x67, 0x05, 0x6a, 0x29, 0xf7, + 0x45, 0x65, 0xb0, 0x8a, 0x97, 0x33, 0xd7, 0x0f, 0x8f, 0x29, 0x1f, 0xe7, 0xe0, 0x21, 0xb6, 0x01, + 0xc0, 0xc0, 0x46, 0xcd, 0x22, 0x60, 0x23, 0x89, 0xae, 0x01, 0xf0, 0x91, 0x9a, 0x7c, 0xe2, 0x30, + 0x09, 0xf2, 0x08, 0xd9, 0x70, 0xfc, 0x14, 0x42, 0x94, 0xd5, 0xe0, 0xd3, 0x60, 0x83, 0x81, 0x4e, + 0x58, 0xc9, 0xcc, 0xa5, 0x7d, 0xfc, 0x0c, 0x27, 0xad, 0x7d, 0x50, 0xd4, 0x8f, 0x33, 0xb3, 0xb7, + 0x98, 0x49, 0xf3, 0xa8, 0x00, 0x1a, 0x2c, 0x88, 0xee, 0xd6, 0x7e, 0x67, 0xb5, 0x0c, 0x4b, 0x0b, + 0x96, 0x0b, 0xff, 0x8a, 0x52, 0x05, 0xdf, 0x32, 0x6b, 0xdb, 0x00, 0xde, 0x8e, 0x59, 0xd4, 0x07, + 0xd8, 0xab, 0x34, 0xf9, 0x35, 0xd7, 0x69, 0x4d, 0xf9, 0x8b, 0xa6, 0xb8, 0xc4, 0x47, 0x9c, 0x01, + 0x87, 0x26, 0x48, 0x25, 0x00, 0x5c, 0x4f, 0x6d, 0x01, 0xa7, 0xd4, 0x6c, 0x81, 0xe9, 0x19, 0x6f, + 0x60, 0xfc, 0x2d, 0xbd, 0xb6, 0x45, 0xa6, 0x3b, 0x4d, 0x2c, 0xf0, 0xbf, 0x9d, 0x2f, 0x2c, 0xfe, + 0xa2, 0x80, 0x09, 0x39, 0x31, 0xfe, 0x4e, 0xfa, 0x53, 0x49, 0xb5, 0x4f, 0xe1, 0xf6, 0x2e, 0xfd, + 0x6d, 0x8b, 0x20, 0x80, 0xda, 0x3e, 0xc3, 0x7a, 0x56, 0x6d, 0x22, 0x6b, 0x7a, 0x0f, 0x2d, 0xc1, + 0x17, 0xc6, 0x58, 0x73, 0x3a, 0xfa, 0xca, 0x0a, 0x9e, 0xc6, 0xdf, 0x21, 0x4b, 0xd1, 0x97, 0xc1, + 0x92, 0x91, 0xb5, 0x58, 0x35, 0xfe, 0xeb, 0x5e, 0x01, 0x6f, 0x4f, 0xe2, 0xc6, 0xd1, 0xd2, 0x7a, + 0x52, 0xe2, 0xf7, 0x9d, 0x71, 0xee, 0xd8, 0x2a, 0xf9, 0x9c, 0xab, 0x4f, 0x85, 0x70, 0xe0, 0xb6, + 0xc9, 0xda, 0x42, 0xc7, 0x0b, 0xec, 0xab, 0x2f, 0x46, 0x14, 0x0e, 0x6e, 0x5b, 0x0c, 0x32, 0x3e, + 0xcc, 0x9c, 0x06, 0x0e, 0x12, 0x8f, 0x02, 0xa8, 0x49, 0xb2, 0x8d, 0xea, 0x79, 0x3b, 0x56, 0x70, + 0x49, 0x21, 0x1d, 0x5a, 0x29, 0xbd, 0x9a, 0xe4, 0x14, 0xd5, 0x7f, 0xad, 0x62, 0x85, 0xfa, 0x20, + 0x43, 0x05, 0xf5, 0xec, 0x70, 0x32, 0x4d, 0x42, 0x9f, 0x14, 0x29, 0x79, 0x45, 0x00, 0x60, 0xe8, + 0xf8, 0x12, 0x1c, 0x7c, 0xf4, 0x9d, 0xdf, 0xbf, 0x63, 0x58, 0x10, 0x5b, 0x0b, 0x96, 0x37, 0x6c, + 0x2f, 0xc2, 0x99, 0x4e, 0x45, 0x93, 0xc7, 0x3d, 0x77, 0xcb, 0x4d, 0xbb, 0x88, 0x47, 0xaa, 0xc9, + 0xb5, 0x50, 0x20, 0x48, 0x13, 0xd3, 0x03, 0x8d, 0xd4, 0x22, 0x00, 0x92, 0xdb, 0xa0, 0x25, 0xb9, + 0x15, 0x20, 0xa5, 0xfc, 0xa1, 0x5f, 0x95, 0x5d, 0x97, 0x61, 0x05, 0x2a, 0x6c, 0x1b, 0x50, 0xb8, + 0xe8, 0xde, 0x01, 0x69, 0xd3, 0x5a, 0x01, 0x33, 0x01, 0x00, 0xc1, 0xc3, 0x4f, 0x8d, 0x1c, 0xd0, + 0xb7, 0x3e, 0xcf, 0x06, 0x25, 0x15, 0x01, 0x02, 0x9e, 0x1b, 0x51, 0x4a, 0x11, 0x97, 0x12, 0x3c, + 0xed, 0x51, 0x9e, 0x12, 0x78, 0x7f, 0xcb, 0x83, 0xbb, 0x18, 0xe1, 0xcb, 0x08, 0xa0, 0x1f, 0xd4, + 0x72, 0xa8, 0xbd, 0xff, 0xe1, 0xcb, 0x1c, 0xd0, 0xc2, 0xbb, 0xf0, 0xbb, 0xa9, 0x17, 0x00, 0xbf, + 0x23, 0x2e, 0xa1, 0xf2, 0xe9, 0xd4, 0x57, 0xa4, 0x03, 0xf9, 0x73, 0xc3, 0x92, 0x43, 0x5a, 0xb0, + 0x5c, 0xf0, 0xdd, 0x62, 0x74, 0x7a, 0xb5, 0xd8, 0x43, 0x0f, 0x4e, 0x19, 0x2d, 0xa3, 0x05, 0x66, + 0x27, 0x8b, 0x15, 0x36, 0x62, 0x9f, 0x2f, 0x0e, 0x77, 0xb7, 0x32, 0x17, 0xc9, 0xf2, 0xee, 0xd0, + 0x62, 0xf2, 0x0c, 0x3a, 0xa5, 0x2a, 0x80, 0xd5, 0x79, 0xd2, 0x9e, 0x35, 0x00, 0x18, 0x3c, 0xa4, + 0xdb, 0x48, 0x70, 0xf1, 0xfa, 0xd4, 0x8f, 0x14, 0x07, 0xfb, 0x04, 0xd0, 0x3d, 0x33, 0x58, 0x4b, + 0x9e, 0x93, 0xcd, 0xda, 0x37, 0x6b, 0x47, 0xa1, 0x4f, 0x2b, 0xde, 0xff, 0x90, 0xe4, 0xd0, 0xb1, + 0xc1, 0x03, 0x14, 0x2f, 0xa7, 0x44, 0xd3, 0x2b, 0x9b, 0x3f, 0xcb, 0x28, 0x63, 0x3e, 0x93, 0xd1, + 0x1e, 0x8d, 0x0d, 0x66, 0x32, 0x17, 0x87, 0x99, 0x4c, 0xa9, 0x04, 0x10, 0xba, 0xb9, 0xde, 0x5b, + 0xde, 0xca, 0x02, 0x70, 0xbe, 0x33, 0x34, 0x77, 0x74, 0xee, 0x58, 0xd6, 0x6d, 0x94, 0x8b, 0x27, + 0xf5, 0xd7, 0x89, 0xad, 0xf2, 0xe7, 0x04, 0x00, 0xc0, 0x5f, 0xcb, 0x19, 0x70, 0xbb, 0x49, 0xbb, + 0xc8, 0x7f, 0x01, 0xda, 0x5e, 0x96, 0x78, 0x7c, 0xc9, 0x52, 0x6d, 0x23, 0x93, 0xf9, 0x04, 0x9f, + 0xbb, 0x38, 0x4b, 0x6c, 0x34, 0xaa, 0xe7, 0x12, 0xae, 0x46, 0xe9, 0x7a, 0xbe, 0x68, 0xa9, 0xb2, + 0x21, 0x96, 0x35, 0x6b, 0xcd, 0xe6, 0xaa, 0x8d, 0x79, 0xf6, 0x37, 0x7a, 0x26, 0x89, 0x10, 0xdf, + 0x59, 0x47, 0xc0, 0xdb, 0x82, 0xe5, 0xbd, 0xbd, 0xf1, 0xdf, 0x3e, 0x3e, 0x03, 0x90, 0x17, 0x00, + 0x58, 0x60, 0x2b, 0x86, 0x77, 0xd2, 0xf0, 0x86, 0x33, 0xe3, 0x1d, 0xc9, 0xd0, 0xbf, 0x16, 0xe6, + 0x33, 0xc5, 0x41, 0x85, 0xeb, 0x56, 0x2b, 0x31, 0x1f, 0x00, 0xb0, 0xd8, 0x9a, 0x4f, 0xe5, 0x6c, + 0x82, 0x64, 0xa0, 0xef, 0x5a, 0x96, 0x4c, 0xeb, 0x54, 0x3b, 0xe1, 0x05, 0x9e, 0x2a, 0xf4, 0x09, + 0xb3, 0x32, 0x67, 0xf7, 0x5a, 0x24, 0x88, 0xc2, 0x3a, 0x80, 0xbc, 0x7d, 0x06, 0x2f, 0xf7, 0x0c, + 0x5f, 0x92, 0x9c, 0x30, 0x98, 0x92, 0xe9, 0x39, 0x05, 0xb8, 0x64, 0xe1, 0xa7, 0x78, 0x68, 0x46, + 0x81, 0xe4, 0xbb, 0xfe, 0x35, 0x77, 0xdd, 0xc2, 0xa8, 0x96, 0x27, 0x88, 0xa0, 0x81, 0xae, 0x61, + 0x9a, 0x31, 0x59, 0xe4, 0xe7, 0x78, 0x08, 0xe5, 0xc7, 0xb7, 0x81, 0x89, 0x31, 0x85, 0x81, 0x3d, + 0x8a, 0x4b, 0xfc, 0xab, 0x71, 0xb9, 0xcb, 0xc0, 0x7b, 0xae, 0x9c, 0xd5, 0xde, 0x69, 0x41, 0x83, + 0x16, 0xa9, 0x1a, 0x56, 0x2a, 0x83, 0x16, 0xff, 0x02, 0x2d, 0xc0, 0x33, 0x86, 0xa3, 0x3b, 0xd6, + 0xb4, 0x71, 0x4d, 0x14, 0xc2, 0xd7, 0x54, 0x03, 0x98, 0x56, 0xf9, 0x5c, 0xe9, 0x3b, 0xb9, 0xb6, + 0x15, 0xe3, 0x83, 0x29, 0x82, 0x30, 0x82, 0x16, 0x3e, 0x00, 0xc8, 0x89, 0x9f, 0x67, 0xcd, 0x20, + 0x1e, 0x90, 0x2c, 0x18, 0x23, 0x56, 0xeb, 0x45, 0xbe, 0x93, 0x06, 0x0f, 0x12, 0x6c, 0x57, 0xd3, + 0x0a, 0x79, 0x68, 0x3a, 0x77, 0xfd, 0x0c, 0x10, 0xfa, 0xf7, 0x10, 0x46, 0x7d, 0xaa, 0x46, 0x14, + 0xa2, 0x76, 0xbc, 0xeb, 0xd7, 0xf0, 0x3f, 0x41, 0x67, 0x16, 0x66, 0x8f, 0xe3, 0x61, 0x23, 0xfd, + 0x9d, 0xd5, 0x32, 0xf0, 0x16, 0x2c, 0x6f, 0x18, 0x02, 0xe8, 0xa3, 0x7b, 0xaf, 0xf5, 0xc9, 0xd2, + 0xc3, 0x41, 0x5e, 0x35, 0x0c, 0xbc, 0x07, 0x39, 0x48, 0x01, 0xb0, 0xb5, 0x0d, 0x91, 0x3a, 0x69, + 0xe4, 0x3e, 0xb2, 0x41, 0x80, 0xad, 0x80, 0x2d, 0x0e, 0x88, 0x0e, 0x09, 0x17, 0x41, 0x03, 0x55, + 0xbf, 0x63, 0x94, 0xa0, 0x56, 0xde, 0x69, 0x01, 0x34, 0xba, 0x02, 0xed, 0x11, 0x0d, 0x37, 0x16, + 0x0d, 0x54, 0xcd, 0x9e, 0x46, 0x35, 0x5b, 0xe0, 0x3e, 0xb5, 0xb0, 0x4e, 0x9f, 0x71, 0x50, 0x0a, + 0x10, 0xb0, 0xe4, 0x9e, 0x8b, 0xe6, 0x89, 0x21, 0x52, 0x86, 0xce, 0x0b, 0x81, 0x1a, 0xdd, 0xd3, + 0x40, 0x45, 0xc0, 0xeb, 0x0a, 0x00, 0xa2, 0xd2, 0x02, 0x8b, 0x88, 0x20, 0x82, 0x5b, 0x9c, 0xf2, + 0x00, 0xbf, 0xab, 0x80, 0xf5, 0x43, 0x9a, 0x2e, 0xf0, 0x20, 0xd7, 0x78, 0x2d, 0x78, 0xd3, 0xae, + 0x81, 0x5b, 0xeb, 0x87, 0x34, 0x5e, 0x15, 0xe2, 0x14, 0xe4, 0xc6, 0x50, 0xb9, 0x2c, 0x3c, 0x35, + 0x67, 0x66, 0x9b, 0x38, 0x85, 0x16, 0xf4, 0x3d, 0xa9, 0x8f, 0xb3, 0x95, 0xd6, 0x4b, 0x37, 0xf4, + 0x6c, 0xb6, 0x60, 0xf9, 0x90, 0x7c, 0xeb, 0xe4, 0xf2, 0xcd, 0x8b, 0xa9, 0x10, 0x2c, 0x44, 0x6c, + 0xae, 0x25, 0xcb, 0xdb, 0x9f, 0x2e, 0x87, 0x53, 0x53, 0x43, 0x73, 0xb1, 0xee, 0xfd, 0x0a, 0x65, + 0x50, 0xee, 0x63, 0x53, 0xc9, 0x6a, 0x69, 0xb9, 0x0c, 0xdc, 0x6c, 0xa8, 0x16, 0xeb, 0x66, 0x96, + 0x75, 0x47, 0x67, 0x1a, 0x58, 0xa7, 0x7d, 0xef, 0x53, 0xad, 0x52, 0x9d, 0x5a, 0xaa, 0x1b, 0x7d, + 0x6e, 0xa3, 0x6e, 0x83, 0xc0, 0xc7, 0x7e, 0xf7, 0xa9, 0xf0, 0xd1, 0xda, 0x06, 0x85, 0xcb, 0xf0, + 0x8e, 0x32, 0x06, 0x03, 0x74, 0xc9, 0x21, 0xea, 0xdb, 0x09, 0xe3, 0x09, 0xfc, 0xc8, 0xfe, 0x23, + 0x30, 0x7d, 0xf1, 0xef, 0x1a, 0x17, 0xa4, 0x7b, 0x84, 0x52, 0x99, 0xc7, 0xfd, 0x06, 0xd6, 0x7c, + 0x8d, 0xbd, 0xb0, 0x57, 0xf0, 0x67, 0xea, 0x83, 0xfd, 0xe4, 0x98, 0x38, 0x3b, 0xa6, 0x49, 0xd0, + 0x01, 0x58, 0x4d, 0x92, 0xc3, 0xf9, 0x8d, 0x4d, 0xe6, 0x62, 0x63, 0xd7, 0x9e, 0xd7, 0xfe, 0x1f, + 0x5a, 0xba, 0x81, 0xe0, 0xb5, 0xf8, 0x9e, 0x1d, 0xad, 0xdf, 0x4f, 0xbf, 0x38, 0xd7, 0xb1, 0x09, + 0xc7, 0xf8, 0xd8, 0xc1, 0xfa, 0x67, 0x2c, 0x1a, 0xf1, 0xe7, 0xd5, 0x8c, 0x05, 0x8f, 0x4e, 0xee, + 0x87, 0xa2, 0x91, 0x6e, 0xf9, 0xc1, 0x01, 0xca, 0x4f, 0x84, 0xdf, 0xb2, 0x84, 0x55, 0x75, 0x03, + 0x69, 0x34, 0x6a, 0x00, 0x9b, 0xc6, 0x35, 0x91, 0xae, 0xad, 0xd3, 0x88, 0xa9, 0xb4, 0x4f, 0x1a, + 0x17, 0x86, 0x59, 0xf3, 0xe7, 0xa2, 0x3c, 0x2e, 0xc1, 0x8b, 0xcf, 0xe3, 0xa4, 0xff, 0xa8, 0x70, + 0x0a, 0x41, 0x90, 0x55, 0x73, 0x53, 0xfd, 0x0d, 0xc0, 0x26, 0x3a, 0x30, 0xae, 0x51, 0x04, 0xad, + 0x69, 0x7f, 0xd1, 0x98, 0x91, 0xe0, 0x6e, 0x36, 0x91, 0xc6, 0xa3, 0xa6, 0x9d, 0xac, 0x13, 0xeb, + 0xdc, 0x20, 0x4b, 0x94, 0xea, 0x94, 0x5a, 0xdf, 0xc0, 0xad, 0xb7, 0xb0, 0xa9, 0xa4, 0xf7, 0x01, + 0xa3, 0xf3, 0x96, 0x85, 0x38, 0xc9, 0xcb, 0x55, 0xa6, 0xef, 0x64, 0x8e, 0xeb, 0xe5, 0x97, 0x2c, + 0x59, 0xd3, 0xf2, 0x01, 0x68, 0x59, 0x49, 0x1e, 0x11, 0x46, 0xd6, 0x1a, 0x2f, 0x7c, 0x25, 0x6e, + 0x61, 0x53, 0x15, 0x37, 0x1a, 0x17, 0x00, 0xfe, 0x71, 0xc7, 0x00, 0x16, 0xf1, 0xe7, 0xb8, 0x31, + 0xdd, 0xba, 0xc1, 0x02, 0x40, 0x1a, 0x3f, 0x33, 0xfe, 0xb9, 0xcc, 0x9f, 0x5c, 0x56, 0xdd, 0x0d, + 0xc0, 0x0a, 0x51, 0x00, 0x82, 0x7c, 0x98, 0xc1, 0x28, 0x22, 0xbf, 0x62, 0xd0, 0x1f, 0xf4, 0x26, + 0x45, 0xdc, 0xcb, 0x00, 0xa0, 0xc5, 0xcf, 0x64, 0xc6, 0xa9, 0x5c, 0xa3, 0xd2, 0x63, 0xc9, 0xdd, + 0x3a, 0x5f, 0x49, 0x8e, 0x76, 0xb5, 0x60, 0xf9, 0xed, 0x88, 0x40, 0xd7, 0xe0, 0x7d, 0x10, 0xf4, + 0x14, 0x14, 0xd0, 0x28, 0x00, 0x7c, 0xb9, 0x56, 0xf9, 0x9c, 0x16, 0xb6, 0xd0, 0xaa, 0xef, 0xc3, + 0x88, 0xfb, 0xea, 0xdd, 0x25, 0x52, 0x70, 0x43, 0x9c, 0xb0, 0x82, 0xb0, 0x14, 0x21, 0x94, 0x62, + 0x09, 0x4d, 0x80, 0x40, 0xed, 0x16, 0xbe, 0x70, 0x71, 0xd6, 0x83, 0x81, 0xd2, 0x5b, 0x98, 0x03, + 0x02, 0xb0, 0x41, 0x04, 0xd1, 0x76, 0x01, 0x13, 0xd2, 0x18, 0xba, 0x44, 0xe4, 0x4f, 0x09, 0x07, + 0x78, 0x9f, 0xa6, 0x49, 0xe2, 0x06, 0x30, 0xc0, 0x2f, 0x1b, 0x84, 0x70, 0xfd, 0x6a, 0x80, 0xbb, + 0xb4, 0x7d, 0x70, 0xec, 0x53, 0xf4, 0x18, 0x04, 0x8d, 0x48, 0x64, 0x77, 0x8b, 0xda, 0x37, 0x5f, + 0x10, 0x98, 0xa9, 0x1e, 0x0e, 0x1d, 0xf5, 0x3f, 0x1e, 0xbf, 0x14, 0x2a, 0xef, 0xc1, 0x26, 0xc1, + 0xfd, 0xa2, 0x94, 0x8f, 0xd6, 0x11, 0x10, 0x3e, 0xc9, 0x72, 0x26, 0xd7, 0xa8, 0x41, 0x5e, 0x77, + 0xe0, 0x40, 0x30, 0x6e, 0x47, 0x9d, 0x80, 0x60, 0x54, 0x1c, 0x2c, 0x1e, 0xed, 0x64, 0x1a, 0xb5, + 0x10, 0x43, 0xde, 0xe3, 0x0c, 0x29, 0xc3, 0x86, 0x01, 0xbc, 0x46, 0x3b, 0x5f, 0xed, 0x9c, 0x38, + 0xf3, 0x2f, 0x24, 0x61, 0xc3, 0xbd, 0xd1, 0x33, 0x38, 0x16, 0x76, 0xfa, 0xb9, 0x94, 0xe4, 0xe4, + 0x8e, 0x0f, 0x9c, 0xb6, 0x29, 0x13, 0x21, 0xf3, 0xca, 0x4c, 0xda, 0xef, 0x2f, 0xdb, 0xe2, 0x70, + 0x40, 0x4c, 0x32, 0x4b, 0x13, 0xc6, 0x07, 0x23, 0x5b, 0x7a, 0xed, 0xe2, 0x16, 0x9f, 0x3b, 0x76, + 0x8a, 0x53, 0x51, 0x1a, 0x73, 0xe7, 0xca, 0x1b, 0x43, 0xb3, 0x95, 0x4e, 0x7e, 0x7c, 0x1e, 0x7b, + 0x91, 0x08, 0x7d, 0x25, 0x1e, 0x8f, 0x85, 0x71, 0xa3, 0x67, 0xdc, 0x20, 0x1e, 0x1e, 0x1d, 0xb3, + 0x92, 0x07, 0x1e, 0xbb, 0x35, 0x14, 0xd1, 0x29, 0x49, 0x52, 0x3d, 0xcc, 0x24, 0x9e, 0x1a, 0x3d, + 0x2b, 0x14, 0x0e, 0x48, 0xe1, 0x6c, 0x63, 0x2c, 0x0c, 0x20, 0x10, 0x33, 0x66, 0x78, 0x45, 0x4a, + 0x9c, 0xd8, 0x58, 0xc0, 0xa4, 0x9e, 0x65, 0x22, 0xf1, 0x13, 0xd4, 0x7b, 0x33, 0x16, 0x06, 0xc0, + 0x07, 0x84, 0x12, 0x25, 0x83, 0x15, 0xfd, 0x79, 0x7a, 0x1c, 0xb8, 0xe0, 0xc6, 0x50, 0xa0, 0x46, + 0xcb, 0x8f, 0x93, 0x07, 0xab, 0x39, 0xd2, 0xf4, 0x1b, 0x93, 0x23, 0x36, 0x14, 0x37, 0xa3, 0x67, + 0xa1, 0xef, 0x80, 0xfe, 0x8e, 0xfe, 0x16, 0x52, 0x6e, 0x6c, 0xd6, 0xb0, 0x6e, 0x62, 0xf1, 0x1e, + 0xe0, 0x9b, 0x3b, 0x78, 0x4f, 0x8e, 0x9e, 0xc9, 0x5d, 0x37, 0x63, 0x61, 0x50, 0xe4, 0xe4, 0x74, + 0x0e, 0x06, 0x8c, 0xb4, 0x10, 0x88, 0xa1, 0x0b, 0x51, 0xc8, 0x1f, 0x20, 0x70, 0x2e, 0xb6, 0xa1, + 0x91, 0xdb, 0x30, 0x4e, 0xa9, 0x44, 0x9a, 0x23, 0xf2, 0x42, 0x04, 0x46, 0xc9, 0x92, 0xbb, 0x12, + 0x73, 0xd3, 0x96, 0x46, 0x6f, 0xc5, 0x55, 0xd9, 0x7f, 0x13, 0xc1, 0x4b, 0x60, 0x05, 0xd8, 0x7e, + 0x09, 0xdd, 0xf1, 0xc4, 0xe8, 0xd9, 0xdd, 0xb1, 0x30, 0x38, 0x90, 0xaf, 0x84, 0x41, 0x88, 0x51, + 0x02, 0xf4, 0x42, 0x88, 0xdc, 0x8e, 0x85, 0x41, 0x28, 0xd1, 0x0c, 0x5e, 0x80, 0x4a, 0xf4, 0x37, + 0x1e, 0x0e, 0xc7, 0x03, 0xc1, 0x7b, 0x34, 0x06, 0xe8, 0x07, 0xe4, 0xb4, 0x16, 0xe9, 0x93, 0xd0, + 0xc8, 0xdd, 0xf1, 0x36, 0xd0, 0x8c, 0x1b, 0xde, 0xb8, 0x1d, 0xa1, 0x13, 0xa8, 0x41, 0x33, 0x25, + 0x22, 0xa1, 0xb5, 0xb6, 0x7e, 0xa9, 0xe2, 0x16, 0xf4, 0xb7, 0x73, 0xfa, 0xda, 0xd4, 0xa6, 0x36, + 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, + 0xff, 0x1b, 0x09, 0xfe, 0xd3, 0xc7, 0xfd, 0x41, 0x78, 0x3a, 0x62, 0xd4, 0x48, 0x99, 0x7c, 0x51, + 0x9d, 0xd5, 0xf4, 0x32, 0x81, 0xf7, 0xcb, 0x86, 0x8e, 0x4e, 0x75, 0xc6, 0xcd, 0x8c, 0x39, 0xdc, + 0x02, 0x85, 0x66, 0x8b, 0xf6, 0x1c, 0x17, 0xe4, 0x4b, 0x8c, 0x57, 0x6e, 0x0f, 0xa1, 0x26, 0xd5, + 0xbe, 0xb3, 0xb6, 0x1e, 0x97, 0x66, 0xed, 0x68, 0xa7, 0xfa, 0x2b, 0xda, 0x5b, 0x0d, 0x49, 0x08, + 0xea, 0xea, 0x04, 0xb6, 0xd8, 0xca, 0xe2, 0x3c, 0xb1, 0x63, 0x9a, 0xa0, 0xce, 0xf7, 0x9c, 0xb5, + 0xd4, 0xa6, 0xe8, 0x47, 0x66, 0xba, 0x2c, 0x2f, 0xf4, 0x9e, 0x39, 0x42, 0x97, 0x6f, 0xba, 0xed, + 0x59, 0x5d, 0x21, 0x35, 0x15, 0xd6, 0x51, 0xe5, 0x29, 0x0b, 0x6e, 0x50, 0x31, 0xc4, 0x28, 0x75, + 0x16, 0xae, 0x70, 0xbf, 0x70, 0x7d, 0x8a, 0xf9, 0x74, 0xa9, 0x7b, 0x49, 0x13, 0x70, 0x77, 0x5c, + 0x47, 0x55, 0xb7, 0x4e, 0x5b, 0x4f, 0x8f, 0x40, 0x2c, 0xb8, 0xe9, 0xe9, 0xff, 0xea, 0x95, 0x1a, + 0x17, 0xae, 0xf2, 0xc2, 0xff, 0x46, 0xf3, 0x3d, 0x3e, 0x38, 0xc9, 0x78, 0xf6, 0x53, 0xcd, 0xfb, + 0xa3, 0xb3, 0x75, 0x3a, 0xbb, 0xf7, 0x4f, 0x61, 0xe2, 0x0f, 0xb7, 0xc9, 0x8e, 0x6e, 0xec, 0x32, + 0xef, 0x2e, 0x62, 0xdd, 0xe1, 0x4c, 0x6d, 0x23, 0x35, 0x85, 0x1b, 0x87, 0x77, 0x99, 0xd1, 0xc6, + 0x94, 0xc4, 0x98, 0x32, 0x9c, 0xb9, 0xa0, 0xce, 0x1c, 0x4b, 0xb5, 0x8d, 0x00, 0xee, 0x9b, 0x67, + 0x07, 0x4e, 0x3e, 0x07, 0xbb, 0x0a, 0xd3, 0x4b, 0x1e, 0x6f, 0xdc, 0xbc, 0xf8, 0x74, 0x02, 0x82, + 0x54, 0xe6, 0xca, 0x75, 0xc9, 0x65, 0x74, 0x47, 0x9f, 0xd1, 0x6e, 0xc5, 0xb0, 0x40, 0x7c, 0xda, + 0xd3, 0xaa, 0xbb, 0xde, 0x5c, 0xfd, 0x9d, 0x93, 0x68, 0xcc, 0xbe, 0x88, 0x8b, 0x42, 0xa8, 0xf7, + 0xbb, 0x13, 0x98, 0x3a, 0x83, 0x33, 0xf9, 0x5c, 0x63, 0x86, 0x8b, 0x86, 0x29, 0xa2, 0xb6, 0x1a, + 0xe2, 0x24, 0x78, 0x7c, 0x98, 0x07, 0x11, 0x17, 0x4d, 0xaf, 0x7a, 0x07, 0x9e, 0x68, 0xdb, 0x27, + 0xc1, 0xbe, 0x33, 0x75, 0x31, 0xb7, 0xd9, 0x82, 0xe5, 0x1a, 0x6e, 0x4a, 0x22, 0x37, 0x8f, 0x00, + 0xff, 0xd7, 0x34, 0x97, 0x85, 0x03, 0x6e, 0x18, 0xf2, 0xe7, 0xf8, 0x2c, 0x29, 0xc3, 0xf8, 0xf1, + 0xd1, 0x85, 0xe7, 0xf1, 0xfe, 0x19, 0x73, 0xea, 0xb0, 0xf8, 0xd4, 0x94, 0xc4, 0x92, 0x5a, 0xd6, + 0x9c, 0xc4, 0x98, 0xc6, 0xa3, 0xfc, 0xa4, 0x05, 0xcf, 0xca, 0x59, 0x09, 0x6a, 0x78, 0x31, 0x30, + 0x8a, 0xfd, 0x33, 0xd2, 0xe3, 0x4b, 0x5c, 0xb7, 0xc0, 0x0c, 0xa9, 0x2a, 0x15, 0x54, 0xd0, 0x35, + 0x6c, 0x4f, 0x6d, 0xf5, 0x80, 0x67, 0x60, 0xfc, 0x24, 0x69, 0x74, 0xaf, 0xb3, 0xd6, 0xaf, 0xb0, + 0xfb, 0xf3, 0x87, 0xeb, 0x83, 0x5b, 0xda, 0xb7, 0xf1, 0xb5, 0xdb, 0x16, 0x46, 0xf5, 0x60, 0xa2, + 0x31, 0x25, 0x31, 0x38, 0x26, 0x6b, 0xce, 0x87, 0x20, 0x8d, 0x11, 0xd3, 0x0e, 0xf9, 0x15, 0x83, + 0xf3, 0x0b, 0xbc, 0x82, 0x80, 0x89, 0xe5, 0x0d, 0x23, 0xfe, 0x9b, 0x69, 0x8f, 0xe3, 0xfa, 0x14, + 0x41, 0x94, 0xe0, 0x94, 0xc4, 0x52, 0xf1, 0x66, 0x4a, 0x22, 0x4e, 0x1e, 0xef, 0x90, 0x97, 0x3a, + 0x3b, 0x6b, 0x4d, 0x17, 0x85, 0x01, 0x92, 0xed, 0x60, 0xfa, 0x1e, 0x4e, 0x49, 0x04, 0x2d, 0x88, + 0x92, 0xd4, 0x97, 0xfe, 0xb9, 0x31, 0x25, 0xd1, 0x9f, 0x30, 0xb1, 0xc4, 0x84, 0xc1, 0x68, 0x82, + 0xf3, 0xa4, 0x43, 0x86, 0xf9, 0xdc, 0x3a, 0xe2, 0xfa, 0x8d, 0x78, 0x30, 0x89, 0x31, 0x42, 0x94, + 0x14, 0x96, 0x34, 0x31, 0x3d, 0x89, 0xfe, 0x9f, 0x99, 0xd4, 0xa5, 0xd0, 0xf2, 0x5a, 0x7c, 0xcf, + 0xeb, 0x89, 0x0b, 0xae, 0x8e, 0xe6, 0x4c, 0x1f, 0xf9, 0xf8, 0x82, 0x9a, 0x07, 0x7e, 0xe9, 0xba, + 0xed, 0x70, 0x7e, 0x02, 0x72, 0x52, 0xf3, 0x62, 0xea, 0x83, 0x1f, 0xd0, 0x28, 0xa0, 0xed, 0xcc, + 0x56, 0xc5, 0x08, 0x14, 0x1d, 0x1f, 0x2d, 0x42, 0xe5, 0x07, 0xbf, 0x96, 0x47, 0x63, 0x62, 0xc6, + 0x02, 0x37, 0x4b, 0x17, 0x9c, 0x82, 0x51, 0xe7, 0xcc, 0x10, 0x9c, 0xa8, 0x9b, 0xc5, 0x75, 0xaa, + 0x29, 0x38, 0x1b, 0xd0, 0x5e, 0xc1, 0x46, 0xce, 0x19, 0x5c, 0xc1, 0xb0, 0x84, 0xc1, 0x54, 0x64, + 0x8a, 0xc5, 0x54, 0x6c, 0x8d, 0x5e, 0xd6, 0xe5, 0x83, 0xd8, 0x97, 0xbc, 0x77, 0x6b, 0x32, 0x54, + 0x7c, 0xd3, 0x1d, 0xe6, 0x7a, 0xb5, 0x98, 0xf3, 0xee, 0x4c, 0x7e, 0xbf, 0x7f, 0x2b, 0x28, 0x21, + 0x6d, 0xcc, 0x26, 0x72, 0x79, 0x95, 0xe7, 0x94, 0x65, 0xcc, 0xe4, 0x5d, 0x98, 0xcc, 0x05, 0x37, + 0x0b, 0x30, 0xd9, 0xd2, 0xed, 0x3a, 0xca, 0xef, 0x9e, 0x96, 0xd4, 0xc6, 0x2b, 0xc7, 0xa7, 0xab, + 0xbc, 0xb8, 0x6a, 0xc4, 0x46, 0xce, 0x8a, 0x27, 0x7f, 0xbc, 0xd9, 0xa5, 0x97, 0x13, 0x95, 0xda, + 0x31, 0x19, 0xf0, 0xf2, 0xf5, 0xd3, 0x64, 0x79, 0xbd, 0xe4, 0x22, 0x34, 0x4a, 0xe9, 0xc5, 0xfc, + 0xea, 0x91, 0xfd, 0xfd, 0x1f, 0x6f, 0xc6, 0xf6, 0x2f, 0xae, 0x36, 0x94, 0x73, 0x4e, 0xd7, 0x77, + 0x72, 0x4f, 0xbb, 0x5a, 0xb0, 0x5c, 0xa7, 0x89, 0x19, 0x32, 0xb1, 0xe4, 0x7e, 0x28, 0x8f, 0x05, + 0x2d, 0x9a, 0x8f, 0xb4, 0xc3, 0x1d, 0xfa, 0xea, 0x4b, 0x87, 0xf6, 0x12, 0x02, 0xb5, 0x5c, 0xf7, + 0x91, 0x32, 0x4e, 0x87, 0x70, 0x2f, 0xdf, 0xfc, 0xa0, 0xfa, 0x84, 0xab, 0x43, 0x2b, 0x9f, 0x95, + 0xb9, 0x78, 0x2a, 0x57, 0xf6, 0x7d, 0x56, 0x15, 0x4e, 0xd1, 0x7c, 0xdc, 0x61, 0x5c, 0x30, 0x1d, + 0xed, 0x71, 0x67, 0xa7, 0x03, 0x81, 0xf2, 0x90, 0x02, 0xd5, 0x0f, 0xc8, 0x17, 0x23, 0x3c, 0xbe, + 0xc8, 0x1f, 0x00, 0xe6, 0x62, 0x1a, 0xe3, 0x09, 0x65, 0x07, 0xb9, 0x8a, 0x92, 0x2b, 0x8b, 0x24, + 0xf2, 0xa3, 0x51, 0xdf, 0xfa, 0x12, 0x9d, 0x53, 0xdc, 0xe4, 0x60, 0xc4, 0x45, 0xf3, 0x1e, 0x60, + 0x1a, 0x9a, 0xbc, 0xe3, 0x9b, 0x5c, 0xf5, 0x89, 0x02, 0xc1, 0x94, 0xd0, 0x35, 0xa5, 0xd4, 0xd5, + 0x31, 0x22, 0x36, 0xbb, 0x3b, 0xba, 0xf6, 0xdd, 0xef, 0x6a, 0x5e, 0x35, 0x63, 0xce, 0xf3, 0xce, + 0xf7, 0x5c, 0x13, 0xec, 0x73, 0x98, 0x58, 0x29, 0x66, 0xaa, 0x0c, 0xb4, 0x46, 0x6b, 0xc3, 0x9c, + 0xa3, 0xe8, 0x9b, 0x39, 0x85, 0x26, 0xd8, 0x49, 0xb0, 0xe2, 0x49, 0x17, 0xae, 0xed, 0x1b, 0x04, + 0x16, 0x19, 0xb6, 0x10, 0x36, 0x7d, 0x09, 0x73, 0x7e, 0x24, 0x76, 0xf8, 0x9d, 0xf8, 0xd8, 0xd4, + 0x27, 0x94, 0x0f, 0x76, 0x6b, 0x47, 0x85, 0x1f, 0x32, 0xd0, 0x73, 0xdf, 0xcb, 0xb0, 0x16, 0xb6, + 0x60, 0xf9, 0xc8, 0x98, 0x94, 0xa9, 0x6d, 0xac, 0x4f, 0x2d, 0xcb, 0x69, 0xc2, 0x6d, 0xd0, 0x25, + 0xcf, 0xa1, 0x18, 0x8a, 0xed, 0x19, 0xe7, 0x26, 0x5f, 0x36, 0xb3, 0x48, 0x1d, 0xed, 0x4d, 0xa3, + 0xfc, 0x3e, 0x75, 0x26, 0x0f, 0x85, 0x85, 0xa0, 0x8e, 0xcd, 0x2b, 0x78, 0xc7, 0x8f, 0x79, 0x90, + 0x93, 0x5a, 0x4c, 0xc0, 0x10, 0xd8, 0x48, 0x33, 0x9d, 0xf4, 0xa4, 0x76, 0x93, 0x58, 0xda, 0xdc, + 0xc0, 0x6c, 0xae, 0x58, 0xb7, 0x03, 0x4e, 0x6f, 0xdf, 0xca, 0xd4, 0xd8, 0x17, 0xa0, 0x45, 0x12, + 0x5e, 0x07, 0x54, 0xc2, 0xa8, 0xcb, 0x43, 0xe7, 0x99, 0x57, 0x56, 0x0d, 0xcb, 0xda, 0xaa, 0x23, + 0xab, 0x63, 0x1d, 0x15, 0x43, 0x2a, 0xa1, 0x24, 0x96, 0xe9, 0x42, 0xaa, 0x8a, 0x03, 0xf9, 0x24, + 0xf0, 0x85, 0xe2, 0x2f, 0xe1, 0x93, 0xcb, 0x37, 0x82, 0xfd, 0x53, 0x37, 0x50, 0x84, 0x93, 0x3a, + 0xd8, 0x9c, 0x1a, 0x47, 0x8e, 0x55, 0x8b, 0x11, 0xef, 0x8e, 0xfd, 0x5b, 0x1e, 0xe7, 0xfa, 0x62, + 0x6a, 0xe6, 0x78, 0xe7, 0x9f, 0x98, 0x60, 0x47, 0x74, 0xf5, 0x81, 0x2f, 0x0f, 0x3e, 0xdc, 0xe2, + 0x8a, 0x97, 0xaf, 0x72, 0xa2, 0x3e, 0x91, 0xea, 0xba, 0xf7, 0xf1, 0x90, 0xff, 0x88, 0x30, 0xaa, + 0x65, 0xb4, 0x56, 0x24, 0x47, 0x73, 0x47, 0x23, 0x92, 0x99, 0xef, 0xb0, 0xbc, 0xd2, 0xdf, 0x82, + 0xe5, 0x63, 0xc9, 0xea, 0xb4, 0x97, 0xc7, 0x0f, 0x7d, 0xc9, 0x07, 0x9f, 0x4f, 0x1e, 0xe4, 0xba, + 0x76, 0x80, 0xa6, 0x36, 0x52, 0xf3, 0xe2, 0x2a, 0xa7, 0x97, 0x27, 0x9a, 0x6e, 0xcc, 0xce, 0xf2, + 0xb2, 0x5e, 0x38, 0xa5, 0x7e, 0xc0, 0xfc, 0x9f, 0xe1, 0xb1, 0x79, 0x05, 0x4e, 0x78, 0xff, 0xfd, + 0xec, 0xb5, 0x46, 0xf1, 0x36, 0x1f, 0x0c, 0x9c, 0x7e, 0x2b, 0x4d, 0x28, 0xf7, 0x17, 0x51, 0x2f, + 0x6f, 0x7a, 0xd1, 0xf5, 0xc4, 0xbb, 0xba, 0x94, 0x4a, 0x02, 0xa6, 0x34, 0xa9, 0x16, 0x31, 0xd0, + 0xa1, 0xfb, 0x67, 0x55, 0x37, 0x33, 0xcf, 0xee, 0x6f, 0x54, 0x4c, 0x63, 0x76, 0x16, 0xae, 0x7b, + 0xfe, 0x0e, 0xec, 0x0e, 0x56, 0x27, 0xf3, 0x22, 0x3b, 0x4b, 0x47, 0x81, 0x44, 0x27, 0x12, 0x45, + 0x91, 0x84, 0x64, 0x36, 0x27, 0xe9, 0x0c, 0xbc, 0x04, 0xc5, 0x7b, 0x8f, 0x1b, 0xcd, 0x96, 0xc0, + 0x46, 0x06, 0x15, 0x55, 0x2e, 0x43, 0x3b, 0x79, 0x44, 0x78, 0x41, 0x2d, 0x20, 0xae, 0x33, 0xf9, + 0xf9, 0xe6, 0xff, 0xdc, 0x3a, 0x02, 0xf4, 0x77, 0xe6, 0xd1, 0x09, 0x5a, 0xb0, 0xbc, 0xe7, 0x9e, + 0xc1, 0x28, 0x5b, 0xb8, 0x5f, 0x0a, 0xca, 0xef, 0x84, 0x10, 0x69, 0x48, 0xc7, 0x69, 0xef, 0xe0, + 0x9e, 0xa4, 0x81, 0x4d, 0x7a, 0x1b, 0xb3, 0x1b, 0xe5, 0xc4, 0xe2, 0x1a, 0xb7, 0x7b, 0x75, 0x02, + 0xf0, 0x9f, 0x48, 0x5a, 0x37, 0x74, 0xec, 0xcd, 0x7e, 0xce, 0xf3, 0x8e, 0xcd, 0xce, 0x0a, 0x75, + 0x24, 0x3a, 0xa8, 0x25, 0xa1, 0x9a, 0xe0, 0x40, 0x85, 0x7f, 0x0c, 0x54, 0xb1, 0x01, 0x8a, 0x42, + 0xaa, 0xe1, 0xca, 0x02, 0xa7, 0x12, 0x31, 0xe0, 0x0c, 0x74, 0x31, 0x5b, 0x38, 0x3b, 0xd7, 0x80, + 0x52, 0x6b, 0xd4, 0x69, 0x5a, 0x53, 0x05, 0x42, 0x5f, 0xee, 0xa5, 0xea, 0x6c, 0xfa, 0x8c, 0xa8, + 0xb3, 0x6c, 0x1a, 0xfe, 0xba, 0x8c, 0xd6, 0x0d, 0x45, 0x2a, 0x0a, 0x76, 0x35, 0xfb, 0xd5, 0xab, + 0x8d, 0x7a, 0xb5, 0xa2, 0x99, 0x70, 0xb0, 0xbe, 0x63, 0x5f, 0x21, 0xc5, 0xad, 0x4d, 0x41, 0xeb, + 0x4a, 0x60, 0xf3, 0x71, 0x68, 0x67, 0xa7, 0x54, 0x12, 0xf6, 0xee, 0x57, 0x1c, 0xe7, 0x6b, 0x74, + 0x68, 0x2e, 0xd6, 0x35, 0xe9, 0x5b, 0xf5, 0x6e, 0x21, 0x8b, 0x34, 0x2a, 0x84, 0xcc, 0xbf, 0xb1, + 0xa1, 0x02, 0x11, 0xf7, 0x19, 0x66, 0xdf, 0x5e, 0x97, 0x1e, 0x9a, 0x24, 0xe8, 0xe3, 0xcd, 0xe9, + 0xd1, 0x24, 0x01, 0x0c, 0xcb, 0x77, 0x6c, 0x79, 0x4f, 0x6f, 0x0b, 0x96, 0x4f, 0x88, 0x01, 0x1c, + 0xdc, 0x60, 0xa7, 0x96, 0x23, 0x05, 0x96, 0x31, 0x52, 0x43, 0x4a, 0x9a, 0x72, 0xeb, 0x53, 0x53, + 0xcb, 0xa6, 0xa2, 0x92, 0xa1, 0xf0, 0xa2, 0x20, 0x5c, 0x5b, 0x36, 0x80, 0x5f, 0xee, 0x22, 0x00, + 0x95, 0xee, 0xd7, 0xc9, 0xf8, 0x49, 0xf1, 0x75, 0x6a, 0x67, 0x48, 0x77, 0xc4, 0x31, 0x7f, 0x37, + 0xbe, 0x98, 0xe7, 0x4c, 0xa7, 0x57, 0x74, 0xa7, 0x97, 0xf7, 0xd8, 0x26, 0x3f, 0xd6, 0x69, 0xbb, + 0x1a, 0x36, 0x85, 0x3a, 0x67, 0xbd, 0x5c, 0xb3, 0xc2, 0x63, 0x51, 0x6a, 0xf8, 0x6e, 0x98, 0x51, + 0xd0, 0xdd, 0xab, 0x19, 0x4f, 0xdb, 0x04, 0x16, 0xc4, 0xd2, 0x27, 0x4c, 0x99, 0x17, 0x23, 0xd6, + 0x34, 0x79, 0x4c, 0x3c, 0x95, 0x80, 0x7a, 0xc5, 0xe6, 0x2c, 0x46, 0x85, 0x0c, 0xe0, 0x44, 0xb1, + 0x64, 0xe1, 0x1f, 0xde, 0x78, 0xc8, 0xe7, 0x47, 0x27, 0x99, 0x02, 0x51, 0xec, 0x1e, 0x74, 0x7d, + 0x7c, 0x1d, 0x97, 0x4f, 0xd6, 0x12, 0xca, 0xad, 0xac, 0xa1, 0xe3, 0xdc, 0x61, 0x38, 0x4e, 0xd6, + 0xa2, 0xea, 0x0c, 0x95, 0x20, 0x2b, 0x8b, 0x5e, 0xc9, 0xe0, 0xb2, 0xca, 0x7b, 0x75, 0xe2, 0x72, + 0xc5, 0x10, 0xdf, 0x22, 0x70, 0x9f, 0x6a, 0x10, 0x3a, 0x88, 0x54, 0x4b, 0x39, 0xaa, 0xe9, 0x89, + 0x9c, 0x35, 0x6e, 0x76, 0x74, 0x97, 0xd8, 0x91, 0x71, 0xfe, 0x29, 0x14, 0x5f, 0xee, 0xf9, 0xce, + 0x9c, 0x68, 0x65, 0x0b, 0x96, 0x5f, 0x27, 0x54, 0xd1, 0x1d, 0x42, 0x9f, 0x73, 0x46, 0x30, 0x50, + 0xd8, 0x0b, 0xe5, 0x44, 0xaa, 0xfd, 0x86, 0x2e, 0x6a, 0x7a, 0x39, 0xef, 0x22, 0x71, 0x2d, 0x71, + 0x0f, 0x59, 0x7b, 0x4d, 0xc3, 0xb8, 0xa0, 0x4f, 0x7d, 0x7a, 0x37, 0x4c, 0x10, 0x49, 0xb8, 0xa8, + 0xe1, 0x4f, 0x05, 0xb7, 0x69, 0x03, 0xfe, 0x4d, 0xa1, 0xe7, 0x32, 0x97, 0xb2, 0x0b, 0xbd, 0x9c, + 0x80, 0xc3, 0xf8, 0x01, 0x84, 0x3f, 0x25, 0xcf, 0x61, 0x0a, 0x48, 0x3e, 0x80, 0x3c, 0x66, 0x70, + 0x76, 0xca, 0xe8, 0x29, 0xbe, 0x68, 0x2e, 0x62, 0x70, 0x11, 0x13, 0x6f, 0x07, 0x3b, 0x37, 0x4f, + 0x3f, 0x67, 0xa2, 0xda, 0xf2, 0x07, 0xa0, 0xa3, 0x3e, 0x09, 0x10, 0x70, 0xfe, 0xa7, 0x66, 0x34, + 0x00, 0xec, 0xa5, 0x93, 0x10, 0x0e, 0x48, 0x5c, 0xbc, 0x7e, 0xb8, 0x40, 0x45, 0x57, 0x5c, 0x02, + 0x0b, 0x5a, 0x99, 0xff, 0x24, 0x7f, 0xa1, 0x52, 0xb2, 0x0c, 0xd2, 0xda, 0x46, 0x4e, 0x5d, 0xf3, + 0xe2, 0x95, 0xef, 0xd8, 0x72, 0x42, 0xd3, 0x82, 0xe5, 0x0a, 0x88, 0x8e, 0x7d, 0xdb, 0x69, 0x4c, + 0xef, 0x65, 0x58, 0xbc, 0x10, 0xdd, 0xb1, 0xb8, 0xf9, 0x51, 0xd3, 0x3b, 0xf7, 0x33, 0xe4, 0x66, + 0x19, 0x11, 0xb8, 0x54, 0xc9, 0x21, 0xb7, 0x54, 0x49, 0x8d, 0x08, 0x2c, 0xc8, 0x57, 0x85, 0xb3, + 0xda, 0x8f, 0xba, 0x17, 0xbe, 0x04, 0x5c, 0x78, 0x64, 0xbe, 0x08, 0x71, 0xda, 0x17, 0x36, 0x60, + 0x58, 0x4c, 0x08, 0xb7, 0x6e, 0x96, 0x11, 0x89, 0xc3, 0x85, 0x47, 0x08, 0x0c, 0xa6, 0xf8, 0x0c, + 0x8d, 0xc1, 0xa5, 0x4a, 0x66, 0xfe, 0x19, 0xc7, 0x8c, 0x6a, 0x55, 0x85, 0x4a, 0x53, 0xeb, 0xc7, + 0xbb, 0x46, 0x3c, 0x3a, 0x66, 0xba, 0xdf, 0xa2, 0xb1, 0xf0, 0x08, 0x68, 0x41, 0x52, 0xa5, 0xc9, + 0xf5, 0x34, 0xa1, 0x97, 0x76, 0xd0, 0x16, 0x8d, 0x82, 0xae, 0xe8, 0x8b, 0xc6, 0x05, 0x44, 0x14, + 0xa2, 0x0c, 0x82, 0x6d, 0xf5, 0xfc, 0xe1, 0xda, 0xf5, 0xc4, 0x6d, 0x7f, 0x09, 0xe0, 0xf8, 0x48, + 0xcf, 0xf6, 0xb8, 0x5a, 0xce, 0x50, 0x41, 0x03, 0x5b, 0x01, 0x58, 0x9c, 0x28, 0x39, 0x86, 0xe4, + 0xa8, 0x57, 0x8f, 0x8d, 0xa2, 0xa5, 0x2d, 0xf2, 0x00, 0xe5, 0xb3, 0x46, 0xd0, 0xe2, 0xc1, 0x52, + 0x25, 0x6c, 0x73, 0xa9, 0x12, 0x10, 0x85, 0x14, 0x12, 0x74, 0xc5, 0xc1, 0x2d, 0x55, 0x52, 0x93, + 0xd7, 0xf9, 0x71, 0x72, 0xc2, 0xe8, 0x85, 0x01, 0x08, 0x1e, 0xb8, 0x6e, 0xc1, 0xbe, 0xda, 0x29, + 0x35, 0x96, 0x2a, 0xe9, 0x09, 0x70, 0x51, 0x48, 0x73, 0xa9, 0x92, 0x0d, 0x82, 0x26, 0x4b, 0x1b, + 0x47, 0xc7, 0x69, 0xcf, 0x77, 0x2a, 0x95, 0xe4, 0x3a, 0x5a, 0xb0, 0xdc, 0x57, 0xb0, 0x0f, 0x2e, + 0xb2, 0xe2, 0xcc, 0xd8, 0xc2, 0x59, 0xa3, 0x46, 0x62, 0xca, 0xef, 0x41, 0x6f, 0x7c, 0xf4, 0xf5, + 0xe4, 0xe6, 0x26, 0x76, 0xf3, 0x1e, 0x4f, 0x7e, 0xb9, 0xf3, 0xe9, 0x9b, 0xd3, 0x92, 0xe5, 0xb5, + 0x45, 0x4e, 0xca, 0xd5, 0xc9, 0xb8, 0x9b, 0x37, 0x02, 0x80, 0xbd, 0xdd, 0x2b, 0x99, 0xfd, 0x94, + 0xef, 0x24, 0x43, 0x4e, 0x22, 0x36, 0xf0, 0x8e, 0xc6, 0xb5, 0x52, 0xb7, 0xde, 0x19, 0x18, 0x03, + 0xa6, 0xfd, 0xcd, 0xc0, 0x3b, 0x14, 0x7f, 0x1d, 0x97, 0x02, 0x7d, 0xff, 0x11, 0x23, 0xaf, 0x22, + 0x96, 0x6a, 0xa9, 0xd4, 0x3e, 0x67, 0xdf, 0x09, 0x5c, 0x0b, 0xf0, 0xbb, 0x07, 0x20, 0xfe, 0xf1, + 0x46, 0xcc, 0x6f, 0xe8, 0x26, 0x09, 0xfc, 0x75, 0x8a, 0x0e, 0x83, 0xdd, 0xfd, 0x0c, 0xc0, 0x2e, + 0x3b, 0x83, 0x17, 0xc9, 0xf3, 0xa9, 0x65, 0xcf, 0x51, 0xd5, 0x11, 0x36, 0xbe, 0xae, 0x13, 0xc6, + 0x48, 0xe1, 0x2a, 0x10, 0x2c, 0x02, 0x53, 0x79, 0xe9, 0x56, 0x27, 0x03, 0x94, 0xaf, 0x28, 0x80, + 0x68, 0x2d, 0xc9, 0x50, 0x85, 0xd2, 0xb1, 0x9d, 0xc3, 0x38, 0x15, 0xb7, 0x32, 0x2e, 0x05, 0x8e, + 0x7e, 0x6b, 0x72, 0xb1, 0x89, 0x71, 0xae, 0x97, 0x13, 0xba, 0xdf, 0x17, 0xf4, 0x7b, 0x35, 0xac, + 0xb5, 0x2d, 0x58, 0x0e, 0x6e, 0x18, 0x86, 0x0a, 0x79, 0xaa, 0x3b, 0xaa, 0x36, 0x70, 0x5a, 0xc5, + 0x0f, 0x7e, 0x7d, 0x85, 0x6b, 0x8e, 0x2c, 0x73, 0x23, 0x02, 0x86, 0x37, 0x20, 0x2e, 0x19, 0x05, + 0x8a, 0x3b, 0x08, 0x33, 0x74, 0x00, 0x44, 0xeb, 0xde, 0xaf, 0x94, 0x0c, 0x1a, 0xc6, 0x50, 0xa8, + 0x7a, 0x03, 0x08, 0x42, 0x4f, 0xbe, 0x75, 0x9e, 0x65, 0x03, 0xaa, 0xa8, 0xae, 0xc0, 0xec, 0x2c, + 0x7d, 0xe4, 0xf1, 0xa6, 0x43, 0x98, 0xd7, 0x77, 0x2f, 0x50, 0x07, 0x86, 0x3a, 0xe1, 0x35, 0xa5, + 0x23, 0xf6, 0xcf, 0xab, 0xdb, 0x5b, 0x7f, 0xd9, 0xba, 0xb8, 0xb8, 0xb4, 0x31, 0x98, 0x3a, 0xf1, + 0xad, 0xd2, 0x9c, 0x04, 0x8e, 0x2b, 0x4b, 0x1a, 0x80, 0xe2, 0x84, 0x3d, 0xfe, 0x0a, 0xae, 0x4f, + 0x1d, 0x2f, 0x47, 0x00, 0x7a, 0x4c, 0xfb, 0x83, 0xbe, 0xbd, 0xa5, 0x7c, 0xac, 0xfb, 0xf4, 0x00, + 0x00, 0x8e, 0x69, 0x67, 0x8e, 0x17, 0x37, 0xcf, 0x02, 0x64, 0x37, 0xef, 0x74, 0x09, 0x84, 0x77, + 0xb3, 0xb9, 0x50, 0x7e, 0x63, 0xfe, 0x3c, 0xb7, 0x34, 0x8d, 0xca, 0xd5, 0x21, 0xe4, 0xd2, 0x42, + 0xfa, 0xd4, 0x59, 0x95, 0x57, 0xec, 0x70, 0xc2, 0x61, 0x20, 0x57, 0x50, 0x17, 0x78, 0x07, 0x2c, + 0xbd, 0x78, 0xfb, 0xab, 0x73, 0xdb, 0x32, 0xc5, 0xc1, 0xa0, 0x95, 0x4b, 0x44, 0x24, 0x09, 0x41, + 0x18, 0x74, 0x8d, 0x7b, 0x38, 0x5b, 0xab, 0x99, 0xe1, 0x76, 0x7d, 0xdf, 0x29, 0x67, 0x47, 0x8f, + 0x3c, 0xcd, 0xf2, 0x8a, 0x46, 0x24, 0xf9, 0xf2, 0xf8, 0x85, 0xef, 0x49, 0x79, 0xaf, 0x58, 0x4a, + 0xe7, 0x6c, 0x7d, 0x92, 0x6f, 0x78, 0x27, 0xcf, 0x41, 0xd6, 0xa8, 0xa3, 0x5f, 0x43, 0xc9, 0x94, + 0x62, 0x4c, 0xed, 0x0c, 0x48, 0xf6, 0xcc, 0x15, 0x4a, 0xbf, 0xb4, 0xf8, 0x0d, 0x07, 0xf1, 0x53, + 0xee, 0x75, 0x72, 0x3f, 0x6b, 0x50, 0x28, 0xe3, 0x40, 0xd0, 0x94, 0xfb, 0x95, 0x45, 0x5c, 0x83, + 0x1b, 0x8e, 0x8f, 0xea, 0x9f, 0x73, 0x50, 0xf8, 0x8c, 0xd1, 0x6d, 0xa9, 0x1e, 0x7b, 0x59, 0x4f, + 0xd9, 0x9d, 0xa8, 0x90, 0xbf, 0xc7, 0xd4, 0xd6, 0xf6, 0x24, 0x68, 0x07, 0xb0, 0xcc, 0x8b, 0x00, + 0xa1, 0xee, 0xfd, 0x48, 0x70, 0xbb, 0xbc, 0x08, 0x03, 0x59, 0x10, 0xb4, 0xd2, 0xfe, 0x0b, 0xce, + 0xdc, 0x8f, 0x9c, 0x6f, 0x37, 0x53, 0x56, 0x59, 0xc1, 0xed, 0xfa, 0x34, 0x53, 0x43, 0x73, 0xc9, + 0x3b, 0x01, 0x40, 0xf8, 0x74, 0x2e, 0x79, 0xee, 0x68, 0x38, 0x08, 0x1d, 0x90, 0xb8, 0xac, 0x8e, + 0x28, 0xbd, 0x0f, 0x7e, 0x01, 0xbb, 0xb4, 0x52, 0x5e, 0x07, 0x60, 0xe2, 0xec, 0xea, 0x43, 0xa4, + 0xb8, 0xb1, 0x81, 0xd5, 0xdc, 0x87, 0x6b, 0x99, 0x21, 0x5d, 0x91, 0x9c, 0x8a, 0xc2, 0x4d, 0xd8, + 0x0d, 0x10, 0x3f, 0x80, 0xfd, 0xdd, 0xfb, 0x5f, 0x72, 0xf8, 0x8e, 0x6a, 0xe1, 0x3b, 0x20, 0x91, + 0x36, 0xb6, 0x90, 0xf2, 0x87, 0x3a, 0xab, 0x04, 0x61, 0x8a, 0xe1, 0x25, 0xf3, 0xee, 0x52, 0x0b, + 0x04, 0xdc, 0x0d, 0x78, 0x57, 0x72, 0x1b, 0x40, 0x44, 0x01, 0x84, 0x7e, 0xeb, 0xeb, 0xc5, 0x46, + 0x6a, 0x6a, 0xb0, 0xc6, 0x2d, 0x9b, 0x13, 0x53, 0xc2, 0x07, 0xbf, 0x00, 0x27, 0xf2, 0xc1, 0xe2, + 0x39, 0x0c, 0xd0, 0x41, 0xac, 0xd2, 0xcd, 0x9e, 0xa6, 0xb3, 0xcc, 0xb1, 0xdd, 0x97, 0x37, 0xd2, + 0x40, 0x7b, 0x99, 0xad, 0xec, 0x44, 0x45, 0x24, 0x43, 0x51, 0xdf, 0x0e, 0xc0, 0x06, 0xbc, 0x8c, + 0xfa, 0x3f, 0xc7, 0x4f, 0x0f, 0x4f, 0x02, 0xe0, 0x88, 0x50, 0x23, 0x73, 0xd1, 0x83, 0x38, 0x39, + 0x34, 0x17, 0xa3, 0x1c, 0xd9, 0x05, 0x8d, 0x58, 0x72, 0xe1, 0x8f, 0xf0, 0xa6, 0xe7, 0xd1, 0x6e, + 0x5f, 0x63, 0x5c, 0x92, 0x36, 0x34, 0xf2, 0x45, 0xc4, 0x9a, 0x09, 0x7c, 0x64, 0x40, 0x36, 0xb7, + 0x60, 0xe8, 0x66, 0xbe, 0x95, 0x3a, 0x61, 0x2e, 0xaf, 0xf6, 0x52, 0x21, 0xab, 0x18, 0x7d, 0x85, + 0x10, 0x08, 0x92, 0x62, 0x63, 0x6a, 0xe4, 0x7a, 0x90, 0x2c, 0xc8, 0x49, 0x52, 0x03, 0x24, 0xa9, + 0x06, 0xe5, 0x39, 0x9e, 0x4a, 0x9a, 0x42, 0x3b, 0x9f, 0xbf, 0x73, 0xe1, 0xc3, 0x9b, 0xbf, 0x02, + 0x2c, 0xa4, 0x82, 0x11, 0x2e, 0xa7, 0xa3, 0x85, 0x87, 0x83, 0x64, 0x8d, 0x55, 0x06, 0x3c, 0x02, + 0xc3, 0xf8, 0x6c, 0x44, 0xd0, 0x48, 0x7e, 0x6f, 0xb9, 0x5a, 0x46, 0x4f, 0x0b, 0x96, 0x77, 0x89, + 0xcc, 0xeb, 0xde, 0x1e, 0xa5, 0x8c, 0x72, 0x8d, 0x48, 0xb9, 0x5b, 0xc7, 0xe7, 0xcb, 0xfc, 0x23, + 0x87, 0xcb, 0x25, 0x6c, 0xd8, 0x05, 0xf3, 0x67, 0x7c, 0x35, 0x33, 0x78, 0x23, 0x86, 0x66, 0x14, + 0x29, 0x35, 0xd3, 0x44, 0xa6, 0x0f, 0x71, 0xa8, 0x21, 0x9c, 0x19, 0x07, 0x3e, 0x1f, 0x58, 0x3e, + 0x91, 0x0a, 0x29, 0x54, 0x8e, 0x39, 0xaf, 0x3b, 0x73, 0xd2, 0x08, 0xec, 0x74, 0xaf, 0x58, 0xb8, + 0x2e, 0x83, 0x7c, 0xcc, 0xd0, 0xd1, 0xa9, 0x91, 0xc1, 0x5d, 0x8d, 0x40, 0x21, 0x9e, 0xe4, 0x86, + 0x82, 0xb9, 0x81, 0x5d, 0x37, 0xcf, 0x20, 0x36, 0x43, 0x15, 0x36, 0xfb, 0xf2, 0xbc, 0xe6, 0xbb, + 0x82, 0xd8, 0x3c, 0xce, 0x85, 0xef, 0xea, 0xaf, 0x1c, 0x4e, 0xe3, 0xc6, 0x7e, 0x39, 0x1b, 0x00, + 0x5b, 0xfc, 0xd0, 0x00, 0xf0, 0x5c, 0x63, 0x85, 0x24, 0x28, 0xea, 0x87, 0xbb, 0x5b, 0x40, 0x25, + 0xce, 0xec, 0x40, 0x74, 0x94, 0x24, 0xae, 0x2b, 0xa4, 0x18, 0x63, 0xbe, 0xd4, 0x34, 0xae, 0x59, + 0x76, 0x48, 0x49, 0xfa, 0xe1, 0xaf, 0xba, 0x3d, 0x16, 0xf9, 0x40, 0x50, 0x63, 0x08, 0x53, 0xc2, + 0x75, 0xc2, 0xfd, 0xe8, 0x4f, 0x78, 0xd2, 0xea, 0xe8, 0x1c, 0xde, 0xb5, 0xd7, 0xc7, 0x0c, 0xc9, + 0xd3, 0xd4, 0x77, 0x70, 0x39, 0x61, 0x69, 0xc1, 0x72, 0xe1, 0x9f, 0x01, 0x33, 0xae, 0x0b, 0x5f, + 0x6f, 0x7e, 0x81, 0xb8, 0xa4, 0xa9, 0x90, 0x25, 0xe8, 0x02, 0x80, 0xf8, 0x97, 0x1d, 0x70, 0x98, + 0x7a, 0x6a, 0xd9, 0xf0, 0x46, 0xb9, 0x9f, 0x5d, 0x80, 0x1e, 0x0c, 0x3a, 0x83, 0xf2, 0xdc, 0xe1, + 0xda, 0xf1, 0x50, 0x20, 0x45, 0x16, 0x4f, 0x35, 0x43, 0xbf, 0x10, 0x15, 0x4a, 0xa7, 0x26, 0xca, + 0xa6, 0x43, 0x86, 0x31, 0xe2, 0x06, 0x3b, 0x6e, 0xa4, 0x26, 0xd9, 0xc4, 0x32, 0x1c, 0xce, 0x2e, + 0xa6, 0xb2, 0x0e, 0x7c, 0x7c, 0x22, 0xf6, 0x4b, 0x38, 0x03, 0xe2, 0x5f, 0xfb, 0x09, 0x30, 0xca, + 0x70, 0xb8, 0x8a, 0x73, 0x5e, 0xf1, 0x3b, 0x81, 0xec, 0x5f, 0xe6, 0x6c, 0xa5, 0x0b, 0xca, 0x4a, + 0x17, 0x08, 0xd5, 0x49, 0xfc, 0xe7, 0x5f, 0xbf, 0xac, 0x62, 0xf1, 0x82, 0xf3, 0x66, 0xad, 0x93, + 0x50, 0xd3, 0xb9, 0x0c, 0xa8, 0xa0, 0x10, 0xa9, 0x96, 0x30, 0xde, 0x53, 0x63, 0x2c, 0x7d, 0xb2, + 0x60, 0xd2, 0x32, 0x35, 0x48, 0x7f, 0xca, 0xed, 0xc9, 0x5c, 0x5a, 0x9e, 0x40, 0xff, 0x35, 0x28, + 0x3c, 0x4f, 0x21, 0x8b, 0xc0, 0xa4, 0x7a, 0xd4, 0xf4, 0xe5, 0x07, 0x20, 0x1c, 0x63, 0xfb, 0xb5, + 0xf2, 0x44, 0xd0, 0x4e, 0x13, 0xdf, 0x59, 0xf9, 0xc8, 0xd6, 0x82, 0xe5, 0x77, 0x97, 0xcd, 0x01, + 0x10, 0x55, 0xa8, 0x41, 0x68, 0x5a, 0xc9, 0x37, 0x83, 0x80, 0x9f, 0xf7, 0x69, 0xd1, 0x85, 0x8b, + 0xa0, 0x6e, 0x03, 0x89, 0xf6, 0xf2, 0xf4, 0xf3, 0xf3, 0x25, 0x1e, 0xc7, 0x84, 0x5b, 0x4e, 0x08, + 0xa5, 0x0d, 0x1f, 0xe5, 0xbd, 0xd3, 0x5f, 0x2e, 0x38, 0x69, 0x8e, 0x54, 0x39, 0x89, 0x2e, 0x4e, + 0x25, 0x24, 0x37, 0x23, 0xfc, 0xe7, 0x7b, 0x7f, 0x85, 0x6d, 0x17, 0xc9, 0xc6, 0xf2, 0x10, 0x31, + 0xbf, 0x73, 0x1b, 0xb8, 0x3b, 0x4d, 0x2d, 0xf0, 0xce, 0x53, 0xa0, 0x10, 0x87, 0xdf, 0x19, 0x80, + 0x21, 0x03, 0xb0, 0x01, 0xd7, 0x6e, 0xec, 0x47, 0xc7, 0x7b, 0x92, 0x67, 0x53, 0x61, 0x63, 0x6f, + 0x53, 0x9c, 0x4e, 0xe7, 0x52, 0x10, 0x1f, 0x00, 0xc4, 0x9f, 0xa9, 0x6d, 0x24, 0x69, 0x20, 0x49, + 0xc9, 0x29, 0xdc, 0xa8, 0x3d, 0xb3, 0x7f, 0x85, 0x19, 0xd0, 0x61, 0xe3, 0x9b, 0xa9, 0x6c, 0x84, + 0xad, 0x91, 0x5b, 0xf5, 0x51, 0xaa, 0xeb, 0x5f, 0x27, 0x97, 0xba, 0xee, 0xfd, 0xdc, 0xf7, 0xd6, + 0xf7, 0x42, 0x5a, 0xb0, 0x5c, 0x20, 0x0a, 0xc1, 0xd4, 0x7b, 0x83, 0x3f, 0xf7, 0x83, 0xe9, 0xc9, + 0x9c, 0xe4, 0x03, 0xa8, 0x56, 0x71, 0x18, 0x52, 0xd9, 0x35, 0x1c, 0xa0, 0x2e, 0x15, 0x13, 0x5e, + 0x18, 0xa2, 0x08, 0xea, 0x6b, 0xa9, 0x1a, 0x3e, 0x85, 0x03, 0x19, 0x51, 0x76, 0x68, 0x8d, 0x8c, + 0x16, 0x81, 0xce, 0x46, 0x17, 0xb2, 0x14, 0x55, 0x71, 0x0f, 0x25, 0x37, 0xa2, 0xc5, 0x62, 0x8a, + 0xa9, 0x60, 0x86, 0x75, 0xd2, 0x82, 0x1b, 0x06, 0xd3, 0x10, 0x89, 0xec, 0x2c, 0xd5, 0x92, 0x35, + 0x87, 0x85, 0x9a, 0x18, 0xdb, 0xca, 0xea, 0x8e, 0xb7, 0xd7, 0x97, 0x0d, 0xab, 0x71, 0xd1, 0x2d, + 0x02, 0x3a, 0x20, 0x94, 0x13, 0x83, 0xb4, 0x12, 0x9c, 0x05, 0xaa, 0xae, 0xa0, 0x0d, 0xaa, 0xf3, + 0xb5, 0xd3, 0x73, 0x3f, 0x50, 0x89, 0x8b, 0xaf, 0xde, 0x38, 0x32, 0xf7, 0x91, 0x53, 0x8e, 0xce, + 0x5e, 0xf2, 0x26, 0x4a, 0xa5, 0x65, 0x15, 0x4e, 0x97, 0x85, 0x2f, 0x9b, 0x03, 0x37, 0xb8, 0x45, + 0x0e, 0xec, 0x31, 0x26, 0x4e, 0x28, 0x90, 0x3e, 0xbe, 0x1a, 0x48, 0x48, 0x61, 0xa6, 0x58, 0x3a, + 0x3b, 0x93, 0x2c, 0x3d, 0xe4, 0xc1, 0x88, 0x54, 0x8e, 0x8c, 0x14, 0x26, 0x07, 0xa1, 0xfc, 0xa4, + 0x96, 0x3c, 0x44, 0xe9, 0x61, 0x89, 0xc4, 0x85, 0xd6, 0x86, 0x05, 0xd1, 0x7a, 0x5b, 0xb0, 0xbc, + 0xf7, 0xde, 0x58, 0x64, 0xd0, 0xf0, 0xb2, 0x1a, 0xc6, 0xc6, 0x5e, 0x92, 0xfe, 0xcb, 0xe1, 0x4c, + 0xc6, 0x5c, 0xcb, 0x76, 0xbf, 0x5f, 0x7e, 0x9b, 0xc9, 0x64, 0x28, 0xaf, 0x4e, 0xbc, 0xbd, 0x1e, + 0xd1, 0x89, 0xb7, 0xbe, 0x2d, 0x82, 0x57, 0x0a, 0xd5, 0xad, 0x97, 0xf3, 0x9c, 0x7d, 0xe7, 0x62, + 0x17, 0x2c, 0x5d, 0x4d, 0x47, 0x50, 0x1b, 0xd2, 0x35, 0x6d, 0xce, 0x7b, 0x76, 0xec, 0xe1, 0x29, + 0x6a, 0xd7, 0xcc, 0x19, 0xf9, 0xe5, 0xf7, 0x59, 0xb2, 0x32, 0xa7, 0xd4, 0xc0, 0xf5, 0x26, 0xbc, + 0x71, 0x91, 0x1f, 0x5f, 0x3d, 0x8e, 0xb5, 0x73, 0xfa, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, + 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, + 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0xff, 0x1b, 0x09, + 0xfe, 0xd3, 0x37, 0x64, 0x4f, 0x0f, 0xa9, 0x08, 0x4c, 0x5d, 0x09, 0x1a, 0x52, 0x33, 0xfb, 0x3d, + 0x4c, 0xad, 0x6c, 0xc1, 0xdf, 0x04, 0x46, 0x23, 0x41, 0x83, 0x6a, 0xbf, 0x30, 0xfb, 0xff, 0xb6, + 0x77, 0xff, 0x3f, 0x4d, 0xe6, 0x09, 0x02, 0xc7, 0x61, 0xbe, 0x74, 0x76, 0x77, 0x76, 0x3b, 0x97, + 0xdc, 0xe5, 0x6e, 0x6e, 0x7f, 0xda, 0x5c, 0xc2, 0x6c, 0x70, 0x82, 0xde, 0xee, 0x1e, 0x7a, 0x38, + 0x8b, 0x66, 0x76, 0xc6, 0x9b, 0x03, 0x17, 0xdd, 0x20, 0x2d, 0x69, 0x19, 0xe0, 0x97, 0x41, 0x0e, + 0xb0, 0x98, 0xa8, 0xd5, 0x40, 0x07, 0xe6, 0xfe, 0x06, 0x57, 0xf4, 0x66, 0x04, 0x4d, 0x2e, 0xcb, + 0x90, 0x52, 0x1f, 0x48, 0xd0, 0x96, 0x1b, 0xb0, 0xf0, 0xcb, 0xfd, 0x22, 0x44, 0x48, 0xc4, 0x96, + 0x00, 0x63, 0x49, 0x2e, 0x8b, 0x44, 0xb0, 0x36, 0x51, 0x4b, 0x23, 0xc8, 0x78, 0xcf, 0xa7, 0x7c, + 0x6f, 0x9f, 0xa7, 0xa0, 0x95, 0x8f, 0xc2, 0xbc, 0x5f, 0xbb, 0x83, 0x80, 0x50, 0xe1, 0xcd, 0xd3, + 0x0f, 0x4f, 0x9f, 0xe7, 0xf3, 0x79, 0xaa, 0x1c, 0x77, 0x04, 0x22, 0x53, 0xce, 0x4a, 0xbf, 0x38, + 0x5d, 0x3b, 0xe5, 0xbf, 0x71, 0xfa, 0x6a, 0xf4, 0x6c, 0x73, 0x52, 0x13, 0x98, 0x5a, 0x46, 0x07, + 0xeb, 0x6d, 0x93, 0x13, 0x21, 0x47, 0x30, 0x38, 0x6d, 0x51, 0x6f, 0x6f, 0xe4, 0x89, 0x23, 0x1c, + 0x0c, 0x95, 0x78, 0xc6, 0x5b, 0x46, 0xe6, 0x3a, 0xcf, 0x25, 0x98, 0xee, 0xe2, 0xab, 0x38, 0xae, + 0xf9, 0x0c, 0x82, 0xad, 0xbe, 0xd7, 0xf0, 0x79, 0xf9, 0xb6, 0xce, 0x0b, 0x57, 0x82, 0x67, 0x9d, + 0xf2, 0xd9, 0x8e, 0x6b, 0xcf, 0xa3, 0xdb, 0xd1, 0xa3, 0x54, 0x59, 0x7d, 0xa1, 0xfe, 0xc7, 0x4f, + 0x7b, 0xed, 0x6e, 0x87, 0x67, 0xe4, 0xe1, 0x97, 0x81, 0xe1, 0xee, 0x91, 0x80, 0x6b, 0x6a, 0xda, + 0x32, 0x34, 0x7f, 0x79, 0xbf, 0xc7, 0x21, 0x66, 0x6c, 0x5d, 0x7d, 0x74, 0x71, 0xdf, 0xe8, 0x80, + 0x22, 0x9e, 0x9b, 0xa1, 0xb4, 0x3c, 0xfa, 0xc2, 0x3b, 0x53, 0x77, 0xf9, 0x4c, 0x68, 0x47, 0xdf, + 0xd9, 0x96, 0x9b, 0x3d, 0xe6, 0x96, 0xf6, 0xec, 0xd3, 0xfe, 0x50, 0xa0, 0xd7, 0xe4, 0x1a, 0x57, + 0xaa, 0x7f, 0x98, 0xb9, 0x16, 0xf1, 0xcd, 0xfa, 0x3b, 0x2f, 0xf5, 0x5a, 0xdd, 0x67, 0xac, 0xb3, + 0xf3, 0xd3, 0x81, 0xc8, 0xbd, 0x50, 0x9d, 0xd2, 0xe8, 0x0d, 0xd5, 0x5d, 0x89, 0x78, 0x9f, 0xf4, + 0x2f, 0x4e, 0x65, 0xeb, 0xb9, 0xd7, 0xd5, 0xf8, 0xed, 0x8d, 0x8c, 0xdc, 0xc6, 0x96, 0x74, 0x4b, + 0xbe, 0x2f, 0x2d, 0x23, 0x3f, 0xff, 0xb6, 0x7b, 0xe7, 0x8d, 0x8e, 0x63, 0xc1, 0xe3, 0x77, 0xfc, + 0xf6, 0x3b, 0xf6, 0xfa, 0xe5, 0xa7, 0xc4, 0xe9, 0x5b, 0x99, 0xab, 0xb9, 0x30, 0xbb, 0xcf, 0x67, + 0x9f, 0x3d, 0xd9, 0xe8, 0x1b, 0x29, 0xaa, 0x9e, 0xfa, 0x7e, 0xc2, 0xb9, 0xb7, 0xa3, 0xcb, 0x95, + 0x33, 0x54, 0x79, 0xfb, 0xbb, 0x1b, 0x3e, 0xfb, 0x11, 0x53, 0xa1, 0xd5, 0x1f, 0x2e, 0xb6, 0x2d, + 0x2c, 0x13, 0xf0, 0x5d, 0x55, 0x2a, 0xc5, 0x8a, 0xb1, 0x61, 0xab, 0xff, 0xea, 0xc2, 0x34, 0xd2, + 0x85, 0x25, 0x35, 0xc9, 0xcc, 0xd6, 0x30, 0x0f, 0x88, 0x5b, 0x1c, 0x50, 0x6c, 0x55, 0x96, 0xa1, + 0x47, 0x4d, 0xe5, 0x87, 0xbb, 0x67, 0x13, 0xcc, 0xbd, 0x70, 0x67, 0xea, 0x24, 0xdf, 0x55, 0xe8, + 0x38, 0xfb, 0x58, 0x71, 0x4d, 0xdd, 0xef, 0x4e, 0x7b, 0x78, 0xbf, 0xd3, 0x3a, 0x77, 0xdc, 0xd1, + 0x94, 0x2e, 0x56, 0xb6, 0x75, 0x8b, 0x59, 0x57, 0xe5, 0x6a, 0x27, 0xab, 0xdb, 0x3b, 0x53, 0x7f, + 0x29, 0x32, 0x9d, 0x93, 0x1b, 0x54, 0xca, 0xcd, 0xbe, 0x92, 0xe1, 0x5c, 0xab, 0x5f, 0x69, 0xf1, + 0x2b, 0xc7, 0x9a, 0x15, 0x87, 0xbd, 0x3d, 0x99, 0x4d, 0xe4, 0x5a, 0x64, 0x26, 0x14, 0xec, 0x54, + 0x1c, 0xd6, 0x81, 0x4b, 0x73, 0xa5, 0x96, 0xa1, 0xa0, 0x7a, 0x77, 0x0d, 0xa8, 0x63, 0x46, 0x97, + 0xa7, 0xf4, 0xca, 0xd8, 0xe1, 0x80, 0x5d, 0x4c, 0x5b, 0x52, 0x5a, 0xee, 0xcd, 0xa8, 0x7f, 0x9b, + 0xfd, 0xa4, 0x6e, 0x61, 0xbd, 0x9d, 0xab, 0x6c, 0x56, 0x3c, 0xdd, 0x93, 0xd5, 0xa3, 0xb4, 0x4c, + 0x8d, 0x46, 0xd7, 0xe0, 0x89, 0x89, 0x1a, 0x4f, 0x16, 0x66, 0xab, 0x84, 0x8a, 0xfc, 0xe1, 0xde, + 0xf6, 0xee, 0xd9, 0x6e, 0xe5, 0xf4, 0xec, 0x64, 0x4d, 0x9b, 0xad, 0xae, 0x7a, 0xf8, 0xe6, 0xec, + 0xfc, 0x7e, 0xb1, 0x2a, 0xce, 0x3c, 0xe6, 0xae, 0x6b, 0xaa, 0x1a, 0x09, 0x28, 0x57, 0xa6, 0x46, + 0xeb, 0x3b, 0xc4, 0x2c, 0xa6, 0xe8, 0x6b, 0x8d, 0x6e, 0xe7, 0x40, 0xad, 0x98, 0x83, 0xb8, 0xb0, + 0xf2, 0xae, 0xb1, 0x39, 0x7d, 0x40, 0x4c, 0x3d, 0x3a, 0x78, 0x36, 0xfa, 0xa3, 0x6e, 0xf8, 0xda, + 0xb2, 0x70, 0x9d, 0xe8, 0xfc, 0x2b, 0x4f, 0x7b, 0xf7, 0x0c, 0x96, 0x75, 0xd7, 0x38, 0x8a, 0xeb, + 0xc4, 0x3f, 0xe9, 0x2a, 0xf1, 0x47, 0x82, 0xd5, 0x63, 0xad, 0xc1, 0x5b, 0x67, 0x13, 0x4c, 0x5d, + 0x6c, 0xb6, 0x33, 0xb0, 0xc8, 0x1d, 0x58, 0x0a, 0x1b, 0x6a, 0x74, 0xb6, 0xf2, 0x85, 0x49, 0x5d, + 0x76, 0xf1, 0xf4, 0x12, 0x62, 0xbd, 0x58, 0xfa, 0xa3, 0x2f, 0x03, 0x9d, 0x6d, 0x1d, 0x8a, 0xeb, + 0x1b, 0xf7, 0xe0, 0xe9, 0xa2, 0xf3, 0xca, 0xad, 0x53, 0xed, 0x1f, 0xf6, 0x75, 0x7a, 0x1d, 0xd6, + 0xe1, 0xa2, 0x61, 0xf5, 0xae, 0x39, 0x53, 0x5f, 0x7a, 0xac, 0xa7, 0xb3, 0xbd, 0x5a, 0x2c, 0x95, + 0x16, 0xab, 0xa4, 0xeb, 0x8f, 0xcd, 0x1f, 0x0d, 0x07, 0x8f, 0x5b, 0x67, 0xc2, 0x5f, 0x1d, 0xaf, + 0x4f, 0xea, 0x69, 0xcb, 0xd4, 0xa1, 0x4d, 0xcc, 0x9c, 0x2a, 0x99, 0xcb, 0x9e, 0x59, 0x99, 0x46, + 0x5b, 0x6f, 0x0b, 0xde, 0x1d, 0x54, 0x5f, 0x1b, 0x1d, 0xf4, 0xdb, 0xbf, 0x9c, 0x19, 0xac, 0x7b, + 0x18, 0xfd, 0x8b, 0xb9, 0xd2, 0x3a, 0x31, 0xfb, 0xf6, 0x70, 0xff, 0xf8, 0x85, 0x9e, 0x27, 0xa1, + 0xe3, 0x67, 0x66, 0x42, 0x8e, 0xfb, 0x4f, 0x27, 0x42, 0xd3, 0x33, 0x73, 0xa7, 0xfd, 0xd1, 0xa7, + 0x50, 0x13, 0x83, 0x97, 0x98, 0xa5, 0x3b, 0x12, 0xba, 0xfa, 0xa8, 0xb8, 0xd2, 0x7d, 0xa7, 0xce, + 0xea, 0x0b, 0xb7, 0x3b, 0xca, 0x7b, 0xba, 0x66, 0x6c, 0x3d, 0x0f, 0xc6, 0x6e, 0x86, 0xbf, 0x3a, + 0xe3, 0x71, 0x8c, 0x1f, 0x9b, 0x34, 0x0f, 0xd8, 0x8e, 0xf5, 0xee, 0x19, 0x7a, 0x54, 0xb7, 0xdf, + 0xe2, 0x77, 0x37, 0x55, 0x15, 0x0d, 0x2b, 0x5e, 0x31, 0x1f, 0xb0, 0x7c, 0xb2, 0xc8, 0xaf, 0xde, + 0x07, 0xc4, 0xf0, 0xd9, 0xe3, 0x1f, 0x28, 0x51, 0xc7, 0xa8, 0x01, 0x71, 0x97, 0x50, 0xc7, 0xd5, + 0xe9, 0xac, 0xa1, 0x8e, 0xf9, 0xac, 0xe0, 0x54, 0x9b, 0xe7, 0x46, 0x71, 0x95, 0xaf, 0xb9, 0xb7, + 0xfd, 0xe6, 0xb5, 0x44, 0xf3, 0xe8, 0x4c, 0x3a, 0xc9, 0xb3, 0xc4, 0xbc, 0xf3, 0xa9, 0xb1, 0x3b, + 0x25, 0x91, 0x29, 0xbf, 0x23, 0xdc, 0xe8, 0x7d, 0x32, 0x14, 0xbe, 0xb8, 0xb8, 0x64, 0xd6, 0x53, + 0x12, 0x99, 0x5e, 0x9c, 0x8d, 0xe8, 0x6a, 0xbd, 0xfb, 0x9d, 0x6b, 0xba, 0x72, 0xca, 0xe3, 0x9a, + 0xb6, 0x8d, 0x9d, 0xbe, 0xa3, 0x5c, 0x34, 0x8f, 0x78, 0xe6, 0x9b, 0xf6, 0x8f, 0xf8, 0x14, 0x31, + 0x07, 0xb1, 0x63, 0x71, 0x69, 0x60, 0x96, 0xaf, 0x71, 0x52, 0xdc, 0x53, 0x27, 0x9d, 0x83, 0x7d, + 0x6b, 0xd7, 0x02, 0x9e, 0x58, 0x5c, 0xf7, 0x96, 0x73, 0xa8, 0xe0, 0xc2, 0xb9, 0xef, 0x72, 0xf3, + 0xcf, 0x5f, 0xb0, 0xd4, 0x5c, 0x8d, 0x2e, 0xa9, 0x7a, 0xec, 0x9d, 0xbc, 0x65, 0x3e, 0x37, 0x91, + 0x61, 0xb6, 0x7e, 0xdf, 0xd2, 0xfe, 0xbb, 0xa1, 0x8e, 0x4b, 0x0f, 0x9e, 0x04, 0x1b, 0x27, 0xd2, + 0x06, 0x6a, 0x1f, 0xd5, 0x28, 0xd5, 0x17, 0x47, 0xaf, 0x38, 0x2b, 0xbf, 0x39, 0xdf, 0xdc, 0xea, + 0xac, 0xba, 0x50, 0xf6, 0x20, 0xe7, 0x62, 0xc1, 0xc4, 0xba, 0xcf, 0xa2, 0x71, 0xd1, 0x39, 0x79, + 0xf8, 0x66, 0xab, 0xf3, 0x89, 0x29, 0xff, 0x61, 0x64, 0xb4, 0xcf, 0xec, 0x2d, 0x8e, 0xb4, 0xd7, + 0x7a, 0xbf, 0xde, 0x65, 0xb9, 0x35, 0xfe, 0xfb, 0x1b, 0xf9, 0x5f, 0x9e, 0x0b, 0x5b, 0xac, 0xf9, + 0x8d, 0x11, 0x4b, 0x57, 0xee, 0xf5, 0xf9, 0x74, 0x53, 0xbb, 0xad, 0x38, 0xfd, 0xb0, 0xc3, 0xa7, + 0x14, 0xba, 0x6b, 0x1b, 0x5a, 0xc6, 0x76, 0x0d, 0x45, 0xc4, 0x9b, 0xf3, 0xad, 0x53, 0xed, 0x8e, + 0x73, 0x62, 0xda, 0xf4, 0xb4, 0x2b, 0x6d, 0xa8, 0xc9, 0x2e, 0x56, 0x6e, 0x46, 0xc7, 0x5a, 0xad, + 0x7f, 0xad, 0x29, 0xc1, 0xa4, 0x2e, 0xbb, 0x53, 0x27, 0x79, 0xf6, 0xe1, 0xa2, 0x4b, 0x2d, 0x8b, + 0xdf, 0xc8, 0x89, 0xb3, 0xce, 0xa5, 0x85, 0x15, 0x0d, 0x69, 0x65, 0x87, 0xf2, 0x4d, 0xea, 0x0b, + 0x6b, 0xf4, 0x3b, 0x6c, 0x5a, 0x7e, 0x3e, 0x15, 0x57, 0xb1, 0x69, 0x6c, 0xe1, 0x43, 0xae, 0xba, + 0x2a, 0x66, 0x3d, 0xdd, 0x5f, 0xef, 0x3b, 0x6e, 0xb6, 0x29, 0x55, 0x7b, 0xeb, 0x2e, 0x17, 0xdd, + 0x09, 0xd7, 0x4d, 0x8f, 0x06, 0xbc, 0xca, 0x49, 0x9b, 0xba, 0xd9, 0x24, 0x73, 0x77, 0x6d, 0xaf, + 0x9f, 0x9d, 0x0b, 0xd9, 0xa2, 0xcf, 0x74, 0x7c, 0x69, 0x6a, 0xe6, 0x41, 0xfb, 0xb1, 0x99, 0x48, + 0xc8, 0xe1, 0x8a, 0x5e, 0x47, 0x41, 0x7d, 0xcd, 0xde, 0xa4, 0xfe, 0xbe, 0x57, 0x87, 0xf1, 0xd1, + 0x9e, 0xcb, 0xe5, 0xbd, 0xbb, 0x7c, 0x6e, 0x57, 0x55, 0x96, 0xff, 0xd2, 0x5c, 0x6f, 0xbb, 0xd2, + 0x25, 0x66, 0xae, 0x5e, 0xae, 0xda, 0x9f, 0x55, 0x77, 0x69, 0xae, 0xa8, 0x76, 0xa6, 0x54, 0x0c, + 0xfc, 0x1d, 0xf3, 0xfb, 0x46, 0xea, 0x15, 0x45, 0xec, 0xd4, 0x4d, 0xab, 0xdb, 0xcf, 0xe3, 0xf9, + 0x72, 0xbf, 0xbf, 0x76, 0xce, 0x3b, 0xdf, 0x3f, 0xaf, 0x4c, 0xaa, 0xb7, 0x77, 0xb1, 0x78, 0xde, + 0xeb, 0x55, 0x8e, 0x97, 0x88, 0x99, 0x7c, 0xe6, 0xfe, 0xc0, 0xd3, 0x5e, 0xb3, 0x5f, 0x51, 0x16, + 0x5e, 0x3b, 0xec, 0x3f, 0x35, 0x5f, 0x6e, 0xf5, 0xdb, 0x17, 0x57, 0x70, 0xa8, 0x2f, 0x6c, 0x95, + 0xa3, 0x03, 0xea, 0xfb, 0xd4, 0xbf, 0x78, 0x3a, 0x21, 0xee, 0x8a, 0x77, 0x47, 0xeb, 0x3b, 0x33, + 0x13, 0xcc, 0xa3, 0x53, 0x74, 0x92, 0x5b, 0x42, 0xee, 0x47, 0x63, 0x63, 0x5d, 0xde, 0xcb, 0x81, + 0x5e, 0xb3, 0xa7, 0xdb, 0x35, 0x26, 0xd6, 0xfd, 0x89, 0x05, 0xb0, 0xea, 0xaf, 0xac, 0x9b, 0x97, + 0xbb, 0x1d, 0x7b, 0xeb, 0xd4, 0xfb, 0x67, 0x78, 0xe9, 0x1e, 0xbd, 0x5f, 0x5c, 0x6a, 0x61, 0x69, + 0x05, 0xed, 0xf8, 0xc5, 0x6c, 0xf1, 0xac, 0x4e, 0x81, 0x9e, 0xf6, 0xaa, 0xa9, 0xc8, 0x1e, 0xf7, + 0x23, 0xc7, 0xbe, 0xb1, 0x7a, 0xa5, 0x73, 0x7a, 0xd7, 0x90, 0xfa, 0x2b, 0x6b, 0xcf, 0x57, 0x27, + 0xeb, 0xf6, 0x8d, 0xaa, 0xf7, 0xcf, 0xe8, 0x7a, 0xbb, 0x22, 0x75, 0x97, 0xa7, 0xa9, 0x48, 0x2c, + 0x22, 0xb1, 0x2c, 0x2d, 0x3a, 0xbc, 0x72, 0x4f, 0xbd, 0x37, 0x2c, 0x3c, 0x57, 0xac, 0xb7, 0xdf, + 0xda, 0xd8, 0xa2, 0x0c, 0x58, 0x1b, 0x27, 0x95, 0xc3, 0x85, 0x5f, 0x84, 0xb3, 0x6b, 0xcd, 0xc3, + 0x13, 0xb6, 0x1f, 0x7a, 0x5c, 0xd3, 0xea, 0x7d, 0xaa, 0xbb, 0xad, 0x59, 0xcc, 0xb6, 0xce, 0x38, + 0x68, 0x2e, 0x78, 0xd2, 0x63, 0xf2, 0x8a, 0x7d, 0x2b, 0x71, 0x03, 0x63, 0x6d, 0x21, 0x57, 0xbf, + 0xf3, 0x41, 0xeb, 0xd4, 0x88, 0x58, 0x37, 0xab, 0xfc, 0xee, 0x8f, 0xdf, 0x37, 0xa7, 0xdf, 0xab, + 0xad, 0xbd, 0xd4, 0x5f, 0x75, 0x6b, 0xd6, 0xd3, 0xd6, 0xfa, 0xf0, 0xda, 0x95, 0xd6, 0xa9, 0x1e, + 0x57, 0xe5, 0x3d, 0xf1, 0x23, 0x54, 0x72, 0xef, 0xd8, 0x6c, 0x65, 0x0b, 0xcf, 0x8a, 0x7d, 0xb6, + 0xeb, 0x42, 0xeb, 0xf1, 0xa2, 0xe1, 0xb2, 0x29, 0x9b, 0xf5, 0xaf, 0x4f, 0xf6, 0xef, 0xbe, 0x3d, + 0x7f, 0xba, 0x2f, 0xdf, 0x7f, 0xca, 0xbb, 0x6b, 0x67, 0x63, 0xd8, 0x62, 0x2a, 0x32, 0x37, 0xb5, + 0x54, 0xd6, 0x4d, 0x4f, 0x3b, 0x22, 0xea, 0x90, 0x55, 0xde, 0x6b, 0x19, 0x12, 0x73, 0x91, 0xfb, + 0xc3, 0xc7, 0x7a, 0xdc, 0xea, 0xbf, 0xeb, 0x0f, 0x07, 0xab, 0xac, 0x33, 0xd1, 0xf4, 0x9d, 0xea, + 0x6b, 0xbe, 0xf5, 0x9f, 0x80, 0xb7, 0x20, 0x7c, 0x83, 0x5f, 0x9f, 0xb2, 0x7e, 0x7d, 0xca, 0xb8, + 0x74, 0x83, 0x3d, 0x5d, 0xe7, 0x2e, 0xf4, 0x6b, 0xb3, 0x7a, 0xdf, 0xcd, 0x0e, 0x4f, 0x07, 0xe6, + 0xf7, 0xef, 0x16, 0xab, 0x31, 0x2c, 0xd1, 0x8b, 0x29, 0x38, 0x82, 0x62, 0x90, 0x10, 0xab, 0x36, + 0x1c, 0xe3, 0x5f, 0xde, 0x1d, 0x1c, 0x3c, 0x73, 0xd9, 0xf1, 0x51, 0x9d, 0xfb, 0xd8, 0xdd, 0x51, + 0xbf, 0x7d, 0xfa, 0xf8, 0x5e, 0x7f, 0x30, 0x38, 0x39, 0x18, 0x70, 0x8c, 0x8d, 0x79, 0xbd, 0xea, + 0xdd, 0xaa, 0xe6, 0x6a, 0xf8, 0xca, 0xb4, 0xd9, 0xe3, 0x56, 0x7f, 0x45, 0xfb, 0xc5, 0x93, 0x0e, + 0xd5, 0x9f, 0x52, 0x7f, 0xc9, 0xfa, 0x4b, 0xc5, 0x7e, 0xe2, 0xe5, 0x72, 0xf5, 0x06, 0xc4, 0xd5, + 0x5a, 0x7c, 0xdd, 0x9f, 0x8f, 0x77, 0x06, 0x23, 0x77, 0xce, 0x14, 0xfb, 0xc5, 0x2f, 0x94, 0xa1, + 0xf0, 0x65, 0xf5, 0xc5, 0x78, 0xf4, 0xf1, 0xc3, 0x19, 0xdf, 0xbc, 0xf7, 0x5a, 0xb0, 0x68, 0xcf, + 0xcd, 0xaa, 0xea, 0x89, 0x50, 0xed, 0x95, 0x48, 0xe0, 0x87, 0x99, 0xe3, 0xd6, 0xe9, 0xe2, 0xe0, + 0x49, 0xc7, 0xdc, 0xa8, 0xaf, 0x55, 0x7d, 0xc4, 0xa1, 0xee, 0xfe, 0xaa, 0x43, 0xb7, 0xf8, 0x05, + 0xed, 0x78, 0xbc, 0x7a, 0xf1, 0x7b, 0xdc, 0x8b, 0x07, 0xae, 0x1d, 0x7d, 0x1d, 0xd7, 0xc5, 0xb3, + 0x8d, 0x9c, 0x73, 0xe7, 0x1c, 0x2c, 0x38, 0x27, 0x56, 0xa7, 0xbb, 0xbf, 0x2a, 0x1d, 0x0e, 0xcf, + 0x36, 0xa5, 0x1f, 0x54, 0x1f, 0x44, 0xe4, 0x58, 0x1a, 0x82, 0xca, 0x99, 0xe3, 0xc7, 0xfe, 0xda, + 0xf4, 0x6d, 0xdb, 0xa3, 0xb1, 0x86, 0xac, 0x1c, 0x6b, 0xc7, 0x6d, 0x67, 0x6b, 0x65, 0xcc, 0x73, + 0x38, 0xa9, 0xe3, 0x75, 0x61, 0x61, 0xd9, 0xc8, 0xd4, 0x9c, 0xdb, 0xae, 0x4c, 0x8f, 0x76, 0x76, + 0x17, 0xf9, 0xe6, 0x1d, 0xe1, 0x26, 0x75, 0x1c, 0x16, 0xa3, 0x74, 0x9d, 0xab, 0xc8, 0xdf, 0xd9, + 0x2e, 0x96, 0xea, 0x0c, 0xb8, 0x83, 0xe2, 0x3a, 0x14, 0x99, 0x09, 0x9e, 0xc3, 0x3a, 0x43, 0x27, + 0x79, 0x79, 0xdb, 0xad, 0xae, 0xfb, 0xae, 0xa1, 0xcf, 0x27, 0x32, 0x6f, 0x54, 0x1e, 0xf1, 0x35, + 0x58, 0xfa, 0x4e, 0x7c, 0xe3, 0xfa, 0x30, 0x77, 0xd4, 0x73, 0xc5, 0x59, 0x71, 0x49, 0x7d, 0xb3, + 0xb8, 0x30, 0x3a, 0xc7, 0x5d, 0x2c, 0xd7, 0x53, 0x1f, 0x12, 0x45, 0xf7, 0x9d, 0x32, 0xf2, 0x0a, + 0x1a, 0x1a, 0xee, 0xe5, 0x5a, 0xef, 0x7c, 0x5d, 0xa3, 0xee, 0x6e, 0xd4, 0x3a, 0x33, 0xcf, 0x16, + 0xb8, 0xcb, 0x3c, 0x27, 0xd4, 0x5f, 0x1e, 0xae, 0xf3, 0xca, 0xb1, 0x5e, 0xd3, 0x50, 0x60, 0xf2, + 0x70, 0xc7, 0xfd, 0xee, 0x9d, 0x7d, 0x21, 0xaf, 0xbb, 0xa9, 0x2c, 0x54, 0xdf, 0x7a, 0xbe, 0xcd, + 0xea, 0xf7, 0x2a, 0xa1, 0x9c, 0x5c, 0x7f, 0xa4, 0x47, 0xbd, 0xdf, 0x37, 0xed, 0x15, 0x2b, 0x8c, + 0xbd, 0xe1, 0xb1, 0x7c, 0xb7, 0x78, 0xb3, 0xa5, 0xd9, 0x55, 0xa4, 0xee, 0xc3, 0x74, 0xdd, 0xca, + 0xff, 0x2e, 0x7a, 0x09, 0x81, 0xa4, 0xee, 0xd3, 0x33, 0xfd, 0xe1, 0x2a, 0xdb, 0x0f, 0x9e, 0x53, + 0x73, 0xe5, 0x62, 0x5f, 0x47, 0xfd, 0x55, 0x60, 0x2b, 0x0f, 0x05, 0xfc, 0xf3, 0xb6, 0x72, 0xb1, + 0x10, 0xa3, 0xca, 0xea, 0xee, 0x8a, 0xa8, 0xc3, 0xf2, 0xe5, 0xb6, 0xb1, 0xc5, 0xb1, 0xdf, 0x7e, + 0xcc, 0xab, 0x0e, 0xbc, 0x17, 0xc4, 0xef, 0x97, 0x96, 0x11, 0xf1, 0xb9, 0x6a, 0xd4, 0x8e, 0x48, + 0x74, 0x5d, 0xd3, 0xc2, 0x4e, 0x55, 0xa8, 0xae, 0x2b, 0x32, 0x3a, 0xea, 0x09, 0x76, 0x4e, 0x0d, + 0xd7, 0x87, 0x6d, 0x55, 0x3b, 0x6b, 0x3b, 0x66, 0x83, 0x73, 0xf5, 0xe3, 0x9d, 0xd3, 0x85, 0xbe, + 0xb0, 0xb7, 0x4c, 0xdd, 0x39, 0x4c, 0xb0, 0x44, 0x2c, 0x9c, 0xc3, 0xa8, 0x25, 0xf9, 0x68, 0xc2, + 0x44, 0x9e, 0xce, 0x56, 0x5e, 0x3d, 0xea, 0x2b, 0xb5, 0x4e, 0x5b, 0x6e, 0x06, 0x15, 0x73, 0x7b, + 0xbd, 0xfb, 0x4a, 0x20, 0x1c, 0xae, 0x8c, 0xf4, 0xee, 0xf6, 0xa8, 0x83, 0x44, 0x57, 0x5d, 0xa9, + 0xa3, 0x6a, 0x77, 0x9d, 0xab, 0xa9, 0xb6, 0x47, 0x59, 0x5a, 0xbd, 0xb8, 0x63, 0xba, 0x71, 0x61, + 0x39, 0xf6, 0xe2, 0x6e, 0x93, 0xe9, 0x4a, 0x5b, 0xbf, 0x73, 0x5a, 0xfc, 0xeb, 0x25, 0xd5, 0x8b, + 0xcf, 0x68, 0x2f, 0xd6, 0x83, 0x88, 0x2b, 0x2f, 0xfc, 0x45, 0xfd, 0x55, 0xd8, 0xe8, 0x74, 0x56, + 0x9e, 0xbd, 0xf6, 0xf5, 0x07, 0x39, 0x67, 0x0b, 0x7c, 0x76, 0xcb, 0xe7, 0x57, 0x7f, 0x3f, 0x98, + 0xdb, 0xe1, 0xe9, 0x0e, 0xf8, 0x8a, 0x17, 0xd6, 0xe1, 0xa8, 0xbb, 0x34, 0x33, 0xe2, 0x71, 0x6b, + 0xec, 0x02, 0x9d, 0x07, 0x91, 0x9e, 0x48, 0xb0, 0xf4, 0x4c, 0x92, 0x47, 0xbb, 0xdc, 0xea, 0x68, + 0xe0, 0xb9, 0xdc, 0x32, 0x96, 0xe5, 0xbf, 0x36, 0x5f, 0x3d, 0xe8, 0x78, 0x28, 0x9e, 0x99, 0x4e, + 0x59, 0xbc, 0x06, 0xc1, 0xae, 0xa1, 0xf0, 0x9d, 0x91, 0xd9, 0x9b, 0xd7, 0xd4, 0x1d, 0x1e, 0x9f, + 0xb8, 0x7e, 0x55, 0xbd, 0x4d, 0x29, 0x37, 0xf5, 0x9e, 0x3c, 0x13, 0x8e, 0x38, 0xc6, 0xad, 0x11, + 0x75, 0x04, 0x7b, 0xda, 0x6b, 0xfa, 0xca, 0xa6, 0x4c, 0x97, 0x04, 0x4a, 0xad, 0x91, 0xf6, 0xab, + 0xe3, 0x8d, 0xea, 0xc3, 0xfb, 0x87, 0x4b, 0x5f, 0x5f, 0x7f, 0xa4, 0x75, 0xd6, 0xdd, 0xae, 0x3e, + 0xc2, 0xb6, 0x5c, 0xbd, 0x95, 0xe0, 0xa1, 0x6d, 0x66, 0x96, 0x4e, 0xf2, 0xcc, 0x8d, 0x7e, 0x0f, + 0xb3, 0x1e, 0x7b, 0x55, 0xc5, 0x13, 0xc7, 0x78, 0x55, 0xa5, 0xfa, 0x30, 0xfe, 0x62, 0x85, 0x3a, + 0xd4, 0x5d, 0x18, 0x53, 0x47, 0xeb, 0x6e, 0xdf, 0xe2, 0x25, 0x4d, 0xc6, 0x95, 0x72, 0xb1, 0x20, + 0xb1, 0xb2, 0x4b, 0xdd, 0xeb, 0xd9, 0xbf, 0x4b, 0xbd, 0xa7, 0x8e, 0x15, 0x89, 0x05, 0x7e, 0xe6, + 0x01, 0xb1, 0xd0, 0x7a, 0xc0, 0xad, 0x0e, 0x7f, 0xd1, 0x3b, 0xb3, 0xc7, 0x2d, 0x86, 0xc4, 0xcb, + 0xea, 0xaf, 0x8f, 0xba, 0xd2, 0xce, 0xb9, 0x41, 0xb1, 0xef, 0xd4, 0x19, 0xbc, 0x5a, 0xdd, 0x6b, + 0x7e, 0x34, 0x35, 0xab, 0x3e, 0x64, 0x3f, 0x59, 0xb7, 0xdf, 0xe3, 0x9a, 0xab, 0xec, 0xb5, 0xa8, + 0xb7, 0x52, 0x24, 0xae, 0x69, 0x50, 0xf1, 0xa0, 0x36, 0x30, 0xa9, 0x3c, 0x70, 0x04, 0x3a, 0xbd, + 0x7d, 0xf9, 0xe7, 0xd5, 0x07, 0xf9, 0xd6, 0xc6, 0xb5, 0x97, 0xa4, 0xf2, 0x2f, 0xbe, 0x56, 0x71, + 0xe2, 0xf6, 0xbd, 0x9c, 0x43, 0x67, 0x6f, 0x37, 0xa4, 0xfb, 0x4b, 0x0a, 0xee, 0xf7, 0x3c, 0x99, + 0x1e, 0xbe, 0x58, 0xf4, 0x91, 0x67, 0xdc, 0x55, 0xdd, 0x3e, 0x73, 0x6a, 0x3e, 0xbb, 0xd0, 0x7e, + 0xe4, 0xd4, 0xcd, 0xd6, 0xbe, 0xae, 0x36, 0xa7, 0xf3, 0x64, 0xf1, 0xf0, 0x8d, 0x47, 0xd7, 0xc2, + 0x1f, 0xde, 0x58, 0x59, 0xfe, 0x17, 0xbd, 0x95, 0xbe, 0x13, 0xe7, 0xef, 0xa5, 0xf5, 0x45, 0x77, + 0x9b, 0xe2, 0xd6, 0xe2, 0x2d, 0x3d, 0xd9, 0xeb, 0x50, 0x20, 0xec, 0xb4, 0xfc, 0xf9, 0x6e, 0xb8, + 0xe8, 0xbb, 0x36, 0x53, 0xf9, 0x68, 0xf7, 0xc3, 0xf2, 0x04, 0x4f, 0x1b, 0x9e, 0x96, 0xad, 0x3d, + 0xb0, 0xb4, 0xdd, 0x0c, 0xa9, 0x3b, 0x59, 0x77, 0x07, 0xc5, 0xca, 0x2d, 0xd1, 0xa4, 0x48, 0xdd, + 0x03, 0xed, 0x16, 0xaf, 0x79, 0x4b, 0x2d, 0x33, 0xae, 0xd6, 0x39, 0xf5, 0x35, 0x57, 0xa5, 0xb7, + 0xbd, 0x6a, 0x74, 0x58, 0x7d, 0xcd, 0xe1, 0x1b, 0xe8, 0xf4, 0x34, 0x75, 0x9f, 0xae, 0x15, 0x57, + 0xe5, 0x29, 0x38, 0x3f, 0x9f, 0xa6, 0x6e, 0xea, 0x5f, 0x7f, 0x28, 0xae, 0xe9, 0x91, 0x21, 0xbe, + 0xd4, 0x9c, 0xe2, 0x4b, 0x55, 0xea, 0x40, 0x75, 0x3e, 0xbf, 0xc5, 0x79, 0xcf, 0xe3, 0xf9, 0x76, + 0xb0, 0xae, 0xf6, 0x9c, 0x3b, 0xd7, 0x6f, 0x2d, 0xf8, 0x4b, 0x6b, 0x5f, 0xdf, 0xd9, 0x98, 0x8b, + 0x91, 0x44, 0x57, 0x2b, 0x4f, 0xac, 0x5a, 0xfa, 0xb4, 0xf0, 0x64, 0xd9, 0x66, 0x71, 0x45, 0x16, + 0x71, 0x37, 0x09, 0x7b, 0x4b, 0x87, 0xef, 0xcc, 0xd6, 0x35, 0x64, 0x7e, 0x68, 0xf6, 0xa8, 0xbf, + 0x89, 0x6b, 0xdb, 0x15, 0x93, 0xe5, 0x35, 0x1c, 0x58, 0xda, 0x13, 0x0c, 0x2c, 0x6e, 0x8b, 0xce, + 0x56, 0x5e, 0xf3, 0xc2, 0x6b, 0x93, 0x16, 0x77, 0x15, 0xee, 0x06, 0xea, 0xc5, 0xb1, 0x35, 0x47, + 0xa4, 0xbb, 0x66, 0xf6, 0xe6, 0xf5, 0xf9, 0xa3, 0x83, 0x37, 0xaf, 0x3c, 0x1d, 0x1d, 0xac, 0x2f, + 0x79, 0xaa, 0xde, 0x49, 0x67, 0xc5, 0x65, 0x44, 0xba, 0xc7, 0xbc, 0x33, 0x0f, 0x4a, 0x1b, 0xc5, + 0xea, 0x6c, 0xf5, 0xf1, 0xf2, 0x8c, 0x58, 0x86, 0x28, 0x8e, 0x1c, 0x0c, 0xd6, 0x89, 0xcb, 0x2f, + 0xa8, 0xf7, 0xfc, 0x69, 0xcb, 0x80, 0x5d, 0x6c, 0xf9, 0xee, 0xfb, 0x63, 0x7b, 0x3d, 0xae, 0xd1, + 0x99, 0xf6, 0xaf, 0xa2, 0x3b, 0x3a, 0xe3, 0xd7, 0xa7, 0xc6, 0x06, 0x2e, 0x7f, 0x3f, 0x6e, 0x56, + 0xba, 0xe6, 0xf7, 0x8f, 0x0c, 0xcd, 0x37, 0x4d, 0xf5, 0xb4, 0xb9, 0xa3, 0xc7, 0xbd, 0x5a, 0xd4, + 0x47, 0xfa, 0xea, 0x6b, 0xa3, 0x81, 0x8e, 0xb9, 0xfd, 0xbb, 0x86, 0x82, 0xea, 0x03, 0xff, 0x01, + 0xf1, 0xa0, 0x2c, 0x7a, 0x49, 0xbb, 0xe8, 0xb1, 0xd4, 0x81, 0xcf, 0x27, 0xbd, 0x03, 0x8e, 0xe8, + 0xd2, 0xa7, 0xbf, 0x3c, 0x29, 0x2d, 0x39, 0x1f, 0xbc, 0x57, 0x79, 0xf3, 0x9b, 0x63, 0x4d, 0x3b, + 0xfa, 0x72, 0x2f, 0xfa, 0xac, 0xa7, 0x4b, 0xce, 0xff, 0xe0, 0x0d, 0xd5, 0x8b, 0x6f, 0x41, 0x7d, + 0x40, 0xa3, 0xee, 0x75, 0x5c, 0x8a, 0xf4, 0x8c, 0xf8, 0x2f, 0x5d, 0xb8, 0x17, 0x74, 0x94, 0x5c, + 0x68, 0x39, 0x54, 0xb7, 0x32, 0x96, 0xfd, 0xf9, 0xd7, 0x79, 0x85, 0x05, 0x0d, 0x3e, 0x5b, 0xce, + 0x37, 0xd7, 0x1f, 0x2c, 0x5d, 0xd8, 0xa1, 0x69, 0xe9, 0x89, 0x0c, 0xf3, 0xaf, 0x4f, 0x28, 0x07, + 0x13, 0x8e, 0xe5, 0xcd, 0xc5, 0x3a, 0xc9, 0x4d, 0xfd, 0xb5, 0xe7, 0x27, 0xd7, 0xb9, 0xd8, 0x85, + 0xb8, 0x06, 0x94, 0x12, 0x5d, 0xb3, 0xa7, 0xee, 0x4d, 0xb5, 0xa4, 0x4f, 0x15, 0x35, 0x36, 0x58, + 0x73, 0xf3, 0x0b, 0xc4, 0xba, 0x55, 0xf5, 0x2f, 0x4a, 0xc4, 0xc5, 0x82, 0xfa, 0xcf, 0x46, 0x17, + 0x10, 0xfa, 0x32, 0xf3, 0x7e, 0x7b, 0x4c, 0xfd, 0x90, 0x1d, 0xb7, 0xbe, 0x69, 0x49, 0x6f, 0x9d, + 0x0a, 0x7d, 0x54, 0x93, 0x7e, 0xee, 0x5a, 0xd3, 0xd1, 0xf6, 0x07, 0xee, 0xeb, 0xee, 0xdc, 0xfc, + 0xb9, 0xe2, 0xc2, 0x81, 0xe8, 0x9a, 0xd2, 0xfc, 0xb3, 0x2e, 0xe7, 0xc2, 0x05, 0x01, 0xfc, 0xee, + 0x86, 0x9e, 0xfa, 0xb3, 0xe7, 0x9e, 0x64, 0x3f, 0xe8, 0xad, 0x0a, 0xa5, 0x9b, 0xd4, 0x68, 0x73, + 0x19, 0xd6, 0xa3, 0x7f, 0x1d, 0x09, 0x7c, 0xd5, 0x54, 0x18, 0xb4, 0x7a, 0x14, 0xa7, 0xe9, 0x4c, + 0x51, 0x43, 0x7a, 0xa5, 0xbb, 0xfd, 0xcb, 0xb9, 0xb4, 0xa1, 0x86, 0x33, 0xd6, 0x88, 0xc7, 0xd1, + 0x94, 0xe5, 0x0b, 0xd5, 0x29, 0xad, 0xad, 0xb7, 0xce, 0xbb, 0x95, 0xa3, 0xe1, 0x5b, 0xe7, 0x22, + 0xf7, 0x72, 0x73, 0x1f, 0x46, 0x9c, 0x26, 0xc5, 0xed, 0x4a, 0x3f, 0x5e, 0xdb, 0xa0, 0x64, 0x47, + 0xba, 0x1a, 0x94, 0x8a, 0xe4, 0x96, 0xeb, 0x85, 0x9b, 0xc4, 0x61, 0xe4, 0xa7, 0x63, 0x87, 0x3d, + 0x76, 0xa5, 0xec, 0x49, 0x74, 0xf4, 0x57, 0x37, 0x98, 0x7b, 0xea, 0x9e, 0xcd, 0x05, 0xb1, 0xe4, + 0xf9, 0xa9, 0xd8, 0xd1, 0x71, 0x95, 0xa9, 0xbf, 0x7f, 0x12, 0xac, 0x3d, 0x35, 0xa5, 0xe9, 0x24, + 0x77, 0xa9, 0x23, 0xb3, 0xd7, 0x94, 0xc4, 0x17, 0xb8, 0x63, 0xf4, 0x41, 0x7b, 0xf5, 0xd4, 0x88, + 0x5f, 0x69, 0x13, 0x0f, 0xcf, 0xc5, 0xf2, 0x3a, 0x75, 0x78, 0xca, 0xf2, 0x5f, 0x6d, 0x19, 0xdb, + 0xeb, 0x77, 0xb7, 0x97, 0xa9, 0xfb, 0x91, 0x62, 0xd1, 0x78, 0xb0, 0x29, 0x3b, 0x54, 0x5f, 0xaa, + 0x6e, 0xe5, 0xea, 0xa3, 0xc6, 0x7b, 0xb3, 0x9e, 0xd2, 0x96, 0x11, 0x71, 0xfc, 0x5f, 0xbd, 0x87, + 0xb4, 0x5f, 0x16, 0xbf, 0xbc, 0x26, 0x43, 0x81, 0x40, 0x78, 0x5a, 0x3c, 0xe6, 0xbf, 0xa2, 0x3e, + 0xcc, 0xee, 0x76, 0x55, 0x7d, 0xd7, 0x3d, 0x57, 0x3e, 0x11, 0xea, 0xbf, 0xff, 0xb4, 0x77, 0x30, + 0x70, 0xea, 0xa9, 0x77, 0x71, 0x2d, 0xa2, 0x38, 0x7c, 0xb0, 0xb8, 0x6c, 0x5d, 0x3c, 0x6f, 0xb2, + 0xfa, 0x4b, 0x4e, 0xfd, 0x6d, 0xe2, 0xaa, 0x1c, 0x53, 0xef, 0x17, 0xd1, 0x8b, 0x38, 0x54, 0x1d, + 0xee, 0xbb, 0x36, 0x1b, 0x7d, 0xf4, 0x3b, 0x62, 0x76, 0x57, 0x15, 0xbb, 0xac, 0xea, 0x03, 0xff, + 0x1e, 0x6f, 0x5b, 0x73, 0x40, 0xdc, 0x9d, 0x1a, 0x7b, 0x8b, 0xa7, 0xa3, 0xed, 0x02, 0x09, 0xf7, + 0xee, 0x57, 0xbf, 0xe8, 0xed, 0x9b, 0xea, 0x6a, 0x73, 0xed, 0xc8, 0x6d, 0xf4, 0x8c, 0xf4, 0x9d, + 0xf2, 0x95, 0x4d, 0x15, 0xf6, 0x57, 0x7f, 0xeb, 0xda, 0xe3, 0x38, 0xa6, 0xee, 0x1a, 0xe4, 0xdf, + 0x0e, 0x3b, 0xf3, 0x0b, 0xe6, 0x12, 0xec, 0x97, 0x4f, 0x94, 0xe9, 0x24, 0x57, 0x66, 0xea, 0x1d, + 0xe5, 0xbd, 0x1e, 0x47, 0xb0, 0xfc, 0xde, 0x4c, 0xbd, 0xdd, 0x5b, 0x3b, 0xe6, 0xbf, 0x14, 0xfd, + 0x6d, 0x25, 0xce, 0x7a, 0x44, 0x0f, 0x53, 0x7f, 0x3f, 0xa9, 0x84, 0x6a, 0xfd, 0xee, 0xf4, 0x01, + 0x6b, 0x74, 0xe5, 0xfc, 0xed, 0x85, 0xcb, 0x20, 0xa8, 0xbf, 0xc6, 0x9a, 0x2d, 0xf6, 0xc2, 0x0b, + 0xa6, 0xe6, 0xa0, 0xb5, 0xd0, 0xdd, 0x5b, 0x58, 0x34, 0x5c, 0xf9, 0xc3, 0x68, 0x7b, 0xf0, 0xba, + 0x2b, 0xbd, 0xaf, 0xe3, 0xec, 0x15, 0xf5, 0x6e, 0xd8, 0x30, 0xa1, 0x3e, 0x10, 0xf1, 0x65, 0xd6, + 0x58, 0x4b, 0xae, 0x8f, 0x7c, 0xdb, 0xd6, 0x7a, 0x6c, 0x3a, 0x7b, 0xd8, 0x13, 0xbd, 0x74, 0x96, + 0x4f, 0x5c, 0x33, 0xe1, 0x96, 0xd2, 0xe6, 0x6d, 0x73, 0x4c, 0xce, 0x39, 0x6b, 0x4f, 0xdc, 0x77, + 0xed, 0xe8, 0xba, 0x1e, 0x70, 0xe5, 0xad, 0xb9, 0xa6, 0x43, 0xde, 0xe2, 0xd3, 0x61, 0xb6, 0x14, + 0xde, 0x09, 0x4d, 0x3f, 0x7e, 0xda, 0x75, 0xe2, 0xfc, 0xe3, 0xe0, 0x47, 0x79, 0x27, 0xdb, 0x26, + 0x58, 0xd3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x45, 0xe2, 0x4c, + 0x9f, 0xd4, 0x95, 0x1c, 0xf6, 0xbc, 0xd3, 0xcc, 0xa3, 0x93, 0x3b, 0x8f, 0xae, 0x39, 0x8b, 0xe4, + 0x92, 0x93, 0xbb, 0xb3, 0x49, 0x2e, 0x79, 0x89, 0x58, 0x9a, 0x85, 0xe4, 0x92, 0x93, 0x67, 0x16, + 0x93, 0x5c, 0xf6, 0x0a, 0xeb, 0x34, 0x92, 0x4b, 0xde, 0xca, 0x7d, 0x65, 0x24, 0x97, 0x9c, 0x7c, + 0xa2, 0x82, 0xe4, 0x92, 0x93, 0x9b, 0x6c, 0x24, 0x97, 0x3c, 0x96, 0x37, 0x64, 0x92, 0x5c, 0xf6, + 0x75, 0x04, 0xec, 0x24, 0x97, 0x9c, 0xbc, 0xb9, 0x86, 0xe4, 0x92, 0x93, 0xbb, 0x4d, 0x24, 0x97, + 0x9b, 0xbc, 0x60, 0xc2, 0x49, 0x72, 0xc9, 0xc9, 0xc3, 0x0a, 0xc9, 0xe5, 0x26, 0x37, 0x95, 0xdd, + 0x20, 0xf9, 0x36, 0xba, 0x74, 0x83, 0x79, 0x22, 0x9d, 0x9f, 0xa7, 0xe4, 0x9d, 0xfe, 0x70, 0x06, + 0xc9, 0x25, 0xef, 0x0e, 0x95, 0xe5, 0x90, 0x3c, 0x3d, 0x97, 0x35, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x56, 0x24, 0xce, 0xf4, 0x71, 0x56, 0xf8, 0x65, 0xcc, 0x30, + 0x72, 0x9e, 0xe1, 0xc4, 0xb1, 0xe4, 0x79, 0x74, 0x0a, 0xc9, 0x25, 0x4f, 0xea, 0xb2, 0xdf, 0x20, + 0xf9, 0x76, 0x9a, 0xd4, 0x15, 0x4e, 0xe7, 0xe7, 0x29, 0xfb, 0x99, 0x4a, 0x32, 0x48, 0x2e, 0x79, + 0x52, 0x97, 0x3d, 0x87, 0xe4, 0xb2, 0xe7, 0xd1, 0xe5, 0x91, 0x5c, 0xf6, 0x75, 0x04, 0xb2, 0x48, + 0x2e, 0xfb, 0x6a, 0x19, 0xd9, 0x24, 0x97, 0x7d, 0x1d, 0x01, 0x0b, 0xc9, 0x65, 0x5f, 0x2d, 0xa3, + 0x98, 0xe4, 0xb2, 0xaf, 0x23, 0x90, 0x46, 0x72, 0xd9, 0x57, 0xcb, 0x28, 0x23, 0xb9, 0xec, 0xeb, + 0x08, 0x54, 0x90, 0x5c, 0xf6, 0xd5, 0x32, 0x6c, 0x24, 0x97, 0x7d, 0x1d, 0x81, 0x4c, 0x92, 0xcb, + 0xbe, 0x5a, 0x86, 0x9d, 0xe4, 0xb2, 0xaf, 0x23, 0x50, 0x43, 0x72, 0xd9, 0x57, 0xcb, 0x30, 0x3d, + 0x4f, 0x72, 0xd6, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x91, + 0x38, 0xd3, 0xc7, 0x29, 0xd2, 0x85, 0xd9, 0xa2, 0x65, 0x15, 0x9c, 0x95, 0x96, 0x3c, 0x27, 0xba, + 0x82, 0xe4, 0xb2, 0x67, 0xfe, 0xdb, 0x48, 0x2e, 0x7b, 0x7d, 0x4b, 0x26, 0xc9, 0x65, 0xaf, 0xe2, + 0xb2, 0x93, 0x5c, 0xf6, 0x5a, 0xc5, 0x1a, 0x92, 0xcb, 0xbe, 0xe6, 0xbf, 0x89, 0xe4, 0x92, 0x17, + 0xb5, 0x37, 0x3b, 0x49, 0x2e, 0x39, 0xb9, 0x5b, 0x21, 0xb9, 0xe4, 0xab, 0x65, 0x34, 0xdc, 0x20, + 0xf9, 0x36, 0xba, 0x74, 0x43, 0x61, 0x73, 0x3a, 0x3f, 0x4f, 0xd9, 0x73, 0xdc, 0x33, 0x48, 0x2e, + 0x7b, 0x25, 0x47, 0x0e, 0xc9, 0x65, 0xaf, 0x57, 0xca, 0x23, 0xb9, 0xec, 0x55, 0x79, 0x59, 0x24, + 0x97, 0xbd, 0xf6, 0x34, 0x9b, 0xe4, 0xb2, 0x57, 0x58, 0x5b, 0x48, 0x2e, 0xfb, 0x3a, 0x02, 0xc5, + 0x24, 0x97, 0x7d, 0xb5, 0x8c, 0x34, 0x79, 0xc9, 0x59, 0xd3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x45, 0x3f, 0xfb, 0x65, 0x4a, 0xca, 0x6b, 0x73, 0xba, 0x73, 0x69, + 0x06, 0x62, 0x46, 0x0d, 0x27, 0x97, 0xa5, 0xd5, 0x6e, 0xc8, 0xa1, 0xb6, 0xb4, 0xda, 0xe6, 0x86, + 0x3c, 0x6a, 0xcb, 0xdb, 0xb6, 0x4d, 0x59, 0xd4, 0x96, 0x57, 0x7b, 0x22, 0x9b, 0xda, 0xf2, 0x6a, + 0xfb, 0x2c, 0xd4, 0x96, 0x37, 0x6e, 0xfb, 0x8a, 0xa9, 0x2d, 0x6f, 0xdb, 0xce, 0x4c, 0xa3, 0xb6, + 0xbc, 0xda, 0x69, 0x65, 0xd4, 0x96, 0x37, 0x92, 0xb8, 0x2b, 0xa8, 0x2d, 0xaf, 0x76, 0xb3, 0x8d, + 0xda, 0xf2, 0x46, 0x12, 0x7b, 0x26, 0xb5, 0xe5, 0xd5, 0x2e, 0xb3, 0x53, 0x5b, 0xde, 0x48, 0x12, + 0xae, 0xa1, 0xb6, 0xbc, 0xda, 0x13, 0x26, 0x6a, 0x4b, 0xab, 0x6d, 0x72, 0x3b, 0xa9, 0x2d, 0xaf, + 0x76, 0xb3, 0x42, 0xed, 0x2d, 0x77, 0xc5, 0x84, 0xa5, 0xa5, 0xfa, 0xe9, 0xdb, 0xf9, 0x67, 0x27, + 0xce, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xbb, 0x12, 0x67, 0x83, + 0x7e, 0xb4, 0xb3, 0x3d, 0xec, 0xb5, 0x9c, 0xa3, 0x95, 0x37, 0x93, 0xa9, 0x86, 0xda, 0x12, 0x67, + 0xe9, 0x99, 0xa8, 0x2d, 0xad, 0x76, 0x41, 0x83, 0x93, 0xda, 0xf2, 0xe6, 0xd6, 0x34, 0x28, 0xd4, + 0xde, 0xa2, 0x73, 0x6b, 0xcc, 0x0d, 0xe9, 0xfc, 0xec, 0x24, 0xae, 0xfb, 0xcd, 0xa0, 0xb6, 0xc4, + 0x35, 0xed, 0x39, 0xd4, 0x96, 0x57, 0xdb, 0x9d, 0x47, 0x6d, 0x89, 0x6b, 0x23, 0xb3, 0xa8, 0x2d, + 0x71, 0xdd, 0x6f, 0x36, 0xb5, 0x25, 0xae, 0x69, 0xb7, 0x50, 0x5b, 0xe2, 0xf5, 0x1a, 0x8a, 0xa9, + 0x2d, 0x71, 0x6d, 0x64, 0x1a, 0xb5, 0x25, 0xae, 0xfb, 0x2d, 0xa3, 0xb6, 0xc4, 0x35, 0xed, 0x15, + 0xd4, 0x96, 0x78, 0xbd, 0x06, 0x1b, 0xb5, 0x25, 0xae, 0x8d, 0xcc, 0x7c, 0x15, 0xb5, 0x59, 0x1b, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x9d, 0x3d, 0xd7, 0xf3, 0x06, 0xe9, + 0xcd, 0xf6, 0xb0, 0x38, 0x38, 0x6b, 0x28, 0x6f, 0x26, 0x53, 0x31, 0xb5, 0x25, 0xce, 0xf6, 0x48, + 0xa3, 0xb6, 0xc4, 0x99, 0x4c, 0x65, 0xd4, 0x96, 0x38, 0xdb, 0xa3, 0x82, 0xda, 0x12, 0x67, 0x32, + 0xd9, 0xa8, 0x2d, 0x71, 0xdd, 0x6f, 0x26, 0xb5, 0x25, 0xce, 0x64, 0xb2, 0x53, 0x5b, 0xe2, 0xba, + 0xdf, 0x1a, 0x6a, 0x4b, 0x5c, 0xd3, 0x6e, 0xa2, 0xb6, 0xc4, 0x75, 0xbf, 0x4e, 0x6a, 0x4b, 0x5c, + 0xd3, 0xae, 0x50, 0x7b, 0xab, 0x3e, 0x83, 0x41, 0x43, 0x3a, 0x3f, 0x3b, 0x89, 0xcf, 0xf7, 0x9b, + 0x41, 0x6d, 0x89, 0xeb, 0x7e, 0x73, 0xa8, 0x2d, 0x71, 0x4d, 0x7b, 0x1e, 0xb5, 0x25, 0xae, 0xfb, + 0xcd, 0xa2, 0xb6, 0xc4, 0x35, 0xed, 0xd9, 0xd4, 0xe6, 0x79, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0xbc, 0x96, 0xcf, 0x1b, 0x24, 0x65, 0x6e, 0xcd, 0x44, 0xba, 0x8d, + 0xb3, 0x86, 0xf2, 0xae, 0x16, 0x9c, 0x41, 0x6d, 0x89, 0x67, 0xc4, 0x73, 0xa8, 0x2d, 0x71, 0xb6, + 0x47, 0x1e, 0xb5, 0x25, 0xce, 0x64, 0xca, 0xa2, 0xb6, 0xc4, 0x59, 0x7a, 0xd9, 0xd4, 0x96, 0x38, + 0x03, 0xd5, 0x42, 0x6d, 0x89, 0xcf, 0xaa, 0x54, 0x4c, 0x6d, 0x89, 0x6b, 0x6c, 0xd2, 0xa8, 0x2d, + 0x71, 0xfd, 0x58, 0x19, 0xb5, 0x25, 0xae, 0x8d, 0xac, 0xa0, 0xb6, 0xc4, 0x75, 0xbf, 0x36, 0x6a, + 0x4b, 0x5c, 0xd3, 0x9e, 0x49, 0x6d, 0x89, 0xd7, 0x6b, 0xb0, 0x53, 0x5b, 0xe2, 0xb5, 0x48, 0x6a, + 0xa8, 0x2d, 0xf1, 0x3a, 0x3b, 0x26, 0x6a, 0xcb, 0x5b, 0x65, 0x3d, 0xe1, 0xa4, 0xb6, 0xbc, 0xda, + 0x26, 0x65, 0x3b, 0xd4, 0x66, 0x6d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x76, 0x26, 0xce, 0x06, 0x71, 0xd6, 0x70, 0x53, 0x67, 0x7b, 0x64, 0xd6, 0x71, 0x8e, 0x56, 0xde, + 0x4c, 0x26, 0x3b, 0xb5, 0x25, 0xce, 0xf6, 0xa8, 0xa1, 0xb6, 0xc4, 0x99, 0x4c, 0x26, 0x6a, 0x4b, + 0x9c, 0xed, 0xe1, 0xa4, 0xb6, 0xc4, 0x99, 0x4c, 0x0a, 0xb5, 0xb7, 0xea, 0x2a, 0x6b, 0x53, 0x3a, + 0x3f, 0x3b, 0x89, 0xcf, 0x1b, 0x99, 0x41, 0x6d, 0x89, 0xeb, 0x7e, 0x73, 0xa8, 0x2d, 0x71, 0x4d, + 0x7b, 0x1e, 0xb5, 0x25, 0xae, 0xfb, 0xcd, 0xa2, 0xb6, 0xc4, 0x35, 0xed, 0xd9, 0xd4, 0x96, 0xb8, + 0xee, 0xd7, 0x42, 0x6d, 0x89, 0x6b, 0xda, 0x8b, 0xa9, 0x2d, 0x71, 0xdd, 0x6f, 0x1a, 0xb5, 0x25, + 0xae, 0x69, 0x2f, 0xa3, 0xb6, 0xc4, 0x75, 0xbf, 0x15, 0xd4, 0x96, 0xb8, 0xa6, 0xdd, 0xb6, 0xb6, + 0x36, 0x6b, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x33, 0x71, 0x36, + 0x68, 0x8b, 0xcc, 0xf6, 0xc8, 0xae, 0xe7, 0xac, 0xa1, 0xbc, 0x99, 0x4c, 0x16, 0x6a, 0x4b, 0x9c, + 0xa5, 0x57, 0x4c, 0x6d, 0x89, 0x67, 0xc4, 0xd3, 0xa8, 0x2d, 0x71, 0xb6, 0x47, 0x19, 0xb5, 0x25, + 0xce, 0x64, 0xaa, 0xa0, 0xb6, 0xc4, 0x59, 0x7a, 0x36, 0x6a, 0x4b, 0x5c, 0x1b, 0x99, 0x49, 0x6d, + 0x89, 0xeb, 0x7e, 0xed, 0xd4, 0x96, 0xb8, 0xa6, 0xbd, 0x86, 0xda, 0x12, 0xaf, 0xd7, 0x60, 0xa2, + 0xb6, 0xb4, 0xda, 0x05, 0x3e, 0x27, 0xb5, 0xe5, 0xad, 0xb2, 0xf6, 0x29, 0xd4, 0xde, 0xa2, 0xab, + 0xac, 0xcd, 0xbe, 0x74, 0x7e, 0x76, 0x12, 0xd7, 0xfd, 0x66, 0x50, 0x5b, 0xe2, 0x9a, 0xf6, 0x1c, + 0x6a, 0x4b, 0x7c, 0x9e, 0xf6, 0x3c, 0x6a, 0x4b, 0x5c, 0x1b, 0x99, 0xb5, 0x3d, 0x6a, 0xb3, 0x36, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3b, 0xab, 0x7c, 0xff, 0xb5, 0x5b, + 0x1b, 0xa4, 0x73, 0x26, 0x6e, 0x69, 0x12, 0x9d, 0xc9, 0xce, 0x49, 0x4f, 0x29, 0xa9, 0x4d, 0x3e, + 0x27, 0xa9, 0xb7, 0xd8, 0x2c, 0xa3, 0xa5, 0x59, 0x2f, 0xe9, 0xfc, 0xe4, 0xe4, 0xdc, 0x49, 0xcc, + 0xbe, 0x0c, 0x52, 0x4b, 0x1a, 0xfa, 0x4d, 0x39, 0xa4, 0x96, 0x94, 0x7a, 0x22, 0x8f, 0xd4, 0x92, + 0x52, 0x37, 0x64, 0x91, 0x5a, 0xd2, 0x58, 0xdd, 0x90, 0x4d, 0x6a, 0x49, 0x5b, 0xb5, 0xdb, 0x42, + 0x6a, 0x49, 0xa9, 0x9b, 0x8b, 0x49, 0x2d, 0x69, 0x00, 0x09, 0xa7, 0x91, 0x5a, 0x52, 0xea, 0x89, + 0x32, 0x52, 0x4b, 0x1a, 0x40, 0xec, 0x15, 0xa4, 0x96, 0x94, 0xba, 0xcc, 0x46, 0x6a, 0x49, 0x03, + 0x88, 0x3b, 0x93, 0xd4, 0x92, 0x52, 0x37, 0xdb, 0x49, 0x2d, 0x69, 0x00, 0xc9, 0xac, 0xd9, 0xca, + 0xa9, 0xc5, 0xd9, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, 0x27, 0xce, + 0x36, 0x6c, 0xe7, 0x93, 0x41, 0x65, 0xee, 0xa3, 0xb9, 0x9c, 0x77, 0x93, 0x92, 0xfa, 0x8b, 0x86, + 0x4a, 0x52, 0x4b, 0xda, 0xaa, 0x1b, 0xaa, 0x49, 0x2d, 0x29, 0xf5, 0xc4, 0x6e, 0x52, 0x4b, 0x4a, + 0x6d, 0x3a, 0x4d, 0x6a, 0x49, 0x63, 0xb5, 0xaf, 0x96, 0xd4, 0x92, 0xb6, 0x6a, 0x9f, 0x99, 0xd4, + 0x72, 0x52, 0x97, 0xa7, 0xb5, 0x92, 0x7a, 0x4b, 0xae, 0xc6, 0x2c, 0x4b, 0xdb, 0xc1, 0x4f, 0x4e, + 0xd2, 0x78, 0x94, 0xb9, 0x93, 0xd4, 0x92, 0x7e, 0xcb, 0x36, 0xe7, 0x92, 0x5a, 0x52, 0x6a, 0xf7, + 0x21, 0x52, 0x4b, 0x1a, 0x40, 0xca, 0xf6, 0x92, 0x5a, 0x52, 0x6a, 0xfb, 0x3e, 0x52, 0x4b, 0x1a, + 0x40, 0x26, 0xac, 0xa4, 0x96, 0x94, 0x3a, 0x5c, 0x42, 0x6a, 0x49, 0x03, 0x48, 0xf3, 0x07, 0xaf, + 0x53, 0x6a, 0xd6, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe4, 0x88, 0xb3, + 0x0d, 0x9c, 0x0c, 0x5a, 0x3d, 0x1d, 0xe5, 0xd0, 0x41, 0xce, 0xbb, 0x49, 0x3a, 0x71, 0xbf, 0x97, + 0xd4, 0xb2, 0xa6, 0xa3, 0xec, 0x23, 0xb5, 0xac, 0x13, 0xf7, 0x56, 0x52, 0xcb, 0x9a, 0x8e, 0x52, + 0x42, 0x6a, 0x59, 0x4b, 0x04, 0x3f, 0x20, 0xb5, 0xac, 0xe9, 0x28, 0x47, 0x49, 0x2d, 0x6b, 0x89, + 0x60, 0x25, 0xa9, 0x65, 0x2d, 0x7c, 0xad, 0x26, 0xb5, 0xac, 0x25, 0x82, 0xbb, 0x49, 0x2d, 0x6b, + 0xe1, 0xeb, 0x69, 0x52, 0xcb, 0x5a, 0x22, 0x58, 0x4b, 0x6a, 0x59, 0x0b, 0x5f, 0xcd, 0xa4, 0x96, + 0xb4, 0x1a, 0x33, 0xb3, 0x95, 0xd4, 0x5b, 0x73, 0x35, 0x66, 0xe6, 0x0e, 0x7e, 0x72, 0x92, 0x86, + 0xfe, 0xb4, 0x9d, 0xa4, 0x96, 0xb5, 0x44, 0x30, 0x77, 0x33, 0x53, 0xb3, 0xb6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x47, 0x9c, 0x6d, 0xf8, 0x91, 0x4d, 0x47, 0xa9, 0xcd, + 0xe7, 0x44, 0x99, 0xa4, 0x49, 0x56, 0x66, 0x52, 0xcb, 0x49, 0x7d, 0xb4, 0xb9, 0x95, 0xd4, 0x5b, + 0x72, 0x8e, 0xc4, 0x17, 0xcd, 0x3b, 0xf8, 0xc9, 0xc9, 0x3a, 0x71, 0xbf, 0x93, 0xd4, 0xb2, 0xa6, + 0xa3, 0xe4, 0x92, 0x5a, 0xd6, 0x75, 0xd8, 0x0f, 0x91, 0x5a, 0xd6, 0x62, 0xaa, 0xbd, 0xa4, 0x96, + 0xb5, 0x44, 0x70, 0x1f, 0xa9, 0x65, 0x2d, 0x7c, 0xb5, 0x92, 0x5a, 0xd6, 0x72, 0xee, 0x12, 0x52, + 0xcb, 0x5a, 0x4c, 0xf5, 0x01, 0xa9, 0x65, 0x2d, 0x11, 0x3c, 0x4a, 0x6a, 0x59, 0x0b, 0x5f, 0x2b, + 0x49, 0x2d, 0x6b, 0x39, 0x77, 0x35, 0xa9, 0x65, 0x2d, 0xa6, 0xda, 0x4d, 0x6a, 0x59, 0x4b, 0x04, + 0x4f, 0xbf, 0xc2, 0xd4, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, + 0x11, 0x67, 0x1b, 0x38, 0x0f, 0x94, 0xf0, 0xc4, 0xfd, 0x07, 0x47, 0x38, 0xef, 0x26, 0x69, 0x3a, + 0xca, 0x51, 0x52, 0xcb, 0x3a, 0x71, 0x5f, 0x49, 0x6a, 0x59, 0xd3, 0x51, 0xaa, 0x49, 0x2d, 0xeb, + 0xc4, 0xfd, 0x6e, 0x52, 0xcb, 0x9a, 0x8e, 0x72, 0x9a, 0xd4, 0xb2, 0x96, 0x08, 0xd6, 0x92, 0x5a, + 0xd6, 0xc2, 0x57, 0x33, 0xa9, 0x25, 0xad, 0xc6, 0x74, 0xb7, 0x92, 0x7a, 0x6b, 0xae, 0xc6, 0x74, + 0xef, 0xe0, 0x27, 0x27, 0xeb, 0x59, 0x04, 0x77, 0x92, 0x5a, 0xd6, 0x12, 0xc1, 0x5c, 0x52, 0xcb, + 0x5a, 0xf8, 0x7a, 0x88, 0xd4, 0xb2, 0x96, 0x08, 0xee, 0x25, 0xb5, 0xac, 0x85, 0xaf, 0xfb, 0x48, + 0x2d, 0x6b, 0x89, 0xa0, 0x95, 0xd4, 0xb2, 0x16, 0xbe, 0x96, 0xbc, 0xc4, 0xd4, 0xac, 0x6d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x11, 0x67, 0x1b, 0x4c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x8c, 0xb5, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x39, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, + 0x61, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0e, 0x6b, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x72, 0x58, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x92, 0xc3, 0xda, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x1c, 0xd6, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe4, 0xb0, 0xb6, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x87, 0xb5, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x39, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc9, 0x61, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0e, + 0x6b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x72, 0x58, 0xdb, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xc8, 0xa1, 0xc3, 0x39, 0x79, 0x1f, 0x7f, 0x76, + 0xe0, 0x37, 0x4b, 0x6f, 0xa7, 0xa6, 0xfc, 0xfd, 0xca, 0x7b, 0x7f, 0xab, 0xf9, 0xde, 0xdf, 0xad, + 0x7d, 0xef, 0xbf, 0x1d, 0xf9, 0x34, 0x3f, 0xc7, 0x7c, 0x60, 0xd5, 0x6d, 0xbe, 0x9f, 0x4a, 0xd7, + 0x94, 0x14, 0x73, 0xce, 0x27, 0x19, 0x39, 0x39, 0x2b, 0x6f, 0xa7, 0xbe, 0x99, 0xf1, 0x7f, 0x5a, + 0x61, 0x2e, 0xee, 0x51, 0x5f, 0xfc, 0x24, 0xe5, 0xef, 0x16, 0xdf, 0x34, 0x1a, 0x52, 0xdf, 0x78, + 0xf3, 0xad, 0x14, 0xf1, 0xe2, 0x6d, 0xc3, 0x3b, 0x3f, 0x8f, 0xfb, 0xf0, 0x5f, 0x88, 0x17, 0x6f, + 0xa6, 0xa4, 0xfe, 0x32, 0x7a, 0x9b, 0x7b, 0xc4, 0x2d, 0xfe, 0x6a, 0x83, 0x8c, 0x1b, 0x94, 0xf2, + 0x1f, 0xe2, 0xeb, 0xc0, 0x8f, 0x52, 0xec, 0xf6, 0xf6, 0xe6, 0xf2, 0x9d, 0x7d, 0xc5, 0x3b, 0xba, + 0x1b, 0xfd, 0xb3, 0x45, 0x17, 0xdf, 0x5a, 0x7e, 0x8f, 0xf1, 0xd9, 0xb3, 0xd4, 0xd4, 0xd4, 0x1a, + 0xca, 0x02, 0xdb, 0xdf, 0x1b, 0xef, 0xfd, 0xe4, 0x9d, 0x94, 0xf7, 0xde, 0x52, 0xff, 0xf7, 0xf6, + 0x7b, 0x6f, 0x1a, 0x53, 0xde, 0x7d, 0xeb, 0xdd, 0x37, 0xde, 0x4b, 0x79, 0xe7, 0xed, 0x9f, 0x3f, + 0x4b, 0x79, 0xb6, 0x3c, 0x8c, 0xc4, 0xbf, 0xfe, 0xec, 0x39, 0x5f, 0x8f, 0xbf, 0x9d, 0x14, 0xe3, + 0xaf, 0xc4, 0xff, 0x17, 0xde, 0x5e, 0x7c, 0x65, 0x7d, 0xcf, 0xd6, 0xf9, 0xdf, 0xaa, 0x5f, 0xdf, + 0x4b, 0xbf, 0x45, 0x97, 0xde, 0x61, 0x5c, 0x7a, 0x7b, 0xf1, 0x57, 0xf5, 0x4f, 0x7e, 0xfa, 0xb3, + 0x77, 0x7f, 0xfe, 0x0b, 0xe3, 0x7b, 0xb1, 0xff, 0x44, 0xcc, 0x2f, 0xf4, 0x67, 0xc6, 0xa5, 0xdf, + 0xde, 0xff, 0xa9, 0x7e, 0xdd, 0xff, 0x9a, 0xba, 0xf0, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0x9d, 0x70, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8b, 0x32, 0x20, 0x29, 0xf4, + 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0xff, 0x8f, 0xb3, 0xff, + 0xd2, 0xad, 0x2d, 0xfe, 0xb9, 0xf4, 0x62, 0xf9, 0x8d, 0xe5, 0xf7, 0x2f, 0xfe, 0xa3, 0xab, 0xde, + 0x5e, 0xfe, 0xd3, 0xa8, 0x71, 0x7b, 0x4b, 0xb7, 0xb5, 0xfa, 0x1b, 0x5e, 0xfd, 0xde, 0x98, 0x7f, + 0xd7, 0x10, 0x77, 0x33, 0xcb, 0x5f, 0xcb, 0x66, 0x6c, 0x6d, 0x9b, 0xde, 0x7f, 0xe9, 0xeb, 0xd7, + 0xfb, 0x4f, 0xff, 0xe3, 0x8c, 0x31, 0xff, 0x2d, 0xff, 0xdd, 0xaa, 0x1f, 0x89, 0xf6, 0x6d, 0xad, + 0xe9, 0xb6, 0x70, 0x53, 0xba, 0x3d, 0x57, 0x3e, 0x6e, 0xe5, 0x65, 0xa2, 0xaf, 0xeb, 0x79, 0xbf, + 0xaf, 0x57, 0xbe, 0xfd, 0xeb, 0x6d, 0x5f, 0x1a, 0xdb, 0xd9, 0xda, 0xef, 0x6b, 0xe1, 0xf6, 0x57, + 0xfe, 0x7c, 0xbe, 0xef, 0x79, 0xe5, 0x6d, 0xa3, 0x71, 0xbd, 0x6e, 0xab, 0x3f, 0x23, 0xc1, 0xcf, + 0xd1, 0xa0, 0x79, 0xff, 0x5a, 0xe7, 0xfb, 0x7a, 0xc5, 0xfd, 0x37, 0xfc, 0xf9, 0xf1, 0xfd, 0x0d, + 0xc6, 0xc5, 0x8d, 0x7d, 0xe9, 0x4f, 0x9d, 0xff, 0x8c, 0x9a, 0xc3, 0x83, 0x31, 0x6e, 0xfb, 0x8e, + 0x7d, 0x7f, 0xfc, 0x80, 0xb6, 0x4e, 0xff, 0xb8, 0x9b, 0x79, 0x09, 0xe3, 0xf2, 0x6b, 0xbc, 0xfd, + 0xaf, 0x1d, 0xff, 0x13, 0xf5, 0x4f, 0xd4, 0x4d, 0xeb, 0xe7, 0x1c, 0xbb, 0xed, 0xc7, 0x8e, 0x3f, + 0x06, 0xed, 0xf1, 0xff, 0x85, 0xbe, 0xaf, 0xad, 0x3b, 0xfe, 0xeb, 0xf6, 0x8f, 0x1d, 0xff, 0x75, + 0xf2, 0x68, 0x8f, 0x1b, 0xfa, 0x5f, 0x87, 0xf6, 0xf8, 0xbf, 0x66, 0x7f, 0xc0, 0xb0, 0x05, 0xc7, + 0xff, 0x4d, 0xdf, 0xff, 0x59, 0xbd, 0x9d, 0x6f, 0x7c, 0xff, 0x27, 0x6e, 0xbf, 0x46, 0x77, 0xfb, + 0x5d, 0x79, 0xf7, 0x26, 0xec, 0x00, 0xb1, 0xff, 0xcf, 0xfe, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0xff, 0xad, 0xd6, 0x3f, 0xe6, 0xf1, 0xa6, + 0xde, 0x71, 0xaf, 0x35, 0x8f, 0xf6, 0x35, 0x3e, 0x3f, 0xfe, 0xf8, 0xf0, 0xc2, 0x2b, 0x2b, 0x7f, + 0x1a, 0xb4, 0x1f, 0xe0, 0xeb, 0x3e, 0x8e, 0xd5, 0x3c, 0x7a, 0xf9, 0x02, 0xe7, 0x01, 0xb4, 0x1f, + 0x6f, 0x1b, 0x75, 0x0e, 0x00, 0xae, 0xf9, 0x7b, 0x8d, 0xef, 0xe3, 0x65, 0xf7, 0x8f, 0x3d, 0xde, + 0xbe, 0x74, 0xe8, 0x40, 0xff, 0xb8, 0xbb, 0xd1, 0x90, 0xe8, 0xb8, 0x98, 0xd6, 0x71, 0x19, 0x83, + 0xc6, 0xe7, 0x6d, 0xf4, 0xf3, 0xe3, 0xfb, 0x27, 0x7b, 0x1e, 0x20, 0xfe, 0xd6, 0x63, 0x3f, 0x5e, + 0x6b, 0x5b, 0x8c, 0x3b, 0xb8, 0xf1, 0x12, 0xfb, 0xaf, 0xde, 0x10, 0xe3, 0x8f, 0x07, 0x6b, 0x1c, + 0x37, 0x4e, 0x7c, 0xfc, 0x59, 0xf3, 0xb8, 0x7c, 0xa2, 0x71, 0x4f, 0xe7, 0x18, 0x9e, 0xc6, 0x59, + 0x98, 0x17, 0x3f, 0x0f, 0x90, 0xa8, 0xbf, 0xc1, 0xf0, 0x2a, 0xfb, 0xc7, 0xdd, 0x3f, 0x0d, 0xda, + 0xc7, 0xe3, 0x97, 0xc7, 0x11, 0xa3, 0xd6, 0xf8, 0xa3, 0x37, 0x7e, 0xac, 0x3a, 0xce, 0x6c, 0xd4, + 0x3e, 0xc0, 0xa8, 0xf1, 0xf9, 0xc6, 0xf5, 0xc7, 0x9f, 0x8d, 0x9f, 0x07, 0x48, 0xfc, 0x75, 0x19, + 0x74, 0x0e, 0xff, 0xc5, 0xde, 0xbc, 0xe6, 0x30, 0xf5, 0x12, 0xc7, 0x9f, 0xd5, 0xe7, 0xad, 0xb4, + 0x87, 0x67, 0xfd, 0x63, 0xea, 0xb1, 0xdf, 0xb9, 0xee, 0x76, 0xb6, 0x81, 0xed, 0x7f, 0xbd, 0x2d, + 0xf4, 0x85, 0xcf, 0x03, 0xe8, 0xdc, 0xba, 0xde, 0xeb, 0x89, 0xb7, 0x82, 0x4d, 0x19, 0xff, 0x0d, + 0x3a, 0xe3, 0x7f, 0xdc, 0x79, 0x5b, 0x83, 0xe6, 0xe7, 0xc7, 0x8e, 0xbf, 0x1b, 0xeb, 0xff, 0xa2, + 0xe3, 0xff, 0x46, 0xcf, 0x03, 0xac, 0xd7, 0x3f, 0xc1, 0xf8, 0xbf, 0xe6, 0x4b, 0xde, 0xac, 0xfe, + 0xeb, 0xef, 0xff, 0x68, 0x9f, 0x5f, 0x89, 0xff, 0xfc, 0xd8, 0xfb, 0xf3, 0xda, 0xe3, 0xef, 0xcf, + 0xbb, 0xff, 0xa3, 0xb3, 0xdf, 0xf1, 0xdc, 0xe7, 0x01, 0x8c, 0x3a, 0xfb, 0x53, 0xfa, 0xfb, 0x3f, + 0x5a, 0xe3, 0xc2, 0xe6, 0xed, 0xff, 0x80, 0xc7, 0x5f, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, + 0x1f, 0xf4, 0xa7, 0x3f, 0x36, 0xb7, 0x7f, 0xfc, 0xfc, 0xfb, 0xb8, 0xe3, 0x65, 0x06, 0x7e, 0x4c, + 0x9b, 0xd9, 0x3f, 0xa6, 0xf1, 0xca, 0xe3, 0x7a, 0xcd, 0xf9, 0xc7, 0xd8, 0xdc, 0xfe, 0x49, 0xce, + 0x47, 0xa5, 0x7f, 0x12, 0xe3, 0x4f, 0xec, 0x71, 0xb2, 0x4d, 0x5c, 0xb7, 0x43, 0xff, 0x98, 0xe3, + 0xfc, 0x7a, 0xdb, 0x3f, 0x5b, 0xff, 0xa6, 0x8f, 0x3f, 0x71, 0xc7, 0xb7, 0xd7, 0x1e, 0xff, 0xd7, + 0x3b, 0x43, 0x87, 0x97, 0x3b, 0xfe, 0xaf, 0x1d, 0x77, 0x56, 0x86, 0x1d, 0xfa, 0xb3, 0xff, 0xbf, + 0x6d, 0xfb, 0xf3, 0x73, 0xa0, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, + 0x79, 0xfc, 0x05, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, + 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, + 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0x14, 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, + 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, + 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, + 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, + 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, + 0xfe, 0x14, 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, + 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, + 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, + 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, + 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0x14, + 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, + 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, + 0xfe, 0xf4, 0xa7, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3e, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x41, 0x9f, 0xfd, 0xd1, 0x74, 0x60, + 0xf5, 0xdb, 0xa9, 0x29, 0xff, 0xb8, 0xf0, 0xca, 0x27, 0xbb, 0xff, 0x25, 0xef, 0x40, 0xde, 0xbf, + 0x7f, 0xfc, 0xc9, 0xc1, 0x23, 0x8b, 0x7f, 0xf5, 0x0f, 0xe2, 0x45, 0xc1, 0xc7, 0x7f, 0x3a, 0xf0, + 0xa7, 0xc3, 0xf9, 0x05, 0x2b, 0x1f, 0xff, 0xbe, 0x78, 0x99, 0xfa, 0xe9, 0xc7, 0x05, 0x1f, 0x1f, + 0x39, 0x50, 0x50, 0xb0, 0x74, 0x63, 0xa9, 0x6f, 0x7f, 0xa1, 0xfd, 0x0f, 0x3e, 0x5b, 0xa4, 0xfd, + 0xb7, 0xff, 0xfb, 0xd3, 0x85, 0x3f, 0xff, 0xe7, 0xdd, 0x94, 0x94, 0xc7, 0xa9, 0x31, 0x7f, 0x79, + 0xf0, 0x80, 0xe5, 0x0f, 0x87, 0x3f, 0xce, 0xff, 0x74, 0xe5, 0xdf, 0x3e, 0x2d, 0xa1, 0x50, 0xee, + 0x61, 0x8b, 0xf8, 0x86, 0xff, 0x79, 0xe5, 0x3d, 0x22, 0x44, 0xaa, 0xfa, 0xee, 0x23, 0x05, 0x39, + 0x9f, 0x1c, 0x5c, 0x7a, 0x7f, 0xea, 0x1b, 0xef, 0xaf, 0xfe, 0xf0, 0xdf, 0xe8, 0x7c, 0xf8, 0x6f, + 0x62, 0x3e, 0xdc, 0x74, 0xe4, 0x40, 0xbe, 0x46, 0xcf, 0x94, 0x4f, 0x0f, 0xfc, 0xc1, 0xf4, 0xd9, + 0x67, 0x07, 0xf2, 0x57, 0x7e, 0x30, 0xff, 0xf4, 0x5f, 0xa9, 0x29, 0x7f, 0xfb, 0xdd, 0x7f, 0xa7, + 0x9e, 0x7a, 0x5b, 0x7d, 0xe3, 0x6f, 0x52, 0xd9, 0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x7e, 0xb8, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, 0x65, 0x40, 0x52, 0xe8, 0x4f, 0x7f, + 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0xff, 0x1f, 0x67, 0xff, 0xa5, 0x5b, + 0x5b, 0xfc, 0x73, 0xe9, 0xc5, 0xf2, 0x1b, 0xcb, 0xef, 0x5f, 0xfc, 0x47, 0x57, 0xbd, 0xbd, 0xfc, + 0xa7, 0x51, 0xe3, 0xf6, 0x96, 0x6e, 0x6b, 0xf5, 0x37, 0xbc, 0xfa, 0xbd, 0x31, 0xff, 0xae, 0x21, + 0xee, 0x66, 0x96, 0xbf, 0x96, 0xcd, 0xd8, 0xda, 0x36, 0xbd, 0xff, 0xd2, 0xd7, 0xaf, 0xf7, 0x9f, + 0xfe, 0xc7, 0x19, 0x63, 0xfe, 0x5b, 0xfe, 0xbb, 0x55, 0x3f, 0x12, 0xed, 0xdb, 0x5a, 0xd3, 0x6d, + 0xe1, 0xa6, 0x74, 0x7b, 0xae, 0x7c, 0xdc, 0xca, 0xcb, 0x44, 0x5f, 0xd7, 0xf3, 0x7e, 0x5f, 0xaf, + 0x7c, 0xfb, 0xd7, 0xdb, 0xbe, 0x34, 0xb6, 0xb3, 0xb5, 0xdf, 0xd7, 0xc2, 0xed, 0xaf, 0xfc, 0xf9, + 0x7c, 0xdf, 0xf3, 0xca, 0xdb, 0x46, 0xe3, 0x7a, 0xdd, 0x56, 0x7f, 0x46, 0x82, 0x9f, 0xa3, 0x41, + 0xf3, 0xfe, 0xb5, 0xce, 0xf7, 0xf5, 0x8a, 0xfb, 0x6f, 0xf8, 0xf3, 0xe3, 0xfb, 0x1b, 0x8c, 0x8b, + 0x1b, 0xfb, 0xd2, 0x9f, 0x3a, 0xff, 0x19, 0x35, 0x87, 0x07, 0x63, 0xdc, 0xf6, 0x1d, 0xfb, 0xfe, + 0xf8, 0x01, 0x6d, 0x9d, 0xfe, 0x71, 0x37, 0xf3, 0x12, 0xc6, 0xe5, 0xd7, 0x78, 0xfb, 0x5f, 0x3b, + 0xfe, 0x27, 0xea, 0x9f, 0xa8, 0x9b, 0xd6, 0xcf, 0x39, 0x76, 0xdb, 0x8f, 0x1d, 0x7f, 0x0c, 0xda, + 0xe3, 0xff, 0x0b, 0x7d, 0x5f, 0x5b, 0x77, 0xfc, 0xd7, 0xed, 0x1f, 0x3b, 0xfe, 0xeb, 0xe4, 0xd1, + 0x1e, 0x37, 0xf4, 0xbf, 0x0e, 0xed, 0xf1, 0x7f, 0xcd, 0xfe, 0x80, 0x61, 0x0b, 0x8e, 0xff, 0x9b, + 0xbe, 0xff, 0xb3, 0x7a, 0x3b, 0xdf, 0xf8, 0xfe, 0x4f, 0xdc, 0x7e, 0x8d, 0xee, 0xf6, 0xbb, 0xf2, + 0xee, 0x4d, 0xd8, 0x01, 0x62, 0xff, 0x9f, 0xfd, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0x5b, 0xad, 0x7f, 0xcc, 0xe3, 0x4d, 0xbd, 0xe3, + 0x5e, 0x6b, 0x1e, 0xed, 0x6b, 0x7c, 0x7e, 0xfc, 0xf1, 0xe1, 0x85, 0x57, 0x56, 0xfe, 0x34, 0x68, + 0x3f, 0xc0, 0xd7, 0x7d, 0x1c, 0xab, 0x79, 0xf4, 0xf2, 0x05, 0xce, 0x03, 0x68, 0x3f, 0xde, 0x36, + 0xea, 0x1c, 0x00, 0x5c, 0xf3, 0xf7, 0x1a, 0xdf, 0xc7, 0xcb, 0xee, 0x1f, 0x7b, 0xbc, 0x7d, 0xe9, + 0xd0, 0x81, 0xfe, 0x71, 0x77, 0xa3, 0x21, 0xd1, 0x71, 0x31, 0xad, 0xe3, 0x32, 0x06, 0x8d, 0xcf, + 0xdb, 0xe8, 0xe7, 0xc7, 0xf7, 0x4f, 0xf6, 0x3c, 0x40, 0xfc, 0xad, 0xc7, 0x7e, 0xbc, 0xd6, 0xb6, + 0x18, 0x77, 0x70, 0xe3, 0x25, 0xf6, 0x5f, 0xbd, 0x21, 0xc6, 0x1f, 0x0f, 0xd6, 0x38, 0x6e, 0x9c, + 0xf8, 0xf8, 0xb3, 0xe6, 0x71, 0xf9, 0x44, 0xe3, 0x9e, 0xce, 0x31, 0x3c, 0x8d, 0xb3, 0x30, 0x2f, + 0x7e, 0x1e, 0x20, 0x51, 0x7f, 0x83, 0xe1, 0x55, 0xf6, 0x8f, 0xbb, 0x7f, 0x1a, 0xb4, 0x8f, 0xc7, + 0x2f, 0x8f, 0x23, 0x46, 0xad, 0xf1, 0x47, 0x6f, 0xfc, 0x58, 0x75, 0x9c, 0xd9, 0xa8, 0x7d, 0x80, + 0x51, 0xe3, 0xf3, 0x8d, 0xeb, 0x8f, 0x3f, 0x1b, 0x3f, 0x0f, 0x90, 0xf8, 0xeb, 0x32, 0xe8, 0x1c, + 0xfe, 0x8b, 0xbd, 0x79, 0xcd, 0x61, 0xea, 0x25, 0x8e, 0x3f, 0xab, 0xcf, 0x5b, 0x69, 0x0f, 0xcf, + 0xfa, 0xc7, 0xd4, 0x63, 0xbf, 0x73, 0xdd, 0xed, 0x6c, 0x03, 0xdb, 0xff, 0x7a, 0x5b, 0xe8, 0x0b, + 0x9f, 0x07, 0xd0, 0xb9, 0x75, 0xbd, 0xd7, 0x13, 0x6f, 0x05, 0x9b, 0x32, 0xfe, 0x1b, 0x74, 0xc6, + 0xff, 0xb8, 0xf3, 0xb6, 0x06, 0xcd, 0xcf, 0x8f, 0x1d, 0x7f, 0x37, 0xd6, 0xff, 0x45, 0xc7, 0xff, + 0x8d, 0x9e, 0x07, 0x58, 0xaf, 0x7f, 0x82, 0xf1, 0x7f, 0xcd, 0x97, 0xbc, 0x59, 0xfd, 0xd7, 0xdf, + 0xff, 0xd1, 0x3e, 0xbf, 0x12, 0xff, 0xf9, 0xb1, 0xf7, 0xe7, 0xb5, 0xc7, 0xdf, 0x9f, 0x77, 0xff, + 0x47, 0x67, 0xbf, 0xe3, 0xb9, 0xcf, 0x03, 0x18, 0x75, 0xf6, 0xa7, 0xf4, 0xf7, 0x7f, 0xb4, 0xc6, + 0x85, 0xcd, 0xdb, 0xff, 0x01, 0x8f, 0xbf, 0xe8, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, + 0x4f, 0x7f, 0x6c, 0x6e, 0xff, 0xf8, 0xf9, 0xf7, 0x71, 0xc7, 0xcb, 0x0c, 0xfc, 0x98, 0x36, 0xb3, + 0x7f, 0x4c, 0xe3, 0x95, 0xc7, 0xf5, 0x9a, 0xf3, 0x8f, 0xb1, 0xb9, 0xfd, 0x93, 0x9c, 0x8f, 0x4a, + 0xff, 0x24, 0xc6, 0x9f, 0xd8, 0xe3, 0x64, 0x9b, 0xb8, 0x6e, 0x87, 0xfe, 0x31, 0xc7, 0xf9, 0xf5, + 0xb6, 0x7f, 0xb6, 0xfe, 0x4d, 0x1f, 0x7f, 0xe2, 0x8e, 0x6f, 0xaf, 0x3d, 0xfe, 0xaf, 0x77, 0x86, + 0x0e, 0x2f, 0x77, 0xfc, 0x5f, 0x3b, 0xee, 0xac, 0x0c, 0x3b, 0xf4, 0x67, 0xff, 0x7f, 0xdb, 0xf6, + 0xe7, 0xe7, 0x40, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xf3, 0xf8, + 0x0b, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, + 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, + 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, + 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0x29, 0x48, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, + 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, + 0xf4, 0x07, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, + 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, + 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0x29, + 0x48, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, + 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, + 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0x29, 0x48, 0x7f, + 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, + 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, + 0x4f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb9, 0x52, + 0xfe, 0x1f, 0xdc, 0xd1, 0x78, 0x32 }; diff --git a/docs/superpowers/notes/2026-05-27-phase-0-baseline.md b/docs/superpowers/notes/2026-05-27-phase-0-baseline.md new file mode 100644 index 00000000..b4fad74e --- /dev/null +++ b/docs/superpowers/notes/2026-05-27-phase-0-baseline.md @@ -0,0 +1,258 @@ +# Phase 0 — VICE 3.10 upgrade baseline findings + +**Date:** 2026-05-27 +**Branch:** vice-3.10-upgrade + +## Reference sources acquired + +- Vanilla VICE 3.1: `~/vice-ref/3.1/src/` (downloaded from SourceForge releases — vice-3.1.tar.gz) +- Vanilla VICE 3.10: `~/vice-ref/3.10/src/` (downloaded from SourceForge releases — vice-3.10.tar.gz) + +## Baseline diff summary + +Diff command: `diff -ruN ~/vice-ref/3.1/src/ src/Emulators/vice/` +Diff size: 2,715,007 lines (92 MB on disk) + +The large size is expected: the `-N` flag in `diff -ruN` treats absent files as empty, so files that exist on one side only each contribute their entire content as additions or deletions. There are no "Only in ..." summary lines — every difference is rendered as a full unified diff. + +Breakdown (using 1969-epoch timestamp as the marker for a file absent on that side): + +- Files only in slajerek's tree (new additions — ViceInterface/, root/ extras, arch/ extensions): **408** +- Files only in vanilla 3.1 (absent from slajerek's tree — removed, restructured, or renamed): **7,174** +- Files present in both trees but different (the real modification set): **524** +- Files with `c64d_` / RetroDebugger hook markers (C64DEBUGGER, c64d, RetroDebugger, RETRO_DEBUGGER) in the canonical hook directories: **67** + +Note: The expected 96 from the spec was not reached — the grep covered only 7 directories +(`c64/`, `drive/`, `monitor/`, `core/`, `root/`, `arch/`, `viciisc/`). The 67 count is correct +for those directories. Additional hook-carrying files may exist in other subdirectories not yet +surveyed (e.g., `sound/`, `resid/`). + +The high "only in vanilla" count (7,174) reflects that slajerek's tree is a subset of vanilla +VICE: many platform/architecture/machine targets from the vanilla source (CBM-II, PET, VIC20, +Plus/4, C128, DTV, SCPU, etc.) were removed or not carried over. The in-tree `src/Emulators/vice/` +is scoped to the C64 + drive + monitor stack. + +## Spot-check of modification style + +Three representative files were diffed against their vanilla 3.1 counterparts: + +### `c64/cart/reu.c` — 268 lines of diff + +Additions (+79), Deletions (-24). The deletions are **not** functional removals — they are: +- `#include "types.h"` replaced by `#include "vicetypes.h"` (renamed header) +- `static` qualifier removed from several functions to expose them for external linkage (e.g., + `set_reu_enabled`, `set_reu_size`, `set_reu_filename`) — these become callable from ViceInterface +- One `static int reu_enabled` made `volatile int reu_enabled` + +Additions include: `#include "ViceWrapper.h"`, `LOGD(...)` debug log calls, and +`c64d_maincpu_clk++` increments inserted at two clock-bump sites in REU cycle functions. + +Pattern: mixed diff (both `+` and `-` lines), but the `-` lines are header renames and +`static`-to-public promotions, not logic deletions. + +### `drive/drive.c` — 199 lines of diff + +Additions (+138), Deletions (-1). The single deletion is `#include "types.h"` (replaced by +`#include "vicetypes.h"`). Everything else is pure addition: +- Two new fields initialized in `drive_init_structure`: `GCR_dirty_track_for_snapshot`, + `GCR_dirty_track_needs_refresh`, `P64_dirty_for_snapshot` +- Commented-out `LOGD` stubs (left as `//`) +- NULL-guard additions in `drive_gcr_data_writeback_all` before dereferencing `drive_context[i]` + and `drive` — these are safety patches, not control-flow changes +- 125-line block of new functions appended at end of file (beyond vanilla's last line) + +Pattern: almost entirely additive; the one `-` line is a header rename. + +### `monitor/monitor.c` — 186 lines of diff + +Additions (+41), Deletions (-9). Deletions are header rename (`types.h` → `vicetypes.h`) plus +`static` qualifier removal from `make_prompt`, `monitor_open`, `monitor_process`, `monitor_close` +(same pattern as reu.c — promoting internal functions to external linkage). A closing brace and +one `monitor_close(1)` call are also restructured. + +Additions include: `#include "DebuggerDefs.h"`, a new `execute_monitor_command_jump_trap` +function + trampoline inserted into `mon_jump`, and `c64d_set_debug_mode(DEBUGGER_MODE_RUNNING)` +calls in `mon_instructions_step`, `mon_instructions_next`, and `mon_instruction_return`. + +Pattern: mixed diff; deletions are `static`-removal and header renames, not logic deletions. + +**Overall modification style:** The dominant pattern across all three samples is: +1. Header rename: `types.h` → `vicetypes.h` (appears in every modified file) +2. `static` qualifier removal to expose functions +3. Pure additions: new `c64d_*` hook calls, `LOGD` debug traces, new functions appended at EOF +4. No original VICE logic is deleted or restructured — control flow is augmented, not replaced + +## MTEngineSDL coupling + +- MTEngineSDL location: `/Users/garion/develop/MTEngineSDL` + (CMakeLists references it as `../MTEngineSDL` relative to the RetroDebugger repo root; + the repo lives at `~/develop/MTEngineSDL`, not `~/Projects/MTEngineSDL`) +- Files referencing VICE internals: **7** (across 3 platform variants + 1 GUI file) +- Categories: + - 6 files: logging infrastructure only — `DBG_Log.h`/`.mm` (macOS), `DBG_Log.h`/`.cpp` (Linux), + `DBG_Log.h`/`.cpp` (Windows). These define three log-level bitmasks: + `DBGLVL_VICE_DEBUG (1<<23)`, `DBGLVL_VICE_MAIN (1<<24)`, `DBGLVL_VICE_VERBOSE (1<<25)`, + and the corresponding macros `LOGVD`, `LOGVM`, `LOGVV`. + - 1 file: `src/Engine/GUI/Helpers/CGuiViewDebugLog.cpp` — renders toggle switches for the + three VICE log levels in the engine's debug log UI. +- Concrete VICE symbols MTEngineSDL touches: **none**. MTEngineSDL references no VICE-internal + symbols, types, or headers. The VICE coupling is entirely in named log-level constants + (`DBGLVL_VICE_*`) that are defined within MTEngineSDL's own `DBG_Log.h`. These are + string-labelled log channels, not structural dependencies on VICE internals. +- Risk assessment: **Low**. Upgrading VICE from 3.1 to 3.10 requires zero changes to MTEngineSDL. + The log-level bitmasks are stable values with no tie to VICE version. No MTEngineSDL source file + includes any VICE header or references any `c64d_*`, `vicii_*`, `maincpu_*`, or `drive_*` + symbol. The only action needed is confirming MTEngineSDL is still at `../MTEngineSDL` relative + to the repo at build time (it is, at `~/develop/MTEngineSDL`). + +## Known surprises / open issues + +1. **`types.h` → `vicetypes.h` rename is pervasive.** Every modified vanilla VICE file replaces + `#include "types.h"` with `#include "vicetypes.h"`. This rename must be forward-ported + mechanically when replaying patches onto 3.10 — the 3.10 source may have a different type + header name or layout. + +2. **`static` promotions create ABI surface.** The pattern of removing `static` from previously + internal functions (to make them callable from ViceInterface) means those function signatures + are part of the upgrade contract. Phase 1 must catalog every such promotion. + +3. **7,174 "only in vanilla" entries.** The slajerek tree is a heavily stripped version of the + vanilla source. The diff is not a delta of a complete VICE install — it is a curated subset. + The 7,174 missing files are intentionally absent (other machine targets, autoconf infrastructure, + build tooling). Phase 4 should not attempt to restore these. + +4. **MTEngineSDL not at expected `~/Projects/MTEngineSDL` path.** CMakeLists says `../MTEngineSDL` + (relative to the repo at `~/Projects/RetroDebugger/`), which resolves to + `~/Projects/MTEngineSDL`. But the actual install is at `~/develop/MTEngineSDL`. This path + mismatch will cause a build failure unless the CMakeLists path or a symlink is corrected + before Phase 4 (the build phase). Track as a pre-build blocker. + +5. **c64d_ file count discrepancy (67 vs spec's ~96).** The 67 count covers 7 subdirectories. + The spec's ~96 likely includes additional directories not in the grep scope (e.g., `resid/`, + `sound/`, platform-specific files under `arch/`). Phase 1 should run the hook scan with a + wider glob. + +## Followup decisions for Phase 1 + +- Phase 1 hook catalog should grep all of `src/Emulators/vice/` recursively (not directory-by- + directory) to avoid missing hook files outside the 7 directories surveyed here. +- Phase 1 should specifically catalog every `static`-removal (function promotion) in addition + to `c64d_*` hook sites — these are implicit API surface. +- Phase 1 should note the `types.h`→`vicetypes.h` rename in each file, since this is a + mechanical change that will need automation when replaying patches onto 3.10. +- Before Phase 4 begins: resolve the MTEngineSDL path discrepancy (symlink or CMakeLists edit). + +## WebSocket regression suite baseline (3.1) + +Date captured: 2026-05-27 +RetroDebugger: 3.1 (slajerek's current fork) + +### Summary + +- Total tests: 30 +- Passed: 28 +- Skipped: 2 +- Failed: 0 (suite must be green to merge this plan) +- Suite wall time: 21.5 seconds + +### Skipped tests (3.1 baseline findings — Phase 4 fix targets) + +- **`test_load.py::test_load_nonexistent_file_does_not_crash`** — "Phase 4 bug: RD 3.1 closes the WebSocket with no close frame when load is given a nonexistent path — the bridge crashes instead of returning an error response. Baseline finding; fix needed before Phase 4." + - Phase 4 expected behavior: 3.10 should return a 4xx error response and keep the WebSocket connection alive. + +- **`test_input.py::test_key_down_accepted_by_api`** — dynamically skipped at runtime when KERNAL keyboard buffer is empty after key/down+up: "KERNAL keyboard buffer empty after key/down+up — known threading limitation: keyboard alarm_set() is called without LockMutex from the WebSocket handler thread (see module docstring). Flag for Phase 4: wrap key/down and key/up in LockMutex in CDebuggerServerApiVice.cpp." + - Phase 4 expected behavior: wrapping key/down and key/up in LockMutex in CDebuggerServerApiVice.cpp should make the KERNAL keyboard buffer reliably populated, and the buffer-level assertion should pass. + +### Behavioral notes captured in test code (preserved 3.1 contracts) + +These are NOT bugs — they are behaviors the suite EXPECTS, so we know if 3.10 changes them. + +- `makejmp` is queued, takes effect on next step_instruction +- `step/cycle` counter updates asynchronously, needs settle window +- `reset(hard=True)` from paused state keeps CPU paused +- `c64/cpu/memory/breakpoint/add` requires `comparison` + `value` params even for "any write" (e.g. `comparison=">="`, `value=0`) +- Async breakpoint-fired event frames pollute response stream (test_breakpoints uses local `_drain_events` helper) +- Chip endpoints: response wraps results in a `registers` key (not bare dict at `result`) +- CIA endpoint param is `num`, not `cia` +- Joystick endpoint uses `axis` (compass names like `"n"`, `"sw"`), not `direction` +- Keyboard endpoint uses `keyCode` (int, ASCII for letters) +- `cpu/counters/read` `cycle` counter resets to 0 asynchronously ~10-20ms after `cont()` is called — it is NOT monotonic across pause/cont boundaries; `reset(hard=True)` does NOT reset it +- VIC register map is serialized as a JSON array of `[reg_num, value]` pairs (not a plain dict) — due to nlohmann/json serialization of C++ unordered_map + +### Suite is the gate + +This is the behavior contract preserved through Phase 2 (refactor on 3.1) and +re-established during Phase 4 (3.10 integration). Any divergence is either: + +1. **A fix** — the test was wrong, update it +2. **An expected change** — 3.10 behaves differently for a documented reason + +The suite must run green before each merge gate during the upgrade. + +## Phase 0 + 0.5 + 1 closeout + +**Date completed:** 2026-05-27 + +### Artifacts produced + +- Branch `vice-3.10-upgrade` on origin (all commits pushed) +- `~/vice-ref/3.1/src/` — vanilla VICE 3.1 reference (outside repo) +- `~/vice-ref/3.10/src/` — vanilla VICE 3.10 reference (outside repo) +- `tests/websocket/` — pytest regression suite, 30 tests (28 pass / 2 skip), runtime ~21.5 s +- `tests/fixtures/known_state.{asm,prg,sym}` + `build.sh` — fixture infrastructure (park label = $0837) +- `tests/retrodebugger.py` — vendored WebSocket client +- `tests/run-ws-tests.sh` — suite runner +- `docs/vice-hook-surface.md` — Phase 1 catalog (1234 lines): 64 modified files, 633 call sites, 282 distinct `c64d_*` symbols, 15 hook categories, ~14 files with genuine non-additive changes + +### Catalog headline findings (drive the Phase 2-5 plan) + +- **"Essentially all additive" upheld with nuance.** ~50 of 64 files are pure additive. The large + apparent "deletion" counts in `c64cpusc.c` (166) and `drivecpu.c` (409) are **inline expansion** + of `mainc64cpu.c` / `6510core.c` into the host file (slajerek inlined the CPU core to inject + hooks), NOT removed logic. Verified directly: `c64cpusc.c` contains a "mainc64cpu.c starts here" + block and is 4357 lines. +- **Genuine non-additive patches** (confirmed against corrected ground-truth diff): `resid-filter.cpp` + (261 lines — 8580 SID filter section deleted, only 6581 kept), `soundsdl.c` (155 — audio callback + rewrite), `resid-sid.cpp` (89 — TTL/read-path behavior + waveform-callback ctor param), plus + smaller logic changes in `sid.c`, `joystick.c`, `keyboard.c`, `vsync.c`, `c64-snapshot.c`, + `ciacore.c`, and several `viciisc/` files. + +### Hardest 3.10 migration risks (from catalog) + +1. **CRITICAL — CPU inline expansion.** `c64cpusc.c` / `drivecpu.c` must be re-inlined from 3.10's + `mainc64cpu.c` / `6510core.c`, and 3.10 **removes `clkguard.c/.h`** which slajerek's tree uses + (`root/clkguard.c`). +2. **HIGH — soundsdl.c.** Moved to `arch/shared/sounddrv/soundsdl.c` in 3.10; callback structure differs. +3. **HIGH — monitor.** 3.10's `monitor.c` grew ~1000 lines; injection points must be re-identified. +4. **HIGH — c64memsc.c `mem_ram`.** slajerek converted it to a pointer; 3.10 reverts to a static array. + +### Phase 4 vanilla-path mapping cheat sheet + +When replaying patches, map a repo file to its vanilla equivalent as follows (verified 2026-05-27): + +| Repo path pattern | Vanilla 3.1 path | +|---|---| +| `src/Emulators/vice//` | `~/vice-ref/3.1/src//` (note the `src/` component) | +| `src/Emulators/vice/root/` | `~/vice-ref/3.1/src/` (slajerek's `root/` = vanilla top-level `src/`) | +| `src/Emulators/vice/resid/resid-.cpp` | `~/vice-ref/3.1/src/resid/.cc` (renamed: `resid-` prefix dropped, `.cpp`→`.cc`) | +| `src/Emulators/vice/resid-fp/residfp-.cpp` | check `~/vice-ref/3.1/src/resid-fp/` for the analogous `.cc` | + +A naive `diff` that drops the `src/` prefix or ignores the resid rename will silently skip files +(the `[ -f ]` guard treats a missing vanilla file as "all additive"). Use the mapping above. + +### Open issues for Phase 2 planning + +- **MTEngineSDL path mismatch** (pre-build blocker for Phase 4): CMakeLists expects `../MTEngineSDL` + → `~/Projects/MTEngineSDL`, but it lives at `~/develop/MTEngineSDL`. Symlink or CMakeLists edit needed. +- **2 skipped tests** are 3.1 bugs (load-crash, keyboard mutex race) — Phase 4 fix targets, listed above. +- **Async event-frame pollution** in the WebSocket stream — the client's `call()` can return an event + frame instead of the response. Currently worked around per-test (`_drain_events`); Phase 2/4 may + want to fix this in the shared `retrodebugger.py` client. + +### Phase 2 plan input + +The followup plan (Phases 2-5) should: +1. Begin with `VICE_HOOK_*` macro-family design driven by the catalog's 15 categories +2. Refactor on 3.1 in `src/Emulators/vice/`, keeping the regression suite green between every commit +3. Treat the CPU inline-expansion files and the ~14 non-additive patches as the high-risk set + requiring careful per-file handling, distinct from the mechanical additive-hook sweep diff --git a/docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md b/docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md new file mode 100644 index 00000000..27b2e1b1 --- /dev/null +++ b/docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md @@ -0,0 +1,472 @@ +# Phase 2 Step 1 — Call-Site Classification for RETRODEBUGGER Gating + +**Date:** 2026-05-27 +**Branch:** vice-3.10-phase-2 +**Task:** Classify every clean-additive `c64d_*` call site so a later step can route them through +gated `VICE_HOOK_*` macros. This document is the authoritative design input for Task 2 and all +conversion tasks. + +--- + +## Summary + +| Metric | Count | +|--------|-------| +| Candidate lines (grep output, all files, pre-filter) | **241** | +| Candidate lines (after definition-heuristic filter) | **152** | +| Distinct call symbols (injected into vanilla VICE) | **26** | +| Class 1 macros (see Class 1 table) | **36** (34 pure side-effect with OFF=`((void)0)` + 2 value-guards with OFF=`0`); 26 distinct symbols map to 36 macros because some symbols yield multiple op-variants (e.g. `c64d_maincpu_clk` → INC/DEC/ADD) | +| Class 2 — value-returning observer hooks | **0** (the 2 value-guards are folded into Class 1 with documented OFF=`0`) | +| Class 3 — functional insertions (newly promoted to excluded) | **5 symbols across 2 files** | +| Definition-only files (leave as-is) | **14** | +| Final include-file count (files to convert) | **20** | +| Final exclude-file count (15 original + 2 newly promoted) | **17** | + +**Key finding:** The four call sites flagged for extra scrutiny by the plan (`ciacore.c:1021`, +`vicii.c:783`, `via2d.c:480`, `via1d1541.c:343`) are ALL within `c64d_*` function DEFINITIONS, +not injected into vanilla VICE logic. They do not require macro-ization. Two files contain genuine +class-3 functional insertions and are promoted to the excluded set: `root/sound.c` and +`c64/patchrom.c`. + +--- + +## Final Include List — Files to Convert + +These files have injected call sites (class 1) that will be routed through `VICE_HOOK_*` macros. +No class-2 or class-3 sites were found in these files. + +| Directory | File | Symbols present | Notes | +|-----------|------|-----------------|-------| +| `c64/` | `c64cia1.c` | `c64d_cia1_register_written`, `c64d_cia1_write_value`, `c64d_cia1_register_read`, `c64d_cia1_read_value` | Global observer assignments; also contains `c64d_cia1_peek` definition | +| `c64/` | `c64cia2.c` | Same set for `cia2_` | Also contains `c64d_cia1_peek` and `c64d_cia2_peek` definitions | +| `c64/cart/` | `reu.c` | `c64d_maincpu_clk++` (×3) | Also contains `c64d_reu_io2_store` definition | +| `core/` | `ciacore.c` | `cia_context->c64d_irq_flag = 1`, `cia_context->c64d_irq_flag = 0` | Also contains `c64d_ciacore_peek`, `c64d_get_cia_context` definitions | +| `core/` | `flash040core.c` | `c64d_maincpu_clk--`, `c64d_maincpu_clk++` | | +| `core/` | `viacore.c` | `via_context->c64d_irq_flagged = 0` | Also contains `c64d_viacore_peek` definition | +| `drive/` | `drivemem.c` | `c64d_mark_drive1541_cell_read`, `c64d_mark_drive1541_cell_write` | | +| `drive/` | `rotation.c` | `c64d_mark_drive1541_contents_track_dirty` | | +| `drive/iec/` | `memiec.c` | `c64d_mark_drive1541_cell_read`, `c64d_mark_drive1541_cell_write` (×3 each) | Also contains many `c64d_*` definitions | +| `drive/iec/` | `via1d1541.c` | `c64d_mark_drive1541_cell_write`, `c64d_mark_drive1541_cell_read`, `c64d_is_debug_on_drive1541()`, `via_context->c64d_irq_flagged = 1` | Also contains `c64d_via1d1541_peek` etc. definitions | +| `drive/iecieee/` | `via2d.c` | `c64d_mark_drive1541_cell_write`, `c64d_mark_drive1541_cell_read` | Also contains `c64d_via2d_peek` etc. definitions | +| `monitor/` | `monitor.c` | `c64d_set_debug_mode` (×4) | | +| `root/` | `dma.c` | `c64d_maincpu_clk += num` | | +| `root/` | `machine.c` | `c64d_set_debug_mode` | | +| `root/` | `midi.c` | `c64d_maincpu_clk--`, `c64d_maincpu_clk++` | | +| `sid/` | `fastsid.c` | `c64d_is_receive_channels_data[]`, `c64d_sid_channels_data` | Observer-only path; SID output unaffected | +| `viciisc/` | `vicii.c` | `vicii.c64d_irq_flag = 0` | Also contains multiple `c64d_*` definitions | +| `viciisc/` | `vicii-cycle.c` | `c64d_c64_vicii_start_frame`, `c64d_c64_vicii_start_raster_line`, `c64d_c64_vicii_cycle`, `c64d_maincpu_clk++` | | +| `viciisc/` | `vicii-irq.c` | `vicii.c64d_irq_flag = 1` (×4) | | +| `arch/` | `uistatusbar.c` | `c64d_display_drive_led` | | +| `arch/` | `vsyncarch.c` | `c64d_display_speed` | | +| `arch/` | `video.c` | `c64d_refresh_screen` | | +| `arch/` | `uimon.c` | `c64d_uimon_print_line`, `c64d_uimon_print` | | +| `arch/` | `ui.c` | `c64d_is_cpu_in_jam_state = 1`, `c64d_show_message`, `c64d_set_debug_mode` | Also contains `c64d_is_cpu_in_jam_state` variable definition | +| `arch/` | `uimsgbox.c` | `c64d_show_message` | | +| `resid-fp/` | `residfp-sid.cpp` | `c64d_wave_attenuation`, `c64d_wave_shift` assignments; `c64d_is_receive_channels_data[]`; `c64d_sid_channels_data`; `voice[n].c64d_output` reads | Observer-only path; audio output unaffected | + +> **Note on arch/mousedrv.c:** Contains only a `c64d_mouse_set_position()` DEFINITION and a +> commented-out line. No live call sites to macro-ize. + +--- + +## Final Exclude List + +### Original 15 hard files (unchanged from plan) + +| File | Rationale | +|------|-----------| +| `c64/c64cpusc.c` | CPU inline-expansion with hooks throughout; non-additive inline of mainc64cpu.c | +| `drive/drivecpu.c` | Drive CPU inline-expansion; non-additive inline of 6510core.c | +| `sounddrv/soundsdl.c` | SDL audio callback substantially rewritten (non-additive) | +| `resid/resid-filter.cpp` | 8580 SID section (~180 lines) deleted; genuine non-additive deletion | +| `resid/resid-sid.cpp` | Multiple behavioral changes to read paths and bus_value_ttl | +| `c64/c64memsc.c` | `mem_ram` changed from static array to pointer (non-additive data decl) | +| `sid/sid.c` | `sid_read_chip()` return path restructured (control-flow change) | +| `sid/sid-snapshot.c` | Snapshot write gated on `c64d_get_sid_enable()` (functional insertion) | +| `root/vsync.c` | (per original plan; inspect before Phase 3 replay) | +| `root/keyboard.c` | (per original plan; inspect before Phase 3 replay) | +| `joyport/joystick.c` | `joystick_process_latch()` bypasses random alarm delay (functional) | +| `joyport/mouse.c` | (per original plan) | +| `c64/c64-snapshot.c` | (per original plan) | +| `viciisc/vicii-draw-cycle.c` | Sprite drawing wrapped in `if (c64d_skip_drawing_sprites == 0)` (functional) | +| `viciisc/viciitypes.h` | Struct field additions to `vicii_t`; cannot be macro-ized | + +### Newly promoted class-3 files (discovered in this analysis) + +#### `root/sound.c` — PROMOTED TO EXCLUDED + +**Rationale:** Contains multiple functional insertions that alter whether and how SID emulation runs: + +1. `c64d_setting_run_sid_emulation == 0` at line 1287 — gates the entire SID sample-generation + path in `sound_run_sound()`. If `RETRODEBUGGER` is off and this evaluates false (as it would + if the symbol is absent), SID never produces audio. This is NOT a pure observer. +2. `c64d_setting_run_sid_when_in_warp == 0` at line 1288 — controls SID emulation during warp + mode; same issue. +3. `c64d_sound_run_sound_when_paused()` call at line 1578 — replaces `sound_run_sound()` in the + pause path; this is slajerek's own function that drives SID from a fake delta_t. Gating it out + would break the pause-while-SID-plays feature but more importantly the else-branch is + fundamentally different from vanilla VICE. +4. `c64d_skip_sound_run_sound_in_sound_store` at line 1933 — gates `sound_run_sound()` in + `sound_store()`. If undefined/zero, the guard is always false and `sound_run_sound()` is + always called — this matches vanilla behavior. But the guard expression inverts when the + variable disappears. Class 3. +5. `c64d_lock_sound_mutex()` / `c64d_unlock_sound_mutex()` at lines 1277/1279 — synchronization + wrappers inserted into `sound_run_sound()`; these change thread safety behavior. + +`sound.c` also contains the DEFINITIONS `c64d_set_volume()`, `c64d_reset_sound_clk()`, and +`c64d_sound_run_sound_when_paused()` which should be left as-is. + +#### `c64/patchrom.c` — PROMOTED TO EXCLUDED + +**Rationale:** Contains functional insertions that modify ROM bytes during emulation: + +1. `c64d_un_patch_kernal_fast_boot()` at line 473 — called at the start of `patch_rom_idx()`, + restores previously patched KERNAL ROM bytes. This modifies emulator ROM state. +2. `c64d_patch_kernal_fast_boot()` at lines 486 and 538 — patches KERNAL ROM bytes `$FD84`/`$FD85` + to `$A0`/`$00` (a fast-boot bypass). This is a genuine KERNAL ROM modification that changes + how the C64 boots. Gating this out would cause the fast-boot patches to be permanently applied + or not applied, depending on the ordering — not safely gate-able. + +The `c64d_patch_kernal_fast_boot_flag` variable controls whether patching happens; the whole +mechanism is a debugger feature that alters ROM. This file must be handled in a later step. + +--- + +## Call-Site Shape → Macro Table + +Every distinct `c64d_*` symbol that appears as a **call site injected into vanilla VICE logic** +(not within a `c64d_*` function definition) is listed here with its class, proposed macro, and +expansions. + +### Class 1 — Side-Effect Hooks (OFF = `((void)0)`) + +| Symbol | Proposed Macro | ON Expansion | OFF Expansion | Representative file:line | Notes | +|--------|---------------|--------------|---------------|--------------------------|-------| +| `c64d_maincpu_clk++` | `VICE_HOOK_CPU_CLK_INC()` | `c64d_maincpu_clk++` | `((void)0)` | `reu.c:757`, `vicii-cycle.c:560`, `midi.c:331`, `flash040core.c:400` | Simple increment of global clock | +| `c64d_maincpu_clk--` | `VICE_HOOK_CPU_CLK_DEC()` | `c64d_maincpu_clk--` | `((void)0)` | `midi.c:327`, `flash040core.c:397` | Decrement for RMW correction | +| `c64d_maincpu_clk += num` | `VICE_HOOK_CPU_CLK_ADD(n)` | `c64d_maincpu_clk += (n)` | `((void)0)` | `dma.c:100` | DMA cycle addition | +| `c64d_mark_drive1541_cell_read(addr)` | `VICE_HOOK_DRIVE_CELL_READ(addr)` | `c64d_mark_drive1541_cell_read(addr)` | `((void)0)` | `memiec.c:59`, `via1d1541.c:71`, `drivemem.c:61` | Drive memory read tap | +| `c64d_mark_drive1541_cell_write(addr, val)` | `VICE_HOOK_DRIVE_CELL_WRITE(addr, val)` | `c64d_mark_drive1541_cell_write((addr), (val))` | `((void)0)` | `memiec.c:66`, `via1d1541.c:64`, `via2d.c:128`, `drivemem.c:68` | Drive memory write tap | +| `c64d_mark_drive1541_contents_track_dirty(track)` | `VICE_HOOK_DRIVE_TRACK_DIRTY(track)` | `c64d_mark_drive1541_contents_track_dirty(track)` | `((void)0)` | `rotation.c:260` | GCR dirty-flag notification | +| `c64d_c64_vicii_start_frame()` | `VICE_HOOK_VIC_START_FRAME()` | `c64d_c64_vicii_start_frame()` | `((void)0)` | `vicii-cycle.c:351` | VIC frame-start notification | +| `c64d_c64_vicii_start_raster_line(line)` | `VICE_HOOK_VIC_START_RASTER(line)` | `c64d_c64_vicii_start_raster_line(line)` | `((void)0)` | `vicii-cycle.c:352,361` | VIC raster-line notification | +| `c64d_c64_vicii_cycle()` | `VICE_HOOK_VIC_CYCLE()` | `c64d_c64_vicii_cycle()` | `((void)0)` | `vicii-cycle.c:538` | VIC cycle-end notification | +| `vicii.c64d_irq_flag = 0` | `VICE_HOOK_VIC_IRQ_FLAG_CLEAR()` | `vicii.c64d_irq_flag = 0` | `((void)0)` | `vicii.c:294` | VIC IRQ observer flag reset | +| `vicii.c64d_irq_flag = 1` | `VICE_HOOK_VIC_IRQ_FLAG_SET()` | `vicii.c64d_irq_flag = 1` | `((void)0)` | `vicii-irq.c:75,89,103,127` | VIC IRQ observer flag set | +| `cia_context->c64d_irq_flag = 1` | `VICE_HOOK_CIA_IRQ_FLAG_SET(ctx)` | `(ctx)->c64d_irq_flag = 1` | `((void)0)` | `ciacore.c:93` | CIA IRQ observer flag set | +| `cia_context->c64d_irq_flag = 0` | `VICE_HOOK_CIA_IRQ_FLAG_CLEAR(ctx)` | `(ctx)->c64d_irq_flag = 0` | `((void)0)` | `ciacore.c:1567` | CIA IRQ observer flag reset (in init) | +| `via_context->c64d_irq_flagged = 0` | `VICE_HOOK_VIA_IRQ_FLAG_CLEAR(ctx)` | `(ctx)->c64d_irq_flagged = 0` | `((void)0)` | `viacore.c:1227` | VIA IRQ observer flag reset | +| `via_context->c64d_irq_flagged = 1` | `VICE_HOOK_VIA_IRQ_FLAG_SET(ctx)` | `(ctx)->c64d_irq_flagged = 1` | `((void)0)` | `via1d1541.c:104` | VIA IRQ observer flag set (guarded by `c64d_is_debug_on_drive1541()`) | +| `c64d_cia1_register_written = addr & 0xf` | `VICE_HOOK_CIA1_REG_WRITTEN(addr)` | `c64d_cia1_register_written = (addr) & 0xf` | `((void)0)` | `c64cia1.c:81` | CIA1 last-written register observer | +| `c64d_cia1_write_value = data` | `VICE_HOOK_CIA1_WRITE_VALUE(val)` | `c64d_cia1_write_value = (val)` | `((void)0)` | `c64cia1.c:82` | CIA1 last-written value observer | +| `c64d_cia1_register_read = addr & 0xf` | `VICE_HOOK_CIA1_REG_READ(addr)` | `c64d_cia1_register_read = (addr) & 0xf` | `((void)0)` | `c64cia1.c:94` | CIA1 last-read register observer | +| `c64d_cia1_read_value = val` | `VICE_HOOK_CIA1_READ_VALUE(val)` | `c64d_cia1_read_value = (val)` | `((void)0)` | `c64cia1.c:95` | CIA1 last-read value observer | +| `c64d_cia2_register_written = addr & 0xf` | `VICE_HOOK_CIA2_REG_WRITTEN(addr)` | `c64d_cia2_register_written = (addr) & 0xf` | `((void)0)` | `c64cia2.c:72` | CIA2 variant | +| `c64d_cia2_write_value = data` | `VICE_HOOK_CIA2_WRITE_VALUE(val)` | `c64d_cia2_write_value = (val)` | `((void)0)` | `c64cia2.c:73` | CIA2 variant | +| `c64d_cia2_register_read = addr & 0xf` | `VICE_HOOK_CIA2_REG_READ(addr)` | `c64d_cia2_register_read = (addr) & 0xf` | `((void)0)` | `c64cia2.c:91` | CIA2 variant | +| `c64d_cia2_read_value = val` | `VICE_HOOK_CIA2_READ_VALUE(val)` | `c64d_cia2_read_value = (val)` | `((void)0)` | `c64cia2.c:92` | CIA2 variant | +| `c64d_set_debug_mode(mode)` | `VICE_HOOK_LIFECYCLE_DEBUG_MODE(mode)` | `c64d_set_debug_mode(mode)` | `((void)0)` | `monitor.c:1792,1815,1831,2385`, `machine.c:95`, `ui.c:436` | Debugger state notification | +| `c64d_is_cpu_in_jam_state = 1` | `VICE_HOOK_LIFECYCLE_JAM_FLAG()` | `c64d_is_cpu_in_jam_state = 1` | `((void)0)` | `ui.c:432` | CPU JAM flag for debugger | +| `c64d_show_message(msg)` | `VICE_HOOK_LIFECYCLE_MESSAGE(msg)` | `c64d_show_message(msg)` | `((void)0)` | `ui.c:434`, `uimsgbox.c:257` | Debugger message notification | +| `c64d_display_drive_led(n, p1, p2)` | `VICE_HOOK_INPUT_DRIVE_LED(n, p1, p2)` | `c64d_display_drive_led((n), (p1), (p2))` | `((void)0)` | `uistatusbar.c:223` | Drive LED status display | +| `c64d_display_speed(spd, fps)` | `VICE_HOOK_LIFECYCLE_SPEED(spd, fps)` | `c64d_display_speed((spd), (fps))` | `((void)0)` | `vsyncarch.c:82` | Speed/fps display notification | +| `c64d_refresh_screen()` | `VICE_HOOK_VIC_REFRESH_SCREEN()` | `c64d_refresh_screen()` | `((void)0)` | `video.c:732` | Screen refresh notification | +| `c64d_uimon_print_line(p)` | `VICE_HOOK_LIFECYCLE_UIMON_LINE(p)` | `c64d_uimon_print_line(p)` | `((void)0)` | `uimon.c:98` | Monitor output line | +| `c64d_uimon_print(p)` | `VICE_HOOK_LIFECYCLE_UIMON_PRINT(p)` | `c64d_uimon_print(p)` | `((void)0)` | `uimon.c:110` | Monitor output partial | +| `c64d_is_debug_on_drive1541()` (in if condition) | `VICE_HOOK_DRIVE_IS_DEBUG()` | `c64d_is_debug_on_drive1541()` | `0` | `via1d1541.c:102` | Guard for VIA IRQ flag; OFF=0 means flag is never set (safe: debug never active) | +| `c64d_is_receive_channels_data[chipNo]` (in if) | `VICE_HOOK_SID_IS_RECEIVING_CHANNELS(n)` | `c64d_is_receive_channels_data[(n)]` | `0` | `fastsid.c:790`, `residfp-sid.cpp:308` | Guard for channel data callback; OFF=0 skips callback safely | +| `c64d_sid_channels_data(no, v1, v2, v3, mix)` | `VICE_HOOK_SID_CHANNELS_DATA(no, v1, v2, v3, mix)` | `c64d_sid_channels_data((no),(v1),(v2),(v3),(mix))` | `((void)0)` | `fastsid.c:795`, `residfp-sid.cpp:311` | Per-voice audio data callback | +| `c64d_wave_attenuation = val` | `VICE_HOOK_SID_SET_WAVE_ATTENUATION(val)` | `c64d_wave_attenuation = (val)` | `((void)0)` | `residfp-sid.cpp:250,256` | Wave display correction factor | +| `c64d_wave_shift = val` | `VICE_HOOK_SID_SET_WAVE_SHIFT(val)` | `c64d_wave_shift = (val)` | `((void)0)` | `residfp-sid.cpp:251,257` | Wave display shift factor | + +### Class 2 — Value-Returning Observer Hooks + +**None identified.** All suspected class-2 sites (`ciacore.c:1021`, `vicii.c:783`, `via2d.c:480`, +`via1d1541.c:343`) are located WITHIN `c64d_*` function DEFINITIONS, not in injected call sites. +See detailed analysis below. + +### Class 3 — Functional Insertions (files promoted to excluded) + +| Symbol | File | Why functional | +|--------|------|----------------| +| `c64d_setting_run_sid_emulation` | `root/sound.c` | Gates SID sample generation entirely; removing it breaks audio | +| `c64d_setting_run_sid_when_in_warp` | `root/sound.c` | Gates SID during warp; same issue | +| `c64d_sound_run_sound_when_paused()` | `root/sound.c` | Replaces `sound_run_sound()` in pause path; functional substitution | +| `c64d_skip_sound_run_sound_in_sound_store` | `root/sound.c` | Guards `sound_run_sound()` in `sound_store()`; removing inverts the guard | +| `c64d_patch_kernal_fast_boot()` | `c64/patchrom.c` | Patches KERNAL ROM bytes (modifies emulation) | +| `c64d_un_patch_kernal_fast_boot()` | `c64/patchrom.c` | Restores KERNAL ROM bytes (modifies emulation) | + +--- + +## Special Notes on the Four Flagged Call Sites + +The plan asked for extra scrutiny on these four: + +### `ciacore.c:1021` — `value |= c64d_iecbus_cpu_peek_conf1()` + +**Classification: Definition context — NOT an injected call site.** + +This call is inside `c64d_ciacore_peek()`, which is itself a slajerek-added DEFINITION function +(comment: "// slaj: this is 'real' peek, no changes to c64 state, only reads"). The function is +never called from vanilla VICE logic; it is called by ViceInterface. The `c64d_iecbus_cpu_peek_conf1()` +function (defined in `iecbus/iecbus.c:228`) returns `iecbus.cpu_port` directly, without calling +`drive_cpu_execute_all()` — it was specifically created to avoid the side effects of the original +`iecbus_callback_read`. Not a class-3 site; this whole block is definition code. + +### `vicii.c:783` — `*cD800 = c64d_colorram_peek(0xD800) & 0x0F` + +**Classification: Definition context — NOT an injected call site.** + +This is inside `c64d_get_vic_colors()`, a slajerek-added DEFINITION function called by +ViceInterface. Not injected into vanilla VICE logic. + +### `via2d.c:480` — `BYTE byte = c64d_peek_via2d_prb(via_context)` + +**Classification: Definition context — NOT an injected call site.** + +This is inside `c64d_via2d_peek()`, a slajerek-added DEFINITION function. Not injected into +vanilla VICE logic. + +### `drive/iec/via1d1541.c:343` — `BYTE byte = c64d_peek_via1d1541_prb(via_context)` + +**Classification: Definition context — NOT an injected call site.** + +This is inside `c64d_via1d1541_peek()`, a slajerek-added DEFINITION function. Not injected into +vanilla VICE logic. + +**Result: Zero class-2 sites identified. Zero class-3 sites in the originally-clean files +(beyond the two newly promoted files).** + +--- + +## Definition Sites — Leave Untouched + +These files contain ONLY `c64d_*` function/variable definitions with no call-site injections into +vanilla VICE logic, or are header files with declarations/struct fields. They are left exactly +as-is in this MR. + +| File | `c64d_*` things defined | +|------|------------------------| +| `drive/drive.c` | `c64d_get_drive_context`, `c64d_get_drive_current_halftrack`, `c64d_get_drive_disk_image`, `c64d_get_drive_is_disk_attached`, `c64d_set_drive_half_track`, `c64d_set_drive_disk_memory`, `c64d_get_drive_disk_gcr`, `c64d_read_disk_image`, `c64d_disk_image_destroy` | +| `drive/drive-writeprotect.c` | `c64d_drive_writeprotect_sense_peek` | +| `drive/iec/memiec.c` | `c64d_peek_mem_drive_internal`, `c64d_peek_memory_drive_internal`, `c64d_copy_ram_memory_drive_internal`, `c64d_peek_whole_map_drive_internal`, `c64d_mem_ram_read_drive_internal`, `c64d_copy_mem_ram_drive_internal`, `c64d_mem_ram_write_drive_internal` (also has call sites — see include list) | +| `iecbus/iecbus.c` | `c64d_iecbus_cpu_peek_conf1`, `c64d_get_drivecpu_regs`, `c64d_peek_drive`, `c64d_peek_memory_drive`, `c64d_copy_ram_memory_drive`, `c64d_peek_whole_map_drive`, `c64d_mem_ram_read_drive`, `c64d_copy_mem_ram_drive`, `c64d_mem_ram_write_drive`, `c64d_drive_poke` | +| `core/ciacore.c` | `c64d_ciacore_peek`, `c64d_get_cia_context` (also has call sites — see include list) | +| `core/viacore.c` | `c64d_viacore_peek` (also has call site — see include list) | +| `c64/c64cia2.c` | `c64d_cia1_peek`, `c64d_cia2_peek` (also has call sites — see include list) | +| `c64/c64memrom.c` | `c64d_update_rom` | +| `c64/cart/c64-generic.c` | `c64d_peek_cart_roml`, `c64d_poke_cart_roml` | +| `c64/cart/reu.c` | `c64d_reu_io2_store` (also has call sites — see include list) | +| `root/interrupt.c` | `c64d_interrupt_drivecpu_trigger_trap` | +| `arch/mousedrv.c` | `c64d_mouse_set_position` | +| `drive/iec/via1d1541.c` | `c64d_via1d1541_peek`, `c64d_peek_via1d1541_pra`, `c64d_peek_via1d1541_prb` (also has call sites — see include list) | +| `drive/iecieee/via2d.c` | `c64d_peek_via2d_pra`, `c64d_peek_via2d_prb`, `c64d_via2d_peek` (also has call sites — see include list) | +| `root/sound.c` | `c64d_set_volume`, `c64d_reset_sound_clk`, `c64d_sound_run_sound_when_paused` (file promoted to excluded due to class-3 sites) | +| `viciisc/vicii.c` | `c64d_vicii_get_geometry`, `c64d_vicii_render_when_paused`, `c64d_fetch_phi1_type`, `c64d_get_vic_colors`, `c64d_get_vic_simple_state` (also has one call site — see include list) | +| `sid/sid-resources.c` | `c64d_sid_set_sampling_method`, `c64d_sid_set_emulate_filters`, `c64d_sid_set_passband`, `c64d_sid_set_filter_bias`, `c64d_sid_set_stereo`, `c64d_sid_set_stereo_address`, `c64d_sid_set_triple_address`, `c64d_sid_set_engine_model_direct` | + +### Header/declaration-only files + +These files contain only `extern` declarations or struct field additions; no code changes: + +| File | Content | +|------|---------| +| `root/cia.h` | `int c64d_irq_flag` field in `cia_context_t` struct | +| `root/via.h` | `int c64d_irq_flagged` field in `via_context_t` struct; `extern BYTE c64d_viacore_peek(...)` | +| `root/maincpu.h` | `extern CLOCK c64d_maincpu_clk` | +| `root/interrupt.h` | `extern CLOCK c64d_maincpu_clk` | +| `root/keyboard.h` | `void c64d_keyboard_keymap_clear()` declaration (file excluded) | +| `arch/ui.h` | `extern int c64d_is_cpu_in_jam_state` | +| `drive/viad.h` | `extern BYTE c64d_via2d_peek(...)` | +| `drive/iec/via1d1541.h` | `extern BYTE c64d_via1d1541_peek(...)` | +| `sid/sid-resources.h` | `extern` declarations for the sid-resources functions | +| `resid/resid-sid.h` | `SID(void *c64d_waveform_callback)` constructor parameter | +| `resid/resid-filter.h` | `void *c64d_waveform_callback` field; inline filter function with `c64d_sid_channels_data` call (class 1 hook inside inline function in header) | +| `resid-fp/residfp-sid.h` | `float c64d_wave_attenuation`, `float c64d_wave_shift` fields in SIDFP class | +| `resid-fp/residfp-voice.h` | `float c64d_output` field in VoiceFP class; assignment in inline `output()` method | + +> **Note on `resid/resid-filter.h` and `resid-fp/residfp-voice.h`:** These headers contain inline +> C++ function bodies with `c64d_*` usage. The `resid-filter.h` inline function calls +> `c64d_sid_channels_data` as a class-1 side-effect observer. The `residfp-voice.h` inline +> function assigns to `c64d_output` which is a struct field used for waveform capture — the +> actual return value is `c64d_output` (same value, using the field as the local variable). +> Both are observer-only. These headers are included by `resid-fp/residfp-sid.cpp` (in include +> list) and by the excluded `resid/resid-filter.cpp` / `resid/resid-sid.cpp` respectively. +> The headers themselves need the `c64d_*` symbols to compile; they do NOT need macro-ization +> since they are internal to slajerek's additions. + +--- + +## Macro Naming Rationalization + +The 30+ distinct symbol shapes can be grouped into areas. The following table maps area names to +macro prefixes for Task 2: + +| Area | Prefix | Symbols covered | +|------|--------|-----------------| +| CPU clock | `VICE_HOOK_CPU_CLK_*` | `c64d_maincpu_clk` increments/decrements/additions | +| Drive cell access | `VICE_HOOK_DRIVE_CELL_*` | `c64d_mark_drive1541_cell_read/write` | +| Drive state | `VICE_HOOK_DRIVE_*` | `c64d_mark_drive1541_contents_track_dirty`, `c64d_is_debug_on_drive1541` | +| CIA observer | `VICE_HOOK_CIA1_*`, `VICE_HOOK_CIA2_*`, `VICE_HOOK_CIA_IRQ_*` | CIA register/value globals, IRQ flag | +| VIA observer | `VICE_HOOK_VIA_IRQ_*` | VIA IRQ flag | +| VIC observer | `VICE_HOOK_VIC_*` | VIC cycle, raster, frame, IRQ flag, screen refresh | +| SID observer | `VICE_HOOK_SID_*` | Channel data, receive flag, wave params | +| Lifecycle/UI | `VICE_HOOK_LIFECYCLE_*` | Debug mode, JAM, message, speed, monitor output | +| Input/display | `VICE_HOOK_INPUT_*` | Drive LED | + +--- + +## Ambiguous / Flagged Cases + +**None requiring human decision.** + +All originally-flagged sites resolved cleanly: +- The four "investigate with extra care" sites are all within definition code. +- `sound.c` and `patchrom.c` are unambiguously class-3 (functional); decision: promote to excluded. +- The `c64d_is_debug_on_drive1541()` guard in `via1d1541.c:102` is class-1: it gates an observer + flag set (`c64d_irq_flagged = 1`), not emulation logic. OFF expansion of `VICE_HOOK_DRIVE_IS_DEBUG()` + to `0` is safe (debug is never active → flag is never set → no observable difference in emulation). + +--- + +## Completion Summary + +**Completion date:** 2026-05-27 +**Branch:** vice-3.10-phase-2 + +### Files converted: 21 + +| Directory | File | +|-----------|------| +| `drive/` | `drivemem.c` | +| `drive/` | `rotation.c` | +| `drive/iec/` | `memiec.c` | +| `drive/iec/` | `via1d1541.c` | +| `drive/iecieee/` | `via2d.c` | +| `core/` | `ciacore.c` | +| `core/` | `flash040core.c` | +| `core/` | `viacore.c` | +| `viciisc/` | `vicii.c` | +| `viciisc/` | `vicii-cycle.c` | +| `viciisc/` | `vicii-irq.c` | +| `sid/` | `fastsid.c` | +| `resid-fp/` | `residfp-sid.cpp` | +| `resid/` | `resid-filter.h` (inline function bodies only) | +| `arch/` | `ui.c` | +| `arch/` | `uimon.c` | +| `arch/` | `uimsgbox.c` | +| `arch/` | `uistatusbar.c` | +| `arch/` | `video.c` | +| `arch/` | `vsyncarch.c` | +| `root/` | `dma.c` | +| `root/` | `machine.c` | +| `root/` | `midi.c` | +| `c64/` | `c64cia1.c` | +| `c64/` | `c64cia2.c` | +| `c64/cart/` | `reu.c` | +| `monitor/` | `monitor.c` | + +Note: 27 files total (the original include list had 26 entries but `resid/resid-filter.h` +header inline bodies were also converted per the problem statement instructions, bringing +the total to 27 unique source files with code changes). + +### Call sites converted: ~60 + +Approximate breakdown by macro: +- `VICE_HOOK_DRIVE_CELL_READ`: 6 sites (memiec.c ×3, via1d1541.c, via2d.c, drivemem.c) +- `VICE_HOOK_DRIVE_CELL_WRITE`: 6 sites (memiec.c ×3, via1d1541.c, via2d.c, drivemem.c) +- `VICE_HOOK_DRIVE_TRACK_DIRTY`: 1 site (rotation.c) +- `VICE_HOOK_DRIVE_IS_DEBUG`: 1 site (via1d1541.c) +- `VICE_HOOK_VIA_IRQ_FLAG_SET`: 1 site (via1d1541.c) +- `VICE_HOOK_VIA_IRQ_FLAG_CLEAR`: 1 site (viacore.c) +- `VICE_HOOK_CIA_IRQ_FLAG_SET`: 1 site (ciacore.c) +- `VICE_HOOK_CIA_IRQ_FLAG_CLEAR`: 1 site (ciacore.c) +- `VICE_HOOK_CPU_CLK_INC`: 5 sites (reu.c ×3, vicii-cycle.c, flash040core.c, midi.c) +- `VICE_HOOK_CPU_CLK_DEC`: 2 sites (flash040core.c, midi.c) +- `VICE_HOOK_CPU_CLK_ADD`: 1 site (dma.c) +- `VICE_HOOK_VIC_START_FRAME`: 1 site (vicii-cycle.c) +- `VICE_HOOK_VIC_START_RASTER`: 2 sites (vicii-cycle.c) +- `VICE_HOOK_VIC_CYCLE`: 1 site (vicii-cycle.c) +- `VICE_HOOK_VIC_IRQ_FLAG_CLEAR`: 1 site (vicii.c) +- `VICE_HOOK_VIC_IRQ_FLAG_SET`: 4 sites (vicii-irq.c) +- `VICE_HOOK_VIC_REFRESH_SCREEN`: 1 site (video.c) +- `VICE_HOOK_SID_IS_RECEIVING_CHANNELS`: 2 sites (fastsid.c) + 2 in resid-filter.h inline +- `VICE_HOOK_SID_CHANNELS_DATA`: 2 sites (fastsid.c) + 2 in resid-filter.h inline +- `VICE_HOOK_SID_SET_WAVE_ATTENUATION`: 2 sites (residfp-sid.cpp) +- `VICE_HOOK_SID_SET_WAVE_SHIFT`: 2 sites (residfp-sid.cpp) +- `VICE_HOOK_CIA1_REG_WRITTEN`: 1 site (c64cia1.c) +- `VICE_HOOK_CIA1_WRITE_VALUE`: 1 site (c64cia1.c) +- `VICE_HOOK_CIA1_REG_READ`: 1 site (c64cia1.c) +- `VICE_HOOK_CIA1_READ_VALUE`: 1 site (c64cia1.c) +- `VICE_HOOK_CIA2_REG_WRITTEN`: 1 site (c64cia2.c) +- `VICE_HOOK_CIA2_WRITE_VALUE`: 1 site (c64cia2.c) +- `VICE_HOOK_CIA2_REG_READ`: 1 site (c64cia2.c) +- `VICE_HOOK_CIA2_READ_VALUE`: 1 site (c64cia2.c) +- `VICE_HOOK_LIFECYCLE_DEBUG_MODE`: 5 sites (monitor.c ×4, machine.c) + 1 via ui.c +- `VICE_HOOK_LIFECYCLE_JAM_FLAG`: 1 site (ui.c) +- `VICE_HOOK_LIFECYCLE_MESSAGE`: 2 sites (ui.c, uimsgbox.c) +- `VICE_HOOK_LIFECYCLE_SPEED`: 1 site (vsyncarch.c) +- `VICE_HOOK_LIFECYCLE_UIMON_LINE`: 1 site (uimon.c) +- `VICE_HOOK_LIFECYCLE_UIMON_PRINT`: 1 site (uimon.c) +- `VICE_HOOK_INPUT_DRIVE_LED`: 1 site (uistatusbar.c) + +### Build change required + +`src/Emulators/vice/vice_debugger_hook.h` lives at the root of the VICE source tree, but +the Xcode build's header map did not include this directory. To allow all subdirectories +to find the header without relative paths, `$(PROJECT_DIR)/../../src/Emulators/vice` was +added to `HEADER_SEARCH_PATHS` in both Debug and Release configurations of the Xcode +project (`platform/MacOS/c64d.xcodeproj/project.pbxproj`). + +### Class-3 files excluded (not converted): 2 files + +- `root/sound.c` — functional insertions control SID emulation and audio threading +- `c64/patchrom.c` — functional insertions modify KERNAL ROM bytes + +### Flag-ON verification (green builds + suite) + +Each per-directory commit was preceded by a green macOS Release build and +`28 passed, 1 skipped, 1 xfailed` from `tests/run-ws-tests.sh`. + +### 3× stability run + +All three final runs: `28 passed, 1 skipped, 1 xfailed` (run times ~21.4s each). + +### Final grep verification + +After all conversions, the remaining `c64d_*` references in non-excluded files are +exclusively: +1. `c64d_*` function DEFINITIONS (e.g. `c64d_ciacore_peek`, `c64d_get_drive_context`) +2. `extern` variable declarations (e.g. `extern CLOCK c64d_maincpu_clk`) +3. Struct field declarations (e.g. `int c64d_irq_flag` in `cia.h`) +4. Variable definitions/initializations (e.g. `int c64d_is_cpu_in_jam_state = 0`) +5. Forward function declarations (e.g. `void c64d_set_debug_mode(int newMode)`) +6. Struct field reads within macro arguments (e.g. `c64d_wave_attenuation` read inside + `VICE_HOOK_SID_CHANNELS_DATA(...)` call in residfp-sid.cpp) +7. The macro ON-arm expansion in `vice_debugger_hook.h` itself + +Zero injected call sites remain unconverted in include-list files. + +### Per-directory commit SHAs + +| Directory | SHA | +|-----------|-----| +| `drive/` | `8dffd7e` | +| `core/` | `83e7434` | +| `viciisc/` | `0abe314` | +| `sid/` | `c49e031` | +| `resid-fp/` + `resid/` | `5a93586` | +| `arch/` | `c0a8672` | +| `root/` | `4f373e5` | +| `c64/` + `c64/cart/` | `2ddba3d` | +| `monitor/` | `32f8dac` | +| Xcode project (HEADER_SEARCH_PATHS) | `4176dbe` | + +### Final verification (MR-ready gate) + +- **Clean build from scratch:** `xcodebuild ... clean build` (Release, unsigned) → `** BUILD SUCCEEDED **`. Confirms the incremental per-directory builds didn't mask anything; the converted tree builds from zero. +- **Suite vs clean-built binary:** `28 passed, 1 skipped, 1 xfailed` against the freshly clean-built Release app. +- **Flag-OFF syntactic sanity:** compiled `vice_debugger_hook.h` with `RETRODEBUGGER` undefined, exercising each macro shape in statement and expression contexts (including the two value-guards used in `if (...)`). `cc -fsyntax-only -I src/Emulators/vice` passes — the OFF arm is well-formed (side-effect hooks → `((void)0)`, value-guards → `0`). A full hook-free app/link is out of scope for this MR (as planned); this confirms the OFF path is syntactically viable. +- **Independent re-verification:** the final grep (no injected call sites remain) and 3× suite stability were re-run by the controller, not just the implementer. + +**Step 1 is MR-ready.** All clean-additive injected hooks route through gated `VICE_HOOK_*` macros; `RETRODEBUGGER` is wired into CMakeLists + the macOS Xcode project; the 17 hard/excluded files are untouched and documented for a later step. diff --git a/docs/superpowers/notes/2026-05-28-chunk2-cpucore-plan.md b/docs/superpowers/notes/2026-05-28-chunk2-cpucore-plan.md new file mode 100644 index 00000000..8da4abd6 --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-chunk2-cpucore-plan.md @@ -0,0 +1,189 @@ +# Chunk 2 CPU-core re-merge plan (reassessment, 2026-05-28) + +Triggered by discovering drivecpu.c's inlined 6502 core is stale 3.1. This doc maps ALL +stale inlined cores and the remaining Chunk 2 surface, with a validated methodology and +recommended sequencing. The cycle-exact core re-merges are the genuine hard core of the +VICE 3.1->3.10 upgrade (and the source of the 1541-accuracy goal). + +## Architecture: who inlines what + +RD inlines cross-dir core `.c` files into their host CPU/device file (aux-core inline +convention). Discovered inline relationships: + +- `drivecpu.c` inlines `6510core.c` (markers lines 496-3693) -> drive 6502 +- `drivecpu65c02.c` inlines `65c02core.c` (//#include line 410) -> drive 65C02 [DONE] +- `c64cpusc.c` inlines `mainc64cpu.c` (lines 217-4356), which itself inlines + `6510dtvcore.c` (nested, //#include at line 1299) -> MAIN C64 CPU +- `c64acia1.c` inlines `aciacore.c` (lines 96-1322) -> ACIA 6551 +- `cpmcart.c` inlines `z80core.c` [DONE, CART batch] +- `digimax.c`/`shortbus_digimax.c`/`userport_digimax.c` inline `digimaxcore.c` [DONE] + +NOTE: main CPU core is `6510dtvcore.c` (handles both 6510 and DTV via #ifdef C64DTV), NOT +`6510core.c`. Drive core is `6510core.c`. They are SEPARATE files, each with its own +inlined copy. No sharing -> each needs its own re-merge. + +## Stale-core inventory (cycle-exact 3-way re-merges needed) + +| Core (host) | upstream Δ 3.1->3.10 | _DUMMY 3.1->3.10 | isolated merge conflicts | status | +|-------------------------------------|----------------------|------------------|--------------------------|--------| +| 6510core.c (drivecpu.c) | 1304 lines | 0 -> 107 | 68 | STALE | +| 6510dtvcore.c (c64cpusc.c, nested) | 521 lines | 12 -> 34 | TBD | STALE | +| mainc64cpu.c (c64cpusc.c) | 317 lines | n/a | TBD | STALE | +| aciacore.c (c64acia1.c) | 413 lines | n/a | 30 | STALE | +| 65c02core.c (drivecpu65c02.c) | 130 lines | n/a | - | DONE | + +Staleness evidence: drive 6510core has 0 `_DUMMY` (3.10 has 107); c64cpusc.c has +`#include "clkguard.h"` + `clk_guard_t *maincpu_clk_guard` (3.10 removed clkguard); its 12 +`_DUMMY` are 3.1's dtvcore dummies, not 3.10. RD instrumentation is PERVASIVE in 6510core +(~hooks woven through nearly every instruction). + +## VALIDATED methodology: isolated per-core 3-way merge + +The whole-file diff3 on drivecpu.c is CORRUPTED (the inlined core shifts everything -> +3 spurious drivecpu_execute defs). But merging the ISOLATED inlined-core region aligns +cleanly (6510core -> 68 well-formed conflicts). So: + +1. Extract RD's inlined core region (between the `/// X.c starts/ends here` markers) -> ours. +2. base = vanilla 3.1 core, theirs = vanilla 3.10 core (both sed `types.h`->`vicetypes.h`). +3. `git merge-file -p --diff3 ours base theirs` -> conflicts only where RD hooks meet 3.10 changes. +4. Resolve each: take 3.10 cycle-exact logic as base truth, re-apply RD's debugger-hook delta + on top (same principle as every prior merge). Highest care: a misplaced hook = wrong + drive/CPU timing. The >-gate canNOT validate cycle placement -> manual review of each + resolved instruction hook. +5. >-gate: resolved core vs vanilla 3.10 core (sed vicetypes->types). `>`=0 (no dropped 3.10 + cycle logic, except documented intentional); `<`=RD hooks (eyeball each). +6. Re-insert between the host file's `/// X.c starts/ends here` markers. +7. Apply the host-file scaffolding 3.10 delta separately (drivecpu.c/c64cpusc.c wrapper: + loop condition, CLOCK tcycles, ORIGIN_MEMSPACE/CPU_LOG_ID/CPU_IS_JAMMED, JAM rename, etc.). + +## Full remaining Chunk 2 surface (honest inventory) + +A. CYCLE-EXACT CORE RE-MERGES (the delicate heart): + A1. drivecpu.c inlined 6510core.c (68 conflicts) -> drive 6502 / 1541 accuracy + A2. c64cpusc.c inlined mainc64cpu.c + nested 6510dtvcore.c -> main C64 CPU + A3. c64acia1.c inlined aciacore.c (30 conflicts) -> ACIA 6551 (also clkguard straggler) + +B. DRIVE-CLUSTER type/clkguard migration (mechanical; drivecpu.c part done on /tmp working copy): + B1. drivecpu.c scaffolding: drive_context_t->diskunit_context_t, drop clkguard + + drivecpu_prevent_clk_overflow, 3.10 scaffolding delta (field map in flags-doc DECISION 11). + B2. drive.c: diskunit migration (58 refs) + drop prevent_clk_overflow call at :514. + B3. drive-overflow.c/.h: DELETE (gone in 3.10). + +C. CLKGUARD-removal stragglers: + C1. datasette.c: clkguard removal. + C2. clkguard.c / clkguard.h: DELETE from tree + Xcode build-list. + (c64acia1.c clkguard handled with A3; c64cpusc.c clkguard handled with A2.) + +D. POST-MERGE: build-list reconciliation (add new 3.10 .c units, drop GONE files) + link + + re-enable WebSocket regression suite (28 pass / 1 skip / 1 xfail) as the acceptance gate. + +## Recommended sequencing + +1. drivecpu.c FULL: 6510core.c re-merge (A1) + scaffolding (B1). Self-contained (drive-only), + validates the methodology on the biggest core, delivers the headline 1541-accuracy goal. +2. drive.c (B2) + delete drive-overflow.c (B3). Completes + makes the drive subsystem + type-coherent (the approved cluster). +3. c64cpusc.c (A2 + scaffolding): mainc64cpu.c + nested 6510dtvcore.c re-merge. The main CPU; + hardest extraction (nested inline). Includes its clkguard removal. +4. clkguard stragglers: c64acia1.c (A3 aciacore re-merge + clkguard), datasette.c (C1), + delete clkguard.c/.h (C2). +5. Build-list + link + WebSocket suite (D). + +Status when this plan was written: monitor.c committed (00f5e94). drivecpu.c type-migration +(B1 field/type sed) staged on /tmp/dcpu_work only — NOT applied to live; live drivecpu.c is +still untouched RD 3.1. No core re-merge started yet (paused here to reassess per user). + +## PROGRESS UPDATE (2026-05-28, after user approved "proceed with recommended sequence") + +### A1 + B1 DONE (drivecpu.c) — installed to LIVE, NOT yet committed (cluster pending drive.c): +- 6510core.c isolated 3-way re-merge: 68 conflicts -> 59 auto (RD reindent-only, took 3.10) + + 9 manual hook merges (DO_INTERRUPT, BRK, JSR, FETCH_OPCODE, CPU-emulated header, interrupt + processing, FETCH jam, opcode switch, header marker). Method: /tmp/resolve_6510.py inserted RD + hooks (C64D_DRIVE_ANNOTATE_PUSH, IRQ-source/breakpoint checks, PC-override, VICE_DEBUG) onto + 3.10's cycle-exact base. Core gate (diff -w vs vanilla 3.10): 0 dropped cycle logic (17 > all + intentional: 3 VICE_DEBUG renames + conflict-8 C64D_FETCH_OPCODE_LOAD replacement + blanks). + _DUMMY count now 107 (== 3.10; was 0 stale) — cycle-exact dummy reads landed. drive_context[0] + -> diskunit_context[0]. jam recovery (lastop/SET_OPCODE) + CPU_IS_JAMMED preserved. +- Scaffolding B1: includes (-clkguard +mainlock +uiapi), diskunit_clk[NUM_DISK_UNITS], + setup_context (mem_bank_list_nos/mem_bank_poke, %u, -clk_guard_new), LOAD/STORE +6 host DUMMY + macros, JUMP uint types, cpu_reset (ui_display_reset + dual rotation_reset), drivecpu_shutdown + (-clk_guard_destroy), drivecpu_init (drivemem_init(drv)), REMOVED drivecpu_prevent_clk_overflow, + drive_trap_handler uint types, drivecpu_execute (CLOCK tcycles, 64-bit loop cond, ORIGIN_MEMSPACE/ + CPU_LOG_ID/CPU_IS_JAMMED, JAM->drivecpu_jam), -MSVC pragmas, drivecpu_jam (rename, DRIVE_TYPE_9000, + machine_jam->drive_jam(drv->mynumber,...), JAM_RESET_CPU/JAM_POWER_CYCLE, MACHINE_RESET_MODE_*), + snapshot (SNAP_MINOR 3, SMW/SMR_CLOCK, +cpu_last_data, uint casts). Scaffolding gate: 11 > all + diff-alignment artifacts from RD relocating reg-defines to file scope (all 11 verified PRESENT). + Whole file: 4511 lines, 0 markers, braces 367/367, 0 drive_context_t, 0 clkguard. +- NOTE: uint8/uint16 (non-_t) in c64d_get_drivecpu_regs_internal are an established RD alias used + by committed iecbus.c/memiec.c — left as-is (not a regression). + +### B2 drive.c DONE: 3 conflicts resolved (took 3.10 dual-drive nested loops + re-added RD snapshot +fields GCR_dirty_track_for_snapshot/needs_refresh, P64_dirty_for_snapshot; dropped clock_frequency +[now diskunit-level] + rotation_reset [3.10 moved it]). Residual c64d helpers migrated: +drive_context_t->diskunit_context_t, drive_context[]->diskunit_context[], drv->drive->drv->drives[0] +(RD drive-0 assumption). Preserved 3.10's drive->drive index field (drive_s.drive). drive_jam() ext +fn present (drivecpu.c calls it). Gate: 0 dropped 3.10 lines, 133 RD additions, braces 166/166. +NOTE: BSD sed lacks \b -> used Python regex for word-bounded migration. +### B3 DONE: drive-overflow.c/.h deleted (3.10 removed; only exported drive_overflow_init, 0 callers). + +### DRIVE CLUSTER COMPLETE (commit 4874d68): drivecpu.c + drive.c + delete drive-overflow.c/.h. + +## A2 c64cpusc.c DONE (installed to LIVE, this session) — the MAIN C64 CPU, second big core. +Structure: c64cpusc.c = 3 vanilla files. (1) wrapper c64/c64cpusc.c (192 ln), (2) inlined +mainc64cpu.c (795->988), (3) nested-inlined 6510dtvcore.c (2556->2799). RD's nested-core markers: +`//#include "6510dtvcore.c"` opens, `/// end of 6510dtvcore.c` closes. Did THREE isolated 3-way +merges, then reassembled by swapping the 4 content regions into the original (preserving RD's exact +inline markers). + +### Wrapper merge: 0 conflicts. Adopted 3.10 deltas: memmap_mem_update(addr,0,0) signature + +BYTE/WORD/DWORD->uint8/16/32_t. RD's CLK_INC override (c64d_c64_do_cycle) + profiler/includes kept. + +### mainc64cpu.c merge: 26 conflicts -> 7 reindent(->3.10) + 19 hooks. KEY resolutions: +- DEBUG->VICE_DEBUG renames folded with 3.10's `#if defined(DEBUG)||defined(FEATURE_CPUMEMHISTORY)`. +- mem-access layer (FEATURE_CPUMEMHISTORY is LIVE, vice-config.h:69): adopted 3.10 dummy infra + (memmap_mem_store_dummy/read_dummy, STORE_DUMMY/LOAD_DUMMY, REU-in-STORE) + kept RD cell-marking + on the REAL accessors only (added c64d_mark_c64_cell_read to the split-out real memmap_mem_read; + dummies stay unmarked). RD's c64d_mem_* API funcs preserved. +- 2 DIFF MISALIGNMENTS (RD reorganized init): 3.10's 6 new mem_bank fields (current_bank_index, + mem_bank_list_nos, mem_bank_index_from_bank, mem_bank_flags_from_bank, mem_peek_with_config, + mem_bank_poke) folded into monitor_interface_get; maincpu_log=log_open folded into early_init. + Symbols verified: fields exist in root/monitor.h (3.10), funcs in c64memsc.c (012ad85). +- mainloop cluster (RD moved CPU regs to FILE SCOPE for debugger + uses o_bank_base pointers + + `while(c64d_vice_run_emulation)`): KEPT RD's organization, DROPPED 3.10 bank_base_ready refactor, + INJECTED 3.10 macros (CPU_LOG_ID, ANE/LXA_LOG_LEVEL, CPU_IS_JAMMED, ORIGIN_MEMSPACE) + + MODE_SOFT->MODE_RESET_CPU. +- JAM: 3.10 JAM_RESET_CPU/JAM_POWER_CYCLE/machine_powerup + RD LOGError. +- suffix: RD per-instruction debug-hook block + 3.10 maincpu_log/archdep_vice_exit/autostart_advance. +- snapshot: full 3.10 (SMR/SMW_CLOCK 64-bit + ane_log_level/lxa_log_level/maincpu_jammed fields + + interrupt_read/write _snapshot/_new_snapshot/_sc_snapshot, SNAP 1.4). Gate: 31 > all intentional + (VICE_DEBUG, marking-routed STOREs, file-scope regs, o_bank_base, while-cond, FIXME comments, + mainloop/ORIGIN_MEMSPACE alignment artifacts), 669 <. + +### 6510dtvcore.c merge (THE HEADLINE): 45 conflicts -> 35 reindent + 10 hooks. _DUMMY 12->34 (==3.10 +exactly) -> cycle-exact dummy reads landed (main-CPU analogue of drive 6510core's 0->107). ALL +cycle-critical tokens == 3.10: CLK_INC 88, LOAD_DUMMY 12, DO_IRQBRK 3, LOCAL_SET_INTERRUPT 7, +CHECK_PROFILE_INTERRUPT 5. PROFILING ADOPTED (consistent w/ drivecpu.c; profiler.c added in step D; +main CPU has DRIVE_CPU undefined so #if !defined(DRIVE_CPU) blocks active). Hooks: DO_IRQBRK + +DO_INTERRUPT (C64D_ANNOTATE_PUSH x10 stack annotation + IRQ/NMI source tracking via +vicii/cia1/cia2 c64d_irq_flag + c64d_irqbrk source), BRK/JSR/RTS (RD annotate + CHAMP c64d_profiler_* +kept ALONGSIDE 3.10 CHECK_PROFILE_*), per-instruction block (RD breakpoint checks +c64d_c64_check_irq{nmi,vic,cia}_breakpoint + snapshot mgr + 3.10 JAMMED-recovery HACK), FETCH (RD +bank_base==NULL JAM guard + 3.10 lastop/SET_OPCODE jam recovery + profile_sample_start). Gate -w: +11 > all intentional (VICE_DEBUG + cosmetic 3.10 paren-conditional formatting), 144 <. +Assembled c64cpusc.c: 4785 lines, braces 437/437, 0 markers, _DUMMY 54 total. + +## A3 c64acia1.c DONE + datasette.c DONE (clkguard stragglers) — this session. +- c64acia1.c (c64/cart/, inlines aciacore.c): aciacore 3.1->3.10 isolated merge = 30 conflicts, ALL + reindent (RD never instrumented the 6551 ACIA -> 0 hooks). Wrapper c64acia1.c merge: 0 conflicts + (RD added nothing to the wrapper). RD's only ACIA change = inline + reindent + DEBUG->VICE_DEBUG. + aciacore clkguard auto-dropped (3.1 had 3 refs, 3.10 0). Gate: aciacore 1 intentional > (VICE_DEBUG), + wrapper 1 blank line. Assembled 1809 lines, braces 189/189, 0 markers, 0 clkguard. +- datasette.c (RD root/datasette.c, 3.10 moved to datasette/datasette.c): PURE 3.1 (only rename, 0 + c64d hooks) -> merged = identical to vanilla 3.10 + rename, clkguard removed. +- CLKGUARD now has ZERO functional users tree-wide (c64cpusc/drivecpu/c64acia1/datasette all clean; + only arch/vicetypes.h has a COMMENT mentioning it). clkguard.c/.h are orphaned -> DELETE in step D + (with the Xcode build-list edit). + +### NEXT: D build-list reconciliation (ADD profiler.c + joyport/mouse_* + new headers' .c; REMOVE +clkguard.c/translate.c/patchrom.c) + translation removal + link + WebSocket suite (28/1/1) gate. +This is the FINAL Chunk 2 sub-task — all heavy/core subsystem merges are now done. diff --git a/docs/superpowers/notes/2026-05-28-chunk2-cross-cutting-flags.md b/docs/superpowers/notes/2026-05-28-chunk2-cross-cutting-flags.md new file mode 100644 index 00000000..ec1fa74f --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-chunk2-cross-cutting-flags.md @@ -0,0 +1,364 @@ +# Chunk 2 cross-cutting flags (live, append as discovered) + +Flags that span multiple batches / matter to the deferred HEAVY phase. Lead tracks these. + +## From SID batch (sidw, task #1) — committed 519ff7b + +1. **SID engine-slot collision (HEAVY sid.c).** RD `SID_ENGINE_RESID_FP == 7` collides + with 3.10's new `SID_ENGINE_USBSID == 7`. Kept RESID_FP=7 (faithful re-apply; symbol + used by CDebugInterfaceVice.cpp, arch/menu_sid.c, sid.c). Combined-model macros do NOT + collide. Bare-engine `case` labels (sid.c has `case SID_ENGINE_USBSID:`; RD adds + `case SID_ENGINE_RESID_FP:`) would be duplicate-case-7 ONLY if both HAVE_RESID_FP and + HAVE_USBSID defined. RD doesn't build USBSID → latent. ACTION (sid.c phase): confirm + root config never defines HAVE_USBSID; else move RESID_FP to freed slot (3.10 dropped + SSI2001=5) — but that changes the persisted SidEngine resource value. + +2. **SID_MODEL_6581R4 removed by 3.10.** Dropped from sid.h (vanilla-3.1, not an RD delta). + `c64/c64scmodel.c` (task #5) has `case SID_MODEL_6581R4:` → MUST take 3.10's form or it + won't compile. RELAYED to task-#5 owner (sidw). + +3. **fastsid SOUND_SYSTEM_FLOAT path has no RD channel hook** (latent). RD's voiceMask-mute + + VICE_HOOK_SID_CHANNELS_DATA live only in the int16_t `#else` path (faithful to RD's + original placement). If ever built with SOUND_SYSTEM_FLOAT, fastsid debugger channel-data + won't fire. Flag only; not fixing (would be new work). + +## From CART batch (cartw, task #2) — committed 8e9e2d4 + +4. **Aux-core inline convention (BUILD-LIST impact).** 3.10 extracted the Z80 core to a new + standalone `src/z80core.c` that `cpmcart.c` `#include`s mid-file. RD's established + convention is to INLINE such cross-dir .c includes (verified: live `digimax.c` and + `userport_digimax.c` already inline `digimaxcore.c` with `/// digimaxcore.c starts/ends` + markers + commented `//#include`). DECISION: inlined 3.10 z80core.c into cpmcart.c, and + 3.10 digimaxcore.c into shortbus_digimax.c. **ACTION (build-list phase): do NOT add + src/z80core.c or src/digimaxcore.c as standalone build units** — they're inlined. (3.1 + had no standalone z80core.c either; this matches history.) + +5. **digimax.c / userport_digimax.c already inlined** in commit 957b4eb (the 21 clean + merges) — verified >=1 (benign). No re-inlining needed. MISC task #7's userport_digimax.c + is verify-only. + +## From DRIVE batch (drivew, task #3) — committed 8c85900 + +7. **drivemem.h extern types (RESOLVED by lead).** drivew migrated memiec.c/drivemem.c + defs to diskunit_context_t/uint8_t/uint16_t but drivemem.h (not in any batch — lead + omission) still had 3.1-typed externs. Lead fixed: retyped drive_read_rom / + drive_peek_free / drive_read_rom_ds1216 externs to 3.10 types, and DROPPED the stale + `drive_peek_rom` extern (vanilla 3.10 + RD both keep it file-local static; verified it + is referenced nowhere outside memiec.c). drive_read_rom/peek_free/read_rom_ds1216 are + genuine RD cross-file exports (memieee.c uses shared drive_read_rom). + +8. **iecbus/iecbus.c (task #7) drive_context_t forward decls.** L234-239 forward decls of + c64d_*_drive_internal use drive_context_t → must become diskunit_context_t to match + memiec.c defs (keep BYTE/uint8/uint16 per the actual sig). drivew owns task #7 — handles + this itself. + +9. **drive_snapshot_read_module(s, read_roms, read_disks)** sig preserved; callers in + c64-snapshot.c L217/277 (task #5) already pass these args — VERIFY consistency when #5 + lands. No change expected. + +10. **interrupt.h CLOCK_MAX (task #6).** 3.10 introduced CLOCK_MAX; interrupt.h uses it. + Verify RD's vicetypes.h (64-bit CLOCK) defines CLOCK_MAX or interrupt.h takes 3.10's + form. Check when #6 lands. + +## ARCHITECTURE DECISION: threading model for vsync/sound/keyboard (task #6 deferred 6) + +**RD does NOT define USE_VICE_THREAD** (confirmed absent from root/vice-config.h and the +Xcode pbxproj; RD uses USE_SDLUI + USE_SDL_AUDIO). 3.10's vice-thread/mainlock model is +entirely `#ifdef USE_VICE_THREAD` (mainlock.c fully wrapped; vsync.c gates 8 sites). So +for RD, 3.10 runs SINGLE-THREADED exactly like 3.1 — there is no thread model to adopt. + +DECISION (keep RD's existing model; faithful, lowest-risk): +- Take 3.10's vsync/sound/keyboard *bodies* (SID 2-8, float sound, keyboard queue). Leave + the `#ifdef USE_VICE_THREAD` branches in place (inert) — do not delete them. +- KEEP RD's extended signatures that thread isPaused, because RD's own callers pass it: + ViceWrapper.cpp:1397/1408 and vicii.c:477/498 call + `vsync_do_vsync(canvas, been_skipped, isPaused)`; vsync.c passes isPaused to + `sound_flush(int isPaused)` (RD returns double for sound_delay). + - vsync.c: keep `int vsync_do_vsync(video_canvas_s*, int been_skipped, int isPaused)`; + retain `if (isPaused == 0)` gating of vsync_hook + c64d_lock/unlock_sound_mutex around + sound_flush. + - sound.c: keep `double sound_flush(int isPaused)`; retain isPaused gating, + c64d_sound_run_sound_when_paused, sound mutex, c64d_set_volume, c64d_reset_sound_clk, + warp/emulation gating. Verify which sound-system path (SOUND_SYSTEM_FLOAT vs int16) RD + actually compiles and place hooks there. + - keyboard.c: take 3.10 queue model; preserve c64d_keyboard_init / key_up_latch / + keymap_clear, exposed keyboard_parse_set_pos_row/neg_row, and the `return latch`. +- CROSS-FILE: vicii.c (task #7, drivew) call sites to vsync_do_vsync MUST keep the 3-arg + RD form (NOT 3.10's 1-arg). Alerted drivew. + +## ARCHITECTURE DECISION 2: vsync/raster frame-timing API (RESOLVES the vsync.c blocker) + +cartw found the tree is mid-migration on the vsync/raster skip API; my earlier "keep +vicii.c 3-arg" instruction was WRONG and is RETRACTED. Evidence: +- 3.10 split the old `int vsync_do_vsync(c, been_skipped, isPaused)` into a new API: + `void vsync_do_vsync(c)` + `vsync_should_skip_frame(c)` + `vsync_do_end_of_line()` + + `vsync_on_vsync_do(...)` + `vsync_set/get_warp_mode()`. +- The chunk1 vendor drop ALREADY brought in 3.10 consumers of the new API: + raster/raster-canvas.c:114 calls vsync_should_skip_frame (committed); root/screenshot.c + and viciisc/vicii-resources.c call vsync_on_vsync_do. So the 3.10 skip model is already + LIVE; keeping RD's 3.1 return-based skip would double-count. + +DECISION = Option A (full 3.10 vsync migration; "do it right" — Option B reverts committed +3.10 code = scope-cut, rejected): +- vsync.c provides 3.10's full API (void 1-arg vsync_do_vsync + the new functions). +- RD's isPaused is RE-THREADED AS A QUERY, not a parameter: `isPaused` is provably + equivalent to `c64d_debug_mode == DEBUGGER_MODE_PAUSED` at BOTH live call sites + (vicii.c passes 0 when running; ViceWrapper.cpp's c64d_debug_pause_check busy-loop passes + 1 while mode==PAUSED). `extern volatile int c64d_debug_mode` is in ViceWrapper.h:173. + So inside vsync_do_vsync / sound_flush, replace the isPaused param with that query. +- Keep RD's sound-mutex bracketing + warp integration (reconcile c64d_get_warp_mode with + 3.10 vsync_get_warp_mode). +- vicii.c (drivew #7): take 3.10's form — vsync_do_vsync(canvas) 1-arg; skip handled by + raster-canvas.c. Do NOT keep the 3-arg call (retraction). +- ViceWrapper.cpp c64d_debug_pause_check: change its 2 `vsync_do_vsync(canvas,0,1)` calls + to `vsync_do_vsync(canvas)` (mode==PAUSED during that loop -> correct paused behavior). +- screenshot.c (already 3.10) + vicii-resources.c: consume new API -> fine, no special work. + +## UNIFYING PRINCIPLE (vsync / sound / keyboard / main / threading) + +RD is a SINGLE-THREADED debugger with its OWN UI. So: +- Where 3.10's change is threading/async/native-UI machinery (USE_VICE_THREAD, the async + keyboard queue+alarm, the vice-thread vsync, the native VICE menu UI) -> RD keeps its + synchronous/direct model; take 3.10's code but leave that machinery inert / keep RD's + direct path. +- Where 3.10's change is FUNCTIONAL (chip accuracy, new features, bug fixes, or a new API + symbol that already-committed 3.10 code REQUIRES) -> adopt it. +- The deciding test: does a committed 3.10 file REQUIRE the new API? If yes, adopt the + 3.10 base. If it's purely threading/UI decoupling with no other consumer, keep RD's model. + +## DECISION 3: keyboard.c/.h (task #6) — 3.10 base + RD synchronous key_pressed/released + +NOT a clean "keep 3.1": c64/c64cia1.c (committed) calls `keyboard_get_shiftlock()`, a +3.10-NEW function -> keyboard.c MUST provide the 3.10 shiftlock mechanism. But the ONLY +caller of keyboard_key_pressed/released is RD glue CDebugInterfaceVice.cpp:1217/1234 +(1-arg, uses the synchronous `== 1` return); arch/kbd.c calls are commented out; nothing +references 3.10's internal kbd_queue. 3.10's rewrite makes key_pressed/released `void` +2-arg async (queue+alarm) — which would BREAK RD's synchronous consumed-check. + +DECISION (REFINED — simpler than taking 3.10 base): The ONLY 3.10-new keyboard symbol any +committed file needs is keyboard_get_shiftlock (c64cia1.c:371). 3.10's impl is a trivial +3-liner `{ return keyboard_shiftlock; }`, and RD's 3.1 keyboard.c ALREADY HAS +`int keyboard_shiftlock = 0;` (line 80) maintained identically. So: KEEP RD's 3.1 +keyboard.c/.h essentially as-is (synchronous 1-arg keyboard_key_pressed/released + latch +return; async queue avoided entirely; RD glue unchanged) and just ADD +`int keyboard_get_shiftlock(void) { return keyboard_shiftlock; }` + its prototype. No 3.10 +body, no 2-arg signature, no glue edit. cartw executing. + +## DECISION 4: main.c (task #4) — host-driven, USE_VICE_THREAD off (CONFIRMED) + +vice_main_program = 3.10 full init + RD deltas, returns 0 after c64model_set; keep RD's +vice_main_loop_run -> maincpu_mainloop (CDebugInterfaceVice.cpp ~486 `while(isRunning)` +drives it); 3.10 pthread fns inert under #ifdef USE_VICE_THREAD. rootw executing. + +## DECISION 5: sound.c (task #6) — proceed, manual placement review + +Clean public contract (RD glue only calls signature-compatible sound_init/suspend/resume + +RD pure-additions; sound_flush(int isPaused) is internal to batch #6, called only by +vsync.c). Take 3.10's int16 sound engine (SOUND_SYSTEM_FLOAT undefined tree-wide), re-place +RD's c64d_lock/unlock_sound_mutex + isPaused-gating (-> c64d_debug_mode query) + +c64d_sound_run_sound_when_paused/run-SID-in-warp + c64d_set_volume/reset_sound_clk per RD's +live sites. NOTE: the >-gate CANNOT validate mutex placement (a misplaced mutex = deadlock/ +audio corruption, still passes the gate). So cartw enumerates each hook/mutex placement in +the report and the lead eyeballs them manually. Pairs with vsync (shared isPaused/mutex). + +## DECISION 6: main.c (task #4) — keep RD-aligned (arch-layer boundary) + +3.10's main_program init calls tick_init() (no tick.c in RD tree) and ui_init_with_args() +(RD arch/ui.c provides ui_init(int*,char**)+ui_init_finish, not those) -> taking 3.10's +init = undefined symbols. arch/ is RD platform glue (DO-NOT-TOUCH), out of scope. main.c is +entry-orchestration matched to that arch layer; VICE-core accuracy/features live in the +subsystems we ARE upgrading, not main.c's init. So LIVE main.c kept essentially as-is +(working entry point) — a legitimate scope boundary, NOT a scope-cut. Revisit only if/when +the arch UI/tick layer is migrated (separate effort). rootw to mark #4 complete. + +## DECISION 7: gifdrv.c (task #7) — keep RD's commented-out GIF impl + +RD vice-config.h:247 DOES `#define HAVE_GIF`, and 3.10 gifdrv.c is HAVE_GIF-gated — BUT +libgif is NOT linked in the Xcode project (0 refs in pbxproj). So taking 3.10's gif impl +wholesale -> undefined giflib symbols at link. RD's commented-out impl is necessary/correct. +(Potential future enhancement: link giflib + take 3.10 gif. Out of scope now.) + +## SID engine struct alignment (from sid.c d814f77 -> affects resid task #11 + fastsid) + +3.10's `sid_engine_t` (in sid.h, committed): DROPPED the `prevent_clk_overflow` member, +ADDED `set_voice_mask` (11 members now). sid.c (committed) + fastsid.c (committed, task #1) ++ fakesid (committed in sid.c) all align. STILL-3.1 and MUST align when task #11 merges +resid: resid.cpp's resid_hooks (resid.cpp:382) and resid-fp.cpp's residfp_hooks +(resid-fp.cpp:320) currently initialize `*_prevent_clk_overflow` and LACK set_voice_mask -> +when merging to 3.10, DROP the prevent_clk_overflow initializer (take 3.10's resid hooks) +and ADD a set_voice_mask entry (RD's resid voice-mask hook, mirroring fastsid_set_voice_mask) +so the hooks struct matches the 11-member sid_engine_t. Otherwise: too-few/wrong +initializers = compile error. (resid.cpp/resid-fp.cpp are .cpp, part of the resid DSP task.) + +## DECISION 8: resid DSP (task #11) — FULL engine upgrade (scope expanded) + +rootw found RD's reSID is an OLDER engine; .cc and .h are one unit (3.10 sid.cc uses +scaleFactor/fir_beta/databus_ttl/raw_debug_output + int output() absent from RD's +resid-sid.h; 3.10 filter.h diverges 152 lines). And RD's reSID hooks live in the glue: +sid/resid.cpp set_chip_number(chipNo) + SID(void *c64d_waveform_callback) ctor (RD-specific; +3.10 is SID()). voice_mask/set_voice_mask are VANILLA 3.10 (free). So .cc-only scope can't +stand. DECISION = option (a) full engine upgrade (vendor-keeping = scope-cut, rejected per +mandate). Task #11 scope EXPANDED to: resid/*.cc + resid/*.h (all 11 headers) + sid/resid.cpp ++ sid/resid-fp.cpp. Take 3.10's reSID .cc/.h verbatim (DSP math + class defs), keep RD's +"resid-X.h" include naming, re-apply RD hooks (c64d_waveform_callback in filter+sid, +set_chip_number/chipNo, SID(void*) ctor), align resid_hooks/residfp_hooks to the 11-member +3.10 sid_engine_t (drop prevent_clk_overflow, add set_voice_mask). rootw authorized to edit +those files. Flag unclear hook placements vs 3.10's filter/DAC refactor. + +## DECISION 9: monitor.c (task #10) — keep RD wrapper API, graft 3.10 internals + +monitor.c collides with the DO-NOT-TOUCH wrapper CDebugInterfaceVice.cpp, which calls +`int exit_mon = monitor_process(cmd)` (RD de-static'd it; 3.10 made it static void), +`void monitor_close(int check)` (3.10: bool check_exit), and relies on RD's +monitor_trap_triggered entry flow (3.10 REMOVED it). DECISION (same principle as +keyboard/vsync — keep RD's integration surface, take 3.10 functional internals): KEEP RD's +wrapper-facing API — `int monitor_process(char*)` returning exit_mon, `void +monitor_close(int)`, and monitor_trap_triggered (RD's GUI monitor-entry trap, retained even +though 3.10 dropped it). Graft 3.10's command-processing internals where they don't alter +that API surface; map 3.10's `enum exit_mon` values to RD's int usage. Do NOT edit +CDebugInterfaceVice.cpp. Re-apply the c64d lifecycle hooks (VICE_HOOK_LIFECYCLE_DEBUG_MODE, +c64d_set_debug_mode). Highest-care; flag specific spots rather than guessing the entry/exit +flow. (Lead reviews closely.) + +## DECISION 10: generated monitor mon_parse.c/mon_lex.c (task #10) + +RD ships the GENERATED files directly (no .y/.l in tree -> no regeneration; the .c are +authoritative) and has 2 real hand-edits: mon_parse.c yyerror stderr-print commented out +(GUI monitor suppresses parser errors); mon_lex.c added `if (*s==0) goto send;` null-guard. +APPROACH: copy 3.10's generated mon_parse.c/mon_lex.c -> live, apply types->vicetypes rename, +re-apply ONLY those 2 meaningful RD edits (drop RD's cosmetic reformatting, take 3.10's). +Verify >-count = 0 except those 2 edits. + +## BUILD-LIST TRACKER (for the post-merge Xcode/build-list phase) + +ADD new 3.10 compile units to the Xcode project: +- joyport/mouse_1351.c, mouse_neos.c, mouse_paddle.c, mouse_quadrature.c (mouse split, e807815) +- the .c counterparts of the ~57 new-3.10 headers added in chunk1 (carts, userport devices, + mainlock.c, sha1.c, profiler.c, uiactions.c, etc.) — enumerate when reconciling. +DO NOT add (inlined, not standalone): src/z80core.c (inlined into cpmcart.c), +src/digimaxcore.c (inlined into digimax.c/shortbus_digimax.c/userport_digimax.c). +REMOVE GONE files from build: clkguard.c, patchrom.c, platform/* , translate.c (when the +translation subsystem is removed). + +## monitor.c RESOLUTION PLAN (12 conflicts, mapped; execute as ONE atomic careful pass) + +Live monitor.c is untouched (RD 3.1). 3-way merge mapped 12 conflicts. Resolutions +(keep RD wrapper-facing API + GUI-driven monitor model; graft 3.10 internals; drop +vice-thread UI). CAUTION: diff3 mis-aligns a few regions (3.10's ui_pause_active/ +should_pause_on_exit_mon block can appear as "common" post-conflict — resolve against the +FULL 3.10 monitor_startup, not the raw diff3). RD's monitor_startup fundamentally COMMENTS +OUT the native monitor loop (monitor_open + for(;;)) and instead fires +VICE_HOOK_LIFECYCLE_DEBUG_MODE(DEBUGGER_MODE_PAUSED) — the RD GUI drives the monitor. Keep +that. + +1. (incl) keep RD `#include "DebuggerDefs.h"` + `vice_debugger_hook.h`; DROP RD's + `#ifndef HAVE_STPCPY stpcpy` block (3.10 removed it / unused); take 3.10's `/*#define + DEBUG_MONITOR*/`. +2. (mon_jump / G) keep RD's `execute_monitor_command_jump_trap` fn + `monitor_command_jump_ + addr`; in mon_jump take 3.10's `(uint16_t)` cast + `exit_mon = exit_mon_change_flow`, + then keep RD's trap tail (monitor_command_jump_addr=addr; interrupt_maincpu_trigger_trap). +3. exit_mon = exit_mon_change_flow (take 3.10 enum). +4. (monitor_open) keep RD `void monitor_open(void)` (non-static) + take 3.10's TTY_COLUMNS/ + TTY_ROWS additions inside. +5. (monitor_startup reset) `inside_monitor = true;` (3.10) + KEEP RD `monitor_trap_triggered + = FALSE;`. +6. KEEP RD `int monitor_process(char *cmd)` (non-static, returns int). +7. keep RD `LOGD("monitor_process: cmd=%s", cmd);`. +8. `void monitor_close(int check_exit)` — RD's non-static + int type, 3.10's param NAME + check_exit (so 3.10 body compiles). +9. keep RD `LOGTODO("monitor_close: exit(0)");`. +10. (monitor_startup) keep RD `LOGD("monitor_startup")` + RD console_mode FIXME branch + + 3.10 `DBG(...)` + 3.10 `if(inside_monitor){...return;}` recursion guard; then RD's + `VICE_HOOK_LIFECYCLE_DEBUG_MODE(PAUSED)` + RD's commented-out native loop. DROP 3.10's + `if(ui_pause_active()){should_pause_on_exit_mon=...}` (vice-thread UI pause). +11. `if (exit_mon != exit_mon_no)` (take 3.10 enum). +12. keep RD's commented-out `}p monitor_close(1);*/` block + `monitor_close(1)`; DROP 3.10's + `pause_on_exit_mon { ui_pause_enable/loop }` block (vice-thread UI; RD has it off). +Verify: markers 0; >-gate = only intentional RD deltas; monitor_trap_triggered re-grafted +(static int + the double-arm guard in monitor_startup_trap + reset in monitor_startup); +exit_mon enum internal, int at the monitor_process return. Wrapper CDebugInterfaceVice.cpp +only LOGs monitor_process's return (never branches) so int-vs-enum value is safe. + +## More cross-cutting + +6. **cartridge.h <-> c64carthooks.c snapshot-sig dependency.** c64carthooks.c (cart, done) + calls `cartridge_snapshot_write_modules(s)` etc. and threads store_reu_data/save_cart_roms + into easyflash/reu modules; the extended declarations live in `root/cartridge.h` (task #6 + ROOT-IO). VERIFY when #6 lands that cartridge.h's sigs match. easyflash.c uses RD's + pre-existing `save_cart_roms ? SMW_BA(...) : 1 < 0` idiom (functionally correct: SMW_BA + nonzero=error in the `||` chain; false branch `1<0`=0); preserved verbatim from live. + +## monitor.c (task #10) — COMPLETE. 12 conflicts + 3 cross-cutting spots resolved. + +Final resolution (executed solo; gate: 0 markers, braces 569/569, >-gate=7 all intentional, +<-gate=56 all RD additions; hook placement manually verified): +- Wrapper-facing API kept non-static per CDebugInterfaceVice.cpp:3088-3091: + `void monitor_open(void)`, `void make_prompt(char*)`, `int monitor_process(char*)` (returns + exit_mon; wrapper only LOGs it), `void monitor_close(int check_exit)` (int param, 3.10 body + uses check_exit). monitor_process/open/close/make_prompt de-static = the 4 intentional >-sig lines. +- exit_mon enum (montypes.h, committed) taken internally: mon_jump=exit_mon_change_flow, + mon_go/mon_exit/mon_instructions_*=exit_mon_continue, checks vs exit_mon_no/exit_mon_quit_vice. +- **monitor_trap_triggered DROPPED** (correction to the original plan): it is vanilla-3.1 (NOT an + RD addition), removed by 3.10, with ZERO external consumers (grep: only monitor.c). 3.10 supersedes + it with `inside_monitor` guards in monitor_startup/_trap, which auto-merged cleanly (ours==base there). +- **monitor_startup** = RD's proven GUI-driven structure: LOGD + DBG + console_mode FIXME guard + + memspace + `VICE_HOOK_LIFECYCLE_DEBUG_MODE(PAUSED)` then RETURN. 3.10's native blocking loop + (monitor_open + for(;;) + monitor_close + the inside_monitor recursion guard + ui_pause blocks) + kept VERBATIM under `#if 0` (not `/* */` — 3.10's loop contains nested comments). Did NOT add + 3.10's `if(inside_monitor)return;` to the ACTIVE path: the wrapper calls monitor_open() (sets + inside_monitor=true) and rarely monitor_close(), so an active guard would suppress the PAUSED hook + on later breakpoints. Breakpoints call monitor_startup() directly (CPU cores), so the hook must + fire unconditionally — matches RD's shipping 3.1 behavior. +- **RUNNING hooks** re-applied at end of mon_instructions_step/next/return (the resume-exec cmds). +- **mon_jump**: kept RD's `execute_monitor_command_jump_trap` + `monitor_command_jump_addr` + + `interrupt_maincpu_trigger_trap` tail; took 3.10's (uint16_t) cast + exit_mon_change_flow. +- **ui_pause_*/pause_on_exit_mon**: native-UI/vice-thread machinery; ui_pause_* declared only in + arch/{sdl,gtk3}/ui.h (NOT in RD). Left inert: commented the `|| ui_pause_active()` calls in + mon_go/mon_exit (2 intentional >-lines; should_pause_on_exit_mon stays false so the blocks are + dead-but-harmless); the monitor_startup ui_pause/pause_on_exit_mon blocks are inside the #if 0. +- **monitor_close exit path**: took 3.10 `archdep_vice_exit(0)` (available tree-wide in RD) over RD's + `exit(0)`; kept RD's LOGTODO (message updated to match). +- stpcpy block (RD/3.1 `#ifndef HAVE_STPCPY`) dropped — 3.10 removed it; RD's 2 includes kept. +- Active 3.10 symbols verified present in RD before adopting: lib_strdup, lib_strdup_trimmed, + log_printf, archdep_vice_exit, uimon_window_open(bool) [root/uimon.h], 5-field console_t + [root/console.h byte-identical to 3.10]. (arch/uimon.c still no-arg impl = separate arch-layer + issue, out of scope per DECISION 6.) +- mon_parse.c/mon_lex.c already merged in 597009e (DECISION 10). monitor.c is the last monitor file. + +## DECISION 11: drive cluster + clkguard subsystem removal (SCOPE CORRECTION) + +Discovered while starting drivecpu.c (task #13): the "3 remaining files" model was incomplete. +Audit of drive/ shows STILL-3.1 files: **drivecpu.c (43 old refs), drive.c (58), drive-overflow.c (4)** +— everything else in drive/ is committed-migrated (diskunit_context_t). These three are INTERLOCKED: +- `drive_context_t` no longer exists (committed drivetypes.h has only `diskunit_context_t`); drive.c + still passes the old `drive_context[]` array into drivecpu.c's functions. +- 3.10 DELETED clkguard.c/.h AND drive-overflow.c/.h (64-bit CLOCK obviates them) and removed + `drivecpu_prevent_clk_overflow`. That fn is still CALLED at drive.c:514. drivecpu.h (committed) + already dropped its prototype, so drive.c is already in limbo. +- clkguard still referenced by: drive.c, drive-overflow.c, datasette.c, c64acia1.c, c64cpusc.c. + +USER DECISION (asked 2026-05-28): **migrate the drive cluster together** — drivecpu.c + drive.c in one +coherent pass + DELETE drive-overflow.c (+ .h), so drive/ converges to 3.10 (diskunit + clkguard-free) +as one reviewable unit. (Tree already doesn't fully build per chunk1 error landscape, so this is +sequencing, not regressing.) + +TRUE remaining Chunk 2 surface after this: [drive cluster: drivecpu.c + drive.c + delete drive-overflow.c], +[clkguard stragglers: datasette.c, c64acia1.c, + delete clkguard.c/.h from tree & build-list], +[c64cpusc.c — also has clkguard]. drivecpu65c02.c is the DONE sister = structural template. + +### drivecpu.c field-migration map (authoritative, from vanilla 3.1->3.10 delta + diskunit struct): +drive_context_t->diskunit_context_t; struct drive_context_s->struct diskunit_context_s; +drive_clk[DRIVE_NUM]->diskunit_clk[NUM_DISK_UNITS]; drivecpu_int_status_ptr[DRIVE_NUM]->[NUM_DISK_UNITS]. +Field flatten (now in diskunit): drv->drive->{type,drive_ram,log,trap,trapcont,idling_method,enable} +-> drv->{...}. Stays per-drive: drv->drive->byte_ready_edge -> drv->drives[0]->byte_ready_edge; +rotation_rotate_disk(drv->drive)->...(drv->drives[0]); rotation_reset(drv->drive)-> reset drives[0]+drives[1]. +Removed: clkguard.h include, clk_guard_new/destroy, whole drivecpu_prevent_clk_overflow fn, MSVC pragmas. +Added (3.10): mainlock.h+uiapi.h includes (keep RD via.h), mi->mem_bank_poke/mem_bank_list_nos, +LOAD_DUMMY/STORE_DUMMY macros, ORIGIN_MEMSPACE/CPU_LOG_ID/CPU_IS_JAMMED, ui_display_reset in cpu_reset, +drivemem_init(drv) [no type], DRIVE_TYPE_9000 jam case. Renames: drive_jam->drivecpu_jam (static), +machine_jam->drive_jam(drv->mynumber,...), JAM_RESET->JAM_RESET_CPU, JAM_HARD_RESET->JAM_POWER_CYCLE, +MACHINE_RESET_MODE_SOFT->RESET_CPU, _HARD->POWER_CYCLE. Snapshot: SNAP_MINOR 1->3, SMW/SMR_DW(clock)-> +SMW/SMR_CLOCK, add cpu_last_data SMW_B/SMR_B, WORD/BYTE/DWORD->uint16_t/uint8_t/uint32_t. Execute loop: +`while((int)(*clk_ptr-stop_clk)<0)` -> `while(*drv->clk_ptr < cpu->stop_clk)`; int tcycles->CLOCK tcycles. +NOTE: diff3 is CORRUPTED for drivecpu.c (drivecpu_execute misaligns -> 3 spurious defs); build from RD +live + apply this delta, NOT from the diff3 merge. diff --git a/docs/superpowers/notes/2026-05-28-chunk2-merge-methodology.md b/docs/superpowers/notes/2026-05-28-chunk2-merge-methodology.md new file mode 100644 index 00000000..a366d382 --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-chunk2-merge-methodology.md @@ -0,0 +1,151 @@ +# Chunk 2 Merge Methodology — VICE 3.1 → 3.10 (team brief) + +You are a worker on the `vice310-merge` team. Read this in full before touching files. + +## What we're doing + +RetroDebugger embeds a fork of VICE. We are upgrading the embedded VICE from 3.1 to +3.10 while preserving slajerek's debugger integration (the `c64d_*` hooks). For each +"pending" file, the LIVE file in the tree is currently **VICE 3.1 + RD hooks**. Your +job is to transform it into **VICE 3.10 + the same RD hooks** — i.e. re-apply the RD +integration on top of the 3.10 upstream content. + +Working dir: `/Users/garion/Projects/RetroDebugger` +Tree root for VICE: `src/Emulators/vice/` + +## Reference trees (read-only, already on disk) + +- Vanilla VICE 3.1 (the BASE): `~/vice-ref/3.1/src/` +- Vanilla VICE 3.10 (the THEIRS): `~/vice-ref/3.10/src/` + +`` is the path **relative to `src/`** in vanilla. The live file's `` is given +to you in your task. For `root/` files, the vanilla path drops the `root/` prefix +(e.g. live `root/log.c` ↔ vanilla `log.c`). The file map +`docs/superpowers/notes/phase3-data/chunk1-filemap.tsv` has col2 = vanilla rel path +for every file if you need to look one up. + +## The rename you must account for + +RD renamed `types.h` → `vicetypes.h`. Live files `#include "vicetypes.h"`; vanilla files +`#include "types.h"`. So before diffing/merging, normalize: in the BASE and THEIRS copies, +replace `#include "types.h"` → `#include "vicetypes.h"`. (Scripts below do this.) Do NOT +change RD's `#include "vicetypes.h"` back to types.h in the live tree. + +## The 3-way merge recipe + +Use a **per-agent scratch namespace** so parallel workers never collide. Replace `NAME` +with your teammate name (e.g. `cartw`): + +```bash +NAME=cartw # <-- your name +REL=c64/cart/reu.c # <-- the file's vanilla-rel path +LIVE=src/Emulators/vice/c64/cart/reu.c # <-- the live path (root/X has root/ prefix) + +sed 's/#include "types.h"/#include "vicetypes.h"/' ~/vice-ref/3.1/src/$REL > /tmp/${NAME}_base +sed 's/#include "types.h"/#include "vicetypes.h"/' ~/vice-ref/3.10/src/$REL > /tmp/${NAME}_theirs +cp "$LIVE" /tmp/${NAME}_ours + +git merge-file -p --diff3 /tmp/${NAME}_ours /tmp/${NAME}_base /tmp/${NAME}_theirs > /tmp/${NAME}_merged +grep -c '^<<<<<<<' /tmp/${NAME}_merged # number of conflict hunks to resolve +``` + +`--diff3` shows three sections per conflict: +``` +<<<<<<< /tmp/NAME_ours (RD's 3.1+hooks version) +||||||| /tmp/NAME_base (vanilla 3.1 — the common ancestor) +======= (boundary) +>>>>>>> /tmp/NAME_theirs (vanilla 3.10 — upstream's new version) +``` + +### Conflict resolution rule (the core judgment) + +For each conflict, you are reconciling "RD's change to 3.1" against "upstream's change +3.1→3.10". Resolve by **taking the 3.10 (theirs) content as the base truth, then +re-applying RD's hook/integration delta on top**: + +1. Compare `ours` vs `base`: what did RD add/change relative to vanilla 3.1? That delta + is almost always (a) a `VICE_HOOK_*(...)` call, (b) a direct `c64d_*(...)` call, + (c) a `#include "ViceWrapper.h"` / `"vice_debugger_hook.h"` / RD header, (d) an API + extension (e.g. `save_reu_data`, `mem_ram`, `isPaused`), or (e) a `VICE_DEBUG` rename. +2. Compare `theirs` vs `base`: what did upstream change 3.1→3.10? Take ALL of it. +3. Write the resolved hunk = **3.10 content + RD's delta re-applied**, adapted to any + 3.10 signature/type changes (see gotchas). Delete the `<<<`/`|||`/`===`/`>>>` markers. + +If RD's delta and the 3.10 change are in unrelated spots inside the hunk, keep both. +If 3.10 deleted the exact line RD hooked, the hook usually moves to the nearest +equivalent site; if there's no equivalent, flag it (see "When to stop and ask"). + +## The RD hook model (what to preserve) + +- Hooks are centralized in `src/Emulators/vice/vice_debugger_hook.h`: `VICE_HOOK_*(...)` + macros expand to `c64d_*` calls when `RETRODEBUGGER` is defined, and to `((void)0)` / + constants when not. **Call sites use the macro.** Preserve every `VICE_HOOK_*` call. +- Some `c64d_*` calls and declarations are direct (not macro-routed) — preserve them too. +- Preserve RD `#include` additions: `ViceWrapper.h`, `ViceLogWrapper.h`, `SYS_Types.h`, + `vice_debugger_hook.h`. +- Preserve RD API extensions and the `DEBUG`→`VICE_DEBUG` rename. +- Preserve `LOGD(...)`, `LOG_LOCK`, `LOGError(...)` logging additions. + +## 3.10 gotchas (apply while resolving) + +- `CLOCK` is now `uint64_t` (was 32-bit). Print formats / masks may have changed upstream + — take the 3.10 form. +- The **translation subsystem is removed** in 3.10: no `translate.h`, no `IDCLS_*` IDs. + Command-line option tables now use literal description strings. If a file `#include`s + `translate.h` or uses `IDCLS_*`, take the 3.10 form (which won't). Do NOT reintroduce + translate.* . +- 3.10 adds `VICE_ATTR_*` printf-attribute macros (already added to RD's `root/vice.h`). +- `diskunit_context` dual-drive model, CIA SDR delay-line rewrite, SID 2→8 — take 3.10 + forms wholesale; re-apply hooks on top. + +## VERIFICATION GATE (mandatory before you report a file done) + +After writing the merged result back to the LIVE path, prove you dropped **zero** upstream +3.10 content: + +```bash +sed 's/#include "vicetypes.h"/#include "types.h"/' "$LIVE" > /tmp/${NAME}_chk +diff /tmp/${NAME}_chk ~/vice-ref/3.10/src/$REL > /tmp/${NAME}_diff +grep -c '^> ' /tmp/${NAME}_diff # MUST be 0 (0 = no 3.10 line is missing) +grep -c '^< ' /tmp/${NAME}_diff # >0 expected = your RD additions (hooks/includes/etc.) +``` + +- `> ` lines = 3.10 content NOT present in your merged file = **content you dropped. BAD.** + Keep resolving until this is 0. (Rare legitimate exception: a 3.10 line RD intentionally + replaced — e.g. `DEBUG`→`VICE_DEBUG`. If you believe a `>` line is an intentional RD + replacement, list it explicitly in your report so the lead can confirm.) +- `< ` lines = lines in your file but not in 3.10 = your preserved RD additions. Eyeball + them: every one should be a hook/include/API-ext/log/VICE_DEBUG line, NOT leftover 3.1 + code. If you see leftover 3.1 logic here, you failed to take 3.10's version — fix it. +- Also: `grep -c '^<<<<<<<\|^=======\|^>>>>>>>' "$LIVE"` MUST be 0 (no leftover markers). +- The file must still be syntactically plausible C/C++ (balanced braces; includes intact). + +## DO NOT TOUCH (RD-custom config — merging toward vanilla destroys them) + +`root/vice.h`, `root/vice_sdl.h`, `arch/vicetypes.h`, anything under `arch/` that is RD +platform glue, and `vice_debugger_hook.h`, `ViceWrapper.*`, `ViceLogWrapper.*`. If your +batch seems to require editing one of these, STOP and message the lead. + +## Cross-cutting conventions (coordinate via SendMessage) + +- **Snapshot/REU extension**: RD adds `save_reu_data` / `store_reu_data` and cart-ROM + snapshot extensions threading through `snapshot.c`, `c64-snapshot.c`, + `c64memsnapshot.c`, `cart/reu.c`, `drive-snapshot.c`. If your file calls a snapshot + helper whose signature you're unsure of, message the owner of that file (or the lead) + rather than guessing. Keep signatures identical to what the live 3.1+RD tree already used. +- **VICE_DEBUG rename**: apply consistently; it's RD-wide. + +## TEAM RULES (strict) + +1. **Edit ONLY the files in your assigned task.** Never touch another batch's files. +2. **Do NOT run any git command that changes state** (no add/commit/checkout/reset/stash/ + branch). The lead reviews your working-tree edits and commits them. Read-only git + (`git diff `, `git status`) is fine. +3. Use `/tmp/_*` for all scratch. Never use bare `/tmp/_b` etc. +4. When your task is done, mark it completed via TaskUpdate and SendMessage the lead a + concise per-file report: for each file, the conflict count you resolved and the final + `> `-line count (must be 0) and a one-line note on any judgment call. +5. If a file is genuinely too hard / deeply RD-customized / you'd be guessing — do NOT + guess. Mark it and SendMessage the lead with specifics. Partial-but-correct beats + complete-but-wrong. Per project mandate: do it right. +6. Then check TaskList for the next available task (lowest ID first) and continue. diff --git a/docs/superpowers/notes/2026-05-28-phase-2-step2-functional-gating.md b/docs/superpowers/notes/2026-05-28-phase-2-step2-functional-gating.md new file mode 100644 index 00000000..e9c6709e --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-phase-2-step2-functional-gating.md @@ -0,0 +1,83 @@ +# Phase 2 Step 2 — Functional-file gating completion summary + +**Date:** 2026-05-28 +**Branch:** `vice-3.10-phase-2-step2` +**Plan:** `docs/superpowers/plans/2026-05-28-vice-3.10-phase-2-step2-functional-gating.md` + +## Goal + +Gate slajerek's *functional* `c64d_*` modifications in the 11 Tier A+B files behind +`#ifdef RETRODEBUGGER`, so the ON build behaves exactly as before (regression suite green) +and the OFF build reverts toward vanilla VICE 3.1 (clean hook-free bisection build) for the +cleanly-gateable changes. + +## Scope + +- **Included (11 files):** `joyport/joystick.c`, `joyport/mouse.c`, `viciisc/viciitypes.h`, + `viciisc/vicii-draw-cycle.c`, `c64/patchrom.c`, `root/sound.c`, `sid/sid-snapshot.c`, + `root/keyboard.c`, `root/vsync.c`, `sid/sid.c`, `c64/c64-snapshot.c`. +- **Deferred to the 3.10 vendor swap (Tier C/D):** `resid/resid-filter.cpp`, + `resid/resid-sid.cpp`, `sounddrv/soundsdl.c` (C++/audio rewrites) and + `c64/c64cpusc.c`, `drive/drivecpu.c` (CPU inline-expansion). These get re-done against + 3.10 source, so gating the 3.1 copies would be throwaway. +- **Untouched:** the pervasive `types.h`→`vicetypes.h` rename (mechanical, handled at the swap). + +## Gating patterns used + +- **Pure additions** (slajerek added a call/def/block): `#ifdef RETRODEBUGGER … #endif`. +- **Replacements** (slajerek changed vanilla code): `#ifdef RETRODEBUGGER #else #endif` — every `#else` copied verbatim from `~/vice-ref/3.1/src/`. +- **Conditional guard:** `vicii-draw-cycle.c` sprite-draw uses `VICE_HOOK_VIC_DRAW_SPRITES()` + (added to `vice_debugger_hook.h`): ON = `(c64d_skip_drawing_sprites == 0)`, OFF = `1` + (vanilla always draws sprites). +- **Storage class:** `static` removals gated `#ifdef RETRODEBUGGER`(non-static)`#else`(static). + +## Commits + +| Commit | Content | +|--------|---------| +| `3f778d4` | Step 2 plan | +| `d9ed0ed` | Batch 1: 7 non-signature files (mouse, viciitypes, vicii-draw-cycle, patchrom, joystick, sound, sid-snapshot) | +| `68835f1` | Batch 2: 4 signature files (keyboard, vsync, sid, c64-snapshot) + joystick LOGD cleanup | + +## Verification + +- **ON build:** clean-from-scratch Release build succeeds; suite `28 passed, 1 skipped, 1 xfailed`, stable across 3 runs. ON behavior is unchanged because each `#ifdef RETRODEBUGGER` arm is exactly slajerek's prior code. +- **OFF correctness (the suite can't test this):** verified with `unifdef -URETRODEBUGGER` + per file, diffing the OFF path against the vanilla reference. Result: **no RETRODEBUGGER/`c64d_` + functional behavior leaks into the OFF path.** Files with zero functional OFF residual: + `mouse.c`, `patchrom.c`, `sid-snapshot.c`, `viciitypes.h`, `joystick.c` (after the LOGD cleanup), + `sound.c` (behavior; signature exception below). `vicii-draw-cycle.c` is vanilla-by-construction + (guard macro OFF=1). +- **Flag-OFF syntactic:** the new `VICE_HOOK_VIC_DRAW_SPRITES()` guard compiles with + `RETRODEBUGGER` undefined (statement + `if(...)` contexts). + +## OFF-purity exceptions (documented, accepted) + +These are intentional limits on the "OFF == vanilla" goal. ON-build correctness is unaffected. + +### Retained signatures (gating a signature ripples to all callers — body gated instead) + +| Function | File | Vanilla → Slajerek | Note | +|---|---|---|---| +| `keyboard_key_pressed` / `keyboard_key_released` | `root/keyboard.c` | `void`→`int` return | body `return` values gated; signature kept | +| `vsync_do_vsync` | `root/vsync.c` | +`isPaused` param | body behavior gated; call sites gated | +| `sound_flush` | `root/sound.c` | `()`→`(int isPaused)` | paired with vsync call site (gated); signature kept | +| `sid_sound_machine_open` engine hook | `sid/sid.c` | `open(d)`→`open(d, chipno)` | engine vtable; call site gated | +| `c64_snapshot_write` / `c64_snapshot_read` | `c64/c64-snapshot.c` | extended params (+ callee ripples) | bodies/new funcs gated; signatures kept | +| various `static`→external | keyboard/vsync/sid/sound | linkage only | non-functional | + +### Non-hook slajerek divergences left for the 3.10 reconciliation (not debugger hooks, out of scope) + +- `sid/sid.c`: ReSID-FP engine support (guarded by its own `HAVE_RESID_FP` flag), `byte`→`value` + param rename, added `LOGD`/`log.h`. +- General: brace-style reformatting, added comments/LOGD lines across files. + +These are pre-existing slajerek-vs-vanilla differences unrelated to `c64d_*` debugger hooks; they +will be reconciled when slajerek's tree is merged onto vanilla VICE 3.10. + +## Net result + +Every cleanly-gateable debugger functional change in the Tier A+B files is now behind +`RETRODEBUGGER`. Combined with Step 1 (the 36 `VICE_HOOK_*` side-effect macros), the debugger +hook surface across all non-Tier-C/D files is consolidated and gated. Remaining hook work is the +Tier C/D files, folded into Phase 3 (the VICE 3.10 vendor swap). diff --git a/docs/superpowers/notes/2026-05-28-phase-3-chunk1-error-landscape.md b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-error-landscape.md new file mode 100644 index 00000000..186eb214 --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-error-landscape.md @@ -0,0 +1,79 @@ +# Phase 3 Chunk 1 — Task 6: build attempt + error landscape + +**Date:** 2026-05-28 +**Branch:** `vice-3.10-phase-3-vendor-swap` +**Build:** macOS Release, `xcodebuild ... -configuration Release -arch arm64` (unsigned). Log: `/tmp/chunk1-build.log`. + +## Result: BUILD FAILED (exit 65), failed FAST on missing headers + +The build stopped after 5 errors — all **missing-header** errors — before reaching a +single `CompileC` of a vice translation unit's *body*. So we have NOT yet seen the +type/subsystem error wave; the tree is blocked at the `#include` resolution layer. + +The 3 distinct first errors: +- `root/uiapi.h:127` → `arch/shared/uiactions.h` not found +- `root/maincpu.h:31` → `mainlock.h` not found +- `c64/c64rom.c:42` → `sha1.h` not found + +## HEADLINE FINDING: the vendor drop is incomplete — 3.10's NEW files were never added + +Task 2 only **replaced same-path files** (858 SAME + the MOVED/hooked merges). It never +**added** the files 3.10 introduced. The vendor-dropped 3.10 files now `#include` those +new headers, which don't exist in the tree → immediate build failure. + +Static scan (`#include "x.h"` in the vice tree whose basename has no file in the tree, +cross-referenced against `~/vice-ref/3.10/src/`): **62 genuine new-3.10 headers referenced +but absent** (the other 86 "missing" are RetroDebugger GUI / system headers that resolve via +other search paths — false positives). The 62, grouped: + +| Group | Examples | ~count | +|-------|----------|--------| +| **New cartridge types** | bisplus, blackbox3/4/8/9, bmpdataturbo, drean, freezeframe2, gmod3, hyperbasic, ieeeflash64, ltkernal, magicdesk16, maxbasic, megabyter, multimax, partner64, profidos, ramlink, rexramfloppy, sdbox, spaceballs, tapecart, turtlegraphics, uc1, uc2, zippcode48 | ~25 | +| **New userport devices** | userport_{diag_pin,funmp3,hks_joystick,hummer_joystick,io_sim,petscii_snespad,ps2mouse,spt_joystick,superpad64,synergy_joystick,wic64,woj_joystick} | ~12 | +| **New drive types** | cmdhd (drive/iec/cmdhd.h) | 1 | +| **New / reorganized subsystems** | `mainlock.h` (mainlock — needed by 3.10 mainc64cpu), `sha1.h` (ROM checksums, used by c64rom), `arch/shared/uiactions.h` + `uihotkeys.h` (UI actions/hotkeys), `profiler.h` (new profiler), `monitor_binary.h` (binary monitor), `render-common.h` (video render), `fsdevice-filename.h` (fsdevice split), `archdep.h`/`archdep_dir.h`/`archdep_exit.h` (archdep reorg), `rawnetarch.h`, `opencbm.h`, `plus4parallel.h`, `iec-ieee488-shared.h`, `usbsid.h` | ~15 | + +Each new header generally has a `.c` counterpart that also must be added to the tree AND the +build lists. So the real first task is a **second vendor-drop pass that ADDS 3.10's new files** +(largely mechanical: copy from `~/vice-ref/3.10/src/` + `types.h`→`vicetypes.h` rename + add to +CMake/Xcode). Most (carts, userport devices) are self-contained; a few (mainlock, archdep, +uiactions) need integration with RetroDebugger's own arch layer. + +## Second finding: vicetypes.h must be reconciled to 3.10's type model + +`src/Emulators/vice/arch/vicetypes.h` (slajerek's shim, included everywhere via the rename) +diverges from vanilla 3.10 `types.h`: +- **`CLOCK` is 32-bit** (`typedef DWORD CLOCK`, DWORD=`unsigned int`) vs 3.10's **`typedef uint64_t CLOCK`**. This won't error (silent truncation) but is a real correctness bug — and 3.10's clock-overflow handling (which replaced `clkguard`) assumes 64-bit CLOCK. Must change to `uint64_t` + `CLOCK_MAX`. +- 3.10 `types.h` includes ``/`` + **``** unconditionally; vicetypes.h only pulls stdint under `#ifdef LINUX` (relies on SDL on macOS) and never includes stdbool — but 3.10 now uses `bool` (e.g. `via_context_s.enabled`). vicetypes.h must unconditionally provide the stdint types + `bool`. +- Keep the `BYTE`/`WORD`/`DWORD`/`SWORD` shims (slajerek's ungated c64d_ code still uses them). + +## Still-deferred (will surface once the header layer clears) — Chunk 2 subsystem merges + +The 22 conflict files left at 3.1 content (CIA core, drive/diskunit cluster, SID 2→8 + ReSID-FP, +c64memsc mem model, keyboard signature ripple, sound.c, vsync+vicii, snapshot, mouse) plus the +CPU cores (c64cpusc/drivecpu), monitor.c, and Tier C resid/soundsdl. These need build feedback, +which only becomes available after the header layer + vicetypes are fixed. + +## GONE files to remove from the build (Task 5) + +`root/clkguard.c`, `c64/patchrom.c`, `platform/*.c` (11) — deleted/removed upstream. Still in the +build list (and still present at 3.1 content). Remove from CMake + Xcode Sources phase. + +## Recommended Chunk 2 plan (in order) + +1. **Complete the vendor drop:** add 3.10's new files (62+ headers + their .c) to the tree + (mechanical copy + rename) and to the build lists; remove the GONE files. Reconcile + `vicetypes.h` (CLOCK=uint64_t, unconditional stdint/stdbool). → clears the header layer. +2. **Heavy subsystem merges** (the 22 deferred conflict files) + CPU-core re-inline + (c64cpusc/drivecpu) + monitor + Tier C resid/soundsdl, reconciled WITH the cross-cutting + infra (clkguard removal in includers, diskunit dual-drive rename, mainlock stub). Iterate + against the compiler. +3. **Link + run:** resolve undefined symbols (new-file/build-list gaps), get the app launching, + then re-enable the WebSocket regression suite as the acceptance gate (target 28/1/1). + +## Note on this build attempt + +Built as-is (no build-list surgery) for the fastest, safest signal. Because it failed at the +header layer, the GONE-file errors and the type/subsystem error wave were never reached — they'll +appear after step 1 above. The key takeaway (incomplete vendor drop + vicetypes mismatch) is the +actionable Chunk 2 starting point. diff --git a/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task1-filemap.md b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task1-filemap.md new file mode 100644 index 00000000..c7896b34 --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task1-filemap.md @@ -0,0 +1,47 @@ +# Phase 3 Chunk 1 — Task 1: file-fate map + merge scoping + +**Date:** 2026-05-28 +**Branch:** `vice-3.10-phase-3-vendor-swap` +**Data:** `phase3-data/chunk1-filemap.tsv` (1155 rows: `\t\t`) + +## What this is + +Maps every source/header file in `src/Emulators/vice/` (excluding `ViceInterface/` and our +`vice_debugger_hook.h`) to its vanilla VICE 3.10 equivalent, to drive the Chunk 1 3-way merge. +Path-mapping rules applied: slajerek `root/` → vanilla top-level ``; resid +`resid-.cpp` → `resid/.cc`; resid-fp `residfp-.cpp` → `resid-fp/.cc`. + +## Category counts (1155 files total) + +| Fate | Count | Meaning | Merge handling | +|------|-------|---------|----------------| +| **SAME** | 858 | same relative path in 3.10 | mechanical 3-way merge (most are unhooked → content + `vicetypes.h` rename) — Task 2 | +| **MOVED** | 154 | found in 3.10 at a different path (basename match) | path-aware mechanical merge — Task 2 (verify each basename match is the real file, not a namesake) | +| **GONE** | 142 | no 3.10 file by that basename | triage below — Task 4 | +| OURS | 1 | `vice_debugger_hook.h` (ours) | leave | + +## GONE triage: only ~32 are actually COMPILED (the real breakage set) + +Of the 142 GONE files, only ~32 are referenced in the build; the other ~110 are non-compiled / +vestigial (headers, unused platform variants) and can be ignored. The compiled-GONE set, grouped: + +| Group | Files | Disposition | +|-------|-------|-------------| +| `platform/` subsystem | `platform.c`, `platform_*_runtime_os.c` (×9), `platform_x86_runtime_cpu.c` | 3.10 REMOVED the platform-detection subsystem. Drop all from the build; confirm nothing references `platform_get_*`. | +| translation / legacy `root/` | `root/translate.c`, `root/libm_math.c`, `root/embedded.c`, `root/ioutil.c` | 3.10 removed translation; `ioutil`/`embedded`/`libm_math` reorganized. Drop + reconcile any callers. | +| `root/clkguard.c` | 1 | DELETED upstream; CLOCK-overflow handling redesigned. Remove + fix the 9 includers (Task 4 Step 1). | +| video render | `video/render1x1crt.c`, `render1x2crt.c`, `render2x2crt.c`, `render2x4crt.c`, `renderyuv.c` | 3.10 restructured `video/`. Adopt 3.10's video-render file set (these specific files replaced). | +| monitor | `monitor/mon_ui.c` | removed in 3.10's monitor rewrite. Drop; monitor replay is a later chunk anyway. | +| c64 | `c64/patchrom.c`, `c64/c64embedded.c` | both gone in 3.10. patchrom fast-boot was `#ifdef RETRODEBUGGER`-gated → OFF-safe to drop. | +| sid/resid | `sid/resid.cpp` (+ resid/resid-fp renames) | resid file naming/structure changed; reconcile in the resid handling. | +| arch SDL-UI | `arch/blockdev.c`, `arch/menu_lightpen.c`, `arch/menu_tfe.c` | SDL-menu/arch files; likely shouldn't be in RetroDebugger's build. Verify + drop. | +| misc drivers | `gfxoutputdrv/doodledrv.c`, `jpegdrv.c`, `diskimage/rawimage.c`, `tapeport/tapelog.c` | individual files; check for 3.10 equivalents (may be renamed/moved) or drop. | + +## Implication for the rest of Chunk 1 + +- **Task 2 (mechanical):** ~1000 SAME+MOVED files, the bulk unhooked → content replace + `vicetypes.h` rename. Delegatable, but MOVED (154) need per-file path verification (basename match could be a namesake). +- **Task 3 (delicate):** ~60 hooked files (the catalog's 64 minus CPU-cores `c64cpusc.c`/`drivecpu.c` and Tier C resid/sound, all deferred to Chunk 2) → hand 3-way merge preserving gated hooks. +- **Task 4 (infra/GONE):** the ~32 compiled-GONE groups above + clkguard/diskunit/mainlock reconciliation. +- **Tasks 5–6:** build-list update + error-landscape capture. + +This is a large multi-session operation (~1000+ files). The mechanical bulk is low-risk; the risk concentrates in the ~60 hooked merges + the GONE/infra reconciliation + (Chunk 2) the CPU-core re-inline and monitor. diff --git a/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task3-merge-scoping.md b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task3-merge-scoping.md new file mode 100644 index 00000000..9c68327b --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-phase-3-chunk1-task3-merge-scoping.md @@ -0,0 +1,132 @@ +# Phase 3 Chunk 1 — Task 2 done + Task 3 scoping & findings + +**Date:** 2026-05-28 +**Branch:** `vice-3.10-phase-3-vendor-swap` + +## Landed this session + +| Commit | Content | +|--------|---------| +| `36683b3` | **Task 2** — vendor-dropped 695 unhooked files (3.10 content + `types.h`→`vicetypes.h`). Verified: each file == vanilla-3.10(col2)+rename, 0 failures; 0 hook tokens in the changed set. | +| `4e41816` | **Task 3a** — 14 hooked files whose upstream delta did NOT overlap a hook → diff3 auto-merged with 0 conflicts. Verified: hook-token counts unchanged pre/post, no leaked markers, rename preserved. | +| `f76ee03` | **Task 3b** — 4 hooked headers (via1d1541.h, viad.h, via.h, interrupt.h): 3.10 content + gated c64d_ decls/fields adapted to 3.10 types. | +| `bc40261` | **Task 3c** — viacore.c (alarm_context+zero/uflow alarms; kept VICE_HOOK_VIA_IRQ_FLAG_CLEAR + c64d_viacore_peek) + c64cia1.c/c64cia2.c (uint sigs; kept VICE_HOOK_CIA* macros, externs, peek wrappers). | +| `f432ce7` | **Task 3d** — vicii-draw-cycle.c (VICE_HOOK_VIC_DRAW_SPRITES guard around 3.10's s→as switch; c64d_set_color_register). | + +## REFINED Chunk 1 / Chunk 2 boundary (decided 2026-05-28 mid-Task-3) + +Triaging the 30 conflict files revealed a clean split. **Chunk 1 = vendor drop + +tractable hook merges** (additive/localized hooks onto modestly-changed 3.10 +code, verifiable via the additions-only OFF check). **Chunk 2 = heavy subsystem +rewrites** where 3.10 restructured the model AND slajerek's ungated c64d_ +accessors read that model directly → need build feedback to re-apply correctly +(same character as the CPU cores). Forcing the heavy ones now, with no test net, +risks subtle timing/model bugs. + +**Chunk 1 DONE (8 conflict files merged + 14 auto-merged + headers):** all of the +above commits. + +**Chunk 1 TRACTABLE-MERGE PHASE COMPLETE (2026-05-28).** 24 hooked files merged +total (commits 4e41816, f76ee03, bc40261, f432ce7, 0eee15c). The +"remaining-tractable" candidates were re-triaged by conflict CONTENT (not count): +only `root/machine.c` and `c64/cart/reu.c` (`0eee15c`) were genuinely tractable; +the rest turned out heavy/coupled and moved to Chunk 2: +- `joyport/mouse.c` — 3.10 rewrote joyport + calls the REMOVED `clk_guard_add_callback` +- `c64/c64-snapshot.c` — 3.10 changed snapshot_create/drive_snapshot sigs; couples to reu.c +- `iecbus/iecbus.c` — 3.10 multi-drive iecbus restructure +- `root/vsync.c` + `viciisc/vicii.c` — 3.10 rewrote the vsync timing/metrics model; vicii.c calls it +- `sid/fastsid.c`, `sid/sid-resources.h` — entangled with SID 2→8 + ReSID-FP + float-sound + +**Net: every remaining conflict file is now a Chunk 2 item** (see the deferral list +above + these). Chunk 2 = the heavy subsystem rewrites + CPU cores + monitor + +Tier C, reconciled WITH the infra (clkguard/diskunit/mainlock) using build feedback, +to a building + suite-green state. + +**Remaining Chunk 1 tasks:** Task 5 (build-list reconciliation: drop GONE files — +clkguard.c, patchrom.c, platform/* — add NEW 3.10 files), Task 6 (build attempt → +categorized error-landscape doc = the Chunk 2 planning input). Task 4 infra +(clkguard include removal, diskunit rename, mainlock stub) is largely entangled +with the deferred subsystem files, so it folds into Chunk 2 rather than Chunk 1. + +**Chunk 2 — heavy subsystem rewrites (defer, need build feedback):** +- CPU cores: c64/c64cpusc.c, drive/drivecpu.c (already deferred) +- monitor: monitor/monitor.c (already deferred) +- Tier C: resid/*, resid-fp/*, sounddrv/soundsdl.c (already deferred) +- **CIA core:** core/ciacore.c (SDR delay-line rewrite; c64d_ciacore_peek/get_cia_context) +- **drive/diskunit model** (3.10 dual-drive `diskunit_context[u]->drives[d]`): + drive/drive.c, drive/drivemem.c, drive/iec/via1d1541.c, drive/iecieee/via2d.c, + drive/iec/memiec.c — their c64d_ accessors read drive-VIA/drive internals +- **SID 2→8 + ReSID-FP:** sid/sid.c, sid/sid-snapshot.c, sid/sid-resources.c +- **mem model:** c64/c64memsc.c (mem_ram pointer; 33 hook-hunk-lines) +- **signature ripple:** root/keyboard.c + root/keyboard.h (3.10 added `mod` param, + slajerek changed return void→int; ripples to ViceInterface callers) +- root/sound.c (SID-run/pause/mutex gating; 23 conflict hunks, entangled w/ sound subsystem) + +Verification method (reusable, bash-3.2 safe — macOS has no `declare -A`): +- Per-file gate for the vendor drop: `sed 's/#include "vicetypes.h"/#include "types.h"/' live | diff -q - vanilla31` → empty ⇒ file diverged from 3.1 by ONLY the rename ⇒ safe to overwrite with `sed 's/types.h/vicetypes.h/' vanilla310 > live`. +- 3-way merge: `git merge-file -p --diff3 ours base theirs` where `base`/`theirs` are vanilla 3.1/3.10 **pre-renamed to vicetypes.h** (so the rename isn't a spurious conflict) and `ours` = the gated live file. + +## The 64-file hook surface (token scan: `c64d_|RETRODEBUGGER|VICE_HOOK_`) — partition + +- **44 mergeable hooked files** (all SAME-fate, vanilla path = filemap col2, both 3.1/3.10 exist): + - **14 DONE** (Task 3a, clean auto-merge). + - **30 CONFLICTED** — need hand resolution (135 conflict hunks total). See table below. +- **8 RetroDebugger arch glue** — `arch/{mousedrv,ui,ui.h,uimon,uimsgbox,uistatusbar,video,vsyncarch}.c` map (namesake) to vanilla `arch/gtk3|sdl/*`. These are RD's OWN archdep layer, NOT vendored VICE. **Leave as-is**; they will surface as archdep-interface errors in Task 6 → later integration chunk. +- **12 Chunk 2 deferrals:** `c64/c64cpusc.c`, `drive/drivecpu.c` (CPU-core inline); `monitor/monitor.c` (monitor subsystem); `resid/resid-{filter,sid}.{cpp,h}`, `resid-fp/residfp-{sid.cpp,sid.h,voice.h}`, `sounddrv/soundsdl.c` (Tier C). +- **1 infra (Task 4):** `c64/patchrom.c` — GONE in 3.10 (deleted). Fast-boot was `#ifdef RETRODEBUGGER`-gated → OFF-safe to drop. + +## The 30 conflict files (Task 3 hand-merge queue) + +`hookhunk` = conflict-hunk lines carrying hook tokens; `rename` = theirs-side lines with `diskunit_context`/`uint8_t`/`uint16_t`. + +| File | hunks | hookhunk | rename | Notes | +|---|---|---|---|---| +| c64/c64-snapshot.c | 3 | 3 | 1 | snapshot signature ext + `_in_memory` fn | +| c64/c64cia1.c | 2 | 4 | 1 | | +| c64/c64cia2.c | 2 | 4 | 1 | | +| c64/c64memsc.c | 3 | 33 | 3 | `mem_ram` pointer-vs-array; heavy hooks | +| c64/cart/reu.c | 7 | 2 | 7 | REU — relevant to riscv-c64 work; rename-heavy | +| core/ciacore.c | 5 | 2 | 1 | CIA core | +| core/viacore.c | 1 | 1 | 0 | 3.10 added t1/t2 zero/underflow alarms; VICE_HOOK_VIA_IRQ_FLAG_CLEAR placement | +| drive/drive.c | 3 | 0 | 2 | **take-theirs UNSAFE**: ours has untokened `*_for_snapshot` GCR/P64 fields + NULL guards; 3.10 restructured to `diskunit_context[unit]->drives[d]` | +| drive/drivemem.c | 3 | 2 | 1 | | +| drive/iec/memiec.c | 8 | 6 | 7 | | +| drive/iec/via1d1541.c | 5 | 12 | 2 | | +| drive/iec/via1d1541.h | 1 | 1 | 4 | take theirs (diskunit+uint) + re-add gated `c64d_via1d1541_peek` | +| drive/iecieee/via2d.c | 4 | 10 | 3 | | +| drive/viad.h | 1 | 1 | 5 | take theirs + re-add gated `c64d_via2d_peek` | +| iecbus/iecbus.c | 2 | 25 | 1 | big hook regions | +| joyport/mouse.c | 3 | 6 | 2 | static-removal linkage | +| root/interrupt.h | 1 | 0 | 0 | **TRAP**: slajerek `DEBUG`→`VICE_DEBUG` rename half-merged by diff3 (some blocks kept VICE_DEBUG, conflict region would flip to DEBUG). Resolve ALL guards consistently to VICE_DEBUG, fold in theirs' `LOG_DEFAULT` logging. | +| root/keyboard.c | 23 | 14 | 0 | `key_pressed/released` void→int; many #else vanilla arms collide w/ upstream | +| root/keyboard.h | 1 | 0 | 0 | needs FULL 3.10-file context (3.10 added `key_custom_func_t`; also `key_pressed/released` signature) | +| root/machine.c | 3 | 2 | 0 | | +| root/sound.c | 23 | 33 | 1 | SID-run gating, pause path, mutex; Step-2 #else arms collide w/ upstream | +| root/via.h | 2 | 2 | 13 | take theirs struct (bool enabled, alarm_context, sr_underflow, uint types) + re-add gated `c64d_irq_flagged` field + `c64d_viacore_peek` decl | +| root/vsync.c | 8 | 10 | 0 | **COUPLED**: 3.10 changed `vsync_do_vsync(canvas)` (dropped skip_frame + raster_skip_frame wrap); slajerek added isPaused. Drives the vicii.c/raster callers. | +| sid/fastsid.c | 6 | 2 | 4 | | +| sid/sid-resources.c | 2 | 0 | 0 | **take-theirs UNSAFE**: ours has untokened `parsid_port` + `HAVE_RESID_FP` wiring (coupled to deferred ReSID-FP); 3.10 added USBSID | +| sid/sid-resources.h | 1 | 0 | 0 | 3.10 dropped stereo/triple addr, added sid2-8; ours added set_sid_engine/model externs | +| sid/sid-snapshot.c | 1 | 2 | 0 | | +| sid/sid.c | 7 | 12 | 8 | 2→8 SID support; `sid_read` restructure; `sid_sound_machine_open(+chipno)` | +| viciisc/vicii-draw-cycle.c | 1 | 1 | 0 | `VICE_HOOK_VIC_DRAW_SPRITES` guard region | +| viciisc/vicii.c | 3 | 0 | 0 | **take-theirs MOSTLY**: vsync_do_vsync caller (coupled to vsync.c) + 3.10 deleted `__MSDOS__` blocks | + +## Critical findings (shape how the hand-merge must be done) + +1. **"Take theirs" is NOT mechanically safe**, even for hookhunk=0 files. `drive.c`, `sid-resources.c`, `vicii.c` carry **functional, untokened** slajerek changes (snapshot GCR fields; ReSID-FP wiring; the isPaused param) that taking theirs would silently drop. Every conflict needs per-hunk judgment. +2. **diff3 can silently mis-merge** (no marker) by line-combining ours+theirs into plausible-but-wrong code — e.g. `interrupt.h` ended with `#ifdef VICE_DEBUG` (ours) wrapping `log_debug(LOG_DEFAULT,…)` (theirs). Must eyeball auto-merged regions of conflict files too, not just the markers. +3. **Coupling:** `vsync.c`'s new signature drives `vicii.c` (and other raster callers); `sid-resources.c`↔ deferred ReSID-FP; `drive.c`↔ the diskunit restructure. Resolve coupled files together. +4. **Some files need full 3.10-file context** (e.g. `keyboard.h`) — the diff3 hunk alignment alone is misleading. +5. **diskunit rename** lands naturally through these merges (theirs side) for hooked drive files; unhooked drive files already got it via Task 2. Task 4's diskunit step then mostly reconciles `ViceInterface/` consumers + verifies consistency. + +## Suggested hand-merge order (low-risk → coupled) + +1. **Headers:** via1d1541.h, viad.h, via.h (rename + re-add gated decl/field), interrupt.h (VICE_DEBUG consistency), keyboard.h (full-context). +2. **CIA/VIA cores:** core/viacore.c, core/ciacore.c, c64cia1/2.c — chip cores, careful. +3. **Drive cluster (with diskunit):** drive.c, drivemem.c, via1d1541.c, via2d.c, memiec.c, iecbus.c. +4. **SID cluster:** sid.c, sid-resources.c/.h, fastsid.c, sid-snapshot.c (note ReSID-FP coupling → may partially defer to Chunk 2). +5. **VIC-II + vsync coupling:** vsync.c + vicii.c + vicii-draw-cycle.c together. +6. **Remaining:** c64memsc.c (mem_ram), c64-snapshot.c, machine.c, mouse.c, reu.c, keyboard.c, sound.c (the two 23-hunk files last — most #else-arm collisions). + +After all 30: Task 4 (clkguard/diskunit/patchrom/mainlock/soundsdl/resid infra), Task 5 (build lists), Task 6 (build attempt + error landscape). CPU cores + Tier C + monitor = Chunk 2. diff --git a/docs/superpowers/notes/2026-05-28-vice-3.1-to-3.10-migration-survey.md b/docs/superpowers/notes/2026-05-28-vice-3.1-to-3.10-migration-survey.md new file mode 100644 index 00000000..6bf5ab2b --- /dev/null +++ b/docs/superpowers/notes/2026-05-28-vice-3.1-to-3.10-migration-survey.md @@ -0,0 +1,386 @@ +# VICE 3.1 → 3.10 Migration Survey (Phase 3 Swap Planning Input) + +**Date:** 2026-05-28 +**Purpose:** Map exactly what changed between vanilla VICE 3.1 and 3.10 for the files slajerek +modified, so Phase 3 can write a concrete replay plan. +**Source trees verified:** +- Vanilla 3.1: `~/vice-ref/3.1/src/` +- Vanilla 3.10: `~/vice-ref/3.10/src/` +- Slajerek fork: `/Users/garion/Projects/RetroDebugger/src/Emulators/vice/` +- Inputs: `docs/vice-hook-surface.md`, `docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md` + +--- + +## Section 1: File-Fate Map for Slajerek-Touched Files + +Path mapping rules applied: +- Slajerek `root/` → vanilla `src/` (top-level) +- Slajerek `resid/resid-.cpp` → vanilla `resid/.cc` (rename convention) +- `resid-fp/` is entirely slajerek's own (no vanilla counterpart at all) +- `arch/` files are slajerek's own SDL arch (no vanilla counterpart) + +### DELETED / MOVED files (the breakage set) — 11 files + +| Slajerek file | 3.10 fate | New path in 3.10 | Notes | +|---|---|---|---| +| `root/clkguard.c` | **DELETED** | — | Removed from all of 3.10. 9 slajerek files `#include "clkguard.h"`. `ciacore_init()` and `viacore_init()` signatures dropped the `clk_guard_t *` parameter. Overflow callbacks now handled differently. **HIGH IMPACT.** | +| `root/clkguard.h` | **DELETED** | — | See above. | +| `c64/patchrom.c` | **DELETED** | — | Grep of all 3.10 c64/ sources finds no `patch_kernal` anywhere. Functionality appears removed from vanilla. Slajerek's 7-hit file is a hard excluded file (class 3 functional); must be retained as-is from the 3.1 fork. | +| `sounddrv/soundsdl.c` | **MOVED** | `arch/shared/sounddrv/soundsdl.c` | Moved to `arch/shared/`. Slajerek's version (415 lines) vs 3.10 (302 lines). The SDL callback rewrite must be replayed at the new path. | +| `resid/resid-filter.cpp` | **RENAMED** | `resid/filter.cc` | Slajerek uses `.cpp` suffix. Vanilla 3.10 has `filter.cc` (686 lines vs 3.1's 776 lines — 3.10 trimmed some 8580 code itself). The slajerek deletions (8580 section) need to be re-applied against 3.10's `filter.cc`. | +| `resid/resid-sid.cpp` | **RENAMED** | `resid/sid.cc` | 3.10's `sid.cc` is 1087 lines vs 3.1's 1027. Slajerek's is 1014 lines. Multiple behavioral changes must be re-replayed against the 3.10 base. | +| `resid/resid-sid.h` | **RENAMED** | `resid/sid.h` | Naming convention only. | +| `resid/resid-filter.h` | **RENAMED** | `resid/filter.h` | Naming convention only. Inline hook bodies must be re-applied. | +| `resid-fp/residfp-sid.cpp` | **SLAJEREK-ONLY** | no vanilla counterpart | `resid-fp/` directory does not exist in vanilla 3.1 or 3.10. This is entirely slajerek's addition. It does not need to be patched against upstream — it is simply carried forward. | +| `resid-fp/residfp-sid.h` | **SLAJEREK-ONLY** | no vanilla counterpart | Same. | +| `resid-fp/residfp-voice.h` | **SLAJEREK-ONLY** | no vanilla counterpart | Same. | + +### SAME-PATH files (most files) — 53 files + +| Slajerek file | 3.10 path | 3.1 lines | 3.10 lines | Delta | Notes | +|---|---|---|---|---|---| +| `c64/c64cpusc.c` | SAME | 192 | 192 | 0 | Shell file only — both still use `#include "../mainc64cpu.c"`. BYTE→uint8_t in struct, DWORD→uint32_t. CLK_INC macro identical. MEMMAP_UPDATE gains extra `0` param in 3.10. Slajerek's inlined version (4357 lines) is off mainc64cpu.c 3.1 — needs full re-inline against 3.10's mainc64cpu.c (+193 lines). | +| `c64/c64memsc.c` | SAME | 1116 | 1534 | +418 | **HIGH RISK.** Slajerek changed `mem_ram` to a pointer; 3.10 has `uint8_t mem_ram[C64_RAM_SIZE]` (static array again). Complete conflict. Also adds `c64-memory-hacks.h`, `c64model.h`, watchpoint infrastructure. | +| `c64/c64cia1.c` | SAME | 532 | 524 | -8 | BYTE→uint8_t throughout. Otherwise structurally similar. Hook insertion points (register read/write wrappers) should be findable. | +| `c64/c64cia2.c` | SAME | 371 | 343 | -28 | Same as cia1. | +| `c64/c64-snapshot.c` | SAME | 149 | 154 | +5 | Minimal change. Slajerek signature extensions must be replayed carefully. | +| `c64/c64memrom.c` | SAME | 115 | 110 | -5 | Minimal. Low risk. | +| `c64/cart/reu.c` | SAME | 1602 | 1688 | +86 | DMA cycle bump points likely shifted. Low risk — insertions are mechanical. | +| `c64/cart/c64-generic.c` | SAME | — | — | — | Small file; peek/poke additions. Low risk. | +| `core/ciacore.c` | SAME | 1734 | 2637 | +903 | **MODERATE-HIGH.** ciacore_init signature dropped `clk_guard_t *` param. Substantial new alarm/timer logic. IRQ flag hook insertion points need re-identification in 52% more code. | +| `core/viacore.c` | SAME | 1423 | 2233 | +810 | Same situation — viacore_init dropped `clk_guard_t *`. +57% code. Hook insertion points need re-identification. | +| `core/flash040core.c` | SAME | — | — | small | CLK_DEC/INC hooks; low risk. | +| `drive/drivecpu.c` | SAME | 725 | 715 | -10 | **HIGH RISK.** drive_context_t → diskunit_context_t rename throughout. mainlock.h added. Slajerek's version (4130 lines) inlines 6510core.c 3.1 (3062 lines) + hooks; 3.10's 6510core.c is 3476 lines (+414). Full re-inline needed. | +| `drive/drive.c` | SAME | 879 | 1104 | +225 | +26%. Additive definitions mostly. Medium risk. | +| `drive/drivemem.c` | SAME | 257 | 312 | +55 | Cell R/W hooks; low-medium risk. | +| `drive/rotation.c` | SAME | 1309 | 1349 | +40 | Track dirty hook; minimal diff. Low risk. | +| `drive/drive-writeprotect.c` | SAME | — | — | small | Peek definition only; low risk. | +| `drive/iec/memiec.c` | SAME | 178 | 281 | +103 | +58%. Cell read/write hooks in both. More code means re-finding insertion points. Medium risk. | +| `drive/iec/via1d1541.c` | SAME | 398 | 406 | +8 | Minimal. Low risk. | +| `drive/iecieee/via2d.c` | SAME | 480 | 566 | +86 | +18%. Low-medium risk. | +| `iecbus/iecbus.c` | SAME | 538 | 570 | +32 | Additive definitions. Low risk. | +| `viciisc/vicii.c` | SAME | — | — | moderate | IRQ flag hook, struct field additions via viciitypes.h. Medium risk. | +| `viciisc/vicii-cycle.c` | SAME | 533 | 636 | +103 | +19%. VIC raster/frame/cycle hooks; insertion points shifted. Medium risk. | +| `viciisc/vicii-draw-cycle.c` | SAME | — | — | small | Sprite skip guard; low risk for logic, insertion point stable. | +| `viciisc/vicii-irq.c` | SAME | — | — | small | IRQ flag hooks; stable. | +| `viciisc/viciitypes.h` | SAME | 296 | 296 | 0 | Identical line count. Only change: BYTE→uint8_t, DWORD→uint32_t, WORD→uint16_t throughout. Slajerek struct field additions (c64d_irq_flag etc.) replay cleanly. | +| `sid/sid.c` | SAME | 629 | 1340 | +711 | **MODERATE-HIGH.** +113%. Major expansion; `sid_read_chip()` restructuring must be re-done in 2× the code. | +| `sid/sid-snapshot.c` | SAME | 1089 | 1208 | +119 | Gating change and mutex addition; medium risk. | +| `sid/sid-resources.c` | SAME | — | — | small | Static promotions; low risk. | +| `sid/sid-resources.h` | SAME | — | — | small | extern declarations; low risk. | +| `sid/fastsid.c` | SAME | 1275 | 1396 | +121 | +9%. Channel data hook; low risk. | +| `monitor/monitor.c` | SAME | 2389 | 3421 | +1032 | **HIGH RISK.** +43%. 4 `c64d_set_debug_mode` injection points in step/next/return functions. Static promotions. New `monitor_binary.c` (2168 lines) added. mon_profile.c (new), mon_ui.c removed. | +| `keyboard.c` | SAME | 1836 | 1365 | -471 | -26%. `keyboard_key_pressed()` return type change must be re-applied to now-smaller file. | +| `joyport/joystick.c` | SAME | 776 | 4255 | +3479 | **HIGH RISK.** +448%. Massively expanded. `joystick_process_latch()` still exists (line 299 in 3.10). The delay bypass must be re-applied but the function body is in totally different context. | +| `joyport/mouse.c` | SAME | 2138 | 681 | -1457 | -68%. Mouse split into multiple files (mouse_1351.c, mouse_neos.c etc.) in 3.10. Slajerek's 2 static-promotion changes need to be re-applied to the smaller remaining file. | +| `root/vsync.c` | SAME (vsync.c) | 648 | 716 | +68 | vsync_do_vsync() signature changed to `void vsync_do_vsync(struct video_canvas_s *c)` in 3.10 (no `been_skipped`). Slajerek added `isPaused` parameter. mainlock_yield() calls added. sound_flush() return type changed bool. **Moderate risk.** | +| `root/sound.c` | SAME | 1778 | 1937 | +159 | Excluded file (class 3); must be carried from 3.1 fork. | +| `root/keyboard.c` | SAME | 1836 | 1365 | -471 | See keyboard.c above. | +| `root/maincpu.h` | SAME | — | — | small | extern c64d_maincpu_clk; stable. | +| `root/interrupt.h` | SAME | — | — | small | extern declaration; stable. | +| `root/cia.h` | SAME | 173 | 219 | +46 | +27%. struct field c64d_irq_flag must be re-added. Function pointer sigs: BYTE→uint8_t. | +| `root/via.h` | SAME | 180 | 251 | +71 | +39%. struct field c64d_irq_flagged must be re-added. BYTE→uint8_t throughout. | +| `root/machine.c` | SAME | — | — | small | c64d_set_debug_mode hook; low risk. | +| `root/dma.c` | SAME | — | — | small | CLK_ADD hook; low risk. | +| `root/midi.c` | SAME | — | — | small | CLK hooks; low risk. | +| `root/interrupt.c` | SAME | — | — | small | Definition only; low risk. | +| `drive/viad.h` | SAME | — | — | small | extern declaration; low risk. | +| `drive/iec/via1d1541.h` | SAME | — | — | small | extern declaration; low risk. | +| `arch/ui.c` | SLAJEREK-ONLY | — | — | — | No vanilla 3.10 SDL arch counterpart to diff; carried as-is. | +| `arch/uimon.c` | SLAJEREK-ONLY | — | — | — | Same. | +| `arch/video.c` | SLAJEREK-ONLY | — | — | — | Same. | +| `arch/vsyncarch.c` | SLAJEREK-ONLY | — | — | — | Same. | +| `arch/uistatusbar.c` | SLAJEREK-ONLY | — | — | — | Same. | +| `arch/uimsgbox.c` | SLAJEREK-ONLY | — | — | — | Same. | +| `arch/mousedrv.c` | SLAJEREK-ONLY | — | — | — | Same. | + +### Summary: Breakage set + +| Fate | Count | Files | +|---|---|---| +| DELETED (no 3.10 counterpart) | 3 | `clkguard.c`, `clkguard.h`, `patchrom.c` | +| MOVED (different path in 3.10) | 1 | `sounddrv/soundsdl.c` → `arch/shared/sounddrv/soundsdl.c` | +| RENAMED (same dir, `.cpp`→`.cc`) | 4 | resid/{filter,sid}.{cpp,h} all 4 files | +| SLAJEREK-ONLY (no vanilla at all) | ~10 | `resid-fp/*`, `arch/*` (8 files) | +| SAME PATH | ~53 | All others | + +**Files where hook replay breaks due to structural conflict: 8 files** (`clkguard.c/h` deletion, `patchrom.c` deletion, `soundsdl.c` moved+diverged, 4 resid renames). + +The `resid-fp/` and `arch/` files are slajerek's own code and do not need upstream patching — they simply carry forward. + +--- + +## Section 2: Upstream Structural Changes (3.1 → 3.10) + +### Verified structural changes + +| Change | Confirmed | Impact on slajerek files | +|---|---|---| +| **`clkguard.c/.h` REMOVED** | Yes — not found anywhere in 3.10 | Breaks `ciacore_init()` and `viacore_init()` call sites; 9 slajerek files `#include "clkguard.h"`. `c64memsc.c`, `c64cpusc.c`, `c64acia1.c`, `c64.c`, `viacore.c`, `ciacore.c`, `riotcore.c`, `mouse.c`, `datasette.c` all need include removed. | +| **`datasette.c/.h` → `datasette/`** | Yes — `src/datasette/` dir with 4 files | Slajerek's `root/datasette.c` and `root/datasette.h` need path check; not a modified file (not in the 64). | +| **`tools/` new** | Yes — `src/tools/{cartconv,petcat}/` | No slajerek impact; not compiled by RetroDebugger. | +| **`hvsc/` new** | Yes — HVSC library | No slajerek impact. | +| **`mainlock.c/.h` new** | Yes — threading lock | `mainc64cpu.c` (3.10) includes `mainlock.h`. `drivecpu.c` includes `mainlock.h`. When bringing over the 3.10 mainc64cpu.c base for re-inlining, the `mainlock_yield()` calls inside the main CPU loop are NEW. RetroDebugger has its own thread model; these calls may conflict with `c64d_lock_mutex` / debug pause system. **Moderate risk.** | +| **`profiler.c/.h` + `profiler_data.h` new** | Yes | 3.10's mainc64cpu.c likely uses profiler hooks. Must check when re-inlining. Slajerek already has a CHAMP profiler in c64cpusc.c. | +| **`sounddrv/` → `arch/shared/sounddrv/`** | Yes | soundsdl.c path changed. | +| **`hwsiddrv/` → `arch/shared/hwsiddrv/`** | Yes | Not a slajerek-modified file. | +| **`mididrv/` → `arch/shared/mididrv/`** | Yes | Not a slajerek-modified file. | +| **`socketdrv/` → `arch/shared/socketdrv/`** | Yes | Not a slajerek-modified file. | +| **`iodrv/` removed** | Yes — not found in 3.10 | Not a slajerek-modified file. | +| **Translation subsystem removed** | Yes — `translate.c`, `translate_text.c`, `translate_funcs.h`, `translate_languages.h` all gone | Slajerek files may `#include "translate.h"` — must check. | +| **`datasette.c/.h` at root→subdir** | Yes | Slajerek's datasette.c (root/) is not in the 64-file modified set so no direct hook impact. | +| **`drive_context_t` → `diskunit_context_t`** | Yes — confirmed in drivetypes.h and drivecpu.c | Massive impact: all slajerek drive functions use `drive_context_t *drv`. Requires a global rename across `drivecpu.c` and all drive hook functions in ViceInterface. | +| **`BYTE`/`WORD`/`DWORD` → `uint8_t`/`uint16_t`/`uint32_t`** | Yes — confirmed in types.h (3.10 is top-level, uses stdint.h; BYTE typedef removed) | Pervasive. Every slajerek file using BYTE/WORD/DWORD needs updating. slajerek's `vicetypes.h` still defines BYTE etc. — decision: keep vicetypes.h for slajerek's own code or migrate everything. | +| **`memmap_mem_update()` gained extra param** | Yes — 3.10 adds 3rd `int` argument | slajerek's `c64cpusc.c` uses the 2-argument form via inlined mainc64cpu.c 3.1. The 3.10 version uses 3 args. Affects MEMMAP_UPDATE macro in c64cpusc.c re-inline. | +| **`vsync_do_vsync()` signature changed** | Yes — 3.10: `void f(canvas*)` vs 3.1: `int f(canvas*, int)` | Slajerek adds `isPaused` (3 args). The `been_skipped` param is gone; return type changed to void. Must be reconciled. | +| **`sound_flush()` return type changed** | Yes — 3.1: `double/int`, 3.10: `bool` | slajerek's vsync.c calls `sound_flush(isPaused)` with an int param. 3.10's sound_flush takes no param and returns bool. | +| **`mon_ui.c` removed from monitor/`** | Yes — not in 3.10 monitor/ | New: `mon_profile.c`, `monitor_binary.c` (2168 lines — the binary monitor RetroDebugger uses). | +| **`ciacore_init()` / `viacore_init()` dropped `clk_guard_t *`** | Yes — confirmed in both 3.10 source files | All callers of ciacore_init/viacore_init need their call site updated. Not directly in slajerek's 64 files (callers are c64cia1.c etc.) but affects compilation. | + +--- + +## Section 3: Key API/Header Changes Affecting Hooks + ViceInterface + +### `types.h` / `vicetypes.h` (CRITICAL) + +- **3.1:** No top-level `types.h` exists. Each arch has its own. Slajerek created `arch/vicetypes.h` which defines `BYTE`, `WORD`, `DWORD`, `SIGNED_CHAR`, `SWORD`, `SDWORD`, and `CLOCK`. It includes `"vice_sdl.h"`. This is included by `root/maincpu.h` and many other root headers. +- **3.10:** `types.h` exists at top-level `src/types.h`. It includes `` / ``. It does NOT define `BYTE`/`WORD`/`DWORD` — these have been migrated to `uint8_t`/`uint16_t`/`uint32_t` throughout. +- **Impact:** The 3.10 vanilla sources use `uint8_t` everywhere. slajerek's files still use `BYTE`. **Strategy:** Keep `vicetypes.h` as the bridge; it remains a slajerek-only header that provides BYTE/WORD/DWORD via `typedef` for all slajerek-modified files. The 3.10 files that don't include it will use stdint natively. Do NOT migrate to stdint — this would touch 4000+ lines across 64 files needlessly. Instead, ensure `vicetypes.h` compiles cleanly alongside `types.h` (guard against double-typedef). + +### `maincpu.h` and `CLK_INC()` macro + +- The `CLK_INC()` macro is defined in `c64cpusc.c` (not in maincpu.h). Both 3.1 and 3.10 define it identically in the shell file: + ```c + #define CLK_INC() \ + interrupt_delay(); \ + maincpu_clk++; \ + maincpu_ba_low_flags &= ~MAINCPU_BA_LOW_VICII; \ + maincpu_ba_low_flags |= vicii_cycle() + ``` + slajerek inserts `c64d_maincpu_clk++` inside the macro body (now routed through `VICE_HOOK_CPU_CLK_INC()`). This insertion point is **identical** in 3.1 and 3.10. No delta here. +- `maincpu.h` itself: contains `extern CLOCK c64d_maincpu_clk` in slajerek's version. 3.10's `maincpu.h` is effectively identical (externs only). Low risk. + +### `mainc64cpu.c` and `6510core.c` (CPU cores) + +| Metric | 3.1 | 3.10 | Delta | +|---|---|---|---| +| `mainc64cpu.c` lines | 795 | 988 | **+193 (+24%)** | +| `6510core.c` lines | 3062 | 3476 | **+414 (+14%)** | +| slajerek's inlined `c64cpusc.c` | 4357 | — | based on 3.1 base | + +Key structural delta between 3.1 and 3.10 mainc64cpu.c: +- 3.10 adds `#include "mainlock.h"` and calls `mainlock_yield()` inside the main CPU loop (inside `mainc64cpu_mainloop()`). This is a new mandatory yield point for the 3.10 threading model. +- 3.10 adds `#include "cmdline.h"`, `archdep.h`, `resources.h` — these affect the include chain but not logic. +- 3.10 `mainc64cpu.c` drops the `stolen_cycles` usage path changes slightly. + +Key structural delta between 3.1 and 3.10 `6510core.c`: +- Several RMW cycle constants (`CLK_ABS_RMW2`, `CLK_ABS_I_RMW2`, `CLK_ZERO_RMW`, `CLK_ZERO_I_RMW`, `CLK_IND_X_RMW`, `CLK_IND_Y_RMW1`, `CLK_IND_Y_RMW2`) are **commented out** in 3.10 (`/* #define CLK_ABS_RMW2 3 */`). The 3.10 cycle timing model changed for RMW instructions. This is significant: slajerek's inlined CPU has many hooks tied to cycle counts. +- 3.10 adds `CPU_LOG_ID LOG_DEFAULT` definition. +- Line count difference (+414) means substantial new per-opcode implementations (illegal opcode handling, new accurate timing). + +**Re-inline strategy:** Must diff slajerek's current c64cpusc.c (4357 lines, based on 3.1 mainc64cpu.c + 3.1 6510core.c) against the new 3.10 base by creating a fresh 3.10-based inline expansion, then re-applying all slajerek hooks. This is the largest single task. + +### `drivetypes.h` / drive struct rename + +- `drive_context_t` (3.1) → `diskunit_context_t` (3.10). +- drivetypes.h grew from 188 to 256 lines (+68 lines). +- All slajerek drive hook functions in `iecbus/iecbus.c`, `drivecpu.c`, `ViceInterface/` that take `drive_context_t *drv` must be renamed. Global rename across ~15 files. + +### `snapshot.h` + +- Identical structure in both versions. Error code defines unchanged. Low risk. + +### `vicii.h` / `viciitypes.h` + +- `vicii.h`: 122 lines in both 3.1 and 3.10 — identical size. +- `viciitypes.h` (viciisc): exactly 296 lines in both — identical size. The only diffs are BYTE→uint8_t, WORD→uint16_t, DWORD→uint32_t substitutions throughout. The slajerek struct field additions (`c64d_irq_flag`, `register_written`, `register_read`, etc.) replay cleanly — the struct layout is otherwise unchanged. + +### `sid.h` + +- 3.1: 138 lines. 3.10: 262 lines (+124). Large expansion. +- `sid_read()` signature: `BYTE sid_read(WORD address)` → `uint8_t sid_read(uint16_t address)`. Pure BYTE→uint8_t rename. +- `sid_sound_machine_open()` signature unchanged functionally. +- 3.10 adds many new SID functions (multi-SID, model detection, etc.). +- `sid.c` doubled from 629 to 1340 lines. slajerek's `sid_read_chip()` restructuring must be located and replayed in the 2× larger file. + +### `cia.h` and `via.h` struct layouts + +**`cia.h`** (173 → 219 lines, +46): +- 3.10 adds `unsigned int ack_irqflags`, `unsigned int new_irqflags`, `uint8_t irq_enabled`, `CLOCK ifr_clock` fields. +- slajerek's `c64d_irq_flag` field must be re-added to the 3.10 `cia_context_t` struct. +- Function pointer parameters changed: `BYTE` → `uint8_t` throughout. +- `ciacore_init()` signature: drops `clk_guard_t *` parameter. All callers affected. + +**`via.h`** (180 → 251 lines, +39%): +- Similarly expanded; BYTE→uint8_t throughout. +- slajerek's `c64d_irq_flagged` field must be re-added. +- `viacore_init()` signature drops `clk_guard_t *` parameter. + +### `ciacore.c` and `viacore.c` + +| File | 3.1 | slajerek | 3.10 | +|---|---|---|---| +| `ciacore.c` | 1734 | 1933 (+199) | 2637 (+903) | +| `viacore.c` | 1423 | ~1600 | 2233 (+810) | + +Both files grew significantly (+52% and +57% respectively). The two slajerek hook insertions in `ciacore.c` (CIA IRQ flag set/clear) and one insertion in `viacore.c` (VIA IRQ flag clear) are simple single-line field assignments. They should be re-insertable with a careful contextual diff, but the surrounding code will have moved substantially. + +--- + +## Section 4: The Monitor Subsystem + +### File list changes + +| File | 3.1 | 3.10 | Notes | +|---|---|---|---| +| `monitor.c` | 2389 lines | 3421 lines | +1032 (+43%) | +| `montypes.h` | 305 lines | 355 lines | +50 | +| `mon_lex.l` | 580 lines | 661 lines | +81 | +| `mon_ui.c` / `mon_ui.h` | present | **REMOVED** | — | +| `mon_profile.c/.h` | absent | **NEW** | profiler commands | +| `monitor_binary.c/.h` | absent | **NEW (2168 lines)** | binary monitor protocol — this IS the RetroDebugger binary monitor | + +### Hook home in 3.10 + +slajerek's 4 `c64d_set_debug_mode` injections are in `mon_instructions_step()`, `mon_instructions_next()`, `mon_instruction_return()`, and `monitor_close()`. In 3.10: +- `mon_instructions_step()` is at line 2561, `mon_instructions_next()` at 2577, `mon_instruction_return()` at 2596. These functions still exist with the same names. +- `monitor_open()` (now static) is at line 3045; `monitor_close()` is at line 3253. The static promotions slajerek applies to `make_prompt`, `monitor_open`, `monitor_process`, `monitor_close` need re-applying. +- The `execute_monitor_command_jump_trap` trampoline restructuring in `monitor_close` must be re-identified at line ~3278. + +**Critical new element:** `monitor_binary.c` (2168 lines) implements the binary monitor protocol over a socket. This IS the mechanism RetroDebugger uses (WebSocket on port 3563 per the skill). If 3.10's binary monitor protocol differs from RetroDebugger's implementation, there could be a protocol mismatch. However, RetroDebugger has its own binary monitor implementation in `ViceInterface/` — it may not need the VICE binary monitor at all. This needs clarification. + +**Replay difficulty rank: HIGH.** The monitor grew 43%, the injection points are in a different positional context, `mon_ui.c` was removed, and the new `monitor_binary.c` adds a 2168-line dependency. The `c64d_set_debug_mode` hook itself transfers cleanly (same function names, same logical positions) but surrounding code churn is substantial. Estimated effort: 2–3× harder than a typical Tier B file. + +--- + +## Section 5: Build-System Considerations + +### Vanilla 3.10 build system + +Both 3.1 and 3.10 use **autotools** (Makefile.am/Makefile.in throughout). Neither has `configure.ac` in the ref trees (they're pre-configured source snapshots). No Meson, no CMake in vanilla VICE. + +### RetroDebugger embedded build model + +RetroDebugger does NOT use VICE's build system. It compiles VICE sources via: +- **macOS:** Xcode project (`platform/MacOS/c64d.xcodeproj/project.pbxproj`) — explicit source file list +- **Linux:** CMakeLists.txt — explicit source file list + +The swap requires updating these file lists to reflect moved/renamed/added files. + +### File count changes in compiled subsystems + +| Subsystem | 3.1 .c count | 3.10 .c count | Delta | Notes | +|---|---|---|---|---| +| `c64/` (including cart) | 141 | 165 | +24 | Many new cartridge types (bisplus, blackbox, gmod3, ramlink, etc.) — RetroDebugger only compiles the ones it needs | +| `drive/` | 60 | 60 | 0 | Stable | +| `monitor/` | 31 | 32 | +1 | `monitor_binary.c` added; `mon_ui.c` removed → net +1 in .c count, but +1 large file | +| `resid/` | .cc files | .cc files | +2 | `filter8580new.cc` (778 lines) added to vanilla; slajerek deleted 8580 in filter.cc | +| `joyport/` | — | — | +many | Mouse split into 4 files | +| `arch/shared/sounddrv/` | — | new location | — | soundsdl.c moved here | + +### Hard new dependencies + +1. **`mainlock.c/.h`** — 3.10's `mainc64cpu.c` calls `mainlock_yield()` inside the CPU loop. The `mainlock` is a threading primitive for VICE's UI thread ↔ emulation thread synchronization. RetroDebugger has its own mutex (`c64d_lock_mutex`). Options: + - Provide a stub `mainlock.c` that maps `mainlock_yield()` → a no-op or a call to `c64d_debug_pause_check()`. + - Risk: if `mainlock_yield()` is not called, 3.10's UI responsiveness model breaks. For RetroDebugger (which has its own UI thread model), the calls may be safely stubbed to no-ops. **Needs decision before re-inline.** + +2. **`monitor_binary.c`** — adds a socket-based binary monitor. RetroDebugger may not need this compiled in at all. It can be excluded from the build file list. + +3. **`profiler.c`** — 3.10 mainc64cpu.c may reference profiler functions. Must check when re-inlining; if so, a stub or the full profiler must be included. + +4. **`filter8580new.cc`** — new in 3.10 resid/. slajerek targets 6581 only; this file can be excluded from the build. + +--- + +## Section 6: Risk-Ranked Swap Strategy + +### Risk table + +| Subsystem / File | Difficulty | Reason | +|---|---|---| +| `c64/c64cpusc.c` (re-inline against mainc64cpu.c 3.10 + 6510core.c 3.10) | **HARD** | 14% larger 6510core, RMW cycle const changes, new mainlock_yield calls, memmap_mem_update 3-arg, all ~283 slajerek hook points must be re-identified | +| `drive/drivecpu.c` (re-inline against 6510core.c 3.10) | **HARD** | Same 6510core issues + `drive_context_t`→`diskunit_context_t` rename throughout (97 hits) | +| `monitor/monitor.c` | **HARD** | +43% code, mon_ui.c removed, 4 injection points in larger context, static promotions | +| `joyport/joystick.c` | **HARD** | +448% (776→4255 lines), completely different structure | +| `core/ciacore.c` | **MODERATE-HIGH** | +52% code, clkguard param removed, IRQ hook re-insertion in larger context | +| `core/viacore.c` | **MODERATE-HIGH** | +57% code, same clkguard issue | +| `sid/sid.c` | **MODERATE-HIGH** | +113% code, sid_read_chip() restructuring in 2× code | +| `root/vsync.c` | **MODERATE** | Signature changed (no `been_skipped`, no return value), mainlock_yield calls, sound_flush signature changed | +| `resid/resid-sid.cpp` → `resid/sid.cc` | **MODERATE** | Rename + 3.10 base +60 lines, behavioral patches (TTL, bus_value) must be re-applied | +| `resid/resid-filter.cpp` → `resid/filter.cc` | **MODERATE** | Rename + 3.10 already trimmed some 8580 code; re-apply deletion | +| `c64/c64memsc.c` | **MODERATE** | slajerek pointer patch conflicts with 3.10's static array; +418 lines of new watchpoint infrastructure | +| `sounddrv/soundsdl.c` → `arch/shared/sounddrv/soundsdl.c` | **MODERATE** | Moved + 3.10 base already different; SDL callback rewrite must be replayed | +| `clkguard.c/.h` | **MODERATE** (infrastructure) | Must provide stubs or remove all 9 `#include "clkguard.h"` sites and remove clkguard_init calls | +| `cia.h` / `via.h` struct field additions | **LOW-MODERATE** | Field additions are simple, but BYTE→uint8_t throughout changes all sigs | +| `viciisc/vicii-cycle.c` | **LOW-MODERATE** | +19%, 5 hook points must be re-identified | +| Drive file taps (drivemem, memiec, via1d1541, via2d, rotation) | **LOW** | Small delta, hook insertions are mechanical | +| CIA/VIC hook insertions (c64cia1/2, vicii-irq, vicii.c) | **LOW** | File shrunk or stable; hook shapes simple | +| SID observers (fastsid, sid-resources, sid-snapshot) | **LOW-MODERATE** | Small-medium delta, observer-only hooks | +| REU/flash/dma/midi hooks | **LOW** | Minimal delta, simple insertions | +| Keyboard/mouse (static promotions, return type) | **LOW-MODERATE** | keyboard.c shrunk; mouse split but 2 hits are definitional | + +### Recommended incremental swap ordering + +**Goal:** Get a building + booting C64 soonest, deferring high-risk subsystems. + +**Wave 1 — Infrastructure + easy mechanics** (achieves: builds without errors) +1. Global mechanical pass: `BYTE`→`uint8_t` compile test, `vicetypes.h` guarding against double-typedef with 3.10 `types.h`. +2. `drive_context_t` → `diskunit_context_t` rename (global, affects drivecpu.c, iecbus.c, ViceInterface). +3. Remove all `#include "clkguard.h"` from the 9 affected files; provide minimal stub or remove clkguard callbacks from ciacore/viacore init (since 3.10 already dropped the param). +4. `resid` file renames: rename `resid-*.cpp` → `*.cc` in build lists, re-apply slajerek patches to 3.10 bases. +5. Move soundsdl.c to new path in build lists. +6. Provide `mainlock.h` stub (all `mainlock_yield()` → no-op) so mainc64cpu.c 3.10 compiles. + +**Wave 2 — CPU cores** (achieves: C64 executes instructions) +7. Re-inline `mainc64cpu.c` 3.10 into new `c64cpusc.c`, re-apply all slajerek hooks. Use diff between slajerek's current c64cpusc.c and 3.1 mainc64cpu.c to identify hook positions, then apply to 3.10. +8. Re-inline `6510core.c` 3.10 into `drivecpu.c`, re-apply drive hooks + diskunit_context_t rename. + +**Wave 3 — Chip peripherals** (achieves: C64 boots to BASIC) +9. `ciacore.c` + `viacore.c`: remove clkguard, re-insert IRQ flag hooks in larger 3.10 context. +10. `cia.h` + `via.h`: re-add c64d struct fields to 3.10 versions. +11. `viciitypes.h`: re-add c64d struct fields (trivial — identical size). +12. `viciisc` files (vicii.c, vicii-cycle.c, vicii-irq.c, vicii-draw-cycle.c): re-apply hooks. +13. `c64memsc.c`: reconcile mem_ram pointer vs static array conflict; re-apply read/write taps. + +**Wave 4 — SID + drive subsystems** (achieves: audio and drive work) +14. `sid.c`, `sid-snapshot.c`, `sid-resources.c`, `fastsid.c`. +15. Drive taps: `drivemem.c`, `memiec.c`, `via1d1541.c`, `via2d.c`, `rotation.c`, `drive.c`. + +**Wave 5 — Monitor + input** (achieves: full debugger functionality) +16. `monitor.c`: re-apply debug mode hooks and static promotions to 3.10's 3421-line version. +17. `vsync.c` + `sound.c`: reconcile signature changes. +18. `joystick.c`: locate `joystick_process_latch()` in 3.10's massive rewrite, re-apply delay bypass. +19. `keyboard.c`, `mouse.c`: re-apply return type change and static promotions. +20. `c64-snapshot.c`: re-apply signature extensions. + +**Wave 6 — Verification** +21. REU, flash, DMA, MIDI, iecbus hooks (low risk; apply mechanically). +22. Full build + WebSocket test suite (28 passed, 1 skipped, 1 xfailed target). + +### Top 5 highest-risk items + +1. **`c64cpusc.c` re-inline** — 4357 lines built from scratch against a 3.10 mainc64cpu.c that added 193 lines + mainlock_yield + profiler refs + memmap_mem_update 3-arg change. 283 hook positions to re-verify. If a hook is placed one cycle off, timing-sensitive tests will fail silently. + +2. **`drivecpu.c` re-inline + drive_context_t rename** — 4130 lines rebuilt + pervasive rename of the context type across the entire drive subsystem. The 6510core RMW cycle const changes also affect drive timing. + +3. **`clkguard.c/.h` deletion** — The overflow-prevention callbacks that `ciacore_init` and `viacore_init` used to register via `clk_guard_add_callback` no longer exist in 3.10. How 3.10 handles CLOCK overflow instead must be understood before removing the clkguard dependency — otherwise the emulator will silently misbehave after ~2^32 cycles. + +4. **`monitor.c` hook injection** — The `execute_monitor_command_jump_trap` trampoline is a non-additive control-flow change (not just an observer hook) inside `monitor_close()`. With 3.10's `monitor_close` at line 3253 in a completely rewritten file, finding the correct injection point requires careful manual diff. Getting this wrong silently breaks step/next/return in the debugger. + +5. **`mainlock` threading model conflict** — 3.10's CPU loop calls `mainlock_yield()` to let the UI thread in. RetroDebugger has its own mutex-based debug pause (`c64d_debug_pause_check()`). If mainlock_yield() is simply stubbed to a no-op, 3.10's behavior changes (UI may not update during emulation). If it's mapped to the debug pause check, there may be deadlocks. The threading architecture interaction is subtle and not fully characterized. + +**Honorable mention:** `joystick.c` (+448% growth, 776→4255 lines) and `sid.c` (+113%, 629→1340 lines). Both contain slajerek changes that need to be replayed in fundamentally rewritten code. However, joystick failures are less likely to prevent boot (graceful degradation), and the SID changes are additive/observable-only. + +--- + +## Appendix: Quick Reference — Files NOT in 3.10 + +| File | Was in 3.1 | Notes | +|---|---|---| +| `clkguard.c` / `clkguard.h` | Yes | Removed; functionality internalized in alarm subsystem | +| `c64/patchrom.c` | Yes | Removed; fast-boot patch mechanism not in vanilla 3.10 | +| `sounddrv/soundsdl.c` | Yes (at root sounddrv/) | Moved to `arch/shared/sounddrv/` | +| `monitor/mon_ui.c` | Yes | Removed | +| `translate.c` + related | Yes | Translation subsystem removed entirely | +| `resid-fp/` (all) | No (slajerek-added) | Slajerek's own; carry forward unchanged | +| All `arch/` slajerek files | No (slajerek-added) | Slajerek's own SDL arch; carry forward | diff --git a/docs/superpowers/notes/phase3-data/chunk1-filemap.tsv b/docs/superpowers/notes/phase3-data/chunk1-filemap.tsv new file mode 100644 index 00000000..0147b265 --- /dev/null +++ b/docs/superpowers/notes/phase3-data/chunk1-filemap.tsv @@ -0,0 +1,1155 @@ +src/Emulators/vice/video/render1x1ntsc.c video/render1x1ntsc.c SAME +src/Emulators/vice/video/video-sound.h video/video-sound.h SAME +src/Emulators/vice/video/render2x2pal.h video/render2x2pal.h SAME +src/Emulators/vice/video/render1x2.h video/render1x2.h SAME +src/Emulators/vice/video/render2x4.c video/render2x4.c SAME +src/Emulators/vice/video/render2x2.h video/render2x2.h SAME +src/Emulators/vice/video/render2x2ntsc.c video/render2x2ntsc.c SAME +src/Emulators/vice/video/video-render-1x2.c video/video-render-1x2.c GONE +src/Emulators/vice/video/render1x1crt.h video/render1x1crt.h GONE +src/Emulators/vice/video/video-render-pal.c video/video-render-pal.c GONE +src/Emulators/vice/video/video-render-2x2.c video/video-render-2x2.c GONE +src/Emulators/vice/video/render2x4crt.h video/render2x4crt.h GONE +src/Emulators/vice/video/render1x1.h video/render1x1.h SAME +src/Emulators/vice/video/video-render.c video/video-render.c SAME +src/Emulators/vice/video/video-resources.h video/video-resources.h SAME +src/Emulators/vice/video/render1x2crt.c video/render1x2crt.c GONE +src/Emulators/vice/video/render1x1pal.h video/render1x1pal.h SAME +src/Emulators/vice/video/video-render-crt.c video/video-render-crt.c GONE +src/Emulators/vice/video/renderscale2x.c video/renderscale2x.c SAME +src/Emulators/vice/video/renderyuv.c video/renderyuv.c GONE +src/Emulators/vice/video/video-color.h video/video-color.h SAME +src/Emulators/vice/video/video-canvas.c video/video-canvas.c SAME +src/Emulators/vice/video/render2x2crt.h video/render2x2crt.h GONE +src/Emulators/vice/video/render2x2.c video/render2x2.c SAME +src/Emulators/vice/video/render2x2ntsc.h video/render2x2ntsc.h SAME +src/Emulators/vice/video/render2x4.h video/render2x4.h SAME +src/Emulators/vice/video/render1x2.c video/render1x2.c SAME +src/Emulators/vice/video/video-sound.c video/video-sound.c SAME +src/Emulators/vice/video/render1x1ntsc.h video/render1x1ntsc.h SAME +src/Emulators/vice/video/video-viewport.c video/video-viewport.c SAME +src/Emulators/vice/video/render2x2pal.c video/render2x2pal.c SAME +src/Emulators/vice/video/render2x4crt.c video/render2x4crt.c GONE +src/Emulators/vice/video/render1x1crt.c video/render1x1crt.c GONE +src/Emulators/vice/video/render1x1pal.c video/render1x1pal.c SAME +src/Emulators/vice/video/render1x2crt.h video/render1x2crt.h GONE +src/Emulators/vice/video/renderscale2x.h video/renderscale2x.h SAME +src/Emulators/vice/video/render1x1.c video/render1x1.c SAME +src/Emulators/vice/video/video-resources.c video/video-resources.c SAME +src/Emulators/vice/video/video-render.h video/video-render.h SAME +src/Emulators/vice/video/video-cmdline-options.c video/video-cmdline-options.c SAME +src/Emulators/vice/video/render2x2crt.c video/render2x2crt.c GONE +src/Emulators/vice/video/video-color.c video/video-color.c SAME +src/Emulators/vice/video/video-canvas.h video/video-canvas.h SAME +src/Emulators/vice/video/renderyuv.h video/renderyuv.h GONE +src/Emulators/vice/parallel/parallel-trap.c parallel/parallel-trap.c SAME +src/Emulators/vice/parallel/parallel.c parallel/parallel.c SAME +src/Emulators/vice/parallel/parallel-trap.h parallel/parallel-trap.h SAME +src/Emulators/vice/imagecontents/diskcontents-iec.c imagecontents/diskcontents-iec.c SAME +src/Emulators/vice/imagecontents/diskcontents-block.c imagecontents/diskcontents-block.c SAME +src/Emulators/vice/imagecontents/tapecontents.h imagecontents/tapecontents.h SAME +src/Emulators/vice/imagecontents/diskcontents.h imagecontents/diskcontents.h SAME +src/Emulators/vice/imagecontents/imagecontents.c imagecontents/imagecontents.c SAME +src/Emulators/vice/imagecontents/diskcontents-iec.h imagecontents/diskcontents-iec.h SAME +src/Emulators/vice/imagecontents/diskcontents-block.h imagecontents/diskcontents-block.h SAME +src/Emulators/vice/imagecontents/diskcontents.c imagecontents/diskcontents.c SAME +src/Emulators/vice/imagecontents/tapecontents.c imagecontents/tapecontents.c SAME +src/Emulators/vice/diag/c64_diag_586220_harness.h diag/c64_diag_586220_harness.h SAME +src/Emulators/vice/diag/c64_diag_586220_harness.c diag/c64_diag_586220_harness.c SAME +src/Emulators/vice/monitor/mon_assemble6502.c monitor/mon_assemble6502.c SAME +src/Emulators/vice/monitor/mon_parse.h monitor/mon_parse.h SAME +src/Emulators/vice/monitor/mon_register6502.c monitor/mon_register6502.c SAME +src/Emulators/vice/monitor/mon_util.c monitor/mon_util.c SAME +src/Emulators/vice/monitor/monitor.c monitor/monitor.c SAME +src/Emulators/vice/monitor/mon_ui.c monitor/mon_ui.c GONE +src/Emulators/vice/monitor/mon_assemble.h monitor/mon_assemble.h SAME +src/Emulators/vice/monitor/mon_register6809.c monitor/mon_register6809.c SAME +src/Emulators/vice/monitor/mon_drive.h monitor/mon_drive.h SAME +src/Emulators/vice/monitor/mon_assembleR65C02.c monitor/mon_assembleR65C02.c SAME +src/Emulators/vice/monitor/mon_assemble6809.c monitor/mon_assemble6809.c SAME +src/Emulators/vice/monitor/mon_command.c monitor/mon_command.c SAME +src/Emulators/vice/monitor/mon_register6502dtv.c monitor/mon_register6502dtv.c SAME +src/Emulators/vice/monitor/mon_disassemble.c monitor/mon_disassemble.c SAME +src/Emulators/vice/monitor/mon_memmap.h monitor/mon_memmap.h SAME +src/Emulators/vice/monitor/asm6502.c monitor/asm6502.c SAME +src/Emulators/vice/monitor/mon_assemblez80.c monitor/mon_assemblez80.c SAME +src/Emulators/vice/monitor/mon_breakpoint.h monitor/mon_breakpoint.h SAME +src/Emulators/vice/monitor/mon_memory.h monitor/mon_memory.h SAME +src/Emulators/vice/monitor/asmz80.c monitor/asmz80.c SAME +src/Emulators/vice/monitor/mon_register.c monitor/mon_register.c SAME +src/Emulators/vice/monitor/mon_file.h monitor/mon_file.h SAME +src/Emulators/vice/monitor/mon_registerz80.c monitor/mon_registerz80.c SAME +src/Emulators/vice/monitor/monitor_network.h monitor/monitor_network.h SAME +src/Emulators/vice/monitor/asm6809.c monitor/asm6809.c SAME +src/Emulators/vice/monitor/asm.h monitor/asm.h SAME +src/Emulators/vice/monitor/mon_register65816.c monitor/mon_register65816.c SAME +src/Emulators/vice/monitor/mon_util.h monitor/mon_util.h SAME +src/Emulators/vice/monitor/mon_parse.c monitor/mon_parse.c SAME +src/Emulators/vice/monitor/asm6502dtv.c monitor/asm6502dtv.c SAME +src/Emulators/vice/monitor/mon_registerR65C02.c monitor/mon_registerR65C02.c SAME +src/Emulators/vice/monitor/mon_command.h monitor/mon_command.h SAME +src/Emulators/vice/monitor/mon_lex.c monitor/mon_lex.c SAME +src/Emulators/vice/monitor/mon_drive.c monitor/mon_drive.c SAME +src/Emulators/vice/monitor/mon_ui.h monitor/mon_ui.h GONE +src/Emulators/vice/monitor/asmR65C02.c monitor/asmR65C02.c SAME +src/Emulators/vice/monitor/montypes.h monitor/montypes.h SAME +src/Emulators/vice/monitor/mon_breakpoint.c monitor/mon_breakpoint.c SAME +src/Emulators/vice/monitor/mon_memmap.c monitor/mon_memmap.c SAME +src/Emulators/vice/monitor/mon_disassemble.h monitor/mon_disassemble.h SAME +src/Emulators/vice/monitor/mon_file.c monitor/mon_file.c SAME +src/Emulators/vice/monitor/mon_register.h monitor/mon_register.h SAME +src/Emulators/vice/monitor/monitor_network.c monitor/monitor_network.c SAME +src/Emulators/vice/monitor/mon_memory.c monitor/mon_memory.c SAME +src/Emulators/vice/c64/c64-memory-hacks.h c64/c64-memory-hacks.h SAME +src/Emulators/vice/c64/c64embedded.c c64/c64embedded.c GONE +src/Emulators/vice/c64/c64pla.c c64/c64pla.c SAME +src/Emulators/vice/c64/plus60k.c c64/plus60k.c SAME +src/Emulators/vice/c64/c64keyboard.c c64/c64keyboard.c SAME +src/Emulators/vice/c64/c64-resources.h c64/c64-resources.h SAME +src/Emulators/vice/c64/c64-cmdline-options.c c64/c64-cmdline-options.c SAME +src/Emulators/vice/c64/c64bus.c c64/c64bus.c SAME +src/Emulators/vice/c64/psid.c c64/psid.c SAME +src/Emulators/vice/c64/c64memrom.c c64/c64memrom.c SAME +src/Emulators/vice/c64/c64cia1.c c64/c64cia1.c SAME +src/Emulators/vice/c64/c64memsnapshot.h c64/c64memsnapshot.h SAME +src/Emulators/vice/c64/musdrv.h c64/musdrv.h SAME +src/Emulators/vice/c64/c64rsuser.c c64/c64rsuser.c SAME +src/Emulators/vice/c64/c64.h c64/c64.h SAME +src/Emulators/vice/c64/c64cart.h c64/c64cart.h SAME +src/Emulators/vice/c64/c64_256k.h c64/c64_256k.h SAME +src/Emulators/vice/c64/c64iec.h c64/c64iec.h SAME +src/Emulators/vice/c64/c64-snapshot.h c64/c64-snapshot.h SAME +src/Emulators/vice/c64/c64parallel.c c64/c64parallel.c SAME +src/Emulators/vice/c64/c64gluelogic.h c64/c64gluelogic.h SAME +src/Emulators/vice/c64/c64meminit.h c64/c64meminit.h SAME +src/Emulators/vice/c64/plus256k.h c64/plus256k.h SAME +src/Emulators/vice/c64/c64rom.c c64/c64rom.c SAME +src/Emulators/vice/c64/c64fastiec.c c64/c64fastiec.c SAME +src/Emulators/vice/c64/c64video.c c64/c64video.c SAME +src/Emulators/vice/c64/c64memsc.c c64/c64memsc.c SAME +src/Emulators/vice/c64/c64cia2.c c64/c64cia2.c SAME +src/Emulators/vice/c64/c64mem.h c64/c64mem.h SAME +src/Emulators/vice/c64/c64memlimit.c c64/c64memlimit.c SAME +src/Emulators/vice/c64/patchrom.h c64/patchrom.h GONE +src/Emulators/vice/c64/c64cpusc.c c64/c64cpusc.c SAME +src/Emulators/vice/c64/c64romset.c c64/c64romset.c SAME +src/Emulators/vice/c64/plus60k.h c64/plus60k.h SAME +src/Emulators/vice/c64/c64cia.h c64/c64cia.h SAME +src/Emulators/vice/c64/c64-resources.c c64/c64-resources.c SAME +src/Emulators/vice/c64/c64keyboard.h c64/c64keyboard.h SAME +src/Emulators/vice/c64/psiddrv.h c64/psiddrv.h SAME +src/Emulators/vice/c64/c64pla.h c64/c64pla.h SAME +src/Emulators/vice/c64/c64-memory-hacks.c c64/c64-memory-hacks.c SAME +src/Emulators/vice/c64/c64memrom.h c64/c64memrom.h SAME +src/Emulators/vice/c64/c64drive.c c64/c64drive.c SAME +src/Emulators/vice/c64/psid.h c64/psid.h SAME +src/Emulators/vice/c64/cart/gamekiller.h c64/cart/gamekiller.h SAME +src/Emulators/vice/c64/cart/dinamic.h c64/cart/dinamic.h SAME +src/Emulators/vice/c64/cart/freezemachine.c c64/cart/freezemachine.c SAME +src/Emulators/vice/c64/cart/magicformel.c c64/cart/magicformel.c SAME +src/Emulators/vice/c64/cart/capture.h c64/cart/capture.h SAME +src/Emulators/vice/c64/cart/supersnapshot.c c64/cart/supersnapshot.c SAME +src/Emulators/vice/c64/cart/epyxfastload.h c64/cart/epyxfastload.h SAME +src/Emulators/vice/c64/cart/c64-midi.h c64/cart/c64-midi.h SAME +src/Emulators/vice/c64/cart/daa.c c64/cart/daa.c SAME +src/Emulators/vice/c64/cart/delaep64.c c64/cart/delaep64.c SAME +src/Emulators/vice/c64/cart/ds12c887rtc.c c64/cart/ds12c887rtc.c SAME +src/Emulators/vice/c64/cart/ross.c c64/cart/ross.c SAME +src/Emulators/vice/c64/cart/c64acia.h c64/cart/c64acia.h SAME +src/Emulators/vice/c64/cart/formel64.h c64/cart/formel64.h SAME +src/Emulators/vice/c64/cart/westermann.h c64/cart/westermann.h SAME +src/Emulators/vice/c64/cart/kcs.c c64/cart/kcs.c SAME +src/Emulators/vice/c64/cart/superexplode5.c c64/cart/superexplode5.c SAME +src/Emulators/vice/c64/cart/diashowmaker.c c64/cart/diashowmaker.c SAME +src/Emulators/vice/c64/cart/mach5.c c64/cart/mach5.c SAME +src/Emulators/vice/c64/cart/shortbus_digimax.c c64/cart/shortbus_digimax.c SAME +src/Emulators/vice/c64/cart/atomicpower.h c64/cart/atomicpower.h SAME +src/Emulators/vice/c64/cart/c64acia1.c c64/cart/c64acia1.c SAME +src/Emulators/vice/c64/cart/supersnapshot4.c c64/cart/supersnapshot4.c SAME +src/Emulators/vice/c64/cart/rexutility.h c64/cart/rexutility.h SAME +src/Emulators/vice/c64/cart/cs8900io.h c64/cart/cs8900io.h SAME +src/Emulators/vice/c64/cart/crt.c c64/cart/crt.c MOVED:tools/cartconv/crt.c +src/Emulators/vice/c64/cart/ocean.h c64/cart/ocean.h SAME +src/Emulators/vice/c64/cart/pagefox.h c64/cart/pagefox.h SAME +src/Emulators/vice/c64/cart/delaep7x8.c c64/cart/delaep7x8.c SAME +src/Emulators/vice/c64/cart/rgcd.h c64/cart/rgcd.h SAME +src/Emulators/vice/c64/cart/supergames.h c64/cart/supergames.h SAME +src/Emulators/vice/c64/cart/finalplus.c c64/cart/finalplus.c SAME +src/Emulators/vice/c64/cart/reu.h c64/cart/reu.h SAME +src/Emulators/vice/c64/cart/final.c c64/cart/final.c SAME +src/Emulators/vice/c64/cart/magicvoice.h c64/cart/magicvoice.h SAME +src/Emulators/vice/c64/cart/mikroass.h c64/cart/mikroass.h SAME +src/Emulators/vice/c64/cart/clockport-rrnet.c c64/cart/clockport-rrnet.c SAME +src/Emulators/vice/c64/cart/funplay.c c64/cart/funplay.c SAME +src/Emulators/vice/c64/cart/comal80.h c64/cart/comal80.h SAME +src/Emulators/vice/c64/cart/debugcart.h c64/cart/debugcart.h SAME +src/Emulators/vice/c64/cart/actionreplay3.h c64/cart/actionreplay3.h SAME +src/Emulators/vice/c64/cart/rrnetmk3.h c64/cart/rrnetmk3.h SAME +src/Emulators/vice/c64/cart/c64tpi.h c64/cart/c64tpi.h SAME +src/Emulators/vice/c64/cart/simonsbasic.h c64/cart/simonsbasic.h SAME +src/Emulators/vice/c64/cart/georam.h c64/cart/georam.h SAME +src/Emulators/vice/c64/cart/shortbus_etfe.c c64/cart/shortbus_etfe.c SAME +src/Emulators/vice/c64/cart/warpspeed.c c64/cart/warpspeed.c SAME +src/Emulators/vice/c64/cart/delaep256.h c64/cart/delaep256.h SAME +src/Emulators/vice/c64/cart/rexep256.h c64/cart/rexep256.h SAME +src/Emulators/vice/c64/cart/mmcreplay.h c64/cart/mmcreplay.h SAME +src/Emulators/vice/c64/cart/snapshot64.c c64/cart/snapshot64.c SAME +src/Emulators/vice/c64/cart/easyflash.c c64/cart/easyflash.c SAME +src/Emulators/vice/c64/cart/stardos.c c64/cart/stardos.c SAME +src/Emulators/vice/c64/cart/prophet64.c c64/cart/prophet64.c SAME +src/Emulators/vice/c64/cart/sfx_soundexpander.h c64/cart/sfx_soundexpander.h SAME +src/Emulators/vice/c64/cart/actionreplay.h c64/cart/actionreplay.h SAME +src/Emulators/vice/c64/cart/ramcart.h c64/cart/ramcart.h SAME +src/Emulators/vice/c64/cart/ethernetcart.h c64/cart/ethernetcart.h SAME +src/Emulators/vice/c64/cart/retroreplay.h c64/cart/retroreplay.h SAME +src/Emulators/vice/c64/cart/shortbus.h c64/cart/shortbus.h SAME +src/Emulators/vice/c64/cart/final3.c c64/cart/final3.c SAME +src/Emulators/vice/c64/cart/ide64.h c64/cart/ide64.h SAME +src/Emulators/vice/c64/cart/exos.h c64/cart/exos.h SAME +src/Emulators/vice/c64/cart/clockport.h c64/cart/clockport.h SAME +src/Emulators/vice/c64/cart/freezeframe.h c64/cart/freezeframe.h SAME +src/Emulators/vice/c64/cart/silverrock128.c c64/cart/silverrock128.c SAME +src/Emulators/vice/c64/cart/gs.c c64/cart/gs.c SAME +src/Emulators/vice/c64/cart/cpmcart.h c64/cart/cpmcart.h SAME +src/Emulators/vice/c64/cart/kingsoft.c c64/cart/kingsoft.c SAME +src/Emulators/vice/c64/cart/stb.h c64/cart/stb.h SAME +src/Emulators/vice/c64/cart/mmc64.c c64/cart/mmc64.c SAME +src/Emulators/vice/c64/cart/actionreplay2.c c64/cart/actionreplay2.c SAME +src/Emulators/vice/c64/cart/expert.c c64/cart/expert.c SAME +src/Emulators/vice/c64/cart/zaxxon.c c64/cart/zaxxon.c SAME +src/Emulators/vice/c64/cart/actionreplay4.h c64/cart/actionreplay4.h SAME +src/Emulators/vice/c64/cart/gmod2.h c64/cart/gmod2.h SAME +src/Emulators/vice/c64/cart/c64-generic.c c64/cart/c64-generic.c SAME +src/Emulators/vice/c64/cart/sfx_soundsampler.c c64/cart/sfx_soundsampler.c SAME +src/Emulators/vice/c64/cart/isepic.h c64/cart/isepic.h SAME +src/Emulators/vice/c64/cart/digimax.c c64/cart/digimax.c SAME +src/Emulators/vice/c64/cart/clockport-mp3at64.c c64/cart/clockport-mp3at64.c SAME +src/Emulators/vice/c64/cart/magicdesk.c c64/cart/magicdesk.c SAME +src/Emulators/vice/c64/cart/easycalc.h c64/cart/easycalc.h SAME +src/Emulators/vice/c64/cart/c64cartmem.h c64/cart/c64cartmem.h SAME +src/Emulators/vice/c64/cart/dqbb.h c64/cart/dqbb.h SAME +src/Emulators/vice/c64/cart/superexplode5.h c64/cart/superexplode5.h SAME +src/Emulators/vice/c64/cart/shortbus_digimax.h c64/cart/shortbus_digimax.h SAME +src/Emulators/vice/c64/cart/atomicpower.c c64/cart/atomicpower.c SAME +src/Emulators/vice/c64/cart/mach5.h c64/cart/mach5.h SAME +src/Emulators/vice/c64/cart/diashowmaker.h c64/cart/diashowmaker.h SAME +src/Emulators/vice/c64/cart/formel64.c c64/cart/formel64.c SAME +src/Emulators/vice/c64/cart/ross.h c64/cart/ross.h SAME +src/Emulators/vice/c64/cart/kcs.h c64/cart/kcs.h SAME +src/Emulators/vice/c64/cart/westermann.c c64/cart/westermann.c SAME +src/Emulators/vice/c64/cart/c64-midi.c c64/cart/c64-midi.c SAME +src/Emulators/vice/c64/cart/supersnapshot.h c64/cart/supersnapshot.h SAME +src/Emulators/vice/c64/cart/epyxfastload.c c64/cart/epyxfastload.c SAME +src/Emulators/vice/c64/cart/capture.c c64/cart/capture.c SAME +src/Emulators/vice/c64/cart/magicformel.h c64/cart/magicformel.h SAME +src/Emulators/vice/c64/cart/ds12c887rtc.h c64/cart/ds12c887rtc.h SAME +src/Emulators/vice/c64/cart/delaep64.h c64/cart/delaep64.h SAME +src/Emulators/vice/c64/cart/daa.h c64/cart/daa.h SAME +src/Emulators/vice/c64/cart/freezemachine.h c64/cart/freezemachine.h SAME +src/Emulators/vice/c64/cart/dinamic.c c64/cart/dinamic.c SAME +src/Emulators/vice/c64/cart/gamekiller.c c64/cart/gamekiller.c SAME +src/Emulators/vice/c64/cart/actionreplay3.c c64/cart/actionreplay3.c SAME +src/Emulators/vice/c64/cart/debugcart.c c64/cart/debugcart.c SAME +src/Emulators/vice/c64/cart/comal80.c c64/cart/comal80.c SAME +src/Emulators/vice/c64/cart/shortbus_etfe.h c64/cart/shortbus_etfe.h SAME +src/Emulators/vice/c64/cart/georam.c c64/cart/georam.c SAME +src/Emulators/vice/c64/cart/simonsbasic.c c64/cart/simonsbasic.c SAME +src/Emulators/vice/c64/cart/rrnetmk3.c c64/cart/rrnetmk3.c SAME +src/Emulators/vice/c64/cart/c64tpi.c c64/cart/c64tpi.c SAME +src/Emulators/vice/c64/cart/final.h c64/cart/final.h SAME +src/Emulators/vice/c64/cart/magicvoice.c c64/cart/magicvoice.c SAME +src/Emulators/vice/c64/cart/mikroass.c c64/cart/mikroass.c SAME +src/Emulators/vice/c64/cart/reu.c c64/cart/reu.c SAME +src/Emulators/vice/c64/cart/finalplus.h c64/cart/finalplus.h SAME +src/Emulators/vice/c64/cart/supergames.c c64/cart/supergames.c SAME +src/Emulators/vice/c64/cart/funplay.h c64/cart/funplay.h SAME +src/Emulators/vice/c64/cart/clockport-rrnet.h c64/cart/clockport-rrnet.h SAME +src/Emulators/vice/c64/cart/pagefox.c c64/cart/pagefox.c SAME +src/Emulators/vice/c64/cart/ocean.c c64/cart/ocean.c SAME +src/Emulators/vice/c64/cart/rgcd.c c64/cart/rgcd.c SAME +src/Emulators/vice/c64/cart/delaep7x8.h c64/cart/delaep7x8.h SAME +src/Emulators/vice/c64/cart/supersnapshot4.h c64/cart/supersnapshot4.h SAME +src/Emulators/vice/c64/cart/crt.h c64/cart/crt.h MOVED:tools/cartconv/crt.h +src/Emulators/vice/c64/cart/cs8900io.c c64/cart/cs8900io.c SAME +src/Emulators/vice/c64/cart/rexutility.c c64/cart/rexutility.c SAME +src/Emulators/vice/c64/cart/gs.h c64/cart/gs.h SAME +src/Emulators/vice/c64/cart/silverrock128.h c64/cart/silverrock128.h SAME +src/Emulators/vice/c64/cart/freezeframe.c c64/cart/freezeframe.c SAME +src/Emulators/vice/c64/cart/clockport.c c64/cart/clockport.c SAME +src/Emulators/vice/c64/cart/retroreplay.c c64/cart/retroreplay.c SAME +src/Emulators/vice/c64/cart/c64cart.c c64/cart/c64cart.c SAME +src/Emulators/vice/c64/cart/ethernetcart.c c64/cart/ethernetcart.c SAME +src/Emulators/vice/c64/cart/ramcart.c c64/cart/ramcart.c SAME +src/Emulators/vice/c64/cart/actionreplay.c c64/cart/actionreplay.c SAME +src/Emulators/vice/c64/cart/sfx_soundexpander.c c64/cart/sfx_soundexpander.c SAME +src/Emulators/vice/c64/cart/final3.h c64/cart/final3.h SAME +src/Emulators/vice/c64/cart/ide64.c c64/cart/ide64.c SAME +src/Emulators/vice/c64/cart/exos.c c64/cart/exos.c SAME +src/Emulators/vice/c64/cart/shortbus.c c64/cart/shortbus.c SAME +src/Emulators/vice/c64/cart/easyflash.h c64/cart/easyflash.h SAME +src/Emulators/vice/c64/cart/snapshot64.h c64/cart/snapshot64.h SAME +src/Emulators/vice/c64/cart/rexep256.c c64/cart/rexep256.c SAME +src/Emulators/vice/c64/cart/mmcreplay.c c64/cart/mmcreplay.c SAME +src/Emulators/vice/c64/cart/delaep256.c c64/cart/delaep256.c SAME +src/Emulators/vice/c64/cart/prophet64.h c64/cart/prophet64.h SAME +src/Emulators/vice/c64/cart/stardos.h c64/cart/stardos.h SAME +src/Emulators/vice/c64/cart/warpspeed.h c64/cart/warpspeed.h SAME +src/Emulators/vice/c64/cart/c64cartsystem.h c64/cart/c64cartsystem.h SAME +src/Emulators/vice/c64/cart/easycalc.c c64/cart/easycalc.c SAME +src/Emulators/vice/c64/cart/magicdesk.h c64/cart/magicdesk.h SAME +src/Emulators/vice/c64/cart/dqbb.c c64/cart/dqbb.c SAME +src/Emulators/vice/c64/cart/c64cartmem.c c64/cart/c64cartmem.c SAME +src/Emulators/vice/c64/cart/sfx_soundsampler.h c64/cart/sfx_soundsampler.h SAME +src/Emulators/vice/c64/cart/clockport-mp3at64.h c64/cart/clockport-mp3at64.h SAME +src/Emulators/vice/c64/cart/digimax.h c64/cart/digimax.h SAME +src/Emulators/vice/c64/cart/isepic.c c64/cart/isepic.c SAME +src/Emulators/vice/c64/cart/zaxxon.h c64/cart/zaxxon.h SAME +src/Emulators/vice/c64/cart/expert.h c64/cart/expert.h SAME +src/Emulators/vice/c64/cart/gmod2.c c64/cart/gmod2.c SAME +src/Emulators/vice/c64/cart/c64-generic.h c64/cart/c64-generic.h SAME +src/Emulators/vice/c64/cart/actionreplay4.c c64/cart/actionreplay4.c SAME +src/Emulators/vice/c64/cart/c64carthooks.c c64/cart/c64carthooks.c SAME +src/Emulators/vice/c64/cart/kingsoft.h c64/cart/kingsoft.h SAME +src/Emulators/vice/c64/cart/cpmcart.c c64/cart/cpmcart.c SAME +src/Emulators/vice/c64/cart/actionreplay2.h c64/cart/actionreplay2.h SAME +src/Emulators/vice/c64/cart/mmc64.h c64/cart/mmc64.h SAME +src/Emulators/vice/c64/cart/stb.c c64/cart/stb.c SAME +src/Emulators/vice/c64/c64-cmdline-options.h c64/c64-cmdline-options.h SAME +src/Emulators/vice/c64/c64gluelogic.c c64/c64gluelogic.c SAME +src/Emulators/vice/c64/c64scmodel.c c64/c64scmodel.c SAME +src/Emulators/vice/c64/c64sound.c c64/c64sound.c SAME +src/Emulators/vice/c64/c64meminit.c c64/c64meminit.c SAME +src/Emulators/vice/c64/c64iec.c c64/c64iec.c SAME +src/Emulators/vice/c64/c64_256k.c c64/c64_256k.c SAME +src/Emulators/vice/c64/c64.c c64/c64.c SAME +src/Emulators/vice/c64/c64parallel.h c64/c64parallel.h SAME +src/Emulators/vice/c64/c64-snapshot.c c64/c64-snapshot.c SAME +src/Emulators/vice/c64/reloc65.c c64/reloc65.c SAME +src/Emulators/vice/c64/c64memsnapshot.c c64/c64memsnapshot.c SAME +src/Emulators/vice/c64/c64datasette.c c64/c64datasette.c SAME +src/Emulators/vice/c64/c64rsuser.h c64/c64rsuser.h SAME +src/Emulators/vice/c64/patchrom.c c64/patchrom.c GONE +src/Emulators/vice/c64/c64export.c c64/c64export.c SAME +src/Emulators/vice/c64/c64memlimit.h c64/c64memlimit.h SAME +src/Emulators/vice/c64/c64io.c c64/c64io.c SAME +src/Emulators/vice/c64/c64model.h c64/c64model.h SAME +src/Emulators/vice/c64/c64fastiec.h c64/c64fastiec.h SAME +src/Emulators/vice/c64/plus256k.c c64/plus256k.c SAME +src/Emulators/vice/c64/c64rom.h c64/c64rom.h SAME +src/Emulators/vice/c64/c64printer.c c64/c64printer.c SAME +src/Emulators/vice/core/cs8900.c core/cs8900.c SAME +src/Emulators/vice/core/fmopl.c core/fmopl.c SAME +src/Emulators/vice/core/viacore.c core/viacore.c SAME +src/Emulators/vice/core/ciacore.c core/ciacore.c SAME +src/Emulators/vice/core/ata.h core/ata.h SAME +src/Emulators/vice/core/riotcore.c core/riotcore.c SAME +src/Emulators/vice/core/ciatimer.c core/ciatimer.c SAME +src/Emulators/vice/core/tpicore.c core/tpicore.c SAME +src/Emulators/vice/core/spi-sdcard.h core/spi-sdcard.h SAME +src/Emulators/vice/core/t6721.h core/t6721.h SAME +src/Emulators/vice/core/mc6821core.h core/mc6821core.h SAME +src/Emulators/vice/core/ser-eeprom.c core/ser-eeprom.c SAME +src/Emulators/vice/core/m93c86.c core/m93c86.c SAME +src/Emulators/vice/core/ata.c core/ata.c SAME +src/Emulators/vice/core/fmopl.h core/fmopl.h SAME +src/Emulators/vice/core/cs8900.h core/cs8900.h SAME +src/Emulators/vice/core/ser-eeprom.h core/ser-eeprom.h SAME +src/Emulators/vice/core/mc6821core.c core/mc6821core.c SAME +src/Emulators/vice/core/t6721.c core/t6721.c SAME +src/Emulators/vice/core/ciatimer.h core/ciatimer.h SAME +src/Emulators/vice/core/spi-sdcard.c core/spi-sdcard.c SAME +src/Emulators/vice/core/m93c86.h core/m93c86.h SAME +src/Emulators/vice/core/flash040core.c core/flash040core.c SAME +src/Emulators/vice/resid-fp/residfp-siddefs-fp.h resid-fp/siddefs-fp.h.cc GONE +src/Emulators/vice/resid-fp/residfp-pot.cpp resid-fp/pot.cc MOVED:resid/pot.cc +src/Emulators/vice/resid-fp/residfp-wave.h resid-fp/wave.h.cc GONE +src/Emulators/vice/resid-fp/residfp-filter.h resid-fp/filter.h.cc GONE +src/Emulators/vice/resid-fp/residfp-extfilt.cpp resid-fp/extfilt.cc MOVED:resid-dtv/extfilt.cc +src/Emulators/vice/resid-fp/residfp-sid.cpp resid-fp/sid.cc MOVED:resid-dtv/sid.cc +src/Emulators/vice/resid-fp/residfp-envelope.cpp resid-fp/envelope.cc MOVED:resid-dtv/envelope.cc +src/Emulators/vice/resid-fp/residfp-filter.cpp resid-fp/filter.cc MOVED:resid-dtv/filter.cc +src/Emulators/vice/resid-fp/residfp-convolve.cpp resid-fp/convolve.cc GONE +src/Emulators/vice/resid-fp/residfp-wave.cpp resid-fp/wave.cc MOVED:resid-dtv/wave.cc +src/Emulators/vice/resid-fp/residfp-voice.h resid-fp/voice.h.cc GONE +src/Emulators/vice/resid-fp/residfp-convolve-sse.cpp resid-fp/convolve-sse.cc GONE +src/Emulators/vice/resid-fp/residfp-voice.cpp resid-fp/voice.cc MOVED:resid-dtv/voice.cc +src/Emulators/vice/resid-fp/residfp-sid.h resid-fp/sid.h.cc GONE +src/Emulators/vice/resid-fp/residfp-extfilt.h resid-fp/extfilt.h.cc GONE +src/Emulators/vice/resid-fp/residfp-pot.h resid-fp/pot.h.cc GONE +src/Emulators/vice/resid-fp/residfp-config.h resid-fp/config.h.cc GONE +src/Emulators/vice/resid-fp/residfp-envelope.h resid-fp/envelope.h.cc GONE +src/Emulators/vice/fileio/fileio.c fileio/fileio.c SAME +src/Emulators/vice/fileio/p00.c fileio/p00.c SAME +src/Emulators/vice/fileio/cbmfile.c fileio/cbmfile.c SAME +src/Emulators/vice/fileio/p00.h fileio/p00.h SAME +src/Emulators/vice/fileio/cbmfile.h fileio/cbmfile.h SAME +src/Emulators/vice/vice_debugger_hook.h - - OURS +src/Emulators/vice/platform/platform_discovery.h platform/platform_discovery.h GONE +src/Emulators/vice/platform/platform_os2_runtime_os.c platform/platform_os2_runtime_os.c GONE +src/Emulators/vice/platform/platform_amd64_msvc_cpuid.h platform/platform_amd64_msvc_cpuid.h GONE +src/Emulators/vice/platform/platform_solaris_runtime_os.c platform/platform_solaris_runtime_os.c GONE +src/Emulators/vice/platform/platform_macosx.c platform/platform_macosx.c GONE +src/Emulators/vice/platform/platform_x86_runtime_cpu.c platform/platform_x86_runtime_cpu.c GONE +src/Emulators/vice/platform/platform_compiler.h platform/platform_compiler.h GONE +src/Emulators/vice/platform/platform.c platform/platform.c GONE +src/Emulators/vice/platform/platform_cpu_type.h platform/platform_cpu_type.h GONE +src/Emulators/vice/platform/platform_x86_gcc_cpuid.h platform/platform_x86_gcc_cpuid.h GONE +src/Emulators/vice/platform/platform_beos_runtime_os.c platform/platform_beos_runtime_os.c GONE +src/Emulators/vice/platform/platform_aros_runtime_os.c platform/platform_aros_runtime_os.c GONE +src/Emulators/vice/platform/platform_x86_msvc_cpuid.h platform/platform_x86_msvc_cpuid.h GONE +src/Emulators/vice/platform/platform_amigaos3_runtime_os.c platform/platform_amigaos3_runtime_os.c GONE +src/Emulators/vice/platform/platform_amigaos4_runtime_os.c platform/platform_amigaos4_runtime_os.c GONE +src/Emulators/vice/platform/platform_macosx.h platform/platform_macosx.h GONE +src/Emulators/vice/platform/platform_windows_runtime_os.c platform/platform_windows_runtime_os.c GONE +src/Emulators/vice/platform/platform_x86_runtime_cpu.h platform/platform_x86_runtime_cpu.h GONE +src/Emulators/vice/platform/platform.h platform/platform.h GONE +src/Emulators/vice/platform/platform_linux_libc_version.h platform/platform_linux_libc_version.h GONE +src/Emulators/vice/platform/platform_syllable_runtime_os.c platform/platform_syllable_runtime_os.c GONE +src/Emulators/vice/diskimage/fsimage.h diskimage/fsimage.h SAME +src/Emulators/vice/diskimage/fsimage-dxx.h diskimage/fsimage-dxx.h SAME +src/Emulators/vice/diskimage/fsimage-probe.h diskimage/fsimage-probe.h SAME +src/Emulators/vice/diskimage/fsimage-p64.h diskimage/fsimage-p64.h SAME +src/Emulators/vice/diskimage/rawimage.h diskimage/rawimage.h GONE +src/Emulators/vice/diskimage/fsimage-create.c diskimage/fsimage-create.c SAME +src/Emulators/vice/diskimage/fsimage-gcr.c diskimage/fsimage-gcr.c SAME +src/Emulators/vice/diskimage/fsimage-check.c diskimage/fsimage-check.c SAME +src/Emulators/vice/diskimage/fsimage-dxx.c diskimage/fsimage-dxx.c SAME +src/Emulators/vice/diskimage/fsimage.c diskimage/fsimage.c SAME +src/Emulators/vice/diskimage/x64.h diskimage/x64.h SAME +src/Emulators/vice/diskimage/rawimage.c diskimage/rawimage.c GONE +src/Emulators/vice/diskimage/diskimage.c diskimage/diskimage.c SAME +src/Emulators/vice/diskimage/fsimage-p64.c diskimage/fsimage-p64.c SAME +src/Emulators/vice/diskimage/fsimage-probe.c diskimage/fsimage-probe.c SAME +src/Emulators/vice/diskimage/fsimage-create.h diskimage/fsimage-create.h SAME +src/Emulators/vice/diskimage/realimage.h diskimage/realimage.h SAME +src/Emulators/vice/diskimage/fsimage-gcr.h diskimage/fsimage-gcr.h SAME +src/Emulators/vice/diskimage/c1541.c diskimage/c1541.c MOVED:c1541.c +src/Emulators/vice/diskimage/fsimage-check.h diskimage/fsimage-check.h SAME +src/Emulators/vice/resid/resid-envelope.h resid/envelope.h.cc GONE +src/Emulators/vice/resid/resid-pot.h resid/pot.h.cc GONE +src/Emulators/vice/resid/resid-extfilt.cpp resid/extfilt.cc SAME +src/Emulators/vice/resid/resid-spline.h resid/spline.h.cc GONE +src/Emulators/vice/resid/resid-config.h resid/config.h.cc GONE +src/Emulators/vice/resid/resid-wave.cpp resid/wave.cc SAME +src/Emulators/vice/resid/wave8580__ST.h resid/wave8580__ST.h SAME +src/Emulators/vice/resid/wave8580_P_T.h resid/wave8580_P_T.h SAME +src/Emulators/vice/resid/wave8580_PS_.h resid/wave8580_PS_.h SAME +src/Emulators/vice/resid/resid-sid.h resid/sid.h.cc GONE +src/Emulators/vice/resid/resid-voice.h resid/voice.h.cc GONE +src/Emulators/vice/resid/wave6581_PST.h resid/wave6581_PST.h SAME +src/Emulators/vice/resid/resid-dac.cpp resid/dac.cc SAME +src/Emulators/vice/resid/resid-filter.cpp resid/filter.cc SAME +src/Emulators/vice/resid/resid-version.cpp resid/version.cc SAME +src/Emulators/vice/resid/resid-dac.h resid/dac.h.cc GONE +src/Emulators/vice/resid/resid-wave.h resid/wave.h.cc GONE +src/Emulators/vice/resid/wave6581__ST.h resid/wave6581__ST.h SAME +src/Emulators/vice/resid/resid-voice.cpp resid/voice.cc SAME +src/Emulators/vice/resid/wave6581_P_T.h resid/wave6581_P_T.h SAME +src/Emulators/vice/resid/resid-siddefs.h resid/siddefs.h.cc GONE +src/Emulators/vice/resid/resid-envelope.cpp resid/envelope.cc SAME +src/Emulators/vice/resid/resid-extfilt.h resid/extfilt.h.cc GONE +src/Emulators/vice/resid/resid-sid.cpp resid/sid.cc SAME +src/Emulators/vice/resid/wave8580_PST.h resid/wave8580_PST.h SAME +src/Emulators/vice/resid/resid-pot.cpp resid/pot.cc SAME +src/Emulators/vice/resid/resid-filter.h resid/filter.h.cc GONE +src/Emulators/vice/resid/wave6581_PS_.h resid/wave6581_PS_.h SAME +src/Emulators/vice/iecbus/iecbus.c iecbus/iecbus.c SAME +src/Emulators/vice/sounddrv/soundaiff.c sounddrv/soundaiff.c MOVED:arch/shared/sounddrv/soundaiff.c +src/Emulators/vice/sounddrv/sounddump.c sounddrv/sounddump.c MOVED:arch/shared/sounddrv/sounddump.c +src/Emulators/vice/sounddrv/soundfs.c sounddrv/soundfs.c MOVED:arch/shared/sounddrv/soundfs.c +src/Emulators/vice/sounddrv/soundsdl.c sounddrv/soundsdl.c MOVED:arch/shared/sounddrv/soundsdl.c +src/Emulators/vice/sounddrv/sounddummy.c sounddrv/sounddummy.c MOVED:arch/shared/sounddrv/sounddummy.c +src/Emulators/vice/sounddrv/soundiff.c sounddrv/soundiff.c MOVED:arch/shared/sounddrv/soundiff.c +src/Emulators/vice/sounddrv/soundmovie.h sounddrv/soundmovie.h MOVED:arch/shared/sounddrv/soundmovie.h +src/Emulators/vice/sounddrv/soundvoc.c sounddrv/soundvoc.c MOVED:arch/shared/sounddrv/soundvoc.c +src/Emulators/vice/sounddrv/soundmovie.c sounddrv/soundmovie.c MOVED:arch/shared/sounddrv/soundmovie.c +src/Emulators/vice/sounddrv/soundwav.c sounddrv/soundwav.c MOVED:arch/shared/sounddrv/soundwav.c +src/Emulators/vice/gfxoutputdrv/jpegdrv.c gfxoutputdrv/jpegdrv.c GONE +src/Emulators/vice/gfxoutputdrv/nativedrv.c gfxoutputdrv/nativedrv.c SAME +src/Emulators/vice/gfxoutputdrv/godotdrv.h gfxoutputdrv/godotdrv.h SAME +src/Emulators/vice/gfxoutputdrv/ppmdrv.c gfxoutputdrv/ppmdrv.c SAME +src/Emulators/vice/gfxoutputdrv/bmpdrv.h gfxoutputdrv/bmpdrv.h SAME +src/Emulators/vice/gfxoutputdrv/koaladrv.c gfxoutputdrv/koaladrv.c SAME +src/Emulators/vice/gfxoutputdrv/doodledrv.h gfxoutputdrv/doodledrv.h GONE +src/Emulators/vice/gfxoutputdrv/pcxdrv.h gfxoutputdrv/pcxdrv.h SAME +src/Emulators/vice/gfxoutputdrv/iffdrv.c gfxoutputdrv/iffdrv.c SAME +src/Emulators/vice/gfxoutputdrv/nativedrv.h gfxoutputdrv/nativedrv.h SAME +src/Emulators/vice/gfxoutputdrv/jpegdrv.h gfxoutputdrv/jpegdrv.h GONE +src/Emulators/vice/gfxoutputdrv/godotdrv.c gfxoutputdrv/godotdrv.c SAME +src/Emulators/vice/gfxoutputdrv/ppmdrv.h gfxoutputdrv/ppmdrv.h SAME +src/Emulators/vice/gfxoutputdrv/bmpdrv.c gfxoutputdrv/bmpdrv.c SAME +src/Emulators/vice/gfxoutputdrv/gfxoutput.c gfxoutputdrv/gfxoutput.c SAME +src/Emulators/vice/gfxoutputdrv/iffdrv.h gfxoutputdrv/iffdrv.h SAME +src/Emulators/vice/gfxoutputdrv/pcxdrv.c gfxoutputdrv/pcxdrv.c SAME +src/Emulators/vice/gfxoutputdrv/doodledrv.c gfxoutputdrv/doodledrv.c GONE +src/Emulators/vice/gfxoutputdrv/gifdrv.c gfxoutputdrv/gifdrv.c SAME +src/Emulators/vice/printerdrv/interface-serial.c printerdrv/interface-serial.c SAME +src/Emulators/vice/printerdrv/output-graphics.h printerdrv/output-graphics.h SAME +src/Emulators/vice/printerdrv/driver-select.c printerdrv/driver-select.c SAME +src/Emulators/vice/printerdrv/output-select.c printerdrv/output-select.c SAME +src/Emulators/vice/printerdrv/drv-nl10.h printerdrv/drv-nl10.h SAME +src/Emulators/vice/printerdrv/drv-1520.c printerdrv/drv-1520.c SAME +src/Emulators/vice/printerdrv/interface-userport.h printerdrv/interface-userport.h SAME +src/Emulators/vice/printerdrv/drv-raw.c printerdrv/drv-raw.c SAME +src/Emulators/vice/printerdrv/drv-ascii.h printerdrv/drv-ascii.h SAME +src/Emulators/vice/printerdrv/drv-mps803.h printerdrv/drv-mps803.h SAME +src/Emulators/vice/printerdrv/output-text.c printerdrv/output-text.c SAME +src/Emulators/vice/printerdrv/output.h printerdrv/output.h SAME +src/Emulators/vice/printerdrv/interface-serial.h printerdrv/interface-serial.h SAME +src/Emulators/vice/printerdrv/printer.c printerdrv/printer.c SAME +src/Emulators/vice/printerdrv/printer-userport.c printerdrv/printer-userport.c SAME +src/Emulators/vice/printerdrv/output-select.h printerdrv/output-select.h SAME +src/Emulators/vice/printerdrv/driver-select.h printerdrv/driver-select.h SAME +src/Emulators/vice/printerdrv/output-graphics.c printerdrv/output-graphics.c SAME +src/Emulators/vice/printerdrv/drv-ascii.c printerdrv/drv-ascii.c SAME +src/Emulators/vice/printerdrv/drv-raw.h printerdrv/drv-raw.h SAME +src/Emulators/vice/printerdrv/interface-userport.c printerdrv/interface-userport.c SAME +src/Emulators/vice/printerdrv/drv-nl10.c printerdrv/drv-nl10.c SAME +src/Emulators/vice/printerdrv/drv-1520.h printerdrv/drv-1520.h SAME +src/Emulators/vice/printerdrv/output-text.h printerdrv/output-text.h SAME +src/Emulators/vice/printerdrv/printer-serial.c printerdrv/printer-serial.c SAME +src/Emulators/vice/printerdrv/drv-mps803.c printerdrv/drv-mps803.c SAME +src/Emulators/vice/arch/joy.h arch/joy.h MOVED:arch/sdl/joy.h +src/Emulators/vice/arch/menu_sid.h arch/menu_sid.h MOVED:arch/sdl/menu_sid.h +src/Emulators/vice/arch/uistatusbar.c arch/uistatusbar.c MOVED:arch/gtk3/uistatusbar.c +src/Emulators/vice/arch/mousedrv.h arch/mousedrv.h MOVED:arch/gtk3/mousedrv.h +src/Emulators/vice/arch/menu_drive.c arch/menu_drive.c MOVED:arch/sdl/menu_drive.c +src/Emulators/vice/arch/x64sc_ui.c arch/x64sc_ui.c MOVED:arch/sdl/x64sc_ui.c +src/Emulators/vice/arch/blockdev.c arch/blockdev.c GONE +src/Emulators/vice/arch/menu_c64hw.c arch/menu_c64hw.c MOVED:arch/sdl/menu_c64hw.c +src/Emulators/vice/arch/menu_network.c arch/menu_network.c MOVED:arch/sdl/menu_network.c +src/Emulators/vice/arch/coproc.c arch/coproc.c MOVED:arch/shared/coproc.c +src/Emulators/vice/arch/menu_printer.h arch/menu_printer.h MOVED:arch/sdl/menu_printer.h +src/Emulators/vice/arch/menu_c64_common_expansions.c arch/menu_c64_common_expansions.c MOVED:arch/sdl/menu_c64_common_expansions.c +src/Emulators/vice/arch/menu_midi.c arch/menu_midi.c MOVED:arch/sdl/menu_midi.c +src/Emulators/vice/arch/menu_tfe.c arch/menu_tfe.c GONE +src/Emulators/vice/arch/menu_c64model.h arch/menu_c64model.h MOVED:arch/sdl/menu_c64model.h +src/Emulators/vice/arch/uimenu.h arch/uimenu.h MOVED:arch/gtk3/uimenu.h +src/Emulators/vice/arch/catweaselmkiii.c arch/catweaselmkiii.c MOVED:sid/catweaselmkiii.c +src/Emulators/vice/arch/menu_snapshot.h arch/menu_snapshot.h MOVED:arch/sdl/menu_snapshot.h +src/Emulators/vice/arch/menu_rom.c arch/menu_rom.c MOVED:arch/sdl/menu_rom.c +src/Emulators/vice/arch/uifilereq.h arch/uifilereq.h MOVED:arch/sdl/uifilereq.h +src/Emulators/vice/arch/menu_reset.h arch/menu_reset.h MOVED:arch/sdl/menu_reset.h +src/Emulators/vice/arch/menu_ffmpeg.h arch/menu_ffmpeg.h MOVED:arch/sdl/menu_ffmpeg.h +src/Emulators/vice/arch/rs232net.c arch/rs232net.c MOVED:rs232drv/rs232net.c +src/Emulators/vice/arch/uihotkey.c arch/uihotkey.c MOVED:arch/sdl/uihotkey.c +src/Emulators/vice/arch/vsyncarch.c arch/vsyncarch.c MOVED:arch/gtk3/vsyncarch.c +src/Emulators/vice/arch/uimsgbox.h arch/uimsgbox.h MOVED:arch/sdl/uimsgbox.h +src/Emulators/vice/arch/ui.h arch/ui.h MOVED:arch/gtk3/ui.h +src/Emulators/vice/arch/fullscreen.c arch/fullscreen.c MOVED:arch/sdl/fullscreen.c +src/Emulators/vice/arch/menu_joystick.c arch/menu_joystick.c MOVED:arch/sdl/menu_joystick.c +src/Emulators/vice/arch/menu_screenshot.c arch/menu_screenshot.c MOVED:arch/sdl/menu_screenshot.c +src/Emulators/vice/arch/video.c arch/video.c MOVED:arch/gtk3/video.c +src/Emulators/vice/arch/lightpendrv.h arch/lightpendrv.h MOVED:arch/sdl/lightpendrv.h +src/Emulators/vice/arch/menu_help.c arch/menu_help.c MOVED:arch/sdl/menu_help.c +src/Emulators/vice/arch/menu_common.c arch/menu_common.c MOVED:arch/sdl/menu_common.c +src/Emulators/vice/arch/uimon.c arch/uimon.c MOVED:arch/gtk3/uimon.c +src/Emulators/vice/arch/menu_tape.h arch/menu_tape.h MOVED:arch/sdl/menu_tape.h +src/Emulators/vice/arch/socketimpl.h arch/socketimpl.h MOVED:arch/shared/socketdrv/socketimpl.h +src/Emulators/vice/arch/vicetypes.h arch/vicetypes.h GONE +src/Emulators/vice/arch/kbd.h arch/kbd.h MOVED:arch/gtk3/kbd.h +src/Emulators/vice/arch/menu_rs232.c arch/menu_rs232.c MOVED:arch/sdl/menu_rs232.c +src/Emulators/vice/arch/menu_ram.c arch/menu_ram.c MOVED:arch/sdl/menu_ram.c +src/Emulators/vice/arch/videoarch.h arch/videoarch.h MOVED:arch/gtk3/videoarch.h +src/Emulators/vice/arch/menu_c64cart.h arch/menu_c64cart.h MOVED:arch/sdl/menu_c64cart.h +src/Emulators/vice/arch/menu_video.h arch/menu_video.h MOVED:arch/sdl/menu_video.h +src/Emulators/vice/arch/menu_vic20cart.c arch/menu_vic20cart.c MOVED:arch/sdl/menu_vic20cart.c +src/Emulators/vice/arch/menu_settings.c arch/menu_settings.c MOVED:arch/sdl/menu_settings.c +src/Emulators/vice/arch/menu_drive_rom.h arch/menu_drive_rom.h MOVED:arch/sdl/menu_drive_rom.h +src/Emulators/vice/arch/rawnetarch.c arch/rawnetarch.c MOVED:arch/shared/rawnetarch.c +src/Emulators/vice/arch/uicmdline.c arch/uicmdline.c MOVED:arch/gtk3/uicmdline.c +src/Emulators/vice/arch/menu_lightpen.c arch/menu_lightpen.c GONE +src/Emulators/vice/arch/menu_sound.c arch/menu_sound.c MOVED:arch/sdl/menu_sound.c +src/Emulators/vice/arch/parsid.c arch/parsid.c MOVED:sid/parsid.c +src/Emulators/vice/arch/menu_vic20hw.c arch/menu_vic20hw.c MOVED:arch/sdl/menu_vic20hw.c +src/Emulators/vice/arch/vkbd.h arch/vkbd.h MOVED:arch/sdl/vkbd.h +src/Emulators/vice/arch/menu_speed.c arch/menu_speed.c MOVED:arch/sdl/menu_speed.c +src/Emulators/vice/arch/vsidui_sdl.h arch/vsidui_sdl.h MOVED:arch/sdl/vsidui_sdl.h +src/Emulators/vice/arch/menu_c64_expansions.h arch/menu_c64_expansions.h MOVED:arch/sdl/menu_c64_expansions.h +src/Emulators/vice/arch/menu_debug.c arch/menu_debug.c MOVED:arch/sdl/menu_debug.c +src/Emulators/vice/arch/rs232dev.c arch/rs232dev.c MOVED:arch/shared/rs232dev.c +src/Emulators/vice/arch/menu_mouse.h arch/menu_mouse.h MOVED:arch/sdl/menu_mouse.h +src/Emulators/vice/arch/uipoll.h arch/uipoll.h MOVED:arch/sdl/uipoll.h +src/Emulators/vice/arch/archdep_unix.h arch/archdep_unix.h MOVED:arch/shared/archdep_unix.h +src/Emulators/vice/arch/menu_rom.h arch/menu_rom.h MOVED:arch/sdl/menu_rom.h +src/Emulators/vice/arch/menu_snapshot.c arch/menu_snapshot.c MOVED:arch/sdl/menu_snapshot.c +src/Emulators/vice/arch/menu_ffmpeg.c arch/menu_ffmpeg.c MOVED:arch/sdl/menu_ffmpeg.c +src/Emulators/vice/arch/menu_reset.c arch/menu_reset.c MOVED:arch/sdl/menu_reset.c +src/Emulators/vice/arch/uifilereq.c arch/uifilereq.c MOVED:arch/sdl/uifilereq.c +src/Emulators/vice/arch/menu_printer.c arch/menu_printer.c MOVED:arch/sdl/menu_printer.c +src/Emulators/vice/arch/coproc.h arch/coproc.h MOVED:arch/shared/coproc.h +src/Emulators/vice/arch/menu_network.h arch/menu_network.h MOVED:arch/sdl/menu_network.h +src/Emulators/vice/arch/uimenu.c arch/uimenu.c MOVED:arch/gtk3/uimenu.c +src/Emulators/vice/arch/menu_c64model.c arch/menu_c64model.c MOVED:arch/sdl/menu_c64model.c +src/Emulators/vice/arch/menu_midi.h arch/menu_midi.h MOVED:arch/sdl/menu_midi.h +src/Emulators/vice/arch/menu_tfe.h arch/menu_tfe.h GONE +src/Emulators/vice/arch/menu_c64_common_expansions.h arch/menu_c64_common_expansions.h MOVED:arch/sdl/menu_c64_common_expansions.h +src/Emulators/vice/arch/menu_drive.h arch/menu_drive.h MOVED:arch/sdl/menu_drive.h +src/Emulators/vice/arch/console.c arch/console.c MOVED:arch/shared/console.c +src/Emulators/vice/arch/menu_c64hw.h arch/menu_c64hw.h MOVED:arch/sdl/menu_c64hw.h +src/Emulators/vice/arch/uipause.c arch/uipause.c MOVED:arch/sdl/uipause.c +src/Emulators/vice/arch/menu_sid.c arch/menu_sid.c MOVED:arch/sdl/menu_sid.c +src/Emulators/vice/arch/joy.c arch/joy.c MOVED:arch/sdl/joy.c +src/Emulators/vice/arch/mousedrv.c arch/mousedrv.c MOVED:arch/gtk3/mousedrv.c +src/Emulators/vice/arch/uistatusbar.h arch/uistatusbar.h MOVED:arch/gtk3/uistatusbar.h +src/Emulators/vice/arch/fullscreenarch.h arch/fullscreenarch.h MOVED:arch/sdl/fullscreenarch.h +src/Emulators/vice/arch/menu_common.h arch/menu_common.h MOVED:arch/sdl/menu_common.h +src/Emulators/vice/arch/lightpendrv.c arch/lightpendrv.c MOVED:arch/sdl/lightpendrv.c +src/Emulators/vice/arch/menu_help.h arch/menu_help.h MOVED:arch/sdl/menu_help.h +src/Emulators/vice/arch/menu_screenshot.h arch/menu_screenshot.h MOVED:arch/sdl/menu_screenshot.h +src/Emulators/vice/arch/menu_joystick.h arch/menu_joystick.h MOVED:arch/sdl/menu_joystick.h +src/Emulators/vice/arch/c64-hardsid.c arch/c64-hardsid.c GONE +src/Emulators/vice/arch/rs232.c arch/rs232.c MOVED:rs232drv/rs232.c +src/Emulators/vice/arch/ui.c arch/ui.c MOVED:arch/gtk3/ui.c +src/Emulators/vice/arch/uimsgbox.c arch/uimsgbox.c MOVED:arch/sdl/uimsgbox.c +src/Emulators/vice/arch/uihotkey.h arch/uihotkey.h MOVED:arch/sdl/uihotkey.h +src/Emulators/vice/arch/rs232net.h arch/rs232net.h MOVED:rs232drv/rs232net.h +src/Emulators/vice/arch/menu_lightpen.h arch/menu_lightpen.h GONE +src/Emulators/vice/arch/menu_video.c arch/menu_video.c MOVED:arch/sdl/menu_video.c +src/Emulators/vice/arch/menu_drive_rom.c arch/menu_drive_rom.c MOVED:arch/sdl/menu_drive_rom.c +src/Emulators/vice/arch/dynlib.c arch/dynlib.c MOVED:arch/shared/dynlib.c +src/Emulators/vice/arch/menu_settings.h arch/menu_settings.h MOVED:arch/sdl/menu_settings.h +src/Emulators/vice/arch/menu_vic20cart.h arch/menu_vic20cart.h MOVED:arch/sdl/menu_vic20cart.h +src/Emulators/vice/arch/menu_c64cart.c arch/menu_c64cart.c MOVED:arch/sdl/menu_c64cart.c +src/Emulators/vice/arch/menu_ram.h arch/menu_ram.h MOVED:arch/sdl/menu_ram.h +src/Emulators/vice/arch/kbd.c arch/kbd.c MOVED:arch/gtk3/kbd.c +src/Emulators/vice/arch/menu_rs232.h arch/menu_rs232.h MOVED:arch/sdl/menu_rs232.h +src/Emulators/vice/arch/menu_tape.c arch/menu_tape.c MOVED:arch/sdl/menu_tape.c +src/Emulators/vice/arch/rs232dev.h arch/rs232dev.h MOVED:rs232drv/rs232dev.h +src/Emulators/vice/arch/menu_debug.h arch/menu_debug.h MOVED:arch/sdl/menu_debug.h +src/Emulators/vice/arch/menu_mouse.c arch/menu_mouse.c MOVED:arch/sdl/menu_mouse.c +src/Emulators/vice/arch/uipoll.c arch/uipoll.c MOVED:arch/sdl/uipoll.c +src/Emulators/vice/arch/vkbd.c arch/vkbd.c MOVED:arch/sdl/vkbd.c +src/Emulators/vice/arch/menu_c64_expansions.c arch/menu_c64_expansions.c MOVED:arch/sdl/menu_c64_expansions.c +src/Emulators/vice/arch/menu_speed.h arch/menu_speed.h MOVED:arch/sdl/menu_speed.h +src/Emulators/vice/arch/menu_vic20hw.h arch/menu_vic20hw.h MOVED:arch/sdl/menu_vic20hw.h +src/Emulators/vice/arch/menu_sound.h arch/menu_sound.h MOVED:arch/sdl/menu_sound.h +src/Emulators/vice/arch/signals.c arch/signals.c MOVED:arch/shared/signals.c +src/Emulators/vice/rtc/ds12c887.h rtc/ds12c887.h MOVED:core/rtc/ds12c887.h +src/Emulators/vice/rtc/ds1202_1302.h rtc/ds1202_1302.h MOVED:core/rtc/ds1202_1302.h +src/Emulators/vice/rtc/ds1602.c rtc/ds1602.c MOVED:core/rtc/ds1602.c +src/Emulators/vice/rtc/rtc.c rtc/rtc.c MOVED:core/rtc/rtc.c +src/Emulators/vice/rtc/bq4830y.h rtc/bq4830y.h MOVED:core/rtc/bq4830y.h +src/Emulators/vice/rtc/ds1216e.h rtc/ds1216e.h MOVED:core/rtc/ds1216e.h +src/Emulators/vice/rtc/ds1307.h rtc/ds1307.h MOVED:core/rtc/ds1307.h +src/Emulators/vice/rtc/rtc-58321a.h rtc/rtc-58321a.h MOVED:core/rtc/rtc-58321a.h +src/Emulators/vice/rtc/pcf8583.h rtc/pcf8583.h MOVED:core/rtc/pcf8583.h +src/Emulators/vice/rtc/ds1602.h rtc/ds1602.h MOVED:core/rtc/ds1602.h +src/Emulators/vice/rtc/ds1202_1302.c rtc/ds1202_1302.c MOVED:core/rtc/ds1202_1302.c +src/Emulators/vice/rtc/ds12c887.c rtc/ds12c887.c MOVED:core/rtc/ds12c887.c +src/Emulators/vice/rtc/bq4830y.c rtc/bq4830y.c MOVED:core/rtc/bq4830y.c +src/Emulators/vice/rtc/rtc.h rtc/rtc.h MOVED:core/rtc/rtc.h +src/Emulators/vice/rtc/pcf8583.c rtc/pcf8583.c MOVED:core/rtc/pcf8583.c +src/Emulators/vice/rtc/rtc-58321a.c rtc/rtc-58321a.c MOVED:core/rtc/rtc-58321a.c +src/Emulators/vice/rtc/ds1307.c rtc/ds1307.c MOVED:core/rtc/ds1307.c +src/Emulators/vice/rtc/ds1216e.c rtc/ds1216e.c MOVED:core/rtc/ds1216e.c +src/Emulators/vice/joyport/cx85.h joyport/cx85.h SAME +src/Emulators/vice/joyport/script64_dongle.c joyport/script64_dongle.c SAME +src/Emulators/vice/joyport/coplin_keypad.c joyport/coplin_keypad.c SAME +src/Emulators/vice/joyport/rushware_keypad.c joyport/rushware_keypad.c SAME +src/Emulators/vice/joyport/mouse.c joyport/mouse.c SAME +src/Emulators/vice/joyport/cardkey.h joyport/cardkey.h SAME +src/Emulators/vice/joyport/joyport.c joyport/joyport.c SAME +src/Emulators/vice/joyport/sampler2bit.c joyport/sampler2bit.c SAME +src/Emulators/vice/joyport/lightpen.h joyport/lightpen.h SAME +src/Emulators/vice/joyport/joystick.h joyport/joystick.h SAME +src/Emulators/vice/joyport/bbrtc.h joyport/bbrtc.h SAME +src/Emulators/vice/joyport/cx21.h joyport/cx21.h SAME +src/Emulators/vice/joyport/vizawrite64_dongle.h joyport/vizawrite64_dongle.h SAME +src/Emulators/vice/joyport/sampler4bit.c joyport/sampler4bit.c SAME +src/Emulators/vice/joyport/paperclip64.h joyport/paperclip64.h SAME +src/Emulators/vice/joyport/mouse.h joyport/mouse.h SAME +src/Emulators/vice/joyport/rushware_keypad.h joyport/rushware_keypad.h SAME +src/Emulators/vice/joyport/script64_dongle.h joyport/script64_dongle.h SAME +src/Emulators/vice/joyport/cx85.c joyport/cx85.c SAME +src/Emulators/vice/joyport/coplin_keypad.h joyport/coplin_keypad.h SAME +src/Emulators/vice/joyport/lightpen.c joyport/lightpen.c SAME +src/Emulators/vice/joyport/sampler2bit.h joyport/sampler2bit.h SAME +src/Emulators/vice/joyport/cardkey.c joyport/cardkey.c SAME +src/Emulators/vice/joyport/joyport.h joyport/joyport.h SAME +src/Emulators/vice/joyport/cx21.c joyport/cx21.c SAME +src/Emulators/vice/joyport/vizawrite64_dongle.c joyport/vizawrite64_dongle.c SAME +src/Emulators/vice/joyport/joystick.c joyport/joystick.c SAME +src/Emulators/vice/joyport/bbrtc.c joyport/bbrtc.c SAME +src/Emulators/vice/joyport/paperclip64.c joyport/paperclip64.c SAME +src/Emulators/vice/joyport/sampler4bit.h joyport/sampler4bit.h SAME +src/Emulators/vice/samplerdrv/file_drv.c samplerdrv/file_drv.c SAME +src/Emulators/vice/samplerdrv/sampler.h samplerdrv/sampler.h SAME +src/Emulators/vice/samplerdrv/portaudio_drv.h samplerdrv/portaudio_drv.h SAME +src/Emulators/vice/samplerdrv/file_drv.h samplerdrv/file_drv.h SAME +src/Emulators/vice/samplerdrv/sampler.c samplerdrv/sampler.c SAME +src/Emulators/vice/samplerdrv/portaudio_drv.c samplerdrv/portaudio_drv.c SAME +src/Emulators/vice/root/main.h main.h SAME +src/Emulators/vice/root/iecbus.h iecbus.h SAME +src/Emulators/vice/root/log.c log.c SAME +src/Emulators/vice/root/vice-crc32.c vice-crc32.c GONE +src/Emulators/vice/root/fliplist.c fliplist.c SAME +src/Emulators/vice/root/sound.h sound.h SAME +src/Emulators/vice/root/drivedos2040.h drivedos2040.h GONE +src/Emulators/vice/root/console.h console.h SAME +src/Emulators/vice/root/cbmdos.h cbmdos.h SAME +src/Emulators/vice/root/maincpu.h maincpu.h SAME +src/Emulators/vice/root/rawnet.c rawnet.c SAME +src/Emulators/vice/root/network.c network.c SAME +src/Emulators/vice/root/printer.h printer.h MOVED:printerdrv/printer.h +src/Emulators/vice/root/translate_funcs.h translate_funcs.h GONE +src/Emulators/vice/root/drivedos1541.h drivedos1541.h GONE +src/Emulators/vice/root/ram.h ram.h SAME +src/Emulators/vice/root/dma.h dma.h SAME +src/Emulators/vice/root/mididrv.h mididrv.h SAME +src/Emulators/vice/root/uicolor.h uicolor.h SAME +src/Emulators/vice/root/palette.c palette.c SAME +src/Emulators/vice/root/vicesocket.h vicesocket.h SAME +src/Emulators/vice/root/vsyncapi.h vsyncapi.h SAME +src/Emulators/vice/root/machine-video.h machine-video.h SAME +src/Emulators/vice/root/drivedos2000.h drivedos2000.h GONE +src/Emulators/vice/root/imagecontents.h imagecontents.h SAME +src/Emulators/vice/root/debug.h debug.h SAME +src/Emulators/vice/root/lib.c lib.c SAME +src/Emulators/vice/root/interrupt.c interrupt.c SAME +src/Emulators/vice/root/version.h version.h SAME +src/Emulators/vice/root/vicii_vice_vpl.h vicii_vice_vpl.h GONE +src/Emulators/vice/root/autostart-prg.c autostart-prg.c SAME +src/Emulators/vice/root/gcr.c gcr.c SAME +src/Emulators/vice/root/export.h export.h SAME +src/Emulators/vice/root/alarm.h alarm.h SAME +src/Emulators/vice/root/drivedos1570.h drivedos1570.h GONE +src/Emulators/vice/root/initcmdline.h initcmdline.h SAME +src/Emulators/vice/root/resources.h resources.h SAME +src/Emulators/vice/root/vice_sdl.h vice_sdl.h MOVED:arch/sdl/vice_sdl.h +src/Emulators/vice/root/util.c util.c SAME +src/Emulators/vice/root/c64_vice_vpl.h c64_vice_vpl.h GONE +src/Emulators/vice/root/drivedos1001.h drivedos1001.h GONE +src/Emulators/vice/root/cia.h cia.h SAME +src/Emulators/vice/root/embedded.c embedded.c GONE +src/Emulators/vice/root/midi.h midi.h SAME +src/Emulators/vice/root/c64_default_vpl.h c64_default_vpl.h GONE +src/Emulators/vice/root/c64_pc64_vpl.h c64_pc64_vpl.h GONE +src/Emulators/vice/root/diskimage.h diskimage.h SAME +src/Emulators/vice/root/via.h via.h SAME +src/Emulators/vice/root/screenshot.h screenshot.h SAME +src/Emulators/vice/root/cbmimage.c cbmimage.c SAME +src/Emulators/vice/root/clipboard.c clipboard.c SAME +src/Emulators/vice/root/vicii_ptoing_vpl.h vicii_ptoing_vpl.h GONE +src/Emulators/vice/root/drivedos3040.h drivedos3040.h GONE +src/Emulators/vice/root/machine.h machine.h SAME +src/Emulators/vice/root/findpath.c findpath.c SAME +src/Emulators/vice/root/keyboard.c keyboard.c SAME +src/Emulators/vice/root/drivedos2031.h drivedos2031.h GONE +src/Emulators/vice/root/vicii_pc64_vpl.h vicii_pc64_vpl.h GONE +src/Emulators/vice/root/autostart.h autostart.h SAME +src/Emulators/vice/root/opencbmlib.c opencbmlib.c SAME +src/Emulators/vice/root/traps.c traps.c SAME +src/Emulators/vice/root/viewport.h viewport.h SAME +src/Emulators/vice/root/gfxoutput.h gfxoutput.h SAME +src/Emulators/vice/root/wdc65816.h wdc65816.h SAME +src/Emulators/vice/root/vicefeatures.c vicefeatures.c SAME +src/Emulators/vice/root/init.c init.c SAME +src/Emulators/vice/root/fixpoint.h fixpoint.h SAME +src/Emulators/vice/root/vice-event.h vice-event.h SAME +src/Emulators/vice/root/info.c info.c SAME +src/Emulators/vice/root/vice-config.h vice-config.h GONE +src/Emulators/vice/root/translate.h translate.h GONE +src/Emulators/vice/root/drivedos4000.h drivedos4000.h GONE +src/Emulators/vice/root/ioutil.h ioutil.h GONE +src/Emulators/vice/root/romset.h romset.h SAME +src/Emulators/vice/root/vicii_deekay_vpl.h vicii_deekay_vpl.h GONE +src/Emulators/vice/root/kbdbuf.h kbdbuf.h SAME +src/Emulators/vice/root/dynlib.h dynlib.h SAME +src/Emulators/vice/root/libm_math.c libm_math.c GONE +src/Emulators/vice/root/drivedos4040.h drivedos4040.h GONE +src/Emulators/vice/root/clkguard.c clkguard.c GONE +src/Emulators/vice/root/cmdline.h cmdline.h SAME +src/Emulators/vice/root/charset.h charset.h SAME +src/Emulators/vice/root/sysfile.c sysfile.c SAME +src/Emulators/vice/root/attach.h attach.h SAME +src/Emulators/vice/root/mainc64cpu.h mainc64cpu.h SAME +src/Emulators/vice/root/machine-bus.h machine-bus.h SAME +src/Emulators/vice/root/rawfile.c rawfile.c SAME +src/Emulators/vice/root/color.h color.h SAME +src/Emulators/vice/root/r65c02.h r65c02.h SAME +src/Emulators/vice/root/signals.h signals.h SAME +src/Emulators/vice/root/printernl10cbm.h printernl10cbm.h GONE +src/Emulators/vice/root/drived1541II.h drived1541II.h GONE +src/Emulators/vice/root/datasette.c datasette.c MOVED:datasette/datasette.c +src/Emulators/vice/root/socket.c socket.c SAME +src/Emulators/vice/root/machine-printer.h machine-printer.h SAME +src/Emulators/vice/root/vsync.h vsync.h SAME +src/Emulators/vice/root/zfile.c zfile.c SAME +src/Emulators/vice/root/zipcode.c zipcode.c SAME +src/Emulators/vice/root/vicii_community_colors_vpl.h vicii_community_colors_vpl.h GONE +src/Emulators/vice/root/snapshot.c snapshot.c SAME +src/Emulators/vice/root/c64chargen.h c64chargen.h GONE +src/Emulators/vice/root/serial.h serial.h SAME +src/Emulators/vice/root/lib.h lib.h SAME +src/Emulators/vice/root/debug.c debug.c SAME +src/Emulators/vice/root/archapi.h archapi.h MOVED:arch/shared/archapi.h +src/Emulators/vice/root/drivedos1581.h drivedos1581.h GONE +src/Emulators/vice/root/mos6510.h mos6510.h SAME +src/Emulators/vice/root/rs232drv.h rs232drv.h MOVED:rs232drv/rs232drv.h +src/Emulators/vice/root/dma.c dma.c SAME +src/Emulators/vice/root/catweaselmkiii.h catweaselmkiii.h SAME +src/Emulators/vice/root/palette.h palette.h SAME +src/Emulators/vice/root/rsuser.h rsuser.h MOVED:rs232drv/rsuser.h +src/Emulators/vice/root/monitor.h monitor.h SAME +src/Emulators/vice/root/rawnet.h rawnet.h SAME +src/Emulators/vice/root/cbmdos.c cbmdos.c SAME +src/Emulators/vice/root/ssi2001.h ssi2001.h GONE +src/Emulators/vice/root/ram.c ram.c SAME +src/Emulators/vice/root/iecdrive.h iecdrive.h SAME +src/Emulators/vice/root/blockdev.h blockdev.h GONE +src/Emulators/vice/root/vicii.h vicii.h SAME +src/Emulators/vice/root/network.h network.h SAME +src/Emulators/vice/root/c64_ccs64_vpl.h c64_ccs64_vpl.h GONE +src/Emulators/vice/root/main.c main.c SAME +src/Emulators/vice/root/vice.h vice.h SAME +src/Emulators/vice/root/tpi.h tpi.h SAME +src/Emulators/vice/root/sound.c sound.c SAME +src/Emulators/vice/root/vice-crc32.h vice-crc32.h GONE +src/Emulators/vice/root/fliplist.h fliplist.h SAME +src/Emulators/vice/root/log.h log.h SAME +src/Emulators/vice/root/vicii_pepto_palold_vpl.h vicii_pepto_palold_vpl.h GONE +src/Emulators/vice/root/event.c event.c SAME +src/Emulators/vice/root/keyboard.h keyboard.h SAME +src/Emulators/vice/root/findpath.h findpath.h SAME +src/Emulators/vice/root/machine.c machine.c SAME +src/Emulators/vice/root/translate_languages.h translate_languages.h GONE +src/Emulators/vice/root/vicii_pepto_ntsc_vpl.h vicii_pepto_ntsc_vpl.h GONE +src/Emulators/vice/root/vsidui.h vsidui.h SAME +src/Emulators/vice/root/uimon.h uimon.h SAME +src/Emulators/vice/root/opencbmlib.h opencbmlib.h SAME +src/Emulators/vice/root/autostart.c autostart.c SAME +src/Emulators/vice/root/screenshot.c screenshot.c SAME +src/Emulators/vice/root/mos6510dtv.h mos6510dtv.h SAME +src/Emulators/vice/root/fullscreen.h fullscreen.h SAME +src/Emulators/vice/root/cartridge.h cartridge.h SAME +src/Emulators/vice/root/video.h video.h SAME +src/Emulators/vice/root/clipboard.h clipboard.h SAME +src/Emulators/vice/root/cbmimage.h cbmimage.h SAME +src/Emulators/vice/root/util.h util.h SAME +src/Emulators/vice/root/fsdevice.h fsdevice.h SAME +src/Emulators/vice/root/c64_c64hq_vpl.h c64_c64hq_vpl.h GONE +src/Emulators/vice/root/resources.c resources.c SAME +src/Emulators/vice/root/initcmdline.c initcmdline.c SAME +src/Emulators/vice/root/fileio.h fileio.h SAME +src/Emulators/vice/root/6510core.h 6510core.h SAME +src/Emulators/vice/root/c64_frodo_vpl.h c64_frodo_vpl.h GONE +src/Emulators/vice/root/midi.c midi.c SAME +src/Emulators/vice/root/embedded.h embedded.h GONE +src/Emulators/vice/root/autostart-prg.h autostart-prg.h SAME +src/Emulators/vice/root/gcr.h gcr.h SAME +src/Emulators/vice/root/diskconstants.h diskconstants.h SAME +src/Emulators/vice/root/interrupt.h interrupt.h SAME +src/Emulators/vice/root/alarm.c alarm.c SAME +src/Emulators/vice/root/vicii_godot_vpl.h vicii_godot_vpl.h GONE +src/Emulators/vice/root/sysfile.h sysfile.h SAME +src/Emulators/vice/root/charset.c charset.c SAME +src/Emulators/vice/root/attach.c attach.c SAME +src/Emulators/vice/root/infocontrib.h infocontrib.h GONE +src/Emulators/vice/root/uicmdline.h uicmdline.h SAME +src/Emulators/vice/root/vicii_c64hq_vpl.h vicii_c64hq_vpl.h GONE +src/Emulators/vice/root/hardsid.h hardsid.h SAME +src/Emulators/vice/root/cmdline.c cmdline.c SAME +src/Emulators/vice/root/clkguard.h clkguard.h GONE +src/Emulators/vice/root/rawfile.h rawfile.h SAME +src/Emulators/vice/root/machine-bus.c machine-bus.c SAME +src/Emulators/vice/root/vicii_frodo_vpl.h vicii_frodo_vpl.h GONE +src/Emulators/vice/root/drivedos1540.h drivedos1540.h GONE +src/Emulators/vice/root/kbdbuf.c kbdbuf.c SAME +src/Emulators/vice/root/libm_math.h libm_math.h GONE +src/Emulators/vice/root/c64_godot_vpl.h c64_godot_vpl.h GONE +src/Emulators/vice/root/ioutil.c ioutil.c GONE +src/Emulators/vice/root/translate.c translate.c GONE +src/Emulators/vice/root/cartio.h cartio.h SAME +src/Emulators/vice/root/acia.h acia.h SAME +src/Emulators/vice/root/mem.h mem.h SAME +src/Emulators/vice/root/flash040.h flash040.h SAME +src/Emulators/vice/root/romset.c romset.c SAME +src/Emulators/vice/root/vicefeatures.h vicefeatures.h SAME +src/Emulators/vice/root/traps.h traps.h SAME +src/Emulators/vice/root/machine-drive.h machine-drive.h SAME +src/Emulators/vice/root/tap.h tap.h SAME +src/Emulators/vice/root/info.h info.h SAME +src/Emulators/vice/root/fixpoint.c fixpoint.c SAME +src/Emulators/vice/root/init.h init.h SAME +src/Emulators/vice/root/vicemaxpath.h vicemaxpath.h GONE +src/Emulators/vice/root/c64basic.h c64basic.h GONE +src/Emulators/vice/root/snapshot.h snapshot.h SAME +src/Emulators/vice/root/tape.h tape.h SAME +src/Emulators/vice/root/riot.h riot.h SAME +src/Emulators/vice/root/parallel.h parallel.h SAME +src/Emulators/vice/root/h6809regs.h h6809regs.h SAME +src/Emulators/vice/root/vsync.c vsync.c SAME +src/Emulators/vice/root/vicii_pepto_pal_vpl.h vicii_pepto_pal_vpl.h GONE +src/Emulators/vice/root/vicii_rgb_vpl.h vicii_rgb_vpl.h GONE +src/Emulators/vice/root/vicii_ccs64_vpl.h vicii_ccs64_vpl.h GONE +src/Emulators/vice/root/vicii_pepto_ntsc_sony_vpl.h vicii_pepto_ntsc_sony_vpl.h GONE +src/Emulators/vice/root/datasette.h datasette.h MOVED:datasette/datasette.h +src/Emulators/vice/root/zipcode.h zipcode.h SAME +src/Emulators/vice/root/zfile.h zfile.h SAME +src/Emulators/vice/root/drivedos1571.h drivedos1571.h GONE +src/Emulators/vice/root/c64kernal.h c64kernal.h GONE +src/Emulators/vice/root/c64_c64s_vpl.h c64_c64s_vpl.h GONE +src/Emulators/vice/root/z80regs.h z80regs.h SAME +src/Emulators/vice/root/parsid.h parsid.h SAME +src/Emulators/vice/root/color.c color.c SAME +src/Emulators/vice/root/printermps803.h printermps803.h GONE +src/Emulators/vice/root/c64ui.h c64ui.h SAME +src/Emulators/vice/root/vicii_c64s_vpl.h vicii_c64s_vpl.h GONE +src/Emulators/vice/root/uiapi.h uiapi.h SAME +src/Emulators/vice/lib/p64/p64config.h lib/p64/p64config.h SAME +src/Emulators/vice/lib/p64/p64.h lib/p64/p64.h SAME +src/Emulators/vice/lib/p64/p64.c lib/p64/p64.c SAME +src/Emulators/vice/tape/tapeimage.h tape/tapeimage.h SAME +src/Emulators/vice/tape/tape-snapshot.h tape/tape-snapshot.h SAME +src/Emulators/vice/tape/tap.c tape/tap.c SAME +src/Emulators/vice/tape/tape-internal.c tape/tape-internal.c SAME +src/Emulators/vice/tape/t64.h tape/t64.h SAME +src/Emulators/vice/tape/tape.c tape/tape.c SAME +src/Emulators/vice/tape/tapeimage.c tape/tapeimage.c SAME +src/Emulators/vice/tape/tape-snapshot.c tape/tape-snapshot.c SAME +src/Emulators/vice/tape/t64.c tape/t64.c SAME +src/Emulators/vice/tape/tape-internal.h tape/tape-internal.h SAME +src/Emulators/vice/viciisc/vicii.c viciisc/vicii.c SAME +src/Emulators/vice/viciisc/vicii-irq.c viciisc/vicii-irq.c SAME +src/Emulators/vice/viciisc/vicii-lightpen.c viciisc/vicii-lightpen.c SAME +src/Emulators/vice/viciisc/vicii-draw-cycle.h viciisc/vicii-draw-cycle.h SAME +src/Emulators/vice/viciisc/vicii-chip-model.h viciisc/vicii-chip-model.h SAME +src/Emulators/vice/viciisc/vicii-timing.h viciisc/vicii-timing.h SAME +src/Emulators/vice/viciisc/vicii-draw.h viciisc/vicii-draw.h SAME +src/Emulators/vice/viciisc/vicii-fetch.h viciisc/vicii-fetch.h SAME +src/Emulators/vice/viciisc/vicii-cmdline-options.c viciisc/vicii-cmdline-options.c SAME +src/Emulators/vice/viciisc/vicii-cycle.c viciisc/vicii-cycle.c SAME +src/Emulators/vice/viciisc/vicii-color.c viciisc/vicii-color.c SAME +src/Emulators/vice/viciisc/vicii-snapshot.h viciisc/vicii-snapshot.h SAME +src/Emulators/vice/viciisc/vicii-resources.h viciisc/vicii-resources.h SAME +src/Emulators/vice/viciisc/vicii-phi1.h viciisc/vicii-phi1.h SAME +src/Emulators/vice/viciisc/vicii-mem.c viciisc/vicii-mem.c SAME +src/Emulators/vice/viciisc/vicii-irq.h viciisc/vicii-irq.h SAME +src/Emulators/vice/viciisc/vicii-lightpen.h viciisc/vicii-lightpen.h SAME +src/Emulators/vice/viciisc/viciitypes.h viciisc/viciitypes.h SAME +src/Emulators/vice/viciisc/vicii-fetch.c viciisc/vicii-fetch.c SAME +src/Emulators/vice/viciisc/vicii-draw.c viciisc/vicii-draw.c SAME +src/Emulators/vice/viciisc/vicii-timing.c viciisc/vicii-timing.c SAME +src/Emulators/vice/viciisc/vicii-chip-model.c viciisc/vicii-chip-model.c SAME +src/Emulators/vice/viciisc/vicii-draw-cycle.c viciisc/vicii-draw-cycle.c SAME +src/Emulators/vice/viciisc/vicii-snapshot.c viciisc/vicii-snapshot.c SAME +src/Emulators/vice/viciisc/vicii-color.h viciisc/vicii-color.h SAME +src/Emulators/vice/viciisc/vicii-cmdline-options.h viciisc/vicii-cmdline-options.h SAME +src/Emulators/vice/viciisc/vicii-cycle.h viciisc/vicii-cycle.h SAME +src/Emulators/vice/viciisc/vicii-mem.h viciisc/vicii-mem.h SAME +src/Emulators/vice/viciisc/vicii-phi1.c viciisc/vicii-phi1.c SAME +src/Emulators/vice/viciisc/vicii-resources.c viciisc/vicii-resources.c SAME +src/Emulators/vice/raster/raster-canvas.c raster/raster-canvas.c SAME +src/Emulators/vice/raster/raster-changes.h raster/raster-changes.h SAME +src/Emulators/vice/raster/raster-cache.h raster/raster-cache.h SAME +src/Emulators/vice/raster/raster-line-changes.c raster/raster-line-changes.c SAME +src/Emulators/vice/raster/raster-modes.c raster/raster-modes.c SAME +src/Emulators/vice/raster/raster-sprite-status.c raster/raster-sprite-status.c SAME +src/Emulators/vice/raster/raster-resources.h raster/raster-resources.h SAME +src/Emulators/vice/raster/raster-line.c raster/raster-line.c SAME +src/Emulators/vice/raster/raster-sprite.c raster/raster-sprite.c SAME +src/Emulators/vice/raster/raster-cmdline-options.h raster/raster-cmdline-options.h SAME +src/Emulators/vice/raster/raster-line-changes-sprite.c raster/raster-line-changes-sprite.c SAME +src/Emulators/vice/raster/raster.h raster/raster.h SAME +src/Emulators/vice/raster/raster-sprite-cache.c raster/raster-sprite-cache.c SAME +src/Emulators/vice/raster/raster-modes.h raster/raster-modes.h SAME +src/Emulators/vice/raster/raster-sprite-status.h raster/raster-sprite-status.h SAME +src/Emulators/vice/raster/raster-cache.c raster/raster-cache.c SAME +src/Emulators/vice/raster/raster-changes.c raster/raster-changes.c SAME +src/Emulators/vice/raster/raster-canvas.h raster/raster-canvas.h SAME +src/Emulators/vice/raster/raster-line.h raster/raster-line.h SAME +src/Emulators/vice/raster/raster-resources.c raster/raster-resources.c SAME +src/Emulators/vice/raster/raster-cmdline-options.c raster/raster-cmdline-options.c SAME +src/Emulators/vice/raster/raster-sprite.h raster/raster-sprite.h SAME +src/Emulators/vice/raster/raster-sprite-cache.h raster/raster-sprite-cache.h SAME +src/Emulators/vice/raster/raster.c raster/raster.c SAME +src/Emulators/vice/rs232drv/rs232drv.c rs232drv/rs232drv.c SAME +src/Emulators/vice/rs232drv/rsuser.c rs232drv/rsuser.c SAME +src/Emulators/vice/rs232drv/rs232.h rs232drv/rs232.h SAME +src/Emulators/vice/sid/sid-cmdline-options.h sid/sid-cmdline-options.h SAME +src/Emulators/vice/sid/fastsid.c sid/fastsid.c SAME +src/Emulators/vice/sid/wave6581.h sid/wave6581.h SAME +src/Emulators/vice/sid/sid-resources.c sid/sid-resources.c SAME +src/Emulators/vice/sid/wave8580.h sid/wave8580.h SAME +src/Emulators/vice/sid/sid-snapshot.c sid/sid-snapshot.c SAME +src/Emulators/vice/sid/sid.c sid/sid.c SAME +src/Emulators/vice/sid/resid.cpp sid/resid.cpp GONE +src/Emulators/vice/sid/resid-fp.h sid/resid-fp.h GONE +src/Emulators/vice/sid/sid-resources.h sid/sid-resources.h SAME +src/Emulators/vice/sid/fastsid.h sid/fastsid.h SAME +src/Emulators/vice/sid/sid-cmdline-options.c sid/sid-cmdline-options.c SAME +src/Emulators/vice/sid/resid.h sid/resid.h SAME +src/Emulators/vice/sid/resid-fp.cpp sid/resid-fp.cpp GONE +src/Emulators/vice/sid/sid.h sid/sid.h SAME +src/Emulators/vice/sid/sid-snapshot.h sid/sid-snapshot.h SAME +src/Emulators/vice/drive/drive-check.h drive/drive-check.h SAME +src/Emulators/vice/drive/tcbm/tpid.h drive/tcbm/tpid.h SAME +src/Emulators/vice/drive/tcbm/tpid.c drive/tcbm/tpid.c SAME +src/Emulators/vice/drive/iecieee.h drive/iecieee.h SAME +src/Emulators/vice/drive/drive-cmdline-options.c drive/drive-cmdline-options.c SAME +src/Emulators/vice/drive/drive-snapshot.h drive/drive-snapshot.h SAME +src/Emulators/vice/drive/drive-sound.c drive/drive-sound.c SAME +src/Emulators/vice/drive/drivecpu.h drive/drivecpu.h SAME +src/Emulators/vice/drive/drivecpu65c02.c drive/drivecpu65c02.c SAME +src/Emulators/vice/drive/drivemem.h drive/drivemem.h SAME +src/Emulators/vice/drive/driverom.c drive/driverom.c SAME +src/Emulators/vice/drive/rotation.h drive/rotation.h SAME +src/Emulators/vice/drive/iecieee/iecieee.c drive/iecieee/iecieee.c SAME +src/Emulators/vice/drive/iecieee/via2d.c drive/iecieee/via2d.c SAME +src/Emulators/vice/drive/drivesync.c drive/drivesync.c SAME +src/Emulators/vice/drive/driveimage.h drive/driveimage.h SAME +src/Emulators/vice/drive/drive-resources.c drive/drive-resources.c SAME +src/Emulators/vice/drive/drive.h drive/drive.h SAME +src/Emulators/vice/drive/drive-writeprotect.h drive/drive-writeprotect.h SAME +src/Emulators/vice/drive/drive-overflow.h drive/drive-overflow.h GONE +src/Emulators/vice/drive/viad.h drive/viad.h SAME +src/Emulators/vice/drive/drive-check.c drive/drive-check.c SAME +src/Emulators/vice/drive/drivecpu.c drive/drivecpu.c SAME +src/Emulators/vice/drive/drive-snapshot.c drive/drive-snapshot.c SAME +src/Emulators/vice/drive/drive-sound.h drive/drive-sound.h SAME +src/Emulators/vice/drive/drivetypes.h drive/drivetypes.h SAME +src/Emulators/vice/drive/iec-c64exp.h drive/iec-c64exp.h SAME +src/Emulators/vice/drive/drive-cmdline-options.h drive/drive-cmdline-options.h SAME +src/Emulators/vice/drive/rotation.c drive/rotation.c SAME +src/Emulators/vice/drive/drivesync.h drive/drivesync.h SAME +src/Emulators/vice/drive/driverom.h drive/driverom.h SAME +src/Emulators/vice/drive/ieee/ieee-resources.h drive/ieee/ieee-resources.h SAME +src/Emulators/vice/drive/ieee/memieee.h drive/ieee/memieee.h SAME +src/Emulators/vice/drive/ieee/riotd.h drive/ieee/riotd.h SAME +src/Emulators/vice/drive/ieee/fdc.h drive/ieee/fdc.h SAME +src/Emulators/vice/drive/ieee/ieeerom.c drive/ieee/ieeerom.c SAME +src/Emulators/vice/drive/ieee/ieee-cmdline-options.h drive/ieee/ieee-cmdline-options.h SAME +src/Emulators/vice/drive/ieee/riot1d.c drive/ieee/riot1d.c SAME +src/Emulators/vice/drive/ieee/via1d2031.h drive/ieee/via1d2031.h SAME +src/Emulators/vice/drive/ieee/ieee.c drive/ieee/ieee.c SAME +src/Emulators/vice/drive/ieee/memieee.c drive/ieee/memieee.c SAME +src/Emulators/vice/drive/ieee/ieee-resources.c drive/ieee/ieee-resources.c SAME +src/Emulators/vice/drive/ieee/fdc.c drive/ieee/fdc.c SAME +src/Emulators/vice/drive/ieee/riot2d.c drive/ieee/riot2d.c SAME +src/Emulators/vice/drive/ieee/ieee-cmdline-options.c drive/ieee/ieee-cmdline-options.c SAME +src/Emulators/vice/drive/ieee/ieeerom.h drive/ieee/ieeerom.h SAME +src/Emulators/vice/drive/ieee/via1d2031.c drive/ieee/via1d2031.c SAME +src/Emulators/vice/drive/drivemem.c drive/drivemem.c SAME +src/Emulators/vice/drive/drivecpu65c02.h drive/drivecpu65c02.h SAME +src/Emulators/vice/drive/iec/via4000.h drive/iec/via4000.h SAME +src/Emulators/vice/drive/iec/iec-resources.c drive/iec/iec-resources.c SAME +src/Emulators/vice/drive/iec/pc8477.c drive/iec/pc8477.c SAME +src/Emulators/vice/drive/iec/glue1571.c drive/iec/glue1571.c SAME +src/Emulators/vice/drive/iec/cia1571d.c drive/iec/cia1571d.c SAME +src/Emulators/vice/drive/iec/iec-cmdline-options.c drive/iec/iec-cmdline-options.c SAME +src/Emulators/vice/drive/iec/iecrom.h drive/iec/iecrom.h SAME +src/Emulators/vice/drive/iec/memiec.h drive/iec/memiec.h SAME +src/Emulators/vice/drive/iec/wd1770.c drive/iec/wd1770.c SAME +src/Emulators/vice/drive/iec/via1d1541.h drive/iec/via1d1541.h SAME +src/Emulators/vice/drive/iec/iec.c drive/iec/iec.c SAME +src/Emulators/vice/drive/iec/fdd.h drive/iec/fdd.h SAME +src/Emulators/vice/drive/iec/ciad.h drive/iec/ciad.h SAME +src/Emulators/vice/drive/iec/pc8477.h drive/iec/pc8477.h SAME +src/Emulators/vice/drive/iec/iec-resources.h drive/iec/iec-resources.h SAME +src/Emulators/vice/drive/iec/c64exp/profdos.h drive/iec/c64exp/profdos.h SAME +src/Emulators/vice/drive/iec/c64exp/c64exp-resources.c drive/iec/c64exp/c64exp-resources.c SAME +src/Emulators/vice/drive/iec/c64exp/iec-c64exp.c drive/iec/c64exp/iec-c64exp.c SAME +src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.c drive/iec/c64exp/c64exp-cmdline-options.c SAME +src/Emulators/vice/drive/iec/c64exp/dolphindos3.c drive/iec/c64exp/dolphindos3.c SAME +src/Emulators/vice/drive/iec/c64exp/supercard.c drive/iec/c64exp/supercard.c SAME +src/Emulators/vice/drive/iec/c64exp/stardos-exp.h drive/iec/c64exp/stardos-exp.h SAME +src/Emulators/vice/drive/iec/c64exp/profdos.c drive/iec/c64exp/profdos.c SAME +src/Emulators/vice/drive/iec/c64exp/c64exp-resources.h drive/iec/c64exp/c64exp-resources.h SAME +src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.h drive/iec/c64exp/c64exp-cmdline-options.h SAME +src/Emulators/vice/drive/iec/c64exp/dolphindos3.h drive/iec/c64exp/dolphindos3.h SAME +src/Emulators/vice/drive/iec/c64exp/stardos-exp.c drive/iec/c64exp/stardos-exp.c SAME +src/Emulators/vice/drive/iec/c64exp/supercard.h drive/iec/c64exp/supercard.h SAME +src/Emulators/vice/drive/iec/via4000.c drive/iec/via4000.c SAME +src/Emulators/vice/drive/iec/glue1571.h drive/iec/glue1571.h SAME +src/Emulators/vice/drive/iec/via1d1541.c drive/iec/via1d1541.c SAME +src/Emulators/vice/drive/iec/wd1770.h drive/iec/wd1770.h SAME +src/Emulators/vice/drive/iec/memiec.c drive/iec/memiec.c SAME +src/Emulators/vice/drive/iec/iecrom.c drive/iec/iecrom.c SAME +src/Emulators/vice/drive/iec/iec-cmdline-options.h drive/iec/iec-cmdline-options.h SAME +src/Emulators/vice/drive/iec/cia1581d.c drive/iec/cia1581d.c SAME +src/Emulators/vice/drive/iec/fdd.c drive/iec/fdd.c SAME +src/Emulators/vice/drive/ieee.h drive/ieee.h SAME +src/Emulators/vice/drive/drive-overflow.c drive/drive-overflow.c GONE +src/Emulators/vice/drive/drive-writeprotect.c drive/drive-writeprotect.c SAME +src/Emulators/vice/drive/drive-resources.h drive/drive-resources.h SAME +src/Emulators/vice/drive/drive.c drive/drive.c SAME +src/Emulators/vice/drive/iec.h drive/iec.h SAME +src/Emulators/vice/drive/driveimage.c drive/driveimage.c SAME +src/Emulators/vice/vdrive/vdrive.h vdrive/vdrive.h SAME +src/Emulators/vice/vdrive/vdrive-bam.h vdrive/vdrive-bam.h SAME +src/Emulators/vice/vdrive/vdrive-internal.h vdrive/vdrive-internal.h SAME +src/Emulators/vice/vdrive/vdrive-command.c vdrive/vdrive-command.c SAME +src/Emulators/vice/vdrive/vdrive-iec.c vdrive/vdrive-iec.c SAME +src/Emulators/vice/vdrive/vdrive-dir.c vdrive/vdrive-dir.c SAME +src/Emulators/vice/vdrive/vdrive-rel.c vdrive/vdrive-rel.c SAME +src/Emulators/vice/vdrive/vdrive-snapshot.c vdrive/vdrive-snapshot.c SAME +src/Emulators/vice/vdrive/vdrive-internal.c vdrive/vdrive-internal.c SAME +src/Emulators/vice/vdrive/vdrive-bam.c vdrive/vdrive-bam.c SAME +src/Emulators/vice/vdrive/vdrive.c vdrive/vdrive.c SAME +src/Emulators/vice/vdrive/vdrive-command.h vdrive/vdrive-command.h SAME +src/Emulators/vice/vdrive/vdrive-dir.h vdrive/vdrive-dir.h SAME +src/Emulators/vice/vdrive/vdrive-iec.h vdrive/vdrive-iec.h SAME +src/Emulators/vice/vdrive/vdrive-snapshot.h vdrive/vdrive-snapshot.h SAME +src/Emulators/vice/vdrive/vdrive-rel.h vdrive/vdrive-rel.h SAME +src/Emulators/vice/fsdevice/fsdevicetypes.h fsdevice/fsdevicetypes.h SAME +src/Emulators/vice/fsdevice/fsdevice-resources.c fsdevice/fsdevice-resources.c SAME +src/Emulators/vice/fsdevice/fsdevice-open.h fsdevice/fsdevice-open.h SAME +src/Emulators/vice/fsdevice/fsdevice.c fsdevice/fsdevice.c SAME +src/Emulators/vice/fsdevice/fsdevice-flush.h fsdevice/fsdevice-flush.h SAME +src/Emulators/vice/fsdevice/fsdevice-read.c fsdevice/fsdevice-read.c SAME +src/Emulators/vice/fsdevice/fsdevice-cmdline-options.h fsdevice/fsdevice-cmdline-options.h SAME +src/Emulators/vice/fsdevice/fsdevice-close.c fsdevice/fsdevice-close.c SAME +src/Emulators/vice/fsdevice/fsdevice-write.c fsdevice/fsdevice-write.c SAME +src/Emulators/vice/fsdevice/fsdevice-resources.h fsdevice/fsdevice-resources.h SAME +src/Emulators/vice/fsdevice/fsdevice-cmdline-options.c fsdevice/fsdevice-cmdline-options.c SAME +src/Emulators/vice/fsdevice/fsdevice-flush.c fsdevice/fsdevice-flush.c SAME +src/Emulators/vice/fsdevice/fsdevice-read.h fsdevice/fsdevice-read.h SAME +src/Emulators/vice/fsdevice/fsdevice-open.c fsdevice/fsdevice-open.c SAME +src/Emulators/vice/fsdevice/fsdevice-write.h fsdevice/fsdevice-write.h SAME +src/Emulators/vice/fsdevice/fsdevice-close.h fsdevice/fsdevice-close.h SAME +src/Emulators/vice/userport/userport_8bss.c userport/userport_8bss.c SAME +src/Emulators/vice/userport/userport_4bit_sampler.c userport/userport_4bit_sampler.c SAME +src/Emulators/vice/userport/userport.h userport/userport.h SAME +src/Emulators/vice/userport/userport_diag_586220_harness.c userport/userport_diag_586220_harness.c SAME +src/Emulators/vice/userport/userport_rtc_58321a.h userport/userport_rtc_58321a.h SAME +src/Emulators/vice/userport/userport_joystick.c userport/userport_joystick.c SAME +src/Emulators/vice/userport/userport_rtc_ds1307.h userport/userport_rtc_ds1307.h SAME +src/Emulators/vice/userport/userport_digimax.h userport/userport_digimax.h SAME +src/Emulators/vice/userport/userport_dac.h userport/userport_dac.h SAME +src/Emulators/vice/userport/userport_4bit_sampler.h userport/userport_4bit_sampler.h SAME +src/Emulators/vice/userport/userport_8bss.h userport/userport_8bss.h SAME +src/Emulators/vice/userport/userport_rtc_58321a.c userport/userport_rtc_58321a.c SAME +src/Emulators/vice/userport/userport_diag_586220_harness.h userport/userport_diag_586220_harness.h SAME +src/Emulators/vice/userport/userport.c userport/userport.c SAME +src/Emulators/vice/userport/userport_joystick.h userport/userport_joystick.h SAME +src/Emulators/vice/userport/userport_dac.c userport/userport_dac.c SAME +src/Emulators/vice/userport/userport_digimax.c userport/userport_digimax.c SAME +src/Emulators/vice/userport/userport_rtc_ds1307.c userport/userport_rtc_ds1307.c SAME +src/Emulators/vice/tapeport/sense-dongle.h tapeport/sense-dongle.h SAME +src/Emulators/vice/tapeport/cp-clockf83.h tapeport/cp-clockf83.h SAME +src/Emulators/vice/tapeport/tapelog.c tapeport/tapelog.c GONE +src/Emulators/vice/tapeport/tapeport.c tapeport/tapeport.c SAME +src/Emulators/vice/tapeport/tape_diag_586220_harness.c tapeport/tape_diag_586220_harness.c SAME +src/Emulators/vice/tapeport/dtl-basic-dongle.h tapeport/dtl-basic-dongle.h SAME +src/Emulators/vice/tapeport/sense-dongle.c tapeport/sense-dongle.c SAME +src/Emulators/vice/tapeport/tapelog.h tapeport/tapelog.h GONE +src/Emulators/vice/tapeport/cp-clockf83.c tapeport/cp-clockf83.c SAME +src/Emulators/vice/tapeport/tape_diag_586220_harness.h tapeport/tape_diag_586220_harness.h SAME +src/Emulators/vice/tapeport/tapeport.h tapeport/tapeport.h SAME +src/Emulators/vice/tapeport/dtl-basic-dongle.c tapeport/dtl-basic-dongle.c SAME +src/Emulators/vice/serial/serial-iec.c serial/serial-iec.c SAME +src/Emulators/vice/serial/fsdrive.c serial/fsdrive.c SAME +src/Emulators/vice/serial/serial-device.c serial/serial-device.c SAME +src/Emulators/vice/serial/serial.c serial/serial.c SAME +src/Emulators/vice/serial/serial-trap.h serial/serial-trap.h SAME +src/Emulators/vice/serial/serial-iec-device.h serial/serial-iec-device.h SAME +src/Emulators/vice/serial/serial-iec-bus.h serial/serial-iec-bus.h SAME +src/Emulators/vice/serial/serial-iec-lib.c serial/serial-iec-lib.c SAME +src/Emulators/vice/serial/serial-trap.c serial/serial-trap.c SAME +src/Emulators/vice/serial/fsdrive.h serial/fsdrive.h SAME +src/Emulators/vice/serial/serial-iec.h serial/serial-iec.h SAME +src/Emulators/vice/serial/serial-iec-bus.c serial/serial-iec-bus.c SAME +src/Emulators/vice/serial/serial-iec-device.c serial/serial-iec-device.c SAME +src/Emulators/vice/serial/realdevice.h serial/realdevice.h SAME +src/Emulators/vice/serial/serial-realdevice.c serial/serial-realdevice.c SAME diff --git a/docs/superpowers/plans/2026-05-27-vice-3.10-phase-2-step1-gating.md b/docs/superpowers/plans/2026-05-27-vice-3.10-phase-2-step1-gating.md new file mode 100644 index 00000000..095414ef --- /dev/null +++ b/docs/superpowers/plans/2026-05-27-vice-3.10-phase-2-step1-gating.md @@ -0,0 +1,335 @@ +# VICE 3.10 Upgrade — Phase 2 Step 1: RETRODEBUGGER gating + clean-additive hook conversion + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Introduce an `#ifdef RETRODEBUGGER`-gated macro layer (`vice_debugger_hook.h`) and route every clean-additive `c64d_*` hook call site through it, so the hook surface is centralized (trivial to replay onto VICE 3.10) and the hooks can be compiled out for a vanilla bisection build. + +**Architecture:** A single header defines `VICE_HOOK_*` macros. With `RETRODEBUGGER` defined (the normal RD build), each macro expands to the existing `c64d_*` call — behavior is provably unchanged. With it undefined, side-effect hooks become `((void)0)` and value-returning *observer* hooks expand to a documented neutral value. Call sites in the ~49 clean-additive files are converted to these macros. The ~15 hard files (CPU inline-expansion, non-additive, and functional insertions) are explicitly excluded and handled in a later step/phase. + +**Tech stack:** C/C++ (VICE source), CMake + Xcode (build wiring), the existing pytest WebSocket regression suite as the behavioral gate. + +**MR boundary:** This plan is one self-contained MR off `vice-3.10-phase-2`. It does NOT touch the excluded hard files and does NOT begin the vendor swap to 3.10. Stop when the final verification task passes. + +--- + +## Design + +### Gating model + +- A new define `RETRODEBUGGER` is added to the RD build (CMakeLists.txt `add_definitions`, and the macOS Xcode project / build). The normal app build always defines it. +- New header `src/Emulators/vice/vice_debugger_hook.h` defines all `VICE_HOOK_*` macros with two arms: + ```c + #ifdef RETRODEBUGGER + #define VICE_HOOK_C64_CELL_READ(addr) c64d_mark_c64_cell_read(addr) + #define VICE_HOOK_C64_CELL_WRITE(addr, val) c64d_mark_c64_cell_write((addr), (val)) + /* ... */ + #else + #define VICE_HOOK_C64_CELL_READ(addr) ((void)0) + #define VICE_HOOK_C64_CELL_WRITE(addr, val) ((void)0) + /* ... */ + #endif + ``` +- The `c64d_*` function bodies and their declarations in `ViceWrapper.h` (and other headers) are NOT moved or changed by this MR — only the *call sites* inside VICE source are rerouted through macros. + +### Three hook-call classes (the crux) + +Not every clean-additive `c64d_*` reference is a fire-and-forget side effect. Task 1 classifies every distinct call-site shape into exactly one of: + +1. **Side-effect hook** — `c64d_mark_*`, observer notifications, counter bumps used as standalone statements. Gate to `((void)0)` when off. Example: `c64d_mark_drive1541_cell_write(addr, value);` +2. **Value-returning OBSERVER hook** — returns a value the debugger computes but that does NOT alter emulation semantics, used in an expression. Gate to a documented neutral r-value when off (chosen per hook so the off-path matches vanilla VICE behavior). Example candidates: `c64d_colorram_peek(...)`, `c64d_*_peek_*`. +3. **Functional insertion** — a `c64d_*` call whose return value or side effect actually changes emulation (not pure observation). These are NOT debugger hooks; they must NOT be gated. Any file containing one is **promoted to the excluded set** and deferred. Example to scrutinize: `ciacore.c:1021` `value |= c64d_iecbus_cpu_peek_conf1()`. + +Also distinguish **`c64d_*` function DEFINITIONS** (e.g. `drive_context_t *c64d_get_drive_context(int)` in `drive.c`) — these are slajerek's accessor implementations called by ViceInterface, NOT injected call sites. They are left exactly as-is (not macro-ized) in this MR. + +### Excluded files (NOT touched in this MR) + +From the catalog's non-additive table (`docs/vice-hook-surface.md`), defer these 15: +`c64/c64cpusc.c`, `drive/drivecpu.c`, `sounddrv/soundsdl.c`, `resid/resid-filter.cpp`, `resid/resid-sid.cpp`, `c64/c64memsc.c`, `sid/sid.c`, `sid/sid-snapshot.c`, `root/vsync.c`, `root/keyboard.c`, `joyport/joystick.c`, `joyport/mouse.c`, `c64/c64-snapshot.c`, `viciisc/vicii-draw-cycle.c`, `viciisc/viciitypes.h`. + +PLUS any file Task 1 finds to contain a class-3 functional insertion. Task 1 produces the final authoritative include/exclude list before any conversion begins. + +### Naming convention + +`VICE_HOOK__` — areas mirror the catalog categories: `C64_CELL`, `DRIVE_CELL`, `DRIVE` (state), `CIA`, `VIA`, `VIC`, `SID`, `REU`, `CPU` (clock/step accounting that lives in clean files only — the inline-expansion clock hooks are excluded), `INPUT`, `LIFECYCLE`, `ROM`. Final macro list is fixed in Task 2 from Task 1's classification. + +### Verification protocol (the gate) + +- **Flag ON (the must-pass):** after every conversion commit, the macOS build compiles AND `tests/run-ws-tests.sh` reports the baseline `28 passed, 1 skipped, 1 xfailed` with 0 failures. Behavior must not change — the macros expand to the same `c64d_*` calls. +- **Flag OFF (syntactic viability):** the macro header and each converted file must remain *syntactically valid* with `RETRODEBUGGER` undefined (value-returning macros yield valid r-values). A full hook-free app/link is NOT a deliverable of this MR — only that the off-path compiles the converted translation units without syntax errors. Verified once in the final task via a targeted compile check, not per-commit. +- RetroDebugger must be running for the suite (see `tests/README.md`). + +### Commit cadence + +One commit per directory-batch of conversions (so a regression can be bisected to a small file set), each with the suite green. Build-wiring and the header are their own commits. + +--- + +## File structure + +``` +src/Emulators/vice/vice_debugger_hook.h [create] — the macro layer +CMakeLists.txt [modify] — add -DRETRODEBUGGER +platform/MacOS/c64d.xcodeproj/... [modify] — add RETRODEBUGGER define +docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md [create] — Task 1 output +src/Emulators/vice/**/ [modify] — call sites → macros +``` + +Converted directories (clean files only; excluded files above are skipped): `drive/` (minus drivecpu.c), `core/` (ciacore.c, viacore.c, flash040core.c — pending class-3 check), `iecbus/`, `viciisc/` (minus vicii-draw-cycle.c, viciitypes.h), `sid/` (minus sid.c, sid-snapshot.c), `resid-fp/`, `arch/`, `root/` (minus vsync.c, keyboard.c), `c64/` (minus c64cpusc.c, c64memsc.c, c64-snapshot.c), `monitor/`, `c64/cart/` (reu.c clean-additive portion). + +--- + +## Task 0 (PREREQUISITE): Establish a working from-source build of RetroDebugger + +**Why this is first:** The regression suite tests whatever RetroDebugger is *running* on port 3563. So far that has been the pre-installed `/Applications/Retro Debugger.app` (a release binary), NOT a build from this repo. To verify the gating conversion — and to catch compile errors the conversion may introduce — we must be able to build RD from this source tree, run that build, and have the suite pass against it. Without this, the conversion cannot be verified. This task also resolves the known MTEngineSDL path-mismatch pre-build blocker. + +**Files:** none committed by this task (build/config only); may require a CMakeLists or local path fix. + +- [ ] **Step 1: Locate the build inputs** + +```bash +ls -d /Users/garion/develop/MTEngineSDL /Users/garion/Projects/MTEngineSDL 2>/dev/null +cat /Users/garion/Projects/RetroDebugger/platform/MacOS/build.sh +ls /Users/garion/Projects/RetroDebugger/platform/MacOS/ +``` +The CMake/Xcode build expects `../MTEngineSDL` (→ `~/Projects/MTEngineSDL`) but it's at `~/develop/MTEngineSDL`. Resolve via a symlink (`ln -s ~/develop/MTEngineSDL ~/Projects/MTEngineSDL`) or by correcting the build's path — pick whichever the user prefers; do NOT commit a machine-specific absolute path into CMakeLists. + +- [ ] **Step 2: Build RetroDebugger from source (macOS)** + +Follow `platform/MacOS/build.sh` (or the Xcode project). Resolve dependency/config errors. This may be a yak-shave (SDL2, GTK3, MTEngineSDL must build first). If the build cannot be made to work, STOP and escalate to the user — the rest of this plan is blocked on it. + +- [ ] **Step 3: Run the freshly-built RD and point the suite at it** + +Kill the installed app, launch the from-source build, confirm port 3563, run `./tests/run-ws-tests.sh`. Expected: `28 passed, 1 skipped, 1 xfailed`. If the from-source build behaves differently from the release app, investigate — the suite baseline was captured against the release app and may need a one-time re-baseline against the from-source build (document any differences). + +- [ ] **Step 4: Record the build procedure** + +Note the exact working build + launch commands (and the MTEngineSDL path fix) in `tests/README.md` under a new "Building from source" section, so every later verification step can rebuild. Commit that doc change. + +```bash +git add tests/README.md +git commit -m "Phase 2 Step 1: document from-source build procedure (verification prerequisite)" +git push +``` + +**Gate:** a from-source RetroDebugger build runs and passes the regression suite. All later build/suite verification steps in this plan use this build, not the installed release app. + +--- + +## Task 1: Classify every clean-additive call site + +**Files:** +- Create: `docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md` + +- [ ] **Step 1: Enumerate candidate call sites (exclude the 15 hard files + c64d_ definitions)** + +```bash +cd /Users/garion/Projects/RetroDebugger +EXCLUDE='c64cpusc.c|drivecpu.c|soundsdl.c|resid-filter.cpp|resid-sid.cpp|c64memsc.c|/sid/sid.c|sid-snapshot.c|vsync.c|/keyboard.c|joystick.c|/mouse.c|c64-snapshot.c|vicii-draw-cycle.c|viciitypes.h' +grep -rEn '\bc64d_[a-zA-Z0-9_]+\b' src/Emulators/vice/ \ + | grep -v '/ViceInterface/' \ + | grep -vE "$EXCLUDE" \ + > /tmp/clean-callsites.txt +wc -l /tmp/clean-callsites.txt +``` + +- [ ] **Step 2: Separate definitions from call sites** + +A line is a DEFINITION if it matches a function-definition form (return type + `c64d_name(` + `)` with no trailing `;`, or is followed by `{`). Filter those out of the call-site set: + +```bash +grep -vE '^\S+:[0-9]+:\s*(void|int|unsigned|signed|char|float|double|BYTE|WORD|DWORD|disk_image_t|gcr_t|drive_context_t|static|extern)\b[^;]*c64d_[a-zA-Z0-9_]+\s*\(' /tmp/clean-callsites.txt > /tmp/clean-callsites-only.txt +wc -l /tmp/clean-callsites-only.txt +``` +Manually spot-check the result — the heuristic won't be perfect. Note definition-site files (like `drive/drive.c`'s `c64d_get_drive_*` block) so they're recorded as "definitions, leave as-is." + +- [ ] **Step 3: Classify each distinct call-site shape into class 1/2/3** + +For each distinct `c64d_*` symbol that appears as a CALL (not definition), determine its class: +- Read the call site(s) in context (the surrounding line). +- **Class 1 (side-effect):** standalone statement `c64d_x(...);` whose value is discarded. +- **Class 2 (value-returning observer):** appears as an r-value (`= c64d_x(...)`, `|= c64d_x(...)`, `c64d_x(...) &`, passed as arg) AND inspection of the `c64d_*` body (find it in the repo or `ViceWrapper`-adjacent source) shows it returns observed state without changing emulation. For each, decide the neutral off-value (the value that makes the off-path equal vanilla VICE — usually `0`, but justify per hook). +- **Class 3 (functional):** the call's effect/return alters emulation. Investigate `c64d_iecbus_cpu_peek_conf1()` (ciacore.c:1021) specifically — determine whether it injects real IEC bus state into the CIA read (functional) or merely observes. If functional, the containing file is excluded. + +- [ ] **Step 4: Write the classification document** + +Create `docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md` with: +- The final **include list** (clean-additive files to convert) and **exclude list** (15 hard files + any class-3 files found), each file with its directory. +- A **call-site shape → macro** table: distinct symbol, class (1/2/3), proposed `VICE_HOOK_*` macro name, the ON expansion (the exact `c64d_*` call), and the OFF expansion (`((void)0)` for class 1; the justified neutral r-value for class 2). +- A list of `c64d_*` **definition sites** to leave untouched. +- Any ambiguous cases flagged for human decision. + +- [ ] **Step 5: Commit** + +```bash +git add docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md +git commit -m "Phase 2 Step 1: classify clean-additive c64d_ call sites for gating" +git push +``` + +**Gate:** every clean-additive call site is classified; the include/exclude lists are final; class-3 files (if any) are moved to excluded with rationale. + +--- + +## Task 2: Create the macro header + wire RETRODEBUGGER into the build + +**Files:** +- Create: `src/Emulators/vice/vice_debugger_hook.h` +- Modify: `CMakeLists.txt` +- Modify: `platform/MacOS/c64d.xcodeproj/project.pbxproj` (or the macOS build script that sets preprocessor defines) + +- [ ] **Step 1: Author `vice_debugger_hook.h`** + +Using Task 1's classification table, write the header. Structure: +```c +#ifndef VICE_DEBUGGER_HOOK_H +#define VICE_DEBUGGER_HOOK_H + +/* Declarations of the c64d_* hook functions are provided by ViceWrapper.h / + * the per-subsystem headers; this file only routes call sites through macros. + * With RETRODEBUGGER defined, macros expand to the real hook calls (normal RD + * build, behavior unchanged). Undefined, side-effect hooks no-op and + * value-returning observer hooks expand to documented neutral values. */ + +#ifdef RETRODEBUGGER + #define VICE_HOOK_C64_CELL_READ(addr) c64d_mark_c64_cell_read(addr) + /* ... all class-1 and class-2 macros, ON arm, from Task 1 ... */ +#else + #define VICE_HOOK_C64_CELL_READ(addr) ((void)0) + /* ... class-1 -> ((void)0); class-2 -> neutral r-value ... */ +#endif + +#endif /* VICE_DEBUGGER_HOOK_H */ +``` +Include the exact macros enumerated in Task 1. Do not invent macros for symbols not in the classification. + +- [ ] **Step 2: Add the build define (CMake)** + +In `CMakeLists.txt`, add `-DRETRODEBUGGER` to the existing `add_definitions(...)` block (alongside `-DLINUX`): +```cmake +add_definitions( + -DLINUX + -DRETRODEBUGGER + -DIMGUI_IMPL_OPENGL_LOADER_GL3W + -DENABLE_IMGUI_TEST_ENGINE +) +``` + +- [ ] **Step 3: Add the build define (macOS)** + +The user's primary build is macOS via `platform/MacOS`. Add `RETRODEBUGGER` to `GCC_PREPROCESSOR_DEFINITIONS` in the Xcode project (`c64d.xcodeproj/project.pbxproj`) for all build configurations, OR to whatever define list `platform/MacOS/build.sh` passes. Inspect the build setup first to find the right insertion point; mirror how an existing define (e.g. the platform macro) is set. + +- [ ] **Step 4: Verify the macOS build still compiles with the header present (no call sites converted yet)** + +Build via the macOS flow. The header exists but is not yet `#include`d anywhere, so this only proves it doesn't break the build and `RETRODEBUGGER` is accepted. If a full build is slow, at minimum confirm the define is in the compile commands. + +- [ ] **Step 5: Run the regression suite (must be green — nothing changed behaviorally yet)** + +```bash +./tests/run-ws-tests.sh +``` +Expected: `28 passed, 1 skipped, 1 xfailed`. + +- [ ] **Step 6: Commit** + +```bash +git add src/Emulators/vice/vice_debugger_hook.h CMakeLists.txt platform/MacOS/ +git commit -m "Phase 2 Step 1: add vice_debugger_hook.h + wire RETRODEBUGGER build define" +git push +``` + +**Gate:** macOS build compiles with `RETRODEBUGGER` defined; suite green. + +--- + +## Tasks 3–N: Convert clean-additive call sites, one directory-batch per task + +Each conversion task follows the SAME procedure (repeated here in full so tasks are self-contained). Do them in this order (lowest-risk, highest-volume first): `drive/` → `iecbus/` → `core/` → `viciisc/` → `sid/` → `resid-fp/` → `arch/` → `root/` → `c64/` (+ `c64/cart/`) → `monitor/`. Skip every excluded file. + +For each directory batch: + +- [ ] **Step 1: Add the include** + +In each file to be converted in this directory, add `#include "vice_debugger_hook.h"` near the existing VICE includes (after `vicetypes.h`). Verify the include path resolves (the header is at `src/Emulators/vice/vice_debugger_hook.h`; confirm the directory is on the VICE include path — it should be, as sibling headers resolve). + +- [ ] **Step 2: Replace call sites with macros** + +For every classified call site in this directory's clean files, replace the `c64d_*` call with its `VICE_HOOK_*` macro per Task 1's table. Class 1: `c64d_x(a);` → `VICE_HOOK_X(a);`. Class 2: `v = c64d_x(a);` → `v = VICE_HOOK_X(a);`. Leave `c64d_*` definition lines untouched. Do NOT touch excluded files even if they live in this directory. + +- [ ] **Step 3: Build (macOS)** + +Compile. Fix any macro arity / type mismatches (the macro args must match the original call exactly). + +- [ ] **Step 4: Run the regression suite** + +```bash +./tests/run-ws-tests.sh +``` +Expected: `28 passed, 1 skipped, 1 xfailed`, 0 failures. If any test newly fails, the conversion changed behavior — diff against the prior commit, find the macro that doesn't expand to the original call, fix it. Do NOT proceed with a red suite. + +- [ ] **Step 5: Commit** + +```bash +git add src/Emulators/vice// +git commit -m "Phase 2 Step 1: route clean-additive hooks through VICE_HOOK_* macros" +git push +``` + +**Per-task gate:** directory's clean files converted; build compiles; suite green. + +> The implementer creates one task per directory in the order above, using Task 1's classification table for the exact per-symbol macro. If a directory has no clean-additive call sites (only definitions or only excluded files), skip it and note so. + +--- + +## Final Task: Whole-surface verification + flag-off sanity + MR summary + +**Files:** +- Modify: `docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md` (append completion summary) + +- [ ] **Step 1: Confirm no clean-additive call sites remain unconverted** + +```bash +cd /Users/garion/Projects/RetroDebugger +EXCLUDE='c64cpusc.c|drivecpu.c|soundsdl.c|resid-filter.cpp|resid-sid.cpp|c64memsc.c|/sid/sid.c|sid-snapshot.c|vsync.c|/keyboard.c|joystick.c|/mouse.c|c64-snapshot.c|vicii-draw-cycle.c|viciitypes.h' +# Remaining c64d_ CALL sites (not definitions) in clean files should now be ~0 +grep -rEn '\bc64d_[a-zA-Z0-9_]+\s*\(' src/Emulators/vice/ \ + | grep -v '/ViceInterface/' | grep -vE "$EXCLUDE" \ + | grep -vE '(void|int|unsigned|signed|char|float|double|BYTE|WORD|DWORD|disk_image_t|gcr_t|drive_context_t|static|extern)\b[^;]*c64d_' \ + | grep -v 'VICE_HOOK_' || echo "none remaining" +``` +Any remaining hits are either definitions (fine) or missed call sites (convert them). Document the result. + +- [ ] **Step 2: Full build + suite (flag ON)** + +macOS build clean; `./tests/run-ws-tests.sh` → `28 passed, 1 skipped, 1 xfailed`. Run it 3× to confirm stability. + +- [ ] **Step 3: Flag-OFF syntactic sanity** + +Verify the macro header and converted files compile with `RETRODEBUGGER` undefined. Targeted check (don't need a full hook-free app): compile a few representative converted translation units with the define removed, OR add a tiny throwaway compile test that includes the header without `RETRODEBUGGER` and references each value-returning macro to confirm it yields a valid r-value. Confirm no syntax errors. Document that a full hook-free app/link is out of scope for this MR. + +- [ ] **Step 4: Append completion summary to the classification doc** + +Record: number of files converted, number of call sites converted, any class-3 files that ended up excluded, flag-off check result, final suite status. + +- [ ] **Step 5: Commit + open MR readiness** + +```bash +git add docs/superpowers/notes/2026-05-27-phase-2-step1-callsite-classification.md +git commit -m "Phase 2 Step 1: verification summary (gating + clean-additive conversion complete)" +git push +``` + +**Gate (MR-ready):** all clean-additive call sites routed through gated macros; flag-on suite green and stable; flag-off compiles; excluded files untouched and documented. STOP here — this is the boundary of the Step 1 MR. + +--- + +## Acceptance check + +- [ ] `vice_debugger_hook.h` exists with macros for every class-1/class-2 symbol from Task 1 +- [ ] `RETRODEBUGGER` defined in CMakeLists.txt and the macOS build +- [ ] All ~49 clean-additive files route hooks through `VICE_HOOK_*` (verified by the Step 1 grep above) +- [ ] The 15 hard files + any class-3 files are untouched +- [ ] Flag-ON: macOS builds, suite green (`28 passed, 1 skipped, 1 xfailed`), stable across 3 runs +- [ ] Flag-OFF: converted files + header compile without syntax errors +- [ ] Classification + completion docs committed + +After this MR merges, the next step (separate plan) handles the excluded hard files (CPU inline-expansion, non-additive patches) and then the Phase 3 vendor swap to VICE 3.10. diff --git a/docs/superpowers/plans/2026-05-27-vice-3.10-upgrade-phases-0-1.md b/docs/superpowers/plans/2026-05-27-vice-3.10-upgrade-phases-0-1.md new file mode 100644 index 00000000..7055a3f6 --- /dev/null +++ b/docs/superpowers/plans/2026-05-27-vice-3.10-upgrade-phases-0-1.md @@ -0,0 +1,1681 @@ +# VICE 3.10 Upgrade — Phases 0–1 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Lay the foundation for the VICE 3.1 → 3.10 upgrade: create the upgrade branch, fetch upstream reference sources, build a WebSocket regression test harness (the gating signal for every later phase), and produce a complete catalog of slajerek's in-tree `c64d_*` hooks. + +**Architecture:** Three sub-phases of the larger upgrade described in [the design spec](../specs/2026-05-27-vice-3.10-upgrade-design.md): +- **Phase 0** — Setup and baselining. Branch, reference sources, baseline diff, MTEngineSDL survey. +- **Phase 0.5** — WebSocket regression harness. pytest suite + fixture PRG, must run green against current 3.1. +- **Phase 1** — Hook catalog. Read every modified VICE file, document each `c64d_*` symbol and its consumer. + +**Scope split:** This plan covers Phases 0, 0.5, and 1 only. Phases 2–5 (hook refactor, vendor swap, integration, validation) get their own plan written *after* Phase 1's catalog completes, since their tasks depend on what the catalog reveals. + +**Tech stack:** Bash, git, Python 3, pytest, KickAssembler (cross-compile to 6502), existing `retrodebugger.py` WebSocket client. + +--- + +## File structure + +This plan creates or modifies: + +``` +docs/superpowers/notes/ + 2026-05-27-phase-0-baseline.md [create] — Phase 0 findings +docs/ + vice-hook-surface.md [create] — Phase 1 catalog output +tests/ + retrodebugger.py [create — vendored from riscv-c64-2] + requirements.txt [create] + pytest.ini [create] + conftest.py [create] — pytest fixtures + websocket/__init__.py [create] + websocket/test_lifecycle.py [create] + websocket/test_cpu.py [create] + websocket/test_memory.py [create] + websocket/test_breakpoints.py [create] + websocket/test_chips.py [create] + websocket/test_input.py [create] + websocket/test_load.py [create] + fixtures/known_state.asm [create] — KickAssembler source + fixtures/known_state.prg [create — built from .asm] + fixtures/build.sh [create] — fixture rebuild script + run-ws-tests.sh [create] — convenience runner +``` + +Nothing under `src/Emulators/vice/` is touched in this plan. That happens in the followup plan (Phases 2–5). + +--- + +## Phase 0 — Setup & baselining + +### Task 1: Create the upgrade feature branch + +**Files:** none (git operation) + +- [ ] **Step 1: Verify clean working tree on master** + +Run: `git status && git log --oneline -1` +Expected: working tree clean, currently on `master`, HEAD is the design-doc commit `2527412`. + +- [ ] **Step 2: Create and switch to the upgrade branch** + +Run: `git checkout -b vice-3.10-upgrade` +Expected: `Switched to a new branch 'vice-3.10-upgrade'`. + +- [ ] **Step 3: Push the branch to set tracking** + +Run: `git push -u origin vice-3.10-upgrade` +Expected: branch created on origin, tracking set up. Future pushes go to `origin/vice-3.10-upgrade`. + +--- + +### Task 2: Acquire vanilla VICE 3.1 reference source + +**Files:** +- Create directory: `~/vice-ref/3.1/` + +The reference source lives outside the repo on purpose — it's a comparison artifact, not source we ship. + +- [ ] **Step 1: Create reference directory** + +Run: `mkdir -p ~/vice-ref/3.1 && cd ~/vice-ref/3.1` + +- [ ] **Step 2: Download VICE 3.1 release tarball** + +VICE 3.1 is published on SourceForge. The canonical release tarball is `vice-3.1.tar.gz`. Locate the current direct URL from `https://sourceforge.net/projects/vice-emu/files/releases/` (browse to `3.1/` and copy the download link). Then: + +```bash +cd ~/vice-ref/3.1 +curl -L -o vice-3.1.tar.gz "" +ls -l vice-3.1.tar.gz +``` + +Expected: tarball downloaded, ~10-15 MB. + +If the URL fails, search VICE's official site at `https://vice-emu.sourceforge.io/` for the 3.1 archive download. + +- [ ] **Step 3: Extract and verify version** + +```bash +cd ~/vice-ref/3.1 +tar xzf vice-3.1.tar.gz +ls vice-3.1/ +grep -r '^#define VERSION ' vice-3.1/src/version.h 2>/dev/null || \ + grep -r '^#define VERSION ' vice-3.1/ 2>/dev/null | head -3 +``` + +Expected: a `vice-3.1/` directory with `src/`, `configure.ac`, `README`. Version string in `version.h` reads `"3.1"`. + +- [ ] **Step 4: Move source into place** + +```bash +mv ~/vice-ref/3.1/vice-3.1/src ~/vice-ref/3.1/src +ls ~/vice-ref/3.1/src/ | head -20 +``` + +Expected: directories matching `src/Emulators/vice/` in our repo: `c64/`, `drive/`, `monitor/`, `core/`, etc. + +--- + +### Task 3: Acquire vanilla VICE 3.10 reference source + +**Files:** +- Create directory: `~/vice-ref/3.10/` + +- [ ] **Step 1: Create reference directory** + +Run: `mkdir -p ~/vice-ref/3.10 && cd ~/vice-ref/3.10` + +- [ ] **Step 2: Download VICE 3.10 release tarball** + +VICE 3.10 should also be on SourceForge releases at `https://sourceforge.net/projects/vice-emu/files/releases/3.10/`. Pull the source tarball (typically `vice-3.10.tar.gz`). + +```bash +cd ~/vice-ref/3.10 +curl -L -o vice-3.10.tar.gz "" +ls -l vice-3.10.tar.gz +``` + +Expected: tarball downloaded. + +If 3.10 is not on SourceForge (VICE may have migrated hosts post-3.1), check `https://vice-emu.sourceforge.io/` for the current canonical download location. As a fallback, the VICE git repository (often at `https://github.com/VICE-Team/svn-mirror` or similar) has tagged releases — locate the tag `v3.10` or `r3.10` and download the tarball from there. + +- [ ] **Step 3: Extract and verify version** + +```bash +cd ~/vice-ref/3.10 +tar xzf vice-3.10.tar.gz +ls vice-3.10/ +find vice-3.10/ -name version.h | head -3 +grep '^#define VERSION ' $(find vice-3.10/ -name version.h | head -1) +``` + +Expected: extracted directory, version string `"3.10"`. + +- [ ] **Step 4: Move source into place** + +```bash +mv ~/vice-ref/3.10/vice-3.10/src ~/vice-ref/3.10/src +ls ~/vice-ref/3.10/src/ | head -20 +``` + +Expected: subsystems present. Note any new subdirs that didn't exist in 3.1 (jot down for later). + +--- + +### Task 4: Generate baseline diff & sanity report + +**Files:** +- Create: `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` + +We need to know exactly what slajerek changed vs upstream 3.1, so Phase 1 has a focused worklist and Phase 2 has a clear refactor target. + +- [ ] **Step 1: Generate raw diff** + +```bash +cd /Users/garion/Projects/RetroDebugger +diff -ruN ~/vice-ref/3.1/src/ src/Emulators/vice/ > /tmp/slajerek-vs-vanilla-3.1.diff +wc -l /tmp/slajerek-vs-vanilla-3.1.diff +ls -l /tmp/slajerek-vs-vanilla-3.1.diff +``` + +Expected: diff file produced. Size will be substantial — tens of thousands of lines is normal because slajerek's tree has different file layouts (`root/` extra dir, `arch/` rearranged, `ViceInterface/` is new). The size itself is not interesting; the breakdown is. + +- [ ] **Step 2: Categorize the diff into 3 buckets** + +```bash +# Files only in slajerek's tree (additions — e.g., ViceInterface/) +grep '^Only in src/Emulators/vice' /tmp/slajerek-vs-vanilla-3.1.diff | head -40 > /tmp/diff-slajerek-only.txt +wc -l /tmp/diff-slajerek-only.txt + +# Files only in vanilla 3.1 (slajerek deletions or moves) +grep '^Only in /Users/garion/vice-ref/3.1' /tmp/slajerek-vs-vanilla-3.1.diff | head -40 > /tmp/diff-vanilla-only.txt +wc -l /tmp/diff-vanilla-only.txt + +# Files present in both but different (the real modification set) +grep '^diff -ruN' /tmp/slajerek-vs-vanilla-3.1.diff > /tmp/diff-modified-files.txt +wc -l /tmp/diff-modified-files.txt +``` + +Expected: three categorization files. The third (`diff-modified-files.txt`) should be ~80–150 lines depending on how slajerek rearranged things; this is the set we'll patch-replay in Phase 4. + +- [ ] **Step 3: Cross-check against the c64d_ modified-file count** + +```bash +# Files with c64d_ markers (the hook injection set from our spec analysis) +grep -rln -E "C64DEBUGGER|c64d|RetroDebugger|RETRO_DEBUGGER" \ + src/Emulators/vice/c64/ src/Emulators/vice/drive/ \ + src/Emulators/vice/monitor/ src/Emulators/vice/core/ \ + src/Emulators/vice/root/ src/Emulators/vice/arch/ \ + src/Emulators/vice/viciisc/ 2>/dev/null | sort -u > /tmp/files-with-c64d.txt +wc -l /tmp/files-with-c64d.txt +``` + +Expected: ~96 files (matches Section 2 of the spec). Compare to `diff-modified-files.txt` — every file with `c64d_` markers should also appear in modified-files. + +- [ ] **Step 4: Spot-check three modified files for non-additive patches** + +The Phase 1 catalog needs to know which patches are pure additions vs which alter VICE control flow. Sample three files to see what we're dealing with. + +```bash +for f in src/Emulators/vice/c64/cart/reu.c src/Emulators/vice/drive/drive.c src/Emulators/vice/monitor/monitor.c; do + vanilla="$HOME/vice-ref/3.1/${f#src/Emulators/vice/}" + if [ -f "$vanilla" ]; then + echo "=== $f ===" + diff -u "$vanilla" "$f" | head -80 + echo "(diff size: $(diff -u "$vanilla" "$f" | wc -l) lines)" + echo "" + fi +done +``` + +Expected: see the actual nature of slajerek's modifications. Note whether the diff hunks are exclusively `+` lines (pure additions) or also include `-` lines (deletions / control-flow changes). + +- [ ] **Step 5: Write up Phase 0 findings** + +Create `docs/superpowers/notes/2026-05-27-phase-0-baseline.md`: + +```markdown +# Phase 0 — VICE 3.10 upgrade baseline findings + +**Date:** 2026-05-27 +**Branch:** vice-3.10-upgrade + +## Reference sources acquired + +- Vanilla VICE 3.1: `~/vice-ref/3.1/src/` (downloaded from ) +- Vanilla VICE 3.10: `~/vice-ref/3.10/src/` (downloaded from ) + +## Baseline diff summary + +Diff command: `diff -ruN ~/vice-ref/3.1/src/ src/Emulators/vice/` +Diff size: lines + +Breakdown: +- Files only in slajerek's tree: (mostly `ViceInterface/`, `root/`) +- Files only in vanilla 3.1: (deletions / restructured directories) +- Files present in both but different: +- Files with `c64d_` markers (hook injections): 96 + +## Spot-check of modification style + +[Paste/summarize the three diffs from Step 4. Note: are most modifications +pure additions (just `+` lines), or do they include deletions / control-flow +changes (`-` lines too)? This determines Phase 2's macro design.] + +## MTEngineSDL coupling + +[Filled in by Task 5.] + +## Known surprises / open issues + +- [Anything weird discovered during the diff — file moves, encoding issues, + trailing-whitespace noise polluting the diff, etc.] + +## Followup decisions for Phase 1 + +- [Things the Phase 1 catalog must resolve based on what was discovered here.] +``` + +Fill in the `` placeholders with real numbers from Steps 1–3, and the spot-check from Step 4. + +- [ ] **Step 6: Commit Phase 0 baseline findings** + +```bash +git add docs/superpowers/notes/2026-05-27-phase-0-baseline.md +git commit -m "Phase 0: VICE upgrade baseline findings + +Document vanilla 3.1 + 3.10 reference acquisition, diff size, +and modification-style spot-check used to inform Phase 1. +" +``` + +--- + +### Task 5: Survey MTEngineSDL for VICE coupling + +**Files:** +- Modify: `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` (fill in MTEngineSDL section) + +`MTEngineSDL` is the sibling library RetroDebugger depends on (referenced as `../MTEngineSDL` in CMakeLists). If it has assumptions about VICE 3.1 internals, those break too. + +- [ ] **Step 1: Locate MTEngineSDL** + +```bash +ls ../MTEngineSDL 2>/dev/null || ls ~/develop/MTEngineSDL 2>/dev/null || \ + find ~ -maxdepth 4 -type d -name MTEngineSDL 2>/dev/null +``` + +Expected: MTEngineSDL directory located. If not found, this becomes an open issue to resolve before Phase 4 (the build will fail without it). + +- [ ] **Step 2: Search for VICE references in MTEngineSDL** + +```bash +MTEDIR= +grep -rln -iE "vice|c64d_|VICII|maincpu|drive.*1541" "$MTEDIR" 2>/dev/null | head -30 +``` + +Expected: list of files in MTEngineSDL that mention VICE internals. + +- [ ] **Step 3: Update Phase 0 findings doc** + +Open `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` and fill in the "MTEngineSDL coupling" section: + +```markdown +## MTEngineSDL coupling + +- MTEngineSDL location: +- Files referencing VICE internals: +- Categories: + - files: hand audio/SID glue + - files: video glue (VIC-II) + - files: +- Concrete VICE symbols MTEngineSDL touches: [list specific symbols, e.g. + `maincpu_clk`, `vicii_palette`, etc.] +- Risk assessment: [Low / Medium / High] — explain why +``` + +- [ ] **Step 4: Amend the Phase 0 commit** + +```bash +git add docs/superpowers/notes/2026-05-27-phase-0-baseline.md +git commit --amend --no-edit +``` + +(`--amend` is acceptable here because the commit was just made locally in Task 4 and has not been pushed yet. Do not push --force; only push after the amend.) + +```bash +git push -u origin vice-3.10-upgrade +``` + +--- + +## Phase 0.5 — WebSocket regression test harness + +The harness is the gating signal for every later phase. Built on the existing `retrodebugger.py` client (vendored from `~/Projects/riscv-c64-2/tests/`) and pytest. + +**Prerequisites before starting any Phase 0.5 task:** +- RetroDebugger must be running with the WebSocket server enabled. Steps: + 1. Confirm `~/Library/RetroDebugger/settings.hjson` has `RunDebuggerServerWebSockets: true` + 2. Launch: `"/Applications/Retro Debugger.app/Contents/MacOS/Retro Debugger" -c64 -unpause &` + 3. Wait ~6 seconds for port `:3563` to bind + 4. Verify: `nc -z 127.0.0.1 3563 && echo READY` +- `kickass` must be on PATH (verify: `kickass --help | head -3`) +- Python 3 with `pip` available + +--- + +### Task 6: Pytest infrastructure + +**Files:** +- Create: `tests/requirements.txt` +- Create: `tests/pytest.ini` +- Create: `tests/websocket/__init__.py` +- Create: `tests/fixtures/.gitkeep` + +- [ ] **Step 1: Create tests directory layout** + +```bash +mkdir -p tests/websocket tests/fixtures +touch tests/websocket/__init__.py tests/fixtures/.gitkeep +``` + +- [ ] **Step 2: Write requirements file** + +Create `tests/requirements.txt`: + +``` +pytest>=7.0 +websockets>=11.0 +``` + +- [ ] **Step 3: Write pytest configuration** + +Create `tests/pytest.ini`: + +```ini +[pytest] +testpaths = websocket +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = -v --tb=short --strict-markers +markers = + slow: tests that take more than 1s wall clock +``` + +- [ ] **Step 4: Install dependencies in a virtual env** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +python3 -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +pip list | grep -E "pytest|websockets" +``` + +Expected: pytest and websockets installed and listed. + +- [ ] **Step 5: Verify pytest discovers no tests yet (smoke)** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest --collect-only +``` + +Expected: "no tests ran", exits 5. (Exit code 5 = no tests collected; this is fine before we write any.) + +- [ ] **Step 6: Commit infrastructure** + +```bash +git add tests/requirements.txt tests/pytest.ini tests/websocket/__init__.py tests/fixtures/.gitkeep +echo ".venv/" >> tests/.gitignore +git add tests/.gitignore +git commit -m "Phase 0.5: pytest infrastructure for WebSocket regression suite" +``` + +--- + +### Task 7: Vendor `retrodebugger.py` and write conftest + +**Files:** +- Create: `tests/retrodebugger.py` (vendored from `~/Projects/riscv-c64-2/tests/retrodebugger.py`) +- Create: `tests/conftest.py` + +- [ ] **Step 1: Vendor the client** + +```bash +cp ~/Projects/riscv-c64-2/tests/retrodebugger.py tests/retrodebugger.py +wc -l tests/retrodebugger.py +``` + +Expected: ~185 lines copied. + +- [ ] **Step 2: Write the conftest fixtures** + +Create `tests/conftest.py`: + +```python +"""Shared pytest fixtures for the RetroDebugger WebSocket regression suite. + +Assumes a RetroDebugger instance is running with the WebSocket server enabled +on ws://127.0.0.1:3563/stream. See plan's Phase 0.5 prerequisites. +""" + +import sys +import time +from pathlib import Path + +import pytest + +# Make `tests/retrodebugger.py` importable from `tests/websocket/test_*.py`. +sys.path.insert(0, str(Path(__file__).parent)) +from retrodebugger import RetroDebugger # noqa: E402 + +FIXTURE_DIR = Path(__file__).parent / "fixtures" + + +@pytest.fixture(scope="session") +def rd(): + """One WebSocket connection shared across the session.""" + client = RetroDebugger() + yield client + client.close() + + +@pytest.fixture +def fresh_cpu(rd): + """Hard-reset before each test; settle KERNAL.""" + rd.reset(hard=True) + time.sleep(0.5) + return rd + + +@pytest.fixture +def loaded_fixture(fresh_cpu): + """Reset, load known_state.prg, jump to $0810, run briefly, pause at park loop.""" + rd = fresh_cpu + rd.call("load", {"path": str(FIXTURE_DIR / "known_state.prg")}) + time.sleep(0.2) + rd.call(f"{rd.platform}/cpu/makejmp", {"address": 0x0810}) + rd.cont() + time.sleep(0.05) + rd.pause() + return rd +``` + +- [ ] **Step 3: Sanity-check the fixture loads (no tests yet)** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +python -c "from retrodebugger import RetroDebugger; rd = RetroDebugger(); print(rd.cpu_status()); rd.close()" +``` + +Expected: dict with at least `result.pc`, `status: 200`. If this fails, RetroDebugger is not running or the WebSocket server is not enabled — fix before proceeding. + +- [ ] **Step 4: Commit client + conftest** + +```bash +git add tests/retrodebugger.py tests/conftest.py +git commit -m "Phase 0.5: vendor retrodebugger.py client and write pytest conftest" +``` + +--- + +### Task 8: Build the fixture PRG + +**Files:** +- Create: `tests/fixtures/known_state.asm` +- Create: `tests/fixtures/build.sh` +- Create: `tests/fixtures/known_state.prg` (built artifact) + +The fixture is a tiny 6502 program that establishes a known machine state. Tests load it, jump to its entry point, let it run, then assert specific memory contents. + +- [ ] **Step 1: Write KickAssembler source** + +Create `tests/fixtures/known_state.asm`: + +```asm +// known_state.asm — RetroDebugger WebSocket regression-suite fixture. +// +// Loaded via the `load` endpoint at $0801 (BASIC SYS line). +// Entry point at $0810 via `makejmp`. +// +// Post-run state (after letting it reach `park`): +// $C000 = $AA +// $C001 = $BB +// $C002 = $CC +// $C003 = $DD +// $0400-$07E7 cleared to $20 (space char) — screen RAM +// PC parked in the infinite loop at label `park` +// +// Build: kickass known_state.asm -o known_state.prg + +*=$0801 "BASIC Upstart" +BasicUpstart2(start) + +*=$0810 "Code" +start: + // Clear visible screen RAM ($0400-$07FF) to space + lda #$20 + ldx #$00 +clear_loop: + sta $0400, x + sta $0500, x + sta $0600, x + sta $0700, x + inx + bne clear_loop + + // Write known sentinel bytes to $C000-$C003 + lda #$AA + sta $C000 + lda #$BB + sta $C001 + lda #$CC + sta $C002 + lda #$DD + sta $C003 + +park: + jmp park +``` + +- [ ] **Step 2: Write build script** + +Create `tests/fixtures/build.sh`: + +```bash +#!/bin/sh +# Rebuild known_state.prg from known_state.asm using KickAssembler. +set -eu +cd "$(dirname "$0")" +kickass known_state.asm -o known_state.prg +echo "Built: $(pwd)/known_state.prg ($(wc -c < known_state.prg) bytes)" +``` + +```bash +chmod +x tests/fixtures/build.sh +``` + +- [ ] **Step 3: Build the fixture** + +```bash +tests/fixtures/build.sh +ls -l tests/fixtures/known_state.prg +``` + +Expected: a tiny .prg file (~50-80 bytes). KickAssembler will also emit a `.sym` / `.dbg` log; ignore those, or add `-vicesymbols` only if needed later. + +- [ ] **Step 4: Verify the fixture loads & runs against RetroDebugger** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +python << 'PY' +import time +from retrodebugger import RetroDebugger +rd = RetroDebugger() +rd.reset(hard=True); time.sleep(0.5) +rd.call("load", {"path": "fixtures/known_state.prg"}) +time.sleep(0.2) +rd.call(f"{rd.platform}/cpu/makejmp", {"address": 0x0810}) +rd.cont(); time.sleep(0.05); rd.pause() +print("$C000:$C003 =", rd.read_memory(0xC000, 4).hex()) +status = rd.cpu_status() +print("PC =", hex(status["result"]["pc"])) +rd.close() +PY +``` + +Expected: +- `$C000:$C003 = aabbccdd` +- `PC` is at or near the `park` label (some address in $0820–$0840 range — confirm what kickass placed it at by checking the `.sym` file or reading the listing). + +If sentinel bytes are not `aabbccdd`, the fixture didn't execute. Most likely cause: wrong `makejmp` address — check the .sym output. + +- [ ] **Step 5: Capture the park address for use in tests** + +```bash +grep -i 'park' tests/fixtures/known_state.sym 2>/dev/null || \ + cat tests/fixtures/known_state.sym 2>/dev/null +``` + +Expected: a line giving `park = $xxxx`. Remember this for tests that assert PC values. If kickass doesn't emit a `.sym` file by default, add `-symbolfile` to `build.sh`. + +If easier: hard-code `EXPECTED_PARK_ADDR = 0x0820` (approximate — verify with the actual build) into `conftest.py` as a constant. + +- [ ] **Step 6: Commit fixture** + +```bash +git add tests/fixtures/known_state.asm tests/fixtures/build.sh tests/fixtures/known_state.prg +# Optionally add tests/fixtures/known_state.sym if it's useful for debugging +git commit -m "Phase 0.5: add known_state.prg fixture for regression suite" +``` + +--- + +### Task 9: Lifecycle tests + +**Files:** +- Create: `tests/websocket/test_lifecycle.py` + +- [ ] **Step 1: Write lifecycle tests** + +Create `tests/websocket/test_lifecycle.py`: + +```python +"""Lifecycle endpoint tests: reset, pause, continue, warp.""" + +import time + + +def test_hard_reset_returns_to_kernal(fresh_cpu): + """After hard reset, KERNAL is running — PC should be in the $E000-$FFFF range.""" + status = fresh_cpu.cpu_status()["result"] + pc = status["pc"] + assert 0xE000 <= pc <= 0xFFFF, f"PC after reset = {pc:#06x}, expected KERNAL range" + + +def test_pause_then_continue_changes_running_state(fresh_cpu): + """Cycle counter should be ~static while paused, advancing after continue.""" + rd = fresh_cpu + rd.pause() + time.sleep(0.05) + c1 = rd.cpu_counters()["result"]["cycle"] + time.sleep(0.05) + c2 = rd.cpu_counters()["result"]["cycle"] + # Paused -> cycle should not advance (or advance only minimally from internal ticks) + delta_paused = c2 - c1 + assert delta_paused < 1000, f"Cycles advanced {delta_paused} while paused" + + rd.cont() + time.sleep(0.05) + c3 = rd.cpu_counters()["result"]["cycle"] + delta_running = c3 - c2 + assert delta_running > 10000, f"Cycles advanced only {delta_running} while running" + + +def test_warp_on_increases_cycle_rate(fresh_cpu): + """Enabling warp should measurably increase the cycle rate over wall time.""" + rd = fresh_cpu + + # Baseline rate without warp + rd.call(f"{rd.platform}/warp/set", {"warp": False}) + rd.cont() + c_start = rd.cpu_counters()["result"]["cycle"] + time.sleep(0.5) + c_end = rd.cpu_counters()["result"]["cycle"] + rd.pause() + rate_normal = (c_end - c_start) / 0.5 + + # Warp rate + rd.call(f"{rd.platform}/warp/set", {"warp": True}) + rd.cont() + c_start = rd.cpu_counters()["result"]["cycle"] + time.sleep(0.5) + c_end = rd.cpu_counters()["result"]["cycle"] + rd.pause() + rate_warp = (c_end - c_start) / 0.5 + + # Clean up + rd.call(f"{rd.platform}/warp/set", {"warp": False}) + + # Expect at least 1.5x — generous because warp ratio on macOS varies + assert rate_warp > rate_normal * 1.5, \ + f"Warp rate {rate_warp:.0f} not >> normal rate {rate_normal:.0f}" + + +def test_soft_reset_does_not_crash(fresh_cpu): + """Soft reset should succeed and CPU should be in KERNAL after.""" + fresh_cpu.reset(hard=False) + time.sleep(0.5) + status = fresh_cpu.cpu_status()["result"] + pc = status["pc"] + assert 0xE000 <= pc <= 0xFFFF, f"PC after soft reset = {pc:#06x}, not in KERNAL" +``` + +- [ ] **Step 2: Run lifecycle tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_lifecycle.py -v +``` + +Expected: all 4 tests pass. If `test_warp_on_increases_cycle_rate` fails because warp rate is only barely above normal on your machine, adjust the multiplier — but if the ratio is suspiciously small (< 1.2x) that's a real bug to investigate, not a test-tweak. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_lifecycle.py +git commit -m "Phase 0.5: lifecycle endpoint tests (reset, pause, continue, warp)" +``` + +--- + +### Task 10: CPU tests (status, counters, control) + +**Files:** +- Create: `tests/websocket/test_cpu.py` + +- [ ] **Step 1: Write CPU tests** + +Create `tests/websocket/test_cpu.py`: + +```python +"""CPU endpoint tests: status, counters, step, makejmp.""" + +import time + + +# ── status ───────────────────────────────────────────────────────────────── + +EXPECTED_STATUS_KEYS = {"pc", "a", "x", "y", "sp", "p"} + + +def test_cpu_status_has_expected_keys(fresh_cpu): + """cpu/status must return at least the canonical 6 register fields.""" + result = fresh_cpu.cpu_status()["result"] + missing = EXPECTED_STATUS_KEYS - set(result) + assert not missing, f"cpu/status missing keys: {missing}" + + +def test_cpu_status_register_ranges(fresh_cpu): + """Each register field must be in the right value range.""" + r = fresh_cpu.cpu_status()["result"] + assert 0 <= r["pc"] <= 0xFFFF, f"PC out of range: {r['pc']}" + for reg in ("a", "x", "y", "sp"): + assert 0 <= r[reg] <= 0xFF, f"{reg.upper()} out of range: {r[reg]}" + assert 0 <= r["p"] <= 0xFF, f"P out of range: {r['p']}" + + +# ── counters ─────────────────────────────────────────────────────────────── + +def test_counters_monotonic(fresh_cpu): + """Cycle/instruction/frame counts must monotonically increase while running.""" + rd = fresh_cpu + rd.cont() + samples = [] + for _ in range(3): + time.sleep(0.05) + samples.append(rd.cpu_counters()["result"]) + rd.pause() + + for i in range(len(samples) - 1): + s_prev, s_next = samples[i], samples[i + 1] + for key in ("cycle", "instruction", "frame"): + assert s_next[key] >= s_prev[key], \ + f"{key} went backwards: {s_prev[key]} -> {s_next[key]}" + + +# ── control: makejmp ─────────────────────────────────────────────────────── + +def test_makejmp_sets_pc(fresh_cpu): + """makejmp(addr) must set PC to addr exactly.""" + rd = fresh_cpu + rd.pause() + rd.call(f"{rd.platform}/cpu/makejmp", {"address": 0x4000}) + pc = rd.cpu_status()["result"]["pc"] + assert pc == 0x4000, f"After makejmp($4000), PC = {pc:#06x}" + + +# ── control: step_instruction ────────────────────────────────────────────── + +def test_step_instruction_advances_pc(loaded_fixture): + """Step from inside the park loop. PC should land at park+0 again (3-byte JMP).""" + rd = loaded_fixture + pc_before = rd.cpu_status()["result"]["pc"] + rd.step_instruction() + pc_after = rd.cpu_status()["result"]["pc"] + # JMP abs is 3 bytes but loops back, so PC should == pc_before (the JMP target). + # OR — if step happened mid-fetch — PC could be pc_before + 3 (next instr). + # Be permissive but assert *something changed* in a sane way. + assert pc_after == pc_before or pc_after == pc_before + 3, \ + f"step_instruction: pc {pc_before:#06x} -> {pc_after:#06x} (expected either same or +3)" + + +# ── control: step_cycle ──────────────────────────────────────────────────── + +def test_step_cycle_advances_one_cycle(fresh_cpu): + """step/cycle should advance the cycle counter by exactly 1 (one machine cycle).""" + rd = fresh_cpu + rd.pause() + c_before = rd.cpu_counters()["result"]["cycle"] + rd.call(f"{rd.platform}/step/cycle") + c_after = rd.cpu_counters()["result"]["cycle"] + delta = c_after - c_before + assert delta == 1, f"step/cycle: cycle counter advanced {delta}, expected 1" +``` + +- [ ] **Step 2: Run CPU tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_cpu.py -v +``` + +Expected: all pass. Note: `test_step_instruction_advances_pc` requires the `loaded_fixture`, which means the fixture PRG must have been built in Task 8. + +If `test_step_cycle_advances_one_cycle` fails because the counter advances by more than 1, the `step/cycle` endpoint in 3.1 may step a full instruction instead — *document this as a baseline observation in 3.1 behavior*, don't fix the test. We may revisit in 3.10 if behavior changes. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_cpu.py +git commit -m "Phase 0.5: CPU endpoint tests (status, counters, makejmp, step)" +``` + +--- + +### Task 11: Memory tests (main + drive) + +**Files:** +- Create: `tests/websocket/test_memory.py` + +- [ ] **Step 1: Write memory tests** + +Create `tests/websocket/test_memory.py`: + +```python +"""Memory endpoint tests: main memory + drive 1541 memory.""" + +import time + + +# ── main memory ──────────────────────────────────────────────────────────── + +def test_read_main_memory_returns_requested_size(fresh_cpu): + """readBlock should return exactly `size` bytes.""" + data = fresh_cpu.read_memory(0x0400, 256) + assert len(data) == 256, f"Expected 256 bytes, got {len(data)}" + + +def test_write_then_read_round_trips(fresh_cpu): + """writeBlock followed by readBlock should return the same data.""" + rd = fresh_cpu + rd.pause() + payload = bytes(range(64)) + rd.write_memory(0xC100, payload) + readback = rd.read_memory(0xC100, len(payload)) + assert readback == payload, f"Round-trip mismatch:\n wrote: {payload.hex()}\n read: {readback.hex()}" + + +def test_loaded_fixture_sentinels(loaded_fixture): + """After running known_state.prg, sentinel bytes at $C000 must match.""" + data = loaded_fixture.read_memory(0xC000, 4) + assert data == bytes([0xAA, 0xBB, 0xCC, 0xDD]), \ + f"Sentinels at $C000: got {data.hex()}, expected aabbccdd" + + +def test_loaded_fixture_screen_cleared(loaded_fixture): + """After running known_state.prg, screen RAM should be space ($20).""" + screen = loaded_fixture.read_memory(0x0400, 1000) + assert all(b == 0x20 for b in screen), \ + f"Screen not cleared: first non-space at offset {next(i for i, b in enumerate(screen) if b != 0x20)}" + + +def test_ram_readblock_excludes_io(fresh_cpu): + """Reading the I/O area ($D000-$DFFF) via /ram/ should see RAM-under-I/O, not chip registers. + + /cpu/memory/ uses the CPU view (sees I/O); /ram/ reads raw RAM bytes underneath. + Test by writing 0xEE to $D020 via RAM (won't change VIC border), then reading both.""" + rd = fresh_cpu + rd.pause() + # Write a sentinel to $D020 via /ram/ — RAM under I/O + rd.write_memory(0xD020, b"\xEE", with_io=False) + # Read via /ram/ — should see our sentinel + ram_view = rd.read_memory(0xD020, 1, with_io=False) + # Read via /cpu/memory/ — sees VIC register value (border color, low nibble) + cpu_view = rd.read_memory(0xD020, 1, with_io=True) + assert ram_view == b"\xEE", f"/ram/ view of $D020: got {ram_view.hex()}, expected ee" + # CPU view: VIC border register only uses low 4 bits; high nibble undefined. + # Just assert they differ (proves the two views are distinct). + assert ram_view != cpu_view, \ + f"/ram/ and /cpu/memory/ returned same byte for $D020 — I/O distinction broken" + + +# ── drive 1541 memory ────────────────────────────────────────────────────── + +def test_read_drive_memory_returns_requested_size(fresh_cpu): + """Drive 1541 readBlock should return exactly `size` bytes.""" + data = fresh_cpu.read_drive_memory(0x00, 16) + assert len(data) == 16, f"Expected 16 bytes from drive, got {len(data)}" + + +def test_drive_via1_readable(fresh_cpu): + """VIA1 at $1800 (with_io=True) should produce some defined byte values.""" + data = fresh_cpu.read_drive_memory(0x1800, 4, with_io=True) + assert len(data) == 4 + # Bytes can be any value, but the call must succeed without exception. + + +def test_drive_memory_write_then_read(fresh_cpu): + """Round-trip writeBlock/readBlock against drive RAM.""" + rd = fresh_cpu + payload = bytes([0x11, 0x22, 0x33, 0x44]) + rd.write_drive_memory(0x0500, payload) + readback = rd.read_drive_memory(0x0500, len(payload)) + assert readback == payload, \ + f"Drive round-trip mismatch:\n wrote: {payload.hex()}\n read: {readback.hex()}" +``` + +- [ ] **Step 2: Run memory tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_memory.py -v +``` + +Expected: all pass. If `test_ram_readblock_excludes_io` fails because /ram/ and /cpu/memory/ behave the same in 3.1, document as 3.1 limitation; we'll revisit in 3.10. + +If `test_drive_memory_write_then_read` fails with "no drive context" or similar, the True Drive Emulation setting may not be enabled — confirm via the RetroDebugger GUI (Settings → Emulator → C64 → Drive emulation → True drive), restart RD, and rerun. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_memory.py +git commit -m "Phase 0.5: memory endpoint tests (main + drive 1541)" +``` + +--- + +### Task 12: Breakpoint tests + +**Files:** +- Create: `tests/websocket/test_breakpoints.py` + +- [ ] **Step 1: Write breakpoint tests** + +Create `tests/websocket/test_breakpoints.py`: + +```python +"""Breakpoint endpoint tests: CPU PC breakpoints, memory access breakpoints.""" + +import time + + +def _is_paused_at(rd, target_pc, tolerance=4): + """Helper — check if CPU is paused at or near target_pc.""" + pc = rd.cpu_status()["result"]["pc"] + return abs(pc - target_pc) <= tolerance + + +def test_cpu_breakpoint_fires_on_pc_match(fresh_cpu): + """Set a breakpoint at a KERNAL address; reset; verify CPU pauses near it.""" + rd = fresh_cpu + # $FCE2 = KERNAL reset vector. CPU passes through here right after reset. + # Pause first so we can install bp cleanly. + rd.pause() + rd.add_breakpoint(0xFCE2) + + # Reset triggers PC to land on $FCE2; with bp set, CPU should pause there. + rd.reset(hard=True) + time.sleep(0.3) + + pc = rd.cpu_status()["result"]["pc"] + # PC might be exactly $FCE2 or a few instructions past if bp fires post-fetch. + assert 0xFCE2 <= pc <= 0xFCF0, \ + f"After reset with bp at $FCE2, PC = {pc:#06x}, expected close to $FCE2" + + rd.remove_breakpoint(0xFCE2) + + +def test_memory_write_breakpoint_fires_on_store(loaded_fixture): + """Set a write-bp at $C000. Re-run fixture. CPU must pause at the STA that hits $C000.""" + rd = loaded_fixture + # CPU is paused inside park loop. Add write-bp at $C000. + rd.add_memory_breakpoint(0xC000, access="write") + + # Re-trigger the write by re-jumping to fixture start. + rd.call(f"{rd.platform}/cpu/makejmp", {"address": 0x0810}) + rd.cont() + time.sleep(0.1) + + status = rd.cpu_status()["result"] + pc = status["pc"] + # The STA $C000 instruction lives somewhere in $0820-$083F range (after the screen clear). + # Just check we paused before reaching `park`. + park_addr = 0x0820 # Approximate; replace with actual park address from fixture .sym + assert pc < park_addr + 0x100, \ + f"Write bp at $C000 did not fire — PC ran to {pc:#06x}, past expected STA" + + +def test_breakpoint_remove_does_not_error(fresh_cpu): + """Removing a non-existent breakpoint should not error.""" + response = fresh_cpu.remove_breakpoint(0xDEAD) + # Status code may be 200 or 400 depending on impl, but should not raise. + assert "status" in response, f"remove_breakpoint returned no status: {response}" +``` + +- [ ] **Step 2: Run breakpoint tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_breakpoints.py -v +``` + +Expected: all pass. If `test_memory_write_breakpoint_fires_on_store` fails because PC ran to the park loop, the memory-write breakpoint isn't firing in 3.1 — that's a real finding worth noting in `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` under "Known surprises". Mark the test with `pytest.mark.skip(reason="3.1 memory bp not firing — investigate")` and continue. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_breakpoints.py +git commit -m "Phase 0.5: breakpoint endpoint tests (CPU PC, memory access)" +``` + +--- + +### Task 13: Chip register tests (VIC, CIA, SID) + +**Files:** +- Create: `tests/websocket/test_chips.py` + +- [ ] **Step 1: Write chip tests** + +Create `tests/websocket/test_chips.py`: + +```python +"""Chip register tests: VIC-II, CIA1, CIA2, SID.""" + + +def test_vic_read_returns_dict(fresh_cpu): + """VIC read with a list of register names returns a dict mapping to values.""" + rd = fresh_cpu + # $D020 is VIC border color, $D021 is background color. + resp, _ = rd.call(f"{rd.platform}/vic/read", {"registers": [0x20, 0x21]}) + assert "result" in resp, f"vic/read returned no result: {resp}" + result = resp["result"] + assert isinstance(result, dict) or isinstance(result, list), \ + f"vic/read result is {type(result).__name__}, expected dict or list" + + +def test_vic_write_then_read_round_trips(fresh_cpu): + """Writing $07 (yellow) to VIC border, then reading back, should return $07.""" + rd = fresh_cpu + rd.pause() + # Write border = 7 + rd.call(f"{rd.platform}/vic/write", {"registers": {"0x20": 7}}) + # Read back + resp, _ = rd.call(f"{rd.platform}/vic/read", {"registers": [0x20]}) + result = resp["result"] + # Tolerate dict-of-strings or list shapes by extracting any value + if isinstance(result, dict): + val = list(result.values())[0] + else: + val = result[0] if isinstance(result, list) else result + assert (val & 0x0F) == 7, f"VIC $D020 readback: got {val}, expected 7 (border yellow)" + + +def test_cia1_read_returns_dict(fresh_cpu): + """CIA1 read should work with cia=0 (or 1 — confirm which).""" + rd = fresh_cpu + resp, _ = rd.call(f"{rd.platform}/cia/read", {"cia": 0, "registers": [0x00, 0x01]}) + assert "result" in resp, f"cia/read returned no result: {resp}" + + +def test_sid_read_returns_dict(fresh_cpu): + """SID read should return register values.""" + rd = fresh_cpu + resp, _ = rd.call(f"{rd.platform}/sid/read", {"registers": [0x18, 0x1B]}) + assert "result" in resp, f"sid/read returned no result: {resp}" +``` + +- [ ] **Step 2: Run chip tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_chips.py -v +``` + +Expected: all pass. If parameter names are wrong (e.g., `cia` should be `index`), the test will fail with a 400-status response — adjust based on the actual schema in `src/Remote/CDebuggerServerApi.cpp`. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_chips.py +git commit -m "Phase 0.5: chip register tests (VIC, CIA, SID)" +``` + +--- + +### Task 14: Input tests (keyboard, joystick) + +**Files:** +- Create: `tests/websocket/test_input.py` + +- [ ] **Step 1: Write input tests** + +Create `tests/websocket/test_input.py`: + +```python +"""Input endpoint tests: keyboard key down/up, joystick down/up. + +KERNAL keyboard buffer: + $00C6 — number of chars in buffer (0..10) + $0277-$0280 — buffer +""" + +import time + + +def test_key_down_populates_keyboard_buffer(fresh_cpu): + """Pressing 'A' should result in a char in the keyboard buffer.""" + rd = fresh_cpu + rd.cont() + time.sleep(0.2) # let KERNAL keyscan start + + # Send 'A' down then up. + rd.call(f"{rd.platform}/input/key/down", {"key": "A"}) + time.sleep(0.05) + rd.call(f"{rd.platform}/input/key/up", {"key": "A"}) + time.sleep(0.1) + rd.pause() + + # Check kbd buffer state + buf_len = rd.read_memory(0x00C6, 1)[0] + buf = rd.read_memory(0x0277, max(buf_len, 1)) + # 'A' shifted to PETSCII = $41 + assert buf_len > 0, f"Keyboard buffer empty after key press; $00C6 = {buf_len}" + assert buf[0] in (0x41, 0x01), f"Buffer head = {buf[0]:#04x}, expected $41 (A) or $01 (lowercase a)" + + +def test_joystick_down_does_not_error(fresh_cpu): + """Joystick input call should succeed.""" + rd = fresh_cpu + resp, _ = rd.call(f"{rd.platform}/input/joystick/down", {"port": 2, "direction": "up"}) + # Status 200 means accepted + assert resp.get("status", 200) == 200, f"joystick/down failed: {resp}" + rd.call(f"{rd.platform}/input/joystick/up", {"port": 2, "direction": "up"}) +``` + +- [ ] **Step 2: Run input tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_input.py -v +``` + +Expected: both pass. If `test_key_down_populates_keyboard_buffer` fails because the buffer is empty, the param name for `key` may be wrong — check the actual API (could be `keycode`, `scancode`, `key`, `c64Key`). Adjust. + +If joystick param names are wrong (port/direction), check `CDebuggerServerApi.cpp`. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_input.py +git commit -m "Phase 0.5: input endpoint tests (keyboard, joystick)" +``` + +--- + +### Task 15: Load tests (PRG, D64) + +**Files:** +- Create: `tests/websocket/test_load.py` + +- [ ] **Step 1: Write load tests** + +Create `tests/websocket/test_load.py`: + +```python +"""Top-level load endpoint tests: PRG, D64.""" + +import time +from pathlib import Path + +FIXTURE_DIR = Path(__file__).parent.parent / "fixtures" + + +def test_load_prg_places_bytes_at_load_address(fresh_cpu): + """`load` of known_state.prg should put the BASIC SYS line at $0801.""" + rd = fresh_cpu + rd.call("load", {"path": str(FIXTURE_DIR / "known_state.prg")}) + time.sleep(0.2) + # $0801 is BASIC pointer; first bytes are SYS-line tokens, not zero. + head = rd.read_memory(0x0801, 16) + assert any(b != 0 for b in head), \ + f"After load, memory at $0801 is empty: {head.hex()}" + + +def test_load_prg_then_makejmp_and_run(fresh_cpu): + """End-to-end: load + makejmp + cont reaches park with sentinels in place.""" + rd = fresh_cpu + rd.call("load", {"path": str(FIXTURE_DIR / "known_state.prg")}) + time.sleep(0.2) + rd.call(f"{rd.platform}/cpu/makejmp", {"address": 0x0810}) + rd.cont() + time.sleep(0.05) + rd.pause() + sentinels = rd.read_memory(0xC000, 4) + assert sentinels == bytes([0xAA, 0xBB, 0xCC, 0xDD]), \ + f"E2E run produced wrong sentinels: {sentinels.hex()}" + + +def test_load_nonexistent_file_does_not_crash(fresh_cpu): + """Loading a missing file should return an error response, not crash the bridge.""" + rd = fresh_cpu + resp, _ = rd.call("load", {"path": "/nonexistent/file.prg"}) + # Should be a 4xx response, but the connection must survive. + assert "status" in resp, f"load of nonexistent file returned no status: {resp}" + # Verify we can still talk to RD. + status = rd.cpu_status() + assert status["status"] == 200, "WebSocket dead after bad load" +``` + +- [ ] **Step 2: Run load tests** + +```bash +cd /Users/garion/Projects/RetroDebugger/tests +source .venv/bin/activate +pytest websocket/test_load.py -v +``` + +Expected: all pass. + +D64 load testing is omitted from this task — it requires an extra fixture file and exercises the disk-attach path. We can add it as a follow-up if needed; for now the disk-swap workflow is verified manually. + +- [ ] **Step 3: Commit** + +```bash +git add tests/websocket/test_load.py +git commit -m "Phase 0.5: load endpoint tests (PRG)" +``` + +--- + +### Task 16: Suite runner + timing assertion + +**Files:** +- Create: `tests/run-ws-tests.sh` + +- [ ] **Step 1: Write the runner script** + +Create `tests/run-ws-tests.sh`: + +```bash +#!/bin/sh +# Run the full WebSocket regression suite. +# Assumes RetroDebugger is running and the WebSocket server is enabled. +set -eu +cd "$(dirname "$0")" +. .venv/bin/activate +exec pytest websocket/ "$@" +``` + +```bash +chmod +x tests/run-ws-tests.sh +``` + +- [ ] **Step 2: Run the full suite and time it** + +```bash +cd /Users/garion/Projects/RetroDebugger +time tests/run-ws-tests.sh +``` + +Expected: all tests pass; total wall time < 60 seconds. If runtime > 60s, identify the slowest tests with `pytest --durations=10` and either tighten the sleeps or mark them `@pytest.mark.slow` and skip from the default suite. + +- [ ] **Step 3: Confirm green-suite baseline captured** + +Capture the full output (pass/fail per test, total time) into the Phase 0 baseline doc: + +Open `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` and append: + +```markdown +## WebSocket regression suite baseline (3.1) + +Date captured: 2026-05-27 +Total tests: +Passed: +Skipped/xfail: (list any test marked skip + reason) +Suite wall time: seconds + +This is the behavior contract we preserve through Phase 2 (refactor on 3.1) +and re-establish during Phase 4 (3.10 integration). Any divergence is either +a fix (test was wrong) or a documented expected-change (3.10 behaves +differently for a good reason). +``` + +- [ ] **Step 4: Commit runner + baseline** + +```bash +git add tests/run-ws-tests.sh docs/superpowers/notes/2026-05-27-phase-0-baseline.md +git commit -m "Phase 0.5: suite runner script + 3.1 baseline capture" +git push +``` + +--- + +## Phase 1 — Hook surface catalog + +Goal: produce `docs/vice-hook-surface.md` — a complete map of slajerek's in-tree modifications. This document drives the Phase 2 macro design in the followup plan. + +### Task 17: Enumerate `c64d_*` symbols and their definitions + +**Files:** +- Create: `/tmp/c64d-symbols.txt` (intermediate) +- Create: `/tmp/c64d-callsites.txt` (intermediate) + +- [ ] **Step 1: Find all c64d_* symbol definitions** + +```bash +cd /Users/garion/Projects/RetroDebugger +grep -rEn '^(void|int|unsigned|BYTE|WORD|signed|char|disk_image_t|gcr_t|drive_context_t|static|extern)[ \t][ \t]*\*?[ \t]*c64d_[a-zA-Z0-9_]+\s*\(' \ + src/Emulators/vice/ src/Emulators/vice/ViceInterface/ \ + > /tmp/c64d-symbols.txt +wc -l /tmp/c64d-symbols.txt +head -20 /tmp/c64d-symbols.txt +``` + +Expected: a list of `path:line:declaration` entries. ~50-100 symbol definitions expected. + +- [ ] **Step 2: Find all c64d_* call sites** + +```bash +grep -rEn '\bc64d_[a-zA-Z0-9_]+\b' src/Emulators/vice/ \ + | grep -v ':\s*\(void\|int\|unsigned\|BYTE\|WORD\|signed\|char\|static\|extern\|//' \ + > /tmp/c64d-callsites.txt +wc -l /tmp/c64d-callsites.txt +head -30 /tmp/c64d-callsites.txt +``` + +Expected: a longer list (~500-1500 call sites). Each line is `path:line:source`. + +- [ ] **Step 3: Build per-file modification counts** + +```bash +grep -rln 'c64d_' src/Emulators/vice/ \ + | grep -v 'ViceInterface' \ + | while read f; do + count=$(grep -c 'c64d_' "$f") + echo "$count $f" + done \ + | sort -rn > /tmp/c64d-per-file.txt +head -30 /tmp/c64d-per-file.txt +``` + +Expected: ranked file list. Top entries are the "hottest" modification sites — likely `monitor.c`, `drive.c`, `reu.c`, `ciacore.c`. These get the most attention in Phase 2. + +--- + +### Task 18: Categorize hooks and identify non-additive patches + +**Files:** +- Modify: writes directly to the catalog doc in Task 19 + +- [ ] **Step 1: Sample each top-10 file to identify hook category** + +For each of the top 10 most-modified files from `/tmp/c64d-per-file.txt`: + +```bash +# Replace with each top-10 path: +echo "=== ===" +grep -n 'c64d_' | head -20 +vanilla="$HOME/vice-ref/3.1/${FILE#src/Emulators/vice/}" +diff -u "$vanilla" "" | head -100 +``` + +For each file, note: +1. **Category** — which hook family does it belong to? (CPU step, mem read/write, drive state, REU DMA tick, CIA observer, monitor integration, control flow) +2. **Style** — pure additive (`+` only) or has deletions (`-` lines too)? +3. **Notable patches** — any control-flow modifications that won't macro-ize cleanly + +- [ ] **Step 2: Sweep remaining files in bulk** + +For files not in the top 10, group them by directory and count categories: + +```bash +for dir in c64 c64/cart drive drive/iec drive/iecieee monitor core viciisc arch; do + echo "=== src/Emulators/vice/$dir/ ===" + grep -rln 'c64d_' src/Emulators/vice/$dir 2>/dev/null | wc -l +done +``` + +Expected: a per-directory file count. Helps verify the 96-file total breaks down where we expected. + +- [ ] **Step 3: Identify non-additive patches systematically** + +```bash +# A non-additive patch is one where the slajerek diff has `-` lines that aren't just +# whitespace/comment changes. Find these by examining the per-file diff: +for f in $(grep -rln 'c64d_' src/Emulators/vice/ | grep -v ViceInterface); do + vanilla="$HOME/vice-ref/3.1/${f#src/Emulators/vice/}" + if [ -f "$vanilla" ]; then + delcount=$(diff "$vanilla" "$f" | grep -c '^<') + if [ "$delcount" -gt 0 ]; then + echo "$delcount $f" + fi + fi +done | sort -rn > /tmp/c64d-nonadditive.txt +wc -l /tmp/c64d-nonadditive.txt +head -20 /tmp/c64d-nonadditive.txt +``` + +Expected: a (hopefully short) list of files where slajerek actually removed or replaced VICE code (not just added). These need special treatment in Phase 2. + +--- + +### Task 19: Write the hook surface catalog + +**Files:** +- Create: `docs/vice-hook-surface.md` + +- [ ] **Step 1: Write the catalog** + +Create `docs/vice-hook-surface.md`: + +```markdown +# VICE Hook Surface Catalog + +> Captures every in-tree modification slajerek made to vanilla VICE 3.1, as the +> basis for Phase 2's macro consolidation in the VICE 3.10 upgrade. + +**Generated:** 2026-05-27 +**Baseline:** vanilla VICE 3.1 source from `~/vice-ref/3.1/` +**Modified tree:** `src/Emulators/vice/` in `garionphx/RetroDebugger` + +## Summary + +- Modified files: +- Total `c64d_*` call sites: +- Total `c64d_*` definitions: +- Files with non-additive (control-flow) patches: + +## Hook categories + +Each category groups call sites with a common purpose. Phase 2 will define +one `VICE_HOOK__*` macro family per category. + +### Category 1: CPU step / cycle accounting + +**Files:** [list, e.g. `maincpu.c`, `c64cpusc.c`, `c64memsc.c`] +**Symbols touched:** `c64d_maincpu_clk`, `c64d_set_pc`, ... +**Hook count:** +**Style:** [additive / mixed] +**Notes:** [anything special — e.g., "fires on every instruction boundary; +hot path, performance-sensitive"] + +### Category 2: Memory read taps + +**Files:** [list] +**Symbols:** `c64d_mem_read_byte`, `c64d_mark_read`, ... +**Hook count:** +**Style:** [additive / mixed] +**Notes:** ... + +### Category 3: Memory write taps + +[Same format] + +### Category 4: Drive state observer + +**Files:** `drive.c`, `drivecpu.c`, `drivemem.c`, `rotation.c`, `via1d1541.c`, ... +**Symbols:** `c64d_drive_*`, `c64d_get_drive_*`, `c64d_set_drive_*` +**Hook count:** +**Style:** ... + +### Category 5: REU DMA taps + +**Files:** `reu.c` +**Symbols:** `c64d_maincpu_clk` (in DMA loop), `c64d_reu_io2_store` +**Hook count:** +**Style:** ... + +### Category 6: CIA / VIA observer + +**Files:** `ciacore.c`, `viacore.c`, `c64cia1.c`, `c64cia2.c`, `via1d1541.c`, `via2d.c` +**Symbols:** `c64d_cia_*`, `c64d_via_*` +**Hook count:** +**Style:** ... + +### Category 7: Monitor integration + +**Files:** `monitor.c`, `mon_lex.l`, `montypes.h` +**Symbols:** `c64d_mon_*` +**Hook count:** +**Notes:** [Likely the largest refactor target — monitor was rewritten upstream.] + +### Category 8: [other — anything that doesn't fit above] + +## Non-additive patches + +These modifications change VICE control flow (early returns, condition flips, +expression replacement). They don't fit the additive-hook macro model and must +be reapplied as in-tree edits with `/* RETRODEBUGGER: */` markers. + +| File | Lines | What slajerek changed | Why | +|---|---|---|---| +| `drive/rotation.c` | | | | +| ... | | | | + +## Top-10 hottest files (most c64d_ touches) + +| Rank | File | Hook count | Categories | +|---|---|---|---| +| 1 | | | | +| ... | | | | + +## Symbol-to-file index + +Lists every `c64d_*` symbol with its definition site and call sites. Used by +Phase 2 when designing macro signatures. + +| Symbol | Defined in | Call sites | +|---|---|---| +| `c64d_maincpu_clk` | `ViceInterface/...` | `c64/cart/reu.c:757,766,781`, `monitor/...`, ... | +| `c64d_reu_io2_store` | `ViceInterface/...` | `c64/cart/reu.c:1003` | +| ... | | | + +## Phase 2 design seed + +Based on this catalog, the macro families that Phase 2 will define: + +- `VICE_HOOK_CPU_*` — covers Category 1 +- `VICE_HOOK_MEM_*` — covers Categories 2 + 3 +- `VICE_HOOK_DRIVE_*` — covers Category 4 +- `VICE_HOOK_REU_*` — covers Category 5 +- `VICE_HOOK_CIA_*` / `VICE_HOOK_VIA_*` — covers Category 6 +- `VICE_HOOK_MONITOR_*` — covers Category 7 + +Non-additive patches do NOT get macros; they get inline `/* RETRODEBUGGER */` +comments at the patch site, listed individually for the rebase to track. +``` + +Fill in every `` and `` placeholder with real data gathered in Tasks 17 and 18. Where exhaustive enumeration is impractical (e.g., listing every one of 1500 call sites), summarize: include the top-N hotspots in tables and rely on the symbol-to-file index for the rest. + +- [ ] **Step 2: Verify the catalog accounts for every modified file** + +```bash +# Make sure no file slips through the catalog. +catalog_files=$(grep -oE 'src/Emulators/vice/[a-zA-Z0-9/_.-]+\.[ch]' docs/vice-hook-surface.md | sort -u) +modified_files=$(grep -rln 'c64d_' src/Emulators/vice/ | grep -v ViceInterface | sort -u) + +# Files in modified set but not in catalog: +comm -23 <(echo "$modified_files") <(echo "$catalog_files") +``` + +Expected: empty output, OR a list of files not yet mentioned in the catalog. If non-empty, those files need at least a passing mention in the catalog (likely under one of the category sections). + +- [ ] **Step 3: Commit catalog** + +```bash +git add docs/vice-hook-surface.md +git commit -m "Phase 1: VICE hook surface catalog (basis for Phase 2 macro design)" +git push +``` + +--- + +### Task 20: Phase 1 closeout + +**Files:** +- Modify: `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` (append closeout summary) + +- [ ] **Step 1: Add closeout summary to baseline notes** + +Append to `docs/superpowers/notes/2026-05-27-phase-0-baseline.md`: + +```markdown +## Phase 0 + 0.5 + 1 closeout + +**Date completed:** + +### Artifacts produced + +- Branch `vice-3.10-upgrade` on origin +- `~/vice-ref/3.1/src/` — vanilla 3.1 reference (outside repo) +- `~/vice-ref/3.10/src/` — vanilla 3.10 reference (outside repo) +- `tests/websocket/` — pytest regression suite, tests, runtime s +- `tests/fixtures/known_state.prg` + `.asm` + `build.sh` — fixture infrastructure +- `tests/retrodebugger.py` — vendored WebSocket client +- `docs/vice-hook-surface.md` — Phase 1 catalog + +### Open issues for Phase 2 planning + +- [Any test that was marked skip/xfail in Phase 0.5 — list them here, they + may indicate real 3.1 bugs to fix or expected-changes to absorb in 3.10] +- [Any catalog ambiguities — patches whose intent wasn't obvious from the + diff and may need archeology] +- [MTEngineSDL findings from Task 5 that affect Phase 4 integration] + +### Phase 2 plan input + +The followup plan should: +1. Begin with macro-family design driven by the catalog's category breakdown +2. Refactor on 3.1 in `src/Emulators/vice/`, with the regression suite green + between every commit +3. Land non-additive patches first (smallest set, riskiest), pure-additive + hooks second (mechanical sweep) +``` + +- [ ] **Step 2: Commit closeout** + +```bash +git add docs/superpowers/notes/2026-05-27-phase-0-baseline.md +git commit -m "Phase 1 closeout: summary of artifacts and inputs for Phase 2 plan" +git push +``` + +--- + +## Acceptance check for this plan + +When all 20 tasks complete: + +- [ ] Branch `vice-3.10-upgrade` exists on origin with all commits +- [ ] `~/vice-ref/3.1/` and `~/vice-ref/3.10/` contain extracted upstream source +- [ ] `docs/superpowers/notes/2026-05-27-phase-0-baseline.md` exists and is complete +- [ ] `tests/run-ws-tests.sh` runs the full suite green against the current 3.1 build +- [ ] Suite total runtime < 60 seconds +- [ ] `docs/vice-hook-surface.md` exists and accounts for every modified VICE file + +Once acceptance is met: invoke the writing-plans skill again to write the Phase 2–5 implementation plan, using `docs/vice-hook-surface.md` as design input. diff --git a/docs/superpowers/plans/2026-05-28-vice-3.10-phase-2-step2-functional-gating.md b/docs/superpowers/plans/2026-05-28-vice-3.10-phase-2-step2-functional-gating.md new file mode 100644 index 00000000..9c14ba3a --- /dev/null +++ b/docs/superpowers/plans/2026-05-28-vice-3.10-phase-2-step2-functional-gating.md @@ -0,0 +1,94 @@ +# VICE 3.10 Upgrade — Phase 2 Step 2: gate Tier A+B functional files under RETRODEBUGGER + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax. + +**Goal:** Wrap the functional `c64d_*` modifications in the 11 "Tier A+B" files in `#ifdef RETRODEBUGGER` so that with the flag defined the build behaves exactly as today (regression suite green), and with it undefined the code reverts to vanilla VICE 3.1 behavior — enabling a clean hook-free vanilla build for bug bisection. + +**Architecture:** Unlike Step 1 (side-effect hooks → `VICE_HOOK_*` macros), these files contain *functional* changes (altered control flow, replaced expressions, added emulation-affecting calls). The technique here is per-delta `#ifdef` gating: +- **Pure additions** (slajerek added a call/block that doesn't replace vanilla code): `#ifdef RETRODEBUGGER #endif`. +- **Replacements** (slajerek changed vanilla code): `#ifdef RETRODEBUGGER #else #endif`. The `#else` MUST be the verbatim vanilla code from `~/vice-ref/3.1/src/`. +- **Conditional guards** (slajerek wrapped vanilla code in `if (c64d_... )`): prefer a guard macro in `vice_debugger_hook.h` (ON = the real condition, OFF = the always-vanilla value) so the vanilla block isn't duplicated. E.g. sprite-draw: `if (VICE_HOOK_VIC_DRAW_SPRITES()) { }` with ON=`(c64d_skip_drawing_sprites == 0)`, OFF=`1`. +- **New `c64d_*` function definitions** appended to a file: wrap the whole definition in `#ifdef RETRODEBUGGER ... #endif` so a vanilla build doesn't compile code that references debugger-only infrastructure. + +**Out of scope (leave untouched):** the pervasive `#include "types.h"` → `"vicetypes.h"` rename (handled mechanically at the 3.10 vendor swap) and the Tier C/D files (resid/sound C++ rewrites; `c64cpusc.c`/`drivecpu.c` CPU inline-expansion — deferred to the swap where they're re-inlined from 3.10). + +**Tech stack:** C/C++, the from-source macOS Release build (`tests/README.md` "Building from source"), the pytest WebSocket suite as the ON-build behavior gate. + +**MR boundary:** One MR off `vice-3.10-phase-2-step2`. Stop after the final verification task. + +--- + +## The 11 Tier A+B files + +| # | File | Functional delta (from classification doc + diffs) | +|---|------|----------------------------------------------------| +| 1 | `joyport/joystick.c` | `joystick_process_latch()`: `delay = lib_unsigned_rand(...)` → `delay = 0`; `alarm_set(...)` replaced by direct `joystick_latch_matrix(0); joystick_event_record();`. Plus appended `c64d_*` key up/down defs. | +| 2 | `joyport/mouse.c` | `static` removed from `joyport_mouse_enable()` / `set_mouse_enabled()` (linkage only — confirm no behavior delta; if purely linkage, gating not needed, just note). | +| 3 | `viciisc/vicii-draw-cycle.c` | sprite-draw `switch` wrapped in `if (c64d_skip_drawing_sprites == 0)`; appended `c64d_set_color_register()` def. | +| 4 | `viciisc/viciitypes.h` | new fields added to `vicii_t` struct; possibly toggled debug `#define`s. | +| 5 | `c64/patchrom.c` | appended fast-boot patch calls gated on `c64d_patch_kernal_fast_boot_flag`; `c64d_(un_)patch_kernal_fast_boot()` defs. | +| 6 | `root/sound.c` | SID-run gating (`c64d_setting_run_sid_emulation`, `..._when_in_warp`), `c64d_sound_run_sound_when_paused()` in pause path, `c64d_skip_sound_run_sound_in_sound_store` guard, mutex lock/unlock wrappers; plus `c64d_*` defs. | +| 7 | `root/keyboard.c` | `keyboard_key_pressed()` return type `void`→`int`; appended `c64d_*` defs. | +| 8 | `root/vsync.c` | `vsync_do_vsync()`/`sound_flush()` gain `isPaused` param; `vsync_hook()` gated. | +| 9 | `sid/sid.c` | `sid_read()` restructured to capture return value; `sid_sound_machine_open()` gains `chipno`. | +| 10 | `sid/sid-snapshot.c` | snapshot write gated on `c64d_get_sid_enable()`; mutex around `sound_open()`. | +| 11 | `c64/c64-snapshot.c` | `c64_snapshot_write()` signature extended; appended `c64_snapshot_write_in_memory()`. | + +**Note on signature changes (files 7, 8, 9, 11):** where slajerek changed a function's SIGNATURE (e.g. added a param), gating the signature with `#ifdef` means every caller must also be gated — messy. For these, evaluate per-file in the task: if the signature change ripples widely, it may be cleaner to leave the signature as-is (slajerek's) and only gate the *body behavior*, accepting that the vanilla-build purity for that one signature is imperfect (document it). Correctness of the ON build is the hard requirement; OFF vanilla purity is best-effort for signature-level changes. + +--- + +## Task 1: Setup — confirm baseline build + suite green on the new branch + +- [ ] **Step 1:** Confirm on branch `vice-3.10-phase-2-step2`, tree clean, `RETRODEBUGGER` already wired (inherited from Step 1). +- [ ] **Step 2:** Build from source (Release, see `tests/README.md`), relaunch, run `./tests/run-ws-tests.sh`. Expect `28 passed, 1 skipped, 1 xfailed`. This is the pre-Step-2 baseline. If not green, STOP — the branch base is wrong. + +--- + +## Tasks 2–12: gate each file (one task per file, or batch the trivial ones) + +Do them lowest-risk first: 2 (mouse.c, likely linkage-only) → 3 (vicii-draw guard macro) → 5 (patchrom additions) → 1 (joystick replacement) → 4 (viciitypes struct) → 6 (sound.c) → 10 (sid-snapshot) → 9 (sid.c) → 8 (vsync) → 7 (keyboard) → 11 (c64-snapshot). + +Each file task follows this procedure (repeated in full so tasks are self-contained): + +- [ ] **Step 1: Diff against vanilla** to enumerate the exact deltas: + ```bash + diff "$HOME/vice-ref/3.1/src/" "src/Emulators/vice/" + ``` + Ignore the `types.h`→`vicetypes.h` line and pure comment/LOGD additions (harmless; may leave or gate — prefer leave for comments). Identify each FUNCTIONAL delta. +- [ ] **Step 2: Gate each functional delta** using the right pattern from the Architecture section: + - pure addition → `#ifdef RETRODEBUGGER ... #endif` + - replacement → `#ifdef RETRODEBUGGER #else #endif` + - conditional guard → add a guard macro to `src/Emulators/vice/vice_debugger_hook.h` (ON = real condition, OFF = vanilla-equivalent constant) and use it + - appended `c64d_*` defs → wrap whole def in `#ifdef RETRODEBUGGER ... #endif` + The `#else`/vanilla branches MUST be copied verbatim from `~/vice-ref/3.1/src/` — do not paraphrase. +- [ ] **Step 3: Build (Release, from source)** — must be `** BUILD SUCCEEDED **`. +- [ ] **Step 4: Relaunch + suite** — must be `28 passed, 1 skipped, 1 xfailed`. ON behavior is unchanged because the `#ifdef RETRODEBUGGER` arm is exactly slajerek's current code. If red, the gating altered the ON path — fix. +- [ ] **Step 5: Commit + push** — `git commit -m "Phase 2 Step 2: gate functional changes under RETRODEBUGGER"`. + +Trivial files (mouse.c if linkage-only, possibly viciitypes.h) may be batched into one commit + one build/suite cycle. Every commit must be preceded by a green build+suite. + +If any file's gating turns out to require rippling signature gates across many callers (files 7/8/9/11), STOP and report it as DONE_WITH_CONCERNS with the specifics so the controller can decide whether to gate the body only or defer that file. + +--- + +## Final Task: whole-surface verification + MR summary + +- [ ] **Step 1: Clean build from scratch** (`xcodebuild ... clean build`, Release, unsigned) → `** BUILD SUCCEEDED **`. +- [ ] **Step 2: Suite vs clean-built binary** → `28 passed, 1 skipped, 1 xfailed`, run 3× for stability. +- [ ] **Step 3: Flag-OFF syntactic sanity** — compile the new guard macro(s) in `vice_debugger_hook.h` with `RETRODEBUGGER` undefined (extend the Step 1 `hooktest_off.c` check). For the gated `.c` files, spot-confirm that each `#else` block is verbatim vanilla by re-diffing the `#else` content against `~/vice-ref/3.1/src/`. A full hook-free app link remains out of scope. +- [ ] **Step 4: Write completion summary** to `docs/superpowers/notes/2026-05-28-phase-2-step2-functional-gating.md`: per-file what was gated and by which pattern, any signature-change files left body-only-gated (with rationale), commit SHAs, verification results. +- [ ] **Step 5: Commit summary + push.** STOP — MR-ready. + +--- + +## Acceptance check + +- [ ] All 11 Tier A+B files' functional deltas gated under `RETRODEBUGGER` (or documented exceptions for ripple-y signatures) +- [ ] Every `#else`/vanilla branch is verbatim from `~/vice-ref/3.1/src/` +- [ ] ON build: clean-from-scratch Release builds; suite green + stable 3× +- [ ] OFF: new guard macros compile; `#else` blocks confirmed vanilla by re-diff +- [ ] Tier C/D files and the `types.h` rename left untouched +- [ ] Completion summary committed + +After this MR: the only remaining hook work is Tier C/D, which is folded into Phase 3 (the VICE 3.10 vendor swap). diff --git a/docs/superpowers/plans/2026-05-28-vice-3.10-phase-3-chunk1-vendor-drop.md b/docs/superpowers/plans/2026-05-28-vice-3.10-phase-3-chunk1-vendor-drop.md new file mode 100644 index 00000000..ba269b63 --- /dev/null +++ b/docs/superpowers/plans/2026-05-28-vice-3.10-phase-3-chunk1-vendor-drop.md @@ -0,0 +1,115 @@ +# VICE 3.10 Upgrade — Phase 3 Chunk 1: vendor drop + infrastructure reconciliation + +> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:subagent-driven-development. Steps use `- [ ]`. + +**Goal:** Bring vanilla VICE 3.10 source into `src/Emulators/vice/` via per-file 3-way merge that PRESERVES slajerek's gated hooks (Steps 1&2), reconcile the cross-cutting infrastructure changes (types, `clkguard` removal, `diskunit` rename, resid renames, `soundsdl` move, `patchrom` deletion, `mainlock` stub), update the build file-lists, then attempt the build and CAPTURE the remaining compile-error landscape as the input for Chunk 2. + +**Honest scope / non-goal:** This chunk does NOT produce a fully building or suite-green tree. The shared headers (`types.h`, CPU cores) force a build-broken window during the swap; the regression suite cannot guard us until the tree builds + runs again (a later chunk). Chunk 1's deliverable is: a clean 3-way merge, reconciled infrastructure, updated build lists, and a categorized error-landscape doc. Do NOT thrash trying to reach zero compile errors here — capture them and stop. + +**Strategy: 3-way merge (not discard-and-replay).** For each file slajerek's tree currently compiles, merge with: `base` = its vanilla 3.1 version, `ours` = the current gated tree version, `theirs` = its vanilla 3.10 version. Where upstream's 3.1→3.10 delta doesn't touch slajerek's gated hook lines, it auto-merges; where it does, resolve manually (favoring: keep the gated `#ifdef RETRODEBUGGER`/`VICE_HOOK_*` structure, apply upstream's vanilla-side change inside it). This leverages the gating to minimize conflicts. `git merge-file` / `diff3` does per-file 3-way merges. + +**Reference inputs:** +- `~/vice-ref/3.1/src/` (base) and `~/vice-ref/3.10/src/` (theirs) +- `docs/superpowers/notes/2026-05-28-vice-3.1-to-3.10-migration-survey.md` — the file-fate map, breakage set, and path-mapping gotchas (slajerek `root/`→vanilla `src/`; resid `resid-.cpp`↔`.cc`) +- `docs/vice-hook-surface.md` — which files carry hooks + +**Tech stack:** git/`git merge-file`, the from-source macOS Release build (`tests/README.md`), shell. + +**Branch:** `vice-3.10-phase-3-vendor-swap` (current). One MR for Chunk 1. + +--- + +## Task 1: Scope the file set + establish the path mapping + +**Files:** create `/tmp/phase3-filemap.tsv` (intermediate). + +- [ ] **Step 1:** List the VICE source files slajerek's tree actually compiles. Derive from the build lists, not a blind `find`: + ```bash + cd /Users/garion/Projects/RetroDebugger + # Xcode project source references under the vice tree: + grep -oE 'src/Emulators/vice/[A-Za-z0-9_./-]+\.(c|cpp|cc)' platform/MacOS/c64d.xcodeproj/project.pbxproj | sort -u > /tmp/vice-build-files.txt + # CMake (Linux) source references: + grep -oE 'src/Emulators/vice/[A-Za-z0-9_./-]+\.(c|cpp|cc)' CMakeLists.txt | sort -u >> /tmp/vice-build-files.txt + sort -u /tmp/vice-build-files.txt -o /tmp/vice-build-files.txt + wc -l /tmp/vice-build-files.txt + ``` +- [ ] **Step 2:** For each compiled file, record its 3-way triple in `/tmp/phase3-filemap.tsv`: `\t\t\t` using the survey's file-fate map + path-mapping rules. Mark fate as one of: `SAME`, `MOVED`, `RENAMED`, `DELETED-UPSTREAM`, `NEW-NEEDED`. For `DELETED-UPSTREAM` (e.g. anything mapping to `clkguard.c`) and `NEW-NEEDED` (e.g. `mainlock.c`), flag for special handling in Task 4. +- [ ] **Step 3:** Sanity-check: every live build file has a resolved vanilla-3.10 path OR is flagged DELETED/NEW. List unresolved ones explicitly — do not guess. + +--- + +## Task 2: 3-way merge the UNHOOKED files (mechanical) + +**Files:** the subset of `/tmp/phase3-filemap.tsv` NOT in `docs/vice-hook-surface.md`'s 64-file hook set and not Tier C/D — i.e. files slajerek did not modify beyond the `types.h`→`vicetypes.h` rename. + +- [ ] **Step 1:** For each such file with fate `SAME`/`MOVED`/`RENAMED`: replace the live file's content with its vanilla 3.10 content, then re-apply ONLY the `types.h`→`vicetypes.h` include rename (slajerek's mechanical convention) so includes still resolve. (These files have no hooks, so 3.10 content + the include rename = correct.) + ```bash + # per file: + sed 's/#include "types.h"/#include "vicetypes.h"/' "$THEIRS" > "$LIVE" + ``` +- [ ] **Step 2:** Commit this batch: `git commit -m "Phase 3 Chunk 1: drop in 3.10 source for unhooked files"`. (Build still broken overall — fine.) + +--- + +## Task 3: 3-way merge the HOOKED files (preserve gated hooks) + +**Files:** the hook-set files (from the catalog) that still exist in 3.10, EXCLUDING the CPU-core inline files (`c64cpusc.c`, `drivecpu.c` — deferred to Chunk 2) and Tier C resid/sound rewrites (deferred to Chunk 2). + +- [ ] **Step 1:** For each, run a 3-way merge: + ```bash + # base = vanilla 3.1, ours = current gated live file, theirs = vanilla 3.10 + cp "$LIVE" /tmp/ours.c + git merge-file -p --diff3 /tmp/ours.c "$BASE" "$THEIRS" > /tmp/merged.c 2>/tmp/merge.status || echo "CONFLICTS in $LIVE" + ``` + Note: `base`/`theirs` are the VANILLA files; `ours` is the gated live file. Apply the `types.h`→`vicetypes.h` rename consistently (the rename itself may show as a conflict — resolve to `vicetypes.h`). +- [ ] **Step 2:** For each conflicted file, resolve by hand: keep slajerek's `#ifdef RETRODEBUGGER`/`VICE_HOOK_*` gated structure; fold upstream's vanilla-side change into the non-gated code (and into the `#else` arm where one exists). The gating should localize conflicts to small regions. +- [ ] **Step 3:** Where a hook's anchor line was changed/moved by upstream, re-place the `VICE_HOOK_*` call / `#ifdef` block at the equivalent 3.10 location (use the catalog's hook description to know intent). +- [ ] **Step 4:** Commit per directory or in a few logical batches: `git commit -m "Phase 3 Chunk 1: 3-way merge hooked files onto 3.10"`. Record any file whose merge was non-trivial (for the error-landscape doc). + +--- + +## Task 4: Reconcile cross-cutting infrastructure + +- [ ] **Step 1 — `clkguard` removal:** 3.10 deleted `clkguard.c/.h`. Find every live file that `#include "clkguard.h"` or calls `clkguard_*`. For each, apply 3.10's replacement approach (inspect how vanilla 3.10 handles what `clkguard` used to do — likely the CLOCK-overflow handling moved into `maincpu`/`alarm`). Remove the includes/calls; document any behavioral uncertainty. Remove `root/clkguard.c` from the build lists. +- [ ] **Step 2 — `diskunit` rename:** 3.10 renamed `drive_context_t`→`diskunit_context_t` (and related). Apply the rename across the drive-side files (and `ViceInterface/` consumers that reference `drive_context_t` — check `ViceWrapper.h`/`CDebugInterfaceVice.cpp`). This is mechanical but pervasive; verify against 3.10's actual type name. +- [ ] **Step 2b — `BYTE`/`WORD`→`uint8_t`/`uint16_t`:** if 3.10 dropped the legacy `BYTE`/`WORD` typedefs, reconcile. Check whether `vicetypes.h` (slajerek's) still defines them; if so, slajerek's shim may bridge this — verify and document. +- [ ] **Step 3 — resid renames:** ensure the resid `.cc`↔`resid-*.cpp` mapping is consistent in the merged tree and build lists (resid/resid-fp are Tier C for content, but their file presence/naming must be coherent now). +- [ ] **Step 4 — `soundsdl` move:** 3.10 moved it to `arch/shared/sounddrv/soundsdl.c`. Decide its live location (keep slajerek's `sounddrv/` path or adopt 3.10's) and reflect in build lists. Content reconciliation (it's a Tier C rewrite) is deferred to Chunk 2 — for now get the file present + path coherent. +- [ ] **Step 5 — `patchrom.c` deletion:** 3.10 deleted `c64/patchrom.c`. slajerek's gated fast-boot patches lived there. Decide: drop the fast-boot feature, or relocate its `c64d_*` functions. For Chunk 1, remove `patchrom.c` from the build if 3.10 has no equivalent, and note the fast-boot feature as a deferred decision (it was already `#ifdef RETRODEBUGGER`-gated, so dropping it is OFF-safe). +- [ ] **Step 6 — `mainlock` stub:** 3.10's `mainc64cpu.c` calls `mainlock_yield()`. RetroDebugger isn't a threaded VICE. Provide a minimal `mainlock` stub (or `#define mainlock_yield() ((void)0)`) so the embedded single-threaded build is satisfied. Add `mainlock.c/.h` to the tree+build only if genuinely needed; prefer a no-op stub. Document this as a key reconciliation point (it interacts with RetroDebugger's debug-pause — flag for Chunk 2 scrutiny). +- [ ] **Step 7:** Commit: `git commit -m "Phase 3 Chunk 1: reconcile cross-cutting infra (clkguard, diskunit, resid, soundsdl, patchrom, mainlock)"`. + +--- + +## Task 5: Update build file-lists + +- [ ] **Step 1:** Reconcile `CMakeLists.txt` and `platform/MacOS/c64d.xcodeproj/project.pbxproj` vice-source lists: add any NEW 3.10 files now required (e.g. `mainlock.c` if used, new core files), remove DELETED ones (`clkguard.c`, `patchrom.c` if dropped), fix MOVED/RENAMED paths (`soundsdl.c`, resid). Keep `vice_debugger_hook.h` and `ViceInterface/` entries intact. +- [ ] **Step 2:** Commit: `git commit -m "Phase 3 Chunk 1: update CMake + Xcode source lists for 3.10 file set"`. + +--- + +## Task 6: Attempt build, capture the error landscape + +**Files:** create `docs/superpowers/notes/2026-05-28-phase-3-chunk1-error-landscape.md`. + +- [ ] **Step 1:** Attempt the macOS Release build (per `tests/README.md`). Expect failures. Capture full output: + ```bash + cd platform/MacOS + xcodebuild -project c64d.xcodeproj -scheme "Retro Debugger" -configuration Release -arch arm64 CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO build 2>&1 | tee /tmp/chunk1-build.log | tail -40 + ``` +- [ ] **Step 2:** Categorize errors in the landscape doc: group by file/subsystem and by type (missing symbol, signature mismatch, missing header, type mismatch, hook-anchor gone, etc.). Quantify (how many errors, which subsystems dominate). Explicitly separate: (a) CPU-core / Tier C items already deferred to Chunk 2 (expected), (b) infra items that should have been fixed here (fix if quick), (c) surprises that change the plan. +- [ ] **Step 3:** Write the landscape doc with: the build's error count + categorization, the subsystems sorted by remaining-work, confirmation that the deferred CPU-core/Tier-C errors match expectations, any surprises, and a recommended Chunk 2 scope. This is the planning input for Chunk 2. +- [ ] **Step 4:** Commit: `git commit -m "Phase 3 Chunk 1: error-landscape capture (Chunk 2 planning input)"; git push`. + +--- + +## Acceptance check (Chunk 1) + +- [ ] Vanilla 3.10 source merged into the tree for all compiled files via 3-way merge, gated hooks preserved where applicable +- [ ] Cross-cutting infra reconciled: clkguard removed, diskunit rename applied, resid/soundsdl paths coherent, patchrom decision made, mainlock stubbed +- [ ] Build lists (CMake + Xcode) updated for the 3.10 file set +- [ ] `git diff` against the pre-Chunk-1 commit is reviewable and the merge commits cleanly separate "upstream 3.10 content" from "hook re-application" from "infra reconciliation" +- [ ] Error-landscape doc committed, categorizing remaining compile errors and scoping Chunk 2 +- [ ] Build is NOT expected to pass yet — that is fine and documented + +**Explicitly deferred to Chunk 2+:** `c64cpusc.c`/`drivecpu.c` CPU-core re-inline (283+97 hooks against 3.10's mainc64cpu.c/6510core.c + RMW-timing changes), Tier C resid/soundsdl content rewrites, the monitor subsystem replay, and getting back to a building + suite-green state. diff --git a/docs/superpowers/specs/2026-05-27-vice-3.10-upgrade-design.md b/docs/superpowers/specs/2026-05-27-vice-3.10-upgrade-design.md new file mode 100644 index 00000000..81d12116 --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-vice-3.10-upgrade-design.md @@ -0,0 +1,397 @@ +# RetroDebugger: VICE 3.1 → 3.10 Upgrade Design + +**Date:** 2026-05-27 +**Status:** Draft for user review +**Branch:** `vice-3.10-upgrade` (to be created off `master`) + +## 1. Goal & Acceptance + +### Goal + +Upgrade the in-tree VICE fork embedded in `garionphx/RetroDebugger` from version +3.1 to 3.10 while preserving the full RetroDebugger feature set (ImGui GUI, +plugins, Atari/NES emulator slots, all UI tooling). Simultaneously consolidate +slajerek's scattered in-tree `c64d_*` hooks into a single header-based macro +surface, so future VICE upgrades drop from "weeks of merging" to "days of +patching." + +### Motivation + +- Better 1541 drive emulation accuracy (relevant to our riscv-c64 boot path) +- More accurate REU support (also relevant to riscv-c64) +- Bug/accuracy fixes accumulated upstream over ~8 years +- New chip cores and features +- Reduce drift from upstream so this fork remains maintainable + +### Acceptance criteria + +The upgrade is **done** when all of: + +1. Branch builds cleanly on macOS via the existing `platform/MacOS/build.sh` and + Xcode flows +2. App launches, GUI renders, loads a known PRG, and runs to a known screen +3. The WebSocket regression suite (introduced in Phase 0.5) passes against the + rebuilt app, exercising every endpoint family from the `retrodebugger` skill + catalog +4. Branch merges to `master` with cleanly separated commits (vendor import, + hook refactor, patch replay, integration fixes) + +### Explicit non-goals (followup work, not this project) + +- Linux and Windows builds +- riscv-c64 boot path validation under the upgraded debugger +- Atari800 and NestopiaUE emulator updates +- Snapshot format compatibility shim (3.1 snapshots will not load in 3.10) +- Any new RetroDebugger features + +## 2. Background: current embed shape + +- VICE 3.1 is an **in-tree fork** at `src/Emulators/vice/` (~17 MB, all major + subsystems: `c64/`, `drive/`, `monitor/`, `arch/`, `viciisc/`, `resid/`, etc.) +- Build system is RetroDebugger's own CMake — VICE's autotools build is not used +- The bridge layer is `src/Emulators/vice/ViceInterface/` (~5,500 LOC across two + large files plus a dozen smaller ones), which reaches directly into VICE + internal headers (`vicii.h`, `viciitypes.h`, `maincpu.h`, `drivetypes.h`, + `vicii-resources.h`, `snapshot.h`, `machine.h`) +- **96 VICE source files contain in-place `c64d_*` modifications** — hooks + scattered through REU, drive, monitor, CIA, VIA, and CPU code. These are not + isolated to `ViceInterface/`. This is the core complexity of the upgrade. +- The repo's `patch-apply.sh` / `patch-format.sh` are generic git wrappers, not + a managed patch series. There is no existing diff between slajerek's tree and + vanilla 3.1 — we must produce one ourselves in Phase 0. + +## 3. Strategy: three-layer rebase + +Work is structured as three layers of git commits, each independently +reviewable: + +### Layer 1 — Vanilla baseline reference + +Commit unmodified VICE 3.1 source into a scratch reference directory **outside +the repo** so we can mechanically `diff` against current `src/Emulators/vice/` +and produce the canonical "slajerek patches": the 96 files of `c64d_*` +modifications, cleanly isolated from upstream code. This becomes our patch +series source of truth. + +### Layer 2 — Hook consolidation refactor (on 3.1) + +Before touching 3.10 at all, refactor the slajerek patches in-place on 3.1 so +they all dispatch through a single, narrow header — `vice_debugger_hook.h` +(working name). Each instrumented VICE file shrinks from "scattered `c64d_*` +calls" to "one `#include` + a few `VICE_HOOK_*(...)` macro invocations." The +macros expand to no-ops by default and to `c64d_*` calls when `RETRODEBUGGER` +is defined. + +Validate this refactor on 3.1 first — build + the new WebSocket regression +suite must stay green — so we know the consolidation is behavior-preserving +before introducing a second variable (the 3.10 jump). + +### Layer 3 — Vendor swap to 3.10 + patch replay + +Commit pristine VICE 3.10 source over `src/Emulators/vice/` (preserving only +`ViceInterface/`). One single commit whose diff equals "VICE upstream changes +3.1 → 3.10" — clean for archaeology. Then commit the consolidated patch +series on top. Conflicts get resolved per-file. `ViceInterface/` API breakage +gets a final commit dedicated to bridge-side fixes. + +The win: layer-2 hooks land surgically on 3.10. Instead of 96 messy three-way +merges, we get 96 small includes that mostly just work — only the files VICE +itself restructured produce real conflicts. The next VICE upgrade +(3.10 → 3.11 …) reuses the same hook header; at most we update the macro +definitions and re-add the include to any newly created VICE files. + +## 4. Hook refactor design + +A single header `src/Emulators/vice/vice_debugger_hook.h` is added to the VICE +include path. **Macro-only**, no link-time symbols. Three macro families cover +the slajerek hook categories (final list confirmed during Phase 1 catalog): + +```c +/* Memory access taps — fired from CPU/memory accessors */ +VICE_HOOK_MEM_READ(addr, value) +VICE_HOOK_MEM_WRITE(addr, value) +VICE_HOOK_MEM_EXEC(addr, opcode) + +/* Drive state taps — fired from drivecpu/viad/rotation */ +VICE_HOOK_DRIVE_STEP(drive_idx) +VICE_HOOK_DRIVE_HEAD_MOVE(drive_idx, halftrack) + +/* REU DMA taps */ +VICE_HOOK_REU_DMA_TICK() +VICE_HOOK_REU_IO2_WRITE(addr, value) + +/* CIA / VIA observer */ +VICE_HOOK_CIA_READ(cia_idx, reg, value) +VICE_HOOK_CIA_WRITE(cia_idx, reg, value) + +/* CPU stepping and cycle accounting */ +VICE_HOOK_CLK_TICK() +VICE_HOOK_INSTR_BOUNDARY(pc) +``` + +Each macro has two definitions: + +```c +#ifdef RETRODEBUGGER + #define VICE_HOOK_REU_DMA_TICK() do { c64d_maincpu_clk++; } while (0) + #define VICE_HOOK_REU_IO2_WRITE(a, v) c64d_reu_io2_store((a), (v)) + /* etc. */ +#else + #define VICE_HOOK_REU_DMA_TICK() ((void)0) + #define VICE_HOOK_REU_IO2_WRITE(a, v) ((void)0) + /* etc. */ +#endif +``` + +### What changes inside each instrumented VICE file + +**Before** (slajerek's in-tree pattern, e.g. `src/Emulators/vice/c64/cart/reu.c:757`): + +```c +some_existing_dma_loop: + c64d_maincpu_clk++; /* slajerek injection */ + /* loop body */ + c64d_maincpu_clk++; +``` + +**After**: + +```c +#include "vice_debugger_hook.h" +... +some_existing_dma_loop: + VICE_HOOK_REU_DMA_TICK(); /* same behavior under RETRODEBUGGER, no-op otherwise */ + /* loop body */ + VICE_HOOK_REU_DMA_TICK(); +``` + +### Properties this gives us + +- **Each VICE file's diff against upstream becomes 1–3 lines** instead of + 5–30 lines. Future VICE upgrades produce tiny, easily-resolved three-way + merges. +- **The hook contract lives in one place.** When upstream renames `BYTE` → + `uint8_t` or restructures a struct, only `vice_debugger_hook.h` plus the + corresponding `c64d_*` function in `ViceInterface/` needs updating, not + 96 files. +- **Vanilla VICE still compiles unchanged** when `RETRODEBUGGER` is undefined + — enabling "is this a slajerek bug or a vanilla VICE bug?" bisection. +- **The `c64d_*` C function bodies stay where they are today** (mostly in + `ViceInterface/CDebugInterfaceVice.cpp`-adjacent code). The refactor moves + only the *call sites*, not the implementations. + +### Handling non-additive slajerek modifications + +Some of slajerek's modifications aren't pure additive hook calls — they patch +VICE control flow (early returns, condition changes, replaced expressions). +The Phase 1 catalog surfaces every such case. Treatment per-case in Phase 2: + +- **Default:** keep as an in-tree control-flow patch with a + `/* RETRODEBUGGER: */` comment marking the change, so future + rebases see why it exists +- **When a clean abstraction emerges:** factor into a `VICE_HOOK_OVERRIDE_*` + macro family + +## 5. WebSocket regression test harness + +Built as **Phase 0.5**, *before* any VICE code is touched, so it is available +as a gating signal for every subsequent phase. + +### Shape + +A `pytest` suite under `tests/websocket/`, built on the existing +`tests/retrodebugger.py` client. Each test is self-contained: takes the +RetroDebugger WebSocket as a fixture, drives it to a known state +(reset → load fixture PRG → optional warp), asserts response shape and +values. + +### Coverage organized by endpoint family + +| Family | Examples of what we assert | +|---|---| +| Lifecycle | `reset/hard` returns to PC = $FCE2 (KERNAL reset vector); `pause` / `continue` actually halt/resume; `warp/set true` measurably increases cycle rate | +| CPU status | `cpu/status` has all expected keys, types correct, PC plausible after reset, A/X/Y/SP within range, P flag bits sane | +| CPU counters | `cycle` / `instruction` / `frame` monotonically increase between samples | +| CPU control | `step/instruction` advances PC by the current opcode's length; `step/cycle` advances by 1 cycle; `makejmp(addr)` sets PC to `addr` | +| Main memory | `cpu/memory/readBlock` round-trips a `writeBlock`; `ram/readBlock` excludes I/O range; sizes match request | +| Drive 1541 memory | `drive1541/cpu/memory/readBlock` reads drive ZP correctly; VIA1 ($1800) readable; writes round-trip | +| Breakpoints | CPU bp at a known PC fires (CPU pauses with PC at that address); memory write bp fires on store; raster bp fires | +| Chips | VIC/CIA/SID read returns a dict of register values; write updates them | +| Input | key down/up updates `$00C6` / `$0277` keyboard buffer state | +| Top-level | `load` of a known PRG places bytes at the expected load address; `load` of a `.d64` triggers disk insertion | + +### Fixture strategy + +- A tiny known PRG (~32 bytes) committed to `tests/fixtures/`, doing a + clear-screen plus writes of known bytes to predictable addresses. Tests load + it, jump to it, then assert memory state. +- Optionally a tiny D64 fixture for disk-swap and drive-memory tests. +- RetroDebugger assumed running already (matches current developer workflow). + A pytest `session` fixture connects once. Tests that need a fresh CPU call + `reset/hard` in setup. + +### Test discipline + +- Every test runs in <2 s wall-clock — keeps the whole suite under a minute, so + we actually run it after every commit during the rebase +- Tests assert **observable behavior**, not internal VICE state. This keeps + them version-independent across the 3.1 → 3.10 jump. If a test fails on 3.10 + because it asserted a VICE internal that changed, we revise the test. +- Suite runs in two modes: + - **strict** — every assertion must hold + - **expected-change** — lists known intentional behavior changes between 3.1 + and 3.10. Empty at project start, populated as we discover them in Phase 4. + +### Workflow + +- **Phase 0.5:** write the suite, validate green on the current 3.1 build → + captures baseline behavior +- **Phase 2** (hook refactor): suite must stay green → proves the refactor is + behavior-preserving +- **Phase 4** (3.10 integration): suite runs after every fix; regressions + triaged as "fix" or "expected-change-document" +- **Phase 5** (acceptance): green suite is the merge gate + +### Effort estimate + +~3–5 days for ~40–60 tests plus fixtures. Front-loaded but pays dividends +through every later phase. + +## 6. Phases and workflow + +Each phase has an explicit gate before moving to the next. + +### Phase 0 — Setup and baselining (1–2 days) + +- Create branch `vice-3.10-upgrade` off `master` +- Acquire vanilla VICE 3.1 source (upstream SourceForge SVN tag `v3.1` or + released tarball — pick whichever produces the cleanest diff) +- Acquire vanilla VICE 3.10 source (upstream gitlab tag `v3.10`) +- Drop both into reference directories outside the repo + (e.g. `~/vice-ref/3.1/`, `~/vice-ref/3.10/`) +- Run `diff -ruN ~/vice-ref/3.1/src/ src/Emulators/vice/` — confirm we can + mechanically extract slajerek's patches +- Survey `../MTEngineSDL` for any references to specific VICE internals +- **Gate:** patch extraction produces a tractable, readable diff (expected: + mostly `c64d_*` additions, possibly some `WORD/BYTE` type fixes) + +### Phase 0.5 — WebSocket regression test harness (3–5 days) + +- Implement the harness described in Section 5 +- Add fixture PRG(s) and D64 to `tests/fixtures/` +- Validate green on the current 3.1 build +- **Gate:** full suite green on 3.1; suite runtime <60 s + +### Phase 1 — Document the hook surface (2–3 days) + +- Catalog every `c64d_*` symbol exported from VICE source: name, signature, + call site (inside VICE) and consumer (in `ViceInterface/` or elsewhere) +- Group by concern: CPU stepping, memory access taps, drive state, + REU DMA taps, CIA/VIA observer, monitor integration +- Identify non-additive modifications (control-flow patches) separately +- Output: `docs/vice-hook-surface.md` committed to the branch — this drives + the Phase 2 refactor design +- **Gate:** every modification in the 96 files is accounted for in the catalog + +### Phase 2 — Design and apply hook consolidation on 3.1 (~1 week) + +- Author `vice_debugger_hook.h` with macros covering each hook category from + the Phase 1 catalog +- For each of the 96 files, replace scattered `c64d_*` mentions with the + appropriate `VICE_HOOK_*` macros +- Mark non-additive control-flow patches with `/* RETRODEBUGGER: */` +- Build and run the WebSocket regression suite on refactored 3.1 — must stay + green. If anything breaks, the refactor is wrong; fix before moving on. +- **Gate:** all WebSocket tests still pass on refactored 3.1; observable + behavior unchanged + +### Phase 3 — Vendor swap to 3.10 (1–2 days) + +- Single commit: replace `src/Emulators/vice/` contents with pristine VICE + 3.10 source, preserving only the `ViceInterface/` subdirectory +- Tree will not build — expected +- The commit's diff equals "VICE upstream changes 3.1 → 3.10" — clean for + later archaeology + +### Phase 4 — Patch replay and integration fix (~2–3 weeks; largest phase) + +- Re-apply the consolidated hooks to 3.10 source. Most files: just add the + `#include "vice_debugger_hook.h"` and the macro invocations +- Hand-resolve conflict files where VICE refactored the surrounding code + (expected: most painful in `monitor/`, `drive/`, `arch/`) +- Fix `ViceInterface/` consumers — internal VICE APIs that changed (snapshot + struct layout, drive context shape, monitor command names, archdep + signatures) need bridge-side updates +- Iterate to a green build on macOS +- **Gate:** macOS builds, launches, runs a known PRG to a known screen + +### Phase 5 — Validate and merge (3–5 days) + +- Run the full WebSocket regression suite; fix any debugger API regressions +- Manual GUI sanity sweep: open/close emulator slots, step, breakpoint, + memory edit, disk swap, REU attach +- Squash where it helps readability, but preserve the three-layer separation + (vendor / refactor / integration) in the merged history +- Open self-PR for review, merge to `master` + +### Total calendar estimate + +~4–6 weeks of focused work. Could extend if the monitor or `archdep` refactors +turn out deeper than expected. + +## 7. Risks and mitigations + +1. **Slajerek's 3.1 baseline drift.** His "3.1" tree may not match upstream + 3.1 exactly — possible backported fixes, started from an RC, or modifications + made before tagging. Phase 0's diff reveals this. + *Mitigation:* if drift is small, manually categorize stray hunks as "early + bugfixes" versus "patches"; if drift is large, choose closest upstream + snapshot (possibly 3.0 or 3.2) as baseline instead. + +2. **Monitor subsystem rework.** VICE's monitor was rewritten across 3.4–3.6 + (flex/bison sources, command tables, binary monitor protocol all changed). + `mon_lex.l`, `monitor.c`, `montypes.h` likely require near-total re-port. + *Mitigation:* allocate disproportionate Phase 4 time to monitor; consider + isolating monitor work into its own sub-phase if it gets out of hand. + +3. **`archdep` rework.** VICE moved to a unified arch layer in 3.5+. Anything + in `src/Emulators/vice/arch/` that slajerek customized for embedding will + need restructuring. + *Mitigation:* may need a Phase 4.5 specifically for the arch shim. + +4. **`viciisc` divergence.** The accurate VIC-II implementation has had + significant refinements upstream. Slajerek's modifications may not map + cleanly. + *Mitigation:* if `viciisc` patches are pure observer hooks, easy; if they + are correction patches, evaluate whether they are still needed against the + improved 3.10 core. + +5. **`ViceInterface/` snapshot API.** VICE's snapshot serialization format + changed between 3.1 and 3.10. Loading 3.1 snapshots in 3.10 will not work + without conversion. + *Mitigation:* accepted as known incompatibility; documented in 3.10 release + notes for the fork. + +6. **MTEngineSDL sibling library compatibility.** Build references + `../MTEngineSDL`. If that has assumptions about VICE 3.1 it will break. + *Mitigation:* Phase 0 surveys `MTEngineSDL` for VICE references early. + +## 8. Open questions + +To resolve during execution; do not block design approval: + +- Exact upstream source for vanilla 3.1 — SourceForge SVN tag versus released + tarball (prefer whichever produces the cleanest diff against slajerek) +- Exact upstream source for 3.10 — VICE moved hosts at some point post-3.1; + pin the canonical release artifact in Phase 0 +- Whether MTEngineSDL needs any update at all + +## 9. Out of scope + +- Linux and Windows builds (followup project) +- riscv-c64 boot path validation (followup; the WebSocket suite is this + project's gate) +- Atari800 and NestopiaUE updates (those embedded emulators stay on whatever + version they are currently on) +- Snapshot format compatibility shim +- Any new RetroDebugger features diff --git a/docs/vice-hook-surface.md b/docs/vice-hook-surface.md new file mode 100644 index 00000000..7ac028b4 --- /dev/null +++ b/docs/vice-hook-surface.md @@ -0,0 +1,1234 @@ +# VICE Hook Surface Catalog — Phase 1 + +**Date:** 2026-05-27 +**Branch:** vice-3.10-upgrade +**Baseline:** vanilla VICE 3.1 (`~/vice-ref/3.1/src/`) +**Modified tree:** `src/Emulators/vice/` (slajerek's fork) +**Excludes:** `src/Emulators/vice/ViceInterface/` — slajerek's own bridge code, not patched VICE + +This document is the complete map of every modification slajerek made to vanilla VICE 3.1 inside +`src/Emulators/vice/`. It is the authoritative reference for Phase 2 macro design and Phase 4 +replay planning. + +--- + +## Summary + +| Metric | Count | +|--------|-------| +| Modified files with `c64d_` markers (full tree sweep) | **64** | +| Total `c64d_` reference lines (call sites + definitions) | **633** | +| Distinct `c64d_*` symbol names | **282** | +| `c64d_*` function definition lines (grep for definition forms) | **312** | +| Files with genuine non-additive patches (deletions beyond header/static noise) | **~14** (see table below) | + +**Prior finding upheld with corrections:** The Phase 0 finding that "modifications are essentially +all additive" is **substantially correct** for the majority of files (~50 of 64). However, the +full sweep reveals six categories of genuine non-additive changes that go beyond the known +header-rename / static-removal noise: + +1. `c64cpusc.c` and `drivecpu.c`: vanilla files include `mainc64cpu.c` / `6510core.c` via + `#include` at the bottom; slajerek's versions have **inlined** those files and inserted hooks + throughout. The diff shows large deletion blocks, but no logic was removed — it is an + inline-expansion with hooks inserted. This is non-additive in diff form but not in substance. + +2. `soundsdl.c`: SDL audio callback was substantially **rewritten** to support multi-channel + (mono/stereo) output. Vanilla callback logic was replaced, not augmented. + +3. `resid/resid-filter.cpp`: The **8580 SID model section** (~180 lines of commentary and filter + coefficient tables) was deleted. Only 6581 filter remains. + +4. `resid/resid-sid.cpp`: Multiple behavioral changes — `SID::read()` POT/OSC/ENV paths no longer + update `bus_value_ttl`; write pipeline behavior changed (no 8580 fake pipeline delay); + `databus_ttl` initialization changed to a fixed `0x4000`. + +5. `c64memsc.c`: `mem_ram[C64_RAM_SIZE]` (static array) changed to `BYTE *mem_ram` (pointer), + externally initialized via `c64d_init_memory()` to allow memory-mapped file backing. + +6. `joystick.c`: `joystick_process_latch()` bypasses the random alarm delay (sets `delay=0` and + calls `joystick_latch_matrix(0)` directly), and `keyboard_key_pressed()` return type changed + from `void` to `int`. + +--- + +## Pervasive non-`c64d_*` noise (present in virtually every modified file) + +Two changes appear in essentially all 64 modified files and are mechanical, not logical: + +- **Header rename:** `#include "types.h"` → `#include "vicetypes.h"` (must be replayed as a + mechanical substitution on every patched file when targeting VICE 3.10). +- **`static` removal:** Internal functions promoted to external linkage (removing `static`) so + ViceInterface can call them. See the "Static promotions" subsection in each category below. + +--- + +## Hook Categories + +### Category 1: CPU Step / Cycle Accounting + +**Purpose:** Track the C64 main CPU and drive CPU at per-cycle granularity for the debugger, +profiler, and step/trace modes. + +**Files involved:** +- `c64/c64cpusc.c` (283 hits — primary definition site) +- `drive/drivecpu.c` (97 hits — drive CPU variant) +- `c64/cart/reu.c` (4 hits — REU DMA cycles) +- `core/flash040core.c` (2 hits — flash cycle adjustment) +- `root/dma.c` (1 hit — DMA cycle accounting) +- `root/midi.c` (2 hits — MIDI cycle correction) +- `root/maincpu.h`, `root/interrupt.h` (extern declarations) +- `viciisc/vicii-cycle.c` (1 hit — raster cycle increment) +- `sid/sid.c` (4 hits — SID cycle correction) + +**Representative symbols:** +- `c64d_maincpu_clk` — global CLOCK counter incremented alongside `maincpu_clk` in the `CLK_INC()` macro; used throughout as the debugger's authoritative clock +- `c64d_maincpu_current_instruction_clk` — clock value at start of current instruction +- `c64d_maincpu_previous_instruction_clk`, `c64d_maincpu_previous2_instruction_clk` — ring of saved per-instruction clocks +- `c64d_c64_instruction_cycle` — cycle counter within current instruction +- `c64d_c64_do_cycle()` — hook injected into `CLK_INC()` macro; returns BA-low flags +- `c64d_do_cycle` — drive CPU equivalent +- `c64d_reset_counters` — resets cycle counters +- `c64d_get_maincpu_clock` — returns current `c64d_maincpu_clk` +- `c64d_get_vice_maincpu_clk`, `c64d_get_vice_maincpu_current_instruction_clk` — accessors + +**Style:** Mixed. `c64d_maincpu_clk` increment is inserted into the `CLK_INC()` macro body +(control-flow change to the macro); all functions are additive. + +**Hook count (distinct symbols):** ~15 + +**3.10 impact:** `c64cpusc.c` still exists in 3.10 (192 lines, same structure — `#include +"../mainc64cpu.c"` pattern). `drivecpu.c` still exists in 3.10 at `drive/drivecpu.c` (715 +lines, same structure — `#include "6510core.c"` pattern). The inline-expansion approach slajerek +used means replay requires re-inlining mainc64cpu.c and re-inserting all hooks. **Risk: HIGH** — +both files require full re-examination since vanilla 3.10's versions differ from 3.1's. +`clkguard.c/.h` is present in slajerek's tree (`root/clkguard.c`) but is REMOVED from 3.10; +several files in the slajerek tree include it. + +--- + +### Category 2: Memory Read Taps (C64 side) + +**Purpose:** Intercept every C64 memory read for the debugger's memory access visualizer and +breakpoint system. + +**Files involved:** +- `c64/c64cpusc.c` (primary — `c64d_mark_c64_cell_read` injected at read points) +- `c64/c64memsc.c` (34 hits — peek functions, init, RAM accessor) + +**Representative symbols:** +- `c64d_mark_c64_cell_read(addr)` — callback on every C64 read +- `c64d_peek_c64(addr)` — side-effect-free peek (does not advance state) +- `c64d_peek_c64_for_cycle(addr, mem0001, exrom, game)` — cycle-accurate peek +- `c64d_peek_io(addr)` — peek into I/O region +- `c64d_peek_memory_c64(buf, start, end)` — bulk range peek +- `c64d_peek_whole_map_c64(buf)` — full 64K map with banking +- `c64d_peek_memory0001()` — read port register $01 +- `c64d_mem_ram_read_c64(addr)` — raw RAM read (no banking) +- `c64d_colorram_peek(addr)` — color RAM read + +**Style:** Additive — all new functions appended or inline hooks at read sites. + +**Notable structural change:** `mem_ram` in `c64memsc.c` changed from `BYTE mem_ram[C64_RAM_SIZE]` +(static array) to `BYTE *mem_ram` (pointer), initialized via `c64d_init_memory(uint8 *c64memory)`. +This allows memory-mapped file backing. This is a genuine non-additive change to a data declaration +that affects all consumers of `mem_ram`. + +**Hook count (distinct symbols):** ~10 + +**3.10 impact:** `c64memsc.c` still exists in 3.10 but has structural changes (added +`c64-memory-hacks.h`, `c64model.h` includes; `mem_ram` is `uint8_t mem_ram[C64_RAM_SIZE]` — a +**static array again**, which conflicts with slajerek's pointer patch). **Risk: HIGH** — the +`mem_ram` pointer change must be carefully re-evaluated for 3.10. + +--- + +### Category 3: Memory Write Taps (C64 side) + +**Purpose:** Intercept C64 memory writes for the debugger's write-access tracking and +mem-store breakpoints. + +**Files involved:** +- `c64/c64cpusc.c` (primary — `c64d_mark_c64_cell_write` at STORE macro sites) +- `c64/c64memsc.c` (write-RAM accessors) + +**Representative symbols:** +- `c64d_mark_c64_cell_write(addr, value)` — callback on every C64 write +- `c64d_mark_c64_cell_execute(addr, opcode)` — callback on every C64 instruction fetch +- `c64d_mem_write_c64(addr, value)` — write to C64 memory (honors banking) +- `c64d_mem_write_c64_no_mark(addr, value)` — write without triggering mark +- `c64d_mem_store`, `c64d_mem_store_zero` — store wrappers for debugger +- `c64d_mem_ram_write_c64(addr, value)` — raw RAM write +- `c64d_mem_ram_fill_c64(addr, size, value)` — bulk RAM fill +- `c64d_copy_ram_memory_c64(buf, start, end)` — copy RAM range to buffer +- `c64d_copy_whole_mem_ram_c64(buf)` — copy all RAM +- `c64d_mem_access_addr`, `c64d_mem_access_value`, `c64d_mem_access_is_write`, `c64d_mem_access_watch` — per-access state variables + +**Style:** Additive. Hooks are inserted immediately before/after the vanilla STORE macro body +in the inlined `mainc64cpu.c` expansion. + +**Hook count (distinct symbols):** ~15 + +**3.10 impact:** Same as Category 2 — the STORE macro sites must be re-identified in the 3.10 +inlined CPU core. Risk: MEDIUM (write hooks are structurally parallel to read hooks). + +--- + +### Category 4: Drive State Observer + +**Purpose:** Track 1541 drive CPU state, memory access, and disk state for the drive debugger. + +**Files involved:** +- `drive/drivecpu.c` (97 hits — drive CPU primary) +- `drive/iec/memiec.c` (18 hits — IEC memory R/W hooks) +- `drive/iecieee/via2d.c` (10 hits — VIA-2 read/write) +- `drive/iec/via1d1541.c` (12 hits — VIA-1 read/write/peek) +- `drive/drive.c` (12 hits — GCR dirty flags) +- `drive/drive-writeprotect.c` (1 hit — sense peek) +- `drive/drivemem.c` (2 hits — RAM read/write hooks) +- `drive/rotation.c` (2 hits — track dirty flag) +- `drive/viad.h`, `drive/iec/via1d1541.h` (extern declarations) +- `iecbus/iecbus.c` (25 hits — IEC bus peek and drive accessors) + +**Representative symbols:** +- `c64d_mark_drive1541_cell_read(addr)` / `c64d_mark_drive1541_cell_write(addr, val)` / `c64d_mark_drive1541_cell_execute(addr, op)` — access markers +- `c64d_peek_drive(driveNum, addr)` — side-effect-free peek +- `c64d_peek_mem_drive_internal(drv, addr)` — internal peek by context +- `c64d_peek_memory_drive_internal(drv, buf, start, end)` — bulk peek +- `c64d_peek_whole_map_drive(driveNum, buf)` / `c64d_peek_whole_map_drive_internal(drv, buf)` — full drive memory map +- `c64d_get_drivecpu_regs(driveNum, a, x, y, p, sp, pc)` — CPU register readout +- `c64d_set_drivecpu_pc_no_trap(drv, pc)` — set PC without triggering trap +- `c64d_set_drivecpu_regs_no_trap(drv, ...)` — set all regs +- `c64d_mem_ram_read_drive(driveNum, addr)` / `c64d_mem_ram_write_drive(driveNum, addr, val)` — raw RAM access +- `c64d_copy_ram_memory_drive(driveNum, buf, start, end)` / `c64d_copy_mem_ram_drive(driveNum, buf)` — bulk copy +- `c64d_get_drive_disk_gcr()` / `c64d_get_drive_disk_image()` / `c64d_get_drive_is_disk_attached()` — disk state queries +- `c64d_get_drive_current_halftrack()` / `c64d_set_drive_half_track(track)` — track position +- `c64d_mark_drive1541_contents_track_dirty(track)` — GCR dirty flag +- `c64d_is_drive_dirty_for_snapshot()` / `c64d_is_drive_dirty_and_needs_refresh()` etc. — dirty state flags +- `c64d_drive1541_check_pc_breakpoint(pc)` — PC breakpoint check (drive) +- `c64d_drive1541_check_irqvia1_breakpoint()` / `c64d_drive1541_check_irqvia2_breakpoint()` / `c64d_drive1541_check_irqiec_breakpoint()` — IRQ breakpoints +- `c64d_peek_via1d1541_pra/prb` / `c64d_via1d1541_peek(ctxptr, addr)` — VIA-1 side-effect-free reads +- `c64d_via2d_peek(ctxptr, addr)` / `c64d_peek_via2d_pra/prb` — VIA-2 reads +- `c64d_peek_via_context` / `c64d_viacore_peek` — generic VIA core peek +- `c64d_interrupt_drivecpu_trigger_trap` — inject trap into drive CPU +- `c64d_iecbus_cpu_peek_conf1()` — IEC bus CPU port peek +- `c64d_set_drive_disk_memory(drv, buf)` — inject disk memory +- `c64d_drive_poke(driveNum, addr, val)` — write via store function table + +**Style:** Mostly additive. VIA read hooks (`c64d_mark_drive1541_cell_read/write`) are inserted +immediately before/after the original read/write in `memiec.c`, `via1d1541.c`, `via2d.c`, +`drivemem.c` (control-flow: one line before original action, one after — genuine non-additive +modification). Drive peek functions are all new. + +**Static promotions in this category:** +- `memiec.c`: `drive_read_rom`, `drive_read_rom_ds1216` — promoted to external +- `iecieee/via2d.c`: multiple via store/read functions promoted + +**Hook count (distinct symbols):** ~55 + +**3.10 impact:** `drive/drivecpu.c`, `drive/drive.c`, `drive/drivemem.c`, `drive/rotation.c` +all exist in 3.10. `drive/iec/memiec.c` and `drive/iec/via1d1541.c` exist in 3.10 at the same +paths. `drive/iecieee/via2d.c` exists in 3.10. **Risk: MEDIUM** — file paths are stable, but +the 6510core.c inline expansion in drivecpu.c requires the same re-inlining approach. + +--- + +### Category 5: REU DMA Taps + +**Purpose:** Track REU DMA cycles so `c64d_maincpu_clk` stays in sync during DMA transfers. + +**Files involved:** +- `c64/cart/reu.c` (4 hits) +- `c64/cart/c64-generic.c` (2 hits — cart ROML peek/poke) + +**Representative symbols:** +- `c64d_maincpu_clk++` — inserted at three DMA cycle-bump sites in `reu_dma_host_to_reu()` and related functions +- `c64d_reu_io2_store(addr, value)` — public wrapper for `reu_io2_store()` +- `c64d_peek_cart_roml(addr)` — peek into cartridge ROML +- `c64d_poke_cart_roml(addr, value)` — poke cartridge ROML + +**Style:** Additive. The `c64d_maincpu_clk++` insertions are pure additions within unchanged logic. +Two `assert()` calls were commented out (minor non-additive: `//assert(...)`). + +**Static promotions:** `reu_io2_store`, `reu_read_without_sideeffects`, `set_reu_enabled`, +`set_reu_size`, `set_reu_filename` all had `static` removed. `reu_enabled` changed from +`static int` to `volatile int`. + +**Hook count (distinct symbols):** ~5 + +**3.10 impact:** `c64/cart/reu.c` exists in 3.10. `c64/cart/c64-generic.c` exists in 3.10. +**Risk: LOW** — the DMA tap approach will still work; only the cycle-bump insertion points may +have shifted if 3.10 restructured the DMA loop. + +--- + +### Category 6: CIA / VIA Observer + +**Purpose:** Capture every CIA1/CIA2 register read/write and surface side-effect-free peek for +the debugger's chip inspector and IRQ breakpoints. + +**Files involved:** +- `c64/c64cia1.c` (8 hits) +- `c64/c64cia2.c` (13 hits) +- `core/ciacore.c` (6 hits — `c64d_ciacore_peek` and IRQ flag) +- `root/cia.h` (1 hit — struct field `c64d_irq_flag`) +- `core/viacore.c` (2 hits — `c64d_viacore_peek`) +- `root/via.h` (2 hits — struct field `c64d_irq_flagged`) +- `drive/iec/via1d1541.c` (IRQ flag set on via interrupt) +- `viciisc/vicii-irq.c` (4 hits — VIC IRQ flag) +- `viciisc/viciitypes.h` (1 hit — struct field `c64d_irq_flag`) + +**Representative symbols:** +- `c64d_cia1_peek(addr)` / `c64d_cia2_peek(addr)` — side-effect-free CIA register reads +- `c64d_ciacore_peek(cia_context, addr)` — core CIA peek implementation +- `c64d_cia1_register_read` / `c64d_cia1_register_written` / `c64d_cia1_read_value` / `c64d_cia1_write_value` — per-access state variables (extern globals) +- Same set for `cia2_` +- `c64d_viacore_peek(via_context, addr)` — VIA core peek +- `c64d_get_cia_context(num)` — return CIA context pointer +- `c64d_refresh_cia` — force CIA state refresh +- `c64d_c64_check_irqcia_breakpoint()` / `c64d_c64_check_irqnmi_breakpoint()` — IRQ breakpoint checks +- `c64d_c64_is_checking_irq_breakpoints_enabled()` / `c64d_drive1541_is_checking_irq_breakpoints_enabled()` — predicate +- `c64d_irq_flag` struct field on `cia_context_t` (set when CIA triggers IRQ) +- `c64d_irq_flagged` struct field on `via_context_t` +- `c64d_irq_flag` / `c64d_irq_flag_needs_clear` / `c64d_irqbrk_irq_source` — VIC IRQ observation globals +- `c64d_irqbrk_entry_type_base` — IRQ entry type classification + +**Style:** Additive for peek functions. The register-read/write observation is a non-additive +insertion: in `c64cia1.c` and `c64cia2.c`, both `ciacore_store()` and `ciacore_read()` calls +are wrapped so the observed address/value is captured before/after the real call. +`ciacore.c:ciacore_store()` had its parameter renamed from `byte` to `value` (non-additive: both +original and new logic remain but the variable name changed throughout). `cia_update_ta` / +`cia_update_tb` had `static` removed. + +**Hook count (distinct symbols):** ~25 + +**3.10 impact:** `c64cia1.c` and `c64cia2.c` exist in 3.10. `core/ciacore.c` exists in 3.10. +`viciisc/vicii-irq.c` exists in 3.10. **Risk: LOW-MEDIUM** — file paths stable; the observation +wrappers need re-insertion at the same call sites. + +--- + +### Category 7: VIC-II State Observer + +**Purpose:** Capture VIC-II raster state, color registers, border mode, and frame events for the +debugger's VIC viewer and cycle-accurate state snapshots. + +**Files involved:** +- `viciisc/vicii.c` (8 hits) +- `viciisc/vicii-cycle.c` (5 hits) +- `viciisc/vicii-draw-cycle.c` (5 hits) +- `viciisc/vicii-irq.c` (4 hits) +- `viciisc/viciitypes.h` (1 hit — struct field additions) + +**Representative symbols:** +- `c64d_c64_vicii_cycle()` — called at end of every `vicii_cycle()` +- `c64d_c64_vicii_start_frame()` — called at start-of-frame detection +- `c64d_c64_vicii_start_raster_line(line)` — called at start of each raster line +- `c64d_c64_set_vicii_record_state_mode(mode)` / `c64d_vicii_record_state_mode` — state recording control +- `c64d_c64_vicii_store_state_to_bytebuffer()` / `c64d_c64_vicii_restore_state_from_bytebuffer()` — snapshot helpers +- `c64d_get_vicii_state_for_raster_cycle()` / `c64d_get_vicii_state_for_raster_line()` — state readouts +- `c64d_vicii_copy_state()` / `c64d_vicii_copy_state_data` — copy current VIC state +- `c64d_set_color_register(regNum, val)` — write color register (injected in draw-cycle) +- `c64d_get_vic_colors()` / `c64d_get_vic_simple_state()` — bulk readouts +- `c64d_get_vicii_border_mode()` / `c64d_set_vicii_border_mode(mode)` — border control +- `c64d_fetch_phi1_type(addr)` — classify VIC phi-1 fetch (RAM / charROM / cart) +- `c64d_vicii_render_when_paused()` — force render update while paused +- `c64d_vicii_get_geometry(...)` — canvas geometry readout +- `c64d_skip_drawing_sprites` — flag to suppress sprite rendering +- `c64d_refresh_dbuf()` — force display buffer refresh when paused +- `c64d_refresh_previous_lines` / `c64d_refresh_screen` / `c64d_refresh_screen_no_callback` +- Struct field additions to `vicii_t` in `viciitypes.h`: `c64d_irq_flag`, `register_written`, + `prev_register_written`, `register_read`, `prev_register_read` + +**Style:** Mixed. Most new symbols are additive. The sprite drawing block in +`vicii-draw-cycle.c` is wrapped in `if (c64d_skip_drawing_sprites == 0)` — genuine control-flow +change. The `VICE_DEBUG` vs `DEBUG` conditional change in `vicii-cycle.c` is a non-additive rename. + +**Static promotions in this category:** +- `vicii.c`: `fetch_phi1_type` promoted to external linkage + +**Hook count (distinct symbols):** ~20 + +**3.10 impact:** `viciisc/vicii.c`, `vicii-cycle.c`, `vicii-draw-cycle.c`, `vicii-irq.c` all +exist in 3.10. 3.10's monitor is in a `monitor/` subdirectory (existing in 3.1 as well). +**Risk: MEDIUM** — file paths stable; the hooks inside the raster loop are insertion-point +sensitive. + +--- + +### Category 8: SID Observer + +**Purpose:** Capture SID register reads/writes, provide voice masking, waveform callbacks, and +per-channel audio data for the debugger's SID viewer and audio analyzer. + +**Files involved:** +- `sid/sid.c` (17 hits) +- `sid/sid-snapshot.c` (10 hits) +- `sid/sid-resources.c` (8 hits) + `sid/sid-resources.h` (8 hits) +- `sid/fastsid.c` (2 hits) +- `resid/resid-sid.cpp` (3 hits) + `resid/resid-sid.h` (1 hit) + `resid/resid-filter.h` (5 hits) + `resid/resid-filter.cpp` (1 hit) +- `resid-fp/residfp-sid.cpp` (10 hits) + `resid-fp/residfp-sid.h` (2 hits) + `resid-fp/residfp-voice.h` (3 hits) + +**Representative symbols:** +- `c64d_sid_register_read` / `c64d_sid_read_value` — last-read register address/value (extern globals) +- `c64d_sid_register_written` / `c64d_sid_write_value` — last-written register address/value +- `c64d_sid_voiceMask` — bitmask for voice enable/disable (per chip) +- `c64d_store_sid_data(buf, sidNum)` — copy SID register array to buffer +- `c64d_sid_read(addr)` / `c64d_sid_write(addr, val)` — instrumented SID access +- `c64d_get_sid_enable()` — predicate for SID enable status +- `c64d_sid_set_engine_model_direct(engine, model)` — force-set engine and model +- `c64d_sid_set_emulate_filters(val)` — filter emulation toggle +- `c64d_sid_set_sampling_method(method)` — sampling method control +- `c64d_sid_set_passband(val)` / `c64d_sid_set_filter_bias(val)` — filter parameters +- `c64d_sid_set_stereo(stereo)` / `c64d_sid_set_stereo_address(addr)` / `c64d_sid_set_triple_address(addr)` — multi-SID config +- `c64d_is_receive_channels_data[chipNo]` — flag array: whether per-channel data is requested +- `c64d_sid_channels_data(chipNo, v1, v2, v3, mixed)` — per-voice audio data callback +- `c64d_waveform_callback` — C++ constructor parameter / function pointer for waveform data +- `c64d_wave_attenuation` / `c64d_wave_shift` — waveform scaling parameters (ReSID-FP) +- `c64d_output` (field on `Voice`) — per-voice sample capture in ReSID-FP +- `c64d_lock_sound_mutex(who)` / `c64d_unlock_sound_mutex(who)` — threaded snapshot protection +- `c64d_sound_init()` / `c64d_sound_pause()` / `c64d_sound_resume()` — sound lifecycle +- `c64d_sound_run_sound_when_paused` / `c64d_skip_sound_run_sound_in_sound_store` — control flags +- `c64d_setting_run_sid_emulation` / `c64d_setting_run_sid_when_in_warp` — SID run flags +- `c64d_reset_sound_clk` — reset sound clock on pause +- `c64d_store_vicii_state_with_snapshot` — save VIC state alongside SID snapshot + +**Genuine non-additive changes:** +- `sid.c`: `sid_read_chip()` return path restructured to always capture into `val`, then + observe before returning (control-flow change — else-if chain changed). +- `sid-snapshot.c`: snapshot write function gated with `c64d_get_sid_enable()` check. +- `resid/resid-filter.cpp`: 8580 SID section (180+ lines) **deleted**. +- `resid/resid-sid.cpp`: `SID::read()` no longer updates `bus_value_ttl`; `SID::write()` uses + fixed `bus_value_ttl = 0x4000` instead of `databus_ttl`; write pipeline behavior changed. + +**Static promotions in this category:** +- `sid.c`: `sid_peek_chip`, `sid_store_chip` promoted +- `sid-resources.c`: `set_sid_engine`, `set_sid_model` promoted +- `fastsid.c`: `fastsid_set_voice_mask` added (new function) + +**Hook count (distinct symbols):** ~35 + +**3.10 impact:** `sid/sid.c`, `sid/sid-snapshot.c`, `sid/fastsid.c`, `sid/sid-resources.c` +exist in 3.10. ReSID is at `resid/` in 3.10 (same path); ReSID-FP (`resid-fp/`) exists in 3.10 +(this is a slajerek addition not in vanilla). The 8580 filter deletion in +`resid/resid-filter.cpp` means 3.10's filter.cc has the 8580 code again — this must be +re-deleted or gated. **Risk: MEDIUM-HIGH** for ReSID (behavioral changes are subtle). + +--- + +### Category 9: Sound Driver (SDL Audio) + +**Purpose:** Rewrite the SDL audio callback to support multi-channel output (mono/stereo/triple +SID) with the RetroDebugger audio pipeline. + +**Files involved:** +- `sounddrv/soundsdl.c` (4 hits) + +**Representative symbols:** +- `sidNumChannels` — global for active channel count +- `c64d_set_volume(float)` — volume control (wraps `set_volume`) +- `c64d_wave_attenuation`, `c64d_wave_shift` — referenced via extern + +**Genuine non-additive changes:** +- The entire `sdl_callback()` function body was replaced: parameter type changed + (`Uint8 *stream, int len` → `uint8 *stream, int numSamples`), logic now branches on + `sidNumChannels` for mono vs stereo handling, doing explicit per-sample interleaving. +- `USE_SDL_AUDIO` / `ANDROID_COMPILE` conditional blocks removed. +- `static SDL_AudioSpec sdl_spec` commented out. + +**Hook count (distinct symbols):** ~3 (plus the rewrite) + +**3.10 impact:** In 3.10, `soundsdl.c` moved to `arch/shared/sounddrv/soundsdl.c`. The 3.10 +version is structurally closer to the vanilla 3.1 version (SDL callback still mono). The +slajerek rewrite will need to be replayed at the new path, against a 3.10 callback that already +differs from 3.1. **Risk: HIGH** — path moved, and 3.10 version already diverged from 3.1. + +--- + +### Category 10: Monitor Integration + +**Purpose:** Integrate VICE's built-in monitor with the RetroDebugger step/trace/run commands. + +**Files involved:** +- `monitor/monitor.c` (5 hits) +- `arch/uimon.c` (4 hits) + +**Representative symbols:** +- `c64d_set_debug_mode(mode)` — called from `mon_instructions_step()`, `mon_instructions_next()`, + `mon_instruction_return()` to transition to RUNNING after a step +- `execute_monitor_command_jump_trap` / `c64d_execute_monitor_command_jump_trap` — trampoline + injected into `mon_jump()` for async jump execution +- `c64d_uimon_buf` / `c64d_uimon_bufpos` — output buffer for monitor text +- `c64d_uimon_print(str)` / `c64d_uimon_print_line(str)` — write to monitor buffer +- `c64d_console_log` — `console_t` struct for monitor window routing + +**Genuine non-additive changes:** +- `monitor.c`: A closing `}` + `monitor_close(1)` call restructured around the + `execute_monitor_command_jump_trap` trampoline (the original call is conditional on whether it + returns a non-jump result). `make_prompt`, `monitor_open`, `monitor_process`, `monitor_close` + had `static` removed. +- `arch/uimon.c`: Completely new file (not in vanilla SDL arch) — provides the `uimon_*` console + interface routing output to `c64d_uimon_buf`. + +**Hook count (distinct symbols):** ~8 + +**3.10 impact:** `monitor/monitor.c` exists in 3.10 inside `monitor/` directory (as in 3.1). +3.10's `monitor.c` is significantly larger (3421 vs 2389 lines) — substantial new code. The +`static` promotions and `c64d_set_debug_mode` injection points may have shifted considerably. +**Risk: HIGH** — monitor grew substantially; injection points need to be re-identified. + +--- + +### Category 11: Keyboard & Input + +**Purpose:** Provide latch-based keyboard/joystick injection for the debugger API. + +**Files involved:** +- `root/keyboard.c` (6 hits) +- `root/keyboard.h` (1 hit) +- `joyport/joystick.c` (10 hits) +- `joyport/mouse.c` (2 hits) +- `arch/mousedrv.c` (2 hits) + +**Representative symbols:** +- `c64d_keyboard_init()` — initialize keyboard matrix constants (lshift/rshift row/col) +- `c64d_keyboard_key_down_latch(keycode)` / `c64d_keyboard_key_up_latch(keycode)` — latch key events +- `c64d_keyboard_force_key_up_latch(keycode)` — force key release +- `c64d_keyboard_keymap_clear()` — clear keymap +- `c64d_joystick_key_down(key, joyport)` / `c64d_joystick_key_up(key, joyport)` — joystick input +- `c64d_joystick_latch_matrix_workaround` — workaround flag +- `c64d_mouse_set_type(mt)` — set mouse type +- `c64d_mouse_type_to_joyportid(mouseType)` — map mouse type to joyport ID +- `c64d_mouse_set_position(x, y)` / `c64d_set_mouse_pos(x, y)` — mouse position injection + +**Genuine non-additive changes:** +- `keyboard.c`: `keyboard_key_pressed()` return type changed from `void` to `int` (returns 0/1 + to indicate success). `keyboard_set_latch_keyarr()`, `keyboard_key_pressed_matrix()` had + `static` removed. +- `joystick.c`: `joystick_process_latch()` bypass — `delay` forced to 0 and `alarm_set()` is + replaced by direct `joystick_latch_matrix(0)` call (the random delay was removed). + +**Hook count (distinct symbols):** ~12 + +**3.10 impact:** `keyboard.c`, `joystick.c`, `mouse.c` exist in 3.10 at same paths. +**Risk: LOW-MEDIUM** — the return type change on `keyboard_key_pressed()` must be tracked; +joystick latch change may conflict with 3.10's joystick handling. + +--- + +### Category 12: Snapshot / State Manager + +**Purpose:** Extended snapshot system: in-memory snapshots, screen save, REU/cart data inclusion, +per-frame snapshot manager, and SID enable guard. + +**Files involved:** +- `c64/c64-snapshot.c` (6 hits) +- `sid/sid-snapshot.c` (see Category 8) +- `c64/c64cpusc.c` (snapshot manager functions) + +**Representative symbols:** +- `c64d_snapshot_write_module(s, save_screen)` / `c64d_snapshot_read_module(s)` — write/read the + RetroDebugger-specific snapshot module +- `c64_snapshot_write()` — signature extended with `save_reu_data`, `save_cart_roms`, `save_screen` params +- `c64_snapshot_write_in_memory()` — new function: create snapshot in memory buffer +- `c64d_start_frame_for_snapshots_manager()` — called each frame to manage auto-snapshots +- `c64d_check_snapshot_interval()` / `c64d_check_snapshot_restore()` — interval-based snapshot trigger +- `c64d_check_cpu_snapshot_manager_store()` / `c64d_check_cpu_snapshot_manager_restore()` — CPU-side snapshot hooks +- `c64d_is_performing_snapshot_restore` — flag during restore +- `c64d_store_vicii_state_with_snapshot` — co-save VIC state + +**Genuine non-additive changes:** +- `c64-snapshot.c`: `c64_snapshot_write()` signature changed (new params); `snapshot_create()` + call gains new `0` param (snapshot format version). `c64_snapshot_write_module()` call gains + three new params. A large new function `c64_snapshot_write_in_memory()` is appended. + +**Hook count (distinct symbols):** ~12 + +**3.10 impact:** `c64/c64-snapshot.c` exists in 3.10 but with structural changes (SNAP_MAJOR +changed from 2 to 1 in 3.1→3.10? No — 3.10 uses 1.1 vs 3.1 uses 1.1 as well but with different +module list). The signature changes to `c64_snapshot_write()` must be replayed carefully. +**Risk: MEDIUM** — snapshot API evolved between versions. + +--- + +### Category 13: Profiler + +**Purpose:** Built-in CHAMP-style profiler for C64 code: JSR/RTS call stack tracking, cycle-per- +function accounting, watchpoints. + +**Files involved:** +- `c64/c64cpusc.c` (profiler implementation — all under `#ifdef USE_CHAMP_PROFILER` / `#ifndef`) + +**Representative symbols:** +- `c64d_profiler_init()` / `c64d_profiler_activate(file, cycles, pauseWhenDone)` / `c64d_profiler_deactivate()` +- `c64d_profiler_jsr(target)` / `c64d_profiler_rts()` — JSR/RTS tracking +- `c64d_profiler_start_handle_cpu_instruction()` / `c64d_profiler_end_cpu_instruction()` — per-instruction callbacks +- `c64d_profiler_is_active` — flag +- `c64d_profiler_cpu_total_cycles` / `c64d_profiler_cycles_per_function[]` / `c64d_profiler_calls_per_function[]` — counters +- `c64d_profiler_trace_stack[N]` / `c64d_profiler_trace_stack_pointer` / `c64d_profiler_trace_stack_function[]` — call stack +- `c64d_profiler_watches[]` / `c64d_profiler_watch_count` / `c64d_profiler_watches_allocated` / `c64d_profiler_watch_offset_for_pc_and_post()` — watchpoints +- `c64d_profiler_last_cycles` / `c64d_profiler_old_pc` — per-instruction state +- `c64d_profiler_file_out` — output FILE pointer +- `c64d_activate_profiler` — flag + +**Style:** Entirely additive. All profiler code is appended to `c64cpusc.c` with `#ifdef +USE_CHAMP_PROFILER` guard. Stub implementations provided under `#ifndef USE_CHAMP_PROFILER`. + +**Hook count (distinct symbols):** ~18 + +**3.10 impact:** Profiler is self-contained in `c64cpusc.c` additions. The injection points +(profiler calls inside the CPU instruction loop) depend on the inlined `mainc64cpu.c` structure. +3.10's `mainc64cpu.c` exists at `src/mainc64cpu.c` (same path as 3.1). **Risk: LOW** — profiler +is additive and self-contained. + +--- + +### Category 14: System Lifecycle / Arch Callbacks + +**Purpose:** Machine lifecycle hooks, display callbacks, mutex management, and arch-level +integration (JAM, speed, LED, screen refresh). + +**Files involved:** +- `arch/ui.c` (5 hits) +- `arch/uimon.c` (4 hits — see Category 10) +- `arch/video.c` (1 hit — screen refresh) +- `arch/vsyncarch.c` (1 hit — speed display) +- `arch/uistatusbar.c` (1 hit — drive LED) +- `arch/uimsgbox.c` (1 hit — message display) +- `arch/mousedrv.c` (2 hits — mouse position) +- `root/vsync.c` (5 hits — vsync/sound mutex) +- `root/machine.c` (2 hits — machine pause) +- `root/sound.c` (23 hits — sound lifecycle) + +**Representative symbols:** +- `c64d_set_debug_mode(mode)` — central debug mode state machine (defined in `c64cpusc.c`, + declared/called widely) +- `c64d_debug_mode` — global mode variable +- `c64d_debug_pause_check()` — called in tight loops to check for pause requests +- `c64d_stop_vice_emulation()` — halt the emulation loop +- `c64d_vice_run_emulation()` — start/resume emulation +- `c64d_is_debug_on_c64()` / `c64d_is_debug_on_drive1541()` — mode predicates +- `c64d_lock_mutex(who)` / `c64d_unlock_mutex(who)` — main emulator mutex +- `c64d_lock_sound_mutex(who)` / `c64d_unlock_sound_mutex(who)` — sound thread mutex +- `c64d_refresh_screen()` / `c64d_refresh_screen_no_callback()` — force screen update +- `c64d_clear_screen()` — blank screen buffer +- `c64d_display_speed(speed, fps)` — update speed display +- `c64d_display_drive_led(drive, pwm1, pwm2)` — drive LED state +- `c64d_show_message(msg)` — show UI message +- `c64d_output(str)` — console output +- `c64d_console_log` — console_t routing struct +- `c64d_get_frame_num()` — frame counter +- `c64d_screen_num_skip_top_lines` — display crop control +- `c64d_setting_render_transparent_screen` — transparency flag +- `c64d_update_c64_model()` / `c64d_update_c64_machine_from_model_type()` / `c64d_update_c64_screen_height_from_model_type()` — model management +- `c64d_is_cpu_in_jam_state` — CPU JAM flag set in `arch/ui.c` + +**Genuine non-additive changes in this category:** +- `root/vsync.c`: `vsync_do_vsync()` signature changed: new `isPaused` parameter; + `vsync_hook()` call gated on `!isPaused`; `sound_flush()` call wrapped in mutex; + `sound_flush()` itself gains `isPaused` parameter; `set_warp_mode()` had `static` removed. +- `root/sound.c`: `set_volume()` had `static` removed; `ui_error()` call replaced with + `LOGError()` (no UI popup on sound error); `sound_open()` loop adds `// LOGD` traces but + original loop logic unchanged. + +**Hook count (distinct symbols):** ~25 + +**3.10 impact:** `arch/` files are slajerek's own (no vanilla counterpart). `root/vsync.c` maps +to `vsync.c` in 3.10 at root level. `vsync_do_vsync()` signature change must be tracked in +3.10's version. `root/sound.c` maps to `sound.c` in 3.10 (still at root, still present). +**Risk: MEDIUM** — vsync and sound changes are sensitive to 3.10 API changes. + +--- + +### Category 15: ROM / KERNAL Patching + +**Purpose:** Fast-boot KERNAL patch and ROM update hooks. + +**Files involved:** +- `c64/c64memsc.c` (2 hits — patch/unpatch implementation) +- `c64/c64memrom.c` (1 hit — ROM update) +- `c64/patchrom.c` (7 hits — trigger patching on ROM refresh) + +**Representative symbols:** +- `c64d_patch_kernal_fast_boot()` — patch KERNAL ROM for fast boot +- `c64d_un_patch_kernal_fast_boot()` — restore KERNAL ROM +- `c64d_patch_kernal_fast_boot_flag` — enable/disable flag +- `c64d_update_rom()` — copy ROM to trap ROM copy after ROM load +- `c64d_trigger_update_roms()` / `c64d_update_roms` — trigger ROM refresh +- `c64d_update_rom` — callback registered with ViceInterface + +**Style:** Additive. ROM patch calls are inserted in `patchrom.c` around the existing +`c64memrom_patch_kernal()` logic. + +**Hook count (distinct symbols):** ~6 + +**3.10 impact:** `c64/patchrom.c` and `c64/c64memrom.c` exist in 3.10. **Risk: LOW**. + +--- + +## Non-Additive Patches Table + +The following files have genuine logic changes beyond header-rename and `static`-removal noise. + +| File | Genuine deletions | What changed | Inferred why | +|------|-------------------|--------------|--------------| +| `c64/c64cpusc.c` | Structural | `#include "../mainc64cpu.c"` replaced by inlined content + hooks | Required to inject hooks at exact points in instruction fetch/execute loop; can't inject into a separately compiled TU | +| `drive/drivecpu.c` | Structural | `#include "6510core.c"` replaced by inlined content + hooks | Same reason as c64cpusc.c — drive 6510 needed per-cycle hooks | +| `sounddrv/soundsdl.c` | ~100 lines | SDL callback completely rewritten for mono/stereo/triple SID support | Needed multi-channel audio routing for SID waveform capture | +| `resid/resid-filter.cpp` | ~261 lines | 8580 SID filter section deleted; only 6581 filter kept | slajerek targets only 6581 emulation (ReSID-FP handles 8580 path) | +| `resid/resid-sid.cpp` | ~89 lines | `SID::read()` POT/OSC/ENV path bypasses `bus_value_ttl` update; write pipeline behavior changed; `SID()` constructor gains `c64d_waveform_callback` parameter | Waveform callback injection; TTL behavior simplification | +| `c64/c64memsc.c` | 1 line | `BYTE mem_ram[C64_RAM_SIZE]` → `BYTE *mem_ram` (pointer externally set) | Allows memory-mapped file backing for the RAM buffer | +| `sid/sid.c` | ~15 lines | `sid_read()` restructured to always capture return value before returning (added else-if chain); `sid_sound_machine_open()` gains `chipno` parameter; SID engine open call updated | Needed to observe the actual returned SID read value | +| `sid/sid-snapshot.c` | ~15 lines | Snapshot write gated on `c64d_get_sid_enable()`; mutex wraps around `sound_open()` call | Prevent crash when SID is disabled; thread safety for snapshot | +| `root/vsync.c` | ~9 lines | `vsync_do_vsync()` gains `isPaused` parameter; `vsync_hook()` gated; `sound_flush()` gains `isPaused` param | Suppress vsync side-effects (sound events) when emulator is paused | +| `root/keyboard.c` | ~15 lines | `keyboard_key_pressed()` return type `void` → `int` | Return value needed by ViceInterface to check if key was accepted | +| `joyport/joystick.c` | ~3 lines | `joystick_process_latch()` bypass of random delay | Avoid timing non-determinism in debugger-driven key injection | +| `joyport/mouse.c` | ~2 lines | `joyport_mouse_enable()` / `set_mouse_enabled()` static removal | ViceInterface needs to call these directly | +| `c64/c64-snapshot.c` | ~9 lines | `c64_snapshot_write()` signature extended; `snapshot_create()` call updated; large new `c64_snapshot_write_in_memory()` function added | Extended snapshot capability needed by state manager | +| `viciisc/vicii-draw-cycle.c` | ~14 lines | Sprite draw block wrapped in `c64d_skip_drawing_sprites` condition | Allow suppressing sprites in debugger rendering | +| `viciisc/viciitypes.h` | ~5 lines | New struct fields added to `vicii_t`; some debug `#define` guards changed from `/* #define */` to active/commented | Need per-cycle register observation fields | + +**Note:** Files with only header-rename (`types.h` → `vicetypes.h`) and `static` removal are NOT +listed here. Those changes affect nearly all 64 modified files. They must be replayed as a +mechanical step during Phase 4. + +--- + +## Top Hotspot Files + +| Rank | File | `c64d_` hits | Primary categories | +|------|----|---|---| +| 1 | `c64/c64cpusc.c` | 283 | CPU Step, Memory R/W taps, Profiler, Snapshot, Lifecycle | +| 2 | `drive/drivecpu.c` | 97 | Drive State Observer | +| 3 | `c64/c64memsc.c` | 34 | Memory Read/Write taps | +| 4 | `iecbus/iecbus.c` | 25 | Drive State Observer (wrapper dispatch) | +| 5 | `root/sound.c` | 23 | SID Observer, Sound Driver | +| 6 | `drive/iec/memiec.c` | 18 | Drive State Observer (IEC memory) | +| 7 | `sid/sid.c` | 17 | SID Observer | +| 8 | `c64/c64cia2.c` | 13 | CIA/VIA Observer | +| 9 | `drive/iec/via1d1541.c` | 12 | Drive State Observer (VIA-1) | +| 10 | `drive/drive.c` | 12 | Drive State Observer (GCR dirty) | +| 11 | `sid/sid-snapshot.c` | 10 | SID Observer, Snapshot | +| 12 | `resid-fp/residfp-sid.cpp` | 10 | SID Observer (ReSID-FP) | +| 13 | `joyport/joystick.c` | 10 | Keyboard & Input | +| 14 | `drive/iecieee/via2d.c` | 10 | Drive State Observer (VIA-2) | +| 15 | `viciisc/vicii.c` | 8 | VIC-II State Observer | + +--- + +## Per-Directory Summary + +| Count | Directory | Primary category | +|-------|-----------|-----------------| +| 12 | `root/` | CPU clock, sound, vsync, keyboard | +| 10 | `drive/` | Drive State Observer | +| 9 | `c64/` | CPU step, memory, CIA, snapshot, ROM | +| 8 | `arch/` | System lifecycle callbacks | +| 5 | `viciisc/` | VIC-II State Observer | +| 5 | `sid/` | SID Observer | +| 4 | `resid/` | SID Observer (ReSID backend) | +| 3 | `resid-fp/` | SID Observer (ReSID-FP backend) | +| 3 | `core/` | CIA/VIA Observer (ciacore, viacore, flash040) | +| 2 | `joyport/` | Keyboard & Input | +| 1 | `sounddrv/` | Sound Driver (SDL) | +| 1 | `monitor/` | Monitor Integration | +| 1 | `iecbus/` | Drive State Observer (wrapper) | + +--- + +## Symbol-to-File Index + +All 282 distinct `c64d_*` symbols. Format: **symbol** — defined in `file` — called in `files`. +Where a symbol is a global variable (not a function), "defined" means the declaration with initializer. + +### CPU / Clock + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_maincpu_clk` | `c64/c64cpusc.c` | `c64/cart/reu.c`, `core/flash040core.c`, `root/dma.c`, `root/midi.c`, `root/interrupt.h`, `root/maincpu.h`, `viciisc/vicii-cycle.c`, `sid/sid.c`, `c64/c64cpusc.c` (CLK_INC macro) | +| `c64d_maincpu_current_instruction_clk` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_maincpu_previous_instruction_clk` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_maincpu_previous2_instruction_clk` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_c64_instruction_cycle` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_c64_do_cycle` | `c64/c64cpusc.c` | `c64/c64cpusc.c` (CLK_INC macro) | +| `c64d_do_cycle` | `drive/drivecpu.c` | `drive/drivecpu.c` | +| `c64d_get_maincpu_clock` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_get_vice_maincpu_clk` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_get_vice_maincpu_current_instruction_clk` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_reset_counters` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_reset_sound_clk` | `root/sound.c` | ViceInterface | + +### CPU Registers / Control + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_get_maincpu_regs` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_set_maincpu_regs` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_set_maincpu_regs_no_trap` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_set_c64_pc` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_set_maincpu_set_a/x/y/p/sp` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_maincpu_make_basic_run` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_get_drivecpu_regs` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_get_drivecpu_regs_internal` | `drive/drivecpu.c` | `iecbus/iecbus.c` | +| `c64d_set_drivecpu_pc_no_trap` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drivecpu_regs_no_trap` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drive_register_a/x/y/p/sp` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drive_pc` | `drive/drivecpu.c` | ViceInterface | +| `c64d_is_cpu_in_jam_state` | `arch/ui.c` | ViceInterface | +| `c64d_interrupt_drivecpu_trigger_trap` | `drive/drivecpu.c` | ViceInterface | + +### Debug Mode / Lifecycle + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_set_debug_mode` | `c64/c64cpusc.c` | `monitor/monitor.c`, `arch/ui.c`, `root/machine.c`, `root/midi.c` | +| `c64d_debug_mode` | `c64/c64cpusc.c` | `root/sound.c`, `viciisc/vicii-draw-cycle.c`, `resid/resid-sid.cpp` | +| `c64d_debug_pause_check` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_stop_vice_emulation` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_vice_run_emulation` | ViceInterface def | Called from ViceInterface | +| `c64d_is_debug_on_c64` | `c64/c64cpusc.c` | `drive/iec/via1d1541.c` | +| `c64d_is_debug_on_drive1541` | `drive/drivecpu.c` | `drive/iec/via1d1541.c` | +| `c64d_shutdown_vice` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_get_warp_mode` | `root/vsync.c` | ViceInterface | +| `c64d_get_frame_num` | ViceInterface def | ViceInterface | +| `c64d_lock_mutex` / `c64d_unlock_mutex` | ViceInterface def | `joyport/joystick.c` | +| `c64d_lock_sound_mutex` / `c64d_unlock_sound_mutex` | ViceInterface def | `root/vsync.c`, `sid/sid-snapshot.c` | + +### Memory Access — C64 + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_mark_c64_cell_read` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_mark_c64_cell_write` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_mark_c64_cell_execute` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_init_memory` | `c64/c64memsc.c` | ViceInterface | +| `c64d_peek_c64` | `c64/c64memsc.c` | ViceInterface, `c64/c64cpusc.c` | +| `c64d_peek_c64_for_cycle` | `c64/c64memsc.c` | ViceInterface | +| `c64d_peek_io` | `c64/c64memsc.c` | ViceInterface | +| `c64d_peek_memory0001` | `c64/c64memsc.c` | ViceInterface | +| `c64d_peek_memory_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_peek_whole_map_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_copy_ram_memory_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_copy_whole_mem_ram_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_mem_ram_read_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_mem_ram_write_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_mem_ram_fill_c64` | `c64/c64memsc.c` | ViceInterface | +| `c64d_mem_write_c64` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_mem_write_c64_no_mark` | `c64/c64cpusc.c` | ViceInterface, `c64/c64cpusc.c` | +| `c64d_mem_store` / `c64d_mem_store_zero` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_mem_access_addr` / `c64d_mem_access_value` / `c64d_mem_access_is_write` / `c64d_mem_access_watch` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_peek_cart_roml` | `c64/cart/c64-generic.c` | ViceInterface | +| `c64d_poke_cart_roml` | `c64/cart/c64-generic.c` | ViceInterface | +| `c64d_colorram_peek` | `c64/c64memsc.c` | ViceInterface | +| `c64d_get_exrom_game` | `c64/c64memsc.c` | ViceInterface | +| `c64d_get_ultimax_phi` | `c64/c64memsc.c` | ViceInterface | + +### Memory Access — Drive + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_mark_drive1541_cell_read` | ViceInterface def | `drive/iec/memiec.c`, `drive/drivemem.c`, `drive/iecieee/via2d.c`, `drive/iec/via1d1541.c` | +| `c64d_mark_drive1541_cell_write` | ViceInterface def | `drive/iec/memiec.c`, `drive/drivemem.c`, `drive/iecieee/via2d.c`, `drive/iec/via1d1541.c` | +| `c64d_mark_drive1541_cell_execute` | ViceInterface def | `drive/drivecpu.c` | +| `c64d_peek_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_peek_mem_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_peek_memory_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_peek_memory_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_peek_whole_map_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_peek_whole_map_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_copy_ram_memory_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_copy_ram_memory_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_copy_mem_ram_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_copy_mem_ram_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_mem_ram_read_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_mem_ram_read_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_mem_ram_write_drive` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_mem_ram_write_drive_internal` | `drive/iec/memiec.c` | `iecbus/iecbus.c` | +| `c64d_drive_poke` | `iecbus/iecbus.c` | ViceInterface | +| `c64d_iecbus_cpu_peek_conf1` | `iecbus/iecbus.c` | `core/ciacore.c` | + +### Drive State + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_get_drive_context` | `drive/drivecpu.c` | ViceInterface | +| `c64d_get_drive_disk_gcr` | `drive/drivecpu.c` | ViceInterface | +| `c64d_get_drive_disk_image` | `drive/drivecpu.c` | ViceInterface | +| `c64d_get_drive_is_disk_attached` | `drive/drivecpu.c` | ViceInterface | +| `c64d_get_drive_current_halftrack` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drive_half_track` | `drive/drivecpu.c` | ViceInterface | +| `c64d_read_disk_image` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drive_disk_memory` | `drive/drivecpu.c` | ViceInterface | +| `c64d_mark_drive1541_contents_track_dirty` | `drive/rotation.c` | `drive/rotation.c` | +| `c64d_is_drive_dirty_for_snapshot` | `drive/drivecpu.c` | ViceInterface | +| `c64d_is_drive_dirty_and_needs_refresh` | `drive/drivecpu.c` | ViceInterface | +| `c64d_clear_drive_dirty_for_snapshot` | `drive/drivecpu.c` | ViceInterface | +| `c64d_clear_drive_dirty_needs_refresh_flag` | `drive/drivecpu.c` | ViceInterface | +| `c64d_set_drive_dirty_needs_refresh_flag` | `drive/drivecpu.c` | ViceInterface | +| `c64d_disk_image_destroy` | `drive/drivecpu.c` | ViceInterface | +| `c64d_drive_writeprotect_sense_peek` | `drive/drive-writeprotect.c` | `drive/iecieee/via2d.c` | +| `c64d_drive_cpu_stack_entry_types` / `c64d_drive_cpu_stack_irq_sources` / `c64d_drive_cpu_stack_origin_pc` | `drive/drivecpu.c` | ViceInterface | +| `c64d_drive_irqbrk_irq_source` | `drive/drivecpu.c` | ViceInterface | +| `c64d_drive1541_check_pc_breakpoint` | `drive/drivecpu.c` | ViceInterface | +| `c64d_drive1541_check_irqvia1_breakpoint` / `c64d_drive1541_check_irqvia2_breakpoint` / `c64d_drive1541_check_irqiec_breakpoint` | `drive/drivecpu.c` | ViceInterface | +| `c64d_drive1541_is_checking_irq_breakpoints_enabled` | `drive/drivecpu.c` | `drive/drivecpu.c` | + +### CIA / VIA / VIC-II Observer + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_cia1_peek` / `c64d_cia2_peek` | `c64/c64cia2.c` | `c64/c64memsc.c`, ViceInterface | +| `c64d_ciacore_peek` | `core/ciacore.c` | `c64/c64cia2.c` | +| `c64d_cia1_register_read` / `c64d_cia1_read_value` | `c64/c64cpusc.c` (extern) | `c64/c64cia1.c` (set), ViceInterface (read) | +| `c64d_cia1_register_written` / `c64d_cia1_write_value` | `c64/c64cpusc.c` (extern) | `c64/c64cia1.c` (set), ViceInterface (read) | +| `c64d_cia2_register_read/written` / `c64d_cia2_read/write_value` | `c64/c64cpusc.c` (extern) | `c64/c64cia2.c` (set), ViceInterface (read) | +| `c64d_get_cia_context` | `core/ciacore.c` | ViceInterface | +| `c64d_refresh_cia` | ViceInterface def | — | +| `c64d_viacore_peek` | `core/viacore.c` | `drive/iec/via1d1541.c`, `drive/iecieee/via2d.c` | +| `c64d_via1d1541_peek` | `drive/iec/via1d1541.c` | `drive/iec/memiec.c` | +| `c64d_peek_via1d1541_pra/prb` | `drive/iec/via1d1541.c` | `drive/iec/via1d1541.c` | +| `c64d_via2d_peek` | `drive/iecieee/via2d.c` | `drive/iec/memiec.c` | +| `c64d_peek_via2d_pra/prb` | `drive/iecieee/via2d.c` | `drive/iecieee/via2d.c` | +| `c64d_peek_via_context` / `c64d_viacore_peek` | `core/viacore.c` | various via peek functions | +| `c64d_c64_check_irqcia_breakpoint` / `c64d_c64_check_irqnmi_breakpoint` / `c64d_c64_check_irqvic_breakpoint` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_c64_is_checking_irq_breakpoints_enabled` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_irq_flag` (struct field on `cia_context_t`) | `root/cia.h` | `core/ciacore.c`, ViceInterface | +| `c64d_irq_flagged` (struct field on `via_context_t`) | `root/via.h` | `drive/iec/via1d1541.c` | +| `c64d_irqbrk_irq_source` / `c64d_irqbrk_entry_type_base` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_main_cpu_stack_entry_types` / `c64d_main_cpu_stack_irq_sources` / `c64d_main_cpu_stack_origin_pc` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_irq_flag` (VIC) | `viciisc/viciitypes.h` field | `viciisc/vicii-irq.c` (set), ViceInterface (read) | +| `c64d_irq_flag_needs_clear` / `c64d_irqbrk_irq_source` (VIC) | `c64/c64cpusc.c` | ViceInterface | +| `c64d_c64_check_raster_breakpoint` / `c64d_c64_check_pc_breakpoint` | `c64/c64cpusc.c` | ViceInterface | + +### VIC-II State + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_c64_vicii_cycle` | ViceInterface def | `viciisc/vicii-cycle.c` | +| `c64d_c64_vicii_start_frame` | ViceInterface def | `viciisc/vicii-cycle.c` | +| `c64d_c64_vicii_start_raster_line` | ViceInterface def | `viciisc/vicii-cycle.c` | +| `c64d_c64_set_vicii_record_state_mode` | ViceInterface def | ViceInterface | +| `c64d_vicii_record_state_mode` | ViceInterface def | `viciisc/vicii-cycle.c` (extern) | +| `c64d_c64_vicii_store_state_to_bytebuffer` | ViceInterface def | ViceInterface | +| `c64d_c64_vicii_restore_state_from_bytebuffer` | ViceInterface def | ViceInterface | +| `c64d_get_vicii_state_for_raster_cycle` / `c64d_get_vicii_state_for_raster_line` | ViceInterface def | ViceInterface | +| `c64d_vicii_copy_state` / `c64d_vicii_copy_state_data` | ViceInterface def | ViceInterface | +| `c64d_set_color_register` | `viciisc/vicii-draw-cycle.c` | ViceInterface | +| `c64d_get_vic_colors` | ViceInterface def | ViceInterface | +| `c64d_get_vic_simple_state` | ViceInterface def | ViceInterface | +| `c64d_get_vicii_border_mode` / `c64d_set_vicii_border_mode` | ViceInterface def | ViceInterface | +| `c64d_fetch_phi1_type` | `viciisc/vicii.c` | ViceInterface | +| `c64d_vicii_render_when_paused` | `viciisc/vicii.c` | ViceInterface | +| `c64d_vicii_get_geometry` | `viciisc/vicii.c` | ViceInterface | +| `c64d_skip_drawing_sprites` | ViceInterface def | `viciisc/vicii-draw-cycle.c` | +| `c64d_refresh_dbuf` | ViceInterface def | `viciisc/vicii-draw-cycle.c` | +| `c64d_refresh_previous_lines` | ViceInterface def | ViceInterface | +| `c64d_refresh_screen` / `c64d_refresh_screen_no_callback` | ViceInterface def | `arch/video.c` | +| `c64d_screen_num_skip_top_lines` | ViceInterface def | (extern) | +| `c64d_setting_render_transparent_screen` | ViceInterface def | (extern) | + +### SID / Sound + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_sid_register_read` / `c64d_sid_read_value` | `c64/c64cpusc.c` (extern) | `sid/sid.c` (set), ViceInterface (read) | +| `c64d_sid_register_written` / `c64d_sid_write_value` | `c64/c64cpusc.c` (extern) | `sid/sid.c` (set), ViceInterface (read) | +| `c64d_sid_voiceMask` | `sid/sid.c` | `sid/sid.c`, ViceInterface | +| `c64d_store_sid_data` | `sid/sid.c` | ViceInterface | +| `c64d_get_sid_enable` | `sid/sid-snapshot.c` | `sid/sid-snapshot.c` | +| `c64d_sid_set_engine_model_direct` | ViceInterface def | ViceInterface | +| `c64d_sid_set_emulate_filters` / `c64d_sid_set_sampling_method` / `c64d_sid_set_passband` / `c64d_sid_set_filter_bias` | ViceInterface def | ViceInterface | +| `c64d_sid_set_stereo` / `c64d_sid_set_stereo_address` / `c64d_sid_set_triple_address` | ViceInterface def | ViceInterface | +| `c64d_is_receive_channels_data` | ViceInterface def | `sid/fastsid.c`, `resid/resid-sid.cpp`, `resid-fp/residfp-sid.cpp` | +| `c64d_sid_channels_data` | ViceInterface def | `sid/fastsid.c`, `resid/resid-sid.cpp`, `resid-fp/residfp-sid.cpp` | +| `c64d_waveform_callback` | ViceInterface def | `resid/resid-filter.h`, `resid/resid-sid.cpp`, `resid-fp/residfp-sid.cpp` | +| `c64d_wave_attenuation` / `c64d_wave_shift` | ViceInterface def | `resid-fp/residfp-sid.cpp` | +| `c64d_output` (Voice field) | `resid-fp/residfp-voice.h` | `resid-fp/residfp-sid.cpp` | +| `c64d_sound_init` / `c64d_sound_pause` / `c64d_sound_resume` | ViceInterface def | ViceInterface | +| `c64d_sound_run_sound_when_paused` | ViceInterface def | `root/sound.c` | +| `c64d_skip_sound_run_sound_in_sound_store` | ViceInterface def | `root/sound.c` | +| `c64d_setting_run_sid_emulation` / `c64d_setting_run_sid_when_in_warp` | ViceInterface def | `root/sound.c` | +| `c64d_set_volume` | `root/sound.c` | ViceInterface | +| `c64d_store_vicii_state_with_snapshot` | ViceInterface def | `root/sound.c` | +| `c64d_sid_read_value` | `c64/c64cpusc.c` (extern) | `sid/sid.c`, ViceInterface | + +### Snapshot / State Manager + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_snapshot_write_module` / `c64d_snapshot_read_module` | ViceInterface def | `c64/c64-snapshot.c` | +| `c64d_start_frame_for_snapshots_manager` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_check_snapshot_interval` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_check_snapshot_restore` | ViceInterface def | `c64/c64cpusc.c` | +| `c64d_check_cpu_snapshot_manager_store` / `c64d_check_cpu_snapshot_manager_restore` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_is_performing_snapshot_restore` | ViceInterface def | `c64/c64cpusc.c` (extern) | + +### Profiler + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_profiler_init` / `c64d_activate_profiler` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_profiler_activate` / `c64d_profiler_deactivate` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_profiler_jsr` / `c64d_profiler_rts` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_start_handle_cpu_instruction` / `c64d_profiler_end_cpu_instruction` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_is_active` / `c64d_profiler_file_out` / `c64d_profiler_cpu_total_cycles` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_cycles_per_function` / `c64d_profiler_calls_per_function` | `c64/c64cpusc.c` | ViceInterface | +| `c64d_profiler_trace_stack` / `c64d_profiler_trace_stack_pointer` / `c64d_profiler_trace_stack_function` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_watches` / `c64d_profiler_watch_count` / `c64d_profiler_watches_allocated` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_watch_offset_for_pc_and_post` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | +| `c64d_profiler_last_cycles` / `c64d_profiler_old_pc` | `c64/c64cpusc.c` | `c64/c64cpusc.c` | + +### System Lifecycle / Display + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_display_speed` | ViceInterface def | `arch/vsyncarch.c` | +| `c64d_display_drive_led` | ViceInterface def | `arch/uistatusbar.c` | +| `c64d_show_message` | ViceInterface def | `arch/ui.c`, `arch/uimsgbox.c` | +| `c64d_output` | ViceInterface def | `arch/ui.c` | +| `c64d_console_log` | `arch/uimon.c` | `arch/uimon.c` | +| `c64d_uimon_buf` / `c64d_uimon_bufpos` | ViceInterface def | `arch/uimon.c` | +| `c64d_uimon_print` / `c64d_uimon_print_line` | ViceInterface def | `arch/uimon.c` | +| `c64d_clear_screen` | ViceInterface def | ViceInterface | +| `c64d_update_c64_model` / `c64d_update_c64_machine_from_model_type` / `c64d_update_c64_screen_height_from_model_type` | ViceInterface def | ViceInterface | +| `c64d_update_rom` / `c64d_update_roms` / `c64d_trigger_update_roms` | `c64/c64memrom.c`, `c64/c64cpusc.c` | ViceInterface | + +### Keyboard / Input / Mouse + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_keyboard_init` | `root/keyboard.c` | ViceInterface | +| `c64d_keyboard_keymap_clear` | `root/keyboard.h` | ViceInterface | +| `c64d_keyboard_key_down_latch` / `c64d_keyboard_key_up_latch` / `c64d_keyboard_force_key_up_latch` | ViceInterface def | ViceInterface, `root/keyboard.c` | +| `c64d_joystick_key_down` / `c64d_joystick_key_up` | `joyport/joystick.c` | ViceInterface | +| `c64d_joystick_latch_matrix_workaround` | ViceInterface def | (extern flag) | +| `c64d_mouse_set_type` / `c64d_mouse_type_to_joyportid` | `joyport/mouse.c` | ViceInterface | +| `c64d_mouse_set_position` | `arch/mousedrv.c` | ViceInterface | +| `c64d_set_mouse_pos` | ViceInterface def | ViceInterface | + +### ROM Patching + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_patch_kernal_fast_boot` / `c64d_un_patch_kernal_fast_boot` | `c64/c64memsc.c` | `c64/patchrom.c` | +| `c64d_patch_kernal_fast_boot_flag` | ViceInterface def | `c64/patchrom.c`, `c64/c64memsc.c` | +| `c64d_prev_val_of_FD84` / `c64d_prev_val_of_FD85` | ViceInterface def | (extern, snapshot state) | + +### REU / DMA + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_reu_io2_store` | `c64/cart/reu.c` | ViceInterface | +| `c64d_maincpu_clk` (REU bump) | (call site) | `c64/cart/reu.c`, `core/flash040core.c`, `root/dma.c`, `root/midi.c` | + +### Palette / Colors + +| Symbol | Defined in | Called/referenced in | +|--------|-----------|---------------------| +| `c64d_palette_red` / `c64d_palette_green` / `c64d_palette_blue` | ViceInterface def | ViceInterface | +| `c64d_float_palette_red` / `c64d_float_palette_green` / `c64d_float_palette_blue` | ViceInterface def | ViceInterface | +| `c64d_set_palette` / `c64d_set_palette_vice` | ViceInterface def | ViceInterface | +| `c64d_set_color_register` | `viciisc/vicii-draw-cycle.c` | ViceInterface | + +--- + +## 3.10 Migration Risk Assessment + +Ranked by estimated replay difficulty: + +### Critical (replay requires significant investigation) + +1. **CPU inline expansion (`c64cpusc.c`, `drivecpu.c`) — Risk: CRITICAL** + - Both files use a unique pattern: vanilla includes `mainc64cpu.c` / `6510core.c` at end. + Slajerek inlined the included file and inserted hooks throughout. + - 3.10 maintains the same `#include` pattern (`c64cpusc.c` = 192 lines, includes + `../mainc64cpu.c`). The 3.10 versions of both included files differ from 3.1. + - Phase 4 must: (a) inline 3.10's `mainc64cpu.c` into 3.10's `c64cpusc.c`, (b) diff slajerek's + expanded version against the 3.1 expansion to identify insertion points, (c) map those + insertion points to their equivalents in the 3.10 expansion. + - `clkguard.c/.h` is referenced by `c64cpusc.c` and `drivecpu.c` in the slajerek tree but + is **removed from 3.10**. All `clkguard` usage must be eliminated or replaced. + +2. **`soundsdl.c` rewrite — Risk: HIGH** + - Moved to `arch/shared/sounddrv/soundsdl.c` in 3.10. + - 3.10 version differs from both vanilla 3.1 and slajerek's rewrite. + - The rewrite must be replayed against 3.10's version (which is closer to vanilla 3.1 mono + callback style) at the new path. + +3. **Monitor (`monitor/monitor.c`) — Risk: HIGH** + - 3.10's monitor is 3421 lines vs 3.1's 2389 lines (+1000 lines of new features). + - `static` promotions (`make_prompt`, `monitor_open`, etc.) and `c64d_set_debug_mode` injection + points must be re-identified in substantially reworked code. + +### High (require careful line-by-line mapping) + +4. **`c64memsc.c` `mem_ram` pointer change — Risk: HIGH** + - 3.10 retains `uint8_t mem_ram[C64_RAM_SIZE]` as a static array. Slajerek's pointer-based + approach must be re-evaluated or the memory-mapped-file approach reimplemented for 3.10. + +5. **ReSID backend (`resid/resid-sid.cpp`, `resid/resid-filter.cpp`) — Risk: MEDIUM-HIGH** + - 8580 filter deletion, constructor signature change, behavioral changes to `read()` and + `write()`. 3.10's resid/ is unchanged from 3.1 (same files, same structure). The deletions + and behavioral changes must be replayed exactly. + +6. **Snapshot system (`c64/c64-snapshot.c`) — Risk: MEDIUM-HIGH** + - 3.10's `c64-snapshot.c` (154 lines) differs structurally from 3.1 (149 lines). + The extended `c64_snapshot_write()` signature and new `c64_snapshot_write_in_memory()` must + be replayed against a changed base. + +### Medium (structural changes but file paths stable) + +7. **VIC-II hooks (`viciisc/vicii-cycle.c`, `vicii-draw-cycle.c`, `vicii.c`) — Risk: MEDIUM** + - Files exist in 3.10 at same paths. Insertion points are in the raster cycle loop; must + verify loop structure unchanged in 3.10. + +8. **SID observation (`sid/sid.c`, `sid-snapshot.c`) — Risk: MEDIUM** + - Files exist in 3.10 at same paths. The `sid_read()` restructuring is subtle and must be + verified against 3.10's SID read logic. + +9. **vsync (`root/vsync.c`) — Risk: MEDIUM** + - 3.10's `vsync.c` likely differs; `vsync_do_vsync()` signature change must be replayed. + `sound_flush()` also gains `isPaused` parameter which may conflict with 3.10's sound API. + +### Low (additive, file paths stable) + +10. **CIA/VIA observer (`core/ciacore.c`, `c64cia1/2.c`) — Risk: LOW-MEDIUM** +11. **Keyboard/Input (`root/keyboard.c`, `joyport/joystick.c`) — Risk: LOW-MEDIUM** +12. **ROM patching (`c64/patchrom.c`, `c64/c64memrom.c`) — Risk: LOW** +13. **Profiler (all in `c64cpusc.c`) — Risk: LOW** (once CPU inline expansion is done) +14. **REU DMA taps (`c64/cart/reu.c`) — Risk: LOW** +15. **Drive memory access marking — Risk: LOW** (additive insertions, stable file paths) + +--- + +## Phase 2 Design Seed: Proposed `VICE_HOOK_*` Macro Families + +Based on the category analysis above, Phase 2 should define the following macro families to +replace the inline `c64d_*` calls with version-portable hooks: + +### `VICE_HOOK_CLK_INC()` +Wraps the `CLK_INC()` macro expansion in both `c64cpusc.c` and `drivecpu.c`. +Replaces: `c64d_maincpu_clk++`, `c64d_c64_do_cycle()` call in CLK_INC. +Note: will need two variants — `VICE_HOOK_CLK_INC_C64()` and `VICE_HOOK_CLK_INC_DRIVE()`. + +### `VICE_HOOK_CPU_INSTRUCTION_START(pc, opcode)` +Called at the start of each 6510 instruction decode. +Replaces: `c64d_c64_instruction_cycle = 0`, `c64d_maincpu_previous_instruction_clk` saves, +`c64d_profiler_start_handle_cpu_instruction()`. + +### `VICE_HOOK_CPU_INSTRUCTION_END(pc, opcode, cycles)` +Called at end of each 6510 instruction. +Replaces: `c64d_profiler_end_cpu_instruction()`, `c64d_mark_c64_cell_execute()`. + +### `VICE_HOOK_MEM_READ_C64(addr)` / `VICE_HOOK_MEM_WRITE_C64(addr, value)` +Injected at LOAD/STORE macro sites in the inlined mainc64cpu.c. +Replaces: `c64d_mark_c64_cell_read()`, `c64d_mark_c64_cell_write()`. + +### `VICE_HOOK_MEM_READ_DRIVE(addr)` / `VICE_HOOK_MEM_WRITE_DRIVE(addr, value)` +Injected at LOAD/STORE macro sites in the inlined 6510core.c. +Replaces: `c64d_mark_drive1541_cell_read()`, `c64d_mark_drive1541_cell_write()`. + +### `VICE_HOOK_CIA_STORE(cia_num, addr, value)` / `VICE_HOOK_CIA_READ(cia_num, addr, result)` +Injected at `ciacore_store()` and `ciacore_read()` call sites in `c64cia1.c`/`c64cia2.c`. +Replaces: `c64d_cia1_register_written`, `c64d_cia1_read_value` etc. + +### `VICE_HOOK_SID_STORE(addr, value)` / `VICE_HOOK_SID_READ(addr, result)` +Injected at SID store/read sites in `sid/sid.c`. +Replaces: `c64d_sid_register_written`, `c64d_sid_read_value` etc. + +### `VICE_HOOK_VICII_CYCLE(raster_line, raster_cycle)` +Called at end of `vicii_cycle()`. +Replaces: `c64d_c64_vicii_cycle()`, `c64d_c64_vicii_start_raster_line()`, `c64d_c64_vicii_start_frame()`. + +### `VICE_HOOK_VSYNC_FRAME(is_paused)` +Called in `vsync_do_vsync()`. +Replaces: `c64d_start_frame_for_snapshots_manager()`, `c64d_check_snapshot_interval()`. + +### `VICE_HOOK_DRIVE_MEM_READ(drv, addr)` / `VICE_HOOK_DRIVE_MEM_WRITE(drv, addr, value)` +Injected at drive memory read/write functions in `memiec.c`, `drivemem.c`, VIA stores. +Replaces: `c64d_mark_drive1541_cell_read()`, `c64d_mark_drive1541_cell_write()`. + +### `VICE_HOOK_SOUND_OPEN(chip_num)` / `VICE_HOOK_SOUND_FRAME(is_paused)` +Injected at `sound_machine_open()` and `sound_flush()` in `sound.c`. +Replaces: `c64d_sound_init()`, `c64d_sound_run_sound_when_paused` checks. + +### Non-hookable (must remain direct calls) +- `c64d_set_debug_mode()` — state machine transitions; must remain direct calls +- `c64d_lock_mutex()` / `c64d_unlock_mutex()` — threading primitives; cannot be macros +- All `c64d_peek_*` functions — complex accessor logic; stay as function calls via ViceInterface + +--- + +## Completeness Verification + +The following files were cross-checked to confirm all 64 modified files are referenced in this +catalog. Files not present in vanilla 3.1 (`arch/*`, `resid/resid-*.cpp/h`, `resid-fp/*`) are +noted as new additions in their respective sections. + +All 64 files from `/tmp/c64d-per-file.txt` are accounted for in the categories above. + +``` +src/Emulators/vice/arch/mousedrv.c → Category 11 +src/Emulators/vice/arch/ui.c → Category 14 +src/Emulators/vice/arch/ui.h → Category 14 +src/Emulators/vice/arch/uimsgbox.c → Category 14 +src/Emulators/vice/arch/uimon.c → Categories 10, 14 +src/Emulators/vice/arch/uistatusbar.c → Category 14 +src/Emulators/vice/arch/video.c → Category 14 +src/Emulators/vice/arch/vsyncarch.c → Category 14 +src/Emulators/vice/c64/c64-snapshot.c → Category 12 +src/Emulators/vice/c64/c64cia1.c → Category 6 +src/Emulators/vice/c64/c64cia2.c → Category 6 +src/Emulators/vice/c64/c64cpusc.c → Categories 1, 2, 3, 6, 12, 13 +src/Emulators/vice/c64/c64memrom.c → Category 15 +src/Emulators/vice/c64/c64memsc.c → Categories 2, 3, 15 +src/Emulators/vice/c64/cart/c64-generic.c → Category 5 +src/Emulators/vice/c64/cart/reu.c → Categories 1, 5 +src/Emulators/vice/c64/patchrom.c → Category 15 +src/Emulators/vice/core/ciacore.c → Category 6 +src/Emulators/vice/core/flash040core.c → Category 1 +src/Emulators/vice/core/viacore.c → Category 6 +src/Emulators/vice/drive/drive-writeprotect.c → Category 4 +src/Emulators/vice/drive/drive.c → Category 4 +src/Emulators/vice/drive/drivecpu.c → Categories 1, 4 +src/Emulators/vice/drive/drivemem.c → Category 4 +src/Emulators/vice/drive/iec/memiec.c → Category 4 +src/Emulators/vice/drive/iec/via1d1541.c → Category 4 +src/Emulators/vice/drive/iec/via1d1541.h → Category 4 +src/Emulators/vice/drive/iecieee/via2d.c → Categories 3, 4 +src/Emulators/vice/drive/rotation.c → Category 4 +src/Emulators/vice/drive/viad.h → Category 4 +src/Emulators/vice/iecbus/iecbus.c → Category 4 +src/Emulators/vice/joyport/joystick.c → Category 11 +src/Emulators/vice/joyport/mouse.c → Category 11 +src/Emulators/vice/monitor/monitor.c → Category 10 +src/Emulators/vice/resid-fp/residfp-sid.cpp → Category 8 +src/Emulators/vice/resid-fp/residfp-sid.h → Category 8 +src/Emulators/vice/resid-fp/residfp-voice.h → Category 8 +src/Emulators/vice/resid/resid-filter.cpp → Category 8 +src/Emulators/vice/resid/resid-filter.h → Category 8 +src/Emulators/vice/resid/resid-sid.cpp → Category 8 +src/Emulators/vice/resid/resid-sid.h → Category 8 +src/Emulators/vice/root/cia.h → Category 6 +src/Emulators/vice/root/dma.c → Category 1 +src/Emulators/vice/root/interrupt.c → Category 1 +src/Emulators/vice/root/interrupt.h → Category 1 +src/Emulators/vice/root/keyboard.c → Category 11 +src/Emulators/vice/root/keyboard.h → Category 11 +src/Emulators/vice/root/machine.c → Category 14 +src/Emulators/vice/root/maincpu.h → Category 1 +src/Emulators/vice/root/midi.c → Category 1 +src/Emulators/vice/root/sound.c → Categories 8, 14 +src/Emulators/vice/root/via.h → Category 6 +src/Emulators/vice/root/vsync.c → Category 14 +src/Emulators/vice/sid/fastsid.c → Category 8 +src/Emulators/vice/sid/sid-resources.c → Category 8 +src/Emulators/vice/sid/sid-resources.h → Category 8 +src/Emulators/vice/sid/sid-snapshot.c → Category 8 +src/Emulators/vice/sid/sid.c → Category 8 +src/Emulators/vice/sounddrv/soundsdl.c → Category 9 +src/Emulators/vice/viciisc/vicii-cycle.c → Category 7 +src/Emulators/vice/viciisc/vicii-draw-cycle.c → Category 7 +src/Emulators/vice/viciisc/vicii-irq.c → Categories 6, 7 +src/Emulators/vice/viciisc/vicii.c → Category 7 +src/Emulators/vice/viciisc/viciitypes.h → Categories 6, 7 +``` diff --git a/platform/Linux/src.Linux/archdep.c b/platform/Linux/src.Linux/archdep.c index 1e26b52f..c7c25748 100644 --- a/platform/Linux/src.Linux/archdep.c +++ b/platform/Linux/src.Linux/archdep.c @@ -123,7 +123,7 @@ static int archdep_init_extra(int *argc, char **argv) archdep_pref_path = archdep_boot_path(); #else - argv0 = lib_stralloc(argv[0]); + argv0 = lib_strdup(argv[0]); #endif return 0; } @@ -137,9 +137,9 @@ char *archdep_program_name(void) p = strrchr(argv0, '/'); if (p == NULL) { - program_name = lib_stralloc(argv0); + program_name = lib_strdup(argv0); } else { - program_name = lib_stralloc(p + 1); + program_name = lib_strdup(p + 1); } } @@ -151,7 +151,7 @@ const char *archdep_boot_path(void) if (boot_path == NULL) { #ifdef USE_PROC_SELF_EXE /* known from setup in archdep_init_extra() so just reuse it */ - boot_path = lib_stralloc(argv0); + boot_path = lib_strdup(argv0); #else boot_path = findpath(argv0, getenv("PATH"), IOUTIL_ACCESS_X_OK); #endif @@ -457,7 +457,7 @@ int archdep_expand_path(char **return_path, const char *orig_name) { /* Unix version. */ if (*orig_name == '/') { - *return_path = lib_stralloc(orig_name); + *return_path = lib_strdup(orig_name); } else { static char *cwd; @@ -480,13 +480,13 @@ void archdep_startup_log_error(const char *format, ...) char *archdep_filename_parameter(const char *name) { /* nothing special(?) */ - return lib_stralloc(name); + return lib_strdup(name); } char *archdep_quote_parameter(const char *name) { /*not needed(?) */ - return lib_stralloc(name); + return lib_strdup(name); } char *archdep_tmpnam(void) @@ -517,11 +517,11 @@ char *archdep_tmpnam(void) close(fd); } - final_name = lib_stralloc(tmp_name); + final_name = lib_strdup(tmp_name); lib_free(tmp_name); return final_name; #else - return lib_stralloc(tmpnam(NULL)); + return lib_strdup(tmpnam(NULL)); #endif } @@ -578,7 +578,7 @@ FILE *archdep_mkstemp_fd(char **filename, const char *mode) return NULL; } - *filename = lib_stralloc(tmp); + *filename = lib_strdup(tmp); return fd; #endif @@ -793,7 +793,7 @@ static char *archdep_make_default_pref_path(int create) // path = util_concat(home, "/.vice", NULL); path = util_concat(home, "/.C64Debugger", NULL); } else { - path = lib_stralloc(archdep_pref_path); + path = lib_strdup(archdep_pref_path); } if(create) { if (access(path, F_OK)) { diff --git a/platform/Linux/src.Linux/mididrv.c b/platform/Linux/src.Linux/mididrv.c index c9bdd050..b84abc61 100644 --- a/platform/Linux/src.Linux/mididrv.c +++ b/platform/Linux/src.Linux/mididrv.c @@ -70,7 +70,6 @@ #include "log.h" #include "mididrv.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -85,7 +84,7 @@ static int fd_out = -1; #define MIDI_DRIVER_ALSA 1 static int midi_driver_num = MIDI_DRIVER_OSS; -static log_t mididrv_log = LOG_ERR; +static log_t mididrv_log = LOG_DEFAULT; /* ------------------------------------------------------------------------- */ /* OSS driver */ @@ -546,7 +545,7 @@ static midi_driver_t midi_drivers[] = { void mididrv_init(void) { - if (mididrv_log == LOG_ERR) { + if (mididrv_log == LOG_DEFAULT) { mididrv_log = log_open("MIDIdrv"); } @@ -671,22 +670,13 @@ void mididrv_resources_shutdown(void) } static const cmdline_option_t cmdline_options[] = { - { "-midiin", SET_RESOURCE, -1, - NULL, NULL, "MIDIInDev", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Specify MIDI-In device") }, - { "-midiout", SET_RESOURCE, -1, - NULL, NULL, "MIDIOutDev", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Specify MIDI-Out device") }, + { "-midiin", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIInDev", NULL, N_(""), N_("Specify MIDI-In device")}, + { "-midiout", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIOutDev", NULL, N_(""), N_("Specify MIDI-Out device")}, #ifdef USE_ALSA - { "-mididrv", SET_RESOURCE, -1, - NULL, NULL, "MIDIDriver", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Specify MIDI driver (0 = OSS, 1 = ALSA)") }, + { "-mididrv", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIDriver", NULL, N_(""), N_("Specify MIDI driver (0 = OSS, 1 = ALSA)")}, #endif CMDLINE_LIST_END }; diff --git a/platform/MacOS/c64d.xcodeproj/project.pbxproj b/platform/MacOS/c64d.xcodeproj/project.pbxproj index 2aff8652..96e5ceca 100644 --- a/platform/MacOS/c64d.xcodeproj/project.pbxproj +++ b/platform/MacOS/c64d.xcodeproj/project.pbxproj @@ -604,10 +604,29 @@ 41C84C2F23C6183A007C0889 /* catweaselmkiii.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92623AA0F1000A54EB2 /* catweaselmkiii.c */; }; 41C84C3023C6183A007C0889 /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92723AA0F1000A54EB2 /* console.c */; }; 41C84C3123C6183A007C0889 /* coproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92823AA0F1000A54EB2 /* coproc.c */; }; + 41C8CA1223C6183B007C0001 /* rd_ui_stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA1323C6183B007C0001 /* rd_ui_stubs.c */; }; + 41C8CA0C23C6183B007C0001 /* archdep_chdir.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0001 /* archdep_chdir.c */; }; + 41C8CA0C23C6183B007C0002 /* archdep_close.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0002 /* archdep_close.c */; }; + 41C8CA0C23C6183B007C0003 /* archdep_current_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0003 /* archdep_current_dir.c */; }; + 41C8CA0C23C6183B007C0004 /* archdep_default_portable_resource_file_name.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0004 /* archdep_default_portable_resource_file_name.c */; }; + 41C8CA0C23C6183B007C0005 /* archdep_dir.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0005 /* archdep_dir.c */; }; + 41C8CA0C23C6183B007C0007 /* archdep_exit.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0007 /* archdep_exit.c */; }; + 41C8CA0C23C6183B007C0008 /* archdep_fdopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0008 /* archdep_fdopen.c */; }; + 41C8CA0C23C6183B007C0009 /* archdep_file_exists.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0009 /* archdep_file_exists.c */; }; + 41C8CA0C23C6183B007C000A /* archdep_file_size.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000A /* archdep_file_size.c */; }; + 41C8CA0C23C6183B007C000B /* archdep_fseeko.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000B /* archdep_fseeko.c */; }; + 41C8CA0C23C6183B007C000C /* archdep_ftello.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000C /* archdep_ftello.c */; }; + 41C8CA0C23C6183B007C000D /* archdep_getcwd.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000D /* archdep_getcwd.c */; }; + 41C8CA0C23C6183B007C000E /* archdep_is_haiku.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000E /* archdep_is_haiku.c */; }; + 41C8CA0C23C6183B007C000F /* archdep_quote_unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C000F /* archdep_quote_unzip.c */; }; + 41C8CA0C23C6183B007C0010 /* archdep_real_path.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0010 /* archdep_real_path.c */; }; + 41C8CA0C23C6183B007C0011 /* archdep_remove.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0011 /* archdep_remove.c */; }; + 41C8CA0C23C6183B007C0012 /* archdep_rmdir.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0012 /* archdep_rmdir.c */; }; + 41C8CA0C23C6183B007C0013 /* archdep_sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0013 /* archdep_sound.c */; }; + 41C8CA0C23C6183B007C0014 /* archdep_usleep.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0D23C6183B007C0014 /* archdep_usleep.c */; }; 41C84C3223C6183A007C0889 /* dynlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92A23AA0F1000A54EB2 /* dynlib.c */; }; 41C84C3323C6183A007C0889 /* fullscreen.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92B23AA0F1000A54EB2 /* fullscreen.c */; }; 41C84C3423C6183A007C0889 /* c64-hardsid.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92D23AA0F1000A54EB2 /* c64-hardsid.c */; }; - 41C84C3523C6183A007C0889 /* joy.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A92E23AA0F1000A54EB2 /* joy.c */; }; 41C84C3623C6183A007C0889 /* kbd.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A93023AA0F1000A54EB2 /* kbd.c */; }; 41C84C3723C6183A007C0889 /* lightpendrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A93223AA0F1000A54EB2 /* lightpendrv.c */; }; 41C84C3823C6183A007C0889 /* menu_c64_common_expansions.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4A93423AA0F1000A54EB2 /* menu_c64_common_expansions.c */; }; @@ -740,6 +759,35 @@ 41C84CB823C6183B007C0889 /* freezemachine.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2323AA0F1000A54EB2 /* freezemachine.c */; }; 41C84CB923C6183B007C0889 /* funplay.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2523AA0F1000A54EB2 /* funplay.c */; }; 41C84CBA23C6183B007C0889 /* gamekiller.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2723AA0F1000A54EB2 /* gamekiller.c */; }; + 41C8CA0823C6183B007C0001 /* bisplus.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0001 /* bisplus.c */; }; + 41C8CA0823C6183B007C0002 /* blackbox3.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0002 /* blackbox3.c */; }; + 41C8CA0823C6183B007C0003 /* blackbox4.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0003 /* blackbox4.c */; }; + 41C8CA0823C6183B007C0004 /* blackbox8.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0004 /* blackbox8.c */; }; + 41C8CA0823C6183B007C0005 /* blackbox9.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0005 /* blackbox9.c */; }; + 41C8CA0823C6183B007C0006 /* bmpdataturbo.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0006 /* bmpdataturbo.c */; }; + 41C8CA0823C6183B007C0007 /* drean.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0007 /* drean.c */; }; + 41C8CA0823C6183B007C0008 /* freezeframe2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0008 /* freezeframe2.c */; }; + 41C8CA0823C6183B007C0009 /* gmod3.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0009 /* gmod3.c */; }; + 41C8CA0823C6183B007C000A /* hyperbasic.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000A /* hyperbasic.c */; }; + 41C8CA0823C6183B007C000B /* ieeeflash64.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000B /* ieeeflash64.c */; }; + 41C8CA0823C6183B007C000C /* ltkernal.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000C /* ltkernal.c */; }; + 41C8CA0823C6183B007C000D /* magicdesk16.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000D /* magicdesk16.c */; }; + 41C8CA0823C6183B007C000E /* maxbasic.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000E /* maxbasic.c */; }; + 41C8CA0823C6183B007C000F /* megabyter.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C000F /* megabyter.c */; }; + 41C8CA0823C6183B007C0010 /* multimax.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0010 /* multimax.c */; }; + 41C8CA0823C6183B007C0011 /* partner64.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0011 /* partner64.c */; }; + 41C8CA0823C6183B007C0012 /* profidos.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0012 /* profidos.c */; }; + 41C8CA0823C6183B007C0013 /* ramlink.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0013 /* ramlink.c */; }; + 41C8CA0823C6183B007C0014 /* rexramfloppy.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0014 /* rexramfloppy.c */; }; + 41C8CA0823C6183B007C0015 /* sdbox.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0015 /* sdbox.c */; }; + 41C8CA0823C6183B007C0016 /* turtlegraphics.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0016 /* turtlegraphics.c */; }; + 41C8CA0823C6183B007C0017 /* uc1.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0017 /* uc1.c */; }; + 41C8CA0823C6183B007C0018 /* uc2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0018 /* uc2.c */; }; + 41C8CA0823C6183B007C0019 /* zippcode48.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0019 /* zippcode48.c */; }; + 41C8CA0823C6183B007C001A /* artstudiodrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001A /* artstudiodrv.c */; }; + 41C8CA0823C6183B007C001B /* minipaintdrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001B /* minipaintdrv.c */; }; + 41C8CA0823C6183B007C001C /* ffmpegexedrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001C /* ffmpegexedrv.c */; }; + 41C8CA0823C6183B007C001D /* zmbvdrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001D /* zmbvdrv.c */; }; 41C84CBB23C6183B007C0889 /* georam.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2923AA0F1000A54EB2 /* georam.c */; }; 41C84CBC23C6183B007C0889 /* gmod2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2B23AA0F1000A54EB2 /* gmod2.c */; }; 41C84CBD23C6183B007C0889 /* gs.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA2D23AA0F1000A54EB2 /* gs.c */; }; @@ -792,6 +840,16 @@ 41C84CEC23C6183B007C0889 /* ciatimer.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA8C23AA0F1000A54EB2 /* ciatimer.c */; }; 41C84CED23C6183B007C0889 /* cs8900.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA8E23AA0F1000A54EB2 /* cs8900.c */; }; 41C84CEE23C6183B007C0889 /* flash040core.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA9023AA0F1000A54EB2 /* flash040core.c */; }; + 41C8CA0E23C6183B007C0001 /* cmdhd.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0F23C6183B007C0001 /* cmdhd.c */; }; + 41C8CA0E23C6183B007C0002 /* rtc-72421.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0F23C6183B007C0002 /* rtc-72421.c */; }; + 41C8CA0E23C6183B007C0003 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0F23C6183B007C0003 /* sha1.c */; }; + 41C8CA0E23C6183B007C0004 /* iec-ieee488-shared.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0F23C6183B007C0004 /* iec-ieee488-shared.c */; }; + 41C8CA0823C6183B007C001E /* flash800core.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001E /* flash800core.c */; }; + 41C8CA0823C6183B007C001F /* spi-flash.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C001F /* spi-flash.c */; }; + 41C8CA0823C6183B007C0020 /* archdep_sleep.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0020 /* archdep_sleep.c */; }; + 41C8CA0823C6183B007C0021 /* zmbv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0021 /* zmbv.c */; }; + 41C8CA0823C6183B007C0022 /* zmbv_avi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0022 /* zmbv_avi.c */; }; + 41C8CA0823C6183B007C0023 /* miniz.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0923C6183B007C0023 /* miniz.c */; }; 41C84CEF23C6183B007C0889 /* fmopl.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA9123AA0F1000A54EB2 /* fmopl.c */; }; 41C84CF023C6183B007C0889 /* m93c86.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA9323AA0F1000A54EB2 /* m93c86.c */; }; 41C84CF123C6183B007C0889 /* mc6821core.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AA9523AA0F1000A54EB2 /* mc6821core.c */; }; @@ -813,7 +871,6 @@ 41C84D0123C6183B007C0889 /* rawimage.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AAB323AA0F1000A54EB2 /* rawimage.c */; }; 41C84D0223C6183B007C0889 /* drive-check.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AAB823AA0F1000A54EB2 /* drive-check.c */; }; 41C84D0323C6183B007C0889 /* drive-cmdline-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AABA23AA0F1000A54EB2 /* drive-cmdline-options.c */; }; - 41C84D0423C6183B007C0889 /* drive-overflow.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AABC23AA0F1000A54EB2 /* drive-overflow.c */; }; 41C84D0523C6183B007C0889 /* drive-resources.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AABE23AA0F1000A54EB2 /* drive-resources.c */; }; 41C84D0623C6183B007C0889 /* drive-snapshot.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AAC023AA0F1000A54EB2 /* drive-snapshot.c */; }; 41C84D0723C6183B007C0889 /* drive-sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AAC223AA0F1000A54EB2 /* drive-sound.c */; }; @@ -864,6 +921,7 @@ 41C84D3423C6183B007C0889 /* fsdevice-close.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2123AA0F1100A54EB2 /* fsdevice-close.c */; }; 41C84D3523C6183B007C0889 /* fsdevice-cmdline-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2323AA0F1100A54EB2 /* fsdevice-cmdline-options.c */; }; 41C84D3623C6183B007C0889 /* fsdevice-flush.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2523AA0F1100A54EB2 /* fsdevice-flush.c */; }; + 41C8CA1023C6183B007C0001 /* fsdevice-filename.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA1123C6183B007C0001 /* fsdevice-filename.c */; }; 41C84D3723C6183B007C0889 /* fsdevice-open.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2723AA0F1100A54EB2 /* fsdevice-open.c */; }; 41C84D3823C6183B007C0889 /* fsdevice-read.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2923AA0F1100A54EB2 /* fsdevice-read.c */; }; 41C84D3923C6183B007C0889 /* fsdevice-resources.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB2B23AA0F1100A54EB2 /* fsdevice-resources.c */; }; @@ -892,6 +950,36 @@ 41C84D5023C6183B007C0889 /* cx21.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB5823AA0F1100A54EB2 /* cx21.c */; }; 41C84D5123C6183B007C0889 /* cx85.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB5A23AA0F1100A54EB2 /* cx85.c */; }; 41C84D5223C6183B007C0889 /* joyport.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB5C23AA0F1100A54EB2 /* joyport.c */; }; + 41C8CA0A23C6183B007C0001 /* inception.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0001 /* inception.c */; }; + 41C8CA0A23C6183B007C0002 /* joyport_io_sim.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0002 /* joyport_io_sim.c */; }; + 41C8CA0A23C6183B007C0003 /* multijoy.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0003 /* multijoy.c */; }; + 41C8CA0A23C6183B007C0004 /* ninja_snespad.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0004 /* ninja_snespad.c */; }; + 41C8CA0A23C6183B007C0005 /* paperclip2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0005 /* paperclip2.c */; }; + 41C8CA0A23C6183B007C0006 /* paperclip64e.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0006 /* paperclip64e.c */; }; + 41C8CA0A23C6183B007C0007 /* paperclip64sc.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0007 /* paperclip64sc.c */; }; + 41C8CA0A23C6183B007C0008 /* powerpad.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0008 /* powerpad.c */; }; + 41C8CA0A23C6183B007C0009 /* protopad.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0009 /* protopad.c */; }; + 41C8CA0A23C6183B007C000A /* spaceballs.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000A /* spaceballs.c */; }; + 41C8CA0A23C6183B007C000B /* trapthem_snespad.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000B /* trapthem_snespad.c */; }; + 41C8CA0A23C6183B007C000C /* waasoft_dongle.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000C /* waasoft_dongle.c */; }; + 41C8CA0A23C6183B007C000D /* mouse_1351.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000D /* mouse_1351.c */; }; + 41C8CA0A23C6183B007C000E /* mouse_neos.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000E /* mouse_neos.c */; }; + 41C8CA0A23C6183B007C000F /* mouse_paddle.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C000F /* mouse_paddle.c */; }; + 41C8CA0A23C6183B007C0010 /* mouse_quadrature.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0010 /* mouse_quadrature.c */; }; + 41C8CA0A23C6183B007C0011 /* userport_diag_pin.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0011 /* userport_diag_pin.c */; }; + 41C8CA0A23C6183B007C0012 /* userport_io_sim.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0012 /* userport_io_sim.c */; }; + 41C8CA0A23C6183B007C0013 /* userport_petscii_snespad.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0013 /* userport_petscii_snespad.c */; }; + 41C8CA0A23C6183B007C0014 /* userport_ps2mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0014 /* userport_ps2mouse.c */; }; + 41C8CA0A23C6183B007C0015 /* userport_spt_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0015 /* userport_spt_joystick.c */; }; + 41C8CA0A23C6183B007C0016 /* userport_superpad64.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0016 /* userport_superpad64.c */; }; + 41C8CA0A23C6183B007C0017 /* userport_hummer_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0017 /* userport_hummer_joystick.c */; }; + 41C8CA0A23C6183B007C0018 /* userport_synergy_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0018 /* userport_synergy_joystick.c */; }; + 41C8CA0A23C6183B007C0019 /* userport_woj_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C0019 /* userport_woj_joystick.c */; }; + 41C8CA0A23C6183B007C001A /* userport_hks_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C001A /* userport_hks_joystick.c */; }; + 41C8CA0A23C6183B007C001B /* i8255a.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C001B /* i8255a.c */; }; + 41C8CA0A23C6183B007C001C /* scsi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C001C /* scsi.c */; }; + 41C8CA0A23C6183B007C001D /* mon_profile.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C001D /* mon_profile.c */; }; + 41C8CA0A23C6183B007C001E /* monitor_binary.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0B23C6183B007C001E /* monitor_binary.c */; }; 41C84D5323C6183B007C0889 /* joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB5E23AA0F1100A54EB2 /* joystick.c */; }; 41C84D5423C6183B007C0889 /* lightpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB6023AA0F1100A54EB2 /* lightpen.c */; }; 41C84D5523C6183B007C0889 /* mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AB6223AA0F1100A54EB2 /* mouse.c */; }; @@ -958,6 +1046,7 @@ 41C84D9223C6183B007C0889 /* printer-serial.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABD423AA0F1100A54EB2 /* printer-serial.c */; }; 41C84D9323C6183B007C0889 /* printer-userport.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABD523AA0F1100A54EB2 /* printer-userport.c */; }; 41C84D9423C6183B007C0889 /* printer.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABD623AA0F1100A54EB2 /* printer.c */; }; + 41C8CA0723C6183B007C0030 /* profiler.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0723C6183B007C0031 /* profiler.c */; }; 41C84D9523C6183B007C0889 /* raster-cache.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABD823AA0F1100A54EB2 /* raster-cache.c */; }; 41C84D9623C6183B007C0889 /* raster-canvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABDA23AA0F1100A54EB2 /* raster-canvas.c */; }; 41C84D9723C6183B007C0889 /* raster-changes.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABDC23AA0F1100A54EB2 /* raster-changes.c */; }; @@ -971,6 +1060,7 @@ 41C84D9F23C6183B007C0889 /* raster-sprite-status.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABEA23AA0F1100A54EB2 /* raster-sprite-status.c */; }; 41C84DA023C6183B007C0889 /* raster-sprite.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABEC23AA0F1100A54EB2 /* raster-sprite.c */; }; 41C84DA123C6183B007C0889 /* raster.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ABEE23AA0F1100A54EB2 /* raster.c */; }; + 41C8DEAD23C6183B007C0001 /* raster-snapshot.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8DEAD23C6183B007C0002 /* raster-snapshot.c */; }; 41C84DA223C6183B007C0889 /* alarm.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC2323AA0F1100A54EB2 /* alarm.c */; }; 41C84DA323C6183B007C0889 /* attach.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC2623AA0F1100A54EB2 /* attach.c */; }; 41C84DA423C6183B007C0889 /* autostart-prg.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC2823AA0F1100A54EB2 /* autostart-prg.c */; }; @@ -983,6 +1073,7 @@ 41C84DAB23C6183B007C0889 /* cmdline.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC4723AA0F1100A54EB2 /* cmdline.c */; }; 41C84DAC23C6183B007C0889 /* color.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC4923AA0F1100A54EB2 /* color.c */; }; 41C84DAD23C6183B007C0889 /* datasette.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC4C23AA0F1100A54EB2 /* datasette.c */; }; + 41C8CA0723C6183B007C0020 /* datasette-sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0723C6183B007C0021 /* datasette-sound.c */; }; 41C84DAE23C6183B007C0889 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC4E23AA0F1100A54EB2 /* debug.c */; }; 41C84DAF23C6183B007C0889 /* dma.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC5223AA0F1100A54EB2 /* dma.c */; }; 41C84DB023C6183B007C0889 /* embedded.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AC6223AA0F1100A54EB2 /* embedded.c */; }; @@ -1018,7 +1109,6 @@ 41C84DCE23C6183B007C0889 /* socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACBE23AA0F1100A54EB2 /* socket.c */; }; 41C84DCF23C6183B007C0889 /* sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACBF23AA0F1100A54EB2 /* sound.c */; }; 41C84DD023C6183B007C0889 /* sysfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACC223AA0F1100A54EB2 /* sysfile.c */; }; - 41C84DD123C6183B007C0889 /* translate.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACC723AA0F1100A54EB2 /* translate.c */; }; 41C84DD223C6183B007C0889 /* traps.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACCB23AA0F1100A54EB2 /* traps.c */; }; 41C84DD323C6183B007C0889 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACD123AA0F1100A54EB2 /* util.c */; }; 41C84DD423C6183B007C0889 /* vice-crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ACD623AA0F1100A54EB2 /* vice-crc32.c */; }; @@ -1073,7 +1163,8 @@ 41C84E0523C6183B007C0889 /* dtl-basic-dongle.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5323AA0F1100A54EB2 /* dtl-basic-dongle.c */; }; 41C84E0623C6183B007C0889 /* sense-dongle.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5523AA0F1100A54EB2 /* sense-dongle.c */; }; 41C84E0723C6183B007C0889 /* tape_diag_586220_harness.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5723AA0F1100A54EB2 /* tape_diag_586220_harness.c */; }; - 41C84E0823C6183B007C0889 /* tapelog.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5923AA0F1100A54EB2 /* tapelog.c */; }; + 41C8CA0723C6183B007C0010 /* tapecart.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0723C6183B007C0011 /* tapecart.c */; }; + 41C8CA0723C6183B007C0012 /* wordcraft-dongle.c in Sources */ = {isa = PBXBuildFile; fileRef = 41C8CA0723C6183B007C0013 /* wordcraft-dongle.c */; }; 41C84E0923C6183B007C0889 /* tapeport.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5B23AA0F1100A54EB2 /* tapeport.c */; }; 41C84E0A23C6183B007C0889 /* userport.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD5E23AA0F1100A54EB2 /* userport.c */; }; 41C84E0B23C6183B007C0889 /* userport_4bit_sampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4AD6023AA0F1100A54EB2 /* userport_4bit_sampler.c */; }; @@ -1108,26 +1199,25 @@ 41C84E2823C6183B007C0889 /* vicii-timing.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADA723AA0F1100A54EB2 /* vicii-timing.c */; }; 41C84E2923C6183B007C0889 /* vicii.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADA923AA0F1100A54EB2 /* vicii.c */; }; 41C84E2A23C6183B007C0889 /* render1x1.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADAC23AA0F1100A54EB2 /* render1x1.c */; }; - 41C84E2B23C6183B007C0889 /* render1x1crt.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADAE23AA0F1100A54EB2 /* render1x1crt.c */; }; + 41C84E2B23C6183B007C0889 /* render1x1rgbi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADAE23AA0F1100A54EB2 /* render1x1rgbi.c */; }; 41C84E2C23C6183B007C0889 /* render1x1ntsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB023AA0F1100A54EB2 /* render1x1ntsc.c */; }; 41C84E2D23C6183B007C0889 /* render1x1pal.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB223AA0F1100A54EB2 /* render1x1pal.c */; }; 41C84E2E23C6183B007C0889 /* render1x2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB423AA0F1100A54EB2 /* render1x2.c */; }; - 41C84E2F23C6183B007C0889 /* render1x2crt.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB623AA0F1100A54EB2 /* render1x2crt.c */; }; + 41C84E2F23C6183B007C0889 /* render1x2rgbi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB623AA0F1100A54EB2 /* render1x2rgbi.c */; }; 41C84E3023C6183B007C0889 /* render2x2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADB823AA0F1100A54EB2 /* render2x2.c */; }; - 41C84E3123C6183B007C0889 /* render2x2crt.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADBA23AA0F1100A54EB2 /* render2x2crt.c */; }; + 41C84E3123C6183B007C0889 /* render2x2rgbi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADBA23AA0F1100A54EB2 /* render2x2rgbi.c */; }; 41C84E3223C6183B007C0889 /* render2x2ntsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADBC23AA0F1100A54EB2 /* render2x2ntsc.c */; }; 41C84E3323C6183B007C0889 /* render2x2pal.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADBE23AA0F1100A54EB2 /* render2x2pal.c */; }; 41C84E3423C6183B007C0889 /* render2x4.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC023AA0F1100A54EB2 /* render2x4.c */; }; - 41C84E3523C6183B007C0889 /* render2x4crt.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC223AA0F1100A54EB2 /* render2x4crt.c */; }; + 41C84E3523C6183B007C0889 /* render2x4rgbi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC223AA0F1100A54EB2 /* render2x4rgbi.c */; }; 41C84E3623C6183B007C0889 /* renderscale2x.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC423AA0F1100A54EB2 /* renderscale2x.c */; }; - 41C84E3723C6183B007C0889 /* renderyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC623AA0F1100A54EB2 /* renderyuv.c */; }; + 41C84E3723C6183B007C0889 /* render2x2palu.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC623AA0F1100A54EB2 /* render2x2palu.c */; }; 41C84E3823C6183B007C0889 /* video-canvas.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADC823AA0F1100A54EB2 /* video-canvas.c */; }; 41C84E3923C6183B007C0889 /* video-cmdline-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCA23AA0F1100A54EB2 /* video-cmdline-options.c */; }; 41C84E3A23C6183B007C0889 /* video-color.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCB23AA0F1100A54EB2 /* video-color.c */; }; - 41C84E3B23C6183B007C0889 /* video-render-1x2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCD23AA0F1100A54EB2 /* video-render-1x2.c */; }; - 41C84E3C23C6183B007C0889 /* video-render-2x2.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCE23AA0F1100A54EB2 /* video-render-2x2.c */; }; - 41C84E3D23C6183B007C0889 /* video-render-crt.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCF23AA0F1100A54EB2 /* video-render-crt.c */; }; - 41C84E3E23C6183B007C0889 /* video-render-pal.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADD023AA0F1100A54EB2 /* video-render-pal.c */; }; + 41C84E3B23C6183B007C0889 /* video-render-crtmono.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCD23AA0F1100A54EB2 /* video-render-crtmono.c */; }; + 41C84E3C23C6183B007C0889 /* video-render-rgbi.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADCE23AA0F1100A54EB2 /* video-render-rgbi.c */; }; + 41C84E3E23C6183B007C0889 /* video-render-palntsc.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADD023AA0F1100A54EB2 /* video-render-palntsc.c */; }; 41C84E3F23C6183B007C0889 /* video-render.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADD123AA0F1100A54EB2 /* video-render.c */; }; 41C84E4023C6183B007C0889 /* video-resources.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADD323AA0F1100A54EB2 /* video-resources.c */; }; 41C84E4123C6183B007C0889 /* video-sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D4ADD523AA0F1100A54EB2 /* video-sound.c */; }; @@ -1166,7 +1256,6 @@ 41CE4AFE2BD18B86008A2147 /* CViewC64BreakpointsIrq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41CE4AFD2BD18B86008A2147 /* CViewC64BreakpointsIrq.cpp */; }; 41CE4B012BD1932D008A2147 /* CViewDrive1541BreakpointsIrq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41CE4AFF2BD1932D008A2147 /* CViewDrive1541BreakpointsIrq.cpp */; }; 41D4F7032AF5228D002CE68F /* CViewFileBrowser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D4F7012AF5228C002CE68F /* CViewFileBrowser.cpp */; }; - 41D699732AFA6284008124F6 /* c1541.c in Sources */ = {isa = PBXBuildFile; fileRef = 41D699722AFA5ACB008124F6 /* c1541.c */; }; 41D9972E276D46CC00ECBF2C /* CDebugSymbolsSegmentDrive1541.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41D9972C276D46CC00ECBF2C /* CDebugSymbolsSegmentDrive1541.cpp */; }; 41DF68B12BA9BAD000511704 /* CDataAdapterDrive1541Minimal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41DF68AF2BA9BAD000511704 /* CDataAdapterDrive1541Minimal.cpp */; }; 41E5CE5A2436360A0018F049 /* altirra_5200_os.c in Sources */ = {isa = PBXBuildFile; fileRef = 41E5CE522436360A0018F049 /* altirra_5200_os.c */; }; @@ -2441,12 +2530,31 @@ 41D4A92623AA0F1000A54EB2 /* catweaselmkiii.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = catweaselmkiii.c; sourceTree = ""; }; 41D4A92723AA0F1000A54EB2 /* console.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = console.c; sourceTree = ""; }; 41D4A92823AA0F1000A54EB2 /* coproc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coproc.c; sourceTree = ""; }; + 41C8CA1323C6183B007C0001 /* rd_ui_stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "rd_ui_stubs.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0001 /* archdep_chdir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_chdir.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0002 /* archdep_close.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_close.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0003 /* archdep_current_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_current_dir.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0004 /* archdep_default_portable_resource_file_name.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_default_portable_resource_file_name.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0005 /* archdep_dir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_dir.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0007 /* archdep_exit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_exit.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0008 /* archdep_fdopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_fdopen.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0009 /* archdep_file_exists.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_file_exists.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000A /* archdep_file_size.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_file_size.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000B /* archdep_fseeko.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_fseeko.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000C /* archdep_ftello.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_ftello.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000D /* archdep_getcwd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_getcwd.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000E /* archdep_is_haiku.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_is_haiku.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C000F /* archdep_quote_unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_quote_unzip.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0010 /* archdep_real_path.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_real_path.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0011 /* archdep_remove.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_remove.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0012 /* archdep_rmdir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_rmdir.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0013 /* archdep_sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_sound.c"; sourceTree = ""; }; + 41C8CA0D23C6183B007C0014 /* archdep_usleep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_usleep.c"; sourceTree = ""; }; 41D4A92923AA0F1000A54EB2 /* coproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coproc.h; sourceTree = ""; }; 41D4A92A23AA0F1000A54EB2 /* dynlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dynlib.c; sourceTree = ""; }; 41D4A92B23AA0F1000A54EB2 /* fullscreen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fullscreen.c; sourceTree = ""; }; 41D4A92C23AA0F1000A54EB2 /* fullscreenarch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fullscreenarch.h; sourceTree = ""; }; 41D4A92D23AA0F1000A54EB2 /* c64-hardsid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "c64-hardsid.c"; sourceTree = ""; }; - 41D4A92E23AA0F1000A54EB2 /* joy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = joy.c; sourceTree = ""; }; 41D4A92F23AA0F1000A54EB2 /* joy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = joy.h; sourceTree = ""; }; 41D4A93023AA0F1000A54EB2 /* kbd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kbd.c; sourceTree = ""; }; 41D4A93123AA0F1000A54EB2 /* kbd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kbd.h; sourceTree = ""; }; @@ -2693,6 +2801,35 @@ 41D4AA2523AA0F1000A54EB2 /* funplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = funplay.c; sourceTree = ""; }; 41D4AA2623AA0F1000A54EB2 /* funplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = funplay.h; sourceTree = ""; }; 41D4AA2723AA0F1000A54EB2 /* gamekiller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gamekiller.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0001 /* bisplus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bisplus.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0002 /* blackbox3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blackbox3.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0003 /* blackbox4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blackbox4.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0004 /* blackbox8.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blackbox8.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0005 /* blackbox9.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blackbox9.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0006 /* bmpdataturbo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bmpdataturbo.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0007 /* drean.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = drean.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0008 /* freezeframe2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = freezeframe2.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0009 /* gmod3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gmod3.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000A /* hyperbasic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hyperbasic.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000B /* ieeeflash64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ieeeflash64.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000C /* ltkernal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ltkernal.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000D /* magicdesk16.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = magicdesk16.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000E /* maxbasic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = maxbasic.c; sourceTree = ""; }; + 41C8CA0923C6183B007C000F /* megabyter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = megabyter.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0010 /* multimax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = multimax.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0011 /* partner64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = partner64.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0012 /* profidos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = profidos.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0013 /* ramlink.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ramlink.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0014 /* rexramfloppy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rexramfloppy.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0015 /* sdbox.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sdbox.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0016 /* turtlegraphics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = turtlegraphics.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0017 /* uc1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uc1.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0018 /* uc2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uc2.c; sourceTree = ""; }; + 41C8CA0923C6183B007C0019 /* zippcode48.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zippcode48.c; sourceTree = ""; }; + 41C8CA0923C6183B007C001A /* artstudiodrv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = artstudiodrv.c; sourceTree = ""; }; + 41C8CA0923C6183B007C001B /* minipaintdrv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = minipaintdrv.c; sourceTree = ""; }; + 41C8CA0923C6183B007C001C /* ffmpegexedrv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpegexedrv.c; sourceTree = ""; }; + 41C8CA0923C6183B007C001D /* zmbvdrv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zmbvdrv.c; sourceTree = ""; }; 41D4AA2823AA0F1000A54EB2 /* gamekiller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gamekiller.h; sourceTree = ""; }; 41D4AA2923AA0F1000A54EB2 /* georam.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = georam.c; sourceTree = ""; }; 41D4AA2A23AA0F1000A54EB2 /* georam.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = georam.h; sourceTree = ""; }; @@ -2797,6 +2934,16 @@ 41D4AA8E23AA0F1000A54EB2 /* cs8900.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cs8900.c; sourceTree = ""; }; 41D4AA8F23AA0F1000A54EB2 /* cs8900.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cs8900.h; sourceTree = ""; }; 41D4AA9023AA0F1000A54EB2 /* flash040core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = flash040core.c; sourceTree = ""; }; + 41C8CA0F23C6183B007C0001 /* cmdhd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "cmdhd.c"; sourceTree = ""; }; + 41C8CA0F23C6183B007C0002 /* rtc-72421.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "rtc-72421.c"; sourceTree = ""; }; + 41C8CA0F23C6183B007C0003 /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sha1.c"; sourceTree = ""; }; + 41C8CA0F23C6183B007C0004 /* iec-ieee488-shared.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "iec-ieee488-shared.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C001E /* flash800core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "flash800core.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C001F /* spi-flash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "spi-flash.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C0020 /* archdep_sleep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "archdep_sleep.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C0021 /* zmbv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "zmbv.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C0022 /* zmbv_avi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "zmbv_avi.c"; sourceTree = ""; }; + 41C8CA0923C6183B007C0023 /* miniz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "miniz.c"; sourceTree = ""; }; 41D4AA9123AA0F1000A54EB2 /* fmopl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmopl.c; sourceTree = ""; }; 41D4AA9223AA0F1000A54EB2 /* fmopl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmopl.h; sourceTree = ""; }; 41D4AA9323AA0F1000A54EB2 /* m93c86.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = m93c86.c; sourceTree = ""; }; @@ -2837,8 +2984,6 @@ 41D4AAB923AA0F1000A54EB2 /* drive-check.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "drive-check.h"; sourceTree = ""; }; 41D4AABA23AA0F1000A54EB2 /* drive-cmdline-options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "drive-cmdline-options.c"; sourceTree = ""; }; 41D4AABB23AA0F1000A54EB2 /* drive-cmdline-options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "drive-cmdline-options.h"; sourceTree = ""; }; - 41D4AABC23AA0F1000A54EB2 /* drive-overflow.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "drive-overflow.c"; sourceTree = ""; }; - 41D4AABD23AA0F1000A54EB2 /* drive-overflow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "drive-overflow.h"; sourceTree = ""; }; 41D4AABE23AA0F1000A54EB2 /* drive-resources.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "drive-resources.c"; sourceTree = ""; }; 41D4AABF23AA0F1000A54EB2 /* drive-resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "drive-resources.h"; sourceTree = ""; }; 41D4AAC023AA0F1000A54EB2 /* drive-snapshot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "drive-snapshot.c"; sourceTree = ""; }; @@ -2936,6 +3081,7 @@ 41D4AB2323AA0F1100A54EB2 /* fsdevice-cmdline-options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "fsdevice-cmdline-options.c"; sourceTree = ""; }; 41D4AB2423AA0F1100A54EB2 /* fsdevice-cmdline-options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "fsdevice-cmdline-options.h"; sourceTree = ""; }; 41D4AB2523AA0F1100A54EB2 /* fsdevice-flush.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "fsdevice-flush.c"; sourceTree = ""; }; + 41C8CA1123C6183B007C0001 /* fsdevice-filename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "fsdevice-filename.c"; sourceTree = ""; }; 41D4AB2623AA0F1100A54EB2 /* fsdevice-flush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "fsdevice-flush.h"; sourceTree = ""; }; 41D4AB2723AA0F1100A54EB2 /* fsdevice-open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "fsdevice-open.c"; sourceTree = ""; }; 41D4AB2823AA0F1100A54EB2 /* fsdevice-open.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "fsdevice-open.h"; sourceTree = ""; }; @@ -2987,6 +3133,36 @@ 41D4AB5A23AA0F1100A54EB2 /* cx85.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cx85.c; sourceTree = ""; }; 41D4AB5B23AA0F1100A54EB2 /* cx85.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cx85.h; sourceTree = ""; }; 41D4AB5C23AA0F1100A54EB2 /* joyport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = joyport.c; sourceTree = ""; }; + 41C8CA0B23C6183B007C0001 /* inception.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "inception.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0002 /* joyport_io_sim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "joyport_io_sim.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0003 /* multijoy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "multijoy.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0004 /* ninja_snespad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "ninja_snespad.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0005 /* paperclip2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "paperclip2.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0006 /* paperclip64e.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "paperclip64e.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0007 /* paperclip64sc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "paperclip64sc.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0008 /* powerpad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "powerpad.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0009 /* protopad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "protopad.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000A /* spaceballs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "spaceballs.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000B /* trapthem_snespad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "trapthem_snespad.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000C /* waasoft_dongle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "waasoft_dongle.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000D /* mouse_1351.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mouse_1351.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000E /* mouse_neos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mouse_neos.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C000F /* mouse_paddle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mouse_paddle.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0010 /* mouse_quadrature.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mouse_quadrature.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0011 /* userport_diag_pin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_diag_pin.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0012 /* userport_io_sim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_io_sim.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0013 /* userport_petscii_snespad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_petscii_snespad.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0014 /* userport_ps2mouse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_ps2mouse.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0015 /* userport_spt_joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_spt_joystick.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0016 /* userport_superpad64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_superpad64.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0017 /* userport_hummer_joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_hummer_joystick.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0018 /* userport_synergy_joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_synergy_joystick.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C0019 /* userport_woj_joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_woj_joystick.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C001A /* userport_hks_joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "userport_hks_joystick.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C001B /* i8255a.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "i8255a.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C001C /* scsi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "scsi.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C001D /* mon_profile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mon_profile.c"; sourceTree = ""; }; + 41C8CA0B23C6183B007C001E /* monitor_binary.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "monitor_binary.c"; sourceTree = ""; }; 41D4AB5D23AA0F1100A54EB2 /* joyport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = joyport.h; sourceTree = ""; }; 41D4AB5E23AA0F1100A54EB2 /* joystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = joystick.c; sourceTree = ""; }; 41D4AB5F23AA0F1100A54EB2 /* joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = joystick.h; sourceTree = ""; }; @@ -3102,6 +3278,9 @@ 41D4ABD423AA0F1100A54EB2 /* printer-serial.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "printer-serial.c"; sourceTree = ""; }; 41D4ABD523AA0F1100A54EB2 /* printer-userport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "printer-userport.c"; sourceTree = ""; }; 41D4ABD623AA0F1100A54EB2 /* printer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = printer.c; sourceTree = ""; }; + 41C8CA0723C6183B007C0031 /* profiler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = profiler.c; sourceTree = ""; }; + 41C8CA0723C6183B007C0032 /* profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profiler.h; sourceTree = ""; }; + 41C8CA0723C6183B007C0033 /* profiler_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = profiler_data.h; sourceTree = ""; }; 41D4ABD823AA0F1100A54EB2 /* raster-cache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "raster-cache.c"; sourceTree = ""; }; 41D4ABD923AA0F1100A54EB2 /* raster-cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "raster-cache.h"; sourceTree = ""; }; 41D4ABDA23AA0F1100A54EB2 /* raster-canvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "raster-canvas.c"; sourceTree = ""; }; @@ -3125,6 +3304,7 @@ 41D4ABEC23AA0F1100A54EB2 /* raster-sprite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "raster-sprite.c"; sourceTree = ""; }; 41D4ABED23AA0F1100A54EB2 /* raster-sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "raster-sprite.h"; sourceTree = ""; }; 41D4ABEE23AA0F1100A54EB2 /* raster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = raster.c; sourceTree = ""; }; + 41C8DEAD23C6183B007C0002 /* raster-snapshot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "raster-snapshot.c"; sourceTree = ""; }; 41D4ABEF23AA0F1100A54EB2 /* raster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = raster.h; sourceTree = ""; }; 41D4ABF123AA0F1100A54EB2 /* resid-config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "resid-config.h"; sourceTree = ""; }; 41D4AC2123AA0F1100A54EB2 /* 6510core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6510core.h; sourceTree = ""; }; @@ -3172,6 +3352,8 @@ 41D4AC4B23AA0F1100A54EB2 /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = ""; }; 41D4AC4C23AA0F1100A54EB2 /* datasette.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = datasette.c; sourceTree = ""; }; 41D4AC4D23AA0F1100A54EB2 /* datasette.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = datasette.h; sourceTree = ""; }; + 41C8CA0723C6183B007C0021 /* datasette-sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "datasette-sound.c"; sourceTree = ""; }; + 41C8CA0723C6183B007C0022 /* datasette-sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "datasette-sound.h"; sourceTree = ""; }; 41D4AC4E23AA0F1100A54EB2 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = debug.c; sourceTree = ""; }; 41D4AC4F23AA0F1100A54EB2 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; 41D4AC5023AA0F1100A54EB2 /* diskconstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = diskconstants.h; sourceTree = ""; }; @@ -3293,10 +3475,6 @@ 41D4ACC423AA0F1100A54EB2 /* tap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tap.h; sourceTree = ""; }; 41D4ACC523AA0F1100A54EB2 /* tape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tape.h; sourceTree = ""; }; 41D4ACC623AA0F1100A54EB2 /* tpi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tpi.h; sourceTree = ""; }; - 41D4ACC723AA0F1100A54EB2 /* translate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = translate.c; sourceTree = ""; }; - 41D4ACC823AA0F1100A54EB2 /* translate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = translate.h; sourceTree = ""; }; - 41D4ACC923AA0F1100A54EB2 /* translate_funcs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = translate_funcs.h; sourceTree = ""; }; - 41D4ACCA23AA0F1100A54EB2 /* translate_languages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = translate_languages.h; sourceTree = ""; }; 41D4ACCB23AA0F1100A54EB2 /* traps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traps.c; sourceTree = ""; }; 41D4ACCC23AA0F1100A54EB2 /* traps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traps.h; sourceTree = ""; }; 41D4ACCD23AA0F1100A54EB2 /* uiapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uiapi.h; sourceTree = ""; }; @@ -3312,6 +3490,7 @@ 41D4ACD723AA0F1100A54EB2 /* vice-crc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "vice-crc32.h"; sourceTree = ""; }; 41D4ACD823AA0F1100A54EB2 /* vice-event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "vice-event.h"; sourceTree = ""; }; 41D4ACD923AA0F1100A54EB2 /* vice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vice.h; sourceTree = ""; }; + A1B2C3D4E5F600001A2B3C4D /* vice_debugger_hook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vice_debugger_hook.h; sourceTree = ""; }; 41D4ACDA23AA0F1100A54EB2 /* vice_sdl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vice_sdl.h; sourceTree = ""; }; 41D4ACDB23AA0F1100A54EB2 /* vicefeatures.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vicefeatures.c; sourceTree = ""; }; 41D4ACDC23AA0F1100A54EB2 /* vicefeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vicefeatures.h; sourceTree = ""; }; @@ -3429,8 +3608,11 @@ 41D4AD5623AA0F1100A54EB2 /* sense-dongle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "sense-dongle.h"; sourceTree = ""; }; 41D4AD5723AA0F1100A54EB2 /* tape_diag_586220_harness.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tape_diag_586220_harness.c; sourceTree = ""; }; 41D4AD5823AA0F1100A54EB2 /* tape_diag_586220_harness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tape_diag_586220_harness.h; sourceTree = ""; }; - 41D4AD5923AA0F1100A54EB2 /* tapelog.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tapelog.c; sourceTree = ""; }; - 41D4AD5A23AA0F1100A54EB2 /* tapelog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tapelog.h; sourceTree = ""; }; + 41C8CA0723C6183B007C0011 /* tapecart.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tapecart.c; sourceTree = ""; }; + 41C8CA0723C6183B007C0013 /* wordcraft-dongle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "wordcraft-dongle.c"; sourceTree = ""; }; + 41C8CA0723C6183B007C0014 /* tapecart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tapecart.h; sourceTree = ""; }; + 41C8CA0723C6183B007C0015 /* tapecart-loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "tapecart-loader.h"; sourceTree = ""; }; + 41C8CA0723C6183B007C0016 /* wordcraft-dongle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "wordcraft-dongle.h"; sourceTree = ""; }; 41D4AD5B23AA0F1100A54EB2 /* tapeport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tapeport.c; sourceTree = ""; }; 41D4AD5C23AA0F1100A54EB2 /* tapeport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tapeport.h; sourceTree = ""; }; 41D4AD5E23AA0F1100A54EB2 /* userport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = userport.c; sourceTree = ""; }; @@ -3509,41 +3691,41 @@ 41D4ADAA23AA0F1100A54EB2 /* viciitypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = viciitypes.h; sourceTree = ""; }; 41D4ADAC23AA0F1100A54EB2 /* render1x1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x1.c; sourceTree = ""; }; 41D4ADAD23AA0F1100A54EB2 /* render1x1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x1.h; sourceTree = ""; }; - 41D4ADAE23AA0F1100A54EB2 /* render1x1crt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x1crt.c; sourceTree = ""; }; - 41D4ADAF23AA0F1100A54EB2 /* render1x1crt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x1crt.h; sourceTree = ""; }; + 41D4ADAE23AA0F1100A54EB2 /* render1x1rgbi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x1rgbi.c; sourceTree = ""; }; + 41D4ADAF23AA0F1100A54EB2 /* render1x1rgbi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x1rgbi.h; sourceTree = ""; }; 41D4ADB023AA0F1100A54EB2 /* render1x1ntsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x1ntsc.c; sourceTree = ""; }; 41D4ADB123AA0F1100A54EB2 /* render1x1ntsc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x1ntsc.h; sourceTree = ""; }; 41D4ADB223AA0F1100A54EB2 /* render1x1pal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x1pal.c; sourceTree = ""; }; 41D4ADB323AA0F1100A54EB2 /* render1x1pal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x1pal.h; sourceTree = ""; }; 41D4ADB423AA0F1100A54EB2 /* render1x2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x2.c; sourceTree = ""; }; 41D4ADB523AA0F1100A54EB2 /* render1x2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x2.h; sourceTree = ""; }; - 41D4ADB623AA0F1100A54EB2 /* render1x2crt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x2crt.c; sourceTree = ""; }; - 41D4ADB723AA0F1100A54EB2 /* render1x2crt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x2crt.h; sourceTree = ""; }; + 41D4ADB623AA0F1100A54EB2 /* render1x2rgbi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render1x2rgbi.c; sourceTree = ""; }; + 41D4ADB723AA0F1100A54EB2 /* render1x2rgbi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render1x2rgbi.h; sourceTree = ""; }; 41D4ADB823AA0F1100A54EB2 /* render2x2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2.c; sourceTree = ""; }; 41D4ADB923AA0F1100A54EB2 /* render2x2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2.h; sourceTree = ""; }; - 41D4ADBA23AA0F1100A54EB2 /* render2x2crt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2crt.c; sourceTree = ""; }; - 41D4ADBB23AA0F1100A54EB2 /* render2x2crt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2crt.h; sourceTree = ""; }; + 41D4ADBA23AA0F1100A54EB2 /* render2x2rgbi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2rgbi.c; sourceTree = ""; }; + 41D4ADBB23AA0F1100A54EB2 /* render2x2rgbi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2rgbi.h; sourceTree = ""; }; 41D4ADBC23AA0F1100A54EB2 /* render2x2ntsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2ntsc.c; sourceTree = ""; }; 41D4ADBD23AA0F1100A54EB2 /* render2x2ntsc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2ntsc.h; sourceTree = ""; }; 41D4ADBE23AA0F1100A54EB2 /* render2x2pal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2pal.c; sourceTree = ""; }; 41D4ADBF23AA0F1100A54EB2 /* render2x2pal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2pal.h; sourceTree = ""; }; 41D4ADC023AA0F1100A54EB2 /* render2x4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x4.c; sourceTree = ""; }; 41D4ADC123AA0F1100A54EB2 /* render2x4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x4.h; sourceTree = ""; }; - 41D4ADC223AA0F1100A54EB2 /* render2x4crt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x4crt.c; sourceTree = ""; }; - 41D4ADC323AA0F1100A54EB2 /* render2x4crt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x4crt.h; sourceTree = ""; }; + 41D4ADC223AA0F1100A54EB2 /* render2x4rgbi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x4rgbi.c; sourceTree = ""; }; + 41D4ADC323AA0F1100A54EB2 /* render2x4rgbi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x4rgbi.h; sourceTree = ""; }; 41D4ADC423AA0F1100A54EB2 /* renderscale2x.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderscale2x.c; sourceTree = ""; }; 41D4ADC523AA0F1100A54EB2 /* renderscale2x.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderscale2x.h; sourceTree = ""; }; - 41D4ADC623AA0F1100A54EB2 /* renderyuv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = renderyuv.c; sourceTree = ""; }; - 41D4ADC723AA0F1100A54EB2 /* renderyuv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderyuv.h; sourceTree = ""; }; + 41D4ADC623AA0F1100A54EB2 /* render2x2palu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = render2x2palu.c; sourceTree = ""; }; + 41D4ADC723AA0F1100A54EB2 /* render2x2palu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render2x2palu.h; sourceTree = ""; }; 41D4ADC823AA0F1100A54EB2 /* video-canvas.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-canvas.c"; sourceTree = ""; }; 41D4ADC923AA0F1100A54EB2 /* video-canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "video-canvas.h"; sourceTree = ""; }; 41D4ADCA23AA0F1100A54EB2 /* video-cmdline-options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-cmdline-options.c"; sourceTree = ""; }; 41D4ADCB23AA0F1100A54EB2 /* video-color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-color.c"; sourceTree = ""; }; 41D4ADCC23AA0F1100A54EB2 /* video-color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "video-color.h"; sourceTree = ""; }; - 41D4ADCD23AA0F1100A54EB2 /* video-render-1x2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-1x2.c"; sourceTree = ""; }; - 41D4ADCE23AA0F1100A54EB2 /* video-render-2x2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-2x2.c"; sourceTree = ""; }; - 41D4ADCF23AA0F1100A54EB2 /* video-render-crt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-crt.c"; sourceTree = ""; }; - 41D4ADD023AA0F1100A54EB2 /* video-render-pal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-pal.c"; sourceTree = ""; }; + 41D4ADCD23AA0F1100A54EB2 /* video-render-crtmono.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-crtmono.c"; sourceTree = ""; }; + 41D4ADCE23AA0F1100A54EB2 /* video-render-rgbi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-rgbi.c"; sourceTree = ""; }; + 41D4ADCF23AA0F1100A54EB2 /* render-common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "render-common.c"; sourceTree = ""; }; + 41D4ADD023AA0F1100A54EB2 /* video-render-palntsc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render-palntsc.c"; sourceTree = ""; }; 41D4ADD123AA0F1100A54EB2 /* video-render.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-render.c"; sourceTree = ""; }; 41D4ADD223AA0F1100A54EB2 /* video-render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "video-render.h"; sourceTree = ""; }; 41D4ADD323AA0F1100A54EB2 /* video-resources.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "video-resources.c"; sourceTree = ""; }; @@ -5547,12 +5729,32 @@ 41D4A92623AA0F1000A54EB2 /* catweaselmkiii.c */, 41D4A92723AA0F1000A54EB2 /* console.c */, 41D4A92823AA0F1000A54EB2 /* coproc.c */, + 41C8CA1323C6183B007C0001 /* rd_ui_stubs.c */, + 41C8CA0D23C6183B007C0001 /* archdep_chdir.c */, + 41C8CA0D23C6183B007C0002 /* archdep_close.c */, + 41C8CA0D23C6183B007C0003 /* archdep_current_dir.c */, + 41C8CA0D23C6183B007C0004 /* archdep_default_portable_resource_file_name.c */, + 41C8CA0D23C6183B007C0005 /* archdep_dir.c */, + 41C8CA0D23C6183B007C0007 /* archdep_exit.c */, + 41C8CA0D23C6183B007C0008 /* archdep_fdopen.c */, + 41C8CA0D23C6183B007C0009 /* archdep_file_exists.c */, + 41C8CA0D23C6183B007C000A /* archdep_file_size.c */, + 41C8CA0D23C6183B007C000B /* archdep_fseeko.c */, + 41C8CA0D23C6183B007C000C /* archdep_ftello.c */, + 41C8CA0D23C6183B007C000D /* archdep_getcwd.c */, + 41C8CA0D23C6183B007C000E /* archdep_is_haiku.c */, + 41C8CA0D23C6183B007C000F /* archdep_quote_unzip.c */, + 41C8CA0D23C6183B007C0010 /* archdep_real_path.c */, + 41C8CA0D23C6183B007C0011 /* archdep_remove.c */, + 41C8CA0D23C6183B007C0012 /* archdep_rmdir.c */, + 41C8CA0D23C6183B007C0013 /* archdep_sound.c */, + 41C8CA0D23C6183B007C0014 /* archdep_usleep.c */, + 41C8CA0923C6183B007C0020 /* archdep_sleep.c */, 41D4A92923AA0F1000A54EB2 /* coproc.h */, 41D4A92A23AA0F1000A54EB2 /* dynlib.c */, 41D4A92B23AA0F1000A54EB2 /* fullscreen.c */, 41D4A92C23AA0F1000A54EB2 /* fullscreenarch.h */, 41D4A92D23AA0F1000A54EB2 /* c64-hardsid.c */, - 41D4A92E23AA0F1000A54EB2 /* joy.c */, 41D4A92F23AA0F1000A54EB2 /* joy.h */, 41D4A93023AA0F1000A54EB2 /* kbd.c */, 41D4A93123AA0F1000A54EB2 /* kbd.h */, @@ -5825,6 +6027,31 @@ 41D4AA2523AA0F1000A54EB2 /* funplay.c */, 41D4AA2623AA0F1000A54EB2 /* funplay.h */, 41D4AA2723AA0F1000A54EB2 /* gamekiller.c */, + 41C8CA0923C6183B007C0001 /* bisplus.c */, + 41C8CA0923C6183B007C0002 /* blackbox3.c */, + 41C8CA0923C6183B007C0003 /* blackbox4.c */, + 41C8CA0923C6183B007C0004 /* blackbox8.c */, + 41C8CA0923C6183B007C0005 /* blackbox9.c */, + 41C8CA0923C6183B007C0006 /* bmpdataturbo.c */, + 41C8CA0923C6183B007C0007 /* drean.c */, + 41C8CA0923C6183B007C0008 /* freezeframe2.c */, + 41C8CA0923C6183B007C0009 /* gmod3.c */, + 41C8CA0923C6183B007C000A /* hyperbasic.c */, + 41C8CA0923C6183B007C000B /* ieeeflash64.c */, + 41C8CA0923C6183B007C000C /* ltkernal.c */, + 41C8CA0923C6183B007C000D /* magicdesk16.c */, + 41C8CA0923C6183B007C000E /* maxbasic.c */, + 41C8CA0923C6183B007C000F /* megabyter.c */, + 41C8CA0923C6183B007C0010 /* multimax.c */, + 41C8CA0923C6183B007C0011 /* partner64.c */, + 41C8CA0923C6183B007C0012 /* profidos.c */, + 41C8CA0923C6183B007C0013 /* ramlink.c */, + 41C8CA0923C6183B007C0014 /* rexramfloppy.c */, + 41C8CA0923C6183B007C0015 /* sdbox.c */, + 41C8CA0923C6183B007C0016 /* turtlegraphics.c */, + 41C8CA0923C6183B007C0017 /* uc1.c */, + 41C8CA0923C6183B007C0018 /* uc2.c */, + 41C8CA0923C6183B007C0019 /* zippcode48.c */, 41D4AA2823AA0F1000A54EB2 /* gamekiller.h */, 41D4AA2923AA0F1000A54EB2 /* georam.c */, 41D4AA2A23AA0F1000A54EB2 /* georam.h */, @@ -5925,6 +6152,11 @@ 41D4AA8E23AA0F1000A54EB2 /* cs8900.c */, 41D4AA8F23AA0F1000A54EB2 /* cs8900.h */, 41D4AA9023AA0F1000A54EB2 /* flash040core.c */, + 41C8CA0F23C6183B007C0002 /* rtc-72421.c */, + 41C8CA0B23C6183B007C001B /* i8255a.c */, + 41C8CA0B23C6183B007C001C /* scsi.c */, + 41C8CA0923C6183B007C001E /* flash800core.c */, + 41C8CA0923C6183B007C001F /* spi-flash.c */, 41D4AA9123AA0F1000A54EB2 /* fmopl.c */, 41D4AA9223AA0F1000A54EB2 /* fmopl.h */, 41D4AA9323AA0F1000A54EB2 /* m93c86.c */, @@ -5987,8 +6219,6 @@ 41D4AAB923AA0F1000A54EB2 /* drive-check.h */, 41D4AABA23AA0F1000A54EB2 /* drive-cmdline-options.c */, 41D4AABB23AA0F1000A54EB2 /* drive-cmdline-options.h */, - 41D4AABC23AA0F1000A54EB2 /* drive-overflow.c */, - 41D4AABD23AA0F1000A54EB2 /* drive-overflow.h */, 41D4AABE23AA0F1000A54EB2 /* drive-resources.c */, 41D4AABF23AA0F1000A54EB2 /* drive-resources.h */, 41D4AAC023AA0F1000A54EB2 /* drive-snapshot.c */, @@ -6050,6 +6280,7 @@ 41D4AAF423AA0F1000A54EB2 /* pc8477.c */, 41D4AAF523AA0F1000A54EB2 /* pc8477.h */, 41D4AAF623AA0F1000A54EB2 /* via1d1541.c */, + 41C8CA0F23C6183B007C0001 /* cmdhd.c */, 41D4AAF723AA0F1000A54EB2 /* via1d1541.h */, 41D4AAF823AA0F1000A54EB2 /* via4000.c */, 41D4AAF923AA0F1000A54EB2 /* via4000.h */, @@ -6140,6 +6371,7 @@ 41D4AB2323AA0F1100A54EB2 /* fsdevice-cmdline-options.c */, 41D4AB2423AA0F1100A54EB2 /* fsdevice-cmdline-options.h */, 41D4AB2523AA0F1100A54EB2 /* fsdevice-flush.c */, + 41C8CA1123C6183B007C0001 /* fsdevice-filename.c */, 41D4AB2623AA0F1100A54EB2 /* fsdevice-flush.h */, 41D4AB2723AA0F1100A54EB2 /* fsdevice-open.c */, 41D4AB2823AA0F1100A54EB2 /* fsdevice-open.h */, @@ -6159,6 +6391,13 @@ isa = PBXGroup; children = ( 41D4AB3223AA0F1100A54EB2 /* bmpdrv.c */, + 41C8CA0923C6183B007C0021 /* zmbv.c */, + 41C8CA0923C6183B007C0022 /* zmbv_avi.c */, + 41C8CA0923C6183B007C0023 /* miniz.c */, + 41C8CA0923C6183B007C001A /* artstudiodrv.c */, + 41C8CA0923C6183B007C001B /* minipaintdrv.c */, + 41C8CA0923C6183B007C001C /* ffmpegexedrv.c */, + 41C8CA0923C6183B007C001D /* zmbvdrv.c */, 41D4AB3323AA0F1100A54EB2 /* bmpdrv.h */, 41D4AB3423AA0F1100A54EB2 /* doodledrv.c */, 41D4AB3523AA0F1100A54EB2 /* doodledrv.h */, @@ -6219,6 +6458,22 @@ 41D4AB5A23AA0F1100A54EB2 /* cx85.c */, 41D4AB5B23AA0F1100A54EB2 /* cx85.h */, 41D4AB5C23AA0F1100A54EB2 /* joyport.c */, + 41C8CA0B23C6183B007C0001 /* inception.c */, + 41C8CA0B23C6183B007C0002 /* joyport_io_sim.c */, + 41C8CA0B23C6183B007C0003 /* multijoy.c */, + 41C8CA0B23C6183B007C0004 /* ninja_snespad.c */, + 41C8CA0B23C6183B007C0005 /* paperclip2.c */, + 41C8CA0B23C6183B007C0006 /* paperclip64e.c */, + 41C8CA0B23C6183B007C0007 /* paperclip64sc.c */, + 41C8CA0B23C6183B007C0008 /* powerpad.c */, + 41C8CA0B23C6183B007C0009 /* protopad.c */, + 41C8CA0B23C6183B007C000A /* spaceballs.c */, + 41C8CA0B23C6183B007C000B /* trapthem_snespad.c */, + 41C8CA0B23C6183B007C000C /* waasoft_dongle.c */, + 41C8CA0B23C6183B007C000D /* mouse_1351.c */, + 41C8CA0B23C6183B007C000E /* mouse_neos.c */, + 41C8CA0B23C6183B007C000F /* mouse_paddle.c */, + 41C8CA0B23C6183B007C0010 /* mouse_quadrature.c */, 41D4AB5D23AA0F1100A54EB2 /* joyport.h */, 41D4AB5E23AA0F1100A54EB2 /* joystick.c */, 41D4AB5F23AA0F1100A54EB2 /* joystick.h */, @@ -6304,6 +6559,8 @@ 41D4AB9D23AA0F1100A54EB2 /* mon_util.c */, 41D4AB9E23AA0F1100A54EB2 /* mon_util.h */, 41D4AB9F23AA0F1100A54EB2 /* monitor.c */, + 41C8CA0B23C6183B007C001D /* mon_profile.c */, + 41C8CA0B23C6183B007C001E /* monitor_binary.c */, 41D4ABA023AA0F1100A54EB2 /* monitor_network.c */, 41D4ABA123AA0F1100A54EB2 /* monitor_network.h */, 41D4ABA223AA0F1100A54EB2 /* montypes.h */, @@ -6407,6 +6664,7 @@ 41D4ABEC23AA0F1100A54EB2 /* raster-sprite.c */, 41D4ABED23AA0F1100A54EB2 /* raster-sprite.h */, 41D4ABEE23AA0F1100A54EB2 /* raster.c */, + 41C8DEAD23C6183B007C0002 /* raster-snapshot.c */, 41D4ABEF23AA0F1100A54EB2 /* raster.h */, ); path = raster; @@ -6519,7 +6777,13 @@ 41D4AC4A23AA0F1100A54EB2 /* color.h */, 41D4AC4B23AA0F1100A54EB2 /* console.h */, 41D4AC4C23AA0F1100A54EB2 /* datasette.c */, + 41C8CA0F23C6183B007C0003 /* sha1.c */, 41D4AC4D23AA0F1100A54EB2 /* datasette.h */, + 41C8CA0723C6183B007C0021 /* datasette-sound.c */, + 41C8CA0723C6183B007C0022 /* datasette-sound.h */, + 41C8CA0723C6183B007C0031 /* profiler.c */, + 41C8CA0723C6183B007C0032 /* profiler.h */, + 41C8CA0723C6183B007C0033 /* profiler_data.h */, 41D4AC4E23AA0F1100A54EB2 /* debug.c */, 41D4AC4F23AA0F1100A54EB2 /* debug.h */, 41D4AC5023AA0F1100A54EB2 /* diskconstants.h */, @@ -6641,10 +6905,6 @@ 41D4ACC423AA0F1100A54EB2 /* tap.h */, 41D4ACC523AA0F1100A54EB2 /* tape.h */, 41D4ACC623AA0F1100A54EB2 /* tpi.h */, - 41D4ACC723AA0F1100A54EB2 /* translate.c */, - 41D4ACC823AA0F1100A54EB2 /* translate.h */, - 41D4ACC923AA0F1100A54EB2 /* translate_funcs.h */, - 41D4ACCA23AA0F1100A54EB2 /* translate_languages.h */, 41D4ACCB23AA0F1100A54EB2 /* traps.c */, 41D4ACCC23AA0F1100A54EB2 /* traps.h */, 41D4ACCD23AA0F1100A54EB2 /* uiapi.h */, @@ -6660,6 +6920,7 @@ 41D4ACD723AA0F1100A54EB2 /* vice-crc32.h */, 41D4ACD823AA0F1100A54EB2 /* vice-event.h */, 41D4ACD923AA0F1100A54EB2 /* vice.h */, + A1B2C3D4E5F600001A2B3C4D /* vice_debugger_hook.h */, 41D4ACDA23AA0F1100A54EB2 /* vice_sdl.h */, 41D4ACDB23AA0F1100A54EB2 /* vicefeatures.c */, 41D4ACDC23AA0F1100A54EB2 /* vicefeatures.h */, @@ -6755,6 +7016,7 @@ 41D4AD1E23AA0F1100A54EB2 /* serial-iec-bus.c */, 41D4AD1F23AA0F1100A54EB2 /* serial-iec-bus.h */, 41D4AD2023AA0F1100A54EB2 /* serial-iec-device.c */, + 41C8CA0F23C6183B007C0004 /* iec-ieee488-shared.c */, 41D4AD2123AA0F1100A54EB2 /* serial-iec-device.h */, 41D4AD2223AA0F1100A54EB2 /* serial-iec-lib.c */, 41D4AD2323AA0F1100A54EB2 /* serial-iec.c */, @@ -6835,8 +7097,11 @@ 41D4AD5623AA0F1100A54EB2 /* sense-dongle.h */, 41D4AD5723AA0F1100A54EB2 /* tape_diag_586220_harness.c */, 41D4AD5823AA0F1100A54EB2 /* tape_diag_586220_harness.h */, - 41D4AD5923AA0F1100A54EB2 /* tapelog.c */, - 41D4AD5A23AA0F1100A54EB2 /* tapelog.h */, + 41C8CA0723C6183B007C0011 /* tapecart.c */, + 41C8CA0723C6183B007C0014 /* tapecart.h */, + 41C8CA0723C6183B007C0015 /* tapecart-loader.h */, + 41C8CA0723C6183B007C0013 /* wordcraft-dongle.c */, + 41C8CA0723C6183B007C0016 /* wordcraft-dongle.h */, 41D4AD5B23AA0F1100A54EB2 /* tapeport.c */, 41D4AD5C23AA0F1100A54EB2 /* tapeport.h */, ); @@ -6847,6 +7112,16 @@ isa = PBXGroup; children = ( 41D4AD5E23AA0F1100A54EB2 /* userport.c */, + 41C8CA0B23C6183B007C0011 /* userport_diag_pin.c */, + 41C8CA0B23C6183B007C0012 /* userport_io_sim.c */, + 41C8CA0B23C6183B007C0013 /* userport_petscii_snespad.c */, + 41C8CA0B23C6183B007C0014 /* userport_ps2mouse.c */, + 41C8CA0B23C6183B007C0015 /* userport_spt_joystick.c */, + 41C8CA0B23C6183B007C0016 /* userport_superpad64.c */, + 41C8CA0B23C6183B007C0017 /* userport_hummer_joystick.c */, + 41C8CA0B23C6183B007C0018 /* userport_synergy_joystick.c */, + 41C8CA0B23C6183B007C0019 /* userport_woj_joystick.c */, + 41C8CA0B23C6183B007C001A /* userport_hks_joystick.c */, 41D4AD5F23AA0F1100A54EB2 /* userport.h */, 41D4AD6023AA0F1100A54EB2 /* userport_4bit_sampler.c */, 41D4AD6123AA0F1100A54EB2 /* userport_4bit_sampler.h */, @@ -6957,41 +7232,41 @@ children = ( 41D4ADAC23AA0F1100A54EB2 /* render1x1.c */, 41D4ADAD23AA0F1100A54EB2 /* render1x1.h */, - 41D4ADAE23AA0F1100A54EB2 /* render1x1crt.c */, - 41D4ADAF23AA0F1100A54EB2 /* render1x1crt.h */, + 41D4ADAE23AA0F1100A54EB2 /* render1x1rgbi.c */, + 41D4ADAF23AA0F1100A54EB2 /* render1x1rgbi.h */, 41D4ADB023AA0F1100A54EB2 /* render1x1ntsc.c */, 41D4ADB123AA0F1100A54EB2 /* render1x1ntsc.h */, 41D4ADB223AA0F1100A54EB2 /* render1x1pal.c */, 41D4ADB323AA0F1100A54EB2 /* render1x1pal.h */, 41D4ADB423AA0F1100A54EB2 /* render1x2.c */, 41D4ADB523AA0F1100A54EB2 /* render1x2.h */, - 41D4ADB623AA0F1100A54EB2 /* render1x2crt.c */, - 41D4ADB723AA0F1100A54EB2 /* render1x2crt.h */, + 41D4ADB623AA0F1100A54EB2 /* render1x2rgbi.c */, + 41D4ADB723AA0F1100A54EB2 /* render1x2rgbi.h */, 41D4ADB823AA0F1100A54EB2 /* render2x2.c */, 41D4ADB923AA0F1100A54EB2 /* render2x2.h */, - 41D4ADBA23AA0F1100A54EB2 /* render2x2crt.c */, - 41D4ADBB23AA0F1100A54EB2 /* render2x2crt.h */, + 41D4ADBA23AA0F1100A54EB2 /* render2x2rgbi.c */, + 41D4ADBB23AA0F1100A54EB2 /* render2x2rgbi.h */, 41D4ADBC23AA0F1100A54EB2 /* render2x2ntsc.c */, 41D4ADBD23AA0F1100A54EB2 /* render2x2ntsc.h */, 41D4ADBE23AA0F1100A54EB2 /* render2x2pal.c */, 41D4ADBF23AA0F1100A54EB2 /* render2x2pal.h */, 41D4ADC023AA0F1100A54EB2 /* render2x4.c */, 41D4ADC123AA0F1100A54EB2 /* render2x4.h */, - 41D4ADC223AA0F1100A54EB2 /* render2x4crt.c */, - 41D4ADC323AA0F1100A54EB2 /* render2x4crt.h */, + 41D4ADC223AA0F1100A54EB2 /* render2x4rgbi.c */, + 41D4ADC323AA0F1100A54EB2 /* render2x4rgbi.h */, 41D4ADC423AA0F1100A54EB2 /* renderscale2x.c */, 41D4ADC523AA0F1100A54EB2 /* renderscale2x.h */, - 41D4ADC623AA0F1100A54EB2 /* renderyuv.c */, - 41D4ADC723AA0F1100A54EB2 /* renderyuv.h */, + 41D4ADC623AA0F1100A54EB2 /* render2x2palu.c */, + 41D4ADC723AA0F1100A54EB2 /* render2x2palu.h */, 41D4ADC823AA0F1100A54EB2 /* video-canvas.c */, 41D4ADC923AA0F1100A54EB2 /* video-canvas.h */, 41D4ADCA23AA0F1100A54EB2 /* video-cmdline-options.c */, 41D4ADCB23AA0F1100A54EB2 /* video-color.c */, 41D4ADCC23AA0F1100A54EB2 /* video-color.h */, - 41D4ADCD23AA0F1100A54EB2 /* video-render-1x2.c */, - 41D4ADCE23AA0F1100A54EB2 /* video-render-2x2.c */, - 41D4ADCF23AA0F1100A54EB2 /* video-render-crt.c */, - 41D4ADD023AA0F1100A54EB2 /* video-render-pal.c */, + 41D4ADCD23AA0F1100A54EB2 /* video-render-crtmono.c */, + 41D4ADCE23AA0F1100A54EB2 /* video-render-rgbi.c */, + 41D4ADCF23AA0F1100A54EB2 /* render-common.c */, + 41D4ADD023AA0F1100A54EB2 /* video-render-palntsc.c */, 41D4ADD123AA0F1100A54EB2 /* video-render.c */, 41D4ADD223AA0F1100A54EB2 /* video-render.h */, 41D4ADD323AA0F1100A54EB2 /* video-resources.c */, @@ -7492,7 +7767,6 @@ files = ( 411D2E402D71D4D3007714A9 /* CRenderShaderCRTMonitorOpenGL4.cpp in Sources */, 41805F602BC756CF00344BD9 /* CDataAddressEditBoxHex.cpp in Sources */, - 41D699732AFA6284008124F6 /* c1541.c in Sources */, 410836D02AD15E6D0086B9BA /* C64SIDDump.cpp in Sources */, 419703EC28D36FD100DDD728 /* AtariAsap.cpp in Sources */, 419703ED28D36FD100DDD728 /* asap.c in Sources */, @@ -7609,10 +7883,29 @@ 416FDA9C28D5FF41003DAB13 /* CVicEditorLayerC64Canvas.cpp in Sources */, 41C84C3023C6183A007C0889 /* console.c in Sources */, 41C84C3123C6183A007C0889 /* coproc.c in Sources */, + 41C8CA1223C6183B007C0001 /* rd_ui_stubs.c in Sources */, + 41C8CA0C23C6183B007C0001 /* archdep_chdir.c in Sources */, + 41C8CA0C23C6183B007C0002 /* archdep_close.c in Sources */, + 41C8CA0C23C6183B007C0003 /* archdep_current_dir.c in Sources */, + 41C8CA0C23C6183B007C0004 /* archdep_default_portable_resource_file_name.c in Sources */, + 41C8CA0C23C6183B007C0005 /* archdep_dir.c in Sources */, + 41C8CA0C23C6183B007C0007 /* archdep_exit.c in Sources */, + 41C8CA0C23C6183B007C0008 /* archdep_fdopen.c in Sources */, + 41C8CA0C23C6183B007C0009 /* archdep_file_exists.c in Sources */, + 41C8CA0C23C6183B007C000A /* archdep_file_size.c in Sources */, + 41C8CA0C23C6183B007C000B /* archdep_fseeko.c in Sources */, + 41C8CA0C23C6183B007C000C /* archdep_ftello.c in Sources */, + 41C8CA0C23C6183B007C000D /* archdep_getcwd.c in Sources */, + 41C8CA0C23C6183B007C000E /* archdep_is_haiku.c in Sources */, + 41C8CA0C23C6183B007C000F /* archdep_quote_unzip.c in Sources */, + 41C8CA0C23C6183B007C0010 /* archdep_real_path.c in Sources */, + 41C8CA0C23C6183B007C0011 /* archdep_remove.c in Sources */, + 41C8CA0C23C6183B007C0012 /* archdep_rmdir.c in Sources */, + 41C8CA0C23C6183B007C0013 /* archdep_sound.c in Sources */, + 41C8CA0C23C6183B007C0014 /* archdep_usleep.c in Sources */, 41C84C3223C6183A007C0889 /* dynlib.c in Sources */, 41C84C3323C6183A007C0889 /* fullscreen.c in Sources */, 41C84C3423C6183A007C0889 /* c64-hardsid.c in Sources */, - 41C84C3523C6183A007C0889 /* joy.c in Sources */, 41BA937C2AEAACF30006D4F0 /* CViewDataPlot.cpp in Sources */, 41C84C3623C6183A007C0889 /* kbd.c in Sources */, 41C84C3723C6183A007C0889 /* lightpendrv.c in Sources */, @@ -7767,6 +8060,35 @@ 41C84CB823C6183B007C0889 /* freezemachine.c in Sources */, 41C84CB923C6183B007C0889 /* funplay.c in Sources */, 41C84CBA23C6183B007C0889 /* gamekiller.c in Sources */, + 41C8CA0823C6183B007C0001 /* bisplus.c in Sources */, + 41C8CA0823C6183B007C0002 /* blackbox3.c in Sources */, + 41C8CA0823C6183B007C0003 /* blackbox4.c in Sources */, + 41C8CA0823C6183B007C0004 /* blackbox8.c in Sources */, + 41C8CA0823C6183B007C0005 /* blackbox9.c in Sources */, + 41C8CA0823C6183B007C0006 /* bmpdataturbo.c in Sources */, + 41C8CA0823C6183B007C0007 /* drean.c in Sources */, + 41C8CA0823C6183B007C0008 /* freezeframe2.c in Sources */, + 41C8CA0823C6183B007C0009 /* gmod3.c in Sources */, + 41C8CA0823C6183B007C000A /* hyperbasic.c in Sources */, + 41C8CA0823C6183B007C000B /* ieeeflash64.c in Sources */, + 41C8CA0823C6183B007C000C /* ltkernal.c in Sources */, + 41C8CA0823C6183B007C000D /* magicdesk16.c in Sources */, + 41C8CA0823C6183B007C000E /* maxbasic.c in Sources */, + 41C8CA0823C6183B007C000F /* megabyter.c in Sources */, + 41C8CA0823C6183B007C0010 /* multimax.c in Sources */, + 41C8CA0823C6183B007C0011 /* partner64.c in Sources */, + 41C8CA0823C6183B007C0012 /* profidos.c in Sources */, + 41C8CA0823C6183B007C0013 /* ramlink.c in Sources */, + 41C8CA0823C6183B007C0014 /* rexramfloppy.c in Sources */, + 41C8CA0823C6183B007C0015 /* sdbox.c in Sources */, + 41C8CA0823C6183B007C0016 /* turtlegraphics.c in Sources */, + 41C8CA0823C6183B007C0017 /* uc1.c in Sources */, + 41C8CA0823C6183B007C0018 /* uc2.c in Sources */, + 41C8CA0823C6183B007C0019 /* zippcode48.c in Sources */, + 41C8CA0823C6183B007C001A /* artstudiodrv.c in Sources */, + 41C8CA0823C6183B007C001B /* minipaintdrv.c in Sources */, + 41C8CA0823C6183B007C001C /* ffmpegexedrv.c in Sources */, + 41C8CA0823C6183B007C001D /* zmbvdrv.c in Sources */, 41C84CBB23C6183B007C0889 /* georam.c in Sources */, 41F665B52CB1215300EFFFD5 /* CDebugBreakpointEventCallback.cpp in Sources */, 41C84CBC23C6183B007C0889 /* gmod2.c in Sources */, @@ -7826,6 +8148,16 @@ 41C84CEC23C6183B007C0889 /* ciatimer.c in Sources */, 41C84CED23C6183B007C0889 /* cs8900.c in Sources */, 41C84CEE23C6183B007C0889 /* flash040core.c in Sources */, + 41C8CA0E23C6183B007C0001 /* cmdhd.c in Sources */, + 41C8CA0E23C6183B007C0002 /* rtc-72421.c in Sources */, + 41C8CA0E23C6183B007C0003 /* sha1.c in Sources */, + 41C8CA0E23C6183B007C0004 /* iec-ieee488-shared.c in Sources */, + 41C8CA0823C6183B007C001E /* flash800core.c in Sources */, + 41C8CA0823C6183B007C001F /* spi-flash.c in Sources */, + 41C8CA0823C6183B007C0020 /* archdep_sleep.c in Sources */, + 41C8CA0823C6183B007C0021 /* zmbv.c in Sources */, + 41C8CA0823C6183B007C0022 /* zmbv_avi.c in Sources */, + 41C8CA0823C6183B007C0023 /* miniz.c in Sources */, 41C84CEF23C6183B007C0889 /* fmopl.c in Sources */, 41BFDD152BC84BDE00002182 /* CDataAddressEditBoxDiskContents.cpp in Sources */, 41C84CF023C6183B007C0889 /* m93c86.c in Sources */, @@ -7850,7 +8182,6 @@ 41C84D0123C6183B007C0889 /* rawimage.c in Sources */, 41C84D0223C6183B007C0889 /* drive-check.c in Sources */, 41C84D0323C6183B007C0889 /* drive-cmdline-options.c in Sources */, - 41C84D0423C6183B007C0889 /* drive-overflow.c in Sources */, 41C84D0523C6183B007C0889 /* drive-resources.c in Sources */, 41C84D0623C6183B007C0889 /* drive-snapshot.c in Sources */, 41C84D0723C6183B007C0889 /* drive-sound.c in Sources */, @@ -7910,6 +8241,7 @@ 41C84D3423C6183B007C0889 /* fsdevice-close.c in Sources */, 41C84D3523C6183B007C0889 /* fsdevice-cmdline-options.c in Sources */, 41C84D3623C6183B007C0889 /* fsdevice-flush.c in Sources */, + 41C8CA1023C6183B007C0001 /* fsdevice-filename.c in Sources */, 41C84D3723C6183B007C0889 /* fsdevice-open.c in Sources */, 41C84D3823C6183B007C0889 /* fsdevice-read.c in Sources */, 41C84D3923C6183B007C0889 /* fsdevice-resources.c in Sources */, @@ -7944,6 +8276,36 @@ 41EE302425E92A930050257F /* CViewNesStatePPU.cpp in Sources */, 41C84D5123C6183B007C0889 /* cx85.c in Sources */, 41C84D5223C6183B007C0889 /* joyport.c in Sources */, + 41C8CA0A23C6183B007C0001 /* inception.c in Sources */, + 41C8CA0A23C6183B007C0002 /* joyport_io_sim.c in Sources */, + 41C8CA0A23C6183B007C0003 /* multijoy.c in Sources */, + 41C8CA0A23C6183B007C0004 /* ninja_snespad.c in Sources */, + 41C8CA0A23C6183B007C0005 /* paperclip2.c in Sources */, + 41C8CA0A23C6183B007C0006 /* paperclip64e.c in Sources */, + 41C8CA0A23C6183B007C0007 /* paperclip64sc.c in Sources */, + 41C8CA0A23C6183B007C0008 /* powerpad.c in Sources */, + 41C8CA0A23C6183B007C0009 /* protopad.c in Sources */, + 41C8CA0A23C6183B007C000A /* spaceballs.c in Sources */, + 41C8CA0A23C6183B007C000B /* trapthem_snespad.c in Sources */, + 41C8CA0A23C6183B007C000C /* waasoft_dongle.c in Sources */, + 41C8CA0A23C6183B007C000D /* mouse_1351.c in Sources */, + 41C8CA0A23C6183B007C000E /* mouse_neos.c in Sources */, + 41C8CA0A23C6183B007C000F /* mouse_paddle.c in Sources */, + 41C8CA0A23C6183B007C0010 /* mouse_quadrature.c in Sources */, + 41C8CA0A23C6183B007C0011 /* userport_diag_pin.c in Sources */, + 41C8CA0A23C6183B007C0012 /* userport_io_sim.c in Sources */, + 41C8CA0A23C6183B007C0013 /* userport_petscii_snespad.c in Sources */, + 41C8CA0A23C6183B007C0014 /* userport_ps2mouse.c in Sources */, + 41C8CA0A23C6183B007C0015 /* userport_spt_joystick.c in Sources */, + 41C8CA0A23C6183B007C0016 /* userport_superpad64.c in Sources */, + 41C8CA0A23C6183B007C0017 /* userport_hummer_joystick.c in Sources */, + 41C8CA0A23C6183B007C0018 /* userport_synergy_joystick.c in Sources */, + 41C8CA0A23C6183B007C0019 /* userport_woj_joystick.c in Sources */, + 41C8CA0A23C6183B007C001A /* userport_hks_joystick.c in Sources */, + 41C8CA0A23C6183B007C001B /* i8255a.c in Sources */, + 41C8CA0A23C6183B007C001C /* scsi.c in Sources */, + 41C8CA0A23C6183B007C001D /* mon_profile.c in Sources */, + 41C8CA0A23C6183B007C001E /* monitor_binary.c in Sources */, 41C84D5323C6183B007C0889 /* joystick.c in Sources */, 41C84D5423C6183B007C0889 /* lightpen.c in Sources */, 41C84D5523C6183B007C0889 /* mouse.c in Sources */, @@ -8021,6 +8383,7 @@ 41C84D9223C6183B007C0889 /* printer-serial.c in Sources */, 41C84D9323C6183B007C0889 /* printer-userport.c in Sources */, 41C84D9423C6183B007C0889 /* printer.c in Sources */, + 41C8CA0723C6183B007C0030 /* profiler.c in Sources */, 41C84D9523C6183B007C0889 /* raster-cache.c in Sources */, 41C84D9623C6183B007C0889 /* raster-canvas.c in Sources */, 4113CE9825F8AF2000FB1236 /* TextEditor.cpp in Sources */, @@ -8035,6 +8398,7 @@ 41C84D9F23C6183B007C0889 /* raster-sprite-status.c in Sources */, 41C84DA023C6183B007C0889 /* raster-sprite.c in Sources */, 41C84DA123C6183B007C0889 /* raster.c in Sources */, + 41C8DEAD23C6183B007C0001 /* raster-snapshot.c in Sources */, 41C84DA223C6183B007C0889 /* alarm.c in Sources */, 41C84DA323C6183B007C0889 /* attach.c in Sources */, 41C84DA423C6183B007C0889 /* autostart-prg.c in Sources */, @@ -8049,6 +8413,7 @@ 41C84DAC23C6183B007C0889 /* color.c in Sources */, 41EE302925E92A930050257F /* CViewNesPpuPatterns.cpp in Sources */, 41C84DAD23C6183B007C0889 /* datasette.c in Sources */, + 41C8CA0723C6183B007C0020 /* datasette-sound.c in Sources */, 41C84DAE23C6183B007C0889 /* debug.c in Sources */, 41C84DAF23C6183B007C0889 /* dma.c in Sources */, 41C84DB023C6183B007C0889 /* embedded.c in Sources */, @@ -8087,7 +8452,6 @@ 41C84DCE23C6183B007C0889 /* socket.c in Sources */, 41C84DCF23C6183B007C0889 /* sound.c in Sources */, 41C84DD023C6183B007C0889 /* sysfile.c in Sources */, - 41C84DD123C6183B007C0889 /* translate.c in Sources */, 41C84DD223C6183B007C0889 /* traps.c in Sources */, 41E9A5CA26301C58008F013A /* CAudioChannelGoatTracker.cpp in Sources */, 41C84DD323C6183B007C0889 /* util.c in Sources */, @@ -8154,7 +8518,8 @@ 41C84E0523C6183B007C0889 /* dtl-basic-dongle.c in Sources */, 41C84E0623C6183B007C0889 /* sense-dongle.c in Sources */, 41C84E0723C6183B007C0889 /* tape_diag_586220_harness.c in Sources */, - 41C84E0823C6183B007C0889 /* tapelog.c in Sources */, + 41C8CA0723C6183B007C0010 /* tapecart.c in Sources */, + 41C8CA0723C6183B007C0012 /* wordcraft-dongle.c in Sources */, 41C84E0923C6183B007C0889 /* tapeport.c in Sources */, 41C84E0A23C6183B007C0889 /* userport.c in Sources */, 41C84E0B23C6183B007C0889 /* userport_4bit_sampler.c in Sources */, @@ -8194,30 +8559,29 @@ 41C84E2823C6183B007C0889 /* vicii-timing.c in Sources */, 41C84E2923C6183B007C0889 /* vicii.c in Sources */, 41C84E2A23C6183B007C0889 /* render1x1.c in Sources */, - 41C84E2B23C6183B007C0889 /* render1x1crt.c in Sources */, + 41C84E2B23C6183B007C0889 /* render1x1rgbi.c in Sources */, 41C84E2C23C6183B007C0889 /* render1x1ntsc.c in Sources */, 41C84E2D23C6183B007C0889 /* render1x1pal.c in Sources */, 41C84E2E23C6183B007C0889 /* render1x2.c in Sources */, 41FD535B293CD9420051A851 /* CViewC64AllGraphicsBitmaps.cpp in Sources */, - 41C84E2F23C6183B007C0889 /* render1x2crt.c in Sources */, + 41C84E2F23C6183B007C0889 /* render1x2rgbi.c in Sources */, 41C84E3023C6183B007C0889 /* render2x2.c in Sources */, - 41C84E3123C6183B007C0889 /* render2x2crt.c in Sources */, + 41C84E3123C6183B007C0889 /* render2x2rgbi.c in Sources */, 416C256A28D6A3DB002BDC0D /* CVicEditorBrush.cpp in Sources */, 41C84E3223C6183B007C0889 /* render2x2ntsc.c in Sources */, 41C84E3323C6183B007C0889 /* render2x2pal.c in Sources */, 41C84E3423C6183B007C0889 /* render2x4.c in Sources */, 4134D04D2B06CBB90032BE07 /* CViewDrive1541DiskData.cpp in Sources */, - 41C84E3523C6183B007C0889 /* render2x4crt.c in Sources */, + 41C84E3523C6183B007C0889 /* render2x4rgbi.c in Sources */, 41C84E3623C6183B007C0889 /* renderscale2x.c in Sources */, - 41C84E3723C6183B007C0889 /* renderyuv.c in Sources */, + 41C84E3723C6183B007C0889 /* render2x2palu.c in Sources */, 4110D864262BE2A400CF6F36 /* gt-log.c in Sources */, 41C84E3823C6183B007C0889 /* video-canvas.c in Sources */, 41C84E3923C6183B007C0889 /* video-cmdline-options.c in Sources */, 41C84E3A23C6183B007C0889 /* video-color.c in Sources */, - 41C84E3B23C6183B007C0889 /* video-render-1x2.c in Sources */, - 41C84E3C23C6183B007C0889 /* video-render-2x2.c in Sources */, - 41C84E3D23C6183B007C0889 /* video-render-crt.c in Sources */, - 41C84E3E23C6183B007C0889 /* video-render-pal.c in Sources */, + 41C84E3B23C6183B007C0889 /* video-render-crtmono.c in Sources */, + 41C84E3C23C6183B007C0889 /* video-render-rgbi.c in Sources */, + 41C84E3E23C6183B007C0889 /* video-render-palntsc.c in Sources */, 41C84E3F23C6183B007C0889 /* video-render.c in Sources */, 41C84E4023C6183B007C0889 /* video-resources.c in Sources */, 41C84E4123C6183B007C0889 /* video-sound.c in Sources */, @@ -8833,6 +9197,7 @@ GCC_C_LANGUAGE_STANDARD = c17; GCC_PREPROCESSOR_DEFINITIONS = ( MACOS, + RETRODEBUGGER, ENABLE_IMGUI_TEST_ENGINE, "$(inherited)", ); @@ -8843,6 +9208,8 @@ /usr/local/include/freetype2, "$(PROJECT_DIR)/../../src/Tests", "$(PROJECT_DIR)/../../../MTEngineSDL/src/Engine/Tests", + "$(PROJECT_DIR)/../../src/Emulators/vice", + "$(PROJECT_DIR)/../../src/Emulators/vice/**", ); INFOPLIST_FILE = "$(SRCROOT)/src.MacOS/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Retro Debugger"; @@ -8885,6 +9252,7 @@ GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( MACOS, + RETRODEBUGGER, ENABLE_IMGUI_TEST_ENGINE, ); HEADER_SEARCH_PATHS = ( @@ -8894,6 +9262,8 @@ /usr/local/include/freetype2, "$(PROJECT_DIR)/../../src/Tests", "$(PROJECT_DIR)/../../../MTEngineSDL/src/Engine/Tests", + "$(PROJECT_DIR)/../../src/Emulators/vice", + "$(PROJECT_DIR)/../../src/Emulators/vice/**", ); INFOPLIST_FILE = "$(SRCROOT)/src.MacOS/Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = "Retro Debugger"; diff --git a/platform/MacOS/src.MacOS/archdep.c b/platform/MacOS/src.MacOS/archdep.c index 8561c7e9..e898df82 100644 --- a/platform/MacOS/src.MacOS/archdep.c +++ b/platform/MacOS/src.MacOS/archdep.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include "vice_sdl.h" #include @@ -105,6 +107,64 @@ void archdep_network_shutdown(void) { } +/* VICE 3.10: replaced ioutil_access(); ARCHDEP_ACCESS_* values match POSIX. */ +int archdep_access(const char *pathname, int mode) +{ + return access(pathname, mode); +} + +/* VICE 3.10 tick subsystem (mach_absolute_time on macOS). Vanilla's + arch/shared/archdep_tick.c is gated on configure-set MACOS_COMPILE which RD's + Xcode build doesn't define, so the implementation lives here. */ +static mach_timebase_info_data_t c64d_timebase_info; + +void tick_init(void) +{ + mach_timebase_info(&c64d_timebase_info); +} + +tick_t tick_per_second(void) +{ + return TICK_PER_SECOND; +} + +tick_t tick_now(void) +{ + return NANO_TO_TICK(mach_absolute_time() * c64d_timebase_info.numer / c64d_timebase_info.denom); +} + +void tick_sleep(tick_t sleep_ticks) +{ + uint64_t nanos = TICK_TO_NANO(sleep_ticks); + struct timespec ts; + + if (nanos < NANO_PER_SECOND) { + ts.tv_sec = 0; + ts.tv_nsec = nanos; + } else { + ts.tv_sec = nanos / NANO_PER_SECOND; + ts.tv_nsec = nanos % NANO_PER_SECOND; + } + + nanosleep(&ts, NULL); +} + +tick_t tick_now_after(tick_t previous_tick) +{ + tick_t after = tick_now(); + + if (after == previous_tick - 1) { + after = previous_tick; + } + + return after; +} + +tick_t tick_now_delta(tick_t previous_tick) +{ + return tick_now_after(previous_tick) - previous_tick; +} + static int archdep_init_extra(int *argc, char **argv) { #ifdef USE_PROC_SELF_EXE @@ -123,12 +183,12 @@ static int archdep_init_extra(int *argc, char **argv) archdep_pref_path = archdep_boot_path(); #else - argv0 = lib_stralloc(argv[0]); + argv0 = lib_strdup(argv[0]); #endif return 0; } -char *archdep_program_name(void) +const char *archdep_program_name(void) { static char *program_name = NULL; @@ -137,9 +197,9 @@ char *archdep_program_name(void) p = strrchr(argv0, '/'); if (p == NULL) { - program_name = lib_stralloc(argv0); + program_name = lib_strdup(argv0); } else { - program_name = lib_stralloc(p + 1); + program_name = lib_strdup(p + 1); } } @@ -151,9 +211,9 @@ const char *archdep_boot_path(void) if (boot_path == NULL) { #ifdef USE_PROC_SELF_EXE /* known from setup in archdep_init_extra() so just reuse it */ - boot_path = lib_stralloc(argv0); + boot_path = lib_strdup(argv0); #else - boot_path = findpath(argv0, getenv("PATH"), IOUTIL_ACCESS_X_OK); + boot_path = findpath(argv0, getenv("PATH"), NULL, IOUTIL_ACCESS_X_OK); #endif /* Remove the program name. */ @@ -220,35 +280,19 @@ char *archdep_default_sysfile_pathlist(const char *emu_id) lib_free(default_path_temp); #else -#if defined(MACOSX_BUNDLE) - /* Mac OS X Bundles keep their ROMS in Resources/bin/../ROM */ -#if defined(MACOSX_COCOA) || defined(USE_SDLUI) -#define MACOSX_ROMDIR "/../Resources/ROM/" -#else -#define MACOSX_ROMDIR "/../ROM/" -#endif - default_path = util_concat(boot_path, MACOSX_ROMDIR, emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/", emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/", emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - - boot_path, MACOSX_ROMDIR, "DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - - boot_path, MACOSX_ROMDIR, "PRINTER", ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/PRINTER", ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/PRINTER", NULL); -#else - default_path = util_concat(LIBDIR, "/", emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/", emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/", emu_id, ARCHDEP_FINDPATH_SEPARATOR_STRING, - LIBDIR, "/DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/DRIVES", ARCHDEP_FINDPATH_SEPARATOR_STRING, - LIBDIR, "/PRINTER", ARCHDEP_FINDPATH_SEPARATOR_STRING, - home_path, "/", VICEUSERDIR, "/PRINTER", ARCHDEP_FINDPATH_SEPARATOR_STRING, - boot_path, "/PRINTER", NULL); -#endif + /* VICE 3.10 changed the contract: sysfile_open now appends a subpath ("C64", + "DRIVES", "PRINTER", ...) onto each search-path element. The 3.1-vintage + list below baked the machine name *into* each path, which would now produce + "/C64/C64/kernal-901227-03.bin" -- double-suffix, never found, hard + reset jumps to PC=$0000. Return generic VICE-data roots and let the caller + supply the subpath. (void)emu_id since the caller already encodes it. + Also add /opt/homebrew/share/vice for arm64 Homebrew (LIBDIR points at + /usr/local/lib/vice from the legacy Intel prefix). */ + (void)emu_id; + default_path = util_concat("/opt/homebrew/share/vice", ARCHDEP_FINDPATH_SEPARATOR_STRING, + LIBDIR, ARCHDEP_FINDPATH_SEPARATOR_STRING, + home_path, "/", VICEUSERDIR, ARCHDEP_FINDPATH_SEPARATOR_STRING, + boot_path, NULL); #endif } @@ -450,7 +494,7 @@ int archdep_expand_path(char **return_path, const char *orig_name) { /* Unix version. */ if (*orig_name == '/') { - *return_path = lib_stralloc(orig_name); + *return_path = lib_strdup(orig_name); } else { static char *cwd; @@ -473,13 +517,13 @@ void archdep_startup_log_error(const char *format, ...) char *archdep_filename_parameter(const char *name) { /* nothing special(?) */ - return lib_stralloc(name); + return lib_strdup(name); } char *archdep_quote_parameter(const char *name) { /*not needed(?) */ - return lib_stralloc(name); + return lib_strdup(name); } char *archdep_tmpnam(void) @@ -510,11 +554,11 @@ char *archdep_tmpnam(void) close(fd); } - final_name = lib_stralloc(tmp_name); + final_name = lib_strdup(tmp_name); lib_free(tmp_name); return final_name; #else - return lib_stralloc(tmpnam(NULL)); + return lib_strdup(tmpnam(NULL)); #endif } @@ -571,7 +615,7 @@ FILE *archdep_mkstemp_fd(char **filename, const char *mode) return NULL; } - *filename = lib_stralloc(tmp); + *filename = lib_strdup(tmp); return fd; #endif @@ -601,19 +645,19 @@ int archdep_mkdir(const char *pathname, int mode) #endif } -int archdep_stat(const char *file_name, unsigned int *len, unsigned int *isdir) +int archdep_stat(const char *file_name, size_t *len, unsigned int *isdir) { struct stat statbuf; - + if (stat(file_name, &statbuf) < 0) { - *len = 0; - *isdir = 0; + if (len) { *len = 0; } + if (isdir) { *isdir = 0; } return -1; } - - *len = statbuf.st_size; - *isdir = S_ISDIR(statbuf.st_mode); - + + if (len) { *len = (size_t)statbuf.st_size; } + if (isdir) { *isdir = S_ISDIR(statbuf.st_mode); } + return 0; } @@ -799,7 +843,15 @@ int archdep_init(int *argc, char **argv) // fprintf(stderr, "SDL error: %s\n", SDL_GetError()); // return 1; // } - + + /* VICE 3.10 expects the host tick subsystem live before main_program starts. + Without this, c64d_timebase_info stays zeroed, tick_now() does an integer + divide-by-zero (returns 0 on arm64), the throttle loop sees "no wallclock + advance" and lets the OS scheduler dribble cycles in -- C64 runs at ~3 kHz + instead of ~1 MHz and the kernal cold-start never reaches the BASIC prompt + (black screen). */ + tick_init(); + return archdep_init_extra(argc, argv); } diff --git a/platform/MacOS/src.MacOS/archdep.h b/platform/MacOS/src.MacOS/archdep.h index b890357e..09a19e78 100644 --- a/platform/MacOS/src.MacOS/archdep.h +++ b/platform/MacOS/src.MacOS/archdep.h @@ -32,6 +32,93 @@ #include "vice_sdl.h" #include "sound.h" +#include "archdep_tick.h" /* VICE 3.10: tick_t + tick_now/tick_sleep/... */ +#include "archdep_dir.h" /* VICE 3.10: archdep_dir_t + archdep_opendir/readdir/closedir (palette/fileio dir scans expect this via archdep.h) */ +#include "archdep_current_dir.h" /* VICE 3.10: archdep_current_dir(). Without this prototype the -Wno-implicit-function-declaration silently truncates the returned char* to int -> sign-extended 64-bit garbage -> free() aborts (caught in sysfile.c set_system_path). */ + +/* VICE 3.10 archdep_*.h sweep: each declares one function. Without these prototypes -Wno-implicit-function-declaration silently truncates pointer returns to 32-bit ints -> sign-extended 64-bit garbage -> abort/SIGSEGV. Sweep added 2026-05-29 after archdep_current_dir + archdep_default_joymap_file_name caused exactly this. */ +#include "archdep_access.h" +#include "archdep_boot_path.h" +#include "archdep_cbmfont.h" +#include "archdep_chdir.h" +#include "archdep_close.h" +#include "archdep_create_user_cache_dir.h" +#include "archdep_create_user_config_dir.h" +#include "archdep_create_user_state_dir.h" +#include "archdep_default_autostart_disk_image_file_name.h" +#include "archdep_default_fliplist_file_name.h" +#include "archdep_default_joymap_file_name.h" +#include "archdep_default_logfile.h" +#include "archdep_default_logger.h" +#include "archdep_default_portable_resource_file_name.h" +#include "archdep_default_resource_file_name.h" +#include "archdep_default_rtc_file_name.h" +#include "archdep_default_sysfile_pathlist.h" +#include "archdep_ethernet_available.h" +#include "archdep_exit.h" +#include "archdep_expand_path.h" +#include "archdep_extra_title_text.h" +#include "archdep_fdopen.h" +#include "archdep_file_exists.h" +#include "archdep_file_is_blockdev.h" +#include "archdep_file_is_chardev.h" +#include "archdep_file_size.h" +#include "archdep_filename_parameter.h" +#include "archdep_fix_permissions.h" +#include "archdep_fix_streams.h" +#include "archdep_fseeko.h" +#include "archdep_ftello.h" +#include "archdep_get_current_drive.h" +#include "archdep_get_hvsc_dir.h" +#include "archdep_get_runtime_info.h" +#include "archdep_get_vice_datadir.h" +#include "archdep_get_vice_docsdir.h" +#include "archdep_get_vice_drivesdir.h" +#include "archdep_get_vice_hotkeysdir.h" +#include "archdep_get_vice_machinedir.h" +#include "archdep_getcwd.h" +#include "archdep_glob.h" +#include "archdep_home_path.h" +#include "archdep_icon_path.h" +#include "archdep_is_haiku.h" +#include "archdep_is_macos_bindist.h" +#include "archdep_is_windows_nt.h" +#include "archdep_kbd_get_host_mapping.h" +#include "archdep_list_drives.h" +#include "archdep_make_backup_filename.h" +#include "archdep_mkdir.h" +#include "archdep_mkstemp_fd.h" +#include "archdep_network.h" +#include "archdep_open_default_log_file.h" +#include "archdep_path_is_relative.h" +#include "archdep_program_name.h" +#include "archdep_program_path.h" +#include "archdep_quote_parameter.h" +#include "archdep_quote_unzip.h" +#include "archdep_rawnet_capability.h" +#include "archdep_real_path.h" +#include "archdep_remove.h" +#include "archdep_rename.h" +#include "archdep_require_vkbd.h" +#include "archdep_rmdir.h" +#include "archdep_rtc_get_centisecond.h" +#include "archdep_sanitize_filename.h" +#include "archdep_set_current_drive.h" +#include "archdep_set_openmp_wait_policy.h" +#include "archdep_signals.h" +#include "archdep_sleep.h" +#include "archdep_socketpeek.h" +#include "archdep_sound.h" +#include "archdep_spawn.h" +#include "archdep_startup_log_error.h" +#include "archdep_stat.h" +#include "archdep_tmpnam.h" +#include "archdep_user_cache_path.h" +#include "archdep_user_config_path.h" +#include "archdep_user_state_path.h" +#include "archdep_usleep.h" +#include "archdep_xdg.h" + /* Extra functions for SDL UI */ //extern char *archdep_default_hotkey_file_name(void); @@ -51,6 +138,31 @@ extern void archdep_set_current_drive(const char *drive); /* Virtual keyboard handling */ extern int archdep_require_vkbd(void); +/* VICE 3.10: archdep_access() replaced ioutil_access(). Mode constants match + POSIX R_OK/W_OK/X_OK/F_OK so the values pass straight through to access(). */ +#define ARCHDEP_ACCESS_R_OK 4 +#define ARCHDEP_ACCESS_W_OK 2 +#define ARCHDEP_ACCESS_X_OK 1 +#define ARCHDEP_ACCESS_F_OK 0 +int archdep_access(const char *pathname, int mode); + +/* VICE 3.10: archdep_mkdir() mode constants (from arch/shared/archdep_mkdir.h). + Octal POSIX permission bits passed straight to mkdir(). */ +#define ARCHDEP_MKDIR_RWXU 0700 +#define ARCHDEP_MKDIR_RWXUG 0770 +#define ARCHDEP_MKDIR_RWXUGO 0777 + +/* VICE 3.10 UI factory defaults referenced by the (3.10) core resources. */ +#define ARCHDEP_MOUSE_ENABLE_DEFAULT 0 +#define ARCHDEP_SHOW_STATUSBAR_FACTORY 0 + +/* VICE 3.10 archdep macros normally from arch/shared/archdep_defs.h+archdep_unix.h + (gated on configure-set *_COMPILE macros RD doesn't define). macOS values. */ +#define PRI_SIZE_T "zu" +#define ARCHDEP_DIR_SEP_STR "/" +#define ARCHDEP_DIR_SEP_CHR '/' +#define ARCHDEP_FSDEVICE_DEFAULT_DIR "." /* CWD (archdep_unix.h value) */ + /* Video chip scaling. */ #define ARCHDEP_VICII_DSIZE 1 #define ARCHDEP_VICII_DSCAN 1 @@ -119,3 +231,7 @@ extern char *archdep_sdl2_default_renderers[]; #endif #endif + +/* VICE 3.10: socket error retrieval (unix uses errno). */ +#include +#define ARCHDEP_SOCKET_ERROR errno diff --git a/platform/MacOS/src.MacOS/mididrv.c b/platform/MacOS/src.MacOS/mididrv.c index 88c2f052..d79d7eb1 100644 --- a/platform/MacOS/src.MacOS/mididrv.c +++ b/platform/MacOS/src.MacOS/mididrv.c @@ -47,11 +47,10 @@ #include "log.h" #include "mididrv.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" -static log_t mididrv_log = LOG_ERR; +static log_t mididrv_log = LOG_DEFAULT; /* ----- FIFO Buffer ----- */ #define OUT_BUF_LEN 3 @@ -116,21 +115,12 @@ void mididrv_resources_shutdown(void) } static const cmdline_option_t cmdline_options[] = { - { "-midiname", SET_RESOURCE, -1, - NULL, NULL, "MIDIName", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Name of MIDI Client") }, - { "-midiinname", SET_RESOURCE, -1, - NULL, NULL, "MIDIInName", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Name of MIDI-In Port") }, - { "-midioutname", SET_RESOURCE, -1, - NULL, NULL, "MIDIOutName", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, - IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), N_("Name of MIDI-Out Port") }, + { "-midiname", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIName", NULL, N_(""), N_("Name of MIDI Client")}, + { "-midiinname", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIInName", NULL, N_(""), N_("Name of MIDI-In Port")}, + { "-midioutname", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MIDIOutName", NULL, N_(""), N_("Name of MIDI-Out Port")}, CMDLINE_LIST_END }; @@ -304,7 +294,7 @@ static void dump_destinations(void) void mididrv_init(void) { - if (mididrv_log == LOG_ERR) { + if (mididrv_log == LOG_DEFAULT) { mididrv_log = log_open("MIDIdrv"); } } diff --git a/platform/Windows/src.Windows/arch/archdep.c b/platform/Windows/src.Windows/arch/archdep.c index e5660326..6c6a9987 100644 --- a/platform/Windows/src.Windows/arch/archdep.c +++ b/platform/Windows/src.Windows/arch/archdep.c @@ -120,7 +120,7 @@ int archdep_init(int *argc, char **argv) _setmode(_fileno(stdin), O_BINARY); _setmode(_fileno(stdout), O_BINARY); - argv0 = lib_stralloc(argv[0]); + argv0 = lib_strdup(argv[0]); orig_workdir = getcwd(NULL, MAX_PATH); @@ -307,7 +307,7 @@ const char *archdep_boot_path(void) util_fname_split(temp, &boot_path, NULL); break; } else if (i == 0) { - possible_trojan_path = lib_stralloc(temp); + possible_trojan_path = lib_strdup(temp); } } } @@ -325,7 +325,7 @@ const char *archdep_boot_path(void) if (verify_exe(ment.szExePath)) { util_fname_split(ment.szExePath, &boot_path, NULL); } else { - possible_trojan_path = lib_stralloc(ment.szExePath); + possible_trojan_path = lib_strdup(ment.szExePath); while (func_Module32Next(snap, &ment)) { OutputDebugString(ment.szExePath); if (verify_exe(ment.szExePath)) { @@ -342,7 +342,7 @@ const char *archdep_boot_path(void) if (GetModuleFileName(NULL, st_temp, MAX_PATH)) { system_wcstombs(temp, st_temp, MAX_PATH); if (!verify_exe(temp)) { - possible_trojan_path = lib_stralloc(temp); + possible_trojan_path = lib_strdup(temp); } util_fname_split(temp, &boot_path, NULL); } else { @@ -355,7 +355,7 @@ const char *archdep_boot_path(void) /* This should not happen, but you never know... */ if (boot_path == NULL) { - boot_path = lib_stralloc(".\\"); + boot_path = lib_strdup(".\\"); } } @@ -561,7 +561,7 @@ int archdep_spawn(const char *name, char **argv, char **pstdout_redir, const cha int archdep_expand_path(char **return_path, const char *orig_name) { /* Win32 version */ - *return_path = lib_stralloc(orig_name); + *return_path = lib_strdup(orig_name); return 0; } @@ -608,7 +608,7 @@ char *archdep_tmpnam(void) } else if (getenv("tmp")) { return util_concat(getenv("tmp"), tmpnam(NULL), NULL); } else { - return lib_stralloc(tmpnam(NULL)); + return lib_strdup(tmpnam(NULL)); } } @@ -622,7 +622,7 @@ FILE *archdep_mkstemp_fd(char **filename, const char *mode) } else if (getenv("tmp")) { tmp = util_concat(getenv("tmp"), tmpnam(NULL), NULL); } else { - tmp = lib_stralloc(tmpnam(NULL)); + tmp = lib_strdup(tmpnam(NULL)); } fd = fopen(tmp, mode); diff --git a/platform/Windows/src.Windows/arch/mididrv.c b/platform/Windows/src.Windows/arch/mididrv.c index 1e799b47..951e3b50 100644 --- a/platform/Windows/src.Windows/arch/mididrv.c +++ b/platform/Windows/src.Windows/arch/mididrv.c @@ -45,7 +45,6 @@ #include "mididrv.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #ifndef DWORD_PTR @@ -54,7 +53,7 @@ /* ------------------------------------------------------------------------- */ -static log_t mididrv_log = LOG_ERR; +static log_t mididrv_log = LOG_DEFAULT; static HMIDIIN handle_in = 0; static HMIDIOUT handle_out = 0; @@ -108,22 +107,12 @@ void mididrv_resources_shutdown(void) { } -#define DEFAULT_PARAM USE_PARAM_STRING -#define DEFAULT_DESCR USE_DESCRIPTION_STRING -#define IDS_P_NUMBER IDCLS_UNUSED -#define IDS_SPECIFY_MIDI_IN IDCLS_UNUSED -#define IDS_SPECIFY_MIDI_OUT IDCLS_UNUSED - static const cmdline_option_t cmdline_options[] = { - { "-midiin", SET_RESOURCE, 1, + { "-midiin", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MIDIInDev", NULL, - DEFAULT_PARAM, DEFAULT_DESCR, - IDS_P_NUMBER, IDS_SPECIFY_MIDI_IN, "", "Specify MIDI-In device" }, - { "-midiout", SET_RESOURCE, 1, + { "-midiout", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MIDIOutDev", NULL, - DEFAULT_PARAM, DEFAULT_DESCR, - IDS_P_NUMBER, IDS_SPECIFY_MIDI_OUT, "", "Specify MIDI-Out device" }, CMDLINE_LIST_END }; @@ -215,7 +204,7 @@ static int message_len(BYTE msg) void mididrv_init(void) { - if (mididrv_log == LOG_ERR) { + if (mididrv_log == LOG_DEFAULT) { mididrv_log = log_open("MIDIdrv"); } } diff --git a/platform/Windows/src.Windows/arch/ui-resources.c b/platform/Windows/src.Windows/arch/ui-resources.c index 16bcd519..7947463c 100644 --- a/platform/Windows/src.Windows/arch/ui-resources.c +++ b/platform/Windows/src.Windows/arch/ui-resources.c @@ -41,7 +41,6 @@ //#include "res.h" #include "machine.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" //#include "uilib.h" diff --git a/src/Embedded/reset_basic_snap_zlib.h b/src/Embedded/reset_basic_snap_zlib.h index 29dae9de..73292487 100644 --- a/src/Embedded/reset_basic_snap_zlib.h +++ b/src/Embedded/reset_basic_snap_zlib.h @@ -1,434 +1,7416 @@ // Embedded file name: reset_basic.snap.zlib // #include "reset_basic_snap_zlib.h" // RES_AddEmbeddedDataToDeploy("/gfx/reset_basic", DEPLOY_FILE_TYPE_GFX, reset_basic_snap_zlib, reset_basic_snap_zlib_length); -int reset_basic_snap_zlib_length = 6822; -uint8 reset_basic_snap_zlib[6822] = { - 0x5a, 0x4c, 0x00, 0x07, 0x32, 0x77, 0x00, 0x00, 0x1a, 0x9c, 0x78, 0xda, 0xed, 0xdd, 0x7f, 0x6c, - 0x1b, 0xf7, 0x7d, 0xc6, 0xf1, 0x3b, 0xfd, 0xa0, 0x15, 0x27, 0xa6, 0x63, 0xd9, 0x71, 0xaa, 0x0c, - 0x58, 0x55, 0xb7, 0x97, 0x86, 0x46, 0xe8, 0x58, 0x89, 0x4f, 0x09, 0x8d, 0xd1, 0xb5, 0x22, 0x6b, - 0x0e, 0xe5, 0xd0, 0xf6, 0x64, 0x9d, 0x5c, 0x7a, 0x60, 0x90, 0xa1, 0x39, 0x77, 0x74, 0x46, 0x67, - 0x48, 0x46, 0x07, 0x74, 0xd7, 0xd4, 0xcb, 0x8f, 0x6e, 0xc0, 0x56, 0x14, 0xc1, 0x2a, 0x6c, 0x69, - 0x07, 0x4c, 0x40, 0xcb, 0x66, 0xf4, 0xc6, 0x61, 0x59, 0xc0, 0x3f, 0x54, 0x60, 0xc0, 0xfe, 0xeb, - 0xd8, 0x41, 0x5b, 0x03, 0x4c, 0x5b, 0x36, 0x14, 0x43, 0x87, 0x4e, 0x01, 0x92, 0x34, 0x98, 0x7f, - 0x54, 0xc5, 0x32, 0x64, 0xe2, 0x8e, 0x22, 0x25, 0x91, 0x14, 0x29, 0xcb, 0x56, 0xf4, 0x78, 0xa2, - 0xdf, 0x4f, 0x2a, 0xca, 0x92, 0x48, 0x7e, 0xa4, 0xd7, 0x9d, 0x4e, 0xd4, 0xf7, 0x39, 0xaa, 0x63, - 0x91, 0xc1, 0xa1, 0xde, 0x13, 0x67, 0x7f, 0xed, 0x37, 0x9f, 0xfb, 0xf5, 0x67, 0x7e, 0xab, 0xf7, - 0x97, 0x13, 0xbf, 0xe1, 0xde, 0x63, 0x9a, 0x83, 0xfd, 0xfb, 0x4e, 0x0c, 0x1a, 0x4b, 0x19, 0x2b, - 0x5d, 0x69, 0xcc, 0x7d, 0xf6, 0xb9, 0xc4, 0x33, 0x67, 0xef, 0x69, 0x37, 0xcb, 0xef, 0x8c, 0x0e, - 0x44, 0x8e, 0x0e, 0x1e, 0x77, 0x16, 0xaf, 0x64, 0x9a, 0xbf, 0xe2, 0x5d, 0x7e, 0x54, 0x7c, 0xcd, - 0x34, 0xcc, 0x1d, 0x57, 0xa6, 0x66, 0x76, 0x5d, 0xaa, 0x5c, 0xf1, 0x5f, 0xde, 0x7e, 0x6d, 0xfe, - 0x5f, 0xd3, 0xff, 0xfa, 0x9a, 0x69, 0x34, 0xc8, 0xbd, 0x96, 0x61, 0xfc, 0x7d, 0xe1, 0xa5, 0xd2, - 0xd4, 0xe8, 0x50, 0xb4, 0xea, 0x03, 0x66, 0xc0, 0x30, 0x8d, 0x87, 0x1f, 0x30, 0x8c, 0x62, 0xd1, - 0xb8, 0xf8, 0xc6, 0xab, 0x6f, 0xee, 0xda, 0x65, 0x18, 0x8f, 0x1b, 0x45, 0xa3, 0xad, 0xfc, 0xe1, - 0x9e, 0x9d, 0xc6, 0xe6, 0x73, 0xdf, 0x2e, 0xff, 0xfb, 0xae, 0xae, 0x37, 0xff, 0xa6, 0x7c, 0x9b, - 0xae, 0xbb, 0xe7, 0xff, 0x33, 0x26, 0xe6, 0xff, 0x2b, 0x56, 0xee, 0xaa, 0xab, 0x74, 0xf1, 0x99, - 0xf2, 0x2b, 0xef, 0x96, 0x86, 0xd1, 0xfe, 0x78, 0xf5, 0xa7, 0xe0, 0xdd, 0x4f, 0xcf, 0xd2, 0x5b, - 0xe7, 0x8c, 0x0b, 0xdf, 0x7e, 0xe7, 0xfc, 0x0f, 0xdb, 0xde, 0xf9, 0x52, 0xce, 0xe8, 0x2a, 0xec, - 0xff, 0xab, 0xcd, 0x85, 0xde, 0x4b, 0xff, 0xf5, 0xc8, 0xbb, 0x7b, 0x1f, 0x79, 0xf7, 0x87, 0x4f, - 0x5e, 0x38, 0xf6, 0xfd, 0x91, 0xcf, 0x1f, 0xf4, 0xee, 0xf6, 0xe0, 0xfc, 0x5d, 0xb7, 0x1b, 0xc6, - 0x05, 0xef, 0x55, 0xe7, 0x47, 0x07, 0x97, 0x6e, 0xee, 0x0d, 0x37, 0x7e, 0xa9, 0xbd, 0xf4, 0xb9, - 0x18, 0x4f, 0x76, 0x15, 0xff, 0x74, 0xfe, 0x7d, 0x13, 0x66, 0x97, 0x77, 0x8d, 0xdb, 0x6e, 0x37, - 0x0e, 0x1a, 0xdd, 0xbd, 0xa6, 0x71, 0xa9, 0xc3, 0x30, 0x3e, 0xeb, 0xdb, 0x61, 0xbc, 0x5c, 0xce, - 0x2b, 0xf3, 0xf9, 0x6a, 0x39, 0xbf, 0x3b, 0x9f, 0x4b, 0x6f, 0xff, 0xce, 0xfb, 0x0b, 0x77, 0xd8, - 0xfb, 0xd0, 0x23, 0xa1, 0xbe, 0x3e, 0x63, 0xaf, 0x17, 0xe3, 0x86, 0x52, 0x5c, 0x63, 0x8c, 0x35, - 0x66, 0x55, 0x43, 0xbe, 0xfc, 0xde, 0xed, 0xfe, 0xaf, 0x78, 0x97, 0x3b, 0x4c, 0x63, 0xd7, 0x3f, - 0xce, 0x78, 0xfb, 0xd0, 0x7f, 0x3c, 0x95, 0x79, 0xe5, 0x3b, 0xaf, 0xa7, 0xbf, 0xfb, 0x27, 0x3f, - 0xf9, 0xc3, 0x5d, 0xbb, 0x77, 0xdd, 0xff, 0x88, 0x71, 0xbf, 0x71, 0xd3, 0x52, 0xda, 0x9f, 0xfc, - 0x73, 0x1d, 0x9b, 0x8d, 0xf6, 0x2d, 0x86, 0xf1, 0xd8, 0xfb, 0x0d, 0xaf, 0x63, 0xae, 0xdb, 0xf4, - 0xdf, 0xff, 0xc9, 0x4b, 0xdf, 0xf9, 0xed, 0xcc, 0x3d, 0xaf, 0xff, 0xe7, 0xeb, 0x5f, 0xfd, 0xcb, - 0xd2, 0xdb, 0x8f, 0x3f, 0xf6, 0xd7, 0x46, 0xdf, 0x7b, 0xa7, 0xe7, 0x0e, 0xcf, 0x0d, 0x5f, 0x7d, - 0xf5, 0x8a, 0xff, 0xca, 0xf1, 0x2b, 0x0f, 0x5d, 0x3d, 0x79, 0xf9, 0x07, 0x97, 0x3f, 0xf8, 0xf9, - 0x81, 0xcb, 0x0f, 0x5c, 0x3d, 0x3d, 0x97, 0xf9, 0xd9, 0x07, 0xb3, 0x46, 0x0b, 0xa5, 0xf7, 0x3a, - 0xb2, 0xdb, 0x4b, 0x6f, 0xfb, 0xd6, 0x2d, 0x5b, 0xb6, 0x76, 0x6c, 0xed, 0xee, 0xec, 0xed, 0xdf, - 0xd7, 0xdb, 0x66, 0x6e, 0xbf, 0xad, 0xbd, 0x77, 0xe7, 0x83, 0xe5, 0x0f, 0x5d, 0x57, 0xfa, 0xf7, - 0xdd, 0xde, 0xdb, 0x6d, 0x6e, 0xe9, 0xdd, 0xde, 0xb3, 0x7d, 0x47, 0xe7, 0x96, 0xde, 0xf2, 0x37, - 0x62, 0xe5, 0x0e, 0xdb, 0x7a, 0x76, 0x74, 0x6e, 0xef, 0xf5, 0x75, 0x77, 0x76, 0xae, 0xfa, 0xee, - 0xba, 0x3b, 0xcd, 0x8e, 0x9e, 0x3d, 0xd7, 0xbe, 0xde, 0x44, 0x2f, 0x21, 0xb7, 0x5e, 0x6e, 0xea, - 0xcf, 0x9f, 0x9b, 0xfd, 0xf3, 0x8f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, - 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, - 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, - 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, - 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, - 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, - 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, - 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, - 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, - 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, - 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, - 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, - 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, - 0xf3, 0x99, 0x7f, 0xab, 0xcd, 0xdf, 0xed, 0xe0, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, - 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, - 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, - 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, - 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, - 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, - 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, - 0xf9, 0xcc, 0x67, 0x3e, 0xf3, 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0x9f, 0xf9, 0xcc, 0x67, 0x3e, 0xf3, - 0x99, 0xcf, 0x7c, 0xe6, 0x33, 0xff, 0x26, 0xcd, 0xef, 0x7b, 0xef, 0xf4, 0xdc, 0xe1, 0xb9, 0xe1, - 0xab, 0xaf, 0x5e, 0xf1, 0x5f, 0x39, 0x7e, 0xe5, 0xa1, 0xab, 0x27, 0x2f, 0xff, 0xe0, 0xf2, 0x07, - 0x3f, 0x3f, 0x70, 0xf9, 0x81, 0xab, 0xa7, 0xe7, 0x32, 0x3f, 0xfb, 0x60, 0x16, 0x7f, 0xe6, 0x6f, - 0xa4, 0xf9, 0x0f, 0x3f, 0xfc, 0x40, 0xf5, 0xdd, 0x0d, 0xf6, 0xef, 0x1b, 0x1c, 0x18, 0x19, 0x5d, - 0x7a, 0x87, 0x79, 0xf7, 0xfc, 0xbb, 0x23, 0x03, 0x7d, 0xd5, 0x57, 0x6b, 0x6b, 0x1b, 0xf4, 0x2e, - 0xbf, 0x62, 0x78, 0x9f, 0x7e, 0x4f, 0xb1, 0xa3, 0x74, 0x35, 0xc3, 0x34, 0x6f, 0xb3, 0x0e, 0x7a, - 0xff, 0xbe, 0x50, 0xb9, 0x46, 0xe9, 0x9d, 0x5f, 0xfb, 0xb4, 0x61, 0x7c, 0xa1, 0xeb, 0xbe, 0x6d, - 0x95, 0xbb, 0x78, 0x70, 0xf9, 0x5d, 0x7c, 0xdf, 0xf8, 0x9c, 0x51, 0x61, 0x30, 0x0d, 0xa3, 0xab, - 0xab, 0x9a, 0x64, 0xfe, 0x2e, 0xbe, 0xee, 0xdd, 0xc5, 0x7d, 0xdb, 0xca, 0x77, 0x71, 0x22, 0x72, - 0xa8, 0xe6, 0x6b, 0x37, 0xdb, 0x43, 0xf3, 0xaf, 0x36, 0x5d, 0x0b, 0xc9, 0xbb, 0xe1, 0xd0, 0xe7, - 0x47, 0x87, 0x8e, 0x1e, 0x1a, 0x3a, 0x54, 0xb9, 0xe1, 0x4e, 0xef, 0xf2, 0xd0, 0x48, 0x64, 0x6c, - 0xa8, 0xfa, 0xee, 0x3a, 0xee, 0x30, 0xe7, 0x3f, 0x8d, 0xca, 0x9b, 0xbb, 0xaa, 0xef, 0xe2, 0xcd, - 0xd2, 0xa7, 0xd5, 0xee, 0xbd, 0xf8, 0x7c, 0x86, 0xf1, 0x6f, 0x01, 0xc3, 0x78, 0xf7, 0xf9, 0x37, - 0x16, 0xaf, 0xfb, 0x45, 0xf3, 0xb4, 0x51, 0xf9, 0xf0, 0xc2, 0x4b, 0x09, 0xa5, 0x74, 0x77, 0x9f, - 0xad, 0xba, 0x8f, 0x0a, 0x8d, 0x71, 0xf1, 0x47, 0x8f, 0xfc, 0x43, 0xe9, 0x75, 0x6f, 0x67, 0x7f, - 0x67, 0xcd, 0xd7, 0x63, 0x7e, 0xa6, 0xe6, 0xd3, 0x5e, 0xeb, 0xff, 0x37, 0x43, 0x55, 0xa6, 0xfe, - 0x7c, 0x5f, 0x77, 0xf3, 0x8f, 0x9a, 0x65, 0x8b, 0xc1, 0xe3, 0xce, 0xde, 0xc5, 0x4f, 0xc5, 0xe9, - 0xf2, 0xb6, 0xed, 0xa7, 0x27, 0x4c, 0xc3, 0x5f, 0x1c, 0xda, 0xf1, 0xd3, 0x4f, 0x7d, 0xd7, 0x7b, - 0xe7, 0x47, 0xc5, 0xd7, 0xcc, 0x3f, 0xfb, 0xf7, 0xf2, 0x15, 0x4a, 0x1f, 0xba, 0xb0, 0x7d, 0x62, - 0x5e, 0xe0, 0x7b, 0x95, 0xd7, 0x95, 0x5b, 0x6e, 0x2d, 0xbd, 0xb1, 0xcd, 0xe8, 0x36, 0xbb, 0x8d, - 0xd2, 0xcc, 0xbe, 0xbe, 0xd2, 0xcb, 0x36, 0xa3, 0xb4, 0x09, 0xef, 0x9c, 0xff, 0xc8, 0xc8, 0x58, - 0x3e, 0xf0, 0xf4, 0x37, 0xdf, 0xc9, 0x07, 0x86, 0x3d, 0xa6, 0x8e, 0x2e, 0x6f, 0x2f, 0x2a, 0x1a, - 0x9b, 0xba, 0xdc, 0xd2, 0xde, 0x6c, 0x6e, 0x33, 0x8b, 0x77, 0x79, 0x4e, 0x9b, 0x8c, 0xb0, 0x71, - 0xaa, 0xf3, 0x4e, 0xf3, 0x7b, 0xde, 0x87, 0xbc, 0x0f, 0x6c, 0xde, 0xbc, 0x73, 0xeb, 0x66, 0x2f, - 0x1d, 0x1e, 0x6b, 0xe7, 0xff, 0xfc, 0xdd, 0xae, 0xf7, 0xbd, 0x77, 0x75, 0xbe, 0xe7, 0xdd, 0xca, - 0xbb, 0x8d, 0xbf, 0x34, 0xf4, 0xbe, 0xc7, 0xe6, 0x87, 0x97, 0x66, 0x98, 0xdd, 0x3f, 0xfe, 0x5c, - 0xed, 0x97, 0xd7, 0xd6, 0x59, 0xde, 0x3a, 0x1d, 0x6d, 0x9d, 0x6d, 0xbe, 0xb6, 0x4d, 0x46, 0xdb, - 0x3f, 0xb7, 0x95, 0xf6, 0xb3, 0x4e, 0xdf, 0x4b, 0xe5, 0xef, 0x81, 0x97, 0x4d, 0x73, 0xa5, 0x6f, - 0xae, 0x0a, 0x51, 0x65, 0x8f, 0x2c, 0x6f, 0xc5, 0x17, 0xe7, 0xdf, 0xec, 0x58, 0xfc, 0xa2, 0x7f, - 0xef, 0x82, 0xf7, 0x1d, 0xd0, 0xd6, 0xee, 0x33, 0x8a, 0x03, 0xab, 0xd8, 0x1a, 0x5f, 0xf8, 0x70, - 0xff, 0xec, 0x9d, 0x1f, 0x96, 0x2f, 0x9f, 0xff, 0xf0, 0x85, 0xb9, 0x36, 0xb3, 0xaf, 0xef, 0xad, - 0xbe, 0xb7, 0x52, 0x73, 0x2f, 0xcc, 0x15, 0xdb, 0x8a, 0x9f, 0xda, 0x71, 0xc9, 0xb8, 0x09, 0xf9, - 0x46, 0x26, 0x30, 0x3c, 0xb2, 0x96, 0x8b, 0xbf, 0x98, 0x0d, 0x0c, 0x5f, 0xbc, 0xf1, 0x43, 0xd7, - 0xcb, 0x9d, 0xc5, 0xe2, 0x8b, 0x25, 0xec, 0xbd, 0xc5, 0x1e, 0xef, 0xf2, 0xc7, 0x6d, 0xa6, 0x47, - 0xfd, 0xdf, 0x65, 0xfd, 0xad, 0xe5, 0xef, 0x9f, 0x0b, 0x6f, 0x5c, 0xa8, 0x7c, 0xcf, 0xb5, 0xd5, - 0xec, 0xbe, 0x5f, 0x33, 0xcd, 0x85, 0xef, 0xdc, 0x6d, 0x75, 0xdf, 0x6d, 0xa5, 0x77, 0x7a, 0x1b, - 0x7d, 0x6d, 0x34, 0x7b, 0xf7, 0xde, 0xdf, 0x7b, 0xec, 0xc8, 0xfd, 0xde, 0xab, 0xbd, 0x7b, 0x1f, - 0xdc, 0xd3, 0xdf, 0xdb, 0x67, 0xef, 0xeb, 0x2b, 0xbf, 0x55, 0x75, 0xa5, 0x3f, 0x32, 0xda, 0x0c, - 0x62, 0xf4, 0x98, 0x5d, 0x77, 0x75, 0x7d, 0xb3, 0xed, 0xeb, 0xbd, 0x23, 0x43, 0xa3, 0x23, 0xc7, - 0x0e, 0x0d, 0x3d, 0xea, 0x1c, 0x3e, 0x3c, 0x34, 0x72, 0xeb, 0x7c, 0xfd, 0xc5, 0x17, 0xbd, 0x03, - 0x5c, 0xf5, 0x97, 0x3e, 0x31, 0x31, 0x51, 0x75, 0xa0, 0x25, 0xad, 0x9d, 0x6e, 0x73, 0xc0, 0xb8, - 0xab, 0x58, 0xfc, 0xe4, 0x5a, 0x5e, 0x76, 0xcc, 0x15, 0x3f, 0xb9, 0xed, 0xa3, 0xe2, 0xa6, 0xed, - 0xc5, 0xc6, 0x2f, 0xdd, 0xc5, 0x62, 0x7b, 0xa3, 0x97, 0x6d, 0x45, 0xef, 0xe7, 0x67, 0xdd, 0x4b, - 0xfd, 0xae, 0x38, 0x31, 0xd1, 0xd7, 0x37, 0xf1, 0xe0, 0xc0, 0x44, 0xf5, 0x5e, 0xb9, 0x5e, 0x29, - 0x1d, 0x26, 0xc7, 0xbc, 0x47, 0x8e, 0x87, 0x2a, 0x87, 0xc9, 0x36, 0x73, 0xfe, 0xb1, 0x66, 0xd1, - 0xb8, 0xa7, 0x68, 0x26, 0xe7, 0x0f, 0xff, 0xef, 0xff, 0xa8, 0xf4, 0x4d, 0x71, 0xd0, 0x3b, 0x70, - 0xfe, 0xad, 0x61, 0x78, 0x57, 0x7d, 0xf0, 0x50, 0xd5, 0x11, 0xb5, 0x72, 0x75, 0xe3, 0xd2, 0x33, - 0xc6, 0xfe, 0xff, 0xdd, 0x5d, 0xbe, 0xfa, 0x05, 0x63, 0xe0, 0xa7, 0xc6, 0x41, 0xc3, 0x38, 0x78, - 0xf1, 0xd2, 0xe1, 0xc1, 0x91, 0x48, 0x74, 0xe0, 0xf0, 0xd0, 0xc2, 0x2d, 0xda, 0xcd, 0x6f, 0xbc, - 0xd2, 0x61, 0xfc, 0x41, 0xe9, 0x71, 0xd7, 0x2f, 0x56, 0x7e, 0xb8, 0x8c, 0x8c, 0xe6, 0x03, 0x47, - 0xbc, 0x07, 0x1a, 0xce, 0x52, 0xe6, 0xdf, 0xef, 0xfc, 0xd3, 0x5a, 0x7f, 0xd6, 0x71, 0x31, 0x5c, - 0x23, 0x3a, 0x32, 0x9a, 0x09, 0x22, 0x2d, 0x91, 0x76, 0xec, 0x08, 0xd2, 0x1a, 0x69, 0x2b, 0x8a, - 0xb4, 0xe6, 0xe8, 0x31, 0x1b, 0x42, 0x5a, 0x23, 0x3d, 0x13, 0x46, 0x5a, 0x73, 0xf4, 0x48, 0xc5, - 0x90, 0xd6, 0x48, 0xbb, 0x71, 0xa4, 0x35, 0xd2, 0xe3, 0x16, 0xd2, 0x9a, 0xe3, 0xf4, 0xb8, 0x8b, - 0xb4, 0x66, 0x9f, 0xce, 0x27, 0x90, 0xd6, 0x48, 0x67, 0x92, 0x48, 0x6b, 0xa4, 0xa7, 0x6d, 0xa4, - 0x35, 0xc7, 0xe9, 0xe9, 0x14, 0xd2, 0x9a, 0x7d, 0xda, 0x49, 0x23, 0xad, 0x91, 0x9e, 0x71, 0x90, - 0x96, 0x48, 0x8f, 0xe5, 0xb3, 0x48, 0x6b, 0xa4, 0x33, 0x39, 0xa4, 0x25, 0xd2, 0x27, 0xed, 0x02, - 0xd2, 0x1a, 0x69, 0x6b, 0x0a, 0x69, 0xcd, 0xd1, 0x63, 0x76, 0x12, 0xe9, 0x75, 0x96, 0x5e, 0xbf, - 0x18, 0x35, 0x9d, 0xb0, 0x63, 0x05, 0x46, 0xd8, 0x96, 0x9a, 0xa6, 0x32, 0x88, 0xb4, 0xa8, 0x7d, - 0x8f, 0x20, 0xad, 0x91, 0xce, 0x47, 0x91, 0x16, 0xb5, 0x3a, 0x21, 0xa4, 0x45, 0x4d, 0x65, 0x18, - 0x69, 0x51, 0xfb, 0x1e, 0x43, 0x5a, 0x74, 0x46, 0x49, 0x1c, 0x69, 0x51, 0xab, 0x63, 0x21, 0x2d, - 0x6a, 0x2a, 0x5d, 0xa4, 0x45, 0xed, 0x7b, 0x02, 0x69, 0xd1, 0x19, 0x25, 0x49, 0xa4, 0x45, 0xad, - 0x8e, 0x8d, 0xb4, 0xa8, 0xa9, 0x4c, 0x21, 0x2d, 0x6a, 0xdf, 0xd3, 0x48, 0x8b, 0xce, 0x28, 0x71, - 0x90, 0x16, 0xb5, 0x3a, 0x59, 0xa4, 0x45, 0x4d, 0x65, 0x0e, 0x69, 0x51, 0xfb, 0x5e, 0x40, 0x5a, - 0x74, 0x46, 0xc9, 0x14, 0xd2, 0x9a, 0xa3, 0x87, 0x3b, 0x89, 0x74, 0xab, 0x74, 0xc2, 0x76, 0xe0, - 0x04, 0xdb, 0x52, 0xf3, 0x9c, 0xca, 0x20, 0xd2, 0xa2, 0xa6, 0x32, 0x82, 0xb4, 0xa8, 0x7d, 0x8f, - 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, 0x30, 0xd2, 0xa2, 0xa6, 0x32, 0x86, 0xb4, - 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, 0x45, 0xed, 0xbb, 0x8b, 0xb4, 0xa8, 0xa9, - 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, 0x4a, 0x1b, 0x69, 0x51, 0xfb, 0x9e, 0x42, - 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, 0xd2, 0xa2, 0xa6, 0x32, 0x8b, 0xb4, 0xa8, - 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, 0xda, 0xf7, 0x29, 0xa4, 0x35, 0x47, 0x8f, - 0xd4, 0x24, 0xd2, 0x2d, 0xd2, 0x09, 0x8f, 0xce, 0x04, 0x8e, 0xb2, 0x2d, 0x35, 0x2b, 0xe0, 0x41, - 0xa4, 0x45, 0xad, 0x4e, 0x04, 0x69, 0x51, 0x53, 0x19, 0x45, 0x5a, 0xd4, 0xbe, 0x87, 0x90, 0x16, - 0x9d, 0x51, 0x12, 0x46, 0x5a, 0x74, 0x96, 0x54, 0x0c, 0x69, 0xd1, 0xdf, 0x28, 0x89, 0x23, 0x2d, - 0x5a, 0x2d, 0xb4, 0x90, 0x16, 0xad, 0x80, 0xbb, 0x48, 0x8b, 0x5a, 0x9d, 0x04, 0xd2, 0xa2, 0xa6, - 0x32, 0x89, 0xb4, 0xa8, 0x7d, 0xb7, 0x91, 0x16, 0x9d, 0x51, 0x92, 0x42, 0x5a, 0x74, 0x96, 0x54, - 0x1a, 0x69, 0xd1, 0x99, 0x7f, 0x0e, 0xd2, 0x9a, 0x56, 0x67, 0x26, 0x8b, 0xb4, 0xe8, 0xaf, 0xbf, - 0xe6, 0x90, 0x16, 0x3d, 0xa7, 0xb2, 0x80, 0xb4, 0xa8, 0xa9, 0x9c, 0x42, 0x5a, 0xd4, 0xbe, 0x4f, - 0x22, 0xdd, 0x2a, 0x9d, 0xf0, 0x6c, 0xe0, 0x18, 0xdb, 0x52, 0xf3, 0x5c, 0x9d, 0x20, 0xd2, 0xa2, - 0xa6, 0x32, 0x82, 0xb4, 0xa8, 0x7d, 0x8f, 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, - 0x30, 0xd2, 0xa2, 0xa6, 0x32, 0x86, 0xb4, 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, - 0x45, 0xed, 0xbb, 0x8b, 0xb4, 0xa8, 0xa9, 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, - 0x4a, 0x1b, 0x69, 0x51, 0xfb, 0x9e, 0x42, 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, - 0xd2, 0xa2, 0xa6, 0x32, 0x8b, 0xb4, 0xa8, 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, - 0xda, 0xf7, 0x29, 0xa4, 0x45, 0xcf, 0x7d, 0x9f, 0x44, 0xba, 0x55, 0xfe, 0x76, 0xb4, 0x1b, 0x18, - 0x63, 0x5b, 0x6a, 0x9a, 0xca, 0x20, 0xd2, 0xa2, 0xf6, 0x3d, 0x82, 0xb4, 0xe8, 0xb9, 0xef, 0x51, - 0xa4, 0x45, 0xad, 0x4e, 0x08, 0x69, 0x51, 0x53, 0x19, 0x46, 0x5a, 0xd4, 0xbe, 0xc7, 0x90, 0x16, - 0x9d, 0x51, 0x12, 0x47, 0x5a, 0xd4, 0xea, 0x58, 0x48, 0x8b, 0x9a, 0x4a, 0x17, 0x69, 0x51, 0xfb, - 0x9e, 0x40, 0x5a, 0x74, 0x46, 0x49, 0x12, 0x69, 0x51, 0xab, 0x63, 0x23, 0x2d, 0x6a, 0x2a, 0x53, - 0x48, 0x8b, 0xda, 0xf7, 0x34, 0xd2, 0xa2, 0x33, 0x4a, 0x1c, 0xa4, 0x45, 0xad, 0x4e, 0x16, 0x69, - 0x51, 0x53, 0x99, 0x43, 0x5a, 0xd4, 0xbe, 0x17, 0x90, 0x16, 0x9d, 0x51, 0x32, 0x85, 0xb4, 0xe6, - 0xe8, 0x61, 0x4d, 0x22, 0xdd, 0x2a, 0x9d, 0x70, 0x2a, 0x70, 0x92, 0x6d, 0xa9, 0x79, 0x4e, 0x65, - 0x10, 0x69, 0x51, 0x53, 0x19, 0x41, 0x5a, 0xd4, 0xbe, 0x47, 0x91, 0x16, 0x35, 0x95, 0x21, 0xa4, - 0x45, 0xed, 0x7b, 0x18, 0x69, 0x51, 0x53, 0x19, 0x43, 0x5a, 0xd4, 0xbe, 0xc7, 0x91, 0x16, 0x35, - 0x95, 0x16, 0xd2, 0xa2, 0xf6, 0xdd, 0x45, 0x5a, 0xd4, 0x54, 0x26, 0x90, 0x16, 0xb5, 0xef, 0x49, - 0xa4, 0x45, 0x4d, 0xa5, 0x8d, 0xb4, 0xa8, 0x7d, 0x4f, 0x21, 0x2d, 0x6a, 0x2a, 0xd3, 0x48, 0x8b, - 0xda, 0x77, 0x07, 0x69, 0x51, 0x53, 0x99, 0x45, 0x5a, 0xd4, 0xbe, 0xe7, 0x90, 0x16, 0x35, 0x95, - 0x05, 0xa4, 0x45, 0xed, 0xfb, 0x14, 0xd2, 0x9a, 0xa3, 0x87, 0x3d, 0x89, 0x74, 0xab, 0xfc, 0xed, - 0xe8, 0xf1, 0x40, 0x84, 0x6d, 0xa9, 0x79, 0xc4, 0x1e, 0x44, 0x5a, 0xf4, 0x5b, 0x68, 0x04, 0x69, - 0xd1, 0xca, 0x4a, 0x14, 0x69, 0xd1, 0x6a, 0x61, 0x08, 0x69, 0xd1, 0x0a, 0x78, 0x18, 0x69, 0x51, - 0xab, 0x13, 0x43, 0x5a, 0xd4, 0x54, 0xc6, 0x91, 0x16, 0xb5, 0xef, 0x16, 0xd2, 0xa2, 0x33, 0x4a, - 0x5c, 0xa4, 0x45, 0x67, 0x49, 0x25, 0x90, 0x16, 0x9d, 0xf9, 0x97, 0x44, 0x5a, 0x74, 0x36, 0xab, - 0x8d, 0xb4, 0xe8, 0x0c, 0xed, 0x14, 0xd2, 0xa2, 0x67, 0x1d, 0xa4, 0x91, 0x16, 0xfd, 0xcd, 0x3f, - 0x07, 0x69, 0x4d, 0xab, 0x33, 0x9e, 0x45, 0x5a, 0xd3, 0xea, 0x8c, 0xe7, 0x90, 0xd6, 0x48, 0x67, - 0x0a, 0x48, 0x6b, 0xa4, 0xf3, 0x53, 0x48, 0x6b, 0x8e, 0xd3, 0xd3, 0x93, 0x48, 0xb7, 0xca, 0xf3, - 0x84, 0xc7, 0x03, 0x31, 0xb6, 0xa5, 0xe6, 0xdc, 0xc2, 0x20, 0xd2, 0xa2, 0xa6, 0x32, 0x82, 0xb4, - 0xa8, 0x7d, 0x8f, 0x22, 0x2d, 0x6a, 0x2a, 0x43, 0x48, 0x8b, 0xda, 0xf7, 0x30, 0xd2, 0xa2, 0xa6, - 0x32, 0x86, 0xb4, 0xa8, 0x7d, 0x8f, 0x23, 0x2d, 0x6a, 0x2a, 0x2d, 0xa4, 0x45, 0xed, 0xbb, 0x8b, - 0xb4, 0xa8, 0xa9, 0x4c, 0x20, 0x2d, 0x6a, 0xdf, 0x93, 0x48, 0x8b, 0x9a, 0x4a, 0x1b, 0x69, 0x51, - 0xfb, 0x9e, 0x42, 0x5a, 0xd4, 0x54, 0xa6, 0x91, 0x16, 0xb5, 0xef, 0x0e, 0xd2, 0xa2, 0xa6, 0x32, - 0x8b, 0xb4, 0xa8, 0x7d, 0xcf, 0x21, 0x2d, 0x6a, 0x2a, 0x0b, 0x48, 0x8b, 0xda, 0xf7, 0x29, 0xa4, - 0x35, 0xd2, 0xd3, 0x93, 0x48, 0xb7, 0x4a, 0x27, 0x9c, 0x09, 0x9c, 0x62, 0x5b, 0x6a, 0x9a, 0xca, - 0x20, 0xd2, 0xa2, 0xf6, 0x3d, 0x82, 0xb4, 0xe8, 0xb9, 0xef, 0x51, 0xa4, 0x45, 0xad, 0x4e, 0x08, - 0x69, 0x51, 0x53, 0x19, 0x46, 0x5a, 0xd4, 0xbe, 0xc7, 0x90, 0x16, 0x9d, 0x51, 0x12, 0x47, 0x5a, - 0xd4, 0xea, 0x58, 0x48, 0x8b, 0x9a, 0x4a, 0x17, 0x69, 0x51, 0xfb, 0x9e, 0x40, 0x5a, 0x74, 0x46, - 0x49, 0x12, 0x69, 0x51, 0xab, 0x63, 0x23, 0x2d, 0x6a, 0x2a, 0x53, 0x48, 0x8b, 0xda, 0xf7, 0x34, - 0xd2, 0xa2, 0x33, 0x4a, 0x1c, 0xa4, 0x45, 0xad, 0x4e, 0x16, 0x69, 0x51, 0x53, 0x99, 0x43, 0x5a, - 0xd4, 0xbe, 0x17, 0x90, 0x16, 0x9d, 0x51, 0x32, 0x85, 0xb4, 0x46, 0x7a, 0x66, 0x12, 0xe9, 0x56, - 0xe9, 0x84, 0xf3, 0x81, 0x5f, 0x65, 0x5b, 0x6a, 0x9e, 0x53, 0x19, 0x44, 0x5a, 0xd4, 0x54, 0x46, - 0x90, 0x16, 0xb5, 0xef, 0x51, 0xa4, 0x45, 0x4d, 0x65, 0x08, 0x69, 0x51, 0xfb, 0x1e, 0x46, 0x5a, - 0xd4, 0x54, 0xc6, 0x90, 0x16, 0xb5, 0xef, 0x71, 0xa4, 0x45, 0x4d, 0xa5, 0x85, 0xb4, 0xa8, 0x7d, - 0x77, 0x91, 0x16, 0x35, 0x95, 0x09, 0xa4, 0x45, 0xed, 0x7b, 0x12, 0x69, 0x51, 0x53, 0x69, 0x23, - 0x2d, 0x6a, 0xdf, 0x53, 0x48, 0x8b, 0x9a, 0xca, 0x34, 0xd2, 0xa2, 0xf6, 0xdd, 0x41, 0x5a, 0xd4, - 0x54, 0x66, 0x91, 0x16, 0xb5, 0xef, 0x39, 0xa4, 0x45, 0x4d, 0x65, 0x01, 0x69, 0x51, 0xfb, 0x3e, - 0x85, 0xb4, 0x66, 0x9f, 0x76, 0x26, 0x91, 0x6e, 0x91, 0x4e, 0x78, 0x74, 0x3a, 0x10, 0x65, 0x5b, - 0x6a, 0x56, 0xc0, 0x83, 0x48, 0x8b, 0x5a, 0x9d, 0x08, 0xd2, 0xa2, 0xa6, 0x32, 0x8a, 0xb4, 0xa8, - 0x7d, 0x0f, 0x21, 0x2d, 0x3a, 0xa3, 0x24, 0x8c, 0xb4, 0xe8, 0x2c, 0xa9, 0x18, 0xd2, 0xa2, 0xbf, - 0x51, 0x12, 0x47, 0x5a, 0xb4, 0x5a, 0x68, 0x21, 0x2d, 0x5a, 0x01, 0x77, 0x91, 0x16, 0xb5, 0x3a, - 0x09, 0xa4, 0x45, 0x4d, 0x65, 0x12, 0x69, 0x51, 0xfb, 0x6e, 0x23, 0x2d, 0x3a, 0xa3, 0x24, 0x85, - 0xb4, 0xe8, 0x2c, 0xa9, 0x34, 0xd2, 0xa2, 0x33, 0xff, 0x1c, 0xa4, 0x35, 0xad, 0xce, 0x74, 0x16, - 0x69, 0xd1, 0x5f, 0x7f, 0xcd, 0x21, 0x2d, 0x7a, 0x4e, 0x65, 0x01, 0x69, 0x51, 0x53, 0x39, 0x85, - 0xb4, 0xa8, 0x7d, 0x9f, 0x44, 0xba, 0x55, 0x9e, 0x27, 0x3c, 0x1d, 0x88, 0xb3, 0x2d, 0x35, 0xcf, - 0xd5, 0x09, 0x22, 0x2d, 0x6a, 0x2a, 0x23, 0x48, 0x8b, 0xda, 0xf7, 0x28, 0xd2, 0xa2, 0xa6, 0x32, - 0x84, 0xb4, 0xa8, 0x7d, 0x0f, 0x23, 0x2d, 0x6a, 0x2a, 0x63, 0x48, 0x8b, 0xda, 0xf7, 0x38, 0xd2, - 0xa2, 0xa6, 0xd2, 0x42, 0x5a, 0xd4, 0xbe, 0xbb, 0x48, 0x8b, 0x9a, 0xca, 0x04, 0xd2, 0xa2, 0xf6, - 0x3d, 0x89, 0xb4, 0xa8, 0xa9, 0xb4, 0x91, 0x16, 0xb5, 0xef, 0x29, 0xa4, 0x45, 0x4d, 0x65, 0x1a, - 0x69, 0x51, 0xfb, 0xee, 0x20, 0x2d, 0x6a, 0x2a, 0xb3, 0x48, 0x8b, 0xda, 0xf7, 0x1c, 0xd2, 0xa2, - 0xa6, 0xb2, 0x80, 0xb4, 0xa8, 0x7d, 0x9f, 0x42, 0x5a, 0xf4, 0xdc, 0xf7, 0x49, 0xa4, 0x5b, 0xa5, - 0x13, 0x9e, 0x09, 0x3c, 0xc1, 0xb6, 0xd4, 0x34, 0x95, 0x41, 0xa4, 0x45, 0xed, 0x7b, 0x04, 0x69, - 0xd1, 0x73, 0xdf, 0xa3, 0x48, 0x8b, 0x5a, 0x9d, 0x10, 0xd2, 0xa2, 0xa6, 0x32, 0x8c, 0xb4, 0xa8, - 0x7d, 0x8f, 0x21, 0x2d, 0x3a, 0xa3, 0x24, 0x8e, 0xb4, 0xa8, 0xd5, 0xb1, 0x90, 0x16, 0x35, 0x95, - 0x2e, 0xd2, 0xa2, 0xf6, 0x3d, 0x81, 0xb4, 0xe8, 0x8c, 0x92, 0x24, 0xd2, 0xa2, 0x56, 0xc7, 0x46, - 0x5a, 0xd4, 0x54, 0xa6, 0x90, 0x16, 0xb5, 0xef, 0x69, 0xa4, 0x45, 0x67, 0x94, 0x38, 0x48, 0x8b, - 0x5a, 0x9d, 0x2c, 0xd2, 0xa2, 0xa6, 0x32, 0x87, 0xb4, 0xa8, 0x7d, 0x2f, 0x20, 0x2d, 0x3a, 0xa3, - 0x64, 0x0a, 0x69, 0x8d, 0x74, 0x66, 0x12, 0xe9, 0x56, 0xe9, 0x84, 0x9d, 0x80, 0xc3, 0xb6, 0xd4, - 0x3c, 0xa7, 0x32, 0x88, 0xb4, 0xa8, 0xa9, 0x8c, 0x20, 0x2d, 0x6a, 0xdf, 0xa3, 0x48, 0x8b, 0x9a, - 0xca, 0x10, 0xd2, 0xa2, 0xf6, 0x3d, 0x8c, 0xb4, 0xa8, 0xa9, 0x8c, 0x21, 0x2d, 0x6a, 0xdf, 0xe3, - 0x48, 0x8b, 0x9a, 0x4a, 0x0b, 0x69, 0x51, 0xfb, 0xee, 0x22, 0x2d, 0x6a, 0x2a, 0x13, 0x48, 0x8b, - 0xda, 0xf7, 0x24, 0xd2, 0xa2, 0xa6, 0xd2, 0x46, 0x5a, 0xd4, 0xbe, 0xa7, 0x90, 0x16, 0x35, 0x95, - 0x69, 0xa4, 0x45, 0xed, 0xbb, 0x83, 0xb4, 0xa8, 0xa9, 0xcc, 0x22, 0x2d, 0x6a, 0xdf, 0x73, 0x48, - 0x8b, 0x9a, 0xca, 0x02, 0xd2, 0xa2, 0xf6, 0x7d, 0x0a, 0x69, 0xcd, 0x3e, 0x9d, 0x9f, 0x44, 0xba, - 0x45, 0x3a, 0xe1, 0xb1, 0x4c, 0xe0, 0x0c, 0xdb, 0x52, 0x72, 0x7c, 0xca, 0x07, 0x91, 0xd6, 0x1c, - 0x9f, 0xac, 0x08, 0xd2, 0x1a, 0x69, 0x3b, 0x8a, 0xb4, 0xe6, 0xe8, 0x31, 0x13, 0x42, 0x5a, 0x23, - 0x3d, 0x1b, 0x46, 0x5a, 0x73, 0xf4, 0x70, 0x63, 0x48, 0x6b, 0xa4, 0x53, 0x71, 0xa4, 0x35, 0x47, - 0x8f, 0x71, 0x0b, 0x69, 0xd1, 0x5f, 0xab, 0x72, 0x91, 0x16, 0x9d, 0x03, 0x9e, 0x40, 0x5a, 0xb4, - 0xb2, 0x92, 0x44, 0x5a, 0xb4, 0x5a, 0x68, 0x23, 0x2d, 0x5a, 0x01, 0x4f, 0x21, 0x2d, 0x6a, 0x75, - 0xd2, 0x48, 0x8b, 0x9a, 0x4a, 0x07, 0x69, 0x51, 0xfb, 0x9e, 0x45, 0x5a, 0x74, 0x46, 0x49, 0x0e, - 0x69, 0xd1, 0x59, 0x52, 0x05, 0xa4, 0x45, 0x67, 0xfe, 0x4d, 0x21, 0x2d, 0x3a, 0x9b, 0x75, 0x12, - 0xe9, 0x56, 0xe9, 0x84, 0xf3, 0x81, 0xa7, 0x6b, 0xb6, 0xe5, 0xee, 0xf9, 0xf7, 0x17, 0x2f, 0xbe, - 0xc7, 0xd6, 0x58, 0xf3, 0x45, 0xed, 0x6f, 0xa1, 0x99, 0xe0, 0xd3, 0x7c, 0xd7, 0x68, 0x9a, 0xca, - 0x08, 0xd2, 0xa2, 0xf6, 0x3d, 0x8a, 0xb4, 0xa8, 0xa9, 0x0c, 0x21, 0x2d, 0x6a, 0xdf, 0xc3, 0x48, - 0x8b, 0x9a, 0xca, 0x18, 0xd2, 0xa2, 0xf6, 0x3d, 0x8e, 0xb4, 0xa8, 0xa9, 0xb4, 0x90, 0x16, 0xb5, - 0xef, 0x2e, 0xd2, 0xa2, 0xa6, 0x32, 0x81, 0xb4, 0xa8, 0x7d, 0x4f, 0x22, 0x2d, 0x6a, 0x2a, 0x6d, - 0xa4, 0x45, 0xed, 0x7b, 0x0a, 0x69, 0x51, 0x53, 0x99, 0x46, 0x5a, 0xd4, 0xbe, 0x3b, 0x48, 0x8b, - 0x9a, 0xca, 0x2c, 0xd2, 0xa2, 0xf6, 0x3d, 0x87, 0xb4, 0xa8, 0xa9, 0x2c, 0x20, 0x2d, 0x6a, 0xdf, - 0xa7, 0x90, 0x16, 0xfd, 0x2d, 0xa9, 0x49, 0xa4, 0x37, 0x74, 0x27, 0xfc, 0xce, 0x2f, 0x2c, 0x74, - 0xc2, 0x27, 0xad, 0xc0, 0xb3, 0x0d, 0xb6, 0x25, 0x1b, 0x73, 0x3d, 0x36, 0xe6, 0x42, 0x65, 0x19, - 0xac, 0x21, 0x1f, 0x1b, 0x83, 0x7c, 0x9d, 0xc9, 0xc7, 0x32, 0x91, 0x67, 0x39, 0x62, 0x89, 0x8e, - 0x58, 0x0b, 0x27, 0x9b, 0x44, 0x21, 0xd7, 0x92, 0x9f, 0x74, 0x43, 0x90, 0x8b, 0xc9, 0x53, 0x61, - 0xc8, 0xc5, 0x07, 0x96, 0x99, 0x18, 0xe4, 0x62, 0xf2, 0xd9, 0x38, 0xe4, 0xe2, 0x03, 0x4b, 0xc6, - 0x82, 0x5c, 0x4c, 0x9e, 0x77, 0x21, 0x17, 0x1f, 0x58, 0xc6, 0x13, 0x90, 0x8b, 0xf7, 0xf2, 0xf1, - 0x24, 0xe4, 0x62, 0xf2, 0x19, 0x1b, 0x72, 0x31, 0xb9, 0x93, 0x82, 0x5c, 0x7c, 0x2c, 0x9f, 0x4e, - 0x43, 0x2e, 0xde, 0xcb, 0xa7, 0x1d, 0xc8, 0xb5, 0xe4, 0x8e, 0x95, 0x85, 0x5c, 0x4c, 0x6e, 0xe7, - 0x20, 0xd7, 0x92, 0x8f, 0x66, 0x0a, 0x90, 0x6f, 0xd8, 0x86, 0x6f, 0x85, 0xb6, 0xcf, 0x0e, 0x3c, - 0xc7, 0x76, 0xd5, 0xfe, 0x8c, 0xb6, 0x82, 0x90, 0xab, 0xab, 0xa7, 0x08, 0xe4, 0x62, 0xf2, 0x4c, - 0x14, 0x72, 0x75, 0xf5, 0x14, 0x82, 0x5c, 0x5d, 0xb0, 0x86, 0x21, 0x57, 0x57, 0x4f, 0x31, 0xc8, - 0xd5, 0x05, 0x6b, 0x1c, 0x72, 0x75, 0xf5, 0x64, 0x41, 0xae, 0x2e, 0x58, 0x5d, 0xc8, 0xd5, 0xd5, - 0x53, 0x02, 0x72, 0x75, 0xc1, 0x9a, 0x84, 0x5c, 0x5d, 0x3d, 0xd9, 0x90, 0xab, 0x0b, 0xd6, 0x14, - 0xe4, 0xea, 0xea, 0x29, 0x0d, 0xb9, 0xba, 0x60, 0x75, 0x20, 0x57, 0x57, 0x4f, 0x59, 0xc8, 0xd5, - 0x05, 0x6b, 0x0e, 0x72, 0x71, 0xdb, 0x97, 0x2f, 0x40, 0xde, 0x82, 0x6d, 0xdf, 0xd8, 0x4c, 0xe0, - 0x2c, 0xdb, 0x55, 0xbc, 0x5c, 0x19, 0x84, 0x5c, 0xbd, 0x28, 0x1f, 0x81, 0x5c, 0x5d, 0x3d, 0x45, - 0x21, 0x57, 0x17, 0xac, 0x21, 0xc8, 0xd5, 0xa7, 0x11, 0x84, 0x21, 0x57, 0x9f, 0x2c, 0x13, 0x83, - 0x5c, 0x4c, 0x6e, 0xc7, 0x21, 0x57, 0x2f, 0xe4, 0x58, 0x90, 0xab, 0x97, 0x2b, 0x5d, 0xc8, 0xd5, - 0x8b, 0xf2, 0x09, 0xc8, 0xd5, 0xd5, 0x53, 0x12, 0x72, 0x75, 0xc1, 0x6a, 0x43, 0xae, 0x3e, 0x8d, - 0x20, 0x05, 0xb9, 0xfa, 0x64, 0x99, 0x34, 0xe4, 0xea, 0x53, 0xc2, 0x1c, 0xc8, 0xc5, 0x3d, 0xc8, - 0x4c, 0x16, 0x72, 0x31, 0xf9, 0x6c, 0x0e, 0x72, 0x71, 0xc1, 0xea, 0x16, 0x20, 0x6f, 0xc5, 0xb6, - 0x6f, 0x36, 0xf0, 0x0c, 0xdb, 0x55, 0x7c, 0xa6, 0x7c, 0x10, 0x72, 0x75, 0xf5, 0x14, 0x81, 0x5c, - 0x5d, 0xb0, 0x46, 0x21, 0x57, 0x57, 0x4f, 0x21, 0xc8, 0xd5, 0x05, 0x6b, 0x18, 0x72, 0x75, 0xf5, - 0x14, 0x83, 0x5c, 0x5d, 0xb0, 0xc6, 0x21, 0x57, 0x57, 0x4f, 0x16, 0xe4, 0xea, 0x82, 0xd5, 0x85, - 0x5c, 0x5d, 0x3d, 0x25, 0x20, 0x57, 0x17, 0xac, 0x49, 0xc8, 0xd5, 0xd5, 0x93, 0x0d, 0xb9, 0xba, - 0x60, 0x4d, 0x41, 0xae, 0xae, 0x9e, 0xd2, 0x90, 0xab, 0x0b, 0x56, 0x07, 0x72, 0x75, 0xf5, 0x94, - 0x85, 0x5c, 0x5d, 0xb0, 0xe6, 0x20, 0x17, 0xb7, 0x7d, 0xa9, 0x02, 0xe4, 0xad, 0xf8, 0x97, 0x3c, - 0xdd, 0xc0, 0x39, 0xb6, 0xab, 0xb8, 0x7a, 0x0a, 0x42, 0xae, 0x2e, 0x58, 0x23, 0x90, 0xab, 0x9f, - 0xc1, 0x1a, 0x85, 0x5c, 0xbd, 0x28, 0x1f, 0x82, 0x5c, 0x5d, 0x3d, 0x85, 0x21, 0x57, 0x17, 0xac, - 0x31, 0xc8, 0xd5, 0xa7, 0x11, 0xc4, 0x21, 0x57, 0x2f, 0xca, 0x5b, 0x90, 0xab, 0xab, 0x27, 0x17, - 0x72, 0x75, 0xc1, 0x9a, 0x80, 0x5c, 0x7d, 0x1a, 0x41, 0x12, 0x72, 0xf5, 0xa2, 0xbc, 0x0d, 0xb9, - 0xba, 0x7a, 0x4a, 0x41, 0xae, 0x2e, 0x58, 0xd3, 0x90, 0xab, 0x4f, 0x23, 0x70, 0x20, 0x57, 0x3f, - 0xeb, 0x29, 0x0b, 0xb9, 0xba, 0x7a, 0xca, 0x41, 0xae, 0x2e, 0x58, 0x0b, 0x90, 0xb7, 0x62, 0xdb, - 0x97, 0x0a, 0x3c, 0xcf, 0x76, 0x15, 0x3f, 0xeb, 0x29, 0x08, 0xb9, 0xba, 0x7a, 0x8a, 0x40, 0xae, - 0x2e, 0x58, 0xa3, 0x90, 0xab, 0xab, 0xa7, 0x10, 0xe4, 0xea, 0x82, 0x35, 0x0c, 0xb9, 0xba, 0x7a, - 0x8a, 0x41, 0xae, 0x2e, 0x58, 0xe3, 0x90, 0xab, 0xab, 0x27, 0x0b, 0x72, 0x75, 0xc1, 0xea, 0x42, - 0xae, 0xae, 0x9e, 0x12, 0x90, 0xab, 0x0b, 0xd6, 0x24, 0xe4, 0xea, 0xea, 0xc9, 0x86, 0x5c, 0x5d, - 0xb0, 0xa6, 0x20, 0x57, 0x57, 0x4f, 0x69, 0xc8, 0xd5, 0x05, 0xab, 0x03, 0xb9, 0xba, 0x7a, 0xca, - 0x42, 0xae, 0x2e, 0x58, 0x73, 0x90, 0xab, 0x9f, 0xc1, 0x5a, 0x80, 0xbc, 0x15, 0xff, 0x92, 0xe7, - 0x78, 0x20, 0xc1, 0x76, 0x15, 0x3f, 0x2c, 0x0a, 0x42, 0xae, 0x7e, 0xf0, 0x1f, 0x81, 0x5c, 0xfd, - 0x2b, 0x6e, 0x14, 0x72, 0xf5, 0x42, 0x4e, 0x08, 0x72, 0xf5, 0x72, 0x65, 0x18, 0x72, 0xf5, 0xa2, - 0x7c, 0x0c, 0x72, 0x75, 0xf5, 0x14, 0x87, 0x5c, 0x5d, 0xb0, 0x5a, 0x90, 0xab, 0x4f, 0x23, 0x70, - 0x21, 0x57, 0x9f, 0x2c, 0x93, 0x80, 0x5c, 0x7d, 0x4a, 0x58, 0x12, 0x72, 0xf5, 0x89, 0x8f, 0x36, - 0xe4, 0xea, 0xd3, 0x7b, 0x53, 0x90, 0xab, 0x4f, 0x62, 0x4f, 0x43, 0xae, 0xfe, 0x2b, 0x61, 0x0e, - 0xe4, 0xe2, 0x1e, 0x64, 0x3c, 0x0b, 0xb9, 0xb8, 0xed, 0x1b, 0xcf, 0x41, 0x2e, 0x26, 0xcf, 0x14, - 0x20, 0x6f, 0x99, 0xb6, 0x6f, 0xf3, 0x3d, 0x8b, 0xcf, 0xed, 0x1b, 0x0f, 0xa4, 0xd9, 0xae, 0xeb, - 0xbf, 0x5d, 0x17, 0xba, 0xd5, 0x20, 0xda, 0x32, 0xed, 0x93, 0xf9, 0x08, 0xda, 0x3a, 0xed, 0x4c, - 0x14, 0x6d, 0x9d, 0xf6, 0x74, 0x08, 0x6d, 0xdd, 0x71, 0x7b, 0x3a, 0x8c, 0xb6, 0x6e, 0xdf, 0x76, - 0x62, 0x68, 0xeb, 0xb4, 0x67, 0xe2, 0x68, 0xeb, 0x8e, 0x24, 0x79, 0x0b, 0x6d, 0x9d, 0x76, 0xc6, - 0x45, 0x5b, 0x77, 0x24, 0xb1, 0x13, 0x68, 0xeb, 0xb4, 0xad, 0x24, 0xda, 0xba, 0x23, 0xc9, 0xac, - 0x8d, 0xb6, 0x4e, 0x7b, 0x26, 0x85, 0xb6, 0xee, 0x48, 0x92, 0x4a, 0xa3, 0xad, 0xd3, 0x76, 0x1d, - 0xb4, 0x65, 0xda, 0xce, 0x78, 0x16, 0x6d, 0x99, 0xf6, 0xe8, 0x78, 0x0e, 0xed, 0x0d, 0xd7, 0x12, - 0xd5, 0x35, 0x42, 0x99, 0xc0, 0x79, 0xb6, 0xa1, 0xae, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0xdf, 0x22, - 0x68, 0xeb, 0xf6, 0xed, 0xf1, 0x28, 0xda, 0xc2, 0x75, 0xdc, 0x10, 0xda, 0xc2, 0x8e, 0x22, 0x8c, - 0xb6, 0xb0, 0x7f, 0x8b, 0xa1, 0x2d, 0xec, 0x96, 0xe3, 0x68, 0x0b, 0xd7, 0x71, 0x2d, 0xb4, 0x85, - 0x1d, 0x85, 0x8b, 0xb6, 0xb0, 0x7f, 0x4b, 0xa0, 0x2d, 0xec, 0x96, 0x93, 0x68, 0x0b, 0xd7, 0x71, - 0x6d, 0xb4, 0x85, 0x1d, 0x45, 0x0a, 0x6d, 0x61, 0xff, 0x96, 0x46, 0x5b, 0xd8, 0x2d, 0x3b, 0x68, - 0xeb, 0x1a, 0xa1, 0x4c, 0x16, 0x6d, 0x9d, 0x76, 0x3e, 0x87, 0xf6, 0x46, 0x6f, 0x84, 0xf2, 0x81, - 0x2f, 0xb1, 0x0d, 0x75, 0xcf, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0x28, 0x22, 0x68, 0x0b, 0xfb, 0xb7, - 0x28, 0xda, 0xc2, 0x8e, 0x22, 0x84, 0xb6, 0xb0, 0x7f, 0x0b, 0xa3, 0x2d, 0xec, 0x28, 0x62, 0x68, - 0x0b, 0xfb, 0xb7, 0x38, 0xda, 0xc2, 0x8e, 0xc2, 0x42, 0x5b, 0xd8, 0xbf, 0xb9, 0x68, 0x0b, 0x3b, - 0x8a, 0x04, 0xda, 0xc2, 0xfe, 0x2d, 0x89, 0xb6, 0xb0, 0xa3, 0xb0, 0xd1, 0x16, 0xf6, 0x6f, 0x29, - 0xb4, 0x85, 0x1d, 0x45, 0x1a, 0x6d, 0x61, 0xff, 0xe6, 0xa0, 0x2d, 0xec, 0x28, 0xb2, 0x68, 0x0b, - 0xfb, 0xb7, 0x1c, 0xda, 0x1b, 0xbc, 0x11, 0x1a, 0x9b, 0x0e, 0x24, 0xd9, 0x86, 0xba, 0xb5, 0xae, - 0x20, 0xda, 0xc2, 0x75, 0xdc, 0x08, 0xda, 0xc2, 0x8e, 0x22, 0x8a, 0xb6, 0xb0, 0x7f, 0x0b, 0xa1, - 0x2d, 0xec, 0x96, 0xc3, 0x68, 0x0b, 0xcf, 0x9b, 0x88, 0xa1, 0x2d, 0x7c, 0xde, 0x72, 0x1c, 0x6d, - 0xe1, 0x7a, 0x80, 0x85, 0xb6, 0x70, 0xad, 0xcb, 0x45, 0x5b, 0xb8, 0x8e, 0x9b, 0x40, 0x5b, 0xd8, - 0x51, 0x24, 0xd1, 0x16, 0xf6, 0x6f, 0x36, 0xda, 0xc2, 0x6e, 0x39, 0x85, 0xb6, 0xf0, 0xbc, 0x89, - 0x34, 0xda, 0xc2, 0x73, 0x82, 0x1c, 0xb4, 0x75, 0x7f, 0xc7, 0x6c, 0x3a, 0x8b, 0xb6, 0xae, 0x11, - 0x9a, 0xce, 0xa1, 0xbd, 0xd1, 0x9f, 0x23, 0x34, 0x1d, 0xf8, 0x32, 0xdb, 0x50, 0x77, 0x3e, 0x6e, - 0x10, 0x6d, 0x61, 0x47, 0x11, 0x41, 0x5b, 0xd8, 0xbf, 0x45, 0xd1, 0x16, 0x76, 0x14, 0x21, 0xb4, - 0x85, 0xfd, 0x5b, 0x18, 0x6d, 0x61, 0x47, 0x11, 0x43, 0x5b, 0xd8, 0xbf, 0xc5, 0xd1, 0x16, 0x76, - 0x14, 0x16, 0xda, 0xc2, 0xfe, 0xcd, 0x45, 0x5b, 0xd8, 0x51, 0x24, 0xd0, 0x16, 0xf6, 0x6f, 0x49, - 0xb4, 0x85, 0x1d, 0x85, 0x8d, 0xb6, 0xb0, 0x7f, 0x4b, 0xa1, 0x2d, 0xec, 0x28, 0xd2, 0x68, 0x0b, - 0xfb, 0x37, 0x07, 0x6d, 0x61, 0x47, 0x91, 0x45, 0x5b, 0xd8, 0xbf, 0xe5, 0xd0, 0xde, 0xe8, 0x8d, - 0xd0, 0x4c, 0xe0, 0x05, 0xb6, 0xa1, 0xae, 0xa3, 0x08, 0xa2, 0x2d, 0xec, 0xdf, 0x22, 0x68, 0x0b, - 0x9f, 0xff, 0x16, 0x45, 0x5b, 0xb8, 0x8e, 0x1b, 0x42, 0x5b, 0xd8, 0x51, 0x84, 0xd1, 0x16, 0xf6, - 0x6f, 0x31, 0xb4, 0x85, 0xdd, 0x72, 0x1c, 0x6d, 0xe1, 0x3a, 0xae, 0x85, 0xb6, 0xb0, 0xa3, 0x70, - 0xd1, 0x16, 0xf6, 0x6f, 0x09, 0xb4, 0x85, 0xdd, 0x72, 0x12, 0x6d, 0xe1, 0x3a, 0xae, 0x8d, 0xb6, - 0xb0, 0xa3, 0x48, 0xa1, 0x2d, 0xec, 0xdf, 0xd2, 0x68, 0x0b, 0xbb, 0x65, 0x07, 0x6d, 0x5d, 0x23, - 0x34, 0x93, 0x45, 0x5b, 0xa7, 0xed, 0xe4, 0xd0, 0xde, 0x90, 0x8d, 0xd0, 0x99, 0x4f, 0x2c, 0x36, - 0x42, 0x4e, 0x20, 0xc5, 0x36, 0x5c, 0xe7, 0x6d, 0xb8, 0x50, 0xbe, 0x05, 0xa1, 0x16, 0x51, 0x4f, - 0x47, 0xa0, 0xd6, 0x50, 0x8f, 0x4d, 0x47, 0xa1, 0x16, 0xed, 0xd5, 0xf9, 0x10, 0xd4, 0x22, 0xea, - 0x4c, 0x18, 0x6a, 0x11, 0xf5, 0x78, 0x0c, 0x6a, 0xd1, 0xb1, 0x7a, 0x3c, 0x0e, 0xb5, 0x68, 0xaf, - 0x4e, 0x59, 0x50, 0x8b, 0xa8, 0x5d, 0x17, 0x6a, 0xd1, 0x01, 0x64, 0x36, 0x01, 0xb5, 0x88, 0x7a, - 0x26, 0x09, 0xb5, 0xe8, 0x00, 0x62, 0xdb, 0x50, 0x8b, 0xa8, 0xad, 0x14, 0xd4, 0xa2, 0x03, 0x48, - 0x3e, 0x0d, 0xb5, 0x88, 0x3a, 0xe3, 0x40, 0xad, 0xa1, 0x76, 0x9c, 0x2c, 0xd4, 0x1b, 0xac, 0x73, - 0xa8, 0x6d, 0x1c, 0x9e, 0xca, 0xec, 0x1e, 0x66, 0x0b, 0x4a, 0xbe, 0x59, 0x9e, 0xca, 0xef, 0x81, - 0x5a, 0x43, 0xed, 0x5a, 0xc3, 0x50, 0x8b, 0xa8, 0xed, 0xa3, 0x50, 0x8b, 0x0e, 0x20, 0x33, 0xfb, - 0xa1, 0x16, 0x51, 0xcf, 0x1e, 0x80, 0x5a, 0x74, 0x00, 0x71, 0x4f, 0x41, 0x2d, 0xa2, 0x4e, 0x3d, - 0x01, 0xb5, 0xe8, 0x00, 0x32, 0x7e, 0x2f, 0xd4, 0xa2, 0xbd, 0x7a, 0xfc, 0x34, 0xd4, 0x22, 0xea, - 0xcc, 0x19, 0xa8, 0x45, 0xd4, 0xf9, 0xb3, 0x50, 0x8b, 0x8e, 0xd5, 0xd3, 0xfd, 0x50, 0x8b, 0xf6, - 0xea, 0xe9, 0x73, 0x50, 0x8b, 0xa8, 0x67, 0xce, 0x43, 0x2d, 0xa2, 0x76, 0xc6, 0xa0, 0xd6, 0x50, - 0x9f, 0xce, 0x5c, 0x84, 0x7a, 0x63, 0x37, 0x0e, 0xf9, 0xdd, 0x47, 0xd8, 0x82, 0x9a, 0x07, 0x36, - 0x99, 0x3d, 0x50, 0xab, 0x96, 0xc1, 0x87, 0xa1, 0x56, 0x95, 0x3b, 0x47, 0xa1, 0x56, 0x2d, 0x83, - 0xef, 0x87, 0x5a, 0x55, 0xee, 0x1c, 0x80, 0x5a, 0xb5, 0x0c, 0x7e, 0x0a, 0x6a, 0x55, 0xb9, 0xf3, - 0x04, 0xd4, 0xaa, 0x65, 0xf0, 0x7b, 0xa1, 0x56, 0x95, 0x3b, 0xa7, 0xa1, 0x56, 0x2d, 0x83, 0x9f, - 0x81, 0x5a, 0x55, 0xee, 0x9c, 0x85, 0x5a, 0xb5, 0x0c, 0xde, 0x0f, 0xb5, 0xaa, 0xdc, 0x39, 0x07, - 0xb5, 0x6a, 0x19, 0xfc, 0x3c, 0xd4, 0xaa, 0x72, 0x67, 0x0c, 0x6a, 0x51, 0xe3, 0x90, 0xbf, 0x08, - 0xf5, 0x86, 0x6e, 0x1c, 0x5c, 0x6b, 0xf7, 0x08, 0x5b, 0x50, 0xb4, 0x0c, 0xbe, 0x07, 0x6a, 0x55, - 0xb9, 0x33, 0x0c, 0xb5, 0xea, 0x99, 0x3b, 0x47, 0xa1, 0x56, 0x2d, 0x18, 0xee, 0x87, 0x5a, 0xb5, - 0x0c, 0x7e, 0x00, 0x6a, 0x55, 0xb9, 0x73, 0x0a, 0x6a, 0x55, 0x65, 0xf9, 0x04, 0xd4, 0xaa, 0x05, - 0xc3, 0x7b, 0xa1, 0x56, 0x2d, 0x83, 0x9f, 0x86, 0x5a, 0x55, 0xee, 0x9c, 0x81, 0x5a, 0x55, 0x59, - 0x9e, 0x85, 0x5a, 0xb5, 0x60, 0xd8, 0x0f, 0xb5, 0x6a, 0x19, 0xfc, 0x1c, 0xd4, 0xaa, 0x72, 0xe7, - 0x3c, 0xd4, 0xaa, 0xca, 0x72, 0x0c, 0x6a, 0x0d, 0xf5, 0x17, 0xad, 0x8b, 0x50, 0x6f, 0xec, 0xc6, - 0xc1, 0xde, 0x7d, 0x82, 0x2d, 0x28, 0x3a, 0x1b, 0x7c, 0x0f, 0xd4, 0xaa, 0x65, 0xf0, 0x61, 0xa8, - 0x55, 0xe5, 0xce, 0x51, 0xa8, 0x55, 0xcb, 0xe0, 0xfb, 0xa1, 0x56, 0x95, 0x3b, 0x07, 0xa0, 0x56, - 0x2d, 0x83, 0x9f, 0x82, 0x5a, 0x55, 0xee, 0x3c, 0x01, 0xb5, 0x6a, 0x19, 0xfc, 0x5e, 0xa8, 0x55, - 0xe5, 0xce, 0x69, 0xa8, 0x55, 0xcb, 0xe0, 0x67, 0xa0, 0x56, 0x95, 0x3b, 0x67, 0xa1, 0x56, 0x2d, - 0x83, 0xf7, 0x43, 0xad, 0x2a, 0x77, 0xce, 0x41, 0xad, 0x5a, 0x06, 0x3f, 0x0f, 0xb5, 0xaa, 0xdc, - 0x19, 0x83, 0x5a, 0xd4, 0x38, 0xd8, 0x17, 0xa1, 0xde, 0xa0, 0x8d, 0x83, 0x43, 0x08, 0x21, 0x84, - 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x72, 0xc3, 0xa1, 0x71, 0x20, - 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0xc8, 0xda, 0x43, - 0xe3, 0x40, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x90, - 0xb5, 0x87, 0xc6, 0x81, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, - 0x08, 0x21, 0x6b, 0x0f, 0x8d, 0x03, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0xd6, 0x1e, 0x1a, 0x07, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, - 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0xac, 0x3d, 0x34, 0x0e, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, - 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x59, 0x7b, 0x8c, 0x5b, 0x20, 0x47, 0x8f, 0x45, - 0xa2, 0x03, 0x87, 0x87, 0xfa, 0x16, 0xde, 0x36, 0x8d, 0x9d, 0xde, 0xe5, 0x58, 0x64, 0x30, 0x18, - 0x89, 0x2c, 0x5d, 0xcb, 0x34, 0x7b, 0xba, 0x1a, 0xdd, 0xfa, 0x5b, 0x0f, 0x7b, 0x17, 0x5d, 0xc6, - 0x8e, 0xca, 0x9b, 0x7e, 0x9f, 0xd9, 0xd6, 0xde, 0x61, 0x94, 0x2e, 0x3a, 0x7d, 0x9b, 0xee, 0x58, - 0x76, 0xf5, 0x0e, 0xef, 0xe5, 0xc9, 0xb1, 0xfe, 0xf2, 0x1b, 0xb7, 0x3d, 0x6c, 0x7a, 0x97, 0xbd, - 0xab, 0x8c, 0x7f, 0x95, 0x29, 0xf6, 0x96, 0x3e, 0x0f, 0x72, 0x4b, 0xa6, 0x7e, 0x7f, 0x6b, 0x5f, - 0xdc, 0xa9, 0x97, 0xb2, 0xa9, 0xe6, 0x1a, 0x6f, 0x55, 0x5e, 0xb7, 0x79, 0x2f, 0x45, 0x2f, 0xdf, - 0xea, 0x58, 0xf8, 0x48, 0xd1, 0x5f, 0x2c, 0x9a, 0xa6, 0x59, 0x44, 0x95, 0x90, 0x5b, 0xef, 0xd8, - 0xb1, 0x78, 0x1c, 0x28, 0x16, 0x4b, 0x97, 0xe6, 0x7a, 0xfd, 0xdb, 0xf0, 0xf7, 0x96, 0xfe, 0x57, - 0x3e, 0x4c, 0x55, 0xfe, 0x71, 0xed, 0x94, 0xee, 0x61, 0xa5, 0x97, 0xaa, 0x1f, 0xdd, 0x0b, 0x3f, - 0x41, 0x17, 0xde, 0xe1, 0x5f, 0x78, 0xbb, 0xf2, 0x63, 0xba, 0xeb, 0xb6, 0xcd, 0xb7, 0xdf, 0xb1, - 0xc5, 0xbf, 0xb5, 0x7e, 0x44, 0xdd, 0x0f, 0xf3, 0xa2, 0xbf, 0xf4, 0x93, 0xfb, 0xf0, 0xe3, 0xce, - 0x50, 0xf5, 0x95, 0x4c, 0xa3, 0xa7, 0xfc, 0x8f, 0xc1, 0xfe, 0x7d, 0xd1, 0xa1, 0xe8, 0x63, 0x03, - 0x83, 0x47, 0x4e, 0x54, 0x3e, 0x74, 0x77, 0xe9, 0x62, 0x74, 0xe0, 0xf8, 0xd0, 0xf1, 0x63, 0x23, - 0xa3, 0x4b, 0xb7, 0xf8, 0xc4, 0xfc, 0xad, 0x8e, 0x0c, 0xc5, 0x1e, 0x3d, 0x36, 0x30, 0x72, 0x68, - 0xe9, 0x7e, 0xce, 0x09, 0x1e, 0xec, 0x0c, 0x1f, 0x8b, 0x95, 0x3e, 0x99, 0xbd, 0x4b, 0xef, 0x29, - 0x7d, 0x92, 0xa6, 0xf7, 0xee, 0x13, 0xa3, 0x91, 0xc1, 0x23, 0x7b, 0x17, 0x1f, 0xed, 0xdc, 0x5d, - 0x75, 0xed, 0xbe, 0x26, 0xd7, 0xee, 0xab, 0xbd, 0xb6, 0x73, 0x62, 0x68, 0xa4, 0xf6, 0x2b, 0xed, - 0x29, 0xff, 0xe4, 0x39, 0x34, 0xf4, 0xa8, 0x73, 0xf8, 0xf0, 0xd0, 0xc8, 0x92, 0xd9, 0xae, 0x3f, - 0x36, 0x8d, 0x3b, 0xde, 0x7e, 0xcd, 0x3c, 0xd9, 0xe9, 0xbd, 0x71, 0xa7, 0x69, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0xa4, 0xe5, 0x42, 0xf7, 0x46, - 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0xb9, - 0xd1, 0xf8, 0xc8, 0x9a, 0x82, 0x3f, 0xfe, 0xf8, 0xe3, 0x8f, 0x3f, 0xfe, 0xf8, 0xe3, 0x8f, 0x3f, - 0xfe, 0xb7, 0xa6, 0xff, 0xc2, 0xbd, 0x55, 0x5e, 0x2f, 0x5c, 0x2c, 0xbe, 0xb1, 0xf8, 0xfe, 0xca, - 0xd0, 0xaa, 0xb7, 0x17, 0x5f, 0xfb, 0x1b, 0xdc, 0xdf, 0xc2, 0x7d, 0x55, 0x7f, 0xc1, 0xd5, 0xef, - 0xad, 0x9b, 0xeb, 0x5b, 0x76, 0x37, 0x8b, 0x9f, 0xcb, 0x7a, 0xec, 0x6d, 0xeb, 0xee, 0xbf, 0xf0, - 0xf9, 0x37, 0x7b, 0x69, 0x7e, 0x3d, 0x7f, 0xdd, 0xcb, 0xe2, 0xc7, 0xaa, 0x36, 0x49, 0xe3, 0xfb, - 0xaa, 0x71, 0x2b, 0xdf, 0x55, 0x53, 0xcf, 0xa5, 0xeb, 0x2d, 0x5d, 0xae, 0xf4, 0x79, 0x5d, 0xef, - 0xd7, 0x75, 0xd3, 0xf7, 0xff, 0x66, 0xfb, 0x57, 0x83, 0xfd, 0xac, 0xf6, 0xeb, 0x2a, 0xdf, 0xff, - 0xd2, 0xeb, 0xeb, 0xfb, 0x9a, 0x97, 0xde, 0xf6, 0xfb, 0xaf, 0xe5, 0x56, 0x7d, 0x8b, 0x15, 0xb6, - 0xa3, 0xaf, 0xe1, 0xf7, 0xd7, 0x35, 0xbe, 0xae, 0x9b, 0xec, 0xbf, 0xea, 0xdb, 0x2f, 0xf7, 0xf7, - 0xf9, 0x2b, 0x3b, 0xfb, 0xc2, 0xeb, 0x26, 0x2f, 0xfe, 0x86, 0x87, 0x07, 0xff, 0xb2, 0xfd, 0xbb, - 0xfe, 0xfd, 0xcb, 0x0f, 0x68, 0xd7, 0xf0, 0x5f, 0x76, 0x37, 0x1f, 0xc3, 0x71, 0xf9, 0xff, 0xf1, - 0xfe, 0x5f, 0x7b, 0xfc, 0x5f, 0xc9, 0x7f, 0x25, 0xb7, 0x46, 0xdb, 0xb9, 0x7e, 0xdf, 0xaf, 0x3f, - 0xfe, 0xf8, 0x1a, 0x1f, 0xff, 0x6f, 0xe8, 0xeb, 0xda, 0xb8, 0xc7, 0xff, 0xa6, 0xfe, 0xf5, 0xc7, - 0xff, 0x26, 0x3c, 0x8d, 0x8f, 0x1b, 0xcd, 0x3f, 0x8f, 0xc6, 0xc7, 0xff, 0x9a, 0xc7, 0x03, 0xbe, - 0x0d, 0x78, 0xfc, 0x5f, 0xf7, 0xc7, 0x3f, 0xd5, 0xfb, 0xf9, 0xea, 0x1f, 0xff, 0x2c, 0x7b, 0x5c, - 0xd3, 0x74, 0xff, 0x5d, 0x7a, 0xf7, 0x3a, 0x3c, 0x00, 0xe2, 0xf1, 0x3f, 0x8f, 0xff, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0xff, 0x8d, 0xe6, 0x5f, 0xf7, - 0xfb, 0x66, 0xb3, 0x75, 0xaf, 0x9a, 0xdf, 0xf6, 0x1b, 0xdc, 0x7e, 0xf9, 0xfa, 0x70, 0xf9, 0x1f, - 0x4b, 0xaf, 0x7d, 0x8d, 0x7f, 0xc1, 0x6f, 0xfa, 0x7b, 0x6c, 0xc3, 0xd5, 0xcb, 0x1b, 0xe8, 0x01, - 0x1a, 0xff, 0xbe, 0xed, 0x6f, 0xb2, 0x00, 0x58, 0xf3, 0xf1, 0x06, 0x5f, 0xc7, 0xc7, 0xed, 0x5f, - 0xbf, 0xde, 0xbe, 0xb0, 0x74, 0xd0, 0x7c, 0xdd, 0xdd, 0xef, 0x5b, 0x69, 0x5d, 0xac, 0xd1, 0xba, - 0x8c, 0xaf, 0xc1, 0xed, 0x56, 0x7b, 0xfb, 0xe5, 0xfe, 0x6b, 0xed, 0x01, 0x96, 0xdf, 0x7b, 0xfd, - 0xf5, 0x1b, 0xed, 0x8b, 0xcb, 0x16, 0x37, 0x3e, 0x46, 0xff, 0xea, 0x1d, 0x71, 0xf9, 0x7a, 0x70, - 0x83, 0x75, 0xe3, 0x95, 0xd7, 0x9f, 0x1b, 0xae, 0xcb, 0xaf, 0x74, 0xdc, 0x6b, 0xb2, 0x86, 0xd7, - 0xa0, 0x85, 0xb9, 0xf1, 0x1e, 0x60, 0x25, 0x7f, 0x9f, 0xef, 0x66, 0xfa, 0x2f, 0xfb, 0xfe, 0xf4, - 0x35, 0x5e, 0x8f, 0x5f, 0x3c, 0x8e, 0xf8, 0x1b, 0x1d, 0x7f, 0x9a, 0x1d, 0x3f, 0xaa, 0xd6, 0x99, - 0xfd, 0x8d, 0x17, 0x18, 0x1b, 0xdc, 0xde, 0x7f, 0xed, 0xe3, 0xcf, 0xea, 0x7b, 0x80, 0x95, 0x3f, - 0x2f, 0x5f, 0x93, 0xe5, 0xbf, 0xfa, 0xbb, 0x6f, 0x78, 0x98, 0xfa, 0x18, 0x8f, 0x3f, 0xd5, 0xbd, - 0x55, 0xe3, 0xc3, 0x73, 0xf3, 0x35, 0xf5, 0xfa, 0xaf, 0xbc, 0xe9, 0x7e, 0xb6, 0x8a, 0xfd, 0xff, - 0x5a, 0x7b, 0xe8, 0x0d, 0xf7, 0x00, 0x4d, 0xee, 0xbd, 0xd9, 0xbf, 0x57, 0xde, 0x0b, 0xd6, 0xe5, - 0xf8, 0xef, 0x6b, 0x72, 0xfc, 0x5f, 0xd6, 0xdb, 0xfa, 0x1a, 0xde, 0xbe, 0xfe, 0xf8, 0xbb, 0x3a, - 0xff, 0x1b, 0x3d, 0xfe, 0xaf, 0xb6, 0x07, 0xb8, 0x96, 0xff, 0x0a, 0xc7, 0xff, 0x9a, 0x4f, 0x79, - 0xbd, 0xfc, 0xaf, 0xfd, 0xf8, 0xa7, 0x71, 0xbf, 0xb2, 0xfc, 0xf6, 0xf5, 0xdf, 0xcf, 0xb5, 0xeb, - 0xef, 0xd7, 0xfb, 0xf8, 0xa7, 0xc9, 0xe3, 0x8e, 0xeb, 0xee, 0x01, 0xfc, 0x4d, 0x1e, 0x4f, 0x35, - 0x7f, 0xfc, 0xd3, 0xe8, 0xb8, 0xb0, 0x7e, 0x8f, 0x7f, 0x08, 0xbf, 0x7f, 0xe1, 0x4f, 0xf0, 0xc7, - 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0xb2, 0xbe, 0xfe, 0xcb, 0xcf, 0xbf, 0x5f, 0xb6, 0x5e, - 0xe6, 0x63, 0x33, 0xad, 0xa7, 0x7f, 0x9d, 0xf1, 0xd2, 0xef, 0xf5, 0x0d, 0xcf, 0x3f, 0x26, 0xeb, - 0xeb, 0xbf, 0xc6, 0xf3, 0x51, 0xf1, 0x5f, 0xc3, 0xf1, 0xa7, 0x7e, 0x9d, 0x6c, 0x1d, 0x9f, 0xb7, - 0x83, 0x7f, 0xdd, 0x3a, 0x7f, 0xb3, 0xfd, 0x9f, 0xbd, 0x7f, 0xdd, 0x8f, 0x3f, 0xcb, 0xd6, 0xb7, - 0x6b, 0xd7, 0xff, 0x9b, 0x35, 0x74, 0xe4, 0xe3, 0x3d, 0xfe, 0xd7, 0x1e, 0x77, 0x96, 0x0e, 0x3b, - 0xf8, 0xf3, 0xf8, 0xbf, 0x65, 0xfd, 0xd9, 0x0e, 0xf8, 0xe3, 0x8f, 0x3f, 0xfe, 0xf8, 0x13, 0xfc, - 0xf1, 0x27, 0xf8, 0xf3, 0xfb, 0x17, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, - 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, 0xf0, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, - 0xfc, 0xf1, 0x47, 0x10, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, - 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0x11, 0xc4, 0x1f, 0x7f, - 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0xf1, - 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, - 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, - 0x7f, 0xfc, 0xf1, 0xc7, 0x1f, 0x7f, 0x04, 0xf1, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, - 0x82, 0x3f, 0xfe, 0x04, 0x7f, 0xfc, 0x09, 0xfe, 0xf8, 0x13, 0xfc, 0xf1, 0x27, 0xf8, 0xe3, 0x4f, - 0xf0, 0xc7, 0x9f, 0xe0, 0x8f, 0x3f, 0xc1, 0x1f, 0x7f, 0xfc, 0x09, 0x21, 0x84, 0x10, 0x42, 0x08, - 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x10, 0xb2, 0xbe, 0x31, - 0xfe, 0x0f, 0x12, 0x0a, 0x67, 0x72 +int reset_basic_snap_zlib_length = 118534; +uint8 reset_basic_snap_zlib[118534] = { + 0x5a, 0x4c, 0x00, 0x0d, 0x94, 0x2f, 0x00, 0x01, 0xce, 0xfc, 0x78, 0xda, 0xec, 0xbd, 0x7f, 0x54, + 0x62, 0x59, 0x9e, 0x27, 0x68, 0x44, 0x46, 0xd6, 0x64, 0xd7, 0x4e, 0x77, 0xe5, 0x54, 0xf5, 0xe9, + 0xdd, 0xee, 0xb3, 0x3b, 0x27, 0xb6, 0x36, 0x4d, 0x1b, 0x2d, 0x23, 0xaa, 0x22, 0xd2, 0xb0, 0xd5, + 0x34, 0xcc, 0xda, 0xaa, 0xda, 0x6e, 0x20, 0xd1, 0x3e, 0xc0, 0x83, 0x01, 0x04, 0x66, 0xcf, 0x84, + 0xba, 0x80, 0xc0, 0x1e, 0x15, 0x38, 0x82, 0x10, 0x71, 0xce, 0xce, 0xcc, 0xce, 0x39, 0xbb, 0xfd, + 0x47, 0xab, 0xc8, 0x84, 0x08, 0xf4, 0xe9, 0x0e, 0x64, 0x78, 0xcf, 0x07, 0x3b, 0xe0, 0x83, 0x01, + 0x7c, 0xd0, 0xff, 0xcd, 0x8a, 0x89, 0xf4, 0x88, 0xef, 0xb1, 0x80, 0xc0, 0xec, 0x99, 0x40, 0x16, + 0x10, 0xa8, 0x52, 0x81, 0xa3, 0x04, 0xc6, 0x1a, 0x11, 0xf5, 0x23, 0xab, 0x22, 0x23, 0x7f, 0x1a, + 0x91, 0x1a, 0xc9, 0x07, 0xe5, 0xfb, 0xde, 0xe3, 0xbe, 0xfb, 0xee, 0xfd, 0xde, 0x5f, 0xdf, 0xef, + 0xf7, 0x7e, 0xef, 0x7d, 0x0c, 0xe2, 0x4f, 0x7e, 0x76, 0x95, 0x26, 0xf9, 0x9f, 0xff, 0xd7, 0xc9, + 0xff, 0x45, 0x3a, 0x75, 0xf5, 0x7f, 0x12, 0x8c, 0x8f, 0xfc, 0xc9, 0xe5, 0x96, 0x9f, 0xdc, 0x7a, + 0x8f, 0xf6, 0x93, 0x96, 0xdf, 0x80, 0xf1, 0x24, 0x10, 0x63, 0x64, 0x62, 0x52, 0x20, 0x95, 0xfc, + 0xc9, 0x1b, 0xdf, 0x7e, 0x76, 0x91, 0xf2, 0x63, 0xe2, 0xe0, 0x4f, 0xfe, 0x12, 0xf8, 0x75, 0xa0, + 0x4b, 0x57, 0xd4, 0xa7, 0xdf, 0xdf, 0xf3, 0xfc, 0xed, 0xa5, 0x67, 0xe7, 0xdf, 0x3e, 0x08, 0x65, + 0xbe, 0xff, 0xf3, 0x4b, 0x2d, 0xcf, 0x61, 0x4b, 0xfb, 0xb7, 0xbf, 0x75, 0x35, 0xbc, 0xf0, 0xb7, + 0x9f, 0x10, 0xea, 0x37, 0x78, 0xeb, 0xf4, 0xff, 0x8f, 0xbe, 0xff, 0xec, 0xf8, 0xdf, 0xfe, 0xfb, + 0xbf, 0x7a, 0x1a, 0xf6, 0x34, 0x85, 0x94, 0x9f, 0x51, 0x3e, 0x16, 0xe8, 0x12, 0xa1, 0xe5, 0x52, + 0x4b, 0xf7, 0xf5, 0xa7, 0xc7, 0xe0, 0xbf, 0xff, 0x6b, 0xe7, 0xf7, 0x9f, 0xde, 0xf0, 0xf8, 0x57, + 0x3f, 0xff, 0xf1, 0x1f, 0xb5, 0x7c, 0x5b, 0xfe, 0x77, 0xcf, 0x8e, 0xe5, 0x7f, 0xe7, 0x44, 0x9f, + 0xdd, 0xf3, 0xd6, 0x1b, 0x4f, 0x3f, 0x2d, 0x7f, 0x73, 0x7a, 0xf2, 0x37, 0xbf, 0xf5, 0xbc, 0x96, + 0x77, 0x3e, 0x16, 0xf7, 0x1b, 0x1f, 0xfe, 0xea, 0xe8, 0xd1, 0x93, 0x7c, 0xc9, 0xff, 0xee, 0x8f, + 0x5b, 0xae, 0xb6, 0xb4, 0xdc, 0x3b, 0x3d, 0xbe, 0xd2, 0x22, 0x6f, 0xb9, 0xf7, 0x77, 0xbb, 0xca, + 0x7f, 0xb8, 0xbc, 0xab, 0x82, 0x5b, 0xde, 0x5a, 0xef, 0xfd, 0xbf, 0xbe, 0xbd, 0x7e, 0xf5, 0xe7, + 0xe5, 0x3f, 0xcb, 0xfd, 0xf0, 0xcf, 0x72, 0xff, 0xf0, 0xcf, 0xef, 0x0d, 0xfd, 0x47, 0xea, 0x3f, + 0xfb, 0x4d, 0x1a, 0xde, 0x78, 0x76, 0xcf, 0xb7, 0xbe, 0xfd, 0x3b, 0xf9, 0x7b, 0xff, 0x8d, 0xdf, + 0x3e, 0xff, 0x9b, 0x1f, 0x36, 0x3e, 0x78, 0x12, 0xae, 0xe5, 0x83, 0x96, 0x4b, 0x57, 0x2f, 0xb5, + 0xfc, 0xfc, 0x4a, 0x4b, 0x4b, 0xdb, 0xe9, 0x4d, 0xff, 0xf2, 0x19, 0xfe, 0xd5, 0x53, 0xfc, 0xeb, + 0x67, 0xf8, 0xdf, 0x9f, 0xe2, 0xe7, 0xff, 0xcf, 0x6f, 0x6e, 0xbe, 0x7a, 0xf3, 0xcf, 0x7a, 0x7e, + 0xf4, 0xa3, 0x96, 0x1f, 0x9e, 0xe2, 0xf1, 0x29, 0x9e, 0x32, 0xe1, 0x3c, 0xd2, 0x4b, 0x6f, 0x7f, + 0x95, 0xfb, 0xd5, 0xf9, 0x27, 0x9f, 0xab, 0xea, 0xfc, 0x29, 0x2f, 0xbf, 0xff, 0x9f, 0x32, 0x2d, + 0xdf, 0xfe, 0xc3, 0xff, 0xf7, 0x8e, 0xf9, 0x5f, 0x3d, 0x98, 0x5e, 0x5e, 0xfa, 0x2f, 0x2d, 0x5f, + 0x3b, 0x9e, 0xd4, 0xa7, 0x3f, 0xf8, 0x83, 0x2b, 0xdf, 0x6e, 0x39, 0xfd, 0x6b, 0xf9, 0x8b, 0xc2, + 0x27, 0x86, 0xb9, 0xf4, 0xd2, 0x9e, 0xfe, 0x7f, 0xfc, 0x97, 0xff, 0xed, 0xc1, 0x8c, 0xf9, 0x4f, + 0x2c, 0x0f, 0x2d, 0xff, 0xda, 0xf6, 0xe4, 0xfc, 0xc3, 0xbf, 0x70, 0xb4, 0xfc, 0x28, 0x3f, 0x7a, + 0xf2, 0xe7, 0x27, 0xa4, 0x83, 0xbf, 0xde, 0xff, 0x83, 0xfd, 0xbf, 0xdc, 0xbf, 0x79, 0xc0, 0xfc, + 0x45, 0xf0, 0x17, 0xc5, 0xea, 0xed, 0x5f, 0x5c, 0x3f, 0x18, 0x3d, 0x31, 0x1f, 0x16, 0x2b, 0x2d, + 0xaf, 0x11, 0xae, 0x7e, 0x01, 0xb4, 0x9f, 0xe2, 0xea, 0x1b, 0xdf, 0xf9, 0xfd, 0xdf, 0xff, 0xce, + 0x95, 0xef, 0x7c, 0xf7, 0xcd, 0xab, 0xb7, 0xde, 0xbb, 0x7a, 0xf9, 0xd2, 0xf7, 0x7e, 0xef, 0x8d, + 0xab, 0x7f, 0x74, 0xe3, 0xd9, 0x4f, 0x5f, 0x08, 0xb7, 0xde, 0xfb, 0xaf, 0xae, 0x7e, 0xf7, 0xd2, + 0xef, 0x5f, 0xfd, 0xde, 0x1f, 0x7f, 0xef, 0x0f, 0xdf, 0xfc, 0xfd, 0xab, 0xcf, 0x1a, 0xe2, 0x2f, + 0x23, 0xbc, 0xfc, 0xc7, 0x7f, 0xf8, 0xe6, 0xf7, 0xae, 0x7e, 0xeb, 0xbb, 0x6f, 0xbe, 0xf9, 0xb9, + 0xa3, 0xfb, 0xee, 0x9b, 0x97, 0xae, 0xfc, 0xf1, 0xb5, 0xcf, 0x0e, 0xf7, 0x37, 0x57, 0x9b, 0x68, + 0xe2, 0x9b, 0x87, 0x17, 0x8f, 0x0f, 0x2d, 0xdf, 0x6e, 0x31, 0xde, 0xf8, 0xe1, 0xad, 0xf7, 0x9e, + 0xf5, 0x07, 0xd6, 0xab, 0x7f, 0xdb, 0x62, 0x68, 0xb9, 0x62, 0x68, 0x79, 0xd3, 0xd0, 0xf2, 0x2d, + 0x43, 0xcb, 0x3f, 0xfa, 0xff, 0xfe, 0xe1, 0x17, 0x56, 0xf0, 0xaf, 0x5a, 0xfe, 0xde, 0xea, 0xfb, + 0xab, 0x4b, 0x7f, 0x6f, 0xfd, 0xe8, 0xaf, 0x2e, 0xff, 0xbd, 0x35, 0xf9, 0x57, 0x6f, 0xfc, 0xfd, + 0x87, 0xdd, 0x6f, 0x7d, 0xea, 0xb8, 0x73, 0xef, 0x15, 0x8f, 0x8f, 0x57, 0xcf, 0xe9, 0xb8, 0x7d, + 0x46, 0xf4, 0xde, 0x6b, 0x97, 0xaf, 0xab, 0xaf, 0x75, 0x79, 0x9d, 0x63, 0x7a, 0xf9, 0x73, 0x85, + 0xbb, 0xfc, 0xdb, 0xe7, 0x57, 0x5e, 0x1c, 0xfe, 0x52, 0x93, 0xaf, 0x5f, 0x90, 0xde, 0xfd, 0xba, + 0x9e, 0x5f, 0x7f, 0x5d, 0xf8, 0x58, 0x3e, 0x67, 0xe9, 0x69, 0xbc, 0xd4, 0xf4, 0x97, 0x1f, 0x9f, + 0x9c, 0xcf, 0x72, 0x48, 0xbf, 0xaa, 0xfb, 0x9f, 0xe5, 0x3f, 0xdd, 0xec, 0x3f, 0x3e, 0x8d, 0xa6, + 0x4f, 0x3b, 0x96, 0xdf, 0xbd, 0xfe, 0xc1, 0x59, 0xc5, 0x7f, 0xe5, 0x6b, 0xc9, 0x57, 0xe0, 0xdc, + 0x8f, 0x93, 0x2f, 0x57, 0x9e, 0xfd, 0xdd, 0x7e, 0xa2, 0xfe, 0x5b, 0xe7, 0x27, 0x67, 0xf2, 0xbc, + 0x7b, 0x9f, 0x19, 0xae, 0x71, 0xe6, 0xf9, 0xab, 0x9f, 0x41, 0x3c, 0x1f, 0x9c, 0x4d, 0x7a, 0xde, + 0x6e, 0xf6, 0x1f, 0x5f, 0x7f, 0x3b, 0x3f, 0xb7, 0xfa, 0xd3, 0xab, 0xd0, 0xbb, 0xee, 0x7e, 0x56, + 0xb8, 0x74, 0x53, 0x5f, 0x6b, 0xd2, 0x97, 0x45, 0xef, 0x7d, 0xe2, 0xf5, 0x0f, 0x3e, 0x8f, 0x3c, + 0xd6, 0xe4, 0xdf, 0x57, 0xa7, 0xf7, 0x2e, 0x42, 0x3a, 0xef, 0x7e, 0xea, 0xef, 0x8d, 0x0b, 0xc9, + 0xff, 0xb7, 0xce, 0x71, 0xfa, 0x6a, 0x9f, 0xc7, 0xee, 0x72, 0xbe, 0xe9, 0xd5, 0xa6, 0xfd, 0xf4, + 0xeb, 0xa4, 0x97, 0x9a, 0xfd, 0xeb, 0x59, 0xd5, 0xd7, 0x17, 0xea, 0x81, 0x81, 0x57, 0x96, 0xbe, + 0xc6, 0xb9, 0xe0, 0x53, 0xe0, 0x15, 0x3f, 0xef, 0xe4, 0xf3, 0x87, 0x4f, 0x7f, 0x96, 0x3c, 0x73, + 0x06, 0xf4, 0x6a, 0xb3, 0x9d, 0xfc, 0x2e, 0x3d, 0xf9, 0xd2, 0xf7, 0x5f, 0xbd, 0xe8, 0x7a, 0xe4, + 0xd7, 0x23, 0xb7, 0xd5, 0x9b, 0xf5, 0xee, 0xd5, 0xd3, 0xbb, 0x5f, 0xa0, 0x3e, 0x5f, 0x7a, 0xb5, + 0xf2, 0x46, 0xfa, 0x0b, 0x85, 0xaf, 0x9d, 0x4b, 0x39, 0xeb, 0x5e, 0xb3, 0x9e, 0x5d, 0xbc, 0xfa, + 0x7e, 0xc6, 0xf4, 0xab, 0xda, 0x13, 0x6a, 0xe7, 0x5e, 0xee, 0xbe, 0xf4, 0xea, 0xc7, 0xe1, 0xbb, + 0x17, 0xa8, 0xde, 0x7d, 0x70, 0x76, 0xf1, 0xbd, 0x75, 0xc1, 0xdb, 0xdf, 0xcb, 0xe9, 0x0f, 0x2f, + 0x7f, 0xb3, 0xed, 0x99, 0x9f, 0x9f, 0x7e, 0xd0, 0x1c, 0x07, 0xce, 0x11, 0x1f, 0xee, 0x35, 0xc7, + 0xe3, 0xd7, 0x98, 0x36, 0xbe, 0x99, 0xf9, 0x6e, 0xbc, 0xac, 0xf8, 0x3f, 0xd3, 0xbf, 0x2b, 0xf0, + 0x4d, 0xaf, 0x77, 0x97, 0xbf, 0x48, 0xf8, 0xf4, 0xcb, 0x9b, 0xdf, 0xf9, 0x52, 0x76, 0xfd, 0xbb, + 0x17, 0x97, 0xef, 0x6f, 0x35, 0xed, 0x6c, 0x5f, 0xc5, 0x5f, 0xb0, 0x49, 0xbf, 0x9a, 0x7d, 0xf8, + 0xa2, 0xd3, 0xbb, 0xcd, 0x7a, 0xfb, 0xcd, 0xf4, 0x5b, 0xfa, 0xa2, 0xfe, 0x70, 0x67, 0x29, 0x2f, + 0xa7, 0x9b, 0xfd, 0xcc, 0x85, 0xa2, 0xb5, 0x2f, 0x55, 0xae, 0x67, 0x3a, 0x5f, 0xf6, 0x92, 0xe5, + 0xcb, 0x7a, 0xb3, 0x9c, 0xbf, 0xe2, 0xbc, 0xdb, 0xf3, 0xf4, 0x42, 0xf3, 0xe2, 0xd2, 0xc5, 0x5b, + 0x03, 0xd8, 0x78, 0x2d, 0xea, 0xde, 0xa7, 0xca, 0x5e, 0x97, 0x5e, 0xa1, 0x0d, 0xb4, 0x7c, 0xae, + 0x6c, 0xc2, 0xf7, 0xea, 0x17, 0xa9, 0xbd, 0x5c, 0x18, 0x7a, 0xa5, 0xe9, 0x63, 0xff, 0x05, 0x69, + 0xe3, 0x6b, 0x4b, 0x7f, 0xed, 0xfc, 0xfa, 0x54, 0xde, 0xfb, 0x74, 0x9f, 0xa6, 0x97, 0xe6, 0x33, + 0xf7, 0xc1, 0x99, 0xf9, 0x4a, 0xbe, 0xfd, 0xb2, 0x6c, 0x57, 0xf5, 0x6f, 0xb8, 0x4c, 0x95, 0xae, + 0x9d, 0x61, 0x3d, 0xfb, 0xb2, 0xf7, 0xbf, 0xdd, 0x94, 0x6d, 0x5f, 0xdd, 0x5a, 0xd4, 0xbb, 0x67, + 0xd3, 0xce, 0x5e, 0x89, 0x2f, 0xee, 0x5b, 0xaf, 0x67, 0xb9, 0x9d, 0xe7, 0x39, 0xe9, 0xf4, 0x6b, + 0x61, 0x4b, 0x7f, 0xad, 0xe6, 0x82, 0xcf, 0xaf, 0xcf, 0xc0, 0x19, 0xd2, 0xf2, 0xab, 0x79, 0x4e, + 0xf9, 0x25, 0xd8, 0x76, 0x2f, 0xc6, 0x5a, 0x95, 0x72, 0x73, 0xbc, 0x7c, 0x5d, 0xe9, 0x07, 0x5f, + 0x71, 0x3c, 0x7f, 0xeb, 0x95, 0x8e, 0xbf, 0xe5, 0xf3, 0xa0, 0xd7, 0xd6, 0xcf, 0x4a, 0xdf, 0x68, + 0xd2, 0x26, 0xfd, 0x86, 0xad, 0x05, 0x79, 0x35, 0x34, 0x70, 0xb6, 0xfa, 0x7b, 0xe3, 0xc2, 0xae, + 0xed, 0xaf, 0xbd, 0x68, 0xce, 0xf3, 0x82, 0x96, 0x6f, 0xe0, 0x4c, 0x7c, 0xb4, 0xd3, 0xcd, 0x76, + 0xf2, 0xa5, 0x7c, 0xed, 0x1a, 0xaf, 0x6f, 0xbe, 0xdf, 0xbe, 0x28, 0xe9, 0xfd, 0x62, 0xf6, 0xae, + 0xc6, 0xe7, 0x97, 0xd7, 0x2e, 0xa8, 0xfd, 0xe2, 0x33, 0xd7, 0x14, 0x5e, 0xba, 0xf0, 0x7b, 0x53, + 0x7c, 0x25, 0x9f, 0x92, 0x57, 0x51, 0xde, 0xb5, 0x57, 0x59, 0x8f, 0xae, 0x5e, 0xc0, 0xf6, 0xfb, + 0x59, 0xf3, 0xd7, 0x67, 0xe9, 0xa3, 0x71, 0xe9, 0xca, 0x39, 0xf4, 0xd1, 0x4e, 0x7f, 0x89, 0x7c, + 0x7c, 0x6d, 0xbe, 0xd7, 0x67, 0xe7, 0xc3, 0x75, 0x72, 0x7e, 0xe7, 0x23, 0x5f, 0x17, 0xfb, 0xfa, + 0x73, 0xf6, 0x8b, 0xcb, 0x17, 0x7a, 0x5e, 0xbc, 0xa9, 0xd7, 0x7d, 0x09, 0x3b, 0xf3, 0x57, 0xda, + 0xd3, 0xf1, 0xa5, 0xec, 0x65, 0xf8, 0x05, 0x7d, 0x8f, 0x2f, 0x9a, 0x7d, 0xb5, 0xfe, 0x2a, 0xf5, + 0xd5, 0x26, 0xfd, 0xca, 0x7b, 0x06, 0x5f, 0x64, 0x9f, 0xf1, 0xe6, 0x1e, 0x8a, 0x17, 0x71, 0x6d, + 0x7a, 0x93, 0x9e, 0x17, 0x5f, 0xe5, 0x0b, 0x4c, 0x03, 0x2f, 0x71, 0x8f, 0x97, 0xb7, 0xcf, 0xb0, + 0x1d, 0xd6, 0xbf, 0x7a, 0x7e, 0xaf, 0x9c, 0x4d, 0xbf, 0xfc, 0xca, 0xd7, 0x3c, 0x9d, 0xa3, 0xb5, + 0xe6, 0x57, 0x2e, 0x46, 0x7b, 0xbb, 0xf4, 0x4d, 0x6c, 0xcf, 0x5f, 0x5e, 0xae, 0x7b, 0xa9, 0xfe, + 0x7d, 0xe5, 0x33, 0xae, 0x47, 0xaf, 0x7c, 0x0f, 0x9f, 0xd7, 0x6a, 0xef, 0xc2, 0x0b, 0xb7, 0x36, + 0xfb, 0x22, 0xcc, 0x87, 0x7c, 0x70, 0xae, 0xd2, 0x53, 0x7e, 0x19, 0xeb, 0x5f, 0x4e, 0xbe, 0xbe, + 0xf6, 0x7b, 0xb6, 0xfe, 0x67, 0x81, 0x33, 0x8a, 0xe7, 0x4c, 0xe7, 0x37, 0xbf, 0x88, 0xbd, 0xec, + 0x6e, 0xb3, 0x7f, 0xb8, 0x68, 0xfa, 0xfc, 0xb9, 0xa5, 0x97, 0xbf, 0xc9, 0xf9, 0x3f, 0xcf, 0x7b, + 0xce, 0x5c, 0x79, 0x36, 0x9f, 0x75, 0xef, 0x7c, 0xec, 0xb5, 0x7a, 0xe5, 0x15, 0x8c, 0xf3, 0x5f, + 0xff, 0x7a, 0xb3, 0xf4, 0xd9, 0x3f, 0xff, 0x55, 0xda, 0xd5, 0x02, 0x9f, 0x33, 0x5c, 0xed, 0x6b, + 0xb1, 0x2b, 0xbc, 0xac, 0x79, 0xb6, 0xf2, 0x37, 0xb1, 0xff, 0x3a, 0x6f, 0xeb, 0x53, 0xee, 0xbd, + 0x0c, 0x79, 0xab, 0x39, 0x76, 0x9e, 0x23, 0x7a, 0x31, 0xde, 0xab, 0x53, 0x7b, 0x7d, 0x6d, 0x4a, + 0x1f, 0xbc, 0x54, 0x1f, 0x8a, 0x0b, 0x3d, 0xb7, 0x74, 0xf5, 0x65, 0xad, 0x4d, 0x7a, 0x39, 0xb6, + 0x99, 0xaf, 0x7b, 0xcd, 0xda, 0x07, 0x17, 0x6b, 0xce, 0xfc, 0x15, 0xf8, 0xd6, 0x3d, 0x91, 0x4d, + 0x2e, 0x7f, 0xf1, 0xfb, 0x3e, 0xdf, 0x1a, 0x94, 0xab, 0x17, 0xa3, 0x9f, 0xbf, 0xf7, 0xe5, 0x7c, + 0x2b, 0x6b, 0x67, 0xe1, 0x8b, 0x79, 0xf7, 0xe2, 0xd8, 0xd6, 0x5e, 0xc7, 0x7d, 0xc9, 0xbf, 0x06, + 0x1d, 0xe4, 0xeb, 0xdf, 0x73, 0xe3, 0x1c, 0xfb, 0x80, 0xdd, 0x7b, 0x75, 0xf2, 0x4f, 0xf9, 0x6b, + 0x19, 0x6f, 0x5e, 0xf2, 0x9c, 0xc7, 0x57, 0xb2, 0x4d, 0x5f, 0x6e, 0xf6, 0x2f, 0xaf, 0xcd, 0xda, + 0xb3, 0xb3, 0xb0, 0x39, 0x35, 0x7d, 0x45, 0x5f, 0xcf, 0xf7, 0x31, 0x5e, 0xc0, 0x76, 0x7e, 0xb9, + 0x59, 0x5f, 0xce, 0x77, 0x79, 0x7f, 0xed, 0x6b, 0x09, 0xea, 0xcd, 0x72, 0xfe, 0x06, 0xd0, 0x0f, + 0xce, 0x67, 0x3d, 0x7e, 0xab, 0x59, 0x3e, 0x4d, 0xda, 0xa4, 0x67, 0xa9, 0xcf, 0xbd, 0x7a, 0xfa, + 0x6a, 0xe6, 0x96, 0x03, 0x67, 0xb0, 0x07, 0xec, 0xd5, 0x2f, 0x68, 0xd7, 0x3a, 0x5f, 0xbe, 0xd3, + 0xcd, 0x3d, 0xc6, 0xce, 0xb9, 0xaf, 0xc7, 0x5b, 0x2f, 0x6d, 0x8f, 0xa1, 0x7b, 0x57, 0x9a, 0x6b, + 0x4d, 0x9a, 0xb4, 0xa9, 0x6f, 0x7e, 0x16, 0x05, 0x2e, 0xe0, 0x5e, 0x22, 0x9a, 0xd7, 0xa2, 0xfc, + 0x1b, 0xaf, 0x4d, 0x3d, 0x2e, 0x9f, 0x4b, 0x9f, 0x99, 0x73, 0xb1, 0xa7, 0xf5, 0x8f, 0xbf, 0x9a, + 0x8f, 0xd8, 0xa5, 0x66, 0xff, 0xf8, 0x2a, 0xdf, 0x53, 0x74, 0xde, 0xfc, 0x6f, 0xee, 0x36, 0xcb, + 0xf7, 0x42, 0xca, 0xe7, 0xe9, 0xf3, 0x91, 0xaf, 0xbb, 0x5f, 0x47, 0x3c, 0x57, 0xce, 0x6f, 0x39, + 0x07, 0xbe, 0xf4, 0xfc, 0xfe, 0x59, 0xea, 0xb7, 0xb5, 0x0b, 0xdc, 0x4e, 0x9a, 0xe3, 0x51, 0x93, + 0x9e, 0x33, 0x7f, 0xab, 0xb7, 0xbe, 0xf8, 0xda, 0xae, 0xa6, 0x8f, 0xfc, 0xe7, 0xa2, 0x27, 0x67, + 0x1c, 0xee, 0xfc, 0xfa, 0x37, 0x07, 0x5e, 0x8e, 0xdc, 0x78, 0xe6, 0x7e, 0x5a, 0x67, 0x2d, 0x57, + 0x94, 0xcf, 0x70, 0x7e, 0xec, 0xea, 0xd9, 0x8e, 0xa3, 0x97, 0xce, 0x87, 0x3e, 0xfb, 0xda, 0xfa, + 0xe1, 0x7f, 0xf0, 0x55, 0xf7, 0x1c, 0xbb, 0xf7, 0x4d, 0x1e, 0xff, 0xee, 0x35, 0xe5, 0x80, 0x4f, + 0x7f, 0xc7, 0xe2, 0x97, 0xda, 0xeb, 0xe2, 0x1c, 0xbd, 0xdf, 0xf5, 0xf2, 0x27, 0xb7, 0xb3, 0xb3, + 0xf0, 0x07, 0xbe, 0xfb, 0xb8, 0x39, 0x0f, 0x75, 0x91, 0xe9, 0x85, 0xd0, 0xdf, 0xbe, 0x9c, 0x3f, + 0x7f, 0xed, 0xdc, 0xd9, 0x4f, 0xcf, 0x09, 0x7d, 0xbb, 0xc9, 0x87, 0xf3, 0xbc, 0x47, 0xda, 0x37, + 0x44, 0x7e, 0x39, 0x33, 0xb9, 0xb4, 0xfe, 0x79, 0xc6, 0xe1, 0xda, 0xe7, 0xec, 0x27, 0x2e, 0x1a, + 0xfd, 0x6a, 0x7a, 0xfa, 0x45, 0xf0, 0xbf, 0x0b, 0x34, 0xfb, 0x93, 0x57, 0x4b, 0xcb, 0x67, 0x22, + 0x3f, 0x34, 0xbe, 0xb4, 0xbc, 0xfd, 0x15, 0xe6, 0x89, 0xbe, 0x52, 0xde, 0x3f, 0x9f, 0xef, 0xce, + 0xbd, 0x8b, 0x5d, 0xc6, 0x57, 0xcf, 0xae, 0xed, 0x5f, 0x7a, 0x5d, 0xea, 0xfc, 0xe7, 0xef, 0x43, + 0x9b, 0xfb, 0xbf, 0x7e, 0xed, 0x3a, 0xef, 0x07, 0xe7, 0xca, 0xa6, 0x5f, 0x3e, 0x37, 0xfc, 0x3f, + 0xbf, 0xfd, 0xd2, 0xbd, 0xb3, 0xd7, 0x5d, 0xca, 0xaf, 0xf3, 0x1c, 0xd0, 0x37, 0x57, 0xd7, 0xa9, + 0x5d, 0xd0, 0xfc, 0x9f, 0xfd, 0x1a, 0xaa, 0xf4, 0x6b, 0x59, 0x4f, 0x4e, 0xce, 0x55, 0x7a, 0x5e, + 0xfa, 0x9a, 0xa8, 0xf4, 0xc5, 0x2f, 0xb7, 0x97, 0x57, 0x0f, 0xcf, 0xd4, 0xb7, 0xf2, 0xcb, 0xca, + 0x65, 0x8d, 0xcf, 0x11, 0xee, 0xf2, 0xc5, 0xe2, 0xeb, 0x79, 0x9d, 0x83, 0x78, 0x45, 0x3a, 0xff, + 0xa5, 0xa6, 0x9c, 0xfd, 0xfa, 0x8f, 0xb7, 0xdf, 0xf4, 0x35, 0x11, 0xe9, 0x57, 0xe8, 0x1b, 0xfc, + 0xd6, 0x85, 0xa9, 0x57, 0x1f, 0x34, 0xe5, 0xa2, 0x8b, 0xb0, 0xf6, 0xf0, 0xf2, 0x2b, 0xb6, 0x71, + 0x5f, 0x00, 0x5f, 0xf6, 0x2f, 0xda, 0x9e, 0x2f, 0xd0, 0xfb, 0x9e, 0xbf, 0xc0, 0x78, 0xfc, 0xd6, + 0x6b, 0xda, 0xff, 0xbf, 0xfd, 0xba, 0x8f, 0x73, 0xaf, 0xca, 0x07, 0x24, 0xf0, 0x35, 0xe6, 0xf3, + 0xca, 0x4b, 0x7f, 0xce, 0xb9, 0x7f, 0xff, 0xd0, 0xdb, 0x5f, 0xf7, 0x1a, 0xbf, 0xaf, 0x65, 0x1c, + 0xb8, 0xfc, 0x7a, 0xb4, 0xd3, 0x6f, 0x84, 0x5e, 0x14, 0x68, 0xea, 0x1b, 0xaf, 0x1d, 0xbd, 0xf2, + 0x12, 0x7c, 0x46, 0x5e, 0xaa, 0xfc, 0xd4, 0xdc, 0xd3, 0xa8, 0x49, 0x9b, 0x7b, 0xba, 0x34, 0xe9, + 0xf9, 0x9b, 0xc7, 0xf9, 0x82, 0xf2, 0xf3, 0xab, 0xf4, 0x29, 0xfc, 0x52, 0x3e, 0x78, 0x27, 0x5f, + 0xc8, 0xdf, 0xe5, 0x1b, 0x4d, 0x3f, 0xdb, 0x5e, 0x71, 0xf5, 0x77, 0xec, 0x82, 0xe7, 0xc4, 0x9f, + 0xe0, 0x93, 0x7d, 0x95, 0xcf, 0xc5, 0x7b, 0xda, 0xae, 0x7c, 0xce, 0x79, 0xa4, 0xcf, 0x68, 0x47, + 0x6f, 0x9f, 0xb7, 0xfa, 0x72, 0xb5, 0xd9, 0x5e, 0x9a, 0xf4, 0xdc, 0xda, 0xb7, 0x2f, 0x7f, 0xfc, + 0xfd, 0x97, 0x27, 0xe7, 0x64, 0x2d, 0x4b, 0xed, 0x82, 0x95, 0x4b, 0xe3, 0x1b, 0x53, 0xff, 0x3e, + 0xf8, 0x86, 0x3f, 0xff, 0x8b, 0xd0, 0x46, 0x53, 0xff, 0x78, 0x45, 0xf6, 0x84, 0xda, 0xab, 0x19, + 0xaf, 0x2f, 0xc8, 0xfc, 0xfe, 0xe7, 0xeb, 0xb7, 0x2f, 0x7d, 0x85, 0xf7, 0x1f, 0x9f, 0x07, 0x7f, + 0xfb, 0x8b, 0xb7, 0xf6, 0xba, 0xb9, 0x66, 0xf2, 0x8b, 0xfa, 0x75, 0x34, 0xdf, 0x1f, 0x7d, 0xc1, + 0xfd, 0x6e, 0x9b, 0xf4, 0xb5, 0xf6, 0xa7, 0xaa, 0x37, 0xf9, 0xf7, 0xaa, 0xe8, 0x5b, 0xe7, 0x2e, + 0x5d, 0xf7, 0x9a, 0xe5, 0x72, 0x11, 0xfd, 0xd4, 0x2f, 0x37, 0xf7, 0xae, 0x79, 0x75, 0xfe, 0x91, + 0x81, 0x8b, 0x9b, 0xbf, 0x0f, 0x9a, 0xe5, 0xfc, 0x85, 0xed, 0xb8, 0x3f, 0xca, 0x8f, 0x9e, 0xfc, + 0xf9, 0x09, 0xe9, 0xe0, 0xaf, 0xf7, 0xff, 0x60, 0xff, 0x2f, 0xf7, 0x6f, 0x1e, 0x30, 0x7f, 0x11, + 0xfc, 0x45, 0xb1, 0x7a, 0xfb, 0x17, 0xd7, 0x0f, 0x46, 0x4f, 0xcc, 0x87, 0xc5, 0xca, 0xeb, 0xcf, + 0xa7, 0xd7, 0x7b, 0x7e, 0xe8, 0xee, 0x57, 0xb5, 0xaf, 0xbc, 0xfa, 0xfe, 0xe0, 0xca, 0x57, 0xf1, + 0x9f, 0x6d, 0xeb, 0xbe, 0xde, 0xf2, 0x31, 0xfc, 0xe4, 0xd6, 0x7b, 0x3f, 0xf9, 0x31, 0x95, 0xfe, + 0x9b, 0x0b, 0x97, 0xfe, 0xeb, 0xa7, 0x97, 0x89, 0x3f, 0xfe, 0xd1, 0xc7, 0x83, 0x5d, 0x7e, 0xf3, + 0x5f, 0x3c, 0xf1, 0x62, 0x6c, 0x79, 0xdc, 0xf2, 0xf0, 0xbf, 0x7d, 0xb6, 0xb2, 0xbd, 0xe5, 0xd2, + 0xa5, 0xb7, 0x5a, 0x3f, 0x78, 0x16, 0xeb, 0xd3, 0x10, 0x4f, 0x2e, 0x2e, 0x7f, 0xff, 0xd9, 0xc9, + 0xbf, 0x78, 0xeb, 0x4f, 0xff, 0xc9, 0xb3, 0xa3, 0xbf, 0x6f, 0xf9, 0xf9, 0x93, 0x7e, 0xe7, 0x13, + 0x70, 0xfa, 0x88, 0x1b, 0xcf, 0x3f, 0x42, 0xd7, 0x32, 0xf0, 0xeb, 0xc5, 0xf3, 0x2d, 0x2d, 0x6f, + 0xfd, 0xda, 0xe1, 0xf5, 0xd7, 0x8f, 0x98, 0xf8, 0xe5, 0x23, 0xfe, 0xf4, 0x9f, 0x7c, 0xf6, 0x23, + 0x68, 0xc4, 0x9f, 0xfe, 0xd6, 0xf9, 0xa5, 0x37, 0x7b, 0x9f, 0x92, 0x4b, 0x2d, 0x9f, 0x85, 0xd3, + 0x3b, 0x7f, 0xf6, 0xcf, 0xe8, 0x3f, 0x1b, 0xfc, 0xe9, 0xcf, 0x9e, 0xc5, 0x70, 0xe9, 0x8a, 0xfe, + 0xd3, 0x82, 0xff, 0x3a, 0x8d, 0xff, 0x5d, 0x4b, 0x0b, 0x00, 0x00, 0xbf, 0xfe, 0x3f, 0x79, 0x7c, + 0xf7, 0xd7, 0xff, 0x57, 0x9e, 0x7e, 0x7e, 0x93, 0xdd, 0xcb, 0x97, 0x2f, 0x9d, 0xb2, 0xb0, 0xe5, + 0xc9, 0xe7, 0xd2, 0xd3, 0xcf, 0xa7, 0xe3, 0xf1, 0x77, 0x9e, 0x7c, 0x5a, 0xfe, 0x9b, 0xc7, 0x3f, + 0xa5, 0x12, 0x19, 0x3f, 0xfb, 0xb3, 0x8f, 0x45, 0xd4, 0x62, 0x79, 0x9a, 0xa7, 0xdf, 0x8a, 0xe0, + 0x52, 0xeb, 0x6f, 0x0e, 0xc3, 0xa7, 0x5f, 0x74, 0xe0, 0xf4, 0xeb, 0x8d, 0xd3, 0xff, 0x6f, 0x7d, + 0xab, 0xa5, 0xe5, 0xdf, 0x26, 0xdf, 0x6c, 0xf9, 0xf9, 0x5f, 0x7e, 0xe7, 0xb7, 0xa2, 0xa7, 0x5f, + 0x7a, 0x5a, 0x07, 0xde, 0xf8, 0xe5, 0xff, 0x67, 0x21, 0x04, 0xbd, 0xf7, 0xdd, 0x4f, 0x0f, 0xf1, + 0x34, 0x99, 0x3d, 0x9f, 0x9e, 0xcc, 0x4b, 0x97, 0xde, 0xf9, 0xcd, 0xf1, 0xd3, 0x6f, 0xa0, 0xe5, + 0x4c, 0xf1, 0x59, 0xc9, 0xbc, 0xf4, 0x2c, 0x99, 0x3f, 0xfa, 0xe1, 0xc5, 0x48, 0xe6, 0x8f, 0x2e, + 0x44, 0x32, 0x7f, 0xf2, 0x97, 0xc0, 0xaf, 0xf8, 0x79, 0xe9, 0x0d, 0xcd, 0xa9, 0x92, 0x63, 0x68, + 0xfc, 0xbb, 0xa7, 0xe9, 0x79, 0xfc, 0xad, 0xc7, 0x3f, 0xfb, 0xee, 0xde, 0x7f, 0xff, 0xf6, 0xe9, + 0xc9, 0xf7, 0x3c, 0x7f, 0xfb, 0xf4, 0xd2, 0x7f, 0xfa, 0xa7, 0xbf, 0x1d, 0xc5, 0xd2, 0x2f, 0x83, + 0xfe, 0xcd, 0xdd, 0x47, 0xff, 0xee, 0xb7, 0x2a, 0xf4, 0x7f, 0xf8, 0x9d, 0xf3, 0xcf, 0x83, 0x4b, + 0x97, 0xde, 0x7e, 0xf1, 0x8f, 0x6f, 0x3d, 0x4d, 0xd1, 0xaf, 0xce, 0xfe, 0x51, 0x4b, 0xff, 0xaf, + 0xda, 0xd9, 0xc7, 0x03, 0x5d, 0x39, 0x6d, 0xb0, 0x6f, 0x1e, 0xff, 0xdf, 0xdf, 0x2f, 0xb4, 0xb4, + 0x7c, 0xfb, 0xcd, 0xfc, 0xb3, 0x9f, 0xde, 0x7c, 0x12, 0xf3, 0x9f, 0xfe, 0xc5, 0x67, 0x3e, 0xfd, + 0x8d, 0xd3, 0xd6, 0xfe, 0x66, 0xcb, 0xb7, 0x4e, 0xa3, 0xbe, 0x8c, 0x3f, 0xd5, 0xc7, 0xdf, 0xfc, + 0xd6, 0xe3, 0x5f, 0xe2, 0xc5, 0xdd, 0xc8, 0xa7, 0xfd, 0xfa, 0xf1, 0x9c, 0xfd, 0x9b, 0x27, 0x5f, + 0x97, 0xdf, 0xf8, 0xd6, 0x57, 0x29, 0x4e, 0x45, 0xf6, 0x1d, 0xcd, 0xc9, 0xe3, 0xdf, 0x7b, 0xfc, + 0x3f, 0x74, 0xec, 0xb5, 0x7c, 0x13, 0xf0, 0xf8, 0xb7, 0xf1, 0x2f, 0xdf, 0xfc, 0x25, 0xab, 0xbb, + 0x9f, 0x7e, 0x97, 0x9e, 0x7e, 0xff, 0xe7, 0x67, 0x97, 0xbe, 0xf3, 0xf5, 0xa6, 0xb4, 0xfb, 0xe6, + 0x0f, 0x7e, 0xf2, 0x3f, 0x52, 0xae, 0xfe, 0x74, 0x88, 0x76, 0x95, 0x71, 0xe3, 0xda, 0xad, 0xab, + 0x3f, 0xea, 0x7a, 0xef, 0x47, 0x3f, 0xf8, 0xe1, 0x0f, 0x4f, 0xff, 0x5a, 0x9a, 0x68, 0xa2, 0x89, + 0x26, 0x9a, 0x78, 0x1e, 0x4f, 0xba, 0x49, 0xc6, 0xa9, 0xe2, 0xf2, 0xd3, 0x1f, 0xfe, 0x4a, 0xc4, + 0x7e, 0xaa, 0x60, 0x3c, 0xbe, 0xf2, 0x27, 0x8f, 0x1f, 0xbf, 0xfd, 0xd4, 0x15, 0x4d, 0xf0, 0x54, + 0x85, 0x68, 0xb9, 0x7c, 0xef, 0xed, 0xff, 0xfc, 0x34, 0xc4, 0x69, 0xe8, 0x1b, 0x3f, 0xfd, 0xe1, + 0xc7, 0x85, 0xf2, 0x67, 0x2a, 0xc9, 0xcf, 0xa5, 0x2d, 0xbd, 0x8a, 0x9e, 0x67, 0x77, 0xdc, 0x6b, + 0xf9, 0xf1, 0xde, 0xa9, 0x7a, 0xf1, 0xf6, 0x3f, 0x7f, 0xfa, 0xcb, 0x9f, 0xff, 0x84, 0x4a, 0xa4, + 0xfc, 0xf8, 0xcf, 0x7f, 0xf6, 0xab, 0x9b, 0xde, 0xb8, 0x94, 0x7a, 0xeb, 0xf7, 0x5a, 0xfe, 0xcf, + 0xd3, 0xa3, 0x7f, 0x7c, 0x2a, 0xca, 0xbc, 0xb7, 0x49, 0xdb, 0x8e, 0xdc, 0x67, 0xfb, 0x7c, 0x90, + 0xe8, 0xda, 0xf1, 0x92, 0x7d, 0x27, 0x40, 0xd0, 0xc0, 0x6d, 0xa2, 0x9b, 0x2e, 0x93, 0x3b, 0x19, + 0xd7, 0xa7, 0x77, 0xb3, 0xb4, 0xc0, 0x9d, 0xe5, 0x38, 0xfa, 0x51, 0x42, 0x24, 0x22, 0xe3, 0x2b, + 0x79, 0x3b, 0x43, 0x26, 0x75, 0xf7, 0x70, 0x14, 0x70, 0x6c, 0x1a, 0xd2, 0xd0, 0x2c, 0xb7, 0xca, + 0x05, 0x99, 0x99, 0x24, 0xd5, 0xe3, 0x27, 0x01, 0x24, 0x14, 0x85, 0xe5, 0x3e, 0x4a, 0xed, 0x4e, + 0x4c, 0x4e, 0x69, 0x74, 0x71, 0xa7, 0x25, 0xbe, 0xae, 0xa2, 0x4c, 0xcd, 0x07, 0xb0, 0x14, 0x53, + 0xc7, 0x2c, 0x50, 0x8b, 0x45, 0x91, 0x32, 0x91, 0x42, 0x32, 0x6c, 0xb9, 0x1e, 0xaf, 0x10, 0x48, + 0xc0, 0x2f, 0xf1, 0x74, 0x58, 0xa3, 0x02, 0xd8, 0x34, 0x79, 0xd1, 0xd2, 0x0a, 0xfc, 0x06, 0x4f, + 0xaf, 0x03, 0xdb, 0x48, 0xa7, 0x9d, 0xba, 0x0d, 0x0b, 0x82, 0xf8, 0x98, 0x5d, 0x34, 0x28, 0x16, + 0xb9, 0xdd, 0x1d, 0xca, 0xb4, 0xdb, 0xed, 0x24, 0xa5, 0xc7, 0xfa, 0xcb, 0xce, 0x9a, 0x61, 0x7a, + 0x7f, 0x01, 0xed, 0x2c, 0x03, 0x2e, 0xb8, 0xa0, 0x52, 0xa6, 0x6a, 0x68, 0x54, 0xa6, 0x31, 0x8d, + 0xf9, 0x1b, 0x28, 0x9f, 0x53, 0x45, 0x21, 0xfb, 0xfb, 0x10, 0x78, 0x00, 0xe6, 0x77, 0xd1, 0x15, + 0x58, 0x6d, 0x1b, 0x94, 0x70, 0x45, 0x98, 0x34, 0xe2, 0xce, 0x8e, 0xdc, 0xa6, 0x3b, 0xe0, 0xfe, + 0x2a, 0x73, 0xc1, 0x23, 0x62, 0x27, 0x27, 0xdf, 0x2f, 0xa8, 0xe7, 0x0a, 0x78, 0x69, 0xfa, 0xee, + 0x98, 0x7c, 0xbd, 0x9d, 0x63, 0x1a, 0x41, 0xc9, 0x32, 0xd3, 0x48, 0x8e, 0x2a, 0x34, 0x41, 0x92, + 0x44, 0x01, 0xe6, 0x30, 0xd9, 0x51, 0x13, 0xe6, 0x27, 0xe6, 0x4d, 0xee, 0x62, 0x85, 0x49, 0x35, + 0x0b, 0x20, 0x67, 0x45, 0x9c, 0xe0, 0x54, 0x21, 0x68, 0xac, 0x07, 0x33, 0xa9, 0x6b, 0x4a, 0x1b, + 0x64, 0x21, 0xb4, 0x07, 0x1d, 0xf6, 0x8e, 0xe0, 0x01, 0x78, 0x9f, 0x9b, 0xe4, 0x64, 0xc4, 0x4c, + 0x7b, 0xf1, 0xb0, 0xc2, 0x5d, 0x0f, 0x4f, 0x15, 0x0b, 0xde, 0x90, 0x53, 0x3c, 0x1a, 0xd7, 0x98, + 0xfa, 0xaa, 0xd5, 0x61, 0x47, 0x63, 0x00, 0x28, 0xd1, 0x33, 0xb1, 0xb2, 0xe4, 0x51, 0xae, 0x5b, + 0x26, 0x99, 0xb2, 0xc0, 0x2c, 0xe5, 0x2c, 0x18, 0x1d, 0x2a, 0xea, 0x75, 0xd7, 0x6f, 0xb9, 0xe7, + 0x33, 0x2c, 0xaa, 0x9c, 0x6f, 0xcd, 0x34, 0x1c, 0x32, 0x2e, 0x93, 0x85, 0x9b, 0x90, 0x21, 0x71, + 0x92, 0xef, 0x93, 0xa4, 0x92, 0x8a, 0x3c, 0xc6, 0x58, 0xe4, 0x8f, 0xa1, 0x7e, 0x12, 0x02, 0x73, + 0x6e, 0xb9, 0x78, 0x27, 0x01, 0xf4, 0xae, 0xf2, 0x18, 0x2d, 0x2b, 0x79, 0x95, 0x6a, 0x15, 0xb5, + 0xd5, 0xd1, 0x06, 0x75, 0x3e, 0xd3, 0xcb, 0xfc, 0x68, 0xce, 0xed, 0xbe, 0x69, 0x4c, 0xc5, 0xcb, + 0xd7, 0x7d, 0x6e, 0xeb, 0x2e, 0x8d, 0xb1, 0x5f, 0x4d, 0xae, 0x6b, 0xb4, 0x33, 0x56, 0x95, 0xed, + 0x0e, 0xf6, 0xbb, 0x9c, 0xa6, 0x63, 0xc0, 0x0b, 0x38, 0x4d, 0x54, 0x52, 0xb3, 0xb1, 0xe5, 0x04, + 0x32, 0xb9, 0x56, 0xbe, 0x85, 0xf9, 0x38, 0x68, 0xcc, 0x2d, 0x4d, 0x05, 0xa4, 0x07, 0x8f, 0x6a, + 0xc9, 0xca, 0x87, 0xf3, 0xf5, 0x56, 0x1e, 0x02, 0x75, 0xc0, 0xf1, 0x89, 0x45, 0xb8, 0x83, 0xb4, + 0x8f, 0x88, 0xf1, 0xd4, 0x56, 0x7a, 0xbc, 0xca, 0xc4, 0x18, 0x66, 0xa4, 0x2c, 0x7b, 0x50, 0x18, + 0xf1, 0x61, 0x11, 0x51, 0x7f, 0x6d, 0x8b, 0x6f, 0xc9, 0xb2, 0x42, 0x90, 0xd1, 0x77, 0x1d, 0x17, + 0x9b, 0xe4, 0xce, 0x4d, 0xf5, 0x0f, 0x3c, 0x3d, 0xce, 0x7a, 0x9a, 0xbb, 0xee, 0x80, 0xd1, 0xeb, + 0x60, 0x42, 0x6e, 0x9e, 0x8e, 0x45, 0x26, 0x7b, 0x04, 0xed, 0xdc, 0x0c, 0x12, 0x53, 0x6a, 0xec, + 0x05, 0x55, 0x5c, 0x33, 0x9e, 0xe8, 0x0d, 0xa1, 0xab, 0xfa, 0xd6, 0x5c, 0x90, 0x77, 0x18, 0x0e, + 0x6f, 0x89, 0x08, 0x22, 0xee, 0x06, 0x67, 0x4c, 0x12, 0x3a, 0x84, 0x59, 0xfd, 0x83, 0x32, 0x9b, + 0x27, 0x96, 0xe4, 0x29, 0xb2, 0x5c, 0x49, 0x72, 0x15, 0xb9, 0x1d, 0x0b, 0x70, 0xee, 0x0b, 0x79, + 0x3c, 0x2d, 0x42, 0xa9, 0xee, 0xd8, 0x3d, 0x55, 0xbf, 0x5d, 0x68, 0x27, 0x6b, 0xf6, 0x56, 0x1f, + 0x5a, 0x8f, 0x19, 0x0d, 0xeb, 0x75, 0x95, 0x8c, 0x7a, 0x44, 0xd8, 0xa2, 0x2e, 0x83, 0xae, 0xfa, + 0x84, 0x56, 0x61, 0x8d, 0x4a, 0x55, 0x86, 0xd6, 0x0e, 0xfa, 0xca, 0x76, 0x8c, 0xc3, 0x39, 0xc8, + 0x90, 0xa9, 0x33, 0xc6, 0xe5, 0x04, 0x6d, 0xdc, 0x22, 0xe0, 0x43, 0xe3, 0xdb, 0xd1, 0x81, 0x9b, + 0x45, 0x73, 0x51, 0x3a, 0x28, 0x5b, 0x31, 0x75, 0x4f, 0x7e, 0x88, 0xbd, 0xb7, 0x29, 0x39, 0x10, + 0xdd, 0x6f, 0x63, 0x03, 0x2e, 0xb3, 0x07, 0x3c, 0x44, 0xdb, 0xad, 0xd4, 0x2d, 0xae, 0xb9, 0x78, + 0x30, 0xa5, 0x1d, 0x59, 0xdf, 0xa2, 0xd7, 0x62, 0x82, 0x9a, 0xc1, 0x9d, 0x63, 0xdb, 0x2b, 0x22, + 0x88, 0x49, 0xf5, 0xa6, 0xb2, 0x38, 0x1a, 0x8c, 0x88, 0x5a, 0xf3, 0x1f, 0x69, 0x47, 0x28, 0xa5, + 0xd2, 0x68, 0x2a, 0x8c, 0xc1, 0x32, 0x8e, 0x2a, 0xec, 0xb0, 0x3d, 0xc7, 0x69, 0x66, 0x97, 0xf5, + 0x05, 0x9c, 0xa6, 0xac, 0x83, 0x23, 0xba, 0xe5, 0xe0, 0xac, 0x45, 0x3b, 0x28, 0xa8, 0x02, 0xef, + 0x05, 0x5c, 0x6b, 0x8d, 0x77, 0x02, 0x6e, 0xb2, 0xf7, 0x61, 0xc2, 0xbe, 0xa5, 0xed, 0xb4, 0xdb, + 0x36, 0x95, 0x08, 0x81, 0xc0, 0xe1, 0xcf, 0xc0, 0x02, 0x1c, 0xe8, 0x1b, 0xb0, 0x91, 0x8f, 0xf7, + 0xac, 0xd4, 0x8a, 0xb7, 0xc2, 0x81, 0xf2, 0xda, 0x9e, 0x0e, 0x9c, 0x3e, 0xaf, 0x03, 0x6e, 0x7c, + 0xb4, 0x6f, 0x16, 0xdc, 0xb8, 0x4b, 0xcb, 0x09, 0x84, 0xb5, 0x3b, 0x06, 0x90, 0x4d, 0x3e, 0xb6, + 0x5a, 0x86, 0x8a, 0x6b, 0x27, 0x56, 0x34, 0x52, 0xbf, 0x3b, 0x22, 0xa5, 0x56, 0xad, 0x23, 0x91, + 0x39, 0x6d, 0x3f, 0x81, 0x24, 0x59, 0x5b, 0xb2, 0x3b, 0x84, 0xec, 0x12, 0x04, 0xc2, 0x95, 0x56, + 0x12, 0x89, 0x83, 0xdd, 0x5a, 0x06, 0x53, 0xa3, 0x06, 0x48, 0xed, 0xa2, 0x43, 0xbc, 0xc8, 0xe4, + 0x48, 0x17, 0x85, 0x2d, 0xd3, 0x6b, 0x87, 0x6e, 0x6c, 0x28, 0xe7, 0x03, 0x9e, 0x05, 0x63, 0x59, + 0x40, 0x9c, 0xa9, 0xc0, 0x2e, 0x11, 0x3d, 0xd2, 0x15, 0x25, 0x68, 0xbd, 0xf7, 0x39, 0x1e, 0x92, + 0x12, 0x5c, 0xef, 0x95, 0x98, 0xb5, 0x83, 0x20, 0x55, 0x2d, 0x31, 0xe7, 0xb7, 0x51, 0x49, 0x16, + 0xdc, 0x8f, 0x42, 0x43, 0x8e, 0x83, 0x63, 0xdd, 0xfa, 0xad, 0x48, 0x7d, 0x60, 0xc0, 0x73, 0xe0, + 0xf2, 0x5b, 0x22, 0x4c, 0x57, 0xac, 0x35, 0xf5, 0xa1, 0x49, 0x80, 0x50, 0x27, 0x26, 0x74, 0xad, + 0x51, 0xf9, 0x8a, 0x76, 0xc0, 0x0d, 0xce, 0x1f, 0xc6, 0xac, 0x40, 0xc4, 0xd2, 0x86, 0xe3, 0xdc, + 0x4e, 0xc1, 0xe4, 0xa6, 0xd2, 0x4c, 0x74, 0x15, 0x13, 0x92, 0x04, 0xbe, 0x87, 0x4a, 0x7c, 0x20, + 0x9b, 0x76, 0xdf, 0xdc, 0xef, 0x57, 0xfa, 0xda, 0x88, 0x8e, 0x71, 0xb3, 0x85, 0xe0, 0xab, 0xff, + 0x20, 0xe0, 0x90, 0x2b, 0xda, 0x13, 0x4e, 0x09, 0x04, 0xf8, 0x1d, 0x55, 0xbd, 0x9e, 0x42, 0x63, + 0x8f, 0x9f, 0x24, 0x90, 0x79, 0xe4, 0x1d, 0xc8, 0xed, 0x98, 0xcf, 0x10, 0x83, 0xb4, 0x52, 0xd1, + 0x6a, 0x85, 0xb9, 0xad, 0xcf, 0x71, 0xba, 0x15, 0x7e, 0x01, 0xa7, 0x7b, 0x61, 0x68, 0x3c, 0x41, + 0x29, 0x3a, 0x27, 0x4c, 0x6d, 0x09, 0xad, 0xa9, 0x95, 0x70, 0x73, 0xe1, 0x01, 0x22, 0x13, 0xeb, + 0x6d, 0x90, 0x3f, 0xa6, 0x33, 0x59, 0xc4, 0x1c, 0x5e, 0x92, 0x29, 0x74, 0xed, 0x39, 0xcc, 0xdd, + 0x54, 0xe9, 0x8a, 0xae, 0x78, 0x5c, 0x13, 0x0b, 0x84, 0x13, 0x62, 0xae, 0x56, 0x1e, 0xe6, 0xa4, + 0xf6, 0x72, 0x65, 0x7d, 0xb1, 0x20, 0x65, 0x6f, 0x3a, 0xf4, 0x23, 0x09, 0xe1, 0x8a, 0xbe, 0xf5, + 0x80, 0x02, 0x74, 0x11, 0x68, 0xfb, 0x8a, 0x38, 0x1c, 0xe7, 0x9b, 0xdc, 0x2c, 0xc6, 0x70, 0xaa, + 0xd8, 0x76, 0x1d, 0x47, 0xb8, 0xaa, 0x78, 0x15, 0x9b, 0xae, 0x92, 0xa9, 0x74, 0x5d, 0xeb, 0x8d, + 0x71, 0x63, 0xc3, 0x33, 0xe4, 0xca, 0x58, 0x05, 0x6c, 0xd8, 0x80, 0x96, 0x21, 0x8a, 0x28, 0x66, + 0x1b, 0x4c, 0xee, 0x3c, 0x6e, 0xe5, 0x31, 0xb2, 0x1e, 0x51, 0x5c, 0xe3, 0x34, 0x0f, 0x30, 0x5c, + 0x88, 0x17, 0x4b, 0xd2, 0x64, 0xdc, 0x32, 0x86, 0xcd, 0xd7, 0x76, 0x73, 0xb3, 0x07, 0x4b, 0xbe, + 0x1e, 0xe7, 0xc1, 0xcc, 0x86, 0xa6, 0x5a, 0x68, 0xf5, 0xe2, 0x1a, 0xcc, 0x33, 0x8a, 0x23, 0x15, + 0x54, 0x19, 0xe7, 0x4c, 0x1c, 0xc5, 0x7d, 0x3a, 0x7e, 0x5b, 0xd0, 0xb1, 0x62, 0x6a, 0xed, 0x58, + 0x07, 0x7d, 0xc9, 0x70, 0x7f, 0x6d, 0x4c, 0x20, 0x5b, 0x57, 0xee, 0xef, 0x41, 0xed, 0x5b, 0x36, + 0xe3, 0x32, 0x69, 0x2f, 0x3a, 0xc2, 0x62, 0xcc, 0xb1, 0xd3, 0xbd, 0x22, 0xd9, 0x8e, 0x8e, 0xb0, + 0x2e, 0xa4, 0xc7, 0x6e, 0x6d, 0x3a, 0x57, 0xea, 0x3d, 0x65, 0xd1, 0xda, 0x23, 0x74, 0x9a, 0xa7, + 0x33, 0x4f, 0x33, 0xc7, 0xe7, 0x32, 0xdc, 0x94, 0xd2, 0xb5, 0x0c, 0x16, 0xa9, 0x2b, 0x3b, 0x89, + 0x5e, 0x1a, 0x26, 0x58, 0x87, 0x4c, 0x9c, 0x62, 0x9d, 0xed, 0x98, 0x5a, 0x0a, 0x95, 0x52, 0x0b, + 0x2b, 0xeb, 0x52, 0x40, 0x7b, 0x6d, 0x19, 0x9f, 0x5f, 0xb4, 0x4b, 0x68, 0xfc, 0x31, 0x21, 0x0c, + 0x01, 0xa3, 0x09, 0x7e, 0x17, 0x2a, 0x4a, 0x04, 0xe4, 0x9b, 0xc8, 0xc8, 0xef, 0x72, 0x9a, 0x81, + 0xac, 0xbf, 0x80, 0xd3, 0xfd, 0x2a, 0xf9, 0x42, 0x25, 0x57, 0x95, 0x69, 0x5b, 0x59, 0x93, 0x2e, + 0x64, 0xc9, 0x8f, 0xba, 0x12, 0x46, 0x9c, 0x04, 0xdb, 0xee, 0x4f, 0x5f, 0xb7, 0xb9, 0xad, 0x52, + 0x4f, 0xc9, 0x51, 0xf7, 0x37, 0x56, 0x71, 0x6b, 0x0f, 0x89, 0x03, 0xa9, 0x92, 0x3e, 0x6d, 0x51, + 0x07, 0xb1, 0xaa, 0x90, 0x37, 0x97, 0x9f, 0xc0, 0xee, 0x13, 0xdb, 0xf7, 0xc1, 0xc5, 0xba, 0xc6, + 0x66, 0x48, 0x8a, 0x8f, 0x23, 0xca, 0x4a, 0x26, 0x2e, 0xa7, 0x1e, 0xae, 0xdf, 0x10, 0x1e, 0xfb, + 0x6d, 0x76, 0xbf, 0xd4, 0x5a, 0x0a, 0xa9, 0xa8, 0x58, 0x67, 0x14, 0xcf, 0xf4, 0x48, 0x81, 0xe4, + 0x58, 0x8e, 0xb9, 0x19, 0x99, 0x5a, 0xc9, 0x69, 0xe6, 0x96, 0xcc, 0x76, 0x46, 0x59, 0x8e, 0x12, + 0x8e, 0xc6, 0xc1, 0x4a, 0x2d, 0x51, 0x45, 0x50, 0x20, 0xbf, 0x12, 0x1d, 0x89, 0x49, 0xd8, 0x0c, + 0x2d, 0x48, 0x12, 0x17, 0xe9, 0xa7, 0xbd, 0x02, 0x90, 0x91, 0xb0, 0x35, 0x52, 0x96, 0xd2, 0x16, + 0xe2, 0x9d, 0xb8, 0x6c, 0xca, 0xb9, 0xf7, 0xa0, 0xe8, 0x42, 0x72, 0xd7, 0x25, 0x11, 0xcd, 0x31, + 0x13, 0xce, 0x64, 0x19, 0x09, 0x71, 0xa5, 0xf6, 0x64, 0x39, 0xe1, 0x53, 0x59, 0xc6, 0x7a, 0x39, + 0xb8, 0xc5, 0x47, 0xdc, 0x33, 0xba, 0x61, 0x91, 0x6c, 0xd5, 0x0c, 0x87, 0xd9, 0x49, 0x7b, 0xff, + 0x74, 0x31, 0x69, 0x36, 0x4f, 0xf3, 0xf8, 0x05, 0x5e, 0xa2, 0x9a, 0x6f, 0x04, 0xd4, 0xf8, 0x7e, + 0x0c, 0xe7, 0xa9, 0xc6, 0xeb, 0xac, 0xb2, 0x3a, 0x15, 0xdd, 0x4d, 0x42, 0x5e, 0x4b, 0x47, 0x5f, + 0x55, 0x6c, 0xb1, 0x06, 0x0f, 0xeb, 0xca, 0xb4, 0x83, 0x67, 0x81, 0x46, 0x23, 0xb0, 0x94, 0x7b, + 0xcd, 0x1e, 0x62, 0xae, 0x59, 0xaf, 0xe7, 0xa9, 0xf7, 0x37, 0x49, 0x0e, 0xc3, 0x3b, 0xa1, 0x2a, + 0x10, 0xed, 0x5e, 0xdf, 0x67, 0x97, 0xf5, 0xd0, 0x50, 0xf1, 0x4e, 0x83, 0x0f, 0xd4, 0xdc, 0xd9, + 0xfc, 0x3a, 0x83, 0x93, 0xeb, 0x00, 0x83, 0xb5, 0x6e, 0x2b, 0x95, 0x2a, 0x41, 0x5d, 0x4e, 0x46, + 0xd2, 0xfc, 0x1c, 0xa7, 0xcd, 0xa1, 0x17, 0x70, 0x9a, 0x25, 0xf1, 0x1a, 0x3c, 0xed, 0xd4, 0x64, + 0xd1, 0x30, 0xd2, 0x5e, 0x31, 0xbc, 0x07, 0x4e, 0x48, 0x46, 0x46, 0xb8, 0x71, 0xdb, 0x9d, 0x05, + 0x68, 0x33, 0x2f, 0x03, 0x7c, 0xe0, 0xe4, 0x0e, 0x02, 0x4b, 0x7c, 0x52, 0x00, 0x24, 0xa6, 0x1d, + 0xd9, 0x1e, 0xdb, 0xdd, 0x29, 0xaf, 0xa5, 0x6b, 0x6e, 0x3b, 0xd0, 0x3e, 0x44, 0x4b, 0xbf, 0xb7, + 0x9b, 0x3f, 0x58, 0xd0, 0xae, 0xd7, 0x68, 0x7a, 0x6b, 0xd9, 0xc1, 0xdd, 0x31, 0xe4, 0xc4, 0x79, + 0xd0, 0x1f, 0xed, 0x88, 0x38, 0xcc, 0x99, 0x1b, 0x68, 0x1d, 0xb6, 0x59, 0x0f, 0xd8, 0x15, 0xfe, + 0xb4, 0x57, 0x58, 0xcb, 0xc9, 0xdd, 0x48, 0x87, 0xdf, 0x4e, 0x35, 0x45, 0xf1, 0x8d, 0xd5, 0xa2, + 0xe8, 0xdd, 0xb8, 0x53, 0xcc, 0xb1, 0x1d, 0xf8, 0xca, 0xaa, 0xdd, 0x62, 0x60, 0xf6, 0xc1, 0xfa, + 0x35, 0xca, 0xec, 0x7c, 0xae, 0x73, 0xc8, 0xb1, 0x62, 0xbf, 0xb9, 0x71, 0x30, 0x63, 0xe9, 0xdd, + 0x98, 0xdc, 0x89, 0x92, 0x4e, 0xeb, 0xc0, 0x00, 0x03, 0xab, 0x18, 0x44, 0x9c, 0x88, 0x2c, 0xa9, + 0x02, 0xe2, 0x2e, 0x74, 0x63, 0x62, 0xa7, 0x5a, 0xf4, 0x49, 0x93, 0x4e, 0x75, 0x92, 0xb4, 0x0f, + 0xc2, 0x68, 0xe7, 0x70, 0xad, 0xab, 0x06, 0xc7, 0xab, 0x30, 0x93, 0x17, 0x9d, 0x4a, 0x4a, 0xd9, + 0xb8, 0x4c, 0xcd, 0x19, 0xda, 0xae, 0x74, 0x76, 0x74, 0x85, 0x27, 0x76, 0x0a, 0x84, 0xd0, 0xfe, + 0xa3, 0x70, 0x47, 0x70, 0xee, 0x21, 0xd2, 0x4b, 0xa2, 0xdd, 0xf1, 0xdc, 0x20, 0xd9, 0x0b, 0xae, + 0x23, 0xb4, 0x54, 0xdf, 0x2c, 0x20, 0xe3, 0x09, 0xe1, 0x3a, 0x02, 0xf7, 0x75, 0x56, 0xee, 0xf2, + 0x2d, 0xe6, 0xaa, 0xca, 0xe8, 0x06, 0x92, 0xf2, 0x1d, 0x1d, 0x6b, 0x73, 0x6a, 0xc9, 0x7a, 0xac, + 0x32, 0x8e, 0x4d, 0xfb, 0x27, 0x17, 0x33, 0x2c, 0x39, 0x67, 0x61, 0x64, 0x9a, 0x3d, 0x38, 0xff, + 0xc0, 0x8c, 0xa9, 0x79, 0x51, 0xb3, 0x59, 0xc1, 0xc1, 0x33, 0xeb, 0x22, 0xb6, 0x36, 0x23, 0xa3, + 0x30, 0x30, 0xf3, 0x08, 0x11, 0xc0, 0x46, 0xfa, 0x87, 0x68, 0xae, 0xe7, 0x64, 0x0f, 0xa6, 0xcc, + 0xf3, 0x02, 0x4e, 0xf3, 0x26, 0xa9, 0x5b, 0x87, 0x76, 0x12, 0x05, 0x8a, 0xa9, 0x6e, 0x18, 0x2b, + 0x63, 0x62, 0xcd, 0x47, 0x73, 0xfc, 0x36, 0xe8, 0xae, 0x38, 0x2b, 0x98, 0x9e, 0xcb, 0x4c, 0xf3, + 0x86, 0xe6, 0x0e, 0x8a, 0x9b, 0x61, 0xa4, 0xce, 0x73, 0xc1, 0xdc, 0xba, 0x1f, 0x0c, 0x92, 0x56, + 0x6a, 0x04, 0xb2, 0x36, 0x4d, 0x00, 0x64, 0xa1, 0x03, 0x0e, 0xa1, 0xaf, 0x64, 0x78, 0x3f, 0x0d, + 0xea, 0xbd, 0xbb, 0xcb, 0x11, 0x7a, 0xfa, 0x41, 0x10, 0xdf, 0x73, 0x6b, 0x45, 0x2a, 0x71, 0x71, + 0x9a, 0x3c, 0xe9, 0x1a, 0xaf, 0x0f, 0xf4, 0x56, 0x26, 0xaa, 0x6e, 0xbf, 0x8e, 0xa1, 0x25, 0x1e, + 0x1f, 0x98, 0x0b, 0x99, 0x0a, 0x32, 0x0e, 0x43, 0x42, 0x8c, 0x6f, 0x83, 0x86, 0x22, 0x59, 0xe3, + 0xd1, 0xc1, 0x06, 0xba, 0x98, 0x21, 0x6d, 0x3c, 0xac, 0x59, 0xa7, 0x79, 0x74, 0x6d, 0x97, 0x78, + 0x6e, 0x54, 0x6f, 0x0e, 0x2e, 0xa8, 0x2d, 0xf6, 0xf8, 0x70, 0xea, 0x88, 0xb1, 0x99, 0x9c, 0x58, + 0xda, 0x8d, 0x91, 0xa8, 0x27, 0x61, 0x8f, 0x7f, 0xcc, 0x02, 0xe1, 0x1c, 0x26, 0xd2, 0x79, 0x0c, + 0xe8, 0xc6, 0x42, 0x51, 0x2e, 0xcc, 0x2c, 0x5f, 0x2f, 0x65, 0xb8, 0xfd, 0x43, 0x0b, 0x8c, 0x87, + 0x5e, 0x12, 0xc9, 0x05, 0xda, 0xc2, 0x9a, 0xe2, 0x4c, 0xc2, 0xba, 0x15, 0xb5, 0xb2, 0xa6, 0x5d, + 0x3a, 0x16, 0xb7, 0xdf, 0x85, 0xb8, 0x05, 0xca, 0x12, 0xb4, 0x1c, 0xb3, 0xdb, 0x45, 0xd7, 0x82, + 0x21, 0xf7, 0xc4, 0xfd, 0x8e, 0x1e, 0xcd, 0x81, 0x3e, 0x58, 0xd7, 0xe7, 0xcb, 0x32, 0x86, 0x77, + 0x2f, 0xc3, 0x05, 0xf8, 0x96, 0x62, 0x94, 0xb5, 0xf0, 0x50, 0xef, 0x6f, 0x04, 0x86, 0x1b, 0x47, + 0x8c, 0x88, 0x41, 0xab, 0x18, 0xfc, 0xd0, 0xa0, 0xea, 0x0b, 0x69, 0xeb, 0xfd, 0x9b, 0x07, 0x80, + 0x08, 0x40, 0x81, 0x35, 0xe3, 0x49, 0xae, 0x33, 0x64, 0xf6, 0x57, 0x20, 0xfa, 0x2a, 0x18, 0x8d, + 0x61, 0xa9, 0x55, 0x6b, 0xf5, 0xa3, 0x82, 0x4f, 0x35, 0x89, 0xdf, 0xb9, 0xdf, 0xb5, 0xb1, 0xa6, + 0xcd, 0x4c, 0x03, 0xa7, 0xec, 0xfe, 0x0d, 0xa7, 0x5f, 0x1e, 0x7e, 0x29, 0x3f, 0x76, 0x11, 0x5e, + 0x50, 0x86, 0xad, 0x64, 0x2a, 0x80, 0xb4, 0x92, 0xa8, 0xce, 0x5c, 0x50, 0x68, 0x58, 0x46, 0x08, + 0x24, 0xaa, 0xcd, 0x30, 0x2a, 0x21, 0x6f, 0xa3, 0x24, 0x55, 0x9a, 0x09, 0xb4, 0x5d, 0x07, 0xf4, + 0x66, 0xd0, 0x3a, 0x49, 0xd7, 0x76, 0x88, 0x49, 0xa7, 0x39, 0x99, 0x56, 0xd3, 0x66, 0x32, 0x24, + 0x98, 0x6a, 0x04, 0xdd, 0x71, 0x6c, 0x0d, 0xe6, 0x89, 0xb5, 0x8c, 0x18, 0x25, 0xb2, 0x8d, 0x67, + 0x88, 0x71, 0x54, 0x9d, 0xa9, 0x53, 0x27, 0xef, 0x7b, 0x68, 0x42, 0x25, 0x98, 0x26, 0xd1, 0x5d, + 0x08, 0xa7, 0x87, 0xbe, 0xfd, 0xc0, 0x2c, 0x04, 0x19, 0x86, 0x11, 0x9a, 0x13, 0xbb, 0x83, 0x32, + 0x82, 0xda, 0xeb, 0x2c, 0xe6, 0xe4, 0x68, 0x66, 0x90, 0x14, 0x07, 0xba, 0xda, 0x58, 0xd4, 0x87, + 0xb0, 0x99, 0x16, 0xd4, 0x0a, 0x3a, 0x04, 0xf4, 0x8c, 0x19, 0xb4, 0xcf, 0xca, 0xcd, 0xe6, 0xeb, + 0xf4, 0x55, 0x73, 0x87, 0x08, 0x70, 0x20, 0x3d, 0x56, 0x91, 0xf6, 0x1a, 0xe8, 0xde, 0xd6, 0x12, + 0x3a, 0x50, 0x7a, 0x7c, 0x11, 0x72, 0x2f, 0xca, 0x6d, 0xa9, 0x18, 0x15, 0xb4, 0x74, 0x5d, 0xa7, + 0x9f, 0x0e, 0xc7, 0x2c, 0xea, 0x6c, 0xa5, 0xf5, 0x3a, 0x63, 0xc4, 0xfa, 0xe4, 0xde, 0xa7, 0x5f, + 0xb0, 0x48, 0x7c, 0x00, 0xf4, 0x3c, 0x39, 0x1a, 0x79, 0x97, 0xc1, 0x38, 0x4d, 0x9f, 0x6b, 0x50, + 0x6f, 0x1d, 0xa1, 0x81, 0xf3, 0x26, 0x16, 0x31, 0x8f, 0x9a, 0x58, 0xac, 0xfc, 0xda, 0x91, 0x65, + 0x88, 0xb6, 0x76, 0x7a, 0x1b, 0x75, 0xaa, 0x32, 0x10, 0x66, 0x50, 0x2b, 0x63, 0x22, 0xea, 0xc4, + 0xaf, 0x1f, 0x34, 0x6f, 0x3d, 0x7d, 0xd0, 0xee, 0x03, 0x1f, 0xcb, 0xb0, 0x55, 0xe9, 0xcc, 0x4d, + 0xd2, 0xcd, 0x23, 0x0c, 0xfa, 0xb1, 0x95, 0xb0, 0x1e, 0x1c, 0x36, 0x10, 0x48, 0x71, 0x4c, 0xca, + 0x62, 0xe4, 0x9f, 0xa4, 0x7e, 0x71, 0xe4, 0x01, 0x4a, 0xc3, 0xe9, 0x8f, 0x59, 0x64, 0xf2, 0x1d, + 0x9b, 0xb5, 0x73, 0xb6, 0x01, 0x3c, 0x27, 0xa9, 0xb7, 0x76, 0xbe, 0x80, 0xd3, 0xa3, 0x54, 0xc6, + 0x8e, 0x99, 0xb5, 0x4e, 0x37, 0x03, 0x25, 0x09, 0x97, 0x57, 0x94, 0xb2, 0x27, 0x30, 0x8f, 0x94, + 0x36, 0x98, 0xe9, 0xb3, 0x38, 0xb0, 0x95, 0x25, 0xcb, 0xa0, 0xd3, 0xb8, 0xe7, 0x63, 0xaa, 0x0f, + 0x8b, 0x08, 0xf3, 0x2e, 0xe3, 0xb8, 0x36, 0xe4, 0x86, 0x09, 0x5c, 0x5a, 0xda, 0x3b, 0x5f, 0x8a, + 0xe7, 0xc5, 0x59, 0x8b, 0xc3, 0xc8, 0x1c, 0x23, 0x0c, 0x31, 0x7d, 0xad, 0x49, 0x05, 0xc2, 0x2d, + 0xe5, 0x4a, 0x22, 0x19, 0x5a, 0x8a, 0x97, 0x86, 0x4f, 0x0a, 0x9e, 0xb8, 0x59, 0x5f, 0xc1, 0x23, + 0x7b, 0x0d, 0xd1, 0x0d, 0x97, 0xdb, 0x4c, 0x38, 0x72, 0xcf, 0x5a, 0x6a, 0xee, 0x42, 0xea, 0x51, + 0xa5, 0x0c, 0x15, 0x14, 0x95, 0x46, 0x60, 0xbc, 0x66, 0x19, 0x8a, 0x14, 0xb5, 0x22, 0xc2, 0x94, + 0xa1, 0x8d, 0x00, 0x32, 0x97, 0x3c, 0xee, 0x76, 0x55, 0xcd, 0x98, 0x92, 0xcd, 0xd7, 0xb8, 0x31, + 0xd9, 0xf0, 0x9e, 0x3b, 0x06, 0xcd, 0xed, 0x5b, 0x6f, 0x25, 0x26, 0x76, 0x90, 0x7e, 0x09, 0x63, + 0x49, 0xeb, 0xc9, 0x4f, 0x69, 0x6d, 0xb6, 0xc8, 0xcc, 0xfc, 0x2a, 0x6a, 0x87, 0x68, 0x92, 0x5d, + 0xaa, 0x31, 0x2d, 0xe8, 0x61, 0xa7, 0xbd, 0x8b, 0x05, 0xd5, 0xac, 0xae, 0x95, 0xd8, 0x2e, 0x9a, + 0x47, 0x58, 0x2a, 0x35, 0x77, 0x0c, 0xde, 0xa4, 0x9a, 0x40, 0x74, 0xb0, 0xe4, 0x5d, 0xb2, 0x92, + 0xf4, 0x7c, 0x54, 0xcc, 0x5e, 0x4a, 0xb0, 0x5c, 0x93, 0x52, 0x48, 0xb6, 0x1b, 0x8c, 0x38, 0xb2, + 0x5e, 0x04, 0x8e, 0xe6, 0x0a, 0x2e, 0xa8, 0xd2, 0x9d, 0xb8, 0xbe, 0x89, 0xbc, 0x63, 0x1d, 0x24, + 0xcf, 0x7a, 0x52, 0x5b, 0xd5, 0xdd, 0xc3, 0xac, 0x7d, 0x92, 0x2b, 0x88, 0xd1, 0x60, 0x95, 0x25, + 0xea, 0x26, 0xcd, 0x1f, 0x26, 0x7b, 0x26, 0x56, 0x2b, 0x02, 0x9f, 0x0b, 0x95, 0xc4, 0x5d, 0x45, + 0xc7, 0xa3, 0xb4, 0x4b, 0xc3, 0xbf, 0xef, 0x0f, 0x2e, 0xa1, 0xa6, 0xd1, 0x58, 0x9a, 0xa3, 0x95, + 0xe5, 0x70, 0x73, 0x36, 0x73, 0xac, 0xe1, 0x55, 0xbc, 0x71, 0xcd, 0x8c, 0xf6, 0x39, 0x49, 0x1d, + 0x21, 0xbe, 0x80, 0xd3, 0x42, 0xcc, 0x0d, 0x67, 0x8b, 0x75, 0x0d, 0x5c, 0x9c, 0xde, 0x9c, 0xdf, + 0xb1, 0x8e, 0x92, 0x7c, 0x99, 0x3b, 0xa9, 0x75, 0xb1, 0x32, 0xfd, 0x2e, 0x8e, 0x58, 0xc6, 0xc3, + 0x12, 0xd4, 0x3e, 0x56, 0x08, 0xc9, 0x7c, 0x9d, 0xbe, 0xeb, 0x9b, 0x70, 0x7b, 0x1c, 0xc7, 0x8b, + 0x66, 0x4a, 0x67, 0xd5, 0x64, 0x08, 0x28, 0x42, 0xfc, 0x69, 0x20, 0x82, 0x15, 0x3b, 0x49, 0x52, + 0x5f, 0xaa, 0xf2, 0xae, 0x7d, 0x21, 0x2d, 0x09, 0x91, 0x37, 0x9d, 0x1c, 0x60, 0x1a, 0x9b, 0xc2, + 0xcb, 0xd3, 0x76, 0x28, 0xd7, 0xb9, 0xae, 0xb6, 0x25, 0x8e, 0xfd, 0x80, 0xc3, 0xec, 0x99, 0xe6, + 0x2e, 0x1c, 0x8d, 0xd0, 0x8a, 0x95, 0x77, 0xc3, 0xdc, 0x9d, 0x48, 0xa0, 0x3b, 0x6a, 0x42, 0xed, + 0x14, 0xea, 0x9c, 0xd1, 0x3d, 0x80, 0xba, 0x99, 0xee, 0xd6, 0x60, 0x4a, 0xec, 0x1b, 0xd4, 0xd0, + 0x46, 0xb1, 0x3e, 0x7c, 0xc7, 0xfe, 0x6e, 0xa5, 0x8b, 0x9a, 0x4a, 0x61, 0xa9, 0x78, 0x81, 0x65, + 0x06, 0x45, 0x22, 0x45, 0xcf, 0x3e, 0x15, 0xea, 0x92, 0x48, 0x55, 0x51, 0xb7, 0x58, 0x0e, 0x38, + 0x62, 0xd3, 0xfd, 0xfe, 0xf1, 0x04, 0x24, 0x4e, 0x08, 0x4d, 0xef, 0xc2, 0xdb, 0x3a, 0xa8, 0x63, + 0xeb, 0xa3, 0xe3, 0x93, 0x00, 0x91, 0xa9, 0xef, 0xad, 0x79, 0x1c, 0xba, 0xb6, 0x50, 0x44, 0x06, + 0x20, 0x82, 0x30, 0x60, 0x12, 0x73, 0xd8, 0xc9, 0x71, 0x4b, 0xb1, 0xb2, 0x49, 0x53, 0x13, 0xe3, + 0x8c, 0x65, 0x78, 0xfd, 0xe6, 0x8c, 0x11, 0xe2, 0x4e, 0xc6, 0x85, 0x29, 0xbf, 0xc0, 0xfb, 0x00, + 0x93, 0x93, 0x49, 0x49, 0xed, 0x08, 0x1b, 0x31, 0x62, 0xf1, 0x21, 0x04, 0x89, 0xc5, 0x7a, 0x38, + 0x93, 0x46, 0xab, 0x78, 0xc3, 0xd7, 0x11, 0x8b, 0x7f, 0xe4, 0x75, 0x97, 0xf0, 0xb0, 0x65, 0x7e, + 0xd9, 0xe5, 0x74, 0xcf, 0x2c, 0x47, 0x97, 0x6a, 0x60, 0x39, 0xf1, 0xa1, 0x7e, 0x29, 0x10, 0xd4, + 0xdb, 0x3b, 0x7b, 0xea, 0x78, 0x8d, 0x5b, 0x88, 0xdb, 0x50, 0x3e, 0x53, 0x2a, 0x8f, 0x30, 0x93, + 0x25, 0x25, 0xff, 0x79, 0x9d, 0xc8, 0x4c, 0x79, 0x01, 0xa7, 0xc5, 0xfd, 0x4e, 0x48, 0xc7, 0x61, + 0xd3, 0x13, 0xda, 0x76, 0xc0, 0x90, 0x90, 0x51, 0x4e, 0x6b, 0xf7, 0x3b, 0x55, 0x1f, 0x63, 0xf8, + 0x41, 0xd5, 0x3b, 0xb8, 0x90, 0x6b, 0x25, 0x82, 0xda, 0x77, 0xe2, 0x02, 0xce, 0x54, 0xf6, 0xd6, + 0x11, 0xc5, 0x00, 0xd9, 0xc0, 0xa9, 0x07, 0xb0, 0x67, 0x12, 0xdc, 0x3f, 0x22, 0x50, 0x87, 0xd4, + 0xc8, 0x20, 0x18, 0x91, 0xcf, 0xbb, 0x79, 0xb6, 0x28, 0xc2, 0xe1, 0x7e, 0x08, 0x27, 0x6d, 0x13, + 0x5b, 0xfb, 0xe6, 0xa1, 0x94, 0x2d, 0xe5, 0x19, 0x05, 0x81, 0x5d, 0x0c, 0x02, 0x69, 0xf5, 0x29, + 0xe4, 0xc8, 0x30, 0xe7, 0x47, 0xd9, 0x2e, 0xba, 0xaf, 0x83, 0xc4, 0x96, 0xb5, 0xf6, 0x74, 0x4e, + 0x44, 0xb2, 0xd7, 0xa7, 0xb7, 0xe7, 0xe7, 0x8f, 0x22, 0xae, 0xa9, 0xd3, 0xf1, 0x87, 0x33, 0x8b, + 0x41, 0x71, 0x12, 0x6d, 0xc9, 0x4c, 0xde, 0x2f, 0x55, 0xd0, 0xb8, 0x7c, 0xd1, 0x24, 0x14, 0x29, + 0xd8, 0xab, 0x96, 0x78, 0x75, 0x69, 0x71, 0x39, 0x28, 0xb4, 0x61, 0x36, 0xeb, 0xe1, 0x3c, 0x0e, + 0x72, 0x45, 0x75, 0x10, 0x65, 0x51, 0x9d, 0x5a, 0xf3, 0x60, 0x70, 0x31, 0xd1, 0x2e, 0x70, 0x21, + 0x90, 0x48, 0x4e, 0x82, 0x2d, 0xc2, 0xfc, 0xaa, 0x8f, 0x9e, 0x8b, 0xe7, 0x51, 0x88, 0x50, 0x59, + 0x75, 0x73, 0x58, 0xb7, 0xec, 0xa0, 0x55, 0x00, 0x29, 0xe7, 0xb1, 0x7e, 0xf2, 0xf0, 0xf6, 0x11, + 0x81, 0xc5, 0x34, 0x62, 0xeb, 0x92, 0xd9, 0xa5, 0x4a, 0x0f, 0x93, 0xad, 0xc0, 0x00, 0xc6, 0xec, + 0x52, 0x66, 0x64, 0x12, 0x88, 0xb6, 0x76, 0xd2, 0x68, 0xf9, 0x47, 0x49, 0x32, 0x4d, 0xaf, 0xb3, + 0x72, 0x66, 0x97, 0x3d, 0xb7, 0x48, 0xc3, 0x98, 0xb6, 0x2f, 0x14, 0x1e, 0xf6, 0x10, 0x1a, 0xd4, + 0x02, 0x1b, 0x61, 0x06, 0xd8, 0xb1, 0x77, 0x11, 0x98, 0xee, 0xc5, 0x61, 0xa0, 0xc0, 0xb6, 0xca, + 0x60, 0x36, 0x84, 0x23, 0x4f, 0x7f, 0x80, 0x85, 0x66, 0x1c, 0x11, 0xda, 0xd9, 0x18, 0x19, 0x16, + 0x62, 0x3c, 0x04, 0x5c, 0x78, 0x5e, 0xcf, 0x97, 0xf5, 0xbc, 0x80, 0xd3, 0xb7, 0x62, 0x45, 0x7d, + 0x61, 0xba, 0x9d, 0xe4, 0x05, 0xad, 0x5b, 0xd4, 0x24, 0x3b, 0x34, 0x49, 0x81, 0x87, 0xd3, 0x2e, + 0x93, 0x7b, 0xcd, 0x2f, 0xa7, 0x15, 0x3b, 0x09, 0x79, 0x25, 0xcf, 0xc4, 0xb6, 0x97, 0xe9, 0xb5, + 0xce, 0x0d, 0xf6, 0x82, 0x99, 0x98, 0xa8, 0xf0, 0xdc, 0x84, 0x41, 0xb6, 0x3c, 0x0f, 0x41, 0xc2, + 0xdd, 0xd5, 0x20, 0x08, 0x4c, 0x15, 0x7a, 0x71, 0xba, 0x16, 0x93, 0x0a, 0x4b, 0x93, 0xef, 0xba, + 0x39, 0xea, 0xa5, 0x63, 0x04, 0x5d, 0x33, 0x16, 0xa1, 0xcd, 0x9a, 0x14, 0x95, 0x3a, 0x5c, 0xc3, + 0x95, 0x91, 0x21, 0x20, 0x33, 0xdd, 0x5f, 0xa4, 0x57, 0x58, 0x98, 0x0b, 0x96, 0x68, 0x47, 0xf1, + 0x80, 0xd2, 0x9b, 0xf7, 0x61, 0xe2, 0xf1, 0x7c, 0x02, 0xaf, 0x15, 0xeb, 0xf1, 0x9a, 0xb1, 0x81, + 0x73, 0xd5, 0x88, 0xf8, 0xb6, 0xb0, 0xc2, 0x1d, 0x4f, 0x56, 0xc2, 0x6e, 0xeb, 0xad, 0xf2, 0x69, + 0x95, 0xd9, 0xb5, 0xc3, 0x90, 0x08, 0x2d, 0xab, 0xf9, 0xcc, 0x62, 0xe2, 0xc3, 0x72, 0x8f, 0x5b, + 0x9c, 0xa0, 0x5b, 0x28, 0x12, 0x79, 0xd2, 0x85, 0x25, 0xe8, 0xa5, 0xfb, 0xd3, 0xeb, 0x52, 0xb9, + 0xde, 0x22, 0x29, 0x4c, 0xd5, 0xc7, 0xc2, 0x71, 0x9d, 0x81, 0x73, 0xeb, 0x23, 0x44, 0x6d, 0x63, + 0x4f, 0x44, 0x5a, 0x7b, 0xa7, 0x49, 0xe9, 0xd5, 0x2a, 0x8b, 0xa1, 0x6d, 0x23, 0xc6, 0xa7, 0x50, + 0x97, 0x9b, 0xe9, 0x3a, 0x74, 0xbb, 0xd8, 0x0b, 0x19, 0x73, 0x4e, 0xc5, 0xe5, 0xba, 0x85, 0xde, + 0x92, 0xa9, 0x74, 0xec, 0x2a, 0x1b, 0x6b, 0xe6, 0xfd, 0x82, 0xa1, 0x6d, 0xcc, 0x5e, 0x1c, 0x6b, + 0x3d, 0xca, 0x6d, 0x67, 0x62, 0x49, 0x80, 0xe9, 0xf6, 0x0d, 0x4e, 0x0c, 0xf9, 0xec, 0x42, 0x95, + 0x78, 0x58, 0x67, 0x07, 0x41, 0x61, 0xf1, 0x98, 0x35, 0xb7, 0x60, 0xbe, 0x8e, 0xb0, 0xe9, 0x59, + 0x3b, 0x7b, 0x70, 0xaf, 0xc1, 0xc1, 0x17, 0x2c, 0xb9, 0xfc, 0x90, 0xc1, 0xb4, 0x54, 0x2d, 0x82, + 0xea, 0x07, 0xe0, 0xba, 0x2d, 0x75, 0x02, 0x17, 0x36, 0xb6, 0x9f, 0x93, 0x1f, 0x81, 0x91, 0xfe, + 0x17, 0x70, 0x5a, 0x16, 0x07, 0x74, 0xd0, 0xf4, 0x34, 0x2d, 0x12, 0xdb, 0x60, 0x2f, 0x22, 0x5c, + 0xde, 0x10, 0x36, 0x09, 0xa4, 0xa2, 0xf8, 0xf8, 0x5e, 0xb6, 0x6f, 0x4e, 0x15, 0xcf, 0x75, 0xba, + 0x32, 0x7c, 0xe9, 0xcd, 0x60, 0x6a, 0x05, 0xea, 0x24, 0x9d, 0xaa, 0x03, 0x2a, 0x39, 0xaf, 0x4c, + 0x9a, 0xdc, 0xde, 0x2b, 0x8e, 0x49, 0xa0, 0xed, 0x23, 0x05, 0x79, 0xf0, 0xe1, 0x7d, 0xc2, 0x4d, + 0x80, 0x96, 0x93, 0xe1, 0x07, 0x93, 0x45, 0xa9, 0x9c, 0x71, 0x68, 0x8e, 0x35, 0x36, 0xaa, 0x60, + 0x1c, 0xb5, 0xdb, 0xc1, 0x3a, 0x5c, 0x5c, 0xcb, 0x00, 0x05, 0xb9, 0xc5, 0x96, 0x42, 0x50, 0x7e, + 0x86, 0xe8, 0x18, 0x4c, 0xa6, 0x55, 0x51, 0x85, 0x85, 0x85, 0x6d, 0x41, 0xc6, 0xca, 0x80, 0x6f, + 0x1e, 0xda, 0x3b, 0x16, 0x38, 0x75, 0x06, 0x26, 0x22, 0x3f, 0xf6, 0xe7, 0xe3, 0x13, 0x3c, 0x43, + 0x0e, 0xd9, 0x4e, 0x8f, 0xf4, 0xb3, 0x3f, 0x5c, 0x85, 0x85, 0x07, 0x46, 0x8b, 0x98, 0x50, 0xde, + 0x3a, 0x40, 0xfa, 0x45, 0x4a, 0x44, 0x65, 0x17, 0x68, 0x9c, 0x8a, 0xdd, 0xcd, 0xe0, 0xac, 0xb9, + 0x4b, 0x4a, 0x5a, 0x40, 0x6b, 0x5d, 0x8a, 0xd1, 0xba, 0xe7, 0xb6, 0xbc, 0x01, 0x09, 0x51, 0x5b, + 0xe4, 0x07, 0xc5, 0x7d, 0x8d, 0x51, 0xb7, 0x4e, 0xa3, 0x2d, 0xdd, 0xef, 0x93, 0x6f, 0x6e, 0x67, + 0xaf, 0xc5, 0x57, 0x8a, 0x1e, 0x8b, 0x40, 0xa3, 0x32, 0x06, 0xc2, 0x0b, 0xaa, 0x11, 0x3b, 0x6e, + 0x18, 0x8e, 0x2f, 0x17, 0x55, 0xc3, 0xcb, 0x15, 0x1e, 0xc5, 0x51, 0x90, 0x93, 0x68, 0xf3, 0x9e, + 0xce, 0x89, 0xc1, 0x29, 0x4c, 0x20, 0xdf, 0x28, 0xe4, 0x92, 0x60, 0x11, 0x3c, 0xae, 0x34, 0x5c, + 0x46, 0x63, 0xc1, 0xe6, 0xe0, 0x19, 0xa1, 0x20, 0x57, 0x67, 0x0d, 0xd0, 0xee, 0x3a, 0xf5, 0x01, + 0x74, 0x23, 0x05, 0x41, 0xed, 0x3b, 0xb5, 0xee, 0xc2, 0xad, 0x22, 0xea, 0x4e, 0x56, 0xfd, 0x26, + 0x91, 0x12, 0x4f, 0x8e, 0x1f, 0xa6, 0x6f, 0xef, 0x8b, 0xb5, 0x41, 0x49, 0xa9, 0xe2, 0x11, 0x0f, + 0x1e, 0x2e, 0x3e, 0x57, 0xa7, 0x4f, 0xeb, 0xd4, 0x0b, 0x38, 0x3d, 0x4d, 0xa3, 0x63, 0xa7, 0xc3, + 0x65, 0x75, 0x24, 0x07, 0xe6, 0xe8, 0x86, 0x91, 0x91, 0xc1, 0x21, 0xb7, 0x96, 0xc5, 0xa4, 0x02, + 0x5a, 0x01, 0x87, 0x06, 0x60, 0xd3, 0x42, 0x76, 0xb4, 0xd5, 0x23, 0xe5, 0xe2, 0xda, 0x9c, 0x8a, + 0xcf, 0x64, 0xb5, 0x53, 0xe7, 0xcc, 0x02, 0x1e, 0x6b, 0x21, 0x13, 0x63, 0x88, 0x96, 0x76, 0x8f, + 0x52, 0xd3, 0xc6, 0x6c, 0x96, 0xb0, 0x35, 0x69, 0x18, 0x6b, 0x4d, 0x28, 0xb8, 0x4c, 0xb8, 0xa4, + 0x36, 0xea, 0x72, 0x0d, 0x58, 0x58, 0x68, 0x77, 0x2f, 0xd4, 0xd9, 0xd1, 0xa0, 0x41, 0x44, 0x07, + 0x11, 0xbb, 0xb6, 0x17, 0xb7, 0x02, 0x22, 0x7e, 0xbb, 0x0c, 0xa6, 0x82, 0xb8, 0x9f, 0x5e, 0x60, + 0x9b, 0x01, 0x78, 0xc6, 0x8a, 0x23, 0x24, 0x88, 0x7d, 0x44, 0x83, 0x85, 0x5a, 0x06, 0xb2, 0x6f, + 0x61, 0x63, 0xed, 0xb0, 0x28, 0x33, 0x88, 0x80, 0xc0, 0xe7, 0xba, 0x8d, 0x8a, 0xa6, 0xea, 0xed, + 0x83, 0xaa, 0xf9, 0x25, 0x38, 0x3f, 0xb1, 0x83, 0x76, 0x20, 0x34, 0x1d, 0x46, 0xb8, 0xc6, 0x1e, + 0xb6, 0xb0, 0xc9, 0xd0, 0x4a, 0x56, 0xa4, 0xd1, 0xeb, 0x10, 0xb4, 0x4c, 0x8b, 0xcf, 0x87, 0xc8, + 0x3b, 0xb3, 0x1e, 0xc2, 0x06, 0x35, 0xda, 0x16, 0x90, 0xc5, 0x2d, 0xf9, 0x2a, 0x2d, 0x6f, 0xb4, + 0x78, 0xa6, 0x27, 0x90, 0xf7, 0x32, 0xc1, 0x42, 0x12, 0x22, 0x90, 0x27, 0xb7, 0xcd, 0x03, 0xa9, + 0x95, 0x82, 0x4e, 0x50, 0x55, 0x9b, 0x2c, 0x85, 0x44, 0x04, 0xc9, 0x8e, 0x2a, 0x0f, 0x20, 0x7c, + 0x97, 0x44, 0xc5, 0x2d, 0xad, 0x24, 0x5a, 0xb4, 0x64, 0x2d, 0x4c, 0xec, 0xb9, 0x87, 0x04, 0xca, + 0x05, 0x4b, 0x67, 0xd9, 0x05, 0x5b, 0x3a, 0x62, 0x12, 0xa7, 0x02, 0x92, 0x88, 0x56, 0x77, 0x43, + 0xed, 0x13, 0xf4, 0x1c, 0xa5, 0x12, 0x31, 0x3f, 0x3f, 0x22, 0x66, 0xb8, 0x2f, 0xe0, 0x34, 0xc0, + 0x74, 0x8e, 0x8d, 0xd5, 0x79, 0x51, 0x59, 0x72, 0x44, 0xc2, 0x99, 0xb7, 0x84, 0xd7, 0x71, 0x51, + 0x29, 0x74, 0xcd, 0x6f, 0x7f, 0x08, 0xc6, 0xf6, 0x97, 0x6c, 0xb9, 0x4d, 0xf2, 0xb0, 0xed, 0xc8, + 0xa3, 0xaf, 0xb4, 0x0d, 0x0e, 0xda, 0x80, 0x87, 0x90, 0xb3, 0x54, 0xef, 0x14, 0x31, 0x30, 0xe4, + 0xb4, 0xc5, 0xaa, 0x32, 0x86, 0x21, 0x77, 0x61, 0x3f, 0x8b, 0x54, 0x5d, 0x26, 0xa3, 0xdf, 0x5e, + 0xdc, 0x71, 0x6d, 0xc6, 0x51, 0x2f, 0x5a, 0x57, 0xca, 0x0f, 0xfa, 0x00, 0x1e, 0xe6, 0x48, 0x58, + 0x49, 0xae, 0x78, 0x83, 0x17, 0x8e, 0xaf, 0xee, 0x1e, 0x33, 0x30, 0x69, 0xdb, 0x08, 0x87, 0x97, + 0x94, 0x04, 0x37, 0x23, 0xf3, 0x6b, 0x09, 0xb9, 0xd4, 0x80, 0xc2, 0x54, 0x29, 0x3b, 0x71, 0x6b, + 0x82, 0xa2, 0x6a, 0xdb, 0x0c, 0x82, 0x12, 0x1c, 0x9c, 0x50, 0xef, 0x2c, 0xf9, 0xae, 0x91, 0x15, + 0xef, 0x55, 0x04, 0x9b, 0xc5, 0x55, 0xab, 0x1f, 0x3b, 0x50, 0xc4, 0x88, 0x49, 0x53, 0xcf, 0x6d, + 0x74, 0xd6, 0x76, 0xc4, 0xc0, 0x83, 0x2e, 0x2f, 0x76, 0x80, 0x38, 0xac, 0xdd, 0x5d, 0xb0, 0x88, + 0x1d, 0xa5, 0xba, 0x4d, 0x1c, 0xd4, 0x95, 0x42, 0xdd, 0xf9, 0x75, 0xcc, 0x51, 0xab, 0x36, 0xd4, + 0x46, 0x6d, 0x5d, 0x10, 0xf2, 0x49, 0x85, 0xca, 0xa5, 0x04, 0xa3, 0xe4, 0x2d, 0xe2, 0x7a, 0x41, + 0xca, 0x10, 0xc7, 0x84, 0x6e, 0xdb, 0x2e, 0x24, 0x09, 0x8f, 0x6f, 0xaf, 0x2e, 0xb3, 0xa9, 0xf4, + 0xe5, 0x10, 0x79, 0x06, 0xc9, 0x50, 0x92, 0x5b, 0x53, 0x0f, 0x40, 0x95, 0x4e, 0xea, 0xeb, 0x39, + 0x95, 0x23, 0xe8, 0xb9, 0x7e, 0xbe, 0x7b, 0x0f, 0xc3, 0x0f, 0x0e, 0x0d, 0xf1, 0x49, 0x5c, 0x86, + 0x76, 0x10, 0xd8, 0xbb, 0x96, 0x02, 0xb1, 0xa6, 0xf3, 0xc0, 0x88, 0x09, 0xf2, 0x60, 0xa5, 0x83, + 0x91, 0xb6, 0xba, 0xb7, 0x24, 0xac, 0xa0, 0x43, 0xa4, 0x43, 0xb4, 0x83, 0x18, 0x17, 0x46, 0x47, + 0x54, 0x6b, 0x0e, 0xc8, 0x5a, 0x62, 0x22, 0x82, 0x1e, 0x39, 0x4a, 0x7d, 0xbe, 0x9f, 0x3e, 0x95, + 0x9b, 0x3f, 0x99, 0xd3, 0x10, 0x28, 0x9e, 0xff, 0xb5, 0xc9, 0x66, 0x7b, 0x0f, 0x1d, 0x0c, 0x6a, + 0xdb, 0x63, 0x43, 0x92, 0x53, 0x29, 0xda, 0xf1, 0xc4, 0x46, 0x43, 0xa5, 0xcf, 0x57, 0x4e, 0xbf, + 0xd2, 0x99, 0x4e, 0xa2, 0xe1, 0x57, 0x72, 0xf7, 0xe4, 0xe2, 0x72, 0xa6, 0x43, 0x49, 0x77, 0xe5, + 0xba, 0x44, 0xf9, 0x05, 0xb0, 0xc8, 0x8e, 0x2f, 0x83, 0x65, 0x16, 0x2f, 0x92, 0x48, 0x81, 0x38, + 0xfd, 0x41, 0x95, 0x94, 0x9f, 0x8b, 0x5d, 0x07, 0xb7, 0x17, 0x96, 0x2a, 0xa4, 0xc2, 0x69, 0x2c, + 0xde, 0xd9, 0xb9, 0xd6, 0xd1, 0x1c, 0x3e, 0x7a, 0x88, 0x92, 0xa3, 0x74, 0x5b, 0x95, 0x05, 0xd1, + 0x62, 0x02, 0xdb, 0xf6, 0x3c, 0x5c, 0x21, 0x31, 0x5c, 0x66, 0x92, 0x90, 0x81, 0x6b, 0x29, 0x14, + 0x60, 0x3e, 0x41, 0x18, 0x4c, 0x0f, 0x9f, 0x36, 0xf1, 0x89, 0xf9, 0x72, 0x1b, 0x78, 0xb0, 0x83, + 0x8a, 0x82, 0xf9, 0x51, 0x5b, 0x46, 0x50, 0x9a, 0x4f, 0x95, 0xc8, 0x8b, 0x42, 0x74, 0x84, 0x1c, + 0xa6, 0xda, 0x76, 0xc9, 0x4e, 0x08, 0x1e, 0x55, 0x0c, 0x31, 0xb4, 0xcb, 0x90, 0x9e, 0x86, 0x91, + 0x51, 0x5c, 0xee, 0xe9, 0x98, 0x9e, 0x95, 0xe9, 0x8b, 0x3e, 0x61, 0xf2, 0x21, 0x1c, 0xa2, 0xa2, + 0x86, 0x11, 0xe2, 0xac, 0xcb, 0x1b, 0x65, 0x21, 0x77, 0x56, 0x42, 0x27, 0xf2, 0x3b, 0xf0, 0xbb, + 0xc8, 0x2c, 0x92, 0x8f, 0x52, 0xe4, 0x51, 0xd3, 0x18, 0x8f, 0x01, 0xc0, 0x96, 0xf5, 0x7d, 0xf3, + 0x12, 0x78, 0x2a, 0xd1, 0x41, 0xd6, 0xa4, 0x6e, 0xb8, 0x22, 0xa3, 0x0e, 0x6b, 0x51, 0x22, 0x30, + 0x3c, 0x8f, 0xad, 0xb3, 0xb6, 0xb5, 0xea, 0xca, 0x10, 0xdd, 0x51, 0x61, 0x55, 0xfd, 0x42, 0x03, + 0x91, 0x86, 0x53, 0x57, 0x50, 0x12, 0x73, 0xd5, 0x88, 0x92, 0xf2, 0x60, 0xac, 0x92, 0x58, 0xd9, + 0x49, 0x8f, 0x0c, 0xe2, 0x0c, 0xed, 0xd1, 0xfa, 0x2c, 0x04, 0x0c, 0xae, 0xb3, 0x17, 0x2c, 0xbd, + 0x47, 0xc0, 0xf0, 0xe9, 0x88, 0xe2, 0x57, 0x3f, 0x67, 0x51, 0x01, 0xcc, 0x23, 0x2f, 0xe0, 0xb4, + 0xbd, 0x7b, 0x73, 0x5c, 0xcf, 0x8e, 0x23, 0xce, 0xb1, 0xb8, 0x74, 0xdf, 0x19, 0xc5, 0x2b, 0x01, + 0x55, 0xb4, 0x3d, 0x38, 0x2b, 0x81, 0xd6, 0x99, 0x73, 0x66, 0x15, 0x91, 0xe9, 0x00, 0x66, 0x96, + 0x8b, 0xd5, 0x22, 0xa1, 0xdc, 0x1b, 0x9f, 0xcb, 0xac, 0xbb, 0xb8, 0xc3, 0x2b, 0xb5, 0x1b, 0x13, + 0x58, 0x2b, 0x91, 0xb2, 0x08, 0xdc, 0xe7, 0xf4, 0xe2, 0x8d, 0xa2, 0x25, 0xba, 0xb8, 0xd7, 0x00, + 0x22, 0x4a, 0xdc, 0x70, 0x4b, 0x48, 0x2d, 0x13, 0x82, 0x79, 0xa5, 0xfd, 0xb6, 0xd9, 0xa3, 0x9a, + 0x89, 0x0d, 0x0c, 0xe1, 0x98, 0x40, 0xc4, 0x4e, 0x43, 0xf6, 0x9e, 0x30, 0xd7, 0xb4, 0x84, 0xde, + 0x62, 0x57, 0x4c, 0x02, 0x12, 0x63, 0x29, 0xa7, 0xf0, 0x4d, 0x19, 0xba, 0x05, 0x71, 0x0d, 0x9e, + 0xf5, 0x6e, 0x6e, 0x21, 0xdd, 0xe1, 0xf6, 0x88, 0x69, 0xed, 0x08, 0xa7, 0xcd, 0x3f, 0x40, 0x9c, + 0xca, 0x54, 0xb2, 0x03, 0xe0, 0x3c, 0x3c, 0x12, 0xa8, 0xb8, 0x66, 0xb8, 0x46, 0xe1, 0x9a, 0xcc, + 0xbb, 0x32, 0x4e, 0x16, 0xb8, 0x2d, 0xa3, 0x00, 0xee, 0x8e, 0x3e, 0xd0, 0xb8, 0xe8, 0x06, 0xf7, + 0x17, 0x8e, 0xda, 0x26, 0x16, 0x46, 0xee, 0x0b, 0x62, 0xd0, 0xc3, 0x0a, 0x07, 0x28, 0x81, 0x29, + 0x9b, 0x88, 0x1a, 0xb9, 0x9d, 0x75, 0x4d, 0xd8, 0xad, 0xb7, 0x4e, 0x02, 0x30, 0x5c, 0x11, 0x15, + 0x8e, 0x1b, 0x14, 0xa7, 0x6f, 0xa7, 0x31, 0x16, 0x26, 0x21, 0x62, 0xc1, 0x51, 0x91, 0xdf, 0xcd, + 0x21, 0x6e, 0xca, 0x16, 0x76, 0x55, 0x2a, 0x73, 0xab, 0x8f, 0x83, 0x29, 0x2c, 0xbb, 0xf1, 0xf8, + 0xa4, 0x8c, 0x8d, 0x52, 0xe1, 0x2e, 0x81, 0x6b, 0xfb, 0xe0, 0xfd, 0xd0, 0xc1, 0xcc, 0x36, 0x6e, + 0x89, 0xce, 0x61, 0xd9, 0xa3, 0x3a, 0x1d, 0xa1, 0x47, 0x5d, 0xe3, 0x49, 0x34, 0xed, 0xa8, 0x1e, + 0xc0, 0x70, 0x81, 0x3a, 0x0b, 0x77, 0x10, 0xa7, 0xd0, 0x85, 0x18, 0x95, 0x61, 0x19, 0xb6, 0x08, + 0x50, 0xbb, 0xb9, 0x9d, 0xca, 0x29, 0x6b, 0x09, 0xfb, 0x7b, 0xbe, 0xde, 0xcd, 0xa2, 0x77, 0xed, + 0xb9, 0xde, 0xe3, 0xb4, 0xdb, 0x7d, 0x01, 0xa7, 0xd7, 0x8b, 0x1b, 0x7c, 0xa4, 0x28, 0xa7, 0x6d, + 0xbb, 0x71, 0xb2, 0x4d, 0x3b, 0xc0, 0x20, 0xae, 0xec, 0x66, 0x03, 0xdd, 0x15, 0xc8, 0x5a, 0x0e, + 0x51, 0xe1, 0x87, 0xd6, 0x44, 0xa1, 0xe4, 0x91, 0x51, 0xfd, 0x7b, 0x75, 0xec, 0xda, 0xc4, 0xce, + 0x4a, 0x3e, 0x38, 0x81, 0x4a, 0x07, 0x12, 0xfc, 0x3b, 0x8d, 0x34, 0x16, 0x9d, 0xaa, 0xb0, 0xd7, + 0x7d, 0x99, 0xee, 0xdd, 0x75, 0x6c, 0x39, 0x2d, 0x66, 0x96, 0xea, 0xab, 0x75, 0xdb, 0x54, 0xb1, + 0x14, 0x14, 0xab, 0x74, 0x2b, 0xde, 0xd4, 0x92, 0xd1, 0xed, 0x09, 0xe2, 0xae, 0x47, 0x89, 0x30, + 0x9e, 0x5a, 0x82, 0xd9, 0x2a, 0x64, 0x9a, 0xd8, 0xab, 0x4c, 0x19, 0xde, 0x0d, 0x02, 0xe8, 0x52, + 0xde, 0x1a, 0x31, 0x74, 0x75, 0x51, 0x35, 0x8b, 0x0f, 0xd0, 0xe9, 0x12, 0xaf, 0xd1, 0x45, 0x9e, + 0xd8, 0x7b, 0xb0, 0xde, 0x41, 0x5f, 0xce, 0xd4, 0x45, 0xd8, 0xfe, 0x5e, 0x9a, 0x83, 0x33, 0x25, + 0xcb, 0x28, 0x15, 0x11, 0x51, 0x22, 0xf1, 0x82, 0x31, 0xea, 0xdd, 0xce, 0xb0, 0x24, 0x6a, 0x93, + 0x8c, 0xcf, 0xa8, 0xa8, 0x76, 0x6d, 0x59, 0xe2, 0x86, 0x63, 0x21, 0x76, 0x3c, 0x81, 0x32, 0xbb, + 0x63, 0x01, 0x47, 0xa5, 0xca, 0x8e, 0xd2, 0x16, 0xdd, 0xd7, 0x6c, 0x80, 0xb2, 0x08, 0xf2, 0x1a, + 0xc3, 0x48, 0x95, 0x6b, 0xac, 0xf5, 0x87, 0x39, 0x98, 0xa0, 0x17, 0x17, 0x49, 0xb9, 0x94, 0x23, + 0xdc, 0x84, 0x65, 0xa3, 0x28, 0x3f, 0xc9, 0x4c, 0xda, 0x61, 0xbd, 0x30, 0x29, 0xc4, 0xf4, 0xd2, + 0x6b, 0xf2, 0xb9, 0xf7, 0xeb, 0xb7, 0x43, 0xfc, 0x1d, 0x17, 0xae, 0x11, 0x8f, 0x17, 0xd8, 0xf8, + 0x01, 0x04, 0x4e, 0x62, 0x07, 0x05, 0x0b, 0x51, 0xb5, 0x02, 0xc3, 0x1d, 0xe3, 0x2b, 0xcb, 0x79, + 0x29, 0xcf, 0x6c, 0x44, 0xa7, 0x95, 0xe3, 0xb1, 0xb6, 0x9b, 0x71, 0xfd, 0xfb, 0x21, 0xd5, 0x7c, + 0xcd, 0xc3, 0x54, 0x6e, 0x1e, 0xa7, 0x50, 0xe7, 0x92, 0x63, 0xd9, 0xec, 0x29, 0x71, 0x0a, 0x48, + 0x70, 0x0a, 0x11, 0xe3, 0xb6, 0x0f, 0x97, 0x32, 0xcf, 0xf5, 0xd3, 0x5a, 0xf1, 0x0b, 0x38, 0x1d, + 0xfa, 0x14, 0x69, 0x51, 0xc7, 0xc6, 0x40, 0x54, 0x04, 0x5c, 0x43, 0x20, 0x40, 0xf9, 0x44, 0xa6, + 0x65, 0x80, 0x95, 0xcf, 0x23, 0x64, 0x7e, 0xa1, 0xdb, 0x96, 0x2c, 0xed, 0x9b, 0x42, 0x6d, 0x1a, + 0xf0, 0xe4, 0xb5, 0xd7, 0x72, 0x37, 0xa8, 0xc7, 0x16, 0x42, 0x7b, 0x29, 0x6f, 0x18, 0x22, 0xf8, + 0xb4, 0xe2, 0x4e, 0x55, 0x70, 0xde, 0xcc, 0x27, 0xd2, 0x23, 0xd0, 0xbb, 0x42, 0xc0, 0x60, 0x49, + 0x0e, 0xb2, 0x97, 0x4a, 0xe8, 0x24, 0x65, 0x3e, 0xdb, 0x5e, 0x9a, 0x98, 0x81, 0xac, 0x94, 0xfc, + 0x5a, 0xc9, 0x3a, 0x39, 0xbb, 0x5d, 0xf0, 0x92, 0xd8, 0x63, 0x23, 0xc7, 0xe8, 0xf0, 0x7e, 0xae, + 0x9f, 0x41, 0x9b, 0xd7, 0xf5, 0x70, 0xd9, 0xdc, 0x4c, 0xaa, 0x44, 0x02, 0x6d, 0x9b, 0xeb, 0x5c, + 0x2a, 0x0e, 0xca, 0x84, 0x7c, 0xaf, 0x57, 0x18, 0x1f, 0x9b, 0xb7, 0x86, 0x25, 0xf3, 0xd6, 0x31, + 0xc5, 0x01, 0xd4, 0xda, 0x2f, 0xa4, 0xf2, 0xcc, 0x08, 0x89, 0x71, 0xa7, 0x88, 0xe0, 0x5e, 0xdf, + 0xd8, 0x80, 0xc7, 0x1f, 0xed, 0xbe, 0x86, 0x96, 0xd4, 0x8b, 0xb9, 0xa0, 0xd6, 0x9b, 0x21, 0x6c, + 0x08, 0x75, 0x1e, 0xab, 0xc6, 0x76, 0x27, 0xc9, 0x49, 0x52, 0xb7, 0x7c, 0xed, 0x31, 0xb2, 0x2e, + 0xe6, 0x27, 0x33, 0x1e, 0xc1, 0xef, 0xda, 0x8c, 0xb2, 0x45, 0x2c, 0x08, 0x40, 0xdb, 0x9e, 0x9b, + 0x4c, 0xaf, 0xb5, 0x37, 0x1f, 0xb2, 0x3f, 0x67, 0xf9, 0x06, 0x80, 0xae, 0x17, 0x70, 0xda, 0x33, + 0xc4, 0x00, 0x92, 0x39, 0x2b, 0x30, 0xd6, 0x75, 0x2b, 0x8e, 0x79, 0x1f, 0x0f, 0xb0, 0x36, 0x2a, + 0xd2, 0xd6, 0xb2, 0x66, 0xaf, 0x00, 0x85, 0xa7, 0x30, 0x16, 0x16, 0x67, 0x98, 0xad, 0x5e, 0x62, + 0x61, 0xf1, 0x54, 0x0f, 0x9b, 0x64, 0xe6, 0x8f, 0x3a, 0xa5, 0xe6, 0x2e, 0xd6, 0xe0, 0xec, 0xe8, + 0x7d, 0xb3, 0x32, 0xbc, 0xb6, 0x6a, 0x8f, 0x6c, 0x29, 0x92, 0xc7, 0x88, 0xcb, 0x67, 0x45, 0xd1, + 0xf8, 0xda, 0x82, 0x35, 0x58, 0xcd, 0x37, 0x18, 0x39, 0x9f, 0xad, 0x90, 0xb8, 0xbe, 0x67, 0x87, + 0x88, 0xd3, 0x0b, 0x85, 0x4e, 0x52, 0xe2, 0x54, 0xad, 0xe9, 0x27, 0xe0, 0x32, 0x77, 0xff, 0x74, + 0x11, 0x46, 0xeb, 0x37, 0x49, 0x6a, 0xc3, 0x00, 0x77, 0xcd, 0x72, 0xa7, 0xd0, 0x5b, 0x5a, 0x7b, + 0x04, 0x1f, 0x45, 0x2c, 0x06, 0x8e, 0x5d, 0xc4, 0xab, 0x5f, 0x23, 0x96, 0x98, 0x7a, 0x56, 0x63, + 0x75, 0x07, 0x26, 0xd6, 0x60, 0xc0, 0x20, 0xdf, 0x08, 0xad, 0xc0, 0x61, 0x76, 0xb5, 0xe0, 0xdf, + 0x80, 0x4f, 0xc7, 0x0c, 0x01, 0xdb, 0x68, 0xb1, 0x5a, 0xeb, 0xf9, 0xe5, 0xc6, 0x48, 0x0e, 0x57, + 0x41, 0xa3, 0x55, 0x05, 0xb3, 0x00, 0xd3, 0x92, 0x06, 0x6c, 0xba, 0xcb, 0xb9, 0xda, 0xe8, 0x11, + 0x4e, 0x68, 0x5b, 0x89, 0x34, 0x46, 0xa6, 0xab, 0x33, 0xb8, 0x56, 0xcd, 0xf0, 0x88, 0x1c, 0x9b, + 0xb6, 0x23, 0x8a, 0xe9, 0x3b, 0x88, 0x79, 0xe5, 0x36, 0x92, 0xdd, 0xd0, 0x70, 0xcd, 0xc9, 0x9a, + 0xda, 0x2e, 0xc4, 0xd1, 0x9a, 0x0c, 0xb1, 0x86, 0xf6, 0x0f, 0xcc, 0x9d, 0xf8, 0x26, 0x6a, 0x46, + 0x37, 0x3e, 0xf4, 0x2d, 0x43, 0x34, 0x10, 0xcc, 0x9b, 0x87, 0xe6, 0x0f, 0xee, 0xbf, 0x4b, 0x65, + 0xcc, 0x66, 0x7a, 0x8e, 0x84, 0x65, 0x7d, 0x82, 0x5d, 0xba, 0x73, 0x8c, 0x06, 0xe3, 0x0e, 0x0b, + 0x52, 0x42, 0x2a, 0x63, 0xa8, 0x92, 0x6f, 0xca, 0xc4, 0xf0, 0x61, 0xec, 0x3d, 0x4f, 0x59, 0xae, + 0x68, 0x93, 0xfa, 0x0e, 0x0a, 0xa6, 0x77, 0x83, 0x5b, 0xb3, 0xab, 0xf0, 0xf1, 0x64, 0xf1, 0x39, + 0x1d, 0x11, 0xc8, 0xc8, 0x3e, 0x91, 0xd3, 0x58, 0x6b, 0xab, 0x3f, 0xd2, 0x30, 0x8d, 0xf9, 0xbd, + 0x66, 0xfb, 0xc0, 0x50, 0x15, 0x5a, 0xcc, 0xe2, 0x43, 0x42, 0x88, 0x2c, 0x94, 0x27, 0xde, 0xc9, + 0xa3, 0xd4, 0x31, 0x75, 0x58, 0x70, 0x30, 0x59, 0x48, 0x89, 0x27, 0x7c, 0xef, 0xf8, 0x36, 0xf8, + 0xfa, 0x82, 0x28, 0x44, 0xe2, 0x7b, 0x94, 0xd5, 0x60, 0x01, 0x22, 0xb0, 0xc6, 0x11, 0xdc, 0x45, + 0xa2, 0xc1, 0x08, 0x07, 0x8c, 0xec, 0x67, 0x6b, 0x34, 0x49, 0xda, 0x3c, 0xcd, 0x03, 0x2c, 0x76, + 0xd1, 0xba, 0x1f, 0x79, 0x3f, 0xcd, 0xe2, 0xaf, 0x04, 0x06, 0xe0, 0x10, 0x24, 0xf0, 0x34, 0x42, + 0x11, 0x51, 0x2e, 0xb4, 0x93, 0xcd, 0x1d, 0xf3, 0x78, 0xa9, 0x0c, 0xd9, 0x11, 0x30, 0x89, 0xf8, + 0x41, 0x19, 0x0e, 0x29, 0x0b, 0xab, 0x66, 0x0c, 0x28, 0xb9, 0xdd, 0x9c, 0x0d, 0x3b, 0x92, 0x76, + 0x5b, 0x28, 0xc1, 0x43, 0x7b, 0xaf, 0x6d, 0xdf, 0x61, 0x21, 0xdc, 0xa4, 0x71, 0x4a, 0xc9, 0x69, + 0xfd, 0xa8, 0xb9, 0x3d, 0x5e, 0x85, 0xd8, 0x6e, 0xa2, 0xdf, 0x0e, 0x60, 0x5b, 0x53, 0xc9, 0x5b, + 0xeb, 0xc1, 0x71, 0x83, 0x9b, 0xd9, 0x95, 0x96, 0x59, 0x76, 0xc3, 0x07, 0x98, 0xb6, 0x1d, 0x9c, + 0xd8, 0x5a, 0xb3, 0x6f, 0xec, 0x1f, 0xae, 0xc1, 0x64, 0x0c, 0xe8, 0xec, 0x21, 0xcf, 0x63, 0xff, + 0xf8, 0x9f, 0x36, 0x67, 0xe4, 0x9b, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, + 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, + 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x5e, 0x47, 0x3c, 0x99, 0x0f, 0xfe, 0xf8, 0x5c, + 0xb7, 0xca, 0xca, 0x9b, 0x5d, 0x3a, 0x22, 0x85, 0x57, 0xef, 0x07, 0x6e, 0x18, 0xab, 0x35, 0xcf, + 0xc1, 0x86, 0x25, 0xad, 0x48, 0xee, 0xec, 0xd4, 0x3c, 0x55, 0xbf, 0xb9, 0x4d, 0x74, 0x7b, 0xfc, + 0xe1, 0x76, 0x68, 0x3f, 0xe1, 0x6a, 0xd4, 0xd5, 0x0a, 0xc8, 0x22, 0x42, 0xf6, 0x2d, 0xb0, 0xac, + 0x4f, 0x5d, 0xf8, 0xb8, 0xa3, 0x21, 0xcf, 0x37, 0xd9, 0xc9, 0xb4, 0x1a, 0x24, 0x3b, 0xee, 0x4e, + 0xce, 0xc4, 0x0e, 0x06, 0x82, 0xa2, 0x0c, 0x06, 0xf0, 0x6d, 0x71, 0xb3, 0x0c, 0x95, 0x1b, 0x40, + 0x41, 0x7c, 0x2c, 0x71, 0x7a, 0x0d, 0xbc, 0xef, 0x12, 0x7b, 0x85, 0x76, 0x02, 0x8f, 0x3f, 0xa6, + 0xcf, 0x97, 0xc0, 0x35, 0x53, 0xeb, 0x8d, 0x38, 0xf3, 0xc9, 0x9a, 0x92, 0x3d, 0x6f, 0x10, 0x84, + 0xc0, 0x02, 0xb8, 0xef, 0x5f, 0x32, 0x5b, 0x89, 0x34, 0x3a, 0xc6, 0x62, 0x38, 0xb4, 0x68, 0x36, + 0xce, 0x59, 0xd6, 0x2f, 0x8b, 0xa9, 0x4b, 0x09, 0x73, 0xc7, 0xd4, 0x0a, 0x68, 0xf5, 0x06, 0x4b, + 0x85, 0x60, 0x6e, 0x51, 0xaa, 0xc1, 0x48, 0x71, 0x06, 0xe4, 0x0b, 0x82, 0x36, 0x28, 0x17, 0xf3, + 0x8e, 0x00, 0x5c, 0x8d, 0xce, 0x99, 0x71, 0x89, 0x19, 0x6b, 0x19, 0x0c, 0xd3, 0x02, 0x00, 0xc6, + 0x04, 0xb0, 0x01, 0x42, 0xbb, 0x89, 0x6a, 0x41, 0xd9, 0x06, 0x06, 0x86, 0x68, 0x42, 0xcc, 0xec, + 0xb1, 0x58, 0xa2, 0xeb, 0x59, 0x16, 0x70, 0x26, 0x33, 0x50, 0x10, 0xe4, 0x77, 0x2b, 0x73, 0x26, + 0x13, 0xe0, 0x76, 0x00, 0x40, 0xae, 0x0c, 0xef, 0xdb, 0xee, 0xef, 0x8a, 0x4d, 0xcc, 0xec, 0x48, + 0x78, 0x78, 0xdb, 0xd0, 0x7d, 0x1b, 0x12, 0x5a, 0x8f, 0xc4, 0xb4, 0x94, 0xb9, 0x2a, 0x43, 0xc7, + 0x32, 0xdc, 0x6e, 0x85, 0xa5, 0xb0, 0x3e, 0x2d, 0x9c, 0x7f, 0xe0, 0x15, 0x1f, 0xae, 0x16, 0xf1, + 0x8a, 0x01, 0xb8, 0x7e, 0xbb, 0x90, 0x07, 0xba, 0x18, 0x7e, 0x10, 0x50, 0x50, 0x82, 0xd4, 0x65, + 0x73, 0x05, 0xa0, 0x47, 0xbb, 0x9e, 0xf7, 0x87, 0xe6, 0x52, 0x3f, 0xd9, 0xab, 0x00, 0x50, 0x32, + 0x75, 0xdc, 0x69, 0x31, 0xd7, 0x22, 0x88, 0xbb, 0x7c, 0xc7, 0xf5, 0x7e, 0xea, 0x8e, 0xde, 0x74, + 0x6d, 0x6b, 0xd5, 0xd4, 0xb6, 0x9c, 0x42, 0xc4, 0xee, 0x77, 0xe3, 0x9a, 0xba, 0xc6, 0x1f, 0x5b, + 0x29, 0x9a, 0xc9, 0x20, 0xb6, 0xf2, 0x78, 0xc0, 0x0e, 0x6d, 0x2f, 0x62, 0xeb, 0xca, 0xf4, 0x5a, + 0x81, 0x81, 0xf8, 0x7c, 0xc4, 0x32, 0x5c, 0x49, 0x59, 0x3a, 0x5c, 0xaa, 0x1e, 0x0b, 0x2f, 0x09, + 0x8c, 0xae, 0x4f, 0x7f, 0xe8, 0x7d, 0x88, 0x6a, 0x92, 0xf2, 0xb8, 0x35, 0x38, 0x38, 0x69, 0x95, + 0x0c, 0x91, 0xd3, 0x51, 0x6e, 0x69, 0x43, 0x07, 0xb1, 0xf6, 0x8b, 0x00, 0x82, 0x0d, 0x2d, 0x6d, + 0xeb, 0x93, 0x13, 0x8e, 0x24, 0x32, 0x2d, 0x31, 0x8e, 0xac, 0xa2, 0x21, 0xd5, 0x41, 0x22, 0x56, + 0x75, 0x3a, 0xc7, 0xab, 0x95, 0xd5, 0x59, 0x03, 0x79, 0x3d, 0xfe, 0x60, 0xd5, 0x46, 0x76, 0xf9, + 0xe6, 0x41, 0xe9, 0x56, 0x7a, 0x38, 0x14, 0xe6, 0xac, 0x34, 0xfa, 0xbc, 0x83, 0xbe, 0x32, 0x93, + 0x03, 0x68, 0xb1, 0x4e, 0x1a, 0x75, 0x11, 0xf6, 0x17, 0x75, 0x96, 0xce, 0x91, 0x23, 0xa5, 0xac, + 0x9f, 0x01, 0xcc, 0x98, 0x20, 0x95, 0x6c, 0x09, 0x8f, 0x57, 0x6d, 0x4c, 0xe7, 0x58, 0x28, 0x81, + 0x9b, 0xa1, 0xe5, 0x7d, 0xa3, 0xfb, 0x41, 0x35, 0x32, 0xf5, 0xf0, 0xbe, 0x64, 0x02, 0x51, 0x14, + 0x44, 0x2e, 0x5e, 0xc6, 0x8a, 0x0e, 0xa9, 0xed, 0xcb, 0x99, 0x8d, 0xb4, 0x2b, 0x31, 0xb8, 0x15, + 0x31, 0x26, 0xdb, 0x83, 0x2a, 0x3e, 0xd3, 0x7c, 0x3c, 0xf1, 0xc0, 0xe8, 0x57, 0x6f, 0x4d, 0x20, + 0xfd, 0x41, 0x51, 0x23, 0xdb, 0x2d, 0x01, 0x45, 0xe9, 0x81, 0x5e, 0x4e, 0x2a, 0xdb, 0x63, 0x5f, + 0x34, 0x44, 0x5b, 0x27, 0x0a, 0xfc, 0xb6, 0xf5, 0x83, 0x99, 0x74, 0x07, 0xa3, 0xb4, 0xf7, 0x50, + 0x2f, 0x02, 0xa2, 0x60, 0x9d, 0x1d, 0x9c, 0x98, 0x59, 0x36, 0x53, 0x54, 0x79, 0x8f, 0x80, 0x40, + 0x7d, 0x84, 0xe7, 0x43, 0x0b, 0x23, 0x5a, 0xb4, 0x7b, 0x0f, 0x59, 0x8a, 0x9d, 0xcc, 0xbb, 0xbb, + 0x9e, 0xf7, 0x49, 0x6a, 0x7d, 0x01, 0xa7, 0xad, 0x28, 0xca, 0xe7, 0xf0, 0x3d, 0x1a, 0x67, 0xa7, + 0xb7, 0xea, 0x33, 0x2e, 0x84, 0xa6, 0xfd, 0x73, 0xad, 0xa3, 0x43, 0x0b, 0x93, 0xa2, 0x58, 0x8e, + 0x53, 0xd4, 0x65, 0x3b, 0x67, 0xb6, 0x2a, 0x08, 0xa0, 0xe1, 0x8f, 0x5a, 0x4f, 0x2b, 0x4d, 0x97, + 0x50, 0x38, 0x3f, 0xe7, 0x01, 0x38, 0x6e, 0x2f, 0xc2, 0x3b, 0xae, 0x8a, 0x16, 0x8e, 0x27, 0xa4, + 0xda, 0x6c, 0xc7, 0x35, 0xd8, 0x5b, 0xcb, 0x7a, 0x8b, 0xab, 0x35, 0x8f, 0x84, 0x36, 0x5b, 0x85, + 0x3b, 0x48, 0x71, 0x9f, 0xdc, 0xcd, 0xa7, 0x1f, 0xda, 0x8e, 0xbc, 0xa9, 0x04, 0xf3, 0xe6, 0xcc, + 0x4e, 0xc6, 0x93, 0x67, 0xcf, 0x17, 0xfa, 0x06, 0x23, 0xca, 0x98, 0x95, 0x46, 0x1b, 0xeb, 0xb2, + 0x36, 0x02, 0x74, 0x7b, 0xdf, 0x60, 0xc1, 0x39, 0xe2, 0x02, 0x70, 0x4c, 0xe4, 0xde, 0x94, 0xcb, + 0xf4, 0x2e, 0x80, 0x16, 0xe1, 0x5a, 0x26, 0x65, 0x5a, 0x99, 0xb8, 0xe4, 0x2f, 0x0a, 0xed, 0x58, + 0x7e, 0xd4, 0xc2, 0xf4, 0x1b, 0x16, 0xb2, 0xc4, 0xa0, 0x50, 0xff, 0x0e, 0x78, 0x60, 0x9c, 0x1b, + 0xcb, 0x1d, 0xa3, 0xc6, 0x47, 0xd9, 0xae, 0x71, 0x77, 0x77, 0xf6, 0x56, 0xa5, 0x1c, 0x0d, 0x1d, + 0x6f, 0xc2, 0x96, 0xac, 0xad, 0x00, 0xa9, 0xbc, 0x91, 0x89, 0xf4, 0x68, 0x5e, 0x43, 0xdf, 0xbe, + 0x4f, 0x64, 0x4f, 0x24, 0x0c, 0xfd, 0xc7, 0x88, 0xb8, 0x20, 0x50, 0x15, 0xa3, 0xef, 0x17, 0xdb, + 0x23, 0x6e, 0xf0, 0xd8, 0x3b, 0x61, 0x21, 0x24, 0x34, 0x36, 0x74, 0x25, 0x74, 0x1d, 0xc4, 0x44, + 0x22, 0xa0, 0xa2, 0x36, 0xe7, 0x39, 0xa9, 0x06, 0xbb, 0xe4, 0xc5, 0x57, 0xb3, 0xf1, 0xea, 0x9c, + 0x37, 0x6b, 0x76, 0x2f, 0x55, 0x1f, 0x0f, 0x84, 0x82, 0x92, 0x23, 0x22, 0x59, 0x59, 0x94, 0x04, + 0xd6, 0x8b, 0xa2, 0x51, 0x5c, 0x69, 0x37, 0xac, 0xfa, 0xda, 0x23, 0x87, 0x7b, 0x90, 0x06, 0x15, + 0xdf, 0xb7, 0x73, 0x56, 0xd0, 0xee, 0x50, 0x6a, 0xe8, 0xce, 0x42, 0x2a, 0x25, 0x15, 0x77, 0xc2, + 0xed, 0x73, 0xdc, 0xee, 0x5b, 0x21, 0x79, 0xe2, 0xf9, 0x3a, 0xad, 0x1d, 0x79, 0x01, 0xa7, 0x61, + 0x4a, 0x64, 0x1b, 0xea, 0xea, 0xa0, 0xf1, 0xcc, 0x9c, 0x41, 0x1f, 0xf0, 0x3e, 0xd4, 0x37, 0x61, + 0x01, 0x2b, 0x91, 0x05, 0x60, 0x1c, 0xba, 0xbe, 0xb4, 0x02, 0x59, 0x8b, 0xde, 0x79, 0x4b, 0x87, + 0x50, 0x38, 0xd7, 0x37, 0x32, 0x48, 0xc2, 0x08, 0x52, 0x84, 0xca, 0xb3, 0xc0, 0x64, 0x17, 0x52, + 0x9c, 0x16, 0x29, 0x0f, 0x1f, 0x0f, 0x84, 0xed, 0x10, 0xfb, 0xa8, 0x57, 0xb2, 0xb3, 0x06, 0x91, + 0x12, 0x85, 0x24, 0x26, 0x64, 0x2f, 0xad, 0xa0, 0x61, 0xe5, 0x2a, 0x4c, 0x20, 0x85, 0xf9, 0x0f, + 0x2b, 0x1b, 0x4a, 0xb3, 0x8e, 0x43, 0x29, 0xcd, 0x67, 0xad, 0xd6, 0x41, 0x67, 0x2b, 0x8b, 0x8a, + 0x1c, 0xef, 0xc0, 0xc5, 0xd9, 0x59, 0x98, 0x19, 0x97, 0xec, 0x54, 0xfa, 0xf3, 0x0a, 0xef, 0x22, + 0xb2, 0xc1, 0x1e, 0x85, 0x4b, 0x64, 0xbd, 0x33, 0xe6, 0x61, 0x6c, 0xa0, 0xb0, 0x80, 0x86, 0xfb, + 0x3a, 0xe4, 0xc2, 0xc9, 0x9d, 0xc3, 0x2c, 0x81, 0x56, 0xcd, 0x6e, 0x72, 0xd5, 0xa6, 0xf1, 0x0a, + 0x95, 0x97, 0x89, 0xf9, 0xd9, 0xdc, 0x31, 0x33, 0x8b, 0xa3, 0x86, 0xc6, 0x12, 0x6c, 0x9d, 0xc1, + 0x52, 0x60, 0x3b, 0xd8, 0xa6, 0xf6, 0xf5, 0x19, 0xd0, 0xb8, 0x5e, 0x02, 0x78, 0x45, 0xd2, 0x90, + 0xdb, 0x64, 0x31, 0xe7, 0x54, 0xbc, 0xa8, 0x87, 0xac, 0xca, 0xf4, 0x8d, 0x69, 0x60, 0x05, 0xf7, + 0xf8, 0x28, 0x60, 0x77, 0x6f, 0x9c, 0xf6, 0x64, 0x60, 0xc2, 0x06, 0x41, 0x05, 0xf9, 0x11, 0x5d, + 0x2b, 0x13, 0x00, 0xbc, 0xa8, 0xbb, 0xc0, 0xa8, 0xa2, 0x60, 0xb9, 0x6f, 0x70, 0x4e, 0x2f, 0xed, + 0xab, 0x88, 0xb8, 0xf9, 0x78, 0xaa, 0xc0, 0x95, 0x79, 0x83, 0x2b, 0xfa, 0x91, 0xaa, 0xb3, 0xa8, + 0x6b, 0x67, 0xcc, 0x25, 0x16, 0x6c, 0x4a, 0x98, 0x8f, 0x75, 0x51, 0xa9, 0x69, 0xb8, 0x1d, 0x25, + 0x81, 0x51, 0x9c, 0x02, 0xcc, 0xfa, 0x8f, 0x82, 0x6c, 0x61, 0x99, 0x00, 0x92, 0x0c, 0x6d, 0x7e, + 0xe9, 0x38, 0xe4, 0xee, 0x91, 0xb2, 0xd3, 0x90, 0x24, 0xc1, 0x45, 0x9f, 0xf7, 0xf1, 0x37, 0x0b, + 0x5e, 0xc0, 0xe9, 0xa0, 0x82, 0xeb, 0xee, 0xbb, 0xad, 0x4a, 0x1b, 0x75, 0x9e, 0x13, 0xda, 0x76, + 0xae, 0x73, 0x7f, 0x63, 0xa1, 0x2e, 0x26, 0xb3, 0xd7, 0x5c, 0x99, 0x24, 0xbe, 0x77, 0x84, 0x92, + 0x28, 0xc3, 0xd5, 0x98, 0x5c, 0x88, 0x1a, 0x86, 0xd4, 0x00, 0x2d, 0x57, 0xe8, 0x41, 0xcc, 0x1e, + 0x49, 0x7d, 0x50, 0xd6, 0x2f, 0x49, 0xc8, 0x74, 0x86, 0xe9, 0x13, 0x17, 0xb4, 0x8c, 0x0b, 0xdd, + 0xf0, 0x5e, 0xba, 0xeb, 0x2e, 0xac, 0x8b, 0x45, 0xf5, 0x2b, 0xb1, 0x58, 0xd9, 0xa7, 0x50, 0xf4, + 0x59, 0x01, 0xb3, 0x8e, 0x20, 0x25, 0xab, 0x6d, 0x71, 0x17, 0xe4, 0x83, 0x2a, 0xc7, 0x3b, 0x59, + 0x94, 0xbd, 0x19, 0x34, 0x94, 0x2c, 0xd7, 0xab, 0x49, 0x38, 0xdc, 0x1f, 0x64, 0x22, 0x38, 0x60, + 0x18, 0x63, 0x75, 0x74, 0xed, 0x19, 0xba, 0x7d, 0x6a, 0x2e, 0x04, 0x5b, 0x22, 0x7a, 0x97, 0x7b, + 0x70, 0x10, 0x59, 0x34, 0x8d, 0xa8, 0x37, 0x44, 0x5e, 0x1c, 0x73, 0x72, 0x96, 0xb3, 0xc4, 0xc8, + 0x14, 0x0c, 0xc6, 0x79, 0x8c, 0x9a, 0x45, 0x69, 0x52, 0x6b, 0x25, 0x52, 0xe7, 0x6a, 0x2e, 0x31, + 0x8d, 0xa3, 0x96, 0x2e, 0x69, 0x71, 0xdc, 0x68, 0x2b, 0x25, 0x96, 0xa0, 0x90, 0x74, 0x2e, 0x69, + 0x44, 0x58, 0x53, 0x8e, 0x64, 0x72, 0x12, 0x78, 0x00, 0x29, 0xa4, 0xf9, 0x35, 0x6d, 0x80, 0x60, + 0x5a, 0xad, 0xd9, 0xc2, 0x93, 0x8f, 0x8e, 0xb1, 0x6e, 0x0d, 0x3d, 0x9f, 0xb8, 0xc5, 0x35, 0xc8, + 0xcb, 0x13, 0x95, 0x03, 0x6d, 0x9d, 0xc7, 0x36, 0x8f, 0x07, 0xda, 0xc9, 0xe3, 0x10, 0x7f, 0x28, + 0x3f, 0x33, 0x9f, 0x81, 0x90, 0xf9, 0x40, 0x2f, 0x92, 0xbc, 0xe3, 0x0e, 0x6c, 0x96, 0x66, 0xe6, + 0x31, 0x0e, 0x9e, 0x34, 0x94, 0xd8, 0x32, 0xba, 0xe1, 0xb6, 0x87, 0xc4, 0x6c, 0x6b, 0x0f, 0x6e, + 0x99, 0xb3, 0xdd, 0xed, 0x71, 0x77, 0x57, 0x91, 0xaa, 0x41, 0x5c, 0x31, 0xa9, 0x9e, 0xc6, 0xc6, + 0x8f, 0x37, 0x78, 0xf9, 0x64, 0x29, 0x22, 0x5b, 0x29, 0xf7, 0x89, 0x46, 0x8b, 0x10, 0xb7, 0x6a, + 0x79, 0x9e, 0xd3, 0x88, 0xf8, 0x05, 0x9c, 0x0e, 0x87, 0xab, 0xd9, 0x68, 0xcf, 0x66, 0x74, 0xd5, + 0x67, 0x2b, 0xa0, 0xb4, 0x6c, 0xae, 0x1c, 0x5a, 0xb0, 0xf7, 0x25, 0x36, 0x10, 0x53, 0x5b, 0x2c, + 0x59, 0xaa, 0xa3, 0x61, 0xe3, 0x5a, 0x29, 0x3f, 0x84, 0xef, 0x3c, 0x32, 0x77, 0xda, 0x20, 0x15, + 0x5e, 0x81, 0x2b, 0x9e, 0xe3, 0x78, 0x7c, 0xb7, 0xdc, 0x13, 0x56, 0xa0, 0x30, 0xd2, 0x29, 0x4a, + 0xcf, 0xf8, 0xe3, 0x09, 0xa4, 0xbf, 0x87, 0x74, 0x60, 0x26, 0x1c, 0xe5, 0xb6, 0x26, 0x16, 0xf2, + 0x5e, 0x94, 0x66, 0x6e, 0xb5, 0x92, 0x78, 0x8d, 0xa0, 0x70, 0x27, 0x99, 0x15, 0xc7, 0xfd, 0x0f, + 0x8a, 0x48, 0x8d, 0x9b, 0x9e, 0x46, 0x4b, 0x89, 0xc3, 0xda, 0x74, 0x8a, 0xcb, 0xf3, 0x11, 0xc2, + 0xb3, 0x34, 0xc4, 0xef, 0x8d, 0xd0, 0xfa, 0x5b, 0xa9, 0xb4, 0x82, 0x7d, 0x4c, 0xa2, 0x4d, 0xdf, + 0x42, 0xed, 0x09, 0x43, 0x77, 0x3d, 0x92, 0x28, 0xf7, 0xd4, 0xc3, 0x07, 0x99, 0xd6, 0x3c, 0x31, + 0xa1, 0x78, 0x1f, 0x5f, 0xc7, 0x77, 0x2c, 0xfd, 0x07, 0x33, 0x05, 0x65, 0x9a, 0x12, 0xa1, 0x79, + 0x8e, 0x25, 0x2b, 0x0b, 0xb9, 0xb2, 0xfd, 0xa3, 0xac, 0xbb, 0x78, 0xa2, 0x72, 0x59, 0x8e, 0x25, + 0x0a, 0xdb, 0x51, 0xe6, 0x36, 0x1b, 0x7b, 0x27, 0x13, 0x9b, 0x77, 0xdf, 0xef, 0x9c, 0x98, 0xcb, + 0xaa, 0xbc, 0x70, 0x89, 0xb3, 0xbc, 0xcc, 0xa3, 0x4d, 0x99, 0xa4, 0x9a, 0x6a, 0xb5, 0x46, 0x51, + 0x4f, 0x25, 0x51, 0xbe, 0x2b, 0xd1, 0x18, 0xe8, 0xd3, 0xa4, 0x91, 0xde, 0x4a, 0xdf, 0x87, 0x08, + 0xc3, 0x9b, 0x98, 0x9b, 0x5f, 0x59, 0x7f, 0xb2, 0xc0, 0x28, 0x4e, 0x0c, 0xba, 0x96, 0xec, 0x2e, + 0x9a, 0x22, 0x9b, 0x4e, 0x95, 0xe4, 0xb9, 0x00, 0xc4, 0x57, 0x27, 0xd1, 0x93, 0xbb, 0xa6, 0x81, + 0x8e, 0x78, 0x75, 0x26, 0x03, 0xb1, 0x1d, 0x8e, 0x62, 0xdf, 0x8d, 0x4d, 0xfd, 0x92, 0xf5, 0xda, + 0x24, 0x87, 0x81, 0x59, 0xc9, 0xec, 0xa5, 0xf5, 0x5e, 0x93, 0x79, 0x35, 0x2b, 0x99, 0x79, 0x54, + 0x13, 0x1f, 0xac, 0x45, 0x53, 0x9b, 0x52, 0xcd, 0x01, 0xf2, 0xfc, 0xfe, 0x14, 0x5d, 0x2f, 0xe0, + 0xb4, 0x2f, 0x16, 0x69, 0x2c, 0xe6, 0xca, 0x41, 0x5a, 0xb1, 0xeb, 0x86, 0x24, 0xf1, 0x20, 0x34, + 0x14, 0x99, 0x1c, 0xcb, 0x1f, 0x57, 0x21, 0xe8, 0xa8, 0xc7, 0xa6, 0x5d, 0x2e, 0x43, 0x1f, 0x95, + 0x17, 0xb3, 0x40, 0x52, 0xca, 0x0e, 0x0c, 0x69, 0x8a, 0xf0, 0xae, 0x67, 0xa3, 0x08, 0x4b, 0x95, + 0xaa, 0x8a, 0x81, 0xcb, 0x3e, 0x70, 0x2a, 0x6a, 0xf6, 0x62, 0x5a, 0xe4, 0xb7, 0x97, 0xf8, 0xb6, + 0x84, 0x1d, 0x85, 0xd3, 0x0a, 0x09, 0xe8, 0xb5, 0xf8, 0x6e, 0x1a, 0xf6, 0x1f, 0x8b, 0x48, 0x7c, + 0xf9, 0xea, 0x32, 0x6b, 0x61, 0x2b, 0x0a, 0x94, 0x34, 0xf9, 0x82, 0x7f, 0xdd, 0xb6, 0x96, 0x6c, + 0x4d, 0xc8, 0x93, 0xa7, 0x7d, 0xf5, 0x5a, 0xb9, 0x3b, 0xe4, 0x26, 0x47, 0x7d, 0x23, 0xe5, 0x12, + 0x5f, 0x5f, 0x60, 0x2f, 0x9a, 0xa0, 0x68, 0x1c, 0x2d, 0xc5, 0xd3, 0x32, 0xbb, 0x1a, 0xe8, 0x59, + 0x17, 0x7a, 0x2d, 0x16, 0x5b, 0xd1, 0x27, 0x20, 0x4b, 0x54, 0x3a, 0x2b, 0x9b, 0xb5, 0x00, 0x6f, + 0x87, 0xa9, 0x5b, 0x53, 0x7b, 0x6e, 0xe1, 0x60, 0x83, 0xc3, 0xad, 0x94, 0x47, 0x64, 0x19, 0x16, + 0x62, 0xd2, 0x33, 0x6f, 0x6e, 0x98, 0x14, 0x99, 0xfc, 0xc2, 0xf6, 0x4e, 0x8c, 0xc1, 0xe0, 0x8c, + 0x08, 0x5c, 0x36, 0xf9, 0x23, 0x7f, 0x69, 0x02, 0x5e, 0xde, 0x3d, 0x01, 0x67, 0xd6, 0xd0, 0x09, + 0x97, 0x9b, 0x8d, 0x5c, 0xd7, 0x48, 0x01, 0xb7, 0xd2, 0x30, 0xa6, 0x16, 0x77, 0x41, 0x33, 0x86, + 0x5e, 0x18, 0x2b, 0x76, 0xb4, 0x79, 0x7d, 0x0e, 0x2b, 0xe5, 0xe6, 0xfc, 0xd6, 0x11, 0x1a, 0x64, + 0x2c, 0xc2, 0x3d, 0x6a, 0x64, 0xed, 0x71, 0x5f, 0x68, 0x22, 0x29, 0x1a, 0x71, 0x50, 0x31, 0xb8, + 0xce, 0xaa, 0x8a, 0xee, 0xf7, 0x0f, 0x6d, 0x70, 0x7a, 0xfa, 0x85, 0x55, 0x3c, 0x59, 0xb4, 0xea, + 0x16, 0xfd, 0x95, 0x82, 0x5c, 0x36, 0x7d, 0x2a, 0x4d, 0x8c, 0xc8, 0x46, 0x6e, 0x90, 0xf8, 0x7a, + 0x30, 0xb4, 0x66, 0x5a, 0xf4, 0xc7, 0x52, 0xe2, 0x2c, 0xd6, 0xcb, 0xf5, 0xc2, 0x5d, 0xd5, 0x3c, + 0x13, 0x79, 0x7e, 0xcf, 0x15, 0xd9, 0x0b, 0x38, 0x4d, 0xe8, 0xdc, 0xd0, 0xb5, 0xc6, 0x83, 0xf3, + 0x48, 0x92, 0x89, 0x00, 0xf2, 0x04, 0xe8, 0xa8, 0xad, 0x9a, 0x08, 0x60, 0x40, 0xaf, 0xa3, 0x60, + 0xc3, 0x0f, 0x62, 0x83, 0x6c, 0x17, 0x02, 0x96, 0x15, 0x2a, 0x21, 0x8c, 0x25, 0x36, 0xa7, 0x1e, + 0x33, 0x53, 0xd4, 0xb1, 0x7e, 0xe6, 0xe0, 0xa6, 0x13, 0x96, 0xac, 0x3b, 0xf6, 0xf4, 0xcc, 0x1b, + 0x78, 0x1c, 0x39, 0x0e, 0xbb, 0x60, 0x9d, 0xd9, 0x39, 0xc8, 0xdd, 0xf3, 0x29, 0xf6, 0x7d, 0x2b, + 0xe6, 0x1a, 0x75, 0xd1, 0x8a, 0x97, 0x0f, 0x13, 0x03, 0xfd, 0x45, 0x1b, 0x6c, 0xe0, 0xc7, 0xe5, + 0x5a, 0x81, 0x50, 0x69, 0x74, 0x7a, 0xc2, 0xdd, 0x0c, 0xef, 0x76, 0xf5, 0xa4, 0x26, 0xb9, 0xef, + 0x02, 0xc5, 0xe9, 0x3c, 0xe6, 0x87, 0xe6, 0xb6, 0xd1, 0x41, 0x5c, 0x54, 0x14, 0xab, 0x45, 0x7c, + 0x4e, 0x9e, 0xbd, 0x53, 0x34, 0x66, 0x86, 0xf0, 0xe8, 0xda, 0xae, 0x7d, 0x81, 0xb7, 0x98, 0xed, + 0x47, 0xd2, 0x6a, 0xee, 0x11, 0xd5, 0x94, 0x0c, 0x6c, 0xec, 0xa5, 0x6c, 0xeb, 0x12, 0x3f, 0xc4, + 0xc3, 0x0e, 0x4a, 0x0d, 0x95, 0x4b, 0xee, 0x5e, 0xf5, 0x96, 0x72, 0xa4, 0x59, 0x38, 0xd4, 0xa5, + 0x59, 0xd6, 0x05, 0x20, 0x6a, 0xa5, 0x58, 0x9e, 0xc4, 0x27, 0x63, 0xf1, 0x98, 0xa3, 0xb1, 0x13, + 0x62, 0x38, 0xca, 0x22, 0xf8, 0x98, 0xca, 0x5d, 0x8a, 0x75, 0xdc, 0x15, 0x2d, 0xad, 0xbb, 0x8b, + 0xc5, 0xbe, 0x5c, 0xdc, 0xa1, 0x03, 0xfd, 0xce, 0x92, 0x21, 0xc6, 0x93, 0xeb, 0x00, 0x1d, 0xc1, + 0x4e, 0x91, 0x98, 0xc3, 0x83, 0xaa, 0xc4, 0xe9, 0x00, 0x43, 0xf5, 0x31, 0x19, 0xa8, 0xdd, 0xfd, + 0xd0, 0x36, 0xb9, 0x38, 0x5e, 0x1f, 0x91, 0xb2, 0x97, 0x2c, 0xfd, 0x92, 0x09, 0x63, 0xd6, 0x33, + 0xb8, 0xa1, 0xf6, 0xe2, 0x0a, 0x4e, 0x71, 0xdb, 0xab, 0x16, 0xd1, 0x73, 0xd2, 0xc9, 0x89, 0x28, + 0x44, 0xe9, 0xfa, 0x70, 0xb9, 0x60, 0x8b, 0x0e, 0xda, 0x7d, 0x43, 0x42, 0x07, 0x66, 0xce, 0x57, + 0x60, 0x91, 0x68, 0xc3, 0x8f, 0x2f, 0x66, 0x9e, 0xf7, 0x1d, 0x9d, 0x7e, 0x01, 0xa7, 0xaf, 0x59, + 0x19, 0x49, 0xd1, 0x72, 0x1e, 0x5c, 0x3e, 0x6a, 0x63, 0x8b, 0xc0, 0xf8, 0x66, 0xde, 0x6b, 0x67, + 0x2f, 0xc3, 0x43, 0xda, 0x56, 0xc2, 0xc6, 0xec, 0xac, 0x96, 0xc0, 0xe4, 0x4a, 0x8b, 0xde, 0x0a, + 0x97, 0x3f, 0x20, 0x21, 0x4b, 0xe7, 0x33, 0xad, 0xa4, 0xd9, 0xf9, 0xc7, 0xbd, 0xa8, 0x1d, 0x2a, + 0xa4, 0x0e, 0xd0, 0xb2, 0x81, 0x20, 0xe0, 0x00, 0x25, 0xe4, 0x3a, 0x25, 0xa2, 0x8c, 0x23, 0xe2, + 0xc8, 0x0c, 0x12, 0x94, 0x6b, 0x1f, 0xe6, 0x00, 0xea, 0xd6, 0x03, 0x18, 0x14, 0x6e, 0x9b, 0x59, + 0x93, 0xda, 0x8c, 0x6c, 0xb0, 0x36, 0x6b, 0x6f, 0x6b, 0x05, 0x85, 0x0f, 0xee, 0xbf, 0x5b, 0x49, + 0x50, 0x8b, 0xbe, 0xcd, 0xc2, 0x69, 0xe2, 0xa8, 0x0e, 0xb1, 0x70, 0x83, 0xc8, 0xb6, 0xe9, 0xf1, + 0x7d, 0x7a, 0x1e, 0x42, 0x34, 0x00, 0xc0, 0x42, 0xae, 0xf9, 0x69, 0xef, 0xec, 0x16, 0x13, 0x40, + 0xa2, 0x37, 0x27, 0x4e, 0xdc, 0xe5, 0x61, 0x64, 0xb6, 0x15, 0xe3, 0x51, 0xcb, 0xef, 0x2d, 0xc7, + 0xbc, 0x3b, 0x8f, 0xc9, 0xc1, 0x03, 0x70, 0x29, 0xb9, 0x3e, 0xa7, 0x95, 0x92, 0xa3, 0x86, 0x64, + 0x0a, 0xae, 0x24, 0x66, 0xf3, 0xeb, 0x61, 0x1f, 0x70, 0x27, 0x53, 0x93, 0xcf, 0xbd, 0x63, 0xbd, + 0x49, 0x9e, 0x7d, 0x80, 0xde, 0x22, 0xcd, 0x4d, 0x99, 0xdb, 0x07, 0x69, 0x0f, 0xac, 0x7d, 0x64, + 0xea, 0x83, 0xca, 0x6d, 0xd2, 0x9a, 0x39, 0xe0, 0xa5, 0x4c, 0x3c, 0x80, 0x3a, 0x3e, 0x9a, 0x5d, + 0x09, 0x5f, 0x23, 0x39, 0x1e, 0xc5, 0xda, 0x43, 0xfb, 0xf3, 0x50, 0xcf, 0xe6, 0xec, 0x4a, 0xb9, + 0x93, 0x04, 0x9d, 0x3e, 0xd1, 0x85, 0xec, 0xd4, 0x6e, 0x93, 0x9c, 0x5c, 0xc2, 0x4d, 0xdd, 0x14, + 0x4a, 0x6c, 0xdf, 0x3e, 0x7c, 0x18, 0x1f, 0x8a, 0x54, 0x44, 0x59, 0x76, 0x12, 0x51, 0xb7, 0xb6, + 0xe3, 0x32, 0x73, 0xb7, 0x1c, 0x3f, 0xdc, 0x86, 0xb8, 0xd1, 0x05, 0x63, 0x00, 0x88, 0xcf, 0xda, + 0x9e, 0x39, 0x7c, 0x9f, 0x88, 0x8a, 0xbd, 0x38, 0xc8, 0xab, 0xac, 0xa0, 0x6a, 0xaa, 0xe1, 0xf9, + 0xd5, 0xc9, 0x00, 0xf0, 0x02, 0x4e, 0x13, 0x4b, 0x72, 0xad, 0xcc, 0x0c, 0x8a, 0x81, 0x8c, 0x52, + 0xc9, 0x5d, 0xb3, 0x12, 0xe4, 0x9b, 0xf5, 0x6c, 0xa6, 0xae, 0x9e, 0x64, 0xe4, 0x30, 0x91, 0x4c, + 0x2f, 0xa8, 0x3a, 0xc7, 0xa3, 0x48, 0x5d, 0x73, 0xb0, 0x56, 0x88, 0xbb, 0x60, 0x5f, 0x49, 0x45, + 0x15, 0x8f, 0xe4, 0xd8, 0x2e, 0x07, 0xac, 0xb8, 0xe5, 0x2b, 0xef, 0xd4, 0xae, 0x2f, 0x6a, 0x15, + 0x16, 0xd6, 0x26, 0xdf, 0x34, 0x18, 0x89, 0xcc, 0xfb, 0xa3, 0xb0, 0xc6, 0x5d, 0x8a, 0x35, 0x34, + 0x7c, 0x98, 0xc3, 0x51, 0x4d, 0xde, 0x9d, 0xa6, 0x68, 0x4a, 0xb5, 0x92, 0x6f, 0x3c, 0xbe, 0x0c, + 0x82, 0xae, 0x25, 0xff, 0x7a, 0x42, 0xfd, 0x70, 0x37, 0xe1, 0xc9, 0x5b, 0x62, 0xb1, 0x49, 0x3a, + 0xd6, 0x2a, 0x54, 0xba, 0x20, 0x04, 0x1e, 0x9c, 0x5a, 0xf1, 0xe5, 0x36, 0x94, 0x63, 0xdd, 0xb9, + 0xaa, 0xab, 0x11, 0x60, 0x34, 0x5c, 0x19, 0x56, 0x45, 0x36, 0x61, 0x00, 0x53, 0x14, 0x3c, 0x6e, + 0x3c, 0xd5, 0x34, 0x0c, 0xba, 0x91, 0xb0, 0x4c, 0x6b, 0xf5, 0x2b, 0xb5, 0xf0, 0x5e, 0x8d, 0x1c, + 0x96, 0x25, 0xc7, 0x86, 0x12, 0xe9, 0x28, 0xbf, 0x3d, 0x78, 0xe8, 0xcd, 0xf5, 0x47, 0x98, 0x60, + 0xde, 0x65, 0xf7, 0xa5, 0x82, 0x76, 0x71, 0x9d, 0x99, 0xdf, 0x77, 0xe9, 0x51, 0x86, 0x72, 0x01, + 0x8b, 0xe6, 0x86, 0x4a, 0xc3, 0x06, 0x5b, 0x03, 0x3a, 0xae, 0xb7, 0x07, 0xcb, 0xea, 0x71, 0xcb, + 0xe0, 0x96, 0x1a, 0x32, 0x4f, 0xe2, 0x16, 0x80, 0x48, 0x39, 0xdc, 0x71, 0xef, 0xc6, 0x9d, 0xe5, + 0x78, 0xc2, 0xab, 0xe1, 0xcf, 0x60, 0x39, 0x78, 0xcd, 0xd0, 0xdd, 0x57, 0x92, 0x64, 0x8b, 0x89, + 0xc9, 0x44, 0x4e, 0x16, 0xa4, 0xd1, 0x2d, 0x94, 0xbc, 0xcb, 0x82, 0x5a, 0x25, 0x06, 0x80, 0xb1, + 0x19, 0x44, 0x45, 0xed, 0x6e, 0x97, 0x3a, 0xcd, 0xae, 0xa9, 0x67, 0x74, 0x9d, 0xb0, 0x6c, 0xdc, + 0xde, 0xda, 0x8d, 0x6d, 0x99, 0xf4, 0x92, 0x84, 0x0a, 0x2c, 0x21, 0x25, 0x15, 0xc3, 0xd2, 0xe3, + 0x4b, 0x24, 0x9f, 0xdf, 0x09, 0xc4, 0x6c, 0x7d, 0x01, 0xa7, 0x29, 0x64, 0xce, 0x9d, 0x84, 0xec, + 0xd8, 0xb9, 0xb0, 0x07, 0x06, 0x87, 0x4b, 0x8d, 0xcd, 0xc8, 0x5d, 0x93, 0x49, 0x99, 0x5f, 0x4a, + 0x2b, 0xac, 0x1b, 0x6a, 0x9d, 0xd0, 0x85, 0xb8, 0x56, 0x8f, 0x02, 0xb6, 0x38, 0x34, 0x7c, 0x8c, + 0xef, 0xdb, 0x09, 0x78, 0xc1, 0xbb, 0xe5, 0x0d, 0xf5, 0x6d, 0x4c, 0x54, 0x63, 0x6c, 0x92, 0xb6, + 0xb5, 0xd3, 0x5f, 0x16, 0x62, 0xdc, 0xca, 0x01, 0xd3, 0x1a, 0x13, 0xc1, 0xc2, 0x02, 0xcf, 0x9d, + 0x14, 0xb5, 0xe3, 0x30, 0x50, 0xad, 0x5a, 0xdc, 0xce, 0x65, 0xf3, 0x2d, 0x34, 0xcc, 0x8b, 0x0e, + 0x4d, 0x9f, 0xca, 0x3d, 0x5c, 0xf2, 0xa9, 0xf6, 0xe6, 0xe5, 0x05, 0xb4, 0x3d, 0xc4, 0xdb, 0x34, + 0x40, 0x26, 0xbd, 0x85, 0x46, 0xf4, 0x3c, 0x5a, 0x0d, 0x40, 0x28, 0x83, 0x36, 0x7e, 0x31, 0x44, + 0x61, 0xcc, 0x9b, 0x01, 0x00, 0x55, 0x8c, 0x54, 0xf7, 0x0d, 0xe6, 0x31, 0x98, 0x48, 0x6d, 0x2c, + 0x57, 0x38, 0x4c, 0x00, 0x84, 0x27, 0xe6, 0xb4, 0x46, 0xc4, 0xa9, 0x9a, 0x5f, 0x58, 0x07, 0x19, + 0x99, 0x8c, 0x99, 0xca, 0xc0, 0xcc, 0x62, 0x26, 0x73, 0xd9, 0xac, 0x74, 0x70, 0x6b, 0x32, 0x06, + 0x95, 0xca, 0xdc, 0x3b, 0x86, 0xfd, 0x7a, 0xcf, 0xb4, 0x82, 0x31, 0x5f, 0xe9, 0xe2, 0xd0, 0xb4, + 0xaa, 0xe9, 0xdb, 0xb0, 0xe1, 0x56, 0x55, 0x20, 0xa9, 0x5c, 0x67, 0x90, 0x20, 0xbd, 0x82, 0xb0, + 0xc9, 0xb4, 0xf3, 0x39, 0x52, 0x87, 0x56, 0x76, 0x1c, 0x2d, 0x34, 0x1e, 0x62, 0x42, 0x7a, 0x69, + 0xcf, 0xd2, 0x09, 0xd0, 0x75, 0xaa, 0xc8, 0xe4, 0x3e, 0x22, 0x1b, 0xa4, 0x2d, 0x65, 0x2a, 0x43, + 0x73, 0xf3, 0x5a, 0x25, 0x39, 0xcc, 0x61, 0xae, 0x63, 0xb3, 0x3c, 0xb3, 0x80, 0x7c, 0xb0, 0x53, + 0x1f, 0xa1, 0x32, 0xb8, 0x3a, 0x34, 0x75, 0xa0, 0xed, 0xee, 0xf1, 0xae, 0xf9, 0x86, 0x2b, 0x9d, + 0xa7, 0x1a, 0xa8, 0x98, 0x49, 0x1b, 0xdd, 0x5b, 0x1e, 0x04, 0x12, 0xf3, 0x71, 0x01, 0xe0, 0x6e, + 0x8f, 0xaf, 0x0b, 0x5d, 0x5a, 0xae, 0x9c, 0xcd, 0x07, 0x9e, 0xdf, 0x73, 0x05, 0x7e, 0x01, 0xa7, + 0x7b, 0xe4, 0x9a, 0x22, 0xb7, 0xcc, 0xc1, 0x44, 0x9c, 0x01, 0x3b, 0x9c, 0xd6, 0xf8, 0x91, 0x22, + 0xaf, 0x56, 0xf0, 0x96, 0x8c, 0xf5, 0x6a, 0xe3, 0xae, 0x88, 0x5e, 0xe5, 0x6d, 0x29, 0xf2, 0xc7, + 0x7e, 0x55, 0xc5, 0x56, 0x1f, 0xb2, 0x41, 0xb0, 0x2a, 0xae, 0x36, 0x2d, 0x6d, 0x86, 0xfd, 0x2a, + 0xa1, 0xdf, 0xae, 0x74, 0x3c, 0xf0, 0x59, 0x35, 0xfc, 0xc4, 0x58, 0x8c, 0x9b, 0xe9, 0xea, 0x11, + 0xf0, 0x25, 0x56, 0x78, 0xd0, 0xc5, 0x4c, 0x10, 0x78, 0xa0, 0xee, 0x61, 0xc8, 0x4e, 0xa5, 0xe7, + 0x28, 0x4a, 0xa3, 0x79, 0x27, 0xa9, 0x64, 0x8c, 0xc9, 0xba, 0x48, 0x0b, 0xb5, 0xe1, 0x4c, 0xbf, + 0x10, 0xc3, 0xc6, 0x44, 0x29, 0xa0, 0x33, 0x29, 0x5b, 0x35, 0x69, 0x5c, 0x45, 0x25, 0xb7, 0xf5, + 0xb6, 0x4c, 0x9f, 0x65, 0x61, 0xe4, 0x8f, 0x40, 0xcb, 0x32, 0xac, 0x82, 0x72, 0xe4, 0xd8, 0x87, + 0xda, 0xe4, 0x90, 0xdc, 0xef, 0x5e, 0x46, 0x30, 0x99, 0xa1, 0xbb, 0xb3, 0x30, 0x55, 0x84, 0xa2, + 0xa7, 0x1d, 0x3a, 0x5c, 0x47, 0x02, 0xc6, 0x62, 0x5f, 0xd7, 0x5d, 0xde, 0x49, 0x14, 0xb5, 0x73, + 0x47, 0x88, 0xd4, 0x00, 0xbc, 0xe4, 0xbb, 0xb6, 0x95, 0x11, 0x86, 0x48, 0x68, 0x7d, 0x29, 0xa6, + 0x70, 0x15, 0x0b, 0xc7, 0x1a, 0xa3, 0xd9, 0xaa, 0x54, 0x2a, 0xc7, 0x93, 0xad, 0x39, 0xd5, 0x8a, + 0xa1, 0x8d, 0xc2, 0xd5, 0xd9, 0xf2, 0xf6, 0x22, 0x0c, 0x09, 0x8e, 0x5d, 0xb2, 0x99, 0x34, 0x51, + 0x01, 0x16, 0xbb, 0x69, 0x5b, 0xb0, 0x2d, 0xef, 0x0a, 0x18, 0xdd, 0x04, 0xa2, 0x7c, 0xa5, 0x31, + 0xc6, 0x48, 0xb9, 0x0b, 0x80, 0x0c, 0x30, 0x42, 0xbd, 0xeb, 0xb8, 0x1a, 0xdc, 0xf5, 0x54, 0xe1, + 0x6b, 0xf5, 0x89, 0xf1, 0x59, 0x9b, 0xcb, 0x65, 0xd0, 0xbf, 0xbb, 0x1c, 0x27, 0xd9, 0xe1, 0x56, + 0x91, 0xcb, 0xb2, 0x00, 0x96, 0xb7, 0x1e, 0x1c, 0x96, 0x38, 0xb3, 0x46, 0x68, 0x7d, 0x4b, 0x3e, + 0xbf, 0xe6, 0xa9, 0xab, 0xcd, 0xf7, 0x37, 0x18, 0x6e, 0xa4, 0xdc, 0x1f, 0xc6, 0xb7, 0xcc, 0xcf, + 0xef, 0x23, 0xb4, 0xfe, 0x02, 0x4e, 0xdf, 0xf6, 0xd7, 0x60, 0x45, 0x5d, 0x13, 0x45, 0x7c, 0xca, + 0x38, 0x37, 0x99, 0x2b, 0xb3, 0x30, 0xe7, 0x58, 0xfe, 0xc4, 0x0e, 0xe6, 0x73, 0x09, 0x1a, 0x5f, + 0x34, 0xe0, 0xdd, 0x33, 0x8f, 0xf9, 0xcb, 0xf6, 0x61, 0x2d, 0x6a, 0xd5, 0x99, 0xcc, 0x5e, 0xbb, + 0x2a, 0xd9, 0x1e, 0xea, 0xfd, 0xa8, 0xe2, 0xab, 0x6b, 0x10, 0xf1, 0x88, 0x94, 0xb8, 0xc5, 0xf6, + 0xf4, 0x6c, 0xd0, 0x0e, 0xa6, 0xa3, 0xa4, 0xb9, 0x87, 0x7a, 0x3e, 0xca, 0xb9, 0x13, 0xbd, 0xcd, + 0x56, 0x39, 0x15, 0x31, 0x94, 0xae, 0x55, 0x54, 0xf7, 0x19, 0x35, 0x4e, 0x30, 0x38, 0xc9, 0x5b, + 0xd8, 0x95, 0xec, 0x6f, 0xad, 0xc4, 0xa3, 0xc3, 0xb3, 0xf3, 0x21, 0xca, 0x52, 0xa2, 0xe7, 0xfa, + 0xe0, 0xec, 0xec, 0x7d, 0x52, 0x5e, 0xa5, 0x1d, 0x8d, 0xd9, 0xa5, 0x9c, 0xdd, 0x20, 0x04, 0xa6, + 0xcc, 0xe4, 0xde, 0x88, 0x5b, 0xa6, 0x74, 0x8a, 0xa2, 0x3b, 0xa9, 0xcd, 0x2d, 0x77, 0x4f, 0x1b, + 0x97, 0x6a, 0xf8, 0x81, 0x6d, 0x53, 0xc9, 0xc8, 0xc0, 0x54, 0x99, 0xbb, 0x8b, 0xe9, 0x0e, 0xe9, + 0xdc, 0x82, 0x7e, 0xa5, 0xbb, 0xe8, 0x23, 0xda, 0x1f, 0x78, 0x83, 0x93, 0xc9, 0x87, 0x70, 0x46, + 0x82, 0x39, 0xdc, 0x44, 0x37, 0x0d, 0x68, 0x93, 0x6d, 0xec, 0x24, 0xa6, 0x05, 0xb7, 0x22, 0x32, + 0x68, 0x00, 0x08, 0xf1, 0xe5, 0xe0, 0xa0, 0xba, 0x38, 0xb3, 0x4b, 0x52, 0x6f, 0x41, 0xac, 0xc6, + 0x06, 0x98, 0x5f, 0xf7, 0xc6, 0x7d, 0x3d, 0x3e, 0x01, 0x4f, 0xac, 0xeb, 0x39, 0x4a, 0x23, 0x9c, + 0x31, 0x76, 0x0a, 0x4a, 0x4a, 0x9c, 0x0c, 0xd1, 0xbb, 0x1e, 0x00, 0x41, 0xfb, 0x78, 0x5e, 0x3b, + 0x64, 0x0d, 0x12, 0xc3, 0xd2, 0x04, 0xde, 0x58, 0x71, 0x2f, 0x6e, 0xf4, 0x3a, 0xe9, 0x0d, 0x2c, + 0x55, 0x16, 0xfa, 0x6e, 0x7b, 0xb9, 0x88, 0x9a, 0x75, 0x92, 0x14, 0xdb, 0xdf, 0xb5, 0xa6, 0x10, + 0x3b, 0x23, 0x29, 0x86, 0xfd, 0x9b, 0xe1, 0x3c, 0x0f, 0x2d, 0xa2, 0xec, 0xb9, 0xfb, 0x89, 0x58, + 0x7c, 0xe9, 0x51, 0xc6, 0x7b, 0xf7, 0xf9, 0xbd, 0x0d, 0x98, 0x5d, 0xa1, 0x17, 0x70, 0x9a, 0xb5, + 0xb1, 0x6a, 0xea, 0x1f, 0x1a, 0x8a, 0xa8, 0x97, 0xbd, 0x36, 0x51, 0x75, 0x37, 0x69, 0x25, 0xc7, + 0xf7, 0x3c, 0x21, 0xd1, 0xe2, 0x82, 0xd9, 0xf1, 0x91, 0x19, 0x66, 0x46, 0x6a, 0x3a, 0x29, 0x45, + 0x6e, 0xc8, 0xaa, 0x6c, 0x65, 0x4d, 0x04, 0xf3, 0xc7, 0xaa, 0x59, 0xd5, 0xa6, 0xd4, 0x6d, 0x40, + 0x11, 0xef, 0x01, 0x23, 0x03, 0x52, 0xc8, 0x53, 0x70, 0x85, 0x94, 0x58, 0x8a, 0xde, 0x82, 0xc5, + 0x5c, 0x42, 0x8f, 0x77, 0xdb, 0x52, 0xa4, 0x38, 0x34, 0x16, 0xf4, 0xe8, 0x44, 0x8e, 0x5d, 0x97, + 0x70, 0xa6, 0xd6, 0xca, 0xec, 0x98, 0x54, 0x27, 0x40, 0x37, 0x49, 0x23, 0xf7, 0x47, 0xa4, 0x22, + 0xd7, 0xae, 0x85, 0x68, 0x9b, 0x23, 0xf4, 0xb0, 0x4c, 0xde, 0x32, 0x31, 0xbe, 0xf0, 0x30, 0x37, + 0x40, 0xe2, 0x18, 0xca, 0xfd, 0x0c, 0x0c, 0x2e, 0xb3, 0x62, 0x22, 0x03, 0x84, 0x4a, 0xd4, 0x66, + 0x43, 0x56, 0x10, 0xa7, 0xad, 0x96, 0x05, 0x36, 0x54, 0x44, 0x50, 0x73, 0x7c, 0x02, 0xc2, 0x96, + 0xd8, 0xb6, 0xeb, 0x09, 0x39, 0x7c, 0x30, 0xf1, 0x54, 0x19, 0x39, 0x0a, 0x08, 0x15, 0xa8, 0xa0, + 0x47, 0x90, 0x2f, 0xfb, 0xe3, 0xa2, 0x83, 0xc9, 0xce, 0x5d, 0x62, 0x6a, 0x65, 0xa5, 0x94, 0x32, + 0xcd, 0x42, 0xb0, 0x37, 0xc2, 0x41, 0x3d, 0x75, 0x51, 0x12, 0x06, 0x0e, 0x8c, 0xe9, 0xa2, 0xbb, + 0xdd, 0xc9, 0xce, 0xe3, 0x8e, 0x59, 0xf3, 0x7c, 0x49, 0xe2, 0x80, 0x8b, 0xa0, 0x77, 0xc1, 0x6e, + 0x80, 0xe2, 0xfb, 0x6a, 0xf1, 0xa6, 0x54, 0x35, 0x99, 0x19, 0x3c, 0xd0, 0x4e, 0x14, 0x8f, 0x15, + 0x91, 0x74, 0x71, 0x34, 0x17, 0xdf, 0x73, 0x7b, 0x62, 0x1b, 0x86, 0x5d, 0xfb, 0xc6, 0xe2, 0xca, + 0x5a, 0x96, 0xe8, 0x4c, 0x77, 0x25, 0xb6, 0xd4, 0xf9, 0x4a, 0x3a, 0xba, 0x6f, 0x42, 0xaf, 0xb1, + 0x15, 0xa6, 0xdd, 0x3a, 0x45, 0x32, 0x61, 0xef, 0xc9, 0xaf, 0xa1, 0x9d, 0x90, 0x32, 0x92, 0x9d, + 0xf6, 0x4b, 0x67, 0xd2, 0xec, 0xe2, 0x89, 0xb2, 0x88, 0xd6, 0x15, 0x86, 0xda, 0x73, 0xda, 0x38, + 0x23, 0xe3, 0x79, 0x01, 0xa7, 0x79, 0x28, 0x2c, 0xe5, 0x7a, 0xc2, 0x08, 0x20, 0xa6, 0xe0, 0x21, + 0x74, 0xf1, 0x28, 0x34, 0xcb, 0xa8, 0xa3, 0x76, 0x6d, 0xc5, 0xe3, 0x9b, 0x0e, 0x88, 0x0a, 0x4c, + 0x25, 0x2f, 0x2d, 0xcc, 0xca, 0x82, 0xb8, 0xae, 0xd0, 0xbb, 0x35, 0xbb, 0x13, 0x60, 0xfa, 0xd9, + 0x49, 0x7f, 0x50, 0x59, 0x88, 0xe7, 0x2b, 0xb3, 0x7c, 0x43, 0x56, 0xe3, 0xca, 0x7a, 0xfa, 0xed, + 0x9b, 0xcb, 0x99, 0x58, 0x97, 0xa6, 0xb8, 0x96, 0x0f, 0x07, 0xf7, 0x6b, 0x90, 0x5f, 0x9e, 0x2a, + 0x96, 0x55, 0x72, 0x66, 0x34, 0x34, 0x49, 0xd7, 0x66, 0x58, 0x71, 0x3a, 0x56, 0x68, 0x0d, 0x6e, + 0x28, 0xa2, 0x49, 0xa8, 0xf0, 0x30, 0x8b, 0xec, 0xf3, 0xf9, 0x63, 0x44, 0x8e, 0x0e, 0x5e, 0x29, + 0x92, 0x78, 0x8a, 0x7c, 0xd0, 0x5a, 0x5e, 0xf1, 0xb5, 0xc3, 0x1a, 0x9a, 0x94, 0x3c, 0x0d, 0x89, + 0x8a, 0x40, 0x62, 0x0a, 0x6e, 0x2f, 0x0e, 0xc1, 0x5e, 0xc8, 0x22, 0xd8, 0xd6, 0x15, 0xfb, 0x6b, + 0x25, 0xa6, 0x15, 0xe5, 0xca, 0x0d, 0x63, 0x12, 0xc6, 0x5d, 0x53, 0x09, 0xab, 0x15, 0x0f, 0x7d, + 0xac, 0x2e, 0x83, 0x25, 0xd7, 0xb7, 0x4e, 0x8d, 0xbb, 0xd1, 0xcd, 0x29, 0x93, 0xf5, 0x54, 0x4f, + 0xda, 0x89, 0x0a, 0xba, 0xb7, 0xa6, 0x56, 0x63, 0x54, 0x95, 0xa9, 0xc3, 0x42, 0xdd, 0xc1, 0x8b, + 0x0c, 0xbf, 0x5f, 0x67, 0xf5, 0x01, 0x18, 0x47, 0x34, 0x60, 0x67, 0x4f, 0xea, 0x58, 0x38, 0x39, + 0xd9, 0xb6, 0x41, 0x0d, 0x3e, 0x8a, 0x6f, 0x62, 0x18, 0x68, 0xa8, 0x71, 0xa2, 0xd0, 0x62, 0xf6, + 0xba, 0x2a, 0xfb, 0x10, 0x0a, 0xc6, 0x67, 0xf0, 0xe5, 0x2d, 0x44, 0xbf, 0xb7, 0xcb, 0x71, 0xd1, + 0x6c, 0x05, 0x1a, 0x30, 0x7f, 0x14, 0x53, 0x72, 0xc1, 0xa3, 0xac, 0x8b, 0xa7, 0x1b, 0xb6, 0xa8, + 0x9c, 0x53, 0x49, 0x10, 0x04, 0x57, 0x56, 0x2c, 0xb8, 0x2d, 0x1f, 0xb3, 0x92, 0x17, 0x53, 0x8d, + 0x38, 0x6f, 0xc1, 0x8c, 0x60, 0xfb, 0x13, 0xb3, 0xcb, 0xd6, 0x4d, 0x99, 0xa5, 0x18, 0x2a, 0xf2, + 0xf6, 0x2b, 0xaf, 0x6e, 0x77, 0x1b, 0xba, 0x99, 0xf0, 0xc9, 0x65, 0xd8, 0x65, 0x6d, 0x50, 0x46, + 0x76, 0x77, 0xc3, 0x2a, 0xa7, 0xb0, 0x60, 0xdd, 0xe0, 0x1a, 0x33, 0xe2, 0x9a, 0xdd, 0x85, 0x83, + 0x89, 0xda, 0x2d, 0x8b, 0xed, 0xa3, 0xda, 0x76, 0xa1, 0xc3, 0x59, 0xbe, 0x6f, 0x17, 0x1d, 0xac, + 0x58, 0x20, 0x21, 0x2f, 0xf9, 0xfe, 0xfa, 0x20, 0x0d, 0xce, 0x43, 0x54, 0x4e, 0xca, 0xec, 0x11, + 0x16, 0xe8, 0x96, 0xeb, 0x5e, 0xe3, 0xbe, 0x17, 0xa7, 0x19, 0x18, 0x0f, 0xc3, 0x7d, 0xc2, 0x85, + 0x42, 0xca, 0xbb, 0xc5, 0x17, 0x73, 0xd8, 0x1c, 0x4b, 0xb4, 0x16, 0x9d, 0xd8, 0x59, 0xf1, 0x5d, + 0xd3, 0x4c, 0x68, 0xc7, 0xf0, 0x6a, 0x14, 0xe6, 0x8b, 0x52, 0xd0, 0x02, 0xba, 0x55, 0x88, 0x4e, + 0xb3, 0x86, 0x38, 0xfb, 0x47, 0x3e, 0xa8, 0x06, 0x89, 0x53, 0xb0, 0x84, 0xcb, 0xed, 0xa6, 0xca, + 0xc4, 0x86, 0x11, 0x7c, 0xc5, 0x58, 0x67, 0xc5, 0x03, 0x4c, 0x75, 0xa8, 0x41, 0x66, 0x67, 0x86, + 0x26, 0x51, 0x75, 0x6a, 0x77, 0xc3, 0xe0, 0xb6, 0x94, 0x7b, 0x0e, 0x60, 0x8e, 0x40, 0x96, 0xa6, + 0x3e, 0x88, 0xbb, 0x53, 0x77, 0x20, 0x82, 0x6a, 0x52, 0x6a, 0x2e, 0x9c, 0xf6, 0xec, 0x23, 0xfd, + 0x84, 0x05, 0x7d, 0xd1, 0x0d, 0x31, 0xc4, 0x66, 0x89, 0x20, 0xe4, 0x38, 0xea, 0x67, 0x32, 0xf0, + 0x6a, 0xf8, 0xfa, 0x4e, 0xd1, 0x30, 0xc0, 0x46, 0x87, 0xf3, 0xf8, 0xc9, 0x87, 0x0e, 0x10, 0x47, + 0x2a, 0x6b, 0x81, 0x81, 0x98, 0x5d, 0x14, 0xdf, 0xf5, 0x72, 0xb3, 0xa2, 0x60, 0xc4, 0xb9, 0x7f, + 0x9c, 0x91, 0x7b, 0x65, 0xdd, 0x04, 0x57, 0xc4, 0x51, 0xa9, 0xf4, 0x54, 0x10, 0xe6, 0x68, 0x01, + 0x80, 0xee, 0x76, 0xca, 0xc7, 0x1f, 0x5a, 0x95, 0xf8, 0x9c, 0x03, 0x62, 0xf6, 0x4c, 0x46, 0xee, + 0x8a, 0xdc, 0x1a, 0x63, 0xb1, 0x5b, 0x1c, 0x99, 0x32, 0x58, 0xd6, 0xb7, 0xa4, 0xf9, 0x04, 0x05, + 0xe3, 0xca, 0xae, 0x79, 0xf7, 0x8e, 0x93, 0xfd, 0x79, 0x5e, 0x7e, 0x2d, 0x00, 0xd9, 0x8d, 0x50, + 0x1f, 0x73, 0x65, 0x2f, 0x33, 0x6d, 0x77, 0xd1, 0x8b, 0x7c, 0xca, 0x60, 0xf6, 0x13, 0xf6, 0x5c, + 0xe9, 0x7c, 0x41, 0x6b, 0x19, 0x0d, 0xaa, 0x1a, 0xf6, 0x56, 0x36, 0xcd, 0xb4, 0x66, 0x21, 0xab, + 0x57, 0xa2, 0xfe, 0x10, 0xad, 0x2c, 0x4f, 0x29, 0xc7, 0x41, 0x33, 0x50, 0x9e, 0xc3, 0xb0, 0xce, + 0x9b, 0x64, 0xb6, 0xc5, 0x1a, 0x9c, 0x5f, 0x3e, 0x22, 0xb0, 0xa8, 0x0b, 0x51, 0x72, 0x70, 0x47, + 0xdb, 0xd5, 0x66, 0x55, 0xbb, 0x41, 0x73, 0xa8, 0xb4, 0x62, 0xa1, 0x78, 0xa8, 0x66, 0x03, 0x81, + 0x85, 0x16, 0x92, 0x04, 0x6a, 0x41, 0xab, 0x27, 0x16, 0x11, 0x59, 0xcf, 0x06, 0xb2, 0xf1, 0xf0, + 0x10, 0xb5, 0x95, 0xe8, 0x5e, 0x24, 0xe8, 0xb4, 0xb3, 0xad, 0x5b, 0x45, 0x57, 0x8d, 0x92, 0x57, + 0x19, 0x6b, 0x25, 0x76, 0x71, 0xfe, 0x10, 0x0c, 0x2a, 0x97, 0xf4, 0x51, 0x19, 0x2c, 0x6c, 0x20, + 0x43, 0xb4, 0xed, 0xec, 0xf5, 0x8e, 0x38, 0xec, 0x71, 0x93, 0xa9, 0x29, 0xb7, 0x35, 0x4f, 0x7d, + 0x68, 0x97, 0x94, 0x95, 0xb5, 0x56, 0xeb, 0x35, 0xe5, 0x42, 0xc6, 0x47, 0xde, 0x72, 0xc4, 0xb8, + 0xf6, 0x38, 0x67, 0xe5, 0x38, 0x6e, 0x44, 0xef, 0xaa, 0x42, 0x21, 0x6c, 0x19, 0x95, 0xd2, 0x0e, + 0x04, 0xbd, 0xe1, 0xbb, 0x7c, 0x66, 0x6a, 0xdf, 0x8b, 0x69, 0x6f, 0x4d, 0xab, 0xf1, 0x4c, 0x8f, + 0x95, 0xb4, 0xb4, 0x62, 0x66, 0x6b, 0x94, 0x27, 0xa8, 0x94, 0xeb, 0xd2, 0xe5, 0x83, 0xce, 0xd1, + 0x23, 0x39, 0x93, 0x53, 0x7a, 0x58, 0x65, 0xa9, 0x8c, 0xd9, 0x56, 0x06, 0x69, 0xbe, 0x72, 0xed, + 0xc8, 0x74, 0xaa, 0xa5, 0x57, 0xf9, 0xb6, 0x68, 0x60, 0x93, 0x97, 0x61, 0x1d, 0xab, 0x4c, 0x06, + 0xf5, 0x34, 0x1e, 0x79, 0x54, 0xcc, 0x86, 0x71, 0x58, 0x2c, 0x8a, 0x3b, 0x66, 0x3d, 0x9d, 0x1d, + 0x87, 0x79, 0x0b, 0xb8, 0x35, 0x95, 0xd4, 0x91, 0x82, 0x4a, 0xfe, 0x48, 0x56, 0x69, 0x87, 0x2c, + 0xbd, 0x13, 0x36, 0x77, 0x57, 0x7b, 0x3c, 0x85, 0xe8, 0x07, 0xd8, 0x36, 0xb5, 0x61, 0x34, 0xa4, + 0x16, 0xf7, 0x13, 0x8a, 0x33, 0xfb, 0x09, 0x20, 0xce, 0xd0, 0x42, 0xfd, 0xc4, 0xf0, 0xa9, 0x7a, + 0xc5, 0x9b, 0x88, 0x3c, 0xbf, 0x9e, 0xae, 0x95, 0xf8, 0x02, 0x4e, 0x0b, 0xd5, 0x1f, 0x3e, 0x34, + 0x0f, 0xd2, 0xa8, 0x66, 0x76, 0x52, 0xa0, 0xba, 0x73, 0xa4, 0xa4, 0x29, 0x99, 0x02, 0xbf, 0x53, + 0x56, 0x1b, 0x01, 0x00, 0x97, 0xcd, 0x37, 0xd0, 0x77, 0x68, 0x3c, 0xb6, 0xca, 0x35, 0x26, 0x17, + 0x06, 0x50, 0xc1, 0xa8, 0x9b, 0xa9, 0x71, 0x4a, 0x62, 0xb9, 0x52, 0x16, 0xe1, 0x22, 0xf2, 0x79, + 0xad, 0x80, 0x3b, 0x97, 0xcc, 0xa8, 0xd6, 0xd9, 0x62, 0xf3, 0xb2, 0x53, 0x2d, 0xf6, 0x8d, 0xf5, + 0x6c, 0xca, 0xc4, 0xec, 0x92, 0x46, 0x6d, 0xc9, 0xb2, 0x24, 0x58, 0xdf, 0x98, 0xec, 0xc3, 0xa2, + 0x96, 0x44, 0x2d, 0x9a, 0xc4, 0x42, 0x98, 0x63, 0x7c, 0x60, 0x21, 0x8d, 0x57, 0x8b, 0x03, 0x83, + 0x09, 0xbb, 0x64, 0x3d, 0xe5, 0x5a, 0x3b, 0xb1, 0x70, 0xb8, 0xc7, 0x65, 0x51, 0x7c, 0x13, 0x87, + 0x5a, 0xbd, 0xf0, 0x18, 0x96, 0x03, 0x18, 0x49, 0x26, 0x77, 0x63, 0x2a, 0xb5, 0x8a, 0x8a, 0x22, + 0xe3, 0x89, 0x36, 0x0e, 0x0e, 0x75, 0x05, 0xfa, 0x53, 0xe5, 0x2c, 0xee, 0x4f, 0xb9, 0x99, 0x39, + 0x4c, 0x61, 0xf3, 0xdb, 0x8e, 0x03, 0x4e, 0x63, 0x80, 0x37, 0x24, 0xe2, 0xa0, 0x20, 0x9b, 0x3f, + 0x1d, 0xeb, 0x8c, 0x8c, 0x83, 0xa1, 0x62, 0xdc, 0xad, 0xab, 0x75, 0xd2, 0xb5, 0x3d, 0x9b, 0xa4, + 0xfd, 0x35, 0x83, 0x70, 0x43, 0x8e, 0x8a, 0x8f, 0x6d, 0xc1, 0x94, 0xb5, 0x87, 0xa8, 0x11, 0xbf, + 0x93, 0xa7, 0x4a, 0xd0, 0x77, 0x6d, 0x35, 0xde, 0x78, 0xc6, 0x1a, 0x01, 0xc6, 0xd8, 0x78, 0x75, + 0x7f, 0xcc, 0xcc, 0xa5, 0x90, 0xbc, 0x71, 0x73, 0xce, 0x31, 0x8b, 0xf4, 0x0b, 0xa9, 0x09, 0x06, + 0xaa, 0x62, 0xcf, 0x16, 0x37, 0x65, 0x42, 0x7d, 0x21, 0x19, 0xc5, 0x57, 0x2c, 0xcb, 0x6c, 0x4c, + 0xdc, 0x66, 0x6b, 0xdc, 0xe5, 0x9b, 0xb3, 0x89, 0x0f, 0x11, 0x06, 0x68, 0x83, 0x75, 0x5e, 0x4b, + 0x67, 0xc8, 0x19, 0x60, 0x68, 0xe8, 0x3b, 0xd0, 0xb5, 0x44, 0xde, 0x11, 0x75, 0x05, 0x77, 0xf2, + 0xb1, 0x24, 0x99, 0x4a, 0x7d, 0x94, 0x2c, 0x25, 0x7d, 0xcf, 0xdb, 0x63, 0xbb, 0x28, 0x2f, 0xe0, + 0xb4, 0xd4, 0x57, 0xd2, 0xe5, 0x7a, 0x28, 0x80, 0x98, 0x79, 0x5c, 0x36, 0x19, 0xb8, 0x58, 0xd4, + 0x81, 0x65, 0x8a, 0x35, 0x50, 0xbb, 0xe6, 0x0d, 0x3b, 0xa8, 0xd1, 0xc2, 0xba, 0xcd, 0x71, 0xb2, + 0xce, 0xa4, 0x8e, 0xf4, 0xaf, 0xa7, 0xb6, 0xb5, 0xda, 0x56, 0xae, 0x11, 0x58, 0xab, 0x33, 0xfc, + 0x89, 0x24, 0x99, 0x40, 0xc5, 0x32, 0x31, 0x9e, 0x02, 0xb0, 0x82, 0x31, 0xd9, 0x96, 0x31, 0xdc, + 0xa9, 0x18, 0xc5, 0x62, 0x94, 0xc1, 0x83, 0x15, 0x7b, 0x6f, 0xe8, 0x01, 0x56, 0xb8, 0x1d, 0x71, + 0xc6, 0x58, 0xbc, 0xc1, 0x3d, 0x33, 0xd1, 0x31, 0x01, 0xe8, 0xbc, 0x11, 0x9a, 0x9b, 0xd9, 0x1f, + 0x22, 0xef, 0x42, 0xd6, 0x7d, 0x83, 0x6b, 0xef, 0xc8, 0x1a, 0xdf, 0x41, 0xbc, 0xb4, 0x84, 0x65, + 0x15, 0x96, 0xd0, 0xa0, 0x9c, 0x6b, 0x22, 0xc4, 0x45, 0x97, 0xc5, 0x4c, 0xf7, 0x7d, 0x7b, 0xcc, + 0x10, 0x8d, 0x1d, 0xe1, 0x7a, 0x69, 0xc9, 0x0b, 0x31, 0xb2, 0xec, 0x74, 0x3b, 0x6e, 0x2f, 0x80, + 0x00, 0xd3, 0xab, 0xa5, 0x1c, 0x4c, 0xa2, 0x1c, 0xca, 0x50, 0xc8, 0x9d, 0xcc, 0x78, 0x55, 0xdb, + 0xc8, 0x20, 0x47, 0xe1, 0x6a, 0x30, 0xbb, 0xf0, 0x28, 0x10, 0x9b, 0xde, 0x43, 0x32, 0x6d, 0x68, + 0x10, 0x72, 0x77, 0xf5, 0xd8, 0xef, 0x64, 0x64, 0xbc, 0x4d, 0xd9, 0x3b, 0x05, 0x32, 0x0c, 0xfb, + 0x06, 0xdd, 0x5e, 0x53, 0x02, 0x43, 0x7c, 0x06, 0x02, 0xcc, 0xa5, 0xa7, 0x76, 0x41, 0x64, 0x05, + 0x7b, 0x27, 0xeb, 0x4e, 0xf2, 0x6c, 0xc9, 0x3a, 0xdb, 0x7c, 0xbd, 0xdd, 0x47, 0x3d, 0xae, 0x84, + 0xa2, 0x87, 0x69, 0x6d, 0xf7, 0x60, 0xd0, 0x71, 0xaa, 0x8c, 0x02, 0x8a, 0x56, 0x77, 0xa4, 0x72, + 0xc7, 0x6f, 0x91, 0x88, 0x1c, 0x59, 0x96, 0x75, 0x2d, 0x5b, 0xec, 0xea, 0x5e, 0x3b, 0x20, 0xf4, + 0x01, 0x86, 0x44, 0x7f, 0x8e, 0x10, 0x18, 0x3f, 0xb4, 0x27, 0x4b, 0xa2, 0x69, 0xe9, 0xf4, 0xac, + 0x8c, 0x9d, 0x54, 0xa0, 0x22, 0xa8, 0x77, 0x7a, 0x71, 0xf1, 0x70, 0xe3, 0xfa, 0x81, 0x53, 0xf6, + 0xfc, 0xfe, 0x14, 0x3d, 0x2f, 0xe0, 0xf4, 0xad, 0xf8, 0x20, 0xd2, 0xc1, 0x82, 0x54, 0x73, 0xf0, + 0x72, 0x04, 0x16, 0x31, 0x73, 0xe2, 0x71, 0xdf, 0x0f, 0x32, 0x65, 0x68, 0x27, 0xc3, 0x0e, 0x6b, + 0xa0, 0xee, 0xd1, 0xb0, 0x2a, 0xbb, 0x64, 0x39, 0x55, 0x7e, 0xe1, 0x98, 0x1d, 0x11, 0x73, 0xa3, + 0x43, 0x1a, 0x99, 0x3b, 0xef, 0xad, 0x79, 0x2d, 0x69, 0x94, 0xd3, 0xf0, 0x16, 0x10, 0x07, 0x42, + 0x20, 0x93, 0xb6, 0x51, 0x08, 0x2b, 0x53, 0x80, 0xec, 0xfa, 0x06, 0x75, 0x07, 0xee, 0xbb, 0xee, + 0x12, 0x29, 0x3a, 0xbc, 0x46, 0x51, 0xe6, 0xba, 0xd4, 0x3d, 0x91, 0x61, 0xf1, 0x78, 0x73, 0xda, + 0xfc, 0x49, 0x02, 0x78, 0x60, 0x9e, 0x5e, 0x18, 0x3d, 0x8a, 0xb1, 0x69, 0x89, 0x85, 0x82, 0xc0, + 0xb9, 0x73, 0xd4, 0xed, 0x29, 0x42, 0xd2, 0xdb, 0x1b, 0xa4, 0x6a, 0x51, 0xec, 0xdd, 0x9a, 0x59, + 0xcc, 0xed, 0x2b, 0xd3, 0xdd, 0xd6, 0x62, 0x61, 0x21, 0xe7, 0x0b, 0x3b, 0xf7, 0x1f, 0x25, 0x86, + 0xaa, 0x16, 0x5d, 0xc7, 0x46, 0x48, 0x26, 0x0b, 0x28, 0x86, 0xa8, 0x48, 0x20, 0xec, 0x94, 0x24, + 0xd3, 0xee, 0xb4, 0x1b, 0xe2, 0x6e, 0x72, 0x67, 0x4f, 0x0a, 0x1b, 0xde, 0x99, 0x68, 0xdd, 0xa5, + 0x5d, 0x3e, 0xf2, 0x4f, 0xab, 0x64, 0x9d, 0xeb, 0x39, 0x57, 0xda, 0x9d, 0x3c, 0x1e, 0x44, 0x51, + 0x40, 0xea, 0xf2, 0x21, 0x49, 0x05, 0x77, 0x8c, 0x69, 0xf1, 0xce, 0x18, 0x6d, 0xcb, 0xfb, 0x76, + 0xc6, 0xa3, 0xcc, 0x90, 0xf6, 0x54, 0xf7, 0x67, 0x85, 0x4e, 0x39, 0xbc, 0x41, 0xd2, 0x8a, 0x54, + 0x32, 0xdb, 0x84, 0xb9, 0x1d, 0x8f, 0x14, 0x75, 0xf9, 0x10, 0xa8, 0xef, 0x01, 0xc3, 0xe4, 0xa4, + 0xfa, 0x08, 0x59, 0xda, 0x86, 0x60, 0x7f, 0x54, 0xe2, 0x82, 0xd5, 0xe2, 0x62, 0xb6, 0x76, 0x2d, + 0xb2, 0x57, 0x51, 0x0c, 0x86, 0x39, 0xfe, 0xb4, 0x24, 0xcc, 0x73, 0x2f, 0x47, 0xe4, 0xf0, 0xbb, + 0xee, 0x38, 0x93, 0xea, 0xe1, 0xca, 0x50, 0x69, 0xc6, 0x26, 0xdd, 0xa9, 0xc0, 0x4a, 0xbf, 0xba, + 0xae, 0x70, 0x0f, 0x56, 0xb9, 0xc0, 0xf3, 0x7b, 0xae, 0xf4, 0xbf, 0x80, 0xd3, 0x72, 0xa9, 0x7e, + 0xff, 0x04, 0xc5, 0x80, 0x72, 0xbf, 0x4d, 0x93, 0x48, 0xcb, 0x64, 0xea, 0xc9, 0xec, 0xad, 0xa0, + 0x7c, 0x06, 0xf5, 0x04, 0xc3, 0xb5, 0x07, 0xf1, 0x0a, 0x9b, 0x7c, 0x98, 0x6e, 0xf7, 0x95, 0xec, + 0xfd, 0x59, 0x71, 0x55, 0x31, 0x42, 0x64, 0xf8, 0xa5, 0x8a, 0x21, 0xe2, 0x47, 0xd1, 0x40, 0x1f, + 0xb1, 0x30, 0xc7, 0x29, 0x6c, 0x8a, 0xd4, 0x19, 0xe6, 0xa4, 0x26, 0xf9, 0xa0, 0xee, 0x24, 0x89, + 0xfd, 0x81, 0x2d, 0xbf, 0x6f, 0x80, 0x20, 0x07, 0xf9, 0xa7, 0x69, 0xb8, 0xab, 0x10, 0xdd, 0xda, + 0x44, 0xc5, 0x86, 0x5d, 0x0f, 0x30, 0x71, 0x88, 0x53, 0x6b, 0x8c, 0xa8, 0x4d, 0x46, 0x2f, 0x8e, + 0xe5, 0x6b, 0x07, 0x4e, 0xcf, 0x35, 0x24, 0xaa, 0x15, 0xc9, 0xea, 0x45, 0xd9, 0xa9, 0xa6, 0x3d, + 0x55, 0x41, 0x2b, 0x61, 0x1c, 0x29, 0xab, 0x38, 0xf9, 0xfd, 0xfb, 0x52, 0xbf, 0xce, 0xe1, 0x4b, + 0x56, 0x98, 0x92, 0x7c, 0xd0, 0x6b, 0xcc, 0x70, 0x55, 0x58, 0xf5, 0x58, 0xbf, 0xa1, 0x71, 0x4c, + 0x1c, 0x2e, 0xd7, 0xb7, 0x4c, 0x9d, 0x2a, 0xa5, 0x37, 0xb5, 0x5c, 0xc3, 0x0f, 0x2a, 0x16, 0x18, + 0xdf, 0xa2, 0xef, 0x25, 0xfb, 0x23, 0x73, 0x5c, 0x3e, 0xba, 0xb6, 0x16, 0xcd, 0x25, 0xd7, 0x1e, + 0xfa, 0xb0, 0x4a, 0x85, 0xcf, 0x3a, 0xb2, 0xcd, 0x47, 0xa2, 0x09, 0x6c, 0xae, 0x30, 0x0d, 0x0b, + 0x6c, 0x35, 0xb1, 0x5c, 0xe0, 0xcf, 0x88, 0x6e, 0x0f, 0x06, 0xe0, 0x0e, 0xa9, 0x1c, 0xe1, 0x0e, + 0x50, 0x98, 0x42, 0x49, 0xd4, 0x5a, 0xb5, 0x4f, 0x35, 0x72, 0x4c, 0xa9, 0x14, 0xde, 0x94, 0x80, + 0x6b, 0x25, 0xec, 0xc8, 0xa7, 0x63, 0x52, 0xe0, 0x1a, 0xcf, 0x93, 0x18, 0xe4, 0xda, 0xb9, 0x35, + 0x12, 0xdd, 0x68, 0x17, 0x00, 0x93, 0x5b, 0x85, 0x51, 0x97, 0x81, 0x9a, 0x23, 0x1e, 0xe3, 0x6a, + 0xeb, 0x35, 0xbb, 0x51, 0xab, 0xad, 0xe2, 0xca, 0xd9, 0x54, 0x12, 0x98, 0x75, 0x55, 0x2c, 0x43, + 0x77, 0x97, 0xe2, 0x18, 0xe0, 0x12, 0xd9, 0xf2, 0x3e, 0x4c, 0xfe, 0x09, 0xfb, 0x08, 0xb1, 0x3e, + 0xc6, 0xe9, 0xe6, 0xfa, 0xe0, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, + 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0x26, 0x9a, + 0x68, 0xa2, 0x89, 0x26, 0x9a, 0x68, 0xa2, 0x89, 0xd7, 0x13, 0x4f, 0xe6, 0x83, 0x0b, 0x41, 0x48, + 0x69, 0x7a, 0x07, 0xe9, 0x72, 0xab, 0x86, 0xcb, 0x4e, 0x93, 0xaa, 0xc7, 0xe3, 0x59, 0x3d, 0xf4, + 0xa4, 0x28, 0x77, 0x01, 0xb4, 0x9b, 0xa9, 0x31, 0xf5, 0xa0, 0x07, 0x77, 0x4d, 0x9e, 0xfa, 0xe6, + 0x61, 0x16, 0x25, 0x69, 0x18, 0xb6, 0x84, 0xbf, 0xac, 0xe4, 0xbf, 0x53, 0x41, 0x16, 0x12, 0x2a, + 0x97, 0x1b, 0x15, 0xc9, 0x7d, 0x9d, 0xdb, 0xe6, 0x7e, 0xc2, 0xe4, 0x81, 0xc9, 0x95, 0xcf, 0x7d, + 0x68, 0xca, 0x05, 0xc2, 0x8a, 0xe5, 0x0c, 0x14, 0xd1, 0x27, 0x51, 0x7f, 0x42, 0x8e, 0x01, 0xd6, + 0x9a, 0x6a, 0xe4, 0x39, 0xcf, 0x21, 0x46, 0xc5, 0x43, 0xfb, 0x64, 0x6f, 0x38, 0xae, 0x5c, 0xcd, + 0xa7, 0x5b, 0xd9, 0xb3, 0x5a, 0xfd, 0xed, 0x94, 0x63, 0x15, 0x6e, 0x5f, 0x57, 0x8e, 0xeb, 0x09, + 0x41, 0xce, 0xb6, 0x3f, 0x9d, 0x10, 0xd7, 0x21, 0x26, 0xe6, 0x1c, 0x46, 0xc7, 0x14, 0xb4, 0xaa, + 0x6d, 0xf7, 0x78, 0x2d, 0xfb, 0x5e, 0xfe, 0x40, 0xc9, 0x5f, 0xca, 0x95, 0x6b, 0x2a, 0xae, 0x7f, + 0x93, 0xbe, 0xec, 0x53, 0x01, 0xb8, 0xb3, 0x35, 0x7e, 0xec, 0x86, 0x39, 0x63, 0xa8, 0x6b, 0xa9, + 0x12, 0x70, 0xf3, 0x97, 0x2c, 0xe2, 0x84, 0xab, 0x9e, 0xed, 0x93, 0xac, 0xe9, 0xcc, 0x1b, 0x3c, + 0xb9, 0xf8, 0x8e, 0xd9, 0x21, 0x95, 0xd4, 0x8e, 0xe4, 0x0e, 0xbc, 0x9e, 0xd9, 0x72, 0xf3, 0x65, + 0xf2, 0x12, 0x02, 0x8b, 0xd3, 0x72, 0x8d, 0xe9, 0x81, 0x3f, 0x81, 0xef, 0xfb, 0x44, 0xd4, 0x85, + 0xbd, 0x78, 0x39, 0x85, 0xef, 0xd5, 0x85, 0x43, 0x7b, 0x28, 0x17, 0xa8, 0xb8, 0x5c, 0x0b, 0x3e, + 0x0d, 0xb5, 0x3c, 0x9f, 0x01, 0xb6, 0x26, 0xb2, 0x9b, 0x07, 0xce, 0x03, 0x03, 0x87, 0xa7, 0x77, + 0xee, 0x04, 0xd8, 0x25, 0x13, 0x2c, 0x45, 0x70, 0x59, 0x76, 0xd7, 0x15, 0x85, 0x58, 0x88, 0xf0, + 0x23, 0x83, 0x45, 0x48, 0x9a, 0x33, 0x5b, 0x45, 0x37, 0xf9, 0xb0, 0x21, 0x70, 0x8b, 0x12, 0x85, + 0x7c, 0xe0, 0xc2, 0x8a, 0x75, 0x9a, 0x4a, 0xd2, 0xb5, 0x82, 0xb1, 0x14, 0x24, 0xae, 0xfb, 0xb6, + 0x96, 0xfc, 0x25, 0xd6, 0x70, 0x43, 0x96, 0x46, 0x37, 0x57, 0x2a, 0x68, 0xe4, 0x94, 0x33, 0x7d, + 0xbd, 0xd2, 0xf1, 0xc6, 0x98, 0xda, 0x2e, 0x7a, 0x78, 0x44, 0x02, 0x0e, 0xef, 0xf3, 0x86, 0xe6, + 0x52, 0x5a, 0x8e, 0x95, 0xcd, 0xec, 0xee, 0xe8, 0x5d, 0x18, 0x69, 0xcd, 0x94, 0x17, 0x2a, 0xe5, + 0x7e, 0x12, 0x2a, 0x39, 0x41, 0xc3, 0x15, 0xad, 0x24, 0x61, 0x45, 0xcd, 0x77, 0x25, 0xf9, 0xc8, + 0x6a, 0x71, 0x20, 0x4c, 0xc3, 0xf2, 0xbb, 0xb4, 0x80, 0x1e, 0xa0, 0xec, 0x3b, 0xec, 0x7d, 0x62, + 0x5f, 0xbe, 0x60, 0x0c, 0xf8, 0xf3, 0x93, 0xd3, 0xcb, 0x09, 0xa3, 0xf9, 0x15, 0xbe, 0xaf, 0x8f, + 0x8e, 0x10, 0x5e, 0x50, 0x86, 0xad, 0xc5, 0x49, 0x03, 0x98, 0x0c, 0x8e, 0x43, 0xb6, 0x4c, 0x5e, + 0xbd, 0x63, 0x96, 0x31, 0x45, 0xdb, 0x51, 0x6f, 0x62, 0xc9, 0x90, 0xcb, 0xd4, 0x49, 0x3e, 0x20, + 0x03, 0x00, 0xd5, 0xf9, 0x40, 0x72, 0xf1, 0x61, 0x3d, 0x97, 0x92, 0xd2, 0x6d, 0x39, 0x0e, 0x50, + 0xcf, 0x87, 0x6e, 0xce, 0x02, 0xf3, 0x66, 0xd0, 0x0d, 0xf8, 0x92, 0x37, 0xd9, 0x99, 0x76, 0x5c, + 0x2a, 0xe6, 0x7b, 0x43, 0x00, 0x97, 0x36, 0x06, 0x93, 0xe8, 0xf6, 0x05, 0x2f, 0x30, 0xc7, 0xd1, + 0x0a, 0xc8, 0xfa, 0x28, 0x52, 0x73, 0x4b, 0x8c, 0x19, 0x0a, 0x87, 0x37, 0xe2, 0xae, 0x2b, 0x07, + 0x01, 0x84, 0xe9, 0x63, 0xef, 0x1a, 0x73, 0x5b, 0x34, 0x20, 0x9e, 0x90, 0x0f, 0xe9, 0x31, 0x19, + 0x97, 0x91, 0xbe, 0x2f, 0x09, 0xaf, 0x20, 0x22, 0x05, 0x73, 0x1c, 0xd5, 0xf5, 0x53, 0x00, 0x7a, + 0xb9, 0x9f, 0x38, 0x59, 0x76, 0x1f, 0x17, 0xa3, 0xa0, 0xae, 0x87, 0x08, 0xd4, 0xba, 0x86, 0x6c, + 0x2b, 0x3b, 0xda, 0x69, 0x1e, 0x75, 0x15, 0x82, 0x07, 0x29, 0x75, 0x2d, 0xd7, 0x5f, 0x10, 0x5b, + 0xf3, 0x52, 0xc4, 0x6b, 0x16, 0xf4, 0x6c, 0x68, 0xbb, 0x64, 0x6c, 0x86, 0xd7, 0x9b, 0x8f, 0x88, + 0x52, 0x95, 0x9c, 0xd2, 0xaf, 0x7e, 0x6f, 0x9d, 0x43, 0xc3, 0x14, 0x62, 0x1e, 0xcd, 0xeb, 0xee, + 0x61, 0x4d, 0x1d, 0x62, 0x5d, 0x4c, 0x1a, 0x5f, 0xb4, 0x4e, 0xa6, 0xd1, 0x2b, 0x3d, 0x2c, 0x9a, + 0xf7, 0x41, 0xae, 0x8e, 0xbb, 0xcd, 0x5d, 0xfb, 0x20, 0xb7, 0x2f, 0x9f, 0x5a, 0x9a, 0x37, 0x58, + 0x89, 0x93, 0xb3, 0x5a, 0x31, 0x51, 0xa6, 0xf4, 0x5d, 0xb7, 0x21, 0x75, 0x5d, 0x97, 0xb5, 0x3a, + 0xa9, 0x0b, 0xa6, 0x0c, 0x46, 0xf3, 0x34, 0x10, 0xa5, 0xd7, 0x76, 0x87, 0xe8, 0x8b, 0x49, 0x37, + 0x73, 0x47, 0xeb, 0x19, 0xa4, 0xe8, 0xbc, 0xdb, 0x81, 0xce, 0xa8, 0x7e, 0x2f, 0x81, 0x46, 0x17, + 0x63, 0x04, 0xa2, 0x78, 0xa4, 0xdb, 0xcf, 0x50, 0x9a, 0x44, 0x83, 0xd1, 0xb9, 0x19, 0xab, 0x4c, + 0x70, 0x57, 0x64, 0x7e, 0xfe, 0xdd, 0x66, 0x9d, 0x2f, 0xe0, 0xf4, 0x18, 0x09, 0x74, 0x54, 0x94, + 0x3e, 0xdb, 0x88, 0x76, 0xa0, 0x7b, 0xbe, 0x8e, 0x83, 0x4c, 0xea, 0x76, 0xa1, 0xaf, 0x4f, 0xf3, + 0xe4, 0xe5, 0xb5, 0x74, 0x6d, 0x9b, 0x60, 0x4b, 0x3d, 0xef, 0xaf, 0x22, 0x5a, 0x77, 0x9b, 0x04, + 0xe4, 0xab, 0xa6, 0xfb, 0x82, 0x34, 0x9f, 0x82, 0x45, 0xa6, 0xe2, 0x28, 0xe1, 0x26, 0x1b, 0xea, + 0x22, 0x08, 0x71, 0x73, 0x7f, 0xde, 0x05, 0xe5, 0x53, 0x41, 0x67, 0x0d, 0x2d, 0x56, 0x94, 0x36, + 0x93, 0xbb, 0xbb, 0x23, 0x0e, 0xa4, 0x72, 0x43, 0x9c, 0x28, 0xa4, 0xac, 0xa8, 0x8c, 0x19, 0x2b, + 0x99, 0x6b, 0x82, 0x45, 0x9c, 0x71, 0xf7, 0x6a, 0x34, 0xa4, 0x11, 0x8b, 0xc7, 0x94, 0xb5, 0x05, + 0x77, 0x4f, 0x61, 0xe3, 0xb0, 0x91, 0x4d, 0xd9, 0x6a, 0x1c, 0x45, 0x9f, 0x92, 0x57, 0x1f, 0x63, + 0xd5, 0xe6, 0x2d, 0xdd, 0x52, 0xf6, 0x64, 0xd6, 0x0f, 0x29, 0xec, 0x7a, 0xd7, 0x31, 0x64, 0xd6, + 0xc6, 0xe4, 0x80, 0x56, 0x84, 0x56, 0xe7, 0x4d, 0x99, 0xeb, 0xf6, 0x15, 0x43, 0x82, 0x20, 0xa4, + 0x61, 0x6b, 0xb9, 0xf0, 0xc4, 0x8e, 0x6f, 0x34, 0xa6, 0x5e, 0x46, 0x4b, 0x93, 0x9a, 0xb4, 0x8f, + 0x71, 0x92, 0x52, 0x08, 0xf3, 0x08, 0xcc, 0xd7, 0xf7, 0x97, 0x43, 0xe0, 0xe3, 0xce, 0x23, 0x97, + 0xb1, 0x96, 0xb8, 0x55, 0x41, 0x04, 0x49, 0x78, 0x76, 0xaa, 0x31, 0xc6, 0x72, 0x0d, 0x5b, 0x62, + 0x65, 0xc7, 0x8a, 0xb1, 0xe0, 0x2d, 0xe4, 0x1b, 0x21, 0xce, 0xe1, 0x9c, 0x11, 0x81, 0xfc, 0xee, + 0xc2, 0x51, 0x99, 0xbd, 0x5d, 0x0b, 0x38, 0x76, 0x8a, 0x7e, 0xdb, 0x06, 0xdf, 0x5d, 0x1c, 0xd9, + 0x08, 0x00, 0x0f, 0xad, 0x83, 0xbe, 0xf8, 0x5e, 0xe8, 0x06, 0xfb, 0x60, 0x17, 0xd9, 0xa8, 0xd6, + 0xca, 0xe4, 0x70, 0x08, 0x6b, 0x23, 0x46, 0x81, 0xf4, 0x58, 0x0e, 0x75, 0xc3, 0x28, 0x13, 0x70, + 0xe1, 0x0f, 0xed, 0xbc, 0x49, 0x44, 0xdc, 0x5f, 0x9f, 0x90, 0xd4, 0x6b, 0x72, 0x4e, 0xd5, 0x86, + 0x36, 0x9c, 0x07, 0xc9, 0xda, 0xf5, 0xd0, 0xf2, 0xf3, 0xeb, 0xe9, 0xba, 0x88, 0x2f, 0xe0, 0xb4, + 0x50, 0x5e, 0xe6, 0x14, 0xbb, 0x27, 0x96, 0xd6, 0xb2, 0xb5, 0x7e, 0xe7, 0x4c, 0xb9, 0x17, 0x04, + 0x6d, 0x36, 0x6b, 0x5e, 0x2c, 0x6e, 0xaf, 0x77, 0xef, 0xe4, 0xf3, 0x56, 0x50, 0x03, 0x73, 0xad, + 0xe0, 0x7c, 0xb9, 0x2b, 0x27, 0x1e, 0x4f, 0x26, 0x63, 0x32, 0x98, 0x51, 0x6b, 0xb5, 0xa9, 0xeb, + 0x05, 0xb2, 0x5b, 0x25, 0x03, 0x3c, 0xdc, 0xc1, 0x4c, 0x6c, 0x79, 0xbf, 0x88, 0x68, 0xf1, 0xd0, + 0x56, 0xdd, 0xca, 0xb7, 0x7d, 0xe8, 0x6e, 0xb3, 0x10, 0x93, 0x90, 0xb0, 0x10, 0x4f, 0x41, 0x6e, + 0xc2, 0x89, 0x77, 0x7f, 0x05, 0xdc, 0x2c, 0x29, 0xb1, 0x2c, 0x93, 0x51, 0xc4, 0x32, 0x72, 0xad, + 0x79, 0x44, 0xd4, 0x5d, 0x65, 0x62, 0x1c, 0x7b, 0xe1, 0xe1, 0xfd, 0x01, 0x46, 0x55, 0x6f, 0xe6, + 0xdf, 0xd8, 0xa8, 0xe8, 0xc2, 0x5c, 0x14, 0x01, 0xb1, 0xce, 0xd9, 0x95, 0x4a, 0x1f, 0x5a, 0x84, + 0xee, 0xdf, 0x16, 0xaa, 0x1a, 0xcc, 0xdd, 0xa8, 0x9a, 0x8b, 0xb1, 0x83, 0x43, 0x16, 0xf1, 0x06, + 0x5e, 0x50, 0x2e, 0xae, 0x7b, 0x87, 0x9d, 0x5d, 0x9d, 0x61, 0x7d, 0xc4, 0xdd, 0x3d, 0xe9, 0x44, + 0x52, 0x3e, 0xa7, 0x98, 0x8d, 0x98, 0x5d, 0x7b, 0xdb, 0xf7, 0x11, 0x97, 0x78, 0x18, 0xe3, 0x4d, + 0x28, 0x66, 0xa1, 0xdc, 0x11, 0x2a, 0xe5, 0xdc, 0xce, 0x31, 0x27, 0xc5, 0xa1, 0x68, 0x18, 0x81, + 0x43, 0x1c, 0x55, 0x64, 0xd7, 0xd2, 0xb7, 0x68, 0xef, 0x57, 0x78, 0x2b, 0xee, 0x8c, 0xf5, 0xc8, + 0xc5, 0xd9, 0x3e, 0xa6, 0x6d, 0x1a, 0x32, 0xb2, 0xa3, 0x38, 0xb6, 0xe3, 0x8d, 0x4b, 0x4d, 0x10, + 0x2f, 0x1e, 0x70, 0x17, 0xae, 0x95, 0xfc, 0x10, 0xa7, 0xdc, 0x3e, 0x47, 0x5f, 0x0d, 0x08, 0x23, + 0x32, 0x4b, 0x5b, 0x08, 0xa5, 0xc1, 0xb7, 0x12, 0xb0, 0x0d, 0xb2, 0xf2, 0x34, 0x3a, 0x7e, 0xd7, + 0x84, 0xdb, 0x3e, 0x26, 0x67, 0xbb, 0xcc, 0x9d, 0x7e, 0x29, 0x58, 0xaa, 0x7b, 0x83, 0x61, 0x31, + 0x8e, 0x53, 0x26, 0x54, 0x6d, 0x60, 0xd4, 0x45, 0xcf, 0xc6, 0xa6, 0xb7, 0xa1, 0x4f, 0xf0, 0x1d, + 0xa5, 0xbc, 0x80, 0xd3, 0x92, 0xad, 0x85, 0xd5, 0x62, 0x2b, 0x75, 0x41, 0xef, 0x9e, 0x0e, 0x4f, + 0x6e, 0xaf, 0x6e, 0x90, 0xd4, 0xf3, 0x19, 0x96, 0x74, 0x22, 0x65, 0xb3, 0x10, 0x0f, 0x5c, 0x76, + 0xc0, 0xb5, 0x92, 0x49, 0xe4, 0x1d, 0x8c, 0xbd, 0x5c, 0x14, 0x73, 0x89, 0x34, 0x6e, 0xd0, 0x61, + 0xf2, 0xac, 0xbb, 0x31, 0x69, 0x29, 0x11, 0xdf, 0x71, 0x97, 0xa5, 0x21, 0xd0, 0xc2, 0xb2, 0x96, + 0x27, 0xd3, 0xff, 0x3f, 0x7b, 0xe7, 0xd3, 0x93, 0xc8, 0xb6, 0x3d, 0xec, 0x2f, 0x73, 0x6d, 0x83, + 0x1e, 0x34, 0xe9, 0x73, 0xd1, 0xa0, 0x57, 0x7b, 0x2c, 0x1e, 0x30, 0x01, 0x0b, 0x02, 0x34, 0x30, + 0x39, 0x68, 0x00, 0x81, 0x04, 0x04, 0x22, 0x25, 0xf4, 0x77, 0x50, 0xfe, 0x44, 0x11, 0x99, 0x08, + 0x04, 0xca, 0x82, 0x04, 0xac, 0x22, 0x80, 0x05, 0x63, 0xa1, 0xc1, 0x04, 0xac, 0xaa, 0x40, 0x09, + 0x4c, 0x1a, 0x09, 0x60, 0x41, 0x22, 0x02, 0x41, 0xda, 0xbe, 0xaf, 0x77, 0xdc, 0xc7, 0xe9, 0x3b, + 0xf8, 0xc5, 0xe7, 0x13, 0xc0, 0xc3, 0xae, 0xb5, 0xf7, 0xa2, 0xf6, 0x5a, 0xcb, 0x7d, 0x13, 0x92, + 0x06, 0x67, 0xa3, 0xf2, 0x3c, 0xf2, 0xf6, 0x70, 0xe5, 0xef, 0xe0, 0xc8, 0x84, 0xef, 0x64, 0x7c, + 0xe2, 0xe5, 0xf4, 0x33, 0x5f, 0x16, 0x21, 0xc2, 0x33, 0xd6, 0x3b, 0x05, 0xe2, 0xae, 0x8c, 0xa3, + 0x97, 0x72, 0x78, 0x1c, 0xf9, 0x8f, 0x50, 0x5c, 0x2a, 0x27, 0x67, 0x72, 0xe1, 0xd1, 0xd9, 0x70, + 0x62, 0x3e, 0xac, 0x36, 0x97, 0xa5, 0x5f, 0x11, 0x76, 0x59, 0x74, 0x58, 0xd1, 0x6b, 0x81, 0xbf, + 0x13, 0xa1, 0xcf, 0x86, 0xcb, 0xf1, 0x22, 0x4b, 0x0e, 0x65, 0xcd, 0xbc, 0xaf, 0x67, 0x2d, 0xf6, + 0x0d, 0xec, 0xb3, 0xd0, 0xc3, 0xfc, 0x76, 0x3b, 0x19, 0x2e, 0x59, 0x2e, 0xc2, 0xfd, 0xaa, 0x97, + 0x0c, 0xd7, 0x74, 0x42, 0xda, 0xb2, 0x29, 0x7d, 0x48, 0xdd, 0xa4, 0xea, 0xb5, 0xc4, 0x2a, 0x04, + 0xd4, 0x2b, 0x7d, 0xfd, 0x08, 0x5c, 0xd3, 0xa6, 0x8f, 0x01, 0x4b, 0x56, 0x3a, 0x06, 0x64, 0x13, + 0xec, 0x0c, 0x57, 0xe8, 0x6b, 0xce, 0x48, 0xbd, 0xb9, 0xbe, 0x89, 0x25, 0xe9, 0x03, 0x85, 0x6c, + 0x1e, 0xfe, 0xd3, 0xfe, 0x84, 0x10, 0xf8, 0x66, 0xff, 0x8b, 0x98, 0xa1, 0x30, 0x84, 0x91, 0x61, + 0x6d, 0x84, 0x16, 0xed, 0x91, 0xea, 0x45, 0x48, 0x9c, 0xf0, 0x33, 0x11, 0x0e, 0xdf, 0x4c, 0xad, + 0x4b, 0x44, 0x00, 0xb2, 0xbc, 0x90, 0xe0, 0x27, 0x59, 0x1b, 0xf6, 0x01, 0x23, 0x82, 0x7c, 0x4b, + 0x64, 0x45, 0xfa, 0x1c, 0x80, 0x9b, 0x36, 0xab, 0xb1, 0x49, 0xb0, 0x92, 0x7f, 0x0d, 0xfa, 0xdf, + 0xe2, 0x1c, 0xbe, 0x44, 0xdc, 0x5f, 0xa7, 0xc5, 0x02, 0x6f, 0xe2, 0xf7, 0xe8, 0x31, 0x64, 0xbf, + 0x63, 0x9a, 0x85, 0x35, 0xc2, 0x4e, 0xb9, 0x91, 0xa7, 0x50, 0x63, 0xc4, 0x61, 0xff, 0x9b, 0xa5, + 0x32, 0xd0, 0xd4, 0x32, 0xf4, 0xa8, 0xd7, 0x09, 0xe6, 0x4a, 0x1e, 0xd1, 0x30, 0x24, 0x87, 0xd3, + 0x42, 0x1c, 0xd3, 0x0a, 0x03, 0xa3, 0xdc, 0x75, 0xff, 0x53, 0x32, 0x42, 0xbc, 0xee, 0x4a, 0x9c, + 0xde, 0xaa, 0x5f, 0x22, 0x84, 0x94, 0xb4, 0xe9, 0xdb, 0x31, 0x81, 0x5a, 0xbd, 0x32, 0x6c, 0x51, + 0x8e, 0x0a, 0xb3, 0xf3, 0xe5, 0x6a, 0x63, 0x36, 0x57, 0xf1, 0xc9, 0x9b, 0x37, 0xe3, 0xe1, 0x10, + 0xd3, 0xd8, 0x63, 0x2e, 0x07, 0x25, 0x24, 0xb0, 0x70, 0xd7, 0x0a, 0xf8, 0xfd, 0x5a, 0x7e, 0x03, + 0x68, 0x1e, 0x88, 0x63, 0xfc, 0x8b, 0x10, 0xa3, 0x61, 0xda, 0x1e, 0xf6, 0xac, 0x7a, 0x59, 0x1a, + 0xeb, 0xfe, 0xe8, 0xe1, 0x53, 0x39, 0x26, 0xf2, 0x0b, 0x0c, 0xb5, 0x5d, 0xd9, 0x58, 0x48, 0x9d, + 0x35, 0x96, 0x11, 0xa5, 0x28, 0x43, 0xe2, 0x4f, 0xc3, 0x69, 0xa8, 0xde, 0x9c, 0x49, 0x1c, 0x44, + 0x0e, 0x7f, 0xc2, 0x39, 0x24, 0xf6, 0x8c, 0xdd, 0xd2, 0x51, 0xdd, 0x4b, 0x74, 0xa4, 0x58, 0xb4, + 0xda, 0x47, 0xb6, 0xda, 0xd4, 0x24, 0x77, 0xfb, 0xd9, 0x13, 0x73, 0x79, 0xad, 0x63, 0x42, 0xfd, + 0x9d, 0x8e, 0x0e, 0x85, 0xd3, 0x0a, 0xe9, 0x5e, 0x3a, 0x53, 0xed, 0x77, 0xfb, 0x5d, 0x89, 0x4a, + 0xfe, 0xe0, 0x3b, 0xb0, 0x1e, 0xc7, 0xcf, 0x86, 0x26, 0xfb, 0x5e, 0x97, 0xfd, 0xa2, 0xa1, 0xc4, + 0x0d, 0xbd, 0xd9, 0xbd, 0xda, 0x35, 0x74, 0xfb, 0x33, 0x7a, 0x29, 0x57, 0x18, 0x64, 0x77, 0xf2, + 0x57, 0xaf, 0xea, 0x27, 0xed, 0xf1, 0xac, 0x56, 0xea, 0xea, 0xaa, 0x16, 0xa8, 0xc2, 0x73, 0x5f, + 0x84, 0x8f, 0x86, 0x32, 0xa2, 0x6e, 0x87, 0x67, 0x1e, 0x88, 0x4b, 0xda, 0x91, 0x41, 0x47, 0x35, + 0xdf, 0x5c, 0x24, 0xac, 0x76, 0x77, 0xd5, 0x77, 0xcd, 0x90, 0xf2, 0xc0, 0xe5, 0x65, 0x57, 0x04, + 0x23, 0xc0, 0x5a, 0xd4, 0xf4, 0x91, 0xb5, 0xe6, 0x1a, 0xff, 0xc7, 0xef, 0x33, 0x28, 0x9b, 0x6b, + 0xef, 0x98, 0x36, 0x65, 0x7a, 0xa4, 0x14, 0xb4, 0x48, 0xf4, 0x9e, 0x15, 0xdd, 0xf6, 0x8b, 0x3b, + 0x20, 0x26, 0xcf, 0xa6, 0x0f, 0xc3, 0x06, 0x1a, 0x12, 0x4f, 0x04, 0xfa, 0x33, 0x1a, 0xbd, 0xea, + 0x36, 0xa4, 0x52, 0x78, 0x57, 0x94, 0x5d, 0x07, 0xb1, 0xf3, 0x4c, 0x3f, 0x3f, 0x68, 0x7f, 0x2a, + 0xd6, 0xb0, 0xe6, 0xaa, 0x4e, 0x73, 0x37, 0x44, 0xba, 0x60, 0xf7, 0x3f, 0x01, 0x40, 0x04, 0x49, + 0x21, 0xea, 0x0a, 0x59, 0xeb, 0xa4, 0x22, 0xb0, 0x2a, 0xd0, 0x75, 0xc5, 0x57, 0xc6, 0x09, 0x59, + 0x04, 0xdf, 0x58, 0x8b, 0x42, 0xf2, 0x5a, 0xc7, 0xa6, 0xb7, 0xd4, 0x5e, 0x9f, 0x5a, 0xc9, 0x00, + 0xad, 0x0e, 0x2e, 0x11, 0x43, 0xd0, 0xd0, 0xbe, 0x09, 0xc1, 0x7b, 0x27, 0x2d, 0xb4, 0x30, 0x3e, + 0x09, 0x65, 0x8e, 0xfc, 0xa1, 0x2c, 0xf3, 0x7f, 0x63, 0xc3, 0xe4, 0xe0, 0x30, 0x78, 0xa0, 0xf6, + 0x52, 0x3f, 0x72, 0xa0, 0xc3, 0xd3, 0x8c, 0xd0, 0xbe, 0xb4, 0x73, 0xa1, 0x58, 0xdb, 0xf9, 0x85, + 0x1f, 0x28, 0x5c, 0x5e, 0xa0, 0xae, 0xde, 0x73, 0x47, 0x36, 0x52, 0x32, 0x5b, 0x96, 0xdc, 0xc7, + 0xff, 0xd5, 0x46, 0xb3, 0xe9, 0x6f, 0xe0, 0xfa, 0x93, 0x7b, 0x77, 0x83, 0x1f, 0x03, 0x98, 0x90, + 0x30, 0x02, 0xa5, 0x5e, 0x32, 0x47, 0xe6, 0xc7, 0x86, 0x08, 0x57, 0x88, 0xba, 0xa5, 0xd3, 0x1f, + 0xb4, 0x76, 0xba, 0x95, 0x78, 0xc8, 0x0a, 0x8b, 0xaf, 0x59, 0xad, 0xc9, 0x76, 0xfd, 0x23, 0x6f, + 0x2c, 0x3d, 0xb5, 0xfc, 0x2f, 0x57, 0x58, 0x0f, 0xef, 0x0a, 0x2e, 0x4e, 0xd4, 0x3d, 0xe4, 0xb2, + 0x99, 0x58, 0x75, 0x1c, 0xcf, 0x1c, 0xac, 0x42, 0x5e, 0x47, 0x90, 0x97, 0xe5, 0x63, 0x99, 0x54, + 0x39, 0x28, 0x21, 0xe2, 0x7c, 0xcf, 0xbf, 0x72, 0xb1, 0xee, 0xf5, 0x7f, 0x55, 0x2b, 0x9b, 0x60, + 0x22, 0xb8, 0x8c, 0xc6, 0x61, 0xac, 0x97, 0xdb, 0x83, 0x37, 0x56, 0x38, 0x17, 0x27, 0x33, 0xb9, + 0xb3, 0xd6, 0xe9, 0xb4, 0x42, 0xbd, 0xfa, 0x25, 0xd5, 0xa8, 0x34, 0xc4, 0xd1, 0x77, 0xe9, 0xdf, + 0x27, 0x6e, 0x99, 0xc4, 0xef, 0x98, 0x06, 0x21, 0x85, 0x14, 0x43, 0x10, 0x13, 0x38, 0x87, 0x44, + 0x74, 0x38, 0x44, 0xf4, 0xec, 0x8d, 0xe5, 0xdb, 0xdb, 0x27, 0x41, 0xe8, 0xe0, 0xd7, 0xe0, 0x7e, + 0x9c, 0xac, 0x1f, 0xef, 0xb5, 0x6e, 0xfa, 0x67, 0x41, 0x53, 0xad, 0x97, 0x2e, 0x4d, 0xd6, 0x5e, + 0xbb, 0x6f, 0xbf, 0x3a, 0x8d, 0xa9, 0xab, 0xc9, 0x48, 0xee, 0xe2, 0xd2, 0xbf, 0x32, 0x72, 0xdd, + 0x57, 0x5e, 0xef, 0xcb, 0x17, 0x37, 0x65, 0x9f, 0xb7, 0xdd, 0xae, 0x82, 0x3e, 0x72, 0x38, 0x05, + 0xaf, 0xa7, 0xcc, 0xc8, 0xe6, 0x0e, 0x3e, 0xd6, 0x44, 0xad, 0xa9, 0xf4, 0x92, 0xda, 0x00, 0x91, + 0xa5, 0xa3, 0x47, 0x4f, 0xde, 0xbe, 0x75, 0x34, 0x46, 0x9f, 0x9e, 0x5a, 0xa6, 0x64, 0x7d, 0x80, + 0xb0, 0x3b, 0x7a, 0xca, 0x47, 0xe6, 0xf2, 0x1d, 0x8b, 0x27, 0xdc, 0xce, 0x99, 0x89, 0x21, 0x52, + 0x9d, 0xca, 0x09, 0xac, 0x64, 0xf0, 0x02, 0xa9, 0x88, 0x96, 0xcd, 0x33, 0x46, 0x76, 0xc6, 0xfe, + 0x35, 0x4f, 0x8b, 0xc2, 0xaa, 0x65, 0x6f, 0xb0, 0xde, 0xab, 0xf5, 0xda, 0xec, 0xd2, 0x7e, 0xd4, + 0x93, 0x99, 0x50, 0x66, 0x34, 0xaa, 0x6d, 0x80, 0x6f, 0xcf, 0x4a, 0xe4, 0xf8, 0xcc, 0x4f, 0x34, + 0xe2, 0xf3, 0xd8, 0x13, 0x28, 0x71, 0x8c, 0x6c, 0xdd, 0xbe, 0x8d, 0xe8, 0xbe, 0xed, 0x5f, 0x2b, + 0x9d, 0x34, 0x7e, 0x11, 0x5d, 0x34, 0x35, 0xbc, 0x28, 0x24, 0xdb, 0xc5, 0x76, 0x61, 0x1d, 0x22, + 0x69, 0x83, 0x12, 0x81, 0x3d, 0x57, 0xba, 0x3f, 0xaf, 0xcd, 0x2c, 0x6e, 0x79, 0xab, 0xc3, 0xc5, + 0x53, 0x07, 0x14, 0x56, 0xf1, 0x86, 0x7e, 0xda, 0xd8, 0xdb, 0x21, 0x59, 0x11, 0xcb, 0xbe, 0x2b, + 0x59, 0xe0, 0x9b, 0x92, 0xed, 0xb6, 0xda, 0x96, 0xca, 0x00, 0x09, 0x05, 0x3e, 0x5c, 0x04, 0xa3, + 0xf3, 0xf3, 0x25, 0x27, 0xa9, 0x9f, 0xd3, 0x46, 0xe4, 0x63, 0x59, 0xc4, 0x5c, 0xc3, 0x92, 0xab, + 0x6a, 0xc1, 0x55, 0x7f, 0x15, 0xb7, 0xd6, 0x96, 0x19, 0x6f, 0x87, 0xa1, 0xa2, 0x74, 0xe0, 0xf8, + 0xbd, 0xee, 0x59, 0x29, 0x7b, 0xc7, 0x34, 0x60, 0x15, 0x39, 0x95, 0xbc, 0x0a, 0x0e, 0x5b, 0x24, + 0x69, 0x62, 0x98, 0xd5, 0xbd, 0x28, 0xe0, 0xcb, 0x2c, 0x3a, 0xea, 0xca, 0x88, 0xf1, 0x31, 0x6d, + 0x93, 0x71, 0x88, 0xda, 0x59, 0xbd, 0x1a, 0xe9, 0xa6, 0x3a, 0x43, 0x1b, 0x28, 0x1d, 0x02, 0xf9, + 0xd7, 0xb9, 0xa6, 0x64, 0xaf, 0xa6, 0xff, 0xa2, 0xa7, 0x6b, 0x52, 0x2d, 0x42, 0xc5, 0xf7, 0xa8, + 0x95, 0xba, 0xe6, 0xef, 0x66, 0x6f, 0x2c, 0x58, 0xfc, 0xa4, 0xb1, 0x91, 0x91, 0x62, 0x38, 0xfe, + 0xfc, 0xb3, 0x13, 0x19, 0xc0, 0xf3, 0x5f, 0x56, 0x8a, 0xc6, 0xd3, 0xf1, 0x2a, 0x31, 0x5c, 0x53, + 0xf0, 0x9c, 0x81, 0x4b, 0x48, 0x93, 0x26, 0x61, 0x88, 0x3a, 0x73, 0x27, 0x75, 0x2f, 0x75, 0x5f, + 0x18, 0xeb, 0x7e, 0xd3, 0x4d, 0xeb, 0xa3, 0xec, 0x65, 0x30, 0x18, 0x52, 0x87, 0xff, 0xbb, 0x1c, + 0xb3, 0x7e, 0xf5, 0x6f, 0x14, 0x64, 0x4e, 0xe1, 0xe4, 0x4f, 0x77, 0xc2, 0xbb, 0x56, 0x28, 0xb4, + 0x0e, 0x82, 0xc2, 0x47, 0xaf, 0x3b, 0x7f, 0x23, 0x75, 0x9f, 0xe8, 0x00, 0xf7, 0xe5, 0xc5, 0x48, + 0x8e, 0x78, 0x12, 0x42, 0x2e, 0x14, 0x18, 0x8e, 0x97, 0x81, 0xa0, 0x8a, 0xd2, 0xd6, 0x83, 0x24, + 0x1a, 0x36, 0x02, 0x5d, 0xf3, 0x4d, 0x3c, 0xf6, 0x18, 0xb8, 0x21, 0x5e, 0xf7, 0xc3, 0xaf, 0x47, + 0xba, 0xf1, 0x7c, 0x71, 0x48, 0x2a, 0xe1, 0xa1, 0xe9, 0xf8, 0xdf, 0x05, 0x41, 0xfc, 0xe7, 0x59, + 0xaa, 0x60, 0xb1, 0x06, 0x13, 0x62, 0xd9, 0x5d, 0x2b, 0x52, 0x4b, 0x98, 0x6a, 0x22, 0x2c, 0x6e, + 0xa2, 0xd6, 0x71, 0xdd, 0xae, 0xbf, 0x02, 0x5f, 0xb5, 0x90, 0xcd, 0xba, 0xfe, 0x3a, 0x98, 0x25, + 0xcb, 0xea, 0x57, 0x2c, 0x52, 0xc3, 0xce, 0xfb, 0x9a, 0xad, 0xf4, 0xdc, 0xb4, 0xfe, 0x1d, 0x93, + 0x56, 0xa1, 0xbf, 0xd2, 0x88, 0x5f, 0x2b, 0x90, 0x91, 0x11, 0x2b, 0xf8, 0x23, 0x10, 0xee, 0xa4, + 0xe5, 0x24, 0x3e, 0x22, 0x82, 0x92, 0xa4, 0x40, 0x04, 0x87, 0x5e, 0xea, 0x59, 0x3d, 0xa3, 0x73, + 0x50, 0x6f, 0xfd, 0x3e, 0x07, 0xca, 0x39, 0xf3, 0x8f, 0xa6, 0xef, 0x9a, 0x5b, 0xc9, 0x32, 0x7f, + 0xc8, 0x12, 0x1f, 0x83, 0xae, 0xca, 0x2b, 0x84, 0xb6, 0x92, 0x9b, 0x8e, 0xf4, 0xca, 0x70, 0xc5, + 0x7e, 0xea, 0xb8, 0x11, 0xf3, 0x7e, 0x20, 0xec, 0x7c, 0x26, 0xf6, 0x5c, 0x23, 0xca, 0x57, 0x18, + 0xbb, 0xdd, 0xd9, 0x95, 0xcd, 0x30, 0x49, 0xcb, 0x49, 0xf1, 0x69, 0x9f, 0x34, 0xe9, 0x6f, 0xb3, + 0xc1, 0x4e, 0x66, 0x03, 0xa9, 0x69, 0xc7, 0xe8, 0x5e, 0x00, 0x9e, 0xb7, 0xab, 0x23, 0x2f, 0x11, + 0x19, 0x25, 0x09, 0xea, 0x79, 0x65, 0x64, 0x46, 0x98, 0xd6, 0x51, 0x1e, 0x46, 0x35, 0x7a, 0x91, + 0x2a, 0x2c, 0x97, 0x62, 0xfe, 0x17, 0xd2, 0x36, 0x4e, 0x2e, 0xf5, 0x73, 0x28, 0xda, 0xdd, 0xf8, + 0x1e, 0x67, 0xa8, 0xb9, 0x47, 0x46, 0x86, 0xe5, 0x2d, 0x0b, 0xac, 0x99, 0x5f, 0x8e, 0x64, 0xe1, + 0x4c, 0x0a, 0x57, 0x9e, 0x85, 0x43, 0xd5, 0xe9, 0x6e, 0x43, 0xfa, 0x4d, 0x10, 0x1e, 0xa5, 0xa0, + 0xa1, 0xa4, 0x7b, 0x70, 0xe9, 0xb7, 0x60, 0xa0, 0x2c, 0x78, 0x11, 0x18, 0x9b, 0x7f, 0x78, 0x85, + 0x09, 0x4c, 0x2f, 0x13, 0xf1, 0x4a, 0x82, 0xa0, 0xaa, 0x5a, 0x76, 0x60, 0x9f, 0x6c, 0x76, 0x85, + 0x58, 0x0f, 0x48, 0x8f, 0xa5, 0x6f, 0x8b, 0xd8, 0x74, 0xd6, 0xe3, 0xe2, 0x82, 0xa0, 0xb6, 0x9a, + 0x72, 0xb8, 0x19, 0x40, 0x4f, 0xf1, 0x08, 0x31, 0x4a, 0xca, 0x70, 0x44, 0xec, 0x8a, 0xa4, 0x61, + 0x0b, 0x2e, 0xb8, 0x82, 0x39, 0x75, 0x83, 0x87, 0x6b, 0x3e, 0x4c, 0x1c, 0x2c, 0x46, 0x88, 0xe7, + 0xd7, 0x55, 0xdd, 0xe5, 0x45, 0x7a, 0xe5, 0xed, 0xe0, 0x2e, 0x6b, 0xe8, 0xac, 0xae, 0xf1, 0x72, + 0x46, 0x36, 0x64, 0x08, 0x47, 0x55, 0xef, 0x32, 0x50, 0x94, 0x08, 0xcc, 0x49, 0xc2, 0xf2, 0x75, + 0x82, 0xdc, 0x3a, 0x30, 0x9a, 0x4b, 0x71, 0xe4, 0x0f, 0x01, 0x6e, 0xaa, 0x66, 0x59, 0xb6, 0x7e, + 0x3f, 0xbb, 0xa3, 0x45, 0xbc, 0xa8, 0x6c, 0xf6, 0xf3, 0x5f, 0x08, 0xab, 0x81, 0x67, 0xde, 0x12, + 0x3a, 0xf9, 0xe8, 0x6a, 0x5c, 0xd4, 0x1f, 0x2b, 0xff, 0xa1, 0x8f, 0x90, 0xf2, 0x9d, 0x35, 0x1d, + 0xa9, 0xa2, 0xa2, 0x90, 0x89, 0x53, 0x3c, 0x6e, 0x48, 0x41, 0x8d, 0x0e, 0xdb, 0x5d, 0x21, 0x90, + 0xbd, 0x6a, 0x4e, 0x6e, 0x4e, 0xf8, 0xdb, 0xb4, 0x17, 0xc9, 0xd8, 0x63, 0xca, 0xb3, 0x5b, 0xa9, + 0x74, 0x10, 0x26, 0x62, 0x08, 0xc8, 0x5e, 0x1f, 0x42, 0x09, 0x08, 0xdf, 0x00, 0x5d, 0xe3, 0x8a, + 0x05, 0xc0, 0x11, 0xda, 0x2c, 0x9f, 0x5a, 0x9a, 0x49, 0xbd, 0xcf, 0xd2, 0x9c, 0xa0, 0xda, 0xdd, + 0xea, 0xd8, 0x38, 0x96, 0xfb, 0x57, 0x91, 0xab, 0xf1, 0x3a, 0xaf, 0x90, 0xde, 0x0b, 0xa9, 0x0b, + 0xd0, 0xbf, 0xd2, 0x6b, 0x20, 0x9d, 0xe8, 0x6e, 0x79, 0x86, 0x90, 0x78, 0x5a, 0xbd, 0x0e, 0xee, + 0x8a, 0x6a, 0xba, 0x90, 0x59, 0x67, 0x8f, 0xc3, 0x52, 0xb1, 0x6b, 0xd7, 0xfd, 0xe9, 0x97, 0xfa, + 0xac, 0x5b, 0x21, 0x71, 0xd9, 0xbf, 0xa1, 0xf0, 0xd3, 0xdb, 0x8e, 0xa6, 0x92, 0xfe, 0x68, 0xb6, + 0x93, 0xc4, 0x73, 0xe8, 0xcb, 0x96, 0x4e, 0xeb, 0x51, 0xc1, 0x45, 0x0a, 0x56, 0xe5, 0x2d, 0xbb, + 0x49, 0x02, 0x96, 0x5c, 0x62, 0x2a, 0x9d, 0xd3, 0x81, 0x69, 0xc2, 0x3e, 0x47, 0x76, 0x0e, 0x2e, + 0xea, 0xb2, 0x33, 0x5b, 0x1a, 0x9f, 0x46, 0x23, 0x2e, 0x3f, 0xbf, 0x4a, 0x54, 0xc7, 0x63, 0x5a, + 0x23, 0xd9, 0x1e, 0xd2, 0xc2, 0xad, 0x4d, 0x0b, 0xd4, 0x90, 0xd6, 0x1c, 0xc3, 0xca, 0x68, 0xfb, + 0xd8, 0x5d, 0x9b, 0xde, 0xbd, 0x45, 0x6c, 0x6e, 0x7d, 0x2c, 0x21, 0x26, 0xf1, 0xa9, 0x46, 0x52, + 0x1d, 0xe9, 0xa6, 0x5f, 0x78, 0x57, 0x2f, 0xe3, 0x45, 0xc8, 0xf6, 0xb6, 0xfb, 0xe4, 0x37, 0x1b, + 0x4c, 0x22, 0x53, 0x87, 0x17, 0x37, 0x6f, 0x22, 0x69, 0x11, 0xf1, 0x2b, 0xf5, 0xd5, 0xc9, 0xd0, + 0x49, 0xbc, 0xb3, 0xd1, 0x3f, 0x81, 0xf8, 0xbf, 0x23, 0x13, 0x84, 0xb6, 0xd7, 0x2d, 0x00, 0xb0, + 0x14, 0xe2, 0xc4, 0xb5, 0xe4, 0x94, 0x5b, 0x56, 0x24, 0x6a, 0xe6, 0xc7, 0xd3, 0x7a, 0x73, 0xb3, + 0xc1, 0xbf, 0x82, 0x21, 0x2c, 0x3e, 0xaf, 0x59, 0xe9, 0x0c, 0x7e, 0x8f, 0xd3, 0x88, 0xea, 0x1d, + 0xd3, 0x37, 0x63, 0x4f, 0xad, 0xb1, 0xf4, 0xb4, 0xf9, 0x78, 0xde, 0xae, 0x97, 0x0c, 0x6d, 0x6b, + 0xbf, 0x8e, 0x39, 0x11, 0x20, 0xae, 0xa7, 0xb4, 0xa8, 0x51, 0x1b, 0xa2, 0x59, 0x4f, 0x5d, 0xb7, + 0x32, 0x7f, 0x98, 0x9e, 0x9d, 0x3c, 0x9d, 0x3b, 0x03, 0x58, 0x14, 0xdb, 0x09, 0xa3, 0xa5, 0x43, + 0x48, 0xb5, 0x82, 0xf6, 0x8e, 0x30, 0x76, 0x2f, 0x1e, 0x7b, 0xcd, 0xeb, 0x1e, 0x9b, 0x8b, 0x26, + 0x4d, 0x2f, 0xad, 0x02, 0x58, 0x88, 0x05, 0x48, 0x15, 0xcb, 0xae, 0x51, 0x5a, 0x25, 0xef, 0x77, + 0xad, 0x75, 0xb7, 0xfb, 0xa1, 0xd6, 0xb5, 0x5f, 0x4e, 0x6b, 0xb1, 0x91, 0x47, 0x8c, 0xa2, 0xb0, + 0x17, 0x9a, 0x0d, 0x77, 0xac, 0x9d, 0xe1, 0x18, 0xe9, 0xde, 0x4f, 0x78, 0x52, 0x8c, 0x8d, 0xcc, + 0x5f, 0xd7, 0xba, 0x1b, 0x75, 0x4f, 0x29, 0xb4, 0xb5, 0x96, 0x35, 0x37, 0xa4, 0xd6, 0x4c, 0x2f, + 0x73, 0xf3, 0x67, 0x2c, 0x40, 0x37, 0x56, 0x08, 0x72, 0x4d, 0xd7, 0x13, 0x99, 0x2b, 0x22, 0xf9, + 0xb9, 0x8f, 0x2d, 0x5d, 0xca, 0x2b, 0xea, 0x18, 0x81, 0xdc, 0x4d, 0x0b, 0x62, 0x22, 0x80, 0x84, + 0xf4, 0x88, 0x9b, 0x0a, 0xc2, 0xe3, 0xa3, 0x1a, 0x59, 0xad, 0xd1, 0x36, 0xd2, 0x84, 0xba, 0xbf, + 0xb0, 0xe5, 0x44, 0x09, 0xcf, 0x58, 0x2f, 0xef, 0x28, 0x29, 0x23, 0x3d, 0x95, 0xaa, 0x50, 0x54, + 0xa3, 0x02, 0x97, 0x6a, 0x0f, 0xe3, 0x8d, 0xda, 0x96, 0xe0, 0x47, 0x9b, 0x8d, 0x8c, 0xc1, 0xf5, + 0x83, 0x32, 0xe6, 0x40, 0x25, 0xa7, 0x80, 0x3f, 0x0b, 0x6f, 0x53, 0xcc, 0xf4, 0xe7, 0xd1, 0xae, + 0x9f, 0xf3, 0x54, 0xd2, 0x7e, 0xed, 0x6f, 0x81, 0x02, 0x1b, 0x3b, 0x4c, 0x50, 0xb5, 0x2f, 0xa4, + 0xa0, 0x21, 0x87, 0x57, 0xfe, 0x3a, 0x9e, 0x95, 0xda, 0xe5, 0xfb, 0x8f, 0xa1, 0xdc, 0xb3, 0xd3, + 0x09, 0x70, 0xbc, 0x7b, 0x49, 0xb1, 0xce, 0x65, 0x4a, 0xde, 0x8c, 0xd2, 0x81, 0x76, 0x48, 0xdd, + 0x25, 0x9d, 0x73, 0x95, 0xfd, 0x23, 0xbc, 0x2e, 0x12, 0x1c, 0xff, 0x9e, 0xb9, 0xbc, 0x45, 0x9c, + 0x7f, 0x36, 0x7d, 0xbb, 0x6c, 0xab, 0x36, 0x59, 0x5d, 0x37, 0xc0, 0xe2, 0xca, 0xf9, 0xce, 0x2e, + 0xaf, 0x22, 0xc0, 0xc9, 0xb9, 0xad, 0xed, 0xa7, 0x74, 0xd0, 0x78, 0x2b, 0x74, 0xaa, 0x24, 0x7c, + 0x64, 0xe6, 0x66, 0xeb, 0x49, 0x34, 0x8f, 0x73, 0x05, 0x17, 0x43, 0x36, 0xb7, 0x0a, 0x00, 0xa6, + 0x0d, 0x2d, 0xea, 0x64, 0xcc, 0x71, 0xb7, 0xdb, 0x4b, 0xd0, 0xd7, 0x18, 0xc2, 0x12, 0xd9, 0xe4, + 0x63, 0x25, 0x14, 0x53, 0x9a, 0x78, 0x25, 0xc5, 0x71, 0x8b, 0x2d, 0xb3, 0xe2, 0xfe, 0x35, 0xee, + 0xf1, 0xf6, 0x8f, 0xe0, 0x52, 0x6c, 0xcf, 0x79, 0x90, 0xb3, 0xa2, 0x8e, 0xc6, 0x26, 0xfa, 0x96, + 0xce, 0x0b, 0xd5, 0xe0, 0x5c, 0xb2, 0x5c, 0xe8, 0x21, 0xb2, 0xcf, 0x03, 0xfc, 0xac, 0xa2, 0xb7, + 0xef, 0xfe, 0xf0, 0x8b, 0xf2, 0x4e, 0xc6, 0xf0, 0xed, 0x10, 0x18, 0xc4, 0x96, 0x87, 0x06, 0x72, + 0x46, 0x5a, 0x82, 0x67, 0xb4, 0x9b, 0x00, 0x88, 0x17, 0x9e, 0x2c, 0x69, 0xd1, 0x66, 0xd1, 0x81, + 0x03, 0xb2, 0x9b, 0x6d, 0x7c, 0x5e, 0xbf, 0x30, 0x72, 0x62, 0x39, 0x01, 0x97, 0x64, 0x81, 0x45, + 0x52, 0x71, 0x99, 0xdf, 0x92, 0xa6, 0x99, 0xec, 0xfa, 0x7d, 0x07, 0x97, 0x8b, 0x4a, 0xdb, 0x4e, + 0xd3, 0x96, 0xd0, 0xd9, 0x8c, 0x4a, 0x9e, 0x5b, 0x38, 0x63, 0x7e, 0xfb, 0xda, 0xdd, 0x66, 0x87, + 0xa9, 0xfb, 0x28, 0x82, 0x28, 0xc3, 0x6f, 0x66, 0x22, 0x8f, 0xa1, 0xa7, 0xee, 0xd4, 0x55, 0xb1, + 0xe7, 0x7f, 0x36, 0xfd, 0x56, 0xf9, 0x69, 0x67, 0xd4, 0xef, 0x3c, 0xb6, 0x19, 0x92, 0x23, 0x20, + 0xca, 0x1d, 0xde, 0x45, 0xdb, 0xbd, 0x0d, 0xb8, 0x31, 0x8f, 0x15, 0x1c, 0x8e, 0xe1, 0xfc, 0xa2, + 0xc0, 0xf1, 0xbf, 0xae, 0x35, 0x4f, 0x88, 0x92, 0x89, 0x8e, 0xae, 0x82, 0x85, 0xef, 0xe3, 0xc7, + 0xe4, 0x6a, 0xb9, 0x33, 0x39, 0xa8, 0x9f, 0x06, 0x2b, 0x91, 0xb7, 0x0c, 0xf4, 0x13, 0x91, 0xaa, + 0x96, 0x70, 0xf6, 0x2d, 0xb6, 0x3d, 0x14, 0xcf, 0x09, 0x5f, 0xd7, 0x86, 0x30, 0x37, 0xfe, 0xfb, + 0x8e, 0x88, 0xb3, 0xde, 0x31, 0x9d, 0x94, 0x8c, 0x76, 0xb0, 0x91, 0x04, 0xc2, 0xd6, 0x0a, 0x11, + 0x3b, 0xda, 0xda, 0x28, 0x59, 0x3c, 0x4d, 0x95, 0xf4, 0xbc, 0x25, 0x55, 0x15, 0x3b, 0xe6, 0x84, + 0x56, 0x15, 0x07, 0xfd, 0x1b, 0x4b, 0x11, 0x28, 0x02, 0x8b, 0xcb, 0x43, 0xd6, 0x81, 0x59, 0xbe, + 0xe7, 0x99, 0xe5, 0x64, 0x00, 0x8b, 0xa4, 0x2b, 0x57, 0x9c, 0x08, 0x6d, 0x99, 0xc4, 0x89, 0x24, + 0xe1, 0x04, 0xb4, 0x96, 0x90, 0x4f, 0x51, 0x4b, 0xe4, 0xb5, 0x41, 0x67, 0x46, 0xe6, 0x56, 0xec, + 0x8c, 0x4a, 0x67, 0x8f, 0xd4, 0x32, 0x17, 0x26, 0xbf, 0xc9, 0x36, 0x0d, 0x52, 0x61, 0xc8, 0xea, + 0xd3, 0x7b, 0xb1, 0xd1, 0x37, 0x5f, 0xeb, 0xa0, 0x6e, 0x6a, 0x88, 0x5e, 0x08, 0xe2, 0x72, 0x5a, + 0xb0, 0xcb, 0x88, 0x13, 0x50, 0xbe, 0x95, 0x8e, 0xb4, 0xa2, 0x43, 0x68, 0x79, 0x08, 0x13, 0x03, + 0x48, 0xcf, 0xe4, 0x99, 0xae, 0xb2, 0x1b, 0x76, 0x4c, 0x5b, 0xbd, 0x45, 0xae, 0xdc, 0x0f, 0x25, + 0x9f, 0xe9, 0xac, 0x35, 0xa7, 0x97, 0x61, 0x84, 0xa0, 0x0f, 0x3b, 0x50, 0x7d, 0x9e, 0x0c, 0xa7, + 0xa2, 0x79, 0xa3, 0x57, 0xb3, 0x52, 0x40, 0xc2, 0xb5, 0x09, 0xd5, 0x57, 0x75, 0xaa, 0xa7, 0x4f, + 0x1e, 0x60, 0x5a, 0x74, 0x8a, 0xc0, 0xcf, 0xc6, 0x21, 0xab, 0xa1, 0x3a, 0x1d, 0xfa, 0xa4, 0x15, + 0x03, 0xa5, 0xab, 0x46, 0xbf, 0x81, 0x12, 0x22, 0x51, 0xf3, 0x5e, 0x75, 0x4c, 0xdd, 0xae, 0xbc, + 0x91, 0xd8, 0xf6, 0x63, 0xb2, 0x45, 0xd3, 0xc8, 0xa9, 0x4a, 0xe9, 0xbc, 0x41, 0x71, 0xb5, 0x70, + 0x0c, 0x2b, 0x5f, 0xb7, 0x4e, 0x9b, 0x34, 0xce, 0xbd, 0x23, 0x37, 0x84, 0xd4, 0x2e, 0xfb, 0xd3, + 0xaf, 0xde, 0xdf, 0x95, 0xc5, 0x1a, 0xb0, 0xdf, 0x02, 0xf5, 0xd6, 0xfa, 0x75, 0x53, 0xfb, 0x9d, + 0xe8, 0xf6, 0xa3, 0xb2, 0xf3, 0xe0, 0x06, 0x9f, 0x4f, 0xfe, 0x3b, 0x39, 0xc9, 0x04, 0x7a, 0x63, + 0x46, 0x03, 0x5a, 0x15, 0x0f, 0xf6, 0x6b, 0x7f, 0xc0, 0x1c, 0x9b, 0x57, 0xdc, 0x62, 0x64, 0xe2, + 0xbf, 0x67, 0x2e, 0xb8, 0xe9, 0x1d, 0xd3, 0x73, 0x95, 0xcc, 0x4b, 0xa2, 0xb9, 0x80, 0x98, 0x42, + 0x28, 0xff, 0xce, 0xf1, 0x9c, 0x09, 0xe1, 0x06, 0xa2, 0x21, 0x80, 0xaa, 0xa1, 0x7e, 0xad, 0x67, + 0x03, 0xb5, 0xc6, 0x6f, 0x22, 0x0b, 0x48, 0xf0, 0xbb, 0x1e, 0xab, 0x11, 0x85, 0x99, 0xa3, 0xca, + 0x35, 0x31, 0x46, 0x0e, 0x46, 0x5f, 0xa1, 0x16, 0xeb, 0x31, 0x0e, 0x4b, 0x5e, 0xd0, 0xc7, 0x73, + 0xac, 0x94, 0x8f, 0x5b, 0x64, 0x29, 0xef, 0x0f, 0x4a, 0x46, 0xd1, 0xc7, 0xf0, 0x52, 0x11, 0x8c, + 0x0d, 0x33, 0x3c, 0x00, 0x49, 0x84, 0xf2, 0xd6, 0x9f, 0x69, 0x39, 0xfd, 0x14, 0x0b, 0x32, 0x73, + 0xe7, 0xdb, 0xed, 0xe8, 0x52, 0xaf, 0xbc, 0x8d, 0x20, 0xda, 0x9a, 0x58, 0xc2, 0x4b, 0x80, 0x6b, + 0x5f, 0x64, 0x55, 0xf2, 0x9b, 0xa9, 0x27, 0x4d, 0x0d, 0x31, 0x9b, 0x07, 0xff, 0x4f, 0x37, 0x77, + 0xa4, 0xdd, 0x7d, 0xf9, 0xd5, 0x00, 0xdd, 0x1d, 0xd9, 0xb6, 0xcf, 0xbb, 0x64, 0x03, 0x07, 0xe9, + 0xb9, 0x9b, 0x98, 0x25, 0x5d, 0x08, 0x6b, 0xf4, 0x69, 0x25, 0xeb, 0x1b, 0x22, 0x7b, 0x90, 0x14, + 0xdf, 0x52, 0xc6, 0x02, 0xdc, 0xaa, 0xa7, 0x17, 0x36, 0x45, 0xca, 0xac, 0x88, 0xa3, 0x0b, 0x76, + 0xd7, 0xbe, 0xe9, 0x41, 0xec, 0x85, 0x68, 0x79, 0xa4, 0xf9, 0x62, 0x30, 0xcb, 0x94, 0x3e, 0xf9, + 0x52, 0x0f, 0x49, 0x62, 0xcf, 0xdb, 0xf8, 0x5c, 0xbf, 0xf3, 0x88, 0xb7, 0xd2, 0xd6, 0x5f, 0xc3, + 0xd7, 0x23, 0xdf, 0x59, 0x0d, 0x8d, 0xec, 0x38, 0x26, 0x9d, 0x6f, 0x18, 0x10, 0x0d, 0x5d, 0xb9, + 0x59, 0x29, 0x22, 0xb1, 0x33, 0x42, 0x0a, 0x44, 0xa0, 0x7d, 0xb0, 0x21, 0x73, 0x3b, 0xe1, 0x91, + 0xbc, 0x29, 0x4b, 0xb3, 0x0d, 0x53, 0x4d, 0x65, 0xd4, 0x03, 0x3c, 0x52, 0x61, 0xb5, 0x7f, 0xe1, + 0x0f, 0x09, 0x65, 0xdf, 0x84, 0x91, 0x9a, 0x51, 0xd7, 0x06, 0xa3, 0x9a, 0x1f, 0xd8, 0x8a, 0x4c, + 0x83, 0x53, 0xb6, 0xc3, 0xd7, 0xbb, 0x51, 0xff, 0xe9, 0x7f, 0xe3, 0x36, 0x9d, 0x77, 0xee, 0xce, + 0x96, 0xd0, 0xf3, 0xfb, 0x5c, 0x55, 0xe0, 0xe0, 0x1d, 0xd3, 0x8b, 0x1c, 0xf0, 0xf8, 0x30, 0xab, + 0x33, 0x8f, 0x35, 0x3a, 0xaa, 0xe6, 0x9c, 0x9f, 0x3d, 0x28, 0x8e, 0xa9, 0x2d, 0xbb, 0x11, 0x5e, + 0x0d, 0x8d, 0x39, 0xe5, 0xcb, 0xda, 0xab, 0xd1, 0x32, 0xd3, 0x2f, 0x39, 0x8e, 0x4f, 0x43, 0x80, + 0xe0, 0xe1, 0x2c, 0xc4, 0x18, 0x81, 0x5e, 0xdd, 0x26, 0x74, 0x96, 0x9d, 0x59, 0x13, 0x06, 0x2a, + 0x5a, 0x66, 0xe3, 0xc8, 0xd1, 0xb3, 0xdc, 0xdf, 0x85, 0x87, 0x13, 0x49, 0x99, 0x62, 0xad, 0xd4, + 0x2e, 0xd2, 0x1b, 0xea, 0x22, 0xbe, 0xde, 0x19, 0x39, 0xbd, 0xee, 0x60, 0x12, 0x90, 0x40, 0xc9, + 0x15, 0xad, 0x48, 0xd3, 0x6c, 0x17, 0x5b, 0x30, 0x68, 0x6c, 0xa0, 0x5d, 0x6a, 0x9d, 0xff, 0xe4, + 0x91, 0x43, 0x92, 0xd1, 0x45, 0xb8, 0x7d, 0x8b, 0x9c, 0xf5, 0xd7, 0xbd, 0xfd, 0x2f, 0x5b, 0xc5, + 0xba, 0x01, 0x9e, 0xb3, 0x9e, 0x96, 0x1d, 0x0f, 0x82, 0x0e, 0x2e, 0x49, 0x2e, 0x0d, 0x9a, 0xd7, + 0x2d, 0xfb, 0xb0, 0xbf, 0x5a, 0x04, 0xeb, 0xfa, 0xe5, 0x4c, 0x37, 0xb7, 0x8b, 0xfa, 0x59, 0x65, + 0xba, 0xd6, 0xa3, 0x39, 0xfa, 0xc5, 0x1d, 0xbb, 0xb7, 0x85, 0x85, 0x38, 0x3c, 0xc8, 0xa3, 0x92, + 0x5e, 0xfa, 0x7d, 0x62, 0xcb, 0xe5, 0xe3, 0x55, 0x33, 0xe4, 0x35, 0xd3, 0x6b, 0xa1, 0x5a, 0x29, + 0x3b, 0x07, 0x70, 0x35, 0xb5, 0x80, 0xd1, 0x10, 0xbc, 0x0a, 0xb2, 0xf8, 0x36, 0x79, 0x50, 0x8d, + 0x69, 0x44, 0x8c, 0x4d, 0x5b, 0x94, 0xcc, 0xe6, 0xdc, 0xf2, 0x56, 0x28, 0xf7, 0xd7, 0xb3, 0x3f, + 0x08, 0x78, 0x44, 0xcd, 0x76, 0x87, 0xef, 0x9d, 0x67, 0x6c, 0xf2, 0x03, 0x6e, 0x32, 0x6c, 0x6a, + 0xce, 0xf8, 0xf5, 0x82, 0xbb, 0x84, 0x04, 0xd1, 0x61, 0x0f, 0xd8, 0x81, 0xf9, 0x6b, 0x68, 0x91, + 0x3a, 0xc7, 0x92, 0x38, 0x67, 0x70, 0xd5, 0xc3, 0xc7, 0xc7, 0xbb, 0x92, 0x7c, 0x89, 0x26, 0xa6, + 0x91, 0xf4, 0xa3, 0xcf, 0x3a, 0xda, 0xda, 0xec, 0x47, 0x1a, 0xe6, 0xef, 0x9e, 0xd5, 0x9d, 0xa2, + 0x59, 0xf7, 0x5f, 0xd9, 0xcb, 0xf6, 0xd3, 0xef, 0x53, 0x99, 0x9b, 0xc0, 0x3b, 0xa6, 0x37, 0xe7, + 0xed, 0xd5, 0x7a, 0xdd, 0xc8, 0x31, 0xc9, 0x76, 0x8a, 0xc4, 0x2b, 0xb4, 0xf0, 0x3a, 0x1c, 0x77, + 0xc5, 0x37, 0x64, 0x3c, 0xb8, 0xcc, 0xfe, 0x3e, 0xed, 0x4a, 0x97, 0xe8, 0x68, 0x54, 0x93, 0xec, + 0xc5, 0xe7, 0x91, 0x91, 0x42, 0x5f, 0x4d, 0x7e, 0x3e, 0x8b, 0x9f, 0x50, 0x15, 0x5e, 0xab, 0x5d, + 0x30, 0xa5, 0x1a, 0xed, 0x3c, 0x37, 0xa5, 0x9d, 0xdd, 0x88, 0xf3, 0xa6, 0x27, 0x29, 0xc0, 0x55, + 0x47, 0x8b, 0x7d, 0x1b, 0x4d, 0xdf, 0x68, 0xb1, 0xb1, 0xbd, 0x3b, 0x67, 0xdb, 0x4b, 0x53, 0x37, + 0x31, 0x25, 0xde, 0xe5, 0xde, 0xd7, 0x03, 0xa1, 0xba, 0xc8, 0xf9, 0xf5, 0xc6, 0x24, 0x93, 0x57, + 0xa7, 0xa5, 0x4c, 0x63, 0x51, 0x54, 0x89, 0x8c, 0x5b, 0x52, 0xcc, 0x24, 0x0d, 0x99, 0xa4, 0x84, + 0x10, 0x91, 0xfd, 0x79, 0x36, 0x16, 0xe2, 0x61, 0x23, 0x5d, 0xed, 0x84, 0xba, 0xa9, 0x56, 0x68, + 0xe3, 0xf2, 0x9e, 0x64, 0xa1, 0xa5, 0xd7, 0xbd, 0x69, 0xa6, 0x8f, 0xb5, 0xad, 0xb7, 0x60, 0x3c, + 0xd3, 0x9f, 0xe3, 0xc5, 0xb5, 0xe2, 0xf4, 0x29, 0x42, 0xce, 0xf4, 0x33, 0x36, 0x95, 0xbe, 0x3c, + 0x68, 0xde, 0xdf, 0x88, 0xb6, 0xfd, 0x6d, 0x96, 0xc5, 0x3a, 0x90, 0x89, 0xb8, 0xe0, 0x53, 0x94, + 0xb5, 0xb8, 0x89, 0xe3, 0x52, 0xa6, 0x13, 0x90, 0x31, 0x57, 0x81, 0xcb, 0x93, 0x03, 0x5e, 0x2e, + 0xe6, 0x44, 0x87, 0x08, 0x56, 0x25, 0x4a, 0xd6, 0xa7, 0xb3, 0x7c, 0x2d, 0x13, 0xd4, 0x15, 0x44, + 0x71, 0x5b, 0xbb, 0x5d, 0x18, 0xb6, 0xd4, 0x54, 0x25, 0x7e, 0x7d, 0xc2, 0x9e, 0x44, 0x25, 0x14, + 0x52, 0xb4, 0x05, 0x12, 0x79, 0x59, 0x49, 0x19, 0x18, 0xe3, 0x47, 0x87, 0x91, 0x2e, 0x2b, 0xe1, + 0x23, 0xc5, 0xa3, 0xcb, 0x1e, 0x72, 0x2b, 0xe6, 0x08, 0x87, 0x93, 0x7e, 0x09, 0xa3, 0xad, 0x76, + 0xe4, 0x74, 0xac, 0xd0, 0x0d, 0x0d, 0x15, 0x14, 0xa5, 0xad, 0x8f, 0xb9, 0x18, 0xfe, 0x3c, 0x5d, + 0x9b, 0x16, 0x69, 0x77, 0xad, 0x48, 0xf5, 0x9c, 0xbf, 0xf7, 0x5c, 0x09, 0xbd, 0x63, 0x9a, 0xdb, + 0xe6, 0x48, 0x2e, 0xe1, 0x69, 0xe4, 0x47, 0xea, 0x45, 0x4a, 0xa6, 0x3c, 0x6c, 0xb0, 0x43, 0x46, + 0xa0, 0x5c, 0xce, 0xe9, 0xa7, 0x78, 0x55, 0x61, 0xef, 0x2d, 0xc1, 0x0e, 0x2a, 0x39, 0x62, 0xb4, + 0xee, 0x6d, 0x25, 0x4a, 0x9a, 0x40, 0xb0, 0x52, 0x1e, 0x7b, 0x5b, 0xd5, 0x51, 0xeb, 0x30, 0x55, + 0xee, 0x59, 0x5f, 0x28, 0x8d, 0x2d, 0x98, 0x94, 0x54, 0xc2, 0xd6, 0x66, 0x6a, 0x03, 0x10, 0xc2, + 0x69, 0xb6, 0x3e, 0x7e, 0xd1, 0xdc, 0xba, 0x7e, 0x05, 0x69, 0xe3, 0xd7, 0xa7, 0x9f, 0x95, 0x01, + 0x2f, 0x1c, 0xfc, 0x54, 0xc2, 0x21, 0xf3, 0xe4, 0x06, 0x7d, 0xe9, 0xce, 0x84, 0xed, 0xb1, 0x16, + 0xbb, 0x37, 0x8e, 0x83, 0xb2, 0x42, 0xbe, 0xb5, 0x33, 0x29, 0xf1, 0x34, 0x7b, 0x37, 0xf6, 0xd2, + 0xfe, 0x7f, 0x77, 0xf8, 0x54, 0x9d, 0xf4, 0x8f, 0x63, 0x47, 0x50, 0x25, 0x06, 0x35, 0x3c, 0x3b, + 0x75, 0x97, 0x1b, 0xa1, 0xa5, 0x42, 0x7c, 0xa6, 0xa2, 0xaf, 0xfa, 0x5a, 0x2f, 0x19, 0xa9, 0x71, + 0xad, 0x6e, 0x74, 0x22, 0x1a, 0x35, 0xda, 0x40, 0x42, 0x0b, 0x85, 0x98, 0x22, 0x88, 0x0f, 0x33, + 0x30, 0xd4, 0xae, 0x8c, 0x9c, 0xb6, 0x39, 0x1b, 0x68, 0x81, 0xb5, 0x05, 0x81, 0xab, 0xb9, 0x26, + 0x04, 0x3b, 0xfd, 0xd9, 0xd2, 0xe0, 0xeb, 0x58, 0xd6, 0xcb, 0xf9, 0xdc, 0x4d, 0xab, 0x3d, 0xbe, + 0x9b, 0xbd, 0x09, 0xcb, 0xfd, 0x0b, 0x45, 0x8d, 0x40, 0x4c, 0x5b, 0xe5, 0x7b, 0xc3, 0xcc, 0x8d, + 0x55, 0xde, 0x14, 0xdd, 0x62, 0x9d, 0x4c, 0x36, 0x66, 0xb0, 0x49, 0xa5, 0x6f, 0x49, 0xd5, 0x1f, + 0x0f, 0x62, 0xfb, 0xb8, 0x4b, 0x25, 0x4b, 0xd7, 0xd1, 0x8d, 0x94, 0x46, 0x1e, 0x49, 0x45, 0x6e, + 0x77, 0xa6, 0xc5, 0x74, 0x9f, 0xdf, 0x42, 0x20, 0xbd, 0x5f, 0x0c, 0x8b, 0x01, 0xf8, 0xec, 0x65, + 0xa0, 0x50, 0x1c, 0x46, 0x26, 0xc5, 0x3a, 0x15, 0x9a, 0x43, 0xdd, 0x6b, 0xdd, 0xf4, 0x91, 0x22, + 0x38, 0xb3, 0xe6, 0x4a, 0x24, 0x49, 0xf6, 0x1e, 0xed, 0xff, 0xbd, 0x8f, 0x10, 0xfc, 0x8e, 0x69, + 0xf6, 0x9f, 0xa8, 0x52, 0xba, 0x58, 0x37, 0x08, 0x22, 0x79, 0xfd, 0x5d, 0x6b, 0x29, 0xcc, 0x8b, + 0x97, 0x10, 0xcd, 0xa2, 0x50, 0x1b, 0x6c, 0xd2, 0xdc, 0x69, 0x65, 0xc4, 0x23, 0x15, 0x41, 0xd6, + 0x2f, 0xc7, 0x50, 0x9d, 0x48, 0x16, 0x9a, 0x4a, 0x93, 0xca, 0x40, 0xf9, 0xa4, 0x51, 0xbe, 0xe3, + 0x79, 0xf4, 0x7a, 0x8c, 0xef, 0xf2, 0xb0, 0xbf, 0x5e, 0xda, 0xa4, 0xec, 0x7b, 0xcc, 0xbf, 0xb1, + 0x65, 0x00, 0xfc, 0x9f, 0x36, 0xec, 0xb8, 0x2e, 0xd7, 0x96, 0x5f, 0x06, 0x7a, 0x46, 0x04, 0xaa, + 0x66, 0xd1, 0xfc, 0xe5, 0x38, 0x78, 0x80, 0x23, 0x62, 0xfd, 0x96, 0xd0, 0x04, 0xe9, 0xaa, 0x65, + 0xda, 0xfb, 0x45, 0x54, 0x30, 0x4a, 0x51, 0x1a, 0xde, 0xbb, 0x08, 0x71, 0xb6, 0x9d, 0x07, 0x68, + 0x78, 0x2f, 0xbe, 0xd4, 0xec, 0x50, 0xd7, 0x63, 0x4e, 0x57, 0xb2, 0x4d, 0x6f, 0xca, 0x00, 0x22, + 0x13, 0x0e, 0x9f, 0xba, 0xfc, 0x8c, 0x3c, 0x67, 0x94, 0x64, 0x94, 0x01, 0x40, 0x52, 0xe5, 0xf2, + 0x7d, 0x99, 0x2a, 0xdf, 0x7d, 0x75, 0x12, 0xa8, 0xfe, 0xd5, 0x67, 0xf8, 0xdb, 0x82, 0x7b, 0x64, + 0x4b, 0x58, 0x56, 0x43, 0xa0, 0x58, 0x11, 0x5c, 0x0e, 0xc3, 0x05, 0xf7, 0x63, 0xae, 0x1c, 0xf9, + 0x11, 0x86, 0xf3, 0xc2, 0xfd, 0xca, 0x9c, 0xea, 0x2d, 0x66, 0x75, 0x00, 0xcb, 0xd9, 0xdd, 0x70, + 0xae, 0x90, 0xf8, 0xa3, 0x70, 0x63, 0x7e, 0x3b, 0xb1, 0x8e, 0x74, 0x10, 0xa5, 0xd9, 0x78, 0xda, + 0xa7, 0xdb, 0x55, 0xe1, 0x69, 0x0b, 0xf9, 0x5f, 0x5f, 0x4c, 0xd2, 0x3e, 0x78, 0x79, 0x0c, 0xcd, + 0xd9, 0xfb, 0x57, 0xed, 0x50, 0xd4, 0xc9, 0x9a, 0xd3, 0xe6, 0xf7, 0x12, 0x5f, 0xe6, 0xaa, 0xbd, + 0x07, 0x3a, 0x0a, 0x1e, 0xdb, 0x0a, 0x15, 0xea, 0x8a, 0x36, 0xc7, 0xdc, 0x10, 0xb0, 0xd1, 0x3d, + 0x84, 0x4e, 0x36, 0xad, 0x19, 0xaf, 0x42, 0x22, 0xf8, 0x8a, 0xef, 0xee, 0x12, 0xf1, 0x86, 0x9b, + 0xe2, 0x39, 0xbd, 0x7f, 0xb4, 0xb6, 0x4e, 0x7b, 0x7d, 0x4d, 0xdd, 0x33, 0x42, 0x7e, 0xef, 0xb9, + 0x72, 0xf3, 0x8e, 0xe9, 0x2f, 0xaa, 0xe7, 0x56, 0x83, 0x35, 0x21, 0xc6, 0x58, 0xdf, 0x64, 0xf3, + 0x8b, 0xf1, 0x02, 0x61, 0xf1, 0x76, 0x25, 0x23, 0xb9, 0x27, 0xd0, 0x4e, 0x61, 0x9f, 0x3a, 0x12, + 0xe2, 0x65, 0xac, 0xb3, 0x9f, 0x05, 0xff, 0xe8, 0x16, 0xf7, 0x7f, 0xa4, 0xa3, 0x29, 0x57, 0x50, + 0x79, 0xb0, 0x5e, 0x14, 0xd4, 0xab, 0xb7, 0xa7, 0xa7, 0x43, 0xed, 0x7a, 0x4e, 0xa0, 0xab, 0x70, + 0xac, 0xf2, 0x50, 0x7e, 0xee, 0x7b, 0x93, 0xa8, 0xd2, 0xd8, 0xc0, 0xbf, 0x99, 0xd8, 0xc2, 0xd2, + 0xf0, 0x7c, 0xcd, 0x3d, 0x93, 0x04, 0x1e, 0x8f, 0xa1, 0xa4, 0x55, 0x6f, 0x13, 0xc9, 0xb5, 0xf5, + 0xe7, 0x5e, 0x8d, 0x3e, 0x32, 0x59, 0x1a, 0xe6, 0x23, 0x39, 0xfd, 0x85, 0x61, 0x18, 0xac, 0x82, + 0x60, 0x58, 0xa4, 0xee, 0x64, 0x22, 0xe7, 0xfe, 0x61, 0x5a, 0xe6, 0x0e, 0x84, 0xc7, 0xb2, 0x12, + 0x54, 0x23, 0x91, 0x60, 0x5f, 0x2c, 0x40, 0xfd, 0x7b, 0xad, 0x45, 0x74, 0xff, 0x27, 0xbd, 0x35, + 0xd8, 0xa7, 0x22, 0x70, 0xb9, 0xef, 0xa0, 0x97, 0xb8, 0x71, 0x75, 0xf3, 0x4f, 0x44, 0x99, 0x78, + 0x5b, 0xeb, 0x01, 0x0a, 0x94, 0xef, 0x9f, 0x87, 0x33, 0x48, 0xa4, 0x0c, 0xe9, 0x6c, 0xa3, 0x7b, + 0x8c, 0x4e, 0xf6, 0x9c, 0xa7, 0x89, 0x39, 0xdc, 0x6b, 0x7a, 0x19, 0xa5, 0x9e, 0xc7, 0x16, 0x43, + 0xf9, 0x22, 0x8c, 0xe7, 0x36, 0x2f, 0xe1, 0x79, 0x4b, 0xdc, 0x81, 0x57, 0x46, 0x65, 0x0f, 0xd9, + 0xe7, 0x3e, 0x3a, 0xdd, 0x73, 0x15, 0x5e, 0x93, 0x09, 0xac, 0x3f, 0x36, 0x52, 0x09, 0x99, 0xc2, + 0xf0, 0x78, 0x9b, 0x12, 0xec, 0x4a, 0x90, 0x11, 0x1d, 0x18, 0x9a, 0x16, 0x7a, 0x3e, 0x70, 0xa7, + 0xc4, 0x57, 0x13, 0x93, 0xd7, 0xdb, 0x73, 0xef, 0xdc, 0xad, 0x04, 0x10, 0x13, 0x5a, 0x93, 0x63, + 0x2c, 0x5d, 0xeb, 0xe8, 0x19, 0x6b, 0x15, 0x40, 0xe1, 0xdd, 0x65, 0xf3, 0xc2, 0x8f, 0xdd, 0xfa, + 0xb9, 0x93, 0xd1, 0xe2, 0x96, 0x4d, 0x74, 0x9f, 0x6b, 0xf5, 0x8b, 0x94, 0x73, 0xce, 0x3b, 0xfc, + 0xf7, 0x3e, 0x42, 0x85, 0x77, 0x4c, 0x4b, 0x20, 0xea, 0xa7, 0xbf, 0x20, 0x74, 0x75, 0xa6, 0x5d, + 0x64, 0xc8, 0x77, 0x0c, 0x49, 0x1b, 0xf4, 0x1f, 0x32, 0xb2, 0xdf, 0x0f, 0x8d, 0xc6, 0xd6, 0xd1, + 0x4b, 0xbb, 0x44, 0x99, 0x24, 0xd5, 0x03, 0xc3, 0x6b, 0x88, 0x33, 0x2c, 0x8e, 0x2f, 0x1b, 0x48, + 0x2e, 0xad, 0xa2, 0xd9, 0x1d, 0xf5, 0x14, 0xcf, 0xe7, 0x25, 0x50, 0x41, 0x53, 0x33, 0xcd, 0x4c, + 0xe2, 0x98, 0x92, 0x29, 0xe2, 0x72, 0xa9, 0xb4, 0x62, 0x63, 0x04, 0xdd, 0x67, 0x57, 0x09, 0x41, + 0x74, 0x91, 0x2c, 0xd9, 0xb6, 0x43, 0x39, 0xeb, 0xdf, 0xad, 0x96, 0xae, 0x26, 0xc0, 0x5b, 0xf3, + 0x87, 0xf5, 0x16, 0x1d, 0x3f, 0x1b, 0x5f, 0x53, 0x8c, 0xfc, 0x53, 0x20, 0xf4, 0xb4, 0xd9, 0x38, + 0x59, 0x29, 0x53, 0x5f, 0x31, 0xab, 0xc9, 0xd6, 0xb2, 0x4c, 0x26, 0xf9, 0x06, 0x99, 0xd6, 0xf3, + 0xf4, 0x9a, 0x5a, 0x0c, 0x3d, 0xbb, 0xc8, 0x7e, 0xce, 0x1b, 0xda, 0xc2, 0x4e, 0x2e, 0xf6, 0xe3, + 0x81, 0x42, 0x5f, 0x93, 0xdd, 0xb9, 0xfc, 0xd0, 0x8f, 0x5b, 0xae, 0xc9, 0x16, 0xfd, 0x6a, 0xae, + 0xb5, 0xc0, 0xf8, 0xe8, 0xa8, 0x26, 0x1e, 0xdb, 0xea, 0x21, 0x52, 0xeb, 0x94, 0x4a, 0x50, 0x78, + 0x8f, 0x5a, 0x6a, 0xbe, 0x94, 0xce, 0x26, 0x33, 0x1c, 0x1e, 0x7f, 0x1c, 0xac, 0x7c, 0x8f, 0x77, + 0x33, 0x16, 0xaa, 0x81, 0x15, 0xf5, 0xcf, 0x77, 0x75, 0xa8, 0x3c, 0x68, 0x7c, 0xd4, 0x07, 0x7f, + 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, + 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, + 0x07, 0x1f, 0xfc, 0xdf, 0xe4, 0x7f, 0xef, 0x83, 0xeb, 0xaf, 0x52, 0x09, 0x74, 0x7f, 0x09, 0x6d, + 0x34, 0x10, 0x5a, 0xc7, 0x3b, 0x9e, 0x3a, 0x23, 0x11, 0xce, 0x19, 0xc4, 0xe8, 0x20, 0x7a, 0xe9, + 0xf4, 0x40, 0x76, 0x31, 0x5c, 0x13, 0xdb, 0xd3, 0x50, 0xea, 0x57, 0x54, 0x63, 0x1d, 0x32, 0x84, + 0xc1, 0x7a, 0x36, 0xe1, 0x05, 0x84, 0x18, 0x9a, 0x8a, 0x5f, 0xf4, 0xc4, 0x45, 0x9b, 0x3a, 0xbb, + 0x71, 0x7c, 0xcc, 0xde, 0x21, 0xc2, 0x4e, 0x50, 0x1e, 0x1d, 0xb6, 0xa4, 0x3b, 0x48, 0x56, 0x4f, + 0x65, 0x17, 0x73, 0xdb, 0xd0, 0x5a, 0xff, 0xb9, 0xb5, 0xfd, 0x02, 0x22, 0x16, 0x60, 0x49, 0x1b, + 0xbb, 0x84, 0x43, 0x71, 0x51, 0x30, 0xba, 0x26, 0x38, 0x6d, 0x98, 0x26, 0xaf, 0x8f, 0xc8, 0xe9, + 0xa4, 0xba, 0xef, 0x59, 0xc8, 0x87, 0xad, 0x67, 0x69, 0x65, 0xbe, 0x7c, 0xed, 0x89, 0xb2, 0x48, + 0xb7, 0x77, 0x69, 0xd3, 0xe5, 0x11, 0xeb, 0x0b, 0xb9, 0x63, 0x61, 0x33, 0x5e, 0x3a, 0x22, 0x5e, + 0x12, 0x98, 0xed, 0x64, 0x51, 0x28, 0xc7, 0x7f, 0x20, 0x12, 0xd7, 0xfe, 0x98, 0xb1, 0x25, 0x87, + 0x21, 0xbd, 0x34, 0x81, 0x00, 0x8b, 0x15, 0xbd, 0xfe, 0x6b, 0x54, 0x3c, 0xbe, 0x42, 0x54, 0x6b, + 0xb9, 0xbf, 0x2f, 0x82, 0x9c, 0xd8, 0x61, 0x30, 0xd9, 0xde, 0x8f, 0xb3, 0x70, 0xfb, 0x95, 0x77, + 0x99, 0x4b, 0xc9, 0x7c, 0x87, 0x7d, 0x09, 0x69, 0xf2, 0x66, 0x75, 0xf6, 0x4b, 0xcf, 0x3c, 0xa8, + 0xe5, 0x5f, 0x14, 0x81, 0x7b, 0xef, 0x0c, 0x83, 0x27, 0x39, 0x6f, 0x45, 0x23, 0x79, 0x1f, 0x24, + 0x4d, 0xc9, 0x82, 0x4e, 0x40, 0x26, 0x3a, 0x0f, 0xfa, 0xe9, 0x81, 0x85, 0xa6, 0x50, 0xda, 0x3b, + 0x1b, 0x86, 0x3d, 0xbb, 0x8a, 0x0d, 0x13, 0x77, 0xc7, 0xbb, 0x5c, 0x39, 0x7e, 0x18, 0x1e, 0xc4, + 0xd5, 0xbe, 0xc7, 0xc4, 0x72, 0xfd, 0x9c, 0x96, 0x8a, 0x91, 0xb3, 0x47, 0xbf, 0x8a, 0xd0, 0xfd, + 0x77, 0x53, 0xbe, 0x65, 0xf3, 0x29, 0x0b, 0x9c, 0x1e, 0xb4, 0xc6, 0x18, 0x05, 0xff, 0xe1, 0x3e, + 0xb4, 0x89, 0xf7, 0xcf, 0x77, 0xfc, 0xe7, 0xd1, 0xaf, 0xe9, 0xf9, 0x6c, 0x06, 0x76, 0xfe, 0x81, + 0x51, 0xe6, 0x0e, 0x62, 0x1d, 0x53, 0xce, 0xee, 0x81, 0xd4, 0x35, 0xba, 0xf0, 0xab, 0x4d, 0xce, + 0x1f, 0x37, 0x7c, 0x2a, 0x4a, 0x6f, 0x5a, 0xcf, 0x1e, 0x93, 0xe8, 0xd8, 0x4a, 0xfe, 0xab, 0x58, + 0x44, 0x1f, 0xdb, 0xc8, 0x13, 0x85, 0xb6, 0x58, 0x05, 0x43, 0xa0, 0xb5, 0xf4, 0xeb, 0x3b, 0xd2, + 0x1e, 0x56, 0x4a, 0xb2, 0x20, 0xb7, 0x6c, 0x11, 0x79, 0xb5, 0xf5, 0xe7, 0x57, 0x36, 0x67, 0xe2, + 0xbb, 0xaa, 0x4d, 0xed, 0x16, 0x2f, 0x96, 0xd0, 0x6a, 0xa5, 0x42, 0x9a, 0x06, 0x87, 0x28, 0x09, + 0x75, 0xa6, 0xb2, 0xae, 0xce, 0x1c, 0x4b, 0x91, 0xe4, 0x63, 0xab, 0xd2, 0xa7, 0xbc, 0xad, 0x6f, + 0xbc, 0xa2, 0x37, 0x6e, 0xd2, 0x97, 0x47, 0xaf, 0x6b, 0x69, 0xaa, 0x2a, 0x4d, 0x25, 0xd4, 0x26, + 0xa0, 0xd9, 0x1e, 0x1c, 0x8e, 0x82, 0x7a, 0x04, 0x1a, 0x1c, 0x68, 0x0b, 0x3e, 0x51, 0xa5, 0xaf, + 0x03, 0xcf, 0x42, 0xf5, 0x41, 0xfc, 0xec, 0xaa, 0x16, 0xd9, 0x6f, 0x61, 0x15, 0xc2, 0x58, 0x7a, + 0x4e, 0xa8, 0xaa, 0x68, 0x20, 0x79, 0x7b, 0x58, 0x77, 0x4e, 0x16, 0x8d, 0x0f, 0xd3, 0x64, 0xdc, + 0x07, 0x44, 0xbf, 0xe8, 0x0f, 0xef, 0x27, 0x75, 0xbb, 0x99, 0xd6, 0x15, 0x31, 0xd0, 0xb7, 0xfa, + 0xa2, 0xdb, 0x6f, 0xed, 0x23, 0x2b, 0x55, 0xb3, 0x03, 0x1b, 0x78, 0x1b, 0xcb, 0x5b, 0xd6, 0xbb, + 0xfe, 0x72, 0x21, 0xee, 0xd9, 0x79, 0xc5, 0xa6, 0x60, 0x62, 0xb5, 0x38, 0xc8, 0x8c, 0xe8, 0xca, + 0x24, 0x7e, 0x11, 0x7a, 0x49, 0x6c, 0xb9, 0xc1, 0x42, 0xf9, 0xdc, 0xb3, 0xfc, 0xb6, 0x54, 0x76, + 0x4d, 0x8d, 0x79, 0xeb, 0x43, 0x72, 0x5c, 0xf3, 0x0a, 0x12, 0x89, 0x90, 0x6f, 0xa7, 0x1e, 0xcd, + 0x3c, 0xbe, 0xb2, 0xa7, 0xc5, 0x78, 0x7c, 0xed, 0x06, 0x02, 0xdd, 0xd9, 0xe5, 0x78, 0x17, 0x6d, + 0x7e, 0xa9, 0x79, 0x22, 0x48, 0x7d, 0xfa, 0x4d, 0x8a, 0x85, 0xec, 0x9c, 0xfe, 0x7d, 0xd3, 0xf8, + 0xb5, 0xff, 0x7b, 0x1f, 0x7f, 0xe7, 0xc1, 0x3b, 0xa6, 0x99, 0x79, 0x7a, 0x1b, 0x66, 0x08, 0xb7, + 0x83, 0x6c, 0x00, 0x11, 0xfe, 0x38, 0x45, 0x46, 0xf6, 0xfd, 0xb6, 0x44, 0x82, 0x79, 0x6b, 0x2b, + 0x80, 0xeb, 0x92, 0xde, 0x05, 0xa3, 0x50, 0x16, 0xd0, 0xbb, 0x9c, 0xd2, 0xc9, 0x9b, 0xb2, 0xdd, + 0x1e, 0x59, 0xde, 0x87, 0x0b, 0xb8, 0x56, 0x2a, 0xc6, 0xd5, 0x06, 0x57, 0x90, 0x19, 0x46, 0xf1, + 0xfb, 0x30, 0x3d, 0x0a, 0x3b, 0xc2, 0xd5, 0x7b, 0xf7, 0xd7, 0x16, 0xea, 0xb9, 0x1b, 0xaa, 0xe4, + 0x22, 0x5f, 0xba, 0x9f, 0xb6, 0x35, 0x34, 0x1a, 0x90, 0x70, 0x21, 0x1b, 0x61, 0xc3, 0xd1, 0xd5, + 0x4d, 0x4e, 0xfa, 0xe3, 0x11, 0x83, 0xee, 0x53, 0x68, 0x8f, 0xd0, 0xc9, 0x18, 0xf3, 0xff, 0xab, + 0x13, 0xaa, 0x12, 0xf9, 0x63, 0x6a, 0x0a, 0x66, 0xf0, 0x50, 0x7e, 0x23, 0xbf, 0x4f, 0xc2, 0x06, + 0xc3, 0xdb, 0x53, 0xc4, 0xdf, 0xf6, 0x2f, 0x72, 0x63, 0xb6, 0xbf, 0x4f, 0x58, 0x7f, 0xee, 0x97, + 0x57, 0x09, 0x43, 0x78, 0x7b, 0x2c, 0x6e, 0x67, 0xd2, 0xbb, 0x15, 0x4d, 0xcc, 0x85, 0xac, 0x08, + 0x1c, 0x4e, 0xa5, 0xb8, 0x2c, 0x0f, 0xbc, 0xdc, 0x2c, 0x8d, 0x7c, 0xbb, 0xf5, 0x90, 0xed, 0xfe, + 0x55, 0x8f, 0xd7, 0x87, 0x40, 0x9b, 0xe7, 0x42, 0x52, 0x69, 0x4e, 0x1d, 0x10, 0x75, 0x42, 0x25, + 0x6d, 0xc8, 0x0a, 0x7a, 0x77, 0x9b, 0xb8, 0x1c, 0x10, 0x90, 0x68, 0xd8, 0x9a, 0x6a, 0xa8, 0xc7, + 0xb9, 0x28, 0xa9, 0x8b, 0x1e, 0x27, 0x58, 0x33, 0x1b, 0x91, 0xb1, 0x98, 0x1e, 0xe9, 0x0d, 0x99, + 0x10, 0xc7, 0x65, 0x52, 0x72, 0x4b, 0xdb, 0x74, 0xe0, 0x86, 0x09, 0xd4, 0xaf, 0x33, 0xb7, 0x4f, + 0x3e, 0x7a, 0x3d, 0x19, 0xd1, 0x42, 0x16, 0x73, 0x0f, 0x86, 0xa5, 0x4b, 0x19, 0xaf, 0xbf, 0x82, + 0xdb, 0xcd, 0x17, 0x34, 0x61, 0x18, 0xfa, 0xfd, 0x5b, 0xb6, 0x9f, 0x89, 0xb9, 0x74, 0x1c, 0x90, + 0xc3, 0x9b, 0xdb, 0xd7, 0xb4, 0xe6, 0xcf, 0xd3, 0x40, 0x38, 0x55, 0xbd, 0x45, 0x43, 0x6d, 0xa6, + 0xd9, 0xf1, 0x7b, 0x77, 0x79, 0x27, 0xf0, 0x8e, 0x69, 0x4e, 0x27, 0xbd, 0x1d, 0xd2, 0xc8, 0x64, + 0x34, 0xce, 0xe6, 0x49, 0xc9, 0x65, 0xbf, 0x58, 0x40, 0x4c, 0xb4, 0x7a, 0x57, 0x5c, 0x4a, 0x66, + 0x50, 0x97, 0x53, 0xfc, 0xf9, 0x49, 0x7e, 0x5e, 0xa1, 0xf6, 0xea, 0xc8, 0xcc, 0x82, 0xc1, 0xb9, + 0x77, 0x93, 0x33, 0x38, 0x82, 0xac, 0x15, 0x2f, 0x9d, 0x56, 0x57, 0x6c, 0xfe, 0x9d, 0x40, 0xf8, + 0x2f, 0xdc, 0x3d, 0x27, 0xc0, 0xb5, 0xf3, 0x19, 0xa1, 0xc3, 0x81, 0xb0, 0x51, 0x14, 0xb8, 0xa8, + 0x70, 0x0c, 0x03, 0xcd, 0x4a, 0x3a, 0xd2, 0xf5, 0x27, 0xe7, 0x90, 0xd7, 0x19, 0xc9, 0x98, 0x34, + 0xb8, 0xc3, 0x1b, 0x0e, 0xe7, 0xbf, 0x0a, 0x7d, 0xde, 0x74, 0xa6, 0x2d, 0x4d, 0xe8, 0x26, 0x6a, + 0xf2, 0x09, 0xc0, 0x6e, 0x45, 0x23, 0x44, 0xc9, 0xd0, 0x79, 0xca, 0x00, 0x6b, 0x99, 0xf7, 0x83, + 0xac, 0xbc, 0x22, 0x0a, 0x4f, 0xa6, 0x0b, 0xe1, 0xe2, 0x74, 0xae, 0x2c, 0x50, 0xf2, 0x44, 0x02, + 0x11, 0xc2, 0x7c, 0xcd, 0xa6, 0x6d, 0x72, 0x9b, 0x4f, 0x11, 0x6c, 0x4e, 0x50, 0x01, 0xbc, 0xf1, + 0x99, 0xef, 0x63, 0x68, 0xe4, 0x7a, 0x39, 0x14, 0xee, 0xa5, 0xe1, 0xbd, 0xbe, 0xb0, 0x18, 0xdf, + 0xeb, 0xca, 0xeb, 0x3e, 0xbd, 0x6e, 0x52, 0x7e, 0x7e, 0xcd, 0xde, 0xa6, 0x89, 0x20, 0xa3, 0xed, + 0xb8, 0x7f, 0x8c, 0x62, 0x08, 0xb0, 0x84, 0x17, 0x72, 0xf4, 0x59, 0x47, 0x73, 0x9c, 0x0e, 0x91, + 0x05, 0x2b, 0x1a, 0x1c, 0xca, 0xc2, 0x26, 0xe6, 0x27, 0x75, 0x4e, 0xe6, 0x55, 0xa9, 0xb9, 0x83, + 0x7f, 0xe3, 0x16, 0x39, 0xd9, 0xb6, 0x52, 0x88, 0xbe, 0xb5, 0x65, 0xc2, 0xb4, 0x21, 0x66, 0x3b, + 0xec, 0x18, 0x16, 0xc2, 0x9c, 0xed, 0x93, 0x59, 0x9b, 0x9d, 0xef, 0x6f, 0xde, 0x4a, 0xc3, 0x81, + 0x56, 0x78, 0x8f, 0x5a, 0x45, 0x4d, 0xb1, 0x61, 0x4d, 0x4c, 0x0b, 0xdc, 0x9a, 0x0d, 0x58, 0x98, + 0x66, 0x75, 0x24, 0x2e, 0x6d, 0x82, 0x5e, 0x35, 0x91, 0xa2, 0x1e, 0x45, 0xc0, 0x50, 0x67, 0xd8, + 0x0d, 0xfe, 0x36, 0x31, 0x41, 0xa4, 0x0c, 0xfd, 0xb3, 0xe9, 0xa1, 0x5e, 0xf2, 0x9d, 0xb2, 0x6c, + 0xe4, 0x10, 0x79, 0xbb, 0x69, 0xbf, 0x05, 0xbc, 0x4b, 0xd5, 0x91, 0xfb, 0x04, 0x13, 0x89, 0x14, + 0xd5, 0x24, 0xb5, 0x7f, 0x86, 0xb1, 0x3a, 0x46, 0x57, 0x24, 0xbf, 0x75, 0xdc, 0xa0, 0x3b, 0x12, + 0xbe, 0x91, 0x1d, 0xca, 0x1d, 0xf1, 0x9b, 0xa1, 0xe2, 0x21, 0x11, 0x6c, 0x57, 0xcd, 0xbb, 0x64, + 0x70, 0x55, 0x1b, 0x64, 0xc1, 0x7c, 0xa0, 0x71, 0x46, 0xb2, 0x05, 0xb0, 0x9f, 0xf9, 0x82, 0x7a, + 0xb5, 0xb3, 0x1b, 0x42, 0x65, 0x73, 0x81, 0x4a, 0xc0, 0x18, 0xa8, 0xaa, 0x57, 0xe9, 0x3e, 0x1e, + 0xbb, 0x0e, 0xce, 0x97, 0x9e, 0xd3, 0xce, 0x76, 0xd9, 0xea, 0x0d, 0x8a, 0x37, 0xe5, 0x2d, 0x27, + 0xd3, 0x80, 0x00, 0x98, 0x99, 0xc8, 0x37, 0xee, 0x09, 0x91, 0xb0, 0xa6, 0x64, 0x6f, 0x6a, 0x91, + 0x1f, 0xfe, 0x45, 0xf5, 0xcb, 0x65, 0x68, 0x6a, 0x6f, 0x58, 0x6a, 0xa4, 0x0c, 0xb2, 0x8c, 0x17, + 0xad, 0x86, 0x47, 0x6a, 0xed, 0xd6, 0x78, 0xd8, 0x10, 0x9d, 0x1d, 0xaf, 0x2e, 0x09, 0x8b, 0x0f, + 0xf7, 0xe9, 0x5b, 0xe9, 0x45, 0x28, 0x54, 0xa2, 0x02, 0x09, 0xb5, 0xe6, 0xe8, 0xec, 0x6a, 0xc4, + 0x2f, 0x6d, 0x07, 0x13, 0xd5, 0xb0, 0x13, 0x5f, 0x09, 0x37, 0xa2, 0x1d, 0x4c, 0x54, 0x8e, 0xcf, + 0x64, 0x6b, 0xde, 0x60, 0x63, 0x49, 0x10, 0xf3, 0xed, 0xb6, 0x27, 0x68, 0xed, 0x8a, 0xfe, 0xdc, + 0x51, 0xb8, 0xb3, 0x6c, 0xa1, 0xfc, 0x39, 0xc9, 0x8c, 0xbf, 0x56, 0xeb, 0x3c, 0x52, 0xf0, 0xd8, + 0x64, 0x9c, 0x5f, 0x21, 0x62, 0xd0, 0xa6, 0xef, 0x75, 0x08, 0x3b, 0xdc, 0x5d, 0xef, 0x62, 0x2f, + 0xd3, 0x06, 0x62, 0x6b, 0x50, 0x1a, 0x49, 0x7d, 0xd8, 0x2a, 0xf2, 0xa3, 0x58, 0x92, 0xb6, 0x72, + 0xbc, 0x21, 0xf8, 0xd6, 0x78, 0x35, 0x96, 0x71, 0xb6, 0x53, 0x4e, 0xe9, 0x62, 0xe3, 0xa8, 0xd2, + 0x5e, 0xb5, 0x26, 0x1a, 0x22, 0xbb, 0xda, 0xf5, 0xa3, 0xd2, 0xfd, 0xcb, 0xc3, 0xc0, 0xea, 0xe6, + 0xd3, 0x90, 0x70, 0x5a, 0x93, 0xfc, 0x3e, 0xdb, 0xcc, 0x04, 0xbf, 0xb3, 0xa6, 0xd9, 0xbf, 0x12, + 0x4a, 0xb1, 0x78, 0x82, 0xbb, 0xcf, 0xa2, 0x73, 0xb6, 0x74, 0x92, 0x39, 0xe5, 0x78, 0xae, 0xea, + 0xa9, 0xd1, 0x5e, 0x2d, 0xa1, 0x81, 0xa6, 0x76, 0x62, 0x68, 0x3b, 0x3c, 0xd9, 0xc5, 0xac, 0xa3, + 0x06, 0xa3, 0x1f, 0x1f, 0x40, 0xbb, 0x4c, 0x03, 0x06, 0x14, 0xe3, 0x9b, 0x06, 0xa2, 0x68, 0xd2, + 0xee, 0x2e, 0x85, 0x11, 0xab, 0x5f, 0x46, 0x52, 0xf5, 0x2e, 0xf3, 0x53, 0x65, 0x04, 0x05, 0x5f, + 0x48, 0xd4, 0xa9, 0x9c, 0x1b, 0xee, 0x9f, 0xff, 0xca, 0xc4, 0x65, 0x9a, 0xc3, 0x61, 0xff, 0xc8, + 0x26, 0x6e, 0x2c, 0xa7, 0x1e, 0xcf, 0x33, 0x51, 0x5b, 0x43, 0x84, 0xcf, 0x4b, 0xa7, 0xec, 0x15, + 0x2d, 0x36, 0xa5, 0xea, 0x18, 0x80, 0xd0, 0xf4, 0x8a, 0x1d, 0x8a, 0x0a, 0x33, 0xb1, 0x92, 0x57, + 0x39, 0x1e, 0x8e, 0xa6, 0x0f, 0x39, 0xfe, 0x65, 0x0b, 0xca, 0x9d, 0x1d, 0x25, 0xe4, 0x12, 0x22, + 0xe8, 0xa1, 0x2b, 0x5b, 0xba, 0xd7, 0x88, 0xba, 0xd7, 0xc2, 0x66, 0xa8, 0xe1, 0x8e, 0x57, 0x45, + 0xf5, 0xf7, 0x7d, 0x4c, 0x1e, 0x38, 0xcc, 0xce, 0x1b, 0x60, 0xed, 0x09, 0xb3, 0x18, 0xb6, 0xd2, + 0xc5, 0x72, 0xdc, 0xab, 0x5a, 0x40, 0x8d, 0x5e, 0x07, 0xda, 0xb1, 0x35, 0x0e, 0x83, 0x95, 0x3d, + 0x22, 0xba, 0x10, 0xe7, 0xe0, 0x89, 0x6a, 0x4e, 0x10, 0x94, 0xc1, 0x96, 0x3e, 0xb6, 0xcb, 0x3d, + 0xd8, 0x83, 0xdc, 0x8c, 0x82, 0x17, 0x64, 0x6a, 0xc4, 0x68, 0xf7, 0xb0, 0xbd, 0x06, 0x1e, 0x7f, + 0x9a, 0x6c, 0x72, 0xae, 0xe0, 0x65, 0x13, 0x30, 0x3a, 0x99, 0x33, 0xf3, 0xb6, 0x29, 0x46, 0x45, + 0x2a, 0x81, 0x83, 0x32, 0x09, 0x7c, 0xd5, 0x79, 0xe1, 0x2a, 0xaf, 0x7a, 0xf2, 0x92, 0xc5, 0xb3, + 0x19, 0xb1, 0xfa, 0x7b, 0xbd, 0xdb, 0xc2, 0xd7, 0x48, 0x22, 0xcc, 0xf5, 0xd7, 0xde, 0x76, 0x53, + 0x83, 0x33, 0x33, 0xd2, 0x68, 0x77, 0x77, 0x2a, 0xb8, 0xec, 0x21, 0x29, 0xb5, 0x3a, 0x9c, 0xed, + 0xcd, 0xeb, 0xe7, 0xf1, 0x83, 0x10, 0xfd, 0x39, 0xfc, 0x7d, 0xb6, 0xd9, 0xcd, 0x3b, 0xa6, 0xd7, + 0x46, 0x06, 0x93, 0x57, 0x89, 0x3c, 0x0e, 0x81, 0xc0, 0x04, 0x47, 0xe0, 0xdd, 0x9c, 0x75, 0xcf, + 0xb3, 0x1a, 0x8b, 0x08, 0xbd, 0x42, 0xd4, 0xb2, 0x07, 0xcd, 0x70, 0xf8, 0xf2, 0xcb, 0xa9, 0x7e, + 0x13, 0x89, 0xb4, 0x6e, 0x90, 0xf0, 0xe4, 0x41, 0x98, 0xee, 0xd4, 0x8b, 0x52, 0x47, 0x5f, 0x5b, + 0xb7, 0x28, 0x24, 0x4e, 0x31, 0x93, 0xb8, 0x08, 0x9a, 0x6f, 0x4a, 0x1e, 0x02, 0x21, 0x40, 0xa7, + 0xa4, 0x52, 0xba, 0xa7, 0x94, 0x0c, 0x30, 0x8a, 0x5d, 0x14, 0x52, 0x25, 0x81, 0x3f, 0x64, 0x43, + 0xc6, 0x78, 0xab, 0x9a, 0xf1, 0xba, 0x71, 0xe6, 0x30, 0x11, 0x9e, 0x44, 0xa5, 0x94, 0xb6, 0x53, + 0x2d, 0x0e, 0x53, 0x7d, 0xb0, 0x3e, 0xf4, 0xb2, 0x27, 0x67, 0xfe, 0xb5, 0xc9, 0x84, 0x87, 0xf5, + 0x0a, 0x82, 0xa8, 0xc5, 0x22, 0x16, 0x49, 0x47, 0x28, 0xc4, 0x4e, 0x9f, 0x67, 0x77, 0x2b, 0xd1, + 0xab, 0xe1, 0x0c, 0xb2, 0x15, 0x9c, 0x99, 0x8d, 0x03, 0x91, 0x6e, 0x68, 0x1a, 0x7f, 0x5b, 0x5c, + 0x9f, 0x21, 0xc3, 0x69, 0x23, 0x02, 0x50, 0xed, 0x39, 0xf8, 0xee, 0xac, 0xad, 0x5a, 0x95, 0x0b, + 0x9b, 0xe6, 0x9c, 0xa1, 0x13, 0x94, 0x02, 0xd6, 0xa8, 0x04, 0x0f, 0x3f, 0xc9, 0xc7, 0x9f, 0x10, + 0x08, 0xf8, 0xb6, 0x1c, 0xf3, 0xf4, 0xef, 0x22, 0x9b, 0x85, 0x16, 0x54, 0xcb, 0x15, 0x47, 0x8e, + 0x36, 0x2e, 0x78, 0xfb, 0xa6, 0xdc, 0xae, 0x08, 0x31, 0xc9, 0x00, 0xbd, 0x14, 0xf9, 0x2c, 0xda, + 0x4e, 0x24, 0x05, 0x00, 0x6e, 0x02, 0x37, 0xb8, 0xd7, 0x6d, 0x6d, 0xb1, 0x7b, 0x39, 0x96, 0x49, + 0xa5, 0xc7, 0x95, 0x65, 0x9e, 0x00, 0x6f, 0x6c, 0x40, 0xe7, 0xd5, 0x8a, 0x58, 0x50, 0xc3, 0x5b, + 0xc9, 0x2d, 0x91, 0xa3, 0xa9, 0xdd, 0x04, 0x6a, 0xab, 0x32, 0x3d, 0xe7, 0xae, 0xd5, 0xb3, 0x9c, + 0x36, 0x67, 0xf4, 0x84, 0xad, 0x39, 0x33, 0xab, 0x71, 0x84, 0x3d, 0xd9, 0xd5, 0x63, 0x1c, 0xe7, + 0xf2, 0x1e, 0x07, 0xfd, 0x8d, 0x98, 0x45, 0xd6, 0xfc, 0xbd, 0xe7, 0x4a, 0xe1, 0x1d, 0xd3, 0x62, + 0xf1, 0xf6, 0x51, 0xd0, 0xdf, 0xcb, 0xfa, 0xfc, 0xf3, 0xe2, 0x42, 0x84, 0xb6, 0x88, 0x4d, 0x57, + 0x3f, 0x1a, 0x29, 0x17, 0xea, 0x65, 0xe4, 0x28, 0xc9, 0xb0, 0x36, 0x04, 0x7b, 0x53, 0xb1, 0x1e, + 0x1c, 0xc2, 0x7a, 0x39, 0x78, 0x37, 0x64, 0xe4, 0x04, 0x57, 0xd7, 0xdd, 0x5b, 0xaf, 0xdf, 0xad, + 0xdd, 0x2c, 0x1d, 0xf9, 0x38, 0x46, 0xc2, 0x83, 0x06, 0xea, 0x86, 0xf3, 0xc7, 0x82, 0x84, 0xeb, + 0x9c, 0xd1, 0x49, 0xad, 0x4e, 0x13, 0x7b, 0x33, 0x91, 0xa0, 0xa7, 0x26, 0x41, 0xd3, 0xef, 0xef, + 0xd4, 0x35, 0x9d, 0x4e, 0xca, 0x0e, 0x9f, 0x28, 0x0f, 0x9e, 0xc2, 0xa7, 0x93, 0xba, 0xfa, 0x6c, + 0x8a, 0x48, 0x3b, 0xcd, 0x13, 0x65, 0x9e, 0x07, 0x9c, 0xac, 0xe9, 0x4b, 0xa6, 0xe5, 0xf9, 0xb9, + 0xb8, 0xcf, 0xc9, 0x29, 0x48, 0x7f, 0x4e, 0x56, 0x4a, 0xf1, 0xd7, 0x5a, 0xc7, 0x7c, 0x76, 0xf7, + 0x16, 0x3c, 0xee, 0x62, 0x63, 0x06, 0xd8, 0x38, 0xf7, 0x6c, 0xac, 0x3a, 0x15, 0x41, 0x2d, 0xcb, + 0x7d, 0xed, 0x5f, 0x63, 0x1b, 0x7e, 0x46, 0xc2, 0xe1, 0x4b, 0xe8, 0x13, 0xfe, 0x6a, 0x06, 0x94, + 0xed, 0x17, 0xc4, 0x27, 0x55, 0x5a, 0x41, 0x5a, 0xb3, 0x2b, 0x2c, 0x9a, 0x42, 0x93, 0x5c, 0x39, + 0xf2, 0xb3, 0x25, 0x26, 0x91, 0xda, 0x70, 0x0b, 0x47, 0xc7, 0x8b, 0xa5, 0x4e, 0xf8, 0xd4, 0xdf, + 0xbf, 0x47, 0x4f, 0xdb, 0x7a, 0xfb, 0xae, 0x37, 0x05, 0xa6, 0x5e, 0xf0, 0x0d, 0xcc, 0xe4, 0xfd, + 0xbb, 0x32, 0x70, 0xc1, 0x50, 0x86, 0xfc, 0x9e, 0x0a, 0xa7, 0x22, 0x61, 0x40, 0x99, 0xec, 0x1d, + 0xc6, 0xff, 0x45, 0xaf, 0x02, 0xdb, 0xc3, 0x76, 0xd1, 0x45, 0x79, 0xf4, 0x6b, 0xa8, 0x76, 0xb7, + 0x39, 0xca, 0x77, 0xcf, 0x2a, 0x5d, 0x03, 0xec, 0x51, 0xf6, 0xe1, 0xb7, 0x58, 0x66, 0x1a, 0xee, + 0x25, 0x60, 0xf6, 0x51, 0x99, 0xc9, 0x98, 0x3b, 0x3a, 0x4b, 0xac, 0x73, 0x4f, 0x41, 0x9b, 0x10, + 0xb4, 0xc5, 0x3d, 0x7a, 0xb9, 0xf1, 0xbc, 0x4a, 0xe2, 0x8d, 0xf8, 0xef, 0xd1, 0x63, 0x26, 0xf9, + 0x8e, 0x69, 0x19, 0x53, 0x88, 0xfb, 0x55, 0x5b, 0x02, 0x07, 0x34, 0x3f, 0xe7, 0x3c, 0xf7, 0xb3, + 0x55, 0x12, 0xb9, 0x2b, 0x34, 0x40, 0x6b, 0x74, 0xaf, 0xc4, 0x3d, 0xfe, 0x03, 0x07, 0xf8, 0xea, + 0x96, 0x52, 0x0f, 0xa6, 0xd0, 0x90, 0xb5, 0xa7, 0x7d, 0x78, 0x48, 0x9f, 0x0b, 0x2b, 0xd4, 0x12, + 0x5f, 0xa1, 0xb2, 0x6c, 0x91, 0x98, 0x2c, 0x8c, 0x9b, 0xf9, 0x59, 0xc6, 0x53, 0x2c, 0x3d, 0x0b, + 0x77, 0x63, 0x44, 0x54, 0x6c, 0x4e, 0xfd, 0x70, 0x84, 0x73, 0x56, 0xe3, 0x1f, 0xcd, 0x08, 0x1a, + 0x6c, 0xea, 0xd5, 0x31, 0x85, 0xe7, 0x25, 0x56, 0x23, 0x9b, 0xfe, 0x35, 0x7a, 0xca, 0x4c, 0x8d, + 0x13, 0x89, 0xb6, 0x3f, 0xfc, 0xfd, 0xe1, 0xb4, 0x50, 0x55, 0xff, 0x4c, 0xb5, 0x2b, 0xa8, 0x8b, + 0x18, 0xcb, 0xf2, 0xf4, 0xdb, 0x79, 0xe2, 0xf8, 0xc7, 0x6b, 0xe6, 0xd5, 0x8e, 0x90, 0x53, 0xd9, + 0x20, 0xf6, 0x08, 0xcd, 0xa1, 0x43, 0x11, 0x93, 0xcf, 0x75, 0x75, 0xe5, 0xd6, 0x63, 0x93, 0x4f, + 0x73, 0x90, 0xf1, 0x43, 0xf5, 0xf2, 0x60, 0xcf, 0x13, 0x6e, 0x5b, 0x75, 0x6e, 0x36, 0x2d, 0xa0, + 0x9d, 0x9c, 0xb0, 0xdc, 0x9f, 0xd4, 0x5a, 0xed, 0x8f, 0xbe, 0xd9, 0x9b, 0xa7, 0x4b, 0x98, 0x61, + 0xf5, 0x45, 0x92, 0xf2, 0x2d, 0xb7, 0xf2, 0xdb, 0xec, 0xe2, 0xde, 0x13, 0xae, 0xd6, 0xed, 0x1f, + 0x3d, 0x63, 0x0b, 0xdc, 0xf3, 0xd0, 0xbc, 0xd1, 0xe7, 0x9e, 0x91, 0xe8, 0x5d, 0x32, 0xfd, 0x16, + 0x83, 0xee, 0xdb, 0xbb, 0x52, 0x4f, 0x2d, 0x01, 0x48, 0xe3, 0x82, 0x6d, 0xa4, 0x63, 0x71, 0xab, + 0x87, 0x5c, 0xa7, 0x96, 0xde, 0x60, 0x20, 0x0a, 0x4b, 0x6b, 0x43, 0x00, 0x87, 0x20, 0x0d, 0xac, + 0x49, 0xb6, 0xe5, 0xdb, 0x3f, 0xd2, 0xca, 0x5b, 0xc9, 0x59, 0xa2, 0x32, 0xc9, 0x9b, 0x47, 0x53, + 0xa9, 0x57, 0x08, 0xad, 0x26, 0xb3, 0x97, 0x5e, 0x30, 0x99, 0x22, 0xba, 0xa8, 0x4a, 0x72, 0xdf, + 0x84, 0x6f, 0x41, 0x52, 0x13, 0x52, 0x03, 0xd0, 0x42, 0x11, 0xc7, 0x81, 0x99, 0xff, 0x7f, 0xdd, + 0x6d, 0x00, 0x25, 0xe3, 0x9d, 0xdf, 0x70, 0x36, 0x3e, 0xde, 0x49, 0x4f, 0xff, 0x14, 0x9a, 0x49, + 0xad, 0x06, 0x44, 0x44, 0xdd, 0x45, 0x62, 0x28, 0x82, 0x51, 0x8b, 0xd7, 0xa2, 0x8f, 0x17, 0x8f, + 0x2d, 0xe9, 0x72, 0x6d, 0x84, 0x45, 0xc4, 0xb9, 0xd1, 0xb0, 0xc1, 0x77, 0xd5, 0x5b, 0x2b, 0x5c, + 0xef, 0xa8, 0xc5, 0xe1, 0x1e, 0x96, 0x61, 0x76, 0xe8, 0xbe, 0x46, 0xaa, 0x26, 0xe9, 0xd7, 0x83, + 0x17, 0x3d, 0x18, 0xc1, 0xb7, 0x24, 0x87, 0x63, 0x78, 0xd4, 0xb3, 0xd7, 0x92, 0xeb, 0x06, 0xaa, + 0x85, 0x17, 0xca, 0x8a, 0xdd, 0xda, 0x54, 0x7d, 0x64, 0x62, 0xd4, 0x74, 0xe4, 0xc5, 0x98, 0xcb, + 0x37, 0xde, 0x23, 0x0d, 0x76, 0x55, 0x60, 0x9a, 0x55, 0x69, 0x76, 0x13, 0x45, 0x83, 0xa9, 0x97, + 0xb9, 0x85, 0xec, 0xb5, 0xb5, 0xa2, 0xf6, 0x6b, 0x2a, 0xc1, 0xfe, 0xac, 0xeb, 0xa5, 0x8b, 0x56, + 0x4a, 0x71, 0xb0, 0x62, 0xb1, 0xdf, 0x07, 0xbf, 0x48, 0xea, 0xc7, 0x57, 0x59, 0x9d, 0x25, 0x71, + 0xd8, 0x9c, 0x1c, 0xa1, 0x93, 0x6c, 0xbc, 0x3b, 0x66, 0x47, 0xf4, 0xc6, 0x32, 0x93, 0x90, 0x0e, + 0x1e, 0x48, 0x8a, 0x4f, 0x8c, 0xc2, 0x51, 0x46, 0x37, 0x11, 0xd4, 0x4e, 0xa9, 0x21, 0xe3, 0x0b, + 0xf9, 0xed, 0xdc, 0xdd, 0x37, 0x8e, 0xc6, 0xff, 0xce, 0x2e, 0x0a, 0x2f, 0xa6, 0xab, 0xf1, 0xf3, + 0xd1, 0x5d, 0x56, 0x8d, 0xfb, 0xbf, 0xac, 0x77, 0xca, 0x57, 0x13, 0x7f, 0x92, 0xbe, 0x0c, 0xed, + 0xe8, 0xcc, 0xc1, 0x83, 0xf4, 0xfc, 0x76, 0x83, 0xa5, 0xe2, 0x8f, 0x9e, 0x9f, 0xfd, 0x23, 0x33, + 0xff, 0xa4, 0xc6, 0x3b, 0x7c, 0x82, 0x82, 0x46, 0x23, 0xec, 0xd3, 0xbe, 0xc4, 0x6c, 0x4c, 0x4d, + 0x7a, 0x13, 0xc2, 0x78, 0x1b, 0x66, 0x8d, 0xbb, 0x6b, 0x82, 0x60, 0x34, 0x65, 0xf0, 0x8e, 0xd7, + 0x26, 0xab, 0x8f, 0xd8, 0x09, 0xc0, 0xf7, 0x81, 0x22, 0xe0, 0xd6, 0xd8, 0x00, 0x8b, 0xfa, 0x2a, + 0x22, 0x19, 0x0e, 0xa2, 0xbb, 0x87, 0xe9, 0x85, 0xce, 0xb1, 0x68, 0x6d, 0x05, 0x8c, 0xf4, 0xd9, + 0x2a, 0x8d, 0xe5, 0xf7, 0x4e, 0x20, 0x26, 0xe6, 0x3b, 0xa6, 0x77, 0xa3, 0x88, 0x5f, 0xd4, 0xa9, + 0x93, 0xc6, 0xda, 0xee, 0x5a, 0x7c, 0xcf, 0x3d, 0x46, 0xfa, 0x8e, 0xc4, 0x48, 0x97, 0x35, 0x90, + 0xf0, 0x7c, 0xee, 0x09, 0x6d, 0xab, 0x7a, 0x3d, 0x5a, 0x53, 0x8e, 0x39, 0x55, 0xcd, 0x5c, 0xf7, + 0xc7, 0x74, 0x77, 0xf9, 0x9b, 0x85, 0xc2, 0xfa, 0x48, 0x23, 0x59, 0xe7, 0x74, 0x88, 0x5e, 0xa8, + 0xf7, 0x1d, 0x5e, 0x14, 0x56, 0x9f, 0x64, 0xca, 0x5e, 0x95, 0xba, 0xbb, 0xa7, 0xcb, 0xe9, 0xfd, + 0xae, 0x66, 0x05, 0xa7, 0x2d, 0x24, 0x13, 0xda, 0x86, 0xb8, 0x65, 0x2e, 0x20, 0xc6, 0xf9, 0x79, + 0xe7, 0xb2, 0x92, 0xbf, 0x59, 0x4b, 0x70, 0xbb, 0x7b, 0xc3, 0x2f, 0x07, 0xa6, 0x4e, 0x2a, 0x15, + 0x9a, 0xc4, 0x9f, 0x7f, 0xd1, 0x26, 0x84, 0xc4, 0x65, 0xf9, 0xd8, 0x11, 0x8d, 0x5a, 0x10, 0xa0, + 0xaf, 0x59, 0xa8, 0x59, 0xa4, 0x81, 0x5a, 0xb5, 0x37, 0xf9, 0x64, 0x2c, 0xdc, 0xbf, 0xae, 0x2e, + 0x83, 0xf2, 0x1a, 0x55, 0x19, 0xfa, 0xd8, 0x53, 0xc9, 0x9d, 0x23, 0x11, 0x94, 0x52, 0x20, 0x11, + 0xb6, 0x12, 0xf0, 0xfc, 0x02, 0x6e, 0x7c, 0xbe, 0xea, 0x6c, 0x95, 0x86, 0xcc, 0xf9, 0x8d, 0x38, + 0x09, 0xef, 0x6e, 0x15, 0x7c, 0x10, 0x64, 0x8c, 0xa5, 0xaa, 0x0d, 0x3c, 0x42, 0xef, 0x92, 0x0c, + 0xd8, 0xea, 0xe8, 0x54, 0xbb, 0x7d, 0x12, 0x4a, 0xd8, 0x48, 0x08, 0x94, 0xd6, 0x13, 0xd8, 0xc1, + 0xe7, 0xbb, 0x46, 0xa2, 0x2f, 0x2d, 0x07, 0xf1, 0x3a, 0xdd, 0x30, 0x90, 0x5d, 0x76, 0x79, 0xec, + 0x7d, 0xa8, 0x23, 0x4a, 0x11, 0xb3, 0xeb, 0x3b, 0x9a, 0xa6, 0xc5, 0xf5, 0x44, 0x77, 0x3e, 0x9c, + 0x3f, 0xa7, 0x93, 0xda, 0x41, 0xf7, 0x72, 0x54, 0x39, 0x1f, 0xff, 0x68, 0xf2, 0xf5, 0xc6, 0xfd, + 0x16, 0x20, 0x75, 0x75, 0xd7, 0x2b, 0x23, 0x9b, 0x1f, 0x58, 0x92, 0x93, 0x08, 0x6e, 0x7a, 0x73, + 0xa6, 0x95, 0xbf, 0x6d, 0x8f, 0xda, 0x29, 0x4a, 0x67, 0xd5, 0x21, 0x24, 0xda, 0xed, 0xbc, 0x7c, + 0xd3, 0xfd, 0x43, 0x7f, 0x8a, 0x8d, 0x77, 0x4c, 0x6b, 0xc4, 0x09, 0xb8, 0x45, 0xe4, 0xae, 0x60, + 0x88, 0x53, 0xf2, 0x7a, 0x61, 0x25, 0xac, 0xf3, 0xb0, 0x0f, 0xf8, 0x1d, 0x77, 0x84, 0x5a, 0x26, + 0x9e, 0xf1, 0x83, 0xc1, 0x48, 0xdd, 0xfe, 0x54, 0xd4, 0x2b, 0x98, 0x2a, 0xfc, 0x7f, 0xe5, 0x33, + 0xfc, 0x6d, 0xef, 0xa7, 0x5b, 0x3d, 0x36, 0x48, 0x32, 0xe7, 0xba, 0x17, 0x94, 0x8e, 0x44, 0xfa, + 0x04, 0x2c, 0xe6, 0xdf, 0x4d, 0xe7, 0xac, 0xb7, 0x6a, 0x7c, 0xa6, 0x84, 0x8c, 0xda, 0x08, 0xe2, + 0x73, 0xbc, 0xbe, 0xf0, 0x3d, 0xc0, 0x55, 0x84, 0x78, 0x42, 0xe1, 0x40, 0x1d, 0x7f, 0xfe, 0xd5, + 0xa2, 0x3a, 0x41, 0x4f, 0x9f, 0x82, 0xb7, 0x27, 0x3b, 0x12, 0xc4, 0x87, 0xe9, 0xed, 0x51, 0xed, + 0xcc, 0x42, 0x7d, 0xcf, 0xe3, 0xd7, 0xe8, 0x8a, 0xd0, 0x6a, 0x68, 0xa5, 0xf7, 0xd5, 0xa9, 0x92, + 0x0a, 0xe0, 0x3d, 0x44, 0xdb, 0xd7, 0x3c, 0x16, 0xc6, 0x7d, 0x49, 0x15, 0x67, 0xc9, 0x3d, 0xc1, + 0x69, 0x45, 0xe6, 0x57, 0x2a, 0x39, 0xea, 0x20, 0xc0, 0x9a, 0xe3, 0x13, 0x99, 0x89, 0xda, 0xe1, + 0x56, 0x36, 0x18, 0x57, 0x57, 0xf4, 0x6a, 0xe4, 0xf0, 0x38, 0x91, 0x9c, 0x20, 0x3e, 0xaf, 0xf2, + 0xd6, 0xe5, 0xf4, 0x33, 0xa6, 0x98, 0xb6, 0xa1, 0x0c, 0x37, 0x74, 0x2e, 0x72, 0xd5, 0xee, 0x08, + 0xcd, 0x85, 0x24, 0x8a, 0xcb, 0x0e, 0x31, 0x0a, 0xfa, 0x79, 0x7d, 0x32, 0x18, 0x7c, 0xe8, 0x1a, + 0x2c, 0xad, 0xb5, 0x7e, 0x6a, 0x80, 0xe5, 0x17, 0x4d, 0x3d, 0x52, 0x67, 0x76, 0xfa, 0x55, 0x6b, + 0x99, 0xab, 0x96, 0x49, 0xaa, 0x8b, 0xf0, 0xa3, 0xd6, 0x8c, 0xc4, 0xec, 0x9c, 0xb9, 0x31, 0xf0, + 0x7f, 0x84, 0xd4, 0x51, 0x5d, 0x63, 0x59, 0xce, 0x2b, 0x39, 0x33, 0x65, 0x7e, 0x1c, 0x53, 0x0a, + 0x0d, 0xf5, 0x84, 0x78, 0x69, 0x1b, 0xd7, 0x65, 0xb1, 0xbe, 0x96, 0xcd, 0x78, 0xd9, 0x1b, 0x44, + 0x2d, 0xea, 0xef, 0x4d, 0x2d, 0x46, 0xbb, 0x5a, 0xab, 0x7a, 0x31, 0xc7, 0x14, 0x9a, 0x45, 0x70, + 0x29, 0xf2, 0x7b, 0xcf, 0x15, 0xee, 0x3b, 0xa6, 0x75, 0x55, 0xef, 0xf9, 0x33, 0xfd, 0x39, 0x92, + 0x80, 0xeb, 0x43, 0xe3, 0xfd, 0xa4, 0x66, 0x71, 0x5d, 0x4c, 0x8b, 0x7a, 0xa3, 0x86, 0x62, 0xb5, + 0xab, 0x35, 0x4c, 0xcf, 0x89, 0xd5, 0xb2, 0xec, 0x7a, 0xc3, 0x3a, 0xf2, 0x2f, 0xe7, 0x11, 0x59, + 0x9b, 0x85, 0xef, 0x4c, 0x32, 0x96, 0x70, 0x74, 0x39, 0xd0, 0xc5, 0xa5, 0x4c, 0x61, 0x7f, 0xf3, + 0xcc, 0x9f, 0x64, 0xd7, 0x03, 0x59, 0x50, 0x30, 0x08, 0x62, 0xb7, 0xd0, 0x7e, 0xad, 0xcd, 0x31, + 0x9c, 0x9b, 0xee, 0x3b, 0x40, 0x04, 0x59, 0xc0, 0x34, 0x7c, 0x10, 0x9f, 0x6a, 0xa5, 0x88, 0x24, + 0x78, 0x40, 0x79, 0xa8, 0x50, 0x8a, 0xda, 0x3e, 0x59, 0x18, 0x58, 0x2e, 0x13, 0x6a, 0x9b, 0xa7, + 0x45, 0x6b, 0x43, 0x85, 0xd7, 0x13, 0x0d, 0xdf, 0x95, 0x5e, 0x2f, 0xc4, 0x9f, 0x3d, 0x96, 0x54, + 0x0a, 0xee, 0x74, 0xea, 0x29, 0xde, 0xc0, 0x3f, 0x86, 0xf8, 0xe7, 0x4d, 0x48, 0x9a, 0xd9, 0x19, + 0xaf, 0x0f, 0xee, 0x86, 0xcb, 0x29, 0x3d, 0x75, 0xe7, 0x2f, 0x96, 0xbf, 0x96, 0xee, 0xfd, 0x88, + 0x67, 0x87, 0xb8, 0xe5, 0x4a, 0xa3, 0xa7, 0x70, 0x01, 0x32, 0xc3, 0xcd, 0x4a, 0xd9, 0x2b, 0xb3, + 0x72, 0xf8, 0xde, 0xe5, 0x62, 0xfe, 0x11, 0x9b, 0x6d, 0xe8, 0xa8, 0x87, 0x3e, 0x6f, 0x50, 0x4d, + 0xff, 0x01, 0x97, 0xca, 0xb2, 0x1d, 0x7f, 0x08, 0xb0, 0x6c, 0x23, 0x21, 0x1d, 0x46, 0xee, 0xa4, + 0xaa, 0x0e, 0x38, 0x69, 0xa8, 0x9f, 0x07, 0xda, 0x5c, 0x73, 0xe3, 0x20, 0x6b, 0xe0, 0x37, 0x58, + 0xca, 0x29, 0x45, 0xe9, 0x86, 0x4c, 0x0e, 0x9f, 0xf0, 0x6f, 0x1d, 0xd6, 0xd3, 0x75, 0xa2, 0x24, + 0x0b, 0x04, 0x3f, 0xd7, 0x64, 0x09, 0x6b, 0xc1, 0xd8, 0x04, 0x2a, 0xba, 0xd4, 0x33, 0x9c, 0x19, + 0x78, 0x5b, 0x60, 0x46, 0x23, 0x7b, 0x98, 0x22, 0x6d, 0x1d, 0x7e, 0x7d, 0xc3, 0x3c, 0x12, 0x30, + 0x94, 0x9f, 0x79, 0x57, 0x5e, 0x7f, 0x24, 0x67, 0xbd, 0x87, 0xc4, 0xb7, 0x31, 0xe7, 0x8c, 0xf4, + 0xfc, 0xe1, 0xf7, 0x6a, 0xdc, 0x19, 0xf6, 0x3b, 0xa6, 0x97, 0xb7, 0xce, 0x83, 0xac, 0x59, 0x49, + 0x51, 0x39, 0x47, 0xbe, 0xa5, 0x7d, 0x41, 0x44, 0x6d, 0xbe, 0x0c, 0xcd, 0x74, 0xe1, 0xc3, 0xec, + 0xdb, 0xe3, 0xea, 0x70, 0xd0, 0xf4, 0xf7, 0x51, 0xbd, 0x4e, 0xc2, 0x29, 0xaa, 0x67, 0x51, 0x80, + 0xab, 0x78, 0xc9, 0xb9, 0xef, 0x9d, 0x89, 0xf6, 0x85, 0xd5, 0xec, 0xe2, 0xe8, 0xee, 0x64, 0x63, + 0xc3, 0x78, 0x97, 0x5c, 0x54, 0x51, 0x16, 0x98, 0xcb, 0x8a, 0x2b, 0xc9, 0x3e, 0x9a, 0xd7, 0xf9, + 0xf3, 0x2b, 0x71, 0x8f, 0x29, 0x4b, 0x40, 0xe7, 0x2f, 0x7d, 0x36, 0xff, 0xe7, 0x4f, 0x28, 0xae, + 0x90, 0x25, 0x12, 0xb9, 0x12, 0x0c, 0xcf, 0xa8, 0x41, 0xa5, 0x72, 0x91, 0x95, 0x13, 0x5e, 0xb6, + 0x05, 0x63, 0x45, 0x3b, 0x8d, 0x9c, 0x9e, 0xbf, 0x2a, 0x43, 0x3d, 0x93, 0xfb, 0x06, 0x8e, 0xa3, + 0x99, 0x0c, 0xa2, 0x99, 0x52, 0x98, 0xee, 0xd0, 0xb9, 0x8c, 0x2d, 0x18, 0xa6, 0xcd, 0xf5, 0x83, + 0x2a, 0xda, 0x6c, 0xcb, 0xff, 0x4a, 0xcf, 0x50, 0x37, 0xd6, 0xbd, 0xcb, 0xda, 0xc1, 0x5f, 0xae, + 0x93, 0xae, 0xaa, 0xb0, 0xd7, 0xac, 0xd6, 0xef, 0x9b, 0x92, 0x6a, 0xff, 0xd6, 0x13, 0xa8, 0xf0, + 0xe5, 0xf4, 0x61, 0x6d, 0x8c, 0xf5, 0x41, 0x62, 0x68, 0x4d, 0x0d, 0xb3, 0x42, 0x1a, 0xda, 0xcd, + 0xea, 0x0b, 0xd8, 0x27, 0x5a, 0x4f, 0x61, 0x09, 0x8d, 0x76, 0x14, 0x5c, 0x6d, 0x70, 0xaa, 0x3e, + 0x5d, 0xa5, 0x5f, 0xff, 0x0a, 0x63, 0x1a, 0xbb, 0xec, 0xb1, 0x1f, 0x8f, 0x4f, 0xaf, 0x6a, 0x99, + 0xa3, 0x27, 0x9f, 0x15, 0xd0, 0xef, 0x07, 0xa5, 0x69, 0x75, 0x7f, 0xa1, 0xa1, 0x2a, 0xaa, 0x5f, + 0x83, 0xf3, 0x70, 0x5c, 0xd5, 0x05, 0xc9, 0x28, 0xad, 0x11, 0x1a, 0xc1, 0x13, 0xd9, 0xdc, 0xe1, + 0x0f, 0x3f, 0xd7, 0xc2, 0xd9, 0x7b, 0x5b, 0x6d, 0x39, 0x7d, 0x68, 0x13, 0x74, 0xd6, 0x4f, 0xb0, + 0xf5, 0x4d, 0x65, 0x48, 0x53, 0x73, 0x99, 0x9c, 0xa6, 0xe5, 0xbf, 0x1c, 0x69, 0x09, 0x32, 0x6a, + 0x82, 0xd2, 0xb7, 0x64, 0xe3, 0xf7, 0x38, 0xcd, 0x5a, 0x7b, 0xc7, 0xb4, 0x69, 0x9d, 0x0f, 0x5c, + 0x23, 0x4c, 0xee, 0x40, 0x12, 0xb6, 0xbe, 0x85, 0x73, 0x56, 0x4e, 0x70, 0xd7, 0x9a, 0x31, 0x44, + 0x83, 0xa2, 0x9d, 0x08, 0xe7, 0xdc, 0xa7, 0x7c, 0xe1, 0x03, 0x7e, 0xae, 0x44, 0x40, 0x6e, 0xb7, + 0xd7, 0xca, 0x28, 0xbe, 0xb5, 0xfe, 0x7d, 0x38, 0xb3, 0xb6, 0x05, 0x78, 0x11, 0x31, 0x6f, 0xcb, + 0x18, 0x1a, 0xaf, 0xea, 0xac, 0xf7, 0xe9, 0xd0, 0xb1, 0x33, 0xb9, 0x9c, 0xd7, 0x5d, 0xa4, 0x99, + 0x1b, 0xfc, 0x6d, 0x9c, 0x25, 0xb3, 0x1a, 0xae, 0xa8, 0x0c, 0xe7, 0xfc, 0x1e, 0xc3, 0xba, 0x41, + 0x25, 0x2b, 0x5f, 0xd4, 0x1c, 0x2c, 0xf5, 0x1d, 0xaf, 0x21, 0xdd, 0x2b, 0x5c, 0x7a, 0x89, 0xea, + 0xf2, 0xea, 0x64, 0x36, 0x5c, 0x8f, 0x62, 0x32, 0x98, 0xd3, 0xa2, 0x39, 0xe0, 0x5d, 0xb3, 0xb9, + 0xca, 0x13, 0x08, 0x7a, 0x6f, 0x07, 0xef, 0x9f, 0x4e, 0x3d, 0x75, 0x7a, 0x86, 0xd7, 0xb6, 0xe2, + 0x41, 0x72, 0x37, 0xd2, 0x10, 0x11, 0xdd, 0x58, 0xbe, 0xd4, 0xca, 0xd7, 0x79, 0xaf, 0x4e, 0xe0, + 0xb3, 0x71, 0xf7, 0x3a, 0xf7, 0x02, 0x9e, 0x9e, 0x61, 0xed, 0xd3, 0x96, 0x72, 0xad, 0x3c, 0xf0, + 0xa0, 0xc9, 0xa8, 0xed, 0xb0, 0x9d, 0xae, 0x20, 0x43, 0x5c, 0x6d, 0x50, 0x5c, 0xff, 0x68, 0xf1, + 0xcd, 0xee, 0xfb, 0xea, 0x56, 0xe6, 0xfc, 0x7a, 0xac, 0xe1, 0x0f, 0xd6, 0x43, 0x3c, 0x47, 0x35, + 0xcb, 0xe1, 0x6b, 0x60, 0xaf, 0x8c, 0xd8, 0x0e, 0x20, 0x33, 0xf2, 0xd3, 0x6d, 0x47, 0x30, 0x75, + 0xfc, 0x1c, 0x64, 0x2d, 0xe6, 0xbd, 0xe4, 0x97, 0xb5, 0x6f, 0xd7, 0xf8, 0xdc, 0x86, 0xb0, 0xbb, + 0x02, 0xbf, 0xe6, 0x84, 0x08, 0x6c, 0x33, 0x07, 0x67, 0xa1, 0xd0, 0xf9, 0xae, 0x26, 0xad, 0xd3, + 0xb9, 0x4f, 0x98, 0x93, 0xe3, 0xfb, 0x90, 0x52, 0x24, 0x34, 0xf8, 0xf1, 0xea, 0x39, 0xfc, 0x80, + 0x89, 0x1e, 0x5b, 0x81, 0x1c, 0x7c, 0x7d, 0x7e, 0x86, 0xc5, 0xe2, 0xbb, 0x49, 0x8d, 0x36, 0x43, + 0xad, 0xe4, 0xab, 0x60, 0xed, 0x30, 0x29, 0xb2, 0xfd, 0xc3, 0x64, 0x44, 0xbf, 0xf8, 0x1d, 0xd3, + 0xe0, 0x01, 0x72, 0x89, 0xe8, 0x4d, 0x30, 0x40, 0x0b, 0x35, 0x9e, 0x58, 0x7f, 0xb3, 0x3a, 0x42, + 0xc2, 0x99, 0x89, 0x42, 0xf7, 0xd0, 0x2b, 0xe1, 0xca, 0x44, 0x0b, 0xed, 0xd6, 0x66, 0x6f, 0x3a, + 0x60, 0xaa, 0x15, 0x8d, 0x5a, 0xeb, 0x41, 0xb8, 0x64, 0x72, 0x2a, 0x55, 0xa0, 0x6b, 0x68, 0x8a, + 0x50, 0x36, 0x1a, 0xd4, 0xfe, 0xca, 0xe8, 0x5e, 0x4d, 0x30, 0x06, 0x09, 0xc3, 0xb9, 0x52, 0x1c, + 0xe9, 0x54, 0x33, 0x7b, 0x4d, 0xf1, 0x0b, 0x01, 0xef, 0x3d, 0x1c, 0x9c, 0x5d, 0xe0, 0x6b, 0x8b, + 0xea, 0x9f, 0x61, 0x68, 0xab, 0x2f, 0xf2, 0xcd, 0xa8, 0xa5, 0x6e, 0xa7, 0x72, 0xcb, 0x58, 0x9b, + 0xc9, 0x51, 0x72, 0xfc, 0x60, 0xcd, 0xea, 0x75, 0xbd, 0x7e, 0xd9, 0x42, 0xc7, 0x00, 0x5d, 0xf8, + 0xda, 0x38, 0xb9, 0x59, 0xc0, 0x31, 0x58, 0x78, 0x6b, 0x8b, 0x5e, 0x3e, 0xdc, 0x82, 0x53, 0x30, + 0x2b, 0xc9, 0xd3, 0x7b, 0x5d, 0x31, 0xfe, 0x44, 0xa1, 0xe1, 0x2a, 0x3c, 0xcf, 0x5d, 0x25, 0xfc, + 0x26, 0x5d, 0xfe, 0x5b, 0xf8, 0x64, 0x2e, 0x17, 0x3b, 0xf2, 0x6f, 0x48, 0x00, 0xf7, 0xde, 0x44, + 0xc8, 0xaf, 0x86, 0x42, 0xe1, 0xbf, 0x5e, 0xf0, 0xa5, 0x4a, 0x79, 0x60, 0xc1, 0x4d, 0x87, 0x70, + 0x26, 0xb9, 0x15, 0x47, 0x4f, 0xd1, 0xe4, 0xc8, 0x02, 0x6b, 0xaa, 0xa8, 0xdf, 0xbf, 0xd1, 0x97, + 0x43, 0xe1, 0x14, 0xd7, 0xf0, 0x98, 0xc6, 0x7e, 0x1d, 0x5e, 0x0d, 0x27, 0xed, 0xf8, 0x15, 0xad, + 0x58, 0xb6, 0x6b, 0xa1, 0x2f, 0x86, 0xd2, 0xf6, 0x64, 0x7d, 0xcb, 0xa5, 0x54, 0x2a, 0x53, 0x3a, + 0xad, 0x88, 0xd4, 0x52, 0x3a, 0x2a, 0xdc, 0x09, 0xc7, 0x22, 0x6d, 0x9e, 0xb4, 0xe9, 0x59, 0x28, + 0x38, 0x50, 0xbc, 0x23, 0xac, 0xdb, 0x94, 0xaa, 0x4d, 0x4e, 0x29, 0xc1, 0xe0, 0x48, 0x1e, 0xee, + 0x2a, 0xa5, 0xe3, 0x3a, 0xb4, 0x2b, 0x23, 0xad, 0xa3, 0xcc, 0x84, 0x9a, 0x82, 0xa3, 0x42, 0x0a, + 0xbd, 0x08, 0xc5, 0xd5, 0x4e, 0x96, 0x48, 0xed, 0x71, 0xfd, 0x1e, 0xa7, 0x11, 0xd9, 0x3b, 0xa6, + 0x45, 0x00, 0x31, 0xa4, 0x19, 0x0b, 0x09, 0xc3, 0x23, 0x8c, 0x19, 0xb5, 0x30, 0x10, 0xe6, 0x3b, + 0x75, 0xcd, 0xa8, 0x7d, 0xb7, 0xc9, 0x10, 0x08, 0x6c, 0x80, 0x35, 0x17, 0x57, 0xa0, 0x15, 0xc9, + 0xbd, 0xa7, 0x4d, 0x9a, 0xbe, 0xba, 0x90, 0xa8, 0x2e, 0x23, 0x55, 0xca, 0xa9, 0xd3, 0x86, 0xd4, + 0x0a, 0xda, 0x1a, 0xc9, 0xc9, 0x24, 0x0b, 0x7d, 0xed, 0x86, 0x3c, 0xd8, 0xb2, 0x46, 0x90, 0x3f, + 0xf4, 0xa6, 0x86, 0x90, 0x3a, 0x72, 0x6b, 0xd6, 0x19, 0x48, 0x16, 0xe7, 0xaa, 0xe1, 0x99, 0xe3, + 0x7c, 0x25, 0xad, 0x11, 0x13, 0x72, 0x89, 0x29, 0x99, 0xc0, 0x7d, 0x35, 0xb2, 0x21, 0x83, 0xee, + 0x10, 0xa2, 0x5e, 0x73, 0x10, 0x07, 0xc7, 0x8d, 0xb6, 0xd0, 0x84, 0xd1, 0xee, 0xfe, 0x32, 0x3e, + 0x3c, 0x44, 0xe8, 0xbc, 0x31, 0x35, 0x4d, 0xfa, 0xe2, 0x6c, 0x06, 0xa7, 0xe7, 0x20, 0x03, 0x52, + 0x8f, 0xdb, 0x33, 0x15, 0xcb, 0xe3, 0xcc, 0x83, 0x0c, 0x00, 0x28, 0x65, 0x8b, 0x48, 0xfd, 0x31, + 0x39, 0x2d, 0x36, 0x54, 0x2a, 0x69, 0x5f, 0x90, 0x78, 0xa8, 0x92, 0xa6, 0xfb, 0x21, 0xf3, 0x0e, + 0xb9, 0x1a, 0x49, 0xce, 0xbf, 0x36, 0x43, 0xc5, 0x44, 0x38, 0x91, 0xb3, 0x9e, 0x27, 0xc0, 0x2c, + 0x0b, 0x78, 0x84, 0x82, 0xac, 0x54, 0xbd, 0xcf, 0x23, 0x8a, 0x22, 0x1d, 0x81, 0x17, 0xbd, 0xeb, + 0x19, 0x5e, 0x79, 0x18, 0xa4, 0x32, 0x61, 0x9d, 0x07, 0xca, 0x7d, 0x75, 0x44, 0x75, 0x76, 0x14, + 0x30, 0x69, 0x4d, 0x4e, 0x3d, 0x64, 0xb1, 0xd5, 0xc0, 0xed, 0xb6, 0x41, 0x63, 0xed, 0xb2, 0x7b, + 0xc8, 0xe5, 0x4b, 0xa8, 0xa2, 0x77, 0xae, 0xc3, 0x65, 0x0d, 0x1f, 0xad, 0x41, 0x9d, 0xab, 0x60, + 0xdb, 0xaa, 0x00, 0x2a, 0x2a, 0xa6, 0x8e, 0x70, 0x57, 0x5f, 0x62, 0x74, 0x57, 0x57, 0x37, 0xc9, + 0xbe, 0x42, 0x0b, 0x83, 0xeb, 0x97, 0x4c, 0xd4, 0xa0, 0x7b, 0x69, 0xe6, 0x90, 0x9d, 0x11, 0xc2, + 0x2c, 0x3c, 0x52, 0x6b, 0x4f, 0x29, 0xcf, 0xef, 0xff, 0x7c, 0x37, 0x67, 0xde, 0x31, 0x1d, 0xca, + 0xfb, 0x14, 0xff, 0x89, 0xa8, 0x41, 0x44, 0x07, 0xdb, 0xa0, 0x04, 0x34, 0x0f, 0x10, 0xf2, 0xc6, + 0x3a, 0x6e, 0x2b, 0x45, 0x45, 0x15, 0x98, 0x38, 0x41, 0x38, 0xb1, 0xf3, 0x5f, 0x15, 0x7e, 0x0e, + 0x71, 0x27, 0x3b, 0xd6, 0x3a, 0x02, 0xa9, 0x05, 0x77, 0x21, 0xec, 0x25, 0xa3, 0x6f, 0xa6, 0x19, + 0x86, 0x7a, 0xa8, 0xcb, 0x68, 0x20, 0x30, 0x6b, 0x64, 0xf3, 0xfe, 0x81, 0xde, 0x16, 0x4d, 0xf0, + 0x0c, 0x21, 0x7b, 0x1a, 0x65, 0x84, 0x9c, 0xb7, 0x6c, 0xa3, 0xfd, 0xb6, 0xfc, 0xb6, 0x54, 0x06, + 0x87, 0x9f, 0xa1, 0xab, 0x6b, 0xda, 0x0b, 0x6a, 0xe9, 0xdd, 0xf0, 0x45, 0xfd, 0x9c, 0x1a, 0xf6, + 0x6f, 0x0d, 0xce, 0x59, 0x25, 0x73, 0x1c, 0x48, 0xaa, 0x43, 0xa8, 0x80, 0xc5, 0xe4, 0x54, 0x2f, + 0x4f, 0x54, 0x1d, 0x5a, 0x8d, 0xb3, 0xbb, 0x9c, 0x33, 0x77, 0x68, 0x0b, 0x84, 0x67, 0xe1, 0x89, + 0x3d, 0xd2, 0x7b, 0xc1, 0x06, 0x75, 0xf2, 0xa1, 0x5a, 0x44, 0xd2, 0x42, 0x93, 0x53, 0xf1, 0xaf, + 0xf6, 0xaa, 0x21, 0x06, 0xcf, 0x17, 0xc3, 0x1a, 0x12, 0x2e, 0xa6, 0x64, 0x8b, 0xac, 0xfe, 0x31, + 0x30, 0xd3, 0x16, 0x12, 0x3a, 0x27, 0x50, 0x35, 0x5e, 0x0c, 0x95, 0xe3, 0xac, 0xf7, 0x64, 0x95, + 0x03, 0x06, 0x5e, 0x55, 0xd2, 0x4c, 0x04, 0x57, 0xcb, 0xeb, 0x8e, 0x21, 0xa6, 0xf9, 0x76, 0xde, + 0x15, 0xa6, 0xc0, 0xe7, 0x89, 0x8a, 0x71, 0x8d, 0xad, 0x25, 0xe7, 0xd4, 0x57, 0x8f, 0xa3, 0x9b, + 0xe3, 0x1f, 0x43, 0x6c, 0xa9, 0x17, 0xf5, 0xe2, 0xb7, 0x4f, 0xc1, 0xf3, 0x9a, 0xaa, 0x74, 0xed, + 0x9d, 0xb5, 0xda, 0xa7, 0xea, 0x2a, 0x06, 0xef, 0xb2, 0x84, 0xc6, 0x48, 0x1a, 0x5e, 0xa9, 0xa1, + 0x8d, 0x44, 0xfb, 0xe9, 0xec, 0x2e, 0xc1, 0x9c, 0xe3, 0x07, 0xee, 0xab, 0x20, 0x74, 0xdf, 0x0b, + 0x68, 0x0c, 0x6e, 0xa4, 0x99, 0xab, 0xbe, 0x5c, 0x15, 0xf3, 0xe8, 0xdf, 0x27, 0x0c, 0x8d, 0xb7, + 0xe3, 0xc7, 0x47, 0xbc, 0x86, 0x30, 0x21, 0x3f, 0x7f, 0xfe, 0x87, 0x5a, 0x7e, 0xe5, 0x3b, 0xa6, + 0xe1, 0xd5, 0x86, 0x9b, 0x52, 0x2c, 0xe4, 0xaf, 0xfe, 0xfb, 0xe5, 0xa0, 0xe3, 0x66, 0x25, 0x65, + 0x88, 0x77, 0xb6, 0x5f, 0xbf, 0x76, 0xaf, 0x17, 0x0e, 0x9c, 0x0a, 0x39, 0x49, 0x44, 0x1a, 0x27, + 0x07, 0x8b, 0x4e, 0xa4, 0x76, 0xf0, 0xab, 0x76, 0xe9, 0xe7, 0xce, 0x4b, 0x44, 0xce, 0x9a, 0x5d, + 0x7e, 0x11, 0xb2, 0xda, 0xf1, 0x78, 0x56, 0x03, 0x46, 0x2e, 0xdf, 0x3e, 0x63, 0x54, 0x3e, 0x9e, + 0xce, 0x29, 0x7c, 0xe1, 0x6c, 0x34, 0xdd, 0xa0, 0xea, 0xaf, 0x68, 0x14, 0xcf, 0x6f, 0x8e, 0x5e, + 0x81, 0xcd, 0x84, 0xf0, 0xb5, 0x5a, 0xbb, 0x4d, 0x43, 0x75, 0x12, 0xb3, 0x5a, 0xbb, 0xda, 0x3f, + 0x79, 0xcd, 0xbb, 0x4e, 0x0e, 0xf6, 0x29, 0x49, 0xd9, 0x55, 0x3d, 0xc8, 0xee, 0xf0, 0x7d, 0xda, + 0xf6, 0xed, 0x68, 0x37, 0x32, 0x66, 0xa3, 0x67, 0x9d, 0x97, 0x50, 0xc9, 0x11, 0x9a, 0x89, 0x3d, + 0xe9, 0x92, 0xb3, 0x50, 0x4c, 0x29, 0xd5, 0xab, 0xc6, 0x32, 0x0d, 0xab, 0x68, 0xad, 0xf7, 0x2a, + 0xd3, 0x6d, 0x27, 0x4b, 0x2b, 0x42, 0x2f, 0x9d, 0x7d, 0xc9, 0x10, 0x41, 0x9a, 0x66, 0xaf, 0xc7, + 0x3b, 0x25, 0x85, 0x65, 0x37, 0x1c, 0x53, 0x1f, 0x03, 0x0d, 0xde, 0xb1, 0xc5, 0x9b, 0x15, 0x22, + 0x6e, 0x25, 0x5a, 0xb5, 0x49, 0xe1, 0xdb, 0x64, 0xcf, 0x3a, 0x55, 0x57, 0x8a, 0xc6, 0xbd, 0x06, + 0x0b, 0x31, 0x53, 0x4b, 0x74, 0x35, 0x1c, 0x08, 0xc5, 0x73, 0x22, 0x27, 0x6d, 0x15, 0x7a, 0xd2, + 0xdc, 0x3c, 0xa7, 0x6c, 0xc1, 0x18, 0x24, 0x7a, 0x4e, 0x65, 0xbe, 0x1d, 0xf6, 0x17, 0x97, 0x8b, + 0xb2, 0x55, 0x49, 0x68, 0x20, 0x38, 0x9c, 0x4c, 0x88, 0xf8, 0xa7, 0x76, 0x01, 0x47, 0x32, 0x81, + 0x58, 0x97, 0xd4, 0xee, 0x72, 0xa9, 0xeb, 0x8b, 0x90, 0x04, 0xec, 0x35, 0x15, 0xe0, 0xf8, 0xb8, + 0x0b, 0x87, 0xed, 0x89, 0xa8, 0x35, 0xf5, 0xdc, 0x9a, 0x31, 0x01, 0xe7, 0x63, 0xb1, 0x92, 0x40, + 0x7d, 0x4d, 0x5a, 0x18, 0x0b, 0xfe, 0x87, 0x5a, 0x21, 0x30, 0xe5, 0xef, 0xfd, 0x29, 0x54, 0xef, + 0x98, 0xce, 0xd9, 0x0b, 0x71, 0xed, 0x03, 0x0f, 0xf7, 0xef, 0x4e, 0xb7, 0xac, 0x53, 0xbd, 0x3a, + 0x15, 0x3d, 0xbd, 0x0e, 0xe4, 0x3c, 0x50, 0x10, 0x80, 0x9f, 0xac, 0xa7, 0xb5, 0x42, 0x0e, 0x21, + 0x57, 0x0d, 0x3d, 0xd9, 0x0c, 0x17, 0xf0, 0xbc, 0x4c, 0x0b, 0x72, 0xec, 0x75, 0x0f, 0x2d, 0x28, + 0xb0, 0x48, 0xa8, 0x3d, 0x42, 0x58, 0x98, 0x59, 0x80, 0x5b, 0x23, 0x6a, 0x3e, 0x3f, 0x12, 0xc2, + 0xee, 0x22, 0x2f, 0xc4, 0xf0, 0xea, 0x22, 0xf1, 0x92, 0xba, 0xaa, 0xff, 0xc4, 0x05, 0x9b, 0xe4, + 0x49, 0x46, 0xa4, 0x0e, 0x87, 0xf1, 0xbe, 0xf3, 0xef, 0xac, 0x22, 0x73, 0xe7, 0x7a, 0x4c, 0xa8, + 0xd5, 0xce, 0x55, 0x5e, 0xea, 0xba, 0x0b, 0x64, 0x3a, 0x6e, 0x73, 0x05, 0x67, 0x89, 0x82, 0xc8, + 0x81, 0x7c, 0xfb, 0x14, 0x2d, 0x84, 0x1d, 0xd8, 0x6c, 0x7a, 0x09, 0x87, 0xc1, 0x4f, 0x07, 0x55, + 0xe7, 0xb7, 0xf5, 0x9a, 0x30, 0xee, 0x64, 0x92, 0x86, 0xd8, 0x6b, 0x1d, 0x29, 0x27, 0xc8, 0x40, + 0x5f, 0xdb, 0x80, 0x2d, 0x1b, 0xe5, 0x54, 0x92, 0x61, 0x28, 0x12, 0xcd, 0x10, 0x67, 0xff, 0xe8, + 0x8c, 0xbe, 0x7d, 0x32, 0x2d, 0x9b, 0x36, 0x1e, 0x9d, 0xfe, 0xee, 0x6a, 0xa9, 0x5f, 0x63, 0x2d, + 0xe4, 0xc6, 0x7a, 0x61, 0xfb, 0xb9, 0xe3, 0x16, 0xc3, 0x82, 0xa6, 0x69, 0x63, 0x53, 0x5d, 0x85, + 0x0b, 0x65, 0x5b, 0x54, 0xc1, 0x92, 0x5a, 0x07, 0x5e, 0x2c, 0xef, 0x86, 0x96, 0x82, 0xe5, 0xb2, + 0xfb, 0x3f, 0xd1, 0x83, 0xd1, 0xd1, 0x59, 0x12, 0xe1, 0xc9, 0xfe, 0x93, 0x29, 0x13, 0x83, 0xb3, + 0xe1, 0x06, 0x72, 0x88, 0x36, 0xc1, 0x0c, 0xdd, 0x07, 0xab, 0xa3, 0xab, 0xe9, 0xa4, 0x96, 0x3e, + 0x74, 0xc1, 0x44, 0x7c, 0x1f, 0x0e, 0xcd, 0x1d, 0x29, 0x59, 0x80, 0xe6, 0xfe, 0x27, 0x5e, 0x49, + 0x13, 0x0a, 0x90, 0xcd, 0x8f, 0x47, 0x3f, 0xb5, 0x75, 0xa7, 0x01, 0x22, 0x9b, 0xcc, 0x2a, 0xcc, + 0x45, 0x49, 0xd4, 0xd1, 0xe0, 0x3d, 0xed, 0xbd, 0xce, 0xf5, 0x3a, 0xea, 0xde, 0xef, 0xef, 0x18, + 0x70, 0xed, 0x3b, 0xa6, 0x8b, 0x95, 0x7c, 0x63, 0x6d, 0xce, 0x42, 0x9e, 0x3a, 0x1e, 0x24, 0xae, + 0x56, 0x68, 0x57, 0x70, 0xa4, 0x3c, 0x09, 0x6c, 0x94, 0x6a, 0x5e, 0x7d, 0xd2, 0xfa, 0x14, 0x2c, + 0x70, 0xef, 0x7c, 0x89, 0x4e, 0xc4, 0xe6, 0xf9, 0xa2, 0xd3, 0x72, 0x63, 0x8e, 0xf6, 0x67, 0xaf, + 0x9e, 0x6a, 0x58, 0x8e, 0x64, 0xcc, 0x54, 0x65, 0x13, 0xe9, 0x65, 0x78, 0x2e, 0x93, 0x4f, 0xd7, + 0xb7, 0x9a, 0x5b, 0xaa, 0xdb, 0x23, 0xfe, 0x75, 0x88, 0x03, 0x3b, 0xd3, 0x2b, 0x3c, 0xb3, 0x16, + 0xf5, 0xcf, 0xb9, 0xa0, 0x0a, 0x2b, 0x75, 0xe9, 0x39, 0x1c, 0xa6, 0x1d, 0x71, 0xac, 0xb9, 0x15, + 0xf5, 0xce, 0x8b, 0x34, 0x26, 0xb5, 0x23, 0xc4, 0x89, 0x05, 0x45, 0x99, 0xcc, 0x76, 0x57, 0xe2, + 0x17, 0xdb, 0x4e, 0x11, 0xc5, 0x22, 0xe8, 0xa5, 0x88, 0xcc, 0x77, 0xbc, 0xc9, 0x1c, 0xd9, 0x7d, + 0x90, 0xba, 0x4a, 0x04, 0x3c, 0x2a, 0x51, 0x5f, 0x3d, 0xad, 0x4b, 0xcb, 0x1d, 0x6f, 0x30, 0xf2, + 0x9d, 0xc4, 0x44, 0x12, 0xef, 0x29, 0x1a, 0xe2, 0x78, 0xfe, 0x4e, 0xa8, 0x16, 0x85, 0x80, 0x73, + 0x01, 0x2e, 0x0e, 0x3d, 0x19, 0x99, 0x2d, 0xbe, 0x47, 0x2d, 0x3e, 0x9d, 0x77, 0x95, 0x3a, 0x1b, + 0x7e, 0x81, 0xab, 0xca, 0xdd, 0xeb, 0xba, 0xc9, 0xbc, 0x73, 0x55, 0xec, 0x7c, 0xfb, 0x3a, 0x2c, + 0x6c, 0x3e, 0xa5, 0xef, 0x6b, 0x52, 0x43, 0xbd, 0xe5, 0xef, 0xc4, 0xbc, 0x33, 0xba, 0xa1, 0x94, + 0x18, 0xae, 0x6d, 0x19, 0x9e, 0x26, 0x93, 0xc1, 0x5f, 0x3f, 0x86, 0xd2, 0xe2, 0xf0, 0x68, 0xac, + 0xce, 0x19, 0x9d, 0x41, 0x13, 0x6f, 0x3b, 0x72, 0x07, 0x45, 0x23, 0xe7, 0xd8, 0x4b, 0xdc, 0x7a, + 0x74, 0x01, 0xcd, 0x95, 0xae, 0xe0, 0x15, 0xd0, 0xf6, 0x84, 0x33, 0xa3, 0x9e, 0xb7, 0x13, 0xec, + 0x0a, 0x81, 0xb6, 0x6e, 0xc4, 0xa7, 0xfe, 0x39, 0xbc, 0xc6, 0x6d, 0xc0, 0xcc, 0x4d, 0x41, 0x6b, + 0xbf, 0xd9, 0x03, 0x5e, 0x9c, 0xaa, 0x17, 0xce, 0x55, 0xd4, 0x2c, 0xc1, 0x2d, 0x52, 0xbc, 0x7f, + 0xfc, 0x0f, 0xfd, 0x29, 0xfc, 0xac, 0x77, 0x4c, 0xa7, 0xf0, 0x86, 0xc8, 0x32, 0xd7, 0xef, 0x7e, + 0xd4, 0x07, 0x7f, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, + 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0x7c, 0xf0, 0xc1, 0x07, 0x1f, + 0x7c, 0xf0, 0xc1, 0x07, 0x1f, 0xfc, 0xdf, 0xe4, 0x7f, 0xef, 0x83, 0x5b, 0x2f, 0xf5, 0x5e, 0xc3, + 0x34, 0x35, 0xe7, 0x77, 0x49, 0xc6, 0xbc, 0xd5, 0xb8, 0x97, 0x11, 0x39, 0x5b, 0x8b, 0xda, 0x27, + 0x89, 0xa3, 0xb9, 0x96, 0x8f, 0xc7, 0xf7, 0x8a, 0x99, 0xc4, 0xf1, 0xde, 0x34, 0x9a, 0x85, 0xcc, + 0x74, 0x3b, 0x37, 0x0d, 0x4d, 0x81, 0xbf, 0xee, 0xa3, 0xeb, 0xa4, 0x3c, 0x91, 0x0c, 0x60, 0x7d, + 0x8d, 0x65, 0x24, 0x88, 0x3b, 0x86, 0xc3, 0xf0, 0x33, 0xbd, 0x3c, 0x67, 0xea, 0x01, 0x49, 0xad, + 0xe1, 0xfc, 0xac, 0x7b, 0x10, 0x3a, 0x35, 0x21, 0x07, 0xa9, 0x4d, 0x2b, 0xa9, 0x8a, 0x1c, 0xc7, + 0x1e, 0x93, 0x9a, 0xdc, 0x35, 0xc9, 0x36, 0x6e, 0x4e, 0x71, 0x22, 0x66, 0x3f, 0xf3, 0xf8, 0xad, + 0x3a, 0x9b, 0x49, 0xcc, 0x93, 0x92, 0x1e, 0xe0, 0x96, 0xff, 0xaa, 0x9f, 0xe3, 0x02, 0xde, 0xd9, + 0x68, 0x34, 0x6f, 0xbc, 0xa0, 0xc2, 0xbc, 0x3b, 0xff, 0xc1, 0xfc, 0x79, 0xda, 0x64, 0xb5, 0xe4, + 0x9f, 0xa7, 0x92, 0xa8, 0xd7, 0x40, 0x40, 0xe2, 0xed, 0xab, 0x56, 0x06, 0xd1, 0x00, 0xbf, 0xdf, + 0x2a, 0x98, 0x59, 0xdb, 0xfa, 0xe7, 0x7a, 0x3a, 0x13, 0x6c, 0xdf, 0x6e, 0xf9, 0x9f, 0x38, 0xfb, + 0x97, 0xf9, 0x1b, 0x3e, 0x3f, 0x3a, 0x13, 0x91, 0x05, 0x35, 0x40, 0x0d, 0x3e, 0x1f, 0xef, 0x2e, + 0x6a, 0xa1, 0x40, 0xaa, 0x1f, 0x7f, 0xf4, 0xcf, 0x8a, 0xd5, 0xee, 0x24, 0xac, 0xe3, 0xe3, 0x27, + 0x0b, 0xd6, 0x58, 0x37, 0xa4, 0xe4, 0x1c, 0x41, 0x16, 0xc5, 0x46, 0x79, 0x8f, 0x9a, 0x2f, 0x9d, + 0xb9, 0xa1, 0x65, 0xe9, 0x29, 0x9d, 0xd5, 0x80, 0xa7, 0x7c, 0xb2, 0x63, 0xae, 0x5a, 0x0e, 0xd8, + 0x50, 0x2c, 0xe8, 0x4a, 0xc7, 0xa1, 0x91, 0x3f, 0xd3, 0xbf, 0xf5, 0x34, 0xeb, 0x56, 0x7b, 0xac, + 0x92, 0x7c, 0xdd, 0x7e, 0x48, 0xb4, 0x3b, 0xf6, 0xf3, 0x04, 0x14, 0x96, 0x3a, 0x6a, 0x21, 0x23, + 0xa0, 0x35, 0xad, 0xcb, 0x4e, 0x7d, 0xf0, 0xcc, 0xdc, 0xa9, 0xe6, 0x7a, 0x0a, 0xab, 0x6b, 0xc9, + 0xd6, 0x9c, 0xf3, 0x14, 0x6e, 0x94, 0x21, 0xc5, 0x61, 0x60, 0x73, 0x74, 0xd9, 0x23, 0x3f, 0x83, + 0xf0, 0x76, 0x7b, 0x64, 0x6b, 0x01, 0x73, 0x55, 0x42, 0xef, 0xb8, 0x59, 0x4b, 0xab, 0xfd, 0x5c, + 0x00, 0xbf, 0x48, 0xaf, 0x86, 0xee, 0xfa, 0x52, 0x44, 0xd0, 0xd7, 0xce, 0x30, 0x92, 0x97, 0x4f, + 0x3f, 0x13, 0x89, 0x5e, 0xc0, 0xcb, 0xbe, 0xf5, 0x40, 0xe8, 0xb0, 0xdf, 0xc3, 0x7c, 0x1a, 0x6d, + 0x79, 0x3b, 0x10, 0xea, 0x5b, 0xef, 0xd2, 0x80, 0xe5, 0x9a, 0xae, 0x31, 0x6e, 0x60, 0xa8, 0x1e, + 0xdd, 0x42, 0x68, 0xca, 0x5a, 0x47, 0x2c, 0xd2, 0x5b, 0x75, 0x15, 0x4e, 0x2e, 0x0b, 0x8a, 0xaf, + 0x22, 0xf1, 0x81, 0x57, 0xdb, 0xed, 0x45, 0x89, 0x7b, 0x7f, 0x6d, 0x8b, 0x4f, 0x04, 0x3b, 0x07, + 0xea, 0xe6, 0xbf, 0x5e, 0x30, 0x1b, 0xb2, 0xd7, 0xb1, 0x98, 0x06, 0x17, 0xa3, 0x31, 0xd2, 0x07, + 0x65, 0xc0, 0xe9, 0x65, 0xad, 0xc0, 0x8a, 0x9d, 0x79, 0x18, 0x2b, 0x75, 0x99, 0x97, 0x94, 0x4a, + 0x88, 0x11, 0x81, 0x66, 0x94, 0xe0, 0x83, 0x4c, 0xdd, 0x3d, 0x49, 0x46, 0x23, 0x53, 0x31, 0x6b, + 0x0a, 0x81, 0xbf, 0x57, 0xe3, 0x22, 0xe2, 0x77, 0x4c, 0x83, 0x61, 0x97, 0x33, 0xd8, 0x5a, 0xb1, + 0x39, 0x3c, 0xca, 0xad, 0x91, 0x96, 0x9c, 0xac, 0x16, 0xa6, 0xcc, 0x85, 0xde, 0xa6, 0x9f, 0xc9, + 0xbe, 0xcd, 0xfd, 0x84, 0x03, 0x75, 0xf9, 0x5e, 0x97, 0x9d, 0x49, 0x09, 0xaf, 0xb3, 0x7a, 0xad, + 0x6f, 0x7e, 0xd3, 0x78, 0x3f, 0x58, 0x96, 0x89, 0xa8, 0xf3, 0xa9, 0x94, 0x7d, 0x1f, 0xd7, 0x8e, + 0x0c, 0x89, 0x04, 0x46, 0x6e, 0xf0, 0xd5, 0xfe, 0xe5, 0x8d, 0xab, 0x23, 0x2f, 0xb2, 0x2c, 0xbc, + 0xf7, 0xc9, 0xc7, 0xdf, 0x5b, 0x01, 0x72, 0x69, 0x7c, 0x49, 0x2d, 0xbd, 0x12, 0x58, 0xbb, 0x11, + 0x0e, 0x9f, 0xfe, 0x68, 0x6a, 0xce, 0x5e, 0xfc, 0xc9, 0x7e, 0xf4, 0x72, 0xb8, 0xb9, 0x25, 0x75, + 0x35, 0xd9, 0xbc, 0xfb, 0xb2, 0xac, 0x29, 0x16, 0xb9, 0xc6, 0x11, 0x23, 0xfa, 0xba, 0x4c, 0x8f, + 0x0a, 0xaf, 0x07, 0x34, 0x7c, 0xff, 0x78, 0x4f, 0xe7, 0xad, 0xf7, 0x08, 0x9c, 0x1f, 0xa4, 0xeb, + 0x8d, 0xb5, 0xc2, 0x69, 0x97, 0xf1, 0x99, 0xa7, 0x49, 0x61, 0x0b, 0xd2, 0xc4, 0x8f, 0xd0, 0x81, + 0xf3, 0xd8, 0x92, 0xa9, 0xf4, 0x75, 0x91, 0x5c, 0x91, 0xa0, 0x53, 0xf9, 0x0d, 0x45, 0x14, 0xd6, + 0xb0, 0xfb, 0x1e, 0xe6, 0x5a, 0x31, 0x43, 0xb4, 0x08, 0x1e, 0xa6, 0x3d, 0xac, 0x93, 0x05, 0x5d, + 0x35, 0x14, 0x06, 0xb6, 0x87, 0x4a, 0x31, 0x1f, 0x5f, 0xb8, 0x61, 0x68, 0x0c, 0x9e, 0x4f, 0xb9, + 0x41, 0xa4, 0x19, 0x69, 0x53, 0xfb, 0x10, 0xc5, 0x8e, 0x7d, 0x85, 0x92, 0x12, 0xcf, 0x7d, 0x3a, + 0x2f, 0xa9, 0x6e, 0x5f, 0x17, 0x40, 0x7e, 0xc3, 0xbd, 0x38, 0x97, 0x17, 0x86, 0x3a, 0x06, 0x39, + 0x9c, 0x48, 0xaa, 0x0a, 0x43, 0x3c, 0x08, 0xd0, 0x5a, 0x6b, 0xc4, 0xe6, 0xd9, 0x1e, 0x51, 0xaa, + 0xea, 0x25, 0x14, 0xee, 0x8c, 0x3a, 0x44, 0xa8, 0xe2, 0x12, 0x26, 0xd8, 0x73, 0x56, 0xe0, 0x2a, + 0x0b, 0x0b, 0x45, 0x10, 0x68, 0x1d, 0x27, 0x3c, 0xc5, 0x4a, 0x4d, 0x20, 0xef, 0x54, 0x10, 0xd8, + 0x63, 0x7a, 0xb2, 0x02, 0xff, 0x30, 0x2b, 0x58, 0xf6, 0x8e, 0x69, 0xc0, 0x60, 0xf4, 0xd8, 0x98, + 0xaa, 0xec, 0x99, 0xb7, 0xb1, 0x12, 0x4f, 0xa8, 0x7a, 0x72, 0x3b, 0xbe, 0x9a, 0x00, 0xb9, 0xda, + 0xb4, 0x94, 0x8d, 0x23, 0xc1, 0x6e, 0x64, 0xf3, 0x3c, 0xd3, 0x7b, 0x85, 0x5f, 0x46, 0xb5, 0x82, + 0x4d, 0x4b, 0xb7, 0x91, 0x7d, 0x0c, 0x59, 0x34, 0x9a, 0x12, 0x4c, 0x46, 0x8f, 0x40, 0xd2, 0x0c, + 0x3a, 0x0e, 0x31, 0xea, 0x38, 0x4a, 0x5a, 0x94, 0x73, 0xd5, 0xe8, 0x7d, 0x9d, 0xe0, 0xe3, 0x08, + 0x66, 0x16, 0x09, 0x1a, 0x66, 0x6c, 0x90, 0x5e, 0xcd, 0x96, 0xe3, 0xc3, 0xe5, 0x1e, 0x1a, 0x99, + 0x02, 0x81, 0x5f, 0xdc, 0x5e, 0x4b, 0xba, 0xc1, 0xf9, 0x09, 0x09, 0x01, 0x19, 0xe0, 0x57, 0x11, + 0xb9, 0x61, 0x14, 0x58, 0x1f, 0x48, 0xb5, 0x26, 0x10, 0xd6, 0x48, 0xe0, 0xb0, 0xbd, 0x31, 0x4b, + 0x73, 0xae, 0x52, 0xde, 0x95, 0x2a, 0xae, 0xc1, 0x43, 0x50, 0xc4, 0x74, 0x16, 0x4e, 0x8e, 0xce, + 0xda, 0xa6, 0x49, 0x4e, 0xd4, 0xec, 0x01, 0x88, 0xb6, 0xbb, 0xcb, 0xb3, 0x46, 0x29, 0xff, 0x67, + 0xa4, 0xc1, 0xd0, 0x69, 0x21, 0xcd, 0xfc, 0x2c, 0x27, 0xae, 0xbc, 0x0c, 0x58, 0x06, 0xb2, 0x70, + 0xa4, 0x6f, 0xd7, 0xce, 0x83, 0xd8, 0xed, 0x11, 0x49, 0xd9, 0x53, 0xf2, 0xc0, 0x4b, 0xf1, 0x74, + 0xf7, 0x44, 0xdb, 0x8d, 0xfb, 0x9d, 0x4d, 0x31, 0x0f, 0x0c, 0x1e, 0xf4, 0x9d, 0x24, 0x42, 0xd8, + 0xec, 0xbe, 0xd3, 0x24, 0x5c, 0xbe, 0xae, 0x85, 0x46, 0x88, 0xc7, 0x66, 0x9e, 0x44, 0xa4, 0x6d, + 0x22, 0xd7, 0xd1, 0x68, 0xc6, 0x08, 0x0c, 0x52, 0x8d, 0x02, 0xce, 0xaf, 0x68, 0x57, 0xaf, 0xea, + 0x1e, 0xf1, 0xc4, 0x7e, 0xe9, 0x9d, 0xe5, 0xdf, 0x95, 0x11, 0x21, 0x5e, 0x45, 0xf6, 0x28, 0x09, + 0x0e, 0x6b, 0x56, 0x23, 0x72, 0xad, 0x2a, 0x9d, 0xb6, 0x8e, 0x45, 0x59, 0x76, 0x1c, 0xff, 0xfb, + 0x21, 0xca, 0x19, 0x2c, 0x77, 0xd1, 0x9e, 0x82, 0x6d, 0x49, 0xd2, 0xe9, 0x70, 0x1b, 0xa8, 0x5a, + 0xff, 0xe1, 0x9e, 0xdd, 0xcc, 0x3b, 0xa6, 0x43, 0x44, 0x7a, 0x9a, 0x5d, 0xe3, 0xf4, 0x41, 0x46, + 0x27, 0x99, 0x3f, 0xd6, 0xcc, 0x98, 0xaf, 0x1b, 0x27, 0x5d, 0x5b, 0x44, 0x8b, 0x91, 0x2c, 0xbd, + 0x89, 0x0a, 0x9a, 0x63, 0x32, 0x6f, 0x83, 0xb2, 0x0d, 0x4e, 0x61, 0xee, 0xa0, 0xd9, 0xd6, 0x96, + 0x24, 0xca, 0xff, 0x44, 0xb5, 0xfb, 0x63, 0x73, 0x70, 0xce, 0xb9, 0x3f, 0xba, 0x8d, 0x99, 0x60, + 0x34, 0x68, 0x34, 0x7c, 0xcd, 0x14, 0xc6, 0xdd, 0xb2, 0x52, 0xd5, 0x97, 0x48, 0x4e, 0xa2, 0x6b, + 0x7b, 0x2e, 0x77, 0xfb, 0xf6, 0x91, 0x6a, 0x99, 0x73, 0xc7, 0x2e, 0x57, 0x33, 0x1a, 0xee, 0x9f, + 0xdc, 0x96, 0x21, 0xff, 0x45, 0x17, 0x06, 0x9a, 0x27, 0xf0, 0xdb, 0x5a, 0xf1, 0x67, 0x53, 0x46, + 0xe7, 0x69, 0x87, 0x53, 0x02, 0x56, 0x19, 0xa8, 0x01, 0x98, 0x49, 0xf5, 0xf7, 0x06, 0x0f, 0x95, + 0xb6, 0xed, 0x31, 0x3b, 0xf3, 0x54, 0x36, 0xb2, 0x1e, 0x84, 0xe7, 0x0a, 0xcf, 0x2a, 0x27, 0x77, + 0xf5, 0x5f, 0x0d, 0xcf, 0x7a, 0x9e, 0x60, 0x9a, 0xf3, 0x68, 0x37, 0xd0, 0xb1, 0xc2, 0xff, 0xba, + 0xd1, 0xc9, 0xb5, 0xc1, 0x96, 0x24, 0x7d, 0xdc, 0x9c, 0x7b, 0xf9, 0xea, 0x53, 0xa7, 0x93, 0x8f, + 0x5e, 0xd3, 0xcc, 0xa6, 0xed, 0xea, 0x2e, 0x44, 0x12, 0xda, 0xbf, 0x03, 0xc5, 0x1c, 0xdf, 0x75, + 0xa3, 0x7d, 0x92, 0x56, 0xda, 0xb5, 0x3c, 0x6e, 0x0d, 0x0d, 0xf9, 0xd6, 0xd4, 0x43, 0x98, 0xab, + 0xd0, 0x15, 0xc1, 0x27, 0xf2, 0x1c, 0x35, 0x99, 0x4e, 0xeb, 0x89, 0x5c, 0x21, 0x98, 0x5d, 0xe9, + 0x95, 0x1d, 0xc4, 0xd4, 0xbe, 0x69, 0x4e, 0x16, 0x39, 0x02, 0x43, 0x66, 0x08, 0x9e, 0x83, 0x22, + 0x99, 0x95, 0x2f, 0x25, 0x09, 0x73, 0xfe, 0x61, 0x12, 0xd5, 0x95, 0x5e, 0xdc, 0x92, 0x22, 0x52, + 0xc5, 0xd8, 0xc9, 0xda, 0xfd, 0xcf, 0x97, 0x62, 0xe6, 0xf9, 0x0a, 0xf9, 0xec, 0xac, 0x4f, 0x64, + 0xc8, 0x9e, 0x5f, 0x3e, 0x0e, 0x5b, 0xd2, 0xcb, 0x78, 0x49, 0x2a, 0x52, 0x8a, 0xa1, 0x70, 0xb8, + 0x4a, 0x14, 0xcb, 0xd1, 0xdf, 0x6f, 0x9e, 0x37, 0x95, 0xef, 0x98, 0x86, 0xf9, 0xa2, 0xaf, 0x14, + 0xb7, 0x98, 0xaf, 0xb9, 0x0a, 0x7d, 0xc5, 0xb1, 0x76, 0x37, 0x9c, 0x0e, 0x62, 0x42, 0x09, 0x10, + 0xf1, 0x92, 0x6a, 0x41, 0x79, 0x1f, 0x5b, 0xe4, 0x89, 0x98, 0xb0, 0xd8, 0x6e, 0x9d, 0x22, 0x25, + 0x22, 0x58, 0xcd, 0x46, 0xe1, 0x2e, 0xd0, 0x86, 0x1c, 0x89, 0x50, 0xea, 0x26, 0xeb, 0xd3, 0x3c, + 0x14, 0xca, 0x68, 0x04, 0xa6, 0x4c, 0x80, 0x3c, 0x58, 0xd8, 0xf3, 0x2c, 0x15, 0xcb, 0x26, 0xd8, + 0xb3, 0x86, 0x3b, 0x9b, 0x5e, 0xb8, 0x8f, 0xdc, 0x4d, 0x02, 0xa3, 0x23, 0xd7, 0x09, 0x53, 0x65, + 0xbd, 0xa7, 0x79, 0xd4, 0xf1, 0xd4, 0x5f, 0x59, 0x91, 0x3b, 0xff, 0xdd, 0x8a, 0x37, 0xe4, 0x43, + 0xfd, 0xd2, 0xd3, 0xab, 0x2a, 0x53, 0xa5, 0xc3, 0xd3, 0xd1, 0x00, 0xdc, 0xf3, 0xcf, 0x8c, 0xb4, + 0xd7, 0x27, 0x5f, 0xfe, 0x74, 0x39, 0x5c, 0x37, 0xa3, 0x6f, 0x1a, 0x06, 0xda, 0x07, 0x7f, 0xe2, + 0x8b, 0xcb, 0x9b, 0x2f, 0x58, 0xba, 0x58, 0x3a, 0xf4, 0xcc, 0xa6, 0x28, 0x77, 0x73, 0xad, 0xd4, + 0x09, 0xff, 0x80, 0x24, 0xf7, 0x55, 0x84, 0x11, 0xa6, 0xb7, 0x9b, 0xac, 0x91, 0xf1, 0x12, 0xdb, + 0xf8, 0xa5, 0x1d, 0xa0, 0xd5, 0xb8, 0xc5, 0x34, 0xb3, 0x52, 0x01, 0x89, 0xcb, 0x82, 0x4e, 0x70, + 0x3f, 0x95, 0x54, 0x7b, 0x3b, 0xd3, 0xde, 0xc0, 0x1d, 0x08, 0xf6, 0x17, 0xc3, 0xad, 0x34, 0x38, + 0x47, 0xe3, 0xb2, 0xca, 0xaa, 0xed, 0xfc, 0x2c, 0x33, 0x39, 0xe2, 0xfb, 0x37, 0x36, 0x64, 0xbe, + 0x20, 0x6d, 0x92, 0x6d, 0x0f, 0xa3, 0xb8, 0xd0, 0x8b, 0xcd, 0x6e, 0x50, 0xe1, 0x47, 0x8a, 0x87, + 0x92, 0xfe, 0xca, 0x96, 0xda, 0x7c, 0x9d, 0x4f, 0xa2, 0x9d, 0xb3, 0x8c, 0xc4, 0xd1, 0x12, 0x26, + 0xf4, 0xb8, 0x4f, 0xa3, 0xe7, 0xde, 0x77, 0x2a, 0xaa, 0x8c, 0xc7, 0xed, 0xcc, 0x88, 0x64, 0xa4, + 0x09, 0x4b, 0x0d, 0xca, 0x4c, 0x19, 0xbf, 0xea, 0x65, 0x41, 0xcb, 0x47, 0x57, 0x24, 0x3b, 0x6f, + 0x38, 0x9f, 0xa8, 0x0a, 0x76, 0xf4, 0x77, 0xd3, 0xb8, 0xea, 0x1d, 0xd3, 0x79, 0x6c, 0x9c, 0xaa, + 0x13, 0x66, 0x85, 0x87, 0xb2, 0x12, 0x2e, 0x64, 0x75, 0xf2, 0xea, 0x13, 0xd0, 0xba, 0x9e, 0x33, + 0xee, 0x04, 0xfa, 0xdd, 0xbd, 0x5f, 0xe3, 0xcf, 0x8f, 0x2f, 0xfd, 0x2f, 0x5b, 0xa8, 0xa4, 0x61, + 0xba, 0x75, 0x3a, 0x2d, 0x84, 0xee, 0xc8, 0xfc, 0xda, 0xb8, 0xad, 0x76, 0x1b, 0x7a, 0x73, 0x01, + 0xa7, 0x6a, 0xcb, 0x48, 0x6a, 0xdc, 0x5d, 0xa9, 0xd7, 0x6b, 0x91, 0xc1, 0x5d, 0x7c, 0x19, 0xbe, + 0x35, 0xdc, 0x4f, 0x99, 0x72, 0x8d, 0x89, 0xdd, 0x65, 0x9b, 0x01, 0x60, 0x2b, 0xfe, 0xfd, 0xa1, + 0x85, 0x0d, 0x61, 0xdb, 0x43, 0x41, 0x68, 0xfc, 0xdf, 0x8c, 0xb2, 0x2d, 0xef, 0xea, 0xa7, 0x27, + 0xa0, 0xf9, 0x75, 0x34, 0x8e, 0xaa, 0xa7, 0x1b, 0x39, 0x61, 0x50, 0x52, 0xad, 0x0d, 0xe8, 0xd0, + 0x0e, 0x34, 0x6a, 0x75, 0xc5, 0x07, 0xd0, 0x65, 0xa5, 0xda, 0xe7, 0x62, 0xce, 0xe5, 0xa2, 0x81, + 0xc0, 0x12, 0x91, 0x63, 0x8b, 0x90, 0xbc, 0xd9, 0xc2, 0xae, 0xf0, 0x17, 0x84, 0xb6, 0x7d, 0x11, + 0x15, 0xf6, 0x42, 0xd9, 0x34, 0x57, 0x3f, 0x53, 0xe7, 0x27, 0x7c, 0x9a, 0x95, 0x70, 0xf8, 0x2c, + 0xba, 0xba, 0xa8, 0xd7, 0x88, 0x27, 0x39, 0xb3, 0x09, 0x5e, 0x63, 0x6a, 0xce, 0x5e, 0x89, 0xa4, + 0x57, 0xb3, 0xd4, 0x29, 0x0a, 0x88, 0xff, 0xea, 0xd7, 0x87, 0xe1, 0xf6, 0x01, 0xc1, 0xf7, 0xfe, + 0x07, 0x92, 0x6f, 0x19, 0x29, 0xbc, 0x1f, 0x33, 0x5d, 0xdf, 0x30, 0x0c, 0x3f, 0xbd, 0x37, 0x62, + 0xd9, 0xab, 0x02, 0xe8, 0x57, 0xb1, 0x76, 0xd2, 0x9e, 0x0d, 0x7a, 0xb0, 0x75, 0x14, 0x4e, 0xd7, + 0x36, 0xeb, 0x2d, 0x2f, 0x30, 0xed, 0xa9, 0x5f, 0x5a, 0x09, 0xbb, 0xde, 0xde, 0xab, 0xc4, 0xea, + 0x11, 0x7f, 0x07, 0x8b, 0x37, 0x3f, 0x19, 0x06, 0x78, 0xf8, 0x76, 0x59, 0x11, 0x80, 0xa2, 0xeb, + 0xf6, 0xe7, 0xea, 0x4b, 0xda, 0x07, 0x5f, 0xf6, 0xcb, 0x47, 0x83, 0x9d, 0x71, 0x75, 0x3b, 0x5c, + 0x4b, 0x2c, 0xdb, 0xb5, 0xda, 0xd9, 0x05, 0x69, 0xe3, 0x1f, 0xee, 0x8e, 0x6a, 0xdf, 0x31, 0x7d, + 0x8b, 0x83, 0x48, 0xb8, 0x2b, 0x69, 0x9c, 0x0f, 0xa3, 0x92, 0xef, 0x91, 0x7a, 0x10, 0xa5, 0x53, + 0x63, 0x4a, 0xa0, 0x1b, 0xaa, 0x94, 0xa9, 0x06, 0x22, 0xd3, 0x4b, 0xe3, 0x7d, 0xa6, 0x35, 0x71, + 0x75, 0x89, 0x2d, 0x50, 0xf8, 0xd0, 0xd4, 0xad, 0xd8, 0x22, 0xbf, 0x46, 0xe3, 0xbe, 0x46, 0x54, + 0x25, 0x88, 0x78, 0x90, 0x73, 0x03, 0x6b, 0xe4, 0x91, 0x84, 0xe4, 0xba, 0xbf, 0x6b, 0x1d, 0x21, + 0x5e, 0x71, 0x3c, 0x47, 0x04, 0xd3, 0x8b, 0x65, 0xcc, 0xab, 0xc6, 0x75, 0x68, 0x17, 0xb7, 0x7e, + 0x87, 0xce, 0x1f, 0x42, 0x51, 0x4c, 0xd6, 0xee, 0x58, 0x0d, 0x27, 0x6c, 0xc9, 0x5f, 0x97, 0x41, + 0x3f, 0xe7, 0x2f, 0xb7, 0x23, 0x37, 0x78, 0x72, 0x2a, 0x65, 0x5d, 0x93, 0xdb, 0xf3, 0x65, 0xab, + 0xfc, 0xf4, 0xba, 0x5e, 0x2a, 0xed, 0x5f, 0x04, 0x78, 0x47, 0x47, 0x30, 0x37, 0xf6, 0xbd, 0x99, + 0xe9, 0x9a, 0x7b, 0xe7, 0xcd, 0x50, 0xce, 0xbc, 0x4f, 0xf2, 0x72, 0x1e, 0xe9, 0xee, 0x16, 0xf0, + 0x35, 0xda, 0x8a, 0xf2, 0x78, 0x96, 0x13, 0x06, 0x6d, 0xf6, 0x21, 0x2f, 0x60, 0x56, 0x7b, 0x11, + 0xae, 0x5a, 0x9b, 0x7d, 0x4d, 0xd5, 0x6c, 0x42, 0x43, 0xfa, 0x27, 0xb9, 0xdb, 0x3f, 0x30, 0x3b, + 0x4f, 0x76, 0x0e, 0xa8, 0xae, 0x9a, 0x2a, 0xa1, 0xb4, 0x14, 0x58, 0x24, 0xb1, 0x7f, 0x93, 0x80, + 0x53, 0xa0, 0x62, 0x54, 0x8f, 0x68, 0x17, 0x1c, 0xcb, 0x37, 0xc1, 0x65, 0x71, 0xd1, 0x78, 0xd1, + 0x86, 0xb7, 0x9c, 0x24, 0xa7, 0x4b, 0xbb, 0x35, 0x9d, 0xe4, 0xd0, 0xe7, 0xe9, 0x97, 0xbf, 0x93, + 0x5a, 0x49, 0x14, 0xea, 0xba, 0x1f, 0x04, 0x71, 0xe2, 0x31, 0x8b, 0xde, 0xbf, 0xb4, 0xbb, 0x5c, + 0x38, 0xf2, 0x93, 0xe4, 0xb8, 0x12, 0x6b, 0xea, 0x0a, 0x3a, 0xb5, 0x12, 0xf4, 0x25, 0x55, 0xcd, + 0xe4, 0x62, 0x67, 0xe1, 0x4e, 0xd8, 0xea, 0x1a, 0x73, 0xb4, 0x42, 0xf2, 0x7f, 0x57, 0xe6, 0x2d, + 0xd0, 0x2e, 0x57, 0x1d, 0x17, 0xeb, 0xf4, 0xc5, 0xdf, 0xbb, 0x26, 0x00, 0x08, 0xeb, 0x1d, 0xd3, + 0xc9, 0xd1, 0x9e, 0xdf, 0x27, 0x95, 0xd6, 0xe4, 0x5e, 0x9c, 0x85, 0x98, 0x6b, 0xa1, 0x34, 0x4a, + 0xb7, 0x48, 0xa1, 0x81, 0xef, 0xc4, 0x7b, 0xd7, 0x75, 0xe4, 0xa1, 0x38, 0x78, 0xa2, 0x5f, 0xfa, + 0x08, 0xac, 0x64, 0xaf, 0x9b, 0x8f, 0x7b, 0xa3, 0xb2, 0xec, 0x47, 0x50, 0xf2, 0x24, 0x81, 0xa9, + 0xf9, 0x3f, 0x11, 0x8d, 0xc8, 0x0a, 0xeb, 0xfd, 0x0b, 0x49, 0x9e, 0xe1, 0x2e, 0xdd, 0x99, 0xa8, + 0xf7, 0x5f, 0x4d, 0x7d, 0xa3, 0xcf, 0x23, 0xc2, 0x4d, 0xbb, 0xea, 0x7a, 0x34, 0x16, 0xd7, 0x04, + 0x44, 0x2e, 0xdf, 0xf9, 0x64, 0xb3, 0xd6, 0x64, 0xad, 0x77, 0x12, 0x00, 0x7d, 0xfb, 0x59, 0x1f, + 0x4d, 0xe8, 0xe7, 0xf3, 0x0a, 0x09, 0x26, 0x7f, 0x24, 0xc9, 0x87, 0x8d, 0xf8, 0x55, 0x7f, 0x3e, + 0xcc, 0x39, 0x83, 0xc6, 0xa5, 0xfb, 0x26, 0xa4, 0x3e, 0xb8, 0x3c, 0x9b, 0xca, 0xac, 0x5a, 0xa3, + 0x27, 0x1a, 0x45, 0xe2, 0xeb, 0x84, 0x25, 0x8b, 0xf6, 0x37, 0x13, 0xd4, 0x79, 0xd0, 0x3f, 0xbc, + 0x8b, 0xab, 0xb4, 0x84, 0xd5, 0xd5, 0x6b, 0x48, 0x5c, 0xfd, 0x99, 0x95, 0xaa, 0x5c, 0x52, 0x99, + 0x74, 0xa0, 0x5d, 0x4b, 0x5a, 0x68, 0x6b, 0x1c, 0xe0, 0xd2, 0xa7, 0x9f, 0xff, 0xdd, 0x5d, 0x20, + 0x2d, 0x32, 0x62, 0x68, 0x77, 0xff, 0x8d, 0x19, 0xee, 0x1e, 0x5b, 0xed, 0xdb, 0xb8, 0x49, 0x86, + 0xc6, 0x05, 0x32, 0xfb, 0x50, 0x67, 0x15, 0x21, 0x2f, 0x56, 0x5f, 0x30, 0x89, 0x9b, 0x80, 0xc7, + 0x9f, 0x95, 0x7e, 0xfd, 0xbe, 0xda, 0xaf, 0x13, 0xa9, 0x5f, 0x15, 0xf5, 0x38, 0xa8, 0xb0, 0x66, + 0xc6, 0xc1, 0x04, 0xab, 0xcc, 0xa1, 0x32, 0x85, 0x79, 0x43, 0x2f, 0x81, 0x15, 0xc8, 0x00, 0x3c, + 0xd9, 0x94, 0xdc, 0x25, 0xd6, 0x34, 0x20, 0xfd, 0x9f, 0xf0, 0x4d, 0x42, 0xf7, 0xd3, 0x2f, 0x92, + 0x53, 0xd2, 0x6e, 0x55, 0x4e, 0xc3, 0x44, 0x14, 0x36, 0x3a, 0xa1, 0xc4, 0x5f, 0x17, 0xdd, 0xdd, + 0xa5, 0x78, 0xfd, 0x92, 0xb2, 0xcb, 0xdd, 0x0e, 0x2a, 0x1f, 0xb6, 0xfc, 0x3e, 0xc1, 0xd6, 0x6f, + 0x7a, 0xc7, 0xf4, 0x9c, 0x15, 0x8d, 0xe3, 0xf3, 0xcb, 0xf8, 0xeb, 0x2e, 0xf3, 0x4f, 0x74, 0xec, + 0x11, 0xa6, 0xf8, 0x3e, 0x9b, 0x9f, 0xe7, 0xc4, 0x4f, 0x54, 0x1b, 0xc5, 0x60, 0xa7, 0xa8, 0x4b, + 0x47, 0xe7, 0xe0, 0xd8, 0xa5, 0x67, 0x66, 0x63, 0x12, 0x3b, 0x4b, 0x47, 0x52, 0x46, 0x5b, 0x54, + 0xb5, 0x68, 0x0c, 0x9f, 0xac, 0xae, 0x64, 0xa3, 0x77, 0x01, 0x99, 0xd0, 0x9d, 0x26, 0x10, 0x44, + 0xe9, 0xdd, 0x5c, 0x6d, 0x98, 0x5f, 0xd3, 0x61, 0x40, 0xef, 0x6f, 0x76, 0xcb, 0x66, 0x68, 0xae, + 0x54, 0xf0, 0x86, 0xe0, 0xcf, 0xdb, 0xce, 0xd0, 0x34, 0xb3, 0xd9, 0xc5, 0x64, 0x94, 0x4e, 0xe9, + 0x59, 0x5c, 0x46, 0xc2, 0x91, 0xa4, 0x80, 0xf2, 0xea, 0x67, 0xe6, 0xac, 0xe7, 0xee, 0xb5, 0xa5, + 0xd3, 0x7b, 0x5a, 0xc5, 0xef, 0xba, 0xc6, 0x1d, 0x89, 0xde, 0x3d, 0x37, 0x55, 0x29, 0x8c, 0xd0, + 0xa7, 0x5f, 0x4f, 0xee, 0x6a, 0xf2, 0xb6, 0xbb, 0xed, 0x56, 0xaa, 0xc1, 0xd3, 0xab, 0x2a, 0xf7, + 0x8c, 0xbe, 0x43, 0xb1, 0xa2, 0xd1, 0x11, 0x9a, 0xe7, 0x97, 0xb5, 0x08, 0xc3, 0x85, 0x87, 0x36, + 0x24, 0x86, 0x33, 0x44, 0x6c, 0xab, 0xef, 0xbf, 0xdc, 0x4c, 0xb7, 0xbb, 0x2c, 0x64, 0x5e, 0xf2, + 0xd3, 0x23, 0xd6, 0xf5, 0x12, 0xc1, 0xa5, 0x5e, 0xef, 0x95, 0x85, 0x89, 0x39, 0x47, 0xf4, 0x5a, + 0xcf, 0x3a, 0x3e, 0xbd, 0xa1, 0x8c, 0x44, 0x82, 0xf9, 0xb9, 0x0a, 0x8a, 0xd7, 0xd4, 0x16, 0x51, + 0xd4, 0x1a, 0xf7, 0x04, 0xaf, 0xfa, 0x0b, 0xc5, 0xfd, 0x89, 0xaa, 0x5f, 0x1c, 0x7b, 0x28, 0x39, + 0xae, 0xae, 0x88, 0xf9, 0x26, 0x85, 0x05, 0x0f, 0x21, 0x7f, 0x9f, 0x7c, 0xe1, 0x64, 0xca, 0xcc, + 0xa5, 0x22, 0xe0, 0x43, 0xa6, 0x15, 0x2d, 0x72, 0xd8, 0xe7, 0xf1, 0xc8, 0x4f, 0x75, 0x3e, 0xac, + 0x5f, 0x9d, 0xd7, 0x6d, 0xc6, 0x4d, 0xc1, 0xca, 0xb9, 0xf3, 0x01, 0x8e, 0x01, 0xd7, 0x6d, 0xe5, + 0x5a, 0x51, 0x96, 0x96, 0xc7, 0x20, 0x03, 0x39, 0xd2, 0xc5, 0x4e, 0xfd, 0xcb, 0xaa, 0xe7, 0xe8, + 0xef, 0x55, 0x6f, 0xce, 0x83, 0x77, 0x4c, 0x33, 0x5f, 0xae, 0xe1, 0x59, 0x55, 0x95, 0xe7, 0x87, + 0x2b, 0xa6, 0xbe, 0xc0, 0xc9, 0xb6, 0x0e, 0xb4, 0x27, 0x6a, 0xa9, 0x9c, 0x4c, 0x68, 0x49, 0x13, + 0x7d, 0x32, 0x33, 0xe9, 0xbd, 0xa6, 0x7a, 0x99, 0xa8, 0x03, 0x3b, 0x40, 0xca, 0x57, 0x5e, 0x50, + 0xac, 0xb3, 0x88, 0x57, 0x8c, 0x52, 0x51, 0x74, 0x81, 0x88, 0xbb, 0x49, 0xd3, 0xeb, 0x26, 0x30, + 0x8f, 0xf5, 0xe4, 0x81, 0x74, 0x96, 0xd0, 0x9f, 0x61, 0x10, 0x17, 0x31, 0xb8, 0x51, 0x6e, 0xc4, + 0x46, 0x77, 0xea, 0x2e, 0x89, 0x53, 0xc1, 0x16, 0xe0, 0xbb, 0x52, 0x28, 0x9f, 0x1a, 0x37, 0xc7, + 0x57, 0xe9, 0xe5, 0xa5, 0x4a, 0x64, 0x57, 0xbf, 0x9c, 0xcc, 0x27, 0x64, 0x22, 0x68, 0xeb, 0xc2, + 0x29, 0x16, 0x9e, 0x83, 0x5e, 0xc5, 0x32, 0x4f, 0xfa, 0x47, 0x5e, 0x26, 0x1c, 0xb7, 0x22, 0x18, + 0x79, 0xe5, 0x59, 0x0e, 0x99, 0x50, 0x6a, 0x56, 0x8c, 0x6a, 0xd4, 0x0f, 0xa9, 0xba, 0x56, 0xd9, + 0xdc, 0x32, 0x38, 0x77, 0x0a, 0x5c, 0x1c, 0x7d, 0x46, 0xd6, 0xed, 0xda, 0x5d, 0x50, 0x6a, 0x3a, + 0xff, 0x59, 0x7b, 0x75, 0xee, 0x05, 0x99, 0xa3, 0xb7, 0x1d, 0x32, 0x5c, 0xc4, 0xaa, 0xad, 0x8d, + 0x85, 0x6e, 0x2c, 0x92, 0x2e, 0xca, 0x8d, 0x30, 0x6f, 0x24, 0x95, 0xf9, 0x99, 0x66, 0x0f, 0x59, + 0x21, 0x88, 0xac, 0x7a, 0xaa, 0x80, 0xef, 0xfb, 0xd4, 0x68, 0x58, 0xbe, 0x20, 0x43, 0xdd, 0x08, + 0x14, 0x9d, 0x09, 0xe9, 0x45, 0xf3, 0x69, 0x63, 0xa7, 0xa9, 0x0b, 0xeb, 0x8e, 0x9b, 0x1e, 0x66, + 0x79, 0x1c, 0xf0, 0xb4, 0x6e, 0xad, 0x60, 0xb0, 0x93, 0xe2, 0x78, 0x17, 0xfc, 0xf6, 0xce, 0xfe, + 0x34, 0x5c, 0x8d, 0xd7, 0x6c, 0xd3, 0x68, 0xf8, 0xed, 0x58, 0x57, 0xdd, 0x34, 0xc3, 0x16, 0xa9, + 0xc1, 0x3d, 0xbb, 0x21, 0xf8, 0x5a, 0x72, 0x2b, 0xcb, 0x68, 0x5c, 0x9b, 0x3b, 0xa8, 0x27, 0x82, + 0x9b, 0x88, 0x26, 0x21, 0x21, 0x17, 0xba, 0x26, 0x10, 0x88, 0x0e, 0xe3, 0x95, 0x15, 0x8d, 0x6b, + 0x7f, 0xf8, 0x7b, 0x1f, 0x21, 0xe0, 0x1d, 0xd3, 0x1b, 0x6c, 0xfc, 0xf4, 0x57, 0xbb, 0x66, 0x3d, + 0xcf, 0xee, 0x46, 0xf6, 0x7d, 0xb3, 0x1c, 0xca, 0xaa, 0xed, 0xe5, 0xb0, 0x2c, 0x48, 0x61, 0x7d, + 0x99, 0x6b, 0x82, 0xe9, 0x15, 0x3b, 0xc3, 0x91, 0xa5, 0x50, 0xa2, 0xa8, 0xb8, 0x1d, 0x24, 0x87, + 0xa3, 0xac, 0xbe, 0x61, 0x8e, 0x19, 0xd2, 0xd5, 0xae, 0xb8, 0x8f, 0x91, 0x32, 0x1b, 0xd2, 0x10, + 0x65, 0x59, 0x94, 0x3a, 0x00, 0x71, 0xb7, 0xa1, 0xa4, 0x36, 0x75, 0x0b, 0xfb, 0xbe, 0xdc, 0xe6, + 0xfb, 0x5a, 0xc6, 0x22, 0x1a, 0x6d, 0xcc, 0xe2, 0x10, 0x28, 0x25, 0xf9, 0x7f, 0xd1, 0x4d, 0xd9, + 0x12, 0x11, 0xf0, 0x48, 0x79, 0xe7, 0xa6, 0xc5, 0x35, 0x4d, 0x4f, 0xdb, 0x0c, 0x0a, 0xc7, 0x22, + 0xed, 0xb2, 0xca, 0x1d, 0x0b, 0x2e, 0x15, 0x33, 0x0a, 0x21, 0x21, 0x90, 0x3c, 0xfe, 0xd7, 0x82, + 0x3d, 0x37, 0x59, 0x1b, 0x52, 0xb3, 0x9e, 0x75, 0x2b, 0x4d, 0xf8, 0x2b, 0x33, 0x84, 0xd3, 0xad, + 0x9a, 0x30, 0xdf, 0xf6, 0x02, 0xd9, 0x88, 0x88, 0xb3, 0x96, 0x32, 0x9b, 0xa7, 0x38, 0xfb, 0x20, + 0x7c, 0x38, 0xc6, 0xec, 0xe8, 0xde, 0x09, 0x9a, 0xb2, 0xc6, 0xee, 0xd3, 0xa2, 0x42, 0x7d, 0x02, + 0xda, 0xce, 0x5a, 0xe2, 0x2f, 0xb5, 0xbd, 0xd3, 0x54, 0xe8, 0xe9, 0xb0, 0xbf, 0xac, 0xc5, 0xf5, + 0x17, 0x27, 0x9b, 0xa1, 0xac, 0xa9, 0x53, 0x3f, 0xc8, 0xc4, 0xef, 0xea, 0xd8, 0x9b, 0xea, 0xde, + 0xd6, 0x66, 0xcd, 0xb3, 0x03, 0x39, 0x7d, 0x33, 0x0c, 0xb6, 0x94, 0xa4, 0xb9, 0xe5, 0x43, 0x3a, + 0xaa, 0xd5, 0x28, 0x8c, 0xb2, 0xae, 0xbc, 0x3e, 0x14, 0x05, 0x9e, 0x3a, 0xe6, 0x86, 0xa6, 0x74, + 0x87, 0xcc, 0x60, 0xeb, 0x25, 0x43, 0x2a, 0x1c, 0xa1, 0x4e, 0x13, 0x8a, 0x88, 0xdc, 0xab, 0x4b, + 0x75, 0xd3, 0xf7, 0x67, 0x45, 0xa2, 0xe7, 0xe8, 0xef, 0xa4, 0xae, 0x6b, 0x04, 0xc6, 0x43, 0xd4, + 0x81, 0x89, 0x46, 0xea, 0xf3, 0xe8, 0x8b, 0x42, 0x85, 0x2d, 0xf1, 0xe7, 0x60, 0x9f, 0x80, 0x80, + 0xf8, 0xae, 0xff, 0xf7, 0x9e, 0x2b, 0xa1, 0x77, 0x4c, 0x73, 0x63, 0x8f, 0x48, 0x17, 0xb7, 0x85, + 0x7d, 0xa7, 0x0f, 0xc3, 0x2b, 0xe4, 0xdf, 0xd8, 0xa2, 0xb5, 0x31, 0x2b, 0xa3, 0x00, 0x00, 0xd6, + 0xc8, 0xe2, 0xe7, 0x5d, 0x5d, 0xa1, 0xea, 0x61, 0x09, 0x91, 0xfd, 0x63, 0x48, 0xbb, 0x04, 0x3d, + 0x9d, 0xe4, 0xcb, 0x86, 0xfb, 0xe0, 0xaa, 0x78, 0xeb, 0x6b, 0x02, 0xdb, 0xf2, 0x1c, 0x5b, 0x70, + 0x8b, 0x29, 0x2d, 0xdd, 0xe1, 0xdb, 0x69, 0x7f, 0x26, 0x56, 0x4c, 0x21, 0x9b, 0x2b, 0xa9, 0xa3, + 0x09, 0x18, 0x8a, 0x7a, 0x2f, 0x1f, 0x26, 0xda, 0xe8, 0x79, 0x2a, 0xa5, 0x16, 0x06, 0x02, 0xe6, + 0xaf, 0x70, 0x74, 0xbd, 0x57, 0x8c, 0x9f, 0x84, 0x2a, 0xf1, 0xb1, 0xbc, 0xce, 0x29, 0x0b, 0x03, + 0x53, 0xfe, 0x19, 0x6c, 0xcd, 0x83, 0xdb, 0x35, 0x3a, 0x01, 0x5e, 0x05, 0xe7, 0x82, 0x38, 0xc1, + 0x0f, 0x90, 0x7a, 0x07, 0x84, 0xcc, 0xac, 0x82, 0x96, 0xbf, 0x93, 0x13, 0x6f, 0x4b, 0x15, 0xd6, + 0x14, 0x45, 0x69, 0x8d, 0xb5, 0x08, 0xb5, 0xe5, 0xa8, 0xa4, 0x3b, 0xab, 0x61, 0x68, 0x11, 0xef, + 0x5c, 0xb1, 0x8a, 0xf9, 0xe9, 0xb6, 0x44, 0xcf, 0x5e, 0xa8, 0x77, 0x1a, 0xe9, 0x5d, 0x28, 0xbf, + 0xeb, 0xd6, 0xda, 0xad, 0xf8, 0x8f, 0xcc, 0x01, 0xc7, 0xfd, 0xe3, 0x46, 0x5a, 0x74, 0x9c, 0xe7, + 0x64, 0xba, 0xc4, 0x6e, 0x11, 0xe5, 0xef, 0x5c, 0x36, 0x55, 0xa9, 0x31, 0x22, 0xe4, 0x0c, 0xac, + 0xae, 0x8a, 0xf0, 0xaf, 0xa0, 0x76, 0x2b, 0xe5, 0x8e, 0x0c, 0x57, 0x5e, 0x6a, 0xb0, 0xaa, 0x17, + 0x2f, 0x1e, 0x51, 0x9d, 0xcc, 0x76, 0xcc, 0x7f, 0x20, 0x70, 0x01, 0x99, 0x4a, 0xce, 0x83, 0x03, + 0x8a, 0x2d, 0xa9, 0xcd, 0xc9, 0xe4, 0x9e, 0xf6, 0xe7, 0x35, 0x6b, 0xee, 0x44, 0x92, 0x88, 0x7d, + 0x6d, 0xed, 0x37, 0x07, 0x02, 0xe7, 0x0c, 0x53, 0xc4, 0x17, 0xcc, 0x86, 0x04, 0x92, 0x06, 0x3e, + 0x91, 0xbb, 0xb6, 0x33, 0x4d, 0xc3, 0xf5, 0xdd, 0x89, 0x3e, 0xa4, 0xf0, 0xa9, 0x98, 0x3c, 0x7e, + 0xef, 0x67, 0x48, 0x0a, 0x80, 0xbf, 0x4f, 0x91, 0x53, 0xc2, 0xef, 0x98, 0x5e, 0x35, 0xdd, 0xee, + 0xbf, 0xaa, 0x7a, 0xdf, 0xce, 0xa3, 0x33, 0xfd, 0x0c, 0x3f, 0xc8, 0x16, 0x26, 0xe0, 0xd9, 0xb6, + 0x4c, 0xbf, 0x9d, 0xe8, 0xbc, 0x58, 0x44, 0xe9, 0x61, 0x06, 0xd6, 0x7a, 0xe7, 0xac, 0xb4, 0xf4, + 0x21, 0x88, 0x71, 0x7f, 0x0c, 0x0f, 0xec, 0x19, 0x0d, 0xf4, 0x65, 0x4b, 0x5a, 0x3d, 0xf5, 0xaf, + 0x3d, 0x62, 0xdd, 0x1a, 0x59, 0xdc, 0x4f, 0xce, 0xe5, 0xbe, 0xc2, 0x33, 0x1b, 0x36, 0xe0, 0x82, + 0x98, 0xf4, 0x0a, 0xca, 0xd0, 0x17, 0xa6, 0x7d, 0xef, 0x67, 0xcd, 0x54, 0xd0, 0x5b, 0x44, 0x14, + 0x58, 0xff, 0x05, 0x0f, 0xbd, 0xbe, 0xb4, 0x8c, 0xae, 0x9e, 0x42, 0x5c, 0x68, 0x0b, 0xc0, 0xe5, + 0x16, 0xef, 0x74, 0x97, 0x51, 0x32, 0xc8, 0x66, 0xe6, 0xf8, 0xfc, 0xbf, 0x83, 0x5d, 0xe3, 0xb9, + 0xf1, 0x8b, 0x10, 0xcd, 0x59, 0xbb, 0xdd, 0x3f, 0x39, 0xb1, 0xa0, 0x1a, 0x02, 0x04, 0x38, 0x63, + 0x30, 0x94, 0x39, 0xfd, 0x52, 0x21, 0x6e, 0xe2, 0x0a, 0x45, 0x32, 0x51, 0xfe, 0xc6, 0x7c, 0x7e, + 0x55, 0xaf, 0x49, 0x28, 0x2c, 0x2b, 0xbd, 0x74, 0xff, 0x2b, 0x81, 0xd2, 0x3e, 0xaa, 0x46, 0xd9, + 0x65, 0xfe, 0x1b, 0x9e, 0xba, 0x1a, 0x98, 0x08, 0x88, 0xa6, 0x32, 0x55, 0xf0, 0xe8, 0xfc, 0x4b, + 0x62, 0x93, 0xc2, 0x1a, 0x21, 0xed, 0x8f, 0xbf, 0x1e, 0x84, 0xf2, 0xa0, 0x73, 0x2d, 0x7c, 0xd6, + 0x80, 0xa8, 0x9b, 0xc8, 0xd9, 0x65, 0x0b, 0xec, 0x76, 0xba, 0xcc, 0xa2, 0x61, 0xe7, 0xba, 0xc9, + 0x8a, 0x79, 0x2b, 0x50, 0xce, 0x00, 0xec, 0x2e, 0x58, 0xbc, 0xd7, 0x70, 0x5e, 0x26, 0xc1, 0x42, + 0xf4, 0x2b, 0xc7, 0x41, 0xcd, 0xf2, 0x39, 0x12, 0xea, 0x46, 0x70, 0x35, 0x58, 0xa5, 0xa3, 0x46, + 0x7f, 0x4b, 0x25, 0x94, 0xdd, 0x3d, 0x63, 0xb7, 0x16, 0xd9, 0x36, 0xbd, 0xfa, 0x17, 0xde, 0x37, + 0x8d, 0x8a, 0xc3, 0xff, 0xc7, 0xde, 0x1b, 0xf4, 0xa4, 0x92, 0x75, 0x01, 0xbb, 0x7f, 0xa6, 0x39, + 0x06, 0x7d, 0xd5, 0xa4, 0xfb, 0x55, 0x83, 0x36, 0xe7, 0x8c, 0x2d, 0x1a, 0x48, 0x0a, 0xaa, 0x08, + 0x20, 0x38, 0x11, 0x0d, 0x20, 0x90, 0x80, 0x40, 0x04, 0xb1, 0xff, 0x03, 0x52, 0x10, 0x41, 0x64, + 0x62, 0x41, 0xaa, 0xca, 0x82, 0x04, 0x2c, 0x08, 0x60, 0xe1, 0x18, 0x6c, 0x34, 0x01, 0x0b, 0x02, + 0x08, 0x4c, 0x44, 0x02, 0x08, 0x24, 0x2a, 0x10, 0xf5, 0xd8, 0xef, 0xb5, 0xef, 0xe0, 0x4e, 0x4e, + 0x9f, 0xe9, 0x97, 0xdc, 0x2f, 0x3e, 0x03, 0x62, 0x62, 0x08, 0xe4, 0xa9, 0xcd, 0xda, 0x6b, 0x57, + 0xad, 0xbd, 0x36, 0x6d, 0xb0, 0x45, 0xb7, 0x7d, 0x9d, 0xbf, 0xfb, 0xda, 0x29, 0x43, 0xcd, 0x75, + 0xfc, 0x4e, 0x5c, 0x5b, 0x74, 0x72, 0xf5, 0xfc, 0x1f, 0xbd, 0x1f, 0xcf, 0xa0, 0x1c, 0x65, 0x7f, + 0x62, 0x9a, 0x3b, 0x56, 0x98, 0xda, 0xd7, 0x69, 0xe8, 0xa8, 0xdc, 0x5f, 0x38, 0x2e, 0x90, 0x73, + 0xb5, 0x9b, 0xf8, 0xb8, 0xb3, 0x1c, 0xd1, 0xee, 0x2a, 0x45, 0x86, 0xc8, 0x66, 0xe8, 0x37, 0x44, + 0x47, 0x48, 0xaa, 0x1e, 0x7f, 0x6d, 0x4c, 0x6b, 0xdc, 0xe3, 0xa0, 0x94, 0xec, 0xaf, 0x2f, 0x9a, + 0xdc, 0x01, 0x34, 0x69, 0x97, 0x78, 0xcc, 0xeb, 0xe9, 0xfc, 0xe8, 0x77, 0xea, 0xc5, 0xeb, 0x31, + 0x67, 0xd5, 0x31, 0x77, 0x68, 0x55, 0x04, 0x33, 0xea, 0x8e, 0xad, 0x1f, 0x48, 0x12, 0xb2, 0xf8, + 0xba, 0x66, 0xb0, 0x0b, 0x29, 0xeb, 0x4b, 0x3a, 0x6a, 0xa4, 0x80, 0x16, 0x24, 0x08, 0xb5, 0x2b, + 0xf3, 0x2a, 0x29, 0x5a, 0xe0, 0xb6, 0x0e, 0x77, 0x5f, 0x32, 0x5b, 0xe5, 0xf6, 0xae, 0x71, 0xe7, + 0xe5, 0x4d, 0x10, 0x8e, 0xd8, 0xdb, 0x15, 0xb9, 0xee, 0x28, 0x61, 0xd6, 0x3c, 0x74, 0x16, 0x4a, + 0x71, 0x53, 0x68, 0x51, 0x54, 0xea, 0x2b, 0x60, 0xd3, 0x65, 0xc0, 0xd5, 0x66, 0x23, 0x10, 0x64, + 0x68, 0xdc, 0x34, 0x7c, 0x2b, 0x66, 0x81, 0xd6, 0x7a, 0x65, 0xe2, 0x47, 0x28, 0x09, 0x47, 0xd0, + 0x5b, 0x87, 0x64, 0xa3, 0xfb, 0xd1, 0xd2, 0xd2, 0x9f, 0xeb, 0x96, 0x48, 0x21, 0x57, 0x20, 0x46, + 0xaf, 0x56, 0xdd, 0xd1, 0xe8, 0x2b, 0x05, 0x7e, 0x24, 0x33, 0x8e, 0x90, 0x4e, 0x65, 0x50, 0x9e, + 0x8f, 0xee, 0x0d, 0x22, 0x86, 0xe1, 0x8f, 0x8b, 0xad, 0xa3, 0x57, 0x6b, 0xb7, 0xa6, 0x6d, 0xa6, + 0x7d, 0xa2, 0xba, 0xdc, 0xbc, 0x46, 0xcc, 0x36, 0x46, 0xf9, 0xad, 0xdf, 0x47, 0x93, 0x0b, 0xad, + 0x5c, 0xfa, 0xfa, 0x70, 0x37, 0x4a, 0x48, 0x46, 0x23, 0x6b, 0x07, 0x04, 0x22, 0xfa, 0x97, 0xe5, + 0x48, 0x84, 0x59, 0x8a, 0x65, 0x86, 0xf2, 0x91, 0x2e, 0xdd, 0xfa, 0x6f, 0x64, 0xfa, 0x29, 0xe1, + 0xc6, 0x06, 0x57, 0x4d, 0x29, 0xdf, 0x12, 0x7e, 0x4a, 0x5c, 0x00, 0xee, 0x08, 0xf9, 0x9a, 0x9a, + 0xd0, 0x04, 0x5c, 0xb4, 0x4b, 0xb6, 0xf0, 0x3e, 0x15, 0xd9, 0x27, 0xf5, 0x47, 0x3e, 0xea, 0xc7, + 0x3e, 0x42, 0xf9, 0x9f, 0x98, 0x96, 0xcf, 0xef, 0x13, 0x5b, 0x94, 0x21, 0x6e, 0x95, 0xbd, 0xc9, + 0xa2, 0x43, 0x9a, 0x67, 0x73, 0xf9, 0xb7, 0x18, 0x8d, 0xbb, 0x5a, 0xfb, 0x06, 0x97, 0x62, 0xe7, + 0xc3, 0xd5, 0xa7, 0x9d, 0x9a, 0x01, 0xaa, 0x6b, 0x93, 0x71, 0x8d, 0xc6, 0x4b, 0xe8, 0x24, 0x36, + 0x74, 0x11, 0x4d, 0x1a, 0xbf, 0x1f, 0x75, 0x61, 0x83, 0xe1, 0xb4, 0xa5, 0xa3, 0x34, 0xa3, 0xb7, + 0x15, 0x2d, 0x89, 0xf6, 0x61, 0x66, 0x4b, 0x27, 0x95, 0xe2, 0x34, 0x59, 0x2b, 0x53, 0x8f, 0xb5, + 0xd2, 0x88, 0xd0, 0x54, 0xf1, 0x98, 0xb2, 0x6e, 0x8e, 0xc8, 0xd3, 0x31, 0xcf, 0xfa, 0x9c, 0x72, + 0x7d, 0x7f, 0x24, 0x41, 0xec, 0x0b, 0x2c, 0x7e, 0xdc, 0x77, 0xdc, 0x01, 0x52, 0xca, 0x72, 0x99, + 0xa2, 0x8e, 0x5f, 0x33, 0xf4, 0x68, 0xe3, 0x5d, 0xbd, 0x1f, 0x0b, 0x6c, 0x5f, 0x2c, 0x96, 0xe8, + 0x10, 0xad, 0x7b, 0x92, 0x10, 0x89, 0xb9, 0xaa, 0xe3, 0x64, 0x52, 0xa1, 0xb6, 0xab, 0x18, 0x20, + 0x66, 0x5a, 0x3a, 0x19, 0x78, 0xd3, 0xab, 0x14, 0xfe, 0x8a, 0x86, 0xd2, 0x33, 0xf6, 0x2e, 0x91, + 0x5e, 0x90, 0x1d, 0x5d, 0x48, 0x25, 0x32, 0x71, 0x4f, 0x9f, 0xfb, 0xab, 0x84, 0x42, 0x90, 0xc4, + 0x51, 0xc3, 0x06, 0xd4, 0xb1, 0x2b, 0x2b, 0xf7, 0x98, 0x2b, 0xfd, 0xa1, 0x7b, 0xa3, 0xbe, 0x1c, + 0x75, 0x34, 0xaa, 0xbd, 0x55, 0x83, 0x62, 0x2f, 0x6b, 0x81, 0x10, 0xb4, 0x6b, 0xbb, 0x20, 0x1d, + 0xea, 0x74, 0xf1, 0xac, 0x2f, 0x11, 0x15, 0xe2, 0x54, 0x48, 0x56, 0xd2, 0xf5, 0x16, 0x0c, 0xe9, + 0xb7, 0x76, 0x6d, 0xce, 0xe6, 0x3c, 0x21, 0x0b, 0xe6, 0x26, 0x6b, 0x77, 0xd6, 0x13, 0xa9, 0xc6, + 0x93, 0x16, 0x85, 0x5f, 0x26, 0x90, 0xc7, 0xfb, 0x41, 0xcc, 0x6f, 0xa7, 0xe6, 0xd3, 0x83, 0x77, + 0xc6, 0xdc, 0xdb, 0x0b, 0x84, 0xd0, 0x41, 0x43, 0xdc, 0x68, 0x26, 0xc8, 0x68, 0xf8, 0x62, 0xee, + 0x02, 0xda, 0x68, 0x2d, 0x5b, 0xc8, 0x29, 0x42, 0x7f, 0xb1, 0x55, 0x26, 0xe2, 0xb7, 0x91, 0x1f, + 0xe3, 0xf4, 0x42, 0xf2, 0x27, 0xa6, 0xd7, 0x77, 0xcb, 0x54, 0xa8, 0xff, 0x77, 0x5e, 0xa7, 0xb0, + 0x4a, 0xcd, 0x31, 0x66, 0xb7, 0x9f, 0xdf, 0x09, 0xf5, 0xc0, 0xa6, 0x79, 0xeb, 0x45, 0x1b, 0x6b, + 0xee, 0x25, 0xa6, 0x2f, 0x42, 0xda, 0x45, 0x5b, 0x9f, 0xa8, 0x43, 0xc0, 0xa3, 0x76, 0x90, 0x7d, + 0xb3, 0x2a, 0x90, 0x65, 0xdb, 0x24, 0xea, 0x99, 0x81, 0xbc, 0xeb, 0xb5, 0xc5, 0x41, 0xea, 0x38, + 0x91, 0x2f, 0x42, 0x1e, 0x4c, 0xdf, 0x28, 0x27, 0xfa, 0xaf, 0x94, 0x23, 0xa4, 0xdd, 0x7c, 0x49, + 0xf7, 0x90, 0xe6, 0xac, 0x73, 0x7d, 0x90, 0x94, 0x45, 0x48, 0x87, 0x5c, 0x18, 0x1b, 0xba, 0xca, + 0x70, 0xb5, 0x38, 0x55, 0xe3, 0x22, 0xaa, 0x6e, 0x26, 0xb5, 0x6f, 0xfe, 0xa5, 0x91, 0x05, 0x87, + 0x4b, 0xd5, 0xfc, 0x4d, 0x6c, 0x3f, 0x0c, 0x9a, 0x1a, 0x89, 0xd9, 0x3c, 0x10, 0x9b, 0xea, 0x5e, + 0xcb, 0xca, 0x2a, 0x2c, 0x92, 0xf1, 0xc9, 0x39, 0x30, 0xfc, 0xe6, 0x8e, 0x4b, 0xf3, 0x31, 0xfd, + 0x47, 0xba, 0x4a, 0xc0, 0x75, 0x5a, 0x98, 0x58, 0x61, 0x2a, 0xc5, 0x1d, 0xa4, 0xbf, 0x7a, 0x1b, + 0x2b, 0x4d, 0xa4, 0x37, 0x67, 0x3e, 0x20, 0x0b, 0xfa, 0x16, 0xd1, 0x4b, 0xc3, 0xda, 0xf7, 0x46, + 0x65, 0x10, 0x52, 0x7d, 0x33, 0xac, 0x6b, 0x0f, 0x71, 0x53, 0x21, 0x31, 0xc5, 0xab, 0xbb, 0x07, + 0x88, 0x99, 0xa7, 0x45, 0xd8, 0x59, 0x3b, 0xb5, 0x35, 0xf7, 0x1a, 0xb5, 0x91, 0xf6, 0x95, 0x18, + 0x25, 0xa1, 0xa4, 0xef, 0x5a, 0x64, 0xe3, 0x72, 0x19, 0x50, 0x35, 0xb7, 0xaa, 0x65, 0x5a, 0xa1, + 0x37, 0x1a, 0x95, 0xd4, 0x6e, 0x2c, 0x85, 0x57, 0x52, 0x6a, 0x47, 0x93, 0x30, 0xc8, 0x47, 0x5b, + 0x70, 0xdb, 0x64, 0x7c, 0x5b, 0x67, 0xc5, 0xeb, 0x7b, 0x13, 0xe5, 0x04, 0x3c, 0xed, 0x64, 0x2a, + 0x54, 0x8d, 0x5c, 0x99, 0x37, 0x32, 0x2c, 0xfe, 0xa4, 0xf4, 0x74, 0xda, 0x49, 0x08, 0x34, 0xb4, + 0xc4, 0x1c, 0xa6, 0xf1, 0x9e, 0xdd, 0x11, 0x48, 0xc3, 0x0c, 0x6d, 0x55, 0xc4, 0x49, 0x79, 0x99, + 0xfa, 0x3f, 0xd8, 0xdd, 0xc6, 0xcc, 0xfe, 0xc9, 0x35, 0x64, 0xf1, 0xfd, 0x94, 0x6c, 0xc0, 0xcb, + 0x6f, 0xdc, 0xc7, 0x4d, 0x22, 0xdd, 0x5a, 0x7c, 0x64, 0xd7, 0xca, 0x22, 0x56, 0x9d, 0x8b, 0xc1, + 0x2e, 0x65, 0x67, 0xc1, 0xcc, 0x7e, 0xd5, 0x5d, 0x5f, 0xb4, 0x5c, 0x49, 0xca, 0xb4, 0x0d, 0xd9, + 0xa2, 0x35, 0xe3, 0x82, 0xbf, 0x37, 0x6d, 0x84, 0x8e, 0xfb, 0x2b, 0x1c, 0xf0, 0x36, 0x7d, 0xc1, + 0x95, 0x91, 0x06, 0x41, 0x92, 0xdf, 0xde, 0xe2, 0x7c, 0xed, 0x2b, 0xee, 0x3b, 0xa0, 0x3b, 0xf2, + 0xa5, 0xa6, 0x57, 0x1a, 0xbc, 0x69, 0xdc, 0x48, 0x78, 0x87, 0x06, 0x41, 0xc8, 0xbe, 0x52, 0x1f, + 0x2a, 0x0f, 0x93, 0x5c, 0xa1, 0xf8, 0x8e, 0x56, 0x18, 0xd7, 0xbe, 0x47, 0x56, 0x45, 0xdf, 0xfd, + 0x5f, 0x56, 0xed, 0x1e, 0x89, 0x8e, 0xb9, 0x92, 0xb3, 0x2f, 0x68, 0x73, 0xa3, 0xaf, 0x9e, 0x66, + 0x8e, 0xc8, 0x15, 0xde, 0x50, 0x36, 0x52, 0x56, 0x7b, 0xaf, 0xae, 0xdc, 0xab, 0x19, 0x5d, 0xc8, + 0x49, 0x13, 0xa7, 0x37, 0x91, 0xcb, 0x70, 0x84, 0x7b, 0x71, 0x59, 0x93, 0xab, 0xeb, 0x8d, 0xcb, + 0x50, 0x44, 0x99, 0x75, 0xf4, 0x5b, 0xdd, 0x88, 0x28, 0x7d, 0x43, 0x08, 0x60, 0xf1, 0xe8, 0xab, + 0x70, 0xfb, 0x5d, 0x8e, 0x3f, 0x3e, 0x6d, 0x11, 0x5c, 0x60, 0xbf, 0xe1, 0x1a, 0xcd, 0x02, 0xfd, + 0x6d, 0x8c, 0xe3, 0x38, 0xc8, 0x64, 0x47, 0xa6, 0x6a, 0x75, 0xb2, 0x62, 0xb4, 0x64, 0x5e, 0x0c, + 0xb6, 0xf2, 0x0d, 0x16, 0x61, 0x82, 0xa4, 0x79, 0xf7, 0x60, 0xa3, 0x22, 0x2c, 0x51, 0xb2, 0x73, + 0x92, 0x50, 0xa6, 0xd7, 0xed, 0xf9, 0x41, 0xfa, 0xe1, 0xfa, 0xb7, 0xc2, 0x81, 0xae, 0x23, 0xd4, + 0x98, 0xdb, 0x90, 0x21, 0x7c, 0x4a, 0x68, 0xa0, 0xb0, 0xf1, 0x3c, 0xf7, 0x74, 0x40, 0x37, 0x77, + 0x75, 0x80, 0x3c, 0x3d, 0xa8, 0x68, 0x9f, 0x6a, 0x7c, 0x18, 0x3a, 0x63, 0xfa, 0x6a, 0x9b, 0xe3, + 0x06, 0xbf, 0x2c, 0xc8, 0x39, 0x6d, 0x40, 0x4b, 0xf7, 0x57, 0x16, 0xc2, 0xb5, 0x96, 0xb5, 0x52, + 0xf8, 0x8e, 0x7e, 0xed, 0x3d, 0x8c, 0x7e, 0x7c, 0xc6, 0xa0, 0x9a, 0xfd, 0x89, 0xe9, 0xcd, 0x17, + 0x9a, 0x4c, 0xd3, 0x43, 0xbd, 0x92, 0x54, 0x3f, 0xca, 0x75, 0x98, 0x1d, 0xa4, 0x9a, 0x76, 0xe8, + 0xdd, 0x39, 0x76, 0x5f, 0x08, 0xe3, 0x66, 0xfa, 0x4b, 0xc2, 0x6c, 0xe2, 0x96, 0x93, 0x96, 0x75, + 0x48, 0x9a, 0x8b, 0x1f, 0x63, 0x6a, 0xde, 0x5e, 0x60, 0x2a, 0x12, 0xde, 0xe9, 0xbe, 0xd0, 0xe3, + 0xb3, 0xe3, 0xfe, 0x75, 0xe4, 0xe0, 0xe6, 0x4d, 0x0b, 0xdb, 0x15, 0xba, 0x8e, 0xfe, 0x60, 0x24, + 0xa9, 0x4d, 0x3f, 0x05, 0x4a, 0x61, 0x3a, 0x63, 0xe9, 0x5b, 0xed, 0xa5, 0x51, 0x6b, 0x98, 0xb6, + 0xc4, 0x29, 0xf6, 0xb4, 0x0f, 0xed, 0x90, 0x36, 0xf3, 0xf1, 0x79, 0x92, 0x48, 0xf7, 0xcd, 0x7d, + 0xc9, 0xbe, 0xc9, 0x5f, 0x29, 0xda, 0x65, 0x38, 0x56, 0xca, 0x7d, 0xef, 0x06, 0x29, 0x7a, 0x9d, + 0x69, 0x0c, 0x1f, 0x12, 0xf3, 0x9a, 0x5d, 0x89, 0xe2, 0x77, 0xfc, 0xca, 0xde, 0x24, 0xe4, 0xa5, + 0x86, 0xbe, 0xc3, 0x94, 0xd3, 0xc7, 0x7d, 0x9e, 0x84, 0x5f, 0xa4, 0xe6, 0x12, 0xeb, 0xeb, 0xc1, + 0x74, 0xac, 0x6e, 0xed, 0x77, 0xf6, 0x91, 0xea, 0xd1, 0x05, 0x54, 0xa2, 0xce, 0xfb, 0x42, 0x8f, + 0xa9, 0x56, 0x4b, 0xc5, 0x63, 0x84, 0x7a, 0xdc, 0xd3, 0x13, 0x40, 0x55, 0x40, 0x25, 0xda, 0xf1, + 0xb5, 0x68, 0xfa, 0x22, 0x4e, 0x37, 0xa5, 0xb0, 0xc8, 0x55, 0x9e, 0x4d, 0xd5, 0x6d, 0x83, 0xe3, + 0xb7, 0xfa, 0x98, 0x58, 0x62, 0x46, 0x17, 0xe0, 0x6b, 0x7d, 0xd1, 0x6b, 0xb0, 0x8e, 0x26, 0xf1, + 0x8f, 0x55, 0xbd, 0xb6, 0x68, 0x77, 0x74, 0xaa, 0xf9, 0x71, 0xab, 0x31, 0xe0, 0x47, 0xe9, 0x14, + 0xb9, 0x6f, 0xf4, 0x32, 0x2f, 0x7f, 0x24, 0x1a, 0x55, 0xcb, 0x3e, 0xa1, 0xb0, 0xa5, 0xc3, 0x04, + 0xad, 0x85, 0xf7, 0x43, 0xdb, 0xd7, 0xd6, 0xbf, 0x9c, 0x3e, 0xe8, 0x29, 0xf5, 0xe0, 0xe3, 0x81, + 0x7f, 0x14, 0x29, 0x5d, 0xc7, 0xe9, 0x50, 0x94, 0xe8, 0x88, 0x19, 0xdb, 0x52, 0xda, 0xac, 0x43, + 0xb3, 0x1a, 0x70, 0x92, 0x4b, 0xec, 0xb0, 0xea, 0xc7, 0xee, 0x36, 0xa3, 0xd5, 0x9f, 0x98, 0xd6, + 0x54, 0x1a, 0x3b, 0x2d, 0x3a, 0x12, 0xf6, 0x1c, 0x72, 0x6d, 0x0a, 0x8f, 0x5f, 0xa3, 0x1f, 0xa1, + 0x75, 0xf9, 0x92, 0xe3, 0xc9, 0x71, 0x55, 0x34, 0x7e, 0x4c, 0xde, 0xf6, 0xd3, 0xf7, 0x32, 0x31, + 0xc7, 0xb3, 0x73, 0xb5, 0xa0, 0x20, 0x76, 0x87, 0x19, 0x72, 0x56, 0x8e, 0x4c, 0x2a, 0x30, 0xed, + 0xbd, 0x95, 0x10, 0x34, 0xb9, 0x2b, 0x3b, 0x7d, 0x6e, 0x74, 0x08, 0x73, 0xf8, 0xa5, 0xa7, 0x7c, + 0x6e, 0x3a, 0x18, 0x20, 0xb5, 0xae, 0x9d, 0xc9, 0x3d, 0x9f, 0xa1, 0x73, 0xc5, 0xed, 0x60, 0x4b, + 0x21, 0xb1, 0xee, 0xb4, 0xe0, 0x46, 0xa9, 0x41, 0x57, 0x1c, 0x26, 0x2a, 0x51, 0x4b, 0xed, 0x1f, + 0xac, 0x0c, 0xde, 0xa2, 0xe6, 0xa9, 0x6c, 0xee, 0xb1, 0xce, 0x55, 0x8d, 0x63, 0xa5, 0x8e, 0x46, + 0x7b, 0xd0, 0xf6, 0xd2, 0x43, 0x7e, 0x82, 0x26, 0xaf, 0x12, 0xca, 0x88, 0xea, 0xaa, 0x0b, 0xad, + 0xc0, 0xe0, 0x4d, 0xea, 0xa5, 0x61, 0x86, 0xc4, 0x8c, 0xa0, 0x9e, 0xaf, 0x6f, 0x75, 0xc9, 0xd3, + 0x6a, 0x05, 0x07, 0x14, 0xd5, 0xbf, 0x2f, 0x61, 0x37, 0x8a, 0x75, 0x6d, 0x02, 0xb0, 0xbe, 0x25, + 0x2f, 0x0d, 0xfc, 0xd7, 0xcb, 0x29, 0xf1, 0xc5, 0x17, 0xc1, 0x8e, 0x2b, 0xd8, 0x90, 0x38, 0x12, + 0xff, 0x45, 0xb1, 0x74, 0x69, 0xdc, 0xe8, 0x2b, 0x7a, 0x9d, 0x5c, 0x1f, 0x7c, 0xf0, 0xcc, 0xa4, + 0xba, 0x0e, 0x33, 0x57, 0xef, 0x6c, 0x4d, 0xad, 0x56, 0x27, 0xb6, 0xc3, 0x71, 0xfe, 0x69, 0x6b, + 0xf3, 0xe5, 0x63, 0x29, 0xd2, 0x63, 0x19, 0xc5, 0xc8, 0x31, 0x59, 0xa0, 0x28, 0xc2, 0xb0, 0x52, + 0xea, 0xd3, 0x12, 0xbb, 0xed, 0x34, 0x3d, 0x53, 0xdf, 0x79, 0x40, 0xe7, 0x4c, 0x8d, 0x54, 0x73, + 0x2b, 0x95, 0x57, 0x6c, 0xd1, 0xec, 0xd1, 0x4d, 0x25, 0xcd, 0x4b, 0x49, 0xfe, 0x3b, 0x29, 0x85, + 0xb5, 0x7f, 0x7e, 0x24, 0x58, 0xce, 0xd2, 0xa4, 0x76, 0x69, 0x20, 0xaa, 0x63, 0x07, 0xa1, 0xc9, + 0x64, 0xcb, 0xa7, 0xd5, 0x61, 0xc6, 0x6e, 0x47, 0x17, 0x16, 0xe9, 0xfa, 0x8f, 0xcf, 0x18, 0x5a, + 0xfc, 0x7f, 0x35, 0xcd, 0xa8, 0xf2, 0x90, 0x1d, 0x46, 0x95, 0x97, 0xdd, 0x21, 0x4c, 0x82, 0xb0, + 0x95, 0x90, 0x0a, 0xc5, 0xb1, 0x84, 0x59, 0x20, 0x2e, 0xce, 0x2e, 0x11, 0x22, 0xc4, 0x0c, 0xad, + 0xc2, 0x4f, 0x6e, 0x54, 0x26, 0x6f, 0xaa, 0x76, 0xe5, 0x70, 0x51, 0x9a, 0x95, 0x17, 0x46, 0x2c, + 0x8e, 0x12, 0xba, 0x61, 0xcc, 0x9c, 0x3d, 0x17, 0xc3, 0xf9, 0x5b, 0xb7, 0xd1, 0x7f, 0x5b, 0xd9, + 0x43, 0x16, 0x16, 0x25, 0x4f, 0xcd, 0x6d, 0x4c, 0x07, 0x3f, 0xb4, 0x2f, 0xb5, 0xa2, 0xf2, 0x2f, + 0x49, 0x10, 0xea, 0x36, 0xae, 0x6c, 0xca, 0x61, 0x79, 0xc2, 0x96, 0x40, 0x04, 0x63, 0x86, 0x43, + 0x56, 0xf6, 0xa3, 0x16, 0x7f, 0xd1, 0xb1, 0x25, 0xfe, 0xff, 0xa4, 0x81, 0x6d, 0xe6, 0x7e, 0x24, + 0x78, 0xa4, 0x7a, 0x7a, 0x0d, 0x0c, 0xb1, 0xcc, 0x36, 0x25, 0x43, 0xc9, 0x56, 0x21, 0xa4, 0xc3, + 0x91, 0xe4, 0x1e, 0x9b, 0x0b, 0x26, 0xa7, 0x6b, 0xc4, 0x51, 0x9c, 0x32, 0x56, 0x96, 0x34, 0x5a, + 0xa7, 0x16, 0xf8, 0x11, 0xe7, 0x6b, 0xa5, 0xb0, 0x7f, 0x72, 0x1e, 0x16, 0xfc, 0xe1, 0xea, 0x85, + 0x6d, 0x16, 0x28, 0x31, 0x6b, 0x70, 0xcb, 0x7a, 0xab, 0x16, 0xe0, 0xd4, 0x27, 0x04, 0x08, 0xeb, + 0x9f, 0x9c, 0xba, 0x96, 0xae, 0x84, 0xae, 0xe8, 0xef, 0xed, 0x85, 0x74, 0xcc, 0x38, 0x4a, 0x54, + 0x4a, 0x84, 0x5a, 0x10, 0x0b, 0xec, 0xdd, 0xfc, 0xd3, 0xe4, 0x01, 0x4f, 0xc0, 0x0f, 0x1f, 0xd9, + 0xee, 0xeb, 0x93, 0xbf, 0xb3, 0x75, 0x35, 0x44, 0x38, 0x2c, 0x8d, 0xa8, 0x56, 0x81, 0xa3, 0xba, + 0xf0, 0x80, 0x84, 0x3e, 0x56, 0xcc, 0x33, 0x84, 0x00, 0xfa, 0x8a, 0x2b, 0x8f, 0x46, 0x6d, 0x81, + 0xda, 0x1d, 0x6e, 0xee, 0xd6, 0x63, 0xc4, 0x4c, 0x27, 0xfa, 0x27, 0x7c, 0xfc, 0xb6, 0xaa, 0x78, + 0x4e, 0x24, 0x18, 0xcb, 0x69, 0x8b, 0xf3, 0xf2, 0xb4, 0xfd, 0xda, 0x5e, 0x75, 0xdd, 0x4c, 0x16, + 0x56, 0xba, 0x3e, 0x96, 0x90, 0xbb, 0xf6, 0x3d, 0xc9, 0xd2, 0x8b, 0x98, 0x10, 0xd7, 0x76, 0xf4, + 0xfe, 0x63, 0xf4, 0x58, 0xe0, 0xfc, 0x64, 0x4c, 0x2f, 0xe4, 0x7d, 0x43, 0x7d, 0x46, 0x71, 0xda, + 0x1a, 0x2e, 0x8f, 0x2f, 0x90, 0x5f, 0xe2, 0xaf, 0xb8, 0x82, 0x1b, 0xb6, 0xd6, 0x23, 0x2a, 0xc6, + 0x10, 0xde, 0x9e, 0x2c, 0xe6, 0x47, 0x6b, 0x2f, 0xcd, 0xc6, 0x28, 0x5a, 0xbf, 0xd0, 0x5e, 0x6c, + 0xfd, 0x12, 0x07, 0x00, 0x27, 0xc2, 0x26, 0xf6, 0x62, 0x6a, 0xae, 0x14, 0x3c, 0x3e, 0xa1, 0xf0, + 0x9e, 0xed, 0x65, 0xd0, 0x13, 0x95, 0x3c, 0x43, 0x88, 0x10, 0x93, 0x73, 0x95, 0x63, 0x6f, 0x9f, + 0x3f, 0x03, 0xde, 0x51, 0x7c, 0x01, 0x13, 0x70, 0x61, 0x95, 0x52, 0xfc, 0x3e, 0xd3, 0x79, 0x3c, + 0x2e, 0xb5, 0xa2, 0xb1, 0x72, 0x4b, 0x0b, 0x3a, 0xa2, 0xc7, 0x44, 0x16, 0x3e, 0xf1, 0xb3, 0x41, + 0xf0, 0xb6, 0xbd, 0x5a, 0xba, 0xf4, 0x49, 0xba, 0x7f, 0xeb, 0xfb, 0xb6, 0xd4, 0x38, 0xb6, 0xbe, + 0xc2, 0x30, 0xa4, 0x38, 0xb4, 0x6a, 0xdc, 0x61, 0x96, 0x74, 0x72, 0xc8, 0x2a, 0x5f, 0x50, 0xd0, + 0xb5, 0xcf, 0xfd, 0xc1, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, + 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, + 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0xff, 0x77, 0xf2, 0xcf, 0xf3, 0x60, 0x5b, 0x6b, 0x57, + 0xa9, 0x1d, 0xbc, 0x74, 0x5e, 0xfe, 0x44, 0x10, 0x05, 0x28, 0x62, 0x58, 0xbb, 0x72, 0x08, 0x62, + 0xad, 0xf2, 0xaf, 0xec, 0x1d, 0x5a, 0x00, 0xbb, 0x70, 0x06, 0x28, 0xae, 0x95, 0x9b, 0x0d, 0xd3, + 0x4e, 0x6b, 0xe1, 0x0a, 0x42, 0x7e, 0x27, 0xbb, 0x0e, 0x47, 0x79, 0x91, 0x94, 0x41, 0x73, 0x6d, + 0xe0, 0xb8, 0x8c, 0xd5, 0xdf, 0x47, 0xfa, 0x49, 0x2b, 0x9b, 0x5b, 0xf3, 0x73, 0x79, 0x46, 0xf3, + 0x21, 0x3d, 0x1f, 0xf3, 0xcc, 0x5e, 0x69, 0x3d, 0x41, 0xff, 0x66, 0x47, 0x08, 0x1f, 0x13, 0xca, + 0x51, 0x6f, 0x76, 0x24, 0xb9, 0xa6, 0x6e, 0x7b, 0x8e, 0x83, 0xde, 0x92, 0x34, 0x37, 0x89, 0x9c, + 0xf4, 0x1a, 0x4a, 0x1b, 0x69, 0xe5, 0x5d, 0x2b, 0x0f, 0xa7, 0x05, 0xe3, 0xd8, 0x94, 0x32, 0x66, + 0x39, 0x3b, 0x9c, 0xce, 0xe3, 0xdb, 0xbe, 0x55, 0x5d, 0x74, 0x33, 0xd8, 0x94, 0x45, 0xd7, 0x42, + 0x92, 0x39, 0x07, 0xb2, 0xd4, 0xb2, 0x14, 0x6c, 0xe4, 0x57, 0x58, 0x28, 0xce, 0x60, 0x5c, 0xf1, + 0x0d, 0xc3, 0x85, 0x25, 0x88, 0x35, 0x2c, 0x11, 0x42, 0xc7, 0x04, 0x2e, 0x4e, 0x45, 0xa4, 0xbf, + 0x59, 0x20, 0x25, 0x6e, 0xe9, 0x89, 0xeb, 0x56, 0x36, 0x2e, 0x62, 0xd8, 0xb6, 0x5b, 0xd7, 0x31, + 0xa6, 0x8e, 0x6f, 0xe2, 0x75, 0xce, 0x3e, 0x12, 0xc6, 0x4b, 0x22, 0x18, 0xa1, 0x1d, 0xf1, 0x0d, + 0x74, 0x57, 0xe0, 0x13, 0x57, 0x7a, 0x57, 0x5e, 0x44, 0x4b, 0x2a, 0xa1, 0x96, 0x8e, 0xcb, 0xd7, + 0x12, 0xc8, 0x48, 0x28, 0x32, 0x49, 0xc3, 0xa6, 0x62, 0x59, 0xfe, 0x6d, 0xa1, 0xa7, 0xf1, 0x94, + 0x2a, 0xe2, 0x83, 0x6a, 0x8b, 0x30, 0x69, 0xd1, 0x0c, 0x2f, 0xdc, 0x94, 0xcb, 0xa4, 0x42, 0x4d, + 0x29, 0xbf, 0x1a, 0x91, 0x6c, 0x07, 0xbb, 0x1e, 0x91, 0x8f, 0x33, 0xe2, 0xa5, 0x55, 0x3f, 0xd6, + 0x43, 0xe7, 0xe1, 0x7f, 0xaf, 0xb2, 0x90, 0x69, 0x21, 0xc5, 0x5e, 0x72, 0x52, 0x78, 0x1f, 0x6a, + 0x76, 0x6b, 0x1e, 0x66, 0x41, 0x0d, 0x8a, 0x91, 0x85, 0xf8, 0xc0, 0x45, 0xa9, 0x95, 0x12, 0x5b, + 0xa8, 0x25, 0x5c, 0x0f, 0x24, 0xd8, 0xfc, 0x2b, 0xc3, 0xf2, 0xc5, 0xaf, 0x47, 0xa9, 0xe7, 0x78, + 0xd2, 0xb7, 0xb5, 0xb2, 0x42, 0x5e, 0xca, 0x59, 0xb0, 0xa1, 0xea, 0xef, 0x09, 0xb3, 0xb5, 0x00, + 0x6b, 0xea, 0x2b, 0x2e, 0x72, 0x87, 0x74, 0x4e, 0xa4, 0x45, 0x8a, 0xc0, 0xf3, 0x6e, 0x0a, 0x14, + 0x47, 0x42, 0x11, 0xcd, 0xa8, 0xac, 0xc0, 0x2d, 0xbe, 0xc0, 0x8c, 0xdc, 0xb8, 0xee, 0x3d, 0xc5, + 0x78, 0x7f, 0xdc, 0x35, 0x72, 0x57, 0xfd, 0xb5, 0xa3, 0xcb, 0x86, 0xef, 0xe4, 0x8d, 0x95, 0xcc, + 0x97, 0xd9, 0x49, 0xa3, 0x05, 0xaa, 0x94, 0xc2, 0xb6, 0xd1, 0x03, 0x29, 0xca, 0x3f, 0x21, 0xcb, + 0x29, 0xbb, 0x0d, 0xa3, 0xaf, 0x0c, 0xca, 0xef, 0x8c, 0x82, 0x76, 0x70, 0xaf, 0x56, 0xd3, 0xed, + 0x99, 0x2f, 0x99, 0x53, 0xd4, 0xa3, 0x37, 0xf5, 0x8f, 0xee, 0xa9, 0x89, 0xbd, 0x07, 0x69, 0xe1, + 0x53, 0x64, 0x37, 0x63, 0x78, 0x82, 0x3b, 0x69, 0x76, 0xf8, 0xa8, 0x6d, 0x87, 0x27, 0xf1, 0xc6, + 0xf8, 0x4d, 0xd4, 0x1b, 0x24, 0xd2, 0xe0, 0x3b, 0x5e, 0xd1, 0x67, 0x1c, 0x7b, 0x8d, 0x17, 0x37, + 0x51, 0x21, 0x56, 0xfb, 0x92, 0xad, 0x16, 0x58, 0x6c, 0x42, 0x97, 0x2b, 0x37, 0x48, 0x3a, 0xbb, + 0xcb, 0x13, 0x53, 0x39, 0x39, 0xac, 0x75, 0x75, 0x99, 0xf3, 0x08, 0xf7, 0x0b, 0x3e, 0x4e, 0x2c, + 0xf0, 0x09, 0x00, 0xed, 0xa1, 0xa6, 0x1e, 0x32, 0x1b, 0x01, 0x19, 0xd5, 0xde, 0xf0, 0x57, 0x8b, + 0x28, 0x69, 0x98, 0x53, 0xca, 0x43, 0x21, 0x23, 0x68, 0xe5, 0xac, 0x6b, 0xdd, 0x8f, 0xdf, 0x23, + 0x90, 0xfc, 0xcd, 0xca, 0x9a, 0x20, 0xef, 0xeb, 0x8a, 0x09, 0x30, 0x26, 0xdb, 0x5f, 0xc7, 0x65, + 0xcb, 0x40, 0xe4, 0xac, 0xcf, 0xa6, 0xf7, 0xcf, 0x5b, 0x14, 0x2e, 0xaf, 0x22, 0xfd, 0x2b, 0x93, + 0x29, 0xf6, 0x83, 0x69, 0x18, 0x4d, 0xfe, 0xc4, 0xb4, 0xa2, 0x03, 0xde, 0xa0, 0x02, 0x20, 0x72, + 0x82, 0x2d, 0xf3, 0x9c, 0x8c, 0x7a, 0x26, 0xe7, 0x04, 0x07, 0x24, 0x70, 0x20, 0x76, 0xd5, 0x56, + 0xed, 0x47, 0x28, 0x67, 0x95, 0xdc, 0xc0, 0xd8, 0x7c, 0x59, 0xb1, 0xce, 0x5e, 0x05, 0x75, 0x27, + 0x49, 0x81, 0xe3, 0x08, 0x5d, 0x5d, 0x15, 0x3f, 0xdc, 0x10, 0x2b, 0x62, 0xf4, 0x84, 0x90, 0xf9, + 0xe3, 0x08, 0x87, 0x27, 0x77, 0xa3, 0xd3, 0x35, 0xd7, 0xc1, 0x0c, 0x5a, 0xe6, 0x21, 0x54, 0x4b, + 0x63, 0xdc, 0x0b, 0x8e, 0x0a, 0x40, 0x00, 0x4d, 0x0a, 0x4a, 0x37, 0x9e, 0x81, 0x16, 0xf4, 0xa8, + 0x04, 0x7d, 0xc4, 0x4d, 0x61, 0x36, 0xd1, 0xc3, 0x49, 0xab, 0xa3, 0x3c, 0x4a, 0xec, 0xb2, 0x3f, + 0x86, 0x55, 0x7c, 0xf5, 0xe0, 0x9f, 0xd2, 0x0f, 0x08, 0x31, 0x9b, 0xe5, 0xb8, 0x98, 0x02, 0x00, + 0x70, 0x6f, 0x9c, 0x95, 0xc2, 0xce, 0xd1, 0xc2, 0x92, 0x08, 0x44, 0x16, 0x96, 0x45, 0x12, 0xba, + 0x06, 0x00, 0x92, 0x93, 0x0a, 0x00, 0x94, 0x49, 0xd6, 0xb4, 0xf2, 0xec, 0x84, 0x74, 0x48, 0x60, + 0x1f, 0x5b, 0x47, 0x4a, 0x7e, 0xbf, 0x8e, 0xf2, 0x5c, 0xa8, 0xa6, 0xa7, 0xa4, 0xcc, 0x9d, 0x05, + 0xf0, 0x60, 0x2b, 0x1e, 0x3d, 0x16, 0xb9, 0xb2, 0xb6, 0x75, 0xd9, 0x4d, 0x56, 0xa7, 0xf4, 0x97, + 0x53, 0xa3, 0x9b, 0x42, 0x52, 0x1a, 0xe1, 0x0f, 0xef, 0xf2, 0x8f, 0x14, 0x74, 0x28, 0x5b, 0xe5, + 0xa1, 0xee, 0xcc, 0xdf, 0xc0, 0xe0, 0x50, 0x07, 0xf0, 0xd0, 0x12, 0x3d, 0x7f, 0x71, 0xc6, 0xb4, + 0x61, 0xbb, 0xa8, 0x35, 0xc3, 0x03, 0xee, 0xee, 0x2b, 0xb6, 0xda, 0x70, 0x0d, 0x87, 0x81, 0x48, + 0x8b, 0xe4, 0xdd, 0xdc, 0xc6, 0x53, 0x0a, 0xe0, 0x3e, 0x48, 0xb3, 0x2f, 0x62, 0xad, 0x57, 0x85, + 0x38, 0xc4, 0x96, 0x83, 0x88, 0x7b, 0x7c, 0x39, 0xbd, 0x6e, 0xc4, 0xe6, 0xa7, 0x0f, 0xd2, 0x67, + 0xb5, 0x69, 0xb7, 0x11, 0xb3, 0x4e, 0x7b, 0xfd, 0x9c, 0x9c, 0xd0, 0x09, 0xf5, 0x56, 0x80, 0x61, + 0x1c, 0xfd, 0x3f, 0x57, 0xd1, 0x28, 0x6e, 0xb1, 0x7f, 0x72, 0x0d, 0x59, 0xd3, 0xc5, 0xe3, 0xe7, + 0x96, 0x46, 0x74, 0x1f, 0x50, 0x61, 0x6b, 0xe8, 0x46, 0xae, 0xb7, 0xee, 0x39, 0xbe, 0x64, 0x3b, + 0xad, 0x8d, 0x7b, 0x39, 0xd5, 0xf2, 0x6f, 0x02, 0xe0, 0x84, 0xa2, 0xa4, 0x25, 0x31, 0x33, 0x61, + 0x32, 0x32, 0xff, 0x57, 0x81, 0x7e, 0xa3, 0x8f, 0x99, 0x1e, 0xad, 0xff, 0xed, 0x54, 0x4b, 0xd0, + 0x36, 0xc6, 0xeb, 0x21, 0x9e, 0x25, 0x3e, 0x7e, 0xd7, 0xa5, 0x26, 0x4a, 0xa3, 0xab, 0x5b, 0x78, + 0x94, 0x21, 0xa8, 0x03, 0xb6, 0x11, 0x55, 0x3b, 0x44, 0xff, 0xb7, 0x9c, 0xa5, 0x1f, 0xef, 0x2b, + 0xf6, 0xbd, 0x96, 0x43, 0xa5, 0xc9, 0xa7, 0xb5, 0x1d, 0x4c, 0x81, 0xae, 0xeb, 0xf5, 0xa2, 0xa0, + 0xaf, 0xc3, 0x19, 0x43, 0xe1, 0x0e, 0x37, 0x7d, 0x14, 0xbe, 0x5e, 0x14, 0x88, 0xd6, 0x86, 0xa9, + 0x03, 0x47, 0xb0, 0x32, 0x6b, 0xdc, 0xf8, 0x9f, 0x52, 0x44, 0x9e, 0x76, 0x6b, 0xfb, 0xbe, 0xfb, + 0x3b, 0xea, 0x7a, 0xd0, 0xf4, 0x5b, 0x44, 0x07, 0x38, 0xc6, 0xaf, 0xd7, 0xee, 0xde, 0x31, 0xbb, + 0xa2, 0x47, 0x73, 0x14, 0xca, 0x37, 0x68, 0xdd, 0xec, 0xd7, 0x25, 0x66, 0x0b, 0x7a, 0xd5, 0x39, + 0x26, 0xf4, 0x1f, 0x87, 0x19, 0xc7, 0xfe, 0xe6, 0xcb, 0xa2, 0xb1, 0x7a, 0x5c, 0xc1, 0x73, 0x35, + 0x2b, 0x51, 0xc5, 0x81, 0x62, 0x79, 0xd1, 0x78, 0x4a, 0xb8, 0xb3, 0x7f, 0x0b, 0x8e, 0x9b, 0x52, + 0xa0, 0x1c, 0x62, 0x7f, 0x59, 0xf5, 0x6e, 0x7a, 0x58, 0x59, 0xfc, 0x7b, 0x05, 0xd7, 0x18, 0x8f, + 0x42, 0xff, 0x14, 0x15, 0xa7, 0xcb, 0xf9, 0xb1, 0x99, 0xd1, 0xd9, 0xcc, 0x9e, 0xed, 0x2c, 0x2f, + 0x7a, 0x1e, 0x91, 0xea, 0x12, 0x50, 0x15, 0x83, 0xfc, 0x81, 0x15, 0x95, 0x15, 0x0f, 0xd1, 0xb9, + 0xaa, 0x70, 0x5d, 0x3b, 0x0d, 0xe8, 0x63, 0xfe, 0xd4, 0xdf, 0x7d, 0x49, 0xbc, 0x17, 0x33, 0xf5, + 0x56, 0x66, 0x2b, 0x39, 0xa5, 0xc7, 0xc0, 0x69, 0x52, 0xec, 0x72, 0xc3, 0xe4, 0x53, 0x59, 0x2a, + 0xce, 0xa3, 0x54, 0x3a, 0x07, 0xee, 0x21, 0x3f, 0xd6, 0xd9, 0xcd, 0xfe, 0xc4, 0xf4, 0xd6, 0xfe, + 0xc1, 0x89, 0x6b, 0x68, 0x38, 0x10, 0xb7, 0x79, 0x99, 0x80, 0xef, 0xeb, 0xdb, 0xd5, 0x93, 0x9f, + 0x36, 0x98, 0xbb, 0x2d, 0xc5, 0x25, 0x7f, 0xbb, 0x26, 0xa3, 0xae, 0xd6, 0xbe, 0x23, 0x84, 0xf6, + 0x7c, 0x74, 0x7a, 0xcf, 0xaf, 0xea, 0x96, 0xe6, 0x2f, 0x73, 0xe7, 0xe4, 0x9b, 0xe5, 0x36, 0x81, + 0x77, 0x6a, 0x99, 0x90, 0x22, 0x3d, 0x47, 0x6d, 0xcd, 0x00, 0xb9, 0xc0, 0x56, 0xaf, 0x6c, 0xf5, + 0x3f, 0x7d, 0x49, 0x4a, 0x4c, 0x93, 0xdd, 0x97, 0x86, 0xc6, 0x9c, 0xbc, 0x88, 0xf9, 0xce, 0x2f, + 0x94, 0xfb, 0x96, 0x22, 0x9a, 0x07, 0xe2, 0xe5, 0xed, 0xab, 0x88, 0xec, 0xce, 0x7f, 0x5f, 0xd3, + 0x6d, 0x3f, 0x0c, 0x94, 0x75, 0x07, 0x87, 0x56, 0x3e, 0x85, 0xfa, 0x5f, 0x22, 0x55, 0x6f, 0x66, + 0x60, 0x87, 0x82, 0x0f, 0x4c, 0x35, 0x7c, 0x87, 0x37, 0x34, 0x17, 0x12, 0xf2, 0x3e, 0xbd, 0x7f, + 0x53, 0x9b, 0x59, 0xcc, 0x05, 0x92, 0x33, 0xbf, 0xca, 0x5c, 0x28, 0x35, 0x01, 0xef, 0x2b, 0xaa, + 0x99, 0x7e, 0x20, 0xb0, 0x12, 0x17, 0x93, 0xc9, 0x15, 0x4d, 0x34, 0x64, 0xb7, 0xce, 0x9d, 0x45, + 0xcf, 0x89, 0x69, 0x30, 0x8e, 0x96, 0xd5, 0x7f, 0xe0, 0xc8, 0xee, 0xa3, 0x73, 0x93, 0xbc, 0xd8, + 0x05, 0xea, 0xb3, 0xad, 0x59, 0x85, 0x4a, 0x13, 0xb2, 0x3c, 0x7b, 0xa4, 0x53, 0x0d, 0x20, 0x7c, + 0xfe, 0xb6, 0x5b, 0x6b, 0xee, 0x0d, 0xe7, 0x7b, 0x93, 0x23, 0x62, 0x25, 0x17, 0x63, 0x85, 0xcd, + 0x74, 0x63, 0xb2, 0xbe, 0x12, 0x3e, 0x7e, 0x78, 0xc9, 0x26, 0x5c, 0x99, 0x97, 0xcb, 0x91, 0xcd, + 0x8f, 0x8f, 0x48, 0x31, 0x65, 0x55, 0x17, 0x6f, 0x28, 0x7e, 0x47, 0x24, 0xba, 0xa9, 0x71, 0x44, + 0x4c, 0x6b, 0xa5, 0x60, 0xba, 0x89, 0x4c, 0xaf, 0x42, 0x48, 0xaa, 0x52, 0x14, 0x95, 0x1a, 0xcd, + 0x5f, 0xe9, 0x36, 0xa1, 0xc7, 0x15, 0xd5, 0x88, 0x2c, 0xd3, 0x45, 0xe6, 0x65, 0x94, 0xe1, 0x2c, + 0xc2, 0xd5, 0xc0, 0x14, 0xc2, 0xe5, 0x4e, 0x5c, 0x1e, 0x15, 0x4f, 0x08, 0xff, 0xb8, 0xc3, 0x5c, + 0xb5, 0xfa, 0x13, 0xd3, 0x6a, 0xbb, 0xe4, 0x63, 0x04, 0xe4, 0x44, 0x09, 0xc7, 0xbd, 0x40, 0xe0, + 0x47, 0x05, 0xfd, 0xc1, 0xe9, 0x2d, 0x91, 0x7f, 0x40, 0x3c, 0x53, 0xdc, 0x31, 0x53, 0xff, 0x92, + 0x55, 0xae, 0x1f, 0x8d, 0x00, 0xd3, 0xf7, 0x63, 0x3c, 0xca, 0xdb, 0x70, 0x8d, 0x22, 0x67, 0x81, + 0x6f, 0x3a, 0xae, 0x8e, 0xf8, 0x1d, 0x17, 0x94, 0x4e, 0x5a, 0xcb, 0x39, 0x5e, 0xb9, 0xda, 0x93, + 0xc2, 0xb2, 0xef, 0x35, 0x3d, 0x61, 0x3e, 0x64, 0x47, 0x22, 0xae, 0xe6, 0xd4, 0xb4, 0x50, 0x65, + 0x30, 0x48, 0xcb, 0xa2, 0x7a, 0x9a, 0x31, 0x29, 0x16, 0x56, 0xd4, 0xb2, 0x2a, 0x32, 0x1f, 0xbb, + 0x42, 0x97, 0xd2, 0x0a, 0xc4, 0x11, 0xd9, 0x85, 0xfd, 0x10, 0x1a, 0xd7, 0x98, 0x1c, 0xa8, 0x7c, + 0x1e, 0xb7, 0x56, 0xc8, 0x62, 0x1e, 0x77, 0xbd, 0xaa, 0xf9, 0x0f, 0x21, 0x2d, 0x38, 0x39, 0x1e, + 0x50, 0x26, 0x3b, 0x89, 0x29, 0x04, 0xc2, 0x8d, 0x34, 0xdb, 0x52, 0x0a, 0x59, 0x5a, 0xa2, 0x1c, + 0xd2, 0x54, 0x89, 0xf4, 0x9b, 0xae, 0x56, 0x6f, 0xbc, 0xb5, 0xd9, 0x12, 0xe6, 0x5c, 0xe9, 0x19, + 0x99, 0x71, 0xc7, 0x3f, 0x5a, 0xee, 0x3b, 0xb6, 0x9b, 0x91, 0x27, 0x49, 0x04, 0xe2, 0x9a, 0x68, + 0xc5, 0x2a, 0x76, 0xad, 0x55, 0x36, 0xb9, 0xba, 0xd7, 0xa3, 0xd1, 0xc2, 0x40, 0x1e, 0xc6, 0xc3, + 0xe9, 0x9a, 0x8e, 0x0d, 0x35, 0x45, 0xca, 0x32, 0x27, 0xfa, 0x1c, 0x60, 0xb1, 0x65, 0xc4, 0x56, + 0x4d, 0xe2, 0x1b, 0x63, 0x33, 0xa6, 0x31, 0xc5, 0x9a, 0x7d, 0x72, 0x8a, 0x27, 0x80, 0xb4, 0xbc, + 0xfe, 0x25, 0xc2, 0xbd, 0x4a, 0xfb, 0xcd, 0x06, 0x20, 0x56, 0xc2, 0x2c, 0xd1, 0x33, 0x0c, 0xb3, + 0xca, 0xcc, 0x0b, 0x0b, 0xb0, 0x0c, 0xe2, 0x4a, 0x79, 0x4a, 0x90, 0x54, 0xe1, 0xca, 0x53, 0x72, + 0x51, 0xa3, 0x2c, 0x7b, 0xd8, 0xd0, 0x80, 0x62, 0x28, 0x7c, 0xed, 0x14, 0x1d, 0x6b, 0xe4, 0x25, + 0xe4, 0x85, 0x0f, 0xb9, 0x11, 0xbe, 0x19, 0x2c, 0x9f, 0xe1, 0x80, 0x26, 0xf4, 0xe3, 0xce, 0x45, + 0x33, 0xff, 0x27, 0xa6, 0x75, 0x02, 0x11, 0xa2, 0x62, 0x99, 0xbd, 0x8a, 0x2d, 0x55, 0xcd, 0xa8, + 0xb0, 0x4a, 0xaf, 0xfc, 0x21, 0xb6, 0x92, 0x89, 0x45, 0x93, 0x21, 0xdd, 0x95, 0xf3, 0x06, 0xe5, + 0xe6, 0x9f, 0x4e, 0xdb, 0x8b, 0xbc, 0x41, 0x8d, 0x4b, 0x91, 0xe3, 0x72, 0xfe, 0xd1, 0xac, 0x0c, + 0x8d, 0xea, 0xc6, 0x70, 0x1a, 0xd5, 0xcb, 0x11, 0x84, 0x23, 0x84, 0xdd, 0x2f, 0x73, 0x26, 0xa3, + 0x7f, 0x2f, 0x95, 0xb0, 0x37, 0x42, 0xb9, 0xcb, 0xe8, 0xd3, 0x4a, 0xeb, 0xab, 0xbb, 0x8d, 0x62, + 0xbb, 0x07, 0x77, 0x15, 0xa9, 0x03, 0x39, 0xc2, 0x5a, 0xc3, 0xf5, 0xad, 0xb2, 0xd2, 0xa6, 0xad, + 0x97, 0x83, 0x97, 0x8a, 0x41, 0x6f, 0x3a, 0x9f, 0xda, 0xf6, 0x34, 0xea, 0xb4, 0xb1, 0x57, 0x1a, + 0xf3, 0x0a, 0x37, 0xe4, 0x8c, 0x42, 0x82, 0xd2, 0xfb, 0x90, 0x98, 0x89, 0x8b, 0x0e, 0xda, 0x6c, + 0xcb, 0xee, 0xd1, 0xc9, 0xe1, 0x6e, 0x76, 0xa7, 0xed, 0x61, 0x4d, 0xac, 0xa1, 0x04, 0x3a, 0x3e, + 0x0b, 0x10, 0x9b, 0xb5, 0xf8, 0x47, 0x3a, 0xc1, 0x9c, 0x0f, 0x6f, 0xb2, 0xdc, 0xbf, 0x0e, 0xaa, + 0x59, 0x62, 0x88, 0x1e, 0x86, 0x15, 0x07, 0xe8, 0x6e, 0xb6, 0xb0, 0x73, 0xdb, 0x9e, 0x53, 0xfb, + 0x1a, 0x6d, 0xdd, 0xb5, 0x69, 0xdd, 0xa3, 0x78, 0xa7, 0x02, 0xe5, 0xc6, 0x55, 0x54, 0xdf, 0xd3, + 0x3c, 0x5d, 0x07, 0xeb, 0xf6, 0x32, 0x0f, 0x55, 0xcf, 0x81, 0x72, 0xc9, 0x3f, 0x07, 0x8f, 0x87, + 0x76, 0x35, 0x50, 0x60, 0xb3, 0x63, 0x2e, 0x07, 0xb6, 0x3c, 0x2a, 0xc6, 0x52, 0xaf, 0x8c, 0x86, + 0x7b, 0x4d, 0xfb, 0xec, 0x1b, 0x15, 0x0e, 0x95, 0x8a, 0x40, 0xbf, 0xa7, 0x1f, 0x5d, 0x88, 0xf6, + 0xb2, 0xb3, 0x3c, 0xe4, 0xb4, 0x22, 0x81, 0xc5, 0xe1, 0x01, 0x58, 0x0e, 0x7b, 0x2c, 0xab, 0x4e, + 0x66, 0x61, 0x56, 0x04, 0xbb, 0x3b, 0x32, 0xb3, 0xa3, 0xf0, 0xbd, 0x29, 0x6a, 0x38, 0x93, 0xf9, + 0xce, 0xf3, 0x99, 0x8b, 0x99, 0x3d, 0x3f, 0x6d, 0x0b, 0x8c, 0x32, 0x88, 0x61, 0xad, 0x8a, 0x6f, + 0xff, 0xa5, 0x3f, 0x05, 0xe7, 0x27, 0xa6, 0x97, 0xd8, 0xee, 0x07, 0x6f, 0x29, 0xfc, 0x57, 0x6f, + 0x13, 0xbb, 0xa6, 0x22, 0xdf, 0x38, 0x99, 0x2e, 0x3d, 0x4b, 0xe4, 0xf8, 0x47, 0x8d, 0x5a, 0x11, + 0xd8, 0xec, 0x11, 0xc5, 0xbd, 0x90, 0xf9, 0xb2, 0x02, 0x38, 0x2b, 0x6f, 0x6c, 0xd0, 0xfc, 0xb5, + 0x59, 0xb4, 0x29, 0x23, 0xeb, 0x85, 0x44, 0xc2, 0x85, 0x2d, 0x9f, 0x17, 0xfe, 0xc7, 0xe7, 0xad, + 0x7d, 0x4f, 0xca, 0xc3, 0xe3, 0xf7, 0xff, 0x8e, 0xf6, 0x4d, 0x3b, 0xd8, 0xb4, 0xc6, 0x52, 0x0e, + 0x2d, 0x3c, 0x3d, 0xdd, 0xf4, 0x14, 0xa4, 0xe6, 0xe8, 0x6d, 0x8a, 0x7c, 0xbe, 0x2d, 0x6f, 0x15, + 0x3d, 0xe6, 0xba, 0xe5, 0xf1, 0xa9, 0x70, 0x42, 0xcd, 0xaf, 0x7b, 0x51, 0x43, 0xb1, 0xa8, 0xbd, + 0xc7, 0x4a, 0x97, 0xdf, 0x5b, 0x91, 0x72, 0x3c, 0xb2, 0x70, 0x9d, 0x17, 0xf9, 0x0d, 0x0a, 0x3d, + 0xd3, 0xfc, 0xf3, 0xab, 0x46, 0xf6, 0x84, 0x59, 0x2e, 0x8b, 0x8a, 0x79, 0xae, 0xc5, 0xa8, 0x6f, + 0x72, 0xdf, 0xf6, 0x6f, 0x28, 0x6a, 0xe6, 0x1a, 0x3c, 0xb9, 0xc7, 0xe5, 0xdd, 0xce, 0xd4, 0x3c, + 0x4c, 0x73, 0x30, 0xad, 0x85, 0x36, 0x08, 0x72, 0xae, 0xd8, 0x56, 0xed, 0xca, 0xdb, 0x53, 0x01, + 0xfa, 0xab, 0xed, 0x70, 0xc3, 0xfc, 0x24, 0xab, 0x7f, 0x53, 0x02, 0xef, 0x48, 0xef, 0xda, 0x84, + 0x98, 0x75, 0xb9, 0xf0, 0x79, 0x3f, 0xa5, 0xd5, 0x6e, 0x2d, 0x57, 0x64, 0x4e, 0x6d, 0x8d, 0x59, + 0xe2, 0xd9, 0x30, 0x95, 0x3e, 0x45, 0x59, 0xd7, 0xf3, 0x42, 0x5f, 0x88, 0x7d, 0x35, 0xa2, 0x50, + 0x8d, 0x25, 0x11, 0x48, 0x87, 0xa6, 0x9f, 0x8a, 0x58, 0x36, 0x0f, 0x7e, 0x1f, 0x6d, 0x0a, 0xfa, + 0x07, 0x37, 0x91, 0xeb, 0x9c, 0x64, 0x29, 0x27, 0xb0, 0x3f, 0xdf, 0xd5, 0xae, 0x35, 0xd4, 0xe1, + 0xe6, 0xe0, 0x29, 0xc2, 0xba, 0xd4, 0x3d, 0xa5, 0x77, 0xe7, 0x1c, 0x99, 0xbd, 0x5e, 0xd6, 0x18, + 0xff, 0xfe, 0xf2, 0xed, 0x37, 0xea, 0xfc, 0x8d, 0x3d, 0xb8, 0xaa, 0xfd, 0xc9, 0x01, 0x4b, 0x81, + 0x6f, 0x0b, 0xb2, 0xa2, 0xa6, 0xf3, 0x11, 0x8c, 0xca, 0xff, 0x72, 0xb6, 0x19, 0xf7, 0x27, 0xa6, + 0xad, 0x0a, 0x93, 0x7d, 0xb8, 0xdb, 0x0b, 0x3f, 0x4e, 0x18, 0xf3, 0xed, 0xa8, 0x2c, 0xdf, 0x97, + 0xa5, 0xab, 0xd7, 0x8e, 0xbe, 0x96, 0x83, 0x0b, 0x0d, 0xe9, 0x6e, 0x5e, 0xe3, 0x3c, 0xa8, 0xb0, + 0x23, 0xce, 0x56, 0x5f, 0x90, 0x3c, 0x1d, 0xb1, 0x94, 0xbd, 0xdb, 0x33, 0x2c, 0x9e, 0x12, 0x7a, + 0x1a, 0x44, 0x56, 0xe8, 0xbe, 0xad, 0x96, 0xdd, 0x9b, 0x4d, 0x9b, 0xc2, 0x6d, 0x1e, 0x7e, 0x89, + 0x0a, 0xf1, 0x04, 0x59, 0xe9, 0x95, 0x5b, 0x78, 0x45, 0xa7, 0xb3, 0x24, 0xd3, 0xee, 0x54, 0xe2, + 0xa5, 0xa0, 0x11, 0x97, 0x69, 0x8d, 0x33, 0x50, 0xe1, 0x55, 0x05, 0xe9, 0x85, 0x4d, 0xb9, 0x35, + 0x7e, 0x9f, 0x22, 0xf6, 0x27, 0x87, 0xdf, 0xb4, 0xfb, 0x47, 0xaf, 0xf1, 0x46, 0x04, 0x3e, 0xad, + 0x39, 0xc6, 0x5a, 0xb6, 0x6a, 0xe1, 0x92, 0x4c, 0xa7, 0xc1, 0xfd, 0xb5, 0x74, 0x67, 0x66, 0xec, + 0xdf, 0x02, 0xec, 0xae, 0x08, 0x67, 0x09, 0x54, 0x44, 0x5f, 0x04, 0x92, 0x8b, 0xd4, 0xd9, 0xb5, + 0xa8, 0xa7, 0x42, 0x2e, 0x34, 0x66, 0x15, 0xfb, 0xfa, 0x37, 0x5b, 0x7b, 0x37, 0x5d, 0xb3, 0xd8, + 0xdb, 0x42, 0x8e, 0x4c, 0xdc, 0xab, 0xa6, 0x8c, 0x83, 0x77, 0x20, 0x9c, 0xdb, 0xbe, 0xd0, 0x46, + 0x79, 0x0f, 0xdd, 0x91, 0xf5, 0x78, 0xbb, 0xb5, 0xae, 0x18, 0xa9, 0xf6, 0x71, 0x9e, 0x76, 0xb3, + 0x5b, 0x89, 0x3e, 0x6e, 0x9e, 0xf4, 0xb8, 0x1e, 0x6a, 0x0e, 0xcb, 0x97, 0x1d, 0x0a, 0x95, 0xf1, + 0x92, 0xba, 0x49, 0xef, 0x37, 0x14, 0xc7, 0x57, 0x11, 0x4f, 0x40, 0xc7, 0x0d, 0x3f, 0x30, 0xbf, + 0xf4, 0x67, 0x1c, 0xa6, 0xba, 0x39, 0x36, 0x92, 0x23, 0xf3, 0xd3, 0xe2, 0x6e, 0xa8, 0x9b, 0x2b, + 0x7b, 0x87, 0x92, 0x86, 0x36, 0x6d, 0xf8, 0x98, 0xe3, 0x83, 0x58, 0x02, 0x57, 0x9a, 0x5d, 0xd8, + 0xbc, 0x73, 0x52, 0x8b, 0xe3, 0x3c, 0x8f, 0x7f, 0xc4, 0xc6, 0x5d, 0x01, 0x1e, 0xf7, 0x31, 0x66, + 0x0b, 0x39, 0xaa, 0x9a, 0x93, 0x09, 0x5b, 0x13, 0xed, 0xb1, 0xe3, 0xc5, 0x8d, 0x7f, 0x39, 0x83, + 0x52, 0xfa, 0x13, 0xd3, 0x36, 0x1b, 0x2e, 0x5f, 0x8e, 0x0b, 0x9c, 0xfe, 0x25, 0xe1, 0xca, 0xe8, + 0xdd, 0x16, 0xd7, 0x95, 0x06, 0x54, 0x93, 0x69, 0x9e, 0xd3, 0x57, 0xf6, 0xda, 0x78, 0xd2, 0x9f, + 0xb8, 0x26, 0xbf, 0xb4, 0x64, 0x07, 0xfe, 0xf9, 0x29, 0xb6, 0x60, 0x1d, 0x99, 0xe6, 0x97, 0xbd, + 0xa1, 0x85, 0xb0, 0x4e, 0x31, 0xa5, 0xb4, 0xee, 0xb4, 0xa9, 0xc6, 0x53, 0x5d, 0x4e, 0xa7, 0x52, + 0x8c, 0x75, 0x5d, 0x52, 0x7c, 0x6e, 0xf7, 0xdf, 0x84, 0xbc, 0xc7, 0xa4, 0xbd, 0x70, 0x80, 0x7e, + 0x13, 0xa4, 0x14, 0xe8, 0x52, 0x28, 0x73, 0xe0, 0xbd, 0x4f, 0xe6, 0x77, 0xea, 0x0e, 0xed, 0xaa, + 0xc5, 0xc3, 0xa6, 0xdf, 0xf6, 0xda, 0x7b, 0xcd, 0x42, 0x33, 0xde, 0x5f, 0xd1, 0x8c, 0xc7, 0xfd, + 0x54, 0x82, 0x7c, 0x5f, 0x37, 0xd4, 0x1a, 0x71, 0x7f, 0x90, 0xf7, 0x31, 0xa9, 0xbf, 0xcd, 0x74, + 0xdf, 0x38, 0xd9, 0x68, 0x4d, 0x05, 0x5f, 0x49, 0xcc, 0x75, 0xce, 0x04, 0xda, 0x69, 0x93, 0x57, + 0x56, 0xad, 0xbf, 0x7f, 0xb1, 0xdf, 0xf4, 0xd3, 0x2b, 0x36, 0xd9, 0x6b, 0xc8, 0x50, 0xbb, 0x6d, + 0x97, 0x07, 0x5a, 0xff, 0x84, 0x9b, 0x77, 0x8c, 0x4a, 0xaf, 0x54, 0xfc, 0xaf, 0x70, 0x72, 0xc4, + 0x3b, 0xf6, 0xab, 0x15, 0xd6, 0x54, 0xa9, 0x14, 0x89, 0x35, 0xce, 0xda, 0x42, 0x51, 0xd1, 0xaf, + 0xed, 0x47, 0xc7, 0x75, 0x12, 0x7e, 0x4d, 0x0d, 0xdb, 0xf6, 0x05, 0xf8, 0x6d, 0x69, 0x78, 0x79, + 0xdc, 0x1e, 0x0a, 0x1c, 0x0f, 0xb5, 0x54, 0x63, 0x44, 0xb6, 0xd9, 0x2a, 0x25, 0x0f, 0xed, 0x4b, + 0x8c, 0xeb, 0x36, 0x6a, 0x42, 0x3e, 0xbf, 0xa7, 0x57, 0xe0, 0xe8, 0x69, 0x44, 0x23, 0xda, 0xf1, + 0xf7, 0x99, 0xaa, 0x2b, 0xd0, 0xce, 0x27, 0x40, 0x6b, 0xa7, 0xf1, 0x77, 0x93, 0x96, 0xbe, 0x2a, + 0x9d, 0xf1, 0xd2, 0x80, 0x50, 0x4e, 0x8e, 0xb2, 0xc6, 0xbf, 0xd0, 0xa9, 0xb8, 0xfd, 0xfc, 0xbe, + 0x16, 0xce, 0xc7, 0x27, 0xa1, 0x70, 0x23, 0x40, 0xeb, 0x2e, 0xaa, 0xf0, 0xf3, 0xed, 0xbd, 0xf5, + 0xbc, 0xf6, 0xe3, 0x5e, 0xfe, 0x05, 0xc5, 0x4f, 0x4c, 0xc3, 0x22, 0x67, 0xf0, 0x1c, 0xd7, 0xff, + 0xc1, 0xf8, 0xd9, 0x8b, 0x17, 0x51, 0xfc, 0xc5, 0xb6, 0xfd, 0x88, 0xd1, 0x33, 0x03, 0x67, 0xef, + 0x65, 0xc9, 0xa9, 0x3b, 0xcc, 0xbd, 0x5f, 0xda, 0x5c, 0x57, 0x46, 0x5a, 0xef, 0xce, 0xf7, 0x60, + 0xef, 0x90, 0x07, 0xca, 0x0f, 0xf6, 0xc3, 0x96, 0xc7, 0x96, 0x2b, 0x2c, 0xe7, 0xb5, 0x4a, 0xd7, + 0x97, 0xc6, 0x22, 0x35, 0x03, 0x02, 0xa5, 0x96, 0x0c, 0x04, 0x89, 0x96, 0xb9, 0x6e, 0x0f, 0x94, + 0x42, 0xbb, 0x86, 0x23, 0x1f, 0x3a, 0xed, 0x0d, 0xfd, 0x92, 0xd3, 0x6f, 0x17, 0x5e, 0x07, 0x02, + 0xa3, 0xb9, 0x15, 0xd6, 0xdf, 0x14, 0x39, 0x74, 0x44, 0x60, 0xbc, 0xbb, 0xda, 0xf5, 0x19, 0x24, + 0xad, 0x39, 0xc5, 0x81, 0xbb, 0x2b, 0x95, 0x49, 0xc4, 0xa4, 0xfa, 0xd9, 0xed, 0x59, 0x61, 0x6e, + 0x7c, 0xfd, 0x19, 0x8b, 0xf3, 0xee, 0x2e, 0xdc, 0xcd, 0x88, 0xa4, 0x0b, 0x26, 0xfd, 0x01, 0xd5, + 0x21, 0xfe, 0x88, 0xdc, 0x67, 0xa7, 0xe3, 0x6b, 0xfe, 0xd9, 0xb9, 0x80, 0xf7, 0xbd, 0x1e, 0xb1, + 0xdf, 0x74, 0x54, 0xbf, 0xf9, 0xe4, 0xff, 0x4d, 0x81, 0x16, 0x59, 0x47, 0xa8, 0xf5, 0x97, 0x55, + 0xac, 0x08, 0xf0, 0xb4, 0xd2, 0x5d, 0x15, 0x15, 0xaa, 0xf4, 0x8b, 0xc2, 0x95, 0x54, 0xf0, 0xbc, + 0xe2, 0x84, 0x8e, 0xe7, 0x10, 0xa7, 0xf3, 0x3c, 0x81, 0x8b, 0x9e, 0xe5, 0x35, 0x28, 0xb8, 0x67, + 0xf7, 0x8a, 0x53, 0x18, 0x4f, 0x82, 0xb0, 0xcd, 0xa0, 0x15, 0x99, 0x21, 0xc1, 0x3c, 0x32, 0x3b, + 0x02, 0x47, 0x0c, 0x2b, 0x2f, 0xda, 0x41, 0x56, 0x92, 0xa2, 0x12, 0xf4, 0x8d, 0x2d, 0x52, 0xde, + 0xb4, 0x3b, 0x82, 0xab, 0x9b, 0xe1, 0xaa, 0xe0, 0x40, 0xfc, 0xd6, 0x17, 0x1a, 0x5c, 0x2f, 0x0a, + 0x98, 0xc7, 0x18, 0x58, 0xb0, 0x8d, 0xb1, 0x90, 0x12, 0xff, 0x8d, 0x3f, 0xb9, 0xea, 0x67, 0xdc, + 0x49, 0xa9, 0x83, 0xc1, 0x69, 0xd9, 0x25, 0x94, 0xd8, 0xe5, 0xc3, 0x10, 0x33, 0xa1, 0xcd, 0xe6, + 0x85, 0xdd, 0x5f, 0x21, 0xd1, 0x8f, 0x71, 0x9a, 0x61, 0xfd, 0xc4, 0x34, 0x51, 0x0b, 0xa7, 0x13, + 0x49, 0xae, 0x4d, 0x6b, 0xb0, 0xf5, 0x26, 0xa2, 0x07, 0x3c, 0x47, 0x8c, 0xd4, 0xf3, 0x0d, 0x01, + 0x4c, 0x9a, 0xaf, 0x15, 0x91, 0xa4, 0x74, 0xa6, 0xbc, 0x76, 0x9f, 0xed, 0xd4, 0x37, 0x4e, 0xf2, + 0xab, 0xc3, 0xc4, 0x7f, 0x92, 0x99, 0xc2, 0xce, 0x77, 0xba, 0x00, 0x1b, 0xb4, 0xdf, 0xea, 0x50, + 0xf4, 0xc5, 0x5e, 0x95, 0xa7, 0x5d, 0xe9, 0x5f, 0xbb, 0x10, 0xc3, 0x17, 0x4a, 0x08, 0x69, 0x98, + 0x3a, 0x8e, 0xa7, 0xd9, 0x12, 0x08, 0xc2, 0x3b, 0x26, 0x91, 0xab, 0x47, 0x7c, 0x95, 0x1b, 0x11, + 0x25, 0xa5, 0x71, 0x95, 0x79, 0x98, 0x06, 0x4a, 0xf2, 0xf1, 0xc0, 0xc7, 0xd4, 0x04, 0x83, 0x88, + 0x92, 0x54, 0x0e, 0x5d, 0xc8, 0xaa, 0x54, 0x70, 0x80, 0x4a, 0x27, 0xfb, 0x0f, 0x3e, 0x94, 0xbe, + 0x0e, 0xf4, 0x47, 0x26, 0xc2, 0xf9, 0x36, 0xef, 0x90, 0x23, 0xc1, 0x70, 0xbd, 0x09, 0x4f, 0x82, + 0xc5, 0xa6, 0x44, 0xad, 0x13, 0xc6, 0x26, 0x4c, 0x23, 0x97, 0x48, 0x30, 0x21, 0x7e, 0x2c, 0xc1, + 0xb4, 0x0c, 0x7f, 0x90, 0xf4, 0xc8, 0x56, 0x25, 0x75, 0x23, 0xfb, 0x7e, 0x0b, 0x9d, 0x16, 0x14, + 0x75, 0x8e, 0xb1, 0x50, 0x5e, 0x9c, 0x91, 0x38, 0x90, 0x38, 0xa1, 0x75, 0x20, 0x4d, 0xed, 0x92, + 0xc3, 0x09, 0x05, 0xc3, 0xd9, 0xa6, 0xca, 0x13, 0x2c, 0x34, 0x55, 0x98, 0x36, 0x1d, 0x37, 0xb3, + 0x24, 0x86, 0xa8, 0x33, 0xa2, 0xd0, 0x5c, 0x0e, 0x82, 0x1d, 0x0d, 0x31, 0xba, 0xa9, 0x95, 0x06, + 0x8c, 0xfb, 0x35, 0xec, 0x8f, 0xbf, 0xcc, 0xa4, 0xf7, 0x9f, 0xc9, 0xa0, 0x2c, 0xa1, 0x79, 0x4d, + 0x43, 0xdb, 0x11, 0x59, 0x5c, 0xbe, 0x57, 0x5c, 0xc8, 0x74, 0x63, 0x9b, 0x27, 0x78, 0xde, 0x09, + 0x76, 0xea, 0xf5, 0x6a, 0xf5, 0x2c, 0xa2, 0x29, 0x38, 0xff, 0x1e, 0x5b, 0xf4, 0xcc, 0x46, 0x36, + 0xfa, 0x47, 0x51, 0x9b, 0x4e, 0xfb, 0xe4, 0x7e, 0xab, 0x25, 0xe3, 0x61, 0xb1, 0xe7, 0xce, 0xef, + 0xda, 0x2b, 0xc2, 0x28, 0xf1, 0xe3, 0x98, 0xfe, 0x18, 0xbc, 0xff, 0x6e, 0x9a, 0xe4, 0x3f, 0x52, + 0xe5, 0x7b, 0x1c, 0xae, 0x21, 0x3c, 0x3c, 0x57, 0xcf, 0x60, 0x00, 0x8e, 0xb4, 0x97, 0x8c, 0x8f, + 0xb5, 0x56, 0x39, 0xe7, 0x45, 0x96, 0xf8, 0x1a, 0xd3, 0xc6, 0xff, 0xe6, 0xb9, 0xde, 0x83, 0x7a, + 0x39, 0x57, 0x70, 0x7d, 0xfc, 0xf8, 0x46, 0xa8, 0x0b, 0xc7, 0x25, 0xfa, 0xb7, 0x2f, 0x23, 0xf8, + 0xa0, 0x22, 0xbf, 0xd4, 0x80, 0x95, 0x5a, 0xce, 0xc7, 0xd4, 0xa7, 0x76, 0x2d, 0xae, 0x67, 0x1a, + 0x6c, 0x98, 0x19, 0xb5, 0x88, 0x67, 0xa1, 0x56, 0x35, 0xb1, 0xbe, 0x3e, 0x9d, 0xc3, 0x03, 0x3a, + 0xcb, 0xdf, 0xb8, 0x67, 0x63, 0xac, 0xf9, 0xab, 0x0f, 0x09, 0x6c, 0x8f, 0xc5, 0xb2, 0xb6, 0x20, + 0x5c, 0x63, 0xe6, 0x26, 0x45, 0xc3, 0x3a, 0x80, 0x8b, 0xdf, 0x7b, 0x54, 0xaf, 0xa4, 0x15, 0x8f, + 0xe5, 0xa2, 0xb3, 0xd3, 0x50, 0xae, 0x81, 0x5a, 0xd3, 0xd0, 0xb3, 0xcf, 0xfb, 0x8a, 0x8b, 0x46, + 0xde, 0x97, 0xb9, 0x4b, 0xba, 0xdd, 0xcb, 0x15, 0xa1, 0xdd, 0xb6, 0x54, 0x6f, 0x50, 0x62, 0xb6, + 0xb5, 0xbb, 0x44, 0x27, 0xe7, 0x3f, 0x89, 0xb0, 0xc2, 0x7b, 0x3e, 0x6f, 0x19, 0x07, 0x25, 0xbf, + 0xc4, 0x2f, 0x4d, 0xa2, 0x6f, 0xab, 0xd2, 0x2e, 0x02, 0x45, 0x72, 0x8c, 0xf1, 0x25, 0x0f, 0x09, + 0xad, 0x7f, 0x02, 0xf8, 0xb3, 0xf3, 0x7b, 0x43, 0x50, 0x42, 0x03, 0xec, 0x24, 0x90, 0x42, 0xb3, + 0xcb, 0x6e, 0x18, 0x5d, 0x58, 0xfc, 0xcb, 0x7b, 0x58, 0x86, 0xf2, 0xb5, 0xa9, 0x7b, 0x93, 0x60, + 0x27, 0x8c, 0xe9, 0x05, 0x08, 0xaa, 0x9e, 0x5f, 0x0b, 0xfe, 0x6f, 0x3e, 0x9a, 0xf7, 0xcf, 0x4b, + 0xb9, 0xbc, 0xcd, 0x33, 0xb4, 0xbc, 0x16, 0x52, 0x4c, 0xed, 0x03, 0x8e, 0x8d, 0xd7, 0xe2, 0x41, + 0xa2, 0x3a, 0xbc, 0x0e, 0xef, 0xb5, 0x66, 0x6b, 0x7f, 0x42, 0x5f, 0xb3, 0xa5, 0x67, 0x2f, 0x32, + 0x65, 0xfb, 0xab, 0xfa, 0x4a, 0xf3, 0x53, 0x01, 0xf6, 0xaa, 0xf0, 0xf2, 0xbe, 0xc3, 0x44, 0x79, + 0x1e, 0xf8, 0x55, 0x5a, 0x57, 0xdc, 0x95, 0x93, 0xeb, 0xf6, 0x7f, 0x39, 0x83, 0x52, 0xfd, 0x13, + 0xd3, 0xd9, 0xfd, 0xe8, 0x49, 0x12, 0xe7, 0xc9, 0x54, 0xac, 0x05, 0xf8, 0x00, 0xe1, 0x08, 0xac, + 0xc8, 0x1b, 0x31, 0x53, 0x83, 0xd7, 0x21, 0xbd, 0xf2, 0xf1, 0xf4, 0xe4, 0xd5, 0x4c, 0xf8, 0x08, + 0xe0, 0xc5, 0x88, 0xf7, 0xd5, 0xea, 0xe6, 0x56, 0x2a, 0x3d, 0x0b, 0x38, 0xd2, 0x9b, 0xfa, 0xb4, + 0x37, 0xb1, 0xf8, 0x2e, 0xaf, 0xde, 0xd4, 0x6a, 0x02, 0xff, 0x47, 0x3e, 0x1f, 0x3b, 0x1d, 0xe7, + 0xc9, 0x84, 0xbb, 0x57, 0x27, 0xec, 0x25, 0x17, 0x51, 0x2b, 0x10, 0xe4, 0x2b, 0xe5, 0x98, 0x54, + 0x5e, 0xe0, 0xab, 0xed, 0xfa, 0x6b, 0xd2, 0xa6, 0x52, 0xb5, 0x35, 0x4d, 0x62, 0xa9, 0xcd, 0xa6, + 0x12, 0x43, 0xf3, 0xeb, 0xf6, 0xe9, 0x79, 0x92, 0xdd, 0x4d, 0xfb, 0x77, 0x2f, 0x85, 0xd6, 0xca, + 0x38, 0xec, 0x3e, 0x21, 0xed, 0x5a, 0x9c, 0xaa, 0x49, 0xc3, 0xb9, 0xb5, 0xf6, 0x6e, 0xf6, 0xb8, + 0xf9, 0x9f, 0xe1, 0x3e, 0x98, 0x3a, 0x04, 0x2e, 0x79, 0x55, 0xbf, 0x42, 0x1d, 0x7d, 0x3b, 0x22, + 0x52, 0xa2, 0xcd, 0x70, 0x07, 0x8b, 0xc1, 0xfe, 0x6f, 0x80, 0xcc, 0x3a, 0x64, 0x49, 0x64, 0x7b, + 0xbe, 0xda, 0x92, 0x99, 0x99, 0xfd, 0xa2, 0x09, 0x8f, 0x3a, 0x0c, 0x4e, 0x9d, 0x9c, 0xc4, 0x53, + 0xd1, 0xa3, 0xe7, 0x76, 0x55, 0x07, 0x8e, 0x56, 0xfe, 0xb9, 0x51, 0xf0, 0x0d, 0x04, 0xcd, 0xc7, + 0xf7, 0xa5, 0xdc, 0xcd, 0x3d, 0xba, 0xe4, 0xa7, 0x55, 0xdc, 0x54, 0xce, 0xe0, 0x9b, 0x32, 0x8e, + 0x43, 0xfa, 0x4c, 0x6a, 0x74, 0x44, 0x2f, 0x98, 0x3f, 0x2e, 0x6e, 0x06, 0xd4, 0xc9, 0xc6, 0xad, + 0x79, 0xd7, 0x5d, 0x38, 0x8e, 0x97, 0xb4, 0xee, 0x91, 0xb1, 0x1b, 0xf1, 0xe0, 0x4f, 0x42, 0x2d, + 0xb7, 0x22, 0x30, 0xa1, 0x49, 0x5e, 0xac, 0x4a, 0xa4, 0x83, 0x97, 0xc4, 0x63, 0xf5, 0x95, 0x2a, + 0x39, 0x6e, 0x46, 0xfb, 0x45, 0x8a, 0x6d, 0x77, 0x44, 0xc7, 0xff, 0x9b, 0xc7, 0x9f, 0x6a, 0x78, + 0x53, 0x4a, 0x8b, 0x18, 0x2b, 0x19, 0x45, 0xbf, 0x06, 0xa5, 0x4d, 0x07, 0xf5, 0x63, 0x6f, 0x2c, + 0xdd, 0xbf, 0x9b, 0x36, 0x4b, 0xa5, 0xca, 0xd0, 0xd2, 0x66, 0xb1, 0x17, 0xed, 0x2f, 0x39, 0xf0, + 0xea, 0xdb, 0x37, 0x75, 0xa1, 0xe0, 0x63, 0x5d, 0x2a, 0x20, 0x88, 0x23, 0x3a, 0xa2, 0x2a, 0x95, + 0xee, 0x79, 0xc1, 0x3f, 0x6f, 0x17, 0x1c, 0x4c, 0xcd, 0x17, 0xf9, 0x90, 0x5a, 0x9a, 0xdd, 0xf7, + 0x73, 0xf4, 0xbb, 0xa6, 0xe3, 0x11, 0xab, 0xee, 0x6b, 0x25, 0xe9, 0xa1, 0x11, 0xed, 0x2c, 0x9a, + 0xad, 0xc1, 0x0a, 0xac, 0x74, 0xaf, 0xa5, 0xf9, 0xb5, 0xe7, 0xdb, 0xb6, 0x6d, 0xdf, 0xb9, 0x15, + 0x9a, 0x36, 0xc4, 0x8d, 0x47, 0x11, 0x5e, 0x49, 0xd4, 0x43, 0x39, 0xd7, 0x91, 0x9b, 0xd1, 0xd7, + 0x44, 0xf8, 0x88, 0x11, 0xe5, 0xfb, 0x6b, 0x65, 0xed, 0xa5, 0x68, 0xe5, 0x6b, 0x3d, 0x33, 0xe4, + 0xae, 0x73, 0x73, 0xd4, 0x69, 0xe6, 0x15, 0xd0, 0x7f, 0x44, 0xe2, 0x6b, 0xe7, 0xdd, 0x98, 0x2f, + 0x6b, 0x25, 0x95, 0xfd, 0x7e, 0x8d, 0x9b, 0x57, 0x1e, 0x1d, 0xb5, 0x5e, 0x76, 0x8d, 0x65, 0xaa, + 0x0a, 0xef, 0xdc, 0x96, 0x37, 0x8d, 0xe2, 0xd4, 0x38, 0x25, 0x37, 0xa2, 0x52, 0xba, 0x60, 0x55, + 0x95, 0xb9, 0x6f, 0xc7, 0xca, 0x5e, 0x7b, 0x29, 0x16, 0xb9, 0x25, 0xfb, 0xf9, 0x33, 0x12, 0x06, + 0xfe, 0x28, 0x9e, 0xb7, 0x66, 0xf7, 0x95, 0x35, 0x7a, 0xda, 0xa6, 0x3b, 0xed, 0x2d, 0xed, 0x17, + 0x6b, 0xb6, 0xdc, 0x05, 0xb9, 0x96, 0x96, 0x2b, 0xdd, 0x2f, 0xf1, 0x77, 0xde, 0xa0, 0x37, 0xee, + 0x53, 0x07, 0xc9, 0x6b, 0xcd, 0x44, 0xc1, 0xaa, 0xfc, 0x73, 0x5b, 0x8e, 0x2f, 0x38, 0x1b, 0x7e, + 0xe9, 0x08, 0x21, 0x44, 0xa5, 0x90, 0xec, 0x1c, 0xf5, 0xef, 0x23, 0x0a, 0x88, 0x32, 0xc8, 0x33, + 0x9e, 0x6a, 0x6f, 0x37, 0x47, 0xdb, 0xdb, 0x82, 0xbf, 0x9e, 0x52, 0x21, 0xee, 0x41, 0x91, 0xf3, + 0x9a, 0x74, 0x46, 0xba, 0x9d, 0x37, 0x91, 0x76, 0x61, 0x5e, 0xa8, 0x50, 0x20, 0xb3, 0xf3, 0x8a, + 0x2d, 0xbc, 0x82, 0xed, 0xef, 0x44, 0x58, 0x20, 0x78, 0x3a, 0xb9, 0x54, 0x5e, 0xe2, 0xfe, 0x11, + 0xb0, 0xf3, 0xc4, 0xfa, 0xb1, 0x3f, 0xc5, 0xc2, 0x4f, 0xc6, 0x74, 0x3a, 0x0f, 0xdb, 0x59, 0xdf, + 0xc2, 0xa6, 0x68, 0x89, 0x98, 0x16, 0xa5, 0x10, 0x62, 0xd9, 0xa6, 0xb2, 0x4b, 0x05, 0x47, 0x45, + 0x3d, 0xaa, 0x19, 0x27, 0xe6, 0x15, 0x24, 0xa8, 0x9b, 0xe2, 0xd5, 0xaf, 0x11, 0x98, 0x5a, 0xdd, + 0xe9, 0xd3, 0xfc, 0x82, 0xf6, 0x7b, 0x0b, 0x1d, 0xc7, 0x4f, 0x29, 0x0a, 0xe7, 0x1f, 0xa5, 0xf2, + 0xa0, 0x02, 0x5d, 0xbc, 0x7f, 0x8f, 0x46, 0xb6, 0x98, 0x3e, 0xef, 0x69, 0x6b, 0x9d, 0x20, 0x09, + 0x95, 0x9c, 0x1d, 0xd1, 0x52, 0xfc, 0xab, 0xf0, 0xf7, 0x6e, 0x6b, 0xe6, 0x26, 0x90, 0x48, 0x5c, + 0x8b, 0xeb, 0xda, 0xf9, 0xeb, 0xa2, 0x2a, 0x0d, 0x18, 0xb7, 0xeb, 0x78, 0x85, 0x43, 0x78, 0xc3, + 0xd9, 0xf4, 0x7e, 0xe9, 0xa5, 0xc6, 0x31, 0xfa, 0x3a, 0x11, 0x45, 0xfe, 0xc9, 0x15, 0x81, 0x1d, + 0xf7, 0x7e, 0xbd, 0xe6, 0x63, 0xe9, 0xdd, 0x8d, 0xad, 0xb5, 0x89, 0x29, 0x99, 0xc0, 0x54, 0x6b, + 0x0d, 0x7b, 0x77, 0xd8, 0xb7, 0x99, 0x9c, 0xf8, 0x14, 0xe5, 0xd9, 0x20, 0x37, 0x99, 0x17, 0xbb, + 0x5b, 0x42, 0x58, 0x14, 0x7e, 0xab, 0xcf, 0x9c, 0x06, 0x6b, 0xc9, 0x45, 0x4d, 0xfc, 0xa8, 0xad, + 0xb9, 0x08, 0x8f, 0xb8, 0x96, 0x9b, 0x01, 0xba, 0x29, 0x03, 0xdc, 0x01, 0x0b, 0x21, 0x94, 0x98, + 0x0d, 0x57, 0x3c, 0x59, 0x39, 0x69, 0xbd, 0xdc, 0x46, 0x85, 0xf2, 0x01, 0x8d, 0x60, 0x57, 0x19, + 0xf3, 0x62, 0x33, 0x31, 0xf2, 0xe2, 0xe1, 0xd4, 0xc8, 0x1f, 0x51, 0x4c, 0x1b, 0x5d, 0x95, 0x61, + 0xf2, 0xf2, 0xae, 0xc7, 0xf0, 0x61, 0x71, 0xbf, 0x4d, 0x15, 0xed, 0xf2, 0x32, 0xc0, 0x9c, 0xf5, + 0x81, 0x91, 0xf1, 0x3b, 0xa6, 0x2a, 0x9b, 0x8b, 0x2c, 0x0c, 0x70, 0xbf, 0x22, 0x59, 0xab, 0xdc, + 0x99, 0x98, 0x9d, 0x96, 0xed, 0x20, 0xdc, 0x77, 0x33, 0x01, 0xcd, 0x08, 0x4a, 0x21, 0x15, 0x5b, + 0x40, 0x6a, 0x10, 0xf6, 0x2a, 0xe8, 0x25, 0x37, 0x73, 0x24, 0x88, 0x72, 0xf5, 0x60, 0x94, 0x02, + 0xba, 0x3b, 0xbe, 0x1f, 0xe3, 0x34, 0x62, 0xfe, 0x89, 0x69, 0x36, 0x5c, 0x40, 0x16, 0xeb, 0x3c, + 0xed, 0xc1, 0x7f, 0x5a, 0x9a, 0xae, 0xc7, 0x7d, 0xbd, 0x8c, 0x9b, 0x3d, 0x28, 0x57, 0x5b, 0xe8, + 0x76, 0xcb, 0x51, 0xaa, 0xb3, 0x62, 0xd1, 0x4a, 0xda, 0xab, 0xa4, 0x81, 0x62, 0x92, 0x45, 0x67, + 0x9f, 0x19, 0x01, 0xde, 0xe7, 0x17, 0xa0, 0xfe, 0x97, 0xff, 0x96, 0xc9, 0x1d, 0xec, 0x21, 0x18, + 0x68, 0xd3, 0xf9, 0xbe, 0x8a, 0xdc, 0x90, 0x7d, 0xd1, 0x5e, 0x88, 0x13, 0xd6, 0x3a, 0x4f, 0x92, + 0xc8, 0x80, 0xd4, 0x63, 0x6d, 0x35, 0x7b, 0x4e, 0x24, 0x64, 0x75, 0x8d, 0x43, 0xb2, 0x2a, 0x2d, + 0xcb, 0xad, 0xac, 0xe4, 0x48, 0x4e, 0x61, 0x99, 0xb8, 0x7f, 0x1f, 0x13, 0x06, 0x82, 0x44, 0x9f, + 0x69, 0x42, 0x33, 0x55, 0xbe, 0x5f, 0x3c, 0xc8, 0x5a, 0x65, 0x67, 0xd8, 0x4c, 0x4e, 0x92, 0xa6, + 0x33, 0x3a, 0x10, 0x7f, 0x0d, 0xc6, 0xd7, 0x42, 0x43, 0x9b, 0x89, 0x04, 0x93, 0xe9, 0x70, 0x57, + 0x46, 0xaa, 0x38, 0xfe, 0x03, 0x2e, 0x9b, 0xe3, 0xa4, 0xfe, 0x53, 0xb1, 0x1d, 0x11, 0x2d, 0xc8, + 0x32, 0x10, 0x6d, 0x0f, 0x0c, 0x71, 0xba, 0x6e, 0xee, 0x58, 0xb6, 0xd1, 0xb8, 0xdc, 0xb2, 0xe3, + 0x5f, 0x05, 0xae, 0x0f, 0x52, 0x98, 0x26, 0xac, 0xda, 0xbe, 0x17, 0xe6, 0x7c, 0xbf, 0xdf, 0x6b, + 0x8a, 0x3b, 0x54, 0x9b, 0x73, 0x7d, 0xe0, 0x9b, 0x56, 0x13, 0xb4, 0xa7, 0x5b, 0xf5, 0x6e, 0xdc, + 0x65, 0x60, 0xd0, 0x78, 0x21, 0x35, 0xf0, 0x5a, 0xbb, 0x53, 0x42, 0xd7, 0xfb, 0xe1, 0x8c, 0xe8, + 0xe0, 0xf1, 0x24, 0x91, 0x11, 0xdf, 0x36, 0xe2, 0x84, 0xc9, 0xe0, 0xcd, 0x3d, 0x29, 0xbd, 0xf7, + 0xf7, 0xb1, 0x2a, 0x12, 0x60, 0x25, 0xae, 0xe2, 0xe8, 0x4a, 0x0e, 0x7a, 0xc4, 0xaf, 0x73, 0x8f, + 0x43, 0x71, 0x76, 0x51, 0x76, 0x54, 0xbf, 0x8a, 0x2a, 0xf5, 0x13, 0xc2, 0xf1, 0x48, 0x7c, 0x69, + 0x7d, 0xcc, 0x5f, 0x68, 0x48, 0x8a, 0x54, 0x11, 0x8d, 0xcd, 0xa4, 0x7c, 0x25, 0xd5, 0x90, 0xb1, + 0x7f, 0x8d, 0x43, 0xf2, 0x1f, 0xbb, 0x90, 0xa1, 0xbb, 0x3f, 0x31, 0x3d, 0x67, 0x3f, 0x90, 0x27, + 0x74, 0x91, 0x00, 0x2d, 0x7b, 0xab, 0x3d, 0xd1, 0x34, 0x96, 0xde, 0x69, 0x3b, 0xee, 0xfb, 0x36, + 0x91, 0x2f, 0x79, 0xf9, 0x1c, 0x7c, 0xa7, 0x12, 0xba, 0x31, 0x9d, 0x36, 0x24, 0x36, 0x92, 0x3a, + 0x7e, 0xed, 0x7e, 0x92, 0x7f, 0xf2, 0xd5, 0x02, 0x5f, 0x93, 0xb5, 0xf1, 0x1d, 0xd9, 0xab, 0xd7, + 0xdb, 0x06, 0x0d, 0x0c, 0x91, 0xc9, 0x95, 0x62, 0x99, 0x9c, 0x59, 0x49, 0x0d, 0xe9, 0x9e, 0xde, + 0xf2, 0xb1, 0x0a, 0x16, 0x94, 0x88, 0xe4, 0x55, 0xc1, 0x7f, 0x9f, 0xbe, 0x36, 0xea, 0x3d, 0x8d, + 0xa1, 0x84, 0x9c, 0x28, 0xbe, 0x68, 0xf7, 0xcf, 0xd3, 0x57, 0xaf, 0x36, 0xe3, 0x6b, 0xf2, 0xca, + 0x86, 0x90, 0x3c, 0xc3, 0xd5, 0x98, 0x6e, 0xea, 0x6b, 0xeb, 0xb2, 0x1e, 0x48, 0x07, 0x16, 0x1a, + 0x86, 0x5a, 0xb0, 0x9c, 0xa0, 0x32, 0x38, 0xd5, 0xa4, 0x8a, 0x91, 0x8e, 0x5e, 0xdd, 0xb0, 0x72, + 0xde, 0x4c, 0xde, 0xc9, 0x22, 0x2a, 0x28, 0x99, 0xbe, 0x4c, 0xe6, 0x2e, 0x9f, 0xce, 0xda, 0x70, + 0xf1, 0xac, 0x5f, 0xc9, 0x9e, 0x7a, 0xfb, 0x76, 0x70, 0xa7, 0x3a, 0x2e, 0x25, 0x34, 0xbd, 0xb5, + 0x01, 0x1d, 0xd9, 0x19, 0x0a, 0x44, 0xd5, 0xa7, 0xd3, 0xb4, 0x86, 0x3e, 0x68, 0x75, 0x85, 0x7a, + 0xd5, 0x51, 0x6a, 0xac, 0x73, 0x75, 0x86, 0xba, 0x7d, 0x55, 0x48, 0x31, 0xef, 0xaf, 0x97, 0x77, + 0x53, 0xb7, 0xfe, 0x38, 0x8a, 0xe9, 0xe4, 0xd4, 0x78, 0x54, 0x1a, 0x0f, 0x92, 0xfd, 0xda, 0xd1, + 0xe4, 0xdb, 0xbe, 0x3d, 0x40, 0xd3, 0x4f, 0x82, 0xa7, 0x59, 0xfa, 0x5a, 0x16, 0xfb, 0x6f, 0x87, + 0xac, 0xaf, 0xd5, 0x93, 0xf3, 0x81, 0x8d, 0x43, 0x00, 0x7b, 0xaa, 0xbe, 0xa7, 0x8d, 0x3c, 0xb0, + 0x14, 0xd2, 0x30, 0x66, 0xc5, 0x5b, 0xe6, 0xe1, 0xfd, 0x2b, 0x55, 0xa6, 0x8d, 0x81, 0xf9, 0xa2, + 0xa5, 0x78, 0xd6, 0x7d, 0x14, 0x4c, 0x76, 0x17, 0x45, 0x3e, 0x4b, 0x75, 0x4c, 0x1a, 0x1b, 0xc9, + 0xcc, 0xfe, 0xc3, 0xf7, 0xbb, 0x37, 0xf9, 0xfa, 0xc9, 0x8f, 0xa7, 0x7d, 0x52, 0xd0, 0x4f, 0x4c, + 0x03, 0x0d, 0xd9, 0x29, 0x12, 0x6e, 0xac, 0x39, 0x91, 0x6b, 0x48, 0x4e, 0x53, 0x99, 0x5d, 0xc5, + 0x23, 0x83, 0x9a, 0x94, 0x67, 0x54, 0xbf, 0xb4, 0x2e, 0x6e, 0x95, 0x49, 0xe7, 0x47, 0x42, 0x4a, + 0x1e, 0xb8, 0x31, 0xc5, 0xdf, 0x6e, 0xbb, 0x5a, 0xff, 0xe8, 0x09, 0x1e, 0x86, 0x61, 0x9f, 0x9f, + 0x5d, 0x9f, 0x3d, 0x76, 0x1d, 0xbe, 0xa9, 0x8d, 0xcf, 0xa1, 0x6f, 0x6a, 0xcb, 0x46, 0xc8, 0xae, + 0xdb, 0x3b, 0x2b, 0x37, 0xaf, 0xec, 0x7a, 0x62, 0x35, 0x1f, 0x05, 0x7b, 0xbb, 0xea, 0x74, 0x89, + 0x88, 0x77, 0xff, 0xb8, 0x3d, 0x19, 0x74, 0xff, 0xba, 0x3d, 0x8d, 0x77, 0x8a, 0x0d, 0x3f, 0x84, + 0x35, 0xf6, 0x82, 0x69, 0x76, 0xd7, 0x75, 0x3c, 0xd6, 0x8c, 0x4f, 0xf0, 0xa0, 0x32, 0xa2, 0x95, + 0x95, 0x61, 0x7d, 0xcf, 0xd5, 0x51, 0x3c, 0xd7, 0x4f, 0xba, 0x98, 0x93, 0xfe, 0x53, 0x0f, 0xf8, + 0x68, 0x72, 0xe6, 0xf2, 0xd1, 0x98, 0x9c, 0xbe, 0x26, 0x36, 0x42, 0x82, 0x88, 0xfd, 0x3e, 0x69, + 0xaf, 0x22, 0xa1, 0x59, 0x9e, 0xa0, 0xba, 0xe6, 0x37, 0xc3, 0xa3, 0x2e, 0x3e, 0x04, 0xec, 0xe6, + 0xd9, 0xa4, 0xec, 0xcf, 0x33, 0x3c, 0xb9, 0x74, 0x3a, 0xf2, 0xb0, 0xb9, 0x25, 0x62, 0x31, 0x94, + 0xbd, 0xa9, 0x26, 0xb2, 0xc5, 0xd3, 0x82, 0x2b, 0x24, 0xcf, 0x98, 0x15, 0x29, 0x40, 0x1c, 0x60, + 0xb2, 0x1d, 0x5b, 0xdd, 0x56, 0x36, 0x1f, 0xc0, 0xe7, 0xd4, 0xb5, 0x24, 0xd4, 0x47, 0xfb, 0x43, + 0xb3, 0x1b, 0xe5, 0xca, 0x68, 0xc5, 0xa6, 0x49, 0x08, 0x8f, 0xd4, 0x84, 0xb2, 0xc8, 0xe8, 0xca, + 0x6b, 0x8f, 0x21, 0x9e, 0xc6, 0x5e, 0xac, 0xa3, 0x43, 0x8d, 0xe3, 0x64, 0xb2, 0x3b, 0xda, 0x39, + 0x1d, 0x82, 0xda, 0x9a, 0x6a, 0x96, 0x30, 0xbf, 0xab, 0x66, 0x97, 0x9c, 0xef, 0x61, 0x6c, 0x36, + 0x20, 0x3f, 0xbc, 0xc6, 0x0e, 0xbc, 0xb5, 0xa9, 0xdf, 0x44, 0x5b, 0xe9, 0x10, 0xf7, 0x29, 0xe6, + 0x59, 0xff, 0x35, 0x46, 0x2c, 0x6d, 0xc6, 0x8a, 0xdb, 0x21, 0x79, 0x5a, 0x18, 0xf8, 0xb1, 0x13, + 0x48, 0x0b, 0xfb, 0x89, 0x69, 0x61, 0x69, 0xb0, 0x76, 0x12, 0xa4, 0xfd, 0x3e, 0xe4, 0x6b, 0xe4, + 0x8f, 0x03, 0xef, 0x55, 0x5e, 0x28, 0x7e, 0xce, 0x2e, 0x9f, 0x3e, 0xd4, 0x28, 0xeb, 0xa0, 0xbf, + 0x4c, 0xc4, 0x1e, 0xa1, 0xd2, 0x04, 0x3a, 0x30, 0x6f, 0x53, 0x6f, 0x6e, 0xcd, 0xc9, 0xc5, 0x72, + 0xfa, 0xb6, 0x25, 0x04, 0xfa, 0xe9, 0x5f, 0xd2, 0x61, 0x5e, 0x7a, 0xfb, 0x3e, 0xdf, 0x28, 0xef, + 0x5f, 0x4b, 0x01, 0xf0, 0xef, 0x0b, 0x50, 0x3c, 0xce, 0xe4, 0xa4, 0x90, 0x31, 0x93, 0x5e, 0x24, + 0xdf, 0xf5, 0xd7, 0xa5, 0x5e, 0x83, 0x58, 0xc4, 0x4b, 0x60, 0x5b, 0xfb, 0x5b, 0xf1, 0x8c, 0xc1, + 0x3b, 0xfd, 0x6e, 0xa7, 0xb1, 0x2a, 0x8b, 0x66, 0x6a, 0xfc, 0x18, 0x2d, 0xcd, 0x5a, 0x46, 0x69, + 0x73, 0xaf, 0x54, 0x52, 0x1e, 0xae, 0xae, 0x7e, 0x78, 0x6b, 0x29, 0x6e, 0xdd, 0xe7, 0x91, 0x28, + 0xa0, 0xf5, 0x67, 0xd9, 0xa7, 0x67, 0x11, 0x0e, 0xfe, 0xb8, 0x16, 0xaa, 0x47, 0xf5, 0xba, 0xff, + 0x8c, 0xde, 0xd7, 0x62, 0xf5, 0x29, 0xee, 0x5f, 0xb7, 0x0f, 0xa3, 0x25, 0xe7, 0x13, 0x1e, 0x29, + 0x1f, 0xb5, 0xe6, 0x25, 0x0a, 0xa3, 0xdb, 0x8b, 0xd9, 0x0c, 0x68, 0xb5, 0xc6, 0xf6, 0xdd, 0x8e, + 0x42, 0x8a, 0x7d, 0x42, 0x37, 0xae, 0x7a, 0x6c, 0x2f, 0xd6, 0xc6, 0xbe, 0x56, 0x05, 0x25, 0xc4, + 0x54, 0xab, 0x06, 0x48, 0x12, 0xe5, 0x46, 0x22, 0x93, 0xfe, 0x6f, 0x4a, 0x7e, 0x25, 0xce, 0x10, + 0x8e, 0xfd, 0x9e, 0x8a, 0x25, 0xbb, 0xd2, 0x39, 0x78, 0x16, 0xc4, 0x73, 0xf1, 0x31, 0x85, 0xc1, + 0x91, 0x75, 0xa1, 0xf2, 0xf5, 0x3d, 0x3b, 0xb6, 0x27, 0xca, 0x57, 0x98, 0x50, 0xe3, 0x19, 0x3a, + 0x1c, 0x2e, 0x46, 0x96, 0x14, 0x37, 0x91, 0xb9, 0x14, 0x70, 0x5c, 0xc2, 0xd3, 0xd1, 0x80, 0x14, + 0x27, 0x65, 0xba, 0x8f, 0x74, 0x2c, 0x02, 0xad, 0x70, 0x79, 0x11, 0x27, 0xc1, 0x4a, 0x92, 0xeb, + 0x54, 0x1b, 0x96, 0xdb, 0xa7, 0xbe, 0x5a, 0xd6, 0x6d, 0x11, 0x6d, 0x79, 0xe8, 0x22, 0xed, 0x5f, + 0x45, 0xcc, 0x8f, 0x4f, 0x73, 0x46, 0xe4, 0x4f, 0x4c, 0x73, 0xe6, 0x4c, 0x37, 0xfe, 0x69, 0xc5, + 0x73, 0xc2, 0x23, 0xcb, 0x09, 0x83, 0x21, 0xc5, 0x6e, 0x34, 0xf1, 0x6d, 0x5e, 0xd6, 0x54, 0x45, + 0xd4, 0x95, 0xf0, 0x77, 0x7a, 0x2c, 0x97, 0x1d, 0xfc, 0x32, 0x51, 0xc3, 0x2a, 0x64, 0x3d, 0x22, + 0xc0, 0x51, 0x16, 0xb7, 0xf8, 0xce, 0xde, 0xc4, 0x85, 0xa6, 0x1b, 0x32, 0xeb, 0x6b, 0x2d, 0xc8, + 0x0b, 0x05, 0x79, 0x59, 0x51, 0xc1, 0x11, 0xd6, 0x85, 0x1c, 0x41, 0x1a, 0x49, 0xae, 0x3c, 0xd5, + 0x6e, 0x29, 0x64, 0x6b, 0x17, 0x32, 0x66, 0x6d, 0x78, 0x5b, 0x2f, 0x52, 0x88, 0x6b, 0x24, 0x97, + 0x45, 0xa9, 0xcb, 0xf0, 0xf8, 0xd4, 0x95, 0xea, 0xeb, 0x46, 0x2c, 0x76, 0xe6, 0x52, 0x94, 0xb4, + 0x08, 0x9a, 0x1b, 0xe5, 0x0b, 0xb6, 0x6d, 0xbd, 0x3c, 0xab, 0x59, 0x0b, 0xfa, 0x2d, 0xbc, 0x89, + 0x02, 0x5a, 0x5f, 0xad, 0x22, 0x8b, 0x6f, 0xc2, 0xf4, 0x29, 0xb2, 0x52, 0x90, 0x29, 0x0e, 0xe7, + 0x2a, 0xa0, 0xfb, 0x1c, 0x5b, 0x8c, 0x9e, 0xfd, 0x6f, 0xe1, 0x37, 0x8b, 0xdf, 0x3f, 0xbc, 0xf6, + 0xba, 0x4f, 0x43, 0x02, 0x59, 0xe2, 0xb8, 0x77, 0x9d, 0x01, 0xfb, 0x2c, 0xb9, 0xf7, 0xb8, 0xc5, + 0x91, 0x99, 0x54, 0xbb, 0xd2, 0xea, 0x13, 0x82, 0x6e, 0x02, 0xb5, 0x8f, 0x44, 0x5b, 0x6d, 0x81, + 0x5c, 0x41, 0x85, 0xf3, 0xe4, 0x82, 0xb5, 0xf8, 0xd7, 0xfb, 0xec, 0xa2, 0xfc, 0x3c, 0x48, 0x9a, + 0x5f, 0x53, 0x6d, 0xdf, 0x6c, 0xf8, 0xf8, 0x40, 0xcc, 0x5c, 0x2b, 0xa1, 0xfa, 0x98, 0x7c, 0xba, + 0x7b, 0x9b, 0xfd, 0xfa, 0x10, 0x2d, 0xbd, 0xc0, 0xfc, 0x51, 0xad, 0x01, 0x5f, 0x68, 0x23, 0x5f, + 0xaf, 0x45, 0xc7, 0xdf, 0x93, 0xfc, 0x0b, 0x6d, 0x80, 0x9b, 0x8a, 0x9a, 0x8e, 0xf3, 0xd7, 0xf6, + 0xa3, 0xa6, 0x2e, 0x55, 0x3e, 0xeb, 0x2f, 0x9b, 0x05, 0x45, 0x64, 0x3d, 0x2c, 0x78, 0x6e, 0xd9, + 0xc3, 0x8a, 0x28, 0x3a, 0x15, 0xb6, 0x31, 0x62, 0x5a, 0x06, 0xef, 0x20, 0x58, 0x14, 0x64, 0x50, + 0x8e, 0x56, 0x16, 0xed, 0x6c, 0x52, 0xc2, 0x2d, 0xf3, 0x8f, 0x7d, 0x84, 0xb2, 0x3f, 0x31, 0xfd, + 0x75, 0xc4, 0xeb, 0xdd, 0x65, 0x28, 0xdb, 0x76, 0x28, 0x19, 0xb3, 0x40, 0xbf, 0x0c, 0x34, 0x7b, + 0xb5, 0x5f, 0x48, 0x20, 0x25, 0xa6, 0xe6, 0x62, 0xd0, 0xe7, 0xfe, 0xe0, 0x4f, 0x3e, 0xf9, 0xe4, + 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, + 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0x4f, 0x3e, 0xf9, 0xe4, 0x93, 0xff, + 0x3b, 0xf9, 0xe7, 0x79, 0xb0, 0x79, 0x41, 0xd9, 0x8b, 0x4e, 0x72, 0x23, 0xa0, 0x14, 0x9a, 0x05, + 0x81, 0x46, 0x68, 0x36, 0x07, 0xb8, 0x3c, 0xb3, 0x32, 0xfb, 0x4d, 0x79, 0x96, 0xe7, 0x45, 0xda, + 0x98, 0x69, 0xdd, 0x3f, 0xa5, 0x10, 0xca, 0xe1, 0xc4, 0xac, 0x19, 0xb8, 0xa1, 0xbf, 0x8a, 0x8c, + 0x05, 0x32, 0x05, 0x8b, 0x5c, 0xcf, 0xd5, 0xa1, 0xcc, 0xc9, 0xb0, 0xe6, 0xa8, 0x01, 0xba, 0x48, + 0x81, 0x61, 0x74, 0x29, 0x77, 0xe6, 0x69, 0xa5, 0x80, 0x27, 0xf9, 0x5e, 0xa4, 0x6a, 0x0d, 0xc6, + 0x73, 0x00, 0x29, 0x4e, 0xe3, 0x80, 0x9c, 0x3a, 0x9c, 0x06, 0x0c, 0x86, 0x93, 0x7e, 0xae, 0xb4, + 0x86, 0x97, 0x00, 0xa7, 0xcb, 0x75, 0x09, 0x30, 0xd5, 0x16, 0x7b, 0x6c, 0x3c, 0x46, 0x52, 0x94, + 0xf7, 0x04, 0x0d, 0x82, 0x7b, 0x67, 0x68, 0xf2, 0xda, 0x7f, 0xee, 0xc2, 0x2e, 0x85, 0x32, 0x44, + 0x9a, 0x75, 0x7a, 0xcc, 0x3f, 0xd6, 0x8e, 0xea, 0x24, 0xff, 0x5e, 0xd1, 0x98, 0xd7, 0x90, 0x16, + 0x64, 0x51, 0xaf, 0x40, 0xa4, 0xe5, 0x1c, 0x64, 0x95, 0x24, 0xb8, 0x07, 0xaf, 0xe7, 0xb8, 0x39, + 0x75, 0x8e, 0x85, 0x47, 0xb4, 0x6f, 0x69, 0x4a, 0x13, 0x45, 0x38, 0xd8, 0x6a, 0x2e, 0xec, 0x65, + 0xf6, 0x47, 0xc6, 0x70, 0x27, 0x51, 0x33, 0x5b, 0xef, 0x1d, 0xe9, 0x98, 0x9c, 0x6b, 0xb6, 0x68, + 0x92, 0xc2, 0x5c, 0x40, 0xb5, 0xdf, 0x31, 0x8a, 0x7a, 0x8a, 0x99, 0x4a, 0x20, 0xb0, 0x18, 0x9a, + 0x75, 0xfb, 0xf6, 0x69, 0xde, 0x76, 0x4f, 0xca, 0xfc, 0xa6, 0x07, 0x7d, 0x0c, 0x2f, 0xd7, 0x78, + 0x63, 0xcf, 0x90, 0x86, 0xb3, 0x70, 0x2c, 0x53, 0x5c, 0x0c, 0x27, 0xf9, 0x45, 0x59, 0x6b, 0x41, + 0xd7, 0x3d, 0x2f, 0x17, 0xe3, 0xce, 0xe0, 0x15, 0xa1, 0x90, 0x5d, 0xcc, 0x99, 0x1f, 0x0b, 0x99, + 0xe4, 0x6f, 0xb4, 0xe6, 0x24, 0x0b, 0x03, 0x88, 0x7d, 0x82, 0x13, 0x7a, 0xb4, 0x63, 0x95, 0xdd, + 0x04, 0xa9, 0x69, 0x91, 0x55, 0x31, 0xad, 0xe9, 0xeb, 0xdd, 0x0c, 0x5f, 0xc7, 0x6c, 0x61, 0x4b, + 0x47, 0xce, 0x54, 0x07, 0xe8, 0x6b, 0x6e, 0xc3, 0x34, 0x18, 0x9b, 0xc6, 0x07, 0x7f, 0x3a, 0xab, + 0xaf, 0x54, 0xbe, 0xe4, 0x2d, 0xd1, 0x10, 0x7a, 0xd2, 0xe8, 0xf5, 0x9b, 0xd4, 0xcc, 0x92, 0xb6, + 0xb8, 0x17, 0xa6, 0xba, 0x2d, 0xce, 0x3c, 0x65, 0xf5, 0xa3, 0x72, 0x6d, 0xe6, 0x96, 0xa8, 0x48, + 0xba, 0x22, 0x66, 0x7d, 0x0e, 0xa6, 0xe6, 0x37, 0x29, 0xe0, 0x8d, 0xfd, 0x02, 0x3f, 0x27, 0x90, + 0x5c, 0x18, 0x6a, 0xf9, 0x96, 0xf3, 0x1a, 0xed, 0x9f, 0x40, 0x5f, 0xb7, 0xdd, 0x46, 0xa9, 0x7c, + 0xf5, 0xbe, 0xbc, 0xaf, 0x7d, 0x97, 0x95, 0xcb, 0xa6, 0x9b, 0x54, 0x93, 0x22, 0xb5, 0xbf, 0xe3, + 0x49, 0x99, 0x69, 0xad, 0xb3, 0x5a, 0x37, 0xd5, 0x96, 0x33, 0x17, 0x09, 0x65, 0x47, 0x5d, 0xd7, + 0xf4, 0xe7, 0x23, 0xa5, 0x56, 0x3c, 0x32, 0xcd, 0x87, 0x7d, 0x4c, 0xc6, 0xfe, 0xe8, 0x2b, 0xf5, + 0xfd, 0x92, 0x14, 0xa5, 0x39, 0xf2, 0x2c, 0xfc, 0x58, 0x67, 0xb7, 0xf0, 0x13, 0xd3, 0x49, 0xa5, + 0x69, 0xbb, 0x95, 0xce, 0xac, 0x05, 0x51, 0xfe, 0xaa, 0xed, 0xb6, 0xdc, 0x31, 0x35, 0xb7, 0x38, + 0xac, 0xf9, 0xf0, 0xa4, 0x2e, 0xd5, 0x13, 0xa2, 0xf2, 0x3c, 0x17, 0x34, 0x53, 0x97, 0xda, 0x70, + 0x09, 0x85, 0x64, 0xd7, 0x12, 0x28, 0x98, 0x41, 0xbc, 0xdd, 0x37, 0xd8, 0xb8, 0xc5, 0x52, 0xcf, + 0x17, 0xac, 0x3e, 0xd4, 0x66, 0x4e, 0x1c, 0x8d, 0x6c, 0x6e, 0x54, 0x47, 0xc5, 0x8d, 0xbe, 0xda, + 0x6e, 0x84, 0x70, 0xa7, 0x70, 0xa9, 0xde, 0xd0, 0xc5, 0x6c, 0xd7, 0x1b, 0xa3, 0x90, 0xa3, 0xf7, + 0x48, 0x71, 0xdf, 0x9c, 0xb1, 0xca, 0x14, 0xd0, 0x55, 0x52, 0x3a, 0xa1, 0x4f, 0x45, 0xa1, 0xf9, + 0xfd, 0x52, 0xea, 0xcd, 0xf1, 0xd7, 0xab, 0xb7, 0xcc, 0xf5, 0x04, 0x7c, 0xd9, 0xf9, 0xaa, 0x95, + 0xe9, 0x68, 0xf4, 0xda, 0x2e, 0x36, 0x01, 0xb5, 0xed, 0xa4, 0xe1, 0xf8, 0xd4, 0xaf, 0x78, 0xd4, + 0x1b, 0x94, 0xb8, 0xd9, 0x35, 0xfa, 0x12, 0x5a, 0x7d, 0x0a, 0x2c, 0x04, 0x2b, 0xe0, 0xd3, 0xcd, + 0x1b, 0x10, 0x17, 0xb9, 0x5f, 0x49, 0xe3, 0x99, 0xb7, 0x8c, 0x8b, 0xac, 0xf5, 0xdc, 0x95, 0xc0, + 0xda, 0xcf, 0x75, 0x8b, 0xe7, 0x77, 0x35, 0x5c, 0xe2, 0xbe, 0xbd, 0x6a, 0x18, 0x2d, 0x75, 0xda, + 0x7a, 0x25, 0x1e, 0xa4, 0x1e, 0x01, 0x6b, 0x7d, 0xc4, 0x76, 0x1d, 0x24, 0x3a, 0x4a, 0xd3, 0xa4, + 0xd4, 0xd2, 0xaf, 0xb9, 0x0f, 0x17, 0x76, 0xed, 0x62, 0xa6, 0xc7, 0x11, 0xbd, 0x3e, 0x8c, 0xf5, + 0x32, 0x33, 0x63, 0x36, 0xc2, 0x90, 0x2a, 0x6c, 0x05, 0xf4, 0xe4, 0x82, 0xc5, 0x0c, 0x7b, 0xb1, + 0xd5, 0x92, 0x82, 0xad, 0xcb, 0x0e, 0xca, 0xd6, 0x05, 0xa1, 0x7c, 0xd4, 0x67, 0x65, 0xdd, 0x7b, + 0xc1, 0xd6, 0x74, 0xd7, 0xb3, 0xf2, 0x05, 0x90, 0x45, 0x13, 0xaa, 0x70, 0x54, 0x85, 0x48, 0xb8, + 0x5a, 0xc9, 0xce, 0x18, 0x2e, 0xb5, 0x92, 0xbb, 0x5a, 0xfd, 0x3f, 0x05, 0xd5, 0x51, 0x08, 0x55, + 0xeb, 0x5d, 0x6e, 0x4f, 0x32, 0x6d, 0x53, 0xfc, 0x4b, 0xed, 0xa8, 0xf9, 0x27, 0xa6, 0xd9, 0x03, + 0xd7, 0xcd, 0x49, 0x28, 0x8a, 0x80, 0x2f, 0xf7, 0x02, 0x63, 0x9b, 0xea, 0x88, 0xb6, 0x4f, 0xb0, + 0xae, 0xce, 0xbc, 0xd7, 0xa1, 0x13, 0x96, 0x8d, 0x24, 0x57, 0xc8, 0x3f, 0x58, 0xd8, 0x35, 0xea, + 0x98, 0xa1, 0x7d, 0xd9, 0x7b, 0x90, 0xc4, 0xa2, 0x40, 0xb9, 0x81, 0xf3, 0xf8, 0x8f, 0x0f, 0x9d, + 0x9c, 0x6c, 0x23, 0x39, 0xad, 0x11, 0x99, 0x15, 0x53, 0xb3, 0x88, 0xbf, 0xb9, 0xca, 0xb7, 0x4d, + 0x16, 0xb3, 0x31, 0x5d, 0x21, 0x09, 0x8d, 0xcf, 0x3c, 0x3b, 0xa4, 0x24, 0xb6, 0xf9, 0x4c, 0x2b, + 0x14, 0xd6, 0xc3, 0x71, 0x51, 0x00, 0x86, 0xa6, 0x71, 0xbe, 0xef, 0x77, 0x4c, 0x0a, 0xc7, 0xc2, + 0x98, 0xa5, 0xe0, 0xd1, 0xaa, 0x49, 0xd7, 0x19, 0xaa, 0x9e, 0x11, 0x99, 0x87, 0x2b, 0x71, 0x09, + 0x72, 0xb8, 0x5c, 0x92, 0x80, 0xef, 0xa8, 0x30, 0xba, 0x83, 0xf4, 0x04, 0x81, 0xa3, 0xd1, 0x57, + 0xc0, 0xac, 0x20, 0xd7, 0x01, 0xab, 0x32, 0x01, 0x0d, 0xec, 0x47, 0x9e, 0x29, 0xd8, 0x18, 0xac, + 0x50, 0xfd, 0xf1, 0xe6, 0x0b, 0x2d, 0x74, 0x6f, 0x1c, 0x6e, 0x4a, 0x11, 0x71, 0x64, 0x46, 0x78, + 0x1d, 0x62, 0x0f, 0xec, 0x3b, 0x75, 0x0e, 0xfd, 0xeb, 0xa5, 0x3f, 0x94, 0x7f, 0xda, 0x73, 0x12, + 0xe8, 0x00, 0x38, 0xc2, 0xee, 0xd5, 0x4e, 0x15, 0xc3, 0x9b, 0xa7, 0xcd, 0xd6, 0x1a, 0xfb, 0x2a, + 0xa6, 0x0b, 0x57, 0x98, 0xf6, 0x1e, 0xbe, 0x0b, 0xa0, 0x9c, 0xb4, 0xa1, 0xbb, 0xc5, 0xe8, 0x0d, + 0xb9, 0xc0, 0xe1, 0xba, 0xbe, 0xee, 0x3e, 0x1c, 0x5f, 0xfa, 0xa2, 0x18, 0x3d, 0xed, 0x8b, 0x84, + 0x06, 0xfc, 0x75, 0x8a, 0x7d, 0x39, 0xed, 0xf3, 0xfd, 0x17, 0x8b, 0x8a, 0x0b, 0xf4, 0x5b, 0x56, + 0xd7, 0x65, 0x34, 0xbb, 0x07, 0xe4, 0xdc, 0xb8, 0x57, 0xea, 0x57, 0x58, 0x04, 0x30, 0xbc, 0x23, + 0xc2, 0x56, 0x09, 0x52, 0x03, 0x15, 0x1e, 0x64, 0x22, 0x5a, 0x0f, 0x22, 0x21, 0xcd, 0x04, 0x3e, + 0x26, 0x23, 0x8a, 0xe2, 0xee, 0x17, 0x38, 0x17, 0xfa, 0xb1, 0x8f, 0x3f, 0xb5, 0xfb, 0x13, 0xd3, + 0x73, 0x36, 0xa7, 0x05, 0xbd, 0x57, 0xf7, 0xce, 0x27, 0xbb, 0x73, 0x32, 0xa8, 0x6c, 0xd7, 0x32, + 0xc6, 0x9e, 0x5a, 0x1d, 0x2b, 0xcf, 0x4e, 0x81, 0x85, 0xa0, 0x67, 0x71, 0x10, 0x3e, 0x1b, 0xb5, + 0xaa, 0xca, 0x8f, 0x2f, 0xa2, 0x76, 0x46, 0x58, 0x8c, 0x4c, 0x10, 0xf4, 0x4d, 0xbf, 0x5d, 0x18, + 0x5f, 0x34, 0xe6, 0x2e, 0x32, 0xbb, 0x9a, 0xcb, 0xd5, 0x31, 0x36, 0xae, 0xdc, 0x26, 0xd0, 0x0f, + 0x3d, 0x2a, 0xb6, 0x5c, 0xf6, 0xd6, 0x9a, 0x2e, 0x99, 0xc8, 0xe4, 0x1b, 0x98, 0x36, 0xdd, 0x64, + 0xab, 0xa6, 0xdb, 0x84, 0x81, 0x0b, 0xdc, 0x56, 0xd8, 0xf9, 0x9c, 0xbf, 0xcc, 0x6a, 0x1c, 0xf8, + 0x5b, 0x59, 0xa9, 0x59, 0xdc, 0xc6, 0x7e, 0xb5, 0x1d, 0x87, 0x3e, 0xe2, 0x67, 0x51, 0x8d, 0x49, + 0x1e, 0x43, 0x0d, 0x22, 0xbe, 0x96, 0x5e, 0xec, 0x4d, 0xaf, 0xf5, 0xfe, 0x9b, 0x95, 0x42, 0xf4, + 0x2f, 0x2d, 0x89, 0x6c, 0x0f, 0x59, 0xe1, 0x36, 0x3d, 0x7e, 0xae, 0xf0, 0xda, 0x40, 0x2f, 0x01, + 0x90, 0x15, 0x69, 0x90, 0x7f, 0xf4, 0xd7, 0x2a, 0x1d, 0x7c, 0x67, 0x24, 0x07, 0xc0, 0x3a, 0xba, + 0x02, 0x40, 0x81, 0x59, 0xae, 0xa4, 0x80, 0xb0, 0xd4, 0x1f, 0x71, 0x91, 0xd2, 0x2d, 0xbb, 0x21, + 0xc7, 0xd4, 0xee, 0x9f, 0x9a, 0x3a, 0x5b, 0x20, 0x82, 0x5d, 0xc1, 0x8a, 0x2c, 0xec, 0x9f, 0x5a, + 0xf6, 0xdd, 0x5d, 0x7c, 0x19, 0x77, 0x11, 0x2a, 0xa8, 0xb9, 0x21, 0xdd, 0x18, 0x6f, 0x3b, 0xd8, + 0xb9, 0xd4, 0x47, 0xa3, 0xa4, 0x55, 0xaa, 0x21, 0xff, 0x43, 0xef, 0xe6, 0x2c, 0x87, 0xec, 0x8f, + 0xa0, 0x88, 0xa8, 0x7e, 0x15, 0x31, 0xd4, 0xdc, 0x70, 0xe0, 0xa9, 0x6f, 0xb1, 0x95, 0xb4, 0x6a, + 0x05, 0x47, 0xde, 0x76, 0x2e, 0x85, 0x30, 0xa5, 0x32, 0xd0, 0x1e, 0xcd, 0x2d, 0xbe, 0x3b, 0xdc, + 0xf2, 0x63, 0xb2, 0xe1, 0xda, 0x84, 0x4e, 0x21, 0xf6, 0x72, 0x98, 0xac, 0xa2, 0x24, 0x5b, 0xd8, + 0x50, 0x59, 0xde, 0xf6, 0xcf, 0x1f, 0x83, 0xc1, 0x55, 0xd0, 0xf6, 0x63, 0xe5, 0x39, 0x0a, 0xfd, + 0xc4, 0x34, 0xc0, 0x13, 0x99, 0x76, 0xda, 0x0a, 0xf9, 0x43, 0xb7, 0x3b, 0xf6, 0x06, 0x43, 0xc4, + 0xbc, 0x35, 0xda, 0xe9, 0x6b, 0x9e, 0x18, 0x24, 0xdb, 0xdb, 0xa9, 0x53, 0x6a, 0x12, 0x42, 0x48, + 0x36, 0xcf, 0x64, 0x32, 0xd3, 0xea, 0x0b, 0x3b, 0xba, 0x2a, 0xeb, 0xc7, 0x2a, 0xfd, 0x59, 0x9e, + 0x76, 0xfb, 0x72, 0xfa, 0xd9, 0xa3, 0xb5, 0xfe, 0xd6, 0x73, 0x4f, 0xb6, 0x56, 0x9f, 0xcb, 0xba, + 0x4d, 0x2d, 0x5f, 0x94, 0x7a, 0xa9, 0x39, 0xed, 0xac, 0x66, 0x06, 0x3e, 0x9d, 0xf0, 0xa5, 0x4d, + 0xcd, 0xf7, 0x34, 0x56, 0x9d, 0x70, 0xd1, 0x18, 0x55, 0xe7, 0x60, 0x95, 0xa6, 0x64, 0xcb, 0x9e, + 0x57, 0xb6, 0x15, 0x32, 0xbb, 0x90, 0x64, 0xbe, 0xcd, 0x80, 0xa5, 0x0a, 0xc7, 0x54, 0x1f, 0x74, + 0x12, 0xd3, 0x64, 0xe9, 0x3d, 0xd7, 0xf1, 0x6a, 0xeb, 0x61, 0x5a, 0xd0, 0x57, 0x03, 0x89, 0xa7, + 0x37, 0x49, 0xeb, 0x72, 0xef, 0xec, 0xa6, 0x5f, 0xf0, 0xc7, 0x24, 0x78, 0x21, 0x6a, 0x60, 0xa8, + 0x27, 0x1a, 0x1f, 0xb2, 0xf2, 0x83, 0xf1, 0xf7, 0x88, 0x43, 0xe3, 0xa2, 0x73, 0xb1, 0x61, 0xba, + 0xd3, 0x2f, 0x4b, 0x12, 0x95, 0x29, 0x91, 0x45, 0x7c, 0x7e, 0xc1, 0x5f, 0x9b, 0xf8, 0x06, 0x5a, + 0x79, 0x35, 0x83, 0xc6, 0x1b, 0x22, 0xed, 0x17, 0xf8, 0x09, 0x5d, 0x08, 0x27, 0x7c, 0x27, 0x6f, + 0x93, 0xb2, 0xb7, 0xdc, 0x21, 0xdf, 0xe3, 0x1e, 0x4d, 0x48, 0x1b, 0x51, 0xcc, 0x75, 0x35, 0x31, + 0x04, 0x0a, 0x1a, 0xa1, 0x18, 0x5b, 0xaf, 0x05, 0xaa, 0xe5, 0x89, 0x69, 0x3d, 0x55, 0x27, 0x2d, + 0xc7, 0xeb, 0xfe, 0xca, 0xac, 0x38, 0xd5, 0xdb, 0x5d, 0x34, 0x23, 0x5f, 0x93, 0xe6, 0x3e, 0x33, + 0xc5, 0xb1, 0xf4, 0x62, 0x3d, 0xb9, 0x01, 0x91, 0x2f, 0xcc, 0xf2, 0xca, 0x10, 0x99, 0x2c, 0x28, + 0x7d, 0x6b, 0x03, 0xf3, 0xe3, 0xe8, 0x34, 0xe5, 0xa0, 0xb4, 0x5b, 0x7d, 0x50, 0x4f, 0xaa, 0xd3, + 0xb9, 0x1e, 0x1c, 0xd9, 0xbd, 0x92, 0x99, 0x3b, 0xf4, 0xf5, 0xe3, 0x51, 0xeb, 0xc7, 0x3a, 0x3b, + 0xec, 0x27, 0xa6, 0x85, 0x22, 0x2a, 0xb0, 0x46, 0x94, 0x0f, 0x54, 0x83, 0xb0, 0xf9, 0x4f, 0x94, + 0x4e, 0x2b, 0xb6, 0xcb, 0x6d, 0x55, 0xcd, 0x79, 0x8f, 0x95, 0x88, 0x40, 0xb4, 0xff, 0x4d, 0x13, + 0x36, 0x91, 0x2b, 0x5a, 0xbe, 0x8a, 0x99, 0xc9, 0x29, 0xba, 0x13, 0xd4, 0x4c, 0xca, 0x88, 0x12, + 0x05, 0xf6, 0x64, 0x94, 0x84, 0xd4, 0xa0, 0x17, 0x80, 0x4f, 0xa7, 0x7d, 0x2d, 0x51, 0xce, 0x5e, + 0xbc, 0x04, 0xc4, 0x3b, 0x33, 0x58, 0x94, 0x54, 0x53, 0x73, 0xc2, 0x1d, 0xea, 0x9b, 0xfa, 0xe2, + 0x94, 0x88, 0xe7, 0x2e, 0x4e, 0x08, 0x36, 0x26, 0x3a, 0x25, 0xec, 0x20, 0x48, 0x6e, 0xb6, 0xbe, + 0x7a, 0x9f, 0xba, 0x97, 0x2b, 0x17, 0x3e, 0x8c, 0xe5, 0xe0, 0x6d, 0x69, 0x6d, 0x9d, 0x44, 0x10, + 0x9d, 0xcb, 0x75, 0xef, 0x93, 0x86, 0x02, 0x53, 0xe8, 0xcc, 0x8d, 0x2f, 0xd0, 0xdf, 0x93, 0xda, + 0x61, 0x10, 0x0b, 0x5f, 0x16, 0x18, 0x57, 0x70, 0xbf, 0xca, 0x30, 0xa4, 0xdc, 0xd6, 0xee, 0x4d, + 0xeb, 0xa0, 0x70, 0x8d, 0x9c, 0xce, 0x6c, 0x5e, 0xac, 0x16, 0xff, 0xf8, 0xee, 0x11, 0xae, 0x1c, + 0xbb, 0x8e, 0x7a, 0x3a, 0xd9, 0x5d, 0x2d, 0x7b, 0x69, 0x12, 0x33, 0x41, 0xcd, 0xc5, 0x59, 0xe8, + 0x2a, 0x7f, 0x71, 0x5a, 0xb3, 0x29, 0xe5, 0x64, 0xef, 0x75, 0xec, 0x33, 0x41, 0x99, 0x8a, 0x2c, + 0x82, 0xad, 0x18, 0x70, 0x0d, 0x82, 0x02, 0xc5, 0x32, 0x54, 0xce, 0xd6, 0x4d, 0x4d, 0xa0, 0x74, + 0x35, 0xf6, 0xaf, 0x13, 0xb0, 0x9c, 0x02, 0x28, 0xb1, 0xf7, 0x3e, 0xac, 0x5b, 0xff, 0x88, 0x00, + 0x57, 0x67, 0xa4, 0x8a, 0x58, 0x39, 0xea, 0x7f, 0x5b, 0x92, 0x6e, 0xd7, 0xd7, 0xde, 0x56, 0xf7, + 0x99, 0x95, 0x64, 0x17, 0x74, 0xdd, 0x76, 0xe0, 0x03, 0x17, 0x86, 0xbf, 0xca, 0x51, 0x36, 0x47, + 0x7d, 0x76, 0x82, 0x71, 0x66, 0x85, 0xb6, 0x2a, 0x41, 0x9a, 0xc9, 0xaf, 0xc3, 0x82, 0x72, 0x8f, + 0x61, 0xc1, 0x00, 0xaa, 0x92, 0x88, 0xcc, 0xa5, 0x17, 0x40, 0x6d, 0x19, 0xb1, 0x7e, 0xac, 0x1d, + 0x25, 0x7f, 0x62, 0x9a, 0xc3, 0xfb, 0x08, 0x2d, 0x2c, 0x00, 0x8c, 0x75, 0x72, 0x1a, 0x7f, 0xf0, + 0xe3, 0xc7, 0x00, 0x86, 0xfd, 0x9b, 0x7a, 0xde, 0x0d, 0x0d, 0xd8, 0x9b, 0x12, 0x68, 0x6a, 0x1e, + 0xf2, 0xa1, 0x38, 0x66, 0x12, 0x23, 0x33, 0xb4, 0xee, 0x19, 0x2f, 0xef, 0x06, 0x8e, 0x4e, 0x5b, + 0x00, 0x09, 0x1e, 0xe3, 0x89, 0x2a, 0x73, 0x4e, 0x2a, 0x75, 0x08, 0x5c, 0xe1, 0x17, 0x6f, 0x4a, + 0xad, 0xd5, 0x2a, 0xed, 0x68, 0xbd, 0x81, 0xa6, 0xc3, 0xa4, 0x48, 0x63, 0xc3, 0x9b, 0x80, 0x38, + 0x4e, 0xc9, 0x39, 0xe2, 0x9b, 0x13, 0x54, 0x83, 0xc3, 0x7e, 0x95, 0x28, 0xc6, 0x6c, 0xd0, 0x70, + 0x0e, 0x99, 0x97, 0x4a, 0x4c, 0x9b, 0x2d, 0x01, 0x50, 0x85, 0x16, 0xa6, 0xa4, 0xe0, 0x1d, 0x89, + 0x8a, 0x72, 0x88, 0x7a, 0x46, 0x2d, 0x6e, 0xa1, 0x78, 0xe4, 0x23, 0x88, 0xa1, 0xf3, 0xe2, 0x33, + 0x74, 0x46, 0x0b, 0x45, 0x29, 0x0e, 0xa6, 0x45, 0xe6, 0xf0, 0xc4, 0x0d, 0xc2, 0x9e, 0xa1, 0xc5, + 0x55, 0x2f, 0x91, 0xf0, 0x5a, 0xc2, 0x8d, 0x0a, 0x88, 0x87, 0x16, 0xe6, 0xc5, 0x3e, 0x44, 0x28, + 0x05, 0x9d, 0x23, 0xd6, 0x3c, 0xac, 0xc2, 0xfe, 0x79, 0xef, 0xff, 0xfb, 0x42, 0x6a, 0x75, 0x4f, + 0x10, 0xe7, 0x9f, 0xbf, 0x54, 0x5f, 0x60, 0xf8, 0xe3, 0xfb, 0xc5, 0x05, 0x3e, 0x4c, 0x25, 0xc2, + 0x5d, 0x01, 0xe9, 0x6a, 0x97, 0x0e, 0x48, 0xa5, 0xdd, 0xf3, 0x97, 0x90, 0x50, 0x74, 0xfe, 0xf1, + 0x36, 0x70, 0x67, 0xf4, 0xed, 0x1a, 0x06, 0x47, 0x5b, 0x5a, 0xd0, 0xf8, 0xff, 0x7d, 0x90, 0x0b, + 0xfb, 0xf8, 0xa0, 0xfb, 0x93, 0xb4, 0xd4, 0x5f, 0x18, 0xcd, 0x76, 0x4c, 0x62, 0x2c, 0x0b, 0x8b, + 0x5f, 0x31, 0xf6, 0x3f, 0x1d, 0x63, 0xd8, 0x40, 0x95, 0x31, 0x48, 0xe1, 0xee, 0x3f, 0xdf, 0xde, + 0xab, 0x3a, 0xa1, 0x45, 0x25, 0xf1, 0xff, 0xa4, 0x3c, 0xe1, 0x46, 0x18, 0x9b, 0x75, 0x06, 0x5a, + 0x3f, 0xf6, 0x5c, 0xc9, 0xfe, 0xc4, 0x34, 0x57, 0x63, 0x54, 0xa6, 0xa7, 0x07, 0x82, 0xb4, 0x3b, + 0x67, 0x84, 0x6e, 0xcb, 0xb3, 0x32, 0xdb, 0x51, 0x2f, 0xc9, 0x35, 0x42, 0xec, 0x4d, 0xd0, 0xb8, + 0xc1, 0xe0, 0x00, 0x02, 0x13, 0xe1, 0x47, 0x90, 0x9c, 0xa6, 0x0d, 0x9a, 0xa6, 0x27, 0xc4, 0x7e, + 0x2a, 0x10, 0xba, 0xdc, 0xe5, 0x63, 0x8b, 0xbd, 0x0f, 0xa2, 0x9b, 0x55, 0x70, 0xcd, 0x95, 0x66, + 0xcd, 0x29, 0x4f, 0x32, 0x14, 0xf9, 0x58, 0x4c, 0x2b, 0xd4, 0xeb, 0xc8, 0x2f, 0x28, 0x41, 0x25, + 0x4e, 0x83, 0x8c, 0xf3, 0x26, 0xa4, 0x8b, 0x3e, 0x36, 0xa1, 0x37, 0xbc, 0x07, 0x86, 0x48, 0x9d, + 0xec, 0x04, 0x93, 0xa6, 0xe3, 0x91, 0x80, 0x3d, 0xc7, 0x33, 0x1b, 0x76, 0xe9, 0x33, 0x37, 0xb1, + 0x9a, 0xd3, 0x96, 0x82, 0xb4, 0x41, 0xe7, 0x0e, 0x56, 0x0c, 0x67, 0x2e, 0x32, 0x41, 0x2b, 0xcb, + 0x1b, 0x09, 0x2a, 0x1f, 0xdb, 0xc9, 0x49, 0x61, 0x08, 0x81, 0x20, 0x70, 0x74, 0x87, 0xd9, 0x00, + 0xf8, 0x26, 0xaf, 0x13, 0xb8, 0x6f, 0x28, 0x1d, 0xef, 0xee, 0x2c, 0xce, 0x13, 0x9e, 0x9c, 0xe1, + 0x02, 0x12, 0x44, 0x9b, 0xf3, 0xe0, 0xcd, 0xc8, 0x2c, 0x81, 0x6f, 0x98, 0x05, 0xa3, 0xfc, 0x04, + 0x19, 0xed, 0x2b, 0x36, 0x42, 0x7c, 0x9e, 0x4c, 0x45, 0xb0, 0x61, 0x89, 0x0b, 0x51, 0x6b, 0x64, + 0xe5, 0x85, 0x8c, 0xfc, 0xb9, 0xec, 0x42, 0xed, 0x7f, 0x94, 0xcf, 0x3a, 0x76, 0x9e, 0xe4, 0x2c, + 0x03, 0xf2, 0x54, 0xbf, 0xbc, 0x82, 0x00, 0xba, 0xcc, 0x44, 0xb5, 0x6f, 0xd5, 0x10, 0xc1, 0x3f, + 0x88, 0x18, 0xf6, 0xbb, 0xe1, 0x80, 0x39, 0xc7, 0x3b, 0x2f, 0xf3, 0xd8, 0x12, 0xc3, 0x5c, 0x30, + 0x6a, 0x69, 0x8a, 0xdf, 0x3e, 0x32, 0x2e, 0xf5, 0xb7, 0x25, 0x5d, 0x6f, 0x97, 0x35, 0xe6, 0x8f, + 0x03, 0x1c, 0xfe, 0x41, 0x19, 0x55, 0xd9, 0x41, 0x27, 0x4a, 0xf5, 0xd6, 0x25, 0xcc, 0x0a, 0xee, + 0x70, 0x65, 0x06, 0xef, 0xe7, 0x27, 0xd4, 0x9c, 0xc6, 0xe5, 0x51, 0x0b, 0x44, 0x40, 0xe2, 0x47, + 0xd3, 0xaa, 0xfc, 0xbf, 0x9a, 0xbe, 0x41, 0x76, 0x97, 0xfe, 0x2a, 0x64, 0x5a, 0xaf, 0x16, 0x9f, + 0x32, 0xff, 0xe4, 0x83, 0x94, 0xe8, 0xea, 0x45, 0xec, 0xf7, 0xf8, 0x3e, 0xa5, 0x95, 0xc6, 0x21, + 0xb2, 0x10, 0x6c, 0x63, 0xfb, 0xce, 0x6e, 0x5e, 0x5d, 0x7c, 0x5f, 0x2e, 0xa5, 0x75, 0xa5, 0xb7, + 0x4c, 0x65, 0xfc, 0xea, 0xa5, 0x80, 0xaa, 0xac, 0x4a, 0x29, 0x35, 0x68, 0xb9, 0xc9, 0xb7, 0x68, + 0x3b, 0xeb, 0x71, 0x4b, 0x90, 0x59, 0x9f, 0xdf, 0x6e, 0xa0, 0x2f, 0x93, 0xc8, 0x46, 0xef, 0xe2, + 0xd7, 0x14, 0xa9, 0x19, 0x19, 0xed, 0xa8, 0xb4, 0xc2, 0xf7, 0x6f, 0x62, 0x25, 0xdc, 0x23, 0x41, + 0xc2, 0x22, 0xbd, 0x89, 0x95, 0x77, 0xfc, 0x81, 0x6e, 0x87, 0x96, 0x6e, 0x12, 0xd5, 0xa1, 0x0e, + 0x7c, 0xff, 0x93, 0xf3, 0x1b, 0x68, 0x3c, 0x9c, 0x53, 0xfb, 0xc2, 0x87, 0x92, 0x92, 0x9f, 0x40, + 0xbe, 0x92, 0xd0, 0xb8, 0xb3, 0x14, 0xd7, 0xd6, 0xa5, 0x73, 0x92, 0x9c, 0xfc, 0xcf, 0xaf, 0x9d, + 0xc7, 0x88, 0x4a, 0x8f, 0x1f, 0xb7, 0xa7, 0x93, 0xb0, 0xcd, 0x46, 0x24, 0x2a, 0x57, 0xdb, 0xdf, + 0xaf, 0xba, 0x7e, 0xa6, 0xd1, 0xd4, 0x08, 0xf6, 0x3c, 0xac, 0xdc, 0xda, 0xd0, 0x95, 0xcf, 0x14, + 0x82, 0x75, 0x42, 0x6d, 0x79, 0x38, 0x8a, 0xcb, 0x23, 0xd1, 0xf0, 0xcb, 0xee, 0xf5, 0x11, 0x31, + 0x33, 0xeb, 0x4d, 0x31, 0xed, 0xbc, 0xf1, 0xf4, 0x15, 0x9d, 0x19, 0xc7, 0x90, 0xa9, 0x46, 0x24, + 0x1d, 0x6a, 0x68, 0xe2, 0x2a, 0x4d, 0x30, 0x7f, 0x5c, 0x08, 0x0e, 0x73, 0x00, 0xb1, 0xb4, 0x5c, + 0x37, 0x9e, 0x3e, 0x63, 0x33, 0xa3, 0x90, 0x86, 0x11, 0xf5, 0x06, 0x23, 0x45, 0xb2, 0x64, 0x62, + 0xae, 0xa7, 0x65, 0x14, 0x13, 0xc1, 0xbd, 0x44, 0x52, 0x3d, 0x27, 0x23, 0xe8, 0x55, 0x89, 0xfc, + 0xf5, 0x64, 0x0c, 0x74, 0x0f, 0x2a, 0xf3, 0xf8, 0xb5, 0x6a, 0x1f, 0x4b, 0xc9, 0x08, 0x72, 0x53, + 0xf6, 0x4f, 0xef, 0x23, 0xa9, 0xb2, 0x78, 0x1b, 0xca, 0x3a, 0xdd, 0x95, 0x54, 0xa7, 0xf4, 0x91, + 0x5c, 0xf1, 0x4a, 0xeb, 0x3f, 0xd6, 0x43, 0x53, 0xc9, 0x9f, 0x8c, 0x69, 0x85, 0x54, 0x69, 0xaa, + 0x74, 0xd4, 0xda, 0x33, 0x57, 0xca, 0x0c, 0x7b, 0xd0, 0x05, 0xb9, 0xd1, 0xe4, 0xf9, 0x52, 0xbc, + 0x7c, 0xc4, 0xb1, 0xa4, 0x37, 0x8e, 0x0e, 0xa4, 0xce, 0x18, 0x53, 0xc1, 0xe1, 0x41, 0x0b, 0x35, + 0xd9, 0x54, 0x94, 0x55, 0x2f, 0x73, 0x7b, 0x80, 0x61, 0x42, 0xc7, 0xdd, 0x2d, 0x8b, 0x8a, 0x96, + 0x4e, 0x32, 0x9a, 0xc2, 0xb2, 0xc3, 0x5e, 0xf8, 0x0d, 0xb8, 0xd4, 0xde, 0x1d, 0x6e, 0x62, 0xd7, + 0x7b, 0x9d, 0xd9, 0x2c, 0xf4, 0xd4, 0x54, 0x58, 0x99, 0xda, 0x76, 0x8e, 0x37, 0xf4, 0x58, 0xd3, + 0x97, 0x8a, 0x47, 0x32, 0x51, 0xb5, 0x3d, 0x44, 0x2c, 0x5a, 0x1c, 0x49, 0x5a, 0x80, 0x35, 0x9f, + 0x8f, 0xc0, 0x73, 0xa9, 0x4e, 0x4e, 0xdb, 0x3c, 0x47, 0x84, 0xe1, 0xed, 0xb3, 0x9b, 0x2a, 0x6e, + 0xda, 0x68, 0x71, 0xd4, 0xfe, 0xc7, 0xd0, 0x34, 0x5f, 0xab, 0xec, 0xe6, 0xad, 0x48, 0x6b, 0x5e, + 0xad, 0xf6, 0xf7, 0x5d, 0x04, 0x97, 0x84, 0xb6, 0x82, 0xa3, 0x6b, 0xed, 0x66, 0xf6, 0xea, 0x71, + 0xeb, 0x36, 0x52, 0x30, 0xae, 0xb5, 0xb5, 0xdc, 0xb0, 0xe2, 0x4b, 0x8e, 0x14, 0x24, 0xb6, 0x09, + 0x1c, 0x16, 0x21, 0x9a, 0xde, 0x13, 0x5d, 0x16, 0xe4, 0x7d, 0x88, 0x63, 0x26, 0x5a, 0x3d, 0x58, + 0xa1, 0xde, 0x18, 0x2f, 0x89, 0xfd, 0x76, 0x05, 0x55, 0xda, 0x79, 0xb7, 0x67, 0xad, 0xb7, 0xa8, + 0xd1, 0xcd, 0x85, 0x38, 0x12, 0x4f, 0x60, 0x3e, 0x67, 0x1e, 0x24, 0xd4, 0xc0, 0x53, 0x60, 0x8b, + 0xd5, 0x55, 0xb6, 0x17, 0x96, 0x61, 0x5b, 0x39, 0x59, 0xe9, 0xe1, 0xfe, 0xa3, 0xc6, 0x1b, 0x44, + 0x9f, 0x75, 0x44, 0xd0, 0x06, 0x22, 0x77, 0x58, 0x35, 0xdd, 0x96, 0xe8, 0xe0, 0x86, 0x4a, 0x4e, + 0x2b, 0x64, 0x68, 0x23, 0x2f, 0x44, 0x16, 0x31, 0xb3, 0x11, 0xfd, 0x82, 0x39, 0xb4, 0xc6, 0xc4, + 0x6a, 0x6c, 0x70, 0x4a, 0xc9, 0xb9, 0x4a, 0x68, 0x21, 0x6e, 0xd3, 0x56, 0x6b, 0xca, 0xea, 0x41, + 0x51, 0x56, 0xb5, 0xfd, 0x85, 0xfe, 0x1f, 0x3c, 0xaf, 0x4f, 0x3c, 0x62, 0xff, 0xe4, 0x1a, 0x7e, + 0x59, 0xdd, 0x1e, 0xe0, 0x63, 0x8d, 0x6c, 0xa3, 0x6e, 0xb7, 0xd4, 0xee, 0xd2, 0xd2, 0x62, 0xee, + 0xe8, 0x19, 0x97, 0x17, 0x3d, 0xaa, 0x96, 0xae, 0x7a, 0x74, 0x8e, 0x15, 0x01, 0x34, 0x60, 0x5d, + 0xec, 0xbb, 0xce, 0xca, 0xd3, 0x8f, 0xc8, 0x2e, 0xcb, 0xa2, 0x28, 0xdf, 0x0c, 0x72, 0xda, 0x5a, + 0x13, 0xce, 0x1d, 0x9b, 0x54, 0x02, 0xa9, 0x05, 0x22, 0x55, 0x39, 0xd8, 0xb7, 0x33, 0xe6, 0x83, + 0x2d, 0xd6, 0x56, 0xb2, 0xf0, 0xd8, 0xd7, 0x67, 0xaa, 0x1e, 0x9f, 0x9d, 0x67, 0x3c, 0x23, 0x65, + 0x70, 0x7d, 0xe2, 0xb3, 0xd4, 0x9f, 0x0e, 0x2c, 0x59, 0x9b, 0x24, 0xb1, 0xa0, 0x53, 0x3e, 0x6e, + 0x6d, 0x41, 0x8b, 0x7f, 0xb5, 0x2a, 0xd7, 0x9c, 0x9a, 0xbb, 0xbc, 0xbc, 0x6a, 0x35, 0xa1, 0xfd, + 0xc7, 0xde, 0x19, 0x12, 0xbc, 0xfa, 0xf3, 0xf8, 0x7c, 0xac, 0x79, 0x3e, 0xa7, 0xab, 0xc5, 0x04, + 0x98, 0x80, 0x14, 0x05, 0xb0, 0x44, 0x8e, 0xaa, 0xf4, 0x1c, 0x5e, 0x35, 0xad, 0x95, 0x68, 0x7b, + 0xb8, 0x44, 0x2d, 0xef, 0x17, 0x8c, 0x3e, 0x2a, 0x96, 0x40, 0x92, 0x76, 0xc1, 0x1f, 0xe5, 0x85, + 0xa0, 0xae, 0xe4, 0x2c, 0xd3, 0xb6, 0xd2, 0x49, 0x72, 0x45, 0x0e, 0xee, 0xf9, 0xcd, 0xbf, 0x21, + 0xde, 0xb3, 0xc1, 0xdf, 0x25, 0x67, 0xe7, 0x23, 0xb3, 0x36, 0xdc, 0xa1, 0x3d, 0xa7, 0xe8, 0xf7, + 0x57, 0x59, 0xef, 0xa0, 0xf7, 0x32, 0x07, 0x1e, 0x70, 0x2c, 0x1a, 0x7a, 0xa7, 0x94, 0x4c, 0x2b, + 0xee, 0xfc, 0x8b, 0x46, 0x3d, 0xc9, 0xbe, 0xd7, 0x03, 0x5b, 0xb3, 0x6c, 0x61, 0x51, 0xf3, 0xde, + 0x2c, 0xe8, 0x37, 0x3b, 0x58, 0xde, 0xb8, 0x56, 0x49, 0xbe, 0x79, 0x5d, 0x9e, 0x9c, 0x1d, 0x08, + 0x25, 0xb3, 0x16, 0x63, 0xbb, 0x33, 0x18, 0x1b, 0xa3, 0xed, 0x59, 0xab, 0xeb, 0xe4, 0xb0, 0x33, + 0x7d, 0x1c, 0x1a, 0xf4, 0x75, 0xf2, 0xd0, 0xd2, 0xfc, 0xb5, 0x33, 0x74, 0x68, 0x15, 0x78, 0xc0, + 0xb4, 0x35, 0xe5, 0xa4, 0x4e, 0xae, 0x97, 0x5d, 0xb7, 0x77, 0x39, 0x8d, 0xe9, 0xe6, 0xc7, 0xf3, + 0x9e, 0x5b, 0xb3, 0x3f, 0x31, 0xad, 0x5a, 0x49, 0x05, 0x29, 0x95, 0xf0, 0xb9, 0xd0, 0x92, 0x9b, + 0x78, 0xa3, 0x6f, 0x1f, 0x73, 0x4a, 0x20, 0xa4, 0xeb, 0xba, 0xb7, 0xe0, 0x7b, 0xdd, 0x91, 0xf3, + 0x14, 0x83, 0x47, 0xc8, 0x51, 0xad, 0xe2, 0x87, 0x7d, 0x2a, 0x91, 0xe9, 0x34, 0x20, 0x95, 0xfd, + 0xf1, 0xb6, 0xd9, 0xc2, 0x73, 0xb1, 0x64, 0x50, 0xe0, 0xa4, 0x91, 0x2f, 0x78, 0xf1, 0x11, 0xe3, + 0x1b, 0xad, 0x70, 0x62, 0x55, 0x24, 0x07, 0x3d, 0x40, 0x25, 0xbd, 0x31, 0xe4, 0x72, 0x44, 0xd5, + 0x96, 0x41, 0x08, 0xd7, 0x90, 0x25, 0x8d, 0xf8, 0xb6, 0x5c, 0x4d, 0x5f, 0x3d, 0x19, 0xb4, 0xcb, + 0x7a, 0x18, 0x55, 0x84, 0xbd, 0x76, 0x49, 0x9b, 0xbb, 0x76, 0x94, 0x5e, 0xd9, 0x55, 0x98, 0x6f, + 0xeb, 0xa6, 0xb8, 0xae, 0x0c, 0x9b, 0xba, 0x74, 0x6d, 0x3a, 0x7b, 0x89, 0x84, 0x54, 0xc0, 0x15, + 0x14, 0x61, 0x2d, 0xc7, 0x4a, 0x7e, 0x2d, 0x3b, 0x56, 0xf6, 0xb3, 0xea, 0xa0, 0x7f, 0x7b, 0xa4, + 0xb0, 0x6c, 0x20, 0x15, 0x99, 0x28, 0xe6, 0xee, 0x29, 0xc4, 0x2e, 0x04, 0x07, 0xbc, 0xa2, 0xfe, + 0x0c, 0xbf, 0x7a, 0xd4, 0xe9, 0xee, 0xdf, 0x52, 0xfd, 0x95, 0xc5, 0x34, 0x58, 0xc9, 0x3c, 0x66, + 0x22, 0x5b, 0x7c, 0xa0, 0xe6, 0x61, 0x16, 0x6d, 0x5e, 0x67, 0x68, 0x1a, 0x90, 0xb9, 0x10, 0x0e, + 0x08, 0x16, 0x06, 0xc9, 0xc5, 0x5e, 0xdd, 0xb7, 0xa5, 0xed, 0xc5, 0x8e, 0x49, 0x60, 0xed, 0xa1, + 0x44, 0xbd, 0x8a, 0x1f, 0xfe, 0x4e, 0xce, 0xf7, 0x42, 0xb7, 0x17, 0xdc, 0x1e, 0xa3, 0x8f, 0xe0, + 0xe2, 0x3b, 0xf4, 0x8a, 0x06, 0x45, 0x81, 0x19, 0xd9, 0x59, 0x37, 0xa4, 0x37, 0xb9, 0xdd, 0x11, + 0x4b, 0x5c, 0x07, 0x66, 0x70, 0xa5, 0xd6, 0x91, 0xb0, 0xce, 0x3c, 0x78, 0xdd, 0x69, 0x7c, 0xad, + 0x6c, 0xce, 0x82, 0xce, 0x13, 0xef, 0x08, 0xc3, 0x7d, 0xc9, 0x90, 0x46, 0x67, 0x45, 0xaf, 0xf0, + 0xb4, 0x2a, 0xa4, 0x87, 0xcf, 0xa2, 0x8d, 0xca, 0x7c, 0xbf, 0x15, 0xd2, 0x54, 0x41, 0xc5, 0x8f, + 0xfb, 0xe9, 0xcc, 0xab, 0x3f, 0x31, 0xad, 0xe6, 0x75, 0x5d, 0xef, 0xab, 0x80, 0xf0, 0xa8, 0x85, + 0xd9, 0x4d, 0x37, 0xfd, 0xcc, 0x15, 0xe4, 0x47, 0x84, 0x16, 0xf0, 0xf6, 0xf4, 0xfe, 0x5a, 0x4e, + 0xdd, 0x64, 0x8a, 0x12, 0xd3, 0xd7, 0xc6, 0xd5, 0x47, 0xf4, 0x4b, 0xe5, 0xfe, 0x75, 0xc3, 0xbc, + 0x67, 0x56, 0x22, 0x02, 0xbb, 0xe8, 0xac, 0x52, 0x8c, 0x32, 0xab, 0x0d, 0x71, 0x98, 0xe2, 0x2d, + 0x8a, 0x13, 0x0c, 0xaf, 0x2c, 0xf6, 0x2c, 0xf0, 0x0b, 0xe2, 0x41, 0x4b, 0x28, 0x15, 0x7f, 0x47, + 0xf9, 0x76, 0x51, 0x00, 0x5d, 0x59, 0x11, 0xd1, 0xac, 0x65, 0xbe, 0x68, 0x48, 0x71, 0x33, 0xa2, + 0x96, 0x59, 0x3a, 0x0f, 0x9d, 0x23, 0xd2, 0x1e, 0xf4, 0x31, 0x97, 0x58, 0x41, 0x4b, 0xeb, 0x8b, + 0x15, 0x96, 0xb5, 0x54, 0x13, 0x18, 0x1f, 0x69, 0x67, 0xe1, 0x7a, 0x6b, 0x41, 0x2a, 0xb1, 0xa1, + 0x56, 0x91, 0xe4, 0x80, 0x05, 0x37, 0x46, 0x26, 0x3b, 0xa5, 0x4d, 0x78, 0x7e, 0x41, 0x4d, 0x0c, + 0x3c, 0xd4, 0x19, 0x8e, 0x25, 0x7b, 0x94, 0x7a, 0xad, 0x4c, 0xce, 0xda, 0xcd, 0x1e, 0x86, 0x63, + 0xee, 0x6d, 0x84, 0x71, 0xb0, 0xb7, 0xd1, 0xc2, 0x25, 0x7f, 0xa2, 0xc7, 0x55, 0xf9, 0x39, 0xda, + 0x09, 0x6a, 0x91, 0x60, 0x1b, 0xb0, 0xf2, 0xb6, 0xd0, 0x2f, 0xfb, 0xd5, 0x35, 0x9a, 0x7d, 0x5d, + 0x55, 0x1c, 0xb2, 0x1b, 0xb5, 0xf5, 0xd9, 0x85, 0xc9, 0xd3, 0x71, 0x0d, 0x2f, 0x98, 0xb6, 0x5d, + 0xa9, 0x86, 0x4c, 0x3f, 0xc2, 0xfb, 0xa9, 0x83, 0x25, 0xf6, 0x4a, 0x2a, 0xb6, 0x34, 0x33, 0x9b, + 0xda, 0x99, 0x84, 0x20, 0x8d, 0x35, 0xc0, 0x0e, 0xe7, 0xf4, 0x54, 0x4f, 0x33, 0xdc, 0x8c, 0x68, + 0x00, 0x5c, 0xd5, 0x1d, 0x01, 0xb6, 0xd2, 0x68, 0x9a, 0x77, 0xd0, 0xf2, 0x10, 0xb9, 0x58, 0x1f, + 0x99, 0x05, 0x45, 0x44, 0x77, 0x9c, 0x06, 0x11, 0xb3, 0x7d, 0x75, 0x20, 0x3e, 0x0b, 0xd7, 0x4b, + 0xd6, 0x1f, 0x4d, 0xab, 0xf8, 0x3f, 0x31, 0x6d, 0x10, 0x81, 0xc8, 0x46, 0xc8, 0x22, 0x7b, 0x3c, + 0xbb, 0xaa, 0x00, 0x0f, 0x68, 0x2d, 0x76, 0x76, 0x14, 0xf9, 0xd2, 0x93, 0xdd, 0x13, 0xac, 0x69, + 0x4d, 0x08, 0xfb, 0xa2, 0x51, 0x1c, 0xb0, 0x80, 0x7d, 0x7e, 0x4b, 0x91, 0x35, 0x3d, 0xc9, 0x0d, + 0xd2, 0x44, 0x59, 0xd9, 0xca, 0xa9, 0x45, 0x1b, 0x04, 0x3d, 0xb8, 0xf5, 0xde, 0x61, 0x92, 0xbc, + 0x61, 0x85, 0xc5, 0x7f, 0x3c, 0xc3, 0x72, 0x38, 0x40, 0x4c, 0xad, 0x1a, 0x53, 0xd0, 0xcc, 0xb4, + 0xee, 0x8f, 0x26, 0x2a, 0x64, 0x1e, 0xea, 0x27, 0x98, 0x28, 0xef, 0xc5, 0x4a, 0x57, 0xe2, 0x6e, + 0x25, 0x94, 0x1b, 0x39, 0x54, 0x5f, 0x5e, 0xc2, 0x3e, 0x84, 0xc8, 0x65, 0x24, 0x77, 0x5d, 0xa0, + 0x74, 0x57, 0xdf, 0xca, 0x30, 0x25, 0x54, 0x89, 0x7b, 0x3f, 0xd2, 0xb2, 0x30, 0x18, 0x75, 0x63, + 0xda, 0x1c, 0x48, 0x01, 0x7f, 0xf3, 0xc5, 0xa9, 0x97, 0x69, 0x52, 0x16, 0x51, 0x66, 0x47, 0x20, + 0xc6, 0xc1, 0x81, 0x34, 0x5a, 0xa2, 0x1e, 0x9d, 0xc1, 0xee, 0xc7, 0x18, 0xf4, 0xa2, 0x7c, 0x02, + 0xd2, 0xc2, 0x99, 0xe7, 0xc4, 0x85, 0x95, 0xd3, 0x47, 0x98, 0x05, 0x2b, 0xe8, 0x09, 0x7d, 0x79, + 0x24, 0xa1, 0xdf, 0xc9, 0x38, 0x09, 0xbe, 0x4c, 0x51, 0x20, 0xd2, 0x2d, 0x87, 0x73, 0x3d, 0x64, + 0x76, 0x25, 0xac, 0x79, 0x0b, 0xee, 0x82, 0xe7, 0x3e, 0x92, 0xa7, 0x09, 0x2d, 0xf0, 0xf1, 0x0b, + 0xc4, 0xf2, 0xf2, 0x4f, 0x8c, 0x67, 0x94, 0xd7, 0x5b, 0xdb, 0xdd, 0xa4, 0x77, 0x6b, 0x27, 0x72, + 0x45, 0xbc, 0xb6, 0xd6, 0xcd, 0xb5, 0xc4, 0x12, 0xc7, 0x11, 0xee, 0x3f, 0xd4, 0xca, 0x1f, 0x53, + 0x0d, 0x1b, 0x8a, 0xf5, 0x76, 0xae, 0xba, 0x3e, 0x57, 0xaa, 0x5e, 0x19, 0xdf, 0x12, 0x0d, 0x4a, + 0x1c, 0x91, 0xbd, 0x56, 0x8d, 0xc8, 0x4a, 0x89, 0x84, 0xf4, 0x13, 0x09, 0x10, 0x08, 0xde, 0xa2, + 0x92, 0x51, 0xb9, 0x2c, 0x89, 0x54, 0xb5, 0xd0, 0x22, 0x51, 0x08, 0x92, 0x04, 0xfb, 0xa6, 0xf7, + 0x2f, 0x3d, 0x57, 0x38, 0x3f, 0x31, 0xbd, 0x84, 0xeb, 0x5c, 0xe9, 0xa9, 0xd5, 0xe8, 0x36, 0x1a, + 0x62, 0xa7, 0x6f, 0x1e, 0x68, 0x41, 0x0e, 0x99, 0xae, 0x08, 0xf5, 0x1f, 0xf9, 0x79, 0x34, 0xea, + 0x6a, 0xad, 0x82, 0x62, 0xd7, 0xe8, 0xe3, 0xe5, 0x16, 0x65, 0xaf, 0xa6, 0x5c, 0x28, 0x4c, 0x3d, + 0x86, 0x64, 0xcc, 0x34, 0xa9, 0x6d, 0x09, 0x28, 0x1c, 0x92, 0x95, 0x73, 0x7e, 0xad, 0x18, 0xa7, + 0x22, 0xc8, 0x72, 0x09, 0x83, 0xab, 0xa1, 0x85, 0x9c, 0xec, 0xa8, 0x94, 0xd5, 0x80, 0x4d, 0x71, + 0x0b, 0x02, 0x6f, 0x22, 0xbc, 0xc2, 0x93, 0xab, 0xc5, 0xe9, 0x13, 0x5b, 0xad, 0x5d, 0x9b, 0x15, + 0xf6, 0x4c, 0x67, 0xe4, 0x93, 0x36, 0xab, 0xe3, 0x74, 0x61, 0x6c, 0xdc, 0x5e, 0xa5, 0x55, 0x40, + 0xc1, 0x7c, 0x32, 0xba, 0x92, 0x59, 0x3d, 0x98, 0xfa, 0xda, 0xbc, 0xd0, 0xe4, 0x96, 0x24, 0x8e, + 0x56, 0xcf, 0x49, 0x6d, 0x67, 0xb2, 0x45, 0x89, 0x05, 0xc5, 0x1e, 0xf7, 0x50, 0x21, 0x3e, 0x7a, + 0x78, 0xc3, 0xb8, 0x35, 0x89, 0xc3, 0x02, 0xc8, 0x70, 0xcc, 0x00, 0x8a, 0x63, 0x54, 0x8f, 0x07, + 0x97, 0xb0, 0x09, 0x64, 0xac, 0x52, 0x52, 0x8d, 0xde, 0x8d, 0x87, 0xf9, 0xfc, 0xed, 0x16, 0x66, + 0xb8, 0x71, 0x91, 0xad, 0x47, 0x99, 0x3c, 0x94, 0x7c, 0x92, 0x29, 0x92, 0xea, 0x5f, 0x27, 0x3b, + 0xe8, 0x0c, 0xfb, 0x4a, 0x1c, 0x4e, 0x62, 0x1a, 0xcf, 0x3e, 0x8e, 0x15, 0x4c, 0x48, 0x52, 0x63, + 0xbc, 0xa9, 0xd8, 0x35, 0x05, 0xf7, 0x43, 0xdb, 0xa1, 0x28, 0x20, 0x78, 0xaa, 0x24, 0x3e, 0x1b, + 0xc1, 0x32, 0x33, 0xc2, 0xe7, 0x36, 0xca, 0x0e, 0x15, 0x24, 0x84, 0x10, 0x3c, 0x67, 0x88, 0x8e, + 0x48, 0xcd, 0xda, 0x33, 0x23, 0x5f, 0xde, 0x89, 0x33, 0xe8, 0xb4, 0x21, 0xda, 0xc2, 0x84, 0x37, + 0xc8, 0x5d, 0x3d, 0xdc, 0xdc, 0x68, 0xce, 0xe3, 0xe2, 0xdb, 0x8f, 0xf5, 0x6a, 0x59, 0x52, 0xc6, + 0x71, 0x91, 0x1c, 0xe1, 0xe1, 0x12, 0x6b, 0x89, 0xa9, 0x6e, 0xa3, 0x3f, 0x9e, 0xf6, 0x89, 0x72, + 0x7f, 0x62, 0xda, 0x52, 0xce, 0x24, 0xb8, 0xaa, 0xdf, 0x24, 0x67, 0x67, 0x98, 0xed, 0x06, 0xe9, + 0xb3, 0xc7, 0x67, 0x5e, 0xca, 0xc2, 0xac, 0x21, 0xf5, 0xd5, 0xdd, 0x82, 0xc7, 0x9d, 0xfb, 0x7b, + 0x1d, 0xda, 0xc8, 0xf2, 0x6f, 0x9c, 0xe8, 0x12, 0x4f, 0x66, 0x66, 0x85, 0x00, 0x11, 0xec, 0xef, + 0xc8, 0xe1, 0xe7, 0x13, 0xcc, 0x51, 0x60, 0xe8, 0x55, 0x6b, 0xc1, 0x49, 0x95, 0x46, 0x0d, 0xf7, + 0x9b, 0xe0, 0x6f, 0x68, 0xc4, 0xba, 0xe6, 0x1d, 0x9f, 0x8c, 0xd6, 0x81, 0xb8, 0xc1, 0xcc, 0x9f, + 0x59, 0x2b, 0x91, 0xb3, 0x26, 0xfe, 0x01, 0x97, 0x6d, 0xab, 0xaf, 0xb5, 0x66, 0x1d, 0x32, 0x57, + 0x9d, 0x3f, 0x8d, 0x78, 0x50, 0x4b, 0x09, 0xa4, 0xce, 0x48, 0x1b, 0xe0, 0x53, 0xcc, 0x88, 0x3c, + 0x76, 0x8e, 0x59, 0x11, 0x2d, 0xbb, 0xb0, 0xdd, 0x02, 0x7a, 0x7c, 0x25, 0x95, 0xc8, 0xdc, 0x7d, + 0x9b, 0x64, 0x13, 0xc3, 0x35, 0x3d, 0x23, 0x69, 0xcb, 0x6d, 0xdf, 0x90, 0xdc, 0x19, 0xff, 0x4d, + 0x48, 0x2d, 0x07, 0x42, 0xbb, 0xf5, 0xf0, 0xc7, 0xca, 0xdb, 0xdc, 0xa5, 0x77, 0xee, 0x70, 0x63, + 0xdd, 0xa3, 0xce, 0xa6, 0xca, 0x27, 0xb7, 0x84, 0xe0, 0x58, 0x77, 0xd8, 0x82, 0x4f, 0x7d, 0x58, + 0xca, 0xa0, 0x3c, 0x4a, 0x5e, 0xe8, 0x6e, 0x0f, 0x18, 0x99, 0x2e, 0x17, 0xac, 0xc1, 0xfc, 0x2b, + 0xef, 0x68, 0x06, 0xbe, 0xf5, 0xba, 0x2b, 0x96, 0x3f, 0xbd, 0xa3, 0xe1, 0x95, 0x28, 0xde, 0xd3, + 0x39, 0xc6, 0x62, 0xcc, 0x0c, 0x3e, 0x6d, 0x1c, 0x72, 0x64, 0xa6, 0x8d, 0xf6, 0x17, 0x9e, 0x44, + 0x45, 0xcd, 0xe1, 0xf6, 0x03, 0x1d, 0x7b, 0x06, 0x01, 0x31, 0xe8, 0xf1, 0xc8, 0xf5, 0xbd, 0xfd, + 0x2b, 0x10, 0x1c, 0x69, 0x5e, 0x10, 0x55, 0xc7, 0x66, 0xf4, 0xb5, 0x2a, 0xe6, 0x5f, 0xaf, 0x43, + 0xb7, 0x18, 0x10, 0x40, 0xd3, 0xec, 0x4b, 0xf0, 0xe8, 0x9d, 0x5d, 0xb5, 0xd5, 0xeb, 0x21, 0x4d, + 0x79, 0x0d, 0x61, 0xe7, 0xd6, 0xe1, 0x4e, 0x7f, 0xa1, 0x64, 0xff, 0xbd, 0x0e, 0xb8, 0x9a, 0x3f, + 0xf6, 0xc6, 0xfa, 0x08, 0x7c, 0xff, 0x6e, 0x7a, 0xb7, 0xca, 0xbb, 0x27, 0x47, 0xb9, 0x9d, 0xc2, + 0x4b, 0xcf, 0x71, 0xc4, 0xa4, 0xe7, 0x8c, 0x4d, 0xc3, 0x8a, 0x45, 0xd7, 0xd4, 0xa9, 0xbe, 0x69, + 0x7c, 0x89, 0xba, 0xdc, 0x12, 0x48, 0xdc, 0xb6, 0x7e, 0xed, 0x6e, 0xe9, 0x26, 0xc9, 0xfd, 0xdb, + 0xc4, 0x8c, 0x43, 0xbb, 0x5d, 0x09, 0x39, 0x44, 0xaa, 0xe6, 0x6c, 0xa1, 0x26, 0xf1, 0x08, 0x77, + 0x41, 0xe2, 0x7e, 0xac, 0xad, 0xad, 0xbb, 0xd2, 0x52, 0x5e, 0x9b, 0xa6, 0xf2, 0x67, 0x68, 0xe5, + 0x5a, 0xc7, 0x53, 0xb0, 0x2d, 0x8e, 0x9a, 0x41, 0x0e, 0x28, 0x7c, 0xe3, 0x3a, 0x53, 0xf0, 0x6c, + 0x29, 0x12, 0xc6, 0x8f, 0x7f, 0x34, 0x75, 0xa7, 0x7e, 0xb6, 0xf9, 0xb2, 0xb6, 0xf7, 0x06, 0x28, + 0x8e, 0x2d, 0x15, 0x6e, 0xc1, 0x55, 0x5f, 0x19, 0x0d, 0xfe, 0xea, 0xfa, 0xac, 0xf3, 0x31, 0x4b, + 0x25, 0x2b, 0x2d, 0x1b, 0x5b, 0x2b, 0x8b, 0xdb, 0xcd, 0x6f, 0xdf, 0x7e, 0x75, 0x53, 0x2a, 0xad, + 0x00, 0x4e, 0xf4, 0x80, 0x64, 0xed, 0xfe, 0x84, 0xd6, 0xd4, 0xda, 0x27, 0xb4, 0xb1, 0x49, 0x2e, + 0x54, 0x2e, 0xe5, 0xe4, 0x49, 0xcb, 0xe2, 0x24, 0xab, 0xad, 0x38, 0xec, 0x8e, 0xcc, 0x97, 0x18, + 0x5d, 0xc4, 0xae, 0x8c, 0xa7, 0xfb, 0xd9, 0x91, 0x28, 0xe8, 0xe7, 0xea, 0x9f, 0x4a, 0x24, 0xa6, + 0x67, 0xdc, 0x24, 0x47, 0xcf, 0x73, 0x9f, 0x54, 0x95, 0x5e, 0xc9, 0x2c, 0xc7, 0xc2, 0xf3, 0xfc, + 0x52, 0xb1, 0x58, 0xb4, 0xf2, 0xad, 0xe8, 0xed, 0xf1, 0x77, 0x6a, 0x5e, 0x49, 0xa9, 0xd2, 0x0e, + 0x12, 0x76, 0xd1, 0x82, 0xf5, 0x33, 0xa6, 0x35, 0x2f, 0x7a, 0x46, 0xa7, 0xa4, 0xd1, 0x8f, 0xb5, + 0xee, 0x5b, 0xa9, 0x6d, 0xe6, 0xef, 0x0a, 0xf5, 0xaf, 0x3d, 0x47, 0xf4, 0x24, 0x5d, 0x4d, 0x69, + 0xaa, 0x4c, 0xed, 0x7a, 0xcd, 0xe5, 0xc7, 0x04, 0xb9, 0x87, 0x91, 0x7a, 0x5e, 0x69, 0xed, 0x5b, + 0x64, 0xda, 0xf2, 0x29, 0x06, 0x3e, 0x95, 0x31, 0xe9, 0x2e, 0x29, 0x7e, 0xa0, 0x64, 0x6b, 0x11, + 0x08, 0x25, 0xdc, 0x07, 0x3f, 0xde, 0xbb, 0x62, 0x29, 0x7e, 0x62, 0x1a, 0xd2, 0x03, 0x01, 0x75, + 0x95, 0xf7, 0x44, 0x27, 0x2f, 0xae, 0x2f, 0xcc, 0xbb, 0x90, 0xb4, 0xe0, 0x27, 0x08, 0xa1, 0x06, + 0xe9, 0x10, 0xea, 0xdc, 0x13, 0x4b, 0xb7, 0x6b, 0x39, 0xc3, 0xc6, 0x8f, 0x51, 0x08, 0x6d, 0x87, + 0xf7, 0x7c, 0x87, 0xba, 0x25, 0xf8, 0x80, 0x65, 0x2e, 0x6c, 0x97, 0x3d, 0x5f, 0x1c, 0xe7, 0x21, + 0xa2, 0x5f, 0x49, 0x04, 0x9a, 0xbc, 0x65, 0x5b, 0x60, 0x1a, 0x97, 0x08, 0xc5, 0x2f, 0x70, 0x14, + 0xb2, 0x2e, 0xb4, 0xb8, 0x62, 0xf4, 0xf0, 0x02, 0x66, 0x62, 0xbf, 0x67, 0xb1, 0x27, 0x04, 0xc5, + 0xad, 0x2e, 0x4f, 0x1d, 0xea, 0x88, 0x6e, 0x3c, 0x09, 0xbc, 0x60, 0x65, 0xd5, 0xa5, 0xf8, 0x01, + 0xd3, 0x0c, 0x0b, 0x55, 0x6b, 0xd9, 0x0a, 0x28, 0x39, 0xdc, 0x5d, 0xec, 0xb7, 0xed, 0x2c, 0xe3, + 0xc1, 0xdb, 0x6d, 0x5b, 0xe1, 0x9b, 0x54, 0x7a, 0xe5, 0x07, 0xba, 0xd1, 0x9a, 0xde, 0x67, 0x90, + 0xe9, 0x71, 0x09, 0xda, 0x1d, 0xd5, 0x1a, 0xa7, 0x99, 0xe4, 0xf2, 0x90, 0xd0, 0xb7, 0x67, 0x0e, + 0x2c, 0xd5, 0xab, 0xa8, 0xe3, 0x9d, 0x0a, 0x56, 0x1d, 0xad, 0x76, 0x55, 0x43, 0x8a, 0x32, 0x2d, + 0x43, 0x53, 0xeb, 0xef, 0xe6, 0x33, 0x0e, 0x04, 0xcd, 0xf2, 0x55, 0x1a, 0x4a, 0xf3, 0xa7, 0x32, + 0x91, 0xcd, 0xc8, 0xdd, 0x13, 0x58, 0x1d, 0x86, 0x5f, 0x22, 0x95, 0xfd, 0x27, 0xa6, 0xb3, 0x3c, + 0xb0, 0x4a, 0xdb, 0x26, 0x91, 0xf3, 0xfe, 0x45, 0x94, 0xae, 0x25, 0x15, 0xb6, 0x22, 0xf4, 0x9f, + 0x96, 0xc8, 0xf9, 0xa6, 0xdb, 0xac, 0x1f, 0x50, 0x27, 0xa3, 0xc5, 0xc2, 0x51, 0x7f, 0xa4, 0x56, + 0xbe, 0x9e, 0x5c, 0x9a, 0xdd, 0x84, 0x47, 0x95, 0xc3, 0x43, 0x8a, 0xb8, 0x56, 0x7c, 0x4a, 0x4e, + 0xbf, 0x3f, 0x53, 0xba, 0xd6, 0x57, 0xd9, 0xba, 0xaf, 0x96, 0x78, 0x7a, 0x6c, 0x2b, 0x20, 0x79, + 0xbd, 0x4a, 0xf2, 0x73, 0x5b, 0x2d, 0x8c, 0x34, 0x7b, 0x11, 0x75, 0x41, 0xeb, 0x41, 0xa7, 0x96, + 0x0a, 0x6f, 0x2c, 0x48, 0x63, 0x7b, 0xfa, 0x97, 0x9e, 0x2b, 0xac, 0x9f, 0x98, 0xc6, 0x6a, 0xdb, + 0x28, 0xd5, 0xd1, 0x6a, 0x18, 0x84, 0x1d, 0x4f, 0x38, 0xdd, 0x13, 0x4e, 0x03, 0xc9, 0xb4, 0x97, + 0x8d, 0xb7, 0x04, 0x37, 0x77, 0x65, 0x45, 0xf5, 0xb0, 0xef, 0xe1, 0xa5, 0x62, 0x1b, 0x98, 0x60, + 0x52, 0xfb, 0x07, 0xd2, 0xb1, 0x63, 0x0d, 0x4b, 0xb8, 0x5b, 0xb2, 0x20, 0x77, 0x99, 0xdc, 0xf1, + 0xc1, 0x49, 0x16, 0xb0, 0x6e, 0xdc, 0xe4, 0x01, 0x57, 0x71, 0x65, 0x6b, 0xce, 0x08, 0xb5, 0xb8, + 0xf3, 0xa0, 0x07, 0xb5, 0x63, 0xb2, 0x01, 0x3a, 0x52, 0x8e, 0xfc, 0xdd, 0x16, 0x87, 0x39, 0x49, + 0xe8, 0xea, 0xb1, 0x46, 0xba, 0x6d, 0x76, 0x3e, 0x77, 0xb0, 0x01, 0x2d, 0x4b, 0x63, 0xf1, 0x66, + 0xa8, 0x09, 0x64, 0xdd, 0x14, 0x93, 0x9d, 0x39, 0xd6, 0x86, 0x9b, 0x7a, 0x58, 0xa5, 0x53, 0x19, + 0x0a, 0x88, 0x7f, 0xce, 0x68, 0x2f, 0xea, 0x26, 0x7c, 0xc0, 0xdd, 0x36, 0xab, 0xa3, 0x60, 0x1f, + 0xba, 0xb6, 0x84, 0xd4, 0xd9, 0x3a, 0x8d, 0xdc, 0x51, 0xd3, 0xeb, 0x41, 0xb4, 0x37, 0xbb, 0x6e, + 0x5a, 0x51, 0x08, 0x46, 0xe0, 0xeb, 0x40, 0x46, 0x52, 0xd2, 0x4b, 0x9e, 0xcd, 0xe7, 0x67, 0xdb, + 0x78, 0xa9, 0x93, 0x8a, 0x7c, 0x67, 0xc4, 0xea, 0x90, 0x8e, 0xef, 0xe9, 0x41, 0xd6, 0x9b, 0xe8, + 0x2c, 0xf3, 0xf5, 0x3a, 0x75, 0x27, 0xca, 0x7b, 0x08, 0x07, 0xb5, 0x51, 0xa3, 0x0b, 0x8b, 0x3c, + 0x1a, 0x38, 0x1d, 0x89, 0x76, 0x6b, 0x77, 0x41, 0x57, 0xfa, 0x7e, 0x12, 0x9a, 0xe1, 0x45, 0xd4, + 0x58, 0xf7, 0x78, 0xf3, 0xf0, 0xe2, 0x0a, 0x7e, 0xc2, 0xd0, 0xb8, 0xec, 0xd5, 0x1d, 0xb6, 0x1a, + 0x09, 0xfb, 0xc2, 0xe2, 0x1f, 0xee, 0x8f, 0xe8, 0x2f, 0xf2, 0xfa, 0x96, 0x8d, 0xb6, 0xbd, 0x6e, + 0xf2, 0xd1, 0x27, 0xdf, 0xb9, 0xfa, 0x9b, 0x54, 0xc1, 0x25, 0xb5, 0xbe, 0xc7, 0xee, 0x27, 0xc5, + 0xa1, 0x8e, 0x24, 0x16, 0xf0, 0xb1, 0x34, 0x1a, 0xe3, 0x79, 0xe5, 0x52, 0x1a, 0x90, 0xff, 0x92, + 0xfa, 0x98, 0xbb, 0x4f, 0xea, 0x40, 0x54, 0xf3, 0x63, 0x9c, 0x66, 0x54, 0xff, 0xbe, 0xce, 0x27, + 0xf8, 0x4f, 0xa5, 0x78, 0xa5, 0x41, 0xff, 0x51, 0x66, 0xaa, 0x70, 0x1f, 0xd5, 0xd7, 0xd9, 0x5d, + 0xe2, 0x97, 0x4e, 0xca, 0x0d, 0x2d, 0x13, 0x45, 0xfd, 0x9b, 0x9e, 0xb8, 0x1e, 0xa5, 0xf7, 0x89, + 0xcb, 0x54, 0xb1, 0x71, 0x79, 0xdd, 0xf7, 0xa3, 0x43, 0xe1, 0xc3, 0xf7, 0xbf, 0x9b, 0xbf, 0x56, + 0xdf, 0x36, 0x28, 0xe5, 0x43, 0x62, 0x01, 0x55, 0x98, 0x0c, 0xdd, 0xb8, 0x5d, 0x4e, 0xeb, 0xf2, + 0xd9, 0x51, 0x6a, 0x80, 0x09, 0x8a, 0xc1, 0x43, 0xf5, 0x7c, 0xf7, 0x9d, 0x9a, 0x5c, 0x45, 0xdd, + 0x47, 0xc1, 0xe1, 0x43, 0xf4, 0xef, 0x2c, 0xf6, 0xd0, 0xd3, 0xe7, 0x53, 0x56, 0x57, 0x9a, 0x5d, + 0xd0, 0xc4, 0x16, 0xbe, 0x0a, 0xf6, 0x6e, 0x48, 0x2d, 0xf0, 0xff, 0x4e, 0xa4, 0xa4, 0x18, 0x65, + 0x03, 0xa0, 0xeb, 0xff, 0xd7, 0x2f, 0x07, 0x3f, 0x76, 0x4d, 0x80, 0xd4, 0x3f, 0x19, 0xd3, 0x39, + 0x8d, 0x4c, 0x7c, 0x87, 0x89, 0xaa, 0xbe, 0xad, 0xd9, 0x4b, 0xfb, 0xc8, 0xbf, 0x19, 0x33, 0x22, + 0x2c, 0xbe, 0xc0, 0x79, 0x84, 0x86, 0xf6, 0x4d, 0xcf, 0x6e, 0xec, 0x23, 0x7b, 0x83, 0xb8, 0x5c, + 0x91, 0x8b, 0x59, 0x61, 0x76, 0x98, 0x0e, 0x06, 0x78, 0x5d, 0x2d, 0x96, 0x00, 0x8e, 0x99, 0x17, + 0x2f, 0x45, 0x6e, 0x74, 0x56, 0xe4, 0x44, 0xca, 0xe6, 0xd1, 0x69, 0x73, 0x23, 0x11, 0xc9, 0xdf, + 0xbf, 0x45, 0x2e, 0x1b, 0x66, 0x7a, 0x75, 0xe9, 0x23, 0x33, 0x99, 0xe5, 0x5d, 0xde, 0x22, 0x10, + 0xe0, 0x14, 0x87, 0x72, 0xab, 0x48, 0x80, 0x4d, 0x7e, 0x85, 0x6e, 0x5a, 0xf2, 0xd5, 0x9e, 0x16, + 0xe5, 0x68, 0x80, 0xe3, 0xef, 0x39, 0xd2, 0x27, 0xa6, 0x5e, 0x6c, 0x3b, 0xe5, 0x50, 0xc5, 0x26, + 0xf4, 0xb1, 0xbf, 0x0c, 0x8d, 0x69, 0xf9, 0x08, 0xa0, 0x45, 0x89, 0x19, 0xe9, 0x85, 0x5d, 0xce, + 0x00, 0x26, 0x31, 0xa3, 0x00, 0xe5, 0x48, 0x90, 0x1c, 0x57, 0xcf, 0xea, 0x5b, 0x92, 0xe2, 0x49, + 0x7a, 0x3e, 0x7c, 0xe1, 0x62, 0x74, 0xb5, 0x83, 0xcf, 0xfd, 0xc1, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, + 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, + 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0x9f, 0x7c, 0xf2, 0xc9, 0x27, 0xff, 0x97, + 0xf2, 0xcf, 0xf3, 0xe0, 0x1f, 0xf7, 0x88, 0xf2, 0x57, 0xff, 0x7d, 0xf7, 0x80, 0xbe, 0x7b, 0x3c, + 0xe8, 0x96, 0xd9, 0xc5, 0x40, 0x2a, 0x92, 0xcc, 0x19, 0xb6, 0xaa, 0x0a, 0x6f, 0x9b, 0x8d, 0x36, + 0xf2, 0x5b, 0xe7, 0x6f, 0x5f, 0x4f, 0x7d, 0x96, 0x96, 0xc9, 0xa0, 0x2c, 0xdf, 0x5f, 0x3d, 0xbd, + 0xd1, 0x63, 0xfe, 0xe0, 0x01, 0xc5, 0xb4, 0xb5, 0x42, 0x7d, 0x46, 0xa7, 0x77, 0x70, 0xd6, 0x53, + 0x7b, 0x9e, 0xc3, 0x05, 0x7d, 0x5c, 0xb4, 0x5b, 0x4b, 0x89, 0x09, 0x17, 0x5d, 0xb2, 0x51, 0x6b, + 0xa9, 0x54, 0xd4, 0x72, 0x8e, 0x3e, 0x5e, 0x43, 0x9d, 0xce, 0xb0, 0x6f, 0x49, 0x94, 0xd3, 0x29, + 0xf1, 0x4d, 0x33, 0xd9, 0x2f, 0xb7, 0xe7, 0x6a, 0x8d, 0x70, 0xef, 0xcb, 0x6b, 0x34, 0x78, 0x21, + 0xe7, 0x05, 0x4e, 0xd1, 0xa1, 0x51, 0x59, 0x46, 0x47, 0xf3, 0x0a, 0x83, 0xe7, 0xeb, 0x35, 0x00, + 0x47, 0xe6, 0xf9, 0x42, 0x49, 0x28, 0x68, 0x36, 0xc4, 0x0f, 0x17, 0xc6, 0x01, 0xf1, 0xf9, 0x4b, + 0x89, 0xea, 0x7e, 0x0f, 0x8e, 0x26, 0x11, 0xd5, 0x05, 0x66, 0x88, 0x6c, 0x76, 0x77, 0x1f, 0xcd, + 0xd6, 0x2f, 0x1a, 0xa8, 0xb6, 0x77, 0x8f, 0x2b, 0x99, 0x4a, 0xb3, 0x8e, 0x58, 0x1f, 0xe2, 0x05, + 0x3a, 0x3d, 0xd5, 0xcd, 0xf3, 0xcd, 0x7e, 0xd4, 0xb8, 0xdf, 0x3a, 0xb4, 0x13, 0x0d, 0xfc, 0xef, + 0xe4, 0x92, 0x63, 0x9b, 0x59, 0x2f, 0xcb, 0x24, 0x47, 0xf1, 0x31, 0xd5, 0xfe, 0x6f, 0x24, 0xbf, + 0xee, 0xad, 0xad, 0x97, 0xf5, 0x08, 0x85, 0xc1, 0x17, 0xa9, 0x43, 0x6b, 0x29, 0xd7, 0xeb, 0x7d, + 0x5b, 0xa9, 0xa7, 0x09, 0xf4, 0x4a, 0x99, 0xc6, 0xe0, 0xeb, 0xb5, 0xda, 0xa1, 0xf9, 0xeb, 0x7e, + 0xb5, 0x72, 0x21, 0xab, 0xdb, 0x4f, 0x2e, 0x4b, 0xf4, 0xfa, 0x6d, 0xc6, 0x72, 0xd3, 0x5e, 0x2b, + 0xd3, 0xf1, 0xc8, 0x97, 0x4a, 0x67, 0x6c, 0x62, 0xe7, 0x77, 0xed, 0x05, 0xba, 0x0a, 0xc9, 0xeb, + 0x5b, 0x49, 0xf9, 0x58, 0xd7, 0x5e, 0x4a, 0x47, 0xcc, 0x9c, 0x25, 0x2a, 0xfc, 0x5e, 0x87, 0x1b, + 0x80, 0x63, 0xed, 0x82, 0xab, 0x43, 0xb4, 0x53, 0x42, 0xa6, 0xfd, 0xe3, 0xce, 0xc5, 0x16, 0xe7, + 0x27, 0xa6, 0x17, 0x56, 0xad, 0xc6, 0x1a, 0x95, 0x42, 0x90, 0x44, 0xa4, 0x60, 0x83, 0x4f, 0x73, + 0x31, 0xad, 0x01, 0x9f, 0x28, 0x8c, 0x88, 0xeb, 0xbe, 0xb7, 0xae, 0xb8, 0xbd, 0xa6, 0xe4, 0xc6, + 0x73, 0x12, 0x96, 0x89, 0x7b, 0xcb, 0x5a, 0x41, 0xed, 0x2c, 0x7b, 0xad, 0x78, 0xb2, 0xf3, 0x63, + 0x7a, 0x93, 0x8a, 0x34, 0xc0, 0x5b, 0x83, 0x37, 0x13, 0x13, 0x92, 0xb6, 0x67, 0x46, 0x51, 0x6f, + 0x65, 0xc0, 0xf7, 0x90, 0xa4, 0x8d, 0x38, 0x47, 0x09, 0x85, 0xd1, 0xbe, 0x4d, 0x71, 0xc0, 0x75, + 0xf3, 0xeb, 0xeb, 0x4e, 0x1f, 0x15, 0x1a, 0xff, 0xdc, 0x6a, 0x65, 0xf5, 0x4f, 0x37, 0xb7, 0x54, + 0x4f, 0x8c, 0xde, 0x86, 0x92, 0xb1, 0x28, 0xda, 0x81, 0x22, 0x96, 0x6e, 0xfd, 0xf5, 0x08, 0xed, + 0x84, 0x8d, 0x6e, 0x73, 0x59, 0xa6, 0xcf, 0xbd, 0x11, 0x2b, 0xcc, 0x83, 0x5f, 0xc1, 0x17, 0xca, + 0xd3, 0x2c, 0x40, 0x03, 0xb9, 0x7b, 0xf9, 0x6c, 0xac, 0x1d, 0x26, 0x29, 0xf7, 0x96, 0x0e, 0x15, + 0x1c, 0x18, 0x89, 0x51, 0x29, 0x43, 0x44, 0x38, 0x33, 0x16, 0x08, 0xd1, 0xeb, 0x8b, 0x43, 0xb4, + 0x99, 0x0d, 0xbf, 0xf9, 0x96, 0x0b, 0x1a, 0x64, 0x23, 0xcd, 0x77, 0x50, 0xc4, 0xc2, 0xd7, 0x9e, + 0x1b, 0xa5, 0xc1, 0xd3, 0x83, 0x20, 0xd5, 0x3b, 0x73, 0xdf, 0xbd, 0x5d, 0xfb, 0x74, 0x52, 0x65, + 0x2a, 0xb5, 0x41, 0x41, 0x26, 0x33, 0xed, 0x7e, 0xa1, 0x21, 0x9f, 0x6e, 0x15, 0x72, 0x9e, 0x8d, + 0x3a, 0xc2, 0x35, 0x8f, 0xbb, 0xc5, 0x2b, 0xf5, 0x55, 0xdf, 0x74, 0x86, 0xe3, 0x26, 0xcb, 0x61, + 0xdc, 0x1e, 0xd5, 0x4d, 0xc7, 0xeb, 0xeb, 0x8b, 0xbb, 0xd5, 0x7e, 0x5b, 0x41, 0xee, 0xf7, 0x3a, + 0xc2, 0x38, 0xf2, 0xdd, 0x43, 0xbe, 0x5b, 0xa0, 0x85, 0x8c, 0x85, 0x27, 0xab, 0x2d, 0x3f, 0x5e, + 0x47, 0xe6, 0xe8, 0x92, 0xb7, 0x74, 0x18, 0x56, 0xec, 0x25, 0x16, 0x50, 0xa1, 0x68, 0x23, 0xf0, + 0xc5, 0x76, 0x33, 0x0a, 0xf0, 0x7e, 0x25, 0x53, 0xbe, 0x4a, 0xd8, 0xdd, 0xfc, 0x71, 0xdf, 0x33, + 0xc4, 0xfd, 0x89, 0x69, 0x33, 0x08, 0xa7, 0xfa, 0xe6, 0xff, 0x87, 0xbd, 0xf7, 0xfb, 0x49, 0x9c, + 0x5d, 0x1f, 0x7e, 0xff, 0x99, 0xe5, 0x4c, 0xd0, 0xa5, 0x26, 0xcf, 0x2c, 0x34, 0xe8, 0x83, 0x73, + 0x2c, 0x3c, 0x40, 0x02, 0x16, 0x02, 0x58, 0x3c, 0x19, 0x24, 0x82, 0x40, 0x02, 0x02, 0x01, 0xc4, + 0xf9, 0x1f, 0xd4, 0x42, 0x14, 0xc1, 0x13, 0x91, 0x40, 0x2d, 0x24, 0x60, 0x21, 0x80, 0xc5, 0x63, + 0x71, 0x80, 0x44, 0x69, 0x1b, 0xa8, 0x85, 0x13, 0x81, 0x00, 0x02, 0x89, 0x58, 0x08, 0x32, 0xce, + 0x7a, 0x67, 0x7d, 0xdf, 0x64, 0xef, 0xfd, 0xee, 0x79, 0x26, 0x7b, 0x9f, 0xec, 0xef, 0xc1, 0xbb, + 0xfd, 0x1c, 0x10, 0x4d, 0xa8, 0x2d, 0x9f, 0xde, 0xbd, 0x7f, 0xc8, 0x75, 0xdd, 0x17, 0xed, 0x8f, + 0xa4, 0x6f, 0x23, 0x28, 0x1e, 0xce, 0x39, 0x8e, 0x0f, 0x51, 0x1e, 0xf9, 0xf0, 0xfc, 0x23, 0x80, + 0xe6, 0x54, 0x54, 0x6a, 0x69, 0x1d, 0xda, 0xa3, 0x53, 0xe8, 0x66, 0xdd, 0x19, 0xdf, 0x7d, 0xac, + 0x26, 0x73, 0xd2, 0xe7, 0x61, 0x2b, 0x26, 0xd1, 0x1e, 0x89, 0x66, 0xb2, 0xe2, 0x40, 0xc4, 0xe1, + 0x1d, 0xb9, 0x93, 0xf8, 0xbd, 0xa9, 0x5a, 0x68, 0xdb, 0x0e, 0x5a, 0x4b, 0x82, 0x0a, 0xac, 0xc9, + 0x52, 0xe9, 0x13, 0x2c, 0x37, 0x38, 0xb9, 0xaf, 0x39, 0x04, 0x27, 0xee, 0x8c, 0x7c, 0x1c, 0x95, + 0x9c, 0xb2, 0x59, 0x71, 0x99, 0x4f, 0x73, 0x77, 0x95, 0x6e, 0x8e, 0xcb, 0x6e, 0x65, 0x53, 0xad, + 0x5c, 0x1f, 0xb6, 0x74, 0xc4, 0xd3, 0x23, 0x1a, 0xb0, 0xaf, 0xfb, 0x28, 0x07, 0xd9, 0x0b, 0x58, + 0xec, 0xfc, 0xdd, 0x7e, 0xb8, 0x2a, 0x03, 0x27, 0x57, 0xf5, 0x65, 0x85, 0x7a, 0x27, 0x63, 0x0d, + 0x2b, 0xb9, 0xea, 0x1c, 0x40, 0x85, 0xd0, 0x4f, 0x2a, 0x97, 0x9f, 0x8c, 0xbd, 0x3c, 0x94, 0xc2, + 0x66, 0x5d, 0x9b, 0xb8, 0x96, 0x59, 0xb1, 0x6c, 0x8f, 0x4a, 0xb8, 0xe8, 0x09, 0x92, 0xd3, 0xb9, + 0x1b, 0xd5, 0x5e, 0x2c, 0x43, 0xcd, 0x65, 0x11, 0x0e, 0x29, 0xf5, 0xe9, 0xae, 0xea, 0xf0, 0x50, + 0x36, 0xdb, 0x0d, 0x5f, 0xc3, 0xa7, 0x02, 0xd4, 0x17, 0xcc, 0x96, 0x05, 0x0e, 0x78, 0xae, 0x68, + 0xd8, 0x4b, 0x7e, 0xcc, 0x9b, 0x3a, 0xd5, 0xab, 0x8c, 0xb4, 0x6d, 0x43, 0x5b, 0x0b, 0x0a, 0x68, + 0xb1, 0x5b, 0xc6, 0x4b, 0xd5, 0x76, 0xd5, 0xdd, 0xd1, 0xf5, 0x26, 0x7d, 0x5b, 0x1b, 0xd3, 0x6a, + 0x35, 0x60, 0x67, 0xd1, 0xa7, 0x07, 0x3e, 0x58, 0x89, 0x51, 0x15, 0xcf, 0xee, 0xf5, 0x50, 0x39, + 0x82, 0xd6, 0xbb, 0x29, 0x67, 0xe4, 0xcc, 0xab, 0x09, 0x03, 0x83, 0xe0, 0x52, 0x2f, 0xff, 0x53, + 0xfc, 0xe4, 0xa0, 0x86, 0x0e, 0x7b, 0x17, 0xf5, 0x7f, 0x24, 0x62, 0x12, 0xe3, 0xe1, 0xf9, 0x0f, + 0x26, 0xf9, 0x6b, 0xde, 0x33, 0x2e, 0xff, 0x5b, 0xd3, 0x38, 0x34, 0x1f, 0xfb, 0x86, 0x3d, 0x30, + 0xd9, 0xde, 0x43, 0xbb, 0x09, 0xb8, 0xd6, 0xcf, 0x92, 0x19, 0x69, 0x73, 0xa5, 0x11, 0xdf, 0xd7, + 0x35, 0xa3, 0xd5, 0x4b, 0x06, 0xe3, 0x19, 0x0e, 0x6c, 0x5b, 0x2b, 0x29, 0xde, 0xc4, 0x80, 0x9b, + 0xd0, 0xc1, 0x53, 0xe3, 0xed, 0xf6, 0x10, 0x12, 0x08, 0xdc, 0xb6, 0x2f, 0x5d, 0xab, 0x53, 0x67, + 0xbf, 0x76, 0x60, 0x1b, 0xce, 0x4c, 0xb5, 0x08, 0xcd, 0xdb, 0x44, 0xdb, 0x51, 0x88, 0x2d, 0x6c, + 0x33, 0xba, 0xe6, 0xd2, 0x65, 0x73, 0xaf, 0x13, 0x1a, 0x9e, 0x6a, 0x6c, 0xd6, 0x4c, 0xf2, 0x33, + 0xc7, 0xe8, 0x0c, 0xc2, 0x1c, 0x5e, 0x4c, 0xe6, 0x15, 0x88, 0xda, 0x1a, 0x6d, 0x4d, 0xe0, 0x47, + 0xd4, 0xf3, 0x98, 0x1e, 0x0f, 0x4d, 0x5b, 0xcc, 0x4e, 0x2c, 0x97, 0xd7, 0x6d, 0xa8, 0x17, 0xd3, + 0xdd, 0x51, 0x29, 0x25, 0xc5, 0xc3, 0xfd, 0x25, 0x47, 0x3b, 0xb3, 0xc4, 0x84, 0xfd, 0x51, 0x76, + 0x1f, 0x14, 0x88, 0x43, 0xb7, 0x11, 0x77, 0x83, 0x66, 0xe8, 0x61, 0x90, 0x4d, 0x2b, 0x4f, 0x86, + 0x34, 0x29, 0x3a, 0x00, 0x8c, 0x72, 0x43, 0xdf, 0x74, 0x42, 0xb4, 0x4a, 0xa7, 0x1c, 0xf6, 0x4a, + 0x16, 0x75, 0x4f, 0x5c, 0x30, 0xb6, 0x86, 0x4f, 0xee, 0xd4, 0xbd, 0x6e, 0x9c, 0xf2, 0xfa, 0xcb, + 0x08, 0x5d, 0x5b, 0x44, 0x04, 0xba, 0x20, 0xb8, 0x59, 0xbd, 0x8a, 0xba, 0x68, 0x6e, 0xef, 0x3c, + 0x4d, 0xc9, 0x0b, 0xd5, 0x17, 0x14, 0xf5, 0x24, 0x3c, 0x53, 0xca, 0xfb, 0xb7, 0x47, 0xa2, 0xd7, + 0xed, 0x64, 0x8a, 0x72, 0x4a, 0xf1, 0xe3, 0x66, 0x65, 0xe4, 0x68, 0xea, 0xed, 0x07, 0xdb, 0xcd, + 0xa8, 0x8c, 0x8a, 0x9f, 0x24, 0x81, 0x44, 0xfb, 0x22, 0xbf, 0xe5, 0x91, 0x71, 0xba, 0x02, 0x19, + 0xf0, 0x67, 0x38, 0xd9, 0x73, 0x56, 0x6e, 0x2d, 0xbb, 0xb5, 0x4e, 0xef, 0x16, 0x45, 0x9b, 0xbd, + 0xd4, 0x5f, 0x83, 0x6a, 0x50, 0xa2, 0xc8, 0x28, 0x32, 0x2a, 0x55, 0xff, 0xa8, 0x68, 0xdd, 0x6d, + 0x36, 0xa7, 0xf3, 0xda, 0xcc, 0xaf, 0xbb, 0x26, 0xe0, 0xe0, 0x6f, 0xda, 0x34, 0x60, 0x07, 0xd4, + 0xa4, 0xc8, 0x3e, 0x02, 0xd0, 0x25, 0x30, 0xee, 0xf1, 0x63, 0x0b, 0x16, 0xb5, 0x3a, 0x60, 0xc9, + 0xef, 0x53, 0x72, 0x21, 0xb5, 0xff, 0x42, 0x29, 0x5c, 0x35, 0xce, 0xad, 0x01, 0xc4, 0x37, 0x14, + 0xe6, 0xaa, 0x59, 0x35, 0xb6, 0xe8, 0xef, 0xbb, 0xfa, 0x31, 0x69, 0x18, 0x4f, 0x91, 0x79, 0x3a, + 0x33, 0xe1, 0x47, 0x91, 0x13, 0x32, 0x21, 0x48, 0xb2, 0xb7, 0x44, 0xb1, 0xe8, 0x55, 0x77, 0x0f, + 0x83, 0x48, 0xc6, 0xe1, 0x4d, 0xbf, 0x09, 0xe8, 0x8b, 0x4e, 0x63, 0x68, 0xae, 0x94, 0xaa, 0x37, + 0xce, 0x41, 0xd4, 0x17, 0x7a, 0xde, 0x1d, 0x8e, 0x5a, 0x3f, 0x8c, 0x92, 0xb3, 0xba, 0xe9, 0x70, + 0x44, 0xf7, 0xe9, 0x81, 0x39, 0xc5, 0x76, 0xe5, 0xde, 0x9a, 0x40, 0xaa, 0x30, 0x89, 0xce, 0xa7, + 0x13, 0x03, 0x78, 0x76, 0x5e, 0x8c, 0x47, 0xb5, 0x42, 0xe9, 0x46, 0x83, 0x61, 0xa8, 0x53, 0xed, + 0x50, 0xf5, 0x82, 0x78, 0x6f, 0xc2, 0x91, 0xd7, 0xb1, 0x72, 0xd6, 0xa8, 0x33, 0x2e, 0x73, 0xfe, + 0xa2, 0xc9, 0xca, 0xfd, 0xbd, 0xe9, 0xfb, 0xb0, 0x77, 0x75, 0x55, 0x9b, 0x4b, 0xb4, 0x29, 0x7b, + 0x05, 0x7b, 0xc0, 0x52, 0x76, 0x03, 0x6e, 0xf6, 0xa0, 0xad, 0x4a, 0x0c, 0x6f, 0x89, 0xfa, 0x07, + 0xbb, 0xcd, 0xd4, 0xfa, 0x80, 0x53, 0x10, 0xf4, 0xf4, 0x4e, 0x9e, 0xec, 0xc0, 0xb8, 0x35, 0x34, + 0x69, 0x21, 0xc8, 0xa1, 0x97, 0x0e, 0xfc, 0x64, 0x64, 0x40, 0xaf, 0xe7, 0x6d, 0x96, 0x37, 0x7a, + 0xa6, 0x58, 0xf0, 0x1f, 0xe3, 0xd1, 0x9a, 0x4d, 0xd6, 0x20, 0xaa, 0x9e, 0xa5, 0x3a, 0xb7, 0xa2, + 0x6e, 0x02, 0xd9, 0x6b, 0x2d, 0x22, 0x5f, 0x31, 0x5b, 0xab, 0x75, 0xdc, 0x83, 0xc9, 0x57, 0x85, + 0x74, 0x52, 0x3b, 0x8e, 0x98, 0x3c, 0xff, 0x6c, 0xf3, 0x06, 0xf1, 0xbd, 0x9c, 0x64, 0x70, 0xd8, + 0xe8, 0xa5, 0xf0, 0x78, 0x3a, 0x35, 0xee, 0xaf, 0x9f, 0xe5, 0x4d, 0x5e, 0x45, 0x87, 0xfa, 0xe4, + 0x91, 0x36, 0xe5, 0x2a, 0xa8, 0xfe, 0x37, 0x35, 0x28, 0xa7, 0x7e, 0x63, 0x1a, 0x2e, 0x22, 0x91, + 0xab, 0xfa, 0x8c, 0x7f, 0xad, 0x05, 0x83, 0x39, 0x4a, 0xbd, 0x99, 0xbb, 0xbc, 0x9f, 0x4b, 0x66, + 0xef, 0xe0, 0x0e, 0x00, 0xe7, 0xdf, 0x16, 0x2d, 0x03, 0xea, 0x3b, 0x9e, 0x88, 0x03, 0x8f, 0x04, + 0x8d, 0x67, 0x9a, 0x5a, 0x3c, 0x6b, 0x94, 0xb4, 0xac, 0xf4, 0xf3, 0x04, 0x8c, 0x88, 0x3c, 0xc1, + 0xe3, 0x42, 0x15, 0x71, 0x75, 0x86, 0x7b, 0x51, 0x40, 0x3a, 0x5a, 0xfa, 0xd9, 0xd0, 0x6c, 0x5a, + 0x9e, 0x17, 0x0a, 0x1b, 0x14, 0x48, 0xea, 0x76, 0xa6, 0xd7, 0xe1, 0xd8, 0xf6, 0x6c, 0x58, 0xc7, + 0x5e, 0x96, 0x99, 0x4a, 0x29, 0xf8, 0x6b, 0xbc, 0xf3, 0xc1, 0xd2, 0xf1, 0x36, 0xae, 0xf7, 0xb4, + 0x2f, 0x78, 0x93, 0x23, 0xec, 0xea, 0xfa, 0x99, 0x82, 0xb6, 0xaf, 0x5e, 0x61, 0xcc, 0xde, 0x6a, + 0x8a, 0x69, 0xda, 0x16, 0x68, 0x28, 0x2e, 0x2b, 0x2b, 0xfd, 0xc1, 0x99, 0xa5, 0x48, 0xe5, 0xcd, + 0xe8, 0xe4, 0x74, 0xc1, 0x30, 0x43, 0xc0, 0x70, 0x48, 0xb6, 0x97, 0x9e, 0xa0, 0x0e, 0xcc, 0x87, + 0xf6, 0xf2, 0x26, 0xa3, 0x06, 0x57, 0x23, 0x6e, 0x2d, 0x5a, 0xdb, 0xdb, 0x79, 0xeb, 0x65, 0xee, + 0x0a, 0x98, 0x5c, 0xa7, 0x7b, 0x7a, 0x7c, 0x20, 0x94, 0xde, 0x86, 0x3f, 0x19, 0x7b, 0xf8, 0x4e, + 0x01, 0x36, 0xbf, 0xe9, 0xb1, 0x32, 0xa6, 0x77, 0xbe, 0xf7, 0xe0, 0xea, 0xdd, 0x49, 0x62, 0xdc, + 0xd6, 0x96, 0x31, 0x45, 0x3a, 0x00, 0x2a, 0x57, 0x0a, 0xe0, 0x74, 0x31, 0xc6, 0x0f, 0x1c, 0x2d, + 0xba, 0x4a, 0x1e, 0x55, 0x60, 0x32, 0xdc, 0x0d, 0x28, 0x18, 0xdf, 0x9b, 0xa5, 0x65, 0xb9, 0x1a, + 0x26, 0x82, 0x8e, 0xb8, 0xf7, 0x0a, 0x9e, 0xf6, 0x04, 0x9a, 0x14, 0xe7, 0x96, 0x44, 0x3f, 0x0c, + 0x9d, 0xce, 0x6e, 0xd5, 0xe8, 0x71, 0x2d, 0xf7, 0x8a, 0xe9, 0xfd, 0xd6, 0x9c, 0xc5, 0x6c, 0xdb, + 0x2d, 0xd3, 0x59, 0x13, 0x24, 0xfd, 0xb1, 0xdf, 0x1b, 0x95, 0x69, 0xff, 0xbd, 0x7d, 0x85, 0xa6, + 0xce, 0xff, 0x6d, 0x5b, 0x80, 0xb5, 0xbf, 0xd6, 0xcc, 0x61, 0xab, 0x7f, 0x63, 0x1a, 0xe9, 0x39, + 0x54, 0xd4, 0x74, 0x21, 0xb6, 0x4d, 0x85, 0x7b, 0x69, 0x43, 0x29, 0x34, 0xc7, 0x13, 0x3f, 0xc0, + 0x73, 0x39, 0x13, 0x3d, 0x23, 0x44, 0x5c, 0x1b, 0xce, 0x90, 0x4f, 0x07, 0xcc, 0xa1, 0x30, 0xe0, + 0x20, 0xc2, 0xa0, 0x4e, 0xfa, 0x9f, 0x92, 0xd1, 0x69, 0x02, 0x01, 0x3a, 0x8a, 0xd0, 0xff, 0x99, + 0x01, 0x2d, 0xdc, 0x47, 0xdb, 0xff, 0xf9, 0x35, 0x88, 0x55, 0x24, 0xa5, 0x3a, 0x28, 0xda, 0x87, + 0x00, 0x05, 0x4f, 0x02, 0x41, 0x79, 0xd9, 0xfa, 0x21, 0x2a, 0x10, 0x11, 0x67, 0xa4, 0x03, 0xe4, + 0x45, 0x15, 0xf5, 0xee, 0x8b, 0x67, 0x8a, 0x2b, 0x90, 0x94, 0xd0, 0x7c, 0xdf, 0xf9, 0x25, 0x30, + 0x6b, 0xd8, 0x77, 0x1f, 0x59, 0x4d, 0xc7, 0xe7, 0xa1, 0xa0, 0xf3, 0x1e, 0xd1, 0xfe, 0xcf, 0x3f, + 0xaa, 0x03, 0x99, 0x59, 0xb6, 0x04, 0x00, 0xaa, 0x1d, 0x83, 0x12, 0x02, 0xe4, 0x32, 0xf1, 0x76, + 0xc0, 0x0e, 0x28, 0x2f, 0x21, 0xb9, 0xfc, 0x29, 0xce, 0x9a, 0x05, 0x68, 0xb2, 0x09, 0x2c, 0x3b, + 0x4a, 0x65, 0x96, 0x58, 0xc2, 0xe8, 0x00, 0xee, 0xda, 0x21, 0xca, 0x11, 0xa8, 0xbe, 0x04, 0xf2, + 0x86, 0x75, 0x37, 0x23, 0x30, 0x28, 0xc9, 0x8f, 0x9f, 0x61, 0xa5, 0x87, 0xc5, 0x4e, 0x28, 0x99, + 0x2d, 0xc4, 0xfe, 0xf3, 0xf6, 0x0b, 0xb4, 0x08, 0x4a, 0x73, 0x44, 0x32, 0x55, 0x93, 0xcd, 0x15, + 0xe3, 0xf5, 0x54, 0x01, 0xae, 0xa4, 0x6e, 0xe4, 0x80, 0x34, 0x35, 0x65, 0x3b, 0x58, 0x2f, 0x05, + 0x79, 0x66, 0x77, 0x4b, 0xc5, 0xaf, 0xe0, 0x01, 0xcc, 0xec, 0x85, 0x38, 0x85, 0x7b, 0x9f, 0xa7, + 0xbf, 0xda, 0x53, 0x04, 0xba, 0xce, 0xaa, 0x7f, 0x32, 0xc3, 0xad, 0x7c, 0x95, 0xf4, 0x70, 0xc3, + 0x7a, 0x33, 0xca, 0x21, 0x68, 0xfd, 0x3f, 0x7b, 0xb9, 0xbb, 0xb5, 0x6e, 0x35, 0x76, 0xbc, 0x83, + 0xe7, 0xe5, 0x00, 0xde, 0x9a, 0x31, 0x24, 0xa8, 0x0f, 0x21, 0x41, 0xcc, 0xc7, 0xfe, 0x35, 0xc6, + 0x7f, 0xeb, 0x37, 0xa6, 0x73, 0x44, 0xbc, 0xff, 0x67, 0x7b, 0x7c, 0x00, 0xb1, 0x31, 0xd6, 0xe9, + 0xce, 0x13, 0xf5, 0x49, 0x35, 0xf2, 0x07, 0x10, 0xc4, 0xc8, 0xea, 0x61, 0x55, 0xc4, 0xe6, 0xb0, + 0xf8, 0x0f, 0xab, 0xdd, 0x99, 0xa2, 0x77, 0x1b, 0xa7, 0xc3, 0x5f, 0x8e, 0x7a, 0x46, 0xfd, 0x84, + 0xa5, 0x23, 0x92, 0xda, 0xfa, 0x2a, 0x2e, 0x5d, 0xf3, 0x95, 0x0b, 0x58, 0x32, 0xdd, 0x62, 0x19, + 0xbd, 0x7d, 0x3e, 0xbe, 0x47, 0x11, 0xaf, 0xaa, 0x9c, 0xb8, 0x52, 0xe9, 0x75, 0x2e, 0x27, 0x68, + 0x59, 0x3c, 0x7c, 0x6a, 0x95, 0x21, 0x40, 0x6f, 0x5f, 0xa0, 0x83, 0xa1, 0x76, 0xfb, 0x65, 0x14, + 0x9d, 0x52, 0xe1, 0xb5, 0xa9, 0xfa, 0x3c, 0x19, 0x29, 0x17, 0x15, 0x05, 0x93, 0xb7, 0x4a, 0x14, + 0x6c, 0xff, 0x18, 0xe3, 0x6e, 0x9a, 0x93, 0x42, 0x84, 0xf4, 0xd3, 0x30, 0x62, 0xcb, 0x5c, 0xa4, + 0x0d, 0x9e, 0x53, 0x2e, 0xa2, 0x7d, 0xaa, 0x40, 0x68, 0xb8, 0xd7, 0xad, 0xb1, 0x95, 0xde, 0xee, + 0x5c, 0x4d, 0xea, 0x0a, 0x12, 0x0c, 0x46, 0x04, 0x61, 0x0b, 0x37, 0x11, 0xff, 0xd8, 0xb3, 0xee, + 0x27, 0x5a, 0xc9, 0xc4, 0xb7, 0x87, 0x66, 0xa5, 0xfc, 0xd7, 0x24, 0x3a, 0xd7, 0xeb, 0x67, 0xd8, + 0x65, 0x3d, 0x22, 0x6b, 0x84, 0x26, 0x77, 0x5a, 0x02, 0x8d, 0xc1, 0x58, 0x23, 0x32, 0x39, 0x86, + 0x6a, 0x5a, 0x51, 0x1b, 0x70, 0xd2, 0x9f, 0xfa, 0x92, 0xcd, 0xeb, 0xac, 0xff, 0x2c, 0x54, 0xd8, + 0x02, 0x94, 0xdd, 0x2c, 0x92, 0x7d, 0x38, 0xe9, 0x51, 0x14, 0x73, 0xca, 0x29, 0xea, 0x5f, 0x53, + 0xaf, 0x05, 0x9b, 0xc3, 0x73, 0xbb, 0x78, 0xfc, 0x25, 0x30, 0xa7, 0x3a, 0x26, 0xb9, 0x81, 0xf8, + 0x03, 0x74, 0x9c, 0xca, 0xae, 0x11, 0xe1, 0x1e, 0xf1, 0x72, 0xaf, 0x6f, 0x47, 0x22, 0x57, 0xe3, + 0x44, 0x1c, 0xbd, 0xa7, 0x8a, 0x76, 0xbd, 0x8e, 0x13, 0x10, 0xa8, 0x9e, 0x71, 0x51, 0x26, 0x1d, + 0xc3, 0xe7, 0x54, 0xcf, 0xa8, 0x3c, 0xf4, 0x7c, 0x31, 0xfc, 0x3e, 0x92, 0x59, 0xf6, 0xeb, 0xbf, + 0xe6, 0xad, 0xe8, 0x7f, 0x63, 0xba, 0x68, 0xe9, 0x59, 0x40, 0x6a, 0xfa, 0xe4, 0xad, 0x9b, 0xb3, + 0xc7, 0x9b, 0x7d, 0x85, 0x8d, 0x57, 0x7f, 0x24, 0xac, 0x0a, 0x2f, 0x14, 0xb5, 0xf1, 0xfa, 0x65, + 0xca, 0xb0, 0x7d, 0xff, 0x75, 0x61, 0x1c, 0xdd, 0x40, 0xf5, 0x74, 0xe4, 0xe1, 0x31, 0x2b, 0x5b, + 0x73, 0x87, 0x2c, 0xda, 0xa2, 0x4d, 0xdd, 0xa0, 0xf9, 0x9d, 0x8f, 0x43, 0x83, 0x27, 0x81, 0x51, + 0x3a, 0x67, 0x1d, 0xb5, 0x0a, 0xb0, 0xb3, 0x2b, 0x9c, 0xc5, 0x20, 0xd3, 0xcd, 0x55, 0xba, 0x66, + 0xb3, 0xe5, 0xd1, 0x64, 0xa3, 0xc1, 0x54, 0x8e, 0xdd, 0xc9, 0xf2, 0x45, 0x37, 0x89, 0xea, 0xf0, + 0xa6, 0x66, 0xdc, 0x2e, 0x05, 0x9e, 0x5e, 0x63, 0x43, 0x89, 0x5a, 0xb9, 0x7c, 0xf9, 0x16, 0x54, + 0x73, 0x2d, 0x6b, 0x74, 0x5e, 0x27, 0xd2, 0x78, 0x3e, 0x66, 0xa0, 0xed, 0xba, 0x5c, 0x0b, 0x1f, + 0x46, 0x6e, 0x5e, 0xb1, 0x12, 0xf5, 0x4a, 0x8d, 0x20, 0xb9, 0x8d, 0x12, 0x9a, 0x1d, 0x3d, 0x83, + 0x95, 0xda, 0x2c, 0xf7, 0x45, 0x51, 0x6a, 0x43, 0xd6, 0x23, 0x7d, 0x41, 0x76, 0x5c, 0x33, 0x9b, + 0xb2, 0xe0, 0xf8, 0x72, 0xeb, 0x87, 0xf4, 0x01, 0xce, 0xcf, 0x8e, 0x36, 0xc7, 0x64, 0x26, 0x92, + 0x09, 0x2e, 0x66, 0xc3, 0x12, 0xa5, 0x9c, 0x49, 0xae, 0x63, 0xa0, 0xd8, 0x8f, 0x05, 0xe6, 0xe9, + 0x8d, 0x44, 0x23, 0xf8, 0x69, 0x17, 0x59, 0xd6, 0x91, 0x23, 0x99, 0x06, 0x2f, 0x08, 0x4b, 0x47, + 0x52, 0x3a, 0xd3, 0x5f, 0xe4, 0xef, 0x31, 0xc1, 0xcd, 0xa4, 0xeb, 0xa1, 0x83, 0xc8, 0xe7, 0x64, + 0x00, 0x6b, 0xbe, 0xe0, 0x7a, 0xc3, 0xe6, 0x53, 0xa8, 0x4b, 0x9d, 0xd6, 0x79, 0x49, 0xe7, 0x06, + 0x79, 0x59, 0xcd, 0x06, 0xe2, 0x48, 0x22, 0x35, 0x91, 0xd0, 0x3b, 0x13, 0xc5, 0x9d, 0x96, 0x9e, + 0x25, 0x7a, 0x42, 0x8b, 0x66, 0x03, 0xfb, 0x6b, 0xd0, 0x91, 0x5a, 0xac, 0x23, 0xbd, 0x3e, 0xab, + 0x8a, 0x7e, 0x95, 0x81, 0x0f, 0x68, 0x2f, 0x89, 0xc3, 0xb1, 0xee, 0xa2, 0x7e, 0x78, 0xf2, 0x37, + 0x35, 0xdd, 0xd9, 0xbf, 0x31, 0x9d, 0x52, 0xed, 0xeb, 0xbb, 0xaa, 0xd8, 0x33, 0x72, 0x54, 0x70, + 0xf0, 0x5e, 0xd3, 0xad, 0xfc, 0x3a, 0x74, 0x14, 0x8e, 0x7c, 0x3b, 0x85, 0x57, 0x64, 0x03, 0xa8, + 0xac, 0x37, 0x13, 0xe2, 0x0e, 0xf9, 0x89, 0x26, 0x4f, 0x3f, 0x28, 0xf7, 0xbd, 0x8a, 0x1b, 0x03, + 0xa1, 0xa9, 0x64, 0xf9, 0x16, 0x1f, 0xdc, 0xa3, 0x2f, 0xdc, 0x38, 0x62, 0xad, 0x99, 0xbd, 0x85, + 0x14, 0xaf, 0xbe, 0xd9, 0x02, 0x36, 0xd2, 0x87, 0xb5, 0x98, 0x49, 0xc7, 0xaa, 0xf2, 0x8c, 0x12, + 0xf5, 0x78, 0x6b, 0xa0, 0x2a, 0x2b, 0x7e, 0xdc, 0x21, 0x47, 0x6d, 0xf9, 0x9d, 0xf7, 0xa9, 0x3e, + 0x6b, 0x51, 0xe2, 0xb3, 0xc6, 0xf5, 0x07, 0xbc, 0x97, 0xd0, 0x7b, 0x38, 0x9a, 0xea, 0x1a, 0x75, + 0x18, 0x65, 0xed, 0x57, 0xdf, 0x0c, 0x03, 0x59, 0xc0, 0x92, 0x7e, 0x33, 0xe1, 0x8f, 0x51, 0x6b, + 0xc1, 0x58, 0x62, 0x24, 0x40, 0x93, 0x15, 0x71, 0x94, 0x7c, 0x50, 0x55, 0x7b, 0x1b, 0x40, 0x9b, + 0xc2, 0x78, 0xa2, 0xac, 0x92, 0xa1, 0x6a, 0x7b, 0x65, 0x0c, 0x33, 0x87, 0x94, 0x4d, 0x0c, 0xc9, + 0x16, 0x43, 0x46, 0x65, 0xc8, 0x7a, 0xbb, 0xa1, 0x8c, 0xa0, 0x99, 0x83, 0x7a, 0x68, 0xb9, 0x02, + 0x9f, 0x6e, 0x6d, 0x2d, 0x74, 0xbc, 0xa1, 0x3c, 0x7f, 0xef, 0xf1, 0x82, 0x04, 0xcc, 0x4a, 0x34, + 0x39, 0xa3, 0x70, 0x5f, 0xe4, 0x52, 0x82, 0xd8, 0x9b, 0x13, 0x7d, 0xba, 0x1a, 0x3b, 0x0c, 0x1e, + 0x64, 0xa5, 0x28, 0x15, 0x6b, 0x92, 0x72, 0xd7, 0xf1, 0x59, 0x76, 0x1c, 0x8d, 0x1e, 0x80, 0xf9, + 0x3f, 0xa2, 0xc9, 0x08, 0xc3, 0x73, 0xf7, 0x7f, 0xbe, 0xeb, 0x84, 0x60, 0xe0, 0x2c, 0x11, 0x9d, + 0x9f, 0x1d, 0x57, 0x06, 0x21, 0x63, 0xea, 0x2e, 0x88, 0xca, 0x5f, 0x77, 0x2b, 0x78, 0x42, 0xe8, + 0x55, 0xb4, 0xa4, 0x80, 0x97, 0xa6, 0x2c, 0x4b, 0x99, 0x37, 0xaf, 0x5c, 0xac, 0xdd, 0x7f, 0x93, + 0xcb, 0x24, 0x44, 0x87, 0x87, 0xc6, 0x7c, 0x50, 0x84, 0xbe, 0x67, 0x2e, 0x1a, 0x76, 0xfc, 0xe9, + 0xd7, 0x7e, 0xda, 0x62, 0xf9, 0x8d, 0xe9, 0x99, 0xc5, 0x0d, 0x31, 0xa5, 0x1a, 0x5e, 0x31, 0x6a, + 0x66, 0x4c, 0x6f, 0xd0, 0x84, 0x5c, 0xe1, 0x6e, 0xe6, 0x01, 0x70, 0xe7, 0x8c, 0x4c, 0x02, 0x07, + 0x53, 0x5c, 0x31, 0xf2, 0xec, 0xef, 0xcc, 0xa8, 0xbe, 0xbc, 0x25, 0x85, 0x0a, 0x8d, 0xb4, 0x4e, + 0xa6, 0x6d, 0x60, 0x9d, 0x8c, 0xb9, 0xca, 0x43, 0x2c, 0xde, 0x68, 0x60, 0x8c, 0x05, 0x76, 0x7e, + 0xbe, 0xed, 0x1e, 0x5c, 0xb3, 0x69, 0x18, 0xfe, 0x67, 0x41, 0x3b, 0xda, 0xb9, 0x40, 0x11, 0xe0, + 0x05, 0x57, 0xa6, 0x0e, 0xba, 0xd9, 0x90, 0xe4, 0x36, 0x1e, 0xaa, 0x1a, 0xb4, 0xc8, 0xe7, 0xcf, + 0x84, 0x19, 0x97, 0x47, 0xab, 0xed, 0x9a, 0x9d, 0x79, 0xdd, 0x1d, 0x68, 0x64, 0x45, 0xd4, 0xf2, + 0x8f, 0x49, 0x51, 0x72, 0x96, 0xd2, 0xb0, 0x2e, 0xbb, 0xf4, 0x02, 0x93, 0x1f, 0xd9, 0xd8, 0x8a, + 0x87, 0x61, 0x26, 0x81, 0x10, 0x19, 0xb6, 0xc5, 0xe2, 0x37, 0x1e, 0xa5, 0xe2, 0x4c, 0x05, 0x12, + 0xae, 0x62, 0xc1, 0x70, 0x93, 0x3d, 0xb8, 0xeb, 0xf5, 0xd3, 0x23, 0xe4, 0xb0, 0x5a, 0xdd, 0x6f, + 0xb7, 0x99, 0x8c, 0xd5, 0xa8, 0xea, 0x4b, 0x6c, 0x6a, 0x75, 0xd1, 0xf6, 0x55, 0x31, 0x79, 0x9d, + 0x78, 0x24, 0x2e, 0x8a, 0xe3, 0xcb, 0x38, 0x0b, 0xc0, 0xfd, 0xbd, 0xa1, 0x9f, 0x1a, 0x99, 0x97, + 0x1d, 0xb9, 0xcb, 0x27, 0xa4, 0x72, 0x1f, 0x79, 0x7e, 0x48, 0x94, 0x85, 0x93, 0x0e, 0x87, 0xf7, + 0xad, 0x5e, 0xa6, 0x05, 0x1d, 0xe5, 0x67, 0xb0, 0x5b, 0x81, 0xab, 0xfd, 0xc5, 0x1c, 0x6c, 0x4f, + 0x8f, 0xa4, 0xc0, 0x32, 0x2c, 0x53, 0xd9, 0x2a, 0x54, 0x06, 0x93, 0x12, 0x3d, 0xe7, 0xad, 0x0e, + 0xb1, 0x96, 0xa3, 0x5f, 0x92, 0xe0, 0x70, 0xa4, 0x84, 0xac, 0xb9, 0x64, 0x72, 0xab, 0xc1, 0x88, + 0x02, 0x72, 0xb6, 0x85, 0xef, 0xa8, 0x26, 0x28, 0xaf, 0x81, 0x40, 0x75, 0x99, 0xe6, 0x0a, 0x5c, + 0x55, 0x8e, 0x2e, 0xeb, 0x63, 0x3d, 0xb9, 0x1e, 0xf8, 0xe4, 0x0b, 0x50, 0xcb, 0x19, 0xe5, 0xda, + 0xaf, 0x31, 0xfe, 0x75, 0xfb, 0x6f, 0x4c, 0xcf, 0xf2, 0x45, 0x32, 0x4f, 0x68, 0x55, 0x85, 0x9e, + 0x0f, 0x19, 0x11, 0x50, 0x4d, 0xca, 0xf7, 0x19, 0x56, 0x9e, 0x8b, 0xcb, 0xce, 0xc6, 0xe1, 0x0b, + 0xd4, 0xd3, 0xe2, 0xae, 0xa7, 0x83, 0x41, 0xb1, 0xd8, 0x5f, 0x5f, 0xe2, 0xad, 0x37, 0xb9, 0x23, + 0x93, 0xd7, 0xeb, 0x65, 0x3b, 0xd7, 0xf1, 0xb3, 0x11, 0xee, 0xd4, 0x1d, 0x15, 0x6f, 0xcc, 0xaa, + 0x50, 0x4e, 0x12, 0x8b, 0x75, 0x37, 0x79, 0x82, 0xcc, 0xd6, 0x34, 0x73, 0x72, 0x16, 0x41, 0xa4, + 0x52, 0x20, 0xd9, 0xa9, 0x9e, 0x9c, 0x50, 0x61, 0xd3, 0xb1, 0xbb, 0x3e, 0x67, 0x20, 0xd6, 0x4a, + 0x15, 0x82, 0x22, 0x11, 0x86, 0xe7, 0xa5, 0xdc, 0x01, 0x52, 0xbc, 0x76, 0xd8, 0xa2, 0x32, 0x07, + 0x47, 0xb7, 0xab, 0x7c, 0x4b, 0xf9, 0x66, 0xf6, 0xa1, 0xf9, 0x21, 0x30, 0x5b, 0x15, 0xa3, 0x45, + 0xcb, 0xc9, 0x59, 0x20, 0x24, 0x28, 0xca, 0x02, 0x4a, 0x57, 0x04, 0x5a, 0x6a, 0x6b, 0x61, 0xe8, + 0x61, 0x68, 0x14, 0x8f, 0x6a, 0x76, 0x55, 0xd1, 0x5a, 0xfb, 0x98, 0x8b, 0xa4, 0xa3, 0xa2, 0xaa, + 0x30, 0x52, 0xe6, 0x39, 0x2a, 0x17, 0x67, 0x81, 0xb9, 0xfb, 0xf3, 0xc7, 0xd6, 0x1f, 0x40, 0x20, + 0x80, 0xc9, 0x9f, 0x82, 0x33, 0x2c, 0x6e, 0x5e, 0xf3, 0xd9, 0x19, 0x8b, 0x43, 0x33, 0x73, 0x52, + 0xb3, 0x23, 0x79, 0x3b, 0x4b, 0x34, 0x93, 0x1a, 0xe7, 0xc6, 0xe6, 0xa9, 0x74, 0x28, 0x70, 0x76, + 0x2d, 0xfc, 0x8e, 0x1a, 0x82, 0xc3, 0x11, 0x35, 0x67, 0xd6, 0x79, 0xd2, 0xc4, 0x57, 0xe7, 0xa3, + 0x9a, 0xd0, 0x54, 0x34, 0xea, 0x08, 0xb7, 0x73, 0xfc, 0xd2, 0x63, 0x59, 0xc4, 0x87, 0xf4, 0xb6, + 0x88, 0x61, 0x3b, 0xa4, 0x58, 0xbd, 0xbb, 0x28, 0x4f, 0x57, 0xf2, 0xaf, 0x18, 0x2c, 0xbe, 0x42, + 0xbf, 0xa4, 0x0d, 0x90, 0x6f, 0x66, 0x21, 0xcf, 0x7b, 0x84, 0xe9, 0xfb, 0x98, 0xb5, 0xbb, 0x2a, + 0xb4, 0x59, 0x53, 0x2c, 0x89, 0x02, 0xf9, 0x67, 0xca, 0x7a, 0x12, 0xdf, 0x5a, 0xde, 0xba, 0x93, + 0x1c, 0xcd, 0xf3, 0x4e, 0xee, 0x7f, 0xed, 0xa7, 0x19, 0xe0, 0x37, 0xa6, 0x57, 0xfb, 0x51, 0x8b, + 0xff, 0x55, 0x4f, 0xc4, 0xed, 0x98, 0xe0, 0xf0, 0xd0, 0x8d, 0x0a, 0x72, 0x9b, 0x93, 0x45, 0xe0, + 0x02, 0x9e, 0xff, 0x2c, 0xf3, 0xff, 0x1c, 0xf3, 0x12, 0x71, 0x4b, 0x10, 0x91, 0xf5, 0x5c, 0x86, + 0xdc, 0x58, 0xdf, 0xd4, 0xb1, 0xf1, 0x2a, 0x6a, 0x09, 0x83, 0xc7, 0xd2, 0xa3, 0x54, 0x06, 0x64, + 0x7c, 0x42, 0xc7, 0xd7, 0xcd, 0xd0, 0xa6, 0x2d, 0x07, 0x4f, 0xf5, 0xb2, 0xe9, 0xfd, 0xc7, 0x86, + 0x02, 0x9c, 0xcc, 0xe6, 0x06, 0x6b, 0x1d, 0x3a, 0xcf, 0x1b, 0x49, 0x58, 0xdc, 0x67, 0x37, 0xd2, + 0x40, 0x2d, 0xc7, 0x6b, 0x29, 0xa3, 0x7d, 0x4f, 0x3b, 0xbe, 0x09, 0xb5, 0x4b, 0x6f, 0xab, 0xb2, + 0x87, 0xc3, 0xf3, 0x61, 0x18, 0x39, 0x78, 0x6a, 0x10, 0x17, 0x49, 0x0d, 0x9f, 0x18, 0x78, 0xe6, + 0x98, 0x69, 0x89, 0xfb, 0xa9, 0x93, 0x86, 0x86, 0x3d, 0xec, 0x93, 0x01, 0xc0, 0x2c, 0xf3, 0x08, + 0x32, 0x5d, 0xc8, 0xf9, 0x10, 0xa3, 0x9a, 0xf4, 0xde, 0x57, 0xfb, 0x92, 0xa1, 0x8c, 0xbe, 0x96, + 0xe8, 0x63, 0xb8, 0xa1, 0x28, 0x16, 0xbf, 0xd5, 0x89, 0xed, 0x78, 0x63, 0x64, 0xa1, 0x46, 0x0d, + 0xb4, 0x8f, 0x74, 0x52, 0xf2, 0x67, 0x6f, 0x12, 0x7f, 0x35, 0x8e, 0xce, 0x5b, 0x76, 0x6e, 0x85, + 0x9e, 0x67, 0xab, 0x06, 0x5f, 0x8e, 0x5a, 0x78, 0xd4, 0xd0, 0x5a, 0x64, 0xab, 0x0e, 0xdb, 0xc5, + 0x44, 0x77, 0xa7, 0x25, 0x67, 0xee, 0x88, 0x31, 0xfd, 0x46, 0xa8, 0xea, 0xe5, 0x1c, 0x1a, 0x94, + 0xd6, 0xf9, 0x9e, 0xf3, 0x40, 0x34, 0xae, 0x3a, 0x00, 0x73, 0xd8, 0xb7, 0x28, 0xa7, 0x6f, 0x92, + 0xe9, 0xcf, 0x8a, 0xe1, 0xcb, 0xee, 0x49, 0x74, 0x69, 0x1f, 0xb1, 0xcc, 0x38, 0x92, 0xae, 0x95, + 0x84, 0x08, 0x3b, 0x1f, 0xd5, 0xa7, 0x07, 0x0d, 0x2a, 0x85, 0x3f, 0x9d, 0x50, 0x72, 0x5e, 0xb5, + 0xe3, 0x18, 0xb1, 0x63, 0x23, 0x6c, 0x73, 0x70, 0x51, 0x5b, 0x40, 0x93, 0x7f, 0x05, 0xc0, 0xdb, + 0x8a, 0xd1, 0x51, 0x69, 0xe9, 0x13, 0xca, 0x5f, 0x72, 0xb1, 0x64, 0x81, 0xd0, 0x6f, 0x4c, 0x0b, + 0x60, 0x7c, 0x83, 0xa3, 0xda, 0x2a, 0x7a, 0xcf, 0x7a, 0x92, 0x1e, 0x60, 0xc9, 0x38, 0x2e, 0xdf, + 0x3e, 0x83, 0x86, 0xb0, 0x59, 0x7a, 0x9e, 0xca, 0xbd, 0xc9, 0x1d, 0x96, 0xac, 0xf3, 0xe4, 0x5c, + 0x38, 0xb4, 0xa4, 0xaa, 0xad, 0x88, 0x83, 0x9c, 0x2f, 0xeb, 0x64, 0x32, 0xa5, 0x73, 0x3f, 0xf8, + 0x0f, 0x98, 0x3c, 0x30, 0xfa, 0xf2, 0x6c, 0x9b, 0xb3, 0x81, 0xde, 0x27, 0x9d, 0xdd, 0x64, 0x18, + 0x25, 0x22, 0xaf, 0x04, 0xcc, 0xd0, 0xe7, 0xdd, 0xed, 0xc1, 0x13, 0x1a, 0x2a, 0xa8, 0x3b, 0xe5, + 0xe5, 0x5e, 0x17, 0xb9, 0xb9, 0x39, 0x90, 0xac, 0x04, 0x6c, 0xf7, 0x25, 0xfc, 0x9a, 0x27, 0x0a, + 0xbf, 0x44, 0xa3, 0xf1, 0xb5, 0x31, 0x5d, 0xa5, 0xbe, 0x10, 0x19, 0x13, 0xf4, 0x84, 0x6f, 0xc4, + 0x8f, 0xd5, 0xbe, 0xa9, 0xc5, 0x9e, 0xf2, 0xa4, 0x7b, 0x8b, 0x76, 0x6c, 0x11, 0xa9, 0x74, 0x04, + 0x8d, 0x92, 0xae, 0xc9, 0x3f, 0x6b, 0x5a, 0xdf, 0x64, 0x19, 0x00, 0x8f, 0x37, 0xb4, 0x45, 0x15, + 0xa5, 0x5c, 0x2f, 0xc8, 0x5d, 0xaa, 0x87, 0xa1, 0x10, 0x37, 0x85, 0x9c, 0x2b, 0xd9, 0xaa, 0x6f, + 0x64, 0x5e, 0xf7, 0x42, 0xfd, 0x54, 0x05, 0xd9, 0xad, 0xb9, 0x0c, 0x67, 0x8c, 0xa8, 0x7c, 0x8b, + 0x18, 0x6a, 0x9f, 0xf0, 0x58, 0x25, 0x30, 0x52, 0x24, 0x65, 0xcd, 0xa4, 0xd6, 0x84, 0x11, 0xbd, + 0xf0, 0xc0, 0x50, 0x00, 0xd0, 0xda, 0x21, 0xb9, 0x55, 0x0b, 0x84, 0x28, 0xf8, 0xb2, 0xcf, 0xb9, + 0x5d, 0xe9, 0xdc, 0x43, 0x6c, 0x9d, 0xb2, 0xef, 0x49, 0x4c, 0x64, 0xc1, 0x72, 0xe1, 0xae, 0x13, + 0x7e, 0xc9, 0xd3, 0x91, 0xa0, 0xe1, 0x06, 0xdf, 0xc5, 0x17, 0x19, 0x44, 0xdb, 0x68, 0x2e, 0x12, + 0x7e, 0xf8, 0x30, 0x30, 0x6f, 0xdb, 0x58, 0xa9, 0xfe, 0x00, 0x36, 0x02, 0x15, 0xa4, 0x40, 0x2e, + 0xdc, 0x80, 0x60, 0x0d, 0x1e, 0xcf, 0xb7, 0x8d, 0x4a, 0x6e, 0x4e, 0x07, 0xc8, 0x83, 0x40, 0xd7, + 0x4c, 0x81, 0x78, 0xc1, 0xd4, 0x1d, 0xbe, 0x31, 0x07, 0xbf, 0xfc, 0x87, 0x49, 0x86, 0x22, 0xbf, + 0x31, 0xbd, 0xb4, 0x2a, 0x05, 0x00, 0x3b, 0xbf, 0xea, 0x83, 0x40, 0x87, 0xbb, 0x5f, 0x5e, 0x95, + 0xac, 0x93, 0x8d, 0x90, 0x53, 0x52, 0x0b, 0x4c, 0x49, 0x24, 0xb6, 0x48, 0x34, 0x24, 0xdb, 0x46, + 0xb9, 0x22, 0xe5, 0x23, 0x7e, 0xde, 0xed, 0x0d, 0x53, 0x39, 0xab, 0xd6, 0x68, 0x9f, 0x12, 0x4b, + 0xd6, 0xd0, 0x96, 0x68, 0x3d, 0xec, 0xa6, 0xc0, 0x03, 0xfa, 0x88, 0x2b, 0xc2, 0xea, 0xce, 0x0d, + 0x89, 0xa5, 0xe2, 0x03, 0x66, 0xb3, 0xf5, 0x74, 0xd3, 0xd0, 0x05, 0xa0, 0x1b, 0x61, 0x14, 0x0d, + 0x97, 0x15, 0x9d, 0xae, 0x6e, 0xe6, 0x0f, 0x2f, 0xbe, 0x3e, 0x89, 0x3c, 0x93, 0x5c, 0x0d, 0xf6, + 0x17, 0xf1, 0x66, 0x68, 0x59, 0x3d, 0x73, 0xd8, 0xd2, 0x57, 0x05, 0xae, 0x04, 0xbf, 0x2a, 0xa0, + 0x6b, 0xd6, 0xe1, 0x0b, 0xaa, 0x56, 0xb9, 0x1a, 0xc1, 0xd7, 0x9f, 0x57, 0x01, 0x6d, 0x89, 0x7e, + 0xce, 0xb6, 0x05, 0xab, 0x28, 0xa4, 0x96, 0x8b, 0x7a, 0xdb, 0x99, 0x71, 0xcc, 0xb7, 0x8e, 0x87, + 0x7b, 0xfc, 0x3e, 0xb9, 0x42, 0xf4, 0x25, 0x88, 0x45, 0x29, 0x21, 0xa1, 0x82, 0x0a, 0xab, 0x1c, + 0xe6, 0xb9, 0x05, 0xf2, 0xb2, 0x0c, 0x94, 0xc8, 0xd4, 0x07, 0xeb, 0x45, 0xdd, 0xc7, 0x5e, 0x64, + 0xe8, 0xc7, 0x40, 0x76, 0x7b, 0x88, 0xe7, 0xe3, 0x44, 0x80, 0x25, 0xd2, 0x22, 0xcf, 0x49, 0x8b, + 0xcc, 0xd9, 0x0d, 0x2d, 0x08, 0x9e, 0xde, 0x1a, 0xa9, 0xaa, 0x1e, 0x48, 0xcd, 0x24, 0x2e, 0x4f, + 0x26, 0x29, 0x55, 0xcc, 0x99, 0x02, 0xe6, 0x00, 0xfd, 0x39, 0x5a, 0x01, 0xdc, 0x3f, 0x6a, 0x59, + 0xaa, 0xc2, 0xdc, 0xf2, 0x09, 0x50, 0x97, 0xd1, 0x39, 0x24, 0x5d, 0x7b, 0xe5, 0x05, 0x42, 0x67, + 0x5b, 0x85, 0xb7, 0xf2, 0xa6, 0xee, 0x6a, 0xb4, 0x5d, 0x2c, 0x2b, 0x20, 0x1f, 0x32, 0x8d, 0x6b, + 0x02, 0xce, 0xbc, 0x63, 0x1b, 0xb7, 0x80, 0xb2, 0x8c, 0xef, 0x73, 0x2c, 0xae, 0x91, 0xcf, 0xdd, + 0x56, 0xea, 0x7f, 0x06, 0xe1, 0x67, 0x5f, 0x46, 0x7b, 0x6b, 0xbc, 0xfc, 0xb5, 0x06, 0x25, 0x74, + 0xf3, 0x1b, 0xd3, 0xdc, 0x9b, 0xbe, 0x46, 0x07, 0x22, 0x1b, 0x26, 0x14, 0xd0, 0x5a, 0x8c, 0x2e, + 0x6e, 0x41, 0xa6, 0xb8, 0xa0, 0xf1, 0x9a, 0xb8, 0x6e, 0x8c, 0x92, 0xb6, 0x9d, 0xea, 0x08, 0x7a, + 0x2d, 0x2f, 0xe7, 0x05, 0x2e, 0x77, 0x5f, 0xae, 0x1b, 0x18, 0xd0, 0xd1, 0x50, 0x31, 0x72, 0x22, + 0xbb, 0x17, 0xed, 0x54, 0x16, 0x14, 0x1f, 0xd9, 0xcd, 0xd9, 0x57, 0x72, 0x3c, 0x77, 0x50, 0x27, + 0xa5, 0x5a, 0xef, 0xf0, 0x54, 0x56, 0xdd, 0x79, 0xa1, 0x6e, 0x79, 0x45, 0xb0, 0x35, 0xb2, 0xc2, + 0x98, 0x8c, 0xfb, 0xa3, 0xb8, 0xe1, 0x94, 0xb7, 0xbf, 0x3a, 0x29, 0x79, 0xdf, 0xe2, 0x3e, 0x8a, + 0x18, 0xf1, 0xcb, 0x1f, 0xaf, 0xfd, 0x84, 0xbf, 0xb5, 0x90, 0x2d, 0x74, 0xc9, 0x88, 0x39, 0xb6, + 0x56, 0x82, 0x63, 0x51, 0xa4, 0x6f, 0x24, 0x2c, 0x30, 0x6c, 0xd1, 0xee, 0x97, 0xca, 0xf5, 0xb8, + 0xff, 0xb8, 0xa6, 0x8d, 0x32, 0x2f, 0xd5, 0x46, 0xe7, 0x8a, 0x52, 0x8f, 0x5d, 0xbd, 0xa0, 0xf6, + 0x9a, 0xea, 0xc4, 0x97, 0x98, 0x59, 0x20, 0x7e, 0x54, 0x21, 0x99, 0xda, 0x3f, 0x2a, 0x38, 0xff, + 0xd9, 0x37, 0x2a, 0xe7, 0x37, 0xf4, 0xaa, 0xe8, 0xe9, 0x85, 0xbf, 0x63, 0xf3, 0x9d, 0xd7, 0xcf, + 0xcd, 0x27, 0x01, 0x79, 0xa5, 0x25, 0x98, 0xb4, 0xdb, 0x04, 0xb6, 0xe1, 0x9b, 0x5f, 0x68, 0xd3, + 0x4a, 0xd2, 0x84, 0x3a, 0x7a, 0x48, 0xdc, 0x16, 0xc0, 0xc6, 0x29, 0xcb, 0xa6, 0x6f, 0x03, 0x73, + 0x43, 0x5b, 0xbc, 0x9f, 0x0d, 0xaa, 0xb6, 0x6a, 0xc3, 0xa4, 0xd0, 0xd2, 0x88, 0xdc, 0x99, 0xd8, + 0x53, 0xa3, 0xcc, 0x23, 0x8d, 0x6c, 0x77, 0xb4, 0xdd, 0xbb, 0xdb, 0x20, 0xa7, 0x2f, 0x56, 0x6d, + 0x70, 0xd9, 0xec, 0x1e, 0xdd, 0x26, 0xe7, 0x23, 0xb6, 0xc4, 0x70, 0xd8, 0x36, 0x3c, 0x75, 0x75, + 0xca, 0xc7, 0xe6, 0x38, 0x7b, 0xd1, 0x5c, 0x9c, 0x45, 0x6e, 0x77, 0xf0, 0xa2, 0x56, 0xda, 0x64, + 0x45, 0x4d, 0x2a, 0x4d, 0x7d, 0x09, 0xcc, 0x9d, 0xa6, 0x6e, 0xb6, 0x4c, 0x9b, 0xbf, 0xf6, 0x1e, + 0x50, 0xfe, 0x37, 0xa6, 0xe5, 0x83, 0xf5, 0xd3, 0x23, 0xde, 0xe4, 0xf6, 0x0d, 0xcf, 0x66, 0x63, + 0xd1, 0xab, 0xa0, 0xca, 0xb9, 0xe3, 0x6e, 0x1b, 0x14, 0x9b, 0x49, 0x3d, 0x5a, 0x39, 0x2e, 0xab, + 0x53, 0x03, 0x30, 0x93, 0x49, 0xe5, 0x6b, 0xa9, 0x59, 0xae, 0x0d, 0x5c, 0x8e, 0xf2, 0x0b, 0x6f, + 0x4d, 0xfe, 0x6d, 0x51, 0xbd, 0x5b, 0xe3, 0x02, 0x46, 0x75, 0xc8, 0x81, 0x81, 0xaa, 0xc0, 0x74, + 0x42, 0x37, 0xfd, 0xfa, 0xb6, 0x61, 0xf8, 0xf1, 0xfa, 0x1c, 0x7b, 0x23, 0x6e, 0x6d, 0x26, 0xcd, + 0x54, 0x98, 0xce, 0x5d, 0xe0, 0x05, 0x17, 0x74, 0x5e, 0x65, 0x32, 0xc4, 0xe3, 0x4f, 0xbf, 0x0f, + 0x95, 0xc3, 0x61, 0x15, 0x8d, 0x30, 0x88, 0xc3, 0xf9, 0x42, 0x05, 0xef, 0xbf, 0xf9, 0x1a, 0x23, + 0xd3, 0x55, 0x17, 0x68, 0x58, 0xe2, 0xd6, 0x50, 0x8d, 0x27, 0xae, 0xb7, 0x72, 0xd1, 0x9a, 0xc6, + 0x96, 0xcd, 0x9f, 0x30, 0x65, 0x22, 0x4e, 0xc5, 0x6a, 0x5b, 0xce, 0x03, 0x8f, 0x2a, 0xfb, 0x4a, + 0xf9, 0x42, 0x1a, 0x82, 0xef, 0xe9, 0x70, 0x24, 0xb4, 0xff, 0x64, 0x4c, 0x79, 0x32, 0x75, 0xb6, + 0xbc, 0x6f, 0x53, 0x6e, 0x38, 0x9c, 0xdd, 0x93, 0xfa, 0xec, 0x6e, 0x50, 0x4b, 0x2d, 0x16, 0x23, + 0x41, 0xe7, 0xc2, 0xf1, 0x79, 0xb6, 0xbb, 0xf8, 0xf4, 0xb6, 0x32, 0x81, 0x5d, 0x23, 0x37, 0xc3, + 0xee, 0xf5, 0x9b, 0x13, 0x6e, 0xb6, 0xfb, 0x79, 0x8e, 0x87, 0x0e, 0x14, 0xad, 0x71, 0xd1, 0x0f, + 0xbd, 0xaa, 0x3a, 0x1b, 0xe0, 0x8a, 0x2c, 0xd1, 0x05, 0x15, 0xb2, 0xec, 0xc5, 0x38, 0xf4, 0xbc, + 0x76, 0x7a, 0x6a, 0x9b, 0xb1, 0x5c, 0x24, 0x2d, 0x99, 0xb8, 0x6d, 0x4a, 0x00, 0xde, 0x3d, 0x1d, + 0xf1, 0x4d, 0xc9, 0xd3, 0x48, 0xde, 0x4a, 0xf8, 0xf4, 0x79, 0x9e, 0x0c, 0x76, 0x34, 0xb0, 0xdb, + 0xed, 0x71, 0x9a, 0x58, 0x1b, 0x79, 0xab, 0x7b, 0x1d, 0xdd, 0x42, 0x27, 0x89, 0x67, 0x66, 0x99, + 0xb0, 0x47, 0x3a, 0x1c, 0xa1, 0x89, 0x4d, 0xac, 0xc9, 0xc3, 0xba, 0xb3, 0x22, 0xa3, 0xb0, 0xfd, + 0x6b, 0xef, 0x51, 0x4f, 0xfd, 0xc6, 0x34, 0x98, 0x17, 0x4e, 0x32, 0x33, 0xe9, 0x6f, 0x75, 0x3c, + 0xdf, 0x11, 0xc2, 0x3d, 0x74, 0xa6, 0xa7, 0x99, 0xcd, 0xff, 0xf0, 0xc4, 0xaa, 0x23, 0xe0, 0xc0, + 0xc0, 0x18, 0x86, 0x1e, 0x27, 0xad, 0x48, 0xe4, 0x5c, 0x7d, 0xcd, 0x27, 0xc1, 0x6b, 0xa3, 0xb0, + 0xfa, 0x97, 0x3b, 0x00, 0xf2, 0x0f, 0x64, 0x2b, 0x44, 0xde, 0xb1, 0xf9, 0xbd, 0x69, 0xb1, 0x90, + 0x64, 0x0f, 0x20, 0x77, 0x4e, 0xb0, 0xe7, 0xec, 0x86, 0x32, 0x51, 0xc4, 0x4e, 0xc2, 0x04, 0xb9, + 0x67, 0xd9, 0xe2, 0x5a, 0x5f, 0x90, 0x52, 0xbd, 0xe3, 0x09, 0x2e, 0x8c, 0xa6, 0xa5, 0x6b, 0xa4, + 0xe1, 0xee, 0xc0, 0xf8, 0x75, 0x91, 0xb3, 0x53, 0xf2, 0x2a, 0xe1, 0x38, 0xc3, 0xca, 0x6a, 0x0f, + 0x46, 0x4a, 0xf6, 0x8f, 0x8c, 0xd8, 0xbb, 0xe9, 0x74, 0xab, 0x46, 0x0b, 0xb2, 0x8b, 0x67, 0xfc, + 0xc6, 0x7a, 0xba, 0x0b, 0xd5, 0xf2, 0x87, 0x74, 0xea, 0xd6, 0x8a, 0x8d, 0x32, 0x4b, 0xa2, 0x3c, + 0xcd, 0x59, 0x76, 0xf1, 0x88, 0x5e, 0x3f, 0x0a, 0x3c, 0xd1, 0x55, 0x80, 0x97, 0xd4, 0xf7, 0x8b, + 0xde, 0x4a, 0x90, 0x6e, 0x39, 0x9c, 0x41, 0x8e, 0x0a, 0xf2, 0xad, 0xb4, 0x27, 0xb9, 0x7a, 0x69, + 0x64, 0x4d, 0xaa, 0xb7, 0x5a, 0xaa, 0xec, 0x7f, 0x56, 0x03, 0x90, 0xac, 0x94, 0x4a, 0xad, 0xd5, + 0x5b, 0x91, 0x81, 0xd6, 0xf9, 0xd0, 0x10, 0x9a, 0x33, 0xd5, 0x4a, 0x5e, 0x19, 0x0b, 0xe7, 0xda, + 0x23, 0x5b, 0x9a, 0x8a, 0x00, 0x9b, 0xf5, 0xcf, 0x31, 0x6d, 0x17, 0xbf, 0x36, 0xde, 0x6d, 0x13, + 0x48, 0x2f, 0xe7, 0x5a, 0xe8, 0x98, 0x7b, 0x13, 0xd7, 0xaa, 0x52, 0x0a, 0x68, 0x84, 0x32, 0x71, + 0xff, 0xe1, 0x46, 0x17, 0xb9, 0xf0, 0x44, 0xff, 0x20, 0x2a, 0xb5, 0x15, 0x70, 0xfd, 0xea, 0x81, + 0x30, 0x18, 0x6a, 0x5c, 0x38, 0xfe, 0x84, 0xe8, 0x14, 0x15, 0x95, 0xe2, 0x72, 0x7c, 0x97, 0x95, + 0x44, 0x68, 0xa1, 0x94, 0xfc, 0xb3, 0x9e, 0x44, 0xdc, 0x9d, 0x8c, 0x39, 0x3d, 0xf8, 0x92, 0xf8, + 0x51, 0x34, 0xfe, 0x37, 0xee, 0x6e, 0x03, 0x04, 0x58, 0xbf, 0xb9, 0x87, 0x53, 0x88, 0x0f, 0x36, + 0xaa, 0xee, 0x1f, 0xf0, 0xf9, 0xcd, 0xb7, 0x8e, 0x4e, 0x51, 0xef, 0xda, 0xce, 0x3b, 0xf9, 0xb7, + 0x9c, 0x7e, 0x99, 0x2e, 0x47, 0x64, 0xc7, 0x19, 0x49, 0x2d, 0x02, 0x3b, 0xba, 0x27, 0x6f, 0xb6, + 0xf2, 0x4c, 0x5c, 0x4f, 0xa7, 0x26, 0x89, 0xee, 0x4a, 0x55, 0x79, 0x6c, 0x9b, 0x67, 0x0f, 0x60, + 0x6f, 0x53, 0xc5, 0x93, 0x65, 0x94, 0xaf, 0xf4, 0x2d, 0x5e, 0x93, 0x71, 0x6f, 0xa1, 0x2d, 0x43, + 0x64, 0xf4, 0x05, 0x62, 0x13, 0x57, 0xc1, 0xa7, 0x60, 0x18, 0x7b, 0xeb, 0xd2, 0xaf, 0x89, 0x2e, + 0x3a, 0x1b, 0x8a, 0x19, 0x3b, 0xbc, 0xc8, 0xc9, 0x55, 0xcd, 0x01, 0xef, 0x59, 0x96, 0x49, 0x23, + 0xb2, 0x76, 0xa4, 0x1a, 0xaf, 0x27, 0x7a, 0x79, 0xc6, 0x96, 0xac, 0x20, 0x0c, 0xd3, 0x59, 0x41, + 0xff, 0x78, 0xea, 0xfe, 0x73, 0x28, 0x13, 0x20, 0x21, 0x92, 0x38, 0x96, 0x05, 0x57, 0x18, 0x8b, + 0xb9, 0x55, 0x67, 0xa7, 0x21, 0xdd, 0xb5, 0x62, 0x8f, 0x0c, 0x2e, 0xbd, 0x79, 0x4b, 0xd5, 0x96, + 0x22, 0x13, 0xf1, 0xe7, 0xdb, 0x80, 0x35, 0x24, 0xc3, 0xaf, 0x75, 0x6c, 0x51, 0xd5, 0xe9, 0x82, + 0xf8, 0xf2, 0x6f, 0xd8, 0x67, 0xe9, 0x6a, 0xed, 0xf2, 0x8d, 0x4e, 0x65, 0x3b, 0xd0, 0xb9, 0x19, + 0xd3, 0x3f, 0xde, 0x72, 0x4a, 0x64, 0x73, 0xeb, 0xe7, 0xd8, 0xe8, 0x6d, 0x3f, 0x83, 0x7d, 0x7d, + 0x6a, 0x0c, 0x9c, 0x3f, 0x75, 0xec, 0x6e, 0x54, 0xc6, 0x4a, 0x39, 0x07, 0x7f, 0xe6, 0x4d, 0xd7, + 0x52, 0x8c, 0x10, 0x75, 0xac, 0x93, 0x2d, 0x59, 0x1a, 0xf5, 0x4c, 0xac, 0x46, 0xcc, 0x10, 0x79, + 0x75, 0x6b, 0xab, 0x23, 0xb1, 0xf3, 0xad, 0xfc, 0x6a, 0xcf, 0xbf, 0x52, 0xa2, 0xb8, 0x28, 0x5a, + 0x93, 0x59, 0xb7, 0x3d, 0x97, 0x89, 0x6e, 0xa4, 0xce, 0xb9, 0x75, 0x15, 0x11, 0xb2, 0x98, 0xd6, + 0xfa, 0xfb, 0x96, 0x16, 0x78, 0xf6, 0x00, 0x3b, 0x62, 0x7d, 0xdd, 0x94, 0x31, 0x6b, 0xdb, 0x4b, + 0xc9, 0x41, 0x08, 0xbc, 0xdd, 0x7a, 0x8a, 0xfc, 0x9a, 0x61, 0x8e, 0xce, 0xfe, 0xc6, 0xb4, 0x46, + 0x79, 0xe8, 0x9b, 0x45, 0x51, 0xfe, 0xb1, 0x2f, 0x94, 0xd7, 0x1e, 0x7b, 0x57, 0xc3, 0x25, 0xb7, + 0x3f, 0x34, 0xa7, 0x73, 0xbc, 0x54, 0x56, 0x75, 0x07, 0x9a, 0x65, 0x31, 0xd4, 0xf5, 0xa4, 0xf2, + 0x6d, 0x73, 0x79, 0x4a, 0xe0, 0x80, 0xd4, 0xc2, 0x96, 0xf8, 0xe5, 0x2c, 0x14, 0xd2, 0x86, 0xe1, + 0x2d, 0x89, 0xc2, 0x79, 0xc2, 0xe4, 0xc4, 0x4f, 0x87, 0xf0, 0xb4, 0x36, 0xe1, 0x9d, 0xc9, 0x79, + 0x4b, 0xe8, 0xc7, 0x74, 0x71, 0xf3, 0x2c, 0xd4, 0xd2, 0xee, 0xc3, 0x33, 0xab, 0xc7, 0xe9, 0xc0, + 0x79, 0x48, 0xb6, 0x1e, 0x9a, 0xc9, 0x14, 0xd7, 0xbd, 0xd3, 0xed, 0xe3, 0x18, 0xd4, 0xd6, 0x69, + 0x33, 0xe9, 0xa4, 0x09, 0x6e, 0x92, 0xf3, 0x62, 0xe9, 0xc6, 0x15, 0x26, 0x4a, 0x60, 0xda, 0x21, + 0xcf, 0xd1, 0x68, 0xe6, 0xf8, 0xb6, 0xd8, 0x65, 0x11, 0xdc, 0x9f, 0xec, 0xf4, 0x45, 0x12, 0x54, + 0xfd, 0x59, 0x08, 0x9c, 0x20, 0x9b, 0xa8, 0x48, 0x3a, 0x0c, 0xb8, 0xda, 0x89, 0xe0, 0xc7, 0x70, + 0x61, 0xad, 0x8e, 0x8a, 0xc1, 0x7a, 0x2a, 0xc0, 0x53, 0x84, 0x03, 0x1f, 0xc3, 0x0a, 0xfd, 0x51, + 0x88, 0xbb, 0x16, 0xab, 0xeb, 0xc2, 0x7f, 0x1d, 0xa2, 0x1c, 0xa9, 0x44, 0x1a, 0x98, 0x92, 0xee, + 0xe1, 0xbd, 0x70, 0x8e, 0xd8, 0xf1, 0xf0, 0x52, 0xe1, 0x1d, 0x7a, 0x49, 0x62, 0x7e, 0x09, 0xf2, + 0x44, 0xd2, 0x33, 0x0f, 0x4d, 0xad, 0x9f, 0x7e, 0x41, 0xf9, 0xed, 0xfd, 0xff, 0x54, 0x87, 0x2f, + 0x8d, 0x66, 0x65, 0xed, 0xcb, 0xc0, 0x66, 0x5b, 0x4a, 0x40, 0x16, 0x01, 0x20, 0x4b, 0x1a, 0x72, + 0xd2, 0x06, 0x0a, 0xf0, 0xef, 0xd6, 0xae, 0x86, 0x29, 0x69, 0x09, 0x07, 0x74, 0xf1, 0x7d, 0x48, + 0x0f, 0xf0, 0xcf, 0xc2, 0x5d, 0xa5, 0x6f, 0x50, 0x97, 0xe6, 0x24, 0x87, 0x38, 0x57, 0x22, 0x5b, + 0xab, 0x09, 0xf8, 0x00, 0x0e, 0xd8, 0x05, 0x92, 0x63, 0x34, 0x25, 0x07, 0xa0, 0x34, 0xa9, 0xc2, + 0x0f, 0x71, 0x76, 0xce, 0x7c, 0xe2, 0xc7, 0x44, 0x17, 0xcc, 0xaf, 0x33, 0x75, 0x68, 0xf5, 0x37, + 0xa6, 0xb5, 0x2a, 0x2c, 0x8d, 0x81, 0x79, 0x91, 0xb5, 0x71, 0xae, 0x1c, 0xca, 0xae, 0x97, 0x61, + 0xad, 0xc6, 0x05, 0x12, 0x4a, 0x53, 0xa4, 0xd7, 0xb9, 0xa8, 0xb7, 0xda, 0xd9, 0x9a, 0x39, 0xcb, + 0xcc, 0x0f, 0x25, 0xde, 0x0a, 0x11, 0xab, 0x3b, 0x68, 0xdc, 0x05, 0x53, 0x9c, 0x81, 0x0e, 0x24, + 0xb7, 0xec, 0xe9, 0xee, 0x43, 0x19, 0x2f, 0x35, 0x77, 0x51, 0xce, 0xc8, 0x55, 0x4a, 0x25, 0xbf, + 0x51, 0xe7, 0xcd, 0x4f, 0x1e, 0xbd, 0x6e, 0xe3, 0x3e, 0xef, 0xa4, 0xc3, 0xe0, 0x05, 0x73, 0x99, + 0x12, 0x7b, 0x24, 0xb2, 0xd1, 0xaa, 0x3b, 0x6e, 0xcf, 0xaa, 0xbc, 0x81, 0x53, 0xe7, 0x8a, 0x57, + 0xc9, 0x9e, 0x32, 0xe0, 0x4f, 0x58, 0xc0, 0x69, 0xdd, 0x78, 0xa8, 0x9b, 0x25, 0x00, 0xc5, 0x0e, + 0x47, 0xc4, 0xa1, 0x49, 0x36, 0x96, 0xf6, 0x8d, 0xe4, 0x69, 0xcd, 0x74, 0x8d, 0xbc, 0x53, 0x79, + 0xab, 0xb6, 0xe3, 0x09, 0x67, 0xe5, 0x47, 0x47, 0x63, 0xc5, 0xb9, 0xde, 0x46, 0x2a, 0xa8, 0x03, + 0x8e, 0xbb, 0x43, 0x53, 0x31, 0xe9, 0x35, 0x98, 0x0b, 0x6f, 0x6b, 0xbd, 0x9b, 0x67, 0xcd, 0x9f, + 0x5d, 0x09, 0x73, 0x58, 0x6d, 0xca, 0xf7, 0x71, 0x99, 0x65, 0xf9, 0xa2, 0x57, 0xd7, 0x53, 0xd9, + 0xa8, 0xee, 0xc3, 0xbd, 0xff, 0xfc, 0x1c, 0xe5, 0x1c, 0xf8, 0xc0, 0xd6, 0xdc, 0xf0, 0x22, 0xd9, + 0x1a, 0x8f, 0x8c, 0x3a, 0x05, 0xc8, 0x77, 0x96, 0xeb, 0x78, 0xb8, 0xc3, 0x2d, 0x8b, 0xc8, 0xcd, + 0x94, 0xc3, 0xf8, 0xad, 0x09, 0x0b, 0x6c, 0x06, 0x67, 0xaf, 0x0e, 0x50, 0xf7, 0x65, 0xbd, 0x2d, + 0xf6, 0x86, 0x2d, 0x91, 0x17, 0xd1, 0x8e, 0x8d, 0x65, 0x49, 0xae, 0x8f, 0x39, 0xa3, 0x68, 0x54, + 0x43, 0xdc, 0x6f, 0x8f, 0xab, 0xcf, 0xf1, 0xfe, 0x49, 0x4b, 0xbc, 0x5b, 0xb7, 0x14, 0x9e, 0x8d, + 0x9a, 0x23, 0xea, 0x46, 0x6a, 0x3e, 0x6a, 0x8a, 0x00, 0xfc, 0x08, 0xc3, 0x9f, 0xdc, 0xc7, 0x34, + 0xb7, 0xa8, 0x76, 0x51, 0x56, 0xef, 0x61, 0x76, 0xb4, 0xec, 0xea, 0x41, 0xef, 0xf9, 0xc1, 0xef, + 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, + 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, + 0xce, 0x3b, 0xff, 0x7b, 0xf2, 0x9f, 0xef, 0x83, 0xd3, 0xb9, 0xe2, 0xba, 0x57, 0xd1, 0xb0, 0x79, + 0x8d, 0xd5, 0xcc, 0x4d, 0xb6, 0x39, 0x9d, 0xc9, 0x0f, 0xad, 0x6d, 0xcc, 0x24, 0x0a, 0xc8, 0xec, + 0x76, 0x31, 0x25, 0xdb, 0x9c, 0x38, 0xd4, 0xe5, 0x42, 0x39, 0x3f, 0x42, 0x16, 0xe8, 0xf5, 0x7a, + 0x17, 0xc8, 0x1e, 0xf6, 0x0d, 0xe9, 0x7b, 0xdb, 0x05, 0x9c, 0xa7, 0xee, 0x95, 0xdd, 0xce, 0xd2, + 0xd5, 0x63, 0x40, 0xea, 0xea, 0x2a, 0xd9, 0x4d, 0x53, 0x41, 0xe6, 0x66, 0x68, 0xaa, 0x99, 0xa1, + 0xf8, 0xf7, 0xeb, 0xb8, 0x63, 0x35, 0x71, 0x7f, 0x1e, 0x58, 0xcc, 0xab, 0x33, 0x34, 0xeb, 0x01, + 0xeb, 0x4d, 0x38, 0x6d, 0x2f, 0x59, 0xa1, 0x0b, 0x6f, 0x4e, 0x0d, 0x2d, 0x92, 0x04, 0xb8, 0x65, + 0x95, 0xfa, 0x21, 0x9f, 0xc0, 0x54, 0x7f, 0x13, 0x3b, 0x8a, 0xc8, 0xff, 0x3e, 0xbf, 0x90, 0xf3, + 0x1c, 0x8d, 0x0c, 0x29, 0xbc, 0x10, 0x5d, 0x94, 0xe1, 0x50, 0x60, 0xbb, 0x9b, 0x1b, 0x5a, 0x27, + 0xb5, 0x90, 0x05, 0x39, 0xa9, 0x0f, 0x77, 0xae, 0x68, 0x8d, 0x29, 0x9e, 0xb8, 0x0a, 0x9a, 0x63, + 0x62, 0xf7, 0x35, 0x26, 0xec, 0x70, 0x9c, 0xb0, 0x74, 0x34, 0x43, 0xe6, 0x2f, 0x23, 0x4f, 0xd1, + 0x94, 0x27, 0x1e, 0x58, 0xb5, 0x4a, 0xf5, 0xd0, 0x67, 0x98, 0xd6, 0xd0, 0x37, 0xe1, 0x88, 0xf5, + 0x7a, 0xd1, 0x82, 0x37, 0xe0, 0x71, 0x79, 0xc3, 0x7b, 0x81, 0x0f, 0x9c, 0x86, 0x9a, 0x1d, 0x7f, + 0x56, 0x73, 0x2b, 0x0a, 0x7f, 0xbf, 0x36, 0xcf, 0xba, 0x35, 0xda, 0x22, 0x58, 0x2f, 0x3d, 0x16, + 0x54, 0xaf, 0x37, 0x7c, 0xf9, 0xbe, 0xe1, 0xb5, 0x92, 0x9f, 0xfe, 0xaa, 0xe1, 0xcc, 0x47, 0x78, + 0x9d, 0xcc, 0x94, 0xf6, 0x5b, 0xdd, 0x42, 0x09, 0x84, 0xfe, 0x74, 0x2e, 0xf7, 0xd5, 0xb3, 0xac, + 0x1f, 0xc5, 0x47, 0x20, 0xaf, 0x72, 0x75, 0xd7, 0xcb, 0xc9, 0x90, 0x52, 0x8d, 0x63, 0xd3, 0x53, + 0x8b, 0x34, 0xbd, 0x73, 0xde, 0x68, 0x7d, 0x3a, 0xbc, 0x9a, 0xa8, 0xc6, 0x1b, 0x51, 0x7b, 0xa4, + 0x88, 0x8c, 0xa6, 0x61, 0x49, 0x47, 0x79, 0x24, 0x12, 0xf9, 0xe3, 0x29, 0x83, 0x49, 0x5a, 0xef, + 0x8d, 0x63, 0xfb, 0x17, 0xde, 0x48, 0x9e, 0x8c, 0x6b, 0x74, 0xdc, 0x08, 0x83, 0xd4, 0xa5, 0xd1, + 0xd3, 0xe4, 0x79, 0x8f, 0x6f, 0x22, 0x7b, 0xda, 0xdc, 0x64, 0x91, 0x74, 0x0e, 0x87, 0x8d, 0x86, + 0xde, 0x8d, 0x9e, 0xe1, 0xc0, 0xdd, 0x86, 0xa1, 0x29, 0xa2, 0x82, 0xac, 0xac, 0x35, 0x7d, 0x7a, + 0x1e, 0x36, 0x82, 0xfb, 0x50, 0xf6, 0x16, 0xdd, 0xf7, 0x32, 0x5a, 0xdf, 0xc0, 0x08, 0xb2, 0x7c, + 0x4e, 0x84, 0xad, 0xdb, 0x27, 0x5d, 0x1c, 0xfe, 0x00, 0x76, 0x6a, 0xa6, 0xf7, 0x65, 0xb6, 0x31, + 0x4c, 0xa9, 0x8f, 0xfa, 0x22, 0x6f, 0x50, 0x9d, 0xcb, 0x64, 0x6c, 0x7f, 0x86, 0x87, 0xfd, 0x20, + 0x25, 0x23, 0xa3, 0xa6, 0x93, 0x57, 0xb1, 0x37, 0x82, 0xff, 0x1a, 0x67, 0x77, 0xf3, 0x1b, 0xd3, + 0x5c, 0xbb, 0x25, 0x72, 0xea, 0xe4, 0x5f, 0x45, 0xbf, 0xca, 0x4d, 0xe0, 0x65, 0xbb, 0x29, 0xd0, + 0x63, 0x6a, 0xb9, 0x63, 0xfd, 0x32, 0x25, 0x54, 0x11, 0x4f, 0xa3, 0x69, 0x1e, 0x78, 0x52, 0x9b, + 0x97, 0x55, 0x21, 0x15, 0x35, 0x1b, 0x79, 0xea, 0xcf, 0xb3, 0xda, 0xbb, 0x2d, 0x3d, 0xe6, 0xeb, + 0xcc, 0x64, 0x89, 0x67, 0x3d, 0x54, 0x06, 0xe8, 0x0c, 0x2d, 0xd2, 0x23, 0x1b, 0x5f, 0xb7, 0x8a, + 0x55, 0x49, 0x89, 0xbe, 0x29, 0xd8, 0xec, 0xbd, 0xca, 0xc8, 0x98, 0x46, 0xc3, 0x48, 0xf3, 0x5f, + 0x13, 0xce, 0x43, 0x9d, 0x9c, 0xa4, 0xb7, 0x19, 0x2e, 0xc5, 0x36, 0x63, 0x87, 0x34, 0x19, 0x83, + 0x4f, 0x82, 0x9c, 0x88, 0x72, 0x87, 0xe4, 0xec, 0xc6, 0x51, 0x60, 0x8b, 0x00, 0x80, 0xd4, 0x88, + 0xbf, 0xed, 0xbb, 0xde, 0x72, 0xd5, 0xd5, 0x15, 0x3c, 0x7e, 0x1a, 0x62, 0x5b, 0x12, 0x9a, 0x50, + 0x17, 0x03, 0x6d, 0xba, 0x64, 0x46, 0x07, 0x26, 0x9d, 0x46, 0xbf, 0xad, 0x6f, 0x89, 0x54, 0xaa, + 0x4d, 0x36, 0x88, 0x18, 0x95, 0xf9, 0xad, 0xe2, 0x55, 0x53, 0x68, 0x2b, 0x26, 0x83, 0x5a, 0x5a, + 0x06, 0x95, 0x47, 0xb3, 0x42, 0x8d, 0x73, 0xf1, 0x36, 0xd2, 0x9f, 0x43, 0x64, 0x92, 0xf6, 0xa9, + 0x33, 0xb3, 0xdf, 0x2d, 0x87, 0xcb, 0x43, 0x0d, 0x2d, 0xe7, 0x6f, 0x5c, 0x04, 0xe6, 0xad, 0xfb, + 0xd2, 0x12, 0xf9, 0xf3, 0x34, 0x60, 0xe1, 0xad, 0x62, 0x4e, 0xe6, 0xcc, 0xe8, 0x6b, 0xf8, 0x46, + 0x85, 0xfb, 0x34, 0xcc, 0x42, 0xa7, 0xfd, 0xbd, 0x53, 0xd6, 0x9d, 0xea, 0x9d, 0xa1, 0x03, 0x3f, + 0xf6, 0x59, 0xb5, 0xe7, 0xda, 0x00, 0x9f, 0x93, 0x7a, 0x88, 0x04, 0x0b, 0x2e, 0x8d, 0x7e, 0xaf, + 0x3b, 0x5a, 0xec, 0x2e, 0xc2, 0x12, 0xac, 0x57, 0xc1, 0x26, 0x72, 0x21, 0x39, 0x18, 0xc1, 0xcb, + 0xf6, 0xf8, 0xa4, 0xa3, 0x28, 0x7a, 0xbc, 0xe1, 0xa6, 0xbe, 0xe8, 0xd3, 0xc8, 0x5c, 0x31, 0x92, + 0xcd, 0x27, 0xaf, 0x50, 0x55, 0x04, 0x50, 0x50, 0xbf, 0x56, 0xfb, 0x84, 0xf2, 0xbf, 0x31, 0x2d, + 0x47, 0x0c, 0x2e, 0x90, 0x83, 0x65, 0xac, 0x4f, 0x75, 0x97, 0xfb, 0x7b, 0x07, 0x8d, 0x76, 0x1b, + 0x17, 0xa3, 0x6a, 0x07, 0x40, 0x15, 0xbd, 0xdc, 0xdb, 0x76, 0x6b, 0x9c, 0xb0, 0x25, 0x83, 0xdc, + 0xea, 0x36, 0xc2, 0x47, 0x7a, 0x7a, 0x76, 0x38, 0x7d, 0x89, 0x54, 0x83, 0x28, 0x76, 0x3c, 0xc6, + 0xec, 0x8c, 0x27, 0x5c, 0x57, 0xad, 0x43, 0x90, 0x4a, 0x7c, 0x02, 0xbb, 0x1b, 0x0e, 0xc2, 0x42, + 0x4e, 0xf0, 0xb8, 0xff, 0x1a, 0xc4, 0x5c, 0x27, 0x5e, 0x85, 0xa2, 0xaa, 0x2b, 0x2b, 0x2a, 0xb7, + 0x35, 0xaa, 0x5e, 0x3e, 0x79, 0x4c, 0x4a, 0x75, 0x0a, 0x17, 0x1e, 0x06, 0xbf, 0xd5, 0xd5, 0xd8, + 0x4d, 0x56, 0xe6, 0xd4, 0xc9, 0x8e, 0x3d, 0x09, 0x54, 0x44, 0xa8, 0x17, 0x8b, 0x0b, 0xb0, 0xb2, + 0x54, 0x50, 0xe8, 0x06, 0x1f, 0x19, 0xeb, 0x05, 0xae, 0x9f, 0x6c, 0xe5, 0x8c, 0x0b, 0x63, 0xe6, + 0x2a, 0xfc, 0xca, 0x2c, 0x9f, 0xc6, 0x59, 0x74, 0x35, 0xf2, 0x9d, 0x0c, 0xea, 0xf3, 0xb6, 0x95, + 0x3a, 0xb2, 0x96, 0x3c, 0x8b, 0xd0, 0xbd, 0x8c, 0x62, 0xc2, 0xc2, 0x5d, 0x17, 0xb0, 0x72, 0xaf, + 0xf6, 0x71, 0x48, 0x33, 0x4a, 0x78, 0xfa, 0x79, 0x3f, 0xca, 0xe6, 0xf4, 0x4f, 0x31, 0xb9, 0xc1, + 0xa9, 0x9f, 0x2c, 0xb7, 0x66, 0x07, 0x24, 0x48, 0x2a, 0xf5, 0x5f, 0x8e, 0xa9, 0x70, 0xf5, 0xe1, + 0xa5, 0x16, 0xfb, 0xab, 0xc6, 0x65, 0xb0, 0x98, 0x72, 0x25, 0x90, 0x19, 0x2a, 0xd5, 0xe4, 0x92, + 0xb9, 0x4f, 0x14, 0x86, 0xb6, 0x68, 0x63, 0x18, 0x17, 0xbf, 0xf9, 0xca, 0xd2, 0xce, 0xda, 0xa4, + 0x72, 0x5b, 0x8d, 0x7e, 0xb6, 0x25, 0x98, 0x06, 0xa2, 0x34, 0x40, 0x83, 0xbd, 0x5e, 0xb1, 0x3d, + 0xa8, 0x4e, 0x08, 0xfe, 0x55, 0x5d, 0x10, 0x5f, 0xaf, 0xe9, 0x73, 0x99, 0xc2, 0x6e, 0xba, 0x9e, + 0xf5, 0x31, 0x49, 0x76, 0xb5, 0x2b, 0x4b, 0xf5, 0x5d, 0x3a, 0x7d, 0x3a, 0x42, 0x12, 0x92, 0x80, + 0x14, 0xb7, 0xd8, 0xb6, 0x54, 0xaf, 0xae, 0xd3, 0x5f, 0x72, 0x66, 0x65, 0x40, 0xea, 0x37, 0xa6, + 0x55, 0x96, 0x4e, 0x37, 0x23, 0xbd, 0x3f, 0xa9, 0x29, 0x92, 0xa2, 0xaf, 0x27, 0xc9, 0x25, 0xab, + 0xf7, 0xaa, 0xae, 0x8f, 0x24, 0xe3, 0x5b, 0xe5, 0x30, 0x31, 0x48, 0x5f, 0xb3, 0xa2, 0x91, 0xa0, + 0x48, 0x2e, 0x3b, 0xaf, 0xad, 0xf0, 0x94, 0x23, 0x3b, 0x6a, 0x17, 0x76, 0x89, 0x82, 0x63, 0xb7, + 0x86, 0xe7, 0xb0, 0x6d, 0x9f, 0x53, 0x4a, 0xb7, 0x01, 0x8a, 0xdb, 0x8a, 0x94, 0xb2, 0x43, 0x05, + 0xe4, 0x28, 0xab, 0xee, 0xb6, 0xdf, 0x9a, 0x8b, 0xce, 0x78, 0x50, 0x5d, 0xe6, 0x4b, 0x55, 0x47, + 0xa9, 0xc5, 0x4e, 0x1f, 0xbb, 0x9e, 0x31, 0x0c, 0x1e, 0x22, 0xf7, 0xd6, 0x9a, 0xaf, 0xcf, 0x79, + 0x46, 0xe8, 0xd5, 0x9f, 0xcd, 0x6c, 0xb7, 0x09, 0x63, 0x2f, 0x49, 0xab, 0xea, 0x38, 0xe8, 0xa5, + 0xb2, 0xf9, 0x2f, 0x6f, 0xe5, 0x5b, 0xd1, 0x7e, 0x33, 0x19, 0xd3, 0x9b, 0xb0, 0x4a, 0x44, 0xf0, + 0xe0, 0xaf, 0x13, 0xa0, 0x81, 0xea, 0x3b, 0x68, 0x1c, 0x6a, 0x38, 0x12, 0xe7, 0xad, 0x45, 0xc2, + 0xd1, 0x3f, 0x9a, 0x1b, 0x7c, 0xf3, 0x35, 0xe8, 0xe5, 0xe3, 0xa7, 0xda, 0xa6, 0x93, 0xb4, 0x69, + 0x5e, 0x8b, 0x07, 0x9b, 0x75, 0x05, 0x99, 0x3d, 0x89, 0xdc, 0x58, 0xe2, 0x7a, 0xae, 0x7c, 0x9c, + 0xed, 0x2e, 0x6b, 0x58, 0xce, 0xae, 0x5a, 0x94, 0xb9, 0xc4, 0x76, 0x47, 0xb6, 0xb6, 0x38, 0xf5, + 0xda, 0xcb, 0xc1, 0x97, 0x34, 0x58, 0x81, 0x30, 0xf5, 0x0a, 0xbd, 0x41, 0x57, 0x01, 0xd7, 0x04, + 0x15, 0xc6, 0x81, 0xfb, 0xf3, 0x49, 0xc2, 0x11, 0x9d, 0x21, 0xc0, 0xae, 0x7e, 0x85, 0x9c, 0xd3, + 0x37, 0xc3, 0x30, 0x5e, 0xdc, 0x84, 0x81, 0x65, 0x99, 0xda, 0xa2, 0x4a, 0x9b, 0x99, 0x46, 0x0e, + 0xb8, 0x9b, 0x3c, 0xf5, 0x75, 0x23, 0x4b, 0x53, 0xfe, 0x23, 0x63, 0x01, 0xca, 0xd3, 0x43, 0xdb, + 0x67, 0x45, 0x5b, 0xc0, 0xec, 0x95, 0x99, 0xab, 0x97, 0x2b, 0xc6, 0x9a, 0x48, 0x06, 0x44, 0x1c, + 0x77, 0xf4, 0xcb, 0xad, 0x25, 0x5e, 0x5f, 0x0f, 0x4c, 0x92, 0x1a, 0xfc, 0xbf, 0x31, 0xa2, 0x11, + 0x65, 0xfd, 0xe6, 0x1e, 0x7e, 0xa0, 0x99, 0x07, 0x74, 0x34, 0x47, 0xc7, 0x88, 0xca, 0x08, 0x88, + 0x1f, 0x8e, 0xd8, 0xc4, 0x43, 0xc0, 0x19, 0xba, 0x3a, 0x48, 0x75, 0xf5, 0xb5, 0x2f, 0xaf, 0x74, + 0x51, 0xe2, 0x5c, 0xc6, 0x9d, 0x45, 0xc9, 0x31, 0x36, 0x4d, 0x75, 0x34, 0x53, 0x76, 0xba, 0x72, + 0xd8, 0x4d, 0xed, 0x12, 0xd0, 0x4a, 0x3e, 0xf6, 0xa6, 0x17, 0xda, 0x0d, 0x3a, 0x56, 0x02, 0x54, + 0x1d, 0xc8, 0x3b, 0x0b, 0xc7, 0x8f, 0x65, 0x9b, 0x49, 0x89, 0xfa, 0x93, 0xe9, 0xbf, 0xea, 0x47, + 0x0c, 0xfd, 0x82, 0xb2, 0x33, 0x84, 0x0c, 0x33, 0x10, 0xfc, 0x2e, 0xa2, 0x3e, 0x37, 0x00, 0x67, + 0x65, 0xc7, 0xa0, 0x3a, 0x60, 0x65, 0xb5, 0x8a, 0xcd, 0x54, 0x65, 0x4b, 0xd0, 0xf9, 0x52, 0x16, + 0xfa, 0x5e, 0x3a, 0x02, 0xc1, 0x5a, 0xff, 0xb3, 0xa6, 0xec, 0xd2, 0x2c, 0x8e, 0xaa, 0x3b, 0x87, + 0x50, 0xe0, 0x53, 0xde, 0xa5, 0x5e, 0x05, 0x31, 0xe5, 0x57, 0xb9, 0xc2, 0xd9, 0xb7, 0x77, 0x0d, + 0x00, 0x75, 0x48, 0x48, 0x2a, 0x38, 0x96, 0x4d, 0x3f, 0xbd, 0xa4, 0xd0, 0x30, 0x33, 0xea, 0x1a, + 0xad, 0x1b, 0x07, 0xf6, 0x74, 0xf6, 0x05, 0x6f, 0x53, 0xd9, 0xa8, 0xe9, 0xfb, 0xf8, 0xae, 0x9a, + 0x24, 0xf0, 0x16, 0x4e, 0x93, 0xf6, 0xb7, 0x0c, 0x96, 0x21, 0x74, 0xc2, 0xcc, 0x22, 0x77, 0x45, + 0x3b, 0x5a, 0x96, 0x99, 0x1e, 0x5e, 0xca, 0x49, 0xbb, 0xca, 0xc4, 0x8c, 0x99, 0xe4, 0x45, 0x46, + 0x01, 0x67, 0x4f, 0x3a, 0xe3, 0x3c, 0x56, 0x2b, 0xb7, 0xef, 0xef, 0x5f, 0x71, 0xee, 0x00, 0xbf, + 0x98, 0x30, 0x69, 0xdb, 0xd5, 0x5b, 0x35, 0x69, 0x0a, 0x06, 0x45, 0xb3, 0x51, 0x89, 0x35, 0x48, + 0x13, 0x36, 0xe7, 0x64, 0x3e, 0xfb, 0x70, 0x12, 0x35, 0xa8, 0x32, 0xff, 0x68, 0x60, 0xa6, 0xe6, + 0x3f, 0x27, 0xa6, 0xb5, 0x00, 0x0e, 0xb3, 0x8c, 0x1e, 0x7b, 0x66, 0xc1, 0xa7, 0xe7, 0x8c, 0x38, + 0xcf, 0xfa, 0x43, 0x46, 0xb6, 0x3b, 0x3a, 0xcb, 0x68, 0x7d, 0xdb, 0x94, 0xf0, 0x39, 0xfe, 0xf4, + 0x6b, 0x3e, 0x5d, 0x60, 0xf6, 0x37, 0xa6, 0x35, 0x9f, 0x6c, 0x71, 0x57, 0x2f, 0x83, 0xdb, 0x22, + 0x89, 0x8c, 0x44, 0x4f, 0x2e, 0x64, 0xf7, 0xbd, 0x29, 0xc7, 0x44, 0xf1, 0x80, 0xaa, 0x57, 0x0f, + 0xf4, 0x9d, 0x85, 0x41, 0xd8, 0xd5, 0x0b, 0x4b, 0xfb, 0x49, 0x52, 0x96, 0xf0, 0x1f, 0x9f, 0x37, + 0x17, 0xf6, 0x32, 0xf3, 0x4e, 0x96, 0xdf, 0xe8, 0x2f, 0x4b, 0x93, 0x67, 0x3f, 0x1a, 0xbc, 0x8e, + 0x3a, 0x9b, 0x48, 0x62, 0xd0, 0x76, 0x45, 0x62, 0x1d, 0xb6, 0x54, 0x37, 0x7d, 0x34, 0xdb, 0xbc, + 0xd9, 0xad, 0xa6, 0xac, 0xaf, 0x77, 0xee, 0x71, 0x61, 0x70, 0xba, 0x46, 0x8d, 0xcd, 0x52, 0x33, + 0x3b, 0x59, 0x11, 0x43, 0x4e, 0x01, 0xc6, 0x9b, 0xc0, 0x33, 0xb0, 0xc0, 0x5c, 0x0e, 0xf3, 0x07, + 0xea, 0x72, 0x51, 0x98, 0x20, 0xb5, 0xa9, 0xb7, 0xac, 0x0a, 0x2d, 0x38, 0xdd, 0x26, 0x6a, 0xa1, + 0xac, 0xc3, 0x7a, 0x4d, 0x64, 0xef, 0x2e, 0x68, 0x91, 0xad, 0x85, 0x1b, 0xaf, 0x26, 0xdd, 0x23, + 0x6a, 0x9f, 0xef, 0x06, 0xd3, 0xa3, 0xf9, 0x7b, 0x92, 0x52, 0x99, 0xb3, 0xb6, 0xe8, 0x26, 0xa8, + 0xd7, 0x1e, 0x15, 0x4d, 0x5f, 0xf7, 0xc9, 0xf6, 0xc8, 0x6f, 0xd9, 0xee, 0x8d, 0xf5, 0x3e, 0xa5, + 0xbc, 0x9c, 0xb3, 0xcc, 0xc1, 0x04, 0x36, 0x79, 0x48, 0xb4, 0x87, 0xea, 0x46, 0x43, 0x25, 0xc4, + 0x77, 0x3b, 0x02, 0x86, 0xc9, 0xd6, 0x57, 0x8c, 0xc0, 0x3c, 0x18, 0x57, 0x4d, 0xfe, 0x99, 0x9f, + 0x0c, 0xc4, 0x35, 0xd1, 0x22, 0x0a, 0x2e, 0x6a, 0x15, 0xd6, 0x3e, 0x4b, 0xc7, 0x69, 0x77, 0x5d, + 0xd2, 0xcc, 0x57, 0x88, 0xec, 0xaa, 0xf8, 0x66, 0x79, 0x23, 0x11, 0xc7, 0x61, 0xfb, 0xd6, 0x93, + 0xe7, 0xb3, 0xb6, 0xf8, 0x17, 0x73, 0xad, 0xe0, 0x75, 0x2f, 0xbb, 0x1c, 0xbb, 0xc7, 0x39, 0xc3, + 0x01, 0x99, 0xee, 0xa2, 0x50, 0xc7, 0x03, 0x52, 0xb7, 0xc2, 0x70, 0x87, 0xbd, 0x69, 0xa9, 0x74, + 0x16, 0x46, 0x60, 0x16, 0xd6, 0xd5, 0x31, 0x4f, 0xbc, 0x44, 0x95, 0xbd, 0x49, 0x28, 0x0a, 0x27, + 0xa1, 0x5f, 0x63, 0x47, 0xa1, 0xd5, 0xdf, 0x98, 0xd6, 0xde, 0x1f, 0xa7, 0xa3, 0x5b, 0xf7, 0x6d, + 0x4d, 0x3d, 0x6d, 0xed, 0x0c, 0x92, 0x56, 0x07, 0xec, 0x5a, 0x6a, 0x59, 0xcc, 0x46, 0x56, 0x61, + 0x2f, 0x52, 0xd7, 0xb5, 0x53, 0x49, 0x5b, 0x8a, 0x64, 0xc5, 0xdf, 0xd4, 0xe3, 0xe1, 0xad, 0x18, + 0xd7, 0x50, 0x3e, 0x0f, 0x57, 0xdb, 0x3b, 0x7c, 0x8e, 0x0a, 0xcd, 0xdb, 0xdf, 0x6b, 0x4e, 0x81, + 0x56, 0xa9, 0x34, 0xde, 0x40, 0x2f, 0x19, 0xa7, 0x04, 0xed, 0xb6, 0x0c, 0xba, 0xaf, 0xce, 0xe3, + 0x7e, 0xd8, 0x87, 0x78, 0xfb, 0xb2, 0xde, 0x46, 0x90, 0xf3, 0xe6, 0x1c, 0x5e, 0x04, 0xe3, 0xd7, + 0xc6, 0x72, 0x74, 0x76, 0xa0, 0xd4, 0xb5, 0x94, 0xd8, 0xc9, 0x38, 0x58, 0x89, 0x1c, 0x2c, 0x6b, + 0x1c, 0xc5, 0x88, 0x3b, 0xba, 0xdc, 0xd5, 0x4f, 0xe5, 0x2b, 0xa7, 0x16, 0xbd, 0x36, 0x93, 0x9e, + 0xec, 0xb6, 0x9d, 0x4f, 0x64, 0x2f, 0x8a, 0xc7, 0x34, 0xff, 0xc0, 0x64, 0x62, 0xb2, 0x9c, 0xcf, + 0xe3, 0xc7, 0x44, 0xc1, 0x34, 0x24, 0xd9, 0xe1, 0xb6, 0x81, 0x39, 0x26, 0x44, 0x99, 0x5a, 0x6d, + 0x9a, 0x96, 0xf9, 0x8e, 0xd4, 0x99, 0x13, 0x24, 0x9b, 0xbf, 0x3f, 0x3d, 0xc7, 0x6e, 0x16, 0x2b, + 0xd1, 0x3f, 0x87, 0xce, 0x81, 0x99, 0xae, 0xa6, 0xb5, 0xe2, 0xef, 0xcc, 0xdb, 0x25, 0x2d, 0x7d, + 0xed, 0x57, 0xc9, 0x00, 0xa9, 0xfb, 0x46, 0x21, 0xf3, 0x44, 0x3f, 0x19, 0x0a, 0xea, 0x6d, 0x2e, + 0xc8, 0xe0, 0x40, 0xf5, 0xa5, 0x5a, 0x94, 0x37, 0xd2, 0x59, 0x85, 0x4a, 0x8f, 0xbf, 0x90, 0xf4, + 0xa9, 0x53, 0x6a, 0x33, 0xe5, 0xdc, 0xc5, 0x71, 0x14, 0x79, 0x60, 0x22, 0xa2, 0x33, 0x8c, 0x4a, + 0x80, 0x6a, 0x90, 0x28, 0xae, 0xbf, 0x5e, 0x55, 0xdf, 0xee, 0x47, 0xbd, 0x11, 0x98, 0x58, 0xf7, + 0xf5, 0xa3, 0x2a, 0x32, 0x5d, 0x9c, 0xb7, 0xa5, 0x3d, 0xd2, 0xfc, 0x5e, 0x70, 0x4a, 0x43, 0x80, + 0x2a, 0x4f, 0xf5, 0xb9, 0x03, 0x06, 0xf2, 0x40, 0x06, 0xf0, 0x71, 0xc3, 0x77, 0x96, 0x44, 0x76, + 0xb0, 0xfe, 0xeb, 0xae, 0x09, 0x6b, 0x90, 0xe0, 0x37, 0xa6, 0xf5, 0x0b, 0xd6, 0x47, 0x4a, 0x96, + 0x94, 0x36, 0xd5, 0x00, 0xed, 0x56, 0x3f, 0xc1, 0x0b, 0x39, 0x18, 0x0b, 0xfc, 0xf1, 0x54, 0x19, + 0x8f, 0xcc, 0xed, 0xf8, 0x21, 0xee, 0xc8, 0xc4, 0xe9, 0xe5, 0x54, 0xaf, 0x79, 0x85, 0x86, 0x2e, + 0xd3, 0x9e, 0x71, 0xe8, 0x34, 0x1d, 0xb4, 0x98, 0x54, 0xfd, 0x8f, 0x9a, 0x59, 0xc3, 0x21, 0xce, + 0xdb, 0x63, 0x14, 0xd4, 0x8d, 0x19, 0x25, 0x7a, 0xed, 0x72, 0xcd, 0x72, 0x98, 0x95, 0xc6, 0x69, + 0xac, 0xff, 0xe9, 0xf0, 0xe7, 0xe0, 0xcf, 0x1b, 0xd9, 0x9a, 0xd1, 0x7c, 0xd1, 0xc8, 0x05, 0x50, + 0xff, 0xe0, 0xeb, 0x62, 0xfc, 0x8a, 0x20, 0x52, 0x80, 0x2a, 0x0d, 0x55, 0x69, 0x2f, 0xbc, 0x52, + 0xdf, 0x13, 0x5a, 0x3d, 0x7c, 0x22, 0x1a, 0xef, 0x32, 0x18, 0x8d, 0x2d, 0x92, 0x96, 0x8a, 0x4b, + 0x29, 0x1f, 0xac, 0xe1, 0x1e, 0xa7, 0xeb, 0xa4, 0xb6, 0xc0, 0xe0, 0x09, 0x5a, 0x26, 0x9b, 0xbf, + 0x82, 0x32, 0x2b, 0xfd, 0x01, 0xb8, 0xd4, 0x95, 0x1a, 0x77, 0xd2, 0xe4, 0x02, 0xa2, 0xef, 0x58, + 0x95, 0x04, 0x02, 0xb1, 0x8d, 0x7e, 0x4b, 0xaa, 0x06, 0x97, 0xde, 0xf0, 0x05, 0xb3, 0x6f, 0x14, + 0x29, 0x87, 0x8c, 0xeb, 0xfe, 0x46, 0xd4, 0x82, 0x1c, 0x5e, 0x2f, 0x7a, 0xa1, 0xa3, 0xa5, 0x61, + 0xb5, 0xe6, 0xc7, 0x16, 0x1d, 0x6f, 0x01, 0x06, 0x7b, 0x89, 0xb2, 0x67, 0x33, 0x82, 0xe0, 0x4c, + 0x62, 0x64, 0x4d, 0x9e, 0xe3, 0x3f, 0x86, 0x1e, 0xb9, 0x21, 0x09, 0xb8, 0xba, 0xc4, 0xeb, 0x01, + 0xf2, 0x51, 0x85, 0xa3, 0xbb, 0x65, 0x11, 0x9d, 0xfd, 0x92, 0x54, 0x4b, 0x7e, 0xce, 0x92, 0xe7, + 0x79, 0x45, 0x2f, 0x56, 0xcb, 0xbf, 0x44, 0xd1, 0x46, 0xf6, 0x22, 0x51, 0x17, 0x5a, 0x87, 0x8e, + 0xef, 0xd5, 0x37, 0xe7, 0x73, 0xa2, 0x9a, 0xdf, 0xd0, 0x70, 0xe6, 0x94, 0x16, 0xeb, 0x0f, 0x86, + 0x3f, 0x70, 0x19, 0x35, 0x6c, 0x9b, 0xe9, 0x6d, 0x92, 0x85, 0x34, 0xff, 0xa2, 0x64, 0x89, 0xe3, + 0x91, 0x5d, 0xab, 0x8c, 0xfd, 0xda, 0xa6, 0x01, 0xce, 0x6f, 0x4c, 0x2f, 0x72, 0xb1, 0x68, 0xb6, + 0x31, 0xc8, 0xa9, 0x8d, 0xe0, 0x72, 0x6f, 0xfd, 0xb5, 0x4a, 0x08, 0x01, 0xfd, 0x87, 0xac, 0xc5, + 0x1a, 0x98, 0x17, 0xee, 0x79, 0x10, 0x6b, 0x79, 0x1b, 0x79, 0xec, 0xa1, 0x77, 0x35, 0xa5, 0x3c, + 0x7a, 0xef, 0x0e, 0xb6, 0x65, 0xc7, 0x8d, 0x54, 0x58, 0x14, 0xc3, 0x7d, 0xf2, 0x4e, 0x66, 0xc7, + 0x4d, 0xb8, 0x60, 0x67, 0x13, 0xcc, 0x76, 0x2e, 0x99, 0x69, 0xc7, 0xd3, 0x0b, 0xb6, 0xe8, 0xfa, + 0x2a, 0x7e, 0x53, 0xdc, 0xe6, 0x99, 0xbd, 0x8c, 0x8b, 0x47, 0x2b, 0x3b, 0x16, 0xe6, 0xed, 0x23, + 0x13, 0x71, 0x92, 0x8e, 0xfc, 0x5d, 0x67, 0xbf, 0x36, 0xc3, 0x2e, 0xc0, 0xb6, 0x0f, 0xc5, 0xa8, + 0xd2, 0x4f, 0x54, 0xf0, 0xa7, 0xe8, 0x7c, 0x3a, 0xbf, 0xfb, 0x26, 0x40, 0x78, 0x10, 0xf4, 0x59, + 0xc1, 0x44, 0x29, 0x23, 0x82, 0x7c, 0x19, 0xcf, 0xf1, 0x1f, 0x2e, 0x91, 0xac, 0xf2, 0x00, 0x72, + 0xe6, 0xca, 0xf4, 0xcb, 0x11, 0x47, 0x10, 0x81, 0x64, 0xec, 0x36, 0x7a, 0xd6, 0x5a, 0x15, 0xb8, + 0xc2, 0x3f, 0x27, 0xc6, 0x87, 0x1e, 0x19, 0x90, 0xcc, 0x6a, 0x5b, 0x05, 0x33, 0x34, 0x99, 0x79, + 0xfd, 0x39, 0x20, 0xae, 0x47, 0x15, 0x7d, 0x73, 0xe7, 0xba, 0xcc, 0xaf, 0x7e, 0x0f, 0x1a, 0xae, + 0x46, 0xae, 0xe6, 0x5e, 0x62, 0xf8, 0x83, 0x5c, 0xba, 0x8a, 0x2f, 0xe6, 0xee, 0x30, 0xf7, 0x53, + 0xbb, 0xd0, 0x39, 0xc1, 0xc3, 0xbc, 0x87, 0x37, 0x00, 0xb0, 0xf6, 0x2e, 0x2a, 0x7d, 0xb9, 0xe3, + 0xbc, 0x97, 0xb0, 0x9c, 0x6a, 0xbb, 0xc5, 0x85, 0xe7, 0x0b, 0xe2, 0xf5, 0xde, 0xb6, 0x59, 0xce, + 0x50, 0x68, 0xed, 0x5a, 0x81, 0x88, 0xfc, 0x0f, 0x45, 0xfc, 0x00, 0x75, 0x93, 0x3a, 0x95, 0x6c, + 0x4a, 0x07, 0x18, 0x37, 0xc0, 0x99, 0x6a, 0x3c, 0x3c, 0x1c, 0x03, 0x50, 0xe0, 0xa9, 0x4d, 0xeb, + 0x4f, 0x17, 0xeb, 0x06, 0xdf, 0xa9, 0xef, 0x35, 0x79, 0xf2, 0x78, 0x7c, 0xf3, 0x47, 0xc2, 0x49, + 0xb4, 0xf9, 0x9e, 0x40, 0xd3, 0x99, 0x74, 0xbf, 0xfd, 0x5a, 0x71, 0xab, 0xce, 0xfd, 0x8d, 0x69, + 0x5b, 0x94, 0xd7, 0x5c, 0xae, 0x86, 0x2f, 0xdd, 0x67, 0xaf, 0x51, 0x9b, 0x38, 0x94, 0x29, 0x62, + 0xb6, 0x2f, 0xfd, 0xb8, 0x4f, 0x5f, 0x0e, 0xdd, 0xdc, 0x05, 0x20, 0xd5, 0x5e, 0x5b, 0x89, 0x0b, + 0xcd, 0xf9, 0x33, 0xea, 0xe6, 0x35, 0xde, 0xad, 0x94, 0x6d, 0x4f, 0x4d, 0xe9, 0xc8, 0xbe, 0x7b, + 0x9c, 0xcd, 0x65, 0xb3, 0xcc, 0x57, 0x55, 0xa5, 0xbf, 0x73, 0xf2, 0x73, 0xc4, 0x39, 0xa6, 0x65, + 0x96, 0x8b, 0xb7, 0x7a, 0xa5, 0xd7, 0x61, 0xb8, 0x0c, 0xd7, 0x30, 0xc8, 0x06, 0x46, 0xbb, 0x8f, + 0x8f, 0xa4, 0x4c, 0x1a, 0x3d, 0xc1, 0x8d, 0xdb, 0x17, 0x4c, 0xba, 0x8f, 0xff, 0x74, 0x90, 0x1a, + 0xee, 0xc2, 0x94, 0xcc, 0x27, 0x73, 0xf6, 0x7f, 0x76, 0xd6, 0x1b, 0x8a, 0x7b, 0x3e, 0xf0, 0x67, + 0x4e, 0x09, 0x61, 0xbb, 0x30, 0x60, 0xd1, 0x06, 0xad, 0x2a, 0xad, 0xe3, 0x4d, 0x3a, 0xc9, 0x58, + 0xae, 0x48, 0x1e, 0x5a, 0xc3, 0x9a, 0x7f, 0x20, 0xbd, 0x94, 0xa1, 0x33, 0x7c, 0x80, 0xe8, 0x9f, + 0x73, 0x54, 0xff, 0xf9, 0x6d, 0x67, 0xd0, 0x09, 0x15, 0x09, 0x47, 0xdd, 0xbe, 0x7c, 0x20, 0xfb, + 0xb3, 0x3a, 0xb0, 0x9d, 0x87, 0x9a, 0xf2, 0x2b, 0x28, 0xd8, 0x05, 0xd7, 0x07, 0x9a, 0x8e, 0x48, + 0xa7, 0x09, 0xe5, 0xf5, 0x09, 0xf3, 0x26, 0xc5, 0x3e, 0xf1, 0xcc, 0x2f, 0x10, 0xd4, 0x0b, 0xb3, + 0xc1, 0x52, 0xed, 0xa2, 0x84, 0x56, 0x17, 0x0c, 0xc8, 0x6c, 0x64, 0x3c, 0x08, 0x80, 0xc7, 0x07, + 0xbd, 0x22, 0xb7, 0x06, 0x1f, 0xf5, 0x4c, 0x07, 0xde, 0xe4, 0x3c, 0x92, 0x4e, 0x53, 0x34, 0xdb, + 0x7a, 0x3a, 0xd7, 0x15, 0x16, 0x33, 0x53, 0x3a, 0x79, 0xa4, 0xd9, 0x1a, 0x5a, 0x09, 0x45, 0x39, + 0x07, 0x4a, 0x15, 0x2d, 0x55, 0xae, 0x6b, 0xd9, 0xab, 0xbc, 0x3a, 0x4a, 0x95, 0x2e, 0x1e, 0x53, + 0x65, 0x87, 0x58, 0xcc, 0x66, 0x6d, 0x2d, 0x1b, 0x02, 0xee, 0x9a, 0x3d, 0x6a, 0x03, 0x97, 0x54, + 0xd4, 0x69, 0xb5, 0xa8, 0x3c, 0xd0, 0xbe, 0xa9, 0xc1, 0x35, 0xcf, 0xaf, 0x6d, 0x1a, 0x97, 0xff, + 0xad, 0xe9, 0x12, 0x72, 0x2b, 0x68, 0x1f, 0x70, 0x53, 0x37, 0x5a, 0xf5, 0xfa, 0x70, 0x15, 0x6b, + 0x6e, 0xd5, 0x39, 0xc8, 0x53, 0xf7, 0x3a, 0x31, 0x7c, 0xc1, 0xaa, 0xfc, 0x8c, 0x6e, 0x8d, 0x2e, + 0x0b, 0x06, 0xee, 0x0a, 0x71, 0xb0, 0x9e, 0xb2, 0x2b, 0x2b, 0xe7, 0xbd, 0xfe, 0x1f, 0x51, 0xdf, + 0x57, 0x9e, 0x32, 0x6e, 0x71, 0x21, 0x0c, 0x92, 0xa4, 0x1a, 0x44, 0xf5, 0x38, 0x63, 0x9b, 0xf6, + 0xc5, 0x1f, 0x73, 0x91, 0xd3, 0x63, 0xaa, 0x37, 0x50, 0xbd, 0xd6, 0xf3, 0xab, 0x38, 0x0e, 0x8d, + 0xdf, 0xbc, 0x26, 0x78, 0x38, 0x08, 0x27, 0x35, 0x53, 0x82, 0xe2, 0x0e, 0xce, 0x31, 0xae, 0xbd, + 0x06, 0x81, 0x1f, 0x5a, 0x6a, 0xf1, 0xa3, 0x0c, 0x27, 0xb2, 0x43, 0xdb, 0x03, 0x23, 0xd7, 0xbe, + 0x41, 0xee, 0x8b, 0xf6, 0xeb, 0x4e, 0x9d, 0x6e, 0xe9, 0x8c, 0xa6, 0xd6, 0xeb, 0x2d, 0x8a, 0x44, + 0x46, 0xf6, 0x2e, 0x72, 0x49, 0x24, 0x80, 0xe6, 0x11, 0x61, 0x18, 0xd0, 0x49, 0xf6, 0x2b, 0xe2, + 0x4d, 0xad, 0xc6, 0xad, 0x17, 0xee, 0x86, 0xae, 0x28, 0x9b, 0xc9, 0xdc, 0xc3, 0xb5, 0xfa, 0x12, + 0x88, 0x1f, 0x43, 0x23, 0xa1, 0xf2, 0xbe, 0xa5, 0x56, 0x79, 0x54, 0xff, 0xfe, 0xbc, 0x10, 0xaf, + 0x92, 0x05, 0x9d, 0xbb, 0xa9, 0x22, 0xf8, 0xb9, 0x52, 0x60, 0xfa, 0x7f, 0xd6, 0xc3, 0x04, 0x74, + 0x1b, 0xd3, 0x16, 0x44, 0x1c, 0x26, 0xd0, 0xff, 0xaf, 0x2b, 0x6e, 0xfd, 0x4d, 0x3f, 0x8d, 0x83, + 0xbf, 0x69, 0xd3, 0x80, 0xf4, 0x81, 0x3e, 0x21, 0x78, 0xc5, 0x8c, 0xef, 0xb6, 0x4c, 0xd7, 0x3a, + 0x01, 0x59, 0x2c, 0xa9, 0x59, 0xca, 0xdf, 0xd5, 0xd8, 0x76, 0xd1, 0x48, 0xd1, 0x2a, 0x54, 0xdc, + 0xfd, 0x7f, 0xd4, 0x55, 0x02, 0xda, 0xd0, 0x8c, 0x30, 0x57, 0xee, 0x94, 0x72, 0xbb, 0x96, 0x4a, + 0x24, 0x0c, 0x66, 0x50, 0xae, 0x3b, 0x95, 0xb0, 0x2a, 0xb9, 0x0d, 0xf3, 0x53, 0xca, 0x25, 0xe9, + 0xc3, 0xf3, 0xe5, 0xa1, 0xb7, 0xf3, 0xc1, 0x85, 0x27, 0x17, 0x19, 0x9e, 0xff, 0x5e, 0xdd, 0x45, + 0x72, 0x10, 0xce, 0x1b, 0x39, 0x0c, 0x74, 0x4a, 0xa4, 0xb2, 0xa9, 0x60, 0x3d, 0xb4, 0x19, 0xe2, + 0x65, 0x0e, 0x00, 0xb8, 0x2f, 0x8c, 0xbc, 0x21, 0xdd, 0x3d, 0x11, 0xa6, 0x11, 0xe2, 0x17, 0xfd, + 0xcd, 0xda, 0xa7, 0xca, 0xe9, 0xe9, 0x42, 0xe6, 0x82, 0xd6, 0x77, 0x49, 0xea, 0xf8, 0xc8, 0x40, + 0xc7, 0x0c, 0x6f, 0xa3, 0x74, 0xbb, 0x06, 0xae, 0x2e, 0xfa, 0xa5, 0xe7, 0xe8, 0xfc, 0x41, 0xa9, + 0x5a, 0x53, 0xdc, 0x45, 0xd9, 0x5a, 0xfc, 0xd0, 0x47, 0x09, 0x8d, 0x3f, 0xbb, 0x2e, 0x07, 0x72, + 0x1f, 0x2c, 0x6f, 0x76, 0x5c, 0x83, 0xfe, 0xaa, 0x19, 0xcc, 0x9c, 0x4d, 0xa8, 0x8b, 0xc7, 0x50, + 0xed, 0x0f, 0xfd, 0x30, 0xb8, 0x78, 0x03, 0xb8, 0x1c, 0x39, 0x57, 0x51, 0xf5, 0xa6, 0x4a, 0xa7, + 0xa3, 0x27, 0xc3, 0x11, 0x12, 0xcd, 0x36, 0xa3, 0xc9, 0xd8, 0x51, 0xbb, 0xf0, 0xf4, 0x32, 0xde, + 0xd4, 0x4b, 0x9b, 0xb3, 0xf2, 0xad, 0xfd, 0xd7, 0x80, 0x31, 0xaf, 0xd0, 0xa5, 0xc7, 0x16, 0xef, + 0xc9, 0xbf, 0xd9, 0x2a, 0xff, 0x4b, 0xb7, 0x1f, 0xb7, 0xe2, 0x99, 0x25, 0xb8, 0xf7, 0x1d, 0x6e, + 0x46, 0x31, 0xa4, 0x12, 0x98, 0xa8, 0xcc, 0x8a, 0xc9, 0x5c, 0x41, 0xa2, 0x91, 0x73, 0x61, 0xdd, + 0x87, 0x9e, 0xad, 0x52, 0xf1, 0xd6, 0xcc, 0x91, 0x46, 0x1a, 0xcd, 0xd6, 0x8c, 0x6c, 0x1e, 0x4d, + 0xf4, 0x6d, 0xd4, 0x6c, 0xe7, 0x34, 0x69, 0x1f, 0x54, 0x3d, 0x9f, 0x2d, 0xb3, 0xd1, 0x5f, 0xd7, + 0xf9, 0x00, 0x7b, 0xea, 0x37, 0xa6, 0xc3, 0x23, 0xbe, 0xf3, 0xa8, 0xd0, 0xdb, 0xf3, 0xc2, 0x63, + 0x4a, 0x98, 0xb1, 0x26, 0x28, 0x78, 0xa4, 0x03, 0x31, 0xd9, 0x95, 0x97, 0x65, 0x28, 0x04, 0xfd, + 0x61, 0xa3, 0xb0, 0x79, 0xc4, 0xcb, 0x8c, 0xf4, 0x21, 0x7e, 0xb5, 0x07, 0x40, 0x7c, 0x56, 0xf7, + 0xb5, 0x92, 0x28, 0x7e, 0x4d, 0x44, 0xba, 0xda, 0xdb, 0xe8, 0x9f, 0x93, 0x90, 0x50, 0xda, 0x55, + 0x31, 0x15, 0xac, 0xda, 0xff, 0xe3, 0xe7, 0x05, 0x16, 0x74, 0xc7, 0xe8, 0xdc, 0x50, 0xeb, 0xca, + 0x4c, 0x55, 0x49, 0xa0, 0xe1, 0x4b, 0x21, 0x97, 0x1e, 0xb6, 0x43, 0xd6, 0x3f, 0xa1, 0x94, 0x73, + 0xbe, 0x83, 0xe4, 0x75, 0x16, 0x43, 0x5b, 0x02, 0xa9, 0x59, 0x02, 0x44, 0xed, 0x89, 0xfd, 0xba, + 0x03, 0xef, 0x11, 0xcd, 0x21, 0xe5, 0x83, 0xd5, 0x1f, 0x8a, 0xfb, 0xaf, 0x04, 0x36, 0x7d, 0xe0, + 0x38, 0x6c, 0x97, 0x3b, 0x75, 0x1b, 0x9f, 0x3e, 0xd5, 0x9e, 0x27, 0x74, 0x56, 0xd9, 0x3f, 0xc7, + 0x2a, 0x57, 0xb2, 0xbc, 0x94, 0xb5, 0x49, 0x58, 0x8b, 0xb3, 0x06, 0xb5, 0x1d, 0x14, 0x52, 0xf7, + 0x0b, 0x43, 0x21, 0xbc, 0x8f, 0x34, 0x26, 0x61, 0x70, 0x1b, 0x8d, 0x5d, 0x75, 0x5d, 0xcb, 0x96, + 0xb6, 0xe4, 0xab, 0x3a, 0x46, 0x5e, 0x84, 0xeb, 0x0b, 0x17, 0xfd, 0xb9, 0x2e, 0x7f, 0xe0, 0x4d, + 0xf2, 0x9c, 0xe8, 0xf0, 0x21, 0x6a, 0x6d, 0xf7, 0xf5, 0x1f, 0xc6, 0xba, 0xbe, 0x93, 0xd5, 0xa1, + 0xe1, 0x54, 0xef, 0xae, 0x33, 0x08, 0x74, 0x52, 0xe2, 0x97, 0x36, 0x8c, 0x26, 0x40, 0xee, 0x2a, + 0x7e, 0xec, 0xfc, 0x6c, 0xed, 0x3e, 0x74, 0xc1, 0x55, 0x7b, 0x57, 0x51, 0xd3, 0xac, 0xfa, 0x26, + 0xf5, 0x4c, 0x41, 0xa2, 0xc0, 0x13, 0x99, 0xc1, 0x90, 0xaa, 0x0c, 0x95, 0xfd, 0x76, 0x5e, 0x89, + 0xbd, 0x30, 0x8a, 0xe7, 0x84, 0xf3, 0x1f, 0x55, 0xdb, 0xdd, 0x84, 0xdd, 0x73, 0xd1, 0xdf, 0xcf, + 0x99, 0xf8, 0x95, 0x27, 0x90, 0xd7, 0x7a, 0xbd, 0x65, 0xf8, 0xc6, 0xa0, 0x76, 0x29, 0xef, 0xf7, + 0x14, 0xbf, 0x9a, 0x9e, 0x52, 0xff, 0xc6, 0x74, 0xd4, 0xf6, 0xe0, 0x59, 0xcf, 0x4b, 0xd7, 0xe2, + 0x24, 0xdb, 0xf2, 0x80, 0x03, 0x23, 0x39, 0x7e, 0xe1, 0xb3, 0x4d, 0xd3, 0x93, 0xbe, 0x53, 0x62, + 0x96, 0xa5, 0x78, 0xcf, 0xb0, 0xcb, 0xf2, 0x73, 0xee, 0x34, 0xd2, 0x8c, 0x96, 0x4c, 0xa7, 0xbd, + 0x30, 0x10, 0x07, 0x2b, 0x69, 0xd8, 0xb7, 0x5e, 0x7e, 0x1d, 0xc2, 0xea, 0x6b, 0x87, 0xc1, 0x4f, + 0x44, 0x6d, 0xa6, 0x6b, 0x47, 0x7f, 0x39, 0xa7, 0xc8, 0x60, 0xaf, 0xa3, 0xf0, 0x29, 0x3d, 0x53, + 0xd4, 0xc6, 0x35, 0xaa, 0x6a, 0x42, 0xb7, 0x01, 0x0a, 0x23, 0x1b, 0xfa, 0x1e, 0xa2, 0x04, 0x33, + 0x1f, 0x24, 0xc7, 0x78, 0x37, 0x55, 0xdd, 0xc6, 0x69, 0x98, 0xfd, 0xdc, 0xeb, 0x35, 0xc9, 0xa7, + 0x24, 0xdc, 0xee, 0x38, 0x47, 0x9e, 0x0d, 0xd3, 0x10, 0xb1, 0x47, 0xed, 0x84, 0xd7, 0xd0, 0xa7, + 0xac, 0x83, 0xe6, 0x34, 0x78, 0x0c, 0xfb, 0x53, 0x89, 0x6d, 0x52, 0xc3, 0xdc, 0x50, 0xda, 0x37, + 0x20, 0x1f, 0x1e, 0x2d, 0x63, 0xfa, 0xe1, 0x65, 0x20, 0x08, 0x17, 0x86, 0xc3, 0x6b, 0x7e, 0x4d, + 0x63, 0x5b, 0x4c, 0x15, 0xac, 0xe7, 0x89, 0xb0, 0xf0, 0x38, 0x60, 0x74, 0x54, 0xd5, 0x5c, 0x35, + 0xf8, 0xac, 0xb1, 0xd7, 0x7f, 0x18, 0x35, 0x5c, 0x14, 0x15, 0x50, 0x1d, 0xa1, 0x39, 0x41, 0xe3, + 0x15, 0xc2, 0xb3, 0x3b, 0xa6, 0x69, 0xd2, 0xf8, 0x05, 0x71, 0x5c, 0x0e, 0x7f, 0xd0, 0x7c, 0x3f, + 0x00, 0xd4, 0x90, 0x7e, 0x26, 0xd5, 0xc6, 0x12, 0xa3, 0xb3, 0x4e, 0xdc, 0x23, 0x99, 0xae, 0x2f, + 0x0b, 0x90, 0x5d, 0x92, 0xc8, 0x19, 0x4f, 0xd9, 0x38, 0xa4, 0xd3, 0x5e, 0x67, 0x0c, 0x17, 0xe9, + 0xf4, 0x6a, 0x3f, 0xfc, 0x8a, 0x57, 0x95, 0x41, 0x56, 0xa4, 0x0c, 0x3b, 0x95, 0x5b, 0x46, 0x3a, + 0x60, 0x69, 0xae, 0x22, 0x86, 0x4c, 0xb6, 0xe8, 0xea, 0x72, 0x44, 0x0a, 0x3c, 0xd2, 0x6e, 0xc6, + 0x3c, 0x17, 0x44, 0x9f, 0x2b, 0xf2, 0xff, 0xa8, 0xe4, 0x99, 0xce, 0x56, 0x54, 0xe4, 0xb7, 0xfe, + 0xba, 0x6b, 0x02, 0xba, 0xf5, 0x1b, 0xd3, 0x37, 0x8a, 0xcb, 0x80, 0x45, 0x48, 0x3d, 0x9c, 0xd3, + 0x45, 0xf8, 0xaa, 0x81, 0xac, 0x22, 0x78, 0x92, 0x3d, 0xdc, 0xa3, 0xa3, 0xc9, 0xb1, 0xc0, 0x8c, + 0xa8, 0x23, 0x76, 0x8f, 0x31, 0xd3, 0xe1, 0x42, 0xf7, 0xa9, 0xb4, 0xf0, 0xb8, 0xb9, 0xdb, 0xe1, + 0x3d, 0x5b, 0xe4, 0x0d, 0xde, 0x13, 0x4e, 0x92, 0x66, 0x43, 0x06, 0x9d, 0xff, 0xb4, 0x3f, 0x5a, + 0xef, 0x00, 0x83, 0x87, 0x71, 0x45, 0x90, 0xeb, 0x78, 0x84, 0x3d, 0xe3, 0xa9, 0xfd, 0xc3, 0x5e, + 0x5b, 0x1a, 0x0c, 0x98, 0xfb, 0xa6, 0x89, 0x6a, 0xcf, 0xaf, 0xdb, 0xac, 0xdc, 0xa5, 0x5f, 0x43, + 0x00, 0xae, 0xd8, 0x6c, 0x9c, 0x8b, 0x0f, 0xd6, 0x7c, 0x54, 0x74, 0xcf, 0xd4, 0x54, 0xb2, 0x54, + 0xe9, 0xc3, 0x68, 0x26, 0xef, 0x0a, 0xaa, 0xf9, 0x92, 0x9d, 0x46, 0x05, 0xc4, 0x9b, 0x27, 0xa8, + 0xea, 0x32, 0xe3, 0xe2, 0xdc, 0x19, 0xc4, 0x29, 0x6a, 0x59, 0x11, 0x4c, 0x24, 0xf5, 0xf9, 0x68, + 0xa7, 0x0a, 0xc6, 0x3d, 0xd6, 0xb2, 0xc4, 0x86, 0x85, 0x32, 0x60, 0xa1, 0x77, 0x55, 0xb3, 0x63, + 0x86, 0x0e, 0x49, 0x77, 0xbd, 0x4a, 0xc1, 0x7d, 0xce, 0x7c, 0x6a, 0x23, 0x0a, 0x40, 0x0a, 0x73, + 0x1a, 0x92, 0x5f, 0xe5, 0x7b, 0xae, 0x6d, 0xa4, 0xc9, 0xd1, 0x19, 0x17, 0xf5, 0x3a, 0x7f, 0x12, + 0x9e, 0x9d, 0x69, 0x5b, 0x4f, 0xd5, 0x30, 0x34, 0x28, 0xe5, 0x05, 0x80, 0xb3, 0x9a, 0x1f, 0x47, + 0xb7, 0x89, 0x5b, 0xd0, 0xcd, 0xe8, 0xd8, 0x33, 0x79, 0xdf, 0x11, 0xc7, 0x24, 0xdb, 0xbf, 0x6a, + 0x17, 0x86, 0x93, 0x46, 0xa2, 0xfc, 0xd3, 0xf2, 0x34, 0x5c, 0xd8, 0x08, 0xa4, 0xec, 0xdb, 0x49, + 0xb9, 0x00, 0xe8, 0xa5, 0xbd, 0x65, 0x5b, 0xda, 0xf4, 0x10, 0x1e, 0x80, 0xf5, 0x32, 0x91, 0xc2, + 0xf7, 0xd1, 0xd5, 0xdc, 0x50, 0x07, 0x92, 0x19, 0xc4, 0xa8, 0xd7, 0x16, 0xd6, 0xe8, 0x4e, 0xb9, + 0x1d, 0xd5, 0x83, 0x5d, 0x4b, 0xd4, 0xab, 0xdf, 0xd8, 0xb2, 0xd4, 0xd5, 0xb7, 0x09, 0xed, 0xe4, + 0x6f, 0xf6, 0x11, 0xd2, 0xff, 0xc6, 0x74, 0xfe, 0xee, 0xc0, 0xf1, 0xda, 0xd5, 0x81, 0x1e, 0xb2, + 0x2b, 0xc2, 0x47, 0x8a, 0x6c, 0x94, 0x27, 0xa1, 0xad, 0x09, 0xdb, 0xd9, 0xc9, 0x18, 0xbe, 0x68, + 0x2e, 0x4d, 0x62, 0x07, 0x97, 0xf5, 0x73, 0xde, 0xc5, 0x44, 0x43, 0xea, 0xf4, 0xa3, 0x65, 0x32, + 0x03, 0x57, 0x88, 0xe2, 0x9c, 0xf4, 0x3e, 0x74, 0x23, 0xf8, 0xaa, 0xad, 0x5e, 0x0b, 0x0f, 0x5c, + 0x2c, 0x03, 0x68, 0x1e, 0xd1, 0x1d, 0x3c, 0xd3, 0xdd, 0xab, 0x54, 0x0c, 0x9a, 0x72, 0x75, 0x7c, + 0x47, 0x97, 0x49, 0x64, 0xb4, 0x5d, 0xb6, 0xcf, 0x3e, 0x51, 0x2b, 0x0d, 0x9b, 0x4f, 0xdf, 0xe8, + 0x8e, 0x79, 0xc6, 0xc6, 0x70, 0x82, 0xba, 0x9c, 0xd6, 0x3b, 0x9d, 0x26, 0x5c, 0x78, 0x8e, 0x5a, + 0x33, 0xd7, 0x55, 0xd7, 0x79, 0xaf, 0x78, 0x7f, 0x8c, 0x9d, 0xfe, 0xec, 0x2f, 0xe9, 0x47, 0x26, + 0xef, 0xb7, 0x65, 0x03, 0xaf, 0x3c, 0x25, 0x35, 0x43, 0xc3, 0x95, 0xd2, 0x6b, 0xdc, 0x41, 0x96, + 0x2b, 0x95, 0x91, 0xe6, 0xb8, 0xeb, 0x12, 0xe9, 0xd7, 0x93, 0x66, 0xbf, 0xaf, 0xbf, 0xb1, 0xb8, + 0xdb, 0x75, 0x37, 0x65, 0xbb, 0x1d, 0x4d, 0x1f, 0xa4, 0xbc, 0x4a, 0xa9, 0x7e, 0x6f, 0xc4, 0x01, + 0xab, 0x89, 0x0d, 0xce, 0x9c, 0xdc, 0xad, 0x31, 0x6e, 0x64, 0x48, 0x7d, 0x6b, 0x25, 0x79, 0xd5, + 0x51, 0x25, 0x42, 0x6b, 0x23, 0x4b, 0x26, 0x53, 0xb9, 0x20, 0xe0, 0x30, 0x44, 0xfb, 0xdb, 0x15, + 0xc1, 0xce, 0x6b, 0x25, 0x2e, 0xc4, 0xa6, 0xaa, 0xcf, 0xa8, 0x33, 0x74, 0x4e, 0x84, 0x6d, 0x41, + 0x0e, 0x5d, 0x3a, 0x1c, 0xcd, 0x3e, 0x9b, 0xdf, 0x92, 0xf5, 0x99, 0x5a, 0xec, 0xaa, 0x27, 0x3c, + 0xa0, 0x97, 0xe8, 0x72, 0xf6, 0x22, 0x39, 0x2f, 0x5d, 0x9b, 0x1c, 0x69, 0xad, 0x5a, 0xc0, 0xd5, + 0x1a, 0x42, 0x01, 0xdb, 0xb2, 0xd1, 0x7a, 0x7f, 0x38, 0x89, 0xef, 0xbb, 0x9f, 0xa2, 0x77, 0x06, + 0x0d, 0xcb, 0x3a, 0xd6, 0xc6, 0xb7, 0xce, 0x05, 0x4c, 0xb2, 0x41, 0xdf, 0xad, 0x65, 0xfa, 0xaa, + 0xfe, 0x1d, 0xf9, 0xeb, 0xdc, 0xc3, 0xc2, 0xfe, 0x8d, 0xe9, 0xb4, 0x28, 0xef, 0xf5, 0x6c, 0xe5, + 0xf3, 0x41, 0xed, 0xb5, 0x65, 0x77, 0x64, 0x1d, 0x65, 0xb7, 0xfb, 0x4e, 0xfd, 0xcc, 0x37, 0x7c, + 0x56, 0x63, 0x78, 0x19, 0x24, 0x7b, 0x6f, 0xae, 0x2f, 0xb0, 0x32, 0xb4, 0xff, 0xa6, 0xfe, 0xb8, + 0xe2, 0x72, 0x76, 0x0c, 0x89, 0x87, 0x91, 0xb6, 0x9b, 0xf6, 0x5d, 0x9e, 0x6a, 0x58, 0x96, 0x38, + 0xae, 0x4a, 0x15, 0x64, 0x6b, 0xf5, 0x37, 0xeb, 0x66, 0x3a, 0x5d, 0x79, 0xc2, 0x41, 0x9b, 0x56, + 0x31, 0x99, 0xc9, 0x77, 0x77, 0x18, 0xa3, 0x34, 0x9d, 0x05, 0x97, 0xb9, 0x85, 0xae, 0x5a, 0xda, + 0x4c, 0x99, 0xc2, 0xb5, 0x99, 0xa4, 0xd1, 0x39, 0xdb, 0x81, 0x87, 0xdb, 0x6f, 0xdd, 0x3f, 0xba, + 0x9a, 0x45, 0x0e, 0xf2, 0xd7, 0x43, 0x3d, 0x14, 0x32, 0xab, 0x37, 0x14, 0x31, 0x54, 0x5f, 0x2d, + 0x13, 0x71, 0x78, 0xa1, 0xbe, 0x5c, 0x18, 0x6d, 0x36, 0x8c, 0x50, 0x20, 0xb4, 0x38, 0xdd, 0xdd, + 0x3f, 0xdd, 0x4c, 0x0f, 0x69, 0x79, 0x1a, 0xf4, 0xd6, 0xcb, 0x7a, 0xc1, 0xda, 0x00, 0x6c, 0x99, + 0xf6, 0x9b, 0x51, 0x45, 0xea, 0xa2, 0x7f, 0xb4, 0x28, 0xb6, 0x9d, 0x92, 0xdd, 0x1b, 0xe4, 0xea, + 0xaa, 0x68, 0x42, 0x76, 0x0f, 0xf3, 0x83, 0x2b, 0x26, 0x79, 0x23, 0x90, 0x04, 0xca, 0x52, 0xfc, + 0x5b, 0x70, 0x63, 0xc1, 0x7a, 0x7d, 0xe5, 0x01, 0x91, 0xca, 0x79, 0x57, 0x67, 0x17, 0x9d, 0x56, + 0x98, 0x88, 0x72, 0x3f, 0x90, 0x18, 0x9a, 0x95, 0x41, 0xab, 0x0c, 0x2b, 0x75, 0xd5, 0x2a, 0x65, + 0xd7, 0x63, 0x4c, 0xae, 0xd5, 0x3e, 0x54, 0x5a, 0x84, 0x93, 0x1d, 0xc5, 0x1e, 0xbc, 0xd5, 0xae, + 0x64, 0xb7, 0xae, 0x9c, 0xf9, 0x94, 0xef, 0x2c, 0x15, 0x13, 0x80, 0x5e, 0x56, 0x31, 0x81, 0xb0, + 0x4e, 0xed, 0x92, 0xfd, 0x7c, 0x3e, 0xd8, 0x8a, 0xe0, 0x45, 0x27, 0x94, 0xb0, 0x25, 0xb3, 0xcf, + 0x4c, 0xac, 0xcb, 0xb8, 0xfe, 0xb3, 0x7d, 0x04, 0xdd, 0x56, 0x9f, 0x04, 0xc2, 0xc9, 0xdd, 0x94, + 0x73, 0x59, 0x8c, 0x9d, 0x1a, 0xc1, 0x6e, 0xf4, 0x6f, 0x6a, 0xba, 0x5b, 0x7e, 0x63, 0x9a, 0x05, + 0xec, 0xab, 0xf1, 0x62, 0x51, 0xe2, 0xf4, 0x74, 0x91, 0x53, 0x18, 0xc3, 0xc4, 0xca, 0xae, 0x0f, + 0x64, 0x5f, 0x7b, 0xbb, 0x82, 0xea, 0x5a, 0x90, 0x6d, 0x79, 0x3e, 0x7e, 0x2d, 0xf3, 0xcb, 0xbc, + 0xb7, 0x26, 0xa9, 0xba, 0x0b, 0x5e, 0x34, 0x67, 0xa2, 0xe2, 0xfa, 0xac, 0xd6, 0xbf, 0xf1, 0xf0, + 0xea, 0xca, 0x26, 0x5e, 0x7b, 0x49, 0x8f, 0x17, 0x02, 0x81, 0xfd, 0x80, 0xab, 0x33, 0x5b, 0x41, + 0xbc, 0x49, 0xe7, 0x61, 0xbd, 0x2c, 0xb4, 0x16, 0x64, 0x33, 0xcb, 0xa1, 0x5e, 0x1f, 0x99, 0x54, + 0xa4, 0x34, 0x98, 0xcc, 0xef, 0x60, 0x91, 0x66, 0xb6, 0xa0, 0xd3, 0x4c, 0x99, 0x40, 0x8f, 0x7b, + 0x6c, 0x47, 0x9a, 0x9e, 0x5e, 0x46, 0x02, 0x74, 0x0b, 0x6f, 0x9d, 0x2f, 0x8f, 0xd7, 0x52, 0x4f, + 0xc6, 0xe6, 0x18, 0x7a, 0x3d, 0x27, 0xc3, 0x6a, 0x61, 0x93, 0xe2, 0xa6, 0xf5, 0x8e, 0xf3, 0x44, + 0x4e, 0x58, 0x29, 0x17, 0x0b, 0x7f, 0xb9, 0xdf, 0x3a, 0xa9, 0xc3, 0x8e, 0x5a, 0x91, 0xbe, 0x8c, + 0x2b, 0x8b, 0xaa, 0xbe, 0xb8, 0x52, 0xff, 0x24, 0xc8, 0x10, 0xe9, 0xf2, 0xd7, 0xa8, 0x4e, 0x5a, + 0x4e, 0x9c, 0x77, 0xa4, 0xc4, 0xa0, 0x0f, 0x83, 0xf6, 0x8c, 0xda, 0x30, 0xd1, 0x61, 0xbd, 0x6c, + 0x4d, 0x84, 0xf8, 0x0c, 0x41, 0x79, 0x84, 0x0a, 0x2d, 0xa2, 0x97, 0xcd, 0xa9, 0x5a, 0x65, 0xbb, + 0xda, 0xa9, 0xb4, 0xf2, 0x87, 0xe9, 0x57, 0x59, 0xdf, 0xd6, 0x08, 0xc2, 0xc2, 0x28, 0x07, 0xcc, + 0x2a, 0x1d, 0x19, 0xbe, 0xd3, 0x83, 0x34, 0x82, 0x94, 0xae, 0x43, 0xde, 0xa2, 0x49, 0xdd, 0x0e, + 0x35, 0x87, 0xae, 0xd3, 0x3d, 0x87, 0xca, 0x65, 0x4b, 0xbd, 0x75, 0x07, 0x4a, 0xe1, 0x00, 0x0f, + 0x4f, 0x5a, 0xaf, 0x7b, 0x44, 0x40, 0x6e, 0xaa, 0xea, 0xb7, 0xf4, 0xa2, 0xf5, 0x91, 0x9e, 0xc1, + 0xcc, 0x01, 0x3f, 0x9d, 0xb7, 0x25, 0x17, 0x57, 0xbb, 0xfa, 0x68, 0x4a, 0x98, 0x55, 0xd8, 0x34, + 0x60, 0xd9, 0x6d, 0x3e, 0x1a, 0xa7, 0xf2, 0x55, 0xe6, 0xd7, 0x3d, 0x57, 0xec, 0x7f, 0x6f, 0x3a, + 0xa0, 0xe6, 0x8b, 0x01, 0x74, 0x8a, 0x27, 0x8e, 0xb7, 0x72, 0x5a, 0xdf, 0xf9, 0xcf, 0x87, 0x41, + 0x1c, 0xf1, 0x6d, 0x1a, 0xf8, 0x25, 0x8c, 0xe7, 0xac, 0xc9, 0x80, 0x8f, 0xf3, 0x80, 0x37, 0x10, + 0x0e, 0x99, 0xd7, 0x20, 0x56, 0x28, 0x7c, 0x19, 0x26, 0xed, 0xbb, 0xe4, 0x6e, 0x9d, 0x87, 0x88, + 0xfd, 0xe1, 0x64, 0x05, 0xbf, 0x42, 0x54, 0x7a, 0x48, 0x5a, 0x16, 0xdc, 0x97, 0x88, 0xfa, 0x6a, + 0x05, 0x73, 0xd5, 0x27, 0x62, 0xf3, 0x51, 0x4a, 0xa2, 0x75, 0x84, 0x6b, 0xbc, 0xb5, 0x04, 0xaa, + 0xe4, 0xac, 0x95, 0xce, 0x02, 0xda, 0xb0, 0xd4, 0xa7, 0x96, 0xc4, 0xf1, 0x2f, 0x98, 0x34, 0x07, + 0xcd, 0xcb, 0x65, 0xe6, 0xcd, 0xba, 0x90, 0x57, 0x01, 0xd8, 0x1f, 0xe5, 0xe2, 0x47, 0x24, 0x20, + 0xc9, 0x41, 0x5b, 0x33, 0x5b, 0x6b, 0xf5, 0x40, 0x38, 0xba, 0x6f, 0x0d, 0x04, 0xe6, 0xd7, 0x2e, + 0x03, 0x33, 0x3a, 0x20, 0x86, 0x72, 0x42, 0x3a, 0x68, 0x2e, 0x9c, 0x2c, 0x41, 0xac, 0x19, 0x6c, + 0xad, 0x72, 0x0c, 0x27, 0x8f, 0xad, 0x91, 0x6a, 0x59, 0x1c, 0x0e, 0xb2, 0xe7, 0xd7, 0xbc, 0x90, + 0x48, 0x2e, 0xde, 0x67, 0xa6, 0xe6, 0xa5, 0xea, 0xd0, 0x7f, 0x8e, 0xfd, 0xaf, 0x17, 0x44, 0xa7, + 0x1f, 0x00, 0x9c, 0xff, 0xfc, 0xa4, 0xfe, 0x20, 0x95, 0xfe, 0xbc, 0xbe, 0x84, 0xd0, 0x1b, 0x52, + 0x4b, 0xc2, 0x87, 0xa7, 0xf2, 0xd5, 0x36, 0x76, 0x2a, 0x97, 0xb7, 0xaf, 0xc6, 0x41, 0x91, 0xe4, + 0xea, 0xe7, 0x61, 0xe2, 0x1d, 0xe6, 0x73, 0x51, 0x2a, 0x66, 0x34, 0x3a, 0xb1, 0xe9, 0xff, 0x38, + 0xd1, 0x61, 0xe8, 0xe7, 0x89, 0x1a, 0x67, 0x19, 0xb9, 0xef, 0x8e, 0x99, 0x6d, 0x99, 0x01, 0x7c, + 0x4a, 0xba, 0xf6, 0x1a, 0x62, 0xdd, 0xe4, 0xd6, 0x7d, 0x2c, 0x5e, 0x05, 0x37, 0xca, 0xa5, 0xed, + 0xff, 0x5c, 0xfd, 0xb1, 0xfa, 0x0c, 0x93, 0x10, 0x6b, 0xff, 0x96, 0xf3, 0x45, 0x5f, 0x22, 0xa1, + 0xd9, 0xfd, 0x5f, 0xb3, 0x93, 0xd7, 0xea, 0xc0, 0x6f, 0xda, 0xf4, 0x6a, 0xae, 0xe7, 0xaf, 0x69, + 0xee, 0x23, 0xaf, 0x50, 0xa1, 0x9a, 0xbe, 0xbb, 0x9a, 0xdc, 0xed, 0xd6, 0xa1, 0x0d, 0x87, 0xf6, + 0xfb, 0x61, 0x28, 0x0f, 0x4c, 0x5a, 0xa9, 0x4c, 0xfe, 0x4b, 0xb2, 0x72, 0x0f, 0xd9, 0x6c, 0xc9, + 0x74, 0xd2, 0xfd, 0xbd, 0x3f, 0x83, 0x05, 0x1c, 0xe7, 0x03, 0x9d, 0x53, 0x5b, 0xfc, 0xa4, 0x53, + 0x84, 0xaa, 0xba, 0xd3, 0x0c, 0x96, 0x29, 0xca, 0xd4, 0xe5, 0x8a, 0x61, 0xbd, 0x7f, 0x98, 0x4d, + 0x16, 0xd2, 0xfe, 0xfa, 0x56, 0xe1, 0x90, 0x09, 0x8d, 0xb1, 0x73, 0x92, 0x36, 0x30, 0x87, 0x99, + 0xba, 0xbc, 0x0a, 0xc3, 0x1c, 0x86, 0x8c, 0xa1, 0xf4, 0x1f, 0xe1, 0xda, 0xcf, 0xc5, 0xe1, 0xd7, + 0xb5, 0xf1, 0xa2, 0xbc, 0x7f, 0x32, 0x9a, 0x96, 0x09, 0x9e, 0x8f, 0xce, 0x47, 0x85, 0x78, 0xe4, + 0x55, 0x8e, 0xc0, 0xae, 0xdc, 0x28, 0x11, 0xcc, 0x2c, 0xe0, 0x71, 0x8d, 0x67, 0x19, 0xbb, 0xed, + 0x36, 0xd5, 0xcb, 0xdb, 0xf5, 0x74, 0x41, 0xd7, 0xd5, 0xa4, 0xe6, 0x85, 0x7b, 0xde, 0xa4, 0x6a, + 0x2b, 0x29, 0x9b, 0x4d, 0x86, 0xc0, 0xc6, 0x11, 0x9c, 0xbf, 0xec, 0x65, 0xb1, 0x41, 0x81, 0xc9, + 0xf0, 0xe7, 0x6b, 0xd1, 0x2e, 0xd2, 0xd2, 0xb9, 0x7f, 0x14, 0x26, 0xd9, 0x81, 0x77, 0x21, 0x0e, + 0x69, 0xfe, 0xd5, 0x8f, 0x5b, 0xbe, 0x53, 0x93, 0x28, 0x4c, 0x9f, 0xaa, 0x5a, 0x05, 0x53, 0x13, + 0x1c, 0xda, 0x76, 0x1e, 0x08, 0xfe, 0xc3, 0x45, 0x82, 0x8e, 0x38, 0x80, 0x87, 0x04, 0xdc, 0x23, + 0x3c, 0x5b, 0x06, 0xb7, 0xb3, 0xd5, 0x20, 0x18, 0x99, 0x4f, 0x3b, 0xcc, 0x29, 0x9d, 0x72, 0xf9, + 0x45, 0x5c, 0x33, 0xb5, 0x6c, 0x82, 0x53, 0x8b, 0x4a, 0xa0, 0x8f, 0xd9, 0xef, 0x00, 0x74, 0xf3, + 0xd5, 0x38, 0x7c, 0x40, 0x5b, 0xb4, 0xd1, 0x66, 0xcd, 0x00, 0xbd, 0xcb, 0xf2, 0x58, 0xca, 0xf8, + 0xba, 0x9d, 0x4c, 0xa9, 0xb3, 0xd9, 0x91, 0x48, 0x89, 0xf2, 0xb5, 0xfe, 0x2e, 0x93, 0x6e, 0x83, + 0xfb, 0xcd, 0x66, 0x67, 0x6f, 0x3b, 0x00, 0xfd, 0xba, 0xe7, 0x4a, 0xe8, 0x37, 0xa6, 0x05, 0x15, + 0x6a, 0xf7, 0xdf, 0x46, 0x9e, 0x2c, 0xfe, 0xd8, 0x89, 0xa1, 0xd5, 0x2a, 0x61, 0xb2, 0x66, 0xd0, + 0xbc, 0x7d, 0x00, 0xad, 0x93, 0xe2, 0xa1, 0xa4, 0xa6, 0xfc, 0x64, 0x19, 0x41, 0xcd, 0xea, 0xc0, + 0xda, 0x6b, 0xd9, 0x0c, 0x8f, 0x30, 0xdb, 0xb4, 0x1d, 0xdc, 0x6c, 0x3a, 0xdd, 0xdd, 0x56, 0xd8, + 0x9a, 0x44, 0xb6, 0x34, 0x89, 0x6c, 0x47, 0xb3, 0xac, 0xc3, 0x60, 0x5b, 0x12, 0x8b, 0x64, 0x10, + 0xd0, 0xbc, 0xfe, 0x4a, 0x3b, 0xe5, 0x7b, 0x46, 0x3a, 0xaa, 0xec, 0xef, 0x7a, 0x37, 0x73, 0x48, + 0x35, 0xb9, 0x51, 0xa5, 0x93, 0xc0, 0xcf, 0x41, 0xa9, 0xc6, 0xcd, 0x8e, 0xf0, 0xb0, 0xbf, 0x47, + 0x5f, 0xd5, 0x92, 0xcd, 0x05, 0xd7, 0x69, 0x0a, 0x91, 0x96, 0x06, 0x30, 0x2f, 0x49, 0x8d, 0xfc, + 0x45, 0x96, 0xb5, 0x3a, 0x29, 0x2e, 0xf6, 0xf0, 0xa3, 0x42, 0x9e, 0xdc, 0x3c, 0xe5, 0x57, 0x3d, + 0xb6, 0x95, 0x2c, 0x4f, 0x85, 0xee, 0x26, 0x0a, 0x92, 0x7a, 0xa9, 0xab, 0xcd, 0x5c, 0x51, 0x05, + 0xeb, 0xb3, 0x32, 0x1d, 0xc9, 0x99, 0x64, 0x5c, 0x1d, 0x5d, 0x18, 0x7a, 0x8d, 0xe8, 0xbd, 0x7e, + 0x3b, 0x4d, 0x0d, 0x64, 0xba, 0xca, 0xf3, 0xb7, 0xb3, 0xf7, 0xfc, 0xe0, 0x77, 0xde, 0x79, 0xe7, + 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, + 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0xff, + 0x3d, 0xf9, 0xcf, 0xf7, 0xc1, 0x7f, 0x1f, 0xbf, 0x11, 0x0d, 0xeb, 0x0f, 0x33, 0x1f, 0x57, 0x63, + 0xdb, 0x81, 0x20, 0x2b, 0x53, 0x7a, 0xc2, 0x84, 0x39, 0x68, 0xba, 0x2c, 0x32, 0x78, 0x03, 0xe1, + 0x58, 0xec, 0xb0, 0xbe, 0x2a, 0x5e, 0x3b, 0x64, 0x7e, 0xbe, 0x54, 0xa1, 0xd9, 0x55, 0x2d, 0xf4, + 0x7f, 0x89, 0xf3, 0x98, 0x56, 0x85, 0x1f, 0x03, 0x2c, 0xf9, 0x31, 0x8c, 0xad, 0xf2, 0x44, 0x9e, + 0x48, 0x28, 0x25, 0x6e, 0x07, 0xd8, 0xa9, 0xb5, 0x70, 0x20, 0x94, 0x5a, 0x6b, 0x07, 0x52, 0x29, + 0x49, 0x38, 0x70, 0xce, 0x3b, 0x7e, 0x4a, 0xc1, 0xb7, 0x66, 0xd9, 0xd4, 0x14, 0xa8, 0x38, 0x8f, + 0xd4, 0xe7, 0x24, 0x38, 0x57, 0x04, 0x8b, 0xd7, 0xea, 0x72, 0xb1, 0x41, 0x6d, 0xb3, 0x26, 0x9f, + 0x4f, 0x35, 0x6c, 0xb9, 0x74, 0xbd, 0xc4, 0x48, 0x9f, 0x37, 0xd8, 0x9b, 0x2d, 0x42, 0xb3, 0x83, + 0xf1, 0xf7, 0xf7, 0xd3, 0x04, 0x8f, 0x0f, 0x51, 0xa9, 0x25, 0xc4, 0x02, 0xb1, 0xb8, 0x1e, 0x28, + 0x35, 0xfd, 0x26, 0xf9, 0x12, 0x5d, 0x42, 0x0d, 0x5f, 0x22, 0x21, 0x51, 0xe9, 0xf0, 0x72, 0xbc, + 0x97, 0xf3, 0x42, 0x96, 0xf2, 0xda, 0xfe, 0x53, 0x88, 0xb1, 0x02, 0xff, 0xca, 0x4c, 0x9b, 0x40, + 0x88, 0x33, 0x47, 0x49, 0x7b, 0x21, 0xc9, 0x7e, 0x2c, 0xa0, 0x03, 0xdd, 0x96, 0x74, 0x08, 0x8b, + 0x79, 0x11, 0x3e, 0x77, 0x60, 0x41, 0xc2, 0x16, 0x49, 0x2c, 0x8c, 0xe3, 0xd0, 0x41, 0x76, 0x24, + 0x8e, 0x49, 0x2a, 0xaf, 0xd2, 0x7b, 0x75, 0x27, 0x11, 0x5e, 0xf7, 0x7a, 0x0a, 0xe1, 0x43, 0xaf, + 0x67, 0x29, 0xec, 0xf1, 0x7a, 0x0c, 0xe1, 0xe3, 0xe4, 0x9f, 0x48, 0xfc, 0x2e, 0xe8, 0x5a, 0x05, + 0xf7, 0x51, 0xb2, 0x63, 0x18, 0x42, 0x5d, 0x16, 0xaf, 0xe4, 0x0f, 0x4d, 0x5b, 0xa5, 0x77, 0x3e, + 0x0d, 0xcf, 0x82, 0xfd, 0xa3, 0xc1, 0x23, 0xc4, 0x47, 0x0a, 0x9e, 0x11, 0xa8, 0xe4, 0xe4, 0x87, + 0x1e, 0xb6, 0x74, 0x35, 0x16, 0x20, 0x11, 0xd3, 0x8e, 0x1b, 0xd2, 0x26, 0xf6, 0x06, 0xbf, 0xc6, + 0x24, 0x4d, 0x6d, 0x29, 0xfe, 0xde, 0xf4, 0x8d, 0x04, 0x51, 0xaa, 0xc1, 0x7b, 0x6d, 0xa9, 0xce, + 0xe5, 0x87, 0xf7, 0xc3, 0xa9, 0xd8, 0xb3, 0x3b, 0x00, 0x17, 0x78, 0xe9, 0xb3, 0x94, 0xa8, 0x13, + 0x4d, 0xa0, 0x80, 0x0e, 0xef, 0xab, 0x8d, 0xeb, 0x8f, 0x17, 0x68, 0x66, 0xed, 0x7b, 0xf0, 0x56, + 0xa6, 0xda, 0x67, 0xec, 0x15, 0xb1, 0x98, 0xd1, 0x6c, 0x69, 0x9f, 0x18, 0x75, 0x85, 0xf1, 0x58, + 0x88, 0x8a, 0x05, 0xf2, 0x6a, 0x57, 0x73, 0x89, 0xea, 0x8d, 0x90, 0x5f, 0x3a, 0x72, 0x10, 0x80, + 0xff, 0xb2, 0x65, 0x60, 0x20, 0xe8, 0xbc, 0xf8, 0x1c, 0x63, 0xf4, 0x8a, 0x7b, 0xdc, 0xab, 0xe6, + 0x49, 0xb7, 0xcf, 0xb2, 0x72, 0x14, 0x82, 0xa7, 0xcb, 0x6e, 0xe0, 0x4f, 0xa4, 0x02, 0x43, 0x9e, + 0xc0, 0xbc, 0xf4, 0x85, 0xd9, 0x9a, 0x97, 0xec, 0x30, 0x06, 0x39, 0x80, 0x7b, 0x42, 0xf3, 0xb2, + 0x6d, 0x44, 0xae, 0xea, 0x8a, 0xc7, 0xf2, 0xf9, 0x7d, 0xf4, 0x54, 0xa0, 0xc8, 0xc4, 0xce, 0xb2, + 0x62, 0x1f, 0x02, 0x33, 0xb7, 0xa4, 0xa7, 0x3c, 0xaf, 0x93, 0x88, 0xc7, 0x22, 0xdd, 0xd3, 0x59, + 0x23, 0x20, 0x3a, 0x3e, 0x1b, 0x15, 0xa4, 0x12, 0xa2, 0xa5, 0x12, 0xe7, 0x20, 0xee, 0x8a, 0xd0, + 0xe2, 0x6e, 0x27, 0x85, 0xc4, 0xe5, 0x98, 0x4b, 0x48, 0xc8, 0x59, 0xf9, 0x3c, 0x60, 0x1d, 0xcf, + 0x60, 0xc7, 0x34, 0x2d, 0x07, 0x94, 0x8f, 0x48, 0xfd, 0x93, 0x30, 0x53, 0x0f, 0x8a, 0x24, 0xc8, + 0xd1, 0x07, 0xd9, 0xc6, 0x4e, 0x9d, 0x4b, 0xde, 0x07, 0x34, 0x72, 0x91, 0x56, 0xdb, 0x02, 0x09, + 0x5e, 0x62, 0x98, 0x6e, 0x1d, 0x6f, 0xc8, 0xf9, 0xe5, 0xd3, 0xb4, 0xbb, 0x9c, 0x90, 0x3c, 0x85, + 0xae, 0x85, 0x62, 0xfd, 0x61, 0x01, 0x93, 0x7a, 0xec, 0xb7, 0x84, 0x14, 0x53, 0x2f, 0x86, 0x25, + 0x98, 0xda, 0x48, 0xc8, 0x14, 0x81, 0x65, 0xf1, 0xb6, 0xff, 0x2a, 0x6d, 0x96, 0x1c, 0x07, 0xb2, + 0x36, 0x33, 0x0d, 0xa7, 0x16, 0xb4, 0x2a, 0x5c, 0x0e, 0xe2, 0xf7, 0x1a, 0xf6, 0x8a, 0xf2, 0xfe, + 0xd7, 0x38, 0x3b, 0xb6, 0xfe, 0x37, 0xa6, 0xf3, 0xbf, 0xc6, 0x24, 0x1d, 0xb1, 0x92, 0x57, 0x6f, + 0xc8, 0xff, 0x3d, 0x26, 0xa9, 0x77, 0xfb, 0x12, 0x26, 0xed, 0xfa, 0xfe, 0x3f, 0xff, 0xff, 0x10, + 0x93, 0x64, 0x3a, 0x47, 0xff, 0x1f, 0x62, 0x92, 0x0e, 0x64, 0x2b, 0x61, 0xc1, 0x7a, 0xf5, 0x6f, + 0x6a, 0x9b, 0xb1, 0x7f, 0x63, 0x3a, 0xc3, 0xf3, 0x3e, 0x26, 0x1a, 0xe8, 0x86, 0x79, 0x0b, 0x5e, + 0xbd, 0x38, 0x3e, 0x09, 0xdc, 0x98, 0x48, 0xcf, 0x54, 0xae, 0x8d, 0xc2, 0x53, 0x15, 0x69, 0x80, + 0x3b, 0xb5, 0xa5, 0x87, 0x95, 0x1f, 0x57, 0xe3, 0xcc, 0xbf, 0xb2, 0xb9, 0x5c, 0x9c, 0x3d, 0xa5, + 0x2a, 0x3c, 0x31, 0xf9, 0x88, 0x75, 0x63, 0xd1, 0xe8, 0x2c, 0x9e, 0x8c, 0xec, 0x7d, 0x44, 0x7b, + 0x2d, 0x10, 0x3f, 0xc4, 0x8e, 0xf1, 0x7b, 0x9d, 0x26, 0x92, 0xeb, 0x5a, 0xd6, 0x93, 0x4b, 0x3c, + 0xad, 0x72, 0x21, 0xc7, 0x73, 0xf8, 0x3c, 0x42, 0xd4, 0x9c, 0xe1, 0xcc, 0xc8, 0x9f, 0x1e, 0x92, + 0xe5, 0xa2, 0xe3, 0x20, 0x10, 0x2a, 0xea, 0x90, 0x4d, 0x0c, 0xde, 0x3d, 0x19, 0x09, 0x7a, 0x96, + 0x8d, 0x8f, 0x0d, 0xd4, 0xe2, 0x4d, 0xb4, 0x8d, 0x06, 0x90, 0x0c, 0xe1, 0xb6, 0xb5, 0x32, 0x2b, + 0x33, 0x58, 0x27, 0x67, 0x79, 0x7f, 0xed, 0x93, 0x1f, 0x79, 0x0f, 0xc1, 0x52, 0xbd, 0x6c, 0x5e, + 0x9f, 0x24, 0x2c, 0xdf, 0x26, 0x80, 0x2c, 0x55, 0x35, 0x60, 0xdd, 0xbe, 0x89, 0xf6, 0x38, 0x97, + 0x85, 0x8f, 0xb0, 0x28, 0xe6, 0xa4, 0x7b, 0x85, 0x9c, 0x23, 0x81, 0xb1, 0xa7, 0xf7, 0xf6, 0x7b, + 0xf9, 0xb6, 0x89, 0xe6, 0x28, 0xe7, 0xba, 0x3e, 0x0f, 0x77, 0x54, 0xea, 0xd7, 0x78, 0xfd, 0xa7, + 0x93, 0x51, 0xaa, 0xbf, 0xeb, 0xab, 0xdf, 0xce, 0xe9, 0x1e, 0x9a, 0xea, 0xde, 0xc1, 0xc1, 0x42, + 0x99, 0xc9, 0x3c, 0x66, 0x2c, 0xbd, 0xd2, 0xf1, 0x51, 0x6b, 0x12, 0x7f, 0x18, 0xb1, 0xdb, 0x45, + 0x74, 0x71, 0x96, 0x34, 0xd7, 0xd8, 0x63, 0xbe, 0xee, 0x80, 0xd3, 0x2a, 0x3e, 0x5b, 0xc7, 0x37, + 0xb7, 0xbb, 0x41, 0xcb, 0x58, 0xe8, 0xee, 0xbd, 0x21, 0xf9, 0xfd, 0x53, 0x17, 0xd6, 0x36, 0x7d, + 0x09, 0xdc, 0x86, 0xbf, 0x9d, 0x24, 0x43, 0xc5, 0x6f, 0xd0, 0xa2, 0xcc, 0x99, 0x70, 0x5d, 0xdc, + 0x54, 0xad, 0x4d, 0x60, 0x1a, 0x3d, 0x50, 0xee, 0x06, 0xee, 0x2d, 0xeb, 0x0f, 0x37, 0x26, 0x7f, + 0x9c, 0x33, 0xf3, 0x47, 0x1b, 0x01, 0x7e, 0x8d, 0xb3, 0xb3, 0xfc, 0xc6, 0x34, 0x2b, 0x66, 0x08, + 0x10, 0x9d, 0x32, 0x76, 0x0a, 0xcd, 0x19, 0x0b, 0x8a, 0x0c, 0x6b, 0xba, 0x8a, 0x1c, 0x76, 0x53, + 0xd4, 0xce, 0x0b, 0x63, 0xb7, 0xae, 0x61, 0xd9, 0xbe, 0x61, 0x63, 0x59, 0xa3, 0xf0, 0xa1, 0xbe, + 0xe9, 0x57, 0x33, 0x86, 0x4f, 0xd1, 0xa2, 0x20, 0x9a, 0x2b, 0xab, 0x6c, 0x5b, 0xd9, 0x64, 0x26, + 0x9d, 0xea, 0x52, 0x44, 0xf2, 0xa1, 0xcd, 0xc7, 0x3a, 0x9a, 0xcd, 0x89, 0xa4, 0x8b, 0x0e, 0x09, + 0x45, 0xa9, 0x3e, 0x5a, 0x50, 0x19, 0x10, 0x8c, 0xd5, 0x0e, 0x3f, 0x56, 0xca, 0x68, 0x07, 0xe5, + 0x21, 0xdb, 0xde, 0x8f, 0x30, 0x88, 0x49, 0x03, 0x65, 0xfb, 0x6d, 0xb8, 0x65, 0xb4, 0x8a, 0xcd, + 0xb0, 0x08, 0x4b, 0x2b, 0x7d, 0xa1, 0x7c, 0x36, 0x5d, 0x0f, 0x4e, 0xdf, 0x5f, 0x20, 0x0a, 0xfb, + 0x76, 0x17, 0x4f, 0x0b, 0xd6, 0xa2, 0xe7, 0x8d, 0x42, 0x0e, 0x5a, 0x08, 0x96, 0xe3, 0x17, 0xaf, + 0xb9, 0x5b, 0x17, 0x15, 0x9c, 0x36, 0xe5, 0x20, 0xeb, 0xb9, 0x69, 0x3d, 0x1d, 0xba, 0x49, 0x29, + 0x63, 0x01, 0x4e, 0x4e, 0x09, 0x3b, 0xd9, 0xb9, 0xde, 0x64, 0x63, 0x7a, 0xb2, 0x16, 0x46, 0xc3, + 0xda, 0x3b, 0xc0, 0x22, 0x78, 0xdd, 0xa1, 0x82, 0x7c, 0xe3, 0x43, 0x7c, 0x76, 0x18, 0xed, 0x81, + 0xde, 0x19, 0x8b, 0xfb, 0x0b, 0xce, 0x5d, 0x20, 0x5e, 0xdf, 0x52, 0x37, 0x39, 0xa9, 0x77, 0x53, + 0xeb, 0x1a, 0x36, 0x7a, 0x80, 0x27, 0xee, 0x9a, 0x09, 0xbb, 0x0e, 0x1f, 0x3b, 0xa0, 0x11, 0x80, + 0x36, 0x14, 0x14, 0x15, 0x6c, 0xe8, 0xf8, 0x25, 0x8c, 0x25, 0xa3, 0x91, 0x07, 0x86, 0x55, 0x0b, + 0xce, 0xa5, 0xa5, 0xc8, 0xc8, 0xd9, 0xc4, 0x86, 0x6b, 0x13, 0x0b, 0xfb, 0xf6, 0x38, 0xc0, 0x42, + 0xb4, 0xfb, 0x89, 0x08, 0xea, 0x9e, 0xb4, 0x42, 0x82, 0xb5, 0xa6, 0x94, 0x88, 0xc3, 0xc6, 0xb5, + 0x10, 0xcf, 0x04, 0xe9, 0x2a, 0x4c, 0x2f, 0xa0, 0xf8, 0x5f, 0x0a, 0xcc, 0x56, 0x7e, 0xad, 0xe9, + 0xae, 0xb6, 0xff, 0xc6, 0xf4, 0xac, 0x54, 0x04, 0x2d, 0xaa, 0x04, 0x0f, 0x38, 0xa2, 0x73, 0xb9, + 0x3d, 0xe4, 0x66, 0x46, 0x9a, 0x2c, 0x1b, 0xc4, 0x8a, 0x03, 0x3a, 0x70, 0xeb, 0xfe, 0x12, 0xee, + 0xe8, 0xc2, 0x87, 0x87, 0x23, 0x91, 0xb4, 0x7e, 0x1c, 0xe2, 0x16, 0x55, 0xc1, 0x0f, 0xd2, 0x7b, + 0x48, 0x6d, 0xe8, 0x8b, 0x95, 0xb5, 0x4d, 0x71, 0x18, 0x9a, 0xcd, 0x16, 0x64, 0x8e, 0x47, 0xc6, + 0xd0, 0xf1, 0xa6, 0xe6, 0x25, 0x26, 0x1c, 0xb0, 0xdd, 0xed, 0x92, 0x2b, 0xa9, 0x7b, 0x14, 0x3a, + 0x64, 0x94, 0x8a, 0x18, 0x7a, 0x1b, 0x19, 0x5e, 0x1c, 0xa6, 0xbb, 0x7a, 0x66, 0x8a, 0x95, 0xbd, + 0x95, 0xa4, 0xac, 0xc2, 0xda, 0x17, 0xf2, 0x9a, 0xe5, 0xd8, 0x20, 0x67, 0xb5, 0xeb, 0xe7, 0x3e, + 0x2b, 0x7f, 0x04, 0x02, 0x1b, 0xab, 0x15, 0x68, 0x61, 0x22, 0xca, 0x5c, 0x40, 0x1c, 0xa5, 0x02, + 0x3c, 0x9a, 0x2b, 0x8b, 0xdd, 0x57, 0xa1, 0x85, 0xd8, 0xe5, 0xbf, 0xd9, 0x9f, 0xac, 0x3e, 0x5f, + 0x57, 0x75, 0xec, 0xbe, 0x08, 0x0a, 0x15, 0x49, 0x7f, 0x4b, 0x95, 0x15, 0x77, 0xa7, 0x94, 0xc7, + 0x3e, 0xf5, 0x92, 0x84, 0x1f, 0xb0, 0xd6, 0xbb, 0xd2, 0xfd, 0x14, 0xc7, 0x7a, 0x7a, 0x08, 0x05, + 0x38, 0xfb, 0x77, 0x47, 0x9f, 0x85, 0xbe, 0x35, 0x28, 0x14, 0xfd, 0x86, 0x63, 0x0b, 0x55, 0x0b, + 0x84, 0x59, 0xaa, 0xd0, 0x63, 0xf9, 0xdc, 0x91, 0xfb, 0x8e, 0x59, 0x49, 0x34, 0x59, 0x41, 0x55, + 0x56, 0x95, 0x57, 0x64, 0xc0, 0x4b, 0x89, 0x09, 0x9f, 0x34, 0x5a, 0x9b, 0x9c, 0x6b, 0x5d, 0xc0, + 0x7e, 0xab, 0x7c, 0x62, 0x84, 0xa6, 0x6b, 0x1d, 0xe4, 0x5c, 0x82, 0x22, 0x3d, 0xa4, 0xbf, 0xde, + 0x0c, 0xdf, 0x2a, 0x09, 0xf5, 0x11, 0x21, 0x7e, 0x41, 0xa6, 0x36, 0x22, 0x43, 0xa0, 0x97, 0x12, + 0xdd, 0x1f, 0xfa, 0x53, 0x86, 0x18, 0x2e, 0x5b, 0x95, 0x13, 0xe7, 0x81, 0xd0, 0xb4, 0xf4, 0x04, + 0x45, 0x84, 0x07, 0xf5, 0x63, 0x42, 0x82, 0x42, 0x91, 0xb6, 0x25, 0xfa, 0xa5, 0x3d, 0xd2, 0x2a, + 0x1e, 0x7e, 0xad, 0xca, 0x6c, 0x01, 0x7e, 0x63, 0x9a, 0x5f, 0x38, 0x76, 0x67, 0x66, 0xc3, 0x20, + 0xd5, 0x3c, 0xbf, 0xdd, 0x08, 0x40, 0xea, 0xec, 0xed, 0x65, 0x3d, 0xc0, 0xb1, 0x79, 0x3e, 0xe0, + 0x20, 0xf0, 0x74, 0x64, 0xb4, 0xe9, 0x9f, 0xbc, 0xd4, 0xbc, 0xc9, 0xa3, 0x5e, 0x42, 0x9d, 0x1d, + 0x68, 0xc9, 0xa8, 0xec, 0xfa, 0xd4, 0x21, 0x85, 0xf5, 0xb0, 0x3f, 0xdf, 0xb3, 0x34, 0x53, 0x3a, + 0x73, 0x73, 0x0e, 0xc5, 0x76, 0x3d, 0x3b, 0xf9, 0x6e, 0x1b, 0xa2, 0xed, 0x7d, 0x05, 0xd5, 0x2c, + 0xff, 0xbc, 0x37, 0x23, 0x69, 0x8e, 0x8c, 0x3c, 0x8e, 0x87, 0x87, 0x97, 0xcd, 0xbc, 0xce, 0xe8, + 0x4e, 0xce, 0xae, 0xae, 0x95, 0x10, 0xab, 0xdc, 0xbd, 0x96, 0xca, 0xf6, 0xcc, 0x3b, 0x50, 0x64, + 0x75, 0xcd, 0x3d, 0xb1, 0x64, 0xff, 0xda, 0x87, 0x96, 0x56, 0x23, 0x2f, 0xc8, 0xea, 0xaa, 0xf4, + 0xe4, 0x48, 0x60, 0x72, 0xc3, 0x7a, 0x24, 0xf5, 0xed, 0xb2, 0x2e, 0xfa, 0x74, 0xe9, 0xf6, 0x4e, + 0x97, 0x7f, 0x0e, 0x01, 0x22, 0xf6, 0xb3, 0x84, 0x2e, 0x96, 0x8f, 0x9f, 0x53, 0x5b, 0x5c, 0xc5, + 0xe9, 0x94, 0xd3, 0xa8, 0xd2, 0x2f, 0x6f, 0x9a, 0x44, 0x8e, 0x0c, 0x4b, 0x74, 0xaf, 0x84, 0x3e, + 0x4f, 0x03, 0x6f, 0x27, 0xf8, 0x1c, 0x75, 0xd7, 0x40, 0xed, 0xf7, 0x36, 0x5b, 0x40, 0x29, 0x7d, + 0x3e, 0x0a, 0x65, 0x95, 0x07, 0xcd, 0x85, 0x90, 0x80, 0x0c, 0xcc, 0x72, 0xef, 0x46, 0x38, 0xa2, + 0x70, 0xd4, 0xb1, 0x90, 0x2c, 0x21, 0x0d, 0x72, 0xf4, 0x3b, 0x03, 0x77, 0x58, 0x1a, 0x3e, 0x2c, + 0x07, 0xcb, 0xe0, 0x49, 0xdf, 0xde, 0xca, 0x6f, 0xa0, 0x6d, 0x60, 0xe4, 0xcf, 0xa8, 0x6d, 0x3b, + 0x9d, 0xd4, 0x42, 0xcc, 0x04, 0x7f, 0x48, 0x5a, 0x4b, 0xde, 0xd6, 0xcd, 0xf4, 0x76, 0x72, 0x33, + 0x57, 0x7c, 0x20, 0xff, 0xc4, 0x9d, 0x3d, 0x69, 0x70, 0x45, 0x52, 0x84, 0x88, 0xeb, 0xd9, 0xca, + 0x03, 0x2c, 0xdf, 0xdb, 0x73, 0xb1, 0xec, 0xd3, 0x2f, 0xdd, 0xce, 0xe7, 0x05, 0xad, 0xda, 0x55, + 0x84, 0xc1, 0x4b, 0x7a, 0xc5, 0xe6, 0xb6, 0xa0, 0xbf, 0xee, 0x4f, 0x11, 0xfa, 0x8d, 0x69, 0x21, + 0x1a, 0x06, 0x14, 0x64, 0xce, 0xa7, 0xfb, 0xf9, 0x40, 0xfe, 0xaf, 0x29, 0x63, 0xd9, 0xb5, 0x8e, + 0x22, 0x00, 0x20, 0xbb, 0x21, 0x02, 0xe5, 0xc1, 0x8a, 0xb1, 0x04, 0xd1, 0x42, 0x52, 0xf4, 0x39, + 0xa8, 0xc0, 0xa7, 0x11, 0x5d, 0xfd, 0xfd, 0xb0, 0xff, 0x3a, 0xcc, 0xc2, 0xfe, 0x75, 0xcf, 0x15, + 0xe4, 0x37, 0xa6, 0x97, 0xb6, 0x6a, 0xeb, 0x30, 0xc9, 0x15, 0xfb, 0x21, 0x76, 0x77, 0x1d, 0xfa, + 0x12, 0xe2, 0xef, 0x49, 0x3e, 0x32, 0x39, 0x5e, 0x25, 0xd8, 0xd6, 0x7e, 0x3d, 0x39, 0xbc, 0xd9, + 0xda, 0xc3, 0xf5, 0x6c, 0xe6, 0xd9, 0x11, 0x69, 0xba, 0xf6, 0x25, 0x1c, 0x35, 0x70, 0xa0, 0x0a, + 0xc8, 0x95, 0xce, 0xf3, 0xb3, 0x8c, 0xd6, 0x41, 0x78, 0xb2, 0x02, 0x3e, 0xf5, 0x21, 0xf4, 0x1c, + 0x3b, 0xd5, 0xe7, 0x17, 0xa4, 0xa5, 0x64, 0x7e, 0xde, 0xd5, 0x66, 0x36, 0x60, 0x52, 0x7a, 0x56, + 0x35, 0x95, 0xce, 0xaf, 0x18, 0xd0, 0x41, 0x05, 0xc2, 0xe9, 0xd8, 0x81, 0x5a, 0x9b, 0x38, 0x6e, + 0xb2, 0x0a, 0x06, 0x6f, 0x73, 0xab, 0xba, 0xe5, 0xa8, 0xd9, 0xb8, 0xcf, 0xce, 0x53, 0x0f, 0x56, + 0x36, 0xed, 0x44, 0x2a, 0xad, 0x8c, 0x7f, 0xbc, 0x12, 0x1e, 0xd6, 0xdc, 0xf5, 0x76, 0x18, 0xa2, + 0x57, 0x47, 0x94, 0xef, 0x38, 0x24, 0x13, 0x06, 0x22, 0x35, 0xca, 0xac, 0xb6, 0xe8, 0x57, 0xae, + 0x21, 0x64, 0x3a, 0xaa, 0xf0, 0xa5, 0x42, 0x40, 0x5f, 0x1c, 0xd0, 0x85, 0xc3, 0xb8, 0xa2, 0x98, + 0x1a, 0x84, 0x87, 0x61, 0x83, 0x6b, 0x30, 0xc5, 0x95, 0x31, 0x28, 0x09, 0x4b, 0xf6, 0x25, 0x14, + 0xae, 0x00, 0xef, 0x5e, 0x52, 0x42, 0x42, 0x75, 0x86, 0x89, 0x48, 0x5b, 0x72, 0x46, 0xfc, 0x5f, + 0x73, 0x8a, 0x36, 0x7c, 0x2d, 0x17, 0x19, 0xd2, 0xe1, 0xb2, 0x02, 0xc2, 0x29, 0xde, 0x0d, 0x69, + 0x6c, 0xa1, 0x96, 0x7b, 0x0d, 0xae, 0xe4, 0xf9, 0x36, 0x1f, 0x03, 0xda, 0xc8, 0x03, 0xc5, 0x88, + 0xbf, 0xa1, 0xc7, 0x78, 0x55, 0x77, 0xe1, 0x9d, 0x8e, 0xe6, 0x4f, 0x1e, 0x13, 0x86, 0xab, 0x40, + 0xf9, 0x5a, 0x74, 0x30, 0xda, 0x10, 0xf2, 0x74, 0x80, 0xeb, 0x56, 0xa1, 0x7c, 0x40, 0xe7, 0xa5, + 0xd5, 0xcb, 0x90, 0x1e, 0xa9, 0xc2, 0xa0, 0xd5, 0x2c, 0x65, 0x3e, 0xca, 0x78, 0x92, 0x47, 0x64, + 0xf8, 0x8c, 0x1e, 0x87, 0x49, 0xf1, 0xe9, 0x7e, 0x83, 0xda, 0x72, 0x7a, 0xeb, 0xbf, 0xee, 0x23, + 0x74, 0xf3, 0x1b, 0xd3, 0xdc, 0x94, 0xf6, 0xbc, 0xc4, 0xf4, 0x7d, 0x58, 0x60, 0x6b, 0xbe, 0x77, + 0x39, 0xf9, 0x18, 0x23, 0x77, 0xc6, 0x1d, 0xeb, 0x4e, 0xe0, 0xb8, 0x2f, 0x48, 0xaf, 0x95, 0x27, + 0xf2, 0x7b, 0xaa, 0x4e, 0x00, 0x10, 0xa6, 0xb6, 0xbf, 0x82, 0xd5, 0x8b, 0x32, 0xeb, 0x60, 0x13, + 0x62, 0xc0, 0xe1, 0x7a, 0x25, 0x48, 0xee, 0xe0, 0x47, 0xe7, 0x95, 0x38, 0xf6, 0x73, 0x9c, 0x40, + 0x31, 0x88, 0xa5, 0x3d, 0xd6, 0x97, 0xc8, 0xc2, 0xc0, 0xf8, 0x98, 0x34, 0x21, 0x77, 0xf4, 0x6d, + 0x3e, 0xe7, 0x91, 0xc9, 0xcb, 0x1b, 0xe9, 0xab, 0xbc, 0x85, 0x52, 0xfa, 0x51, 0x2e, 0xed, 0x4f, + 0x7d, 0xe4, 0x82, 0xe8, 0x94, 0x48, 0x79, 0x0b, 0xb9, 0x61, 0xae, 0xce, 0x7c, 0x92, 0x9f, 0x45, + 0x0e, 0x3e, 0xce, 0xce, 0xaa, 0x24, 0x41, 0x36, 0x57, 0x77, 0xa0, 0x9c, 0x66, 0x46, 0x08, 0x81, + 0xfe, 0xe1, 0xd4, 0x4c, 0x51, 0xa2, 0xe3, 0xc0, 0x11, 0xeb, 0x8f, 0xdd, 0x03, 0x75, 0x45, 0x82, + 0xea, 0x16, 0x37, 0xe3, 0x60, 0x52, 0xdb, 0xca, 0xc8, 0x64, 0x8e, 0x10, 0x3f, 0x16, 0x4f, 0x45, + 0x98, 0xe1, 0x3a, 0xcd, 0x02, 0x4e, 0x4d, 0x78, 0x33, 0x63, 0x68, 0xc3, 0x1f, 0x57, 0x75, 0x67, + 0xc3, 0x8a, 0xeb, 0xce, 0x03, 0x71, 0x81, 0x5c, 0xe9, 0x88, 0x85, 0x80, 0xe7, 0xbe, 0xe4, 0xb4, + 0xc4, 0x8a, 0x2e, 0xc9, 0xc3, 0x50, 0x29, 0x22, 0x00, 0x2e, 0x3c, 0xec, 0x3f, 0xc0, 0x44, 0x4d, + 0xcd, 0xf5, 0x28, 0x7c, 0xe5, 0x82, 0x35, 0xce, 0x52, 0x14, 0xa8, 0x09, 0xa4, 0x1f, 0xab, 0xf6, + 0xf1, 0x73, 0x3a, 0xf2, 0x05, 0xd3, 0x22, 0x2f, 0x74, 0xaa, 0x68, 0x7d, 0x81, 0x4b, 0x29, 0xf4, + 0x32, 0xba, 0xc8, 0x7b, 0x05, 0x25, 0x8d, 0x84, 0xcc, 0x4b, 0x64, 0x7a, 0x77, 0xf9, 0x6e, 0x90, + 0x62, 0xe1, 0x5d, 0x35, 0x95, 0x8e, 0x27, 0xbd, 0x1a, 0x97, 0xe9, 0xfb, 0xbf, 0xc1, 0x70, 0x8e, + 0x3c, 0xc9, 0x8a, 0xbf, 0xe1, 0xea, 0x25, 0x85, 0x14, 0x98, 0x19, 0xa7, 0x9f, 0xd5, 0x7f, 0x13, + 0x0f, 0x9d, 0xff, 0x8d, 0x69, 0xe5, 0xff, 0xab, 0x35, 0xe2, 0x43, 0x68, 0xbc, 0x3a, 0xba, 0x84, + 0xca, 0x7c, 0xa8, 0x94, 0x0a, 0xf0, 0xad, 0xa5, 0x24, 0xce, 0xbf, 0x2a, 0x5d, 0xb6, 0xf8, 0x77, + 0x25, 0xac, 0xc5, 0xef, 0x1c, 0xa6, 0x43, 0x7c, 0x19, 0xc4, 0xb2, 0x88, 0x6d, 0xd0, 0x0c, 0x22, + 0xce, 0x43, 0xb3, 0x8c, 0x98, 0xc1, 0xa7, 0xf2, 0x92, 0x1d, 0x68, 0x39, 0x25, 0x21, 0x80, 0xcf, + 0x2c, 0x89, 0xaa, 0xd4, 0x6c, 0x09, 0x0b, 0xa5, 0xfe, 0xaa, 0xf0, 0x60, 0x6d, 0xd2, 0x15, 0x19, + 0x0f, 0xc7, 0xa0, 0x94, 0x8f, 0x1b, 0xa7, 0xa4, 0x0e, 0xdc, 0x8a, 0xc8, 0x7c, 0x25, 0x5f, 0x6a, + 0xd5, 0x87, 0xbb, 0x53, 0x72, 0x17, 0x1e, 0xc6, 0x14, 0xb7, 0x40, 0xd2, 0x2e, 0x90, 0x02, 0xd5, + 0x10, 0x58, 0xc2, 0x1f, 0x6f, 0x80, 0xa4, 0x1b, 0x9e, 0xd2, 0x25, 0x3d, 0xff, 0x08, 0x98, 0x71, + 0x69, 0x5f, 0x6f, 0xf4, 0xcb, 0x76, 0xd1, 0xad, 0x75, 0x12, 0x99, 0x75, 0x5a, 0x3c, 0x38, 0xc7, + 0xd2, 0xf9, 0x12, 0x09, 0x8b, 0x3b, 0x5f, 0xea, 0x61, 0xd9, 0xd7, 0x80, 0xbf, 0xa2, 0xbc, 0x0a, + 0xb4, 0xce, 0x75, 0xd0, 0x79, 0x93, 0x67, 0xe3, 0x6b, 0x02, 0x1f, 0xf6, 0x2a, 0xeb, 0x18, 0xab, + 0x58, 0x01, 0x8f, 0x58, 0x55, 0x6a, 0x63, 0x96, 0x3d, 0x1a, 0xf8, 0xa9, 0xf0, 0x9d, 0x79, 0xfb, + 0x30, 0x5d, 0x55, 0x18, 0x98, 0x70, 0x37, 0x7d, 0xb0, 0xc8, 0x5a, 0x4e, 0xc7, 0x17, 0x67, 0x66, + 0xd3, 0x3b, 0xa3, 0x20, 0xa0, 0xb5, 0x9d, 0xb2, 0x22, 0x39, 0x47, 0xe0, 0x23, 0x76, 0x8c, 0x85, + 0xa6, 0x43, 0x1e, 0xb8, 0x42, 0xa0, 0x0c, 0xdc, 0x0b, 0x89, 0x19, 0x58, 0x3a, 0xe1, 0xc9, 0xdc, + 0x01, 0x9d, 0x5c, 0x72, 0x5f, 0xee, 0x49, 0xac, 0x6b, 0x97, 0x0c, 0x8f, 0x04, 0x67, 0x1b, 0x61, + 0xe9, 0xe8, 0xd7, 0x7e, 0x1a, 0x4f, 0xfd, 0xc6, 0x34, 0xc8, 0xe4, 0x49, 0x24, 0x65, 0x33, 0x43, + 0x1f, 0x9a, 0x5b, 0xe8, 0xc3, 0x44, 0x27, 0xb6, 0x81, 0x32, 0x4e, 0xf1, 0xe0, 0x4b, 0x10, 0x1b, + 0x14, 0xe3, 0xd8, 0xac, 0xc4, 0x12, 0xa9, 0x4d, 0xcb, 0x5c, 0x77, 0x23, 0x2e, 0xb9, 0xef, 0x4b, + 0x72, 0xc7, 0xbb, 0xf5, 0x96, 0x23, 0xa2, 0x3b, 0x4f, 0x59, 0xb7, 0x90, 0x74, 0xca, 0x92, 0xfa, + 0xe6, 0xdd, 0x1e, 0xca, 0x77, 0x22, 0xfe, 0xfa, 0x62, 0x02, 0x08, 0x06, 0xe2, 0xa7, 0x26, 0xf7, + 0xad, 0xb4, 0xe3, 0x4b, 0x82, 0xcf, 0x96, 0x8d, 0x4d, 0xba, 0x20, 0xfb, 0x82, 0x95, 0x93, 0x07, + 0xdd, 0x95, 0x14, 0x6e, 0xa1, 0x6d, 0x0b, 0x69, 0xc4, 0x6b, 0xbb, 0x29, 0x9b, 0x61, 0x39, 0x1d, + 0xdf, 0x3d, 0x5d, 0xcc, 0x81, 0x8e, 0xb5, 0x72, 0x4b, 0x6c, 0x5e, 0x4f, 0x16, 0xe3, 0x95, 0x73, + 0x34, 0x8c, 0x4a, 0xb7, 0x3d, 0x73, 0xf7, 0xd4, 0xbe, 0xa7, 0x8e, 0x09, 0x2f, 0xa8, 0xad, 0xdb, + 0xbd, 0x2f, 0x24, 0x9c, 0xf2, 0xfd, 0x5c, 0x54, 0x0d, 0x5e, 0x22, 0x87, 0xa4, 0xce, 0xbd, 0x3d, + 0x52, 0xa0, 0x52, 0xef, 0xe2, 0x07, 0x6a, 0x27, 0xd6, 0xcd, 0x29, 0x6c, 0x1b, 0x2c, 0xfb, 0xbd, + 0x8f, 0x56, 0xab, 0x57, 0x0a, 0xa5, 0x90, 0xfd, 0x66, 0x87, 0x66, 0x2d, 0xf3, 0x00, 0xcb, 0xe1, + 0xcd, 0xcc, 0xe9, 0xc6, 0x54, 0x88, 0x1b, 0x7b, 0x68, 0xa7, 0x24, 0xb5, 0x5d, 0xc6, 0xc9, 0xdd, + 0x2b, 0x0d, 0x8b, 0x7f, 0x30, 0x6a, 0x3d, 0x83, 0x4b, 0xba, 0x57, 0xc5, 0xe9, 0xca, 0x21, 0xa3, + 0xce, 0x15, 0xc1, 0xb5, 0x73, 0xf8, 0x09, 0xd9, 0x44, 0xb8, 0x96, 0x6d, 0x5f, 0xb7, 0xa0, 0x40, + 0x21, 0xe9, 0xc0, 0xec, 0xf6, 0xaa, 0xf9, 0xd9, 0x53, 0xdf, 0x56, 0x5a, 0x2c, 0x65, 0x56, 0xf5, + 0x06, 0xc5, 0x45, 0x48, 0xec, 0xb6, 0x81, 0x3c, 0xf9, 0x86, 0x2b, 0x33, 0x43, 0x3c, 0xdd, 0x53, + 0x21, 0x40, 0xec, 0xef, 0xd8, 0x81, 0x7c, 0xad, 0x91, 0xef, 0x14, 0x76, 0x3c, 0xb0, 0x70, 0x00, + 0x5d, 0x9d, 0x3b, 0xbe, 0xa6, 0xff, 0x1b, 0x77, 0xb7, 0xf9, 0xb9, 0x7a, 0xfc, 0xcd, 0x3d, 0xfc, + 0x80, 0x86, 0x3d, 0x0a, 0x3c, 0x9c, 0x99, 0x68, 0xb1, 0x19, 0x87, 0xa9, 0xcc, 0xe3, 0xf1, 0xce, + 0x42, 0x2c, 0xdd, 0x3e, 0x4a, 0x3a, 0x5e, 0xab, 0x89, 0x16, 0x5b, 0xd7, 0x76, 0x87, 0xbb, 0x8a, + 0xe2, 0x66, 0xb8, 0xef, 0x82, 0xea, 0xf6, 0x91, 0xf0, 0x02, 0x53, 0x06, 0xab, 0x7b, 0xf5, 0xb9, + 0x5c, 0xcf, 0xf1, 0x18, 0xdd, 0xf8, 0xf9, 0x49, 0x58, 0xa4, 0x7c, 0xa8, 0xd7, 0x05, 0x2d, 0x51, + 0x97, 0x77, 0x0e, 0x5c, 0x43, 0xab, 0x01, 0x5e, 0x6c, 0x0d, 0x9d, 0xeb, 0xa5, 0x83, 0xff, 0x64, + 0xe6, 0x25, 0xd0, 0x5c, 0x5f, 0x79, 0x5f, 0xe7, 0x6a, 0x42, 0x7c, 0xdc, 0x62, 0xbb, 0xa9, 0x7e, + 0x41, 0xd4, 0x6d, 0x91, 0x2d, 0x34, 0x2d, 0x7f, 0xae, 0x87, 0xe6, 0xe5, 0xce, 0x83, 0xb2, 0x81, + 0xff, 0xd5, 0xca, 0x74, 0x0c, 0x7c, 0xa8, 0xab, 0xe1, 0xe5, 0x4a, 0x8d, 0xa0, 0x48, 0x06, 0x5d, + 0x8d, 0x9c, 0x1e, 0xdf, 0x14, 0xab, 0xed, 0x06, 0xa4, 0x98, 0xaa, 0xed, 0xe1, 0xaa, 0x67, 0xa5, + 0x27, 0x81, 0xc0, 0x52, 0x1c, 0xd7, 0xde, 0xa4, 0x4d, 0x17, 0xcc, 0x06, 0x0e, 0x5e, 0x9d, 0x4e, + 0xaf, 0xe6, 0x32, 0x1b, 0x72, 0xd5, 0xad, 0x12, 0x82, 0xa7, 0x0d, 0x84, 0xcf, 0x92, 0x93, 0xea, + 0x8f, 0xa6, 0xac, 0xf7, 0xa6, 0x80, 0xa8, 0xca, 0xab, 0xd6, 0x83, 0xac, 0x78, 0xa9, 0xaf, 0x12, + 0x58, 0x91, 0xfa, 0xb2, 0xbd, 0xfd, 0x98, 0xbc, 0xd9, 0x0b, 0xef, 0x04, 0xe6, 0x45, 0x00, 0x80, + 0xe8, 0x66, 0x19, 0xda, 0x49, 0xab, 0xee, 0x4b, 0xdf, 0x43, 0x8e, 0x87, 0x87, 0x66, 0x06, 0x30, + 0xca, 0xe0, 0x0d, 0xb1, 0x52, 0xf2, 0x67, 0x10, 0xc6, 0xbd, 0x94, 0x9c, 0x0b, 0x1c, 0xd6, 0x15, + 0xaf, 0xb7, 0x95, 0x0c, 0x57, 0xe6, 0x18, 0x7a, 0xd1, 0xdb, 0xe4, 0x39, 0x93, 0xb1, 0x53, 0xa6, + 0x00, 0xda, 0x53, 0x0e, 0x93, 0x19, 0x02, 0x50, 0xd3, 0x5a, 0x95, 0x41, 0xe6, 0x0b, 0x49, 0xcc, + 0x3b, 0x47, 0x33, 0xbc, 0xf4, 0xc5, 0xc5, 0x44, 0x1f, 0xbb, 0xfc, 0x35, 0x1b, 0x17, 0x9a, 0xfd, + 0x7b, 0xd3, 0x28, 0x32, 0xbe, 0xc2, 0x89, 0x49, 0x58, 0xfa, 0x52, 0x3e, 0xe7, 0x97, 0x4e, 0xaa, + 0x65, 0x81, 0xec, 0x4b, 0x27, 0x24, 0x30, 0xd5, 0x4f, 0x42, 0xd3, 0x7c, 0xcd, 0x53, 0x60, 0xb5, + 0xf4, 0x73, 0x9d, 0xd0, 0x72, 0x60, 0x16, 0x43, 0xb5, 0x2a, 0x3e, 0x6b, 0x0f, 0xf8, 0x25, 0x7c, + 0xd6, 0xfc, 0x5c, 0x37, 0x64, 0x28, 0x89, 0x04, 0x1f, 0xff, 0x0f, 0xf6, 0xde, 0xa6, 0x27, 0x91, + 0xae, 0x6d, 0xd4, 0xfe, 0x33, 0x17, 0x6d, 0x80, 0x1b, 0x4d, 0xba, 0x2f, 0x34, 0xea, 0xa3, 0x3d, + 0x06, 0x1a, 0x48, 0x8a, 0xaf, 0x50, 0x58, 0x38, 0x11, 0x0d, 0x20, 0x90, 0xf0, 0x19, 0x40, 0xed, + 0xff, 0x00, 0x14, 0x44, 0x01, 0x9d, 0x50, 0x92, 0x2a, 0x2c, 0x48, 0xd0, 0x82, 0x00, 0x82, 0x63, + 0xe0, 0x02, 0x13, 0xa0, 0x20, 0x80, 0xe0, 0x44, 0x24, 0x80, 0x60, 0xa2, 0x02, 0x51, 0xdb, 0xbe, + 0xb7, 0xf7, 0xde, 0x6f, 0xde, 0x49, 0x77, 0x4f, 0x76, 0xf6, 0xbb, 0xf3, 0xe6, 0x89, 0xc7, 0x80, + 0x09, 0x29, 0x02, 0xc7, 0x5a, 0xac, 0x75, 0xae, 0xaa, 0x75, 0x9e, 0xab, 0x50, 0x0a, 0xa0, 0x68, + 0x53, 0xee, 0xab, 0x15, 0xe4, 0x02, 0xdc, 0x4c, 0x60, 0x86, 0xbb, 0x43, 0x82, 0x6b, 0x80, 0xe0, + 0x79, 0xa8, 0x66, 0x6a, 0x66, 0xe5, 0x6c, 0x47, 0x25, 0xbd, 0xa7, 0x82, 0x89, 0x05, 0x6e, 0xe4, + 0x20, 0x28, 0x9b, 0x7b, 0x74, 0x5f, 0xc8, 0x1b, 0xe7, 0xb5, 0xaf, 0x4c, 0x9e, 0x29, 0x6d, 0x4a, + 0x49, 0x76, 0xc9, 0x1e, 0xaa, 0x2e, 0x22, 0xcd, 0x39, 0xae, 0x11, 0xee, 0xd4, 0xb3, 0x29, 0x51, + 0x77, 0xf8, 0x0a, 0x54, 0x2b, 0x91, 0x15, 0xb6, 0xf3, 0x20, 0x34, 0x87, 0x3b, 0x91, 0x34, 0xf7, + 0xc0, 0x1d, 0x57, 0x57, 0x05, 0xdb, 0x28, 0x67, 0x7e, 0x17, 0xae, 0x87, 0x63, 0xc2, 0xe3, 0xbb, + 0xdb, 0xdc, 0xb0, 0xbb, 0xce, 0xc4, 0xcb, 0xe3, 0x9b, 0x48, 0x5d, 0x0e, 0x77, 0x17, 0x25, 0xe2, + 0x2b, 0xac, 0x07, 0x35, 0x8f, 0x63, 0x31, 0x03, 0x0e, 0xa3, 0x9f, 0xd2, 0x69, 0x81, 0x31, 0x8e, + 0xb9, 0xc5, 0x83, 0x90, 0xc4, 0xf4, 0xa3, 0xf2, 0x9c, 0xd4, 0xfb, 0x3a, 0x12, 0x50, 0x1c, 0x54, + 0x5b, 0x5f, 0x93, 0x7a, 0xc4, 0xba, 0xe4, 0xf3, 0x91, 0x0c, 0xb9, 0x78, 0x63, 0x54, 0x5f, 0x61, + 0x93, 0x77, 0x88, 0x61, 0x27, 0xd0, 0xbd, 0xe0, 0x71, 0xe1, 0xdb, 0x90, 0xd4, 0xad, 0xed, 0x98, + 0x1f, 0xd6, 0x62, 0xa4, 0x25, 0xee, 0xe8, 0x36, 0x3b, 0xd0, 0xb9, 0x87, 0xae, 0x91, 0x3b, 0x1f, + 0x97, 0xa5, 0xf2, 0xe8, 0xe1, 0xdd, 0x30, 0x2e, 0x11, 0x31, 0x94, 0x8f, 0x8f, 0x22, 0x7c, 0x3e, + 0xec, 0x4c, 0xf6, 0xee, 0x0b, 0x62, 0x3b, 0xe5, 0x6b, 0xd8, 0x10, 0xad, 0x86, 0x68, 0x82, 0x90, + 0xe2, 0xd7, 0x3a, 0x42, 0xac, 0x3f, 0xf4, 0x69, 0x25, 0xad, 0xef, 0xf2, 0xaf, 0xaa, 0xdd, 0x86, + 0x84, 0x46, 0xb9, 0x2e, 0xa9, 0x25, 0xf6, 0x24, 0x38, 0x73, 0x82, 0xb9, 0x41, 0xbc, 0xdd, 0xab, + 0xbc, 0x52, 0xa4, 0x99, 0x0b, 0x0f, 0xd9, 0xe5, 0xad, 0x1f, 0x9c, 0x45, 0xcc, 0x0e, 0x49, 0x67, + 0xaa, 0x6f, 0x93, 0xf6, 0x39, 0x48, 0x66, 0x3e, 0x4b, 0x64, 0x87, 0x4f, 0x44, 0xa7, 0xcf, 0x01, + 0xd1, 0x04, 0x43, 0xad, 0x36, 0x65, 0x19, 0x7c, 0x43, 0x93, 0x8f, 0xe9, 0x05, 0xbd, 0xc5, 0xd5, + 0x52, 0x34, 0x40, 0x36, 0x73, 0xe5, 0xf5, 0x99, 0x5c, 0x32, 0x8a, 0xa5, 0x7f, 0x1e, 0xae, 0x79, + 0xd3, 0x02, 0x71, 0xb9, 0xfd, 0x0c, 0xe6, 0xdc, 0x83, 0x4f, 0xb6, 0x32, 0xe1, 0x45, 0xe7, 0x04, + 0x84, 0x8b, 0x9c, 0x13, 0xbc, 0x10, 0xa6, 0x9a, 0x28, 0x70, 0xd2, 0xd1, 0x12, 0x07, 0x69, 0xd1, + 0x7b, 0x48, 0xfc, 0x6f, 0xa9, 0xb8, 0x4c, 0x6e, 0x76, 0xc0, 0x5c, 0x5a, 0x46, 0x49, 0xf2, 0xd5, + 0xd0, 0xa4, 0xcf, 0xc7, 0x2d, 0xdc, 0x55, 0x6d, 0xbc, 0x8d, 0x47, 0x93, 0x24, 0x3e, 0x58, 0xd0, + 0xb7, 0xe8, 0xd9, 0x5d, 0x7d, 0xf3, 0x2f, 0x62, 0x7a, 0x36, 0x09, 0xe5, 0x77, 0x81, 0xf8, 0x7b, + 0xc4, 0x21, 0x3c, 0x4e, 0xf1, 0x6c, 0x4f, 0xb1, 0x9b, 0xb8, 0xc9, 0x7d, 0x8f, 0xf0, 0x20, 0x47, + 0xb4, 0x73, 0x09, 0x38, 0x04, 0xff, 0x42, 0xfa, 0x6e, 0xad, 0x2b, 0x4f, 0x2d, 0x21, 0x6e, 0x04, + 0x18, 0xc0, 0xd2, 0x2a, 0x64, 0x09, 0xf8, 0x1b, 0x38, 0xf7, 0xe9, 0x36, 0xc7, 0xab, 0xc4, 0xc8, + 0xf5, 0x52, 0x73, 0x6d, 0xbf, 0x06, 0x89, 0x9e, 0xc6, 0x50, 0x42, 0xa0, 0xff, 0xb7, 0x2a, 0x5b, + 0x42, 0x56, 0xc6, 0xbc, 0x12, 0x90, 0x9e, 0x84, 0xd9, 0xd8, 0x71, 0xbe, 0x68, 0x91, 0x5f, 0x50, + 0x57, 0xae, 0x6d, 0x3d, 0xeb, 0x52, 0x3f, 0x9a, 0xe6, 0x52, 0xc1, 0xf3, 0x5e, 0x97, 0xe6, 0xba, + 0xc1, 0x12, 0x03, 0x73, 0xf9, 0x5f, 0xc7, 0x8f, 0x6e, 0xc3, 0x59, 0x9e, 0xba, 0xdd, 0x39, 0xd2, + 0x00, 0x13, 0xc5, 0xaf, 0x7d, 0x9a, 0xe0, 0xfe, 0xd6, 0x74, 0x25, 0x94, 0xf9, 0xdf, 0x0d, 0x5f, + 0xc5, 0x65, 0xea, 0x8b, 0xc1, 0xd7, 0xed, 0x61, 0x2a, 0x70, 0x4b, 0x8a, 0x69, 0x0e, 0xb6, 0xa4, + 0x8c, 0x92, 0xaf, 0x9b, 0xa8, 0x5a, 0xd6, 0x3d, 0xfb, 0x14, 0xa5, 0x64, 0xe3, 0x80, 0xa4, 0x0b, + 0x42, 0xd0, 0x0c, 0x0d, 0x38, 0x8e, 0x50, 0xa8, 0x7a, 0x49, 0xaf, 0xc0, 0x5b, 0x77, 0x87, 0x58, + 0x26, 0x41, 0x4d, 0x44, 0x61, 0xfb, 0xd5, 0x5d, 0x5a, 0x83, 0x07, 0x37, 0x90, 0x2a, 0xae, 0xde, + 0x7f, 0x95, 0xa4, 0x01, 0x84, 0x9a, 0x03, 0x7e, 0x1c, 0x93, 0x13, 0x5b, 0x04, 0x24, 0xd9, 0xff, + 0x5f, 0x17, 0x95, 0xf8, 0x3f, 0xf8, 0x92, 0xfe, 0xf5, 0x0c, 0x4a, 0x72, 0xf1, 0x0f, 0x7d, 0x9a, + 0x79, 0x8a, 0x03, 0xae, 0xf6, 0x65, 0xf9, 0x01, 0x43, 0x05, 0x07, 0x66, 0xf4, 0xbd, 0x27, 0xbf, + 0x4f, 0xbf, 0x2d, 0x81, 0x0e, 0xa5, 0x0a, 0x4e, 0x43, 0x96, 0xe3, 0xe8, 0xae, 0x78, 0xc8, 0x91, + 0x0b, 0x3b, 0x0c, 0x26, 0x3e, 0xb8, 0xeb, 0x71, 0x38, 0x07, 0xe4, 0x59, 0x4c, 0x2f, 0xbe, 0x75, + 0x0d, 0x5a, 0x82, 0x46, 0x60, 0x22, 0x12, 0x3f, 0x1c, 0x99, 0x75, 0x13, 0xbf, 0x12, 0x95, 0x81, + 0xdb, 0x21, 0xb1, 0xbe, 0x55, 0xdd, 0x1f, 0xb7, 0xab, 0xbe, 0xd7, 0xce, 0xbc, 0x60, 0x0c, 0x2f, + 0x03, 0xe7, 0x67, 0xa1, 0x2a, 0xbb, 0xaf, 0x5e, 0x4b, 0xa4, 0x87, 0x26, 0x8a, 0x4d, 0x30, 0x8c, + 0x1d, 0x20, 0x21, 0xb7, 0x6f, 0xc8, 0xa9, 0x97, 0xe0, 0x61, 0x5a, 0xea, 0x54, 0xaf, 0x7c, 0xb5, + 0x39, 0x62, 0x37, 0xb5, 0x64, 0x7b, 0xe3, 0xa4, 0xc1, 0x81, 0x8c, 0x81, 0x0b, 0x5a, 0x09, 0xfe, + 0x3b, 0x69, 0x77, 0x9c, 0xbd, 0x90, 0x73, 0x5e, 0xe3, 0x5d, 0x08, 0x83, 0xf5, 0xa4, 0x9d, 0xe5, + 0x30, 0xf6, 0x86, 0xd4, 0x7e, 0xda, 0x0f, 0x6a, 0x74, 0x0a, 0xeb, 0xdc, 0x6e, 0x75, 0x03, 0xa5, + 0x47, 0xf1, 0x6d, 0x5c, 0xca, 0x28, 0x7b, 0x18, 0x2a, 0x4c, 0xe4, 0xc1, 0xd1, 0x82, 0xb3, 0xd2, + 0x52, 0x40, 0x3c, 0x44, 0x96, 0x05, 0xfa, 0x5e, 0x25, 0xb5, 0x84, 0x9f, 0xda, 0x6e, 0x79, 0x98, + 0xab, 0x5f, 0x1d, 0x86, 0xee, 0x02, 0xf7, 0xe5, 0x6f, 0x4f, 0x83, 0x38, 0x5f, 0x4e, 0x7c, 0x5f, + 0x96, 0x70, 0x89, 0xa1, 0xd4, 0x52, 0x5a, 0xf3, 0x67, 0x13, 0x50, 0xfb, 0x48, 0x55, 0x8d, 0xf8, + 0x6d, 0xcf, 0x8d, 0x93, 0x87, 0x64, 0x56, 0x7e, 0x72, 0x88, 0xe5, 0x0c, 0x27, 0xd7, 0x36, 0x3c, + 0x89, 0xbd, 0x35, 0x1a, 0x7b, 0x58, 0x07, 0xbc, 0xa4, 0xe7, 0x36, 0xe2, 0x43, 0x7d, 0xb3, 0x5c, + 0x9f, 0xc3, 0x4a, 0x87, 0xcf, 0x5b, 0xf4, 0xe8, 0x61, 0xa0, 0x38, 0x1a, 0x99, 0x28, 0xf3, 0x6c, + 0x87, 0xb0, 0xf2, 0xc2, 0xe9, 0x77, 0x4f, 0xc8, 0x85, 0x46, 0xeb, 0xd7, 0x3e, 0x4d, 0xae, 0xfc, + 0xc1, 0xb4, 0xf9, 0xf2, 0x91, 0x0c, 0x2d, 0xb1, 0xa2, 0x44, 0x4f, 0xce, 0x6f, 0x49, 0xbe, 0x2f, + 0xb1, 0x31, 0x37, 0xae, 0xb8, 0x7f, 0x0c, 0x24, 0x51, 0xb0, 0x6a, 0x8a, 0x2c, 0x01, 0xd8, 0x61, + 0xbf, 0x56, 0x74, 0xdd, 0x9d, 0x1c, 0xf3, 0x9b, 0x0a, 0x57, 0x06, 0xe4, 0x74, 0xd2, 0x0a, 0xc1, + 0x28, 0x3c, 0xce, 0x8b, 0x45, 0x93, 0xe7, 0x65, 0xa8, 0x58, 0x1d, 0x67, 0x73, 0xa6, 0x23, 0x38, + 0x44, 0xc7, 0x03, 0x3e, 0x64, 0x19, 0x52, 0x7f, 0xaa, 0x4b, 0xc0, 0xb4, 0xba, 0x0f, 0xd8, 0xd2, + 0x92, 0xd5, 0x67, 0xdb, 0xd5, 0x2d, 0x2a, 0x68, 0xb8, 0x9e, 0x72, 0x76, 0x95, 0x80, 0x90, 0xeb, + 0x87, 0x01, 0xff, 0xd7, 0xc5, 0x98, 0xc8, 0xbf, 0x0a, 0xfe, 0x93, 0xda, 0xd7, 0xea, 0x6d, 0x2f, + 0x37, 0xb7, 0x6f, 0xec, 0xce, 0x5d, 0x58, 0x2b, 0xf6, 0x0d, 0xda, 0xad, 0xdc, 0x76, 0xe8, 0x35, + 0xa4, 0xa9, 0xa5, 0x7b, 0x2a, 0x07, 0x51, 0xc5, 0xb9, 0xf2, 0x9d, 0xe3, 0x74, 0xb8, 0x02, 0xef, + 0xd2, 0x32, 0x1c, 0x61, 0x38, 0x4e, 0x3d, 0x50, 0xa0, 0xcb, 0x62, 0xe0, 0xe5, 0x2a, 0xa3, 0x1a, + 0x36, 0xb7, 0xa0, 0x44, 0xd3, 0xdc, 0x99, 0xc5, 0x92, 0x26, 0x0a, 0x43, 0xd5, 0x74, 0x1d, 0x60, + 0xfd, 0x8a, 0x0b, 0xc6, 0xc2, 0x7a, 0x2c, 0x34, 0x03, 0x08, 0xcf, 0x9e, 0x1b, 0xaa, 0x83, 0x3b, + 0x3c, 0x27, 0x10, 0x6c, 0x76, 0x83, 0x80, 0x58, 0x8c, 0xa3, 0xef, 0x3f, 0x01, 0x67, 0x81, 0x9c, + 0xb5, 0xe0, 0x54, 0xd5, 0xaf, 0x0c, 0x57, 0x75, 0x80, 0x77, 0x86, 0x0e, 0x08, 0x6e, 0x09, 0x6a, + 0xf4, 0xc0, 0x44, 0xd1, 0xaa, 0x01, 0x2f, 0x35, 0x04, 0x08, 0x36, 0x09, 0xea, 0xaa, 0xc3, 0x44, + 0x9f, 0x00, 0x5e, 0x17, 0x4a, 0x2d, 0xe6, 0xaa, 0x2e, 0x2c, 0x0b, 0x9a, 0x28, 0x66, 0xc1, 0x91, + 0x7c, 0x3a, 0x07, 0x48, 0xdc, 0x2e, 0xf4, 0x05, 0x30, 0x51, 0x24, 0x7c, 0xdf, 0xdd, 0x3e, 0xb2, + 0x28, 0x72, 0xf6, 0x46, 0x3a, 0xff, 0x43, 0x22, 0x85, 0x65, 0x52, 0xbf, 0xa9, 0x23, 0x24, 0xfd, + 0x83, 0x69, 0x6b, 0x42, 0x98, 0x44, 0x96, 0xa5, 0x00, 0x86, 0x58, 0x0b, 0x57, 0xf0, 0xf1, 0xb3, + 0x49, 0xbc, 0x89, 0x70, 0x79, 0x07, 0x57, 0xf5, 0x15, 0x50, 0x6c, 0xff, 0x7b, 0x6a, 0x12, 0x1b, + 0x11, 0xba, 0x35, 0x27, 0x92, 0x2a, 0x68, 0x18, 0x4c, 0x42, 0x93, 0xb4, 0x28, 0x30, 0x11, 0x8b, + 0x0f, 0x5c, 0x31, 0xb3, 0x58, 0xb0, 0x10, 0x62, 0xb5, 0x6d, 0x43, 0xea, 0x9c, 0x30, 0xee, 0x37, + 0xf5, 0x85, 0x4f, 0xee, 0xa6, 0x5a, 0xe8, 0x0e, 0xa6, 0xf1, 0x01, 0x7c, 0x80, 0xf1, 0xb5, 0xba, + 0x3e, 0x6a, 0xe6, 0x6f, 0x9e, 0x0c, 0x65, 0x87, 0x4e, 0x84, 0xdb, 0x10, 0x97, 0x6b, 0x4c, 0x4e, + 0xfa, 0xa9, 0x49, 0xca, 0x30, 0xf8, 0xab, 0x6d, 0x68, 0x1b, 0x1f, 0x90, 0x2b, 0xee, 0xca, 0x90, + 0x4e, 0x15, 0x5b, 0x50, 0x48, 0x4d, 0x2a, 0xc2, 0x58, 0x06, 0x73, 0xbd, 0x6d, 0x66, 0xfe, 0x71, + 0x44, 0xac, 0x2f, 0x62, 0xe3, 0xb5, 0x5c, 0xe7, 0xf2, 0x7a, 0x6b, 0x98, 0xfc, 0xa4, 0xdb, 0x67, + 0x09, 0x82, 0x8a, 0xb1, 0x92, 0x2d, 0x3b, 0xa8, 0x2d, 0x63, 0xd1, 0x01, 0x97, 0x65, 0x10, 0x30, + 0x35, 0xd9, 0x3e, 0x2c, 0x24, 0x79, 0xa4, 0x09, 0x16, 0xad, 0xb4, 0xc8, 0x73, 0x72, 0x56, 0x7c, + 0xd3, 0xea, 0x82, 0xee, 0x9d, 0xe3, 0x0e, 0xad, 0xef, 0xf9, 0xab, 0x2f, 0x05, 0x03, 0xa1, 0x25, + 0x6d, 0xc1, 0xf7, 0x5c, 0x1d, 0x5e, 0x9f, 0xd5, 0x3a, 0x52, 0xad, 0x31, 0x8c, 0x6a, 0x79, 0x30, + 0xa2, 0x5c, 0xb1, 0xdd, 0x8e, 0x55, 0x90, 0xc0, 0xff, 0x57, 0x96, 0xa1, 0x39, 0x26, 0x66, 0x4a, + 0x7e, 0xa3, 0xff, 0x99, 0x2a, 0x12, 0x74, 0xe7, 0x8b, 0xd7, 0x6a, 0xc2, 0xce, 0xf4, 0xbe, 0xc7, + 0x4a, 0xcd, 0x52, 0x24, 0xd8, 0xa9, 0x8a, 0x2b, 0x44, 0xeb, 0x21, 0x69, 0x19, 0x32, 0x56, 0xc5, + 0x3e, 0x94, 0xa3, 0x27, 0x9d, 0x36, 0xa4, 0x0f, 0x19, 0xdc, 0x17, 0x26, 0xb7, 0x2d, 0x39, 0x12, + 0x34, 0x7c, 0x4f, 0xb8, 0xd6, 0x23, 0x4a, 0x77, 0xaa, 0x02, 0xc1, 0xaf, 0x33, 0xa2, 0x08, 0xfa, + 0x83, 0x69, 0x71, 0xff, 0xa4, 0x1f, 0x64, 0x25, 0x64, 0x18, 0x0a, 0x25, 0xf8, 0xeb, 0x3b, 0xd5, + 0x90, 0x76, 0x1b, 0x0f, 0xb5, 0xb4, 0x0a, 0x5a, 0xa8, 0x5e, 0x25, 0x60, 0xba, 0x1a, 0x88, 0x21, + 0x91, 0x76, 0x3c, 0x7a, 0x32, 0xa6, 0x9e, 0x39, 0x03, 0xc7, 0x99, 0xed, 0x03, 0x4f, 0xa6, 0x99, + 0x24, 0x6a, 0x2b, 0x03, 0x0c, 0xbe, 0x7d, 0x69, 0xaf, 0xb9, 0xfd, 0x4a, 0x93, 0xba, 0xef, 0x0f, + 0xe9, 0xf5, 0xe7, 0xc4, 0x6a, 0x6e, 0xed, 0x34, 0x34, 0x47, 0xc8, 0x5c, 0xd3, 0x85, 0xc8, 0x49, + 0x4b, 0xc1, 0xfc, 0xa2, 0x75, 0x54, 0x86, 0x56, 0xbe, 0xb9, 0x83, 0xb1, 0x65, 0x6e, 0x84, 0x92, + 0x07, 0x89, 0x4a, 0x8f, 0x89, 0x85, 0x52, 0x74, 0xe8, 0xaa, 0xe6, 0x67, 0xb1, 0x77, 0x5c, 0x19, + 0x84, 0x36, 0x02, 0xc3, 0xfd, 0x86, 0x2e, 0x75, 0x31, 0x83, 0x61, 0xe3, 0x83, 0xf1, 0x0a, 0x26, + 0x90, 0x36, 0x6a, 0xd7, 0xc6, 0x4e, 0x37, 0xf7, 0x4f, 0x5c, 0xa2, 0x2b, 0x45, 0xaf, 0x9e, 0xc6, + 0x56, 0xc7, 0xd1, 0x56, 0x08, 0x5a, 0xab, 0x0e, 0x15, 0x58, 0x05, 0xd9, 0x19, 0x63, 0xdc, 0xad, + 0xbf, 0x1a, 0x0f, 0x0e, 0xd7, 0xb8, 0xc1, 0x96, 0xd5, 0xd4, 0x94, 0x76, 0x79, 0xf3, 0x29, 0xcd, + 0xa9, 0x09, 0xc3, 0x13, 0x69, 0x48, 0x40, 0xa6, 0x73, 0xd5, 0xad, 0x9b, 0x31, 0x50, 0xf5, 0xfb, + 0xd3, 0x2b, 0x91, 0x10, 0x94, 0x34, 0xe1, 0xa2, 0xda, 0x92, 0xfc, 0x1a, 0x18, 0xa3, 0xe2, 0xd3, + 0x17, 0xa4, 0x87, 0xa5, 0x05, 0xa4, 0x05, 0xaf, 0xd9, 0xba, 0xc7, 0x39, 0xb6, 0x03, 0x3b, 0x8e, + 0x39, 0x83, 0x89, 0xea, 0x03, 0xf0, 0x02, 0xd3, 0x94, 0x40, 0x25, 0x19, 0x6e, 0xe9, 0x9f, 0x6a, + 0x94, 0x25, 0xfd, 0x6e, 0x48, 0xc6, 0x07, 0xae, 0xdc, 0xc4, 0x5c, 0x94, 0x38, 0x44, 0x56, 0xa0, + 0x24, 0xbe, 0x19, 0xe5, 0x4b, 0x18, 0x52, 0xe9, 0x59, 0x94, 0xc0, 0x97, 0x46, 0xbb, 0x9d, 0x2e, + 0x96, 0x0c, 0xf8, 0xcd, 0xa3, 0xbe, 0x47, 0x36, 0x26, 0x8d, 0x5d, 0xe4, 0xd7, 0xfa, 0x14, 0x94, + 0x3f, 0x98, 0x0e, 0x35, 0x4a, 0x61, 0x17, 0xa1, 0xec, 0x9f, 0xa1, 0x24, 0x03, 0xac, 0x0e, 0x28, + 0x51, 0xf6, 0x56, 0x42, 0x59, 0x88, 0x95, 0xde, 0x87, 0xa7, 0xea, 0xfa, 0x77, 0xe5, 0xfd, 0x64, + 0x27, 0x70, 0x91, 0xe7, 0xa6, 0x19, 0x9b, 0x52, 0xcb, 0x51, 0xc4, 0xaa, 0xef, 0xa7, 0xa4, 0x72, + 0x4b, 0xfb, 0xf0, 0x48, 0x89, 0x79, 0x1c, 0xd3, 0x79, 0xb1, 0xeb, 0x14, 0x67, 0xb1, 0xb4, 0x49, + 0x6c, 0x2a, 0x06, 0x88, 0x26, 0x35, 0x2d, 0x8f, 0x62, 0x28, 0xbb, 0x02, 0xa7, 0xa6, 0xf3, 0x71, + 0x05, 0x63, 0x33, 0x29, 0x7a, 0x6a, 0x63, 0xa9, 0xea, 0xd6, 0xdf, 0xe3, 0xe5, 0x35, 0x82, 0xa2, + 0xd0, 0x6a, 0x8f, 0xe3, 0x20, 0xe4, 0x70, 0xec, 0x73, 0x5a, 0xc3, 0xad, 0x39, 0x5a, 0xad, 0xb6, + 0x81, 0x70, 0xec, 0xfe, 0x70, 0xf0, 0x75, 0x9e, 0x0f, 0x41, 0xe6, 0xb2, 0xc3, 0x59, 0x2f, 0xfc, + 0x2c, 0x9f, 0xe3, 0x5f, 0xf3, 0x64, 0x7a, 0x86, 0x2e, 0x4f, 0xc6, 0x52, 0xeb, 0xc4, 0xff, 0xef, + 0x6f, 0x65, 0xfd, 0xa6, 0x12, 0x08, 0xa1, 0x00, 0x3f, 0xf2, 0x83, 0x3f, 0xf8, 0xe0, 0x83, 0x0f, + 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, + 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0xfe, 0x7b, + 0xf2, 0x9f, 0xe7, 0xc1, 0x0b, 0x5c, 0x4c, 0x20, 0x49, 0xd3, 0x55, 0xb8, 0xb0, 0x43, 0xa5, 0x09, + 0x5d, 0x0d, 0x92, 0x26, 0x70, 0x23, 0xd4, 0x2c, 0xf7, 0x1c, 0x23, 0xb5, 0xdf, 0x60, 0x0a, 0x21, + 0x10, 0xb8, 0xf6, 0xa9, 0x6c, 0xb6, 0x3c, 0x88, 0x11, 0xce, 0x50, 0x05, 0xa5, 0x3b, 0x45, 0x94, + 0xf4, 0xac, 0x43, 0x34, 0x8f, 0x02, 0x5e, 0xac, 0x46, 0xe5, 0x1d, 0x28, 0x3a, 0x14, 0x9e, 0xd7, + 0x15, 0xa2, 0x02, 0xfa, 0x10, 0x44, 0xe5, 0x19, 0x70, 0xe6, 0x62, 0x2e, 0x24, 0x9b, 0xb1, 0x66, + 0xd9, 0xa4, 0xa2, 0x4f, 0x38, 0x02, 0x21, 0x34, 0x6b, 0x39, 0x43, 0x3e, 0x49, 0xef, 0x45, 0x0b, + 0xa3, 0x9c, 0xfa, 0x30, 0x58, 0xed, 0x27, 0xcd, 0x9d, 0x39, 0x0b, 0x1b, 0x36, 0x2d, 0x13, 0xbc, + 0x52, 0x17, 0x13, 0x03, 0x9b, 0x41, 0x68, 0xd1, 0x7b, 0x8b, 0x2c, 0xf3, 0xb8, 0x24, 0xc2, 0x64, + 0x3d, 0x24, 0x6f, 0x50, 0xbe, 0xc4, 0x4f, 0x61, 0x8a, 0x85, 0x67, 0x2e, 0x54, 0x2c, 0x11, 0x13, + 0xeb, 0x52, 0x8e, 0x7c, 0x1a, 0xa7, 0xbb, 0xcf, 0x6e, 0x51, 0xf6, 0x81, 0xef, 0x76, 0x00, 0x3a, + 0x03, 0x08, 0x93, 0xb6, 0xeb, 0x0b, 0xd2, 0xa4, 0x1c, 0x0f, 0x41, 0x2b, 0x9e, 0x5d, 0xff, 0xba, + 0x53, 0x86, 0x60, 0xc9, 0x7e, 0xbf, 0x77, 0x54, 0xa9, 0xd5, 0x90, 0x0c, 0xae, 0xc8, 0x83, 0xb5, + 0xee, 0xf5, 0x97, 0x40, 0xa0, 0x93, 0x04, 0x65, 0x9d, 0xe5, 0x2a, 0xaf, 0x95, 0xb2, 0xd3, 0x55, + 0xaf, 0xa6, 0x20, 0x0d, 0xb4, 0x68, 0x2e, 0x92, 0x2a, 0xd1, 0x5e, 0x3b, 0x7b, 0xe5, 0xc4, 0x6e, + 0xdf, 0xdc, 0x5e, 0x45, 0xfd, 0xad, 0x4c, 0x90, 0xd7, 0xf1, 0xd8, 0x39, 0x96, 0x55, 0x6a, 0x82, + 0xbb, 0xf9, 0x45, 0x30, 0x8a, 0x34, 0x2e, 0xe1, 0xb2, 0x0e, 0x4a, 0x1b, 0x1b, 0x1d, 0xb2, 0x01, + 0x12, 0x78, 0x68, 0xa5, 0x7f, 0x77, 0x3e, 0x15, 0x84, 0x3d, 0x3a, 0x4d, 0xae, 0x78, 0x86, 0x1c, + 0xb7, 0xb0, 0xc3, 0x3b, 0x42, 0x79, 0x6f, 0x0c, 0x25, 0x47, 0x20, 0x50, 0x8f, 0x49, 0x5d, 0xe3, + 0xbb, 0xd0, 0xf2, 0xae, 0x79, 0x40, 0x28, 0x87, 0x6f, 0xf5, 0xaf, 0x51, 0x50, 0x9d, 0x6e, 0xd1, + 0x40, 0xe3, 0x8f, 0x4e, 0x33, 0x59, 0xf5, 0x74, 0x67, 0xdd, 0xd5, 0x83, 0x8b, 0x45, 0xf3, 0x2e, + 0x72, 0x5c, 0xdd, 0x39, 0x1f, 0x07, 0xe3, 0x8f, 0xb2, 0xcd, 0x5e, 0xf8, 0xc2, 0x7d, 0x78, 0xdd, + 0xe6, 0xeb, 0x86, 0xd5, 0x67, 0x9d, 0x60, 0x6b, 0x51, 0xcf, 0x8b, 0x2c, 0x90, 0xcc, 0xcc, 0x35, + 0xad, 0xd9, 0x34, 0xc8, 0x32, 0x61, 0x0b, 0x6c, 0xdf, 0xd7, 0x09, 0xf4, 0xc8, 0x5e, 0x6a, 0x37, + 0x0c, 0xbc, 0xf2, 0x99, 0x1c, 0x45, 0x4f, 0x72, 0x19, 0x71, 0x90, 0xea, 0x56, 0x1f, 0x4a, 0x88, + 0xb1, 0x49, 0xc4, 0xce, 0x7e, 0x01, 0xc5, 0x70, 0x7d, 0x18, 0x52, 0xfc, 0x57, 0x3b, 0xa9, 0x6f, + 0xec, 0xf7, 0x27, 0x55, 0x8b, 0x7c, 0x0c, 0x5e, 0xc7, 0xc5, 0x5d, 0x0e, 0x68, 0xa7, 0x55, 0xf9, + 0x7d, 0xb7, 0x5f, 0x7c, 0x2a, 0x7b, 0xff, 0xbd, 0x5c, 0xef, 0x01, 0xce, 0xb1, 0x99, 0xc2, 0x4d, + 0x13, 0xf5, 0x02, 0xee, 0xd8, 0xc3, 0x53, 0xc7, 0xdb, 0x98, 0x0d, 0x28, 0x90, 0x56, 0xa6, 0xba, + 0x95, 0x56, 0xee, 0x7a, 0xe2, 0x77, 0xe3, 0x5a, 0xcc, 0xf6, 0x6c, 0x5f, 0xb1, 0x0d, 0x0f, 0x53, + 0x90, 0xf9, 0xd7, 0x8c, 0x18, 0x11, 0xc2, 0xfd, 0x83, 0x69, 0x1d, 0xcf, 0xe1, 0x42, 0x3a, 0x3c, + 0x10, 0x20, 0x9e, 0x69, 0xf2, 0xb3, 0x27, 0x5c, 0x29, 0x77, 0x84, 0x42, 0x76, 0x43, 0xe0, 0x1c, + 0xe3, 0x55, 0xa2, 0x48, 0x93, 0x05, 0x9d, 0xf5, 0xa8, 0x6c, 0x50, 0xfc, 0x73, 0x60, 0x0e, 0x6d, + 0x99, 0xe2, 0x5a, 0xf0, 0x2c, 0x4d, 0x51, 0x02, 0x6e, 0x98, 0x4a, 0x2f, 0x12, 0xb7, 0x97, 0x59, + 0xff, 0xe3, 0xbf, 0xee, 0x59, 0x2a, 0x99, 0xa2, 0x01, 0x80, 0x81, 0xe1, 0x26, 0xe0, 0x0c, 0xbc, + 0x6d, 0xb5, 0xab, 0xeb, 0x32, 0x29, 0xad, 0x32, 0x79, 0x36, 0xa9, 0xc4, 0x47, 0xfb, 0x45, 0x43, + 0x5f, 0x3f, 0xe6, 0xae, 0x3c, 0x6e, 0xbc, 0x99, 0xdb, 0x19, 0x93, 0xe6, 0x92, 0x01, 0x37, 0xfb, + 0x55, 0xfe, 0xd9, 0x28, 0xc8, 0x6d, 0x1b, 0xd4, 0x52, 0xd9, 0xea, 0x9a, 0xb3, 0x07, 0x4e, 0xe3, + 0xa7, 0xb1, 0x89, 0x48, 0xb7, 0x49, 0x4a, 0x32, 0x31, 0x0b, 0x4c, 0x93, 0xa8, 0x00, 0xb2, 0x21, + 0x16, 0x25, 0x6b, 0xb7, 0x3a, 0x02, 0xff, 0xbe, 0x45, 0x78, 0xd6, 0xe7, 0x27, 0x3a, 0x98, 0xe8, + 0x81, 0x98, 0x0c, 0x37, 0x93, 0x36, 0x41, 0x99, 0x54, 0x49, 0xfa, 0xf0, 0x57, 0xdb, 0xa9, 0xda, + 0x8c, 0xac, 0x62, 0x39, 0xdc, 0x2a, 0x7d, 0xdd, 0x1b, 0x5f, 0x8d, 0x58, 0xbe, 0xf3, 0xfa, 0x32, + 0x7b, 0x1a, 0x44, 0x65, 0xdc, 0x23, 0x48, 0x9a, 0x8d, 0x1e, 0x3a, 0x90, 0x7a, 0xbe, 0x3f, 0xfc, + 0xbe, 0xbe, 0x98, 0x2c, 0xd5, 0x98, 0x34, 0x87, 0x62, 0xc6, 0x1a, 0x4e, 0xd9, 0xce, 0x5f, 0x2e, + 0xcb, 0x67, 0xe8, 0x27, 0x6e, 0xf1, 0xe9, 0x79, 0x46, 0x35, 0x1c, 0x53, 0xa1, 0x15, 0xd3, 0x8d, + 0x6b, 0x5c, 0x77, 0x88, 0x2c, 0xc3, 0xf4, 0x29, 0x10, 0x9e, 0x56, 0x1b, 0x35, 0xb8, 0xf5, 0xb8, + 0x73, 0xd8, 0xbb, 0x15, 0x9f, 0x5c, 0xc3, 0x59, 0x11, 0x3c, 0xfe, 0x57, 0x2c, 0xed, 0x71, 0x36, + 0xab, 0xea, 0x4b, 0x3c, 0x4e, 0x61, 0x6d, 0x77, 0x64, 0x91, 0x55, 0xbd, 0x88, 0xb1, 0xb5, 0xd2, + 0xd6, 0x50, 0xaa, 0xa3, 0x7f, 0x22, 0xbf, 0x9a, 0x26, 0x17, 0xff, 0x60, 0x9a, 0x29, 0x76, 0x78, + 0x3a, 0x9f, 0x58, 0x16, 0x21, 0xca, 0x64, 0x81, 0x9a, 0x00, 0x3e, 0xd2, 0xbb, 0x3a, 0x9f, 0xde, + 0xff, 0x7a, 0x08, 0x53, 0x59, 0x72, 0xc1, 0x33, 0xb1, 0x92, 0xb0, 0x5b, 0xcf, 0x09, 0x5d, 0x30, + 0xaf, 0xc0, 0xf6, 0xfb, 0x31, 0xa0, 0x24, 0x5a, 0x51, 0x35, 0xbf, 0xb9, 0x3a, 0x0c, 0x2d, 0xe8, + 0x0a, 0x69, 0x59, 0x70, 0x69, 0x80, 0xe4, 0xe4, 0x66, 0x62, 0x39, 0xa7, 0x03, 0x7a, 0x14, 0x7e, + 0xc9, 0xdd, 0x59, 0x96, 0x71, 0xc6, 0x54, 0x9c, 0x0d, 0xc1, 0xcb, 0xb1, 0xd2, 0xe5, 0x5a, 0xa7, + 0xa7, 0xfb, 0x16, 0x78, 0x65, 0xd8, 0x04, 0x5d, 0x94, 0xcb, 0x05, 0xc5, 0xf5, 0x4f, 0x5c, 0x61, + 0xa5, 0xb3, 0x22, 0x16, 0x91, 0xa4, 0x2e, 0x07, 0x54, 0x60, 0xca, 0x97, 0x1c, 0x09, 0x2b, 0x51, + 0x81, 0xe0, 0xbd, 0x6f, 0x8c, 0xdc, 0x08, 0x73, 0x7e, 0x6a, 0x0c, 0x20, 0x36, 0xae, 0x2b, 0x80, + 0xdb, 0x4a, 0x00, 0x32, 0x60, 0xb3, 0x6b, 0x95, 0x42, 0xf5, 0xfd, 0x32, 0x32, 0xfc, 0x88, 0xdd, + 0x24, 0xd8, 0xdf, 0xa2, 0xe4, 0x40, 0x22, 0x77, 0x8a, 0xa8, 0xf3, 0xbb, 0xb7, 0x95, 0x97, 0xd2, + 0x37, 0x0f, 0x32, 0x79, 0x5c, 0x2b, 0x53, 0x08, 0x9b, 0xbd, 0x3a, 0xa8, 0x09, 0xd8, 0x9d, 0xcd, + 0xf4, 0xc2, 0x85, 0xf3, 0xbf, 0x86, 0x51, 0x38, 0xe0, 0x4a, 0x4a, 0xd5, 0xf7, 0x37, 0xf8, 0x4f, + 0x77, 0x25, 0x90, 0x84, 0xd4, 0xa5, 0xd7, 0x17, 0x99, 0x88, 0xd8, 0x6a, 0x89, 0xf9, 0x2e, 0x9c, + 0x41, 0x77, 0x7a, 0x35, 0xe6, 0x71, 0x0e, 0xd9, 0xc0, 0x7e, 0x1a, 0x7c, 0x38, 0xb7, 0x9f, 0xec, + 0x54, 0xc2, 0x2a, 0x75, 0xc9, 0xfb, 0x22, 0xe1, 0x76, 0x2a, 0x98, 0x9e, 0x67, 0x74, 0x75, 0xe6, + 0x92, 0x51, 0x64, 0x4a, 0x73, 0x3c, 0xa0, 0xcb, 0xe6, 0x87, 0x07, 0x74, 0x8b, 0xe6, 0xd1, 0xa3, + 0x21, 0x9a, 0xcf, 0xeb, 0x51, 0x0a, 0x8a, 0x1b, 0xfb, 0x2d, 0xaa, 0x4a, 0x78, 0x85, 0x69, 0xbf, + 0xb5, 0xe8, 0x94, 0xf9, 0x0b, 0xdf, 0xaf, 0x67, 0x31, 0x90, 0x2b, 0x7f, 0x30, 0x6d, 0xda, 0xe3, + 0xa6, 0x57, 0x07, 0xec, 0xa7, 0x0e, 0x61, 0x9d, 0xc7, 0x74, 0x56, 0x99, 0xd2, 0x17, 0x81, 0x3e, + 0x41, 0x15, 0x77, 0x82, 0x32, 0xbb, 0x1e, 0x80, 0x47, 0x61, 0x63, 0x88, 0x1a, 0xa7, 0xba, 0x65, + 0x1b, 0xe1, 0x31, 0x37, 0xba, 0xaf, 0xc9, 0xbb, 0x7f, 0xa4, 0x7b, 0x8b, 0xa9, 0xdd, 0xe3, 0x34, + 0x08, 0x39, 0x02, 0xb8, 0x19, 0x12, 0xd0, 0x9e, 0x21, 0xbd, 0xd8, 0x85, 0x2e, 0xb2, 0x41, 0xbc, + 0x07, 0xdd, 0x47, 0x5f, 0xb2, 0xc9, 0xa8, 0xd1, 0x85, 0x95, 0x1c, 0x12, 0x05, 0x61, 0x6d, 0x6e, + 0x8e, 0x41, 0x00, 0x54, 0xf5, 0xc6, 0x06, 0x50, 0xe5, 0x67, 0x5f, 0x3e, 0x3c, 0x0d, 0x21, 0x48, + 0xfc, 0x10, 0xb1, 0x26, 0x46, 0xdb, 0xad, 0x55, 0xfb, 0x3f, 0xf0, 0xc9, 0xb0, 0xf4, 0xad, 0x82, + 0xa6, 0xf9, 0x4f, 0x21, 0xf3, 0x60, 0xb1, 0x14, 0x6b, 0x6d, 0x36, 0xfc, 0x2e, 0xb2, 0x26, 0x66, + 0x97, 0x17, 0x34, 0xda, 0x66, 0x99, 0xa4, 0x46, 0xd9, 0xee, 0x18, 0xc6, 0x4f, 0xeb, 0x98, 0x33, + 0x36, 0x1c, 0xe9, 0x31, 0x38, 0xf8, 0x6d, 0x00, 0xf9, 0xe2, 0xf1, 0x20, 0x8c, 0x52, 0xda, 0xe4, + 0xee, 0xcc, 0x4a, 0x22, 0x78, 0x5d, 0x97, 0x1b, 0xa4, 0xc7, 0x73, 0xf1, 0x13, 0x5c, 0xb9, 0xc4, + 0x26, 0x87, 0x9a, 0xfb, 0x83, 0xb3, 0x76, 0x8e, 0x35, 0x2e, 0xcf, 0xf6, 0x42, 0x3c, 0x47, 0x22, + 0x89, 0xa6, 0x1b, 0xe9, 0x90, 0xb8, 0x10, 0x92, 0x32, 0x26, 0x7e, 0xa1, 0x2b, 0x87, 0x0f, 0xdc, + 0x89, 0x45, 0x56, 0xf5, 0xa8, 0x46, 0xa1, 0x09, 0x1d, 0x04, 0xaa, 0x02, 0x27, 0x81, 0xac, 0x3c, + 0x5a, 0xde, 0xba, 0x96, 0x89, 0xd3, 0xf6, 0x94, 0xf5, 0xb0, 0x0c, 0xcb, 0xed, 0x39, 0xd8, 0x44, + 0xd5, 0xdc, 0x1b, 0x03, 0x9d, 0x98, 0xb1, 0x02, 0xab, 0x9e, 0xbd, 0xdb, 0xc7, 0x9d, 0xcf, 0x7c, + 0x62, 0xcb, 0xba, 0x64, 0x3a, 0xc0, 0x53, 0xb4, 0x32, 0x51, 0x09, 0xcb, 0x2a, 0x57, 0xe9, 0x10, + 0x57, 0x36, 0x5e, 0x20, 0x94, 0x12, 0xd7, 0x6f, 0xce, 0xa0, 0x94, 0xfe, 0xc1, 0xb4, 0xfd, 0x72, + 0x20, 0x80, 0xd5, 0xad, 0xe4, 0x96, 0xd4, 0x9e, 0x0b, 0x8f, 0x06, 0x9f, 0x1a, 0x6e, 0xb7, 0x47, + 0x99, 0xb0, 0xbf, 0x0f, 0x68, 0x0f, 0xfa, 0x66, 0xba, 0xbb, 0x7b, 0x1e, 0xce, 0x64, 0x22, 0x5a, + 0x28, 0x30, 0x02, 0xed, 0x06, 0xc8, 0x66, 0xdb, 0x3b, 0xaf, 0xab, 0xcb, 0x8d, 0x7e, 0x42, 0xcd, + 0xdd, 0xa9, 0xc6, 0x1b, 0xd5, 0x12, 0x72, 0x61, 0x67, 0x9a, 0xcb, 0x6b, 0xd9, 0x72, 0x2d, 0xd8, + 0x94, 0x24, 0x08, 0x91, 0xd2, 0x0e, 0x49, 0x62, 0x07, 0x69, 0x42, 0xd6, 0x6e, 0xdc, 0x0e, 0x26, + 0x53, 0x25, 0x38, 0xea, 0xb7, 0xc7, 0x45, 0xdb, 0x83, 0x29, 0x3c, 0x28, 0x0f, 0x08, 0x49, 0xef, + 0x14, 0x10, 0x3e, 0xa3, 0xd2, 0x1d, 0xf8, 0xa4, 0xb5, 0x57, 0x35, 0xa3, 0xcf, 0xd5, 0x23, 0x67, + 0xaf, 0xb6, 0xb0, 0xae, 0xd9, 0x3e, 0xe6, 0xea, 0x3c, 0xa8, 0x66, 0xf9, 0xc1, 0xb9, 0xc5, 0xb4, + 0x39, 0x01, 0x78, 0x59, 0xea, 0x7e, 0x38, 0xc9, 0x98, 0x4d, 0xb7, 0x41, 0x71, 0x0f, 0xb2, 0xd0, + 0x87, 0x55, 0xf9, 0x4d, 0xe3, 0x96, 0x7d, 0xd0, 0xc9, 0x4c, 0x1e, 0xa6, 0x26, 0xf3, 0xad, 0xcc, + 0x93, 0x0a, 0x6a, 0xf9, 0x4e, 0x8b, 0xf5, 0xe2, 0x72, 0x44, 0x4a, 0xa9, 0xd2, 0x6f, 0x08, 0xf1, + 0x55, 0x57, 0x03, 0x7a, 0x16, 0xf9, 0xbd, 0x67, 0x26, 0xd4, 0xb6, 0x77, 0xd2, 0xcc, 0xbd, 0xf2, + 0xeb, 0xfb, 0xcc, 0x00, 0xdc, 0x12, 0xeb, 0xf3, 0xe9, 0xf5, 0x16, 0x12, 0x33, 0x68, 0xf6, 0x2d, + 0x97, 0xa3, 0x47, 0x34, 0xdf, 0x22, 0x9d, 0xfb, 0x26, 0x5c, 0x5e, 0x66, 0x28, 0x8b, 0xf0, 0x46, + 0x65, 0xa2, 0xf2, 0x08, 0xea, 0xb9, 0xf7, 0xef, 0xfc, 0x73, 0x88, 0x4a, 0xec, 0xf6, 0x79, 0x2d, + 0x6f, 0xec, 0xdf, 0x04, 0xed, 0x48, 0x7c, 0xaa, 0x75, 0x07, 0x5a, 0x5f, 0x53, 0x07, 0xba, 0x14, + 0x37, 0xd5, 0x2a, 0x23, 0xc3, 0x06, 0x76, 0xbd, 0x38, 0x7a, 0x50, 0x1f, 0xd5, 0xab, 0xfc, 0xd3, + 0x0e, 0x89, 0xda, 0xa2, 0x11, 0x61, 0x32, 0x44, 0x76, 0x7e, 0xcd, 0xc6, 0xed, 0x40, 0x7f, 0x30, + 0x2d, 0x32, 0xfc, 0x3f, 0x09, 0xc7, 0x55, 0xe2, 0x41, 0xff, 0xa3, 0x9a, 0x36, 0x44, 0x6b, 0xbe, + 0x0e, 0xad, 0xe8, 0x78, 0xff, 0xbf, 0x94, 0x04, 0x76, 0x29, 0x90, 0x7f, 0x20, 0x2f, 0x0d, 0xc0, + 0x53, 0x70, 0x39, 0xb7, 0x36, 0xdd, 0x22, 0xf1, 0xc7, 0xda, 0x0a, 0xf3, 0xf1, 0xd1, 0x4f, 0x6c, + 0x86, 0xd7, 0xde, 0x6e, 0x87, 0x4b, 0xce, 0x40, 0x50, 0x09, 0xfc, 0xf3, 0x18, 0x1a, 0x97, 0xe5, + 0x01, 0x22, 0x04, 0x3d, 0xb6, 0x90, 0x74, 0x53, 0x7e, 0x72, 0x1b, 0xd2, 0x44, 0x63, 0x95, 0x71, + 0x42, 0xd4, 0x02, 0x5b, 0x8f, 0x1e, 0x3f, 0x33, 0x68, 0x16, 0x96, 0x13, 0xe9, 0x25, 0x59, 0xb3, + 0x23, 0xd2, 0x5e, 0x55, 0x7a, 0xd2, 0x42, 0xc4, 0x7c, 0xd6, 0x15, 0xcb, 0x02, 0xc1, 0xdb, 0xa1, + 0x41, 0x64, 0x9d, 0x0d, 0xab, 0xc2, 0x44, 0x3f, 0x23, 0x4b, 0xba, 0x8a, 0x62, 0x59, 0x78, 0x42, + 0x48, 0x64, 0xf1, 0x4e, 0x12, 0x93, 0x69, 0x52, 0xcb, 0xda, 0x7e, 0x99, 0xa4, 0xe8, 0x54, 0x5e, + 0x93, 0x74, 0x45, 0xb2, 0xae, 0xa6, 0x68, 0xa7, 0xc1, 0xc3, 0x41, 0xdd, 0xd0, 0x4e, 0x81, 0x63, + 0x28, 0xa5, 0x31, 0xd7, 0xa1, 0x83, 0x93, 0x82, 0xd4, 0xb1, 0xdb, 0x55, 0x6a, 0xcb, 0x22, 0x49, + 0x01, 0xd0, 0xfb, 0x71, 0xaa, 0x0a, 0x8e, 0x78, 0xdb, 0x31, 0x41, 0xf4, 0x8c, 0x28, 0xd8, 0x3c, + 0x4a, 0x4e, 0xa8, 0x0c, 0x99, 0xc7, 0x56, 0x76, 0x87, 0x6e, 0xee, 0x41, 0xd1, 0x57, 0x26, 0x4b, + 0xaf, 0x23, 0x1b, 0xb5, 0xbd, 0x4a, 0x92, 0xa0, 0xdd, 0xeb, 0x08, 0x8a, 0xe5, 0x2a, 0xea, 0xcb, + 0xd6, 0x65, 0x84, 0x82, 0x5f, 0x5f, 0x73, 0x4f, 0x99, 0x12, 0x1d, 0x4e, 0x04, 0xf5, 0xc4, 0xe3, + 0xdf, 0xb7, 0x6a, 0xe8, 0x24, 0x33, 0xde, 0x3d, 0xb8, 0x96, 0xcc, 0x2a, 0xa1, 0xb3, 0x54, 0x96, + 0xd5, 0x57, 0xbb, 0xb3, 0x74, 0xe7, 0x91, 0xbf, 0x91, 0x76, 0x8a, 0xfc, 0xe0, 0x69, 0xa5, 0xab, + 0x45, 0xd8, 0x25, 0x7b, 0xe7, 0xc2, 0xaa, 0xb5, 0xfc, 0x3a, 0x7a, 0x10, 0x94, 0x3f, 0x98, 0x0e, + 0x65, 0xd8, 0xfa, 0xfd, 0x79, 0x6e, 0x13, 0x98, 0x26, 0x59, 0x90, 0x25, 0x49, 0x4c, 0xce, 0x3a, + 0xc7, 0xb9, 0xa6, 0x2f, 0xb8, 0xd3, 0x8d, 0x3e, 0x76, 0x6f, 0xe2, 0x74, 0x68, 0xa8, 0xb8, 0xd8, + 0xe5, 0x75, 0xf0, 0xf0, 0xf3, 0xfa, 0x46, 0x8f, 0xad, 0xe1, 0x47, 0x3b, 0xd9, 0x46, 0x4d, 0x3e, + 0x68, 0x03, 0x9c, 0xeb, 0xc5, 0xe3, 0x84, 0xfa, 0xea, 0x48, 0x31, 0x95, 0xf7, 0x43, 0x73, 0xd4, + 0x07, 0xac, 0xc9, 0xc6, 0x2e, 0x6c, 0xc7, 0x4d, 0xab, 0x60, 0xa3, 0x1b, 0x89, 0x01, 0x3e, 0x78, + 0x11, 0x75, 0x3d, 0x4c, 0xa9, 0x12, 0xc7, 0xf9, 0x60, 0x01, 0x88, 0xee, 0xa2, 0xe9, 0x89, 0x08, + 0xc6, 0xa9, 0x1c, 0x83, 0x49, 0xca, 0x52, 0x5e, 0xac, 0x5f, 0x2f, 0x82, 0xf7, 0x7e, 0x7f, 0x8b, + 0xd1, 0x40, 0xfe, 0x7e, 0x0d, 0x3d, 0xe1, 0x5f, 0x45, 0xf5, 0x46, 0x67, 0xe5, 0x5e, 0x7c, 0x70, + 0xd0, 0x4a, 0xc9, 0x1e, 0x4f, 0xbd, 0x1d, 0x6d, 0x3e, 0xd0, 0xfb, 0xd4, 0xf0, 0x79, 0xbc, 0x76, + 0xbd, 0x8f, 0x34, 0x86, 0xd4, 0xfc, 0xf8, 0x1c, 0x0d, 0x70, 0xfa, 0x3d, 0xa6, 0xe5, 0x8c, 0x0a, + 0xe5, 0xe9, 0x45, 0x47, 0x3b, 0xb9, 0xa1, 0x49, 0xb5, 0x5f, 0xf8, 0x6c, 0x68, 0x05, 0x67, 0xc0, + 0x14, 0x3c, 0x9b, 0xc8, 0xe6, 0x0e, 0x60, 0x7e, 0xf8, 0xbb, 0x73, 0x8b, 0xc5, 0x1e, 0x24, 0x7b, + 0x28, 0x07, 0x34, 0xed, 0x64, 0x6d, 0xa0, 0xe9, 0x24, 0x12, 0x03, 0x75, 0x5e, 0x46, 0xa8, 0x4d, + 0xd4, 0x14, 0xc9, 0xc6, 0xe1, 0xfe, 0x12, 0xfb, 0xd1, 0xdb, 0x7e, 0xad, 0xb1, 0x2b, 0x43, 0xe8, + 0xd9, 0x3f, 0x58, 0xbe, 0xe5, 0x4c, 0x4f, 0xe7, 0x38, 0x50, 0xdc, 0xbe, 0x7c, 0x5b, 0x03, 0x4e, + 0x10, 0xea, 0x22, 0xd7, 0xb0, 0xb8, 0x5c, 0x90, 0xeb, 0x28, 0x0c, 0x40, 0x10, 0xea, 0x4f, 0x52, + 0x00, 0x6c, 0xb2, 0xb2, 0xc3, 0xa5, 0x10, 0x65, 0x31, 0x17, 0xb8, 0xa9, 0xf2, 0x4e, 0xfc, 0x24, + 0x4b, 0x52, 0x0e, 0x34, 0x7b, 0x3f, 0x85, 0x8f, 0xbb, 0x96, 0x44, 0x28, 0xf8, 0x9b, 0xbd, 0xa3, + 0x8a, 0xdf, 0x9a, 0xae, 0x90, 0x8b, 0x72, 0xc7, 0xed, 0x40, 0x4a, 0xe3, 0x9d, 0xc0, 0x63, 0x36, + 0x07, 0x61, 0xa2, 0xf5, 0x07, 0xa4, 0xc6, 0x80, 0x5c, 0x2f, 0xe1, 0x71, 0x5e, 0xb2, 0xd9, 0x61, + 0x2c, 0xeb, 0xab, 0x43, 0xa4, 0x77, 0xe8, 0xa7, 0x50, 0x00, 0x9e, 0x8e, 0x42, 0x51, 0xc9, 0x82, + 0xa6, 0xd9, 0x12, 0xc7, 0x83, 0x12, 0x02, 0xb7, 0x33, 0xd0, 0xd8, 0x53, 0x79, 0xfd, 0x0c, 0x7e, + 0xae, 0xc5, 0x64, 0xd7, 0xd9, 0xee, 0x09, 0xaa, 0x8c, 0x6e, 0x2d, 0x33, 0x73, 0xe0, 0x71, 0x07, + 0xa9, 0xab, 0x1d, 0x27, 0x75, 0x49, 0x59, 0xeb, 0x49, 0x18, 0x1e, 0xdd, 0x9d, 0x63, 0xee, 0xc1, + 0x71, 0xed, 0x13, 0x8f, 0x43, 0x52, 0xb8, 0x54, 0x21, 0xb2, 0x11, 0x2f, 0x15, 0x60, 0x0f, 0x75, + 0x4e, 0x40, 0x6e, 0x1c, 0xe7, 0x38, 0x9b, 0xc4, 0xca, 0x6a, 0x14, 0xb6, 0x25, 0x58, 0x62, 0xe1, + 0xb0, 0x45, 0x05, 0x04, 0x88, 0x82, 0x21, 0xfc, 0x11, 0x94, 0xce, 0x01, 0x82, 0x5d, 0x6a, 0xfa, + 0x3d, 0x7e, 0xc5, 0x00, 0x00, 0x80, 0x49, 0x26, 0x20, 0x11, 0x0e, 0x8a, 0xcd, 0xcd, 0x09, 0x42, + 0xe3, 0x9f, 0x9c, 0xb5, 0x24, 0x0d, 0x11, 0x15, 0x02, 0x1c, 0xc2, 0xf1, 0x5c, 0xc4, 0xfe, 0x84, + 0xae, 0x70, 0x41, 0x37, 0x91, 0xb5, 0x00, 0x15, 0xd2, 0x2a, 0x12, 0x49, 0x14, 0x2d, 0x48, 0x9c, + 0x9e, 0xe9, 0xf3, 0xe4, 0x12, 0x84, 0xb0, 0x9f, 0xdd, 0x2b, 0xc3, 0xa0, 0x7c, 0xad, 0xbe, 0x02, + 0xad, 0x55, 0x3b, 0xab, 0x05, 0x89, 0xe8, 0x86, 0xd0, 0x89, 0x44, 0x5e, 0x2b, 0x55, 0x56, 0x46, + 0x44, 0x0c, 0x51, 0x23, 0x30, 0x9e, 0x93, 0x95, 0xed, 0x0c, 0xa6, 0x4d, 0x94, 0x60, 0xe8, 0x5c, + 0x25, 0x64, 0xbc, 0x27, 0xc3, 0x51, 0x2a, 0xc3, 0x41, 0x84, 0x9e, 0x1f, 0x2a, 0x70, 0x87, 0x2a, + 0x17, 0x0e, 0xfd, 0x69, 0x79, 0x5a, 0x76, 0x3c, 0xfc, 0x52, 0x71, 0x20, 0x76, 0x8e, 0x84, 0x98, + 0x8f, 0x70, 0x6c, 0xdd, 0xe3, 0x22, 0xe6, 0x84, 0xa0, 0xb9, 0xc2, 0xda, 0xdd, 0x6f, 0xce, 0xa0, + 0x54, 0xfe, 0xa1, 0x4f, 0xe7, 0x73, 0x76, 0x59, 0xb3, 0xaa, 0x1a, 0x81, 0xae, 0x42, 0x62, 0xef, + 0x2e, 0x5d, 0xd4, 0xad, 0xa7, 0xd6, 0x50, 0x55, 0xcd, 0x22, 0xe5, 0x2b, 0xa3, 0xf0, 0x7c, 0xbe, + 0xb6, 0x2e, 0x1f, 0xc4, 0xb9, 0xed, 0x34, 0xca, 0x98, 0xe6, 0x1a, 0x24, 0xcf, 0x96, 0x24, 0xf6, + 0xae, 0x5b, 0xa2, 0x4d, 0xef, 0x16, 0x47, 0x65, 0x6b, 0xd5, 0xe2, 0x25, 0x49, 0x3d, 0xa7, 0x8b, + 0x9e, 0xae, 0x14, 0xd2, 0x63, 0x0f, 0xd2, 0xb3, 0x0b, 0xdc, 0x15, 0xb4, 0xb1, 0x2e, 0x4c, 0x30, + 0xf7, 0x04, 0x1e, 0x10, 0xd5, 0x45, 0x09, 0x11, 0x95, 0x0b, 0x44, 0x20, 0x8e, 0xac, 0x64, 0x9c, + 0xdc, 0xc7, 0xc4, 0x95, 0x66, 0xcd, 0x52, 0xb5, 0x0f, 0x6a, 0x99, 0x1a, 0xe1, 0x5f, 0xcf, 0x39, + 0xee, 0x29, 0x4c, 0x65, 0x1a, 0x88, 0x33, 0xf2, 0x7a, 0xf8, 0x6f, 0x5c, 0x0d, 0x54, 0xc6, 0x0a, + 0xb6, 0xc0, 0x1e, 0x40, 0x55, 0xec, 0x21, 0x18, 0xcf, 0x01, 0xb5, 0x0d, 0x3c, 0xc7, 0xf6, 0x04, + 0xda, 0xe2, 0xf5, 0xf7, 0x75, 0x0d, 0x07, 0x50, 0xaf, 0x9b, 0x1a, 0x16, 0x68, 0xeb, 0xbd, 0x2d, + 0x42, 0x1b, 0x1d, 0xd6, 0x75, 0xea, 0xbf, 0x0a, 0x3c, 0x60, 0x2d, 0x90, 0x60, 0x01, 0x3a, 0x0f, + 0x6b, 0x24, 0xf3, 0x05, 0x30, 0x36, 0x5b, 0xd8, 0xa5, 0xdc, 0x97, 0xda, 0x1d, 0x94, 0xdd, 0x70, + 0x20, 0xcb, 0xb3, 0x80, 0xca, 0x3d, 0xfe, 0x5c, 0x74, 0x8d, 0x67, 0x95, 0xf0, 0xdd, 0x6b, 0xba, + 0x21, 0xae, 0xa4, 0x10, 0xf6, 0x41, 0xa5, 0x93, 0x60, 0x03, 0x6b, 0x04, 0x45, 0x29, 0xae, 0x99, + 0xf8, 0x3a, 0xe0, 0x90, 0x98, 0x41, 0x25, 0xae, 0xe1, 0x35, 0x07, 0x7e, 0xf1, 0xe7, 0x17, 0x85, + 0xa3, 0xfd, 0x90, 0xf8, 0x00, 0x26, 0x16, 0x17, 0x1d, 0xd7, 0x16, 0x0a, 0x90, 0x96, 0x9f, 0x1c, + 0x8b, 0x39, 0xae, 0xe0, 0x0c, 0x50, 0x09, 0x04, 0x17, 0x63, 0xb2, 0x63, 0x84, 0x60, 0x1b, 0xdd, + 0x09, 0x79, 0x5e, 0x78, 0x78, 0x83, 0xcc, 0xed, 0xb9, 0xc9, 0x45, 0xfe, 0x59, 0xec, 0xd7, 0x71, + 0x9a, 0xa2, 0xf9, 0x83, 0xe9, 0xe2, 0xd0, 0x01, 0xc0, 0xd6, 0xc5, 0x47, 0x64, 0x11, 0x2a, 0xa6, + 0xc4, 0x1d, 0x32, 0xb4, 0x83, 0x28, 0x21, 0xfe, 0x81, 0x7f, 0x65, 0x96, 0x38, 0x15, 0x05, 0x5e, + 0xec, 0x95, 0xe6, 0x16, 0xc4, 0x77, 0x84, 0xa4, 0x76, 0x50, 0xec, 0x6e, 0xe0, 0xd2, 0xd2, 0x69, + 0xcf, 0xb4, 0x74, 0x3a, 0x56, 0xaa, 0x58, 0x6d, 0x21, 0x2a, 0x1a, 0xc6, 0x6e, 0xee, 0x8a, 0x50, + 0x5b, 0x98, 0x10, 0x15, 0x64, 0xf0, 0x49, 0x5d, 0x25, 0xf4, 0x1e, 0x07, 0x57, 0xe0, 0x31, 0x3e, + 0xcd, 0xab, 0x86, 0x47, 0xab, 0x92, 0xeb, 0x5d, 0xaa, 0xbd, 0x8c, 0x11, 0xd4, 0x59, 0xe9, 0x03, + 0x72, 0x0f, 0x01, 0x86, 0x68, 0x6f, 0x46, 0xc5, 0xd5, 0x28, 0x94, 0x02, 0x9e, 0x0a, 0x95, 0xb3, + 0x41, 0xd9, 0x55, 0x2a, 0x8a, 0xc1, 0xd4, 0x08, 0x5d, 0x94, 0xec, 0x6a, 0xb2, 0x2a, 0x55, 0xdd, + 0xae, 0x33, 0xdb, 0x3a, 0x19, 0x83, 0x4e, 0xc7, 0x5c, 0x7a, 0xae, 0x9d, 0xb8, 0x22, 0x2b, 0x97, + 0x78, 0xec, 0xd9, 0xba, 0x2e, 0xee, 0x2d, 0xef, 0x3e, 0x75, 0x86, 0xca, 0xe5, 0xbc, 0x42, 0xfe, + 0xd2, 0x30, 0x38, 0xfe, 0x6d, 0xd6, 0x40, 0x86, 0x81, 0x52, 0x92, 0xf7, 0xeb, 0x6c, 0x12, 0x10, + 0xb8, 0xcb, 0xbd, 0xcf, 0x32, 0xb1, 0xaa, 0xce, 0xe9, 0xa1, 0x20, 0x25, 0x12, 0x46, 0x6d, 0xaa, + 0x91, 0x26, 0xa1, 0x10, 0xb5, 0x21, 0xa9, 0x8d, 0x73, 0xfa, 0x90, 0x48, 0xbe, 0x71, 0x42, 0xaa, + 0x02, 0x53, 0x6c, 0x7f, 0x1f, 0xac, 0x1f, 0xc8, 0x7e, 0x61, 0xe5, 0x70, 0xa3, 0x37, 0x53, 0x83, + 0xb6, 0xdf, 0xbe, 0x66, 0x38, 0xc6, 0xa7, 0x0c, 0xab, 0xb9, 0xf3, 0xca, 0x5a, 0x72, 0x18, 0x5b, + 0x6d, 0x81, 0xe0, 0xf1, 0xc8, 0x64, 0x28, 0x44, 0x13, 0x72, 0x5b, 0xe5, 0xec, 0xb5, 0xcb, 0x75, + 0xf9, 0x7d, 0x6d, 0xf9, 0x3f, 0xad, 0xc8, 0xd6, 0xbc, 0x07, 0xd9, 0xa2, 0x66, 0x24, 0xa2, 0xa1, + 0x79, 0x64, 0xd0, 0x5d, 0x65, 0xe4, 0xdb, 0x2e, 0xbf, 0x86, 0x25, 0xd7, 0x5d, 0x25, 0xe5, 0x9c, + 0xf3, 0xdf, 0x9c, 0x6d, 0xc6, 0xfc, 0x83, 0xe9, 0x14, 0xcd, 0x2f, 0xd0, 0x84, 0x68, 0xde, 0x52, + 0xb2, 0x3e, 0x7b, 0xe1, 0x34, 0xf6, 0x6c, 0x06, 0x83, 0x4c, 0x6e, 0xfe, 0xd6, 0xa5, 0x93, 0x7b, + 0x32, 0xef, 0x02, 0x2b, 0xdc, 0x30, 0xfd, 0x95, 0xe1, 0x84, 0xfc, 0xad, 0x63, 0x29, 0xbb, 0x73, + 0x96, 0x81, 0xb6, 0x47, 0x1e, 0x74, 0x19, 0x20, 0xfe, 0xc2, 0x2f, 0x81, 0x12, 0x4c, 0x37, 0x7d, + 0xbb, 0x5e, 0x48, 0x5b, 0xce, 0x91, 0xc1, 0xe5, 0xe7, 0x75, 0x07, 0x8a, 0xe9, 0xbf, 0x1d, 0xdf, + 0x16, 0xe6, 0x8e, 0xbc, 0x70, 0x4e, 0xc6, 0x39, 0x1e, 0x72, 0xbf, 0x78, 0x1b, 0x4f, 0xb7, 0x97, + 0x90, 0x73, 0xf1, 0x56, 0x93, 0xde, 0x26, 0x1a, 0xc0, 0xb9, 0x13, 0x41, 0x4c, 0xec, 0xaa, 0x17, + 0x51, 0xe6, 0xba, 0x17, 0x33, 0x86, 0x92, 0xe2, 0x2a, 0xc6, 0x71, 0x3a, 0x88, 0xe7, 0x26, 0x57, + 0xd8, 0xcf, 0x2e, 0xcb, 0x0f, 0xce, 0x72, 0x3f, 0xb7, 0x1d, 0x27, 0xbd, 0x87, 0x52, 0xa9, 0xf7, + 0x1c, 0xf1, 0xa8, 0xe2, 0xe9, 0xbc, 0xd8, 0xe7, 0x2a, 0x6a, 0xb6, 0x4b, 0x77, 0xd9, 0xac, 0xfa, + 0xbc, 0xb6, 0x6a, 0xf9, 0x16, 0xb8, 0x4d, 0xd3, 0xef, 0x9d, 0xc8, 0x22, 0xa3, 0x15, 0x14, 0x62, + 0xc3, 0xa1, 0xef, 0x9c, 0xd0, 0xc8, 0xc5, 0x58, 0x48, 0x05, 0x4c, 0xeb, 0x43, 0x1b, 0xdf, 0xf4, + 0x57, 0xbf, 0xe9, 0x90, 0x51, 0x09, 0x75, 0x4d, 0x67, 0xcd, 0x97, 0x33, 0x2e, 0xa2, 0x90, 0xd9, + 0xa9, 0x26, 0x50, 0x01, 0xa0, 0xf1, 0x30, 0x87, 0x6b, 0x8e, 0x94, 0xb2, 0xf0, 0xe4, 0x8e, 0xd3, + 0x4f, 0x77, 0x6a, 0xa1, 0x95, 0x38, 0x7b, 0x90, 0xb0, 0x69, 0xbf, 0x4b, 0xe8, 0x79, 0x40, 0x3f, + 0x44, 0x22, 0x16, 0x79, 0xb3, 0x46, 0x99, 0x13, 0xa6, 0xe7, 0xb3, 0x56, 0xf2, 0xb0, 0xa9, 0x2c, + 0xe0, 0xe2, 0x24, 0xaa, 0x6d, 0xd8, 0x15, 0x2b, 0x2b, 0x44, 0x6d, 0x16, 0x1b, 0xa5, 0xec, 0x3b, + 0xb7, 0x75, 0xa7, 0x86, 0x92, 0x2d, 0xb4, 0xab, 0x09, 0xeb, 0xdc, 0x3f, 0x21, 0xc5, 0x65, 0x22, + 0xb6, 0x9d, 0x58, 0xe1, 0x4c, 0x7f, 0x53, 0xdd, 0xa6, 0x63, 0xfa, 0x83, 0x69, 0x2a, 0xed, 0xd1, + 0xf9, 0x5f, 0x11, 0x2e, 0xbb, 0xfa, 0x66, 0x96, 0x57, 0x6e, 0xd0, 0x2d, 0xee, 0xc1, 0xfa, 0xfe, + 0xdc, 0xdc, 0xc1, 0xbb, 0xb7, 0x9c, 0x18, 0x5f, 0xdc, 0x92, 0x44, 0xcf, 0x47, 0x17, 0x5f, 0x00, + 0xa2, 0x73, 0x01, 0xc8, 0x6e, 0xba, 0x56, 0xd6, 0x95, 0xe7, 0xaa, 0xc3, 0x06, 0x4d, 0x1d, 0x48, + 0xad, 0xef, 0x6e, 0x8e, 0xcd, 0x35, 0xc2, 0x18, 0x04, 0x25, 0xae, 0x1e, 0xa3, 0x2f, 0x77, 0x75, + 0xd6, 0x79, 0x86, 0x70, 0x88, 0xc9, 0x28, 0x0b, 0x5b, 0x4a, 0xae, 0x88, 0x8c, 0x50, 0x0c, 0xa2, + 0xab, 0x01, 0xad, 0xed, 0x3b, 0x65, 0xaa, 0xc1, 0xbd, 0x7e, 0x5d, 0xc7, 0x36, 0x48, 0x48, 0x9c, + 0xde, 0xf0, 0xca, 0x9f, 0x95, 0x5e, 0xb0, 0xce, 0x55, 0x89, 0x09, 0x78, 0x65, 0x05, 0xda, 0xac, + 0xcf, 0x4f, 0x04, 0x1b, 0x38, 0x0b, 0xb8, 0x06, 0xf7, 0xf9, 0x98, 0xf0, 0xaa, 0xae, 0x12, 0xd4, + 0x36, 0x12, 0x4b, 0x98, 0xc0, 0x9e, 0x4c, 0xd7, 0x25, 0x96, 0x66, 0x43, 0xd0, 0x1a, 0x30, 0x29, + 0x16, 0x57, 0xaa, 0xfb, 0x49, 0x25, 0xbc, 0xb9, 0x60, 0x15, 0xa2, 0x81, 0xf4, 0xb8, 0xed, 0x2a, + 0x4d, 0xfa, 0x2d, 0x5b, 0x67, 0xe5, 0x3a, 0x9c, 0x33, 0x34, 0xe5, 0x82, 0xe2, 0xe8, 0x02, 0x2a, + 0xc5, 0x64, 0x75, 0x9e, 0x39, 0x14, 0xc8, 0xd4, 0x27, 0x4d, 0x4d, 0x9d, 0x2f, 0xbe, 0x8f, 0xdd, + 0x0d, 0xbe, 0x60, 0x81, 0x81, 0x68, 0x0a, 0xba, 0x7f, 0x4c, 0x57, 0x5d, 0xd3, 0x66, 0xcc, 0x20, + 0xa8, 0xe0, 0x93, 0xb1, 0x5d, 0x94, 0x56, 0xb0, 0x2f, 0x8d, 0x09, 0x6e, 0xe1, 0x5b, 0x00, 0x7b, + 0x31, 0x94, 0x4c, 0x07, 0xb5, 0x95, 0x72, 0xe0, 0xaa, 0xf3, 0xf9, 0xb1, 0x32, 0xec, 0x0b, 0x5a, + 0x29, 0x08, 0xc9, 0x46, 0x82, 0xdf, 0x59, 0xcb, 0x16, 0x8b, 0xe4, 0x93, 0x89, 0xef, 0x4c, 0xf0, + 0x59, 0xfa, 0x56, 0xe7, 0xb8, 0x0e, 0x3c, 0xd6, 0xd3, 0x9f, 0x63, 0x0a, 0x6b, 0xf3, 0x52, 0x66, + 0xab, 0xe3, 0x25, 0x81, 0xa5, 0x96, 0x14, 0x18, 0xe0, 0x5f, 0xef, 0x7b, 0x98, 0xac, 0x7f, 0x30, + 0x3d, 0x17, 0xdd, 0x29, 0xff, 0xab, 0x97, 0x3f, 0x78, 0xd8, 0x67, 0xf6, 0xe5, 0xd1, 0xca, 0x85, + 0x74, 0xdd, 0x76, 0xc1, 0x13, 0xb0, 0x5d, 0xa9, 0xa4, 0x74, 0xed, 0x71, 0x8e, 0xf5, 0x50, 0xdc, + 0xa8, 0x5e, 0xf2, 0x1f, 0x6e, 0x5a, 0xf3, 0xb6, 0xcc, 0x69, 0x8f, 0x79, 0x5a, 0x8e, 0xd4, 0x2d, + 0xaa, 0x89, 0x76, 0xdf, 0x2c, 0x12, 0x94, 0xbc, 0x20, 0xb7, 0x29, 0x1e, 0x6c, 0xd6, 0xb9, 0x43, + 0x75, 0x22, 0x3b, 0xf0, 0xaf, 0xb5, 0x3e, 0x27, 0x03, 0xa3, 0xa4, 0x4e, 0xdb, 0x08, 0x69, 0xf4, + 0xaa, 0x13, 0xaf, 0x72, 0x5c, 0x28, 0xd3, 0xb1, 0x28, 0x86, 0xe3, 0x9c, 0x9a, 0xb6, 0x41, 0x64, + 0xb5, 0x53, 0x55, 0xe8, 0xf9, 0x27, 0x10, 0xb9, 0x9e, 0xc1, 0x26, 0x01, 0x32, 0x38, 0x97, 0x7f, + 0xf1, 0xc8, 0x45, 0x02, 0xe7, 0xd2, 0x6d, 0xef, 0xe0, 0xe5, 0xe5, 0x22, 0x67, 0x12, 0xd5, 0x2d, + 0x8b, 0xce, 0xb3, 0x57, 0x1b, 0x44, 0x4a, 0x98, 0x99, 0x47, 0x8f, 0xb1, 0xd5, 0x51, 0x3a, 0x05, + 0x33, 0x33, 0x4c, 0x73, 0xe3, 0x47, 0x76, 0x4c, 0x4a, 0xb6, 0x36, 0x73, 0x3a, 0xb7, 0xdf, 0x62, + 0x0d, 0x63, 0xf1, 0xf6, 0xc8, 0x7e, 0x6f, 0xff, 0x5a, 0x22, 0xd7, 0x7c, 0xdd, 0x53, 0x43, 0xbb, + 0xbb, 0xd0, 0xac, 0x10, 0xb1, 0x61, 0x38, 0x46, 0xde, 0xbc, 0xe4, 0x44, 0x26, 0x05, 0x0a, 0xee, + 0xb8, 0x93, 0xf8, 0xbd, 0x09, 0x36, 0x23, 0xa9, 0x7e, 0x53, 0xc4, 0x8e, 0x9e, 0x9e, 0x2e, 0x33, + 0x50, 0x28, 0xd0, 0x0c, 0xa5, 0x06, 0xd0, 0x4a, 0x32, 0xc4, 0x97, 0x58, 0x25, 0x8b, 0xed, 0xb4, + 0xa2, 0xb6, 0x08, 0xd9, 0x5e, 0x8e, 0x73, 0xc2, 0xd2, 0x1d, 0x8a, 0xe9, 0x92, 0x63, 0x16, 0x04, + 0x5f, 0x79, 0xc1, 0x17, 0xde, 0x23, 0x3e, 0xa7, 0x6d, 0xbd, 0x12, 0xef, 0xcb, 0x66, 0x47, 0xa0, + 0xc9, 0x55, 0xd9, 0x15, 0x34, 0xd5, 0x6e, 0x29, 0xdd, 0x8f, 0x82, 0x81, 0x84, 0xb8, 0x94, 0x2e, + 0x57, 0x5e, 0xc5, 0xdb, 0xcd, 0x8b, 0xf7, 0x56, 0x3f, 0xac, 0xe3, 0x40, 0xf2, 0xfc, 0x37, 0x75, + 0x84, 0x44, 0x7f, 0x30, 0xcd, 0xb2, 0xfa, 0x8f, 0x88, 0x3a, 0x7b, 0x22, 0x20, 0xd2, 0x8d, 0xed, + 0xbb, 0x41, 0x33, 0xc2, 0xe9, 0x5e, 0xa1, 0x3a, 0xdb, 0x3a, 0xbd, 0x60, 0xde, 0x75, 0x87, 0xec, + 0x2c, 0x36, 0x38, 0xbe, 0x8d, 0xea, 0xb4, 0xb5, 0x7a, 0xaf, 0x80, 0x13, 0x17, 0xa7, 0x86, 0x81, + 0xe4, 0x95, 0x31, 0xd0, 0x2c, 0x32, 0xac, 0xbc, 0xa0, 0xa9, 0x85, 0x1a, 0x5e, 0xc8, 0x49, 0x64, + 0xb2, 0xd9, 0x0d, 0x73, 0xb5, 0x65, 0x6b, 0xbc, 0x95, 0xc4, 0xa6, 0x9d, 0xb9, 0xc7, 0xe6, 0xdf, + 0x9d, 0x14, 0xb7, 0xbc, 0x94, 0xcf, 0x73, 0xef, 0x17, 0x64, 0xb8, 0xac, 0xea, 0x4a, 0x71, 0x07, + 0x32, 0xea, 0x6d, 0xff, 0xd1, 0xdd, 0x3a, 0x2e, 0x55, 0x5c, 0xa8, 0x4d, 0x63, 0xd7, 0xdd, 0x24, + 0x09, 0xbb, 0xb6, 0xc3, 0x35, 0x87, 0x9a, 0xd6, 0xb4, 0x52, 0x05, 0xc5, 0x3b, 0x66, 0xbb, 0x40, + 0x4d, 0x35, 0x97, 0x15, 0xa1, 0x1c, 0x8b, 0xb8, 0xc6, 0xf9, 0x19, 0x0f, 0xe1, 0x0e, 0x41, 0xa2, + 0x68, 0x07, 0xe5, 0x73, 0xae, 0x25, 0xe3, 0x67, 0x42, 0x31, 0xb4, 0xf1, 0x8c, 0xc4, 0xb5, 0xf4, + 0x6d, 0x4f, 0x10, 0xec, 0x88, 0x0f, 0xae, 0x32, 0xbd, 0x66, 0xd4, 0x2f, 0x09, 0xe9, 0x38, 0x48, + 0x65, 0x3c, 0x94, 0xb9, 0xe1, 0x51, 0xfd, 0xdb, 0x2d, 0x29, 0x61, 0x40, 0x03, 0x77, 0x28, 0x96, + 0x17, 0x1f, 0x29, 0x42, 0xe9, 0x28, 0x19, 0xaa, 0xab, 0x42, 0xb6, 0x8b, 0xf4, 0xde, 0xc6, 0x18, + 0xc9, 0x70, 0x24, 0x9a, 0xaf, 0x4a, 0xc7, 0x78, 0x66, 0x61, 0x05, 0xaa, 0x3c, 0x2f, 0x09, 0xa0, + 0x57, 0xe9, 0x16, 0x33, 0x7d, 0x97, 0x4c, 0xd9, 0x4b, 0x86, 0xce, 0x75, 0x74, 0x40, 0x30, 0xeb, + 0xf6, 0xda, 0x51, 0x3b, 0xa9, 0x84, 0x7e, 0xfc, 0x1c, 0xb7, 0x4a, 0x12, 0x7b, 0x6b, 0xe2, 0x54, + 0x83, 0x64, 0xe1, 0xb1, 0xe5, 0xbf, 0x5c, 0xfd, 0x6e, 0x7b, 0x0e, 0x09, 0xa0, 0xab, 0x46, 0xdc, + 0x76, 0x81, 0x90, 0xc7, 0xd3, 0xe4, 0x29, 0x75, 0xab, 0xad, 0x69, 0xec, 0x8f, 0x9b, 0xed, 0xf8, + 0x6f, 0x6a, 0xae, 0xa0, 0x7f, 0x30, 0xcd, 0x95, 0x7a, 0x83, 0xcd, 0x08, 0xdf, 0xe9, 0x08, 0xce, + 0xf3, 0x05, 0xcd, 0xf7, 0x06, 0x8c, 0x1e, 0x23, 0x74, 0xac, 0x15, 0x0a, 0x59, 0x41, 0x60, 0x20, + 0xbb, 0xcc, 0x3d, 0x28, 0x16, 0xb9, 0x32, 0x81, 0x46, 0x3c, 0x66, 0xe5, 0x22, 0x24, 0x8d, 0x9d, + 0x96, 0x58, 0xaf, 0x51, 0x7b, 0x67, 0x03, 0xcf, 0xb3, 0x5d, 0x4f, 0x61, 0x95, 0x9e, 0x74, 0xe1, + 0x7d, 0xb1, 0x90, 0xb0, 0x8e, 0xf4, 0xb0, 0xaa, 0xcf, 0x3b, 0x70, 0x1d, 0x5e, 0xaa, 0xde, 0x97, + 0x9c, 0xf1, 0xcc, 0x50, 0x3e, 0xcd, 0xd2, 0xf5, 0x4e, 0xca, 0x22, 0xb0, 0x2b, 0x0c, 0x86, 0x49, + 0xee, 0x5a, 0x44, 0x9a, 0xbe, 0x3f, 0xe9, 0x51, 0xf5, 0xc9, 0x93, 0xda, 0x6c, 0xd6, 0xa2, 0x0e, + 0x31, 0x26, 0xe9, 0x4a, 0x08, 0x67, 0xcb, 0x0e, 0xa7, 0x75, 0x1b, 0x46, 0xc2, 0x13, 0xa9, 0xe0, + 0xb0, 0x45, 0x2c, 0xaf, 0xc1, 0xcc, 0x39, 0x8b, 0xef, 0xfe, 0xae, 0x37, 0x74, 0xf9, 0x4d, 0x3c, + 0x0b, 0xd6, 0xaa, 0x12, 0xf8, 0x35, 0x9c, 0xce, 0xca, 0x45, 0xc2, 0x10, 0x5b, 0x75, 0x76, 0x82, + 0x30, 0x24, 0xa2, 0x0a, 0xbc, 0x49, 0x08, 0xe4, 0x08, 0x8f, 0x10, 0xb9, 0x9e, 0xe7, 0xd8, 0x77, + 0x9d, 0x16, 0xcb, 0x20, 0x38, 0x92, 0x4a, 0x75, 0x64, 0xd5, 0x5b, 0xe3, 0x7c, 0xab, 0x1d, 0xa3, + 0xb3, 0x17, 0x07, 0x67, 0xd8, 0x4f, 0x4e, 0x05, 0x67, 0x7d, 0x96, 0x81, 0x81, 0xe2, 0x4f, 0x2e, + 0xae, 0x13, 0x81, 0x32, 0x80, 0x18, 0x63, 0x3c, 0xdd, 0xcd, 0x70, 0xe2, 0x78, 0x7a, 0x66, 0xd0, + 0x1d, 0x63, 0xea, 0x32, 0x9f, 0x7d, 0xf8, 0xaa, 0x34, 0x57, 0x10, 0x35, 0x49, 0x13, 0x0b, 0x7c, + 0x83, 0xdd, 0x3b, 0xb8, 0x8a, 0xce, 0x5d, 0x04, 0x69, 0xc5, 0x07, 0x48, 0x18, 0xc8, 0x71, 0x54, + 0x4e, 0xb5, 0xd9, 0x66, 0x00, 0x7e, 0xbe, 0xe8, 0x4e, 0xdf, 0x48, 0x29, 0xd9, 0x7e, 0xf2, 0x0f, + 0x5f, 0x48, 0x07, 0x82, 0x2c, 0x01, 0x41, 0x02, 0x1b, 0x93, 0x63, 0x6d, 0x88, 0x25, 0xf7, 0x22, + 0xbf, 0xd6, 0x11, 0xc2, 0xff, 0x60, 0x7a, 0x19, 0x05, 0x4f, 0x83, 0xc7, 0x12, 0xc2, 0xd5, 0x2b, + 0xcc, 0xf7, 0xc5, 0x11, 0xb5, 0x7e, 0xdc, 0x20, 0x3f, 0x95, 0x8c, 0xe9, 0xab, 0x67, 0x91, 0x5a, + 0xe8, 0xe1, 0x35, 0x2b, 0xad, 0x4f, 0x69, 0x08, 0x5c, 0x57, 0xab, 0xf2, 0xef, 0xdf, 0xba, 0x9e, + 0x3f, 0x21, 0x29, 0x0d, 0x81, 0x56, 0xd7, 0xa4, 0x4d, 0x76, 0xe5, 0x95, 0x8b, 0x79, 0xd3, 0x4b, + 0xb2, 0x11, 0x13, 0x45, 0x0f, 0x26, 0x29, 0xe1, 0x55, 0x7f, 0x08, 0x85, 0x81, 0x34, 0xeb, 0xd5, + 0x2e, 0xea, 0x70, 0xab, 0x51, 0x72, 0x38, 0x2f, 0x3b, 0x0b, 0x7e, 0x2a, 0x34, 0x70, 0xe7, 0x41, + 0x02, 0xbb, 0xf3, 0xc6, 0x87, 0x3a, 0xff, 0xa9, 0x87, 0x9a, 0x39, 0x18, 0x5f, 0x5d, 0x2f, 0xb2, + 0xc7, 0x5b, 0x6d, 0x65, 0xf5, 0x36, 0x62, 0x9a, 0xd5, 0x86, 0x98, 0x45, 0x5b, 0xd4, 0x14, 0xe8, + 0xae, 0x64, 0xe4, 0x3f, 0x33, 0x6c, 0xe7, 0xc3, 0x39, 0xc2, 0xce, 0x09, 0xe3, 0x88, 0x54, 0x75, + 0x45, 0xb2, 0xb4, 0xc2, 0xb1, 0x62, 0xe9, 0x3e, 0x5d, 0x4a, 0xe6, 0x34, 0x29, 0xe7, 0x66, 0x48, + 0x59, 0x34, 0x87, 0x5e, 0xee, 0x05, 0x35, 0x0d, 0xbb, 0x2f, 0xb6, 0xc0, 0x5c, 0x65, 0x13, 0x3b, + 0x1b, 0x5b, 0x60, 0x03, 0xb5, 0xa8, 0xb6, 0x1d, 0xfe, 0xc8, 0xe4, 0x84, 0xe3, 0xcc, 0xa0, 0x0e, + 0xfa, 0x06, 0x5d, 0x81, 0xe6, 0xf5, 0x3b, 0xa7, 0x85, 0x0d, 0x10, 0x91, 0x08, 0x3f, 0x43, 0x50, + 0xae, 0x58, 0x18, 0x42, 0x41, 0x7d, 0x44, 0xb4, 0x40, 0x33, 0x3f, 0x8e, 0x6a, 0xdc, 0xa1, 0x0e, + 0xa2, 0x8b, 0xcb, 0x04, 0x9d, 0xcc, 0x0b, 0xa3, 0x1e, 0xa8, 0xe6, 0xa8, 0x20, 0x9c, 0xdd, 0x35, + 0x8f, 0x29, 0x41, 0xd7, 0x97, 0xde, 0x35, 0x72, 0x2a, 0x3f, 0x93, 0x04, 0x80, 0x07, 0xd5, 0x02, + 0xc0, 0xd5, 0xaf, 0xa2, 0x80, 0x0b, 0xa6, 0x62, 0xb1, 0x53, 0x15, 0x49, 0x13, 0x54, 0x3b, 0x54, + 0x29, 0x18, 0x18, 0x60, 0xfc, 0x6f, 0x2e, 0x82, 0x2a, 0x70, 0x84, 0x3a, 0x6c, 0xde, 0x5a, 0xf0, + 0xd7, 0x3e, 0x4d, 0x64, 0xff, 0x60, 0x7a, 0x35, 0x37, 0x26, 0xbf, 0x2f, 0xf2, 0x81, 0x93, 0x63, + 0x2c, 0x07, 0x9c, 0x05, 0xe9, 0xec, 0xe2, 0x15, 0x42, 0xcb, 0xd8, 0x1c, 0x88, 0x14, 0x74, 0xba, + 0x89, 0xc6, 0xb3, 0xd1, 0xf5, 0x4c, 0xe5, 0x89, 0x6a, 0x94, 0x31, 0xcf, 0xec, 0x46, 0xa9, 0xb4, + 0x1d, 0x84, 0x3a, 0xcb, 0xde, 0xf3, 0x98, 0x7a, 0xe2, 0xbc, 0x82, 0x9a, 0xd6, 0xcb, 0xc8, 0xbf, + 0x43, 0x34, 0x40, 0x74, 0x9c, 0xdd, 0x13, 0x88, 0x48, 0xa6, 0x1c, 0xdb, 0x52, 0x8c, 0x4a, 0xa0, + 0x84, 0x98, 0xa3, 0x0a, 0xdf, 0x2f, 0x33, 0xc8, 0x0e, 0x11, 0x05, 0x17, 0x76, 0xa5, 0x5b, 0x6f, + 0x5c, 0x92, 0x50, 0x8a, 0xb0, 0x93, 0xfa, 0x82, 0x5e, 0x2e, 0x26, 0xd9, 0x44, 0xe5, 0xd5, 0xb3, + 0x18, 0xba, 0x38, 0x39, 0x29, 0x8a, 0xd9, 0xe5, 0x95, 0x78, 0x0e, 0x57, 0x79, 0x66, 0x79, 0xfe, + 0x09, 0x89, 0x28, 0xdf, 0x17, 0xa8, 0x09, 0x5e, 0xa9, 0x3a, 0x64, 0xd9, 0x04, 0x76, 0xa9, 0x94, + 0x5d, 0x39, 0x49, 0x17, 0x25, 0x12, 0xf1, 0xfe, 0xb2, 0xb4, 0x92, 0xae, 0xbc, 0xf0, 0x4a, 0x9e, + 0x60, 0x8f, 0x1f, 0x11, 0x68, 0xe3, 0x3a, 0x63, 0xa5, 0x43, 0x82, 0xa3, 0x8d, 0x54, 0x8d, 0xe7, + 0x39, 0x1b, 0xae, 0xf2, 0x24, 0x2e, 0x04, 0xfa, 0xdc, 0x6c, 0x24, 0x18, 0xdc, 0xa8, 0xb0, 0xc5, + 0xa4, 0xc6, 0xc6, 0x8a, 0x01, 0x1f, 0x54, 0x77, 0xda, 0xd1, 0x43, 0x0b, 0x43, 0xaa, 0x2c, 0x5f, + 0x1d, 0x17, 0x55, 0xdf, 0xc8, 0xd1, 0x33, 0x13, 0x70, 0x22, 0x74, 0xde, 0x37, 0xd7, 0x35, 0xbb, + 0x07, 0x3b, 0x5c, 0xc8, 0x1b, 0x58, 0xbb, 0xa0, 0x9b, 0xd6, 0x5e, 0x61, 0x6d, 0x2f, 0x7d, 0x15, + 0x31, 0x01, 0x11, 0xef, 0x72, 0x86, 0x13, 0x3f, 0xbb, 0xeb, 0x43, 0xe4, 0x0d, 0x7a, 0x91, 0x6f, + 0xbf, 0xd2, 0x67, 0x24, 0xe5, 0xd3, 0xc8, 0xb2, 0x4e, 0x07, 0xed, 0xcb, 0x38, 0x12, 0xff, 0x72, + 0x24, 0x6d, 0x0b, 0x27, 0x28, 0x0b, 0xc6, 0x51, 0xbd, 0x5f, 0x7c, 0x78, 0x0d, 0x74, 0x05, 0x6e, + 0x0b, 0xf2, 0x6b, 0x1d, 0xa1, 0xc2, 0x1f, 0x4c, 0xcb, 0x42, 0xbe, 0xf1, 0xc6, 0x80, 0x55, 0xb4, + 0xef, 0xa4, 0xdf, 0xec, 0x07, 0xe8, 0xd7, 0x79, 0x9e, 0x6e, 0xe7, 0x45, 0x0c, 0x90, 0x21, 0x2a, + 0x50, 0x26, 0x17, 0xc7, 0xf6, 0xea, 0x84, 0x94, 0xd0, 0x9f, 0x5a, 0xb0, 0xa5, 0xc5, 0x26, 0x3e, + 0x8d, 0x95, 0x6e, 0xef, 0xb0, 0xc8, 0x3a, 0x3d, 0x20, 0x4c, 0x85, 0x82, 0x02, 0x46, 0x75, 0xdc, + 0x87, 0xc8, 0x26, 0xe8, 0x3e, 0x0e, 0x23, 0x6c, 0x67, 0xab, 0xb7, 0xa5, 0x02, 0x62, 0xc1, 0xa4, + 0x34, 0x27, 0x0c, 0xaa, 0x62, 0x25, 0xf9, 0xfe, 0x02, 0xcf, 0xbd, 0x46, 0xca, 0xa5, 0x50, 0x4a, + 0x63, 0x02, 0xdc, 0x0d, 0x84, 0x55, 0xe2, 0x8a, 0x47, 0x7d, 0xde, 0x3a, 0xa1, 0xa0, 0x02, 0x23, + 0x27, 0x4c, 0x49, 0x1e, 0x84, 0xfd, 0xc5, 0x53, 0xc0, 0x15, 0xeb, 0xff, 0x24, 0xdf, 0xac, 0x2a, + 0x15, 0x70, 0x8a, 0x16, 0xd8, 0x02, 0xd8, 0xaa, 0x99, 0xe3, 0x08, 0xc9, 0xf4, 0x03, 0xa9, 0x70, + 0x4d, 0xe5, 0x6e, 0x67, 0x0b, 0x03, 0x1d, 0xe1, 0x37, 0x94, 0xad, 0x79, 0xb4, 0x53, 0xd9, 0x86, + 0xc9, 0x28, 0x15, 0xce, 0xbf, 0xee, 0x7f, 0x52, 0x01, 0xd1, 0x61, 0x02, 0x03, 0x42, 0x17, 0x0c, + 0xe6, 0x81, 0xeb, 0x38, 0x0d, 0x55, 0xdd, 0x7e, 0x45, 0xc4, 0x1f, 0xa8, 0xf1, 0x53, 0x27, 0x47, + 0x47, 0x3c, 0x10, 0x78, 0x89, 0x5d, 0x53, 0xb9, 0x8e, 0x7d, 0x34, 0xab, 0x7a, 0x78, 0x3e, 0xc6, + 0x4a, 0xd3, 0x65, 0x04, 0xf4, 0x20, 0xbb, 0xec, 0xb4, 0xf9, 0x35, 0x14, 0xb6, 0x94, 0xa3, 0x09, + 0xb5, 0xbd, 0x90, 0xba, 0x4b, 0x82, 0x0d, 0xdc, 0x3b, 0x0b, 0xc6, 0xc8, 0x6d, 0x62, 0xcf, 0x1d, + 0x0b, 0x25, 0x35, 0xe6, 0x0e, 0x22, 0x5b, 0xc2, 0x91, 0x88, 0x4d, 0x7c, 0xaa, 0xc0, 0xef, 0x67, + 0x77, 0x8d, 0x3f, 0x89, 0xba, 0xc4, 0xd6, 0x99, 0xd1, 0x4f, 0xfd, 0xcc, 0x7c, 0x18, 0xdc, 0xfe, + 0x19, 0xd3, 0x89, 0x5f, 0xea, 0xa9, 0xac, 0xdb, 0x9b, 0xbe, 0x55, 0x66, 0x74, 0xd6, 0xf4, 0xe0, + 0xbc, 0xf9, 0xab, 0x69, 0x32, 0xf1, 0x07, 0xd3, 0xd0, 0x2a, 0xf8, 0x74, 0xad, 0xba, 0x2c, 0xbb, + 0x6f, 0x9e, 0x81, 0x18, 0x7c, 0x33, 0x32, 0xf9, 0x52, 0x7f, 0xc5, 0xea, 0x06, 0x3b, 0x51, 0x58, + 0xb0, 0xd5, 0x4c, 0x91, 0x1c, 0x1e, 0x6d, 0x67, 0x35, 0x6b, 0xa5, 0x37, 0xb3, 0x41, 0x45, 0xc4, + 0x79, 0x83, 0x35, 0x67, 0x8b, 0x30, 0x8c, 0x52, 0x5e, 0x73, 0x51, 0xf8, 0xa3, 0x55, 0xa7, 0xa6, + 0xe3, 0x3b, 0xdd, 0x28, 0x5f, 0x9c, 0x96, 0xbe, 0xea, 0xb7, 0xc9, 0xfc, 0xac, 0xed, 0xa0, 0xd3, + 0x5d, 0x79, 0x28, 0x55, 0x47, 0x4d, 0xef, 0x43, 0x4b, 0xb9, 0x58, 0x2e, 0x37, 0xd0, 0xc4, 0xc3, + 0xf1, 0x55, 0x61, 0xc5, 0x30, 0xdd, 0x8f, 0x0d, 0x44, 0x63, 0x8a, 0x6c, 0xc1, 0xe0, 0x22, 0xee, + 0x4b, 0xbe, 0x1a, 0xbc, 0xb5, 0xbc, 0x36, 0x9d, 0x9b, 0xcb, 0x91, 0xa7, 0x26, 0x55, 0xf6, 0xdb, + 0x8b, 0x77, 0x4e, 0x69, 0x3c, 0x5a, 0x1e, 0x6a, 0x9f, 0xe2, 0x12, 0x8a, 0x86, 0xab, 0xf8, 0xd4, + 0x53, 0xd9, 0x22, 0xc4, 0xa5, 0x55, 0xb5, 0x89, 0xce, 0xd0, 0x6c, 0xf1, 0xd6, 0x27, 0xdb, 0xdd, + 0x08, 0xb9, 0xdc, 0xad, 0x4a, 0xf6, 0x65, 0x39, 0x0f, 0x34, 0x73, 0x29, 0x91, 0x2b, 0x74, 0xcb, + 0xe4, 0xda, 0xe3, 0x7e, 0x8b, 0x3f, 0xf1, 0x1d, 0x37, 0x5e, 0xf5, 0x95, 0x24, 0xc6, 0xe3, 0x42, + 0x4c, 0xd4, 0x7a, 0xed, 0x35, 0x75, 0x77, 0x8b, 0xaf, 0xbe, 0x63, 0xb6, 0xe0, 0xc6, 0x17, 0x33, + 0x00, 0xa4, 0x31, 0xb8, 0x22, 0x3f, 0xe9, 0xf0, 0x57, 0xdf, 0xdb, 0xb6, 0xf0, 0xb9, 0xe2, 0x6d, + 0x7e, 0x7d, 0x8f, 0x89, 0x87, 0x6a, 0xeb, 0x76, 0xcd, 0x17, 0xac, 0x3d, 0x1e, 0xf5, 0xa4, 0x4b, + 0x87, 0x41, 0xf8, 0x78, 0x4f, 0x3b, 0x39, 0x8c, 0x87, 0x78, 0x40, 0x8b, 0xc5, 0xd3, 0x85, 0xd3, + 0x5b, 0xd8, 0xfa, 0xda, 0x70, 0xac, 0x8c, 0x7b, 0xe3, 0x4c, 0x7c, 0xc7, 0x29, 0x4b, 0xe0, 0x36, + 0x02, 0x57, 0xd3, 0xe4, 0xe5, 0x64, 0xa3, 0x94, 0xeb, 0x5c, 0x5b, 0x4e, 0x65, 0xe4, 0x77, 0xb0, + 0xf4, 0x2d, 0x2d, 0xea, 0x67, 0x33, 0xdb, 0xe3, 0xff, 0x7b, 0xd5, 0x6d, 0x44, 0x30, 0xf5, 0x0f, + 0x6d, 0x38, 0x93, 0xe1, 0x1c, 0x59, 0xb9, 0x75, 0xed, 0x59, 0x00, 0x91, 0xe7, 0xc8, 0x6a, 0xb0, + 0x09, 0xdf, 0xa1, 0xfc, 0x45, 0x41, 0xb2, 0x7b, 0xcb, 0x26, 0xae, 0xba, 0x4b, 0xc0, 0x9e, 0x93, + 0xd1, 0x9b, 0x4d, 0x9e, 0x93, 0x59, 0xa5, 0xdb, 0x73, 0xcd, 0xf8, 0xe2, 0x3c, 0x85, 0xbf, 0x86, + 0x2f, 0x4d, 0x56, 0xea, 0x6c, 0x0e, 0xde, 0x9a, 0x01, 0x39, 0xeb, 0x73, 0x62, 0xc0, 0x38, 0x9c, + 0x99, 0x59, 0x2e, 0xde, 0x20, 0xc5, 0xec, 0x37, 0x77, 0x90, 0xab, 0xab, 0xdc, 0xed, 0x2b, 0x44, + 0x97, 0xba, 0x15, 0x69, 0xcb, 0xb2, 0x8e, 0xd2, 0xad, 0xed, 0xed, 0xfd, 0x55, 0x81, 0xdb, 0x70, + 0x35, 0x12, 0x18, 0x6e, 0xf7, 0x33, 0xbc, 0x4b, 0x53, 0x93, 0x35, 0x02, 0x84, 0x84, 0x48, 0x8c, + 0x29, 0xfe, 0x9e, 0xe6, 0x5c, 0xf1, 0x83, 0x9e, 0xea, 0x61, 0x02, 0xcf, 0x01, 0x51, 0x9b, 0x97, + 0xec, 0xab, 0x45, 0xc6, 0x69, 0x9c, 0xed, 0x78, 0x1e, 0xc8, 0x4c, 0xf2, 0x36, 0x22, 0xb8, 0x74, + 0xa5, 0xaf, 0x55, 0x7d, 0x1c, 0x09, 0x2e, 0x0b, 0x44, 0x9a, 0xb1, 0xe0, 0xbc, 0x9a, 0x6a, 0x44, + 0xf4, 0x92, 0xba, 0xe6, 0x73, 0x53, 0xf4, 0xfe, 0xc9, 0x87, 0xed, 0xe9, 0x1c, 0xd5, 0xf5, 0x03, + 0x99, 0xc5, 0x44, 0xf1, 0xfd, 0x5e, 0xe9, 0xac, 0x15, 0xc4, 0x53, 0xae, 0x6e, 0x6d, 0xcc, 0x11, + 0x78, 0xcf, 0x73, 0x96, 0xa4, 0x11, 0x07, 0x31, 0xc8, 0x79, 0xd5, 0x16, 0xe7, 0x3d, 0xb5, 0xbe, + 0x98, 0xb7, 0xb9, 0xbf, 0x24, 0xf2, 0x0a, 0xbb, 0x72, 0xa5, 0xab, 0x96, 0xa6, 0xaf, 0x24, 0x31, + 0xb4, 0x13, 0xfd, 0xa7, 0xf4, 0xcc, 0x9d, 0x0f, 0x05, 0xba, 0x9f, 0x20, 0xe7, 0x63, 0x65, 0xc4, + 0x56, 0x39, 0xbb, 0x20, 0x7b, 0x3d, 0xb4, 0x1f, 0xa7, 0x7f, 0x7b, 0x19, 0xd4, 0x56, 0xd8, 0x8a, + 0xf9, 0x98, 0xd6, 0x1b, 0xb8, 0x0b, 0x3f, 0xea, 0x2d, 0xf3, 0xc5, 0xe8, 0xda, 0xd3, 0x68, 0x0a, + 0x25, 0x11, 0xcd, 0x14, 0xca, 0xdd, 0x07, 0xc1, 0x17, 0x00, 0x21, 0x37, 0x79, 0xfd, 0xd7, 0x5f, + 0xef, 0x5d, 0xc1, 0x8c, 0x3f, 0x98, 0xde, 0xd4, 0x8b, 0xb7, 0x16, 0x68, 0x7c, 0xef, 0x09, 0xda, + 0xb5, 0xfb, 0x35, 0xa3, 0xeb, 0x54, 0x5b, 0x15, 0x64, 0xca, 0xbe, 0x55, 0x3b, 0x14, 0xb1, 0x00, + 0xa6, 0x88, 0x68, 0x3c, 0x61, 0xcb, 0xfc, 0xb3, 0x98, 0x82, 0x51, 0x89, 0x58, 0x48, 0xd2, 0x69, + 0x6b, 0xa4, 0x97, 0x6c, 0x3d, 0x00, 0x7e, 0x25, 0xf5, 0xe1, 0x7c, 0x44, 0x16, 0x89, 0xd0, 0xdf, + 0xc3, 0x96, 0xd0, 0x11, 0x47, 0xf3, 0xa2, 0x34, 0x42, 0x01, 0xc1, 0x3b, 0x22, 0x21, 0x62, 0xb7, + 0xc7, 0x59, 0x96, 0xfe, 0x0a, 0x59, 0x7d, 0x04, 0x37, 0x88, 0xe1, 0xbd, 0xbd, 0xd6, 0xc1, 0x75, + 0x8e, 0xab, 0x0b, 0xaa, 0xca, 0x55, 0x0b, 0xce, 0xea, 0xd8, 0x95, 0x7a, 0x8f, 0xee, 0x95, 0x0c, + 0x78, 0x75, 0x7d, 0xed, 0x23, 0x3f, 0xf8, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, + 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, + 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0xbf, 0x27, 0xff, 0x79, 0x1e, 0x5c, + 0x21, 0x59, 0x8c, 0x81, 0x6e, 0xe3, 0x72, 0x45, 0xf5, 0x36, 0xa0, 0x96, 0x2e, 0xcd, 0x47, 0xbc, + 0x4b, 0x20, 0x89, 0x82, 0xc0, 0xf9, 0x53, 0xa2, 0x43, 0x38, 0xbc, 0x76, 0x16, 0x59, 0x09, 0xee, + 0x23, 0xf4, 0x24, 0xe9, 0xe7, 0x59, 0x4d, 0x5b, 0xc4, 0xfc, 0x63, 0xc6, 0x8f, 0xd3, 0x8a, 0x7d, + 0xf8, 0xef, 0x26, 0xf6, 0x00, 0x53, 0xe3, 0x73, 0xfa, 0xb1, 0xaf, 0xa8, 0xfc, 0x27, 0xed, 0x7b, + 0xb1, 0xba, 0x5e, 0xef, 0x22, 0x65, 0xee, 0x8f, 0xae, 0x34, 0x7b, 0x6f, 0x6f, 0x20, 0xc0, 0xf5, + 0x4e, 0x6a, 0xc2, 0xf3, 0x76, 0x21, 0x15, 0x47, 0x6c, 0x80, 0x97, 0xc3, 0x86, 0xed, 0x5e, 0x30, + 0xa3, 0x26, 0x11, 0x8c, 0xdb, 0x34, 0x3f, 0x75, 0x56, 0x0e, 0x0d, 0x23, 0x72, 0x35, 0x05, 0xe0, + 0x75, 0xeb, 0xc8, 0x94, 0x1e, 0x03, 0xa7, 0xcd, 0x93, 0xb4, 0x59, 0xd5, 0x5a, 0xc4, 0x75, 0xd7, + 0x96, 0xb3, 0xce, 0x62, 0x46, 0x90, 0xe8, 0xa8, 0x1f, 0xe3, 0x43, 0xb6, 0xde, 0x3e, 0xd4, 0x2c, + 0x0d, 0xfd, 0x9d, 0x93, 0x17, 0x65, 0x58, 0x11, 0xe4, 0xd4, 0x1b, 0x76, 0x61, 0x01, 0x55, 0x4b, + 0x3a, 0x84, 0xf8, 0x02, 0x68, 0xe5, 0xad, 0xc6, 0xae, 0xb7, 0xab, 0xba, 0xf0, 0xa1, 0x0c, 0x54, + 0x66, 0x4a, 0x33, 0x24, 0xa2, 0x9b, 0xde, 0x8a, 0xc1, 0x74, 0x7d, 0xd2, 0xe4, 0xfe, 0xaf, 0x04, + 0x19, 0x73, 0xaf, 0xa5, 0xbc, 0x00, 0x43, 0x59, 0x30, 0xe9, 0x1f, 0x0d, 0x19, 0x0f, 0xc7, 0xae, + 0x10, 0x0b, 0x7b, 0x5c, 0x16, 0xf3, 0x1e, 0x6e, 0x8f, 0x68, 0x22, 0x50, 0xa3, 0x5b, 0xbc, 0x3f, + 0xf1, 0xb5, 0x14, 0x85, 0x27, 0xac, 0x09, 0x55, 0xc5, 0x16, 0x92, 0xd5, 0x93, 0x95, 0xb1, 0x38, + 0xc7, 0x5b, 0xad, 0x66, 0xcb, 0x4d, 0x15, 0x3a, 0x5f, 0xd4, 0x20, 0x68, 0xb8, 0x75, 0x28, 0x0b, + 0x59, 0xa2, 0xb9, 0x26, 0xd1, 0xa9, 0xf3, 0xd4, 0x0a, 0xd6, 0x20, 0xd6, 0x75, 0xbd, 0x86, 0x76, + 0x83, 0x89, 0xe2, 0x73, 0x2c, 0x08, 0x57, 0xb9, 0x03, 0xfb, 0x2f, 0x19, 0x42, 0x92, 0x0e, 0xca, + 0xfd, 0x7d, 0xde, 0x0a, 0xef, 0x85, 0xc4, 0x12, 0xf3, 0x62, 0x20, 0xa2, 0xa4, 0xb2, 0xbe, 0x79, + 0x3a, 0x8b, 0x2a, 0x99, 0x1b, 0x26, 0x38, 0xb2, 0x4a, 0x1f, 0xd1, 0x8b, 0x45, 0xb0, 0x46, 0x26, + 0x81, 0x3b, 0x5c, 0x0b, 0x34, 0x10, 0xa2, 0x80, 0x8c, 0xf4, 0xd5, 0x0d, 0x80, 0x10, 0x56, 0xd7, + 0xdf, 0x2f, 0x5f, 0x54, 0x7e, 0x73, 0xbb, 0x0a, 0x4a, 0x4e, 0xd5, 0x45, 0x58, 0x79, 0x1e, 0x57, + 0xcb, 0x2a, 0x0f, 0x09, 0x09, 0x33, 0x40, 0xfc, 0x8d, 0xea, 0x53, 0xd5, 0x8e, 0x09, 0x02, 0xdd, + 0xc4, 0x52, 0x98, 0x53, 0xdb, 0x68, 0x99, 0xd9, 0x92, 0x8d, 0x9e, 0x54, 0x76, 0xb4, 0x41, 0xa8, + 0x8a, 0xb5, 0x64, 0xf5, 0x61, 0xed, 0x5d, 0xe5, 0xa4, 0xe4, 0x20, 0x0a, 0x34, 0xf8, 0xac, 0x12, + 0x16, 0x97, 0xe0, 0xd6, 0x27, 0xa9, 0x6d, 0x8b, 0x52, 0x14, 0xaf, 0xdd, 0xb8, 0x70, 0x1d, 0xdb, + 0xdd, 0xcc, 0xe6, 0x1c, 0x4f, 0x11, 0xaa, 0xee, 0x9b, 0xbb, 0x92, 0x55, 0xcb, 0x00, 0x62, 0xe5, + 0x8b, 0xeb, 0x10, 0xe5, 0xb0, 0xfd, 0x67, 0xf8, 0x6a, 0xc1, 0xe3, 0x51, 0xb2, 0xcc, 0x8e, 0x12, + 0x81, 0xd0, 0x9c, 0x6e, 0x04, 0xa1, 0xe7, 0x8d, 0x4f, 0x39, 0x8e, 0x33, 0x02, 0x81, 0x7b, 0x45, + 0x63, 0x9c, 0xc8, 0xb9, 0x5f, 0x45, 0xcc, 0xac, 0xdb, 0x98, 0xee, 0x85, 0x74, 0x1b, 0xc8, 0x05, + 0xa7, 0x30, 0xdc, 0x9f, 0xe1, 0x14, 0xc2, 0xee, 0xa2, 0xbc, 0xd4, 0x19, 0x15, 0xf5, 0xa5, 0x66, + 0x3a, 0xa9, 0x2a, 0x4d, 0x13, 0xf6, 0x82, 0xa6, 0xb6, 0x81, 0x35, 0xa3, 0x8e, 0x44, 0x46, 0xaf, + 0xdd, 0xec, 0xa1, 0x02, 0xc1, 0xd6, 0xa7, 0x82, 0xa1, 0xdc, 0x8c, 0x50, 0xe5, 0x65, 0x85, 0xc6, + 0xc6, 0x73, 0x9e, 0x8d, 0xab, 0x1c, 0x79, 0xf4, 0x8d, 0xce, 0x97, 0x04, 0x08, 0xbb, 0x5c, 0x2d, + 0x1e, 0xd6, 0xd5, 0xeb, 0xe2, 0xf4, 0x3c, 0xcf, 0x77, 0x3b, 0x4c, 0x72, 0x54, 0xf7, 0x9d, 0x58, + 0xb1, 0x16, 0x20, 0xc2, 0x6c, 0xe1, 0x03, 0x32, 0x90, 0xb0, 0xc3, 0xbf, 0xec, 0xf1, 0x97, 0x88, + 0xf0, 0xdf, 0x9a, 0x26, 0x49, 0x26, 0x9a, 0x7c, 0xdc, 0x6b, 0x6b, 0xb8, 0x0d, 0xd7, 0x74, 0x61, + 0xe0, 0x1a, 0x5d, 0x87, 0xd9, 0xb6, 0x84, 0xa4, 0x39, 0x19, 0xf7, 0x16, 0x34, 0xd7, 0x71, 0xa9, + 0x45, 0x73, 0x1d, 0x4b, 0xcc, 0xb5, 0x4c, 0xa2, 0xef, 0xab, 0x11, 0xc9, 0x69, 0xc2, 0x1c, 0xb1, + 0x55, 0x61, 0xc5, 0x33, 0x51, 0x1a, 0xe4, 0x92, 0xaa, 0x8d, 0xd8, 0x2b, 0x33, 0xf6, 0x86, 0x66, + 0x04, 0xd0, 0x01, 0xbe, 0x60, 0x69, 0x8b, 0x0e, 0x71, 0x94, 0x23, 0xb9, 0x17, 0x8d, 0xd5, 0xba, + 0xc1, 0x64, 0xbc, 0x86, 0xc4, 0xf3, 0x0b, 0x27, 0xc3, 0xe4, 0x05, 0x35, 0x69, 0xd8, 0xca, 0x9b, + 0x0c, 0xfa, 0x78, 0x9e, 0x6b, 0x3f, 0xef, 0x86, 0xd8, 0x6d, 0x82, 0x3e, 0x11, 0x0d, 0x1e, 0x9e, + 0x1b, 0x92, 0xd8, 0x66, 0xe2, 0x53, 0x5b, 0x60, 0x6a, 0xd2, 0xda, 0xbb, 0xc6, 0xab, 0x20, 0x7d, + 0x17, 0x0e, 0x0e, 0xe6, 0xfe, 0xe9, 0xa0, 0xff, 0x6f, 0x46, 0x22, 0x96, 0x4b, 0xaf, 0xb9, 0x22, + 0x12, 0x1c, 0x02, 0xe3, 0x4c, 0x40, 0x06, 0xaf, 0xac, 0x26, 0xab, 0x25, 0x52, 0x42, 0x1f, 0x3e, + 0x75, 0x9e, 0xf9, 0x6a, 0x6f, 0xa5, 0x60, 0x28, 0x49, 0x94, 0x96, 0xa5, 0x24, 0x0c, 0x8b, 0x75, + 0x92, 0x24, 0x86, 0xaf, 0x40, 0xd3, 0xee, 0x0c, 0x43, 0xed, 0xb4, 0x5e, 0x9a, 0xed, 0x27, 0x08, + 0x6f, 0x94, 0x7f, 0xf2, 0x5b, 0xc3, 0x3b, 0x8d, 0x60, 0x8a, 0x10, 0xe8, 0x20, 0xc9, 0x6a, 0x79, + 0xe3, 0x6d, 0x81, 0x38, 0x5a, 0x5f, 0x84, 0xe8, 0x55, 0xdc, 0x03, 0xf1, 0x8e, 0xe4, 0x28, 0xc4, + 0x22, 0xd3, 0xa6, 0x05, 0xd2, 0xa2, 0x5e, 0xcd, 0xeb, 0xc1, 0x08, 0x52, 0x27, 0x05, 0xbe, 0xdb, + 0x0e, 0x6b, 0xb2, 0x05, 0xcf, 0xef, 0xc2, 0xbb, 0x92, 0xcd, 0xd3, 0xbb, 0x90, 0x87, 0xaf, 0x69, + 0x29, 0x18, 0x98, 0x89, 0xd8, 0xba, 0xb0, 0x2c, 0x99, 0x5d, 0x37, 0xa3, 0x67, 0x7e, 0xb2, 0x23, + 0x65, 0x67, 0x42, 0x4b, 0x53, 0xae, 0xd8, 0x15, 0x3c, 0xe6, 0x98, 0x8d, 0xf0, 0xaf, 0x67, 0x9b, + 0x65, 0xff, 0xd0, 0xa7, 0x57, 0x4d, 0x47, 0x7a, 0x17, 0x31, 0xb7, 0x7e, 0x80, 0xa8, 0xec, 0x65, + 0xd5, 0xf3, 0x84, 0x0d, 0x88, 0xd0, 0x84, 0xd9, 0xf6, 0xd4, 0x9c, 0xd6, 0xca, 0xee, 0xb3, 0x71, + 0xc1, 0x19, 0xac, 0x0f, 0xc7, 0x2e, 0x58, 0xfa, 0x92, 0xd5, 0xac, 0xc1, 0xd9, 0xe2, 0x91, 0x64, + 0x8b, 0x52, 0x3f, 0x5a, 0x8f, 0xdf, 0x87, 0xec, 0x40, 0x78, 0x9a, 0xad, 0xee, 0x8a, 0x32, 0x61, + 0x87, 0x7e, 0xbc, 0x69, 0x3f, 0x12, 0x4f, 0x97, 0x2f, 0x0f, 0x9f, 0xfc, 0x99, 0xac, 0xb1, 0x5c, + 0x6f, 0x68, 0x38, 0xba, 0x5d, 0x0e, 0xe8, 0x8c, 0xdf, 0x4b, 0xcb, 0x7c, 0x5c, 0x33, 0xe1, 0x1b, + 0xcb, 0x6b, 0x29, 0x29, 0xd0, 0x3a, 0x19, 0x03, 0xb6, 0x37, 0x6b, 0xdc, 0x64, 0x3e, 0x4c, 0x8c, + 0x57, 0x1c, 0x41, 0xd2, 0x14, 0xb6, 0x79, 0xad, 0x31, 0x48, 0xa4, 0x5b, 0x5c, 0x3c, 0xdd, 0x76, + 0x62, 0x31, 0x4e, 0x52, 0x7e, 0x5c, 0xb3, 0x70, 0x86, 0xfb, 0x5b, 0xa1, 0x70, 0x67, 0x05, 0x2b, + 0xa4, 0x0e, 0x8f, 0x5f, 0x34, 0x6d, 0x4d, 0x3d, 0x1b, 0xb2, 0x1f, 0xb7, 0xd4, 0xbb, 0x86, 0x83, + 0x3b, 0x42, 0xfe, 0xcf, 0xd5, 0x94, 0x8b, 0x3b, 0x8e, 0x3c, 0xac, 0x47, 0x63, 0x6b, 0x3e, 0x26, + 0xcb, 0xab, 0x17, 0x99, 0x3a, 0xf1, 0xd6, 0xe2, 0xd4, 0x1a, 0x27, 0xfc, 0x72, 0xcd, 0x3a, 0xf4, + 0x69, 0x62, 0x3b, 0x79, 0x49, 0xf7, 0x1f, 0x72, 0x8f, 0x74, 0xa8, 0x9c, 0x54, 0x5c, 0xa1, 0xa7, + 0x63, 0x68, 0x73, 0xc2, 0x97, 0xe8, 0x56, 0x23, 0xd6, 0xed, 0x96, 0x44, 0x9a, 0x34, 0x9d, 0xb5, + 0x3a, 0xd1, 0xc8, 0xce, 0x21, 0x91, 0x9d, 0xae, 0xcf, 0x87, 0x13, 0x0f, 0xb6, 0xfd, 0xe3, 0x51, + 0xd4, 0xf8, 0x4c, 0x28, 0xcd, 0x1b, 0x29, 0x05, 0x5b, 0xa6, 0x1a, 0x58, 0xf3, 0x63, 0x48, 0x5b, + 0x20, 0x8c, 0xa7, 0x37, 0x53, 0x5e, 0x18, 0xa2, 0xa7, 0x55, 0x25, 0x81, 0xbd, 0x6f, 0x2e, 0x80, + 0xfb, 0xb1, 0x5d, 0x79, 0x2b, 0xb1, 0xb9, 0x9b, 0x09, 0x6e, 0x66, 0xe4, 0x47, 0xc6, 0xa6, 0xb5, + 0x2a, 0xee, 0x8a, 0x7e, 0xdd, 0x67, 0x57, 0xf8, 0x83, 0x69, 0x50, 0x32, 0xb0, 0x93, 0xf6, 0x05, + 0xcf, 0x06, 0xc1, 0x8d, 0xfe, 0x73, 0x43, 0x7c, 0x02, 0x01, 0xe8, 0x06, 0xfb, 0x19, 0xad, 0x24, + 0x06, 0xa9, 0x42, 0x14, 0xcd, 0x6a, 0x9c, 0x3b, 0x77, 0x28, 0x0d, 0xbc, 0x79, 0x0b, 0xe6, 0xdd, + 0x16, 0xba, 0x0e, 0x75, 0x75, 0xbd, 0x35, 0x80, 0x8d, 0x87, 0x5f, 0x93, 0xe1, 0xfe, 0x7e, 0x23, + 0xbf, 0x37, 0x39, 0xce, 0x48, 0xd2, 0xc6, 0x4a, 0x01, 0x4c, 0x3b, 0x4f, 0xb2, 0x91, 0x8b, 0x28, + 0x52, 0xf8, 0x7c, 0x71, 0x70, 0xd6, 0x02, 0x0b, 0x70, 0xe7, 0x75, 0x19, 0x14, 0x30, 0x9e, 0x07, + 0x1c, 0xef, 0x46, 0x5e, 0x82, 0xfb, 0x7b, 0x39, 0x31, 0x1b, 0xab, 0xcb, 0xf0, 0x4a, 0x97, 0x21, + 0xe7, 0x7f, 0x8b, 0x7f, 0xe7, 0x94, 0x49, 0xe3, 0xeb, 0x75, 0x75, 0x2c, 0xc9, 0xe4, 0xeb, 0x8f, + 0xd3, 0x7b, 0xcd, 0x62, 0x54, 0xfe, 0xb6, 0xbc, 0x6b, 0xbf, 0xbd, 0xbd, 0x4c, 0xd5, 0x1c, 0x04, + 0x01, 0x7e, 0xdf, 0xf8, 0xd1, 0x7a, 0x78, 0x3c, 0x1d, 0x0e, 0x16, 0x9c, 0xad, 0xe0, 0x28, 0xe7, + 0x2c, 0x7f, 0x35, 0x2d, 0xdc, 0x61, 0xa1, 0x55, 0xa8, 0x7d, 0xba, 0xc0, 0xe4, 0x9a, 0x15, 0x7f, + 0xb5, 0x33, 0xf6, 0x1f, 0x87, 0x13, 0x35, 0x70, 0x40, 0x50, 0x2d, 0x26, 0x35, 0x31, 0x2b, 0x6f, + 0x1f, 0xfe, 0x0c, 0x3f, 0x98, 0x8e, 0x12, 0x9f, 0x0a, 0x6a, 0x64, 0xb6, 0x58, 0x68, 0x1d, 0xb9, + 0x90, 0xda, 0xb0, 0x95, 0x90, 0x4f, 0xa2, 0x81, 0xd7, 0xec, 0xf8, 0xfd, 0x65, 0x99, 0xc8, 0x89, + 0x60, 0xc6, 0x6e, 0x9b, 0xec, 0x58, 0xad, 0x2d, 0x78, 0xab, 0xd1, 0x7b, 0x04, 0xb0, 0x4e, 0xbe, + 0x41, 0x76, 0x67, 0x1b, 0x63, 0x78, 0xa6, 0xa3, 0x75, 0x68, 0x16, 0x74, 0x9c, 0x07, 0xbc, 0x65, + 0x37, 0x47, 0x7d, 0x35, 0xaa, 0xa6, 0x80, 0xab, 0xb2, 0x9f, 0xf9, 0x66, 0x34, 0x6d, 0x37, 0x8e, + 0x32, 0x04, 0x24, 0x96, 0xc4, 0x6e, 0xd3, 0x0d, 0x24, 0x93, 0x80, 0x5a, 0xf0, 0x41, 0xf7, 0x8b, + 0x28, 0xb9, 0xbf, 0xde, 0x8c, 0xfa, 0x7e, 0xb3, 0x77, 0x34, 0xf1, 0x07, 0xd3, 0x72, 0x0b, 0xe1, + 0x42, 0xb1, 0x28, 0x31, 0x3c, 0xeb, 0x2c, 0xa5, 0x07, 0x75, 0x14, 0x74, 0x92, 0xfe, 0x98, 0x8c, + 0x7b, 0x2d, 0x0d, 0x59, 0x2e, 0x77, 0x6a, 0x50, 0xc1, 0x43, 0x68, 0xbb, 0xfa, 0x7b, 0xd8, 0xd7, + 0xcc, 0x78, 0x36, 0x43, 0x5c, 0xdc, 0x15, 0xee, 0x69, 0xe6, 0xfb, 0x0f, 0x08, 0x6b, 0xce, 0xf9, + 0x44, 0xf0, 0x43, 0x82, 0xb3, 0xe7, 0xd5, 0x1a, 0xc7, 0xc3, 0xec, 0x2d, 0x97, 0x81, 0x44, 0x9e, + 0x46, 0x74, 0xee, 0x7a, 0xe2, 0x5c, 0x60, 0x28, 0xa5, 0x5d, 0x95, 0x9a, 0x9a, 0xd9, 0xef, 0xce, + 0xb8, 0x12, 0xdd, 0x49, 0xf9, 0x9f, 0x41, 0xd8, 0xf7, 0xef, 0x39, 0x51, 0xdc, 0x54, 0x5f, 0xfc, + 0x02, 0x47, 0xa0, 0x7a, 0xdd, 0x0e, 0xb9, 0x5a, 0xf7, 0xd1, 0xbb, 0x16, 0x42, 0x6e, 0x07, 0xbd, + 0xe8, 0x8b, 0x79, 0x63, 0x5f, 0x31, 0x39, 0x70, 0xba, 0x8e, 0x65, 0x65, 0xef, 0x3e, 0x2b, 0x91, + 0x72, 0x6a, 0xd3, 0xfc, 0xf1, 0x64, 0x7c, 0x49, 0x93, 0x39, 0x90, 0x82, 0x5a, 0x74, 0x7e, 0xdc, + 0x97, 0x11, 0x30, 0x45, 0xc1, 0x75, 0xbe, 0x78, 0x3e, 0xa9, 0x78, 0x81, 0xa7, 0xa1, 0xea, 0x9b, + 0x3b, 0xd1, 0xd9, 0xd5, 0x78, 0xe7, 0xc3, 0x6a, 0xb1, 0xd7, 0xd8, 0x01, 0xcc, 0xe6, 0xd0, 0x68, + 0xd7, 0x0e, 0x43, 0xc7, 0x3c, 0xae, 0x2c, 0x98, 0x58, 0x2d, 0x7a, 0x68, 0x84, 0x24, 0xd3, 0x80, + 0x17, 0xc1, 0x43, 0x43, 0x97, 0xc6, 0x16, 0x94, 0x9b, 0xb1, 0xa8, 0x64, 0x9b, 0x98, 0xd7, 0x55, + 0x60, 0x86, 0xa9, 0x61, 0x51, 0x21, 0xcc, 0x84, 0xf0, 0x68, 0x36, 0x2f, 0x3e, 0xd0, 0x8c, 0xd0, + 0xa8, 0x6c, 0x6b, 0xef, 0x59, 0x7f, 0x00, 0x33, 0x29, 0x3f, 0x0d, 0x50, 0xbd, 0xb9, 0xcb, 0x39, + 0x76, 0xa5, 0x81, 0x6b, 0x81, 0x35, 0x98, 0x2a, 0x13, 0xbe, 0xe0, 0x4a, 0xe1, 0x76, 0xbf, 0xd5, + 0xd2, 0x69, 0xb6, 0xb3, 0xb2, 0x43, 0xcd, 0x90, 0x98, 0x5d, 0xeb, 0x7a, 0x9a, 0x9a, 0xcb, 0x4d, + 0xbf, 0xac, 0x39, 0xf1, 0x37, 0x92, 0x3a, 0xcc, 0x49, 0xfc, 0x5f, 0xdc, 0xd1, 0xd8, 0xa1, 0xfe, + 0xa1, 0x0d, 0x3f, 0xed, 0xb9, 0xe5, 0xfb, 0xa4, 0x38, 0xef, 0xb7, 0xb0, 0xca, 0xd1, 0x1a, 0xd2, + 0xad, 0xba, 0x7c, 0x11, 0x66, 0xbe, 0x3c, 0x60, 0xa2, 0x1a, 0xaf, 0x5d, 0xf2, 0x1c, 0x3d, 0x2d, + 0xaf, 0x53, 0x52, 0xb9, 0xd1, 0xdb, 0x6d, 0xc3, 0x38, 0xc6, 0xe3, 0x29, 0xbd, 0x23, 0xc8, 0x5a, + 0xd2, 0xaa, 0xa6, 0xb3, 0x22, 0xd9, 0x69, 0x6a, 0x2e, 0x64, 0x0c, 0xd2, 0xf3, 0xa7, 0x19, 0xf7, + 0x00, 0x29, 0x0d, 0xa7, 0xfb, 0x9b, 0x0d, 0xfd, 0xdd, 0x34, 0xaf, 0xd7, 0x3f, 0x6e, 0x35, 0x63, + 0xdf, 0xae, 0x32, 0xf5, 0x7b, 0xd7, 0x91, 0x84, 0xf5, 0xec, 0xbd, 0x0e, 0x72, 0xda, 0x16, 0x4b, + 0x6d, 0xf6, 0xb5, 0xba, 0x3e, 0x7b, 0xd9, 0xe6, 0x6c, 0x8c, 0x12, 0x0b, 0x97, 0xba, 0xf3, 0x2c, + 0x7f, 0xe0, 0x1b, 0x2e, 0xec, 0xaa, 0x5d, 0xc3, 0x69, 0xf8, 0xe9, 0x25, 0x51, 0x15, 0xa5, 0xce, + 0xd3, 0x17, 0xed, 0xc1, 0xdd, 0xa4, 0xb6, 0xd0, 0x0e, 0xdc, 0x9b, 0xa5, 0x0f, 0x58, 0x6b, 0x1c, + 0xda, 0xb5, 0xa5, 0xe7, 0xec, 0xfa, 0xea, 0xbe, 0x56, 0xde, 0x70, 0x76, 0x5f, 0xeb, 0xa2, 0x66, + 0x86, 0xc0, 0x5d, 0x4d, 0xef, 0x58, 0xa4, 0x2d, 0xfd, 0x08, 0xa9, 0xc1, 0x86, 0x2b, 0x16, 0xc3, + 0x5d, 0xe8, 0x7f, 0x8e, 0x31, 0x42, 0x52, 0xa4, 0x7e, 0xac, 0xa0, 0x99, 0x76, 0x55, 0x5d, 0xb4, + 0xd4, 0x1c, 0xc8, 0x58, 0xf7, 0xc6, 0xb3, 0x96, 0x1c, 0xe0, 0xdc, 0x8d, 0x48, 0xc3, 0x44, 0xb7, + 0xbe, 0x20, 0x6f, 0xb4, 0x64, 0x5b, 0x9f, 0x85, 0xcd, 0x4e, 0x10, 0x72, 0xbe, 0xda, 0x9e, 0x43, + 0x39, 0x13, 0x01, 0x3e, 0xe0, 0xb6, 0x7d, 0xd2, 0x70, 0x78, 0xe2, 0x57, 0x2e, 0x5e, 0x6a, 0xbb, + 0x99, 0xe7, 0xb4, 0x8c, 0xa4, 0x3d, 0x0b, 0x84, 0x44, 0x02, 0x50, 0xb5, 0x10, 0xee, 0x38, 0x1c, + 0x77, 0x63, 0x89, 0x75, 0x4b, 0x90, 0x9d, 0xb3, 0xaf, 0xb5, 0x8f, 0xed, 0x86, 0x33, 0xa4, 0xa9, + 0x4f, 0x9e, 0xa6, 0x73, 0x93, 0xb1, 0xde, 0x53, 0xe5, 0xed, 0xe2, 0xd4, 0xeb, 0xc5, 0xbb, 0x32, + 0xfc, 0x6b, 0x2e, 0x3f, 0xe3, 0x0f, 0xa6, 0xb7, 0x92, 0x35, 0xa1, 0x27, 0x14, 0xdf, 0xf6, 0xff, + 0x45, 0xea, 0xb4, 0x6e, 0xf2, 0x95, 0x8f, 0xb9, 0x27, 0xbd, 0x1c, 0xe9, 0xbb, 0x58, 0x8d, 0x0f, + 0x1b, 0x38, 0x98, 0xdb, 0x8e, 0xcc, 0x99, 0x48, 0x0c, 0x22, 0x6f, 0x87, 0x20, 0x5c, 0xc3, 0xee, + 0x0f, 0xc4, 0xc1, 0x90, 0xb9, 0xd9, 0x3f, 0x46, 0xa0, 0xf7, 0x77, 0x45, 0x4b, 0x61, 0x5d, 0x5d, + 0x99, 0xb0, 0xac, 0x8b, 0x96, 0xf9, 0x96, 0xb3, 0x17, 0x4c, 0x19, 0xc2, 0xbf, 0xea, 0xf2, 0x7a, + 0xfb, 0xbe, 0x5a, 0x7d, 0x72, 0x37, 0xc9, 0x80, 0x29, 0x18, 0xce, 0xab, 0x1a, 0xe7, 0x84, 0x99, + 0x35, 0x81, 0x84, 0xcd, 0x66, 0xed, 0xf4, 0x1c, 0x25, 0xd5, 0x47, 0x83, 0x65, 0x2a, 0x47, 0x9e, + 0x26, 0x8a, 0xb0, 0x08, 0x41, 0x98, 0xeb, 0xc8, 0xbe, 0xa2, 0xcd, 0xb5, 0xc3, 0xe3, 0x39, 0x77, + 0x44, 0x3a, 0xcb, 0x2b, 0xb4, 0xa0, 0xe7, 0x11, 0xfb, 0x68, 0x46, 0x82, 0x39, 0xaf, 0x2d, 0x62, + 0x48, 0x50, 0xc2, 0xa5, 0xe4, 0xb5, 0xff, 0x80, 0x20, 0xd7, 0x9d, 0x30, 0xa3, 0x4f, 0x1a, 0xe8, + 0xda, 0xa2, 0x69, 0x67, 0x0a, 0x99, 0x4b, 0xc3, 0xa3, 0xc5, 0x3d, 0xa3, 0xab, 0xf5, 0xfc, 0xfc, + 0xe8, 0xec, 0x72, 0x9a, 0x36, 0xa2, 0xbb, 0xde, 0x7c, 0x3c, 0x9d, 0xb3, 0x92, 0x72, 0x75, 0x33, + 0xae, 0x53, 0x3f, 0xee, 0xb4, 0x52, 0x50, 0x50, 0x33, 0x5b, 0x1a, 0xcb, 0x2e, 0x56, 0xf4, 0xb2, + 0x74, 0x03, 0xfb, 0xb9, 0xbb, 0x41, 0xcc, 0x96, 0x9c, 0x27, 0x41, 0xb1, 0x20, 0xff, 0x28, 0x9a, + 0xb9, 0x3c, 0x89, 0x06, 0xb9, 0x99, 0xa3, 0x94, 0x19, 0xd1, 0xc4, 0xdc, 0xaf, 0x24, 0x6b, 0x9a, + 0x4a, 0xf5, 0xd1, 0xa7, 0xd7, 0xef, 0xba, 0x52, 0x41, 0x1f, 0x17, 0x8b, 0x78, 0x47, 0x58, 0x96, + 0xc4, 0xcc, 0xc9, 0x16, 0x59, 0x5e, 0x27, 0x22, 0x0b, 0xb2, 0x68, 0x1c, 0xdb, 0x9d, 0x68, 0x9b, + 0x4c, 0x46, 0xb9, 0x53, 0x5f, 0xdd, 0xcd, 0x2b, 0x18, 0x0d, 0x09, 0x29, 0x1a, 0xbe, 0xe8, 0xc6, + 0x2a, 0xf2, 0xd7, 0xfa, 0x14, 0xac, 0x3f, 0x98, 0x56, 0xb3, 0x47, 0xdd, 0x4f, 0xa9, 0x5d, 0xd1, + 0x5a, 0x2c, 0x19, 0xdb, 0x85, 0xe0, 0x84, 0x1e, 0xbc, 0x6f, 0x86, 0xc7, 0xf9, 0x5b, 0x9c, 0xa9, + 0x12, 0x8e, 0xa5, 0x29, 0x3d, 0xcf, 0xb4, 0x37, 0xc0, 0x0d, 0xf0, 0x6c, 0xf2, 0x54, 0x00, 0x8c, + 0xf9, 0xe1, 0xfe, 0x76, 0x87, 0x1e, 0x76, 0xca, 0x98, 0x0c, 0x0e, 0xcf, 0x6e, 0xb5, 0xe7, 0x79, + 0x76, 0x54, 0xcd, 0x29, 0xed, 0xd4, 0x27, 0x97, 0xb8, 0x1f, 0xcf, 0x26, 0xa3, 0xb7, 0x77, 0x09, + 0x8b, 0xf7, 0xc7, 0x49, 0x77, 0x09, 0x34, 0xc1, 0x4b, 0xf1, 0x3c, 0x62, 0x3d, 0xde, 0x95, 0x11, + 0x8d, 0x26, 0x03, 0xda, 0xf4, 0x52, 0xd9, 0xc3, 0xd4, 0xf5, 0x92, 0x55, 0x74, 0x77, 0xdc, 0x9f, + 0xfe, 0xcf, 0xbc, 0xed, 0x3e, 0x4c, 0xb6, 0x9e, 0xcf, 0x10, 0x6a, 0x57, 0xa2, 0x25, 0x29, 0x90, + 0x40, 0xf8, 0x06, 0x5b, 0xed, 0xb0, 0xbc, 0xf9, 0xfc, 0x99, 0x1b, 0xdc, 0xef, 0x71, 0x74, 0xb0, + 0x10, 0xb5, 0xc4, 0xfc, 0x43, 0x0e, 0xab, 0x3c, 0xa6, 0x84, 0x3e, 0x97, 0x84, 0x21, 0x74, 0x29, + 0x4e, 0xc0, 0xb8, 0x5e, 0x20, 0x0a, 0xc7, 0xec, 0x84, 0xb7, 0x4e, 0xf0, 0x6d, 0x11, 0x09, 0x23, + 0x0f, 0x5c, 0xc5, 0xb9, 0x3c, 0x90, 0x0c, 0x5a, 0x55, 0xa0, 0x7b, 0xdc, 0x33, 0xb3, 0xe1, 0x41, + 0x48, 0x3f, 0xaa, 0x31, 0x19, 0xba, 0x6f, 0x8d, 0xeb, 0xd9, 0xba, 0x53, 0x52, 0x83, 0x78, 0x90, + 0x8d, 0x1c, 0x55, 0x71, 0xb0, 0x33, 0x43, 0x84, 0x15, 0x0a, 0x26, 0x3b, 0x64, 0x77, 0x47, 0x3e, + 0x6f, 0xbb, 0x11, 0x1a, 0x5b, 0xe8, 0x86, 0x51, 0x9e, 0x0c, 0x9a, 0x31, 0xf1, 0x40, 0x35, 0x34, + 0x1a, 0xc7, 0xcf, 0x51, 0x0a, 0x77, 0x20, 0xda, 0xef, 0x4c, 0xd9, 0x4e, 0x0a, 0x05, 0x88, 0x59, + 0xbe, 0xb3, 0xa4, 0x82, 0xe0, 0x76, 0x82, 0x0f, 0x1c, 0x92, 0x58, 0x8b, 0x6f, 0xdf, 0xae, 0xab, + 0x84, 0x95, 0xf3, 0xe7, 0xd9, 0x6d, 0x8f, 0x82, 0xc4, 0xd5, 0x00, 0x02, 0x7d, 0xde, 0x73, 0x52, + 0x7e, 0xad, 0xb9, 0xc2, 0xfd, 0x83, 0x69, 0xed, 0x5e, 0xb9, 0xb3, 0x45, 0xe7, 0xa7, 0xfc, 0x69, + 0xb9, 0x46, 0x7d, 0x9c, 0x52, 0xc8, 0x45, 0xe2, 0x14, 0xe5, 0xb2, 0x7c, 0xd3, 0xe3, 0x29, 0x5b, + 0xfe, 0x34, 0x54, 0x56, 0x07, 0xcf, 0x62, 0xec, 0xd2, 0x58, 0xaa, 0x1d, 0x82, 0x25, 0xa2, 0x2f, + 0xf6, 0x39, 0x09, 0x62, 0xe1, 0x40, 0xb3, 0x5d, 0x48, 0xb2, 0x1d, 0x89, 0x4f, 0xd3, 0x52, 0x4b, + 0x1c, 0x96, 0x8e, 0x37, 0x52, 0x39, 0x95, 0xec, 0x86, 0x18, 0xa2, 0xbb, 0x26, 0xd8, 0xd2, 0x10, + 0x5c, 0x0d, 0x29, 0x9f, 0xe5, 0xc4, 0x11, 0x2b, 0x54, 0xf5, 0xe0, 0x3a, 0xd4, 0x79, 0xe6, 0x0a, + 0x2b, 0xd9, 0x81, 0xc4, 0xac, 0xb8, 0x5a, 0xe9, 0xd0, 0x59, 0xfa, 0x13, 0xbf, 0x42, 0x7d, 0x64, + 0x46, 0xb7, 0xa4, 0xeb, 0xb6, 0x31, 0x53, 0x5d, 0x05, 0x12, 0x8b, 0x2c, 0x17, 0x42, 0x0d, 0x17, + 0x4b, 0x1b, 0x69, 0x85, 0x09, 0x12, 0xc5, 0xea, 0x0c, 0x08, 0xdf, 0x87, 0xcc, 0xeb, 0x1b, 0x21, + 0x06, 0x4d, 0x48, 0x56, 0xeb, 0x0d, 0xad, 0xc4, 0x98, 0xb5, 0x80, 0xdb, 0x89, 0x88, 0x14, 0x04, + 0xde, 0xe6, 0x58, 0x6c, 0xb7, 0x5f, 0xcb, 0xfb, 0x27, 0xd0, 0x99, 0x8f, 0xba, 0x9f, 0x5a, 0x0c, + 0x79, 0xc5, 0x83, 0xcf, 0x41, 0xd5, 0xd3, 0xd4, 0xf1, 0x5b, 0xb2, 0x69, 0xca, 0xee, 0xba, 0xce, + 0x86, 0x0c, 0xb5, 0x6c, 0x7b, 0x7f, 0x8e, 0xc5, 0x73, 0xa7, 0xe7, 0x16, 0xa2, 0x83, 0xfd, 0xc5, + 0x59, 0xd2, 0x17, 0x0b, 0xea, 0x21, 0xb8, 0x4b, 0xd9, 0x75, 0x9e, 0x06, 0x59, 0xe6, 0x12, 0xa9, + 0x90, 0x60, 0x13, 0xc4, 0xd4, 0x14, 0x57, 0x37, 0xdf, 0x98, 0xf9, 0x52, 0xd5, 0xd7, 0xcf, 0xeb, + 0x09, 0xc5, 0x71, 0xbf, 0xbf, 0x25, 0xe2, 0x36, 0xfb, 0xd1, 0xe7, 0xd5, 0xcb, 0xdc, 0x59, 0xab, + 0xae, 0xac, 0x4a, 0x56, 0x54, 0x4a, 0xb7, 0x89, 0x19, 0x61, 0xad, 0x95, 0xf7, 0xeb, 0x7b, 0x3b, + 0x8f, 0x7e, 0x0d, 0xd5, 0x74, 0xed, 0x95, 0xf3, 0x6d, 0x27, 0xfe, 0x05, 0xea, 0x89, 0x47, 0x1b, + 0x4c, 0xed, 0x3a, 0x7f, 0x1d, 0x3d, 0x90, 0xc5, 0x3f, 0x98, 0x5e, 0x60, 0x54, 0x1e, 0xfc, 0xac, + 0xd9, 0xa8, 0xc8, 0xb3, 0xa0, 0xc5, 0xbd, 0xdb, 0x19, 0x10, 0x68, 0x9c, 0xbd, 0xfc, 0x74, 0xaf, + 0x3d, 0x45, 0x56, 0x54, 0x9a, 0xc6, 0xf1, 0xe4, 0xc9, 0x49, 0xdc, 0xb3, 0xe5, 0xb1, 0x9b, 0x34, + 0xfb, 0x09, 0xbf, 0xa0, 0x63, 0xd5, 0x76, 0x2c, 0xfb, 0xf9, 0xc2, 0xfb, 0x77, 0xb1, 0xa8, 0x7e, + 0x7a, 0x42, 0x6d, 0xf9, 0xb2, 0x5f, 0x6a, 0x2b, 0x97, 0x88, 0x01, 0x9d, 0xf4, 0x04, 0xd3, 0x35, + 0x15, 0xf0, 0xc6, 0x80, 0x9c, 0xf7, 0x10, 0xe3, 0x59, 0xe8, 0x43, 0x06, 0xea, 0xb1, 0x2b, 0x14, + 0x93, 0x36, 0x4a, 0xa8, 0x34, 0x6e, 0x89, 0x58, 0xe7, 0xa3, 0xe6, 0x20, 0x85, 0x0a, 0xb4, 0xee, + 0x5a, 0x45, 0x91, 0x6a, 0xad, 0x52, 0x67, 0x97, 0xa1, 0x19, 0xca, 0x67, 0xc0, 0x33, 0xc3, 0x00, + 0x4b, 0xc6, 0xe3, 0xe4, 0xb4, 0x11, 0xbb, 0x41, 0xb3, 0xdb, 0x65, 0xf5, 0xf3, 0x97, 0x50, 0x67, + 0x91, 0x11, 0xe6, 0xbb, 0xc2, 0x05, 0xc6, 0x5a, 0xe9, 0xfc, 0xb9, 0x20, 0xde, 0x92, 0x32, 0x74, + 0x5c, 0x57, 0x85, 0x94, 0x78, 0x37, 0xea, 0x9d, 0x08, 0xfb, 0xfe, 0x26, 0x51, 0x12, 0xde, 0x5e, + 0x43, 0x35, 0xac, 0xf9, 0x29, 0x7b, 0x4f, 0xea, 0x76, 0x69, 0xb2, 0xed, 0xc8, 0x0d, 0x6e, 0x62, + 0x23, 0x5e, 0x50, 0xf6, 0xed, 0x66, 0x98, 0x35, 0x88, 0x3b, 0xca, 0xe7, 0x98, 0x60, 0x0d, 0xed, + 0xe4, 0xab, 0x01, 0x62, 0x41, 0xea, 0xd9, 0x76, 0x37, 0x7e, 0x3e, 0xde, 0x6f, 0x71, 0x69, 0x7a, + 0xf8, 0xa6, 0x0b, 0x1a, 0x2b, 0xaf, 0x2b, 0x0d, 0xc0, 0xe7, 0x4e, 0x7f, 0x76, 0xf9, 0x8d, 0x97, + 0xf8, 0xd5, 0x94, 0x51, 0xf8, 0xf2, 0x94, 0x4e, 0xd1, 0x8b, 0x46, 0x52, 0x38, 0xae, 0x56, 0x4b, + 0xa8, 0xc5, 0x60, 0x38, 0xc6, 0xb9, 0xd5, 0xc3, 0xab, 0x9f, 0x03, 0xba, 0x47, 0x88, 0x90, 0x11, + 0xf2, 0x7e, 0xd1, 0x2a, 0x3e, 0xf3, 0xff, 0x5d, 0x54, 0xb5, 0xbc, 0x4a, 0xa5, 0x16, 0x3e, 0x0b, + 0x35, 0x65, 0xb6, 0xc6, 0x0f, 0x74, 0x64, 0x2b, 0xff, 0xa6, 0x36, 0xd6, 0xca, 0x1f, 0x4c, 0x9b, + 0x77, 0xd7, 0x10, 0xfb, 0x65, 0xa8, 0x89, 0x6c, 0xf1, 0x8a, 0xeb, 0x0a, 0xfa, 0xa6, 0xa4, 0x6c, + 0x73, 0x15, 0x8a, 0x35, 0x31, 0x1c, 0x8f, 0x5e, 0x6c, 0x74, 0xb9, 0xa4, 0x78, 0xdc, 0xea, 0x2e, + 0x5c, 0x28, 0x16, 0xf8, 0x3c, 0xc3, 0xae, 0x9f, 0x03, 0xc2, 0xe1, 0x9f, 0xf8, 0x7d, 0xfb, 0xf4, + 0x66, 0x92, 0xfa, 0xee, 0xf8, 0x31, 0x48, 0x1d, 0x79, 0xbb, 0xed, 0xdd, 0x64, 0x99, 0xd2, 0x2b, + 0x7c, 0xdf, 0xea, 0x51, 0xf5, 0x58, 0xb7, 0xc6, 0x1e, 0x85, 0x5b, 0xab, 0xd7, 0x02, 0x61, 0xff, + 0xdf, 0x94, 0xea, 0xf7, 0xe0, 0x5d, 0x8c, 0x17, 0x0f, 0x92, 0xf7, 0xb2, 0xef, 0x8e, 0x0e, 0xb8, + 0xf7, 0xf8, 0x63, 0x3f, 0x97, 0x8d, 0xaf, 0xd3, 0x73, 0x7b, 0x7c, 0xdd, 0x22, 0xb9, 0x92, 0xea, + 0x4a, 0x9e, 0x17, 0x47, 0x1d, 0x09, 0xad, 0xcc, 0x4e, 0x1e, 0xf7, 0x77, 0xbf, 0x2b, 0xf6, 0x57, + 0xe2, 0x7e, 0x93, 0x44, 0xaa, 0x37, 0xbc, 0xdd, 0x65, 0x6b, 0xa2, 0xb1, 0xb7, 0x07, 0xfc, 0xe3, + 0x08, 0x59, 0xf3, 0xfd, 0xfb, 0xeb, 0xaf, 0x59, 0x50, 0xd3, 0xc9, 0x33, 0xca, 0x5b, 0xd0, 0xd8, + 0x60, 0x3a, 0xba, 0x49, 0xe0, 0x7e, 0xe0, 0x47, 0x3e, 0xe4, 0x97, 0x68, 0x9b, 0xbb, 0x72, 0x61, + 0xba, 0x1f, 0x06, 0xef, 0x2d, 0x55, 0x51, 0xf9, 0x21, 0x31, 0x7e, 0xef, 0x92, 0x03, 0xf3, 0xde, + 0xb5, 0x68, 0xf7, 0x99, 0x7b, 0xa1, 0x43, 0x15, 0x76, 0xe7, 0xb5, 0xf2, 0xa5, 0x50, 0x36, 0x4e, + 0xad, 0x74, 0x17, 0x2e, 0xa9, 0x73, 0x4a, 0x67, 0x6f, 0x9f, 0x4c, 0x60, 0xaa, 0x79, 0xfd, 0xc5, + 0xb4, 0x25, 0x79, 0xcd, 0x88, 0x4f, 0x82, 0x3a, 0x3e, 0xc7, 0x8d, 0xc7, 0x58, 0xbb, 0xad, 0x56, + 0xd2, 0x1c, 0x55, 0x61, 0x53, 0x7a, 0x5f, 0x93, 0xe8, 0x8b, 0x77, 0x83, 0xd0, 0x58, 0x3a, 0xd8, + 0xea, 0x6a, 0xf6, 0x0a, 0x81, 0x5e, 0x4d, 0x3d, 0xd9, 0x49, 0xbc, 0x36, 0xd7, 0x4f, 0x3f, 0x61, + 0x26, 0xcd, 0x58, 0x33, 0x32, 0x5d, 0x8b, 0xf6, 0xc5, 0x26, 0x72, 0x6d, 0x3c, 0xa9, 0x67, 0xce, + 0x7f, 0xad, 0x04, 0x02, 0x4b, 0xff, 0x60, 0xda, 0xc6, 0x6f, 0x1c, 0xdd, 0xa2, 0x0d, 0xf9, 0x0f, + 0x72, 0x91, 0x09, 0xb8, 0x52, 0xf1, 0x6a, 0x24, 0x89, 0x70, 0xaa, 0xb8, 0x6c, 0x54, 0x78, 0x00, + 0x61, 0x5c, 0xc1, 0xe7, 0x8b, 0xee, 0xa9, 0x75, 0xa0, 0x7c, 0xcd, 0x6c, 0xd4, 0x04, 0xd5, 0x17, + 0xf6, 0x7a, 0x44, 0xc2, 0xcc, 0xe0, 0x10, 0x8a, 0x0a, 0xbe, 0x79, 0x82, 0x4c, 0xbe, 0x41, 0x13, + 0x1b, 0x7c, 0x29, 0x42, 0x29, 0xdd, 0xec, 0xe9, 0xd1, 0xea, 0x78, 0x36, 0x1a, 0xb9, 0x9f, 0xe7, + 0xa8, 0x44, 0x5b, 0xcc, 0xf7, 0x75, 0xe8, 0x96, 0x56, 0x27, 0x31, 0xfa, 0x3b, 0xcf, 0x6a, 0x62, + 0x26, 0x85, 0xee, 0xa4, 0x67, 0xc2, 0xd6, 0x9a, 0x3f, 0x96, 0xe2, 0x80, 0xa7, 0xcb, 0xea, 0x2f, + 0x72, 0x5f, 0x65, 0x22, 0xb0, 0x08, 0xea, 0x2b, 0x2d, 0x1e, 0x74, 0x18, 0x94, 0xe6, 0x75, 0x61, + 0xd4, 0xa6, 0xbf, 0x9f, 0xd1, 0xb6, 0x6a, 0x3a, 0x8b, 0xb9, 0xed, 0xbc, 0x3d, 0xc9, 0xd2, 0xa6, + 0xc1, 0xa0, 0x8e, 0x1b, 0xba, 0xf5, 0x25, 0xc0, 0x43, 0x17, 0x51, 0x97, 0x18, 0x06, 0x3b, 0x44, + 0xc3, 0x14, 0xb4, 0x30, 0x87, 0x96, 0x4d, 0x5f, 0x6a, 0xc9, 0x57, 0xf6, 0x2c, 0x0d, 0x2d, 0xc0, + 0x8f, 0x2c, 0xdd, 0xf2, 0xae, 0xbb, 0xb4, 0x73, 0x83, 0xb6, 0x07, 0x8e, 0xb5, 0x71, 0x75, 0x78, + 0x1d, 0x7d, 0xee, 0x34, 0x0f, 0xf4, 0xdd, 0x45, 0x9d, 0xc1, 0xe8, 0x97, 0x4b, 0x76, 0xca, 0x4d, + 0x16, 0x37, 0x06, 0x0e, 0x79, 0x3c, 0xcb, 0xfa, 0xdf, 0x2f, 0xd5, 0x6b, 0x55, 0x2d, 0x5b, 0xf7, + 0x35, 0xe0, 0xb9, 0x39, 0x9f, 0xeb, 0x76, 0xac, 0x2d, 0x8b, 0x16, 0xd0, 0xa6, 0x0d, 0xaa, 0xcf, + 0xa9, 0x78, 0x6a, 0x91, 0xa6, 0x8f, 0x77, 0x67, 0xe6, 0x53, 0x8e, 0x8d, 0x56, 0xd6, 0xc2, 0xb1, + 0xab, 0x42, 0x8b, 0xe5, 0x2e, 0x5a, 0x2d, 0xa6, 0x7d, 0xcf, 0x9a, 0xc7, 0x24, 0x18, 0xb7, 0x58, + 0x9d, 0x86, 0x0d, 0xb4, 0x50, 0x8d, 0x93, 0x22, 0x79, 0xf3, 0x60, 0xba, 0xb0, 0x0b, 0x1e, 0x7d, + 0xa5, 0xce, 0x7e, 0x3b, 0xf8, 0xcd, 0x59, 0xc1, 0xd0, 0x1f, 0x4c, 0x8b, 0x79, 0xc3, 0x57, 0x63, + 0x56, 0x77, 0x29, 0xeb, 0x05, 0x77, 0xcb, 0x9b, 0x87, 0x28, 0xfb, 0xda, 0x04, 0x59, 0xad, 0xe2, + 0x31, 0x4c, 0x5f, 0xe9, 0xdf, 0x7a, 0xe6, 0x5f, 0xbc, 0x83, 0x51, 0x4a, 0x8a, 0x1b, 0xda, 0x09, + 0xb3, 0xfe, 0x21, 0x95, 0xfd, 0xbc, 0xf7, 0x86, 0x1e, 0x4f, 0x42, 0x1b, 0x9d, 0x51, 0x06, 0xbb, + 0x7a, 0x93, 0xb5, 0x1e, 0x91, 0x1a, 0x74, 0x99, 0x7b, 0xf2, 0xd3, 0x25, 0xa0, 0x06, 0x9e, 0x5b, + 0x91, 0x1f, 0xa4, 0x14, 0x86, 0xe2, 0xfd, 0x5f, 0x2f, 0xed, 0x90, 0x91, 0x58, 0xd8, 0xe5, 0x1d, + 0xef, 0xb3, 0x49, 0xa3, 0xb3, 0x7e, 0xcc, 0x3b, 0x38, 0x35, 0x26, 0x58, 0x2e, 0x82, 0xf9, 0xb5, + 0x21, 0x36, 0x9e, 0x44, 0x30, 0xd0, 0x7c, 0x85, 0x29, 0x6b, 0xb2, 0x5e, 0x77, 0x51, 0xf0, 0x72, + 0x37, 0x8d, 0xeb, 0x65, 0xd2, 0x45, 0xf1, 0x5a, 0x20, 0xd3, 0x0f, 0xbb, 0x37, 0x7d, 0x21, 0x9a, + 0xde, 0xa4, 0x0a, 0x67, 0xd7, 0xee, 0xf6, 0xa9, 0xaa, 0x5c, 0xe4, 0x7d, 0x80, 0x70, 0x8b, 0xd6, + 0xa6, 0x82, 0xe1, 0xe3, 0xbf, 0x0a, 0x0f, 0xde, 0xa1, 0x08, 0x29, 0x44, 0xc1, 0x5a, 0x77, 0x45, + 0x7b, 0xeb, 0x99, 0x95, 0x16, 0xb6, 0x7c, 0xd3, 0xf4, 0x76, 0x8d, 0xc1, 0x52, 0xf9, 0x45, 0x21, + 0x79, 0x4d, 0x6c, 0xf4, 0x4d, 0xb0, 0x03, 0x8b, 0x97, 0x09, 0x9c, 0x54, 0x3b, 0xa1, 0x25, 0xec, + 0x6d, 0x91, 0xca, 0xc6, 0x9d, 0xc7, 0xc9, 0x04, 0x7e, 0x02, 0xcf, 0x16, 0x9c, 0x1b, 0xb8, 0x8a, + 0x1c, 0x63, 0xee, 0x67, 0xe5, 0xb8, 0x42, 0xca, 0x42, 0xc2, 0x47, 0x84, 0x91, 0x62, 0xa7, 0xab, + 0xef, 0x6b, 0x0d, 0x62, 0x8b, 0x6a, 0x33, 0xbd, 0x79, 0xa4, 0x0b, 0xcd, 0xdd, 0x1a, 0x9d, 0xff, + 0x20, 0xda, 0x44, 0xb2, 0xa5, 0xe0, 0x21, 0x21, 0x0d, 0x09, 0x02, 0x49, 0xe2, 0x60, 0xe7, 0x7f, + 0xa6, 0xc5, 0xf8, 0x17, 0x47, 0xcd, 0x5b, 0x18, 0x5a, 0x69, 0x3a, 0xd1, 0x4e, 0x9d, 0xaf, 0x3a, + 0x99, 0xda, 0x4d, 0x3f, 0xf0, 0xe7, 0x9e, 0x68, 0xfa, 0xeb, 0x8c, 0xa8, 0xa0, 0xfc, 0xc1, 0x34, + 0xb6, 0xc7, 0xbb, 0x43, 0x78, 0x26, 0x63, 0x6b, 0xe7, 0x25, 0x21, 0xd8, 0x1a, 0x8c, 0x93, 0xde, + 0xeb, 0x11, 0xf1, 0x56, 0x56, 0xe0, 0x1a, 0x89, 0xf3, 0x76, 0xba, 0xce, 0xd4, 0x9c, 0x23, 0x0c, + 0xad, 0xfb, 0xce, 0xb3, 0x88, 0xe9, 0xd7, 0xc6, 0x2b, 0x0f, 0x26, 0xbf, 0x47, 0xd1, 0x30, 0xf9, + 0x2d, 0x50, 0x56, 0xe5, 0xf3, 0x28, 0x24, 0xfe, 0xda, 0x42, 0x9e, 0xa8, 0xbd, 0x2f, 0xb0, 0xdb, + 0x0e, 0x7f, 0x8b, 0x19, 0x7d, 0x68, 0xf8, 0x45, 0x50, 0x69, 0xec, 0x97, 0x09, 0x84, 0x11, 0x72, + 0xb1, 0x5e, 0xd3, 0xb5, 0x6e, 0x01, 0xbd, 0x8b, 0x64, 0xce, 0x03, 0xc9, 0xda, 0x2d, 0x9b, 0x7d, + 0x15, 0xcf, 0x4a, 0xe2, 0xee, 0x96, 0x42, 0xe6, 0xb8, 0x22, 0xac, 0x74, 0x53, 0xf5, 0x2c, 0x62, + 0x01, 0xdb, 0x70, 0x8b, 0x0e, 0xfa, 0x88, 0xe1, 0xa3, 0xbe, 0x1d, 0xc0, 0xd8, 0x8f, 0x81, 0x0e, + 0xe5, 0xd1, 0xa1, 0x3d, 0xcf, 0xf6, 0xe3, 0xc1, 0x4f, 0x79, 0x95, 0xc0, 0x55, 0x2f, 0x0e, 0xfe, + 0x49, 0x85, 0x6c, 0xfa, 0x6b, 0xfd, 0x01, 0xa9, 0xc5, 0xd5, 0x34, 0x52, 0x09, 0xb8, 0x31, 0x52, + 0xd3, 0xaa, 0xed, 0x5b, 0x1f, 0xe3, 0xc1, 0x19, 0x93, 0x58, 0x23, 0xef, 0xae, 0xe6, 0x84, 0xae, + 0xfa, 0x12, 0xf4, 0x9f, 0x32, 0x24, 0x39, 0xa0, 0xd2, 0xeb, 0x00, 0x32, 0x11, 0x5d, 0x49, 0x93, + 0xb5, 0xaa, 0xbd, 0xba, 0xd9, 0xec, 0x59, 0xa0, 0x0b, 0x8e, 0x56, 0xda, 0x03, 0x08, 0x66, 0x2e, + 0xa2, 0x25, 0xa7, 0x42, 0xc1, 0x36, 0x3f, 0x9d, 0xb5, 0xb4, 0x12, 0xd1, 0x5f, 0x3d, 0x1a, 0x54, + 0x19, 0x2a, 0xcd, 0x30, 0xac, 0x2c, 0x8e, 0x04, 0xb7, 0x04, 0x62, 0x10, 0xe0, 0x81, 0x36, 0x20, + 0x73, 0x23, 0x2b, 0x29, 0x36, 0x6c, 0x8c, 0x88, 0xe5, 0xa2, 0x4f, 0xc1, 0xc6, 0xc1, 0x46, 0x02, + 0x65, 0xe3, 0xa5, 0xf1, 0x22, 0x7b, 0x5d, 0x18, 0x94, 0xaa, 0xa2, 0x4e, 0xba, 0x89, 0x57, 0x4c, + 0x05, 0x93, 0x6c, 0x97, 0xeb, 0x66, 0x50, 0x52, 0x1d, 0xfd, 0x9a, 0x61, 0x6e, 0x52, 0xfc, 0xc1, + 0x34, 0xae, 0xfb, 0x1e, 0xf2, 0xc6, 0x9a, 0x38, 0xa2, 0x4e, 0x85, 0xec, 0xb5, 0xc5, 0x41, 0xb6, + 0x1a, 0xa2, 0x05, 0xc5, 0xa2, 0x97, 0xbb, 0x6b, 0x86, 0x0c, 0x76, 0xe3, 0xef, 0xb1, 0x45, 0xb3, + 0xc8, 0x56, 0x8b, 0xd6, 0xf0, 0xd3, 0xca, 0xe0, 0xfb, 0x6a, 0x68, 0xcf, 0xb4, 0x85, 0x67, 0x1c, + 0x87, 0xf8, 0x27, 0xa5, 0x63, 0x32, 0x65, 0xea, 0x6d, 0xa3, 0xc4, 0x62, 0xdf, 0xd7, 0x89, 0x87, + 0x16, 0x52, 0x5d, 0xff, 0xb0, 0x9f, 0xbe, 0x22, 0x91, 0x85, 0x1d, 0x64, 0x06, 0x5f, 0xb1, 0x9c, + 0x10, 0xac, 0xe6, 0x4e, 0x3c, 0x81, 0xbf, 0xec, 0xdd, 0x5d, 0x2f, 0x64, 0x72, 0x11, 0x09, 0xfa, + 0xba, 0x47, 0xb4, 0x58, 0x0f, 0xd3, 0xf3, 0xff, 0xd4, 0x75, 0xf0, 0x5b, 0x42, 0xdc, 0xc9, 0x51, + 0x1b, 0xad, 0x95, 0xdc, 0x68, 0x3b, 0xf7, 0xb0, 0x75, 0xa1, 0xb3, 0x1d, 0x04, 0x4d, 0x66, 0x2b, + 0xf7, 0x9a, 0xde, 0xae, 0x72, 0x2c, 0xe9, 0x2d, 0xc9, 0x0e, 0x9c, 0x58, 0xe6, 0xee, 0x20, 0x2d, + 0xf3, 0x34, 0xf9, 0xe3, 0x67, 0x7b, 0x04, 0x97, 0xff, 0x53, 0x40, 0xd1, 0xbf, 0x85, 0xbe, 0x0d, + 0x3c, 0xb5, 0x08, 0xff, 0x7e, 0xd3, 0x75, 0x5b, 0x9e, 0x4c, 0xe3, 0x33, 0x11, 0x9d, 0x6c, 0x6d, + 0xc4, 0x9a, 0xac, 0xaf, 0x50, 0xb3, 0xe6, 0xe3, 0xc1, 0x50, 0x9c, 0x77, 0x2e, 0x64, 0xcb, 0xa7, + 0xaf, 0x2b, 0x73, 0xab, 0x67, 0xee, 0xfd, 0x4f, 0x52, 0xaf, 0xaf, 0x03, 0x81, 0x6b, 0x37, 0x41, + 0xba, 0xb8, 0x32, 0x40, 0xf3, 0xc5, 0xef, 0xeb, 0x54, 0xc5, 0x63, 0x15, 0x46, 0xe6, 0xf4, 0xf7, + 0xc9, 0xbb, 0xc4, 0x03, 0xcf, 0x71, 0x9e, 0x53, 0xef, 0x1c, 0x0d, 0x6f, 0x75, 0xa4, 0xb3, 0x85, + 0x3f, 0xd8, 0xc2, 0x37, 0x43, 0xdd, 0xd9, 0x91, 0x27, 0x27, 0xaa, 0x29, 0xee, 0x12, 0x83, 0x26, + 0x7e, 0xc4, 0x1c, 0xc4, 0x5a, 0xdb, 0x79, 0xa9, 0xed, 0x25, 0x43, 0x54, 0xc1, 0x75, 0x86, 0xed, + 0xd1, 0x7b, 0x4d, 0x4b, 0xb7, 0xc2, 0xf2, 0xd4, 0xa4, 0x6e, 0x4c, 0x76, 0x27, 0x9a, 0xcc, 0xfa, + 0xaf, 0xb9, 0x58, 0x1d, 0xe5, 0x1f, 0x4c, 0x67, 0x75, 0xc2, 0xb3, 0xbb, 0x61, 0xc4, 0x5d, 0x23, + 0x5b, 0x3c, 0x41, 0x09, 0x59, 0xa4, 0x81, 0x0e, 0x24, 0xa5, 0x5a, 0x8b, 0x22, 0xb3, 0x84, 0xa8, + 0x02, 0x27, 0x95, 0xc2, 0x96, 0xa5, 0x07, 0xe0, 0x40, 0xea, 0x39, 0x74, 0x8a, 0xb5, 0xa4, 0x9a, + 0x6f, 0x9e, 0x2a, 0x9e, 0x08, 0x6b, 0xdc, 0xd9, 0x2f, 0x80, 0x67, 0x33, 0xf2, 0xe5, 0x84, 0xec, + 0xa4, 0x95, 0xaa, 0x6b, 0x05, 0xa2, 0xcc, 0xb9, 0x2a, 0x28, 0x17, 0x34, 0x76, 0x82, 0x8b, 0x64, + 0xbc, 0xd2, 0x61, 0x97, 0x4b, 0xe8, 0xe2, 0x67, 0xe0, 0xf8, 0xb6, 0x06, 0xe6, 0x2b, 0x95, 0x1c, + 0x67, 0xbb, 0x74, 0x9b, 0xa0, 0x69, 0x1f, 0xf7, 0xd1, 0x2f, 0x4e, 0xe2, 0xaf, 0x46, 0x36, 0x79, + 0x92, 0x00, 0xc5, 0xdf, 0x52, 0xff, 0x95, 0x64, 0x35, 0x08, 0x05, 0x5d, 0xf0, 0xed, 0x3d, 0xfa, + 0x43, 0x55, 0x5d, 0xb5, 0xec, 0x12, 0x00, 0x12, 0xe6, 0x5c, 0x2e, 0xf5, 0x57, 0x58, 0x25, 0x3a, + 0x18, 0x68, 0xb4, 0xbe, 0xf7, 0x20, 0x27, 0xf1, 0x1e, 0xe0, 0x61, 0xd6, 0x32, 0x78, 0x97, 0x4a, + 0xb8, 0xcb, 0x54, 0xb3, 0x7a, 0xe4, 0x4c, 0x35, 0xee, 0x23, 0xe6, 0x51, 0x9d, 0x17, 0xaa, 0x41, + 0x53, 0xea, 0x7d, 0xfc, 0x0a, 0xf9, 0xbc, 0xf3, 0x68, 0x61, 0xab, 0x01, 0x6d, 0x95, 0xc8, 0x73, + 0x62, 0xf5, 0x01, 0x14, 0x8f, 0xa0, 0x6a, 0xc3, 0xce, 0x6d, 0xf5, 0x99, 0x38, 0xf4, 0x1d, 0xa0, + 0x65, 0x8b, 0xaf, 0x9d, 0xb1, 0x97, 0x5f, 0xe9, 0x9b, 0xf6, 0x74, 0xec, 0x6e, 0x68, 0x31, 0x24, + 0xe3, 0x84, 0xe8, 0xde, 0x89, 0x77, 0x63, 0x87, 0x0d, 0x57, 0xbc, 0x7a, 0x08, 0x6b, 0x47, 0xf7, + 0xde, 0xa1, 0x9a, 0x53, 0xbf, 0x6a, 0xcd, 0x5c, 0x86, 0xec, 0x1d, 0xf5, 0x8b, 0x1d, 0xf3, 0xc8, + 0x58, 0x69, 0xd0, 0x79, 0x4d, 0xff, 0x12, 0x6b, 0x7e, 0x57, 0xd9, 0xf9, 0xbb, 0x09, 0x62, 0x65, + 0xba, 0xd9, 0x40, 0x05, 0xd3, 0x93, 0x46, 0x82, 0x1e, 0xb5, 0x27, 0x86, 0x05, 0x63, 0x30, 0x61, + 0x81, 0x6a, 0x5b, 0xbf, 0xae, 0x5c, 0xc6, 0x9a, 0x3f, 0x98, 0x2e, 0x14, 0xc4, 0xc4, 0xbe, 0xc2, + 0x66, 0xf3, 0x25, 0x96, 0x65, 0xa1, 0x7b, 0x3a, 0xc3, 0x96, 0x91, 0x34, 0x97, 0x30, 0xc7, 0x50, + 0x51, 0xcd, 0x3a, 0x9e, 0xe0, 0x9e, 0x65, 0xed, 0xe5, 0xcd, 0xfe, 0x19, 0x26, 0xf0, 0x95, 0xf0, + 0x99, 0x33, 0x70, 0xaf, 0x3e, 0x5a, 0xbf, 0x8a, 0xaf, 0xaa, 0x4c, 0x7e, 0x56, 0xc3, 0x78, 0x90, + 0x8c, 0x28, 0x7d, 0x1d, 0x86, 0xd8, 0x52, 0xdb, 0xf2, 0x50, 0x25, 0x15, 0xec, 0x38, 0x07, 0x9c, + 0x0a, 0xb6, 0xc3, 0xf5, 0xab, 0x26, 0x85, 0x26, 0x36, 0x8e, 0x95, 0xd7, 0x90, 0x45, 0xc2, 0x54, + 0xdd, 0xc3, 0x2d, 0x24, 0xfd, 0x28, 0xd9, 0xd8, 0xa7, 0xf3, 0x21, 0x9c, 0xc1, 0x2a, 0x5a, 0x3c, + 0xbe, 0xac, 0xdd, 0x11, 0x9a, 0x59, 0xe6, 0xc8, 0x5d, 0xbd, 0xfa, 0xa5, 0x4a, 0xd3, 0xc5, 0xb2, + 0x7a, 0xa4, 0x96, 0x50, 0x15, 0x25, 0xbb, 0x38, 0xbd, 0x7f, 0x4f, 0xd4, 0xad, 0xd0, 0xc0, 0x85, + 0x87, 0xb8, 0x04, 0x03, 0x55, 0x82, 0x1a, 0x75, 0x5a, 0x2f, 0xf2, 0x88, 0xee, 0xb9, 0xc2, 0xe6, + 0xcd, 0x58, 0xb0, 0x37, 0x4a, 0x50, 0xa7, 0xfa, 0x20, 0x75, 0x49, 0x17, 0xd7, 0x28, 0x96, 0x05, + 0x82, 0xcd, 0x34, 0xd6, 0xf0, 0x3b, 0x37, 0x2f, 0xb5, 0x3b, 0x57, 0x18, 0x4a, 0x17, 0xc7, 0x89, + 0xd5, 0xd3, 0xe4, 0xe6, 0x10, 0x51, 0x7a, 0x4b, 0xcf, 0x66, 0x80, 0x27, 0xaa, 0x77, 0x69, 0x79, + 0x8f, 0x7b, 0x9a, 0xd0, 0x79, 0x65, 0x79, 0x2e, 0xbb, 0x45, 0x4d, 0x16, 0xbc, 0x9b, 0xe3, 0xfb, + 0x9c, 0x5d, 0x53, 0x1b, 0x62, 0x6a, 0x19, 0xfd, 0xf9, 0x4b, 0xbf, 0x51, 0xd3, 0x00, 0xb2, 0xc6, + 0x8f, 0xb6, 0x2e, 0x9d, 0x0c, 0x64, 0x75, 0x6a, 0x47, 0x05, 0x55, 0x55, 0xee, 0xff, 0xca, 0xf3, + 0x2b, 0x55, 0xcf, 0x50, 0x5c, 0x6c, 0xed, 0x23, 0x74, 0x87, 0xb0, 0x4b, 0x91, 0x3a, 0x84, 0xa8, + 0x4e, 0x12, 0x8d, 0xcf, 0xcc, 0x4a, 0x85, 0x67, 0x3f, 0x53, 0x05, 0xb9, 0x8f, 0x24, 0x73, 0xee, + 0x32, 0xe5, 0x2b, 0xdf, 0x6c, 0xf8, 0xb5, 0xb2, 0x1e, 0x85, 0xf9, 0x07, 0xd3, 0x89, 0xe2, 0x00, + 0xde, 0x9f, 0xe1, 0x95, 0x37, 0xba, 0xac, 0x39, 0x50, 0xd1, 0x55, 0x98, 0x45, 0x2d, 0xef, 0x22, + 0xdf, 0x36, 0xae, 0x34, 0xf6, 0xd8, 0x22, 0x93, 0x4e, 0x9e, 0x6b, 0xce, 0xb7, 0x56, 0x2e, 0xa2, + 0x08, 0x11, 0xf7, 0x5d, 0xff, 0xdd, 0x63, 0x93, 0xa6, 0xab, 0xf4, 0xa5, 0xa6, 0xe4, 0x7d, 0x66, + 0x00, 0x8e, 0xc4, 0x9c, 0xca, 0x76, 0x83, 0x53, 0xe9, 0xce, 0x30, 0xba, 0x0c, 0x81, 0xee, 0x84, + 0x4c, 0xad, 0x32, 0x06, 0x72, 0x3c, 0x4d, 0xe9, 0x35, 0x5e, 0xb8, 0xab, 0x22, 0xac, 0xf8, 0x60, + 0xd7, 0x63, 0xce, 0xe5, 0xcf, 0x6f, 0xf0, 0x05, 0x00, 0x0e, 0xa0, 0x3c, 0x2d, 0xee, 0x6a, 0x88, + 0x89, 0xd2, 0xb3, 0x4c, 0xe5, 0x24, 0xa4, 0x8a, 0xf8, 0xb7, 0xdb, 0x3a, 0x25, 0x0e, 0xc4, 0xd0, + 0x2d, 0x91, 0xf3, 0xa8, 0x53, 0x60, 0x9c, 0x76, 0xff, 0x22, 0xe2, 0xa2, 0xb5, 0x9e, 0x4e, 0xd5, + 0x2c, 0x9f, 0x25, 0xa5, 0x69, 0xc8, 0x97, 0x90, 0xec, 0x78, 0x60, 0xa6, 0x32, 0x87, 0xdc, 0x5c, + 0x52, 0x61, 0x45, 0xbd, 0x6b, 0x33, 0x1d, 0xbc, 0x4c, 0xb4, 0x07, 0x7a, 0x74, 0x86, 0xe6, 0x06, + 0x50, 0xca, 0x82, 0xb1, 0xb3, 0xf1, 0x62, 0x20, 0x5e, 0xbb, 0x09, 0xb1, 0x0b, 0x5e, 0xa4, 0xf1, + 0x7c, 0xd3, 0x70, 0x37, 0xc2, 0xeb, 0x30, 0x69, 0xe2, 0xa6, 0x73, 0x97, 0x6d, 0xde, 0x03, 0x86, + 0xf8, 0x4f, 0xf0, 0xd1, 0x58, 0xe4, 0x6b, 0xde, 0xba, 0x5c, 0xf5, 0x37, 0xf7, 0xfb, 0xaa, 0xe1, + 0xc2, 0xdf, 0xcd, 0x01, 0x8d, 0x40, 0x5a, 0x94, 0x28, 0x1e, 0xc7, 0xda, 0x79, 0x48, 0x63, 0xda, + 0x04, 0x64, 0x5b, 0xb0, 0xb5, 0xe8, 0xc2, 0x17, 0x72, 0x11, 0xcd, 0x8f, 0x31, 0x38, 0xb8, 0xf2, + 0xe0, 0xcc, 0xac, 0x4a, 0x37, 0x88, 0xac, 0x7a, 0xc5, 0x95, 0xa4, 0xaa, 0xfa, 0x58, 0xa7, 0x64, + 0x34, 0xe9, 0x4f, 0xf7, 0x32, 0xb3, 0x3c, 0x9d, 0xab, 0x69, 0xbd, 0xae, 0x30, 0x84, 0x75, 0x57, + 0x8b, 0x7a, 0xd9, 0x21, 0x31, 0xf8, 0x5c, 0xad, 0x99, 0x7e, 0xad, 0x8d, 0x65, 0xfa, 0x83, 0x69, + 0xaa, 0x5e, 0x62, 0xeb, 0xb2, 0xe5, 0xd7, 0x22, 0x78, 0x21, 0xec, 0x28, 0x6f, 0x3d, 0x7f, 0x11, + 0x5f, 0xdf, 0x5c, 0x42, 0xc6, 0x76, 0x6b, 0x6c, 0xe0, 0xa6, 0x76, 0xb9, 0xf7, 0x85, 0x6e, 0xf7, + 0x99, 0x9a, 0x4b, 0xb7, 0xa0, 0x2f, 0x27, 0x58, 0x07, 0xc2, 0x4c, 0x48, 0x9d, 0x54, 0x72, 0xce, + 0x5a, 0x89, 0xe8, 0xa1, 0x0e, 0x5d, 0x34, 0x69, 0x5f, 0xce, 0x5e, 0x45, 0x24, 0x44, 0x27, 0xfa, + 0x7e, 0x0b, 0xb9, 0xa5, 0xf6, 0x6b, 0x32, 0x68, 0xa4, 0x15, 0x84, 0xe6, 0xdb, 0x26, 0x38, 0x96, + 0xd6, 0xc3, 0xaf, 0xb4, 0xc4, 0xb3, 0xe8, 0x2e, 0x2e, 0x8b, 0x26, 0x65, 0x1d, 0x50, 0x5e, 0xd3, + 0x0d, 0xc7, 0xba, 0x7b, 0xf1, 0x74, 0x9a, 0xc8, 0x20, 0x99, 0x9c, 0x38, 0x95, 0x8c, 0xa7, 0x0d, + 0x87, 0xe7, 0x7e, 0x55, 0x34, 0xe4, 0x41, 0xd6, 0xab, 0x39, 0xe1, 0xbe, 0xaa, 0x20, 0xb6, 0x0d, + 0x92, 0xa3, 0x6b, 0xf1, 0x14, 0xa7, 0x9f, 0x04, 0x69, 0xc9, 0xc7, 0x90, 0x85, 0xd4, 0x6a, 0x63, + 0x6b, 0xb1, 0x57, 0xc2, 0xbf, 0xcb, 0x5c, 0xd2, 0x1a, 0x6c, 0x71, 0x6a, 0xce, 0x79, 0x32, 0xa5, + 0xce, 0x3e, 0xfe, 0x68, 0xe6, 0x1b, 0xf0, 0x7d, 0x90, 0x26, 0x2f, 0xbd, 0x9a, 0xb0, 0x08, 0x19, + 0xdc, 0xa2, 0xa9, 0x8c, 0x27, 0x75, 0x45, 0xc9, 0x73, 0x76, 0x7b, 0xb1, 0x60, 0xbb, 0x3b, 0xcc, + 0xe6, 0x0c, 0x5b, 0x5d, 0x1a, 0x54, 0x33, 0x35, 0xa5, 0xa5, 0xd4, 0x4d, 0xef, 0x53, 0x4c, 0xe4, + 0xc3, 0x99, 0x92, 0xaa, 0x76, 0xcc, 0x12, 0x03, 0x6a, 0xcd, 0x27, 0xf6, 0x7f, 0xa6, 0x06, 0x16, + 0xac, 0xde, 0x4a, 0x34, 0x8d, 0xe7, 0x3f, 0xdf, 0xa3, 0xc6, 0x34, 0xba, 0xd4, 0x34, 0x06, 0xae, + 0xb0, 0xbe, 0x31, 0xae, 0xb9, 0x08, 0x6b, 0x1e, 0x2d, 0xe3, 0xd2, 0x18, 0xb9, 0xa0, 0x0c, 0x8e, + 0x84, 0x53, 0xda, 0xbd, 0x73, 0xbb, 0xa7, 0xc8, 0xa5, 0x6a, 0x33, 0xcc, 0xbc, 0x26, 0x38, 0x1c, + 0xcc, 0xf2, 0x0d, 0x33, 0x43, 0x93, 0xdf, 0xd7, 0x5c, 0xe4, 0x3d, 0x6a, 0x7e, 0xad, 0x23, 0x84, + 0x58, 0xff, 0x60, 0x9a, 0xa1, 0x92, 0xc0, 0xdd, 0xcd, 0xbe, 0x05, 0x8c, 0x7c, 0x6a, 0xda, 0x5c, + 0xcf, 0x16, 0xde, 0x9d, 0xaf, 0x59, 0x60, 0xe9, 0xec, 0xfb, 0x9b, 0x98, 0x30, 0x3d, 0x3f, 0xb1, + 0xe8, 0x65, 0xfb, 0xd2, 0x47, 0xaf, 0xc0, 0x8c, 0x3c, 0xe7, 0xb7, 0x88, 0xa1, 0x9e, 0x3b, 0x5c, + 0x18, 0x97, 0x65, 0x04, 0x85, 0x2e, 0x91, 0x9c, 0x8c, 0x23, 0x89, 0xd3, 0x97, 0xfa, 0x2d, 0xde, + 0xf2, 0xd2, 0xc6, 0xa7, 0xf9, 0xb5, 0x23, 0xd3, 0xa3, 0x6a, 0xe0, 0xbe, 0x64, 0xfc, 0x33, 0x5c, + 0x50, 0x96, 0x0c, 0x62, 0xcf, 0x66, 0x1d, 0x70, 0x1d, 0x41, 0xf2, 0x73, 0x38, 0x44, 0xc9, 0x7c, + 0x73, 0xb5, 0x96, 0x33, 0x3b, 0xc7, 0xc8, 0x34, 0x3f, 0x78, 0x80, 0xb7, 0xda, 0x77, 0xc9, 0xb3, + 0xe2, 0xf0, 0x61, 0x4a, 0xe6, 0x0b, 0x3b, 0xc7, 0xaf, 0xb2, 0xbc, 0xe4, 0x3c, 0x3d, 0xd9, 0x03, + 0xfc, 0xcd, 0x06, 0xbb, 0x78, 0x17, 0x37, 0x2d, 0xc8, 0x76, 0xd5, 0x38, 0x68, 0x31, 0xb6, 0x09, + 0x86, 0x5e, 0x3b, 0xb5, 0x30, 0x07, 0x3b, 0xb1, 0xb4, 0x35, 0xb2, 0x4e, 0x69, 0xe7, 0xb9, 0xa7, + 0xff, 0xea, 0xcd, 0x3d, 0x24, 0x71, 0x53, 0xff, 0xd1, 0x9b, 0x9a, 0xa4, 0x76, 0x52, 0xa8, 0x7a, + 0xb7, 0xa8, 0x6b, 0xf4, 0x1e, 0x2e, 0x7c, 0xb7, 0xaf, 0x4b, 0x6e, 0x82, 0x0e, 0xbd, 0xc9, 0xae, + 0xab, 0x05, 0xe6, 0x79, 0x23, 0x43, 0xec, 0x82, 0xb0, 0xd4, 0xb2, 0x94, 0x17, 0x77, 0x22, 0x12, + 0xc9, 0xf1, 0xab, 0x82, 0x7e, 0x72, 0x7c, 0xa4, 0x30, 0x45, 0x4c, 0xc2, 0x6c, 0x1a, 0x6c, 0x89, + 0x9f, 0x99, 0x96, 0xb5, 0x63, 0x1c, 0x32, 0xe8, 0xa7, 0x56, 0x95, 0x58, 0xe1, 0xb1, 0x71, 0x4a, + 0xd7, 0x0b, 0xba, 0xbc, 0xc8, 0xf8, 0x82, 0x56, 0x0b, 0xfe, 0x21, 0x8d, 0x4d, 0xfa, 0xdb, 0x93, + 0x07, 0x4c, 0x61, 0x7d, 0x6e, 0xc3, 0x40, 0xfa, 0x7d, 0xb0, 0x3e, 0x65, 0x28, 0xdb, 0x7c, 0x73, + 0x57, 0xb4, 0xd2, 0xf2, 0x83, 0x48, 0x7b, 0xa4, 0x25, 0x9b, 0xcb, 0x16, 0x1f, 0xc9, 0x6a, 0x7f, + 0x3b, 0x81, 0x7f, 0xad, 0x61, 0x28, 0xfa, 0xad, 0xe9, 0x8f, 0xfc, 0xe0, 0x0f, 0x3e, 0xf8, 0xe0, + 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, + 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0x0f, 0x3e, 0xf8, 0xe0, 0x83, 0xff, + 0x9e, 0xfc, 0xe7, 0x79, 0xb0, 0x2b, 0x8b, 0x61, 0x1d, 0x8f, 0x6a, 0x74, 0x71, 0x70, 0xb4, 0xf0, + 0x45, 0x73, 0xd8, 0x94, 0xf2, 0x72, 0x72, 0x5f, 0x2b, 0xa9, 0x82, 0x67, 0x82, 0xf3, 0xec, 0x9b, + 0x69, 0xab, 0xc7, 0xdb, 0xad, 0x14, 0x56, 0x6c, 0xda, 0xab, 0x5c, 0xda, 0xb6, 0x45, 0x16, 0x80, + 0xbd, 0x75, 0xe9, 0x52, 0xd1, 0x66, 0x37, 0xf7, 0x56, 0xbd, 0x76, 0x57, 0x91, 0x23, 0x3a, 0x92, + 0x2e, 0x44, 0x8c, 0x37, 0xa9, 0xeb, 0xd4, 0x41, 0xe0, 0x5e, 0xd4, 0xe3, 0x46, 0x24, 0x55, 0x28, + 0x79, 0xf7, 0xef, 0xd5, 0xa8, 0xba, 0xdc, 0xa2, 0xf4, 0xda, 0x03, 0x5a, 0xa7, 0xc8, 0x79, 0xab, + 0x13, 0xa6, 0x42, 0x03, 0x66, 0xf5, 0x78, 0xdb, 0x41, 0x84, 0xf5, 0x38, 0x34, 0xe7, 0xac, 0x29, + 0x63, 0x07, 0xcd, 0x68, 0x2c, 0xcd, 0x38, 0x6b, 0x74, 0x8f, 0xdd, 0x3e, 0x8e, 0xde, 0x2e, 0x96, + 0x99, 0xff, 0x1c, 0xee, 0x4b, 0x3e, 0xef, 0x85, 0x16, 0x8e, 0x13, 0x07, 0x7d, 0x4f, 0x90, 0xbb, + 0xf7, 0x70, 0xd6, 0x91, 0xec, 0x49, 0x96, 0x5e, 0x17, 0xb4, 0x07, 0x87, 0xbd, 0xc7, 0xbb, 0xc3, + 0x6e, 0x27, 0xec, 0x3a, 0xfe, 0xf5, 0xc4, 0x2d, 0x13, 0x05, 0xfa, 0x7d, 0x8e, 0x28, 0x76, 0x99, + 0x7a, 0x3b, 0x1c, 0x59, 0xbe, 0xbb, 0x51, 0xa5, 0x4d, 0xfc, 0x48, 0xe7, 0x03, 0xb2, 0x53, 0xf5, + 0x57, 0xf3, 0xe4, 0xc5, 0xa3, 0xc8, 0x4d, 0x8f, 0x42, 0x7c, 0x6e, 0x06, 0x1f, 0x12, 0x45, 0xb9, + 0xde, 0xd3, 0xeb, 0x03, 0x5b, 0xca, 0xbe, 0xe8, 0x6a, 0xf4, 0xef, 0x45, 0x09, 0x1b, 0xb8, 0xaa, + 0x17, 0x32, 0x77, 0xff, 0x96, 0x35, 0xaf, 0xba, 0x03, 0xbb, 0x2d, 0xf7, 0x98, 0x5a, 0x91, 0xe7, + 0xce, 0x42, 0x5f, 0xcd, 0xad, 0x74, 0xba, 0xc3, 0xc9, 0x8c, 0x7e, 0xe6, 0xf6, 0xdc, 0x4f, 0x2f, + 0x89, 0xe7, 0xb3, 0xb1, 0x7f, 0xd0, 0x70, 0xde, 0x0e, 0x96, 0x74, 0x07, 0xc2, 0x01, 0x73, 0x85, + 0x3d, 0x5c, 0xb0, 0xc4, 0xf7, 0x4c, 0x74, 0xe6, 0xaa, 0x2b, 0xce, 0x98, 0xee, 0xc6, 0xae, 0x7c, + 0xcf, 0x45, 0x60, 0xbc, 0x83, 0x01, 0x51, 0xe3, 0x14, 0x23, 0xe5, 0x47, 0xde, 0xf6, 0xa5, 0x04, + 0xe8, 0x52, 0xf6, 0xd4, 0x5e, 0x75, 0xfb, 0x85, 0xdb, 0x88, 0x6b, 0x9a, 0x8e, 0xfb, 0x18, 0xd2, + 0x38, 0x15, 0x0f, 0x83, 0x4c, 0xd3, 0x4b, 0xe5, 0x95, 0x05, 0x6c, 0xb7, 0xec, 0xe8, 0xe9, 0x14, + 0xde, 0xd4, 0xab, 0x0c, 0xb2, 0x65, 0xf0, 0xda, 0x46, 0xae, 0xd6, 0x1f, 0x4f, 0x86, 0xd3, 0x74, + 0x6c, 0x6a, 0xa7, 0x73, 0x1c, 0x29, 0x22, 0xfe, 0x85, 0xbb, 0xfd, 0x6a, 0xa5, 0xf1, 0xce, 0x90, + 0x04, 0xb8, 0x86, 0xa5, 0x96, 0xac, 0x1c, 0x6f, 0xd3, 0x52, 0xe3, 0xaa, 0x46, 0x13, 0x81, 0x13, + 0x5e, 0x5e, 0x68, 0xb5, 0x6f, 0x52, 0xeb, 0x19, 0xbf, 0x21, 0x44, 0x28, 0xc3, 0x96, 0x83, 0xec, + 0xdb, 0x3d, 0x4e, 0xd4, 0xdf, 0xda, 0x6a, 0xf3, 0xa8, 0x00, 0xdb, 0xcf, 0xc9, 0xff, 0xd5, 0x04, + 0xc5, 0x47, 0x11, 0xc4, 0x84, 0xd2, 0xcd, 0x45, 0x25, 0xe7, 0x94, 0xae, 0x60, 0x83, 0xcd, 0x6a, + 0x8d, 0x27, 0xf3, 0x0e, 0xe7, 0x30, 0xf9, 0xd6, 0x7e, 0xbb, 0xa9, 0xd9, 0x3e, 0xc0, 0x63, 0x29, + 0xc9, 0x85, 0xac, 0x06, 0xe8, 0xbc, 0x3a, 0x7a, 0xb5, 0xf5, 0xeb, 0x9e, 0x24, 0x85, 0xe2, 0x0f, + 0xa6, 0xc3, 0x00, 0x88, 0xd3, 0x88, 0x85, 0xfb, 0x40, 0x5a, 0x9a, 0x97, 0xd7, 0xb4, 0x44, 0x84, + 0x4d, 0xba, 0xb2, 0x52, 0xc9, 0x91, 0xb5, 0x35, 0xe0, 0xb4, 0x13, 0x6d, 0x8b, 0x6d, 0xcb, 0x4e, + 0x4b, 0x90, 0xa1, 0xea, 0x20, 0x7d, 0xd0, 0xa5, 0x16, 0xb5, 0xde, 0xae, 0xb2, 0xad, 0x3c, 0x94, + 0x7b, 0xea, 0x4b, 0x22, 0xe0, 0xf8, 0x98, 0x00, 0x1e, 0x7a, 0xcf, 0x02, 0xa7, 0x8a, 0x04, 0x4b, + 0x98, 0xb0, 0x7d, 0xcd, 0x12, 0xbd, 0xfc, 0xdb, 0xd4, 0x93, 0xcb, 0xbd, 0xd5, 0x31, 0x7f, 0x4b, + 0x26, 0x0f, 0x45, 0xbd, 0xa1, 0x5e, 0x98, 0xad, 0x51, 0xeb, 0x48, 0x8f, 0xc9, 0xaf, 0x3b, 0xcd, + 0x34, 0xef, 0x62, 0x56, 0x19, 0x51, 0x1b, 0xcb, 0x64, 0xe6, 0xf7, 0x06, 0xd9, 0x8b, 0x0d, 0x28, + 0x11, 0xf7, 0xb5, 0x85, 0x93, 0x8a, 0x19, 0x33, 0xb1, 0xcc, 0xba, 0x67, 0xbe, 0x90, 0xda, 0x5d, + 0xf7, 0x9a, 0xd3, 0x55, 0xdd, 0x76, 0x50, 0xf9, 0x30, 0x14, 0x06, 0xdb, 0xd0, 0x41, 0x98, 0x94, + 0x8d, 0x6e, 0x08, 0x93, 0x3c, 0x2e, 0x20, 0xeb, 0x32, 0xce, 0x1b, 0xa5, 0xcf, 0x23, 0xbd, 0x9e, + 0x59, 0xa5, 0x7c, 0x03, 0x59, 0x7d, 0xb1, 0x10, 0xd4, 0x2d, 0xcd, 0xe3, 0x91, 0x3d, 0xc2, 0x4f, + 0x5e, 0x5b, 0xae, 0x6d, 0xaa, 0xa9, 0xa4, 0x1a, 0x55, 0x25, 0xc7, 0xb3, 0xe9, 0x88, 0xc5, 0x8e, + 0xb3, 0xc5, 0xe7, 0x21, 0x16, 0xeb, 0xda, 0xc9, 0x20, 0xff, 0x07, 0x7b, 0xe7, 0xf7, 0x5b, 0xca, + 0xda, 0xf7, 0xff, 0x7f, 0x66, 0x5b, 0x0d, 0xb6, 0x36, 0x59, 0x7b, 0x6b, 0xa3, 0xbd, 0x75, 0x1d, + 0x77, 0x2c, 0x24, 0xc3, 0x10, 0x94, 0x9e, 0x2c, 0x6d, 0x50, 0x24, 0x5a, 0xa4, 0x54, 0xf7, 0xff, + 0x80, 0x21, 0xf5, 0xa3, 0x3d, 0x31, 0x15, 0xa3, 0x43, 0xa2, 0x86, 0xa0, 0xf4, 0x18, 0x9b, 0x26, + 0x18, 0x82, 0xe2, 0xa4, 0x2a, 0x28, 0x4d, 0xda, 0x85, 0xb4, 0x5d, 0x5d, 0xfb, 0xdb, 0x75, 0xdf, + 0x77, 0x9e, 0xe7, 0x7e, 0x9e, 0xb5, 0x7b, 0xf0, 0x3d, 0xf9, 0x1e, 0x7c, 0xd3, 0xd7, 0x81, 0x54, + 0xaf, 0xb9, 0x06, 0x6f, 0x73, 0x5d, 0xd7, 0xe7, 0x1a, 0x9f, 0x1f, 0x5c, 0xd4, 0x43, 0xac, 0xe5, + 0xa0, 0xeb, 0xae, 0x08, 0xd4, 0xd9, 0x1f, 0x19, 0x1c, 0xfe, 0xf4, 0x78, 0x25, 0xc6, 0x3f, 0x96, + 0xab, 0x41, 0x33, 0x51, 0x41, 0xe3, 0x95, 0xda, 0x49, 0xa0, 0x29, 0x98, 0x22, 0x59, 0x36, 0xcf, + 0x35, 0xab, 0x7f, 0x6c, 0x6c, 0x74, 0x39, 0x89, 0xe1, 0xec, 0x1f, 0xc4, 0xd4, 0xb0, 0x6f, 0x3f, + 0xc1, 0xf8, 0xdf, 0x1a, 0x17, 0x97, 0xd2, 0xe8, 0xa1, 0x3a, 0x98, 0x36, 0x52, 0xdb, 0x77, 0x9a, + 0x1d, 0x8b, 0xf9, 0x8c, 0x3f, 0xbe, 0x2d, 0xa6, 0x72, 0x2d, 0xf3, 0x9d, 0xa4, 0xa3, 0xff, 0x1b, + 0x3f, 0x3b, 0xc5, 0x1b, 0x4a, 0x67, 0x95, 0x98, 0x0c, 0xfd, 0xe1, 0x00, 0xeb, 0x22, 0x14, 0xd8, + 0x3e, 0x4a, 0xa8, 0xc1, 0xed, 0x7a, 0x9c, 0xb3, 0x7f, 0x85, 0x88, 0xd6, 0xc6, 0x5f, 0x91, 0xa5, + 0x95, 0xa4, 0x56, 0x33, 0xb1, 0xb4, 0x4a, 0x08, 0x3d, 0x7b, 0x6e, 0xef, 0xc6, 0x72, 0x3a, 0x3b, + 0xbe, 0xd8, 0x16, 0xf3, 0xf4, 0xb8, 0x06, 0xd4, 0x5a, 0x02, 0xcb, 0x00, 0xac, 0x67, 0xb0, 0x24, + 0x76, 0x5f, 0x00, 0xd0, 0x55, 0x2b, 0x89, 0x81, 0x59, 0xba, 0x98, 0x00, 0x6b, 0x20, 0x42, 0x01, + 0x40, 0x5f, 0x17, 0x30, 0x6d, 0x3b, 0x49, 0xf3, 0x8a, 0x62, 0xb9, 0x2f, 0x07, 0x20, 0x9b, 0x3d, + 0xc0, 0xab, 0x0a, 0x60, 0x36, 0x68, 0xf1, 0x56, 0xbb, 0x66, 0xa9, 0x7d, 0x3a, 0x58, 0x93, 0xd8, + 0xbb, 0x72, 0x50, 0xc9, 0xb3, 0xe3, 0xca, 0xcf, 0x76, 0xb4, 0x05, 0xde, 0x7b, 0xe9, 0x24, 0x29, + 0xe8, 0x55, 0xcc, 0xe7, 0x78, 0xf6, 0xeb, 0x96, 0x52, 0xf2, 0xe5, 0x34, 0xab, 0xe3, 0x61, 0xb7, + 0x48, 0x00, 0xe4, 0x1f, 0x2e, 0x03, 0x65, 0x9c, 0x4a, 0x2b, 0x5a, 0x2b, 0xdd, 0x80, 0xc6, 0x11, + 0xf5, 0xa1, 0xc0, 0x06, 0x1f, 0x4f, 0x3f, 0xf2, 0x61, 0x3a, 0x83, 0x0b, 0x39, 0x49, 0xd8, 0xce, + 0xba, 0xa3, 0x9b, 0x36, 0xfc, 0x08, 0x83, 0x67, 0x6f, 0x9c, 0x62, 0x8a, 0x9c, 0xc0, 0x4a, 0xa8, + 0x97, 0x04, 0x25, 0x58, 0xbd, 0xcc, 0x82, 0xa2, 0x84, 0xc4, 0x6e, 0xaf, 0xe0, 0x02, 0x93, 0xf5, + 0x31, 0x5b, 0xe6, 0xc2, 0xa9, 0xf4, 0xfc, 0xc4, 0x0a, 0x23, 0x34, 0x31, 0x38, 0x41, 0xd8, 0x3a, + 0x9b, 0x01, 0x59, 0xb6, 0xde, 0xba, 0x03, 0x6b, 0x00, 0x0c, 0x13, 0x6b, 0x02, 0xe1, 0x02, 0x89, + 0x2d, 0x84, 0xba, 0x90, 0x0c, 0xaa, 0xc1, 0x7d, 0xb3, 0x44, 0x25, 0xfd, 0x11, 0x7f, 0x63, 0x0f, + 0x98, 0xaa, 0x4e, 0x4c, 0x6d, 0xf9, 0x7c, 0x3d, 0x22, 0x51, 0x3f, 0x5b, 0x91, 0x9c, 0xa0, 0x5a, + 0x45, 0x44, 0x40, 0xc3, 0xd1, 0x92, 0xab, 0x30, 0xcf, 0xdf, 0xf8, 0x8e, 0xaa, 0xdf, 0x50, 0xba, + 0xf0, 0x9d, 0x93, 0x76, 0x4f, 0xc5, 0x99, 0x6d, 0x27, 0xa1, 0x31, 0x63, 0xde, 0xd5, 0xa0, 0x4b, + 0x1c, 0xe4, 0x36, 0xbf, 0x5e, 0x79, 0x6f, 0xc4, 0xc9, 0x41, 0xea, 0x93, 0xc5, 0xa1, 0xec, 0x92, + 0x6a, 0x9f, 0x47, 0x88, 0x22, 0x58, 0x9e, 0x36, 0x15, 0xca, 0x3b, 0xad, 0xe3, 0xa4, 0xac, 0x8a, + 0x5e, 0xec, 0x89, 0x23, 0xc7, 0xd2, 0xd5, 0xa6, 0x38, 0x56, 0xff, 0xa0, 0x37, 0xf2, 0xe6, 0xfd, + 0xbf, 0xdd, 0xab, 0xce, 0xc3, 0xe1, 0x63, 0x48, 0xb5, 0x54, 0x9e, 0x62, 0xe2, 0x4c, 0x43, 0xba, + 0x41, 0x55, 0x36, 0x22, 0xb0, 0xe7, 0x69, 0xaf, 0x9c, 0x0e, 0x2a, 0x92, 0xb8, 0x14, 0x22, 0x1e, + 0x66, 0xea, 0x20, 0x59, 0x9d, 0x4f, 0x0d, 0xb7, 0x8c, 0x1c, 0xf9, 0x8a, 0xa2, 0x99, 0x91, 0xf6, + 0xc5, 0x75, 0xa5, 0x1f, 0x5e, 0x0a, 0xc5, 0x8e, 0x37, 0xfb, 0xcc, 0xd8, 0xf1, 0x0d, 0x2e, 0xe1, + 0xaa, 0x7d, 0xe8, 0x9d, 0x23, 0x78, 0xcc, 0x6d, 0xef, 0x3e, 0x55, 0x51, 0xf3, 0xd1, 0x68, 0xd3, + 0xbf, 0x84, 0x95, 0xa5, 0xa2, 0x20, 0xc7, 0x79, 0x8a, 0x08, 0x63, 0xee, 0x84, 0x40, 0x29, 0x0c, + 0xba, 0x8d, 0x55, 0xf0, 0xe9, 0x5f, 0x71, 0xef, 0x22, 0x96, 0xf2, 0xe9, 0xe6, 0x82, 0x65, 0x53, + 0x23, 0x27, 0x12, 0x0f, 0xea, 0x7b, 0xca, 0x6d, 0x7c, 0xf1, 0xd5, 0x33, 0x17, 0x9b, 0x88, 0x39, + 0xa5, 0x7e, 0x6a, 0x0d, 0xf7, 0x04, 0xfb, 0x95, 0x1e, 0xef, 0x6e, 0x9f, 0x58, 0x55, 0x85, 0x54, + 0xf2, 0x35, 0xc6, 0x19, 0x86, 0x16, 0x58, 0x3b, 0xae, 0x67, 0x95, 0x81, 0x6f, 0xad, 0x0e, 0x1a, + 0xe5, 0x0d, 0xed, 0x72, 0x6e, 0x6c, 0x68, 0x02, 0x2f, 0x2e, 0xc7, 0x28, 0x7f, 0xa0, 0xea, 0xd4, + 0x45, 0x2f, 0x42, 0x57, 0x34, 0x2e, 0x95, 0x9c, 0x13, 0xab, 0x6c, 0x59, 0x19, 0x43, 0x89, 0xd7, + 0x86, 0xc0, 0x22, 0x1c, 0x1a, 0x63, 0x77, 0xeb, 0xbd, 0xf0, 0x9c, 0x78, 0xa4, 0x86, 0xaa, 0xf7, + 0x67, 0xa3, 0xd3, 0xa7, 0x83, 0x07, 0x5b, 0x0c, 0x27, 0x3c, 0xa3, 0x9f, 0x3d, 0xcf, 0xe9, 0xf4, + 0x37, 0x94, 0x4e, 0x70, 0xc4, 0x76, 0x7c, 0xe1, 0x72, 0xdb, 0x56, 0xc9, 0x82, 0x9f, 0x89, 0x0f, + 0xfd, 0x17, 0xb1, 0x95, 0x58, 0x5b, 0xe6, 0xdb, 0xf4, 0x6b, 0x14, 0xfe, 0x90, 0x8f, 0x70, 0x38, + 0xf6, 0x6b, 0x9c, 0xc3, 0xb5, 0x5f, 0x13, 0x9c, 0xdc, 0xdd, 0xaf, 0x09, 0x2e, 0x6f, 0xf8, 0xc3, + 0xa9, 0xce, 0x4d, 0xeb, 0xe9, 0x09, 0x42, 0x36, 0x9e, 0xe8, 0xad, 0xc3, 0xc7, 0xc5, 0x4b, 0x43, + 0x53, 0xb5, 0x12, 0xc2, 0x94, 0xfe, 0x35, 0x99, 0xad, 0xb7, 0x59, 0xaf, 0x94, 0x10, 0xf3, 0x01, + 0x1c, 0x9a, 0x76, 0x98, 0xea, 0x12, 0x62, 0x3a, 0x8b, 0x7d, 0x23, 0xaa, 0x3c, 0x27, 0x98, 0x10, + 0x6b, 0x3d, 0xd1, 0xfe, 0x1d, 0x0a, 0x4f, 0x7e, 0xcf, 0x5c, 0x96, 0x63, 0xf5, 0x45, 0x6c, 0x0c, + 0x26, 0xb6, 0x88, 0x83, 0x19, 0x7d, 0x59, 0x7f, 0x26, 0xf6, 0x65, 0x1f, 0x6a, 0x5b, 0x96, 0x46, + 0xce, 0xd4, 0x9e, 0x3e, 0xe1, 0xfb, 0x4f, 0xc9, 0x13, 0x56, 0xcb, 0x43, 0x30, 0xef, 0x54, 0xfc, + 0x5e, 0x0a, 0xaa, 0xf2, 0xe2, 0xb3, 0x9d, 0x81, 0x0b, 0x1d, 0x14, 0x94, 0xde, 0xda, 0x05, 0x19, + 0x94, 0xf5, 0xeb, 0xa9, 0x23, 0x7d, 0x02, 0x7b, 0x30, 0x38, 0xfc, 0xf1, 0x94, 0xcb, 0xd9, 0x4b, + 0x25, 0x80, 0xa3, 0xef, 0x63, 0xe5, 0xb1, 0xec, 0xeb, 0x94, 0x67, 0xb1, 0xd5, 0x99, 0x53, 0x57, + 0xe7, 0x1f, 0x33, 0x33, 0x0e, 0x23, 0xec, 0xec, 0xf9, 0x51, 0xdf, 0x28, 0xad, 0x69, 0x8d, 0xf5, + 0xe5, 0xcb, 0x1f, 0x45, 0x84, 0x8f, 0x8e, 0x46, 0xf4, 0x83, 0x96, 0x8b, 0xc8, 0x52, 0xa4, 0x9e, + 0x4c, 0xe8, 0x65, 0xa0, 0x3f, 0x42, 0x0f, 0x3c, 0x67, 0x71, 0xfa, 0xc8, 0x12, 0xf1, 0xca, 0xd3, + 0x1b, 0x46, 0x3a, 0x6d, 0xda, 0x3a, 0x0d, 0xd0, 0xa6, 0xf1, 0xed, 0x5a, 0x32, 0xc2, 0x1f, 0x79, + 0x0b, 0x02, 0xc7, 0xb7, 0xa7, 0xe4, 0x9e, 0x19, 0x6f, 0x15, 0x00, 0xf3, 0xfd, 0x24, 0x71, 0x66, + 0xe6, 0x35, 0x59, 0x79, 0xee, 0x66, 0xbc, 0x58, 0x3c, 0xda, 0xa8, 0x3c, 0xd2, 0x06, 0xa5, 0xbf, + 0xf1, 0x1d, 0xd5, 0xbf, 0xa1, 0x34, 0xf9, 0xa3, 0xd6, 0x6d, 0xa4, 0x51, 0x72, 0x5d, 0x7a, 0x5f, + 0x7f, 0x7e, 0xf6, 0x07, 0x05, 0xf0, 0x20, 0x72, 0xc5, 0x9e, 0xcc, 0xf7, 0x42, 0xaa, 0x81, 0x1d, + 0x67, 0x9a, 0x7c, 0xd0, 0xfa, 0x47, 0xd6, 0xe0, 0x26, 0xc8, 0x14, 0x8d, 0xd5, 0x4f, 0x16, 0x89, + 0x65, 0x4e, 0x85, 0x70, 0x4d, 0x5f, 0x49, 0x2c, 0x4b, 0xa5, 0xde, 0xf9, 0x6e, 0x32, 0xe7, 0x64, + 0xa4, 0x55, 0x6e, 0x3b, 0x3e, 0xaf, 0x73, 0x1d, 0x21, 0x85, 0xcc, 0x4c, 0x4a, 0x46, 0x44, 0x0e, + 0x39, 0x51, 0xa0, 0x7e, 0xf6, 0x46, 0xd1, 0xbd, 0x1c, 0x44, 0xee, 0xb0, 0x74, 0xeb, 0x44, 0x92, + 0x05, 0x0c, 0xf9, 0x37, 0xd9, 0xa9, 0x61, 0xb6, 0x37, 0x6d, 0x11, 0x50, 0x30, 0x11, 0xe3, 0x1f, + 0xb6, 0xd6, 0xdc, 0xaf, 0x0b, 0xc2, 0x22, 0x50, 0xfa, 0x51, 0x72, 0xee, 0xf8, 0xcb, 0x20, 0x26, + 0x38, 0xa3, 0x5d, 0xec, 0xa0, 0x9e, 0x7e, 0x97, 0xc3, 0xf3, 0x1b, 0xb0, 0x12, 0xd0, 0xd2, 0x34, + 0xb8, 0xbc, 0x6b, 0x64, 0x64, 0xe4, 0xf5, 0x9c, 0xbd, 0x15, 0x6f, 0xf5, 0xb0, 0x75, 0xc9, 0xbb, + 0xed, 0x2c, 0x0a, 0x04, 0x91, 0xd3, 0x2c, 0x13, 0xf4, 0xaa, 0x47, 0xa6, 0x75, 0x3f, 0x8d, 0x7e, + 0x77, 0x54, 0x3b, 0xea, 0x49, 0x9d, 0x5b, 0xbf, 0xf8, 0x95, 0xdb, 0xd6, 0x53, 0x9c, 0x0b, 0xfb, + 0x5e, 0x56, 0xa5, 0x5f, 0x3b, 0xa4, 0x96, 0x40, 0xd2, 0x55, 0xef, 0x71, 0xe0, 0xaf, 0xcf, 0x92, + 0x35, 0x76, 0x6f, 0x61, 0xb9, 0x70, 0xe9, 0xb2, 0x27, 0x35, 0xca, 0x1f, 0x31, 0x65, 0x8e, 0x9b, + 0x44, 0x62, 0xde, 0x4d, 0x30, 0xc6, 0x2f, 0x0d, 0x37, 0x42, 0xac, 0x0d, 0x46, 0xbf, 0xcc, 0x28, + 0x6e, 0x30, 0xf8, 0x74, 0xdf, 0x38, 0xbd, 0xce, 0xcf, 0x67, 0xba, 0x6a, 0x83, 0x4a, 0x73, 0xdb, + 0x6f, 0x05, 0x21, 0x41, 0x2a, 0xb8, 0x28, 0x6e, 0xce, 0x69, 0xcb, 0x80, 0x3e, 0x48, 0xbf, 0x2c, + 0xc2, 0xe4, 0xbc, 0xc1, 0x81, 0xb4, 0x3e, 0x19, 0x1a, 0xfe, 0x1e, 0x39, 0x69, 0xb0, 0xce, 0x68, + 0x41, 0xd6, 0xdf, 0x54, 0x1a, 0xc7, 0xf7, 0xde, 0x50, 0x9a, 0x56, 0xfc, 0xda, 0x3e, 0x45, 0x3e, + 0x16, 0xac, 0x23, 0x73, 0xe4, 0xc0, 0x1a, 0x60, 0x10, 0x66, 0x5b, 0x5f, 0xc1, 0x30, 0x95, 0x90, + 0xa6, 0xf2, 0x0a, 0xf6, 0xee, 0x95, 0x84, 0x31, 0x3f, 0xbd, 0x7c, 0x55, 0xd6, 0x53, 0x79, 0x42, + 0x21, 0x39, 0xa9, 0x4d, 0x61, 0x34, 0xf1, 0x9e, 0xbb, 0x11, 0x4d, 0x5d, 0x16, 0xe3, 0x57, 0x29, + 0x9e, 0xfb, 0x6b, 0x3f, 0x53, 0x72, 0x6d, 0xf6, 0x1f, 0xcf, 0x06, 0xca, 0xc9, 0x54, 0x59, 0xb9, + 0x19, 0x12, 0x05, 0x18, 0x97, 0xac, 0x01, 0xba, 0x19, 0x49, 0x15, 0x21, 0x52, 0xd2, 0x38, 0x34, + 0xf8, 0x52, 0xb9, 0xdb, 0x91, 0x6a, 0x6e, 0x33, 0x31, 0xf0, 0xa4, 0xbe, 0x20, 0xb3, 0x5e, 0xa7, + 0xb3, 0xda, 0x5a, 0xb4, 0x8f, 0xb2, 0x0d, 0x18, 0x69, 0x28, 0xdb, 0xed, 0x12, 0x9f, 0xb8, 0x02, + 0xde, 0xdd, 0x8a, 0x7e, 0xb4, 0x1e, 0x4c, 0x84, 0x32, 0xfa, 0x80, 0x49, 0xa6, 0xb2, 0xc7, 0x1b, + 0x1c, 0x96, 0xef, 0x26, 0x59, 0xe4, 0x45, 0xbb, 0xcb, 0x45, 0x62, 0x17, 0x5b, 0x0b, 0xa1, 0xb1, + 0xeb, 0x44, 0x51, 0x30, 0x20, 0xb2, 0x1a, 0x56, 0xb4, 0xb3, 0x2c, 0x09, 0x56, 0x12, 0x5a, 0x1a, + 0xd8, 0x83, 0xe4, 0xac, 0x88, 0xf3, 0x50, 0xbe, 0x57, 0x9e, 0xac, 0x50, 0xb8, 0x79, 0x13, 0xa2, + 0xd2, 0x06, 0x65, 0x8d, 0x38, 0xcd, 0x6d, 0x6a, 0xc6, 0x31, 0x37, 0x7f, 0xc6, 0x91, 0x0e, 0x65, + 0x44, 0x1c, 0xcb, 0xcb, 0x0e, 0x97, 0x45, 0x43, 0xed, 0x16, 0xdd, 0x12, 0xbc, 0x0d, 0xa8, 0x70, + 0xf3, 0x74, 0x96, 0x09, 0xe7, 0x6f, 0xbe, 0x67, 0xb4, 0xf9, 0xca, 0x8c, 0xd3, 0x14, 0xdc, 0x47, + 0xc7, 0xda, 0xab, 0xb0, 0xb9, 0x5d, 0x2f, 0x4c, 0xce, 0x0b, 0x3c, 0xc3, 0x17, 0x37, 0x15, 0x3d, + 0x7a, 0xf8, 0xb5, 0x78, 0x6f, 0xdd, 0x31, 0x24, 0x80, 0xe9, 0x10, 0x9e, 0x9f, 0xee, 0x37, 0xe5, + 0x4f, 0xc5, 0x83, 0x9d, 0x3a, 0x43, 0x51, 0xc4, 0xf1, 0xfa, 0x77, 0x67, 0xd2, 0x6f, 0x92, 0x1d, + 0x20, 0xdd, 0x81, 0x6c, 0xec, 0xfc, 0x79, 0x45, 0x44, 0xa0, 0x37, 0x94, 0x66, 0x19, 0x39, 0xe8, + 0x85, 0xf6, 0xd2, 0x22, 0x88, 0x67, 0x82, 0x85, 0x26, 0x56, 0x03, 0xf1, 0x16, 0x91, 0x1e, 0x7a, + 0x26, 0xd7, 0x43, 0xe9, 0x45, 0xca, 0xde, 0x8e, 0x84, 0xbe, 0x54, 0x03, 0x4f, 0x5a, 0x5f, 0xbc, + 0x17, 0xb2, 0x09, 0x42, 0x58, 0x01, 0xee, 0x20, 0xe4, 0xe5, 0x76, 0x07, 0xce, 0xff, 0x96, 0x8a, + 0xf7, 0xd0, 0xa4, 0xe5, 0x4b, 0x9f, 0xf4, 0x14, 0x73, 0x92, 0x0c, 0x8a, 0x03, 0xf3, 0x9e, 0xf0, + 0xe3, 0x79, 0xd2, 0x7f, 0x93, 0x90, 0x6d, 0x91, 0x9b, 0x22, 0xf7, 0x86, 0x6f, 0xda, 0x38, 0x28, + 0x37, 0xe9, 0xcf, 0xb0, 0xee, 0xce, 0xb8, 0xa4, 0x94, 0xd7, 0x28, 0xf5, 0xfc, 0x31, 0xfc, 0x49, + 0x5b, 0x33, 0xf6, 0xee, 0xa0, 0xc2, 0x3f, 0xeb, 0x81, 0x6f, 0x78, 0xe9, 0x07, 0xe5, 0x21, 0x49, + 0x31, 0x02, 0x6f, 0xe0, 0x8d, 0xa5, 0xbb, 0x63, 0x91, 0xc2, 0xd4, 0x38, 0x4d, 0xf4, 0x78, 0x07, + 0xe3, 0x96, 0x88, 0xd6, 0xf1, 0x3a, 0x0a, 0xcf, 0x62, 0xc2, 0x81, 0x3c, 0x0b, 0x46, 0xf1, 0x2a, + 0x1b, 0x48, 0x35, 0x71, 0xb2, 0x6e, 0xb2, 0xde, 0x89, 0x1c, 0x74, 0xbc, 0xab, 0x11, 0x83, 0xdf, + 0xd8, 0x9f, 0xd8, 0x27, 0xbf, 0x37, 0x0e, 0x3a, 0x47, 0xd7, 0xb3, 0x8f, 0xd5, 0x9a, 0xa8, 0x3e, + 0xda, 0x8f, 0x3e, 0x2e, 0x55, 0xed, 0x83, 0x11, 0x9d, 0x57, 0x68, 0x9d, 0x12, 0xcf, 0xd6, 0x19, + 0x9a, 0x50, 0xe9, 0x6d, 0x4e, 0x2e, 0x26, 0xf1, 0x7e, 0xc0, 0x1a, 0x46, 0x5f, 0x0a, 0x19, 0x58, + 0x1f, 0xe2, 0x9f, 0xcc, 0x0e, 0x53, 0x72, 0xcc, 0xbb, 0x0a, 0xc7, 0xd2, 0x23, 0xfc, 0xeb, 0x18, + 0x79, 0x1e, 0xf7, 0xea, 0x8c, 0xd6, 0x41, 0x03, 0x69, 0x1b, 0x92, 0x5e, 0xc7, 0xe4, 0x39, 0x9f, + 0xbe, 0x1d, 0x5b, 0xe0, 0xa4, 0x7f, 0x84, 0x1e, 0x7f, 0x99, 0x62, 0x4f, 0x1d, 0x71, 0x4b, 0xbd, + 0x7c, 0xd0, 0xc9, 0x0c, 0x86, 0xb2, 0x63, 0xe4, 0x6e, 0xbe, 0x74, 0x1c, 0xbd, 0xe1, 0x5c, 0x1d, + 0xa7, 0x94, 0x99, 0xb3, 0x9a, 0x8a, 0xfe, 0xcc, 0xef, 0xfc, 0x9c, 0x35, 0x01, 0x0a, 0xbc, 0xa1, + 0x34, 0xc7, 0x08, 0x6a, 0xb5, 0x52, 0x91, 0x74, 0xfb, 0xa9, 0xf8, 0xc0, 0xb2, 0xbe, 0xda, 0xc4, + 0x93, 0x4a, 0xe5, 0x75, 0x22, 0x7d, 0x5d, 0x2b, 0x4a, 0x3b, 0x91, 0xe1, 0x6a, 0x66, 0x92, 0xd6, + 0xcf, 0x1d, 0xc4, 0x1a, 0x5e, 0x35, 0xdb, 0x1d, 0x19, 0x27, 0x21, 0xc8, 0x66, 0x31, 0x10, 0x70, + 0xb8, 0x15, 0x6b, 0xfe, 0x91, 0x8c, 0x5f, 0x14, 0x34, 0x77, 0xad, 0x71, 0xf3, 0xf4, 0xbf, 0x63, + 0x5e, 0x52, 0x35, 0x48, 0x1f, 0xd6, 0x4b, 0xfa, 0x69, 0x58, 0x6d, 0x78, 0x96, 0x9d, 0xf5, 0x04, + 0x98, 0x74, 0xc7, 0xb8, 0x22, 0x52, 0x0a, 0xa4, 0x66, 0x31, 0xab, 0xd4, 0x14, 0x6a, 0x71, 0x68, + 0xf7, 0x2f, 0xa8, 0xda, 0xc4, 0xb6, 0x6b, 0x80, 0xea, 0xf6, 0xfb, 0xf4, 0x1e, 0x9b, 0x18, 0x63, + 0x55, 0x58, 0x1b, 0x34, 0x1f, 0xe0, 0xa7, 0xb7, 0x4f, 0x55, 0xae, 0x79, 0x45, 0xca, 0x1c, 0x8e, + 0xf6, 0x3b, 0x07, 0x69, 0x77, 0xe6, 0x59, 0xd3, 0x56, 0x6f, 0x2d, 0xb2, 0x70, 0xa7, 0xa6, 0x29, + 0x85, 0x6f, 0xbd, 0xd3, 0x88, 0x24, 0x74, 0xbc, 0xb5, 0x76, 0x8f, 0x3e, 0x0a, 0xfa, 0x53, 0x3d, + 0xb2, 0x16, 0x86, 0xe4, 0xd2, 0xa6, 0x25, 0xe8, 0x5f, 0xa1, 0x9a, 0xce, 0xed, 0xcd, 0x0f, 0x71, + 0x95, 0xca, 0x7d, 0x17, 0xb1, 0x6d, 0x1f, 0x2e, 0x44, 0x5c, 0xb7, 0x70, 0x33, 0xd6, 0x51, 0xc1, + 0xf3, 0x4f, 0xd8, 0x7d, 0x6c, 0xf2, 0x02, 0xef, 0xfe, 0xf5, 0xe1, 0xd2, 0xf0, 0x7c, 0xdb, 0x3f, + 0xc3, 0x83, 0x07, 0xa9, 0x3a, 0x3e, 0xa2, 0x13, 0xdf, 0x43, 0x9e, 0x69, 0xf7, 0x81, 0xcd, 0x4b, + 0x18, 0xeb, 0xfa, 0x5d, 0x3f, 0x19, 0xcf, 0x77, 0xe4, 0x94, 0x2c, 0x97, 0xef, 0x9e, 0x03, 0x65, + 0x93, 0x51, 0x96, 0x4b, 0xa8, 0x2d, 0x0b, 0xed, 0xb3, 0x88, 0x57, 0x3d, 0x1c, 0x7b, 0xfa, 0x90, + 0x58, 0xac, 0xef, 0xc6, 0x44, 0xfa, 0xde, 0x75, 0x6d, 0x6f, 0x63, 0x83, 0x24, 0x2b, 0x24, 0x95, + 0x57, 0x43, 0x03, 0x3e, 0xf0, 0xae, 0x2a, 0xf1, 0x12, 0xfc, 0x73, 0x1e, 0x21, 0xec, 0x0d, 0xa5, + 0x97, 0x5f, 0xac, 0x88, 0x68, 0x33, 0x5e, 0x71, 0x4b, 0x97, 0xab, 0xc3, 0x27, 0xef, 0x25, 0x1a, + 0x86, 0x88, 0xc5, 0x34, 0x2f, 0x48, 0x30, 0x75, 0x03, 0x58, 0x39, 0x11, 0x86, 0xf9, 0x70, 0x62, + 0x71, 0x00, 0xa3, 0x13, 0x89, 0xd8, 0x5e, 0x53, 0x67, 0xc3, 0x50, 0x77, 0x33, 0x0b, 0xa9, 0x08, + 0x34, 0x2d, 0x26, 0xdc, 0x24, 0x5d, 0x58, 0xb8, 0x3c, 0xd1, 0x08, 0xb6, 0xe1, 0x4c, 0x5a, 0x1a, + 0x24, 0x5a, 0xa2, 0x88, 0xc0, 0x35, 0xd9, 0x0b, 0x0b, 0x91, 0xcd, 0xac, 0x6c, 0x48, 0xc4, 0xd2, + 0x1b, 0x90, 0x9b, 0x74, 0x10, 0x16, 0x8a, 0xa7, 0x80, 0x40, 0xab, 0x98, 0x4f, 0xdb, 0x51, 0x44, + 0x9d, 0xe0, 0x27, 0x91, 0x15, 0x11, 0x88, 0x22, 0x7b, 0x05, 0xf6, 0xd1, 0xc9, 0xa3, 0x5e, 0xbf, + 0x89, 0xb0, 0x3f, 0x8a, 0xd7, 0x09, 0x6c, 0xc0, 0xc2, 0x11, 0x26, 0xb3, 0xdc, 0x92, 0x92, 0x81, + 0xb6, 0xa6, 0xe7, 0x5f, 0x6b, 0x9b, 0x9d, 0xf5, 0x05, 0x7e, 0xdc, 0x35, 0x10, 0xf2, 0x6f, 0x30, + 0x12, 0x28, 0x3e, 0x8a, 0xc7, 0x4d, 0x7a, 0x25, 0x42, 0x24, 0x2e, 0x50, 0x24, 0xc0, 0x94, 0x36, + 0xdc, 0x17, 0x65, 0x6b, 0xdb, 0x37, 0x5d, 0x33, 0x95, 0xeb, 0x8a, 0x21, 0x0a, 0x7f, 0xda, 0xd3, + 0xb1, 0x71, 0x17, 0xc1, 0x5c, 0x47, 0x87, 0x8f, 0xc4, 0xe7, 0xe4, 0xcb, 0x82, 0x34, 0x25, 0x8b, + 0xdd, 0x64, 0x50, 0xfb, 0xcb, 0x66, 0xc6, 0x56, 0xb9, 0xd8, 0xab, 0xea, 0x77, 0xab, 0x33, 0xf1, + 0x8e, 0xdb, 0x5d, 0x43, 0x65, 0x11, 0xa7, 0xe8, 0xc7, 0x36, 0x0c, 0xed, 0x77, 0x8e, 0x3f, 0xdc, + 0xe0, 0x03, 0x3b, 0x9c, 0xa5, 0x45, 0xae, 0x9a, 0xb4, 0xa1, 0xc0, 0x84, 0x40, 0xaa, 0xfb, 0xd0, + 0x55, 0x86, 0x05, 0xf1, 0x2a, 0xd8, 0xf0, 0xcc, 0xb6, 0x85, 0x2d, 0x14, 0xba, 0x4c, 0xa5, 0xe8, + 0xde, 0x6d, 0x0f, 0xa2, 0xeb, 0xb6, 0x80, 0x5c, 0xa9, 0x71, 0xfa, 0x35, 0x20, 0x1c, 0xef, 0x55, + 0x9f, 0x76, 0x5a, 0x82, 0x1e, 0x30, 0xf0, 0xff, 0x9c, 0xb1, 0x89, 0xc8, 0xbe, 0xa1, 0xf4, 0xaa, + 0xa8, 0x2a, 0xac, 0x16, 0xee, 0x20, 0x47, 0x5a, 0x4e, 0xb5, 0x59, 0x03, 0xcb, 0xa0, 0xdd, 0xe7, + 0xfd, 0xc0, 0xaa, 0x0a, 0x05, 0xc1, 0x9c, 0xe4, 0x7e, 0x14, 0x5a, 0xab, 0x0a, 0x5e, 0x94, 0x4a, + 0xc7, 0x96, 0x3c, 0xad, 0x47, 0x9f, 0x49, 0x14, 0x96, 0xbb, 0xec, 0x25, 0xed, 0x54, 0xe5, 0x88, + 0xfa, 0xa3, 0xd4, 0x1a, 0x60, 0x69, 0xd0, 0x6b, 0xbc, 0x6e, 0x61, 0x7d, 0x4d, 0x93, 0x28, 0x62, + 0x7d, 0x62, 0xe5, 0xa3, 0xcd, 0x5e, 0x5b, 0x9e, 0x94, 0x9c, 0x23, 0x2a, 0xeb, 0x68, 0xf3, 0x51, + 0x6c, 0x04, 0x6a, 0x81, 0xae, 0xb6, 0xe2, 0x3f, 0x4c, 0xae, 0x55, 0x3d, 0xbe, 0x22, 0x0b, 0xe8, + 0xd2, 0xe6, 0x4d, 0xc7, 0x08, 0x55, 0x4b, 0xd5, 0x39, 0xbc, 0xc0, 0xeb, 0xfe, 0xe6, 0x50, 0xa3, + 0x11, 0x6f, 0x91, 0x82, 0x4a, 0x69, 0x34, 0xf1, 0xa4, 0xb5, 0xfb, 0x77, 0x31, 0xcb, 0x91, 0x53, + 0x0d, 0xa8, 0xdd, 0xdd, 0xf4, 0x54, 0x2a, 0x16, 0xa4, 0xe7, 0xd5, 0x2e, 0x07, 0xbe, 0xc0, 0xf2, + 0x56, 0xd3, 0xf2, 0x79, 0x97, 0xb3, 0xde, 0xa3, 0xba, 0x89, 0xeb, 0x84, 0xa2, 0xf4, 0x4c, 0x47, + 0x78, 0xc5, 0x4a, 0x20, 0x85, 0x09, 0xad, 0xc3, 0x9b, 0x11, 0xbf, 0xdb, 0xa4, 0x99, 0x2a, 0xfe, + 0xfe, 0xf2, 0x81, 0x0c, 0x74, 0x63, 0x3b, 0x82, 0xdd, 0x40, 0x56, 0xef, 0xbd, 0x46, 0x42, 0xa6, + 0xf5, 0x09, 0x79, 0xa0, 0xcd, 0x23, 0x09, 0xe3, 0x4e, 0x05, 0x33, 0x24, 0x0f, 0xd4, 0x82, 0x40, + 0x0a, 0xda, 0xff, 0xe6, 0x9d, 0x57, 0xe4, 0xaa, 0xf5, 0xb1, 0x46, 0xb2, 0x09, 0xc7, 0xc1, 0xed, + 0xd3, 0x0c, 0x96, 0x93, 0xd4, 0xd2, 0x06, 0x8d, 0xb5, 0x77, 0x98, 0xd5, 0x5a, 0xc3, 0x87, 0x53, + 0x20, 0x13, 0xb4, 0xa3, 0x2c, 0xc9, 0x35, 0x7e, 0xc2, 0x11, 0x6b, 0xf9, 0x45, 0x85, 0xb2, 0xac, + 0x7a, 0x04, 0x80, 0x9e, 0x23, 0xf4, 0xbd, 0x7c, 0xe2, 0xe5, 0x98, 0xf9, 0x5d, 0x44, 0xb3, 0x57, + 0xe9, 0x8d, 0x96, 0xcd, 0x95, 0x32, 0xe3, 0xa9, 0x0a, 0xd4, 0x48, 0x3f, 0xe7, 0x11, 0x2a, 0xbc, + 0xa1, 0xb4, 0xd8, 0x02, 0x75, 0xa8, 0x64, 0x1e, 0x4f, 0xf0, 0x88, 0x8d, 0x93, 0x65, 0xcb, 0x8a, + 0xb8, 0xf5, 0x94, 0xc4, 0xd6, 0x24, 0x72, 0x32, 0x54, 0x4d, 0x9e, 0x59, 0xf0, 0xb3, 0xd1, 0xa8, + 0x15, 0xd0, 0xc5, 0xa3, 0xc8, 0x64, 0x8a, 0x3e, 0x18, 0x29, 0xad, 0x6a, 0xd4, 0x2b, 0xe2, 0x44, + 0x82, 0xea, 0x9a, 0xaa, 0xc6, 0xa3, 0xc7, 0x39, 0x95, 0x28, 0xc6, 0xe2, 0xa4, 0xc5, 0xa3, 0x8b, + 0x94, 0x72, 0x0b, 0xfe, 0xc0, 0xfd, 0xfc, 0x84, 0x84, 0xc4, 0xbb, 0xf6, 0x5e, 0x46, 0x36, 0x80, + 0x9d, 0x64, 0xa0, 0xba, 0xb5, 0x1b, 0x52, 0x03, 0x95, 0xe7, 0xad, 0x4b, 0x81, 0x2e, 0x10, 0x67, + 0xed, 0x44, 0x11, 0x26, 0x50, 0xb8, 0x45, 0x56, 0xbf, 0x9f, 0x5a, 0x5f, 0x16, 0x0f, 0x40, 0x7f, + 0x80, 0x3d, 0x73, 0xef, 0x26, 0xa4, 0xdc, 0x3c, 0x52, 0x67, 0xac, 0xc5, 0x52, 0x83, 0xec, 0x62, + 0x52, 0x8a, 0xaf, 0xcd, 0x67, 0xa4, 0x2b, 0x97, 0x8b, 0x9f, 0x9d, 0x01, 0x29, 0xa8, 0xb1, 0x91, + 0xc4, 0xec, 0xb3, 0xd7, 0x09, 0x41, 0xe1, 0xb2, 0x07, 0x10, 0x4a, 0xc6, 0x63, 0x0f, 0x70, 0x50, + 0x14, 0xa1, 0xa8, 0x33, 0x3b, 0x1f, 0x26, 0x0a, 0x09, 0xd8, 0x91, 0xde, 0xb9, 0xac, 0x13, 0xc5, + 0x92, 0xc0, 0x0a, 0x2b, 0x28, 0x3c, 0x10, 0x66, 0x2f, 0xf3, 0xcb, 0x10, 0x7b, 0x89, 0x5f, 0x36, + 0xa4, 0x69, 0x7c, 0x82, 0xce, 0xd4, 0xb0, 0xaa, 0xbe, 0x96, 0x12, 0x10, 0xf8, 0xfa, 0x4a, 0xd6, + 0xc6, 0x48, 0x91, 0x63, 0x41, 0xb0, 0x7c, 0x41, 0xc0, 0xd3, 0xcb, 0xc9, 0x02, 0x10, 0x51, 0x93, + 0x79, 0x36, 0x84, 0x41, 0xcf, 0x7f, 0xc9, 0xd4, 0x69, 0xaf, 0x9b, 0xa5, 0xb4, 0x80, 0x4d, 0x7c, + 0x41, 0x04, 0x1c, 0x78, 0x37, 0xad, 0x65, 0x57, 0xbf, 0x22, 0x5a, 0x8e, 0xe3, 0x2b, 0xae, 0xc2, + 0xf8, 0x78, 0x16, 0xe4, 0xa5, 0xe8, 0x05, 0xa9, 0x50, 0xdc, 0x78, 0x04, 0xf3, 0xc1, 0xd7, 0x77, + 0x2b, 0xe1, 0xa9, 0x80, 0x72, 0x2e, 0x7a, 0x1d, 0xd2, 0x55, 0xee, 0xf4, 0x3f, 0xd7, 0xa0, 0x4c, + 0xbc, 0xa1, 0xf4, 0x86, 0x25, 0x25, 0x6b, 0x14, 0x07, 0x42, 0x8f, 0xdf, 0x1c, 0x78, 0xd8, 0x50, + 0x29, 0x8b, 0xb2, 0x63, 0x27, 0x32, 0x15, 0x9a, 0x13, 0xdc, 0xfc, 0x99, 0xda, 0x5c, 0xc7, 0xa0, + 0xa3, 0xef, 0xdd, 0xdf, 0xce, 0x10, 0xa8, 0x27, 0xbd, 0x7f, 0xf8, 0xd7, 0x8d, 0x1f, 0xfa, 0xb2, + 0xba, 0xdd, 0xc0, 0x7e, 0xb3, 0xc4, 0x1d, 0x27, 0x3c, 0xe0, 0xe8, 0x99, 0x01, 0x14, 0x5f, 0x52, + 0xfa, 0xb0, 0x79, 0x76, 0x85, 0x8f, 0x3e, 0x4f, 0x48, 0x0b, 0xcb, 0x1a, 0x8d, 0xbf, 0x69, 0x10, + 0x44, 0xba, 0xb4, 0x44, 0xcc, 0x3c, 0x97, 0x56, 0x6f, 0xbb, 0xeb, 0xcd, 0xd0, 0x98, 0x37, 0x27, + 0xaa, 0x6f, 0x1f, 0xb5, 0x94, 0xdf, 0x77, 0xdd, 0x35, 0x23, 0xf9, 0xc8, 0xe1, 0xea, 0x32, 0x34, + 0x3b, 0xcd, 0xfa, 0x63, 0x1a, 0xd9, 0xab, 0x4a, 0x1b, 0x71, 0x09, 0xf0, 0xb0, 0xee, 0xb8, 0x33, + 0xa0, 0xe9, 0xed, 0x6a, 0x48, 0xd1, 0x74, 0xf7, 0xd2, 0x0a, 0xdb, 0xa8, 0xbb, 0xa7, 0x52, 0x49, + 0x87, 0x0c, 0x8d, 0xd6, 0x36, 0x1f, 0xd8, 0x3b, 0xde, 0x9a, 0x8b, 0xef, 0xf0, 0xca, 0xc4, 0x89, + 0x51, 0xb5, 0x5e, 0x45, 0xa6, 0x58, 0xb4, 0x1d, 0x63, 0x11, 0x2e, 0x42, 0x3a, 0x9d, 0xe9, 0xe0, + 0xbd, 0xe9, 0xab, 0x41, 0x9e, 0x9e, 0x96, 0xd5, 0x3d, 0x31, 0x27, 0xd5, 0xd9, 0x12, 0xb6, 0xa3, + 0x98, 0x2f, 0xf6, 0x62, 0xe6, 0xa5, 0x03, 0x67, 0x06, 0x69, 0x0d, 0x40, 0xa3, 0x78, 0x47, 0x68, + 0x92, 0xd4, 0xcc, 0xa3, 0x51, 0xf3, 0xe8, 0x79, 0xac, 0xbb, 0xd0, 0xfa, 0x63, 0x18, 0x67, 0xa7, + 0x9e, 0xb8, 0xdb, 0x71, 0x8f, 0x06, 0xe2, 0x56, 0x67, 0x45, 0xc4, 0xee, 0x38, 0x33, 0x63, 0xa5, + 0x55, 0xe6, 0x78, 0xa4, 0x5b, 0x92, 0x5d, 0xba, 0x72, 0x7c, 0x75, 0x95, 0x9e, 0xe1, 0xf0, 0x52, + 0xbb, 0xa0, 0xfc, 0xfa, 0x14, 0x40, 0x43, 0xa7, 0xd5, 0x40, 0xcb, 0x72, 0x0f, 0xd3, 0xa6, 0xed, + 0x94, 0xa1, 0xf0, 0xfc, 0xda, 0xd0, 0x79, 0xb5, 0xe3, 0xe3, 0xed, 0x2a, 0x54, 0x45, 0xfe, 0x1f, + 0x66, 0xb7, 0x81, 0xc8, 0x6f, 0x7c, 0x87, 0x1f, 0xda, 0xf7, 0xf7, 0x7e, 0x2a, 0x45, 0x57, 0x9e, + 0x5b, 0x55, 0x2b, 0xaf, 0xeb, 0x8c, 0x8f, 0xbb, 0x37, 0x9e, 0xec, 0x47, 0x9d, 0x8d, 0x90, 0x92, + 0x61, 0xef, 0x76, 0xa0, 0x6c, 0x9f, 0x6c, 0x62, 0x94, 0x6d, 0x04, 0x0e, 0xe4, 0xd3, 0xe2, 0x3b, + 0x29, 0x59, 0xe5, 0xfe, 0x3d, 0xc4, 0xe1, 0x6d, 0x5d, 0x17, 0x96, 0x35, 0x31, 0x5f, 0x76, 0x5e, + 0x37, 0x4e, 0xd1, 0xc3, 0xbb, 0xf7, 0x7e, 0x66, 0x69, 0xb7, 0x47, 0x0a, 0xe4, 0xc1, 0xe4, 0x6c, + 0x05, 0xe4, 0xe8, 0x6e, 0xf0, 0x8f, 0xc9, 0x1a, 0x52, 0x88, 0xec, 0x7c, 0xf5, 0x14, 0x96, 0x79, + 0x57, 0x98, 0xdc, 0x50, 0xed, 0xaa, 0x95, 0xa2, 0xaa, 0x7c, 0x33, 0x2f, 0xba, 0x6a, 0x92, 0x98, + 0x0a, 0xa8, 0x84, 0x9f, 0xe8, 0x42, 0x47, 0x37, 0x33, 0x88, 0x7f, 0x7d, 0xdb, 0x4c, 0xca, 0x70, + 0x85, 0x7c, 0x2f, 0xe9, 0x83, 0xa9, 0x5c, 0x87, 0x5e, 0x21, 0x16, 0x44, 0x46, 0xbf, 0x17, 0xa8, + 0x1b, 0x66, 0x0d, 0xc6, 0x92, 0xc8, 0xdb, 0xf1, 0x84, 0x45, 0x5c, 0xbd, 0x50, 0x97, 0x11, 0x9a, + 0x0c, 0x94, 0x3a, 0xbe, 0x8d, 0x14, 0x65, 0xdf, 0xa0, 0x8a, 0xfe, 0xb1, 0x83, 0xa5, 0xf6, 0x4c, + 0x3c, 0x18, 0xb7, 0xb8, 0x77, 0x1d, 0x88, 0xcc, 0x51, 0x7d, 0x79, 0x3c, 0x68, 0x55, 0xbf, 0xb6, + 0x0c, 0xac, 0xaa, 0x73, 0xd0, 0x1c, 0xbf, 0x78, 0x1e, 0xef, 0x42, 0x77, 0x30, 0x75, 0x9e, 0xa7, + 0x4e, 0x66, 0xc1, 0x0d, 0x68, 0x4e, 0xce, 0x2a, 0x61, 0x4c, 0x3d, 0x53, 0x6b, 0xde, 0x7f, 0x5e, + 0x3d, 0x73, 0x77, 0xab, 0x65, 0x17, 0xfc, 0x7b, 0xd6, 0xb4, 0xf3, 0x65, 0xb8, 0x5c, 0x3f, 0x38, + 0x63, 0x9e, 0x94, 0x4d, 0x9b, 0x83, 0x58, 0x61, 0x3c, 0x91, 0x50, 0xbe, 0xff, 0xd8, 0x5e, 0x73, + 0xcf, 0x5c, 0xf6, 0x98, 0x21, 0x7a, 0x33, 0x31, 0xae, 0xb5, 0x37, 0xbc, 0x83, 0x88, 0xd9, 0x97, + 0xd2, 0xa6, 0x33, 0x5b, 0x8e, 0x69, 0xb9, 0x8d, 0x26, 0x84, 0xbf, 0xc5, 0xce, 0x18, 0x37, 0x45, + 0xae, 0x94, 0xca, 0x64, 0xee, 0x04, 0x7f, 0x8e, 0xf2, 0xea, 0xd2, 0xde, 0x50, 0x7a, 0x53, 0x56, + 0xc4, 0x47, 0x01, 0x7a, 0xc3, 0x7a, 0xf2, 0xc8, 0xd2, 0x98, 0x30, 0x43, 0x04, 0x98, 0x66, 0xb2, + 0x4c, 0xa8, 0x7d, 0x94, 0x60, 0x0a, 0x11, 0xfc, 0x53, 0x8c, 0xcb, 0x4f, 0x51, 0x03, 0x5c, 0xbe, + 0x77, 0x29, 0xc9, 0x85, 0xa0, 0x34, 0x79, 0xc8, 0x23, 0x58, 0x39, 0x7e, 0x59, 0xf3, 0xc8, 0x14, + 0x08, 0x10, 0x92, 0x38, 0xf2, 0xcd, 0x37, 0x51, 0x82, 0x8e, 0x68, 0xb3, 0xc4, 0xe5, 0x77, 0x15, + 0xc1, 0x07, 0x1b, 0xa1, 0xee, 0x4f, 0x6c, 0x44, 0x4e, 0xc2, 0xfb, 0x66, 0x9f, 0x08, 0x22, 0x69, + 0xdf, 0x44, 0x5a, 0x3e, 0xef, 0xd0, 0x13, 0x30, 0xee, 0x0a, 0x9a, 0x63, 0xb3, 0x63, 0x71, 0x66, + 0x00, 0x2f, 0x88, 0xf1, 0x99, 0x2f, 0x75, 0x89, 0x6e, 0xa4, 0x35, 0xe1, 0xea, 0xed, 0x8b, 0xe6, + 0xa2, 0x3a, 0x7a, 0xd1, 0xf4, 0xaa, 0xe3, 0x17, 0xcd, 0xac, 0x3a, 0xb2, 0x68, 0x17, 0xaa, 0x5f, + 0x5f, 0xb4, 0x9f, 0xaa, 0x93, 0x17, 0xed, 0x56, 0x75, 0xfa, 0xa2, 0x35, 0xe4, 0x2e, 0xc4, 0x35, + 0x44, 0xe3, 0xda, 0x10, 0x56, 0x65, 0x67, 0xe3, 0x8b, 0x35, 0xd4, 0x11, 0xf2, 0x8b, 0x68, 0x62, + 0xa9, 0xdc, 0xc8, 0x50, 0x77, 0xaf, 0x83, 0x6d, 0xa5, 0x50, 0xb1, 0x27, 0x0a, 0x4e, 0xfa, 0x6c, + 0x0d, 0x20, 0x08, 0x90, 0xc9, 0xf7, 0xce, 0x46, 0xcb, 0x08, 0x35, 0xbb, 0x54, 0xd1, 0x20, 0xea, + 0xa7, 0xa2, 0x4a, 0x7f, 0x14, 0x49, 0x8f, 0xa1, 0xdf, 0x47, 0xcc, 0x64, 0xd5, 0x2b, 0xdb, 0x3b, + 0x3f, 0xef, 0x77, 0x81, 0xaf, 0x47, 0xb5, 0x61, 0x4e, 0x72, 0x03, 0x17, 0x05, 0x3b, 0x42, 0xba, + 0x6c, 0x28, 0x33, 0x26, 0x28, 0xc3, 0xe4, 0xeb, 0x09, 0x38, 0x11, 0xd9, 0x10, 0xcd, 0x0a, 0x7d, + 0xd3, 0xc7, 0x05, 0x70, 0x62, 0x4c, 0xe4, 0xc4, 0xe7, 0xc8, 0x24, 0x84, 0x9f, 0x57, 0xb0, 0xb0, + 0x3a, 0x66, 0x8f, 0x63, 0x67, 0x96, 0x41, 0x5c, 0x11, 0xbc, 0xa3, 0x21, 0x06, 0x27, 0xdc, 0xf6, + 0x37, 0xa7, 0x35, 0xd5, 0x1c, 0x18, 0x8d, 0xfc, 0x7c, 0x3f, 0x96, 0x58, 0x7b, 0x43, 0x69, 0x55, + 0xdd, 0xd2, 0xbc, 0x7a, 0xd6, 0x6d, 0xbc, 0xae, 0x67, 0x89, 0x6a, 0xb7, 0xb7, 0xa2, 0x6f, 0x85, + 0x03, 0x29, 0x8e, 0x29, 0x88, 0x53, 0xd2, 0xc9, 0xdb, 0xbf, 0x44, 0x2c, 0x4c, 0xde, 0xc2, 0xd1, + 0xe3, 0x7f, 0xe6, 0x50, 0x0a, 0xc6, 0x3b, 0x85, 0x87, 0x48, 0xad, 0x0f, 0x1d, 0x54, 0xe1, 0xfc, + 0x8e, 0xa7, 0x72, 0x2c, 0x62, 0x9d, 0xda, 0x1d, 0x4f, 0xb5, 0xdb, 0x0a, 0x3a, 0x33, 0x64, 0xdc, + 0x69, 0x23, 0xe5, 0xd2, 0xe5, 0x55, 0x5a, 0x86, 0x62, 0x7f, 0x87, 0x5e, 0xd8, 0x0e, 0xa8, 0xe8, + 0xfa, 0x4e, 0x22, 0xa0, 0x35, 0x7c, 0x75, 0x8e, 0x73, 0x0e, 0xd7, 0x8b, 0xfe, 0xb9, 0xbc, 0x5d, + 0x13, 0x8d, 0x6e, 0x3b, 0xfd, 0xd0, 0x41, 0x0e, 0x0a, 0xdd, 0xe4, 0xa3, 0xf8, 0x6d, 0x51, 0xc6, + 0xbe, 0x3d, 0x69, 0x4a, 0x05, 0x61, 0x39, 0xcb, 0x20, 0x14, 0xcf, 0x4e, 0x8c, 0xaf, 0x0d, 0x48, + 0x79, 0xbd, 0x17, 0x9c, 0x13, 0x73, 0x76, 0x9a, 0x89, 0x3b, 0xdc, 0xb8, 0x59, 0x63, 0x78, 0x62, + 0x33, 0x23, 0xdd, 0xe3, 0xf9, 0x4b, 0x2c, 0x6c, 0xef, 0xdc, 0xe6, 0xcd, 0xa6, 0x53, 0x84, 0x4b, + 0x17, 0xf8, 0xe7, 0xba, 0x14, 0xe2, 0x99, 0xc4, 0x31, 0xc6, 0xbe, 0xbe, 0xf4, 0xd2, 0x3c, 0x44, + 0x78, 0xd3, 0xcc, 0xc5, 0xbe, 0xf7, 0x01, 0xd8, 0xd3, 0x5c, 0x61, 0x6c, 0xa7, 0x21, 0x3c, 0x9b, + 0x7c, 0xb0, 0xcc, 0x52, 0x7f, 0x6c, 0x74, 0xe5, 0x13, 0x9d, 0xef, 0x99, 0x4c, 0x29, 0x9c, 0xe2, + 0x6b, 0x83, 0x28, 0x0c, 0x6b, 0x0c, 0x4d, 0xcc, 0xbb, 0x25, 0xa8, 0x4c, 0x5f, 0x6e, 0x5e, 0xf8, + 0x88, 0xda, 0xf0, 0x32, 0x0e, 0xce, 0xb1, 0x1f, 0x78, 0x10, 0x2c, 0xe2, 0xad, 0x5f, 0x23, 0xf4, + 0xbe, 0xc7, 0x93, 0x32, 0xce, 0xeb, 0x3c, 0x09, 0xb5, 0xf8, 0x75, 0xe0, 0x05, 0xf2, 0x82, 0x5b, + 0x67, 0x80, 0x22, 0xf6, 0xd7, 0x03, 0x1a, 0x5d, 0x4d, 0xde, 0xa7, 0xba, 0xe0, 0xd7, 0xa1, 0x01, + 0xb4, 0x1f, 0xd7, 0x1e, 0xe2, 0xf6, 0x59, 0x9e, 0x8c, 0x69, 0x7f, 0x8e, 0xa7, 0x23, 0xd8, 0x6f, + 0x28, 0xad, 0x61, 0x87, 0x8e, 0x83, 0x99, 0x9a, 0x5a, 0xaf, 0xc8, 0xd5, 0x3a, 0x08, 0x3c, 0xce, + 0x6e, 0xd8, 0x0e, 0x29, 0x59, 0x82, 0x17, 0x54, 0x7f, 0xc4, 0x5f, 0x96, 0xa4, 0x07, 0x49, 0xd5, + 0x55, 0xe0, 0x37, 0x98, 0x37, 0x6c, 0xa6, 0x72, 0xf1, 0x18, 0xa1, 0x2f, 0x63, 0xd7, 0x8d, 0xa7, + 0x42, 0xd3, 0x58, 0x7f, 0xcc, 0x68, 0x9a, 0xa1, 0x72, 0x0c, 0xee, 0x9b, 0xb0, 0xce, 0xc9, 0xbf, + 0x13, 0x28, 0x06, 0x85, 0xbe, 0xc0, 0xe6, 0x77, 0xbc, 0x72, 0xbc, 0x5a, 0xdd, 0xf6, 0xbb, 0x63, + 0x45, 0xb1, 0xfb, 0xa6, 0x66, 0x49, 0x6d, 0x1f, 0xdd, 0x45, 0x50, 0xcb, 0xea, 0x5d, 0xf3, 0xeb, + 0x59, 0x0b, 0xad, 0xc1, 0xbc, 0xde, 0xc9, 0x7d, 0xc4, 0x6c, 0x48, 0x2f, 0x4b, 0x4f, 0xbd, 0x4b, + 0x01, 0x96, 0xc1, 0xbb, 0x9c, 0xe5, 0xa8, 0x84, 0xda, 0xf2, 0xd9, 0xe9, 0xe3, 0x56, 0xdd, 0xe1, + 0xeb, 0xd0, 0x54, 0xc3, 0xab, 0xe7, 0x93, 0x30, 0xda, 0x74, 0xa2, 0x50, 0x0d, 0x6c, 0x3d, 0x69, + 0xc3, 0x42, 0xc6, 0x20, 0x5b, 0xb5, 0x79, 0xa6, 0x63, 0xf3, 0x28, 0xd9, 0xa2, 0x8f, 0x76, 0x0c, + 0x99, 0xea, 0x9d, 0xda, 0xf1, 0xa4, 0x8f, 0xec, 0x86, 0xc9, 0x8b, 0x3b, 0xeb, 0x43, 0x39, 0x99, + 0x97, 0x74, 0xcf, 0x51, 0x06, 0x51, 0xef, 0x6a, 0x90, 0xfd, 0x4c, 0xf1, 0xf3, 0x76, 0x46, 0xce, + 0xc0, 0xc0, 0x72, 0xea, 0x36, 0x4b, 0x53, 0xea, 0x5e, 0x71, 0x2f, 0xa2, 0xa9, 0xd1, 0x89, 0x62, + 0xbb, 0x77, 0x53, 0xe7, 0xf2, 0xcc, 0x0a, 0x26, 0x47, 0x7d, 0xda, 0x8a, 0xa5, 0xdd, 0x17, 0x00, + 0x60, 0x38, 0x19, 0xe5, 0xb2, 0xd2, 0x96, 0x7f, 0x2b, 0x15, 0xc3, 0x2e, 0xd8, 0xf3, 0xb9, 0x97, + 0x61, 0x7f, 0xa8, 0x7c, 0xf1, 0x13, 0xca, 0x4c, 0x14, 0x09, 0x4c, 0x33, 0xda, 0x56, 0x26, 0x58, + 0x7a, 0xc0, 0x3f, 0x9d, 0x29, 0xb1, 0xd7, 0x1e, 0x78, 0xf3, 0x82, 0x45, 0xbd, 0xc7, 0x10, 0x33, + 0xe5, 0x61, 0x84, 0x35, 0xb5, 0x68, 0x03, 0xd6, 0xc6, 0x55, 0xee, 0x9f, 0xef, 0x5d, 0xe1, 0x8c, + 0xbf, 0x57, 0xba, 0x9b, 0xd0, 0x70, 0x3c, 0xce, 0x3a, 0x53, 0x22, 0xf3, 0x2b, 0x96, 0x4d, 0xfa, + 0x5a, 0x8b, 0x19, 0x93, 0x28, 0x68, 0x6a, 0xef, 0xae, 0xf7, 0x89, 0x67, 0xe2, 0xf5, 0x48, 0x58, + 0x47, 0xbd, 0xd5, 0xf9, 0x88, 0x3f, 0x90, 0x68, 0x3f, 0x6e, 0xc5, 0x7e, 0x48, 0x6b, 0xd2, 0x74, + 0x06, 0xe5, 0xd5, 0x88, 0x1e, 0xdc, 0x6d, 0xec, 0x23, 0x98, 0x34, 0x3d, 0x20, 0x64, 0x53, 0x5d, + 0x12, 0x46, 0xee, 0x04, 0x91, 0xf3, 0xfa, 0x1a, 0xd1, 0x35, 0x9a, 0x8d, 0x25, 0xb3, 0x24, 0x34, + 0x48, 0xda, 0x27, 0x2a, 0x9a, 0xdd, 0xf3, 0x75, 0x0c, 0xf2, 0xa7, 0xf6, 0x78, 0x3a, 0x77, 0xe2, + 0xf5, 0x87, 0x73, 0x0f, 0x5b, 0x43, 0xa3, 0xf3, 0x88, 0x68, 0x01, 0x33, 0x7f, 0x26, 0x61, 0x72, + 0x9f, 0xc2, 0xc3, 0xdc, 0x86, 0x78, 0x28, 0x29, 0x00, 0x8d, 0x69, 0x93, 0xcd, 0x32, 0x0c, 0xeb, + 0xcb, 0x5c, 0x07, 0x4e, 0x0b, 0xb5, 0xa1, 0x4d, 0x54, 0x33, 0x8d, 0x5c, 0xc5, 0x84, 0xff, 0xd5, + 0x37, 0x2e, 0x7e, 0x88, 0xce, 0x98, 0xa3, 0x1d, 0xfd, 0xb3, 0xc4, 0x42, 0x9c, 0x77, 0x0c, 0x42, + 0xd3, 0xb1, 0x26, 0x18, 0x5f, 0x0f, 0x30, 0x78, 0xfc, 0x41, 0xa5, 0x93, 0xb1, 0x4e, 0xb6, 0x68, + 0x26, 0x69, 0xb2, 0x1d, 0x78, 0xba, 0x57, 0x22, 0x46, 0x4a, 0xb3, 0x02, 0x4b, 0x05, 0x50, 0xc5, + 0xdd, 0xe2, 0xe1, 0x4e, 0xdf, 0x60, 0xcf, 0x16, 0xaf, 0xb4, 0x66, 0xb3, 0x75, 0xff, 0xa5, 0xb8, + 0x03, 0xfe, 0xa5, 0x88, 0x98, 0x37, 0x98, 0x93, 0x45, 0x4b, 0xd7, 0x4d, 0x30, 0x65, 0x82, 0x68, + 0x62, 0xa6, 0xe1, 0x9d, 0xa3, 0x28, 0xc8, 0x23, 0xa4, 0x63, 0x87, 0xd2, 0x37, 0x01, 0xcd, 0x71, + 0x5f, 0x56, 0xb9, 0x7e, 0xe2, 0xd5, 0x97, 0x66, 0x3b, 0x5d, 0x41, 0xa9, 0x01, 0x2f, 0x3e, 0x36, + 0x77, 0x3d, 0x4d, 0xe6, 0x83, 0x53, 0xe0, 0x96, 0x03, 0x20, 0xef, 0x36, 0x28, 0xcb, 0x79, 0x17, + 0x9f, 0x0e, 0xa2, 0x5d, 0xad, 0x5c, 0x6d, 0xf9, 0x79, 0xf7, 0x09, 0x21, 0xcc, 0x37, 0xae, 0x69, + 0x3d, 0xa0, 0xf3, 0xab, 0x3f, 0x1c, 0x54, 0x4a, 0x89, 0x47, 0x85, 0xce, 0x87, 0x85, 0x2c, 0xca, + 0x32, 0x95, 0x76, 0xe9, 0xdc, 0x0c, 0xd6, 0x04, 0xfb, 0xee, 0x34, 0xdd, 0x42, 0xcc, 0x2a, 0x29, + 0xae, 0xf4, 0x4b, 0x1a, 0xa3, 0x6e, 0xec, 0xfe, 0xb5, 0x0a, 0x08, 0xf1, 0x03, 0xdc, 0x50, 0xc0, + 0xe5, 0x53, 0xdd, 0xd0, 0x97, 0x58, 0x66, 0x79, 0x22, 0xc4, 0x44, 0xe5, 0x29, 0x3b, 0xe5, 0x6b, + 0x52, 0x89, 0x06, 0x51, 0xc3, 0x3e, 0x7b, 0xa0, 0x2c, 0x55, 0xcb, 0x33, 0xc6, 0xcf, 0x29, 0x9a, + 0xc8, 0xa0, 0x59, 0x9f, 0x14, 0x41, 0xc7, 0x97, 0xd1, 0x22, 0xfb, 0xcf, 0x48, 0x97, 0x50, 0x78, + 0x5a, 0xbf, 0xe2, 0x81, 0xfd, 0x49, 0x3d, 0x27, 0x25, 0x5c, 0xa9, 0x0f, 0xda, 0x2a, 0x5e, 0x47, + 0xa5, 0xbc, 0x0e, 0x26, 0x66, 0xd5, 0x36, 0xfb, 0x46, 0xe0, 0xc0, 0xbc, 0x15, 0x00, 0x9d, 0xae, + 0x63, 0x25, 0xd7, 0x31, 0x91, 0xfb, 0xa5, 0x76, 0xbc, 0x46, 0xe1, 0xae, 0x5b, 0x03, 0x06, 0x01, + 0x50, 0xd6, 0x4b, 0xe6, 0xed, 0x0f, 0x64, 0xf1, 0xc4, 0xb6, 0x43, 0xde, 0x14, 0x00, 0xae, 0xee, + 0x54, 0x5b, 0xf2, 0x9f, 0xa2, 0x05, 0xc7, 0x35, 0x9c, 0x66, 0x0b, 0x10, 0x86, 0x5c, 0x6c, 0xfd, + 0xd2, 0x5d, 0x7c, 0x04, 0x05, 0x81, 0x79, 0xc5, 0x86, 0x2f, 0xc1, 0xa6, 0x49, 0xed, 0xc4, 0x09, + 0x7b, 0x74, 0xee, 0xe5, 0xfe, 0x96, 0x6b, 0xfe, 0x92, 0x5a, 0x30, 0x80, 0xfd, 0x01, 0x27, 0x67, + 0x63, 0x22, 0x09, 0xb7, 0x7c, 0x69, 0x60, 0xaa, 0xf4, 0x10, 0xd1, 0xd0, 0xad, 0x67, 0xb4, 0x3e, + 0x26, 0x0d, 0xd1, 0xf1, 0xf7, 0xcf, 0x8e, 0xfe, 0x90, 0x53, 0xf1, 0x1d, 0xde, 0x14, 0xdc, 0xb7, + 0xc1, 0x4d, 0xe3, 0xfe, 0xf1, 0x75, 0xc6, 0x68, 0x84, 0x2a, 0x39, 0x4d, 0x75, 0x90, 0x98, 0xd7, + 0x2a, 0x47, 0x09, 0xe4, 0xc9, 0xe3, 0x8a, 0xa6, 0x0b, 0x07, 0xfb, 0x78, 0xe1, 0xb7, 0x0b, 0xdf, + 0x23, 0xfd, 0xc1, 0xd6, 0x13, 0x25, 0xa8, 0xd6, 0x2f, 0x38, 0x7d, 0xa5, 0xb6, 0xf9, 0xb3, 0xd2, + 0xb0, 0xe8, 0x0d, 0xa5, 0xf7, 0x3e, 0x7a, 0x30, 0x1a, 0x63, 0x15, 0xb4, 0x06, 0x3a, 0x14, 0x97, + 0x2e, 0xd0, 0xc9, 0xab, 0x4e, 0xbe, 0xe3, 0x0f, 0x7f, 0x96, 0x2a, 0xa9, 0x85, 0x48, 0x09, 0x37, + 0x8b, 0x00, 0x64, 0x1b, 0xd5, 0x55, 0xad, 0x88, 0x3a, 0x2f, 0x8b, 0xc2, 0x7b, 0xa6, 0xaa, 0x6e, + 0x9c, 0x0d, 0xc9, 0x22, 0xc8, 0x9e, 0x5a, 0x2a, 0x24, 0x36, 0xab, 0x66, 0x7c, 0xf3, 0x42, 0x79, + 0x64, 0xc0, 0x3f, 0x65, 0x6b, 0xf2, 0x96, 0x49, 0x50, 0xfb, 0x92, 0x0e, 0x50, 0x8f, 0xf4, 0x90, + 0xc9, 0x24, 0xc1, 0x6f, 0xe3, 0x74, 0xad, 0xe3, 0x79, 0xa8, 0xf9, 0x6c, 0x3f, 0xc1, 0x18, 0x60, + 0xc4, 0x9e, 0x10, 0xad, 0x7b, 0xa2, 0x27, 0x6b, 0x02, 0x7e, 0x90, 0x3b, 0x2f, 0xbd, 0x82, 0xa9, + 0x32, 0x53, 0x3b, 0x9d, 0x6d, 0xd4, 0xbc, 0x7e, 0x95, 0x6e, 0x67, 0xd2, 0x7f, 0x3a, 0xb8, 0xf2, + 0x7b, 0x4d, 0x3a, 0x4f, 0x9c, 0x46, 0x63, 0x5f, 0x85, 0xba, 0x89, 0xb6, 0xc7, 0xde, 0x1b, 0xf2, + 0x00, 0x7f, 0x9f, 0x21, 0x62, 0x0b, 0x6f, 0xb3, 0x2b, 0xa0, 0xb5, 0x5e, 0xa7, 0x1c, 0x6d, 0x1d, + 0xaa, 0x1b, 0xe8, 0xe9, 0xcb, 0xab, 0xb9, 0x1e, 0x1b, 0x19, 0xf6, 0x76, 0x9d, 0xab, 0x21, 0xd6, + 0xa5, 0xcd, 0x8e, 0x4a, 0x0b, 0xfb, 0xfd, 0xac, 0x41, 0xec, 0x3f, 0x96, 0xbf, 0xd8, 0x7c, 0xe7, + 0x01, 0x63, 0x39, 0x45, 0x1a, 0x08, 0x72, 0x55, 0x6f, 0xa0, 0x54, 0xf2, 0x5b, 0x72, 0xda, 0x88, + 0x9e, 0xf1, 0x81, 0xe5, 0xf8, 0xd2, 0xd7, 0x08, 0x1a, 0x44, 0x57, 0xaa, 0x9b, 0x39, 0x49, 0x27, + 0x92, 0xea, 0xe6, 0x29, 0xaa, 0x1e, 0x7f, 0xb9, 0x4e, 0x03, 0xe2, 0xb4, 0x91, 0xb8, 0xbf, 0x83, + 0x0d, 0xf5, 0x33, 0x4e, 0xfc, 0xf7, 0xec, 0xd4, 0x60, 0x4d, 0x3c, 0x61, 0xb0, 0xb3, 0x5a, 0xa8, + 0x0a, 0x71, 0x3d, 0x47, 0x70, 0xe0, 0xbf, 0xc6, 0x1a, 0xe8, 0xdd, 0x17, 0x0c, 0xb8, 0x22, 0x20, + 0x75, 0xc9, 0x66, 0x0f, 0xcb, 0xa6, 0x85, 0x93, 0x00, 0x27, 0x67, 0xb0, 0xfb, 0x9b, 0xd8, 0x51, + 0x9c, 0xf4, 0x73, 0x1e, 0x21, 0xe9, 0x1b, 0x4a, 0x0b, 0xb9, 0x96, 0x72, 0x2b, 0xdd, 0xe7, 0x1a, + 0x8d, 0x27, 0xe8, 0xa5, 0x31, 0x25, 0xe2, 0x5a, 0x8f, 0x8d, 0x74, 0xd0, 0x32, 0x53, 0xeb, 0x45, + 0x07, 0xaa, 0x4d, 0x5c, 0xf5, 0xd5, 0x8d, 0xb1, 0x7f, 0x1b, 0xa5, 0xec, 0x79, 0x31, 0x1f, 0x97, + 0x0b, 0xa0, 0xa6, 0xb1, 0x9b, 0xd4, 0x46, 0xdc, 0xd4, 0x7c, 0xdb, 0xa4, 0x74, 0xea, 0x0d, 0xa5, + 0xa3, 0xae, 0xfc, 0xb1, 0x94, 0x72, 0x76, 0x25, 0xb1, 0x0e, 0x44, 0xa7, 0x8c, 0x4f, 0xab, 0xd8, + 0x8f, 0x6c, 0x7b, 0xea, 0x84, 0xe5, 0xd5, 0xb8, 0xbd, 0xb7, 0x0c, 0xe0, 0x58, 0xc8, 0x35, 0x78, + 0x0a, 0x72, 0xce, 0x74, 0xb3, 0x93, 0xc4, 0x4c, 0x77, 0xb8, 0x29, 0xf4, 0x9c, 0xa4, 0x57, 0x73, + 0x5f, 0x9d, 0xfe, 0x70, 0xc3, 0x04, 0xd5, 0xa6, 0x7b, 0x7f, 0x3e, 0xbc, 0xee, 0x9c, 0x31, 0xcb, + 0x96, 0x9e, 0xfa, 0x87, 0x91, 0x2e, 0x0a, 0xfc, 0x91, 0x7a, 0x8f, 0x0f, 0x7e, 0xe7, 0x9d, 0x77, + 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, + 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0x79, 0xe7, 0x9d, 0x77, 0xde, 0xf9, + 0xff, 0x93, 0x1f, 0xbf, 0x07, 0xff, 0xdf, 0x79, 0x34, 0xf2, 0x09, 0xb2, 0xec, 0xef, 0x3d, 0x65, + 0x48, 0x3f, 0x7c, 0x33, 0xe3, 0xe2, 0xa9, 0xd5, 0xff, 0x81, 0x4b, 0x44, 0x10, 0x6a, 0xc8, 0xc1, + 0x8f, 0xe6, 0xc9, 0x7c, 0x04, 0x66, 0x83, 0x15, 0xc4, 0x55, 0x5b, 0x53, 0x06, 0xe1, 0x9b, 0x31, + 0x37, 0x3c, 0x46, 0x80, 0xf2, 0xc6, 0x08, 0xca, 0xdc, 0xe3, 0xed, 0xb4, 0x5a, 0x9c, 0x8c, 0x2f, + 0xe5, 0x6a, 0xf6, 0xd3, 0x1c, 0x51, 0x73, 0xfe, 0x23, 0x81, 0x2a, 0x61, 0x39, 0x51, 0x00, 0x8f, + 0x2e, 0x16, 0x64, 0x55, 0x9f, 0xab, 0x23, 0xf5, 0xb6, 0xab, 0x01, 0xee, 0x11, 0x4f, 0xba, 0x47, + 0x11, 0x78, 0x3a, 0x5a, 0x19, 0x88, 0xa9, 0x71, 0x94, 0x77, 0x7b, 0x21, 0x91, 0xed, 0xac, 0x7b, + 0x4d, 0x53, 0x81, 0x6f, 0xa6, 0x52, 0x36, 0xec, 0xe7, 0x41, 0xde, 0x40, 0x98, 0x36, 0xb3, 0x37, + 0x70, 0x39, 0x85, 0x25, 0xab, 0x0c, 0x5a, 0x77, 0x6e, 0xe3, 0xf2, 0x08, 0x10, 0x0f, 0xcd, 0x55, + 0x21, 0x6c, 0x08, 0x04, 0x58, 0x45, 0xa4, 0x16, 0xd6, 0x44, 0x0c, 0xa1, 0xf6, 0xd9, 0x67, 0xdc, + 0xbf, 0x1c, 0xae, 0xd9, 0x1a, 0x4d, 0x88, 0xab, 0xf4, 0x42, 0xb2, 0x96, 0x3d, 0xd0, 0x65, 0xb5, + 0x2b, 0x48, 0x2e, 0xe9, 0x8c, 0xba, 0xa7, 0x62, 0x19, 0x3e, 0x24, 0x83, 0x79, 0x14, 0xdb, 0x43, + 0x79, 0xd7, 0xb5, 0x05, 0x28, 0xda, 0x20, 0x28, 0xc3, 0xdd, 0x91, 0xef, 0x49, 0x9c, 0x6c, 0x55, + 0x46, 0xda, 0xb2, 0x9c, 0x19, 0x60, 0x3a, 0xa6, 0xbe, 0x60, 0x41, 0xa6, 0x39, 0x7d, 0xd2, 0x84, + 0x08, 0xe9, 0x9e, 0x26, 0x02, 0x5b, 0xc4, 0x11, 0xc1, 0x49, 0x98, 0xc2, 0xc1, 0x65, 0x99, 0xc9, + 0x81, 0x23, 0x3c, 0x7f, 0xd9, 0xe0, 0x79, 0xdb, 0x3d, 0x28, 0xb9, 0x33, 0x57, 0x83, 0x0a, 0xbe, + 0x47, 0xa3, 0x90, 0x50, 0xcf, 0x15, 0x8b, 0x84, 0x59, 0xb1, 0xca, 0xdd, 0x9d, 0xfa, 0xba, 0xf5, + 0xe3, 0x58, 0xd0, 0xcf, 0xde, 0xbd, 0x79, 0x11, 0x96, 0x2a, 0xad, 0x3a, 0xa4, 0xd3, 0x41, 0xed, + 0x04, 0x31, 0x2a, 0x1f, 0x32, 0xd8, 0x43, 0xeb, 0xcf, 0x35, 0x73, 0x08, 0xda, 0x1b, 0x4a, 0x6f, + 0x59, 0x88, 0x72, 0xa5, 0x2b, 0xea, 0xe8, 0x02, 0x9b, 0xb1, 0x8e, 0x9c, 0xd1, 0xa4, 0xfe, 0x59, + 0xfe, 0x63, 0x79, 0x47, 0x67, 0x6e, 0x22, 0x4b, 0x3b, 0xc6, 0x26, 0x32, 0xd1, 0x59, 0x8c, 0xc6, + 0x86, 0x0a, 0xf2, 0x74, 0x39, 0x43, 0x4f, 0x63, 0xa8, 0xbe, 0x3b, 0x3a, 0x41, 0x4b, 0x36, 0x43, + 0xcd, 0xc8, 0x9a, 0x4a, 0xf5, 0x1b, 0x65, 0x7d, 0xad, 0x51, 0x87, 0x0e, 0x76, 0xa4, 0xb1, 0xb3, + 0x42, 0xd7, 0x85, 0x3f, 0x5a, 0x2a, 0xc4, 0x85, 0x65, 0xbf, 0x31, 0x6e, 0x3c, 0x4e, 0x66, 0x75, + 0x46, 0xed, 0xcf, 0x63, 0xd5, 0x63, 0xdd, 0x7c, 0xe7, 0x4b, 0x0a, 0x9a, 0x1b, 0xd8, 0xbc, 0x3a, + 0x24, 0xbb, 0x93, 0x2f, 0x24, 0x67, 0xd0, 0x06, 0x55, 0x77, 0xfd, 0xa2, 0xb2, 0x78, 0x47, 0xf0, + 0xc6, 0x5e, 0xdb, 0x69, 0x26, 0x4d, 0x8f, 0x6c, 0x70, 0x42, 0x20, 0x88, 0x22, 0xf3, 0x97, 0x15, + 0x9b, 0x17, 0x57, 0x5c, 0xf0, 0x28, 0x59, 0x43, 0x5b, 0x4d, 0x84, 0x5a, 0x2c, 0x6d, 0x7a, 0x66, + 0xd6, 0x38, 0xf7, 0xa7, 0x23, 0xc0, 0x2f, 0x68, 0x4c, 0x0c, 0xc3, 0x39, 0x5a, 0xe9, 0x38, 0xde, + 0x7e, 0x5e, 0x0a, 0x4b, 0x57, 0x9b, 0xe1, 0xe4, 0x91, 0xfd, 0xb1, 0x1e, 0x71, 0xc7, 0xa1, 0xc2, + 0xee, 0xb4, 0x32, 0x06, 0x55, 0x70, 0xbc, 0xbb, 0xd7, 0x96, 0xb4, 0x26, 0x8c, 0xdb, 0xde, 0x6d, + 0x31, 0x63, 0x92, 0x20, 0x8c, 0x5a, 0x6e, 0x12, 0xc0, 0x52, 0x1d, 0x69, 0x40, 0x11, 0xb6, 0x85, + 0x1d, 0xc3, 0x90, 0x15, 0xaf, 0x51, 0x62, 0xfb, 0x76, 0xef, 0xc4, 0xc0, 0xba, 0xed, 0xf5, 0xd9, + 0x7f, 0xfa, 0x0e, 0x97, 0x5f, 0xec, 0x69, 0x4a, 0x55, 0xa4, 0xf3, 0x24, 0xc8, 0x45, 0xe8, 0xd4, + 0xb9, 0xd1, 0x34, 0x6e, 0x7e, 0x0b, 0x30, 0xf8, 0xc9, 0xdb, 0xfa, 0x9e, 0x80, 0x58, 0x4d, 0x29, + 0x95, 0xfc, 0x50, 0xe2, 0x91, 0x0d, 0xd3, 0x69, 0xba, 0xf3, 0xe3, 0xc5, 0x82, 0x2e, 0xd5, 0x8a, + 0xb3, 0x87, 0x83, 0xad, 0x6a, 0x8f, 0xfd, 0x67, 0x7a, 0x73, 0x58, 0x53, 0x7a, 0x7f, 0xf6, 0xfe, + 0xea, 0xae, 0xbd, 0xa1, 0xb4, 0x62, 0xc1, 0xe9, 0xed, 0x12, 0xdf, 0x6b, 0x06, 0xe7, 0x13, 0xca, + 0xbf, 0xba, 0x7a, 0x9c, 0x98, 0xce, 0xba, 0x40, 0x8d, 0xfb, 0xe5, 0x99, 0xba, 0xc7, 0xaf, 0x74, + 0xb6, 0xe8, 0x16, 0x3d, 0x36, 0x8b, 0xe1, 0xb6, 0x0e, 0x63, 0xd2, 0x31, 0x9b, 0xc5, 0x7b, 0x05, + 0xfb, 0x88, 0xc6, 0x1b, 0x3e, 0xfc, 0x52, 0xcd, 0x9d, 0x5f, 0x77, 0x13, 0xcb, 0x7c, 0xfb, 0x75, + 0xbe, 0x88, 0x76, 0xa4, 0x37, 0x19, 0xdc, 0x5d, 0xc1, 0x26, 0x28, 0x3c, 0x17, 0x5e, 0x93, 0x24, + 0xaf, 0x67, 0x80, 0x1e, 0x46, 0xa7, 0xc0, 0xfa, 0xfd, 0xf9, 0x08, 0x74, 0x40, 0xf6, 0x89, 0x6e, + 0x78, 0xd2, 0x18, 0x3f, 0xa5, 0xb6, 0xfd, 0x8b, 0xcf, 0x11, 0x9c, 0x44, 0xa5, 0x05, 0x7d, 0xdf, + 0x4f, 0xaa, 0x83, 0xdb, 0xef, 0xb1, 0x50, 0xca, 0xb8, 0x99, 0x4b, 0xab, 0xd7, 0x7b, 0x73, 0xad, + 0xfd, 0x46, 0xb2, 0x8b, 0xeb, 0x6c, 0x92, 0x50, 0x76, 0xb6, 0x01, 0x21, 0x75, 0xeb, 0x08, 0x26, + 0xab, 0x27, 0x93, 0x39, 0x5a, 0x4b, 0x1b, 0xc5, 0x17, 0x7e, 0x73, 0x8d, 0xb6, 0x63, 0x21, 0xd3, + 0x8c, 0x5a, 0x0f, 0xb4, 0x75, 0xcf, 0xc3, 0x86, 0x60, 0x28, 0x8e, 0x41, 0x98, 0x12, 0x9b, 0x8c, + 0x55, 0x9d, 0x03, 0x82, 0x3b, 0xd1, 0x79, 0xd1, 0xf6, 0x3d, 0x64, 0x89, 0x7d, 0x77, 0xc1, 0xce, + 0xac, 0x98, 0xd7, 0x61, 0x6c, 0xe2, 0x5c, 0x08, 0x5f, 0x54, 0xf2, 0x64, 0x7f, 0xc9, 0xa5, 0x43, + 0x9c, 0x58, 0xac, 0xa2, 0x70, 0xac, 0x0b, 0x0e, 0xec, 0x77, 0xd2, 0x46, 0x13, 0xee, 0x2d, 0xa5, + 0xcf, 0xdc, 0xfd, 0x1f, 0xae, 0xba, 0xf4, 0x60, 0x70, 0x67, 0x7d, 0xc8, 0x00, 0xfe, 0x7c, 0x72, + 0xb3, 0xd9, 0x96, 0x6b, 0x0c, 0xa8, 0x39, 0x40, 0x34, 0x20, 0xcd, 0x3c, 0x18, 0x33, 0x80, 0xc0, + 0x56, 0x5b, 0x2d, 0x2a, 0xc1, 0x5a, 0xa3, 0x3c, 0x8c, 0x7a, 0x6f, 0xb4, 0x56, 0x70, 0xc2, 0xda, + 0xdb, 0x70, 0x74, 0x39, 0x62, 0xab, 0x01, 0x5f, 0x53, 0xf2, 0xbf, 0x3d, 0x66, 0x0a, 0xd1, 0xc6, + 0xcf, 0xbe, 0xa3, 0x10, 0xfb, 0x0d, 0xa5, 0xb5, 0x78, 0x15, 0xb7, 0x30, 0xd0, 0xd1, 0x16, 0x89, + 0x2e, 0x4c, 0xe2, 0x69, 0x52, 0xac, 0xa4, 0x85, 0xc8, 0xd9, 0xa2, 0xe3, 0x6b, 0x96, 0x03, 0xf2, + 0x3b, 0x14, 0x41, 0x0d, 0xc7, 0x44, 0x81, 0x8d, 0xf5, 0x5e, 0x3d, 0x26, 0xb1, 0xe2, 0x64, 0xaa, + 0x98, 0xa0, 0xe9, 0x95, 0x90, 0x35, 0x1a, 0x10, 0x01, 0x57, 0x71, 0x9a, 0x94, 0x8f, 0xc4, 0xc9, + 0x14, 0xc0, 0xc9, 0xa0, 0xe5, 0xa5, 0x0e, 0x1c, 0xb9, 0x73, 0xc0, 0xc4, 0x24, 0x2f, 0x15, 0x5c, + 0x50, 0x24, 0xba, 0xee, 0x2e, 0x66, 0x74, 0x58, 0x71, 0xfd, 0x9d, 0xcb, 0x8a, 0x2f, 0xea, 0xdc, + 0x95, 0x44, 0x4b, 0x0a, 0x0e, 0xa5, 0xb1, 0x1c, 0xdf, 0xee, 0xaa, 0x01, 0x3c, 0x7b, 0x1d, 0x78, + 0xb1, 0xd8, 0x71, 0x32, 0x28, 0x09, 0x5e, 0x07, 0x38, 0x62, 0x3e, 0x4e, 0xfa, 0x4d, 0x62, 0xef, + 0x86, 0x80, 0xa0, 0x60, 0x44, 0xe1, 0xf0, 0x3c, 0xdf, 0xc6, 0x00, 0xe8, 0x41, 0x00, 0xb6, 0x2b, + 0x86, 0xac, 0x2a, 0xc1, 0x13, 0x84, 0xb9, 0xa0, 0x03, 0xd1, 0xaa, 0x06, 0x3c, 0x42, 0x28, 0x0a, + 0x50, 0x19, 0x64, 0x3f, 0x9a, 0x6c, 0x54, 0x36, 0xc7, 0xea, 0x43, 0xe8, 0x83, 0x92, 0xdd, 0x8e, + 0x02, 0x67, 0x56, 0x6f, 0x9d, 0xc7, 0x83, 0x19, 0x08, 0x65, 0xa0, 0x67, 0x0c, 0x7f, 0xbb, 0xaf, + 0x31, 0x15, 0x03, 0xb0, 0xbb, 0xc4, 0x1e, 0x80, 0xd0, 0x0a, 0xb3, 0x6c, 0x82, 0x71, 0x89, 0x78, + 0xb7, 0x02, 0x0b, 0xd3, 0x77, 0x82, 0x00, 0xa5, 0xbc, 0xeb, 0x98, 0xcc, 0xbf, 0x88, 0xbf, 0xc4, + 0xea, 0x20, 0x0a, 0x22, 0x4c, 0x25, 0x08, 0x5b, 0x98, 0x60, 0x44, 0x80, 0xd0, 0x4d, 0x7c, 0x5f, + 0x8f, 0x1c, 0xe2, 0x3f, 0x75, 0x09, 0xb0, 0x04, 0x22, 0x34, 0x0e, 0x58, 0x8d, 0x7f, 0x08, 0x58, + 0x09, 0x98, 0x51, 0x85, 0xac, 0x81, 0x00, 0x59, 0x09, 0x22, 0xf5, 0x7e, 0xec, 0x1a, 0x67, 0xcd, + 0xdb, 0x60, 0x84, 0xa4, 0x88, 0x3a, 0xfa, 0x6c, 0x8e, 0x12, 0xf9, 0xd9, 0x77, 0x14, 0x66, 0xbc, + 0xa1, 0x34, 0x9d, 0xcd, 0x76, 0x9c, 0xa6, 0x74, 0xea, 0x17, 0xc8, 0x20, 0xc0, 0x1b, 0x71, 0xb1, + 0x78, 0x7d, 0xf4, 0x21, 0xbc, 0x37, 0xe8, 0xcc, 0xd7, 0xd1, 0x23, 0xeb, 0xcd, 0xf4, 0x6e, 0x52, + 0xfe, 0x47, 0xea, 0xd2, 0x7e, 0x7d, 0xd3, 0x8f, 0x3f, 0xa8, 0xf7, 0x68, 0x4b, 0x77, 0x70, 0xb7, + 0x3f, 0x96, 0x45, 0x5f, 0xd6, 0x00, 0xb7, 0xf0, 0x50, 0xa5, 0xbd, 0x4a, 0xe1, 0x9a, 0xf8, 0xe7, + 0x9b, 0x7f, 0xf9, 0x8e, 0x4a, 0x7f, 0xb3, 0x8e, 0x0c, 0x17, 0xac, 0x5b, 0x17, 0x72, 0xc2, 0x89, + 0xf1, 0x7d, 0xc9, 0x07, 0xe5, 0x03, 0xbc, 0xaa, 0xd1, 0xda, 0xe4, 0x8a, 0xb6, 0xc4, 0x6d, 0x3e, + 0x31, 0xe8, 0x5b, 0x4e, 0x43, 0x29, 0x42, 0x0c, 0xd0, 0x96, 0x77, 0x68, 0x08, 0xfc, 0x96, 0x14, + 0x7e, 0x82, 0x84, 0xfb, 0x47, 0x8e, 0x70, 0x46, 0x18, 0x8b, 0x4f, 0x82, 0xe5, 0x8d, 0x73, 0xec, + 0xe3, 0x99, 0xe4, 0xf7, 0x1e, 0x86, 0x86, 0x26, 0x2d, 0xaa, 0x9a, 0xa8, 0x24, 0x93, 0x06, 0x33, + 0xa2, 0xf8, 0x4d, 0x3a, 0xa9, 0x67, 0x57, 0xc4, 0xda, 0x26, 0x11, 0x6f, 0x21, 0xd8, 0xe8, 0xf1, + 0x42, 0x7b, 0xd3, 0x7e, 0x54, 0xb9, 0x6f, 0x07, 0xe2, 0x0a, 0x66, 0x9c, 0x68, 0x0f, 0x26, 0xc7, + 0x54, 0xa2, 0xf9, 0x62, 0x64, 0x88, 0xb7, 0x9f, 0xfa, 0x89, 0xe0, 0x88, 0xdf, 0x4f, 0x14, 0x58, + 0x92, 0x39, 0x0a, 0xc7, 0xea, 0xfe, 0x25, 0x75, 0x79, 0x21, 0x17, 0xc5, 0x0e, 0x0a, 0x0f, 0x44, + 0x9f, 0xb9, 0x8d, 0x5d, 0x5f, 0x32, 0x95, 0xe3, 0xe9, 0x28, 0x93, 0xdf, 0x9c, 0xe6, 0xd5, 0x93, + 0x33, 0xa3, 0x11, 0x28, 0x35, 0xc9, 0x19, 0xee, 0x76, 0xb9, 0xc5, 0x3e, 0x9b, 0x3c, 0xb4, 0x72, + 0x67, 0xb5, 0x9d, 0x0f, 0xd9, 0x42, 0x48, 0x8c, 0x7f, 0xd2, 0xd6, 0x94, 0xd3, 0x4b, 0xe8, 0xd8, + 0x39, 0xf7, 0xa9, 0xad, 0x6c, 0xe9, 0x37, 0x44, 0x19, 0xc9, 0x07, 0x8c, 0x72, 0xb9, 0xfe, 0xa3, + 0x00, 0xea, 0xfd, 0xd5, 0x34, 0x77, 0x10, 0x9e, 0xef, 0x9f, 0x9d, 0x36, 0x89, 0x9b, 0xc7, 0xdb, + 0xf6, 0xcf, 0xd1, 0xb8, 0x30, 0xf3, 0x0d, 0xa5, 0x8d, 0xb9, 0x8e, 0xf9, 0x90, 0xab, 0x6f, 0xf9, + 0x08, 0x88, 0x3a, 0x09, 0x8e, 0x03, 0xe0, 0x24, 0x28, 0x78, 0x2e, 0x5d, 0x39, 0x10, 0x95, 0x88, + 0x57, 0x6e, 0xe3, 0x75, 0xb0, 0x5c, 0x5f, 0x92, 0xd4, 0x04, 0xd8, 0x5e, 0xfe, 0xdf, 0xe3, 0x6f, + 0x24, 0x07, 0xd0, 0xd7, 0xf1, 0x87, 0x95, 0x25, 0xfd, 0x9a, 0xe4, 0x75, 0xfc, 0xd1, 0x0b, 0xde, + 0xdd, 0x1a, 0x30, 0xe6, 0x4a, 0x46, 0x5a, 0x00, 0x8c, 0x7b, 0x3a, 0x9a, 0x7f, 0x8e, 0x3f, 0xe5, + 0xd3, 0x0b, 0x65, 0xf2, 0x3a, 0xfe, 0xa8, 0xec, 0xd7, 0xf1, 0xd7, 0x94, 0xfc, 0xf7, 0xf8, 0x0b, + 0xff, 0x18, 0x7f, 0xae, 0xe9, 0xeb, 0xf8, 0xcb, 0x7f, 0xbb, 0x33, 0x4b, 0x50, 0xc7, 0xcd, 0xcd, + 0x77, 0xd4, 0xa9, 0xc6, 0x1a, 0x65, 0x13, 0xc2, 0x6d, 0xd7, 0xa4, 0xcc, 0xd7, 0x71, 0xbf, 0x3e, + 0xcd, 0x4a, 0x88, 0x49, 0x7a, 0xfe, 0x52, 0x20, 0xf6, 0xea, 0x13, 0x61, 0xaf, 0x77, 0x33, 0x23, + 0xf8, 0x72, 0x6c, 0x7a, 0xaa, 0x7e, 0x25, 0x4c, 0xa5, 0xfd, 0x7f, 0x46, 0x6a, 0x9d, 0x9c, 0xe4, + 0x9e, 0x80, 0xe3, 0xad, 0x85, 0x20, 0x1e, 0xbd, 0xf9, 0x11, 0xa9, 0x75, 0xc8, 0x54, 0x6c, 0x7b, + 0x5a, 0x46, 0xa9, 0xed, 0xbc, 0x26, 0xfd, 0xa8, 0x94, 0x75, 0x21, 0xa6, 0x56, 0x5f, 0x49, 0xd3, + 0x6e, 0x1d, 0xb3, 0xec, 0xb8, 0xcc, 0x6b, 0xa6, 0xa4, 0x5c, 0xad, 0xda, 0x00, 0x58, 0xae, 0x47, + 0xff, 0x19, 0xb3, 0x05, 0xd9, 0xb6, 0xd3, 0xe4, 0x03, 0xe3, 0xe9, 0x70, 0xe1, 0xcf, 0xb0, 0x57, + 0x9d, 0x28, 0x25, 0x91, 0xc4, 0xb2, 0x00, 0x0e, 0xf5, 0xb3, 0xfa, 0x5d, 0x62, 0x2e, 0x76, 0x55, + 0x6e, 0x55, 0x55, 0xc0, 0x7a, 0x80, 0xa0, 0xb0, 0xef, 0xb1, 0xc4, 0xde, 0x03, 0xfc, 0xcb, 0x90, + 0x31, 0x7e, 0x50, 0x2c, 0xb0, 0x42, 0x5f, 0x5a, 0x5b, 0x52, 0xc0, 0x15, 0x4b, 0x0c, 0xe0, 0xee, + 0xcf, 0xf3, 0x34, 0x22, 0x7a, 0x43, 0x69, 0xd3, 0xe5, 0x04, 0x87, 0xa7, 0xda, 0x81, 0xd6, 0xc8, + 0x65, 0x73, 0x8e, 0x0e, 0x35, 0xb9, 0xb1, 0xe7, 0x2b, 0xae, 0xca, 0x8d, 0x96, 0xf1, 0x56, 0x4c, + 0x58, 0x67, 0xad, 0x85, 0xbf, 0x1c, 0x1a, 0x25, 0xb2, 0x16, 0xd6, 0xfd, 0xe8, 0x39, 0x71, 0x9f, + 0x98, 0x2f, 0xfc, 0x5e, 0xe6, 0xe8, 0x5e, 0xbb, 0x9d, 0x94, 0x55, 0x89, 0x6a, 0x6b, 0x99, 0x27, + 0xeb, 0xee, 0x49, 0x31, 0xf9, 0x97, 0x8e, 0x48, 0x80, 0xc4, 0x1e, 0x65, 0xd6, 0xea, 0xcb, 0xb2, + 0xa0, 0x2a, 0x0c, 0x18, 0x58, 0x1e, 0x44, 0x71, 0x23, 0x2d, 0xfb, 0x47, 0x9b, 0xba, 0x9d, 0xde, + 0xe1, 0xda, 0xfc, 0x7d, 0x87, 0xc4, 0x60, 0xd8, 0x42, 0x17, 0xf2, 0x7b, 0x56, 0x47, 0x5f, 0xa7, + 0x08, 0xe3, 0x8c, 0xbc, 0x12, 0xe8, 0x8d, 0x72, 0xba, 0xab, 0xe7, 0xeb, 0x5c, 0xf1, 0xb6, 0xe6, + 0xbb, 0x58, 0x3e, 0x8e, 0x33, 0x44, 0x46, 0xbe, 0x33, 0xc0, 0x08, 0xb3, 0x23, 0xc3, 0x5a, 0x69, + 0xac, 0x6b, 0x71, 0xf6, 0x54, 0xad, 0xf5, 0xc2, 0xce, 0x99, 0xc4, 0x52, 0x35, 0xa3, 0xde, 0xd3, + 0x99, 0x25, 0xfd, 0x0d, 0x17, 0x32, 0xd1, 0x2f, 0xad, 0xf8, 0x5e, 0x05, 0xa6, 0x19, 0x44, 0x86, + 0x7f, 0x16, 0x6e, 0xc6, 0x55, 0xd9, 0xd6, 0xd1, 0xac, 0x95, 0x50, 0xa8, 0xe3, 0x99, 0xc7, 0x92, + 0xee, 0x06, 0x61, 0x4b, 0xc6, 0x57, 0xc4, 0x86, 0xb9, 0x23, 0xc4, 0x26, 0x0b, 0xfc, 0x38, 0x31, + 0xb3, 0x9c, 0xc9, 0x1e, 0x25, 0xe4, 0xcb, 0x2f, 0xad, 0x59, 0xc2, 0xe9, 0x24, 0x41, 0xe2, 0x4b, + 0x35, 0x73, 0x9a, 0x11, 0x9b, 0x10, 0x4e, 0x26, 0xe7, 0x38, 0x41, 0xc6, 0x25, 0xa3, 0xe7, 0xd9, + 0x52, 0x1c, 0xdf, 0x86, 0x39, 0xa0, 0x69, 0x14, 0xd3, 0x75, 0xcc, 0x69, 0x79, 0xbd, 0x31, 0x43, + 0x51, 0x4e, 0xab, 0xf3, 0x7b, 0x5a, 0x7b, 0xa9, 0xf6, 0xce, 0x2c, 0xba, 0x07, 0x39, 0xd5, 0xb2, + 0x03, 0x63, 0x88, 0xa4, 0xca, 0x3f, 0x9d, 0x16, 0x3a, 0xeb, 0xf5, 0x9e, 0x29, 0x1c, 0xde, 0x0a, + 0x8a, 0xb0, 0xad, 0x9f, 0xab, 0x7d, 0xe2, 0xd2, 0x37, 0x94, 0x16, 0xaa, 0xa5, 0x60, 0x3c, 0x03, + 0x82, 0x76, 0x94, 0x90, 0xde, 0xb7, 0x91, 0xb5, 0x35, 0xcc, 0x80, 0x30, 0xd8, 0xd2, 0xd3, 0x47, + 0xd5, 0x19, 0x18, 0x71, 0x11, 0x3f, 0x65, 0xaf, 0xe0, 0x5d, 0xd7, 0x1f, 0x74, 0xb0, 0xe2, 0x83, + 0xd2, 0x1a, 0x45, 0xe8, 0x97, 0x02, 0x1f, 0x42, 0x12, 0x44, 0x6c, 0x48, 0xf6, 0x32, 0x02, 0x93, + 0xe8, 0x06, 0x9e, 0xa3, 0x49, 0xce, 0x81, 0x65, 0x12, 0x02, 0x4a, 0x04, 0x77, 0x34, 0x19, 0x66, + 0xf3, 0x05, 0x84, 0x3c, 0x3b, 0x9e, 0x00, 0xc4, 0x76, 0x98, 0xa2, 0x94, 0xf0, 0x10, 0x35, 0x39, + 0x09, 0xd1, 0xf4, 0x14, 0xd0, 0x87, 0x50, 0x38, 0xc0, 0xd1, 0x61, 0xbf, 0xbc, 0x53, 0x49, 0x20, + 0x94, 0x3f, 0x93, 0x48, 0xe0, 0x47, 0x0a, 0x0b, 0xd4, 0x34, 0xae, 0xfe, 0x48, 0x61, 0x61, 0x3d, + 0x4d, 0x19, 0xa4, 0xf6, 0x69, 0x3f, 0x29, 0x20, 0xf0, 0x2c, 0xa8, 0x94, 0x2b, 0x02, 0x25, 0x90, + 0x8f, 0xb6, 0x30, 0x7e, 0xf2, 0x7b, 0x36, 0x64, 0xbb, 0x7d, 0xf9, 0x74, 0x09, 0x63, 0x6a, 0x89, + 0x60, 0x82, 0x98, 0x37, 0x84, 0x93, 0x6b, 0xf7, 0xdc, 0xda, 0xbd, 0xdc, 0xbd, 0x29, 0xba, 0xdf, + 0x75, 0x7f, 0x58, 0x9b, 0x4c, 0xcc, 0x32, 0xe1, 0x04, 0x57, 0x89, 0x05, 0x0f, 0x5f, 0x9f, 0x99, + 0x01, 0xaf, 0x76, 0x6b, 0xbe, 0x6d, 0x0d, 0x9a, 0x97, 0x39, 0xd5, 0xb0, 0x56, 0x76, 0x1f, 0xd1, + 0x9a, 0xb9, 0x49, 0xab, 0x4a, 0xc5, 0x69, 0xbb, 0x06, 0xbd, 0x5c, 0xa1, 0xfc, 0x14, 0x37, 0xee, + 0xc0, 0xaa, 0xa3, 0x99, 0x42, 0xf3, 0x54, 0x6b, 0x24, 0x8f, 0x9a, 0xd8, 0xa7, 0xe2, 0x1f, 0x3b, + 0x9a, 0x5c, 0x5d, 0x15, 0x24, 0xb4, 0x16, 0xa5, 0x9e, 0x39, 0xd1, 0xd4, 0xd4, 0x99, 0xd9, 0x92, + 0x6c, 0x28, 0x5c, 0xb2, 0x98, 0x08, 0x4b, 0x0a, 0x6a, 0x78, 0x1c, 0xa9, 0xe2, 0xd0, 0x7c, 0x68, + 0x04, 0x2d, 0xdb, 0x37, 0xcd, 0xa2, 0xd7, 0xfd, 0x37, 0xf9, 0x29, 0x48, 0x6f, 0x28, 0x8d, 0x6a, + 0x35, 0x8d, 0x9e, 0x5a, 0xa2, 0x1a, 0x6d, 0xf5, 0x94, 0xd6, 0xbb, 0xde, 0x93, 0x68, 0x7b, 0x14, + 0xbb, 0x10, 0x6b, 0x1e, 0x44, 0x90, 0x46, 0x67, 0xa9, 0x15, 0x82, 0x21, 0x8d, 0xbd, 0x50, 0xae, + 0xb4, 0x68, 0x41, 0x48, 0xbc, 0xb1, 0xd5, 0xce, 0x4b, 0x0c, 0xb5, 0x2c, 0xd4, 0x7c, 0x59, 0x90, + 0xce, 0x5e, 0x0d, 0xca, 0xe7, 0x33, 0x62, 0xa3, 0xbf, 0xac, 0x69, 0xc4, 0xfe, 0x02, 0x4a, 0x47, + 0x06, 0x6c, 0xc9, 0x68, 0xaf, 0xcc, 0x48, 0x8c, 0xf5, 0x17, 0xb7, 0x5f, 0x67, 0x18, 0xfc, 0xc5, + 0x92, 0xc5, 0x6e, 0x46, 0xe4, 0x70, 0xed, 0x75, 0x44, 0xac, 0xd8, 0x50, 0xcc, 0x68, 0xbe, 0x42, + 0xe3, 0x9d, 0xff, 0xa8, 0x19, 0x3a, 0x2a, 0xa7, 0x57, 0x85, 0x66, 0x2d, 0x9d, 0xc4, 0xfd, 0xa7, + 0xc1, 0x50, 0x28, 0x63, 0x4a, 0xe5, 0xb1, 0x77, 0xeb, 0x71, 0x35, 0xbd, 0xb3, 0x7b, 0x53, 0x55, + 0x4f, 0x63, 0x4f, 0xa5, 0xc6, 0x99, 0x9b, 0xbc, 0xb8, 0x23, 0x1d, 0x85, 0x58, 0x66, 0xad, 0x7f, + 0x4e, 0x69, 0x3c, 0xfe, 0x63, 0x53, 0x76, 0x7e, 0x8c, 0xce, 0x94, 0x93, 0x36, 0xcc, 0x68, 0x36, + 0x1e, 0xea, 0xda, 0xe4, 0xf1, 0x36, 0x82, 0x07, 0x3e, 0xc7, 0xd5, 0xc1, 0xac, 0x56, 0xde, 0x0a, + 0xeb, 0xce, 0xa7, 0xa7, 0xb9, 0xb5, 0x99, 0xcd, 0xf9, 0xc1, 0x62, 0xb8, 0x27, 0x12, 0x0c, 0x7e, + 0x18, 0xa6, 0x5b, 0xc0, 0x61, 0xb3, 0xb0, 0x90, 0x31, 0xdd, 0xc6, 0x17, 0xaf, 0xe2, 0x47, 0x85, + 0xaa, 0x79, 0x7f, 0xd4, 0xd4, 0xb1, 0x4a, 0xad, 0x91, 0x16, 0x3f, 0x1e, 0x61, 0xcc, 0x3f, 0x8c, + 0xa4, 0x67, 0xea, 0x15, 0xcc, 0x34, 0x3c, 0x34, 0xbe, 0x7d, 0x6f, 0x2b, 0xa2, 0xe5, 0xf4, 0x96, + 0xc8, 0x61, 0xf5, 0x06, 0x46, 0x0f, 0xc7, 0xde, 0x30, 0x57, 0x7b, 0xe2, 0x55, 0x96, 0x35, 0x0f, + 0x95, 0xbe, 0x59, 0x3f, 0x8d, 0x17, 0xcd, 0xe7, 0xae, 0xeb, 0x81, 0xde, 0xf6, 0x40, 0xcb, 0x2a, + 0x65, 0xc2, 0x8d, 0x0f, 0xcf, 0x9c, 0xfd, 0xee, 0xcf, 0x39, 0x57, 0xe4, 0x6f, 0x28, 0x1d, 0xde, + 0x23, 0xd0, 0x0b, 0xba, 0xa2, 0xca, 0x1f, 0x67, 0xd8, 0xc5, 0xa1, 0x77, 0xaa, 0xac, 0x49, 0x56, + 0xa7, 0x46, 0x62, 0x1c, 0x24, 0x03, 0xae, 0xf5, 0x5e, 0xf8, 0x40, 0xe8, 0x3a, 0x4f, 0x00, 0xaf, + 0xc7, 0x51, 0x92, 0xf7, 0x4e, 0x0b, 0x9b, 0x67, 0x0e, 0x7d, 0x7d, 0x66, 0x5d, 0x35, 0xf9, 0x1d, + 0x5a, 0xd1, 0xd8, 0xa5, 0x1e, 0x08, 0xbf, 0x60, 0x4d, 0x93, 0xb9, 0x59, 0xcd, 0xc6, 0x34, 0x61, + 0x11, 0x2d, 0x0f, 0x96, 0xf0, 0x16, 0xa7, 0x69, 0xc2, 0xe5, 0x1f, 0xf3, 0xf0, 0xf8, 0x69, 0x7c, + 0x1f, 0x5e, 0x7a, 0x6a, 0x87, 0x70, 0x22, 0x01, 0x28, 0xed, 0x13, 0x14, 0xd7, 0xd9, 0x27, 0x8b, + 0x46, 0x56, 0x57, 0x7e, 0x82, 0x12, 0xd5, 0x3b, 0x23, 0xbe, 0x0f, 0x93, 0x57, 0x56, 0x2a, 0xb1, + 0x09, 0x35, 0x3d, 0xb6, 0xf6, 0x45, 0xac, 0x94, 0xe0, 0xfc, 0x2e, 0xff, 0xe7, 0xd7, 0x66, 0xf1, + 0x80, 0xe7, 0xba, 0x46, 0x28, 0x50, 0xbb, 0xfd, 0xd4, 0xcf, 0xed, 0xfa, 0x0a, 0x82, 0xcf, 0x30, + 0xac, 0x35, 0x95, 0xb7, 0xf6, 0xc8, 0x06, 0x10, 0x84, 0x19, 0x1c, 0x0e, 0xbc, 0x1b, 0x5e, 0x05, + 0xec, 0x4f, 0x04, 0x99, 0x0f, 0xff, 0xde, 0x17, 0x36, 0x4e, 0xd1, 0xda, 0xea, 0x54, 0x25, 0x5d, + 0xa3, 0x78, 0x22, 0x81, 0x14, 0xc5, 0x5d, 0x5e, 0x79, 0x8c, 0xb0, 0x6f, 0x5e, 0x1e, 0xa7, 0xca, + 0x32, 0x89, 0x0a, 0xba, 0xdd, 0xd4, 0x47, 0x8a, 0xcb, 0x11, 0x2a, 0xcc, 0x3b, 0x9a, 0x73, 0xb1, + 0x86, 0x5b, 0xda, 0x5a, 0x5b, 0x24, 0x60, 0x1a, 0x6d, 0x15, 0xb4, 0x3e, 0x8a, 0xe6, 0x1d, 0xe2, + 0x68, 0xfd, 0xc1, 0xfd, 0xd0, 0xd3, 0x47, 0x80, 0xaf, 0x57, 0x79, 0xac, 0x64, 0x0d, 0xd0, 0xb4, + 0xb0, 0xdb, 0x7b, 0x72, 0x40, 0x78, 0x2b, 0x83, 0x42, 0x1a, 0xf4, 0x63, 0x97, 0x79, 0x5e, 0xff, + 0xe9, 0x92, 0x25, 0x78, 0x14, 0x7d, 0xaf, 0x94, 0x70, 0x33, 0x07, 0x80, 0x47, 0x12, 0x20, 0x8a, + 0xef, 0x86, 0x59, 0x91, 0x2a, 0xc6, 0xa4, 0xb2, 0x1d, 0x3f, 0xef, 0x5c, 0xe4, 0x8a, 0x37, 0x94, + 0xce, 0xa1, 0x52, 0x89, 0xfb, 0x09, 0x15, 0xdb, 0x6a, 0xc2, 0x15, 0xcb, 0xb1, 0x9b, 0xc1, 0x64, + 0xdf, 0x7e, 0x9d, 0x30, 0xce, 0x06, 0xc1, 0x5c, 0xe8, 0x41, 0x4e, 0x93, 0x0f, 0x0d, 0xf6, 0xf4, + 0x8a, 0x2e, 0x5a, 0x53, 0x1b, 0xa5, 0xe3, 0xdb, 0xe9, 0xbf, 0x03, 0x89, 0xff, 0xb9, 0x3c, 0x45, + 0x5f, 0x97, 0xa7, 0xd6, 0xbf, 0x96, 0xa7, 0x2f, 0x37, 0xff, 0x5e, 0x9e, 0x52, 0x86, 0x1f, 0xcb, + 0x13, 0xbc, 0x7b, 0x52, 0x6c, 0x7a, 0xaa, 0xe8, 0xa5, 0xfa, 0x88, 0x80, 0xc8, 0xf7, 0xa9, 0xb8, + 0x8a, 0x0a, 0xf1, 0x3a, 0x94, 0x4b, 0x61, 0x24, 0xbc, 0x7a, 0x79, 0x75, 0xfe, 0x3f, 0x16, 0x25, + 0x20, 0x16, 0xca, 0x3e, 0xdf, 0x6d, 0x0c, 0x19, 0x39, 0x00, 0x86, 0xb1, 0xfc, 0x10, 0x9a, 0x9b, + 0xe4, 0xc0, 0x60, 0x7a, 0xae, 0x88, 0xd5, 0x12, 0x43, 0xc9, 0xd1, 0xe0, 0xf9, 0x66, 0x18, 0x8a, + 0x22, 0x93, 0xc7, 0xab, 0xa1, 0xf8, 0xf2, 0x37, 0xd6, 0x4b, 0x1a, 0x7f, 0x76, 0x9b, 0xe2, 0x0a, + 0x8a, 0x2e, 0x08, 0xb1, 0x08, 0x87, 0xf7, 0xf0, 0xf9, 0x92, 0x6b, 0x23, 0x67, 0x1e, 0x34, 0x35, + 0xd2, 0xea, 0x63, 0xd4, 0xd5, 0x67, 0xac, 0x45, 0xf8, 0x61, 0x2a, 0x65, 0x1b, 0x26, 0xc8, 0x55, + 0x70, 0x3b, 0x48, 0xe3, 0xf0, 0x6c, 0x7a, 0x19, 0x00, 0x3b, 0x49, 0xcb, 0x4f, 0x2e, 0x1f, 0x4e, + 0x5a, 0xbb, 0xbf, 0x86, 0xd7, 0xe6, 0x73, 0xfc, 0x3a, 0xcd, 0x04, 0xaa, 0x7f, 0x84, 0xa0, 0xda, + 0xdd, 0x4a, 0x36, 0x18, 0x85, 0x3f, 0xb4, 0x5d, 0xf6, 0xc0, 0x09, 0x20, 0xf0, 0xc0, 0xa4, 0xb1, + 0x9b, 0xdf, 0x0d, 0x68, 0xc4, 0x82, 0x0a, 0x2e, 0xe1, 0x27, 0x7d, 0x2d, 0x09, 0xe0, 0x67, 0x32, + 0xa4, 0x2c, 0x88, 0xce, 0xa6, 0xf3, 0xcb, 0x08, 0x7b, 0x81, 0x5f, 0xd6, 0xb3, 0x0d, 0x2d, 0x3e, + 0xce, 0xa4, 0x88, 0xcb, 0x24, 0xec, 0x37, 0xf1, 0xe4, 0x6f, 0x6a, 0x50, 0xaa, 0xdf, 0x50, 0xba, + 0x20, 0xd4, 0x19, 0xd2, 0xec, 0xa0, 0xf0, 0x0b, 0xb1, 0x22, 0xd2, 0x11, 0xf5, 0x2c, 0x60, 0x50, + 0x7f, 0xc9, 0x0e, 0x55, 0xe2, 0x3a, 0x39, 0xe9, 0xfd, 0x16, 0x56, 0xdf, 0xd9, 0x2b, 0x5d, 0xa0, + 0xbe, 0xe3, 0x40, 0x62, 0x6b, 0x6e, 0x97, 0x27, 0xa0, 0x11, 0x42, 0x18, 0x9d, 0x26, 0xe4, 0x41, + 0xfa, 0x05, 0x21, 0x08, 0xeb, 0x97, 0x85, 0x3c, 0xbd, 0x9e, 0x22, 0x84, 0xa1, 0xec, 0x8e, 0xf8, + 0x1b, 0xd2, 0x52, 0x48, 0xac, 0x44, 0xdf, 0xc4, 0xbe, 0xf5, 0x9d, 0x18, 0xef, 0x79, 0x48, 0xdf, + 0x8c, 0x81, 0x44, 0x82, 0x22, 0x28, 0xeb, 0xe9, 0x34, 0xde, 0x0e, 0x7d, 0x89, 0x2c, 0xbe, 0x3b, + 0xc7, 0xd8, 0x79, 0xfb, 0x55, 0x9d, 0x5d, 0xa8, 0x54, 0x02, 0x4a, 0x31, 0x41, 0xad, 0x6b, 0xa5, + 0x76, 0x3b, 0xbe, 0xc7, 0xae, 0xd9, 0x91, 0x3d, 0x8e, 0xa3, 0x41, 0xb0, 0x4a, 0xfc, 0x09, 0x19, + 0xe4, 0x3f, 0x6f, 0x89, 0x58, 0x56, 0xfb, 0xe4, 0x82, 0x0c, 0xc1, 0x7a, 0x9a, 0x48, 0xe0, 0x41, + 0xf1, 0x8f, 0x42, 0xa7, 0x2f, 0x24, 0xf8, 0xec, 0x27, 0x3f, 0x52, 0x0d, 0xb6, 0xb9, 0x7a, 0x03, + 0xe8, 0xf5, 0xb7, 0xc8, 0xb0, 0x15, 0x1f, 0xa0, 0x65, 0xe8, 0x9a, 0x00, 0xd8, 0x15, 0x6c, 0x8d, + 0x22, 0x8b, 0x26, 0x5a, 0xbf, 0x45, 0x7a, 0x95, 0x0c, 0x50, 0xe9, 0x7e, 0x79, 0xb5, 0xed, 0xad, + 0x01, 0x09, 0x28, 0x73, 0xf8, 0x5a, 0x8b, 0xdb, 0xce, 0x8d, 0x35, 0xde, 0x81, 0x94, 0x1a, 0xe6, + 0xf0, 0x67, 0xd7, 0xc9, 0xbd, 0xdd, 0xfb, 0xc0, 0x5e, 0x2e, 0xd9, 0xeb, 0x0e, 0x04, 0x06, 0xa7, + 0x5f, 0x29, 0xb9, 0x8d, 0xc5, 0x1b, 0x68, 0x26, 0xea, 0xae, 0x71, 0x59, 0xdd, 0xcd, 0xe4, 0xf7, + 0xcf, 0x15, 0x4c, 0x34, 0x6f, 0x15, 0x5f, 0xe7, 0xbe, 0xb3, 0x2a, 0xc1, 0xe5, 0xbe, 0x15, 0xec, + 0xcb, 0x43, 0x9c, 0xf0, 0x75, 0xeb, 0x1e, 0xe8, 0x12, 0xe4, 0x10, 0x50, 0x3a, 0x0c, 0x98, 0xb4, + 0x46, 0x7d, 0xf7, 0x37, 0x8f, 0x2b, 0xda, 0xf8, 0xce, 0x3a, 0xfb, 0x79, 0x9e, 0x46, 0xe8, 0x7f, + 0xaf, 0x34, 0x24, 0x4b, 0x6e, 0x77, 0x94, 0xd9, 0x33, 0x69, 0x4a, 0x1d, 0x4b, 0x80, 0x33, 0xf4, + 0x92, 0x4a, 0x1c, 0x8b, 0x84, 0x5c, 0xa5, 0x2b, 0xae, 0xce, 0xe4, 0x23, 0xd5, 0x57, 0xc3, 0xf3, + 0x85, 0x58, 0x7c, 0xc9, 0x58, 0xe0, 0x31, 0xd7, 0xe2, 0x1f, 0x2e, 0x49, 0x94, 0x90, 0x03, 0x6f, + 0x58, 0xbc, 0x9b, 0x8f, 0x67, 0x56, 0xc1, 0x4d, 0xa1, 0x9c, 0x6a, 0xf6, 0x39, 0x2f, 0xeb, 0x36, + 0xcb, 0x89, 0x28, 0xc3, 0xfb, 0x35, 0xb5, 0xb3, 0x7b, 0x8e, 0x69, 0x20, 0x1b, 0x04, 0x25, 0x01, + 0xa2, 0xf5, 0x07, 0x7d, 0x55, 0xe5, 0x1e, 0x85, 0x8a, 0xdb, 0xd3, 0x46, 0x03, 0x97, 0xb8, 0x99, + 0x39, 0x91, 0xc9, 0xbd, 0xa2, 0x01, 0x2f, 0xe1, 0xea, 0xa5, 0xce, 0x61, 0xb9, 0x29, 0xb2, 0x39, + 0xde, 0x0b, 0xf9, 0x99, 0x5a, 0x4d, 0x92, 0x9f, 0x11, 0x5b, 0xc4, 0xab, 0xe1, 0x7e, 0x7f, 0xdd, + 0x0b, 0x81, 0x46, 0xf4, 0x92, 0xc3, 0x33, 0x5d, 0xd7, 0x0d, 0xc5, 0x66, 0x6f, 0xfa, 0xa8, 0x35, + 0xe3, 0x86, 0xef, 0x4d, 0x15, 0xb6, 0x64, 0x38, 0x0d, 0x2e, 0x26, 0x16, 0x66, 0x9b, 0x44, 0x6d, + 0x29, 0x6f, 0xe9, 0xfb, 0x35, 0x07, 0x12, 0xfa, 0x09, 0xf7, 0xac, 0xdc, 0xc5, 0x52, 0xda, 0x93, + 0x0b, 0x53, 0x0c, 0x1f, 0x8c, 0x62, 0xd8, 0x54, 0x85, 0x5e, 0x0a, 0x2f, 0xdc, 0x8b, 0xa3, 0x4c, + 0x21, 0x25, 0xb8, 0x54, 0x3f, 0xec, 0xdf, 0x5c, 0xb2, 0x2d, 0xe7, 0x43, 0xca, 0x59, 0x23, 0x4d, + 0x9d, 0x42, 0xc7, 0x9a, 0x50, 0xce, 0xf0, 0x67, 0xf8, 0x4b, 0x1e, 0x50, 0x4d, 0xaa, 0xb3, 0xf8, + 0x65, 0x3c, 0xc5, 0x92, 0xb4, 0x52, 0x2b, 0x78, 0x50, 0xf8, 0x9f, 0x75, 0x4e, 0x2f, 0x97, 0xa1, + 0x17, 0x39, 0xb2, 0xf6, 0xba, 0xaf, 0xcd, 0x2f, 0x0b, 0x82, 0x9f, 0xc4, 0x7a, 0x97, 0x50, 0xc4, + 0x11, 0xea, 0xbb, 0x82, 0x51, 0x86, 0x63, 0x38, 0xb9, 0x58, 0x53, 0x61, 0xde, 0xc7, 0xb5, 0xc8, + 0x3a, 0x51, 0x08, 0x03, 0x5e, 0xaf, 0x34, 0x24, 0xd0, 0xd3, 0x7f, 0xce, 0xb9, 0xa2, 0x7f, 0xe3, + 0x9a, 0x26, 0x17, 0x53, 0x82, 0x1e, 0x3d, 0x68, 0x54, 0xcb, 0x11, 0x2c, 0xe9, 0x3b, 0x24, 0xda, + 0xbb, 0xee, 0xeb, 0xe7, 0x2c, 0x7a, 0x1f, 0xc3, 0xb2, 0x0f, 0x71, 0xa6, 0x42, 0xcc, 0x6b, 0x1c, + 0x6e, 0xa2, 0x5c, 0x49, 0x3a, 0xbb, 0x2c, 0x53, 0xcf, 0x75, 0xa4, 0xed, 0xfd, 0x97, 0x62, 0x93, + 0xc3, 0xab, 0x06, 0x75, 0x6d, 0x8b, 0xba, 0xb0, 0xc3, 0x23, 0x3e, 0x14, 0xe6, 0x27, 0x1d, 0x5a, + 0x30, 0x5d, 0xd6, 0x63, 0x93, 0x64, 0xea, 0x61, 0xef, 0x93, 0xb4, 0x23, 0x49, 0x17, 0x5e, 0x58, + 0x48, 0x60, 0x8b, 0xdd, 0x91, 0x78, 0x8b, 0xda, 0x0a, 0x8a, 0x90, 0x98, 0xca, 0x49, 0xcd, 0xaf, + 0xf6, 0x54, 0xee, 0xe6, 0x42, 0x2e, 0xfc, 0x2a, 0xc0, 0xd6, 0x4a, 0x83, 0x9b, 0x28, 0xdf, 0xe1, + 0x40, 0x04, 0xc3, 0xe8, 0x0b, 0x03, 0xb8, 0x2f, 0x5d, 0xf5, 0xb9, 0x43, 0x24, 0x40, 0x17, 0x71, + 0xf9, 0xe3, 0x94, 0x48, 0xd5, 0x62, 0xee, 0x15, 0x27, 0x38, 0x89, 0x9c, 0x71, 0x6d, 0x0f, 0x93, + 0x0d, 0x5b, 0xbc, 0x1a, 0x5f, 0x6b, 0x5b, 0x16, 0x14, 0x22, 0xb1, 0x93, 0xec, 0x97, 0x0a, 0xd2, + 0xcd, 0x13, 0xcb, 0xee, 0x14, 0x61, 0x67, 0x94, 0x93, 0x25, 0x40, 0x56, 0xfb, 0x57, 0xb9, 0x3a, + 0x7b, 0x9c, 0x62, 0x84, 0x0d, 0xa1, 0xa2, 0xe3, 0x98, 0x74, 0xb7, 0xe3, 0x72, 0xf8, 0x4d, 0x53, + 0x71, 0xdc, 0x99, 0xc8, 0x94, 0xa2, 0xf6, 0x90, 0xc6, 0xca, 0xef, 0x2a, 0x0a, 0xa6, 0xab, 0xab, + 0x74, 0x40, 0xe0, 0x9c, 0x9b, 0xcf, 0x1e, 0xdb, 0x61, 0xff, 0xc7, 0xf5, 0x38, 0x59, 0x91, 0xf7, + 0xf2, 0xe1, 0x25, 0x63, 0x6d, 0xb7, 0xd6, 0x2c, 0x46, 0xdc, 0x6a, 0x7f, 0xe9, 0xdc, 0x65, 0xbf, + 0x31, 0x49, 0x85, 0xd7, 0xfd, 0xba, 0xd0, 0x78, 0x15, 0xdc, 0x89, 0xaf, 0xdb, 0x11, 0xfa, 0x55, + 0xc3, 0x3f, 0x0c, 0xac, 0x87, 0x95, 0x41, 0xd6, 0x39, 0xa6, 0x9a, 0xac, 0x5e, 0x11, 0x9b, 0xe9, + 0xbe, 0xcc, 0xd5, 0x9c, 0x30, 0xaf, 0x6a, 0xbf, 0xf7, 0x98, 0xee, 0xbf, 0xa9, 0xe9, 0x4e, 0xda, + 0x7b, 0x43, 0xe9, 0x05, 0x26, 0xbe, 0xe1, 0x0c, 0x2c, 0xa8, 0xc4, 0x2f, 0x33, 0x43, 0x28, 0x82, + 0x91, 0x0c, 0xb8, 0x78, 0xd2, 0x5c, 0xb9, 0x10, 0x24, 0xf4, 0x16, 0xa9, 0x57, 0xfd, 0x21, 0x99, + 0x17, 0xb8, 0xe5, 0xac, 0x4b, 0xed, 0x2f, 0xc9, 0xba, 0x31, 0x34, 0x53, 0xee, 0x35, 0xa4, 0xbe, + 0x04, 0xbb, 0xf3, 0x05, 0x9b, 0x30, 0x3a, 0xfc, 0x43, 0xae, 0x25, 0xe7, 0x26, 0xd3, 0x95, 0x76, + 0x9f, 0x0f, 0x5f, 0x90, 0x20, 0x7b, 0x19, 0x83, 0x34, 0x56, 0x17, 0x95, 0xf4, 0x42, 0x42, 0xf8, + 0xa3, 0xda, 0xf2, 0xf4, 0xbe, 0x63, 0x3a, 0xed, 0x0a, 0x74, 0xa1, 0xaf, 0xad, 0xfb, 0x96, 0xa1, + 0xc6, 0xd6, 0xe9, 0x76, 0xa2, 0x03, 0x60, 0xfd, 0xd6, 0x9e, 0x55, 0xee, 0xba, 0x5e, 0x38, 0x3f, + 0xaa, 0x2d, 0x4f, 0x15, 0x16, 0x6f, 0x4d, 0xaf, 0x6a, 0xc7, 0xbc, 0x9a, 0xb5, 0x08, 0x84, 0xa8, + 0x34, 0x78, 0xbc, 0x16, 0x00, 0xb1, 0x4a, 0xff, 0xa4, 0x1f, 0x39, 0xf5, 0xcc, 0x9a, 0x4d, 0x7e, + 0x6b, 0x8e, 0xc9, 0x99, 0xb5, 0xba, 0xd8, 0x4e, 0xd5, 0xf7, 0xd4, 0x87, 0x79, 0x5b, 0x73, 0xd5, + 0x10, 0xb1, 0x8d, 0x91, 0xf3, 0x27, 0xc8, 0x02, 0xaa, 0x7a, 0x58, 0x9d, 0x99, 0x3a, 0x1b, 0x8a, + 0xa6, 0xe8, 0xc8, 0x61, 0xcf, 0xb2, 0x5f, 0xe7, 0x35, 0x76, 0x03, 0xbc, 0xad, 0xa0, 0x90, 0x12, + 0x53, 0x91, 0xc9, 0xae, 0x13, 0xf8, 0xc4, 0x9c, 0x83, 0x4f, 0x73, 0xa6, 0x83, 0xdd, 0x34, 0x4e, + 0xbe, 0x57, 0xd5, 0xc9, 0xd4, 0xc8, 0x19, 0xc5, 0x6f, 0xf1, 0x36, 0xce, 0xdb, 0x8d, 0xcf, 0x67, + 0xd8, 0x2c, 0x07, 0x0e, 0x10, 0xc9, 0x5e, 0x10, 0x74, 0xea, 0x21, 0x59, 0xe3, 0x58, 0x62, 0xf9, + 0xf3, 0x19, 0x0d, 0x32, 0xf7, 0xcb, 0xe2, 0xc0, 0xb4, 0xe1, 0xb9, 0x98, 0x6b, 0x01, 0x67, 0xb5, + 0xae, 0xb0, 0x71, 0xb7, 0x3e, 0x19, 0x24, 0x67, 0x24, 0x2a, 0x6a, 0xbd, 0x4f, 0xdc, 0x24, 0x3a, + 0x96, 0x7f, 0x04, 0x26, 0xae, 0xae, 0x69, 0x68, 0x61, 0xad, 0x23, 0xd2, 0xf9, 0xd0, 0xdf, 0xd4, + 0x74, 0xa7, 0x43, 0x6f, 0x28, 0x0d, 0x64, 0xfe, 0x48, 0xa3, 0x13, 0xa0, 0x63, 0x4b, 0x57, 0xf7, + 0x3c, 0xc8, 0x86, 0x36, 0x6b, 0xe3, 0x7b, 0x07, 0xa8, 0xf4, 0xca, 0x81, 0x2d, 0x5e, 0xd8, 0x7d, + 0xa1, 0x3d, 0xe5, 0xdd, 0x68, 0xd9, 0x58, 0xe9, 0xe9, 0x7b, 0xc0, 0x91, 0x9e, 0x91, 0x12, 0x7c, + 0xbe, 0x99, 0x62, 0x0b, 0x85, 0x6f, 0x87, 0x89, 0x1f, 0x13, 0x55, 0xe6, 0x3b, 0x50, 0x09, 0xe0, + 0xc1, 0xcf, 0x77, 0xc3, 0x9a, 0x14, 0xb8, 0x4e, 0xd3, 0x29, 0x6e, 0xa4, 0x12, 0x5a, 0xb3, 0xd6, + 0xdc, 0x43, 0xe9, 0x67, 0x5f, 0x62, 0x79, 0x52, 0xb2, 0x22, 0x43, 0x96, 0xec, 0x64, 0x02, 0x00, + 0x6e, 0x5f, 0x20, 0xc7, 0xb1, 0x60, 0x4d, 0xd2, 0xb8, 0x82, 0xfc, 0x1e, 0xfc, 0xe8, 0x14, 0x06, + 0x68, 0x63, 0x69, 0x14, 0x6f, 0x68, 0x01, 0xeb, 0x61, 0x62, 0xcd, 0x03, 0xdb, 0xf3, 0x80, 0x01, + 0xff, 0x25, 0x39, 0x58, 0xf7, 0xf4, 0xf5, 0x06, 0x47, 0x04, 0xb9, 0x64, 0xad, 0xdf, 0x4c, 0x42, + 0x1a, 0xb0, 0x92, 0xc8, 0x81, 0x57, 0xdd, 0xed, 0x57, 0xa3, 0xa6, 0x4a, 0x30, 0x16, 0x9c, 0xc2, + 0x25, 0x8c, 0x0a, 0x19, 0x7c, 0xe8, 0x9e, 0xcc, 0x17, 0x68, 0x69, 0x05, 0x5e, 0x2a, 0x95, 0x05, + 0x10, 0x62, 0xbc, 0x79, 0xb9, 0x45, 0xa2, 0x29, 0xc4, 0xae, 0x6e, 0xba, 0x0c, 0x3a, 0xbe, 0x9e, + 0x18, 0xc1, 0xcd, 0x89, 0xfc, 0x63, 0x19, 0xa1, 0xad, 0xe9, 0xc6, 0xc8, 0xde, 0x5c, 0x4d, 0x3d, + 0xd9, 0x6d, 0x25, 0x79, 0x5e, 0xe3, 0x86, 0x02, 0xde, 0x3f, 0xba, 0x2c, 0x00, 0xcf, 0x46, 0x6c, + 0x0f, 0x53, 0xc1, 0x37, 0x78, 0x48, 0xe8, 0x9d, 0x7f, 0x98, 0xbc, 0x90, 0x56, 0x6b, 0x30, 0xf1, + 0x87, 0x28, 0xa6, 0xf6, 0x8b, 0xab, 0x62, 0xf7, 0xd5, 0xa8, 0x1a, 0x8c, 0x9b, 0xeb, 0xa1, 0x5c, + 0xca, 0xd6, 0x14, 0xe4, 0xb8, 0x5a, 0x33, 0xb5, 0x7d, 0x70, 0xdc, 0xa3, 0x3f, 0xfe, 0x11, 0xa9, + 0x2d, 0x73, 0x36, 0x4e, 0x11, 0x65, 0xae, 0x80, 0xcb, 0xfb, 0xe2, 0x9c, 0x37, 0x5e, 0x15, 0x1d, + 0x23, 0xfa, 0x9f, 0xf3, 0x53, 0x04, 0xde, 0x50, 0x9a, 0x2b, 0xf0, 0xce, 0x3e, 0xf4, 0x96, 0xec, + 0x47, 0x77, 0xec, 0x08, 0x0b, 0x9b, 0x1f, 0xac, 0xdd, 0xed, 0x5c, 0x8f, 0x13, 0x92, 0xe6, 0x27, + 0x71, 0x42, 0xe7, 0xb9, 0xca, 0x47, 0x94, 0x86, 0xf3, 0x74, 0xd0, 0x29, 0xc0, 0xb2, 0xa3, 0xf5, + 0x66, 0x2b, 0xbc, 0xb0, 0x6d, 0xdb, 0xed, 0xe9, 0xcc, 0x42, 0xda, 0x27, 0x9d, 0x79, 0x27, 0xf5, + 0x28, 0xbd, 0x0a, 0x53, 0xe7, 0xf4, 0x86, 0x87, 0x5f, 0xb3, 0x9a, 0xa1, 0x23, 0x95, 0x4e, 0x18, + 0x84, 0xab, 0x09, 0xb6, 0xe7, 0xfc, 0xb6, 0xaf, 0x7b, 0x38, 0x3b, 0x6d, 0x69, 0xcf, 0x9a, 0x9e, + 0x98, 0xa1, 0xbd, 0x85, 0x2d, 0xed, 0x9d, 0x9e, 0xdf, 0xfc, 0x7b, 0x9a, 0xb5, 0xe1, 0x81, 0x81, + 0x46, 0x66, 0x24, 0xbd, 0x4e, 0xb3, 0xf8, 0xeb, 0x34, 0xfb, 0xe7, 0x35, 0x3a, 0x1a, 0x5d, 0x86, + 0x9e, 0xa7, 0xf7, 0xfb, 0x7e, 0x2c, 0xbf, 0x04, 0xbf, 0x44, 0x9f, 0x17, 0x8b, 0x33, 0x9a, 0xbf, + 0x50, 0x8a, 0xd3, 0xe8, 0xe3, 0x87, 0x23, 0x4c, 0x08, 0x45, 0xc3, 0x75, 0xd3, 0x81, 0x01, 0x1a, + 0x9d, 0x24, 0xec, 0x8d, 0x93, 0xa7, 0x52, 0x6d, 0x3f, 0xac, 0xa6, 0x9b, 0x95, 0xf1, 0x34, 0x5e, + 0xa8, 0x8d, 0xc6, 0xa5, 0xff, 0x4a, 0x7b, 0x04, 0x39, 0xfd, 0xb0, 0x59, 0x1a, 0x21, 0x20, 0xd6, + 0xd9, 0xa4, 0xf2, 0x28, 0x57, 0x25, 0x5f, 0x4e, 0x47, 0xbc, 0x07, 0xec, 0xd3, 0x5c, 0x19, 0xb8, + 0x3b, 0xcc, 0x09, 0x95, 0x21, 0xa4, 0xfe, 0xe4, 0x1a, 0x23, 0xf2, 0x90, 0x18, 0x1a, 0xa3, 0x41, + 0xae, 0xd0, 0xf2, 0x54, 0x55, 0xdd, 0xbb, 0xc3, 0xc5, 0x8b, 0x0d, 0x37, 0x99, 0x07, 0x39, 0xea, + 0xd0, 0x52, 0x3c, 0xfa, 0x3d, 0x14, 0x17, 0xd7, 0xfa, 0xfd, 0x51, 0x26, 0xe2, 0x6d, 0xa0, 0x8e, + 0xd3, 0xdb, 0xe7, 0x9a, 0xcb, 0x3f, 0xf4, 0xbf, 0x6e, 0x11, 0xb7, 0x42, 0xb5, 0x94, 0xe1, 0x6b, + 0x90, 0xd6, 0x82, 0xe7, 0xa8, 0x46, 0x38, 0x06, 0xaf, 0xe5, 0xda, 0xf2, 0x1e, 0x19, 0x48, 0x4b, + 0xff, 0x26, 0xe7, 0x0a, 0xf6, 0x86, 0xd2, 0x8c, 0x1d, 0xa1, 0x23, 0x8a, 0x28, 0x04, 0x93, 0x0f, + 0x59, 0x86, 0xed, 0xfe, 0x69, 0xaa, 0xcb, 0x79, 0x43, 0x44, 0xec, 0xec, 0x1a, 0x17, 0x32, 0x74, + 0x9b, 0xe1, 0xa5, 0x83, 0x1a, 0xaf, 0xfa, 0x84, 0x5b, 0x6c, 0x8b, 0x81, 0x0c, 0x66, 0x1c, 0x7e, + 0x6a, 0x83, 0x6a, 0x27, 0xfd, 0x75, 0xbd, 0x6c, 0x67, 0xdb, 0x45, 0xe3, 0x7a, 0x33, 0xc1, 0x75, + 0x1d, 0xca, 0xe3, 0x36, 0x98, 0x10, 0x10, 0x7f, 0x46, 0xbb, 0x0a, 0x26, 0xe4, 0x3a, 0x41, 0x68, + 0xd2, 0x38, 0x34, 0x6e, 0x94, 0x93, 0xd7, 0x8f, 0x0b, 0x7c, 0x2c, 0xa0, 0x88, 0x25, 0xe5, 0xb4, + 0x15, 0x59, 0x4b, 0x89, 0x10, 0xc9, 0x0d, 0x23, 0x29, 0xc0, 0x14, 0x63, 0x04, 0xcd, 0xa4, 0x8c, + 0x3a, 0x30, 0xa6, 0x44, 0x7c, 0xb1, 0x9a, 0x9b, 0x9d, 0xd7, 0x84, 0x22, 0xc9, 0x2e, 0x6c, 0x00, + 0xce, 0xe3, 0xd2, 0xa6, 0x34, 0xee, 0x4a, 0xd7, 0x07, 0x26, 0xa9, 0x93, 0xda, 0x3e, 0x8a, 0x4b, + 0x17, 0x9f, 0x2e, 0xe1, 0xee, 0xaa, 0x09, 0x74, 0x7e, 0xb9, 0x04, 0x43, 0x4d, 0x48, 0xc6, 0x93, + 0x79, 0x5e, 0xb7, 0x52, 0x29, 0x57, 0x8f, 0x01, 0xa5, 0x4c, 0xe7, 0x8f, 0x32, 0x5b, 0x78, 0x31, + 0xc4, 0xce, 0x85, 0x1c, 0x61, 0x43, 0xab, 0x4c, 0xee, 0xb2, 0xda, 0x0d, 0x3c, 0xab, 0xff, 0x67, + 0x7e, 0xb6, 0x96, 0xfe, 0x98, 0xbc, 0x6c, 0xab, 0x4e, 0x03, 0x97, 0x2e, 0x49, 0xac, 0xc5, 0xc4, + 0x31, 0x26, 0xae, 0x32, 0xcd, 0x7a, 0xdd, 0x00, 0x17, 0x61, 0xe4, 0x2d, 0x80, 0xdb, 0xb8, 0xb5, + 0x6a, 0xe0, 0xe3, 0xf3, 0x7b, 0x1c, 0xe9, 0x49, 0xa0, 0xe6, 0xf6, 0x0a, 0xc2, 0x3a, 0x59, 0xc5, + 0x83, 0xc6, 0x9a, 0x84, 0xa4, 0xc8, 0x39, 0x75, 0xff, 0x32, 0x60, 0x5b, 0xc7, 0xee, 0x13, 0xbc, + 0x55, 0xfa, 0x76, 0x23, 0x1a, 0x0c, 0x13, 0x5c, 0xa5, 0x5a, 0xd3, 0x43, 0xd3, 0xca, 0xf8, 0x11, + 0xaa, 0x3b, 0xb2, 0xde, 0x04, 0x15, 0x57, 0xc4, 0x28, 0x91, 0x50, 0xc6, 0x5b, 0x89, 0xf8, 0x84, + 0xf7, 0x73, 0x26, 0x90, 0x6e, 0xf6, 0x0d, 0xa5, 0x99, 0x0b, 0xe2, 0xd7, 0xc5, 0x8c, 0x2c, 0x2e, + 0x23, 0xd8, 0x8a, 0xb8, 0x44, 0x60, 0xaa, 0x57, 0xd3, 0x4c, 0x99, 0x65, 0x13, 0xbe, 0xc0, 0xde, + 0x01, 0xbf, 0x82, 0xbf, 0x5a, 0xa4, 0x10, 0x63, 0x99, 0x67, 0x9d, 0x8c, 0x40, 0xde, 0x79, 0xa6, + 0x95, 0x86, 0x6c, 0x7a, 0x11, 0x19, 0xb2, 0x21, 0x24, 0xca, 0xba, 0x8d, 0x94, 0xfd, 0x6d, 0xdd, + 0x3a, 0xc9, 0x2e, 0xad, 0x5b, 0xe1, 0xec, 0xf2, 0xba, 0x2d, 0xf1, 0x41, 0x5b, 0x9e, 0xcd, 0x21, + 0x79, 0x33, 0x11, 0x97, 0x8f, 0xcd, 0xb0, 0x5b, 0x9b, 0xdb, 0x30, 0xc3, 0xec, 0x70, 0xf3, 0x76, + 0x28, 0x29, 0x41, 0x4f, 0xb5, 0xd8, 0x24, 0x7c, 0xd4, 0xac, 0x66, 0xcc, 0x9a, 0xef, 0x97, 0x01, + 0xaf, 0x35, 0x55, 0x55, 0x71, 0xd0, 0x1e, 0x07, 0x17, 0xa7, 0x2a, 0xe3, 0xac, 0xbd, 0x23, 0xa1, + 0x18, 0x4d, 0xda, 0xd1, 0x23, 0x6f, 0xbf, 0x73, 0x9e, 0xac, 0x9d, 0xdb, 0xcc, 0x26, 0xec, 0x60, + 0x28, 0x0e, 0x11, 0x98, 0xf8, 0x05, 0x59, 0x65, 0x4d, 0xed, 0xd5, 0xd2, 0xfe, 0xe0, 0xf5, 0x02, + 0xd6, 0x05, 0x45, 0x1c, 0x83, 0x74, 0xda, 0x3a, 0xc1, 0x55, 0xb2, 0xc3, 0x2a, 0x1e, 0x75, 0x85, + 0x32, 0xc9, 0x50, 0xdc, 0x9f, 0x66, 0x55, 0x46, 0xe2, 0xb4, 0xf9, 0x68, 0x9a, 0xd2, 0xdf, 0x15, + 0x6a, 0x58, 0x0d, 0x3c, 0xc6, 0xd1, 0x3e, 0xa3, 0xf1, 0xa5, 0x7e, 0x82, 0x6e, 0xc8, 0xbe, 0x8e, + 0xab, 0xbc, 0xe3, 0x74, 0x9f, 0x15, 0xd6, 0xf2, 0x47, 0xbc, 0x3f, 0xcc, 0xa1, 0x61, 0x02, 0x8c, + 0x7c, 0xaf, 0x53, 0x66, 0x2e, 0x38, 0x9b, 0x68, 0x38, 0xdb, 0xdd, 0xbd, 0x10, 0xd2, 0xaf, 0xe2, + 0xce, 0xd7, 0x89, 0x43, 0x06, 0x4a, 0xe4, 0x92, 0x48, 0x47, 0x36, 0x7c, 0xfd, 0xf8, 0xa9, 0xca, + 0xe8, 0x40, 0x0d, 0xff, 0x03, 0x51, 0xc5, 0xcf, 0x61, 0x59, 0xfc, 0x0f, 0x1f, 0x71, 0x37, 0x8f, + 0xdf, 0x51, 0x39, 0xed, 0xe6, 0x46, 0xb2, 0x1a, 0xc4, 0x55, 0x82, 0x0b, 0xcb, 0x83, 0x5f, 0xda, + 0x65, 0x5e, 0xda, 0x7e, 0xbe, 0xa6, 0xa1, 0xc2, 0x1b, 0x4a, 0x4b, 0xf2, 0x0e, 0xef, 0x79, 0x0e, + 0xcc, 0x75, 0x71, 0xf2, 0x6f, 0x4e, 0xc8, 0x59, 0x08, 0x7e, 0x46, 0x90, 0x04, 0xe3, 0xfc, 0xa6, + 0x1a, 0x43, 0x8f, 0x8f, 0x15, 0x4f, 0x02, 0x61, 0x58, 0x2a, 0x59, 0xcc, 0xf9, 0x3c, 0xa8, 0xc2, + 0x63, 0x33, 0x3f, 0x2e, 0xf3, 0x8f, 0xa2, 0xb9, 0x35, 0xd0, 0x77, 0x3d, 0x62, 0xb2, 0xae, 0x63, + 0x09, 0x95, 0xa7, 0x2b, 0x68, 0x69, 0x80, 0xbb, 0x1b, 0x6c, 0x81, 0xfd, 0x75, 0x3c, 0xae, 0xef, + 0x7c, 0x19, 0x6d, 0xb0, 0x4a, 0x6a, 0x85, 0x3a, 0x04, 0xf8, 0x62, 0xfd, 0x06, 0x8c, 0xef, 0x16, + 0x64, 0x25, 0x6d, 0xa5, 0x28, 0x52, 0x96, 0x57, 0x9e, 0x85, 0x83, 0xb0, 0x65, 0xa1, 0xb4, 0xed, + 0x1c, 0xe3, 0x96, 0xd2, 0xb7, 0xee, 0x50, 0x24, 0x69, 0xa4, 0xf1, 0x76, 0x64, 0x0b, 0x19, 0x17, + 0xef, 0xf1, 0xc0, 0x1c, 0x3b, 0x5a, 0x49, 0xab, 0x73, 0x03, 0x5e, 0xff, 0x4e, 0x2c, 0xf4, 0x74, + 0xc3, 0xec, 0x74, 0xad, 0x1a, 0xd6, 0x43, 0xb7, 0x9e, 0x81, 0x6e, 0xbd, 0x47, 0x1a, 0x85, 0xf0, + 0x69, 0x98, 0x6c, 0xd0, 0x21, 0x87, 0xa3, 0xdf, 0x92, 0xe7, 0x08, 0x92, 0x73, 0xf4, 0xa2, 0xc5, + 0xfb, 0x88, 0xbe, 0x26, 0x65, 0xd6, 0xac, 0x89, 0x5c, 0x4e, 0xd9, 0xa4, 0x53, 0xa5, 0x0f, 0x9b, + 0xf0, 0x44, 0x29, 0x3c, 0x09, 0x53, 0xf1, 0xcf, 0xd3, 0x9e, 0x5e, 0x25, 0x85, 0x2a, 0x61, 0xb5, + 0x3e, 0x8c, 0xbf, 0x5e, 0xb9, 0x30, 0xe3, 0x42, 0xe1, 0x7d, 0x1d, 0xbe, 0x0a, 0x7e, 0xcf, 0x72, + 0xa2, 0xda, 0xbe, 0xf5, 0xa0, 0x4f, 0x84, 0xb0, 0xce, 0x82, 0x80, 0x63, 0x66, 0xe8, 0xd9, 0xfc, + 0x65, 0x86, 0x2d, 0x11, 0x7a, 0x52, 0x62, 0xde, 0x72, 0x7d, 0x7d, 0x53, 0x97, 0x34, 0x31, 0xa8, + 0x78, 0xb9, 0x3e, 0x7a, 0x56, 0x18, 0x5e, 0x37, 0x73, 0xd0, 0xce, 0x10, 0xfe, 0x20, 0x52, 0x45, + 0x8f, 0x57, 0xa0, 0x20, 0x46, 0xef, 0x41, 0x35, 0xc9, 0x69, 0x50, 0xdb, 0x72, 0x55, 0xeb, 0x2b, + 0x17, 0x41, 0x52, 0x37, 0x1c, 0xd3, 0xfc, 0xb4, 0x1b, 0x17, 0xc0, 0x89, 0x37, 0x94, 0x96, 0x29, + 0x37, 0x24, 0xee, 0x19, 0x2a, 0xb0, 0x0c, 0xe5, 0x0f, 0x4a, 0xde, 0x76, 0x41, 0x29, 0x19, 0xc9, + 0x83, 0x7b, 0x3a, 0x4f, 0x3a, 0x0b, 0x94, 0xd6, 0x4f, 0x67, 0x31, 0x1e, 0xec, 0x5f, 0x5a, 0xda, + 0x2f, 0xbb, 0xd7, 0xc4, 0xbc, 0x88, 0xbf, 0x78, 0x50, 0xf8, 0xe2, 0x6c, 0x04, 0xf6, 0x67, 0x87, + 0x35, 0xfa, 0x67, 0x87, 0x6b, 0xf2, 0x50, 0xd6, 0x57, 0x91, 0x10, 0x4f, 0x76, 0x7d, 0x83, 0xa9, + 0x9f, 0x5b, 0xcb, 0xa6, 0x8a, 0x1d, 0xe1, 0x94, 0x84, 0xc6, 0xa6, 0x54, 0xd1, 0x8e, 0x0c, 0x46, + 0x3b, 0x92, 0x6a, 0x1a, 0x7f, 0xd0, 0xc6, 0x6a, 0xd4, 0xda, 0xb9, 0x27, 0x35, 0xbd, 0x2c, 0xa5, + 0x2d, 0x4c, 0xce, 0x64, 0x63, 0x65, 0x5a, 0xfc, 0x9c, 0x96, 0x48, 0x5b, 0x92, 0x76, 0xe2, 0x52, + 0xc6, 0x89, 0xd6, 0xe8, 0x2c, 0x5b, 0xd7, 0x91, 0x0a, 0x01, 0x2d, 0x98, 0xb4, 0xc2, 0x2b, 0xd7, + 0xab, 0x97, 0x91, 0xdb, 0x93, 0xc1, 0xeb, 0x57, 0xbc, 0x22, 0x6e, 0x4e, 0xe4, 0xad, 0x2d, 0xc9, + 0xed, 0x1d, 0xce, 0x94, 0x48, 0xab, 0x23, 0xfd, 0x8b, 0xa0, 0x4a, 0x90, 0xc0, 0x3b, 0x7b, 0x97, + 0xa4, 0xc2, 0x47, 0x61, 0xd2, 0xf3, 0x6c, 0xf3, 0x76, 0x24, 0x10, 0x0a, 0x43, 0x27, 0x8f, 0xb1, + 0x97, 0x84, 0x51, 0xdf, 0xec, 0x8e, 0x0b, 0x46, 0x89, 0xbc, 0x81, 0x59, 0xb6, 0x93, 0xf0, 0x5d, + 0x3e, 0x73, 0xdb, 0x5f, 0x60, 0x69, 0x0d, 0xe9, 0xb5, 0x60, 0x32, 0x56, 0x63, 0x17, 0xf3, 0xa9, + 0xc3, 0x0f, 0x42, 0x99, 0xb4, 0x4b, 0x6d, 0x4f, 0x79, 0x38, 0xed, 0x05, 0xc4, 0x85, 0x64, 0x09, + 0x4f, 0x2b, 0x15, 0x8a, 0x08, 0x9c, 0x4e, 0x99, 0x8c, 0xb4, 0x95, 0xb8, 0xf4, 0xc2, 0x0c, 0x25, + 0xd8, 0xd6, 0x09, 0x4c, 0x17, 0x41, 0xf0, 0xef, 0x3d, 0x0a, 0xef, 0x0b, 0x31, 0x44, 0x75, 0x57, + 0x38, 0x8d, 0xaa, 0x23, 0x4e, 0xb2, 0x42, 0xa0, 0xea, 0xa7, 0x49, 0x8a, 0x47, 0xbe, 0x80, 0x12, + 0x5a, 0x27, 0x12, 0x79, 0x5e, 0x99, 0xd4, 0xa7, 0xba, 0xfe, 0xb3, 0x56, 0xf0, 0xff, 0x3d, 0xef, + 0xf1, 0xc1, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, + 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xef, 0xbc, 0xf3, 0xce, 0x3b, + 0xef, 0xbc, 0xf3, 0xce, 0x3b, 0xff, 0x7f, 0xf2, 0xe3, 0xf7, 0xe0, 0x5e, 0x62, 0xad, 0xe2, 0x4d, + 0x91, 0x1f, 0x47, 0x26, 0x44, 0x9e, 0x43, 0x79, 0xe2, 0x5a, 0xce, 0xab, 0xe2, 0xa3, 0x78, 0x18, + 0x5e, 0xae, 0x06, 0x20, 0xd5, 0x06, 0x45, 0x8f, 0x81, 0x68, 0x35, 0xc3, 0x1f, 0x8a, 0x11, 0x08, + 0xdb, 0x0f, 0x54, 0x71, 0x20, 0x28, 0x7e, 0xe4, 0x61, 0x4a, 0x58, 0x80, 0xdf, 0xfb, 0xc5, 0x04, + 0x05, 0x53, 0x75, 0x39, 0x38, 0x0a, 0xbd, 0x76, 0x83, 0xc1, 0x8b, 0x7f, 0x57, 0xc7, 0xd0, 0xfa, + 0xee, 0x98, 0x4a, 0x01, 0x0e, 0x33, 0x99, 0x43, 0x29, 0x4c, 0x63, 0xf2, 0xf6, 0x31, 0xbd, 0xb2, + 0xe6, 0x49, 0x06, 0x24, 0x1a, 0x68, 0x3e, 0xc0, 0xa9, 0xf2, 0xd1, 0x80, 0x6c, 0x67, 0xb7, 0x43, + 0xcb, 0x48, 0xf7, 0x03, 0x01, 0x1e, 0x6f, 0xbd, 0xfe, 0x29, 0xbf, 0x1b, 0xba, 0x9e, 0xe9, 0xef, + 0xa3, 0x08, 0x75, 0xaf, 0xf1, 0xed, 0x51, 0x4e, 0x41, 0xe1, 0x6a, 0x38, 0x5c, 0x0a, 0xfd, 0x1c, + 0x5f, 0x48, 0xdf, 0x83, 0xfe, 0xde, 0x4b, 0x77, 0xfe, 0x72, 0xe2, 0x08, 0x88, 0x4c, 0xba, 0xf2, + 0x9d, 0xa6, 0x55, 0x33, 0x5e, 0x18, 0x9a, 0x5a, 0xf0, 0x36, 0xd5, 0xb6, 0xa4, 0xd3, 0x74, 0x61, + 0xf0, 0x45, 0x8d, 0x1c, 0x98, 0xec, 0x87, 0x39, 0x75, 0x27, 0x85, 0x16, 0x06, 0xda, 0xdd, 0xee, + 0x16, 0x30, 0x93, 0xc4, 0xa6, 0x3b, 0x0f, 0x2f, 0x5b, 0x24, 0x74, 0xc6, 0x33, 0x92, 0xc2, 0xb3, + 0x8d, 0xf8, 0xe0, 0xec, 0xcc, 0xfe, 0x97, 0x1a, 0xdb, 0xe9, 0x05, 0x53, 0x07, 0xf9, 0xf6, 0x5f, + 0x1a, 0xc8, 0x83, 0x25, 0x82, 0x05, 0xed, 0x76, 0x47, 0xba, 0x78, 0x1c, 0x6b, 0x27, 0x56, 0xfe, + 0xc4, 0xf5, 0x84, 0xc1, 0xdc, 0xf9, 0x95, 0xc8, 0x01, 0x23, 0x86, 0x82, 0x92, 0x4f, 0xfd, 0x1a, + 0x6f, 0x01, 0xea, 0xd1, 0x68, 0x7e, 0x77, 0x44, 0xe5, 0x98, 0x1b, 0xb2, 0x0b, 0x2a, 0x57, 0x7f, + 0x8f, 0x4d, 0xce, 0xcc, 0x3d, 0xb9, 0x4a, 0xa3, 0xd7, 0x7f, 0xda, 0xab, 0x1d, 0xc0, 0xca, 0xd1, + 0xf7, 0x54, 0xf2, 0x2f, 0x63, 0xf2, 0xf4, 0x6b, 0x4f, 0xd5, 0x6a, 0x6d, 0x79, 0xcd, 0x8d, 0x1d, + 0x49, 0xd8, 0xc8, 0x0a, 0xa6, 0xf6, 0xa7, 0x06, 0xad, 0x85, 0xa0, 0x8a, 0x3a, 0xe7, 0x2d, 0xc3, + 0x4b, 0xc3, 0xf5, 0x97, 0x41, 0x7a, 0xb1, 0xe9, 0x89, 0x17, 0x9a, 0x83, 0x1b, 0x7c, 0x6f, 0xb6, + 0x5b, 0x69, 0x1b, 0x66, 0x7c, 0x4c, 0xae, 0x9c, 0x19, 0x90, 0x4f, 0xdc, 0xc2, 0xe6, 0x5f, 0xd2, + 0xc0, 0xe7, 0x7b, 0x98, 0x55, 0x2d, 0x3d, 0xc3, 0xc5, 0xcc, 0xe8, 0xbe, 0xb5, 0x10, 0xdc, 0xff, + 0x46, 0xcc, 0xdf, 0x1d, 0xa8, 0x3b, 0x22, 0xa0, 0x71, 0x7d, 0xa1, 0x27, 0xa0, 0x17, 0x39, 0x95, + 0xd5, 0x74, 0xbd, 0xd0, 0xd8, 0x33, 0xc1, 0xa1, 0x66, 0x07, 0xb5, 0x0d, 0xc9, 0x12, 0xab, 0x6d, + 0xf3, 0xe9, 0xc5, 0x65, 0xff, 0xfe, 0xfa, 0x0e, 0x8c, 0x89, 0xae, 0xf8, 0x81, 0xd7, 0xe2, 0xa6, + 0x55, 0x90, 0xe2, 0x26, 0x81, 0xc1, 0x74, 0x79, 0x71, 0xa6, 0xa2, 0xd3, 0xe6, 0xcb, 0x2f, 0x2d, + 0x11, 0x4f, 0xda, 0x92, 0x2e, 0xb4, 0xca, 0xf2, 0xbf, 0xa9, 0x41, 0x09, 0xbd, 0xa1, 0x34, 0x0b, + 0xdd, 0xf6, 0xdb, 0x51, 0xcd, 0x67, 0xa7, 0xe3, 0x29, 0xa6, 0x74, 0x7a, 0x4e, 0x78, 0x1a, 0x6d, + 0x7d, 0x63, 0x29, 0x76, 0x1d, 0x9f, 0x51, 0x87, 0xe1, 0x74, 0x97, 0xa2, 0xde, 0x12, 0x3d, 0xa2, + 0x67, 0xbd, 0x7e, 0x2b, 0x16, 0xf1, 0xff, 0x7a, 0x47, 0x56, 0xdb, 0xcf, 0xf1, 0x90, 0x98, 0x38, + 0x69, 0xb2, 0x87, 0x20, 0xd1, 0x61, 0x97, 0xa5, 0x52, 0x11, 0xcf, 0x7b, 0xec, 0xf7, 0xef, 0x94, + 0xdd, 0xd2, 0x85, 0x80, 0x6b, 0x52, 0x29, 0x58, 0x00, 0x77, 0xa5, 0x18, 0xb4, 0xc0, 0x1b, 0xaf, + 0x0d, 0xce, 0x0f, 0x89, 0x4c, 0x11, 0xc1, 0x80, 0xda, 0x1f, 0x82, 0xd9, 0x53, 0xce, 0x83, 0xe1, + 0x14, 0x2c, 0x62, 0x4f, 0x33, 0x40, 0x41, 0x4b, 0x3d, 0xc8, 0x79, 0x3a, 0x46, 0x44, 0x6f, 0x9f, + 0x09, 0x49, 0x23, 0x41, 0xd9, 0x33, 0x12, 0x96, 0xd5, 0x08, 0xd3, 0x90, 0x0f, 0x85, 0xf0, 0xe7, + 0x56, 0xf7, 0x26, 0x97, 0xb0, 0x07, 0xe9, 0x85, 0x82, 0x36, 0xe8, 0x6a, 0xe4, 0xf8, 0x5f, 0x2f, + 0xe6, 0xc1, 0x28, 0x3e, 0x9f, 0xc3, 0x1d, 0xeb, 0x6e, 0xc9, 0xe2, 0xf6, 0xa0, 0x4f, 0x7a, 0x64, + 0xed, 0x3a, 0x86, 0x97, 0x41, 0xfe, 0x23, 0x3b, 0x6f, 0xbe, 0x7d, 0x9e, 0x04, 0x22, 0x3b, 0xfa, + 0xf9, 0x35, 0x8d, 0xfd, 0xe6, 0x4e, 0xb9, 0xee, 0xaa, 0x04, 0xea, 0x23, 0xe3, 0x56, 0x96, 0x7a, + 0xa1, 0x57, 0xcd, 0xf0, 0x3c, 0x8c, 0x2f, 0x4e, 0x46, 0x56, 0xbc, 0x19, 0x29, 0xe3, 0x5e, 0x09, + 0x60, 0x47, 0xa3, 0x09, 0x0e, 0x28, 0xbc, 0x13, 0xb1, 0x05, 0x76, 0x98, 0x01, 0x82, 0xa9, 0x58, + 0x51, 0xab, 0x3e, 0x96, 0x4b, 0xd9, 0xeb, 0x55, 0xb8, 0xc0, 0x86, 0xee, 0xf8, 0xe1, 0x95, 0xf4, + 0xd7, 0x5a, 0x20, 0xaf, 0xb3, 0x22, 0x32, 0xae, 0xf2, 0x0a, 0x57, 0x53, 0xf5, 0x2d, 0x3d, 0xa4, + 0xe0, 0x8d, 0x08, 0xcc, 0x00, 0xd4, 0xf4, 0x3d, 0x63, 0xe8, 0x14, 0x79, 0xcc, 0x7b, 0x70, 0xd2, + 0x1e, 0xcb, 0xea, 0xed, 0xcb, 0xf3, 0xe0, 0xe8, 0xe7, 0x7a, 0x7d, 0x44, 0xe0, 0x0d, 0xa5, 0xb9, + 0x65, 0xd4, 0x71, 0x83, 0x8a, 0xc7, 0x1d, 0xf5, 0x56, 0x79, 0x70, 0xec, 0x2a, 0x7c, 0xb7, 0xe8, + 0x5e, 0xa8, 0x9c, 0xaf, 0x57, 0xf5, 0x70, 0xb9, 0x85, 0x37, 0x9a, 0xc5, 0xe6, 0xd0, 0x13, 0xe4, + 0x0d, 0xf8, 0x77, 0x5c, 0xf6, 0x46, 0xf4, 0xa9, 0xbb, 0xc6, 0x43, 0x16, 0xc8, 0x67, 0x0f, 0x0f, + 0xeb, 0x9d, 0xea, 0xe7, 0x6f, 0x44, 0xbf, 0x3d, 0xfe, 0xd6, 0xab, 0x31, 0x2a, 0x5d, 0x41, 0xbf, + 0x18, 0xfa, 0xd6, 0x5b, 0x2b, 0x81, 0xe7, 0xdf, 0x87, 0xf1, 0x49, 0x4d, 0x32, 0xfd, 0xae, 0x33, + 0x32, 0x85, 0xac, 0x1d, 0xf8, 0x13, 0x77, 0xe9, 0x01, 0x1e, 0xad, 0x26, 0x0c, 0xf8, 0x1d, 0x7b, + 0x92, 0x77, 0x1e, 0xaf, 0xb0, 0xb8, 0xd6, 0xeb, 0x94, 0x5a, 0xaf, 0xa6, 0x71, 0x95, 0xee, 0x7d, + 0x4c, 0x84, 0x5a, 0xe5, 0x82, 0x1b, 0x95, 0x49, 0x2e, 0x49, 0x64, 0x95, 0x20, 0xb6, 0xdc, 0x7f, + 0x98, 0x20, 0x0a, 0xde, 0xd9, 0xd5, 0x73, 0x90, 0xf3, 0x50, 0x46, 0x96, 0x3e, 0x6e, 0x7f, 0x1b, + 0x14, 0x12, 0x35, 0x5f, 0x74, 0xc2, 0x7d, 0x98, 0xb9, 0x87, 0x97, 0xa8, 0x1e, 0xa7, 0x31, 0x1f, + 0xc6, 0xed, 0x9c, 0xf1, 0xe1, 0x6c, 0x2b, 0x24, 0x4d, 0xed, 0x0f, 0x99, 0x3b, 0x47, 0xfb, 0xe3, + 0xfa, 0xd0, 0x9e, 0xde, 0x60, 0x3c, 0xba, 0x5f, 0xc2, 0xcb, 0x67, 0x46, 0xde, 0xf1, 0xf2, 0xe8, + 0xde, 0x18, 0xd7, 0x56, 0xff, 0x84, 0x35, 0x09, 0xc9, 0xd9, 0xe0, 0xf4, 0x91, 0x31, 0x84, 0x0f, + 0x0d, 0x96, 0xaa, 0x64, 0x34, 0xa9, 0x0f, 0xf7, 0xfb, 0x34, 0x62, 0x34, 0x89, 0x5f, 0x2c, 0xde, + 0x1d, 0x8f, 0xe6, 0x28, 0x33, 0xfd, 0x6e, 0x31, 0x12, 0x24, 0xfe, 0x80, 0x0c, 0xac, 0x6f, 0x5d, + 0x64, 0xbe, 0xbc, 0x13, 0xcb, 0xed, 0x65, 0x6c, 0x5a, 0xc1, 0xce, 0x8e, 0x2a, 0xfe, 0x2c, 0xb0, + 0x37, 0xdd, 0x93, 0x17, 0x99, 0x5a, 0x9a, 0xd5, 0x0e, 0x0c, 0xf1, 0x0d, 0x73, 0x61, 0xb8, 0x5f, + 0xa3, 0x5b, 0x4c, 0xa3, 0x59, 0x31, 0xa4, 0x15, 0xe6, 0x73, 0x0f, 0x29, 0x53, 0x7a, 0xf9, 0xa1, + 0x87, 0xfc, 0xec, 0x3b, 0x8a, 0xbd, 0xa1, 0xf4, 0xca, 0x4e, 0xe4, 0xee, 0x24, 0xbf, 0xf0, 0x15, + 0xdf, 0x5b, 0xa0, 0xc8, 0x22, 0x01, 0x16, 0x45, 0xa2, 0x0b, 0xac, 0x50, 0x36, 0x74, 0x01, 0x09, + 0x45, 0xaa, 0x0b, 0xcc, 0x51, 0xc4, 0x5d, 0x58, 0xae, 0x74, 0x3c, 0x90, 0x01, 0x69, 0x2e, 0x32, + 0x93, 0x80, 0x9f, 0x61, 0x12, 0xf3, 0x37, 0xa8, 0x4c, 0xda, 0xfa, 0xd8, 0xd8, 0xb5, 0xe7, 0x64, + 0xaa, 0xb2, 0xf9, 0xa9, 0xaa, 0x77, 0xef, 0xe6, 0xd8, 0x56, 0xd7, 0x84, 0x9c, 0xda, 0x7d, 0xe8, + 0xab, 0x3f, 0x3a, 0xc5, 0x5f, 0x07, 0xdf, 0x01, 0xeb, 0x68, 0x63, 0x2f, 0x79, 0x7b, 0xb8, 0x47, + 0xbd, 0x70, 0x3d, 0x3f, 0x36, 0xf6, 0x89, 0x84, 0x7c, 0xd9, 0xc4, 0x63, 0xa8, 0xc3, 0x1c, 0x93, + 0xaf, 0x50, 0x02, 0xc1, 0x8b, 0x79, 0xc9, 0x06, 0x8f, 0x4c, 0x0a, 0x03, 0x47, 0xc1, 0xb5, 0x85, + 0xcf, 0xe1, 0x9b, 0xc4, 0xa2, 0x97, 0x38, 0x24, 0x7d, 0x84, 0x5d, 0x5f, 0x33, 0xdf, 0x43, 0x20, + 0x32, 0x2a, 0xaa, 0x6c, 0x2b, 0x8f, 0x54, 0x9b, 0xf9, 0x90, 0xac, 0x80, 0xf9, 0x87, 0x79, 0x4a, + 0x64, 0xf3, 0x1c, 0xd5, 0xe5, 0xec, 0xf6, 0x04, 0xdb, 0xed, 0x27, 0x63, 0x25, 0x41, 0x25, 0x88, + 0x7f, 0x2c, 0x7b, 0xbf, 0x60, 0xb2, 0x6a, 0xab, 0x6b, 0x02, 0x1b, 0x5d, 0x35, 0x42, 0x3d, 0x8e, + 0x9d, 0x5f, 0x2c, 0x36, 0xb6, 0x68, 0x21, 0x9d, 0xc7, 0x2d, 0x37, 0x42, 0x4e, 0x98, 0x68, 0x72, + 0xae, 0xac, 0x7e, 0xe6, 0xe5, 0x7a, 0x5c, 0x9d, 0x3b, 0x00, 0xfc, 0x87, 0x5d, 0x95, 0x05, 0x57, + 0x23, 0xb9, 0x96, 0x7f, 0x58, 0x83, 0xb8, 0x96, 0x38, 0x29, 0xc8, 0xe2, 0x63, 0x69, 0x0a, 0x2a, + 0x17, 0xa4, 0x01, 0x62, 0x7d, 0x26, 0x0c, 0xd5, 0xe4, 0xf3, 0xa9, 0x34, 0x6f, 0xf7, 0x2b, 0xaa, + 0x89, 0xde, 0x4f, 0xf6, 0x8a, 0x20, 0xf6, 0x6b, 0x5b, 0x93, 0x06, 0x03, 0x69, 0xb1, 0x49, 0xde, + 0x08, 0x82, 0x80, 0xb0, 0x1b, 0x52, 0x6b, 0xf9, 0x7e, 0x84, 0xf9, 0xb9, 0xfc, 0xcb, 0x25, 0x03, + 0x90, 0x30, 0x44, 0x34, 0xcf, 0x13, 0xf1, 0xb3, 0x9f, 0x5d, 0xf6, 0x0d, 0xa5, 0x3f, 0x1d, 0xa4, + 0x09, 0x6c, 0x8e, 0xe1, 0x12, 0x62, 0xd2, 0xc8, 0xfd, 0x83, 0x68, 0x55, 0x23, 0xb3, 0xd0, 0x0b, + 0xf9, 0xcb, 0x93, 0x54, 0x88, 0x2b, 0xde, 0x10, 0xb1, 0x8a, 0x5c, 0x1b, 0x9f, 0xd0, 0x25, 0x3b, + 0x27, 0x37, 0x96, 0x82, 0x30, 0xb1, 0x8c, 0xa5, 0x20, 0x35, 0xfd, 0x52, 0xc3, 0xa3, 0x93, 0xcf, + 0x00, 0xfe, 0x09, 0xb6, 0x08, 0xba, 0x7f, 0xe9, 0x6b, 0x80, 0xd2, 0x88, 0xb4, 0x04, 0xc6, 0x07, + 0xd9, 0x86, 0xe3, 0xe4, 0xf1, 0xc3, 0xa4, 0x0a, 0xe2, 0x66, 0x31, 0x8c, 0x93, 0xd8, 0x3c, 0x31, + 0x1e, 0xe7, 0x8c, 0xaa, 0x3d, 0x1a, 0x87, 0x15, 0x11, 0x8f, 0x56, 0x6b, 0xe7, 0x47, 0xb0, 0x99, + 0xe5, 0x1d, 0xdf, 0xad, 0xa2, 0xbb, 0xc4, 0x88, 0x55, 0x64, 0x6b, 0xa9, 0x7a, 0x8e, 0x50, 0xaf, + 0x1f, 0x9a, 0xe0, 0x87, 0xed, 0x70, 0xa2, 0xe0, 0x69, 0xd1, 0x26, 0xb2, 0x06, 0x4c, 0xfb, 0x28, + 0x26, 0x18, 0x86, 0x88, 0x45, 0x10, 0x40, 0x8d, 0x1b, 0x48, 0x22, 0x67, 0x41, 0xf1, 0xeb, 0xea, + 0x33, 0x3c, 0xf9, 0xf5, 0x44, 0x02, 0x22, 0x57, 0xf8, 0x8c, 0xe5, 0xdc, 0x5b, 0x91, 0x95, 0xc4, + 0xb1, 0x74, 0xb1, 0x01, 0xf7, 0x0b, 0xb1, 0x8c, 0xe7, 0xe5, 0x52, 0xa5, 0xb7, 0x26, 0xb2, 0x41, + 0xce, 0xed, 0x38, 0x90, 0x75, 0x1d, 0xdb, 0x3b, 0x62, 0x6b, 0x79, 0x4b, 0xa0, 0xe2, 0x86, 0xaf, + 0xc7, 0x2c, 0xae, 0x9e, 0x8f, 0x1e, 0xac, 0xbb, 0xd2, 0x98, 0x4a, 0xc8, 0x33, 0x3f, 0x2e, 0x7a, + 0x4e, 0x1c, 0xb1, 0x81, 0x65, 0xdb, 0xbf, 0x72, 0x59, 0xb1, 0xfb, 0x9e, 0xee, 0xb4, 0xc6, 0x46, + 0x37, 0xcd, 0x1a, 0x8e, 0x26, 0x62, 0xad, 0xf5, 0xa9, 0x0a, 0xb0, 0xdd, 0x2d, 0xf9, 0x33, 0x57, + 0x90, 0x09, 0x8a, 0xa4, 0x36, 0xc2, 0xcf, 0x16, 0xf3, 0x88, 0xba, 0xa6, 0xd0, 0x23, 0xdd, 0xa5, + 0x01, 0xb9, 0x26, 0xc0, 0xb4, 0x12, 0x72, 0x0e, 0x08, 0x76, 0x99, 0x7d, 0x9e, 0x2d, 0x89, 0xad, + 0xa9, 0x3a, 0xdb, 0xd5, 0x67, 0x66, 0x2a, 0xfa, 0xb3, 0xd2, 0xdd, 0xc2, 0x1b, 0x4a, 0x4b, 0x74, + 0x63, 0x22, 0x59, 0x37, 0xe6, 0xfe, 0xbd, 0x42, 0xb4, 0xa8, 0x69, 0xd7, 0xcb, 0x42, 0x7e, 0x52, + 0x3d, 0xd4, 0xe4, 0x5c, 0xb6, 0xe1, 0xfc, 0xa3, 0x15, 0xdf, 0x7c, 0x5e, 0x00, 0x5a, 0x87, 0x1b, + 0x6d, 0x95, 0xdc, 0xff, 0xa1, 0x38, 0xdd, 0xad, 0x2d, 0xb2, 0x06, 0xb2, 0x91, 0x54, 0x70, 0x2f, + 0xae, 0x2b, 0xee, 0xf1, 0x6f, 0x47, 0xc8, 0xb8, 0x71, 0xdb, 0x99, 0x63, 0x1f, 0xdc, 0x47, 0x73, + 0xcf, 0xdb, 0xe5, 0x23, 0x3c, 0x2d, 0x13, 0x5a, 0x56, 0xda, 0x42, 0x70, 0xd0, 0xaf, 0x8f, 0x61, + 0x5f, 0xa1, 0x5c, 0xdb, 0xd8, 0x2e, 0xca, 0x2e, 0xf4, 0x0b, 0xe6, 0x40, 0x35, 0xdd, 0x5c, 0x7d, + 0x29, 0xbd, 0xdc, 0x49, 0x77, 0x8e, 0x4e, 0xbd, 0x0a, 0xc6, 0xa5, 0xa6, 0x97, 0x69, 0xb1, 0x7b, + 0x12, 0x11, 0xb5, 0x85, 0x99, 0x07, 0xd5, 0xe4, 0x8b, 0x4a, 0x62, 0xc2, 0x4f, 0xbf, 0x85, 0x7f, + 0xd3, 0xed, 0xff, 0x65, 0x78, 0xcc, 0x55, 0x8f, 0x95, 0x5a, 0xe1, 0xfe, 0x61, 0x3d, 0xc8, 0x5b, + 0xbf, 0x1a, 0xd6, 0x77, 0xe3, 0xe4, 0xa5, 0x7a, 0xee, 0xac, 0x9e, 0x09, 0x4f, 0x2c, 0x9b, 0x68, + 0x3a, 0xa3, 0x3b, 0xbf, 0xab, 0x13, 0x6e, 0xef, 0x52, 0x16, 0x4a, 0x87, 0x3a, 0x8c, 0x23, 0xe9, + 0xa7, 0xcd, 0xd7, 0xb9, 0xfb, 0xdb, 0x28, 0x47, 0x58, 0xdc, 0x8a, 0xe6, 0xd4, 0xd6, 0x0a, 0x37, + 0xb4, 0x5b, 0xa9, 0x4f, 0xd5, 0x83, 0x68, 0x58, 0x5e, 0x00, 0x2d, 0xb0, 0xa6, 0x59, 0x83, 0x3e, + 0xa9, 0xbf, 0xc7, 0xa0, 0x40, 0x1c, 0x35, 0x87, 0x82, 0xc3, 0xa5, 0x9c, 0xc9, 0x9f, 0x66, 0x95, + 0x21, 0xe3, 0x6a, 0xac, 0xf0, 0xe0, 0x6b, 0x14, 0x04, 0xde, 0xbb, 0xb9, 0xc6, 0x1f, 0x98, 0xa7, + 0x0a, 0x79, 0x4e, 0x89, 0xb9, 0x66, 0x88, 0x7f, 0xac, 0x7e, 0x3e, 0x08, 0xae, 0x30, 0xb8, 0xd3, + 0x46, 0xed, 0x93, 0x26, 0x15, 0xbf, 0x4d, 0xe3, 0xf7, 0x72, 0x51, 0xf6, 0xbe, 0x9a, 0x76, 0x15, + 0xd4, 0xa1, 0x9b, 0xe4, 0x45, 0xb5, 0x7c, 0x74, 0x95, 0x51, 0xa0, 0xfb, 0x93, 0x9f, 0x94, 0x86, + 0x13, 0x7f, 0xab, 0x74, 0x15, 0x81, 0x00, 0x93, 0xfd, 0x75, 0xb2, 0x01, 0xff, 0xe7, 0x03, 0x04, + 0xcb, 0xf7, 0x7e, 0xfc, 0xb5, 0xc7, 0xe5, 0xf1, 0xff, 0xab, 0x01, 0x26, 0x91, 0x41, 0xfe, 0xeb, + 0xc3, 0xff, 0x3e, 0xf8, 0xc7, 0x03, 0x8b, 0x67, 0xc7, 0xd5, 0xaf, 0x7f, 0x75, 0x19, 0x02, 0x41, + 0xe5, 0xbf, 0x7b, 0xc8, 0xd5, 0x7f, 0xdb, 0xe3, 0xf5, 0xf4, 0x64, 0x48, 0xf8, 0xef, 0xa7, 0x22, + 0x01, 0x8f, 0x90, 0x8b, 0x24, 0x82, 0x7f, 0xbe, 0x10, 0x8c, 0xef, 0x71, 0x5e, 0xbb, 0xfc, 0xaf, + 0x1e, 0x22, 0x01, 0x64, 0xc7, 0x69, 0x42, 0xe8, 0xf5, 0x38, 0x80, 0x67, 0xef, 0xee, 0x09, 0x7e, + 0x34, 0x88, 0xfe, 0xd9, 0xe3, 0xc7, 0xa9, 0x80, 0xff, 0xd5, 0x03, 0xfa, 0x57, 0x0f, 0xe4, 0x6f, + 0xdf, 0x29, 0xf0, 0x7a, 0x16, 0x32, 0x97, 0x57, 0x99, 0xfc, 0xc7, 0xff, 0x04, 0xaf, 0x67, 0x11, + 0x09, 0x79, 0xff, 0x79, 0xdc, 0x3f, 0xb5, 0xfa, 0xf7, 0x53, 0xde, 0xeb, 0x6b, 0x70, 0xa0, 0xff, + 0xee, 0xf1, 0x7a, 0xf0, 0x8f, 0xd3, 0x8b, 0x7e, 0x24, 0x60, 0xf8, 0x7f, 0x58, 0xaf, 0x8f, 0x20, + 0xbf, 0x31, 0x5a, 0x3e, 0x4c, 0x04, 0xb6, 0xba, 0x24, 0xaf, 0x04, 0xeb, 0xcd, 0xdc, 0x7f, 0x47, + 0xdc, 0xc3, 0xff, 0x1d, 0x71, 0x7f, 0xb7, 0x9a, 0xca, 0xa1, 0xbe, 0xe9, 0x8f, 0x88, 0xfb, 0x2f, + 0x53, 0x25, 0x9c, 0xea, 0x0f, 0xf3, 0x5c, 0xe9, 0xa7, 0x35, 0xe6, 0xce, 0xeb, 0x38, 0x1d, 0x98, + 0x34, 0xc7, 0x00, 0xca, 0x7f, 0x19, 0xf8, 0xc1, 0xaa, 0x8a, 0x3f, 0x95, 0x08, 0xd6, 0xcf, 0xfd, + 0xb9, 0x94, 0x77, 0xb4, 0xb5, 0xf6, 0xd5, 0xed, 0x7a, 0x42, 0x79, 0x13, 0xd7, 0xa3, 0xc8, 0x6a, + 0xe9, 0x0d, 0x73, 0x65, 0x68, 0x58, 0xb8, 0xd7, 0x68, 0x65, 0x01, 0x13, 0xec, 0x9d, 0xeb, 0x53, + 0xbc, 0x9e, 0x0c, 0x46, 0xae, 0xb8, 0x5d, 0x35, 0x14, 0x84, 0xaa, 0xf5, 0xdf, 0xd6, 0x3d, 0xcd, + 0x78, 0xe9, 0xcf, 0x24, 0x22, 0xe0, 0x29, 0xbf, 0x1e, 0x2a, 0x8a, 0x10, 0xaf, 0x15, 0x2c, 0xed, + 0x7a, 0x69, 0xfe, 0x92, 0xe6, 0x81, 0xf6, 0x3f, 0x62, 0xef, 0xbd, 0x4b, 0x9b, 0x45, 0xef, 0x86, + 0xe1, 0x2e, 0x7f, 0x20, 0x74, 0xa4, 0x80, 0x81, 0xe3, 0xba, 0x2f, 0x16, 0xb8, 0x7f, 0xb9, 0xd1, + 0xde, 0x8f, 0x9c, 0x9a, 0xe9, 0x43, 0xb9, 0x52, 0x57, 0xa8, 0x90, 0xdf, 0x6f, 0xf4, 0x25, 0xe3, + 0x6d, 0xfc, 0x92, 0x7b, 0x72, 0x9e, 0xb7, 0xe8, 0xf7, 0x9f, 0x63, 0x11, 0x5b, 0x25, 0x4d, 0xa7, + 0x9e, 0x5e, 0x5d, 0x00, 0x45, 0x08, 0x4e, 0xac, 0xe9, 0x43, 0x36, 0xc5, 0x89, 0x48, 0x56, 0xfe, + 0xb5, 0x5e, 0xf0, 0x4a, 0x54, 0x5b, 0xb4, 0xd6, 0xc6, 0xaf, 0x13, 0xfd, 0x95, 0x3f, 0x01, 0x3c, + 0x3e, 0x4c, 0x9b, 0xd4, 0x52, 0x5b, 0x1b, 0x1b, 0x09, 0x6b, 0xfb, 0x69, 0x95, 0xe5, 0x8f, 0x63, + 0x4a, 0x3e, 0xdf, 0xd9, 0x10, 0x7e, 0xe0, 0x70, 0xf5, 0x50, 0x20, 0xfb, 0xc7, 0x16, 0x6d, 0x11, + 0x05, 0x79, 0x57, 0xcf, 0x25, 0x87, 0xd2, 0x37, 0x5b, 0x34, 0xc3, 0xee, 0xb8, 0x08, 0x33, 0x4d, + 0x7e, 0xae, 0x6d, 0x46, 0x7b, 0x43, 0x69, 0xf9, 0x73, 0xee, 0x01, 0xf6, 0x83, 0x17, 0x9b, 0x88, + 0x5f, 0xa7, 0x75, 0x7d, 0x9b, 0x0a, 0x2e, 0xa0, 0x1b, 0x8c, 0x56, 0x13, 0x1c, 0xd3, 0x05, 0x36, + 0x21, 0x7f, 0xa8, 0x4c, 0xbf, 0x36, 0x28, 0x0b, 0xff, 0x51, 0x67, 0x58, 0xa2, 0x67, 0x9c, 0x63, + 0x66, 0xd5, 0xca, 0xfa, 0xf9, 0xf5, 0x08, 0xdb, 0x51, 0x31, 0x46, 0xf1, 0x83, 0x6d, 0x84, 0x6d, + 0x76, 0xad, 0x3b, 0xef, 0x54, 0xed, 0x17, 0x7d, 0xeb, 0xf2, 0x02, 0x17, 0x3c, 0xa5, 0x64, 0xbd, + 0x5e, 0x7c, 0x0f, 0x95, 0xba, 0xe3, 0x2b, 0x25, 0x7d, 0x5a, 0x2d, 0x31, 0x09, 0x12, 0xfa, 0xc7, + 0xb3, 0x01, 0xb2, 0x19, 0xd4, 0x21, 0xca, 0x2c, 0x68, 0x52, 0xd1, 0x37, 0x43, 0x60, 0x3a, 0x34, + 0x86, 0x5c, 0x7c, 0x42, 0xb1, 0x06, 0xd9, 0xbb, 0x80, 0xce, 0xc1, 0x87, 0xd5, 0x6c, 0x9b, 0x3e, + 0x38, 0xc3, 0x1d, 0xf6, 0xc7, 0xec, 0x8f, 0x4b, 0xb2, 0x95, 0x5f, 0xef, 0xea, 0x57, 0xa8, 0xde, + 0xd9, 0x97, 0x1b, 0xa9, 0x2b, 0xd6, 0x83, 0xe6, 0xc5, 0xc2, 0x39, 0x9a, 0xc9, 0x11, 0xeb, 0x4e, + 0xa8, 0xba, 0x2b, 0x1f, 0x0a, 0xea, 0x5a, 0x46, 0x9a, 0x60, 0xfb, 0xfa, 0x3a, 0x34, 0xb0, 0x38, + 0x10, 0x94, 0xe5, 0x2a, 0xe1, 0x43, 0x86, 0xbb, 0x84, 0x8b, 0xbf, 0x1f, 0xa5, 0x42, 0x58, 0x09, + 0xbc, 0x42, 0xd6, 0x34, 0xeb, 0x95, 0x2e, 0x53, 0x01, 0x76, 0xe4, 0x09, 0x20, 0x02, 0x93, 0x29, + 0xb8, 0xd2, 0xfe, 0xb8, 0xcc, 0xe1, 0xdb, 0x27, 0xa3, 0x1c, 0xf6, 0xc5, 0x6d, 0x04, 0xcc, 0xd0, + 0xfc, 0x28, 0xcf, 0xe2, 0x3f, 0x93, 0xe7, 0x25, 0x38, 0x1a, 0x58, 0x03, 0x60, 0x12, 0x7b, 0x0d, + 0x75, 0x07, 0xc9, 0x9c, 0x18, 0xdf, 0x5f, 0x6c, 0xe9, 0xf1, 0x68, 0x80, 0x4b, 0xa4, 0x7c, 0x19, + 0x41, 0x2b, 0xd9, 0x43, 0x58, 0x6a, 0x2b, 0xc2, 0x46, 0x77, 0xdb, 0x08, 0x13, 0xb0, 0x78, 0x57, + 0x18, 0x32, 0x50, 0x12, 0x5f, 0xfb, 0x08, 0x22, 0x3f, 0x5b, 0xea, 0xd0, 0xda, 0x1b, 0x4a, 0x2b, + 0xf7, 0x6c, 0x06, 0x2f, 0x6d, 0xad, 0x55, 0xa9, 0x4e, 0xc2, 0x3c, 0x3b, 0xbc, 0x88, 0xf2, 0x1d, + 0x83, 0x47, 0x80, 0x57, 0x85, 0xd7, 0x4a, 0x12, 0xac, 0x17, 0x68, 0x59, 0x5d, 0xf0, 0x26, 0xa7, + 0x0d, 0x91, 0x00, 0x00, 0x3c, 0x3a, 0xfc, 0x80, 0x3f, 0xf0, 0x03, 0x74, 0xc6, 0x86, 0xf9, 0xbc, + 0xa1, 0xdd, 0x1d, 0x23, 0x6b, 0x2d, 0x0d, 0x41, 0xff, 0x00, 0x4a, 0xed, 0xd7, 0xc1, 0xaa, 0x3a, + 0x66, 0x0f, 0x70, 0x8b, 0x77, 0x04, 0x02, 0xe8, 0xb1, 0xee, 0xab, 0x0d, 0xeb, 0xfd, 0xe5, 0x19, + 0x1b, 0xdc, 0x12, 0xdc, 0x22, 0x00, 0xd3, 0x29, 0xf9, 0x96, 0xeb, 0x3a, 0xc0, 0xc1, 0x6c, 0x30, + 0xf0, 0xd4, 0xba, 0xaa, 0x05, 0x94, 0x02, 0x7e, 0x00, 0xa9, 0x3a, 0x11, 0xd2, 0x87, 0xa9, 0xdd, + 0x75, 0x94, 0x31, 0x08, 0xa1, 0x2f, 0x08, 0xe5, 0xd6, 0x47, 0x60, 0xbc, 0xf1, 0xed, 0x49, 0xba, + 0x38, 0xc4, 0x5a, 0x73, 0x61, 0x9b, 0x70, 0x39, 0x50, 0x3e, 0x73, 0xe2, 0x94, 0x36, 0xe0, 0x38, + 0x49, 0xa1, 0xc6, 0xf5, 0x49, 0x36, 0x2b, 0x74, 0x20, 0x1f, 0x52, 0x80, 0x3d, 0x8a, 0xe2, 0x7f, + 0xc2, 0x1f, 0x46, 0x0c, 0x4e, 0x0b, 0x66, 0x24, 0xe3, 0x3c, 0x3b, 0xca, 0xde, 0xb1, 0xc6, 0x15, + 0xa9, 0x7c, 0xb5, 0x4f, 0xe7, 0x88, 0x1d, 0xf5, 0x0f, 0x6c, 0x97, 0x95, 0xc0, 0x80, 0x12, 0x88, + 0x24, 0x68, 0xeb, 0xd8, 0x22, 0xba, 0xc6, 0x87, 0x7f, 0x49, 0x0e, 0xec, 0x71, 0xf8, 0x04, 0x17, + 0x3b, 0x26, 0x75, 0xe3, 0x7a, 0x8d, 0xce, 0xe4, 0x42, 0xb0, 0x9e, 0x24, 0x62, 0xf1, 0xed, 0x81, + 0xbd, 0x6d, 0xbf, 0x7e, 0x21, 0xa0, 0xdb, 0xed, 0xea, 0xa5, 0x42, 0x18, 0x9a, 0x93, 0xca, 0x82, + 0x52, 0x32, 0x55, 0x86, 0xff, 0x12, 0x30, 0x95, 0x9e, 0xf9, 0x05, 0x55, 0x7a, 0xdd, 0xbf, 0xc0, + 0xd3, 0x09, 0x31, 0x46, 0x9e, 0x6d, 0x4b, 0x9e, 0x68, 0x80, 0x6a, 0xac, 0xa8, 0xc4, 0xba, 0x64, + 0xf6, 0xeb, 0xdb, 0x68, 0x9f, 0xc4, 0xae, 0xf0, 0x9f, 0xa3, 0x71, 0xbb, 0xec, 0x37, 0x94, 0xd6, + 0x16, 0xcb, 0xa6, 0x0a, 0x6e, 0x0c, 0x5a, 0xa3, 0x3d, 0xa1, 0xf5, 0xfa, 0x45, 0x12, 0x37, 0x99, + 0xe9, 0x34, 0xae, 0x0b, 0x9e, 0xcb, 0xf2, 0x0a, 0xf1, 0xd3, 0xaa, 0xf2, 0xd8, 0xfb, 0x8f, 0x47, + 0x32, 0x2a, 0x54, 0xa5, 0x83, 0x57, 0x37, 0x70, 0x43, 0x2a, 0xd6, 0x20, 0x72, 0x1a, 0x54, 0x75, + 0x7f, 0x08, 0x72, 0x85, 0xc6, 0x2a, 0x18, 0x3f, 0x4d, 0xa7, 0x64, 0xba, 0x53, 0x84, 0x6b, 0xb8, + 0xfd, 0xf6, 0x17, 0x13, 0x80, 0x2a, 0x44, 0x41, 0xb1, 0x5e, 0x21, 0xa4, 0x40, 0xda, 0x2c, 0x99, + 0x2c, 0x27, 0x05, 0xf0, 0xe2, 0x44, 0x47, 0xa4, 0x0b, 0xc0, 0x0f, 0x87, 0x70, 0x36, 0xd0, 0x9e, + 0xa5, 0x95, 0x3f, 0xd2, 0x33, 0x00, 0x4e, 0x19, 0x4e, 0xe6, 0x98, 0x36, 0x09, 0xf2, 0xda, 0x8f, + 0x39, 0x94, 0x0d, 0x6e, 0x38, 0xeb, 0xc0, 0x8e, 0xc7, 0x97, 0x5d, 0xc3, 0x36, 0x03, 0xaf, 0x4f, + 0x77, 0xd3, 0xaf, 0x0d, 0x04, 0x19, 0x23, 0x03, 0xf6, 0x54, 0xad, 0xc9, 0xc6, 0x7e, 0x0f, 0x08, + 0xad, 0x76, 0x24, 0x20, 0x43, 0x5d, 0x15, 0xd4, 0xe0, 0x72, 0x74, 0x29, 0xb9, 0xa0, 0xd5, 0xd7, + 0xe7, 0x80, 0xc8, 0xeb, 0xbe, 0x66, 0xd7, 0x11, 0x60, 0x94, 0x0e, 0xf8, 0x68, 0x01, 0xe8, 0xf0, + 0xbb, 0x24, 0x36, 0x8b, 0x1f, 0x25, 0x58, 0x00, 0x3f, 0xda, 0x67, 0xdd, 0x13, 0x18, 0x8a, 0x03, + 0xf0, 0x2f, 0x2d, 0x10, 0xd3, 0xff, 0x12, 0x90, 0x55, 0x88, 0x2e, 0x15, 0x14, 0x46, 0xbb, 0x7d, + 0xd3, 0x7e, 0x14, 0x61, 0xd2, 0x95, 0xf7, 0x87, 0x4c, 0x55, 0x19, 0x91, 0xdf, 0xe5, 0x4b, 0xa5, + 0xc0, 0x63, 0x90, 0xad, 0x1d, 0x3e, 0x46, 0xd8, 0xe1, 0x6b, 0x04, 0xd8, 0x2e, 0x77, 0xd9, 0xdf, + 0xb5, 0xeb, 0x89, 0xad, 0xc2, 0x6c, 0xc7, 0x97, 0x3c, 0xc0, 0xa3, 0x27, 0x39, 0xec, 0x61, 0x52, + 0x6f, 0x2b, 0x89, 0x63, 0x4f, 0xbe, 0xa6, 0x85, 0x37, 0x24, 0x07, 0x83, 0x2f, 0xe9, 0x7a, 0x41, + 0x92, 0x36, 0x2a, 0x42, 0x13, 0xf8, 0xe7, 0xc8, 0x45, 0x98, 0xf1, 0x86, 0xd2, 0xf4, 0x8f, 0x7c, + 0x6b, 0x17, 0x59, 0x82, 0x65, 0xf8, 0x89, 0xc8, 0x3b, 0xee, 0xdf, 0x4c, 0x64, 0xb2, 0x1e, 0x32, + 0xc9, 0xb5, 0xbd, 0x4b, 0x1a, 0x8b, 0x27, 0xb8, 0x25, 0x06, 0x3c, 0x38, 0x32, 0x76, 0xf3, 0x03, + 0x69, 0x20, 0x1f, 0x5e, 0xfa, 0xd0, 0xfa, 0xf3, 0xe9, 0x50, 0x34, 0x30, 0x80, 0x09, 0x03, 0xa0, + 0xf3, 0xff, 0x3a, 0xee, 0xe7, 0x7b, 0x52, 0x39, 0x4d, 0xe8, 0xfe, 0x05, 0x15, 0x34, 0x76, 0x9b, + 0xd2, 0xcb, 0xb4, 0x1e, 0x8b, 0x2b, 0x5a, 0x37, 0x2f, 0x4a, 0x6d, 0xeb, 0x66, 0xa4, 0xd4, 0xb4, + 0x7a, 0xa4, 0x82, 0xc0, 0x76, 0xe2, 0x67, 0x87, 0xa4, 0xb6, 0xc5, 0x13, 0x4d, 0xe9, 0x81, 0x29, + 0x6a, 0x44, 0x22, 0xb8, 0x7f, 0x0d, 0xe8, 0xde, 0xb6, 0xc8, 0x47, 0x26, 0x7c, 0x6e, 0xcd, 0x79, + 0xda, 0x4f, 0x88, 0xef, 0xbb, 0xd7, 0xa8, 0xa9, 0xd5, 0xc3, 0xe6, 0x54, 0x3a, 0x7d, 0xa0, 0x67, + 0x3c, 0xda, 0xba, 0xae, 0x05, 0x4a, 0xf2, 0xb4, 0x4a, 0xb6, 0xd3, 0x6d, 0x62, 0x14, 0x81, 0xf4, + 0x10, 0x6b, 0x98, 0xfc, 0x96, 0xb6, 0x11, 0x88, 0x24, 0x5a, 0x60, 0xd5, 0xbb, 0xa7, 0xbf, 0x6c, + 0x5d, 0xbd, 0x28, 0xca, 0xad, 0xd6, 0x72, 0x6c, 0xd0, 0xaa, 0xe2, 0x39, 0x51, 0x35, 0x3a, 0x91, + 0x24, 0x8e, 0xf5, 0x73, 0x84, 0x29, 0x3f, 0xa3, 0xe7, 0xd1, 0x56, 0x29, 0x91, 0x91, 0x00, 0x37, + 0x7e, 0xaa, 0x51, 0x87, 0x07, 0xf0, 0x92, 0x5b, 0x3e, 0x1f, 0xc8, 0x95, 0xbe, 0x78, 0x15, 0x79, + 0xab, 0x6d, 0xc5, 0xa8, 0x95, 0xbc, 0x9a, 0x10, 0xc2, 0x5d, 0x62, 0x89, 0x2d, 0xd0, 0x0d, 0x1e, + 0xe7, 0xc4, 0xac, 0x2b, 0xdf, 0x25, 0x7d, 0xa8, 0x1d, 0x6a, 0x0e, 0x54, 0xdd, 0x8b, 0x15, 0x6a, + 0xab, 0x37, 0x68, 0x9b, 0x8d, 0x38, 0xb9, 0x3f, 0x30, 0xf4, 0xf6, 0xb2, 0x74, 0x87, 0x7d, 0x9a, + 0x58, 0x10, 0x9b, 0x29, 0x71, 0xa3, 0xdd, 0xe5, 0xac, 0x5a, 0xda, 0xdb, 0x4e, 0x66, 0x8e, 0x73, + 0x76, 0xb8, 0xf8, 0xfa, 0x29, 0x61, 0x28, 0x9b, 0xfb, 0x9b, 0x1a, 0x94, 0x30, 0xf3, 0x0d, 0xa5, + 0xf5, 0xdc, 0x4b, 0x71, 0x2f, 0xa0, 0x81, 0xe2, 0xcd, 0xa7, 0x12, 0x70, 0x4f, 0x7c, 0xb2, 0xe4, + 0x22, 0x77, 0x74, 0x6e, 0x15, 0xa2, 0xd7, 0xd7, 0xc6, 0xb2, 0xa3, 0x6e, 0x52, 0x9c, 0x6a, 0x19, + 0xd0, 0xdc, 0x09, 0x3a, 0x16, 0x97, 0x1d, 0xe8, 0xb8, 0x5f, 0xdd, 0xfc, 0x9a, 0x66, 0x55, 0x4d, + 0x0d, 0x3f, 0x56, 0x3c, 0xae, 0xb4, 0xf6, 0xc4, 0x35, 0x84, 0x6b, 0x86, 0x36, 0x5b, 0x6b, 0xe9, + 0x92, 0xd5, 0x37, 0xcd, 0x60, 0xbc, 0x41, 0x15, 0x67, 0x09, 0xe7, 0xd2, 0xd2, 0xf3, 0x72, 0x63, + 0x80, 0x57, 0x25, 0x95, 0x69, 0x0a, 0xd3, 0x93, 0x66, 0x16, 0xa3, 0xfb, 0xf6, 0xe2, 0xff, 0xb0, + 0xf7, 0x76, 0x3f, 0x89, 0x64, 0x5d, 0xdf, 0xf0, 0xf3, 0x7f, 0xbc, 0xa7, 0x97, 0xd3, 0x01, 0x2f, + 0xdb, 0x64, 0xee, 0xc7, 0x9e, 0xd0, 0x1d, 0xbb, 0x8f, 0xc1, 0x51, 0x12, 0xa0, 0x20, 0x40, 0xa3, + 0x27, 0x83, 0x44, 0x10, 0x4c, 0xb0, 0xc1, 0x20, 0x8d, 0xfd, 0x3f, 0x28, 0x68, 0x5a, 0x45, 0x4f, + 0x2c, 0x09, 0x14, 0x05, 0x09, 0x74, 0x15, 0x51, 0xba, 0xe4, 0x58, 0xbc, 0xd4, 0x44, 0xad, 0x22, + 0x50, 0x0d, 0x9c, 0x0c, 0x12, 0xa1, 0x91, 0x44, 0x1b, 0x88, 0xa2, 0xce, 0xbb, 0x77, 0x81, 0xdf, + 0xd2, 0x33, 0xf7, 0xd5, 0xf7, 0x3d, 0xcf, 0xfb, 0xdc, 0x2f, 0xeb, 0xa0, 0x42, 0x7d, 0xec, 0xaa, + 0x5d, 0xab, 0xd6, 0xc7, 0x6f, 0x6d, 0xf6, 0xda, 0xcb, 0x57, 0xd3, 0xbb, 0xb5, 0xc2, 0x9d, 0x8b, + 0x9c, 0x29, 0xb5, 0xb8, 0x34, 0xf7, 0xc2, 0x36, 0x79, 0x8c, 0x0a, 0x5e, 0x48, 0xf7, 0x72, 0x6a, + 0x4d, 0x9a, 0x60, 0x72, 0x3f, 0x17, 0x30, 0xb7, 0x50, 0x65, 0x5a, 0xf7, 0xd5, 0x12, 0x4c, 0xe6, + 0x88, 0x27, 0x1a, 0x4f, 0x8c, 0x89, 0x8e, 0xc7, 0x7e, 0xf3, 0x9f, 0x51, 0x13, 0x73, 0x9d, 0xf9, + 0x01, 0x84, 0xd0, 0xbe, 0x11, 0x4b, 0x09, 0xda, 0x67, 0x32, 0x13, 0x1d, 0x5d, 0xbf, 0x98, 0xbe, + 0xcc, 0x6e, 0x6c, 0xf8, 0x9c, 0x51, 0xde, 0xcf, 0x71, 0xd5, 0x39, 0xbd, 0x37, 0x30, 0x47, 0x9e, + 0xf5, 0x3a, 0x4e, 0xbc, 0x3d, 0xfd, 0xc8, 0xd2, 0xdc, 0xb0, 0x63, 0x8c, 0xfc, 0x7d, 0xb5, 0x3c, + 0xb0, 0x94, 0x47, 0xa8, 0x10, 0x41, 0x77, 0x8c, 0x17, 0x42, 0x65, 0xfb, 0xc0, 0x18, 0x41, 0xab, + 0x9f, 0x9b, 0x74, 0xcf, 0x73, 0xa1, 0x19, 0xfa, 0x83, 0x5d, 0xfa, 0x6b, 0xe5, 0x45, 0xc1, 0x88, + 0x20, 0x0e, 0xb1, 0xfe, 0x60, 0xa1, 0x34, 0x39, 0xb6, 0x55, 0x63, 0xf9, 0x35, 0xb1, 0xd1, 0xeb, + 0x13, 0x0d, 0x0e, 0x61, 0x46, 0x39, 0xa3, 0x5b, 0xa9, 0x6e, 0x23, 0x44, 0xa9, 0xbf, 0x5b, 0x8e, + 0xd3, 0x6b, 0xc5, 0x88, 0xcb, 0x28, 0x1c, 0x58, 0xac, 0xfd, 0xb3, 0x9a, 0x3a, 0x0e, 0xe4, 0x07, + 0xd6, 0x43, 0x1e, 0x83, 0xd6, 0x94, 0x98, 0x66, 0x79, 0xa2, 0xf5, 0x60, 0xcf, 0xe3, 0x35, 0x57, + 0x94, 0x2d, 0x38, 0x6d, 0x37, 0x33, 0xa1, 0xa3, 0xa3, 0x01, 0xb9, 0x25, 0x12, 0xc5, 0x91, 0x50, + 0xf9, 0x55, 0xea, 0xdd, 0x71, 0xb5, 0x2a, 0x1d, 0x48, 0x13, 0x79, 0xea, 0xd7, 0x20, 0xa2, 0x17, + 0xea, 0xf7, 0xaa, 0x78, 0xf5, 0xc3, 0xa4, 0x8b, 0x54, 0xce, 0x79, 0x60, 0x61, 0x7a, 0xcd, 0x9b, + 0x09, 0x09, 0x79, 0xda, 0x3d, 0x82, 0xff, 0x6b, 0x6e, 0x79, 0xc4, 0x1b, 0xfe, 0x7c, 0x34, 0x91, + 0x0a, 0xcf, 0xf5, 0x94, 0x53, 0xdb, 0xee, 0xee, 0x61, 0x49, 0x75, 0xd9, 0xf5, 0x32, 0x52, 0x8d, + 0xbe, 0x3f, 0x1c, 0x23, 0x2f, 0x83, 0x6a, 0x29, 0x3d, 0x7c, 0x45, 0x79, 0xc7, 0x4f, 0xdf, 0x1f, + 0x9b, 0xd8, 0xf9, 0x85, 0xee, 0xf5, 0x4a, 0xe1, 0x0f, 0x65, 0xb2, 0xea, 0x40, 0xad, 0x57, 0xac, + 0x9d, 0x4b, 0x1a, 0xff, 0x45, 0xd0, 0xc8, 0x66, 0x8c, 0xeb, 0x93, 0x1e, 0x13, 0x71, 0x89, 0xc2, + 0xa4, 0x71, 0x2d, 0x1e, 0x35, 0x0c, 0xaf, 0x93, 0x21, 0xa2, 0x50, 0x8a, 0xc0, 0xa4, 0xf1, 0x1d, + 0x45, 0x9f, 0x63, 0xb5, 0x84, 0x6f, 0x53, 0x59, 0x83, 0xd1, 0x60, 0xe8, 0x36, 0xf4, 0x3b, 0xe6, + 0x8b, 0xbd, 0xa4, 0xc8, 0x11, 0x9b, 0x54, 0x7c, 0xc5, 0x7e, 0x49, 0x6b, 0x9c, 0xa5, 0x8f, 0x83, + 0x9b, 0xb3, 0xce, 0xb4, 0xa5, 0x54, 0x1e, 0x73, 0x8f, 0x59, 0x67, 0x23, 0xd1, 0x78, 0xd8, 0x71, + 0x92, 0xf8, 0x25, 0x79, 0x40, 0x78, 0x55, 0xe5, 0x42, 0xe6, 0x2a, 0xfb, 0x8a, 0x4d, 0x65, 0xb6, + 0x4b, 0x91, 0xe1, 0x6a, 0x30, 0x3c, 0x75, 0xa9, 0x8c, 0xd9, 0xbf, 0x66, 0x3f, 0x55, 0xc7, 0xd8, + 0x42, 0x9a, 0xf0, 0x66, 0xdf, 0x7f, 0x39, 0x7a, 0x51, 0x3d, 0x8d, 0xf2, 0x5e, 0x8c, 0xff, 0x16, + 0x7c, 0xd1, 0x37, 0xa5, 0xd0, 0x3d, 0x63, 0x27, 0x96, 0x7f, 0xf2, 0x85, 0xdf, 0x5d, 0x2e, 0xe4, + 0x3b, 0xa7, 0x2f, 0xd2, 0x4a, 0xef, 0x22, 0xb5, 0x96, 0x2e, 0xb1, 0xea, 0xd9, 0x3c, 0x4b, 0xb2, + 0xac, 0x3d, 0xe1, 0x5a, 0x5f, 0x8b, 0x6d, 0xa7, 0x2c, 0x9e, 0xb1, 0xb4, 0xd8, 0xb8, 0x6c, 0xa1, + 0x96, 0xca, 0x4f, 0xac, 0x23, 0xa4, 0x69, 0xc1, 0x69, 0x64, 0x3d, 0xb4, 0x5c, 0x5c, 0xbd, 0x62, + 0x0d, 0xc6, 0xb5, 0x5e, 0x43, 0x7e, 0xe2, 0xf9, 0x80, 0x21, 0x12, 0x7c, 0x93, 0x98, 0x20, 0x99, + 0xb5, 0xab, 0xcf, 0x89, 0x23, 0x75, 0x70, 0xe6, 0xf7, 0x59, 0xaa, 0x77, 0x6a, 0xe1, 0xb7, 0x4a, + 0xc9, 0x48, 0xbd, 0xaf, 0x99, 0xfd, 0x7b, 0xae, 0x9c, 0x66, 0x7a, 0x7a, 0x35, 0x6a, 0x4d, 0x58, + 0x0e, 0xd9, 0xb1, 0x0a, 0xfb, 0x6c, 0x44, 0x5a, 0x5b, 0x9c, 0x8d, 0xf6, 0x17, 0xc9, 0x6c, 0xd7, + 0xa6, 0x79, 0xe5, 0x88, 0x1f, 0x0a, 0x5c, 0x92, 0xf4, 0x48, 0xf1, 0xed, 0x97, 0x6d, 0x92, 0x35, + 0xfc, 0xf2, 0x46, 0x8e, 0xe3, 0x1d, 0x5e, 0xf2, 0x8b, 0xbb, 0x0b, 0x25, 0x8f, 0xa3, 0xef, 0x19, + 0x91, 0x3b, 0x5b, 0x8c, 0x6b, 0x66, 0x2f, 0xce, 0xd7, 0x12, 0x06, 0x62, 0x21, 0x1f, 0x72, 0xa6, + 0x2e, 0xb2, 0x5d, 0xff, 0xba, 0xf8, 0x94, 0x40, 0x96, 0xb5, 0xaf, 0x5e, 0xa9, 0x8c, 0xec, 0x97, + 0x8d, 0x63, 0x66, 0xd2, 0x2b, 0xa8, 0x5a, 0xe7, 0x57, 0x32, 0xa6, 0x7e, 0xb5, 0x71, 0xd3, 0x2e, + 0x31, 0xaf, 0x25, 0x05, 0xef, 0xce, 0xe9, 0x0d, 0xeb, 0xe2, 0x82, 0xa1, 0xf3, 0xd5, 0x74, 0xd9, + 0xa3, 0x39, 0x0d, 0x59, 0x1c, 0xaf, 0x27, 0xdd, 0xa3, 0xc5, 0x54, 0x66, 0x4c, 0xed, 0xd0, 0x67, + 0xc6, 0xd7, 0x57, 0x51, 0x72, 0xc0, 0xf3, 0xcc, 0xe4, 0x30, 0xfa, 0x2e, 0x4a, 0x3d, 0x33, 0x11, + 0x26, 0xb9, 0xee, 0x4a, 0x33, 0x47, 0xe3, 0xfa, 0x05, 0x03, 0xaf, 0x7f, 0x8b, 0x24, 0x63, 0x56, + 0xb9, 0x61, 0x98, 0x62, 0x43, 0xe9, 0x23, 0x4d, 0x70, 0x4e, 0x72, 0xb6, 0x6d, 0x30, 0xae, 0x7c, + 0x29, 0x4b, 0x8c, 0x4e, 0x4c, 0x20, 0x35, 0xae, 0xbb, 0xfa, 0x4f, 0xc6, 0x42, 0xae, 0x81, 0x01, + 0x64, 0xfd, 0xf7, 0x55, 0x87, 0xc8, 0xf3, 0xac, 0x43, 0x5c, 0x0c, 0xbf, 0x45, 0xa5, 0x83, 0x07, + 0x39, 0xfe, 0xfe, 0xd6, 0x62, 0x4d, 0xa1, 0x47, 0xd6, 0xeb, 0x6f, 0x26, 0xe2, 0x48, 0x53, 0x30, + 0x78, 0x32, 0xda, 0xa1, 0xb1, 0xe2, 0xaa, 0x0a, 0xfa, 0x7c, 0x7f, 0xf8, 0x31, 0xca, 0xab, 0x74, + 0xb4, 0xe0, 0x34, 0xb6, 0xa5, 0x96, 0xfe, 0x54, 0x35, 0x99, 0xf5, 0x68, 0x9f, 0x62, 0x0a, 0xc9, + 0xac, 0xf5, 0xaa, 0xd7, 0x8f, 0xd2, 0x6b, 0xd3, 0xa6, 0x3f, 0x7a, 0xc3, 0x2a, 0x73, 0x6e, 0x37, + 0x50, 0x98, 0xff, 0xb4, 0xa6, 0x14, 0x23, 0x6b, 0x02, 0x73, 0x31, 0xf8, 0xbe, 0x70, 0xa9, 0xfe, + 0xad, 0x24, 0x14, 0x0d, 0xb8, 0x92, 0xaf, 0x1c, 0xa1, 0xa5, 0x8b, 0x4c, 0x68, 0xd9, 0x8c, 0xf6, + 0x98, 0xe7, 0x2d, 0xc9, 0x57, 0xe9, 0xd9, 0xf7, 0x3e, 0x0a, 0x44, 0xe9, 0x2f, 0xea, 0xaf, 0xe7, + 0x0c, 0xb1, 0xae, 0x11, 0xf9, 0x6f, 0x45, 0xad, 0xc8, 0xb9, 0xea, 0xc7, 0x54, 0xe6, 0x34, 0x53, + 0x47, 0xa4, 0xeb, 0x47, 0xba, 0xdd, 0xf9, 0x59, 0xff, 0xf6, 0xd8, 0x01, 0x83, 0x1f, 0xda, 0x4d, + 0x64, 0x4c, 0xa0, 0x64, 0xd4, 0x1d, 0x02, 0x15, 0x10, 0x26, 0xe1, 0x88, 0x09, 0x41, 0x85, 0x9b, + 0x73, 0xba, 0x5c, 0xc7, 0xc8, 0xdb, 0x99, 0x7f, 0xe0, 0x29, 0xb3, 0x0e, 0xf9, 0xa9, 0x6f, 0x60, + 0x3a, 0xdb, 0x07, 0x47, 0x22, 0x59, 0x79, 0xd8, 0x9d, 0x47, 0x25, 0x4b, 0x33, 0xea, 0x5e, 0x9b, + 0x62, 0x22, 0x81, 0xed, 0x6a, 0xbe, 0x46, 0xd8, 0x9f, 0x7f, 0x9d, 0xe9, 0xea, 0xf4, 0x25, 0x4c, + 0x41, 0x01, 0x1e, 0xd3, 0x94, 0xdf, 0x08, 0x06, 0x22, 0x9d, 0x6f, 0x04, 0x31, 0x4d, 0xf6, 0xb5, + 0xe5, 0xba, 0xce, 0x70, 0xae, 0x5c, 0x0c, 0x7c, 0x4c, 0x74, 0x46, 0x64, 0xae, 0xa1, 0x40, 0x75, + 0x71, 0xcd, 0xdb, 0xab, 0x58, 0x2f, 0x6a, 0x85, 0x45, 0xe7, 0x17, 0x14, 0x01, 0x90, 0x7e, 0x64, + 0x5b, 0xb5, 0x82, 0x8e, 0xe8, 0xcd, 0x0c, 0x31, 0xac, 0xc4, 0xdf, 0x2e, 0xa5, 0x7f, 0x4e, 0xcf, + 0x0c, 0xd2, 0x49, 0xd7, 0x28, 0xdd, 0xf7, 0xc2, 0xfd, 0xf9, 0xf0, 0x6c, 0xed, 0x1b, 0x1e, 0x48, + 0x0a, 0x43, 0x6f, 0xbf, 0xd4, 0xf7, 0x7f, 0x4d, 0xcf, 0x79, 0xf6, 0x55, 0x6e, 0x9c, 0x1f, 0x57, + 0xd3, 0x1a, 0x65, 0x9f, 0x79, 0x7c, 0x48, 0x1c, 0xdc, 0xff, 0x1c, 0x14, 0xda, 0x13, 0x7e, 0x34, + 0x3a, 0x10, 0x19, 0x26, 0x1e, 0xaf, 0x23, 0xa4, 0x6d, 0xc1, 0x69, 0xdc, 0x5c, 0x88, 0x26, 0x3b, + 0xb6, 0xcc, 0x07, 0xb9, 0xa3, 0x81, 0x9d, 0x83, 0x35, 0x7e, 0x5f, 0x9f, 0x9c, 0xe6, 0x7b, 0x65, + 0x8b, 0x5e, 0xeb, 0x9e, 0x46, 0x56, 0xd4, 0x8a, 0xa7, 0x7f, 0x47, 0x7d, 0x03, 0x03, 0x8e, 0x7f, + 0x6c, 0x9a, 0x54, 0x28, 0xc1, 0x8f, 0xee, 0x9c, 0x76, 0xbc, 0xd4, 0xf7, 0x3b, 0xb1, 0x23, 0x7e, + 0xbc, 0x8c, 0x75, 0x64, 0x24, 0x6e, 0xe2, 0x27, 0x51, 0x42, 0xea, 0xee, 0x16, 0xce, 0xf8, 0xf0, + 0x9e, 0xbd, 0x90, 0x33, 0x91, 0x03, 0x51, 0xcf, 0x91, 0x71, 0x60, 0x40, 0xe2, 0xe9, 0x7f, 0x1e, + 0x5c, 0xa4, 0x49, 0xd5, 0xb8, 0xeb, 0x99, 0x5e, 0x38, 0x9e, 0x46, 0xd7, 0x26, 0x65, 0xf3, 0x34, + 0x36, 0xb0, 0x98, 0x75, 0x3d, 0x7b, 0xe1, 0xf4, 0x2c, 0x62, 0x03, 0xea, 0x95, 0x5c, 0x9f, 0x30, + 0xb4, 0xea, 0x12, 0x8c, 0x2c, 0x1e, 0xac, 0x24, 0xf9, 0x03, 0x95, 0x67, 0xc3, 0x13, 0x99, 0x0b, + 0xd4, 0xdb, 0x63, 0xcf, 0x25, 0x3b, 0xba, 0x34, 0xfb, 0x68, 0xba, 0x5b, 0xb2, 0xef, 0x20, 0x45, + 0x43, 0xb2, 0xfa, 0xa6, 0x18, 0x44, 0x94, 0xb4, 0x72, 0xc0, 0xe5, 0x24, 0x94, 0x7d, 0x07, 0x79, + 0xf4, 0xb5, 0x5c, 0x6a, 0x21, 0xba, 0x9d, 0xee, 0x0e, 0x2d, 0xef, 0x83, 0x73, 0x2e, 0x3d, 0xa2, + 0x98, 0x46, 0x29, 0x2b, 0x2e, 0x41, 0xd1, 0x97, 0x2a, 0x09, 0x9a, 0xb3, 0x81, 0x68, 0x51, 0x23, + 0x97, 0x20, 0x81, 0xb3, 0x3d, 0x85, 0xf1, 0x13, 0x6a, 0x93, 0x25, 0x5c, 0x25, 0xbd, 0x2a, 0xd1, + 0xb1, 0x6d, 0x52, 0x2f, 0x20, 0xc2, 0x01, 0x44, 0xc7, 0x5a, 0xb1, 0x49, 0x74, 0x44, 0xa5, 0x9e, + 0xfc, 0x54, 0x39, 0x9a, 0x74, 0xe0, 0x6f, 0x29, 0x0c, 0x4b, 0xa7, 0xf0, 0xf2, 0x5e, 0xe5, 0x37, + 0x9f, 0x5c, 0xbf, 0xaf, 0xed, 0xec, 0x13, 0x7d, 0xa9, 0xbf, 0x31, 0xf4, 0x8d, 0xfd, 0x4e, 0x8b, + 0x44, 0x3a, 0xdb, 0xcb, 0x3e, 0xfd, 0x7e, 0x07, 0x2f, 0x34, 0x50, 0xea, 0x14, 0x99, 0x45, 0x07, + 0x2b, 0x9b, 0x72, 0xc9, 0x9c, 0xf7, 0x97, 0x41, 0x17, 0xc2, 0xa3, 0x26, 0x25, 0xd4, 0xe3, 0xff, + 0x18, 0x2c, 0x23, 0x2d, 0x38, 0xbd, 0xb9, 0xbf, 0xb5, 0x42, 0x6c, 0x3b, 0xf4, 0x73, 0xbd, 0x5d, + 0xe3, 0xfb, 0x73, 0xbd, 0x7d, 0x58, 0x54, 0xe1, 0xe9, 0x13, 0x1d, 0x23, 0x40, 0xe9, 0xe2, 0xfe, + 0x4f, 0x5e, 0x7b, 0x7c, 0x8e, 0xf0, 0xac, 0xc9, 0x55, 0x47, 0x29, 0xc7, 0x80, 0x13, 0x65, 0xe3, + 0x27, 0x73, 0xc6, 0x2e, 0xeb, 0xfe, 0x9c, 0x51, 0xb4, 0x99, 0x75, 0x25, 0xbb, 0xd8, 0xb7, 0xce, + 0xbc, 0x32, 0xec, 0xa2, 0xdf, 0x25, 0x47, 0x0e, 0x18, 0x77, 0xd7, 0xc8, 0xfe, 0x2c, 0xe0, 0x9b, + 0x68, 0x74, 0xf9, 0xa7, 0xab, 0x69, 0xfa, 0x20, 0x2a, 0x18, 0x1c, 0xd3, 0xbc, 0x96, 0xcc, 0xcf, + 0x47, 0xcf, 0x44, 0xe3, 0xd3, 0x04, 0xcf, 0xfc, 0xab, 0x13, 0x8d, 0x6c, 0xcd, 0x0f, 0x11, 0x46, + 0xa3, 0x64, 0xee, 0x20, 0xba, 0xf5, 0x29, 0x41, 0x5b, 0xfa, 0x46, 0x71, 0x17, 0x1d, 0x92, 0x5e, + 0x44, 0xf8, 0x95, 0xfd, 0xb7, 0xb9, 0xd4, 0xc9, 0x07, 0x19, 0x9a, 0xda, 0x89, 0xa0, 0x3d, 0x45, + 0xb9, 0xe6, 0xd3, 0x37, 0x4f, 0xf2, 0xe0, 0xa0, 0x8e, 0xf6, 0xe8, 0xf7, 0x68, 0x8f, 0x78, 0x68, + 0xf0, 0x0b, 0x6a, 0xfb, 0x75, 0xb6, 0x82, 0xda, 0x45, 0xd2, 0x0e, 0xea, 0x25, 0xe0, 0xc2, 0xf6, + 0xe6, 0xc0, 0x58, 0xb1, 0xf7, 0x38, 0x3e, 0xfb, 0xc5, 0xeb, 0xf8, 0x35, 0x78, 0x88, 0xf7, 0x4c, + 0xaf, 0xb0, 0x67, 0x9d, 0xd3, 0xcc, 0x99, 0xe0, 0x2a, 0x1d, 0x39, 0x38, 0x06, 0x2c, 0xa3, 0xf1, + 0x2d, 0x91, 0xec, 0xb2, 0xcb, 0xd2, 0xbf, 0x42, 0xf5, 0x3f, 0x9f, 0x4e, 0xe5, 0x26, 0xd5, 0x72, + 0xed, 0xc7, 0xe1, 0x0a, 0xbd, 0xe7, 0x55, 0x5a, 0xc7, 0x51, 0x83, 0x37, 0x70, 0xec, 0xab, 0xa4, + 0x95, 0xa3, 0x0b, 0x23, 0x3f, 0x9d, 0x18, 0xd8, 0x4e, 0xcc, 0x30, 0x6b, 0xfd, 0xbc, 0x1a, 0x19, + 0xd7, 0x92, 0x71, 0x44, 0x5d, 0xef, 0xf2, 0x49, 0x3e, 0x10, 0x3d, 0x22, 0x49, 0x35, 0xf7, 0x0a, + 0x1f, 0x29, 0x12, 0x23, 0x7d, 0x0a, 0x4b, 0x9a, 0x5e, 0x55, 0x1b, 0x82, 0xb9, 0x17, 0x7b, 0x33, + 0x84, 0x4d, 0xc7, 0x0c, 0x20, 0x39, 0xd4, 0x30, 0x37, 0xf1, 0xc4, 0x3a, 0x42, 0xc6, 0x16, 0x9c, + 0xde, 0xed, 0x61, 0x64, 0xf3, 0x98, 0x9e, 0x9e, 0xf7, 0x55, 0xba, 0x17, 0x57, 0x89, 0x58, 0x62, + 0xe9, 0x37, 0xaf, 0x9a, 0x39, 0x3e, 0x60, 0xd5, 0xfd, 0xa3, 0xe1, 0x8f, 0x15, 0x65, 0x6d, 0xfa, + 0x8c, 0x12, 0x88, 0x1d, 0x7a, 0xaf, 0x65, 0x9e, 0x30, 0x26, 0x77, 0x34, 0x6a, 0xf7, 0xba, 0xb2, + 0x42, 0x1b, 0x5f, 0x6d, 0x8a, 0xb5, 0xb1, 0x0e, 0x6a, 0x36, 0x38, 0x4c, 0xf6, 0x8f, 0xcf, 0xa1, + 0x6a, 0xfe, 0xaf, 0x94, 0xae, 0x54, 0x4f, 0x8c, 0x65, 0x3b, 0xd4, 0xc0, 0xc0, 0x74, 0x66, 0xac, + 0x94, 0xf1, 0x85, 0x63, 0x9e, 0x5c, 0x13, 0xda, 0xc6, 0x35, 0xde, 0x8e, 0x01, 0xd7, 0x1c, 0x9d, + 0x5d, 0xeb, 0xdb, 0xf7, 0x28, 0x15, 0x22, 0x4d, 0x74, 0x7b, 0xfb, 0xd3, 0x67, 0x97, 0x51, 0xb9, + 0x3d, 0x8c, 0x7b, 0x37, 0x7f, 0xfd, 0xec, 0x4c, 0x6f, 0xf6, 0x5f, 0xcc, 0x95, 0xea, 0xf2, 0x83, + 0x03, 0xcc, 0xd1, 0xb7, 0xb7, 0x66, 0x1b, 0xfb, 0x8a, 0x79, 0xd6, 0x92, 0x95, 0x85, 0x64, 0xaf, + 0x79, 0x86, 0x7a, 0x5f, 0xec, 0xaa, 0x52, 0xbf, 0x57, 0xcb, 0xf3, 0x15, 0xc3, 0x70, 0x7f, 0xca, + 0x21, 0xab, 0x77, 0x4e, 0x45, 0xd2, 0xe2, 0xcc, 0x32, 0x7a, 0x00, 0x00, 0xfd, 0x34, 0x21, 0x12, + 0xdb, 0x0f, 0x22, 0xac, 0xf8, 0xc3, 0xe7, 0x45, 0x8c, 0xfa, 0x40, 0x7e, 0xca, 0x75, 0xd5, 0x22, + 0xbf, 0x10, 0xa6, 0xa5, 0x4a, 0x47, 0x4a, 0x3d, 0x5f, 0x4c, 0x2b, 0xb1, 0x3d, 0xcd, 0xfc, 0xfa, + 0xa5, 0xde, 0x81, 0xd6, 0x32, 0x6a, 0x67, 0xf6, 0x99, 0xad, 0x22, 0x3b, 0xa8, 0xfd, 0x47, 0xa5, + 0xa6, 0xed, 0xdf, 0x48, 0x4c, 0x2e, 0x0f, 0x39, 0x8c, 0x8e, 0x23, 0x1f, 0x23, 0x0d, 0x9d, 0xf5, + 0x52, 0xb5, 0x55, 0x4c, 0x99, 0xa4, 0x3e, 0x3b, 0x77, 0xf4, 0xeb, 0x99, 0xbc, 0xca, 0x57, 0x23, + 0x46, 0x83, 0x89, 0x22, 0xfa, 0xa2, 0x36, 0x38, 0x8a, 0x09, 0x36, 0x27, 0xe9, 0x9c, 0xeb, 0x50, + 0x5e, 0x75, 0xe4, 0x5f, 0x9f, 0x49, 0xb5, 0xb9, 0x5f, 0xa2, 0x0b, 0xf8, 0xab, 0xfe, 0x7d, 0xc7, + 0x30, 0x4e, 0xaa, 0x0a, 0x9f, 0x1e, 0xaf, 0x8d, 0x45, 0xf4, 0x3c, 0xc9, 0xe9, 0x03, 0x7c, 0x53, + 0x3f, 0x6f, 0x8e, 0xbc, 0x31, 0x2d, 0xd5, 0x6c, 0xa5, 0xbd, 0x3e, 0xc9, 0xef, 0x11, 0x5b, 0xda, + 0xbe, 0x7a, 0x2e, 0x1f, 0x90, 0xf9, 0xbd, 0x23, 0xdf, 0xea, 0xbc, 0xb3, 0xbe, 0x45, 0xd4, 0x10, + 0xd7, 0x38, 0xcb, 0x73, 0x62, 0x5f, 0x89, 0x58, 0xf8, 0xa5, 0xeb, 0x54, 0x6b, 0x51, 0x92, 0x33, + 0x9f, 0x0b, 0xc5, 0x5f, 0x24, 0x33, 0xea, 0xf3, 0xad, 0x93, 0x45, 0xba, 0x30, 0x71, 0x52, 0xea, + 0x7a, 0x81, 0x15, 0xdc, 0x87, 0xd1, 0xb4, 0x7e, 0x30, 0xbd, 0xc6, 0x97, 0x85, 0x50, 0x1d, 0x5f, + 0x11, 0x42, 0x63, 0xfc, 0xfd, 0xca, 0x1b, 0xe3, 0xbe, 0x5c, 0xca, 0xdb, 0x56, 0xcb, 0x15, 0xcf, + 0x9e, 0xfd, 0xc7, 0xdb, 0xa0, 0x26, 0xb0, 0x65, 0x5c, 0xfd, 0x68, 0x4d, 0x5b, 0x64, 0xde, 0x9c, + 0x28, 0xed, 0x9a, 0x53, 0x1b, 0x66, 0xf5, 0x7f, 0xf4, 0x66, 0x24, 0xc3, 0x09, 0xbe, 0x70, 0x27, + 0xb1, 0x20, 0xaa, 0x55, 0xbe, 0xb9, 0x15, 0x9a, 0x9a, 0xa6, 0x50, 0x31, 0x4d, 0xfd, 0xc6, 0x9a, + 0x54, 0x19, 0x47, 0xa4, 0x5f, 0x1a, 0xce, 0xb9, 0xdf, 0xec, 0xfc, 0x4a, 0x17, 0x15, 0xdd, 0x96, + 0xf1, 0x95, 0xcc, 0x40, 0x50, 0x9a, 0x08, 0xda, 0x0c, 0x46, 0xdc, 0x5b, 0x8d, 0x4f, 0xd6, 0xc4, + 0xcc, 0x42, 0xda, 0xc2, 0xa7, 0x24, 0x98, 0x2a, 0xa1, 0x94, 0xcc, 0x24, 0x3b, 0x7d, 0xe2, 0xdf, + 0x36, 0xbc, 0xbd, 0xaa, 0x73, 0x7c, 0xd8, 0xd4, 0x77, 0x10, 0x7d, 0x7a, 0xec, 0xea, 0xbf, 0x72, + 0x33, 0xfd, 0xc4, 0x3a, 0x42, 0x96, 0x16, 0x32, 0xcd, 0x17, 0xcd, 0xcb, 0xbd, 0xde, 0x4d, 0x89, + 0x79, 0xd6, 0x13, 0x4f, 0x91, 0x98, 0xcf, 0x97, 0x72, 0x12, 0x3c, 0xa5, 0x46, 0xcb, 0x2b, 0x4c, + 0x8d, 0x6b, 0xd4, 0xcf, 0x13, 0x24, 0x2e, 0xa3, 0x78, 0xf1, 0x71, 0xca, 0x28, 0xa2, 0xe5, 0xcb, + 0x9d, 0x9b, 0xd2, 0xcf, 0xab, 0x64, 0x44, 0x4f, 0xae, 0x1e, 0x07, 0x7d, 0x58, 0x8f, 0xd6, 0x30, + 0xbd, 0x72, 0xb6, 0x31, 0x69, 0x5d, 0x7e, 0x35, 0x70, 0xfa, 0xa9, 0x42, 0xe5, 0xa7, 0x4e, 0x3e, + 0x57, 0x2b, 0x62, 0x29, 0x92, 0x33, 0xc4, 0x81, 0xa5, 0x78, 0x5d, 0x94, 0x04, 0x72, 0xfc, 0x23, + 0x49, 0xe0, 0x4b, 0x5e, 0x30, 0xf5, 0x3b, 0x93, 0x2e, 0xcf, 0x4e, 0xd3, 0x9d, 0x7c, 0x49, 0x28, + 0xd7, 0xc9, 0x93, 0x84, 0xe8, 0x4e, 0x91, 0xe4, 0x53, 0xae, 0x53, 0x18, 0x9a, 0xf7, 0x50, 0x9b, + 0xe3, 0x5f, 0xf2, 0x9a, 0xdd, 0x90, 0x5b, 0xa1, 0x8a, 0x8f, 0xbb, 0xe7, 0xb6, 0x13, 0xef, 0x17, + 0x23, 0xfd, 0xbb, 0x13, 0xc8, 0x2f, 0x6b, 0x9b, 0x4b, 0x43, 0xbf, 0x20, 0xe5, 0x89, 0xc5, 0x76, + 0x7e, 0x70, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, + 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, + 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xfd, 0xcf, 0x24, 0xf8, 0x7f, 0xb0, 0x80, 0xcb, + 0x1e, 0x41, 0xa4, 0x73, 0x8f, 0xe6, 0x8e, 0xca, 0x73, 0x4a, 0xfd, 0xd3, 0x19, 0x31, 0x36, 0x91, + 0xd9, 0xe9, 0xe9, 0x36, 0x91, 0x5f, 0x99, 0x74, 0xa4, 0xf9, 0x77, 0xb9, 0x9f, 0x7d, 0x95, 0x99, + 0x70, 0xe7, 0x4d, 0x19, 0x2b, 0xca, 0x57, 0x4a, 0xdc, 0x0a, 0xe3, 0x5a, 0xe3, 0x44, 0xc4, 0xad, + 0x7b, 0xfe, 0x2f, 0x62, 0x31, 0x1e, 0x0f, 0x39, 0x3d, 0x26, 0xd6, 0x9a, 0xb6, 0xe3, 0x13, 0xd7, + 0x2d, 0xca, 0xaf, 0x76, 0xaa, 0xa5, 0xa8, 0x29, 0x0d, 0x77, 0x2d, 0x4e, 0x0c, 0xa1, 0xc3, 0x6f, + 0x59, 0x7d, 0x51, 0x5d, 0x41, 0x12, 0x0a, 0x4d, 0xe9, 0xab, 0x2f, 0x29, 0x71, 0x62, 0xc3, 0xac, + 0x85, 0x42, 0xd2, 0x77, 0x5b, 0x9c, 0x52, 0x51, 0x53, 0x98, 0xdb, 0xf5, 0x7b, 0x10, 0xd3, 0xb8, + 0x46, 0x67, 0xd4, 0xab, 0x66, 0x51, 0x8c, 0x21, 0x4a, 0xd1, 0x61, 0x56, 0x12, 0x41, 0xf8, 0x6c, + 0x2c, 0x10, 0x0d, 0x14, 0x9b, 0x2d, 0xf0, 0xbc, 0x2d, 0x63, 0x2d, 0xad, 0xb1, 0x96, 0xc6, 0xae, + 0xc7, 0x68, 0x31, 0x1f, 0x60, 0x3c, 0x5a, 0xf3, 0x25, 0xa2, 0x36, 0x59, 0xab, 0xa5, 0xd4, 0x4e, + 0x68, 0x4e, 0x6d, 0xda, 0x39, 0x9d, 0xb3, 0x78, 0xf5, 0xb7, 0x2d, 0x58, 0x12, 0xb4, 0x98, 0x70, + 0xfa, 0xbd, 0x60, 0x17, 0xa3, 0x7b, 0x34, 0xa3, 0x68, 0x27, 0xa3, 0xd1, 0x94, 0xd6, 0x32, 0x78, + 0x62, 0xc8, 0x18, 0x30, 0x25, 0x52, 0x04, 0xa1, 0x91, 0xa3, 0xb7, 0x2d, 0xa2, 0x26, 0x96, 0x3c, + 0x58, 0x0b, 0x8c, 0xb9, 0xb5, 0xdc, 0xbc, 0x01, 0x7e, 0x40, 0x33, 0xa1, 0xc9, 0xdb, 0xc2, 0x91, + 0xfc, 0xe4, 0x06, 0x5e, 0x88, 0x30, 0x41, 0x2c, 0x91, 0xc2, 0x2b, 0x05, 0xe6, 0xa6, 0x45, 0xf0, + 0xd1, 0x7c, 0x68, 0x79, 0x45, 0xf3, 0x34, 0xa7, 0x09, 0xa1, 0x75, 0x16, 0x75, 0x15, 0x5f, 0x66, + 0xa2, 0x58, 0xf1, 0x75, 0x3a, 0x5a, 0x32, 0xec, 0xb2, 0x99, 0x3a, 0x5d, 0x76, 0x2c, 0x47, 0x35, + 0x3f, 0x34, 0xb3, 0x41, 0xea, 0x24, 0x94, 0xb6, 0xf0, 0x9c, 0x4b, 0x29, 0x92, 0xce, 0x2d, 0x08, + 0x6c, 0x88, 0x33, 0xa2, 0xb4, 0x81, 0x5f, 0x6a, 0x81, 0xc5, 0x19, 0xe1, 0xf5, 0x21, 0xe0, 0x17, + 0xb5, 0x75, 0x69, 0x2c, 0x53, 0x54, 0x3d, 0x9d, 0xbe, 0xda, 0xbe, 0xb8, 0xd8, 0x60, 0x76, 0x8c, + 0xa3, 0xf9, 0x0d, 0x47, 0xa6, 0xfe, 0x26, 0xb3, 0x93, 0x1d, 0x8d, 0x31, 0x99, 0xcb, 0x62, 0x39, + 0x9d, 0xb9, 0x2c, 0x65, 0x83, 0x8e, 0x7a, 0xc9, 0xb3, 0x3d, 0xb9, 0x88, 0xf2, 0x14, 0x1f, 0x8c, + 0x1a, 0x98, 0xdf, 0xe4, 0x01, 0xcf, 0x58, 0x5c, 0xf1, 0xfe, 0x48, 0xff, 0xfa, 0x60, 0x9e, 0x11, + 0xc7, 0x2d, 0x09, 0x90, 0x42, 0x9f, 0xc8, 0xbc, 0xe8, 0xe1, 0x35, 0xef, 0x7c, 0x7d, 0x89, 0x54, + 0xe1, 0x59, 0xd6, 0xc2, 0x63, 0x6b, 0xe5, 0xad, 0x6f, 0xe7, 0x15, 0x78, 0xac, 0x53, 0x14, 0x1a, + 0xc2, 0x94, 0x77, 0x6f, 0xe5, 0x79, 0x9c, 0x4f, 0x87, 0x76, 0xb4, 0x90, 0xe9, 0xef, 0x77, 0xb8, + 0x93, 0xbf, 0x1d, 0x1e, 0x65, 0x5f, 0x80, 0x4d, 0x52, 0x54, 0x2d, 0x17, 0x5f, 0xc6, 0x25, 0x7e, + 0xec, 0x95, 0x29, 0xec, 0xbf, 0xbe, 0x84, 0xac, 0x19, 0x37, 0x59, 0x6b, 0x35, 0x77, 0xaf, 0x45, + 0xc8, 0x0f, 0x5b, 0x18, 0x8c, 0x19, 0xcd, 0x68, 0xf1, 0x25, 0x90, 0xaa, 0xa8, 0x91, 0xb5, 0xdc, + 0xb4, 0x08, 0xf9, 0xf2, 0xbf, 0x00, 0xc1, 0xb9, 0x6d, 0xe1, 0xc7, 0xf8, 0x71, 0xf8, 0x8c, 0x9d, + 0x93, 0x5c, 0xe7, 0x14, 0x9e, 0xe6, 0x84, 0xc9, 0xb7, 0x1e, 0xb0, 0x60, 0x91, 0xc9, 0x1d, 0x92, + 0x4b, 0x18, 0xf3, 0xe7, 0x95, 0xd1, 0x71, 0x55, 0xbe, 0xd9, 0x22, 0xde, 0xec, 0x10, 0x50, 0x8a, + 0x93, 0x3c, 0x62, 0xca, 0x92, 0xf9, 0x31, 0x2b, 0x59, 0x8a, 0x18, 0x59, 0xf8, 0x70, 0xf0, 0x0b, + 0x48, 0x99, 0x35, 0x4d, 0xf0, 0xb6, 0xc7, 0x55, 0xd7, 0xcf, 0xe0, 0x5e, 0x61, 0xa7, 0xe4, 0xce, + 0xdb, 0xb6, 0x6e, 0xbb, 0x81, 0x47, 0xc1, 0xad, 0xb8, 0x1e, 0xe0, 0xa0, 0x05, 0xf6, 0xb9, 0x74, + 0x18, 0xa5, 0xc6, 0x90, 0x3b, 0x2d, 0x6c, 0x50, 0xaf, 0xad, 0x95, 0x51, 0x2f, 0x3f, 0xde, 0x68, + 0xe1, 0xf4, 0xc7, 0x8f, 0xe8, 0xfd, 0x45, 0xc0, 0x30, 0xf8, 0x59, 0xf0, 0x54, 0xfe, 0x45, 0x10, + 0x1b, 0x7e, 0x9c, 0xf7, 0x4c, 0x68, 0x5b, 0x70, 0x3a, 0xc0, 0x66, 0x26, 0x16, 0x89, 0x80, 0x61, + 0xfe, 0xd0, 0xfb, 0xdf, 0x3a, 0x83, 0x87, 0xb8, 0x16, 0xf6, 0x90, 0x07, 0x48, 0xd4, 0x2c, 0x77, + 0x2c, 0xa2, 0x16, 0x84, 0x67, 0x51, 0x41, 0x9f, 0x24, 0xbc, 0xf0, 0x8a, 0x0f, 0x14, 0x00, 0x5a, + 0x3f, 0xa0, 0x0a, 0x08, 0xdc, 0x10, 0x21, 0x4f, 0x27, 0x38, 0x36, 0xa7, 0xee, 0x34, 0x03, 0xcd, + 0xb0, 0x11, 0x61, 0xa0, 0x0f, 0x60, 0xf3, 0x86, 0x17, 0x0e, 0x79, 0xbc, 0x7c, 0x73, 0xf3, 0xce, + 0x42, 0x25, 0x02, 0x3f, 0xc6, 0x92, 0x91, 0x62, 0x08, 0x5c, 0x86, 0xf2, 0x2d, 0x5b, 0x99, 0x5a, + 0xb2, 0xea, 0x80, 0x02, 0x7b, 0x7a, 0x4e, 0x26, 0x7f, 0xb1, 0xc2, 0xb3, 0x66, 0xdc, 0xd3, 0x5b, + 0x68, 0xb4, 0x58, 0xc4, 0xb5, 0x7d, 0x8d, 0x0e, 0x1d, 0x00, 0x09, 0xdd, 0x71, 0x29, 0xa3, 0x7c, + 0x89, 0xab, 0xc7, 0x22, 0x4a, 0x81, 0x63, 0x8a, 0x69, 0x33, 0x3c, 0x31, 0x17, 0x14, 0x34, 0x58, + 0x2b, 0x59, 0xfa, 0xf3, 0xd7, 0x22, 0xe8, 0xc7, 0xb5, 0x18, 0x46, 0x5a, 0x70, 0x7a, 0x93, 0x6b, + 0xd3, 0x0f, 0x8e, 0xf4, 0xf4, 0x37, 0xf3, 0xf2, 0xe8, 0x9b, 0x9b, 0xe5, 0xfa, 0xd5, 0x12, 0x17, + 0xd2, 0x4c, 0x1e, 0x04, 0x1b, 0xa3, 0xf8, 0xe6, 0x29, 0x8a, 0x96, 0x8f, 0x97, 0xd3, 0x39, 0x68, + 0x3d, 0x1a, 0xbb, 0xbd, 0x2d, 0x6c, 0xcb, 0xa3, 0x63, 0x4a, 0xb0, 0x41, 0xc0, 0x2f, 0xfa, 0xe1, + 0x09, 0x05, 0xe8, 0x81, 0x60, 0x50, 0x2a, 0xa3, 0x9f, 0x7c, 0x9a, 0x5c, 0xfa, 0xb8, 0x05, 0x38, + 0x86, 0x6a, 0x95, 0x12, 0x97, 0x56, 0x2b, 0x7f, 0xdc, 0x42, 0x39, 0x20, 0x3f, 0x40, 0x7b, 0xc5, + 0x77, 0xba, 0x8b, 0x68, 0xb9, 0x77, 0xd3, 0xc2, 0xf4, 0x45, 0xed, 0x6d, 0x66, 0xe5, 0x6d, 0x0b, + 0xd1, 0xfd, 0x34, 0xc7, 0xbb, 0x1b, 0x57, 0xc7, 0xe3, 0x1c, 0x51, 0x63, 0x0b, 0x4e, 0xef, 0x24, + 0x70, 0x60, 0xf9, 0xd9, 0x10, 0x5e, 0x34, 0x8a, 0x32, 0xd6, 0x14, 0x19, 0x6c, 0xdc, 0xc2, 0x87, + 0x31, 0x11, 0xe0, 0x1e, 0xf0, 0x09, 0x4d, 0xc2, 0x92, 0x9e, 0xd0, 0x30, 0x34, 0x3f, 0x19, 0x82, + 0x27, 0x22, 0x78, 0x51, 0x30, 0x15, 0xc5, 0x4b, 0x5e, 0x51, 0x8a, 0x84, 0x3e, 0xca, 0xec, 0x23, + 0xa9, 0xe6, 0x93, 0x31, 0x9a, 0xc0, 0x8f, 0xa3, 0xcd, 0x16, 0x2a, 0x58, 0x9d, 0x91, 0x7c, 0x0b, + 0x4e, 0xfc, 0x2b, 0x04, 0xfc, 0x51, 0xd0, 0xad, 0x05, 0x9a, 0x7d, 0x02, 0x76, 0x33, 0x13, 0xb3, + 0x74, 0xf0, 0xba, 0x05, 0x53, 0x5c, 0xbf, 0x6e, 0xa1, 0x1f, 0xf2, 0x73, 0x2c, 0xf3, 0xa8, 0xe2, + 0xd7, 0x6f, 0xc2, 0xcf, 0x80, 0x4b, 0x60, 0xaf, 0x0e, 0xa9, 0xa0, 0xbe, 0xd9, 0x22, 0xc0, 0xb5, + 0x30, 0xa9, 0x67, 0x73, 0xcc, 0xb1, 0xc5, 0x7d, 0xad, 0x28, 0xf1, 0x3b, 0x0c, 0xf0, 0x63, 0x36, + 0xf2, 0xeb, 0x21, 0x15, 0xb8, 0xbe, 0x0b, 0xec, 0x0b, 0x5a, 0xb3, 0xa5, 0x35, 0x54, 0x8a, 0x4d, + 0x91, 0xa5, 0x86, 0x55, 0xb0, 0xdd, 0x65, 0x19, 0x9e, 0x7f, 0x65, 0x98, 0xaf, 0xae, 0xdd, 0xb6, + 0xd0, 0x87, 0x6a, 0x6e, 0xce, 0xff, 0x46, 0xe1, 0xc5, 0x5c, 0x8b, 0xc3, 0x64, 0x66, 0xe2, 0x26, + 0x0f, 0x35, 0x04, 0xde, 0x1c, 0x18, 0x01, 0xd0, 0x62, 0x2e, 0xf7, 0x38, 0xef, 0xb9, 0xa7, 0x05, + 0xa7, 0xa3, 0xc0, 0x29, 0xb1, 0xe5, 0x14, 0x53, 0x49, 0x67, 0x43, 0xf6, 0x73, 0x8f, 0xa0, 0x30, + 0x3e, 0xeb, 0xe1, 0x04, 0x11, 0xa8, 0xd5, 0xa9, 0x9a, 0x86, 0xbf, 0xca, 0xdd, 0xf6, 0x4c, 0x8d, + 0x82, 0x2f, 0x91, 0xd5, 0xec, 0xbf, 0x2b, 0xad, 0xc1, 0x37, 0xfe, 0x49, 0xc5, 0x58, 0x63, 0x1c, + 0xd6, 0xe1, 0x15, 0x12, 0x37, 0xa6, 0x41, 0x12, 0x71, 0x1d, 0xdd, 0xf4, 0x5f, 0x70, 0x63, 0x38, + 0x46, 0x24, 0x8a, 0xe1, 0x33, 0xd5, 0xf1, 0xf1, 0x68, 0x4d, 0x70, 0x1e, 0x9e, 0x48, 0x65, 0xe2, + 0xef, 0x68, 0x6d, 0x5e, 0x19, 0x1b, 0x45, 0xf9, 0x8a, 0xe0, 0x28, 0xca, 0x2b, 0x33, 0x4e, 0x1f, + 0x51, 0xce, 0x1c, 0xa0, 0xfc, 0x53, 0xf2, 0x80, 0xe0, 0x6f, 0x3b, 0x5c, 0xb9, 0xce, 0xa4, 0x63, + 0xdc, 0x4e, 0x21, 0xfa, 0x10, 0x26, 0x10, 0xe9, 0x49, 0x7f, 0x84, 0xbf, 0x87, 0x10, 0xb6, 0xbf, + 0x6a, 0xab, 0x10, 0xb9, 0x82, 0x26, 0xc5, 0xe1, 0xd5, 0x7a, 0xef, 0xd8, 0xee, 0xc4, 0x02, 0x2f, + 0x6e, 0x9e, 0x5e, 0xf1, 0xa5, 0x28, 0x83, 0x2a, 0x11, 0x2c, 0x9e, 0x5c, 0x50, 0x97, 0x54, 0xc5, + 0x3d, 0xa6, 0x9a, 0x02, 0x08, 0x80, 0xd8, 0x76, 0xa4, 0x2b, 0x65, 0x47, 0xd6, 0x91, 0xfe, 0xf7, + 0x67, 0x34, 0x3e, 0x91, 0xcb, 0x6f, 0x69, 0xc1, 0x69, 0x70, 0xa5, 0x0c, 0xe5, 0x0d, 0x40, 0xeb, + 0x01, 0x93, 0x81, 0x7b, 0x45, 0x52, 0x3a, 0xf7, 0xf0, 0x8e, 0x1a, 0x4e, 0x7d, 0xa4, 0xe0, 0x12, + 0x25, 0xe2, 0xa4, 0xc1, 0xa5, 0xa0, 0x45, 0xbf, 0xfc, 0x80, 0x46, 0x06, 0xe4, 0x34, 0xd2, 0x35, + 0x20, 0xe5, 0x38, 0x7d, 0x63, 0x74, 0x90, 0x83, 0x4a, 0x4f, 0x3f, 0x30, 0x9f, 0x88, 0x46, 0xe2, + 0xb2, 0xf4, 0xf4, 0xc3, 0xb6, 0x88, 0x14, 0xd8, 0xa0, 0x7e, 0x04, 0x58, 0x00, 0x70, 0x03, 0x60, + 0x24, 0xe4, 0x08, 0xd2, 0x75, 0xef, 0x19, 0xb4, 0x46, 0xa4, 0x68, 0xa6, 0x19, 0x0b, 0x06, 0x10, + 0x19, 0x34, 0x3f, 0xc0, 0x66, 0x40, 0xcd, 0x86, 0xaa, 0x6c, 0xb1, 0x29, 0x81, 0x6a, 0x0b, 0x34, + 0xf7, 0x5a, 0x70, 0x1b, 0xd8, 0x17, 0x42, 0xa3, 0xbc, 0x39, 0xd6, 0x30, 0x17, 0x0a, 0x17, 0x38, + 0xce, 0x19, 0xc5, 0xdb, 0x16, 0x0a, 0x59, 0xa5, 0x17, 0x1c, 0xb5, 0x80, 0x13, 0x07, 0x68, 0x97, + 0x48, 0xde, 0x4c, 0xe7, 0xb6, 0x29, 0xe4, 0x34, 0xd7, 0x7b, 0x42, 0xd0, 0xcc, 0x80, 0xbe, 0xc9, + 0xf3, 0x96, 0xde, 0xf0, 0x0a, 0xd8, 0x2f, 0xcb, 0x8d, 0x21, 0x12, 0x28, 0xc0, 0xbb, 0x19, 0x1b, + 0x9f, 0x54, 0x32, 0xa7, 0x7d, 0xbc, 0x3e, 0x85, 0xad, 0x05, 0xa7, 0xbb, 0x44, 0x6c, 0x44, 0x91, + 0x35, 0xb1, 0xaa, 0xc3, 0xb5, 0x4c, 0x24, 0xe2, 0xea, 0xe4, 0x67, 0x26, 0x52, 0x15, 0x9a, 0xb5, + 0xe2, 0x51, 0xa3, 0x61, 0xbe, 0xb0, 0xb6, 0x6d, 0x58, 0x50, 0x11, 0x41, 0x4c, 0x4f, 0x78, 0xf5, + 0xaa, 0xb9, 0x6b, 0x5e, 0xe2, 0xc5, 0xc9, 0x4c, 0x24, 0x80, 0xb1, 0xb5, 0x08, 0xa5, 0x26, 0xa2, + 0x26, 0x60, 0x10, 0x4a, 0x01, 0x03, 0xc0, 0x18, 0x26, 0x0c, 0x03, 0x1a, 0x37, 0x2e, 0x4f, 0x27, + 0x8c, 0xac, 0x1a, 0xf1, 0xea, 0x87, 0x14, 0xd7, 0xce, 0x1c, 0x2b, 0x4e, 0x6e, 0x04, 0xb1, 0x32, + 0x5b, 0x8d, 0x50, 0x06, 0x9a, 0x09, 0x18, 0xd5, 0x54, 0xc4, 0x68, 0xd4, 0x00, 0x3c, 0x0d, 0x9a, + 0xe5, 0x4d, 0xa7, 0x73, 0xf6, 0xc9, 0x24, 0x59, 0x4d, 0x11, 0xfa, 0x21, 0xfb, 0x4d, 0x8b, 0xc2, + 0xf9, 0x46, 0x04, 0x2f, 0xb3, 0x4c, 0x05, 0x2f, 0xf8, 0x48, 0xdc, 0xb0, 0x40, 0x45, 0xf4, 0x81, + 0x6a, 0x3a, 0x62, 0x63, 0x23, 0xee, 0xc3, 0xf8, 0x10, 0x5e, 0x4a, 0xb1, 0x64, 0x6d, 0xf4, 0x38, + 0x1a, 0xd4, 0x5f, 0x73, 0xc6, 0x31, 0xa4, 0x3a, 0x0f, 0xe2, 0x45, 0x6b, 0x3a, 0x62, 0x2c, 0x4e, + 0x12, 0xac, 0xb5, 0xb6, 0x88, 0xf1, 0x33, 0x1a, 0x6a, 0x2d, 0x03, 0xcc, 0x1e, 0x3f, 0x9e, 0xa6, + 0xa2, 0x2f, 0x33, 0x10, 0x9e, 0x3c, 0xc7, 0x8a, 0xf4, 0x4d, 0xaf, 0xac, 0x4c, 0x29, 0xaa, 0x96, + 0xa7, 0x23, 0xc0, 0xec, 0x91, 0x71, 0xeb, 0xd7, 0x06, 0xee, 0x7e, 0xc5, 0xc4, 0x3e, 0x43, 0xee, + 0xfb, 0x8b, 0xb6, 0x86, 0x35, 0xb2, 0x16, 0xce, 0x9b, 0x70, 0x01, 0x63, 0xad, 0x19, 0xf0, 0x9e, + 0x4c, 0x86, 0x33, 0x62, 0x11, 0x09, 0xfe, 0xc4, 0x9a, 0x2b, 0x48, 0x0b, 0x4e, 0x0b, 0x81, 0x07, + 0xd3, 0x1a, 0xaf, 0xb3, 0xdc, 0x11, 0x9e, 0xf0, 0xfa, 0xdb, 0xd9, 0x80, 0x4f, 0xb1, 0xf4, 0xf6, + 0xdd, 0x4d, 0xa7, 0xcf, 0xf1, 0x84, 0x8d, 0xfc, 0x79, 0x27, 0x27, 0xd3, 0x00, 0x8c, 0x02, 0x31, + 0x17, 0x88, 0x25, 0x88, 0x85, 0x03, 0x99, 0x5a, 0x28, 0x7e, 0x77, 0x13, 0xf0, 0x25, 0x4e, 0x57, + 0xc7, 0xcd, 0xfd, 0x94, 0x6a, 0xa8, 0x00, 0x40, 0x7a, 0x10, 0x64, 0x40, 0x7a, 0x9d, 0xee, 0xaf, + 0x94, 0xba, 0x90, 0xfb, 0x29, 0xfb, 0xb9, 0x0e, 0xa1, 0xe2, 0x06, 0xf5, 0xc2, 0x63, 0xd0, 0xf5, + 0x0a, 0x80, 0x63, 0x76, 0x01, 0xa7, 0xe9, 0x42, 0x80, 0xdf, 0x3a, 0x40, 0xef, 0x79, 0x2b, 0xf8, + 0x0c, 0xd0, 0xc2, 0xd6, 0x6c, 0x71, 0x00, 0x37, 0x34, 0x61, 0x53, 0x23, 0x08, 0x5c, 0x16, 0xc0, + 0x85, 0xf4, 0x0c, 0xc8, 0x1f, 0xea, 0x3d, 0xdd, 0x73, 0xd3, 0x2b, 0x81, 0x50, 0x7e, 0xc0, 0xd9, + 0x5a, 0xc2, 0x38, 0x08, 0xd4, 0xc3, 0x28, 0x85, 0xba, 0x89, 0xdc, 0x57, 0x69, 0x21, 0x5c, 0x8f, + 0x60, 0xf0, 0x66, 0x77, 0x80, 0xeb, 0xb3, 0xd4, 0x99, 0x43, 0x10, 0xc5, 0xdc, 0xe3, 0x39, 0xfe, + 0x1d, 0xde, 0x16, 0x9c, 0xee, 0x7f, 0x10, 0x19, 0x02, 0xf3, 0x0f, 0x34, 0x62, 0x3c, 0xad, 0x7e, + 0xc5, 0x07, 0x9f, 0xb7, 0x93, 0xbf, 0x13, 0x5e, 0xd9, 0xfa, 0x79, 0xd6, 0xcc, 0x01, 0x4a, 0x7c, + 0x9d, 0x4d, 0x93, 0x4c, 0xba, 0xf6, 0x44, 0x9c, 0xf7, 0xb3, 0xa9, 0x14, 0x51, 0x5b, 0x2d, 0x4e, + 0xef, 0xf0, 0xfa, 0x80, 0xc6, 0x45, 0x0b, 0x28, 0x8b, 0xd2, 0x08, 0x62, 0x49, 0x3c, 0xc5, 0x06, + 0xdd, 0xb9, 0xf4, 0xd3, 0xb1, 0xa4, 0x1f, 0xa3, 0x2d, 0xe4, 0x62, 0x3a, 0x09, 0xb4, 0xe5, 0xdd, + 0xd1, 0x78, 0xa8, 0xe4, 0xe2, 0x27, 0x25, 0xf8, 0xc2, 0x30, 0x1b, 0x9c, 0xb3, 0xdc, 0xb4, 0x80, + 0x5e, 0x77, 0xc2, 0x7d, 0x13, 0x19, 0xa2, 0x3c, 0xda, 0xe2, 0xc4, 0x09, 0x0b, 0x70, 0x72, 0x99, + 0x44, 0x1a, 0x87, 0xb1, 0x64, 0x10, 0xc0, 0xf5, 0xe0, 0x13, 0xb1, 0x64, 0xd8, 0x89, 0x41, 0x83, + 0x10, 0x54, 0x05, 0x2c, 0x00, 0xfe, 0x65, 0xf0, 0x14, 0x15, 0xdd, 0x39, 0xfd, 0x5c, 0x8a, 0x5a, + 0x59, 0x45, 0xc4, 0x78, 0x3f, 0x32, 0xc4, 0x4c, 0x30, 0x96, 0xdc, 0x1e, 0x1f, 0xe5, 0x76, 0xbd, + 0x67, 0x96, 0x21, 0xdf, 0x67, 0x5f, 0xb2, 0xe2, 0x2e, 0xbf, 0x8c, 0x68, 0x8a, 0x1f, 0xfa, 0x09, + 0x7f, 0x42, 0x15, 0xd9, 0xf5, 0x31, 0x0f, 0x62, 0x49, 0xe0, 0x11, 0x0d, 0xb3, 0x4f, 0xac, 0x8d, + 0x85, 0xb7, 0xe0, 0xb4, 0xe0, 0xcf, 0x82, 0xa9, 0x03, 0xce, 0x82, 0x79, 0x0e, 0xe9, 0x9d, 0xac, + 0xee, 0xb5, 0x06, 0xa1, 0x5d, 0x63, 0xd8, 0x7e, 0x69, 0xa1, 0x2c, 0x08, 0x9f, 0x2e, 0xa8, 0x83, + 0xd4, 0xb2, 0x8e, 0xb5, 0x6f, 0x9d, 0x3a, 0x0c, 0x83, 0x53, 0x59, 0x4f, 0xdd, 0x42, 0x4c, 0x0c, + 0xc6, 0xba, 0x77, 0xea, 0xa5, 0x32, 0x5d, 0x71, 0x68, 0x14, 0x08, 0x55, 0x57, 0x27, 0xff, 0xfb, + 0x40, 0x3a, 0x94, 0xf8, 0x2e, 0xf9, 0x20, 0x30, 0xea, 0x03, 0x83, 0xa3, 0x5f, 0xbd, 0x71, 0x88, + 0xc5, 0x1b, 0xc0, 0xdd, 0x1c, 0x8a, 0x2a, 0xc1, 0x06, 0x13, 0x00, 0x54, 0x1e, 0xe1, 0xd9, 0x60, + 0x44, 0x2a, 0x08, 0x83, 0x63, 0x7d, 0x96, 0xf0, 0xc2, 0x2d, 0x34, 0x7f, 0x05, 0xa0, 0x39, 0xc6, + 0x21, 0x35, 0xa5, 0xc6, 0xbd, 0x92, 0xf6, 0xda, 0x89, 0x31, 0x55, 0xdd, 0x2b, 0x02, 0x77, 0x2e, + 0xdb, 0x4b, 0x24, 0x67, 0x2e, 0xf8, 0x1b, 0xd5, 0xc1, 0xa6, 0xb7, 0x9f, 0x0c, 0x30, 0xcd, 0x5f, + 0x85, 0x9d, 0xc1, 0x26, 0xe8, 0xeb, 0xb3, 0xd7, 0x5d, 0x8f, 0xe7, 0xf8, 0x6f, 0xb6, 0xe0, 0x74, + 0xef, 0x9f, 0xbd, 0xce, 0x41, 0x43, 0x31, 0xb5, 0x77, 0x4e, 0x28, 0x5c, 0x39, 0x61, 0xab, 0x35, + 0x41, 0x84, 0xb7, 0xaa, 0x07, 0xbc, 0x83, 0x05, 0xb9, 0xde, 0xcd, 0xf5, 0x48, 0xe4, 0x07, 0xae, + 0x47, 0xd0, 0x17, 0x18, 0xa2, 0x2e, 0x91, 0xec, 0x80, 0x16, 0x0c, 0x40, 0x83, 0x25, 0x57, 0xb8, + 0x08, 0xa5, 0xbc, 0xe9, 0xad, 0x72, 0x3c, 0xf5, 0xc3, 0x35, 0x41, 0xb8, 0x25, 0x38, 0x90, 0x27, + 0x20, 0xbc, 0x8c, 0x5b, 0xaf, 0x03, 0xba, 0x72, 0xc4, 0xf2, 0x70, 0x85, 0x0f, 0xf9, 0x7d, 0xf4, + 0xae, 0x94, 0xdf, 0x41, 0xfe, 0x04, 0x78, 0xc6, 0x83, 0x0e, 0x81, 0x16, 0xd0, 0xc3, 0x0a, 0x6f, + 0x4e, 0x00, 0xa3, 0x88, 0x5c, 0xbf, 0x2a, 0x82, 0x68, 0x05, 0xc8, 0x1d, 0x78, 0x3d, 0xf7, 0x44, + 0xde, 0xca, 0x76, 0x0b, 0x4e, 0x2b, 0xff, 0xa2, 0x08, 0x75, 0xf2, 0xe3, 0x8d, 0x28, 0x7b, 0x34, + 0x49, 0x46, 0xe6, 0xec, 0x30, 0xca, 0x5e, 0x7b, 0x79, 0x63, 0xee, 0x40, 0x40, 0x1d, 0x71, 0xac, + 0x3d, 0x88, 0xcb, 0x5f, 0x34, 0x23, 0x79, 0x43, 0x9d, 0xb9, 0xb9, 0xae, 0x1c, 0xf3, 0xe7, 0x4d, + 0x3b, 0x4d, 0x48, 0xa8, 0x33, 0xb2, 0x77, 0x62, 0xe6, 0xe6, 0xed, 0x59, 0x10, 0x65, 0x7b, 0xb4, + 0x13, 0xa1, 0x12, 0xd4, 0xd0, 0x34, 0xc5, 0x4e, 0x59, 0x96, 0xca, 0xaf, 0x1a, 0xf6, 0x46, 0x82, + 0x47, 0x94, 0xcc, 0x83, 0x28, 0x7b, 0x3b, 0xfc, 0xb9, 0xfc, 0x6a, 0x3b, 0x38, 0xd7, 0x7c, 0x8f, + 0x10, 0x0c, 0xee, 0x39, 0xe4, 0xcf, 0xc5, 0xe5, 0xe4, 0xd7, 0x1c, 0x88, 0xcb, 0xd5, 0x8f, 0xa2, + 0x6c, 0x5b, 0xd8, 0x48, 0xdc, 0xc4, 0xe5, 0x44, 0xa7, 0x70, 0x5a, 0x0b, 0x3f, 0xe9, 0x22, 0xda, + 0x69, 0xc3, 0x16, 0xd3, 0xeb, 0xc1, 0x27, 0xe2, 0xf2, 0xad, 0xac, 0xd3, 0xf3, 0x62, 0x27, 0xdd, + 0x88, 0xcb, 0x7d, 0xab, 0x45, 0x4d, 0x61, 0x71, 0x8b, 0x2f, 0x89, 0x3e, 0x5e, 0x45, 0x42, 0xbb, + 0xd6, 0x82, 0xd3, 0x9a, 0x66, 0xa4, 0xbc, 0xe8, 0x07, 0xfa, 0x07, 0x23, 0x65, 0xa0, 0x6b, 0x4a, + 0x03, 0x30, 0x17, 0x9d, 0xfc, 0x71, 0xb0, 0xe9, 0x24, 0x40, 0x2c, 0x0c, 0x8e, 0x81, 0x48, 0xd9, + 0xbc, 0x88, 0xf5, 0x09, 0x88, 0xdb, 0xd0, 0x38, 0xca, 0xb2, 0x10, 0x8b, 0xb3, 0xeb, 0x64, 0x18, + 0x6b, 0xfc, 0xea, 0xa5, 0x2b, 0xee, 0xa1, 0xd7, 0x1b, 0x51, 0x36, 0xda, 0x0b, 0x94, 0xf5, 0xcd, + 0x2f, 0x1f, 0xe6, 0x74, 0x05, 0x35, 0x61, 0xae, 0xd5, 0xe3, 0xa2, 0x88, 0x8a, 0x21, 0x02, 0xa3, + 0xf0, 0x75, 0x96, 0x6a, 0x99, 0x75, 0x11, 0xc7, 0xb7, 0xcf, 0x9f, 0xa9, 0x72, 0x33, 0xa8, 0x7d, + 0x4b, 0xee, 0x36, 0x3f, 0xc6, 0x2a, 0xd6, 0xc4, 0x6c, 0xa8, 0x5b, 0xd9, 0x3c, 0x8b, 0x53, 0x06, + 0xfb, 0x38, 0xe7, 0xe9, 0xc2, 0xa5, 0xc9, 0xe8, 0xe4, 0x01, 0x1c, 0x07, 0xfa, 0x7d, 0x25, 0x5e, + 0xb6, 0x1f, 0xc0, 0x8e, 0x87, 0x56, 0xbc, 0xa2, 0xb0, 0xfc, 0x46, 0xca, 0x16, 0x51, 0xfc, 0x69, + 0x61, 0x59, 0xa9, 0x74, 0x49, 0x9b, 0x9a, 0xf1, 0xbf, 0x31, 0xfe, 0xf4, 0x2a, 0x50, 0x32, 0xc9, + 0xc1, 0x8a, 0x4f, 0xa4, 0x5a, 0x41, 0x3b, 0x44, 0xa2, 0xa7, 0xc5, 0xab, 0x1f, 0xa8, 0x1b, 0x21, + 0x94, 0xca, 0x2e, 0xd9, 0xc9, 0xcc, 0xc6, 0xc9, 0xb1, 0xe7, 0x79, 0xe1, 0x76, 0xad, 0x9f, 0x39, + 0x6d, 0x4a, 0xa5, 0x59, 0x46, 0xfe, 0xbe, 0xd5, 0x6d, 0x14, 0x1d, 0xbc, 0x16, 0xdf, 0xb0, 0x43, + 0x74, 0x1f, 0x04, 0x2b, 0xee, 0xa1, 0x86, 0x1b, 0x83, 0xe0, 0x02, 0x1f, 0xd7, 0x95, 0xb3, 0x29, + 0x39, 0x24, 0x01, 0x43, 0x72, 0xf1, 0xdd, 0xb3, 0xc8, 0x7d, 0x00, 0x7d, 0xa7, 0x99, 0xf2, 0xda, + 0xa6, 0x3d, 0x0e, 0xd3, 0x1b, 0x98, 0xf8, 0xe0, 0x4e, 0x9c, 0x7f, 0xff, 0x92, 0x87, 0x01, 0x83, + 0x06, 0x98, 0x38, 0xda, 0x08, 0xf0, 0x0d, 0xf1, 0x14, 0xbb, 0x1b, 0xe6, 0x47, 0x7c, 0xff, 0x18, + 0xbc, 0x0b, 0x17, 0xec, 0x37, 0x61, 0xf8, 0xbd, 0xb3, 0x5a, 0x35, 0x17, 0x99, 0x3c, 0x58, 0xd8, + 0x08, 0xf6, 0x59, 0x89, 0xdc, 0x5b, 0x4b, 0xe9, 0xf6, 0x65, 0xe0, 0x33, 0xee, 0x19, 0xf2, 0xd9, + 0x47, 0x1e, 0x40, 0xd1, 0xd3, 0xd5, 0x82, 0xd3, 0xb0, 0x00, 0x38, 0x68, 0x53, 0xc1, 0x55, 0xe7, + 0xbe, 0x18, 0x09, 0x0c, 0x8c, 0x64, 0xf6, 0x2b, 0x66, 0x4b, 0x93, 0xa9, 0xe3, 0xe0, 0x6d, 0xfc, + 0x6e, 0x34, 0x45, 0x71, 0x7d, 0x23, 0xe2, 0x4f, 0x00, 0x0b, 0x4b, 0x42, 0x1e, 0x85, 0xd1, 0xcf, + 0xbe, 0x2b, 0xbc, 0x44, 0xad, 0xef, 0x40, 0x24, 0xc1, 0x8f, 0x47, 0xe6, 0xd6, 0xf1, 0x66, 0x0b, + 0x5f, 0xe6, 0x36, 0x7e, 0x07, 0x1b, 0x6d, 0x73, 0x28, 0x4e, 0x12, 0x82, 0x67, 0xdd, 0x11, 0x1b, + 0x70, 0x8b, 0x58, 0x94, 0xff, 0x44, 0xfc, 0x0e, 0x5b, 0x78, 0xf5, 0x13, 0xcb, 0x9c, 0x15, 0xc7, + 0xf8, 0xdb, 0xf7, 0x2d, 0xa3, 0x2d, 0xa3, 0x26, 0xd7, 0x82, 0xb7, 0xf1, 0xbb, 0x26, 0x31, 0x85, + 0x9b, 0x00, 0x30, 0xef, 0xd9, 0x36, 0xbb, 0xb5, 0x4f, 0x70, 0x1f, 0xe0, 0x1b, 0x53, 0xea, 0x7e, + 0xc4, 0x1f, 0xa2, 0x20, 0xe6, 0x49, 0x83, 0xf8, 0xdd, 0xda, 0xc0, 0x4b, 0x60, 0x23, 0xbb, 0xd3, + 0x82, 0x7d, 0xde, 0x88, 0xdf, 0x9b, 0xbd, 0xc2, 0x2d, 0x8d, 0x4b, 0x40, 0xfc, 0x61, 0xcd, 0x4c, + 0x2c, 0xc2, 0x11, 0x7c, 0x14, 0xc6, 0x32, 0xe0, 0x65, 0x52, 0x24, 0x1c, 0x5f, 0xf8, 0xf4, 0x78, + 0xcd, 0x3e, 0x54, 0xd8, 0x82, 0xd3, 0x23, 0x83, 0xf0, 0xcb, 0x8a, 0x9f, 0x18, 0x5c, 0x1a, 0x80, + 0xe1, 0xe6, 0x20, 0x00, 0xe4, 0x5a, 0x25, 0x02, 0xe4, 0x08, 0x81, 0xd0, 0x1c, 0x44, 0x9a, 0x68, + 0x0f, 0xb4, 0x64, 0x3d, 0x22, 0xe9, 0xc1, 0x23, 0xd9, 0xea, 0x97, 0xd2, 0xb4, 0x05, 0x44, 0x91, + 0xb4, 0x0d, 0x91, 0xd3, 0x2e, 0x23, 0x78, 0x0a, 0x01, 0x51, 0x2f, 0x10, 0x67, 0x39, 0xe7, 0xb1, + 0x5d, 0x30, 0x56, 0xbf, 0x51, 0x00, 0xa0, 0x3c, 0x3d, 0x0a, 0x6e, 0xc4, 0x0a, 0x34, 0xb1, 0x70, + 0x03, 0x44, 0x6a, 0xa9, 0x8b, 0x40, 0x40, 0xd8, 0xe7, 0x52, 0x42, 0xa0, 0xdd, 0x90, 0xe4, 0x3e, + 0xc5, 0x1d, 0x56, 0xa0, 0x36, 0xf1, 0x75, 0x64, 0xd8, 0x85, 0x48, 0x65, 0x50, 0x92, 0x01, 0xc6, + 0x56, 0x5f, 0xaf, 0xa6, 0x85, 0x70, 0x78, 0x7a, 0xe0, 0xce, 0x7b, 0xc8, 0xe8, 0x1e, 0x18, 0x04, + 0x73, 0xaf, 0xdc, 0x73, 0xa3, 0x37, 0xb6, 0x81, 0xeb, 0x20, 0xd3, 0xc6, 0x5d, 0xac, 0x54, 0xdc, + 0x89, 0x39, 0x2d, 0xd7, 0x2c, 0x92, 0xa1, 0x5d, 0xb7, 0x23, 0x74, 0x6a, 0xe4, 0x3a, 0x2a, 0xe7, + 0x8e, 0x0d, 0x34, 0xd6, 0x16, 0x7b, 0x2c, 0xd3, 0x72, 0xa2, 0xbf, 0x05, 0xa7, 0xc7, 0x18, 0xee, + 0x3b, 0x49, 0xe6, 0x10, 0x7a, 0x0b, 0x7c, 0xbb, 0xbc, 0x95, 0x35, 0x31, 0x0c, 0x6e, 0xd4, 0x33, + 0x34, 0xe1, 0xe0, 0x62, 0xce, 0xd9, 0xeb, 0x3e, 0xe0, 0x65, 0x35, 0x13, 0xb1, 0xbc, 0x4d, 0x58, + 0x2f, 0x83, 0x11, 0x80, 0x9d, 0x33, 0x66, 0x86, 0xde, 0xc6, 0x48, 0x10, 0xa5, 0x9a, 0x52, 0x3e, + 0x10, 0xa5, 0xb2, 0xaa, 0x74, 0x10, 0x33, 0xd0, 0x20, 0xe6, 0x94, 0xa3, 0xb7, 0x51, 0xea, 0x46, + 0x30, 0x80, 0x4d, 0x66, 0xb1, 0x98, 0x3e, 0x93, 0x00, 0x91, 0x66, 0x8a, 0x08, 0x8c, 0xeb, 0x4b, + 0x6b, 0x01, 0xfc, 0x18, 0x78, 0xd2, 0x89, 0x40, 0xb4, 0x6c, 0x63, 0x17, 0x90, 0x8a, 0x63, 0x48, + 0x41, 0xdf, 0x89, 0x39, 0x83, 0xa5, 0x72, 0x26, 0x10, 0xc1, 0xeb, 0x56, 0x06, 0xc7, 0x54, 0x87, + 0x3e, 0x1c, 0xd3, 0xa7, 0x23, 0x10, 0x4a, 0x1f, 0xee, 0x84, 0xe7, 0xd4, 0xc0, 0x10, 0x91, 0x38, + 0x49, 0xf9, 0x6e, 0x22, 0x48, 0x87, 0xfe, 0x3c, 0x13, 0x09, 0x1a, 0x58, 0x26, 0x82, 0x27, 0x52, + 0x95, 0x80, 0x15, 0x8e, 0x3a, 0xb1, 0xf3, 0x87, 0xd1, 0xd7, 0x1c, 0x02, 0xc8, 0x06, 0xa3, 0x2f, + 0xd9, 0x90, 0xd3, 0xc3, 0x5f, 0x0b, 0x1a, 0x6e, 0x5a, 0x0c, 0x29, 0x98, 0x20, 0x5e, 0x60, 0x60, + 0x18, 0xb9, 0x0e, 0x1c, 0x7a, 0x28, 0xc7, 0x45, 0x9a, 0x2f, 0x33, 0x59, 0x3f, 0x54, 0xe9, 0x88, + 0xc1, 0x44, 0xc3, 0x98, 0xd3, 0x84, 0xe9, 0xaf, 0xdd, 0x0a, 0xc6, 0xca, 0xc1, 0xc5, 0x6a, 0xa0, + 0x3e, 0xeb, 0xc7, 0x1b, 0x99, 0xed, 0x38, 0xbe, 0xc8, 0x45, 0xa9, 0xba, 0xad, 0x30, 0xfa, 0x78, + 0x44, 0x45, 0x2b, 0x68, 0xc1, 0xe9, 0x17, 0xa9, 0xa6, 0x43, 0x1b, 0x2d, 0xb0, 0xd7, 0xae, 0xcd, + 0x6e, 0x6f, 0xfc, 0x22, 0x31, 0x63, 0xd9, 0x08, 0xbe, 0xb6, 0xa6, 0x02, 0x7b, 0x5d, 0x71, 0x06, + 0xa8, 0xf3, 0x34, 0xfc, 0xf8, 0xe3, 0xcb, 0xbe, 0x84, 0x6a, 0xbc, 0x31, 0xfe, 0xef, 0x4b, 0x55, + 0xf6, 0x0f, 0xae, 0x81, 0xcf, 0xe9, 0x5f, 0x05, 0xda, 0xb3, 0x37, 0xfa, 0x40, 0xcd, 0x1f, 0xc1, + 0xb0, 0xaf, 0x5f, 0x2a, 0x1f, 0x7f, 0xcb, 0xec, 0x86, 0x8b, 0x89, 0x84, 0x92, 0x5e, 0xba, 0x4a, + 0x55, 0x1d, 0x11, 0x7c, 0x32, 0x45, 0x2e, 0xe7, 0x59, 0x15, 0xe3, 0x3b, 0xa7, 0xca, 0x53, 0xe1, + 0x52, 0xbd, 0x87, 0x21, 0x4a, 0x09, 0x64, 0xea, 0xe0, 0xbf, 0x02, 0xe5, 0x37, 0x2d, 0x31, 0x21, + 0xe8, 0xe3, 0x86, 0xc4, 0xcd, 0x70, 0x91, 0x00, 0xf8, 0x4b, 0x6f, 0xe6, 0x00, 0x06, 0x84, 0x1f, + 0x52, 0x00, 0x3a, 0x04, 0xb2, 0x30, 0xfc, 0x2f, 0x6a, 0x6e, 0x41, 0x28, 0x70, 0x71, 0xff, 0x4f, + 0x35, 0x51, 0x3e, 0xd8, 0xcc, 0xb1, 0xd9, 0x0d, 0x6a, 0xff, 0xd1, 0x3f, 0x94, 0x0a, 0x4b, 0x6f, + 0x0b, 0x4e, 0x5b, 0x1a, 0xab, 0xcf, 0x35, 0x9e, 0x0c, 0x70, 0xb2, 0xfa, 0xd6, 0xa3, 0x83, 0x30, + 0xbd, 0xe1, 0x58, 0x80, 0x87, 0x20, 0x7a, 0xef, 0xf8, 0x19, 0x70, 0x71, 0x33, 0x7e, 0x07, 0x3a, + 0x24, 0x80, 0x6e, 0x02, 0x78, 0x2b, 0xc4, 0xd2, 0x81, 0x48, 0xae, 0xe3, 0x7c, 0x25, 0x82, 0xdc, + 0x8b, 0xf8, 0x81, 0x63, 0xb9, 0x8d, 0xf8, 0x39, 0x43, 0x84, 0x34, 0x43, 0x2e, 0x2e, 0x7e, 0x07, + 0xde, 0x6f, 0x10, 0x91, 0xa1, 0xf7, 0xc7, 0x08, 0xd0, 0x3b, 0x2d, 0x38, 0x6d, 0xef, 0x83, 0xfa, + 0xcc, 0x8d, 0x4f, 0xab, 0xe1, 0xe2, 0x80, 0x6a, 0xc9, 0xbd, 0x88, 0x7f, 0x80, 0x1b, 0x55, 0xb8, + 0xf6, 0x65, 0xca, 0x3e, 0xa8, 0xde, 0x0a, 0x60, 0x65, 0x6c, 0xa0, 0x57, 0x39, 0x8d, 0x1a, 0x91, + 0xd1, 0xc6, 0x41, 0xe9, 0xc3, 0xaf, 0x94, 0xeb, 0x69, 0x02, 0xfc, 0xe6, 0xb2, 0x83, 0x3c, 0xb9, + 0x9c, 0x06, 0xe1, 0xbb, 0x84, 0xce, 0xd9, 0x80, 0xe1, 0x41, 0x1e, 0x7e, 0xa0, 0x01, 0x6e, 0x44, + 0x0d, 0xd8, 0xc3, 0x76, 0x7e, 0x70, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, + 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xfd, 0xcf, 0x24, 0xf8, + 0x7f, 0xf0, 0xcd, 0x1f, 0xc5, 0x98, 0xea, 0xec, 0xdc, 0xb1, 0x54, 0x7f, 0xbd, 0xeb, 0xc0, 0x3d, + 0x47, 0x55, 0x72, 0xc8, 0x30, 0x72, 0x6e, 0xff, 0x76, 0x41, 0x95, 0xed, 0xa7, 0x1e, 0xb6, 0xdb, + 0x5e, 0x71, 0xe8, 0x54, 0x0c, 0x31, 0x0a, 0x76, 0xb3, 0x6f, 0xb3, 0x63, 0x4c, 0x96, 0xcd, 0x52, + 0x8e, 0x93, 0xcb, 0x37, 0xca, 0x8a, 0x5d, 0x57, 0x24, 0x1d, 0xcb, 0x8a, 0x74, 0x85, 0x21, 0xdc, + 0x86, 0x97, 0x8e, 0xe8, 0xd0, 0xd0, 0x9a, 0x83, 0xc0, 0xf5, 0xa9, 0xa9, 0xe5, 0xb7, 0xa5, 0xba, + 0x03, 0x2f, 0x1a, 0xcf, 0xa7, 0x70, 0xcf, 0x2a, 0x33, 0x65, 0x0c, 0xea, 0x99, 0x29, 0xd9, 0xaa, + 0x57, 0x34, 0x3a, 0x83, 0x4f, 0x8c, 0xb1, 0x6c, 0x4f, 0xff, 0xa0, 0xf5, 0xf4, 0x4b, 0x4c, 0xbc, + 0x55, 0x5b, 0x50, 0xf7, 0x3a, 0x16, 0x9e, 0x58, 0xc7, 0x7f, 0xcd, 0xf0, 0x74, 0xce, 0xec, 0xbf, + 0x95, 0x1a, 0x4b, 0xe0, 0x3a, 0xf9, 0xd6, 0xb7, 0xcb, 0xe1, 0xd4, 0x54, 0x24, 0x95, 0xa1, 0xa8, + 0xba, 0x23, 0x96, 0xce, 0xd4, 0x82, 0xea, 0xde, 0x68, 0x2d, 0x36, 0x59, 0xa1, 0x2d, 0xee, 0xa1, + 0x5e, 0x98, 0x53, 0x54, 0x76, 0x60, 0x2c, 0xd8, 0x2c, 0x2f, 0xf4, 0x96, 0x1d, 0x44, 0xc9, 0x94, + 0x9a, 0x5a, 0x02, 0xc7, 0xec, 0x15, 0x5c, 0xa7, 0xda, 0x21, 0xf0, 0xe1, 0x5d, 0x66, 0xb0, 0x46, + 0x55, 0xb7, 0xc0, 0x75, 0xd5, 0x29, 0xff, 0x45, 0x4c, 0xce, 0xc0, 0xb3, 0x5b, 0x25, 0xdc, 0x20, + 0xdf, 0xca, 0x2e, 0x8c, 0x00, 0xe6, 0x01, 0x6e, 0x4d, 0x0d, 0xe9, 0x62, 0xdd, 0xf6, 0xaf, 0x3e, + 0x6f, 0x61, 0x72, 0xc9, 0x0f, 0x36, 0x77, 0xe6, 0x27, 0xa2, 0x1d, 0x37, 0x1d, 0x12, 0x70, 0x53, + 0xe7, 0x84, 0xd3, 0x7f, 0xde, 0xf1, 0xc9, 0x95, 0x1c, 0xaa, 0x94, 0x9b, 0x31, 0xdf, 0x80, 0x5a, + 0x96, 0xeb, 0x91, 0xca, 0x2a, 0x8a, 0x92, 0xb5, 0x91, 0x75, 0x33, 0x8d, 0xf1, 0x4a, 0xdb, 0x39, + 0x8b, 0x56, 0x22, 0x71, 0xb9, 0x84, 0x22, 0xc9, 0xfc, 0x0a, 0xc6, 0xb7, 0xaf, 0xfb, 0xa2, 0xb6, + 0x41, 0x17, 0xd1, 0xcc, 0xb0, 0x31, 0xaf, 0xfb, 0x50, 0xfb, 0xcd, 0xe4, 0x01, 0x6e, 0xc1, 0x72, + 0x91, 0x64, 0x39, 0xf7, 0x37, 0xce, 0x68, 0xec, 0xe1, 0xb5, 0xf8, 0x86, 0xcf, 0xd4, 0xcc, 0xbb, + 0x52, 0xd4, 0x60, 0x58, 0xaa, 0x6d, 0xec, 0x89, 0xb4, 0xff, 0x58, 0xd5, 0x17, 0x8d, 0xef, 0x89, + 0x46, 0xaf, 0x45, 0xce, 0x15, 0x14, 0xbc, 0x53, 0x47, 0x97, 0x54, 0x2a, 0xcb, 0x75, 0xdc, 0xe5, + 0x07, 0xfa, 0x4f, 0xaf, 0x61, 0x79, 0x6c, 0x41, 0x2b, 0x11, 0x5d, 0x4f, 0xb7, 0xee, 0x53, 0x0c, + 0x13, 0x4a, 0x2b, 0x92, 0xb0, 0x8c, 0x05, 0xb7, 0x97, 0x75, 0xa9, 0x2b, 0x2a, 0x58, 0x64, 0xc9, + 0xed, 0xd0, 0x45, 0x2a, 0x39, 0x65, 0x71, 0xeb, 0x53, 0xe4, 0xf2, 0x68, 0xb2, 0x4c, 0xe2, 0x6e, + 0x6d, 0xd5, 0xf1, 0xe9, 0xb2, 0xf7, 0x9c, 0x31, 0x2e, 0x68, 0x7f, 0x60, 0xa2, 0x4b, 0xe7, 0x6e, + 0xc6, 0x98, 0x2f, 0x55, 0xb7, 0x2e, 0x2e, 0x62, 0xdd, 0x53, 0xc6, 0x52, 0x39, 0x93, 0x19, 0xad, + 0x51, 0xf5, 0xc8, 0xf2, 0xe2, 0xc6, 0xee, 0xd4, 0x60, 0x2d, 0xd6, 0xed, 0xc8, 0xaa, 0xe9, 0x33, + 0x20, 0x45, 0xb1, 0xee, 0xd3, 0xda, 0x82, 0xad, 0xee, 0x58, 0xaa, 0xc5, 0x14, 0xbb, 0x16, 0xc7, + 0x70, 0xea, 0x78, 0xec, 0x7d, 0x35, 0xae, 0xff, 0xbc, 0xea, 0x8b, 0x87, 0x96, 0x3c, 0xff, 0x7e, + 0x4e, 0xac, 0xab, 0xe3, 0x39, 0x95, 0x8d, 0x14, 0x13, 0x41, 0x75, 0xe9, 0xf1, 0x9c, 0xa4, 0x8e, + 0xae, 0x16, 0x9c, 0xfe, 0xab, 0x6f, 0xdc, 0xa9, 0xd8, 0xcf, 0x40, 0x6d, 0x3f, 0xa9, 0x25, 0xab, + 0xf6, 0xac, 0x2e, 0x59, 0x27, 0x89, 0x52, 0xf9, 0xa5, 0x23, 0xf4, 0xc7, 0x9b, 0xee, 0xed, 0xd3, + 0x89, 0xc4, 0x2f, 0x8e, 0xac, 0xbd, 0x72, 0x4e, 0xbe, 0xbb, 0x88, 0x01, 0x33, 0x80, 0x0f, 0xd3, + 0x0e, 0xf0, 0xc6, 0x2f, 0xc9, 0x65, 0x60, 0x1a, 0xe8, 0x70, 0xd4, 0x58, 0xdb, 0x2e, 0x29, 0xb2, + 0x2a, 0x26, 0xec, 0x01, 0x6d, 0x01, 0x03, 0x94, 0xfb, 0xc0, 0x34, 0x88, 0x13, 0x46, 0x8d, 0x4e, + 0xcc, 0x58, 0xfc, 0xf9, 0x20, 0x56, 0x2c, 0xd0, 0x65, 0xa8, 0x5f, 0xf5, 0xa9, 0x6c, 0xa4, 0x6c, + 0xdb, 0x30, 0xb2, 0x16, 0x60, 0x47, 0x0c, 0xca, 0x73, 0x32, 0x8b, 0x19, 0x2b, 0x54, 0x18, 0xd7, + 0x96, 0x89, 0xd3, 0x05, 0xed, 0xa5, 0x3d, 0xbb, 0xa0, 0x5e, 0xdf, 0x20, 0xf0, 0x23, 0x78, 0x71, + 0x4c, 0xcc, 0xdd, 0x8a, 0xb1, 0x94, 0x1a, 0x6d, 0xcf, 0x1d, 0xd9, 0x89, 0x58, 0x37, 0xfb, 0xed, + 0x72, 0xa2, 0x7b, 0xbf, 0xb2, 0x6c, 0xa9, 0x6e, 0x9d, 0x5f, 0xc5, 0xba, 0x8b, 0x17, 0x7f, 0xbc, + 0xd1, 0x30, 0x8e, 0x68, 0xf9, 0x45, 0x38, 0xab, 0x03, 0xda, 0x67, 0xd4, 0x79, 0x26, 0x19, 0xe3, + 0x6f, 0x87, 0x09, 0xbd, 0x13, 0xe5, 0x27, 0xb6, 0xb2, 0x07, 0x69, 0xf5, 0x9c, 0xc7, 0xcb, 0xdb, + 0x1b, 0x25, 0x62, 0x76, 0x38, 0x09, 0x98, 0x7f, 0x15, 0x78, 0x4b, 0x74, 0x71, 0x69, 0x40, 0xb0, + 0x2f, 0xc7, 0xb6, 0x80, 0x63, 0xb9, 0xb7, 0xea, 0x58, 0x9e, 0x58, 0x0d, 0x9e, 0xae, 0x7f, 0xf5, + 0xee, 0x35, 0xa6, 0xea, 0xa3, 0x5c, 0x4e, 0x21, 0xe4, 0x4b, 0xd8, 0xf2, 0x78, 0x9e, 0x9d, 0xb0, + 0x05, 0xa7, 0x47, 0x1e, 0x71, 0x75, 0x11, 0x4e, 0x3f, 0x76, 0xe6, 0x04, 0x7d, 0x8f, 0x3f, 0xa5, + 0x56, 0x25, 0x71, 0x12, 0x5d, 0x52, 0xb9, 0x61, 0xfe, 0xd0, 0xb6, 0x50, 0x65, 0x23, 0x46, 0xa6, + 0xc4, 0x2a, 0x34, 0xb4, 0x0c, 0x1d, 0x96, 0x03, 0x61, 0xa2, 0x0a, 0xa2, 0x88, 0x26, 0xeb, 0x60, + 0xcf, 0xff, 0xe8, 0x1d, 0x9b, 0xb9, 0xb8, 0x8c, 0xed, 0x32, 0x84, 0xe7, 0xe8, 0x7c, 0x2a, 0xb2, + 0x0c, 0x8c, 0x30, 0x9c, 0x7e, 0xbe, 0xf5, 0x23, 0xf3, 0xb6, 0x66, 0x17, 0x78, 0x7c, 0x2e, 0x11, + 0xc8, 0x15, 0xfe, 0xa8, 0x54, 0xce, 0x84, 0xbc, 0x02, 0xa5, 0x2b, 0x14, 0xbd, 0x4e, 0x92, 0xa6, + 0x4a, 0xd9, 0x60, 0xfa, 0xb2, 0x94, 0xdf, 0xcd, 0x0c, 0x5e, 0xb0, 0xbb, 0xc0, 0xb0, 0xd9, 0xed, + 0x91, 0xc8, 0x32, 0xd8, 0x2c, 0xcf, 0xc5, 0x5e, 0x9c, 0xd6, 0xb2, 0x6f, 0x6c, 0x40, 0xe2, 0x63, + 0xbb, 0x99, 0xca, 0x42, 0xf7, 0x7f, 0xbc, 0x63, 0x7f, 0xda, 0xec, 0x93, 0x94, 0xde, 0x47, 0xf8, + 0xa9, 0x69, 0x6e, 0x59, 0x80, 0x7b, 0x0f, 0x32, 0xaf, 0xa2, 0xe4, 0x44, 0x23, 0x1b, 0xc1, 0x49, + 0x08, 0xa5, 0xcd, 0x04, 0xeb, 0x15, 0x6f, 0xfc, 0xa9, 0x72, 0xab, 0x4f, 0x54, 0x46, 0x94, 0xa3, + 0xfd, 0x2d, 0x38, 0x6d, 0xfc, 0xce, 0xdb, 0x71, 0x16, 0x3b, 0xab, 0x3b, 0x82, 0x82, 0xb8, 0xb1, + 0xcb, 0x58, 0x70, 0x9d, 0x78, 0xeb, 0xa4, 0xde, 0x7b, 0x06, 0xac, 0xf3, 0xc6, 0xae, 0xbd, 0x82, + 0x19, 0x81, 0x9d, 0xae, 0xa5, 0x2b, 0x31, 0x6a, 0xbe, 0xb0, 0x91, 0xb6, 0x68, 0x4c, 0xcc, 0x8e, + 0xe9, 0x2a, 0x79, 0x4e, 0x0e, 0x79, 0x92, 0xe5, 0xad, 0x53, 0x37, 0xf0, 0x0f, 0x58, 0xf1, 0xec, + 0xaa, 0x04, 0x6e, 0x15, 0x37, 0x2f, 0x7a, 0x3a, 0xe3, 0x85, 0xbf, 0x9e, 0x8e, 0x2e, 0x6c, 0x4e, + 0x3f, 0x5f, 0x9a, 0x5b, 0xab, 0x39, 0x82, 0x9a, 0x84, 0x45, 0x63, 0xbe, 0xa2, 0xc6, 0x66, 0x0e, + 0xab, 0x94, 0x20, 0xa6, 0xf2, 0xf0, 0xe2, 0xa2, 0xf5, 0xe0, 0xf3, 0x20, 0x06, 0xbf, 0x9c, 0x14, + 0xfd, 0xe7, 0x21, 0xc3, 0xcd, 0x6e, 0x9f, 0x9e, 0x76, 0xf3, 0x33, 0xdb, 0xd5, 0x8b, 0x9a, 0x78, + 0x56, 0xa1, 0xed, 0xdd, 0x2a, 0x10, 0xba, 0xa3, 0x4b, 0xca, 0x5c, 0xef, 0xbd, 0x72, 0x60, 0x89, + 0x8d, 0xe4, 0x0e, 0x3e, 0x97, 0xab, 0x55, 0x97, 0x4d, 0x79, 0x12, 0xab, 0x38, 0xde, 0x08, 0x08, + 0xca, 0xfd, 0xa6, 0x7b, 0xab, 0xa8, 0x62, 0x32, 0xfb, 0xc5, 0xc2, 0x39, 0x15, 0xb0, 0xa4, 0x99, + 0xa0, 0xbd, 0xa6, 0x26, 0x8a, 0x69, 0x7c, 0xb4, 0x50, 0x2d, 0x43, 0x93, 0xc4, 0x2c, 0xb3, 0x31, + 0x8a, 0x0a, 0x41, 0x1e, 0x64, 0x6a, 0xd5, 0xf2, 0x8e, 0xf9, 0x32, 0x36, 0xb6, 0x0f, 0x67, 0x5c, + 0x06, 0x8c, 0xc0, 0xa7, 0xd9, 0x33, 0xc0, 0x74, 0x6d, 0x9d, 0x13, 0x8f, 0xe7, 0xd9, 0x09, 0x5a, + 0x70, 0xfa, 0x45, 0xb8, 0xf1, 0x29, 0xf1, 0xc5, 0xd5, 0x9d, 0x49, 0xf3, 0xf2, 0x4f, 0x7a, 0x29, + 0x4c, 0xff, 0x90, 0x42, 0x0f, 0x76, 0x93, 0x49, 0x32, 0xd0, 0xc2, 0x5a, 0x5d, 0xe7, 0x79, 0x86, + 0x82, 0x2f, 0xcf, 0xe6, 0x14, 0x88, 0x51, 0x21, 0xa1, 0xb5, 0xfd, 0x7d, 0xe6, 0x4f, 0xd8, 0xb3, + 0x75, 0x2a, 0x84, 0xbf, 0x72, 0xc4, 0x56, 0xce, 0x28, 0x0d, 0x97, 0x1d, 0x67, 0x9e, 0xf7, 0x74, + 0xea, 0xe3, 0x4f, 0xa4, 0xf6, 0xdf, 0xd9, 0x84, 0x3e, 0xe1, 0x4a, 0x29, 0xad, 0xad, 0x38, 0xec, + 0xd6, 0x8b, 0xd8, 0x7f, 0x0c, 0xd0, 0xae, 0xd5, 0x81, 0x79, 0xdf, 0x8a, 0x37, 0xfe, 0x67, 0x09, + 0x48, 0x5c, 0x8a, 0xe7, 0x4f, 0xe7, 0x0e, 0xac, 0xb6, 0xfc, 0xc6, 0x36, 0x03, 0xad, 0xf3, 0xee, + 0x98, 0x3a, 0x61, 0x49, 0x0f, 0x72, 0x8b, 0x5e, 0xe8, 0x72, 0x65, 0xfb, 0x8f, 0xe8, 0x92, 0xff, + 0xf2, 0x90, 0x9e, 0xca, 0x4e, 0x54, 0xcb, 0xc5, 0x4a, 0xc9, 0xa0, 0x22, 0xb1, 0xc2, 0x31, 0x59, + 0x2c, 0x16, 0xb2, 0xbb, 0x19, 0xc7, 0x28, 0x55, 0xb3, 0x3f, 0xae, 0x61, 0x0e, 0x3e, 0x72, 0x0b, + 0x4e, 0x5b, 0x1e, 0x98, 0xe3, 0x35, 0x32, 0xba, 0x90, 0xa5, 0xa8, 0x28, 0x00, 0x5a, 0x54, 0x7d, + 0xc1, 0x20, 0x67, 0x2c, 0x98, 0x61, 0x8d, 0x24, 0x00, 0x50, 0xa1, 0x71, 0xdc, 0xa0, 0x62, 0x2a, + 0x6a, 0x23, 0xf8, 0x9e, 0x75, 0x00, 0x54, 0x42, 0x97, 0x6f, 0xba, 0x81, 0xe5, 0xb4, 0x77, 0x57, + 0x22, 0x51, 0x5b, 0x3d, 0x62, 0xbd, 0x8a, 0xf1, 0x53, 0x24, 0xe0, 0x8c, 0x79, 0xfa, 0xe9, 0x55, + 0x3a, 0x24, 0x37, 0x33, 0x10, 0x7d, 0x22, 0xbf, 0x9f, 0x18, 0x59, 0x40, 0xb5, 0x36, 0x15, 0x72, + 0xcd, 0xf3, 0x91, 0x19, 0xd7, 0x48, 0xaf, 0x5c, 0xe1, 0xd2, 0xaa, 0x7b, 0x91, 0x03, 0x42, 0x28, + 0xd2, 0xc3, 0xb5, 0x3e, 0xf4, 0x01, 0xdf, 0xea, 0xd9, 0x90, 0xcb, 0x42, 0x5f, 0xa7, 0x19, 0x7b, + 0xbc, 0x12, 0x99, 0x93, 0x80, 0x69, 0xf7, 0x16, 0x0d, 0x82, 0x3b, 0xdc, 0xaf, 0xc9, 0x63, 0xd0, + 0xab, 0x9f, 0xa7, 0xd6, 0xcf, 0x29, 0xe8, 0xf8, 0x28, 0x91, 0xc8, 0x1f, 0x58, 0xbd, 0x9a, 0xfa, + 0xfa, 0xc7, 0xf0, 0xa4, 0x6b, 0x1d, 0xb8, 0x15, 0x07, 0xb1, 0x9e, 0x88, 0x17, 0x26, 0xe7, 0xd9, + 0xdd, 0x74, 0x56, 0x97, 0x9a, 0x0a, 0x44, 0xe7, 0x62, 0x5c, 0x12, 0x77, 0x99, 0xc1, 0xd6, 0xab, + 0x6b, 0xd8, 0xe7, 0x4f, 0x6b, 0x71, 0xd1, 0x3c, 0x00, 0x87, 0xe6, 0xeb, 0x19, 0x8d, 0x7d, 0x5c, + 0x7a, 0xfe, 0x13, 0x6b, 0x0d, 0x98, 0x67, 0x74, 0x1d, 0x7c, 0x70, 0xf6, 0x1f, 0x5e, 0x89, 0x84, + 0xee, 0x10, 0x4a, 0x14, 0xae, 0x0e, 0xeb, 0x7a, 0x60, 0xfe, 0x89, 0x35, 0x57, 0x94, 0x2d, 0x38, + 0xcd, 0xb9, 0xe6, 0x8d, 0xab, 0x72, 0x50, 0x95, 0xe8, 0x26, 0x32, 0xb5, 0x3c, 0x70, 0x68, 0xd8, + 0x48, 0x65, 0x7b, 0xdc, 0x3e, 0x44, 0x94, 0x0c, 0xeb, 0x99, 0x35, 0xe0, 0xad, 0x2a, 0x15, 0xe0, + 0x1c, 0x52, 0x1b, 0xc1, 0x31, 0x75, 0xc3, 0xf7, 0x94, 0xb7, 0xbe, 0x5e, 0x50, 0x55, 0xe0, 0x1b, + 0x73, 0x65, 0x60, 0x9d, 0x53, 0xe7, 0x0e, 0xa0, 0x5c, 0xbb, 0xdb, 0x38, 0x66, 0x2c, 0x17, 0x4f, + 0xb3, 0x63, 0x49, 0x08, 0x09, 0x39, 0x97, 0x15, 0x24, 0x8d, 0x0b, 0x3a, 0x02, 0x2f, 0xaa, 0x0a, + 0xeb, 0xc7, 0xf6, 0x05, 0x83, 0x92, 0x5e, 0xc6, 0x46, 0xca, 0x54, 0x7d, 0x68, 0x12, 0xe0, 0xdf, + 0xd1, 0x98, 0x6a, 0x27, 0xca, 0x26, 0xab, 0x53, 0xcb, 0x51, 0xc5, 0x18, 0x76, 0x72, 0x45, 0x81, + 0x47, 0xbe, 0x4d, 0xec, 0x9e, 0x5e, 0xfc, 0xd1, 0x5b, 0x9d, 0x1a, 0xbd, 0x88, 0xd9, 0x3f, 0x2c, + 0x27, 0xb2, 0xbd, 0x6c, 0x25, 0x6d, 0x50, 0x55, 0x31, 0x2c, 0x5d, 0x27, 0x8c, 0x0a, 0x86, 0x05, + 0xb2, 0x95, 0x6c, 0xf4, 0xe0, 0xf1, 0x26, 0x77, 0xb6, 0xff, 0xb5, 0xc6, 0xb9, 0xca, 0x8d, 0x32, + 0x5e, 0x9f, 0x48, 0xff, 0xc8, 0x1c, 0x5e, 0xd0, 0xab, 0xb9, 0x23, 0xd8, 0xa1, 0x6c, 0xb7, 0xfd, + 0x04, 0x18, 0x89, 0xfd, 0x6f, 0x17, 0x69, 0x80, 0x83, 0x47, 0xa1, 0x05, 0x2d, 0x8d, 0x01, 0x40, + 0xe3, 0x36, 0x65, 0x32, 0x97, 0x69, 0xea, 0x32, 0x5a, 0x7f, 0x6c, 0xa7, 0x73, 0x9a, 0x16, 0x9c, + 0x6e, 0xcc, 0x96, 0xbd, 0x55, 0x51, 0xb5, 0x02, 0xfd, 0x68, 0xb7, 0xcf, 0x4d, 0x7f, 0xec, 0xeb, + 0x26, 0x42, 0xb3, 0x9c, 0xee, 0xf2, 0x6f, 0x52, 0x73, 0x38, 0x73, 0x81, 0x09, 0x66, 0x4e, 0xea, + 0xaf, 0xc5, 0x33, 0xcc, 0x1f, 0x6f, 0x2c, 0xe9, 0xd3, 0x34, 0x87, 0xb6, 0xab, 0xb5, 0xf2, 0x58, + 0xcc, 0xf6, 0x43, 0x6f, 0x07, 0xd0, 0xbb, 0xee, 0x25, 0x83, 0x7b, 0x8a, 0x3d, 0x99, 0xcb, 0x14, + 0x5d, 0x9e, 0x1a, 0xad, 0xc5, 0x5e, 0x4c, 0xe1, 0xf8, 0x08, 0x78, 0x45, 0x0c, 0x02, 0xf7, 0x1a, + 0x75, 0x06, 0xa3, 0x99, 0x97, 0x0c, 0x01, 0x91, 0x3f, 0x38, 0x06, 0xf8, 0x31, 0x1a, 0x13, 0x33, + 0x46, 0xa0, 0x69, 0x74, 0xe8, 0xf2, 0x75, 0x12, 0x5c, 0x3c, 0x9c, 0x02, 0x72, 0x02, 0x9c, 0x49, + 0x56, 0x57, 0x04, 0xa8, 0x06, 0x46, 0x38, 0x83, 0x97, 0xaf, 0x77, 0x99, 0x77, 0x50, 0xba, 0x97, + 0x3d, 0xdc, 0x57, 0x02, 0x7c, 0x3b, 0x01, 0xbe, 0x7b, 0x92, 0xcb, 0x06, 0x5b, 0x5c, 0x7d, 0x52, + 0xfb, 0x84, 0xd7, 0xf3, 0x93, 0x1b, 0x79, 0x35, 0x77, 0x77, 0x1f, 0x68, 0xe9, 0xc5, 0xe3, 0xbc, + 0x15, 0xa2, 0xa3, 0x05, 0xa7, 0x7d, 0xe2, 0x05, 0x5a, 0x2b, 0x10, 0x8e, 0x2f, 0xae, 0x46, 0xf9, + 0xf1, 0xbb, 0x39, 0x82, 0x96, 0x3e, 0x19, 0x97, 0x2f, 0xb1, 0x74, 0x05, 0x1c, 0x01, 0xe8, 0xdb, + 0x15, 0x31, 0xd8, 0x94, 0xd5, 0xee, 0xd3, 0x4c, 0x23, 0xb8, 0x01, 0xc6, 0x04, 0xc6, 0x35, 0x8e, + 0xc2, 0x55, 0x2a, 0x19, 0xfe, 0x76, 0x11, 0x8b, 0x38, 0xec, 0xba, 0x43, 0x86, 0x19, 0x87, 0x0e, + 0xa3, 0x52, 0x2c, 0x0a, 0xc2, 0xa5, 0xf7, 0xd5, 0xc4, 0xee, 0x58, 0x3a, 0x5d, 0x0e, 0xe7, 0xfe, + 0xb1, 0xba, 0x17, 0x9f, 0xc0, 0xd4, 0x02, 0xc2, 0x79, 0xb8, 0xba, 0x73, 0xe2, 0xf7, 0x61, 0xbe, + 0xdb, 0xcc, 0x2a, 0x73, 0x78, 0x34, 0x65, 0x4d, 0xa3, 0xb6, 0x41, 0x85, 0xeb, 0x60, 0xd5, 0xbb, + 0x2f, 0x5a, 0xfa, 0xe4, 0x2d, 0x9e, 0xea, 0x5c, 0xc3, 0x0e, 0xf9, 0x5c, 0xce, 0x26, 0x47, 0x96, + 0x75, 0xec, 0x2b, 0x32, 0x1b, 0x01, 0x41, 0x61, 0x16, 0x62, 0x99, 0x25, 0x88, 0x33, 0x2b, 0x6e, + 0xf0, 0x70, 0xce, 0x63, 0xc3, 0x28, 0x8a, 0xe6, 0x7e, 0xfd, 0x88, 0x39, 0x5e, 0xd6, 0x1d, 0x67, + 0x32, 0xef, 0x2f, 0xc0, 0xc7, 0xc8, 0xc2, 0x50, 0x15, 0x7c, 0x52, 0x80, 0xca, 0xbf, 0x64, 0x76, + 0x81, 0xa1, 0x7c, 0xa3, 0xdc, 0xcf, 0xd4, 0x92, 0x50, 0xf5, 0x93, 0xf5, 0x08, 0x40, 0xb5, 0xb6, + 0x5a, 0x24, 0xa8, 0x06, 0x48, 0x12, 0xc6, 0xb5, 0x92, 0xc7, 0xeb, 0x53, 0xa0, 0xda, 0x16, 0x9c, + 0xc6, 0x35, 0x9a, 0x06, 0x6b, 0x05, 0x99, 0x7d, 0x33, 0xe8, 0xb0, 0x58, 0x82, 0xc9, 0xce, 0x6d, + 0x7a, 0x1c, 0x98, 0x5e, 0x29, 0xfd, 0x6c, 0x6b, 0xe0, 0x83, 0xa1, 0x50, 0x4c, 0x32, 0xc1, 0x2f, + 0x09, 0x0d, 0x7d, 0x59, 0x4c, 0x50, 0xd1, 0x13, 0xc0, 0xe9, 0xf0, 0xa9, 0x1b, 0x78, 0xef, 0x1f, + 0x7e, 0xbb, 0x4f, 0x97, 0xa0, 0xaf, 0x20, 0xe6, 0x38, 0x23, 0xc3, 0x50, 0xde, 0x4a, 0x9e, 0x42, + 0xd5, 0x71, 0x8a, 0xf7, 0x96, 0x3f, 0x00, 0x37, 0x06, 0x8d, 0x53, 0xa5, 0xf6, 0x61, 0x10, 0x4a, + 0xb2, 0xbf, 0x0e, 0x42, 0x9f, 0xa1, 0x39, 0xaa, 0x1c, 0xfe, 0xca, 0xb9, 0x06, 0x10, 0xa1, 0x53, + 0xe6, 0x4b, 0xb5, 0x8a, 0xc1, 0xbe, 0xc6, 0xa0, 0xfc, 0x1e, 0x32, 0x3b, 0x8e, 0xd2, 0x61, 0x66, + 0xaa, 0x84, 0xab, 0x76, 0x33, 0x63, 0x13, 0xc7, 0x74, 0xa6, 0x58, 0x28, 0xac, 0x57, 0x2d, 0x0a, + 0x00, 0x9a, 0x4e, 0xfe, 0x78, 0xb3, 0x7b, 0x5a, 0xd4, 0x83, 0x98, 0x3e, 0xba, 0xc4, 0xae, 0xd1, + 0xb8, 0xc1, 0xf0, 0x8a, 0x7e, 0x0f, 0xc0, 0x3c, 0xd0, 0x02, 0xb5, 0x00, 0x7e, 0xa0, 0x33, 0x62, + 0x69, 0x01, 0xa8, 0x74, 0xa8, 0xae, 0xb6, 0x3b, 0x39, 0xbc, 0xb7, 0x54, 0x7f, 0x23, 0xa8, 0x35, + 0x42, 0x4b, 0x68, 0xab, 0x7e, 0xff, 0x96, 0x03, 0xbf, 0x14, 0xe5, 0x57, 0xdb, 0xe1, 0x2f, 0x59, + 0xb1, 0xfc, 0xfd, 0xf9, 0x21, 0x15, 0x5c, 0xba, 0x58, 0xe3, 0x8b, 0xd6, 0x03, 0x5e, 0x7e, 0x3c, + 0xf8, 0x18, 0x7b, 0xb8, 0x46, 0x5a, 0x70, 0x7a, 0xf3, 0x5e, 0xe6, 0x2d, 0xf1, 0xd0, 0x1b, 0xf4, + 0x49, 0x13, 0x5a, 0xd3, 0x64, 0xd5, 0xb0, 0xac, 0x53, 0xd3, 0xd6, 0xab, 0x8d, 0xd4, 0x0e, 0xee, + 0xc9, 0xef, 0x66, 0x2d, 0x1a, 0x00, 0xf0, 0x96, 0xb1, 0xb1, 0x97, 0xc4, 0x72, 0x20, 0x09, 0x20, + 0xbe, 0xa7, 0x04, 0x71, 0x1c, 0xaf, 0x20, 0x5a, 0xf2, 0xaf, 0x3d, 0x85, 0x2e, 0xee, 0x41, 0x73, + 0x0f, 0x4f, 0x64, 0xbe, 0xf7, 0x0c, 0xb1, 0x5c, 0xf7, 0xb1, 0x04, 0x04, 0x9a, 0xae, 0xfd, 0x1c, + 0x8a, 0x74, 0x6e, 0xfe, 0xfc, 0x2e, 0x15, 0xe9, 0x17, 0x99, 0x81, 0x47, 0xc4, 0x44, 0xd3, 0x9f, + 0xa8, 0xb1, 0x53, 0xe6, 0x6a, 0xa3, 0x42, 0xe2, 0xd8, 0x59, 0xd9, 0x61, 0x54, 0x25, 0x54, 0xe4, + 0xe5, 0xc2, 0x58, 0x8a, 0xaa, 0xa7, 0x87, 0x34, 0xc4, 0x25, 0x3b, 0xf2, 0x23, 0x91, 0x26, 0xef, + 0x53, 0x78, 0x4e, 0xd9, 0x58, 0xa7, 0x0b, 0xe6, 0x5d, 0xae, 0x11, 0x60, 0xc3, 0x2d, 0xcc, 0x05, + 0x42, 0x50, 0x18, 0x78, 0xbe, 0x87, 0xde, 0x08, 0x84, 0x6b, 0x40, 0x9c, 0x2f, 0xc0, 0x31, 0x60, + 0xce, 0xba, 0x9b, 0x5e, 0xa1, 0xfe, 0x9a, 0xb1, 0x0f, 0x26, 0xd0, 0xa3, 0xc9, 0x60, 0xc7, 0xe3, + 0x75, 0x84, 0x8c, 0x2d, 0x38, 0xbd, 0x1b, 0x2c, 0x65, 0x55, 0xe5, 0x17, 0xdb, 0x61, 0x60, 0xd5, + 0xc0, 0xeb, 0x80, 0x0d, 0x01, 0x6c, 0x63, 0x0b, 0xb7, 0xd3, 0xd8, 0xfc, 0x88, 0x39, 0x06, 0x61, + 0x1a, 0x44, 0xe5, 0xdf, 0x2e, 0xb5, 0x70, 0xa5, 0x33, 0x5b, 0xc5, 0x91, 0x2d, 0x02, 0x4b, 0x1c, + 0xfa, 0xe3, 0x35, 0x81, 0x8f, 0x3b, 0x0c, 0xaa, 0x1a, 0x80, 0x31, 0xe7, 0x60, 0x57, 0x95, 0xd9, + 0x79, 0xf7, 0x87, 0x8e, 0xa0, 0x0c, 0xaa, 0xb3, 0xa6, 0x39, 0xb6, 0xe0, 0x06, 0xb8, 0x19, 0xde, + 0x85, 0xea, 0x5d, 0x98, 0x1c, 0xcc, 0xb3, 0x49, 0x12, 0xf7, 0xe4, 0x9a, 0xe6, 0x67, 0xde, 0xdf, + 0x34, 0xb8, 0x00, 0xd5, 0xa0, 0xf7, 0x1f, 0xd9, 0x35, 0x00, 0xd3, 0x53, 0xb8, 0x54, 0x60, 0x61, + 0x3f, 0xea, 0x9e, 0x14, 0x2f, 0xe4, 0x3f, 0xe6, 0xaa, 0x1f, 0x96, 0x27, 0x32, 0x97, 0x11, 0x20, + 0xab, 0x6a, 0x07, 0x17, 0x69, 0x3a, 0xd6, 0xeb, 0x2a, 0x12, 0xf7, 0x1f, 0x35, 0x06, 0x71, 0x8a, + 0x20, 0xf8, 0x82, 0x91, 0x44, 0xe3, 0x7d, 0xab, 0xe1, 0xec, 0x12, 0x55, 0x05, 0xf1, 0xe5, 0xa1, + 0xd2, 0x1a, 0x9d, 0xa8, 0xd6, 0x2a, 0x86, 0xa0, 0x1d, 0x01, 0xc6, 0xb3, 0xae, 0xb0, 0xa7, 0x1f, + 0xe7, 0xad, 0x20, 0x3d, 0x2d, 0x38, 0x1d, 0x5d, 0x27, 0x09, 0xca, 0xae, 0x8c, 0x00, 0xdb, 0x63, + 0xa9, 0x8c, 0xab, 0x01, 0xb6, 0x0b, 0xc7, 0x46, 0xca, 0xc5, 0x8b, 0xcb, 0x7c, 0xf7, 0xe9, 0x09, + 0x00, 0x25, 0x69, 0x63, 0x3e, 0x57, 0xdd, 0x01, 0x36, 0x39, 0xb3, 0x83, 0xe3, 0xc5, 0x20, 0x74, + 0x45, 0xe5, 0xb2, 0xa9, 0x96, 0x84, 0xb6, 0x0c, 0x84, 0xcb, 0xef, 0x80, 0x05, 0x20, 0x2b, 0xb8, + 0x5a, 0x4d, 0x4f, 0x0c, 0x6e, 0x50, 0xd8, 0xa9, 0x7b, 0x24, 0x2e, 0x9a, 0x5e, 0xf5, 0x02, 0xbc, + 0x07, 0xde, 0xfd, 0x0e, 0x20, 0x97, 0xe5, 0x7e, 0x1a, 0x90, 0xfc, 0x06, 0x07, 0x9c, 0xfe, 0xaa, + 0xbd, 0x59, 0x41, 0x3b, 0x06, 0xe5, 0x07, 0x44, 0xdf, 0xda, 0xa0, 0x47, 0xab, 0x54, 0x20, 0xee, + 0x7f, 0xe0, 0x3f, 0xc7, 0xcf, 0x83, 0xaf, 0x7c, 0xbe, 0xa5, 0xe2, 0xc4, 0x76, 0x60, 0x08, 0xb5, + 0xf5, 0x5d, 0x23, 0x3f, 0x7e, 0x7c, 0xd2, 0x6e, 0xa3, 0xee, 0xa8, 0xcc, 0x4d, 0x96, 0xb5, 0x48, + 0x35, 0xdb, 0xd4, 0xa0, 0xc2, 0x1d, 0x35, 0xa2, 0x89, 0x73, 0xf9, 0x56, 0x68, 0x19, 0x9c, 0x98, + 0xf6, 0xdc, 0x3a, 0x7a, 0xe0, 0xdf, 0x68, 0x37, 0xcc, 0xce, 0xc1, 0x85, 0x40, 0x08, 0x02, 0xb4, + 0x55, 0x33, 0xb4, 0x00, 0x6d, 0x95, 0x2d, 0xb2, 0x0b, 0x63, 0xfa, 0x31, 0xf6, 0xf0, 0x0c, 0xc8, + 0x74, 0x09, 0x18, 0xb6, 0xe2, 0xf1, 0x8d, 0xb4, 0xcd, 0x3c, 0xc6, 0xd3, 0x39, 0x4b, 0x0b, 0x4e, + 0xf3, 0xd7, 0x02, 0x96, 0xb7, 0x89, 0x1e, 0x6a, 0x4c, 0xc3, 0x54, 0xd2, 0x63, 0x6a, 0xb0, 0xb1, + 0x00, 0x99, 0xde, 0xff, 0x06, 0x6c, 0x99, 0x23, 0xec, 0x2f, 0x02, 0x57, 0x8f, 0xbf, 0x11, 0x33, + 0x3f, 0x92, 0xfa, 0x04, 0xa0, 0x79, 0x2f, 0x15, 0xc5, 0x74, 0x0a, 0xd2, 0xbe, 0x00, 0x50, 0x39, + 0x01, 0x10, 0xc2, 0x31, 0x81, 0x19, 0x54, 0x3b, 0x41, 0x53, 0xb5, 0xb6, 0x3b, 0x01, 0x87, 0x80, + 0xe0, 0x40, 0xe8, 0x71, 0x24, 0xa6, 0x86, 0x23, 0x42, 0x40, 0x98, 0xaa, 0x7f, 0x4c, 0x80, 0x38, + 0x3a, 0x92, 0x2c, 0x3b, 0x40, 0x18, 0x2c, 0x12, 0x01, 0x3b, 0xc2, 0x17, 0xfd, 0xc9, 0x98, 0x8f, + 0x4b, 0x28, 0xb9, 0x67, 0x9c, 0xa0, 0x88, 0x13, 0xc0, 0xa9, 0x83, 0xf0, 0xaa, 0x4f, 0x72, 0x8c, + 0xf9, 0xe2, 0x93, 0x4b, 0x1e, 0xb4, 0x64, 0x77, 0x69, 0xe1, 0x7a, 0x01, 0xc0, 0xcd, 0x2a, 0x46, + 0x3d, 0xd1, 0xb5, 0xfe, 0xa5, 0x28, 0x8f, 0x2f, 0x72, 0x7d, 0x4a, 0xab, 0xad, 0xfb, 0xaf, 0xfa, + 0xed, 0xae, 0xa7, 0x74, 0x18, 0xc4, 0x0f, 0x55, 0x07, 0xe7, 0x92, 0x80, 0x97, 0x94, 0x57, 0x38, + 0x54, 0x50, 0x5c, 0x06, 0x9f, 0x00, 0xc4, 0x97, 0x14, 0xbe, 0xfc, 0x58, 0xa6, 0x69, 0x5b, 0x0b, + 0x4e, 0x77, 0xc1, 0x41, 0x23, 0xaa, 0x1c, 0x1b, 0x52, 0x2b, 0x94, 0xcc, 0xb2, 0xae, 0x90, 0xa2, + 0x29, 0xdf, 0x31, 0xb1, 0x01, 0x1d, 0x1f, 0x0d, 0x87, 0x6c, 0x88, 0xe2, 0x5b, 0xf8, 0x3c, 0x8d, + 0x62, 0x90, 0x19, 0xbd, 0x04, 0x41, 0x12, 0x1e, 0x28, 0x06, 0x8b, 0x75, 0xe0, 0x9e, 0xa6, 0x26, + 0x2f, 0x8a, 0xeb, 0x45, 0xf0, 0xf8, 0xdd, 0xea, 0xbb, 0xab, 0xd8, 0x6e, 0xb1, 0xec, 0xd9, 0x80, + 0x7d, 0x18, 0x5a, 0xdb, 0x3a, 0xbe, 0x8a, 0x69, 0x32, 0x43, 0xef, 0x63, 0x62, 0x7a, 0xd9, 0xb4, + 0x51, 0x2e, 0x5e, 0xce, 0x17, 0xd6, 0x83, 0x30, 0x51, 0x8c, 0xc1, 0x00, 0x08, 0xa3, 0x26, 0xd4, + 0x0c, 0x4d, 0x1b, 0x15, 0x89, 0x57, 0xdb, 0xb5, 0x52, 0x56, 0x9c, 0x30, 0xaa, 0x8d, 0x57, 0x53, + 0x85, 0xf3, 0x73, 0x2a, 0x3d, 0x08, 0x15, 0x25, 0x3b, 0x07, 0x36, 0x95, 0xf7, 0x79, 0x05, 0x63, + 0xcc, 0x33, 0x70, 0x04, 0x37, 0x79, 0xce, 0x98, 0x6a, 0x2c, 0x70, 0x08, 0x45, 0x66, 0xbd, 0x16, + 0x19, 0x1b, 0xde, 0xdd, 0xfa, 0x76, 0xb1, 0xb1, 0x0b, 0x80, 0x65, 0x6a, 0x37, 0x3e, 0x0a, 0xc7, + 0x72, 0xed, 0x0a, 0x7e, 0x58, 0x1e, 0x2d, 0x14, 0xd7, 0x1d, 0x73, 0x8b, 0xf9, 0x64, 0xc0, 0x08, + 0xad, 0x60, 0x08, 0x80, 0xe0, 0xed, 0x60, 0x67, 0x61, 0x2f, 0xb4, 0xbe, 0x82, 0xf1, 0xcd, 0xd0, + 0xc9, 0x71, 0x19, 0x62, 0x33, 0x20, 0x74, 0xd8, 0xdd, 0x19, 0x0e, 0x9a, 0x7c, 0x92, 0xa8, 0xbe, + 0x4a, 0x05, 0x01, 0xdf, 0xd4, 0x6a, 0x88, 0xa6, 0x8a, 0x65, 0x4d, 0xa2, 0xc7, 0x71, 0x6d, 0x2e, + 0x1a, 0x2c, 0xe1, 0x0c, 0x87, 0x63, 0x39, 0x72, 0x54, 0xff, 0x80, 0x8f, 0x1e, 0xa6, 0x76, 0xfe, + 0xe2, 0x7a, 0x6f, 0x34, 0xf2, 0x24, 0xa7, 0x13, 0x3d, 0x77, 0x7d, 0x8a, 0x79, 0xf6, 0xa1, 0xfe, + 0xdd, 0x8c, 0xa4, 0xb8, 0x6c, 0xcd, 0x91, 0x88, 0xe9, 0x20, 0xdf, 0xbb, 0x8b, 0xb8, 0xfa, 0x9b, + 0x27, 0x48, 0x0f, 0x39, 0x86, 0xbc, 0x73, 0x35, 0x57, 0xc1, 0x01, 0xc2, 0xd4, 0x19, 0x57, 0xdf, + 0x05, 0xdf, 0x37, 0x42, 0xd7, 0xa3, 0x1f, 0x73, 0xdd, 0xaa, 0xb7, 0xcb, 0xa5, 0x57, 0x22, 0xa8, + 0xeb, 0xb5, 0x52, 0x7a, 0xd2, 0xf0, 0x33, 0xc9, 0xaa, 0xa3, 0xac, 0x06, 0xa8, 0x7c, 0x14, 0x84, + 0x43, 0xf6, 0xca, 0xe8, 0x21, 0xb3, 0x05, 0xd1, 0xd6, 0x8e, 0xec, 0x07, 0x74, 0x89, 0x70, 0xbf, + 0x69, 0x78, 0xb0, 0x06, 0x16, 0x87, 0xec, 0x76, 0x10, 0x0d, 0x68, 0x9e, 0x04, 0xbe, 0xa0, 0xc6, + 0x76, 0x03, 0x8c, 0xcd, 0x0a, 0xf6, 0x2b, 0xee, 0x37, 0x4a, 0x38, 0xcc, 0x78, 0x4e, 0x12, 0x7e, + 0x6e, 0x88, 0xe7, 0x30, 0x05, 0x1c, 0xc2, 0x08, 0xfc, 0x45, 0x9d, 0xb1, 0xb0, 0x1b, 0x0e, 0x3f, + 0x64, 0xfc, 0xd7, 0x5a, 0x51, 0xfc, 0x50, 0xe2, 0xeb, 0x8f, 0x57, 0xb7, 0xe9, 0xf1, 0xb6, 0x90, + 0xe9, 0x01, 0x70, 0xdb, 0xf7, 0xb5, 0x81, 0x14, 0x59, 0x5a, 0xdf, 0xb1, 0x2f, 0x47, 0x4a, 0xb7, + 0x7d, 0xd5, 0xcf, 0xac, 0x1e, 0x09, 0x0c, 0xd2, 0x07, 0x2c, 0x7b, 0x6a, 0xe8, 0x81, 0x76, 0x75, + 0x01, 0x28, 0x4c, 0x5b, 0x10, 0x0b, 0x1b, 0x1b, 0x0b, 0x9d, 0x14, 0xd6, 0xa3, 0x5b, 0xbe, 0xc2, + 0x79, 0xae, 0x06, 0x85, 0xe4, 0x29, 0xf3, 0x49, 0x13, 0x0a, 0xa4, 0xa4, 0x06, 0x21, 0x75, 0x1f, + 0x5b, 0x2d, 0xfa, 0x72, 0x75, 0xc2, 0xa2, 0x51, 0x28, 0xb6, 0xc7, 0xd4, 0xb5, 0x17, 0xfb, 0xc7, + 0x17, 0x95, 0xea, 0x54, 0x6d, 0xbd, 0x40, 0x56, 0x8d, 0xba, 0x98, 0x2a, 0x03, 0x38, 0x53, 0x76, + 0xe0, 0xd1, 0x84, 0x2a, 0x11, 0x59, 0x84, 0x83, 0x9e, 0x46, 0x03, 0x42, 0x66, 0x3d, 0x6c, 0x86, + 0x79, 0x07, 0xde, 0x73, 0x1b, 0xff, 0x00, 0xd7, 0x89, 0x0a, 0xa0, 0x3e, 0xb3, 0xeb, 0x1f, 0x81, + 0xc9, 0xea, 0x6f, 0x57, 0x54, 0x9f, 0x94, 0xa9, 0x15, 0x21, 0x7f, 0x13, 0x13, 0x69, 0xf0, 0x78, + 0xa6, 0xf2, 0xf9, 0x0a, 0xa8, 0xd6, 0xa7, 0xcb, 0xa1, 0x24, 0x40, 0xf9, 0xc3, 0xa4, 0x03, 0x9f, + 0x3b, 0xaa, 0xef, 0xe0, 0x94, 0xa2, 0x17, 0x04, 0xa3, 0x6f, 0x76, 0xc3, 0xe7, 0x57, 0xd4, 0x8f, + 0x39, 0xff, 0xc7, 0x6b, 0xcd, 0x22, 0x1d, 0x78, 0x0b, 0x4e, 0xbf, 0xea, 0x3f, 0x51, 0xb8, 0xb4, + 0x4f, 0xf0, 0x83, 0xf7, 0x00, 0xfe, 0xc1, 0xb1, 0x9c, 0xe7, 0x74, 0x64, 0x6c, 0x61, 0xa3, 0x30, + 0xf9, 0x76, 0x05, 0x1b, 0xef, 0x47, 0x68, 0xed, 0xa0, 0x54, 0xee, 0xc2, 0xf4, 0x85, 0xfd, 0x67, + 0xc3, 0x6a, 0x92, 0x48, 0x77, 0x9c, 0xed, 0xbd, 0x23, 0xd7, 0x8a, 0xe3, 0xcc, 0xc2, 0x1a, 0x5c, + 0xc0, 0xf6, 0xa9, 0xd5, 0x68, 0x1a, 0xf0, 0x4a, 0x2c, 0xd6, 0xd2, 0x5a, 0x05, 0xb0, 0xa1, 0x7d, + 0xdd, 0x40, 0x52, 0xb8, 0x77, 0x4a, 0xed, 0x42, 0xc3, 0x71, 0x66, 0xbf, 0xf3, 0x6d, 0xfe, 0x1d, + 0xe0, 0xa6, 0x4c, 0x4c, 0x4c, 0xe5, 0xbb, 0x01, 0x0c, 0xcf, 0xf7, 0x12, 0xd9, 0x44, 0x96, 0x80, + 0x2b, 0xaa, 0xa6, 0x18, 0x07, 0x56, 0xdf, 0xd8, 0xa0, 0xf0, 0xe1, 0xf2, 0x07, 0x73, 0x6d, 0x83, + 0xc0, 0x4f, 0xd9, 0xe4, 0xd9, 0x56, 0xe6, 0x22, 0x46, 0x50, 0xe1, 0xf4, 0x90, 0x9a, 0x5c, 0xd6, + 0x15, 0xc7, 0x6a, 0xd6, 0xab, 0x64, 0x75, 0x0a, 0x2f, 0x1d, 0xa7, 0x1d, 0xf6, 0x89, 0x84, 0x92, + 0x8c, 0x52, 0xc9, 0x2b, 0x47, 0xbd, 0x54, 0x8c, 0x46, 0x22, 0x31, 0xcb, 0xf9, 0x4e, 0x49, 0x63, + 0x22, 0x70, 0x83, 0x9a, 0x93, 0xfd, 0x14, 0x49, 0x2d, 0xeb, 0xd2, 0x55, 0xfb, 0xf9, 0xd5, 0x46, + 0xa2, 0x28, 0xed, 0x78, 0xbc, 0xe6, 0xca, 0x66, 0x0b, 0x4e, 0xf7, 0x16, 0xd6, 0x5d, 0x1d, 0xc2, + 0x16, 0x5d, 0xf7, 0xf2, 0x84, 0x88, 0x2b, 0x27, 0x6c, 0xf2, 0x68, 0x1e, 0xc3, 0xf4, 0x71, 0x7f, + 0xf2, 0xc5, 0x84, 0x74, 0x98, 0x46, 0x15, 0x70, 0xa4, 0x47, 0xb2, 0xc8, 0xad, 0x7b, 0xf9, 0x19, + 0xc3, 0xbc, 0xa5, 0x16, 0x0c, 0xd0, 0xdf, 0xc0, 0xeb, 0xe6, 0x5d, 0x80, 0xe1, 0x2b, 0x37, 0xc6, + 0x7a, 0xb1, 0xaf, 0x6b, 0xdc, 0xa0, 0x37, 0x38, 0xe6, 0xe2, 0xc6, 0x06, 0x55, 0x9a, 0xb9, 0x09, + 0xb4, 0xb7, 0x4f, 0xed, 0xcc, 0x0b, 0xb6, 0xe2, 0x9f, 0xb0, 0x67, 0x12, 0x66, 0x96, 0xe8, 0xb5, + 0x0e, 0x3a, 0x23, 0xbc, 0xa2, 0xbd, 0x52, 0x2a, 0x10, 0xf8, 0x41, 0x53, 0x1c, 0xe2, 0xa2, 0xdb, + 0xcf, 0x37, 0x0b, 0x9f, 0x31, 0xfb, 0xc0, 0xd8, 0x25, 0xad, 0xca, 0x69, 0x05, 0x81, 0x5a, 0x66, + 0x34, 0x3f, 0xe1, 0x7b, 0x7a, 0xfa, 0x27, 0x5c, 0x22, 0xf9, 0x12, 0x19, 0x49, 0x8e, 0xd7, 0x9c, + 0x85, 0x35, 0xb6, 0xac, 0x66, 0x58, 0xb2, 0x04, 0x97, 0x69, 0xaa, 0x2c, 0x16, 0x27, 0x77, 0x87, + 0xde, 0x26, 0xba, 0xe1, 0xff, 0x75, 0x2a, 0xa6, 0xe2, 0xd6, 0xa9, 0xa6, 0xfe, 0x53, 0x1f, 0x77, + 0xe9, 0xf1, 0xea, 0x36, 0xe8, 0x76, 0x0b, 0x4e, 0xab, 0x18, 0x7b, 0xe6, 0xd2, 0x30, 0x45, 0x1b, + 0x14, 0x19, 0x76, 0xc7, 0x50, 0xd2, 0xa7, 0x98, 0x89, 0xa2, 0x89, 0x76, 0x0c, 0x4d, 0xd4, 0x93, + 0x53, 0xcb, 0x94, 0x7d, 0x92, 0xc1, 0x35, 0x4c, 0xa4, 0x3c, 0x36, 0x51, 0xa9, 0xed, 0x8e, 0xab, + 0xcf, 0xa3, 0xb5, 0xc0, 0x55, 0xfa, 0x72, 0x23, 0xb8, 0x71, 0x5e, 0xfe, 0x30, 0x01, 0x3a, 0x47, + 0x46, 0x82, 0x93, 0xb5, 0xf2, 0x10, 0x08, 0xd3, 0xec, 0x15, 0xcc, 0xf0, 0x92, 0xc4, 0x4c, 0xf9, + 0x6e, 0x2c, 0xab, 0x03, 0x56, 0x17, 0xc3, 0x8e, 0x9a, 0x3e, 0x3b, 0xf3, 0xdd, 0x0d, 0xb8, 0xf8, + 0xdf, 0x8a, 0x34, 0xdb, 0xf9, 0xc1, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, + 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, + 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xf4, 0x3f, 0x93, 0x0e, + 0xff, 0x9f, 0xff, 0xf5, 0xbf, 0xfe, 0x8d, 0x79, 0x10, 0xd8, 0x53, 0x45, 0x33, 0xae, 0x67, 0xb0, + 0x1b, 0xcd, 0x4f, 0xfd, 0x67, 0x7e, 0xe0, 0xa3, 0xff, 0x5b, 0x6b, 0x85, 0xfe, 0x4f, 0xdf, 0x7c, + 0x87, 0xe5, 0x72, 0xba, 0xe7, 0x69, 0x96, 0x9f, 0xf9, 0xd4, 0x72, 0x02, 0xaf, 0x0d, 0x4a, 0xf7, + 0x2a, 0x6a, 0x07, 0x2d, 0xfb, 0x46, 0x29, 0x18, 0x59, 0xce, 0x22, 0x52, 0x4b, 0x69, 0x9e, 0x91, + 0x79, 0xbf, 0x42, 0x89, 0x26, 0xdf, 0x55, 0xf8, 0x7a, 0xcc, 0xe4, 0xee, 0x15, 0xfa, 0x16, 0x0e, + 0x28, 0xf9, 0x3e, 0xed, 0xa4, 0x14, 0xe3, 0x0a, 0xcb, 0x6b, 0x25, 0x25, 0xf9, 0xc6, 0x2a, 0xdf, + 0x12, 0x1d, 0xbc, 0x6e, 0xc5, 0x8c, 0x56, 0xa1, 0x94, 0x22, 0xa0, 0x85, 0x58, 0x86, 0x92, 0xa2, + 0x98, 0xec, 0xd2, 0x4a, 0x20, 0xa9, 0x6f, 0xac, 0x0f, 0x27, 0x5c, 0xbe, 0x7e, 0xc9, 0xac, 0xcb, + 0x17, 0x05, 0x27, 0x3c, 0x4a, 0xc9, 0x0a, 0xcd, 0x1b, 0x99, 0xc7, 0x3e, 0x55, 0x44, 0x2a, 0x4b, + 0x87, 0xf2, 0x05, 0xf2, 0x1b, 0x56, 0x11, 0x1f, 0x38, 0xf1, 0x8a, 0x08, 0x39, 0x4d, 0xdb, 0xc4, + 0x27, 0x93, 0xbe, 0xf4, 0xb6, 0xdf, 0x59, 0xea, 0xb5, 0xf6, 0x25, 0xba, 0x7a, 0x27, 0xfa, 0x12, + 0xbd, 0x5a, 0x7e, 0xdf, 0x41, 0xde, 0x23, 0x96, 0xae, 0xfa, 0xc8, 0x23, 0x93, 0x6c, 0x03, 0x4b, + 0x85, 0x08, 0x27, 0x26, 0x3c, 0x98, 0xf5, 0xf6, 0x88, 0x54, 0x72, 0x5f, 0xe9, 0xb5, 0x64, 0xd6, + 0x2d, 0x14, 0xcd, 0xc8, 0xd0, 0x55, 0x7d, 0xa0, 0x02, 0xee, 0x2c, 0x76, 0xa2, 0x68, 0xca, 0xea, + 0xf6, 0xaf, 0xa6, 0xe2, 0x9f, 0xa3, 0x9d, 0x12, 0x09, 0x31, 0x9f, 0xe8, 0x95, 0xb8, 0xba, 0x9f, + 0xc5, 0x83, 0xeb, 0x3e, 0x8f, 0x44, 0x33, 0xc1, 0xf8, 0xbc, 0xf3, 0xb3, 0x07, 0xd4, 0x8b, 0x59, + 0xbd, 0x47, 0xf9, 0x22, 0xe5, 0xea, 0xd0, 0x0a, 0x2d, 0x33, 0x46, 0xaf, 0x44, 0x8e, 0x3c, 0x6b, + 0xec, 0x0e, 0x34, 0x76, 0x65, 0x9f, 0x2b, 0x22, 0x59, 0x38, 0xc9, 0x93, 0xec, 0xbe, 0x45, 0xfb, + 0x7a, 0x43, 0xae, 0x9f, 0x8e, 0xf4, 0x05, 0xa2, 0x83, 0x7e, 0x29, 0x77, 0xe1, 0xcf, 0x1c, 0x12, + 0x17, 0x2f, 0xd7, 0x29, 0x0b, 0x3b, 0x71, 0x49, 0x1c, 0x41, 0x47, 0x54, 0x7d, 0x59, 0xa2, 0xb5, + 0x94, 0xd3, 0x96, 0xb6, 0x94, 0xff, 0xbd, 0x52, 0xae, 0xc8, 0xd9, 0xda, 0x2c, 0xff, 0x9b, 0x59, + 0x8e, 0x20, 0x4f, 0xb2, 0x9c, 0xe6, 0x01, 0x25, 0x1d, 0xf6, 0x95, 0x7a, 0x81, 0xfa, 0x8f, 0x28, + 0x55, 0x91, 0xdf, 0xbd, 0x7d, 0x40, 0x53, 0x51, 0x7d, 0x60, 0x1f, 0x68, 0xaa, 0x1e, 0x53, 0xf9, + 0x4c, 0x59, 0x09, 0x21, 0x02, 0xc6, 0xe1, 0x23, 0x67, 0x1c, 0x50, 0x95, 0x5c, 0x8e, 0x9f, 0x57, + 0x24, 0xbf, 0x83, 0xb3, 0x2a, 0xce, 0x42, 0x4c, 0xd0, 0x3c, 0x49, 0x43, 0xb7, 0x61, 0x0b, 0xb9, + 0xcb, 0x85, 0x4d, 0x51, 0x88, 0xad, 0xa1, 0xf9, 0xe0, 0xa6, 0xb3, 0x3e, 0xc2, 0xe7, 0x2f, 0x01, + 0x4d, 0xbd, 0xb5, 0x29, 0x08, 0xaa, 0xd5, 0x67, 0x9d, 0xe8, 0xe0, 0x8d, 0xc5, 0x41, 0x79, 0x59, + 0x19, 0xfa, 0xf0, 0x19, 0x57, 0xc8, 0xca, 0xcd, 0x33, 0x54, 0x3e, 0xc6, 0x37, 0x37, 0x71, 0x40, + 0x3c, 0x7c, 0x90, 0xc4, 0x75, 0xfb, 0x20, 0x77, 0xa5, 0x53, 0x16, 0x29, 0xd2, 0x8a, 0x7b, 0x97, + 0x78, 0xb7, 0x0b, 0x48, 0xaf, 0x56, 0x74, 0x7b, 0x8c, 0x31, 0xd8, 0x9a, 0x46, 0x93, 0x9e, 0x31, + 0x12, 0x22, 0x59, 0x68, 0xde, 0x2b, 0x61, 0x0c, 0x6f, 0xf3, 0x5b, 0xb2, 0x6f, 0x95, 0x8e, 0x20, + 0xb2, 0x8e, 0x0e, 0x89, 0xe5, 0x92, 0x8a, 0x66, 0x5b, 0xea, 0xea, 0x15, 0x8a, 0x76, 0x08, 0x57, + 0xd7, 0x36, 0x69, 0xf8, 0xd8, 0x39, 0x28, 0x3d, 0x76, 0x0f, 0x8b, 0xc4, 0x88, 0x25, 0xa2, 0xc4, + 0x25, 0x67, 0x75, 0xa5, 0x3f, 0x77, 0x6d, 0x43, 0xfb, 0xde, 0xa2, 0x2d, 0x59, 0x2e, 0x43, 0xbd, + 0x6d, 0x29, 0xff, 0x7b, 0xa5, 0x5c, 0x46, 0xe0, 0x6d, 0x96, 0xff, 0xbd, 0x2c, 0x47, 0x3a, 0x36, + 0x9f, 0x64, 0x79, 0x6d, 0xa5, 0xbe, 0x27, 0x25, 0xf8, 0x89, 0x97, 0xd3, 0x2e, 0x1f, 0x55, 0x08, + 0x92, 0x6e, 0x4b, 0x9f, 0xda, 0xe2, 0xea, 0x14, 0x89, 0xa6, 0xbf, 0x25, 0x9b, 0xbb, 0x1a, 0xff, + 0x61, 0x05, 0x41, 0x17, 0x78, 0xe2, 0xfe, 0xf0, 0xc2, 0x99, 0x7c, 0x12, 0x2b, 0x79, 0x34, 0x12, + 0xe6, 0x60, 0x55, 0xef, 0xae, 0x60, 0x23, 0xa9, 0x59, 0xd3, 0x97, 0x1c, 0x1f, 0xc9, 0xf8, 0xea, + 0x23, 0x09, 0x19, 0x41, 0x6c, 0xca, 0x51, 0x97, 0xb2, 0xbb, 0x7f, 0xc6, 0x3b, 0xb2, 0xd9, 0xbc, + 0xee, 0x0b, 0x68, 0x9b, 0x5b, 0x06, 0x6d, 0xa7, 0x17, 0x73, 0x7d, 0x37, 0xd7, 0xa5, 0x76, 0x64, + 0xe8, 0xa0, 0x6a, 0x16, 0xb1, 0x60, 0x9a, 0x03, 0xec, 0x6d, 0x51, 0x44, 0x4d, 0x38, 0xbd, 0x7d, + 0xb3, 0xa6, 0xc4, 0x33, 0x1b, 0x25, 0x5b, 0xd3, 0x5a, 0xcc, 0x13, 0x0b, 0xb4, 0x62, 0x56, 0xf1, + 0x16, 0xb4, 0xdd, 0x73, 0xe7, 0x44, 0x48, 0x6e, 0x21, 0x22, 0x90, 0xb8, 0xde, 0xa1, 0xfa, 0x13, + 0x22, 0x45, 0x2b, 0xac, 0x6e, 0xfc, 0x99, 0x06, 0x47, 0x46, 0xb4, 0x16, 0x26, 0x32, 0xeb, 0xf3, + 0x0e, 0xbd, 0xf3, 0xa1, 0xdd, 0x12, 0x4b, 0x8a, 0xee, 0x83, 0x27, 0x06, 0x83, 0x4e, 0x2a, 0xe7, + 0xf3, 0x29, 0xd2, 0x7c, 0x6f, 0x1f, 0x0d, 0xf0, 0xcc, 0xfe, 0xc1, 0x92, 0x57, 0xbf, 0x4f, 0x7f, + 0xd4, 0x4a, 0x19, 0x12, 0x98, 0xc0, 0x7d, 0x7a, 0x6e, 0x24, 0x49, 0x8d, 0x2f, 0x77, 0x49, 0xfb, + 0x67, 0x8c, 0x5a, 0xa1, 0x42, 0x86, 0x12, 0xc0, 0x28, 0xa5, 0x79, 0xfc, 0x6c, 0x10, 0x19, 0x52, + 0xaa, 0xee, 0xd8, 0x32, 0x94, 0xef, 0x23, 0x6b, 0x07, 0xf8, 0x63, 0xa3, 0x39, 0x72, 0x63, 0xcb, + 0x9c, 0x1e, 0x87, 0xc4, 0x63, 0xf9, 0x3b, 0x96, 0x7e, 0x79, 0x02, 0x81, 0xa2, 0xbc, 0x27, 0xbf, + 0x67, 0xa2, 0xa3, 0x6b, 0xeb, 0xbf, 0x47, 0xb8, 0x5c, 0x29, 0x32, 0x2d, 0xbb, 0x33, 0x01, 0x36, + 0xf7, 0x72, 0x40, 0x3a, 0xf7, 0x92, 0x21, 0x90, 0xc4, 0xed, 0x86, 0xcf, 0x10, 0xb2, 0x96, 0x1b, + 0x66, 0x9d, 0x21, 0x24, 0x4f, 0x6d, 0x72, 0x49, 0xde, 0x9e, 0x45, 0xa3, 0x38, 0xda, 0x9d, 0x5e, + 0xcc, 0xf7, 0x9e, 0x5a, 0x35, 0x13, 0x93, 0xa2, 0xb9, 0x77, 0x38, 0xdf, 0x3c, 0xbf, 0xea, 0x5d, + 0xed, 0xdb, 0xfb, 0x84, 0x77, 0xfe, 0x7d, 0x2a, 0x34, 0x1f, 0xa6, 0x5b, 0x83, 0x7e, 0xa2, 0xab, + 0x05, 0xcb, 0x05, 0xbe, 0xb7, 0xce, 0x55, 0xaf, 0x4f, 0x3f, 0xff, 0x60, 0xf3, 0xe8, 0xfe, 0x21, + 0xc9, 0x81, 0xa7, 0x77, 0xc7, 0xf2, 0xe5, 0x8c, 0x47, 0x5b, 0x56, 0x3c, 0x82, 0xe4, 0xfb, 0xf4, + 0xc4, 0xe6, 0xd6, 0xbb, 0x2f, 0x95, 0x3b, 0x97, 0xfc, 0xcc, 0x2d, 0x22, 0xf0, 0xd6, 0xe9, 0xe5, + 0x8b, 0xa6, 0x57, 0x1e, 0x6c, 0x1e, 0xdd, 0xef, 0xe6, 0x3a, 0xde, 0x8e, 0x75, 0xe8, 0x17, 0x93, + 0x68, 0xbe, 0xf5, 0x75, 0x7f, 0xad, 0x7f, 0x08, 0x13, 0xb1, 0xd1, 0xf6, 0xc5, 0xd6, 0xfd, 0xe3, + 0x4f, 0xfe, 0xa7, 0xee, 0x27, 0x77, 0xad, 0xf1, 0x35, 0xd3, 0xcb, 0xbf, 0x20, 0xe5, 0x89, 0xc5, + 0xfc, 0xda, 0x89, 0x39, 0x0d, 0x3a, 0x39, 0xf7, 0xdb, 0x9d, 0x4b, 0xf8, 0x69, 0x49, 0xf4, 0x3b, + 0x70, 0xa8, 0x43, 0xd8, 0x76, 0x14, 0x7f, 0x33, 0x02, 0xed, 0xe9, 0x6f, 0xb3, 0xfc, 0x6f, 0x1e, + 0x4d, 0xc8, 0x09, 0x5a, 0xb1, 0xfc, 0xaf, 0x2b, 0x1a, 0x92, 0xef, 0xd8, 0x7f, 0x87, 0x26, 0x7a, + 0x77, 0xac, 0x83, 0x79, 0xe4, 0x64, 0x7a, 0x79, 0xc4, 0x37, 0x38, 0xbf, 0x7a, 0xd7, 0xb0, 0x18, + 0xae, 0x0d, 0x86, 0x55, 0x33, 0xa7, 0x4d, 0xde, 0xdf, 0xd0, 0x8f, 0x0d, 0x81, 0x3c, 0x6f, 0xdc, + 0x9d, 0xd0, 0xcc, 0x19, 0xb7, 0xc6, 0x7f, 0x6b, 0x98, 0x18, 0xdb, 0xe6, 0xbb, 0xf4, 0x9d, 0x8a, + 0xcc, 0x7c, 0x2e, 0x35, 0x25, 0xf4, 0xf6, 0x20, 0xa1, 0x04, 0xd7, 0x3d, 0x43, 0x8e, 0xaf, 0x0d, + 0xd5, 0x93, 0xd7, 0xfd, 0xd5, 0xf7, 0xf8, 0x2f, 0xdd, 0xcc, 0xe4, 0x5a, 0xb3, 0xbc, 0xd2, 0xdb, + 0x96, 0xf2, 0xbf, 0xd9, 0xb0, 0x68, 0x95, 0x6d, 0x96, 0xff, 0xcd, 0x2c, 0xb7, 0x68, 0xda, 0x2c, + 0xff, 0x9b, 0x6d, 0xb9, 0xab, 0xa3, 0xcd, 0xf2, 0xbf, 0x59, 0xca, 0x5d, 0xda, 0x27, 0x59, 0xbe, + 0xff, 0xdb, 0x51, 0xca, 0x0a, 0xe2, 0x51, 0x71, 0xff, 0x27, 0x77, 0x45, 0x24, 0xf3, 0xb8, 0x78, + 0x12, 0x10, 0x76, 0x0a, 0x5f, 0x5a, 0xdd, 0x5e, 0xad, 0xa2, 0x6f, 0x7f, 0x74, 0x55, 0x19, 0x72, + 0x7e, 0x63, 0x85, 0x70, 0x50, 0xcb, 0xd6, 0x87, 0xfc, 0x33, 0xd7, 0x25, 0x5b, 0x40, 0xbd, 0x61, + 0x46, 0xf7, 0x0e, 0x5c, 0x4c, 0x2c, 0x58, 0x7a, 0x25, 0x74, 0x97, 0x6e, 0x40, 0x8c, 0x74, 0xf4, + 0x29, 0x25, 0x33, 0x74, 0xbf, 0x24, 0xf4, 0xff, 0x37, 0x96, 0x47, 0x3b, 0x5a, 0xb3, 0x1c, 0x1d, + 0x69, 0x4b, 0xf9, 0x9f, 0x6d, 0xe0, 0x3f, 0x7d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, + 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xfe, 0x6f, 0x23, + 0xf8, 0x4f, 0xdf, 0xe3, 0x19, 0x46, 0x82, 0xf1, 0x27, 0xff, 0x22, 0x0d, 0x6c, 0xab, 0xe4, 0x48, + 0x63, 0x82, 0x54, 0x77, 0xe6, 0x60, 0x9a, 0x9b, 0x5a, 0x8b, 0x97, 0x44, 0xa2, 0xcf, 0x1f, 0x57, + 0x07, 0x97, 0x2e, 0x4b, 0xa5, 0xef, 0xfe, 0xab, 0x78, 0x5d, 0xfe, 0x66, 0x36, 0xff, 0xfd, 0x25, + 0x95, 0x61, 0x5d, 0x06, 0x82, 0x3f, 0xae, 0x77, 0xf5, 0xf0, 0x07, 0x33, 0x16, 0x58, 0xde, 0xa2, + 0x52, 0x32, 0x96, 0xa7, 0x46, 0x61, 0x81, 0xae, 0xcb, 0xd2, 0x6a, 0x62, 0xeb, 0xf7, 0x33, 0x2d, + 0xfb, 0xc1, 0x65, 0x19, 0xd8, 0xdd, 0xfe, 0x7a, 0x91, 0xab, 0x6e, 0x95, 0x46, 0x0f, 0x61, 0xe5, + 0xae, 0x0d, 0xb8, 0x7b, 0xc8, 0x4c, 0x0d, 0x35, 0x76, 0x73, 0xff, 0x1f, 0xfc, 0x67, 0x95, 0x44, + 0xbf, 0x33, 0x8f, 0xae, 0x77, 0xfc, 0xe9, 0x45, 0xde, 0x27, 0x18, 0xb2, 0xae, 0x3f, 0x8f, 0x87, + 0x16, 0x59, 0xc1, 0xda, 0x74, 0xfa, 0x59, 0x97, 0xe9, 0x66, 0x69, 0xec, 0xed, 0x71, 0x55, 0x95, + 0xc1, 0x31, 0x43, 0xaa, 0x62, 0xd1, 0xb0, 0xca, 0x67, 0x3f, 0xcf, 0x6a, 0x17, 0xbd, 0x4c, 0xda, + 0xb7, 0x8e, 0xdb, 0x25, 0x78, 0x71, 0x92, 0x25, 0xbf, 0x26, 0x7a, 0x92, 0x2e, 0xcd, 0x33, 0xe1, + 0x56, 0xb3, 0xae, 0xa8, 0xc7, 0x08, 0x5a, 0x1c, 0xae, 0x37, 0x5a, 0x04, 0x82, 0x72, 0xda, 0xfb, + 0x2b, 0xfa, 0x71, 0x98, 0xd6, 0x28, 0x10, 0xda, 0x22, 0xf1, 0x63, 0xc3, 0x49, 0xd2, 0x38, 0xbb, + 0x96, 0x79, 0xe7, 0x06, 0x2d, 0xcc, 0xd7, 0x2d, 0x58, 0xd0, 0x62, 0x2d, 0x80, 0xe9, 0x53, 0x15, + 0x87, 0x46, 0x45, 0xd2, 0x5e, 0xbd, 0xf4, 0x9f, 0x71, 0xdc, 0xa8, 0x46, 0xc0, 0x2e, 0xbe, 0xc4, + 0x6c, 0x87, 0xfc, 0x81, 0x35, 0x86, 0x4c, 0x77, 0xd0, 0x37, 0xbd, 0x32, 0xb2, 0xd6, 0x14, 0x68, + 0x61, 0xd7, 0xa7, 0x08, 0x4b, 0xc9, 0x8e, 0x50, 0x84, 0xde, 0x3c, 0x8f, 0x13, 0x43, 0x0a, 0xd0, + 0x54, 0x6d, 0x24, 0x98, 0x50, 0x78, 0xfd, 0xab, 0x37, 0xc0, 0xce, 0x1f, 0xe2, 0xd7, 0x2d, 0xfc, + 0xe5, 0x57, 0xd6, 0x74, 0x04, 0x74, 0xed, 0x2d, 0xc3, 0xe0, 0x41, 0x43, 0x26, 0x41, 0x60, 0x6a, + 0x9a, 0xb0, 0xa8, 0x66, 0x51, 0xaf, 0xbe, 0x34, 0x4a, 0xac, 0xa6, 0x42, 0x4e, 0x3c, 0xc5, 0x92, + 0xe0, 0xa6, 0xd8, 0x6d, 0x8b, 0x9d, 0x46, 0x8b, 0xc4, 0x0b, 0xbc, 0xa4, 0x18, 0x4c, 0xc0, 0xdb, + 0x57, 0x1c, 0x85, 0xf3, 0x68, 0xc0, 0x80, 0xe3, 0x94, 0xc7, 0x4a, 0x96, 0x88, 0x4e, 0xbe, 0xc4, + 0x3d, 0x5c, 0x0a, 0x48, 0x88, 0xef, 0xcd, 0x30, 0x52, 0xb6, 0x60, 0xf9, 0xa3, 0xe2, 0x52, 0x52, + 0x04, 0x96, 0x16, 0x83, 0x0b, 0x84, 0xcb, 0x9c, 0x68, 0xbf, 0x44, 0xe1, 0xe2, 0xaa, 0xc8, 0xe5, + 0xe0, 0x86, 0x50, 0x82, 0x0d, 0xca, 0xd5, 0xa0, 0xed, 0x52, 0x3c, 0x2c, 0xed, 0x24, 0x73, 0xf5, + 0x6a, 0xa4, 0x2e, 0x6d, 0x07, 0x57, 0x12, 0x4f, 0x02, 0x6b, 0xdb, 0x69, 0xae, 0x0b, 0x31, 0xf5, + 0x2b, 0xae, 0xeb, 0xe2, 0xdd, 0x9f, 0xa9, 0x8e, 0x58, 0x06, 0xa5, 0xce, 0x9c, 0x12, 0xb6, 0xd0, + 0x6a, 0xa4, 0x74, 0x8f, 0x11, 0x74, 0x3f, 0xc7, 0x1b, 0x84, 0xf5, 0x61, 0x45, 0x08, 0x78, 0x86, + 0xe6, 0x91, 0x64, 0xd1, 0x4a, 0xf8, 0xcb, 0x78, 0x53, 0xe2, 0xc9, 0xd8, 0x77, 0xf3, 0x4b, 0x0c, + 0x5a, 0x28, 0xe5, 0xc8, 0xc3, 0xd9, 0xf0, 0x08, 0xfc, 0xe5, 0x02, 0x7a, 0xe6, 0x6a, 0x4e, 0x9e, + 0xd4, 0x70, 0x97, 0xc0, 0xda, 0x8c, 0x4a, 0xf9, 0x93, 0xcb, 0xf6, 0xdf, 0x54, 0xdb, 0x71, 0x69, + 0x1b, 0xd7, 0xdd, 0xbf, 0x04, 0x41, 0xee, 0xd6, 0x93, 0xfc, 0x4e, 0x22, 0xa4, 0x56, 0xd3, 0x82, + 0xe5, 0xf2, 0xdd, 0xa9, 0x21, 0xd3, 0x8f, 0xe8, 0x6c, 0xa7, 0xb8, 0x51, 0x88, 0x17, 0xc7, 0xb5, + 0x5c, 0x5d, 0x43, 0xf1, 0xfe, 0xdd, 0x45, 0xb0, 0xd7, 0xe0, 0x26, 0x0a, 0x6b, 0x8b, 0x3d, 0x8f, + 0x73, 0xb2, 0x2d, 0x27, 0x4a, 0xe0, 0x69, 0x2e, 0xef, 0x84, 0x6a, 0x07, 0x18, 0x16, 0xbb, 0x3c, + 0xa1, 0x4b, 0x96, 0xb7, 0xbe, 0xd6, 0xa8, 0xf3, 0x9d, 0xb0, 0x41, 0xdd, 0x9b, 0x2e, 0xd9, 0xad, + 0x97, 0xf8, 0xd0, 0xc4, 0x46, 0xd9, 0x9e, 0x7d, 0x1f, 0x53, 0x55, 0x23, 0x41, 0x5b, 0xd9, 0xe1, + 0xbf, 0xcc, 0x5d, 0xdf, 0xef, 0x62, 0x23, 0xe9, 0x88, 0x36, 0x4a, 0x3b, 0x6c, 0xd4, 0x63, 0xcb, + 0x8a, 0x5a, 0xd0, 0xb1, 0x54, 0xcb, 0x33, 0x3b, 0x17, 0x17, 0x5c, 0xed, 0x57, 0x4a, 0xb4, 0x67, + 0x1c, 0xcd, 0x71, 0xc5, 0x62, 0x44, 0x22, 0x74, 0x8e, 0x2a, 0x03, 0x7b, 0x44, 0x89, 0x5c, 0xf8, + 0xe2, 0xea, 0xe6, 0xa4, 0x1f, 0x87, 0x85, 0x31, 0xfd, 0xa8, 0x44, 0x46, 0x77, 0x5c, 0x17, 0x62, + 0x70, 0xe2, 0x3f, 0x68, 0x58, 0x42, 0xb9, 0xef, 0xcc, 0x30, 0xea, 0x68, 0xc1, 0x72, 0xdf, 0x75, + 0xb2, 0x45, 0x20, 0xe8, 0x2b, 0xd9, 0x55, 0x35, 0x82, 0x2c, 0x2d, 0xf0, 0xd9, 0x90, 0x9f, 0x3b, + 0xe6, 0x4b, 0xed, 0x90, 0x32, 0xbf, 0x2f, 0x29, 0x09, 0x71, 0xf7, 0x77, 0xe6, 0xc7, 0x08, 0xe3, + 0xc2, 0x70, 0xf2, 0xa6, 0x05, 0x56, 0xa8, 0xab, 0x2a, 0x16, 0x8b, 0x86, 0x62, 0xa7, 0xb8, 0x63, + 0xa4, 0x91, 0x4a, 0xb2, 0x12, 0x9c, 0x4a, 0xed, 0x48, 0xfc, 0x50, 0x3f, 0x4f, 0x5c, 0x40, 0x03, + 0xc3, 0x06, 0xed, 0xda, 0x9d, 0x16, 0xe7, 0x1b, 0xb4, 0xa3, 0x34, 0xfe, 0x4f, 0xce, 0x0f, 0x74, + 0xbe, 0xea, 0x07, 0x97, 0x11, 0x95, 0xd1, 0xa2, 0xd1, 0x34, 0xe4, 0x84, 0x05, 0xd2, 0xc0, 0x75, + 0x11, 0xb5, 0x62, 0x4c, 0xb5, 0x75, 0xaf, 0x45, 0x10, 0xa3, 0x7e, 0x5b, 0xdc, 0xfa, 0xb9, 0x51, + 0xc3, 0x0c, 0xa7, 0x92, 0x4c, 0xda, 0x9d, 0xda, 0x64, 0xbe, 0x24, 0x5e, 0x19, 0x7d, 0x5b, 0xea, + 0x51, 0xb2, 0xc8, 0xcd, 0x02, 0x7e, 0xd0, 0x42, 0xb3, 0x97, 0x7c, 0xf6, 0xf3, 0xbf, 0x42, 0xb0, + 0xfc, 0x4f, 0xc4, 0x30, 0xa6, 0x07, 0x46, 0x49, 0x69, 0x97, 0x38, 0x83, 0xaa, 0xed, 0x2d, 0xf5, + 0x70, 0xe2, 0x17, 0xd8, 0xc2, 0x77, 0xdd, 0x02, 0x6b, 0xb4, 0x28, 0x9a, 0x48, 0xd4, 0x1b, 0x6f, + 0x76, 0x8d, 0x27, 0x4a, 0x51, 0xd1, 0xce, 0xa9, 0x90, 0x13, 0xe5, 0x6f, 0x9b, 0xd4, 0x8b, 0x5b, + 0xfc, 0xf5, 0x84, 0x2b, 0x67, 0xbb, 0x6e, 0x91, 0xf0, 0x15, 0xd6, 0xe1, 0x83, 0xe8, 0xef, 0xcd, + 0xa3, 0xd3, 0xb6, 0x60, 0x39, 0x0e, 0x55, 0xd8, 0x26, 0x97, 0xca, 0x50, 0xad, 0xf2, 0x89, 0x0f, + 0xd9, 0x2f, 0x73, 0x21, 0x3d, 0xb7, 0xbb, 0x72, 0x29, 0xb0, 0x33, 0x6a, 0xf9, 0x01, 0xda, 0x23, + 0x97, 0x22, 0x1d, 0x4f, 0x17, 0xee, 0x55, 0x20, 0x96, 0x9e, 0x9b, 0xda, 0x30, 0x5a, 0xa0, 0xa4, + 0xb9, 0x86, 0x92, 0xf6, 0x03, 0xc3, 0x72, 0x4f, 0x2b, 0x9d, 0xa8, 0x45, 0xc4, 0x55, 0xcd, 0x92, + 0xbb, 0xd0, 0xdb, 0x45, 0xff, 0x05, 0x72, 0x79, 0x33, 0x2d, 0x46, 0xd0, 0xaf, 0x40, 0x5c, 0xa0, + 0xc5, 0xc1, 0x75, 0x35, 0x2c, 0xe9, 0x41, 0xa5, 0xb7, 0xf1, 0x0b, 0x41, 0x50, 0x44, 0x78, 0x9d, + 0x39, 0x63, 0x94, 0x23, 0xae, 0x1c, 0xb4, 0x38, 0xb9, 0x9e, 0x7e, 0xb9, 0x8c, 0xe6, 0xc1, 0xd2, + 0x33, 0x37, 0x2d, 0xd0, 0x5e, 0xf1, 0x75, 0xaf, 0x6e, 0x2a, 0x35, 0xe7, 0x04, 0x03, 0x08, 0xe8, + 0x90, 0x06, 0x3c, 0x48, 0x28, 0x41, 0x64, 0xb4, 0x70, 0x00, 0x91, 0xdd, 0x56, 0xdc, 0xaa, 0xf4, + 0x8a, 0x9b, 0x15, 0xa9, 0x89, 0xeb, 0xee, 0xba, 0x10, 0x81, 0x08, 0x91, 0x01, 0x9b, 0x07, 0x2d, + 0x8e, 0x44, 0x2a, 0xcb, 0x09, 0xfa, 0x1b, 0xcf, 0x70, 0xa1, 0xdf, 0x59, 0x47, 0x60, 0xa4, 0x05, + 0xcb, 0x37, 0xcb, 0xf6, 0x53, 0x03, 0xbb, 0x8f, 0x17, 0x96, 0xb5, 0x7c, 0xf3, 0x62, 0xa3, 0x64, + 0xd1, 0x5f, 0xd6, 0x2c, 0xbd, 0xd4, 0xd5, 0xd1, 0x71, 0x5d, 0x27, 0xc2, 0xd3, 0xc9, 0xd7, 0xaf, + 0xa2, 0xfd, 0xff, 0x25, 0x60, 0x80, 0xbf, 0x2d, 0xfd, 0x4e, 0x79, 0x14, 0xbe, 0x46, 0xf5, 0xe0, + 0xac, 0xeb, 0xa3, 0x52, 0x29, 0xfd, 0xfd, 0xac, 0x77, 0x0c, 0x16, 0x14, 0xac, 0x3a, 0xb2, 0x91, + 0xb2, 0x22, 0x61, 0xbd, 0xa8, 0xc0, 0xc2, 0x26, 0xb9, 0x32, 0x67, 0xf8, 0xb8, 0xf2, 0xb6, 0x53, + 0x43, 0x3f, 0x54, 0xae, 0x82, 0x77, 0x06, 0x2b, 0x88, 0xc2, 0xe2, 0x5a, 0xb0, 0x86, 0x21, 0x66, + 0x90, 0x33, 0xe4, 0x77, 0x6c, 0x39, 0x6a, 0x6c, 0xc1, 0x72, 0xae, 0xa2, 0xe8, 0x4d, 0x9d, 0xa2, + 0xa6, 0x28, 0x89, 0x15, 0x32, 0xb4, 0xab, 0x0f, 0x08, 0x46, 0xb3, 0xf4, 0x23, 0xf4, 0x38, 0x72, + 0xce, 0x9d, 0x70, 0x62, 0x08, 0xbf, 0xb0, 0xe4, 0x9e, 0x8f, 0x42, 0xa0, 0x60, 0x74, 0xf5, 0x21, + 0xd7, 0x9c, 0x50, 0x02, 0xd1, 0xec, 0xea, 0x03, 0x6c, 0xb3, 0x29, 0x81, 0xa8, 0x0b, 0x34, 0xe0, + 0x81, 0xf7, 0x5a, 0x40, 0x2f, 0x04, 0x1e, 0xc4, 0xb5, 0xed, 0xe2, 0xb4, 0xa1, 0x5f, 0x8a, 0x20, + 0x9c, 0xd3, 0xb4, 0x40, 0x4f, 0xd7, 0x05, 0xd4, 0xee, 0x6e, 0xa5, 0xb7, 0x7e, 0xae, 0xa0, 0x5b, + 0xa3, 0x05, 0xe7, 0xbb, 0x81, 0xf2, 0xf5, 0x5f, 0xd7, 0x61, 0xb4, 0x71, 0xc2, 0xd7, 0x2f, 0x75, + 0x12, 0x5d, 0xfd, 0xd7, 0x2d, 0x94, 0xf2, 0x46, 0xf1, 0x62, 0xf8, 0x32, 0x0f, 0x78, 0x27, 0xa7, + 0x3b, 0x6e, 0x4b, 0x2c, 0xde, 0x29, 0xef, 0x0c, 0x74, 0xc5, 0xc5, 0x53, 0x73, 0x7a, 0x71, 0x53, + 0x77, 0x5d, 0x04, 0xd0, 0x16, 0x57, 0x71, 0x5a, 0x28, 0xbf, 0xae, 0xd0, 0xa5, 0xec, 0xbf, 0x5b, + 0x2c, 0xe5, 0x3b, 0xb6, 0x9c, 0xee, 0x69, 0xc1, 0xf2, 0x2e, 0x51, 0xb3, 0x88, 0x32, 0x0d, 0xac, + 0x01, 0xe0, 0xa5, 0x48, 0x0a, 0xec, 0x13, 0x60, 0x79, 0xc5, 0x06, 0x80, 0x44, 0x0e, 0x3e, 0x2e, + 0x87, 0x40, 0x4e, 0x70, 0xaf, 0xc4, 0xbb, 0x83, 0x53, 0x00, 0x3f, 0x1b, 0xc8, 0x46, 0x83, 0xb8, + 0x3a, 0x6c, 0x72, 0x78, 0x4c, 0x0a, 0xdf, 0x41, 0xc4, 0x15, 0x48, 0x93, 0x72, 0x1f, 0xc9, 0xd9, + 0x80, 0x37, 0xf7, 0x91, 0x0d, 0xcd, 0x93, 0x02, 0xf3, 0xa4, 0x85, 0x67, 0x05, 0x6a, 0x29, 0xf7, + 0x45, 0x65, 0xb0, 0x8a, 0x97, 0x33, 0xd7, 0x0f, 0x8f, 0x29, 0x1f, 0xe7, 0xe0, 0x21, 0xb6, 0x01, + 0xc0, 0xc0, 0x46, 0xcd, 0x22, 0x60, 0x23, 0x89, 0xae, 0x01, 0xf0, 0x91, 0x9a, 0x7c, 0xe2, 0x30, + 0x09, 0xf2, 0x08, 0xd9, 0x70, 0xfc, 0x14, 0x42, 0x94, 0xd5, 0xe0, 0xd3, 0x60, 0x83, 0x81, 0x4e, + 0x58, 0xc9, 0xcc, 0xa5, 0x7d, 0xfc, 0x0c, 0x27, 0xad, 0x7d, 0x50, 0xd4, 0x8f, 0x33, 0xb3, 0xb7, + 0x98, 0x49, 0xf3, 0xa8, 0x00, 0x1a, 0x2c, 0x88, 0xee, 0xd6, 0x7e, 0x67, 0xb5, 0x0c, 0x4b, 0x0b, + 0x96, 0x0b, 0xff, 0x8a, 0x52, 0x05, 0xdf, 0x32, 0x6b, 0xdb, 0x00, 0xde, 0x8e, 0x59, 0xd4, 0x07, + 0xd8, 0xab, 0x34, 0xf9, 0x35, 0xd7, 0x69, 0x4d, 0xf9, 0x8b, 0xa6, 0xb8, 0xc4, 0x47, 0x9c, 0x01, + 0x87, 0x26, 0x48, 0x25, 0x00, 0x5c, 0x4f, 0x6d, 0x01, 0xa7, 0xd4, 0x6c, 0x81, 0xe9, 0x19, 0x6f, + 0x60, 0xfc, 0x2d, 0xbd, 0xb6, 0x45, 0xa6, 0x3b, 0x4d, 0x2c, 0xf0, 0xbf, 0x9d, 0x2f, 0x2c, 0xfe, + 0xa2, 0x80, 0x09, 0x39, 0x31, 0xfe, 0x4e, 0xfa, 0x53, 0x49, 0xb5, 0x4f, 0xe1, 0xf6, 0x2e, 0xfd, + 0x6d, 0x8b, 0x20, 0x80, 0xda, 0x3e, 0xc3, 0x7a, 0x56, 0x6d, 0x22, 0x6b, 0x7a, 0x0f, 0x2d, 0xc1, + 0x17, 0xc6, 0x58, 0x73, 0x3a, 0xfa, 0xca, 0x0a, 0x9e, 0xc6, 0xdf, 0x21, 0x4b, 0xd1, 0x97, 0xc1, + 0x92, 0x91, 0xb5, 0x58, 0x35, 0xfe, 0xeb, 0x5e, 0x01, 0x6f, 0x4f, 0xe2, 0xc6, 0xd1, 0xd2, 0x7a, + 0x52, 0xe2, 0xf7, 0x9d, 0x71, 0xee, 0xd8, 0x2a, 0xf9, 0x9c, 0xab, 0x4f, 0x85, 0x70, 0xe0, 0xb6, + 0xc9, 0xda, 0x42, 0xc7, 0x0b, 0xec, 0xab, 0x2f, 0x46, 0x14, 0x0e, 0x6e, 0x5b, 0x0c, 0x32, 0x3e, + 0xcc, 0x9c, 0x06, 0x0e, 0x12, 0x8f, 0x02, 0xa8, 0x49, 0xb2, 0x8d, 0xea, 0x79, 0x3b, 0x56, 0x70, + 0x49, 0x21, 0x1d, 0x5a, 0x29, 0xbd, 0x9a, 0xe4, 0x14, 0xd5, 0x7f, 0xad, 0x62, 0x85, 0xfa, 0x20, + 0x43, 0x05, 0xf5, 0xec, 0x70, 0x32, 0x4d, 0x42, 0x9f, 0x14, 0x29, 0x79, 0x45, 0x00, 0x60, 0xe8, + 0xf8, 0x12, 0x1c, 0x7c, 0xf4, 0x9d, 0xdf, 0xbf, 0x63, 0x58, 0x10, 0x5b, 0x0b, 0x96, 0x37, 0x6c, + 0x2f, 0xc2, 0x99, 0x4e, 0x45, 0x93, 0xc7, 0x3d, 0x77, 0xcb, 0x4d, 0xbb, 0x88, 0x47, 0xaa, 0xc9, + 0xb5, 0x50, 0x20, 0x48, 0x13, 0xd3, 0x03, 0x8d, 0xd4, 0x22, 0x00, 0x92, 0xdb, 0xa0, 0x25, 0xb9, + 0x15, 0x20, 0xa5, 0xfc, 0xa1, 0x5f, 0x95, 0x5d, 0x97, 0x61, 0x05, 0x2a, 0x6c, 0x1b, 0x50, 0xb8, + 0xe8, 0xde, 0x01, 0x69, 0xd3, 0x5a, 0x01, 0x33, 0x01, 0x00, 0xc1, 0xc3, 0x4f, 0x8d, 0x1c, 0xd0, + 0xb7, 0x3e, 0xcf, 0x06, 0x25, 0x15, 0x01, 0x02, 0x9e, 0x1b, 0x51, 0x4a, 0x11, 0x97, 0x12, 0x3c, + 0xed, 0x51, 0x9e, 0x12, 0x78, 0x7f, 0xcb, 0x83, 0xbb, 0x18, 0xe1, 0xcb, 0x08, 0xa0, 0x1f, 0xd4, + 0x72, 0xa8, 0xbd, 0xff, 0xe1, 0xcb, 0x1c, 0xd0, 0xc2, 0xbb, 0xf0, 0xbb, 0xa9, 0x17, 0x00, 0xbf, + 0x23, 0x2e, 0xa1, 0xf2, 0xe9, 0xd4, 0x57, 0xa4, 0x03, 0xf9, 0x73, 0xc3, 0x92, 0x43, 0x5a, 0xb0, + 0x5c, 0xf0, 0xdd, 0x62, 0x74, 0x7a, 0xb5, 0xd8, 0x43, 0x0f, 0x4e, 0x19, 0x2d, 0xa3, 0x05, 0x66, + 0x27, 0x8b, 0x15, 0x36, 0x62, 0x9f, 0x2f, 0x0e, 0x77, 0xb7, 0x32, 0x17, 0xc9, 0xf2, 0xee, 0xd0, + 0x62, 0xf2, 0x0c, 0x3a, 0xa5, 0x2a, 0x80, 0xd5, 0x79, 0xd2, 0x9e, 0x35, 0x00, 0x18, 0x3c, 0xa4, + 0xdb, 0x48, 0x70, 0xf1, 0xfa, 0xd4, 0x8f, 0x14, 0x07, 0xfb, 0x04, 0xd0, 0x3d, 0x33, 0x58, 0x4b, + 0x9e, 0x93, 0xcd, 0xda, 0x37, 0x6b, 0x47, 0xa1, 0x4f, 0x2b, 0xde, 0xff, 0x90, 0xe4, 0xd0, 0xb1, + 0xc1, 0x03, 0x14, 0x2f, 0xa7, 0x44, 0xd3, 0x2b, 0x9b, 0x3f, 0xcb, 0x28, 0x63, 0x3e, 0x93, 0xd1, + 0x1e, 0x8d, 0x0d, 0x66, 0x32, 0x17, 0x87, 0x99, 0x4c, 0xa9, 0x04, 0x10, 0xba, 0xb9, 0xde, 0x5b, + 0xde, 0xca, 0x02, 0x70, 0xbe, 0x33, 0x34, 0x77, 0x74, 0xee, 0x58, 0xd6, 0x6d, 0x94, 0x8b, 0x27, + 0xf5, 0xd7, 0x89, 0xad, 0xf2, 0xe7, 0x04, 0x00, 0xc0, 0x5f, 0xcb, 0x19, 0x70, 0xbb, 0x49, 0xbb, + 0xc8, 0x7f, 0x01, 0xda, 0x5e, 0x96, 0x78, 0x7c, 0xc9, 0x52, 0x6d, 0x23, 0x93, 0xf9, 0x04, 0x9f, + 0xbb, 0x38, 0x4b, 0x6c, 0x34, 0xaa, 0xe7, 0x12, 0xae, 0x46, 0xe9, 0x7a, 0xbe, 0x68, 0xa9, 0xb2, + 0x21, 0x96, 0x35, 0x6b, 0xcd, 0xe6, 0xaa, 0x8d, 0x79, 0xf6, 0x37, 0x7a, 0x26, 0x89, 0x10, 0xdf, + 0x59, 0x47, 0xc0, 0xdb, 0x82, 0xe5, 0xbd, 0xbd, 0xf1, 0xdf, 0x3e, 0x3e, 0x03, 0x90, 0x17, 0x00, + 0x58, 0x60, 0x2b, 0x86, 0x77, 0xd2, 0xf0, 0x86, 0x33, 0xe3, 0x1d, 0xc9, 0xd0, 0xbf, 0x16, 0xe6, + 0x33, 0xc5, 0x41, 0x85, 0xeb, 0x56, 0x2b, 0x31, 0x1f, 0x00, 0xb0, 0xd8, 0x9a, 0x4f, 0xe5, 0x6c, + 0x82, 0x64, 0xa0, 0xef, 0x5a, 0x96, 0x4c, 0xeb, 0x54, 0x3b, 0xe1, 0x05, 0x9e, 0x2a, 0xf4, 0x09, + 0xb3, 0x32, 0x67, 0xf7, 0x5a, 0x24, 0x88, 0xc2, 0x3a, 0x80, 0xbc, 0x7d, 0x06, 0x2f, 0xf7, 0x0c, + 0x5f, 0x92, 0x9c, 0x30, 0x98, 0x92, 0xe9, 0x39, 0x05, 0xb8, 0x64, 0xe1, 0xa7, 0x78, 0x68, 0x46, + 0x81, 0xe4, 0xbb, 0xfe, 0x35, 0x77, 0xdd, 0xc2, 0xa8, 0x96, 0x27, 0x88, 0xa0, 0x81, 0xae, 0x61, + 0x9a, 0x31, 0x59, 0xe4, 0xe7, 0x78, 0x08, 0xe5, 0xc7, 0xb7, 0x81, 0x89, 0x31, 0x85, 0x81, 0x3d, + 0x8a, 0x4b, 0xfc, 0xab, 0x71, 0xb9, 0xcb, 0xc0, 0x7b, 0xae, 0x9c, 0xd5, 0xde, 0x69, 0x41, 0x83, + 0x16, 0xa9, 0x1a, 0x56, 0x2a, 0x83, 0x16, 0xff, 0x02, 0x2d, 0xc0, 0x33, 0x86, 0xa3, 0x3b, 0xd6, + 0xb4, 0x71, 0x4d, 0x14, 0xc2, 0xd7, 0x54, 0x03, 0x98, 0x56, 0xf9, 0x5c, 0xe9, 0x3b, 0xb9, 0xb6, + 0x15, 0xe3, 0x83, 0x29, 0x82, 0x30, 0x82, 0x16, 0x3e, 0x00, 0xc8, 0x89, 0x9f, 0x67, 0xcd, 0x20, + 0x1e, 0x90, 0x2c, 0x18, 0x23, 0x56, 0xeb, 0x45, 0xbe, 0x93, 0x06, 0x0f, 0x12, 0x6c, 0x57, 0xd3, + 0x0a, 0x79, 0x68, 0x3a, 0x77, 0xfd, 0x0c, 0x10, 0xfa, 0xf7, 0x10, 0x46, 0x7d, 0xaa, 0x46, 0x14, + 0xa2, 0x76, 0xbc, 0xeb, 0xd7, 0xf0, 0x3f, 0x41, 0x67, 0x16, 0x66, 0x8f, 0xe3, 0x61, 0x23, 0xfd, + 0x9d, 0xd5, 0x32, 0xf0, 0x16, 0x2c, 0x6f, 0x18, 0x02, 0xe8, 0xa3, 0x7b, 0xaf, 0xf5, 0xc9, 0xd2, + 0xc3, 0x41, 0x5e, 0x35, 0x0c, 0xbc, 0x07, 0x39, 0x48, 0x01, 0xb0, 0xb5, 0x0d, 0x91, 0x3a, 0x69, + 0xe4, 0x3e, 0xb2, 0x41, 0x80, 0xad, 0x80, 0x2d, 0x0e, 0x88, 0x0e, 0x09, 0x17, 0x41, 0x03, 0x55, + 0xbf, 0x63, 0x94, 0xa0, 0x56, 0xde, 0x69, 0x01, 0x34, 0xba, 0x02, 0xed, 0x11, 0x0d, 0x37, 0x16, + 0x0d, 0x54, 0xcd, 0x9e, 0x46, 0x35, 0x5b, 0xe0, 0x3e, 0xb5, 0xb0, 0x4e, 0x9f, 0x71, 0x50, 0x0a, + 0x10, 0xb0, 0xe4, 0x9e, 0x8b, 0xe6, 0x89, 0x21, 0x52, 0x86, 0xce, 0x0b, 0x81, 0x1a, 0xdd, 0xd3, + 0x40, 0x45, 0xc0, 0xeb, 0x0a, 0x00, 0xa2, 0xd2, 0x02, 0x8b, 0x88, 0x20, 0x82, 0x5b, 0x9c, 0xf2, + 0x00, 0xbf, 0xab, 0x80, 0xf5, 0x43, 0x9a, 0x2e, 0xf0, 0x20, 0xd7, 0x78, 0x2d, 0x78, 0xd3, 0xae, + 0x81, 0x5b, 0xeb, 0x87, 0x34, 0x5e, 0x15, 0xe2, 0x14, 0xe4, 0xc6, 0x50, 0xb9, 0x2c, 0x3c, 0x35, + 0x67, 0x66, 0x9b, 0x38, 0x85, 0x16, 0xf4, 0x3d, 0xa9, 0x8f, 0xb3, 0x95, 0xd6, 0x4b, 0x37, 0xf4, + 0x6c, 0xb6, 0x60, 0xf9, 0x90, 0x7c, 0xeb, 0xe4, 0xf2, 0xcd, 0x8b, 0xa9, 0x10, 0x2c, 0x44, 0x6c, + 0xae, 0x25, 0xcb, 0xdb, 0x9f, 0x2e, 0x87, 0x53, 0x53, 0x43, 0x73, 0xb1, 0xee, 0xfd, 0x0a, 0x65, + 0x50, 0xee, 0x63, 0x53, 0xc9, 0x6a, 0x69, 0xb9, 0x0c, 0xdc, 0x6c, 0xa8, 0x16, 0xeb, 0x66, 0x96, + 0x75, 0x47, 0x67, 0x1a, 0x58, 0xa7, 0x7d, 0xef, 0x53, 0xad, 0x52, 0x9d, 0x5a, 0xaa, 0x1b, 0x7d, + 0x6e, 0xa3, 0x6e, 0x83, 0xc0, 0xc7, 0x7e, 0xf7, 0xa9, 0xf0, 0xd1, 0xda, 0x06, 0x85, 0xcb, 0xf0, + 0x8e, 0x32, 0x06, 0x03, 0x74, 0xc9, 0x21, 0xea, 0xdb, 0x09, 0xe3, 0x09, 0xfc, 0xc8, 0xfe, 0x23, + 0x30, 0x7d, 0xf1, 0xef, 0x1a, 0x17, 0xa4, 0x7b, 0x84, 0x52, 0x99, 0xc7, 0xfd, 0x06, 0xd6, 0x7c, + 0x8d, 0xbd, 0xb0, 0x57, 0xf0, 0x67, 0xea, 0x83, 0xfd, 0xe4, 0x98, 0x38, 0x3b, 0xa6, 0x49, 0xd0, + 0x01, 0x58, 0x4d, 0x92, 0xc3, 0xf9, 0x8d, 0x4d, 0xe6, 0x62, 0x63, 0xd7, 0x9e, 0xd7, 0xfe, 0x1f, + 0x5a, 0xba, 0x81, 0xe0, 0xb5, 0xf8, 0x9e, 0x1d, 0xad, 0xdf, 0x4f, 0xbf, 0x38, 0xd7, 0xb1, 0x09, + 0xc7, 0xf8, 0xd8, 0xc1, 0xfa, 0x67, 0x2c, 0x1a, 0xf1, 0xe7, 0xd5, 0x8c, 0x05, 0x8f, 0x4e, 0xee, + 0x87, 0xa2, 0x91, 0x6e, 0xf9, 0xc1, 0x01, 0xca, 0x4f, 0x84, 0xdf, 0xb2, 0x84, 0x55, 0x75, 0x03, + 0x69, 0x34, 0x6a, 0x00, 0x9b, 0xc6, 0x35, 0x91, 0xae, 0xad, 0xd3, 0x88, 0xa9, 0xb4, 0x4f, 0x1a, + 0x17, 0x86, 0x59, 0xf3, 0xe7, 0xa2, 0x3c, 0x2e, 0xc1, 0x8b, 0xcf, 0xe3, 0xa4, 0xff, 0xa8, 0x70, + 0x0a, 0x41, 0x90, 0x55, 0x73, 0x53, 0xfd, 0x0d, 0xc0, 0x26, 0x3a, 0x30, 0xae, 0x51, 0x04, 0xad, + 0x69, 0x7f, 0xd1, 0x98, 0x91, 0xe0, 0x6e, 0x36, 0x91, 0xc6, 0xa3, 0xa6, 0x9d, 0xac, 0x13, 0xeb, + 0xdc, 0x20, 0x4b, 0x94, 0xea, 0x94, 0x5a, 0xdf, 0xc0, 0xad, 0xb7, 0xb0, 0xa9, 0xa4, 0xf7, 0x01, + 0xa3, 0xf3, 0x96, 0x85, 0x38, 0xc9, 0xcb, 0x55, 0xa6, 0xef, 0x64, 0x8e, 0xeb, 0xe5, 0x97, 0x2c, + 0x59, 0xd3, 0xf2, 0x01, 0x68, 0x59, 0x49, 0x1e, 0x11, 0x46, 0xd6, 0x1a, 0x2f, 0x7c, 0x25, 0x6e, + 0x61, 0x53, 0x15, 0x37, 0x1a, 0x17, 0x00, 0xfe, 0x71, 0xc7, 0x00, 0x16, 0xf1, 0xe7, 0xb8, 0x31, + 0xdd, 0xba, 0xc1, 0x02, 0x40, 0x1a, 0x3f, 0x33, 0xfe, 0xb9, 0xcc, 0x9f, 0x5c, 0x56, 0xdd, 0x0d, + 0xc0, 0x0a, 0x51, 0x00, 0x82, 0x7c, 0x98, 0xc1, 0x28, 0x22, 0xbf, 0x62, 0xd0, 0x1f, 0xf4, 0x26, + 0x45, 0xdc, 0xcb, 0x00, 0xa0, 0xc5, 0xcf, 0x64, 0xc6, 0xa9, 0x5c, 0xa3, 0xd2, 0x63, 0xc9, 0xdd, + 0x3a, 0x5f, 0x49, 0x8e, 0x76, 0xb5, 0x60, 0xf9, 0xed, 0x88, 0x40, 0xd7, 0xe0, 0x7d, 0x10, 0xf4, + 0x14, 0x14, 0xd0, 0x28, 0x00, 0x7c, 0xb9, 0x56, 0xf9, 0x9c, 0x16, 0xb6, 0xd0, 0xaa, 0xef, 0xc3, + 0x88, 0xfb, 0xea, 0xdd, 0x25, 0x52, 0x70, 0x43, 0x9c, 0xb0, 0x82, 0xb0, 0x14, 0x21, 0x94, 0x62, + 0x09, 0x4d, 0x80, 0x40, 0xed, 0x16, 0xbe, 0x70, 0x71, 0xd6, 0x83, 0x81, 0xd2, 0x5b, 0x98, 0x03, + 0x02, 0xb0, 0x41, 0x04, 0xd1, 0x76, 0x01, 0x13, 0xd2, 0x18, 0xba, 0x44, 0xe4, 0x4f, 0x09, 0x07, + 0x78, 0x9f, 0xa6, 0x49, 0xe2, 0x06, 0x30, 0xc0, 0x2f, 0x1b, 0x84, 0x70, 0xfd, 0x6a, 0x80, 0xbb, + 0xb4, 0x7d, 0x70, 0xec, 0x53, 0xf4, 0x18, 0x04, 0x8d, 0x48, 0x64, 0x77, 0x8b, 0xda, 0x37, 0x5f, + 0x10, 0x98, 0xa9, 0x1e, 0x0e, 0x1d, 0xf5, 0x3f, 0x1e, 0xbf, 0x14, 0x2a, 0xef, 0xc1, 0x26, 0xc1, + 0xfd, 0xa2, 0x94, 0x8f, 0xd6, 0x11, 0x10, 0x3e, 0xc9, 0x72, 0x26, 0xd7, 0xa8, 0x41, 0x5e, 0x77, + 0xe0, 0x40, 0x30, 0x6e, 0x47, 0x9d, 0x80, 0x60, 0x54, 0x1c, 0x2c, 0x1e, 0xed, 0x64, 0x1a, 0xb5, + 0x10, 0x43, 0xde, 0xe3, 0x0c, 0x29, 0xc3, 0x86, 0x01, 0xbc, 0x46, 0x3b, 0x5f, 0xed, 0x9c, 0x38, + 0xf3, 0x2f, 0x24, 0x61, 0xc3, 0xbd, 0xd1, 0x33, 0x38, 0x16, 0x76, 0xfa, 0xb9, 0x94, 0xe4, 0xe4, + 0x8e, 0x0f, 0x9c, 0xb6, 0x29, 0x13, 0x21, 0xf3, 0xca, 0x4c, 0xda, 0xef, 0x2f, 0xdb, 0xe2, 0x70, + 0x40, 0x4c, 0x32, 0x4b, 0x13, 0xc6, 0x07, 0x23, 0x5b, 0x7a, 0xed, 0xe2, 0x16, 0x9f, 0x3b, 0x76, + 0x8a, 0x53, 0x51, 0x1a, 0x73, 0xe7, 0xca, 0x1b, 0x43, 0xb3, 0x95, 0x4e, 0x7e, 0x7c, 0x1e, 0x7b, + 0x91, 0x08, 0x7d, 0x25, 0x1e, 0x8f, 0x85, 0x71, 0xa3, 0x67, 0xdc, 0x20, 0x1e, 0x1e, 0x1d, 0xb3, + 0x92, 0x07, 0x1e, 0xbb, 0x35, 0x14, 0xd1, 0x29, 0x49, 0x52, 0x3d, 0xcc, 0x24, 0x9e, 0x1a, 0x3d, + 0x2b, 0x14, 0x0e, 0x48, 0xe1, 0x6c, 0x63, 0x2c, 0x0c, 0x20, 0x10, 0x33, 0x66, 0x78, 0x45, 0x4a, + 0x9c, 0xd8, 0x58, 0xc0, 0xa4, 0x9e, 0x65, 0x22, 0xf1, 0x13, 0xd4, 0x7b, 0x33, 0x16, 0x06, 0xc0, + 0x07, 0x84, 0x12, 0x25, 0x83, 0x15, 0xfd, 0x79, 0x7a, 0x1c, 0xb8, 0xe0, 0xc6, 0x50, 0xa0, 0x46, + 0xcb, 0x8f, 0x93, 0x07, 0xab, 0x39, 0xd2, 0xf4, 0x1b, 0x93, 0x23, 0x36, 0x14, 0x37, 0xa3, 0x67, + 0xa1, 0xef, 0x80, 0xfe, 0x8e, 0xfe, 0x16, 0x52, 0x6e, 0x6c, 0xd6, 0xb0, 0x6e, 0x62, 0xf1, 0x1e, + 0xe0, 0x9b, 0x3b, 0x78, 0x4f, 0x8e, 0x9e, 0xc9, 0x5d, 0x37, 0x63, 0x61, 0x50, 0xe4, 0xe4, 0x74, + 0x0e, 0x06, 0x8c, 0xb4, 0x10, 0x88, 0xa1, 0x0b, 0x51, 0xc8, 0x1f, 0x20, 0x70, 0x2e, 0xb6, 0xa1, + 0x91, 0xdb, 0x30, 0x4e, 0xa9, 0x44, 0x9a, 0x23, 0xf2, 0x42, 0x04, 0x46, 0xc9, 0x92, 0xbb, 0x12, + 0x73, 0xd3, 0x96, 0x46, 0x6f, 0xc5, 0x55, 0xd9, 0x7f, 0x13, 0xc1, 0x4b, 0x60, 0x05, 0xd8, 0x7e, + 0x09, 0xdd, 0xf1, 0xc4, 0xe8, 0xd9, 0xdd, 0xb1, 0x30, 0x38, 0x90, 0xaf, 0x84, 0x41, 0x88, 0x51, + 0x02, 0xf4, 0x42, 0x88, 0xdc, 0x8e, 0x85, 0x41, 0x28, 0xd1, 0x0c, 0x5e, 0x80, 0x4a, 0xf4, 0x37, + 0x1e, 0x0e, 0xc7, 0x03, 0xc1, 0x7b, 0x34, 0x06, 0xe8, 0x07, 0xe4, 0xb4, 0x16, 0xe9, 0x93, 0xd0, + 0xc8, 0xdd, 0xf1, 0x36, 0xd0, 0x8c, 0x1b, 0xde, 0xb8, 0x1d, 0xa1, 0x13, 0xa8, 0x41, 0x33, 0x25, + 0x22, 0xa1, 0xb5, 0xb6, 0x7e, 0xa9, 0xe2, 0x16, 0xf4, 0xb7, 0x73, 0xfa, 0xda, 0xd4, 0xa6, 0x36, + 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, + 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, + 0xff, 0x1b, 0x09, 0xfe, 0xd3, 0xc7, 0xfd, 0x41, 0x78, 0x3a, 0x62, 0xd4, 0x48, 0x99, 0x7c, 0x51, + 0x9d, 0xd5, 0xf4, 0x32, 0x81, 0xf7, 0xcb, 0x86, 0x8e, 0x4e, 0x75, 0xc6, 0xcd, 0x8c, 0x39, 0xdc, + 0x02, 0x85, 0x66, 0x8b, 0xf6, 0x1c, 0x17, 0xe4, 0x4b, 0x8c, 0x57, 0x6e, 0x0f, 0xa1, 0x26, 0xd5, + 0xbe, 0xb3, 0xb6, 0x1e, 0x97, 0x66, 0xed, 0x68, 0xa7, 0xfa, 0x2b, 0xda, 0x5b, 0x0d, 0x49, 0x08, + 0xea, 0xea, 0x04, 0xb6, 0xd8, 0xca, 0xe2, 0x3c, 0xb1, 0x63, 0x9a, 0xa0, 0xce, 0xf7, 0x9c, 0xb5, + 0xd4, 0xa6, 0xe8, 0x47, 0x66, 0xba, 0x2c, 0x2f, 0xf4, 0x9e, 0x39, 0x42, 0x97, 0x6f, 0xba, 0xed, + 0x59, 0x5d, 0x21, 0x35, 0x15, 0xd6, 0x51, 0xe5, 0x29, 0x0b, 0x6e, 0x50, 0x31, 0xc4, 0x28, 0x75, + 0x16, 0xae, 0x70, 0xbf, 0x70, 0x7d, 0x8a, 0xf9, 0x74, 0xa9, 0x7b, 0x49, 0x13, 0x70, 0x77, 0x5c, + 0x47, 0x55, 0xb7, 0x4e, 0x5b, 0x4f, 0x8f, 0x40, 0x2c, 0xb8, 0xe9, 0xe9, 0xff, 0xea, 0x95, 0x1a, + 0x17, 0xae, 0xf2, 0xc2, 0xff, 0x46, 0xf3, 0x3d, 0x3e, 0x38, 0xc9, 0x78, 0xf6, 0x53, 0xcd, 0xfb, + 0xa3, 0xb3, 0x75, 0x3a, 0xbb, 0xf7, 0x4f, 0x61, 0xe2, 0x0f, 0xb7, 0xc9, 0x8e, 0x6e, 0xec, 0x32, + 0xef, 0x2e, 0x62, 0xdd, 0xe1, 0x4c, 0x6d, 0x23, 0x35, 0x85, 0x1b, 0x87, 0x77, 0x99, 0xd1, 0xc6, + 0x94, 0xc4, 0x98, 0x32, 0x9c, 0xb9, 0xa0, 0xce, 0x1c, 0x4b, 0xb5, 0x8d, 0x00, 0xee, 0x9b, 0x67, + 0x07, 0x4e, 0x3e, 0x07, 0xbb, 0x0a, 0xd3, 0x4b, 0x1e, 0x6f, 0xdc, 0xbc, 0xf8, 0x74, 0x02, 0x82, + 0x54, 0xe6, 0xca, 0x75, 0xc9, 0x65, 0x74, 0x47, 0x9f, 0xd1, 0x6e, 0xc5, 0xb0, 0x40, 0x7c, 0xda, + 0xd3, 0xaa, 0xbb, 0xde, 0x5c, 0xfd, 0x9d, 0x93, 0x68, 0xcc, 0xbe, 0x88, 0x8b, 0x42, 0xa8, 0xf7, + 0xbb, 0x13, 0x98, 0x3a, 0x83, 0x33, 0xf9, 0x5c, 0x63, 0x86, 0x8b, 0x86, 0x29, 0xa2, 0xb6, 0x1a, + 0xe2, 0x24, 0x78, 0x7c, 0x98, 0x07, 0x11, 0x17, 0x4d, 0xaf, 0x7a, 0x07, 0x9e, 0x68, 0xdb, 0x27, + 0xc1, 0xbe, 0x33, 0x75, 0x31, 0xb7, 0xd9, 0x82, 0xe5, 0x1a, 0x6e, 0x4a, 0x22, 0x37, 0x8f, 0x00, + 0xff, 0xd7, 0x34, 0x97, 0x85, 0x03, 0x6e, 0x18, 0xf2, 0xe7, 0xf8, 0x2c, 0x29, 0xc3, 0xf8, 0xf1, + 0xd1, 0x85, 0xe7, 0xf1, 0xfe, 0x19, 0x73, 0xea, 0xb0, 0xf8, 0xd4, 0x94, 0xc4, 0x92, 0x5a, 0xd6, + 0x9c, 0xc4, 0x98, 0xc6, 0xa3, 0xfc, 0xa4, 0x05, 0xcf, 0xca, 0x59, 0x09, 0x6a, 0x78, 0x31, 0x30, + 0x8a, 0xfd, 0x33, 0xd2, 0xe3, 0x4b, 0x5c, 0xb7, 0xc0, 0x0c, 0xa9, 0x2a, 0x15, 0x54, 0xd0, 0x35, + 0x6c, 0x4f, 0x6d, 0xf5, 0x80, 0x67, 0x60, 0xfc, 0x24, 0x69, 0x74, 0xaf, 0xb3, 0xd6, 0xaf, 0xb0, + 0xfb, 0xf3, 0x87, 0xeb, 0x83, 0x5b, 0xda, 0xb7, 0xf1, 0xb5, 0xdb, 0x16, 0x46, 0xf5, 0x60, 0xa2, + 0x31, 0x25, 0x31, 0x38, 0x26, 0x6b, 0xce, 0x87, 0x20, 0x8d, 0x11, 0xd3, 0x0e, 0xf9, 0x15, 0x83, + 0xf3, 0x0b, 0xbc, 0x82, 0x80, 0x89, 0xe5, 0x0d, 0x23, 0xfe, 0x9b, 0x69, 0x8f, 0xe3, 0xfa, 0x14, + 0x41, 0x94, 0xe0, 0x94, 0xc4, 0x52, 0xf1, 0x66, 0x4a, 0x22, 0x4e, 0x1e, 0xef, 0x90, 0x97, 0x3a, + 0x3b, 0x6b, 0x4d, 0x17, 0x85, 0x01, 0x92, 0xed, 0x60, 0xfa, 0x1e, 0x4e, 0x49, 0x04, 0x2d, 0x88, + 0x92, 0xd4, 0x97, 0xfe, 0xb9, 0x31, 0x25, 0xd1, 0x9f, 0x30, 0xb1, 0xc4, 0x84, 0xc1, 0x68, 0x82, + 0xf3, 0xa4, 0x43, 0x86, 0xf9, 0xdc, 0x3a, 0xe2, 0xfa, 0x8d, 0x78, 0x30, 0x89, 0x31, 0x42, 0x94, + 0x14, 0x96, 0x34, 0x31, 0x3d, 0x89, 0xfe, 0x9f, 0x99, 0xd4, 0xa5, 0xd0, 0xf2, 0x5a, 0x7c, 0xcf, + 0xeb, 0x89, 0x0b, 0xae, 0x8e, 0xe6, 0x4c, 0x1f, 0xf9, 0xf8, 0x82, 0x9a, 0x07, 0x7e, 0xe9, 0xba, + 0xed, 0x70, 0x7e, 0x02, 0x72, 0x52, 0xf3, 0x62, 0xea, 0x83, 0x1f, 0xd0, 0x28, 0xa0, 0xed, 0xcc, + 0x56, 0xc5, 0x08, 0x14, 0x1d, 0x1f, 0x2d, 0x42, 0xe5, 0x07, 0xbf, 0x96, 0x47, 0x63, 0x62, 0xc6, + 0x02, 0x37, 0x4b, 0x17, 0x9c, 0x82, 0x51, 0xe7, 0xcc, 0x10, 0x9c, 0xa8, 0x9b, 0xc5, 0x75, 0xaa, + 0x29, 0x38, 0x1b, 0xd0, 0x5e, 0xc1, 0x46, 0xce, 0x19, 0x5c, 0xc1, 0xb0, 0x84, 0xc1, 0x54, 0x64, + 0x8a, 0xc5, 0x54, 0x6c, 0x8d, 0x5e, 0xd6, 0xe5, 0x83, 0xd8, 0x97, 0xbc, 0x77, 0x6b, 0x32, 0x54, + 0x7c, 0xd3, 0x1d, 0xe6, 0x7a, 0xb5, 0x98, 0xf3, 0xee, 0x4c, 0x7e, 0xbf, 0x7f, 0x2b, 0x28, 0x21, + 0x6d, 0xcc, 0x26, 0x72, 0x79, 0x95, 0xe7, 0x94, 0x65, 0xcc, 0xe4, 0x5d, 0x98, 0xcc, 0x05, 0x37, + 0x0b, 0x30, 0xd9, 0xd2, 0xed, 0x3a, 0xca, 0xef, 0x9e, 0x96, 0xd4, 0xc6, 0x2b, 0xc7, 0xa7, 0xab, + 0xbc, 0xb8, 0x6a, 0xc4, 0x46, 0xce, 0x8a, 0x27, 0x7f, 0xbc, 0xd9, 0xa5, 0x97, 0x13, 0x95, 0xda, + 0x31, 0x19, 0xf0, 0xf2, 0xf5, 0xd3, 0x64, 0x79, 0xbd, 0xe4, 0x22, 0x34, 0x4a, 0xe9, 0xc5, 0xfc, + 0xea, 0x91, 0xfd, 0xfd, 0x1f, 0x6f, 0xc6, 0xf6, 0x2f, 0xae, 0x36, 0x94, 0x73, 0x4e, 0xd7, 0x77, + 0x72, 0x4f, 0xbb, 0x5a, 0xb0, 0x5c, 0xa7, 0x89, 0x19, 0x32, 0xb1, 0xe4, 0x7e, 0x28, 0x8f, 0x05, + 0x2d, 0x9a, 0x8f, 0xb4, 0xc3, 0x1d, 0xfa, 0xea, 0x4b, 0x87, 0xf6, 0x12, 0x02, 0xb5, 0x5c, 0xf7, + 0x91, 0x32, 0x4e, 0x87, 0x70, 0x2f, 0xdf, 0xfc, 0xa0, 0xfa, 0x84, 0xab, 0x43, 0x2b, 0x9f, 0x95, + 0xb9, 0x78, 0x2a, 0x57, 0xf6, 0x7d, 0x56, 0x15, 0x4e, 0xd1, 0x7c, 0xdc, 0x61, 0x5c, 0x30, 0x1d, + 0xed, 0x71, 0x67, 0xa7, 0x03, 0x81, 0xf2, 0x90, 0x02, 0xd5, 0x0f, 0xc8, 0x17, 0x23, 0x3c, 0xbe, + 0xc8, 0x1f, 0x00, 0xe6, 0x62, 0x1a, 0xe3, 0x09, 0x65, 0x07, 0xb9, 0x8a, 0x92, 0x2b, 0x8b, 0x24, + 0xf2, 0xa3, 0x51, 0xdf, 0xfa, 0x12, 0x9d, 0x53, 0xdc, 0xe4, 0x60, 0xc4, 0x45, 0xf3, 0x1e, 0x60, + 0x1a, 0x9a, 0xbc, 0xe3, 0x9b, 0x5c, 0xf5, 0x89, 0x02, 0xc1, 0x94, 0xd0, 0x35, 0xa5, 0xd4, 0xd5, + 0x31, 0x22, 0x36, 0xbb, 0x3b, 0xba, 0xf6, 0xdd, 0xef, 0x6a, 0x5e, 0x35, 0x63, 0xce, 0xf3, 0xce, + 0xf7, 0x5c, 0x13, 0xec, 0x73, 0x98, 0x58, 0x29, 0x66, 0xaa, 0x0c, 0xb4, 0x46, 0x6b, 0xc3, 0x9c, + 0xa3, 0xe8, 0x9b, 0x39, 0x85, 0x26, 0xd8, 0x49, 0xb0, 0xe2, 0x49, 0x17, 0xae, 0xed, 0x1b, 0x04, + 0x16, 0x19, 0xb6, 0x10, 0x36, 0x7d, 0x09, 0x73, 0x7e, 0x24, 0x76, 0xf8, 0x9d, 0xf8, 0xd8, 0xd4, + 0x27, 0x94, 0x0f, 0x76, 0x6b, 0x47, 0x85, 0x1f, 0x32, 0xd0, 0x73, 0xdf, 0xcb, 0xb0, 0x16, 0xb6, + 0x60, 0xf9, 0xc8, 0x98, 0x94, 0xa9, 0x6d, 0xac, 0x4f, 0x2d, 0xcb, 0x69, 0xc2, 0x6d, 0xd0, 0x25, + 0xcf, 0xa1, 0x18, 0x8a, 0xed, 0x19, 0xe7, 0x26, 0x5f, 0x36, 0xb3, 0x48, 0x1d, 0xed, 0x4d, 0xa3, + 0xfc, 0x3e, 0x75, 0x26, 0x0f, 0x85, 0x85, 0xa0, 0x8e, 0xcd, 0x2b, 0x78, 0xc7, 0x8f, 0x79, 0x90, + 0x93, 0x5a, 0x4c, 0xc0, 0x10, 0xd8, 0x48, 0x33, 0x9d, 0xf4, 0xa4, 0x76, 0x93, 0x58, 0xda, 0xdc, + 0xc0, 0x6c, 0xae, 0x58, 0xb7, 0x03, 0x4e, 0x6f, 0xdf, 0xca, 0xd4, 0xd8, 0x17, 0xa0, 0x45, 0x12, + 0x5e, 0x07, 0x54, 0xc2, 0xa8, 0xcb, 0x43, 0xe7, 0x99, 0x57, 0x56, 0x0d, 0xcb, 0xda, 0xaa, 0x23, + 0xab, 0x63, 0x1d, 0x15, 0x43, 0x2a, 0xa1, 0x24, 0x96, 0xe9, 0x42, 0xaa, 0x8a, 0x03, 0xf9, 0x24, + 0xf0, 0x85, 0xe2, 0x2f, 0xe1, 0x93, 0xcb, 0x37, 0x82, 0xfd, 0x53, 0x37, 0x50, 0x84, 0x93, 0x3a, + 0xd8, 0x9c, 0x1a, 0x47, 0x8e, 0x55, 0x8b, 0x11, 0xef, 0x8e, 0xfd, 0x5b, 0x1e, 0xe7, 0xfa, 0x62, + 0x6a, 0xe6, 0x78, 0xe7, 0x9f, 0x98, 0x60, 0x47, 0x74, 0xf5, 0x81, 0x2f, 0x0f, 0x3e, 0xdc, 0xe2, + 0x8a, 0x97, 0xaf, 0x72, 0xa2, 0x3e, 0x91, 0xea, 0xba, 0xf7, 0xf1, 0x90, 0xff, 0x88, 0x30, 0xaa, + 0x65, 0xb4, 0x56, 0x24, 0x47, 0x73, 0x47, 0x23, 0x92, 0x99, 0xef, 0xb0, 0xbc, 0xd2, 0xdf, 0x82, + 0xe5, 0x63, 0xc9, 0xea, 0xb4, 0x97, 0xc7, 0x0f, 0x7d, 0xc9, 0x07, 0x9f, 0x4f, 0x1e, 0xe4, 0xba, + 0x76, 0x80, 0xa6, 0x36, 0x52, 0xf3, 0xe2, 0x2a, 0xa7, 0x97, 0x27, 0x9a, 0x6e, 0xcc, 0xce, 0xf2, + 0xb2, 0x5e, 0x38, 0xa5, 0x7e, 0xc0, 0xfc, 0x9f, 0xe1, 0xb1, 0x79, 0x05, 0x4e, 0x78, 0xff, 0xfd, + 0xec, 0xb5, 0x46, 0xf1, 0x36, 0x1f, 0x0c, 0x9c, 0x7e, 0x2b, 0x4d, 0x28, 0xf7, 0x17, 0x51, 0x2f, + 0x6f, 0x7a, 0xd1, 0xf5, 0xc4, 0xbb, 0xba, 0x94, 0x4a, 0x02, 0xa6, 0x34, 0xa9, 0x16, 0x31, 0xd0, + 0xa1, 0xfb, 0x67, 0x55, 0x37, 0x33, 0xcf, 0xee, 0x6f, 0x54, 0x4c, 0x63, 0x76, 0x16, 0xae, 0x7b, + 0xfe, 0x0e, 0xec, 0x0e, 0x56, 0x27, 0xf3, 0x22, 0x3b, 0x4b, 0x47, 0x81, 0x44, 0x27, 0x12, 0x45, + 0x91, 0x84, 0x64, 0x36, 0x27, 0xe9, 0x0c, 0xbc, 0x04, 0xc5, 0x7b, 0x8f, 0x1b, 0xcd, 0x96, 0xc0, + 0x46, 0x06, 0x15, 0x55, 0x2e, 0x43, 0x3b, 0x79, 0x44, 0x78, 0x41, 0x2d, 0x20, 0xae, 0x33, 0xf9, + 0xf9, 0xe6, 0xff, 0xdc, 0x3a, 0x02, 0xf4, 0x77, 0xe6, 0xd1, 0x09, 0x5a, 0xb0, 0xbc, 0xe7, 0x9e, + 0xc1, 0x28, 0x5b, 0xb8, 0x5f, 0x0a, 0xca, 0xef, 0x84, 0x10, 0x69, 0x48, 0xc7, 0x69, 0xef, 0xe0, + 0x9e, 0xa4, 0x81, 0x4d, 0x7a, 0x1b, 0xb3, 0x1b, 0xe5, 0xc4, 0xe2, 0x1a, 0xb7, 0x7b, 0x75, 0x02, + 0xf0, 0x9f, 0x48, 0x5a, 0x37, 0x74, 0xec, 0xcd, 0x7e, 0xce, 0xf3, 0x8e, 0xcd, 0xce, 0x0a, 0x75, + 0x24, 0x3a, 0xa8, 0x25, 0xa1, 0x9a, 0xe0, 0x40, 0x85, 0x7f, 0x0c, 0x54, 0xb1, 0x01, 0x8a, 0x42, + 0xaa, 0xe1, 0xca, 0x02, 0xa7, 0x12, 0x31, 0xe0, 0x0c, 0x74, 0x31, 0x5b, 0x38, 0x3b, 0xd7, 0x80, + 0x52, 0x6b, 0xd4, 0x69, 0x5a, 0x53, 0x05, 0x42, 0x5f, 0xee, 0xa5, 0xea, 0x6c, 0xfa, 0x8c, 0xa8, + 0xb3, 0x6c, 0x1a, 0xfe, 0xba, 0x8c, 0xd6, 0x0d, 0x45, 0x2a, 0x0a, 0x76, 0x35, 0xfb, 0xd5, 0xab, + 0x8d, 0x7a, 0xb5, 0xa2, 0x99, 0x70, 0xb0, 0xbe, 0x63, 0x5f, 0x21, 0xc5, 0xad, 0x4d, 0x41, 0xeb, + 0x4a, 0x60, 0xf3, 0x71, 0x68, 0x67, 0xa7, 0x54, 0x12, 0xf6, 0xee, 0x57, 0x1c, 0xe7, 0x6b, 0x74, + 0x68, 0x2e, 0xd6, 0x35, 0xe9, 0x5b, 0xf5, 0x6e, 0x21, 0x8b, 0x34, 0x2a, 0x84, 0xcc, 0xbf, 0xb1, + 0xa1, 0x02, 0x11, 0xf7, 0x19, 0x66, 0xdf, 0x5e, 0x97, 0x1e, 0x9a, 0x24, 0xe8, 0xe3, 0xcd, 0xe9, + 0xd1, 0x24, 0x01, 0x0c, 0xcb, 0x77, 0x6c, 0x79, 0x4f, 0x6f, 0x0b, 0x96, 0x4f, 0x88, 0x01, 0x1c, + 0xdc, 0x60, 0xa7, 0x96, 0x23, 0x05, 0x96, 0x31, 0x52, 0x43, 0x4a, 0x9a, 0x72, 0xeb, 0x53, 0x53, + 0xcb, 0xa6, 0xa2, 0x92, 0xa1, 0xf0, 0xa2, 0x20, 0x5c, 0x5b, 0x36, 0x80, 0x5f, 0xee, 0x22, 0x00, + 0x95, 0xee, 0xd7, 0xc9, 0xf8, 0x49, 0xf1, 0x75, 0x6a, 0x67, 0x48, 0x77, 0xc4, 0x31, 0x7f, 0x37, + 0xbe, 0x98, 0xe7, 0x4c, 0xa7, 0x57, 0x74, 0xa7, 0x97, 0xf7, 0xd8, 0x26, 0x3f, 0xd6, 0x69, 0xbb, + 0x1a, 0x36, 0x85, 0x3a, 0x67, 0xbd, 0x5c, 0xb3, 0xc2, 0x63, 0x51, 0x6a, 0xf8, 0x6e, 0x98, 0x51, + 0xd0, 0xdd, 0xab, 0x19, 0x4f, 0xdb, 0x04, 0x16, 0xc4, 0xd2, 0x27, 0x4c, 0x99, 0x17, 0x23, 0xd6, + 0x34, 0x79, 0x4c, 0x3c, 0x95, 0x80, 0x7a, 0xc5, 0xe6, 0x2c, 0x46, 0x85, 0x0c, 0xe0, 0x44, 0xb1, + 0x64, 0xe1, 0x1f, 0xde, 0x78, 0xc8, 0xe7, 0x47, 0x27, 0x99, 0x02, 0x51, 0xec, 0x1e, 0x74, 0x7d, + 0x7c, 0x1d, 0x97, 0x4f, 0xd6, 0x12, 0xca, 0xad, 0xac, 0xa1, 0xe3, 0xdc, 0x61, 0x38, 0x4e, 0xd6, + 0xa2, 0xea, 0x0c, 0x95, 0x20, 0x2b, 0x8b, 0x5e, 0xc9, 0xe0, 0xb2, 0xca, 0x7b, 0x75, 0xe2, 0x72, + 0xc5, 0x10, 0xdf, 0x22, 0x70, 0x9f, 0x6a, 0x10, 0x3a, 0x88, 0x54, 0x4b, 0x39, 0xaa, 0xe9, 0x89, + 0x9c, 0x35, 0x6e, 0x76, 0x74, 0x97, 0xd8, 0x91, 0x71, 0xfe, 0x29, 0x14, 0x5f, 0xee, 0xf9, 0xce, + 0x9c, 0x68, 0x65, 0x0b, 0x96, 0x5f, 0x27, 0x54, 0xd1, 0x1d, 0x42, 0x9f, 0x73, 0x46, 0x30, 0x50, + 0xd8, 0x0b, 0xe5, 0x44, 0xaa, 0xfd, 0x86, 0x2e, 0x6a, 0x7a, 0x39, 0xef, 0x22, 0x71, 0x2d, 0x71, + 0x0f, 0x59, 0x7b, 0x4d, 0xc3, 0xb8, 0xa0, 0x4f, 0x7d, 0x7a, 0x37, 0x4c, 0x10, 0x49, 0xb8, 0xa8, + 0xe1, 0x4f, 0x05, 0xb7, 0x69, 0x03, 0xfe, 0x4d, 0xa1, 0xe7, 0x32, 0x97, 0xb2, 0x0b, 0xbd, 0x9c, + 0x80, 0xc3, 0xf8, 0x01, 0x84, 0x3f, 0x25, 0xcf, 0x61, 0x0a, 0x48, 0x3e, 0x80, 0x3c, 0x66, 0x70, + 0x76, 0xca, 0xe8, 0x29, 0xbe, 0x68, 0x2e, 0x62, 0x70, 0x11, 0x13, 0x6f, 0x07, 0x3b, 0x37, 0x4f, + 0x3f, 0x67, 0xa2, 0xda, 0xf2, 0x07, 0xa0, 0xa3, 0x3e, 0x09, 0x10, 0x70, 0xfe, 0xa7, 0x66, 0x34, + 0x00, 0xec, 0xa5, 0x93, 0x10, 0x0e, 0x48, 0x5c, 0xbc, 0x7e, 0xb8, 0x40, 0x45, 0x57, 0x5c, 0x02, + 0x0b, 0x5a, 0x99, 0xff, 0x24, 0x7f, 0xa1, 0x52, 0xb2, 0x0c, 0xd2, 0xda, 0x46, 0x4e, 0x5d, 0xf3, + 0xe2, 0x95, 0xef, 0xd8, 0x72, 0x42, 0xd3, 0x82, 0xe5, 0x0a, 0x88, 0x8e, 0x7d, 0xdb, 0x69, 0x4c, + 0xef, 0x65, 0x58, 0xbc, 0x10, 0xdd, 0xb1, 0xb8, 0xf9, 0x51, 0xd3, 0x3b, 0xf7, 0x33, 0xe4, 0x66, + 0x19, 0x11, 0xb8, 0x54, 0xc9, 0x21, 0xb7, 0x54, 0x49, 0x8d, 0x08, 0x2c, 0xc8, 0x57, 0x85, 0xb3, + 0xda, 0x8f, 0xba, 0x17, 0xbe, 0x04, 0x5c, 0x78, 0x64, 0xbe, 0x08, 0x71, 0xda, 0x17, 0x36, 0x60, + 0x58, 0x4c, 0x08, 0xb7, 0x6e, 0x96, 0x11, 0x89, 0xc3, 0x85, 0x47, 0x08, 0x0c, 0xa6, 0xf8, 0x0c, + 0x8d, 0xc1, 0xa5, 0x4a, 0x66, 0xfe, 0x19, 0xc7, 0x8c, 0x6a, 0x55, 0x85, 0x4a, 0x53, 0xeb, 0xc7, + 0xbb, 0x46, 0x3c, 0x3a, 0x66, 0xba, 0xdf, 0xa2, 0xb1, 0xf0, 0x08, 0x68, 0x41, 0x52, 0xa5, 0xc9, + 0xf5, 0x34, 0xa1, 0x97, 0x76, 0xd0, 0x16, 0x8d, 0x82, 0xae, 0xe8, 0x8b, 0xc6, 0x05, 0x44, 0x14, + 0xa2, 0x0c, 0x82, 0x6d, 0xf5, 0xfc, 0xe1, 0xda, 0xf5, 0xc4, 0x6d, 0x7f, 0x09, 0xe0, 0xf8, 0x48, + 0xcf, 0xf6, 0xb8, 0x5a, 0xce, 0x50, 0x41, 0x03, 0x5b, 0x01, 0x58, 0x9c, 0x28, 0x39, 0x86, 0xe4, + 0xa8, 0x57, 0x8f, 0x8d, 0xa2, 0xa5, 0x2d, 0xf2, 0x00, 0xe5, 0xb3, 0x46, 0xd0, 0xe2, 0xc1, 0x52, + 0x25, 0x6c, 0x73, 0xa9, 0x12, 0x10, 0x85, 0x14, 0x12, 0x74, 0xc5, 0xc1, 0x2d, 0x55, 0x52, 0x93, + 0xd7, 0xf9, 0x71, 0x72, 0xc2, 0xe8, 0x85, 0x01, 0x08, 0x1e, 0xb8, 0x6e, 0xc1, 0xbe, 0xda, 0x29, + 0x35, 0x96, 0x2a, 0xe9, 0x09, 0x70, 0x51, 0x48, 0x73, 0xa9, 0x92, 0x0d, 0x82, 0x26, 0x4b, 0x1b, + 0x47, 0xc7, 0x69, 0xcf, 0x77, 0x2a, 0x95, 0xe4, 0x3a, 0x5a, 0xb0, 0xdc, 0x57, 0xb0, 0x0f, 0x2e, + 0xb2, 0xe2, 0xcc, 0xd8, 0xc2, 0x59, 0xa3, 0x46, 0x62, 0xca, 0xef, 0x41, 0x6f, 0x7c, 0xf4, 0xf5, + 0xe4, 0xe6, 0x26, 0x76, 0xf3, 0x1e, 0x4f, 0x7e, 0xb9, 0xf3, 0xe9, 0x9b, 0xd3, 0x92, 0xe5, 0xb5, + 0x45, 0x4e, 0xca, 0xd5, 0xc9, 0xb8, 0x9b, 0x37, 0x02, 0x80, 0xbd, 0xdd, 0x2b, 0x99, 0xfd, 0x94, + 0xef, 0x24, 0x43, 0x4e, 0x22, 0x36, 0xf0, 0x8e, 0xc6, 0xb5, 0x52, 0xb7, 0xde, 0x19, 0x18, 0x03, + 0xa6, 0xfd, 0xcd, 0xc0, 0x3b, 0x14, 0x7f, 0x1d, 0x97, 0x02, 0x7d, 0xff, 0x11, 0x23, 0xaf, 0x22, + 0x96, 0x6a, 0xa9, 0xd4, 0x3e, 0x67, 0xdf, 0x09, 0x5c, 0x0b, 0xf0, 0xbb, 0x07, 0x20, 0xfe, 0xf1, + 0x46, 0xcc, 0x6f, 0xe8, 0x26, 0x09, 0xfc, 0x75, 0x8a, 0x0e, 0x83, 0xdd, 0xfd, 0x0c, 0xc0, 0x2e, + 0x3b, 0x83, 0x17, 0xc9, 0xf3, 0xa9, 0x65, 0xcf, 0x51, 0xd5, 0x11, 0x36, 0xbe, 0xae, 0x13, 0xc6, + 0x48, 0xe1, 0x2a, 0x10, 0x2c, 0x02, 0x53, 0x79, 0xe9, 0x56, 0x27, 0x03, 0x94, 0xaf, 0x28, 0x80, + 0x68, 0x2d, 0xc9, 0x50, 0x85, 0xd2, 0xb1, 0x9d, 0xc3, 0x38, 0x15, 0xb7, 0x32, 0x2e, 0x05, 0x8e, + 0x7e, 0x6b, 0x72, 0xb1, 0x89, 0x71, 0xae, 0x97, 0x13, 0xba, 0xdf, 0x17, 0xf4, 0x7b, 0x35, 0xac, + 0xb5, 0x2d, 0x58, 0x0e, 0x6e, 0x18, 0x86, 0x0a, 0x79, 0xaa, 0x3b, 0xaa, 0x36, 0x70, 0x5a, 0xc5, + 0x0f, 0x7e, 0x7d, 0x85, 0x6b, 0x8e, 0x2c, 0x73, 0x23, 0x02, 0x86, 0x37, 0x20, 0x2e, 0x19, 0x05, + 0x8a, 0x3b, 0x08, 0x33, 0x74, 0x00, 0x44, 0xeb, 0xde, 0xaf, 0x94, 0x0c, 0x1a, 0xc6, 0x50, 0xa8, + 0x7a, 0x03, 0x08, 0x42, 0x4f, 0xbe, 0x75, 0x9e, 0x65, 0x03, 0xaa, 0xa8, 0xae, 0xc0, 0xec, 0x2c, + 0x7d, 0xe4, 0xf1, 0xa6, 0x43, 0x98, 0xd7, 0x77, 0x2f, 0x50, 0x07, 0x86, 0x3a, 0xe1, 0x35, 0xa5, + 0x23, 0xf6, 0xcf, 0xab, 0xdb, 0x5b, 0x7f, 0xd9, 0xba, 0xb8, 0xb8, 0xb4, 0x31, 0x98, 0x3a, 0xf1, + 0xad, 0xd2, 0x9c, 0x04, 0x8e, 0x2b, 0x4b, 0x1a, 0x80, 0xe2, 0x84, 0x3d, 0xfe, 0x0a, 0xae, 0x4f, + 0x1d, 0x2f, 0x47, 0x00, 0x7a, 0x4c, 0xfb, 0x83, 0xbe, 0xbd, 0xa5, 0x7c, 0xac, 0xfb, 0xf4, 0x00, + 0x00, 0x8e, 0x69, 0x67, 0x8e, 0x17, 0x37, 0xcf, 0x02, 0x64, 0x37, 0xef, 0x74, 0x09, 0x84, 0x77, + 0xb3, 0xb9, 0x50, 0x7e, 0x63, 0xfe, 0x3c, 0xb7, 0x34, 0x8d, 0xca, 0xd5, 0x21, 0xe4, 0xd2, 0x42, + 0xfa, 0xd4, 0x59, 0x95, 0x57, 0xec, 0x70, 0xc2, 0x61, 0x20, 0x57, 0x50, 0x17, 0x78, 0x07, 0x2c, + 0xbd, 0x78, 0xfb, 0xab, 0x73, 0xdb, 0x32, 0xc5, 0xc1, 0xa0, 0x95, 0x4b, 0x44, 0x24, 0x09, 0x41, + 0x18, 0x74, 0x8d, 0x7b, 0x38, 0x5b, 0xab, 0x99, 0xe1, 0x76, 0x7d, 0xdf, 0x29, 0x67, 0x47, 0x8f, + 0x3c, 0xcd, 0xf2, 0x8a, 0x46, 0x24, 0xf9, 0xf2, 0xf8, 0x85, 0xef, 0x49, 0x79, 0xaf, 0x58, 0x4a, + 0xe7, 0x6c, 0x7d, 0x92, 0x6f, 0x78, 0x27, 0xcf, 0x41, 0xd6, 0xa8, 0xa3, 0x5f, 0x43, 0xc9, 0x94, + 0x62, 0x4c, 0xed, 0x0c, 0x48, 0xf6, 0xcc, 0x15, 0x4a, 0xbf, 0xb4, 0xf8, 0x0d, 0x07, 0xf1, 0x53, + 0xee, 0x75, 0x72, 0x3f, 0x6b, 0x50, 0x28, 0xe3, 0x40, 0xd0, 0x94, 0xfb, 0x95, 0x45, 0x5c, 0x83, + 0x1b, 0x8e, 0x8f, 0xea, 0x9f, 0x73, 0x50, 0xf8, 0x8c, 0xd1, 0x6d, 0xa9, 0x1e, 0x7b, 0x59, 0x4f, + 0xd9, 0x9d, 0xa8, 0x90, 0xbf, 0xc7, 0xd4, 0xd6, 0xf6, 0x24, 0x68, 0x07, 0xb0, 0xcc, 0x8b, 0x00, + 0xa1, 0xee, 0xfd, 0x48, 0x70, 0xbb, 0xbc, 0x08, 0x03, 0x59, 0x10, 0xb4, 0xd2, 0xfe, 0x0b, 0xce, + 0xdc, 0x8f, 0x9c, 0x6f, 0x37, 0x53, 0x56, 0x59, 0xc1, 0xed, 0xfa, 0x34, 0x53, 0x43, 0x73, 0xc9, + 0x3b, 0x01, 0x40, 0xf8, 0x74, 0x2e, 0x79, 0xee, 0x68, 0x38, 0x08, 0x1d, 0x90, 0xb8, 0xac, 0x8e, + 0x28, 0xbd, 0x0f, 0x7e, 0x01, 0xbb, 0xb4, 0x52, 0x5e, 0x07, 0x60, 0xe2, 0xec, 0xea, 0x43, 0xa4, + 0xb8, 0xb1, 0x81, 0xd5, 0xdc, 0x87, 0x6b, 0x99, 0x21, 0x5d, 0x91, 0x9c, 0x8a, 0xc2, 0x4d, 0xd8, + 0x0d, 0x10, 0x3f, 0x80, 0xfd, 0xdd, 0xfb, 0x5f, 0x72, 0xf8, 0x8e, 0x6a, 0xe1, 0x3b, 0x20, 0x91, + 0x36, 0xb6, 0x90, 0xf2, 0x87, 0x3a, 0xab, 0x04, 0x61, 0x8a, 0xe1, 0x25, 0xf3, 0xee, 0x52, 0x0b, + 0x04, 0xdc, 0x0d, 0x78, 0x57, 0x72, 0x1b, 0x40, 0x44, 0x01, 0x84, 0x7e, 0xeb, 0xeb, 0xc5, 0x46, + 0x6a, 0x6a, 0xb0, 0xc6, 0x2d, 0x9b, 0x13, 0x53, 0xc2, 0x07, 0xbf, 0x00, 0x27, 0xf2, 0xc1, 0xe2, + 0x39, 0x0c, 0xd0, 0x41, 0xac, 0xd2, 0xcd, 0x9e, 0xa6, 0xb3, 0xcc, 0xb1, 0xdd, 0x97, 0x37, 0xd2, + 0x40, 0x7b, 0x99, 0xad, 0xec, 0x44, 0x45, 0x24, 0x43, 0x51, 0xdf, 0x0e, 0xc0, 0x06, 0xbc, 0x8c, + 0xfa, 0x3f, 0xc7, 0x4f, 0x0f, 0x4f, 0x02, 0xe0, 0x88, 0x50, 0x23, 0x73, 0xd1, 0x83, 0x38, 0x39, + 0x34, 0x17, 0xa3, 0x1c, 0xd9, 0x05, 0x8d, 0x58, 0x72, 0xe1, 0x8f, 0xf0, 0xa6, 0xe7, 0xd1, 0x6e, + 0x5f, 0x63, 0x5c, 0x92, 0x36, 0x34, 0xf2, 0x45, 0xc4, 0x9a, 0x09, 0x7c, 0x64, 0x40, 0x36, 0xb7, + 0x60, 0xe8, 0x66, 0xbe, 0x95, 0x3a, 0x61, 0x2e, 0xaf, 0xf6, 0x52, 0x21, 0xab, 0x18, 0x7d, 0x85, + 0x10, 0x08, 0x92, 0x62, 0x63, 0x6a, 0xe4, 0x7a, 0x90, 0x2c, 0xc8, 0x49, 0x52, 0x03, 0x24, 0xa9, + 0x06, 0xe5, 0x39, 0x9e, 0x4a, 0x9a, 0x42, 0x3b, 0x9f, 0xbf, 0x73, 0xe1, 0xc3, 0x9b, 0xbf, 0x02, + 0x2c, 0xa4, 0x82, 0x11, 0x2e, 0xa7, 0xa3, 0x85, 0x87, 0x83, 0x64, 0x8d, 0x55, 0x06, 0x3c, 0x02, + 0xc3, 0xf8, 0x6c, 0x44, 0xd0, 0x48, 0x7e, 0x6f, 0xb9, 0x5a, 0x46, 0x4f, 0x0b, 0x96, 0x77, 0x89, + 0xcc, 0xeb, 0xde, 0x1e, 0xa5, 0x8c, 0x72, 0x8d, 0x48, 0xb9, 0x5b, 0xc7, 0xe7, 0xcb, 0xfc, 0x23, + 0x87, 0xcb, 0x25, 0x6c, 0xd8, 0x05, 0xf3, 0x67, 0x7c, 0x35, 0x33, 0x78, 0x23, 0x86, 0x66, 0x14, + 0x29, 0x35, 0xd3, 0x44, 0xa6, 0x0f, 0x71, 0xa8, 0x21, 0x9c, 0x19, 0x07, 0x3e, 0x1f, 0x58, 0x3e, + 0x91, 0x0a, 0x29, 0x54, 0x8e, 0x39, 0xaf, 0x3b, 0x73, 0xd2, 0x08, 0xec, 0x74, 0xaf, 0x58, 0xb8, + 0x2e, 0x83, 0x7c, 0xcc, 0xd0, 0xd1, 0xa9, 0x91, 0xc1, 0x5d, 0x8d, 0x40, 0x21, 0x9e, 0xe4, 0x86, + 0x82, 0xb9, 0x81, 0x5d, 0x37, 0xcf, 0x20, 0x36, 0x43, 0x15, 0x36, 0xfb, 0xf2, 0xbc, 0xe6, 0xbb, + 0x82, 0xd8, 0x3c, 0xce, 0x85, 0xef, 0xea, 0xaf, 0x1c, 0x4e, 0xe3, 0xc6, 0x7e, 0x39, 0x1b, 0x00, + 0x5b, 0xfc, 0xd0, 0x00, 0xf0, 0x5c, 0x63, 0x85, 0x24, 0x28, 0xea, 0x87, 0xbb, 0x5b, 0x40, 0x25, + 0xce, 0xec, 0x40, 0x74, 0x94, 0x24, 0xae, 0x2b, 0xa4, 0x18, 0x63, 0xbe, 0xd4, 0x34, 0xae, 0x59, + 0x76, 0x48, 0x49, 0xfa, 0xe1, 0xaf, 0xba, 0x3d, 0x16, 0xf9, 0x40, 0x50, 0x63, 0x08, 0x53, 0xc2, + 0x75, 0xc2, 0xfd, 0xe8, 0x4f, 0x78, 0xd2, 0xea, 0xe8, 0x1c, 0xde, 0xb5, 0xd7, 0xc7, 0x0c, 0xc9, + 0xd3, 0xd4, 0x77, 0x70, 0x39, 0x61, 0x69, 0xc1, 0x72, 0xe1, 0x9f, 0x01, 0x33, 0xae, 0x0b, 0x5f, + 0x6f, 0x7e, 0x81, 0xb8, 0xa4, 0xa9, 0x90, 0x25, 0xe8, 0x02, 0x80, 0xf8, 0x97, 0x1d, 0x70, 0x98, + 0x7a, 0x6a, 0xd9, 0xf0, 0x46, 0xb9, 0x9f, 0x5d, 0x80, 0x1e, 0x0c, 0x3a, 0x83, 0xf2, 0xdc, 0xe1, + 0xda, 0xf1, 0x50, 0x20, 0x45, 0x16, 0x4f, 0x35, 0x43, 0xbf, 0x10, 0x15, 0x4a, 0xa7, 0x26, 0xca, + 0xa6, 0x43, 0x86, 0x31, 0xe2, 0x06, 0x3b, 0x6e, 0xa4, 0x26, 0xd9, 0xc4, 0x32, 0x1c, 0xce, 0x2e, + 0xa6, 0xb2, 0x0e, 0x7c, 0x7c, 0x22, 0xf6, 0x4b, 0x38, 0x03, 0xe2, 0x5f, 0xfb, 0x09, 0x30, 0xca, + 0x70, 0xb8, 0x8a, 0x73, 0x5e, 0xf1, 0x3b, 0x81, 0xec, 0x5f, 0xe6, 0x6c, 0xa5, 0x0b, 0xca, 0x4a, + 0x17, 0x08, 0xd5, 0x49, 0xfc, 0xe7, 0x5f, 0xbf, 0xac, 0x62, 0xf1, 0x82, 0xf3, 0x66, 0xad, 0x93, + 0x50, 0xd3, 0xb9, 0x0c, 0xa8, 0xa0, 0x10, 0xa9, 0x96, 0x30, 0xde, 0x53, 0x63, 0x2c, 0x7d, 0xb2, + 0x60, 0xd2, 0x32, 0x35, 0x48, 0x7f, 0xca, 0xed, 0xc9, 0x5c, 0x5a, 0x9e, 0x40, 0xff, 0x35, 0x28, + 0x3c, 0x4f, 0x21, 0x8b, 0xc0, 0xa4, 0x7a, 0xd4, 0xf4, 0xe5, 0x07, 0x20, 0x1c, 0x63, 0xfb, 0xb5, + 0xf2, 0x44, 0xd0, 0x4e, 0x13, 0xdf, 0x59, 0xf9, 0xc8, 0xd6, 0x82, 0xe5, 0x77, 0x97, 0xcd, 0x01, + 0x10, 0x55, 0xa8, 0x41, 0x68, 0x5a, 0xc9, 0x37, 0x83, 0x80, 0x9f, 0xf7, 0x69, 0xd1, 0x85, 0x8b, + 0xa0, 0x6e, 0x03, 0x89, 0xf6, 0xf2, 0xf4, 0xf3, 0xf3, 0x25, 0x1e, 0xc7, 0x84, 0x5b, 0x4e, 0x08, + 0xa5, 0x0d, 0x1f, 0xe5, 0xbd, 0xd3, 0x5f, 0x2e, 0x38, 0x69, 0x8e, 0x54, 0x39, 0x89, 0x2e, 0x4e, + 0x25, 0x24, 0x37, 0x23, 0xfc, 0xe7, 0x7b, 0x7f, 0x85, 0x6d, 0x17, 0xc9, 0xc6, 0xf2, 0x10, 0x31, + 0xbf, 0x73, 0x1b, 0xb8, 0x3b, 0x4d, 0x2d, 0xf0, 0xce, 0x53, 0xa0, 0x10, 0x87, 0xdf, 0x19, 0x80, + 0x21, 0x03, 0xb0, 0x01, 0xd7, 0x6e, 0xec, 0x47, 0xc7, 0x7b, 0x92, 0x67, 0x53, 0x61, 0x63, 0x6f, + 0x53, 0x9c, 0x4e, 0xe7, 0x52, 0x10, 0x1f, 0x00, 0xc4, 0x9f, 0xa9, 0x6d, 0x24, 0x69, 0x20, 0x49, + 0xc9, 0x29, 0xdc, 0xa8, 0x3d, 0xb3, 0x7f, 0x85, 0x19, 0xd0, 0x61, 0xe3, 0x9b, 0xa9, 0x6c, 0x84, + 0xad, 0x91, 0x5b, 0xf5, 0x51, 0xaa, 0xeb, 0x5f, 0x27, 0x97, 0xba, 0xee, 0xfd, 0xdc, 0xf7, 0xd6, + 0xf7, 0x42, 0x5a, 0xb0, 0x5c, 0x20, 0x0a, 0xc1, 0xd4, 0x7b, 0x83, 0x3f, 0xf7, 0x83, 0xe9, 0xc9, + 0x9c, 0xe4, 0x03, 0xa8, 0x56, 0x71, 0x18, 0x52, 0xd9, 0x35, 0x1c, 0xa0, 0x2e, 0x15, 0x13, 0x5e, + 0x18, 0xa2, 0x08, 0xea, 0x6b, 0xa9, 0x1a, 0x3e, 0x85, 0x03, 0x19, 0x51, 0x76, 0x68, 0x8d, 0x8c, + 0x16, 0x81, 0xce, 0x46, 0x17, 0xb2, 0x14, 0x55, 0x71, 0x0f, 0x25, 0x37, 0xa2, 0xc5, 0x62, 0x8a, + 0xa9, 0x60, 0x86, 0x75, 0xd2, 0x82, 0x1b, 0x06, 0xd3, 0x10, 0x89, 0xec, 0x2c, 0xd5, 0x92, 0x35, + 0x87, 0x85, 0x9a, 0x18, 0xdb, 0xca, 0xea, 0x8e, 0xb7, 0xd7, 0x97, 0x0d, 0xab, 0x71, 0xd1, 0x2d, + 0x02, 0x3a, 0x20, 0x94, 0x13, 0x83, 0xb4, 0x12, 0x9c, 0x05, 0xaa, 0xae, 0xa0, 0x0d, 0xaa, 0xf3, + 0xb5, 0xd3, 0x73, 0x3f, 0x50, 0x89, 0x8b, 0xaf, 0xde, 0x38, 0x32, 0xf7, 0x91, 0x53, 0x8e, 0xce, + 0x5e, 0xf2, 0x26, 0x4a, 0xa5, 0x65, 0x15, 0x4e, 0x97, 0x85, 0x2f, 0x9b, 0x03, 0x37, 0xb8, 0x45, + 0x0e, 0xec, 0x31, 0x26, 0x4e, 0x28, 0x90, 0x3e, 0xbe, 0x1a, 0x48, 0x48, 0x61, 0xa6, 0x58, 0x3a, + 0x3b, 0x93, 0x2c, 0x3d, 0xe4, 0xc1, 0x88, 0x54, 0x8e, 0x8c, 0x14, 0x26, 0x07, 0xa1, 0xfc, 0xa4, + 0x96, 0x3c, 0x44, 0xe9, 0x61, 0x89, 0xc4, 0x85, 0xd6, 0x86, 0x05, 0xd1, 0x7a, 0x5b, 0xb0, 0xbc, + 0xf7, 0xde, 0x58, 0x64, 0xd0, 0xf0, 0xb2, 0x1a, 0xc6, 0xc6, 0x5e, 0x92, 0xfe, 0xcb, 0xe1, 0x4c, + 0xc6, 0x5c, 0xcb, 0x76, 0xbf, 0x5f, 0x7e, 0x9b, 0xc9, 0x64, 0x28, 0xaf, 0x4e, 0xbc, 0xbd, 0x1e, + 0xd1, 0x89, 0xb7, 0xbe, 0x2d, 0x82, 0x57, 0x0a, 0xd5, 0xad, 0x97, 0xf3, 0x9c, 0x7d, 0xe7, 0x62, + 0x17, 0x2c, 0x5d, 0x4d, 0x47, 0x50, 0x1b, 0xd2, 0x35, 0x6d, 0xce, 0x7b, 0x76, 0xec, 0xe1, 0x29, + 0x6a, 0xd7, 0xcc, 0x19, 0xf9, 0xe5, 0xf7, 0x59, 0xb2, 0x32, 0xa7, 0xd4, 0xc0, 0xf5, 0x26, 0xbc, + 0x71, 0x91, 0x1f, 0x5f, 0x3d, 0x8e, 0xb5, 0x73, 0xfa, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, + 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, + 0xd4, 0xa6, 0x36, 0xb5, 0xa9, 0x4d, 0x6d, 0x6a, 0x53, 0x9b, 0xda, 0xd4, 0xa6, 0xff, 0x1b, 0x09, + 0xfe, 0xd3, 0x37, 0x64, 0x4f, 0x0f, 0xa9, 0x08, 0x4c, 0x5d, 0x09, 0x1a, 0x52, 0x33, 0xfb, 0x3d, + 0x4c, 0xad, 0x6c, 0xc1, 0xdf, 0x04, 0x46, 0x23, 0x41, 0x83, 0x6a, 0xbf, 0x30, 0xfb, 0xff, 0xb6, + 0x77, 0xff, 0x3f, 0x4d, 0xe6, 0x09, 0x02, 0xc7, 0x61, 0xbe, 0x74, 0x76, 0x77, 0x76, 0x3b, 0x97, + 0xdc, 0xe5, 0x6e, 0x6e, 0x7f, 0xda, 0x5c, 0xc2, 0x6c, 0x70, 0x82, 0xde, 0xee, 0x1e, 0x7a, 0x38, + 0x8b, 0x66, 0x76, 0xc6, 0x9b, 0x03, 0x17, 0xdd, 0x20, 0x2d, 0x69, 0x19, 0xe0, 0x97, 0x41, 0x0e, + 0xb0, 0x98, 0xa8, 0xd5, 0x40, 0x07, 0xe6, 0xfe, 0x06, 0x57, 0xf4, 0x66, 0x04, 0x4d, 0x2e, 0xcb, + 0x90, 0x52, 0x1f, 0x48, 0xd0, 0x96, 0x1b, 0xb0, 0xf0, 0xcb, 0xfd, 0x22, 0x44, 0x48, 0xc4, 0x96, + 0x00, 0x63, 0x49, 0x2e, 0x8b, 0x44, 0xb0, 0x36, 0x51, 0x4b, 0x23, 0xc8, 0x78, 0xcf, 0xa7, 0x7c, + 0x6f, 0x9f, 0xa7, 0xa0, 0x95, 0x8f, 0xc2, 0xbc, 0x5f, 0xbb, 0x83, 0x80, 0x50, 0xe1, 0xcd, 0xd3, + 0x0f, 0x4f, 0x9f, 0xe7, 0xf3, 0x79, 0xaa, 0x1c, 0x77, 0x04, 0x22, 0x53, 0xce, 0x4a, 0xbf, 0x38, + 0x5d, 0x3b, 0xe5, 0xbf, 0x71, 0xfa, 0x6a, 0xf4, 0x6c, 0x73, 0x52, 0x13, 0x98, 0x5a, 0x46, 0x07, + 0xeb, 0x6d, 0x93, 0x13, 0x21, 0x47, 0x30, 0x38, 0x6d, 0x51, 0x6f, 0x6f, 0xe4, 0x89, 0x23, 0x1c, + 0x0c, 0x95, 0x78, 0xc6, 0x5b, 0x46, 0xe6, 0x3a, 0xcf, 0x25, 0x98, 0xee, 0xe2, 0xab, 0x38, 0xae, + 0xf9, 0x0c, 0x82, 0xad, 0xbe, 0xd7, 0xf0, 0x79, 0xf9, 0xb6, 0xce, 0x0b, 0x57, 0x82, 0x67, 0x9d, + 0xf2, 0xd9, 0x8e, 0x6b, 0xcf, 0xa3, 0xdb, 0xd1, 0xa3, 0x54, 0x59, 0x7d, 0xa1, 0xfe, 0xc7, 0x4f, + 0x7b, 0xed, 0x6e, 0x87, 0x67, 0xe4, 0xe1, 0x97, 0x81, 0xe1, 0xee, 0x91, 0x80, 0x6b, 0x6a, 0xda, + 0x32, 0x34, 0x7f, 0x79, 0xbf, 0xc7, 0x21, 0x66, 0x6c, 0x5d, 0x7d, 0x74, 0x71, 0xdf, 0xe8, 0x80, + 0x22, 0x9e, 0x9b, 0xa1, 0xb4, 0x3c, 0xfa, 0xc2, 0x3b, 0x53, 0x77, 0xf9, 0x4c, 0x68, 0x47, 0xdf, + 0xd9, 0x96, 0x9b, 0x3d, 0xe6, 0x96, 0xf6, 0xec, 0xd3, 0xfe, 0x50, 0xa0, 0xd7, 0xe4, 0x1a, 0x57, + 0xaa, 0x7f, 0x98, 0xb9, 0x16, 0xf1, 0xcd, 0xfa, 0x3b, 0x2f, 0xf5, 0x5a, 0xdd, 0x67, 0xac, 0xb3, + 0xf3, 0xd3, 0x81, 0xc8, 0xbd, 0x50, 0x9d, 0xd2, 0xe8, 0x0d, 0xd5, 0x5d, 0x89, 0x78, 0x9f, 0xf4, + 0x2f, 0x4e, 0x65, 0xeb, 0xb9, 0xd7, 0xd5, 0xf8, 0xed, 0x8d, 0x8c, 0xdc, 0xc6, 0x96, 0x74, 0x4b, + 0xbe, 0x2f, 0x2d, 0x23, 0x3f, 0xff, 0xb6, 0x7b, 0xe7, 0x8d, 0x8e, 0x63, 0xc1, 0xe3, 0x77, 0xfc, + 0xf6, 0x3b, 0xf6, 0xfa, 0xe5, 0xa7, 0xc4, 0xe9, 0x5b, 0x99, 0xab, 0xb9, 0x30, 0xbb, 0xcf, 0x67, + 0x9f, 0x3d, 0xd9, 0xe8, 0x1b, 0x29, 0xaa, 0x9e, 0xfa, 0x7e, 0xc2, 0xb9, 0xb7, 0xa3, 0xcb, 0x95, + 0x33, 0x54, 0x79, 0xfb, 0xbb, 0x1b, 0x3e, 0xfb, 0x11, 0x53, 0xa1, 0xd5, 0x1f, 0x2e, 0xb6, 0x2d, + 0x2c, 0x13, 0xf0, 0x5d, 0x55, 0x2a, 0xc5, 0x8a, 0xb1, 0x61, 0xab, 0xff, 0xea, 0xc2, 0x34, 0xd2, + 0x85, 0x25, 0x35, 0xc9, 0xcc, 0xd6, 0x30, 0x0f, 0x88, 0x5b, 0x1c, 0x50, 0x6c, 0x55, 0x96, 0xa1, + 0x47, 0x4d, 0xe5, 0x87, 0xbb, 0x67, 0x13, 0xcc, 0xbd, 0x70, 0x67, 0xea, 0x24, 0xdf, 0x55, 0xe8, + 0x38, 0xfb, 0x58, 0x71, 0x4d, 0xdd, 0xef, 0x4e, 0x7b, 0x78, 0xbf, 0xd3, 0x3a, 0x77, 0xdc, 0xd1, + 0x94, 0x2e, 0x56, 0xb6, 0x75, 0x8b, 0x59, 0x57, 0xe5, 0x6a, 0x27, 0xab, 0xdb, 0x3b, 0x53, 0x7f, + 0x29, 0x32, 0x9d, 0x93, 0x1b, 0x54, 0xca, 0xcd, 0xbe, 0x92, 0xe1, 0x5c, 0xab, 0x5f, 0x69, 0xf1, + 0x2b, 0xc7, 0x9a, 0x15, 0x87, 0xbd, 0x3d, 0x99, 0x4d, 0xe4, 0x5a, 0x64, 0x26, 0x14, 0xec, 0x54, + 0x1c, 0xd6, 0x81, 0x4b, 0x73, 0xa5, 0x96, 0xa1, 0xa0, 0x7a, 0x77, 0x0d, 0xa8, 0x63, 0x46, 0x97, + 0xa7, 0xf4, 0xca, 0xd8, 0xe1, 0x80, 0x5d, 0x4c, 0x5b, 0x52, 0x5a, 0xee, 0xcd, 0xa8, 0x7f, 0x9b, + 0xfd, 0xa4, 0x6e, 0x61, 0xbd, 0x9d, 0xab, 0x6c, 0x56, 0x3c, 0xdd, 0x93, 0xd5, 0xa3, 0xb4, 0x4c, + 0x8d, 0x46, 0xd7, 0xe0, 0x89, 0x89, 0x1a, 0x4f, 0x16, 0x66, 0xab, 0x84, 0x8a, 0xfc, 0xe1, 0xde, + 0xf6, 0xee, 0xd9, 0x6e, 0xe5, 0xf4, 0xec, 0x64, 0x4d, 0x9b, 0xad, 0xae, 0x7a, 0xf8, 0xe6, 0xec, + 0xfc, 0x7e, 0xb1, 0x2a, 0xce, 0x3c, 0xe6, 0xae, 0x6b, 0xaa, 0x1a, 0x09, 0x28, 0x57, 0xa6, 0x46, + 0xeb, 0x3b, 0xc4, 0x2c, 0xa6, 0xe8, 0x6b, 0x8d, 0x6e, 0xe7, 0x40, 0xad, 0x98, 0x83, 0xb8, 0xb0, + 0xf2, 0xae, 0xb1, 0x39, 0x7d, 0x40, 0x4c, 0x3d, 0x3a, 0x78, 0x36, 0xfa, 0xa3, 0x6e, 0xf8, 0xda, + 0xb2, 0x70, 0x9d, 0xe8, 0xfc, 0x2b, 0x4f, 0x7b, 0xf7, 0x0c, 0x96, 0x75, 0xd7, 0x38, 0x8a, 0xeb, + 0xc4, 0x3f, 0xe9, 0x2a, 0xf1, 0x47, 0x82, 0xd5, 0x63, 0xad, 0xc1, 0x5b, 0x67, 0x13, 0x4c, 0x5d, + 0x6c, 0xb6, 0x33, 0xb0, 0xc8, 0x1d, 0x58, 0x0a, 0x1b, 0x6a, 0x74, 0xb6, 0xf2, 0x85, 0x49, 0x5d, + 0x76, 0xf1, 0xf4, 0x12, 0x62, 0xbd, 0x58, 0xfa, 0xa3, 0x2f, 0x03, 0x9d, 0x6d, 0x1d, 0x8a, 0xeb, + 0x1b, 0xf7, 0xe0, 0xe9, 0xa2, 0xf3, 0xca, 0xad, 0x53, 0xed, 0x1f, 0xf6, 0x75, 0x7a, 0x1d, 0xd6, + 0xe1, 0xa2, 0x61, 0xf5, 0xae, 0x39, 0x53, 0x5f, 0x7a, 0xac, 0xa7, 0xb3, 0xbd, 0x5a, 0x2c, 0x95, + 0x16, 0xab, 0xa4, 0xeb, 0x8f, 0xcd, 0x1f, 0x0d, 0x07, 0x8f, 0x5b, 0x67, 0xc2, 0x5f, 0x1d, 0xaf, + 0x4f, 0xea, 0x69, 0xcb, 0xd4, 0xa1, 0x4d, 0xcc, 0x9c, 0x2a, 0x99, 0xcb, 0x9e, 0x59, 0x99, 0x46, + 0x5b, 0x6f, 0x0b, 0xde, 0x1d, 0x54, 0x5f, 0x1b, 0x1d, 0xf4, 0xdb, 0xbf, 0x9c, 0x19, 0xac, 0x7b, + 0x18, 0xfd, 0x8b, 0xb9, 0xd2, 0x3a, 0x31, 0xfb, 0xf6, 0x70, 0xff, 0xf8, 0x85, 0x9e, 0x27, 0xa1, + 0xe3, 0x67, 0x66, 0x42, 0x8e, 0xfb, 0x4f, 0x27, 0x42, 0xd3, 0x33, 0x73, 0xa7, 0xfd, 0xd1, 0xa7, + 0x50, 0x13, 0x83, 0x97, 0x98, 0xa5, 0x3b, 0x12, 0xba, 0xfa, 0xa8, 0xb8, 0xd2, 0x7d, 0xa7, 0xce, + 0xea, 0x0b, 0xb7, 0x3b, 0xca, 0x7b, 0xba, 0x66, 0x6c, 0x3d, 0x0f, 0xc6, 0x6e, 0x86, 0xbf, 0x3a, + 0xe3, 0x71, 0x8c, 0x1f, 0x9b, 0x34, 0x0f, 0xd8, 0x8e, 0xf5, 0xee, 0x19, 0x7a, 0x54, 0xb7, 0xdf, + 0xe2, 0x77, 0x37, 0x55, 0x15, 0x0d, 0x2b, 0x5e, 0x31, 0x1f, 0xb0, 0x7c, 0xb2, 0xc8, 0xaf, 0xde, + 0x07, 0xc4, 0xf0, 0xd9, 0xe3, 0x1f, 0x28, 0x51, 0xc7, 0xa8, 0x01, 0x71, 0x97, 0x50, 0xc7, 0xd5, + 0xe9, 0xac, 0xa1, 0x8e, 0xf9, 0xac, 0xe0, 0x54, 0x9b, 0xe7, 0x46, 0x71, 0x95, 0xaf, 0xb9, 0xb7, + 0xfd, 0xe6, 0xb5, 0x44, 0xf3, 0xe8, 0x4c, 0x3a, 0xc9, 0xb3, 0xc4, 0xbc, 0xf3, 0xa9, 0xb1, 0x3b, + 0x25, 0x91, 0x29, 0xbf, 0x23, 0xdc, 0xe8, 0x7d, 0x32, 0x14, 0xbe, 0xb8, 0xb8, 0x64, 0xd6, 0x53, + 0x12, 0x99, 0x5e, 0x9c, 0x8d, 0xe8, 0x6a, 0xbd, 0xfb, 0x9d, 0x6b, 0xba, 0x72, 0xca, 0xe3, 0x9a, + 0xb6, 0x8d, 0x9d, 0xbe, 0xa3, 0x5c, 0x34, 0x8f, 0x78, 0xe6, 0x9b, 0xf6, 0x8f, 0xf8, 0x14, 0x31, + 0x07, 0xb1, 0x63, 0x71, 0x69, 0x60, 0x96, 0xaf, 0x71, 0x52, 0xdc, 0x53, 0x27, 0x9d, 0x83, 0x7d, + 0x6b, 0xd7, 0x02, 0x9e, 0x58, 0x5c, 0xf7, 0x96, 0x73, 0xa8, 0xe0, 0xc2, 0xb9, 0xef, 0x72, 0xf3, + 0xcf, 0x5f, 0xb0, 0xd4, 0x5c, 0x8d, 0x2e, 0xa9, 0x7a, 0xec, 0x9d, 0xbc, 0x65, 0x3e, 0x37, 0x91, + 0x61, 0xb6, 0x7e, 0xdf, 0xd2, 0xfe, 0xbb, 0xa1, 0x8e, 0x4b, 0x0f, 0x9e, 0x04, 0x1b, 0x27, 0xd2, + 0x06, 0x6a, 0x1f, 0xd5, 0x28, 0xd5, 0x17, 0x47, 0xaf, 0x38, 0x2b, 0xbf, 0x39, 0xdf, 0xdc, 0xea, + 0xac, 0xba, 0x50, 0xf6, 0x20, 0xe7, 0x62, 0xc1, 0xc4, 0xba, 0xcf, 0xa2, 0x71, 0xd1, 0x39, 0x79, + 0xf8, 0x66, 0xab, 0xf3, 0x89, 0x29, 0xff, 0x61, 0x64, 0xb4, 0xcf, 0xec, 0x2d, 0x8e, 0xb4, 0xd7, + 0x7a, 0xbf, 0xde, 0x65, 0xb9, 0x35, 0xfe, 0xfb, 0x1b, 0xf9, 0x5f, 0x9e, 0x0b, 0x5b, 0xac, 0xf9, + 0x8d, 0x11, 0x4b, 0x57, 0xee, 0xf5, 0xf9, 0x74, 0x53, 0xbb, 0xad, 0x38, 0xfd, 0xb0, 0xc3, 0xa7, + 0x14, 0xba, 0x6b, 0x1b, 0x5a, 0xc6, 0x76, 0x0d, 0x45, 0xc4, 0x9b, 0xf3, 0xad, 0x53, 0xed, 0x8e, + 0x73, 0x62, 0xda, 0xf4, 0xb4, 0x2b, 0x6d, 0xa8, 0xc9, 0x2e, 0x56, 0x6e, 0x46, 0xc7, 0x5a, 0xad, + 0x7f, 0xad, 0x29, 0xc1, 0xa4, 0x2e, 0xbb, 0x53, 0x27, 0x79, 0xf6, 0xe1, 0xa2, 0x4b, 0x2d, 0x8b, + 0xdf, 0xc8, 0x89, 0xb3, 0xce, 0xa5, 0x85, 0x15, 0x0d, 0x69, 0x65, 0x87, 0xf2, 0x4d, 0xea, 0x0b, + 0x6b, 0xf4, 0x3b, 0x6c, 0x5a, 0x7e, 0x3e, 0x15, 0x57, 0xb1, 0x69, 0x6c, 0xe1, 0x43, 0xae, 0xba, + 0x2a, 0x66, 0x3d, 0xdd, 0x5f, 0xef, 0x3b, 0x6e, 0xb6, 0x29, 0x55, 0x7b, 0xeb, 0x2e, 0x17, 0xdd, + 0x09, 0xd7, 0x4d, 0x8f, 0x06, 0xbc, 0xca, 0x49, 0x9b, 0xba, 0xd9, 0x24, 0x73, 0x77, 0x6d, 0xaf, + 0x9f, 0x9d, 0x0b, 0xd9, 0xa2, 0xcf, 0x74, 0x7c, 0x69, 0x6a, 0xe6, 0x41, 0xfb, 0xb1, 0x99, 0x48, + 0xc8, 0xe1, 0x8a, 0x5e, 0x47, 0x41, 0x7d, 0xcd, 0xde, 0xa4, 0xfe, 0xbe, 0x57, 0x87, 0xf1, 0xd1, + 0x9e, 0xcb, 0xe5, 0xbd, 0xbb, 0x7c, 0x6e, 0x57, 0x55, 0x96, 0xff, 0xd2, 0x5c, 0x6f, 0xbb, 0xd2, + 0x25, 0x66, 0xae, 0x5e, 0xae, 0xda, 0x9f, 0x55, 0x77, 0x69, 0xae, 0xa8, 0x76, 0xa6, 0x54, 0x0c, + 0xfc, 0x1d, 0xf3, 0xfb, 0x46, 0xea, 0x15, 0x45, 0xec, 0xd4, 0x4d, 0xab, 0xdb, 0xcf, 0xe3, 0xf9, + 0x72, 0xbf, 0xbf, 0x76, 0xce, 0x3b, 0xdf, 0x3f, 0xaf, 0x4c, 0xaa, 0xb7, 0x77, 0xb1, 0x78, 0xde, + 0xeb, 0x55, 0x8e, 0x97, 0x88, 0x99, 0x7c, 0xe6, 0xfe, 0xc0, 0xd3, 0x5e, 0xb3, 0x5f, 0x51, 0x16, + 0x5e, 0x3b, 0xec, 0x3f, 0x35, 0x5f, 0x6e, 0xf5, 0xdb, 0x17, 0x57, 0x70, 0xa8, 0x2f, 0x6c, 0x95, + 0xa3, 0x03, 0xea, 0xfb, 0xd4, 0xbf, 0x78, 0x3a, 0x21, 0xee, 0x8a, 0x77, 0x47, 0xeb, 0x3b, 0x33, + 0x13, 0xcc, 0xa3, 0x53, 0x74, 0x92, 0x5b, 0x42, 0xee, 0x47, 0x63, 0x63, 0x5d, 0xde, 0xcb, 0x81, + 0x5e, 0xb3, 0xa7, 0xdb, 0x35, 0x26, 0xd6, 0xfd, 0x89, 0x05, 0xb0, 0xea, 0xaf, 0xac, 0x9b, 0x97, + 0xbb, 0x1d, 0x7b, 0xeb, 0xd4, 0xfb, 0x67, 0x78, 0xe9, 0x1e, 0xbd, 0x5f, 0x5c, 0x6a, 0x61, 0x69, + 0x05, 0xed, 0xf8, 0xc5, 0x6c, 0xf1, 0xac, 0x4e, 0x81, 0x9e, 0xf6, 0xaa, 0xa9, 0xc8, 0x1e, 0xf7, + 0x23, 0xc7, 0xbe, 0xb1, 0x7a, 0xa5, 0x73, 0x7a, 0xd7, 0x90, 0xfa, 0x2b, 0x6b, 0xcf, 0x57, 0x27, + 0xeb, 0xf6, 0x8d, 0xaa, 0xf7, 0xcf, 0xe8, 0x7a, 0xbb, 0x22, 0x75, 0x97, 0xa7, 0xa9, 0x48, 0x2c, + 0x22, 0xb1, 0x2c, 0x2d, 0x3a, 0xbc, 0x72, 0x4f, 0xbd, 0x37, 0x2c, 0x3c, 0x57, 0xac, 0xb7, 0xdf, + 0xda, 0xd8, 0xa2, 0x0c, 0x58, 0x1b, 0x27, 0x95, 0xc3, 0x85, 0x5f, 0x84, 0xb3, 0x6b, 0xcd, 0xc3, + 0x13, 0xb6, 0x1f, 0x7a, 0x5c, 0xd3, 0xea, 0x7d, 0xaa, 0xbb, 0xad, 0x59, 0xcc, 0xb6, 0xce, 0x38, + 0x68, 0x2e, 0x78, 0xd2, 0x63, 0xf2, 0x8a, 0x7d, 0x2b, 0x71, 0x03, 0x63, 0x6d, 0x21, 0x57, 0xbf, + 0xf3, 0x41, 0xeb, 0xd4, 0x88, 0x58, 0x37, 0xab, 0xfc, 0xee, 0x8f, 0xdf, 0x37, 0xa7, 0xdf, 0xab, + 0xad, 0xbd, 0xd4, 0x5f, 0x75, 0x6b, 0xd6, 0xd3, 0xd6, 0xfa, 0xf0, 0xda, 0x95, 0xd6, 0xa9, 0x1e, + 0x57, 0xe5, 0x3d, 0xf1, 0x23, 0x54, 0x72, 0xef, 0xd8, 0x6c, 0x65, 0x0b, 0xcf, 0x8a, 0x7d, 0xb6, + 0xeb, 0x42, 0xeb, 0xf1, 0xa2, 0xe1, 0xb2, 0x29, 0x9b, 0xf5, 0xaf, 0x4f, 0xf6, 0xef, 0xbe, 0x3d, + 0x7f, 0xba, 0x2f, 0xdf, 0x7f, 0xca, 0xbb, 0x6b, 0x67, 0x63, 0xd8, 0x62, 0x2a, 0x32, 0x37, 0xb5, + 0x54, 0xd6, 0x4d, 0x4f, 0x3b, 0x22, 0xea, 0x90, 0x55, 0xde, 0x6b, 0x19, 0x12, 0x73, 0x91, 0xfb, + 0xc3, 0xc7, 0x7a, 0xdc, 0xea, 0xbf, 0xeb, 0x0f, 0x07, 0xab, 0xac, 0x33, 0xd1, 0xf4, 0x9d, 0xea, + 0x6b, 0xbe, 0xf5, 0x9f, 0x80, 0xb7, 0x20, 0x7c, 0x83, 0x5f, 0x9f, 0xb2, 0x7e, 0x7d, 0xca, 0xb8, + 0x74, 0x83, 0x3d, 0x5d, 0xe7, 0x2e, 0xf4, 0x6b, 0xb3, 0x7a, 0xdf, 0xcd, 0x0e, 0x4f, 0x07, 0xe6, + 0xf7, 0xef, 0x16, 0xab, 0x31, 0x2c, 0xd1, 0x8b, 0x29, 0x38, 0x82, 0x62, 0x90, 0x10, 0xab, 0x36, + 0x1c, 0xe3, 0x5f, 0xde, 0x1d, 0x1c, 0x3c, 0x73, 0xd9, 0xf1, 0x51, 0x9d, 0xfb, 0xd8, 0xdd, 0x51, + 0xbf, 0x7d, 0xfa, 0xf8, 0x5e, 0x7f, 0x30, 0x38, 0x39, 0x18, 0x70, 0x8c, 0x8d, 0x79, 0xbd, 0xea, + 0xdd, 0xaa, 0xe6, 0x6a, 0xf8, 0xca, 0xb4, 0xd9, 0xe3, 0x56, 0x7f, 0x45, 0xfb, 0xc5, 0x93, 0x0e, + 0xd5, 0x9f, 0x52, 0x7f, 0xc9, 0xfa, 0x4b, 0xc5, 0x7e, 0xe2, 0xe5, 0x72, 0xf5, 0x06, 0xc4, 0xd5, + 0x5a, 0x7c, 0xdd, 0x9f, 0x8f, 0x77, 0x06, 0x23, 0x77, 0xce, 0x14, 0xfb, 0xc5, 0x2f, 0x94, 0xa1, + 0xf0, 0x65, 0xf5, 0xc5, 0x78, 0xf4, 0xf1, 0xc3, 0x19, 0xdf, 0xbc, 0xf7, 0x5a, 0xb0, 0x68, 0xcf, + 0xcd, 0xaa, 0xea, 0x89, 0x50, 0xed, 0x95, 0x48, 0xe0, 0x87, 0x99, 0xe3, 0xd6, 0xe9, 0xe2, 0xe0, + 0x49, 0xc7, 0xdc, 0xa8, 0xaf, 0x55, 0x7d, 0xc4, 0xa1, 0xee, 0xfe, 0xaa, 0x43, 0xb7, 0xf8, 0x05, + 0xed, 0x78, 0xbc, 0x7a, 0xf1, 0x7b, 0xdc, 0x8b, 0x07, 0xae, 0x1d, 0x7d, 0x1d, 0xd7, 0xc5, 0xb3, + 0x8d, 0x9c, 0x73, 0xe7, 0x1c, 0x2c, 0x38, 0x27, 0x56, 0xa7, 0xbb, 0xbf, 0x2a, 0x1d, 0x0e, 0xcf, + 0x36, 0xa5, 0x1f, 0x54, 0x1f, 0x44, 0xe4, 0x58, 0x1a, 0x82, 0xca, 0x99, 0xe3, 0xc7, 0xfe, 0xda, + 0xf4, 0x6d, 0xdb, 0xa3, 0xb1, 0x86, 0xac, 0x1c, 0x6b, 0xc7, 0x6d, 0x67, 0x6b, 0x65, 0xcc, 0x73, + 0x38, 0xa9, 0xe3, 0x75, 0x61, 0x61, 0xd9, 0xc8, 0xd4, 0x9c, 0xdb, 0xae, 0x4c, 0x8f, 0x76, 0x76, + 0x17, 0xf9, 0xe6, 0x1d, 0xe1, 0x26, 0x75, 0x1c, 0x16, 0xa3, 0x74, 0x9d, 0xab, 0xc8, 0xdf, 0xd9, + 0x2e, 0x96, 0xea, 0x0c, 0xb8, 0x83, 0xe2, 0x3a, 0x14, 0x99, 0x09, 0x9e, 0xc3, 0x3a, 0x43, 0x27, + 0x79, 0x79, 0xdb, 0xad, 0xae, 0xfb, 0xae, 0xa1, 0xcf, 0x27, 0x32, 0x6f, 0x54, 0x1e, 0xf1, 0x35, + 0x58, 0xfa, 0x4e, 0x7c, 0xe3, 0xfa, 0x30, 0x77, 0xd4, 0x73, 0xc5, 0x59, 0x71, 0x49, 0x7d, 0xb3, + 0xb8, 0x30, 0x3a, 0xc7, 0x5d, 0x2c, 0xd7, 0x53, 0x1f, 0x12, 0x45, 0xf7, 0x9d, 0x32, 0xf2, 0x0a, + 0x1a, 0x1a, 0xee, 0xe5, 0x5a, 0xef, 0x7c, 0x5d, 0xa3, 0xee, 0x6e, 0xd4, 0x3a, 0x33, 0xcf, 0x16, + 0xb8, 0xcb, 0x3c, 0x27, 0xd4, 0x5f, 0x1e, 0xae, 0xf3, 0xca, 0xb1, 0x5e, 0xd3, 0x50, 0x60, 0xf2, + 0x70, 0xc7, 0xfd, 0xee, 0x9d, 0x7d, 0x21, 0xaf, 0xbb, 0xa9, 0x2c, 0x54, 0xdf, 0x7a, 0xbe, 0xcd, + 0xea, 0xf7, 0x2a, 0xa1, 0x9c, 0x5c, 0x7f, 0xa4, 0x47, 0xbd, 0xdf, 0x37, 0xed, 0x15, 0x2b, 0x8c, + 0xbd, 0xe1, 0xb1, 0x7c, 0xb7, 0x78, 0xb3, 0xa5, 0xd9, 0x55, 0xa4, 0xee, 0xc3, 0x74, 0xdd, 0xca, + 0xff, 0x2e, 0x7a, 0x09, 0x81, 0xa4, 0xee, 0xd3, 0x33, 0xfd, 0xe1, 0x2a, 0xdb, 0x0f, 0x9e, 0x53, + 0x73, 0xe5, 0x62, 0x5f, 0x47, 0xfd, 0x55, 0x60, 0x2b, 0x0f, 0x05, 0xfc, 0xf3, 0xb6, 0x72, 0xb1, + 0x10, 0xa3, 0xca, 0xea, 0xee, 0x8a, 0xa8, 0xc3, 0xf2, 0xe5, 0xb6, 0xb1, 0xc5, 0xb1, 0xdf, 0x7e, + 0xcc, 0xab, 0x0e, 0xbc, 0x17, 0xc4, 0xef, 0x97, 0x96, 0x11, 0xf1, 0xb9, 0x6a, 0xd4, 0x8e, 0x48, + 0x74, 0x5d, 0xd3, 0xc2, 0x4e, 0x55, 0xa8, 0xae, 0x2b, 0x32, 0x3a, 0xea, 0x09, 0x76, 0x4e, 0x0d, + 0xd7, 0x87, 0x6d, 0x55, 0x3b, 0x6b, 0x3b, 0x66, 0x83, 0x73, 0xf5, 0xe3, 0x9d, 0xd3, 0x85, 0xbe, + 0xb0, 0xb7, 0x4c, 0xdd, 0x39, 0x4c, 0xb0, 0x44, 0x2c, 0x9c, 0xc3, 0xa8, 0x25, 0xf9, 0x68, 0xc2, + 0x44, 0x9e, 0xce, 0x56, 0x5e, 0x3d, 0xea, 0x2b, 0xb5, 0x4e, 0x5b, 0x6e, 0x06, 0x15, 0x73, 0x7b, + 0xbd, 0xfb, 0x4a, 0x20, 0x1c, 0xae, 0x8c, 0xf4, 0xee, 0xf6, 0xa8, 0x83, 0x44, 0x57, 0x5d, 0xa9, + 0xa3, 0x6a, 0x77, 0x9d, 0xab, 0xa9, 0xb6, 0x47, 0x59, 0x5a, 0xbd, 0xb8, 0x63, 0xba, 0x71, 0x61, + 0x39, 0xf6, 0xe2, 0x6e, 0x93, 0xe9, 0x4a, 0x5b, 0xbf, 0x73, 0x5a, 0xfc, 0xeb, 0x25, 0xd5, 0x8b, + 0xcf, 0x68, 0x2f, 0xd6, 0x83, 0x88, 0x2b, 0x2f, 0xfc, 0x45, 0xfd, 0x55, 0xd8, 0xe8, 0x74, 0x56, + 0x9e, 0xbd, 0xf6, 0xf5, 0x07, 0x39, 0x67, 0x0b, 0x7c, 0x76, 0xcb, 0xe7, 0x57, 0x7f, 0x3f, 0x98, + 0xdb, 0xe1, 0xe9, 0x0e, 0xf8, 0x8a, 0x17, 0xd6, 0xe1, 0xa8, 0xbb, 0x34, 0x33, 0xe2, 0x71, 0x6b, + 0xec, 0x02, 0x9d, 0x07, 0x91, 0x9e, 0x48, 0xb0, 0xf4, 0x4c, 0x92, 0x47, 0xbb, 0xdc, 0xea, 0x68, + 0xe0, 0xb9, 0xdc, 0x32, 0x96, 0xe5, 0xbf, 0x36, 0x5f, 0x3d, 0xe8, 0x78, 0x28, 0x9e, 0x99, 0x4e, + 0x59, 0xbc, 0x06, 0xc1, 0xae, 0xa1, 0xf0, 0x9d, 0x91, 0xd9, 0x9b, 0xd7, 0xd4, 0x1d, 0x1e, 0x9f, + 0xb8, 0x7e, 0x55, 0xbd, 0x4d, 0x29, 0x37, 0xf5, 0x9e, 0x3c, 0x13, 0x8e, 0x38, 0xc6, 0xad, 0x11, + 0x75, 0x04, 0x7b, 0xda, 0x6b, 0xfa, 0xca, 0xa6, 0x4c, 0x97, 0x04, 0x4a, 0xad, 0x91, 0xf6, 0xab, + 0xe3, 0x8d, 0xea, 0xc3, 0xfb, 0x87, 0x4b, 0x5f, 0x5f, 0x7f, 0xa4, 0x75, 0xd6, 0xdd, 0xae, 0x3e, + 0xc2, 0xb6, 0x5c, 0xbd, 0x95, 0xe0, 0xa1, 0x6d, 0x66, 0x96, 0x4e, 0xf2, 0xcc, 0x8d, 0x7e, 0x0f, + 0xb3, 0x1e, 0x7b, 0x55, 0xc5, 0x13, 0xc7, 0x78, 0x55, 0xa5, 0xfa, 0x30, 0xfe, 0x62, 0x85, 0x3a, + 0xd4, 0x5d, 0x18, 0x53, 0x47, 0xeb, 0x6e, 0xdf, 0xe2, 0x25, 0x4d, 0xc6, 0x95, 0x72, 0xb1, 0x20, + 0xb1, 0xb2, 0x4b, 0xdd, 0xeb, 0xd9, 0xbf, 0x4b, 0xbd, 0xa7, 0x8e, 0x15, 0x89, 0x05, 0x7e, 0xe6, + 0x01, 0xb1, 0xd0, 0x7a, 0xc0, 0xad, 0x0e, 0x7f, 0xd1, 0x3b, 0xb3, 0xc7, 0x2d, 0x86, 0xc4, 0xcb, + 0xea, 0xaf, 0x8f, 0xba, 0xd2, 0xce, 0xb9, 0x41, 0xb1, 0xef, 0xd4, 0x19, 0xbc, 0x5a, 0xdd, 0x6b, + 0x7e, 0x34, 0x35, 0xab, 0x3e, 0x64, 0x3f, 0x59, 0xb7, 0xdf, 0xe3, 0x9a, 0xab, 0xec, 0xb5, 0xa8, + 0xb7, 0x52, 0x24, 0xae, 0x69, 0x50, 0xf1, 0xa0, 0x36, 0x30, 0xa9, 0x3c, 0x70, 0x04, 0x3a, 0xbd, + 0x7d, 0xf9, 0xe7, 0xd5, 0x07, 0xf9, 0xd6, 0xc6, 0xb5, 0x97, 0xa4, 0xf2, 0x2f, 0xbe, 0x56, 0x71, + 0xe2, 0xf6, 0xbd, 0x9c, 0x43, 0x67, 0x6f, 0x37, 0xa4, 0xfb, 0x4b, 0x0a, 0xee, 0xf7, 0x3c, 0x99, + 0x1e, 0xbe, 0x58, 0xf4, 0x91, 0x67, 0xdc, 0x55, 0xdd, 0x3e, 0x73, 0x6a, 0x3e, 0xbb, 0xd0, 0x7e, + 0xe4, 0xd4, 0xcd, 0xd6, 0xbe, 0xae, 0x36, 0xa7, 0xf3, 0x64, 0xf1, 0xf0, 0x8d, 0x47, 0xd7, 0xc2, + 0x1f, 0xde, 0x58, 0x59, 0xfe, 0x17, 0xbd, 0x95, 0xbe, 0x13, 0xe7, 0xef, 0xa5, 0xf5, 0x45, 0x77, + 0x9b, 0xe2, 0xd6, 0xe2, 0x2d, 0x3d, 0xd9, 0xeb, 0x50, 0x20, 0xec, 0xb4, 0xfc, 0xf9, 0x6e, 0xb8, + 0xe8, 0xbb, 0x36, 0x53, 0xf9, 0x68, 0xf7, 0xc3, 0xf2, 0x04, 0x4f, 0x1b, 0x9e, 0x96, 0xad, 0x3d, + 0xb0, 0xb4, 0xdd, 0x0c, 0xa9, 0x3b, 0x59, 0x77, 0x07, 0xc5, 0xca, 0x2d, 0xd1, 0xa4, 0x48, 0xdd, + 0x03, 0xed, 0x16, 0xaf, 0x79, 0x4b, 0x2d, 0x33, 0xae, 0xd6, 0x39, 0xf5, 0x35, 0x57, 0xa5, 0xb7, + 0xbd, 0x6a, 0x74, 0x58, 0x7d, 0xcd, 0xe1, 0x1b, 0xe8, 0xf4, 0x34, 0x75, 0x9f, 0xae, 0x15, 0x57, + 0xe5, 0x29, 0x38, 0x3f, 0x9f, 0xa6, 0x6e, 0xea, 0x5f, 0x7f, 0x28, 0xae, 0xe9, 0x91, 0x21, 0xbe, + 0xd4, 0x9c, 0xe2, 0x4b, 0x55, 0xea, 0x40, 0x75, 0x3e, 0xbf, 0xc5, 0x79, 0xcf, 0xe3, 0xf9, 0x76, + 0xb0, 0xae, 0xf6, 0x9c, 0x3b, 0xd7, 0x6f, 0x2d, 0xf8, 0x4b, 0x6b, 0x5f, 0xdf, 0xd9, 0x98, 0x8b, + 0x91, 0x44, 0x57, 0x2b, 0x4f, 0xac, 0x5a, 0xfa, 0xb4, 0xf0, 0x64, 0xd9, 0x66, 0x71, 0x45, 0x16, + 0x71, 0x37, 0x09, 0x7b, 0x4b, 0x87, 0xef, 0xcc, 0xd6, 0x35, 0x64, 0x7e, 0x68, 0xf6, 0xa8, 0xbf, + 0x89, 0x6b, 0xdb, 0x15, 0x93, 0xe5, 0x35, 0x1c, 0x58, 0xda, 0x13, 0x0c, 0x2c, 0x6e, 0x8b, 0xce, + 0x56, 0x5e, 0xf3, 0xc2, 0x6b, 0x93, 0x16, 0x77, 0x15, 0xee, 0x06, 0xea, 0xc5, 0xb1, 0x35, 0x47, + 0xa4, 0xbb, 0x66, 0xf6, 0xe6, 0xf5, 0xf9, 0xa3, 0x83, 0x37, 0xaf, 0x3c, 0x1d, 0x1d, 0xac, 0x2f, + 0x79, 0xaa, 0xde, 0x49, 0x67, 0xc5, 0x65, 0x44, 0xba, 0xc7, 0xbc, 0x33, 0x0f, 0x4a, 0x1b, 0xc5, + 0xea, 0x6c, 0xf5, 0xf1, 0xf2, 0x8c, 0x58, 0x86, 0x28, 0x8e, 0x1c, 0x0c, 0xd6, 0x89, 0xcb, 0x2f, + 0xa8, 0xf7, 0xfc, 0x69, 0xcb, 0x80, 0x5d, 0x6c, 0xf9, 0xee, 0xfb, 0x63, 0x7b, 0x3d, 0xae, 0xd1, + 0x99, 0xf6, 0xaf, 0xa2, 0x3b, 0x3a, 0xe3, 0xd7, 0xa7, 0xc6, 0x06, 0x2e, 0x7f, 0x3f, 0x6e, 0x56, + 0xba, 0xe6, 0xf7, 0x8f, 0x0c, 0xcd, 0x37, 0x4d, 0xf5, 0xb4, 0xb9, 0xa3, 0xc7, 0xbd, 0x5a, 0xd4, + 0x47, 0xfa, 0xea, 0x6b, 0xa3, 0x81, 0x8e, 0xb9, 0xfd, 0xbb, 0x86, 0x82, 0xea, 0x03, 0xff, 0x01, + 0xf1, 0xa0, 0x2c, 0x7a, 0x49, 0xbb, 0xe8, 0xb1, 0xd4, 0x81, 0xcf, 0x27, 0xbd, 0x03, 0x8e, 0xe8, + 0xd2, 0xa7, 0xbf, 0x3c, 0x29, 0x2d, 0x39, 0x1f, 0xbc, 0x57, 0x79, 0xf3, 0x9b, 0x63, 0x4d, 0x3b, + 0xfa, 0x72, 0x2f, 0xfa, 0xac, 0xa7, 0x4b, 0xce, 0xff, 0xe0, 0x0d, 0xd5, 0x8b, 0x6f, 0x41, 0x7d, + 0x40, 0xa3, 0xee, 0x75, 0x5c, 0x8a, 0xf4, 0x8c, 0xf8, 0x2f, 0x5d, 0xb8, 0x17, 0x74, 0x94, 0x5c, + 0x68, 0x39, 0x54, 0xb7, 0x32, 0x96, 0xfd, 0xf9, 0xd7, 0x79, 0x85, 0x05, 0x0d, 0x3e, 0x5b, 0xce, + 0x37, 0xd7, 0x1f, 0x2c, 0x5d, 0xd8, 0xa1, 0x69, 0xe9, 0x89, 0x0c, 0xf3, 0xaf, 0x4f, 0x28, 0x07, + 0x13, 0x8e, 0xe5, 0xcd, 0xc5, 0x3a, 0xc9, 0x4d, 0xfd, 0xb5, 0xe7, 0x27, 0xd7, 0xb9, 0xd8, 0x85, + 0xb8, 0x06, 0x94, 0x12, 0x5d, 0xb3, 0xa7, 0xee, 0x4d, 0xb5, 0xa4, 0x4f, 0x15, 0x35, 0x36, 0x58, + 0x73, 0xf3, 0x0b, 0xc4, 0xba, 0x55, 0xf5, 0x2f, 0x4a, 0xc4, 0xc5, 0x82, 0xfa, 0xcf, 0x46, 0x17, + 0x10, 0xfa, 0x32, 0xf3, 0x7e, 0x7b, 0x4c, 0xfd, 0x90, 0x1d, 0xb7, 0xbe, 0x69, 0x49, 0x6f, 0x9d, + 0x0a, 0x7d, 0x54, 0x93, 0x7e, 0xee, 0x5a, 0xd3, 0xd1, 0xf6, 0x07, 0xee, 0xeb, 0xee, 0xdc, 0xfc, + 0xb9, 0xe2, 0xc2, 0x81, 0xe8, 0x9a, 0xd2, 0xfc, 0xb3, 0x2e, 0xe7, 0xc2, 0x05, 0x01, 0xfc, 0xee, + 0x86, 0x9e, 0xfa, 0xb3, 0xe7, 0x9e, 0x64, 0x3f, 0xe8, 0xad, 0x0a, 0xa5, 0x9b, 0xd4, 0x68, 0x73, + 0x19, 0xd6, 0xa3, 0x7f, 0x1d, 0x09, 0x7c, 0xd5, 0x54, 0x18, 0xb4, 0x7a, 0x14, 0xa7, 0xe9, 0x4c, + 0x51, 0x43, 0x7a, 0xa5, 0xbb, 0xfd, 0xcb, 0xb9, 0xb4, 0xa1, 0x86, 0x33, 0xd6, 0x88, 0xc7, 0xd1, + 0x94, 0xe5, 0x0b, 0xd5, 0x29, 0xad, 0xad, 0xb7, 0xce, 0xbb, 0x95, 0xa3, 0xe1, 0x5b, 0xe7, 0x22, + 0xf7, 0x72, 0x73, 0x1f, 0x46, 0x9c, 0x26, 0xc5, 0xed, 0x4a, 0x3f, 0x5e, 0xdb, 0xa0, 0x64, 0x47, + 0xba, 0x1a, 0x94, 0x8a, 0xe4, 0x96, 0xeb, 0x85, 0x9b, 0xc4, 0x61, 0xe4, 0xa7, 0x63, 0x87, 0x3d, + 0x76, 0xa5, 0xec, 0x49, 0x74, 0xf4, 0x57, 0x37, 0x98, 0x7b, 0xea, 0x9e, 0xcd, 0x05, 0xb1, 0xe4, + 0xf9, 0xa9, 0xd8, 0xd1, 0x71, 0x95, 0xa9, 0xbf, 0x7f, 0x12, 0xac, 0x3d, 0x35, 0xa5, 0xe9, 0x24, + 0x77, 0xa9, 0x23, 0xb3, 0xd7, 0x94, 0xc4, 0x17, 0xb8, 0x63, 0xf4, 0x41, 0x7b, 0xf5, 0xd4, 0x88, + 0x5f, 0x69, 0x13, 0x0f, 0xcf, 0xc5, 0xf2, 0x3a, 0x75, 0x78, 0xca, 0xf2, 0x5f, 0x6d, 0x19, 0xdb, + 0xeb, 0x77, 0xb7, 0x97, 0xa9, 0xfb, 0x91, 0x62, 0xd1, 0x78, 0xb0, 0x29, 0x3b, 0x54, 0x5f, 0xaa, + 0x6e, 0xe5, 0xea, 0xa3, 0xc6, 0x7b, 0xb3, 0x9e, 0xd2, 0x96, 0x11, 0x71, 0xfc, 0x5f, 0xbd, 0x87, + 0xb4, 0x5f, 0x16, 0xbf, 0xbc, 0x26, 0x43, 0x81, 0x40, 0x78, 0x5a, 0x3c, 0xe6, 0xbf, 0xa2, 0x3e, + 0xcc, 0xee, 0x76, 0x55, 0x7d, 0xd7, 0x3d, 0x57, 0x3e, 0x11, 0xea, 0xbf, 0xff, 0xb4, 0x77, 0x30, + 0x70, 0xea, 0xa9, 0x77, 0x71, 0x2d, 0xa2, 0x38, 0x7c, 0xb0, 0xb8, 0x6c, 0x5d, 0x3c, 0x6f, 0xb2, + 0xfa, 0x4b, 0x4e, 0xfd, 0x6d, 0xe2, 0xaa, 0x1c, 0x53, 0xef, 0x17, 0xd1, 0x8b, 0x38, 0x54, 0x1d, + 0xee, 0xbb, 0x36, 0x1b, 0x7d, 0xf4, 0x3b, 0x62, 0x76, 0x57, 0x15, 0xbb, 0xac, 0xea, 0x03, 0xff, + 0x1e, 0x6f, 0x5b, 0x73, 0x40, 0xdc, 0x9d, 0x1a, 0x7b, 0x8b, 0xa7, 0xa3, 0xed, 0x02, 0x09, 0xf7, + 0xee, 0x57, 0xbf, 0xe8, 0xed, 0x9b, 0xea, 0x6a, 0x73, 0xed, 0xc8, 0x6d, 0xf4, 0x8c, 0xf4, 0x9d, + 0xf2, 0x95, 0x4d, 0x15, 0xf6, 0x57, 0x7f, 0xeb, 0xda, 0xe3, 0x38, 0xa6, 0xee, 0x1a, 0xe4, 0xdf, + 0x0e, 0x3b, 0xf3, 0x0b, 0xe6, 0x12, 0xec, 0x97, 0x4f, 0x94, 0xe9, 0x24, 0x57, 0x66, 0xea, 0x1d, + 0xe5, 0xbd, 0x1e, 0x47, 0xb0, 0xfc, 0xde, 0x4c, 0xbd, 0xdd, 0x5b, 0x3b, 0xe6, 0xbf, 0x14, 0xfd, + 0x6d, 0x25, 0xce, 0x7a, 0x44, 0x0f, 0x53, 0x7f, 0x3f, 0xa9, 0x84, 0x6a, 0xfd, 0xee, 0xf4, 0x01, + 0x6b, 0x74, 0xe5, 0xfc, 0xed, 0x85, 0xcb, 0x20, 0xa8, 0xbf, 0xc6, 0x9a, 0x2d, 0xf6, 0xc2, 0x0b, + 0xa6, 0xe6, 0xa0, 0xb5, 0xd0, 0xdd, 0x5b, 0x58, 0x34, 0x5c, 0xf9, 0xc3, 0x68, 0x7b, 0xf0, 0xba, + 0x2b, 0xbd, 0xaf, 0xe3, 0xec, 0x15, 0xf5, 0x6e, 0xd8, 0x30, 0xa1, 0x3e, 0x10, 0xf1, 0x65, 0xd6, + 0x58, 0x4b, 0xae, 0x8f, 0x7c, 0xdb, 0xd6, 0x7a, 0x6c, 0x3a, 0x7b, 0xd8, 0x13, 0xbd, 0x74, 0x96, + 0x4f, 0x5c, 0x33, 0xe1, 0x96, 0xd2, 0xe6, 0x6d, 0x73, 0x4c, 0xce, 0x39, 0x6b, 0x4f, 0xdc, 0x77, + 0xed, 0xe8, 0xba, 0x1e, 0x70, 0xe5, 0xad, 0xb9, 0xa6, 0x43, 0xde, 0xe2, 0xd3, 0x61, 0xb6, 0x14, + 0xde, 0x09, 0x4d, 0x3f, 0x7e, 0xda, 0x75, 0xe2, 0xfc, 0xe3, 0xe0, 0x47, 0x79, 0x27, 0xdb, 0x26, + 0x58, 0xd3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x45, 0xe2, 0x4c, + 0x9f, 0xd4, 0x95, 0x1c, 0xf6, 0xbc, 0xd3, 0xcc, 0xa3, 0x93, 0x3b, 0x8f, 0xae, 0x39, 0x8b, 0xe4, + 0x92, 0x93, 0xbb, 0xb3, 0x49, 0x2e, 0x79, 0x89, 0x58, 0x9a, 0x85, 0xe4, 0x92, 0x93, 0x67, 0x16, + 0x93, 0x5c, 0xf6, 0x0a, 0xeb, 0x34, 0x92, 0x4b, 0xde, 0xca, 0x7d, 0x65, 0x24, 0x97, 0x9c, 0x7c, + 0xa2, 0x82, 0xe4, 0x92, 0x93, 0x9b, 0x6c, 0x24, 0x97, 0x3c, 0x96, 0x37, 0x64, 0x92, 0x5c, 0xf6, + 0x75, 0x04, 0xec, 0x24, 0x97, 0x9c, 0xbc, 0xb9, 0x86, 0xe4, 0x92, 0x93, 0xbb, 0x4d, 0x24, 0x97, + 0x9b, 0xbc, 0x60, 0xc2, 0x49, 0x72, 0xc9, 0xc9, 0xc3, 0x0a, 0xc9, 0xe5, 0x26, 0x37, 0x95, 0xdd, + 0x20, 0xf9, 0x36, 0xba, 0x74, 0x83, 0x79, 0x22, 0x9d, 0x9f, 0xa7, 0xe4, 0x9d, 0xfe, 0x70, 0x06, + 0xc9, 0x25, 0xef, 0x0e, 0x95, 0xe5, 0x90, 0x3c, 0x3d, 0x97, 0x35, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x56, 0x24, 0xce, 0xf4, 0x71, 0x56, 0xf8, 0x65, 0xcc, 0x30, + 0x72, 0x9e, 0xe1, 0xc4, 0xb1, 0xe4, 0x79, 0x74, 0x0a, 0xc9, 0x25, 0x4f, 0xea, 0xb2, 0xdf, 0x20, + 0xf9, 0x76, 0x9a, 0xd4, 0x15, 0x4e, 0xe7, 0xe7, 0x29, 0xfb, 0x99, 0x4a, 0x32, 0x48, 0x2e, 0x79, + 0x52, 0x97, 0x3d, 0x87, 0xe4, 0xb2, 0xe7, 0xd1, 0xe5, 0x91, 0x5c, 0xf6, 0x75, 0x04, 0xb2, 0x48, + 0x2e, 0xfb, 0x6a, 0x19, 0xd9, 0x24, 0x97, 0x7d, 0x1d, 0x01, 0x0b, 0xc9, 0x65, 0x5f, 0x2d, 0xa3, + 0x98, 0xe4, 0xb2, 0xaf, 0x23, 0x90, 0x46, 0x72, 0xd9, 0x57, 0xcb, 0x28, 0x23, 0xb9, 0xec, 0xeb, + 0x08, 0x54, 0x90, 0x5c, 0xf6, 0xd5, 0x32, 0x6c, 0x24, 0x97, 0x7d, 0x1d, 0x81, 0x4c, 0x92, 0xcb, + 0xbe, 0x5a, 0x86, 0x9d, 0xe4, 0xb2, 0xaf, 0x23, 0x50, 0x43, 0x72, 0xd9, 0x57, 0xcb, 0x30, 0x3d, + 0x4f, 0x72, 0xd6, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x91, + 0x38, 0xd3, 0xc7, 0x29, 0xd2, 0x85, 0xd9, 0xa2, 0x65, 0x15, 0x9c, 0x95, 0x96, 0x3c, 0x27, 0xba, + 0x82, 0xe4, 0xb2, 0x67, 0xfe, 0xdb, 0x48, 0x2e, 0x7b, 0x7d, 0x4b, 0x26, 0xc9, 0x65, 0xaf, 0xe2, + 0xb2, 0x93, 0x5c, 0xf6, 0x5a, 0xc5, 0x1a, 0x92, 0xcb, 0xbe, 0xe6, 0xbf, 0x89, 0xe4, 0x92, 0x17, + 0xb5, 0x37, 0x3b, 0x49, 0x2e, 0x39, 0xb9, 0x5b, 0x21, 0xb9, 0xe4, 0xab, 0x65, 0x34, 0xdc, 0x20, + 0xf9, 0x36, 0xba, 0x74, 0x43, 0x61, 0x73, 0x3a, 0x3f, 0x4f, 0xd9, 0x73, 0xdc, 0x33, 0x48, 0x2e, + 0x7b, 0x25, 0x47, 0x0e, 0xc9, 0x65, 0xaf, 0x57, 0xca, 0x23, 0xb9, 0xec, 0x55, 0x79, 0x59, 0x24, + 0x97, 0xbd, 0xf6, 0x34, 0x9b, 0xe4, 0xb2, 0x57, 0x58, 0x5b, 0x48, 0x2e, 0xfb, 0x3a, 0x02, 0xc5, + 0x24, 0x97, 0x7d, 0xb5, 0x8c, 0x34, 0x79, 0xc9, 0x59, 0xd3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x45, 0x3f, 0xfb, 0x65, 0x4a, 0xca, 0x6b, 0x73, 0xba, 0x73, 0x69, + 0x06, 0x62, 0x46, 0x0d, 0x27, 0x97, 0xa5, 0xd5, 0x6e, 0xc8, 0xa1, 0xb6, 0xb4, 0xda, 0xe6, 0x86, + 0x3c, 0x6a, 0xcb, 0xdb, 0xb6, 0x4d, 0x59, 0xd4, 0x96, 0x57, 0x7b, 0x22, 0x9b, 0xda, 0xf2, 0x6a, + 0xfb, 0x2c, 0xd4, 0x96, 0x37, 0x6e, 0xfb, 0x8a, 0xa9, 0x2d, 0x6f, 0xdb, 0xce, 0x4c, 0xa3, 0xb6, + 0xbc, 0xda, 0x69, 0x65, 0xd4, 0x96, 0x37, 0x92, 0xb8, 0x2b, 0xa8, 0x2d, 0xaf, 0x76, 0xb3, 0x8d, + 0xda, 0xf2, 0x46, 0x12, 0x7b, 0x26, 0xb5, 0xe5, 0xd5, 0x2e, 0xb3, 0x53, 0x5b, 0xde, 0x48, 0x12, + 0xae, 0xa1, 0xb6, 0xbc, 0xda, 0x13, 0x26, 0x6a, 0x4b, 0xab, 0x6d, 0x72, 0x3b, 0xa9, 0x2d, 0xaf, + 0x76, 0xb3, 0x42, 0xed, 0x2d, 0x77, 0xc5, 0x84, 0xa5, 0xa5, 0xfa, 0xe9, 0xdb, 0xf9, 0x67, 0x27, + 0xce, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xbb, 0x12, 0x67, 0x83, + 0x7e, 0xb4, 0xb3, 0x3d, 0xec, 0xb5, 0x9c, 0xa3, 0x95, 0x37, 0x93, 0xa9, 0x86, 0xda, 0x12, 0x67, + 0xe9, 0x99, 0xa8, 0x2d, 0xad, 0x76, 0x41, 0x83, 0x93, 0xda, 0xf2, 0xe6, 0xd6, 0x34, 0x28, 0xd4, + 0xde, 0xa2, 0x73, 0x6b, 0xcc, 0x0d, 0xe9, 0xfc, 0xec, 0x24, 0xae, 0xfb, 0xcd, 0xa0, 0xb6, 0xc4, + 0x35, 0xed, 0x39, 0xd4, 0x96, 0x57, 0xdb, 0x9d, 0x47, 0x6d, 0x89, 0x6b, 0x23, 0xb3, 0xa8, 0x2d, + 0x71, 0xdd, 0x6f, 0x36, 0xb5, 0x25, 0xae, 0x69, 0xb7, 0x50, 0x5b, 0xe2, 0xf5, 0x1a, 0x8a, 0xa9, + 0x2d, 0x71, 0x6d, 0x64, 0x1a, 0xb5, 0x25, 0xae, 0xfb, 0x2d, 0xa3, 0xb6, 0xc4, 0x35, 0xed, 0x15, + 0xd4, 0x96, 0x78, 0xbd, 0x06, 0x1b, 0xb5, 0x25, 0xae, 0x8d, 0xcc, 0x7c, 0x15, 0xb5, 0x59, 0x1b, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x9d, 0x3d, 0xd7, 0xf3, 0x06, 0xe9, + 0xcd, 0xf6, 0xb0, 0x38, 0x38, 0x6b, 0x28, 0x6f, 0x26, 0x53, 0x31, 0xb5, 0x25, 0xce, 0xf6, 0x48, + 0xa3, 0xb6, 0xc4, 0x99, 0x4c, 0x65, 0xd4, 0x96, 0x38, 0xdb, 0xa3, 0x82, 0xda, 0x12, 0x67, 0x32, + 0xd9, 0xa8, 0x2d, 0x71, 0xdd, 0x6f, 0x26, 0xb5, 0x25, 0xce, 0x64, 0xb2, 0x53, 0x5b, 0xe2, 0xba, + 0xdf, 0x1a, 0x6a, 0x4b, 0x5c, 0xd3, 0x6e, 0xa2, 0xb6, 0xc4, 0x75, 0xbf, 0x4e, 0x6a, 0x4b, 0x5c, + 0xd3, 0xae, 0x50, 0x7b, 0xab, 0x3e, 0x83, 0x41, 0x43, 0x3a, 0x3f, 0x3b, 0x89, 0xcf, 0xf7, 0x9b, + 0x41, 0x6d, 0x89, 0xeb, 0x7e, 0x73, 0xa8, 0x2d, 0x71, 0x4d, 0x7b, 0x1e, 0xb5, 0x25, 0xae, 0xfb, + 0xcd, 0xa2, 0xb6, 0xc4, 0x35, 0xed, 0xd9, 0xd4, 0xe6, 0x79, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0xbc, 0x96, 0xcf, 0x1b, 0x24, 0x65, 0x6e, 0xcd, 0x44, 0xba, 0x8d, + 0xb3, 0x86, 0xf2, 0xae, 0x16, 0x9c, 0x41, 0x6d, 0x89, 0x67, 0xc4, 0x73, 0xa8, 0x2d, 0x71, 0xb6, + 0x47, 0x1e, 0xb5, 0x25, 0xce, 0x64, 0xca, 0xa2, 0xb6, 0xc4, 0x59, 0x7a, 0xd9, 0xd4, 0x96, 0x38, + 0x03, 0xd5, 0x42, 0x6d, 0x89, 0xcf, 0xaa, 0x54, 0x4c, 0x6d, 0x89, 0x6b, 0x6c, 0xd2, 0xa8, 0x2d, + 0x71, 0xfd, 0x58, 0x19, 0xb5, 0x25, 0xae, 0x8d, 0xac, 0xa0, 0xb6, 0xc4, 0x75, 0xbf, 0x36, 0x6a, + 0x4b, 0x5c, 0xd3, 0x9e, 0x49, 0x6d, 0x89, 0xd7, 0x6b, 0xb0, 0x53, 0x5b, 0xe2, 0xb5, 0x48, 0x6a, + 0xa8, 0x2d, 0xf1, 0x3a, 0x3b, 0x26, 0x6a, 0xcb, 0x5b, 0x65, 0x3d, 0xe1, 0xa4, 0xb6, 0xbc, 0xda, + 0x26, 0x65, 0x3b, 0xd4, 0x66, 0x6d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x76, 0x26, 0xce, 0x06, 0x71, 0xd6, 0x70, 0x53, 0x67, 0x7b, 0x64, 0xd6, 0x71, 0x8e, 0x56, 0xde, + 0x4c, 0x26, 0x3b, 0xb5, 0x25, 0xce, 0xf6, 0xa8, 0xa1, 0xb6, 0xc4, 0x99, 0x4c, 0x26, 0x6a, 0x4b, + 0x9c, 0xed, 0xe1, 0xa4, 0xb6, 0xc4, 0x99, 0x4c, 0x0a, 0xb5, 0xb7, 0xea, 0x2a, 0x6b, 0x53, 0x3a, + 0x3f, 0x3b, 0x89, 0xcf, 0x1b, 0x99, 0x41, 0x6d, 0x89, 0xeb, 0x7e, 0x73, 0xa8, 0x2d, 0x71, 0x4d, + 0x7b, 0x1e, 0xb5, 0x25, 0xae, 0xfb, 0xcd, 0xa2, 0xb6, 0xc4, 0x35, 0xed, 0xd9, 0xd4, 0x96, 0xb8, + 0xee, 0xd7, 0x42, 0x6d, 0x89, 0x6b, 0xda, 0x8b, 0xa9, 0x2d, 0x71, 0xdd, 0x6f, 0x1a, 0xb5, 0x25, + 0xae, 0x69, 0x2f, 0xa3, 0xb6, 0xc4, 0x75, 0xbf, 0x15, 0xd4, 0x96, 0xb8, 0xa6, 0xdd, 0xb6, 0xb6, + 0x36, 0x6b, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x33, 0x71, 0x36, + 0x68, 0x8b, 0xcc, 0xf6, 0xc8, 0xae, 0xe7, 0xac, 0xa1, 0xbc, 0x99, 0x4c, 0x16, 0x6a, 0x4b, 0x9c, + 0xa5, 0x57, 0x4c, 0x6d, 0x89, 0x67, 0xc4, 0xd3, 0xa8, 0x2d, 0x71, 0xb6, 0x47, 0x19, 0xb5, 0x25, + 0xce, 0x64, 0xaa, 0xa0, 0xb6, 0xc4, 0x59, 0x7a, 0x36, 0x6a, 0x4b, 0x5c, 0x1b, 0x99, 0x49, 0x6d, + 0x89, 0xeb, 0x7e, 0xed, 0xd4, 0x96, 0xb8, 0xa6, 0xbd, 0x86, 0xda, 0x12, 0xaf, 0xd7, 0x60, 0xa2, + 0xb6, 0xb4, 0xda, 0x05, 0x3e, 0x27, 0xb5, 0xe5, 0xad, 0xb2, 0xf6, 0x29, 0xd4, 0xde, 0xa2, 0xab, + 0xac, 0xcd, 0xbe, 0x74, 0x7e, 0x76, 0x12, 0xd7, 0xfd, 0x66, 0x50, 0x5b, 0xe2, 0x9a, 0xf6, 0x1c, + 0x6a, 0x4b, 0x7c, 0x9e, 0xf6, 0x3c, 0x6a, 0x4b, 0x5c, 0x1b, 0x99, 0xb5, 0x3d, 0x6a, 0xb3, 0x36, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3b, 0xab, 0x7c, 0xff, 0xb5, 0x5b, + 0x1b, 0xa4, 0x73, 0x26, 0x6e, 0x69, 0x12, 0x9d, 0xc9, 0xce, 0x49, 0x4f, 0x29, 0xa9, 0x4d, 0x3e, + 0x27, 0xa9, 0xb7, 0xd8, 0x2c, 0xa3, 0xa5, 0x59, 0x2f, 0xe9, 0xfc, 0xe4, 0xe4, 0xdc, 0x49, 0xcc, + 0xbe, 0x0c, 0x52, 0x4b, 0x1a, 0xfa, 0x4d, 0x39, 0xa4, 0x96, 0x94, 0x7a, 0x22, 0x8f, 0xd4, 0x92, + 0x52, 0x37, 0x64, 0x91, 0x5a, 0xd2, 0x58, 0xdd, 0x90, 0x4d, 0x6a, 0x49, 0x5b, 0xb5, 0xdb, 0x42, + 0x6a, 0x49, 0xa9, 0x9b, 0x8b, 0x49, 0x2d, 0x69, 0x00, 0x09, 0xa7, 0x91, 0x5a, 0x52, 0xea, 0x89, + 0x32, 0x52, 0x4b, 0x1a, 0x40, 0xec, 0x15, 0xa4, 0x96, 0x94, 0xba, 0xcc, 0x46, 0x6a, 0x49, 0x03, + 0x88, 0x3b, 0x93, 0xd4, 0x92, 0x52, 0x37, 0xdb, 0x49, 0x2d, 0x69, 0x00, 0xc9, 0xac, 0xd9, 0xca, + 0xa9, 0xc5, 0xd9, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, 0x27, 0xce, + 0x36, 0x6c, 0xe7, 0x93, 0x41, 0x65, 0xee, 0xa3, 0xb9, 0x9c, 0x77, 0x93, 0x92, 0xfa, 0x8b, 0x86, + 0x4a, 0x52, 0x4b, 0xda, 0xaa, 0x1b, 0xaa, 0x49, 0x2d, 0x29, 0xf5, 0xc4, 0x6e, 0x52, 0x4b, 0x4a, + 0x6d, 0x3a, 0x4d, 0x6a, 0x49, 0x63, 0xb5, 0xaf, 0x96, 0xd4, 0x92, 0xb6, 0x6a, 0x9f, 0x99, 0xd4, + 0x72, 0x52, 0x97, 0xa7, 0xb5, 0x92, 0x7a, 0x4b, 0xae, 0xc6, 0x2c, 0x4b, 0xdb, 0xc1, 0x4f, 0x4e, + 0xd2, 0x78, 0x94, 0xb9, 0x93, 0xd4, 0x92, 0x7e, 0xcb, 0x36, 0xe7, 0x92, 0x5a, 0x52, 0x6a, 0xf7, + 0x21, 0x52, 0x4b, 0x1a, 0x40, 0xca, 0xf6, 0x92, 0x5a, 0x52, 0x6a, 0xfb, 0x3e, 0x52, 0x4b, 0x1a, + 0x40, 0x26, 0xac, 0xa4, 0x96, 0x94, 0x3a, 0x5c, 0x42, 0x6a, 0x49, 0x03, 0x48, 0xf3, 0x07, 0xaf, + 0x53, 0x6a, 0xd6, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe4, 0x88, 0xb3, + 0x0d, 0x9c, 0x0c, 0x5a, 0x3d, 0x1d, 0xe5, 0xd0, 0x41, 0xce, 0xbb, 0x49, 0x3a, 0x71, 0xbf, 0x97, + 0xd4, 0xb2, 0xa6, 0xa3, 0xec, 0x23, 0xb5, 0xac, 0x13, 0xf7, 0x56, 0x52, 0xcb, 0x9a, 0x8e, 0x52, + 0x42, 0x6a, 0x59, 0x4b, 0x04, 0x3f, 0x20, 0xb5, 0xac, 0xe9, 0x28, 0x47, 0x49, 0x2d, 0x6b, 0x89, + 0x60, 0x25, 0xa9, 0x65, 0x2d, 0x7c, 0xad, 0x26, 0xb5, 0xac, 0x25, 0x82, 0xbb, 0x49, 0x2d, 0x6b, + 0xe1, 0xeb, 0x69, 0x52, 0xcb, 0x5a, 0x22, 0x58, 0x4b, 0x6a, 0x59, 0x0b, 0x5f, 0xcd, 0xa4, 0x96, + 0xb4, 0x1a, 0x33, 0xb3, 0x95, 0xd4, 0x5b, 0x73, 0x35, 0x66, 0xe6, 0x0e, 0x7e, 0x72, 0x92, 0x86, + 0xfe, 0xb4, 0x9d, 0xa4, 0x96, 0xb5, 0x44, 0x30, 0x77, 0x33, 0x53, 0xb3, 0xb6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x47, 0x9c, 0x6d, 0xf8, 0x91, 0x4d, 0x47, 0xa9, 0xcd, + 0xe7, 0x44, 0x99, 0xa4, 0x49, 0x56, 0x66, 0x52, 0xcb, 0x49, 0x7d, 0xb4, 0xb9, 0x95, 0xd4, 0x5b, + 0x72, 0x8e, 0xc4, 0x17, 0xcd, 0x3b, 0xf8, 0xc9, 0xc9, 0x3a, 0x71, 0xbf, 0x93, 0xd4, 0xb2, 0xa6, + 0xa3, 0xe4, 0x92, 0x5a, 0xd6, 0x75, 0xd8, 0x0f, 0x91, 0x5a, 0xd6, 0x62, 0xaa, 0xbd, 0xa4, 0x96, + 0xb5, 0x44, 0x70, 0x1f, 0xa9, 0x65, 0x2d, 0x7c, 0xb5, 0x92, 0x5a, 0xd6, 0x72, 0xee, 0x12, 0x52, + 0xcb, 0x5a, 0x4c, 0xf5, 0x01, 0xa9, 0x65, 0x2d, 0x11, 0x3c, 0x4a, 0x6a, 0x59, 0x0b, 0x5f, 0x2b, + 0x49, 0x2d, 0x6b, 0x39, 0x77, 0x35, 0xa9, 0x65, 0x2d, 0xa6, 0xda, 0x4d, 0x6a, 0x59, 0x4b, 0x04, + 0x4f, 0xbf, 0xc2, 0xd4, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, + 0x11, 0x67, 0x1b, 0x38, 0x0f, 0x94, 0xf0, 0xc4, 0xfd, 0x07, 0x47, 0x38, 0xef, 0x26, 0x69, 0x3a, + 0xca, 0x51, 0x52, 0xcb, 0x3a, 0x71, 0x5f, 0x49, 0x6a, 0x59, 0xd3, 0x51, 0xaa, 0x49, 0x2d, 0xeb, + 0xc4, 0xfd, 0x6e, 0x52, 0xcb, 0x9a, 0x8e, 0x72, 0x9a, 0xd4, 0xb2, 0x96, 0x08, 0xd6, 0x92, 0x5a, + 0xd6, 0xc2, 0x57, 0x33, 0xa9, 0x25, 0xad, 0xc6, 0x74, 0xb7, 0x92, 0x7a, 0x6b, 0xae, 0xc6, 0x74, + 0xef, 0xe0, 0x27, 0x27, 0xeb, 0x59, 0x04, 0x77, 0x92, 0x5a, 0xd6, 0x12, 0xc1, 0x5c, 0x52, 0xcb, + 0x5a, 0xf8, 0x7a, 0x88, 0xd4, 0xb2, 0x96, 0x08, 0xee, 0x25, 0xb5, 0xac, 0x85, 0xaf, 0xfb, 0x48, + 0x2d, 0x6b, 0x89, 0xa0, 0x95, 0xd4, 0xb2, 0x16, 0xbe, 0x96, 0xbc, 0xc4, 0xd4, 0xac, 0x6d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x11, 0x67, 0x1b, 0x4c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x8c, 0xb5, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x39, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, + 0x61, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0e, 0x6b, 0x1b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x72, 0x58, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x92, 0xc3, 0xda, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x1c, 0xd6, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe4, 0xb0, 0xb6, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x87, 0xb5, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x39, 0xac, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc9, 0x61, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x0e, + 0x6b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x72, 0x58, 0xdb, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xc8, 0xa1, 0xc3, 0x39, 0x79, 0x1f, 0x7f, 0x76, + 0xe0, 0x37, 0x4b, 0x6f, 0xa7, 0xa6, 0xfc, 0xfd, 0xca, 0x7b, 0x7f, 0xab, 0xf9, 0xde, 0xdf, 0xad, + 0x7d, 0xef, 0xbf, 0x1d, 0xf9, 0x34, 0x3f, 0xc7, 0x7c, 0x60, 0xd5, 0x6d, 0xbe, 0x9f, 0x4a, 0xd7, + 0x94, 0x14, 0x73, 0xce, 0x27, 0x19, 0x39, 0x39, 0x2b, 0x6f, 0xa7, 0xbe, 0x99, 0xf1, 0x7f, 0x5a, + 0x61, 0x2e, 0xee, 0x51, 0x5f, 0xfc, 0x24, 0xe5, 0xef, 0x16, 0xdf, 0x34, 0x1a, 0x52, 0xdf, 0x78, + 0xf3, 0xad, 0x14, 0xf1, 0xe2, 0x6d, 0xc3, 0x3b, 0x3f, 0x8f, 0xfb, 0xf0, 0x5f, 0x88, 0x17, 0x6f, + 0xa6, 0xa4, 0xfe, 0x32, 0x7a, 0x9b, 0x7b, 0xc4, 0x2d, 0xfe, 0x6a, 0x83, 0x8c, 0x1b, 0x94, 0xf2, + 0x1f, 0xe2, 0xeb, 0xc0, 0x8f, 0x52, 0xec, 0xf6, 0xf6, 0xe6, 0xf2, 0x9d, 0x7d, 0xc5, 0x3b, 0xba, + 0x1b, 0xfd, 0xb3, 0x45, 0x17, 0xdf, 0x5a, 0x7e, 0x8f, 0xf1, 0xd9, 0xb3, 0xd4, 0xd4, 0xd4, 0x1a, + 0xca, 0x02, 0xdb, 0xdf, 0x1b, 0xef, 0xfd, 0xe4, 0x9d, 0x94, 0xf7, 0xde, 0x52, 0xff, 0xf7, 0xf6, + 0x7b, 0x6f, 0x1a, 0x53, 0xde, 0x7d, 0xeb, 0xdd, 0x37, 0xde, 0x4b, 0x79, 0xe7, 0xed, 0x9f, 0x3f, + 0x4b, 0x79, 0xb6, 0x3c, 0x8c, 0xc4, 0xbf, 0xfe, 0xec, 0x39, 0x5f, 0x8f, 0xbf, 0x9d, 0x14, 0xe3, + 0xaf, 0xc4, 0xff, 0x17, 0xde, 0x5e, 0x7c, 0x65, 0x7d, 0xcf, 0xd6, 0xf9, 0xdf, 0xaa, 0x5f, 0xdf, + 0x4b, 0xbf, 0x45, 0x97, 0xde, 0x61, 0x5c, 0x7a, 0x7b, 0xf1, 0x57, 0xf5, 0x4f, 0x7e, 0xfa, 0xb3, + 0x77, 0x7f, 0xfe, 0x0b, 0xe3, 0x7b, 0xb1, 0xff, 0x44, 0xcc, 0x2f, 0xf4, 0x67, 0xc6, 0xa5, 0xdf, + 0xde, 0xff, 0xa9, 0x7e, 0xdd, 0xff, 0x9a, 0xba, 0xf0, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0x9d, 0x70, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8b, 0x32, 0x20, 0x29, 0xf4, + 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0xff, 0x8f, 0xb3, 0xff, + 0xd2, 0xad, 0x2d, 0xfe, 0xb9, 0xf4, 0x62, 0xf9, 0x8d, 0xe5, 0xf7, 0x2f, 0xfe, 0xa3, 0xab, 0xde, + 0x5e, 0xfe, 0xd3, 0xa8, 0x71, 0x7b, 0x4b, 0xb7, 0xb5, 0xfa, 0x1b, 0x5e, 0xfd, 0xde, 0x98, 0x7f, + 0xd7, 0x10, 0x77, 0x33, 0xcb, 0x5f, 0xcb, 0x66, 0x6c, 0x6d, 0x9b, 0xde, 0x7f, 0xe9, 0xeb, 0xd7, + 0xfb, 0x4f, 0xff, 0xe3, 0x8c, 0x31, 0xff, 0x2d, 0xff, 0xdd, 0xaa, 0x1f, 0x89, 0xf6, 0x6d, 0xad, + 0xe9, 0xb6, 0x70, 0x53, 0xba, 0x3d, 0x57, 0x3e, 0x6e, 0xe5, 0x65, 0xa2, 0xaf, 0xeb, 0x79, 0xbf, + 0xaf, 0x57, 0xbe, 0xfd, 0xeb, 0x6d, 0x5f, 0x1a, 0xdb, 0xd9, 0xda, 0xef, 0x6b, 0xe1, 0xf6, 0x57, + 0xfe, 0x7c, 0xbe, 0xef, 0x79, 0xe5, 0x6d, 0xa3, 0x71, 0xbd, 0x6e, 0xab, 0x3f, 0x23, 0xc1, 0xcf, + 0xd1, 0xa0, 0x79, 0xff, 0x5a, 0xe7, 0xfb, 0x7a, 0xc5, 0xfd, 0x37, 0xfc, 0xf9, 0xf1, 0xfd, 0x0d, + 0xc6, 0xc5, 0x8d, 0x7d, 0xe9, 0x4f, 0x9d, 0xff, 0x8c, 0x9a, 0xc3, 0x83, 0x31, 0x6e, 0xfb, 0x8e, + 0x7d, 0x7f, 0xfc, 0x80, 0xb6, 0x4e, 0xff, 0xb8, 0x9b, 0x79, 0x09, 0xe3, 0xf2, 0x6b, 0xbc, 0xfd, + 0xaf, 0x1d, 0xff, 0x13, 0xf5, 0x4f, 0xd4, 0x4d, 0xeb, 0xe7, 0x1c, 0xbb, 0xed, 0xc7, 0x8e, 0x3f, + 0x06, 0xed, 0xf1, 0xff, 0x85, 0xbe, 0xaf, 0xad, 0x3b, 0xfe, 0xeb, 0xf6, 0x8f, 0x1d, 0xff, 0x75, + 0xf2, 0x68, 0x8f, 0x1b, 0xfa, 0x5f, 0x87, 0xf6, 0xf8, 0xbf, 0x66, 0x7f, 0xc0, 0xb0, 0x05, 0xc7, + 0xff, 0x4d, 0xdf, 0xff, 0x59, 0xbd, 0x9d, 0x6f, 0x7c, 0xff, 0x27, 0x6e, 0xbf, 0x46, 0x77, 0xfb, + 0x5d, 0x79, 0xf7, 0x26, 0xec, 0x00, 0xb1, 0xff, 0xcf, 0xfe, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0xff, 0xad, 0xd6, 0x3f, 0xe6, 0xf1, 0xa6, + 0xde, 0x71, 0xaf, 0x35, 0x8f, 0xf6, 0x35, 0x3e, 0x3f, 0xfe, 0xf8, 0xf0, 0xc2, 0x2b, 0x2b, 0x7f, + 0x1a, 0xb4, 0x1f, 0xe0, 0xeb, 0x3e, 0x8e, 0xd5, 0x3c, 0x7a, 0xf9, 0x02, 0xe7, 0x01, 0xb4, 0x1f, + 0x6f, 0x1b, 0x75, 0x0e, 0x00, 0xae, 0xf9, 0x7b, 0x8d, 0xef, 0xe3, 0x65, 0xf7, 0x8f, 0x3d, 0xde, + 0xbe, 0x74, 0xe8, 0x40, 0xff, 0xb8, 0xbb, 0xd1, 0x90, 0xe8, 0xb8, 0x98, 0xd6, 0x71, 0x19, 0x83, + 0xc6, 0xe7, 0x6d, 0xf4, 0xf3, 0xe3, 0xfb, 0x27, 0x7b, 0x1e, 0x20, 0xfe, 0xd6, 0x63, 0x3f, 0x5e, + 0x6b, 0x5b, 0x8c, 0x3b, 0xb8, 0xf1, 0x12, 0xfb, 0xaf, 0xde, 0x10, 0xe3, 0x8f, 0x07, 0x6b, 0x1c, + 0x37, 0x4e, 0x7c, 0xfc, 0x59, 0xf3, 0xb8, 0x7c, 0xa2, 0x71, 0x4f, 0xe7, 0x18, 0x9e, 0xc6, 0x59, + 0x98, 0x17, 0x3f, 0x0f, 0x90, 0xa8, 0xbf, 0xc1, 0xf0, 0x2a, 0xfb, 0xc7, 0xdd, 0x3f, 0x0d, 0xda, + 0xc7, 0xe3, 0x97, 0xc7, 0x11, 0xa3, 0xd6, 0xf8, 0xa3, 0x37, 0x7e, 0xac, 0x3a, 0xce, 0x6c, 0xd4, + 0x3e, 0xc0, 0xa8, 0xf1, 0xf9, 0xc6, 0xf5, 0xc7, 0x9f, 0x8d, 0x9f, 0x07, 0x48, 0xfc, 0x75, 0x19, + 0x74, 0x0e, 0xff, 0xc5, 0xde, 0xbc, 0xe6, 0x30, 0xf5, 0x12, 0xc7, 0x9f, 0xd5, 0xe7, 0xad, 0xb4, + 0x87, 0x67, 0xfd, 0x63, 0xea, 0xb1, 0xdf, 0xb9, 0xee, 0x76, 0xb6, 0x81, 0xed, 0x7f, 0xbd, 0x2d, + 0xf4, 0x85, 0xcf, 0x03, 0xe8, 0xdc, 0xba, 0xde, 0xeb, 0x89, 0xb7, 0x82, 0x4d, 0x19, 0xff, 0x0d, + 0x3a, 0xe3, 0x7f, 0xdc, 0x79, 0x5b, 0x83, 0xe6, 0xe7, 0xc7, 0x8e, 0xbf, 0x1b, 0xeb, 0xff, 0xa2, + 0xe3, 0xff, 0x46, 0xcf, 0x03, 0xac, 0xd7, 0x3f, 0xc1, 0xf8, 0xbf, 0xe6, 0x4b, 0xde, 0xac, 0xfe, + 0xeb, 0xef, 0xff, 0x68, 0x9f, 0x5f, 0x89, 0xff, 0xfc, 0xd8, 0xfb, 0xf3, 0xda, 0xe3, 0xef, 0xcf, + 0xbb, 0xff, 0xa3, 0xb3, 0xdf, 0xf1, 0xdc, 0xe7, 0x01, 0x8c, 0x3a, 0xfb, 0x53, 0xfa, 0xfb, 0x3f, + 0x5a, 0xe3, 0xc2, 0xe6, 0xed, 0xff, 0x80, 0xc7, 0x5f, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, + 0x1f, 0xf4, 0xa7, 0x3f, 0x36, 0xb7, 0x7f, 0xfc, 0xfc, 0xfb, 0xb8, 0xe3, 0x65, 0x06, 0x7e, 0x4c, + 0x9b, 0xd9, 0x3f, 0xa6, 0xf1, 0xca, 0xe3, 0x7a, 0xcd, 0xf9, 0xc7, 0xd8, 0xdc, 0xfe, 0x49, 0xce, + 0x47, 0xa5, 0x7f, 0x12, 0xe3, 0x4f, 0xec, 0x71, 0xb2, 0x4d, 0x5c, 0xb7, 0x43, 0xff, 0x98, 0xe3, + 0xfc, 0x7a, 0xdb, 0x3f, 0x5b, 0xff, 0xa6, 0x8f, 0x3f, 0x71, 0xc7, 0xb7, 0xd7, 0x1e, 0xff, 0xd7, + 0x3b, 0x43, 0x87, 0x97, 0x3b, 0xfe, 0xaf, 0x1d, 0x77, 0x56, 0x86, 0x1d, 0xfa, 0xb3, 0xff, 0xbf, + 0x6d, 0xfb, 0xf3, 0x73, 0xa0, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, + 0x79, 0xfc, 0x05, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, + 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, + 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0x14, 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, + 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, + 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, + 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, + 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, + 0xfe, 0x14, 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, + 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, + 0xfa, 0x83, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, + 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, + 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0x14, + 0xa4, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, + 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, + 0xfe, 0xf4, 0xa7, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3e, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x41, 0x9f, 0xfd, 0xd1, 0x74, 0x60, + 0xf5, 0xdb, 0xa9, 0x29, 0xff, 0xb8, 0xf0, 0xca, 0x27, 0xbb, 0xff, 0x25, 0xef, 0x40, 0xde, 0xbf, + 0x7f, 0xfc, 0xc9, 0xc1, 0x23, 0x8b, 0x7f, 0xf5, 0x0f, 0xe2, 0x45, 0xc1, 0xc7, 0x7f, 0x3a, 0xf0, + 0xa7, 0xc3, 0xf9, 0x05, 0x2b, 0x1f, 0xff, 0xbe, 0x78, 0x99, 0xfa, 0xe9, 0xc7, 0x05, 0x1f, 0x1f, + 0x39, 0x50, 0x50, 0xb0, 0x74, 0x63, 0xa9, 0x6f, 0x7f, 0xa1, 0xfd, 0x0f, 0x3e, 0x5b, 0xa4, 0xfd, + 0xb7, 0xff, 0xfb, 0xd3, 0x85, 0x3f, 0xff, 0xe7, 0xdd, 0x94, 0x94, 0xc7, 0xa9, 0x31, 0x7f, 0x79, + 0xf0, 0x80, 0xe5, 0x0f, 0x87, 0x3f, 0xce, 0xff, 0x74, 0xe5, 0xdf, 0x3e, 0x2d, 0xa1, 0x50, 0xee, + 0x61, 0x8b, 0xf8, 0x86, 0xff, 0x79, 0xe5, 0x3d, 0x22, 0x44, 0xaa, 0xfa, 0xee, 0x23, 0x05, 0x39, + 0x9f, 0x1c, 0x5c, 0x7a, 0x7f, 0xea, 0x1b, 0xef, 0xaf, 0xfe, 0xf0, 0xdf, 0xe8, 0x7c, 0xf8, 0x6f, + 0x62, 0x3e, 0xdc, 0x74, 0xe4, 0x40, 0xbe, 0x46, 0xcf, 0x94, 0x4f, 0x0f, 0xfc, 0xc1, 0xf4, 0xd9, + 0x67, 0x07, 0xf2, 0x57, 0x7e, 0x30, 0xff, 0xf4, 0x5f, 0xa9, 0x29, 0x7f, 0xfb, 0xdd, 0x7f, 0xa7, + 0x9e, 0x7a, 0x5b, 0x7d, 0xe3, 0x6f, 0x52, 0xd9, 0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x7e, 0xb8, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x17, 0x65, 0x40, 0x52, 0xe8, 0x4f, 0x7f, + 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0xff, 0x1f, 0x67, 0xff, 0xa5, 0x5b, + 0x5b, 0xfc, 0x73, 0xe9, 0xc5, 0xf2, 0x1b, 0xcb, 0xef, 0x5f, 0xfc, 0x47, 0x57, 0xbd, 0xbd, 0xfc, + 0xa7, 0x51, 0xe3, 0xf6, 0x96, 0x6e, 0x6b, 0xf5, 0x37, 0xbc, 0xfa, 0xbd, 0x31, 0xff, 0xae, 0x21, + 0xee, 0x66, 0x96, 0xbf, 0x96, 0xcd, 0xd8, 0xda, 0x36, 0xbd, 0xff, 0xd2, 0xd7, 0xaf, 0xf7, 0x9f, + 0xfe, 0xc7, 0x19, 0x63, 0xfe, 0x5b, 0xfe, 0xbb, 0x55, 0x3f, 0x12, 0xed, 0xdb, 0x5a, 0xd3, 0x6d, + 0xe1, 0xa6, 0x74, 0x7b, 0xae, 0x7c, 0xdc, 0xca, 0xcb, 0x44, 0x5f, 0xd7, 0xf3, 0x7e, 0x5f, 0xaf, + 0x7c, 0xfb, 0xd7, 0xdb, 0xbe, 0x34, 0xb6, 0xb3, 0xb5, 0xdf, 0xd7, 0xc2, 0xed, 0xaf, 0xfc, 0xf9, + 0x7c, 0xdf, 0xf3, 0xca, 0xdb, 0x46, 0xe3, 0x7a, 0xdd, 0x56, 0x7f, 0x46, 0x82, 0x9f, 0xa3, 0x41, + 0xf3, 0xfe, 0xb5, 0xce, 0xf7, 0xf5, 0x8a, 0xfb, 0x6f, 0xf8, 0xf3, 0xe3, 0xfb, 0x1b, 0x8c, 0x8b, + 0x1b, 0xfb, 0xd2, 0x9f, 0x3a, 0xff, 0x19, 0x35, 0x87, 0x07, 0x63, 0xdc, 0xf6, 0x1d, 0xfb, 0xfe, + 0xf8, 0x01, 0x6d, 0x9d, 0xfe, 0x71, 0x37, 0xf3, 0x12, 0xc6, 0xe5, 0xd7, 0x78, 0xfb, 0x5f, 0x3b, + 0xfe, 0x27, 0xea, 0x9f, 0xa8, 0x9b, 0xd6, 0xcf, 0x39, 0x76, 0xdb, 0x8f, 0x1d, 0x7f, 0x0c, 0xda, + 0xe3, 0xff, 0x0b, 0x7d, 0x5f, 0x5b, 0x77, 0xfc, 0xd7, 0xed, 0x1f, 0x3b, 0xfe, 0xeb, 0xe4, 0xd1, + 0x1e, 0x37, 0xf4, 0xbf, 0x0e, 0xed, 0xf1, 0x7f, 0xcd, 0xfe, 0x80, 0x61, 0x0b, 0x8e, 0xff, 0x9b, + 0xbe, 0xff, 0xb3, 0x7a, 0x3b, 0xdf, 0xf8, 0xfe, 0x4f, 0xdc, 0x7e, 0x8d, 0xee, 0xf6, 0xbb, 0xf2, + 0xee, 0x4d, 0xd8, 0x01, 0x62, 0xff, 0x9f, 0xfd, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0x5b, 0xad, 0x7f, 0xcc, 0xe3, 0x4d, 0xbd, 0xe3, + 0x5e, 0x6b, 0x1e, 0xed, 0x6b, 0x7c, 0x7e, 0xfc, 0xf1, 0xe1, 0x85, 0x57, 0x56, 0xfe, 0x34, 0x68, + 0x3f, 0xc0, 0xd7, 0x7d, 0x1c, 0xab, 0x79, 0xf4, 0xf2, 0x05, 0xce, 0x03, 0x68, 0x3f, 0xde, 0x36, + 0xea, 0x1c, 0x00, 0x5c, 0xf3, 0xf7, 0x1a, 0xdf, 0xc7, 0xcb, 0xee, 0x1f, 0x7b, 0xbc, 0x7d, 0xe9, + 0xd0, 0x81, 0xfe, 0x71, 0x77, 0xa3, 0x21, 0xd1, 0x71, 0x31, 0xad, 0xe3, 0x32, 0x06, 0x8d, 0xcf, + 0xdb, 0xe8, 0xe7, 0xc7, 0xf7, 0x4f, 0xf6, 0x3c, 0x40, 0xfc, 0xad, 0xc7, 0x7e, 0xbc, 0xd6, 0xb6, + 0x18, 0x77, 0x70, 0xe3, 0x25, 0xf6, 0x5f, 0xbd, 0x21, 0xc6, 0x1f, 0x0f, 0xd6, 0x38, 0x6e, 0x9c, + 0xf8, 0xf8, 0xb3, 0xe6, 0x71, 0xf9, 0x44, 0xe3, 0x9e, 0xce, 0x31, 0x3c, 0x8d, 0xb3, 0x30, 0x2f, + 0x7e, 0x1e, 0x20, 0x51, 0x7f, 0x83, 0xe1, 0x55, 0xf6, 0x8f, 0xbb, 0x7f, 0x1a, 0xb4, 0x8f, 0xc7, + 0x2f, 0x8f, 0x23, 0x46, 0xad, 0xf1, 0x47, 0x6f, 0xfc, 0x58, 0x75, 0x9c, 0xd9, 0xa8, 0x7d, 0x80, + 0x51, 0xe3, 0xf3, 0x8d, 0xeb, 0x8f, 0x3f, 0x1b, 0x3f, 0x0f, 0x90, 0xf8, 0xeb, 0x32, 0xe8, 0x1c, + 0xfe, 0x8b, 0xbd, 0x79, 0xcd, 0x61, 0xea, 0x25, 0x8e, 0x3f, 0xab, 0xcf, 0x5b, 0x69, 0x0f, 0xcf, + 0xfa, 0xc7, 0xd4, 0x63, 0xbf, 0x73, 0xdd, 0xed, 0x6c, 0x03, 0xdb, 0xff, 0x7a, 0x5b, 0xe8, 0x0b, + 0x9f, 0x07, 0xd0, 0xb9, 0x75, 0xbd, 0xd7, 0x13, 0x6f, 0x05, 0x9b, 0x32, 0xfe, 0x1b, 0x74, 0xc6, + 0xff, 0xb8, 0xf3, 0xb6, 0x06, 0xcd, 0xcf, 0x8f, 0x1d, 0x7f, 0x37, 0xd6, 0xff, 0x45, 0xc7, 0xff, + 0x8d, 0x9e, 0x07, 0x58, 0xaf, 0x7f, 0x82, 0xf1, 0x7f, 0xcd, 0x97, 0xbc, 0x59, 0xfd, 0xd7, 0xdf, + 0xff, 0xd1, 0x3e, 0xbf, 0x12, 0xff, 0xf9, 0xb1, 0xf7, 0xe7, 0xb5, 0xc7, 0xdf, 0x9f, 0x77, 0xff, + 0x47, 0x67, 0xbf, 0xe3, 0xb9, 0xcf, 0x03, 0x18, 0x75, 0xf6, 0xa7, 0xf4, 0xf7, 0x7f, 0xb4, 0xc6, + 0x85, 0xcd, 0xdb, 0xff, 0x01, 0x8f, 0xbf, 0xe8, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, + 0x4f, 0x7f, 0x6c, 0x6e, 0xff, 0xf8, 0xf9, 0xf7, 0x71, 0xc7, 0xcb, 0x0c, 0xfc, 0x98, 0x36, 0xb3, + 0x7f, 0x4c, 0xe3, 0x95, 0xc7, 0xf5, 0x9a, 0xf3, 0x8f, 0xb1, 0xb9, 0xfd, 0x93, 0x9c, 0x8f, 0x4a, + 0xff, 0x24, 0xc6, 0x9f, 0xd8, 0xe3, 0x64, 0x9b, 0xb8, 0x6e, 0x87, 0xfe, 0x31, 0xc7, 0xf9, 0xf5, + 0xb6, 0x7f, 0xb6, 0xfe, 0x4d, 0x1f, 0x7f, 0xe2, 0x8e, 0x6f, 0xaf, 0x3d, 0xfe, 0xaf, 0x77, 0x86, + 0x0e, 0x2f, 0x77, 0xfc, 0x5f, 0x3b, 0xee, 0xac, 0x0c, 0x3b, 0xf4, 0x67, 0xff, 0x7f, 0xdb, 0xf6, + 0xe7, 0xe7, 0x40, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xf3, 0xf8, + 0x0b, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, + 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, + 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, + 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, + 0xfd, 0x29, 0x48, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, + 0xa7, 0x3f, 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, + 0xf4, 0x07, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, + 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, + 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0x29, + 0x48, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, + 0xe8, 0x4f, 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, + 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, + 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, + 0x3f, 0xfd, 0xe9, 0x4f, 0x7f, 0xfa, 0xd3, 0x9f, 0xfe, 0xf4, 0xa7, 0x3f, 0xfd, 0x29, 0x48, 0x7f, + 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, 0x0f, 0xfa, 0xd3, 0x1f, 0xf4, 0xa7, 0x3f, 0xe8, 0x4f, + 0x7f, 0xd0, 0x9f, 0xfe, 0xa0, 0x3f, 0xfd, 0x41, 0x7f, 0xfa, 0x83, 0xfe, 0xf4, 0x07, 0xfd, 0xe9, + 0x4f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb9, 0x52, + 0xfe, 0x1f, 0xdc, 0xd1, 0x78, 0x32 }; diff --git a/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.cpp b/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.cpp index 553f2eff..084cca40 100644 --- a/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.cpp +++ b/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.cpp @@ -447,7 +447,7 @@ void CDataAdapterViceDrive1541DiskContents::FormatDisk(const char *diskName, con vdrive_device_setup(vdrive, 8); vdrive->image = diskImage; - vdrive_attach_image(diskImage, 8, vdrive); + vdrive_attach_image(diskImage, 8, 0, vdrive); char *commandBuf = SYS_GetCharBuf(); @@ -459,8 +459,8 @@ void CDataAdapterViceDrive1541DiskContents::FormatDisk(const char *diskName, con SYS_ReleaseCharBuf(commandBuf); - vdrive_detach_image(diskImage, (unsigned int)8, vdrive); - drive_image_attach(diskImage, 8); + vdrive_detach_image(diskImage, (unsigned int)8, 0, vdrive); + drive_image_attach(diskImage, 8, 0); DiskAttached(); @@ -482,12 +482,12 @@ int CDataAdapterViceDrive1541DiskContents::InsertFile(std::filesystem::path file vdrive_device_setup(vdrive, 8); vdrive->image = diskImage; - vdrive_attach_image(diskImage, 8, vdrive); + vdrive_attach_image(diskImage, 8, 0, vdrive); fileio_info_t *finfo; finfo = fileio_open(filePath.string().c_str(), NULL, FILEIO_FORMAT_RAW | FILEIO_FORMAT_P00, FILEIO_COMMAND_READ | FILEIO_COMMAND_FSNAME, - FILEIO_TYPE_PRG); + FILEIO_TYPE_PRG, NULL); if (finfo == NULL) { LOGError("CDataAdapterViceDrive1541DiskContents::FormatDisk: file not found %s", filePath.string().c_str()); @@ -498,7 +498,7 @@ int CDataAdapterViceDrive1541DiskContents::InsertFile(std::filesystem::path file CSlrString *fileNameNoExt = fileName->GetFileNameWithoutExtensionAndPath(); char *cFileNameNoExt = fileNameNoExt->GetStdASCII(); -// char *dest_name = lib_stralloc((char *)filePath.filename().string().c_str()); //(finfo->name)); +// char *dest_name = lib_strdup((char *)filePath.filename().string().c_str()); //(finfo->name)); char *dest_name = cFileNameNoExt; unsigned int dest_len = strlen(cFileNameNoExt); //finfo->length; @@ -586,8 +586,8 @@ int CDataAdapterViceDrive1541DiskContents::InsertFile(std::filesystem::path file // lib_free(dest_name); STRFREE(cFileNameNoExt); - vdrive_detach_image(diskImage, (unsigned int)8, vdrive); - drive_image_attach(diskImage, 8); + vdrive_detach_image(diskImage, (unsigned int)8, 0, vdrive); + drive_image_attach(diskImage, 8, 0); DiskAttached(); diff --git a/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.h b/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.h index a43e856b..301198bb 100644 --- a/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.h +++ b/src/Emulators/vice/ViceInterface/Adapters/CDataAdapterViceDrive1541DiskContents.h @@ -7,8 +7,8 @@ class CDebugInterfaceVice; extern "C" { -struct drive_context_s; -typedef struct drive_context_s drive_context_t; +struct diskunit_context_s; +typedef struct diskunit_context_s diskunit_context_t; struct disk_image_s; typedef struct disk_image_s disk_image_t; @@ -43,8 +43,8 @@ struct Drive1541ContentsTrack u32 dataOffset; }; -struct drive_context_s; -typedef struct drive_context_s drive_context_t; +struct diskunit_context_s; +typedef struct diskunit_context_s diskunit_context_t; struct gcr_s; typedef struct gcr_s gcr_t; diff --git a/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.cpp b/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.cpp index 90715620..523c10a7 100644 --- a/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.cpp +++ b/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.cpp @@ -1088,7 +1088,7 @@ void CDebugInterfaceVice::ResetSoft() keyboard_clear_keymatrix(); - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); this->ResetEmulationFrameCounter(); c64d_maincpu_clk = 6; @@ -1108,7 +1108,7 @@ void CDebugInterfaceVice::ResetHard() keyboard_clear_keymatrix(); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); this->ResetEmulationFrameCounter(); this->ClearHistory(); @@ -1127,7 +1127,7 @@ void CDebugInterfaceVice::DiskDriveReset() { LOGM("CDebugInterfaceVice::DiskDriveReset()"); - drivecpu_reset(drive_context[0]); + drivecpu_reset(diskunit_context[0]); } extern "C" { @@ -1209,15 +1209,22 @@ bool CDebugInterfaceVice::KeyboardDown(uint32 mtKeyCode) { CDebuggerEmulatorPlugin *plugin = *it; mtKeyCode = plugin->KeyDown(mtKeyCode); - + if (mtKeyCode == 0) return false; } - - if (keyboard_key_pressed((unsigned long)mtKeyCode) == 1) - return true; - - return false; + + /* keyboard_key_pressed() ends up calling alarm_set() on maincpu_alarm_context, + which is NOT thread-safe vs. the emulation thread iterating the alarm list. + The race left the KERNAL keyboard buffer at $00C6 empty even when the API + returned 200 (Phase-4 known bug; captured by the test_input.py docstring). + Take the emulator mutex around the VICE-internal call so the alarm list + mutation is serialized against the CPU thread. */ + this->LockMutex(); + bool pressed = keyboard_key_pressed((unsigned long)mtKeyCode) == 1; + this->UnlockMutex(); + + return pressed; } bool CDebugInterfaceVice::KeyboardUp(uint32 mtKeyCode) @@ -1226,15 +1233,17 @@ bool CDebugInterfaceVice::KeyboardUp(uint32 mtKeyCode) { CDebuggerEmulatorPlugin *plugin = *it; mtKeyCode = plugin->KeyUp(mtKeyCode); - + if (mtKeyCode == 0) return false; } - - if (keyboard_key_released((unsigned long)mtKeyCode) == 1) - return true; - - return false; + + /* Same alarm_set race as KeyboardDown above -- serialize against the CPU thread. */ + this->LockMutex(); + bool released = keyboard_key_released((unsigned long)mtKeyCode) == 1; + this->UnlockMutex(); + + return released; } void CDebugInterfaceVice::JoystickDown(int port, uint32 axis) @@ -1376,7 +1385,7 @@ void CDebugInterfaceVice::GetVICState(C64StateVIC *state) void CDebugInterfaceVice::GetDrive1541State(C64StateDrive1541 *state) { - drive_t *drive = drive_context[0]->drive; + drive_t *drive = diskunit_context[0]->drives[0]; state->headTrackPosition = drive->current_half_track + drive->side * 70; } @@ -1390,7 +1399,7 @@ void CDebugInterfaceVice::InsertD64(CSlrString *path) SYS_FixFileNameSlashes(asciiPath); - int rc = file_system_attach_disk(8, asciiPath); + int rc = file_system_attach_disk(8, 0, asciiPath); if (rc == -1) { @@ -1407,7 +1416,7 @@ void CDebugInterfaceVice::InsertD64(CSlrString *path) void CDebugInterfaceVice::DetachDriveDisk() { - file_system_detach_disk(8); + file_system_detach_disk(8, 0); ((CDataAdapterViceDrive1541DiskContents*)debugInterfaceVice->dataAdapterDrive1541DiskContents)->DiskDetached(); } @@ -2096,14 +2105,14 @@ u8 CDebugInterfaceVice::GetSidRegister(uint8 sidId, uint8 registerNum) } extern "C" { - void via1d1541_store(drive_context_t *ctxptr, WORD addr, BYTE data); - BYTE c64d_via1d1541_peek(drive_context_t *ctxptr, WORD addr); - void via2d_store(drive_context_t *ctxptr, WORD addr, BYTE data); - BYTE c64d_via2d_peek(drive_context_t *ctxptr, WORD addr); + void via1d1541_store(diskunit_context_t *ctxptr, WORD addr, BYTE data); + BYTE c64d_via1d1541_peek(diskunit_context_t *ctxptr, WORD addr); + void via2d_store(diskunit_context_t *ctxptr, WORD addr, BYTE data); + BYTE c64d_via2d_peek(diskunit_context_t *ctxptr, WORD addr); } void CDebugInterfaceVice::SetViaRegister(uint8 driveId, uint8 viaId, uint8 registerNum, uint8 value) { - drive_context_t *drivectx = drive_context[driveId]; + diskunit_context_t *drivectx = diskunit_context[driveId]; if (viaId == 1) { @@ -2118,7 +2127,7 @@ void CDebugInterfaceVice::SetViaRegister(uint8 driveId, uint8 viaId, uint8 regis u8 CDebugInterfaceVice::GetViaRegister(uint8 driveId, uint8 viaId, uint8 registerNum) { - drive_context_t *drivectx = drive_context[driveId]; + diskunit_context_t *drivectx = diskunit_context[driveId]; if (viaId == 1) { @@ -2445,7 +2454,7 @@ uint8 CDebugInterfaceVice::GetDebugMode() extern "C" { int tape_image_attach(unsigned int unit, const char *name); int tape_image_detach(unsigned int unit); - void datasette_control(int command); + void datasette_control(int port, int command); /* VICE 3.10: + port (C64 datasette is tape port 0) */ } static void tape_attach_trap(WORD addr, void *v) @@ -2479,32 +2488,32 @@ void CDebugInterfaceVice::DetachTape() void CDebugInterfaceVice::DatasettePlay() { - datasette_control(DATASETTE_CONTROL_START); + datasette_control(0, DATASETTE_CONTROL_START); } void CDebugInterfaceVice::DatasetteStop() { - datasette_control(DATASETTE_CONTROL_STOP); + datasette_control(0, DATASETTE_CONTROL_STOP); } void CDebugInterfaceVice::DatasetteForward() { - datasette_control(DATASETTE_CONTROL_FORWARD); + datasette_control(0, DATASETTE_CONTROL_FORWARD); } void CDebugInterfaceVice::DatasetteRewind() { - datasette_control(DATASETTE_CONTROL_REWIND); + datasette_control(0, DATASETTE_CONTROL_REWIND); } void CDebugInterfaceVice::DatasetteRecord() { - datasette_control(DATASETTE_CONTROL_RECORD); + datasette_control(0, DATASETTE_CONTROL_RECORD); } void CDebugInterfaceVice::DatasetteReset() { - datasette_control(DATASETTE_CONTROL_RESET); + datasette_control(0, DATASETTE_CONTROL_RESET); } void CDebugInterfaceVice::DatasetteSetSpeedTuning(int speedTuning) @@ -2550,7 +2559,7 @@ static void cartridge_detach_trap(WORD addr, void *v) { // -1 means all slots cartridge_detach_image(-1); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); debugInterfaceVice->ResetEmulationFrameCounter(); c64d_maincpu_clk = 6; } @@ -2611,13 +2620,13 @@ static void trap_detach_everything(WORD addr, void *v) { // -1 means all slots cartridge_detach_image(-1); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); debugInterfaceVice->ResetEmulationFrameCounter(); c64d_maincpu_clk = 6; tape_image_detach(1); - file_system_detach_disk(8); + file_system_detach_disk(8, 0); ((CDataAdapterViceDrive1541DiskContents*)debugInterfaceVice->dataAdapterDrive1541DiskContents)->DiskDetached(); } @@ -3116,7 +3125,7 @@ CSlrString *CDebugInterfaceVice::GetCodeMonitorPrompt() } extern "C" { - char *lib_stralloc(const char *str); + char *lib_strdup(const char *str); } static void execute_monitor_command_trap(WORD addr, void *v) @@ -3145,7 +3154,7 @@ bool CDebugInterfaceVice::ExecuteCodeMonitorCommand(CSlrString *commandStr) commandStr->ConvertToLowerCase(); char *cmdStr = commandStr->GetStdASCII(); - char *monitorCmdStr = lib_stralloc(cmdStr); + char *monitorCmdStr = lib_strdup(cmdStr); delete [] cmdStr; // // we need to move to next instruction on these commands diff --git a/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.h b/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.h index 6e8013b4..23327c26 100644 --- a/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.h +++ b/src/Emulators/vice/ViceInterface/CDebugInterfaceVice.h @@ -6,8 +6,15 @@ #include "SYS_Threading.h" #include "CPool.h" +/* VICE 3.10 sound.h sets SOUND_SIDS_MAX=8 (was 3 in 3.1). RD's earlier fallback to + C64_MAX_NUM_SIDS (3) created an ODR violation: TUs that didn't include sound.h + saw a 192-byte CSidData; TUs that did saw a 512-byte one. new CSidData() then + allocated 192 bytes and the ctor wrote 256+256 -> heap corruption -> WS thread + malloc trap. Caught by ASAN as a 256B write past a 192B allocation made from + CDebuggerServerApiVice ctor's `this->sidData = new CSidData();`. Match VICE 3.10's + value unconditionally so every TU agrees on the struct layout. */ #ifndef SOUND_SIDS_MAX -#define SOUND_SIDS_MAX C64_MAX_NUM_SIDS +#define SOUND_SIDS_MAX 8 #endif //HAVE_NETWORK ? diff --git a/src/Emulators/vice/ViceInterface/CDebuggerServerApiVice.h b/src/Emulators/vice/ViceInterface/CDebuggerServerApiVice.h index 18b3ea35..e28220f9 100644 --- a/src/Emulators/vice/ViceInterface/CDebuggerServerApiVice.h +++ b/src/Emulators/vice/ViceInterface/CDebuggerServerApiVice.h @@ -8,7 +8,7 @@ class CDebugInterfaceVice; class CDebuggerApiVice; class CSidData; -const int MAX_DRIVE_NUM = DRIVE_NUM - 1; +const int MAX_DRIVE_NUM = NUM_DISK_UNITS - 1; class CDebuggerServerApiVice : public CDebuggerServerApi { diff --git a/src/Emulators/vice/ViceInterface/ViceWrapper.cpp b/src/Emulators/vice/ViceInterface/ViceWrapper.cpp index c90a1699..fcfcfdd1 100644 --- a/src/Emulators/vice/ViceInterface/ViceWrapper.cpp +++ b/src/Emulators/vice/ViceInterface/ViceWrapper.cpp @@ -1394,7 +1394,7 @@ void c64d_debug_pause_check(int allowRestore) { if (c64d_is_performing_snapshot_restore()) { - vsync_do_vsync(vicii.raster.canvas, 0, 1); + vsync_do_vsync(vicii.raster.canvas); return; } } @@ -1405,7 +1405,7 @@ void c64d_debug_pause_check(int allowRestore) debugInterfaceVice->sidDataToRestore = NULL; } - vsync_do_vsync(vicii.raster.canvas, 0, 1); + vsync_do_vsync(vicii.raster.canvas); //mt_SYS_Sleep(50); } } @@ -1540,9 +1540,9 @@ void c64d_sid_channels_data(int sidNumber, int v1, int v2, int v3, short mix) int c64d_is_drive_dirty_for_snapshot() { // LOGD("c64d_is_drive_dirty_for_snapshot:"); - for (int dnr = 0; dnr < DRIVE_NUM; dnr++) + for (int dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { - drive_s *drive = drive_context[dnr]->drive; + drive_s *drive = diskunit_context[dnr]->drives[0]; // LOGD(".... dnr=%d drive=%x GCR=%d P64=%d", dnr, drive, drive->GCR_dirty_track_for_snapshot, drive->P64_dirty_for_snapshot); if (drive->GCR_dirty_track_for_snapshot) { @@ -1559,9 +1559,9 @@ int c64d_is_drive_dirty_for_snapshot() void c64d_clear_drive_dirty_for_snapshot() { - for (int dnr = 0; dnr < DRIVE_NUM; dnr++) + for (int dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { - drive_s *drive = drive_context[dnr]->drive; + drive_s *drive = diskunit_context[dnr]->drives[0]; drive->GCR_dirty_track_for_snapshot = 0; drive->P64_dirty_for_snapshot = 0; } @@ -1569,7 +1569,7 @@ void c64d_clear_drive_dirty_for_snapshot() int c64d_is_drive_dirty_and_needs_refresh(int driveNum) { - drive_s *drive = drive_context[driveNum]->drive; + drive_s *drive = diskunit_context[driveNum]->drives[0]; if (drive->GCR_dirty_track_needs_refresh) { return 1; @@ -1583,14 +1583,14 @@ int c64d_is_drive_dirty_and_needs_refresh(int driveNum) void c64d_set_drive_dirty_needs_refresh_flag(int driveNum) { - drive_s *drive = drive_context[driveNum]->drive; + drive_s *drive = diskunit_context[driveNum]->drives[0]; drive->GCR_dirty_track_needs_refresh = 1; drive->P64_dirty_needs_refresh = 1; } void c64d_clear_drive_dirty_needs_refresh_flag(int driveNum) { - drive_s *drive = drive_context[driveNum]->drive; + drive_s *drive = diskunit_context[driveNum]->drives[0]; drive->GCR_dirty_track_needs_refresh = 0; drive->P64_dirty_needs_refresh = 0; } diff --git a/src/Emulators/vice/arch/archdep_access.h b/src/Emulators/vice/arch/archdep_access.h new file mode 100644 index 00000000..98b4d4e5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_access.h @@ -0,0 +1,71 @@ +/** \file archdep_access.h + * \brief Test access mode of a path - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_ACCESS_H +#define VICE_ARCHDEP_ACCESS_H + +#include "vice.h" +#include "archdep_defs.h" + +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + +/* covers linux, bsd, macos and haiku */ +# include +# define ARCHDEP_R_OK R_OK +# define ARCHDEP_W_OK W_OK +# define ARCHDEP_X_OK X_OK +# define ARCHDEP_F_OK F_OK + +#elif defined(WINDOWS_COMPILE) + +/* shitty windows */ +# include +# define ARCHDEP_R_OK 4 +# define ARCHDEP_W_OK 2 +# define ARCHDEP_X_OK 1 +# define ARCHDEP_F_OK 0 + +#else +# error "Unsupported OS!" +#endif + + +/** \brief File is readable */ +#define ARCHDEP_ACCESS_R_OK 4 + +/** \brief File is writeable */ +#define ARCHDEP_ACCESS_W_OK 2 + +/** \brief File is executable */ +#define ARCHDEP_ACCESS_X_OK 1 + +/** \brief File exists */ +#define ARCHDEP_ACCESS_F_OK 0 + + +int archdep_access(const char *pathname, int mode); + +#endif diff --git a/src/Emulators/vice/arch/archdep_beos.h b/src/Emulators/vice/arch/archdep_beos.h new file mode 100644 index 00000000..9d649261 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_beos.h @@ -0,0 +1,105 @@ +/** \file archdep_beos.h + * \brief Miscellaneous BeOS system-specific stuff + * + * \author Marco van den Heuvel + * \author Marcus Sutton + * + * TODO: Either of these authors should properly document the defines using + * Doxygen. + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_BEOS_H +#define VICE_ARCHDEP_BEOS_H + +#define VICE_ARCHAPI_PRIVATE_API +#include "archapi.h" +#undef VICE_ARCHAPI_PRIVATE_API + +/* Video chip scaling. */ +#define ARCHDEP_VICII_DSIZE 1 +#define ARCHDEP_VICII_DSCAN 1 +#define ARCHDEP_VDC_DSIZE 1 +#define ARCHDEP_VDC_DSCAN 1 +#define ARCHDEP_VIC_DSIZE 1 +#define ARCHDEP_VIC_DSCAN 1 +#define ARCHDEP_CRTC_DSIZE 1 +#define ARCHDEP_CRTC_DSCAN 1 +#define ARCHDEP_TED_DSIZE 1 +#define ARCHDEP_TED_DSCAN 1 + +/* Filesystem-dependent constants */ +#define ARCHDEP_FSDEVICE_DEFAULT_DIR "." +#define ARCHDEP_DIR_SEP_STR "/" +#define ARCHDEP_DIR_SEP_CHR '/' + +/* Path separator. */ +#define ARCHDEP_FINDPATH_SEPARATOR_CHAR ':' +#define ARCHDEP_FINDPATH_SEPARATOR_STRING ":" + +/* Modes for fopen(). */ +#define MODE_READ "r" +#define MODE_READ_TEXT "rt" +#define MODE_READ_WRITE "r+" +#define MODE_WRITE "w" +#define MODE_WRITE_TEXT "wt" +#define MODE_APPEND "a" +#define MODE_APPEND_READ_WRITE "a+" + +/* Printer default devices. */ +#define ARCHDEP_PRINTER_DEFAULT_DEV1 "PrinterFile" +#define ARCHDEP_PRINTER_DEFAULT_DEV2 "/dev/parallel/parallel1" +#define ARCHDEP_PRINTER_DEFAULT_DEV3 "/dev/printer/usb/" + +/* Default RS232 devices. */ +#define ARCHDEP_RS232_DEV1 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV2 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV3 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV4 "127.0.0.1:25232" + +/* Default location of raw disk images. */ +#define ARCHDEP_RAWDRIVE_DEFAULT "/dev/disk/floppy/raw" + +/* Standard line delimiter. */ +#define ARCHDEP_LINE_DELIMITER "\n" + +/* Ethernet default device */ +#define ARCHDEP_ETHERNET_DEFAULT_DEVICE "" + +/* + FIXME: confirm wether SIGPIPE must be handled or not. if the emulator quits + or crashes when the connection is closed, you might have to install + a signal handler which calls monitor_abort(). + + see archdep_unix.c and bug #3201796 +*/ +#if 0 +#define archdep_signals_init(x) +#define archdep_signals_pipe_set() +#define archdep_signals_pipe_unset() +#endif + +/* what to use to return an error when a socket error happens */ +#define ARCHDEP_SOCKET_ERROR errno + +#endif diff --git a/src/Emulators/vice/arch/archdep_boot_path.h b/src/Emulators/vice/arch/archdep_boot_path.h new file mode 100644 index 00000000..b32e5204 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_boot_path.h @@ -0,0 +1,33 @@ +/** \file archdep_boot_path.h + * \brief Retrieve dirname of currently running binary - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_BOOT_PATH_H +#define VICE_ARCHDEP_BOOT_PATH_H + +const char *archdep_boot_path(void); +void archdep_boot_path_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_cbmfont.h b/src/Emulators/vice/arch/archdep_cbmfont.h new file mode 100644 index 00000000..5aa349b5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_cbmfont.h @@ -0,0 +1,35 @@ +/** \file archdep_cbmfont.h + * \brief CBM font handling - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CBMFONT_H +#define VICE_ARCHDEP_CBMFONT_H + +/* Register CBM font with the OS without installing */ +int archdep_register_cbmfont(void); +/* Unregister CBM font */ +void archdep_unregister_cbmfont(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_chdir.c b/src/Emulators/vice/arch/archdep_chdir.c new file mode 100644 index 00000000..72bcedf6 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_chdir.c @@ -0,0 +1,64 @@ +/** \file archdep_chdir.c + * \brief Change current working directory + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +#elif defined(WINDOWS_COMPILE) +# include +#else +# error "Unsupported OS!" +#endif + +#include "archdep_chdir.h" + + +/** \brief Change current working directory + * + * \param[in] path new working directiory + * + * \return 0 on success, -1 on failure + */ +int archdep_chdir(const char *path) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + return chdir(path); +#elif defined(WINDOWS_COMPILE) + return _chdir(path); +#else + return -1; +#endif +} diff --git a/src/Emulators/vice/arch/archdep_chdir.h b/src/Emulators/vice/arch/archdep_chdir.h new file mode 100644 index 00000000..d315305a --- /dev/null +++ b/src/Emulators/vice/arch/archdep_chdir.h @@ -0,0 +1,32 @@ +/** \file archdep_chdir.h + * \brief Change current working directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CHDIR_H +#define VICE_ARCHDEP_CHDIR_H + +int archdep_chdir(const char *path); + +#endif diff --git a/src/Emulators/vice/arch/archdep_close.c b/src/Emulators/vice/arch/archdep_close.c new file mode 100644 index 00000000..aea86195 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_close.c @@ -0,0 +1,65 @@ +/** \file archdep_close.c + * \brief Close a file descriptor + * + * Wrapper for the Unix close(2) function. + * + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +#elif defined(WINDOWS_COMPILE) +# include +#else +# error "Unsupported OS!" +#endif + +#include "archdep_close.h" + + +/** \brief Close file descriptor + * + * \param[in] fd file descriptor + * + * \return 0 on success, -1 on failure + */ +int archdep_close(int fd) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + return close(fd); +#elif defined(WINDOWS_COMPILE) + return _close(fd); +#else + return -1; +#endif +} diff --git a/src/Emulators/vice/arch/archdep_close.h b/src/Emulators/vice/arch/archdep_close.h new file mode 100644 index 00000000..e5342380 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_close.h @@ -0,0 +1,39 @@ +/** \file archdep_close.h + * \brief Close a file descriptor - header + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CLOSE_H +#define VICE_ARCHDEP_CLOSE_H + +int archdep_close(int fd); + +#endif diff --git a/src/Emulators/vice/arch/archdep_create_user_cache_dir.h b/src/Emulators/vice/arch/archdep_create_user_cache_dir.h new file mode 100644 index 00000000..6bbe5dc0 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_create_user_cache_dir.h @@ -0,0 +1,33 @@ +/** \file archdep_create_user_cache_dir.h + * \brief Create XDG user cache dir - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CREATE_USER_CACHE_DIR_H +#define VICE_ARCHDEP_CREATE_USER_CACHE_DIR_H + +void archdep_create_user_cache_dir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_create_user_config_dir.h b/src/Emulators/vice/arch/archdep_create_user_config_dir.h new file mode 100644 index 00000000..ab58151e --- /dev/null +++ b/src/Emulators/vice/arch/archdep_create_user_config_dir.h @@ -0,0 +1,33 @@ +/** \file archdep_create_user_config_dir.h + * \brief Create XDG user config dir - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CREATE_USER_CONFIG_DIR_H +#define VICE_ARCHDEP_CREATE_USER_CONFIG_DIR_H + +void archdep_create_user_config_dir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_create_user_state_dir.h b/src/Emulators/vice/arch/archdep_create_user_state_dir.h new file mode 100644 index 00000000..be1cb628 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_create_user_state_dir.h @@ -0,0 +1,33 @@ +/** \file archdep_create_user_state_dir.h + * \brief Create XDG user state dir - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CREATE_USER_STATE_DIR_H +#define VICE_ARCHDEP_CREATE_USER_STATE_DIR_H + +void archdep_create_user_state_dir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_current_dir.c b/src/Emulators/vice/arch/archdep_current_dir.c new file mode 100644 index 00000000..6cff4bd7 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_current_dir.c @@ -0,0 +1,67 @@ +/** \file archdep_current_dir.c + * \brief Get heap-allocated current working directory + * + * \author Bas Wassink + * \author Marco van den Heuvel + * \author trikalio + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "archdep_defs.h" +#include "archdep_getcwd.h" +#include "lib.h" + +#include "archdep_current_dir.h" + + +/** \brief Get heap-allocated current working directory + * + * Get the current working directory via archdep_cwd(), reallocating the buffer + * until the result fits. + * + * \return current working directory or NULL on failure + * + * \note Free result with lib_free() + */ +char *archdep_current_dir(void) +{ + char *p; + static size_t len = 256; /* buffer size on first call of function */ + + p = lib_malloc(len); + while (archdep_getcwd(p, len) == NULL) { + if (errno == ERANGE) { + /* double buffer size and try again */ + len *= 2; + p = lib_realloc(p, len); + } else { + return NULL; + } + } + return p; +} diff --git a/src/Emulators/vice/arch/archdep_current_dir.h b/src/Emulators/vice/arch/archdep_current_dir.h new file mode 100644 index 00000000..e538adee --- /dev/null +++ b/src/Emulators/vice/arch/archdep_current_dir.h @@ -0,0 +1,36 @@ +/** \file archdep_current_dir.h + * \brief Get heap-allocated current working directory - header + * + * \author Bas Wassink + * \author Marco van den Heuvel + * \author trikalio + * + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_CURRENT_DIR_H +#define VICE_ARCHDEP_CURRENT_DIR_H + +char *archdep_current_dir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_autostart_disk_image_file_name.h b/src/Emulators/vice/arch/archdep_default_autostart_disk_image_file_name.h new file mode 100644 index 00000000..cdc786fd --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_autostart_disk_image_file_name.h @@ -0,0 +1,33 @@ +/** \file archdep_default_autostart_disk_image_file_name.h + * \brief Determine default autostart diskimage file - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_AUTOSTART_DISK_IMAGE_FILE_NAME_H +#define VICE_ARCHDEP_DEFAULT_AUTOSTART_DISK_IMAGE_FILE_NAME_H + +char *archdep_default_autostart_disk_image_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_fliplist_file_name.h b/src/Emulators/vice/arch/archdep_default_fliplist_file_name.h new file mode 100644 index 00000000..bf5df913 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_fliplist_file_name.h @@ -0,0 +1,12 @@ +/** \file archdep_default_fliplist_file_name.h + * \brief Determine path to default fliplist file - header + * + * \author Bas Wassink + */ + +#ifndef VICE_ARCHDEP_DEFAULT_FLIPLIST_FILE_NAME_H +#define VICE_ARCHDEP_DEFAULT_FLIPLIST_FILE_NAME_H + +char *archdep_default_fliplist_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_joymap_file_name.h b/src/Emulators/vice/arch/archdep_default_joymap_file_name.h new file mode 100644 index 00000000..b85a3783 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_joymap_file_name.h @@ -0,0 +1,33 @@ +/** \file archdep_default_joymap_file_name.h - header + * \brief Get the path to the default joymap file + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_JOYMAP_FILE_NAME +#define VICE_ARCHDEP_DEFAULT_JOYMAP_FILE_NAME + +char *archdep_default_joymap_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_logfile.h b/src/Emulators/vice/arch/archdep_default_logfile.h new file mode 100644 index 00000000..e3e04afb --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_logfile.h @@ -0,0 +1,33 @@ +/** \file archdep_default_logfile.h + * \brief Get default log file location - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_LOGFILE_H +#define VICE_ARCHDEP_DEFAULT_LOGFILE_H + +char *archdep_default_logfile(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_logger.c b/src/Emulators/vice/arch/archdep_default_logger.c new file mode 100644 index 00000000..0756e0a3 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_logger.c @@ -0,0 +1,166 @@ +/** \file archdep_default_logger.c + * \brief Write to default frogger + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#ifdef WINDOWS_COMPILE +# include +# include +#endif + +#include +#include +#ifdef UNIX_COMPILE +#include +#include +#include +#endif + +#include "lib.h" +#include "util.h" + +#include "archdep_defs.h" +#include "archdep_stat.h" +#include "archdep_default_logger.h" + + +#ifdef WINDOWS_COMPILE + +/** \brief Write message to Windows debugger/logger + * + * \param[in] level_string log level string + * \param[in] txt log message + * + * \note Shamelessly copied from win32/archdep.c + * + * \return 0 on success, < 0 on failure + */ +int archdep_default_logger(const char *level_string, const char *txt) +{ + char *out; + + if (level_string != NULL && *level_string != '\0') { + out = lib_msprintf("%s %s", level_string, txt); + } else { + out = lib_strdup(txt); + } + + /* first output to stdout as usual, and flush the output so it + shows up in the console immediately */ + puts(out); + fflush(stdout); + /* also output to debug output, so it can be captured by Debugview etc */ + OutputDebugString(out); + + lib_free(out); + return 0; +} + +int archdep_default_logger_is_terminal(void) +{ + struct stat statinfo; + DWORD temp; + const bool mode = GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &temp); + const int type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); + /* this works in cmd.exe */ + if (mode || (type == FILE_TYPE_CHAR)) { + return 1; + } + + /* extra check seems to work for msys */ + fstat(fileno(stdout), &statinfo); + /* 1 - 0 msys (-noredir) + 0 - 1 msys (-noredir) > bla + 0 - 1 cmd -noredir > bla + 0 - 0 cmd > bla + 0 - 0 cmd + */ + if (S_ISFIFO(statinfo.st_mode) && !S_ISREG(statinfo.st_mode)) { + return 1; + } + return 0; +} + +#elif defined(UNIX_COMPILE) + +/** \brief Write log message to stdout + * + * \param[in] level_string log level string + * \param[in] txt log message + * + * \note Shamelessly copied from unix/archdep.c + * + * \return 0 on success, < 0 on failure + */ +int archdep_default_logger(const char *level_string, const char *txt) +{ + if (fputs(level_string, stdout) == EOF + || fprintf(stdout, "%s", txt) < 0 + || fputc ('\n', stdout) == EOF) { + return -1; + } + return 0; +} + +int archdep_default_logger_is_terminal(void) +{ + FILE *fp = stdout; + struct stat statinfo; + + fstat(fileno(fp), &statinfo); + if (!S_ISFIFO(statinfo.st_mode) && !S_ISREG(statinfo.st_mode)) { + return 1; + } + return 0; +} + +#else + +/** \brief Write log message to stdout + * + * Stub: doesn't do anything but return 0. + * + * \param[in] level_string log level string + * \param[in] txt log message + * + * \return 0 + */ +int archdep_default_logger(const char *level_string, const char *txt) +{ + return 0; +} + +int archdep_default_logger_is_terminal(void) +{ + return 0; /* FIXME */ +} + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_logger.h b/src/Emulators/vice/arch/archdep_default_logger.h new file mode 100644 index 00000000..01b920f6 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_logger.h @@ -0,0 +1,36 @@ +/** \file archdep_default_logger.h + * \brief Write to default frogger - header + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_LOGGER_H +#define VICE_ARCHDEP_DEFAULT_LOGGER_H + +int archdep_default_logger(const char *level_string, const char *txt); + +int archdep_default_logger_is_terminal(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.c b/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.c new file mode 100644 index 00000000..30f9a884 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.c @@ -0,0 +1,67 @@ +/** \file archdep_default_portable_resource_file_name.c + * \brief Retrieve default portable resource file path + * \author groepaz + * + * Get path to default portable resource file (vicerc/vice.ini) + * + * Unlike the normal resource file, this one is located in the 'root' directory + * of the bindist (Windows) or in the user's home directory (Unix). + * + * OS support: + * - Windows + * - Unix + * + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include + +#include "archdep_boot_path.h" +#include "archdep_home_path.h" +#include "util.h" + +#include "archdep_default_portable_resource_file_name.h" + + +/** \brief Get path to default portable resource file + * + * \return heap-allocated path, free with lib_free() + */ +char *archdep_default_portable_resource_file_name(void) +{ +#ifdef WINDOWS_COMPILE + return util_join_paths(archdep_boot_path(), +# ifdef USE_GTK3UI + "..", /* Gtk-Win binaries live in bin/, so go up */ +# endif + ARCHDEP_VICERC_NAME, + NULL); +#else + return util_join_paths(archdep_home_path(), + "." ARCHDEP_VICERC_NAME, /* ".vicerc" */ + NULL); +#endif +} diff --git a/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.h b/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.h new file mode 100644 index 00000000..bbb289f5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_portable_resource_file_name.h @@ -0,0 +1,32 @@ +/** \file archdep_default_portable_resource_file_name.h + * \brief Retrieve default portable resource file path - header + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_PORTABLE_RESOURCE_FILE_NAME_H +#define VICE_ARCHDEP_DEFAULT_PORTABLE_RESOURCE_FILE_NAME_H + +char *archdep_default_portable_resource_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_resource_file_name.h b/src/Emulators/vice/arch/archdep_default_resource_file_name.h new file mode 100644 index 00000000..7950ec8e --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_resource_file_name.h @@ -0,0 +1,32 @@ +/** \file archdep_default_resource_file_name.h + * \brief Retrieve default resource file path - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_RESOURCE_FILE_NAME_H +#define VICE_ARCHDEP_DEFAULT_RESOURCE_FILE_NAME_H + +char *archdep_default_resource_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_rtc_file_name.h b/src/Emulators/vice/arch/archdep_default_rtc_file_name.h new file mode 100644 index 00000000..b7e710ca --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_rtc_file_name.h @@ -0,0 +1,33 @@ +/** \file archdep_default_rtc_file_name.h + * \brief Determine path to default realtime clock file - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_RTC_FILE_NAME_H +#define VICE_ARCHDEP_DEFAULT_RTC_FILE_NAME_H + +char *archdep_default_rtc_file_name(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_default_sysfile_pathlist.h b/src/Emulators/vice/arch/archdep_default_sysfile_pathlist.h new file mode 100644 index 00000000..6d5a706c --- /dev/null +++ b/src/Emulators/vice/arch/archdep_default_sysfile_pathlist.h @@ -0,0 +1,32 @@ +/** \file archdep_default_sysfile_pathlist.h + * \brief Get a list of paths of required data files - header + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DEFAULT_SYSFILE_PATHLIST_H +#define VICE_ARCHDEP_DEFAULT_SYSFILE_PATHLIST_H + +char * archdep_default_sysfile_pathlist(const char *emu_id); +void archdep_default_sysfile_pathlist_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_defs.h b/src/Emulators/vice/arch/archdep_defs.h new file mode 100644 index 00000000..6ae93565 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_defs.h @@ -0,0 +1,198 @@ +/** \file archdep_defs.h + * \brief Defines, enums and types used by the archdep functions + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef VICE_ARCHDEP_DEFS_H +#define VICE_ARCHDEP_DEFS_H + +#include "vice.h" +#include + + +/* \brief Various OS-identification macros + * + * The question marks indicate ports I have my doubts about they'll even run + * VICE at all. + * + * XXX: Non of the ARCHDEP_OS_* macros should be left when we've finished + * the archdep cleanup! + * TODO: Move this comment to either src/vice.h or configure.ac. + * + *
+ *  UNIX_COMPILE
+ *    MACOS_COMPILE
+ *    LINUX_COMPILE
+ *    BSD_COMPILE
+ *      FREEBSD_COMPILE
+ *      NETBSD_COMPILE
+ *      OPENBSD_COMPILE
+ *      DRAGONFLYBSD_COMPILE
+ *  WINDOWS_COMPILE
+ *  BEOS_COMPILE
+ *    HAIKU_COMPILE
+ * 
+ */ + + +/** \brief Extension used for autostart disks + */ +#define ARCHDEP_AUTOSTART_DISK_EXTENSION "d64" + + +#if defined(WINDOWS_COMPILE) +/** \brief Separator used for a pathlist + */ +# define ARCHDEP_FINDPATH_SEPARATOR_STRING ";" + +#else + +/** \brief Separator used for a pathlist + */ +# define ARCHDEP_FINDPATH_SEPARATOR_STRING ":" +#endif + + +/** \def ARCHDEP_PATH_MAX + * + * \brief Arch-independent replacement for PATH_MAX/MAX_PATH + * + * The maximum size of a pathname. + * + * Note that there are some serious flaws with PATH_MAX and similar constants, + * so only use this if dynamically allocating memory isn't possible. There also + * doesn't seem to be consencus on whether PATH_MAX is enough to hold the + * longest possible path including the terminating NUL character. + */ + +#ifdef WINDOWS_COMPILE +# include +# define ARCHDEP_PATH_MAX _MAX_PATH +#elif defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +/* Not sure we need this fallback: on FreeBSD, NetBSD and OpenBSD using + * `#include ` worked even with -pedantic -ansi passed to the compiler. + */ +#if 0 +# ifndef PATH_MAX +# if defined(BSD_COMPILE) || defined(MACOS_COMPILE) +# include +# endif +# endif +#endif +# define ARCHDEP_PATH_MAX PATH_MAX +#else +/* Paniek! */ +# define ARCHDEP_PATH_MAX 4096 +#endif + + +/** \brief XDG Base Directory Specifiction user cache dir + * + * This defines only the final element of the `XDG_CACHE_HOME` variable. + */ +#define ARCHDEP_XDG_CACHE_HOME ".cache" + + +/** \brief XDG Base Directory Specifiction user config dir + * + * This defines only the final element of `the XDG_CONFIG_HOME` variable. + */ +#define ARCHDEP_XDG_CONFIG_HOME ".config" + + +/** \def ARCHDEP_VICERC_NAME + * \brief The name of the default VICE configuraton file + */ + +/** \def ARCHDEP_VICE_RTC_NAME + * \brief The name of the default VICE RTC status file + */ + +/* + * Determine if we compile against SDL + */ +#if defined(USE_SDLUI) || defined(USE_SDL2UI) +# define ARCHDEP_USE_SDL +#endif + +#if defined(WINDOWS_COMPILE) || defined(BEOS_COMPILE) +# ifdef ARCHDEP_USE_SDL +# define ARCHDEP_VICERC_NAME "sdl-vice.ini" +/* Just copying stuff, I'm backwards */ +# define ARCHDEP_VICE_RTC_NAME "sdl-vice.rtc" +# else +# define ARCHDEP_VICERC_NAME "vice.ini" +# define ARCHDEP_VICE_RTC_NAME "vice.rtc" +# endif +#else +# ifdef ARCHDEP_USE_SDL +# define ARCHDEP_VICERC_NAME "sdl-vicerc" +# define ARCHDEP_VICE_RTC_NAME "sdl-vice.rtc" +# else +# define ARCHDEP_VICERC_NAME "vicerc" +# define ARCHDEP_VICE_RTC_NAME "vice.rtc" +# endif +#endif + +/** \brief Autostart diskimage prefix + */ +#define ARCHDEP_AUTOSTART_DISKIMAGE_PREFIX "autostart-" + +/** \brief Autostart diskimage suffix + */ +#define ARCHDEP_AUTOSTART_DISKIMAGE_SUFFIX ".d64" + + +/* Declare extra printf specifiers for Windows since Microsoft's support for + * C99 fucking sucks. + * + * This declares PRI_SIZE_T and PRI_SSIZE_T for use on all platforms, + * aliasing to 'zu'/'z' on anything not Windows, and using PRI[d|u][32|64] on + * Windows. + */ + +/** \def PRI_SIZE_T + * \brief Printf type specifier alias for 'zu' + * + * Required to work around Microsoft's broken C99 support. + */ + +/** \def PRI_SSIZE_T + * \brief Printf type specifier alias for 'zd' + * + * Required to work around Microsoft's broken C99 support. + */ + +#ifdef _WIN32 +# define PRI_SIZE_T "Iu" +# define PRI_SSIZE_T "Id" +#else +# define PRI_SIZE_T "zu" +# define PRI_SSIZE_T "zd" +#endif + +#endif diff --git a/src/Emulators/vice/arch/archdep_dir.c b/src/Emulators/vice/arch/archdep_dir.c new file mode 100644 index 00000000..7c3e643f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_dir.c @@ -0,0 +1,448 @@ +/** \file archdep_dir.c + * \brief Read host directory + * \author Marco van den Heuvel + * \author Bas Wassink + * \author Andreas Boose + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep.h" + +#include +#include + +#if defined(WINDOWS_COMPILE) +# include +#elif defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +# include +# include +#else +# error "Unsupported OS!" +#endif + +#include "lib.h" +#include "util.h" + +#include "archdep_dir.h" + + +/** \brief Initial size of an array of file/directory entries + * + * Number of elements in the arrays when initially allocating them. + * + * This number was chosen arbitrarily, reasonable trade-off between wasting + * memory for small directories and not triggering too many realloc calls with + * larger directories. + */ +#define INITIAL_ARRAY_SIZE 64 + + +/** \brief Comparision function for qsort() in archdep_opendir() + * + * \param[in] a first item + * \param[in] b second item + * + * \return \< 0 if \a a \< \a b, 0 if \a a == \a b, \> 0 if \a a \> \a b + */ +static int compare_names(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + + +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +/** \brief Check if an entry must be shown + * + * Check if \a name matches the \a mode filter. + * + * Checks if a dotfile must be shown according to \a mode. + * + * \return true if the file or directory must be shown + */ +static bool must_show_dotfile(const char *name, int mode) +{ + if (mode & ARCHDEP_OPENDIR_NO_HIDDEN_FILES) { + /* checks for a *nix "dotfile" */ + if ((name[0] == '.') && + (name[1] != 0) && + (name[1] != '.')) { + return false; + } + } + return true; +} +#endif + + +/** \brief Add dir entry to directory object + * + * Add \a path to the list of directory in \a dir. + * + * \param[in] dir directory object + * \param[in] path dirname to add + */ +static void add_dir_entry(archdep_dir_t *dir, const char *path) +{ + if (dir->dir_amount == dir->dirs_size) { + /* double array size */ + dir->dirs_size *= 2; + dir->dirs = lib_realloc(dir->dirs, dir->dirs_size * sizeof *(dir->dirs)); + } + dir->dirs[dir->dir_amount++] = lib_strdup(path); +} + + +/** \brief Add file entry to directory object + * + * Add \a path to the list of files in \a dir. + * + * \param[in] dir directory object + * \param[in] path filename to add + */ +static void add_file_entry(archdep_dir_t *dir, const char *path) +{ + if (dir->file_amount == dir->files_size) { + /* double array size */ + dir->files_size *= 2; + dir->files = lib_realloc(dir->files, dir->files_size * sizeof *(dir->files)); + } + dir->files[dir->file_amount++] = lib_strdup(path); +} + + +/** \brief Populate the directory and file lists + * + * Scan \a path for files and directories, filtering them according to \a mode. + * + * \param[in] dir directory object + * \param[in] path directory to scan + * \param[in] mode filter to apply to each directory entry + * + * \return true on success + */ +static bool scan_directory(archdep_dir_t *dir, const char *path, int mode) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + DIR *dirp = NULL; + struct dirent *dp = NULL; + char *filename; + size_t len; + unsigned int isdir; + + dirp = opendir(path); + if (dirp == NULL) { + return false; + } + + dp = readdir(dirp); + + while (dp != NULL) { + if (must_show_dotfile(dp->d_name, mode)) { +#ifdef _DIRENT_HAVE_D_TYPE + if (dp->d_type != DT_UNKNOWN) { + if (dp->d_type == DT_DIR) { + add_dir_entry(dir, dp->d_name); +#ifdef DT_LNK + } else if (dp->d_type == DT_LNK) { + filename = util_concat(path, ARCHDEP_DIR_SEP_STR, dp->d_name, NULL); + if (archdep_stat(filename, &len, &isdir) == 0) { + if (isdir) { + add_dir_entry(dir, dp->d_name); + } else { + add_file_entry(dir, dp->d_name); + } + } + if (filename) { + lib_free(filename); + filename = NULL; + } +#endif /* DT_LNK */ + } else { + add_file_entry(dir, dp->d_name); + } + dp = readdir(dirp); + } else { +#endif /* _DIRENT_HAVE_D_TYPE */ + filename = util_concat(path, ARCHDEP_DIR_SEP_STR, dp->d_name, NULL); + if (archdep_stat(filename, &len, &isdir) == 0) { + if (isdir) { + add_dir_entry(dir, dp->d_name); + } else { + add_file_entry(dir, dp->d_name); + } + } + dp = readdir(dirp); + lib_free(filename); +#ifdef _DIRENT_HAVE_D_TYPE + } +#endif + } else { + dp = readdir(dirp); + } + } + closedir(dirp); + +#elif defined(WINDOWS_COMPILE) + HANDLE ffhandle; + WIN32_FIND_DATA ffdata; + char pattern[ARCHDEP_PATH_MAX]; + + snprintf(pattern, sizeof(pattern), "%s\\*", path); + pattern[sizeof(pattern) - 1] = '\0'; + + ffhandle = FindFirstFile(pattern, &ffdata); + if (ffhandle == INVALID_HANDLE_VALUE) { + return false; + } + + do { + /* show hidden files? */ + if ((ffdata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) && + (mode & ARCHDEP_OPENDIR_NO_HIDDEN_FILES)) { + continue; /* nope */ + } + + if (ffdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + add_dir_entry(dir, ffdata.cFileName); + } else { + add_file_entry(dir, ffdata.cFileName); + } + } while (FindNextFile(ffhandle, &ffdata)); + + if (GetLastError() != ERROR_NO_MORE_FILES) { + FindClose(ffhandle); + return false; + } + FindClose(ffhandle); +#endif + return true; +} + + +/** \brief Scan directory and return a directory object + * + * \param[in] path directory to scan + * \param[in] mode filter to apply on each directory entry + * + * \return directory object or NULL on failure + */ +archdep_dir_t *archdep_opendir(const char *path, int mode) +{ + archdep_dir_t *dir = lib_malloc(sizeof *dir); + + dir->pos = 0; + dir->dir_amount = 0; + dir->dirs_size = INITIAL_ARRAY_SIZE; + dir->dirs = lib_malloc(sizeof *(dir->dirs) * dir->dirs_size); + dir->file_amount = 0; + dir->files_size = INITIAL_ARRAY_SIZE; + dir->files = lib_malloc(sizeof *(dir->files) * dir->files_size); + + if (!scan_directory(dir, path, mode)) { + /* clean up */ + archdep_closedir(dir); + return NULL; + } + + qsort(dir->dirs, dir->dir_amount, sizeof *(dir->dirs), compare_names); + qsort(dir->files, dir->file_amount, sizeof *(dir->files), compare_names); + + return dir; +} + + +/** \brief Get an entry from the directory + * + * \param[in] dir directory object + * + * \return entry or NULL when the directory is exhausted + */ +const char *archdep_readdir(archdep_dir_t *dir) +{ + const char *retval = NULL; + int dir_amount = dir->dir_amount; + int file_amount = dir->file_amount; + int pos = dir->pos; + + if (pos >= 0 && pos < dir_amount) { + retval = dir->dirs[pos]; + dir->pos++; + } else if (pos >= dir_amount && pos < (dir_amount + file_amount)) { + retval = dir->files[pos - dir_amount]; + dir->pos++; + } + return retval; +} + + + +/** \brief Close directory + * + * Free memory used by \a dir and its members. + * + * \param[in] dir directory object + */ +void archdep_closedir(archdep_dir_t *dir) +{ + int i; + + for (i = 0; i < dir->dir_amount; i++) { + lib_free(dir->dirs[i]); + } + for (i = 0; i < dir->file_amount; i++) { + lib_free(dir->files[i]); + } + lib_free(dir->dirs); + lib_free(dir->files); + lib_free(dir); +} + + +/** \brief Rewind position in directory + * + * Rewind position in \a dir to the first entry. + * + * \param[in] dir directory object + */ +void archdep_rewinddir(archdep_dir_t *dir) +{ + dir->pos = 0; +} + + +/** \brief Set position in directory + * + * \param[in] dir directory object + * \param[in] pos new position + */ +void archdep_seekdir(archdep_dir_t *dir, int pos) +{ + if (pos >= 0 && pos < (dir->dir_amount + dir->file_amount)) { + dir->pos = pos; + } +} + + +/** \brief Get position in directory + * + * \param[in] dir directory object + * + * \return position in \a dir or -1 when \a dir is exhausted + */ +int archdep_telldir(const archdep_dir_t *dir) +{ + if (dir->pos >= (dir->dir_amount + dir->file_amount)) { + return -1; + } + return dir->pos; +} + + +/** \brief Get directory entry from directory object + * + * \param[in] dir directory object + * \param[in] pos position in directories list in \a dir + * + * \return directory name or NULL when \a pos is out of bounds + */ +const char *archdep_readdir_get_dir(const archdep_dir_t *dir, int pos) +{ + if (pos >= 0 && pos < dir->dir_amount) { + return dir->dirs[pos]; + } + return NULL; +} + + +/** \brief Get filename entry from directory object + * + * \param[in] dir directory object + * \param[in] pos position in files list in \a dir + * + * \return filename or NULL when \a pos is out of bounds + */ +const char *archdep_readdir_get_file(const archdep_dir_t *dir, int pos) +{ + if (pos >= 0 && pos < dir->file_amount) { + return dir->files[pos]; + } + return NULL; +} + + +/** \brief Get entry from directory object + * + * Get entry from \a dir with the assumption that the directories come before + * the files, joining the two lists as a single list for the \a pos argument. + * + * \param[in] dir directory object + * \param[in] pos position in directories and files list in \a dir + * + * \return entry or NULL when \a pos is out of bounds + */ +const char *archdep_readdir_get_entry(const archdep_dir_t *dir, int pos) +{ + if (pos < dir->dir_amount) { + return archdep_readdir_get_dir(dir, pos); + } else { + return archdep_readdir_get_file(dir, pos - dir->dir_amount); + } +} + + +/** \brief Get total number of entries + * + * \param[in] dir directory object + * + * \return total number of entries (dirs + files) + */ +int archdep_readdir_num_entries(const archdep_dir_t *dir) +{ + return dir->dir_amount + dir->file_amount; +} + + +/** \brief Get number of directory entries + * + * \param[in] dir directory object + * + * \return number of directory entries + */ +int archdep_readdir_num_dirs(const archdep_dir_t *dir) +{ + return dir->dir_amount; +} + + +/** \brief Get number of file entries + * + * \param[in] dir directory object + * + * \return number of file entries + */ +int archdep_readdir_num_files(const archdep_dir_t *dir) +{ + return dir->file_amount; +} diff --git a/src/Emulators/vice/arch/archdep_dir.h b/src/Emulators/vice/arch/archdep_dir.h new file mode 100644 index 00000000..ed784ba9 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_dir.h @@ -0,0 +1,82 @@ +/** \file archdep_dir.h + * \brief Read host directory - header + * \author Marco van den Heuvel + * \author Bas Wassink + * \author Andreas Boose + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DIR_H +#define VICE_ARCHDEP_DIR_H + +#include +#include "archdep_defs.h" + +/** \brief Do not display hidden files + * + * Do not display "dotfiles" on Unix or files with the hidden attribute on + * Windows. + * Will still display the special files '.' and '..'. + */ +#define ARCHDEP_OPENDIR_NO_HIDDEN_FILES 1 + +/** \brief Show all files + */ +#define ARCHDEP_OPENDIR_ALL_FILES 0 + + +/** \brief Directory object + * + * Contains a list of directories and a list of files for a given host directory. + * + * For the position in the directory the API concatenates the dirs and files + * with the dirs coming first. The directories and files are sorted in ascending + * order in a case-sensitive manner and thus sorted Unix-style and not Windows- + * style (where case folding is normally applied). + */ +typedef struct archdep_dir_s { + char **dirs; /**< list of directories */ + char **files; /**< list of files */ + int dir_amount; /**< number of entries in `dirs` */ + int file_amount; /**< number of entries in `files` */ + int pos; /**< position in directory, adding together dirs and + files, with dirs coming first */ + int dirs_size; /**< size of the `dirs` array, in number of elements */ + int files_size; /**< size of the `files` array, in number of elements */ +} archdep_dir_t; + + +archdep_dir_t * archdep_opendir(const char *path, int mode); +const char * archdep_readdir(archdep_dir_t *dir); +void archdep_closedir(archdep_dir_t *dir); +void archdep_rewinddir(archdep_dir_t *dir); +void archdep_seekdir(archdep_dir_t *dir, int pos); +int archdep_telldir(const archdep_dir_t *dir); +const char * archdep_readdir_get_entry(const archdep_dir_t *dir, int pos); +const char * archdep_readdir_get_dir(const archdep_dir_t *dir, int pos); +const char * archdep_readdir_get_file(const archdep_dir_t *dir, int pos); +int archdep_readdir_num_entries(const archdep_dir_t *dir); +int archdep_readdir_num_dirs(const archdep_dir_t *dir); +int archdep_readdir_num_files(const archdep_dir_t *dir); + +#endif diff --git a/src/Emulators/vice/arch/archdep_ethernet_available.h b/src/Emulators/vice/arch/archdep_ethernet_available.h new file mode 100644 index 00000000..650b924d --- /dev/null +++ b/src/Emulators/vice/arch/archdep_ethernet_available.h @@ -0,0 +1,35 @@ +/** \file archdep_ethernet_available.h + * \brief Determine if ethernet support is available for the current process + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef HAVE_ARCHEP_ETHERNET_AVAILABLE_H +#define HAVE_ARCHEP_ETHERNET_AVAILABLE_H + +#include + +bool archdep_ethernet_available(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_exit.c b/src/Emulators/vice/arch/archdep_exit.c new file mode 100644 index 00000000..e510a187 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_exit.c @@ -0,0 +1,215 @@ +/** \file archdep_exit.c + * \brief VICE thread aware archdep_vice_exit + * \author Bas Wassink + * \author Blacky Stardust + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#if !defined(USE_HEADLESSUI) && !defined(USE_SDL2UI) && !defined(USE_SDLUI) +#ifdef UNIX_COMPILE +#ifndef MACOS_COMPILE +#include +#endif +#endif +#endif + +#ifdef WINDOWS_COMPILE +#include +#include +#include +#endif + +#include + +#ifdef USE_GTK3UI +#include +#endif /* #ifdef USE_GTK3UI */ + +#ifdef USE_VICE_THREAD +#include + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int vice_exit_code; +static pthread_t main_thread; + +#define LOCK() pthread_mutex_lock(&lock) +#define UNLOCK() pthread_mutex_unlock(&lock) +#else +#define LOCK() +#define UNLOCK() +#endif /* #ifdef USE_VICE_THREAD */ + +#include "archdep.h" +#include "main.h" +#include "mainlock.h" + +#ifdef MACOS_COMPILE +#include "macOS-util.h" +#endif + +#include "archdep_exit.h" +#include "log.h" + +static bool is_exiting; + +bool archdep_is_exiting(void) { + bool result; + + LOCK(); + result = is_exiting; + UNLOCK(); + + return result; +} + +static void actually_exit(int exit_code) +{ + LOCK(); + + if (is_exiting) { + log_message(LOG_DEFAULT, "Ignoring recursive call to archdep_vice_exit()"); + UNLOCK(); + return; + } + is_exiting = true; + + UNLOCK(); + + /* Some exit stuff not safe to run afer exit() is called so we do it here */ + main_exit(); + +#if defined(WINDOWS_COMPILE) + /* Relax scheduler accuracy */ + timeEndPeriod(1); +#endif + +#ifdef USE_VICE_THREAD + archdep_thread_shutdown(); +#endif + + exit(exit_code); +} + +#ifdef USE_GTK3UI + +/* + * GTK3 needs a more controlled shutdown due to the multiple threads involved. + * In particular, it's tricky to synchronously shut down rendering threads as + * certain OpenGL calls can block if the main thread is blocked (either that, or + * if certain UI resources are destroyed, i'm not sure which at this point --dqh) + */ + +static gboolean exit_on_main_thread(gpointer not_used) +{ + actually_exit(vice_exit_code); + + return FALSE; +} + +void archdep_thread_init(void) +{ +#if defined(WINDOWS_COMPILE) + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +#endif +} + +void archdep_thread_shutdown(void) +{ +#if defined(WINDOWS_COMPILE) + CoUninitialize(); +#endif +} + +void archdep_set_main_thread(void) +{ + main_thread = pthread_self(); + +#if defined(MACOS_COMPILE) + + /* macOS specific main thread init written in objective-c */ + vice_macos_set_main_thread(); + +#elif defined(UNIX_COMPILE) + +#ifdef USE_GTK3UI + /* Our GLX OpenGL init stuff will crash if we let GDK use wayland directly */ + putenv("GDK_BACKEND=x11"); +#endif + +#ifndef USE_HEADLESSUI + /* We're calling xlib from our own thread so need this to avoid problems */ + XInitThreads(); +#endif + + /* TODO - set UI/main thread priority for X11 */ + +#elif defined(WINDOWS_COMPILE) + + /* Increase Windows scheduler accuracy */ + timeBeginPeriod(1); + + /* Of course VICE is more important than other puny Windows applications */ + SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); + +#endif +} + +/** \brief Wrapper around exit() + * + * \param[in] exit_code exit code + */ +void archdep_vice_exit(int exit_code) +{ + vice_exit_code = exit_code; + + if (pthread_equal(pthread_self(), main_thread)) { + /* The main thread is calling this, we can shut down directly */ + actually_exit(exit_code); + } else { + /* We need the main thread to process the exit handling. */ + gdk_threads_add_timeout(0, exit_on_main_thread, NULL); + + if (mainlock_is_vice_thread()) { + /* The vice thread will shut itself down so that archdep_vice_exit does not return */ + mainlock_initiate_shutdown(); + assert(false); + } + } +} + +#else /* #ifdef USE_GTK3UI */ + +/** \brief Wrapper around exit() + */ +void archdep_vice_exit(int exit_code) +{ + actually_exit(exit_code); +} + +#endif /* #ifdef USE_GTK3UI else */ diff --git a/src/Emulators/vice/arch/archdep_exit.h b/src/Emulators/vice/arch/archdep_exit.h new file mode 100644 index 00000000..ae14d5d5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_exit.h @@ -0,0 +1,44 @@ +/** \file archdep_exit.h + * \brief atexit(3) work arounds - header + * \author Bas Wassink + * \author Blacky Stardust + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_EXIT_H +#define ARCHDEP_EXIT_H + +#include + +bool archdep_is_exiting(void); +void archdep_vice_exit(int excode); + +/* TODO - something about these being in here */ +#ifdef USE_GTK3UI +void archdep_thread_init(void); +void archdep_set_main_thread(void); +void archdep_set_vice_thread(void); +void archdep_thread_shutdown(void); +#endif + +#endif diff --git a/src/Emulators/vice/arch/archdep_expand_path.h b/src/Emulators/vice/arch/archdep_expand_path.h new file mode 100644 index 00000000..21844598 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_expand_path.h @@ -0,0 +1,32 @@ +/** \file archdep_expand_path.h + * \brief Expand a path into an absolute path - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_EXPAND_PATH_H +#define VICE_ARCHDEP_EXPAND_PATH_H + +int archdep_expand_path(char **return_path, const char *orig_name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_extra_title_text.h b/src/Emulators/vice/arch/archdep_extra_title_text.h new file mode 100644 index 00000000..02a63354 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_extra_title_text.h @@ -0,0 +1,34 @@ +/** \file archdep_extra_title_text.h + * + * \brief Extra text to use in the title bar - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_EXTRA_TITLE_TEXT_H +#define VICE_ARCHDEP_EXTRA_TITLE_TEXT_H + +const char *archdep_extra_title_text(void); +void archdep_extra_title_text_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_fdopen.c b/src/Emulators/vice/arch/archdep_fdopen.c new file mode 100644 index 00000000..25c19dea --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fdopen.c @@ -0,0 +1,64 @@ +/** \file archdep_fdopen.c + * \brief Associate stream with file descriptor + * + * Wrapper for the POSIX fdopen(2) function. + * + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include + +#if !defined(UNIX_COMPILE) && !defined(HAIKU_COMPILE) && !defined(WINDOWS_COMPILE) +# error "Unsupported OS!" +#endif + +#include "archdep_fdopen.h" + + +/** \brief Close file descriptor + * + * \param[in] fd file descriptor + * \param[in] mode access mode + * + * \return FILE pointer on success, NULL on failure + */ +FILE *archdep_fdopen(int fd, const char *mode) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + return fdopen(fd, mode); +#elif defined(WINDOWS_COMPILE) + return _fdopen(fd, mode); +#else + return NULL; +#endif +} diff --git a/src/Emulators/vice/arch/archdep_fdopen.h b/src/Emulators/vice/arch/archdep_fdopen.h new file mode 100644 index 00000000..b7d1ed46 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fdopen.h @@ -0,0 +1,41 @@ +/** \file archdep_fdopen.h + * \brief Associate stream with file descriptor - header + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FDOPEN_H +#define VICE_ARCHDEP_FDOPEN_H + +#include + +FILE *archdep_fdopen(int fd, const char *mode); + +#endif diff --git a/src/Emulators/vice/arch/archdep_file_exists.c b/src/Emulators/vice/arch/archdep_file_exists.c new file mode 100644 index 00000000..30a4ded9 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_exists.c @@ -0,0 +1,71 @@ +/** \file archdep_file_exists.c + * \brief Check if a file exisys + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include +#include +#include +#include + +#include "archdep.h" +#include "archdep_defs.h" + + +#ifdef UNIX_COMPILE +# include +#endif + +#ifdef WINDOWS_COMPILE +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "archdep_file_exists.h" + + +/** \brief Check if file at \a path exists + * + * \param[in] path path to file + * + * \return bool + */ +bool archdep_file_exists(const char *path) +{ +#ifdef UNIX_COMPILE + if (access(path, F_OK) == 0) { + return true; + } +#endif + +#ifdef WINDOWS_COMPILE + /* Possible TODO: convert path from UTF-8 to UTF-16LE and use the + * more consistent GetFileAttributesW call */ + if (GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES) { + return true; + } +#endif + return false; +} diff --git a/src/Emulators/vice/arch/archdep_file_exists.h b/src/Emulators/vice/arch/archdep_file_exists.h new file mode 100644 index 00000000..4ea60876 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_exists.h @@ -0,0 +1,34 @@ +/** \file archdep_file_exists.h + * \brief Check if a file exists - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FILE_EXISTS_H +#define VICE_ARCHDEP_FILE_EXISTS_H + +#include + +bool archdep_file_exists(const char *path); + +#endif diff --git a/src/Emulators/vice/arch/archdep_file_is_blockdev.h b/src/Emulators/vice/arch/archdep_file_is_blockdev.h new file mode 100644 index 00000000..ee1694a5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_is_blockdev.h @@ -0,0 +1,32 @@ +/** \file archdep_file_is_blockdev.h + * \brief Determine if a pathname refers to a block device - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FILE_IS_BLOCKDEV_H +#define VICE_ARCHDEP_FILE_IS_BLOCKDEV_H + +int archdep_file_is_blockdev(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_file_is_chardev.h b/src/Emulators/vice/arch/archdep_file_is_chardev.h new file mode 100644 index 00000000..0bd95355 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_is_chardev.h @@ -0,0 +1,32 @@ +/** \file archdep_file_is_chardev.h + * \brief Determine if a pathname refers to a character device - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FILE_IS_CHARDEV_H +#define VICE_ARCHDEP_FILE_IS_CHARDEV_H + +int archdep_file_is_chardev(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_file_size.c b/src/Emulators/vice/arch/archdep_file_size.c new file mode 100644 index 00000000..a4d4a955 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_size.c @@ -0,0 +1,58 @@ +/** \file archdep_file_size.c + * \brief Get size of an open file + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include +#if defined(WINDOWS_COMPILE) +# include +#endif + +#include "archdep_fseeko.h" +#include "archdep_ftello.h" + +#include "archdep_file_size.h" + + +off_t archdep_file_size(FILE *stream) +{ + off_t pos; + off_t end; + + pos = archdep_ftello(stream); + if (pos < 0) { + return -1; + } + if (archdep_fseeko(stream, 0, SEEK_END) != 0) { + return -1; + } + end = archdep_ftello(stream); + if (archdep_fseeko(stream, pos, SEEK_SET) != 0) { + return -1; + } + return end; +} diff --git a/src/Emulators/vice/arch/archdep_file_size.h b/src/Emulators/vice/arch/archdep_file_size.h new file mode 100644 index 00000000..f25f1ab0 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_file_size.h @@ -0,0 +1,39 @@ +/** \file archdep_file_size.h + * \brief Get size of an open file - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FILE_SIZE_H +#define VICE_ARCHDEP_FILE_SIZE_H + +#include "archdep_defs.h" + +#include +#if defined(WINDOWS_COMPILE) +# include +#endif + +off_t archdep_file_size(FILE *stream); + +#endif diff --git a/src/Emulators/vice/arch/archdep_filename_parameter.h b/src/Emulators/vice/arch/archdep_filename_parameter.h new file mode 100644 index 00000000..eb25d521 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_filename_parameter.h @@ -0,0 +1,32 @@ +/** \file archdep_filename_parameter.h + * \brief Quote filename parameters on systems that need it - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FILENAME_PARAMETER_H +#define VICE_ARCHDEP_FILENAME_PARAMETER_H + +char *archdep_filename_parameter(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_fix_permissions.h b/src/Emulators/vice/arch/archdep_fix_permissions.h new file mode 100644 index 00000000..52aee26b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fix_permissions.h @@ -0,0 +1,32 @@ +/** \file archdep_fix_permissions.h + * \brief Update permissions of a file to R+W - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FIX_PERMISSIONS_H +#define VICE_ARCHDEP_FIX_PERMISSIONS_H + +int archdep_fix_permissions(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_fix_streams.h b/src/Emulators/vice/arch/archdep_fix_streams.h new file mode 100644 index 00000000..41f09861 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fix_streams.h @@ -0,0 +1,33 @@ +/** \file archdep_fix_streams.h + * \brief Fix stdin, stdout, stderr streams if applicable - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FIX_STREAMS_H +#define VICE_ARCHDEP_FIX_STREAMS_H + +void archdep_fix_streams(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_fseeko.c b/src/Emulators/vice/arch/archdep_fseeko.c new file mode 100644 index 00000000..c35b5c9d --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fseeko.c @@ -0,0 +1,60 @@ +/** \file archdep_fseeko.c + * \brief Provides fseeko(3) replacement on systems that lack fseeko(3) + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +/* For off_t on system where off_t doesn't live in stdio.h or where off_t + * doesn't exist at all */ +#include "vicetypes.h" +#include + +#include "archdep_fseeko.h" + + +/** \brief Set position in stream + * + * Set position in \a stream using a 64-bit signed type. + * + * \param[in] stream stream + * + * \return 0 on success, -1 otherwise + * + * \see fseeko(3) + */ +int archdep_fseeko(FILE *stream, off_t offset, int whence) +{ +#ifdef HAVE_FSEEKO + return fseeko(stream, offset, whence); +#else + /* Mingw appears to provide fseeko() on Windows, this is for non-Mingw */ +# ifdef HAVE__FSEEKI64 + /* this assumes `off_t` matches `long long` on Windows */ + return _fseeki64(stream, offset, whence); +# else + /* paniek! */ + return fseek(stream, (long)offset, whence); +# endif +#endif +} diff --git a/src/Emulators/vice/arch/archdep_fseeko.h b/src/Emulators/vice/arch/archdep_fseeko.h new file mode 100644 index 00000000..75c21874 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_fseeko.h @@ -0,0 +1,36 @@ +/** \file archdep_fseeko.h + * \brief Provides fseeko(3) replacement on systems that lack fseeko(3) - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FSEEKO_H +#define VICE_ARCHDEP_FSEEKO_H + +#include "vice.h" +#include "vicetypes.h" +#include + +int archdep_fseeko(FILE *stream, off_t offset, int whence); + +#endif diff --git a/src/Emulators/vice/arch/archdep_ftello.c b/src/Emulators/vice/arch/archdep_ftello.c new file mode 100644 index 00000000..a3c82ba6 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_ftello.c @@ -0,0 +1,58 @@ +/** \file archdep_ftello.c + * \brief Provides ftello(3) replacement on systems that lack ftello(3) + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "vicetypes.h" +#include + +#include "archdep_ftello.h" + + +/** \brief Get position in stream + * + * Get position in \a stream using a 64-bit signed type. + * + * \param[in] stream stream + * + * \return position in \a stream or -1 on error + * + * \see ftello(3) + */ +off_t archdep_ftello(FILE *stream) +{ +#ifdef HAVE_FTELLO + return ftello(stream); +#else + /* Mingw appears to provide ftello() on Windows, this is for non-Mingw */ +# ifdef HAVE__FTELLI64 + /* this assumes `off_t` matches `long long` on Windows */ + return _ftelli64(stream); +# else + /* paniek! */ + return (off_t)ftell(stream); +# endif +#endif +} diff --git a/src/Emulators/vice/arch/archdep_ftello.h b/src/Emulators/vice/arch/archdep_ftello.h new file mode 100644 index 00000000..7d11a079 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_ftello.h @@ -0,0 +1,36 @@ +/** \file archdep_ftello.h + * \brief Provides ftello(3) replacement on systems that lack ftello(3) - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_FTELLO_H +#define VICE_ARCHDEP_FTELLO_H + +#include "vice.h" +#include "vicetypes.h" +#include + +off_t archdep_ftello(FILE *stream); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_current_drive.h b/src/Emulators/vice/arch/archdep_get_current_drive.h new file mode 100644 index 00000000..2317a22b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_current_drive.h @@ -0,0 +1,32 @@ +/** \file archdep_get_current_drive.h + * \brief Get current drive on Windows - header + * \author Unknown (probably copied from old SDL code) + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_CURRENT_DRIVE_H +#define VICE_ARCHDEP_GET_CURRENT_DRIVE_H + +char *archdep_get_current_drive(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_hvsc_dir.h b/src/Emulators/vice/arch/archdep_get_hvsc_dir.h new file mode 100644 index 00000000..ddb2090f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_hvsc_dir.h @@ -0,0 +1,32 @@ +/** \file archdep_get_hvsc_dir.h + * \brief Get HVSC base directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_HVSC_DIR_H +#define VICE_ARCHDEP_GET_HVSC_DIR_H + +const char *archdep_get_hvsc_dir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_runtime_info.h b/src/Emulators/vice/arch/archdep_get_runtime_info.h new file mode 100644 index 00000000..d747273b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_runtime_info.h @@ -0,0 +1,50 @@ +/** \file archdep_get_runtime_info.h + * \brief Get runtime information - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_GET_RUNTIME_INFO_H +#define ARCHDEP_GET_RUNTIME_INFO_H + +#include + +/** \brief Maximum size of a string in the archdep_runtime_info_t struct + */ +#define ARCHDEP_RUNTIME_STRMAX 1024 + + +/** \brief Object to store runtime info + */ +typedef struct archdep_runtime_info_s { + char os_name[ARCHDEP_RUNTIME_STRMAX]; /**< OS name */ + char os_version[ARCHDEP_RUNTIME_STRMAX]; /**< OS version */ + char os_release[ARCHDEP_RUNTIME_STRMAX]; /**< OS release */ + char machine[ARCHDEP_RUNTIME_STRMAX]; /**< machine type */ +} archdep_runtime_info_t; + +bool archdep_get_runtime_info(archdep_runtime_info_t *info); + +#endif + diff --git a/src/Emulators/vice/arch/archdep_get_vice_datadir.h b/src/Emulators/vice/arch/archdep_get_vice_datadir.h new file mode 100644 index 00000000..4c2f4e54 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_vice_datadir.h @@ -0,0 +1,33 @@ +/** \file archdep_get_vice_datadir.h + * \brief Get path to data dir for Gtk3 - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_VICE_DATADIR_H +#define VICE_ARCHDEP_GET_VICE_DATADIR_H + +char *archdep_get_vice_datadir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_vice_docsdir.h b/src/Emulators/vice/arch/archdep_get_vice_docsdir.h new file mode 100644 index 00000000..8631c90b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_vice_docsdir.h @@ -0,0 +1,32 @@ +/** \file archdep_get_vice_docsdir.h + * \brief Get path to VICE doc/ dir - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_VICE_DOCSDIR_H +#define VICE_ARCHDEP_GET_VICE_DOCSDIR_H + +char *archdep_get_vice_docsdir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_vice_drivesdir.h b/src/Emulators/vice/arch/archdep_get_vice_drivesdir.h new file mode 100644 index 00000000..bba08c5b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_vice_drivesdir.h @@ -0,0 +1,33 @@ +/** \file archdep_get_vice_drivesdir.h + * \brief Get path to VICE's DRIVES dir + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_VICE_DRIVESDIR_H +#define VICE_ARCHDEP_GET_VICE_DRIVESDIR_H + +char *archdep_get_vice_drivesdir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_vice_hotkeysdir.h b/src/Emulators/vice/arch/archdep_get_vice_hotkeysdir.h new file mode 100644 index 00000000..8ed5b823 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_vice_hotkeysdir.h @@ -0,0 +1,33 @@ +/** \file archdep_get_vice_hotkeysdir.h + * \brief Get path to VICE's hotkeys dir - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_VICE_HOTKEYSDIR_H +#define VICE_ARCHDEP_GET_VICE_HOTKEYSDIR_H + +char *archdep_get_vice_hotkeysdir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_get_vice_machinedir.h b/src/Emulators/vice/arch/archdep_get_vice_machinedir.h new file mode 100644 index 00000000..739aee52 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_get_vice_machinedir.h @@ -0,0 +1,33 @@ +/** \file archdep_get_vice_machinedir.h + * \brief Get path to machine data dir + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GET_VICE_MACHINEDIR_H +#define VICE_ARCHDEP_GET_VICE_MACHINEDIR_H + +char *archdep_get_vice_machinedir(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_getcwd.c b/src/Emulators/vice/arch/archdep_getcwd.c new file mode 100644 index 00000000..1f7841b0 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_getcwd.c @@ -0,0 +1,69 @@ +/** \file archdep_getcwd.c + * \brief Get current working directory + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +#elif defined(WINDOWS_COMPILE) +# include +#else +# error "Unsupported OS!" +#endif + +#include "archdep_getcwd.h" + + +/** \brief Get current working directory + * + * Store current working directory in \a buf. + * + * \param[in] buf buffer to store current working directory + * \param[in] size size of \a buf + * + * \return pointer to \a buf on success, `NULL` on failure + * + * \see getcwd(3) + */ +char *archdep_getcwd(char *buf, size_t size) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + return getcwd(buf, size); +#elif defined(WINDOWS_COMPILE) + return _getcwd(buf, (int)size); +#else + return NULL; +#endif +} diff --git a/src/Emulators/vice/arch/archdep_getcwd.h b/src/Emulators/vice/arch/archdep_getcwd.h new file mode 100644 index 00000000..3fc86822 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_getcwd.h @@ -0,0 +1,34 @@ +/** \file archdep_getcwd.h + * \brief Get current working directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GETCWD_H +#define VICE_ARCHDEP_GETCWD_H + +#include + +char *archdep_getcwd(char *buf, size_t size); + +#endif diff --git a/src/Emulators/vice/arch/archdep_glob.h b/src/Emulators/vice/arch/archdep_glob.h new file mode 100644 index 00000000..eee9004d --- /dev/null +++ b/src/Emulators/vice/arch/archdep_glob.h @@ -0,0 +1,60 @@ +/** \file archdep_glob.h + * \brief very minimalistic glob() + * \author pottendo + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_GLOB_H +#define VICE_ARCHDEP_GLOB_H + +#if defined(UNIX_COMPILE) +#if defined (HAVE_GLOB_H) +#include +#define archdep_glob glob +#define archdep_globfree globfree +#endif +#endif + +#if defined (WINDOWS_COMPILE) +#include + +typedef struct { + size_t gl_pathc; /* Count of paths matched so far */ + char **gl_pathv; /* List of matched pathnames. */ + size_t gl_offs; /* Slots to reserve in gl_pathv. */ +} glob_t; + +/* expects an absolute path for pattern and many glob() functions are NOT implemented */ +int archdep_glob(const char *pattern, int flags, void *errfunc, glob_t *pglob); +void archdep_globfree(glob_t *pglob); + +#endif + +#endif diff --git a/src/Emulators/vice/arch/archdep_home_path.h b/src/Emulators/vice/arch/archdep_home_path.h new file mode 100644 index 00000000..4d6680df --- /dev/null +++ b/src/Emulators/vice/arch/archdep_home_path.h @@ -0,0 +1,33 @@ +/** \file archdep_home_path.h + * \brief Retrieve home directory of current user - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_HOME_PATH +#define VICE_ARCHDEP_HOME_PATH + +const char *archdep_home_path(void); +void archdep_home_path_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_icon_path.h b/src/Emulators/vice/arch/archdep_icon_path.h new file mode 100644 index 00000000..f1185e18 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_icon_path.h @@ -0,0 +1,33 @@ +/** \file archdep_icon_path.h + * \brief Get path to icon file - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef HAVE_ARCHDEP_ICON_PATH_H +#define HAVE_ARCHDEP_ICON_PATH_H + +char *archdep_app_icon_path_png(int size); + +#endif diff --git a/src/Emulators/vice/arch/archdep_is_haiku.c b/src/Emulators/vice/arch/archdep_is_haiku.c new file mode 100644 index 00000000..a7f6cdc3 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_is_haiku.c @@ -0,0 +1,65 @@ +/** \file archdep_is_haiku.c + * \brief Determine if BeOS is "Haiku" + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include "archdep_is_haiku.h" + +/** \fn archdep_is_haiku + * \brief Determine if we're running on Haiku + * + * This check is needed for Haiku, since it always returns 1 on + * SupportsWindowMode(). + * + * \return 0 if running Haiku, -1 otherwise (BeOS) + * + * FIXME: Would make more sense to return a boolean value, since the function + * name contains *is*. + */ + +#ifdef BEOS_COMPILE +#include +#include "util.h" + +int archdep_is_haiku(void) +{ + struct utsname name; + + uname(&name); + if (!util_strncasecmp(name.sysname, "Haiku", 5)) { + return -1; + } + return 0; +} + +#else + +int archdep_is_haiku(void) +{ + return -1; +} +#endif diff --git a/src/Emulators/vice/arch/archdep_is_haiku.h b/src/Emulators/vice/arch/archdep_is_haiku.h new file mode 100644 index 00000000..e990af0c --- /dev/null +++ b/src/Emulators/vice/arch/archdep_is_haiku.h @@ -0,0 +1,35 @@ +/** \file archdep_is_haiku.h + * \brief Determine if BeOS is "Haiku" + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_IS_HAIKU_H +#define VICE_ARCHDEP_IS_HAIKU_H + +#include "archdep_defs.h" + +int archdep_is_haiku(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_is_macos_bindist.h b/src/Emulators/vice/arch/archdep_is_macos_bindist.h new file mode 100644 index 00000000..333b5fcc --- /dev/null +++ b/src/Emulators/vice/arch/archdep_is_macos_bindist.h @@ -0,0 +1,33 @@ +/** \file archdep_is_macos_bindist.h + * \brief Determine if running from a macOS binary distribution - header + * + * \author David Hogan + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_IS_MACOS_BINDIST_H +#define VICE_ARCHDEP_IS_MACOS_BINDIST_H + +int archdep_is_macos_bindist(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_is_windows_nt.h b/src/Emulators/vice/arch/archdep_is_windows_nt.h new file mode 100644 index 00000000..7339eea4 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_is_windows_nt.h @@ -0,0 +1,33 @@ +/** \file archdep_is_windows_nt.h + * \brief Determine if Windows is 'NT', whatever that means - header + * + * \author Marco van den Heuvel + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_IS_WINDOWS_NT_H +#define VICE_ARCHDEP_IS_WINDOWS_NT_H + +int archdep_is_windows_nt(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_kbd_get_host_mapping.h b/src/Emulators/vice/arch/archdep_kbd_get_host_mapping.h new file mode 100644 index 00000000..4bc51898 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_kbd_get_host_mapping.h @@ -0,0 +1,32 @@ +/** \file archdep_kbd_get_host_mapping.h + * \brief guess the hosts keyboard layout + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_KBD_GET_HOST_MAPPING_H +#define ARCHDEP_KBD_GET_HOST_MAPPING_H + +int archdep_kbd_get_host_mapping(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_list_drives.h b/src/Emulators/vice/arch/archdep_list_drives.h new file mode 100644 index 00000000..1e7e022c --- /dev/null +++ b/src/Emulators/vice/arch/archdep_list_drives.h @@ -0,0 +1,32 @@ +/** \file archdep_list_drives.h + * \brief Get a list of available Windows drives - header + * \author (Unknown) + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_LIST_DRIVES_H +#define VICE_ARCHDEP_LIST_DRIVES_H + +char **archdep_list_drives(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_make_backup_filename.h b/src/Emulators/vice/arch/archdep_make_backup_filename.h new file mode 100644 index 00000000..8326fd41 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_make_backup_filename.h @@ -0,0 +1,32 @@ +/** \file archdep_make_backup_filename.h + * \brief Generate a backup filename for a file - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_MAKE_BACKUP_FILENAME_H +#define VICE_ARCHDEP_MAKE_BACKUP_FILENAME_H + +char *archdep_make_backup_filename(const char *fname); + +#endif diff --git a/src/Emulators/vice/arch/archdep_mkdir.h b/src/Emulators/vice/arch/archdep_mkdir.h new file mode 100644 index 00000000..2674ba8b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_mkdir.h @@ -0,0 +1,38 @@ +/** \file archdep_mkdir.h + * \brief Create a directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_MKDIR_H +#define VICE_ARCHDEP_MKDIR_H + +#define ARCHDEP_MKDIR_RWXU 0700 +#define ARCHDEP_MKDIR_RWXUG 0770 +#define ARCHDEP_MKDIR_RWXUGO 0777 + +int archdep_mkdir (const char *pathname, int mode); +int archdep_mkdir_recursive(const char *pathname, int mode); + +#endif + diff --git a/src/Emulators/vice/arch/archdep_mkstemp_fd.h b/src/Emulators/vice/arch/archdep_mkstemp_fd.h new file mode 100644 index 00000000..1b13bcba --- /dev/null +++ b/src/Emulators/vice/arch/archdep_mkstemp_fd.h @@ -0,0 +1,51 @@ +/** \file archdep_mkstemp_fd.h + * \brief Create temporary file, return file pointer - header + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_MKSTEMP_FD_H +#define VICE_ARCHDEP_MKSTEMP_FD_H + +#include + +/** + * \brief Create temporary file + * + * Create a temporary file with a random name. + * + * \param[out] filename target of temporary file's name + * \param[in] mode file mode + * + * \return file pointer + * + * \note The filename must be freed with lib_free(). + * + * FIXME: For some reason Doxygen doesn't accept this docblock in the .c file + * with '\\fn archdep_mkstemp_fd'. So I had to put it here. + */ +FILE *archdep_mkstemp_fd(char **filename, const char *mode); + +#endif diff --git a/src/Emulators/vice/arch/archdep_network.h b/src/Emulators/vice/arch/archdep_network.h new file mode 100644 index 00000000..62375555 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_network.h @@ -0,0 +1,32 @@ +/** \file archdep_netowrk.h + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_NETWORK_H +#define VICE_ARCHDEP_NETWORK_H + +/* Networking. (in src/socketdrv) */ +int archdep_network_init(void); +void archdep_network_shutdown(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_open_default_log_file.h b/src/Emulators/vice/arch/archdep_open_default_log_file.h new file mode 100644 index 00000000..dbac29b8 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_open_default_log_file.h @@ -0,0 +1,33 @@ +/** \file archdep_open_default_log_file.h + * \brief Open default log file - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_OPEN_DEFAULT_LOG_FILE_H +#define ARCHDEP_OPEN_DEFAULT_LOG_FILE_H + + +FILE *archdep_open_default_log_file(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_path_is_relative.h b/src/Emulators/vice/arch/archdep_path_is_relative.h new file mode 100644 index 00000000..4f1d344b --- /dev/null +++ b/src/Emulators/vice/arch/archdep_path_is_relative.h @@ -0,0 +1,32 @@ +/** \file archdep_path_is_relative.h + * \brief Determine if a path is relative - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_PATH_IS_RELATIVE_H +#define VICE_ARCHDEP_PATH_IS_RELATIVE_H + +int archdep_path_is_relative(const char *path); + +#endif diff --git a/src/Emulators/vice/arch/archdep_program_name.h b/src/Emulators/vice/arch/archdep_program_name.h new file mode 100644 index 00000000..ebc0bb42 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_program_name.h @@ -0,0 +1,34 @@ +/** \file archdep_program_name.h + * \brief Retrieve name of currently running binary - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_PROGRAM_NAME_H +#define VICE_ARCHDEP_PROGRAM_NAME_H + +const char *archdep_program_name(void); +void archdep_program_name_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_program_path.h b/src/Emulators/vice/arch/archdep_program_path.h new file mode 100644 index 00000000..3bed475f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_program_path.h @@ -0,0 +1,48 @@ +/** \file archdep_program_path.h + * \brief Retrieve path of currently running binary - header + * \author Bas Wassink + * + * Get path to running executable. + * + * OS support: + * - Linux + * - Windows + * - MacOS + * - BeOS/Haiku (untested) + * - AmigaOS (untested) + * - OS/2 (untested) + * - MS-DOS (untested) + * + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_PROGRAM_PATH_H +#define VICE_ARCHDEP_PROGRAM_PATH_H + +#include "vice.h" + +void archdep_program_path_set_argv0(char *argv0); +const char *archdep_program_path(void); +void archdep_program_path_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_quote_parameter.h b/src/Emulators/vice/arch/archdep_quote_parameter.h new file mode 100644 index 00000000..81416d39 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_quote_parameter.h @@ -0,0 +1,34 @@ +/** \file archdep_quote_parameter.h + * \brief Add escape sequences to a string - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_QUOTE_PARAMETER_H +#define VICE_ARCHDEP_QUOTE_PARAMETER_H + +#include "vice.h" + +char *archdep_quote_parameter(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_quote_unzip.c b/src/Emulators/vice/arch/archdep_quote_unzip.c new file mode 100644 index 00000000..65f5aa2d --- /dev/null +++ b/src/Emulators/vice/arch/archdep_quote_unzip.c @@ -0,0 +1,57 @@ +/** \file archdep_quote_unzip.c + * \brief Add escape sequences to a filename for use with unzip + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include "lib.h" +#include "util.h" + +#include "archdep_quote_unzip.h" + + +/** \brief Quote \a name for use as a parameter in exec() etc calls with unzip + * + * Surounds \a name with double-quotes and replaces brackets with escaped versions. + * + * \param[in] name string to quote + * + * \return quoted string + */ +char *archdep_quote_unzip(const char *name) +{ +#ifdef WINDOWS_COMPILE + char *a; + char *b; + + a = util_subst(name, "[", "[[]"); + b = util_concat("\"", a, "\"", NULL); + lib_free(a); + return b; +#else + return util_subst(name, "[", "\\["); +#endif +} diff --git a/src/Emulators/vice/arch/archdep_quote_unzip.h b/src/Emulators/vice/arch/archdep_quote_unzip.h new file mode 100644 index 00000000..f39ca1ef --- /dev/null +++ b/src/Emulators/vice/arch/archdep_quote_unzip.h @@ -0,0 +1,32 @@ +/** \file archdep_quote_unzip.h + * \brief Add escape sequences to a filename for use with unzip - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_QUOTE_UNZIP +#define VICE_ARCHDEP_QUOTE_UNZIP + +char *archdep_quote_unzip(const char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_rawnet_capability.h b/src/Emulators/vice/arch/archdep_rawnet_capability.h new file mode 100644 index 00000000..429610b7 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_rawnet_capability.h @@ -0,0 +1,35 @@ +/** \file archdep_rawnet_capability.h + * \brief Determine if ethernet support (libpcap) will actually work - header + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef HAVE_ARCHEP_RAWNET_CAPABILITY_H +#define HAVE_ARCHEP_RAWNET_CAPABILITY_H + +#include + +bool archdep_rawnet_capability(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_real_path.c b/src/Emulators/vice/arch/archdep_real_path.c new file mode 100644 index 00000000..632370b9 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_real_path.c @@ -0,0 +1,94 @@ +/** \file archdep_real_path.c + * \brief Normalize path names + * \author Michael C. Martin + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#ifndef WINDOWS_COMPILE +#include +#else +#include +#endif +#include +#include + +#include "archdep_real_path.h" + +/** \brief Resolve \a pathname to its canonicalized absolute form + * + * \param[in] pathname pathname to normalize. This file must + * exist. + * \param[out] resolved_pathname buffer for result (must be at least + * PATH_MAX/_MAX_PATH long) + * + * \return resolved_pathname on success, NULL on failure. On failure, + * contents of resolved_pathname are undefined. + */ +char *archdep_real_path(const char *pathname, char *resolved_pathname) +{ +#ifdef WINDOWS_COMPILE + DWORD size = GetFullPathNameA(pathname, _MAX_PATH, resolved_pathname, NULL); + if (size == 0 || size >= _MAX_PATH) { + return NULL; + } + size = GetShortPathNameA(resolved_pathname, resolved_pathname, _MAX_PATH); + if (size == 0 || size >= _MAX_PATH) { + return NULL; + } + size = GetLongPathNameA(resolved_pathname, resolved_pathname, _MAX_PATH); + if (size == 0 || size >= _MAX_PATH) { + return NULL; + } + return resolved_pathname; +#else + return realpath(pathname, resolved_pathname); +#endif +} + +/** \brief Compare \a path1 to \a path2 in their canonicalized forms + * + * \param[in] path1 The first path to compare + * \param[in] path2 The second path to compare + * + * \return nonzero if path1 and path2 both refer to the same canonicalized + * path; zero otherwise. If path1 or path2 do not actually exist + * the results are unspecified. + */ +int archdep_real_path_equal(const char *path1, const char *path2) +{ +#ifdef WINDOWS_COMPILE + char path1_norm[_MAX_PATH], path2_norm[_MAX_PATH]; +#else + char path1_norm[PATH_MAX], path2_norm[PATH_MAX]; +#endif + if (!archdep_real_path(path1, path1_norm)) { + return 0; + } + if (!archdep_real_path(path2, path2_norm)) { + return 0; + } + return !strcmp(path1_norm, path2_norm); +} diff --git a/src/Emulators/vice/arch/archdep_real_path.h b/src/Emulators/vice/arch/archdep_real_path.h new file mode 100644 index 00000000..ba520b71 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_real_path.h @@ -0,0 +1,47 @@ +/** \file archdep_real_path.h + * \brief Normalize path names - header + * \author Michael C. Martin + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_REAL_PATH_H +#define VICE_ARCHDEP_REAL_PATH_H + +/* These functions convert, or compare, pathnames in their + * canonicalized forms: aboslute paths, symlinks resolved, and + * capitalization normalized for case-preserving case-insensitive + * filesystems like NTFS and AFS. The following caveats apply to all + * of these functions: + * + * - input paths should be in a form fopen() expects. + * - input paths should be at most PATH_MAX (_MAX_PATH on Windows) long. + * - output paths should fit PATH_MAX (_MAX_PATH on Windows) characters. + * - input paths should exist: canonicalizing paths potentially involves + * directory traversals and if these fail the whole conversion is + * allowed to (but not required to) fail. + */ + +char *archdep_real_path(const char *pathname, char *resolved_pathname); +int archdep_real_path_equal(const char *path1, const char *path2); + +#endif diff --git a/src/Emulators/vice/arch/archdep_remove.c b/src/Emulators/vice/arch/archdep_remove.c new file mode 100644 index 00000000..9dbad2a1 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_remove.c @@ -0,0 +1,63 @@ +/** \file archdep_remove.c + * \brief Remove a file + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - BSD + * - MacOS + * - Haiku + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +#elif defined(WINDOWS_COMPILE) +# include +#else +# error "Unsupported OS!" +#endif + +#include "archdep_remove.h" + + +/** \brief Remove a file + * + * \param[in] path file to remove + * + * \return 0 on success, -1 on failure + */ +int archdep_remove(const char *path) +{ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + return unlink(path); +#elif defined(WINDOWS_COMPILE) + return remove(path); +#else + return -1; +#endif +} diff --git a/src/Emulators/vice/arch/archdep_remove.h b/src/Emulators/vice/arch/archdep_remove.h new file mode 100644 index 00000000..9ac56c7e --- /dev/null +++ b/src/Emulators/vice/arch/archdep_remove.h @@ -0,0 +1,32 @@ +/** \file archdep_remove.h + * \brief Remove a file - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_REMOVE_H +#define VICE_ARCHDEP_REMOVE_H + +int archdep_remove(const char *path); + +#endif diff --git a/src/Emulators/vice/arch/archdep_rename.h b/src/Emulators/vice/arch/archdep_rename.h new file mode 100644 index 00000000..a92fe7cc --- /dev/null +++ b/src/Emulators/vice/arch/archdep_rename.h @@ -0,0 +1,32 @@ +/** \file archdep_rename.h + * \brief Rename a file - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_RENAME_H +#define ARCHDEP_RENAME_H + +int archdep_rename(const char *oldpath, const char *newpath); + +#endif diff --git a/src/Emulators/vice/arch/archdep_require_vkbd.h b/src/Emulators/vice/arch/archdep_require_vkbd.h new file mode 100644 index 00000000..7d8cccb2 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_require_vkbd.h @@ -0,0 +1,32 @@ +/** \file archdep_require_vkbd.h + * \brief + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_REQUIRE_VKBD_H +#define ARCHDEP_REQUIRE_VKBD_H + +int archdep_require_vkbd(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_rmdir.c b/src/Emulators/vice/arch/archdep_rmdir.c new file mode 100644 index 00000000..9faf4883 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_rmdir.c @@ -0,0 +1,60 @@ +/** \file archdep_rmdir.c + * \brief Remove a directory + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" +#include "archdep_defs.h" + +#include +#include +#include + +#if defined(UNIX_COMPILE) || defined(BEOS_COMPILE) +# include +# include +# include +#endif + +#ifdef WINDOWS_COMPILE +# include +#endif + +#include "archdep_rmdir.h" + + +/** \brief Remove directory \a pathname + * + * \param[in] pathname directory to create + * + * \return 0 on success, -1 on error + */ +int archdep_rmdir(const char *pathname) +{ +#ifdef WINDOWS_COMPILE + return _rmdir(pathname); +#else + return rmdir(pathname); +#endif +} diff --git a/src/Emulators/vice/arch/archdep_rmdir.h b/src/Emulators/vice/arch/archdep_rmdir.h new file mode 100644 index 00000000..1ccd7f86 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_rmdir.h @@ -0,0 +1,32 @@ +/** \file archdep_rmdir.h + * \brief Remove a directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_RMDIR_H +#define VICE_ARCHDEP_RMDIR_H + +int archdep_rmdir(const char *pathname); + +#endif diff --git a/src/Emulators/vice/arch/archdep_rtc_get_centisecond.h b/src/Emulators/vice/arch/archdep_rtc_get_centisecond.h new file mode 100644 index 00000000..487b4152 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_rtc_get_centisecond.h @@ -0,0 +1,32 @@ +/** \file archdep_rtc_get_centisecond.h + * \brief get centiseconds time when gettimeofday() is not available + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_RTC_GET_CENTISECOND_H +#define ARCHDEP_RTC_GET_CENTISECOND_H + +int archdep_rtc_get_centisecond(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_sanitize_filename.h b/src/Emulators/vice/arch/archdep_sanitize_filename.h new file mode 100644 index 00000000..128f6e5f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_sanitize_filename.h @@ -0,0 +1,42 @@ +/** \file archdep_sanitize_filename.h + * \brief Sanitize a filename for writing to the host OS - header + * \author Bas Wassink + * + * OS support: + * - Linux + * - Windows + * - MacOS + * - BeOS/Haiku (untested) + * - AmigaOS (untested) + * - OS/2 (untested) + * - MS-DOS (untested) + * + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_SANITIZE_FILENAME +#define VICE_ARCHDEP_SANITIZE_FILENAME + +void archdep_sanitize_filename(char *name); + +#endif diff --git a/src/Emulators/vice/arch/archdep_set_current_drive.h b/src/Emulators/vice/arch/archdep_set_current_drive.h new file mode 100644 index 00000000..0aa69db9 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_set_current_drive.h @@ -0,0 +1,32 @@ +/** \file archdep_set_current_drive.h + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_SET_CURRENT_DRIVE_H +#define VICE_ARCHDEP_SET_CURRENT_DRIVE_H + +/* sets the current drive to the given string */ +void archdep_set_current_drive(const char *drive); + + +#endif diff --git a/src/Emulators/vice/arch/archdep_set_openmp_wait_policy.h b/src/Emulators/vice/arch/archdep_set_openmp_wait_policy.h new file mode 100644 index 00000000..b374276d --- /dev/null +++ b/src/Emulators/vice/arch/archdep_set_openmp_wait_policy.h @@ -0,0 +1,32 @@ +/** \file archdep_set_openmp_wait_policy.h + * \brief Set OMP_WAIT_POLICY to PASSIVE - header + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_SET_OPENMP_WAIT_POLICY +#define VICE_ARCHDEP_SET_OPENMP_WAIT_POLICY + +void archdep_set_openmp_wait_policy(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_signals.h b/src/Emulators/vice/arch/archdep_signals.h new file mode 100644 index 00000000..5e85b31a --- /dev/null +++ b/src/Emulators/vice/arch/archdep_signals.h @@ -0,0 +1,38 @@ +/** \file archdep_signals.c + * \brief Signal handling - header + * + * \author Ettore Perazzoli + * \author Andreas Boose + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_SIGNALS_H +#define VICE_ARCHDEP_SIGNALS_H + +void archdep_signals_pipe_set(void); +void archdep_signals_pipe_unset(void); +void archdep_signals_init(int do_core_dumps); + +#endif diff --git a/src/Emulators/vice/arch/archdep_sleep.c b/src/Emulators/vice/arch/archdep_sleep.c new file mode 100644 index 00000000..4a697f6f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_sleep.c @@ -0,0 +1,58 @@ +/** \file archdep_sleep.c + * \brief sleep replacements for OS'es that don't support sleep + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#ifdef WINDOWS_COMPILE +# include +#endif + +#ifdef UNIX_COMPILE +# include +#endif + +#include "archdep_sleep.h" + +#ifdef WINDOWS_COMPILE + +/* Provide a sleep replacement */ +void archdep_sleep(unsigned int seconds) +{ + Sleep((seconds) * 1000U); +} + +#endif + + +#ifdef UNIX_COMPILE + +void archdep_sleep(unsigned int seconds) +{ + sleep(seconds); +} + +#endif diff --git a/src/Emulators/vice/arch/archdep_sleep.h b/src/Emulators/vice/arch/archdep_sleep.h new file mode 100644 index 00000000..3fe17e71 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_sleep.h @@ -0,0 +1,36 @@ +/** \file archdep_sleep.h + * \brief sleep replacements for OS'es that don't support sleep - header + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef ARCHDEP_SLEEP_H +#define ARCHDEP_SLEEP_H + +#include "vice.h" + +void archdep_sleep(unsigned int seconds); + +#endif diff --git a/src/Emulators/vice/arch/archdep_socketpeek.h b/src/Emulators/vice/arch/archdep_socketpeek.h new file mode 100644 index 00000000..95a994b5 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_socketpeek.h @@ -0,0 +1,38 @@ +/** \file archdep_socketpeek.h + * \brief socketpeek function to avoid ioctl()'s + * + * \author pottendo + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef ARCHDEP_SOCKETPEEK_H +#define ARCHDEP_SOCKETPEEK_H + +#include "vice.h" + +#include + +int archdep_socketpeek(int fd, int *bytes_available); + +#endif diff --git a/src/Emulators/vice/arch/archdep_sound.c b/src/Emulators/vice/arch/archdep_sound.c new file mode 100644 index 00000000..60a30fa3 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_sound.c @@ -0,0 +1,78 @@ +/** \file archdep_sound.c + * \brief Shared platform sound code + * \author David Hogan + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "archdep_sound.h" + +#include "sound.h" + +#ifdef MACOS_COMPILE + +#include + +static OSStatus on_default_device_changed(AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], + void *inClientData) +{ + /* + * If we are monitoring the default audio device, then we launched without + * requesting a specific device. Therefore when the default output device + * changes, reinitialise sound so that our sound targets the new default device + */ + + sound_state_changed = 1; + + return 0; +} + +void archdep_sound_enable_default_device_tracking(void) +{ + AudioObjectPropertyAddress outputDeviceAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + AudioObjectAddPropertyListener(kAudioObjectSystemObject, + &outputDeviceAddress, + on_default_device_changed, + nil); +} + +#else /* #ifdef MACOS_COMPILE */ + +/* Not supported on puny Linux and Windows yet */ + +void archdep_sound_enable_default_device_tracking(void) +{ +} + +#endif /* #ifdef MACOS_COMPILE */ diff --git a/src/Emulators/vice/arch/archdep_sound.h b/src/Emulators/vice/arch/archdep_sound.h new file mode 100644 index 00000000..456bffa7 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_sound.h @@ -0,0 +1,32 @@ +/** \file archdep_sound.h + * \brief Shared platform sound code + * \author David Hogan + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_SOUND_H +#define ARCHDEP_SOUND_H + +void archdep_sound_enable_default_device_tracking(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_spawn.h b/src/Emulators/vice/arch/archdep_spawn.h new file mode 100644 index 00000000..798856b6 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_spawn.h @@ -0,0 +1,36 @@ +/** \file archdep_spawn.h + * \brief Process spawning - header + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef VICE_ARCHDEP_SPAWN_H +#define VICE_ARCHDEP_SPAWN_H + +int archdep_spawn(const char *name, char **argv, + char **pstdout_redir, const char *stderr_redir); + +#endif diff --git a/src/Emulators/vice/arch/archdep_startup_log_error.h b/src/Emulators/vice/arch/archdep_startup_log_error.h new file mode 100644 index 00000000..cda79e3e --- /dev/null +++ b/src/Emulators/vice/arch/archdep_startup_log_error.h @@ -0,0 +1,33 @@ +/** \file archdep_startup_log_error.h + * \brief Log error message on startup - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_STARTUP_LOG_ERROR_H +#define VICE_ARCHDEP_STARTUP_LOG_ERROR_H + +void archdep_startup_log_error(const char *format, ...) VICE_ATTR_PRINTF; + +#endif diff --git a/src/Emulators/vice/arch/archdep_stat.h b/src/Emulators/vice/arch/archdep_stat.h new file mode 100644 index 00000000..4d98ae1c --- /dev/null +++ b/src/Emulators/vice/arch/archdep_stat.h @@ -0,0 +1,43 @@ +/** \file archdep_stat.h + * \brief Simplified stat(2) call - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_STAT_H +#define ARCHDEP_STAT_H + +#include + +/* Visual Studio doesn't provide these macros. */ +#ifdef _MSC_VER +#define S_ISDIR(_m) (((_m) & S_IFMT) == _S_IFDIR) +#define S_ISFIFO(_m) (((_m) & S_IFMT) == _S_IFIFO) +#define S_ISCHR(_m) (((_m) & S_IFMT) == _S_IFCHR) +#define S_ISBLK(_m) (((_m) & S_IFMT) == _S_IFBLK) +#define S_ISREG(_m) (((_m) & S_IFMT) == _S_IFREG) +#endif + +int archdep_stat(const char *filename, size_t *len, unsigned int *isdir); + +#endif diff --git a/src/Emulators/vice/arch/archdep_tick.h b/src/Emulators/vice/arch/archdep_tick.h new file mode 100644 index 00000000..473eee38 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_tick.h @@ -0,0 +1,68 @@ +/** \file archdep_tick.h + * \brief Relating to the management of time. + * + * \author David Hogan + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_TICK_H +#define VICE_TICK_H + +#include + +#define MILLI_PER_SECOND (1000) +#define MICRO_PER_SECOND (1000 * 1000) +#define NANO_PER_SECOND (1000 * 1000 * 1000) + +/* + * The internal VICE timing resolution. + * BTW, Windows can't be more accurate than (NANO_PER_SECOND / 100). + */ +#define TICK_PER_SECOND (MICRO_PER_SECOND) + +/* Using a 32-bit type for tick_t prevents wraparound bugs on platforms with 32-bit timers */ +typedef uint32_t tick_t; + +#define TICK_TO_MILLI(tick) ((uint32_t) (uint64_t)((double)(tick) * ((double)MILLI_PER_SECOND / TICK_PER_SECOND))) +#define TICK_TO_MICRO(tick) ((uint32_t) (uint64_t)((double)(tick) * ((double)MICRO_PER_SECOND / TICK_PER_SECOND))) +#define TICK_TO_NANO(tick) ((uint64_t) (uint64_t)((double)(tick) * ((double)NANO_PER_SECOND / TICK_PER_SECOND))) +#define NANO_TO_TICK(nano) ((tick_t) (uint64_t)((double)(nano) / ((double)NANO_PER_SECOND / TICK_PER_SECOND))) + +void tick_init(void); + +/* number of ticks per second */ +tick_t tick_per_second(void); + +/* Get time in ticks. */ +tick_t tick_now(void); + +/* Get time in ticks, compensating for the +/- 1 tick that is possible on Windows. */ +tick_t tick_now_after(tick_t previous_tick); + +/* Get number of ticks since a previous tick, compensating for the +/- 1 tick that is possible on Windows. */ +tick_t tick_now_delta(tick_t previous_tick); + +/* Sleep a number of ticks. */ +void tick_sleep(tick_t delay); + +#endif diff --git a/src/Emulators/vice/arch/archdep_tmpnam.h b/src/Emulators/vice/arch/archdep_tmpnam.h new file mode 100644 index 00000000..5cf7609f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_tmpnam.h @@ -0,0 +1,33 @@ +/** \file archdep_tmpnam.h + * \brief Generate a unique, temporary filename - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_TMPNAM_H +#define VICE_ARCHDEP_TMPNAM_H + +char *archdep_tmpnam(void); + +#endif + diff --git a/src/Emulators/vice/arch/archdep_user_cache_path.h b/src/Emulators/vice/arch/archdep_user_cache_path.h new file mode 100644 index 00000000..28150885 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_user_cache_path.h @@ -0,0 +1,33 @@ +/** \file archdep_user_cache_path.h + * \brief Retrieve path to the user's cache directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_USER_CACHE_PATH_H +#define VICE_ARCHDEP_USER_CACHE_PATH_H + +const char *archdep_user_cache_path(void); +void archdep_user_cache_path_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_user_config_path.h b/src/Emulators/vice/arch/archdep_user_config_path.h new file mode 100644 index 00000000..6b720a0f --- /dev/null +++ b/src/Emulators/vice/arch/archdep_user_config_path.h @@ -0,0 +1,35 @@ +/** \file archdep_user_config_path.h + * \brief Retrieve path to the user's configuration directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_USER_CONFIG_PATH_H +#define VICE_ARCHDEP_USER_CONFIG_PATH_H + +const char *archdep_user_config_path(void); +void archdep_user_config_path_free(void); + +#endif + + diff --git a/src/Emulators/vice/arch/archdep_user_state_path.h b/src/Emulators/vice/arch/archdep_user_state_path.h new file mode 100644 index 00000000..b93fe570 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_user_state_path.h @@ -0,0 +1,33 @@ +/** \file archdep_user_state_path.h + * \brief Retrieve path to the user's state directory - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_USER_STATE_PATH_H +#define VICE_ARCHDEP_USER_STATE_PATH_H + +const char *archdep_user_state_path(void); +void archdep_user_state_path_free(void); + +#endif diff --git a/src/Emulators/vice/arch/archdep_usleep.c b/src/Emulators/vice/arch/archdep_usleep.c new file mode 100644 index 00000000..6593f009 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_usleep.c @@ -0,0 +1,70 @@ +/** \file archdep_usleep.c + * \brief usleep replacements for OS'es that don't support usleep + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include + +#ifdef WINDOWS_COMPILE +# include +#endif + +#ifdef UNIX_COMPILE +# include +#endif + +#include "archdep_usleep.h" + +#ifdef WINDOWS_COMPILE + +/* Provide a usleep replacement */ +void archdep_usleep(uint64_t usec) +{ + uint64_t time1 = 0, time2 = 0, freq = 0; + + QueryPerformanceCounter((LARGE_INTEGER *) &time1); + QueryPerformanceFrequency((LARGE_INTEGER *)&freq); + + do { + QueryPerformanceCounter((LARGE_INTEGER *) &time2); + } while((time2-time1) < usec); +} + +#endif + + +#ifdef UNIX_COMPILE + +void archdep_usleep(uint64_t usec) +{ + struct timespec req = { 0, (long)usec * 1000 }; + + nanosleep(&req, NULL); +} + +#endif diff --git a/src/Emulators/vice/arch/archdep_usleep.h b/src/Emulators/vice/arch/archdep_usleep.h new file mode 100644 index 00000000..c5701bbe --- /dev/null +++ b/src/Emulators/vice/arch/archdep_usleep.h @@ -0,0 +1,39 @@ +/** \file archdep_usleep.h + * \brief usleep replacements for OS'es that don't support usleep - header + * + * \author Marco van den Heuvel + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef ARCHDEP_USLEEP_H +#define ARCHDEP_USLEEP_H + +#include "vice.h" + +#include + +void archdep_usleep(uint64_t usec); + +#endif diff --git a/src/Emulators/vice/arch/archdep_win32.h b/src/Emulators/vice/arch/archdep_win32.h new file mode 100644 index 00000000..6ec65223 --- /dev/null +++ b/src/Emulators/vice/arch/archdep_win32.h @@ -0,0 +1,131 @@ +/** \file archdep_win32.h + * \brief Windows-specific stuff - header + * + * \author Marco van den Heuvel + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_WIN32_H +#define VICE_ARCHDEP_WIN32_H + +#define VICE_ARCHAPI_PRIVATE_API +#include "archapi.h" +#undef VICE_ARCHAPI_PRIVATE_API + +/* Default MIDI devices. */ +#define ARCHDEP_MIDI_IN_DEV "0" /**< MIDI input dev */ +#define ARCHDEP_MIDI_OUT_DEV "0" /**< MIDI output dev */ + +/* Filesystem-dependent constants */ +#define ARCHDEP_FSDEVICE_DEFAULT_DIR "." +#define ARCHDEP_DIR_SEP_STR "\\" +#define ARCHDEP_DIR_SEP_CHR '\\' + +/* Path separator. */ +#define ARCHDEP_FINDPATH_SEPARATOR_CHAR ';' +#define ARCHDEP_FINDPATH_SEPARATOR_STRING ";" + +/* Modes for fopen(). */ +#define MODE_READ "rb" +#define MODE_READ_TEXT "rt" +#define MODE_READ_WRITE "rb+" +#define MODE_WRITE "wb" +#define MODE_WRITE_TEXT "wt" +#define MODE_APPEND "ab" +#define MODE_APPEND_READ_WRITE "ab+" + +/* Printer default devices. */ +#define ARCHDEP_PRINTER_DEFAULT_DEV1 "viceprnt.out" +#define ARCHDEP_PRINTER_DEFAULT_DEV2 "LPT1:" +#define ARCHDEP_PRINTER_DEFAULT_DEV3 "LPT2:" + +/* Default RS232 devices. */ +#define ARCHDEP_RS232_DEV1 "com1" +#define ARCHDEP_RS232_DEV2 "com2" +#define ARCHDEP_RS232_DEV3 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV4 "127.0.0.1:25232" + +/* Default location of raw disk images. */ +#define ARCHDEP_RAWDRIVE_DEFAULT "A:" + +/* Standard line delimiter. */ +#define ARCHDEP_LINE_DELIMITER "\r\n" + +/* Ethernet default device */ +#define ARCHDEP_ETHERNET_DEFAULT_DEVICE "" + +/* + FIXME: confirm wether SIGPIPE must be handled or not. if the emulator quits + or crashes when the connection is closed, you might have to install + a signal handler which calls monitor_abort(). + + see archdep_unix.c and bug #3201796 +*/ +void archdep_signals_init(int do_coredumps); + +#define MAKE_SO_NAME_VERSION_PROTO(name, version) #name "-" #version ".dll" + +/* add second level macro to allow expansion and stringification */ +#define ARCHDEP_MAKE_SO_NAME_VERSION(n, v) MAKE_SO_NAME_VERSION_PROTO(n, v) + +#define ARCHDEP_OPENCBM_SO_NAME "opencbm.dll" +#define ARCHDEP_LAME_SO_NAME "lame.dll" + +/* ffmpeg headers for windows don't seem to have some of the av_ prefixes */ +#define ARCHDEP_AV_PREFIX_NEEDED + +/* Needs extra call to log_archdep() even when logfile is already opened */ +#define ARCHDEP_EXTRA_LOG_CALL + +/* When using the ascii printer driver we need a return before the newline */ +#define ARCHDEP_PRINTER_RETURN_BEFORE_NEWLINE + +/* what to use to return an error when a socket error happens */ +#define ARCHDEP_SOCKET_ERROR WSAGetLastError() + +int archdep_is_windows_nt(void); + +#endif + +/* FIXME: was dangling around in old archdep. remove once everything is working */ +#if 0 +static char *system_mbstowcs_alloc(const char *mbs) +{ + char *wcs; + size_t len; + + if (mbs == NULL) { + return NULL; + } + + len = strlen(mbs); + + wcs = lib_malloc(len + 1); + return memcpy(wcs, mbs, len + 1); +} + +static void system_mbstowcs_free(char *wcs) +{ + lib_free(wcs); +} +#endif diff --git a/src/Emulators/vice/arch/archdep_xdg.h b/src/Emulators/vice/arch/archdep_xdg.h new file mode 100644 index 00000000..a542424e --- /dev/null +++ b/src/Emulators/vice/arch/archdep_xdg.h @@ -0,0 +1,35 @@ +/** \file archdep_xdg.h + * \brief XDG base dir specification support - header + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_XDG_H +#define VICE_ARCHDEP_XDG_H + +char *archdep_xdg_cache_home (void); +char *archdep_xdg_config_home(void); +char *archdep_xdg_data_home (void); +char *archdep_xdg_state_home (void); + +#endif diff --git a/src/Emulators/vice/arch/coproc.c b/src/Emulators/vice/arch/coproc.c index 9355f36f..913ed78f 100644 --- a/src/Emulators/vice/arch/coproc.c +++ b/src/Emulators/vice/arch/coproc.c @@ -1,9 +1,10 @@ -/* - * coproc.c - coproc.c wrapper for the sdl port. - * - * Written by - * Marco van den Heuvel +/** \file coproc.c + * \brief co-process fork * + * \author Andre Fachat + */ + +/* * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -24,8 +25,316 @@ * */ +/* + * This is modelled after some examples in Stevens, "Advanced Progamming + * in the Unix environment", Addison Wesley. + * + * It simply opens two uni-directional pipes and forks a process to + * use the pipes as bidirectional connection for the stdin/out of the + * child. + * This, however, implies that the child knows its being piped and _buffers_ + * all stdio. To avoid that one has to open a pseudo terminal device, + * which is too heavily system dependant to be included here. + * Instead a wrapper like the program "pty" described in the book mentioned + * above could be used. + * + * Technicalities: It does not store the PID of the forked child but + * instead it relies on the child being killed when the parent terminates + * prematurely or the child terminates itself on EOF on stdin. + * + * The command string is given to "/bin/sh -c cmdstring" such that + * the shell can do fileexpansion. + * + * We ignore all SIGCHLD and SIGPIPE signals that may occur here by + * installing an ignoring handler. + */ + +/* + spawns a shell and executes a shell command (which can be a program) + as a background process + + cmd command to run + + returns: + + fd_wr stdin of the child process + fd_rd stdout of the child process + childpid PID of the child process (to be used with kill_coproc) + + return value: 0:ok, -1:error + +*/ + +/* this code is currently used to spawn sub processes in: + - gfxoutputdrv/ffmpegexedrv.c + - printerdrv/output-text.c + - arch/shared/rs232-unix-dev.c + - arch/shared/rs232-win32-dev.c +*/ + #include "vice.h" -//#if defined(UNIX_COMPILE) && !defined(CEGCC_COMPILE) -//#include "../unix/coproc.c" -//#endif +/* #define DEBUG_COPROC */ + +#ifdef DEBUG_COPROC +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* TODO: Perhaps implement fork_coproc() on Haiku using Haiku-specific code + * instead of relying on the POSIX compatibility layer? */ +#if defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) + +#include +#include +#include +#include +#include +#include + +#include "archdep.h" +#include "log.h" + +#include "coproc.h" + +/* On Haiku /bin/sh is symlinked to /boot/system/bin/bash, so the following + * also works on Haiku: + */ +#define SHELL "/bin/sh" + +#ifndef sigset_t +#define sigset_t int +#endif + +static struct sigaction ignore; + +int fork_coproc(int *fd_wr, int *fd_rd, char *cmd, vice_pid_t *childpid) +{ + int pipe_stdout_fd[2], pipe_stdin_fd[2]; + vice_pid_t pid; + + ignore.sa_handler = SIG_IGN; + sigemptyset(&ignore.sa_mask); + ignore.sa_flags = SA_NOCLDSTOP | SA_RESTART; + + sigaction(SIGCHLD, &ignore, NULL); + sigaction(SIGPIPE, &ignore, NULL); + + *fd_rd = *fd_wr = *childpid = -1; + + if (pipe(pipe_stdout_fd) < 0) { + log_error(LOG_DEFAULT, "Coproc: Couldn't open pipe!"); + return -1; + } + if (pipe(pipe_stdin_fd) < 0) { + log_error(LOG_DEFAULT, "Coproc: Couldn't open pipe!"); + close(pipe_stdout_fd[0]); + close(pipe_stdout_fd[1]); + return -1; + } + + log_message(LOG_DEFAULT, "Coproc: forking process '%s'", cmd); + if ((pid = fork()) < 0) { + log_error(LOG_DEFAULT, "Coproc: Couldn't fork()!"); + close(pipe_stdout_fd[0]); + close(pipe_stdout_fd[1]); + close(pipe_stdin_fd[0]); + close(pipe_stdin_fd[1]); + return -1; + } else if (pid == 0) { + /* child */ + close(pipe_stdout_fd[0]); + if (pipe_stdout_fd[1] != STDOUT_FILENO) { + dup2(pipe_stdout_fd[1], STDOUT_FILENO); + close(pipe_stdout_fd[1]); + } + close(pipe_stdin_fd[1]); + if (pipe_stdin_fd[0] != STDIN_FILENO) { + dup2(pipe_stdin_fd[0], STDIN_FILENO); + close(pipe_stdin_fd[0]); + } + + /* Hm, we have to close all other files that are currently + open now... */ + execl(SHELL, SHELL, "-c", cmd, NULL); + + archdep_vice_exit(127); /* child dies on error */ + } else { + /* parent */ + close(pipe_stdout_fd[1]); + close(pipe_stdin_fd[0]); + + *fd_rd = pipe_stdout_fd[0]; + *fd_wr = pipe_stdin_fd[1]; + *childpid = pid; + log_message(LOG_DEFAULT, "forked process id is: %d", pid); + } + return 0; +} + +void kill_coproc(vice_pid_t pid) +{ + log_message(LOG_DEFAULT, "terminating child process id: %d", pid); + if (kill(pid, SIGKILL) != 0) { + if (errno == ESRCH) { + log_debug(LOG_DEFAULT, "child process id %d does not exist anymore.", pid); + } else { + log_error(LOG_DEFAULT, "terminating child process id %d failed.", pid); + } + } +} + +#elif defined(WINDOWS_COMPILE) + +#include "archdep.h" +#include "coproc.h" +#include "lib.h" +#include "log.h" + +#include +#include +#include +#include +#include + +/* https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output */ + +/* https://marc.info/?l=apreq-dev&m=104840521714506 mentions some hackery we might need too */ + +/* Create a child process that uses the previously created pipes for STDIN and STDOUT. */ +static int CreateChildProcess( + TCHAR *szCmdline, + HANDLE hChildStd_IN_Rd, + HANDLE hChildStd_OUT_Wr, + HANDLE *pid) +{ + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + BOOL bSuccess = FALSE; + + /* Set up members of the PROCESS_INFORMATION structure. */ + ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); + + /* Set up members of the STARTUPINFO structure. */ + /* This structure specifies the STDIN and STDOUT handles for redirection. */ + ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = hChildStd_OUT_Wr; + siStartInfo.hStdOutput = hChildStd_OUT_Wr; + siStartInfo.hStdInput = hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_HIDE; + + /* Create the child process. */ + bSuccess = CreateProcess(NULL, + szCmdline, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* handles are inherited */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &siStartInfo, /* STARTUPINFO pointer */ + &piProcInfo); /* receives PROCESS_INFORMATION */ + + /* If an error occurs, exit */ + if (!bSuccess) { + return -1; + } else { + /* Close handles to the child process and its primary thread. + Some applications might keep these handles to monitor the status + of the child process, for example. */ + *pid = piProcInfo.hProcess; + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + + /* Close handles to the stdin and stdout pipes no longer needed by the child process. + If they are not explicitly closed, there is no way to recognize that the child process has ended. */ + CloseHandle(hChildStd_OUT_Wr); + CloseHandle(hChildStd_IN_Rd); + } + return 0; +} + +int fork_coproc(int *fd_wr, int *fd_rd, char *cmd, vice_pid_t *pid) +{ + HANDLE hChildStd_IN_Rd = NULL; + HANDLE hChildStd_OUT_Wr = NULL; + HANDLE hChildStd_IN_Wr = NULL; + HANDLE hChildStd_OUT_Rd = NULL; + SECURITY_ATTRIBUTES saAttr; + char *cmdline; + + /* Set the bInheritHandle flag so pipe handles are inherited. */ + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* Create a pipe for the child process's STDOUT. */ + if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0)) { + return -1; + } + + /* Ensure the read handle to the pipe for STDOUT is not inherited. */ + if (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { + return -1; + } + + /* Create a pipe for the child process's STDIN. */ + if (!CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &saAttr, 0)) { + return -1; + } + + /* Ensure the write handle to the pipe for STDIN is not inherited. */ + if (!SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { + return -1; + } + + /* use a subshell to execute the given cmdline */ + cmdline = lib_malloc(strlen(cmd) + 20); + strcpy(cmdline, "cmd.exe /C "); + strcat(cmdline, cmd); + + /* Create the child process. */ + if (CreateChildProcess(cmdline, hChildStd_IN_Rd, hChildStd_OUT_Wr, pid) < 0) { + lib_free(cmdline); + return -1; + } + + lib_free(cmdline); + + /* convert the windows HANDLEs to a regular file handle */ + *fd_wr = _open_osfhandle((intptr_t)hChildStd_IN_Wr, _O_WRONLY | _O_BINARY); + *fd_rd = _open_osfhandle((intptr_t)hChildStd_OUT_Rd, _O_RDONLY | _O_BINARY); + + return 0; +} + +void kill_coproc(vice_pid_t pid) +{ + log_message(LOG_DEFAULT, "terminating child process id: %p", pid); + if (TerminateProcess(pid, 0) != 0) { + if (GetLastError() == ERROR_INVALID_HANDLE) { + log_debug(LOG_DEFAULT, "child process id %p does not exist anymore.", pid); + } else { + log_error(LOG_DEFAULT, "terminating child process id %p failed.", pid); + } + } +} + +#else + +/* Stub for systems other than Unix, MacOS, Windows or Haiku: */ +int fork_coproc(int *fd_wr, int *fd_rd, char *cmd, vice_pid_t *pid) +{ + log_error(LOG_DEFAULT, "FIXME: fork_coproc() not implemented for this system."); + return -1; +} + +void kill_coproc(vice_pid_t pid) +{ + log_error(LOG_DEFAULT, "FIXME: kill_coproc() not implemented for this system."); +} + +#endif diff --git a/src/Emulators/vice/arch/coproc.h b/src/Emulators/vice/arch/coproc.h index 4d0c3c84..893a2418 100644 --- a/src/Emulators/vice/arch/coproc.h +++ b/src/Emulators/vice/arch/coproc.h @@ -1,10 +1,10 @@ +/** \file coproc.h + * \brief co-process fork - header + * + * \author Andre Fachat + */ /* - * coproc.h - coproc.h wrapper for the sdl port. - * - * Written by - * Marco van den Heuvel - * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -25,11 +25,20 @@ * */ -#ifndef VICE_SDL_COPROC_H -#define VICE_SDL_COPROC_H +#ifndef VICE_COPROC_H +#define VICE_COPROC_H + +#if defined(WINDOWS_COMPILE) +#include +typedef HANDLE vice_pid_t; +#define VICE_PID_INVALID NULL +#else +#include +typedef pid_t vice_pid_t; +#define VICE_PID_INVALID -1 +#endif -//#if defined(UNIX_COMPILE) && !defined(CEGCC_COMPILE) -//#include "../unix/coproc.h" -//#endif +int fork_coproc(int *fd_wr, int *fd_rd, char *cmd, vice_pid_t *childpid); +void kill_coproc(vice_pid_t pid); #endif diff --git a/src/Emulators/vice/arch/fullscreen.c b/src/Emulators/vice/arch/fullscreen.c index df8671f4..48f99e8d 100644 --- a/src/Emulators/vice/arch/fullscreen.c +++ b/src/Emulators/vice/arch/fullscreen.c @@ -72,38 +72,8 @@ static int fullscreen_enable(struct video_canvas_s *canvas, int enable) return 0; } -static int fullscreen_statusbar(struct video_canvas_s *canvas, int enable) -{ - DBG(("%s: %i", __func__, enable)); - return 0; -} - -static int fullscreen_double_size(struct video_canvas_s *canvas, int double_size) -{ - DBG(("%s: %i", __func__, double_size)); - return 0; -} - -static int fullscreen_double_scan(struct video_canvas_s *canvas, int double_scan) -{ - DBG(("%s: %i", __func__, double_scan)); - return 0; -} - -static int fullscreen_device(struct video_canvas_s *canvas, const char *device) -{ - DBG(("%s: %s", __func__, device)); - - LOGD("canvas=%x", canvas); - -// if (strcmp("SDL", device) != 0) { -// canvas->fullscreenconfig->device_set = 0; -// return -1; -// } -// -// canvas->fullscreenconfig->device_set = 1; - return 0; -} +/* VICE 3.10 gutted cap_fullscreen_s to {enable, mode[]}; the statusbar/ + double_size/double_scan/device capability hooks were removed. */ static int fullscreen_mode_sdl(struct video_canvas_s *canvas, int mode) { @@ -117,13 +87,6 @@ void fullscreen_capability(cap_fullscreen_t *cap_fullscreen) { DBG(("%s", __func__)); - cap_fullscreen->device_num = 0; - cap_fullscreen->device_name[cap_fullscreen->device_num] = "SDL"; cap_fullscreen->enable = fullscreen_enable; - cap_fullscreen->statusbar = fullscreen_statusbar; - cap_fullscreen->double_size = fullscreen_double_size; - cap_fullscreen->double_scan = fullscreen_double_scan; - cap_fullscreen->device = fullscreen_device; - cap_fullscreen->mode[cap_fullscreen->device_num] = fullscreen_mode_sdl; - cap_fullscreen->device_num += 1; + cap_fullscreen->mode[0] = fullscreen_mode_sdl; } diff --git a/src/Emulators/vice/arch/joy.c b/src/Emulators/vice/arch/joy.c index 9228f198..77950975 100644 --- a/src/Emulators/vice/arch/joy.c +++ b/src/Emulators/vice/arch/joy.c @@ -48,7 +48,6 @@ #include "machine.h" #include "resources.h" #include "sysfile.h" -#include "translate.h" #include "util.h" #include "uihotkey.h" #include "uimenu.h" @@ -58,7 +57,7 @@ #define DEFAULT_JOYSTICK_FUZZ 1000 #ifdef HAVE_SDL_NUMJOYSTICKS -static log_t sdljoy_log = LOG_ERR; +static log_t sdljoy_log = LOG_DEFAULT; /* Autorepeat in menu & vkbd */ static ui_menu_action_t autorepeat; @@ -225,44 +224,30 @@ static const resource_int_t resources_int[] = { static const cmdline_option_t cmdline_options[] = { #ifdef HAVE_SDL_NUMJOYSTICKS - { "-joymap", SET_RESOURCE, 1, NULL, NULL, "JoyMapFile", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - N_(""), "Specify name of joystick map file" }, - { "-joythreshold", SET_RESOURCE, 1, NULL, NULL, "JoyThreshold", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-32767>", "Set joystick threshold" }, - { "-joyfuzz", SET_RESOURCE, 1, NULL, NULL, "JoyFuzz", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-32767>", "Set joystick fuzz" }, + { "-joymap", SET_RESOURCE, 1, NULL, NULL, "JoyMapFile", NULL, N_(""), "Specify name of joystick map file"}, + { "-joythreshold", SET_RESOURCE, 1, NULL, NULL, "JoyThreshold", NULL, "<0-32767>", "Set joystick threshold"}, + { "-joyfuzz", SET_RESOURCE, 1, NULL, NULL, "JoyFuzz", NULL, "<0-32767>", "Set joystick fuzz"}, #endif CMDLINE_LIST_END }; static const cmdline_option_t joydev1cmdline_options[] = { - { "-joydev1", SET_RESOURCE, 1, NULL, NULL, "JoyDevice1", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-4>", "Set device for joystick port 1" }, + { "-joydev1", SET_RESOURCE, 1, NULL, NULL, "JoyDevice1", NULL, "<0-4>", "Set device for joystick port 1"}, CMDLINE_LIST_END }; static const cmdline_option_t joydev2cmdline_options[] = { - { "-joydev2", SET_RESOURCE, 1, NULL, NULL, "JoyDevice2", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-4>", "Set device for joystick port 2" }, + { "-joydev2", SET_RESOURCE, 1, NULL, NULL, "JoyDevice2", NULL, "<0-4>", "Set device for joystick port 2"}, CMDLINE_LIST_END }; static const cmdline_option_t joydev3cmdline_options[] = { - { "-extrajoydev1", SET_RESOURCE, 1, NULL, NULL, "JoyDevice3", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-4>", "Set device for extra joystick port 1" }, + { "-extrajoydev1", SET_RESOURCE, 1, NULL, NULL, "JoyDevice3", NULL, "<0-4>", "Set device for extra joystick port 1"}, CMDLINE_LIST_END }; static const cmdline_option_t joydev4cmdline_options[] = { - { "-extrajoydev2", SET_RESOURCE, 1, NULL, NULL, "JoyDevice4", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "<0-4>", "Set device for extra joystick port 2" }, + { "-extrajoydev2", SET_RESOURCE, 1, NULL, NULL, "JoyDevice4", NULL, "<0-4>", "Set device for extra joystick port 2"}, CMDLINE_LIST_END }; @@ -388,7 +373,7 @@ int joy_arch_init(void) // for (i = 0; i < num_joysticks; ++i) { // joy = sdljoystick[i].joyptr = SDL_JoystickOpen(i); // if (joy) { -// sdljoystick[i].name = lib_stralloc(SDL_JoystickName(i)); +// sdljoystick[i].name = lib_strdup(SDL_JoystickName(i)); // axis = sdljoystick[i].input_max[AXIS] = SDL_JoystickNumAxes(joy); // button = sdljoystick[i].input_max[BUTTON] = SDL_JoystickNumButtons(joy); // hat = sdljoystick[i].input_max[HAT] = SDL_JoystickNumHats(joy); diff --git a/src/Emulators/vice/arch/kbd.c b/src/Emulators/vice/arch/kbd.c index 2482b15d..644c08aa 100644 --- a/src/Emulators/vice/arch/kbd.c +++ b/src/Emulators/vice/arch/kbd.c @@ -51,7 +51,7 @@ #include "util.h" #include "vkbd.h" -static log_t sdlkbd_log = LOG_ERR; +static log_t sdlkbd_log = LOG_DEFAULT; /* Hotkey filename */ static char *hotkey_file = NULL; @@ -184,7 +184,7 @@ static void sdlkbd_parse_entry(char *buffer) // // p = strtok(NULL, "\r\n"); // if (p != NULL) { -// full_path = lib_stralloc(p); +// full_path = lib_strdup(p); // action = sdl_ui_hotkey_action(p); // if (action == NULL) { // log_warning(sdlkbd_log, "Cannot find menu item \"%s\"!", full_path); @@ -202,7 +202,7 @@ int sdlkbd_hotkeys_load(const char *filename) // char buffer[1000]; // // /* Silently ignore keymap load on resource & cmdline init */ -// if (sdlkbd_log == LOG_ERR) { +// if (sdlkbd_log == LOG_DEFAULT) { // return 0; // } // diff --git a/src/Emulators/vice/arch/menu_drive.c b/src/Emulators/vice/arch/menu_drive.c index 8d439bb5..fe31ef5f 100644 --- a/src/Emulators/vice/arch/menu_drive.c +++ b/src/Emulators/vice/arch/menu_drive.c @@ -86,7 +86,7 @@ static int has_fs(void) static int is_fs(int type) { - return ((type == 0 || type == ATTACH_DEVICE_FS || type == ATTACH_DEVICE_REAL || type == ATTACH_DEVICE_RAW) && has_fs()); + return ((type == 0 || type == ATTACH_DEVICE_FS || type == ATTACH_DEVICE_REAL) && has_fs()); /* VICE 3.10: ATTACH_DEVICE_RAW removed */ } static int get_drive_type(int drive) @@ -290,7 +290,7 @@ static UI_MENU_CALLBACK(attach_disk_callback) if (activated) { name = sdl_ui_file_selection_dialog("Select disk image", FILEREQ_MODE_CHOOSE_FILE); if (name != NULL) { - if (file_system_attach_disk(vice_ptr_to_int(param), name) < 0) { + if (file_system_attach_disk(vice_ptr_to_int(param), 0, name) < 0) { ui_error("Cannot attach disk image."); } lib_free(name); @@ -306,12 +306,12 @@ static UI_MENU_CALLBACK(detach_disk_callback) if (activated) { parameter = vice_ptr_to_int(param); if (parameter == 0) { - file_system_detach_disk(8); - file_system_detach_disk(9); - file_system_detach_disk(10); - file_system_detach_disk(11); + file_system_detach_disk(8, 0); + file_system_detach_disk(9, 0); + file_system_detach_disk(10, 0); + file_system_detach_disk(11, 0); } else { - file_system_detach_disk(parameter); + file_system_detach_disk(parameter, 0); } } return NULL; @@ -718,10 +718,12 @@ static const ui_menu_entry_t create_disk_image_type_menu[] = { MENU_ENTRY_RESOURCE_RADIO, set_disk_type_callback, (ui_callback_data_t)DISK_IMAGE_TYPE_P64 }, +#ifdef HAVE_X64_IMAGE /* VICE 3.10 deprecated X64; gate behind the (off-by-default) feature macro */ { "X64", MENU_ENTRY_RESOURCE_RADIO, set_disk_type_callback, (ui_callback_data_t)DISK_IMAGE_TYPE_X64 }, +#endif SDL_MENU_LIST_END }; diff --git a/src/Emulators/vice/arch/menu_help.c b/src/Emulators/vice/arch/menu_help.c index f99740ef..c82ad1d9 100644 --- a/src/Emulators/vice/arch/menu_help.c +++ b/src/Emulators/vice/arch/menu_help.c @@ -47,7 +47,7 @@ static char *concat_all(char **text) { int i; char *new_text; - char *old_text = lib_stralloc("\n"); + char *old_text = lib_strdup("\n"); for (i = 0; text[i] != NULL; i++) { new_text = util_concat(old_text, text[i], NULL); diff --git a/src/Emulators/vice/arch/menu_joystick.c b/src/Emulators/vice/arch/menu_joystick.c index 75946d19..8b67abd2 100644 --- a/src/Emulators/vice/arch/menu_joystick.c +++ b/src/Emulators/vice/arch/menu_joystick.c @@ -306,60 +306,9 @@ const ui_menu_entry_t joystick_menu[] = { SDL_MENU_LIST_END }; -UI_MENU_DEFINE_TOGGLE(ExtraJoy) -UI_MENU_DEFINE_RADIO(ExtraJoyType) - -static const ui_menu_entry_t joystick_extra_joy_type_menu[] = { - { "CGA/Protovision userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_CGA }, - { "DXS/HIT userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_HIT }, - { "Kingsoft userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_KINGSOFT }, - { "Starbyte userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_STARBYTE }, - { "PET userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_PET }, - { "Hummer userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_HUMMER }, - { "OEM userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_OEM }, - SDL_MENU_LIST_END -}; - -static const ui_menu_entry_t joystick_extra_joy_type_no_hit_menu[] = { - { "CGA/Protovision userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_CGA }, - { "PET userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_PET }, - { "HUMMER userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_HUMMER }, - { "OEM userport adapter", - MENU_ENTRY_RESOURCE_RADIO, - radio_ExtraJoyType_callback, - (ui_callback_data_t)USERPORT_JOYSTICK_OEM }, - SDL_MENU_LIST_END -}; +/* VICE 3.10 removed the ExtraJoy/ExtraJoyType resources and the + USERPORT_JOYSTICK_* type constants; userport joystick adapters are now + selected as userport devices. The "Extra Joystick Adapter" menus are dropped. */ const ui_menu_entry_t joystick_c64_menu[] = { { "Joystick device in port 1", @@ -396,14 +345,7 @@ const ui_menu_entry_t joystick_c64_menu[] = { submenu_callback, (ui_callback_data_t)define_keyset_menu }, SDL_MENU_ITEM_SEPARATOR, - { "Extra Joystick Adapter", - MENU_ENTRY_RESOURCE_TOGGLE, - toggle_ExtraJoy_callback, - NULL }, - { "Extra Joystick Adapter type", - MENU_ENTRY_SUBMENU, - submenu_radio_callback, - (ui_callback_data_t)joystick_extra_joy_type_menu }, + /* VICE 3.10: "Extra Joystick Adapter" (ExtraJoy/ExtraJoyType) removed. */ #ifdef HAVE_SDL_NUMJOYSTICKS SDL_MENU_ITEM_SEPARATOR, { "Joystick 1 mapping", /* TODO better name */ @@ -465,14 +407,7 @@ const ui_menu_entry_t joystick_c64dtv_menu[] = { submenu_callback, (ui_callback_data_t)define_keyset_menu }, SDL_MENU_ITEM_SEPARATOR, - { "Extra Joystick Adapter", - MENU_ENTRY_RESOURCE_TOGGLE, - toggle_ExtraJoy_callback, - NULL }, - { "Extra Joystick Adapter type", - MENU_ENTRY_SUBMENU, - submenu_radio_callback, - (ui_callback_data_t)joystick_extra_joy_type_no_hit_menu }, + /* VICE 3.10: "Extra Joystick Adapter" (ExtraJoy/ExtraJoyType) removed. */ #ifdef HAVE_SDL_NUMJOYSTICKS SDL_MENU_ITEM_SEPARATOR, { "Joystick 1 mapping", /* TODO better name */ @@ -585,14 +520,7 @@ const ui_menu_entry_t joystick_vic20_menu[] = { submenu_callback, (ui_callback_data_t)define_keyset_menu }, SDL_MENU_ITEM_SEPARATOR, - { "Extra Joystick Adapter", - MENU_ENTRY_RESOURCE_TOGGLE, - toggle_ExtraJoy_callback, - NULL }, - { "Extra Joystick Adapter type", - MENU_ENTRY_SUBMENU, - submenu_radio_callback, - (ui_callback_data_t)joystick_extra_joy_type_no_hit_menu }, + /* VICE 3.10: "Extra Joystick Adapter" (ExtraJoy/ExtraJoyType) removed. */ #ifdef HAVE_SDL_NUMJOYSTICKS SDL_MENU_ITEM_SEPARATOR, { "Joystick 1 mapping", @@ -638,14 +566,7 @@ const ui_menu_entry_t joystick_userport_only_menu[] = { submenu_callback, (ui_callback_data_t)define_keyset_menu }, SDL_MENU_ITEM_SEPARATOR, - { "Extra Joystick Adapter", - MENU_ENTRY_RESOURCE_TOGGLE, - toggle_ExtraJoy_callback, - NULL }, - { "Extra Joystick Adapter type", - MENU_ENTRY_SUBMENU, - submenu_radio_callback, - (ui_callback_data_t)joystick_extra_joy_type_no_hit_menu }, + /* VICE 3.10: "Extra Joystick Adapter" (ExtraJoy/ExtraJoyType) removed. */ #ifdef HAVE_SDL_NUMJOYSTICKS SDL_MENU_ITEM_SEPARATOR, { "Extra joystick 1 mapping", diff --git a/src/Emulators/vice/arch/menu_midi.c b/src/Emulators/vice/arch/menu_midi.c index bdbb065d..9e7860ed 100644 --- a/src/Emulators/vice/arch/menu_midi.c +++ b/src/Emulators/vice/arch/menu_midi.c @@ -163,7 +163,7 @@ UI_MENU_CALLBACK(MIDIInDev_dynmenu_callback) } if (num_in == 0) { - midi_in_dyn_menu[i].string = (char *)lib_stralloc("No Devices Present"); + midi_in_dyn_menu[i].string = (char *)lib_strdup("No Devices Present"); midi_in_dyn_menu[i].type = MENU_ENTRY_TEXT; midi_in_dyn_menu[i].callback = seperator_callback; midi_in_dyn_menu[i].data = NULL; @@ -172,7 +172,7 @@ UI_MENU_CALLBACK(MIDIInDev_dynmenu_callback) for (j = 0; (j < num_in) && (i < 20); j++) { ret = midiInGetDevCaps(j, &mic, sizeof(MIDIINCAPS)); if (ret == MMSYSERR_NOERROR) { - midi_in_dyn_menu[i].string = (char *)lib_stralloc(mic.szPname); + midi_in_dyn_menu[i].string = (char *)lib_strdup(mic.szPname); midi_in_dyn_menu[i].type = MENU_ENTRY_RESOURCE_RADIO; midi_in_dyn_menu[i].callback = radio_MIDIInDev_callback; midi_in_dyn_menu[i].data = (ui_callback_data_t)j; @@ -205,7 +205,7 @@ UI_MENU_CALLBACK(MIDIOutDev_dynmenu_callback) } if (num_out == 0) { - midi_out_dyn_menu[i].string = (char *)lib_stralloc("No Devices Present"); + midi_out_dyn_menu[i].string = (char *)lib_strdup("No Devices Present"); midi_out_dyn_menu[i].type = MENU_ENTRY_TEXT; midi_out_dyn_menu[i].callback = seperator_callback; midi_out_dyn_menu[i].data = NULL; @@ -214,7 +214,7 @@ UI_MENU_CALLBACK(MIDIOutDev_dynmenu_callback) for (j = 0; (j < num_out) && (i < 20); j++) { ret = midiOutGetDevCaps(j, &moc, sizeof(MIDIOUTCAPS)); if (ret == MMSYSERR_NOERROR) { - midi_out_dyn_menu[i].string = (char *)lib_stralloc(moc.szPname); + midi_out_dyn_menu[i].string = (char *)lib_strdup(moc.szPname); midi_out_dyn_menu[i].type = MENU_ENTRY_RESOURCE_RADIO; midi_out_dyn_menu[i].callback = radio_MIDIOutDev_callback; midi_out_dyn_menu[i].data = (ui_callback_data_t)j; diff --git a/src/Emulators/vice/arch/menu_reset.c b/src/Emulators/vice/arch/menu_reset.c index 9eec147c..5e42f6f4 100644 --- a/src/Emulators/vice/arch/menu_reset.c +++ b/src/Emulators/vice/arch/menu_reset.c @@ -38,7 +38,7 @@ static UI_MENU_CALLBACK(maincpu_hard_reset_callback) { if (activated) { vsync_suspend_speed_eval(); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); return sdl_menu_text_exit_ui; } return NULL; @@ -48,7 +48,7 @@ static UI_MENU_CALLBACK(maincpu_soft_reset_callback) { if (activated) { vsync_suspend_speed_eval(); - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); return sdl_menu_text_exit_ui; } return NULL; diff --git a/src/Emulators/vice/arch/menu_sound.c b/src/Emulators/vice/arch/menu_sound.c index 4054b5a8..ab762c58 100644 --- a/src/Emulators/vice/arch/menu_sound.c +++ b/src/Emulators/vice/arch/menu_sound.c @@ -42,7 +42,6 @@ UI_MENU_DEFINE_TOGGLE(Sound) UI_MENU_DEFINE_RADIO(SoundSampleRate) UI_MENU_DEFINE_RADIO(SoundFragmentSize) -UI_MENU_DEFINE_RADIO(SoundSpeedAdjustment) UI_MENU_DEFINE_RADIO(SoundDeviceName) UI_MENU_DEFINE_RADIO(SoundOutput) @@ -380,20 +379,8 @@ const ui_menu_entry_t sound_output_menu[] = { MENU_ENTRY_DIALOG, custom_frequency_callback, NULL }, - SDL_MENU_ITEM_SEPARATOR, - SDL_MENU_ITEM_TITLE("Synchronization method"), - { "Flexible", - MENU_ENTRY_RESOURCE_RADIO, - radio_SoundSpeedAdjustment_callback, - (ui_callback_data_t)SOUND_ADJUST_FLEXIBLE }, - { "Adjusting", - MENU_ENTRY_RESOURCE_RADIO, - radio_SoundSpeedAdjustment_callback, - (ui_callback_data_t)SOUND_ADJUST_ADJUSTING }, - { "Exact", - MENU_ENTRY_RESOURCE_RADIO, - radio_SoundSpeedAdjustment_callback, - (ui_callback_data_t)SOUND_ADJUST_EXACT }, + /* VICE 3.10 removed the SoundSpeedAdjustment resource (sync is now internal, + cycle_based), so the "Synchronization method" radio section is dropped. */ SDL_MENU_ITEM_SEPARATOR, { "Sound recording", MENU_ENTRY_SUBMENU, diff --git a/src/Emulators/vice/arch/menu_tape.c b/src/Emulators/vice/arch/menu_tape.c index 99bd0b2b..18f0955c 100644 --- a/src/Emulators/vice/arch/menu_tape.c +++ b/src/Emulators/vice/arch/menu_tape.c @@ -67,7 +67,7 @@ static UI_MENU_CALLBACK(detach_tape_callback) static UI_MENU_CALLBACK(custom_datasette_control_callback) { if (activated) { - datasette_control(vice_ptr_to_int(param)); + datasette_control(0, vice_ptr_to_int(param)); /* VICE 3.10: + tape port (C64 datasette = port 0) */ } return NULL; } diff --git a/src/Emulators/vice/arch/menu_tfe.c b/src/Emulators/vice/arch/menu_tfe.c index cb21ab39..240d3929 100644 --- a/src/Emulators/vice/arch/menu_tfe.c +++ b/src/Emulators/vice/arch/menu_tfe.c @@ -87,7 +87,7 @@ UI_MENU_CALLBACK(ETHERNET_INTERFACE_dynmenu_callback) } if (!rawnet_enumadapter_open()) { - ethernet_interface_dyn_menu[0].string = (char *)lib_stralloc("No Devices Present"); + ethernet_interface_dyn_menu[0].string = (char *)lib_strdup("No Devices Present"); ethernet_interface_dyn_menu[0].type = MENU_ENTRY_TEXT; ethernet_interface_dyn_menu[0].callback = seperator_callback; ethernet_interface_dyn_menu[0].data = NULL; @@ -97,10 +97,10 @@ UI_MENU_CALLBACK(ETHERNET_INTERFACE_dynmenu_callback) ethernet_interface_dyn_menu[1].data = NULL; } else { for (i = 0; (rawnet_enumadapter(&pname, &pdescription)) && (i < 20); i++) { - ethernet_interface_dyn_menu[i].string = (char *)lib_stralloc(pdescription); + ethernet_interface_dyn_menu[i].string = (char *)lib_strdup(pdescription); ethernet_interface_dyn_menu[i].type = MENU_ENTRY_RESOURCE_RADIO; ethernet_interface_dyn_menu[i].callback = radio_ETHERNET_INTERFACE_callback; - ethernet_interface_dyn_menu[i].data = (ui_callback_data_t)(char *)lib_stralloc(pname); + ethernet_interface_dyn_menu[i].data = (ui_callback_data_t)(char *)lib_strdup(pname); } ethernet_interface_dyn_menu[i].string = NULL; ethernet_interface_dyn_menu[i].type = 0; diff --git a/src/Emulators/vice/arch/menu_video.c b/src/Emulators/vice/arch/menu_video.c index 11f08094..3b9b7123 100644 --- a/src/Emulators/vice/arch/menu_video.c +++ b/src/Emulators/vice/arch/menu_video.c @@ -1055,7 +1055,7 @@ static UI_MENU_CALLBACK(radio_MachineVideoStandard_vic20_callback) if (activated) { int value = vice_ptr_to_int(param); resources_set_int("MachineVideoStandard", value); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); return sdl_menu_text_exit_ui; } return sdl_ui_menu_radio_helper(activated, param, "MachineVideoStandard"); diff --git a/src/Emulators/vice/arch/mousedrv.c b/src/Emulators/vice/arch/mousedrv.c index 070e5d93..522fa894 100644 --- a/src/Emulators/vice/arch/mousedrv.c +++ b/src/Emulators/vice/arch/mousedrv.c @@ -107,12 +107,8 @@ int mousedrv_get_y(void) return mouse_y; } -void mouse_move(int x, int y) -{ - mouse_x += x; - mouse_y -= y; - mouse_timestamp = vsyncarch_gettime(); -} +/* RD: the real mouse_move(float,float) lives in joyport/mouse.c (VICE 3.10); + the arch driver only exposes position via mousedrv_get_x/y + c64d_mouse_set_position. */ void c64d_mouse_set_position(int x, int y) { diff --git a/src/Emulators/vice/arch/mousedrv.h b/src/Emulators/vice/arch/mousedrv.h index 4a3bcf70..dc9656ab 100644 --- a/src/Emulators/vice/arch/mousedrv.h +++ b/src/Emulators/vice/arch/mousedrv.h @@ -41,7 +41,7 @@ extern int mousedrv_get_y(void); extern unsigned long mousedrv_get_timestamp(void); extern void mouse_button(int bnumber, int state); -extern void mouse_move(int x, int y); +/* RD: mouse_move(float,float) is declared in joyport/mouse.h (VICE 3.10), not here. */ extern void mousedrv_button_left(int pressed); extern void mousedrv_button_right(int pressed); diff --git a/src/Emulators/vice/arch/rd_ui_stubs.c b/src/Emulators/vice/arch/rd_ui_stubs.c new file mode 100644 index 00000000..94358af3 --- /dev/null +++ b/src/Emulators/vice/arch/rd_ui_stubs.c @@ -0,0 +1,67 @@ +/* + * rd_ui_stubs.c - Stubs for VICE 3.10 arch UI entry points that RD does not + * implement (RD uses MTEngineSDL for its own UI). Each stub is + * a no-op with the 3.10 signature so the link resolves. + */ + +#include "vice.h" +#include + +/* --- generic UI / arch lifecycle --- */ +void arch_ui_activate(void) {} +int c64scui_init_early(void) { return 0; } +int default_settings_requested(void) { return 0; } +void main_exit(void) {} + +/* --- joystick (SDL arch) --- */ +int joy_sdl_cmdline_options_init(void) { return 0; } +int joy_sdl_resources_init(void) { return 0; } +void joystick_arch_init(void) {} +void joystick_arch_shutdown(void) {} + +/* --- 3.10 UI action system / hotkeys --- */ +void ui_action_trigger(int action) { (void)action; } +void ui_actions_shutdown(void) {} +void ui_hotkeys_shutdown(void) {} + +/* --- video canvas / display settings (RD's canvas is MTEngineSDL-driven) --- */ +void *ui_get_active_canvas(void) { return NULL; } +void ui_display_reset(int device, int mode) { (void)device; (void)mode; } +int ui_set_aspect_mode(int mode, void *canvas) { (void)mode; (void)canvas; return 0; } +int ui_set_aspect_ratio(double aspect, void *canvas) { (void)aspect; (void)canvas; return 0; } +int ui_set_flipx(int val, void *canvas) { (void)val; (void)canvas; return 0; } +int ui_set_flipy(int val, void *canvas) { (void)val; (void)canvas; return 0; } +int ui_set_fullscreen_custom_height(int h, void *canvas) { (void)h; (void)canvas; return 0; } +int ui_set_fullscreen_custom_width(int w, void *canvas) { (void)w; (void)canvas; return 0; } +int ui_set_glfilter(int val, void *canvas) { (void)val; (void)canvas; return 0; } +int ui_set_rotate(int val, void *canvas) { (void)val; (void)canvas; return 0; } +int ui_set_vsync(int val, void *canvas) { (void)val; (void)canvas; return 0; } +/* Stock VICE's set_warp_mode lives in arch//menu_speed.c (returns int, takes + the resource setter's void *param). RD doesn't link those UI files, so we + forward to vsync_set_warp_mode here. Without this, RD's + CDebugInterfaceVice::SetSettingIsWarpSpeed calls a no-op and warp_enabled + never flips -- the C64 thread stays throttled at ~1 MHz even with warp ON + (caught by test_warp_on_increases_cycle_rate). */ +extern void vsync_set_warp_mode(int val); +int set_warp_mode(int value, void *param) { (void)param; vsync_set_warp_mode(value); return 0; } + +/* --- monitor PETSCII/screencode output (echo back, RD shows debugger console) --- */ +int uimon_petscii_out(const char *buffer, int len) { (void)buffer; return len; } +int uimon_petscii_upper_out(const char *buffer, int len) { (void)buffer; return len; } +int uimon_scrcode_out(const char *buffer, int len) { (void)buffer; return len; } +int uimon_scrcode_upper_out(const char *buffer, int len) { (void)buffer; return len; } + +/* --- VSID (SID tune player) UI --- */ +void vsid_ui_display_nr_of_tunes(int count) { (void)count; } +void vsid_ui_set_default_tune(int nr) { (void)nr; } + +/* --- vsync --- */ +void vsync_sync_reset(void) {} + +/* Additional stubs surfaced after dropping arch/joy.c. */ +int archdep_default_logger_is_terminal(void) { return 0; } +void joystick_arch_resources_shutdown(void) {} +void sdljoy_autorepeat(void) {} +void sdljoy_swap_ports(void) {} +int ui_action_get_id(const char *name) { (void)name; return -1; } +const char *ui_action_get_name(int action) { (void)action; return ""; } diff --git a/src/Emulators/vice/arch/sdl/archdep.h b/src/Emulators/vice/arch/sdl/archdep.h new file mode 100644 index 00000000..b1458de0 --- /dev/null +++ b/src/Emulators/vice/arch/sdl/archdep.h @@ -0,0 +1,95 @@ +/* + * archdep.h - Miscellaneous system-specific stuff. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_H +#define VICE_ARCHDEP_H + +#include "vice.h" +#include "vice_sdl.h" + +#include "sound.h" + +#ifndef BEOS_COMPILE +/* Video chip scaling. */ +#define ARCHDEP_VICII_DSIZE 1 +#define ARCHDEP_VICII_DSCAN 1 +#define ARCHDEP_VDC_DSIZE 1 +#define ARCHDEP_VDC_DSCAN 1 +#define ARCHDEP_VIC_DSIZE 1 +#define ARCHDEP_VIC_DSCAN 1 +#define ARCHDEP_CRTC_DSIZE 1 +#define ARCHDEP_CRTC_DSCAN 1 +#define ARCHDEP_TED_DSIZE 1 +#define ARCHDEP_TED_DSCAN 1 +#endif + +/* No key symcode. */ +#define ARCHDEP_KEYBOARD_SYM_NONE SDLK_UNKNOWN + +/* Default sound output mode */ +#define ARCHDEP_SOUND_OUTPUT_MODE SOUND_OUTPUT_SYSTEM + +/* define if the platform supports the monitor in a seperate window */ +/* #define ARCHDEP_SEPERATE_MONITOR_WINDOW */ + +/** \brief Default state of mouse grab + */ +#define ARCHDEP_MOUSE_ENABLE_DEFAULT 0 + +/** \brief Factory value of the CHIPShowStatusbar resource + */ +#define ARCHDEP_SHOW_STATUSBAR_FACTORY 0 + +/* FIXME: Ugly hack for preventing SDL crash using -help */ +extern int sdl_help_shutdown; + +/* VICE 3.10: archdep_access() replaced ioutil_access(). Mode constants match + POSIX R_OK/W_OK/X_OK/F_OK so the values pass straight through to access(). */ +#define ARCHDEP_ACCESS_R_OK 4 +#define ARCHDEP_ACCESS_W_OK 2 +#define ARCHDEP_ACCESS_X_OK 1 +#define ARCHDEP_ACCESS_F_OK 0 +int archdep_access(const char *pathname, int mode); + +/******************************************************************************/ + +#ifdef BEOS_COMPILE +#include "archdep_beos.h" +#endif + +#if defined(UNIX_COMPILE) && !defined(CEGCC_COMPILE) +#include "archdep_unix.h" +/* Allow native monitor code (on host console) */ +#define ALLOW_NATIVE_MONITOR +#endif + +#ifdef WINDOWS_COMPILE +#include "archdep_win32.h" +/* This platform supports choosing drives. */ +#define SDL_CHOOSE_DRIVES +#endif + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_beos.h b/src/Emulators/vice/arch/shared/archdep_beos.h new file mode 100644 index 00000000..9d649261 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_beos.h @@ -0,0 +1,105 @@ +/** \file archdep_beos.h + * \brief Miscellaneous BeOS system-specific stuff + * + * \author Marco van den Heuvel + * \author Marcus Sutton + * + * TODO: Either of these authors should properly document the defines using + * Doxygen. + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_BEOS_H +#define VICE_ARCHDEP_BEOS_H + +#define VICE_ARCHAPI_PRIVATE_API +#include "archapi.h" +#undef VICE_ARCHAPI_PRIVATE_API + +/* Video chip scaling. */ +#define ARCHDEP_VICII_DSIZE 1 +#define ARCHDEP_VICII_DSCAN 1 +#define ARCHDEP_VDC_DSIZE 1 +#define ARCHDEP_VDC_DSCAN 1 +#define ARCHDEP_VIC_DSIZE 1 +#define ARCHDEP_VIC_DSCAN 1 +#define ARCHDEP_CRTC_DSIZE 1 +#define ARCHDEP_CRTC_DSCAN 1 +#define ARCHDEP_TED_DSIZE 1 +#define ARCHDEP_TED_DSCAN 1 + +/* Filesystem-dependent constants */ +#define ARCHDEP_FSDEVICE_DEFAULT_DIR "." +#define ARCHDEP_DIR_SEP_STR "/" +#define ARCHDEP_DIR_SEP_CHR '/' + +/* Path separator. */ +#define ARCHDEP_FINDPATH_SEPARATOR_CHAR ':' +#define ARCHDEP_FINDPATH_SEPARATOR_STRING ":" + +/* Modes for fopen(). */ +#define MODE_READ "r" +#define MODE_READ_TEXT "rt" +#define MODE_READ_WRITE "r+" +#define MODE_WRITE "w" +#define MODE_WRITE_TEXT "wt" +#define MODE_APPEND "a" +#define MODE_APPEND_READ_WRITE "a+" + +/* Printer default devices. */ +#define ARCHDEP_PRINTER_DEFAULT_DEV1 "PrinterFile" +#define ARCHDEP_PRINTER_DEFAULT_DEV2 "/dev/parallel/parallel1" +#define ARCHDEP_PRINTER_DEFAULT_DEV3 "/dev/printer/usb/" + +/* Default RS232 devices. */ +#define ARCHDEP_RS232_DEV1 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV2 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV3 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV4 "127.0.0.1:25232" + +/* Default location of raw disk images. */ +#define ARCHDEP_RAWDRIVE_DEFAULT "/dev/disk/floppy/raw" + +/* Standard line delimiter. */ +#define ARCHDEP_LINE_DELIMITER "\n" + +/* Ethernet default device */ +#define ARCHDEP_ETHERNET_DEFAULT_DEVICE "" + +/* + FIXME: confirm wether SIGPIPE must be handled or not. if the emulator quits + or crashes when the connection is closed, you might have to install + a signal handler which calls monitor_abort(). + + see archdep_unix.c and bug #3201796 +*/ +#if 0 +#define archdep_signals_init(x) +#define archdep_signals_pipe_set() +#define archdep_signals_pipe_unset() +#endif + +/* what to use to return an error when a socket error happens */ +#define ARCHDEP_SOCKET_ERROR errno + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_defs.h b/src/Emulators/vice/arch/shared/archdep_defs.h new file mode 100644 index 00000000..6ae93565 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_defs.h @@ -0,0 +1,198 @@ +/** \file archdep_defs.h + * \brief Defines, enums and types used by the archdep functions + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +#ifndef VICE_ARCHDEP_DEFS_H +#define VICE_ARCHDEP_DEFS_H + +#include "vice.h" +#include + + +/* \brief Various OS-identification macros + * + * The question marks indicate ports I have my doubts about they'll even run + * VICE at all. + * + * XXX: Non of the ARCHDEP_OS_* macros should be left when we've finished + * the archdep cleanup! + * TODO: Move this comment to either src/vice.h or configure.ac. + * + *
+ *  UNIX_COMPILE
+ *    MACOS_COMPILE
+ *    LINUX_COMPILE
+ *    BSD_COMPILE
+ *      FREEBSD_COMPILE
+ *      NETBSD_COMPILE
+ *      OPENBSD_COMPILE
+ *      DRAGONFLYBSD_COMPILE
+ *  WINDOWS_COMPILE
+ *  BEOS_COMPILE
+ *    HAIKU_COMPILE
+ * 
+ */ + + +/** \brief Extension used for autostart disks + */ +#define ARCHDEP_AUTOSTART_DISK_EXTENSION "d64" + + +#if defined(WINDOWS_COMPILE) +/** \brief Separator used for a pathlist + */ +# define ARCHDEP_FINDPATH_SEPARATOR_STRING ";" + +#else + +/** \brief Separator used for a pathlist + */ +# define ARCHDEP_FINDPATH_SEPARATOR_STRING ":" +#endif + + +/** \def ARCHDEP_PATH_MAX + * + * \brief Arch-independent replacement for PATH_MAX/MAX_PATH + * + * The maximum size of a pathname. + * + * Note that there are some serious flaws with PATH_MAX and similar constants, + * so only use this if dynamically allocating memory isn't possible. There also + * doesn't seem to be consencus on whether PATH_MAX is enough to hold the + * longest possible path including the terminating NUL character. + */ + +#ifdef WINDOWS_COMPILE +# include +# define ARCHDEP_PATH_MAX _MAX_PATH +#elif defined(UNIX_COMPILE) || defined(HAIKU_COMPILE) +# include +/* Not sure we need this fallback: on FreeBSD, NetBSD and OpenBSD using + * `#include ` worked even with -pedantic -ansi passed to the compiler. + */ +#if 0 +# ifndef PATH_MAX +# if defined(BSD_COMPILE) || defined(MACOS_COMPILE) +# include +# endif +# endif +#endif +# define ARCHDEP_PATH_MAX PATH_MAX +#else +/* Paniek! */ +# define ARCHDEP_PATH_MAX 4096 +#endif + + +/** \brief XDG Base Directory Specifiction user cache dir + * + * This defines only the final element of the `XDG_CACHE_HOME` variable. + */ +#define ARCHDEP_XDG_CACHE_HOME ".cache" + + +/** \brief XDG Base Directory Specifiction user config dir + * + * This defines only the final element of `the XDG_CONFIG_HOME` variable. + */ +#define ARCHDEP_XDG_CONFIG_HOME ".config" + + +/** \def ARCHDEP_VICERC_NAME + * \brief The name of the default VICE configuraton file + */ + +/** \def ARCHDEP_VICE_RTC_NAME + * \brief The name of the default VICE RTC status file + */ + +/* + * Determine if we compile against SDL + */ +#if defined(USE_SDLUI) || defined(USE_SDL2UI) +# define ARCHDEP_USE_SDL +#endif + +#if defined(WINDOWS_COMPILE) || defined(BEOS_COMPILE) +# ifdef ARCHDEP_USE_SDL +# define ARCHDEP_VICERC_NAME "sdl-vice.ini" +/* Just copying stuff, I'm backwards */ +# define ARCHDEP_VICE_RTC_NAME "sdl-vice.rtc" +# else +# define ARCHDEP_VICERC_NAME "vice.ini" +# define ARCHDEP_VICE_RTC_NAME "vice.rtc" +# endif +#else +# ifdef ARCHDEP_USE_SDL +# define ARCHDEP_VICERC_NAME "sdl-vicerc" +# define ARCHDEP_VICE_RTC_NAME "sdl-vice.rtc" +# else +# define ARCHDEP_VICERC_NAME "vicerc" +# define ARCHDEP_VICE_RTC_NAME "vice.rtc" +# endif +#endif + +/** \brief Autostart diskimage prefix + */ +#define ARCHDEP_AUTOSTART_DISKIMAGE_PREFIX "autostart-" + +/** \brief Autostart diskimage suffix + */ +#define ARCHDEP_AUTOSTART_DISKIMAGE_SUFFIX ".d64" + + +/* Declare extra printf specifiers for Windows since Microsoft's support for + * C99 fucking sucks. + * + * This declares PRI_SIZE_T and PRI_SSIZE_T for use on all platforms, + * aliasing to 'zu'/'z' on anything not Windows, and using PRI[d|u][32|64] on + * Windows. + */ + +/** \def PRI_SIZE_T + * \brief Printf type specifier alias for 'zu' + * + * Required to work around Microsoft's broken C99 support. + */ + +/** \def PRI_SSIZE_T + * \brief Printf type specifier alias for 'zd' + * + * Required to work around Microsoft's broken C99 support. + */ + +#ifdef _WIN32 +# define PRI_SIZE_T "Iu" +# define PRI_SSIZE_T "Id" +#else +# define PRI_SIZE_T "zu" +# define PRI_SSIZE_T "zd" +#endif + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_dir.h b/src/Emulators/vice/arch/shared/archdep_dir.h new file mode 100644 index 00000000..ed784ba9 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_dir.h @@ -0,0 +1,82 @@ +/** \file archdep_dir.h + * \brief Read host directory - header + * \author Marco van den Heuvel + * \author Bas Wassink + * \author Andreas Boose + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_DIR_H +#define VICE_ARCHDEP_DIR_H + +#include +#include "archdep_defs.h" + +/** \brief Do not display hidden files + * + * Do not display "dotfiles" on Unix or files with the hidden attribute on + * Windows. + * Will still display the special files '.' and '..'. + */ +#define ARCHDEP_OPENDIR_NO_HIDDEN_FILES 1 + +/** \brief Show all files + */ +#define ARCHDEP_OPENDIR_ALL_FILES 0 + + +/** \brief Directory object + * + * Contains a list of directories and a list of files for a given host directory. + * + * For the position in the directory the API concatenates the dirs and files + * with the dirs coming first. The directories and files are sorted in ascending + * order in a case-sensitive manner and thus sorted Unix-style and not Windows- + * style (where case folding is normally applied). + */ +typedef struct archdep_dir_s { + char **dirs; /**< list of directories */ + char **files; /**< list of files */ + int dir_amount; /**< number of entries in `dirs` */ + int file_amount; /**< number of entries in `files` */ + int pos; /**< position in directory, adding together dirs and + files, with dirs coming first */ + int dirs_size; /**< size of the `dirs` array, in number of elements */ + int files_size; /**< size of the `files` array, in number of elements */ +} archdep_dir_t; + + +archdep_dir_t * archdep_opendir(const char *path, int mode); +const char * archdep_readdir(archdep_dir_t *dir); +void archdep_closedir(archdep_dir_t *dir); +void archdep_rewinddir(archdep_dir_t *dir); +void archdep_seekdir(archdep_dir_t *dir, int pos); +int archdep_telldir(const archdep_dir_t *dir); +const char * archdep_readdir_get_entry(const archdep_dir_t *dir, int pos); +const char * archdep_readdir_get_dir(const archdep_dir_t *dir, int pos); +const char * archdep_readdir_get_file(const archdep_dir_t *dir, int pos); +int archdep_readdir_num_entries(const archdep_dir_t *dir); +int archdep_readdir_num_dirs(const archdep_dir_t *dir); +int archdep_readdir_num_files(const archdep_dir_t *dir); + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_exit.h b/src/Emulators/vice/arch/shared/archdep_exit.h new file mode 100644 index 00000000..ae14d5d5 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_exit.h @@ -0,0 +1,44 @@ +/** \file archdep_exit.h + * \brief atexit(3) work arounds - header + * \author Bas Wassink + * \author Blacky Stardust + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef ARCHDEP_EXIT_H +#define ARCHDEP_EXIT_H + +#include + +bool archdep_is_exiting(void); +void archdep_vice_exit(int excode); + +/* TODO - something about these being in here */ +#ifdef USE_GTK3UI +void archdep_thread_init(void); +void archdep_set_main_thread(void); +void archdep_set_vice_thread(void); +void archdep_thread_shutdown(void); +#endif + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_tick.h b/src/Emulators/vice/arch/shared/archdep_tick.h new file mode 100644 index 00000000..473eee38 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_tick.h @@ -0,0 +1,68 @@ +/** \file archdep_tick.h + * \brief Relating to the management of time. + * + * \author David Hogan + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_TICK_H +#define VICE_TICK_H + +#include + +#define MILLI_PER_SECOND (1000) +#define MICRO_PER_SECOND (1000 * 1000) +#define NANO_PER_SECOND (1000 * 1000 * 1000) + +/* + * The internal VICE timing resolution. + * BTW, Windows can't be more accurate than (NANO_PER_SECOND / 100). + */ +#define TICK_PER_SECOND (MICRO_PER_SECOND) + +/* Using a 32-bit type for tick_t prevents wraparound bugs on platforms with 32-bit timers */ +typedef uint32_t tick_t; + +#define TICK_TO_MILLI(tick) ((uint32_t) (uint64_t)((double)(tick) * ((double)MILLI_PER_SECOND / TICK_PER_SECOND))) +#define TICK_TO_MICRO(tick) ((uint32_t) (uint64_t)((double)(tick) * ((double)MICRO_PER_SECOND / TICK_PER_SECOND))) +#define TICK_TO_NANO(tick) ((uint64_t) (uint64_t)((double)(tick) * ((double)NANO_PER_SECOND / TICK_PER_SECOND))) +#define NANO_TO_TICK(nano) ((tick_t) (uint64_t)((double)(nano) / ((double)NANO_PER_SECOND / TICK_PER_SECOND))) + +void tick_init(void); + +/* number of ticks per second */ +tick_t tick_per_second(void); + +/* Get time in ticks. */ +tick_t tick_now(void); + +/* Get time in ticks, compensating for the +/- 1 tick that is possible on Windows. */ +tick_t tick_now_after(tick_t previous_tick); + +/* Get number of ticks since a previous tick, compensating for the +/- 1 tick that is possible on Windows. */ +tick_t tick_now_delta(tick_t previous_tick); + +/* Sleep a number of ticks. */ +void tick_sleep(tick_t delay); + +#endif diff --git a/src/Emulators/vice/arch/shared/archdep_win32.h b/src/Emulators/vice/arch/shared/archdep_win32.h new file mode 100644 index 00000000..6ec65223 --- /dev/null +++ b/src/Emulators/vice/arch/shared/archdep_win32.h @@ -0,0 +1,131 @@ +/** \file archdep_win32.h + * \brief Windows-specific stuff - header + * + * \author Marco van den Heuvel + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ARCHDEP_WIN32_H +#define VICE_ARCHDEP_WIN32_H + +#define VICE_ARCHAPI_PRIVATE_API +#include "archapi.h" +#undef VICE_ARCHAPI_PRIVATE_API + +/* Default MIDI devices. */ +#define ARCHDEP_MIDI_IN_DEV "0" /**< MIDI input dev */ +#define ARCHDEP_MIDI_OUT_DEV "0" /**< MIDI output dev */ + +/* Filesystem-dependent constants */ +#define ARCHDEP_FSDEVICE_DEFAULT_DIR "." +#define ARCHDEP_DIR_SEP_STR "\\" +#define ARCHDEP_DIR_SEP_CHR '\\' + +/* Path separator. */ +#define ARCHDEP_FINDPATH_SEPARATOR_CHAR ';' +#define ARCHDEP_FINDPATH_SEPARATOR_STRING ";" + +/* Modes for fopen(). */ +#define MODE_READ "rb" +#define MODE_READ_TEXT "rt" +#define MODE_READ_WRITE "rb+" +#define MODE_WRITE "wb" +#define MODE_WRITE_TEXT "wt" +#define MODE_APPEND "ab" +#define MODE_APPEND_READ_WRITE "ab+" + +/* Printer default devices. */ +#define ARCHDEP_PRINTER_DEFAULT_DEV1 "viceprnt.out" +#define ARCHDEP_PRINTER_DEFAULT_DEV2 "LPT1:" +#define ARCHDEP_PRINTER_DEFAULT_DEV3 "LPT2:" + +/* Default RS232 devices. */ +#define ARCHDEP_RS232_DEV1 "com1" +#define ARCHDEP_RS232_DEV2 "com2" +#define ARCHDEP_RS232_DEV3 "127.0.0.1:25232" +#define ARCHDEP_RS232_DEV4 "127.0.0.1:25232" + +/* Default location of raw disk images. */ +#define ARCHDEP_RAWDRIVE_DEFAULT "A:" + +/* Standard line delimiter. */ +#define ARCHDEP_LINE_DELIMITER "\r\n" + +/* Ethernet default device */ +#define ARCHDEP_ETHERNET_DEFAULT_DEVICE "" + +/* + FIXME: confirm wether SIGPIPE must be handled or not. if the emulator quits + or crashes when the connection is closed, you might have to install + a signal handler which calls monitor_abort(). + + see archdep_unix.c and bug #3201796 +*/ +void archdep_signals_init(int do_coredumps); + +#define MAKE_SO_NAME_VERSION_PROTO(name, version) #name "-" #version ".dll" + +/* add second level macro to allow expansion and stringification */ +#define ARCHDEP_MAKE_SO_NAME_VERSION(n, v) MAKE_SO_NAME_VERSION_PROTO(n, v) + +#define ARCHDEP_OPENCBM_SO_NAME "opencbm.dll" +#define ARCHDEP_LAME_SO_NAME "lame.dll" + +/* ffmpeg headers for windows don't seem to have some of the av_ prefixes */ +#define ARCHDEP_AV_PREFIX_NEEDED + +/* Needs extra call to log_archdep() even when logfile is already opened */ +#define ARCHDEP_EXTRA_LOG_CALL + +/* When using the ascii printer driver we need a return before the newline */ +#define ARCHDEP_PRINTER_RETURN_BEFORE_NEWLINE + +/* what to use to return an error when a socket error happens */ +#define ARCHDEP_SOCKET_ERROR WSAGetLastError() + +int archdep_is_windows_nt(void); + +#endif + +/* FIXME: was dangling around in old archdep. remove once everything is working */ +#if 0 +static char *system_mbstowcs_alloc(const char *mbs) +{ + char *wcs; + size_t len; + + if (mbs == NULL) { + return NULL; + } + + len = strlen(mbs); + + wcs = lib_malloc(len + 1); + return memcpy(wcs, mbs, len + 1); +} + +static void system_mbstowcs_free(char *wcs) +{ + lib_free(wcs); +} +#endif diff --git a/src/Emulators/vice/arch/shared/hotkeys/hotkeystypes.h b/src/Emulators/vice/arch/shared/hotkeys/hotkeystypes.h new file mode 100644 index 00000000..3a23f95d --- /dev/null +++ b/src/Emulators/vice/arch/shared/hotkeys/hotkeystypes.h @@ -0,0 +1,140 @@ +/** \file hotkeystypes.h + * \brief Types used by the hotkeys system + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + */ + +#ifndef VICE_HOTKEYS_HOTKEYSTYPES_H +#define VICE_HOTKEYS_HOTKEYSTYPES_H + +#include +#include +#include +#include +#include "log.h" + + +/** \brief Comment token */ +#define VHK_COMMENT '#' + +/** \brief Alternative comment token */ +#define VHK_COMMENT_ALT ';' + +/** \brief Keyword token */ +#define VHK_KEYWORD '!' + +/** \brief Modifier opening token */ +#define VHK_MODIFIER_OPEN '<' + +/** \brief Modifier closing token */ +#define VHK_MODIFIER_CLOSE '>' + +/** \brief Quote token */ +#define VHK_QUOTE '"' + +/** \brief Token for 'escaping' the following token */ +#define VHK_ESCAPE '\\' + + +/** \brief Hotkey file keyword IDs + */ +typedef enum vhk_keyword_id_e { + VHK_KW_ID_ILLEGAL = -1, /**< illegal directive */ + VHK_KW_ID_CLEAR, /**< clear all hotkeys */ + VHK_KW_ID_DEBUG, /**< enable/disable debuging messages */ + VHK_KW_ID_INCLUDE, /**< include "file" */ + VHK_KW_ID_IF, /**< check condition (TODO) */ + VHK_KW_ID_ELSE, /**< inverse branch of conditional block (TODO) */ + VHK_KW_ID_ENDIF, /**< end of conditional block (TODO) */ + VHK_KW_ID_UNDEF, /**< clear hotkey */ + VHK_KW_ID_WARNING /**< show warning in hotkeys log */ +} vhk_keyword_id_t; + +/** \brief Parser keyword data object + */ +typedef struct vhk_keyword_s { + const char * name; /**< name */ + vhk_keyword_id_t id; /**< ID */ + int args_min; /**< minimum number of arguments */ + int args_max; /**< maximum number of arguments */ + const char * syntax; /**< syntax */ + const char * desc; /**< description */ +} vhk_keyword_t; + +/** \brief Modifier mask data */ +typedef struct vhk_modifier_s { + uint32_t mask; /**< modifier mask */ + const char *name; /**< name in .vhk files */ + const char *desc; /**< description */ +} vhk_modifier_t; + +/** \brief Mapping of a hotkey to menu items + * + */ +typedef struct vhk_map_s { + int action; /**< action ID */ + uint32_t vice_keysym; /**< VICE keysym */ + uint32_t vice_modmask; /**< VICE modifiers */ + uint32_t arch_keysym; /**< arch keysym */ + uint32_t arch_modmask; /**< arch modmask */ + void *menu_item[2]; /**< menu items: primary and secondary display */ + void *user_data; /**< additional arch-specific data */ +} vhk_map_t; + +/** \brief File entry object for the textfile reader + * + * Singly linked list to implement a stack. + */ +typedef struct textfile_entry_s { + char * path; /**< full path of file */ + long pos; /**< position in file */ + long linenum; /**< current line number in file */ + struct textfile_entry_s * next; /**< next entry in stack */ +} textfile_entry_t; + +/** \brief Object to read text files that can 'include' others + */ +typedef struct textfile_reader_s { + char * buffer; /**< buffer holding a single line of text */ + size_t bufsize; /**< size of buffer */ + size_t buflen; /**< length of text in buffer */ + FILE * fp; /**< file pointer for the current file */ + textfile_entry_t * entries; /**< stack of files */ +} textfile_reader_t; + +/** \brief Source of vhk file + * + * Source of the vhk file parsed, used in the UI to display proper path and + * enable/disable widgets. + */ +typedef enum vhk_source_e { + VHK_SOURCE_NONE, /**< no source (no vhk file loaded) */ + VHK_SOURCE_VICE, /**< default location in VICE data dir */ + VHK_SOURCE_USER, /**< UI and emu-specific file in user config dir */ + VHK_SOURCE_RESOURCE /**< path in resource "HotkeyFile */ +} vhk_source_t; + +/* The hotkeys log, perhaps turn this into an accessor instead of this ugly + * extern declaration? */ +extern log_t vhk_log; + +#endif diff --git a/src/Emulators/vice/arch/shared/hotkeys/uihotkeys.h b/src/Emulators/vice/arch/shared/hotkeys/uihotkeys.h new file mode 100644 index 00000000..7b881e3b --- /dev/null +++ b/src/Emulators/vice/arch/shared/hotkeys/uihotkeys.h @@ -0,0 +1,73 @@ +/** \file uihotkeys.h + * \brief UI-agnostic hotkeys - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + */ + +#ifndef VICE_HOTKEYS_UIHOTKEYS_H +#define VICE_HOTKEYS_UIHOTKEYS_H + +#ifndef USE_HEADLESSUI + +#include +#include + +#include "hotkeystypes.h" +#include "vhkkeysyms.h" +#include "uiactions.h" + + +void ui_hotkeys_init (const char *prefix); +void ui_hotkeys_shutdown(void); +void ui_hotkeys_remove_all(void); + +void ui_hotkeys_install_by_map (ui_action_map_t *map); +void ui_hotkeys_update_by_map (ui_action_map_t *map, + uint32_t vice_keysym, + uint32_t vice_modmask); +void ui_hotkeys_update_by_action(int action, + uint32_t vice_keysym, + uint32_t vice_modmask); +void ui_hotkeys_remove_by_map (ui_action_map_t *map); +void ui_hotkeys_remove_by_action(int action); + +int ui_hotkeys_resources_init(void); +int ui_hotkeys_cmdline_options_init(void); +void ui_hotkeys_set_default_requested(bool requested); + +bool ui_hotkeys_load(const char *path); +void ui_hotkeys_load_vice_default(void); +bool ui_hotkeys_load_user_default(void); +void ui_hotkeys_reload(void); +bool ui_hotkeys_save(void); +bool ui_hotkeys_save_as(const char *path); + +const char *ui_hotkeys_vhk_filename_vice(void); +char *ui_hotkeys_vhk_filename_user(void); +char *ui_hotkeys_vhk_full_path_user(void); +char *ui_hotkeys_vhk_full_path_vice(void); +vhk_source_t ui_hotkeys_vhk_source_type(void); +char *ui_hotkeys_vhk_source_path(void); + +#endif /* ifndef USE_HEADLESS_UI */ +#endif diff --git a/src/Emulators/vice/arch/shared/hotkeys/vhkkeysyms.h b/src/Emulators/vice/arch/shared/hotkeys/vhkkeysyms.h new file mode 100644 index 00000000..29afc25d --- /dev/null +++ b/src/Emulators/vice/arch/shared/hotkeys/vhkkeysyms.h @@ -0,0 +1,543 @@ +/** \file vhkkeysyms.h + * \brief UI-agnostic key symbols and names - header + * + * List of keysym identifiers used by the hotkeys in VICE. + * Each UI toolkit has its own key symbols and names, so we need a way to refer + * to keys that isn't toolkit-specific. + * + * The keysyms provided here are taken from `/usr/include/X11/keysymdef.h`. + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + */ + +#ifndef VICE_HOTKEYS_VHKKEYSYMS_H +#define VICE_HOTKEYS_VHKKEYSYMS_H + +#include +#include "hotkeystypes.h" + +#define VHK_KEY_BackSpace 0xff08 /* Back space, back char */ +#define VHK_KEY_Tab 0xff09 +#define VHK_KEY_Linefeed 0xff0a /* Linefeed, LF */ +#define VHK_KEY_Clear 0xff0b +#define VHK_KEY_Return 0xff0d /* Return, enter */ +#define VHK_KEY_Pause 0xff13 /* Pause, hold */ +#define VHK_KEY_Scroll_Lock 0xff14 +#define VHK_KEY_Sys_Req 0xff15 +#define VHK_KEY_Escape 0xff1b +#define VHK_KEY_Delete 0xffff /* Delete, rubout */ + +#define VHK_KEY_Home 0xff50 +#define VHK_KEY_Left 0xff51 /* Move left, left arrow */ +#define VHK_KEY_Up 0xff52 /* Move up, up arrow */ +#define VHK_KEY_Right 0xff53 /* Move right, right arrow */ +#define VHK_KEY_Down 0xff54 /* Move down, down arrow */ +#define VHK_KEY_Prior 0xff55 /* Prior, previous */ +#define VHK_KEY_Page_Up 0xff55 +#define VHK_KEY_Next 0xff56 /* Next */ +#define VHK_KEY_Page_Down 0xff56 +#define VHK_KEY_End 0xff57 /* EOL */ +#define VHK_KEY_Begin 0xff58 /* BOL */ + +/* Misc functions */ + +#define VHK_KEY_Select 0xff60 /* Select, mark */ +#define VHK_KEY_Print 0xff61 +#define VHK_KEY_Execute 0xff62 /* Execute, run, do */ +#define VHK_KEY_Insert 0xff63 /* Insert, insert here */ +#define VHK_KEY_Undo 0xff65 +#define VHK_KEY_Redo 0xff66 /* Redo, again */ +#define VHK_KEY_Menu 0xff67 +#define VHK_KEY_Find 0xff68 /* Find, search */ +#define VHK_KEY_Cancel 0xff69 /* Cancel, stop, abort, exit */ +#define VHK_KEY_Help 0xff6a /* Help */ +#define VHK_KEY_Break 0xff6b +#define VHK_KEY_Mode_switch 0xff7e /* Character set switch */ +#define VHK_KEY_script_switch 0xff7e /* Alias for mode_switch */ + +/* Keypad functions, keypad numbers cleverly chosen to map to ASCII */ + +#define VHK_KEY_KP_Space 0xff80 /* Space */ +#define VHK_KEY_KP_Tab 0xff89 +#define VHK_KEY_KP_Enter 0xff8d /* Enter */ +#define VHK_KEY_KP_F1 0xff91 /* PF1, KP_A, ... */ +#define VHK_KEY_KP_F2 0xff92 +#define VHK_KEY_KP_F3 0xff93 +#define VHK_KEY_KP_F4 0xff94 +#define VHK_KEY_KP_Home 0xff95 +#define VHK_KEY_KP_Left 0xff96 +#define VHK_KEY_KP_Up 0xff97 +#define VHK_KEY_KP_Right 0xff98 +#define VHK_KEY_KP_Down 0xff99 +#define VHK_KEY_KP_Prior 0xff9a +#define VHK_KEY_KP_Page_Up 0xff9a +#define VHK_KEY_KP_Next 0xff9b +#define VHK_KEY_KP_Page_Down 0xff9b +#define VHK_KEY_KP_End 0xff9c +#define VHK_KEY_KP_Begin 0xff9d +#define VHK_KEY_KP_Insert 0xff9e +#define VHK_KEY_KP_Delete 0xff9f +#define VHK_KEY_KP_Equal 0xffbd /* Equals */ +#define VHK_KEY_KP_Multiply 0xffaa +#define VHK_KEY_KP_Add 0xffab +#define VHK_KEY_KP_Separator 0xffac /* Separator, often comma */ +#define VHK_KEY_KP_Subtract 0xffad +#define VHK_KEY_KP_Decimal 0xffae +#define VHK_KEY_KP_Divide 0xffaf + +#define VHK_KEY_KP_0 0xffb0 +#define VHK_KEY_KP_1 0xffb1 +#define VHK_KEY_KP_2 0xffb2 +#define VHK_KEY_KP_3 0xffb3 +#define VHK_KEY_KP_4 0xffb4 +#define VHK_KEY_KP_5 0xffb5 +#define VHK_KEY_KP_6 0xffb6 +#define VHK_KEY_KP_7 0xffb7 +#define VHK_KEY_KP_8 0xffb8 +#define VHK_KEY_KP_9 0xffb9 + +/* Function keys */ + +#define VHK_KEY_F1 0xffbe +#define VHK_KEY_F2 0xffbf +#define VHK_KEY_F3 0xffc0 +#define VHK_KEY_F4 0xffc1 +#define VHK_KEY_F5 0xffc2 +#define VHK_KEY_F6 0xffc3 +#define VHK_KEY_F7 0xffc4 +#define VHK_KEY_F8 0xffc5 +#define VHK_KEY_F9 0xffc6 +#define VHK_KEY_F10 0xffc7 +#define VHK_KEY_F11 0xffc8 +#define VHK_KEY_F12 0xffc9 +#define VHK_KEY_F13 0xffca +#define VHK_KEY_F14 0xffcb +#define VHK_KEY_F15 0xffcc +#define VHK_KEY_F16 0xffcd +#define VHK_KEY_F17 0xffce +#define VHK_KEY_F18 0xffcf +#define VHK_KEY_F19 0xffd0 +#define VHK_KEY_F20 0xffd1 +#define VHK_KEY_F21 0xffd2 +#define VHK_KEY_F22 0xffd3 +#define VHK_KEY_F23 0xffd4 +#define VHK_KEY_F24 0xffd5 +#define VHK_KEY_F25 0xffd6 +#define VHK_KEY_F26 0xffd7 +#define VHK_KEY_F27 0xffd8 +#define VHK_KEY_F28 0xffd9 +#define VHK_KEY_F29 0xffda +#define VHK_KEY_F30 0xffdb +#define VHK_KEY_F31 0xffdc +#define VHK_KEY_F32 0xffdd +#define VHK_KEY_F33 0xffde +#define VHK_KEY_F34 0xffdf +#define VHK_KEY_F35 0xffe0 + +#define VHK_KEY_space 0x0020 /* U+0020 SPACE */ +#define VHK_KEY_exclam 0x0021 /* U+0021 EXCLAMATION MARK */ +#define VHK_KEY_quotedbl 0x0022 /* U+0022 QUOTATION MARK */ +#define VHK_KEY_numbersign 0x0023 /* U+0023 NUMBER SIGN */ +#define VHK_KEY_dollar 0x0024 /* U+0024 DOLLAR SIGN */ +#define VHK_KEY_percent 0x0025 /* U+0025 PERCENT SIGN */ +#define VHK_KEY_ampersand 0x0026 /* U+0026 AMPERSAND */ +#define VHK_KEY_apostrophe 0x0027 /* U+0027 APOSTROPHE */ +#define VHK_KEY_quoteright 0x0027 /* deprecated */ +#define VHK_KEY_parenleft 0x0028 /* U+0028 LEFT PARENTHESIS */ +#define VHK_KEY_parenright 0x0029 /* U+0029 RIGHT PARENTHESIS */ +#define VHK_KEY_asterisk 0x002a /* U+002A ASTERISK */ +#define VHK_KEY_plus 0x002b /* U+002B PLUS SIGN */ +#define VHK_KEY_comma 0x002c /* U+002C COMMA */ +#define VHK_KEY_minus 0x002d /* U+002D HYPHEN-MINUS */ +#define VHK_KEY_period 0x002e /* U+002E FULL STOP */ +#define VHK_KEY_slash 0x002f /* U+002F SOLIDUS */ +#define VHK_KEY_0 0x0030 /* U+0030 DIGIT ZERO */ +#define VHK_KEY_1 0x0031 /* U+0031 DIGIT ONE */ +#define VHK_KEY_2 0x0032 /* U+0032 DIGIT TWO */ +#define VHK_KEY_3 0x0033 /* U+0033 DIGIT THREE */ +#define VHK_KEY_4 0x0034 /* U+0034 DIGIT FOUR */ +#define VHK_KEY_5 0x0035 /* U+0035 DIGIT FIVE */ +#define VHK_KEY_6 0x0036 /* U+0036 DIGIT SIX */ +#define VHK_KEY_7 0x0037 /* U+0037 DIGIT SEVEN */ +#define VHK_KEY_8 0x0038 /* U+0038 DIGIT EIGHT */ +#define VHK_KEY_9 0x0039 /* U+0039 DIGIT NINE */ +#define VHK_KEY_colon 0x003a /* U+003A COLON */ +#define VHK_KEY_semicolon 0x003b /* U+003B SEMICOLON */ +#define VHK_KEY_less 0x003c /* U+003C LESS-THAN SIGN */ +#define VHK_KEY_equal 0x003d /* U+003D EQUALS SIGN */ +#define VHK_KEY_greater 0x003e /* U+003E GREATER-THAN SIGN */ +#define VHK_KEY_question 0x003f /* U+003F QUESTION MARK */ +#define VHK_KEY_at 0x0040 /* U+0040 COMMERCIAL AT */ +/* Upper case letters, conveniently mapping to ASCII */ +#define VHK_KEY_A 0x0041 +#define VHK_KEY_B 0x0042 +#define VHK_KEY_C 0x0043 +#define VHK_KEY_D 0x0044 +#define VHK_KEY_E 0x0045 +#define VHK_KEY_F 0x0046 +#define VHK_KEY_G 0x0047 +#define VHK_KEY_H 0x0048 +#define VHK_KEY_I 0x0049 +#define VHK_KEY_J 0x004a +#define VHK_KEY_K 0x004b +#define VHK_KEY_L 0x004c +#define VHK_KEY_M 0x004d +#define VHK_KEY_N 0x004e +#define VHK_KEY_O 0x004f +#define VHK_KEY_P 0x0050 +#define VHK_KEY_Q 0x0051 +#define VHK_KEY_R 0x0052 +#define VHK_KEY_S 0x0053 +#define VHK_KEY_T 0x0054 +#define VHK_KEY_U 0x0055 +#define VHK_KEY_V 0x0056 +#define VHK_KEY_W 0x0057 +#define VHK_KEY_X 0x0058 +#define VHK_KEY_Y 0x0059 +#define VHK_KEY_Z 0x005a + +#define VHK_KEY_bracketleft 0x005b /* U+005B LEFT SQUARE BRACKET */ +#define VHK_KEY_backslash 0x005c /* U+005C REVERSE SOLIDUS */ +#define VHK_KEY_bracketright 0x005d /* U+005D RIGHT SQUARE BRACKET */ +#define VHK_KEY_asciicircum 0x005e /* U+005E CIRCUMFLEX ACCENT */ +#define VHK_KEY_underscore 0x005f /* U+005F LOW LINE */ +#define VHK_KEY_grave 0x0060 /* U+0060 GRAVE ACCENT */ +#define VHK_KEY_quoteleft 0x0060 /* deprecated */ +/* Lower case letters, conveniently mapping to ASCII */ +#define VHK_KEY_a 0x0061 +#define VHK_KEY_b 0x0062 +#define VHK_KEY_c 0x0063 +#define VHK_KEY_d 0x0064 +#define VHK_KEY_e 0x0065 +#define VHK_KEY_f 0x0066 +#define VHK_KEY_g 0x0067 +#define VHK_KEY_h 0x0068 +#define VHK_KEY_i 0x0069 +#define VHK_KEY_j 0x006a +#define VHK_KEY_k 0x006b +#define VHK_KEY_l 0x006c +#define VHK_KEY_m 0x006d +#define VHK_KEY_n 0x006e +#define VHK_KEY_o 0x006f +#define VHK_KEY_p 0x0070 +#define VHK_KEY_q 0x0071 +#define VHK_KEY_r 0x0072 +#define VHK_KEY_s 0x0073 +#define VHK_KEY_t 0x0074 +#define VHK_KEY_u 0x0075 +#define VHK_KEY_v 0x0076 +#define VHK_KEY_w 0x0077 +#define VHK_KEY_x 0x0078 +#define VHK_KEY_y 0x0079 +#define VHK_KEY_z 0x007a + +#define VHK_KEY_braceleft 0x007b /* U+007B LEFT CURLY BRACKET */ +#define VHK_KEY_bar 0x007c /* U+007C VERTICAL LINE */ +#define VHK_KEY_braceright 0x007d /* U+007D RIGHT CURLY BRACKET */ +#define VHK_KEY_asciitilde 0x007e /* U+007E TILDE */ + +/* Special, "international", keys */ +#define VHK_KEY_nobreakspace 0x00a0 /* U+00A0 NO-BREAK SPACE */ +#define VHK_KEY_exclamdown 0x00a1 /* U+00A1 INVERTED EXCLAMATION MARK */ +#define VHK_KEY_cent 0x00a2 /* U+00A2 CENT SIGN */ +#define VHK_KEY_sterling 0x00a3 /* U+00A3 POUND SIGN */ +#define VHK_KEY_currency 0x00a4 /* U+00A4 CURRENCY SIGN */ +#define VHK_KEY_yen 0x00a5 /* U+00A5 YEN SIGN */ +#define VHK_KEY_brokenbar 0x00a6 /* U+00A6 BROKEN BAR */ +#define VHK_KEY_section 0x00a7 /* U+00A7 SECTION SIGN */ +#define VHK_KEY_diaeresis 0x00a8 /* U+00A8 DIAERESIS */ +#define VHK_KEY_copyright 0x00a9 /* U+00A9 COPYRIGHT SIGN */ +#define VHK_KEY_ordfeminine 0x00aa /* U+00AA FEMININE ORDINAL INDICATOR */ +#define VHK_KEY_guillemotleft 0x00ab /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ +#define VHK_KEY_notsign 0x00ac /* U+00AC NOT SIGN */ +#define VHK_KEY_hyphen 0x00ad /* U+00AD SOFT HYPHEN */ +#define VHK_KEY_registered 0x00ae /* U+00AE REGISTERED SIGN */ +#define VHK_KEY_macron 0x00af /* U+00AF MACRON */ +#define VHK_KEY_degree 0x00b0 /* U+00B0 DEGREE SIGN */ +#define VHK_KEY_plusminus 0x00b1 /* U+00B1 PLUS-MINUS SIGN */ +#define VHK_KEY_twosuperior 0x00b2 /* U+00B2 SUPERSCRIPT TWO */ +#define VHK_KEY_threesuperior 0x00b3 /* U+00B3 SUPERSCRIPT THREE */ +#define VHK_KEY_acute 0x00b4 /* U+00B4 ACUTE ACCENT */ +#define VHK_KEY_mu 0x00b5 /* U+00B5 MICRO SIGN */ +#define VHK_KEY_paragraph 0x00b6 /* U+00B6 PILCROW SIGN */ +#define VHK_KEY_periodcentered 0x00b7 /* U+00B7 MIDDLE DOT */ +#define VHK_KEY_cedilla 0x00b8 /* U+00B8 CEDILLA */ +#define VHK_KEY_onesuperior 0x00b9 /* U+00B9 SUPERSCRIPT ONE */ +#define VHK_KEY_masculine 0x00ba /* U+00BA MASCULINE ORDINAL INDICATOR */ +#define VHK_KEY_guillemotright 0x00bb /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ +#define VHK_KEY_onequarter 0x00bc /* U+00BC VULGAR FRACTION ONE QUARTER */ +#define VHK_KEY_onehalf 0x00bd /* U+00BD VULGAR FRACTION ONE HALF */ +#define VHK_KEY_threequarters 0x00be /* U+00BE VULGAR FRACTION THREE QUARTERS */ +#define VHK_KEY_questiondown 0x00bf /* U+00BF INVERTED QUESTION MARK */ +#define VHK_KEY_Agrave 0x00c0 /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */ +#define VHK_KEY_Aacute 0x00c1 /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */ +#define VHK_KEY_Acircumflex 0x00c2 /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ +#define VHK_KEY_Atilde 0x00c3 /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */ +#define VHK_KEY_Adiaeresis 0x00c4 /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */ +#define VHK_KEY_Aring 0x00c5 /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */ +#define VHK_KEY_AE 0x00c6 /* U+00C6 LATIN CAPITAL LETTER AE */ +#define VHK_KEY_Ccedilla 0x00c7 /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */ +#define VHK_KEY_Egrave 0x00c8 /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */ +#define VHK_KEY_Eacute 0x00c9 /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ +#define VHK_KEY_Ecircumflex 0x00ca /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ +#define VHK_KEY_Ediaeresis 0x00cb /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */ +#define VHK_KEY_Igrave 0x00cc /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */ +#define VHK_KEY_Iacute 0x00cd /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */ +#define VHK_KEY_Icircumflex 0x00ce /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ +#define VHK_KEY_Idiaeresis 0x00cf /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */ +#define VHK_KEY_ETH 0x00d0 /* U+00D0 LATIN CAPITAL LETTER ETH */ +#define VHK_KEY_Eth 0x00d0 /* deprecated */ +#define VHK_KEY_Ntilde 0x00d1 /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */ +#define VHK_KEY_Ograve 0x00d2 /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */ +#define VHK_KEY_Oacute 0x00d3 /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */ +#define VHK_KEY_Ocircumflex 0x00d4 /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ +#define VHK_KEY_Otilde 0x00d5 /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */ +#define VHK_KEY_Odiaeresis 0x00d6 /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */ +#define VHK_KEY_multiply 0x00d7 /* U+00D7 MULTIPLICATION SIGN */ +#define VHK_KEY_Oslash 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ +#define VHK_KEY_Ooblique 0x00d8 /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ +#define VHK_KEY_Ugrave 0x00d9 /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */ +#define VHK_KEY_Uacute 0x00da /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */ +#define VHK_KEY_Ucircumflex 0x00db /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ +#define VHK_KEY_Udiaeresis 0x00dc /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */ +#define VHK_KEY_Yacute 0x00dd /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */ +#define VHK_KEY_THORN 0x00de /* U+00DE LATIN CAPITAL LETTER THORN */ +#define VHK_KEY_Thorn 0x00de /* deprecated */ +#define VHK_KEY_ssharp 0x00df /* U+00DF LATIN SMALL LETTER SHARP S */ +#define VHK_KEY_agrave 0x00e0 /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */ +#define VHK_KEY_aacute 0x00e1 /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */ +#define VHK_KEY_acircumflex 0x00e2 /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */ +#define VHK_KEY_atilde 0x00e3 /* U+00E3 LATIN SMALL LETTER A WITH TILDE */ +#define VHK_KEY_adiaeresis 0x00e4 /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */ +#define VHK_KEY_aring 0x00e5 /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */ +#define VHK_KEY_ae 0x00e6 /* U+00E6 LATIN SMALL LETTER AE */ +#define VHK_KEY_ccedilla 0x00e7 /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */ +#define VHK_KEY_egrave 0x00e8 /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */ +#define VHK_KEY_eacute 0x00e9 /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */ +#define VHK_KEY_ecircumflex 0x00ea /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */ +#define VHK_KEY_ediaeresis 0x00eb /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */ +#define VHK_KEY_igrave 0x00ec /* U+00EC LATIN SMALL LETTER I WITH GRAVE */ +#define VHK_KEY_iacute 0x00ed /* U+00ED LATIN SMALL LETTER I WITH ACUTE */ +#define VHK_KEY_icircumflex 0x00ee /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */ +#define VHK_KEY_idiaeresis 0x00ef /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */ +#define VHK_KEY_eth 0x00f0 /* U+00F0 LATIN SMALL LETTER ETH */ +#define VHK_KEY_ntilde 0x00f1 /* U+00F1 LATIN SMALL LETTER N WITH TILDE */ +#define VHK_KEY_ograve 0x00f2 /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */ +#define VHK_KEY_oacute 0x00f3 /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */ +#define VHK_KEY_ocircumflex 0x00f4 /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */ +#define VHK_KEY_otilde 0x00f5 /* U+00F5 LATIN SMALL LETTER O WITH TILDE */ +#define VHK_KEY_odiaeresis 0x00f6 /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */ +#define VHK_KEY_division 0x00f7 /* U+00F7 DIVISION SIGN */ +#define VHK_KEY_oslash 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ +#define VHK_KEY_ooblique 0x00f8 /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ +#define VHK_KEY_ugrave 0x00f9 /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */ +#define VHK_KEY_uacute 0x00fa /* U+00FA LATIN SMALL LETTER U WITH ACUTE */ +#define VHK_KEY_ucircumflex 0x00fb /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */ +#define VHK_KEY_udiaeresis 0x00fc /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */ +#define VHK_KEY_yacute 0x00fd /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */ +#define VHK_KEY_thorn 0x00fe /* U+00FE LATIN SMALL LETTER THORN */ +#define VHK_KEY_ydiaeresis 0x00ff /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */ + +/* Special "multimedia" keys, not present in the X11 header, but present in the + * GDk header. See https://sourceforge.net/p/vice-emu/bugs/2132/ + */ +#define VHK_KEY_ModeLock 0x1008ff01 +#define VHK_KEY_MonBrightnessUp 0x1008ff02 +#define VHK_KEY_MonBrightnessDown 0x1008ff03 +#define VHK_KEY_KbdLightOnOff 0x1008ff04 +#define VHK_KEY_KbdBrightnessUp 0x1008ff05 +#define VHK_KEY_KbdBrightnessDown 0x1008ff06 +#define VHK_KEY_Standby 0x1008ff10 +#define VHK_KEY_AudioLowerVolume 0x1008ff11 +#define VHK_KEY_AudioMute 0x1008ff12 +#define VHK_KEY_AudioRaiseVolume 0x1008ff13 +#define VHK_KEY_AudioPlay 0x1008ff14 +#define VHK_KEY_AudioStop 0x1008ff15 +#define VHK_KEY_AudioPrev 0x1008ff16 +#define VHK_KEY_AudioNext 0x1008ff17 +#define VHK_KEY_HomePage 0x1008ff18 +#define VHK_KEY_Mail 0x1008ff19 +#define VHK_KEY_Start 0x1008ff1a +#define VHK_KEY_Search 0x1008ff1b +#define VHK_KEY_AudioRecord 0x1008ff1c +#define VHK_KEY_Calculator 0x1008ff1d +#define VHK_KEY_Memo 0x1008ff1e +#define VHK_KEY_ToDoList 0x1008ff1f +#define VHK_KEY_Calendar 0x1008ff20 +#define VHK_KEY_PowerDown 0x1008ff21 +#define VHK_KEY_ContrastAdjust 0x1008ff22 +#define VHK_KEY_RockerUp 0x1008ff23 +#define VHK_KEY_RockerDown 0x1008ff24 +#define VHK_KEY_RockerEnter 0x1008ff25 +#define VHK_KEY_Back 0x1008ff26 +#define VHK_KEY_Forward 0x1008ff27 +#define VHK_KEY_Stop 0x1008ff28 +#define VHK_KEY_Refresh 0x1008ff29 +#define VHK_KEY_PowerOff 0x1008ff2a +#define VHK_KEY_WakeUp 0x1008ff2b +#define VHK_KEY_Eject 0x1008ff2c +#define VHK_KEY_ScreenSaver 0x1008ff2d +#define VHK_KEY_WWW 0x1008ff2e +#define VHK_KEY_Sleep 0x1008ff2f +#define VHK_KEY_Favorites 0x1008ff30 +#define VHK_KEY_AudioPause 0x1008ff31 +#define VHK_KEY_AudioMedia 0x1008ff32 +#define VHK_KEY_MyComputer 0x1008ff33 +#define VHK_KEY_VendorHome 0x1008ff34 +#define VHK_KEY_LightBulb 0x1008ff35 +#define VHK_KEY_Shop 0x1008ff36 +#define VHK_KEY_History 0x1008ff37 +#define VHK_KEY_OpenURL 0x1008ff38 +#define VHK_KEY_AddFavorite 0x1008ff39 +#define VHK_KEY_HotLinks 0x1008ff3a +#define VHK_KEY_BrightnessAdjust 0x1008ff3b +#define VHK_KEY_Finance 0x1008ff3c +#define VHK_KEY_Community 0x1008ff3d +#define VHK_KEY_AudioRewind 0x1008ff3e +#define VHK_KEY_BackForward 0x1008ff3f +#define VHK_KEY_Launch0 0x1008ff40 +#define VHK_KEY_Launch1 0x1008ff41 +#define VHK_KEY_Launch2 0x1008ff42 +#define VHK_KEY_Launch3 0x1008ff43 +#define VHK_KEY_Launch4 0x1008ff44 +#define VHK_KEY_Launch5 0x1008ff45 +#define VHK_KEY_Launch6 0x1008ff46 +#define VHK_KEY_Launch7 0x1008ff47 +#define VHK_KEY_Launch8 0x1008ff48 +#define VHK_KEY_Launch9 0x1008ff49 +#define VHK_KEY_LaunchA 0x1008ff4a +#define VHK_KEY_LaunchB 0x1008ff4b +#define VHK_KEY_LaunchC 0x1008ff4c +#define VHK_KEY_LaunchD 0x1008ff4d +#define VHK_KEY_LaunchE 0x1008ff4e +#define VHK_KEY_LaunchF 0x1008ff4f +#define VHK_KEY_ApplicationLeft 0x1008ff50 +#define VHK_KEY_ApplicationRight 0x1008ff51 +#define VHK_KEY_Book 0x1008ff52 +#define VHK_KEY_CD 0x1008ff53 +#define VHK_KEY_WindowClear 0x1008ff55 +#define VHK_KEY_Close 0x1008ff56 +#define VHK_KEY_Copy 0x1008ff57 +#define VHK_KEY_Cut 0x1008ff58 +#define VHK_KEY_Display 0x1008ff59 +#define VHK_KEY_DOS 0x1008ff5a +#define VHK_KEY_Documents 0x1008ff5b +#define VHK_KEY_Excel 0x1008ff5c +#define VHK_KEY_Explorer 0x1008ff5d +#define VHK_KEY_Game 0x1008ff5e +#define VHK_KEY_Go 0x1008ff5f +#define VHK_KEY_iTouch 0x1008ff60 +#define VHK_KEY_LogOff 0x1008ff61 +#define VHK_KEY_Market 0x1008ff62 +#define VHK_KEY_Meeting 0x1008ff63 +#define VHK_KEY_MenuKB 0x1008ff65 +#define VHK_KEY_MenuPB 0x1008ff66 +#define VHK_KEY_MySites 0x1008ff67 +#define VHK_KEY_New 0x1008ff68 +#define VHK_KEY_News 0x1008ff69 +#define VHK_KEY_OfficeHome 0x1008ff6a +#define VHK_KEY_Open 0x1008ff6b +#define VHK_KEY_Option 0x1008ff6c +#define VHK_KEY_Paste 0x1008ff6d +#define VHK_KEY_Phone 0x1008ff6e +#define VHK_KEY_Reply 0x1008ff72 +#define VHK_KEY_Reload 0x1008ff73 +#define VHK_KEY_RotateWindows 0x1008ff74 +#define VHK_KEY_RotationPB 0x1008ff75 +#define VHK_KEY_RotationKB 0x1008ff76 +#define VHK_KEY_Save 0x1008ff77 +#define VHK_KEY_ScrollUp 0x1008ff78 +#define VHK_KEY_ScrollDown 0x1008ff79 +#define VHK_KEY_ScrollClick 0x1008ff7a +#define VHK_KEY_Send 0x1008ff7b +#define VHK_KEY_Spell 0x1008ff7c +#define VHK_KEY_SplitScreen 0x1008ff7d +#define VHK_KEY_Support 0x1008ff7e +#define VHK_KEY_TaskPane 0x1008ff7f +#define VHK_KEY_Terminal 0x1008ff80 +#define VHK_KEY_Tools 0x1008ff81 +#define VHK_KEY_Travel 0x1008ff82 +#define VHK_KEY_UserPB 0x1008ff84 +#define VHK_KEY_User1KB 0x1008ff85 +#define VHK_KEY_User2KB 0x1008ff86 +#define VHK_KEY_Video 0x1008ff87 +#define VHK_KEY_WheelButton 0x1008ff88 +#define VHK_KEY_Word 0x1008ff89 +#define VHK_KEY_Xfer 0x1008ff8a +#define VHK_KEY_ZoomIn 0x1008ff8b +#define VHK_KEY_ZoomOut 0x1008ff8c +#define VHK_KEY_Away 0x1008ff8d +#define VHK_KEY_Messenger 0x1008ff8e +#define VHK_KEY_WebCam 0x1008ff8f +#define VHK_KEY_MailForward 0x1008ff90 +#define VHK_KEY_Pictures 0x1008ff91 +#define VHK_KEY_Music 0x1008ff92 +#define VHK_KEY_Battery 0x1008ff93 +#define VHK_KEY_Bluetooth 0x1008ff94 +#define VHK_KEY_WLAN 0x1008ff95 +#define VHK_KEY_UWB 0x1008ff96 +#define VHK_KEY_AudioForward 0x1008ff97 +#define VHK_KEY_AudioRepeat 0x1008ff98 +#define VHK_KEY_AudioRandomPlay 0x1008ff99 +#define VHK_KEY_Subtitle 0x1008ff9a +#define VHK_KEY_AudioCycleTrack 0x1008ff9b +#define VHK_KEY_CycleAngle 0x1008ff9c +#define VHK_KEY_FrameBack 0x1008ff9d +#define VHK_KEY_FrameForward 0x1008ff9e +#define VHK_KEY_Time 0x1008ff9f +#define VHK_KEY_SelectButton 0x1008ffa0 +#define VHK_KEY_View 0x1008ffa1 +#define VHK_KEY_TopMenu 0x1008ffa2 +#define VHK_KEY_Red 0x1008ffa3 +#define VHK_KEY_Green 0x1008ffa4 +#define VHK_KEY_Yellow 0x1008ffa5 +#define VHK_KEY_Blue 0x1008ffa6 +#define VHK_KEY_Suspend 0x1008ffa7 +#define VHK_KEY_Hibernate 0x1008ffa8 +#define VHK_KEY_TouchpadToggle 0x1008ffa9 +#define VHK_KEY_TouchpadOn 0x1008ffb0 +#define VHK_KEY_TouchpadOff 0x1008ffb1 +#define VHK_KEY_AudioMicMute 0x1008ffb2 +#define VHK_KEY_Keyboard 0x1008ffb3 +#define VHK_KEY_WWAN 0x1008ffb4 +#define VHK_KEY_RFKill 0x1008ffb5 +#define VHK_KEY_AudioPreset 0x1008ffb6 +/* Key modifier masks */ +#define VHK_MOD_NONE 0x0000 +#define VHK_MOD_ALT 0x0001 +#define VHK_MOD_COMMAND 0x0002 +#define VHK_MOD_CONTROL 0x0004 +#define VHK_MOD_HYPER 0x0008 +#define VHK_MOD_META 0x0010 +#define VHK_MOD_OPTION 0x0020 +#define VHK_MOD_SHIFT 0x0040 +#define VHK_MOD_SUPER 0x0080 + +uint32_t vhk_keysym_from_name (const char *name); +const char *vhk_keysym_name (uint32_t vice_keysym); +uint32_t vhk_modifier_from_name(const char *name, const char **endptr); +const char *vhk_modifier_name (uint32_t vice_modifier); +char *vhk_modmask_name (uint32_t vice_modmask); +char *vhk_hotkey_label (uint32_t vice_keysym, uint32_t vice_modmask); + +#endif diff --git a/src/Emulators/vice/arch/shared/macOS-util.h b/src/Emulators/vice/arch/shared/macOS-util.h new file mode 100644 index 00000000..f8086a2f --- /dev/null +++ b/src/Emulators/vice/arch/shared/macOS-util.h @@ -0,0 +1,48 @@ +/** + * \file macOS-util.h + * \brief A collection of little macOS helpers. + * + * Calling Objective-C code from C is possible, but not very readable. + * Nicer to just plop a few readable functions in here. + * + * \author David Hogan + */ + +/* This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ +#ifndef VICE_MACOS_UTIL_H +#define VICE_MACOS_UTIL_H + +#import + +#ifdef USE_GTK3UI +#import +#import +#endif + +void vice_macos_set_main_thread(void); +void vice_macos_set_vice_thread_priority(bool warp_enabled); +void vice_macos_set_render_thread_priority(void); + +#ifdef USE_GTK3UI +void vice_macos_get_widget_frame_and_content_rect(GtkWidget *widget, CGRect *native_frame, CGRect *content_rect); +#endif + +#endif /* #ifndef VICE_MACOS_UTIL_H */ diff --git a/src/Emulators/vice/arch/shared/rawnetarch.h b/src/Emulators/vice/arch/shared/rawnetarch.h new file mode 100644 index 00000000..a7ac6633 --- /dev/null +++ b/src/Emulators/vice/arch/shared/rawnetarch.h @@ -0,0 +1,124 @@ +/* + * rawnetarch.h - raw ethernet interface + * architecture-dependant stuff + * + * Written by + * Spiro Trikaliotis + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include + +#ifdef HAVE_RAWNET +#else + #error RAWNETARCH.H should not be included if HAVE_RAWNET is not defined! +#endif /* #ifdef HAVE_RAWNET */ + +#ifndef VICE_RAWNETARCH_H +#define VICE_RAWNETARCH_H + +/* define this only if VICE should write each and every frame received + and send into the VICE log + WARNING: The log grows very fast! +*/ +/* #define RAWNET_DEBUG_FRAMES */ + +#include "log.h" +#include "vicetypes.h" + +int rawnet_arch_resources_init(void); +int rawnet_arch_cmdline_options_init(void); +void rawnet_arch_resources_shutdown(void); + +int rawnet_arch_init(void); +void rawnet_arch_pre_reset(void); +void rawnet_arch_post_reset(void); +int rawnet_arch_activate(const char *interface_name); +void rawnet_arch_deactivate(void); +void rawnet_arch_set_mac(const uint8_t mac[6]); +void rawnet_arch_set_hashfilter(const uint32_t hash_mask[2]); + +void rawnet_arch_recv_ctl(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash); + +void rawnet_arch_line_ctl(int bEnableTransmitter, int bEnableReceiver); + +void rawnet_arch_transmit(int force, int onecoll, int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe); + +int rawnet_arch_receive(uint8_t *pbuffer, int *plen, int *phashed, int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast, int *pcrc_error); + +int rawnet_arch_enumadapter_open(void); +int rawnet_arch_enumadapter(char **ppname, char **ppdescription); +int rawnet_arch_enumadapter_close(void); +char *rawnet_arch_get_standard_interface(void); + +int rawnet_arch_enumdriver_open(void); +int rawnet_arch_enumdriver(char **ppname, char **ppdescription); +int rawnet_arch_enumdriver_close(void); +char *rawnet_arch_get_standard_driver(void); + +#ifdef UNIX_COMPILE + +/** #define RAWNET_DEBUG_ARCH 1 **/ +/** #define RAWNET_DEBUG_PKTDUMP 1 **/ + +#ifdef RAWNET_DEBUG_PKTDUMP +void rawnet_arch_debug_output(const char *text, uint8_t *what, int count); +#endif + +/* Logging device to be used by rawnet drivers */ +extern log_t rawnet_arch_log; + +/* Under Unix we can have various rawnet drivers, and each exposes its + * interface by instantiating a rawnet_driver_t structure */ +typedef struct rawnet_arch_driver_s { + const char *name; + void (*pre_reset)(void); + void (*post_reset)(void); + int (*activate)(const char *interface_name); + void (*deactivate)(void); + void (*set_mac)(const uint8_t mac[6]); + void (*set_hashfilter)(const uint32_t hash_mask[2]); + + void (*recv_ctl)(int bBroadcast, int bIA, int bMulticast, int bCorrect, int bPromiscuous, int bIAHash); + + void (*line_ctl)(int bEnableTransmitter, int bEnableReceiver); + + void (*transmit)(int force, int onecoll, int inhibit_crc, int tx_pad_dis, int txlength, uint8_t *txframe); + + int (*receive)(uint8_t *pbuffer, int *plen, int *phashed, int *phash_index, int *prx_ok, int *pcorrect_mac, int *pbroadcast, int *pcrc_error); + + int (*enumadapter_open)(void); + int (*enumadapter)(char **ppname, char **ppdescription); + int (*enumadapter_close)(void); + + char *(*get_standard_interface)(void); +} rawnet_arch_driver_t; + +#ifdef HAVE_PCAP +extern rawnet_arch_driver_t rawnet_arch_driver_pcap; +#endif +#ifdef HAVE_TUNTAP +extern rawnet_arch_driver_t rawnet_arch_driver_tuntap; +#endif + +#endif /* ifdef UNIX_COMPILE */ + +#endif diff --git a/src/Emulators/vice/arch/shared/uiactions.h b/src/Emulators/vice/arch/shared/uiactions.h new file mode 100644 index 00000000..34d6dcae --- /dev/null +++ b/src/Emulators/vice/arch/shared/uiactions.h @@ -0,0 +1,467 @@ +/** \file uiactions.h + * \brief UI actions interface - header + * + * \author Bas Wassink + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + */ + +#ifndef VICE_UIACTIONS_H +#define VICE_UIACTIONS_H + +#include +#include +#include +/* this header is required if the macro IS_ACTION_NAME_CHAR() is used: */ +#include + +/* for the VICE_MACHINE_* masks */ +#include "machine.h" + + +/** \brief Mapping of action IDs to names and descriptions + */ +typedef struct ui_action_info_s { + int id; /**< action ID */ + const char *name; /**< action name */ + const char *desc; /**< action description */ +} ui_action_info_t; + + +/** \brief Mapping of an action ID to a handler + */ +typedef struct ui_action_map_s { + int action; /**< action ID */ + + /* + * Action handler data + */ + + void (*handler)(struct ui_action_map_s*); /**< function handling the action */ + void *data; /**< optional user data */ + + + /* modes */ + bool blocks; /**< action blocks (the same action cannot be + triggered again until it finishes) */ + bool dialog; /**< action pops up a dialog (only one dialog action + is allowed at a time), this implies using the + UI thread */ + bool uithread; /**< must run on the UI thread */ + + /* state */ + bool is_busy; /**< action is busy */ + + /* + * Hotkey data + */ + uint32_t vice_keysym; /**< VICE keysym, see hotkeys.vhkkeysyms.h */ + uint32_t vice_modmask; /**< VICE modmask, see hotkeys.vhkkeysyms.h */ + uint32_t arch_keysym; /**< arch keysym */ + uint32_t arch_modmask; /**< arch modmask */ + void *menu_item[2]; /**< menu item references */ + void *user_data; /**< additional data (optional) */ +} ui_action_map_t; + +/** \brief Terminator of action maps + */ +#define UI_ACTION_MAP_TERMINATOR { .action = ACTION_NONE, .handler = NULL } + + +/** \brief Check for valid action name character + * + * Check if \a ch is a valid character in an action name. + * + * Supported characters are: + * * a-z + * * A-Z + * * 0-9 + * * '_', '-' and ':' + */ +#define IS_ACTION_NAME_CHAR(ch) \ + (isalpha((unsigned char)(ch)) || isdigit((unsigned char)(ch)) || \ + ch == '_' || ch == '-' || ch == ':') + + +/** \brief IDs for the UI actions + * + * These IDs are used to refer to specific UI actions/dialogs. + */ +enum { + ACTION_INVALID = -1, + ACTION_NONE = 0, + ACTION_ADVANCE_FRAME, + ACTION_CART_ATTACH, /* Gtk3 has one dialog for CRT and RAW */ + ACTION_CART_ATTACH_RAW, /* SDL has separate dialogs for CRT and RAW */ + ACTION_CART_ATTACH_RAW_1000, /* CBM-II */ + ACTION_CART_ATTACH_RAW_2000, /* CBM-II, VIC-20 */ + ACTION_CART_ATTACH_RAW_4000, /* CBM-II, VIC_20 */ + ACTION_CART_ATTACH_RAW_6000, /* CBM-II, VIC-20 */ + ACTION_CART_ATTACH_RAW_A000, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_B000, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_BEHRBONZ, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_FINAL, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_MEGACART, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_MINIMON, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_ULTIMEM, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_VICFP, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_WRITENOW, /* VIC-20 */ + ACTION_CART_ATTACH_RAW_JACINT1MB, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_MAGIC, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_MULTI, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_SPEEDY, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C1_FULL, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C1_LOW, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C1_HIGH, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C2_FULL, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C2_LOW, /* Plus/4 */ + ACTION_CART_ATTACH_RAW_C2_HIGH, /* Plus/4 */ + ACTION_CART_DETACH, + ACTION_CART_DETACH_1000, /* CBM-II */ + ACTION_CART_DETACH_2000, /* CBM-II */ + ACTION_CART_DETACH_4000, /* CBM-II */ + ACTION_CART_DETACH_6000, /* CBM-II */ + ACTION_CART_FREEZE, + ACTION_DEBUG_AUTOPLAYBACK_FRAMES, + ACTION_DEBUG_BLITTER_LOG_TOGGLE, + ACTION_DEBUG_CORE_DUMP_TOGGLE, + ACTION_DEBUG_DMA_LOG_TOGGLE, + ACTION_DEBUG_FLASH_LOG_TOGGLE, + ACTION_DEBUG_TRACE_CPU_TOGGLE, + ACTION_DEBUG_TRACE_DRIVE_10_TOGGLE, + ACTION_DEBUG_TRACE_DRIVE_11_TOGGLE, + ACTION_DEBUG_TRACE_DRIVE_8_TOGGLE, + ACTION_DEBUG_TRACE_DRIVE_9_TOGGLE, + ACTION_DEBUG_TRACE_IEC_TOGGLE, + ACTION_DEBUG_TRACE_IEEE488_TOGGLE, + ACTION_DEBUG_TRACE_MODE, + ACTION_DRIVE_ATTACH_10_0, + ACTION_DRIVE_ATTACH_10_1, + ACTION_DRIVE_ATTACH_11_0, + ACTION_DRIVE_ATTACH_11_1, + ACTION_DRIVE_ATTACH_8_0, + ACTION_DRIVE_ATTACH_8_1, + ACTION_DRIVE_ATTACH_9_0, + ACTION_DRIVE_ATTACH_9_1, + ACTION_DRIVE_CREATE, + ACTION_DRIVE_DETACH_10_0, + ACTION_DRIVE_DETACH_10_1, + ACTION_DRIVE_DETACH_11_0, + ACTION_DRIVE_DETACH_11_1, + ACTION_DRIVE_DETACH_8_0, + ACTION_DRIVE_DETACH_8_1, + ACTION_DRIVE_DETACH_9_0, + ACTION_DRIVE_DETACH_9_1, + ACTION_DRIVE_DETACH_ALL, + ACTION_EDIT_COPY, + ACTION_EDIT_PASTE, + ACTION_FLIPLIST_ADD_8_0, + ACTION_FLIPLIST_CLEAR_8_0, + ACTION_FLIPLIST_LOAD_8_0, + ACTION_FLIPLIST_NEXT_8_0, + ACTION_FLIPLIST_PREVIOUS_8_0, + ACTION_FLIPLIST_REMOVE_8_0, + ACTION_FLIPLIST_SAVE_8_0, + ACTION_FLIPLIST_ADD_8_1, + ACTION_FLIPLIST_CLEAR_8_1, + ACTION_FLIPLIST_LOAD_8_1, + ACTION_FLIPLIST_NEXT_8_1, + ACTION_FLIPLIST_PREVIOUS_8_1, + ACTION_FLIPLIST_REMOVE_8_1, + ACTION_FLIPLIST_SAVE_8_1, + ACTION_FLIPLIST_ADD_9_0, + ACTION_FLIPLIST_CLEAR_9_0, + ACTION_FLIPLIST_LOAD_9_0, + ACTION_FLIPLIST_NEXT_9_0, + ACTION_FLIPLIST_PREVIOUS_9_0, + ACTION_FLIPLIST_REMOVE_9_0, + ACTION_FLIPLIST_SAVE_9_0, + ACTION_FLIPLIST_ADD_9_1, + ACTION_FLIPLIST_CLEAR_9_1, + ACTION_FLIPLIST_LOAD_9_1, + ACTION_FLIPLIST_NEXT_9_1, + ACTION_FLIPLIST_PREVIOUS_9_1, + ACTION_FLIPLIST_REMOVE_9_1, + ACTION_FLIPLIST_SAVE_9_1, + + ACTION_FLIPLIST_ADD_10_0, + ACTION_FLIPLIST_CLEAR_10_0, + ACTION_FLIPLIST_LOAD_10_0, + ACTION_FLIPLIST_NEXT_10_0, + ACTION_FLIPLIST_PREVIOUS_10_0, + ACTION_FLIPLIST_REMOVE_10_0, + ACTION_FLIPLIST_SAVE_10_0, + ACTION_FLIPLIST_ADD_10_1, + ACTION_FLIPLIST_CLEAR_10_1, + ACTION_FLIPLIST_LOAD_10_1, + ACTION_FLIPLIST_NEXT_10_1, + ACTION_FLIPLIST_PREVIOUS_10_1, + ACTION_FLIPLIST_REMOVE_10_1, + ACTION_FLIPLIST_SAVE_10_1, + ACTION_FLIPLIST_ADD_11_0, + ACTION_FLIPLIST_CLEAR_11_0, + ACTION_FLIPLIST_LOAD_11_0, + ACTION_FLIPLIST_NEXT_11_0, + ACTION_FLIPLIST_PREVIOUS_11_0, + ACTION_FLIPLIST_REMOVE_11_0, + ACTION_FLIPLIST_SAVE_11_0, + ACTION_FLIPLIST_ADD_11_1, + ACTION_FLIPLIST_CLEAR_11_1, + ACTION_FLIPLIST_LOAD_11_1, + ACTION_FLIPLIST_NEXT_11_1, + ACTION_FLIPLIST_PREVIOUS_11_1, + ACTION_FLIPLIST_REMOVE_11_1, + ACTION_FLIPLIST_SAVE_11_1, + ACTION_FULLSCREEN_DECORATIONS_TOGGLE, + ACTION_FULLSCREEN_TOGGLE, + ACTION_HELP_ABOUT, + ACTION_HELP_COMMAND_LINE, + ACTION_HELP_COMPILE_TIME, + ACTION_HELP_HOTKEYS, + ACTION_HELP_MANUAL, + ACTION_HISTORY_MILESTONE_RESET, + ACTION_HISTORY_MILESTONE_SET, + ACTION_HISTORY_PLAYBACK_START, + ACTION_HISTORY_PLAYBACK_STOP, + ACTION_HISTORY_RECORD_START, + ACTION_HISTORY_RECORD_STOP, + ACTION_HOTKEYS_CLEAR, + ACTION_HOTKEYS_DEFAULT, + ACTION_HOTKEYS_LOAD, + ACTION_HOTKEYS_LOAD_FROM, + ACTION_HOTKEYS_SAVE, + ACTION_HOTKEYS_SAVE_TO, + ACTION_KEYSET_JOYSTICK_TOGGLE, + ACTION_MEDIA_RECORD, + ACTION_MEDIA_RECORD_AUDIO, + ACTION_MEDIA_RECORD_SCREENSHOT, + ACTION_MEDIA_RECORD_VIDEO, + ACTION_MEDIA_STOP, + ACTION_MONITOR_OPEN, + ACTION_MOUSE_GRAB_TOGGLE, + ACTION_PAUSE_TOGGLE, + ACTION_QUIT, + ACTION_MACHINE_RESET_CPU, + ACTION_MACHINE_POWER_CYCLE, + /* TODO: rework into DRIVE_[9-11]RESET_BUTTON/POWER_CYCLE_ etc. */ + ACTION_RESET_DRIVE_8, + ACTION_RESET_DRIVE_8_CONFIG, + ACTION_RESET_DRIVE_8_INSTALL, + ACTION_RESET_DRIVE_9, + ACTION_RESET_DRIVE_9_CONFIG, + ACTION_RESET_DRIVE_9_INSTALL, + ACTION_RESET_DRIVE_10, + ACTION_RESET_DRIVE_10_CONFIG, + ACTION_RESET_DRIVE_10_INSTALL, + ACTION_RESET_DRIVE_11, + ACTION_RESET_DRIVE_11_CONFIG, + ACTION_RESET_DRIVE_11_INSTALL, + ACTION_RESTORE_DISPLAY, + ACTION_SCREENSHOT_QUICKSAVE, + ACTION_SETTINGS_DEFAULT, + ACTION_SETTINGS_DIALOG, + ACTION_SETTINGS_LOAD_EXTRA, + ACTION_SETTINGS_LOAD_FROM, + ACTION_SETTINGS_LOAD, + ACTION_SETTINGS_SAVE, + ACTION_SETTINGS_SAVE_TO, + ACTION_SHOW_STATUSBAR_TOGGLE, + ACTION_SHOW_STATUSBAR_SECONDARY_TOGGLE, + ACTION_SMART_ATTACH, + ACTION_SNAPSHOT_LOAD, + ACTION_SNAPSHOT_QUICKLOAD, + ACTION_SNAPSHOT_QUICKSAVE, + ACTION_SNAPSHOT_SAVE, + ACTION_SPEED_CPU_10, + ACTION_SPEED_CPU_25, + ACTION_SPEED_CPU_50, + ACTION_SPEED_CPU_100, + ACTION_SPEED_CPU_200, + ACTION_SPEED_CPU_CUSTOM, + ACTION_SPEED_FPS_50, + ACTION_SPEED_FPS_60, + ACTION_SPEED_FPS_CUSTOM, + ACTION_SPEED_FPS_REAL, + ACTION_SWAP_CONTROLPORT_TOGGLE, + ACTION_TAPE_ATTACH_1, + ACTION_TAPE_ATTACH_2, + ACTION_TAPE_CREATE_1, + ACTION_TAPE_CREATE_2, + ACTION_TAPE_DETACH_1, + ACTION_TAPE_DETACH_2, + ACTION_TAPE_FFWD_1, + ACTION_TAPE_FFWD_2, + ACTION_TAPE_PLAY_1, + ACTION_TAPE_PLAY_2, + ACTION_TAPE_RECORD_1, + ACTION_TAPE_RECORD_2, + ACTION_TAPE_RESET_1, + ACTION_TAPE_RESET_2, + ACTION_TAPE_RESET_COUNTER_1, + ACTION_TAPE_RESET_COUNTER_2, + ACTION_TAPE_REWIND_1, + ACTION_TAPE_REWIND_2, + ACTION_TAPE_STOP_1, + ACTION_TAPE_STOP_2, + ACTION_WARP_MODE_TOGGLE, + + /* VSID actions */ + ACTION_PSID_LOAD, + ACTION_PSID_OVERRIDE_TOGGLE, + ACTION_PSID_SUBTUNE_1, + ACTION_PSID_SUBTUNE_2, + ACTION_PSID_SUBTUNE_3, + ACTION_PSID_SUBTUNE_4, + ACTION_PSID_SUBTUNE_5, + ACTION_PSID_SUBTUNE_6, + ACTION_PSID_SUBTUNE_7, + ACTION_PSID_SUBTUNE_8, + ACTION_PSID_SUBTUNE_9, + ACTION_PSID_SUBTUNE_10, + ACTION_PSID_SUBTUNE_11, + ACTION_PSID_SUBTUNE_12, + ACTION_PSID_SUBTUNE_13, + ACTION_PSID_SUBTUNE_14, + ACTION_PSID_SUBTUNE_15, + ACTION_PSID_SUBTUNE_16, + ACTION_PSID_SUBTUNE_17, + ACTION_PSID_SUBTUNE_18, + ACTION_PSID_SUBTUNE_19, + ACTION_PSID_SUBTUNE_20, + ACTION_PSID_SUBTUNE_21, + ACTION_PSID_SUBTUNE_22, + ACTION_PSID_SUBTUNE_23, + ACTION_PSID_SUBTUNE_24, + ACTION_PSID_SUBTUNE_25, + ACTION_PSID_SUBTUNE_26, + ACTION_PSID_SUBTUNE_27, + ACTION_PSID_SUBTUNE_28, + ACTION_PSID_SUBTUNE_29, + ACTION_PSID_SUBTUNE_30, + + ACTION_PSID_SUBTUNE_DEFAULT, + ACTION_PSID_SUBTUNE_NEXT, + ACTION_PSID_SUBTUNE_PREVIOUS, + + ACTION_PSID_PLAY, + ACTION_PSID_PAUSE, + ACTION_PSID_STOP, + ACTION_PSID_FFWD, + ACTION_PSID_LOOP_TOGGLE, + + /* playlist actions */ + ACTION_PSID_PLAYLIST_FIRST, + ACTION_PSID_PLAYLIST_PREVIOUS, + ACTION_PSID_PLAYLIST_NEXT, + ACTION_PSID_PLAYLIST_LAST, + ACTION_PSID_PLAYLIST_ADD, + ACTION_PSID_PLAYLIST_LOAD, + ACTION_PSID_PLAYLIST_SAVE, + ACTION_PSID_PLAYLIST_CLEAR, + + /* TODO: VSID playlist controls? */ + + /* PET */ + ACTION_DIAGNOSTIC_PIN_TOGGLE, + + /* Printers and plotters */ + ACTION_PRINTER_FORMFEED_4, + ACTION_PRINTER_FORMFEED_5, + ACTION_PRINTER_FORMFEED_6, + ACTION_PRINTER_FORMFEED_USERPORT, + + /* SDL UI only: show virtual keyboard on the emulated display */ + ACTION_VIRTUAL_KEYBOARD, + + /* Border modes */ + ACTION_BORDER_MODE_NORMAL, + ACTION_BORDER_MODE_FULL, + ACTION_BORDER_MODE_DEBUG, + ACTION_BORDER_MODE_NONE, + + /* SCPU64 switches */ + ACTION_SCPU_JIFFY_SWITCH_TOGGLE, + ACTION_SCPU_SPEED_SWITCH_TOGGLE, + + ACTION_ID_COUNT /**< number of action IDs */ +}; + +/* Action info getters */ +int ui_action_get_id (const char *name); +const char * ui_action_get_name (int action); +const char * ui_action_get_desc (int action); +ui_action_info_t * ui_action_get_info_list(void); +bool ui_action_is_valid (int action); + +/* Get action IDs for drive actions */ +int ui_action_id_fliplist_add (int unit, int drive); +int ui_action_id_fliplist_remove (int unit, int drive); +int ui_action_id_fliplist_next (int unit, int drive); +int ui_action_id_fliplist_previous (int unit, int drive); +int ui_action_id_fliplist_clear (int unit, int drive); +int ui_action_id_fliplist_load (int unit, int drive); +int ui_action_id_fliplist_save (int unit, int drive); +int ui_action_id_drive_attach (int unit, int drive); +int ui_action_id_drive_detach (int unit, int drive); +int ui_action_id_drive_reset (int unit); +int ui_action_id_drive_reset_config (int unit); +int ui_action_id_drive_reset_install(int unit); + +/* Main API */ +void ui_actions_init (void); +void ui_actions_set_dispatch (void (*dispatch)(ui_action_map_t *)); +void ui_actions_shutdown (void); +void ui_actions_register (const ui_action_map_t *mappings); + +void ui_action_trigger (int action); +void ui_action_finish (int action); +/* TODO: implement the following: */ +bool ui_action_def (int action, const char *hotkey); +bool ui_action_redef (int action, const char *hotkey); +bool ui_action_undef (int action); + +/* + * For the added hotkeys data: + */ + +ui_action_map_t *ui_action_map_get (int action); +ui_action_map_t *ui_action_map_get_by_hotkey (uint32_t vice_keysym, uint32_t vice_modmask); +ui_action_map_t *ui_action_map_get_by_arch_hotkey (uint32_t arch_keysym, uint32_t arch_modmask); + +void ui_action_map_clear_hotkey (ui_action_map_t *map); +void ui_action_map_clear_hotkey_by_action(int action); +void ui_action_map_clear_hotkey_by_hotkey(uint32_t vice_keysym, uint32_t vice_modmask); + +ui_action_map_t *ui_action_map_set_hotkey (int action, + uint32_t vice_keysym, + uint32_t vice_modmask, + uint32_t arch_keysym, + uint32_t arch_modmask); +void ui_action_map_set_hotkey_by_map (ui_action_map_t *map, + uint32_t vice_keysym, + uint32_t vice_modmask, + uint32_t arch_keysym, + uint32_t arch_modmask); + +char *ui_action_map_get_hotkey_label (ui_action_map_t *map); +char *ui_action_get_hotkey_label (int action); + +#endif diff --git a/src/Emulators/vice/arch/ui.c b/src/Emulators/vice/arch/ui.c index 26e8335b..27749003 100644 --- a/src/Emulators/vice/arch/ui.c +++ b/src/Emulators/vice/arch/ui.c @@ -45,7 +45,6 @@ #include "mouse.h" #include "mousedrv.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "ui.h" #include "uiapi.h" @@ -59,6 +58,7 @@ #include "vsync.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" #ifndef SDL_DISABLE #define SDL_DISABLE SDL_IGNORE @@ -301,51 +301,21 @@ void ui_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { -// { "-menukey", SET_RESOURCE, 1, NULL, NULL, "MenuKey", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu activate key" }, -// { "-menukeyup", SET_RESOURCE, 1, NULL, NULL, "MenuKeyUp", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu up key" }, -// { "-menukeydown", SET_RESOURCE, 1, NULL, NULL, "MenuKeyDown", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu down key" }, -// { "-menukeyleft", SET_RESOURCE, 1, NULL, NULL, "MenuKeyLeft", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu left key" }, -// { "-menukeyright", SET_RESOURCE, 1, NULL, NULL, "MenuKeyRight", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu right key" }, -// { "-menukeyselect", SET_RESOURCE, 1, NULL, NULL, "MenuKeySelect", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu select key" }, -// { "-menukeycancel", SET_RESOURCE, 1, NULL, NULL, "MenuKeyCancel", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu cancel key" }, -// { "-menukeyexit", SET_RESOURCE, 1, NULL, NULL, "MenuKeyExit", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu exit key" }, -// { "-menukeymap", SET_RESOURCE, 1, NULL, NULL, "MenuKeyMap", NULL, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// "", "Keycode of the menu map key" }, -// { "-saveresourcesonexit", SET_RESOURCE, 0, NULL, NULL, "SaveResourcesOnExit", (resource_value_t)1, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Enable save resource on exit" }, -// { "+saveresourcesonexit", SET_RESOURCE, 0, NULL, NULL, "SaveResourcesOnExit", (resource_value_t)0, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Disable save resource on exit" }, -// { "-confirmonexit", SET_RESOURCE, 0, NULL, NULL, "ConfirmOnExit", (resource_value_t)1, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Enable confirm on exit" }, -// { "+confirmonexit", SET_RESOURCE, 0, NULL, NULL, "ConfirmOnExit", (resource_value_t)0, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Disable confirm on exit" }, -// { "-statusbar", SET_RESOURCE, 0, NULL, NULL, "SDLStatusbar", (resource_value_t)1, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Enable statusbar" }, -// { "+statusbar", SET_RESOURCE, 0, NULL, NULL, "SDLStatusbar", (resource_value_t)0, -// USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, -// NULL, "Disable statusbar" }, +// { "-menukey", SET_RESOURCE, 1, NULL, NULL, "MenuKey", NULL, // "", "Keycode of the menu activate key"}, +// { "-menukeyup", SET_RESOURCE, 1, NULL, NULL, "MenuKeyUp", NULL, // "", "Keycode of the menu up key"}, +// { "-menukeydown", SET_RESOURCE, 1, NULL, NULL, "MenuKeyDown", NULL, // "", "Keycode of the menu down key"}, +// { "-menukeyleft", SET_RESOURCE, 1, NULL, NULL, "MenuKeyLeft", NULL, // "", "Keycode of the menu left key"}, +// { "-menukeyright", SET_RESOURCE, 1, NULL, NULL, "MenuKeyRight", NULL, // "", "Keycode of the menu right key"}, +// { "-menukeyselect", SET_RESOURCE, 1, NULL, NULL, "MenuKeySelect", NULL, // "", "Keycode of the menu select key"}, +// { "-menukeycancel", SET_RESOURCE, 1, NULL, NULL, "MenuKeyCancel", NULL, // "", "Keycode of the menu cancel key"}, +// { "-menukeyexit", SET_RESOURCE, 1, NULL, NULL, "MenuKeyExit", NULL, // "", "Keycode of the menu exit key"}, +// { "-menukeymap", SET_RESOURCE, 1, NULL, NULL, "MenuKeyMap", NULL, // "", "Keycode of the menu map key"}, +// { "-saveresourcesonexit", SET_RESOURCE, 0, NULL, NULL, "SaveResourcesOnExit", (resource_value_t)1, // NULL, "Enable save resource on exit"}, +// { "+saveresourcesonexit", SET_RESOURCE, 0, NULL, NULL, "SaveResourcesOnExit", (resource_value_t)0, // NULL, "Disable save resource on exit"}, +// { "-confirmonexit", SET_RESOURCE, 0, NULL, NULL, "ConfirmOnExit", (resource_value_t)1, // NULL, "Enable confirm on exit"}, +// { "+confirmonexit", SET_RESOURCE, 0, NULL, NULL, "ConfirmOnExit", (resource_value_t)0, // NULL, "Disable confirm on exit"}, +// { "-statusbar", SET_RESOURCE, 0, NULL, NULL, "SDLStatusbar", (resource_value_t)1, // NULL, "Enable statusbar"}, +// { "+statusbar", SET_RESOURCE, 0, NULL, NULL, "SDLStatusbar", (resource_value_t)0, // NULL, "Disable statusbar"}, CMDLINE_LIST_END }; @@ -429,11 +399,11 @@ ui_jam_action_t ui_jam_dialog(const char *format, ...) { // int retval; - c64d_is_cpu_in_jam_state = 1; + VICE_HOOK_LIFECYCLE_JAM_FLAG(); - c64d_show_message("CPU JAM has occurred"); - - c64d_set_debug_mode(DEBUGGER_MODE_PAUSED); + VICE_HOOK_LIFECYCLE_MESSAGE("CPU JAM has occurred"); + + VICE_HOOK_LIFECYCLE_DEBUG_MODE(DEBUGGER_MODE_PAUSED); return UI_JAM_NONE; } diff --git a/src/Emulators/vice/arch/uicmdline.c b/src/Emulators/vice/arch/uicmdline.c index 5e197746..505a84a7 100644 --- a/src/Emulators/vice/arch/uicmdline.c +++ b/src/Emulators/vice/arch/uicmdline.c @@ -38,7 +38,7 @@ void ui_cmdline_show_help(unsigned int num_options, cmdline_option_ram_t *option printf(_("\nAvailable command-line options:\n\n")); for (i = 0; i < num_options; i++) { fputs(options[i].name, stdout); - if (options[i].need_arg && cmdline_options_get_param(i) != NULL) + if ((options[i].attributes & CMDLINE_ATTRIB_NEED_ARGS) && cmdline_options_get_param(i) != NULL) /* VICE 3.10: need_arg -> attributes */ printf(" %s", cmdline_options_get_param(i)); printf("\n\t%s\n", cmdline_options_get_description(i)); } diff --git a/src/Emulators/vice/arch/uifilereq.c b/src/Emulators/vice/arch/uifilereq.c index 79261f6a..bdb6481f 100644 --- a/src/Emulators/vice/arch/uifilereq.c +++ b/src/Emulators/vice/arch/uifilereq.c @@ -142,7 +142,7 @@ static void sdl_ui_print_translate_seperator(const char *text, int x, int y) char *new_text = NULL; len = strlen(text); - new_text = lib_stralloc(text); + new_text = lib_strdup(text); for (i = 0; i < len; i++) { if (new_text[i] == '\\') { @@ -170,7 +170,7 @@ static void sdl_ui_display_path(const char *current_dir) len = strlen(current_dir); if (len > menu_draw->max_text_x) { - text = lib_stralloc(current_dir); + text = lib_strdup(current_dir); temp = strchr(current_dir + 1, FSDEV_DIR_SEP_CHR); before = (int)(temp - current_dir + 1); @@ -346,7 +346,7 @@ char* sdl_ui_file_selection_dialog(const char* title, ui_menu_filereq_mode_t mod current_dir = lib_malloc(maxpathlen); ioutil_getcwd(current_dir, maxpathlen); - backup_dir = lib_stralloc(current_dir); + backup_dir = lib_strdup(current_dir); directory = ioutil_opendir(current_dir); if (directory == NULL) { @@ -436,7 +436,7 @@ char* sdl_ui_file_selection_dialog(const char* title, ui_menu_filereq_mode_t mod } } } else { - retval = lib_stralloc(current_dir); + retval = lib_strdup(current_dir); } active = 0; break; @@ -495,7 +495,7 @@ char* sdl_ui_file_selection_dialog(const char* title, ui_menu_filereq_mode_t mod char *selected_file = directory->files[offset + cur - dirs - SDL_FILEREQ_META_NUM].name; if (mode == FILEREQ_MODE_CHOOSE_FILE) { lib_free(last_selected_file); - last_selected_file = lib_stralloc(selected_file); + last_selected_file = lib_strdup(selected_file); } retval = util_concat(current_dir, FSDEV_DIR_SEP_STR, selected_file, NULL); active = 0; @@ -609,13 +609,13 @@ char* sdl_ui_slot_selection_dialog(const char* title, ui_menu_slot_mode_t mode) slots = lib_malloc(sizeof(ui_menu_slots)); slots->entries = lib_malloc(sizeof(ui_menu_slot_entry) * total); - progname = archdep_program_name(); + progname = (char *)archdep_program_name(); /* 3.10 returns const char *; this SDL-UI path is dead in RD (MTEngineSDL is the active UI), preserve the legacy mutation/free behavior with a cast. */ temp_name = strchr(progname, FSDEV_EXT_SEP_CHR); if (temp_name) { *temp_name = 0; } for (i = 0; i < total; ++i) { - unsigned int len; + size_t len; unsigned int isdir; slots->entries[i].slot_name = lib_msprintf("snapshot_%s_%02d.vsf", progname, i + 1); diff --git a/src/Emulators/vice/arch/uimenu.c b/src/Emulators/vice/arch/uimenu.c index 858360a7..55480fa8 100644 --- a/src/Emulators/vice/arch/uimenu.c +++ b/src/Emulators/vice/arch/uimenu.c @@ -995,7 +995,7 @@ char* sdl_ui_readline(const char* previous, int pos_x, int pos_y) // pc_vkbd_state = archdep_require_vkbd(); // // if (previous) { -// new_string = lib_stralloc(previous); +// new_string = lib_strdup(previous); // size = strlen(new_string) + 1; // if (size < max) { // new_string = lib_realloc(new_string, max); diff --git a/src/Emulators/vice/arch/uimon.c b/src/Emulators/vice/arch/uimon.c index 762cfca3..ad3b4289 100644 --- a/src/Emulators/vice/arch/uimon.c +++ b/src/Emulators/vice/arch/uimon.c @@ -37,6 +37,7 @@ #include "uimenu.h" #include "log.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" static console_t mon_console = { 40, @@ -57,7 +58,7 @@ void uimon_window_close(void) console_t c64d_console_log = { 80, 25, 1, 0 }; -console_t *uimon_window_open(void) +console_t *uimon_window_open(bool display_now) /* VICE 3.10: + display_now */ { return &c64d_console_log; @@ -78,7 +79,7 @@ void uimon_window_suspend(void) console_t *uimon_window_resume(void) { - return uimon_window_open(); + return uimon_window_open(true); } int uimon_out(const char *buffer) @@ -95,7 +96,7 @@ int uimon_out(const char *buffer) p[i] = 0; //sdl_ui_print(p, x_pos, y); //sdl_ui_scroll_screen_up(); - c64d_uimon_print_line(p); + VICE_HOOK_LIFECYCLE_UIMON_LINE(p); //x_pos = 0; p += i + 1; @@ -107,7 +108,7 @@ int uimon_out(const char *buffer) if (p[0] != 0) { //x_pos += sdl_ui_print(p, x_pos, y); - c64d_uimon_print(p); + VICE_HOOK_LIFECYCLE_UIMON_PRINT(p); } return 0; } @@ -125,7 +126,7 @@ char *uimon_get_in(char **ppchCommandLine, const char *prompt) sdl_ui_scroll_screen_up(); if (input == NULL) { - input = lib_stralloc("x"); + input = lib_strdup("x"); } return input; diff --git a/src/Emulators/vice/arch/uimsgbox.c b/src/Emulators/vice/arch/uimsgbox.c index dd7dd763..40acdc28 100644 --- a/src/Emulators/vice/arch/uimsgbox.c +++ b/src/Emulators/vice/arch/uimsgbox.c @@ -42,6 +42,7 @@ #include "log.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" #define MAX_MSGBOX_LEN 28 @@ -88,7 +89,7 @@ static int handle_message_box(const char *title, const char *message, int messag int x; int cur_pos = 0; - text = lib_stralloc(message); + text = lib_strdup(message); pos = text; /* split the message up into a max of 28 char sized lines and remember the amount of lines */ @@ -97,7 +98,7 @@ static int handle_message_box(const char *title, const char *message, int messag /* print the top edge of the dialog. */ sdl_ui_print_center("\260\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\256", 2); - template = lib_stralloc("\335 \335"); + template = lib_strdup("\335 \335"); /* make sure that the title length is not more than 28 chars. */ len = strlen(title); @@ -117,7 +118,7 @@ static int handle_message_box(const char *title, const char *message, int messag sdl_ui_print_center("\253\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\300\263", 4); for (j = 0; j < lines; j++) { - template = lib_stralloc("\335 \335"); + template = lib_strdup("\335 \335"); /* make sure that the message line length is not more than 28 chars. */ len = strlen(pos); @@ -254,7 +255,7 @@ int message_box(const char *title, char *message, int message_mode) { LOGError("message_box: %s %s", title, message); - c64d_show_message(message); + VICE_HOOK_LIFECYCLE_MESSAGE(message); return -1; // sdl_ui_init_draw_params(); diff --git a/src/Emulators/vice/arch/uistatusbar.c b/src/Emulators/vice/arch/uistatusbar.c index b7c0b251..d2b7def4 100644 --- a/src/Emulators/vice/arch/uistatusbar.c +++ b/src/Emulators/vice/arch/uistatusbar.c @@ -41,6 +41,7 @@ #include "log.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" /* ----------------------------------------------------------------- */ /* static functions/variables */ @@ -157,7 +158,7 @@ void ui_display_paused(int flag) /* uiapi.h */ /* Display a mesage without interrupting emulation */ -void ui_display_statustext(const char *text, int fade_out) +void ui_display_statustext(const char *text, bool fade_out) { #ifdef SDL_DEBUG fprintf(stderr, "%s: \"%s\", %i\n", __func__, text, fade_out); @@ -172,7 +173,7 @@ void ui_enable_drive_status(ui_drive_enable_t state, int *drive_led_color) for (drive_number = 0; drive_number < 4; ++drive_number) { if (drive_state & 1) { - ui_display_drive_led(drive_number, 0, 0); + ui_display_drive_led(drive_number, 0, 0, 0); } else { statusbar_text[STATUSBAR_DRIVE_POS + drive_number] = ' '; } @@ -184,7 +185,7 @@ void ui_enable_drive_status(ui_drive_enable_t state, int *drive_led_color) } } -void ui_display_drive_track(unsigned int drive_number, unsigned int drive_base, unsigned int half_track_number) +void ui_display_drive_track(unsigned int drive_number, unsigned int drive_base, unsigned int half_track_number, unsigned int disk_side) { unsigned int track_number = half_track_number / 2; @@ -218,9 +219,9 @@ void ui_display_drive_track(unsigned int drive_number, unsigned int drive_base, } /* The pwm value will vary between 0 and 1000. */ -void ui_display_drive_led(int drive_number, unsigned int pwm1, unsigned int led_pwm2) +void ui_display_drive_led(unsigned int drive_number, unsigned int drive_base, unsigned int pwm1, unsigned int led_pwm2) { - c64d_display_drive_led(drive_number, pwm1, led_pwm2); + VICE_HOOK_INPUT_DRIVE_LED(drive_number, pwm1, led_pwm2); /* char c; @@ -238,7 +239,7 @@ void ui_display_drive_led(int drive_number, unsigned int pwm1, unsigned int led_ }*/ } -void ui_display_drive_current_image(unsigned int drive_number, const char *image) +void ui_display_drive_current_image(unsigned int unit_number, unsigned int drive_number, const char *image) { #ifdef SDL_DEBUG fprintf(stderr, "%s\n", __func__); @@ -247,28 +248,28 @@ void ui_display_drive_current_image(unsigned int drive_number, const char *image /* Tape related UI */ -void ui_set_tape_status(int tape_status) +void ui_set_tape_status(int port, int tape_status) { tape_enabled = tape_status; display_tape(); } -void ui_display_tape_motor_status(int motor) +void ui_display_tape_motor_status(int port, int motor) { tape_motor = motor; display_tape(); } -void ui_display_tape_control_status(int control) +void ui_display_tape_control_status(int port, int control) { tape_control = control; display_tape(); } -void ui_display_tape_counter(int counter) +void ui_display_tape_counter(int port, int counter) { if (tape_counter != counter) { display_tape(); @@ -277,7 +278,7 @@ void ui_display_tape_counter(int counter) tape_counter = counter; } -void ui_display_tape_current_image(const char *image) +void ui_display_tape_current_image(int port, const char *image) { #ifdef SDL_DEBUG fprintf(stderr, "%s: %s\n", __func__, image); @@ -307,7 +308,7 @@ void ui_display_event_time(unsigned int current, unsigned int total) } /* Joystick UI */ -void ui_display_joyport(BYTE *joyport) +void ui_display_joyport(uint16_t *joyport) { #ifdef SDL_DEBUG fprintf(stderr, "%s: %02x %02x %02x %02x %02x\n", __func__, joyport[0], joyport[1], joyport[2], joyport[3], joyport[4]); diff --git a/src/Emulators/vice/arch/vicetypes.h b/src/Emulators/vice/arch/vicetypes.h index 4a23930e..8453d805 100644 --- a/src/Emulators/vice/arch/vicetypes.h +++ b/src/Emulators/vice/arch/vicetypes.h @@ -34,6 +34,13 @@ #include "vice_sdl.h" +/* VICE 3.10 reconciliation: 3.10 uses uint*_t and bool pervasively, and includes + / unconditionally in its types.h. Provide them here so every + file that includes vicetypes.h (the renamed types.h) sees them. The BYTE/WORD/DWORD + shims below remain for slajerek's ungated c64d_ code. */ +#include +#include + #ifndef BYTE //#ifdef WIN32_COMPILE typedef unsigned char BYTE; @@ -63,15 +70,34 @@ typedef signed int SDWORD; //#endif #endif -#ifdef LINUX -#include "stdint.h" -#include "inttypes.h" +#include /* VICE 3.10: PRIx64/PRIu64 for printing 64-bit CLOCK -- needed on all platforms, not just LINUX (was #ifdef LINUX in slajerek's 3.1) */ + +/* VICE 3.10: MSVC <2019 lacks PRIu64/PRIx64, which 3.10 uses to print CLOCK. Provide fallbacks (no-op where already defines them). */ +#ifndef PRIu64 +# ifdef _WIN32 +# define PRIu64 "llu" +# else +# define PRIu64 "lu" +# endif +#endif +#ifndef PRIx64 +# ifdef _WIN32 +# define PRIx64 "llx" +# else +# define PRIx64 "lx" +# endif #endif -typedef DWORD CLOCK; +typedef uint64_t CLOCK; /* VICE 3.10: CLOCK is 64-bit (was DWORD/32-bit); 3.10's + clock-overflow handling that replaced clkguard assumes this. */ /* Maximum value of a CLOCK. */ #define CLOCK_MAX (~((CLOCK)0)) +/* VICE 3.10: int<->ptr helper (RD already has int_to_void_ptr; 3.10 code uses + vice_int_to_ptr). intptr_t cast works for both 32/64-bit. */ +#define vice_int_to_ptr(x) ((void *)(intptr_t)(x)) +#define vice_uint_to_ptr(x) ((void *)(uintptr_t)(x)) /* VICE 3.10 */ + #ifdef _WIN64 #define vice_ptr_to_int(x) ((int)(long long)(x)) #define vice_ptr_to_uint(x) ((unsigned int)(unsigned long long)(x)) diff --git a/src/Emulators/vice/arch/video.c b/src/Emulators/vice/arch/video.c index 12fb52ac..49ea9ecb 100644 --- a/src/Emulators/vice/arch/video.c +++ b/src/Emulators/vice/arch/video.c @@ -46,7 +46,6 @@ #include "palette.h" #include "raster.h" #include "resources.h" -#include "translate.h" #include "uimenu.h" #include "uistatusbar.h" #include "util.h" @@ -56,6 +55,7 @@ #include "vsync.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" #ifdef SDL_DEBUG #define DBG(x) log_debug x @@ -63,7 +63,7 @@ #define DBG(x) #endif -static log_t sdlvideo_log = LOG_ERR; +static log_t sdlvideo_log = LOG_DEFAULT; static int sdl_bitdepth; @@ -206,7 +206,7 @@ static int set_sdl_gl_aspect_mode(int v, void *param) sdl_gl_aspect_mode = v; if (old_v != v) { - if (sdl_active_canvas && sdl_active_canvas->videoconfig->hwscale) { + if (sdl_active_canvas) { /* VICE 3.10: hwscale removed (always hardware-scaled) */ video_viewport_resize(sdl_active_canvas, 1); } } @@ -242,7 +242,7 @@ static int set_aspect_ratio(const char *val, void *param) util_string_set(&aspect_ratio_s, buf); if (old_aspect != aspect_ratio) { - if (sdl_active_canvas && sdl_active_canvas->videoconfig->hwscale) { + if (sdl_active_canvas) { /* VICE 3.10: hwscale removed (always hardware-scaled) */ video_viewport_resize(sdl_active_canvas, 1); } } @@ -332,37 +332,17 @@ void video_arch_resources_shutdown(void) /* Video-related command-line options. */ static const cmdline_option_t cmdline_options[] = { - { "-sdlbitdepth", SET_RESOURCE, 1, NULL, NULL, "SDLBitdepth", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set bitdepth (0 = current, 8, 15, 16, 24, 32)" }, - { "-sdllimitmode", SET_RESOURCE, 1, NULL, NULL, "SDLLimitMode", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set resolution limiting mode (0 = off, 1 = max, 2 = fixed)" }, - { "-sdlcustomw", SET_RESOURCE, 1, NULL, NULL, "SDLCustomWidth", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set custom resolution width" }, - { "-sdlcustomh", SET_RESOURCE, 1, NULL, NULL, "SDLCustomHeight", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set custom resolution height" }, + { "-sdlbitdepth", SET_RESOURCE, 1, NULL, NULL, "SDLBitdepth", NULL, "", "Set bitdepth (0 = current, 8, 15, 16, 24, 32)"}, + { "-sdllimitmode", SET_RESOURCE, 1, NULL, NULL, "SDLLimitMode", NULL, "", "Set resolution limiting mode (0 = off, 1 = max, 2 = fixed)"}, + { "-sdlcustomw", SET_RESOURCE, 1, NULL, NULL, "SDLCustomWidth", NULL, "", "Set custom resolution width"}, + { "-sdlcustomh", SET_RESOURCE, 1, NULL, NULL, "SDLCustomHeight", NULL, "", "Set custom resolution height"}, #ifdef HAVE_HWSCALE - { "-sdlaspectmode", SET_RESOURCE, 1, NULL, NULL, "SDLGLAspectMode", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set aspect ratio mode (0 = off, 1 = custom, 2 = true)" }, - { "-aspect", SET_RESOURCE, 1, NULL, NULL, "AspectRatio", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - "", "Set custom aspect ratio (0.5 - 2.0)" }, - { "-sdlflipx", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipX", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - NULL, "Enable X flip" }, - { "+sdlflipx", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipX", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - NULL, "Disable X flip" }, - { "-sdlflipy", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipY", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - NULL, "Enable Y flip" }, - { "+sdlflipy", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipY", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_STRING, IDCLS_UNUSED, IDCLS_UNUSED, - NULL, "Disable Y flip" }, + { "-sdlaspectmode", SET_RESOURCE, 1, NULL, NULL, "SDLGLAspectMode", NULL, "", "Set aspect ratio mode (0 = off, 1 = custom, 2 = true)"}, + { "-aspect", SET_RESOURCE, 1, NULL, NULL, "AspectRatio", NULL, "", "Set custom aspect ratio (0.5 - 2.0)"}, + { "-sdlflipx", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipX", (resource_value_t)1, NULL, "Enable X flip"}, + { "+sdlflipx", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipX", (resource_value_t)0, NULL, "Disable X flip"}, + { "-sdlflipy", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipY", (resource_value_t)1, NULL, "Enable Y flip"}, + { "+sdlflipy", SET_RESOURCE, 0, NULL, NULL, "SDLGLFlipY", (resource_value_t)0, NULL, "Disable Y flip"}, #endif CMDLINE_LIST_END }; @@ -729,7 +709,7 @@ void video_canvas_refresh(struct video_canvas_s *canvas, unsigned int xs, unsign // draw directly from c64 screen // from: canvas->draw_buffer->draw_buffer - c64d_refresh_screen(); + VICE_HOOK_VIC_REFRESH_SCREEN(); // if ((canvas == NULL) || (canvas->screen == NULL)) { diff --git a/src/Emulators/vice/arch/videoarch.h b/src/Emulators/vice/arch/videoarch.h index bb444eac..9f5ebaed 100644 --- a/src/Emulators/vice/arch/videoarch.h +++ b/src/Emulators/vice/arch/videoarch.h @@ -35,6 +35,8 @@ #include "viewport.h" #include "video.h" +#include "archdep.h" /* VICE 3.10: ARCHDEP_SHOW_STATUSBAR_FACTORY etc. */ +#include "archdep_tick.h" /* VICE 3.10: tick_t (warp_next_render_tick) */ #define MAX_CANVAS_NUM 2 @@ -44,6 +46,10 @@ struct video_canvas_s { unsigned int initialized; unsigned int created; + /* VICE 3.10: warp-mode render pacing (vsync.c) + CRT/color-encoding type (video-canvas.c) */ + tick_t warp_next_render_tick; + int crt_type; + /* Index of the canvas, needed for x128 and xcbm2 */ int index; unsigned int depth; diff --git a/src/Emulators/vice/arch/vsyncarch.c b/src/Emulators/vice/arch/vsyncarch.c index bf3a6ad8..89834445 100644 --- a/src/Emulators/vice/arch/vsyncarch.c +++ b/src/Emulators/vice/arch/vsyncarch.c @@ -44,6 +44,7 @@ #include "vice_sdl.h" #include "log.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" /* ------------------------------------------------------------------------- */ @@ -79,7 +80,7 @@ void vsyncarch_display_speed(double speed, double frame_rate, int warp_enabled) { //LOGD("vsyncarch_display_speed, speed=%f frame_rate=%f warp_enabled=%d", speed, frame_rate, warp_enabled); - c64d_display_speed((float)speed, (float)frame_rate); + VICE_HOOK_LIFECYCLE_SPEED((float)speed, (float)frame_rate); // ui_display_speed((float)speed, (float)frame_rate, warp_enabled); } diff --git a/src/Emulators/vice/c64/c64-cmdline-options.c b/src/Emulators/vice/c64/c64-cmdline-options.c index 0fe76895..05798ed1 100644 --- a/src/Emulators/vice/c64/c64-cmdline-options.c +++ b/src/Emulators/vice/c64/c64-cmdline-options.c @@ -39,12 +39,10 @@ #include "cmdline.h" #include "log.h" #include "machine.h" -#include "patchrom.h" #include "resources.h" -#include "translate.h" #include "vicii.h" -int set_cia_model(const char *value, void *extra_param) +static int set_cia_model(const char *value, void *extra_param) { int model; @@ -158,21 +156,24 @@ struct kernal_s { int rev; }; +/* NOTE: this table is duplicated in psid.c */ static struct kernal_s kernal_match[] = { - { "1", C64_KERNAL_REV1 }, - { "2", C64_KERNAL_REV2 }, - { "3", C64_KERNAL_REV3 }, - { "67", C64_KERNAL_SX64 }, - { "sx", C64_KERNAL_SX64 }, - { "100", C64_KERNAL_4064 }, + { "0", C64_KERNAL_JAP }, + { "jap", C64_KERNAL_JAP }, + { "1", C64_KERNAL_REV1 }, + { "2", C64_KERNAL_REV2 }, + { "3", C64_KERNAL_REV3 }, + { "67", C64_KERNAL_SX64 }, + { "sx", C64_KERNAL_SX64 }, + { "39", C64_KERNAL_GS64 }, + { "gs", C64_KERNAL_GS64 }, + { "100", C64_KERNAL_4064 }, { "4064", C64_KERNAL_4064 }, { NULL, C64_KERNAL_UNKNOWN } }; static int set_kernal_revision(const char *param, void *extra_param) { - WORD sum; /* ROM checksum */ - int id; /* ROM identification number */ int rev = C64_KERNAL_UNKNOWN; int i = 0; @@ -187,107 +188,81 @@ static int set_kernal_revision(const char *param, void *extra_param) i++; } while ((rev == C64_KERNAL_UNKNOWN) && (kernal_match[i].name != NULL)); - if(!c64rom_isloaded()) { - kernal_revision = rev; - return 0; + log_verbose(LOG_DEFAULT, "set_kernal_revision (\"-kernalrev\") val:'%s' rev: %d", param, rev); + + if (rev == C64_KERNAL_UNKNOWN) { + log_error(LOG_DEFAULT, "invalid kernal revision (%d)", rev); + return -1; } - if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) { - id = C64_KERNAL_UNKNOWN; - kernal_revision = id; - } else { - if (patch_rom_idx(rev) >= 0) { - kernal_revision = rev; - } else { - kernal_revision = id; - } + if (resources_set_int("KernalRev", rev) < 0) { + log_error(LOG_DEFAULT, "failed to set kernal revision (%d)", rev); } + return 0; } -static const cmdline_option_t cmdline_options[] = { - { "-pal", CALL_FUNCTION, 0, - set_video_standard, (void *)MACHINE_SYNC_PAL, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_PAL_SYNC_FACTOR, - NULL, NULL }, - { "-ntsc", CALL_FUNCTION, 0, - set_video_standard, (void *)MACHINE_SYNC_NTSC, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_NTSC_SYNC_FACTOR, - NULL, NULL }, - { "-ntscold", CALL_FUNCTION, 0, - set_video_standard, (void *)MACHINE_SYNC_NTSCOLD, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_OLD_NTSC_SYNC_FACTOR, - NULL, NULL }, - { "-paln", CALL_FUNCTION, 0, - set_video_standard, (void *)MACHINE_SYNC_PALN, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_PALN_SYNC_FACTOR, - NULL, NULL }, - { "-kernal", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + /* NOTE: although we use CALL_FUNCTION, we put the resource that will be + modified into the array - this helps reconstructing the cmdline */ + { "-pal", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, + set_video_standard, (void *)MACHINE_SYNC_PAL, "MachineVideoStandard", (void *)MACHINE_SYNC_PAL, + NULL, "Use PAL sync factor" }, + { "-ntsc", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, + set_video_standard, (void *)MACHINE_SYNC_NTSC, "MachineVideoStandard", (void *)MACHINE_SYNC_NTSC, + NULL, "Use NTSC sync factor" }, + { "-ntscold", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, + set_video_standard, (void *)MACHINE_SYNC_NTSCOLD, "MachineVideoStandard", (void *)MACHINE_SYNC_NTSCOLD, + NULL, "Use old NTSC sync factor" }, + { "-paln", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, + set_video_standard, (void *)MACHINE_SYNC_PALN, "MachineVideoStandard", (void *)MACHINE_SYNC_PALN, + NULL, "Use PAL-N sync factor" }, + { "-power50", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MachinePowerFrequency", (void *)50, + NULL, "Use 50Hz Power-grid frequency" }, + { "-power60", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MachinePowerFrequency", (void *)60, + NULL, "Use 60Hz Power-grid frequency" }, + { "-kernal", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KernalName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_KERNAL_ROM_NAME, - NULL, NULL }, - { "-basic", SET_RESOURCE, 1, + "", "Specify name of Kernal ROM image" }, + { "-basic", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "BasicName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_BASIC_ROM_NAME, - NULL, NULL }, - { "-chargen", SET_RESOURCE, 1, + "", "Specify name of BASIC ROM image" }, + { "-chargen", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ChargenName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_CHARGEN_ROM_NAME, - NULL, NULL }, - { "-kernalrev", CALL_FUNCTION, 1, + "", "Specify name of character generator ROM image" }, + { "-kernalrev", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, set_kernal_revision, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_REVISION, IDCLS_PATCH_KERNAL_TO_REVISION, - NULL, NULL }, + "", "Patch the Kernal ROM to the specified " + "(0/jap: japanese 1: rev. 1, 2: rev. 2, 3: rev. 3, 39/gs: C64 GS, 67/sx: sx64, 100/4064: 4064)" }, #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - { "-acia1", SET_RESOURCE, 0, + { "-acia1", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "Acia1Enable", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DEXX_ACIA_RS232_EMU, - NULL, NULL }, - { "+acia1", SET_RESOURCE, 0, + NULL, "Enable the ACIA RS232 interface emulation" }, + { "+acia1", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "Acia1Enable", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DEXX_ACIA_RS232_EMU, - NULL, NULL }, + NULL, "Disable the ACIA RS232 interface emulation" }, #endif - { "-ciamodel", CALL_FUNCTION, 1, + { "-ciamodel", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, set_cia_model, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODEL, IDCLS_SET_BOTH_CIA_MODELS, - NULL, NULL }, - { "-cia1model", SET_RESOURCE, 1, + "", "Set both CIA models (0 = old 6526, 1 = new 8521)" }, + { "-cia1model", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "CIA1Model", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODEL, IDCLS_SET_CIA1_MODEL, - NULL, NULL }, - { "-cia2model", SET_RESOURCE, 1, + "", "Set CIA 1 model (0 = old 6526, 1 = new 8521)" }, + { "-cia2model", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "CIA2Model", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODEL, IDCLS_SET_CIA2_MODEL, - NULL, NULL }, - { "-model", CALL_FUNCTION, 1, + "", "Set CIA 2 model (0 = old 6526, 1 = new 8521)" }, + { "-model", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, set_c64_model, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODEL, IDCLS_SET_C64_MODEL, - NULL, NULL }, - { "-burstmod", SET_RESOURCE, 1, + "", "Set C64 model (c64/c64c/c64old, ntsc/newntsc/oldntsc, drean, jap, c64gs, pet64, ultimax)" }, + { "-burstmod", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "BurstMod", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_BURST_MOD, - NULL, NULL }, - { "-iecreset", SET_RESOURCE, 1, + "", "Burst modification (0 = None, 1 = CIA1, 2 = CIA2)" }, + { "-iecreset", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IECReset", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_IEC_RESET, - NULL, NULL }, + "", "Computer reset goes to IEC bus (0 = No, 1 = Yes)" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/c64/c64-cmdline-options.h b/src/Emulators/vice/c64/c64-cmdline-options.h index 9f23d741..d192f624 100644 --- a/src/Emulators/vice/c64/c64-cmdline-options.h +++ b/src/Emulators/vice/c64/c64-cmdline-options.h @@ -27,6 +27,6 @@ #ifndef VICE_C64_CMDLINE_OPTIONS_H #define VICE_C64_CMDLINE_OPTIONS_H -extern int c64_cmdline_options_init(void); +int c64_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/c64/c64-memory-hacks.c b/src/Emulators/vice/c64/c64-memory-hacks.c index fbcf899d..a6748976 100644 --- a/src/Emulators/vice/c64/c64-memory-hacks.c +++ b/src/Emulators/vice/c64/c64-memory-hacks.c @@ -38,17 +38,29 @@ #include "plus60k.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" +#include "ui.h" static int memory_hack = 0; +/** \brief Set memory hack + * + * Pauses emulation when switching to another memory expansion hack to avoid + * having a running CPU access invalid memory. Unpauses emulation if the + * emulation wasn't already paused before switching memory expansion. + * + * \param[in] value memory hack ID + * \param[in] param extra data (unused) + * + * \return 0 on succes, -1 on failure + */ static int set_memory_hack(int value, void *param) { if (value == memory_hack) { return 0; } + /* check if the new memory hack is a valid one */ switch (value) { case MEMORY_HACK_NONE: case MEMORY_HACK_C64_256K: @@ -59,6 +71,7 @@ static int set_memory_hack(int value, void *param) return -1; } + /* disable already active memory hack */ switch (memory_hack) { case MEMORY_HACK_C64_256K: set_c64_256k_enabled(0, 0); @@ -74,6 +87,7 @@ static int set_memory_hack(int value, void *param) break; } + /* enable new memory hack */ switch (value) { case MEMORY_HACK_C64_256K: set_c64_256k_enabled(1, 0); @@ -96,6 +110,26 @@ static int set_memory_hack(int value, void *param) return 0; } +int memory_hacks_ram_inject(uint16_t addr, uint8_t value) +{ + switch (memory_hack) { + case MEMORY_HACK_C64_256K: + c64_256k_ram_inject(addr, value); + break; + case MEMORY_HACK_PLUS60K: + plus60k_ram_inject(addr, value); + break; + case MEMORY_HACK_PLUS256K: + plus256k_ram_inject(addr, value); + break; + case MEMORY_HACK_NONE: + default: + return 0; + break; + } + return 1; +} + static const resource_int_t resources_int[] = { { "MemoryHack", MEMORY_HACK_NONE, RES_EVENT_STRICT, (resource_value_t)0, &memory_hack, set_memory_hack, NULL }, @@ -111,11 +145,9 @@ int memory_hacks_resources_init(void) static const cmdline_option_t cmdline_options[] = { - { "-memoryexphack", SET_RESOURCE, 1, + { "-memoryexphack", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MemoryHack", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_DEVICE, IDCLS_SET_C64_MEMORY_HACK, - NULL, NULL }, + "", "Set the 'memory expansion hack' device (0: None, 1: C64 256K, 2: +60K, 3: +256K)" }, CMDLINE_LIST_END }; @@ -147,7 +179,7 @@ int memhacks_snapshot_write_modules(struct snapshot_s *s) return -1; } - if (SMW_B(m, (BYTE)memory_hack) < 0) { + if (SMW_B(m, (uint8_t)memory_hack) < 0) { snapshot_module_close(m); return -1; } @@ -179,7 +211,7 @@ int memhacks_snapshot_write_modules(struct snapshot_s *s) int memhacks_snapshot_read_modules(struct snapshot_s *s) { snapshot_module_t *m; - BYTE vmajor, vminor; + uint8_t vmajor, vminor; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -188,7 +220,7 @@ int memhacks_snapshot_read_modules(struct snapshot_s *s) } /* do not accept higher versions than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -236,7 +268,7 @@ int memhacks_snapshot_read_modules(struct snapshot_s *s) } return 0; - + fail: if (m != NULL) { snapshot_module_close(m); diff --git a/src/Emulators/vice/c64/c64-memory-hacks.h b/src/Emulators/vice/c64/c64-memory-hacks.h index fda476b6..a9c2e844 100644 --- a/src/Emulators/vice/c64/c64-memory-hacks.h +++ b/src/Emulators/vice/c64/c64-memory-hacks.h @@ -30,15 +30,19 @@ #include "snapshot.h" #include "vicetypes.h" -#define MEMORY_HACK_NONE 0 -#define MEMORY_HACK_C64_256K 1 -#define MEMORY_HACK_PLUS60K 2 -#define MEMORY_HACK_PLUS256K 3 +enum { + MEMORY_HACK_NONE = 0, + MEMORY_HACK_C64_256K, + MEMORY_HACK_PLUS60K, + MEMORY_HACK_PLUS256K +}; -extern int memory_hacks_resources_init(void); -extern int memory_hacks_cmdline_options_init(void); +int memory_hacks_ram_inject(uint16_t addr, uint8_t value); -extern int memhacks_snapshot_write_modules(struct snapshot_s *s); -extern int memhacks_snapshot_read_modules(struct snapshot_s *s); +int memory_hacks_resources_init(void); +int memory_hacks_cmdline_options_init(void); + +int memhacks_snapshot_write_modules(struct snapshot_s *s); +int memhacks_snapshot_read_modules(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/c64-resources.c b/src/Emulators/vice/c64/c64-resources.c index fdad1d79..63391b0d 100644 --- a/src/Emulators/vice/c64/c64-resources.c +++ b/src/Emulators/vice/c64/c64-resources.c @@ -36,13 +36,13 @@ #include "c64rom.h" #include "c64memrom.h" #include "c64mem.h" +#include "c64model.h" #include "cartio.h" #include "cartridge.h" #include "cia.h" #include "lib.h" #include "log.h" #include "machine.h" -#include "patchrom.h" #include "resources.h" #include "reu.h" #include "georam.h" @@ -56,7 +56,10 @@ `MACHINE_SYNC_PAL', the same as PAL machines. If equal to `MACHINE_SYNC_NTSC', the same as NTSC machines. The sync factor is calculated as 65536 * drive_clk / clk_[main machine] */ -static int sync_factor; +static int sync_factor = -1; + +/* Frequency of the power grid in Hz */ +static int power_freq = -1; /* Name of the character ROM. */ static char *chargen_rom_name = NULL; @@ -73,9 +76,11 @@ int kernal_revision = C64_KERNAL_REV3; int cia1_model; int cia2_model; -static int board_type = 0; +int board_type = BOARD_C64; static int iec_reset = 0; +static log_t res_log = LOG_DEFAULT; + static int set_chargen_rom_name(const char *val, void *param) { if (util_string_set(&chargen_rom_name, val)) { @@ -87,8 +92,12 @@ static int set_chargen_rom_name(const char *val, void *param) static int set_kernal_rom_name(const char *val, void *param) { - int ret, changed = 1; - log_verbose("set_kernal_rom_name val:%s.", val); + int ret; + /* CAUTION: make sure to only trigger a power cycle when the name changed + AND it was not null before (in that case we are setting the + default value) */ + int changed = 0; + log_verbose(res_log, "set_kernal_rom_name val:%s.", val); if ((val != NULL) && (kernal_rom_name != NULL)) { changed = (strcmp(val, kernal_rom_name) != 0); } @@ -98,14 +107,18 @@ static int set_kernal_rom_name(const char *val, void *param) /* load kernal without a kernal overriding buffer */ ret = c64rom_load_kernal(kernal_rom_name, NULL); if (changed) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } return ret; } static int set_basic_rom_name(const char *val, void *param) { - int ret, changed = 1; + int ret; + /* CAUTION: make sure to only trigger a power cycle when the name changed + AND it was not null before (in that case we are setting the + default value) */ + int changed = 0; if ((val != NULL) && (basic_rom_name != NULL)) { changed = (strcmp(val, basic_rom_name) != 0); } @@ -114,7 +127,7 @@ static int set_basic_rom_name(const char *val, void *param) } ret = c64rom_load_basic(basic_rom_name); if (changed) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } return ret; } @@ -122,12 +135,12 @@ static int set_basic_rom_name(const char *val, void *param) static int set_board_type(int val, void *param) { int old_board_type = board_type; - if ((val < 0) || (val > 1)) { + if ((val < 0) || (val > BOARD_LAST_C64)) { return -1; } board_type = val; if (old_board_type != board_type) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } return 0; } @@ -178,33 +191,129 @@ static int set_cia2_model(int val, void *param) return 0; } -static int set_kernal_revision(int val, void *param) +#define NUM_TRAP_DEVICES 9 /* FIXME: is there a better constant ? */ +static const int trapdevices[NUM_TRAP_DEVICES + 1] = { 1, 4, 5, 6, 7, 8, 9, 10, 11, -1 }; + +static unsigned int get_trapflags(void) { + int i; + /*int val = 0;*/ + int ret = 0; int trapfl; + for(i = 0; trapdevices[i] != -1; i++) { + resources_get_int_sprintf("TrapDevice%d", &trapfl, trapdevices[i]); + /*val |= trapfl;*/ + if (trapfl) { + ret |= (1 << i); + } + } + /*printf("get_trapflags(%d)\n", val);*/ + return ret; +} + +static void clear_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_set_int_sprintf("TrapDevice%d", 0, trapdevices[i]); + } + /*printf("clear_trapflags\n");*/ +} + +static void restore_trapflags(unsigned int flags) +{ + int i; + /*int val = 0;*/ + int trapfl; + for(i = 0; trapdevices[i] != -1; i++) { + trapfl = (flags & (1 << i)) ? 1 : 0; + resources_set_int_sprintf("TrapDevice%d", trapfl, trapdevices[i]); + /*val |= trapfl;*/ + } + /*printf("restore_trapflags(%d)\n", val);*/ +} + +struct kernal_s { + const char *name; + int rev; +}; + +/* NOTE: also update the table in c64rom.c */ +static struct kernal_s kernal_match[] = { + { C64_KERNAL_REV1_NAME, C64_KERNAL_REV1 }, + { C64_KERNAL_REV2_NAME, C64_KERNAL_REV2 }, + { C64_KERNAL_REV3_NAME, C64_KERNAL_REV3 }, + { C64_KERNAL_JAP_NAME, C64_KERNAL_JAP }, + { C64_KERNAL_SX64_NAME, C64_KERNAL_SX64 }, + { C64_KERNAL_GS64_NAME, C64_KERNAL_GS64 }, + { C64_KERNAL_4064_NAME, C64_KERNAL_4064 }, + { C64_KERNAL_NONE_NAME, C64_KERNAL_NONE }, + { NULL, C64_KERNAL_UNKNOWN } +}; + +static int set_kernal_revision(int val, void *param) +{ + int n = 0, rev = C64_KERNAL_UNKNOWN; + const char *name = NULL; + int flags; - log_verbose("set_kernal_revision val:%d kernal_revision: %d", val, kernal_revision); - if(!c64rom_isloaded()) { + log_verbose(res_log, "set_kernal_revision(val:%d) was kernal_revision: %d", val, kernal_revision); + + flags = get_trapflags(); + + /* if the new type is "unknown", only remove the traps */ + if (val == C64_KERNAL_UNKNOWN) { + if(c64rom_isloaded()) { + /* disable device traps before kernal patching */ + if (machine_class != VICE_MACHINE_VSID) { + clear_trapflags(); + } + } + kernal_revision = C64_KERNAL_UNKNOWN; + restore_trapflags(flags); return 0; } - /* disable device traps before kernal patching */ - if (machine_class != VICE_MACHINE_VSID) { - resources_get_int("VirtualDevices", &trapfl); - resources_set_int("VirtualDevices", 0); + + /* find given revision */ + do { + if (kernal_match[n].rev == val) { + rev = kernal_match[n].rev; + name = kernal_match[n].name; + } + ++n; + } while ((rev == C64_KERNAL_UNKNOWN) && (kernal_match[n].name != NULL)); + + if (rev == C64_KERNAL_UNKNOWN) { + log_error(res_log, "invalid kernal revision (%d)", val); + return -1; + } + + if(c64rom_isloaded()) { + /* disable device traps before kernal patching */ + if (machine_class != VICE_MACHINE_VSID) { + clear_trapflags(); + } } - /* patch kernal to given revision */ - if ((val != -1) && (patch_rom_idx(val) < 0)) { - val = -1; + + log_verbose(res_log, "set_kernal_revision found rev:%d name: %s", rev, name); + + if (resources_set_string("KernalName", name) < 0) { + log_error(res_log, "failed to set kernal name (%s)", name); + restore_trapflags(flags); + return -1; } + memcpy(c64memrom_kernal64_trap_rom, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE); - if (kernal_revision != val) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + + if (kernal_revision != rev) { + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } /* restore traps */ if (machine_class != VICE_MACHINE_VSID) { - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(flags); } - kernal_revision = val; - log_verbose("set_kernal_revision new kernal_revision: %d", kernal_revision); + kernal_revision = rev; + log_verbose(res_log, "set_kernal_revision new kernal_revision: %d", kernal_revision); return 0; } @@ -218,44 +327,58 @@ static int set_sync_factor(int val, void *param) switch (val) { case MACHINE_SYNC_PAL: - sync_factor = val; - if (change_timing) { - machine_change_timing(MACHINE_SYNC_PAL, vicii_resources.border_mode); - } - break; + case MACHINE_SYNC_PALN: case MACHINE_SYNC_NTSC: - sync_factor = val; - if (change_timing) { - machine_change_timing(MACHINE_SYNC_NTSC, vicii_resources.border_mode); - } - break; case MACHINE_SYNC_NTSCOLD: - sync_factor = val; - if (change_timing) { - machine_change_timing(MACHINE_SYNC_NTSCOLD, vicii_resources.border_mode); - } break; - case MACHINE_SYNC_PALN: - sync_factor = val; - if (change_timing) { - machine_change_timing(MACHINE_SYNC_PALN, vicii_resources.border_mode); - } + default: + return -1; + } + sync_factor = val; + if (change_timing) { + vicii_comply_with_video_standard(val); + if (power_freq > 0) { + machine_change_timing(val, power_freq, vicii_resources.border_mode); + } + } + + return 0; +} + +static int set_power_freq(int val, void *param) +{ + int change_timing = 0; + + if (power_freq != val) { + change_timing = 1; + } + + switch (val) { + case 50: + case 60: break; default: return -1; } + power_freq = val; + if (change_timing) { + /*vicii_comply_with_video_standard(sync_factor);*/ + if (sync_factor > 0) { + machine_change_timing(sync_factor, val, vicii_resources.border_mode); + } + } return 0; } static const resource_string_t resources_string[] = { - { "ChargenName", "chargen", RES_EVENT_NO, NULL, + { "ChargenName", C64_CHARGEN_NAME, RES_EVENT_NO, NULL, /* FIXME: should be same but names may differ */ &chargen_rom_name, set_chargen_rom_name, NULL }, - { "KernalName", "kernal", RES_EVENT_NO, NULL, + { "KernalName", C64_KERNAL_REV3_NAME, RES_EVENT_NO, NULL, /* FIXME: should be same but names may differ */ &kernal_rom_name, set_kernal_rom_name, NULL }, - { "BasicName", "basic", RES_EVENT_NO, NULL, + { "BasicName", C64_BASIC_NAME, RES_EVENT_NO, NULL, /* FIXME: should be same but names may differ */ &basic_rom_name, set_basic_rom_name, NULL }, RESOURCE_STRING_LIST_END @@ -264,7 +387,9 @@ static const resource_string_t resources_string[] = { static const resource_int_t resources_int[] = { { "MachineVideoStandard", MACHINE_SYNC_PAL, RES_EVENT_SAME, NULL, &sync_factor, set_sync_factor, NULL }, - { "BoardType", 0, RES_EVENT_SAME, NULL, + { "MachinePowerFrequency", 50, RES_EVENT_SAME, NULL, + &power_freq, set_power_freq, NULL }, + { "BoardType", BOARD_C64, RES_EVENT_SAME, NULL, &board_type, set_board_type, NULL }, { "IECReset", 0, RES_EVENT_SAME, NULL, &iec_reset, set_iec_reset, NULL }, @@ -274,10 +399,20 @@ static const resource_int_t resources_int[] = { &cia2_model, set_cia2_model, NULL }, { "KernalRev", C64_KERNAL_REV3, RES_EVENT_SAME, NULL, &kernal_revision, set_kernal_revision, NULL }, - { "SidStereoAddressStart", 0xde00, RES_EVENT_SAME, NULL, - (int *)&sid_stereo_address_start, sid_set_sid_stereo_address, NULL }, - { "SidTripleAddressStart", 0xdf00, RES_EVENT_SAME, NULL, - (int *)&sid_triple_address_start, sid_set_sid_triple_address, NULL }, + { "Sid2AddressStart", 0xde00, RES_EVENT_SAME, NULL, + (int *)&sid2_address_start, sid_set_sid2_address, NULL }, + { "Sid3AddressStart", 0xdf00, RES_EVENT_SAME, NULL, + (int *)&sid3_address_start, sid_set_sid3_address, NULL }, + { "Sid4AddressStart", 0xdf80, RES_EVENT_SAME, NULL, + (int *)&sid4_address_start, sid_set_sid4_address, NULL }, + { "Sid5AddressStart", 0xde80, RES_EVENT_SAME, NULL, + (int *)&sid5_address_start, sid_set_sid5_address, NULL }, + { "Sid6AddressStart", 0xdf40, RES_EVENT_SAME, NULL, + (int *)&sid6_address_start, sid_set_sid6_address, NULL }, + { "Sid7AddressStart", 0xde40, RES_EVENT_SAME, NULL, + (int *)&sid7_address_start, sid_set_sid7_address, NULL }, + { "Sid8AddressStart", 0xdfc0, RES_EVENT_SAME, NULL, + (int *)&sid8_address_start, sid_set_sid8_address, NULL }, { "BurstMod", BURST_MOD_NONE, RES_EVENT_NO, NULL, &burst_mod, set_burst_mod, NULL }, RESOURCE_INT_LIST_END @@ -291,6 +426,7 @@ void c64_resources_update_cia_models(int model) int c64_resources_init(void) { + res_log = log_open("C64RES"); if (resources_register_string(resources_string) < 0) { return -1; } diff --git a/src/Emulators/vice/c64/c64-resources.h b/src/Emulators/vice/c64/c64-resources.h index b1d79e28..455f9349 100644 --- a/src/Emulators/vice/c64/c64-resources.h +++ b/src/Emulators/vice/c64/c64-resources.h @@ -27,26 +27,13 @@ #ifndef VICE_C64_RESOURCES_H #define VICE_C64_RESOURCES_H -extern int c64_resources_init(void); -extern void c64_resources_shutdown(void); +int c64_resources_init(void); +void c64_resources_shutdown(void); -extern void c64_resources_update_cia_models(int model); +void c64_resources_update_cia_models(int model); extern int acia_de_enabled; -#define C64_KERNAL_UNKNOWN -1 -#define C64_KERNAL_REV1 1 /* 901227-01 */ -#define C64_KERNAL_REV2 2 /* 901227-02 */ -#define C64_KERNAL_REV3 3 /* 901227-03 */ -#define C64_KERNAL_SX64 67 /* 251104-04 */ -#define C64_KERNAL_4064 100 /* 901246-01 */ - -#define C64_KERNAL_JAP -1 /* FIXME */ -#define C64_KERNAL_GS64 -1 /* FIXME */ -#define C64_KERNAL_MAX -1 /* FIXME */ -#define C64_KERNAL_REV3SWE -1 /* FIXME */ -extern int kernal_revision; - extern int cia1_model; extern int cia2_model; diff --git a/src/Emulators/vice/c64/c64-snapshot.c b/src/Emulators/vice/c64/c64-snapshot.c index 99ebce6d..9e8c9f69 100644 --- a/src/Emulators/vice/c64/c64-snapshot.c +++ b/src/Emulators/vice/c64/c64-snapshot.c @@ -29,15 +29,15 @@ #include +#include "archdep.h" #include "c64-memory-hacks.h" -#include "c64-snapshot.h" #include "c64.h" #include "c64gluelogic.h" #include "c64memsnapshot.h" #include "cia.h" #include "drive-snapshot.h" #include "drive.h" -#include "ioutil.h" +#include "serial.h" #include "joyport.h" #include "joystick.h" #include "keyboard.h" @@ -53,11 +53,15 @@ #include "vice-event.h" #include "vicii.h" +#include "c64-snapshot.h" + +#ifdef RETRODEBUGGER int c64d_snapshot_write_module(snapshot_t *s, int save_screen); int c64d_snapshot_read_module(snapshot_t *s); +#endif -#define SNAP_MAJOR 1 -#define SNAP_MINOR 1 +#define SNAP_MAJOR 2 +#define SNAP_MINOR 0 int c64_snapshot_write(const char *name, int save_roms, int save_disks, int event_mode, int save_reu_data, int save_cart_roms, int save_screen) { @@ -65,7 +69,7 @@ int c64_snapshot_write(const char *name, int save_roms, int save_disks, int even LOGD("c64_snapshot_write: name=%s save_roms=%d save_disks=%d event_mode=%d save_reu_data=%d save_cart_roms=%d save_screen=%d", name, save_roms, save_disks, event_mode, save_reu_data, save_cart_roms, save_screen); - s = snapshot_create(name, ((BYTE)(SNAP_MAJOR)), ((BYTE)(SNAP_MINOR)), machine_get_name(), 0); + s = snapshot_create(name, ((uint8_t)(SNAP_MAJOR)), ((uint8_t)(SNAP_MINOR)), machine_get_name(), 0); if (s == NULL) { return -1; } @@ -81,6 +85,7 @@ int c64_snapshot_write(const char *name, int save_roms, int save_disks, int even || ciacore_snapshot_write_module(machine_context.cia2, s) < 0 || sid_snapshot_write_module(s) < 0 || drive_snapshot_write_module(s, save_disks, save_roms) < 0 + || fsdrive_snapshot_write_module(s) < 0 || vicii_snapshot_write_module(s) < 0 || c64_glue_snapshot_write_module(s) < 0 || event_snapshot_write_module(s, event_mode) < 0 @@ -90,10 +95,12 @@ int c64_snapshot_write(const char *name, int save_roms, int save_disks, int even || joyport_snapshot_write_module(s, JOYPORT_1) < 0 || joyport_snapshot_write_module(s, JOYPORT_2) < 0 || userport_snapshot_write_module(s) < 0 - || c64d_snapshot_write_module(s, save_screen) < 0) - { +#ifdef RETRODEBUGGER + || c64d_snapshot_write_module(s, save_screen) < 0 +#endif + ) { snapshot_close(s); - ioutil_remove(name); + archdep_remove(name); return -1; } @@ -101,6 +108,7 @@ int c64_snapshot_write(const char *name, int save_roms, int save_disks, int even return 0; } +#ifdef RETRODEBUGGER int c64_snapshot_write_in_memory(int save_chips, int save_roms, int save_disks, int event_mode, int save_reu_data, int save_cart_roms, int save_screen, int *snapshot_size, unsigned char **snapshot_data) { @@ -181,19 +189,20 @@ int c64_snapshot_write_in_memory(int save_chips, int save_roms, int save_disks, return 0; } +#endif /* RETRODEBUGGER */ int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_disks, int read_reu_data, int read_cart_roms) { snapshot_t *s; - BYTE minor, major; + uint8_t minor, major; s = snapshot_open(name, &major, &minor, machine_get_name()); if (s == NULL) { return -1; } - if (major != SNAP_MAJOR || minor != SNAP_MINOR) { + if (!snapshot_version_is_equal(major, minor, SNAP_MAJOR, SNAP_MINOR)) { log_error(LOG_DEFAULT, "Snapshot version (%d.%d) not valid: expecting %d.%d.", major, minor, SNAP_MAJOR, SNAP_MINOR); snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); goto fail; @@ -209,6 +218,7 @@ int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_ || ciacore_snapshot_read_module(machine_context.cia2, s) < 0 || sid_snapshot_read_module(s) < 0 || drive_snapshot_read_module(s, read_roms, read_disks) < 0 + || fsdrive_snapshot_read_module(s) < 0 || vicii_snapshot_read_module(s) < 0 || c64_glue_snapshot_read_module(s) < 0 || event_snapshot_read_module(s, event_mode) < 0 @@ -218,7 +228,10 @@ int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_ || joyport_snapshot_read_module(s, JOYPORT_1) < 0 || joyport_snapshot_read_module(s, JOYPORT_2) < 0 || userport_snapshot_read_module(s) < 0 - || c64d_snapshot_read_module(s) < 0) { +#ifdef RETRODEBUGGER + || c64d_snapshot_read_module(s) < 0 +#endif + ) { goto fail; } @@ -233,11 +246,12 @@ int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_ snapshot_close(s); } - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); return -1; } +#ifdef RETRODEBUGGER int c64_snapshot_read_from_memory(int read_chips, int read_roms, int read_disks, int event_mode, int read_reu_data, int read_cart_roms, unsigned char *snapshot_data, int snapshot_size) { @@ -289,7 +303,8 @@ int c64_snapshot_read_from_memory(int read_chips, int read_roms, int read_disks, snapshot_close(s); } - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); - + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); + return -1; } +#endif /* RETRODEBUGGER */ diff --git a/src/Emulators/vice/c64/c64-snapshot.h b/src/Emulators/vice/c64/c64-snapshot.h index fab2463b..45c2008e 100644 --- a/src/Emulators/vice/c64/c64-snapshot.h +++ b/src/Emulators/vice/c64/c64-snapshot.h @@ -27,8 +27,8 @@ #ifndef VICE_C64_SNAPSHOT_H #define VICE_C64_SNAPSHOT_H -extern int c64_snapshot_write(const char *name, int save_roms, int save_disks, int event_mode, int save_reu_data, int save_cart_roms, int save_screen); -extern int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_disks, int read_reu_data, int read_cart_roms); +int c64_snapshot_write(const char *name, int save_roms, int save_disks, int event_mode, int save_reu_data, int save_cart_roms, int save_screen); +int c64_snapshot_read(const char *name, int event_mode, int read_roms, int read_disks, int read_reu_data, int read_cart_roms); extern int c64_snapshot_read_from_memory(int save_chips, int read_roms, int read_disks, int event_mode, int read_reu_data, int read_cart_roms, unsigned char *snapshot_data, int snapshot_size); diff --git a/src/Emulators/vice/c64/c64.c b/src/Emulators/vice/c64/c64.c index f68bf8c7..12c2045c 100644 --- a/src/Emulators/vice/c64/c64.c +++ b/src/Emulators/vice/c64/c64.c @@ -55,17 +55,18 @@ #include "c64keyboard.h" #include "c64mem.h" #include "c64memrom.h" +#include "c64parallel.h" #include "c64rsuser.h" #include "cardkey.h" #include "cartio.h" #include "cartridge.h" #include "cia.h" -#include "clkguard.h" #include "clockport-mp3at64.h" #include "coplin_keypad.h" #include "cx21.h" #include "cx85.h" #include "datasette.h" +#include "datasette-sound.h" #include "debug.h" #include "diskimage.h" #include "drive-cmdline-options.h" @@ -74,11 +75,14 @@ #include "drive.h" #include "export.h" #include "fliplist.h" +#include "fmopl.h" #include "fsdevice.h" #include "gfxoutput.h" #include "imagecontents.h" +#include "inception.h" #include "init.h" #include "joyport.h" +#include "joyport_io_sim.h" #include "joystick.h" #include "kbdbuf.h" #include "keyboard.h" @@ -90,13 +94,18 @@ #include "maincpu.h" #include "mem.h" #include "monitor.h" +#include "multijoy.h" #include "network.h" +#include "ninja_snespad.h" #include "paperclip64.h" +#include "paperclip64e.h" +#include "paperclip64sc.h" +#include "paperclip2.h" #include "parallel.h" -#include "patchrom.h" #include "plus256k.h" #include "plus60k.h" #include "printer.h" +#include "protopad.h" #include "psid.h" #include "resources.h" #include "rs232drv.h" @@ -112,11 +121,13 @@ #include "sid-resources.h" #include "sid.h" #include "sound.h" +#include "spaceballs.h" #include "tape.h" #include "tape_diag_586220_harness.h" #include "tapeport.h" -#include "translate.h" +#include "tapecart.h" #include "traps.h" +#include "trapthem_snespad.h" #include "vicetypes.h" #include "userport.h" #include "userport_4bit_sampler.h" @@ -124,9 +135,19 @@ #include "userport_dac.h" #include "userport_diag_586220_harness.h" #include "userport_digimax.h" +#include "userport_hks_joystick.h" +#include "userport_hummer_joystick.h" +#include "userport_io_sim.h" #include "userport_joystick.h" +#include "userport_petscii_snespad.h" #include "userport_rtc_58321a.h" #include "userport_rtc_ds1307.h" +#include "userport_spt_joystick.h" +#include "userport_superpad64.h" +#include "userport_synergy_joystick.h" +#include "userport_wic64.h" +#include "userport_woj_joystick.h" +#include "userport_funmp3.h" #include "vice-event.h" #include "vicii.h" #include "vicii-mem.h" @@ -134,12 +155,28 @@ #include "video-sound.h" #include "vizawrite64_dongle.h" #include "vsync.h" +#include "waasoft_dongle.h" #ifdef HAVE_MOUSE #include "lightpen.h" #include "mouse.h" #endif + +/* #define DEBUG_C64 */ + +#ifdef DEBUG_C64 +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + + +/** \brief Delay in seconds before pasting -keybuf argument into the buffer + */ +#define KBDBUF_ALARM_DELAY 1 + + machine_context_t machine_context; const char machine_name[] = "C64"; @@ -213,144 +250,196 @@ static const tape_init_t tapeinit = { 100 * 8 }; -static log_t c64_log = LOG_ERR; +static log_t c64_log = LOG_DEFAULT; static machine_timing_t machine_timing; /* ------------------------------------------------------------------------ */ +static int cia2_dump(void) +{ + return ciacore_dump(machine_context.cia2); +} + +/* The following I/O range is only used when +60K or +256K memory hacks are not active. + The +60K or +256K memory hacks unregister this range and use their own replacement. + */ static io_source_t vicii_d000_device = { - "VIC-II", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd000, 0xd0ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd000, 0xd0ff, 0x3f, /* regs: $d000-d03f, mirrors: $d040-$d0ff */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, chip and mirrors never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_MASK /* contains mirrors, defined by mask */ }; +/* The following I/O range is only used when +60K or +256K memory hacks are not active. + The +60K or +256K memory hacks unregister this range and use their own replacement. + */ static io_source_t vicii_d100_device = { - "VIC-II $D100-$D1FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd100, 0xd1ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II $D100-$D1FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd100, 0xd1ff, 0x3f, /* mirrors of $d000-$d03f */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, mirrors never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; +/* The following I/O range is only used when +60K or +256K memory hacks are not active. + The +60K or +256K memory hacks unregister this range and leave the I/O range 'unconnected'. + */ static io_source_t vicii_d200_device = { - "VIC-II $D200-$D2FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd200, 0xd2ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II $D200-$D2FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd200, 0xd2ff, 0x3f, /* mirrors of $d000-$d03f */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, mirrors never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; +/* The following I/O range is only used when +60K or +256K memory hacks are not active. + The +60K or +256K memory hacks unregister this range and leave the I/O range 'unconnected'. + */ static io_source_t vicii_d300_device = { - "VIC-II $D300-$D3FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd300, 0xd3ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II $D300-$D3FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd300, 0xd3ff, 0x3f, /* mirrors of $d000-$d03f */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, mirrors never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; static io_source_t sid_d400_device = { - "SID", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd400, 0xd41f, 0x1f, - 1, /* read is always valid */ - sid_store, - sid_read, - sid_peek, - sid_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "SID", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd400, 0xd41f, 0x1f, /* main registers */ + 1, /* read is always valid */ + sid_store, /* store function */ + NULL, /* NO poke function */ + sid_read, /* read function */ + sid_peek, /* peek function */ + sid_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, chip never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* this is not a mirror */ }; static io_source_t sid_d420_device = { - "SID $D420-$D4FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd420, 0xd4ff, 0x1f, - 1, /* read is always valid */ - sid_store, - sid_read, - sid_peek, - sid_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_LOW, /* low priority, device and mirrors never involved in collisions */ - 0 + "SID $D420-$D4FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd420, 0xd4ff, 0x1f, /* mirrors of $d400-$d41f */ + 1, /* read is always valid */ + sid_store, /* store function */ + NULL, /* NO poke function */ + sid_read, /* read function */ + sid_peek, /* peek function */ + sid_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_LOW, /* low priority, chip never involved in collisions, this is to allow additional SID chips in the same range */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; static io_source_t sid_d500_device = { - "SID $D500-$D5FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd500, 0xd5ff, 0x1f, - 1, /* read is always valid */ - sid_store, - sid_read, - sid_peek, - sid_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_LOW, /* low priority, device and mirrors never involved in collisions */ - 0 + "SID $D500-$D5FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd500, 0xd5ff, 0x1f, /* mirrors of $d400-$d41f */ + 1, /* read is always valid */ + sid_store, /* store function */ + NULL, /* NO poke function */ + sid_read, /* read function */ + sid_peek, /* peek function */ + sid_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_LOW, /* low priority, chip never involved in collisions, this is to allow additional SID chips in the same range */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; static io_source_t sid_d600_device = { - "SID $D600-$D6FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd600, 0xd6ff, 0x1f, - 1, /* read is always valid */ - sid_store, - sid_read, - sid_peek, - sid_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_LOW, /* low priority, device and mirrors never involved in collisions */ - 0 + "SID $D600-$D6FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd600, 0xd6ff, 0x1f, /* mirrors of $d400-$d41f */ + 1, /* read is always valid */ + sid_store, /* store function */ + NULL, /* NO poke function */ + sid_read, /* read function */ + sid_peek, /* peek function */ + sid_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_LOW, /* low priority, chip never involved in collisions, this is to allow additional SID chips in the same range */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ }; static io_source_t sid_d700_device = { - "SID $D700-$D7FF mirrors", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd700, 0xd7ff, 0x1f, - 1, /* read is always valid */ - sid_store, - sid_read, - sid_peek, - sid_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_LOW, /* low priority, device and mirrors never involved in collisions */ - 0 + "SID $D700-$D7FF mirrors", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd700, 0xd7ff, 0x1f, /* mirrors of $d400-$d41f */ + 1, /* read is always valid */ + sid_store, /* store function */ + NULL, /* NO poke function */ + sid_read, /* read function */ + sid_peek, /* peek function */ + sid_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_LOW, /* low priority, chip never involved in collisions, this is to allow additional SID chips in the same range */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_OTHER /* this is a mirror of another registered device */ +}; + +static io_source_t cia2_dd00_device = { + "CIA2", /* name of the chip */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdd00, 0xddff, 0x0f, /* main registers */ + 1, /* read is always valid */ + cia2_store, /* store function */ + NULL, /* NO poke function */ + cia2_read, /* read function */ + cia2_peek, /* peek function */ + cia2_dump, /* chip state information dump function */ + IO_CART_ID_NONE, /* not a cartridge */ + IO_PRIO_HIGH, /* high priority, chip never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* this is not a mirror */ }; static io_source_list_t *vicii_d000_list_item = NULL; @@ -362,8 +451,31 @@ static io_source_list_t *sid_d420_list_item = NULL; static io_source_list_t *sid_d500_list_item = NULL; static io_source_list_t *sid_d600_list_item = NULL; static io_source_list_t *sid_d700_list_item = NULL; +static io_source_list_t *cia2_dd00_list_item = NULL; -void c64io_vicii_init(void) +static int c64_cia2_active = 1; + +void c64_cia2_enable(int val) +{ + if (c64_cia2_active != val) { + if (cia2_dd00_list_item != NULL) { + io_source_unregister(cia2_dd00_list_item); + cia2_dd00_list_item = NULL; + } + if (val) { + cia2_dd00_list_item = io_source_register(&cia2_dd00_device); + } + } + + c64_cia2_active = val; +} + +int c64_cia2_get_active_state(void) +{ + return c64_cia2_active; +} + +void c64io_vicii_reinit(void) { vicii_d000_list_item = io_source_register(&vicii_d000_device); vicii_d100_list_item = io_source_register(&vicii_d100_device); @@ -371,6 +483,17 @@ void c64io_vicii_init(void) vicii_d300_list_item = io_source_register(&vicii_d300_device); } +void c64io_vicii_init(void) +{ + int memhack = 0; + + resources_get_int("MemoryHack", &memhack); + + if (memhack != MEMORY_HACK_PLUS60K && memhack != MEMORY_HACK_PLUS256K) { + c64io_vicii_reinit(); + } +} + void c64io_vicii_deinit(void) { if (vicii_d000_list_item != NULL) { @@ -403,44 +526,122 @@ static void c64io_init(void) sid_d500_list_item = io_source_register(&sid_d500_device); sid_d600_list_item = io_source_register(&sid_d600_device); sid_d700_list_item = io_source_register(&sid_d700_device); + + if (c64_cia2_active) { + cia2_dd00_list_item = io_source_register(&cia2_dd00_device); + } } /* ------------------------------------------------------------------------ */ -static joyport_port_props_t control_port_1 = +static joyport_port_props_t control_port_1 = { "Control port 1", - IDGS_CONTROL_PORT_1, - 1, /* has a potentiometer connected to this port */ - 1, /* has lightpen support on this port */ - 1 /* port is always active */ + 1, /* has a potentiometer connected to this port */ + 1, /* has lightpen support on this port */ + 1, /* has joystick adapter on this port */ + 1, /* has output support on this port */ + 1, /* has +5vdc line on this port */ + 1 /* port is always active */ }; -static joyport_port_props_t control_port_2 = +static joyport_port_props_t control_port_2 = { "Control port 2", - IDGS_CONTROL_PORT_2, - 1, /* has a potentiometer connected to this port */ - 0, /* has NO lightpen support on this port */ - 1 /* port is always active */ + 1, /* has a potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 1, /* has joystick adapter on this port */ + 1, /* has output support on this port */ + 1, /* has +5vdc line on this port */ + 1 /* port is always active */ +}; + +static joyport_port_props_t joy_adapter_control_port_1 = +{ + "Joystick adapter port 1", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ +}; + +static joyport_port_props_t joy_adapter_control_port_2 = +{ + "Joystick adapter port 2", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ +}; + +static joyport_port_props_t joy_adapter_control_port_3 = +{ + "Joystick adapter port 3", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ +}; + +static joyport_port_props_t joy_adapter_control_port_4 = +{ + "Joystick adapter port 4", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ +}; + +static joyport_port_props_t joy_adapter_control_port_5 = +{ + "Joystick adapter port 5", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ +}; + +static joyport_port_props_t joy_adapter_control_port_6 = +{ + "Joystick adapter port 6", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ }; -static joyport_port_props_t userport_joy_control_port_1 = +static joyport_port_props_t joy_adapter_control_port_7 = { - "Userport joystick adapter port 1", - IDGS_USERPORT_JOY_ADAPTER_PORT_1, - 0, /* has NO potentiometer connected to this port */ - 0, /* has NO lightpen support on this port */ - 0 /* port can be switched on/off */ + "Joystick adapter port 7", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ }; -static joyport_port_props_t userport_joy_control_port_2 = +static joyport_port_props_t joy_adapter_control_port_8 = { - "Userport joystick adapter port 2", - IDGS_USERPORT_JOY_ADAPTER_PORT_2, - 0, /* has NO potentiometer connected to this port */ - 0, /* has NO lightpen support on this port */ - 0 /* port can be switched on/off */ + "Joystick adapter port 8", + 0, /* has NO potentiometer connected to this port */ + 0, /* has NO lightpen support on this port */ + 0, /* has NO joystick adapter on this port */ + 1, /* has output support on this port */ + 0, /* default for joystick adapter ports is NO +5vdc line on this port, can be changed by the joystick adapter when activated */ + 0 /* port can be switched on/off */ }; static int init_joyport_ports(void) @@ -451,10 +652,28 @@ static int init_joyport_ports(void) if (joyport_port_register(JOYPORT_2, &control_port_2) < 0) { return -1; } - if (joyport_port_register(JOYPORT_3, &userport_joy_control_port_1) < 0) { + if (joyport_port_register(JOYPORT_3, &joy_adapter_control_port_1) < 0) { return -1; } - return joyport_port_register(JOYPORT_4, &userport_joy_control_port_2); + if (joyport_port_register(JOYPORT_4, &joy_adapter_control_port_2) < 0) { + return -1; + } + if (joyport_port_register(JOYPORT_5, &joy_adapter_control_port_3) < 0) { + return -1; + } + if (joyport_port_register(JOYPORT_6, &joy_adapter_control_port_4) < 0) { + return -1; + } + if (joyport_port_register(JOYPORT_7, &joy_adapter_control_port_5) < 0) { + return -1; + } + if (joyport_port_register(JOYPORT_8, &joy_adapter_control_port_6) < 0) { + return -1; + } + if (joyport_port_register(JOYPORT_9, &joy_adapter_control_port_7) < 0) { + return -1; + } + return joyport_port_register(JOYPORT_10, &joy_adapter_control_port_8); } /* C64-specific resource initialization. This is called before initializing @@ -469,6 +688,13 @@ int machine_resources_init(void) init_resource_fail("rombanks"); return -1; } +#if 0 + /* FIXME: we might want to move this into machine.c or init.c */ + if (maincpu_resources_init() < 0) { + init_resource_fail("maincpu"); + return -1; + } +#endif if (c64_resources_init() < 0) { init_resource_fail("c64"); return -1; @@ -505,22 +731,19 @@ int machine_resources_init(void) init_resource_fail("rs232drv"); return -1; } - if (rsuser_resources_init() < 0) { - init_resource_fail("rsuser"); + if (userport_resources_init() < 0) { + init_resource_fail("userport devices"); return -1; } if (serial_resources_init() < 0) { init_resource_fail("serial"); return -1; } + /* CAUTION: must come after userport and serial */ if (printer_resources_init() < 0) { init_resource_fail("printer"); return -1; } - if (printer_userport_resources_init() < 0) { - init_resource_fail("userport printer"); - return -1; - } if (init_joyport_ports() < 0) { init_resource_fail("joyport ports"); return -1; @@ -529,62 +752,10 @@ int machine_resources_init(void) init_resource_fail("joyport devices"); return -1; } - if (joyport_sampler2bit_resources_init() < 0) { - init_resource_fail("joyport 2bit sampler"); - return -1; - } - if (joyport_sampler4bit_resources_init() < 0) { - init_resource_fail("joyport 4bit sampler"); - return -1; - } - if (joyport_bbrtc_resources_init() < 0) { - init_resource_fail("joyport bbrtc"); - return -1; - } - if (joyport_paperclip64_resources_init() < 0) { - init_resource_fail("joyport paperclip64 dongle"); - return -1; - } - if (joyport_coplin_keypad_resources_init() < 0) { - init_resource_fail("joyport coplin keypad"); - return -1; - } - if (joyport_cx21_resources_init() < 0) { - init_resource_fail("joyport cx21 keypad"); - return -1; - } - if (joyport_script64_dongle_resources_init() < 0) { - init_resource_fail("joyport script64 dongle"); - return -1; - } - if (joyport_vizawrite64_dongle_resources_init() < 0) { - init_resource_fail("joyport vizawrite64 dongle"); - return -1; - } - if (joyport_cx85_resources_init() < 0) { - init_resource_fail("joyport cx85 keypad"); - return -1; - } - if (joyport_rushware_keypad_resources_init() < 0) { - init_resource_fail("joyport rushware keypad"); - return -1; - } - if (joyport_cardkey_resources_init() < 0) { - init_resource_fail("joyport cardkey keypad"); - return -1; - } if (joystick_resources_init() < 0) { init_resource_fail("joystick"); return -1; } - if (userport_resources_init() < 0) { - init_resource_fail("userport devices"); - return -1; - } - if (gfxoutput_resources_init() < 0) { - init_resource_fail("gfxoutput"); - return -1; - } if (sampler_resources_init() < 0) { init_resource_fail("samplerdrv"); return -1; @@ -639,71 +810,15 @@ int machine_resources_init(void) init_resource_fail("mouse"); return -1; } -#ifdef HAVE_LIGHTPEN - if (lightpen_resources_init() < 0) { - init_resource_fail("lightpen"); - return -1; - } #endif -#endif -#ifndef COMMON_KBD - if (kbd_resources_init() < 0) { - init_resource_fail("kbd"); - return -1; - } -#endif - if (drive_resources_init() < 0) { - init_resource_fail("drive"); - return -1; - } - if (tapeport_resources_init() < 0) { + if (tapeport_resources_init(1) < 0) { init_resource_fail("tapeport"); return -1; } - if (tape_diag_586220_harness_resources_init() < 0) { - init_resource_fail("tape diag 586220 harness"); - return -1; - } - if (datasette_resources_init() < 0) { - init_resource_fail("datasette"); - return -1; - } if (c64_glue_resources_init() < 0) { init_resource_fail("c64 glue"); return -1; } - if (userport_joystick_resources_init() < 0) { - init_resource_fail("userport joystick"); - return -1; - } - if (userport_dac_resources_init() < 0) { - init_resource_fail("userport dac"); - return -1; - } - if (userport_digimax_resources_init() < 0) { - init_resource_fail("userport dac"); - return -1; - } - if (userport_rtc_58321a_resources_init() < 0) { - init_resource_fail("userport rtc (58321a)"); - return -1; - } - if (userport_rtc_ds1307_resources_init() < 0) { - init_resource_fail("userport rtc (ds1307)"); - return -1; - } - if (userport_4bit_sampler_resources_init() < 0) { - init_resource_fail("userport 4bit sampler"); - return -1; - } - if (userport_8bss_resources_init() < 0) { - init_resource_fail("userport 8bit stereo sampler"); - return -1; - } - if (userport_diag_586220_harness_resources_init() < 0) { - init_resource_fail("userport diag 586220 harness"); - return -1; - } if (cartio_resources_init() < 0) { init_resource_fail("cartio"); return -1; @@ -712,6 +827,15 @@ int machine_resources_init(void) init_resource_fail("cartridge"); return -1; } + /* Must be called after initializing cartridge resources. Some carts provide + * additional busses. The drive resources check the validity of the drive + * type against the available busses on the system. So if you had e.g. an + * IEEE cart enabled and an IEEE defined, on startup the drive code would + * reset the drive type to the default for the IEC bus. */ + if (drive_resources_init() < 0) { + init_resource_fail("drive"); + return -1; + } return 0; } @@ -727,15 +851,14 @@ void machine_resources_shutdown(void) drive_resources_shutdown(); cartridge_resources_shutdown(); rombanks_resources_shutdown(); - userport_rtc_58321a_resources_shutdown(); - userport_rtc_ds1307_resources_shutdown(); + userport_resources_shutdown(); cartio_shutdown(); fsdevice_resources_shutdown(); disk_image_resources_shutdown(); sampler_resources_shutdown(); - userport_resources_shutdown(); - joyport_bbrtc_resources_shutdown(); tapeport_resources_shutdown(); + tapecart_exit(); + joyport_resources_shutdown(); } /* C64-specific command-line option initialization. */ @@ -745,6 +868,11 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("traps"); return -1; } + /* FIXME: we might want to move this into machine.c or init.c */ + if (maincpu_cmdline_options_init() < 0) { + init_cmdline_options_fail("maincpu"); + return -1; + } if (c64_cmdline_options_init() < 0) { init_cmdline_options_fail("c64"); return -1; @@ -769,7 +897,7 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("vicii"); return -1; } - if (sid_cmdline_options_init() < 0) { + if (sid_cmdline_options_init(SIDTYPE_SID) < 0) { init_cmdline_options_fail("sid"); return -1; } @@ -777,10 +905,6 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("rs232drv"); return -1; } - if (rsuser_cmdline_options_init() < 0) { - init_cmdline_options_fail("rsuser"); - return -1; - } if (serial_cmdline_options_init() < 0) { init_cmdline_options_fail("serial"); return -1; @@ -789,18 +913,10 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("printer"); return -1; } - if (printer_userport_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport printer"); - return -1; - } if (joyport_cmdline_options_init() < 0) { init_cmdline_options_fail("joyport"); return -1; } - if (joyport_bbrtc_cmdline_options_init() < 0) { - init_cmdline_options_fail("bbrtc"); - return -1; - } if (joystick_cmdline_options_init() < 0) { init_cmdline_options_fail("joystick"); return -1; @@ -809,10 +925,6 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("userport"); return -1; } - if (gfxoutput_cmdline_options_init() < 0) { - init_cmdline_options_fail("gfxoutput"); - return -1; - } if (sampler_cmdline_options_init() < 0) { init_cmdline_options_fail("samplerdrv"); return -1; @@ -866,12 +978,6 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("mouse"); return -1; } -#endif -#ifndef COMMON_KBD - if (kbd_cmdline_options_init() < 0) { - init_cmdline_options_fail("kbd"); - return -1; - } #endif if (drive_cmdline_options_init() < 0) { init_cmdline_options_fail("drive"); @@ -881,50 +987,10 @@ int machine_cmdline_options_init(void) init_cmdline_options_fail("tapeport"); return -1; } - if (tape_diag_586220_harness_cmdline_options_init() < 0) { - init_cmdline_options_fail("tape diag 586220 harness"); - return -1; - } - if (datasette_cmdline_options_init() < 0) { - init_cmdline_options_fail("datasette"); - return -1; - } if (c64_glue_cmdline_options_init() < 0) { init_cmdline_options_fail("c64 glue"); return -1; } - if (userport_joystick_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport joystick"); - return -1; - } - if (userport_dac_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport dac"); - return -1; - } - if (userport_digimax_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport digimax"); - return -1; - } - if (userport_rtc_58321a_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport rtc (58321a)"); - return -1; - } - if (userport_rtc_ds1307_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport rtc (ds1307)"); - return -1; - } - if (userport_4bit_sampler_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport 4bit sampler"); - return -1; - } - if (userport_8bss_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport 8bit stereo sampler"); - return -1; - } - if (userport_diag_586220_harness_cmdline_options_init() < 0) { - init_cmdline_options_fail("userport diag 586220 harness"); - return -1; - } if (cartio_cmdline_options_init() < 0) { init_cmdline_options_fail("cartio"); return -1; @@ -940,7 +1006,7 @@ static void c64_monitor_init(void) { unsigned int dnr; monitor_cpu_type_t asm6502, asmR65C02, asmz80; - monitor_interface_t *drive_interface_init[DRIVE_NUM]; + monitor_interface_t *drive_interface_init[NUM_DISK_UNITS]; monitor_cpu_type_t *asmarray[4]; int i = 0; @@ -953,7 +1019,7 @@ static void c64_monitor_init(void) asmR65C02_init(&asmR65C02); asmz80_init(&asmz80); - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { drive_interface_init[dnr] = drive_cpu_monitor_interface_get(dnr); } @@ -972,10 +1038,10 @@ void machine_setup_context(void) /* C64-specific initialization. */ int machine_specific_init(void) { - int delay; - c64_log = log_open("C64"); + DBG(("machine_specific_init")); + if (mem_load() < 0) { return -1; } @@ -1012,24 +1078,15 @@ int machine_specific_init(void) disk_image_init(); /* C64D: do not use autostart feature in C64 debugger as we have our own methods - resources_get_int("AutostartDelay", &delay); - if (delay == 0) { - delay = 3; // default - } - - // Initialize autostart. - autostart_init((CLOCK)(delay * C64_PAL_RFSH_PER_SEC * C64_PAL_CYCLES_PER_RFSH), 1, 0xcc, 0xd1, 0xd3, 0xd5); + autostart_init(3, 1); */ - - -#ifdef USE_BEOS_UI + + /* Pre-init C64-specific parts of the menus before vicii_init() - creates a canvas window with a menubar at the top. This could - also be used by other ports, e.g. GTK+... */ + creates a canvas window with a menubar at the top. */ if (!console_mode) { c64_mem_ui_init_early(); } -#endif if (vicii_init(VICII_STANDARD) == NULL && !video_disabled_mode) { return -1; @@ -1040,12 +1097,7 @@ int machine_specific_init(void) cia1_init(machine_context.cia1); cia2_init(machine_context.cia2); -#ifndef COMMON_KBD /* Initialize the keyboard. */ - if (c64_kbd_init() < 0) { - return -1; - } -#endif c64keyboard_init(); c64_monitor_init(); @@ -1056,6 +1108,7 @@ int machine_specific_init(void) /* Initialize native sound chip */ sid_sound_chip_init(); + fmopl_set_machine_parameter(machine_timing.cycles_per_sec); /* Initialize cartridge based sound chips */ cartridge_sound_chip_init(); @@ -1064,20 +1117,26 @@ int machine_specific_init(void) userport_dac_sound_chip_init(); userport_digimax_sound_chip_init(); - /* Initialize mp3@64 */ + /* Initialize mp3@64, funmp3 */ #ifdef USE_MPG123 clockport_mp3at64_sound_chip_init(); #endif +#if defined(USE_MPG123) && defined (HAVE_GLOB_H) + userport_funmp3_sound_chip_init(); +#endif drive_sound_init(); + datasette_sound_init(); video_sound_init(); /* Initialize sound. Notice that this does not really open the audio device yet. */ - sound_init(machine_timing.cycles_per_sec, machine_timing.cycles_per_rfsh); + sound_init((int)machine_timing.cycles_per_sec, (int)machine_timing.cycles_per_rfsh); /* Initialize keyboard buffer. */ - kbdbuf_init(631, 198, 10, (CLOCK)(machine_timing.rfsh_per_sec * machine_timing.cycles_per_rfsh)); + kbdbuf_init(631, 198, 10, + (CLOCK)(machine_timing.rfsh_per_sec * + machine_timing.cycles_per_rfsh * KBDBUF_ALARM_DELAY)); /* Initialize the C64-specific I/O */ c64io_init(); @@ -1122,16 +1181,8 @@ int machine_specific_init(void) cartridge_init(); machine_drive_stub(); -#if defined (USE_XF86_EXTENSIONS) && (defined(USE_XF86_VIDMODE_EXT) || defined (HAVE_XRANDR)) - { - /* set fullscreen if user used `-fullscreen' on cmdline */ - int fs; - resources_get_int("UseFullscreen", &fs); - if (fs) { - resources_set_int("VICIIFullscreen", 1); - } - } -#endif + + DBG(("machine_specific_init (done)")); return 0; } @@ -1146,13 +1197,14 @@ void machine_specific_reset(void) serial_traps_reset(); + /* These calls must be before the CIA initialization */ + rs232drv_reset(); /* driver is used by both user- and expansion port ? */ + userport_reset(); + ciacore_reset(machine_context.cia1); ciacore_reset(machine_context.cia2); sid_reset(); - rs232drv_reset(); /* driver is used by both user- and expansion port ? */ - rsuser_reset(); - printer_reset(); /* FIXME: whats actually broken here? */ @@ -1162,6 +1214,8 @@ void machine_specific_reset(void) vicii_reset(); cartridge_reset(); + + /* reset drives on powerup, and if "reset goes to IEC" is enabled */ if (reset_poweron || iecreset) { drive_reset(); } @@ -1178,13 +1232,16 @@ void machine_specific_reset(void) void machine_specific_powerup(void) { vicii_reset_registers(); + cartridge_powerup(); + userport_powerup(); + tapeport_powerup(); + joyport_powerup(); reset_poweron = 1; } void machine_specific_shutdown(void) { - /* and the tape */ - tape_image_detach_internal(1); + tape_image_detach_internal(TAPEPORT_PORT_1 + 1); /* and cartridge */ cartridge_detach_image(-1); @@ -1212,7 +1269,7 @@ void machine_specific_shutdown(void) } } -void machine_handle_pending_alarms(int num_write_cycles) +void machine_handle_pending_alarms(CLOCK num_write_cycles) { vicii_handle_pending_alarms_external(num_write_cycles); } @@ -1222,24 +1279,11 @@ void machine_handle_pending_alarms(int num_write_cycles) /* This hook is called at the end of every frame. */ static void machine_vsync_hook(void) { - CLOCK sub; - network_hook(); drive_vsync_hook(); - /* C64D: do not use autostart feature in C64 debugger as we have our own methods - autostart_advance(); - */ - - screenshot_record(); - - sub = clk_guard_prevent_overflow(maincpu_clk_guard); - - /* The drive has to deal both with our overflowing and its own one, so - it is called even when there is no overflowing in the main CPU. */ - drive_cpu_prevent_clk_overflow_all(sub); } void machine_set_restore_key(int v) @@ -1271,7 +1315,7 @@ void machine_get_line_cycle(unsigned int *line, unsigned int *cycle, int *half_c *half_cycle = (int)-1; } -void machine_change_timing(int timeval, int border_mode) +void machine_change_timing(int timeval, int powerfreq, int border_mode) { switch (timeval) { case MACHINE_SYNC_PAL: @@ -1280,7 +1324,7 @@ void machine_change_timing(int timeval, int border_mode) machine_timing.rfsh_per_sec = C64_PAL_RFSH_PER_SEC; machine_timing.cycles_per_line = C64_PAL_CYCLES_PER_LINE; machine_timing.screen_lines = C64_PAL_SCREEN_LINES; - machine_timing.power_freq = 50; + machine_timing.power_freq = powerfreq; break; case MACHINE_SYNC_NTSC: machine_timing.cycles_per_sec = C64_NTSC_CYCLES_PER_SEC; @@ -1288,7 +1332,7 @@ void machine_change_timing(int timeval, int border_mode) machine_timing.rfsh_per_sec = C64_NTSC_RFSH_PER_SEC; machine_timing.cycles_per_line = C64_NTSC_CYCLES_PER_LINE; machine_timing.screen_lines = C64_NTSC_SCREEN_LINES; - machine_timing.power_freq = 60; + machine_timing.power_freq = powerfreq; break; case MACHINE_SYNC_NTSCOLD: machine_timing.cycles_per_sec = C64_NTSCOLD_CYCLES_PER_SEC; @@ -1296,7 +1340,7 @@ void machine_change_timing(int timeval, int border_mode) machine_timing.rfsh_per_sec = C64_NTSCOLD_RFSH_PER_SEC; machine_timing.cycles_per_line = C64_NTSCOLD_CYCLES_PER_LINE; machine_timing.screen_lines = C64_NTSCOLD_SCREEN_LINES; - machine_timing.power_freq = 60; + machine_timing.power_freq = powerfreq; break; case MACHINE_SYNC_PALN: machine_timing.cycles_per_sec = C64_PALN_CYCLES_PER_SEC; @@ -1304,7 +1348,7 @@ void machine_change_timing(int timeval, int border_mode) machine_timing.rfsh_per_sec = C64_PALN_RFSH_PER_SEC; machine_timing.cycles_per_line = C64_PALN_CYCLES_PER_LINE; machine_timing.screen_lines = C64_PALN_SCREEN_LINES; - machine_timing.power_freq = 50; + machine_timing.power_freq = powerfreq; break; default: log_error(c64_log, "Unknown machine timing."); @@ -1317,28 +1361,43 @@ void machine_change_timing(int timeval, int border_mode) serial_iec_device_set_machine_parameter(machine_timing.cycles_per_sec); sid_set_machine_parameter(machine_timing.cycles_per_sec); #ifdef HAVE_MOUSE - neos_mouse_set_machine_parameter(machine_timing.cycles_per_sec); + mouse_set_machine_parameter(machine_timing.cycles_per_sec); #endif - clk_guard_set_clk_base(maincpu_clk_guard, machine_timing.cycles_per_rfsh); vicii_change_timing(&machine_timing, border_mode); - cia1_set_timing(machine_context.cia1, machine_timing.cycles_per_sec, machine_timing.power_freq); - cia2_set_timing(machine_context.cia2, machine_timing.cycles_per_sec, machine_timing.power_freq); + cia1_set_timing(machine_context.cia1, + (int)machine_timing.cycles_per_sec, + machine_timing.power_freq); + cia2_set_timing(machine_context.cia2, + (int)machine_timing.cycles_per_sec, + machine_timing.power_freq); + + fmopl_set_machine_parameter(machine_timing.cycles_per_sec); + + rsuser_change_timing(machine_timing.cycles_per_sec); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } /* ------------------------------------------------------------------------- */ int machine_write_snapshot(const char *name, int save_roms, int save_disks, int event_mode) { - return c64_snapshot_write(name, save_roms, save_disks, event_mode, 1, 1, 1); + int err = c64_snapshot_write(name, save_roms, save_disks, event_mode, 1, 1, 1); + if ((err < 0) && (snapshot_get_error() == SNAPSHOT_NO_ERROR)) { + snapshot_set_error(SNAPSHOT_CANNOT_WRITE_SNAPSHOT); + } + return err; } int machine_read_snapshot(const char *name, int event_mode) { - return c64_snapshot_read(name, event_mode, 1, 1, 1, 1); + int err = c64_snapshot_read(name, event_mode, 1, 1, 1, 1); + if ((err < 0) && (snapshot_get_error() == SNAPSHOT_NO_ERROR)) { + snapshot_set_error(SNAPSHOT_CANNOT_READ_SNAPSHOT); + } + return err; } /* ------------------------------------------------------------------------- */ @@ -1392,39 +1451,44 @@ struct image_contents_s *machine_diskcontents_bus_read(unsigned int unit) return diskcontents_iec_read(unit); } -BYTE machine_tape_type_default(void) +uint8_t machine_tape_type_default(void) { return TAPE_CAS_TYPE_PRG; } -BYTE machine_tape_behaviour(void) +uint8_t machine_tape_behaviour(void) { return TAPE_BEHAVIOUR_NORMAL; } static int get_cart_emulation_state(void) { - int value; - - if (resources_get_int("CartridgeType", &value) < 0) { - return CARTRIDGE_NONE; - } - + /* FIXME: we should also check the other slots */ + int value = cart_getid_slotmain(); return value; } +/* returns TRUE if in RAM, FALSE if in cartridge ROM or IO */ static int check_cart_range(unsigned int addr) { if (get_cart_emulation_state() == CARTRIDGE_NONE) { return 1; } - - return (!(addr >= 0x8000 && addr < 0xa000)); + /* check ROML, ROMH as well as IO1 and IO2 */ + /* FIXME: ideally we should check this accurately per cartridge type, and + take the actual active mapping into account */ + return (!(addr >= 0x8000 && addr < 0xa000) && !(addr >= 0xde00 && addr < 0xe000) ); } +/* returns TRUE if in RAM */ int machine_addr_in_ram(unsigned int addr) { - return ((addr < 0xe000 && !(addr >= 0xa000 && addr < 0xc000)) && check_cart_range(addr)); + return ( + (addr < 0xe000 + && !(addr >= 0xa000 && addr < 0xc000) + && !(addr >= 0x0073 && addr <= 0x008a)) + && check_cart_range(addr) + ); } const char *machine_get_name(void) @@ -1438,19 +1502,22 @@ const char *machine_get_name(void) /* ------------------------------------------------------------------------- */ -static void c64_userport_set_flag(BYTE b) +/* called via userport.c:set_userport_flag->userport_props.set_flag(val); */ +static void c64_userport_set_flag(uint8_t b) { + DBG(("c64_userport_set_flag(%d)", b)); if (b != 0) { ciacore_set_flag(machine_context.cia2); } } static userport_port_props_t userport_props = { - 1, /* has pa2 pin */ - 1, /* has pa3 pin */ - c64_userport_set_flag, /* has flag pin */ - 1, /* has pc pin */ - 1 /* has cnt1, cnt2 and sp pins */ + 1, /* port has the pa2 pin */ + 1, /* port has the pa3 pin */ + c64_userport_set_flag, /* port has the flag pin, set flag function */ + 1, /* port has the pc pin */ + 1, /* port has the cnt1, cnt2 and sp pins */ + 1 /* port has the reset pin */ }; int machine_register_userport(void) @@ -1459,3 +1526,50 @@ int machine_register_userport(void) return 0; } + +/* ------------------------------------------------------------------------- */ + +/** \brief List of drive type names and ID's supported by C64 + * + * Convenience function for UI's. This list should be updated whenever drive + * types are added or removed. + * + * XXX: This is here because c64drive.c is compiled into x64dtv, which supports + * fewer drive types. + */ +static drive_type_info_t drive_type_info_list[] = { + { DRIVE_NAME_NONE, DRIVE_TYPE_NONE }, + { DRIVE_NAME_1540, DRIVE_TYPE_1540 }, + { DRIVE_NAME_1541, DRIVE_TYPE_1541 }, + { DRIVE_NAME_1541II, DRIVE_TYPE_1541II }, + { DRIVE_NAME_1570, DRIVE_TYPE_1570 }, + { DRIVE_NAME_1571, DRIVE_TYPE_1571 }, + { DRIVE_NAME_1581, DRIVE_TYPE_1581 }, + { DRIVE_NAME_2000, DRIVE_TYPE_2000 }, + { DRIVE_NAME_4000, DRIVE_TYPE_4000 }, + { DRIVE_NAME_CMDHD, DRIVE_TYPE_CMDHD }, + { DRIVE_NAME_2031, DRIVE_TYPE_2031 }, + { DRIVE_NAME_2040, DRIVE_TYPE_2040 }, + { DRIVE_NAME_3040, DRIVE_TYPE_3040 }, + { DRIVE_NAME_4040, DRIVE_TYPE_4040 }, + { DRIVE_NAME_1001, DRIVE_TYPE_1001 }, + { DRIVE_NAME_8050, DRIVE_TYPE_8050 }, + { DRIVE_NAME_8250, DRIVE_TYPE_8250 }, + { DRIVE_NAME_9000, DRIVE_TYPE_9000 }, + { NULL, -1 } +}; + +/** \brief Get a list of (name, id) tuples for the drives handles by C64 + * + * Usefull for UI's, get a list of currently supported drive types with a name + * to display and and ID to use in callbacks. + * + * \return list of drive types, NULL terminated + * + * \note 'supported' in this context means the drives C64 can support, not + * what actually is supported due to ROMs and other settings + */ +drive_type_info_t *machine_drive_get_type_info_list(void) +{ + return drive_type_info_list; +} diff --git a/src/Emulators/vice/c64/c64.h b/src/Emulators/vice/c64/c64.h index 80c61e70..3733dcec 100644 --- a/src/Emulators/vice/c64/c64.h +++ b/src/Emulators/vice/c64/c64.h @@ -77,9 +77,11 @@ 8500 */ #define C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES 350000 +/* bits 3,4,5 are not connected on SX-64 board. apparently they take a bit longer */ +#define SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES 1500000 /* cpuports.prg from the lorenz testsuite will fail when the falloff takes less - than 5984 cycles. he explicitly delays by ~1280 cycles and mentions capacitance, + than 5984 cycles. he explicitly delays by ~1280 cycles and mentions capacitance, so he probably even was aware of what happens. */ @@ -97,4 +99,7 @@ typedef struct machine_context_s { extern machine_context_t machine_context; +void c64_cia2_enable(int val); +int c64_cia2_get_active_state(void); + #endif diff --git a/src/Emulators/vice/c64/c64_256k.c b/src/Emulators/vice/c64/c64_256k.c index 3692609d..6f0ef369 100644 --- a/src/Emulators/vice/c64/c64_256k.c +++ b/src/Emulators/vice/c64/c64_256k.c @@ -44,23 +44,22 @@ #include "resources.h" #include "reu.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" #include "vicii.h" /* 256K registers */ -BYTE c64_256k_DDA; -BYTE c64_256k_PRA; -BYTE c64_256k_CRA; -BYTE c64_256k_DDB; -BYTE c64_256k_PRB; -BYTE c64_256k_CRB; +uint8_t c64_256k_DDA; +uint8_t c64_256k_PRA; +uint8_t c64_256k_CRA; +uint8_t c64_256k_DDB; +uint8_t c64_256k_PRB; +uint8_t c64_256k_CRB; int c64_256k_start; -static log_t c64_256k_log = LOG_ERR; +static log_t c64_256k_log = LOG_DEFAULT; static int c64_256k_activate(void); static int c64_256k_deactivate(void); @@ -78,20 +77,20 @@ int c64_256k_segment3; /* Filename of the 256K image. */ static char *c64_256k_filename = NULL; -BYTE *c64_256k_ram = NULL; +uint8_t *c64_256k_ram = NULL; /* ---------------------------------------------------------------------*/ -void pia_set_vbank(void) +static void pia_set_vbank(void) { video_bank_segment = ((c64_256k_PRB & 0xc0) >> 4) + cia_vbank; vicii_set_ram_base(c64_256k_ram + (video_bank_segment * 0x4000)); mem_set_vbank(0); } -static BYTE c64_256k_read(WORD addr) +uint8_t c64_256k_read(uint16_t addr) { - BYTE retval = 0; + uint8_t retval = 0; if (addr == 1) { retval = c64_256k_CRA; @@ -115,9 +114,9 @@ static BYTE c64_256k_read(WORD addr) return retval; } -static void c64_256k_store(WORD addr, BYTE byte) +void c64_256k_store(uint16_t addr, uint8_t byte) { - BYTE old_prb; + uint8_t old_prb; if (addr == 1) { c64_256k_CRA = byte & 0x3f; @@ -163,18 +162,20 @@ static int c64_256k_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t c64_256k_device = { - "C64 256K", - IO_DETACH_RESOURCE, - "C64_256K", - 0xdf80, 0xdfff, 0x7f, - 1, /* read is always valid */ - c64_256k_store, - c64_256k_read, - c64_256k_read, - c64_256k_dump, - CARTRIDGE_C64_256K, - 0, - 0 + "C64 256K", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "C64_256K", /* resource to set to '0' */ + 0xdf80, 0xdfff, 0x03, /* range for the device, registers:$df80-df83, mirrors:$df84-$dfff, range can be changed */ + 1, /* read is always valid */ + c64_256k_store, /* store function */ + NULL, /* NO poke function */ + c64_256k_read, /* read function */ + c64_256k_read, /* peek function */ + c64_256k_dump, /* device state information dump function */ + CARTRIDGE_C64_256K, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *c64_256k_list_item = NULL; @@ -194,7 +195,7 @@ int set_c64_256k_enabled(int value, int disable_reset) return -1; } if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } io_source_unregister(c64_256k_list_item); c64_256k_list_item = NULL; @@ -205,7 +206,7 @@ int set_c64_256k_enabled(int value, int disable_reset) return -1; } if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } c64_256k_list_item = io_source_register(&c64_256k_device); c64_256k_enabled = 1; @@ -247,11 +248,11 @@ static int set_c64_256k_base(int val, void *param) case 0xde80: case 0xdf00: case 0xdf80: - c64_256k_device.start_address = (WORD)val; - c64_256k_device.end_address = (WORD)(val + 0x7f); + c64_256k_device.start_address = (uint16_t)val; + c64_256k_device.end_address = (uint16_t)(val + 0x7f); break; default: - log_message(c64_256k_log, "Unknown 256K base %X.", val); + log_message(c64_256k_log, "Unknown 256K base %X.", (unsigned int)val); return -1; } @@ -296,21 +297,17 @@ void c64_256k_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-256kimage", SET_RESOURCE, 1, + { "-256kimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "C64_256Kfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_C64_256K_NAME, - NULL, NULL }, + "", "Specify name of 256K image" }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-256kbase", SET_RESOURCE, 1, + { "-256kbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "C64_256Kbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_BASE_ADDRESS, IDCLS_C64_256K_BASE, - NULL, NULL }, + "", "Base address of the 256K expansion. (0xDE00/0xDE80/0xDF00/0xDF80)" }, CMDLINE_LIST_END }; @@ -404,7 +401,7 @@ void c64_256k_shutdown(void) /* ------------------------------------------------------------------------- */ -void c64_256k_ram_segment0_store(WORD addr, BYTE value) +void c64_256k_ram_segment0_store(uint16_t addr, uint8_t value) { c64_256k_ram[(c64_256k_segment0 * 0x4000) + (addr & 0x3fff)] = value; if (addr == 0xff00) { @@ -412,7 +409,7 @@ void c64_256k_ram_segment0_store(WORD addr, BYTE value) } } -void c64_256k_ram_segment1_store(WORD addr, BYTE value) +void c64_256k_ram_segment1_store(uint16_t addr, uint8_t value) { c64_256k_ram[(c64_256k_segment1 * 0x4000) + (addr & 0x3fff)] = value; if (addr == 0xff00) { @@ -420,7 +417,7 @@ void c64_256k_ram_segment1_store(WORD addr, BYTE value) } } -void c64_256k_ram_segment2_store(WORD addr, BYTE value) +void c64_256k_ram_segment2_store(uint16_t addr, uint8_t value) { c64_256k_ram[(c64_256k_segment2 * 0x4000) + (addr & 0x3fff)] = value; if (addr == 0xff00) { @@ -428,7 +425,7 @@ void c64_256k_ram_segment2_store(WORD addr, BYTE value) } } -void c64_256k_ram_segment3_store(WORD addr, BYTE value) +void c64_256k_ram_segment3_store(uint16_t addr, uint8_t value) { c64_256k_ram[(c64_256k_segment3 * 0x4000) + (addr & 0x3fff)] = value; if (addr == 0xff00) { @@ -436,22 +433,35 @@ void c64_256k_ram_segment3_store(WORD addr, BYTE value) } } -BYTE c64_256k_ram_segment0_read(WORD addr) +void c64_256k_ram_inject(uint16_t addr, uint8_t value) +{ + if (addr < 0x4000) { + c64_256k_ram_segment0_store(addr, value); + } else if (addr < 0x8000) { + c64_256k_ram_segment1_store(addr, value); + } else if (addr < 0xc000) { + c64_256k_ram_segment2_store(addr, value); + } else { + c64_256k_ram_segment3_store(addr, value); + } +} + +uint8_t c64_256k_ram_segment0_read(uint16_t addr) { return c64_256k_ram[(c64_256k_segment0 * 0x4000) + (addr & 0x3fff)]; } -BYTE c64_256k_ram_segment1_read(WORD addr) +uint8_t c64_256k_ram_segment1_read(uint16_t addr) { return c64_256k_ram[(c64_256k_segment1 * 0x4000) + (addr & 0x3fff)]; } -BYTE c64_256k_ram_segment2_read(WORD addr) +uint8_t c64_256k_ram_segment2_read(uint16_t addr) { return c64_256k_ram[(c64_256k_segment2 * 0x4000) + (addr & 0x3fff)]; } -BYTE c64_256k_ram_segment3_read(WORD addr) +uint8_t c64_256k_ram_segment3_read(uint16_t addr) { return c64_256k_ram[(c64_256k_segment3 * 0x4000) + (addr & 0x3fff)]; } @@ -492,18 +502,18 @@ int c64_256k_snapshot_write(struct snapshot_s *s) } if (0 - || SMW_W (m, (WORD)c64_256k_start) < 0 + || SMW_W (m, (uint16_t)c64_256k_start) < 0 || SMW_B (m, c64_256k_DDA) < 0 || SMW_B (m, c64_256k_PRA) < 0 || SMW_B (m, c64_256k_CRA) < 0 || SMW_B (m, c64_256k_DDB) < 0 || SMW_B (m, c64_256k_PRB) < 0 || SMW_B (m, c64_256k_CRB) < 0 - || SMW_B (m, (BYTE)cia_vbank) < 0 - || SMW_B (m, (BYTE)c64_256k_segment0) < 0 - || SMW_B (m, (BYTE)c64_256k_segment1) < 0 - || SMW_B (m, (BYTE)c64_256k_segment2) < 0 - || SMW_B (m, (BYTE)c64_256k_segment3) < 0 + || SMW_B (m, (uint8_t)cia_vbank) < 0 + || SMW_B (m, (uint8_t)c64_256k_segment0) < 0 + || SMW_B (m, (uint8_t)c64_256k_segment1) < 0 + || SMW_B (m, (uint8_t)c64_256k_segment2) < 0 + || SMW_B (m, (uint8_t)c64_256k_segment3) < 0 || SMW_BA(m, c64_256k_ram, 0x40000) < 0) { snapshot_module_close(m); return -1; @@ -515,7 +525,7 @@ int c64_256k_snapshot_write(struct snapshot_s *s) int c64_256k_snapshot_read(struct snapshot_s *s) { snapshot_module_t *m; - BYTE vmajor, vminor; + uint8_t vmajor, vminor; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -524,7 +534,7 @@ int c64_256k_snapshot_read(struct snapshot_s *s) } /* do not accept higher versions than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -564,7 +574,7 @@ int c64_256k_snapshot_read(struct snapshot_s *s) } return snapshot_module_close(m); - + fail: if (m != NULL) { snapshot_module_close(m); diff --git a/src/Emulators/vice/c64/c64_256k.h b/src/Emulators/vice/c64/c64_256k.h index 95589df2..e8d22af1 100644 --- a/src/Emulators/vice/c64/c64_256k.h +++ b/src/Emulators/vice/c64/c64_256k.h @@ -33,27 +33,31 @@ extern int c64_256k_start; extern int c64_256k_enabled; -extern int c64_256k_resources_init(void); -extern void c64_256k_resources_shutdown(void); -extern int c64_256k_cmdline_options_init(void); - -extern void c64_256k_init(void); -extern void c64_256k_reset(void); -extern void c64_256k_cia_set_vbank(int ciabank); -extern void c64_256k_shutdown(void); - -extern void c64_256k_ram_segment0_store(WORD addr, BYTE value); -extern void c64_256k_ram_segment1_store(WORD addr, BYTE value); -extern void c64_256k_ram_segment2_store(WORD addr, BYTE value); -extern void c64_256k_ram_segment3_store(WORD addr, BYTE value); -extern BYTE c64_256k_ram_segment0_read(WORD addr); -extern BYTE c64_256k_ram_segment1_read(WORD addr); -extern BYTE c64_256k_ram_segment2_read(WORD addr); -extern BYTE c64_256k_ram_segment3_read(WORD addr); - -extern int set_c64_256k_enabled(int value, int disable_reset); - -extern int c64_256k_snapshot_write(struct snapshot_s *s); -extern int c64_256k_snapshot_read(struct snapshot_s *s); +int c64_256k_resources_init(void); +void c64_256k_resources_shutdown(void); +int c64_256k_cmdline_options_init(void); + +void c64_256k_init(void); +void c64_256k_reset(void); +void c64_256k_cia_set_vbank(int ciabank); +void c64_256k_shutdown(void); + +void c64_256k_ram_inject(uint16_t addr, uint8_t value); +void c64_256k_ram_segment0_store(uint16_t addr, uint8_t value); +void c64_256k_ram_segment1_store(uint16_t addr, uint8_t value); +void c64_256k_ram_segment2_store(uint16_t addr, uint8_t value); +void c64_256k_ram_segment3_store(uint16_t addr, uint8_t value); +uint8_t c64_256k_ram_segment0_read(uint16_t addr); +uint8_t c64_256k_ram_segment1_read(uint16_t addr); +uint8_t c64_256k_ram_segment2_read(uint16_t addr); +uint8_t c64_256k_ram_segment3_read(uint16_t addr); + +int set_c64_256k_enabled(int value, int disable_reset); + +int c64_256k_snapshot_write(struct snapshot_s *s); +int c64_256k_snapshot_read(struct snapshot_s *s); + +uint8_t c64_256k_read(uint16_t addr); +void c64_256k_store(uint16_t addr, uint8_t byte); #endif diff --git a/src/Emulators/vice/c64/c64bus.c b/src/Emulators/vice/c64/c64bus.c index 4c386434..139f30b8 100644 --- a/src/Emulators/vice/c64/c64bus.c +++ b/src/Emulators/vice/c64/c64bus.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUG_C64BUS */ + #include "vice.h" #include "iecbus.h" @@ -32,17 +34,24 @@ #include "serial.h" #include "vicetypes.h" -int machine_bus_lib_directory(unsigned int unit, const char *pattern, BYTE **buf) +#ifdef DEBUG_C64BUS +#include "log.h" +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +int machine_bus_lib_directory(unsigned int unit, const char *pattern, uint8_t **buf) { return serial_iec_lib_directory(unit, pattern, buf); } -int machine_bus_lib_read_sector(unsigned int unit, unsigned int track, unsigned int sector, BYTE *buf) +int machine_bus_lib_read_sector(unsigned int unit, unsigned int track, unsigned int sector, uint8_t *buf) { return serial_iec_lib_read_sector(unit, track, sector, buf); } -int machine_bus_lib_write_sector(unsigned int unit, unsigned int track, unsigned int sector, BYTE *buf) +int machine_bus_lib_write_sector(unsigned int unit, unsigned int track, unsigned int sector, uint8_t *buf) { return serial_iec_lib_write_sector(unit, track, sector, buf); } @@ -52,21 +61,23 @@ unsigned int machine_bus_device_type_get(unsigned int unit) return serial_device_type_get(unit); } -void machine_bus_status_truedrive_set(unsigned int enable) +void machine_bus_status_truedrive_set(unsigned int unit, unsigned int enable) { - iecbus_status_set(IECBUS_STATUS_TRUEDRIVE, 0, enable); - serial_trap_truedrive_set(enable); + DBG(("machine_bus_status_truedrive_set unit: %u enable: %u", unit, enable)); + iecbus_status_set(IECBUS_STATUS_TRUEDRIVE, unit, enable); + serial_trap_truedrive_set(unit, enable); } void machine_bus_status_drivetype_set(unsigned int unit, unsigned int enable) { + DBG(("machine_bus_status_drivetype_set unit: %u enable: %u", unit, enable)); iecbus_status_set(IECBUS_STATUS_DRIVETYPE, unit, enable); } -void machine_bus_status_virtualdevices_set(unsigned int enable) +void machine_bus_status_trapdevices_set(unsigned int unit, unsigned int enable) { - iecbus_status_set(IECBUS_STATUS_VIRTUALDEVICES, 0, enable); - parallel_bus_enable(enable); + DBG(("machine_bus_status_trapdevices_set unit: %u enable: %u", unit, enable)); + iecbus_status_set(IECBUS_STATUS_TRAPDEVICE, unit, enable); /* IEC */ } void machine_bus_eof_callback_set(void (*func)(void)) diff --git a/src/Emulators/vice/c64/c64cart.h b/src/Emulators/vice/c64/c64cart.h index 92431943..dab11aab 100644 --- a/src/Emulators/vice/c64/c64cart.h +++ b/src/Emulators/vice/c64/c64cart.h @@ -29,8 +29,8 @@ #include "vicetypes.h" -/* Cartridge ROM limit = 1MB (EasyFlash) */ -#define C64CART_ROM_LIMIT (1024 * 1024) +/* Cartridge ROM limit = 2MB (Magic Desk 2 - 16K config) */ +#define C64CART_ROM_LIMIT (2 * 1024 * 1024) /* Cartridge RAM limit = 32kB (IDE64, ...) */ #define C64CART_RAM_LIMIT (32 * 1024) /* maximum size of a full "all inclusive" cartridge image (16MB for REU) */ @@ -59,21 +59,70 @@ !ROML 11 8K decoded RAM/ROM block @ $8000 (active low) buffered ls ttl output !ROMH B 8K decoded RAM/ROM block @ $E000 buffered + bidirectional: + D7-D0 14-21 Data bus bit 7-0 - unbuffered, 1 ls ttl load max A15-A0 F- Y Address bus bit 0-15 - unbuffered, 1 ls ttl load max */ +/* WARNING: due to the way VICE is being built/linked, this struct has to be + the same in C64/DTV/C128 and CBM2 (ie c64cart.h and cbm2cart.h) */ typedef struct { - BYTE exrom; /* exrom signal, 0 - active */ - BYTE game; /* game signal, 0 - active */ - BYTE ultimax_phi1; /* flag for vic-ii, ultimax mode in phi1 phase */ - BYTE ultimax_phi2; /* flag for vic-ii, ultimax mode in phi2 phase */ + uint8_t exrom; /* exrom signal, 0 - active */ + uint8_t game; /* game signal, 0 - active */ + uint8_t ultimax_phi1; /* flag for vic-ii, ultimax mode in phi1 phase */ + uint8_t ultimax_phi2; /* flag for vic-ii, ultimax mode in phi2 phase */ } export_t; +/* this is referenced by the VICII emulation */ extern export_t export; +/* expose public API symbols for those headers that provide them */ #define CARTRIDGE_INCLUDE_PUBLIC_API -#include "expert.h" +#include "dqbb.h" /* needed for x128 */ +#include "expert.h" /* provide defines for ExpertCartridgeMode resource */ +#include "retroreplay.h" /* provide defines for RRrevision resource */ +#include "mmc64.h" /* provide defines for MMC64_sd_type and MMC64_revision resources */ +#include "mmcreplay.h" /* needed for x128, provide defines for MMCRSDType resource */ +#ifdef HAVE_RAWNET +#include "ethernetcart.h" /* provide defines for ETHERNETCARTMode resource */ +#endif #undef CARTRIDGE_INCLUDE_PUBLIC_API +/* the following is used to hook up the c128 mode in x128 */ +#include +#include "cartridge.h" + +#include "snapshot.h" + +struct c128cartridge_interface_s { + int (*attach_crt)(int type, FILE *fd, const char *filename, uint8_t *rawcart); + int (*bin_attach)(int type, const char *filename, uint8_t *rawcart); + int (*bin_save)(int type, const char *filename); + int (*save_secondary_image)(int type, const char *filename); + int (*crt_save)(int type, const char *filename); + int (*flush_image)(int type); + int (*flush_secondary_image)(int type); + void (*config_init)(int type); + void (*config_setup)(int type, uint8_t *rawcart); + void (*detach_image)(int type); + void (*reset)(void); + int (*freeze_allowed)(void); + void (*freeze)(void); + void (*powerup)(void); + cartridge_info_t* (*get_info_list)(void); + int (*can_flush_image)(int type); + int (*can_flush_secondary_image)(int type); + int (*can_save_image)(int type); + int (*can_save_secondary_image)(int type); + int (*snapshot_read)(int type, snapshot_t *s); + int (*snapshot_write)(int type, snapshot_t *s); +}; +typedef struct c128cartridge_interface_s c128cartridge_interface_t; + +extern c128cartridge_interface_t *c128cartridge; /* lives in c64cart.c */ + +/* only x128 actually implements this function */ +void c128cartridge_setup_interface(void); + #endif diff --git a/src/Emulators/vice/c64/c64cia.h b/src/Emulators/vice/c64/c64cia.h index c4b65a94..4b32718a 100644 --- a/src/Emulators/vice/c64/c64cia.h +++ b/src/Emulators/vice/c64/c64cia.h @@ -32,29 +32,29 @@ struct cia_context_s; struct machine_context_s; -extern void cia1_setup_context(struct machine_context_s *machine_context); -extern void cia2_setup_context(struct machine_context_s *machine_context); +void cia1_setup_context(struct machine_context_s *machine_context); +void cia2_setup_context(struct machine_context_s *machine_context); -extern void cia1_init(struct cia_context_s *cia_context); -extern void cia1_store(WORD addr, BYTE value); -extern BYTE cia1_read(WORD addr); -extern BYTE cia1_peek(WORD addr); -extern void cia1_set_extended_keyboard_rows_mask(BYTE value); +void cia1_init(struct cia_context_s *cia_context); +void cia1_store(uint16_t addr, uint8_t value); +uint8_t cia1_read(uint16_t addr); +uint8_t cia1_peek(uint16_t addr); +void cia1_set_extended_keyboard_rows_mask(uint8_t value); -extern void cia2_init(struct cia_context_s *cia_context); -extern void cia2_store(WORD addr, BYTE value); -extern BYTE cia2_read(WORD addr); -extern BYTE cia2_peek(WORD addr); +void cia2_init(struct cia_context_s *cia_context); +void cia2_store(uint16_t addr, uint8_t value); +uint8_t cia2_read(uint16_t addr); +uint8_t cia2_peek(uint16_t addr); -extern void cia2_set_flagx(void); -extern void cia2_set_sdrx(BYTE received_byte); +void cia2_set_flagx(void); +void cia2_set_sdrx(uint8_t received_byte); -extern void cia1_check_lightpen(void); +void cia1_check_lightpen(void); -extern void cia1_update_model(void); -extern void cia2_update_model(void); +void cia1_update_model(void); +void cia2_update_model(void); -extern void cia1_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); -extern void cia2_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); +void cia1_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); +void cia2_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); #endif diff --git a/src/Emulators/vice/c64/c64cia1.c b/src/Emulators/vice/c64/c64cia1.c index cde62ff6..808ecded 100644 --- a/src/Emulators/vice/c64/c64cia1.c +++ b/src/Emulators/vice/c64/c64cia1.c @@ -59,44 +59,49 @@ #include "mouse.h" #endif +#include "vice_debugger_hook.h" + /* #define DEBUG_KBD */ #ifdef DEBUG_KBD +#define DBG(x) printf x #define DBGA(x) printf x #define DBGB(x) printf x #else +#define DBG(x) #define DBGA(x) #define DBGB(x) #endif -static BYTE cia1_cra = 0; +static uint8_t cia1_cra = 0; /* last value written to control register A */ extern int c64d_cia1_register_written; extern int c64d_cia1_register_read; extern unsigned char c64d_cia1_write_value; extern unsigned char c64d_cia1_read_value; -void cia1_store(WORD addr, BYTE data) +void cia1_store(uint16_t addr, uint8_t data) { - c64d_cia1_register_written = addr & 0xf; - c64d_cia1_write_value = data; + VICE_HOOK_CIA1_REG_WRITTEN(addr); + VICE_HOOK_CIA1_WRITE_VALUE(data); if ((addr & 0xf) == CIA_CRA) { cia1_cra = data; + DBG(("cia1_store cra: %02x\n", data)); } ciacore_store(machine_context.cia1, addr, data); } -BYTE cia1_read(WORD addr) +uint8_t cia1_read(uint16_t addr) { BYTE val = ciacore_read(machine_context.cia1, addr); - c64d_cia1_register_read = addr & 0xf; - c64d_cia1_read_value = val; + VICE_HOOK_CIA1_REG_READ(addr); + VICE_HOOK_CIA1_READ_VALUE(val); return val; } -BYTE cia1_peek(WORD addr) +uint8_t cia1_peek(uint16_t addr) { return ciacore_peek(machine_context.cia1, addr); } @@ -122,7 +127,7 @@ static void cia_restore_int(cia_context_t *cia_context, int value) * I/O */ -void cia1_set_extended_keyboard_rows_mask(BYTE value) +void cia1_set_extended_keyboard_rows_mask(uint8_t value) { } @@ -149,11 +154,11 @@ static void do_reset_cia(cia_context_t *cia_context) { } -static void cia1_internal_lightpen_check(BYTE pa, BYTE pb) +static void cia1_internal_lightpen_check(uint8_t pa, uint8_t pb) { - BYTE val = 0xff; - BYTE msk = pa & read_joyport_dig(JOYPORT_2); - BYTE m; + uint8_t val = 0xff; + uint8_t msk = pa & read_joyport_dig(JOYPORT_2); + uint8_t m; int i; if (c64keyboard_active) { @@ -174,7 +179,7 @@ void cia1_check_lightpen(void) cia1_internal_lightpen_check(machine_context.cia1->old_pa, machine_context.cia1->old_pb); } -static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE b) +static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t b) { cia1_internal_lightpen_check(b, machine_context.cia1->old_pb); @@ -183,18 +188,18 @@ static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE b) store_joyport_dig(JOYPORT_2, b, 0xff); } -static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE b) +static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t b) { } -static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { cia1_internal_lightpen_check(machine_context.cia1->old_pa, byte); store_joyport_dig(JOYPORT_1, byte, 0xff); } -static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { } @@ -211,12 +216,12 @@ static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) the toplevel keyboard emulation later, so it can be used by all machines with a similar keyboard matrix. (VIC20, C16 ...) */ -static void matrix_activate_column(int column, BYTE *activerows, BYTE *activecolumns); -static void matrix_activate_row(int row, BYTE *activerows, BYTE *activecolumns); +static void matrix_activate_column(int column, uint8_t *activerows, uint8_t *activecolumns); +static void matrix_activate_row(int row, uint8_t *activerows, uint8_t *activecolumns); -static void matrix_activate_row(int row, BYTE *activerows, BYTE *activecolumns) +static void matrix_activate_row(int row, uint8_t *activerows, uint8_t *activecolumns) { - BYTE msk; + uint8_t msk; int m, i; if ((1 << row) & ~(*activerows)) { @@ -234,9 +239,9 @@ static void matrix_activate_row(int row, BYTE *activerows, BYTE *activecolumns) } } -static void matrix_activate_column(int column, BYTE *activerows, BYTE *activecolumns) +static void matrix_activate_column(int column, uint8_t *activerows, uint8_t *activecolumns) { - BYTE msk; + uint8_t msk; int m, i; if ((1 << column) & ~(*activecolumns)) { @@ -255,37 +260,37 @@ static void matrix_activate_column(int column, BYTE *activerows, BYTE *activecol } /* get all connected rows for one active column */ -inline static BYTE matrix_get_active_rows_by_column(int column) +inline static uint8_t matrix_get_active_rows_by_column(int column) { - BYTE activerows = 0; - BYTE activecolumns = 0; + uint8_t activerows = 0; + uint8_t activecolumns = 0; matrix_activate_column(column, &activerows, &activecolumns); return activerows; } /* get all connected rows for one active row */ -inline static BYTE matrix_get_active_rows_by_row(int row) +inline static uint8_t matrix_get_active_rows_by_row(int row) { - BYTE activerows = 0; - BYTE activecolumns = 0; + uint8_t activerows = 0; + uint8_t activecolumns = 0; matrix_activate_row(row, &activerows, &activecolumns); return activerows; } /* get all connected columns for one active row */ -inline static BYTE matrix_get_active_columns_by_column(int column) +inline static uint8_t matrix_get_active_columns_by_column(int column) { - BYTE activerows = 0; - BYTE activecolumns = 0; + uint8_t activerows = 0; + uint8_t activecolumns = 0; matrix_activate_column(column, &activerows, &activecolumns); return activecolumns; } /* get all connected columns for one active row */ -inline static BYTE matrix_get_active_columns_by_row(int row) +inline static uint8_t matrix_get_active_columns_by_row(int row) { - BYTE activerows = 0; - BYTE activecolumns = 0; + uint8_t activerows = 0; + uint8_t activecolumns = 0; matrix_activate_row(row, &activerows, &activecolumns); return activecolumns; } @@ -299,12 +304,12 @@ inline static BYTE matrix_get_active_columns_by_row(int row) - add improvements also to C128 */ -static BYTE read_ciapa(cia_context_t *cia_context) +static uint8_t read_ciapa(cia_context_t *cia_context) { - BYTE byte; - BYTE val = 0xff; - BYTE msk; - BYTE m, tmp; + uint8_t byte; + uint8_t val = 0xff; + uint8_t msk; + uint8_t m, tmp; int i; DBGA(("PA ddra:%02x pa:%02x ddrb:%02x pb:%02x ", @@ -357,15 +362,13 @@ static BYTE read_ciapa(cia_context_t *cia_context) return byte; } -inline static int ciapb_forcelow(int row, BYTE mask) +inline static int ciapb_forcelow(int row, uint8_t mask) { - BYTE v; + uint8_t v; if (c64keyboard_active) { - /* Check for shift lock. - FIXME: keyboard_shiftlock state may be inconsistent - with the (rev_)keyarr state. */ - if ((row == 1) && keyboard_shiftlock) { + /* Check for shift lock. */ + if ((row == 1) && keyboard_get_shiftlock()) { return 1; } @@ -380,13 +383,13 @@ inline static int ciapb_forcelow(int row, BYTE mask) return 0; } -static BYTE read_ciapb(cia_context_t *cia_context) +static uint8_t read_ciapb(cia_context_t *cia_context) { - BYTE byte; - BYTE val = 0xff; - BYTE val_outhi; - BYTE msk, tmp; - BYTE m; + uint8_t byte; + uint8_t val = 0xff; + uint8_t val_outhi; + uint8_t msk, tmp; + uint8_t m; int i; /* loop over rows, @@ -416,7 +419,7 @@ static BYTE read_ciapb(cia_context_t *cia_context) if ((cia_context->c_cia[CIA_DDRA] & ~cia_context->c_cia[CIA_PRA] & m) && (cia_context->c_cia[CIA_DDRB] & cia_context->c_cia[CIA_PRB] & tmp)) { DBGB(("(%d)", i)); - if (ciapb_forcelow(i, (BYTE)(cia_context->c_cia[CIA_DDRA] & ~cia_context->c_cia[CIA_PRA]))) { + if (ciapb_forcelow(i, (uint8_t)(cia_context->c_cia[CIA_DDRA] & ~cia_context->c_cia[CIA_PRA]))) { val_outhi &= ~tmp; DBGB(("", val_outhi)); } @@ -431,6 +434,7 @@ static BYTE read_ciapb(cia_context_t *cia_context) handles the case when port b is used for both input and output */ msk = cia_context->old_pb & read_joyport_dig(JOYPORT_1); + DBGB((" oldpb: %02x msk: %02x", cia_context->old_pb, msk)); if (c64keyboard_active) { for (m = 0x1, i = 0; i < 8; m <<= 1, i++) { if (!(msk & m)) { @@ -438,6 +442,7 @@ static BYTE read_ciapb(cia_context_t *cia_context) } } } + DBGB((" val:%02x", val)); byte = val & (cia_context->c_cia[CIA_PRB] | ~(cia_context->c_cia[CIA_DDRB])); @@ -462,37 +467,34 @@ static void read_sdr(cia_context_t *cia_context) drive_cpu_execute_all(maincpu_clk); } cia_context->c_cia[CIA_SDR] = read_userport_sp1(cia_context->c_cia[CIA_SDR]); + DBG(("read_sdr sp1: %02x\n", cia_context->c_cia[CIA_SDR])); } -static void store_sdr(cia_context_t *cia_context, BYTE byte) +static void store_sdr(cia_context_t *cia_context, uint8_t byte) { - if ((cia1_cra & 0x59) == 0x51) { + if ((cia1_cra & 0x49) == 0x41) { + DBG(("store_sdr sp1: %02x\n", byte)); store_userport_sp1(byte); } if (c64iec_active) { if (burst_mod == BURST_MOD_CIA1) { - c64fastiec_fast_cpu_write((BYTE)byte); + c64fastiec_fast_cpu_write((uint8_t)byte); } } -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - if (rsuser_enabled) { - rsuser_tx_byte(byte); - } -#endif } void cia1_init(cia_context_t *cia_context) { - ciacore_init(machine_context.cia1, maincpu_alarm_context, maincpu_int_status, maincpu_clk_guard); + ciacore_init(machine_context.cia1, maincpu_alarm_context, maincpu_int_status); } -void cia1_setup_context(machine_context_t *machine_context) +void cia1_setup_context(machine_context_t *machinecontext) { cia_context_t *cia; - machine_context->cia1 = lib_calloc(1, sizeof(cia_context_t)); - cia = machine_context->cia1; + machinecontext->cia1 = lib_calloc(1, sizeof(cia_context_t)); + cia = machinecontext->cia1; cia->prv = NULL; cia->context = NULL; diff --git a/src/Emulators/vice/c64/c64cia2.c b/src/Emulators/vice/c64/c64cia2.c index c9010b6e..df21f986 100644 --- a/src/Emulators/vice/c64/c64cia2.c +++ b/src/Emulators/vice/c64/c64cia2.c @@ -57,20 +57,22 @@ #include "rsuser.h" #endif +#include "vice_debugger_hook.h" + /* Flag for recording port A DDR changes (for c64gluelogic) */ static int pa_ddr_change = 0; -static BYTE cia2_cra = 0; +static uint8_t cia2_cra = 0; extern int c64d_cia2_register_written; extern int c64d_cia2_register_read; extern unsigned char c64d_cia2_write_value; extern unsigned char c64d_cia2_read_value; -void cia2_store(WORD addr, BYTE data) +void cia2_store(uint16_t addr, uint8_t data) { - c64d_cia2_register_written = addr & 0xf; - c64d_cia2_write_value = data; + VICE_HOOK_CIA2_REG_WRITTEN(addr); + VICE_HOOK_CIA2_WRITE_VALUE(data); if ((addr & 0xf) == CIA_CRA) { cia2_cra = data; @@ -85,15 +87,15 @@ void cia2_store(WORD addr, BYTE data) ciacore_store(machine_context.cia2, addr, data); } -BYTE cia2_read(WORD addr) +uint8_t cia2_read(uint16_t addr) { BYTE val = ciacore_read(machine_context.cia2, addr); - c64d_cia2_register_read = addr & 0xf; - c64d_cia2_read_value = val; + VICE_HOOK_CIA2_REG_READ(addr); + VICE_HOOK_CIA2_READ_VALUE(val); return val; } -BYTE cia2_peek(WORD addr) +uint8_t cia2_peek(uint16_t addr) { return ciacore_peek(machine_context.cia2, addr); } @@ -138,15 +140,9 @@ static int vbank; static void do_reset_cia(cia_context_t *cia_context) { - store_userport_pbx(0xff); + store_userport_pbx(0xff, USERPORT_NO_PULSE); store_userport_pa2(1); - /* The functions below will gradually be removed as the functionality is added to the new userport system. */ -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - rsuser_write_ctrl((BYTE)0xff); - rsuser_set_tx_bit(1); -#endif - vbank = 0; c64_glue_reset(); } @@ -166,105 +162,95 @@ static void pre_peek(void) vicii_handle_pending_alarms_external(0); } -static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { if (cia_context->old_pa != byte) { - BYTE tmp; + uint8_t tmp; int new_vbank; if ((cia_context->old_pa ^ byte) & 4) { - store_userport_pa2((BYTE)((byte & 4) >> 2)); + store_userport_pa2((uint8_t)((byte & 4) >> 2)); } if ((cia_context->old_pa ^ byte) & 8) { - store_userport_pa3((BYTE)((byte & 8) >> 3)); + store_userport_pa3((uint8_t)((byte & 8) >> 3)); } -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - if (rsuser_enabled && ((cia_context->old_pa ^ byte) & 0x04)) { - rsuser_set_tx_bit(byte & 4); - } -#endif - tmp = ~byte; + tmp = (uint8_t)~byte; new_vbank = tmp & 3; if (new_vbank != vbank) { vbank = new_vbank; c64_glue_set_vbank(new_vbank, pa_ddr_change); } if (c64iec_active) { - (*iecbus_callback_write)((BYTE)tmp, maincpu_clk + !(cia_context->write_offset)); + /* Bit 7 Serial Bus Data Input + Bit 6 Serial Bus Clock Pulse Input + Bit 5 Serial Bus Data Output + Bit 4 Serial Bus Clock Pulse Output + Bit 3 Serial Bus ATN Signal Output */ + (*iecbus_callback_write)((uint8_t)tmp, maincpu_clk + !(cia_context->write_offset)); } } } -static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { - store_userport_pa2((BYTE)((byte & 4) >> 2)); - store_userport_pa3((BYTE)((byte & 8) >> 3)); + store_userport_pa2((uint8_t)((byte & 4) >> 2)); + store_userport_pa3((uint8_t)((byte & 8) >> 3)); -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - if (rsuser_enabled) { - rsuser_set_tx_bit((int)(byte & 4)); - } -#endif vbank = (byte ^ 3) & 3; c64_glue_undump(vbank); if (c64iec_active) { - iecbus_cpu_undump((BYTE)(byte ^ 0xff)); + iecbus_cpu_undump((uint8_t)(byte ^ 0xff)); } } -static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { - store_userport_pbx(byte); - - /* The functions below will gradually be removed as the functionality is added to the new userport system. */ - parallel_cable_cpu_write(DRIVE_PC_STANDARD, byte); -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - rsuser_write_ctrl(byte); -#endif + store_userport_pbx(byte, USERPORT_NO_PULSE); } static void pulse_ciapc(cia_context_t *cia_context, CLOCK rclk) { - parallel_cable_cpu_pulse(DRIVE_PC_STANDARD); - store_userport_pbx((BYTE)(cia_context->old_pb)); + store_userport_pbx((uint8_t)(cia_context->old_pb), USERPORT_PULSE); } /* FIXME! */ -static inline void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static inline void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { - store_userport_pbx(byte); + store_userport_pbx(byte, USERPORT_NO_PULSE); /* The functions below will gradually be removed as the functionality is added to the new userport system. */ - parallel_cable_cpu_undump(DRIVE_PC_STANDARD, (BYTE)byte); -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - rsuser_write_ctrl((BYTE)byte); -#endif + parallel_cable_cpu_undump(DRIVE_PC_STANDARD, (uint8_t)byte); } /* read_* functions must return 0xff if nothing to read!!! */ -static BYTE read_ciapa(cia_context_t *cia_context) +static uint8_t read_ciapa(cia_context_t *cia_context) { - BYTE value; - BYTE userval; + uint8_t value; + uint8_t userval = 1; value = ((cia_context->c_cia[CIA_PRA] | ~(cia_context->c_cia[CIA_DDRA])) & 0x3f); if (c64iec_active) { + /* Bit 7 Serial Bus Data Input + Bit 6 Serial Bus Clock Pulse Input + Bit 5 Serial Bus Data Output + Bit 4 Serial Bus Clock Pulse Output + Bit 3 Serial Bus ATN Signal Output */ value |= (*iecbus_callback_read)(maincpu_clk); } if (!(cia_context->c_cia[CIA_DDRA] & 4)) { - userval = read_userport_pa2(value); + userval = read_userport_pa2(userval); if (value != userval) { value &= (userval & 1) ? 0xff : 0xfb; } } if (!(cia_context->c_cia[CIA_DDRA] & 8)) { - userval = read_userport_pa3(value); + userval = read_userport_pa3(userval); if (value != userval) { value &= (userval & 1) ? 0xff : 0xf7; } @@ -274,19 +260,11 @@ static BYTE read_ciapa(cia_context_t *cia_context) } /* read_* functions must return 0xff if nothing to read!!! */ -static BYTE read_ciapb(cia_context_t *cia_context) +static uint8_t read_ciapb(cia_context_t *cia_context) { - BYTE byte = 0xff; - - byte = read_userport_pbx((BYTE)~cia_context->c_cia[CIA_DDRB], byte); + uint8_t byte = 0xff; - /* The functions below will gradually be removed as the functionality is added to the new userport system. */ -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - if (rsuser_enabled) { - byte = rsuser_read_ctrl(byte); - } else -#endif - byte = parallel_cable_cpu_read(DRIVE_PC_STANDARD, byte); + byte = read_userport_pbx(byte); byte = (byte & ~(cia_context->c_cia[CIA_DDRB])) | (cia_context->c_cia[CIA_PRB] & cia_context->c_cia[CIA_DDRB]); @@ -309,7 +287,7 @@ static void read_sdr(cia_context_t *cia_context) cia_context->c_cia[CIA_SDR] = read_userport_sp2(cia_context->c_cia[CIA_SDR]); } -static void store_sdr(cia_context_t *cia_context, BYTE byte) +static void store_sdr(cia_context_t *cia_context, uint8_t byte) { if ((cia2_cra & 0x59) == 0x51) { store_userport_sp2(byte); @@ -317,7 +295,7 @@ static void store_sdr(cia_context_t *cia_context, BYTE byte) if (c64iec_active) { if (burst_mod == BURST_MOD_CIA2) { - c64fastiec_fast_cpu_write((BYTE)byte); + c64fastiec_fast_cpu_write((uint8_t)byte); } } } @@ -328,22 +306,22 @@ void cia2_set_flagx(void) ciacore_set_flag(machine_context.cia2); } -void cia2_set_sdrx(BYTE received_byte) +void cia2_set_sdrx(uint8_t received_byte) { ciacore_set_sdr(machine_context.cia2, received_byte); } void cia2_init(cia_context_t *cia_context) { - ciacore_init(machine_context.cia2, maincpu_alarm_context, maincpu_int_status, maincpu_clk_guard); + ciacore_init(machine_context.cia2, maincpu_alarm_context, maincpu_int_status); } -void cia2_setup_context(machine_context_t *machine_context) +void cia2_setup_context(machine_context_t *machinecontext) { cia_context_t *cia; - machine_context->cia2 = lib_calloc(1, sizeof(cia_context_t)); - cia = machine_context->cia2; + machinecontext->cia2 = lib_calloc(1, sizeof(cia_context_t)); + cia = machinecontext->cia2; cia->prv = NULL; cia->context = NULL; diff --git a/src/Emulators/vice/c64/c64cpusc.c b/src/Emulators/vice/c64/c64cpusc.c index de8d8628..14038251 100644 --- a/src/Emulators/vice/c64/c64cpusc.c +++ b/src/Emulators/vice/c64/c64cpusc.c @@ -49,7 +49,10 @@ CLOCK maincpu_clk = 0L; CLOCK maincpu_clk_limit = 0L; CLOCK c64d_maincpu_clk = 0L; -CLOCK c64d_maincpu_current_instruction_clk = 0L; +/* RD debugger clk-display var: kept 32-bit (matches ViceWrapper.h decl + the + unsigned-int C++ getter and the previous/previous2 siblings). VICE 3.10 widened + CLOCK to 64-bit; truncating maincpu_clk here preserves the original 3.1 semantics. */ +unsigned int c64d_maincpu_current_instruction_clk = 0; #define REWIND_FETCH_OPCODE(clock) /*clock-=2*/ @@ -86,7 +89,7 @@ int c64d_c64_instruction_cycle = 0; #if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS -#define opcode_t DWORD +#define opcode_t uint32_t #define p0 (opcode & 0xff) #define p1 ((opcode >> 8) & 0xff) @@ -98,10 +101,10 @@ int c64d_c64_instruction_cycle = 0; #define opcode_t \ struct { \ - BYTE ins; \ + uint8_t ins; \ union { \ - BYTE op8[2]; \ - WORD op16; \ + uint8_t op8[2]; \ + uint16_t op16; \ } op; \ } @@ -136,7 +139,7 @@ int c64d_c64_instruction_cycle = 0; /* HACK: memmap updates for the reg_pc < bank_limit case */ #ifdef FEATURE_CPUMEMHISTORY -#define MEMMAP_UPDATE(addr) memmap_mem_update(addr, 0) +#define MEMMAP_UPDATE(addr) memmap_mem_update(addr, 0, 0) /* FIXME: is this a dummy access or not? */ #else #define MEMMAP_UPDATE(addr) #endif @@ -147,7 +150,7 @@ int c64d_c64_instruction_cycle = 0; do { \ if (((int)reg_pc) < bank_limit) { \ check_ba(); \ - o = (*((DWORD *)(bank_base + reg_pc)) & 0xffffff); \ + o = (*((uint32_t *)(bank_base + reg_pc)) & 0xffffff); \ MEMMAP_UPDATE(reg_pc); \ SET_LAST_OPCODE(p0); \ CLK_INC(); \ @@ -251,21 +254,26 @@ static void check_and_run_alternate_cpu(void) #include "6510core.h" #include "alarm.h" +#include "archdep.h" +#include "autostart.h" #ifdef FEATURE_CPUMEMHISTORY #include "c64pla.h" #endif -#include "clkguard.h" #include "debug.h" +#include "cmdline.h" #include "interrupt.h" +#include "log.h" #include "machine.h" #include "mainc64cpu.h" #include "maincpu.h" +#include "mainlock.h" #include "mem.h" #include "monitor.h" #include "mos6510.h" #include "reu.h" +#include "resources.h" #include "snapshot.h" #include "traps.h" #include "vicetypes.h" @@ -278,6 +286,7 @@ static void check_and_run_alternate_cpu(void) #define EXIT_FAILURE 1 #endif +log_t maincpu_log = LOG_DEFAULT; /* MACHINE_STUFF should define/undef @@ -286,10 +295,14 @@ static void check_and_run_alternate_cpu(void) */ /* ------------------------------------------------------------------------- */ -#ifdef VICE_DEBUG +#if defined (VICE_DEBUG) || defined (FEATURE_CPUMEMHISTORY) CLOCK debug_clk; #endif +CLOCK stolen_cycles; + +static int reu_dma_triggered = 0; + #define NEED_REG_PC /* ------------------------------------------------------------------------- */ @@ -324,164 +337,203 @@ inline static void interrupt_delay(void) static void maincpu_steal_cycles(void) { - interrupt_cpu_status_t *cs = maincpu_int_status; - BYTE opcode; - - if (maincpu_ba_low_flags & MAINCPU_BA_LOW_VICII) { - vicii_steal_cycles(); - maincpu_ba_low_flags &= ~MAINCPU_BA_LOW_VICII; - } - - if (maincpu_ba_low_flags & MAINCPU_BA_LOW_REU) { - reu_dma_start(); - maincpu_ba_low_flags &= ~MAINCPU_BA_LOW_REU; - } - - while (maincpu_clk >= alarm_context_next_pending_clk(maincpu_alarm_context)) { - alarm_context_dispatch(maincpu_alarm_context, maincpu_clk); - } - - /* special handling for steals during opcodes */ - opcode = OPINFO_NUMBER(*cs->last_opcode_info_ptr); - switch (opcode) { - /* SHA */ - case 0x93: - if (check_ba_low) { - OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); - } - break; - - /* SHS */ - case 0x9b: - /* (fall through) */ - /* SHY */ - case 0x9c: - /* (fall through) */ - /* SHX */ - case 0x9e: - /* (fall through) */ - /* SHA */ - case 0x9f: - /* this is a hacky way of signaling SET_ABS_SH_I() that - cycles were stolen before the write */ - if (check_ba_low) { - OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); - } - break; - - /* ANE */ - case 0x8b: - /* this is a hacky way of signaling ANE() that - cycles were stolen after the first fetch */ - /* (fall through) */ - - /* CLI */ - case 0x58: - /* this is a hacky way of signaling CLI() that it - shouldn't delay the interrupt */ - OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); - break; - - default: - break; - } - - /* SEI: do not update interrupt delay counters */ - if (opcode != 0x78) { - if (cs->irq_delay_cycles == 0 && cs->irq_clk < maincpu_clk) { - cs->irq_delay_cycles++; - } - } - - if (cs->nmi_delay_cycles == 0 && cs->nmi_clk < maincpu_clk) { - cs->nmi_delay_cycles++; - } + interrupt_cpu_status_t *cs = maincpu_int_status; + uint8_t opcode; + + if (maincpu_ba_low_flags & MAINCPU_BA_LOW_VICII) { + vicii_steal_cycles(); + maincpu_ba_low_flags &= ~MAINCPU_BA_LOW_VICII; + } + + if (maincpu_ba_low_flags & MAINCPU_BA_LOW_REU) { + reu_dma_start(); + maincpu_ba_low_flags &= ~MAINCPU_BA_LOW_REU; + } + + while (maincpu_clk >= alarm_context_next_pending_clk(maincpu_alarm_context)) { + alarm_context_dispatch(maincpu_alarm_context, maincpu_clk); + } + + /* special handling for steals during opcodes */ + opcode = OPINFO_NUMBER(*cs->last_opcode_info_ptr); + switch (opcode) { + /* SHA */ + case 0x93: + if (check_ba_low) { + OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); + } + break; + + /* SHS */ + case 0x9b: + /* (fall through) */ + /* SHY */ + case 0x9c: + /* (fall through) */ + /* SHX */ + case 0x9e: + /* (fall through) */ + /* SHA */ + case 0x9f: + /* this is a hacky way of signaling SET_ABS_SH_I() that + cycles were stolen before the write */ + if (check_ba_low) { + OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); + } + break; + + /* ANE */ + case 0x8b: + /* this is a hacky way of signaling ANE() that + cycles were stolen after the first fetch */ + /* (fall through) */ + + /* LXA */ + case 0xab: + /* this is a hacky way of signaling LXA() that + cycles were stolen after the first fetch */ + /* (fall through) */ + + /* CLI */ + case 0x58: + /* this is a hacky way of signaling CLI() that it + shouldn't delay the interrupt */ + OPINFO_SET_ENABLES_IRQ(*cs->last_opcode_info_ptr, 1); + break; + + default: + break; + } + + /* SEI: do not update interrupt delay counters */ + if (opcode != 0x78) { + if (cs->irq_delay_cycles == 0 && cs->irq_clk < maincpu_clk) { + cs->irq_delay_cycles++; + } + } + + if (cs->nmi_delay_cycles == 0 && cs->nmi_clk < maincpu_clk) { + cs->nmi_delay_cycles++; + } } inline static void check_ba(void) { - if (maincpu_ba_low_flags) { -#ifdef VICE_DEBUG - CLOCK old_maincpu_clk = maincpu_clk; -#endif - maincpu_steal_cycles(); -#ifdef VICE_DEBUG - if (debug_clk == old_maincpu_clk) { - debug_clk = maincpu_clk; - } + if (maincpu_ba_low_flags) { + CLOCK old_maincpu_clk = maincpu_clk; + + maincpu_steal_cycles(); +#if defined (VICE_DEBUG) || defined (FEATURE_CPUMEMHISTORY) + if (debug_clk == old_maincpu_clk) { + debug_clk = maincpu_clk; + } #endif - } + + stolen_cycles += maincpu_clk - old_maincpu_clk; + } } #ifdef FEATURE_CPUMEMHISTORY /* FIXME do proper ROM/RAM/IO tests */ -inline static void memmap_mem_update(unsigned int addr, int write) +/* this is called per memory access, so it should only do whats really needed */ +inline static void memmap_mem_update(unsigned int addr, int write, int dummy) { - unsigned int type = MEMMAP_RAM_R; - - if (write) { - if ((addr >= 0xd000) && (addr <= 0xdfff)) { - type = MEMMAP_I_O_W; - } else { - type = MEMMAP_RAM_W; - } - } else { - switch (addr >> 12) { - case 0xa: - case 0xb: - case 0xe: - case 0xf: - if (pport.data_read & (1 << ((addr >> 14) & 1))) { - type = MEMMAP_ROM_R; - } else { - type = MEMMAP_RAM_R; - } - break; - case 0xd: - type = MEMMAP_I_O_R; - break; - default: - type = MEMMAP_RAM_R; - break; - } - if (memmap_state & MEMMAP_STATE_OPCODE) { - /* HACK: transform R to X */ - type >>= 2; - memmap_state &= ~(MEMMAP_STATE_OPCODE); - } else if (memmap_state & MEMMAP_STATE_INSTR) { - /* ignore operand reads */ - type = 0; - } - } - monitor_memmap_store(addr, type); + unsigned int type = MEMMAP_RAM_R; + + if (write) { + if ((addr >= 0xd000) && (addr <= 0xdfff)) { + type = MEMMAP_I_O_W; + } else { + type = MEMMAP_RAM_W; + } + } else { + switch (addr >> 12) { + case 0xa: + case 0xb: + case 0xe: + case 0xf: + if (pport.data_read & (1 << ((addr >> 14) & 1))) { + type = MEMMAP_ROM_R; + } else { + type = MEMMAP_RAM_R; + } + break; + case 0xd: + type = MEMMAP_I_O_R; + break; + default: + type = MEMMAP_RAM_R; + break; + } + if (memmap_state & MEMMAP_STATE_OPCODE) { + /* HACK: transform R to X */ + type >>= 2; + memmap_state &= ~(MEMMAP_STATE_OPCODE); +#if 0 + } else if (memmap_state & MEMMAP_STATE_INSTR) { + /* ignore operand reads */ + type = 0; +#endif + } + if (dummy == 0) { + type |= MEMMAP_REGULAR_READ; + } + } + monitor_memmap_store(addr, type); } -void memmap_mem_store(unsigned int addr, unsigned int value) +static void memmap_mem_store(unsigned int addr, unsigned int value) { - memmap_mem_update(addr, 1); - - c64d_mark_c64_cell_write(addr, value); + memmap_mem_update(addr, 1, 0); - (*_mem_write_tab_ptr[(addr) >> 8])((WORD)(addr), (BYTE)(value)); + c64d_mark_c64_cell_write(addr, value); + + (*_mem_write_tab_ptr[(addr) >> 8])((uint16_t)(addr), (uint8_t)(value)); +} + +static void memmap_mem_store_dummy(unsigned int addr, unsigned int value) +{ + memmap_mem_update(addr, 1, 1); + (*_mem_write_tab_ptr_dummy[(addr) >> 8])((uint16_t)(addr), (uint8_t)(value)); } /* read byte, check BA and mark as read */ -BYTE memmap_mem_read(unsigned int addr) +static uint8_t memmap_mem_read(unsigned int addr) { - check_ba(); - - memmap_mem_update(addr, 0); - - c64d_mark_c64_cell_read(addr); + check_ba(); + memmap_mem_update(addr, 0, 0); + + c64d_mark_c64_cell_read(addr); - return (*_mem_read_tab_ptr[(addr) >> 8])((WORD)(addr)); + return (*_mem_read_tab_ptr[(addr) >> 8])((uint16_t)(addr)); +} + +static uint8_t memmap_mem_read_dummy(unsigned int addr) +{ + check_ba(); + memmap_mem_update(addr, 0, 1); + return (*(_mem_read_tab_ptr_dummy[(addr) >> 8]))((uint16_t)(addr)); } #ifndef STORE #define STORE(addr, value) \ -memmap_mem_store(addr, value) + if (reu_dma_triggered == 0) { \ + memmap_mem_store(addr, value); \ + if (addr == 0xff00) { \ + reu_dma(-1); \ + } \ + } \ + reu_dma_triggered = 0 +#endif + +#ifndef STORE_DUMMY +#define STORE_DUMMY(addr, value) \ + memmap_mem_store_dummy(addr, value); \ + if (addr == 0xff00) { \ + reu_dma_triggered = reu_dma(-1); \ + } #endif #ifndef LOAD @@ -489,11 +541,23 @@ memmap_mem_store(addr, value) memmap_mem_read(addr) #endif +#ifndef LOAD_DUMMY +#define LOAD_DUMMY(addr) \ + memmap_mem_read_dummy(addr) +#endif + #ifndef LOAD_CHECK_BA_LOW #define LOAD_CHECK_BA_LOW(addr) \ -check_ba_low = 1; \ -memmap_mem_read(addr); \ -check_ba_low = 0 + check_ba_low = 1; \ + memmap_mem_read(addr);\ + check_ba_low = 0 +#endif + +#ifndef LOAD_CHECK_BA_LOW_DUMMY +#define LOAD_CHECK_BA_LOW_DUMMY(addr) \ + check_ba_low = 1; \ + memmap_mem_read_dummy(addr);\ + check_ba_low = 0 #endif #ifndef STORE_ZERO @@ -501,16 +565,26 @@ check_ba_low = 0 memmap_mem_store((addr) & 0xff, value) #endif +#ifndef STORE_ZERO_DUMMY +#define STORE_ZERO_DUMMY(addr, value) \ + memmap_mem_store_dummy((addr) & 0xff, value) +#endif + #ifndef LOAD_ZERO #define LOAD_ZERO(addr) \ memmap_mem_read((addr) & 0xff) #endif +#ifndef LOAD_ZERO_DUMMY +#define LOAD_ZERO_DUMMY(addr) \ + memmap_mem_read_dummy((addr) & 0xff) +#endif + /* Route stack operations through memmap */ -#define PUSH(val) memmap_mem_store((0x100 + (reg_sp--)), (BYTE)(val)) +#define PUSH(val) memmap_mem_store((0x100 + (reg_sp--)), (uint8_t)(val)) #define PULL() memmap_mem_read(0x100 + (++reg_sp)) -#define STACK_PEEK() memmap_mem_read(0x100 + reg_sp) +#define STACK_PEEK() memmap_mem_read_dummy(0x100 + reg_sp) /* Stack annotation: after PUSH, reg_sp has been decremented, so the pushed byte is at reg_sp+1 */ #define C64D_ANNOTATE_PUSH(entry_type, irq_source, origin) \ @@ -527,32 +601,33 @@ static int c64d_irq_flag_needs_clear = 0; #endif /* FEATURE_CPUMEMHISTORY */ -inline static BYTE mem_read_check_ba(unsigned int addr) +inline static uint8_t mem_read_check_ba(unsigned int addr) +{ + check_ba(); + return (*_mem_read_tab_ptr[(addr) >> 8])((uint16_t)(addr)); +} + +inline static uint8_t mem_read_check_ba_dummy(unsigned int addr) { - //LOGD("mem_read_check_ba: %4.4x", addr); - check_ba(); - - c64d_mark_c64_cell_read(addr); - - return (*_mem_read_tab_ptr[(addr) >> 8])((WORD)(addr)); + return (*(_mem_read_tab_ptr_dummy[(addr) >> 8]))((uint16_t)(addr)); } inline static void c64d_mem_store(unsigned int addr, unsigned char value) { //LOGD("c64d_mem_store: %4.4x %2.2x", addr, value); - + c64d_mark_c64_cell_write(addr, value); - + (*_mem_write_tab_ptr[(addr) >> 8])((WORD)(addr), (BYTE)(value)); } inline static void c64d_mem_store_zero(unsigned int addr, unsigned char value) { //LOGD("c64d_mem_store_zero: %4.4x %2.2x", addr, value); - + c64d_mark_c64_cell_write(addr, value); - + (*_mem_write_tab_ptr[0])((WORD)(addr), (BYTE)(value)); } @@ -568,7 +643,21 @@ void c64d_mem_write_c64_no_mark(unsigned int addr, unsigned char value) #ifndef STORE #define STORE(addr, value) \ -c64d_mem_store((WORD)(addr), (BYTE)(value)); + if (reu_dma_triggered == 0) { \ + c64d_mem_store((uint16_t)(addr), (uint8_t)(value)); \ + if (addr == 0xff00) { \ + reu_dma(-1); \ + } \ + } \ + reu_dma_triggered = 0 +#endif + +#ifndef STORE_DUMMY +#define STORE_DUMMY(addr, value) \ + (*_mem_write_tab_ptr_dummy[(addr) >> 8])((uint16_t)(addr), (uint8_t)(value)); \ + if (addr == 0xff00) { \ + reu_dma_triggered = reu_dma(-1); \ + } #endif #ifndef LOAD @@ -576,6 +665,11 @@ c64d_mem_store((WORD)(addr), (BYTE)(value)); mem_read_check_ba(addr) #endif +#ifndef LOAD_DUMMY +#define LOAD_DUMMY(addr) \ + mem_read_check_ba_dummy(addr) +#endif + #ifndef LOAD_CHECK_BA_LOW #define LOAD_CHECK_BA_LOW(addr) \ check_ba_low = 1; \ @@ -583,9 +677,21 @@ mem_read_check_ba(addr); \ check_ba_low = 0 #endif +#ifndef LOAD_CHECK_BA_LOW_DUMMY +#define LOAD_CHECK_BA_LOW_DUMMY(addr) \ + check_ba_low = 1; \ + mem_read_check_ba_dummy(addr); \ + check_ba_low = 0 +#endif + #ifndef STORE_ZERO #define STORE_ZERO(addr, value) \ -c64d_mem_store_zero(addr, value); + c64d_mem_store_zero(addr, value) +#endif + +#ifndef STORE_ZERO_DUMMY +#define STORE_ZERO_DUMMY(addr, value) \ + (*_mem_write_tab_ptr_dummy[0])((uint16_t)(addr), (uint8_t)(value)) #endif #ifndef LOAD_ZERO @@ -593,10 +699,15 @@ c64d_mem_store_zero(addr, value); mem_read_check_ba((addr) & 0xff) #endif +#ifndef LOAD_ZERO_DUMMY +#define LOAD_ZERO_DUMMY(addr) \ + mem_read_check_ba_dummy((addr) & 0xff) +#endif + /* Route stack operations through read/write handlers */ #ifndef PUSH -#define PUSH(val) (*_mem_write_tab_ptr[0x01])((WORD)(0x100 + (reg_sp--)), (BYTE)(val)) +#define PUSH(val) (*_mem_write_tab_ptr[0x01])((uint16_t)(0x100 + (reg_sp--)), (uint8_t)(val)) #endif #ifndef PULL @@ -604,7 +715,7 @@ mem_read_check_ba((addr) & 0xff) #endif #ifndef STACK_PEEK -#define STACK_PEEK() mem_read_check_ba(0x100 + reg_sp) +#define STACK_PEEK() mem_read_check_ba_dummy(0x100 + reg_sp) #endif #ifndef DMA_FUNC @@ -632,7 +743,6 @@ static void maincpu_generic_dma(void) struct interrupt_cpu_status_s *maincpu_int_status = NULL; alarm_context_t *maincpu_alarm_context = NULL; -clk_guard_t *maincpu_clk_guard = NULL; monitor_interface_t *maincpu_monitor_interface = NULL; /* This flag is an obsolete optimization. It's always 0 for the x64sc CPU, @@ -675,6 +785,60 @@ const CLOCK maincpu_opcode_write_cycles[] = { the values copied into this struct. */ mos6510_regs_t maincpu_regs; +static int maincpu_jammed = 0; + +/* ------------------------------------------------------------------------- */ + +static int ane_log_level = 0; /* 0: none, 1: unstable only 2: all */ +static int lxa_log_level = 0; /* 0: none, 1: unstable only 2: all */ + +static int set_ane_log_level(int val, void *param) +{ + if ((val < 0) || (val > 2)) { + return -1; + } + ane_log_level = val; + return 0; +} + +static int set_lxa_log_level(int val, void *param) +{ + if ((val < 0) || (val > 2)) { + return -1; + } + lxa_log_level = val; + return 0; +} + +static const resource_int_t maincpu_resources_int[] = { + { "LogLevelANE", 0, RES_EVENT_NO, NULL, + &ane_log_level, set_ane_log_level, NULL }, + { "LogLevelLXA", 0, RES_EVENT_NO, NULL, + &lxa_log_level, set_lxa_log_level, NULL }, + RESOURCE_INT_LIST_END +}; + +int maincpu_resources_init(void) +{ + return resources_register_int(maincpu_resources_int); +} + +static const cmdline_option_t cmdline_options_maincpu[] = +{ + { "-aneloglevel", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LogLevelANE", NULL, + "", "Set ANE log level: (0: None, 1: Unstable, 2: All)" }, + { "-lxaloglevel", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LogLevelLXA", NULL, + "", "Set LXA log level: (0: None, 1: Unstable, 2: All)" }, + CMDLINE_LIST_END +}; + +int maincpu_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options_maincpu); +} + /* ------------------------------------------------------------------------- */ monitor_interface_t *maincpu_monitor_interface_get(void) @@ -690,12 +854,21 @@ monitor_interface_t *maincpu_monitor_interface_get(void) maincpu_monitor_interface->clk = &maincpu_clk; maincpu_monitor_interface->current_bank = 0; + maincpu_monitor_interface->current_bank_index = 0; + maincpu_monitor_interface->mem_bank_list = mem_bank_list; + maincpu_monitor_interface->mem_bank_list_nos = mem_bank_list_nos; + maincpu_monitor_interface->mem_bank_from_name = mem_bank_from_name; + maincpu_monitor_interface->mem_bank_index_from_bank = mem_bank_index_from_bank; + maincpu_monitor_interface->mem_bank_flags_from_bank = mem_bank_flags_from_bank; + maincpu_monitor_interface->mem_bank_read = mem_bank_read; maincpu_monitor_interface->mem_bank_peek = mem_bank_peek; + maincpu_monitor_interface->mem_peek_with_config = mem_peek_with_config; maincpu_monitor_interface->mem_bank_write = mem_bank_write; - + maincpu_monitor_interface->mem_bank_poke = mem_bank_poke; + maincpu_monitor_interface->mem_ioreg_list_get = mem_ioreg_list_get; maincpu_monitor_interface->toggle_watchpoints_func = mem_toggle_watchpoints; @@ -711,12 +884,14 @@ monitor_interface_t *maincpu_monitor_interface_get(void) void maincpu_early_init(void) { maincpu_int_status = interrupt_cpu_status_new(); + + maincpu_log = log_open("Main CPU"); } void maincpu_init(void) { interrupt_cpu_status_init(maincpu_int_status, &last_opcode_info); - + /* cpu specifix additional init routine */ CPU_ADDITIONAL_INIT(); } @@ -1245,9 +1420,14 @@ void maincpu_mainloop(void) o_bank_start = &bank_start; o_bank_limit = &bank_limit; - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); - + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); + while (c64d_vice_run_emulation) { +#define CPU_LOG_ID maincpu_log +#define ANE_LOG_LEVEL ane_log_level +#define LXA_LOG_LEVEL lxa_log_level +#define CPU_IS_JAMMED maincpu_jammed +#define ORIGIN_MEMSPACE (e_comp_space) #define CLK maincpu_clk #define RMW_FLAG maincpu_rmw_flag #define LAST_OPCODE_INFO last_opcode_info @@ -1267,78 +1447,95 @@ void maincpu_mainloop(void) #define ROM_TRAP_HANDLER() traps_handler() #define JAM() \ -do { \ -unsigned int tmp; \ -\ -EXPORT_REGISTERS(); \ + do { \ + unsigned int tmp; \ + \ + EXPORT_REGISTERS(); \ LOGError("CPU JAM: PC=%04x opcode=%x LAST_OPCODE_ADDR=%04x debug_iterations_after_restore=%d debug_prev_iteration_pc=%04x", reg_pc, opcode, LAST_OPCODE_ADDR, debug_iterations_after_restore, debug_prev_iteration_pc); \ -tmp = machine_jam(" " CPU_STR ": JAM at $%04X ", reg_pc); \ -switch (tmp) { \ -case JAM_RESET: \ -DO_INTERRUPT(IK_RESET); \ -break; \ -case JAM_HARD_RESET: \ -mem_powerup(); \ -DO_INTERRUPT(IK_RESET); \ -break; \ -case JAM_MONITOR: \ -monitor_startup(e_comp_space); \ -IMPORT_REGISTERS(); \ -break; \ -default: \ -CLK_INC(); \ -} \ -} while (0) - + tmp = machine_jam(" " CPU_STR ": JAM at $%04X ", reg_pc); \ + switch (tmp) { \ + case JAM_RESET_CPU: \ + DO_INTERRUPT(IK_RESET); \ + break; \ + case JAM_POWER_CYCLE: \ + machine_powerup(); \ + DO_INTERRUPT(IK_RESET); \ + break; \ + case JAM_MONITOR: \ + monitor_startup(e_comp_space); \ + IMPORT_REGISTERS(); \ + break; \ + default: \ + CLK_INC(); \ + } \ + } while (0) + #define CALLER e_comp_space - -#define ROM_TRAP_ALLOWED() mem_rom_trap_allowed((WORD)reg_pc) - + +#define ROM_TRAP_ALLOWED() mem_rom_trap_allowed((uint16_t)reg_pc) + #define GLOBAL_REGS maincpu_regs //#include "6510dtvcore.c" - /* - * 6510dtvcore.c - Cycle based 6510 emulation core. - * - * Written by - * Ettore Perazzoli - * Andreas Boose - * - * DTV sections written by - * M.Kiesel - * Hannu Nuotio - * - * Cycle based rewrite by - * Hannu Nuotio - * - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - - /* This file is included by (some) CPU definition files */ - /* (mainc64cpu.c, mainviccpu.c) */ - +/* + * 6510dtvcore.c - Cycle based 6510 emulation core. + * + * Written by + * Ettore Perazzoli + * Andreas Boose + * + * DTV sections written by + * M.Kiesel + * Hannu Nuotio + * + * Cycle based rewrite by + * Hannu Nuotio + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* This file is included by (some) CPU definition files */ +/* vic20cpu.c->mainviccpu.c + c64sccpu.c->mainc64cpu.c +*/ + +#ifdef DRIVE_CPU +#define CPU_STR "Drive CPU" +#else #define CPU_STR "Main CPU" - +#endif + +#ifndef CPU_LOG_ID +#define CPU_LOG_ID LOG_DEFAULT +#ifdef _MSC_VER +#pragma message ("Warning: CPU_LOG_ID not defined, using LOG_DEFAULT by default") +#else +#warning "CPU_LOG_ID not defined, using LOG_DEFAULT by default" +#endif +#endif + #include "traps.h" - + +#include "profiler.h" + #ifndef C64DTV /* The C64DTV can use different shadow registers for accu read/write. */ /* For standard 6510, this is not the case. */ @@ -1537,7 +1734,35 @@ JUMP(GLOBAL_REGS.pc); \ } while (0) #endif /* C64DTV */ - + +#if !defined(DRIVE_CPU) +#define CHECK_PROFILE_INTERRUPT(dest_addr, handler) \ + do { \ + profile_int(dest_addr, handler, reg_sp + 1, CLK - profiling_clock_start); \ + } while (0) + +#define CHECK_PROFILE_JSR(dest_addr) \ + do { \ + profile_jsr(dest_addr, reg_pc, reg_sp); \ + } while (0) + +#define CHECK_PROFILE_RTS() \ + do { \ + profile_rtx(reg_sp); \ + } while (0) + +#define CHECK_PROFILE_RTI() \ + do { \ + profile_rtx(reg_sp + 1); \ + } while (0) + +#else +#define CHECK_PROFILE_INTERRUPT(dest_addr, handler) +#define CHECK_PROFILE_JSR(dest_addr) +#define CHECK_PROFILE_RTS() +#define CHECK_PROFILE_RTI() +#endif + #ifdef VICE_DEBUG #define TRACE_NMI() \ do { \ @@ -1567,223 +1792,225 @@ debug_text("*** BRK"); \ /* Do the IRQ/BRK sequence, including NMI transformation. */ #define DO_IRQBRK() \ -do { \ -/* Interrupt vector to use. Assume regular IRQ/BRK. */ \ -WORD handler_vector = 0xfffe; \ -\ -PUSH(reg_pc >> 8); \ -C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -CLK_INC(); \ -PUSH(reg_pc & 0xff); \ -C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base + 1, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -CLK_INC(); \ -PUSH(LOCAL_STATUS()); \ -C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base + 2, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -CLK_INC(); \ -\ -/* Process alarms up to this point to get nmi_clk updated. */ \ -while (CLK >= alarm_context_next_pending_clk(ALARM_CONTEXT)) { \ -alarm_context_dispatch(ALARM_CONTEXT, CLK); \ -} \ -\ -/* If an NMI would occur at this cycle... */ \ -if ((CPU_INT_STATUS->global_pending_int & IK_NMI) && (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ -/* Transform the IRQ/BRK into an NMI. Re-annotate the already-pushed bytes. */ \ -handler_vector = 0xfffa; \ -if (c64d_main_cpu_stack_entry_types) { \ - c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ - c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ - c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ -} \ -TRACE_NMI(); \ -if (monitor_mask[CALLER] & (MI_STEP)) { \ -monitor_check_icount_interrupt(); \ -} \ -interrupt_ack_nmi(CPU_INT_STATUS); \ -} \ -\ -LOCAL_SET_INTERRUPT(1); \ -addr = LOAD(handler_vector); \ -CLK_INC(); \ -addr |= (LOAD(handler_vector + 1) << 8); \ -CLK_INC(); \ -JUMP(addr); \ -} while (0) - - /* Perform the interrupts in `int_kind'. If we have both NMI and IRQ, + do { \ + /* Interrupt vector to use. Assume regular IRQ/BRK. */ \ + uint16_t handler_vector = 0xfffe; \ + \ + PUSH(reg_pc >> 8); \ + C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + PUSH(reg_pc & 0xff); \ + C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base + 1, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + PUSH(LOCAL_STATUS()); \ + C64D_ANNOTATE_PUSH(c64d_irqbrk_entry_type_base + 2, c64d_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + \ + /* Process alarms up to this point to get nmi_clk updated. */ \ + while (CLK >= alarm_context_next_pending_clk(ALARM_CONTEXT)) { \ + alarm_context_dispatch(ALARM_CONTEXT, CLK); \ + } \ + \ + /* If an NMI would occur at this cycle... */ \ + if ((CPU_INT_STATUS->global_pending_int & IK_NMI) && (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ + /* Transform the IRQ/BRK into an NMI. Re-annotate the already-pushed bytes. */ \ + handler_vector = 0xfffa; \ + if (c64d_main_cpu_stack_entry_types) { \ + c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ + c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ + c64d_main_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ + } \ + TRACE_NMI(); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_nmi(CPU_INT_STATUS); \ + } \ + \ + LOCAL_SET_INTERRUPT(1); \ + addr = LOAD(handler_vector); \ + CLK_INC(); \ + addr |= (LOAD(handler_vector + 1) << 8); \ + CLK_INC(); \ + CHECK_PROFILE_INTERRUPT(addr, handler_vector); \ + JUMP(addr); \ + } while (0) + +/* Perform the interrupts in `int_kind'. If we have both NMI and IRQ, execute NMI. */ /* FIXME: LOCAL_STATUS() should check byte ready first. */ #define DO_INTERRUPT(int_kind) \ - do { \ - BYTE ik = (int_kind); \ - WORD addr; \ - \ - if (ik & (IK_IRQ | IK_IRQPEND | IK_NMI)) { \ - if ((ik & IK_NMI) \ - && interrupt_check_nmi_delay(CPU_INT_STATUS, CLK)) { \ - TRACE_NMI(); \ - if (monitor_mask[CALLER] & (MI_STEP)) { \ - monitor_check_icount_interrupt(); \ - } \ - interrupt_ack_nmi(CPU_INT_STATUS); \ - if (!SKIP_CYCLE) { \ - LOAD(reg_pc); \ - CLK_INC(); \ - LOAD(reg_pc); \ - CLK_INC(); \ - } \ - LOCAL_SET_BREAK(0); \ - { uint8_t nmi_src = (machine_context.cia2->c64d_irq_flag) ? \ - C64D_IRQ_SOURCE_CIA2_NMI : C64D_IRQ_SOURCE_UNKNOWN; \ - machine_context.cia2->c64d_irq_flag = 0; \ - PUSH(reg_pc >> 8); \ - C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_PCH, nmi_src, LAST_OPCODE_ADDR); \ - CLK_INC(); \ - PUSH(reg_pc & 0xff); \ - C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_PCL, nmi_src, LAST_OPCODE_ADDR); \ - CLK_INC(); \ - PUSH(LOCAL_STATUS()); \ - C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_STATUS, nmi_src, LAST_OPCODE_ADDR); \ - CLK_INC(); } \ - addr = LOAD(0xfffa); \ - CLK_INC(); \ - addr |= (LOAD(0xfffb) << 8); \ - CLK_INC(); \ - LOCAL_SET_INTERRUPT(1); \ - JUMP(addr); \ - SET_LAST_OPCODE(0); \ - } else if ((ik & (IK_IRQ | IK_IRQPEND)) \ - && (!LOCAL_INTERRUPT() \ - || OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ - && interrupt_check_irq_delay(CPU_INT_STATUS, CLK)) { \ - TRACE_IRQ(); \ - if (monitor_mask[CALLER] & (MI_STEP)) { \ - monitor_check_icount_interrupt(); \ - } \ - interrupt_ack_irq(CPU_INT_STATUS); \ - if (!SKIP_CYCLE) { \ - LOAD(reg_pc); \ - CLK_INC(); \ - LOAD(reg_pc); \ - CLK_INC(); \ - } \ - LOCAL_SET_BREAK(0); \ - c64d_irqbrk_entry_type_base = C64D_STACK_ENTRY_IRQ_PCH; \ - c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ - if (vicii.c64d_irq_flag) \ - c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_VIC; \ - else if (machine_context.cia1->c64d_irq_flag) \ - c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_CIA1; \ - c64d_irq_flag_needs_clear = 1; \ - DO_IRQBRK(); \ - SET_LAST_OPCODE(0); \ - } \ - } \ - if (ik & (IK_TRAP | IK_RESET)) { \ - if (ik & IK_TRAP) { \ - EXPORT_REGISTERS(); \ - interrupt_do_trap(CPU_INT_STATUS, (WORD)reg_pc); \ - IMPORT_REGISTERS(); \ - if (CPU_INT_STATUS->global_pending_int & IK_RESET) { \ - ik |= IK_RESET; \ - } \ - } \ - if (ik & IK_RESET) { \ - interrupt_ack_reset(CPU_INT_STATUS); \ - cpu_reset(); \ - addr = LOAD(0xfffc); \ - addr |= (LOAD(0xfffd) << 8); \ - bank_start = bank_limit = 0; /* prevent caching */ \ - JUMP(addr); \ - DMA_ON_RESET; \ - } \ - } \ - if (ik & (IK_MONITOR | IK_DMA)) { \ - if (ik & IK_MONITOR) { \ - if (monitor_force_import(CALLER)) { \ - IMPORT_REGISTERS(); \ - } \ - if (monitor_mask[CALLER]) { \ - EXPORT_REGISTERS(); \ - } \ - if (monitor_mask[CALLER] & (MI_STEP)) { \ - monitor_check_icount((WORD)reg_pc); \ - IMPORT_REGISTERS(); \ - } \ - if (monitor_mask[CALLER] & (MI_BREAK)) { \ - if (monitor_check_breakpoints(CALLER, (WORD)reg_pc)) { \ - monitor_startup(CALLER); \ - IMPORT_REGISTERS(); \ - } \ - } \ - if (monitor_mask[CALLER] & (MI_WATCH)) { \ - monitor_check_watchpoints(LAST_OPCODE_ADDR, (WORD)reg_pc); \ - IMPORT_REGISTERS(); \ - } \ - } \ - if (ik & IK_DMA) { \ - EXPORT_REGISTERS(); \ - DMA_FUNC; \ - interrupt_ack_dma(CPU_INT_STATUS); \ - IMPORT_REGISTERS(); \ - } \ - } \ -} while (0) - - /* ------------------------------------------------------------------------- */ - - /* Addressing modes. For convenience, page boundary crossing cycles and + do { \ + uint8_t ik = (int_kind); \ + uint16_t addr; \ + \ + if (ik & (IK_IRQ | IK_IRQPEND | IK_NMI)) { \ + if ((ik & IK_NMI) \ + && interrupt_check_nmi_delay(CPU_INT_STATUS, CLK)) { \ + TRACE_NMI(); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_nmi(CPU_INT_STATUS); \ + if (!SKIP_CYCLE) { \ + LOAD_DUMMY(reg_pc); /* dummy reads */ \ + CLK_INC(); \ + LOAD_DUMMY(reg_pc); \ + CLK_INC(); \ + } \ + LOCAL_SET_BREAK(0); \ + { uint8_t nmi_src = (machine_context.cia2->c64d_irq_flag) ? \ + C64D_IRQ_SOURCE_CIA2_NMI : C64D_IRQ_SOURCE_UNKNOWN; \ + machine_context.cia2->c64d_irq_flag = 0; \ + PUSH(reg_pc >> 8); \ + C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_PCH, nmi_src, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + PUSH(reg_pc & 0xff); \ + C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_PCL, nmi_src, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + PUSH(LOCAL_STATUS()); \ + C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_NMI_STATUS, nmi_src, LAST_OPCODE_ADDR); \ + CLK_INC(); } \ + addr = LOAD(0xfffa); \ + CLK_INC(); \ + addr |= (LOAD(0xfffb) << 8); \ + CLK_INC(); \ + LOCAL_SET_INTERRUPT(1); \ + CHECK_PROFILE_INTERRUPT(addr, 0xfffb); \ + JUMP(addr); \ + SET_LAST_OPCODE(0); \ + } else if ((ik & (IK_IRQ | IK_IRQPEND)) \ + && (!LOCAL_INTERRUPT() \ + || OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ + && interrupt_check_irq_delay(CPU_INT_STATUS, CLK)) { \ + TRACE_IRQ(); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_irq(CPU_INT_STATUS); \ + if (!SKIP_CYCLE) { \ + LOAD_DUMMY(reg_pc); /* dummy reads */ \ + CLK_INC(); \ + LOAD_DUMMY(reg_pc); \ + CLK_INC(); \ + } \ + LOCAL_SET_BREAK(0); \ + c64d_irqbrk_entry_type_base = C64D_STACK_ENTRY_IRQ_PCH; \ + c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ + if (vicii.c64d_irq_flag) \ + c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_VIC; \ + else if (machine_context.cia1->c64d_irq_flag) \ + c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_CIA1; \ + c64d_irq_flag_needs_clear = 1; \ + DO_IRQBRK(); \ + SET_LAST_OPCODE(0); \ + } \ + } \ + if (ik & (IK_TRAP | IK_RESET)) { \ + if (ik & IK_TRAP) { \ + EXPORT_REGISTERS(); \ + interrupt_do_trap(CPU_INT_STATUS, (uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + if (CPU_INT_STATUS->global_pending_int & IK_RESET) { \ + ik |= IK_RESET; \ + } \ + } \ + if (ik & IK_RESET) { \ + interrupt_ack_reset(CPU_INT_STATUS); \ + cpu_reset(); \ + addr = LOAD(0xfffc); \ + addr |= (LOAD(0xfffd) << 8); \ + bank_start = bank_limit = 0; /* prevent caching */ \ + LOCAL_SET_INTERRUPT(1); \ + CPU_IS_JAMMED = 0; \ + CHECK_PROFILE_INTERRUPT(addr, 0xfffc); \ + JUMP(addr); \ + DMA_ON_RESET; \ + } \ + } \ + if (ik & (IK_MONITOR | IK_DMA)) { \ + if (ik & IK_MONITOR) { \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + EXPORT_REGISTERS(); \ + monitor_check_icount((uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_BREAK)) { \ + EXPORT_REGISTERS(); \ + if (monitor_check_breakpoints(CALLER, (uint16_t)reg_pc)) { \ + monitor_startup(CALLER); \ + } \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_WATCH)) { \ + EXPORT_REGISTERS(); \ + monitor_check_watchpoints(LAST_OPCODE_ADDR, (uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + } \ + if (ik & IK_DMA) { \ + EXPORT_REGISTERS(); \ + DMA_FUNC; \ + interrupt_ack_dma(CPU_INT_STATUS); \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + +/* ------------------------------------------------------------------------- */ + +/* Addressing modes. For convenience, page boundary crossing cycles and ``idle'' memory reads are handled here as well. */ #define GET_TEMP(dest) dest = new_value; - -#define GET_IMM(dest) dest = (BYTE)(p1); - /* same as above, for NOOP */ + +#define GET_IMM(dest) dest = (uint8_t)(p1); +/* same as above, for NOOP */ #define GET_IMM_DUMMY() - -#define GET_ABS(dest) \ -dest = (BYTE)(LOAD(p2)); \ -CLK_INC(); - - /* same as above, for NOOP */ + +#define GET_ABS(dest) \ + dest = (uint8_t)(LOAD(p2)); \ + CLK_INC(); + +/* same as above, for NOOP */ #define GET_ABS_DUMMY() \ -LOAD(p2); \ -CLK_INC(); - + LOAD_DUMMY(p2); \ + CLK_INC(); + #define SET_ABS(value) \ STORE(p2, value); \ CLK_INC(); #define SET_ABS_RMW(old_value, new_value) \ -if (!SKIP_CYCLE) { \ -STORE(p2, old_value); \ -CLK_INC(); \ -} \ -STORE(p2, new_value); \ -CLK_INC(); - -#define INT_ABS_I_R(reg_i) \ -if (!SKIP_CYCLE && ((((p2) & 0xff) + reg_i) > 0xff)) { \ -LOAD((((p2) + reg_i) & 0xff) | ((p2) & 0xff00)); \ -CLK_INC(); \ -} - -#define INT_ABS_I_W(reg_i) \ -if (!SKIP_CYCLE) { \ -LOAD((((p2) + reg_i) & 0xff) | ((p2) & 0xff00)); \ -CLK_INC(); \ -} - + if (!SKIP_CYCLE) { \ + STORE_DUMMY(p2, old_value); \ + CLK_INC(); \ + } \ + STORE(p2, new_value); \ + CLK_INC(); + +#define INT_ABS_I_R(reg_i) \ + if (!SKIP_CYCLE && ((((p2) & 0xff) + reg_i) > 0xff)) { \ + LOAD_DUMMY((((p2) + reg_i) & 0xff) | ((p2) & 0xff00)); \ + CLK_INC(); \ + } + +#define INT_ABS_I_W(reg_i) \ + if (!SKIP_CYCLE) { \ + LOAD_DUMMY((((p2) + reg_i) & 0xff) | ((p2) & 0xff00)); \ + CLK_INC(); \ + } + #define GET_ABS_X(dest) \ INT_ABS_I_R(reg_x) \ dest = LOAD((p2) + reg_x); \ CLK_INC(); /* same as above, for NOOP */ #define GET_ABS_X_DUMMY() \ -INT_ABS_I_R(reg_x) \ -LOAD((p2) + reg_x); \ -CLK_INC(); - + INT_ABS_I_R(reg_x) \ + LOAD_DUMMY((p2) + reg_x); \ + CLK_INC(); + #define GET_ABS_Y(dest) \ INT_ABS_I_R(reg_y) \ dest = LOAD((p2) + reg_y); \ @@ -1810,54 +2037,55 @@ STORE(p2 + reg_y, value); \ CLK_INC(); #define SET_ABS_I_RMW(reg_i, old_value, new_value) \ -if (!SKIP_CYCLE) { \ -STORE(p2 + reg_i, old_value); \ -CLK_INC(); \ -} \ -STORE(p2 + reg_i, new_value); \ -CLK_INC(); - + if (!SKIP_CYCLE) { \ + STORE_DUMMY(p2 + reg_i, old_value); \ + CLK_INC(); \ + } \ + STORE(p2 + reg_i, new_value); \ + CLK_INC(); + #define SET_ABS_X_RMW(old_value, new_value) SET_ABS_I_RMW(reg_x, old_value, new_value) #define SET_ABS_Y_RMW(old_value, new_value) SET_ABS_I_RMW(reg_y, old_value, new_value) #define GET_ZERO(dest) \ -dest = LOAD_ZERO(p1); \ -CLK_INC(); - - /* same as above, for NOOP */ -#define GET_ZERO_DUMMY() \ -LOAD_ZERO(p1); \ -CLK_INC(); - -#define SET_ZERO(value) \ -STORE_ZERO(p1, value); \ + dest = LOAD_ZERO(p1); \ + CLK_INC(); + +/* same as above, for NOOP */ +#define GET_ZERO_DUMMY() \ + LOAD_ZERO_DUMMY(p1); \ + CLK_INC(); + +#define SET_ZERO(value) \ +STORE_ZERO(p1, value); \ CLK_INC(); #define SET_ZERO_RMW(old_value, new_value) \ -if (!SKIP_CYCLE) { \ -STORE_ZERO(p1, old_value); \ -CLK_INC(); \ -} \ -STORE_ZERO(p1, new_value); \ -CLK_INC(); - -#define INT_ZERO_I \ -if (!SKIP_CYCLE) { \ -LOAD_ZERO(p1); \ -CLK_INC(); \ -} - + if (!SKIP_CYCLE) { \ + STORE_ZERO_DUMMY(p1, old_value); \ + CLK_INC(); \ + } \ + STORE_ZERO(p1, new_value); \ + CLK_INC(); + +#define INT_ZERO_I \ + if (!SKIP_CYCLE) { \ + LOAD_ZERO_DUMMY(p1); \ + CLK_INC(); \ + } + +/* load zp, x */ #define GET_ZERO_X(dest) \ INT_ZERO_I \ dest = LOAD_ZERO(p1 + reg_x); \ CLK_INC(); /* same as above, for NOOP */ #define GET_ZERO_X_DUMMY() \ -INT_ZERO_I \ -LOAD_ZERO(p1 + reg_x); \ -CLK_INC(); - + INT_ZERO_I \ + LOAD_ZERO_DUMMY(p1 + reg_x); \ + CLK_INC(); + #define GET_ZERO_Y(dest) \ INT_ZERO_I \ dest = LOAD_ZERO(p1 + reg_y); \ @@ -1874,75 +2102,77 @@ STORE_ZERO(p1 + reg_y, value); \ CLK_INC(); #define SET_ZERO_I_RMW(reg_i, old_value, new_value) \ -if (!SKIP_CYCLE) { \ -STORE_ZERO(p1 + reg_i, old_value); \ -CLK_INC(); \ -} \ -STORE_ZERO(p1 + reg_i, new_value); \ -CLK_INC(); - + if (!SKIP_CYCLE) { \ + STORE_ZERO_DUMMY(p1 + reg_i, old_value); \ + CLK_INC(); \ + } \ + STORE_ZERO(p1 + reg_i, new_value); \ + CLK_INC(); + #define SET_ZERO_X_RMW(old_value, new_value) SET_ZERO_I_RMW(reg_x, old_value, new_value) #define SET_ZERO_Y_RMW(old_value, new_value) SET_ZERO_I_RMW(reg_y, old_value, new_value) #define INT_IND_X \ -unsigned int tmpa, addr; \ -LOAD_ZERO(p1); \ -CLK_INC(); \ -tmpa = (p1 + reg_x) & 0xff; \ -addr = LOAD_ZERO(tmpa); \ -CLK_INC(); \ -tmpa = (tmpa + 1) & 0xff; \ -addr |= (LOAD_ZERO(tmpa) << 8); \ -CLK_INC(); - + unsigned int tmpa, addr; \ + LOAD_ZERO_DUMMY(p1); \ + CLK_INC(); \ + tmpa = (p1 + reg_x) & 0xff; \ + addr = LOAD_ZERO(tmpa); \ + CLK_INC(); \ + tmpa = (tmpa + 1) & 0xff; \ + addr |= (LOAD_ZERO(tmpa) << 8); \ + CLK_INC(); + +/* load (zp, x) */ #define GET_IND_X(dest) \ INT_IND_X \ dest = LOAD(addr); \ CLK_INC(); #define SET_IND_X(value) \ -{ \ -INT_IND_X \ -STORE(addr, value); \ -CLK_INC(); \ -} - -#define INT_IND_Y_R() \ -unsigned int tmpa, addr; \ -tmpa = LOAD_ZERO(p1); \ -CLK_INC(); \ -tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ -CLK_INC(); \ -if (!SKIP_CYCLE && ((((tmpa) & 0xff) + reg_y) > 0xff)) { \ -LOAD((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ -CLK_INC(); \ -} \ -addr = (tmpa + reg_y) & 0xffff; \ - -#define INT_IND_Y_W() \ -unsigned int tmpa, addr; \ -tmpa = LOAD_ZERO(p1); \ -CLK_INC(); \ -tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ -CLK_INC(); \ -if (!SKIP_CYCLE) { \ -LOAD((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ -CLK_INC(); \ -} \ -addr = (tmpa + reg_y) & 0xffff; - /* like above, for SHA_IND_Y */ + { \ + INT_IND_X \ + STORE(addr, value); \ + CLK_INC(); \ + } + +#define INT_IND_Y_R() \ + unsigned int tmpa, addr; \ + tmpa = LOAD_ZERO(p1); \ + CLK_INC(); \ + tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ + CLK_INC(); \ + if (!SKIP_CYCLE && ((((tmpa) & 0xff) + reg_y) > 0xff)) { \ + LOAD_DUMMY((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ + CLK_INC(); \ + } \ + addr = (tmpa + reg_y) & 0xffff; \ + +#define INT_IND_Y_W() \ + unsigned int tmpa, addr; \ + tmpa = LOAD_ZERO(p1); \ + CLK_INC(); \ + tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ + CLK_INC(); \ + if (!SKIP_CYCLE) { \ + LOAD_DUMMY((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ + CLK_INC(); \ + } \ + addr = (tmpa + reg_y) & 0xffff; +/* like above, for SHA_IND_Y */ #define INT_IND_Y_W_NOADDR() \ -unsigned int tmpa; \ -tmpa = LOAD_ZERO(p1); \ -CLK_INC(); \ -tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ -CLK_INC(); \ -if (!SKIP_CYCLE) { \ -LOAD_CHECK_BA_LOW((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ -CLK_INC(); \ -} - + unsigned int tmpa; \ + tmpa = LOAD_ZERO(p1); \ + CLK_INC(); \ + tmpa |= (LOAD_ZERO(p1 + 1) << 8); \ + CLK_INC(); \ + if (!SKIP_CYCLE) { \ + LOAD_CHECK_BA_LOW((tmpa & 0xff00) | ((tmpa + reg_y) & 0xff)); \ + CLK_INC(); \ + } + +/* load (zp),y */ #define GET_IND_Y(dest) \ INT_IND_Y_R() \ dest = LOAD(addr); \ @@ -1961,13 +2191,13 @@ CLK_INC(); \ } #define SET_IND_RMW(old_value, new_value) \ -if (!SKIP_CYCLE) { \ -STORE(addr, old_value); \ -CLK_INC(); \ -} \ -STORE(addr, new_value); \ -CLK_INC(); - + if (!SKIP_CYCLE) { \ + STORE_DUMMY(addr, old_value); \ + CLK_INC(); \ + } \ + STORE(addr, new_value); \ + CLK_INC(); + #define SET_ABS_SH_I(addr, reg_and, reg_i) \ do { \ unsigned int tmp2, tmp3, value; \ @@ -2042,59 +2272,117 @@ INC_PC(pc_inc); } while (0) #define ANC() \ -do { \ -reg_a_write = (BYTE)(reg_a_read & p1); \ -LOCAL_SET_NZ(reg_a_read); \ -LOCAL_SET_CARRY(LOCAL_SIGN()); \ -INC_PC(2); \ -} while (0) - + do { \ + reg_a_write = (uint8_t)(reg_a_read & p1); \ + LOCAL_SET_NZ(reg_a_read); \ + LOCAL_SET_CARRY(LOCAL_SIGN()); \ + INC_PC(2); \ + } while (0) + #define AND(get_func, pc_inc) \ -do { \ -unsigned int value; \ -get_func(value) \ -reg_a_write = (BYTE)(reg_a_read & value); \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(pc_inc); \ -} while (0) - - /* - The result of the ANE opcode is A = ((A | CONST) & X & IMM), with CONST apparently - being both chip- and temperature dependent. - - The commonly used value for CONST in various documents is 0xee, which is however - not to be taken for granted (as it is unstable). see here: - http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,_ANE) - - as seen in the list, there are several possible values, and its origin is still - kinda unknown. instead of the commonly used 0xee we use 0xff here, since this - will make the only known occurance of this opcode in actual code work. see here: - https://sourceforge.net/tracker/?func=detail&aid=2110948&group_id=223021&atid=1057617 - - FIXME: in the unlikely event that other code surfaces that depends on another - CONST value, it probably has to be made configureable somehow if no value can - be found that works for both. - */ - + do { \ + unsigned int value; \ + get_func(value) \ + reg_a_write = (uint8_t)(reg_a_read & value); \ + LOCAL_SET_NZ(reg_a_read); \ + INC_PC(pc_inc); \ + } while (0) + +/* +The result of the ANE opcode is A = ((A | CONST) & X & IMM), with CONST apparently +being both chip- and temperature dependent. There is also a dependency on the RDY +line, ie somehow bit4 and bit0 are affected in the cycle when a DMA starts. + +The commonly used value for CONST in various documents is 0xee, which is however +not to be taken for granted (as it is unstable). see here: +http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,_ANE) + +as seen in the list, there are several possible values, and its origin is still +kinda unknown. instead of the commonly used 0xee we use 0xef here, since this +appears to work with all known occurances of this opcode in real code: + +known occurances of this opcode in actual code are: + +- spectipede (original tape), use of ANE is unstable. bits 7,6,5,0 MUST be set + in the magic constant (that makes it not work with the common 0xee, but 0xef + works) +- turrican 3 (by smash designs), use of ANE is unstable. bits 6,1,0 MUST be set + in the magic constant (that makes it not work with the common 0xee, but 0xef + works) +- the ocean/imagine tape loader (yie ar kung fu, rambo first blood part ii, + comic bakery), use of ANE is stable. + +also see here: + +https://sourceforge.net/tracker/?func=detail&aid=2110948&group_id=223021&atid=1057617 + +FIXME: in the unlikely event that other code surfaces that depends on another +CONST value, it probably has to be made configureable somehow if no value can +be found that works for both. + +FIXME: perhaps we really have to add some randomness to (some) bits +*/ + +#define ANE_MAGIC 0xef +#define ANE_RDY_MAGIC (0xee & ANE_MAGIC) + +#ifndef ANE_LOG_LEVEL +#define ANE_LOG_LEVEL 0 +#ifdef _MSC_VER +#pragma message ("Warning: ANE_LOG_LEVEL not defined, disabling by default") +#else +#warning "ANE_LOG_LEVEL not defined, disabling by default" +#endif +#endif + +#if 1 +/* static int ane_log_level = 1; */ /* 0: none, 1: unstable only 2: all */ + +#define ANE_LOGGING(rdy) \ + do { \ + unsigned int result = ((reg_a_read | (rdy ? ANE_RDY_MAGIC : ANE_MAGIC)) & reg_x & p1); \ + unsigned int unstablebits = ((reg_a_read ^ 0xff) & (p1 & reg_x)); \ + if ((ANE_LOG_LEVEL == 2) || ((ANE_LOG_LEVEL == 1) && (unstablebits != 0))) { \ + if (unstablebits == 0) { \ + log_warning(CPU_LOG_ID, "$%04x ANE #$%02x ; A=$%02x X=$%02x -> A=$%02x%s", \ + reg_pc, p1, reg_a_read, reg_x, result, rdy ? " (RDY cycle)" : ""); \ + } else { \ + log_warning(CPU_LOG_ID, "$%04x ANE #$%02x ; A=$%02x X=$%02x -> A=$%02x (unstable bits: %c%c%c%c%c%c%c%c)%s", \ + reg_pc, p1, reg_a_read, reg_x, result, \ + unstablebits & 0x80 ? '*' : '.', unstablebits & 0x40 ? '*' : '.', \ + unstablebits & 0x20 ? '*' : '.', unstablebits & 0x10 ? '*' : '.', \ + unstablebits & 0x08 ? '*' : '.', unstablebits & 0x04 ? '*' : '.', \ + unstablebits & 0x02 ? '*' : '.', unstablebits & 0x01 ? '*' : '.', \ + rdy ? " (RDY cycle)" : "" \ + ); \ + } \ + } \ + } while (0) +#else +#define ANE_LOGGING(rdy) +#endif + #define ANE() \ -do { \ -/* Set by main-cpu to signal steal after first fetch */ \ -if (OPINFO_ENABLES_IRQ(LAST_OPCODE_INFO)) { \ -/* Remove the signal */ \ -LAST_OPCODE_INFO &= ~OPINFO_ENABLES_IRQ_MSK; \ -/* TODO emulate the different behaviour */ \ -reg_a_write = (BYTE)((reg_a_read | 0xff) & reg_x & p1); \ -} else { \ -reg_a_write = (BYTE)((reg_a_read | 0xff) & reg_x & p1); \ -} \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(2); \ -/* Pretend to be NOP #$nn to not trigger the special case \ -when cycles are stolen after the second fetch */ \ -SET_LAST_OPCODE(0x80); \ -} while (0) - - /* The fanciest opcode ever... ARR! */ + do { \ + /* Set by main-cpu to signal steal after first fetch */ \ + if (OPINFO_ENABLES_IRQ(LAST_OPCODE_INFO)) { \ + /* Remove the signal */ \ + LAST_OPCODE_INFO &= ~OPINFO_ENABLES_IRQ_MSK; \ + /* TODO: the real behaviour is more complex */ \ + ANE_LOGGING(1); \ + reg_a_write = (uint8_t)((reg_a_read | ANE_RDY_MAGIC) & reg_x & p1); \ + } else { \ + ANE_LOGGING(0); \ + reg_a_write = (uint8_t)((reg_a_read | ANE_MAGIC) & reg_x & p1); \ + } \ + LOCAL_SET_NZ(reg_a_write); \ + INC_PC(2); \ + /* Pretend to be NOP #$nn to not trigger the special case \ + when cycles are stolen after the second fetch */ \ + SET_LAST_OPCODE(0x80); \ + } while (0) + +/* The fanciest opcode ever... ARR! */ #define ARR() \ do { \ unsigned int tmp; \ @@ -2197,62 +2485,63 @@ JUMP(dest_addr & 0xffff); \ #else /* !C64DTV */ #define BRANCH(cond) \ -do { \ -INC_PC(2); \ -\ -if (cond) { \ -unsigned int dest_addr; \ -\ -dest_addr = reg_pc + (signed char)(p1); \ -\ -LOAD(reg_pc); \ -CLK_INC(); \ -if ((reg_pc ^ dest_addr) & 0xff00) { \ -LOAD((reg_pc & 0xff00) | (dest_addr & 0xff)); \ -CLK_INC(); \ -} else { \ -OPCODE_DELAYS_INTERRUPT(); \ -} \ -JUMP(dest_addr & 0xffff); \ -} \ -} while (0) - + do { \ + INC_PC(2); \ + \ + if (cond) { \ + unsigned int dest_addr; \ + \ + dest_addr = reg_pc + (signed char)(p1); \ + \ + LOAD_DUMMY(reg_pc); \ + CLK_INC(); \ + if ((reg_pc ^ dest_addr) & 0xff00) { \ + LOAD_DUMMY((reg_pc & 0xff00) | (dest_addr & 0xff)); \ + CLK_INC(); \ + } else { \ + OPCODE_DELAYS_INTERRUPT(); \ + } \ + JUMP(dest_addr & 0xffff); \ + } \ + } while (0) + #endif #define BRK() \ -do { \ -WORD addr; \ -EXPORT_REGISTERS(); \ -TRACE_BRK(); \ -INC_PC(2); \ -LOCAL_SET_BREAK(1); \ -c64d_irqbrk_entry_type_base = C64D_STACK_ENTRY_BRK_PCH; \ -c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ -DO_IRQBRK(); \ -} while (0) - - /* The JAM (0x02) opcode is also used to patch the ROM. The function trap_handler() + do { \ + uint16_t addr; \ + EXPORT_REGISTERS(); \ + TRACE_BRK(); \ + INC_PC(2); \ + LOCAL_SET_BREAK(1); \ + c64d_irqbrk_entry_type_base = C64D_STACK_ENTRY_BRK_PCH; \ + c64d_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ + DO_IRQBRK(); \ + } while (0) + +/* The JAM (0x02) opcode is also used to patch the ROM. The function trap_handler() returns nonzero if this is not a patch, but a `real' JAM instruction. */ #define JAM_02() \ -do { \ -DWORD trap_result; \ -EXPORT_REGISTERS(); \ -if (!ROM_TRAP_ALLOWED() || (trap_result = ROM_TRAP_HANDLER()) == (DWORD)-1) { \ -REWIND_FETCH_OPCODE(CLK); \ -JAM(); \ -} else { \ -if (trap_result) { \ -REWIND_FETCH_OPCODE(CLK); \ -SET_OPCODE(trap_result); \ -IMPORT_REGISTERS(); \ -goto trap_skipped; \ -} else { \ -IMPORT_REGISTERS(); \ -} \ -} \ -} while (0) - + do { \ + uint32_t trap_result; \ + EXPORT_REGISTERS(); \ + if (!ROM_TRAP_ALLOWED() || (trap_result = ROM_TRAP_HANDLER()) == (uint32_t)-1) { \ + CPU_IS_JAMMED = 1; \ + REWIND_FETCH_OPCODE(CLK); \ + JAM(); \ + } else { \ + if (trap_result) { \ + REWIND_FETCH_OPCODE(CLK); \ + SET_OPCODE(trap_result); \ + IMPORT_REGISTERS(); \ + goto trap_skipped; \ + } else { \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + #define CLC() \ do { \ INC_PC(1); \ @@ -2302,16 +2591,16 @@ LOCAL_SET_OVERFLOW(0); \ } while (0) #define CP(reg, get_func, pc_inc) \ -do { \ -unsigned int tmp; \ -BYTE value; \ -get_func(value) \ -tmp = reg - value; \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_NZ(tmp & 0xff); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + unsigned int tmp; \ + uint8_t value; \ + get_func(value) \ + tmp = reg - value; \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + INC_PC(pc_inc); \ + } while (0) + #define DCP(pc_inc, get_func, set_func) \ do { \ unsigned int old_value, new_value; \ @@ -2348,14 +2637,14 @@ INC_PC(1); \ } while (0) #define EOR(get_func, pc_inc) \ -do { \ -unsigned int value; \ -get_func(value) \ -reg_a_write = (BYTE)(reg_a_read ^ (value)); \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + unsigned int value; \ + get_func(value) \ + reg_a_write = (uint8_t)(reg_a_read ^ (value)); \ + LOCAL_SET_NZ(reg_a_read); \ + INC_PC(pc_inc); \ + } while (0) + #define INC(pc_inc, get_func, set_func) \ do { \ unsigned int old_value, new_value; \ @@ -2396,16 +2685,16 @@ JUMP(addr); \ } while (0) #define JMP_IND() \ -do { \ -WORD dest_addr; \ -dest_addr = LOAD(p2); \ -CLK_INC(); \ -dest_addr |= (LOAD((p2 & 0xff00) | ((p2 + 1) & 0xff)) << 8); \ -CLK_INC(); \ -JUMP(dest_addr); \ -} while (0) - - /* HACK: fix JSR MSB in monitor CPU history */ + do { \ + uint16_t dest_addr; \ + dest_addr = LOAD(p2); \ + CLK_INC(); \ + dest_addr |= (LOAD((p2 & 0xff00) | ((p2 + 1) & 0xff)) << 8); \ + CLK_INC(); \ + JUMP(dest_addr); \ + } while (0) + +/* HACK: fix JSR MSB in monitor CPU history */ #ifdef FEATURE_CPUMEMHISTORY #define JSR_FIXUP_MSB(x) monitor_cpuhistory_fix_p2(x) #else @@ -2413,28 +2702,29 @@ JUMP(dest_addr); \ #endif #define JSR() \ -do { \ -BYTE addr_msb; \ -WORD dest_addr; \ -if (!SKIP_CYCLE) { \ -STACK_PEEK(); \ -CLK_INC(); \ -} \ -INC_PC(2); \ -PUSH(((reg_pc) >> 8) & 0xff); \ -C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -CLK_INC(); \ -PUSH((reg_pc) & 0xff); \ -C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -CLK_INC(); \ -addr_msb = LOAD(reg_pc); \ -JSR_FIXUP_MSB(addr_msb); \ -dest_addr = (WORD)(p1 | (addr_msb << 8)); \ -CLK_INC(); \ -c64d_profiler_jsr(dest_addr); \ -JUMP(dest_addr); \ -} while (0) - + do { \ + uint8_t addr_msb; \ + uint16_t dest_addr; \ + if (!SKIP_CYCLE) { \ + STACK_PEEK(); \ + CLK_INC(); \ + } \ + INC_PC(2); \ + PUSH(((reg_pc) >> 8) & 0xff); \ + C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + PUSH((reg_pc) & 0xff); \ + C64D_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + CLK_INC(); \ + addr_msb = LOAD(reg_pc); \ + JSR_FIXUP_MSB(addr_msb); \ + dest_addr = (uint16_t)(p1 | (addr_msb << 8)); \ + CLK_INC(); \ + c64d_profiler_jsr(dest_addr); \ + CHECK_PROFILE_JSR(dest_addr); \ + JUMP(dest_addr); \ + } while (0) + #define LAS() \ do { \ unsigned int value; \ @@ -2471,31 +2761,96 @@ set_func(old_value, new_value) \ } while (0) #define LSR_A() \ -do { \ -LOCAL_SET_CARRY(reg_a_read & 0x01); \ -reg_a_write = reg_a_read >> 1; \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(1); \ -} while (0) - - /* Note: this is not always exact, as this opcode can be quite unstable! - Moreover, the behavior is different from the one described in 64doc. */ -#define LXA(value, pc_inc) \ -do { \ -reg_a_write = reg_x = ((reg_a_read | 0xee) & ((BYTE)(value))); \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + LOCAL_SET_CARRY(reg_a_read & 0x01); \ + reg_a_write = reg_a_read >> 1; \ + LOCAL_SET_NZ(reg_a_read); \ + INC_PC(1); \ + } while (0) + +/* +The result of the LXA opcode is A = X = ((A | CONST) & IMM), with CONST apparently +being both chip- and temperature dependent. There is also a dependency on the RDY +line, ie somehow bit4 and bit0 are affected in the cycle when a DMA starts. + +The commonly used value for CONST in various documents is 0xee, which is however +not to be taken for granted (as it is unstable). + +FIXME: in the unlikely event that other code surfaces that depends on another +CONST value, it probably has to be made configureable somehow if no value can +be found that works for both. + +FIXME: perhaps we really have to add some randomness to (some) bits +*/ + +#define LXA_MAGIC 0xee /* needs to be 0xee for wizball */ +#define LXA_RDY_MAGIC 0xee + +#ifndef LXA_LOG_LEVEL +#define LXA_LOG_LEVEL 0 +#ifdef _MSC_VER +#pragma message ("Warning: LXA_LOG_LEVEL not defined, disabling by default") +#else +#warning "LXA_LOG_LEVEL not defined, disabling by default" +#endif +#endif + +#if 1 +/* static int lxa_log_level = 1; */ /* 0: none, 1: unstable only 2: all */ + +#define LXA_LOGGING(rdy) \ + do { \ + unsigned int result = (reg_a_read | (rdy ? LXA_RDY_MAGIC : LXA_MAGIC)) & p1; \ + unsigned int unstablebits = (reg_a_read ^ 0xff) & p1; \ + if ((LXA_LOG_LEVEL == 2) || ((LXA_LOG_LEVEL == 1) && (unstablebits != 0))) { \ + if (unstablebits == 0) { \ + log_warning(CPU_LOG_ID, "$%04x LAX #$%02x ; A=$%02x -> A=X=$%02x%s", \ + reg_pc, p1, reg_a_read, result, rdy ? " (RDY cycle)" : ""); \ + } else { \ + log_warning(CPU_LOG_ID, "$%04x LAX #$%02x ; A=$%02x -> A=X=$%02x (unstable bits: %c%c%c%c%c%c%c%c)%s", \ + reg_pc, p1, reg_a_read, result, \ + unstablebits & 0x80 ? '*' : '.', unstablebits & 0x40 ? '*' : '.', \ + unstablebits & 0x20 ? '*' : '.', unstablebits & 0x10 ? '*' : '.', \ + unstablebits & 0x08 ? '*' : '.', unstablebits & 0x04 ? '*' : '.', \ + unstablebits & 0x02 ? '*' : '.', unstablebits & 0x01 ? '*' : '.', \ + rdy ? " (RDY cycle)" : "" \ + ); \ + } \ + } \ + } while (0) +#else +#define LXA_LOGGING(rdy) +#endif + +#define LXA() \ + do { \ + /* Set by main-cpu to signal steal after first fetch */ \ + if (OPINFO_ENABLES_IRQ(LAST_OPCODE_INFO)) { \ + /* Remove the signal */ \ + LAST_OPCODE_INFO &= ~OPINFO_ENABLES_IRQ_MSK; \ + /* TODO: the real behaviour is more complex */ \ + LXA_LOGGING(1); \ + reg_a_write = reg_x = (uint8_t)((reg_a_read | LXA_RDY_MAGIC) & p1); \ + } else { \ + LXA_LOGGING(0); \ + reg_a_write = reg_x = (uint8_t)((reg_a_read | LXA_MAGIC) & p1); \ + } \ + LOCAL_SET_NZ(reg_a_write); \ + INC_PC(2); \ + /* Pretend to be NOP #$nn to not trigger the special case \ + when cycles are stolen after the second fetch */ \ + SET_LAST_OPCODE(0x80); \ + } while (0) + #define ORA(get_func, pc_inc) \ -do { \ -unsigned int value; \ -get_func(value) \ -reg_a_write = (BYTE)(reg_a_read | (value)); \ -LOCAL_SET_NZ(reg_a_write); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + unsigned int value; \ + get_func(value) \ + reg_a_write = (uint8_t)(reg_a_read | (value)); \ + LOCAL_SET_NZ(reg_a_write); \ + INC_PC(pc_inc); \ + } while (0) + #define NOOP(get_func, pc_inc) \ do { \ get_func() \ @@ -2531,23 +2886,23 @@ INC_PC(1); \ } while (0) #define PLP() \ -do { \ -BYTE s; \ -if (!SKIP_CYCLE) { \ -STACK_PEEK(); \ -CLK_INC(); \ -} \ -s = PULL(); \ -CLK_INC(); \ -if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) { \ -OPCODE_ENABLES_IRQ(); \ -} else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) { \ -OPCODE_DISABLES_IRQ(); \ -} \ -LOCAL_SET_STATUS(s); \ -INC_PC(1); \ -} while (0) - + do { \ + uint8_t s; \ + if (!SKIP_CYCLE) { \ + STACK_PEEK(); \ + CLK_INC(); \ + } \ + s = PULL(); \ + CLK_INC(); \ + if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) { \ + OPCODE_ENABLES_IRQ(); \ + } else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) { \ + OPCODE_DISABLES_IRQ(); \ + } \ + LOCAL_SET_STATUS(s); \ + INC_PC(1); \ + } while (0) + #define RLA(pc_inc, get_func, set_func) \ do { \ unsigned int old_value, new_value; \ @@ -2597,15 +2952,15 @@ set_func(old_value, new_value) \ } while (0) #define ROR_A() \ -do { \ -BYTE tmp = reg_a_read; \ -\ -reg_a_write = (reg_a_read >> 1) | (reg_p << 7); \ -LOCAL_SET_CARRY(tmp & 0x01); \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(1); \ -} while (0) - + do { \ + uint8_t tmp = reg_a_read; \ + \ + reg_a_write = (reg_a_read >> 1) | (reg_p << 7); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + LOCAL_SET_NZ(reg_a_read); \ + INC_PC(1); \ + } while (0) + #define RRA(pc_inc, get_func, set_func) \ do { \ unsigned int old_value, new_value; \ @@ -2626,41 +2981,45 @@ set_func(old_value, new_value) \ from 1 to 0 because the value of I is set 3 cycles before the end of the opcode, and thus the 6510 has enough time to call the interrupt routine as soon as the opcode ends, if necessary. */ -#define RTI() \ -do { \ -WORD tmp; \ -if (!SKIP_CYCLE) { \ -STACK_PEEK(); \ -CLK_INC(); \ -} \ -tmp = (WORD)PULL(); \ -CLK_INC(); \ -LOCAL_SET_STATUS((BYTE)tmp); \ -tmp = (WORD)PULL(); \ -CLK_INC(); \ -tmp |= (WORD)PULL() << 8; \ -CLK_INC(); \ -JUMP(tmp); \ -} while (0) - +#define RTI() \ + do { \ + uint16_t tmp; \ + \ + CHECK_PROFILE_RTI(); \ + if (!SKIP_CYCLE) { \ + STACK_PEEK(); \ + CLK_INC(); \ + } \ + tmp = (uint16_t)PULL(); \ + CLK_INC(); \ + LOCAL_SET_STATUS((uint8_t)tmp); \ + tmp = (uint16_t)PULL(); \ + CLK_INC(); \ + tmp |= (uint16_t)PULL() << 8; \ + CLK_INC(); \ + JUMP(tmp); \ + } while (0) + #define RTS() \ -do { \ -WORD tmp; \ -if (!SKIP_CYCLE) { \ -STACK_PEEK(); \ -CLK_INC(); \ -} \ -tmp = PULL(); \ -CLK_INC(); \ -tmp |= (PULL() << 8); \ -CLK_INC(); \ -LOAD(tmp); \ -CLK_INC(); \ -tmp++; \ -c64d_profiler_rts(); \ -JUMP(tmp); \ -} while (0) - + do { \ + uint16_t tmp; \ + \ + CHECK_PROFILE_RTS(); \ + if (!SKIP_CYCLE) { \ + STACK_PEEK(); \ + CLK_INC(); \ + } \ + tmp = PULL(); \ + CLK_INC(); \ + tmp |= (PULL() << 8); \ + CLK_INC(); \ + LOAD(tmp); \ + CLK_INC(); \ + tmp++; \ + c64d_profiler_rts(); \ + JUMP(tmp); \ + } while (0) + #define SAC() \ do { \ reg_a_write_idx = p1 >> 4; \ @@ -2669,35 +3028,35 @@ INC_PC(2); \ } while (0) #define SBC(get_func, pc_inc) \ -do { \ -WORD src, tmp; \ -\ -get_func(src) \ -tmp = reg_a_read - src - ((reg_p & P_CARRY) ? 0 : 1); \ -if (reg_p & P_DECIMAL) { \ -unsigned int tmp_a; \ -tmp_a = (reg_a_read & 0xf) - (src & 0xf) - ((reg_p & P_CARRY) ? 0 : 1); \ -if (tmp_a & 0x10) { \ -tmp_a = ((tmp_a - 6) & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0) - 0x10); \ -} else { \ -tmp_a = (tmp_a & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0)); \ -} \ -if (tmp_a & 0x100) { \ -tmp_a -= 0x60; \ -} \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_NZ(tmp & 0xff); \ -LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ -reg_a_write = (BYTE) tmp_a; \ -} else { \ -LOCAL_SET_NZ(tmp & 0xff); \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ -reg_a_write = (BYTE) tmp; \ -} \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint16_t src, tmp; \ + \ + get_func(src) \ + tmp = reg_a_read - src - ((reg_p & P_CARRY) ? 0 : 1); \ + if (reg_p & P_DECIMAL) { \ + unsigned int tmp_a; \ + tmp_a = (reg_a_read & 0xf) - (src & 0xf) - ((reg_p & P_CARRY) ? 0 : 1); \ + if (tmp_a & 0x10) { \ + tmp_a = ((tmp_a - 6) & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0) - 0x10); \ + } else { \ + tmp_a = (tmp_a & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0)); \ + } \ + if (tmp_a & 0x100) { \ + tmp_a -= 0x60; \ + } \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ + reg_a_write = (uint8_t) tmp_a; \ + } else { \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ + reg_a_write = (uint8_t) tmp; \ + } \ + INC_PC(pc_inc); \ + } while (0) + #define SBX() \ do { \ unsigned int tmp; \ @@ -2731,22 +3090,22 @@ INC_PC(1); \ } while (0) #define SHA_IND_Y() \ -do { \ -INT_IND_Y_W_NOADDR(); \ -SET_ABS_SH_I(tmpa, reg_a_read & reg_x, reg_y); \ -INC_PC(2); \ -} while (0) - -#define SH_ABS_I(reg_and, reg_i) \ -do { \ -if (!SKIP_CYCLE) { \ -LOAD_CHECK_BA_LOW(((p2 + reg_i) & 0xff) | ((p2) & 0xff00)); \ -CLK_INC(); \ -} \ -SET_ABS_SH_I(p2, reg_and, reg_i); \ -INC_PC(3); \ -} while (0) - + do { \ + INT_IND_Y_W_NOADDR(); \ + SET_ABS_SH_I(tmpa, reg_a_read & reg_x, reg_y); \ + INC_PC(2); \ + } while (0) + +#define SH_ABS_I(reg_and, reg_i) \ + do { \ + if (!SKIP_CYCLE) { \ + LOAD_CHECK_BA_LOW_DUMMY(((p2 + reg_i) & 0xff) | ((p2) & 0xff00)); \ + CLK_INC(); \ + } \ + SET_ABS_SH_I(p2, reg_and, reg_i); \ + INC_PC(3); \ + } while (0) + #define SHS_ABS_Y() \ do { \ SH_ABS_I(reg_a_read & reg_x, reg_y); \ @@ -2827,59 +3186,84 @@ INC_PC(1); \ } while (0) #define TYA() \ -do { \ -reg_a_write = reg_y; \ -LOCAL_SET_NZ(reg_a_read); \ -INC_PC(1); \ -} while (0) - - - /* ------------------------------------------------------------------------- */ - - static const BYTE fetch_tab[] = { - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* $00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $00 */ - /* $10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $10 */ - /* $20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $20 */ - /* $30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $30 */ - /* $40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $40 */ - /* $50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $50 */ - /* $60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $60 */ - /* $70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $70 */ - /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $80 */ - /* $90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $90 */ - /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $A0 */ - /* $B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $B0 */ - /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $C0 */ - /* $D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $D0 */ - /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $E0 */ - /* $F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 /* $F0 */ - }; - - - /* ------------------------------------------------------------------------ */ - - /* Here, the CPU is emulated. */ - + do { \ + reg_a_write = reg_y; \ + LOCAL_SET_NZ(reg_a_read); \ + INC_PC(1); \ + } while (0) + + +/* ------------------------------------------------------------------------- */ + +static const uint8_t fetch_tab[] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* $00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $00 */ + /* $10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $10 */ + /* $20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $20 */ + /* $30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $30 */ + /* $40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $40 */ + /* $50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $50 */ + /* $60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $60 */ + /* $70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $70 */ + /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $80 */ + /* $90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $90 */ + /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $A0 */ + /* $B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $B0 */ + /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $C0 */ + /* $D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $D0 */ + /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $E0 */ + /* $F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 /* $F0 */ +}; + + +/* ------------------------------------------------------------------------ */ + +/* Here, the CPU is emulated. */ + +{ +#ifndef CPU_IS_JAMMED + static int cpu_is_jammed = 0; +#define CPU_IS_JAMMED cpu_is_jammed +#ifdef _MSC_VER +#pragma message ("Warning: CPU_IS_JAMMED not defined, using default (internal)") +#else +#warning "CPU_IS_JAMMED not defined, using default (internal)" +#endif +#endif + +#if !defined(DRIVE_CPU) + CLOCK profiling_clock_start; +#endif + + //LOGD("reg_pc=%4.4x", reg_pc); + if (_c64d_new_pc == -1) { - //LOGD("reg_pc=%4.4x", reg_pc); - if (_c64d_new_pc == -1) - { - viceCurrentC64PC = reg_pc; - } - else - { - viceCurrentC64PC = _c64d_new_pc; - } - + viceCurrentC64PC = reg_pc; + } + else + { + viceCurrentC64PC = _c64d_new_pc; + } + #ifdef CHECK_AND_RUN_ALTERNATE_CPU CHECK_AND_RUN_ALTERNATE_CPU #endif - + while (CLK >= alarm_context_next_pending_clk(ALARM_CONTEXT)) { alarm_context_dispatch(ALARM_CONTEXT, CLK); } - + + /* HACK: when the CPU is jammed, no interrupts are served, the only way + to recover is reset. so we clear the interrupt flags and force + acknowledging them here in this case. */ + if (CPU_IS_JAMMED) { + interrupt_ack_irq(CPU_INT_STATUS); + CPU_INT_STATUS->global_pending_int &= ~(IK_IRQ | IK_NMI); + if (CPU_INT_STATUS->global_pending_int & IK_RESET) { + CPU_IS_JAMMED = 0; + } + } + { enum cpu_int pending_interrupt; @@ -2894,15 +3278,18 @@ INC_PC(1); \ pending_interrupt = CPU_INT_STATUS->global_pending_int; if (pending_interrupt != IK_NONE) { +#if !defined(DRIVE_CPU) + profiling_clock_start = CLK; +#endif DO_INTERRUPT(pending_interrupt); - + if ((pending_interrupt & IK_NMI) && (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { c64d_c64_check_irqnmi_breakpoint(); viceCurrentC64PC = reg_pc; } - + // c64 debugger - check interrupt breakpoints when irq is ack'ed if ((pending_interrupt & IK_IRQ) && ((reg_p & P_INTERRUPT) == P_INTERRUPT)) { @@ -2914,7 +3301,7 @@ INC_PC(1); \ vicii.c64d_irq_flag = 0; viceCurrentC64PC = reg_pc; } - + if (machine_context.cia1->irq_enabled) { if (machine_context.cia1->c64d_irq_flag == 1) @@ -2924,7 +3311,7 @@ INC_PC(1); \ viceCurrentC64PC = reg_pc; } } - + if (machine_context.cia2->irq_enabled) { if (machine_context.cia2->c64d_irq_flag == 1) @@ -2954,9 +3341,9 @@ INC_PC(1); \ alarm_context_dispatch(ALARM_CONTEXT, CLK); } } - + } - + { c64d_profiler_start_handle_cpu_instruction(); @@ -2965,9 +3352,9 @@ INC_PC(1); \ c64d_maincpu_previous2_instruction_clk = c64d_maincpu_previous_instruction_clk; c64d_maincpu_previous_instruction_clk = maincpu_clk; } - + c64d_maincpu_current_instruction_clk = maincpu_clk; - + if (c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_INSTRUCTION && c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_CYCLE) { @@ -2978,7 +3365,7 @@ INC_PC(1); \ debug_iterations_after_restore = 0; } } - + { opcode_t opcode; #ifdef VICE_DEBUG @@ -2988,11 +3375,19 @@ INC_PC(1); \ #ifdef FEATURE_CPUMEMHISTORY memmap_state |= (MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); #endif - + +#if !defined(DRIVE_CPU) + profiling_clock_start = CLK; + stolen_cycles = 0; + if (maincpu_profiling) { + profile_sample_start(reg_pc); + } +#endif + debug_iterations_after_restore++; debug_prev_iteration_pc = reg_pc; SET_LAST_ADDR(reg_pc); - + // c64 debugger fix if (bank_base == NULL) { @@ -3003,29 +3398,48 @@ INC_PC(1); \ } } /// - FETCH_OPCODE(opcode); + + /* HACK: The real CPU would stop fetching opcodes all together when + * "jammed" - however, our code may rely on FETCH_OPCODE being called + * here, so we can not simply skip it. What we do instead is remembering + * the opcode fetched when not jammed and force it when jammed. + * This is needed so the CPU would not continue executing opcodes when + * the value at the original jam location changed to a non-jam, for + * whatever reason. + */ + { + static uint8_t lastop; + FETCH_OPCODE(opcode); + if (!CPU_IS_JAMMED) { + /* remember current opcode */ + lastop = p0; + } else { + /* set opcode that made the cpu jam */ + SET_OPCODE(lastop); + } + } #ifdef FEATURE_CPUMEMHISTORY - /* If reg_pc >= bank_limit then JSR (0x20) hasn't load p2 yet. - The earlier LOAD(reg_pc+2) hack can break stealing badly on x64sc. - The fixing is now handled in JSR(). */ - monitor_cpuhistory_store(reg_pc, p0, p1, p2 >> 8, reg_a_read, reg_x, reg_y, reg_sp, LOCAL_STATUS()); - memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); + /* If reg_pc >= bank_limit then JSR (0x20) hasn't load p2 yet. + The earlier LOAD(reg_pc+2) hack can break stealing badly on x64sc. + The fixing is now handled in JSR(). */ + monitor_cpuhistory_store(debug_clk, reg_pc, p0, p1, p2 >> 8, reg_a_read, reg_x, reg_y, reg_sp, LOCAL_STATUS(), ORIGIN_MEMSPACE); + memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); #endif - + #ifdef VICE_DEBUG - + // TODO: shall we put here a hook to C64 Debugger? - + if (TRACEFLG) { - BYTE op = (BYTE)(p0); - BYTE lo = (BYTE)(p1); - BYTE hi = (BYTE)(p2 >> 8); - - debug_maincpu((DWORD)(reg_pc), debug_clk, + uint8_t op = (uint8_t)(p0); + uint8_t lo = (uint8_t)(p1); + uint8_t hi = (uint8_t)(p2 >> 8); + + debug_maincpu((uint32_t)(reg_pc), debug_clk, mon_disassemble_to_string(e_comp_space, - (WORD) reg_pc, op, + (uint16_t) reg_pc, op, lo, hi, 0, 1, "6502"), reg_a_read, reg_x, reg_y, reg_sp); } @@ -3068,10 +3482,11 @@ INC_PC(1); \ case 0x32: /* JAM */ case 0x42: /* JAM */ #endif - REWIND_FETCH_OPCODE(CLK); - JAM(); - break; - + CPU_IS_JAMMED = 1; + REWIND_FETCH_OPCODE(CLK); + JAM(); + break; + #ifdef C64DTV case 0x12: /* BRA $nnnn */ BRANCH(1); @@ -3635,359 +4050,367 @@ INC_PC(1); \ #else SHS_ABS_Y(); #endif - break; - - case 0x9c: /* SHY $nnnn,X */ - SH_ABS_I(reg_y, reg_x); - break; - - case 0x9d: /* STA $nnnn,X */ - ST(reg_a_read, SET_ABS_X, 3); - break; - - case 0x9e: /* SHX $nnnn,Y */ - SH_ABS_I(reg_x, reg_y); - break; - - case 0x9f: /* SHA $nnnn,Y */ - SH_ABS_I(reg_a_read & reg_x, reg_y); - break; - - case 0xa0: /* LDY #$nn */ - LD(reg_y, GET_IMM, 2); - break; - - case 0xa1: /* LDA ($nn,X) */ - LD(reg_a_write, GET_IND_X, 2); - break; - - case 0xa2: /* LDX #$nn */ - LD(reg_x, GET_IMM, 2); - break; - - case 0xa3: /* LAX ($nn,X) */ - LAX(GET_IND_X, 2); - break; - - case 0xa4: /* LDY $nn */ - LD(reg_y, GET_ZERO, 2); - break; - - case 0xa5: /* LDA $nn */ - LD(reg_a_write, GET_ZERO, 2); - break; - - case 0xa6: /* LDX $nn */ - LD(reg_x, GET_ZERO, 2); - break; - - case 0xa7: /* LAX $nn */ - LAX(GET_ZERO, 2); - break; - - case 0xa8: /* TAY */ - TAY(); - break; - - case 0xa9: /* LDA #$nn */ - LD(reg_a_write, GET_IMM, 2); - break; - - case 0xaa: /* TAX */ - TAX(); - break; - - case 0xab: /* LXA #$nn */ - LXA(p1, 2); - break; - - case 0xac: /* LDY $nnnn */ - LD(reg_y, GET_ABS, 3); - break; - - case 0xad: /* LDA $nnnn */ - LD(reg_a_write, GET_ABS, 3); - break; - - case 0xae: /* LDX $nnnn */ - LD(reg_x, GET_ABS, 3); - break; - - case 0xaf: /* LAX $nnnn */ - LAX(GET_ABS, 3); - break; - - case 0xb0: /* BCS $nnnn */ - BRANCH(LOCAL_CARRY()); - break; - - case 0xb1: /* LDA ($nn),Y */ - LD(reg_a_write, GET_IND_Y, 2); - break; - - case 0xb3: /* LAX ($nn),Y */ - LAX(GET_IND_Y, 2); - break; - - case 0xb4: /* LDY $nn,X */ - LD(reg_y, GET_ZERO_X, 2); - break; - - case 0xb5: /* LDA $nn,X */ - LD(reg_a_write, GET_ZERO_X, 2); - break; - - case 0xb6: /* LDX $nn,Y */ - LD(reg_x, GET_ZERO_Y, 2); - break; - - case 0xb7: /* LAX $nn,Y */ - LAX(GET_ZERO_Y, 2); - break; - - case 0xb8: /* CLV */ - CLV(); - break; - - case 0xb9: /* LDA $nnnn,Y */ - LD(reg_a_write, GET_ABS_Y, 3); - break; - - case 0xba: /* TSX */ - TSX(); - break; - - case 0xbb: /* LAS $nnnn,Y */ - LAS(); - break; - - case 0xbc: /* LDY $nnnn,X */ - LD(reg_y, GET_ABS_X, 3); - break; - - case 0xbd: /* LDA $nnnn,X */ - LD(reg_a_write, GET_ABS_X, 3); - break; - - case 0xbe: /* LDX $nnnn,Y */ - LD(reg_x, GET_ABS_Y, 3); - break; - - case 0xbf: /* LAX $nnnn,Y */ - LAX(GET_ABS_Y, 3); - break; - - case 0xc0: /* CPY #$nn */ - CP(reg_y, GET_IMM, 2); - break; - - case 0xc1: /* CMP ($nn,X) */ - CP(reg_a_read, GET_IND_X, 2); - break; - - case 0xc3: /* DCP ($nn,X) */ - DCP(2, GET_IND_X, SET_IND_RMW); - break; - - case 0xc4: /* CPY $nn */ - CP(reg_y, GET_ZERO, 2); - break; - - case 0xc5: /* CMP $nn */ - CP(reg_a_read, GET_ZERO, 2); - break; - - case 0xc6: /* DEC $nn */ - DEC(2, GET_ZERO, SET_ZERO_RMW); - break; - - case 0xc7: /* DCP $nn */ - DCP(2, GET_ZERO, SET_ZERO_RMW); - break; - - case 0xc8: /* INY */ - INY(); - break; - - case 0xc9: /* CMP #$nn */ - CP(reg_a_read, GET_IMM, 2); - break; - - case 0xca: /* DEX */ - DEX(); - break; - - case 0xcb: /* SBX #$nn */ - SBX(); - break; - - case 0xcc: /* CPY $nnnn */ - CP(reg_y, GET_ABS, 3); - break; - - case 0xcd: /* CMP $nnnn */ - CP(reg_a_read, GET_ABS, 3); - break; - - case 0xce: /* DEC $nnnn */ - DEC(3, GET_ABS, SET_ABS_RMW); - break; - - case 0xcf: /* DCP $nnnn */ - DCP(3, GET_ABS, SET_ABS_RMW); - break; - - case 0xd0: /* BNE $nnnn */ - BRANCH(!LOCAL_ZERO()); - break; - - case 0xd1: /* CMP ($nn),Y */ - CP(reg_a_read, GET_IND_Y, 2); - break; - - case 0xd3: /* DCP ($nn),Y */ - DCP(2, GET_IND_Y_RMW, SET_IND_RMW); - break; - - case 0xd5: /* CMP $nn,X */ - CP(reg_a_read, GET_ZERO_X, 2); - break; - - case 0xd6: /* DEC $nn,X */ - DEC(2, GET_ZERO_X, SET_ZERO_X_RMW); - break; - - case 0xd7: /* DCP $nn,X */ - DCP(2, GET_ZERO_X, SET_ZERO_X_RMW); - break; - - case 0xd8: /* CLD */ - CLD(); - break; - - case 0xd9: /* CMP $nnnn,Y */ - CP(reg_a_read, GET_ABS_Y, 3); - break; - - case 0xdb: /* DCP $nnnn,Y */ - DCP(3, GET_ABS_Y_RMW, SET_ABS_Y_RMW); - break; - - case 0xdd: /* CMP $nnnn,X */ - CP(reg_a_read, GET_ABS_X, 3); - break; - - case 0xde: /* DEC $nnnn,X */ - DEC(3, GET_ABS_X_RMW, SET_ABS_X_RMW); - break; - - case 0xdf: /* DCP $nnnn,X */ - DCP(3, GET_ABS_X_RMW, SET_ABS_X_RMW); - break; - - case 0xe0: /* CPX #$nn */ - CP(reg_x, GET_IMM, 2); - break; - - case 0xe1: /* SBC ($nn,X) */ - SBC(GET_IND_X, 2); - break; - - case 0xe3: /* ISB ($nn,X) */ - ISB(2, GET_IND_X, SET_IND_RMW); - break; - - case 0xe4: /* CPX $nn */ - CP(reg_x, GET_ZERO, 2); - break; - - case 0xe5: /* SBC $nn */ - SBC(GET_ZERO, 2); - break; - - case 0xe6: /* INC $nn */ - INC(2, GET_ZERO, SET_ZERO_RMW); - break; - - case 0xe7: /* ISB $nn */ - ISB(2, GET_ZERO, SET_ZERO_RMW); - break; - - case 0xe8: /* INX */ - INX(); - break; - - case 0xe9: /* SBC #$nn */ - case 0xeb: /* USBC #$nn (same as SBC) */ - SBC(GET_IMM, 2); - break; - - case 0xec: /* CPX $nnnn */ - CP(reg_x, GET_ABS, 3); - break; - - case 0xed: /* SBC $nnnn */ - SBC(GET_ABS, 3); - break; - - case 0xee: /* INC $nnnn */ - INC(3, GET_ABS, SET_ABS_RMW); - break; - - case 0xef: /* ISB $nnnn */ - ISB(3, GET_ABS, SET_ABS_RMW); - break; - - case 0xf0: /* BEQ $nnnn */ - BRANCH(LOCAL_ZERO()); - break; - - case 0xf1: /* SBC ($nn),Y */ - SBC(GET_IND_Y, 2); - break; - - case 0xf3: /* ISB ($nn),Y */ - ISB(2, GET_IND_Y_RMW, SET_IND_RMW); - break; - - case 0xf5: /* SBC $nn,X */ - SBC(GET_ZERO_X, 2); - break; - - case 0xf6: /* INC $nn,X */ - INC(2, GET_ZERO_X, SET_ZERO_X_RMW); - break; - - case 0xf7: /* ISB $nn,X */ - ISB(2, GET_ZERO_X, SET_ZERO_X_RMW); - break; - - case 0xf8: /* SED */ - SED(); - break; - - case 0xf9: /* SBC $nnnn,Y */ - SBC(GET_ABS_Y, 3); - break; - - case 0xfb: /* ISB $nnnn,Y */ - ISB(3, GET_ABS_Y_RMW, SET_ABS_Y_RMW); - break; - - case 0xfd: /* SBC $nnnn,X */ - SBC(GET_ABS_X, 3); - break; - - case 0xfe: /* INC $nnnn,X */ - INC(3, GET_ABS_X_RMW, SET_ABS_X_RMW); - break; - - case 0xff: /* ISB $nnnn,X */ - ISB(3, GET_ABS_X_RMW, SET_ABS_X_RMW); - break; - } - } - } + break; + + case 0x9c: /* SHY $nnnn,X */ + SH_ABS_I(reg_y, reg_x); + break; + + case 0x9d: /* STA $nnnn,X */ + ST(reg_a_read, SET_ABS_X, 3); + break; + + case 0x9e: /* SHX $nnnn,Y */ + SH_ABS_I(reg_x, reg_y); + break; + + case 0x9f: /* SHA $nnnn,Y */ + SH_ABS_I(reg_a_read & reg_x, reg_y); + break; + + case 0xa0: /* LDY #$nn */ + LD(reg_y, GET_IMM, 2); + break; + + case 0xa1: /* LDA ($nn,X) */ + LD(reg_a_write, GET_IND_X, 2); + break; + + case 0xa2: /* LDX #$nn */ + LD(reg_x, GET_IMM, 2); + break; + + case 0xa3: /* LAX ($nn,X) */ + LAX(GET_IND_X, 2); + break; + + case 0xa4: /* LDY $nn */ + LD(reg_y, GET_ZERO, 2); + break; + + case 0xa5: /* LDA $nn */ + LD(reg_a_write, GET_ZERO, 2); + break; + + case 0xa6: /* LDX $nn */ + LD(reg_x, GET_ZERO, 2); + break; + + case 0xa7: /* LAX $nn */ + LAX(GET_ZERO, 2); + break; + + case 0xa8: /* TAY */ + TAY(); + break; + + case 0xa9: /* LDA #$nn */ + LD(reg_a_write, GET_IMM, 2); + break; + + case 0xaa: /* TAX */ + TAX(); + break; + + case 0xab: /* LXA #$nn */ + LXA(); + break; + + case 0xac: /* LDY $nnnn */ + LD(reg_y, GET_ABS, 3); + break; + + case 0xad: /* LDA $nnnn */ + LD(reg_a_write, GET_ABS, 3); + break; + + case 0xae: /* LDX $nnnn */ + LD(reg_x, GET_ABS, 3); + break; + + case 0xaf: /* LAX $nnnn */ + LAX(GET_ABS, 3); + break; + + case 0xb0: /* BCS $nnnn */ + BRANCH(LOCAL_CARRY()); + break; + + case 0xb1: /* LDA ($nn),Y */ + LD(reg_a_write, GET_IND_Y, 2); + break; + + case 0xb3: /* LAX ($nn),Y */ + LAX(GET_IND_Y, 2); + break; + + case 0xb4: /* LDY $nn,X */ + LD(reg_y, GET_ZERO_X, 2); + break; + + case 0xb5: /* LDA $nn,X */ + LD(reg_a_write, GET_ZERO_X, 2); + break; + + case 0xb6: /* LDX $nn,Y */ + LD(reg_x, GET_ZERO_Y, 2); + break; + + case 0xb7: /* LAX $nn,Y */ + LAX(GET_ZERO_Y, 2); + break; + + case 0xb8: /* CLV */ + CLV(); + break; + + case 0xb9: /* LDA $nnnn,Y */ + LD(reg_a_write, GET_ABS_Y, 3); + break; + + case 0xba: /* TSX */ + TSX(); + break; + + case 0xbb: /* LAS $nnnn,Y */ + LAS(); + break; + + case 0xbc: /* LDY $nnnn,X */ + LD(reg_y, GET_ABS_X, 3); + break; + + case 0xbd: /* LDA $nnnn,X */ + LD(reg_a_write, GET_ABS_X, 3); + break; + + case 0xbe: /* LDX $nnnn,Y */ + LD(reg_x, GET_ABS_Y, 3); + break; + + case 0xbf: /* LAX $nnnn,Y */ + LAX(GET_ABS_Y, 3); + break; + + case 0xc0: /* CPY #$nn */ + CP(reg_y, GET_IMM, 2); + break; + + case 0xc1: /* CMP ($nn,X) */ + CP(reg_a_read, GET_IND_X, 2); + break; + + case 0xc3: /* DCP ($nn,X) */ + DCP(2, GET_IND_X, SET_IND_RMW); + break; + + case 0xc4: /* CPY $nn */ + CP(reg_y, GET_ZERO, 2); + break; + + case 0xc5: /* CMP $nn */ + CP(reg_a_read, GET_ZERO, 2); + break; + + case 0xc6: /* DEC $nn */ + DEC(2, GET_ZERO, SET_ZERO_RMW); + break; + + case 0xc7: /* DCP $nn */ + DCP(2, GET_ZERO, SET_ZERO_RMW); + break; + + case 0xc8: /* INY */ + INY(); + break; + + case 0xc9: /* CMP #$nn */ + CP(reg_a_read, GET_IMM, 2); + break; + + case 0xca: /* DEX */ + DEX(); + break; + + case 0xcb: /* SBX #$nn */ + SBX(); + break; + + case 0xcc: /* CPY $nnnn */ + CP(reg_y, GET_ABS, 3); + break; + + case 0xcd: /* CMP $nnnn */ + CP(reg_a_read, GET_ABS, 3); + break; + + case 0xce: /* DEC $nnnn */ + DEC(3, GET_ABS, SET_ABS_RMW); + break; + + case 0xcf: /* DCP $nnnn */ + DCP(3, GET_ABS, SET_ABS_RMW); + break; + + case 0xd0: /* BNE $nnnn */ + BRANCH(!LOCAL_ZERO()); + break; + + case 0xd1: /* CMP ($nn),Y */ + CP(reg_a_read, GET_IND_Y, 2); + break; + + case 0xd3: /* DCP ($nn),Y */ + DCP(2, GET_IND_Y_RMW, SET_IND_RMW); + break; + + case 0xd5: /* CMP $nn,X */ + CP(reg_a_read, GET_ZERO_X, 2); + break; + + case 0xd6: /* DEC $nn,X */ + DEC(2, GET_ZERO_X, SET_ZERO_X_RMW); + break; + + case 0xd7: /* DCP $nn,X */ + DCP(2, GET_ZERO_X, SET_ZERO_X_RMW); + break; + + case 0xd8: /* CLD */ + CLD(); + break; + + case 0xd9: /* CMP $nnnn,Y */ + CP(reg_a_read, GET_ABS_Y, 3); + break; + + case 0xdb: /* DCP $nnnn,Y */ + DCP(3, GET_ABS_Y_RMW, SET_ABS_Y_RMW); + break; + + case 0xdd: /* CMP $nnnn,X */ + CP(reg_a_read, GET_ABS_X, 3); + break; + + case 0xde: /* DEC $nnnn,X */ + DEC(3, GET_ABS_X_RMW, SET_ABS_X_RMW); + break; + + case 0xdf: /* DCP $nnnn,X */ + DCP(3, GET_ABS_X_RMW, SET_ABS_X_RMW); + break; + + case 0xe0: /* CPX #$nn */ + CP(reg_x, GET_IMM, 2); + break; + + case 0xe1: /* SBC ($nn,X) */ + SBC(GET_IND_X, 2); + break; + + case 0xe3: /* ISB ($nn,X) */ + ISB(2, GET_IND_X, SET_IND_RMW); + break; + + case 0xe4: /* CPX $nn */ + CP(reg_x, GET_ZERO, 2); + break; + + case 0xe5: /* SBC $nn */ + SBC(GET_ZERO, 2); + break; + + case 0xe6: /* INC $nn */ + INC(2, GET_ZERO, SET_ZERO_RMW); + break; + + case 0xe7: /* ISB $nn */ + ISB(2, GET_ZERO, SET_ZERO_RMW); + break; + + case 0xe8: /* INX */ + INX(); + break; + + case 0xe9: /* SBC #$nn */ + case 0xeb: /* USBC #$nn (same as SBC) */ + SBC(GET_IMM, 2); + break; + + case 0xec: /* CPX $nnnn */ + CP(reg_x, GET_ABS, 3); + break; + + case 0xed: /* SBC $nnnn */ + SBC(GET_ABS, 3); + break; + + case 0xee: /* INC $nnnn */ + INC(3, GET_ABS, SET_ABS_RMW); + break; + + case 0xef: /* ISB $nnnn */ + ISB(3, GET_ABS, SET_ABS_RMW); + break; + + case 0xf0: /* BEQ $nnnn */ + BRANCH(LOCAL_ZERO()); + break; + + case 0xf1: /* SBC ($nn),Y */ + SBC(GET_IND_Y, 2); + break; + + case 0xf3: /* ISB ($nn),Y */ + ISB(2, GET_IND_Y_RMW, SET_IND_RMW); + break; + + case 0xf5: /* SBC $nn,X */ + SBC(GET_ZERO_X, 2); + break; + + case 0xf6: /* INC $nn,X */ + INC(2, GET_ZERO_X, SET_ZERO_X_RMW); + break; + + case 0xf7: /* ISB $nn,X */ + ISB(2, GET_ZERO_X, SET_ZERO_X_RMW); + break; + + case 0xf8: /* SED */ + SED(); + break; + + case 0xf9: /* SBC $nnnn,Y */ + SBC(GET_ABS_Y, 3); + break; + + case 0xfb: /* ISB $nnnn,Y */ + ISB(3, GET_ABS_Y_RMW, SET_ABS_Y_RMW); + break; + + case 0xfd: /* SBC $nnnn,X */ + SBC(GET_ABS_X, 3); + break; + + case 0xfe: /* INC $nnnn,X */ + INC(3, GET_ABS_X_RMW, SET_ABS_X_RMW); + break; + + case 0xff: /* ISB $nnnn,X */ + ISB(3, GET_ABS_X_RMW, SET_ABS_X_RMW); + break; + } + +#if !defined(DRIVE_CPU) + if (maincpu_profiling) { + profile_sample_finish(CLK - profiling_clock_start - stolen_cycles, stolen_cycles); + } +#endif + + } +} + /// /// end of 6510dtvcore.c @@ -4028,9 +4451,11 @@ INC_PC(1); \ maincpu_int_status->num_dma_per_opcode = 0; if (maincpu_clk_limit && (maincpu_clk > maincpu_clk_limit)) { - log_error(LOG_DEFAULT, "cycle limit reached."); - exit(EXIT_FAILURE); + log_error(maincpu_log, "cycle limit reached."); + archdep_vice_exit(EXIT_FAILURE); } + + autostart_advance(); #if 0 if (CLK > 246171754) { debug.maincpu_traceflg = 1; @@ -4133,45 +4558,48 @@ unsigned int maincpu_get_sp(void) { static char snap_module_name[] = "MAINCPU"; #define SNAP_MAJOR 1 -#define SNAP_MINOR 1 +#define SNAP_MINOR 4 int maincpu_snapshot_write_module(snapshot_t *s) { - snapshot_module_t *m; - - m = snapshot_module_create(s, snap_module_name, ((BYTE)SNAP_MAJOR), - ((BYTE)SNAP_MINOR)); - if (m == NULL) { - return -1; - } - - if (0 - || SMW_DW(m, maincpu_clk) < 0 - || SMW_B(m, MOS6510_REGS_GET_A(&maincpu_regs)) < 0 - || SMW_B(m, MOS6510_REGS_GET_X(&maincpu_regs)) < 0 - || SMW_B(m, MOS6510_REGS_GET_Y(&maincpu_regs)) < 0 - || SMW_B(m, MOS6510_REGS_GET_SP(&maincpu_regs)) < 0 - || SMW_W(m, (WORD)MOS6510_REGS_GET_PC(&maincpu_regs)) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_STATUS(&maincpu_regs)) < 0 - || SMW_DW(m, (DWORD)last_opcode_info) < 0 - || SMW_DW(m, (DWORD)maincpu_ba_low_flags) < 0) { - goto fail; - } - - if (interrupt_write_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - if (interrupt_write_new_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - if (interrupt_write_sc_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - return snapshot_module_close(m); - + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, ((uint8_t)SNAP_MAJOR), + ((uint8_t)SNAP_MINOR)); + if (m == NULL) { + return -1; + } + + if (0 + || SMW_CLOCK(m, maincpu_clk) < 0 + || SMW_B(m, MOS6510_REGS_GET_A(&maincpu_regs)) < 0 + || SMW_B(m, MOS6510_REGS_GET_X(&maincpu_regs)) < 0 + || SMW_B(m, MOS6510_REGS_GET_Y(&maincpu_regs)) < 0 + || SMW_B(m, MOS6510_REGS_GET_SP(&maincpu_regs)) < 0 + || SMW_W(m, (uint16_t)MOS6510_REGS_GET_PC(&maincpu_regs)) < 0 + || SMW_B(m, (uint8_t)MOS6510_REGS_GET_STATUS(&maincpu_regs)) < 0 + || SMW_DW(m, (uint32_t)last_opcode_info) < 0 + || SMW_DW(m, (uint32_t)ane_log_level) < 0 + || SMW_DW(m, (uint32_t)lxa_log_level) < 0 + || SMW_DW(m, (uint32_t)maincpu_jammed) < 0 + || SMW_DW(m, (uint32_t)maincpu_ba_low_flags) < 0) { + goto fail; + } + + if (interrupt_write_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + if (interrupt_write_new_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + if (interrupt_write_sc_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + return snapshot_module_close(m); + fail: if (m != NULL) { snapshot_module_close(m); @@ -4181,56 +4609,58 @@ int maincpu_snapshot_write_module(snapshot_t *s) int maincpu_snapshot_read_module(snapshot_t *s) { - BYTE a, x, y, sp, status; - WORD pc; - BYTE major, minor; - snapshot_module_t *m; - - m = snapshot_module_open(s, snap_module_name, &major, &minor); - if (m == NULL) { - return -1; - } - - /* XXX: Assumes `CLOCK' is the same size as a `DWORD'. */ - if (0 - || SMR_DW(m, &maincpu_clk) < 0 - || SMR_B(m, &a) < 0 - || SMR_B(m, &x) < 0 - || SMR_B(m, &y) < 0 - || SMR_B(m, &sp) < 0 - || SMR_W(m, &pc) < 0 - || SMR_B(m, &status) < 0 - || SMR_DW_UINT(m, &last_opcode_info) < 0 - || SMR_DW_INT(m, &maincpu_ba_low_flags) < 0) { - goto fail; - } - - MOS6510_REGS_SET_A(&maincpu_regs, a); - MOS6510_REGS_SET_X(&maincpu_regs, x); - MOS6510_REGS_SET_Y(&maincpu_regs, y); - MOS6510_REGS_SET_SP(&maincpu_regs, sp); - MOS6510_REGS_SET_PC(&maincpu_regs, pc); - MOS6510_REGS_SET_STATUS(&maincpu_regs, status); - - if (interrupt_read_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - if (interrupt_read_new_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - if (interrupt_read_sc_snapshot(maincpu_int_status, m) < 0) { - goto fail; - } - - return snapshot_module_close(m); - + uint8_t a, x, y, sp, status; + uint16_t pc; + uint8_t major, minor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &major, &minor); + if (m == NULL) { + return -1; + } + + if (0 + || SMR_CLOCK(m, &maincpu_clk) < 0 + || SMR_B(m, &a) < 0 + || SMR_B(m, &x) < 0 + || SMR_B(m, &y) < 0 + || SMR_B(m, &sp) < 0 + || SMR_W(m, &pc) < 0 + || SMR_B(m, &status) < 0 + || SMR_DW_UINT(m, &last_opcode_info) < 0 + || SMR_DW_INT(m, &ane_log_level) < 0 + || SMR_DW_INT(m, &lxa_log_level) < 0 + || SMR_DW_INT(m, &maincpu_jammed) < 0 + || SMR_DW_INT(m, &maincpu_ba_low_flags) < 0) { + goto fail; + } + + MOS6510_REGS_SET_A(&maincpu_regs, a); + MOS6510_REGS_SET_X(&maincpu_regs, x); + MOS6510_REGS_SET_Y(&maincpu_regs, y); + MOS6510_REGS_SET_SP(&maincpu_regs, sp); + MOS6510_REGS_SET_PC(&maincpu_regs, pc); + MOS6510_REGS_SET_STATUS(&maincpu_regs, status); + + if (interrupt_read_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + if (interrupt_read_new_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + if (interrupt_read_sc_snapshot(maincpu_int_status, m) < 0) { + goto fail; + } + + return snapshot_module_close(m); + fail: - if (m != NULL) { - snapshot_module_close(m); - } - return -1; + if (m != NULL) { + snapshot_module_close(m); + } + return -1; } int c64d_check_cpu_snapshot_manager_restore() @@ -4238,6 +4668,11 @@ int c64d_check_cpu_snapshot_manager_restore() if (c64d_check_snapshot_restore()) { enum cpu_int pending_interrupt; + /* DO_INTERRUPT below expands CHECK_PROFILE_INTERRUPT, which references + profiling_clock_start (a per-instruction local in the main loop). This + one-off restore dispatch isn't a profiled instruction, so anchor it at + the current clock (zero attributed duration). */ + CLOCK profiling_clock_start = CLK; // EXPORT_REGISTERS(); \ // interrupt_do_trap(CPU_INT_STATUS, (WORD)reg_pc); \ @@ -4353,5 +4788,6 @@ void c64d_check_cpu_snapshot_manager_store() } + /// "../mainc64cpu.c" ends here /// diff --git a/src/Emulators/vice/c64/c64datasette.c b/src/Emulators/vice/c64/c64datasette.c index 32c55342..81909fe4 100644 --- a/src/Emulators/vice/c64/c64datasette.c +++ b/src/Emulators/vice/c64/c64datasette.c @@ -31,24 +31,41 @@ #include "c64mem.h" #include "cia.h" #include "datasette.h" +#include "tapeport.h" +void machine_trigger_flux_change(int port, unsigned int on) +{ + if (port == TAPEPORT_PORT_1) { + ciacore_set_flag(machine_context.cia1); + } +} -void machine_trigger_flux_change(unsigned int on) +void machine_set_tape_read_in(int port, unsigned int on) { - ciacore_set_flag(machine_context.cia1); + if (port == TAPEPORT_PORT_1) { + if (on) { + ciacore_set_flag(machine_context.cia1); + } + } } -void machine_set_tape_sense(int sense) +void machine_set_tape_sense(int port, int sense) { - mem_set_tape_sense(sense); + if (port == TAPEPORT_PORT_1) { + mem_set_tape_sense(sense); + } } -void machine_set_tape_write_in(int val) +void machine_set_tape_write_in(int port, int val) { - mem_set_tape_write_in(val); + if (port == TAPEPORT_PORT_1) { + mem_set_tape_write_in(val); + } } -void machine_set_tape_motor_in(int val) +void machine_set_tape_motor_in(int port, int val) { - mem_set_tape_motor_in(val); + if (port == TAPEPORT_PORT_1) { + mem_set_tape_motor_in(val); + } } diff --git a/src/Emulators/vice/c64/c64drive.c b/src/Emulators/vice/c64/c64drive.c index e383d1e4..5c5692dc 100644 --- a/src/Emulators/vice/c64/c64drive.c +++ b/src/Emulators/vice/c64/c64drive.c @@ -38,11 +38,16 @@ #include "vicetypes.h" #include "log.h" + int machine_drive_resources_init(void) { int drive_8_type = (machine_class == VICE_MACHINE_VSID) ? DRIVE_TYPE_NONE : DRIVE_TYPE_1541II; - return drive_resources_type_init(drive_8_type) | iec_drive_resources_init() | iec_c64exp_resources_init() | ieee_drive_resources_init(); + /* init drive type resource last, so the ROMs are loaded when it initializes */ + return iec_drive_resources_init() | + iec_c64exp_resources_init() | + ieee_drive_resources_init() | + drive_resources_type_init(drive_8_type); } void machine_drive_resources_shutdown(void) @@ -57,7 +62,7 @@ int machine_drive_cmdline_options_init(void) return iec_drive_cmdline_options_init() | iec_c64exp_cmdline_options_init() | ieee_drive_cmdline_options_init(); } -void machine_drive_init(struct drive_context_s *drv) +void machine_drive_init(struct diskunit_context_s *drv) { iec_drive_init(drv); iecieee_drive_init(drv); @@ -65,14 +70,14 @@ void machine_drive_init(struct drive_context_s *drv) ieee_drive_init(drv); } -void machine_drive_shutdown(struct drive_context_s *drv) +void machine_drive_shutdown(struct diskunit_context_s *drv) { iec_drive_shutdown(drv); iecieee_drive_shutdown(drv); ieee_drive_shutdown(drv); } -void machine_drive_reset(struct drive_context_s *drv) +void machine_drive_reset(struct diskunit_context_s *drv) { iec_drive_reset(drv); iecieee_drive_reset(drv); @@ -80,14 +85,14 @@ void machine_drive_reset(struct drive_context_s *drv) ieee_drive_reset(drv); } -void machine_drive_mem_init(struct drive_context_s *drv, unsigned int type) +void machine_drive_mem_init(struct diskunit_context_s *drv, unsigned int type) { iec_drive_mem_init(drv, type); iec_c64exp_mem_init(drv, type); ieee_drive_mem_init(drv, type); } -void machine_drive_setup_context(struct drive_context_s *drv) +void machine_drive_setup_context(struct diskunit_context_s *drv) { iec_drive_setup_context(drv); iecieee_drive_setup_context(drv); @@ -99,18 +104,21 @@ void machine_drive_idling_method(unsigned int dnr) iec_drive_idling_method(dnr); } +/* test ROMs for existence, size */ void machine_drive_rom_load(void) { iec_drive_rom_load(); ieee_drive_rom_load(); } +/* setup (=load) the ROM for a given disk unit */ void machine_drive_rom_setup_image(unsigned int dnr) { iec_drive_rom_setup_image(dnr); ieee_drive_rom_setup_image(dnr); } +/* check if the drive ROM is available for a given drive type, returns -1 on error */ int machine_drive_rom_check_loaded(unsigned int type) { if (iec_drive_rom_check_loaded(type) == 0) { @@ -123,13 +131,14 @@ int machine_drive_rom_check_loaded(unsigned int type) return -1; } +/* perform checksum check on ROM for given disk unit nr */ void machine_drive_rom_do_checksum(unsigned int dnr) { iec_drive_rom_do_checksum(dnr); ieee_drive_rom_do_checksum(dnr); } -int machine_drive_snapshot_read(struct drive_context_s *ctxptr, struct snapshot_s *s) +int machine_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { if (iec_drive_snapshot_read(ctxptr, s) < 0) { return -1; @@ -144,7 +153,7 @@ int machine_drive_snapshot_read(struct drive_context_s *ctxptr, struct snapshot_ return 0; } -int machine_drive_snapshot_write(struct drive_context_s *ctxptr, struct snapshot_s *s) +int machine_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { if (iec_drive_snapshot_write(ctxptr, s) < 0) { return -1; @@ -159,17 +168,17 @@ int machine_drive_snapshot_write(struct drive_context_s *ctxptr, struct snapshot return 0; } -int machine_drive_image_attach(struct disk_image_s *image, unsigned int unit) +int machine_drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return iec_drive_image_attach(image, unit) & ieee_drive_image_attach(image, unit); + return iec_drive_image_attach(image, unit, drive) & ieee_drive_image_attach(image, unit, drive); } -int machine_drive_image_detach(struct disk_image_s *image, unsigned int unit) +int machine_drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return iec_drive_image_detach(image, unit) & ieee_drive_image_detach(image, unit); + return iec_drive_image_detach(image, unit, drive) & ieee_drive_image_detach(image, unit, drive); } -void machine_drive_port_default(struct drive_context_s *drv) +void machine_drive_port_default(struct diskunit_context_s *drv) { iec_drive_port_default(drv); } diff --git a/src/Emulators/vice/c64/c64embedded.c b/src/Emulators/vice/c64/c64embedded.c index 0b433bf1..203c1327 100644 --- a/src/Emulators/vice/c64/c64embedded.c +++ b/src/Emulators/vice/c64/c64embedded.c @@ -36,6 +36,7 @@ #include #include "c64mem.h" +#include "c64rom.h" #include "embedded.h" #include "machine.h" @@ -55,10 +56,24 @@ #include "vicii_rgb_vpl.h" #include "vicii_vice_vpl.h" +/* VICE 3.10 added version-suffixed default ROM filenames (KernalName="kernal-901227-03.bin" etc.). + RD doesn't ship real ROM bytes here (esrc=NULL) -- the lookup just claims success so + machine_specific_init proceeds; actual ROM/RAM state is restored from + src/Embedded/reset_basic_snap_zlib.h after vice_main_program returns. + These entries match the 3.10 default names AND keep the 3.1 bare names for any + third-party harness that still sets KernalName="kernal" etc. */ static embedded_t c64files[] = { - { "basic", C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, NULL }, - { "kernal", C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, - { "chargen", C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, NULL }, + { "basic", C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, NULL }, + { "kernal", C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { "chargen", C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, NULL }, + { C64_BASIC_NAME, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE, NULL }, + { C64_KERNAL_REV2_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_KERNAL_REV3_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_KERNAL_JAP_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_KERNAL_SX64_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_KERNAL_GS64_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_KERNAL_4064_NAME, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE, NULL }, + { C64_CHARGEN_NAME, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE, NULL }, EMBEDDED_LIST_END }; @@ -125,10 +140,11 @@ int embedded_palette_load(const char *fname, palette_t *p) if (!strcmp(palette_files[i].name1, fname) || !strcmp(palette_files[i].name2, fname)) { entries = palette_files[i].palette; for (j = 0; j < palette_files[i].num_entries; j++) { + /* VICE 3.10 dropped palette_entry_s.dither; embedded arrays keep the + legacy 4-byte (R,G,B,dither) stride, so the 4th byte is now ignored. */ p->entries[j].red = entries[(j * 4) + 0]; p->entries[j].green = entries[(j * 4) + 1]; p->entries[j].blue = entries[(j * 4) + 2]; - p->entries[j].dither = entries[(j * 4) + 3]; } return 0; } diff --git a/src/Emulators/vice/c64/c64export.c b/src/Emulators/vice/c64/c64export.c index 9aa466e7..db83d3b8 100644 --- a/src/Emulators/vice/c64/c64export.c +++ b/src/Emulators/vice/c64/c64export.c @@ -36,7 +36,6 @@ #include "export.h" #include "lib.h" #include "monitor.h" -#include "translate.h" #include "uiapi.h" /* #define DEBUGEXPORT */ @@ -58,10 +57,13 @@ export_list_t *export_query_list(export_list_t *item) } } +/* assigned to monitor interface in src/c64/cart/c64cart.c */ void export_dump(void) { export_list_t *current = NULL; io_source_t *io; + int cartid; + int is128 = (machine_class == VICE_MACHINE_C128); current = export_query_list(current); @@ -69,14 +71,34 @@ void export_dump(void) mon_out("No expansion port devices.\n"); } else { /*- ----- - - --------- --------- ------------------------ */ + if (is128) { + /*12345*/ + mon_out(" "); + } mon_out(" CRTID GAME EXROM IO1-usage IO2-usage Name\n"); while (current != NULL) { + int c128cart = CARTRIDGE_C128_ISID(current->device->cartid); if (cart_is_slotmain(current->device->cartid)) { mon_out("* "); } else { mon_out(" "); } - mon_out("%5d ", current->device->cartid); + if (is128) { + if (c128cart) { + /*12345*/ + mon_out("C128:"); + } else { + mon_out(" C64:"); + } + } + cartid = ((int)current->device->cartid); + if (cartid < 0) { + mon_out("0/%d ", cartid); + } else if (is128 && c128cart) { + mon_out("%5d ", CARTRIDGE_C128_CRTID(cartid)); + } else { + mon_out("%5d ", cartid); + } mon_out("%4s ", current->device->game ? "*" : "-"); mon_out("%5s ", current->device->exrom ? "*" : "-"); io = current->device->io1; @@ -93,7 +115,7 @@ void export_dump(void) } /* show (inactive) in front of the name when no PLA lines nor I/O resources are used, this should not happen in normal - operation and usually indicates a bug */ + operation and usually indicates a bug UNLESS this is a C128 :) */ if ((!current->device->game) && (!current->device->exrom) && (!current->device->io1) && @@ -103,8 +125,10 @@ void export_dump(void) mon_out("%s\n", current->device->name); current = current->next; } - mon_out("Current GAME status: (%d) (%s)\n", !export.game, (export.game) ? "active" : "inactive"); - mon_out("Current EXROM status: (%d) (%s)\n", !export.exrom, (export.exrom) ? "active" : "inactive"); + mon_out("Current mode: %s, GAME status: (%d) (%s), EXROM status: (%d) (%s)\n", + cart_config_string(((export.exrom ^ 1) << 1) | export.game), + !export.game, (export.game) ? "active" : "inactive", + !export.exrom, (export.exrom) ? "active" : "inactive"); } } diff --git a/src/Emulators/vice/c64/c64fastiec.c b/src/Emulators/vice/c64/c64fastiec.c index cbed3e27..d228df32 100644 --- a/src/Emulators/vice/c64/c64fastiec.c +++ b/src/Emulators/vice/c64/c64fastiec.c @@ -35,11 +35,12 @@ #include "iecdrive.h" #include "maincpu.h" #include "vicetypes.h" +#include "drive/iec/cmdhd.h" /* Fast IEC for C64 with burst mod */ -static int fast_drive_direction[DRIVE_NUM]; +static int fast_drive_direction[NUM_DISK_UNITS]; int burst_mod; int set_burst_mod(int mode, void *param) @@ -61,39 +62,42 @@ void c64fastiec_init(void) { unsigned int dnr; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { fast_drive_direction[dnr] = 1; } } -void c64fastiec_fast_cpu_write(BYTE data) +void c64fastiec_fast_cpu_write(uint8_t data) { - drive_t *drive; unsigned int dnr; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - if (drive->enable) { - drive_cpu_execute_one(drive_context[dnr], maincpu_clk); - switch (drive->type) { + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + + if (unit->enable) { + drive_cpu_execute_one(unit, maincpu_clk); + switch (unit->type) { case DRIVE_TYPE_1570: case DRIVE_TYPE_1571: case DRIVE_TYPE_1571CR: - ciacore_set_sdr(drive_context[dnr]->cia1571, data); + ciacore_set_sdr(unit->cia1571, data); break; case DRIVE_TYPE_1581: - ciacore_set_sdr(drive_context[dnr]->cia1581, data); + ciacore_set_sdr(unit->cia1581, data); break; case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: - viacore_set_sr(drive_context[dnr]->via4000, data); + viacore_set_sr(unit->via4000, data); + break; + case DRIVE_TYPE_CMDHD: + viacore_set_sr(unit->cmdhd->via10, data); break; } } } } -void iec_fast_drive_write(BYTE data, unsigned int dnr) +void iec_fast_drive_write(uint8_t data, unsigned int dnr) { if (fast_drive_direction[dnr]) { switch (burst_mod) { diff --git a/src/Emulators/vice/c64/c64fastiec.h b/src/Emulators/vice/c64/c64fastiec.h index 14f73353..17d4dd0f 100644 --- a/src/Emulators/vice/c64/c64fastiec.h +++ b/src/Emulators/vice/c64/c64fastiec.h @@ -33,9 +33,10 @@ #define BURST_MOD_CIA1 1 #define BURST_MOD_CIA2 2 -extern void c64fastiec_init(void); -extern void c64fastiec_fast_cpu_write(BYTE data); extern int burst_mod; -extern int set_burst_mod(int mode, void *param); + +void c64fastiec_init(void); +void c64fastiec_fast_cpu_write(uint8_t data); +int set_burst_mod(int mode, void *param); #endif diff --git a/src/Emulators/vice/c64/c64gluelogic.c b/src/Emulators/vice/c64/c64gluelogic.c index 538c390e..6878949d 100644 --- a/src/Emulators/vice/c64/c64gluelogic.c +++ b/src/Emulators/vice/c64/c64gluelogic.c @@ -38,7 +38,6 @@ #include "maincpu.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "vicii.h" @@ -133,7 +132,7 @@ static int set_glue_type(int val, void *param) return 0; } -static const resource_int_t resources_int[] = { +static resource_int_t resources_int[] = { { "GlueLogic", GLUE_LOGIC_CUSTOM_IC, RES_EVENT_NO, NULL, &glue_logic_type, set_glue_type, NULL }, RESOURCE_INT_LIST_END @@ -141,15 +140,17 @@ static const resource_int_t resources_int[] = { int c64_glue_resources_init(void) { + if (machine_class == VICE_MACHINE_C64) { + resources_int[0].factory_value = GLUE_LOGIC_DISCRETE; + } return resources_register_int(resources_int); } -static const cmdline_option_t cmdline_options[] = { - { "-gluelogictype", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-gluelogictype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "GlueLogic", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_TYPE, IDCLS_SET_GLUE_LOGIC_TYPE, - NULL, NULL }, + "", "Set glue logic type (0 = discrete, 1 = 252535-01)" }, CMDLINE_LIST_END }; @@ -187,10 +188,9 @@ int c64_glue_snapshot_write_module(snapshot_t *s) return -1; } - if (0 - || SMW_B(m, (BYTE)glue_logic_type) < 0 - || SMW_B(m, (BYTE)old_vbank) < 0 - || SMW_B(m, (BYTE)glue_alarm_active) < 0) { + if (SMW_B(m, (uint8_t)glue_logic_type) < 0 + || SMW_B(m, (uint8_t)old_vbank) < 0 + || SMW_B(m, (uint8_t)glue_alarm_active) < 0) { goto fail; } @@ -205,7 +205,7 @@ int c64_glue_snapshot_write_module(snapshot_t *s) int c64_glue_snapshot_read_module(snapshot_t *s) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; int snap_type, snap_alarm_active; snapshot_module_t *m; @@ -215,15 +215,14 @@ int c64_glue_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (major_version > SNAP_MAJOR || minor_version > SNAP_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } - if (0 - || SMR_B_INT(m, &snap_type) < 0 - || SMR_B_INT(m, &old_vbank) < 0 - || SMR_B_INT(m, &snap_alarm_active) < 0) { + if (SMR_B_INT(m, &snap_type) < 0 + || SMR_B_INT(m, &old_vbank) < 0 + || SMR_B_INT(m, &snap_alarm_active) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/c64gluelogic.h b/src/Emulators/vice/c64/c64gluelogic.h index 47b6d4cd..8e4fe272 100644 --- a/src/Emulators/vice/c64/c64gluelogic.h +++ b/src/Emulators/vice/c64/c64gluelogic.h @@ -32,17 +32,17 @@ #define GLUE_LOGIC_DISCRETE 0 #define GLUE_LOGIC_CUSTOM_IC 1 -extern void c64_glue_set_vbank(int vbank, int ddr_flag); -extern void c64_glue_undump(int vbank); -extern void c64_glue_reset(void); +void c64_glue_set_vbank(int vbank, int ddr_flag); +void c64_glue_undump(int vbank); +void c64_glue_reset(void); -extern void c64_glue_init(void); -extern int c64_glue_resources_init(void); -extern int c64_glue_cmdline_options_init(void); +void c64_glue_init(void); +int c64_glue_resources_init(void); +int c64_glue_cmdline_options_init(void); struct snapshot_s; -extern int c64_glue_snapshot_write_module(struct snapshot_s *s); -extern int c64_glue_snapshot_read_module(struct snapshot_s *s); +int c64_glue_snapshot_write_module(struct snapshot_s *s); +int c64_glue_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/c64iec.c b/src/Emulators/vice/c64/c64iec.c index d21853fb..9742884e 100644 --- a/src/Emulators/vice/c64/c64iec.c +++ b/src/Emulators/vice/c64/c64iec.c @@ -93,7 +93,7 @@ static void iec_debug_ports(void) old_iecbus.drv_port = iecbus.drv_port; } - for (unit = 0; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 0; unit < 8 + NUM_DISK_UNITS; unit++) { if ((old_iecbus.drv_bus[unit] != iecbus.drv_bus[unit]) || firstcall) { log_message(LOG_DEFAULT, "#%lu: drv_bus[ %2u] changed from $%02x to $%02x.", time_usec, unit, old_iecbus.drv_bus[unit], iecbus.drv_bus[unit]); old_iecbus.drv_bus[unit] = iecbus.drv_bus[unit]; @@ -118,7 +118,7 @@ static void iec_debug_ports(void) int c64iec_active = 1; -void iec_update_cpu_bus(BYTE data) +void iec_update_cpu_bus(uint8_t data) { iecbus.cpu_bus = (((data << 2) & 0x80) | ((data << 2) & 0x40) | ((data << 1) & 0x10)); } @@ -128,7 +128,7 @@ void iec_update_ports(void) unsigned int unit; iecbus.cpu_port = iecbus.cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { iecbus.cpu_port &= iecbus.drv_bus[unit]; } @@ -142,14 +142,14 @@ void iec_update_ports_embedded(void) iec_update_ports(); } -void iec_drive_write(BYTE data, unsigned int dnr) +void iec_drive_write(uint8_t data, unsigned int dnr) { iecbus.drv_bus[dnr + 8] = (((data << 3) & 0x40) | ((data << 6) & ((~data ^ iecbus.cpu_bus) << 3) & 0x80)); iecbus.drv_data[dnr + 8] = data; iec_update_ports(); } -BYTE iec_drive_read(unsigned int dnr) +uint8_t iec_drive_read(unsigned int dnr) { return iecbus.drv_port; } @@ -162,7 +162,12 @@ iecbus_t *iecbus_drive_port(void) /* This function is called from ui_update_menus() */ int iec_available_busses(void) { - return IEC_BUS_IEC | (cartridge_type_enabled(CARTRIDGE_IEEE488) ? IEC_BUS_IEEE : 0); + if (cartridge_type_enabled(CARTRIDGE_IEEE488) || + cartridge_type_enabled(CARTRIDGE_IEEEFLASH64)) { + return IEC_BUS_IEC | IEC_BUS_IEEE; + } else { + return IEC_BUS_IEC; + } } void c64iec_init(void) @@ -175,14 +180,22 @@ void c64iec_enable(int val) c64iec_active = val ? 1 : 0; } +int c64iec_get_active_state(void) +{ + return c64iec_active; +} + /* KLUDGES: dummy to satisfy linker, unused */ -BYTE plus4tcbm_outputa[2], plus4tcbm_outputb[2], plus4tcbm_outputc[2]; -void plus4tcbm_update_pa(BYTE byte, unsigned int dnr) +uint8_t plus4tcbm_outputa[2], plus4tcbm_outputb[2], plus4tcbm_outputc[2]; + +void plus4tcbm_update_pa(uint8_t byte, unsigned int dnr) { } -void plus4tcbm_update_pb(BYTE byte, unsigned int dnr) + +void plus4tcbm_update_pb(uint8_t byte, unsigned int dnr) { } -void plus4tcbm_update_pc(BYTE byte, unsigned int dnr) + +void plus4tcbm_update_pc(uint8_t byte, unsigned int dnr) { } diff --git a/src/Emulators/vice/c64/c64iec.h b/src/Emulators/vice/c64/c64iec.h index c998c970..82bf7dcc 100644 --- a/src/Emulators/vice/c64/c64iec.h +++ b/src/Emulators/vice/c64/c64iec.h @@ -31,9 +31,11 @@ #ifndef VICE_C64IEC_H #define VICE_C64IEC_H -extern void c64iec_init(void); -extern void c64iec_enable(int val); +void c64iec_init(void); +void c64iec_enable(int val); extern int c64iec_active; +int c64iec_get_active_state(void); + #endif diff --git a/src/Emulators/vice/c64/c64io.c b/src/Emulators/vice/c64/c64io.c index 251e5fe1..60c727eb 100644 --- a/src/Emulators/vice/c64/c64io.c +++ b/src/Emulators/vice/c64/c64io.c @@ -30,6 +30,7 @@ #include #include +#include "archdep.h" #include "cartio.h" #include "cartridge.h" #include "cmdline.h" @@ -37,7 +38,6 @@ #include "log.h" #include "monitor.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" @@ -48,13 +48,13 @@ /* #define IODEBUGRW */ #ifdef IODEBUG -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif #ifdef IODEBUGRW -#define DBGRW(x) printf x +#define DBGRW(x) log_printf x #else #define DBGRW(x) #endif @@ -74,6 +74,7 @@ static io_source_list_t c64io_d400_head = { NULL, NULL, NULL }; static io_source_list_t c64io_d500_head = { NULL, NULL, NULL }; static io_source_list_t c64io_d600_head = { NULL, NULL, NULL }; static io_source_list_t c64io_d700_head = { NULL, NULL, NULL }; +static io_source_list_t c64io_dd00_head = { NULL, NULL, NULL }; static io_source_list_t c64io_de00_head = { NULL, NULL, NULL }; static io_source_list_t c64io_df00_head = { NULL, NULL, NULL }; @@ -84,9 +85,9 @@ static void io_source_detach(io_source_detach_t *source) if (source->det_cartid != CARTRIDGE_NONE) { #ifdef IODEBUG if (source->det_cartid == 0) { - DBG(("IO: cart id in io struct is 0, it should be updated! name: %s\n", source->det_devname)); + DBG(("IO: cart id in io struct is 0, it should be updated! name: %s", source->det_devname)); } else { - DBG(("IO: io_source_detach id:%d name: %s\n", source->det_cartid, source->det_devname)); + DBG(("IO: io_source_detach id:%d name: %s", source->det_cartid, source->det_devname)); } #endif assert(source->det_cartid != CARTRIDGE_CRT); /* CARTRIDGE_CRT is not allowed at this point */ @@ -97,13 +98,12 @@ static void io_source_detach(io_source_detach_t *source) resources_set_int(source->det_name, 0); break; } - ui_update_menus(); } /* amount is 2 or more */ -static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *start) +static void io_source_msg_detach_all(uint16_t addr, int amount, io_source_list_t *start) { io_source_detach_t *detach_list = lib_malloc(sizeof(io_source_detach_t) * amount); io_source_list_t *current = start; @@ -114,9 +114,9 @@ static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *st current = current->next; - DBG(("IO: check %d sources for addr %04x\n", amount, addr)); + DBG(("IO: check %d sources for addr %04x", amount, addr)); while (current) { - /* DBG(("IO: check '%s'\n", current->device->name)); */ + /* DBG(("IO: check '%s'", current->device->name)); */ if (current->device->io_source_valid && addr >= current->device->start_address && addr <= current->device->end_address && @@ -126,11 +126,11 @@ static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *st detach_list[found].det_name = current->device->resource_name; detach_list[found].det_devname = current->device->name; detach_list[found].det_cartid = current->device->cart_id; - DBG(("IO: found #%d: '%s'\n", found, current->device->name)); + DBG(("IO: found #%d: '%s'", found, current->device->name)); /* first part of the message "read collision at x from" */ if (found == 0) { - old_msg = lib_stralloc(translate_text(IDGS_IO_READ_COLL_AT_X_FROM)); + old_msg = lib_strdup("I/O read collision at %X from "); new_msg = util_concat(old_msg, current->device->name, NULL); lib_free(old_msg); } @@ -141,7 +141,7 @@ static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *st } if (found == amount - 1) { old_msg = new_msg; - new_msg = util_concat(old_msg, translate_text(IDGS_AND), current->device->name, translate_text(IDGS_ALL_DEVICES_DETACHED), NULL); + new_msg = util_concat(old_msg, " and ", current->device->name, ".\nAll the named devices will be detached.", NULL); lib_free(old_msg); } found++; @@ -157,9 +157,9 @@ static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *st ui_error(new_msg, addr); lib_free(new_msg); - DBG(("IO: found %d items to detach\n", found)); + DBG(("IO: found %d items to detach", found)); for (i = 0; i < found; i++) { - DBG(("IO: detach #%d id:%d name: %s\n", i, detach_list[i].det_cartid, detach_list[i].det_devname)); + DBG(("IO: detach #%d id:%d name: %s", i, detach_list[i].det_cartid, detach_list[i].det_devname)); io_source_detach(&detach_list[i]); } } @@ -169,7 +169,7 @@ static void io_source_msg_detach_all(WORD addr, int amount, io_source_list_t *st /* amount is 2 or more */ -static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *start, unsigned int lowest) +static void io_source_msg_detach_last(uint16_t addr, int amount, io_source_list_t *start, unsigned int lowest) { io_source_detach_t *detach_list = lib_malloc(sizeof(io_source_detach_t) * amount); io_source_list_t *current = start; @@ -181,9 +181,9 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s current = current->next; - DBG(("IO: check %d sources for addr %04x\n", real_amount, addr)); + DBG(("IO: check %d sources for addr %04x", real_amount, addr)); while (current) { - /* DBG(("IO: check '%s'\n", current->device->name)); */ + /* DBG(("IO: check '%s'", current->device->name)); */ if (current->device->io_source_valid && addr >= current->device->start_address && addr <= current->device->end_address && @@ -194,7 +194,7 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s detach_list[found].det_devname = current->device->name; detach_list[found].det_cartid = current->device->cart_id; detach_list[found].order = current->device->order; - DBG(("IO: found #%d: '%s'\n", found, current->device->name)); + DBG(("IO: found #%d: '%s'", found, current->device->name)); if (current->device->order == lowest) { first_cart = current->device->name; @@ -202,7 +202,7 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s /* first part of the message "read collision at x from" */ if (found == 0) { - old_msg = lib_stralloc(translate_text(IDGS_IO_READ_COLL_AT_X_FROM)); + old_msg = lib_strdup("I/O read collision at %X from "); new_msg = util_concat(old_msg, current->device->name, NULL); lib_free(old_msg); } @@ -213,7 +213,7 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s } if (found == amount - 1) { old_msg = new_msg; - new_msg = util_concat(old_msg, translate_text(IDGS_AND), current->device->name, translate_text(IDGS_ALL_DEVICES_EXCEPT), first_cart, translate_text(IDGS_WILL_BE_DETACHED), NULL); + new_msg = util_concat(old_msg, " and ", current->device->name, ".\nAll devices except ", first_cart, " will be detached.", NULL); lib_free(old_msg); } found++; @@ -229,10 +229,10 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s ui_error(new_msg, addr); lib_free(new_msg); - DBG(("IO: found %d items to detach\n", found)); + DBG(("IO: found %d items to detach", found)); for (i = 0; i < found; i++) { if (detach_list[i].order != lowest) { - DBG(("IO: detach #%d id:%d name: %s\n", i, detach_list[i].det_cartid, detach_list[i].det_devname)); + DBG(("IO: detach #%d id:%d name: %s", i, detach_list[i].det_cartid, detach_list[i].det_devname)); io_source_detach(&detach_list[i]); } } @@ -243,7 +243,7 @@ static void io_source_msg_detach_last(WORD addr, int amount, io_source_list_t *s /* amount is 2 or more */ -static void io_source_log_collisions(WORD addr, int amount, io_source_list_t *start) +static void io_source_log_collisions(uint16_t addr, int amount, io_source_list_t *start) { io_source_list_t *current = start; char *old_msg = NULL; @@ -252,19 +252,19 @@ static void io_source_log_collisions(WORD addr, int amount, io_source_list_t *st current = current->next; - DBG(("IO: check %d sources for addr %04x\n", amount, addr)); + DBG(("IO: check %d sources for addr %04x", amount, addr)); while (current) { - /* DBG(("IO: check '%s'\n", current->device->name)); */ + /* DBG(("IO: check '%s'", current->device->name)); */ if (current->device->io_source_valid && addr >= current->device->start_address && addr <= current->device->end_address && current->device->io_source_prio == IO_PRIO_NORMAL) { /* found a conflict */ - DBG(("IO: found #%d: '%s'\n", found, current->device->name)); + DBG(("IO: found #%d: '%s'", found, current->device->name)); /* first part of the message "read collision at x from" */ if (found == 0) { - old_msg = lib_stralloc(translate_text(IDGS_IO_READ_COLL_AT_X_FROM)); + old_msg = lib_strdup("I/O read collision at %X from "); new_msg = util_concat(old_msg, current->device->name, NULL); lib_free(old_msg); } @@ -275,7 +275,7 @@ static void io_source_log_collisions(WORD addr, int amount, io_source_list_t *st } if (found == amount - 1) { old_msg = new_msg; - new_msg = util_concat(old_msg, translate_text(IDGS_AND), current->device->name, NULL); + new_msg = util_concat(old_msg, " and ", current->device->name, NULL); lib_free(old_msg); } found++; @@ -292,14 +292,14 @@ static void io_source_log_collisions(WORD addr, int amount, io_source_list_t *st } } -static inline BYTE io_read(io_source_list_t *list, WORD addr) +static inline uint8_t io_read(io_source_list_t *list, uint16_t addr) { io_source_list_t *current = list->next; int io_source_counter = 0; int io_source_valid = 0; - BYTE realval = 0; - BYTE retval = 0; - BYTE firstval = 0; + uint8_t realval = 0; + uint8_t retval = 0; + uint8_t firstval = 0; unsigned int lowest_order = 0xffffffff; vicii_handle_pending_alarms_external(0); @@ -307,7 +307,7 @@ static inline BYTE io_read(io_source_list_t *list, WORD addr) while (current) { if (current->device->read != NULL) { if ((addr >= current->device->start_address) && (addr <= current->device->end_address)) { - retval = current->device->read((WORD)(addr & current->device->address_mask)); + retval = current->device->read((uint16_t)(addr & current->device->address_mask)); if (current->device->io_source_valid) { /* high prio always overrides others, return immediatly */ if (current->device->io_source_prio == IO_PRIO_HIGH) { @@ -354,8 +354,8 @@ static inline BYTE io_read(io_source_list_t *list, WORD addr) return vicii_read_phi1(); } /* only one valid I/O source was read, return value */ - if (!(io_source_counter > 1)) { - return retval; + if (io_source_valid == 1) { + return firstval; } /* more than one I/O source was read, handle collision */ if (io_source_collision_handling == IO_COLLISION_METHOD_DETACH_ALL) { @@ -372,16 +372,16 @@ static inline BYTE io_read(io_source_list_t *list, WORD addr) } /* peek from I/O area with no side-effects */ -static inline BYTE io_peek(io_source_list_t *list, WORD addr) +static inline uint8_t io_peek(io_source_list_t *list, uint16_t addr) { io_source_list_t *current = list->next; while (current) { if (addr >= current->device->start_address && addr <= current->device->end_address) { if (current->device->peek) { - return current->device->peek((WORD)(addr & current->device->address_mask)); + return current->device->peek((uint16_t)(addr & current->device->address_mask)); } else if (current->device->read) { - return current->device->read((WORD)(addr & current->device->address_mask)); + return current->device->read((uint16_t)(addr & current->device->address_mask)); } } current = current->next; @@ -390,12 +390,12 @@ static inline BYTE io_peek(io_source_list_t *list, WORD addr) return vicii_read_phi1(); } -static inline void io_store(io_source_list_t *list, WORD addr, BYTE value) +static inline void io_store(io_source_list_t *list, uint16_t addr, uint8_t value) { int writes = 0; - WORD addy = 0xffff; + uint16_t addy = 0xffff; io_source_list_t *current = list->next; - void (*store)(WORD address, BYTE data) = NULL; + void (*store)(uint16_t address, uint8_t data) = NULL; vicii_handle_pending_alarms_external_write(); @@ -404,10 +404,10 @@ static inline void io_store(io_source_list_t *list, WORD addr, BYTE value) if (addr >= current->device->start_address && addr <= current->device->end_address) { /* delay mirror writes, ensuring real device writes in mirror area */ if (current->device->io_source_prio != IO_PRIO_LOW) { - current->device->store((WORD)(addr & current->device->address_mask), value); + current->device->store((uint16_t)(addr & current->device->address_mask), value); writes++; } else { - addy = (WORD)(addr & current->device->address_mask); + addy = (uint16_t)(addr & current->device->address_mask); store = current->device->store; } } @@ -428,7 +428,7 @@ io_source_list_t *io_source_register(io_source_t *device) io_source_list_t *retval = lib_malloc(sizeof(io_source_list_t)); assert(device != NULL); - DBG(("IO: register id:%d name:%s\n", device->cart_id, device->name)); + DBG(("IO: register id:%d name:%s", device->cart_id, device->name)); switch (device->start_address & 0xff00) { case 0xd000: @@ -455,12 +455,22 @@ io_source_list_t *io_source_register(io_source_t *device) case 0xd700: current = &c64io_d700_head; break; + case 0xdd00: + current = &c64io_dd00_head; + break; case 0xde00: current = &c64io_de00_head; break; case 0xdf00: current = &c64io_df00_head; break; + default: + log_error(LOG_DEFAULT, + "io_source_register internal error: I/O range 0x%04x " + "does not exist", + device->start_address & 0xff00U); + archdep_vice_exit(-1); + break; } while (current->next != NULL) { @@ -480,7 +490,7 @@ void io_source_unregister(io_source_list_t *device) io_source_list_t *prev; assert(device != NULL); - DBG(("IO: unregister id:%d name:%s\n", device->device->cart_id, device->device->name)); + DBG(("IO: unregister id:%d name:%s", device->device->cart_id, device->device->name)); prev = device->previous; prev->next = device->next; @@ -550,6 +560,12 @@ void cartio_shutdown(void) current = c64io_d700_head.next; } + current = c64io_dd00_head.next; + while (current) { + io_source_unregister(current); + current = c64io_dd00_head.next; + } + current = c64io_de00_head.next; while (current) { io_source_unregister(current); @@ -570,183 +586,201 @@ void cartio_set_highest_order(unsigned int nr) /* ---------------------------------------------------------------------------------------------------------- */ -BYTE c64io_d000_read(WORD addr) +uint8_t c64io_d000_read(uint16_t addr) { - DBGRW(("IO: io-d000 r %04x\n", addr)); + DBGRW(("IO: io-d000 r %04x", addr)); return io_read(&c64io_d000_head, addr); } -BYTE c64io_d000_peek(WORD addr) +uint8_t c64io_d000_peek(uint16_t addr) { - DBGRW(("IO: io-d000 p %04x\n", addr)); + DBGRW(("IO: io-d000 p %04x", addr)); return io_peek(&c64io_d000_head, addr); } -void c64io_d000_store(WORD addr, BYTE value) +void c64io_d000_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d000 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d000 w %04x %02x", addr, value)); io_store(&c64io_d000_head, addr, value); } -BYTE c64io_d100_read(WORD addr) +uint8_t c64io_d100_read(uint16_t addr) { - DBGRW(("IO: io-d100 r %04x\n", addr)); + DBGRW(("IO: io-d100 r %04x", addr)); return io_read(&c64io_d100_head, addr); } -BYTE c64io_d100_peek(WORD addr) +uint8_t c64io_d100_peek(uint16_t addr) { - DBGRW(("IO: io-d100 p %04x\n", addr)); + DBGRW(("IO: io-d100 p %04x", addr)); return io_peek(&c64io_d100_head, addr); } -void c64io_d100_store(WORD addr, BYTE value) +void c64io_d100_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d100 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d100 w %04x %02x", addr, value)); io_store(&c64io_d100_head, addr, value); } -BYTE c64io_d200_read(WORD addr) +uint8_t c64io_d200_read(uint16_t addr) { - DBGRW(("IO: io-d200 r %04x\n", addr)); + DBGRW(("IO: io-d200 r %04x", addr)); return io_read(&c64io_d200_head, addr); } -BYTE c64io_d200_peek(WORD addr) +uint8_t c64io_d200_peek(uint16_t addr) { - DBGRW(("IO: io-d200 p %04x\n", addr)); + DBGRW(("IO: io-d200 p %04x", addr)); return io_peek(&c64io_d200_head, addr); } -void c64io_d200_store(WORD addr, BYTE value) +void c64io_d200_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d200 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d200 w %04x %02x", addr, value)); io_store(&c64io_d200_head, addr, value); } -BYTE c64io_d300_read(WORD addr) +uint8_t c64io_d300_read(uint16_t addr) { - DBGRW(("IO: io-d300 r %04x\n", addr)); + DBGRW(("IO: io-d300 r %04x", addr)); return io_read(&c64io_d300_head, addr); } -BYTE c64io_d300_peek(WORD addr) +uint8_t c64io_d300_peek(uint16_t addr) { - DBGRW(("IO: io-d300 p %04x\n", addr)); + DBGRW(("IO: io-d300 p %04x", addr)); return io_peek(&c64io_d300_head, addr); } -void c64io_d300_store(WORD addr, BYTE value) +void c64io_d300_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d300 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d300 w %04x %02x", addr, value)); io_store(&c64io_d300_head, addr, value); } -BYTE c64io_d400_read(WORD addr) +uint8_t c64io_d400_read(uint16_t addr) { - DBGRW(("IO: io-d400 r %04x\n", addr)); + DBGRW(("IO: io-d400 r %04x", addr)); return io_read(&c64io_d400_head, addr); } -BYTE c64io_d400_peek(WORD addr) +uint8_t c64io_d400_peek(uint16_t addr) { - DBGRW(("IO: io-d400 p %04x\n", addr)); + DBGRW(("IO: io-d400 p %04x", addr)); return io_peek(&c64io_d400_head, addr); } -void c64io_d400_store(WORD addr, BYTE value) +void c64io_d400_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d400 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d400 w %04x %02x", addr, value)); io_store(&c64io_d400_head, addr, value); } -BYTE c64io_d500_read(WORD addr) +uint8_t c64io_d500_read(uint16_t addr) { - DBGRW(("IO: io-d500 r %04x\n", addr)); + DBGRW(("IO: io-d500 r %04x", addr)); return io_read(&c64io_d500_head, addr); } -BYTE c64io_d500_peek(WORD addr) +uint8_t c64io_d500_peek(uint16_t addr) { - DBGRW(("IO: io-d500 p %04x\n", addr)); + DBGRW(("IO: io-d500 p %04x", addr)); return io_peek(&c64io_d500_head, addr); } -void c64io_d500_store(WORD addr, BYTE value) +void c64io_d500_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d500 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d500 w %04x %02x", addr, value)); io_store(&c64io_d500_head, addr, value); } -BYTE c64io_d600_read(WORD addr) +uint8_t c64io_d600_read(uint16_t addr) { - DBGRW(("IO: io-d600 r %04x\n", addr)); + DBGRW(("IO: io-d600 r %04x", addr)); return io_read(&c64io_d600_head, addr); } -BYTE c64io_d600_peek(WORD addr) +uint8_t c64io_d600_peek(uint16_t addr) { - DBGRW(("IO: io-d600 p %04x\n", addr)); + DBGRW(("IO: io-d600 p %04x", addr)); return io_peek(&c64io_d600_head, addr); } -void c64io_d600_store(WORD addr, BYTE value) +void c64io_d600_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d600 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d600 w %04x %02x", addr, value)); io_store(&c64io_d600_head, addr, value); } -BYTE c64io_d700_read(WORD addr) +uint8_t c64io_d700_read(uint16_t addr) { - DBGRW(("IO: io-d700 r %04x\n", addr)); + DBGRW(("IO: io-d700 r %04x", addr)); return io_read(&c64io_d700_head, addr); } -BYTE c64io_d700_peek(WORD addr) +uint8_t c64io_d700_peek(uint16_t addr) { - DBGRW(("IO: io-d700 p %04x\n", addr)); + DBGRW(("IO: io-d700 p %04x", addr)); return io_peek(&c64io_d700_head, addr); } -void c64io_d700_store(WORD addr, BYTE value) +void c64io_d700_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-d700 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-d700 w %04x %02x", addr, value)); io_store(&c64io_d700_head, addr, value); } -BYTE c64io_de00_read(WORD addr) +uint8_t c64io_dd00_read(uint16_t addr) { - DBGRW(("IO: io-de00 r %04x\n", addr)); + DBGRW(("IO: io-dd00 r %04x", addr)); + return io_read(&c64io_dd00_head, addr); +} + +uint8_t c64io_dd00_peek(uint16_t addr) +{ + DBGRW(("IO: io-dd00 p %04x", addr)); + return io_peek(&c64io_dd00_head, addr); +} + +void c64io_dd00_store(uint16_t addr, uint8_t value) +{ + DBGRW(("IO: io-dd00 w %04x %02x", addr, value)); + io_store(&c64io_dd00_head, addr, value); +} + +uint8_t c64io_de00_read(uint16_t addr) +{ + DBGRW(("IO: io-de00 r %04x", addr)); return io_read(&c64io_de00_head, addr); } -BYTE c64io_de00_peek(WORD addr) +uint8_t c64io_de00_peek(uint16_t addr) { - DBGRW(("IO: io-de00 p %04x\n", addr)); + DBGRW(("IO: io-de00 p %04x", addr)); return io_peek(&c64io_de00_head, addr); } -void c64io_de00_store(WORD addr, BYTE value) +void c64io_de00_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-de00 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-de00 w %04x %02x", addr, value)); io_store(&c64io_de00_head, addr, value); } -BYTE c64io_df00_read(WORD addr) +uint8_t c64io_df00_read(uint16_t addr) { - DBGRW(("IO: io-df00 r %04x\n", addr)); + DBGRW(("IO: io-df00 r %04x", addr)); return io_read(&c64io_df00_head, addr); } -BYTE c64io_df00_peek(WORD addr) +uint8_t c64io_df00_peek(uint16_t addr) { - DBGRW(("IO: io-df00 p %04x\n", addr)); + DBGRW(("IO: io-df00 p %04x", addr)); return io_peek(&c64io_df00_head, addr); } -void c64io_df00_store(WORD addr, BYTE value) +void c64io_df00_store(uint16_t addr, uint8_t value) { - DBGRW(("IO: io-df00 w %04x %02x\n", addr, value)); + DBGRW(("IO: io-df00 w %04x %02x", addr, value)); io_store(&c64io_df00_head, addr, value); } @@ -754,7 +788,7 @@ void c64io_df00_store(WORD addr, BYTE value) static void io_source_ioreg_add_onelist(struct mem_ioreg_list_s **mem_ioreg_list, io_source_list_t *current) { - WORD end; + uint16_t end; while (current) { end = current->device->end_address; @@ -762,7 +796,8 @@ static void io_source_ioreg_add_onelist(struct mem_ioreg_list_s **mem_ioreg_list end = current->device->start_address + current->device->address_mask; } - mon_ioreg_add_list(mem_ioreg_list, current->device->name, current->device->start_address, end, current->device->dump, NULL); + mon_ioreg_add_list(mem_ioreg_list, current->device->name, current->device->start_address, + end, current->device->dump, NULL, current->device->mirror_mode); current = current->next; } } @@ -778,6 +813,7 @@ void io_source_ioreg_add_list(struct mem_ioreg_list_s **mem_ioreg_list) io_source_ioreg_add_onelist(mem_ioreg_list, c64io_d500_head.next); io_source_ioreg_add_onelist(mem_ioreg_list, c64io_d600_head.next); io_source_ioreg_add_onelist(mem_ioreg_list, c64io_d700_head.next); + io_source_ioreg_add_onelist(mem_ioreg_list, c64io_dd00_head.next); io_source_ioreg_add_onelist(mem_ioreg_list, c64io_de00_head.next); io_source_ioreg_add_onelist(mem_ioreg_list, c64io_df00_head.next); } @@ -810,12 +846,11 @@ int cartio_resources_init(void) return resources_register_int(resources_int); } -static const cmdline_option_t cmdline_options[] = { - { "-iocollision", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-iocollision", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IOCollisionHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_SELECT_CONFLICT_HANDLING, - NULL, NULL }, + "", "Select the way the I/O collisions should be handled, (0: error message and detach all involved carts, 1: error message and detach last attached involved carts, 2: warning in log and 'AND' the valid return values" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/c64/c64keyboard.c b/src/Emulators/vice/c64/c64keyboard.c index 404ffbbf..9eb419d1 100644 --- a/src/Emulators/vice/c64/c64keyboard.c +++ b/src/Emulators/vice/c64/c64keyboard.c @@ -35,11 +35,11 @@ #include "maincpu.h" #include "vicii.h" -int c64keyboard_active = 1; +int c64keyboard_active = 1; /* flag to disable the keyboard for C64GS */ static unsigned int c64keyboard_int_num; -static void c64keyboard_machine_func(int *keyarr) +static void c64keyboard_machine_func(int *karr) { cia1_check_lightpen(); } diff --git a/src/Emulators/vice/c64/c64keyboard.h b/src/Emulators/vice/c64/c64keyboard.h index cbc978c2..152e274d 100644 --- a/src/Emulators/vice/c64/c64keyboard.h +++ b/src/Emulators/vice/c64/c64keyboard.h @@ -27,10 +27,10 @@ #ifndef VICE_C64KEYBOARD_H #define VICE_C64KEYBOARD_H -extern void c64keyboard_init(void); -extern void c64keyboard_restore_key(int v); +void c64keyboard_init(void); +void c64keyboard_restore_key(int v); -extern void c64keyboard_enable(int val); +void c64keyboard_enable(int val); extern int c64keyboard_active; diff --git a/src/Emulators/vice/c64/c64mem.h b/src/Emulators/vice/c64/c64mem.h index 9271b748..115ef4f8 100644 --- a/src/Emulators/vice/c64/c64mem.h +++ b/src/Emulators/vice/c64/c64mem.h @@ -40,63 +40,49 @@ #define C64_BASIC_ROM_SIZE 0x2000 #define C64_CHARGEN_ROM_SIZE 0x1000 -#define C64_BASIC_CHECKSUM 15702 +int c64_mem_init_resources(void); +int c64_mem_init_cmdline_options(void); -#define C64_KERNAL_CHECKSUM_R01 54525 -#define C64_KERNAL_CHECKSUM_R02 50955 -#define C64_KERNAL_CHECKSUM_R03 50954 -#define C64_KERNAL_CHECKSUM_R03swe 50633 -#define C64_KERNAL_CHECKSUM_R43 50955 -#define C64_KERNAL_CHECKSUM_R64 49680 +void mem_set_vbank(int new_vbank); -/* the value located at 0xff80 */ -#define C64_KERNAL_ID_R01 0xaa -#define C64_KERNAL_ID_R02 0x00 -#define C64_KERNAL_ID_R03 0x03 -#define C64_KERNAL_ID_R03swe 0x03 -#define C64_KERNAL_ID_R43 0x43 -#define C64_KERNAL_ID_R64 0x64 +uint8_t ram_read(uint16_t addr); +void ram_store(uint16_t addr, uint8_t value); +void ram_hi_store(uint16_t addr, uint8_t value); -extern int c64_mem_init_resources(void); -extern int c64_mem_init_cmdline_options(void); +uint8_t chargen_read(uint16_t addr); +void chargen_store(uint16_t addr, uint8_t value); -extern void mem_set_vbank(int new_vbank); +void colorram_store(uint16_t addr, uint8_t value); +uint8_t colorram_read(uint16_t addr); -extern BYTE ram_read(WORD addr); -extern void ram_store(WORD addr, BYTE value); -extern void ram_hi_store(WORD addr, BYTE value); +void mem_pla_config_changed(void); +void mem_set_tape_sense(int sense); +void mem_set_tape_write_in(int val); +void mem_set_tape_motor_in(int val); -extern BYTE chargen_read(WORD addr); -extern void chargen_store(WORD addr, BYTE value); +extern uint8_t mem_chargen_rom[C64_CHARGEN_ROM_SIZE]; -extern void colorram_store(WORD addr, BYTE value); -extern BYTE colorram_read(WORD addr); +void mem_set_write_hook(int config, int page, store_func_t *f); +void mem_read_tab_set(unsigned int base, unsigned int index, read_func_ptr_t read_func); +void mem_read_base_set(unsigned int base, unsigned int index, uint8_t *mem_ptr); +void mem_read_addr_set(unsigned int base, unsigned int index, uintptr_t addr); +void mem_read_limit_set(unsigned int base, unsigned int index, uint32_t limit); -extern void mem_pla_config_changed(void); -extern void mem_set_tape_sense(int sense); -extern void mem_set_tape_write_in(int val); -extern void mem_set_tape_motor_in(int val); +void mem_store_without_ultimax(uint16_t addr, uint8_t value); +uint8_t mem_read_without_ultimax(uint16_t addr); +void mem_store_without_romlh(uint16_t addr, uint8_t value); -extern BYTE mem_chargen_rom[C64_CHARGEN_ROM_SIZE]; +void store_bank_io(uint16_t addr, uint8_t byte); +uint8_t read_bank_io(uint16_t addr); -extern void mem_set_write_hook(int config, int page, store_func_t *f); -extern void mem_read_tab_set(unsigned int base, unsigned int index, read_func_ptr_t read_func); -extern void mem_read_base_set(unsigned int base, unsigned int index, BYTE *mem_ptr); +void c64_mem_init(void); -extern void mem_store_without_ultimax(WORD addr, BYTE value); -extern BYTE mem_read_without_ultimax(WORD addr); -extern void mem_store_without_romlh(WORD addr, BYTE value); +int c64_mem_ui_init_early(void); +int c64_mem_ui_init(void); +void c64_mem_ui_shutdown(void); -extern void store_bank_io(WORD addr, BYTE byte); -extern BYTE read_bank_io(WORD addr); - -extern void c64_mem_init(void); - -extern int c64_mem_ui_init_early(void); -extern int c64_mem_ui_init(void); -extern void c64_mem_ui_shutdown(void); - -extern BYTE vsid_io_read(WORD addr); -extern void vsid_io_store(WORD addr, BYTE val); +uint8_t vsid_io_read(uint16_t addr); +uint8_t vsid_io_peek(uint16_t addr); +void vsid_io_store(uint16_t addr, uint8_t val); #endif diff --git a/src/Emulators/vice/c64/c64meminit.c b/src/Emulators/vice/c64/c64meminit.c index 6c7a5da9..195edf19 100644 --- a/src/Emulators/vice/c64/c64meminit.c +++ b/src/Emulators/vice/c64/c64meminit.c @@ -35,6 +35,7 @@ #include "c64mem.h" #include "c64meminit.h" #include "c64memrom.h" +#include "c64model.h" #include "cartio.h" #include "machine.h" #include "resources.h" @@ -47,9 +48,9 @@ bit 4 - !game bit 3 - !exrom - bit 2 - loram + bit 2 - charen bit 1 - hiram - bit 0 - charen + bit 0 - loram 8000 a000 d000 e000 @@ -100,7 +101,7 @@ const unsigned int c64meminit_io_config[32] = { }; /* ROML is enabled at memory configs 11, 15, 27, 31 and Ultimax. */ -static const unsigned int c64meminit_roml_config[32] = { +const unsigned int c64meminit_roml_config[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -109,7 +110,7 @@ static const unsigned int c64meminit_roml_config[32] = { /* ROMH is enabled at memory configs 10, 11, 14, 15, 26, 27, 30, 31 and Ultimax. */ -static const unsigned int c64meminit_romh_config[32] = { +const unsigned int c64meminit_romh_config[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, @@ -118,37 +119,47 @@ static const unsigned int c64meminit_romh_config[32] = { /* ROMH is mapped to $A000-$BFFF at memory configs 10, 11, 14, 15, 26, 27, 30, 31. If Ultimax is enabled it is mapped to $E000-$FFFF. */ -static const unsigned int c64meminit_romh_mapping[32] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xe0, 0xe0, 0xe0, 0xe0, - 0xe0, 0xe0, 0xe0, 0xe0, - 0x00, 0x00, 0xa0, 0xa0, - 0x00, 0x00, 0xa0, 0xa0 +const unsigned int c64meminit_romh_mapping[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0x00, 0x00, 0xa0, 0xa0, 0x00, 0x00, 0xa0, 0xa0 }; void c64meminit(unsigned int base) { unsigned int i, j; - int board = 0; + int board = BOARD_C64; if (machine_class != VICE_MACHINE_C128) { resources_get_int("BoardType", &board); } - if (board != 1) { + if (board != BOARD_MAX) { /* Setup BASIC ROM at $A000-$BFFF (memory configs 3, 7, 11, 15). */ for (i = 0xa0; i <= 0xbf; i++) { + uintptr_t addr = 0 - 0xa000; + mem_read_tab_set(base + 3, i, c64memrom_basic64_read); mem_read_tab_set(base + 7, i, c64memrom_basic64_read); mem_read_tab_set(base + 11, i, c64memrom_basic64_read); mem_read_tab_set(base + 15, i, c64memrom_basic64_read); +#if 0 mem_read_base_set(base + 3, i, c64memrom_basic64_rom - 0xa000); mem_read_base_set(base + 7, i, c64memrom_basic64_rom - 0xa000); mem_read_base_set(base + 11, i, c64memrom_basic64_rom - 0xa000); mem_read_base_set(base + 15, i, c64memrom_basic64_rom - 0xa000); +#else + mem_read_base_set(base + 3, i, (uint8_t*)addr); + mem_read_base_set(base + 7, i, (uint8_t*)addr); + mem_read_base_set(base + 11, i, (uint8_t*)addr); + mem_read_base_set(base + 15, i, (uint8_t*)addr); + + mem_read_addr_set(base + 3, i, (uintptr_t)c64memrom_basic64_rom); + mem_read_addr_set(base + 7, i, (uintptr_t)c64memrom_basic64_rom); + mem_read_addr_set(base + 11, i, (uintptr_t)c64memrom_basic64_rom); + mem_read_addr_set(base + 15, i, (uintptr_t)c64memrom_basic64_rom); +#endif } } @@ -178,10 +189,9 @@ void c64meminit(unsigned int base) mem_read_tab_set(base + j, 0xdc, cia1_read); mem_set_write_hook(base + j, 0xdc, cia1_store); - if (board != 1) { - mem_read_tab_set(base + j, 0xdd, cia2_read); - mem_set_write_hook(base + j, 0xdd, cia2_store); - } + + mem_read_tab_set(base + j, 0xdd, c64io_dd00_read); + mem_set_write_hook(base + j, 0xdd, c64io_dd00_store); mem_read_tab_set(base + j, 0xde, c64io_de00_read); mem_set_write_hook(base + j, 0xde, c64io_de00_store); @@ -201,10 +211,11 @@ void c64meminit(unsigned int base) } } - if (board != 1) { + if (board != BOARD_MAX) { /* Setup Kernal ROM at $E000-$FFFF (memory configs 2, 3, 6, 7, 10, 11, 14, 15, 26, 27, 30, 31). */ for (i = 0xe0; i <= 0xff; i++) { + uintptr_t addr = 0 - 0xe000; mem_read_tab_set(base + 2, i, c64memrom_kernal64_read); mem_read_tab_set(base + 3, i, c64memrom_kernal64_read); mem_read_tab_set(base + 6, i, c64memrom_kernal64_read); @@ -217,6 +228,7 @@ void c64meminit(unsigned int base) mem_read_tab_set(base + 27, i, c64memrom_kernal64_read); mem_read_tab_set(base + 30, i, c64memrom_kernal64_read); mem_read_tab_set(base + 31, i, c64memrom_kernal64_read); +#if 0 mem_read_base_set(base + 2, i, c64memrom_kernal64_trap_rom - 0xe000); mem_read_base_set(base + 3, i, c64memrom_kernal64_trap_rom - 0xe000); mem_read_base_set(base + 6, i, c64memrom_kernal64_trap_rom - 0xe000); @@ -229,6 +241,33 @@ void c64meminit(unsigned int base) mem_read_base_set(base + 27, i, c64memrom_kernal64_trap_rom - 0xe000); mem_read_base_set(base + 30, i, c64memrom_kernal64_trap_rom - 0xe000); mem_read_base_set(base + 31, i, c64memrom_kernal64_trap_rom - 0xe000); +#else + mem_read_base_set(base + 2, i, (uint8_t*)addr); + mem_read_base_set(base + 3, i, (uint8_t*)addr); + mem_read_base_set(base + 6, i, (uint8_t*)addr); + mem_read_base_set(base + 7, i, (uint8_t*)addr); + mem_read_base_set(base + 10, i, (uint8_t*)addr); + mem_read_base_set(base + 11, i, (uint8_t*)addr); + mem_read_base_set(base + 14, i, (uint8_t*)addr); + mem_read_base_set(base + 15, i, (uint8_t*)addr); + mem_read_base_set(base + 26, i, (uint8_t*)addr); + mem_read_base_set(base + 27, i, (uint8_t*)addr); + mem_read_base_set(base + 30, i, (uint8_t*)addr); + mem_read_base_set(base + 31, i, (uint8_t*)addr); + + mem_read_addr_set(base + 2, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 3, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 6, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 7, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 10, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 11, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 14, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 15, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 26, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 27, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 30, i, (uintptr_t)c64memrom_kernal64_trap_rom); + mem_read_addr_set(base + 31, i, (uintptr_t)c64memrom_kernal64_trap_rom); +#endif } } @@ -309,6 +348,13 @@ void c64meminit(unsigned int base) /* Setup Ultimax configuration. */ for (j = 16; j < 24; j++) { + if (board == BOARD_MAX) { + for (i = 0x08; i <= 0x0f; i++) { + mem_read_tab_set(base + j, i, ultimax_0800_0fff_read); + mem_set_write_hook(base + j, i, ultimax_0800_0fff_store); + mem_read_base_set(base + j, i, NULL); + } + } for (i = 0x10; i <= 0x7f; i++) { mem_read_tab_set(base + j, i, ultimax_1000_7fff_read); mem_set_write_hook(base + j, i, ultimax_1000_7fff_store); diff --git a/src/Emulators/vice/c64/c64meminit.h b/src/Emulators/vice/c64/c64meminit.h index 3a009dbc..7a1ebb2c 100644 --- a/src/Emulators/vice/c64/c64meminit.h +++ b/src/Emulators/vice/c64/c64meminit.h @@ -30,5 +30,8 @@ extern void c64meminit(unsigned int base); extern const unsigned int c64meminit_io_config[32]; +extern const unsigned int c64meminit_roml_config[32]; +extern const unsigned int c64meminit_romh_config[32]; +extern const unsigned int c64meminit_romh_mapping[32]; #endif diff --git a/src/Emulators/vice/c64/c64memlimit.c b/src/Emulators/vice/c64/c64memlimit.c index 4c2f8612..da247ce0 100644 --- a/src/Emulators/vice/c64/c64memlimit.c +++ b/src/Emulators/vice/c64/c64memlimit.c @@ -28,7 +28,9 @@ #include "vice.h" #include "c64memlimit.h" +#include "c64mem.h" +#define NUM_CONFIGS 32 #define NUM_SEGMENTS 7 static const int mstart[NUM_SEGMENTS] = { @@ -41,7 +43,7 @@ static const int mend[NUM_SEGMENTS] = { 0xbf, 0xcf, 0xdf, 0xff }; -static const DWORD limit_tab[NUM_SEGMENTS][NUM_CONFIGS] = { +static const uint32_t limit_tab[NUM_SEGMENTS][NUM_CONFIGS] = { /* 0000-0fff */ { 0x0002fffd, 0x0002cffd, 0x0002cffd, 0x00029ffd, 0x0002fffd, 0x0002cffd, 0x0002cffd, 0x00029ffd, 0x0002fffd, 0x0002cffd, 0x00029ffd, 0x00027ffd, 0x0002fffd, 0x0002cffd, 0x00029ffd, 0x00027ffd, @@ -84,21 +86,21 @@ static const DWORD limit_tab[NUM_SEGMENTS][NUM_CONFIGS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0x0002fffd, 0xe000fffd, 0xe000fffd, 0xe000fffd, 0x0002fffd, 0xe000fffd, 0xe000fffd, 0xe000fffd } }; -void mem_limit_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) +void mem_limit_init(void) { int i, j, k; for (i = 0; i < NUM_CONFIGS; i++) { for (j = 0; j < NUM_SEGMENTS; j++) { for (k = mstart[j]; k <= mend[j]; k++) { - mem_read_limit_tab[i][k] = limit_tab[j][i]; + mem_read_limit_set(i, k, limit_tab[j][i]); } } - mem_read_limit_tab[i][0x100] = 0; + mem_read_limit_set(i, 0x100, 0); } } -void mem_limit_plus60k_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) +void mem_limit_plus60k_init(void) { int i, j, k; @@ -106,31 +108,31 @@ void mem_limit_plus60k_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) for (j = 0; j < NUM_SEGMENTS; j++) { for (k = mstart[j]; k <= mend[j]; k++) { if (k < 0x10) { - mem_read_limit_tab[i][k] = 0x00020ffd; + mem_read_limit_set(i, k, 0x00020ffd); } else { - mem_read_limit_tab[i][k] = 0; + mem_read_limit_set(i, k, 0); } } } - mem_read_limit_tab[i][0x100] = 0; + mem_read_limit_set(i, 0x100, 0); } } -void mem_limit_256k_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) +void mem_limit_256k_init(void) { int i, j, k; for (i = 0; i < NUM_CONFIGS; i++) { for (j = 0; j < NUM_SEGMENTS; j++) { for (k = mstart[j]; k <= mend[j]; k++) { - mem_read_limit_tab[i][k] = 0; + mem_read_limit_set(i, k, 0); } } - mem_read_limit_tab[i][0x100] = 0; + mem_read_limit_set(i, 0x100, 0); } } -void mem_limit_max_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) +void mem_limit_max_init(void) { int i, j, k; @@ -138,12 +140,12 @@ void mem_limit_max_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]) for (j = 0; j < NUM_SEGMENTS; j++) { for (k = mstart[j]; k <= mend[j]; k++) { if (k < 0x8) { - mem_read_limit_tab[i][k] = 0x000207fd; + mem_read_limit_set(i, k, 0x000207fd); } else { - mem_read_limit_tab[i][k] = 0; + mem_read_limit_set(i, k, 0); } } } - mem_read_limit_tab[i][0x100] = 0; + mem_read_limit_set(i, 0x100, 0); } } diff --git a/src/Emulators/vice/c64/c64memlimit.h b/src/Emulators/vice/c64/c64memlimit.h index 7dfe1015..b45c2801 100644 --- a/src/Emulators/vice/c64/c64memlimit.h +++ b/src/Emulators/vice/c64/c64memlimit.h @@ -29,11 +29,9 @@ #define VICE_C64MEMLIMIT_H #include "vicetypes.h" -#define NUM_CONFIGS 32 - -extern void mem_limit_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]); -extern void mem_limit_plus60k_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]); -extern void mem_limit_256k_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]); -extern void mem_limit_max_init(DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]); +extern void mem_limit_init(void); +extern void mem_limit_plus60k_init(void); +extern void mem_limit_256k_init(void); +extern void mem_limit_max_init(void); #endif diff --git a/src/Emulators/vice/c64/c64memrom.c b/src/Emulators/vice/c64/c64memrom.c index e7bbaf31..5fd74048 100644 --- a/src/Emulators/vice/c64/c64memrom.c +++ b/src/Emulators/vice/c64/c64memrom.c @@ -31,37 +31,32 @@ #include "vicetypes.h" #include -#ifdef USE_EMBEDDED -#include "c64basic.h" -#include "c64kernal.h" -#else -BYTE c64memrom_basic64_rom[C64_BASIC_ROM_SIZE]; -BYTE c64memrom_kernal64_rom[C64_KERNAL_ROM_SIZE]; -#endif +uint8_t c64memrom_basic64_rom[C64_BASIC_ROM_SIZE]; +uint8_t c64memrom_kernal64_rom[C64_KERNAL_ROM_SIZE]; -BYTE c64memrom_kernal64_trap_rom[C64_KERNAL_ROM_SIZE]; +uint8_t c64memrom_kernal64_trap_rom[C64_KERNAL_ROM_SIZE]; -BYTE c64memrom_kernal64_read(WORD addr) +uint8_t c64memrom_kernal64_read(uint16_t addr) { return c64memrom_kernal64_rom[addr & 0x1fff]; } -static void c64memrom_kernal64_store(WORD addr, BYTE value) +static void c64memrom_kernal64_store(uint16_t addr, uint8_t value) { c64memrom_kernal64_rom[addr & 0x1fff] = value; } -BYTE c64memrom_basic64_read(WORD addr) +uint8_t c64memrom_basic64_read(uint16_t addr) { return c64memrom_basic64_rom[addr & 0x1fff]; } -static void c64memrom_basic64_store(WORD addr, BYTE value) +static void c64memrom_basic64_store(uint16_t addr, uint8_t value) { c64memrom_basic64_rom[addr & 0x1fff] = value; } -BYTE c64memrom_trap_read(WORD addr) +uint8_t c64memrom_trap_read(uint16_t addr) { switch (addr & 0xf000) { case 0xe000: @@ -72,7 +67,7 @@ BYTE c64memrom_trap_read(WORD addr) return 0; } -void c64memrom_trap_store(WORD addr, BYTE value) +void c64memrom_trap_store(uint16_t addr, uint8_t value) { switch (addr & 0xf000) { case 0xe000: @@ -82,7 +77,7 @@ void c64memrom_trap_store(WORD addr, BYTE value) } } -BYTE c64memrom_rom64_read(WORD addr) +uint8_t c64memrom_rom64_read(uint16_t addr) { switch (addr & 0xf000) { case 0xa000: @@ -98,7 +93,7 @@ BYTE c64memrom_rom64_read(WORD addr) return 0; } -void c64memrom_rom64_store(WORD addr, BYTE value) +void c64memrom_rom64_store(uint16_t addr, uint8_t value) { switch (addr & 0xf000) { case 0xa000: diff --git a/src/Emulators/vice/c64/c64memrom.h b/src/Emulators/vice/c64/c64memrom.h index 7ca19329..c99da09f 100644 --- a/src/Emulators/vice/c64/c64memrom.h +++ b/src/Emulators/vice/c64/c64memrom.h @@ -29,16 +29,16 @@ #include "vicetypes.h" -extern BYTE c64memrom_basic64_rom[]; -extern BYTE c64memrom_kernal64_rom[]; -extern BYTE c64memrom_kernal64_trap_rom[]; +extern uint8_t c64memrom_basic64_rom[]; +extern uint8_t c64memrom_kernal64_rom[]; +extern uint8_t c64memrom_kernal64_trap_rom[]; -extern BYTE c64memrom_kernal64_read(WORD addr); -extern BYTE c64memrom_basic64_read(WORD addr); -extern BYTE c64memrom_trap_read(WORD addr); -extern void c64memrom_trap_store(WORD addr, BYTE value); +uint8_t c64memrom_kernal64_read(uint16_t addr); +uint8_t c64memrom_basic64_read(uint16_t addr); +uint8_t c64memrom_trap_read(uint16_t addr); +void c64memrom_trap_store(uint16_t addr, uint8_t value); -extern BYTE c64memrom_rom64_read(WORD addr); -extern void c64memrom_rom64_store(WORD addr, BYTE value); +uint8_t c64memrom_rom64_read(uint16_t addr); +void c64memrom_rom64_store(uint16_t addr, uint8_t value); #endif diff --git a/src/Emulators/vice/c64/c64memsc.c b/src/Emulators/vice/c64/c64memsc.c index 624d147f..3768c0c8 100644 --- a/src/Emulators/vice/c64/c64memsc.c +++ b/src/Emulators/vice/c64/c64memsc.c @@ -35,6 +35,7 @@ #include "alarm.h" #include "c64.h" +#include "c64-memory-hacks.h" #include "c64-resources.h" #include "c64_256k.h" #include "c64cart.h" @@ -43,14 +44,15 @@ #include "c64meminit.h" #include "c64memlimit.h" #include "c64memrom.h" +#include "c64model.h" #include "c64pla.h" #include "c64ui.h" #include "c64cartmem.h" #include "cartio.h" #include "cartridge.h" #include "cia.h" -#include "clkguard.h" #include "cpmcart.h" +#include "lib.h" #include "machine.h" #include "mainc64cpu.h" #include "maincpu.h" @@ -74,6 +76,9 @@ /* Machine class (moved from c64.c to distinguish between x64 and x64sc) */ int machine_class = VICE_MACHINE_C64SC; +/* import from c64-resources.c - don't use the resource for performance reasons */ +extern int board_type; + /* C64 memory-related resources. */ /* ------------------------------------------------------------------------- */ @@ -88,30 +93,29 @@ int machine_class = VICE_MACHINE_C64SC; //BYTE mem_ram[C64_RAM_SIZE]; BYTE *mem_ram; -#ifdef USE_EMBEDDED -#include "c64chargen.h" -#else -BYTE mem_chargen_rom[C64_CHARGEN_ROM_SIZE]; -#endif +uint8_t mem_chargen_rom[C64_CHARGEN_ROM_SIZE]; /* Internal color memory. */ -static BYTE mem_color_ram[0x400]; -BYTE *mem_color_ram_cpu, *mem_color_ram_vicii; +#define COLORRAM_SIZE 0x400 +static uint8_t mem_color_ram[COLORRAM_SIZE]; +uint8_t *mem_color_ram_cpu, *mem_color_ram_vicii; /* Pointer to the chargen ROM. */ -BYTE *mem_chargen_rom_ptr; +uint8_t *mem_chargen_rom_ptr; /* Pointers to the currently used memory read and write tables. */ read_func_ptr_t *_mem_read_tab_ptr; store_func_ptr_t *_mem_write_tab_ptr; -static BYTE **_mem_read_base_tab_ptr; -static DWORD *mem_read_limit_tab_ptr; +read_func_ptr_t *_mem_read_tab_ptr_dummy; +store_func_ptr_t *_mem_write_tab_ptr_dummy; +static uint8_t **_mem_read_base_tab_ptr; +static uint32_t *mem_read_limit_tab_ptr; /* Memory read and write tables. */ static store_func_ptr_t mem_write_tab[NUM_CONFIGS][0x101]; static read_func_ptr_t mem_read_tab[NUM_CONFIGS][0x101]; -static BYTE *mem_read_base_tab[NUM_CONFIGS][0x101]; -static DWORD mem_read_limit_tab[NUM_CONFIGS][0x101]; +static uint8_t *mem_read_base_tab[NUM_CONFIGS][0x101]; +static uint32_t mem_read_limit_tab[NUM_CONFIGS][0x101]; static store_func_ptr_t mem_write_tab_watch[0x101]; static read_func_ptr_t mem_read_tab_watch[0x101]; @@ -128,46 +132,67 @@ static int tape_sense = 0; static int tape_write_in = 0; static int tape_motor_in = 0; -/* Current watchpoint state. 1 = watchpoints active, 0 = no watchpoints */ -static int watchpoints_active; +/* Current watchpoint state. + 0 = no watchpoints + bit0; 1 = watchpoints active + bit1; 2 = watchpoints trigger on dummy accesses +*/ +static int watchpoints_active = 0; /* ------------------------------------------------------------------------- */ -static BYTE zero_read_watch(WORD addr) +static uint8_t zero_read_watch(uint16_t addr) { addr &= 0xff; monitor_watch_push_load_addr(addr, e_comp_space); return mem_read_tab[mem_config][0](addr); } -static void zero_store_watch(WORD addr, BYTE value) +static void zero_store_watch(uint16_t addr, uint8_t value) { addr &= 0xff; monitor_watch_push_store_addr(addr, e_comp_space); mem_write_tab[mem_config][0](addr, value); } -static BYTE read_watch(WORD addr) +static uint8_t read_watch(uint16_t addr) { monitor_watch_push_load_addr(addr, e_comp_space); return mem_read_tab[mem_config][addr >> 8](addr); } -static void store_watch(WORD addr, BYTE value) +static void store_watch(uint16_t addr, uint8_t value) { monitor_watch_push_store_addr(addr, e_comp_space); mem_write_tab[mem_config][addr >> 8](addr, value); } -void mem_toggle_watchpoints(int flag, void *context) +/* called by mem_pla_config_changed(), mem_toggle_watchpoints() */ +static void mem_update_tab_ptrs(int flag) { if (flag) { _mem_read_tab_ptr = mem_read_tab_watch; _mem_write_tab_ptr = mem_write_tab_watch; + if (flag > 1) { + /* enable watchpoints on dummy accesses */ + _mem_read_tab_ptr_dummy = mem_read_tab_watch; + _mem_write_tab_ptr_dummy = mem_write_tab_watch; + } else { + _mem_read_tab_ptr_dummy = mem_read_tab[mem_config]; + _mem_write_tab_ptr_dummy = mem_write_tab[mem_config]; + } } else { + /* all watchpoints disabled */ _mem_read_tab_ptr = mem_read_tab[mem_config]; _mem_write_tab_ptr = mem_write_tab[mem_config]; + _mem_read_tab_ptr_dummy = mem_read_tab[mem_config]; + _mem_write_tab_ptr_dummy = mem_write_tab[mem_config]; } +} + +void mem_toggle_watchpoints(int flag, void *context) +{ + mem_update_tab_ptrs(flag); watchpoints_active = flag; } @@ -190,28 +215,8 @@ void mem_toggle_watchpoints(int flag, void *context) see testprogs/CPU/cpuport for details and tests */ -static void clk_overflow_callback(CLOCK sub, void *unused_data) -{ - if (pport.data_set_clk_bit6 > (CLOCK)0) { - pport.data_set_clk_bit6 -= sub; - } - if (pport.data_falloff_bit6 && (pport.data_set_clk_bit6 < maincpu_clk)) { - pport.data_falloff_bit6 = 0; - pport.data_set_bit6 = 0; - } - if (pport.data_set_clk_bit7 > (CLOCK)0) { - pport.data_set_clk_bit7 -= sub; - } - if (pport.data_falloff_bit7 && (pport.data_set_clk_bit7 < maincpu_clk)) { - pport.data_falloff_bit7 = 0; - pport.data_set_bit7 = 0; - } -} - void c64_mem_init(void) { - clk_guard_add_callback(maincpu_clk_guard, clk_overflow_callback, NULL); - /* Initialize REU BA low interface (FIXME find a better place for this) */ reu_ba_register(vicii_cycle_reu, vicii_steal_cycles, &maincpu_ba_low_flags, MAINCPU_BA_LOW_REU); @@ -219,33 +224,53 @@ void c64_mem_init(void) cpmcart_ba_register(vicii_cycle, vicii_steal_cycles, &maincpu_ba_low_flags, MAINCPU_BA_LOW_VICII); } +int mem_get_current_bank_config(void) { + return mem_config; +} + void mem_pla_config_changed(void) { mem_config = (((~pport.dir | pport.data) & 0x7) | (export.exrom << 3) | (export.game << 4)); - c64pla_config_changed(tape_sense, tape_write_in, tape_motor_in, 1, 0x17); - - if (watchpoints_active) { - _mem_read_tab_ptr = mem_read_tab_watch; - _mem_write_tab_ptr = mem_write_tab_watch; + /* NOTE: CPU port bits 3,4,5 are not connected on the SX64 board */ + if (board_type == BOARD_SX64) { + c64pla_config_changed(1, 1, 1, 1, 0x07); } else { - _mem_read_tab_ptr = mem_read_tab[mem_config]; - _mem_write_tab_ptr = mem_write_tab[mem_config]; + c64pla_config_changed(tape_sense, tape_write_in, tape_motor_in, 1, 0x17); } + mem_update_tab_ptrs(watchpoints_active); + _mem_read_base_tab_ptr = mem_read_base_tab[mem_config]; mem_read_limit_tab_ptr = mem_read_limit_tab[mem_config]; maincpu_resync_limits(); } -BYTE zero_read(WORD addr) +/* reads zeropage, 0/1 comes from RAM */ +uint8_t zero_read_dma(uint16_t addr) +{ + addr &= 0xff; + + if (c64_256k_enabled) { + return c64_256k_ram_segment0_read(addr); + } else { + if (plus256k_enabled) { + return plus256k_ram_low_read(addr); + } else { + return mem_ram[addr & 0xff]; + } + } +} + +/* reads zeropage, 0/1 comes from CPU port */ +uint8_t zero_read(uint16_t addr) { - BYTE retval; + uint8_t retval; addr &= 0xff; - switch ((BYTE)addr) { + switch ((uint8_t)addr) { case 0: /* printf("zero_read %02x %02x: ddr:%02x data:%02x (rd: ddr:%02x data:%02x)\n", addr, pport.dir_read, pport.dir, pport.data, pport.dir_read, pport.data_read); */ return pport.dir_read; @@ -254,6 +279,26 @@ BYTE zero_read(WORD addr) /* discharge the "capacitor" */ + /* FIXME: bits 3,4,5 are not connected on SX-64 boards - whether they + show similar behaviour needs to be tested */ + if (board_type == BOARD_SX64) { + /* set real value of read bit 3 */ + if (pport.data_falloff_bit3 && (pport.data_set_clk_bit3 < maincpu_clk)) { + pport.data_falloff_bit3 = 0; + pport.data_set_bit3 = 0; + } + /* set real value of read bit 4 */ + if (pport.data_falloff_bit4 && (pport.data_set_clk_bit4 < maincpu_clk)) { + pport.data_falloff_bit4 = 0; + pport.data_set_bit4 = 0; + } + /* set real value of read bit 5 */ + if (pport.data_falloff_bit5 && (pport.data_set_clk_bit5 < maincpu_clk)) { + pport.data_falloff_bit5 = 0; + pport.data_set_bit5 = 0; + } + } + /* set real value of read bit 6 */ if (pport.data_falloff_bit6 && (pport.data_set_clk_bit6 < maincpu_clk)) { pport.data_falloff_bit6 = 0; @@ -267,6 +312,23 @@ BYTE zero_read(WORD addr) } /* for unused bits in input mode, the value comes from the "capacitor" */ + if (board_type == BOARD_SX64) { + /* set real value of bit 3 */ + if (!(pport.dir_read & 0x08)) { + retval &= ~0x08; + retval |= pport.data_set_bit3; + } + /* set real value of bit 4 */ + if (!(pport.dir_read & 0x10)) { + retval &= ~0x10; + retval |= pport.data_set_bit4; + } + /* set real value of bit 5 */ + if (!(pport.dir_read & 0x20)) { + retval &= ~0x20; + retval |= pport.data_set_bit5; + } + } /* set real value of bit 6 */ if (!(pport.dir_read & 0x40)) { @@ -283,30 +345,46 @@ BYTE zero_read(WORD addr) return retval; } - if (c64_256k_enabled) { - return c64_256k_ram_segment0_read(addr); - } else { - if (plus256k_enabled) { - return plus256k_ram_low_read(addr); + return zero_read_dma(addr); +} + +/* store zeropage, 0/1 goes to RAM */ +void zero_store_dma(uint16_t addr, uint8_t value) +{ + addr &= 0xff; + + if (vbank == 0) { + if (c64_256k_enabled) { + c64_256k_ram_segment0_store(addr, value); } else { - return mem_ram[addr & 0xff]; + if (plus256k_enabled) { + plus256k_ram_low_store(addr, value); + } else { + mem_ram[addr] = value; + } } + } else { + mem_ram[addr] = value; } } -void zero_store(WORD addr, BYTE value) +#define FALLOFF_RANDOM (C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES / 5) +#define FALLOFF_RANDOM_SX (SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES / 5) + +/* store zeropage, 0/1 goes to CPU port */ +void zero_store(uint16_t addr, uint8_t value) { addr &= 0xff; - switch ((BYTE)addr) { + switch ((uint8_t)addr) { case 0: /* printf("zero_store %02x %02x: ddr:%02x data:%02x\n", addr, value, pport.dir, pport.data); */ if (vbank == 0) { if (c64_256k_enabled) { - c64_256k_ram_segment0_store((WORD)0, vicii_read_phi1()); + c64_256k_ram_segment0_store((uint16_t)0, vicii_read_phi1()); } else { if (plus256k_enabled) { - plus256k_ram_low_store((WORD)0, vicii_read_phi1()); + plus256k_ram_low_store((uint16_t)0, vicii_read_phi1()); } else { mem_ram[0] = vicii_read_phi1(); } @@ -319,10 +397,34 @@ void zero_store(WORD addr, BYTE value) stable value) to input mode (where the input is floating), some of the charge is transferred to the floating input */ + if (board_type == BOARD_SX64) { + if ((pport.dir & 0x08)) { + if ((pport.dir ^ value) & 0x08) { + pport.data_set_clk_bit3 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_set_bit3 = pport.data & 0x08; + pport.data_falloff_bit3 = 1; + } + } + if ((pport.dir & 0x10)) { + if ((pport.dir ^ value) & 0x10) { + pport.data_set_clk_bit4 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_set_bit4 = pport.data & 0x10; + pport.data_falloff_bit4 = 1; + } + } + if ((pport.dir & 0x20)) { + if ((pport.dir ^ value) & 0x20) { + pport.data_set_clk_bit5 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_set_bit5 = pport.data & 0x20; + pport.data_falloff_bit5 = 1; + } + } + } + /* check if bit 6 has flipped */ if ((pport.dir & 0x40)) { if ((pport.dir ^ value) & 0x40) { - pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES; + pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM); pport.data_set_bit6 = pport.data & 0x40; pport.data_falloff_bit6 = 1; } @@ -331,7 +433,7 @@ void zero_store(WORD addr, BYTE value) /* check if bit 7 has flipped */ if ((pport.dir & 0x80)) { if ((pport.dir ^ value) & 0x80) { - pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES; + pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM); pport.data_set_bit7 = pport.data & 0x80; pport.data_falloff_bit7 = 1; } @@ -346,10 +448,10 @@ void zero_store(WORD addr, BYTE value) /* printf("zero_store %02x %02x: ddr:%02x data:%02x\n", addr, value, pport.dir, pport.data); */ if (vbank == 0) { if (c64_256k_enabled) { - c64_256k_ram_segment0_store((WORD)1, vicii_read_phi1()); + c64_256k_ram_segment0_store((uint16_t)1, vicii_read_phi1()); } else { if (plus256k_enabled) { - plus256k_ram_low_store((WORD)1, vicii_read_phi1()); + plus256k_ram_low_store((uint16_t)1, vicii_read_phi1()); } else { mem_ram[1] = vicii_read_phi1(); } @@ -363,105 +465,133 @@ void zero_store(WORD addr, BYTE value) otherwise don't touch it */ if (pport.dir & 0x80) { pport.data_set_bit7 = value & 0x80; - pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES; + pport.data_set_clk_bit7 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM); pport.data_falloff_bit7 = 1; } if (pport.dir & 0x40) { pport.data_set_bit6 = value & 0x40; - pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES; + pport.data_set_clk_bit6 = maincpu_clk + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM); pport.data_falloff_bit6 = 1; } + if (board_type == BOARD_SX64) { + if (pport.dir & 0x20) { + pport.data_set_bit5 = value & 0x20; + pport.data_set_clk_bit5 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_falloff_bit5 = 1; + } + if (pport.dir & 0x10) { + pport.data_set_bit4 = value & 0x10; + pport.data_set_clk_bit4 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_falloff_bit4 = 1; + } + if (pport.dir & 0x08) { + pport.data_set_bit3 = value & 0x08; + pport.data_set_clk_bit3 = maincpu_clk + SX64_CPU6510_DATA_PORT_FALL_OFF_CYCLES + lib_unsigned_rand(0, FALLOFF_RANDOM_SX); + pport.data_falloff_bit3 = 1; + } + } + if (pport.data != value) { pport.data = value; mem_pla_config_changed(); } break; default: - if (vbank == 0) { - if (c64_256k_enabled) { - c64_256k_ram_segment0_store(addr, value); - } else { - if (plus256k_enabled) { - plus256k_ram_low_store(addr, value); - } else { - mem_ram[addr] = value; - } - } - } else { - mem_ram[addr] = value; - } + zero_store_dma(addr, value); + break; } } /* ------------------------------------------------------------------------- */ -BYTE chargen_read(WORD addr) +uint8_t chargen_read(uint16_t addr) { return mem_chargen_rom[addr & 0xfff]; } -void chargen_store(WORD addr, BYTE value) +void chargen_store(uint16_t addr, uint8_t value) { mem_chargen_rom[addr & 0xfff] = value; } -BYTE ram_read(WORD addr) +uint8_t ram_read(uint16_t addr) { return mem_ram[addr]; } -void ram_store(WORD addr, BYTE value) +void ram_store(uint16_t addr, uint8_t value) { mem_ram[addr] = value; } -void ram_hi_store(WORD addr, BYTE value) +void ram_hi_store(uint16_t addr, uint8_t value) { mem_ram[addr] = value; - - if (addr == 0xff00) { - reu_dma(-1); - } } /* unconnected memory space */ -static BYTE void_read(WORD addr) +static uint8_t void_read(uint16_t addr) { return vicii_read_phi1(); } -static void void_store(WORD addr, BYTE value) +static void void_store(uint16_t addr, uint8_t value) { return; } +/* ------------------------------------------------------------------------- */ + +/* DMA memory access, this is the same as generic memory access, but needs to + bypass the CPU port, so it accesses RAM at $00/$01 */ + +void mem_dma_store(uint16_t addr, uint8_t value) +{ + if ((addr & 0xff00) == 0) { + /* exception: 0/1 accesses RAM! */ + zero_store_dma(addr, value); + } else { + _mem_write_tab_ptr[addr >> 8](addr, value); + } +} + +uint8_t mem_dma_read(uint16_t addr) +{ + if ((addr & 0xff00) == 0) { + /* exception: 0/1 accesses RAM! */ + return zero_read_dma(addr); + } + return _mem_read_tab_ptr[addr >> 8](addr); +} + + /* ------------------------------------------------------------------------- */ /* Generic memory access. */ -void mem_store(WORD addr, BYTE value) +void mem_store(uint16_t addr, uint8_t value) { _mem_write_tab_ptr[addr >> 8](addr, value); } -BYTE mem_read(WORD addr) +uint8_t mem_read(uint16_t addr) { return _mem_read_tab_ptr[addr >> 8](addr); } -void mem_store_without_ultimax(WORD addr, BYTE value) +void mem_store_without_ultimax(uint16_t addr, uint8_t value) { mem_write_tab[mem_config & 7][addr >> 8](addr, value); } -BYTE mem_read_without_ultimax(WORD addr) +uint8_t mem_read_without_ultimax(uint16_t addr) { return mem_read_tab[mem_config & 7][addr >> 8](addr); } -void mem_store_without_romlh(WORD addr, BYTE value) +void mem_store_without_romlh(uint16_t addr, uint8_t value) { mem_write_tab[0][addr >> 8](addr, value); } @@ -469,12 +599,12 @@ void mem_store_without_romlh(WORD addr, BYTE value) /* ------------------------------------------------------------------------- */ -void colorram_store(WORD addr, BYTE value) +void colorram_store(uint16_t addr, uint8_t value) { mem_color_ram[addr & 0x3ff] = value & 0xf; } -BYTE colorram_read(WORD addr) +uint8_t colorram_read(uint16_t addr) { return mem_color_ram[addr & 0x3ff] | (vicii_read_phi1() & 0xf0); } @@ -490,19 +620,33 @@ BYTE c64d_colorram_peek(WORD addr) static int check_256k_ram_write(int i, int j) { - if (mem_write_tab[i][j] == ram_hi_store || mem_write_tab[i][j] == ram_store) { + if (mem_write_tab[i][j] == ram_hi_store) { + return 1; + } + if (mem_write_tab[i][j] == ram_store) { + return 1; + } + if (mem_write_tab[i][j] == raml_no_ultimax_store) { + return 1; + } + if (mem_write_tab[i][j] == romh_no_ultimax_store) { + return 1; + } + if (mem_write_tab[i][j] == ramh_no_ultimax_store) { + return 1; + } + if (mem_write_tab[i][j] == romh_store) { return 1; - } else { - return 0; } + return 0; } -void c64_256k_init_config(void) +static void c64_256k_init_config(void) { int i, j; if (c64_256k_enabled) { - mem_limit_256k_init(mem_read_limit_tab); + mem_limit_256k_init(); for (i = 0; i < NUM_CONFIGS; i++) { for (j = 1; j <= 0xff; j++) { if (check_256k_ram_write(i, j) == 1) { @@ -542,12 +686,12 @@ void c64_256k_init_config(void) /* init plus256k memory table changes */ -void plus256k_init_config(void) +static void plus256k_init_config(void) { int i, j; if (plus256k_enabled) { - mem_limit_256k_init(mem_read_limit_tab); + mem_limit_256k_init(); for (i = 0; i < NUM_CONFIGS; i++) { for (j = 1; j <= 0xff; j++) { if (check_256k_ram_write(i, j) == 1) { @@ -577,7 +721,7 @@ static void plus60k_init_config(void) int i, j; if (plus60k_enabled) { - mem_limit_plus60k_init(mem_read_limit_tab); + mem_limit_plus60k_init(); for (i = 0; i < NUM_CONFIGS; i++) { for (j = 0x10; j <= 0xff; j++) { if (mem_write_tab[i][j] == ram_hi_store) { @@ -586,6 +730,18 @@ static void plus60k_init_config(void) if (mem_write_tab[i][j] == ram_store) { mem_write_tab[i][j] = plus60k_ram_store; } + if (mem_write_tab[i][j] == raml_no_ultimax_store) { + mem_write_tab[i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */ + } + if (mem_write_tab[i][j] == romh_no_ultimax_store) { + mem_write_tab[i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */ + } + if (mem_write_tab[i][j] == ramh_no_ultimax_store) { + mem_write_tab[i][j] = plus60k_ram_store; /* possibly breaks mmc64 and expert */ + } + if (mem_write_tab[i][j] == romh_store) { + mem_write_tab[i][j] = plus60k_ram_store; + } if (mem_read_tab[i][j] == ram_read) { mem_read_tab[i][j] = plus60k_ram_read; @@ -607,7 +763,8 @@ void mem_read_tab_set(unsigned int base, unsigned int index, read_func_ptr_t rea mem_read_tab[base][index] = read_func; } -void mem_read_base_set(unsigned int base, unsigned int index, BYTE *mem_ptr) +/* set c64 base */ +void mem_read_base_set(unsigned int base, unsigned int index, uint8_t *mem_ptr) { mem_read_base_tab[base][index] = mem_ptr; } @@ -618,6 +775,18 @@ void c64d_init_memory(uint8 *c64memory) mem_ram = c64memory; } +/* add actual pointer */ +void mem_read_addr_set(unsigned int base, unsigned int index, uintptr_t addr) +{ + mem_read_base_tab[base][index] += addr; +} + + +void mem_read_limit_set(unsigned int base, unsigned int index, uint32_t limit) +{ + mem_read_limit_tab[base][index] = limit; +} + void mem_initialize_memory(void) { int i, j; @@ -627,7 +796,7 @@ void mem_initialize_memory(void) mem_color_ram_cpu = mem_color_ram; mem_color_ram_vicii = mem_color_ram; - mem_limit_init(mem_read_limit_tab); + mem_limit_init(); /* setup watchpoint tables */ mem_read_tab_watch[0] = zero_read_watch; @@ -639,26 +808,35 @@ void mem_initialize_memory(void) resources_get_int("BoardType", &board); + /* first init everything to "nothing" */ + for (i = 0; i < NUM_CONFIGS; i++) { + for (j = 0; j <= 0xff; j++) { + mem_read_tab[i][j] = void_read; + mem_read_base_tab[i][j] = NULL; + mem_set_write_hook(i, j, void_store); + } + } + /* Default is RAM. */ for (i = 0; i < NUM_CONFIGS; i++) { mem_set_write_hook(i, 0, zero_store); mem_read_tab[i][0] = zero_read; mem_read_base_tab[i][0] = mem_ram; for (j = 1; j <= 0xfe; j++) { - if (board == 1 && j >= 0x08) { - mem_read_tab[i][j] = void_read; + if (board == BOARD_MAX && j >= 0x08) { + /* mem_read_tab[i][j] = void_read; mem_read_base_tab[i][j] = NULL; - mem_set_write_hook(0, j, void_store); + mem_set_write_hook(0, j, void_store); */ continue; } mem_read_tab[i][j] = ram_read; mem_read_base_tab[i][j] = mem_ram; mem_write_tab[i][j] = ram_store; } - if (board == 1) { - mem_read_tab[i][0xff] = void_read; + if (board == BOARD_MAX) { + /* mem_read_tab[i][0xff] = void_read; mem_read_base_tab[i][0xff] = NULL; - mem_set_write_hook(0, 0xff, void_store); + mem_set_write_hook(0, 0xff, void_store); */ } else { mem_read_tab[i][0xff] = ram_read; mem_read_base_tab[i][0xff] = mem_ram; @@ -668,8 +846,11 @@ void mem_initialize_memory(void) } } + uintptr_t addr = 0 - 0xd000; + /* Setup character generator ROM at $D000-$DFFF (memory configs 1, 2, 3, 9, 10, 11, 26, 27). */ for (i = 0xd0; i <= 0xdf; i++) { +#if 0 mem_read_tab[1][i] = chargen_read; mem_read_tab[2][i] = chargen_read; mem_read_tab[3][i] = chargen_read; @@ -678,14 +859,60 @@ void mem_initialize_memory(void) mem_read_tab[11][i] = chargen_read; mem_read_tab[26][i] = chargen_read; mem_read_tab[27][i] = chargen_read; - mem_read_base_tab[1][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[2][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[3][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[9][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[10][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[11][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[26][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); - mem_read_base_tab[27][i] = (BYTE *)(mem_chargen_rom - (BYTE *)0xd000); + mem_read_base_tab[1][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[2][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[3][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[9][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[10][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[11][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[26][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); + mem_read_base_tab[27][i] = (uint8_t *)(mem_chargen_rom - (uint8_t *)0xd000); +#endif + mem_read_tab_set(1, i, chargen_read); + mem_read_tab_set(2, i, chargen_read); + mem_read_tab_set(3, i, chargen_read); + mem_read_tab_set(9, i, chargen_read); + mem_read_tab_set(10, i, chargen_read); + mem_read_tab_set(11, i, chargen_read); + mem_read_tab_set(26, i, chargen_read); + mem_read_tab_set(27, i, chargen_read); +#if 0 + mem_read_base_set(1, i, mem_chargen_rom); + mem_read_base_set(2, i, mem_chargen_rom); + mem_read_base_set(3, i, mem_chargen_rom); + mem_read_base_set(9, i, mem_chargen_rom); + mem_read_base_set(10, i, mem_chargen_rom); + mem_read_base_set(11, i, mem_chargen_rom); + mem_read_base_set(26, i, mem_chargen_rom); + mem_read_base_set(27, i, mem_chargen_rom); + + mem_read_addr_set(1, i, addr); + mem_read_addr_set(2, i, addr); + mem_read_addr_set(3, i, addr); + mem_read_addr_set(9, i, addr); + mem_read_addr_set(10, i, addr); + mem_read_addr_set(11, i, addr); + mem_read_addr_set(26, i, addr); + mem_read_addr_set(27, i, addr); +#else + mem_read_base_set(1, i, (uint8_t*)addr); + mem_read_base_set(2, i, (uint8_t*)addr); + mem_read_base_set(3, i, (uint8_t*)addr); + mem_read_base_set(9, i, (uint8_t*)addr); + mem_read_base_set(10, i, (uint8_t*)addr); + mem_read_base_set(11, i, (uint8_t*)addr); + mem_read_base_set(26, i, (uint8_t*)addr); + mem_read_base_set(27, i, (uint8_t*)addr); + + mem_read_addr_set(1, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(2, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(3, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(9, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(10, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(11, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(26, i, (uintptr_t)mem_chargen_rom); + mem_read_addr_set(27, i, (uintptr_t)mem_chargen_rom); +#endif } c64meminit(0); @@ -696,11 +923,6 @@ void mem_initialize_memory(void) mem_read_base_tab[i][0x100] = mem_read_base_tab[i][0]; } - _mem_read_tab_ptr = mem_read_tab[7]; - _mem_write_tab_ptr = mem_write_tab[7]; - _mem_read_base_tab_ptr = mem_read_base_tab[7]; - mem_read_limit_tab_ptr = mem_read_limit_tab[7]; - vicii_set_chargen_addr_options(0x7000, 0x1000); c64pla_pport_reset(); @@ -717,15 +939,15 @@ void mem_initialize_memory(void) plus256k_init_config(); c64_256k_init_config(); - if (board == 1) { - mem_limit_max_init(mem_read_limit_tab); + if (board == BOARD_MAX) { + mem_limit_max_init(); } } -void mem_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void mem_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { - BYTE *p = _mem_read_base_tab_ptr[addr >> 8]; - DWORD limits; + uint8_t *p = _mem_read_base_tab_ptr[addr >> 8]; + uint32_t limits; if (p != NULL && addr > 1) { *base = p; @@ -743,7 +965,7 @@ void mem_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) void mem_powerup(void) { ram_init(mem_ram, 0x10000); - cartridge_ram_init(); /* Clean cartridge ram too */ + vicii_init_colorram(mem_color_ram); } /* ------------------------------------------------------------------------- */ @@ -781,7 +1003,7 @@ void mem_set_tape_motor_in(int val) /* FIXME: this part needs to be checked. */ -void mem_get_basic_text(WORD *start, WORD *end) +void mem_get_basic_text(uint16_t *start, uint16_t *end) { if (start != NULL) { *start = mem_ram[0x2b] | (mem_ram[0x2c] << 8); @@ -791,7 +1013,7 @@ void mem_get_basic_text(WORD *start, WORD *end) } } -void mem_set_basic_text(WORD start, WORD end) +void mem_set_basic_text(uint16_t start, uint16_t end) { mem_ram[0x2b] = mem_ram[0xac] = start & 0xff; mem_ram[0x2c] = mem_ram[0xad] = start >> 8; @@ -799,15 +1021,38 @@ void mem_set_basic_text(WORD start, WORD end) mem_ram[0x2e] = mem_ram[0x30] = mem_ram[0x32] = mem_ram[0xaf] = end >> 8; } -void mem_inject(DWORD addr, BYTE value) +/* this function should always read from the screen currently used by the kernal + for output, normally this does just return system ram - except when the + videoram is not memory mapped. + used by autostart to "read" the kernal messages +*/ +uint8_t mem_read_screen(uint16_t addr) +{ + return ram_read(addr); +} + +void mem_inject(uint32_t addr, uint8_t value) +{ + /* printf("mem_inject addr: %04x value: %02x\n", addr, value); */ + if (!memory_hacks_ram_inject(addr, value)) { + mem_ram[addr & 0xffff] = value; + } +} + +/* In banked memory architectures this will always write to the bank that + contains the keyboard buffer and "number of keys in buffer", regardless of + what the CPU "sees" currently. + In all other cases this just writes to the first 64kb block, usually by + wrapping to mem_inject(). +*/ +void mem_inject_key(uint16_t addr, uint8_t value) { - /* could be made to handle various internal expansions in some sane way */ - mem_ram[addr & 0xffff] = value; + mem_inject(addr, value); } /* ------------------------------------------------------------------------- */ -int mem_rom_trap_allowed(WORD addr) +int mem_rom_trap_allowed(uint16_t addr) { if (addr >= 0xe000) { switch (mem_config) { @@ -836,7 +1081,7 @@ int mem_rom_trap_allowed(WORD addr) /* Banked memory access functions for the monitor. */ -void store_bank_io(WORD addr, BYTE byte) +void store_bank_io(uint16_t addr, uint8_t byte) { switch (addr & 0xff00) { case 0xd000: @@ -873,7 +1118,7 @@ void store_bank_io(WORD addr, BYTE byte) cia1_store(addr, byte); break; case 0xdd00: - cia2_store(addr, byte); + c64io_dd00_store(addr, byte); break; case 0xde00: c64io_de00_store(addr, byte); @@ -885,7 +1130,32 @@ void store_bank_io(WORD addr, BYTE byte) return; } -BYTE read_bank_io(WORD addr) +static void poke_bank_io(uint16_t addr, uint8_t byte) +{ + /* FIXME: open ends */ + switch (addr & 0xff00) { + case 0xd000: + /* c64io_d000_poke(addr, byte); */ + vicii_poke(addr & 0x3f, byte); + break; + case 0xd100: + /* c64io_d100_poke(addr, byte); */ + vicii_poke(addr & 0x3f, byte); + break; + case 0xd200: + /* c64io_d200_poke(addr, byte); */ + vicii_poke(addr & 0x3f, byte); + break; + case 0xd300: + /* c64io_d300_poke(addr, byte); */ + vicii_poke(addr & 0x3f, byte); + break; + } + store_bank_io(addr, byte); + return; +} + +uint8_t read_bank_io(uint16_t addr) { switch (addr & 0xff00) { case 0xd000: @@ -912,7 +1182,7 @@ BYTE read_bank_io(WORD addr) case 0xdc00: return cia1_read(addr); case 0xdd00: - return cia2_read(addr); + return c64io_dd00_read(addr); case 0xde00: return c64io_de00_read(addr); case 0xdf00: @@ -921,7 +1191,7 @@ BYTE read_bank_io(WORD addr) return 0xff; } -static BYTE peek_bank_io(WORD addr) +static uint8_t peek_bank_io(uint16_t addr) { switch (addr & 0xff00) { case 0xd000: @@ -948,7 +1218,7 @@ static BYTE peek_bank_io(WORD addr) case 0xdc00: return cia1_peek(addr); case 0xdd00: - return cia2_peek(addr); + return c64io_dd00_peek(addr); case 0xde00: return c64io_de00_peek(addr); case 0xdf00: @@ -963,21 +1233,29 @@ static BYTE peek_bank_io(WORD addr) static const char *banknames[] = { "default", - "cpu", - "ram", - "rom", - "io", - "cart", + "cpu", /* #0 */ + "ram", /* #1 */ + "rom", /* #2 */ + "io", /* #3 */ + "cart", /* #4 */ + /* by convention, a "bank array" has a 2-hex-digit bank index appended */ NULL }; -static const int banknums[] = { 1, 0, 1, 2, 3, 4 }; +static const int banknums[] = { 0, 0, 1, 2, 3, 4, -1 }; +static const int bankindex[] = { -1, -1, -1, -1, -1, -1, -1 }; +static const int bankflags[] = { 0, 0, 0, 0, 0, 0, -1 }; const char **mem_bank_list(void) { return banknames; } +const int *mem_bank_list_nos(void) { + return banknums; +} + +/* return bank number for a given literal bank name */ int mem_bank_from_name(const char *name) { int i = 0; @@ -991,7 +1269,34 @@ int mem_bank_from_name(const char *name) return -1; } -BYTE mem_bank_read(int bank, WORD addr, void *context) +/* return current index for a given bank */ +int mem_bank_index_from_bank(int bank) +{ + int i = 0; + + while (banknums[i] > -1) { + if (banknums[i] == bank) { + return bankindex[i]; + } + i++; + } + return -1; +} + +int mem_bank_flags_from_bank(int bank) +{ + int i = 0; + + while (banknums[i] > -1) { + if (banknums[i] == bank) { + return bankflags[i]; + } + i++; + } + return -1; +} + +uint8_t mem_bank_read(int bank, uint16_t addr, void *context) { switch (bank) { case 0: /* current */ @@ -1001,6 +1306,7 @@ BYTE mem_bank_read(int bank, WORD addr, void *context) if (addr >= 0xd000 && addr < 0xe000) { return read_bank_io(addr); } + /* FALL THROUGH */ case 4: /* cart */ return cartridge_peek_mem(addr); case 2: /* rom */ @@ -1013,6 +1319,7 @@ BYTE mem_bank_read(int bank, WORD addr, void *context) if (addr >= 0xe000) { return c64memrom_kernal64_rom[addr & 0x1fff]; } + /* FALL THROUGH */ case 1: /* ram */ break; } @@ -1212,9 +1519,18 @@ BYTE c64d_peek_c64(WORD addr) } case 0x0d: { - if (mem_cartridge_type != CARTRIDGE_NONE) + /* I/O 1 ($DE00) and I/O 2 ($DF00) are dispatched via io_source_register. + The 3.1 path here guarded the dispatch on mem_cartridge_type != NONE, + but several devices -- REU notably -- register an io_source without + touching mem_cartridge_type. That meant `c64/cpu/memory/readBlock` + read REU registers via the c64d_peek_c64 path and saw $FF or RAM + instead of the rec.status values the CPU (via the normal mem_read + table) gets correctly. Always go through c64io_de00_peek / + c64io_df00_peek when io_in is on -- if no io_source is registered + for the given address they return the floating-bus value just like + reading through the CPU's load path. */ + if (io_in) { - // TODO: check if peek does not create triggers/alarms... uint8 addrHi2 = (addr >> 8); if (addrHi2 == 0xDE) { @@ -1224,10 +1540,6 @@ BYTE c64d_peek_c64(WORD addr) { return c64io_df00_peek(addr); } - } - - if (io_in) - { return c64d_peek_io(addr); } else if (char_in) @@ -1799,31 +2111,92 @@ void c64d_un_patch_kernal_fast_boot() -// Slaj: unfortunately mem_bank_peek DOES affect I/O state :( :( -BYTE mem_bank_peek(int bank, WORD addr, void *context) +/* VICE 3.10: side-effect-free peek honoring a given mem config (used by mem_bank_peek). */ +uint8_t mem_peek_with_config(int config, uint16_t addr, void *context) { + /* special case to read the CPU port of the 6510 */ + if (addr < 2) { + return mem_read(addr); + } + /* we must check for which bank is currently active */ + /* don't include ultimax here, check later */ + if (c64meminit_io_config[config] == 1) { + if ((addr >= 0xd000) && (addr < 0xe000)) { + return peek_bank_io(addr); + } + } + if (c64meminit_roml_config[config]) { + if (addr >= 0x8000 && addr <= 0x9fff) { + return cartridge_peek_mem(addr); + } + } + if (c64meminit_romh_config[config]) { + unsigned int romhloc = c64meminit_romh_mapping[config] << 8; + if (addr >= romhloc && addr <= (romhloc + 0x1fff)) { + return cartridge_peek_mem(addr); + } + } + if (c64meminit_io_config[config] == 2) { + /* ultimax mode */ + if (/*addr >= 0x0000 &&*/ addr <= 0x0fff) { + return mem_ram[addr]; + } + return cartridge_peek_mem(addr); + } + if((config == 3) || (config == 7) || + (config == 11) || (config == 15)) { + if (addr >= 0xa000 && addr <= 0xbfff) { + return c64memrom_basic64_rom[addr & 0x1fff]; + } + } + if((config & 3) > 1) { + if (addr >= 0xe000) { + return c64memrom_kernal64_rom[addr & 0x1fff]; + } + } + if((config & 3) && (config != 0x19)) { + if ((addr >= 0xd000) && (addr < 0xdfff)) { + return mem_chargen_rom[addr & 0x0fff]; + } + } + + return mem_ram[addr]; +} + + +/* used by monitor if sfx off, and when disassembling/tracing. this function + * can NOT use the generic mem_read stuff, because that DOES have side effects, + * such as (re)triggering checkpoints in the monitor! + */ +uint8_t mem_bank_peek(int bank, uint16_t addr, void *context) { switch (bank) { - case 0: /* current */ - /* we must check for which bank is currently active, and only use peek_bank_io - when needed to avoid side effects */ - if (c64meminit_io_config[mem_config]) { - if ((addr >= 0xd000) && (addr < 0xe000)) { - return peek_bank_io(addr); - } - } - return mem_read(addr); - break; - case 3: /* io */ + case 0: /* CPU */ + return mem_peek_with_config(mem_config, addr, context); + case 3: /* io */ if (addr >= 0xd000 && addr < 0xe000) { return peek_bank_io(addr); } - case 4: /* cart */ + /* FALL THROUGH */ + case 4: /* cart */ return cartridge_peek_mem(addr); + case 2: /* rom */ + if (addr >= 0xa000 && addr <= 0xbfff) { + return c64memrom_basic64_rom[addr & 0x1fff]; + } + if (addr >= 0xd000 && addr <= 0xdfff) { + return mem_chargen_rom[addr & 0x0fff]; + } + if (addr >= 0xe000) { + return c64memrom_kernal64_rom[addr & 0x1fff]; + } + /* FALL THROUGH */ + case 1: /* ram */ + break; } - return mem_bank_read(bank, addr, context); + return mem_ram[addr]; } -void mem_bank_write(int bank, WORD addr, BYTE byte, void *context) +void mem_bank_write(int bank, uint16_t addr, uint8_t byte, void *context) { switch (bank) { case 0: /* current */ @@ -1834,6 +2207,7 @@ void mem_bank_write(int bank, WORD addr, BYTE byte, void *context) store_bank_io(addr, byte); return; } + /* FALL THROUGH */ case 2: /* rom */ if (addr >= 0xa000 && addr <= 0xbfff) { return; @@ -1844,18 +2218,43 @@ void mem_bank_write(int bank, WORD addr, BYTE byte, void *context) if (addr >= 0xe000) { return; } + /* FALL THROUGH */ case 1: /* ram */ break; } mem_ram[addr] = byte; } -static int mem_dump_io(void *context, WORD addr) +/* used by monitor if sfx off */ +void mem_bank_poke(int bank, uint16_t addr, uint8_t byte, void *context) +{ + switch (bank) { + case 0: /* current */ + /* we must check for which bank is currently active, and only use peek_bank_io + when needed to avoid side effects */ + if (c64meminit_io_config[mem_config]) { + /* is i/o */ + if ((addr >= 0xd000) && (addr < 0xe000)) { + poke_bank_io(addr, byte); + return; + } + } + break; + case 3: /* io */ + if (addr >= 0xd000 && addr < 0xe000) { + poke_bank_io(addr, byte); + return; + } + break; + } + + mem_bank_write(bank, addr, byte, context); +} + +static int mem_dump_io(void *context, uint16_t addr) { if ((addr >= 0xdc00) && (addr <= 0xdc3f)) { return ciacore_dump(machine_context.cia1); - } else if ((addr >= 0xdd00) && (addr <= 0xdd3f)) { - return ciacore_dump(machine_context.cia2); } return -1; } @@ -1864,15 +2263,14 @@ mem_ioreg_list_t *mem_ioreg_list_get(void *context) { mem_ioreg_list_t *mem_ioreg_list = NULL; - mon_ioreg_add_list(&mem_ioreg_list, "CIA1", 0xdc00, 0xdc0f, mem_dump_io, NULL); - mon_ioreg_add_list(&mem_ioreg_list, "CIA2", 0xdd00, 0xdd0f, mem_dump_io, NULL); + io_source_ioreg_add_list(&mem_ioreg_list); /* VIC-II, SID first so it's in address order */ - io_source_ioreg_add_list(&mem_ioreg_list); + mon_ioreg_add_list(&mem_ioreg_list, "CIA1", 0xdc00, 0xdc0f, mem_dump_io, NULL, IO_MIRROR_NONE); return mem_ioreg_list; } -void mem_get_screen_parameter(WORD *base, BYTE *rows, BYTE *columns, int *bank) +void mem_get_screen_parameter(uint16_t *base, uint8_t *rows, uint8_t *columns, int *bank) { *base = ((vicii_peek(0xd018) & 0xf0) << 6) | ((~cia2_peek(0xdd00) & 0x03) << 14); *rows = 25; @@ -1880,14 +2278,41 @@ void mem_get_screen_parameter(WORD *base, BYTE *rows, BYTE *columns, int *bank) *bank = 0; } +/* used by autostart to locate and "read" kernal output on the current screen + * this function should return whatever the kernal currently uses, regardless + * what is currently visible/active in the UI + */ +void mem_get_cursor_parameter(uint16_t *screen_addr, uint8_t *cursor_column, uint8_t *line_length, int *blinking) +{ + /* CAUTION: this function can be called at any time when the emulation (KERNAL) + is in the middle of a screen update. we must make sure that all + values are being looked up in an "atomic" way so we dont use a low- + and high- byte from before and after an update, leading to invalid + values */ + int screen_base = (mem_ram[0xd1] + (mem_ram[0xd2] * 256)) & ~0x3ff; /* the upper bits will not change */ + + /* Cursor Blink enable: 1 = Cursor in Blink Phase (visible), 0 = Cursor disabled, -1 = n/a */ + *blinking = mem_ram[0xcc] ? 0 : 1; + /* Current Screen Line Address */ + *screen_addr = screen_base + (mem_ram[0xd6] * 40); + /* Cursor Column on Current Line */ + *cursor_column = mem_ram[0xd3]; + while (*cursor_column >= 40) { + *cursor_column -= 40; + *screen_addr += 40; + } + /* Physical Screen Line Length */ + *line_length = 40; +} + /* ------------------------------------------------------------------------- */ -void mem_color_ram_to_snapshot(BYTE *color_ram) +void mem_color_ram_to_snapshot(uint8_t *color_ram) { memcpy(color_ram, mem_color_ram, 0x400); } -void mem_color_ram_from_snapshot(BYTE *color_ram) +void mem_color_ram_from_snapshot(uint8_t *color_ram) { memcpy(mem_color_ram, color_ram, 0x400); } @@ -1895,12 +2320,10 @@ void mem_color_ram_from_snapshot(BYTE *color_ram) /* ------------------------------------------------------------------------- */ /* UI functions (used to distinguish between x64 and x64sc) */ -#ifdef USE_BEOS_UI int c64_mem_ui_init_early(void) { return c64scui_init_early(); } -#endif int c64_mem_ui_init(void) { diff --git a/src/Emulators/vice/c64/c64memsnapshot.c b/src/Emulators/vice/c64/c64memsnapshot.c index 1bcd186f..4a2383f7 100644 --- a/src/Emulators/vice/c64/c64memsnapshot.c +++ b/src/Emulators/vice/c64/c64memsnapshot.c @@ -67,7 +67,7 @@ static const char snap_rom_module_name[] = "C64ROM"; #define SNAP_ROM_MAJOR 0 #define SNAP_ROM_MINOR 0 -/* static log_t c64_snapshot_log = LOG_ERR; */ +/* static log_t c64_snapshot_log = LOG_DEFAULT; */ static int c64_snapshot_write_rom_module(snapshot_t *s) { @@ -89,16 +89,41 @@ static int c64_snapshot_write_rom_module(snapshot_t *s) return -1; } - ui_update_menus(); - return snapshot_module_close(m); } +#define NUM_TRAP_DEVICES 9 /* FIXME: is there a better constant ? */ +static int trapfl[NUM_TRAP_DEVICES]; +static int trapdevices[NUM_TRAP_DEVICES + 1] = { 1, 4, 5, 6, 7, 8, 9, 10, 11, -1 }; + +static void get_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_get_int_sprintf("TrapDevice%d", &trapfl[i], trapdevices[i]); + } +} + +static void clear_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_set_int_sprintf("TrapDevice%d", 0, trapdevices[i]); + } +} + +static void restore_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_set_int_sprintf("TrapDevice%d", trapfl[i], trapdevices[i]); + } +} + static int c64_snapshot_read_rom_module(snapshot_t *s) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; - int trapfl; /* Main memory module. */ @@ -111,16 +136,16 @@ static int c64_snapshot_read_rom_module(snapshot_t *s) } /* get old value */ - resources_get_int("VirtualDevices", &trapfl); + get_trapflags(); /* Do not accept versions higher than current */ - if (major_version > SNAP_ROM_MAJOR || minor_version > SNAP_ROM_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, SNAP_ROM_MAJOR, SNAP_ROM_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* disable traps before loading the ROM */ - resources_set_int("VirtualDevices", 0); + clear_trapflags(); if (0 || SMR_BA(m, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE) < 0 @@ -130,23 +155,23 @@ static int c64_snapshot_read_rom_module(snapshot_t *s) } if (snapshot_module_close(m) < 0) { - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(); return -1; } memcpy(c64memrom_kernal64_trap_rom, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE); - c64rom_get_kernal_checksum(); - c64rom_get_basic_checksum(); + c64rom_print_kernal_info(); + c64rom_print_basic_info(); /* enable traps again when necessary */ - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(); return 0; fail: snapshot_module_close(m); /* restore old value */ - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(); return -1; } @@ -197,8 +222,8 @@ int c64_snapshot_write_module(snapshot_t *s, int save_roms, int save_reu_data, i || SMW_B(m, pport.data_out) < 0 || SMW_B(m, pport.data_read) < 0 || SMW_B(m, pport.dir_read) < 0 - || SMW_DW(m, (DWORD)pport.data_set_clk_bit6) < 0 - || SMW_DW(m, (DWORD)pport.data_set_clk_bit7) < 0 + || SMW_DW(m, (uint32_t)pport.data_set_clk_bit6) < 0 + || SMW_DW(m, (uint32_t)pport.data_set_clk_bit7) < 0 || SMW_B(m, pport.data_set_bit6) < 0 || SMW_B(m, pport.data_set_bit7) < 0 || SMW_B(m, pport.data_falloff_bit6) < 0 @@ -220,7 +245,7 @@ int c64_snapshot_write_module(snapshot_t *s, int save_roms, int save_reu_data, i int c64_snapshot_read_module(snapshot_t *s, int read_reu_data, int read_cart_roms) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; int tmp_bit6, tmp_bit7; @@ -233,7 +258,7 @@ int c64_snapshot_read_module(snapshot_t *s, int read_reu_data, int read_cart_rom } /* Do not accept versions higher than current */ - if (major_version > SNAP_MAJOR || minor_version > SNAP_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -251,7 +276,7 @@ int c64_snapshot_read_module(snapshot_t *s, int read_reu_data, int read_cart_rom } /* new since 0.1 */ - if (SNAPVAL(major_version, minor_version, 0, 1)) { + if (!snapshot_version_is_smaller(major_version, minor_version, 0, 1)) { if (0 || SMR_DW_INT(m, &tmp_bit6) < 0 || SMR_DW_INT(m, &tmp_bit7) < 0 @@ -286,8 +311,6 @@ int c64_snapshot_read_module(snapshot_t *s, int read_reu_data, int read_cart_rom return -1; } - ui_update_menus(); - return 0; fail: diff --git a/src/Emulators/vice/c64/c64memsnapshot.h b/src/Emulators/vice/c64/c64memsnapshot.h index 4ed7a6d1..48eb2beb 100644 --- a/src/Emulators/vice/c64/c64memsnapshot.h +++ b/src/Emulators/vice/c64/c64memsnapshot.h @@ -29,6 +29,7 @@ struct snapshot_s; -extern int c64_snapshot_write_module(struct snapshot_s *s, int save_roms, int save_reu_data, int save_cart_roms); -extern int c64_snapshot_read_module(struct snapshot_s *s, int read_reu_data, int read_cart_roms); +int c64_snapshot_write_module(struct snapshot_s *s, int save_roms, int save_reu_data, int save_cart_roms); +int c64_snapshot_read_module(struct snapshot_s *s, int read_reu_data, int read_cart_roms); + #endif diff --git a/src/Emulators/vice/c64/c64model.h b/src/Emulators/vice/c64/c64model.h index c8a80035..572149a4 100644 --- a/src/Emulators/vice/c64/c64model.h +++ b/src/Emulators/vice/c64/c64model.h @@ -30,30 +30,34 @@ #include "vicetypes.h" -#define C64MODEL_C64_PAL 0 -#define C64MODEL_C64C_PAL 1 -#define C64MODEL_C64_OLD_PAL 2 +enum { + C64MODEL_C64_PAL = 0, + C64MODEL_C64C_PAL, + C64MODEL_C64_OLD_PAL, -#define C64MODEL_C64_NTSC 3 -#define C64MODEL_C64C_NTSC 4 -#define C64MODEL_C64_OLD_NTSC 5 + C64MODEL_C64_NTSC, + C64MODEL_C64C_NTSC, + C64MODEL_C64_OLD_NTSC, -#define C64MODEL_C64_PAL_N 6 + C64MODEL_C64_PAL_N, /* SX-64 */ -#define C64MODEL_C64SX_PAL 7 -#define C64MODEL_C64SX_NTSC 8 + C64MODEL_C64SX_PAL, + C64MODEL_C64SX_NTSC, -#define C64MODEL_C64_JAP 9 -#define C64MODEL_C64_GS 10 + C64MODEL_C64_JAP, + C64MODEL_C64_GS, /* 4064, PET64, EDUCATOR64 */ -#define C64MODEL_PET64_PAL 11 -#define C64MODEL_PET64_NTSC 12 + C64MODEL_PET64_PAL, + C64MODEL_PET64_NTSC, + /* max machine */ -#define C64MODEL_ULTIMAX 13 + C64MODEL_ULTIMAX, -#define C64MODEL_NUM 14 +/* This entry needs to always be at the end */ + C64MODEL_NUM +}; #define C64MODEL_UNKNOWN 99 @@ -66,8 +70,15 @@ #define GLUE_DISCRETE 0 #define GLUE_CUSTOM_IC 1 -#define BOARD_C64 0 -#define BOARD_MAX 1 +/* CAUTION: these are shared with x128 */ +#define BOARD_C64 0 +#define BOARD_MAX 1 +#define BOARD_SX64 2 +#define BOARD_LAST_C64 2 +/* put all C128 boards last */ +#define BOARD_C128 3 +#define BOARD_C128D 4 +#define BOARD_LAST 4 #define IEC_HARD_RESET 0 #define IEC_SOFT_RESET 1 @@ -84,24 +95,31 @@ #define NO_KEYBOARD 0 #define HAS_KEYBOARD 1 +#define NO_CIA2 0 +#define HAS_CIA2 1 + +#define CIATICK_NET 0 +#define CIATICK_60HZ 1 + typedef struct { int vicii_model; int sid_model; int glue_logic; /* x64sc only */ int cia1_model; int cia2_model; - int board; /* 0: normal, 1: ultimax */ + int cia_tick; + int board; /* 0: normal, 1: ultimax, 2: sx64, 3: C128 */ int iecreset; /* 1: reset goes to IEC bus (old) 0: only reset IEC on hard reset (new) */ const char *kernal; const char *chargen; int kernalrev; } c64model_details_t; -extern int c64model_get(void); -extern void c64model_set(int model); +int c64model_get(void); +void c64model_set(int model); /* get details for model */ -extern void c64model_set_details(c64model_details_t *details, int model); +void c64model_set_details(c64model_details_t *details, int model); /* get model from details */ -extern int c64model_get_model(c64model_details_t *details); +int c64model_get_model(c64model_details_t *details); #endif diff --git a/src/Emulators/vice/c64/c64parallel.c b/src/Emulators/vice/c64/c64parallel.c index 4b84920c..a55c47e9 100644 --- a/src/Emulators/vice/c64/c64parallel.c +++ b/src/Emulators/vice/c64/c64parallel.c @@ -37,43 +37,99 @@ #include "drive.h" #include "drivetypes.h" #include "iecdrive.h" +#include "joyport.h" #include "log.h" #include "maincpu.h" #include "vicetypes.h" +#include "userport.h" #include "via.h" #ifdef C64PAR_DEBUG -#define DBG(x) log_debug x +#define DBG(x) log_printf x #else #define DBG(x) #endif +/* +"standard" (SpeedDOS) cable + +VIA#1 User port plug + 2, PA0 C, PB0 + 3, PA1 D, PB1 + 4, PA2 E, PB2 + 5, PA3 F, PB3 + 6, PA4 H, PB4 + 7, PA5 J, PB5 + 8, PA6 K, PB6 + 9, PA7 L, PB7 + +18, CB1 8, PC2 <- this one is NOT connected on the "21sec Backup" cable! +39, CA2 B, FLAG2 + + +"Data Becker Floppy Express" cable + +VIA#1 User port plug + 2, PA0 C, PB0 + 3, PA1 D, PB1 + 4, PA2 E, PB2 + 5, PA3 F, PB3 + 6, PA4 H, PB4 + 7, PA5 J, PB5 + 8, PA6 K, PB6 + 9, PA7 L, PB7 + +39, CA2 B, FLAG2 +??? M, PA2 <- connects to extra logic on the floppy board + + + +Professional DOS 1571 cable + +CIA#1 User port plug +10, PB0 C, PB0 +11, PB1 D, PB1 +12, PB2 E, PB2 +13, PB3 F, PB3 +14, PB4 H, PB4 +15, PB5 J, PB5 +16, PB6 K, PB6 +17, PB7 L, PB7 + +18, /PC B, FLAG2 + + 8, /PC2 - pulled up via 2k7 to VCC (2) +*/ + #define PC_PORT_STANDARD 0 #define PC_PORT_FORMEL64 1 #define PC_PORT_NUM 2 -static BYTE parallel_cable_drive_value[DRIVE_NUM] = { 0xff, 0xff, 0xff, 0xff }; -static BYTE parallel_cable_cpu_value[PC_PORT_NUM] = { 0xff, 0xff }; +static uint8_t parallel_cable_drive_value[NUM_DISK_UNITS] = { 0xff, 0xff, 0xff, 0xff }; +static uint8_t parallel_cable_cpu_value[PC_PORT_NUM] = { 0xff, 0xff }; -static int portmap[DRIVE_PC_NUM] = { +static int parallel_cable_enabled = 0; + +static const int portmap[DRIVE_PC_NUM] = { PC_PORT_STANDARD, /* DRIVE_PC_NONE */ PC_PORT_STANDARD, /* DRIVE_PC_STANDARD */ PC_PORT_STANDARD, /* DRIVE_PC_DD3 */ PC_PORT_FORMEL64, /* DRIVE_PC_FORMEL64 */ + PC_PORT_STANDARD, /* DRIVE_PC_21SEC_BACKUP */ }; -static BYTE parallel_cable_value(int type) +static uint8_t parallel_cable_value(int type) { unsigned int dnr, port; - BYTE val; + uint8_t val; port = portmap[type]; val = parallel_cable_cpu_value[port]; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - if (drive_context[dnr]->drive->enable && drive_context[dnr]->drive->parallel_cable) { - if (portmap[drive_context[dnr]->drive->parallel_cable] == (int)port) { + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + if (diskunit_context[dnr]->enable && diskunit_context[dnr]->parallel_cable) { + if (portmap[diskunit_context[dnr]->parallel_cable] == (int)port) { val &= parallel_cable_drive_value[dnr]; } } @@ -83,10 +139,69 @@ static BYTE parallel_cable_value(int type) return val; } +/* ------------------------------------------------------------------------- */ + +/* Some prototypes are needed */ +static void userport_par_cable_store_pbx(uint8_t data, int pulse); +static uint8_t userport_par_cable_read_pbx(uint8_t orig); +static int userport_par_cable_enable(int value); + +static userport_device_t par_cable_device = { + "Userport parallel drive cable", /* device name */ + JOYSTICK_ADAPTER_ID_NONE, /* NOT a joystick adapter */ + USERPORT_DEVICE_TYPE_DRIVE_PAR_CABLE, /* device is a parallel drive cable */ + userport_par_cable_enable, /* enable function */ + userport_par_cable_read_pbx, /* read pb0-pb7 function */ + userport_par_cable_store_pbx, /* NO store pb0-pb7 function */ + NULL, /* NO read pa2 pin function */ + NULL, /* NO store pa2 pin function */ + NULL, /* NO read pa3 pin function */ + NULL, /* NO store pa3 pin function */ + 0, /* pc pin is NOT needed */ + NULL, /* NO store sp1 pin function */ + NULL, /* NO read sp1 pin function */ + NULL, /* NO store sp2 pin function */ + NULL, /* NO read sp2 pin function */ + NULL, /* NO reset pin function */ + NULL, /* NO power toggle function */ + NULL, /* NO snapshot write function */ + NULL /* NO snapshot read function */ +}; + +static int userport_par_cable_enable(int value) +{ + int val = value ? 1 : 0; + + parallel_cable_enabled = val; + + return 0; +} + +static void userport_par_cable_store_pbx(uint8_t data, int pulse) +{ + if (pulse) { + parallel_cable_cpu_pulse(DRIVE_PC_STANDARD); + } else { + parallel_cable_cpu_write(DRIVE_PC_STANDARD, data); + } +} + +static uint8_t userport_par_cable_read_pbx(uint8_t orig) +{ + return parallel_cable_cpu_read(DRIVE_PC_STANDARD, orig); +} + +int parallel_cable_cpu_resources_init(void) +{ + return userport_device_register(USERPORT_DEVICE_DRIVE_PAR_CABLE, &par_cable_device); +} + +/* ------------------------------------------------------------------------- */ + /* interface for the drive (read/write) */ -void parallel_cable_drive_write(int type, BYTE data, int handshake, unsigned int dnr) +void parallel_cable_drive_write(int type, uint8_t data, int handshake, unsigned int dnr) { int port; @@ -105,10 +220,10 @@ void parallel_cable_drive_write(int type, BYTE data, int handshake, unsigned int } } -BYTE parallel_cable_drive_read(int type, int handshake) +uint8_t parallel_cable_drive_read(int type, int handshake) { int port; - BYTE rc; + uint8_t rc; port = portmap[type]; @@ -132,21 +247,21 @@ void parallel_cable_cpu_execute(int type) { unsigned int dnr; int port; - drive_t *drive; port = portmap[type]; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - if (drive->enable && drive->parallel_cable) { - if (portmap[drive->parallel_cable] == port) { - drive_cpu_execute_one(drive_context[dnr], maincpu_clk); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + + if (unit->enable && unit->parallel_cable) { + if (portmap[unit->parallel_cable] == port) { + drive_cpu_execute_one(unit, maincpu_clk); } } } } -void parallel_cable_cpu_write(int type, BYTE data) +void parallel_cable_cpu_write(int type, uint8_t data) { int port; @@ -158,9 +273,9 @@ void parallel_cable_cpu_write(int type, BYTE data) DBG(("PARCABLE (%d:%d) CPU W DATA %02x", type, port, data)); } -BYTE parallel_cable_cpu_read(int type, BYTE data) +uint8_t parallel_cable_cpu_read(int type, uint8_t data) { - BYTE rc; + uint8_t rc; parallel_cable_cpu_execute(type); @@ -179,26 +294,27 @@ void parallel_cable_cpu_pulse(int type) DBG(("PARCABLE (%d:%d) CPU Pulse", type, portmap[type])); - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive_t *drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; - drive = drive_context[dnr]->drive; - - if (drive->enable && drive->parallel_cable) { - switch (drive->parallel_cable) { + if (unit->enable && unit->parallel_cable) { + switch (unit->parallel_cable) { case DRIVE_PC_DD3: - dd3_set_signal(drive_context[dnr]); + dd3_set_signal(unit); break; case DRIVE_PC_FORMEL64: - viacore_signal(drive_context[dnr]->via1d1541, VIA_SIG_CB1, VIA_SIG_FALL); + viacore_signal(unit->via1d1541, VIA_SIG_CB1, VIA_SIG_FALL); + break; + case DRIVE_PC_21SEC_BACKUP: + /* do nothing */ break; default: - if (drive->type == DRIVE_TYPE_1570 || - drive->type == DRIVE_TYPE_1571 || - drive->type == DRIVE_TYPE_1571CR) { - ciacore_set_flag(drive_context[dnr]->cia1571); + if (unit->type == DRIVE_TYPE_1570 || + unit->type == DRIVE_TYPE_1571 || + unit->type == DRIVE_TYPE_1571CR) { + ciacore_set_flag(unit->cia1571); } else { - viacore_signal(drive_context[dnr]->via1d1541, VIA_SIG_CB1, VIA_SIG_FALL); + viacore_signal(unit->via1d1541, VIA_SIG_CB1, VIA_SIG_FALL); } break; } @@ -206,7 +322,7 @@ void parallel_cable_cpu_pulse(int type) } } -void parallel_cable_cpu_undump(int type, BYTE data) +void parallel_cable_cpu_undump(int type, uint8_t data) { parallel_cable_cpu_value[portmap[type]] = data; } diff --git a/src/Emulators/vice/c64/c64parallel.h b/src/Emulators/vice/c64/c64parallel.h index c669b40f..7e210577 100644 --- a/src/Emulators/vice/c64/c64parallel.h +++ b/src/Emulators/vice/c64/c64parallel.h @@ -29,10 +29,12 @@ #include "vicetypes.h" -extern void parallel_cable_cpu_execute(int type); -extern void parallel_cable_cpu_write(int type, BYTE data); -extern void parallel_cable_cpu_pulse(int type); -extern BYTE parallel_cable_cpu_read(int type, BYTE data); -extern void parallel_cable_cpu_undump(int type, BYTE data); +void parallel_cable_cpu_execute(int type); +void parallel_cable_cpu_write(int type, uint8_t data); +void parallel_cable_cpu_pulse(int type); +uint8_t parallel_cable_cpu_read(int type, uint8_t data); +void parallel_cable_cpu_undump(int type, uint8_t data); + +int parallel_cable_cpu_resources_init(void); #endif diff --git a/src/Emulators/vice/c64/c64pla.c b/src/Emulators/vice/c64/c64pla.c index bbeff291..f3bb97c2 100644 --- a/src/Emulators/vice/c64/c64pla.c +++ b/src/Emulators/vice/c64/c64pla.c @@ -28,6 +28,7 @@ #include "vice.h" #include "c64pla.h" +#include "c64model.h" #include "datasette.h" #include "mem.h" #include "tapeport.h" @@ -36,15 +37,18 @@ pport_t pport; /* Tape motor status. */ -static BYTE old_port_data_out = 0xff; +static uint8_t old_port_data_out = 0xff; /* Tape write line status. */ -static BYTE old_port_write_bit = 0xff; +static uint8_t old_port_write_bit = 0xff; /* Tape sense line out status. */ -static BYTE old_port_sense_out = 0xff; +static uint8_t old_port_sense_out = 0xff; -void c64pla_config_changed(int tape_sense, int write_in, int motor_in, int caps_sense, BYTE pullup) +/* import from c64-resources.c - don't use the resource for performance reasons */ +extern int board_type; + +void c64pla_config_changed(int tape_sense, int write_in, int motor_in, int caps_sense, uint8_t pullup) { pport.data_out = (pport.data_out & ~pport.dir) | (pport.data & pport.dir); @@ -72,31 +76,48 @@ void c64pla_config_changed(int tape_sense, int write_in, int motor_in, int caps_ if (((pport.dir & pport.data) & 0x20) != old_port_data_out) { old_port_data_out = (pport.dir & pport.data) & 0x20; - tapeport_set_motor(!old_port_data_out); + if (board_type != BOARD_SX64) { + tapeport_set_motor(TAPEPORT_PORT_1, !old_port_data_out); + } } if (((~pport.dir | pport.data) & 0x8) != old_port_write_bit) { old_port_write_bit = (~pport.dir | pport.data) & 0x8; - tapeport_toggle_write_bit((~pport.dir | pport.data) & 0x8); + if (board_type != BOARD_SX64) { + tapeport_toggle_write_bit(TAPEPORT_PORT_1, (~pport.dir | pport.data) & 0x8); + } } if (((pport.dir & pport.data) & 0x10) != old_port_sense_out) { old_port_sense_out = (pport.dir & pport.data) & 0x10; - tapeport_set_sense_out(!old_port_sense_out); + if (board_type != BOARD_SX64) { + tapeport_set_sense_out(TAPEPORT_PORT_1, !old_port_sense_out); + } } pport.dir_read = pport.dir; } +/* + * both DDR and DATA are 0 after poweron/reset, this means all pins are input, + * and the pullups at charen/hiram/loram/sense will pull up the respective lines + * so the kernal will be banked in and i/o is active. + */ void c64pla_pport_reset(void) { - pport.data = 0x3f; - pport.data_out = 0x3f; - pport.data_read = 0x3f; + pport.data = 0; + pport.data_out = 0; + pport.data_read = 0; pport.dir = 0; pport.dir_read = 0; + pport.data_set_bit3 = 0; + pport.data_set_bit4 = 0; + pport.data_set_bit5 = 0; pport.data_set_bit6 = 0; pport.data_set_bit7 = 0; + pport.data_falloff_bit3 = 0; + pport.data_falloff_bit4 = 0; + pport.data_falloff_bit5 = 0; pport.data_falloff_bit6 = 0; pport.data_falloff_bit7 = 0; } diff --git a/src/Emulators/vice/c64/c64pla.h b/src/Emulators/vice/c64/c64pla.h index 1e1c4ac1..b394423b 100644 --- a/src/Emulators/vice/c64/c64pla.h +++ b/src/Emulators/vice/c64/c64pla.h @@ -32,35 +32,44 @@ struct pport_s { /* Value written to processor port. */ - BYTE dir; - BYTE data; + uint8_t dir; + uint8_t data; /* Value read from processor port. */ - BYTE dir_read; - BYTE data_read; + uint8_t dir_read; + uint8_t data_read; /* State of processor port pins. */ - BYTE data_out; + uint8_t data_out; /* cycle that should invalidate the unused bits of the data port. */ + CLOCK data_set_clk_bit3; /* SX-64 only */ + CLOCK data_set_clk_bit4; /* SX-64 only */ + CLOCK data_set_clk_bit5; /* SX-64 only */ CLOCK data_set_clk_bit6; CLOCK data_set_clk_bit7; /* indicates if the unused bits of the data port are still valid or should be read as 0, 1 = unused bits valid, 0 = unused bits should be 0 */ - BYTE data_set_bit6; - BYTE data_set_bit7; + uint8_t data_set_bit3; /* SX-64 only */ + uint8_t data_set_bit4; /* SX-64 only */ + uint8_t data_set_bit5; /* SX-64 only */ + uint8_t data_set_bit6; + uint8_t data_set_bit7; /* indicated if the unused bits are in the process of falling off. */ - BYTE data_falloff_bit6; - BYTE data_falloff_bit7; + uint8_t data_falloff_bit3; /* SX-64 only */ + uint8_t data_falloff_bit4; /* SX-64 only */ + uint8_t data_falloff_bit5; /* SX-64 only */ + uint8_t data_falloff_bit6; + uint8_t data_falloff_bit7; }; typedef struct pport_s pport_t; extern pport_t pport; -extern void c64pla_config_changed(int tape_sense, int write_in, int motor_in, int caps_sense, BYTE pullup); -extern void c64pla_pport_reset(void); +void c64pla_config_changed(int tape_sense, int write_in, int motor_in, int caps_sense, uint8_t pullup); +void c64pla_pport_reset(void); #endif diff --git a/src/Emulators/vice/c64/c64printer.c b/src/Emulators/vice/c64/c64printer.c index 2ad60c7e..65a9ec4c 100644 --- a/src/Emulators/vice/c64/c64printer.c +++ b/src/Emulators/vice/c64/c64printer.c @@ -32,7 +32,7 @@ #include "printer.h" -void machine_printer_setup_context(struct machine_context_s *machine_context) +void machine_printer_setup_context(struct machine_context_s *machinecontext) { } @@ -50,10 +50,7 @@ void machine_printer_resources_shutdown(void) int machine_printer_cmdline_options_init(void) { - if (printer_serial_init_cmdline_options() < 0 || printer_userport_init_cmdline_options() < 0) { - return -1; - } - return 0; + return printer_serial_init_cmdline_options(); } void machine_printer_init(void) diff --git a/src/Emulators/vice/c64/c64rom.c b/src/Emulators/vice/c64/c64rom.c index e0e614f8..41814ba6 100644 --- a/src/Emulators/vice/c64/c64rom.c +++ b/src/Emulators/vice/c64/c64rom.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUG_C64ROM */ + #include "vice.h" #include @@ -36,12 +38,18 @@ #include "log.h" #include "machine.h" #include "mem.h" -#include "patchrom.h" #include "resources.h" +#include "sha1.h" #include "sysfile.h" #include "vicetypes.h" -static log_t c64rom_log = LOG_ERR; +#ifdef DEBUG_C64ROM +#define LOG(x) log_printf x +#else +#define LOG(x) +#endif + +static log_t c64rom_log = LOG_DEFAULT; /* Flag: nonzero if the Kernal and BASIC ROMs have been loaded. */ static int rom_loaded = 0; @@ -51,11 +59,42 @@ int c64rom_isloaded(void) return rom_loaded; } -int c64rom_get_kernal_chksum_id(WORD *sumout, int *idout) +struct kernal_s { + int id; /* the value located at 0xff80 */ + int chksum; + char *sha1hash; + int rev; +}; + +/* NOTE: also update the table in c64-resources.c */ +static struct kernal_s kernal_match[] = { + { C64_KERNAL_ID_R01, C64_KERNAL_CHECKSUM_R01, C64_KERNAL_HASH_R01, C64_KERNAL_REV1 }, + { C64_KERNAL_ID_R02, C64_KERNAL_CHECKSUM_R02, C64_KERNAL_HASH_R02, C64_KERNAL_REV2 }, + { C64_KERNAL_ID_R03, C64_KERNAL_CHECKSUM_R03, C64_KERNAL_HASH_R03, C64_KERNAL_REV3 }, +/* { C64_KERNAL_ID_R03swe, C64_KERNAL_CHECKSUM_R03swe, C64_KERNAL_HASH_R03swe, C64_KERNAL_REV3swe }, */ + { C64_KERNAL_ID_JAP, C64_KERNAL_CHECKSUM_JAP, C64_KERNAL_HASH_JAP, C64_KERNAL_JAP }, + { C64_KERNAL_ID_R43, C64_KERNAL_CHECKSUM_R43, C64_KERNAL_HASH_R43, C64_KERNAL_SX64 }, + { C64_KERNAL_ID_GS64, C64_KERNAL_CHECKSUM_GS64, C64_KERNAL_HASH_GS64, C64_KERNAL_GS64 }, + { C64_KERNAL_ID_R64, C64_KERNAL_CHECKSUM_R64, C64_KERNAL_HASH_R64, C64_KERNAL_4064 }, + { 0, 0, NULL, C64_KERNAL_UNKNOWN } +}; + +int c64rom_get_kernal_chksum_id(uint16_t *sumout, int *idout, char *hash) { int i; - WORD sum; /* ROM checksum */ + uint16_t sum; /* ROM checksum */ int id; /* ROM identification number */ + char sha1hash[41]; + + /* special case to support MAX machine, if kernal is all zeros, return C64_KERNAL_NONE */ + for (i = 0, sum = 0; i < C64_KERNAL_ROM_SIZE; i++) { + sum |= c64memrom_kernal64_rom[i]; + } + if (sum == 0) { + *sumout = 0; *idout = 0; + LOG(("c64rom_get_kernal_chksum_id: C64_KERNAL_NONE")); + return C64_KERNAL_NONE; + } /* Check Kernal ROM. */ for (i = 0, sum = 0; i < C64_KERNAL_ROM_SIZE; i++) { @@ -63,53 +102,103 @@ int c64rom_get_kernal_chksum_id(WORD *sumout, int *idout) } /* get ID from Kernal ROM */ id = c64memrom_rom64_read(0xff80); + + LOG(("c64rom_get_kernal_chksum_id chksum: %d id: %d", sum, id)); + if (sumout) { *sumout = sum; } if (idout) { *idout = id; } - /* check against known kernal versions */ - if (((id == C64_KERNAL_ID_R01) && (sum == C64_KERNAL_CHECKSUM_R01)) || - ((id == C64_KERNAL_ID_R02) && (sum == C64_KERNAL_CHECKSUM_R02)) || - ((id == C64_KERNAL_ID_R03) && (sum == C64_KERNAL_CHECKSUM_R03)) || - /* ((id == C64_KERNAL_ID_R03swe) && (sum == C64_KERNAL_CHECKSUM_R03swe)) || */ - ((id == C64_KERNAL_ID_R43) && (sum == C64_KERNAL_CHECKSUM_R43)) || - ((id == C64_KERNAL_ID_R64) && (sum == C64_KERNAL_CHECKSUM_R64)) - ) { - /* known */ - return 0; + + SHA1String(sha1hash, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE); + LOG(("c64rom_get_kernal_chksum_id sha1: %s", sha1hash)); + + if (hash) { + strncpy(hash, sha1hash, 41); } - return -1; /* unknown */ + + /* find kernal that matches the SHA1 hash */ + i= 0; do { + if (strncmp(kernal_match[i].sha1hash, sha1hash, 40) == 0) { + LOG(("c64rom_get_kernal_chksum_id: rev:%d", kernal_match[i].rev)); + return kernal_match[i].rev; + } + i++; + } while (kernal_match[i].rev != C64_KERNAL_UNKNOWN); + + LOG(("c64rom_get_kernal_chksum_id: C64_KERNAL_NONE")); + return C64_KERNAL_UNKNOWN; /* unknown */ } -/* FIXME: this function should perhaps not patch the kernal, but return -1 on - unknown kernals, like the respective vic-20 functions */ -int c64rom_get_kernal_checksum(void) +/* FIXME: this function has a misleading name, only called from snapshot stuff atm + it was used to patch the kernal before, but not anymore +*/ +int c64rom_print_kernal_info(void) { - WORD sum; /* ROM checksum */ + uint16_t sum; /* ROM checksum */ int id; /* ROM identification number */ - - if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) { - log_warning(c64rom_log, "Unknown Kernal image. ID: %d ($%02X) Sum: %d ($%04X).", id, id, sum, sum); - return -1; + int rev; /* detected revision */ + char hash[41]; + + rev = c64rom_get_kernal_chksum_id(&sum, &id, hash); + if (rev == C64_KERNAL_UNKNOWN) { + log_warning(c64rom_log, "Unknown Kernal image. ID: %d ($%02X) Sum: %d ($%04X) SHA1: %s.", + id, (unsigned int)id, sum, sum, hash); + return rev; + } else if (rev == C64_KERNAL_NONE) { + /* MAX machine doesn't have a kernal */ + log_message(c64rom_log, "No Kernal image. No hash calculated."); } else { - log_message(c64rom_log, "Kernal rev #%d ($%02X) Sum: %d ($%04X).", id, id, sum, sum); + log_message(c64rom_log, "Kernal rev #%d ($%02X) Sum: %d ($%04X) SHA1: %s.", + id, (unsigned int)id, sum, sum, hash); } - return 0; + return rev; } -int c64rom_cartkernal_active = 0; +/* FIXME: this flag is strange, it is only ever set to 1 and never to 0 */ +static int c64rom_cartkernal_active = 0; + +#define NUM_TRAP_DEVICES 9 /* FIXME: is there a better constant ? */ +static int trapfl[NUM_TRAP_DEVICES]; +static int trapdevices[NUM_TRAP_DEVICES + 1] = { 1, 4, 5, 6, 7, 8, 9, 10, 11, -1 }; -/* the extra parameter cartkernal is used to replace the kernal - with a cartridge kernal rom image, if it is NULL normal kernal - is used */ -int c64rom_load_kernal(const char *rom_name, BYTE *cartkernal) +static void get_trapflags(void) { - int trapfl, rev; - WORD sum; /* ROM checksum */ - int id; /* ROM identification number */ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_get_int_sprintf("TrapDevice%d", &trapfl[i], trapdevices[i]); + } +} + +static void clear_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_set_int_sprintf("TrapDevice%d", 0, trapdevices[i]); + } +} + +static void restore_trapflags(void) +{ + int i; + for(i = 0; trapdevices[i] != -1; i++) { + resources_set_int_sprintf("TrapDevice%d", trapfl[i], trapdevices[i]); + } +} + +/* FIXME: the extra parameter cartkernal was used to replace the kernal + with a cartridge kernal rom image. + + CAUTION: The current code does NOT use this anymore, cartkernal is always NULL +*/ +int c64rom_load_kernal(const char *rom_name, uint8_t *cartkernal) +{ + int rev; + + LOG(("c64rom_load_kernal rom_name:%s", rom_name)); if (!rom_loaded) { return 0; @@ -117,57 +206,55 @@ int c64rom_load_kernal(const char *rom_name, BYTE *cartkernal) /* disable traps before loading the ROM */ if (machine_class != VICE_MACHINE_VSID) { - resources_get_int("VirtualDevices", &trapfl); - resources_set_int("VirtualDevices", 0); + get_trapflags(); + clear_trapflags(); } /* Load Kernal ROM. */ if (cartkernal == NULL) { if (c64rom_cartkernal_active == 1) { if (machine_class != VICE_MACHINE_VSID) { - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(); } return -1; } - if (sysfile_load(rom_name, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE) < 0) { - log_error(c64rom_log, "Couldn't load kernal ROM `%s'.", rom_name); - if (machine_class != VICE_MACHINE_VSID) { - resources_set_int("VirtualDevices", trapfl); + if (strcmp(rom_name, C64_KERNAL_NONE_NAME) == 0) { + /* special case handling for "no kernal" (MAX machine) */ + memset(c64memrom_kernal64_rom, 0, C64_KERNAL_ROM_SIZE); + } else { + if (sysfile_load(rom_name, machine_name, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE, C64_KERNAL_ROM_SIZE) < 0) { + log_error(c64rom_log, "Couldn't load kernal ROM `%s'.", rom_name); + if (machine_class != VICE_MACHINE_VSID) { + restore_trapflags(); + } + return -1; } - return -1; } } else { memcpy(c64memrom_kernal64_rom, cartkernal, 0x2000); c64rom_cartkernal_active = 1; } - if (machine_class != VICE_MACHINE_C64DTV) { - resources_get_int("KernalRev", &rev); - } - if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) { - log_verbose("loaded unknown kernal revision:%d chksum: %d", id, sum); - rev = C64_KERNAL_UNKNOWN; - } else { - log_verbose("loaded known kernal revision:%d chksum: %d", id, sum); - rev = id; - } + rev = c64rom_print_kernal_info(); if (machine_class != VICE_MACHINE_C64DTV) { resources_set_int("KernalRev", rev); } + memcpy(c64memrom_kernal64_trap_rom, c64memrom_kernal64_rom, C64_KERNAL_ROM_SIZE); if (machine_class != VICE_MACHINE_VSID) { - resources_set_int("VirtualDevices", trapfl); + restore_trapflags(); } return 0; } -int c64rom_get_basic_checksum(void) +int c64rom_print_basic_info(void) { int i; - WORD sum; + uint16_t sum; /* ROM checksum */ + int rev = 0; /* ROM revision */ /* Check Basic ROM. */ @@ -179,7 +266,7 @@ int c64rom_get_basic_checksum(void) log_warning(c64rom_log, "Unknown Basic image. Sum: %d ($%04X).", sum, sum); } - return 0; + return rev; } int c64rom_load_basic(const char *rom_name) @@ -189,11 +276,12 @@ int c64rom_load_basic(const char *rom_name) } /* Load Basic ROM. */ - if (sysfile_load(rom_name, c64memrom_basic64_rom, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE) < 0) { + if (sysfile_load(rom_name, machine_name, c64memrom_basic64_rom, C64_BASIC_ROM_SIZE, C64_BASIC_ROM_SIZE) < 0) { log_error(c64rom_log, "Couldn't load basic ROM `%s'.", rom_name); return -1; } - return c64rom_get_basic_checksum(); + c64rom_print_basic_info(); + return 0; } int c64rom_load_chargen(const char *rom_name) @@ -204,7 +292,7 @@ int c64rom_load_chargen(const char *rom_name) /* Load chargen ROM. */ - if (sysfile_load(rom_name, mem_chargen_rom, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE) < 0) { + if (sysfile_load(rom_name, machine_name, mem_chargen_rom, C64_CHARGEN_ROM_SIZE, C64_CHARGEN_ROM_SIZE) < 0) { log_error(c64rom_log, "Couldn't load character ROM `%s'.", rom_name); return -1; } @@ -216,7 +304,7 @@ int mem_load(void) { const char *rom_name = NULL; - if (c64rom_log == LOG_ERR) { + if (c64rom_log == LOG_DEFAULT) { c64rom_log = log_open("C64MEM"); } diff --git a/src/Emulators/vice/c64/c64rom.h b/src/Emulators/vice/c64/c64rom.h index 5409d9d0..935fa98e 100644 --- a/src/Emulators/vice/c64/c64rom.h +++ b/src/Emulators/vice/c64/c64rom.h @@ -27,16 +27,84 @@ #ifndef VICE_C64ROM_H #define VICE_C64ROM_H -extern int c64rom_load_kernal(const char *rom_name, BYTE *new_kernal); -extern int c64rom_load_basic(const char *rom_name); -extern int c64rom_load_chargen(const char *rom_name); +/* filenames used for the BASIC ROMs */ +#define C64_BASIC_NAME "basic-901226-01.bin" -extern int c64rom_get_kernal_checksum(void); -extern int c64rom_get_kernal_chksum_id(WORD *sumout, int *idout); -extern int c64rom_get_basic_checksum(void); +/* unique IDs to refer to a kernal, used for the KernalRev resource */ +#define C64_KERNAL_UNKNOWN -1 -extern int c64rom_isloaded(void); +#define C64_KERNAL_JAP 0 /* 906145-02 */ +#define C64_KERNAL_REV1 1 /* 901227-01 */ +#define C64_KERNAL_REV2 2 /* 901227-02 */ +#define C64_KERNAL_REV3 3 /* 901227-03 */ +#define C64_KERNAL_GS64 39 /* 390852-01 */ +#define C64_KERNAL_SX64 67 /* 251104-04 */ +#define C64_KERNAL_4064 100 /* 901246-01 */ -extern int c64rom_cartkernal_active; +#define C64_KERNAL_REV3SWE 13 /* FIXME */ + +#define C64_KERNAL_NONE -2 /* used for the MAX machine, which has no kernal */ + +/* filenames used for the kernal ROMs */ +#define C64_KERNAL_JAP_NAME "kernal-906145-02.bin" +#define C64_KERNAL_REV1_NAME "kernal-901227-01.bin" +#define C64_KERNAL_REV2_NAME "kernal-901227-02.bin" +#define C64_KERNAL_REV3_NAME "kernal-901227-03.bin" +#define C64_KERNAL_GS64_NAME "kernal-390852-01.bin" +#define C64_KERNAL_SX64_NAME "kernal-251104-04.bin" +#define C64_KERNAL_4064_NAME "kernal-901246-01.bin" + +#define C64_KERNAL_NONE_NAME "kernal-none.bin" /* dummy, used for the MAX machine, which has no kernal */ + +/* filenames used for the chargen ROMs */ +#define C64_CHARGEN_NAME "chargen-901225-01.bin" +#define C64_CHARGEN_JAP_NAME "chargen-906143-02.bin" + +/* simple additive checksum */ +#define C64_BASIC_CHECKSUM 15702 + +#define C64_KERNAL_CHECKSUM_JAP 53635 /* 906145-02 */ +#define C64_KERNAL_CHECKSUM_R01 54525 /* 901227-01 */ +#define C64_KERNAL_CHECKSUM_R02 50955 /* 901227-02 */ +#define C64_KERNAL_CHECKSUM_R03 50954 /* 901227-03 */ +#define C64_KERNAL_CHECKSUM_GS64 46538 /* 390852-01 (gs) */ +#define C64_KERNAL_CHECKSUM_R43 50955 /* 251104-04 (sx) */ +#define C64_KERNAL_CHECKSUM_R64 49680 /* 901246-01 (educator) */ + +#define C64_KERNAL_CHECKSUM_R03swe 50633 /* FIXME */ + +/* the value located at 0xff80 */ +#define C64_KERNAL_ID_JAP 0x00 /* 906145-02 */ +#define C64_KERNAL_ID_R01 0xaa /* 901227-01 */ +#define C64_KERNAL_ID_R02 0x00 /* 901227-02 */ +#define C64_KERNAL_ID_R03 0x03 /* 901227-03 */ +#define C64_KERNAL_ID_GS64 0x03 /* 390852-01 (gs) */ +#define C64_KERNAL_ID_R43 0x43 /* 251104-04 (sx) */ +#define C64_KERNAL_ID_R64 0x64 /* 901246-01 (educator) */ + +#define C64_KERNAL_ID_R03swe 0x03 /* FIXME */ + +/* SHA1 hashes */ +#define C64_BASIC_HASH "79015323128650c742a3694c9429aa91f355905e" + +#define C64_KERNAL_HASH_JAP "4ff0f11e80f4b57430d8f0c3799ed0f0e0f4565d" /* 906145-02 */ +#define C64_KERNAL_HASH_R01 "87cc04d61fc748b82df09856847bb5c2754a2033" /* 901227-01 */ +#define C64_KERNAL_HASH_R02 "0e2e4ee3f2d41f00bed72f9ab588b83e306fdb13" /* 901227-02 */ +#define C64_KERNAL_HASH_R03 "1d503e56df85a62fee696e7618dc5b4e781df1bb" /* 901227-03 */ +#define C64_KERNAL_HASH_GS64 "3ad6cc1837c679a11f551ad1cf1a32dd84ace719" /* 390852-01 (gs) */ +#define C64_KERNAL_HASH_R43 "aa136e91ecf3c5ac64f696b3dbcbfc5ba0871c98" /* 251104-04 (sx) */ +#define C64_KERNAL_HASH_R64 "6c4fa9465f6091b174df27dfe679499df447503c" /* 901246-01 (educator) */ + +int c64rom_load_kernal(const char *rom_name, uint8_t *new_kernal); +int c64rom_load_basic(const char *rom_name); +int c64rom_load_chargen(const char *rom_name); + +int c64rom_get_kernal_chksum_id(uint16_t *sumout, int *idout, char *sha1hash); + +/* print ROM ID, checksum, sha1 hash. returns the revision */ +int c64rom_print_kernal_info(void); +int c64rom_print_basic_info(void); + +int c64rom_isloaded(void); #endif diff --git a/src/Emulators/vice/c64/c64romset.c b/src/Emulators/vice/c64/c64romset.c index 44d26820..f863fb8c 100644 --- a/src/Emulators/vice/c64/c64romset.c +++ b/src/Emulators/vice/c64/c64romset.c @@ -28,9 +28,10 @@ #include +#include "machine.h" #include "romset.h" -const char *machine_romset_resources_list[] = { +static const char * const machine_romset_resources_list[] = { "ChargenName", "KernalName", "BasicName", @@ -47,6 +48,7 @@ const char *machine_romset_resources_list[] = { "DosName3040", "DosName4040", "DosName1001", + "DosName9000", NULL }; diff --git a/src/Emulators/vice/c64/c64rsuser.h b/src/Emulators/vice/c64/c64rsuser.h index a0203bb3..10cc40c7 100644 --- a/src/Emulators/vice/c64/c64rsuser.h +++ b/src/Emulators/vice/c64/c64rsuser.h @@ -27,6 +27,6 @@ #ifndef VICE_C64RSUSER_H #define VICE_C64RSUSER_H -extern void c64_rsuser_init(void); +void c64_rsuser_init(void); #endif diff --git a/src/Emulators/vice/c64/c64scmodel.c b/src/Emulators/vice/c64/c64scmodel.c index 6aed1851..a862efa7 100644 --- a/src/Emulators/vice/c64/c64scmodel.c +++ b/src/Emulators/vice/c64/c64scmodel.c @@ -30,10 +30,11 @@ #include -#include "c64-resources.h" +#include "c64.h" #include "c64iec.h" #include "c64keyboard.h" #include "c64model.h" +#include "c64rom.h" #include "cia.h" #include "machine.h" #include "resources.h" @@ -53,38 +54,37 @@ #define CIA_MODEL_DEFAULT_NEW CIA_MODEL_6526A static int c64model_get_temp(int vicii_model, int sid_model, int glue_logic, - int cia1_model, int cia2_model, int board, int iecreset, - const char *kernal, const char *chargen, int kernalrev); + int cia1model, int cia2model, int board, int iecreset, + const char *chargen, int kernalrev); static void c64model_set_temp(int model, int *vicii_model, int *sid_model, - int *glue_logic, int *cia1_model, int *cia2_model, + int *glue_logic, int *cia1model, int *cia2model, int *board, int *iecreset, - const char *kernal, const char *chargen, int *kernalrev); + const char *chargen, int *kernalrev); /******************************************************************************/ // c64d - keep resid-fp static int is_new_sid(int model) { - switch (model) { - case SID_MODEL_6581: - case SID_MODEL_6581R4: - case SID_MODEL_6581R3_4885: - case SID_MODEL_6581R3_0486S: - case SID_MODEL_6581R3_3984: - case SID_MODEL_6581R4AR_3789: - case SID_MODEL_6581R3_4485: - case SID_MODEL_6581R4_1986S: - default: - return 0; - - case SID_MODEL_8580: - case SID_MODEL_8580D: - case SID_MODEL_8580R5_3691: - case SID_MODEL_8580R5_3691D: - case SID_MODEL_8580R5_1489: - case SID_MODEL_8580R5_1489D: - return 1; - } + switch (model) { + case SID_MODEL_6581: + case SID_MODEL_6581R3_4885: + case SID_MODEL_6581R3_0486S: + case SID_MODEL_6581R3_3984: + case SID_MODEL_6581R4AR_3789: + case SID_MODEL_6581R3_4485: + case SID_MODEL_6581R4_1986S: + default: + return 0; + + case SID_MODEL_8580: + case SID_MODEL_8580D: + case SID_MODEL_8580R5_3691: + case SID_MODEL_8580R5_3691D: + case SID_MODEL_8580R5_1489: + case SID_MODEL_8580R5_1489D: + return 1; + } } static int is_new_cia(int model) @@ -102,6 +102,7 @@ static int is_new_cia(int model) struct model_s { int vicii; /* VIC-II model */ int video; /* machine video timing */ + int ciatick; int cia; /* old or new */ int glue; /* discrete or ASIC */ int sid; /* old or new */ @@ -111,115 +112,115 @@ struct model_s { int iec; int userport; int keyboard; - char *kernalname; - char *chargenname; - int kernalrev; + int cia2; + const char *chargenname; + int kernalrev; /* note: the name of the kernal is in a table in c64-resources.c */ }; -static struct model_s c64models[] = { +static const struct model_s c64models[] = { /* C64 PAL */ - { VICII_MODEL_6569, MACHINE_SYNC_PAL, + { VICII_MODEL_6569, MACHINE_SYNC_PAL, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV3 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV3 }, /* C64C PAL */ - { VICII_MODEL_8565, MACHINE_SYNC_PAL, + { VICII_MODEL_8565, MACHINE_SYNC_PAL, CIATICK_NET, CIA_MODEL_DEFAULT_NEW, GLUE_CUSTOM_IC, NEW_SID, BOARD_C64, - IEC_HARD_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV3 }, + IEC_HARD_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV3 }, /* C64 OLD PAL */ - { VICII_MODEL_6569R1, MACHINE_SYNC_PAL, + { VICII_MODEL_6569R1, MACHINE_SYNC_PAL, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV2 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV2 }, /* C64 NTSC */ - { VICII_MODEL_6567, MACHINE_SYNC_NTSC, + { VICII_MODEL_6567, MACHINE_SYNC_NTSC, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV3 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV3 }, /* C64C NTSC */ - { VICII_MODEL_8562, MACHINE_SYNC_NTSC, + { VICII_MODEL_8562, MACHINE_SYNC_NTSC, CIATICK_NET, CIA_MODEL_DEFAULT_NEW, GLUE_CUSTOM_IC, NEW_SID, BOARD_C64, - IEC_HARD_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV3 }, + IEC_HARD_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV3 }, /* C64 OLD NTSC */ - { VICII_MODEL_6567R56A, MACHINE_SYNC_NTSCOLD, + { VICII_MODEL_6567R56A, MACHINE_SYNC_NTSCOLD, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV1 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV1 }, /* C64 PAL-N */ - { VICII_MODEL_6572, MACHINE_SYNC_PALN, + { VICII_MODEL_6572, MACHINE_SYNC_PALN, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_REV3 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_REV3 }, /* SX64 PAL, FIXME: guessed */ - { VICII_MODEL_6569, MACHINE_SYNC_PAL, - CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, NO_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "sxkernal", "chargen", C64_KERNAL_SX64 }, + { VICII_MODEL_6569, MACHINE_SYNC_PAL, CIATICK_60HZ, + CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_SX64, + IEC_SOFT_RESET, NO_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_SX64 }, /* SX64 NTSC, FIXME: guessed */ - { VICII_MODEL_6567, MACHINE_SYNC_NTSC, - CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, NO_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "sxkernal", "chargen", C64_KERNAL_SX64 }, + { VICII_MODEL_6567, MACHINE_SYNC_NTSC, CIATICK_60HZ, + CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_SX64, + IEC_SOFT_RESET, NO_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_SX64 }, /* C64 Japanese, FIXME: guessed */ - { VICII_MODEL_6567, MACHINE_SYNC_NTSC, + { VICII_MODEL_6567, MACHINE_SYNC_NTSC, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "jpkernal", "jpchrgen", C64_KERNAL_JAP }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_JAP_NAME, C64_KERNAL_JAP }, /* C64 GS, FIXME: guessed */ - { VICII_MODEL_8565, MACHINE_SYNC_PAL, + { VICII_MODEL_8565, MACHINE_SYNC_PAL, CIATICK_NET, CIA_MODEL_DEFAULT_NEW, GLUE_CUSTOM_IC, NEW_SID, BOARD_C64, - IEC_HARD_RESET, NO_DATASETTE, NO_IEC, NO_USERPORT, NO_KEYBOARD, - "gskernal", "chargen", C64_KERNAL_GS64 }, + IEC_HARD_RESET, NO_DATASETTE, NO_IEC, NO_USERPORT, NO_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_GS64 }, /* PET64 PAL, FIXME: guessed */ - { VICII_MODEL_6569, MACHINE_SYNC_PAL, + { VICII_MODEL_6569, MACHINE_SYNC_PAL, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "edkernal", "chargen", C64_KERNAL_4064 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_4064 }, /* PET64 NTSC, FIXME: guessed */ - { VICII_MODEL_6567, MACHINE_SYNC_NTSC, + { VICII_MODEL_6567, MACHINE_SYNC_NTSC, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_C64, - IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, - "edkernal", "chargen", C64_KERNAL_4064 }, + IEC_SOFT_RESET, HAS_DATASETTE, HAS_IEC, HAS_USERPORT, HAS_KEYBOARD, HAS_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_4064 }, /* ultimax, FIXME: guessed */ /* FIXME: the MAX uses a VICII 6566, currenly unemulated, NTSC-M only */ - { VICII_MODEL_6567, MACHINE_SYNC_NTSC, + { VICII_MODEL_6567, MACHINE_SYNC_NTSC, CIATICK_NET, CIA_MODEL_DEFAULT_OLD, GLUE_DISCRETE, OLD_SID, BOARD_MAX, - IEC_SOFT_RESET, HAS_DATASETTE, NO_IEC, NO_USERPORT, HAS_KEYBOARD, - "kernal", "chargen", C64_KERNAL_MAX }, + IEC_SOFT_RESET, HAS_DATASETTE, NO_IEC, NO_USERPORT, HAS_KEYBOARD, NO_CIA2, + C64_CHARGEN_NAME, C64_KERNAL_NONE }, }; /* ------------------------------------------------------------------------- */ static int c64model_get_temp(int vicii_model, int sid_model, int glue_logic, - int cia1_model, int cia2_model, int board, - int iecreset, const char *kernal, const char *chargen, int kernalrev) + int cia1model, int cia2model, int board, + int iecreset, const char *chargen, int kernalrev) { int new_sid; int new_cia; int i; - if (cia1_model != cia2_model) { + if (cia1model != cia2model) { return C64MODEL_UNKNOWN; } new_sid = is_new_sid(sid_model); - new_cia = is_new_cia(cia1_model); + new_cia = is_new_cia(cia1model); for (i = 0; i < C64MODEL_NUM; ++i) { if ((c64models[i].vicii == vicii_model) @@ -229,8 +230,7 @@ static int c64model_get_temp(int vicii_model, int sid_model, int glue_logic, && (c64models[i].board == board) && (c64models[i].iecreset == iecreset) && (c64models[i].kernalrev == kernalrev) - && (!strcmp(c64models[i].kernalname, kernal)) - && (!strcmp(c64models[i].chargenname, chargen))) { + && (chargen && (strcmp(c64models[i].chargenname, chargen) == 0))) { return i; } } @@ -243,45 +243,43 @@ int c64model_get_model(c64model_details_t *details) { return c64model_get_temp(details->vicii_model, details->sid_model, details->glue_logic, details->cia1_model, details->cia2_model, - details->board, details->iecreset, details->kernal, details->chargen, details->kernalrev); + details->board, details->iecreset, details->chargen, details->kernalrev); } int c64model_get(void) { - int modelType; - int vicii_model, sid_model, glue_logic, cia1_model, cia2_model, board, iecreset, kernalrev; - char c[0x10], k[0x10]; - const char *chargen = c, *kernal = k; + int modelType; + int vicii_model, sid_model, glue_logic, cia1model, cia2model, board, iecreset, kernalrev; + const char *chargen; if ((resources_get_int("VICIIModel", &vicii_model) < 0) || (resources_get_int("SidModel", &sid_model) < 0) || (resources_get_int("GlueLogic", &glue_logic) < 0) - || (resources_get_int("CIA1Model", &cia1_model) < 0) - || (resources_get_int("CIA2Model", &cia2_model) < 0) + || (resources_get_int("CIA1Model", &cia1model) < 0) + || (resources_get_int("CIA2Model", &cia2model) < 0) || (resources_get_int("BoardType", &board) < 0) || (resources_get_int("IECReset", &iecreset) < 0) || (resources_get_int("KernalRev", &kernalrev) < 0) - || (resources_get_string("KernalName", &kernal) < 0) || (resources_get_string("ChargenName", &chargen) < 0)) { return -1; } LOGD("vicii_resources.model=%d vicii_model=%d", (BYTE)vicii_resources.model, vicii_model); - + modelType = c64model_get_temp(vicii_model, sid_model, glue_logic, - cia1_model, cia2_model, board, iecreset, - kernal, chargen, kernalrev); - + cia1model, cia2model, board, iecreset, + chargen, kernalrev); + LOGD("modelType=%d", modelType); - + return modelType; } static void c64model_set_temp(int model, int *vicii_model, int *sid_model, - int *glue_logic, int *cia1_model, int *cia2_model, + int *glue_logic, int *cia1model, int *cia2model, int *board, int *iecreset, - const char *kernal, const char *chargen, int *kernalrev) + const char *chargen, int *kernalrev) { int old_model; int old_engine; @@ -291,16 +289,16 @@ static void c64model_set_temp(int model, int *vicii_model, int *sid_model, int new_type; old_model = c64model_get_temp(*vicii_model, *sid_model, *glue_logic, - *cia1_model, *cia2_model, *board, - *iecreset, kernal, chargen, *kernalrev); + *cia1model, *cia2model, *board, + *iecreset, chargen, *kernalrev); if ((model == old_model) || (model == C64MODEL_UNKNOWN)) { return; } *vicii_model = c64models[model].vicii; - *cia1_model = c64models[model].cia; - *cia2_model = c64models[model].cia; + *cia1model = c64models[model].cia; + *cia2model = c64models[model].cia; *glue_logic = c64models[model].glue; *board = c64models[model].board; *iecreset = c64models[model].iecreset; @@ -328,7 +326,7 @@ void c64model_set_details(c64model_details_t *details, int model) c64model_set_temp(model, &details->vicii_model, &details->sid_model, &details->glue_logic, &details->cia1_model, &details->cia2_model, &details->board, &details->iecreset, - details->kernal, details->chargen, &details->kernalrev); + details->chargen, &details->kernalrev); } void c64model_set(int model) @@ -339,6 +337,7 @@ void c64model_set(int model) int old_type; int new_sid_model; int new_type; + int pf; old_model = c64model_get(); @@ -348,13 +347,27 @@ void c64model_set(int model) // } resources_set_int("VICIIModel", c64models[model].vicii); + /* Determine the power net frequency for this model. It will be 60Hz in all + cases, except for PAL models that get the tick from the power grid */ + pf = 60; + if (c64models[model].ciatick == CIATICK_NET) { + switch(c64models[model].video) { + case MACHINE_SYNC_PAL: + case MACHINE_SYNC_PALN: + pf = 50; + break; + default: + break; + } + } + resources_set_int("MachinePowerFrequency", pf); + resources_set_int("CIA1Model", c64models[model].cia); resources_set_int("CIA2Model", c64models[model].cia); resources_set_int("GlueLogic", c64models[model].glue); resources_set_int("BoardType", c64models[model].board); resources_set_int("IECReset", c64models[model].iecreset); - resources_set_string("KernalName", c64models[model].kernalname); resources_set_string("ChargenName", c64models[model].chargenname); resources_set_int("KernalRev", c64models[model].kernalrev); @@ -377,4 +390,5 @@ void c64model_set(int model) c64keyboard_enable(c64models[model].keyboard); c64iec_enable(c64models[model].iec); tapeport_enable(c64models[model].datasette); + c64_cia2_enable(c64models[model].cia2); } diff --git a/src/Emulators/vice/c64/c64sound.c b/src/Emulators/vice/c64/c64sound.c index 0aa164a4..7f92cbf6 100644 --- a/src/Emulators/vice/c64/c64sound.c +++ b/src/Emulators/vice/c64/c64sound.c @@ -37,77 +37,236 @@ #include "sound.h" #include "vicetypes.h" -static BYTE machine_sid2_read(WORD addr) -{ - return sid2_read(addr); -} +#define MACHINE_SIDx_RFUNC(fname, func) \ + static uint8_t fname(uint16_t addr) \ + { \ + return func(addr); \ + } -static void machine_sid2_store(WORD addr, BYTE byte) -{ - sid2_store(addr, byte); -} +MACHINE_SIDx_RFUNC(machine_sid2_read, sid2_read) +MACHINE_SIDx_RFUNC(machine_sid3_read, sid3_read) +MACHINE_SIDx_RFUNC(machine_sid4_read, sid4_read) +MACHINE_SIDx_RFUNC(machine_sid5_read, sid5_read) +MACHINE_SIDx_RFUNC(machine_sid6_read, sid6_read) +MACHINE_SIDx_RFUNC(machine_sid7_read, sid7_read) +MACHINE_SIDx_RFUNC(machine_sid8_read, sid8_read) -static BYTE machine_sid3_read(WORD addr) -{ - return sid3_read(addr); -} +MACHINE_SIDx_RFUNC(machine_sid2_peek, sid2_peek) +MACHINE_SIDx_RFUNC(machine_sid3_peek, sid3_peek) +MACHINE_SIDx_RFUNC(machine_sid4_peek, sid4_peek) +MACHINE_SIDx_RFUNC(machine_sid5_peek, sid5_peek) +MACHINE_SIDx_RFUNC(machine_sid6_peek, sid6_peek) +MACHINE_SIDx_RFUNC(machine_sid7_peek, sid7_peek) +MACHINE_SIDx_RFUNC(machine_sid8_peek, sid8_peek) -static void machine_sid3_store(WORD addr, BYTE byte) -{ - sid3_store(addr, byte); -} +#define MACHINE_SIDx_STORE(fname, func) \ + static void fname(uint16_t addr, uint8_t byte) \ + { \ + func(addr, byte); \ + } + +MACHINE_SIDx_STORE(machine_sid2_store, sid2_store) +MACHINE_SIDx_STORE(machine_sid3_store, sid3_store) +MACHINE_SIDx_STORE(machine_sid4_store, sid4_store) +MACHINE_SIDx_STORE(machine_sid5_store, sid5_store) +MACHINE_SIDx_STORE(machine_sid6_store, sid6_store) +MACHINE_SIDx_STORE(machine_sid7_store, sid7_store) +MACHINE_SIDx_STORE(machine_sid8_store, sid8_store) /* ---------------------------------------------------------------------*/ -static io_source_t stereo_sid_device = { - "Stereo SID", - IO_DETACH_RESOURCE, - "SidStereo", - 0xde00, 0xde1f, 0x1f, - 1, /* read is always valid */ - machine_sid2_store, - machine_sid2_read, - NULL, /* TODO: peek */ - sid2_dump, - 0, - 0, - 0 +/* 2nd SID, can be a cartridge or an internal board */ +static io_source_t sid2_device = { + "Stereo SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xde00, 0xde1f, 0x1f, /* range for the 2nd SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid2_store, /* store function */ + NULL, /* NO poke function */ + machine_sid2_read, /* read function */ + machine_sid2_peek, /* peek function */ + sid2_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +/* 3rd SID, can be a cartridge or an internal board */ +static io_source_t sid3_device = { + "Triple SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xdf00, 0xdf1f, 0x1f, /* range for the 3rd SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid3_store, /* store function */ + NULL, /* NO poke function */ + machine_sid3_read, /* read function */ + machine_sid3_peek, /* peek function */ + sid3_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +/* 4th SID, can be a cartridge or an internal board */ +static io_source_t sid4_device = { + "Quad SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xdf80, 0xdf9f, 0x1f, /* range for the 4th SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid4_store, /* store function */ + NULL, /* NO poke function */ + machine_sid4_read, /* read function */ + machine_sid4_peek, /* peek function */ + sid4_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +/* 5th SID, can be a cartridge or an internal board */ +static io_source_t sid5_device = { + "Penta SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xde80, 0xde9f, 0x1f, /* range for the 5th SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid5_store, /* store function */ + NULL, /* NO poke function */ + machine_sid5_read, /* read function */ + machine_sid5_peek, /* peek function */ + sid5_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +/* 6th SID, can be a cartridge or an internal board */ +static io_source_t sid6_device = { + "Hexa SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xdf40, 0xdf5f, 0x1f, /* range for the 6th SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid6_store, /* store function */ + NULL, /* NO poke function */ + machine_sid6_read, /* read function */ + machine_sid6_peek, /* peek function */ + sid6_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +/* 7th SID, can be a cartridge or an internal board */ +static io_source_t sid7_device = { + "Hepta SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xde40, 0xde5f, 0x1f, /* range for the 6th SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid7_store, /* store function */ + NULL, /* NO poke function */ + machine_sid7_read, /* read function */ + machine_sid7_peek, /* peek function */ + sid7_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; -static io_source_t triple_sid_device = { - "Triple SID", - IO_DETACH_RESOURCE, - "SidStereo", - 0xdf00, 0xdf1f, 0x1f, - 1, /* read is always valid */ - machine_sid3_store, - machine_sid3_read, - NULL, /* TODO: peek */ - sid3_dump, - 0, - 0, - 0 +/* 8th SID, can be a cartridge or an internal board */ +static io_source_t sid8_device = { + "Octa SID", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SidStereo", /* resource to set to '0' */ + 0xdfc0, 0xdfdf, 0x1f, /* range for the 6th SID device, can be changed to other ranges */ + 1, /* read is always valid */ + machine_sid8_store, /* store function */ + NULL, /* NO poke function */ + machine_sid8_read, /* read function */ + machine_sid8_peek, /* peek function */ + sid8_dump, /* device state information dump function */ + IO_CART_ID_NONE, /* none is used here, because it is an I/O only device */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; -static io_source_list_t *stereo_sid_list_item = NULL; -static io_source_list_t *triple_sid_list_item = NULL; +static io_source_list_t *sid2_list_item = NULL; +static io_source_list_t *sid3_list_item = NULL; +static io_source_list_t *sid4_list_item = NULL; +static io_source_list_t *sid5_list_item = NULL; +static io_source_list_t *sid6_list_item = NULL; +static io_source_list_t *sid7_list_item = NULL; +static io_source_list_t *sid8_list_item = NULL; /* ---------------------------------------------------------------------*/ +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the C64 SID sound */ +static sound_chip_mixing_spec_t sid_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* SID 1 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 1 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 2 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 2 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 3 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 3 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 4 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 4 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 5 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 5 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 6 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 6 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 7 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 7 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + }, + { + 100, /* SID 8 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + 100, /* SID 8 left channel volume % in case of stereo output, default output to both, activating more sids changes this */ + } +}; +#endif + +/* C64 SID sound chip */ static sound_chip_t sid_sound_chip = { - sid_sound_machine_open, - sid_sound_machine_init, - sid_sound_machine_close, - sid_sound_machine_calculate_samples, - sid_sound_machine_store, - sid_sound_machine_read, - sid_sound_machine_reset, - sid_sound_machine_cycle_based, - sid_sound_machine_channels, - 1 /* chip enabled */ + sid_sound_machine_open, /* sound chip open function */ + sid_sound_machine_init, /* sound chip init function */ + sid_sound_machine_close, /* sound chip close function */ + sid_sound_machine_calculate_samples, /* sound chip calculate samples function */ + sid_sound_machine_store, /* sound chip store function */ + sid_sound_machine_read, /* sound chip read function */ + sid_sound_machine_reset, /* sound chip reset function */ + sid_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, resid engine is cycle based, all other engines are not */ + sid_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, the amount of channels depends on the extra amount of active SIDs */ +#ifdef SOUND_SYSTEM_FLOAT + sid_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 1 /* sound chip is always enabled */ }; -static WORD sid_sound_chip_offset = 0; +static uint16_t sid_sound_chip_offset = 0; void sid_sound_chip_init(void) { @@ -116,104 +275,209 @@ void sid_sound_chip_init(void) /* ---------------------------------------------------------------------*/ -int machine_sid2_check_range(unsigned int sid2_adr) -{ - if (machine_class == VICE_MACHINE_C128) { - if ((sid2_adr >= 0xd400 && sid2_adr <= 0xd4e0) || (sid2_adr >= 0xd700 && sid2_adr <= 0xdfe0)) { - sid_stereo_address_start = sid2_adr; - stereo_sid_device.start_address = sid2_adr; - sid_stereo_address_end = sid2_adr + 0x1f; - stereo_sid_device.end_address = sid2_adr + 0x1f; - if (stereo_sid_list_item != NULL) { - io_source_unregister(stereo_sid_list_item); - stereo_sid_list_item = io_source_register(&stereo_sid_device); - } else { - if (sid_stereo >= 1) { - stereo_sid_list_item = io_source_register(&stereo_sid_device); - } - } - return 0; - } - } else { - if (sid2_adr >= 0xd400 && sid2_adr <= 0xdfe0) { - sid_stereo_address_start = sid2_adr; - stereo_sid_device.start_address = sid2_adr; - sid_stereo_address_end = sid2_adr + 0x1f; - stereo_sid_device.end_address = sid2_adr + 0x1f; - if (stereo_sid_list_item != NULL) { - io_source_unregister(stereo_sid_list_item); - stereo_sid_list_item = io_source_register(&stereo_sid_device); - } else { - if (sid_stereo >= 1) { - stereo_sid_list_item = io_source_register(&stereo_sid_device); - } - } - return 0; - } - } - return -1; -} +#define SIDx_CHECK_RANGE(sid_nr) \ + int machine_sid##sid_nr##_check_range(unsigned int sid_adr) \ + { \ + if (machine_class == VICE_MACHINE_C128) { \ + if ((sid_adr >= 0xd400 && sid_adr <= 0xd4e0) || (sid_adr >= 0xd700 && sid_adr <= 0xdfe0)) { \ + sid##sid_nr##_address_start = sid_adr; \ + sid##sid_nr##_device.start_address = sid_adr; \ + sid##sid_nr##_address_end = sid_adr + 0x1f; \ + sid##sid_nr##_device.end_address = sid_adr + 0x1f; \ + if (sid_adr >= 0xd400 && sid_adr <= 0xd4e0) { \ + sid##sid_nr##_device.io_source_prio = IO_PRIO_HIGH; \ + } else { \ + sid##sid_nr##_device.io_source_prio = IO_PRIO_NORMAL; \ + } \ + if (sid##sid_nr##_list_item != NULL) { \ + io_source_unregister(sid##sid_nr##_list_item); \ + sid##sid_nr##_list_item = io_source_register(&sid##sid_nr##_device); \ + } else { \ + if (sid_stereo >= sid_nr - 1) { \ + sid##sid_nr##_list_item = io_source_register(&sid##sid_nr##_device); \ + } \ + } \ + return 0; \ + } \ + } else { \ + if (sid_adr >= 0xd400 && sid_adr <= 0xdfe0) { \ + sid##sid_nr##_address_start = sid_adr; \ + sid##sid_nr##_device.start_address = sid_adr; \ + sid##sid_nr##_address_end = sid_adr + 0x1f; \ + sid##sid_nr##_device.end_address = sid_adr + 0x1f; \ + if (sid_adr >= 0xd400 && sid_adr <= 0xd7e0) { \ + sid##sid_nr##_device.io_source_prio = IO_PRIO_HIGH; \ + } else { \ + sid##sid_nr##_device.io_source_prio = IO_PRIO_NORMAL; \ + } \ + if (sid##sid_nr##_list_item != NULL) { \ + io_source_unregister(sid##sid_nr##_list_item); \ + sid##sid_nr##_list_item = io_source_register(&sid##sid_nr##_device); \ + } else { \ + if (sid_stereo >= sid_nr - 1) { \ + sid##sid_nr##_list_item = io_source_register(&sid##sid_nr##_device); \ + } \ + } \ + return 0; \ + } \ + } \ + return -1; \ + } -int machine_sid3_check_range(unsigned int sid3_adr) -{ - if (machine_class == VICE_MACHINE_C128) { - if ((sid3_adr >= 0xd400 && sid3_adr <= 0xd4e0) || (sid3_adr >= 0xd700 && sid3_adr <= 0xdfe0)) { - sid_triple_address_start = sid3_adr; - triple_sid_device.start_address = sid3_adr; - sid_triple_address_end = sid3_adr + 0x1f; - triple_sid_device.end_address = sid3_adr + 0x1f; - if (triple_sid_list_item != NULL) { - io_source_unregister(triple_sid_list_item); - triple_sid_list_item = io_source_register(&triple_sid_device); - } else { - if (sid_stereo >= 2) { - triple_sid_list_item = io_source_register(&triple_sid_device); - } - } - return 0; - } - } else { - if (sid3_adr >= 0xd400 && sid3_adr <= 0xdfe0) { - sid_triple_address_start = sid3_adr; - triple_sid_device.start_address = sid3_adr; - sid_triple_address_end = sid3_adr + 0x1f; - triple_sid_device.end_address = sid3_adr + 0x1f; - if (triple_sid_list_item != NULL) { - io_source_unregister(triple_sid_list_item); - triple_sid_list_item = io_source_register(&triple_sid_device); - } else { - if (sid_stereo >= 2) { - triple_sid_list_item = io_source_register(&triple_sid_device); - } - } - return 0; - } - } - return -1; -} +SIDx_CHECK_RANGE(2) +SIDx_CHECK_RANGE(3) +SIDx_CHECK_RANGE(4) +SIDx_CHECK_RANGE(5) +SIDx_CHECK_RANGE(6) +SIDx_CHECK_RANGE(7) +SIDx_CHECK_RANGE(8) void machine_sid2_enable(int val) { - if (stereo_sid_list_item != NULL) { - io_source_unregister(stereo_sid_list_item); - stereo_sid_list_item = NULL; + if (sid2_list_item != NULL) { + io_source_unregister(sid2_list_item); + sid2_list_item = NULL; + } + if (sid3_list_item != NULL) { + io_source_unregister(sid3_list_item); + sid3_list_item = NULL; + } + if (sid4_list_item != NULL) { + io_source_unregister(sid4_list_item); + sid4_list_item = NULL; + } + if (sid5_list_item != NULL) { + io_source_unregister(sid5_list_item); + sid5_list_item = NULL; } - if (triple_sid_list_item != NULL) { - io_source_unregister(triple_sid_list_item); - triple_sid_list_item = NULL; + if (sid6_list_item != NULL) { + io_source_unregister(sid6_list_item); + sid6_list_item = NULL; + } + if (sid7_list_item != NULL) { + io_source_unregister(sid7_list_item); + sid7_list_item = NULL; + } + if (sid8_list_item != NULL) { + io_source_unregister(sid8_list_item); + sid8_list_item = NULL; } if (val >= 1) { - stereo_sid_list_item = io_source_register(&stereo_sid_device); + sid2_list_item = io_source_register(&sid2_device); } if (val >= 2) { - triple_sid_list_item = io_source_register(&triple_sid_device); + sid3_list_item = io_source_register(&sid3_device); + } + if (val >= 3) { + sid4_list_item = io_source_register(&sid4_device); + } + if (val >= 4) { + sid5_list_item = io_source_register(&sid5_device); + } + if (val >= 5) { + sid6_list_item = io_source_register(&sid6_device); + } + if (val >= 6) { + sid7_list_item = io_source_register(&sid7_device); + } + if (val >= 7) { + sid8_list_item = io_source_register(&sid8_device); } -} -void sound_machine_prevent_clk_overflow(sound_t *psid, CLOCK sub) -{ - sid_sound_machine_prevent_clk_overflow(psid, sub); +#ifdef SOUND_SYSTEM_FLOAT + /* set stereo rendering preferences */ + switch (val) { + case 8: /* 8 SID chips, 0/2/4/6 left only, 1/3/5/7 right only */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 0; + sid_sound_mixing_spec[4].left_channel_volume = 100; + sid_sound_mixing_spec[4].right_channel_volume = 0; + sid_sound_mixing_spec[6].left_channel_volume = 100; + sid_sound_mixing_spec[6].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[3].left_channel_volume = 0; + sid_sound_mixing_spec[3].right_channel_volume = 100; + sid_sound_mixing_spec[5].left_channel_volume = 0; + sid_sound_mixing_spec[5].right_channel_volume = 100; + sid_sound_mixing_spec[7].left_channel_volume = 0; + sid_sound_mixing_spec[7].right_channel_volume = 100; + break; + case 7: /* 7 SID chips, 0/2/4 left only, 1/3/5 right only, 6 both */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 0; + sid_sound_mixing_spec[4].left_channel_volume = 100; + sid_sound_mixing_spec[4].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[3].left_channel_volume = 0; + sid_sound_mixing_spec[3].right_channel_volume = 100; + sid_sound_mixing_spec[5].left_channel_volume = 0; + sid_sound_mixing_spec[5].right_channel_volume = 100; + sid_sound_mixing_spec[6].left_channel_volume = 100; + sid_sound_mixing_spec[6].right_channel_volume = 100; + break; + case 6: /* 6 SID chips, 0/2/4 left only, 1/3/5 right only */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 0; + sid_sound_mixing_spec[4].left_channel_volume = 100; + sid_sound_mixing_spec[4].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[3].left_channel_volume = 0; + sid_sound_mixing_spec[3].right_channel_volume = 100; + sid_sound_mixing_spec[5].left_channel_volume = 0; + sid_sound_mixing_spec[5].right_channel_volume = 100; + break; + case 5: /* 5 SID chips, 0/2 left only, 1/3 right only, 4 both */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[3].left_channel_volume = 0; + sid_sound_mixing_spec[3].right_channel_volume = 100; + sid_sound_mixing_spec[4].left_channel_volume = 100; + sid_sound_mixing_spec[4].right_channel_volume = 100; + break; + case 4: /* 4 SID chips, 0/2 left only, 1/3 right only */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[3].left_channel_volume = 0; + sid_sound_mixing_spec[3].right_channel_volume = 100; + break; + case 3: /* 3 SID chips, 0 left only, 1 right only, 2 both */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + sid_sound_mixing_spec[2].left_channel_volume = 100; + sid_sound_mixing_spec[2].right_channel_volume = 100; + break; + case 2: /* 2 SID chips, 0 left only, 1 right only */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 0; + sid_sound_mixing_spec[1].left_channel_volume = 0; + sid_sound_mixing_spec[1].right_channel_volume = 100; + break; + case 1: /* 1 SID chip, mix on both */ + sid_sound_mixing_spec[0].left_channel_volume = 100; + sid_sound_mixing_spec[0].right_channel_volume = 100; + break; + } +#endif } char *sound_machine_dump_state(sound_t *psid) diff --git a/src/Emulators/vice/c64/c64video.c b/src/Emulators/vice/c64/c64video.c index 31b3bfb4..38be4ae9 100644 --- a/src/Emulators/vice/c64/c64video.c +++ b/src/Emulators/vice/c64/c64video.c @@ -32,13 +32,6 @@ #include "vicii.h" #include "video.h" - -void machine_video_init(void) -{ - video_render_2x2_init(); - video_render_pal_init(); -} - int machine_video_resources_init(void) { if (video_resources_init() < 0) { diff --git a/src/Emulators/vice/c64/cart/actionreplay.c b/src/Emulators/vice/c64/cart/actionreplay.c index 88a431e4..387c8412 100644 --- a/src/Emulators/vice/c64/cart/actionreplay.c +++ b/src/Emulators/vice/c64/cart/actionreplay.c @@ -33,14 +33,18 @@ #define CARTRIDGE_INCLUDE_SLOTMAIN_API #include "c64cartsystem.h" #undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" #include "cartio.h" #include "cartridge.h" #include "export.h" +#include "log.h" #include "monitor.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" +#include "vicii-phi1.h" /* Action Replay 4.2, 5, 6 (Hardware stayed the same) @@ -64,46 +68,53 @@ cart RAM (if enabled) or cart ROM */ +#define CART_RAM_SIZE (8 * 1024) + static int ar_active; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE actionreplay_io1_peek(WORD addr); -static void actionreplay_io1_store(WORD addr, BYTE value); -static BYTE actionreplay_io2_read(WORD addr); -static BYTE actionreplay_io2_peek(WORD addr); -static void actionreplay_io2_store(WORD addr, BYTE value); +static uint8_t actionreplay_io1_peek(uint16_t addr); +static uint8_t actionreplay_io1_read(uint16_t addr); +static void actionreplay_io1_store(uint16_t addr, uint8_t value); +static uint8_t actionreplay_io2_read(uint16_t addr); +static uint8_t actionreplay_io2_peek(uint16_t addr); +static void actionreplay_io2_store(uint16_t addr, uint8_t value); static int actionreplay_dump(void); static io_source_t action_replay_io1_device = { - CARTRIDGE_NAME_ACTION_REPLAY, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - actionreplay_io1_store, - NULL, - actionreplay_io1_peek, - actionreplay_dump, - CARTRIDGE_ACTION_REPLAY, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored by the write functions, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + actionreplay_io1_store, /* store function */ + NULL, /* NO poke function */ + actionreplay_io1_read, /* read function */ + actionreplay_io1_peek, /* peek function */ + actionreplay_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t action_replay_io2_device = { - CARTRIDGE_NAME_ACTION_REPLAY, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - actionreplay_io2_store, - actionreplay_io2_read, - actionreplay_io2_peek, - actionreplay_dump, - CARTRIDGE_ACTION_REPLAY, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored by the read/write functions, reg:$df00, mirrors:$df01-$dfff */ + 0, /* validity of the read is determined by the cartridge at read time */ + actionreplay_io2_store, /* store function */ + NULL, /* NO poke function */ + actionreplay_io2_read, /* read function */ + actionreplay_io2_peek, /* peek function */ + actionreplay_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *action_replay_io1_list_item = NULL; @@ -115,9 +126,9 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -static BYTE regvalue; +static uint8_t regvalue; -static void actionreplay_io1_store(WORD addr, BYTE value) +static void actionreplay_io1_store(uint16_t addr, uint8_t value) { unsigned int mode = 0; @@ -129,20 +140,49 @@ static void actionreplay_io1_store(WORD addr, BYTE value) if (value & 0x20) { mode |= CMODE_EXPORT_RAM; } - cart_config_changed_slotmain((BYTE)(value & 3), (BYTE)((value & 3) | (((value >> 3) & 3) << CMODE_BANK_SHIFT)), (unsigned int)(mode | CMODE_WRITE)); - if (value & 4) { ar_active = 0; } + + /* mode 0x22 is broken in the original AR, we handle it here so we can + emit a warning on access */ + if ((value & 0x23) == 0x22) { + cart_config_changed_slotmain(CMODE_8KGAME, + CMODE_8KGAME | (((value >> 3) & 3) << CMODE_BANK_SHIFT), + (unsigned int)(mode | CMODE_WRITE)); + } else { + cart_config_changed_slotmain((uint8_t)(value & 3), + (uint8_t)((value & 3) | (((value >> 3) & 3) << CMODE_BANK_SHIFT)), + (unsigned int)(mode | CMODE_WRITE)); + } + + } +} + +static uint8_t actionreplay_io1_read(uint16_t addr) +{ + uint8_t value; + /* the read is really never valid */ + action_replay_io1_device.io_source_valid = 0; + if (!ar_active) { + return 0; } + /* since the r/w line is not decoded, a read still changes the register, + to whatever was on the bus before */ + value = vicii_read_phi1(); + actionreplay_io1_store(addr, value); + log_warning(LOG_DEFAULT, "AR5: reading IO1 area at 0xde%02x, this corrupts the register", + addr & 0xffu); + + return value; } -static BYTE actionreplay_io1_peek(WORD addr) +static uint8_t actionreplay_io1_peek(uint16_t addr) { return regvalue; } -static BYTE actionreplay_io2_read(WORD addr) +static uint8_t actionreplay_io2_read(uint16_t addr) { action_replay_io2_device.io_source_valid = 0; @@ -174,7 +214,7 @@ static BYTE actionreplay_io2_read(WORD addr) return 0; } -static BYTE actionreplay_io2_peek(WORD addr) +static uint8_t actionreplay_io2_peek(uint16_t addr) { if (!ar_active) { return 0; @@ -200,7 +240,7 @@ static BYTE actionreplay_io2_peek(WORD addr) return 0; } -static void actionreplay_io2_store(WORD addr, BYTE value) +static void actionreplay_io2_store(uint16_t addr, uint8_t value) { if (ar_active) { if (export_ram) { @@ -214,7 +254,7 @@ static int actionreplay_dump(void) mon_out("EXROM line: %s, GAME line: %s, Mode: %s\n", (regvalue & 2) ? "high" : "low", (regvalue & 1) ? "low" : "high", - cart_config_string((BYTE)(regvalue & 3))); + cart_config_string((uint8_t)(regvalue & 3))); mon_out("ROM bank: %d, cart state: %s, reset freeze: %s\n", (regvalue & 0x18) >> 3, (regvalue & 4) ? "disabled" : "enabled", @@ -228,16 +268,24 @@ static int actionreplay_dump(void) /* ---------------------------------------------------------------------*/ -BYTE actionreplay_roml_read(WORD addr) +uint8_t actionreplay_roml_read(uint16_t addr) { + if ((regvalue & 0x23) == 0x22) { + log_warning(LOG_DEFAULT, + "AR5: reading ROML area at 0x%04x in mode $22, this causes bus contention,", addr); + log_warning(LOG_DEFAULT, + " is unreliable, and may damage the hardware - do not do this!"); + /* in mode 0x22 both C64 and cartridge RAM is selected */ + return mem_read_without_ultimax(addr) | export_ram0[addr & 0x1fff]; + } + if (export_ram) { return export_ram0[addr & 0x1fff]; } - return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } -void actionreplay_roml_store(WORD addr, BYTE value) +void actionreplay_roml_store(uint16_t addr, uint8_t value) { if (export_ram) { export_ram0[addr & 0x1fff] = value; @@ -246,24 +294,45 @@ void actionreplay_roml_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void actionreplay_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void actionreplay_freeze(void) { ar_active = 1; - cart_config_changed_slotmain(3, 3, CMODE_READ | CMODE_EXPORT_RAM); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ | CMODE_EXPORT_RAM); } void actionreplay_config_init(void) { ar_active = 1; - cart_config_changed_slotmain(0, 0, CMODE_READ); + regvalue = 0; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } void actionreplay_reset(void) { ar_active = 1; + regvalue = 0; } -void actionreplay_config_setup(BYTE *rawcart) +void actionreplay_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x8000); memcpy(romh_banks, rawcart, 0x8000); @@ -284,7 +353,7 @@ static int actionreplay_common_attach(void) return 0; } -int actionreplay_bin_attach(const char *filename, BYTE *rawcart) +int actionreplay_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -293,7 +362,7 @@ int actionreplay_bin_attach(const char *filename, BYTE *rawcart) return actionreplay_common_attach(); } -int actionreplay_crt_attach(FILE *fd, BYTE *rawcart) +int actionreplay_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -336,7 +405,7 @@ void actionreplay_detach(void) ARRAY | RAM | 8192 BYES of RAM data */ -static char snap_module_name[] = "CARTAR"; +static const char snap_module_name[] = "CARTAR"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -351,7 +420,7 @@ int actionreplay_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ar_active) < 0) + || (SMW_B(m, (uint8_t)ar_active) < 0) || (SMW_BA(m, roml_banks, 0x8000) < 0) || (SMW_BA(m, romh_banks, 0x8000) < 0) || (SMW_BA(m, export_ram0, 0x2000) < 0)) { @@ -365,7 +434,7 @@ int actionreplay_snapshot_write_module(snapshot_t *s) int actionreplay_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -375,7 +444,7 @@ int actionreplay_snapshot_read_module(snapshot_t *s) } /* Do not accept higher versions than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/actionreplay.h b/src/Emulators/vice/c64/cart/actionreplay.h index 8841cd47..995fc458 100644 --- a/src/Emulators/vice/c64/cart/actionreplay.h +++ b/src/Emulators/vice/c64/cart/actionreplay.h @@ -31,21 +31,22 @@ #include "vicetypes.h" -extern BYTE actionreplay_roml_read(WORD addr); -extern void actionreplay_roml_store(WORD addr, BYTE value); +uint8_t actionreplay_roml_read(uint16_t addr); +void actionreplay_roml_store(uint16_t addr, uint8_t value); -extern void actionreplay_freeze(void); +void actionreplay_freeze(void); -extern void actionreplay_config_init(void); -extern void actionreplay_reset(void); -extern void actionreplay_config_setup(BYTE *rawcart); -extern int actionreplay_bin_attach(const char *filename, BYTE *rawcart); -extern int actionreplay_crt_attach(FILE *fd, BYTE *rawcart); -extern void actionreplay_detach(void); +void actionreplay_config_init(void); +void actionreplay_reset(void); +void actionreplay_config_setup(uint8_t *rawcart); +int actionreplay_bin_attach(const char *filename, uint8_t *rawcart); +int actionreplay_crt_attach(FILE *fd, uint8_t *rawcart); +void actionreplay_detach(void); +void actionreplay_powerup(void); struct snapshot_s; -extern int actionreplay_snapshot_write_module(struct snapshot_s *s); -extern int actionreplay_snapshot_read_module(struct snapshot_s *s); +int actionreplay_snapshot_write_module(struct snapshot_s *s); +int actionreplay_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/actionreplay2.c b/src/Emulators/vice/c64/cart/actionreplay2.c index 92ff8294..48e91d2a 100644 --- a/src/Emulators/vice/c64/cart/actionreplay2.c +++ b/src/Emulators/vice/c64/cart/actionreplay2.c @@ -42,6 +42,8 @@ #include "util.h" #include "crt.h" +#include "actionreplay2.h" + /* FIXME: everything here is purely guesswork and doesnt quite work like it should @@ -285,41 +287,45 @@ freezer "main menu": /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE actionreplay2_io1_read(WORD addr); -static BYTE actionreplay2_io1_peek(WORD addr); -static void actionreplay2_io1_store(WORD addr, BYTE value); -static BYTE actionreplay2_io2_read(WORD addr); -static BYTE actionreplay2_io2_peek(WORD addr); -static void actionreplay2_io2_store(WORD addr, BYTE value); +static uint8_t actionreplay2_io1_read(uint16_t addr); +static uint8_t actionreplay2_io1_peek(uint16_t addr); +static void actionreplay2_io1_store(uint16_t addr, uint8_t value); +static uint8_t actionreplay2_io2_read(uint16_t addr); +static uint8_t actionreplay2_io2_peek(uint16_t addr); +static void actionreplay2_io2_store(uint16_t addr, uint8_t value); static io_source_t actionreplay2_io1_device = { - CARTRIDGE_NAME_ACTION_REPLAY2, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - actionreplay2_io1_store, - actionreplay2_io1_read, - actionreplay2_io1_peek, - NULL, /* TODO: dump */ - CARTRIDGE_ACTION_REPLAY2, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device */ + 0, /* read is never valid */ + actionreplay2_io1_store, /* store function */ + NULL, /* NO poke function */ + actionreplay2_io1_read, /* read function */ + actionreplay2_io1_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_ACTION_REPLAY2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t actionreplay2_io2_device = { - CARTRIDGE_NAME_ACTION_REPLAY2, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - actionreplay2_io2_store, - actionreplay2_io2_read, - actionreplay2_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_ACTION_REPLAY2, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device */ + 1, /* read is always valid */ + actionreplay2_io2_store, /* store function */ + NULL, /* NO poke function */ + actionreplay2_io2_read, /* read function */ + actionreplay2_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_ACTION_REPLAY2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *actionreplay2_io1_list_item = NULL; @@ -344,7 +350,7 @@ static void cap_charge(void) if (ar_cap_disable == CAPDISABLE) { ar_enabled = 0; ar_cap_enable = 0; - cart_config_changed_slotmain((BYTE)(CMODE_RAM | (roml_bank << CMODE_BANK_SHIFT)), (BYTE)(CMODE_RAM | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain((uint8_t)(CMODE_RAM | (roml_bank << CMODE_BANK_SHIFT)), (uint8_t)(CMODE_RAM | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); DBG(("disabled\n")); } } @@ -356,41 +362,41 @@ static void cap_discharge(void) if (ar_cap_enable == CAPENABLE) { roml_bank = 1; ar_enabled = 1; - cart_config_changed_slotmain((BYTE)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), (BYTE)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain((uint8_t)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), (uint8_t)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); DBG(("enabled\n")); } ar_cap_disable = 0; } -static BYTE actionreplay2_io1_read(WORD addr) +static uint8_t actionreplay2_io1_read(uint16_t addr) { cap_discharge(); return 0; } -static void actionreplay2_io1_store(WORD addr, BYTE value) +static void actionreplay2_io1_store(uint16_t addr, uint8_t value) { cap_discharge(); } -static BYTE actionreplay2_io1_peek(WORD addr) +static uint8_t actionreplay2_io1_peek(uint16_t addr) { return 0; } -static BYTE actionreplay2_io2_peek(WORD addr) +static uint8_t actionreplay2_io2_peek(uint16_t addr) { addr |= 0xdf00; return roml_banks[(addr & 0x1fff) + (1 << 13)]; } -static BYTE actionreplay2_io2_read(WORD addr) +static uint8_t actionreplay2_io2_read(uint16_t addr) { cap_charge(); return actionreplay2_io2_peek(addr); } -static void actionreplay2_io2_store(WORD addr, BYTE value) +static void actionreplay2_io2_store(uint16_t addr, uint8_t value) { cap_charge(); } @@ -398,7 +404,7 @@ static void actionreplay2_io2_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ -BYTE actionreplay2_roml_read(WORD addr) +uint8_t actionreplay2_roml_read(uint16_t addr) { if (addr < 0x9f00) { return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; @@ -408,7 +414,7 @@ BYTE actionreplay2_roml_read(WORD addr) } } -BYTE actionreplay2_romh_read(WORD addr) +uint8_t actionreplay2_romh_read(uint16_t addr) { return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } @@ -421,7 +427,7 @@ void actionreplay2_freeze(void) ar_cap_enable = 0; ar_cap_disable = 0; DBG(("freeze\n")); - cart_config_changed_slotmain((BYTE)(CMODE_ULTIMAX | (roml_bank << CMODE_BANK_SHIFT)), (BYTE)(CMODE_ULTIMAX | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain((uint8_t)(CMODE_ULTIMAX | (roml_bank << CMODE_BANK_SHIFT)), (uint8_t)(CMODE_ULTIMAX | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); cartridge_release_freeze(); } @@ -432,7 +438,7 @@ void actionreplay2_config_init(void) ar_cap_enable = 0; ar_cap_disable = 0; DBG(("config init\n")); - cart_config_changed_slotmain((BYTE)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), (BYTE)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain((uint8_t)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), (uint8_t)(CMODE_8KGAME | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); } void actionreplay2_reset(void) @@ -444,7 +450,7 @@ void actionreplay2_reset(void) DBG(("reset\n")); } -void actionreplay2_config_setup(BYTE *rawcart) +void actionreplay2_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x4000); } @@ -463,7 +469,7 @@ static int actionreplay2_common_attach(void) return 0; } -int actionreplay2_bin_attach(const char *filename, BYTE *rawcart) +int actionreplay2_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -472,7 +478,7 @@ int actionreplay2_bin_attach(const char *filename, BYTE *rawcart) return actionreplay2_common_attach(); } -int actionreplay2_crt_attach(FILE *fd, BYTE *rawcart) +int actionreplay2_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -515,7 +521,7 @@ void actionreplay2_detach(void) ARRAY | ROML | 16768 BYTES of ROML data */ -static char snap_module_name[] = "CARTAR2"; +static const char snap_module_name[] = "CARTAR2"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -530,9 +536,9 @@ int actionreplay2_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ar_enabled) < 0) - || (SMW_DW(m, (DWORD)ar_cap_enable) < 0) - || (SMW_DW(m, (DWORD)ar_cap_disable) < 0) + || (SMW_B(m, (uint8_t)ar_enabled) < 0) + || (SMW_DW(m, (uint32_t)ar_cap_enable) < 0) + || (SMW_DW(m, (uint32_t)ar_cap_disable) < 0) || (SMW_BA(m, roml_banks, 0x4000) < 0)) { snapshot_module_close(m); return -1; @@ -543,7 +549,7 @@ int actionreplay2_snapshot_write_module(snapshot_t *s) int actionreplay2_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -553,7 +559,7 @@ int actionreplay2_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/actionreplay2.h b/src/Emulators/vice/c64/cart/actionreplay2.h index 7418a825..9673cc1d 100644 --- a/src/Emulators/vice/c64/cart/actionreplay2.h +++ b/src/Emulators/vice/c64/cart/actionreplay2.h @@ -31,21 +31,21 @@ #include "vicetypes.h" -extern void actionreplay2_freeze(void); +void actionreplay2_freeze(void); -extern void actionreplay2_config_init(void); -extern void actionreplay2_reset(void); -extern void actionreplay2_config_setup(BYTE *rawcart); -extern int actionreplay2_bin_attach(const char *filename, BYTE *rawcart); -extern int actionreplay2_crt_attach(FILE *fd, BYTE *rawcart); -extern void actionreplay2_detach(void); +void actionreplay2_config_init(void); +void actionreplay2_reset(void); +void actionreplay2_config_setup(uint8_t *rawcart); +int actionreplay2_bin_attach(const char *filename, uint8_t *rawcart); +int actionreplay2_crt_attach(FILE *fd, uint8_t *rawcart); +void actionreplay2_detach(void); -extern BYTE actionreplay2_roml_read(WORD addr); -extern BYTE actionreplay2_romh_read(WORD addr); +uint8_t actionreplay2_roml_read(uint16_t addr); +uint8_t actionreplay2_romh_read(uint16_t addr); struct snapshot_s; -extern int actionreplay2_snapshot_write_module(struct snapshot_s *s); -extern int actionreplay2_snapshot_read_module(struct snapshot_s *s); +int actionreplay2_snapshot_write_module(struct snapshot_s *s); +int actionreplay2_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/actionreplay3.c b/src/Emulators/vice/c64/cart/actionreplay3.c index 6889e7a3..8c0a8dbf 100644 --- a/src/Emulators/vice/c64/cart/actionreplay3.c +++ b/src/Emulators/vice/c64/cart/actionreplay3.c @@ -43,6 +43,9 @@ #include "util.h" #include "crt.h" +#include "actionreplay3.h" + + /* Action Replay 3 @@ -70,40 +73,44 @@ static int ar_reg = 0; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE actionreplay3_io1_peek(WORD addr); -static void actionreplay3_io1_store(WORD addr, BYTE value); -static BYTE actionreplay3_io2_peek(WORD addr); -static BYTE actionreplay3_io2_read(WORD addr); +static uint8_t actionreplay3_io1_peek(uint16_t addr); +static void actionreplay3_io1_store(uint16_t addr, uint8_t value); +static uint8_t actionreplay3_io2_peek(uint16_t addr); +static uint8_t actionreplay3_io2_read(uint16_t addr); static int actionreplay3_dump(void); static io_source_t actionreplay3_io1_device = { - CARTRIDGE_NAME_ACTION_REPLAY3, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - actionreplay3_io1_store, - NULL, - actionreplay3_io1_peek, - actionreplay3_dump, - CARTRIDGE_ACTION_REPLAY3, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY3, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device */ + 0, /* read is never valid */ + actionreplay3_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + actionreplay3_io1_peek, /* peek function */ + actionreplay3_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t actionreplay3_io2_device = { - CARTRIDGE_NAME_ACTION_REPLAY3, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - NULL, - actionreplay3_io2_read, - actionreplay3_io2_peek, - actionreplay3_dump, - CARTRIDGE_ACTION_REPLAY3, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY3, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + actionreplay3_io2_read, /* read function */ + actionreplay3_io2_peek, /* peek function */ + actionreplay3_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *actionreplay3_io1_list_item = NULL; @@ -111,7 +118,7 @@ static io_source_list_t *actionreplay3_io2_list_item = NULL; /* ---------------------------------------------------------------------*/ -static void actionreplay3_io1_store(WORD addr, BYTE value) +static void actionreplay3_io1_store(uint16_t addr, uint8_t value) { int exrom, bank, conf; @@ -122,14 +129,14 @@ static void actionreplay3_io1_store(WORD addr, BYTE value) conf = (bank << CMODE_BANK_SHIFT) | ((exrom ^ 1) << 1); if (ar_active) { - cart_config_changed_slotmain((BYTE)conf, (BYTE)conf, CMODE_WRITE); + cart_config_changed_slotmain((uint8_t)conf, (uint8_t)conf, CMODE_WRITE); if (value & 4) { ar_active = 0; } } } -static BYTE actionreplay3_io2_read(WORD addr) +static uint8_t actionreplay3_io2_read(uint16_t addr) { actionreplay3_io2_device.io_source_valid = 0; @@ -153,12 +160,12 @@ static BYTE actionreplay3_io2_read(WORD addr) return 0; } -static BYTE actionreplay3_io1_peek(WORD addr) +static uint8_t actionreplay3_io1_peek(uint16_t addr) { return ar_reg; } -static BYTE actionreplay3_io2_peek(WORD addr) +static uint8_t actionreplay3_io2_peek(uint16_t addr) { if (!ar_active) { return 0; @@ -187,29 +194,30 @@ static int actionreplay3_dump(void) /* ---------------------------------------------------------------------*/ -BYTE actionreplay3_roml_read(WORD addr) +uint8_t actionreplay3_roml_read(uint16_t addr) { return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } -BYTE actionreplay3_romh_read(WORD addr) +uint8_t actionreplay3_romh_read(uint16_t addr) { return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } + /* ---------------------------------------------------------------------*/ void actionreplay3_freeze(void) { DBG(("AR3: freeze\n")); ar_active = 1; - cart_config_changed_slotmain(3, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); } void actionreplay3_config_init(void) { DBG(("AR3: config init\n")); ar_active = 1; - cart_config_changed_slotmain(0 | (1 << CMODE_BANK_SHIFT), 0 | (1 << CMODE_BANK_SHIFT), CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME | (1 << CMODE_BANK_SHIFT), CMODE_8KGAME | (1 << CMODE_BANK_SHIFT), CMODE_READ); } void actionreplay3_reset(void) @@ -218,7 +226,7 @@ void actionreplay3_reset(void) ar_active = 1; } -void actionreplay3_config_setup(BYTE *rawcart) +void actionreplay3_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x4000); cart_config_changed_slotmain(0 | (1 << CMODE_BANK_SHIFT), 0 | (1 << CMODE_BANK_SHIFT), CMODE_READ); @@ -242,7 +250,7 @@ static int actionreplay3_common_attach(void) return 0; } -int actionreplay3_bin_attach(const char *filename, BYTE *rawcart) +int actionreplay3_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -251,7 +259,7 @@ int actionreplay3_bin_attach(const char *filename, BYTE *rawcart) return actionreplay3_common_attach(); } -int actionreplay3_crt_attach(FILE *fd, BYTE *rawcart) +int actionreplay3_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -293,7 +301,7 @@ void actionreplay3_detach(void) ARRAY | ROML | 16768 BYTES of ROML data */ -static char snap_module_name[] = "CARTAR3"; +static const char snap_module_name[] = "CARTAR3"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -308,8 +316,8 @@ int actionreplay3_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ar_active) < 0) - || (SMW_B(m, (BYTE)ar_reg) < 0) + || (SMW_B(m, (uint8_t)ar_active) < 0) + || (SMW_B(m, (uint8_t)ar_reg) < 0) || (SMW_BA(m, roml_banks, 0x4000) < 0)) { snapshot_module_close(m); return -1; @@ -321,7 +329,7 @@ int actionreplay3_snapshot_write_module(snapshot_t *s) int actionreplay3_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -331,7 +339,7 @@ int actionreplay3_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/actionreplay3.h b/src/Emulators/vice/c64/cart/actionreplay3.h index afb5cf5f..2057613d 100644 --- a/src/Emulators/vice/c64/cart/actionreplay3.h +++ b/src/Emulators/vice/c64/cart/actionreplay3.h @@ -31,21 +31,21 @@ #include "vicetypes.h" -extern void actionreplay3_freeze(void); +void actionreplay3_freeze(void); -extern void actionreplay3_config_init(void); -extern void actionreplay3_reset(void); -extern void actionreplay3_config_setup(BYTE *rawcart); -extern int actionreplay3_bin_attach(const char *filename, BYTE *rawcart); -extern int actionreplay3_crt_attach(FILE *fd, BYTE *rawcart); -extern void actionreplay3_detach(void); +void actionreplay3_config_init(void); +void actionreplay3_reset(void); +void actionreplay3_config_setup(uint8_t *rawcart); +int actionreplay3_bin_attach(const char *filename, uint8_t *rawcart); +int actionreplay3_crt_attach(FILE *fd, uint8_t *rawcart); +void actionreplay3_detach(void); -extern BYTE actionreplay3_roml_read(WORD addr); -extern BYTE actionreplay3_romh_read(WORD addr); +uint8_t actionreplay3_roml_read(uint16_t addr); +uint8_t actionreplay3_romh_read(uint16_t addr); struct snapshot_s; -extern int actionreplay3_snapshot_write_module(struct snapshot_s *s); -extern int actionreplay3_snapshot_read_module(struct snapshot_s *s); +int actionreplay3_snapshot_write_module(struct snapshot_s *s); +int actionreplay3_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/actionreplay4.c b/src/Emulators/vice/c64/cart/actionreplay4.c index d6194655..2dc504c1 100644 --- a/src/Emulators/vice/c64/cart/actionreplay4.c +++ b/src/Emulators/vice/c64/cart/actionreplay4.c @@ -65,38 +65,42 @@ static int ar_active; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void actionreplay4_io1_store(WORD addr, BYTE value); -static BYTE actionreplay4_io2_read(WORD addr); +static void actionreplay4_io1_store(uint16_t addr, uint8_t value); +static uint8_t actionreplay4_io2_read(uint16_t addr); static int actionreplay4_dump(void); static io_source_t actionreplay4_io1_device = { - CARTRIDGE_NAME_ACTION_REPLAY4, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - actionreplay4_io1_store, - NULL, - NULL, /* TODO: peek */ - actionreplay4_dump, - CARTRIDGE_ACTION_REPLAY4, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY4, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, there is no read or peek function */ + actionreplay4_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* TODO: peek function */ + actionreplay4_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY4, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t actionreplay4_io2_device = { - CARTRIDGE_NAME_ACTION_REPLAY4, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - NULL, - actionreplay4_io2_read, - NULL, /* TODO: peek */ - actionreplay4_dump, - CARTRIDGE_ACTION_REPLAY4, - 0, - 0 + CARTRIDGE_NAME_ACTION_REPLAY4, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device */ + 0, /* read validity is determined by the device upon a read */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + actionreplay4_io2_read, /* read function */ + NULL, /* TODO: peek function */ + actionreplay4_dump, /* device state information dump function */ + CARTRIDGE_ACTION_REPLAY4, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *actionreplay4_io1_list_item = NULL; @@ -108,11 +112,11 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -static BYTE control_reg = 0; +static uint8_t control_reg = 0; -static void actionreplay4_io1_store(WORD addr, BYTE value) +static void actionreplay4_io1_store(uint16_t addr, uint8_t value) { - BYTE exrom, bank, conf, game, disable; + uint8_t exrom, bank, conf, game, disable; control_reg = value; @@ -124,14 +128,14 @@ static void actionreplay4_io1_store(WORD addr, BYTE value) conf = (bank << CMODE_BANK_SHIFT) | ((exrom ^ 1) << 1) | ((game ^ 1) << 0); if (ar_active) { - cart_config_changed_slotmain((BYTE)(conf & 3), conf, CMODE_WRITE); + cart_config_changed_slotmain((uint8_t)(conf & 3), conf, CMODE_WRITE); if (disable) { ar_active = 0; } } } -static BYTE actionreplay4_io2_read(WORD addr) +static uint8_t actionreplay4_io2_read(uint16_t addr) { actionreplay4_io2_device.io_source_valid = 0; @@ -176,13 +180,13 @@ static int actionreplay4_dump(void) void actionreplay4_freeze(void) { ar_active = 1; - cart_config_changed_slotmain(3, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); } void actionreplay4_config_init(void) { ar_active = 1; - cart_config_changed_slotmain(0 | (1 << CMODE_BANK_SHIFT), 0 | (1 << CMODE_BANK_SHIFT), CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME | (1 << CMODE_BANK_SHIFT), CMODE_8KGAME | (1 << CMODE_BANK_SHIFT), CMODE_READ); } void actionreplay4_reset(void) @@ -190,7 +194,7 @@ void actionreplay4_reset(void) ar_active = 1; } -void actionreplay4_config_setup(BYTE *rawcart) +void actionreplay4_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x8000); memcpy(romh_banks, rawcart, 0x8000); @@ -212,7 +216,7 @@ static int actionreplay4_common_attach(void) return 0; } -int actionreplay4_bin_attach(const char *filename, BYTE *rawcart) +int actionreplay4_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -221,7 +225,7 @@ int actionreplay4_bin_attach(const char *filename, BYTE *rawcart) return actionreplay4_common_attach(); } -int actionreplay4_crt_attach(FILE *fd, BYTE *rawcart) +int actionreplay4_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -262,7 +266,7 @@ void actionreplay4_detach(void) ARRAY | ROML | 32768 BYTES of ROML data */ -static char snap_module_name[] = "CARTAR4"; +static const char snap_module_name[] = "CARTAR4"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -277,7 +281,7 @@ int actionreplay4_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ar_active) < 0) + || (SMW_B(m, (uint8_t)ar_active) < 0) || (SMW_BA(m, roml_banks, 0x8000) < 0)) { snapshot_module_close(m); return -1; @@ -288,7 +292,7 @@ int actionreplay4_snapshot_write_module(snapshot_t *s) int actionreplay4_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -297,7 +301,7 @@ int actionreplay4_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/actionreplay4.h b/src/Emulators/vice/c64/cart/actionreplay4.h index 6b29e052..400da052 100644 --- a/src/Emulators/vice/c64/cart/actionreplay4.h +++ b/src/Emulators/vice/c64/cart/actionreplay4.h @@ -31,18 +31,18 @@ #include "vicetypes.h" -extern void actionreplay4_freeze(void); +void actionreplay4_freeze(void); -extern void actionreplay4_config_init(void); -extern void actionreplay4_reset(void); -extern void actionreplay4_config_setup(BYTE *rawcart); -extern int actionreplay4_bin_attach(const char *filename, BYTE *rawcart); -extern int actionreplay4_crt_attach(FILE *fd, BYTE *rawcart); -extern void actionreplay4_detach(void); +void actionreplay4_config_init(void); +void actionreplay4_reset(void); +void actionreplay4_config_setup(uint8_t *rawcart); +int actionreplay4_bin_attach(const char *filename, uint8_t *rawcart); +int actionreplay4_crt_attach(FILE *fd, uint8_t *rawcart); +void actionreplay4_detach(void); struct snapshot_s; -extern int actionreplay4_snapshot_write_module(struct snapshot_s *s); -extern int actionreplay4_snapshot_read_module(struct snapshot_s *s); +int actionreplay4_snapshot_write_module(struct snapshot_s *s); +int actionreplay4_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/atomicpower.c b/src/Emulators/vice/c64/cart/atomicpower.c index 9e0c94c3..c585f36c 100644 --- a/src/Emulators/vice/c64/cart/atomicpower.c +++ b/src/Emulators/vice/c64/cart/atomicpower.c @@ -38,11 +38,14 @@ #include "cartio.h" #include "cartridge.h" #include "export.h" +#include "log.h" #include "monitor.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" +#include "vicii-phi1.h" /* #define DEBUGAP */ @@ -87,6 +90,8 @@ cart RAM (if enabled) or cart ROM */ +#define CART_RAM_SIZE (8 * 1024) + /* Atomic Power RAM hack. */ static int export_ram_at_a000 = 0; static int ap_active; @@ -94,39 +99,44 @@ static int ap_active; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void atomicpower_io1_store(WORD addr, BYTE value); -static BYTE atomicpower_io2_read(WORD addr); -static void atomicpower_io2_store(WORD addr, BYTE value); +static uint8_t atomicpower_io1_read(uint16_t addr); +static void atomicpower_io1_store(uint16_t addr, uint8_t value); +static uint8_t atomicpower_io2_read(uint16_t addr); +static void atomicpower_io2_store(uint16_t addr, uint8_t value); static int atomicpower_dump(void); static io_source_t atomicpower_io1_device = { - CARTRIDGE_NAME_ATOMIC_POWER, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - atomicpower_io1_store, - NULL, - NULL, /* TODO: peek */ - atomicpower_dump, - CARTRIDGE_ATOMIC_POWER, - 0, - 0 + CARTRIDGE_NAME_ATOMIC_POWER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, there is no read or peek function */ + atomicpower_io1_store, /* store function */ + NULL, /* NO poke function */ + atomicpower_io1_read, /* read function */ + NULL, /* TODO: peek function */ + atomicpower_dump, /* device state information dump function */ + CARTRIDGE_ATOMIC_POWER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t atomicpower_io2_device = { - CARTRIDGE_NAME_ATOMIC_POWER, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - atomicpower_io2_store, - atomicpower_io2_read, - NULL, /* TODO: peek */ - atomicpower_dump, - CARTRIDGE_ATOMIC_POWER, - 0, - 0 + CARTRIDGE_NAME_ATOMIC_POWER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range of the device */ + 0, /* read validity is determined by the device upon a read */ + atomicpower_io2_store, /* store function */ + NULL, /* NO poke function */ + atomicpower_io2_read, /* read function */ + NULL, /* TODO: peek function */ + atomicpower_dump, /* device state information dump function */ + CARTRIDGE_ATOMIC_POWER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *atomicpower_io1_list_item = NULL; @@ -138,9 +148,9 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -static BYTE atomicpower_control_reg = 0; +static uint8_t atomicpower_control_reg = 0; -static void atomicpower_io1_store(WORD addr, BYTE value) +static void atomicpower_io1_store(uint16_t addr, uint8_t value) { int flags = CMODE_WRITE, bank, mode; @@ -167,11 +177,29 @@ static void atomicpower_io1_store(WORD addr, BYTE value) ap_active = 0; } - cart_config_changed_slotmain((BYTE) 2, (BYTE) (mode | (bank << CMODE_BANK_SHIFT)), flags); + cart_config_changed_slotmain((uint8_t) 2, (uint8_t) (mode | (bank << CMODE_BANK_SHIFT)), flags); + } +} + +static uint8_t atomicpower_io1_read(uint16_t addr) +{ + uint8_t value; + /* the read is really never valid */ + atomicpower_io1_device.io_source_valid = 0; + if (!ap_active) { + return 0; } + /* since the r/w line is not decoded, a read still changes the register, + to whatever was on the bus before */ + value = vicii_read_phi1(); + atomicpower_io1_store(addr, value); + log_warning(LOG_DEFAULT, "AP: reading IO1 area at 0xde%02x, this corrupts the register", + addr & 0xffu); + + return value; } -static BYTE atomicpower_io2_read(WORD addr) +static uint8_t atomicpower_io2_read(uint16_t addr) { atomicpower_io2_device.io_source_valid = 0; @@ -201,7 +229,7 @@ static BYTE atomicpower_io2_read(WORD addr) return 0; } -static void atomicpower_io2_store(WORD addr, BYTE value) +static void atomicpower_io2_store(uint16_t addr, uint8_t value) { if (ap_active) { if (export_ram || export_ram_at_a000) { @@ -215,7 +243,7 @@ static int atomicpower_dump(void) mon_out("EXROM line: %s, GAME line: %s, Mode: %s\n", (atomicpower_control_reg & 2) ? "high" : "low", (atomicpower_control_reg & 1) ? "low" : "high", - cart_config_string((BYTE)(atomicpower_control_reg & 3))); + cart_config_string((uint8_t)(atomicpower_control_reg & 3))); mon_out("ROM bank: %d, cart state: %s, reset freeze: %s\n", (atomicpower_control_reg & 0x18) >> 3, (atomicpower_control_reg & 4) ? "disabled" : "enabled", @@ -229,7 +257,7 @@ static int atomicpower_dump(void) /* ---------------------------------------------------------------------*/ -BYTE atomicpower_roml_read(WORD addr) +uint8_t atomicpower_roml_read(uint16_t addr) { if (export_ram) { return export_ram0[addr & 0x1fff]; @@ -238,14 +266,14 @@ BYTE atomicpower_roml_read(WORD addr) return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } -void atomicpower_roml_store(WORD addr, BYTE value) +void atomicpower_roml_store(uint16_t addr, uint8_t value) { if (export_ram) { export_ram0[addr & 0x1fff] = value; } } -BYTE atomicpower_romh_read(WORD addr) +uint8_t atomicpower_romh_read(uint16_t addr) { if (export_ram_at_a000) { return export_ram0[addr & 0x1fff]; @@ -253,14 +281,16 @@ BYTE atomicpower_romh_read(WORD addr) return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; } -void atomicpower_romh_store(WORD addr, BYTE value) +void atomicpower_romh_store(uint16_t addr, uint8_t value) { if (export_ram_at_a000) { export_ram0[addr & 0x1fff] = value; + } else { + mem_store_without_romlh(addr, value); } } -void atomicpower_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void atomicpower_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { /* FIXME: this is broken, code-in-ram execution from AR "acid test" fails */ #if 0 @@ -303,25 +333,46 @@ void atomicpower_mmu_translate(unsigned int addr, BYTE **base, int *start, int * /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void atomicpower_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void atomicpower_freeze(void) { ap_active = 1; - cart_config_changed_slotmain(3, 3, CMODE_READ | CMODE_EXPORT_RAM); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ | CMODE_EXPORT_RAM); } void atomicpower_config_init(void) { ap_active = 1; + atomicpower_control_reg = 0; export_ram_at_a000 = 0; - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } void atomicpower_reset(void) { ap_active = 1; + atomicpower_control_reg = 0; } -void atomicpower_config_setup(BYTE *rawcart) +void atomicpower_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x8000); memcpy(romh_banks, rawcart, 0x8000); @@ -342,7 +393,7 @@ static int atomicpower_common_attach(void) return 0; } -int atomicpower_bin_attach(const char *filename, BYTE *rawcart) +int atomicpower_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -351,7 +402,7 @@ int atomicpower_bin_attach(const char *filename, BYTE *rawcart) return atomicpower_common_attach(); } -int atomicpower_crt_attach(FILE *fd, BYTE *rawcart) +int atomicpower_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -394,7 +445,7 @@ void atomicpower_detach(void) ARRAY | RAM | 8192 BYTES of RAM data */ -static char snap_module_name[] = "CARTAP"; +static const char snap_module_name[] = "CARTAP"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -409,8 +460,8 @@ int atomicpower_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ap_active) < 0) - || (SMW_B(m, (BYTE)export_ram_at_a000) < 0) + || (SMW_B(m, (uint8_t)ap_active) < 0) + || (SMW_B(m, (uint8_t)export_ram_at_a000) < 0) || (SMW_BA(m, roml_banks, 0x8000) < 0) || (SMW_BA(m, export_ram0, 0x2000) < 0)) { snapshot_module_close(m); @@ -422,7 +473,7 @@ int atomicpower_snapshot_write_module(snapshot_t *s) int atomicpower_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -432,7 +483,7 @@ int atomicpower_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/atomicpower.h b/src/Emulators/vice/c64/cart/atomicpower.h index f5cc5903..2ad937c4 100644 --- a/src/Emulators/vice/c64/cart/atomicpower.h +++ b/src/Emulators/vice/c64/cart/atomicpower.h @@ -31,24 +31,25 @@ #include "vicetypes.h" -extern BYTE atomicpower_roml_read(WORD addr); -extern void atomicpower_roml_store(WORD addr, BYTE value); -extern BYTE atomicpower_romh_read(WORD addr); -extern void atomicpower_romh_store(WORD addr, BYTE value); -extern void atomicpower_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); - -extern void atomicpower_freeze(void); -extern void atomicpower_reset(void); - -extern void atomicpower_config_init(void); -extern void atomicpower_config_setup(BYTE *rawcart); -extern int atomicpower_bin_attach(const char *filename, BYTE *rawcart); -extern int atomicpower_crt_attach(FILE *fd, BYTE *rawcart); -extern void atomicpower_detach(void); +uint8_t atomicpower_roml_read(uint16_t addr); +void atomicpower_roml_store(uint16_t addr, uint8_t value); +uint8_t atomicpower_romh_read(uint16_t addr); +void atomicpower_romh_store(uint16_t addr, uint8_t value); +void atomicpower_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +void atomicpower_freeze(void); +void atomicpower_reset(void); +void atomicpower_powerup(void); + +void atomicpower_config_init(void); +void atomicpower_config_setup(uint8_t *rawcart); +int atomicpower_bin_attach(const char *filename, uint8_t *rawcart); +int atomicpower_crt_attach(FILE *fd, uint8_t *rawcart); +void atomicpower_detach(void); struct snapshot_s; -extern int atomicpower_snapshot_write_module(struct snapshot_s *s); -extern int atomicpower_snapshot_read_module(struct snapshot_s *s); +int atomicpower_snapshot_write_module(struct snapshot_s *s); +int atomicpower_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/bisplus.c b/src/Emulators/vice/c64/cart/bisplus.c new file mode 100644 index 00000000..422f7241 --- /dev/null +++ b/src/Emulators/vice/c64/cart/bisplus.c @@ -0,0 +1,262 @@ +/* + * bisplus.c - Cartridge handling, BIS-Plus cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "bisplus.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + "BIS-Plus" by Micro-Luc + + - 2/4/8K ROM Variants + - IO1 writes disable the cartridge ROM +*/ + +static uint8_t bis_rom_enabled = 0; +static uint8_t bis_rom_kb = 0; + +/* some prototypes are needed */ +static void bisplus_io1_store(uint16_t addr, uint8_t value); +static int bisplus_dump(void); + +static io_source_t bisplus_io1_device = { + CARTRIDGE_NAME_BISPLUS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid */ + bisplus_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + bisplus_dump, /* device state information dump function */ + CARTRIDGE_BISPLUS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *bisplus_io1_list_item = NULL; + +static const export_resource_t export_res_bis = { + CARTRIDGE_NAME_BISPLUS, 0, 1, &bisplus_io1_device, NULL, CARTRIDGE_BISPLUS +}; + +/* ---------------------------------------------------------------------*/ + +void bisplus_io1_store(uint16_t addr, uint8_t value) +{ + /* printf("io1 write %04x %02x\n", addr, value); */ + bis_rom_enabled = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); +} + +/* FIXME: Add EXROM, GAME lines to the dump */ +static int bisplus_dump(void) +{ + mon_out("ROM Size: %dKiB\n", bis_rom_kb); + mon_out("Status: %s\n", bis_rom_enabled ? "Enabled" : "Disabled"); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void bisplus_config_init(void) +{ + bis_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +void bisplus_config_setup(uint8_t *rawcart) +{ + memcpy(&roml_banks[0], &rawcart[0], 0x2000); + if (bis_rom_kb == 4) { + memcpy(&roml_banks[0x1000], &rawcart[0], 0x1000); + } + if (bis_rom_kb == 2) { + memcpy(&roml_banks[0x0800], &rawcart[0], 0x0800); + memcpy(&roml_banks[0x1000], &rawcart[0], 0x0800); + memcpy(&roml_banks[0x1800], &rawcart[0], 0x0800); + } + bis_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int bisplus_common_attach(void) +{ + if (export_add(&export_res_bis) < 0) { + return -1; + } + + bisplus_io1_list_item = io_source_register(&bisplus_io1_device); + + return 0; +} + +int bisplus_bin_attach(const char *filename, uint8_t *rawcart) +{ + bis_rom_kb = 8; + if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bis_rom_kb = 4; + if (util_file_load(filename, rawcart, 0x1000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bis_rom_kb = 2; + if (util_file_load(filename, rawcart, 0x0800, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + + return bisplus_common_attach(); +} + +int bisplus_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank > 0) { + return -1; + } + + switch (chip.size) { + case 0x2000: + bis_rom_kb = 8; + break; + case 0x1000: + bis_rom_kb = 4; + break; + case 0x0800: + bis_rom_kb = 2; + break; + default: + return -1; + break; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return bisplus_common_attach(); +} + +void bisplus_detach(void) +{ + export_remove(&export_res_bis); + io_source_unregister(bisplus_io1_list_item); + bisplus_io1_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTBB3 snapshot module format: + + type | name | version | description + ------------------------------------------- + BYTE | bis_rom_enabled | 1.0 | 1 if ROM is enabled (informal) + BYTE | bis_rom_kb | 1.0 | 2/4/8 kb ROM + ARRAY | ROML | 1.0 | 8192 of ROML data + + */ + +static const char snap_module_name[] = "CARTBB3"; +#define SNAP_MAJOR 1 +#define SNAP_MINOR 0 + +int bisplus_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, bis_rom_enabled) < 0 + || SMW_B(m, bis_rom_kb) < 0 + || SMW_BA(m, roml_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int bisplus_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B(m, &bis_rom_enabled) < 0 + || SMR_B(m, &bis_rom_kb) < 0 + || SMR_BA(m, roml_banks, 0x2000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return bisplus_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/bisplus.h b/src/Emulators/vice/c64/cart/bisplus.h new file mode 100644 index 00000000..343896d5 --- /dev/null +++ b/src/Emulators/vice/c64/cart/bisplus.h @@ -0,0 +1,45 @@ +/* + * bisplus.h - Cartridge handling, BIS-Plus cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BISPLUS_H +#define VICE_BISPLUS_H + +#include + +#include "vicetypes.h" + +void bisplus_config_init(void); +void bisplus_config_setup(uint8_t *rawcart); +int bisplus_bin_attach(const char *filename, uint8_t *rawcart); +int bisplus_crt_attach(FILE *fd, uint8_t *rawcart); +void bisplus_detach(void); + +struct snapshot_s; + +int bisplus_snapshot_write_module(struct snapshot_s *s); +int bisplus_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/blackbox3.c b/src/Emulators/vice/c64/cart/blackbox3.c new file mode 100644 index 00000000..85ac52c7 --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox3.c @@ -0,0 +1,258 @@ +/* + * blackbox3.c - Cartridge handling, Blackbox V3 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "blackbox3.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + Blackbox V3 + + - 8k ROM (2764) + - IO1 accesses disable the cartridge ROM (writes only?) + - IO2 accesses enable the cartridge ROM (writes only?) +*/ + +static uint8_t bb3_rom_enabled = 0; + +/* some prototypes are needed */ +static void blackbox3_io1_store(uint16_t addr, uint8_t value); +static void blackbox3_io2_store(uint16_t addr, uint8_t value); +static int blackbox3_dump(void); + +static io_source_t blackbox3_io1_device = { + CARTRIDGE_NAME_BLACKBOX3, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid */ + blackbox3_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + blackbox3_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t blackbox3_io2_device = { + CARTRIDGE_NAME_BLACKBOX3, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is always valid */ + blackbox3_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + blackbox3_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *blackbox3_io1_list_item = NULL; +static io_source_list_t *blackbox3_io2_list_item = NULL; + +static const export_resource_t export_res_v3 = { + CARTRIDGE_NAME_BLACKBOX3, 0, 1, &blackbox3_io1_device, &blackbox3_io2_device, CARTRIDGE_BLACKBOX3 +}; + +/* ---------------------------------------------------------------------*/ + +void blackbox3_io1_store(uint16_t addr, uint8_t value) +{ + /* printf("io1 write %04x %02x\n", addr, value); */ + bb3_rom_enabled = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); +} + +void blackbox3_io2_store(uint16_t addr, uint8_t value) +{ + /* printf("io2 write %04x %02x\n", addr, value); */ + bb3_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + +} + +/* FIXME: Add EXROM, GAME lines to the dump */ +static int blackbox3_dump(void) +{ + mon_out("Status: %s\n", bb3_rom_enabled ? "Enabled" : "Disabled"); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void blackbox3_config_init(void) +{ + bb3_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +void blackbox3_config_setup(uint8_t *rawcart) +{ + memcpy(&roml_banks[0], &rawcart[0x0000], 0x2000); + bb3_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int blackbox3_common_attach(void) +{ + if (export_add(&export_res_v3) < 0) { + return -1; + } + + blackbox3_io1_list_item = io_source_register(&blackbox3_io1_device); + blackbox3_io2_list_item = io_source_register(&blackbox3_io2_device); + + return 0; +} + +int blackbox3_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return blackbox3_common_attach(); +} + +int blackbox3_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank > 0 || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return blackbox3_common_attach(); +} + +void blackbox3_detach(void) +{ + export_remove(&export_res_v3); + io_source_unregister(blackbox3_io1_list_item); + io_source_unregister(blackbox3_io2_list_item); + blackbox3_io1_list_item = NULL; + blackbox3_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTBB3 snapshot module format: + + type | name | version | description + ------------------------------------------- + BYTE | bb3_rom_enabled | 1.0 | 1 if ROM is enabled (informal) + ARRAY | ROML | 1.0 | 8192 of ROML data + + */ + +static const char snap_module_name[] = "CARTBB3"; +#define SNAP_MAJOR 1 +#define SNAP_MINOR 0 + +int blackbox3_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, bb3_rom_enabled) < 0 + || SMW_BA(m, roml_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int blackbox3_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B(m, &bb3_rom_enabled) < 0 + || SMR_BA(m, roml_banks, 0x2000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return blackbox3_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/blackbox3.h b/src/Emulators/vice/c64/cart/blackbox3.h new file mode 100644 index 00000000..7c560f91 --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox3.h @@ -0,0 +1,45 @@ +/* + * blackbox3.h - Cartridge handling, Blackbox V3 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BLACKBOX3_H +#define VICE_BLACKBOX3_H + +#include + +#include "vicetypes.h" + +void blackbox3_config_init(void); +void blackbox3_config_setup(uint8_t *rawcart); +int blackbox3_bin_attach(const char *filename, uint8_t *rawcart); +int blackbox3_crt_attach(FILE *fd, uint8_t *rawcart); +void blackbox3_detach(void); + +struct snapshot_s; + +int blackbox3_snapshot_write_module(struct snapshot_s *s); +int blackbox3_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/blackbox4.c b/src/Emulators/vice/c64/cart/blackbox4.c new file mode 100644 index 00000000..75c7fbea --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox4.c @@ -0,0 +1,263 @@ +/* + * blackbox4.c - Cartridge handling, Blackbox V4 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "blackbox4.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + Blackbox V4 + + - 16k ROM + - IO1 accesses enable the cartridge ROM (reads only?) + - IO2 accesses disable the cartridge ROM (reads only?) +*/ + +static uint8_t bb4_rom_enabled = 0; + +/* some prototypes are needed */ +static uint8_t blackbox4_io1_read(uint16_t addr); +static uint8_t blackbox4_io2_read(uint16_t addr); +static int blackbox4_dump(void); + +static io_source_t blackbox4_io1_device = { + CARTRIDGE_NAME_BLACKBOX4, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + blackbox4_io1_read, /* read function */ + blackbox4_io1_read, /* peek function */ + blackbox4_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX4, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t blackbox4_io2_device = { + CARTRIDGE_NAME_BLACKBOX4, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + blackbox4_io2_read, /* read function */ + blackbox4_io2_read, /* peek function */ + blackbox4_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX4, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *blackbox4_io1_list_item = NULL; +static io_source_list_t *blackbox4_io2_list_item = NULL; + +static const export_resource_t export_res_v3 = { + CARTRIDGE_NAME_BLACKBOX4, 1, 1, &blackbox4_io1_device, &blackbox4_io2_device, CARTRIDGE_BLACKBOX4 +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t blackbox4_io1_read(uint16_t addr) +{ + /* printf("io1 read %04x\n", addr); */ + bb4_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + return 0; +} + +uint8_t blackbox4_io2_read(uint16_t addr) +{ + /* printf("io2 read %04x\n", addr); */ + bb4_rom_enabled = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + return 0; +} + +/* FIXME: Add EXROM, GAME lines to the dump */ +static int blackbox4_dump(void) +{ + mon_out("Status: %s\n", bb4_rom_enabled ? "Enabled" : "Disabled"); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void blackbox4_config_init(void) +{ + bb4_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +void blackbox4_config_setup(uint8_t *rawcart) +{ + memcpy(&roml_banks[0], &rawcart[0x0000], 0x2000); + memcpy(&romh_banks[0], &rawcart[0x2000], 0x2000); + bb4_rom_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int blackbox4_common_attach(void) +{ + if (export_add(&export_res_v3) < 0) { + return -1; + } + + blackbox4_io1_list_item = io_source_register(&blackbox4_io1_device); + blackbox4_io2_list_item = io_source_register(&blackbox4_io2_device); + + return 0; +} + +int blackbox4_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return blackbox4_common_attach(); +} + +int blackbox4_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank > 0 || chip.size != 0x4000) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return blackbox4_common_attach(); +} + +void blackbox4_detach(void) +{ + export_remove(&export_res_v3); + io_source_unregister(blackbox4_io1_list_item); + io_source_unregister(blackbox4_io2_list_item); + blackbox4_io1_list_item = NULL; + blackbox4_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTBB4 snapshot module format: + + type | name | version | description + ------------------------------------------- + BYTE | bb4_rom_enabled | 1.0 | 1 if ROM is enabled (informal) + ARRAY | ROML | 1.0 | 8192 of ROML data + ARRAY | ROMH | 1.0 | 8192 of ROMH data + + */ + +static const char snap_module_name[] = "CARTBB4"; +#define SNAP_MAJOR 1 +#define SNAP_MINOR 0 + +int blackbox4_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, bb4_rom_enabled) < 0 + || SMW_BA(m, roml_banks, 0x2000) < 0 + || SMW_BA(m, romh_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int blackbox4_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B(m, &bb4_rom_enabled) < 0 + || SMR_BA(m, roml_banks, 0x2000) < 0 + || SMR_BA(m, romh_banks, 0x2000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return blackbox4_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/blackbox4.h b/src/Emulators/vice/c64/cart/blackbox4.h new file mode 100644 index 00000000..dd8afa30 --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox4.h @@ -0,0 +1,45 @@ +/* + * blackbox4.h - Cartridge handling, Blackbox V4 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BLACKBOX4_H +#define VICE_BLACKBOX4_H + +#include + +#include "vicetypes.h" + +void blackbox4_config_init(void); +void blackbox4_config_setup(uint8_t *rawcart); +int blackbox4_bin_attach(const char *filename, uint8_t *rawcart); +int blackbox4_crt_attach(FILE *fd, uint8_t *rawcart); +void blackbox4_detach(void); + +struct snapshot_s; + +int blackbox4_snapshot_write_module(struct snapshot_s *s); +int blackbox4_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/blackbox8.c b/src/Emulators/vice/c64/cart/blackbox8.c new file mode 100644 index 00000000..7ca9140b --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox8.c @@ -0,0 +1,270 @@ +/* + * blackbox8.c - Cartridge handling, Blackbox v8 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "blackbox8.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + Black Box V8 + + 32k or 64k, 2 or 4 16K banks + + writing to IO2 sets the cartridge config: + A0 - EXROM + A1 - GAME + A2 - bank lsb + A3 - bank msb +*/ + +static int bb8_rom_banks = 4; +static uint8_t regval = 0; + +/* some prototypes are needed */ +static void blackbox8_io2_store(uint16_t addr, uint8_t value); +static int blackbox8_dump(void); + +static io_source_t final3_io2_device = { + CARTRIDGE_NAME_BLACKBOX8, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + blackbox8_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + blackbox8_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX8, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *final3_io2_list_item = NULL; + +static const export_resource_t export_res_v3 = { + CARTRIDGE_NAME_BLACKBOX8, 1, 1, NULL, &final3_io2_device, CARTRIDGE_BLACKBOX8 +}; + +/* ---------------------------------------------------------------------*/ + +void blackbox8_io2_store(uint16_t addr, uint8_t value) +{ + uint8_t mode, bank; + + regval = addr & 0x0f; + + /* printf("io2 write %04x %02x\n", addr, value); */ + mode = (addr & 3) ^ 1; + bank = ((addr >> 2) & 3) ^ 3; + bank &= (bb8_rom_banks - 1); + roml_bank = romh_bank = bank; + /* printf("switch to mode: %s bank: %d\n", cart_config_string(mode), bank); */ + cart_config_changed_slotmain(mode, mode | (bank << CMODE_BANK_SHIFT), CMODE_WRITE); +} + +static int blackbox8_dump(void) +{ + mon_out("Bank: %d of %d, mode: %s\n", + ((regval >> 2) ^ 3) & (bb8_rom_banks - 1), bb8_rom_banks, + cart_config_string((regval & 3) ^ 1)); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void blackbox8_config_init(void) +{ + roml_bank = romh_bank = (bb8_rom_banks - 1); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME | (roml_bank << CMODE_BANK_SHIFT), CMODE_READ); +} + +void blackbox8_config_setup(uint8_t *rawcart) +{ + int i; + for (i = 0; i <= bb8_rom_banks; i++) { + memcpy(&roml_banks[0x2000 * i], &rawcart[0x0000 + (0x4000 * i)], 0x2000); + memcpy(&romh_banks[0x2000 * i], &rawcart[0x2000 + (0x4000 * i)], 0x2000); + } + roml_bank = romh_bank = (bb8_rom_banks - 1); + + /* FIXME: Triggers false positive with the static analyzer: + * "The result of the left shift is undefined because the left + * operand is negative" + */ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME | (roml_bank << CMODE_BANK_SHIFT), CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int blackbox8_common_attach(void) +{ + if (export_add(&export_res_v3) < 0) { + return -1; + } + + final3_io2_list_item = io_source_register(&final3_io2_device); + + return 0; +} + +int blackbox8_bin_attach(const char *filename, uint8_t *rawcart) +{ + bb8_rom_banks = 2; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + bb8_rom_banks = 4; + } + + return blackbox8_common_attach(); +} + +int blackbox8_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i, banks = 0; + + for (i = 0; i <= 4; i++) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.bank > 4 || chip.size != 0x4000) { + break; + } + + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + break; + } + ++banks; + } + + if ((banks != 2) && (banks != 4)) { + return -1; + } + bb8_rom_banks = banks; + + return blackbox8_common_attach(); +} + +void blackbox8_detach(void) +{ + export_remove(&export_res_v3); + io_source_unregister(final3_io2_list_item); + final3_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTBB8 snapshot module format: + + type | name | version | description + ------------------------------------------- + BYTE | ROML banks | 1.1 | amount of ROML banks + BYTE | register | 1.1 | register + ARRAY | ROML | 1.1 | 32768 or 65536 BYTES of ROML data + ARRAY | ROMH | 1.1 | 32768 or 65536 BYTES of ROML data + + */ + +static const char snap_module_name[] = "CARTBB8"; +#define SNAP_MAJOR 1 +#define SNAP_MINOR 1 + +int blackbox8_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)bb8_rom_banks) < 0 + || SMW_B(m, regval) < 0 + || SMW_BA(m, roml_banks, 0x2000 * bb8_rom_banks) < 0 + || SMW_BA(m, romh_banks, 0x2000 * bb8_rom_banks) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int blackbox8_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B_INT(m, &bb8_rom_banks) < 0 + || SMR_B(m, ®val) < 0 + || SMR_BA(m, roml_banks, 0x2000 * bb8_rom_banks) < 0 + || SMR_BA(m, romh_banks, 0x2000 * bb8_rom_banks) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return blackbox8_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/blackbox8.h b/src/Emulators/vice/c64/cart/blackbox8.h new file mode 100644 index 00000000..2be75633 --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox8.h @@ -0,0 +1,46 @@ +/* + * blackbox8.h - Cartridge handling, Blackbox v8 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BLACKBOX8_H +#define VICE_BLACKBOX8_H + +#include + +#include "vicetypes.h" + +void blackbox8_freeze(void); +void blackbox8_config_init(void); +void blackbox8_config_setup(uint8_t *rawcart); +int blackbox8_bin_attach(const char *filename, uint8_t *rawcart); +int blackbox8_crt_attach(FILE *fd, uint8_t *rawcart); +void blackbox8_detach(void); + +struct snapshot_s; + +int blackbox8_snapshot_write_module(struct snapshot_s *s); +int blackbox8_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/blackbox9.c b/src/Emulators/vice/c64/cart/blackbox9.c new file mode 100644 index 00000000..1ddd8f9a --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox9.c @@ -0,0 +1,311 @@ +/* + * blackbox9.c - Cartridge handling, Black BOX 9 cart. + * + * Written by + * Kamil Zbrog + * Based on code written by + * Artur Sidor + * Based on code from VICE written by + * ALeX Kazik + * Marco van den Heuvel + * Andreas Boose + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "blackbox9.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "log.h" +#include "vicii-phi1.h" + +/* + Black BOX 9 + + - 32k ROM, 2*16k (16K Game mode) + - starts from bank 1 in ultimax mode + - cart ROM mirror is visible in IO1 + + A register is mapped to IO1, which is changed by accessing an address in + the IO space, the address bits are mapped like this: + + bit 7 - bank (inverted on write) + bit 6 - exrom + bit 0 - game + + GUESS: The register will be disabled (until reset) when the following + conditions are met: + + - read from io1 + - addr bit 7 is 0 + - addr bit 6 is 1 + - addr bit 0 is 1 +*/ + +/* #define BB9DEBUG */ + +#ifdef BB9DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* some prototypes are needed */ +static uint8_t blackbox9_io1_peek(uint16_t addr); +static uint8_t blackbox9_io1_read(uint16_t addr); +static void blackbox9_io1_store(uint16_t addr, uint8_t); +static int blackbox9_dump(void); + +static io_source_t io1_device = { + CARTRIDGE_NAME_BLACKBOX9, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + blackbox9_io1_store, /* store function */ + NULL, /* NO poke function */ + blackbox9_io1_read, /* read function */ + blackbox9_io1_peek, /* peek function */ + blackbox9_dump, /* device state information dump function */ + CARTRIDGE_BLACKBOX9, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *io1_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_BLACKBOX9, 1, 1, &io1_device, NULL, CARTRIDGE_BLACKBOX9 +}; + +/* ---------------------------------------------------------------------*/ + +static int currbank = 0; +static int currmode = 0; +static int cart_enabled = 0; + +static uint8_t blackbox9_io1_peek(uint16_t addr) +{ + return roml_banks[0x1e00 + (roml_bank << 13) + (addr & 0xff)]; +} + +static uint8_t blackbox9_io1_read(uint16_t addr) +{ + if (cart_enabled) { + currbank = (addr >> 7) & 1; + currmode = ((addr >> 5) & 2) | ((addr & 1) ^ 1); + /* weird hack to prevent ultimax mode in the powerup screen */ + if ((currmode == CMODE_ULTIMAX) && ((addr & 0x40) == 0x40) && ((addr & 0x01) == 0x00)) { + DBG(("ultimax mode ignored")); + } else { + cart_config_changed_slotmain(CMODE_RAM, (currbank << CMODE_BANK_SHIFT) | currmode, CMODE_READ); + } + if (addr == 0x41) { + cart_enabled = 0; + DBG(("disabling cart")); + } +#if 0 + if ((addr != 0x41) && ((currbank == 0) && (currmode == 3))) { + DBG(("IO1 read %04x value:%02x bank:%d mode:%d", + addr, roml_banks[0x1e00 + (roml_bank << 13) + (addr & 0xff)], currbank, currmode)); + } +#endif + return roml_banks[0x1e00 + (roml_bank << 13) + (addr & 0xff)]; + } + return vicii_read_phi1(); +} + +void blackbox9_io1_store(uint16_t addr, uint8_t val) +{ + if (cart_enabled) { + currbank = ((addr >> 7) & 1) ^ 1; + currmode = ((addr >> 5) & 2) | ((addr & 1) ^ 1); + DBG(("IO1 store %04x val:%02x bank:%d mode:%d", addr, val, currbank, currmode)); + cart_config_changed_slotmain(CMODE_RAM, (currbank << CMODE_BANK_SHIFT) | currmode, CMODE_WRITE); + } +} + +static int blackbox9_dump(void) +{ + mon_out("current mode: %s\n", cart_config_string(currmode)); + mon_out("IO at $DE00-$DEFF: %s\n", cart_enabled ? "enabled" : "disabled"); + mon_out("ROM at $8000-$BFFF: %s\n", (currmode != CMODE_RAM) ? "enabled" : "disabled"); + mon_out("ROM bank: %d\n", currbank); + return 0; +} + +/* ---------------------------------------------------------------------*/ +void blackbox9_config_init(void) +{ + DBG(("blackbox9_config_init")); + currmode = CMODE_ULTIMAX; + currbank = 1; + cart_enabled = 1; + cart_config_changed_slotmain(CMODE_RAM, currmode | 1 << CMODE_BANK_SHIFT, CMODE_READ); +} + +void blackbox9_config_setup(uint8_t *rawcart) +{ + int i; + DBG(("blackbox9_config_setup")); + for (i = 0; i <= 2; i++) { + memcpy(&roml_banks[0x2000 * i], &rawcart[0x0000 + (0x4000 * i)], 0x2000); + memcpy(&romh_banks[0x2000 * i], &rawcart[0x2000 + (0x4000 * i)], 0x2000); + } + + currmode = CMODE_ULTIMAX; + currbank = 1; + cart_enabled = 1; + cart_config_changed_slotmain(CMODE_RAM, currmode | 1 << CMODE_BANK_SHIFT, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int blackbox9_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + io1_list_item = io_source_register(&io1_device); + return 0; +} + +int blackbox9_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return blackbox9_common_attach(); +} + +int blackbox9_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i, banks = 0; + + for (i = 0; i <= 2; i++) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.bank > 2 || chip.size != 0x4000) { + break; + } + + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + break; + } + ++banks; + } + + if (banks != 2) { + return -1; + } + + return blackbox9_common_attach(); +} + +void blackbox9_detach(void) +{ + export_remove(&export_res); + io_source_unregister(io1_list_item); + io1_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +static const char snap_module_name[] = "CARTBLACKBOX9"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int blackbox9_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)currmode) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) + || (SMW_BA(m, roml_banks, 0x2000) < 0) + || (SMW_BA(m, romh_banks, 0x2000) < 0)) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int blackbox9_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_B_INT(m, &currmode) < 0) + || (SMR_B_INT(m, &currbank) < 0) + || (SMR_BA(m, roml_banks, 0x2000) < 0) + || (SMR_BA(m, romh_banks, 0x2000) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + return blackbox9_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/blackbox9.h b/src/Emulators/vice/c64/cart/blackbox9.h new file mode 100644 index 00000000..ab3e6257 --- /dev/null +++ b/src/Emulators/vice/c64/cart/blackbox9.h @@ -0,0 +1,46 @@ +/* + * blackbox9.h - Cartridge handling, Black BOX 9 cart. + * + * based on word written by + * Andreas Boose + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BLACKBOX9_H +#define VICE_BLACKBOX9_H + +#include + +#include "vicetypes.h" + +void blackbox9_config_init(void); +void blackbox9_config_setup(uint8_t *rawcart); +int blackbox9_bin_attach(const char *filename, uint8_t *rawcart); +int blackbox9_crt_attach(FILE *fd, uint8_t *rawcart); +void blackbox9_detach(void); + +struct snapshot_s; + +int blackbox9_snapshot_write_module(struct snapshot_s *s); +int blackbox9_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/bmpdataturbo.c b/src/Emulators/vice/c64/cart/bmpdataturbo.c new file mode 100644 index 00000000..393054a6 --- /dev/null +++ b/src/Emulators/vice/c64/cart/bmpdataturbo.c @@ -0,0 +1,287 @@ +/* + * bmpdataturbo.c - Cartridge handling, BMP Data Turbo 2000 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define DEBUG_BMPDATATURBO */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "bmpdataturbo.h" +#include "crt.h" +#include "log.h" + +#ifdef DEBUG_BMPDATATURBO +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* + BMP Data Turbo 2000 + + - 16k ROM + - uses full io1/io2 + + io1 + - write: enable rom at 8000 + + io2 + - write: disable rom at 8000 + +*/ + +/* some prototypes are needed */ +static void bmpdataturbo_io1_store(uint16_t addr, uint8_t value); +static void bmpdataturbo_io2_store(uint16_t addr, uint8_t value); +static int bmpdataturbo_dump(void); + +static io_source_t bmpdataturbo_io1_device = { + CARTRIDGE_NAME_BMPDATATURBO, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid */ + bmpdataturbo_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + bmpdataturbo_dump, /* device state information dump function */ + CARTRIDGE_BMPDATATURBO, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t bmpdataturbo_io2_device = { + CARTRIDGE_NAME_BMPDATATURBO, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is never valid */ + bmpdataturbo_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + bmpdataturbo_dump, /* device state information dump function */ + CARTRIDGE_BMPDATATURBO, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *bmpdataturbo_io1_list_item = NULL; +static io_source_list_t *bmpdataturbo_io2_list_item = NULL; + +/* ---------------------------------------------------------------------*/ + +static int bmpdataturbo_enabled = 0; + +static void bmpdataturbo_io1_store(uint16_t addr, uint8_t value) +{ + bmpdataturbo_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + DBG(("bmpdataturbo_io1_store de%02x %02x (%s)", + addr, value, bmpdataturbo_enabled ? "enabled" : "disabled")); +} + +static void bmpdataturbo_io2_store(uint16_t addr, uint8_t value) +{ + bmpdataturbo_enabled = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_RAM); + DBG(("bmpdataturbo_io2_store df%02x %02x (%s)", + addr, value, bmpdataturbo_enabled ? "enabled" : "disabled")); +} + +static int bmpdataturbo_dump(void) +{ + mon_out("$8000-$9FFF ROM: %s\n", (bmpdataturbo_enabled) ? "enabled" : "disabled"); + + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static const export_resource_t export_res_bmpdataturbo = { + CARTRIDGE_NAME_BMPDATATURBO, 1, 1, &bmpdataturbo_io1_device, &bmpdataturbo_io2_device, CARTRIDGE_BMPDATATURBO +}; + +/* ---------------------------------------------------------------------*/ +void bmpdataturbo_reset(void) +{ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + bmpdataturbo_enabled = 1; +} + +void bmpdataturbo_config_init(void) +{ + bmpdataturbo_reset(); +} + +void bmpdataturbo_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000); + memcpy(romh_banks, &rawcart[0x2000], 0x2000); + bmpdataturbo_reset(); +} + +static int bmpdataturbo_common_attach(void) +{ + if (export_add(&export_res_bmpdataturbo) < 0) { + return -1; + } + + bmpdataturbo_io1_list_item = io_source_register(&bmpdataturbo_io1_device); + bmpdataturbo_io2_list_item = io_source_register(&bmpdataturbo_io2_device); + + return 0; +} + +int bmpdataturbo_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return bmpdataturbo_common_attach(); +} + +int bmpdataturbo_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.start != 0x8000 || chip.size != 0x4000) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return bmpdataturbo_common_attach(); +} + +void bmpdataturbo_detach(void) +{ + export_remove(&export_res_bmpdataturbo); + io_source_unregister(bmpdataturbo_io1_list_item); + io_source_unregister(bmpdataturbo_io2_list_item); + bmpdataturbo_io1_list_item = NULL; + bmpdataturbo_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTWARP snapshot module format: + + type | name | version | description + ---------------------------------------- + BYTE | ROM 8000 | 0.1 | ROM at $8000 flag + ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data + ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data + */ + +static const char snap_module_name[] = "CARTBMPDATATURBO"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int bmpdataturbo_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)bmpdataturbo_enabled) < 0 + || SMW_BA(m, roml_banks, 0x2000) < 0 + || SMW_BA(m, romh_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int bmpdataturbo_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + /* new in 0.1 */ + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { + if (SMR_B_INT(m, &bmpdataturbo_enabled) < 0) { + goto fail; + } + } else { + bmpdataturbo_enabled = 0; + } + + if (0 + || SMR_BA(m, roml_banks, 0x2000) < 0 + || SMR_BA(m, romh_banks, 0x2000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return bmpdataturbo_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/bmpdataturbo.h b/src/Emulators/vice/c64/cart/bmpdataturbo.h new file mode 100644 index 00000000..d4b3e19b --- /dev/null +++ b/src/Emulators/vice/c64/cart/bmpdataturbo.h @@ -0,0 +1,46 @@ +/* + * bmpdataturbo.h - Cartridge handling, BMP Data Turbo 2000 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_BMPDATATURBO_H +#define VICE_BMPDATATURBO_H + +#include + +#include "vicetypes.h" + +void bmpdataturbo_config_setup(uint8_t *rawcart); +int bmpdataturbo_bin_attach(const char *filename, uint8_t *rawcart); +int bmpdataturbo_crt_attach(FILE *fd, uint8_t *rawcart); +void bmpdataturbo_detach(void); +void bmpdataturbo_config_init(void); +void bmpdataturbo_reset(void); + +struct snapshot_s; + +int bmpdataturbo_snapshot_write_module(struct snapshot_s *s); +int bmpdataturbo_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/c64-generic.c b/src/Emulators/vice/c64/cart/c64-generic.c index e0b9ddc8..1f7dbd0d 100644 --- a/src/Emulators/vice/c64/cart/c64-generic.c +++ b/src/Emulators/vice/c64/cart/c64-generic.c @@ -41,6 +41,7 @@ #include "vicetypes.h" #include "util.h" #include "lib.h" +#include "log.h" /* the default cartridge works like this: @@ -76,11 +77,11 @@ /* FIXME: these are shared between all "main slot" carts, individual cart implementations should get reworked to use local buffers */ /* Expansion port ROML/ROMH images. */ -BYTE *roml_banks = NULL; -BYTE *romh_banks = NULL; +uint8_t *roml_banks = NULL; +uint8_t *romh_banks = NULL; /* Expansion port RAM images. */ -BYTE *export_ram0 = NULL; +uint8_t *export_ram0 = NULL; int rombanks_resources_init(void) { @@ -106,11 +107,11 @@ int roml_bank = 0, romh_bank = 0, export_ram = 0; /* ---------------------------------------------------------------------*/ static const export_resource_t export_res_8kb = { - "Generic 8KB", 1, 0, NULL, NULL, CARTRIDGE_GENERIC_8KB + "Generic 8KiB", 1, 0, NULL, NULL, CARTRIDGE_GENERIC_8KB }; static const export_resource_t export_res_16kb = { - "Generic 16KB", 1, 1, NULL, NULL, CARTRIDGE_GENERIC_16KB + "Generic 16KiB", 1, 1, NULL, NULL, CARTRIDGE_GENERIC_16KB }; static export_resource_t export_res_ultimax = { @@ -119,7 +120,7 @@ static export_resource_t export_res_ultimax = { /* ---------------------------------------------------------------------*/ -void generic_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void generic_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { switch (addr & 0xf000) { case 0xf000: @@ -169,37 +170,37 @@ void generic_ultimax_config_init(void) cart_config_changed_slotmain(3, 3, CMODE_READ); } -void generic_8kb_config_setup(BYTE *rawcart) +void generic_8kb_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); cart_config_changed_slotmain(0, 0, CMODE_READ); } -void generic_16kb_config_setup(BYTE *rawcart) +void generic_16kb_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); cart_config_changed_slotmain(1, 1, CMODE_READ); } -void generic_ultimax_config_setup(BYTE *rawcart) +void generic_ultimax_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); cart_config_changed_slotmain(3, 3, CMODE_READ); } -int generic_common_attach(int mode) +static int generic_common_attach(int mode) { switch (mode) { case CARTRIDGE_GENERIC_8KB: - DBG(("generic: attach 8kb\n")); + DBG(("generic: attach 8KiB\n")); if (export_add(&export_res_8kb) < 0) { return -1; } break; case CARTRIDGE_GENERIC_16KB: - DBG(("generic: attach 16kb\n")); + DBG(("generic: attach 16KiB\n")); if (export_add(&export_res_16kb) < 0) { return -1; } @@ -210,11 +211,14 @@ int generic_common_attach(int mode) return -1; } break; + default: + log_error(LOG_DEFAULT, "generic_common_attach: unknown mode %d", mode); + break; } return 0; } -int generic_8kb_bin_attach(const char *filename, BYTE *rawcart) +int generic_8kb_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { /* also accept 4k binaries */ @@ -226,7 +230,7 @@ int generic_8kb_bin_attach(const char *filename, BYTE *rawcart) return generic_common_attach(CARTRIDGE_GENERIC_8KB); } -int generic_16kb_bin_attach(const char *filename, BYTE *rawcart) +int generic_16kb_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { /* also accept 12k binaries */ @@ -238,17 +242,25 @@ int generic_16kb_bin_attach(const char *filename, BYTE *rawcart) return generic_common_attach(CARTRIDGE_GENERIC_16KB); } -int generic_ultimax_bin_attach(const char *filename, BYTE *rawcart) +int generic_ultimax_bin_attach(const char *filename, uint8_t *rawcart) { + /* 16k binaries ($8000-$9fff, $e000-$ffff) */ if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { /* also accept 12k binaries */ if (util_file_load(filename, rawcart, 0x3000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - /* also accept 4k binaries */ - if (util_file_load(filename, &rawcart[0x2000], 0x1000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - return -1; + /* also accept 8k binaries ($e000-$ffff) */ + if (util_file_load(filename, &rawcart[0x2000], 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + /* also accept 4k binaries ($e000-$efff) */ + if (util_file_load(filename, &rawcart[0x2000], 0x1000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + /* produce a mirror at ($f000-$ffff) */ + memcpy(&rawcart[0x3000], &rawcart[0x2000], 0x1000); } + } else { + /* last 4k of the 12k image actually goes to $f000-$ffff */ + memcpy(&rawcart[0x3000], &rawcart[0x2000], 0x1000); } - memcpy(&rawcart[0x3000], &rawcart[0x2000], 0x1000); } return generic_common_attach(CARTRIDGE_ULTIMAX); } @@ -256,12 +268,13 @@ int generic_ultimax_bin_attach(const char *filename, BYTE *rawcart) /* returns -1 on error, else a positive CRT ID */ -int generic_crt_attach(FILE *fd, BYTE *rawcart) +int generic_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int crttype; export_res_ultimax.game = 0; + DBG(("generic_crt_attach\n")); if (crt_read_chip_header(&chip, fd)) { return -1; @@ -301,13 +314,13 @@ int generic_crt_attach(FILE *fd, BYTE *rawcart) void generic_8kb_detach(void) { - DBG(("generic: detach 8kb\n")); + DBG(("generic: detach 8KiB\n")); export_remove(&export_res_8kb); } void generic_16kb_detach(void) { - DBG(("generic: detach 16kb\n")); + DBG(("generic: detach 16KiB\n")); export_remove(&export_res_16kb); } @@ -320,7 +333,7 @@ void generic_ultimax_detach(void) /* ---------------------------------------------------------------------*/ /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -BYTE generic_roml_read(WORD addr) +uint8_t generic_roml_read(uint16_t addr) { if (export_ram) { return export_ram0[addr & 0x1fff]; @@ -330,7 +343,7 @@ BYTE generic_roml_read(WORD addr) } /* ROML store - mapped to 8000 in ultimax mode */ -void generic_roml_store(WORD addr, BYTE value) +void generic_roml_store(uint16_t addr, uint8_t value) { if (export_ram) { export_ram0[addr & 0x1fff] = value; @@ -338,23 +351,23 @@ void generic_roml_store(WORD addr, BYTE value) } /* ROMH read - mapped to A000 in 16k, to E000 in ultimax */ -BYTE generic_romh_read(WORD addr) +uint8_t generic_romh_read(uint16_t addr) { return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; } -int generic_romh_phi1_read(WORD addr, BYTE *value) +int generic_romh_phi1_read(uint16_t addr, uint8_t *value) { *value = romh_banks[(romh_bank << 13) + (addr & 0x1fff)]; return CART_READ_VALID; } -int generic_romh_phi2_read(WORD addr, BYTE *value) +int generic_romh_phi2_read(uint16_t addr, uint8_t *value) { return generic_romh_phi1_read(addr, value); } -int generic_peek_mem(export_t *export, WORD addr, BYTE *value) +int generic_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0x8000 && addr <= 0x9fff) { if (export_ram) { @@ -365,7 +378,7 @@ int generic_peek_mem(export_t *export, WORD addr, BYTE *value) return CART_READ_VALID; } - if (!(((export_t*)export)->exrom) && (((export_t*)export)->game)) { + if (!(((export_t*)ex)->exrom) && (((export_t*)ex)->game)) { if (addr >= 0xe000) { *value = romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; return CART_READ_VALID; @@ -420,7 +433,7 @@ int generic_snapshot_write_module(snapshot_t *s, int type) int generic_snapshot_read_module(snapshot_t *s, int type) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -430,7 +443,7 @@ int generic_snapshot_read_module(snapshot_t *s, int type) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/c64-generic.h b/src/Emulators/vice/c64/cart/c64-generic.h index 59075fd9..050066f6 100644 --- a/src/Emulators/vice/c64/cart/c64-generic.h +++ b/src/Emulators/vice/c64/cart/c64-generic.h @@ -33,29 +33,29 @@ struct snapshot_s; -extern void generic_8kb_config_init(void); -extern void generic_16kb_config_init(void); -extern void generic_ultimax_config_init(void); -extern void generic_8kb_config_setup(BYTE *rawcart); -extern void generic_16kb_config_setup(BYTE *rawcart); -extern void generic_ultimax_config_setup(BYTE *rawcart); -extern int generic_8kb_bin_attach(const char *filename, BYTE *rawcart); -extern int generic_16kb_bin_attach(const char *filename, BYTE *rawcart); -extern int generic_ultimax_bin_attach(const char *filename, BYTE *rawcart); -extern int generic_crt_attach(FILE *fd, BYTE *rawcart); -extern void generic_8kb_detach(void); -extern void generic_16kb_detach(void); -extern void generic_ultimax_detach(void); - -extern BYTE generic_roml_read(WORD addr); -extern void generic_roml_store(WORD addr, BYTE value); -extern BYTE generic_romh_read(WORD addr); -extern int generic_romh_phi1_read(WORD addr, BYTE *value); -extern int generic_romh_phi2_read(WORD addr, BYTE *value); -extern int generic_peek_mem(export_t *export, WORD addr, BYTE *value); -extern void generic_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); - -extern int generic_snapshot_write_module(struct snapshot_s *s, int type); -extern int generic_snapshot_read_module(struct snapshot_s *s, int type); +void generic_8kb_config_init(void); +void generic_16kb_config_init(void); +void generic_ultimax_config_init(void); +void generic_8kb_config_setup(uint8_t *rawcart); +void generic_16kb_config_setup(uint8_t *rawcart); +void generic_ultimax_config_setup(uint8_t *rawcart); +int generic_8kb_bin_attach(const char *filename, uint8_t *rawcart); +int generic_16kb_bin_attach(const char *filename, uint8_t *rawcart); +int generic_ultimax_bin_attach(const char *filename, uint8_t *rawcart); +int generic_crt_attach(FILE *fd, uint8_t *rawcart); +void generic_8kb_detach(void); +void generic_16kb_detach(void); +void generic_ultimax_detach(void); + +uint8_t generic_roml_read(uint16_t addr); +void generic_roml_store(uint16_t addr, uint8_t value); +uint8_t generic_romh_read(uint16_t addr); +int generic_romh_phi1_read(uint16_t addr, uint8_t *value); +int generic_romh_phi2_read(uint16_t addr, uint8_t *value); +int generic_peek_mem(export_t *export, uint16_t addr, uint8_t *value); +void generic_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +int generic_snapshot_write_module(struct snapshot_s *s, int type); +int generic_snapshot_read_module(struct snapshot_s *s, int type); #endif diff --git a/src/Emulators/vice/c64/cart/c64-midi.c b/src/Emulators/vice/c64/cart/c64-midi.c index 80301663..a63363a5 100644 --- a/src/Emulators/vice/c64/cart/c64-midi.c +++ b/src/Emulators/vice/c64/cart/c64-midi.c @@ -41,7 +41,6 @@ #include "machine.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" /* the order must match the enum in c64-midi.h */ midi_interface_t midi_interface[] = { @@ -60,12 +59,12 @@ midi_interface_t midi_interface[] = { /* ---------------------------------------------------------------------*/ -static BYTE c64midi_read(WORD address) +static uint8_t c64midi_read(uint16_t address) { return midi_read(address); } -static BYTE c64midi_peek(WORD address) +static uint8_t c64midi_peek(uint16_t address) { return midi_peek(address); } @@ -73,18 +72,20 @@ static BYTE c64midi_peek(WORD address) /* ---------------------------------------------------------------------*/ static io_source_t midi_device = { - "MIDI", - IO_DETACH_RESOURCE, - "MIDIEnable", - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - midi_store, - c64midi_read, - c64midi_peek, - NULL, /* TODO: dump */ - CARTRIDGE_MIDI_SEQUENTIAL, - 0, - 0 + "MIDI", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MIDIEnable", /* resource to set to '0' */ + 0xde00, 0xdeff, 0xff, /* range of the device, the actual registers and mirrors depend on which MIDI cart is being emulated */ + 1, /* read is always valid */ + midi_store, /* store function */ + NULL, /* NO poke function */ + c64midi_read, /* read function */ + c64midi_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_MIDI_SEQUENTIAL, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static export_resource_t export_res = { @@ -192,6 +193,13 @@ int c64_midi_enable(void) return resources_set_int("MIDIEnable", 1); } + +int c64_midi_disable(void) +{ + return resources_set_int("MIDIEnable", 0); +} + + void c64_midi_detach(void) { resources_set_int("MIDIEnable", 0); @@ -218,12 +226,11 @@ int c64_midi_resources_init(void) /* ---------------------------------------------------------------------*/ -static const cmdline_option_t cmdline_options[] = { - { "-miditype", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-miditype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MIDIMode", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_SPECIFY_C64_MIDI_TYPE, - "<0-4>", NULL }, + "<0-4>", "MIDI interface type (0: Sequential, 1: Passport, 2: DATEL, 3: Namesoft, 4: Maplin)" }, CMDLINE_LIST_END }; @@ -267,7 +274,7 @@ int c64_midi_snapshot_write_module(snapshot_t *s) return -1; } - if (SMW_B(m, (BYTE)midi_mode) < 0) { + if (SMW_B(m, (uint8_t)midi_mode) < 0) { snapshot_module_close(m); return -1; } @@ -279,7 +286,7 @@ int c64_midi_snapshot_write_module(snapshot_t *s) int c64_midi_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int tmp_midi_mode; @@ -290,7 +297,7 @@ int c64_midi_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/c64-midi.h b/src/Emulators/vice/c64/cart/c64-midi.h index f3e827ca..aaef68fa 100644 --- a/src/Emulators/vice/c64/cart/c64-midi.h +++ b/src/Emulators/vice/c64/cart/c64-midi.h @@ -31,10 +31,10 @@ #include "midi.h" /* returns 1 if interface is at $de00 (on C64) */ -extern int c64_midi_base_de00(void); +int c64_midi_base_de00(void); -extern int c64_midi_resources_init(void); -extern int c64_midi_cmdline_options_init(void); +int c64_midi_resources_init(void); +int c64_midi_cmdline_options_init(void); /* Emulated interfaces */ enum { @@ -45,18 +45,20 @@ enum { MIDI_MODE_MAPLIN /* Electronics - Maplin magazine */ }; -extern int c64_midi_cart_enabled(void); -extern int c64_midi_seq_cart_enabled(void); -extern int c64_midi_pp_cart_enabled(void); -extern int c64_midi_datel_cart_enabled(void); -extern int c64_midi_nsoft_cart_enabled(void); -extern int c64_midi_maplin_cart_enabled(void); +int c64_midi_cart_enabled(void); +int c64_midi_seq_cart_enabled(void); +int c64_midi_pp_cart_enabled(void); +int c64_midi_datel_cart_enabled(void); +int c64_midi_nsoft_cart_enabled(void); +int c64_midi_maplin_cart_enabled(void); -extern int c64_midi_enable(void); -extern void c64_midi_detach(void); +int c64_midi_enable(void); +int c64_midi_disable(void); +void c64_midi_detach(void); struct snapshot_s; -extern int c64_midi_snapshot_read_module(struct snapshot_s *s); -extern int c64_midi_snapshot_write_module(struct snapshot_s *s); + +int c64_midi_snapshot_read_module(struct snapshot_s *s); +int c64_midi_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/c64acia.h b/src/Emulators/vice/c64/cart/c64acia.h index 391a804a..f864b79d 100644 --- a/src/Emulators/vice/c64/cart/c64acia.h +++ b/src/Emulators/vice/c64/cart/c64acia.h @@ -30,20 +30,34 @@ #include "vicetypes.h" -extern int aciacart_cart_enabled(void); -extern void aciacart_init(void); -extern BYTE aciacart_read(WORD a); -extern void aciacart_reset(void); +int aciacart_cart_enabled(void); +void aciacart_init(void); +uint8_t aciacart_read(uint16_t a); +void aciacart_reset(void); -extern int aciacart_cmdline_options_init(void); -extern int aciacart_resources_init(void); -extern void aciacart_resources_shutdown(void); +int aciacart_cmdline_options_init(void); +int aciacart_resources_init(void); +void aciacart_resources_shutdown(void); -extern void aciacart_detach(void); -extern int aciacart_enable(void); +void aciacart_detach(void); +int aciacart_enable(void); +int aciacart_disable(void); struct snapshot_s; -extern int aciacart_snapshot_write_module(struct snapshot_s *p); -extern int aciacart_snapshot_read_module(struct snapshot_s *p); + +int aciacart_snapshot_write_module(struct snapshot_s *p); +int aciacart_snapshot_read_module(struct snapshot_s *p); + +void acia1_init(void); +uint8_t acia1_read(uint16_t a); +uint8_t acia1_peek(uint16_t a); +void acia1_store(uint16_t a, uint8_t b); +void acia1_reset(void); + +int acia1_cmdline_options_init(void); +int acia1_resources_init(void); + +int acia1_snapshot_read_module(struct snapshot_s *); +int acia1_snapshot_write_module(struct snapshot_s *); #endif diff --git a/src/Emulators/vice/c64/cart/c64acia1.c b/src/Emulators/vice/c64/cart/c64acia1.c index 3278ccd7..c878688e 100644 --- a/src/Emulators/vice/c64/cart/c64acia1.c +++ b/src/Emulators/vice/c64/cart/c64acia1.c @@ -27,19 +27,32 @@ #include "vice.h" +#include "c64acia.h" + #define mycpu maincpu #define myclk maincpu_clk #define mycpu_rmw_flag maincpu_rmw_flag -#define mycpu_clk_guard maincpu_clk_guard #define myacia acia1 /* resource defaults */ #define MYACIA "Acia1" -#define MyDevice 0 -#define MyIrq IK_IRQ +#define MyDevice 1 +#define MyIrq IK_NMI #define myaciadev acia1dev +#define myaciactrl acia1ctrl + +#if 0 +void acia1_init(void); +void acia1_reset(void); +int acia1_resources_init(void); +int acia1_cmdline_options_init(void); +int acia1_snapshot_write_module(struct snapshot_s *); +int acia1_snapshot_read_module(struct snapshot_s *); +void acia1_store +#endif + #define myacia_init acia1_init #define myacia_init_cmdline_options acia1_cmdline_options_init @@ -50,7 +63,8 @@ #define myacia_reset acia1_reset #define myacia_store acia1_store -extern int acia1_set_mode(int mode); +/* function prototype */ +int acia1_set_mode(int mode); #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) #define myacia_set_mode(x) acia1_set_mode(x) @@ -117,23 +131,26 @@ extern int acia1_set_mode(int mode); #include "acia.h" #include "alarm.h" -#include "clkguard.h" #include "cmdline.h" #include "interrupt.h" #include "log.h" #include "machine.h" #include "resources.h" #include "rs232drv.h" +#include "rs232.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" +#include "monitor.h" +uint8_t myacia_read(uint16_t addr); #undef DEBUG /*!< define if you want "normal" debugging output */ #undef DEBUG_VERBOSE /*!< define if you want very verbose debugging output. */ /* #define DEBUG */ /* #define DEBUG_VERBOSE */ +/* #define LOG_MODEM_STATUS */ + /*! \brief Helper macro for outputting debugging messages */ #ifdef VICE_DEBUG # define DEBUG_LOG_MESSAGE(_x) log_message _x @@ -162,101 +179,102 @@ enum acia_tx_state { }; typedef struct acia_struct { - alarm_t *alarm_tx; /*!< handling of the transmit (TX) alarm */ - alarm_t *alarm_rx; /*!< handling of the receive (RX) alarm */ - unsigned int int_num; /*!< the (internal) number for the ACIA interrupt as returned by interrupt_cpu_status_int_new(). */ - - int ticks; /*!< number of clock ticks per char */ - int ticks_rx; /*!< number of clock ticks per char for reception (workaround for NovaTerm, cf. remark for set_acia_ticks() */ - int fd; /*!< file descriptor used to access the RS232 physical device on the host machine */ - enum acia_tx_state in_tx; /*!< indicates that a transmit is currently ongoing */ - int irq; - BYTE cmd; /*!< value of the 6551 command register */ - BYTE ctrl; /*!< value of the 6551 control register */ - BYTE rxdata; /*!< data that has been received last */ - BYTE txdata; /*!< data prepared to be send */ - BYTE status; /*!< value of the 6551 status register */ - BYTE ectrl; /*!< value of the extended control register of the turbo232 card */ - int alarm_active_tx; /*!< 1 if TX alarm is set; else 0 */ - int alarm_active_rx; /*!< 1 if RX alarm is set; else 0 */ - - log_t log; /*!< the log where to write debugging messages */ - - BYTE last_read; /*!< the byte read the last time (for RMW) */ - - /******************************************************************/ - - /*! \brief the clock value the TX alarm has last been set to fire at - - \note - If alarm_active_tx is set to 1, to alarm is - actually set. If alarm_active_tx is 0, then - the alarm either has already fired, or it - already has been cancelled. - */ - CLOCK alarm_clk_tx; - - /*! \brief the clock value the RX alarm has last been set to fire at - - \note - If alarm_active_rx is set to 1, to alarm is - actually set. If alarm_active_rx is 0, then - the alarm either has already fired, or it - already has been cancelled. - */ - CLOCK alarm_clk_rx; - - /*! \brief the arch-dependant RS232 device to use for this acia implementation */ - int device; - - /*! \brief the type of interrupt implemented by the ACIA - - The ACIA either implements an IRQ (IK_IRQ), an NMI (IK_NMI), - or no interrupt at all (IK_NONE). - - \note - As some cartridges can be switched between these modes, - it is necessary to remember this value. - */ - enum cpu_int irq_type; - - /*! \brief the type of interrupt implemented by the ACIA, - as defined in the resources - - Essentially, this is the same info as acia_irq_type. As the - resource stored in the VICE system is different from - the actual value in acia_irq_type, the resources value is - stored here. - */ - int irq_res; - - /*! \brief the acia variant implemented. - Specifies if this acia implements a "raw" 6551 device - (ACIA_MODE_NORMAL), a swiftlink device (ACIA_MODE_SWIFTLINK) - or a turbo232 device (ACIA_MODE_TURBO232). - */ - int mode; - - /*! \brief The handshake lines as currently seen by the ACIA */ - enum rs232handshake_out rs232_status_lines; + alarm_t *alarm_tx; /*!< handling of the transmit (TX) alarm */ + alarm_t *alarm_rx; /*!< handling of the receive (RX) alarm */ + unsigned int int_num; /*!< the (internal) number for the ACIA interrupt as returned by interrupt_cpu_status_int_new(). */ + + int ticks; /*!< number of clock ticks per char */ + int fd; /*!< file descriptor used to access the RS232 physical device on the host machine */ + enum acia_tx_state in_tx; /*!< indicates that a transmit is currently ongoing */ + int irq; + uint8_t cmd; /*!< value of the 6551 command register */ + uint8_t ctrl; /*!< value of the 6551 control register */ + uint8_t rxdata; /*!< data that has been received last */ + uint8_t txdata; /*!< data prepared to be send */ + uint8_t status; /*!< value of the 6551 status register */ + uint8_t ectrl; /*!< value of the extended control register of the turbo232 card */ + uint8_t datamask; /*!< Word length bitmask used on received and sent data */ + int alarm_active_tx; /*!< 1 if TX alarm is set; else 0 */ + int alarm_active_rx; /*!< 1 if RX alarm is set; else 0 */ + + log_t log; /*!< the log where to write debugging messages */ + + uint8_t last_read; /*!< the byte read the last time (for RMW) */ + + /******************************************************************/ + + /*! \brief the clock value the TX alarm has last been set to fire at + + \note + If alarm_active_tx is set to 1, to alarm is + actually set. If alarm_active_tx is 0, then + the alarm either has already fired, or it + already has been cancelled. + */ + CLOCK alarm_clk_tx; + + /*! \brief the clock value the RX alarm has last been set to fire at + + \note + If alarm_active_rx is set to 1, to alarm is + actually set. If alarm_active_rx is 0, then + the alarm either has already fired, or it + already has been cancelled. + */ + CLOCK alarm_clk_rx; + + /*! \brief the arch-dependant RS232 device to use for this acia implementation */ + int device; + + /*! \brief the type of interrupt implemented by the ACIA + + The ACIA either implements an IRQ (IK_IRQ), an NMI (IK_NMI), + or no interrupt at all (IK_NONE). + + \note + As some cartridges can be switched between these modes, + it is necessary to remember this value. + */ + enum cpu_int irq_type; + + /*! \brief the type of interrupt implemented by the ACIA, + as defined in the resources + + Essentially, this is the same info as acia_irq_type. As the + resource stored in the VICE system is different from + the actual value in acia_irq_type, the resources value is + stored here. + */ + int irq_res; + + /*! \brief the acia variant implemented. + Specifies if this acia implements a "raw" 6551 device + (ACIA_MODE_NORMAL), a swiftlink device (ACIA_MODE_SWIFTLINK) + or a turbo232 device (ACIA_MODE_TURBO232). + */ + int mode; + + /*! \brief The handshake lines as currently seen by the ACIA */ + enum rs232handshake_out rs232_status_lines; + } acia_type; /******************************************************************/ -static acia_type acia = { NULL, NULL, 0, 0, 0, 0, (enum acia_tx_state)0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - (enum cpu_int)0, 0, 0, (enum rs232handshake_out)0 }; +static acia_type acia = { NULL, NULL, 0, 0, 0, (enum acia_tx_state)0, + 0, 0, 0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0, 0, 0, 0, + (enum cpu_int)0, 0, 0, (enum rs232handshake_out)0 }; -void acia_preinit(void) +static void acia_preinit(void) { - memset(&acia, 0, sizeof acia); - - acia.ticks = acia.ticks_rx = 21111; - acia.fd = -1; - acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; - acia.log = LOG_ERR; - acia.irq_type = IK_NONE; - acia.mode = ACIA_MODE_NORMAL; + memset(&acia, 0, sizeof acia); + + acia.ticks = 21111; + acia.fd = -1; + acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; + acia.log = LOG_DEFAULT; + acia.irq_type = IK_NONE; + acia.mode = ACIA_MODE_NORMAL; } static void int_acia_tx(CLOCK offset, void *data); @@ -332,6 +350,7 @@ static int acia_set_device(int val, void *param) return 0; } + /*! \internal \brief Generate an ACIA interrupt This function is used to generate an ACIA interrupt. @@ -358,24 +377,26 @@ static int acia_set_device(int val, void *param) */ static void acia_set_int(int aciairq, unsigned int int_num, int value) { - assert((value == aciairq) || (value == IK_NONE)); - - if (aciairq == IK_IRQ) { - mycpu_set_irq(int_num, value); - } - if (aciairq == IK_NMI) { - mycpu_set_nmi(int_num, value); - } + DEBUG_LOG_MESSAGE((acia.log, "acia_set_int(aciairq=%d, int_num=%u, value=%u", + aciairq, int_num, value)); + assert((value == aciairq) || (value == IK_NONE)); + + if (aciairq == IK_IRQ) { + mycpu_set_irq(int_num, value); + } + if (aciairq == IK_NMI) { + mycpu_set_nmi(int_num, value); + } } /*! \internal \brief Change the Interrupt resource for this ACIA \param new_irq_res - The interrupt type to use: - 0 = none, - 1 = IRQ, - 2 = NMI. - + The interrupt type to use: + 0 = none, + 1 = NMI, + 2 = IRQ. + \param param Unused @@ -389,34 +410,29 @@ static void acia_set_int(int aciairq, unsigned int int_num, int value) #if (ACIA_MODE_HIGHEST == ACIA_MODE_TURBO232) static int acia_set_irq(int new_irq_res, void *param) { - enum cpu_int new_irq; - static const enum cpu_int irq_tab[] = { IK_NONE, IK_IRQ, IK_NMI }; - - /* - * if an invalid interrupt type has been given, return - * with an error. - */ - switch (new_irq_res) { - case IK_NONE: - case IK_NMI: - case IK_IRQ: - break; - default: - return -1; - } - - new_irq = irq_tab[new_irq_res]; - - if (acia.irq_type != new_irq) { - acia_set_int(acia.irq_type, acia.int_num, IK_NONE); - if (new_irq != IK_NONE) { - acia_set_int(new_irq, acia.int_num, new_irq); - } - } - acia.irq_type = new_irq; - acia.irq_res = new_irq_res; - - return 0; + enum cpu_int new_irq; + static const enum cpu_int irq_tab[] = { IK_NONE, IK_NMI, IK_IRQ }; + + /* + * if an invalid interrupt type has been given, return + * with an error. + */ + if ((new_irq_res < 0) || (new_irq_res > 2)) { + return -1; + } + + new_irq = irq_tab[new_irq_res]; + + if (acia.irq_type != new_irq) { + acia_set_int(acia.irq_type, acia.int_num, IK_NONE); + if (new_irq != IK_NONE) { + acia_set_int(new_irq, acia.int_num, new_irq); + } + } + acia.irq_type = new_irq; + acia.irq_res = new_irq_res; + + return 0; } #endif @@ -427,24 +443,24 @@ static int acia_set_irq(int new_irq_res, void *param) */ static double get_acia_bps(void) { - switch (acia.mode) { - case ACIA_MODE_NORMAL: - return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK]; - - case ACIA_MODE_SWIFTLINK: - return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK] * 2; - - case ACIA_MODE_TURBO232: - if ((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) { - return t232_bps_table[acia.ectrl & T232_ECTRL_BITS_EXT_BPS_MASK]; - } else { - return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK] * 2; - } - - default: - log_message(acia.log, "Invalid acia.mode = %u in get_acia_bps()", acia.mode); - return acia_bps_table[0]; /* return dummy value */ - } + switch (acia.mode) { + case ACIA_MODE_NORMAL: + return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK]; + + case ACIA_MODE_SWIFTLINK: + return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK] * 2; + + case ACIA_MODE_TURBO232: + if ((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) { + return t232_bps_table[acia.ectrl & T232_ECTRL_BITS_EXT_BPS_MASK]; + } else { + return acia_bps_table[acia.ctrl & ACIA_CTRL_BITS_BPS_MASK] * 2; + } + + default: + log_message(acia.log, "Invalid acia.mode = %d in get_acia_bps()", acia.mode); + return acia_bps_table[0]; /* return dummy value */ + } } /*! \internal \brief set the ticks between characters of the ACIA according to the bps rate @@ -454,67 +470,65 @@ static double get_acia_bps(void) */ static void set_acia_ticks(void) { - unsigned int bits; - - DEBUG_LOG_MESSAGE((acia.log, "Setting ACIA to %u bps", - (unsigned int) get_acia_bps())); - - switch (acia.ctrl & ACIA_CTRL_BITS_WORD_LENGTH_MASK) { - case ACIA_CTRL_BITS_WORD_LENGTH_8: - bits = 8; - break; - case ACIA_CTRL_BITS_WORD_LENGTH_7: - bits = 7; - break; - case ACIA_CTRL_BITS_WORD_LENGTH_6: - bits = 6; - break; - default: - /* - * this case is only for gcc to calm down, as it wants to warn that - * bits is used uninitialised - which it is not. - */ - /* FALL THROUGH */ - case ACIA_CTRL_BITS_WORD_LENGTH_5: - bits = 5; - break; - } - - /* - * we neglect the fact that we might have 1.5 stop bits instead of 2 - */ - bits += 1 /* the start bit */ - + ((acia.cmd & ACIA_CMD_BITS_PARITY_ENABLED) ? 1 : 0) /* parity or not */ - + ((acia.ctrl & ACIA_CTRL_BITS_2_STOP) ? 2 : 1); /* 1 or 2 stop bits */ - - /* - * calculate time in ticks for the data bits - * including start, stop and parity bits. - */ - acia.ticks = (int) (machine_get_cycles_per_second() / get_acia_bps() * bits); - - /* - * Note: With 10 bit, the timing is very hard to NovaTerm 9.6c with 57600 bps - * on reception. It cannot cope and behaves erroneously, at least when configured - * for NMI interrupts. This is because the interrupt routine needs too much - * time to execute, leaving not more than 20 cycles for the non-NMI routine. - * Thus, it was decided to add 25% "safety margin" to allow NovaTerm to react - * appropriately. This gives the main program 50 extra cycles. - * This way, NovaTerm can cope with the transmission at 57600 bps. - */ - acia.ticks_rx = acia.ticks * 5 / 4; - - /* adjust the alarm rate for reception */ - if (acia.alarm_active_rx) { - acia.alarm_clk_rx = myclk + acia.ticks_rx; - alarm_set(acia.alarm_rx, acia.alarm_clk_rx); - acia.alarm_active_rx = 1; - } - - /* - * set the baud rate of the physical device - */ - rs232drv_set_bps(acia.fd, (unsigned int)get_acia_bps()); + unsigned int bits; + + DEBUG_LOG_MESSAGE((acia.log, "Setting ACIA to %u bps", + (unsigned int) get_acia_bps())); + + switch (acia.ctrl & ACIA_CTRL_BITS_WORD_LENGTH_MASK) { + case ACIA_CTRL_BITS_WORD_LENGTH_8: + bits = 8; + break; + case ACIA_CTRL_BITS_WORD_LENGTH_7: + bits = 7; + break; + case ACIA_CTRL_BITS_WORD_LENGTH_6: + bits = 6; + break; + default: + /* + * this case is only for gcc to calm down, as it wants to warn that + * bits is used uninitialised - which it is not. + */ + /* FALL THROUGH */ + case ACIA_CTRL_BITS_WORD_LENGTH_5: + bits = 5; + break; + } + + /* set the data bitmask */ + + acia.datamask = 0xff >> (8 - bits); + + /* + * we neglect the fact that we might have 1.5 stop bits instead of 2 + * + * FIX ME!!! 8-bit mode with parity should have only 1 stop bit + */ + bits += 1 /* the start bit */ + + ((acia.cmd & ACIA_CMD_BITS_PARITY_ENABLED) ? 1 : 0) /* parity or not */ + + ((acia.ctrl & ACIA_CTRL_BITS_2_STOP) ? 2 : 1); /* 1 or 2 stop bits */ + + /* + * calculate time in ticks for the data bits + * including start, stop and parity bits. + */ + acia.ticks = (int) (machine_get_cycles_per_second() / get_acia_bps() * bits); + + + /* adjust the alarm rate for reception */ + if (acia.alarm_active_rx) { + acia.alarm_clk_rx = myclk + acia.ticks; + alarm_set(acia.alarm_rx, acia.alarm_clk_rx); + acia.alarm_active_rx = 1; + } + + /* + * set the baud rate of the physical device + */ + if (acia.fd >= 0) { + rs232drv_set_bps(acia.fd, (unsigned int)get_acia_bps()); + } } /*! \internal \brief Change the emulation mode for this ACIA @@ -569,22 +583,22 @@ static const resource_int_t resources_int[] = { */ int myacia_init_resources(void) { - acia_preinit(); - - acia.irq_res = MyIrq; - acia.mode = ACIA_MODE_NORMAL; - - return resources_register_int(resources_int); + acia_preinit(); + + acia.irq_res = MyIrq; + acia.irq_type = MyIrq; + acia.mode = ACIA_MODE_NORMAL; + + return resources_register_int(resources_int); } /*! \brief the command-line options available for the ACIA */ -static const cmdline_option_t cmdline_options[] = { - { "-myaciadev", SET_RESOURCE, 1, - NULL, NULL, MYACIA "Dev", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_SPECIFY_ACIA_RS232_DEVICE, - "<0-3>", NULL }, - CMDLINE_LIST_END +static const cmdline_option_t cmdline_options[] = +{ + { "-myaciadev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, MYACIA "Dev", NULL, + "<0-3>", "Specify RS232 device this ACIA should work on" }, + CMDLINE_LIST_END }; /*! \brief initialize the command-line options @@ -603,44 +617,28 @@ int myacia_init_cmdline_options(void) /******************************************************************/ /* auxiliary functions */ -/*! \internal \brief Prevent clock overflow by adjusting clock value - - \param sub - The number of clock ticks to adjust the clock by subtracting - from the current value - - \param var - The data as has been given to clk_guard_add_callback() as - 3rd parameter. For this implementation, always NULL. - - \remark - In order to prevent a clock overflow, the system is able - to subtract a given amount from the clock values. When this - happens, this function is called in order for the module to - adjust its own values. - */ -static void clk_overflow_callback(CLOCK sub, void *var) -{ - assert(var == NULL); - - acia.alarm_clk_tx -= sub; - acia.alarm_clk_rx -= sub; -} - /*! \internal \brief Get the modem status and set the status register accordingly This function reads the physical modem status lines (DSR, DCD) and sets the emulated ACIA status register accordingly. \return - The new value of the status register - */ + The new value of the status register + + \todo + Changes in DSR and DCD should trigger an interrupt +*/ static int acia_get_status(void) { - enum rs232handshake_in modem_status = rs232drv_get_status(acia.fd); - - acia.status &= ~(ACIA_SR_BITS_DCD | ACIA_SR_BITS_DSR); - + enum rs232handshake_in modem_status = 0; +#ifdef LOG_MODEM_STATUS + static int oldstatus = -1; +#endif + + if (acia.fd >= 0) { + modem_status = rs232drv_get_status(acia.fd); + } + acia.status &= ~(ACIA_SR_BITS_DCD | ACIA_SR_BITS_DSR); #if 0 /* * CTS is very different from DCD. @@ -651,12 +649,40 @@ static int acia_get_status(void) acia.status |= ACIA_SR_BITS_DCD; /* we treat CTS like DCD */ } #endif - - if (modem_status & RS232_HSI_DSR) { - acia.status |= ACIA_SR_BITS_DSR; - } - - return acia.status; + if (!(modem_status & RS232_HSI_DCD)) { + /* DCD mirrors DSR for C64/128 machines */ + switch (machine_class) { + case VICE_MACHINE_C64: /* fall through */ + case VICE_MACHINE_C64SC: /* fall through */ + case VICE_MACHINE_SCPU64: /* fall through */ + case VICE_MACHINE_C128: /* fall through */ + acia.status |= ACIA_SR_BITS_DSR; + break; + /* Real DCD for other machines */ + default: + acia.status |= ACIA_SR_BITS_DCD; + } + } + + if (!(modem_status & RS232_HSI_DSR)) { + acia.status |= ACIA_SR_BITS_DSR; + } + + +#ifdef LOG_MODEM_STATUS + if (acia.status != oldstatus) { + printf("acia_get_status(fd:%d): modem_status:%02x dcd:%d dsr:%d status:%02x dcd:%d dsr:%d\n", + acia.fd, modem_status, + modem_status & RS232_HSI_DCD ? 1 : 0, + modem_status & RS232_HSI_DSR ? 1 : 0, + acia.status, + acia.status & ACIA_SR_BITS_DCD ? 1 : 0, + acia.status & ACIA_SR_BITS_DSR ? 1 : 0 + ); + oldstatus = acia.status; + } +#endif + return acia.status; } /*! \internal \brief Set the handshake (output) lines to the status of the cmd register @@ -666,92 +692,122 @@ static int acia_get_status(void) */ static void acia_set_handshake_lines(void) { - switch (acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) { - case ACIA_CMD_BITS_TRANSMITTER_NO_RTS: - /* unset RTS, we are NOT ready to receive */ - acia.rs232_status_lines &= ~RS232_HSO_RTS; - if (acia.alarm_active_rx) { - /* diable RX alarm */ - acia.alarm_active_rx = 0; - alarm_unset(acia.alarm_rx); - } - break; - - case ACIA_CMD_BITS_TRANSMITTER_BREAK: - /* FALL THROUGH */ - case ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ: - /* FALL THROUGH */ - case ACIA_CMD_BITS_TRANSMITTER_TX_WO_IRQ: - /* set RTS, we are ready to receive */ - acia.rs232_status_lines |= RS232_HSO_RTS; - - if (!acia.alarm_active_rx) { - /* enable RX alarm */ - acia.alarm_active_rx = 1; - set_acia_ticks(); - } - break; - } - - if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) { - /* set DTR, we are ready to transmit and receive */ - acia.rs232_status_lines |= RS232_HSO_DTR; - } else { - /* unset DTR, we are NOT ready to receive or to transmit */ - acia.rs232_status_lines &= ~RS232_HSO_DTR; - } - /* set the RTS and the DTR status */ - rs232drv_set_status(acia.fd, acia.rs232_status_lines); +#ifdef LOG_MODEM_STATUS + static int oldstatus = -1; +#endif + switch (acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) { + case ACIA_CMD_BITS_TRANSMITTER_NO_RTS: + /* unset RTS, we are NOT ready to receive */ + acia.rs232_status_lines &= ~RS232_HSO_RTS; + if (acia.alarm_active_rx) { + /* disable RX alarm */ + /* receiver gets disabled after current character is completed */ + acia.alarm_active_rx = 0; + /* disable and unset TX alarm */ + /* transmitter is disabled immediately */ + acia.alarm_active_tx = 0; + alarm_unset(acia.alarm_tx); + } + break; + + case ACIA_CMD_BITS_TRANSMITTER_BREAK: + /* FALL THROUGH */ + case ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ: + /* FALL THROUGH */ + case ACIA_CMD_BITS_TRANSMITTER_TX_WO_IRQ: + /* set RTS, we are ready to receive */ + acia.rs232_status_lines |= RS232_HSO_RTS; + + if (!acia.alarm_active_rx) { + /* enable RX alarm */ + acia.alarm_active_rx = 1; + set_acia_ticks(); + } + /* start tx alarm */ + if (acia.alarm_active_tx == 0) { + acia.alarm_clk_tx = myclk + acia.ticks; + alarm_set(acia.alarm_tx, acia.alarm_clk_tx); + acia.alarm_active_tx = 1; + } + break; + } + + if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) { + /* set DTR, we are ready to transmit and receive */ + acia.rs232_status_lines |= RS232_HSO_DTR; + } else { + /* unset DTR, we are NOT ready to receive or to transmit */ + acia.rs232_status_lines &= ~RS232_HSO_DTR; + } + +#ifdef LOG_MODEM_STATUS + if (acia.rs232_status_lines != oldstatus) { + printf("acia_set_handshake_lines(fd:%d): rs232 status:%02x dtr:%d rts:%d\n", + acia.fd, + acia.rs232_status_lines, + acia.rs232_status_lines & RS232_HSO_DTR ? 1 : 0, + acia.rs232_status_lines & RS232_HSO_RTS ? 1 : 0 + ); + oldstatus = acia.rs232_status_lines; + } +#endif + /* set the RTS and the DTR status */ + if (acia.fd >= 0) { + rs232drv_set_status(acia.fd, acia.rs232_status_lines); + } } /*! \brief initialize the ACIA */ void myacia_init(void) { - acia.int_num = interrupt_cpu_status_int_new(maincpu_int_status, MYACIA); - - acia.alarm_tx = alarm_new(mycpu_alarm_context, MYACIA, int_acia_tx, NULL); - acia.alarm_rx = alarm_new(mycpu_alarm_context, MYACIA, int_acia_rx, NULL); - - clk_guard_add_callback(mycpu_clk_guard, clk_overflow_callback, NULL); - - if (acia.log == LOG_ERR) { - acia.log = log_open(MYACIA); - } + acia.int_num = interrupt_cpu_status_int_new(maincpu_int_status, MYACIA); + + acia.alarm_tx = alarm_new(mycpu_alarm_context, MYACIA, int_acia_tx, NULL); + acia.alarm_rx = alarm_new(mycpu_alarm_context, MYACIA, int_acia_rx, NULL); + + if (acia.log == LOG_DEFAULT) { + acia.log = log_open(MYACIA); + } } /*! \brief reset the ACIA */ void myacia_reset(void) { - DEBUG_LOG_MESSAGE((acia.log, "reset_myacia")); - - acia.rs232_status_lines = 0; - rs232drv_set_status(acia.fd, acia.rs232_status_lines); - - acia.cmd = ACIA_CMD_DEFAULT_AFTER_HW_RESET; - acia.ctrl = ACIA_CTRL_DEFAULT_AFTER_HW_RESET; - acia.ectrl = T232_ECTRL_DEFAULT_AFTER_HW_RESET; - - set_acia_ticks(); - - acia.status = ACIA_SR_DEFAULT_AFTER_HW_RESET; - acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; - - if (acia.fd >= 0) { - rs232drv_close(acia.fd); - } - acia.fd = -1; - - if (acia.alarm_tx) { - alarm_unset(acia.alarm_tx); - } - if (acia.alarm_rx) { - alarm_unset(acia.alarm_rx); - } - acia.alarm_active_tx = 0; - acia.alarm_active_rx = 0; - - acia_set_int(acia.irq_type, acia.int_num, IK_NONE); - acia.irq = 0; + DEBUG_LOG_MESSAGE((acia.log, "reset_myacia")); + + acia.rs232_status_lines = 0; + if (acia.fd >= 0) { + rs232drv_set_status(acia.fd, acia.rs232_status_lines); + } + + acia.cmd = ACIA_CMD_DEFAULT_AFTER_HW_RESET; + acia.ctrl = ACIA_CTRL_DEFAULT_AFTER_HW_RESET; + acia.ectrl = T232_ECTRL_DEFAULT_AFTER_HW_RESET; + + set_acia_ticks(); + + /* ACIA Status Register after HW reset = 0xx10000 */ + acia.status &= ACIA_SR_BITS_DSR; /* Keep DSR from emulated modem */ + acia.status |= ACIA_SR_BITS_DCD | ACIA_SR_DEFAULT_AFTER_HW_RESET; /* But disable DCD, closing the rs232drv will bring it up anyways */ + + acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; + + if (acia.fd >= 0) { + rs232drv_close(acia.fd); + } + acia.fd = -1; + + if (acia.alarm_tx) { + alarm_unset(acia.alarm_tx); + } + if (acia.alarm_rx) { + alarm_unset(acia.alarm_rx); + } + acia.alarm_active_tx = 0; + acia.alarm_active_rx = 0; + + acia_set_int(acia.irq_type, acia.int_num, IK_NONE); + acia.irq = 0; } /******************************************************************/ @@ -765,7 +821,7 @@ void myacia_reset(void) */ #define ACIA_DUMP_VER_MAJOR 1 /*!< the major version number of the dump data */ -#define ACIA_DUMP_VER_MINOR 0 /*!< the minor version number of the dump data */ +#define ACIA_DUMP_VER_MINOR 1 /*!< the minor version number of the dump data */ /* * Layout of the dump data: @@ -778,9 +834,9 @@ void myacia_reset(void) * * UBYTE IN_TX 0 = no data to tx; 2 = TDR valid; 1 = in transmit (cf. enum acia_tx_state) * - * DWORD TICKSTX ticks till the next TDR empty interrupt + * QWORD TICKSTX ticks till the next TDR empty interrupt * - * DWORD TICKSRX ticks till the next RDF empty interrupt + * QWORD TICKSRX ticks till the next RDF empty interrupt * TICKSRX has been added with 2.0.9; if it does not * exist on read, it is assumed that it has the same * value as TICKSTX to emulate the old behaviour. @@ -808,44 +864,43 @@ static const char module_name[] = MYACIA; */ int myacia_snapshot_write_module(snapshot_t *p) { - snapshot_module_t *m; - DWORD act; - DWORD aar; - - m = snapshot_module_create(p, module_name, ACIA_DUMP_VER_MAJOR, ACIA_DUMP_VER_MINOR); - - if (m == NULL) { - return -1; - } - - if (acia.alarm_active_tx) { - act = acia.alarm_clk_tx - myclk; - } else { - act = 0; - } - - if (acia.alarm_active_rx) { - aar = acia.alarm_clk_rx - myclk; - } else { - aar = 0; - } - - if (0 - || SMW_B(m, acia.txdata) < 0 - || SMW_B(m, acia.rxdata) < 0 - || SMW_B(m, (BYTE)(acia_get_status() | (acia.irq ? ACIA_SR_BITS_IRQ : 0))) < 0 - || SMW_B(m, acia.cmd) < 0 - || SMW_B(m, acia.ctrl) < 0 - || SMW_B(m, (BYTE)(acia.in_tx)) < 0 - || SMW_DW(m, act) < 0 - /* new with VICE 2.0.9 */ - || SMW_DW(m, aar) < 0) { - snapshot_module_close(m); - return -1; - } - - - return snapshot_module_close(m); + snapshot_module_t *m; + CLOCK act; + CLOCK aar; + + m = snapshot_module_create(p, module_name, ACIA_DUMP_VER_MAJOR, ACIA_DUMP_VER_MINOR); + + if (m == NULL) { + return -1; + } + + if (acia.alarm_active_tx) { + act = acia.alarm_clk_tx - myclk; + } else { + act = 0; + } + + if (acia.alarm_active_rx) { + aar = acia.alarm_clk_rx - myclk; + } else { + aar = 0; + } + + if (SMW_B(m, acia.txdata) < 0 + || SMW_B(m, acia.rxdata) < 0 + || SMW_B(m, (uint8_t)(acia_get_status() + | (acia.irq ? ACIA_SR_BITS_IRQ : 0))) < 0 + || SMW_B(m, acia.cmd) < 0 + || SMW_B(m, acia.ctrl) < 0 + || SMW_B(m, (uint8_t)(acia.in_tx)) < 0 + || SMW_CLOCK(m, act) < 0 + || SMW_CLOCK(m, aar) < 0) { + snapshot_module_close(m); + return -1; + } + + + return snapshot_module_close(m); } /*! \brief Read the snapshot module for the ACIA @@ -870,293 +925,305 @@ int myacia_snapshot_write_module(snapshot_t *p) */ int myacia_snapshot_read_module(snapshot_t *p) { - BYTE vmajor, vminor; - BYTE byte; - DWORD dword1; - DWORD dword2; - snapshot_module_t *m; - - alarm_unset(acia.alarm_tx); /* just in case we don't find module */ - alarm_unset(acia.alarm_rx); /* just in case we don't find module */ - acia.alarm_active_tx = 0; - acia.alarm_active_rx = 0; - - mycpu_set_int_noclk(acia.int_num, 0); - - m = snapshot_module_open(p, module_name, &vmajor, &vminor); - - if (m == NULL) { - return -1; - } - - /* Do not accept versions higher than current */ - if (vmajor > ACIA_DUMP_VER_MAJOR || vminor > ACIA_DUMP_VER_MINOR) { - snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); - snapshot_module_close(m); - return -1; - } - - if (0 - || SMR_B(m, &acia.txdata) < 0 - || SMR_B(m, &acia.rxdata) < 0 - || SMR_B(m, &acia.status) < 0 - || SMR_B(m, &acia.cmd) < 0 - || SMR_B(m, &acia.ctrl) < 0 - || SMR_B(m, &byte) < 0 - || SMR_DW(m, &dword1) < 0) { - snapshot_module_close(m); - return -1; - } - - acia.irq = 0; - if (acia.status & ACIA_SR_BITS_IRQ) { - acia.status &= ~ACIA_SR_BITS_IRQ; - acia.irq = 1; - mycpu_set_int_noclk(acia.int_num, acia.irq_type); - } else { - mycpu_set_int_noclk(acia.int_num, 0); - } - - if ((acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && (acia.fd < 0)) { - acia.fd = rs232drv_open(acia.device); - acia_set_handshake_lines(); - } else { - if ((acia.fd >= 0) && !(acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ)) { - rs232drv_close(acia.fd); - acia.fd = -1; - } - } - - set_acia_ticks(); - - acia.in_tx = byte; - - if (dword1) { - acia.alarm_clk_tx = myclk + dword1; - alarm_set(acia.alarm_tx, acia.alarm_clk_tx); - acia.alarm_active_tx = 1; - - /* - * for compatibility reasons of old snapshots with new ones, - * set the RX alarm to the same value. - * if we have a new snapshot (2.0.9 and up), this will be - * overwritten directly afterwards. - */ - acia.alarm_clk_rx = myclk + dword1; - alarm_set(acia.alarm_rx, acia.alarm_clk_rx); - acia.alarm_active_rx = 1; - } - - /* - * this is new with VICE 2.0.9; thus, only use the settings - * if it does exist. - */ - if (SMR_DW(m, &dword2) >= 0) { - if (dword2) { - acia.alarm_clk_rx = myclk + dword2; - alarm_set(acia.alarm_rx, acia.alarm_clk_rx); - acia.alarm_active_rx = 1; - } else { - alarm_unset(acia.alarm_rx); - acia.alarm_active_rx = 0; - } - } - - return snapshot_module_close(m); + uint8_t vmajor, vminor; + uint8_t byte; + CLOCK qword1; + CLOCK qword2; + snapshot_module_t *m; + + alarm_unset(acia.alarm_tx); /* just in case we don't find module */ + alarm_unset(acia.alarm_rx); /* just in case we don't find module */ + acia.alarm_active_tx = 0; + acia.alarm_active_rx = 0; + + mycpu_set_int_noclk(acia.int_num, 0); + + m = snapshot_module_open(p, module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, ACIA_DUMP_VER_MAJOR, ACIA_DUMP_VER_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + snapshot_module_close(m); + return -1; + } + + if (SMR_B(m, &acia.txdata) < 0 + || SMR_B(m, &acia.rxdata) < 0 + || SMR_B(m, &acia.status) < 0 + || SMR_B(m, &acia.cmd) < 0 + || SMR_B(m, &acia.ctrl) < 0 + || SMR_B(m, &byte) < 0 + || SMR_CLOCK(m, &qword1) < 0) { + snapshot_module_close(m); + return -1; + } + + acia.irq = 0; + if (acia.status & ACIA_SR_BITS_IRQ) { + acia.status &= ~ACIA_SR_BITS_IRQ; + acia.irq = 1; + mycpu_set_int_noclk(acia.int_num, acia.irq_type); + } else { + mycpu_set_int_noclk(acia.int_num, 0); + } + + if ((acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && (acia.fd < 0)) { + acia.fd = rs232drv_open(acia.device); + acia_set_handshake_lines(); + } else { + if ((acia.fd >= 0) && !(acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && !rs232_useip232[acia.device]) { + rs232drv_close(acia.fd); + acia.fd = -1; + } + } + + set_acia_ticks(); + + acia.in_tx = byte; + + if (qword1) { + acia.alarm_clk_tx = myclk + qword1; + alarm_set(acia.alarm_tx, acia.alarm_clk_tx); + acia.alarm_active_tx = 1; + + /* + * for compatibility reasons of old snapshots with new ones, + * set the RX alarm to the same value. + * if we have a new snapshot (2.0.9 and up), this will be + * overwritten directly afterwards. + */ + acia.alarm_clk_rx = myclk + qword1; + alarm_set(acia.alarm_rx, acia.alarm_clk_rx); + acia.alarm_active_rx = 1; + } + + /* + * this is new with VICE 2.0.9; thus, only use the settings + * if it does exist. + */ + if (SMR_CLOCK(m, &qword2) >= 0) { + if (qword2) { + acia.alarm_clk_rx = myclk + qword2; + alarm_set(acia.alarm_rx, acia.alarm_clk_rx); + acia.alarm_active_rx = 1; + } else { + alarm_unset(acia.alarm_rx); + acia.alarm_active_rx = 0; + } + } + + return snapshot_module_close(m); } /*! \brief write the ACIA register values - This function is used to write the ACIA values from the computer. - - \param addr - The address of the ACIA register to write - - \param byte - The value to set the register to - */ -void myacia_store(WORD addr, BYTE byte) + This function is used to write the ACIA values from the computer. + + \param addr + The address of the ACIA register to write + + \param byte + The value to set the register to +*/ +void myacia_store(uint16_t addr, uint8_t byte) { - int acia_register_size; - - DEBUG_LOG_MESSAGE((acia.log, "store_myacia(%04x,%02x)", addr, byte)); - - if (mycpu_rmw_flag) { - myclk--; - mycpu_rmw_flag = 0; - myacia_store(addr, acia.last_read); - myclk++; - } - - if (acia.mode == ACIA_MODE_TURBO232) { - acia_register_size = 7; - } else { - acia_register_size = 3; - } - - switch (addr & acia_register_size) { - case ACIA_DR: - acia.txdata = byte; - if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) { - if (acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) { - log_message(acia.log, "ACIA: data register written " - "although data has not been sent yet."); - } - acia.in_tx = ACIA_TX_STATE_DR_WRITTEN; - if (acia.alarm_active_tx == 0) { - acia.alarm_clk_tx = myclk + 1; - alarm_set(acia.alarm_tx, acia.alarm_clk_tx); - acia.alarm_active_tx = 1; - } - acia.status &= ~ACIA_SR_BITS_TRANSMIT_DR_EMPTY; /* clr TDRE */ - } - break; - case ACIA_SR: - /* According the CSG and WDC data sheets, this is a programmed reset! */ - - if (acia.fd >= 0) { - rs232drv_close(acia.fd); - } - acia.fd = -1; - - acia.status &= ~ACIA_SR_BITS_OVERRUN_ERROR; - acia.cmd &= ACIA_CMD_BITS_PARITY_TYPE_MASK | ACIA_CMD_BITS_PARITY_ENABLED; - acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; - acia_set_int(acia.irq_type, acia.int_num, IK_NONE); - acia.irq = 0; - if (acia.alarm_tx) { - alarm_unset(acia.alarm_tx); - } - acia.alarm_active_tx = 0; - acia_set_handshake_lines(); - break; - case ACIA_CTRL: - acia.ctrl = byte; - set_acia_ticks(); - break; - case ACIA_CMD: - acia.cmd = byte; - acia_set_handshake_lines(); - if ((acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && (acia.fd < 0)) { - acia.fd = rs232drv_open(acia.device); - /* enable RX alarm */ - acia.alarm_active_rx = 1; - set_acia_ticks(); - } else - if ((acia.fd >= 0) && !(acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ)) { - rs232drv_close(acia.fd); - alarm_unset(acia.alarm_tx); - acia.alarm_active_tx = 0; - acia.fd = -1; - } - break; - case T232_ECTRL: - if ((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) { - acia.ectrl = byte; - set_acia_ticks(); - } - } + int acia_register_size; + + DEBUG_LOG_MESSAGE((acia.log, "store_myacia(%04x,%02x)", addr, byte)); + + if (mycpu_rmw_flag) { + myclk--; + mycpu_rmw_flag = 0; + myacia_store(addr, acia.last_read); + myclk++; + } + + if (acia.mode == ACIA_MODE_TURBO232) { + acia_register_size = 7; + } else { + acia_register_size = 3; + } + + switch (addr & acia_register_size) { + case ACIA_DR: + acia.txdata = byte; + if (acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) { + if (acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) { + log_message(acia.log, "ACIA: data register written " + "although data has not been sent yet."); + } + DEBUG_LOG_MESSAGE((acia.log, "DR write at %d: 0x%02x", myclk, acia.txdata)); + acia.in_tx = ACIA_TX_STATE_DR_WRITTEN; + if (acia.alarm_active_tx == 0) { + acia.alarm_clk_tx = myclk + 1; + alarm_set(acia.alarm_tx, acia.alarm_clk_tx); + acia.alarm_active_tx = 1; + } + acia.status &= ~ACIA_SR_BITS_TRANSMIT_DR_EMPTY; /* clr TDRE */ + } + break; + case ACIA_SR: + /* According the CSG and WDC data sheets, this is a programmed reset! */ + + if ((acia.fd >= 0) && !rs232_useip232[acia.device]) { + rs232drv_close(acia.fd); + acia.fd = -1; + } + + /* Status Register programmed reset = xxxxx0xx */ + acia.status &= ~ACIA_SR_BITS_OVERRUN_ERROR; + /* Command Register programmed reset = xxx00000 */ + acia.cmd &= ACIA_CMD_BITS_PARITY_TYPE_MASK | ACIA_CMD_BITS_PARITY_ENABLED; + /* This bit is set only in the MOS 6551, not the Rockwell 6551 or the 65c51 versions */ + /* acia.cmd |= ACIA_CMD_BITS_IRQ_DISABLED; */ + + acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; + acia_set_int(acia.irq_type, acia.int_num, IK_NONE); + acia.irq = 0; + if (acia.alarm_tx) { + alarm_unset(acia.alarm_tx); + } + acia.alarm_active_tx = 0; + acia_set_handshake_lines(); + break; + case ACIA_CTRL: + acia.ctrl = byte; + set_acia_ticks(); + break; + case ACIA_CMD: + acia.cmd = byte; + if ((acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && (acia.fd < 0)) { + acia.fd = rs232drv_open(acia.device); + /* enable RX alarm */ + acia.alarm_active_rx = 1; + set_acia_ticks(); + /* Set Tx alarm if Tx IRQs are enabled */ + if ((acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) == ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ) { + acia.alarm_clk_tx = myclk + acia.ticks; + alarm_set(acia.alarm_tx, acia.alarm_clk_tx); + acia.alarm_active_tx = 1; + acia.in_tx = ACIA_TX_STATE_NO_TRANSMIT; + } + } else + if ((acia.fd >= 0) && !(acia.cmd & ACIA_CMD_BITS_DTR_ENABLE_RECV_AND_IRQ) && !rs232_useip232[acia.device]) { + rs232drv_close(acia.fd); + alarm_unset(acia.alarm_tx); + acia.alarm_active_tx = 0; + acia.fd = -1; + } + /* Moved here so rs232drv status is always updated */ + acia_set_handshake_lines(); + break; + case T232_ECTRL: + if ((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) { + acia.ectrl = byte; + set_acia_ticks(); + } + } } /*! \brief read the ACIA register values - - This function is used to read the ACIA values from the computer. - All side-effects are executed. - - \param addr - The address of the ACIA register to read - - \return - The value the register has - */ -BYTE myacia_read(WORD addr) + + This function is used to read the ACIA values from the computer. + All side-effects are executed. + + \param addr + The address of the ACIA register to read + + \return + The value the register has +*/ +uint8_t myacia_read(uint16_t addr) { #if 0 /* def DEBUG */ - static BYTE myacia_read_(WORD); - BYTE byte = myacia_read_(addr); - static WORD last_addr = 0; - static BYTE last_byte = 0; - - if ((addr != last_addr) || (byte != last_byte)) { - DEBUG_LOG_MESSAGE((acia.log, "read_myacia(%04x) -> %02x", addr, byte)); - } - last_addr = addr; last_byte = byte; - return byte; + static uint8_t myacia_read_(uint16_t); + uint8_t byte = myacia_read_(addr); + static uint16_t last_addr = 0; + static uint8_t last_byte = 0; + + if ((addr != last_addr) || (byte != last_byte)) { + DEBUG_LOG_MESSAGE((acia.log, "read_myacia(%04x) -> %02x", addr, byte)); + } + last_addr = addr; last_byte = byte; + return byte; } -static BYTE myacia_read_(WORD addr) +static uint8_t myacia_read_(uint16_t addr) { #endif - int acia_register_size; - - if (acia.mode == ACIA_MODE_TURBO232) { - acia_register_size = 7; - } else { - acia_register_size = 3; - } - - switch (addr & acia_register_size) { - case ACIA_DR: - acia.status &= ~ACIA_SR_BITS_RECEIVE_DR_FULL; - acia.last_read = acia.rxdata; - return acia.rxdata; - case ACIA_SR: - { - BYTE c = acia_get_status() | (acia.irq ? ACIA_SR_BITS_IRQ : 0); - acia_set_int(acia.irq_type, acia.int_num, IK_NONE); - acia.irq = 0; - acia.last_read = c; - return c; - } - case ACIA_CTRL: - acia.last_read = acia.ctrl; - return acia.ctrl; - case ACIA_CMD: - acia.last_read = acia.cmd; - return acia.cmd; - case T232_NDEF1: - case T232_NDEF2: - case T232_NDEF3: - return 0xff; - case T232_ECTRL: - return acia.ectrl - + (((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) - ? T232_ECTRL_BITS_EXT_ACTIVE - : 0); - } - /* should never happen */ - return 0; + int acia_register_size; + + if (acia.mode == ACIA_MODE_TURBO232) { + acia_register_size = 7; + } else { + acia_register_size = 3; + } + + switch (addr & acia_register_size) { + case ACIA_DR: + DEBUG_LOG_MESSAGE((acia.log, "DR read at %d: 0x%02x", myclk, acia.rxdata)); + acia.status &= ~(ACIA_SR_BITS_OVERRUN_ERROR | ACIA_SR_BITS_PARITY_ERROR | ACIA_SR_BITS_FRAMING_ERROR | ACIA_SR_BITS_RECEIVE_DR_FULL); + acia.last_read = acia.rxdata; + return acia.rxdata; + case ACIA_SR: + { + uint8_t c = acia_get_status() | (acia.irq ? ACIA_SR_BITS_IRQ : 0); + DEBUG_LOG_MESSAGE((acia.log, "SR read at %d: 0x%02x", myclk,c)); + acia_set_int(acia.irq_type, acia.int_num, IK_NONE); + acia.irq = 0; + acia.last_read = c; + return c; + } + case ACIA_CTRL: + acia.last_read = acia.ctrl; + return acia.ctrl; + case ACIA_CMD: + acia.last_read = acia.cmd; + return acia.cmd; + case T232_NDEF1: + case T232_NDEF2: + case T232_NDEF3: + return 0xff; + case T232_ECTRL: + return acia.ectrl + + (((acia.ctrl & ACIA_CTRL_BITS_BPS_MASK) == ACIA_CTRL_BITS_BPS_16X_EXT_CLK) + ? T232_ECTRL_BITS_EXT_ACTIVE + : 0); + } + /* should never happen */ + return 0; } /*! \brief read the ACIA register values without side effects - This function reads the ACIA values, so they can be accessed like - an array of bytes. No side-effects that would be performed if a real - read access would occur are executed. - - \param addr - The address of the ACIA register to read - - \return - The value the register has - - \todo - Currently unused - */ -BYTE myacia_peek(WORD addr) + This function reads the ACIA values, so they can be accessed like + an array of bytes. No side-effects that would be performed if a real + read access would occur are executed. + + \param addr + The address of the ACIA register to read + + \return + The value the register has +*/ +uint8_t myacia_peek(uint16_t addr) { - switch (addr & 3) { - case ACIA_DR: - return acia.rxdata; - case ACIA_SR: - { - BYTE c = acia.status | (acia.irq ? ACIA_SR_BITS_IRQ : 0); - return c; - } - case ACIA_CTRL: - return acia.ctrl; - case ACIA_CMD: - return acia.cmd; - } - return 0; + switch (addr & 3) { + case ACIA_DR: + return acia.rxdata; + case ACIA_SR: + { + uint8_t c = acia.status | (acia.irq ? ACIA_SR_BITS_IRQ : 0); + return c; + } + case ACIA_CTRL: + return acia.ctrl; + case ACIA_CMD: + return acia.cmd; + } + return 0; } /******************************************************************/ @@ -1183,51 +1250,49 @@ BYTE myacia_peek(WORD addr) For the acia implementation, this is always NULL. \remark - If we just transmitted a value, the alarm is re-scheduled for - the time when the transmission has completed. This way, we - ensure that we do not send out faster than a real ACIA could - do. - - \todo - If no transmit is in progress (in_tx == ACIA_TX_STATE_NO_TRANSMIT), - it is not necessary to schedule a new alarm. - */ + If we just transmitted a value, the alarm is re-scheduled for + the time when the transmission has completed. This way, we + ensure that we do not send out faster than a real ACIA could + do. + +*/ static void int_acia_tx(CLOCK offset, void *data) { - DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_tx(offset=%ld, myclk=%d", offset, myclk)); - - assert(data == NULL); - - if ((acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) && (acia.fd >= 0)) { - rs232drv_putc(acia.fd, acia.txdata); - - /* tell the status register that the transmit register is empty */ - acia.status |= ACIA_SR_BITS_TRANSMIT_DR_EMPTY; - - /* generate an interrupt if the ACIA was programmed to generate one */ - if ((acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) == ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ) { - acia_set_int(acia.irq_type, acia.int_num, acia.irq_type); - acia.irq = 1; - } - } - - if (acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) { - /* - * ACIA_TX_STATE_DR_WRITTEN is decremented to ACIA_TX_STATE_TX_STARTED - * ACIA_TX_STATE_TX_STARTED is decremented to ACIA_TX_STATE_NO_TRANSMIT - */ - acia.in_tx--; - } - - if (acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) { - /* re-schedule alarm */ - acia.alarm_clk_tx = myclk + acia.ticks; - alarm_set(acia.alarm_tx, acia.alarm_clk_tx); - acia.alarm_active_tx = 1; - } else { - alarm_unset(acia.alarm_tx); - acia.alarm_active_tx = 0; - } + DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_tx(offset=%ld, myclk=%d", offset, myclk)); + + assert(data == NULL); + + if ((acia.in_tx == ACIA_TX_STATE_DR_WRITTEN) && (acia.fd >= 0)) { + rs232drv_putc(acia.fd, acia.txdata & acia.datamask); + + /* tell the status register that the transmit register is empty */ + acia.status |= ACIA_SR_BITS_TRANSMIT_DR_EMPTY; + } + + /* generate an interrupt if the ACIA was programmed to generate one */ + /* interrupt will occur everytime even if no data was transmitted */ + if ((acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) == ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ) { + acia_set_int(acia.irq_type, acia.int_num, acia.irq_type); + acia.irq = 1; + } + + if (acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) { + /* + * ACIA_TX_STATE_DR_WRITTEN is decremented to ACIA_TX_STATE_TX_STARTED + * ACIA_TX_STATE_TX_STARTED is decremented to ACIA_TX_STATE_NO_TRANSMIT + */ + acia.in_tx--; + } + + if ((acia.in_tx != ACIA_TX_STATE_NO_TRANSMIT) || ((acia.cmd & ACIA_CMD_BITS_TRANSMITTER_MASK) == ACIA_CMD_BITS_TRANSMITTER_TX_WITH_IRQ)) { + /* re-schedule alarm */ + acia.alarm_clk_tx = myclk + acia.ticks; + alarm_set(acia.alarm_tx, acia.alarm_clk_tx); + acia.alarm_active_tx = 1; + } else { + alarm_unset(acia.alarm_tx); + acia.alarm_active_tx = 0; + } } /*! \internal \brief Receive (RX) alarm function @@ -1256,56 +1321,105 @@ static void int_acia_tx(CLOCK offset, void *data) */ static void int_acia_rx(CLOCK offset, void *data) { - DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_rx(offset=%ld, myclk=%d", offset, myclk)); - - assert(data == NULL); - - do { - BYTE received_byte; - - if (acia.fd < 0) { - break; - } - - if (!rs232drv_getc(acia.fd, &received_byte)) { - break; - } - - DEBUG_LOG_MESSAGE((acia.log, "received byte: %u = '%c'.", - (unsigned) received_byte, received_byte)); - - /*! \todo: What happens on the real 6551? Is the old value overwritten in - * case of an overrun, or is it not? - */ - acia.rxdata = received_byte; - - /* generate an interrupt if the ACIA was configured to generate one */ - if (!(acia.cmd & ACIA_CMD_BITS_IRQ_DISABLED)) { - acia_set_int(acia.irq_type, acia.int_num, acia.irq_type); - acia.irq = 1; - } - - if (acia.status & ACIA_SR_BITS_RECEIVE_DR_FULL) { - acia.status |= ACIA_SR_BITS_OVERRUN_ERROR; - break; - } - - acia.status |= ACIA_SR_BITS_RECEIVE_DR_FULL; - } while (0); - - - acia.alarm_clk_rx = myclk + acia.ticks_rx; - alarm_set(acia.alarm_rx, acia.alarm_clk_rx); - acia.alarm_active_rx = 1; + DEBUG_VERBOSE_LOG_MESSAGE((acia.log, "int_acia_rx(offset=%ld, myclk=%d", offset, myclk)); + + assert(data == NULL); + + do { + uint8_t received_byte; + + if (acia.fd < 0) { + break; + } + + if (!rs232drv_getc(acia.fd, &received_byte)) { + break; + } + + DEBUG_LOG_MESSAGE((acia.log, "received byte: %u = '%c'.", + (unsigned) received_byte, received_byte)); + + /* Datasheet (https://downloads.reactivemicro.com/Electronics/Interface%20Adapters/R65C51.pdf) + * says that new data is discarded on overrun */ + if (!(acia.status & ACIA_SR_BITS_RECEIVE_DR_FULL)) { + acia.rxdata = received_byte & acia.datamask; + } else { + acia.status |= ACIA_SR_BITS_OVERRUN_ERROR; + DEBUG_LOG_MESSAGE((acia.log, "Overrun! Discarding received byte", + (unsigned) acia.rxdata, acia.rxdata)); + } + + /* generate an interrupt if the ACIA was configured to generate one */ + if (!(acia.cmd & ACIA_CMD_BITS_IRQ_DISABLED)) { + acia_set_int(acia.irq_type, acia.int_num, acia.irq_type); + acia.irq = 1; + } + + + acia.status |= ACIA_SR_BITS_RECEIVE_DR_FULL; + } while (0); + + if (acia.alarm_active_rx == 1) { + acia.alarm_clk_rx = myclk + acia.ticks; + alarm_set(acia.alarm_rx, acia.alarm_clk_rx); + /*acia.alarm_active_rx = 1;*/ + } else { + alarm_unset(acia.alarm_rx); + } } -int acia_dump(void *acia_context) +int acia_dump(void) { - /* FIXME: dump details using mon_out(), return 0 on success */ - return -1; + uint8_t st; + uint8_t wl; + char* sb; + const char* parity = "NONENMNS"; + char p; + + /* Status register */ + st = myacia_peek(0x01); + /* Word length */ + wl = 8 - ((myacia_peek(0x03) & 0x60) >> 5); + /* Parity bit */ + p = parity[(myacia_peek(0x02) & 0xE0) >> 5]; + /* Stop bit(s) */ + if (myacia_peek(0x03) & 0x80) { + switch (wl) { + case 8: + if (p != 'N') { + sb = "1"; + } else { + sb = "2"; + } + break; + case 5: + if (p == 'N') { + sb = "1.5"; + } else { + sb = "2"; + } + break; + default: + sb = "2"; + } + } else { + sb = "1"; + } + + mon_out("Receive Interrupt: %s\n", (myacia_peek(0x02) & 0x02) ? "off" : "on"); + mon_out("DR Rx: %02x Status: %s\t%s\t%s\t%s\n", myacia_peek(0x00), (st & 0x08) ? "[Full]" : "[Not Full]", (st & 0x01) ? "[Parity Error]" : "", + (st & 0x02) ? "[Framming Error]" : "", (st & 0x04) ? "[Overrun]" : ""); + mon_out("\nTransmit Interrupt: %s\n", ((myacia_peek(0x02) & 0x0c) == 0x04) ? "on" : "off"); + mon_out("DR Tx: %02x Status: %s\n", acia.txdata, (st & 0x10) ? "[Empty]" : "[Not Empty]"); + mon_out("\nRTS: %s\tDTR: %s\n", (myacia_peek(0x02) & 0x0c) ? "Low" : "High", (myacia_peek(0x02) & 0x01) ? "Low" : "High"); + mon_out("DCD: %s\tDSR: %s\n", (st & 0x20) ? "High" : "Low", (st & 0x40) ? "High" : "Low"); + mon_out("\nSpeed/format: %g bps / %u-%c-%s\n", get_acia_bps(), wl, p, sb); + mon_out("Echo: %s\n", (myacia_peek(0x02) & 0x10) ? "On" : "Off"); + return 0; } + ////// aciacore.c ends here /// /// @@ -1324,23 +1438,26 @@ static char *acia_base_list = NULL; /* ------------------------------------------------------------------------- */ #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) -/* a prototype is needed */ -static BYTE aciacart_read(WORD addr); -static BYTE aciacart_peek(WORD addr); + +/* a prototype is needed (not anymore) */ +uint8_t aciacart_read(uint16_t addr); +uint8_t aciacart_peek(uint16_t addr); static io_source_t acia_device = { - CARTRIDGE_NAME_ACIA, - IO_DETACH_RESOURCE, - "Acia1Enable", - 0xde00, 0xde07, 0x07, - 0, - acia1_store, - aciacart_read, - aciacart_peek, - NULL, /* TODO: dump */ - CARTRIDGE_ACIA, - 0, - 0 + CARTRIDGE_NAME_ACIA, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "Acia1Enable", /* resource to set to '0' */ + 0xde00, 0xde07, 0x07, /* range for the device, can be changed to other ranges */ + 0, /* read validity is determined by the device upon a read */ + acia1_store, /* store function */ + NULL, /* NO poke function */ + aciacart_read, /* read function */ + aciacart_peek, /* peek function */ + acia_dump, /* device state information dump function */ + CARTRIDGE_ACIA, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *acia_list_item = NULL; @@ -1442,6 +1559,7 @@ static int set_acia_enabled(int value, void *param) return -1; } acia_enabled = 1; + acia1_reset(); } else if ((!val) && (acia_enabled)) { acia1_disable(); acia_enabled = 0; @@ -1507,14 +1625,15 @@ int acia1_set_mode(int mode) /* ------------------------------------------------------------------------- */ #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) -static const resource_int_t resources_i[] = { +static resource_int_t resources_i[] = { { "Acia1Enable", 0, RES_EVENT_STRICT, 0, &acia_enabled, set_acia_enabled, NULL }, { "Acia1Irq", MyIrq, RES_EVENT_NO, NULL, &acia.irq_res, acia_set_irq, NULL }, - { "Acia1Mode", ACIA_MODE_NORMAL, RES_EVENT_NO, NULL, + { "Acia1Mode", ACIA_MODE_SWIFTLINK, RES_EVENT_NO, NULL, &acia.mode, acia_set_mode, NULL }, - { "Acia1Base", 0xffff, RES_EVENT_STRICT, int_to_void_ptr(0xffff), + /* CAUTION: position is hardcoded below */ + { "Acia1Base", 0xffff, RES_EVENT_STRICT, vice_int_to_ptr(0xffff), &acia_base, set_acia_base, NULL }, RESOURCE_INT_LIST_END }; @@ -1523,6 +1642,17 @@ static const resource_int_t resources_i[] = { int aciacart_resources_init(void) { #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) + /* Set the default factory value depending on the machine. We do this + here so the default value will not end up in the config file. */ + switch (machine_class) { + case VICE_MACHINE_VIC20: + resources_i[3].factory_value = 0x9800; + break; + default: + resources_i[3].factory_value = 0xde00; + break; + } + if (acia1_resources_init() < 0) { return -1; } @@ -1544,7 +1674,7 @@ void aciacart_resources_shutdown(void) /* ------------------------------------------------------------------------- */ #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) -static BYTE aciacart_read(WORD addr) +uint8_t aciacart_read(uint16_t addr) { acia_device.io_source_valid = 0; if (acia.mode == ACIA_MODE_TURBO232 && (addr & 7 ) > 3 && (addr & 7) != 7) { @@ -1554,7 +1684,7 @@ static BYTE aciacart_read(WORD addr) return myacia_read(addr); } -static BYTE aciacart_peek(WORD addr) +uint8_t aciacart_peek(uint16_t addr) { if (acia.mode == ACIA_MODE_TURBO232 && (addr & 7 ) > 3 && (addr & 7) != 7) { return 0; @@ -1580,14 +1710,10 @@ static const cmdline_option_t cart_cmdline_options[] = { { "-acia1irq", SET_RESOURCE, 1, NULL, NULL, "Acia1Irq", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_IRQ, IDCLS_SET_ACIA_IRQ, - NULL, NULL }, + "", "Set the ACIA interrupt (0: None, 1: NMI, 2: IRQ)" }, { "-acia1mode", SET_RESOURCE, 1, NULL, NULL, "Acia1Mode", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODE, IDCLS_SET_ACIA_MODE, - NULL, NULL }, + "", "Set the ACIA mode (0: Normal, 1: Swiftlink, 2: Turbo232)" }, CMDLINE_LIST_END }; @@ -1595,9 +1721,7 @@ static cmdline_option_t base_cmdline_options[] = { { "-acia1base", SET_RESOURCE, 1, NULL, NULL, "Acia1Base", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_SET_ACIA_BASE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; #endif @@ -1606,11 +1730,11 @@ int aciacart_cmdline_options_init(void) { #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) if (machine_class == VICE_MACHINE_C128) { - acia_base_list = lib_stralloc(". (0xD700, 0xDE00, 0xDF00)"); + acia_base_list = lib_strdup("Set the base address of the ACIA cartridge. (0xD700, 0xDE00, 0xDF00)"); } else if (machine_class == VICE_MACHINE_VIC20) { - acia_base_list = lib_stralloc(". (0x9800, 0x9C00)"); + acia_base_list = lib_strdup("Set the base address of the ACIA cartridge. (0x9800, 0x9C00)"); } else { - acia_base_list = lib_stralloc(". (0xDE00, 0xDF00)"); + acia_base_list = lib_strdup("Set the base address of the ACIA cartridge. (0xDE00, 0xDF00)"); } base_cmdline_options[0].description = acia_base_list; @@ -1645,6 +1769,17 @@ int aciacart_enable(void) #endif } + +int aciacart_disable(void) +{ +#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) + return set_acia_enabled(0, NULL); +#else + return 0; +#endif +} + + /* ------------------------------------------------------------------------- */ int aciacart_snapshot_write_module(struct snapshot_s *p) diff --git a/src/Emulators/vice/c64/cart/c64cart.c b/src/Emulators/vice/c64/cart/c64cart.c index c8e3b717..510e3315 100644 --- a/src/Emulators/vice/c64/cart/c64cart.c +++ b/src/Emulators/vice/c64/cart/c64cart.c @@ -54,9 +54,97 @@ #include "mem.h" #include "monitor.h" #include "resources.h" -#include "translate.h" #include "util.h" +#define CARTRIDGE_INCLUDE_PRIVATE_API +#include "actionreplay.h" +#include "actionreplay2.h" +#include "actionreplay3.h" +#include "actionreplay4.h" +#include "atomicpower.h" +#include "bisplus.h" +#include "blackbox3.h" +#include "blackbox4.h" +#include "blackbox8.h" +#include "blackbox9.h" +#include "bmpdataturbo.h" +#include "c64-generic.h" +#include "c64tpi.h" +#include "comal80.h" +#include "capture.h" +#include "delaep256.h" +#include "delaep64.h" +#include "delaep7x8.h" +#include "diashowmaker.h" +#include "dinamic.h" +#include "drean.h" +#include "easycalc.h" +#include "easyflash.h" +#include "epyxfastload.h" +#include "exos.h" +#include "expert.h" +#include "final.h" +#include "finalplus.h" +#include "final3.h" +#include "formel64.h" +#include "freezeframe.h" +#include "freezeframe2.h" +#include "freezemachine.h" +#include "funplay.h" +#include "gamekiller.h" +#include "gmod2.h" +#include "gmod3.h" +#include "gs.h" +#include "hyperbasic.h" +#include "ide64.h" +#include "ieeeflash64.h" +#include "isepic.h" +#include "kcs.h" +#include "kingsoft.h" +#include "ltkernal.h" +#include "mach5.h" +#include "magicdesk.h" +#include "magicdesk16.h" +#include "magicformel.h" +#include "magicvoice.h" +#include "maxbasic.h" +#include "megabyter.h" +#include "mikroass.h" +#include "mmc64.h" +#include "mmcreplay.h" +#include "multimax.h" +#include "ocean.h" +#include "pagefox.h" +#include "partner64.h" +#include "prophet64.h" +#include "profidos.h" +#include "ramlink.h" +#include "retroreplay.h" +#include "rexep256.h" +#include "rexramfloppy.h" +#include "rexutility.h" +#include "rgcd.h" +#include "rrnetmk3.h" +#include "ross.h" +#include "sdbox.h" +#include "silverrock128.h" +#include "simonsbasic.h" +#include "stardos.h" +#include "stb.h" +#include "snapshot64.h" +#include "supergames.h" +#include "supersnapshot4.h" +#include "supersnapshot.h" +#include "superexplode5.h" +#include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" +#include "warpspeed.h" +#include "westermann.h" +#include "zaxxon.h" +#include "zippcode48.h" +#undef CARTRIDGE_INCLUDE_PRIVATE_API + /* #define DEBUGCART */ #ifdef DEBUGCART @@ -86,7 +174,8 @@ mmc64 Magic Voice ieee488 - (ramlink, scpu, ...) + ramlink + (scpu, ...) "Slot 1" - other ROM/RAM carts that can be enabled individually @@ -126,6 +215,9 @@ cartridge. */ +/* pointer to access c128 specific functions in x128 */ +c128cartridge_interface_t *c128cartridge = NULL; + /* global options for the cart system */ static int c64cartridge_reset; /* (resource) hardreset system after cart was attached/detached */ @@ -147,6 +239,7 @@ CLOCK cart_freeze_alarm_time = CLOCK_MAX; /* cartridge freeze button alarm time /* Type of the cartridge attached. ("Main Slot") */ int mem_cartridge_type = CARTRIDGE_NONE; +/* CAUTION: keep in sync with the list in c128/c128cart.c */ static cartridge_info_t cartlist[] = { /* standard cartridges with CRT ID = 0 */ { CARTRIDGE_NAME_GENERIC_8KB, CARTRIDGE_GENERIC_8KB, CARTRIDGE_GROUP_GENERIC }, @@ -159,6 +252,12 @@ static cartridge_info_t cartlist[] = { { CARTRIDGE_NAME_ACTION_REPLAY3, CARTRIDGE_ACTION_REPLAY3, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_ACTION_REPLAY4, CARTRIDGE_ACTION_REPLAY4, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_ATOMIC_POWER, CARTRIDGE_ATOMIC_POWER, CARTRIDGE_GROUP_FREEZER }, + { CARTRIDGE_NAME_BISPLUS, CARTRIDGE_BISPLUS, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_BLACKBOX3, CARTRIDGE_BLACKBOX3, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_BLACKBOX4, CARTRIDGE_BLACKBOX4, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_BLACKBOX8, CARTRIDGE_BLACKBOX8, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_BLACKBOX9, CARTRIDGE_BLACKBOX9, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_BMPDATATURBO, CARTRIDGE_BMPDATATURBO, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_CAPTURE, CARTRIDGE_CAPTURE, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_COMAL80, CARTRIDGE_COMAL80, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_DELA_EP256, CARTRIDGE_DELA_EP256, CARTRIDGE_GROUP_UTIL }, @@ -166,6 +265,7 @@ static cartridge_info_t cartlist[] = { { CARTRIDGE_NAME_DELA_EP7x8, CARTRIDGE_DELA_EP7x8, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_DIASHOW_MAKER, CARTRIDGE_DIASHOW_MAKER, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_DINAMIC, CARTRIDGE_DINAMIC, CARTRIDGE_GROUP_GAME }, + { CARTRIDGE_NAME_DREAN, CARTRIDGE_DREAN, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_EASYCALC, CARTRIDGE_EASYCALC, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_EASYFLASH, CARTRIDGE_EASYFLASH, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_EPYX_FASTLOAD, CARTRIDGE_EPYX_FASTLOAD, CARTRIDGE_GROUP_UTIL }, @@ -176,33 +276,49 @@ static cartridge_info_t cartlist[] = { { CARTRIDGE_NAME_FINAL_PLUS, CARTRIDGE_FINAL_PLUS, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_FORMEL64, CARTRIDGE_FORMEL64, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_FREEZE_FRAME, CARTRIDGE_FREEZE_FRAME, CARTRIDGE_GROUP_FREEZER }, + { CARTRIDGE_NAME_FREEZE_FRAME_MK2, CARTRIDGE_FREEZE_FRAME_MK2, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_FREEZE_MACHINE, CARTRIDGE_FREEZE_MACHINE, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_FUNPLAY, CARTRIDGE_FUNPLAY, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_GAME_KILLER, CARTRIDGE_GAME_KILLER, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_GMOD2, CARTRIDGE_GMOD2, CARTRIDGE_GROUP_GAME }, + { CARTRIDGE_NAME_GMOD3, CARTRIDGE_GMOD3, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_GS, CARTRIDGE_GS, CARTRIDGE_GROUP_GAME }, + { CARTRIDGE_NAME_HYPERBASIC, CARTRIDGE_HYPERBASIC, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_IDE64, CARTRIDGE_IDE64, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_IEEE488, CARTRIDGE_IEEE488, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_IEEEFLASH64, CARTRIDGE_IEEEFLASH64, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_KCS_POWER, CARTRIDGE_KCS_POWER, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_KINGSOFT, CARTRIDGE_KINGSOFT, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_LT_KERNAL, CARTRIDGE_LT_KERNAL, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_MACH5, CARTRIDGE_MACH5, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_MAGIC_DESK, CARTRIDGE_MAGIC_DESK, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_MAGIC_FORMEL, CARTRIDGE_MAGIC_FORMEL, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_MAGIC_VOICE, CARTRIDGE_MAGIC_VOICE, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_MAX_BASIC, CARTRIDGE_MAX_BASIC, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_MEGABYTER, CARTRIDGE_MEGABYTER, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_MIKRO_ASSEMBLER, CARTRIDGE_MIKRO_ASSEMBLER, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_MMC64, CARTRIDGE_MMC64, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_MMC_REPLAY, CARTRIDGE_MMC_REPLAY, CARTRIDGE_GROUP_FREEZER }, + { CARTRIDGE_NAME_MULTIMAX, CARTRIDGE_MULTIMAX, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_OCEAN, CARTRIDGE_OCEAN, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_P64, CARTRIDGE_P64, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_PAGEFOX, CARTRIDGE_PAGEFOX, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_PARTNER64, CARTRIDGE_PARTNER64, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_PROFIDOS, CARTRIDGE_PROFIDOS, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_RAMLINK, CARTRIDGE_RAMLINK, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_RETRO_REPLAY, CARTRIDGE_RETRO_REPLAY, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_REX, CARTRIDGE_REX, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_REX_EP256, CARTRIDGE_REX_EP256, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_REX_RAMFLOPPY, CARTRIDGE_REX_RAMFLOPPY, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_RGCD, CARTRIDGE_RGCD, CARTRIDGE_GROUP_GAME }, -#ifdef HAVE_PCAP + { CARTRIDGE_NAME_UC1, CARTRIDGE_UC1, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_UC15, CARTRIDGE_UC15, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_UC2, CARTRIDGE_UC2, CARTRIDGE_GROUP_UTIL }, +#ifdef HAVE_RAWNET { CARTRIDGE_NAME_RRNETMK3, CARTRIDGE_RRNETMK3, CARTRIDGE_GROUP_UTIL }, #endif { CARTRIDGE_NAME_ROSS, CARTRIDGE_ROSS, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_SDBOX, CARTRIDGE_SDBOX, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_SILVERROCK_128, CARTRIDGE_SILVERROCK_128, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_SIMONS_BASIC, CARTRIDGE_SIMONS_BASIC, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_SNAPSHOT64, CARTRIDGE_SNAPSHOT64, CARTRIDGE_GROUP_FREEZER }, @@ -212,9 +328,11 @@ static cartridge_info_t cartlist[] = { { CARTRIDGE_NAME_SUPER_GAMES, CARTRIDGE_SUPER_GAMES, CARTRIDGE_GROUP_GAME }, { CARTRIDGE_NAME_SUPER_SNAPSHOT, CARTRIDGE_SUPER_SNAPSHOT, CARTRIDGE_GROUP_FREEZER }, { CARTRIDGE_NAME_SUPER_SNAPSHOT_V5, CARTRIDGE_SUPER_SNAPSHOT_V5, CARTRIDGE_GROUP_FREEZER }, + { CARTRIDGE_NAME_TURTLE_GRAPHICS_II, CARTRIDGE_TURTLE_GRAPHICS_II, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_WARPSPEED, CARTRIDGE_WARPSPEED, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_WESTERMANN, CARTRIDGE_WESTERMANN, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_ZAXXON, CARTRIDGE_ZAXXON, CARTRIDGE_GROUP_GAME }, + { CARTRIDGE_NAME_ZIPPCODE48, CARTRIDGE_ZIPPCODE48, CARTRIDGE_GROUP_UTIL }, /* cartridges that have only RAM, these do not have a CRT ID */ { CARTRIDGE_NAME_DQBB, CARTRIDGE_DQBB, CARTRIDGE_GROUP_RAMEX }, @@ -228,9 +346,51 @@ static cartridge_info_t cartlist[] = { cartridge_info_t *cartridge_get_info_list(void) { + if (machine_class == VICE_MACHINE_C128) { + return &c128cartridge->get_info_list()[0]; + } return &cartlist[0]; } +/* FIXME: slot arg is ignored right now. + this should return a valid cartridge ID for a given slot, or CARTRIDGE_NONE + FIXME: should we return CARTRIDGE_CRT(0) or not? +*/ +int cartridge_get_id(int slot) +{ + int type = cart_getid_slotmain(); + /* DBG(("cartridge_get_id(slot:%d): type:%d\n", slot, type)); */ + return type; +} + +/* FIXME: slot arg is ignored right now. + this should return a pointer to a filename, or NULL +*/ +char *cartridge_get_filename_by_slot(int slot) +{ + DBG(("cartridge_get_filename_by_slot(slot:%d)\n", slot)); +/* return cart_get_filename_by_type(mem_cartridge_type); */ + int type = cart_getid_slotmain(); + if (cart_getid_slotmain() == type) { + return cartfile; + } + log_error(LOG_DEFAULT, "FIXME: cartridge_get_filename_by_slot only works with main-slot"); + return NULL; +#if 0 + /* FIXME: this can not work right! */ + return (char*)cart_get_filename_by_type(type); +#endif +} + +/* FIXME: slot arg is ignored right now. + this should return a pointer to a filename, or NULL +*/ +char *cartridge_get_secondary_filename_by_slot(int slot) +{ + log_error(LOG_DEFAULT, "FIXME: cartridge_get_secondary_filename_by_slot not implemented yet"); + return NULL; +} + /* we have 3 resources for the main cart that may be changed in arbitrary order: @@ -239,17 +399,15 @@ cartridge_info_t *cartridge_get_info_list(void) - cartridge change reset behaviour the following functions try to deal with this in a hopefully sane way... however, - do _NOT_ change the used resources from the (G)UI directly. (used the set_default + do _NOT_ change the used resources from the (G)UI directly. (use the set_default function instead) */ static int try_cartridge_attach(int type, const char *filename) { - int crtid; - if (filename) { if (util_file_exists(filename)) { - if ((crtid = crt_getid(filename)) > 0) { + if (crt_getid(filename) >= 0) { cartridge_type = CARTRIDGE_CRT; /* resource value modified */ return cartridge_attach_image(CARTRIDGE_CRT, filename); } else if ((type != CARTRIDGE_NONE) && (type != CARTRIDGE_CRT)) { @@ -266,6 +424,7 @@ static int try_cartridge_attach(int type, const char *filename) static int set_cartridge_type(int val, void *param) { + DBG(("set_cartridge_type: %d\n", val)); switch (val) { case CARTRIDGE_ULTIMAX: case CARTRIDGE_GENERIC_8KB: @@ -278,6 +437,12 @@ static int set_cartridge_type(int val, void *param) case CARTRIDGE_ACTION_REPLAY3: case CARTRIDGE_ACTION_REPLAY4: case CARTRIDGE_ATOMIC_POWER: + case CARTRIDGE_BISPLUS: + case CARTRIDGE_BLACKBOX3: + case CARTRIDGE_BLACKBOX4: + case CARTRIDGE_BLACKBOX8: + case CARTRIDGE_BLACKBOX9: + case CARTRIDGE_BMPDATATURBO: case CARTRIDGE_CAPTURE: case CARTRIDGE_COMAL80: case CARTRIDGE_DELA_EP64: @@ -285,6 +450,7 @@ static int set_cartridge_type(int val, void *param) case CARTRIDGE_DELA_EP256: case CARTRIDGE_DIASHOW_MAKER: case CARTRIDGE_DINAMIC: + case CARTRIDGE_DREAN: case CARTRIDGE_EASYCALC: case CARTRIDGE_EASYFLASH: case CARTRIDGE_EASYFLASH_XBANK: @@ -296,31 +462,43 @@ static int set_cartridge_type(int val, void *param) case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: case CARTRIDGE_FREEZE_FRAME: + case CARTRIDGE_FREEZE_FRAME_MK2: case CARTRIDGE_FREEZE_MACHINE: case CARTRIDGE_FUNPLAY: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_GMOD2: + case CARTRIDGE_GMOD3: case CARTRIDGE_GS: + case CARTRIDGE_HYPERBASIC: case CARTRIDGE_IEEE488: + case CARTRIDGE_IEEEFLASH64: case CARTRIDGE_IDE64: case CARTRIDGE_KINGSOFT: case CARTRIDGE_KCS_POWER: case CARTRIDGE_MACH5: case CARTRIDGE_MAGIC_DESK: + case CARTRIDGE_MAGIC_DESK_16: case CARTRIDGE_MAGIC_FORMEL: case CARTRIDGE_MAGIC_VOICE: + case CARTRIDGE_MAX_BASIC: case CARTRIDGE_MIKRO_ASSEMBLER: case CARTRIDGE_MMC64: case CARTRIDGE_MMC_REPLAY: + case CARTRIDGE_MULTIMAX: case CARTRIDGE_OCEAN: case CARTRIDGE_P64: case CARTRIDGE_PAGEFOX: + case CARTRIDGE_PARTNER64: + case CARTRIDGE_PROFIDOS: + case CARTRIDGE_RAMLINK: case CARTRIDGE_RETRO_REPLAY: case CARTRIDGE_REX: case CARTRIDGE_REX_EP256: + case CARTRIDGE_REX_RAMFLOPPY: case CARTRIDGE_RGCD: case CARTRIDGE_RRNETMK3: case CARTRIDGE_ROSS: + case CARTRIDGE_SDBOX: case CARTRIDGE_SNAPSHOT64: case CARTRIDGE_SIMONS_BASIC: case CARTRIDGE_SILVERROCK_128: @@ -330,15 +508,28 @@ static int set_cartridge_type(int val, void *param) case CARTRIDGE_SUPER_GAMES: case CARTRIDGE_SUPER_SNAPSHOT: case CARTRIDGE_SUPER_SNAPSHOT_V5: + case CARTRIDGE_TURTLE_GRAPHICS_II: + case CARTRIDGE_UC1: + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: case CARTRIDGE_WARPSPEED: case CARTRIDGE_WESTERMANN: case CARTRIDGE_ZAXXON: break; default: - return -1; + /* FIXME: perhaps make this a call via the c128cartridge interface */ + if ((machine_class == VICE_MACHINE_C128) && ( + (val == CARTRIDGE_C128_MAKEID(CARTRIDGE_C128_GENERIC)) || + (val == CARTRIDGE_C128_MAKEID(CARTRIDGE_C128_WARPSPEED128)) || + (val == CARTRIDGE_C128_MAKEID(CARTRIDGE_C128_PARTNER128)) || + (val == CARTRIDGE_C128_MAKEID(CARTRIDGE_C128_COMAL80)) + )) { + break; + } else { + return -1; + } } -/* DBG(("cartridge_type: %d\n", val)); */ if (cartridge_type != val) { DBG(("cartridge_type changed: %d\n", val)); cartridge_type = val; @@ -450,22 +641,16 @@ int cart_attach_cmdline(const char *param, void *extra_param) static const cmdline_option_t cmdline_options[] = { /* hardreset on cartridge change */ - { "-cartreset", SET_RESOURCE, 0, + { "-cartreset", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "CartridgeReset", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_CART_ATTACH_DETACH_RESET, - NULL, NULL }, - { "+cartreset", SET_RESOURCE, 0, + NULL, "Reset machine if a cartridge is attached or detached" }, + { "+cartreset", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "CartridgeReset", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_CART_ATTACH_DETACH_NO_RESET, - NULL, NULL }, + NULL, "Do not reset machine if a cartridge is attached or detached" }, /* no cartridge */ - { "+cart", CALL_FUNCTION, 0, + { "+cart", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, cart_attach_cmdline, NULL, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_CART, - NULL, NULL }, + NULL, "Disable default cartridge" }, CMDLINE_LIST_END }; @@ -508,12 +693,12 @@ int cart_getid_slotmain(void) /* get filename of cart with given type */ -const char *cartridge_get_file_name(int type) +const char *cartridge_get_filename_by_type(int type) { if (cart_getid_slotmain() == type) { return cartfile; } - return cart_get_file_name(type); + return cart_get_filename_by_type(type); } /* @@ -529,6 +714,350 @@ int cartridge_type_enabled(int type) return cart_type_enabled(type); } +/* + returns -1 on error, else a positive CRT ID + + FIXME: to simplify this function a little bit, all subfunctions should + also return the respective CRT ID on success +*/ +static int crt_attach(const char *filename, uint8_t *rawcart) +{ + crt_header_t header; + int rc = -1, new_crttype; + FILE *fd; + + DBG(("crt_attach: %s\n", filename)); + + fd = crt_open(filename, &header); + if (fd == NULL) { + return -1; + } + + new_crttype = header.type; + + /* if we have loaded a C128 cartridge, convert the C128 crt id to something + else (that can coexist with C64 crt ids) */ + if (header.machine == VICE_MACHINE_C128) { + new_crttype = CARTRIDGE_C128_MAKEID(new_crttype); + } + + /* handle our negative test IDs */ + if (new_crttype & 0x8000) { + new_crttype -= 0x10000; + } + DBG(("crt_attach ID: %d\n", new_crttype)); + +/* cart should always be detached. there is no reason for doing fancy checks + here, and it will cause problems incase a cart MUST be detached before + attaching another, or even itself. (eg for initialization reasons) + + most obvious reason: attaching a different ROM (software) for the same + cartridge (hardware) */ + + cartridge_detach_image(new_crttype); + + /* now attach a crt image. note that for carts not in the main slot, the image + name is usually kept in a resource, and the cartridge is enabled via another + resource - the function called from here must also do this */ + if ((machine_class == VICE_MACHINE_C128) && (header.machine == VICE_MACHINE_C128)) { + DBG(("attaching as C128 cartridge id: %d\n", new_crttype)); + rc = c128cartridge->attach_crt(new_crttype, fd, filename, rawcart); + } else { + + switch (new_crttype) { + case CARTRIDGE_CRT: + rc = generic_crt_attach(fd, rawcart); + if (rc != CARTRIDGE_NONE) { + new_crttype = rc; + } + break; + case CARTRIDGE_ACTION_REPLAY: + rc = actionreplay_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ACTION_REPLAY2: + rc = actionreplay2_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ACTION_REPLAY3: + rc = actionreplay3_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ACTION_REPLAY4: + rc = actionreplay4_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ATOMIC_POWER: + rc = atomicpower_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BISPLUS: + rc = bisplus_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BLACKBOX3: + rc = blackbox3_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BLACKBOX4: + rc = blackbox4_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BLACKBOX8: + rc = blackbox8_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BLACKBOX9: + rc = blackbox9_crt_attach(fd, rawcart); + break; + case CARTRIDGE_BMPDATATURBO: + rc = bmpdataturbo_crt_attach(fd, rawcart); + break; + case CARTRIDGE_CAPTURE: + rc = capture_crt_attach(fd, rawcart); + break; + case CARTRIDGE_COMAL80: + rc = comal80_crt_attach(fd, rawcart, header.subtype); + break; + case CARTRIDGE_DELA_EP256: + rc = delaep256_crt_attach(fd, rawcart); + break; + case CARTRIDGE_DELA_EP64: + rc = delaep64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_DELA_EP7x8: + rc = delaep7x8_crt_attach(fd, rawcart); + break; + case CARTRIDGE_DIASHOW_MAKER: + rc = dsm_crt_attach(fd, rawcart); + break; + case CARTRIDGE_DINAMIC: + rc = dinamic_crt_attach(fd, rawcart); + break; +#if 0 + case CARTRIDGE_DQBB: /* slot 1 */ + rc = dqbb_crt_attach(fd, rawcart, filename); + break; +#endif + case CARTRIDGE_DREAN: + rc = drean_crt_attach(fd, rawcart); + break; + case CARTRIDGE_EASYCALC: + rc = easycalc_crt_attach(fd, rawcart); + break; + case CARTRIDGE_EASYFLASH: + rc = easyflash_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_EPYX_FASTLOAD: + rc = epyxfastload_crt_attach(fd, rawcart); + break; + case CARTRIDGE_EXOS: + rc = exos_crt_attach(fd, rawcart); + break; + case CARTRIDGE_EXPERT: /* slot 1 */ + rc = expert_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_FINAL_I: + rc = final_v1_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FINAL_III: + rc = final_v3_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FINAL_PLUS: + rc = final_plus_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FORMEL64: + rc = formel64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FREEZE_FRAME: + rc = freezeframe_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FREEZE_FRAME_MK2: + rc = freezeframe2_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FREEZE_MACHINE: + rc = freezemachine_crt_attach(fd, rawcart); + break; + case CARTRIDGE_FUNPLAY: + rc = funplay_crt_attach(fd, rawcart); + break; + case CARTRIDGE_GAME_KILLER: + rc = gamekiller_crt_attach(fd, rawcart); + break; + case CARTRIDGE_GMOD2: + rc = gmod2_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_GMOD3: + rc = gmod3_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_GS: + rc = gs_crt_attach(fd, rawcart); + break; + case CARTRIDGE_HYPERBASIC: + rc = hyperbasic_crt_attach(fd, rawcart); + break; + case CARTRIDGE_IDE64: + rc = ide64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_IEEE488: /* slot 0 */ + rc = tpi_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_IEEEFLASH64: /* slot 0 */ + rc = ieeeflash64_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_ISEPIC: /* slot 1 */ + rc = isepic_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_KCS_POWER: + rc = kcs_crt_attach(fd, rawcart); + break; + case CARTRIDGE_KINGSOFT: + rc = kingsoft_crt_attach(fd, rawcart); + break; + case CARTRIDGE_LT_KERNAL: + rc = ltkernal_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MACH5: + rc = mach5_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MAGIC_DESK: + rc = magicdesk_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MAGIC_DESK_16: + rc = magicdesk16_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MAGIC_FORMEL: + rc = magicformel_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MAGIC_VOICE: /* slot 0 */ + rc = magicvoice_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_MAX_BASIC: + rc = maxbasic_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MEGABYTER: + rc = megabyter_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_MIKRO_ASSEMBLER: + rc = mikroass_crt_attach(fd, rawcart); + break; + case CARTRIDGE_MMC64: /* slot 0 */ + rc = mmc64_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_MMC_REPLAY: + rc = mmcreplay_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_MULTIMAX: + rc = multimax_crt_attach(fd, rawcart); + break; + case CARTRIDGE_OCEAN: + rc = ocean_crt_attach(fd, rawcart); + break; + case CARTRIDGE_P64: + rc = p64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_PAGEFOX: + rc = pagefox_crt_attach(fd, rawcart); + break; + case CARTRIDGE_PARTNER64: + rc = partner64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_PROFIDOS: + rc = profidos_crt_attach(fd, rawcart); + break; + case CARTRIDGE_UC1: + rc = uc1_crt_attach(fd, rawcart); + break; + case CARTRIDGE_UC15: + rc = uc15_crt_attach(fd, rawcart); + break; + case CARTRIDGE_UC2: + rc = uc2_crt_attach(fd, rawcart); + break; +#if 0 + case CARTRIDGE_RAMCART: /* slot 1 */ + rc = ramcart_crt_attach(fd, rawcart, filename); + break; +#endif + case CARTRIDGE_RAMLINK: /* slot 0 */ + rc = ramlink_crt_attach(fd, rawcart, filename); + break; + case CARTRIDGE_RETRO_REPLAY: + rc = retroreplay_crt_attach(fd, rawcart, filename, header.subtype); + break; + case CARTRIDGE_REX_EP256: + rc = rexep256_crt_attach(fd, rawcart); + break; + case CARTRIDGE_REX: + rc = rex_crt_attach(fd, rawcart); + break; + case CARTRIDGE_REX_RAMFLOPPY: + rc = rexramfloppy_crt_attach(fd, rawcart); + break; + case CARTRIDGE_RGCD: + rc = rgcd_crt_attach(fd, rawcart, header.subtype); + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_RRNETMK3: + rc = rrnetmk3_crt_attach(fd, rawcart, filename); + break; +#endif + case CARTRIDGE_ROSS: + rc = ross_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SDBOX: + rc = sdbox_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SILVERROCK_128: + rc = silverrock128_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SIMONS_BASIC: + rc = simon_crt_attach(fd, rawcart); + break; + case CARTRIDGE_STARDOS: + rc = stardos_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SNAPSHOT64: + rc = snapshot64_crt_attach(fd, rawcart); + break; + case CARTRIDGE_STRUCTURED_BASIC: + rc = stb_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SUPER_GAMES: + rc = supergames_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SUPER_SNAPSHOT: + rc = supersnapshot_v4_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SUPER_SNAPSHOT_V5: + rc = supersnapshot_v5_crt_attach(fd, rawcart); + break; + case CARTRIDGE_SUPER_EXPLODE_V5: + rc = se5_crt_attach(fd, rawcart); + break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + rc = turtlegraphics_crt_attach(fd, rawcart); + break; + case CARTRIDGE_WARPSPEED: + rc = warpspeed_crt_attach(fd, rawcart); + break; + case CARTRIDGE_WESTERMANN: + rc = westermann_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ZAXXON: + rc = zaxxon_crt_attach(fd, rawcart); + break; + case CARTRIDGE_ZIPPCODE48: + rc = zippcode48_crt_attach(fd, rawcart); + break; + default: + archdep_startup_log_error("unknown CRT ID: %d\n", new_crttype); + rc = -1; + break; + } + } + + fclose(fd); + + if (rc == -1) { + DBG(("crt_attach error (%d)\n", rc)); + return -1; + } + DBG(("crt_attach return ID: %d\n", new_crttype)); + return new_crttype; +} + /* attach cartridge image @@ -539,7 +1068,7 @@ int cartridge_type_enabled(int type) */ int cartridge_attach_image(int type, const char *filename) { - BYTE *rawcart; + uint8_t *rawcart; char *abs_filename; int carttype = CARTRIDGE_NONE; int cartid = CARTRIDGE_NONE; @@ -558,7 +1087,7 @@ int cartridge_attach_image(int type, const char *filename) if (archdep_path_is_relative(filename)) { archdep_expand_path(&abs_filename, filename); } else { - abs_filename = lib_stralloc(filename); + abs_filename = lib_strdup(filename); } if (type == CARTRIDGE_CRT) { @@ -610,7 +1139,16 @@ int cartridge_attach_image(int type, const char *filename) } else { DBG(("CART: attach BIN ID: %d '%s'\n", carttype, filename)); cartid = carttype; - if (cart_bin_attach(carttype, abs_filename, rawcart) < 0) { + /* if this is x128 and the ID is a C128-only cart, use c128 specific function */ + DBG(("cartid: %d c128?:%d c128id:%d\n", cartid, (machine_class == VICE_MACHINE_C128), (CARTRIDGE_C128_ISID(cartid)) )); + if ((machine_class == VICE_MACHINE_C128) && (CARTRIDGE_C128_ISID(cartid))) { + DBG(("trying C128 exclusive function\n")); + if (c128cartridge->bin_attach(carttype, abs_filename, rawcart) < 0) { + DBG(("C128 exclusive function FAILED\n")); + goto exiterror; + } + DBG(("C128 exclusive function OK\n")); + } else if (cart_bin_attach(carttype, abs_filename, rawcart) < 0) { goto exiterror; } } @@ -653,11 +1191,17 @@ int cartridge_attach_image(int type, const char *filename) return -1; } +/* FIXME: add additional image to standard cartridge */ +int cartridge_attach_add_image(int type, const char *filename) +{ + return -1; +} + void cart_power_off(void) { if (c64cartridge_reset) { /* "Turn off machine before removing cartridge" */ - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } } @@ -727,6 +1271,10 @@ void cartridge_detach_image(int type) } } + if (machine_class == VICE_MACHINE_C128) { + c128cartridge->detach_image(type); + } + /* FIXME: cart_detach should take care of it */ DBG(("CART: unset cart config\n")); cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); @@ -764,9 +1312,19 @@ void cartridge_set_default(void) cartridge_type = type; /* resource value modified */ } + +/** \brief Wipe "default cartidge" + */ +void cartridge_unset_default(void) +{ + util_string_set(&cartridge_file, ""); + cartridge_type = CARTRIDGE_NONE; +} + + int cartridge_save_image(int type, const char *filename) { - char *ext = util_get_extension((char *)filename); + char *ext = util_get_extension(filename); if (ext != NULL && !strcmp(ext, "crt")) { return cartridge_crt_save(type, filename); } @@ -832,7 +1390,7 @@ static void cart_freeze_alarm_triggered(CLOCK offset, void *data) */ void cartridge_trigger_freeze(void) { - int delay = lib_unsigned_rand(1, machine_get_cycles_per_frame()); + int delay = lib_unsigned_rand(1, (unsigned int)machine_get_cycles_per_frame()); cart_freeze_alarm_time = maincpu_clk + delay; alarm_set(cartridge_freeze_alarm, cart_freeze_alarm_time); @@ -865,4 +1423,3 @@ void cartridge_init(void) cartridge_freeze_alarm = alarm_new(maincpu_alarm_context, "Cartridge", cart_freeze_alarm_triggered, NULL); cartridge_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "Cartridge"); } - diff --git a/src/Emulators/vice/c64/cart/c64carthooks.c b/src/Emulators/vice/c64/cart/c64carthooks.c index d2b845e4..5fbabd66 100644 --- a/src/Emulators/vice/c64/cart/c64carthooks.c +++ b/src/Emulators/vice/c64/cart/c64carthooks.c @@ -54,7 +54,6 @@ #include "monitor.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -64,6 +63,12 @@ #include "actionreplay4.h" #include "actionreplay.h" #include "atomicpower.h" +#include "bisplus.h" +#include "blackbox3.h" +#include "blackbox4.h" +#include "blackbox8.h" +#include "blackbox9.h" +#include "bmpdataturbo.h" #include "c64acia.h" #include "c64-generic.h" #include "c64-midi.h" @@ -78,6 +83,7 @@ #include "digimax.h" #include "dinamic.h" #include "dqbb.h" +#include "drean.h" #include "ds12c887rtc.h" #include "easycalc.h" #include "easyflash.h" @@ -89,37 +95,51 @@ #include "final3.h" #include "formel64.h" #include "freezeframe.h" +#include "freezeframe2.h" #include "freezemachine.h" #include "funplay.h" #include "gamekiller.h" #include "georam.h" #include "gs.h" #include "gmod2.h" +#include "gmod3.h" +#include "hyperbasic.h" #include "ide64.h" +#include "ieeeflash64.h" #include "isepic.h" #include "kcs.h" #include "kingsoft.h" +#include "ltkernal.h" #include "mach5.h" #include "machine.h" #include "magicdesk.h" +#include "magicdesk16.h" #include "magicformel.h" #include "magicvoice.h" +#include "maxbasic.h" +#include "megabyter.h" #include "mikroass.h" #include "mmc64.h" #include "mmcreplay.h" +#include "multimax.h" #include "sfx_soundexpander.h" #include "sfx_soundsampler.h" #include "ocean.h" #include "pagefox.h" +#include "partner64.h" #include "prophet64.h" +#include "profidos.h" #include "ramcart.h" +#include "ramlink.h" #include "retroreplay.h" #include "reu.h" #include "rexep256.h" +#include "rexramfloppy.h" #include "rexutility.h" #include "rgcd.h" #include "rrnetmk3.h" #include "ross.h" +#include "sdbox.h" #include "shortbus_digimax.h" #include "silverrock128.h" #include "simonsbasic.h" @@ -130,18 +150,23 @@ #include "superexplode5.h" #include "supersnapshot.h" #include "supersnapshot4.h" -#ifdef HAVE_PCAP +#include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" + +#ifdef HAVE_RAWNET #include "ethernetcart.h" #endif #include "warpspeed.h" #include "westermann.h" #include "zaxxon.h" +#include "zippcode48.h" #undef CARTRIDGE_INCLUDE_PRIVATE_API /* #define DEBUGCART */ #ifdef DEBUGCART -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -187,350 +212,293 @@ extern export_t export_passthrough; /* slot1 and main combined, goes into slot0 static const cmdline_option_t cmdline_options[] = { /* generic cartridges */ - { "-cart8", CALL_FUNCTION, 1, + { "-cart8", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GENERIC_8KB, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_GENERIC_8KB_CART, - NULL, NULL }, - { "-cart16", CALL_FUNCTION, 1, + "", "Attach raw 8KiB cartridge image" }, + { "-cart16", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GENERIC_16KB, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_GENERIC_16KB_CART, - NULL, NULL }, - { "-cartultimax", CALL_FUNCTION, 1, + "", "Attach raw 16KiB cartridge image" }, + { "-cartultimax", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ULTIMAX, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_GENERIC_16KB_ULTIMAX_CART, - NULL, NULL }, + "", "Attach generic 16KiB Ultimax cartridge image" }, /* smart-insert CRT */ - { "-cartcrt", CALL_FUNCTION, 1, + { "-cartcrt", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_CRT, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_CRT_CART, - NULL, NULL }, + "", "Attach CRT cartridge image" }, /* binary images: */ - { "-cartap", CALL_FUNCTION, 1, + { "-cartap", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ATOMIC_POWER, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ATOMIC_POWER_CART, - NULL, NULL }, - { "-cartar2", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Atomic Power cartridge image" }, + { "-cartar2", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ACTION_REPLAY2, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ACTION_REPLAY2_CART, - NULL, NULL }, - { "-cartar3", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Action Replay MK2 cartridge image" }, + { "-cartar3", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ACTION_REPLAY3, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ACTION_REPLAY3_CART, - NULL, NULL }, - { "-cartar4", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Action Replay MK3 cartridge image" }, + { "-cartar4", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ACTION_REPLAY4, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ACTION_REPLAY4_CART, - NULL, NULL }, - { "-cartar5", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Action Replay MK4 cartridge image" }, + { "-cartar5", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ACTION_REPLAY, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ACTION_REPLAY_CART }, - { "-cartcap", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Action Replay cartridge image" }, + { "-cartbb3", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BLACKBOX3, NULL, NULL, + "", "Attach raw 8KiB " CARTRIDGE_NAME_BLACKBOX3 " cartridge image" }, + { "-cartbb4", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BLACKBOX4, NULL, NULL, + "", "Attach raw 16KiB " CARTRIDGE_NAME_BLACKBOX4 " cartridge image" }, + { "-cartbb8", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BLACKBOX8, NULL, NULL, + "", "Attach raw 32/64KiB " CARTRIDGE_NAME_BLACKBOX8 " cartridge image" }, + { "-cartbb9", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BLACKBOX9, NULL, NULL, + "", "Attach raw 32KiB " CARTRIDGE_NAME_BLACKBOX9 " cartridge image" }, + { "-cartbdt", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BMPDATATURBO, NULL, NULL, + "", "Attach raw 16KiB " CARTRIDGE_NAME_BMPDATATURBO " cartridge image" }, + { "-cartbis", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_BISPLUS, NULL, NULL, + "", "Attach raw 2/4/8KiB " CARTRIDGE_NAME_BISPLUS " cartridge image" }, + { "-cartcap", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_CAPTURE, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_CAPTURE_CART, - NULL, NULL }, - { "-cartcomal", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Capture cartridge image" }, + { "-cartcomal", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_COMAL80, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_COMAL80_CART, - NULL, NULL }, - { "-cartdep256", CALL_FUNCTION, 1, + "", "Attach raw 64KiB Comal 80 cartridge image" }, + { "-cartdep256", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DELA_EP256, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DELA_EP256_CART, - NULL, NULL }, - { "-cartdep64", CALL_FUNCTION, 1, + "", "Attach raw Dela EP256 cartridge image" }, + { "-cartdep64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DELA_EP64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DELA_EP64_CART, - NULL, NULL }, - { "-cartdep7x8", CALL_FUNCTION, 1, + "", "Attach raw Dela EP64 cartridge image" }, + { "-cartdep7x8", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DELA_EP7x8, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DELA_EP7X8_CART, - NULL, NULL }, - { "-cartdin", CALL_FUNCTION, 1, + "", "Attach raw Dela EP7x8 cartridge image" }, + { "-cartdin", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DINAMIC, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DINAMIC_CART, - NULL, NULL }, - { "-cartdsm", CALL_FUNCTION, 1, + "", "Attach raw 128KiB Dinamic cartridge image" }, + { "-cartdsm", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DIASHOW_MAKER, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DIASHOW_MAKER_CART, - NULL, NULL }, - { "-cartdqbb", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Diashow-Maker cartridge image" }, + { "-cartdqbb", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_DQBB, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_DQBB_CART, - NULL, NULL }, - { "-carteasy", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Double Quick Brown Box cartridge image" }, + { "-cartdrean", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_DREAN, NULL, NULL, + "", "Attach raw 32KiB " CARTRIDGE_NAME_DREAN " cartridge image" }, + { "-carteasy", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_EASYFLASH, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_EASY_FLASH_CART, - NULL, NULL }, - { "-carteasycalc", CALL_FUNCTION, 1, + "", "Attach raw EasyFlash cartridge image" }, + { "-carteasycalc", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_EASYCALC, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_EASYCALC_CART, - NULL, NULL }, + "", "Attach raw 24KiB Easy Calc Result cartridge image" }, /* omitted: CARTRIDGE_EASYFLASH_XBANK (NO CART EXISTS!) */ - { "-cartepyx", CALL_FUNCTION, 1, + { "-cartepyx", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_EPYX_FASTLOAD, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_EPYX_FASTLOAD_CART, - NULL, NULL }, - { "-cartexos", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Epyx FastLoad cartridge image" }, + { "-cartexos", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_EXOS, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_EXOS_CART, - NULL, NULL }, - { "-cartexpert", CALL_FUNCTION, 1, + "", "Attach raw 8KiB EXOS cartridge image" }, + { "-cartexpert", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_EXPERT, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_EXPERT_CART, - NULL, NULL }, - { "-cartf64", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Expert Cartridge image" }, + { "-cartf64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FORMEL64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_F64_CART, - NULL, NULL }, - { "-cartfc1", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Formel 64 image" }, + { "-cartfc1", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FINAL_I, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FC1_CART, - NULL, NULL }, - { "-cartfc3", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Final Cartridge image" }, + { "-cartfc3", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FINAL_III, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FC3_CART, - NULL, NULL }, - { "-cartfcplus", CALL_FUNCTION, 1, + "", "Attach raw 64KiB Final Cartridge III image" }, + { "-cartfcplus", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FINAL_PLUS, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FCPLUS_CART, - NULL, NULL }, - { "-cartff", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Final Cartridge Plus image" }, + { "-cartff", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FREEZE_FRAME, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FREEZE_FRAME_CART, - NULL, NULL }, - { "-cartfm", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Freeze Frame image" }, + { "-cartff2", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_FREEZE_FRAME_MK2, NULL, NULL, + "", "Attach raw 16KiB Freeze Frame MK2/MK3 image" }, + { "-cartfm", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FREEZE_MACHINE, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FREEZE_MACHINE_CART, - NULL, NULL }, - { "-cartfp", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Freeze Machine image" }, + { "-cartfp", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_FUNPLAY, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_FP_PP_CART, - NULL, NULL }, - { "-cartgmod2", CALL_FUNCTION, 1, + "", "Attach raw 128KiB Fun Play/Power Play cartridge image" }, + { "-cartgmod2", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GMOD2, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_GAME_KILLER_CART, /* FIXME */ - NULL, NULL }, - { "-cartgk", CALL_FUNCTION, 1, + "", "Attach raw GMod2 cartridge image" }, + { "-cartgmod3", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_GMOD3, NULL, NULL, + "", "Attach raw GMod2 cartridge image" }, + { "-cartgk", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GAME_KILLER, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_GAME_KILLER_CART, - NULL, NULL }, - { "-cartgeoram", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Game Killer cartridge image" }, + { "-cartgeoram", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GEORAM, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_GEORAM_CART, - NULL, NULL }, - { "-cartgs", CALL_FUNCTION, 1, + "", "Attach raw GEO-RAM cartridge image" }, + { "-cartgs", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_GS, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_GAME_SYSTEM_CART, - NULL, NULL }, - { "-cartide64", CALL_FUNCTION, 1, + "", "Attach raw 512KiB Game System cartridge image" }, + { "-carthyper", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_HYPERBASIC, NULL, NULL, + "", "Attach raw 64KiB " CARTRIDGE_NAME_HYPERBASIC " cartridge image" }, + { "-cartide64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_IDE64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_IDE64_CART, - NULL, NULL }, - { "-cartieee", CALL_FUNCTION, 1, + "", "Attach raw 64KiB IDE64 cartridge image" }, + { "-cartieee", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_IEEE488, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_CBM_IEEE488_CART, - NULL, NULL }, - { "-cartisepic", CALL_FUNCTION, 1, + "", "Attach IEEE-488 Interface cartridge image" }, + { "-cartieeeflash64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_IEEEFLASH64, NULL, NULL, + "", "Attach raw 8KiB IEEE Flash! 64 cartridge image" }, + { "-cartisepic", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ISEPIC, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ISEPIC_CART, - NULL, NULL }, - { "-cartkcs", CALL_FUNCTION, 1, + "", "Attach raw 2KiB ISEPIC cartridge image" }, + { "-cartkcs", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_KCS_POWER, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_KCS_CART, - NULL, NULL }, - { "-cartks", CALL_FUNCTION, 1, + "", "Attach raw 16KiB KCS Power cartridge image" }, + { "-cartks", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_KINGSOFT, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_KINGSOFT_CART, - NULL, NULL }, - { "-cartmach5", CALL_FUNCTION, 1, + "", "Attach raw 24KiB Kingsoft cartridge image" }, + { "-cartltk", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_LT_KERNAL, NULL, NULL, + "", "Attach raw 8kB Lt. Kernal boot image" }, + { "-cartmach5", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MACH5, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MACH5_CART, - NULL, NULL }, - { "-cartmd", CALL_FUNCTION, 1, + "", "Attach raw 8KiB MACH 5 cartridge image" }, + { "-cartmd", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MAGIC_DESK, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MAGIC_DESK_CART, - NULL, NULL }, - { "-cartmf", CALL_FUNCTION, 1, + "", "Attach raw 32/64/128KiB Magic Desk cartridge image" }, + { "-cartmd16", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_MAGIC_DESK_16, NULL, NULL, + "", "Attach raw up to 2048KiB Magic Desk 16K cartridge image" }, + { "-cartmb", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_MEGABYTER, NULL, NULL, + "", "Attach raw 1024KiB " CARTRIDGE_NAME_MEGABYTER " cartridge image" }, + { "-cartmf", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MAGIC_FORMEL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MAGIC_FORMEL_CART, - NULL, NULL }, - { "-cartmikro", CALL_FUNCTION, 1, + "", "Attach raw Magic Formel cartridge image" }, + { "-cartmax", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_MAX_BASIC, NULL, NULL, + "", "Attach raw MAX Basic cartridge image" }, + { "-cartmikro", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MIKRO_ASSEMBLER, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MIKRO_ASSEMBLER_CART, - NULL, NULL }, - { "-cartmmc64", CALL_FUNCTION, 1, + "", "Attach raw 8KiB Mikro Assembler cartridge image" }, + { "-cartmmc64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MMC64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MMC64_CART, - NULL, NULL }, - { "-cartmmcr", CALL_FUNCTION, 1, + "", "Attach raw 8KiB MMC64 cartridge image" }, + { "-cartmmcr", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MMC_REPLAY, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MMC_REPLAY_CART, - NULL, NULL }, - { "-cartmv", CALL_FUNCTION, 1, + "", "Attach raw 512KiB MMC Replay cartridge image" }, + { "-cartmv", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_MAGIC_VOICE, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_MAGIC_VOICE_CART, - NULL, NULL }, - { "-cartocean", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Magic Voice cartridge image" }, + { "-cartmm", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_MULTIMAX, NULL, NULL, + "", "Attach raw 1MiB " CARTRIDGE_NAME_MULTIMAX " cartridge image" }, + { "-cartocean", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_OCEAN, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_OCEAN_CART, - NULL, NULL }, - { "-cartpf", CALL_FUNCTION, 1, + "", "Attach raw Ocean cartridge image" }, + { "-cartpf", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_PAGEFOX, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_PAGEFOX_CART, - NULL, NULL }, - { "-cartp64", CALL_FUNCTION, 1, + "", "Attach raw 64KiB Pagefox cartridge image" }, + { "-cartp64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_P64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_P64_CART, - NULL, NULL }, - { "-cartramcart", CALL_FUNCTION, 1, + "", "Attach raw 256KiB Prophet 64 cartridge image" }, + { "-cartpartner64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_PARTNER64, NULL, NULL, + "", "Attach raw 16KiB " CARTRIDGE_NAME_PARTNER64 " cartridge image" }, + { "-cartpd", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_PROFIDOS, NULL, NULL, + "", "Attach raw 16KiB " CARTRIDGE_NAME_PROFIDOS " cartridge image" }, + { "-cartramcart", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RAMCART, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_RAMCART_CART, - NULL, NULL }, - { "-cartreu", CALL_FUNCTION, 1, + "", "Attach raw RamCart cartridge image" }, + { "-cartramlink", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_RAMLINK, NULL, NULL, + "", "Attach raw 64KiB RAMLink ROM image" }, + { "-cartreu", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_REU, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_REU_CART, - NULL, NULL }, - { "-cartrep256", CALL_FUNCTION, 1, + "", "Attach raw REU cartridge image" }, + { "-cartrep256", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_REX_EP256, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_REX_EP256_CART, - NULL, NULL }, - { "-cartrgcd", CALL_FUNCTION, 1, + "", "Attach raw REX EP256 cartridge image" }, + { "-cartrrf", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_REX_RAMFLOPPY, NULL, NULL, + "", "Attach raw " CARTRIDGE_NAME_REX_RAMFLOPPY " cartridge image" }, + { "-cartrgcd", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RGCD, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_RGCD_CART, - NULL, NULL }, -#ifdef HAVE_PCAP - { "-cartrrnet", CALL_FUNCTION, 1, + "", "Attach raw 64KiB RGCD cartridge image" }, + { "-cartuc1", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC1, NULL, NULL, + "", "Attach raw 32/64/128KiB UC-1 cartridge image" }, + { "-cartuc15", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC15, NULL, NULL, + "", "Attach raw 128/256/512KiB UC-1.5 cartridge image" }, + { "-cartuc2", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC2, NULL, NULL, + "", "Attach raw 128/256/512KiB UC-2 cartridge image" }, +#ifdef HAVE_RAWNET + { "-cartrrnet", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RRNETMK3, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_RRNETMK3_CART, - NULL, NULL }, + "", "Attach raw 8KiB RR-Net MK3 cartridge image" }, #endif - { "-cartross", CALL_FUNCTION, 1, + { "-cartross", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ROSS, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ROSS_CART, - NULL, NULL }, - { "-cartrr", CALL_FUNCTION, 1, + "", "Attach raw 16/32KiB ROSS cartridge image" }, + { "-cartrr", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RETRO_REPLAY, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_RETRO_REPLAY_CART, - NULL, NULL }, - { "-cartru", CALL_FUNCTION, 1, + "", "Attach raw 64KiB Retro Replay cartridge image" }, + { "-cartru", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_REX, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_REX_UTILITY_CART, - NULL, NULL }, - { "-carts64", CALL_FUNCTION, 1, + "", "Attach raw 8KiB REX Utility cartridge image" }, + { "-cartsdbox", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_SDBOX, NULL, NULL, + "", "Attach raw 128KiB " CARTRIDGE_NAME_SDBOX " cartridge image" }, + { "-carts64", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SNAPSHOT64, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SS64_CART, - NULL, NULL }, - { "-cartsb", CALL_FUNCTION, 1, + "", "Attach raw 4KiB Snapshot 64 cartridge image" }, + { "-cartsb", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_STRUCTURED_BASIC, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_STB_CART, - NULL, NULL }, - { "-cartse5", CALL_FUNCTION, 1, + "", "Attach raw Structured Basic cartridge image" }, + { "-cartse5", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SUPER_EXPLODE_V5, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SE5_CART, - NULL, NULL }, - { "-cartsg", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Super Explode V5 cartridge image" }, + { "-cartsg", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SUPER_GAMES, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SUPER_GAMES_CART, - NULL, NULL }, - { "-cartsilver", CALL_FUNCTION, 1, + "", "Attach raw 64KiB Super Games cartridge image" }, + { "-cartsilver", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SILVERROCK_128, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SILVERROCK_128_CART, - NULL, NULL }, - { "-cartsimon", CALL_FUNCTION, 1, + "", "Attach raw Silverrock 128 cartridge image" }, + { "-cartsimon", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SIMONS_BASIC, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SIMONS_BASIC_CART, - NULL, NULL }, - { "-cartss4", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Simons Basic cartridge image" }, + { "-cartss4", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SUPER_SNAPSHOT, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SS4_CART, - NULL, NULL }, - { "-cartss5", CALL_FUNCTION, 1, + "", "Attach raw 32KiB Super Snapshot V4 cartridge image" }, + { "-cartss5", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_SUPER_SNAPSHOT_V5, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_SS5_CART, - NULL, NULL }, - { "-cartstar", CALL_FUNCTION, 1, + "", "Attach raw 64KiB or 128KiB Super Snapshot V5 cartridge image" }, + { "-cartstar", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_STARDOS, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_STARDOS_CART, - NULL, NULL }, - { "-cartwl", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Stardos cartridge image" }, + { "-cartturtle", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_TURTLE_GRAPHICS_II, NULL, NULL, + "", "Attach raw 16KiB " CARTRIDGE_NAME_TURTLE_GRAPHICS_II " cartridge image" }, + { "-cartwl", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_WESTERMANN, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_WESTERMANN_CART, - NULL, NULL }, - { "-cartws", CALL_FUNCTION, 1, + "", "Attach raw 16KiB Westermann Learning cartridge image" }, + { "-cartws", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_WARPSPEED, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_WARPSPEED_CART, - NULL, NULL }, - { "-cartzaxxon", CALL_FUNCTION, 1, + "", "Attach raw 16KiB " CARTRIDGE_NAME_WARPSPEED " cartridge image" }, + { "-cartzaxxon", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_ZAXXON, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ATTACH_RAW_ZAXXON_CART, - NULL, NULL }, + "", "Attach raw 16KiB Zaxxon cartridge image" }, + { "-cartzipp", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_ZIPPCODE48, NULL, NULL, + "", "Attach raw 8KiB " CARTRIDGE_NAME_ZIPPCODE48 " cartridge image" }, CMDLINE_LIST_END }; @@ -540,6 +508,7 @@ int cart_cmdline_options_init(void) if (mmc64_cmdline_options_init() < 0 || magicvoice_cmdline_options_init() < 0 || tpi_cmdline_options_init() < 0 + || ramlink_cmdline_options_init() < 0 /* "Slot 1" */ || dqbb_cmdline_options_init() < 0 || expert_cmdline_options_init() < 0 @@ -558,16 +527,23 @@ int cart_cmdline_options_init(void) || reu_cmdline_options_init() < 0 || sfx_soundexpander_cmdline_options_init() < 0 || sfx_soundsampler_cmdline_options_init() < 0 -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET || ethernetcart_cmdline_options_init() < 0 #endif /* "Main Slot" */ + || comal80_cmdline_options_init() < 0 || easyflash_cmdline_options_init() < 0 || gmod2_cmdline_options_init() < 0 + || gmod3_cmdline_options_init() < 0 || ide64_cmdline_options_init() < 0 + || ieeeflash64_cmdline_options_init() < 0 + || ltkernal_cmdline_options_init() < 0 + || megabyter_cmdline_options_init() < 0 || mmcreplay_cmdline_options_init() < 0 || retroreplay_cmdline_options_init() < 0 -#ifdef HAVE_PCAP + || rexramfloppy_cmdline_options_init() < 0 + || rgcd_cmdline_options_init() < 0 +#ifdef HAVE_RAWNET || rrnetmk3_cmdline_options_init() < 0 #endif || supersnapshot_v5_cmdline_options_init() < 0 @@ -599,6 +575,8 @@ int cart_resources_init(void) if (mmc64_resources_init() < 0 || magicvoice_resources_init() < 0 || tpi_resources_init() < 0 + || ramlink_resources_init() < 0 + || ieeeflash64_resources_init() < 0 /* "Slot 1" */ || expert_resources_init() < 0 || dqbb_resources_init() < 0 @@ -614,19 +592,25 @@ int cart_resources_init(void) || reu_resources_init() < 0 || sfx_soundexpander_resources_init() < 0 || sfx_soundsampler_resources_init() < 0 -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET || ethernetcart_resources_init() < 0 #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) || aciacart_resources_init() < 0 #endif /* "Main Slot" */ + || comal80_resources_init() < 0 || easyflash_resources_init() < 0 || gmod2_resources_init() < 0 + || gmod3_resources_init() < 0 || ide64_resources_init() < 0 + || ltkernal_resources_init() < 0 + || megabyter_resources_init() < 0 || mmcreplay_resources_init() < 0 || retroreplay_resources_init() < 0 -#ifdef HAVE_PCAP + || rexramfloppy_resources_init() < 0 + || rgcd_resources_init() < 0 +#ifdef HAVE_RAWNET || rrnetmk3_resources_init() < 0 #endif || supersnapshot_v5_resources_init() < 0 @@ -659,7 +643,7 @@ void cart_resources_shutdown(void) reu_resources_shutdown(); sfx_soundexpander_resources_shutdown(); sfx_soundsampler_resources_shutdown(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET ethernetcart_resources_shutdown(); #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) @@ -667,12 +651,18 @@ void cart_resources_shutdown(void) #endif /* "Main Slot" */ + comal80_resources_shutdown(); easyflash_resources_shutdown(); gmod2_resources_shutdown(); + gmod3_resources_shutdown(); ide64_resources_shutdown(); + ltkernal_resources_shutdown(); + megabyter_resources_shutdown(); mmcreplay_resources_shutdown(); retroreplay_resources_shutdown(); -#ifdef HAVE_PCAP + rexramfloppy_resources_shutdown(); + rgcd_resources_shutdown(); +#ifdef HAVE_RAWNET rrnetmk3_resources_shutdown(); #endif supersnapshot_v5_resources_shutdown(); @@ -687,6 +677,8 @@ void cart_resources_shutdown(void) mmc64_resources_shutdown(); magicvoice_resources_shutdown(); tpi_resources_shutdown(); + ramlink_resources_shutdown(); + ieeeflash64_resources_shutdown(); } /* ------------------------------------------------------------------------- */ @@ -698,9 +690,11 @@ int cart_is_slotmain(int type) { switch (type) { /* slot 0 */ - case CARTRIDGE_MMC64: - case CARTRIDGE_MAGIC_VOICE: case CARTRIDGE_IEEE488: + case CARTRIDGE_IEEEFLASH64: + case CARTRIDGE_MAGIC_VOICE: + case CARTRIDGE_MMC64: + case CARTRIDGE_RAMLINK: /* slot 1 */ case CARTRIDGE_DQBB: case CARTRIDGE_EXPERT: @@ -737,6 +731,12 @@ int cart_getid_slot0(void) if (tpi_cart_enabled()) { return CARTRIDGE_IEEE488; } + if (ieeeflash64_cart_enabled()) { + return CARTRIDGE_IEEEFLASH64; + } + if (ramlink_cart_enabled()) { + return CARTRIDGE_RAMLINK; + } return CARTRIDGE_NONE; } @@ -770,6 +770,10 @@ int cart_type_enabled(int type) /* "Slot 0" */ case CARTRIDGE_IEEE488: return tpi_cart_enabled(); + case CARTRIDGE_RAMLINK: + return ramlink_cart_enabled(); + case CARTRIDGE_IEEEFLASH64: + return ieeeflash64_cart_enabled(); case CARTRIDGE_MAGIC_VOICE: return magicvoice_cart_enabled(); case CARTRIDGE_MMC64: @@ -790,6 +794,8 @@ int cart_type_enabled(int type) return ds12c887rtc_cart_enabled(); case CARTRIDGE_GEORAM: return georam_cart_enabled(); + case CARTRIDGE_CPM: + return cpmcart_cart_enabled(); #ifdef HAVE_MIDI case CARTRIDGE_MIDI_PASSPORT: return c64_midi_pp_cart_enabled(); @@ -808,7 +814,7 @@ int cart_type_enabled(int type) return sfx_soundexpander_cart_enabled(); case CARTRIDGE_SFX_SOUND_SAMPLER: return sfx_soundsampler_cart_enabled(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_TFE: return ethernetcart_cart_enabled(); #endif @@ -824,12 +830,16 @@ int cart_type_enabled(int type) /* get filename of cart with given type */ -const char *cart_get_file_name(int type) +const char *cart_get_filename_by_type(int type) { switch (type) { /* "Slot 0" */ case CARTRIDGE_IEEE488: return tpi_get_file_name(); + case CARTRIDGE_RAMLINK: + return ramlink_get_ram_file_name(); + case CARTRIDGE_IEEEFLASH64: + return ieeeflash64_get_file_name(); case CARTRIDGE_MAGIC_VOICE: return magicvoice_get_file_name(); case CARTRIDGE_MMC64: @@ -842,7 +852,8 @@ const char *cart_get_file_name(int type) case CARTRIDGE_ISEPIC: return isepic_get_file_name(); case CARTRIDGE_RAMCART: - return ramcart_get_file_name(); + return ramcart_get_filename_by_type(); + /* "Main Slot" */ /* "I/O Slot" */ case CARTRIDGE_GEORAM: return georam_get_file_name(); @@ -860,7 +871,7 @@ const char *cart_get_file_name(int type) #endif case CARTRIDGE_SFX_SOUND_EXPANDER: case CARTRIDGE_SFX_SOUND_SAMPLER: -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_TFE: #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) @@ -868,7 +879,7 @@ const char *cart_get_file_name(int type) #endif break; - /* Main Slot handled in c64cart.c:cartridge_get_file_name */ + /* Main Slot handled in c64cart.c:cartridge_get_filename_by_type */ } return ""; /* FIXME: NULL or empty string? */ } @@ -878,11 +889,11 @@ const char *cart_get_file_name(int type) /* FIXME: shutdown missing */ /* called once by machine_setup_context */ -void cartridge_setup_context(machine_context_t *machine_context) +void cartridge_setup_context(machine_context_t *context) { /* "Slot 0" */ - tpi_setup_context(machine_context); - magicvoice_setup_context(machine_context); + tpi_setup_context(context); + magicvoice_setup_context(context); /* mmc64 */ /* "Slot 1" */ @@ -892,12 +903,19 @@ void cartridge_setup_context(machine_context_t *machine_context) /* ------------------------------------------------------------------------- */ -int cart_bin_attach(int type, const char *filename, BYTE *rawcart) +/* attach a binary image. note that for carts not in the main slot, the image + name is usually kept in a resource, and the cartridge is enabled via another + resource - the function called from here must also do this */ +int cart_bin_attach(int type, const char *filename, uint8_t *rawcart) { switch (type) { /* "Slot 0" */ case CARTRIDGE_IEEE488: return tpi_bin_attach(filename, rawcart); + case CARTRIDGE_RAMLINK: + return ramlink_bin_attach(filename, rawcart); + case CARTRIDGE_IEEEFLASH64: + return ieeeflash64_bin_attach(filename, rawcart); case CARTRIDGE_MAGIC_VOICE: return magicvoice_bin_attach(filename, rawcart); case CARTRIDGE_MMC64: @@ -927,6 +945,18 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return actionreplay4_bin_attach(filename, rawcart); case CARTRIDGE_ATOMIC_POWER: return atomicpower_bin_attach(filename, rawcart); + case CARTRIDGE_BISPLUS: + return bisplus_bin_attach(filename, rawcart); + case CARTRIDGE_BLACKBOX3: + return blackbox3_bin_attach(filename, rawcart); + case CARTRIDGE_BLACKBOX4: + return blackbox4_bin_attach(filename, rawcart); + case CARTRIDGE_BLACKBOX8: + return blackbox8_bin_attach(filename, rawcart); + case CARTRIDGE_BLACKBOX9: + return blackbox9_bin_attach(filename, rawcart); + case CARTRIDGE_BMPDATATURBO: + return bmpdataturbo_bin_attach(filename, rawcart); case CARTRIDGE_CAPTURE: return capture_bin_attach(filename, rawcart); case CARTRIDGE_COMAL80: @@ -941,6 +971,8 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return dsm_bin_attach(filename, rawcart); case CARTRIDGE_DINAMIC: return dinamic_bin_attach(filename, rawcart); + case CARTRIDGE_DREAN: + return drean_bin_attach(filename, rawcart); case CARTRIDGE_EASYCALC: return easycalc_bin_attach(filename, rawcart); case CARTRIDGE_EASYFLASH: @@ -961,6 +993,8 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return formel64_bin_attach(filename, rawcart); case CARTRIDGE_FREEZE_FRAME: return freezeframe_bin_attach(filename, rawcart); + case CARTRIDGE_FREEZE_FRAME_MK2: + return freezeframe2_bin_attach(filename, rawcart); case CARTRIDGE_FREEZE_MACHINE: return freezemachine_bin_attach(filename, rawcart); case CARTRIDGE_FUNPLAY: @@ -973,44 +1007,72 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return generic_16kb_bin_attach(filename, rawcart); case CARTRIDGE_GMOD2: return gmod2_bin_attach(filename, rawcart); + case CARTRIDGE_GMOD3: + return gmod3_bin_attach(filename, rawcart); case CARTRIDGE_GS: return gs_bin_attach(filename, rawcart); + case CARTRIDGE_HYPERBASIC: + return hyperbasic_bin_attach(filename, rawcart); case CARTRIDGE_IDE64: return ide64_bin_attach(filename, rawcart); case CARTRIDGE_KCS_POWER: return kcs_bin_attach(filename, rawcart); case CARTRIDGE_KINGSOFT: return kingsoft_bin_attach(filename, rawcart); + case CARTRIDGE_LT_KERNAL: + return ltkernal_bin_attach(filename, rawcart); case CARTRIDGE_MACH5: return mach5_bin_attach(filename, rawcart); case CARTRIDGE_MAGIC_DESK: return magicdesk_bin_attach(filename, rawcart); + case CARTRIDGE_MAGIC_DESK_16: + return magicdesk16_bin_attach(filename, rawcart); case CARTRIDGE_MAGIC_FORMEL: return magicformel_bin_attach(filename, rawcart); + case CARTRIDGE_MAX_BASIC: + return maxbasic_bin_attach(filename, rawcart); + case CARTRIDGE_MEGABYTER: + return megabyter_bin_attach(filename, rawcart); case CARTRIDGE_MIKRO_ASSEMBLER: return mikroass_bin_attach(filename, rawcart); case CARTRIDGE_MMC_REPLAY: return mmcreplay_bin_attach(filename, rawcart); + case CARTRIDGE_MULTIMAX: + return multimax_bin_attach(filename, rawcart); case CARTRIDGE_OCEAN: return ocean_bin_attach(filename, rawcart); case CARTRIDGE_P64: return p64_bin_attach(filename, rawcart); case CARTRIDGE_PAGEFOX: return pagefox_bin_attach(filename, rawcart); + case CARTRIDGE_PARTNER64: + return partner64_bin_attach(filename, rawcart); + case CARTRIDGE_PROFIDOS: + return profidos_bin_attach(filename, rawcart); case CARTRIDGE_RETRO_REPLAY: return retroreplay_bin_attach(filename, rawcart); case CARTRIDGE_REX: return rex_bin_attach(filename, rawcart); case CARTRIDGE_REX_EP256: return rexep256_bin_attach(filename, rawcart); + case CARTRIDGE_REX_RAMFLOPPY: + return rexramfloppy_bin_attach(filename, rawcart); case CARTRIDGE_RGCD: return rgcd_bin_attach(filename, rawcart); -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + return uc1_bin_attach(filename, rawcart); + case CARTRIDGE_UC15: + return uc15_bin_attach(filename, rawcart); + case CARTRIDGE_UC2: + return uc2_bin_attach(filename, rawcart); +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_bin_attach(filename, rawcart); #endif case CARTRIDGE_ROSS: return ross_bin_attach(filename, rawcart); + case CARTRIDGE_SDBOX: + return sdbox_bin_attach(filename, rawcart); case CARTRIDGE_SILVERROCK_128: return silverrock128_bin_attach(filename, rawcart); case CARTRIDGE_SIMONS_BASIC: @@ -1029,6 +1091,8 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return supersnapshot_v4_bin_attach(filename, rawcart); case CARTRIDGE_SUPER_SNAPSHOT_V5: return supersnapshot_v5_bin_attach(filename, rawcart); + case CARTRIDGE_TURTLE_GRAPHICS_II: + return turtlegraphics_bin_attach(filename, rawcart); case CARTRIDGE_ULTIMAX: return generic_ultimax_bin_attach(filename, rawcart); case CARTRIDGE_WARPSPEED: @@ -1037,6 +1101,8 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) return westermann_bin_attach(filename, rawcart); case CARTRIDGE_ZAXXON: return zaxxon_bin_attach(filename, rawcart); + case CARTRIDGE_ZIPPCODE48: + return zippcode48_bin_attach(filename, rawcart); } return -1; } @@ -1046,14 +1112,29 @@ int cart_bin_attach(int type, const char *filename, BYTE *rawcart) XYZ_config_setup should copy the raw cart image into the individual implementations array. */ -void cart_attach(int type, BYTE *rawcart) +void cart_attach(int type, uint8_t *rawcart) { cart_detach_conflicting(type); + + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + c128cartridge->config_setup(type, rawcart); + return; + } + + /* FIXME: cartridges that work in both c64 and c128 mode must explicitly + call c128cartridge->config_setup() below */ + switch (type) { /* "Slot 0" */ case CARTRIDGE_IEEE488: tpi_config_setup(rawcart); break; + case CARTRIDGE_RAMLINK: + ramlink_config_setup(rawcart); + break; + case CARTRIDGE_IEEEFLASH64: + ieeeflash64_config_setup(rawcart); + break; case CARTRIDGE_MAGIC_VOICE: magicvoice_config_setup(rawcart); break; @@ -1096,6 +1177,24 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_ATOMIC_POWER: atomicpower_config_setup(rawcart); break; + case CARTRIDGE_BISPLUS: + bisplus_config_setup(rawcart); + break; + case CARTRIDGE_BLACKBOX3: + blackbox3_config_setup(rawcart); + break; + case CARTRIDGE_BLACKBOX4: + blackbox4_config_setup(rawcart); + break; + case CARTRIDGE_BLACKBOX8: + blackbox8_config_setup(rawcart); + break; + case CARTRIDGE_BLACKBOX9: + blackbox9_config_setup(rawcart); + break; + case CARTRIDGE_BMPDATATURBO: + bmpdataturbo_config_setup(rawcart); + break; case CARTRIDGE_CAPTURE: capture_config_setup(rawcart); break; @@ -1117,6 +1216,9 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_DINAMIC: dinamic_config_setup(rawcart); break; + case CARTRIDGE_DREAN: + drean_config_setup(rawcart); + break; case CARTRIDGE_EASYCALC: easycalc_config_setup(rawcart); break; @@ -1144,6 +1246,9 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_FREEZE_FRAME: freezeframe_config_setup(rawcart); break; + case CARTRIDGE_FREEZE_FRAME_MK2: + freezeframe2_config_setup(rawcart); + break; case CARTRIDGE_FREEZE_MACHINE: freezemachine_config_setup(rawcart); break; @@ -1162,9 +1267,15 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_GMOD2: gmod2_config_setup(rawcart); break; + case CARTRIDGE_GMOD3: + gmod3_config_setup(rawcart); + break; case CARTRIDGE_GS: gs_config_setup(rawcart); break; + case CARTRIDGE_HYPERBASIC: + hyperbasic_config_setup(rawcart); + break; case CARTRIDGE_IDE64: ide64_config_setup(rawcart); break; @@ -1174,21 +1285,36 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_KINGSOFT: kingsoft_config_setup(rawcart); break; + case CARTRIDGE_LT_KERNAL: + ltkernal_config_setup(rawcart); + break; case CARTRIDGE_MACH5: mach5_config_setup(rawcart); break; case CARTRIDGE_MAGIC_DESK: magicdesk_config_setup(rawcart); break; + case CARTRIDGE_MAGIC_DESK_16: + magicdesk16_config_setup(rawcart); + break; case CARTRIDGE_MAGIC_FORMEL: magicformel_config_setup(rawcart); break; + case CARTRIDGE_MAX_BASIC: + maxbasic_config_setup(rawcart); + break; + case CARTRIDGE_MEGABYTER: + megabyter_config_setup(rawcart); + break; case CARTRIDGE_MIKRO_ASSEMBLER: mikroass_config_setup(rawcart); break; case CARTRIDGE_MMC_REPLAY: mmcreplay_config_setup(rawcart); break; + case CARTRIDGE_MULTIMAX: + multimax_config_setup(rawcart); + break; case CARTRIDGE_OCEAN: ocean_config_setup(rawcart); break; @@ -1198,6 +1324,12 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_PAGEFOX: pagefox_config_setup(rawcart); break; + case CARTRIDGE_PARTNER64: + partner64_config_setup(rawcart); + break; + case CARTRIDGE_PROFIDOS: + profidos_config_setup(rawcart); + break; case CARTRIDGE_RETRO_REPLAY: retroreplay_config_setup(rawcart); break; @@ -1207,17 +1339,30 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_REX_EP256: rexep256_config_setup(rawcart); break; + case CARTRIDGE_REX_RAMFLOPPY: + rexramfloppy_config_setup(rawcart); + break; case CARTRIDGE_RGCD: rgcd_config_setup(rawcart); break; case CARTRIDGE_ROSS: ross_config_setup(rawcart); break; -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + uc1_config_setup(rawcart); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_config_setup(rawcart); + break; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_config_setup(rawcart); break; #endif + case CARTRIDGE_SDBOX: + sdbox_config_setup(rawcart); + break; case CARTRIDGE_SILVERROCK_128: silverrock128_config_setup(rawcart); break; @@ -1245,6 +1390,9 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_SUPER_SNAPSHOT_V5: supersnapshot_v5_config_setup(rawcart); break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + turtlegraphics_config_setup(rawcart); + break; case CARTRIDGE_ULTIMAX: generic_ultimax_config_setup(rawcart); break; @@ -1257,8 +1405,11 @@ void cart_attach(int type, BYTE *rawcart) case CARTRIDGE_ZAXXON: zaxxon_config_setup(rawcart); break; + case CARTRIDGE_ZIPPCODE48: + zippcode48_config_setup(rawcart); + break; default: - DBG(("CART: no attach hook %d\n", type)); + DBG(("CART: no attach hook %d", type)); break; } } @@ -1267,6 +1418,7 @@ void cart_attach(int type, BYTE *rawcart) static int slot0conflicts[] = { CARTRIDGE_IEEE488, + CARTRIDGE_IEEEFLASH64, CARTRIDGE_MAGIC_VOICE, CARTRIDGE_MMC64, 0 @@ -1282,7 +1434,7 @@ static int slot1conflicts[] = 0 }; -void cart_detach_conflicts0(int *list, int type) +static void cart_detach_conflicts0(int *list, int type) { int *l = list; /* find in list */ @@ -1292,7 +1444,7 @@ void cart_detach_conflicts0(int *list, int type) while (*list != 0) { if (*list != type) { if (cartridge_type_enabled(*list)) { - DBG(("CART: detach conflicting cart: %d (only one Slot 0 cart can be active)\n", *list)); + DBG(("CART: detach conflicting cart: %d (only one Slot 0 cart can be active)", *list)); cartridge_detach_image(*list); } } @@ -1306,7 +1458,7 @@ void cart_detach_conflicts0(int *list, int type) void cart_detach_conflicting(int type) { - DBG(("CART: detach conflicting for type: %d ...\n", type)); + DBG(("CART: detach conflicting for type: %d ...", type)); cart_detach_conflicts0(slot0conflicts, type); cart_detach_conflicts0(slot1conflicts, type); } @@ -1316,12 +1468,15 @@ void cart_detach_conflicting(int type) */ int cartridge_enable(int type) { - DBG(("CART: enable type: %d\n", type)); + DBG(("CART: enable type: %d", type)); switch (type) { /* "Slot 0" */ case CARTRIDGE_IEEE488: tpi_enable(); break; + case CARTRIDGE_IEEEFLASH64: + ieeeflash64_enable(); + break; case CARTRIDGE_MAGIC_VOICE: magicvoice_enable(); break; @@ -1341,6 +1496,9 @@ int cartridge_enable(int type) case CARTRIDGE_RAMCART: ramcart_enable(); break; + case CARTRIDGE_RAMLINK: + ramlink_enable(); + break; /* "I/O Slot" */ case CARTRIDGE_DIGIMAX: digimax_enable(); @@ -1351,6 +1509,9 @@ int cartridge_enable(int type) case CARTRIDGE_GEORAM: georam_enable(); break; + case CARTRIDGE_CPM: + cpmcart_enable(); + break; #ifdef HAVE_MIDI case CARTRIDGE_MIDI_PASSPORT: case CARTRIDGE_MIDI_DATEL: @@ -1369,7 +1530,7 @@ int cartridge_enable(int type) case CARTRIDGE_SFX_SOUND_SAMPLER: sfx_soundsampler_enable(); break; -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_TFE: ethernetcart_enable(); break; @@ -1381,7 +1542,7 @@ int cartridge_enable(int type) #endif /* "Main Slot" */ default: - DBG(("CART: no enable hook %d\n", type)); + DBG(("CART: no enable hook %d", type)); break; } cart_detach_conflicting(type); @@ -1389,9 +1550,114 @@ int cartridge_enable(int type) if (cart_type_enabled(type)) { return 0; } + log_error(LOG_DEFAULT, "Failed to enable cartridge with ID %d.", type); + return -1; +} + + +/** \brief Disable cartridge by \a type + * + * \return 0 on success, -1 on failure + * + * \todo More or less copy cartridge_enable() while replacing + * ${cart}_enable() with ${cart_disable(). The various disable + * functions still need to be written at the moment. + */ +int cartridge_disable(int type) +{ + /* + fprintf(stderr, "%s:%d: %s() isn't implemented yet, continuing\n", + __FILE__, __LINE__, __func__); + */ + DBG(("CART: enable type: %d", type)); + switch (type) { + /* "Slot 0" */ + case CARTRIDGE_IEEE488: + tpi_disable(); + break; + case CARTRIDGE_IEEEFLASH64: + ieeeflash64_disable(); + break; + case CARTRIDGE_MAGIC_VOICE: + magicvoice_disable(); + break; + case CARTRIDGE_MMC64: + mmc64_disable(); + break; + /* "Slot 1" */ + case CARTRIDGE_DQBB: + dqbb_disable(); + break; + case CARTRIDGE_EXPERT: + expert_disable(); + break; + case CARTRIDGE_ISEPIC: + isepic_disable(); + break; + case CARTRIDGE_RAMCART: + ramcart_disable(); + break; + case CARTRIDGE_RAMLINK: + ramlink_disable(); + break; + /* "I/O Slot" */ + case CARTRIDGE_DIGIMAX: + digimax_disable(); + break; + case CARTRIDGE_DS12C887RTC: + ds12c887rtc_disable(); + break; + case CARTRIDGE_GEORAM: + georam_disable(); + break; + case CARTRIDGE_CPM: + cpmcart_disable(); + break; +#ifdef HAVE_MIDI + case CARTRIDGE_MIDI_PASSPORT: + case CARTRIDGE_MIDI_DATEL: + case CARTRIDGE_MIDI_SEQUENTIAL: + case CARTRIDGE_MIDI_NAMESOFT: + case CARTRIDGE_MIDI_MAPLIN: + c64_midi_disable(); + break; +#endif + case CARTRIDGE_REU: + reu_disable(); + break; + case CARTRIDGE_SFX_SOUND_EXPANDER: + sfx_soundexpander_disable(); + break; + case CARTRIDGE_SFX_SOUND_SAMPLER: + sfx_soundsampler_disable(); + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_TFE: + ethernetcart_disable(); + break; +#endif +#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) + case CARTRIDGE_TURBO232: + aciacart_disable(); + break; +#endif + /* "Main Slot" */ + default: + DBG(("CART: no disable hook %d", type)); + break; + } +#if 0 + cart_detach_conflicting(type); +#endif + /* make sure the cart has been disabled */ + if (!cart_type_enabled(type)) { + return 0; + } + log_error(LOG_DEFAULT, "Failed to disable cartridge with ID %d.\n", type); return -1; } + /* detach all cartridges @@ -1400,11 +1666,14 @@ int cartridge_enable(int type) */ void cart_detach_all(void) { - DBG(("CART: detach all\n")); + DBG(("CART: detach all")); + debugcart_detach(); /* "slot 0" */ tpi_detach(); magicvoice_detach(); mmc64_detach(); + ieeeflash64_detach(); + ramlink_detach(); /* "Slot 1" */ dqbb_detach(); expert_detach(); @@ -1420,7 +1689,7 @@ void cart_detach_all(void) reu_detach(); sfx_soundexpander_detach(); sfx_soundsampler_detach(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET ethernetcart_detach(); #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) @@ -1440,13 +1709,19 @@ void cart_detach_all(void) */ void cart_detach(int type) { - DBG(("CART: cart_detach ID: %d\n", type)); + DBG(("CART: cart_detach ID: %d", type)); switch (type) { /* "Slot 0" */ case CARTRIDGE_IEEE488: tpi_detach(); break; + case CARTRIDGE_RAMLINK: + ramlink_detach(); + break; + case CARTRIDGE_IEEEFLASH64: + ieeeflash64_detach(); + break; case CARTRIDGE_MAGIC_VOICE: magicvoice_detach(); break; @@ -1494,7 +1769,7 @@ void cart_detach(int type) case CARTRIDGE_SFX_SOUND_SAMPLER: sfx_soundsampler_detach(); break; -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_TFE: ethernetcart_detach(); break; @@ -1520,6 +1795,24 @@ void cart_detach(int type) case CARTRIDGE_ATOMIC_POWER: atomicpower_detach(); break; + case CARTRIDGE_BISPLUS: + bisplus_detach(); + break; + case CARTRIDGE_BLACKBOX3: + blackbox3_detach(); + break; + case CARTRIDGE_BLACKBOX4: + blackbox4_detach(); + break; + case CARTRIDGE_BLACKBOX8: + blackbox8_detach(); + break; + case CARTRIDGE_BLACKBOX9: + blackbox9_detach(); + break; + case CARTRIDGE_BMPDATATURBO: + bmpdataturbo_detach(); + break; case CARTRIDGE_CAPTURE: capture_detach(); break; @@ -1541,6 +1834,9 @@ void cart_detach(int type) case CARTRIDGE_DINAMIC: dinamic_detach(); break; + case CARTRIDGE_DREAN: + drean_detach(); + break; case CARTRIDGE_EASYCALC: easycalc_detach(); break; @@ -1568,6 +1864,9 @@ void cart_detach(int type) case CARTRIDGE_FREEZE_FRAME: freezeframe_detach(); break; + case CARTRIDGE_FREEZE_FRAME_MK2: + freezeframe2_detach(); + break; case CARTRIDGE_FREEZE_MACHINE: freezemachine_detach(); break; @@ -1586,9 +1885,15 @@ void cart_detach(int type) case CARTRIDGE_GMOD2: gmod2_detach(); break; + case CARTRIDGE_GMOD3: + gmod3_detach(); + break; case CARTRIDGE_GS: gs_detach(); break; + case CARTRIDGE_HYPERBASIC: + hyperbasic_detach(); + break; case CARTRIDGE_IDE64: ide64_detach(); break; @@ -1598,21 +1903,36 @@ void cart_detach(int type) case CARTRIDGE_KINGSOFT: kingsoft_detach(); break; + case CARTRIDGE_LT_KERNAL: + ltkernal_detach(); + break; case CARTRIDGE_MACH5: mach5_detach(); break; case CARTRIDGE_MAGIC_DESK: magicdesk_detach(); break; + case CARTRIDGE_MAGIC_DESK_16: + magicdesk16_detach(); + break; case CARTRIDGE_MAGIC_FORMEL: magicformel_detach(); break; + case CARTRIDGE_MAX_BASIC: + maxbasic_detach(); + break; + case CARTRIDGE_MEGABYTER: + megabyter_detach(); + break; case CARTRIDGE_MIKRO_ASSEMBLER: mikroass_detach(); break; case CARTRIDGE_MMC_REPLAY: mmcreplay_detach(); break; + case CARTRIDGE_MULTIMAX: + multimax_detach(); + break; case CARTRIDGE_OCEAN: ocean_detach(); break; @@ -1622,6 +1942,12 @@ void cart_detach(int type) case CARTRIDGE_PAGEFOX: pagefox_detach(); break; + case CARTRIDGE_PARTNER64: + partner64_detach(); + break; + case CARTRIDGE_PROFIDOS: + profidos_detach(); + break; case CARTRIDGE_RETRO_REPLAY: retroreplay_detach(); break; @@ -1631,10 +1957,20 @@ void cart_detach(int type) case CARTRIDGE_REX_EP256: rexep256_detach(); break; + case CARTRIDGE_REX_RAMFLOPPY: + rexramfloppy_detach(); + break; case CARTRIDGE_RGCD: rgcd_detach(); break; -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + uc1_detach(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_detach(); + break; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_detach(); break; @@ -1642,6 +1978,9 @@ void cart_detach(int type) case CARTRIDGE_ROSS: ross_detach(); break; + case CARTRIDGE_SDBOX: + sdbox_detach(); + break; case CARTRIDGE_SILVERROCK_128: silverrock128_detach(); break; @@ -1669,6 +2008,9 @@ void cart_detach(int type) case CARTRIDGE_SUPER_SNAPSHOT_V5: supersnapshot_v5_detach(); break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + turtlegraphics_detach(); + break; case CARTRIDGE_ULTIMAX: generic_ultimax_detach(); break; @@ -1681,8 +2023,11 @@ void cart_detach(int type) case CARTRIDGE_ZAXXON: zaxxon_detach(); break; + case CARTRIDGE_ZIPPCODE48: + zippcode48_detach(); + break; default: - DBG(("CART: no detach hook ID: %d\n", type)); + DBG(("CART: no detach hook ID: %d", type)); break; } } @@ -1690,12 +2035,13 @@ void cart_detach(int type) /* called once by cartridge_init at machine init */ void cart_init(void) { - DBG(("CART: cart_init\n")); + DBG(("CART: cart_init")); /* "Slot 0" */ mmc64_init(); magicvoice_init(); tpi_init(); + /* ieeeflash64_init(); */ /* "Slot 1" */ ramcart_init(); @@ -1715,7 +2061,7 @@ void cart_init(void) reu_init(); /* sfx sound expander */ /* sfx sound sampler */ -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET ethernetcart_init(); #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) @@ -1723,12 +2069,6 @@ void cart_init(void) #endif } -/* Initialize RAM for power-up. */ -void cartridge_ram_init(void) -{ - memset(export_ram0, 0xff, C64CART_RAM_LIMIT); -} - /* called once by c64.c:machine_specific_shutdown at machine shutdown */ void cartridge_shutdown(void) { @@ -1736,9 +2076,11 @@ void cartridge_shutdown(void) tpi_shutdown(); magicvoice_shutdown(); /* mmc64_shutdown(); */ + /* ieeeflash64_shutdown(); */ /* "Main Slot" */ /* "Slot 1" */ + dqbb_shutdown(); /* "IO Slot" */ } @@ -1747,191 +2089,265 @@ void cartridge_shutdown(void) */ void cartridge_init_config(void) { - /* "Main Slot" */ - switch (mem_cartridge_type) { - case CARTRIDGE_STARDOS: - stardos_config_init(); - break; - case CARTRIDGE_ACTION_REPLAY: - actionreplay_config_init(); - break; - case CARTRIDGE_ACTION_REPLAY2: - actionreplay2_config_init(); - break; - case CARTRIDGE_ACTION_REPLAY3: - actionreplay3_config_init(); - break; - case CARTRIDGE_ACTION_REPLAY4: - actionreplay4_config_init(); - break; - case CARTRIDGE_ATOMIC_POWER: - atomicpower_config_init(); - break; - case CARTRIDGE_CAPTURE: - capture_config_init(); - break; - case CARTRIDGE_COMAL80: - comal80_config_init(); - break; - case CARTRIDGE_DELA_EP64: - delaep64_config_init(); - break; - case CARTRIDGE_DELA_EP7x8: - delaep7x8_config_init(); - break; - case CARTRIDGE_DELA_EP256: - delaep256_config_init(); - break; - case CARTRIDGE_DIASHOW_MAKER: - dsm_config_init(); - break; - case CARTRIDGE_DINAMIC: - dinamic_config_init(); - break; - case CARTRIDGE_EASYCALC: - easycalc_config_init(); - break; - case CARTRIDGE_EASYFLASH: - easyflash_config_init(); - break; - case CARTRIDGE_EPYX_FASTLOAD: - epyxfastload_config_init(); - break; - case CARTRIDGE_EXOS: - exos_config_init(); - break; - case CARTRIDGE_FINAL_I: - final_v1_config_init(); - break; - case CARTRIDGE_FINAL_PLUS: - final_plus_config_init(); - break; - case CARTRIDGE_FINAL_III: - final_v3_config_init(); - break; - case CARTRIDGE_FORMEL64: - formel64_config_init(); - break; - case CARTRIDGE_FREEZE_FRAME: - freezeframe_config_init(); - break; - case CARTRIDGE_FREEZE_MACHINE: - freezemachine_config_init(); - break; - case CARTRIDGE_FUNPLAY: - funplay_config_init(); - break; - case CARTRIDGE_GAME_KILLER: - gamekiller_config_init(); - break; - case CARTRIDGE_GENERIC_8KB: - generic_8kb_config_init(); - break; - case CARTRIDGE_GENERIC_16KB: - generic_16kb_config_init(); - break; - case CARTRIDGE_GMOD2: - gmod2_config_init(); - break; - case CARTRIDGE_GS: - gs_config_init(); - break; - case CARTRIDGE_IDE64: - ide64_config_init(); - break; - case CARTRIDGE_KCS_POWER: - kcs_config_init(); - break; - case CARTRIDGE_KINGSOFT: - kingsoft_config_init(); - break; - case CARTRIDGE_MACH5: - mach5_config_init(); - break; - case CARTRIDGE_MAGIC_DESK: - magicdesk_config_init(); - break; - case CARTRIDGE_MAGIC_FORMEL: - magicformel_config_init(); - break; - case CARTRIDGE_MIKRO_ASSEMBLER: - mikroass_config_init(); - break; - case CARTRIDGE_MMC_REPLAY: - mmcreplay_config_init(); - break; - case CARTRIDGE_OCEAN: - ocean_config_init(); - break; - case CARTRIDGE_P64: - p64_config_init(); - break; - case CARTRIDGE_PAGEFOX: - pagefox_config_init(); - break; - case CARTRIDGE_RETRO_REPLAY: - retroreplay_config_init(); - break; - case CARTRIDGE_REX: - rex_config_init(); - break; - case CARTRIDGE_REX_EP256: - rexep256_config_init(); - break; - case CARTRIDGE_RGCD: - rgcd_config_init(); - break; -#ifdef HAVE_PCAP - case CARTRIDGE_RRNETMK3: - rrnetmk3_config_init(); - break; -#endif - case CARTRIDGE_ROSS: - ross_config_init(); - break; - case CARTRIDGE_SILVERROCK_128: - silverrock128_config_init(); - break; - case CARTRIDGE_SIMONS_BASIC: - simon_config_init(); - break; - case CARTRIDGE_SNAPSHOT64: - snapshot64_config_init(); - break; - case CARTRIDGE_STRUCTURED_BASIC: - stb_config_init(); - break; - case CARTRIDGE_SUPER_EXPLODE_V5: - se5_config_init(); - break; - case CARTRIDGE_SUPER_SNAPSHOT: - supersnapshot_v4_config_init(); - break; - case CARTRIDGE_SUPER_SNAPSHOT_V5: - supersnapshot_v5_config_init(); - break; - case CARTRIDGE_SUPER_GAMES: - supergames_config_init(); - break; - case CARTRIDGE_ULTIMAX: - generic_ultimax_config_init(); - break; - case CARTRIDGE_WARPSPEED: - warpspeed_config_init(); - break; - case CARTRIDGE_WESTERMANN: - westermann_config_init(); - break; - case CARTRIDGE_ZAXXON: - zaxxon_config_init(); - break; - /* FIXME: add all missing ones instead of using the default */ - case CARTRIDGE_NONE: - break; - default: - DBG(("CART: no init hook ID: %d\n", mem_cartridge_type)); - cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); - break; + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(mem_cartridge_type)) { + c128cartridge->config_init(mem_cartridge_type); + } else { + /* "Main Slot" */ + switch (mem_cartridge_type) { + case CARTRIDGE_ACTION_REPLAY: + actionreplay_config_init(); + break; + case CARTRIDGE_ACTION_REPLAY2: + actionreplay2_config_init(); + break; + case CARTRIDGE_ACTION_REPLAY3: + actionreplay3_config_init(); + break; + case CARTRIDGE_ACTION_REPLAY4: + actionreplay4_config_init(); + break; + case CARTRIDGE_ATOMIC_POWER: + atomicpower_config_init(); + break; + case CARTRIDGE_BISPLUS: + bisplus_config_init(); + break; + case CARTRIDGE_BLACKBOX3: + blackbox3_config_init(); + break; + case CARTRIDGE_BLACKBOX4: + blackbox4_config_init(); + break; + case CARTRIDGE_BLACKBOX8: + blackbox8_config_init(); + break; + case CARTRIDGE_BLACKBOX9: + blackbox9_config_init(); + break; + case CARTRIDGE_BMPDATATURBO: + bmpdataturbo_config_init(); + break; + case CARTRIDGE_CAPTURE: + capture_config_init(); + break; + case CARTRIDGE_COMAL80: + comal80_config_init(); + break; + case CARTRIDGE_DELA_EP64: + delaep64_config_init(); + break; + case CARTRIDGE_DELA_EP7x8: + delaep7x8_config_init(); + break; + case CARTRIDGE_DELA_EP256: + delaep256_config_init(); + break; + case CARTRIDGE_DIASHOW_MAKER: + dsm_config_init(); + break; + case CARTRIDGE_DINAMIC: + dinamic_config_init(); + break; + case CARTRIDGE_DREAN: + drean_config_init(); + break; + case CARTRIDGE_EASYCALC: + easycalc_config_init(); + break; + case CARTRIDGE_EASYFLASH: + easyflash_config_init(); + break; + case CARTRIDGE_EPYX_FASTLOAD: + epyxfastload_config_init(); + break; + case CARTRIDGE_EXOS: + exos_config_init(); + break; + case CARTRIDGE_FINAL_I: + final_v1_config_init(); + break; + case CARTRIDGE_FINAL_PLUS: + final_plus_config_init(); + break; + case CARTRIDGE_FINAL_III: + final_v3_config_init(); + break; + case CARTRIDGE_FORMEL64: + formel64_config_init(); + break; + case CARTRIDGE_FREEZE_FRAME: + freezeframe_config_init(); + break; + case CARTRIDGE_FREEZE_FRAME_MK2: + freezeframe2_config_init(); + break; + case CARTRIDGE_FREEZE_MACHINE: + freezemachine_config_init(); + break; + case CARTRIDGE_FUNPLAY: + funplay_config_init(); + break; + case CARTRIDGE_GAME_KILLER: + gamekiller_config_init(); + break; + case CARTRIDGE_GENERIC_8KB: + generic_8kb_config_init(); + break; + case CARTRIDGE_GENERIC_16KB: + generic_16kb_config_init(); + break; + case CARTRIDGE_GMOD2: + gmod2_config_init(); + break; + case CARTRIDGE_GMOD3: + gmod3_config_init(); + break; + case CARTRIDGE_GS: + gs_config_init(); + break; + case CARTRIDGE_HYPERBASIC: + hyperbasic_config_init(); + break; + case CARTRIDGE_IDE64: + ide64_config_init(); + break; + case CARTRIDGE_KCS_POWER: + kcs_config_init(); + break; + case CARTRIDGE_KINGSOFT: + kingsoft_config_init(); + break; + case CARTRIDGE_LT_KERNAL: + ltkernal_config_init(); + break; + case CARTRIDGE_MACH5: + mach5_config_init(); + break; + case CARTRIDGE_MAGIC_DESK: + magicdesk_config_init(); + break; + case CARTRIDGE_MAGIC_DESK_16: + magicdesk16_config_init(); + break; + case CARTRIDGE_MAGIC_FORMEL: + magicformel_config_init(); + break; + case CARTRIDGE_MAX_BASIC: + maxbasic_config_init(); + break; + case CARTRIDGE_MEGABYTER: + megabyter_config_init(); + break; + case CARTRIDGE_MIKRO_ASSEMBLER: + mikroass_config_init(); + break; + case CARTRIDGE_MMC_REPLAY: + mmcreplay_config_init(); + break; + case CARTRIDGE_MULTIMAX: + multimax_config_init(); + break; + case CARTRIDGE_OCEAN: + ocean_config_init(); + break; + case CARTRIDGE_P64: + p64_config_init(); + break; + case CARTRIDGE_PAGEFOX: + pagefox_config_init(); + break; + case CARTRIDGE_PARTNER64: + partner64_config_init(); + break; + case CARTRIDGE_PROFIDOS: + profidos_config_init(); + break; + case CARTRIDGE_RETRO_REPLAY: + retroreplay_config_init(); + break; + case CARTRIDGE_REX: + rex_config_init(); + break; + case CARTRIDGE_REX_EP256: + rexep256_config_init(); + break; + case CARTRIDGE_REX_RAMFLOPPY: + rexramfloppy_config_init(); + break; + case CARTRIDGE_RGCD: + rgcd_config_init(); + break; + case CARTRIDGE_UC1: + uc1_config_init(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_config_init(); + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_RRNETMK3: + rrnetmk3_config_init(); + break; +#endif + case CARTRIDGE_ROSS: + ross_config_init(); + break; + case CARTRIDGE_SDBOX: + sdbox_config_init(); + break; + case CARTRIDGE_SILVERROCK_128: + silverrock128_config_init(); + break; + case CARTRIDGE_SIMONS_BASIC: + simon_config_init(); + break; + case CARTRIDGE_SNAPSHOT64: + snapshot64_config_init(); + break; + case CARTRIDGE_STARDOS: + stardos_config_init(); + break; + case CARTRIDGE_STRUCTURED_BASIC: + stb_config_init(); + break; + case CARTRIDGE_SUPER_EXPLODE_V5: + se5_config_init(); + break; + case CARTRIDGE_SUPER_SNAPSHOT: + supersnapshot_v4_config_init(); + break; + case CARTRIDGE_SUPER_SNAPSHOT_V5: + supersnapshot_v5_config_init(); + break; + case CARTRIDGE_SUPER_GAMES: + supergames_config_init(); + break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + turtlegraphics_config_init(); + break; + case CARTRIDGE_ULTIMAX: + generic_ultimax_config_init(); + break; + case CARTRIDGE_WARPSPEED: + warpspeed_config_init(); + break; + case CARTRIDGE_WESTERMANN: + westermann_config_init(); + break; + case CARTRIDGE_ZAXXON: + zaxxon_config_init(); + break; + case CARTRIDGE_ZIPPCODE48: + zippcode48_config_init(); + break; + /* FIXME: add all missing ones instead of using the default */ + case CARTRIDGE_NONE: + break; + default: + DBG(("CART: no init hook ID: %d", mem_cartridge_type)); + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + break; + } } /* "Slot 1" */ @@ -1957,6 +2373,10 @@ void cartridge_init_config(void) mmc64_config_init(&export_passthrough); } else if (tpi_cart_enabled()) { tpi_config_init(&export_passthrough); + } else if (ramlink_cart_enabled()) { + ramlink_config_init(&export_passthrough); + } else if (ieeeflash64_cart_enabled()) { + ieeeflash64_config_init(&export_passthrough); } } @@ -1997,7 +2417,7 @@ void cartridge_reset(void) if (sfx_soundsampler_cart_enabled()) { sfx_soundsampler_reset(); } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (ethernetcart_cart_enabled()) { ethernetcart_reset(); } @@ -2024,6 +2444,9 @@ void cartridge_reset(void) case CARTRIDGE_ATOMIC_POWER: atomicpower_reset(); break; + case CARTRIDGE_BMPDATATURBO: + bmpdataturbo_reset(); + break; case CARTRIDGE_CAPTURE: capture_reset(); break; @@ -2033,12 +2456,21 @@ void cartridge_reset(void) case CARTRIDGE_FORMEL64: formel64_reset(); break; + case CARTRIDGE_FREEZE_FRAME_MK2: + freezeframe2_reset(); + break; case CARTRIDGE_FREEZE_MACHINE: freezemachine_reset(); break; case CARTRIDGE_GMOD2: gmod2_reset(); break; + case CARTRIDGE_GMOD3: + gmod3_reset(); + break; + case CARTRIDGE_HYPERBASIC: + hyperbasic_reset(); + break; case CARTRIDGE_IDE64: ide64_reset(); break; @@ -2048,7 +2480,23 @@ void cartridge_reset(void) case CARTRIDGE_MMC_REPLAY: mmcreplay_reset(); break; -#ifdef HAVE_PCAP + case CARTRIDGE_PARTNER64: + partner64_reset(); + break; + case CARTRIDGE_PROFIDOS: + profidos_reset(); + break; + case CARTRIDGE_REX_RAMFLOPPY: + rexramfloppy_reset(); + break; + case CARTRIDGE_UC1: + uc1_reset(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_reset(); + break; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_reset(); break; @@ -2059,6 +2507,15 @@ void cartridge_reset(void) case CARTRIDGE_RETRO_REPLAY: retroreplay_reset(); break; + case CARTRIDGE_SUPER_EXPLODE_V5: + se5_reset(); + break; + case CARTRIDGE_WARPSPEED: + warpspeed_reset(); + break; + case CARTRIDGE_ZIPPCODE48: + zippcode48_reset(); + break; } /* "Slot 1" */ if (dqbb_cart_enabled()) { @@ -2083,17 +2540,117 @@ void cartridge_reset(void) if (mmc64_cart_enabled()) { mmc64_reset(); } + if (ieeeflash64_cart_enabled()) { + ieeeflash64_reset(); + } if (cpmcart_cart_enabled()) { cpmcart_reset(); } + + if (machine_class == VICE_MACHINE_C128) { + c128cartridge->reset(); + } +} + +/* + called by c64.c:machine_specific_powerup (calls XYZ_powerup) + + we call the hooks in "back to front" order, so carts closer + to the "front" will win with whatever they do. +*/ +void cartridge_powerup(void) +{ + /* "IO Slot" */ + if (georam_cart_enabled()) { + georam_powerup(); + } + if (reu_cart_enabled()) { + reu_powerup(); + } + + if (machine_class == VICE_MACHINE_C128) { + c128cartridge->powerup(); + } + + /* "Main Slot" */ + memset(export_ram0, 0xff, C64CART_RAM_LIMIT); + + switch (mem_cartridge_type) { + case CARTRIDGE_ACTION_REPLAY: + actionreplay_powerup(); + break; + case CARTRIDGE_ATOMIC_POWER: + atomicpower_powerup(); + break; + case CARTRIDGE_CAPTURE: + capture_powerup(); + break; + case CARTRIDGE_EASYFLASH: + easyflash_powerup(); + break; + case CARTRIDGE_KCS_POWER: + kcs_powerup(); + break; + case CARTRIDGE_LT_KERNAL: + ltkernal_powerup(); + break; + case CARTRIDGE_MAGIC_FORMEL: + magicformel_powerup(); + break; + case CARTRIDGE_MAX_BASIC: + maxbasic_powerup(); + break; + case CARTRIDGE_MMC_REPLAY: + mmcreplay_powerup(); + break; + case CARTRIDGE_MULTIMAX: + multimax_powerup(); + break; + case CARTRIDGE_PAGEFOX: + pagefox_powerup(); + break; + case CARTRIDGE_PARTNER64: + partner64_powerup(); + break; + case CARTRIDGE_RETRO_REPLAY: + retroreplay_powerup(); + break; + case CARTRIDGE_SDBOX: + sdbox_powerup(); + break; + case CARTRIDGE_SUPER_SNAPSHOT: + supersnapshot_v4_powerup(); + break; + case CARTRIDGE_SUPER_SNAPSHOT_V5: + supersnapshot_v5_powerup(); + break; + case CARTRIDGE_UC1: + uc1_powerup(); + break; + case CARTRIDGE_UC2: + case CARTRIDGE_UC15: + uc2_powerup(); + break; + } + + /* "Slot 1" */ + if (dqbb_cart_enabled()) { + dqbb_powerup(); + } + if (expert_cart_enabled()) { + expert_powerup(); + } + if (isepic_cart_enabled()) { + isepic_powerup(); + } } /* ------------------------------------------------------------------------- */ /* called by cart_nmi_alarm_triggered, after an alarm occured */ -void cart_freeze(int type) +static void cart_freeze(int type) { - DBG(("CART: freeze\n")); + DBG(("CART: freeze (type:%d)", type)); switch (type) { /* "Slot 0" (no freezer carts) */ /* "Slot 1" */ @@ -2138,6 +2695,9 @@ void cart_freeze(int type) case CARTRIDGE_FREEZE_FRAME: freezeframe_freeze(); break; + case CARTRIDGE_FREEZE_FRAME_MK2: + freezeframe2_freeze(); + break; case CARTRIDGE_FREEZE_MACHINE: freezemachine_freeze(); break; @@ -2147,12 +2707,18 @@ void cart_freeze(int type) case CARTRIDGE_KCS_POWER: kcs_freeze(); break; + case CARTRIDGE_LT_KERNAL: + ltkernal_freeze(); + break; case CARTRIDGE_MAGIC_FORMEL: magicformel_freeze(); break; case CARTRIDGE_MMC_REPLAY: mmcreplay_freeze(); break; + case CARTRIDGE_PARTNER64: + partner64_freeze(); + break; case CARTRIDGE_RETRO_REPLAY: retroreplay_freeze(); break; @@ -2166,6 +2732,9 @@ void cart_freeze(int type) supersnapshot_v5_freeze(); break; } + if (machine_class == VICE_MACHINE_C128) { + c128cartridge->freeze(); + } } /* called by cart_nmi_alarm_triggered */ @@ -2210,9 +2779,11 @@ int cart_freeze_allowed(void) case CARTRIDGE_FINAL_III: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FREEZE_FRAME: + case CARTRIDGE_FREEZE_FRAME_MK2: case CARTRIDGE_FREEZE_MACHINE: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_KCS_POWER: + case CARTRIDGE_LT_KERNAL: case CARTRIDGE_MAGIC_FORMEL: return 1; case CARTRIDGE_MMC_REPLAY: @@ -2220,6 +2791,8 @@ int cart_freeze_allowed(void) return 1; } break; + case CARTRIDGE_PARTNER64: + return 1; case CARTRIDGE_RETRO_REPLAY: if (retroreplay_freeze_allowed()) { return 1; @@ -2230,28 +2803,132 @@ int cart_freeze_allowed(void) case CARTRIDGE_SUPER_SNAPSHOT_V5: return 1; } + + if (machine_class == VICE_MACHINE_C128) { + if (c128cartridge->freeze_allowed() == 1) { + return 1; + } + } + /* "I/O Slot" (no freezer carts) */ return 0; } /* ------------------------------------------------------------------------- */ -/* - flush cart image +/* returns 1 when cartridge (ROM) image can be flushed */ +int cartridge_can_flush_image(int crtid) +{ + const char *p; - all carts whose image might be modified at runtime should be hooked up here. -*/ -int cartridge_flush_image(int type) + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(crtid)) { + return c128cartridge->can_flush_image(crtid); + } + + if (!cartridge_type_enabled(crtid)) { + return 0; + } + p = cartridge_get_filename_by_type(crtid); + if ((p == NULL) || (*p == '\x0')) { + return 0; + } + return 1; +} + +/* returns 1 when secondary cartridge image can be flushed */ +int cartridge_can_flush_secondary_image(int crtid) { - switch (type) { + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(crtid)) { + return c128cartridge->can_flush_secondary_image(crtid); + } + + if (!cartridge_type_enabled(crtid)) { + return 0; + } + + switch (crtid) { /* "Slot 0" */ - case CARTRIDGE_MMC64: - return mmc64_flush_image(); + case CARTRIDGE_RAMLINK: + return ramlink_can_flush_ram_image(); /* "Slot 1" */ - case CARTRIDGE_DQBB: - return dqbb_flush_image(); - case CARTRIDGE_EXPERT: - return expert_flush_image(); + /* "Main Slot" */ + case CARTRIDGE_GMOD2: + return gmod2_can_flush_eeprom(); + case CARTRIDGE_MMC_REPLAY: + return mmcreplay_can_flush_eeprom(); + case CARTRIDGE_REX_RAMFLOPPY: + return rexramfloppy_can_flush_ram(); + } + + return 0; +} + +/* returns 1 when cartridge (ROM) image can be saved */ +int cartridge_can_save_image(int crtid) +{ + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(crtid)) { + return c128cartridge->can_save_image(crtid); + } + + if (!cartridge_type_enabled(crtid)) { + return 0; + } + + return 1; +} + +/* returns 1 when secondary cartridge image can be saved */ +int cartridge_can_save_secondary_image(int crtid) +{ + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(crtid)) { + return c128cartridge->can_save_secondary_image(crtid); + } + + if (!cartridge_type_enabled(crtid)) { + return 0; + } + + switch (crtid) { + /* "Slot 0" */ + case CARTRIDGE_RAMLINK: + return 1; + /* "Slot 1" */ + /* "Main Slot" */ + case CARTRIDGE_GMOD2: + return 1; + case CARTRIDGE_MMC_REPLAY: + return 1; + case CARTRIDGE_REX_RAMFLOPPY: + return 1; + } + + return 0; +} + +/* + flush cart image + + all carts whose image might be modified at runtime should be hooked up here. + + CAUTION: this is only for the primary (usually ROM) image. If the cartridge + has a ROM and a second writeable chip, it should use + cartridge_flush_secondary_image() below for the second chip! +*/ +int cartridge_flush_image(int type) +{ + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + return c128cartridge->flush_image(type); + } + + switch (type) { + /* "Slot 0" */ + case CARTRIDGE_MMC64: + return mmc64_flush_image(); + /* "Slot 1" */ + case CARTRIDGE_DQBB: + return dqbb_flush_image(); + case CARTRIDGE_EXPERT: + return expert_flush_image(); case CARTRIDGE_ISEPIC: return isepic_flush_image(); case CARTRIDGE_RAMCART: @@ -2261,11 +2938,15 @@ int cartridge_flush_image(int type) return easyflash_flush_image(); case CARTRIDGE_GMOD2: return gmod2_flush_image(); + case CARTRIDGE_GMOD3: + return gmod3_flush_image(); + case CARTRIDGE_MEGABYTER: + return megabyter_flush_image(); case CARTRIDGE_MMC_REPLAY: return mmcreplay_flush_image(); case CARTRIDGE_RETRO_REPLAY: return retroreplay_flush_image(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_flush_image(); #endif @@ -2275,6 +2956,30 @@ int cartridge_flush_image(int type) case CARTRIDGE_REU: return reu_flush_image(); } + log_error(LOG_DEFAULT, "Failed flushing cartridge image for cartridge ID %d.", type); + return -1; +} + +int cartridge_flush_secondary_image(int type) +{ + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + return c128cartridge->flush_secondary_image(type); + } + + switch (type) { + /* "Slot 0" */ + case CARTRIDGE_RAMLINK: + return ramlink_flush_ram_image(); + /* "Slot 1" */ + /* "Main Slot" */ + case CARTRIDGE_GMOD2: + return gmod2_flush_eeprom(); + case CARTRIDGE_MMC_REPLAY: + return mmcreplay_flush_eeprom(); + case CARTRIDGE_REX_RAMFLOPPY: + return rexramfloppy_ram_flush(); + } + log_error(LOG_DEFAULT, "Failed flushing secondary image for cartridge ID %d.", type); return -1; } @@ -2284,9 +2989,17 @@ int cartridge_flush_image(int type) *atleast* all carts whose image might be modified at runtime should be hooked up here. TODO: add bin save for all ROM carts also + + CAUTION: this is only for the primary (usually ROM) image. If the cartridge + has a ROM and a second writeable chip, it should use + cartridge_save_secondary_image() below for the second chip! */ int cartridge_bin_save(int type, const char *filename) { + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + return c128cartridge->bin_save(type, filename); + } + switch (type) { /* "Slot 0" */ case CARTRIDGE_MMC64: @@ -2305,11 +3018,15 @@ int cartridge_bin_save(int type, const char *filename) return easyflash_bin_save(filename); case CARTRIDGE_GMOD2: return gmod2_bin_save(filename); + case CARTRIDGE_GMOD3: + return gmod3_bin_save(filename); + case CARTRIDGE_MEGABYTER: + return megabyter_bin_save(filename); case CARTRIDGE_MMC_REPLAY: return mmcreplay_bin_save(filename); case CARTRIDGE_RETRO_REPLAY: return retroreplay_bin_save(filename); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_bin_save(filename); #endif @@ -2319,6 +3036,30 @@ int cartridge_bin_save(int type, const char *filename) case CARTRIDGE_REU: return reu_bin_save(filename); } + log_error(LOG_DEFAULT, "Failed saving binary cartridge image for cartridge ID %d.\n", type); + return -1; +} + +int cartridge_save_secondary_image(int type, const char *filename) +{ + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + return c128cartridge->save_secondary_image(type, filename); + } + + switch (type) { + /* "Slot 0" */ + /* "Slot 1" */ + case CARTRIDGE_RAMLINK: + return ramlink_ram_save(filename); + /* "Main Slot" */ + case CARTRIDGE_GMOD2: + return gmod2_eeprom_save(filename); + case CARTRIDGE_MMC_REPLAY: + return mmcreplay_save_eeprom(filename); + case CARTRIDGE_REX_RAMFLOPPY: + return rexramfloppy_ram_save(filename); + } + log_error(LOG_DEFAULT, "Failed saving secondary image for cartridge ID %d.\n", type); return -1; } @@ -2332,6 +3073,10 @@ int cartridge_bin_save(int type, const char *filename) */ int cartridge_crt_save(int type, const char *filename) { + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(type)) { + return c128cartridge->crt_save(type, filename); + } + switch (type) { /* "Slot 0" */ case CARTRIDGE_MMC64: @@ -2346,15 +3091,20 @@ int cartridge_crt_save(int type, const char *filename) return easyflash_crt_save(filename); case CARTRIDGE_GMOD2: return gmod2_crt_save(filename); + case CARTRIDGE_GMOD3: + return gmod3_crt_save(filename); + case CARTRIDGE_MEGABYTER: + return megabyter_crt_save(filename); case CARTRIDGE_MMC_REPLAY: return mmcreplay_crt_save(filename); case CARTRIDGE_RETRO_REPLAY: return retroreplay_crt_save(filename); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_crt_save(filename); #endif } + log_error(LOG_DEFAULT, "Failed saving .crt cartridge image for cartridge ID %d.", type); return -1; } @@ -2362,6 +3112,7 @@ int cartridge_crt_save(int type, const char *filename) void cartridge_sound_chip_init(void) { + DBG(("cartridge_sound_chip_init")); digimax_sound_chip_init(); sfx_soundsampler_sound_chip_init(); sfx_soundexpander_sound_chip_init(); @@ -2404,8 +3155,9 @@ void cartridge_sound_chip_init(void) TODO: add more cartridges */ -void cartridge_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void cartridge_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { + /* DBG(("CARTHOOKS: cartridge_mmu_translate(%x)",addr)); */ int res = CART_READ_THROUGH; #if 0 /* disable all the mmu translation stuff for testing */ @@ -2427,6 +3179,14 @@ void cartridge_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li if ((res = tpi_mmu_translate(addr, base, start, limit)) == CART_READ_VALID) { return; } + } else if (ieeeflash64_cart_enabled()) { + if ((res = ieeeflash64_mmu_translate(addr, base, start, limit)) == CART_READ_VALID) { + return; + } + } else if (ramlink_cart_enabled()) { + if ((res = ramlink_mmu_translate(addr, base, start, limit)) == CART_READ_VALID) { + return; + } } switch (res) { @@ -2477,13 +3237,22 @@ void cartridge_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li case CARTRIDGE_GMOD2: gmod2_mmu_translate(addr, base, start, limit); return; + case CARTRIDGE_GMOD3: + gmod3_mmu_translate(addr, base, start, limit); + return; case CARTRIDGE_IDE64: ide64_mmu_translate(addr, base, start, limit); return; + case CARTRIDGE_LT_KERNAL: + ltkernal_mmu_translate(addr, base, start, limit); + return; + case CARTRIDGE_MEGABYTER: + megabyter_mmu_translate(addr, base, start, limit); + return; case CARTRIDGE_RETRO_REPLAY: retroreplay_mmu_translate(addr, base, start, limit); return; -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_mmu_translate(addr, base, start, limit); return; @@ -2492,6 +3261,7 @@ void cartridge_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li supersnapshot_v5_mmu_translate(addr, base, start, limit); return; case CARTRIDGE_EPYX_FASTLOAD: /* must go through roml_read to discharge capacitor */ + case CARTRIDGE_ZIPPCODE48: /* must go through roml_read to discharge capacitor */ default: *base = NULL; *start = 0; @@ -2516,10 +3286,10 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i { snapshot_module_t *m; - BYTE i; - BYTE number_of_carts = 0; + uint8_t i; + uint8_t number_of_carts = 0; int cart_ids[C64CART_DUMP_MAX_CARTS]; - int last_cart = 0; + int last_cart = CARTRIDGE_NONE; memset(cart_ids, 0, sizeof(cart_ids)); @@ -2529,7 +3299,7 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i while (e != NULL) { if (number_of_carts == C64CART_DUMP_MAX_CARTS) { - DBG(("CART snapshot save: active carts > max (%i)\n", number_of_carts)); + DBG(("CART snapshot save: active carts > max (%i)", number_of_carts)); return -1; } if (last_cart != (int)e->device->cartid) { @@ -2557,16 +3327,16 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i /* Save "global" cartridge things */ if (0 - || SMW_DW(m, (DWORD)mem_cartridge_type) < 0 + || SMW_DW(m, (uint32_t)mem_cartridge_type) < 0 || SMW_B(m, export.game) < 0 || SMW_B(m, export.exrom) < 0 - || SMW_DW(m, (DWORD)romh_bank) < 0 - || SMW_DW(m, (DWORD)roml_bank) < 0 - || SMW_B(m, (BYTE)export_ram) < 0 + || SMW_DW(m, (uint32_t)romh_bank) < 0 + || SMW_DW(m, (uint32_t)roml_bank) < 0 + || SMW_B(m, (uint8_t)export_ram) < 0 || SMW_B(m, export.ultimax_phi1) < 0 || SMW_B(m, export.ultimax_phi2) < 0 - || SMW_DW(m, (DWORD)cart_freeze_alarm_time) < 0 - || SMW_DW(m, (DWORD)cart_nmi_alarm_time) < 0 + || SMW_CLOCK(m, cart_freeze_alarm_time) < 0 + || SMW_CLOCK(m, cart_nmi_alarm_time) < 0 || SMW_B(m, export_slot1.game) < 0 || SMW_B(m, export_slot1.exrom) < 0 || SMW_B(m, export_slot1.ultimax_phi1) < 0 @@ -2589,7 +3359,7 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i /* Save cart IDs */ for (i = 0; i < number_of_carts; i++) { - if (SMW_DW(m, (DWORD)cart_ids[i]) < 0) { + if (SMW_DW(m, (uint32_t)cart_ids[i]) < 0) { goto fail; } } @@ -2600,399 +3370,534 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i /* Save individual cart data */ for (i = 0; i < number_of_carts; i++) { - switch (cart_ids[i]) { - /* "Slot 0" */ - case CARTRIDGE_CPM: - if (cpmcart_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MMC64: - if (mmc64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MAGIC_VOICE: - if (magicvoice_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_IEEE488: - if (tpi_snapshot_write_module(s) < 0) { - return -1; - } - break; - /* "Slot 1" */ - case CARTRIDGE_DQBB: - if (dqbb_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_EXPERT: - if (expert_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ISEPIC: - if (isepic_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_RAMCART: - if (ramcart_snapshot_write_module(s) < 0) { - return -1; - } - break; + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(cart_ids[i])) { + if (c128cartridge->snapshot_write(cart_ids[i], s) < 0) { + return -1; + } + break; + } else { - /* "Main Slot" */ - case CARTRIDGE_ACTION_REPLAY: - if (actionreplay_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ACTION_REPLAY2: - if (actionreplay2_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ACTION_REPLAY3: - if (actionreplay3_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ACTION_REPLAY4: - if (actionreplay4_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ATOMIC_POWER: - if (atomicpower_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_CAPTURE: - if (capture_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_COMAL80: - if (comal80_snapshot_write_module(s) < 0) { + switch (cart_ids[i]) { + /* "Debug" */ + case CARTRIDGE_DEBUGCART: + /* do nothing */ + break; + + /* "Slot 0" */ + case CARTRIDGE_CPM: + if (cpmcart_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_IEEE488: + if (tpi_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_RAMLINK: + if (ramlink_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_IEEEFLASH64: + if (ieeeflash64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MAGIC_VOICE: + if (magicvoice_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MMC64: + if (mmc64_snapshot_write_module(s) < 0) { + return -1; + } + break; + + /* "Slot 1" */ + case CARTRIDGE_DQBB: + if (dqbb_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_EXPERT: + if (expert_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ISEPIC: + if (isepic_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_RAMCART: + if (ramcart_snapshot_write_module(s) < 0) { + return -1; + } + break; + + /* "Main Slot" */ + case CARTRIDGE_ACTION_REPLAY: + if (actionreplay_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ACTION_REPLAY2: + if (actionreplay2_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ACTION_REPLAY3: + if (actionreplay3_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ACTION_REPLAY4: + if (actionreplay4_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ATOMIC_POWER: + if (atomicpower_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_BISPLUS: + if (bisplus_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_BLACKBOX3: + if (blackbox3_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_BLACKBOX4: + if (blackbox4_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_BLACKBOX8: + if (blackbox8_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_BMPDATATURBO: + if (bmpdataturbo_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_CAPTURE: + if (capture_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_COMAL80: + if (comal80_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DELA_EP64: + if (delaep64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DELA_EP7x8: + if (delaep7x8_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DELA_EP256: + if (delaep256_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DIASHOW_MAKER: + if (dsm_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DINAMIC: + if (dinamic_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DREAN: + if (drean_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_EASYCALC: + if (easycalc_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_EASYFLASH: + if (easyflash_snapshot_write_module(s, save_cart_roms) < 0) { + return -1; + } + break; + case CARTRIDGE_EPYX_FASTLOAD: + if (epyxfastload_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_EXOS: + if (exos_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FINAL_I: + if (final_v1_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FINAL_III: + if (final_v3_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FINAL_PLUS: + if (final_plus_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FORMEL64: + if (formel64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FREEZE_FRAME: + if (freezeframe_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FREEZE_FRAME_MK2: + if (freezeframe2_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FREEZE_MACHINE: + if (freezemachine_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_FUNPLAY: + if (funplay_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_GAME_KILLER: + if (gamekiller_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_GENERIC_16KB: + case CARTRIDGE_GENERIC_8KB: + case CARTRIDGE_ULTIMAX: + if (generic_snapshot_write_module(s, cart_ids[i]) < 0) { + return -1; + } + break; + case CARTRIDGE_GMOD2: + if (gmod2_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_GMOD3: + if (gmod3_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_GS: + if (gs_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_HYPERBASIC: + if (hyperbasic_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_IDE64: + if (ide64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_KCS_POWER: + if (kcs_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_KINGSOFT: + if (kingsoft_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_LT_KERNAL: + if (ltkernal_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MACH5: + if (mach5_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MAGIC_DESK: + if (magicdesk_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MAGIC_DESK_16: + if (magicdesk16_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MAGIC_FORMEL: + if (magicformel_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MAX_BASIC: + if (maxbasic_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MEGABYTER: + if (megabyter_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MIKRO_ASSEMBLER: + if (mikroass_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MMC_REPLAY: + if (mmcreplay_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_MULTIMAX: + if (multimax_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_OCEAN: + if (ocean_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_P64: + if (p64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_PAGEFOX: + if (pagefox_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_PARTNER64: + if (partner64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_PROFIDOS: + if (profidos_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_RETRO_REPLAY: + if (retroreplay_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_REX: + if (rex_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_REX_EP256: + if (rexep256_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_REX_RAMFLOPPY: + if (rexramfloppy_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_RGCD: + if (rgcd_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_UC1: + if (uc1_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + if (uc2_snapshot_write_module(s) < 0) { + return -1; + } + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_RRNETMK3: + if (rrnetmk3_snapshot_write_module(s) < 0) { + return -1; + } + break; +#endif + case CARTRIDGE_ROSS: + if (ross_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SDBOX: + if (sdbox_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SILVERROCK_128: + if (silverrock128_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SIMONS_BASIC: + if (simon_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SNAPSHOT64: + if (snapshot64_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_STARDOS: + if (stardos_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_STRUCTURED_BASIC: + if (stb_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SUPER_EXPLODE_V5: + if (se5_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SUPER_GAMES: + if (supergames_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SUPER_SNAPSHOT: + if (supersnapshot_v4_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SUPER_SNAPSHOT_V5: + if (supersnapshot_v5_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + if (turtlegraphics_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_WARPSPEED: + if (warpspeed_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_WESTERMANN: + if (westermann_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ZAXXON: + if (zaxxon_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_ZIPPCODE48: + if (zippcode48_snapshot_write_module(s) < 0) { + return -1; + } + break; + + /* "IO Slot" */ + case CARTRIDGE_DIGIMAX: + if (digimax_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_DS12C887RTC: + if (ds12c887rtc_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_GEORAM: + if (georam_write_snapshot_module(s) < 0) { + return -1; + } + break; +#ifdef HAVE_MIDI + case CARTRIDGE_MIDI_PASSPORT: + case CARTRIDGE_MIDI_DATEL: + case CARTRIDGE_MIDI_SEQUENTIAL: + case CARTRIDGE_MIDI_NAMESOFT: + case CARTRIDGE_MIDI_MAPLIN: + if (c64_midi_snapshot_write_module(s) < 0) { + return -1; + } + break; +#endif + case CARTRIDGE_REU: + if (reu_write_snapshot_module(s, store_reu_data) < 0) { + return -1; + } + break; + case CARTRIDGE_SFX_SOUND_EXPANDER: + if (sfx_soundexpander_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SFX_SOUND_SAMPLER: + if (sfx_soundsampler_snapshot_write_module(s) < 0) { + return -1; + } + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_TFE: + if (ethernetcart_snapshot_write_module(s) < 0) { + return -1; + } + break; +#endif +#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) + case CARTRIDGE_TURBO232: + if (aciacart_snapshot_write_module(s) < 0) { + return -1; + } + break; +#endif + + default: + /* If the cart cannot be saved, we obviously can't load it either. + Returning an error at this point is better than failing at later. */ + DBG(("CART snapshot save: cart %i handler missing", cart_ids[i])); return -1; - } - break; - case CARTRIDGE_DELA_EP64: - if (delaep64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_DELA_EP7x8: - if (delaep7x8_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_DELA_EP256: - if (delaep256_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_DIASHOW_MAKER: - if (dsm_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_DINAMIC: - if (dinamic_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_EASYCALC: - if (easycalc_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_EASYFLASH: - if (easyflash_snapshot_write_module(s, save_cart_roms) < 0) { - return -1; - } - break; - case CARTRIDGE_EPYX_FASTLOAD: - if (epyxfastload_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_EXOS: - if (exos_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FINAL_I: - if (final_v1_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FINAL_III: - if (final_v3_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FINAL_PLUS: - if (final_plus_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FORMEL64: - if (formel64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FREEZE_FRAME: - if (freezeframe_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FREEZE_MACHINE: - if (freezemachine_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_FUNPLAY: - if (funplay_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_GAME_KILLER: - if (gamekiller_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_GENERIC_16KB: - case CARTRIDGE_GENERIC_8KB: - case CARTRIDGE_ULTIMAX: - if (generic_snapshot_write_module(s, cart_ids[i]) < 0) { - return -1; - } - break; - case CARTRIDGE_GMOD2: - if (gmod2_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_GS: - if (gs_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_IDE64: - if (ide64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_KCS_POWER: - if (kcs_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_KINGSOFT: - if (kingsoft_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MACH5: - if (mach5_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MAGIC_DESK: - if (magicdesk_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MAGIC_FORMEL: - if (magicformel_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MIKRO_ASSEMBLER: - if (mikroass_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_MMC_REPLAY: - if (mmcreplay_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_OCEAN: - if (ocean_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_P64: - if (p64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_PAGEFOX: - if (pagefox_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_RETRO_REPLAY: - if (retroreplay_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_REX: - if (rex_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_REX_EP256: - if (rexep256_snapshot_read_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_RGCD: - if (rgcd_snapshot_write_module(s) < 0) { - return -1; - } - break; -#ifdef HAVE_PCAP - case CARTRIDGE_RRNETMK3: - if (rrnetmk3_snapshot_write_module(s) < 0) { - return -1; - } - break; -#endif - case CARTRIDGE_ROSS: - if (ross_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SILVERROCK_128: - if (silverrock128_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SIMONS_BASIC: - if (simon_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SNAPSHOT64: - if (snapshot64_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_STARDOS: - if (stardos_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_STRUCTURED_BASIC: - if (stb_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SUPER_EXPLODE_V5: - if (se5_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SUPER_GAMES: - if (supergames_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SUPER_SNAPSHOT: - if (supersnapshot_v4_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SUPER_SNAPSHOT_V5: - if (supersnapshot_v5_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_WARPSPEED: - if (warpspeed_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_WESTERMANN: - if (westermann_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_ZAXXON: - if (zaxxon_snapshot_write_module(s) < 0) { - return -1; - } - break; - - /* "IO Slot" */ - case CARTRIDGE_DIGIMAX: - if (digimax_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_DS12C887RTC: - if (ds12c887rtc_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_GEORAM: - if (georam_write_snapshot_module(s) < 0) { - return -1; - } - break; -#ifdef HAVE_MIDI - case CARTRIDGE_MIDI_PASSPORT: - case CARTRIDGE_MIDI_DATEL: - case CARTRIDGE_MIDI_SEQUENTIAL: - case CARTRIDGE_MIDI_NAMESOFT: - case CARTRIDGE_MIDI_MAPLIN: - if (c64_midi_snapshot_write_module(s) < 0) { - return -1; - } - break; -#endif - case CARTRIDGE_REU: - if (reu_write_snapshot_module(s, store_reu_data) < 0) { - return -1; - } - break; - case CARTRIDGE_SFX_SOUND_EXPANDER: - if (sfx_soundexpander_snapshot_write_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SFX_SOUND_SAMPLER: - if (sfx_soundsampler_snapshot_write_module(s) < 0) { - return -1; - } - break; -#ifdef HAVE_PCAP - case CARTRIDGE_TFE: - if (ethernetcart_snapshot_write_module(s) < 0) { - return -1; - } - break; -#endif -#if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - case CARTRIDGE_TURBO232: - if (aciacart_snapshot_write_module(s) < 0) { - return -1; - } - break; -#endif - - default: - /* If the cart cannot be saved, we obviously can't load it either. - Returning an error at this point is better than failing at later. */ - DBG(("CART snapshot save: cart %i handler missing\n", cart_ids[i])); - return -1; + } } } @@ -3008,13 +3913,13 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s, int store_reu_data, i int cartridge_snapshot_read_modules(struct snapshot_s *s, int read_reu_data, int read_cart_roms) { snapshot_module_t *m; - BYTE vmajor, vminor; + uint8_t vmajor, vminor; - BYTE i; - BYTE number_of_carts; + uint8_t i; + uint8_t number_of_carts; int cart_ids[C64CART_DUMP_MAX_CARTS]; int local_cartridge_reset; - DWORD dummy; + uint32_t dummy; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); @@ -3042,7 +3947,7 @@ int cartridge_snapshot_read_modules(struct snapshot_s *s, int read_reu_data, int } if (number_of_carts > C64CART_DUMP_MAX_CARTS) { - DBG(("CART snapshot read: carts %i > max %i\n", number_of_carts, C64CART_DUMP_MAX_CARTS)); + DBG(("CART snapshot read: carts %i > max %i", number_of_carts, C64CART_DUMP_MAX_CARTS)); goto fail; } @@ -3056,8 +3961,8 @@ int cartridge_snapshot_read_modules(struct snapshot_s *s, int read_reu_data, int || SMR_B_INT(m, &export_ram) < 0 || SMR_B(m, &export.ultimax_phi1) < 0 || SMR_B(m, &export.ultimax_phi2) < 0 - || SMR_DW(m, &cart_freeze_alarm_time) < 0 - || SMR_DW(m, &cart_nmi_alarm_time) < 0 + || SMR_CLOCK(m, &cart_freeze_alarm_time) < 0 + || SMR_CLOCK(m, &cart_nmi_alarm_time) < 0 || SMR_B(m, &export_slot1.game) < 0 || SMR_B(m, &export_slot1.exrom) < 0 || SMR_B(m, &export_slot1.ultimax_phi1) < 0 @@ -3091,399 +3996,532 @@ int cartridge_snapshot_read_modules(struct snapshot_s *s, int read_reu_data, int /* Read individual cart data */ for (i = 0; i < number_of_carts; i++) { - switch (cart_ids[i]) { - /* "Slot 0" */ - case CARTRIDGE_CPM: - if (cpmcart_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MMC64: - if (mmc64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MAGIC_VOICE: - if (magicvoice_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_IEEE488: - if (tpi_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + if ((machine_class == VICE_MACHINE_C128) && CARTRIDGE_C128_ISID(cart_ids[i])) { + if (c128cartridge->snapshot_read(cart_ids[i], s) < 0) { + return -1; + } + break; + } else { - /* "Slot 1" */ - case CARTRIDGE_DQBB: - if (dqbb_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_EXPERT: - if (expert_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ISEPIC: - if (isepic_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_RAMCART: - if (ramcart_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + switch (cart_ids[i]) { + /* "Debug" */ + case CARTRIDGE_DEBUGCART: + /* do nothing */ + break; - /* "Main Slot" */ - case CARTRIDGE_ACTION_REPLAY: - if (actionreplay_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ACTION_REPLAY2: - if (actionreplay2_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ACTION_REPLAY3: - if (actionreplay3_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ACTION_REPLAY4: - if (actionreplay4_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ATOMIC_POWER: - if (atomicpower_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_CAPTURE: - if (capture_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_COMAL80: - if (comal80_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DELA_EP64: - if (delaep64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DELA_EP7x8: - if (delaep7x8_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DELA_EP256: - if (delaep256_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DIASHOW_MAKER: - if (dsm_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DINAMIC: - if (dinamic_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_EASYCALC: - if (easycalc_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_EASYFLASH: - if (easyflash_snapshot_read_module(s, read_cart_roms) < 0) { - goto fail2; - } - break; - case CARTRIDGE_EPYX_FASTLOAD: - if (epyxfastload_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_EXOS: - if (exos_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FINAL_I: - if (final_v1_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FINAL_III: - if (final_v3_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FINAL_PLUS: - if (final_plus_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FORMEL64: - if (formel64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FREEZE_FRAME: - if (freezeframe_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FREEZE_MACHINE: - if (freezemachine_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_FUNPLAY: - if (funplay_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_GAME_KILLER: - if (gamekiller_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_GENERIC_16KB: - case CARTRIDGE_GENERIC_8KB: - case CARTRIDGE_ULTIMAX: - if (generic_snapshot_read_module(s, cart_ids[i]) < 0) { - goto fail2; - } - break; - case CARTRIDGE_GMOD2: - if (gmod2_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_GS: - if (gs_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_IDE64: - if (ide64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_KCS_POWER: - if (kcs_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_KINGSOFT: - if (kingsoft_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MACH5: - if (mach5_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MAGIC_DESK: - if (magicdesk_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MAGIC_FORMEL: - if (magicformel_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MIKRO_ASSEMBLER: - if (mikroass_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_MMC_REPLAY: - if (mmcreplay_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_OCEAN: - if (ocean_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_P64: - if (p64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_PAGEFOX: - if (pagefox_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_RETRO_REPLAY: - if (retroreplay_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_REX: - if (rex_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_REX_EP256: - if (rexep256_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_RGCD: - if (rgcd_snapshot_read_module(s) < 0) { - goto fail2; - } - break; -#ifdef HAVE_PCAP - case CARTRIDGE_RRNETMK3: - if (rrnetmk3_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + /* "Slot 0" */ + case CARTRIDGE_CPM: + if (cpmcart_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_IEEE488: + if (tpi_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_RAMLINK: + if (ramlink_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_IEEEFLASH64: + if (ieeeflash64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MAGIC_VOICE: + if (magicvoice_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MMC64: + if (mmc64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + + /* "Slot 1" */ + case CARTRIDGE_DQBB: + if (dqbb_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_EXPERT: + if (expert_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ISEPIC: + if (isepic_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_RAMCART: + if (ramcart_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + + /* "Main Slot" */ + case CARTRIDGE_ACTION_REPLAY: + if (actionreplay_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ACTION_REPLAY2: + if (actionreplay2_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ACTION_REPLAY3: + if (actionreplay3_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ACTION_REPLAY4: + if (actionreplay4_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ATOMIC_POWER: + if (atomicpower_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_BISPLUS: + if (bisplus_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_BLACKBOX3: + if (blackbox3_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_BLACKBOX4: + if (blackbox4_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_BLACKBOX8: + if (blackbox8_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_BMPDATATURBO: + if (bmpdataturbo_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_CAPTURE: + if (capture_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_COMAL80: + if (comal80_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DELA_EP64: + if (delaep64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DELA_EP7x8: + if (delaep7x8_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DELA_EP256: + if (delaep256_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DIASHOW_MAKER: + if (dsm_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DINAMIC: + if (dinamic_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DREAN: + if (drean_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_EASYCALC: + if (easycalc_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_EASYFLASH: + if (easyflash_snapshot_read_module(s, read_cart_roms) < 0) { + goto fail2; + } + break; + case CARTRIDGE_EPYX_FASTLOAD: + if (epyxfastload_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_EXOS: + if (exos_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FINAL_I: + if (final_v1_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FINAL_III: + if (final_v3_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FINAL_PLUS: + if (final_plus_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FORMEL64: + if (formel64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FREEZE_FRAME: + if (freezeframe_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FREEZE_FRAME_MK2: + if (freezeframe2_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FREEZE_MACHINE: + if (freezemachine_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_FUNPLAY: + if (funplay_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GAME_KILLER: + if (gamekiller_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GENERIC_16KB: + case CARTRIDGE_GENERIC_8KB: + case CARTRIDGE_ULTIMAX: + if (generic_snapshot_read_module(s, cart_ids[i]) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GMOD2: + if (gmod2_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GMOD3: + if (gmod3_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GS: + if (gs_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_HYPERBASIC: + if (hyperbasic_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_IDE64: + if (ide64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_KCS_POWER: + if (kcs_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_KINGSOFT: + if (kingsoft_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_LT_KERNAL: + if (ltkernal_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MACH5: + if (mach5_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MAGIC_DESK: + if (magicdesk_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MAGIC_DESK_16: + if (magicdesk16_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MAGIC_FORMEL: + if (magicformel_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MAX_BASIC: + if (maxbasic_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MEGABYTER: + if (megabyter_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MIKRO_ASSEMBLER: + if (mikroass_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MMC_REPLAY: + if (mmcreplay_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_MULTIMAX: + if (multimax_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_OCEAN: + if (ocean_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_P64: + if (p64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_PAGEFOX: + if (pagefox_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_PARTNER64: + if (partner64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_PROFIDOS: + if (profidos_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_RETRO_REPLAY: + if (retroreplay_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_REX: + if (rex_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_REX_EP256: + if (rexep256_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_REX_RAMFLOPPY: + if (rexramfloppy_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_RGCD: + if (rgcd_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_UC1: + if (uc1_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + if (uc2_snapshot_read_module(s) < 0) { + goto fail2; + } + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_RRNETMK3: + if (rrnetmk3_snapshot_read_module(s) < 0) { + goto fail2; + } + break; #endif - case CARTRIDGE_ROSS: - if (ross_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SILVERROCK_128: - if (silverrock128_snapshot_read_module(s) < 0) { - return -1; - } - break; - case CARTRIDGE_SIMONS_BASIC: - if (simon_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SNAPSHOT64: - if (snapshot64_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_STARDOS: - if (stardos_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_STRUCTURED_BASIC: - if (stb_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SUPER_EXPLODE_V5: - if (se5_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SUPER_GAMES: - if (supergames_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SUPER_SNAPSHOT: - if (supersnapshot_v4_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SUPER_SNAPSHOT_V5: - if (supersnapshot_v5_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_WARPSPEED: - if (warpspeed_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_WESTERMANN: - if (westermann_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_ZAXXON: - if (zaxxon_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + case CARTRIDGE_ROSS: + if (ross_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SDBOX: + if (sdbox_snapshot_read_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SILVERROCK_128: + if (silverrock128_snapshot_read_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_SIMONS_BASIC: + if (simon_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SNAPSHOT64: + if (snapshot64_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_STARDOS: + if (stardos_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_STRUCTURED_BASIC: + if (stb_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SUPER_EXPLODE_V5: + if (se5_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SUPER_GAMES: + if (supergames_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SUPER_SNAPSHOT: + if (supersnapshot_v4_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SUPER_SNAPSHOT_V5: + if (supersnapshot_v5_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_TURTLE_GRAPHICS_II: + if (turtlegraphics_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_WARPSPEED: + if (warpspeed_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_WESTERMANN: + if (westermann_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ZAXXON: + if (zaxxon_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_ZIPPCODE48: + if (zippcode48_snapshot_read_module(s) < 0) { + goto fail2; + } + break; - /* "IO Slot" */ - case CARTRIDGE_DIGIMAX: - if (digimax_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_DS12C887RTC: - if (ds12c887rtc_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_GEORAM: - if (georam_read_snapshot_module(s) < 0) { - goto fail2; - } - break; + /* "IO Slot" */ + case CARTRIDGE_DIGIMAX: + if (digimax_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_DS12C887RTC: + if (ds12c887rtc_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_GEORAM: + if (georam_read_snapshot_module(s) < 0) { + goto fail2; + } + break; #ifdef HAVE_MIDI - case CARTRIDGE_MIDI_PASSPORT: - case CARTRIDGE_MIDI_DATEL: - case CARTRIDGE_MIDI_SEQUENTIAL: - case CARTRIDGE_MIDI_NAMESOFT: - case CARTRIDGE_MIDI_MAPLIN: - if (c64_midi_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + case CARTRIDGE_MIDI_PASSPORT: + case CARTRIDGE_MIDI_DATEL: + case CARTRIDGE_MIDI_SEQUENTIAL: + case CARTRIDGE_MIDI_NAMESOFT: + case CARTRIDGE_MIDI_MAPLIN: + if (c64_midi_snapshot_read_module(s) < 0) { + goto fail2; + } + break; #endif - case CARTRIDGE_REU: - if (reu_read_snapshot_module(s, read_reu_data) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SFX_SOUND_EXPANDER: - if (sfx_soundexpander_snapshot_read_module(s) < 0) { - goto fail2; - } - break; - case CARTRIDGE_SFX_SOUND_SAMPLER: - if (sfx_soundsampler_snapshot_read_module(s) < 0) { - goto fail2; - } - break; -#ifdef HAVE_PCAP - case CARTRIDGE_TFE: - if (ethernetcart_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + case CARTRIDGE_REU: + if (reu_read_snapshot_module(s, read_reu_data) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SFX_SOUND_EXPANDER: + if (sfx_soundexpander_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_SFX_SOUND_SAMPLER: + if (sfx_soundsampler_snapshot_read_module(s) < 0) { + goto fail2; + } + break; +#ifdef HAVE_RAWNET + case CARTRIDGE_TFE: + if (ethernetcart_snapshot_read_module(s) < 0) { + goto fail2; + } + break; #endif #if defined(HAVE_RS232DEV) || defined(HAVE_RS232NET) - case CARTRIDGE_TURBO232: - if (aciacart_snapshot_read_module(s) < 0) { - goto fail2; - } - break; + case CARTRIDGE_TURBO232: + if (aciacart_snapshot_read_module(s) < 0) { + goto fail2; + } + break; #endif - default: - DBG(("CART snapshot read: cart %i handler missing\n", cart_ids[i])); - goto fail2; + default: + DBG(("CART snapshot read: cart %i handler missing", cart_ids[i])); + goto fail2; + } } - cart_attach_from_snapshot(cart_ids[i]); } diff --git a/src/Emulators/vice/c64/cart/c64cartmem.c b/src/Emulators/vice/c64/cart/c64cartmem.c index 39307358..33aeee05 100644 --- a/src/Emulators/vice/c64/cart/c64cartmem.c +++ b/src/Emulators/vice/c64/cart/c64cartmem.c @@ -53,6 +53,10 @@ #include "actionreplay4.h" #include "actionreplay.h" #include "atomicpower.h" +#include "bisplus.h" +#include "blackbox3.h" +#include "blackbox4.h" +#include "blackbox8.h" #include "c64acia.h" #include "c64-generic.h" #include "c64-midi.h" @@ -64,6 +68,7 @@ #include "delaep7x8.h" #include "dinamic.h" #include "dqbb.h" +#include "drean.h" #include "easyflash.h" #include "epyxfastload.h" #include "exos.h" @@ -73,33 +78,46 @@ #include "final3.h" #include "formel64.h" #include "freezeframe.h" +#include "freezeframe2.h" #include "freezemachine.h" #include "funplay.h" #include "gamekiller.h" #include "georam.h" #include "gmod2.h" +#include "gmod3.h" #include "gs.h" +#include "hyperbasic.h" #include "ide64.h" +#include "ieeeflash64.h" #include "isepic.h" #include "kcs.h" #include "kingsoft.h" +#include "ltkernal.h" #include "mach5.h" #include "magicdesk.h" #include "magicformel.h" #include "magicvoice.h" +#include "maxbasic.h" +#include "megabyter.h" #include "mikroass.h" #include "mmc64.h" #include "mmcreplay.h" +#include "multimax.h" #include "ocean.h" #include "pagefox.h" +#include "partner64.h" #include "prophet64.h" +#include "profidos.h" #include "ramcart.h" +#include "ramlink.h" #include "retroreplay.h" #include "reu.h" #include "rexep256.h" +#include "rexramfloppy.h" #include "rexutility.h" #include "rrnetmk3.h" #include "ross.h" +#include "sdbox.h" #include "simonsbasic.h" #include "snapshot64.h" #include "stardos.h" @@ -108,9 +126,13 @@ #include "superexplode5.h" #include "supersnapshot.h" #include "supersnapshot4.h" +#include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" #include "warpspeed.h" #include "westermann.h" #include "zaxxon.h" +#include "zippcode48.h" #undef CARTRIDGE_INCLUDE_PRIVATE_API /* #define DEBUGCART */ @@ -135,6 +157,21 @@ extern int mem_cartridge_type; /* Type of the cartridge attached. ("Main Slot") static void ultimax_memptr_update(void); +/* + * Extra static declarations to keep compilers happy with -Wmissing-prototypes + * Since I don't really know how this module works with all the #ifdef's, this + * will have to for now. 2017-04-09, Compyx + */ +void cart_set_port_exrom_slot0(int); +void cart_set_port_game_slot0(int); +void cart_port_config_changed_slot0(void); +void cart_config_changed_slot0(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag); + +void cart_set_port_exrom_slot1(int); +void cart_set_port_game_slot1(int); +void cart_port_config_changed_slot1(void); +void cart_config_changed_slot1(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag); + /* mode_phiN: @@ -155,14 +192,14 @@ static void ultimax_memptr_update(void); bit 1 0x02 - release freeze (stop asserting NMI) bit 0 0x01 - r/w flag */ -const char *cart_config_string(BYTE mode) +const char *cart_config_string(uint8_t mode) { - const char *modes[4] = {"8k game", "16k game", "Off", "Ultimax"}; + static const char * const modes[4] = {"8k game", "16k game", "Off", "Ultimax"}; return modes[mode & 3]; } #ifndef USESLOTS -static void cart_config_changed(int slot, BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag) +static void cart_config_changed(int slot, uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag) { #ifdef DEBUGCART static int old1 = 0, old2 = 0, old3 = 0; @@ -209,6 +246,7 @@ static void cart_config_changed(int slot, BYTE mode_phi1, BYTE mode_phi2, unsign } #endif + void cart_set_port_exrom_slot0(int n) { export.exrom = n; @@ -225,7 +263,7 @@ void cart_port_config_changed_slot0(void) ultimax_memptr_update(); } -void cart_config_changed_slot0(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag) +void cart_config_changed_slot0(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag) { assert(((mode_phi2 >> CMODE_BANK_SHIFT) & CMODE_BANK_MASK) == 0); assert((wflag & CMODE_RELEASE_FREEZE) == 0); @@ -233,6 +271,14 @@ void cart_config_changed_slot0(BYTE mode_phi1, BYTE mode_phi2, unsigned int wfla assert((wflag & CMODE_PHI2_RAM) == 0); assert((wflag & CMODE_EXPORT_RAM) == 0); +#ifdef DEBUGCART + static int old1 = 0, old2 = 0, old3 = 0; + if ((mode_phi1 != old1) || (mode_phi2 != old2) || (wflag != old3)) { + DBG(("CARTMEM: cart_config_changed_slot0 phi1:%d phi2:%d bank: %d flags:%02x\n", mode_phi1 & 3, mode_phi2 & 3, (mode_phi2 >> CMODE_BANK_SHIFT) & CMODE_BANK_MASK, wflag)); + } + old1 = mode_phi1; old2 = mode_phi2; old3 = wflag; +#endif + #ifndef USESLOTS cart_config_changed(0, mode_phi1, mode_phi2, wflag); #else @@ -292,6 +338,12 @@ void cart_passthrough_changed(void) case CARTRIDGE_IEEE488: tpi_passthrough_changed(&export_passthrough); break; + case CARTRIDGE_IEEEFLASH64: + ieeeflash64_passthrough_changed(&export_passthrough); + break; + case CARTRIDGE_RAMLINK: + ramlink_passthrough_changed(&export_passthrough); + break; default: /* no slot 0 cartridge */ break; @@ -299,6 +351,7 @@ void cart_passthrough_changed(void) } #endif + void cart_set_port_exrom_slot1(int n) { #ifndef USESLOTS @@ -325,7 +378,7 @@ void cart_port_config_changed_slot1(void) ultimax_memptr_update(); } -void cart_config_changed_slot1(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag) +void cart_config_changed_slot1(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag) { assert(((mode_phi2 >> CMODE_BANK_SHIFT) & CMODE_BANK_MASK) == 0); assert(((wflag >> CMODE_EXPORT_RAM_SHIFT) & 1) == 0); @@ -369,6 +422,8 @@ void cart_config_changed_slot1(BYTE mode_phi1, BYTE mode_phi2, unsigned int wfla #endif } + + void cart_set_port_exrom_slotmain(int n) { #ifndef USESLOTS @@ -415,7 +470,7 @@ void cart_port_config_changed_slotmain(void) ultimax_memptr_update(); } -void cart_config_changed_slotmain(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag) +void cart_config_changed_slotmain(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag) { #ifndef USESLOTS cart_config_changed(2, mode_phi1, mode_phi2, wflag); @@ -491,6 +546,8 @@ void cart_romlbank_set_slotmain(unsigned int bank) magic voice + ltkernal + isepic expert @@ -498,9 +555,12 @@ void cart_romlbank_set_slotmain(unsigned int bank) exos final plus game killer + gmod3 (Uses ultimax to change the hw vectors at fff8-ffff) capture magicformel mmcreplay + ieeeflash64 + ramlink carts that use "unusual" mapping: @@ -527,7 +587,7 @@ void cart_romlbank_set_slotmain(unsigned int bank) midi acia clockport - ethernetcart + ethernetcart hook default @@ -561,7 +621,7 @@ void cart_romlbank_set_slotmain(unsigned int bank) /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -BYTE roml_read_slotmain(WORD addr) +uint8_t roml_read_slotmain(uint16_t addr) { /* "Main Slot" */ switch (mem_cartridge_type) { @@ -581,21 +641,42 @@ BYTE roml_read_slotmain(WORD addr) return final_v1_roml_read(addr); case CARTRIDGE_FINAL_PLUS: return final_plus_roml_read(addr); + case CARTRIDGE_FREEZE_FRAME_MK2: + return freezeframe2_roml_read(addr); case CARTRIDGE_FREEZE_MACHINE: return freezemachine_roml_read(addr); case CARTRIDGE_GMOD2: return gmod2_roml_read(addr); + case CARTRIDGE_GMOD3: + return gmod3_roml_read(addr); case CARTRIDGE_IDE64: return ide64_rom_read(addr); case CARTRIDGE_KINGSOFT: return kingsoft_roml_read(addr); + case CARTRIDGE_LT_KERNAL: + return ltkernal_roml_read(addr); + case CARTRIDGE_MAX_BASIC: + return maxbasic_roml_read(addr); + case CARTRIDGE_MEGABYTER: + return megabyter_roml_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_roml_read(addr); + case CARTRIDGE_MULTIMAX: + return multimax_roml_read(addr); case CARTRIDGE_PAGEFOX: return pagefox_roml_read(addr); + case CARTRIDGE_PARTNER64: + return partner64_roml_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_roml_read(addr); -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + return uc1_roml_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_roml_read(addr); + case CARTRIDGE_REX_RAMFLOPPY: + return rexramfloppy_roml_read(addr); +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_roml_read(addr); #endif @@ -611,11 +692,14 @@ BYTE roml_read_slotmain(WORD addr) return se5_roml_read(addr); case CARTRIDGE_ZAXXON: return zaxxon_roml_read(addr); + case CARTRIDGE_ZIPPCODE48: + return zippcode48_roml_read(addr); case CARTRIDGE_CAPTURE: case CARTRIDGE_EXOS: case CARTRIDGE_FORMEL64: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_MAGIC_FORMEL: /* ? */ + case CARTRIDGE_PROFIDOS: /* fake ultimax hack */ return mem_read_without_ultimax(addr); case CARTRIDGE_ACTION_REPLAY4: @@ -626,6 +710,16 @@ BYTE roml_read_slotmain(WORD addr) case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; + case CARTRIDGE_NONE: + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + return mem_read_without_ultimax(addr); + } + break; } /* open bus */ @@ -634,7 +728,7 @@ BYTE roml_read_slotmain(WORD addr) } /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -static BYTE roml_read_slot1(WORD addr) +static uint8_t roml_read_slot1(uint16_t addr) { /* "Slot 1" */ if (isepic_cart_active()) { @@ -655,10 +749,10 @@ static BYTE roml_read_slot1(WORD addr) } /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -BYTE roml_read(WORD addr) +uint8_t roml_read(uint16_t addr) { int res = CART_READ_THROUGH; - BYTE value; + uint8_t value; /* DBG(("CARTMEM roml_read (addr %04x)\n", addr)); */ /* "Slot 0" */ @@ -675,6 +769,13 @@ BYTE roml_read(WORD addr) if ((res = tpi_roml_read(addr, &value)) == CART_READ_VALID) { return value; } + } else if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + return mem_read_without_ultimax(addr); + } else if (ramlink_cart_enabled()) { + if ((res = ramlink_roml_read(addr, &value)) == CART_READ_VALID) { + return value; + } } switch (res) { @@ -689,7 +790,7 @@ BYTE roml_read(WORD addr) } /* ROML store - mapped to 8000 in ultimax mode */ -void roml_store(WORD addr, BYTE value) +void roml_store(uint16_t addr, uint8_t value) { /* DBG(("ultimax w 8000: %04x %02x\n", addr, value)); */ @@ -698,7 +799,8 @@ void roml_store(WORD addr, BYTE value) mmc64_roml_store(addr, value); return; } - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { /* fake ultimax hack */ mem_store_without_ultimax(addr, value); return; @@ -728,6 +830,12 @@ void roml_store(WORD addr, BYTE value) case CARTRIDGE_EASYFLASH: easyflash_roml_store(addr, value); return; + case CARTRIDGE_LT_KERNAL: + ltkernal_roml_store(addr, value); + return; + case CARTRIDGE_MEGABYTER: + megabyter_roml_store(addr, value); + return; case CARTRIDGE_MMC_REPLAY: mmcreplay_roml_store(addr, value); return; @@ -740,7 +848,14 @@ void roml_store(WORD addr, BYTE value) case CARTRIDGE_RETRO_REPLAY: retroreplay_roml_store(addr, value); return; -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + uc1_roml_store(addr, value); + return; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_store(addr, value); + return; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_roml_store(addr, value); return; @@ -749,13 +864,29 @@ void roml_store(WORD addr, BYTE value) case CARTRIDGE_EXOS: case CARTRIDGE_FORMEL64: case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_GMOD3: case CARTRIDGE_STARDOS: case CARTRIDGE_MAGIC_FORMEL: /* ? */ + case CARTRIDGE_PROFIDOS: /* fake ultimax hack */ mem_store_without_ultimax(addr, value); return; default: /* use default cartridge */ - generic_roml_store(addr, value); + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + if ( ( (ramlink_cart_mode() & 0x18) == 0x08 ) || + ( (ramlink_cart_mode() & 0x13) == 0x13 ) ) { + /* call slot1 code if cart is in ROMLO mode */ + generic_roml_store(addr, value); + } else { + /* otherwise store to whereever ie. ROM/RAM */ + mem_store_without_ultimax(addr, value); + } + } return; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); @@ -771,7 +902,7 @@ void roml_store(WORD addr, BYTE value) most carts that use romh_read also need to use ultimax_romh_read_hirom below. carts that map an "external kernal" wrap to ram_read here. */ -BYTE romh_read_slotmain(WORD addr) +uint8_t romh_read_slotmain(uint16_t addr) { /* "Main Slot" */ switch (mem_cartridge_type) { @@ -795,33 +926,60 @@ BYTE romh_read_slotmain(WORD addr) return ide64_rom_read(addr); case CARTRIDGE_KINGSOFT: return kingsoft_romh_read(addr); + case CARTRIDGE_LT_KERNAL: + return ltkernal_romh_read(addr); case CARTRIDGE_MAGIC_FORMEL: return magicformel_romh_read(addr); + case CARTRIDGE_MAX_BASIC: + return maxbasic_romh_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_romh_read(addr); + case CARTRIDGE_MULTIMAX: + return multimax_romh_read(addr); case CARTRIDGE_OCEAN: return ocean_romh_read(addr); case CARTRIDGE_PAGEFOX: return pagefox_romh_read(addr); + case CARTRIDGE_PARTNER64: + return partner64_romh_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_romh_read(addr); + case CARTRIDGE_UC1: + return uc1_romh_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_romh_read(addr); case CARTRIDGE_SNAPSHOT64: return snapshot64_romh_read(addr); case CARTRIDGE_EXOS: - case CARTRIDGE_STARDOS: case CARTRIDGE_GMOD2: + case CARTRIDGE_STARDOS: + case CARTRIDGE_PROFIDOS: /* fake ultimax hack, read from ram */ return ram_read(addr); + case CARTRIDGE_GMOD3: + return gmod3_romh_read(addr); /* return mem_read_without_ultimax(addr); */ case CARTRIDGE_ACTION_REPLAY4: case CARTRIDGE_FINAL_III: case CARTRIDGE_FREEZE_FRAME: + case CARTRIDGE_FREEZE_FRAME_MK2: case CARTRIDGE_FREEZE_MACHINE: default: /* use default cartridge */ return generic_romh_read(addr); case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; + case CARTRIDGE_NONE: + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + return mem_read_without_ultimax(addr); + } + break; } /* open bus */ @@ -829,7 +987,7 @@ BYTE romh_read_slotmain(WORD addr) return vicii_read_phi1(); } -static BYTE romh_read_slot1(WORD addr) +static uint8_t romh_read_slot1(uint16_t addr) { /* "Slot 1" */ if (expert_cart_enabled()) { @@ -846,10 +1004,10 @@ static BYTE romh_read_slot1(WORD addr) return romh_read_slotmain(addr); } -BYTE romh_read(WORD addr) +uint8_t romh_read(uint16_t addr) { int res = CART_READ_THROUGH; - BYTE value; + uint8_t value; /* DBG(("ultimax r e000: %04x\n", addr)); */ /* "Slot 0" */ @@ -858,6 +1016,16 @@ BYTE romh_read(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } + if (ramlink_cart_enabled()) { + if ((res = ramlink_romh_read(addr, &value)) == CART_READ_VALID) { + return value; + } + } + switch (res) { case CART_READ_C64MEM: return mem_read_without_ultimax(addr); @@ -874,7 +1042,7 @@ BYTE romh_read(WORD addr) that map an "external kernal" _only_ use this one, and wrap to ram_read in romh_read. */ -BYTE ultimax_romh_read_hirom_slotmain(WORD addr) +static uint8_t ultimax_romh_read_hirom_slotmain(uint16_t addr) { /* "Main Slot" */ switch (mem_cartridge_type) { @@ -900,14 +1068,29 @@ BYTE ultimax_romh_read_hirom_slotmain(WORD addr) return ide64_rom_read(addr); case CARTRIDGE_KINGSOFT: return kingsoft_romh_read(addr); + case CARTRIDGE_LT_KERNAL: + return ltkernal_romh_read(addr); case CARTRIDGE_MAGIC_FORMEL: return magicformel_romh_read_hirom(addr); + case CARTRIDGE_MAX_BASIC: + return maxbasic_romh_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_romh_read(addr); + case CARTRIDGE_MULTIMAX: + return multimax_romh_read(addr); case CARTRIDGE_OCEAN: return ocean_romh_read(addr); + case CARTRIDGE_PARTNER64: + return partner64_romh_read(addr); + case CARTRIDGE_PROFIDOS: + return profidos_romh_read_hirom(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_romh_read(addr); + case CARTRIDGE_UC1: + return uc1_romh_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_romh_read(addr); case CARTRIDGE_SNAPSHOT64: return snapshot64_romh_read(addr); case CARTRIDGE_STARDOS: @@ -915,15 +1098,28 @@ BYTE ultimax_romh_read_hirom_slotmain(WORD addr) case CARTRIDGE_GMOD2: /* ultimax only enabled on writes */ return mem_read_without_ultimax(addr); + case CARTRIDGE_GMOD3: + return gmod3_romh_read(addr); case CARTRIDGE_ACTION_REPLAY4: case CARTRIDGE_FINAL_III: case CARTRIDGE_FREEZE_FRAME: + case CARTRIDGE_FREEZE_FRAME_MK2: case CARTRIDGE_FREEZE_MACHINE: default: /* use default cartridge */ return generic_romh_read(addr); case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; + case CARTRIDGE_NONE: + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + return mem_read_without_ultimax(addr); + } + break; } /* open bus */ @@ -931,7 +1127,7 @@ BYTE ultimax_romh_read_hirom_slotmain(WORD addr) return vicii_read_phi1(); } -static BYTE ultimax_romh_read_hirom_slot1(WORD addr) +static uint8_t ultimax_romh_read_hirom_slot1(uint16_t addr) { /* "Slot 1" */ if (dqbb_cart_enabled()) { @@ -948,10 +1144,10 @@ static BYTE ultimax_romh_read_hirom_slot1(WORD addr) return ultimax_romh_read_hirom_slotmain(addr); } -BYTE ultimax_romh_read_hirom(WORD addr) +uint8_t ultimax_romh_read_hirom(uint16_t addr) { int res; - BYTE value; + uint8_t value; /* DBG(("ultimax r e000: %04x\n", addr)); */ /* "Slot 0" */ @@ -961,6 +1157,15 @@ BYTE ultimax_romh_read_hirom(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + return ieeeflash64_romh_read_hirom(addr); + } + if (ramlink_cart_enabled()) { + if ((res = ramlink_romh_read(addr, &value)) == CART_READ_VALID) { + return value; + } + } + switch (res) { case CART_READ_C64MEM: return mem_read_without_ultimax(addr); @@ -974,12 +1179,13 @@ BYTE ultimax_romh_read_hirom(WORD addr) /* ROMH store - mapped to E000 in ultimax mode - carts that use "external kernal" mode must wrap to ram_store here */ -void romh_store(WORD addr, BYTE value) +void romh_store(uint16_t addr, uint8_t value) { /* DBG(("ultimax w e000: %04x %02x\n", addr, value)); */ /* "Slot 0" */ - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { /* fake ultimax hack, c64 ram */ mem_store_without_ultimax(addr, value); } @@ -991,6 +1197,7 @@ void romh_store(WORD addr, BYTE value) /* "Main Slot" */ /* to aid in debugging, use return instead of break incase of a successful store */ switch (mem_cartridge_type) { + /* DO NOT ADD A DEFAULT CASE OR IT WILL BREAK RAMLINK */ case CARTRIDGE_CAPTURE: capture_romh_store(addr, value); return; @@ -1000,14 +1207,20 @@ void romh_store(WORD addr, BYTE value) case CARTRIDGE_GMOD2: gmod2_romh_store(addr, value); return; + case CARTRIDGE_LT_KERNAL: + ltkernal_romh_store(addr, value); + return; case CARTRIDGE_MMC_REPLAY: mmcreplay_romh_store(addr, value); return; case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: + case CARTRIDGE_GMOD3: + case CARTRIDGE_IEEEFLASH64: + case CARTRIDGE_MAGIC_FORMEL: /* ? */ + case CARTRIDGE_PROFIDOS: case CARTRIDGE_STARDOS: case CARTRIDGE_SNAPSHOT64: /* ? */ - case CARTRIDGE_MAGIC_FORMEL: /* ? */ /* fake ultimax hack, c64 ram */ /* mem_store_without_ultimax(addr, value); */ ram_store(addr, value); @@ -1017,6 +1230,12 @@ void romh_store(WORD addr, BYTE value) return; } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + mem_store_without_ultimax(addr, value); + return; + } + /* open bus */ /* DBG(("CARTMEM: possible BUG! ROMH open bus store (@$%04x, addr %04x)\n", reg_pc, addr)); */ } @@ -1027,7 +1246,7 @@ void romh_store(WORD addr, BYTE value) a write select. some carts however map RAM here and also accept writes in this mode. */ -void romh_no_ultimax_store(WORD addr, BYTE value) +void romh_no_ultimax_store(uint16_t addr, uint8_t value) { /* DBG(("game w a000: %04x %02x\n", addr, value)); */ @@ -1042,15 +1261,24 @@ void romh_no_ultimax_store(WORD addr, BYTE value) switch (mem_cartridge_type) { case CARTRIDGE_ATOMIC_POWER: atomicpower_romh_store(addr, value); + return; /* writes to cartridge RAM should not fall through to C64 RAM in mode 0x22 */ + break; + case CARTRIDGE_IDE64: + ide64_rom_store(addr, value); break; case CARTRIDGE_PAGEFOX: pagefox_romh_store(addr, value); break; case CARTRIDGE_RETRO_REPLAY: retroreplay_romh_store(addr, value); + return; /* writes to cartridge RAM should not fall through to C64 RAM in mode 0x22 */ break; - case CARTRIDGE_IDE64: - ide64_rom_store(addr, value); + case CARTRIDGE_UC1: + uc1_romh_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_romh_store(addr, value); break; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); @@ -1066,7 +1294,7 @@ void romh_no_ultimax_store(WORD addr, BYTE value) a write select. some carts however map ram here and also accept writes in this mode. */ -void roml_no_ultimax_store(WORD addr, BYTE value) +void roml_no_ultimax_store(uint16_t addr, uint8_t value) { /* DBG(("game rom w 8000: %04x %02x\n", addr, value)); */ /* "Slot 0" */ @@ -1094,6 +1322,9 @@ void roml_no_ultimax_store(WORD addr, BYTE value) case CARTRIDGE_ATOMIC_POWER: atomicpower_roml_store(addr, value); break; + case CARTRIDGE_IDE64: + ide64_rom_store(addr, value); + break; case CARTRIDGE_PAGEFOX: pagefox_roml_store(addr, value); break; @@ -1102,16 +1333,24 @@ void roml_no_ultimax_store(WORD addr, BYTE value) return; /* FIXME: this is weird */ } break; -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + uc1_roml_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_store(addr, value); + break; + case CARTRIDGE_REX_RAMFLOPPY: + rexramfloppy_roml_store(addr, value); + return; /* writes to cartridge RAM should not fall through to C64 RAM */ + break; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: if (rrnetmk3_roml_store(addr, value)) { return; /* FAKE ultimax, if EEPROM was being written to, dont write to RAM */ } break; #endif - case CARTRIDGE_IDE64: - ide64_rom_store(addr, value); - break; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; @@ -1130,7 +1369,7 @@ void roml_no_ultimax_store(WORD addr, BYTE value) must NOT be called by any functions called here, as this will cause an endless loop */ -void raml_no_ultimax_store(WORD addr, BYTE value) +void raml_no_ultimax_store(uint16_t addr, uint8_t value) { /* DBG(("game ram w 8000: %04x %02x\n", addr, value)); */ /* "Slot 0" */ @@ -1162,6 +1401,13 @@ void raml_no_ultimax_store(WORD addr, BYTE value) return; /* FIXME: this is weird */ } break; + case CARTRIDGE_UC1: + uc1_roml_no_ultimax_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_no_ultimax_store(addr, value); + break; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; @@ -1180,7 +1426,7 @@ void raml_no_ultimax_store(WORD addr, BYTE value) must NOT be called by any functions called here, as this will cause an endless loop */ -void ramh_no_ultimax_store(WORD addr, BYTE value) +void ramh_no_ultimax_store(uint16_t addr, uint8_t value) { /* DBG(("game ram w 8000: %04x %02x\n", addr, value)); */ @@ -1203,8 +1449,43 @@ void ramh_no_ultimax_store(WORD addr, BYTE value) /* mem_store_without_romlh(addr, value); */ } +/* ultimax read - 0800 to 0fff (MAX-Machine only) */ +uint8_t ultimax_0800_0fff_read(uint16_t addr) +{ + /* "Main Slot" */ + switch (mem_cartridge_type) { + case CARTRIDGE_MAX_BASIC: + return maxbasic_0800_0fff_read(addr); + case CARTRIDGE_MULTIMAX: + return multimax_0800_0fff_read(addr); + case CARTRIDGE_CRT: /* invalid */ + DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); + break; + } + /* default; no cart, open bus */ + return vicii_read_phi1(); +} + +/* ultimax store - 0800 to 0fff (MAX-Machine only) */ +void ultimax_0800_0fff_store(uint16_t addr, uint8_t value) +{ + /* "Main Slot" */ + switch (mem_cartridge_type) { + case CARTRIDGE_MAX_BASIC: + maxbasic_0800_0fff_store(addr, value); + break; + case CARTRIDGE_MULTIMAX: + multimax_0800_0fff_store(addr, value); + break; + case CARTRIDGE_CRT: /* invalid */ + DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); + break; + } + /* default; no cart, open bus */ +} + /* ultimax read - 1000 to 7fff */ -BYTE ultimax_1000_7fff_read_slot1(WORD addr) +static uint8_t ultimax_1000_7fff_read_slot1(uint16_t addr) { /* "Slot 1" */ if (expert_cart_enabled()) { @@ -1223,13 +1504,23 @@ BYTE ultimax_1000_7fff_read_slot1(WORD addr) return ide64_ram_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_1000_7fff_read(addr); + case CARTRIDGE_UC1: + return uc1_1000_7fff_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_1000_7fff_read(addr); + case CARTRIDGE_PARTNER64: + case CARTRIDGE_EXOS: + case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: - case CARTRIDGE_MAGIC_FORMEL: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_GMOD2: + case CARTRIDGE_GMOD3: + case CARTRIDGE_IEEEFLASH64: case CARTRIDGE_KINGSOFT: - case CARTRIDGE_FINAL_PLUS: - case CARTRIDGE_EXOS: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 ram */ return mem_read_without_ultimax(addr); @@ -1242,10 +1533,10 @@ BYTE ultimax_1000_7fff_read_slot1(WORD addr) return vicii_read_phi1(); } -BYTE ultimax_1000_7fff_read(WORD addr) +uint8_t ultimax_1000_7fff_read(uint16_t addr) { int res; - BYTE value; + uint8_t value; /* "Slot 0" */ res = CART_READ_THROUGH; @@ -1255,6 +1546,14 @@ BYTE ultimax_1000_7fff_read(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } switch (res) { case CART_READ_C64MEM: @@ -1270,10 +1569,13 @@ BYTE ultimax_1000_7fff_read(WORD addr) } /* ultimax store - 1000 to 7fff */ -void ultimax_1000_7fff_store(WORD addr, BYTE value) +void ultimax_1000_7fff_store(uint16_t addr, uint8_t value) { + DBG(("ultimax_1000_7fff_store()\n")); + /* "Slot 0" */ - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { mem_store_without_ultimax(addr, value); /* fake ultimax hack, c64 ram */ } /* "Slot 1" */ @@ -1286,6 +1588,7 @@ void ultimax_1000_7fff_store(WORD addr, BYTE value) /* "Main Slot" */ switch (mem_cartridge_type) { + /* DO NOT ADD A DEFAULT CASE OR IT WILL BREAK RAMLINK */ case CARTRIDGE_IDE64: ide64_ram_store(addr, value); break; @@ -1295,14 +1598,25 @@ void ultimax_1000_7fff_store(WORD addr, BYTE value) case CARTRIDGE_CAPTURE: capture_1000_7fff_store(addr, value); break; + case CARTRIDGE_UC1: + uc1_1000_7fff_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_1000_7fff_store(addr, value); + break; + case CARTRIDGE_EXOS: + case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: - case CARTRIDGE_MAGIC_FORMEL: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_GMOD2: - case CARTRIDGE_FINAL_PLUS: - case CARTRIDGE_EXOS: - case CARTRIDGE_STARDOS: + case CARTRIDGE_GMOD3: case CARTRIDGE_KINGSOFT: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PARTNER64: + case CARTRIDGE_PROFIDOS: + case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 ram */ mem_store_without_ultimax(addr, value); break; @@ -1311,11 +1625,17 @@ void ultimax_1000_7fff_store(WORD addr, BYTE value) break; } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + mem_store_without_ultimax(addr, value); + return; + } + /* default; no cart, open bus */ } /* ultimax read - a000 to bfff */ -BYTE ultimax_a000_bfff_read_slot1(WORD addr) +static uint8_t ultimax_a000_bfff_read_slot1(uint16_t addr) { /* "Slot 1" */ if (expert_cart_enabled()) { @@ -1334,29 +1654,55 @@ BYTE ultimax_a000_bfff_read_slot1(WORD addr) return ide64_rom_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_a000_bfff_read(addr); + case CARTRIDGE_PARTNER64: + return partner64_a000_bfff_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_a000_bfff_read(addr); - case CARTRIDGE_FORMEL64: - case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_UC1: + return uc1_a000_bfff_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_a000_bfff_read(addr); case CARTRIDGE_CAPTURE: + case CARTRIDGE_EXOS: + case CARTRIDGE_FORMEL64: case CARTRIDGE_GAME_KILLER: case CARTRIDGE_GMOD2: - case CARTRIDGE_EXOS: + case CARTRIDGE_GMOD3: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 basic, ram */ return mem_read_without_ultimax(addr); case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; + default: + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + if ( (ramlink_cart_mode() & 0x1a) == 0x1a ) { + /* call slot1 code if cart is in ROMHI mode */ + return romh_read_slot1(addr); + } else { + /* otherwise return whatever should be there; ie. ROM/RAM */ + return mem_read_without_ultimax(addr); + } + } + break; } /* default; no cart, open bus */ return vicii_read_phi1(); } -BYTE ultimax_a000_bfff_read(WORD addr) +uint8_t ultimax_a000_bfff_read(uint16_t addr) { int res; - BYTE value; + uint8_t value; /* "Slot 0" */ res = CART_READ_THROUGH; @@ -1365,6 +1711,15 @@ BYTE ultimax_a000_bfff_read(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } + if (ramlink_cart_enabled()) { + if ((res = ramlink_a000_bfff_read(addr, &value)) == CART_READ_VALID) { + return value; + } + } switch (res) { case CART_READ_C64MEM: /* fake ultimax hack, c64 basic, ram */ @@ -1378,10 +1733,11 @@ BYTE ultimax_a000_bfff_read(WORD addr) } /* ultimax store - a000 to bfff */ -void ultimax_a000_bfff_store(WORD addr, BYTE value) +void ultimax_a000_bfff_store(uint16_t addr, uint8_t value) { /* "Slot 0" */ - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { /* fake ultimax hack, c64 ram */ mem_store_without_ultimax(addr, value); } @@ -1395,18 +1751,34 @@ void ultimax_a000_bfff_store(WORD addr, BYTE value) /* "Main Slot" */ switch (mem_cartridge_type) { + /* DO NOT ADD A DEFAULT CASE OR IT WILL BREAK RAMLINK */ case CARTRIDGE_MMC_REPLAY: mmcreplay_a000_bfff_store(addr, value); break; + case CARTRIDGE_PARTNER64: + partner64_a000_bfff_store(addr, value); + break; case CARTRIDGE_RETRO_REPLAY: retroreplay_a000_bfff_store(addr, value); break; + case CARTRIDGE_UC1: + /* fake ultimax hack, c64 ram */ + uc1_a000_bfff_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + /* fake ultimax hack, c64 ram */ + uc2_a000_bfff_store(addr, value); + break; case CARTRIDGE_CAPTURE: - case CARTRIDGE_MAGIC_FORMEL: - case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: - case CARTRIDGE_EXOS: + case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_GMOD3: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 ram */ mem_store_without_ultimax(addr, value); @@ -1416,11 +1788,17 @@ void ultimax_a000_bfff_store(WORD addr, BYTE value) break; } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + mem_store_without_ultimax(addr, value); + return; + } + /* default; no cart, open bus */ } /* ultimax read - c000 to cfff */ -BYTE ultimax_c000_cfff_read_slot1(WORD addr) +static uint8_t ultimax_c000_cfff_read_slot1(uint16_t addr) { /* "Slot 1" */ if (expert_cart_enabled()) { @@ -1435,15 +1813,20 @@ BYTE ultimax_c000_cfff_read_slot1(WORD addr) switch (mem_cartridge_type) { case CARTRIDGE_MMC_REPLAY: return mmcreplay_c000_cfff_read(addr); - case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PARTNER64: case CARTRIDGE_CAPTURE: - case CARTRIDGE_GAME_KILLER: - case CARTRIDGE_GMOD2: + case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: - case CARTRIDGE_EXOS: - case CARTRIDGE_STARDOS: + case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_GMOD2: + case CARTRIDGE_GMOD3: + case CARTRIDGE_IEEEFLASH64: case CARTRIDGE_KINGSOFT: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: + case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 ram */ return mem_read_without_ultimax(addr); case CARTRIDGE_CRT: /* invalid */ @@ -1454,10 +1837,10 @@ BYTE ultimax_c000_cfff_read_slot1(WORD addr) return vicii_read_phi1(); } -BYTE ultimax_c000_cfff_read(WORD addr) +uint8_t ultimax_c000_cfff_read(uint16_t addr) { int res; - BYTE value; + uint8_t value; /* "Slot 0" */ res = CART_READ_THROUGH; @@ -1467,6 +1850,14 @@ BYTE ultimax_c000_cfff_read(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } switch (res) { case CART_READ_C64MEM: @@ -1482,10 +1873,11 @@ BYTE ultimax_c000_cfff_read(WORD addr) } /* ultimax store - c000 to cfff */ -void ultimax_c000_cfff_store(WORD addr, BYTE value) +void ultimax_c000_cfff_store(uint16_t addr, uint8_t value) { /* "Slot 0" */ - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { mem_store_without_ultimax(addr, value); /* fake ultimax hack, c64 ram */ } /* "Slot 1" */ @@ -1498,17 +1890,22 @@ void ultimax_c000_cfff_store(WORD addr, BYTE value) /* "Main Slot" */ switch (mem_cartridge_type) { + /* DO NOT ADD A DEFAULT CASE OR IT WILL BREAK RAMLINK */ case CARTRIDGE_MMC_REPLAY: mmcreplay_c000_cfff_store(addr, value); break; - case CARTRIDGE_MAGIC_FORMEL: case CARTRIDGE_CAPTURE: - case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: - case CARTRIDGE_EXOS: - case CARTRIDGE_STARDOS: + case CARTRIDGE_GAME_KILLER: + case CARTRIDGE_GMOD3: case CARTRIDGE_KINGSOFT: + case CARTRIDGE_LT_KERNAL: + case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PARTNER64: + case CARTRIDGE_PROFIDOS: + case CARTRIDGE_STARDOS: /* fake ultimax hack, c64 ram */ mem_store_without_ultimax(addr, value); break; @@ -1517,11 +1914,17 @@ void ultimax_c000_cfff_store(WORD addr, BYTE value) break; } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + mem_store_without_ultimax(addr, value); + return; + } + /* default; no cart, open bus */ } /* ultimax read - d000 to dfff */ -static BYTE ultimax_d000_dfff_read_slot1(WORD addr) +static uint8_t ultimax_d000_dfff_read_slot1(uint16_t addr) { /* "Slot 1" */ if (expert_cart_enabled()) { @@ -1535,10 +1938,13 @@ static BYTE ultimax_d000_dfff_read_slot1(WORD addr) case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: + case CARTRIDGE_GMOD3: + case CARTRIDGE_KINGSOFT: + case CARTRIDGE_LT_KERNAL: case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: case CARTRIDGE_SNAPSHOT64: /* ? */ case CARTRIDGE_STARDOS: - case CARTRIDGE_KINGSOFT: /* fake ultimax hack, c64 io,colram,ram */ return mem_read_without_ultimax(addr); case CARTRIDGE_CRT: /* invalid */ @@ -1549,10 +1955,10 @@ static BYTE ultimax_d000_dfff_read_slot1(WORD addr) return read_bank_io(addr); } -BYTE ultimax_d000_dfff_read(WORD addr) +uint8_t ultimax_d000_dfff_read(uint16_t addr) { int res = CART_READ_THROUGH; - BYTE value; + uint8_t value; /* "Slot 0" */ @@ -1561,6 +1967,14 @@ BYTE ultimax_d000_dfff_read(WORD addr) return value; } } + if (ieeeflash64_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + res = CART_READ_C64MEM; + } switch (res) { case CART_READ_C64MEM: @@ -1576,10 +1990,11 @@ BYTE ultimax_d000_dfff_read(WORD addr) } /* ultimax store - d000 to dfff */ -void ultimax_d000_dfff_store(WORD addr, BYTE value) +void ultimax_d000_dfff_store(uint16_t addr, uint8_t value) { /* "Slot 0" */ - if (magicvoice_cart_enabled()) { + if (magicvoice_cart_enabled() || + ieeeflash64_cart_enabled()) { /* fake ultimax hack, c64 io,colram,ram */ mem_store_without_ultimax(addr, value); return; @@ -1593,14 +2008,18 @@ void ultimax_d000_dfff_store(WORD addr, BYTE value) /* "Main Slot" */ switch (mem_cartridge_type) { + /* DO NOT ADD A DEFAULT CASE OR IT WILL BREAK RAMLINK */ case CARTRIDGE_CAPTURE: case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: + case CARTRIDGE_GMOD3: + case CARTRIDGE_KINGSOFT: + case CARTRIDGE_LT_KERNAL: case CARTRIDGE_MAGIC_FORMEL: + case CARTRIDGE_PROFIDOS: case CARTRIDGE_SNAPSHOT64: /* ? */ case CARTRIDGE_STARDOS: - case CARTRIDGE_KINGSOFT: /* fake ultimax hack, c64 io,colram,ram */ mem_store_without_ultimax(addr, value); return; @@ -1608,6 +2027,13 @@ void ultimax_d000_dfff_store(WORD addr, BYTE value) DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; } + + if (ramlink_cart_enabled()) { + /* fake ultimax hack */ + mem_store_without_ultimax(addr, value); + return; + } + /* default;no cart, c64 i/o */ store_bank_io(addr, value); } @@ -1622,7 +2048,7 @@ void ultimax_d000_dfff_store(WORD addr, BYTE value) FIXME: lots of testing needed! */ -static int ultimax_romh_phi1_read_slotmain(WORD addr, BYTE *value) +static int ultimax_romh_phi1_read_slotmain(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1642,17 +2068,30 @@ static int ultimax_romh_phi1_read_slotmain(WORD addr, BYTE *value) case CARTRIDGE_FINAL_PLUS: res = final_plus_romh_phi1_read(addr, value); break; + case CARTRIDGE_GMOD3: + res = gmod3_romh_phi1_read(addr, value); + break; case CARTRIDGE_MAGIC_FORMEL: res = magicformel_romh_phi1_read(addr, value); break; case CARTRIDGE_MMC_REPLAY: res = mmcreplay_romh_phi1_read(addr, value); break; + case CARTRIDGE_PROFIDOS: + res = profidos_romh_phi1_read(addr, value); + break; case CARTRIDGE_STARDOS: res = stardos_romh_phi1_read(addr, value); break; case CARTRIDGE_NONE: break; + case CARTRIDGE_UC1: + res = uc1_romh_phi1_read(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_romh_phi1_read(addr, value); + break; default: /* generic fallback */ *value = ultimax_romh_read_hirom(addr); @@ -1674,7 +2113,7 @@ static int ultimax_romh_phi1_read_slotmain(WORD addr, BYTE *value) return 1; } -static int ultimax_romh_phi1_read_slot1(WORD addr, BYTE *value) +static int ultimax_romh_phi1_read_slot1(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1702,7 +2141,7 @@ static int ultimax_romh_phi1_read_slot1(WORD addr, BYTE *value) return ultimax_romh_phi1_read_slotmain(addr, value); } -int ultimax_romh_phi1_read(WORD addr, BYTE *value) +int ultimax_romh_phi1_read(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1713,6 +2152,16 @@ int ultimax_romh_phi1_read(WORD addr, BYTE *value) return 1; } } + if (ieeeflash64_cart_enabled()) { + if ((res = ieeeflash64_romh_phi1_read(addr, value)) == CART_READ_VALID) { + return 1; + } + } + if (ramlink_cart_enabled()) { + if ((res = ramlink_romh_phi1_read(addr, value)) == CART_READ_VALID) { + return 1; + } + } switch (res) { case CART_READ_C64MEM: @@ -1725,7 +2174,7 @@ int ultimax_romh_phi1_read(WORD addr, BYTE *value) return ultimax_romh_phi1_read_slot1(addr, value); } -static int ultimax_romh_phi2_read_slotmain(WORD addr, BYTE *value) +static int ultimax_romh_phi2_read_slotmain(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1745,17 +2194,30 @@ static int ultimax_romh_phi2_read_slotmain(WORD addr, BYTE *value) case CARTRIDGE_FINAL_PLUS: res = final_plus_romh_phi2_read(addr, value); break; + case CARTRIDGE_GMOD3: + res = gmod3_romh_phi2_read(addr, value); + break; case CARTRIDGE_MAGIC_FORMEL: res = magicformel_romh_phi2_read(addr, value); break; case CARTRIDGE_MMC_REPLAY: res = mmcreplay_romh_phi2_read(addr, value); break; + case CARTRIDGE_PROFIDOS: + res = profidos_romh_phi2_read(addr, value); + break; case CARTRIDGE_STARDOS: res = stardos_romh_phi2_read(addr, value); break; case CARTRIDGE_NONE: break; + case CARTRIDGE_UC1: + res = uc1_romh_phi2_read(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_romh_phi2_read(addr, value); + break; default: /* generic fallback */ *value = ultimax_romh_read_hirom(addr); @@ -1777,7 +2239,7 @@ static int ultimax_romh_phi2_read_slotmain(WORD addr, BYTE *value) return 1; } -static int ultimax_romh_phi2_read_slot1(WORD addr, BYTE *value) +static int ultimax_romh_phi2_read_slot1(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1805,7 +2267,7 @@ static int ultimax_romh_phi2_read_slot1(WORD addr, BYTE *value) return ultimax_romh_phi2_read_slotmain(addr, value); } -int ultimax_romh_phi2_read(WORD addr, BYTE *value) +int ultimax_romh_phi2_read(uint16_t addr, uint8_t *value) { int res = CART_READ_THROUGH; @@ -1816,6 +2278,16 @@ int ultimax_romh_phi2_read(WORD addr, BYTE *value) return 1; } } + if (ieeeflash64_cart_enabled()) { + if ((res = ieeeflash64_romh_phi2_read(addr, value)) == CART_READ_VALID) { + return 1; + } + } + if (ramlink_cart_enabled()) { + if ((res = ramlink_romh_phi2_read(addr, value)) == CART_READ_VALID) { + return 1; + } + } switch (res) { case CART_READ_C64MEM: @@ -1839,10 +2311,10 @@ int ultimax_romh_phi2_read(WORD addr, BYTE *value) this hack). */ -static BYTE mem_phi1[0x1000]; -static BYTE mem_phi2[0x1000]; -static BYTE *mem_phi1_ptr[0x1000]; -static BYTE *mem_phi2_ptr[0x1000]; +static uint8_t mem_phi1[0x1000]; +static uint8_t mem_phi2[0x1000]; +static uint8_t *mem_phi1_ptr[0x1000]; +static uint8_t *mem_phi2_ptr[0x1000]; static int mem_phi1_valid = 0; static int mem_phi2_valid = 0; static int mem_phi1_last = 0; @@ -1864,13 +2336,13 @@ static void ultimax_memptr_update(void) } } -BYTE *ultimax_romh_phi1_ptr(WORD addr) +uint8_t *ultimax_romh_phi1_ptr(uint16_t addr) { int n; int res; /* DBG(("phi1 addr %04x\n", addr)); */ n = addr & 0x0fff; - res = ultimax_romh_phi1_read((WORD)(0x1000 + n), &mem_phi1[n]); + res = ultimax_romh_phi1_read((uint16_t)(0x1000 + n), &mem_phi1[n]); if (mem_phi1_ptr[n] != (res ? &mem_phi1[n] : NULL)) { mem_phi1_valid = 0; } @@ -1878,7 +2350,7 @@ BYTE *ultimax_romh_phi1_ptr(WORD addr) if (!mem_phi1_valid) { n = 0; while (n < 0x1000) { - if (ultimax_romh_phi1_read((WORD)(0x1000 + n), &mem_phi1[n]) == 0) { + if (ultimax_romh_phi1_read((uint16_t)(0x1000 + n), &mem_phi1[n]) == 0) { mem_phi1_ptr[n] = NULL; } else { mem_phi1_ptr[n] = &mem_phi1[n]; @@ -1891,13 +2363,13 @@ BYTE *ultimax_romh_phi1_ptr(WORD addr) return mem_phi1_ptr[addr & 0x0fff]; } -BYTE *ultimax_romh_phi2_ptr(WORD addr) +uint8_t *ultimax_romh_phi2_ptr(uint16_t addr) { int n; int res; /* DBG(("phi2 addr %04x\n", addr)); */ n = addr & 0x0fff; - res = ultimax_romh_phi2_read((WORD)(0x1000 + n), &mem_phi2[n]); + res = ultimax_romh_phi2_read((uint16_t)(0x1000 + n), &mem_phi2[n]); if (mem_phi2_ptr[n] != (res ? &mem_phi2[n] : NULL)) { mem_phi2_valid = 0; } @@ -1905,7 +2377,7 @@ BYTE *ultimax_romh_phi2_ptr(WORD addr) if (!mem_phi2_valid) { n = 0; while (n < 0x1000) { - if (ultimax_romh_phi2_read((WORD)(0x1000 + n), &mem_phi2[n]) == 0) { + if (ultimax_romh_phi2_read((uint16_t)(0x1000 + n), &mem_phi2[n]) == 0) { mem_phi2_ptr[n] = NULL; } else { mem_phi2_ptr[n] = &mem_phi2[n]; @@ -1927,9 +2399,9 @@ BYTE *ultimax_romh_phi2_ptr(WORD addr) - "fake ultimax" mapping is used - memory can not be read without side effects */ -BYTE cartridge_peek_mem_slotmain(WORD addr) +uint8_t cartridge_peek_mem_slotmain(uint16_t addr) { - BYTE value; + uint8_t value; int res = CART_READ_THROUGH; /* "Main Slot" */ @@ -1957,13 +2429,29 @@ BYTE cartridge_peek_mem_slotmain(WORD addr) case CARTRIDGE_GMOD2: res = gmod2_peek_mem(&export_slotmain, addr, &value); break; + case CARTRIDGE_GMOD3: + res = gmod3_peek_mem(&export_slotmain, addr, &value); + break; + case CARTRIDGE_LT_KERNAL: + res = ltkernal_peek_mem(&export_slotmain, addr, &value); + break; case CARTRIDGE_MAGIC_FORMEL: res = magicformel_peek_mem(&export_slotmain, addr, &value); break; + case CARTRIDGE_PROFIDOS: + res = profidos_peek_mem(&export_slotmain, addr, &value); + break; case CARTRIDGE_RETRO_REPLAY: res = retroreplay_peek_mem(&export_slotmain, addr, &value); break; -#ifdef HAVE_PCAP + case CARTRIDGE_UC1: + res = uc1_peek_mem(&export_slotmain, addr, &value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_peek_mem(&export_slotmain, addr, &value); + break; +#ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: res = rrnetmk3_peek_mem(&export_slotmain, addr, &value); break; @@ -1984,7 +2472,7 @@ BYTE cartridge_peek_mem_slotmain(WORD addr) if (addr >= 0xe000) { return ultimax_romh_read_hirom_slotmain(addr); } - } else if (!export_slotmain.exrom && !export_slotmain.game) { + } else if (export_slotmain.exrom && export_slotmain.game) { /* 16k Game */ if (addr >= 0x8000 && addr <= 0x9fff) { return roml_read_slotmain(addr); @@ -2000,9 +2488,18 @@ BYTE cartridge_peek_mem_slotmain(WORD addr) } break; case CARTRIDGE_NONE: + /* RAMLINK operates as ULTIMAX when the address is > $e000, but + a normal cart when $8000 - $bfff. Since VICE doesn't allow + the cart config to change on different addresses, we have + to hack it here. + So when RAMLINK is enabled, pass whatever is "default". */ + if (ramlink_cart_enabled()) { + return mem_read_without_ultimax(addr); + } break; } +/* FIXME: if the kernal ROM is exposed here, it doesn't return it, just ram */ switch (res) { case CART_READ_VALID: return value; @@ -2018,9 +2515,9 @@ BYTE cartridge_peek_mem_slotmain(WORD addr) return ram_read(addr); } -static BYTE cartridge_peek_mem_slot1(WORD addr) +static uint8_t cartridge_peek_mem_slot1(uint16_t addr) { - BYTE value; + uint8_t value; int res = CART_READ_THROUGH; /* "Slot 1" */ @@ -2054,9 +2551,9 @@ static BYTE cartridge_peek_mem_slot1(WORD addr) return cartridge_peek_mem_slotmain(addr); } -BYTE cartridge_peek_mem(WORD addr) +uint8_t cartridge_peek_mem(uint16_t addr) { - BYTE value; + uint8_t value; int res = CART_READ_THROUGH; /* DBG(("CARTMEM cartridge_peek_mem (type %d addr %04x)\n", mem_cartridge_type, addr)); */ @@ -2075,6 +2572,14 @@ BYTE cartridge_peek_mem(WORD addr) if ((res = tpi_peek_mem(addr, &value)) == CART_READ_VALID) { return value; } + } else if (ieeeflash64_cart_enabled()) { + if ((res = ieeeflash64_peek_mem(addr, &value)) == CART_READ_VALID) { + return value; + } + } else if (ramlink_cart_enabled()) { + if ((res = ramlink_peek_mem(addr, &value)) == CART_READ_VALID) { + return value; + } } switch (res) { diff --git a/src/Emulators/vice/c64/cart/c64cartmem.h b/src/Emulators/vice/c64/cart/c64cartmem.h index 9d627efd..d525d865 100644 --- a/src/Emulators/vice/c64/cart/c64cartmem.h +++ b/src/Emulators/vice/c64/cart/c64cartmem.h @@ -34,29 +34,31 @@ */ /* expansion port memory read/write hooks */ -extern BYTE roml_read(WORD addr); -extern void roml_store(WORD addr, BYTE value); -extern BYTE romh_read(WORD addr); -extern BYTE ultimax_romh_read_hirom(WORD addr); -extern void romh_store(WORD addr, BYTE value); -extern void roml_no_ultimax_store(WORD addr, BYTE value); -extern void raml_no_ultimax_store(WORD addr, BYTE value); -extern void romh_no_ultimax_store(WORD addr, BYTE value); -extern void ramh_no_ultimax_store(WORD addr, BYTE value); +uint8_t roml_read(uint16_t addr); +void roml_store(uint16_t addr, uint8_t value); +uint8_t romh_read(uint16_t addr); +uint8_t ultimax_romh_read_hirom(uint16_t addr); +void romh_store(uint16_t addr, uint8_t value); +void roml_no_ultimax_store(uint16_t addr, uint8_t value); +void raml_no_ultimax_store(uint16_t addr, uint8_t value); +void romh_no_ultimax_store(uint16_t addr, uint8_t value); +void ramh_no_ultimax_store(uint16_t addr, uint8_t value); -extern BYTE ultimax_1000_7fff_read(WORD addr); -extern void ultimax_1000_7fff_store(WORD addr, BYTE value); -extern BYTE ultimax_a000_bfff_read(WORD addr); -extern void ultimax_a000_bfff_store(WORD addr, BYTE value); -extern BYTE ultimax_c000_cfff_read(WORD addr); -extern void ultimax_c000_cfff_store(WORD addr, BYTE value); -extern BYTE ultimax_d000_dfff_read(WORD addr); -extern void ultimax_d000_dfff_store(WORD addr, BYTE value); +uint8_t ultimax_0800_0fff_read(uint16_t addr); +void ultimax_0800_0fff_store(uint16_t addr, uint8_t value); +uint8_t ultimax_1000_7fff_read(uint16_t addr); +void ultimax_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t ultimax_a000_bfff_read(uint16_t addr); +void ultimax_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t ultimax_c000_cfff_read(uint16_t addr); +void ultimax_c000_cfff_store(uint16_t addr, uint8_t value); +uint8_t ultimax_d000_dfff_read(uint16_t addr); +void ultimax_d000_dfff_store(uint16_t addr, uint8_t value); /* VIC-II reads. the _ptr functions are for the old vic implementation (x64) */ -extern BYTE *ultimax_romh_phi1_ptr(WORD addr); -extern BYTE *ultimax_romh_phi2_ptr(WORD addr); -extern int ultimax_romh_phi1_read(WORD addr, BYTE *value); -extern int ultimax_romh_phi2_read(WORD addr, BYTE *value); +uint8_t *ultimax_romh_phi1_ptr(uint16_t addr); +uint8_t *ultimax_romh_phi2_ptr(uint16_t addr); +int ultimax_romh_phi1_read(uint16_t addr, uint8_t *value); +int ultimax_romh_phi2_read(uint16_t addr, uint8_t *value); #endif diff --git a/src/Emulators/vice/c64/cart/c64cartsystem.h b/src/Emulators/vice/c64/cart/c64cartsystem.h index 04f26635..80b884e5 100644 --- a/src/Emulators/vice/c64/cart/c64cartsystem.h +++ b/src/Emulators/vice/c64/cart/c64cartsystem.h @@ -45,56 +45,57 @@ #include "vicetypes.h" /* from c64cart.c */ -extern int cart_attach_cmdline(const char *param, void *extra_param); +int cart_attach_cmdline(const char *param, void *extra_param); -extern void cart_trigger_nmi(void); +void cart_trigger_nmi(void); -extern void cart_unset_alarms(void); -extern void cart_power_off(void); +void cart_unset_alarms(void); +void cart_power_off(void); -extern void cart_attach_from_snapshot(int type); +void cart_attach_from_snapshot(int type); -extern void cart_detach_slotmain(void); -extern int cart_getid_slotmain(void); /* returns ID of cart in "Main Slot" */ -extern int cart_getid_slot0(void); -extern int cart_getid_slot1(void); +void cart_detach_slotmain(void); +int cart_getid_slotmain(void); /* returns ID of cart in "Main Slot" */ +int cart_getid_slot0(void); +int cart_getid_slot1(void); /* from c64carthooks.c */ -extern void cart_nmi_alarm(CLOCK offset, void *data); -extern int cart_freeze_allowed(void); -extern void cart_undump_alarms(void); +void cart_nmi_alarm(CLOCK offset, void *data); +int cart_freeze_allowed(void); +void cart_undump_alarms(void); extern CLOCK cart_nmi_alarm_time; extern CLOCK cart_freeze_alarm_time; -extern void cart_init(void); -extern int cart_resources_init(void); -extern void cart_resources_shutdown(void); -extern int cart_cmdline_options_init(void); +void cart_init(void); +int cart_resources_init(void); +void cart_resources_shutdown(void); +int cart_cmdline_options_init(void); -extern const char *cart_get_file_name(int type); -extern int cart_is_slotmain(int type); /* returns 1 if cart of given type is in "Main Slot" */ -extern int cart_type_enabled(int type); +int cart_can_get_file_name(int type); +const char *cart_get_filename_by_type(int type); +int cart_is_slotmain(int type); /* returns 1 if cart of given type is in "Main Slot" */ +int cart_type_enabled(int type); -extern void cart_attach(int type, BYTE *rawcart); -extern int cart_bin_attach(int type, const char *filename, BYTE *rawcart); -extern void cart_detach(int type); -extern void cart_detach_all(void); +void cart_attach(int type, uint8_t *rawcart); +int cart_bin_attach(int type, const char *filename, uint8_t *rawcart); +void cart_detach(int type); +void cart_detach_all(void); -extern void cart_detach_conflicting(int type); +void cart_detach_conflicting(int type); /* from c64cartmem.c */ -extern void cart_reset_memptr(void); +void cart_reset_memptr(void); -/* mode_phiN bit 0,1 control exrom/game */ +/* mode_phiN bit 0 controls !GAME, bit 1 controls !EXROM */ -/* FIXME: EXROM is inverted in these constants, while GAME is not */ -#define CMODE_8KGAME 0 -#define CMODE_16KGAME 1 -#define CMODE_RAM 2 -#define CMODE_ULTIMAX 3 +/* FIXME: !GAME is inverted in these constants, while !EXROM is not */ +#define CMODE_8KGAME 0 /* !EXROM: 0 !GAME: 1 */ +#define CMODE_16KGAME 1 /* !EXROM: 0 !GAME: 0 */ +#define CMODE_RAM 2 /* !EXROM: 1 !GAME: 1 */ +#define CMODE_ULTIMAX 3 /* !EXROM: 1 !GAME: 0 */ -extern const char *cart_config_string(BYTE mode); /* convert above mode into human readable string */ +const char *cart_config_string(uint8_t mode); /* convert above mode into human readable string */ /* mode_phiN other bits select bank (main slot only!) */ #define CMODE_BANK_SHIFT 2 @@ -116,45 +117,45 @@ extern const char *cart_config_string(BYTE mode); /* convert above mode into hum #ifdef CARTRIDGE_INCLUDE_SLOT0_API -extern void cart_config_changed_slot0(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag); -extern void cart_set_port_exrom_slot0(int n); -extern void cart_set_port_game_slot0(int n); -extern void cart_port_config_changed_slot0(void); +void cart_config_changed_slot0(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag); +void cart_set_port_exrom_slot0(int n); +void cart_set_port_game_slot0(int n); +void cart_port_config_changed_slot0(void); #endif /* CARTRIDGE_INCLUDE_SLOT0_API */ #ifdef CARTRIDGE_INCLUDE_SLOT1_API -extern void cart_config_changed_slot1(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag); -extern void cart_set_port_exrom_slot1(int n); -extern void cart_set_port_game_slot1(int n); -extern void cart_port_config_changed_slot1(void); +void cart_config_changed_slot1(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag); +void cart_set_port_exrom_slot1(int n); +void cart_set_port_game_slot1(int n); +void cart_port_config_changed_slot1(void); #endif /* CARTRIDGE_INCLUDE_SLOT1_API */ #ifdef CARTRIDGE_INCLUDE_SLOTMAIN_API /* these are for the "Main Slot" only */ -extern void cart_romhbank_set_slotmain(unsigned int bank); -extern void cart_romlbank_set_slotmain(unsigned int bank); +void cart_romhbank_set_slotmain(unsigned int bank); +void cart_romlbank_set_slotmain(unsigned int bank); /* FIXME: these are shared between all "main slot" carts, individual cart implementations should get reworked to use local buffers */ -extern BYTE *roml_banks, *romh_banks, *export_ram0; -extern int rombanks_resources_init(void); -extern void rombanks_resources_shutdown(void); +extern uint8_t *roml_banks, *romh_banks, *export_ram0; +int rombanks_resources_init(void); +void rombanks_resources_shutdown(void); extern int roml_bank, romh_bank, export_ram; /* "Main Slot" ROML/ROMH/RAM banking. */ -extern void cart_config_changed_slotmain(BYTE mode_phi1, BYTE mode_phi2, unsigned int wflag); -extern void cart_set_port_exrom_slotmain(int n); -extern void cart_set_port_game_slotmain(int n); -extern void cart_set_port_phi1_slotmain(int n); -extern void cart_set_port_phi2_slotmain(int n); -extern void cart_port_config_changed_slotmain(void); +void cart_config_changed_slotmain(uint8_t mode_phi1, uint8_t mode_phi2, unsigned int wflag); +void cart_set_port_exrom_slotmain(int n); +void cart_set_port_game_slotmain(int n); +void cart_set_port_phi1_slotmain(int n); +void cart_set_port_phi2_slotmain(int n); +void cart_port_config_changed_slotmain(void); #endif /* CARTRIDGE_INCLUDE_SLOTMAIN_API */ -extern void cart_passthrough_changed(void); +void cart_passthrough_changed(void); #endif diff --git a/src/Emulators/vice/c64/cart/c64tpi.c b/src/Emulators/vice/c64/cart/c64tpi.c index c7100156..558dcabe 100644 --- a/src/Emulators/vice/c64/cart/c64tpi.c +++ b/src/Emulators/vice/c64/cart/c64tpi.c @@ -49,7 +49,6 @@ #include "monitor.h" #include "resources.h" #include "tpi.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "crt.h" @@ -81,29 +80,31 @@ /* 4 KB ROM */ #define TPI_ROM_SIZE 0x1000 -static BYTE *tpi_rom = NULL; +static uint8_t *tpi_rom = NULL; static tpi_context_t *tpi_context; /* ---------------------------------------------------------------------*/ -static void tpi_io2_store(WORD addr, BYTE data); -static BYTE tpi_io2_read(WORD addr); -static BYTE tpi_io2_peek(WORD addr); +static void tpi_io2_store(uint16_t addr, uint8_t data); +static uint8_t tpi_io2_read(uint16_t addr); +static uint8_t tpi_io2_peek(uint16_t addr); static int tpi_io2_dump(void); static io_source_t tpi_io2_device = { - CARTRIDGE_NAME_IEEE488, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0x07, - 1, /* read is always valid */ - tpi_io2_store, - tpi_io2_read, - tpi_io2_peek, - tpi_io2_dump, - CARTRIDGE_IEEE488, - 0, - 0 + CARTRIDGE_NAME_IEEE488, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0x07, /* range for the device, regs:$df00-$df07, mirrors:$df08-$dfff */ + 1, /* read is always valid */ + tpi_io2_store, /* store function */ + NULL, /* NO poke function */ + tpi_io2_read, /* read function */ + tpi_io2_peek, /* peek function */ + tpi_io2_dump, /* device state information dump function */ + CARTRIDGE_IEEE488, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *tpi_list_item = NULL; @@ -128,19 +129,19 @@ int tpi_cart_enabled(void) /* ---------------------------------------------------------------------*/ -static void tpi_io2_store(WORD addr, BYTE data) +static void tpi_io2_store(uint16_t addr, uint8_t data) { DBG(("TPI io2 w %02x (%02x)\n", addr, data)); tpicore_store(tpi_context, addr, data); } -static BYTE tpi_io2_read(WORD addr) +static uint8_t tpi_io2_read(uint16_t addr) { DBG(("TPI io2 r %02x\n", addr)); return tpicore_read(tpi_context, addr); } -static BYTE tpi_io2_peek(WORD addr) +static uint8_t tpi_io2_peek(uint16_t addr) { return tpicore_peek(tpi_context, addr); } @@ -153,7 +154,7 @@ static int tpi_io2_dump(void) } /* ---------------------------------------------------------------------*/ -int tpi_roml_read(WORD addr, BYTE *value) +int tpi_roml_read(uint16_t addr, uint8_t *value) { if (rom_enabled) { *value = tpi_rom[addr & 0xfff]; @@ -162,7 +163,7 @@ int tpi_roml_read(WORD addr, BYTE *value) return CART_READ_THROUGH; } -int tpi_peek_mem(WORD addr, BYTE *value) +int tpi_peek_mem(uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { if (rom_enabled) { @@ -200,18 +201,18 @@ static void restore_int(unsigned int int_num, int value) { } -static void set_ca(tpi_context_t *tpi_context, int a) +static void set_ca(tpi_context_t *tpi_ctx, int a) { } -static void set_cb(tpi_context_t *tpi_context, int a) +static void set_cb(tpi_context_t *tpi_ctx, int a) { } static int ieee_is_dev = 1; -static BYTE ieee_is_out = 1; +static uint8_t ieee_is_out = 1; -static void reset(tpi_context_t *tpi_context) +static void reset(tpi_context_t *tpi_ctx) { /* assuming input after reset */ parallel_cpu_set_atn(0); @@ -225,87 +226,89 @@ static void reset(tpi_context_t *tpi_context) ieee_is_out = 1; } -static void store_pa(tpi_context_t *tpi_context, BYTE byte) +static void store_pa(tpi_context_t *tpi_ctx, uint8_t byte) { - if (byte != tpi_context->oldpa) { - BYTE tmp = ~byte; + if (byte != tpi_ctx->oldpa) { + uint8_t tmp = ~byte; ieee_is_dev = byte & 0x01; ieee_is_out = byte & 0x02; - parallel_cpu_set_bus((BYTE)(ieee_is_out ? tpi_context->oldpb : 0xff)); + parallel_cpu_set_bus((uint8_t)(ieee_is_out ? tpi_ctx->oldpb : 0xff)); if (ieee_is_out) { parallel_cpu_set_ndac(0); parallel_cpu_set_nrfd(0); - parallel_cpu_set_dav((BYTE)(tmp & 0x10)); - parallel_cpu_set_eoi((BYTE)(tmp & 0x20)); + parallel_cpu_set_dav((uint8_t)(tmp & 0x10)); + parallel_cpu_set_eoi((uint8_t)(tmp & 0x20)); } else { - parallel_cpu_set_nrfd((BYTE)(tmp & 0x80)); - parallel_cpu_set_ndac((BYTE)(tmp & 0x40)); + parallel_cpu_set_nrfd((uint8_t)(tmp & 0x80)); + parallel_cpu_set_ndac((uint8_t)(tmp & 0x40)); parallel_cpu_set_dav(0); parallel_cpu_set_eoi(0); } if (ieee_is_dev) { parallel_cpu_set_atn(0); } else { - parallel_cpu_set_atn((BYTE)(tmp & 0x08)); + parallel_cpu_set_atn((uint8_t)(tmp & 0x08)); } } } -static void store_pb(tpi_context_t *tpi_context, BYTE byte) +static void store_pb(tpi_context_t *tpi_ctx, uint8_t byte) { - parallel_cpu_set_bus((BYTE)(ieee_is_out ? byte : 0xff)); + parallel_cpu_set_bus((uint8_t)(ieee_is_out ? byte : 0xff)); } -static void undump_pa(tpi_context_t *tpi_context, BYTE byte) +static void undump_pa(tpi_context_t *tpi_ctx, uint8_t byte) { - BYTE tmp = ~byte; + uint8_t tmp = ~byte; ieee_is_dev = byte & 0x01; ieee_is_out = byte & 0x02; - parallel_cpu_set_bus((BYTE)(ieee_is_out ? tpi_context->oldpb : 0xff)); + parallel_cpu_set_bus((uint8_t)(ieee_is_out ? tpi_ctx->oldpb : 0xff)); if (ieee_is_out) { parallel_cpu_set_ndac(0); parallel_cpu_set_nrfd(0); - parallel_cpu_set_dav((BYTE)(tmp & 0x10)); - parallel_cpu_set_eoi((BYTE)(tmp & 0x20)); + parallel_cpu_set_dav((uint8_t)(tmp & 0x10)); + parallel_cpu_set_eoi((uint8_t)(tmp & 0x20)); } else { - parallel_cpu_set_nrfd((BYTE)(tmp & 0x80)); - parallel_cpu_set_ndac((BYTE)(tmp & 0x40)); + parallel_cpu_set_nrfd((uint8_t)(tmp & 0x80)); + parallel_cpu_set_ndac((uint8_t)(tmp & 0x40)); parallel_cpu_set_dav(0); parallel_cpu_set_eoi(0); } if (ieee_is_dev) { parallel_cpu_restore_atn(0); } else { - parallel_cpu_restore_atn((BYTE)(tmp & 0x08)); + parallel_cpu_restore_atn((uint8_t)(tmp & 0x08)); } } -static void undump_pb(tpi_context_t *tpi_context, BYTE byte) +static void undump_pb(tpi_context_t *tpi_ctx, uint8_t byte) { - parallel_cpu_set_bus((BYTE)(ieee_is_out ? byte : 0xff)); + parallel_cpu_set_bus((uint8_t)(ieee_is_out ? byte : 0xff)); } -static void store_pc(tpi_context_t *tpi_context, BYTE byte) +static void store_pc(tpi_context_t *tpi_ctx, uint8_t byte) { int exrom = ((byte & 0x08) ? 0 : 1); /* bit 3, 1 = active */ rom_enabled = ((byte & 0x10) ? 1 : 0); /* bit 4, 1 = active */ /* passthrough support */ - DBG(("TPI store_pc %02x (rom enabled: %d exrom: %d game: %d)\n", byte, rom_enabled, exrom ^ 1, tpi_extgame)); - cart_config_changed_slot0((BYTE)((exrom << 1) | tpi_extgame), (BYTE)((exrom << 1) | tpi_extgame), CMODE_READ); + DBG(("TPI store_pc %02x (rom enabled: %d exrom: %d game: %d)\n", + byte, rom_enabled, exrom ^ 1, tpi_extgame)); + cart_config_changed_slot0((uint8_t)((exrom << 1) | tpi_extgame), + (uint8_t)((exrom << 1) | tpi_extgame), CMODE_READ); } -static void undump_pc(tpi_context_t *tpi_context, BYTE byte) +static void undump_pc(tpi_context_t *tpi_ctx, uint8_t byte) { } -static BYTE read_pa(tpi_context_t *tpi_context) +static uint8_t read_pa(tpi_context_t *tpi_ctx) { - BYTE byte; + uint8_t byte; drive_cpu_execute_all(maincpu_clk); @@ -331,31 +334,34 @@ static BYTE read_pa(tpi_context_t *tpi_context) } } - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPA]) | (tpi_context->c_tpi[TPI_PA] & tpi_context->c_tpi[TPI_DDPA]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPA]) + | (tpi_ctx->c_tpi[TPI_PA] & tpi_ctx->c_tpi[TPI_DDPA]); return byte; } -static BYTE read_pb(tpi_context_t *tpi_context) +static uint8_t read_pb(tpi_context_t *tpi_ctx) { - BYTE byte; + uint8_t byte; drive_cpu_execute_all(maincpu_clk); byte = ieee_is_out ? 0xff : parallel_bus; - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPB]) | (tpi_context->c_tpi[TPI_PB] & tpi_context->c_tpi[TPI_DDPB]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPB]) + | (tpi_ctx->c_tpi[TPI_PB] & tpi_ctx->c_tpi[TPI_DDPB]); return byte; } -static BYTE read_pc(tpi_context_t *tpi_context) +static uint8_t read_pc(tpi_context_t *tpi_ctx) { - BYTE byte = 0xff; + uint8_t byte = 0xff; if (tpi_extexrom) { byte &= ~(1 << 7); } - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPC]) | (tpi_context->c_tpi[TPI_PC] & tpi_context->c_tpi[TPI_DDPC]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPC]) + | (tpi_ctx->c_tpi[TPI_PC] & tpi_ctx->c_tpi[TPI_DDPC]); return byte; } @@ -379,13 +385,13 @@ void tpi_shutdown(void) tpicore_shutdown(tpi_context); } -void tpi_setup_context(machine_context_t *machine_context) +void tpi_setup_context(machine_context_t *machine_ctx) { tpi_context = lib_malloc(sizeof(tpi_context_t)); tpi_context->prv = NULL; - tpi_context->context = (void *)machine_context; + tpi_context->context = (void *)machine_ctx; tpi_context->rmw_flag = &maincpu_rmw_flag; tpi_context->clk_ptr = &maincpu_clk; @@ -410,10 +416,10 @@ void tpi_setup_context(machine_context_t *machine_context) tpi_context->restore_int = restore_int; } -void tpi_passthrough_changed(export_t *export) +void tpi_passthrough_changed(export_t *ex) { - tpi_extexrom = (export)->exrom; - tpi_extgame = (export)->game; + tpi_extexrom = ex->exrom; + tpi_extgame = ex->game; DBG(("IEEE488 passthrough changed exrom: %d game: %d\n", tpi_extexrom, tpi_extgame)); cart_set_port_game_slot0(tpi_extgame); @@ -449,18 +455,20 @@ static int set_ieee488_enabled(int value, void *param) } if (param) { /* if the param is != NULL, then we should load the default image file */ - if (ieee488_filename) { - if (*ieee488_filename) { - DBG(("IEEE: attach default image\n")); - if (cartridge_attach_image(CARTRIDGE_IEEE488, ieee488_filename) < 0) { - DBG(("IEEE: set_enabled did not register\n")); - lib_free(tpi_rom); - tpi_rom = NULL; - return -1; - } - /* ieee488_enabled = 1; */ /* cartridge_attach_image will end up calling set_ieee488_enabled again */ - return 0; + if ((ieee488_filename != NULL) && (*ieee488_filename != 0)) { + DBG(("IEEE: attach default image\n")); + /* try crt first, then binary */ + if ((cartridge_attach_image(CARTRIDGE_CRT, ieee488_filename) < 0) && + (cartridge_attach_image(CARTRIDGE_IEEE488, ieee488_filename) < 0)) { + DBG(("IEEE: set_enabled did not register\n")); + lib_free(tpi_rom); + tpi_rom = NULL; + return -1; /* loading the default was requested, but file could not be loaded */ } + /* ieee488_enabled = 1; */ /* cartridge_attach_image will end up calling set_ieee488_enabled again */ + return 0; + } else { + return -1; /* loading the default was requested, but no filename was set */ } } else { cart_power_off(); @@ -499,7 +507,7 @@ static int set_ieee488_filename(const char *name, void *param) if (set_ieee488_enabled(enabled, (void*)1) < 0) { lib_free(ieee488_filename); ieee488_filename = NULL; - DBG(("IEEE: set_name done: %d '%s'\n", ieee488_enabled, ieee488_filename)); + DBG(("IEEE: set_name done: %d 'NULL'\n", ieee488_enabled)); return -1; } @@ -521,6 +529,9 @@ static const resource_int_t resources_int[] = { int tpi_resources_init(void) { + if (parallel_resources_init() < 0) { + return -1; + } if (resources_register_string(resources_string) < 0) { return -1; } @@ -537,26 +548,23 @@ void tpi_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-ieee488", SET_RESOURCE, 0, + { "-ieee488", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IEEE488", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_IEEE488_INTERFACE, - NULL, NULL }, - { "+ieee488", SET_RESOURCE, 0, + NULL, "Enable the IEEE488 interface emulation" }, + { "+ieee488", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IEEE488", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_IEEE488_INTERFACE, - NULL, NULL }, - { "-ieee488image", SET_RESOURCE, 1, + NULL, "Disable the IEEE488 interface emulation" }, + { "-ieee488image", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IEEE488Image", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_IEEE488_INTERFACE_NAME, - NULL, NULL }, + "", "specify IEEE488 interface image name" }, CMDLINE_LIST_END }; int tpi_cmdline_options_init(void) { + if (parallel_cmdline_options_init() < 0) { + return -1; + } return cmdline_register_options(cmdline_options); } @@ -567,13 +575,13 @@ const char *tpi_get_file_name(void) return ieee488_filename; } -void tpi_config_setup(BYTE *rawcart) +void tpi_config_setup(uint8_t *rawcart) { DBG(("TPI: config_setup\n")); memcpy(tpi_rom, rawcart, TPI_ROM_SIZE); } -int tpi_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +int tpi_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { if (rom_enabled) { switch (addr & 0xf000) { @@ -594,12 +602,12 @@ int tpi_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) return CART_READ_THROUGH; } -void tpi_config_init(export_t *export) +void tpi_config_init(export_t *ex) { DBG(("TPI: tpi_config_init\n")); - tpi_extexrom = export->exrom; - tpi_extgame = export->game; + tpi_extexrom = ex->exrom; + tpi_extgame = ex->game; cart_set_port_exrom_slot0(1); cart_set_port_game_slot0(tpi_extgame); @@ -613,17 +621,18 @@ static int tpi_common_attach(void) return set_ieee488_enabled(1, NULL); } -int tpi_bin_attach(const char *filename, BYTE *rawcart) +int tpi_bin_attach(const char *filename, uint8_t *rawcart) { DBG(("TPI: tpi_bin_attach\n")); if (util_file_load(filename, rawcart, TPI_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } + set_ieee488_filename(filename, NULL); /* set the resource */ return tpi_common_attach(); } -int tpi_crt_attach(FILE *fd, BYTE *rawcart) +int tpi_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; @@ -639,6 +648,7 @@ int tpi_crt_attach(FILE *fd, BYTE *rawcart) return -1; } + set_ieee488_filename(filename, NULL); /* set the resource */ return tpi_common_attach(); } @@ -652,6 +662,12 @@ int tpi_enable(void) return set_ieee488_enabled(1, (void*)1); } +int tpi_disable(void) +{ + return set_ieee488_enabled(0, (void*)1); +} + + /* ---------------------------------------------------------------------*/ int tpi_snapshot_read_module(struct snapshot_s *s) diff --git a/src/Emulators/vice/c64/cart/c64tpi.h b/src/Emulators/vice/c64/cart/c64tpi.h index fce49972..db27bf3b 100644 --- a/src/Emulators/vice/c64/cart/c64tpi.h +++ b/src/Emulators/vice/c64/cart/c64tpi.h @@ -38,34 +38,36 @@ struct machine_context_s; -extern int tpi_cart_enabled(void); +int tpi_cart_enabled(void); -extern void tpi_config_init(export_t *export); -extern void tpi_config_setup(BYTE *rawcart); -extern void tpi_detach(void); -extern int tpi_enable(void); +void tpi_config_init(export_t *export); +void tpi_config_setup(uint8_t *rawcart); +void tpi_detach(void); +int tpi_enable(void); +int tpi_disable(void); -extern int tpi_cmdline_options_init(void); -extern int tpi_resources_init(void); -extern void tpi_resources_shutdown(void); +int tpi_cmdline_options_init(void); +int tpi_resources_init(void); +void tpi_resources_shutdown(void); -extern int tpi_roml_read(WORD addr, BYTE *value); -extern int tpi_peek_mem(WORD addr, BYTE *value); +int tpi_roml_read(uint16_t addr, uint8_t *value); +int tpi_peek_mem(uint16_t addr, uint8_t *value); -extern void tpi_passthrough_changed(export_t *export); +void tpi_passthrough_changed(export_t *export); -extern void tpi_setup_context(struct machine_context_s *machine_context); -extern int tpi_bin_attach(const char *filename, BYTE *rawcart); -extern int tpi_crt_attach(FILE *fd, BYTE *rawcart); -extern const char *tpi_get_file_name(void); -extern int tpi_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +void tpi_setup_context(struct machine_context_s *machine_context); +int tpi_bin_attach(const char *filename, uint8_t *rawcart); +int tpi_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +const char *tpi_get_file_name(void); +int tpi_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern void tpi_reset(void); -extern void tpi_init(void); -extern void tpi_shutdown(void); +void tpi_reset(void); +void tpi_init(void); +void tpi_shutdown(void); struct snapshot_s; -extern int tpi_snapshot_read_module(struct snapshot_s *s); -extern int tpi_snapshot_write_module(struct snapshot_s *s); + +int tpi_snapshot_read_module(struct snapshot_s *s); +int tpi_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/capture.c b/src/Emulators/vice/c64/cart/capture.c index 9b7cbfb2..1547616f 100644 --- a/src/Emulators/vice/c64/cart/capture.c +++ b/src/Emulators/vice/c64/cart/capture.c @@ -38,6 +38,7 @@ #include "cartio.h" #include "cartridge.h" #include "export.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" @@ -99,12 +100,14 @@ static const export_resource_t export_res = { CARTRIDGE_NAME_CAPTURE, 1, 1, NULL, NULL, CARTRIDGE_CAPTURE }; +#define CART_RAM_SIZE (8 * 1024) + static int cart_enabled = 0; static int freeze_pressed = 0; static int register_enabled = 0; static int romh_enabled = 0; -static void capture_reg(WORD addr) +static void capture_reg(uint16_t addr) { if (register_enabled) { if ((addr & 0xffff) == 0xfff7) { @@ -123,7 +126,7 @@ static void capture_reg(WORD addr) } } -static void capture_romhflip(WORD addr) +static void capture_romhflip(uint16_t addr) { if (freeze_pressed) { if ((addr & 0xff00) == 0xfe00) { @@ -134,7 +137,7 @@ static void capture_romhflip(WORD addr) } } -BYTE capture_romh_read(WORD addr) +uint8_t capture_romh_read(uint16_t addr) { capture_reg(addr); capture_romhflip(addr); @@ -147,7 +150,7 @@ BYTE capture_romh_read(WORD addr) return mem_read_without_ultimax(addr); } -void capture_romh_store(WORD addr, BYTE value) +void capture_romh_store(uint16_t addr, uint8_t value) { capture_reg(addr); /* capture_romhflip(addr); */ @@ -159,7 +162,7 @@ void capture_romh_store(WORD addr, BYTE value) /* there is Cartridge RAM at 0x6000..0x7fff */ -BYTE capture_1000_7fff_read(WORD addr) +uint8_t capture_1000_7fff_read(uint16_t addr) { if (cart_enabled) { if (addr >= 0x6000) { @@ -170,7 +173,7 @@ BYTE capture_1000_7fff_read(WORD addr) return mem_read_without_ultimax(addr); } -void capture_1000_7fff_store(WORD addr, BYTE value) +void capture_1000_7fff_store(uint16_t addr, uint8_t value) { if (cart_enabled) { if (addr >= 0x6000) { @@ -181,17 +184,17 @@ void capture_1000_7fff_store(WORD addr, BYTE value) } } -int capture_romh_phi1_read(WORD addr, BYTE *value) +int capture_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int capture_romh_phi2_read(WORD addr, BYTE *value) +int capture_romh_phi2_read(uint16_t addr, uint8_t *value) { return capture_romh_phi1_read(addr, value); } -int capture_peek_mem(export_t *export, WORD addr, BYTE *value) +int capture_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (cart_enabled == 1) { if (addr >= 0x6000 && addr <= 0x7fff) { @@ -209,11 +212,30 @@ int capture_peek_mem(export_t *export, WORD addr, BYTE *value) } /******************************************************************************/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void capture_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void capture_freeze(void) { DBG(("CAPTURE: freeze\n")); if (freeze_pressed == 0) { - cart_config_changed_slotmain(2, 3, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); cart_enabled = 1; freeze_pressed = 1; register_enabled = 1; @@ -224,7 +246,7 @@ void capture_freeze(void) void capture_config_init(void) { DBG(("CAPTURE: config init\n")); - cart_config_changed_slotmain(2, 2, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); } void capture_reset(void) @@ -233,10 +255,10 @@ void capture_reset(void) cart_enabled = 0; register_enabled = 0; freeze_pressed = 0; - cart_config_changed_slotmain(2, 2, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); } -void capture_config_setup(BYTE *rawcart) +void capture_config_setup(uint8_t *rawcart) { DBG(("CAPTURE: config setup\n")); memcpy(romh_banks, rawcart, 0x2000); @@ -253,7 +275,7 @@ static int capture_common_attach(void) return 0; } -int capture_bin_attach(const char *filename, BYTE *rawcart) +int capture_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -261,7 +283,7 @@ int capture_bin_attach(const char *filename, BYTE *rawcart) return capture_common_attach(); } -int capture_crt_attach(FILE *fd, BYTE *rawcart) +int capture_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -300,7 +322,7 @@ void capture_detach(void) ARRAY | RAM | 8192 BYTES of RAM data */ -static char snap_module_name[] = "CARTCAPTURE"; +static const char snap_module_name[] = "CARTCAPTURE"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -315,10 +337,10 @@ int capture_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)cart_enabled) < 0) - || (SMW_B(m, (BYTE)freeze_pressed) < 0) - || (SMW_B(m, (BYTE)register_enabled) < 0) - || (SMW_B(m, (BYTE)romh_enabled) < 0) + || (SMW_B(m, (uint8_t)cart_enabled) < 0) + || (SMW_B(m, (uint8_t)freeze_pressed) < 0) + || (SMW_B(m, (uint8_t)register_enabled) < 0) + || (SMW_B(m, (uint8_t)romh_enabled) < 0) || (SMW_BA(m, romh_banks, 0x2000) < 0) || (SMW_BA(m, export_ram0, 0x2000) < 0)) { snapshot_module_close(m); @@ -330,7 +352,7 @@ int capture_snapshot_write_module(snapshot_t *s) int capture_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -340,7 +362,7 @@ int capture_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/capture.h b/src/Emulators/vice/c64/cart/capture.h index 5d9563ab..f65c2739 100644 --- a/src/Emulators/vice/c64/cart/capture.h +++ b/src/Emulators/vice/c64/cart/capture.h @@ -35,24 +35,25 @@ struct snapshot_s; -extern BYTE capture_romh_read(WORD addr); -extern void capture_romh_store(WORD addr, BYTE value); -extern BYTE capture_1000_7fff_read(WORD addr); -extern void capture_1000_7fff_store(WORD addr, BYTE value); -extern int capture_romh_phi1_read(WORD addr, BYTE *value); -extern int capture_romh_phi2_read(WORD addr, BYTE *value); -extern int capture_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern void capture_freeze(void); - -extern void capture_config_init(void); -extern void capture_reset(void); -extern void capture_config_setup(BYTE *rawcart); -extern int capture_bin_attach(const char *filename, BYTE *rawcart); -extern int capture_crt_attach(FILE *fd, BYTE *rawcart); -extern void capture_detach(void); - -extern int capture_snapshot_write_module(struct snapshot_s *s); -extern int capture_snapshot_read_module(struct snapshot_s *s); +uint8_t capture_romh_read(uint16_t addr); +void capture_romh_store(uint16_t addr, uint8_t value); +uint8_t capture_1000_7fff_read(uint16_t addr); +void capture_1000_7fff_store(uint16_t addr, uint8_t value); +int capture_romh_phi1_read(uint16_t addr, uint8_t *value); +int capture_romh_phi2_read(uint16_t addr, uint8_t *value); +int capture_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void capture_freeze(void); + +void capture_config_init(void); +void capture_reset(void); +void capture_config_setup(uint8_t *rawcart); +int capture_bin_attach(const char *filename, uint8_t *rawcart); +int capture_crt_attach(FILE *fd, uint8_t *rawcart); +void capture_detach(void); +void capture_powerup(void); + +int capture_snapshot_write_module(struct snapshot_s *s); +int capture_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/clockport-mp3at64.c b/src/Emulators/vice/c64/cart/clockport-mp3at64.c index 7c6c3170..cacdba83 100644 --- a/src/Emulators/vice/c64/cart/clockport-mp3at64.c +++ b/src/Emulators/vice/c64/cart/clockport-mp3at64.c @@ -34,16 +34,31 @@ #include +#include "archdep.h" #include "clockport.h" #include "lib.h" -#ifdef MP3AT64_DEBUG #include "log.h" -#endif +#include "monitor.h" #include "sound.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" +#include "clockport-mp3at64.h" + +/* #define MP3AT64_DEBUG */ + +#ifdef MP3AT64_DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* #define DUMPWAV */ + +#ifdef DUMPWAV +FILE *dumpfile; +#endif + /* ------------------------------------------------------------------------- */ /* variables needed */ @@ -53,9 +68,9 @@ static char *clockport_mp3at64_owner = NULL; -static BYTE mp3_frame_buffer[MP3_INPUT_MAX_FRAME]; +static uint8_t mp3_frame_buffer[MP3_INPUT_MAX_FRAME]; -static SWORD *mp3_output_buffers[MP3_BUFFERS]; +static int16_t *mp3_output_buffers[MP3_BUFFERS]; static int mp3_output_buffers_size[MP3_BUFFERS]; static int mp3_output_sample_pos = 0; @@ -68,7 +83,7 @@ static int mp3_input_rate = 44100; static int mp3_input_channels = 1; static int mp3_input_pointer = 0; static int mp3_input_frame_size = 0; -static int mp3_input_frame_mpeg_version = 0; +static int mp3_input_frame_mpeg_version = 0; static int mp3_input_frame_layer = 3; static int mp3_protection = 0; static int mp3_input_bitrate = 0; @@ -83,7 +98,7 @@ static int mp3_input_padding = 0; #define MP3_INPUT_STATE_ID3 6 static int mp3_input_data_state = MP3_INPUT_STATE_IDLE; -static BYTE mp3_id3_length[4]; +static uint8_t mp3_id3_length[4]; static int mp3_id3_len = 0; /* ------------------------------------------------------------------------- */ @@ -102,7 +117,7 @@ static int mp3_get_free_buffer(void) static void mp3_mono_to_stereo(int block) { - SWORD *buffer = lib_malloc(mp3_output_buffers_size[block] * 2); + int16_t *buffer = lib_malloc(mp3_output_buffers_size[block] * 2); int i; for (i = 0; i < mp3_output_buffers_size[block]; ++i) { @@ -118,7 +133,7 @@ static void mp3_resample(int block, int current_rate) { int i; int new_size = mp3_output_buffers_size[block] * mp3_output_rate / current_rate; - SWORD *buffer = lib_malloc(new_size); + int16_t *buffer = lib_malloc(new_size); for (i = 0; i < new_size; ++i) { buffer[i] = mp3_output_buffers[block][i * current_rate / mp3_output_rate]; @@ -128,7 +143,7 @@ static void mp3_resample(int block, int current_rate) mp3_output_buffers_size[block] = new_size; } -void mp3at64_reset(void) +static void mp3at64_reset(void) { int i; @@ -143,9 +158,10 @@ void mp3at64_reset(void) mp3_input_data_state = MP3_INPUT_STATE_IDLE; } -static SWORD mp3_get_current_sample(void) +#ifdef SOUND_SYSTEM_FLOAT +static float mp3_get_current_sample(void) { - SWORD retval = 0; + int16_t retval = 0; int i; if (mp3_output_buffers_size[0]) { @@ -158,19 +174,48 @@ static SWORD mp3_get_current_sample(void) } mp3_output_buffers[MP3_BUFFERS - 1] = NULL; mp3_output_buffers_size[MP3_BUFFERS - 1] = 0; + mp3_output_sample_pos = 0; } } + return retval / 32767.0; +} +#else +static int16_t mp3_get_current_sample(void) +{ + int16_t retval = 0; + int i; + + if (mp3_output_buffers_size[0]) { + retval = mp3_output_buffers[0][mp3_output_sample_pos++]; + if (mp3_output_sample_pos >= mp3_output_buffers_size[0]) { + lib_free(mp3_output_buffers[0]); + for (i = 1; i < MP3_BUFFERS; ++i) { + mp3_output_buffers[i - 1] = mp3_output_buffers[i]; + mp3_output_buffers_size[i - 1] = mp3_output_buffers_size[i]; + } + mp3_output_buffers[MP3_BUFFERS - 1] = NULL; + mp3_output_buffers_size[MP3_BUFFERS - 1] = 0; + mp3_output_sample_pos = 0; + } + } + return retval; } +#endif /* ------------------------------------------------------------------------- */ /* Some prototypes are needed */ static int clockport_mp3at64_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); -static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); static void clockport_mp3at64_sound_reset(sound_t *psid, CLOCK cpu_clk); static void clockport_mp3at64_sound_machine_close(sound_t *psid); +#ifdef SOUND_SYSTEM_FLOAT +static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int clockport_mp3at64_sound_machine_cycle_based(void) { return 0; @@ -181,20 +226,34 @@ static int clockport_mp3at64_sound_machine_channels(void) return 1; } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the ClockPort MP3@64 sound */ +static sound_chip_mixing_spec_t *clockport_mp3at64_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* left channel volume % in case of stereo output, default output to both */ + 100 /* right channel volume % in case of stereo output, default output to both */ + } +}; +#endif + +/* ClockPort MP3@64 sound chip */ static sound_chip_t clockport_mp3at64_sound_chip = { - NULL, /* no open */ - clockport_mp3at64_sound_machine_init, - clockport_mp3at64_sound_machine_close, - clockport_mp3at64_sound_machine_calculate_samples, - NULL, /* no store */ - NULL, /* no read */ - clockport_mp3at64_sound_reset, - clockport_mp3at64_sound_machine_cycle_based, - clockport_mp3at64_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + clockport_mp3at64_sound_machine_init, /* sound chip init function */ + clockport_mp3at64_sound_machine_close, /* sound chip close function */ + clockport_mp3at64_sound_machine_calculate_samples, /* sound chip calculate samples function */ + NULL, /* NO sound chip store function */ + NULL, /* NO sound chip read function */ + clockport_mp3at64_sound_reset, /* sound chip reset function */ + clockport_mp3at64_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, sound chip is NOT cycle based */ + clockport_mp3at64_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */ +#ifdef SOUND_SYSTEM_FLOAT + clockport_mp3at64_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* chip enabled, toggled when sound chip is (de-)activated */ }; -static WORD clockport_mp3at64_sound_chip_offset = 0; +static uint16_t clockport_mp3at64_sound_chip_offset = 0; void clockport_mp3at64_sound_chip_init(void) { @@ -203,6 +262,9 @@ void clockport_mp3at64_sound_chip_init(void) static int clockport_mp3at64_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec) { +#ifdef DUMPWAV + dumpfile = fopen("dumpwav.raw", "wb"); +#endif mp3_err = mpg123_init(); if (mp3_err != MPG123_OK) { return 0; @@ -233,28 +295,48 @@ static void clockport_mp3at64_sound_machine_close(sound_t *psid) mp3_output_buffers_size[i] = 0; } } +#ifdef DUMPWAV + fclose(dumpfile); +#endif } -static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) +{ + int i; + float sample; + + for (i = 0; i < nr; ++i) { + sample = mp3_get_current_sample(); + pbuf[i] = sample; + } + return nr; +} +#else +static int clockport_mp3at64_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) { int i; - SWORD sample; + int16_t sample; + + DBG(("clockport_mp3at64_sound_machine_calculate_samples soc:%d num:%d clock-delta:%ld n:%04x", soc, nr, *delta_t, n)); for (i = 0; i < nr; ++i) { switch (soc) { default: - case 1: + case SOUND_OUTPUT_MONO: sample = sound_audio_mix(mp3_get_current_sample(), mp3_get_current_sample()); pbuf[i] = sound_audio_mix(pbuf[i], sample); break; - case 2: + case SOUND_OUTPUT_STEREO: pbuf[i * 2] = sound_audio_mix(pbuf[i * 2], mp3_get_current_sample()); - pbuf[(i * 2) + 1] = sound_audio_mix(pbuf[i], mp3_get_current_sample()); + pbuf[(i * 2) + 1] = sound_audio_mix(pbuf[(i * 2) + 1], mp3_get_current_sample()); break; } } return nr; } +#endif static void clockport_mp3at64_sound_reset(sound_t *psid, CLOCK cpu_clk) { @@ -263,23 +345,23 @@ static void clockport_mp3at64_sound_reset(sound_t *psid, CLOCK cpu_clk) /* ------------------------------------------------------------------------- */ -static void mp3at64_set_i2c_data(BYTE val) +static void mp3at64_set_i2c_data(uint8_t val) { /* TODO */ } -static void mp3at64_set_i2c_clock(BYTE val) +static void mp3at64_set_i2c_clock(uint8_t val) { /* TODO */ } -static BYTE mp3at64_read_i2c_data(void) +static uint8_t mp3at64_read_i2c_data(void) { /* TODO */ return 0; } -static BYTE mp3at64_read_i2c_clock(void) +static uint8_t mp3at64_read_i2c_clock(void) { /* TODO */ return 0; @@ -287,13 +369,13 @@ static BYTE mp3at64_read_i2c_clock(void) /* ------------------------------------------------------------------------- */ -static int mp3_sampling_rates[4][3] = { +static const int mp3_sampling_rates[4][3] = { { 44100, 22050, 11025 }, { 48000, 24000, 12000 }, { 32000, 16000, 8000 } }; -static int mp3_bitrates[16][3][3] = { +static const int mp3_bitrates[16][3][3] = { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, { { 32, 32, 32 }, { 32, 8, 8 }, { 32, 8, 8 } }, { { 64, 48, 40 }, { 48, 16, 16 }, { 48, 16, 16 } }, @@ -312,13 +394,13 @@ static int mp3_bitrates[16][3][3] = { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } }; -static int mp3_slot_sizes[3] = { +static const int mp3_slot_sizes[3] = { 4, 1, 1 }; -static int mp3_sampels_per_frame[3][3] = { +static const int mp3_sampels_per_frame[3][3] = { { 384, 1152, 1152 }, { 384, 1152, 576 }, { 384, 1152, 576 } @@ -408,10 +490,16 @@ static int mp3_validate(void) static int mp3_frame_is_empty(void) { - if (mp3_frame_buffer[0x24] == 'X' && mp3_frame_buffer[0x25] == 'i' && mp3_frame_buffer[0x26] == 'n' && mp3_frame_buffer[0x27] == 'g') { + if (mp3_frame_buffer[0x24] == 'X' && + mp3_frame_buffer[0x25] == 'i' && + mp3_frame_buffer[0x26] == 'n' && + mp3_frame_buffer[0x27] == 'g') { return 1; } - if (mp3_frame_buffer[0x24] == 'I' && mp3_frame_buffer[0x25] == 'n' && mp3_frame_buffer[0x26] == 'f' && mp3_frame_buffer[0x27] == 'o') { + if (mp3_frame_buffer[0x24] == 'I' && + mp3_frame_buffer[0x25] == 'n' && + mp3_frame_buffer[0x26] == 'f' && + mp3_frame_buffer[0x27] == 'o') { return 1; } return 0; @@ -420,14 +508,24 @@ static int mp3_frame_is_empty(void) /* ------------------------------------------------------------------------- */ -static void mp3at64_store_mp3_data(BYTE val) +static void mp3at64_store_mp3_data(uint8_t val) { - SWORD *buffer = NULL; + int16_t *buffer = NULL; int block; int ret; size_t size; + static int warnoverflow = 1; - mp3_frame_buffer[mp3_input_pointer] = val; + DBG(("mp3at64_store_mp3_data: 0x%02x ptr:%04x state:%d", val, mp3_input_pointer, mp3_input_data_state)); + + if (mp3_input_pointer < MP3_INPUT_MAX_FRAME) { + mp3_frame_buffer[mp3_input_pointer] = val; + warnoverflow = 1; + } else if (warnoverflow) { + log_error(LOG_DEFAULT, "mp3_frame_buffer overflow (state:%d pos:%04x)", + mp3_input_data_state, (unsigned)mp3_input_pointer); + warnoverflow = 0; + } switch (mp3_input_data_state) { case MP3_INPUT_STATE_IDLE: @@ -546,7 +644,10 @@ static void mp3at64_store_mp3_data(BYTE val) mp3_id3_length[mp3_input_pointer - 6] = val; mp3_input_pointer++; if (mp3_input_pointer == 10) { - mp3_id3_len = (mp3_id3_length[0] << 21) | (mp3_id3_length[1] << 14) | (mp3_id3_length[2] << 7) | mp3_id3_length[3]; + mp3_id3_len = (mp3_id3_length[0] << 21) | + (mp3_id3_length[1] << 14) | + (mp3_id3_length[2] << 7) | + mp3_id3_length[3]; } } break; @@ -602,17 +703,23 @@ static void mp3at64_store_mp3_data(BYTE val) } else { block = mp3_get_free_buffer(); if (block != -1) { - buffer = lib_malloc(MP3_MAX_SAMPLES_PER_FRAME * sizeof(SWORD) * 2); + buffer = lib_malloc(MP3_MAX_SAMPLES_PER_FRAME * sizeof(int16_t) * 2); ret = mpg123_decode(mh, mp3_frame_buffer, mp3_input_frame_size, (unsigned char *)buffer, MP3_MAX_SAMPLES_PER_FRAME * 2, &size); if (ret != MPG123_ERR && ret != MPG123_NEED_MORE) { mp3_output_buffers[block] = buffer; - mp3_output_buffers_size[block] = size / 2; + mp3_output_buffers_size[block] = (int)(size / 2); if (mp3_get_channels() != 2) { mp3_mono_to_stereo(block); } if (mp3_get_sampling_rate() != mp3_output_rate) { mp3_resample(block, mp3_get_sampling_rate()); } + DBG(("block: %d size: %d", block, size)); +#ifdef DUMPWAV + fwrite(mp3_output_buffers[block], 1, mp3_output_buffers_size[block], dumpfile); +#endif + } else { + lib_free(buffer); } } mp3_input_pointer = 0; @@ -624,7 +731,7 @@ static void mp3at64_store_mp3_data(BYTE val) } } -static BYTE mp3at64_read_mp3_status(void) +static uint8_t mp3at64_read_mp3_status(void) { if (mp3_get_free_buffer() != -1) { return 0x80; @@ -634,28 +741,24 @@ static BYTE mp3at64_read_mp3_status(void) /* ------------------------------------------------------------------------- */ -static void clockport_mp3at64_store(WORD address, BYTE val, void *context) +static void clockport_mp3at64_store(uint16_t address, uint8_t val, void *context) { switch (address) { case 4: mp3at64_store_mp3_data(val); break; case 5: -#ifdef MP3AT64_DEBUG - log_warning(LOG_DEFAULT, "storing i2c data: %d", val); -#endif + DBG(("storing i2c data: %d", val)); mp3at64_set_i2c_data(val); break; case 6: -#ifdef MP3AT64_DEBUG - log_warning(LOG_DEFAULT, "storing i2c clock: %d", val); -#endif + DBG(("storing i2c clock: %d", val)); mp3at64_set_i2c_clock(val); break; } } -static BYTE clockport_mp3at64_read(WORD address, int *valid, void *context) +static uint8_t clockport_mp3at64_read(uint16_t address, int *valid, void *context) { switch (address) { case 4: @@ -673,7 +776,7 @@ static BYTE clockport_mp3at64_read(WORD address, int *valid, void *context) return 0; } -static BYTE clockport_mp3at64_peek(WORD address, void *context) +static uint8_t clockport_mp3at64_peek(uint16_t address, void *context) { switch (address) { case 4: @@ -694,6 +797,8 @@ static void clockport_mp3at64_reset(void *context) static int clockport_mp3at64_dump(void *context) { /* TODO */ + /* FIXME: this is incomplete */ + mon_out("mp3 status: $%02x\n", mp3at64_read_mp3_status()); return 0; } @@ -720,11 +825,12 @@ void clockport_mp3at64_shutdown(void) mp3at64_reset(); } -clockport_device_t *clockport_mp3at64_open_device(char *owner) +clockport_device_t *clockport_mp3at64_open_device(const char *owner) { clockport_device_t *retval = NULL; + DBG(("clockport_mp3at64_open_device")); if (clockport_mp3at64_sound_chip.chip_enabled) { - ui_error(translate_text(IDGS_CLOCKPORT_MP3AT64_IN_USE_BY_S), clockport_mp3at64_owner); + ui_error("ClockPort MP3@64 already in use by %s.", clockport_mp3at64_owner); return NULL; } retval = lib_malloc(sizeof(clockport_device_t)); diff --git a/src/Emulators/vice/c64/cart/clockport-mp3at64.h b/src/Emulators/vice/c64/cart/clockport-mp3at64.h index c05058e7..99395dc4 100644 --- a/src/Emulators/vice/c64/cart/clockport-mp3at64.h +++ b/src/Emulators/vice/c64/cart/clockport-mp3at64.h @@ -29,10 +29,10 @@ #include "clockport.h" -extern int clockport_mp3at64_init(void); -extern void clockport_mp3at64_shutdown(void); -extern clockport_device_t *clockport_mp3at64_open_device(char *owner); +int clockport_mp3at64_init(void); +void clockport_mp3at64_shutdown(void); +clockport_device_t *clockport_mp3at64_open_device(const char *owner); -extern void clockport_mp3at64_sound_chip_init(void); +void clockport_mp3at64_sound_chip_init(void); #endif diff --git a/src/Emulators/vice/c64/cart/clockport-rrnet.c b/src/Emulators/vice/c64/cart/clockport-rrnet.c index 5b84d32a..889b2f35 100644 --- a/src/Emulators/vice/c64/cart/clockport-rrnet.c +++ b/src/Emulators/vice/c64/cart/clockport-rrnet.c @@ -30,7 +30,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -39,20 +39,23 @@ #include "clockport.h" #include "cs8900io.h" #include "lib.h" -#include "translate.h" #include "uiapi.h" +#include "clockport-rrnet.h" + /* ------------------------------------------------------------------------- */ /* variables needed */ /* Flag: Do we have the RRNET enabled? */ static int clockport_rrnet_enabled = 0; +/* Flag: Type of device ? */ +static int clockport_rrnet_deviceid = 0; static char *clockport_rrnet_owner = NULL; /* ------------------------------------------------------------------------- */ -static void clockport_rrnet_store(WORD address, BYTE val, void *context) +static void clockport_rrnet_store(uint16_t address, uint8_t val, void *context) { if (address < 0x02) { return; @@ -62,18 +65,33 @@ static void clockport_rrnet_store(WORD address, BYTE val, void *context) cs8900io_store(address, val); } -static BYTE clockport_rrnet_read(WORD address, int *valid, void *context) +static uint8_t clockport_rrnet_read(uint16_t address, int *valid, void *context) { if (address < 0x02) { return 0; } - address ^= 0x08; + /* on the MK3, the MAC and a checksum can be read from the last 4 bytes, see + http://wiki.icomp.de/wiki/RR-Net#Detecting_MK3 */ + if (clockport_rrnet_deviceid == CLOCKPORT_DEVICE_RRNETMK3) { + if ((address >= 0x0c) && (address <= 0x0f)) { + unsigned char mk3mac[4]; + /* use the recommended default for the time being */ + mk3mac[0] = 0xfb; /* MAC hi */ + mk3mac[1] = 0xff; /* MAC lo */ + mk3mac[2] = mk3mac[0] ^ mk3mac[1] ^ 0x55; /* checksum 0 */ + mk3mac[3] = (mk3mac[0] + mk3mac[1] + mk3mac[2]) ^ 0xaa; /* checksum 1 */ + *valid = 1; + return (mk3mac[address - 0x0c]); + } + } + + address ^= 0x08; *valid = 1; return cs8900io_read(address); } -static BYTE clockport_rrnet_peek(WORD address, void *context) +static uint8_t clockport_rrnet_peek(uint16_t address, void *context) { if (address < 0x02) { return 0; @@ -116,14 +134,15 @@ void clockport_rrnet_shutdown(void) { if (clockport_rrnet_enabled) { cs8900io_disable(); + clockport_rrnet_deviceid = 0; } } -clockport_device_t *clockport_rrnet_open_device(char *owner) +clockport_device_t *clockport_rrnet_open_device(const char *owner, int deviceid) { clockport_device_t *retval = NULL; if (clockport_rrnet_enabled) { - ui_error(translate_text(IDGS_CLOCKPORT_RRNET_IN_USE_BY_S), clockport_rrnet_owner); + ui_error("ClockPort RRNET already in use by %s.", clockport_rrnet_owner); return NULL; } if (cs8900io_enable(owner) < 0) { @@ -141,8 +160,9 @@ clockport_device_t *clockport_rrnet_open_device(char *owner) retval->device_context = NULL; clockport_rrnet_enabled = 1; + clockport_rrnet_deviceid = deviceid; return retval; } -#endif /* #ifdef HAVE_PCAP */ +#endif /* #ifdef HAVE_RAWNET */ diff --git a/src/Emulators/vice/c64/cart/clockport-rrnet.h b/src/Emulators/vice/c64/cart/clockport-rrnet.h index 4d372d72..fd490f13 100644 --- a/src/Emulators/vice/c64/cart/clockport-rrnet.h +++ b/src/Emulators/vice/c64/cart/clockport-rrnet.h @@ -27,8 +27,8 @@ #ifndef VICE_CLOCKPORT_RRNET_H #define VICE_CLOCKPORT_RRNET_H -extern int clockport_rrnet_init(void); -extern void clockport_rrnet_shutdown(void); -extern clockport_device_t *clockport_rrnet_open_device(char *owner); +int clockport_rrnet_init(void); +void clockport_rrnet_shutdown(void); +clockport_device_t *clockport_rrnet_open_device(const char *owner, int deviceid); #endif diff --git a/src/Emulators/vice/c64/cart/clockport.c b/src/Emulators/vice/c64/cart/clockport.c index 090800a6..c5adcc25 100644 --- a/src/Emulators/vice/c64/cart/clockport.c +++ b/src/Emulators/vice/c64/cart/clockport.c @@ -33,7 +33,7 @@ #include "clockport.h" #include "lib.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include "clockport-rrnet.h" #endif @@ -50,8 +50,9 @@ clockport_supported_devices_t clockport_supported_devices[] = { { CLOCKPORT_DEVICE_NONE, "None" }, -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET { CLOCKPORT_DEVICE_RRNET, "RRNet" }, + { CLOCKPORT_DEVICE_RRNETMK3, "RRNet MK3" }, #endif #ifdef USE_MPG123 { CLOCKPORT_DEVICE_MP3_64, "MP3@64" }, @@ -81,7 +82,7 @@ static clockport_device_list_t clockport_device_head = { NULL, NULL }; int clockport_resources_init(void) { /* Init clockport devices */ -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET clockport_rrnet_init(); #endif @@ -110,7 +111,7 @@ void clockport_resources_shutdown(void) } /* Shutdown clockport devices */ -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET clockport_rrnet_shutdown(); #endif @@ -126,16 +127,17 @@ void clockport_resources_shutdown(void) #endif } -clockport_device_t *clockport_open_device(int deviceid, char *owner) +clockport_device_t *clockport_open_device(int deviceid, const char *owner) { clockport_device_list_t *current = &clockport_device_head; clockport_device_t *retval = NULL; clockport_device_list_t *entry = NULL; switch (deviceid) { -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET case CLOCKPORT_DEVICE_RRNET: - retval = clockport_rrnet_open_device(owner); + case CLOCKPORT_DEVICE_RRNETMK3: + retval = clockport_rrnet_open_device(owner, deviceid); break; #endif diff --git a/src/Emulators/vice/c64/cart/clockport.h b/src/Emulators/vice/c64/cart/clockport.h index 53fb4465..48472649 100644 --- a/src/Emulators/vice/c64/cart/clockport.h +++ b/src/Emulators/vice/c64/cart/clockport.h @@ -29,21 +29,25 @@ #include "vicetypes.h" -#define CLOCKPORT_DEVICE_NONE 0 -#define CLOCKPORT_DEVICE_ETH64_II 1 -#define CLOCKPORT_DEVICE_RRNET 2 -#define CLOCKPORT_DEVICE_SILVER_SURFER 3 -#define CLOCKPORT_DEVICE_MP3_64 4 -#define CLOCKPORT_DEVICE_CW3_SID 5 +enum { + CLOCKPORT_DEVICE_NONE = 0, + CLOCKPORT_DEVICE_ETH64_II, + CLOCKPORT_DEVICE_RRNET, + CLOCKPORT_DEVICE_RRNETMK3, + CLOCKPORT_DEVICE_SILVER_SURFER, + CLOCKPORT_DEVICE_MP3_64, + CLOCKPORT_DEVICE_CW3_SID, -#define CLOCKPORT_MAX_ENTRIES 6 + /* This entry needs to always be at the end */ + CLOCKPORT_MAX_ENTRIES +}; typedef struct clockport_device_s { - char *owner; + const char *owner; int devicenr; - void (*store)(WORD address, BYTE byte, void *context); - BYTE (*read)(WORD address, int *valid, void *context); - BYTE (*peek)(WORD address, void *context); + void (*store)(uint16_t address, uint8_t byte, void *context); + uint8_t (*read)(uint16_t address, int *valid, void *context); + uint8_t (*peek)(uint16_t address, void *context); void (*reset)(void *context); int (*dump)(void *context); void (*close)(struct clockport_device_s *device); @@ -60,14 +64,14 @@ typedef struct clockport_supported_devices_s { char *name; } clockport_supported_devices_t; -extern int clockport_resources_init(void); -extern void clockport_resources_shutdown(void); +int clockport_resources_init(void); +void clockport_resources_shutdown(void); -extern clockport_device_t *clockport_open_device(int deviceid, char *owner); -extern void clockport_close_device(clockport_device_t *device); +clockport_device_t *clockport_open_device(int deviceid, const char *owner); +void clockport_close_device(clockport_device_t *device); extern clockport_supported_devices_t clockport_supported_devices[]; -extern char *clockport_device_id_to_name(int id); +char *clockport_device_id_to_name(int id); #endif diff --git a/src/Emulators/vice/c64/cart/comal80.c b/src/Emulators/vice/c64/cart/comal80.c index 5d574c99..97bd6309 100644 --- a/src/Emulators/vice/c64/cart/comal80.c +++ b/src/Emulators/vice/c64/cart/comal80.c @@ -38,16 +38,19 @@ #include "c64mem.h" #include "cartio.h" #include "cartridge.h" +#include "cmdline.h" #include "comal80.h" #include "export.h" +#include "log.h" #include "monitor.h" +#include "resources.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" #ifdef DEBUGCART -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -56,76 +59,112 @@ Comal80 Cartridge - 64K ROM (32K mapped to $8000 and 32K mapped to $A000) + - free socket for another 64K eprom + + The cart has 1 (write-only) bank control register which is located at $DE00 + and mirrored throughout the $DE00-$DEFF range. + + Two variants of this Cartridge existed: + + 1. Grey Cartridge (Comal Users Group, USA) + Produced around 1984-1985, likely with UniComal Denmark’s approval. + Approx. 2,000 units distributed (according to COMAL Today). + + - 4 sockets populated with 16 KB EPROMs (27128) + - NO additional socket, but it was possible to piggyback a fifth EPROM via + minor hardware mod + + bit 7 : - + bit 6 : GAME + bit 5 : EXROM + bit 4 : - + bit 3 : - + bit 2 : - + bit 0-1 : selects EPROM (16k bank) + + 2. Black Cartridge (Official Commodore Release) + Used internationally and with a different hardware configuration. + + - Two fixed 32 KB ROMs (Commodore) and one socket for a 32 KB (or with + hardware modification 64 KB ) EPROM + + bit 7 : - + bit 6 : GAME + EXROM + bit 5 : - + bit 4 : - + bit 3 : - + bit 2 : switches to the optional third socket (additional 2x16k) + bit 0-1 : selects EPROM+bank (4x16k bank) - The cart has 1 (write-only) bank control register which - is located at $DE00 and mirrored throughout the $DE00-$DEFF - range. - - bit 7 : exrom? - bit 6 : game? - bit 5 : unknown function (used by the software to disable the cartridge) - bit 4 : unused? - bit 3 : unused? - bit 2 : unknown function (used by the software however) - bit 0-1 : selects bank */ static int currregval = 0; +static int extrarom = 0; + +#define VARIANT_GREY 0 +#define VARIANT_BLACK 1 +static int comal80_variant = VARIANT_BLACK; -static void comal80_io1_store(WORD addr, BYTE value) +static void comal80_io1_store(uint16_t addr, uint8_t value) { int cmode, currbank; - currregval = value & 0xc7; - currbank = value & 3; - - switch (value & 0xe0) { - case 0xe0: - cmode = CMODE_RAM; - break; - default: - case 0x80: - cmode = CMODE_16KGAME; - break; - case 0x40: - cmode = CMODE_8KGAME; - break; + if (comal80_variant == VARIANT_GREY) { + static int modes[4] = { + CMODE_16KGAME, CMODE_ULTIMAX, CMODE_8KGAME, CMODE_RAM + }; + currregval = value & 0x63; + cmode = modes[(value & 0x60) >> 5]; + currbank = value & 3; + } else { + currregval = value & 0x47; + cmode = (value & 0x40) ? CMODE_RAM : CMODE_16KGAME; + currbank = value & 7; } #ifdef DEBUGCART - if ((value != 0x82) && (value != 0x83)) { - DBG(("COMAL80: IO1W %04x %02x mode: %d bank: %d\n", addr, value, cmode, currbank)); + if (currregval != value) { + static unsigned int last = 0; + unsigned int now = value ^ currregval; + if (last != now) { + DBG(("using unconnected bits: 0x%02x", now)); + last = now; + } } #endif - cart_config_changed_slotmain(0, (BYTE)(cmode | (currbank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(0, (uint8_t)(cmode | (currbank << CMODE_BANK_SHIFT)), CMODE_READ); } -static BYTE comal80_io1_peek(WORD addr) +static uint8_t comal80_io1_peek(uint16_t addr) { return currregval; } static int comal80_dump(void) { - mon_out("register value: %d\n", currregval); - mon_out(" bank: %d\n", currregval & 3); + mon_out("Cartridge variant: %s", (comal80_variant == VARIANT_GREY) ? "grey" : "black"); + mon_out("Extra eprom is installed: %s\n", extrarom ? "yes" : "no"); + mon_out("Register value: $%02x\n", (unsigned int)currregval); + mon_out(" bank: %d/%d\n", currregval & 7, extrarom ? 8 : 4); return 0; } /* ---------------------------------------------------------------------*/ static io_source_t comal80_device = { - CARTRIDGE_NAME_COMAL80, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - comal80_io1_store, - NULL, - comal80_io1_peek, - comal80_dump, - CARTRIDGE_COMAL80, - 0, - 0 + CARTRIDGE_NAME_COMAL80, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read never valid, device is write only */ + comal80_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + comal80_io1_peek, /* peek function */ + comal80_dump, /* device state information dump function */ + CARTRIDGE_COMAL80, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *comal80_list_item = NULL; @@ -142,7 +181,7 @@ void comal80_config_init(void) currregval = 0; } -void comal80_config_setup(BYTE *rawcart) +void comal80_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); @@ -152,12 +191,67 @@ void comal80_config_setup(BYTE *rawcart) memcpy(&romh_banks[0x4000], &rawcart[0xa000], 0x2000); memcpy(&roml_banks[0x6000], &rawcart[0xc000], 0x2000); memcpy(&romh_banks[0x6000], &rawcart[0xe000], 0x2000); + + memset(&roml_banks[0x8000], 0xff, 0x8000); + memset(&romh_banks[0x8000], 0xff, 0x8000); + + if (extrarom) { + memcpy(&roml_banks[0x8000], &rawcart[0x10000], 0x2000); + memcpy(&romh_banks[0x8000], &rawcart[0x12000], 0x2000); + memcpy(&roml_banks[0xa000], &rawcart[0x14000], 0x2000); + memcpy(&romh_banks[0xa000], &rawcart[0x16000], 0x2000); + memcpy(&roml_banks[0xc000], &rawcart[0x18000], 0x2000); + memcpy(&romh_banks[0xc000], &rawcart[0x1a000], 0x2000); + memcpy(&roml_banks[0xe000], &rawcart[0x1c000], 0x2000); + memcpy(&romh_banks[0xe000], &rawcart[0x1e000], 0x2000); + } + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ + +static int set_comal80_variant(int val, void *param) +{ + comal80_variant = val ? 1 : 0; + return 0; +} + +static const resource_int_t resources_int[] = { + { "Comal80Revision", VARIANT_BLACK, RES_EVENT_NO, NULL, + &comal80_variant, set_comal80_variant, NULL }, + RESOURCE_INT_LIST_END +}; + +int comal80_resources_init(void) +{ + return resources_register_int(resources_int); +} + +void comal80_resources_shutdown(void) +{ + +} + +static const cmdline_option_t cmdline_options[] = +{ + { "-comal80rev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "Comal80Revision", NULL, + "", "Set Comal 80 Revision (0: Grey, 1: Commodore/Black)" }, + CMDLINE_LIST_END +}; + +int comal80_cmdline_options_init(void) +{ + if (cmdline_register_options(cmdline_options) < 0) { + return -1; + } + return 0; +} + static int comal80_common_attach(void) { + DBG(("using comal 80 variant: %s", (comal80_variant == VARIANT_GREY) ? "grey" : "black (commodore)")); if (export_add(&export_res) < 0) { return -1; } @@ -165,30 +259,42 @@ static int comal80_common_attach(void) return 0; } -int comal80_bin_attach(const char *filename, BYTE *rawcart) +int comal80_bin_attach(const char *filename, uint8_t *rawcart) { - if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - return -1; + extrarom = 1; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + extrarom = 0; + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } } return comal80_common_attach(); } -int comal80_crt_attach(FILE *fd, BYTE *rawcart) +int comal80_crt_attach(FILE *fd, uint8_t *rawcart, int variant) { crt_chip_header_t chip; + extrarom = 0; + /* NOTE: in the CRT file we use 0 for the "black" variant, 1 for "grey" */ + comal80_variant = (variant == 1) ? VARIANT_GREY : VARIANT_BLACK; + while (1) { if (crt_read_chip_header(&chip, fd)) { break; } - if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 3) { + if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 7) { return -1; } if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { return -1; } + + if (chip.bank > 3) { + extrarom = 1; + } } return comal80_common_attach(); } @@ -198,6 +304,7 @@ void comal80_detach(void) export_remove(&export_res); io_source_unregister(comal80_list_item); comal80_list_item = NULL; + comal80_variant = VARIANT_BLACK; } /* ---------------------------------------------------------------------*/ @@ -207,13 +314,15 @@ void comal80_detach(void) type | name | description ------------------------------ BYTE | register | control register - ARRAY | ROML | 32768 BYTES of ROML data - ARRAY | ROMH | 32768 BYTES of ROMH data + BYTE | extra rom| image contains extra eprom + BYTE | revision | hardware variant + ARRAY | ROML | 32768 or 65536 BYTES of ROML data + ARRAY | ROMH | 32768 or 65536 BYTES of ROMH data */ -static char snap_module_name[] = "CARTCOMAL"; +static const char snap_module_name[] = "CARTCOMAL"; #define SNAP_MAJOR 0 -#define SNAP_MINOR 0 +#define SNAP_MINOR 2 int comal80_snapshot_write_module(snapshot_t *s) { @@ -226,9 +335,11 @@ int comal80_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)currregval) < 0) - || (SMW_BA(m, roml_banks, 0x8000) < 0) - || (SMW_BA(m, romh_banks, 0x8000) < 0)) { + || (SMW_B(m, (uint8_t)currregval) < 0) + || (SMW_B(m, (uint8_t)extrarom) < 0) + || (SMW_B(m, (uint8_t)comal80_variant) < 0) + || (SMW_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0) + || (SMW_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) { snapshot_module_close(m); return -1; } @@ -238,7 +349,7 @@ int comal80_snapshot_write_module(snapshot_t *s) int comal80_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -248,15 +359,17 @@ int comal80_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } if (0 || (SMR_B_INT(m, &currregval) < 0) - || (SMR_BA(m, roml_banks, 0x8000) < 0) - || (SMR_BA(m, romh_banks, 0x8000) < 0)) { + || (SMR_B_INT(m, &extrarom) < 0) + || (SMR_B_INT(m, &comal80_variant) < 0) + || (SMR_BA(m, roml_banks, extrarom ? 0x10000 : 0x8000) < 0) + || (SMR_BA(m, romh_banks, extrarom ? 0x10000 : 0x8000) < 0)) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/comal80.h b/src/Emulators/vice/c64/cart/comal80.h index ab3dafa9..3b1e0136 100644 --- a/src/Emulators/vice/c64/cart/comal80.h +++ b/src/Emulators/vice/c64/cart/comal80.h @@ -31,15 +31,19 @@ #include "vicetypes.h" -extern void comal80_config_init(void); -extern void comal80_config_setup(BYTE *rawcart); -extern int comal80_bin_attach(const char *filename, BYTE *rawcart); -extern int comal80_crt_attach(FILE *fd, BYTE *rawcart); -extern void comal80_detach(void); +void comal80_config_init(void); +void comal80_config_setup(uint8_t *rawcart); +int comal80_bin_attach(const char *filename, uint8_t *rawcart); +int comal80_crt_attach(FILE *fd, uint8_t *rawcart, int variant); +void comal80_detach(void); + +int comal80_cmdline_options_init(void); +int comal80_resources_init(void); +void comal80_resources_shutdown(void); struct snapshot_s; -extern int comal80_snapshot_write_module(struct snapshot_s *s); -extern int comal80_snapshot_read_module(struct snapshot_s *s); +int comal80_snapshot_write_module(struct snapshot_s *s); +int comal80_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/cpmcart.c b/src/Emulators/vice/c64/cart/cpmcart.c index 39cdf91b..8597fef4 100644 --- a/src/Emulators/vice/c64/cart/cpmcart.c +++ b/src/Emulators/vice/c64/cart/cpmcart.c @@ -48,139 +48,30 @@ #include "monitor.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "z80regs.h" -#ifdef Z80_4MHZ -#define CLK_ADD(clock, amount) clock = z80cpu_clock_add(clock, amount) -#else -#define CLK_ADD(clock, amount) clock += amount -#endif +#define CLK maincpu_clk -static BYTE reg_a = 0; -static BYTE reg_b = 0; -static BYTE reg_c = 0; -static BYTE reg_d = 0; -static BYTE reg_e = 0; -static BYTE reg_f = 0; -static BYTE reg_h = 0; -static BYTE reg_l = 0; -static BYTE reg_ixh = 0; -static BYTE reg_ixl = 0; -static BYTE reg_iyh = 0; -static BYTE reg_iyl = 0; -static WORD reg_sp = 0; -static DWORD z80_reg_pc = 0; -static BYTE reg_i = 0; -static BYTE reg_r = 0; - -static BYTE iff1 = 0; -static BYTE iff2 = 0; -static BYTE im_mode = 0; - -static BYTE reg_a2 = 0; -static BYTE reg_b2 = 0; -static BYTE reg_c2 = 0; -static BYTE reg_d2 = 0; -static BYTE reg_e2 = 0; -static BYTE reg_f2 = 0; -static BYTE reg_h2 = 0; -static BYTE reg_l2 = 0; +z80_regs_t z80_regs; static int z80_started = 0; static int cpmcart_enabled = 0; -static read_func_ptr_t cpmcart_mem_read_tab[0x101]; -static store_func_ptr_t cpmcart_mem_write_tab[0x101]; - -static BYTE cpmcart_wrap_read(WORD addr) -{ - DWORD address = ((DWORD)addr + 0x1000) & 0xffff; - return cpmcart_mem_read_tab[addr >> 8]((WORD)address); -} - -static void cpmcart_wrap_store(WORD addr, BYTE value) -{ - DWORD address = ((DWORD)addr + 0x1000) & 0xffff; - - cpmcart_mem_write_tab[addr >> 8]((WORD)address, value); -} - -static void set_read_item(int index, BYTE (*func)(WORD addr)) -{ - cpmcart_mem_read_tab[index] = func; -} - -static void set_write_item(int index, void (*func)(WORD addr, BYTE val)) +static uint8_t cpmcart_wrap_read(uint16_t addr) { - cpmcart_mem_write_tab[index] = func; + uint32_t address = ((uint32_t)addr + 0x1000) & 0xffff; + return mem_dma_read((uint16_t)address); } -static void cpmcart_mem_init(void) +static void cpmcart_wrap_store(uint16_t addr, uint8_t value) { - int i; - - /* z80 $0000-$bfff -> c64 $1000-$cfff (RAM) */ - for (i = 0; i < 0xc0; ++i) { - set_read_item(i, ram_read); - set_write_item(i, ram_store); - } - - /* z80 $c000-$c7ff -> c64 $d000-$d7ff (VICII/SID I/O) */ - set_read_item(0xc0, c64io_d000_read); - set_write_item(0xc0, c64io_d000_store); - set_read_item(0xc1, c64io_d100_read); - set_write_item(0xc1, c64io_d100_store); - set_read_item(0xc2, c64io_d200_read); - set_write_item(0xc2, c64io_d200_store); - set_read_item(0xc3, c64io_d300_read); - set_write_item(0xc3, c64io_d300_store); - set_read_item(0xc4, c64io_d400_read); - set_write_item(0xc4, c64io_d400_store); - set_read_item(0xc5, c64io_d500_read); - set_write_item(0xc5, c64io_d500_store); - set_read_item(0xc6, c64io_d600_read); - set_write_item(0xc6, c64io_d600_store); - set_read_item(0xc7, c64io_d700_read); - set_write_item(0xc7, c64io_d700_store); - - /* z80 $c800-$cbff -> c64 $d800-$dbff (VICII colorram) */ - for (i = 0xc8; i <= 0xcb; ++i) { - set_read_item(i, colorram_read); - set_write_item(i, colorram_store); - } - - /* z80 $cc00-$ccff -> c64 $dc00-$dcff (CIA1) */ - set_read_item(0xcc, cia1_read); - set_write_item(0xcc, cia1_store); - - /* z80 $cd00-$cdff -> c64 $dd00-$ddff (CIA1) */ - set_read_item(0xcd, cia2_read); - set_write_item(0xcd, cia2_store); + uint32_t address = ((uint32_t)addr + 0x1000) & 0xffff; - /* z80 $ce00-$ceff -> c64 $de00-$deff (I/O-1) */ - set_read_item(0xce, c64io_de00_read); - set_write_item(0xce, c64io_de00_store); - - /* z80 $cf00-$cfff -> c64 $df00-$dfff (I/O-2) */ - set_read_item(0xcf, c64io_df00_read); - set_write_item(0xcf, c64io_df00_store); - - /* z80 $d000-$efff -> c64 $e000-$ffff (RAM) */ - for (i = 0xd0; i < 0xf0; ++i) { - set_read_item(i, ram_read); - set_write_item(i, ram_store); - } - - /* z80 $f000-$ffff -> c64 $0000-$0fff (RAM) */ - for (i = 0xf0; i < 0x100; ++i) { - set_read_item(i, ram_read); - set_write_item(i, ram_store); - } + mem_dma_store((uint16_t)address, value); } -static void cpmcart_io_store(WORD addr, BYTE byte) +static void cpmcart_io_store(uint16_t addr, uint8_t byte) { int val = byte & 1; @@ -203,18 +94,20 @@ static int cpmcart_dump(void) } static io_source_t cpmcart_device = { - "CP/M Cartridge", - IO_DETACH_RESOURCE, - "CPMCart", - 0xde00, 0xdeff, 0xff, - 0, - cpmcart_io_store, - NULL, /* no read */ - NULL, /* no peek */ - cpmcart_dump, - CARTRIDGE_CPM, - 0, - 0 + "CP/M Cartridge", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "CPMCart", /* resource to set to '0' */ + 0xde00, 0xdeff, 0xff, /* range of the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, device is write only */ + cpmcart_io_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + cpmcart_dump, /* device state information dump function */ + CARTRIDGE_CPM, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *cpmcart_list_item = NULL; @@ -245,6 +138,16 @@ static int set_cpmcart_enabled(int value, void *param) return 0; } +int cpmcart_enable(void) +{ + return set_cpmcart_enabled(1, (void*)1); +} + +int cpmcart_disable(void) +{ + return set_cpmcart_enabled(0, (void*)1); +} + static const resource_int_t resources_int[] = { { "CPMCart", 0, RES_EVENT_STRICT, (resource_value_t)0, &cpmcart_enabled, set_cpmcart_enabled, NULL }, @@ -253,23 +156,17 @@ static const resource_int_t resources_int[] = { int cpmcart_resources_init(void) { - cpmcart_mem_init(); - return resources_register_int(resources_int); } static const cmdline_option_t cmdline_options[] = { - { "-cpmcart", SET_RESOURCE, 0, + { "-cpmcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "CPMCart", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_CPM_CART, - NULL, NULL }, - { "+cpmcart", SET_RESOURCE, 0, + NULL, "Enable the CP/M cartridge" }, + { "+cpmcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "CPMCart", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_CPM_CART, - NULL, NULL }, + NULL, "Disable the CP/M cartridge" }, CMDLINE_LIST_END }; @@ -301,13 +198,11 @@ void cpmcart_ba_register(cpmcart_ba_check_callback_t *ba_check, cpmcart_ba.enabled = 1; } +static void z80core_reset(void); + void cpmcart_reset(void) { - z80_reg_pc = 0; - z80_regs.reg_pc = 0; - iff1 = 0; - iff2 = 0; - im_mode = 0; + z80core_reset(); } #define JUMP(addr) \ @@ -315,9 +210,9 @@ void cpmcart_reset(void) z80_reg_pc = (addr); \ } while (0) -#define LOAD(addr) (cpmcart_wrap_read((WORD)(addr))) +#define LOAD(addr) (cpmcart_wrap_read((uint16_t)(addr))) -#define STORE(addr, value) (cpmcart_wrap_store((WORD)(addr), (BYTE)(value))) +#define STORE(addr, value) (cpmcart_wrap_store((uint16_t)(addr), (uint8_t)(value))) /* undefine IN and OUT first for platforms that have them already defined as something else */ #undef IN @@ -326,25 +221,6 @@ void cpmcart_reset(void) #undef OUT #define OUT(addr, value) STORE(addr, value) -#define opcode_t DWORD - -#define FETCH_OPCODE(o) ((o) = (LOAD(z80_reg_pc) \ - | (LOAD(z80_reg_pc + 1) << 8) \ - | (LOAD(z80_reg_pc + 2) << 16) \ - | (LOAD(z80_reg_pc + 3) << 24))) - -#define p0 (opcode & 0xff) -#define p1 ((opcode >> 8) & 0xff) -#define p2 ((opcode >> 16) & 0xff) -#define p3 (opcode >> 24) - -#define p12 ((opcode >> 8) & 0xffff) -#define p23 ((opcode >> 16) & 0xffff) - -#define CLK maincpu_clk - -#define INC_PC(value) (z80_reg_pc += (value)) - #ifdef Z80_4MHZ static int z80_half_cycle = 0; @@ -389,6 +265,132 @@ void cpmcart_clock_stretch(void) /* ------------------------------------------------------------------------- */ +#define Z80_SET_DMA_REQUEST(x) +#define Z80_LOOP_COND z80_started + + +//#include "z80core.c" +/// +/// +/// +/// z80core.c starts + + +/* + * z80core.c + * + * Written by + * Andreas Boose + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifdef Z80_4MHZ +#define CLK_ADD(clock, amount) clock = z80cpu_clock_add(clock, amount) +#else +#define CLK_ADD(clock, amount) clock += amount +#endif + +static uint8_t reg_a = 0; +static uint8_t reg_b = 0; +static uint8_t reg_c = 0; +static uint8_t reg_d = 0; +static uint8_t reg_e = 0; +static uint8_t reg_f = 0; +static uint8_t reg_h = 0; +static uint8_t reg_l = 0; +static uint8_t reg_ixh = 0; +static uint8_t reg_ixl = 0; +static uint8_t reg_iyh = 0; +static uint8_t reg_iyl = 0; +static uint16_t reg_sp = 0; +static uint32_t z80_reg_pc = 0; +static uint8_t reg_i = 0; +static uint8_t reg_r = 0; + +static uint8_t iff1 = 0; +static uint8_t iff2 = 0; +static uint8_t im_mode = 0; + +static uint8_t reg_a2 = 0; +static uint8_t reg_b2 = 0; +static uint8_t reg_c2 = 0; +static uint8_t reg_d2 = 0; +static uint8_t reg_e2 = 0; +static uint8_t reg_f2 = 0; +static uint8_t reg_h2 = 0; +static uint8_t reg_l2 = 0; + +static uint8_t iff1_1 = 0; +static uint8_t iff2_1 = 0; +static uint8_t iff1_2 = 0; +static uint8_t iff2_2 = 0; + +static uint8_t halt = 0; + +/* See: https://gist.github.com/drhelius/8497817 + for proper implementation of the BIT flags. + Called either memptr or WZ (reg_wz) */ +static uint16_t reg_wz = 0; + +enum INST_MODE_s { + INST_NONE, + INST_IX, + INST_IY +}; +typedef enum INST_MODE_s INST_MODE_t; +static INST_MODE_t inst_mode = INST_NONE; + +static void z80core_reset(void) +{ + z80_reg_pc = 0; + z80_regs.reg_pc = 0; + iff1 = 0; + iff2 = 0; + im_mode = 0; + iff1_1 = 0; + iff2_1 = 0; + iff1_2 = 0; + iff2_2 = 0; + halt = 0; +} + +#define opcode_t uint32_t + +#define FETCH_OPCODE(o) ((o) = (LOAD(z80_reg_pc) \ + | (LOAD(z80_reg_pc + 1) << 8) \ + | (LOAD(z80_reg_pc + 2) << 16) \ + | (LOAD(z80_reg_pc + 3) << 24))) + +#define p0 (opcode & 0xff) +#define p1 ((opcode >> 8) & 0xff) +#define p2 ((opcode >> 16) & 0xff) +#define p3 (opcode >> 24) + +#define p12 ((opcode >> 8) & 0xffff) +#define p23 ((opcode >> 16) & 0xffff) + +#define INC_PC(value) (z80_reg_pc += (value)) + +/* ------------------------------------------------------------------------- */ + static unsigned int z80_last_opcode_info; static unsigned int z80_last_opcode_addr; @@ -426,8 +428,22 @@ static unsigned int z80_last_opcode_addr; #define IX_WORD() ((reg_ixh << 8) | reg_ixl) #define IY_WORD() ((reg_iyh << 8) | reg_iyl) +/* reg_wz needs to be set whenever IX+d or XY+d is used; can't use a macro */ +static inline uint16_t IX_WORD_OFF(int8_t offset) +{ + reg_wz = IX_WORD() + (signed char)(offset); + return reg_wz; +} + +static inline uint16_t IY_WORD_OFF(int8_t offset) +{ + reg_wz = IY_WORD() + (signed char)(offset); + return reg_wz; +} +#if 0 #define IX_WORD_OFF(offset) (IX_WORD() + (signed char)(offset)) #define IY_WORD_OFF(offset) (IY_WORD() + (signed char)(offset)) +#endif #define DEC_BC_WORD() \ do { \ @@ -522,6 +538,8 @@ static unsigned int z80_last_opcode_addr; #define Z_FLAG 0x40 #define S_FLAG 0x80 +#define U35_FLAG (U3_FLAG | U5_FLAG) + #define LOCAL_SET_CARRY(val) \ do { \ if (val) { \ @@ -583,7 +601,8 @@ static unsigned int z80_last_opcode_addr; #define LOCAL_ZERO() (reg_f & Z_FLAG) #define LOCAL_SIGN() (reg_f & S_FLAG) -static const BYTE SZP[256] = { +#if 0 +static const uint8_t SZP[256] = { P_FLAG | Z_FLAG, 0, 0, P_FLAG, 0, P_FLAG, P_FLAG, 0, 0, P_FLAG, P_FLAG, 0, @@ -649,11 +668,268 @@ static const BYTE SZP[256] = { S_FLAG, S_FLAG | P_FLAG, S_FLAG | P_FLAG, S_FLAG, S_FLAG | P_FLAG, S_FLAG, S_FLAG, S_FLAG | P_FLAG }; +#endif +static const uint8_t SZP[256] = { + P_FLAG | Z_FLAG, + 0, + 0, + P_FLAG, + 0, + P_FLAG, + P_FLAG, + 0, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + 0, + P_FLAG, + P_FLAG, + 0, + P_FLAG, + 0, + 0, + P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + 0, + P_FLAG, + P_FLAG, + 0, + P_FLAG, + 0, + 0, + P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + P_FLAG, + 0, + 0, + P_FLAG, + 0, + P_FLAG, + P_FLAG, + 0, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U3_FLAG, + U3_FLAG, + U3_FLAG | P_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG, + U5_FLAG, + U5_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | P_FLAG, + U5_FLAG | U3_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + S_FLAG, + S_FLAG, + S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG | P_FLAG, + U3_FLAG | S_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG | P_FLAG, + U5_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG, + U5_FLAG | U3_FLAG | S_FLAG | P_FLAG, +}; /* ------------------------------------------------------------------------- */ -z80_regs_t z80_regs; - static void import_registers(void) { reg_a = z80_regs.reg_af >> 8; @@ -669,7 +945,7 @@ static void import_registers(void) reg_iyh = z80_regs.reg_iy >> 8; reg_iyl = z80_regs.reg_iy & 0xff; reg_sp = z80_regs.reg_sp; - z80_reg_pc = (DWORD)z80_regs.reg_pc; + z80_reg_pc = (uint32_t)z80_regs.reg_pc; reg_i = z80_regs.reg_i; reg_r = z80_regs.reg_r; reg_a2 = z80_regs.reg_af2 >> 8; @@ -691,7 +967,7 @@ static void export_registers(void) z80_regs.reg_ix = (reg_ixh << 8) | reg_ixl; z80_regs.reg_iy = (reg_iyh << 8) | reg_iyl; z80_regs.reg_sp = reg_sp; - z80_regs.reg_pc = (WORD)z80_reg_pc; + z80_regs.reg_pc = (uint16_t)z80_reg_pc; z80_regs.reg_i = reg_i; z80_regs.reg_r = reg_r; z80_regs.reg_af2 = (reg_a2 << 8) | reg_f2; @@ -704,70 +980,77 @@ static void export_registers(void) /* Interrupt handling. */ +/* FIXME: Only IM 1 is really supported; don't trust others or their timing. */ + #define DO_INTERRUPT(int_kind) \ do { \ - BYTE ik = (int_kind); \ + uint8_t ik = (int_kind); \ \ if (ik & (IK_IRQ | IK_NMI)) { \ if ((ik & IK_NMI) && 0) { \ - } else if ((ik & IK_IRQ) && iff1 && !OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) { \ - WORD jumpdst; \ + } else if ((ik & IK_IRQ) && iff1) { \ + uint16_t jumpdst; \ if (monitor_mask[e_comp_space] & (MI_STEP)) { \ monitor_check_icount_interrupt(); \ } \ - CLK_ADD(CLK, 4); \ + halt = 0; \ + CLK_ADD(CLK, 7); \ --reg_sp; \ - STORE((reg_sp), ((BYTE)(z80_reg_pc >> 8))); \ - CLK_ADD(CLK, 4); \ + STORE((reg_sp), ((uint8_t)(z80_reg_pc >> 8))); \ + CLK_ADD(CLK, 3); \ --reg_sp; \ - STORE((reg_sp), ((BYTE)(z80_reg_pc & 0xff))); \ + STORE((reg_sp), ((uint8_t)(z80_reg_pc & 0xff))); \ iff1 = 0; \ iff2 = 0; \ + iff1_1 = 0; \ + iff2_1 = 0; \ + iff1_2 = 0; \ + iff2_2 = 0; \ if (im_mode == 1) { \ jumpdst = 0x38; \ - CLK_ADD(CLK, 4); \ - JUMP(jumpdst); \ CLK_ADD(CLK, 3); \ + JUMP(jumpdst); \ } else { \ jumpdst = (LOAD(reg_i << 8) << 8); \ - CLK_ADD(CLK, 4); \ + CLK_ADD(CLK, 3); \ jumpdst |= (LOAD((reg_i << 8) + 1)); \ JUMP(jumpdst); \ - CLK_ADD(CLK, 3); \ + CLK_ADD(CLK, 6); \ } \ + interrupt_ack_irq(cpu_int_status); \ } \ } \ if (ik & (IK_TRAP | IK_RESET)) { \ if (ik & IK_TRAP) { \ export_registers(); \ - interrupt_do_trap(cpu_int_status, (WORD)z80_reg_pc); \ + interrupt_do_trap(cpu_int_status, (uint16_t)z80_reg_pc); \ import_registers(); \ if (cpu_int_status->global_pending_int & IK_RESET) { \ ik |= IK_RESET; \ } \ } \ if (ik & IK_RESET) { \ - interrupt_ack_reset(cpu_int_status); \ maincpu_reset(); \ + interrupt_ack_reset(cpu_int_status); \ } \ } \ if (ik & (IK_MONITOR)) { \ - if (monitor_force_import(e_comp_space)) { \ - import_registers(); \ - } \ - if (monitor_mask[e_comp_space]) { \ - export_registers(); \ - } \ if (monitor_mask[e_comp_space] & (MI_STEP)) { \ - monitor_check_icount((WORD)z80_reg_pc); \ + export_registers(); \ + monitor_check_icount((uint16_t)z80_reg_pc); \ + import_registers(); \ } \ if (monitor_mask[e_comp_space] & (MI_BREAK)) { \ - if (monitor_check_breakpoints(e_comp_space, (WORD)z80_reg_pc)) { \ + export_registers(); \ + if (monitor_check_breakpoints(e_comp_space, (uint16_t)z80_reg_pc)) { \ monitor_startup(e_comp_space); \ } \ + import_registers(); \ } \ if (monitor_mask[e_comp_space] & (MI_WATCH)) { \ - monitor_check_watchpoints(LAST_OPCODE_ADDR, (WORD)z80_reg_pc); \ + export_registers(); \ + monitor_check_watchpoints(LAST_OPCODE_ADDR, (uint16_t)z80_reg_pc); \ + import_registers(); \ } \ } \ } while (0) @@ -778,14 +1061,14 @@ static void export_registers(void) #define ADC(loadval, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp, carry, value; \ + uint8_t tmp, carry, value; \ \ CLK_ADD(CLK, clk_inc1); \ - value = (BYTE)(loadval); \ + value = (uint8_t)(loadval); \ carry = LOCAL_CARRY(); \ tmp = reg_a + value + carry; \ reg_f = SZP[tmp]; \ - LOCAL_SET_CARRY((WORD)((WORD)reg_a + (WORD)value + (WORD)(carry)) & 0x100); \ + LOCAL_SET_CARRY((uint16_t)((uint16_t)reg_a + (uint16_t)value + (uint16_t)(carry)) & 0x100); \ LOCAL_SET_HALFCARRY((reg_a ^ value ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY((~(reg_a ^ value)) & (reg_a ^ tmp) & 0x80); \ reg_a = tmp; \ @@ -795,49 +1078,53 @@ static void export_registers(void) #define ADCHLREG(reg_valh, reg_vall) \ do { \ - DWORD tmp, carry; \ + uint32_t tmp, carry; \ \ carry = LOCAL_CARRY(); \ - tmp = (DWORD)((reg_h << 8) + reg_l) + (DWORD)((reg_valh << 8) + reg_vall) + carry; \ + tmp = (uint32_t)((reg_h << 8) + reg_l) + (uint32_t)((reg_valh << 8) + reg_vall) + carry; \ LOCAL_SET_ZERO(!(tmp & 0xffff)); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_SIGN(tmp & 0x8000); \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY(((tmp >> 8) ^ reg_valh ^ reg_h) & H_FLAG); \ LOCAL_SET_PARITY((~(reg_h ^ reg_valh)) & (reg_valh ^ (tmp >> 8)) & 0x80); \ - reg_h = (BYTE)(tmp >> 8); \ - reg_l = (BYTE)(tmp & 0xff); \ + reg_h = (uint8_t)(tmp >> 8); \ + reg_l = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_h & U35_FLAG); \ CLK_ADD(CLK, 15); \ INC_PC(2); \ } while (0) #define ADCHLSP() \ do { \ - DWORD tmp, carry; \ + uint32_t tmp, carry; \ \ carry = LOCAL_CARRY(); \ - tmp = (DWORD)((reg_h << 8) + reg_l) + (DWORD)(reg_sp) + carry; \ + tmp = (uint32_t)((reg_h << 8) + reg_l) + (uint32_t)(reg_sp) + carry; \ + reg_wz = HL_WORD(); \ + reg_wz++; \ LOCAL_SET_ZERO(!(tmp & 0xffff)); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_SIGN(tmp & 0x8000); \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY(((tmp >> 8) ^ (reg_sp >> 8) ^ reg_h) & H_FLAG); \ LOCAL_SET_PARITY((~(reg_h ^ (reg_sp >> 8))) & ((reg_sp >> 8) ^ (tmp >> 8)) & 0x80); \ - reg_h = (BYTE)(tmp >> 8); \ - reg_l = (BYTE)(tmp & 0xff); \ + reg_h = (uint8_t)(tmp >> 8); \ + reg_l = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_h & U35_FLAG); \ CLK_ADD(CLK, 15); \ INC_PC(2); \ } while (0) #define ADD(loadval, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp, value; \ + uint8_t tmp, value; \ \ CLK_ADD(CLK, clk_inc1); \ - value = (BYTE)(loadval); \ + value = (uint8_t)(loadval); \ tmp = reg_a + value; \ reg_f = SZP[tmp]; \ - LOCAL_SET_CARRY((WORD)((WORD)reg_a + (WORD)value) & 0x100); \ + LOCAL_SET_CARRY((uint16_t)((uint16_t)reg_a + (uint16_t)value) & 0x100); \ LOCAL_SET_HALFCARRY((reg_a ^ value ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY((~(reg_a ^ value)) & (reg_a ^ tmp) & 0x80); \ reg_a = tmp; \ @@ -847,28 +1134,34 @@ static void export_registers(void) #define ADDXXREG(reg_dsth, reg_dstl, reg_valh, reg_vall, clk_inc, pc_inc) \ do { \ - DWORD tmp; \ + uint32_t tmp; \ \ - tmp = (DWORD)((reg_dsth << 8) + reg_dstl) + (DWORD)((reg_valh << 8) + reg_vall); \ + tmp = (uint32_t)((reg_dsth << 8) + reg_dstl) + (uint32_t)((reg_valh << 8) + reg_vall); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY(((tmp >> 8) ^ reg_valh ^ reg_dsth) & H_FLAG); \ - reg_dsth = (BYTE)(tmp >> 8); \ - reg_dstl = (BYTE)(tmp & 0xff); \ + reg_wz = (reg_dsth << 8) | reg_dstl; \ + reg_wz++; \ + reg_dsth = (uint8_t)(tmp >> 8); \ + reg_dstl = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_dsth & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define ADDXXSP(reg_dsth, reg_dstl, clk_inc, pc_inc) \ do { \ - DWORD tmp; \ + uint32_t tmp; \ \ - tmp = (DWORD)((reg_dsth << 8) + reg_dstl) + (DWORD)(reg_sp); \ + tmp = (uint32_t)((reg_dsth << 8) + reg_dstl) + (uint32_t)(reg_sp); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY(((tmp >> 8) ^ (reg_sp >> 8) ^ reg_dsth) & H_FLAG); \ - reg_dsth = (BYTE)(tmp >> 8); \ - reg_dstl = (BYTE)(tmp & 0xff); \ + reg_wz = (reg_dsth << 8) | reg_dstl; \ + reg_wz++; \ + reg_dsth = (uint8_t)(tmp >> 8); \ + reg_dstl = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_dsth & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) @@ -883,12 +1176,32 @@ static void export_registers(void) INC_PC(pc_inc); \ } while (0) +/* reg_wz is used here to determine F5 and F3 */ #define BIT(reg_val, value, clk_inc1, clk_inc2, pc_inc) \ do { \ + uint8_t tmp; \ + CLK_ADD(CLK, clk_inc1); \ + tmp = (reg_val) & (1 << value); \ + LOCAL_SET_NADDSUB(0); \ + LOCAL_SET_HALFCARRY(1); \ + LOCAL_SET_ZERO(!tmp); \ + LOCAL_SET_PARITY(!tmp); \ + reg_f = (reg_f & ~(S_FLAG | U35_FLAG)) | (tmp & S_FLAG) | (reg_val & U35_FLAG); \ + CLK_ADD(CLK, clk_inc2); \ + INC_PC(pc_inc); \ + } while (0) + +/* reg_wz is used here to determine F5 and F3 */ +#define BIT16(reg_val, value, clk_inc1, clk_inc2, pc_inc) \ + do { \ + uint8_t tmp; \ CLK_ADD(CLK, clk_inc1); \ + tmp = (reg_val) & (1 << value); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_HALFCARRY(1); \ - LOCAL_SET_ZERO(!((reg_val) & (1 << value))); \ + LOCAL_SET_ZERO(!tmp); \ + LOCAL_SET_PARITY(!tmp); \ + reg_f = (reg_f & ~(S_FLAG | U35_FLAG)) | (tmp & S_FLAG) | ((reg_wz >> 8) & U35_FLAG); \ CLK_ADD(CLK, clk_inc2); \ INC_PC(pc_inc); \ } while (0) @@ -900,7 +1213,7 @@ static void export_registers(void) \ dest_addr = z80_reg_pc + pc_inc + (signed char)(value); \ z80_reg_pc = dest_addr & 0xffff; \ - CLK_ADD(CLK, 7); \ + CLK_ADD(CLK, 12); \ } else { \ CLK_ADD(CLK, 7); \ INC_PC(pc_inc); \ @@ -912,10 +1225,10 @@ static void export_registers(void) INC_PC(pc_inc); \ CLK_ADD(CLK, clk_inc1); \ --reg_sp; \ - STORE((reg_sp), ((BYTE)(z80_reg_pc >> 8))); \ + STORE((reg_sp), ((uint8_t)(z80_reg_pc >> 8))); \ CLK_ADD(CLK, clk_inc2); \ --reg_sp; \ - STORE((reg_sp), ((BYTE)(z80_reg_pc & 0xff))); \ + STORE((reg_sp), ((uint8_t)(z80_reg_pc & 0xff))); \ JUMP(reg_val); \ CLK_ADD(CLK, clk_inc3); \ } while (0) @@ -930,34 +1243,42 @@ static void export_registers(void) } \ } while (0) +/* note that bits 5 and 3 are set based on previous flag and A */ +/* this passes zexall, but see: + https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags#scfccf +*/ #define CCF(clk_inc, pc_inc) \ do { \ LOCAL_SET_HALFCARRY((LOCAL_CARRY())); \ LOCAL_SET_CARRY(!(LOCAL_CARRY())); \ LOCAL_SET_NADDSUB(0); \ + reg_f = reg_f | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) +/* Bits 3 and 5 of flag based on passed value */ #define CP(loadval, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp, value; \ + uint8_t tmp, value; \ \ CLK_ADD(CLK, clk_inc1); \ - value = (BYTE)(loadval); \ + value = (uint8_t)(loadval); \ tmp = reg_a - value; \ reg_f = N_FLAG | SZP[tmp]; \ LOCAL_SET_CARRY(value > reg_a); \ LOCAL_SET_HALFCARRY((reg_a ^ value ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY((reg_a ^ value) & (reg_a ^ tmp) & 0x80); \ + reg_f = (reg_f & ~(U35_FLAG)) | (value & U35_FLAG); \ CLK_ADD(CLK, clk_inc2); \ INC_PC(pc_inc); \ } while (0) -#define CPDI(HL_FUNC) \ +#define CPDI(HL_FUNC,WZ_FUNC) \ do { \ - BYTE val, tmp; \ + uint8_t val, tmp; \ \ + WZ_FUNC; \ CLK_ADD(CLK, 4); \ val = LOAD(HL_WORD()); \ tmp = reg_a - val; \ @@ -966,26 +1287,32 @@ static void export_registers(void) reg_f = N_FLAG | SZP[tmp] | LOCAL_CARRY(); \ LOCAL_SET_HALFCARRY((reg_a ^ val ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY(reg_b | reg_c); \ - CLK_ADD(CLK, 1); \ + tmp = tmp - (LOCAL_HALFCARRY() ? 1 : 0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (tmp & U3_FLAG) | ((tmp << 4) & U5_FLAG); \ + CLK_ADD(CLK, 12); \ INC_PC(2); \ } while (0) #define CPDIR(HL_FUNC) \ do { \ - BYTE val, tmp; \ + uint8_t val, tmp; \ \ CLK_ADD(CLK, 4); \ val = LOAD(HL_WORD()); \ tmp = reg_a - val; \ HL_FUNC; \ DEC_BC_WORD(); \ - CLK_ADD(CLK, 17); \ + CLK_ADD(CLK, 12); \ + reg_wz = z80_reg_pc + 1; \ if (!(BC_WORD() && tmp)) { \ reg_f = N_FLAG | SZP[tmp] | LOCAL_CARRY(); \ LOCAL_SET_HALFCARRY((reg_a ^ val ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY(reg_b | reg_c); \ - CLK_ADD(CLK, 5); \ + tmp = tmp - (LOCAL_HALFCARRY() ? 1 : 0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (tmp & U3_FLAG) | ((tmp << 4) & U5_FLAG); \ INC_PC(2); \ + } else { \ + CLK_ADD(CLK, 5); \ } \ } while (0) @@ -994,13 +1321,14 @@ static void export_registers(void) reg_a ^= 0xff; \ LOCAL_SET_NADDSUB(1); \ LOCAL_SET_HALFCARRY(1); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define DAA(clk_inc, pc_inc) \ do { \ - WORD tmp; \ + uint16_t tmp; \ \ tmp = reg_a | (LOCAL_CARRY() ? 0x100 : 0) | (LOCAL_HALFCARRY() ? 0x200 : 0) | (LOCAL_NADDSUB() ? 0x400 : 0); \ reg_a = daa_reg_a[tmp]; \ @@ -1011,7 +1339,7 @@ static void export_registers(void) #define DECXXIND(reg_val, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((reg_val)); \ @@ -1045,11 +1373,16 @@ static void export_registers(void) #define DJNZ(value, pc_inc) \ do { \ reg_b--; \ + CLK_ADD(CLK, 1); \ BRANCH(reg_b, value, pc_inc); \ } while (0) #define DI(clk_inc, pc_inc) \ do { \ + iff1_2 = 0; \ + iff2_2 = 0; \ + iff1_1 = 0; \ + iff2_1 = 0; \ iff1 = 0; \ iff2 = 0; \ OPCODE_DISABLES_IRQ(); \ @@ -1057,18 +1390,27 @@ static void export_registers(void) INC_PC(pc_inc); \ } while (0) +/* Back to back EIs results in interrupts being delayed until one instruction after the last EI. + So we set iff1_1 and iff2_1 to 0. + See: + http://www.visual6502.org/JSSim/expert-z80.html?a=0&d=ed56fbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfb0000000000000000&a=38&d=c9&int0=48&steps=200&graphics=false +*/ + #define EI(clk_inc, pc_inc) \ do { \ - iff1 = 1; \ - iff2 = 1; \ - OPCODE_DISABLES_IRQ(); \ + iff1_2 = 1; \ + iff2_2 = 1; \ + iff1_1 = 0; \ + iff2_1 = 0; \ + OPCODE_ENABLES_IRQ(); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ + OPCODE_DELAYS_INTERRUPT();\ } while (0) #define EXAFAF(clk_inc, pc_inc) \ do { \ - BYTE tmpl, tmph; \ + uint8_t tmpl, tmph; \ \ tmph = reg_a; \ tmpl = reg_f; \ @@ -1082,7 +1424,7 @@ static void export_registers(void) #define EXX(clk_inc, pc_inc) \ do { \ - BYTE tmpl, tmph; \ + uint8_t tmpl, tmph; \ \ tmph = reg_b; \ tmpl = reg_c; \ @@ -1108,7 +1450,7 @@ static void export_registers(void) #define EXDEHL(clk_inc, pc_inc) \ do { \ - BYTE tmpl, tmph; \ + uint8_t tmpl, tmph; \ \ tmph = reg_d; \ tmpl = reg_e; \ @@ -1122,7 +1464,7 @@ static void export_registers(void) #define EXXXSP(reg_valh, reg_vall, clk_inc1, clk_inc2, clk_inc3, clk_inc4, clk_inc5, pc_inc) \ do { \ - BYTE tmpl, tmph; \ + uint8_t tmpl, tmph; \ \ tmph = reg_valh; \ tmpl = reg_vall; \ @@ -1130,6 +1472,7 @@ static void export_registers(void) reg_valh = LOAD(reg_sp + 1); \ CLK_ADD(CLK, clk_inc2); \ reg_vall = LOAD(reg_sp); \ + reg_wz = (reg_valh << 8) | reg_vall; \ CLK_ADD(CLK, clk_inc3); \ STORE((reg_sp + 1), tmph); \ CLK_ADD(CLK, clk_inc4); \ @@ -1142,6 +1485,8 @@ static void export_registers(void) #define HALT() \ do { \ CLK_ADD(CLK, 4); \ + INC_PC(1); \ + halt = 1; \ } while (0) #define IM(value) \ @@ -1153,34 +1498,52 @@ static void export_registers(void) #define INA(value, clk_inc1, clk_inc2, pc_inc) \ do { \ + uint16_t tmp; \ CLK_ADD(CLK, clk_inc1); \ - reg_a = IN((reg_a << 8) | value); \ + tmp = (reg_a << 8) | value; \ + reg_a = IN(tmp); \ CLK_ADD(CLK, clk_inc2); \ + reg_wz = tmp + 1; \ INC_PC(pc_inc); \ } while (0) +#ifdef Z80_4MHZ +#define INBC(reg_val, clk_inc1, clk_inc2, pc_inc) \ + do { \ + uint8_t tmp = z80_half_cycle; \ + CLK_ADD(CLK, (clk_inc1 + tmp) ); \ + reg_val = IN(BC_WORD()); \ + reg_f = SZP[reg_val & 0xffu] | LOCAL_CARRY(); \ + CLK_ADD(CLK, (clk_inc2 - tmp) ); \ + reg_wz = BC_WORD() + 1; \ + INC_PC(pc_inc); \ + } while (0) +#else #define INBC(reg_val, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ reg_val = IN(BC_WORD()); \ - reg_f = SZP[reg_val & 0xff] | LOCAL_CARRY(); \ + reg_f = SZP[reg_val & 0xffu] | LOCAL_CARRY(); \ CLK_ADD(CLK, clk_inc2); \ + reg_wz = BC_WORD() + 1; \ INC_PC(pc_inc); \ } while (0) +#endif #define INBC0(clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ CLK_ADD(CLK, clk_inc1); \ tmp = IN(BC_WORD()); \ reg_f = SZP[tmp] | LOCAL_CARRY(); \ CLK_ADD(CLK, clk_inc2); \ + reg_wz = BC_WORD() + 1; \ INC_PC(pc_inc); \ } while (0) #define INCXXIND(reg_val, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((reg_val)); \ @@ -1206,13 +1569,14 @@ static void export_registers(void) #define INDI(HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ tmp = IN(BC_WORD()); \ CLK_ADD(CLK, 4); \ STORE(HL_WORD(), tmp); \ HL_FUNC; \ + reg_wz = BC_WORD() + 1; \ reg_b--; \ reg_f = N_FLAG; \ LOCAL_SET_ZERO(!reg_b); \ @@ -1222,7 +1586,7 @@ static void export_registers(void) #define INDIR(HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ tmp = IN(BC_WORD()); \ @@ -1230,11 +1594,13 @@ static void export_registers(void) STORE(HL_WORD(), tmp); \ HL_FUNC; \ reg_b--; \ + reg_wz = z80_reg_pc + 1; \ if (!reg_b) { \ CLK_ADD(CLK, 4); \ reg_f = N_FLAG | Z_FLAG; \ INC_PC(2); \ } else { \ + CLK_ADD(CLK, 9); \ reg_f = N_FLAG; \ } \ CLK_ADD(CLK, 4); \ @@ -1268,7 +1634,7 @@ static void export_registers(void) #define LDDI(DE_FUNC, HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ tmp = LOAD(HL_WORD()); \ @@ -1280,13 +1646,15 @@ static void export_registers(void) LOCAL_SET_NADDSUB(0); \ LOCAL_SET_PARITY(reg_b | reg_c); \ LOCAL_SET_HALFCARRY(0); \ - CLK_ADD(CLK, 12); \ + tmp = tmp + reg_a; \ + reg_f = (reg_f & ~(U35_FLAG)) | (tmp & U3_FLAG) | ((tmp << 4) & U5_FLAG); \ + CLK_ADD(CLK, 8); \ INC_PC(2); \ } while (0) #define LDDIR(DE_FUNC, HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ tmp = LOAD(HL_WORD()); \ @@ -1295,13 +1663,17 @@ static void export_registers(void) DEC_BC_WORD(); \ DE_FUNC; \ HL_FUNC; \ - CLK_ADD(CLK, 13); \ + CLK_ADD(CLK, 8); \ + reg_wz = z80_reg_pc + 1; \ if (!(BC_WORD())) { \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_PARITY(0); \ LOCAL_SET_HALFCARRY(0); \ - CLK_ADD(CLK, 5); \ + tmp = tmp + reg_a; \ + reg_f = (reg_f & ~(U35_FLAG)) | (tmp & U3_FLAG) | ((tmp << 4) & U5_FLAG); \ INC_PC(2); \ + } else { \ + CLK_ADD(CLK, 5); \ } \ } while (0) @@ -1312,13 +1684,14 @@ static void export_registers(void) CLK_ADD(CLK, clk_inc2); \ reg_valh = LOAD((val) + 1); \ CLK_ADD(CLK, clk_inc3); \ + reg_wz = (val) + 1; \ INC_PC(pc_inc); \ } while (0) #define LDSP(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ - reg_sp = (WORD)(value); \ + reg_sp = (uint16_t)(value); \ CLK_ADD(CLK, clk_inc2); \ INC_PC(pc_inc); \ } while (0) @@ -1329,33 +1702,46 @@ static void export_registers(void) reg_sp = LOAD(value); \ CLK_ADD(CLK, clk_inc2); \ reg_sp |= LOAD(value + 1) << 8; \ + reg_wz = value + 1; \ CLK_ADD(CLK, clk_inc3); \ INC_PC(pc_inc); \ } while (0) #define LDREG(reg_dest, value, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ + \ + CLK_ADD(CLK, clk_inc1); \ + tmp = (uint8_t)(value); \ + reg_dest = tmp; \ + CLK_ADD(CLK, clk_inc2); \ + INC_PC(pc_inc); \ + } while (0) + +#define LDREGWZ(reg_dest, addr, clk_inc1, clk_inc2, pc_inc) \ + do { \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ - tmp = (BYTE)(value); \ + tmp = (uint8_t)(LOAD(addr)); \ reg_dest = tmp; \ CLK_ADD(CLK, clk_inc2); \ + reg_wz = addr + 1; \ INC_PC(pc_inc); \ } while (0) #define LDW(value, reg_valh, reg_vall, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ - reg_vall = (BYTE)((value) & 0xff); \ - reg_valh = (BYTE)((value) >> 8); \ + reg_vall = (uint8_t)((value) & 0xff); \ + reg_valh = (uint8_t)((value) >> 8); \ CLK_ADD(CLK, clk_inc2); \ INC_PC(pc_inc); \ } while (0) #define NEG() \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ tmp = 0 - reg_a; \ reg_f = N_FLAG | SZP[tmp]; \ @@ -1390,48 +1776,64 @@ static void export_registers(void) INC_PC(pc_inc); \ } while (0) +#ifdef Z80_4MHZ +#define OUTBC(value, clk_inc1, clk_inc2, pc_inc) \ + do { \ + uint8_t tmp = z80_half_cycle; \ + CLK_ADD(CLK, (clk_inc1 + tmp) ); \ + OUT(BC_WORD(), value); \ + CLK_ADD(CLK, (clk_inc2 - tmp) ); \ + reg_wz = BC_WORD() + 1; \ + INC_PC(pc_inc); \ + } while (0) +#else #define OUTBC(value, clk_inc1, clk_inc2, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ OUT(BC_WORD(), value); \ CLK_ADD(CLK, clk_inc2); \ + reg_wz = BC_WORD() + 1; \ INC_PC(pc_inc); \ } while (0) +#endif #define OUTDI(HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ + reg_b--; \ + reg_wz = BC_WORD() + 1; \ tmp = LOAD(HL_WORD()); \ CLK_ADD(CLK, 4); \ OUT(BC_WORD(), tmp); \ HL_FUNC; \ - reg_b--; \ reg_f = N_FLAG; \ LOCAL_SET_ZERO(!reg_b); \ CLK_ADD(CLK, 4); \ + CLK_ADD(CLK, 4); \ INC_PC(2); \ } while (0) #define OTDIR(HL_FUNC) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, 4); \ + reg_b--; \ tmp = LOAD(HL_WORD()); \ CLK_ADD(CLK, 4); \ OUT(BC_WORD(), tmp); \ HL_FUNC; \ - reg_b--; \ + reg_wz = z80_reg_pc + 1; \ if (!reg_b) { \ - CLK_ADD(CLK, 4); \ reg_f = N_FLAG | Z_FLAG; \ INC_PC(2); \ } else { \ reg_f = N_FLAG; \ + CLK_ADD(CLK, 5); \ } \ - CLK_ADD(CLK, 4); \ + CLK_ADD(CLK, 8); \ } while (0) #define POP(reg_valh, reg_vall, pc_inc) \ @@ -1467,7 +1869,7 @@ static void export_registers(void) #define RESXX(value, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1480,7 +1882,7 @@ static void export_registers(void) #define RESXXREG(value, reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1494,7 +1896,7 @@ static void export_registers(void) #define RET(clk_inc1, clk_inc2, clk_inc3) \ do { \ - WORD tmp; \ + uint16_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD(reg_sp); \ @@ -1517,7 +1919,7 @@ static void export_registers(void) #define RETNI() \ do { \ - WORD tmp; \ + uint16_t tmp; \ \ CLK_ADD(CLK, 4); \ tmp = LOAD(reg_sp); \ @@ -1526,12 +1928,12 @@ static void export_registers(void) reg_sp += 2; \ iff1 = iff2; \ JUMP(tmp); \ - CLK_ADD(CLK, 2); \ + CLK_ADD(CLK, 6); \ } while (0) #define RL(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_val & 0x80) ? C_FLAG : 0; \ reg_val = (reg_val << 1) | LOCAL_CARRY(); \ @@ -1542,20 +1944,21 @@ static void export_registers(void) #define RLA(clk_inc, pc_inc) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_a & 0x80) ? C_FLAG : 0; \ reg_a = (reg_a << 1) | LOCAL_CARRY(); \ LOCAL_SET_CARRY(rot); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_HALFCARRY(0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define RLC(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_val & 0x80) ? C_FLAG : 0; \ reg_val = (reg_val << 1) | rot; \ @@ -1566,20 +1969,21 @@ static void export_registers(void) #define RLCA(clk_inc, pc_inc) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_a & 0x80) ? C_FLAG : 0; \ reg_a = (reg_a << 1) | rot; \ LOCAL_SET_CARRY(rot); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_HALFCARRY(0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define RLCXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1594,7 +1998,7 @@ static void export_registers(void) #define RLCXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1610,9 +2014,11 @@ static void export_registers(void) #define RLD() \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ - tmp = LOAD(HL_WORD()); \ + reg_wz = HL_WORD(); \ + tmp = LOAD(reg_wz); \ + reg_wz++; \ CLK_ADD(CLK, 8); \ STORE(HL_WORD(), (tmp << 4) | (reg_a & 0x0f)); \ reg_a = (tmp >> 4) | (reg_a & 0xf0); \ @@ -1623,7 +2029,7 @@ static void export_registers(void) #define RLXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1638,7 +2044,7 @@ static void export_registers(void) #define RLXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1654,7 +2060,7 @@ static void export_registers(void) #define RR(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_val & C_FLAG; \ reg_val = (reg_val >> 1) | (LOCAL_CARRY() ? 0x80 : 0); \ @@ -1665,20 +2071,21 @@ static void export_registers(void) #define RRA(clk_inc, pc_inc) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_a & C_FLAG; \ reg_a = (reg_a >> 1) | (LOCAL_CARRY() ? 0x80 : 0); \ LOCAL_SET_CARRY(rot); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_HALFCARRY(0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define RRC(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_val & C_FLAG; \ reg_val = (reg_val >> 1) | ((rot) ? 0x80 : 0); \ @@ -1689,20 +2096,21 @@ static void export_registers(void) #define RRCA(clk_inc, pc_inc) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_a & C_FLAG; \ reg_a = (reg_a >> 1) | ((rot) ? 0x80 : 0); \ LOCAL_SET_CARRY(rot); \ LOCAL_SET_NADDSUB(0); \ LOCAL_SET_HALFCARRY(0); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) #define RRCXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1717,7 +2125,7 @@ static void export_registers(void) #define RRCXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1733,9 +2141,11 @@ static void export_registers(void) #define RRD() \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ - tmp = LOAD(HL_WORD()); \ + reg_wz = HL_WORD(); \ + tmp = LOAD(reg_wz); \ + reg_wz++; \ CLK_ADD(CLK, 8); \ STORE(HL_WORD(), (tmp >> 4) | (reg_a << 4)); \ reg_a = (tmp & 0x0f) | (reg_a & 0xf0); \ @@ -1746,7 +2156,7 @@ static void export_registers(void) #define RRXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1761,7 +2171,7 @@ static void export_registers(void) #define RRXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1777,64 +2187,73 @@ static void export_registers(void) #define SBCHLREG(reg_valh, reg_vall) \ do { \ - DWORD tmp; \ - BYTE carry; \ + uint32_t tmp; \ + uint8_t carry; \ \ carry = LOCAL_CARRY(); \ - tmp = (DWORD)(HL_WORD()) - (DWORD)((reg_valh << 8) + reg_vall) - (DWORD)(carry); \ + tmp = (uint32_t)(HL_WORD()) - (uint32_t)((reg_valh << 8) + reg_vall) - (uint32_t)(carry); \ + reg_wz = HL_WORD(); \ + reg_wz++; \ reg_f = N_FLAG; \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY((reg_h ^ reg_valh ^ (tmp >> 8)) & H_FLAG); \ LOCAL_SET_PARITY(((reg_h ^ (tmp >> 8)) & (reg_h ^ reg_valh)) & 0x80); \ LOCAL_SET_ZERO(!(tmp & 0xffff)); \ LOCAL_SET_SIGN(tmp & 0x8000); \ - reg_h = (BYTE)(tmp >> 8); \ - reg_l = (BYTE)(tmp & 0xff); \ + reg_h = (uint8_t)(tmp >> 8); \ + reg_l = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_h & U35_FLAG); \ CLK_ADD(CLK, 15); \ INC_PC(2); \ } while (0) #define SBCHLSP() \ do { \ - DWORD tmp; \ - BYTE carry; \ + uint32_t tmp; \ + uint8_t carry; \ \ carry = LOCAL_CARRY(); \ - tmp = (DWORD)(HL_WORD()) - (DWORD)reg_sp - (DWORD)(carry); \ + tmp = (uint32_t)(HL_WORD()) - (uint32_t)reg_sp - (uint32_t)(carry); \ reg_f = N_FLAG; \ LOCAL_SET_CARRY(tmp & 0x10000); \ LOCAL_SET_HALFCARRY((reg_h ^ (reg_sp >> 8) ^ (tmp >> 8)) & H_FLAG); \ LOCAL_SET_PARITY(((reg_h ^ (tmp >> 8)) & (reg_h ^ (reg_sp >> 8))) & 0x80); \ LOCAL_SET_ZERO(!(tmp & 0xffff)); \ LOCAL_SET_SIGN(tmp & 0x8000); \ - reg_h = (BYTE)(tmp >> 8); \ - reg_l = (BYTE)(tmp & 0xff); \ + reg_h = (uint8_t)(tmp >> 8); \ + reg_l = (uint8_t)(tmp & 0xff); \ + reg_f = (reg_f & ~(U35_FLAG)) | (reg_h & U35_FLAG); \ CLK_ADD(CLK, 15); \ INC_PC(2); \ } while (0) #define SBC(loadval, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp, carry, value; \ + uint8_t tmp, carry, value; \ \ CLK_ADD(CLK, clk_inc1); \ - value = (BYTE)(loadval); \ + value = (uint8_t)(loadval); \ carry = LOCAL_CARRY(); \ tmp = reg_a - value - carry; \ reg_f = N_FLAG | SZP[tmp]; \ LOCAL_SET_HALFCARRY((reg_a ^ value ^ tmp) & H_FLAG); \ LOCAL_SET_PARITY((reg_a ^ value) & (reg_a ^ tmp) & 0x80); \ - LOCAL_SET_CARRY((WORD)((WORD)value + (WORD)(carry)) > reg_a); \ + LOCAL_SET_CARRY((uint16_t)((uint16_t)value + (uint16_t)(carry)) > reg_a); \ reg_a = tmp; \ CLK_ADD(CLK, clk_inc2); \ INC_PC(pc_inc); \ } while (0) +/* note that bits 5 and 3 are set based on previous flag and A */ +/* this passes zexall, but see: + https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags#scfccf +*/ #define SCF(clk_inc, pc_inc) \ do { \ LOCAL_SET_CARRY(1); \ LOCAL_SET_HALFCARRY(0); \ LOCAL_SET_NADDSUB(0); \ + reg_f = reg_f | (reg_a & U35_FLAG); \ CLK_ADD(CLK, clk_inc); \ INC_PC(pc_inc); \ } while (0) @@ -1848,7 +2267,7 @@ static void export_registers(void) #define SETXX(value, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1861,7 +2280,7 @@ static void export_registers(void) #define SETXXREG(value, reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE tmp; \ + uint8_t tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1875,7 +2294,7 @@ static void export_registers(void) #define SLA(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_val & 0x80) ? C_FLAG : 0; \ reg_val <<= 1; \ @@ -1886,7 +2305,7 @@ static void export_registers(void) #define SLAXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1901,7 +2320,7 @@ static void export_registers(void) #define SLAXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1917,7 +2336,7 @@ static void export_registers(void) #define SLL(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = (reg_val & 0x80) ? C_FLAG : 0; \ reg_val = (reg_val << 1) | 1; \ @@ -1928,7 +2347,7 @@ static void export_registers(void) #define SLLXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1943,7 +2362,7 @@ static void export_registers(void) #define SLLXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1959,7 +2378,7 @@ static void export_registers(void) #define SRA(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_val & C_FLAG; \ reg_val = (reg_val >> 1) | (reg_val & 0x80); \ @@ -1970,7 +2389,7 @@ static void export_registers(void) #define SRAXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -1985,7 +2404,7 @@ static void export_registers(void) #define SRAXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -2001,7 +2420,7 @@ static void export_registers(void) #define SRL(reg_val) \ do { \ - BYTE rot; \ + uint8_t rot; \ \ rot = reg_val & C_FLAG; \ reg_val >>= 1; \ @@ -2012,7 +2431,7 @@ static void export_registers(void) #define SRLXX(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -2027,7 +2446,7 @@ static void export_registers(void) #define SRLXXREG(reg_val, addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ - BYTE rot, tmp; \ + uint8_t rot, tmp; \ \ CLK_ADD(CLK, clk_inc1); \ tmp = LOAD((addr)); \ @@ -2044,20 +2463,22 @@ static void export_registers(void) #define STW(addr, reg_valh, reg_vall, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ - STORE((WORD)(addr), reg_vall); \ + STORE((uint16_t)(addr), reg_vall); \ CLK_ADD(CLK, clk_inc2); \ - STORE((WORD)(addr + 1), reg_valh); \ + STORE((uint16_t)(addr + 1), reg_valh); \ CLK_ADD(CLK, clk_inc3); \ + reg_wz = addr + 1; \ INC_PC(pc_inc); \ } while (0) #define STSPW(addr, clk_inc1, clk_inc2, clk_inc3, pc_inc) \ do { \ CLK_ADD(CLK, clk_inc1); \ - STORE((WORD)(addr), (reg_sp & 0xff)); \ + STORE((uint16_t)(addr), (reg_sp & 0xff)); \ CLK_ADD(CLK, clk_inc2); \ - STORE((WORD)(addr + 1), (reg_sp >> 8)); \ + STORE((uint16_t)(addr + 1), (reg_sp >> 8)); \ CLK_ADD(CLK, clk_inc3); \ + reg_wz = addr + 1; \ INC_PC(pc_inc); \ } while (0) @@ -2069,12 +2490,21 @@ static void export_registers(void) INC_PC(pc_inc); \ } while (0) +#define STREGWZ(addr, reg_val, clk_inc1, clk_inc2, pc_inc) \ + do { \ + CLK_ADD(CLK, clk_inc1); \ + STORE(addr, reg_val); \ + CLK_ADD(CLK, clk_inc2); \ + reg_wz = ((addr + 1) & 0xff) | (reg_val << 8); \ + INC_PC(pc_inc); \ + } while (0) + #define SUB(loadval, clk_inc1, clk_inc2, pc_inc) \ do { \ - BYTE tmp, value; \ + uint8_t tmp, value; \ \ CLK_ADD(CLK, clk_inc1); \ - value = (BYTE)(loadval); \ + value = (uint8_t)(loadval); \ tmp = reg_a - value; \ reg_f = N_FLAG | SZP[tmp]; \ LOCAL_SET_HALFCARRY((reg_a ^ value ^ tmp) & H_FLAG); \ @@ -2099,7 +2529,7 @@ static void export_registers(void) /* Extended opcodes. */ -static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) +static void opcode_cb(uint8_t ip1, uint8_t ip2, uint8_t ip3, uint16_t ip12, uint16_t ip23) { switch (ip1) { case 0x00: /* RLC B */ @@ -2313,7 +2743,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 0, 0, 8, 2); break; case 0x46: /* BIT (HL) 0 */ - BIT(LOAD(HL_WORD()), 0, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 0, 4, 8, 2); break; case 0x47: /* BIT A 0 */ BIT(reg_a, 0, 0, 8, 2); @@ -2337,7 +2767,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 1, 0, 8, 2); break; case 0x4e: /* BIT (HL) 1 */ - BIT(LOAD(HL_WORD()), 1, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 1, 4, 8, 2); break; case 0x4f: /* BIT A 1 */ BIT(reg_a, 1, 0, 8, 2); @@ -2361,7 +2791,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 2, 0, 8, 2); break; case 0x56: /* BIT (HL) 2 */ - BIT(LOAD(HL_WORD()), 2, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 2, 4, 8, 2); break; case 0x57: /* BIT A 2 */ BIT(reg_a, 2, 0, 8, 2); @@ -2385,7 +2815,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 3, 0, 8, 2); break; case 0x5e: /* BIT (HL) 3 */ - BIT(LOAD(HL_WORD()), 3, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 3, 4, 8, 2); break; case 0x5f: /* BIT A 3 */ BIT(reg_a, 3, 0, 8, 2); @@ -2409,7 +2839,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 4, 0, 8, 2); break; case 0x66: /* BIT (HL) 4 */ - BIT(LOAD(HL_WORD()), 4, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 4, 4, 8, 2); break; case 0x67: /* BIT A 4 */ BIT(reg_a, 4, 0, 8, 2); @@ -2433,7 +2863,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 5, 0, 8, 2); break; case 0x6e: /* BIT (HL) 5 */ - BIT(LOAD(HL_WORD()), 5, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 5, 4, 8, 2); break; case 0x6f: /* BIT A 5 */ BIT(reg_a, 5, 0, 8, 2); @@ -2457,7 +2887,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 6, 0, 8, 2); break; case 0x76: /* BIT (HL) 6 */ - BIT(LOAD(HL_WORD()), 6, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 6, 4, 8, 2); break; case 0x77: /* BIT A 6 */ BIT(reg_a, 6, 0, 8, 2); @@ -2481,7 +2911,7 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) BIT(reg_l, 7, 0, 8, 2); break; case 0x7e: /* BIT (HL) 7 */ - BIT(LOAD(HL_WORD()), 7, 4, 8, 2); + BIT16(LOAD(HL_WORD()), 7, 4, 8, 2); break; case 0x7f: /* BIT A 7 */ BIT(reg_a, 7, 0, 8, 2); @@ -2875,202 +3305,243 @@ static void opcode_cb(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) } } -static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) +#undef INSTS +#define INSTS(IX,IY) \ + do { \ + switch (inst_mode) { \ + case INST_IX: \ + IX; \ + break; \ + case INST_IY: \ + IY; \ + break; \ + default: \ + break; \ + } \ + } while (0) + +#define INSTS_SH(func, XY, cyc, inc) \ + INSTS(func(IX_##XY, 0, 0, cyc, inc), \ + func(IY_##XY, 0, 0, cyc, inc)); + +#define INSTS_SHREG(func, reg, XY, cyc, inc) \ + INSTS(func(reg, IX_##XY, 0, 0, cyc, inc), \ + func(reg, IY_##XY, 0 ,0, cyc, inc)); + +#define INSTS_RS(func, bit, XY, cyc, inc) \ + INSTS(func(bit, IX_##XY, 0, 0, cyc, inc), \ + func(bit, IY_##XY, 0, 0, cyc, inc)); + +#define INSTS_RSREG(func, bit, reg, XY, cyc, inc) \ + INSTS(func(bit, reg, IX_##XY, 0, 0, cyc, inc), \ + func(bit, reg, IY_##XY, 0, 0, cyc, inc)); + +#define INSTS_BIT(XY, bit, cyc, inc) \ + INSTS(BIT16(LOAD(IX_##XY), bit, 0, cyc, inc), \ + BIT16(LOAD(IY_##XY), bit, 0, cyc, inc)); + +/* use macros to reduce source code and make this more managable. */ +/* "Ir" is either IX or IY. The macros above do the code expansion to + handle both the IX and IY cases. */ +static void opcode_ddfd_cb(uint8_t iip2, uint8_t iip3, uint16_t iip23) { + /* effecitively read 0xcb */ + CLK_ADD(CLK, 4); + INC_PC(1); switch (iip3) { - case 0x00: /* RLC (IX+d),B */ - RLCXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x00: /* RLC (Ir+d),B */ + INSTS_SHREG(RLCXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x01: /* RLC (IX+d),C */ - RLCXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x01: /* RLC (Ir+d),C */ + INSTS_SHREG(RLCXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x02: /* RLC (IX+d),D */ - RLCXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x02: /* RLC (Ir+d),D */ + INSTS_SHREG(RLCXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x03: /* RLC (IX+d),E */ - RLCXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x03: /* RLC (Ir+d),E */ + INSTS_SHREG(RLCXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x04: /* RLC (IX+d),H */ - RLCXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x04: /* RLC (Ir+d),H */ + INSTS_SHREG(RLCXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x05: /* RLC (IX+d),L */ - RLCXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x05: /* RLC (Ir+d),L */ + INSTS_SHREG(RLCXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x06: /* RLC (IX+d) */ - RLCXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x06: /* RLC (Ir+d) */ + INSTS_SH(RLCXX, WORD_OFF(iip2), 15, 2); break; - case 0x07: /* RLC (IX+d),A */ - RLCXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x07: /* RLC (Ir+d),A */ + INSTS_SHREG(RLCXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x08: /* RRC (IX+d),B */ - RRCXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x08: /* RRC (Ir+d),B */ + INSTS_SHREG(RRCXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x09: /* RRC (IX+d),C */ - RRCXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x09: /* RRC (Ir+d),C */ + INSTS_SHREG(RRCXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x0a: /* RRC (IX+d),D */ - RRCXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0a: /* RRC (Ir+d),D */ + INSTS_SHREG(RRCXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x0b: /* RRC (IX+d),E */ - RRCXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0b: /* RRC (Ir+d),E */ + INSTS_SHREG(RRCXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x0c: /* RRC (IX+d),H */ - RRCXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0c: /* RRC (Ir+d),H */ + INSTS_SHREG(RRCXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x0d: /* RRC (IX+d),L */ - RRCXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0d: /* RRC (Ir+d),L */ + INSTS_SHREG(RRCXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x0e: /* RRC (IX+d) */ - RRCXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0e: /* RRC (Ir+d) */ + INSTS_SH(RRCXX, WORD_OFF(iip2), 15, 2); break; - case 0x0f: /* RRC (IX+d),A */ - RRCXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x0f: /* RRC (Ir+d),A */ + INSTS_SHREG(RRCXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x10: /* RL (IX+d),B */ - RLXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x10: /* RL (Ir+d),B */ + INSTS_SHREG(RLXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x11: /* RL (IX+d),C */ - RLXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x11: /* RL (Ir+d),C */ + INSTS_SHREG(RLXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x12: /* RL (IX+d),D */ - RLXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x12: /* RL (Ir+d),D */ + INSTS_SHREG(RLXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x13: /* RL (IX+d),E */ - RLXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x13: /* RL (Ir+d),E */ + INSTS_SHREG(RLXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x14: /* RL (IX+d),H */ - RLXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x14: /* RL (Ir+d),H */ + INSTS_SHREG(RLXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x15: /* RL (IX+d),L */ - RLXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x15: /* RL (Ir+d),L */ + INSTS_SHREG(RLXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x16: /* RL (IX+d) */ - RLXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x16: /* RL (Ir+d) */ + INSTS_SH(RLXX, WORD_OFF(iip2), 15, 2); break; - case 0x17: /* RL (IX+d),A */ - RLXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x17: /* RL (Ir+d),A */ + INSTS_SHREG(RLXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x18: /* RR (IX+d),B */ - RRXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x18: /* RR (Ir+d),B */ + INSTS_SHREG(RRXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x19: /* RR (IX+d),C */ - RRXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x19: /* RR (Ir+d),C */ + INSTS_SHREG(RRXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x1a: /* RR (IX+d),D */ - RRXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1a: /* RR (Ir+d),D */ + INSTS_SHREG(RRXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x1b: /* RR (IX+d),E */ - RRXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1b: /* RR (Ir+d),E */ + INSTS_SHREG(RRXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x1c: /* RR (IX+d),H */ - RRXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1c: /* RR (Ir+d),H */ + INSTS_SHREG(RRXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x1d: /* RR (IX+d),L */ - RRXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1d: /* RR (Ir+d),L */ + INSTS_SHREG(RRXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x1e: /* RR (IX+d) */ - RRXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1e: /* RR (Ir+d) */ + INSTS_SH(RRXX, WORD_OFF(iip2), 15, 2); break; - case 0x1f: /* RR (IX+d),A */ - RRXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x1f: /* RR (Ir+d),A */ + INSTS_SHREG(RRXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x20: /* SLA (IX+d),B */ - SLAXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x20: /* SLA (Ir+d),B */ + INSTS_SHREG(SLAXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x21: /* SLA (IX+d),C */ - SLAXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x21: /* SLA (Ir+d),C */ + INSTS_SHREG(SLAXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x22: /* SLA (IX+d),D */ - SLAXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x22: /* SLA (Ir+d),D */ + INSTS_SHREG(SLAXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x23: /* SLA (IX+d),E */ - SLAXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x23: /* SLA (Ir+d),E */ + INSTS_SHREG(SLAXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x24: /* SLA (IX+d),H */ - SLAXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x24: /* SLA (Ir+d),H */ + INSTS_SHREG(SLAXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x25: /* SLA (IX+d),L */ - SLAXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x25: /* SLA (Ir+d),L */ + INSTS_SHREG(SLAXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x26: /* SLA (IX+d) */ - SLAXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x26: /* SLA (Ir+d) */ + INSTS_SH(SLAXX, WORD_OFF(iip2), 15, 2); break; - case 0x27: /* SLA (IX+d),A */ - SLAXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x27: /* SLA (Ir+d),A */ + INSTS_SHREG(SLAXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x28: /* SRA (IX+d),B */ - SRAXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x28: /* SRA (Ir+d),B */ + INSTS_SHREG(SRAXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x29: /* SRA (IX+d),C */ - SRAXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x29: /* SRA (Ir+d),C */ + INSTS_SHREG(SRAXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x2a: /* SRA (IX+d),D */ - SRAXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2a: /* SRA (Ir+d),D */ + INSTS_SHREG(SRAXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x2b: /* SRA (IX+d),E */ - SRAXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2b: /* SRA (Ir+d),E */ + INSTS_SHREG(SRAXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x2c: /* SRA (IX+d),H */ - SRAXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2c: /* SRA (Ir+d),H */ + INSTS_SHREG(SRAXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x2d: /* SRA (IX+d),L */ - SRAXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2d: /* SRA (Ir+d),L */ + INSTS_SHREG(SRAXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x2e: /* SRA (IX+d) */ - SRAXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2e: /* SRA (Ir+d) */ + INSTS_SH(SRAXX, WORD_OFF(iip2), 15, 2); break; - case 0x2f: /* SRA (IX+d),A */ - SRAXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x2f: /* SRA (Ir+d),A */ + INSTS_SHREG(SRAXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x30: /* SLL (IX+d),B */ - SLLXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x30: /* SLL (Ir+d),B */ + INSTS_SHREG(SLLXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x31: /* SLL (IX+d),C */ - SLLXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x31: /* SLL (Ir+d),C */ + INSTS_SHREG(SLLXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x32: /* SLL (IX+d),D */ - SLLXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x32: /* SLL (Ir+d),D */ + INSTS_SHREG(SLLXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x33: /* SLL (IX+d),E */ - SLLXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x33: /* SLL (Ir+d),E */ + INSTS_SHREG(SLLXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x34: /* SLL (IX+d),H */ - SLLXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x34: /* SLL (Ir+d),H */ + INSTS_SHREG(SLLXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x35: /* SLL (IX+d),L */ - SLLXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x35: /* SLL (Ir+d),L */ + INSTS_SHREG(SLLXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x36: /* SLL (IX+d) */ - SLLXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x36: /* SLL (Ir+d) */ + INSTS_SH(SLLXX, WORD_OFF(iip2), 15, 2); break; - case 0x37: /* SLL (IX+d),A */ - SLLXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x37: /* SLL (Ir+d),A */ + INSTS_SHREG(SLLXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x38: /* SRL (IX+d),B */ - SRLXXREG(reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x38: /* SRL (Ir+d),B */ + INSTS_SHREG(SRLXXREG, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x39: /* SRL (IX+d),C */ - SRLXXREG(reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x39: /* SRL (Ir+d),C */ + INSTS_SHREG(SRLXXREG, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x3a: /* SRL (IX+d),D */ - SRLXXREG(reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3a: /* SRL (Ir+d),D */ + INSTS_SHREG(SRLXXREG, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x3b: /* SRL (IX+d),E */ - SRLXXREG(reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3b: /* SRL (Ir+d),E */ + INSTS_SHREG(SRLXXREG, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x3c: /* SRL (IX+d),H */ - SRLXXREG(reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3c: /* SRL (Ir+d),H */ + INSTS_SHREG(SRLXXREG, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x3d: /* SRL (IX+d),L */ - SRLXXREG(reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3d: /* SRL (Ir+d),L */ + INSTS_SHREG(SRLXXREG, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x3e: /* SRL (IX+d) */ - SRLXX(IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3e: /* SRL (Ir+d) */ + INSTS_SH(SRLXX, WORD_OFF(iip2), 15, 2); break; - case 0x3f: /* SRL (IX+d),A */ - SRLXXREG(reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x3f: /* SRL (Ir+d),A */ + INSTS_SHREG(SRLXXREG, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x40: /* BIT (IX+d) 0 */ + case 0x40: /* BIT (Ir+d) 0 */ case 0x41: case 0x42: case 0x43: @@ -3078,9 +3549,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x45: case 0x46: case 0x47: - BIT(LOAD(IX_WORD_OFF(iip2)), 0, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 0, 12, 2); break; - case 0x48: /* BIT (IX+d) 1 */ + case 0x48: /* BIT (Ir+d) 1 */ case 0x49: case 0x4a: case 0x4b: @@ -3088,9 +3559,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x4d: case 0x4e: case 0x4f: - BIT(LOAD(IX_WORD_OFF(iip2)), 1, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 1, 12, 2); break; - case 0x50: /* BIT (IX+d) 2 */ + case 0x50: /* BIT (Ir+d) 2 */ case 0x51: case 0x52: case 0x53: @@ -3098,9 +3569,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x55: case 0x56: case 0x57: - BIT(LOAD(IX_WORD_OFF(iip2)), 2, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 2, 12, 2); break; - case 0x58: /* BIT (IX+d) 3 */ + case 0x58: /* BIT (Ir+d) 3 */ case 0x59: case 0x5a: case 0x5b: @@ -3108,9 +3579,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x5d: case 0x5e: case 0x5f: - BIT(LOAD(IX_WORD_OFF(iip2)), 3, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 3, 12, 2); break; - case 0x60: /* BIT (IX+d) 4 */ + case 0x60: /* BIT (Ir+d) 4 */ case 0x61: case 0x62: case 0x63: @@ -3118,9 +3589,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x65: case 0x66: case 0x67: - BIT(LOAD(IX_WORD_OFF(iip2)), 4, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 4, 12, 2); break; - case 0x68: /* BIT (IX+d) 5 */ + case 0x68: /* BIT (Ir+d) 5 */ case 0x69: case 0x6a: case 0x6b: @@ -3128,9 +3599,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x6d: case 0x6e: case 0x6f: - BIT(LOAD(IX_WORD_OFF(iip2)), 5, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 5, 12, 2); break; - case 0x70: /* BIT (IX+d) 6 */ + case 0x70: /* BIT (Ir+d) 6 */ case 0x71: case 0x72: case 0x73: @@ -3138,9 +3609,9 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x75: case 0x76: case 0x77: - BIT(LOAD(IX_WORD_OFF(iip2)), 6, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 6, 12, 2); break; - case 0x78: /* BIT (IX+d) 7 */ + case 0x78: /* BIT (Ir+d) 7 */ case 0x79: case 0x7a: case 0x7b: @@ -3148,2574 +3619,697 @@ static void opcode_dd_cb(BYTE iip2, BYTE iip3, WORD iip23) case 0x7d: case 0x7e: case 0x7f: - BIT(LOAD(IX_WORD_OFF(iip2)), 7, 8, 12, 4); + INSTS_BIT(WORD_OFF(iip2), 7, 12, 2); break; - case 0x80: /* RES (IX+d),B 0 */ - RESXXREG(0, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x80: /* RES (Ir+d),B 0 */ + INSTS_RSREG(RESXXREG, 0, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x81: /* RES (IX+d),C 0 */ - RESXXREG(0, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x81: /* RES (Ir+d),C 0 */ + INSTS_RSREG(RESXXREG, 0, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x82: /* RES (IX+d),D 0 */ - RESXXREG(0, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x82: /* RES (Ir+d),D 0 */ + INSTS_RSREG(RESXXREG, 0, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x83: /* RES (IX+d),E 0 */ - RESXXREG(0, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x83: /* RES (Ir+d),E 0 */ + INSTS_RSREG(RESXXREG, 0, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x84: /* RES (IX+d),H 0 */ - RESXXREG(0, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x84: /* RES (Ir+d),H 0 */ + INSTS_RSREG(RESXXREG, 0, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x85: /* RES (IX+d),L 0 */ - RESXXREG(0, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x85: /* RES (Ir+d),L 0 */ + INSTS_RSREG(RESXXREG, 0, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x86: /* RES (IX+d) 0 */ - RESXX(0, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x86: /* RES (Ir+d) 0 */ + INSTS_RS(RESXX, 0, WORD_OFF(iip2), 15, 2); break; - case 0x87: /* RES (IX+d),A 0 */ - RESXXREG(0, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x87: /* RES (Ir+d),A 0 */ + INSTS_RSREG(RESXXREG, 0, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x88: /* RES (IX+d),B 1 */ - RESXXREG(1, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x88: /* RES (Ir+d),B 1 */ + INSTS_RSREG(RESXXREG, 1, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x89: /* RES (IX+d),C 1 */ - RESXXREG(1, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x89: /* RES (Ir+d),C 1 */ + INSTS_RSREG(RESXXREG, 1, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x8a: /* RES (IX+d),D 1 */ - RESXXREG(1, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8a: /* RES (Ir+d),D 1 */ + INSTS_RSREG(RESXXREG, 1, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x8b: /* RES (IX+d),E 1 */ - RESXXREG(1, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8b: /* RES (Ir+d),E 1 */ + INSTS_RSREG(RESXXREG, 1, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x8c: /* RES (IX+d),H 1 */ - RESXXREG(1, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8c: /* RES (Ir+d),H 1 */ + INSTS_RSREG(RESXXREG, 1, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x8d: /* RES (IX+d),L 1 */ - RESXXREG(1, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8d: /* RES (Ir+d),L 1 */ + INSTS_RSREG(RESXXREG, 1, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x8e: /* RES (IX+d) 1 */ - RESXX(1, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8e: /* RES (Ir+d) 1 */ + INSTS_RS(RESXX, 1, WORD_OFF(iip2), 15, 2); break; - case 0x8f: /* RES (IX+d),A 1 */ - RESXXREG(1, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x8f: /* RES (Ir+d),A 1 */ + INSTS_RSREG(RESXXREG, 1, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x90: /* RES (IX+d),B 2 */ - RESXXREG(2, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x90: /* RES (Ir+d),B 2 */ + INSTS_RSREG(RESXXREG, 2, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x91: /* RES (IX+d),C 2 */ - RESXXREG(2, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x91: /* RES (Ir+d),C 2 */ + INSTS_RSREG(RESXXREG, 2, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x92: /* RES (IX+d),D 2 */ - RESXXREG(2, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x92: /* RES (Ir+d),D 2 */ + INSTS_RSREG(RESXXREG, 2, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x93: /* RES (IX+d),E 2 */ - RESXXREG(2, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x93: /* RES (Ir+d),E 2 */ + INSTS_RSREG(RESXXREG, 2, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x94: /* RES (IX+d),H 2 */ - RESXXREG(2, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x94: /* RES (Ir+d),H 2 */ + INSTS_RSREG(RESXXREG, 2, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x95: /* RES (IX+d),L 2 */ - RESXXREG(2, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x95: /* RES (Ir+d),L 2 */ + INSTS_RSREG(RESXXREG, 2, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x96: /* RES (IX+d) 2 */ - RESXX(2, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x96: /* RES (Ir+d) 2 */ + INSTS_RS(RESXX, 2, WORD_OFF(iip2), 15, 2); break; - case 0x97: /* RES (IX+d),A 2 */ - RESXXREG(2, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x97: /* RES (Ir+d),A 2 */ + INSTS_RSREG(RESXXREG, 2, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0x98: /* RES (IX+d),B 3 */ - RESXXREG(3, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x98: /* RES (Ir+d),B 3 */ + INSTS_RSREG(RESXXREG, 3, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0x99: /* RES (IX+d),C 3 */ - RESXXREG(3, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x99: /* RES (Ir+d),C 3 */ + INSTS_RSREG(RESXXREG, 3, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0x9a: /* RES (IX+d),D 3 */ - RESXXREG(3, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9a: /* RES (Ir+d),D 3 */ + INSTS_RSREG(RESXXREG, 3, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0x9b: /* RES (IX+d),E 3 */ - RESXXREG(3, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9b: /* RES (Ir+d),E 3 */ + INSTS_RSREG(RESXXREG, 3, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0x9c: /* RES (IX+d),H 3 */ - RESXXREG(3, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9c: /* RES (Ir+d),H 3 */ + INSTS_RSREG(RESXXREG, 3, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0x9d: /* RES (IX+d),L 3 */ - RESXXREG(3, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9d: /* RES (Ir+d),L 3 */ + INSTS_RSREG(RESXXREG, 3, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0x9e: /* RES (IX+d) 3 */ - RESXX(3, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9e: /* RES (Ir+d) 3 */ + INSTS_RS(RESXX, 3, WORD_OFF(iip2), 15, 2); break; - case 0x9f: /* RES (IX+d),A 3 */ - RESXXREG(3, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0x9f: /* RES (Ir+d),A 3 */ + INSTS_RSREG(RESXXREG, 3, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xa0: /* RES (IX+d),B 4 */ - RESXXREG(4, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa0: /* RES (Ir+d),B 4 */ + INSTS_RSREG(RESXXREG, 4, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xa1: /* RES (IX+d),C 4 */ - RESXXREG(4, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa1: /* RES (Ir+d),C 4 */ + INSTS_RSREG(RESXXREG, 4, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xa2: /* RES (IX+d),D 4 */ - RESXXREG(4, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa2: /* RES (Ir+d),D 4 */ + INSTS_RSREG(RESXXREG, 4, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xa3: /* RES (IX+d),E 4 */ - RESXXREG(4, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa3: /* RES (Ir+d),E 4 */ + INSTS_RSREG(RESXXREG, 4, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xa4: /* RES (IX+d),H 4 */ - RESXXREG(4, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa4: /* RES (Ir+d),H 4 */ + INSTS_RSREG(RESXXREG, 4, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xa5: /* RES (IX+d),L 4 */ - RESXXREG(4, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa5: /* RES (Ir+d),L 4 */ + INSTS_RSREG(RESXXREG, 4, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xa6: /* RES (IX+d) 4 */ - RESXX(4, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa6: /* RES (Ir+d) 4 */ + INSTS_RS(RESXX, 4, WORD_OFF(iip2), 15, 2); break; - case 0xa7: /* RES (IX+d),A 4 */ - RESXXREG(4, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa7: /* RES (Ir+d),A 4 */ + INSTS_RSREG(RESXXREG, 4, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xa8: /* RES (IX+d),B 5 */ - RESXXREG(5, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa8: /* RES (Ir+d),B 5 */ + INSTS_RSREG(RESXXREG, 5, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xa9: /* RES (IX+d),C 5 */ - RESXXREG(5, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xa9: /* RES (Ir+d),C 5 */ + INSTS_RSREG(RESXXREG, 5, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xaa: /* RES (IX+d),D 5 */ - RESXXREG(5, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xaa: /* RES (Ir+d),D 5 */ + INSTS_RSREG(RESXXREG, 5, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xab: /* RES (IX+d),E 5 */ - RESXXREG(5, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xab: /* RES (Ir+d),E 5 */ + INSTS_RSREG(RESXXREG, 5, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xac: /* RES (IX+d),H 5 */ - RESXXREG(5, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xac: /* RES (Ir+d),H 5 */ + INSTS_RSREG(RESXXREG, 5, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xad: /* RES (IX+d),L 5 */ - RESXXREG(5, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xad: /* RES (Ir+d),L 5 */ + INSTS_RSREG(RESXXREG, 5, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xae: /* RES (IX+d) 5 */ - RESXX(5, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xae: /* RES (Ir+d) 5 */ + INSTS_RS(RESXX, 5, WORD_OFF(iip2), 15, 2); break; - case 0xaf: /* RES (IX+d),A 5 */ - RESXXREG(5, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xaf: /* RES (Ir+d),A 5 */ + INSTS_RSREG(RESXXREG, 5, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xb0: /* RES (IX+d),B 6 */ - RESXXREG(6, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb0: /* RES (Ir+d),B 6 */ + INSTS_RSREG(RESXXREG, 6, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xb1: /* RES (IX+d),C 6 */ - RESXXREG(6, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb1: /* RES (Ir+d),C 6 */ + INSTS_RSREG(RESXXREG, 6, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xb2: /* RES (IX+d),D 6 */ - RESXXREG(6, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb2: /* RES (Ir+d),D 6 */ + INSTS_RSREG(RESXXREG, 6, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xb3: /* RES (IX+d),E 6 */ - RESXXREG(6, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb3: /* RES (Ir+d),E 6 */ + INSTS_RSREG(RESXXREG, 6, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xb4: /* RES (IX+d),H 6 */ - RESXXREG(6, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb4: /* RES (Ir+d),H 6 */ + INSTS_RSREG(RESXXREG, 6, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xb5: /* RES (IX+d),L 6 */ - RESXXREG(6, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb5: /* RES (Ir+d),L 6 */ + INSTS_RSREG(RESXXREG, 6, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xb6: /* RES (IX+d) 6 */ - RESXX(6, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb6: /* RES (Ir+d) 6 */ + INSTS_RS(RESXX, 6, WORD_OFF(iip2), 15, 2); break; - case 0xb7: /* RES (IX+d),A 6 */ - RESXXREG(6, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb7: /* RES (Ir+d),A 6 */ + INSTS_RSREG(RESXXREG, 6, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xb8: /* RES (IX+d),B 7 */ - RESXXREG(7, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb8: /* RES (Ir+d),B 7 */ + INSTS_RSREG(RESXXREG, 7, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xb9: /* RES (IX+d),C 7 */ - RESXXREG(7, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xb9: /* RES (Ir+d),C 7 */ + INSTS_RSREG(RESXXREG, 7, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xba: /* RES (IX+d),D 7 */ - RESXXREG(7, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xba: /* RES (Ir+d),D 7 */ + INSTS_RSREG(RESXXREG, 7, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xbb: /* RES (IX+d),E 7 */ - RESXXREG(7, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xbb: /* RES (Ir+d),E 7 */ + INSTS_RSREG(RESXXREG, 7, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xbc: /* RES (IX+d),H 7 */ - RESXXREG(7, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xbc: /* RES (Ir+d),H 7 */ + INSTS_RSREG(RESXXREG, 7, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xbd: /* RES (IX+d),L 7 */ - RESXXREG(7, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xbd: /* RES (Ir+d),L 7 */ + INSTS_RSREG(RESXXREG, 7, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xbe: /* RES (IX+d) 7 */ - RESXX(7, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xbe: /* RES (Ir+d) 7 */ + INSTS_RS(RESXX, 7, WORD_OFF(iip2), 15, 2); break; - case 0xbf: /* RES (IX+d),A 7 */ - RESXXREG(7, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xbf: /* RES (Ir+d),A 7 */ + INSTS_RSREG(RESXXREG, 7, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xc0: /* SET (IX+d),B 0 */ - SETXXREG(0, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc0: /* SET (Ir+d),B 0 */ + INSTS_RSREG(SETXXREG, 0, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xc1: /* SET (IX+d),C 0 */ - SETXXREG(0, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc1: /* SET (Ir+d),C 0 */ + INSTS_RSREG(SETXXREG, 0, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xc2: /* SET (IX+d),D 0 */ - SETXXREG(0, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc2: /* SET (Ir+d),D 0 */ + INSTS_RSREG(SETXXREG, 0, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xc3: /* SET (IX+d),E 0 */ - SETXXREG(0, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc3: /* SET (Ir+d),E 0 */ + INSTS_RSREG(SETXXREG, 0, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xc4: /* SET (IX+d),H 0 */ - SETXXREG(0, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc4: /* SET (Ir+d),H 0 */ + INSTS_RSREG(SETXXREG, 0, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xc5: /* SET (IX+d),L 0 */ - SETXXREG(0, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc5: /* SET (Ir+d),L 0 */ + INSTS_RSREG(SETXXREG, 0, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xc6: /* SET (IX+d) 0 */ - SETXX(0, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc6: /* SET (Ir+d) 0 */ + INSTS_RS(SETXX, 0, WORD_OFF(iip2), 15, 2); break; - case 0xc7: /* SET (IX+d),A 0 */ - SETXXREG(0, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc7: /* SET (Ir+d),A 0 */ + INSTS_RSREG(SETXXREG, 0, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xc8: /* SET (IX+d),B 1 */ - SETXXREG(1, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc8: /* SET (Ir+d),B 1 */ + INSTS_RSREG(SETXXREG, 1, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xc9: /* SET (IX+d),C 1 */ - SETXXREG(1, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xc9: /* SET (Ir+d),C 1 */ + INSTS_RSREG(SETXXREG, 1, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xca: /* SET (IX+d),D 1 */ - SETXXREG(1, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xca: /* SET (Ir+d),D 1 */ + INSTS_RSREG(SETXXREG, 1, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xcb: /* SET (IX+d),E 1 */ - SETXXREG(1, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xcb: /* SET (Ir+d),E 1 */ + INSTS_RSREG(SETXXREG, 1, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xcc: /* SET (IX+d),H 1 */ - SETXXREG(1, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xcc: /* SET (Ir+d),H 1 */ + INSTS_RSREG(SETXXREG, 1, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xcd: /* SET (IX+d),L 1 */ - SETXXREG(1, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xcd: /* SET (Ir+d),L 1 */ + INSTS_RSREG(SETXXREG, 1, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xce: /* SET (IX+d) 1 */ - SETXX(1, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xce: /* SET (Ir+d) 1 */ + INSTS_RS(SETXX, 1, WORD_OFF(iip2), 15, 2); break; - case 0xcf: /* SET (IX+d),A 1 */ - SETXXREG(1, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xcf: /* SET (Ir+d),A 1 */ + INSTS_RSREG(SETXXREG, 1, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xd0: /* SET (IX+d),B 2 */ - SETXXREG(2, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd0: /* SET (Ir+d),B 2 */ + INSTS_RSREG(SETXXREG, 2, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xd1: /* SET (IX+d),C 2 */ - SETXXREG(2, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd1: /* SET (Ir+d),C 2 */ + INSTS_RSREG(SETXXREG, 2, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xd2: /* SET (IX+d),D 2 */ - SETXXREG(2, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd2: /* SET (Ir+d),D 2 */ + INSTS_RSREG(SETXXREG, 2, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xd3: /* SET (IX+d),E 2 */ - SETXXREG(2, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd3: /* SET (Ir+d),E 2 */ + INSTS_RSREG(SETXXREG, 2, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xd4: /* SET (IX+d),H 2 */ - SETXXREG(2, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd4: /* SET (Ir+d),H 2 */ + INSTS_RSREG(SETXXREG, 2, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xd5: /* SET (IX+d),L 2 */ - SETXXREG(2, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd5: /* SET (Ir+d),L 2 */ + INSTS_RSREG(SETXXREG, 2, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xd6: /* SET (IX+d) 2 */ - SETXX(2, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd6: /* SET (Ir+d) 2 */ + INSTS_RS(SETXX, 2, WORD_OFF(iip2), 15, 2); break; - case 0xd7: /* SET (IX+d),A 2 */ - SETXXREG(2, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd7: /* SET (Ir+d),A 2 */ + INSTS_RSREG(SETXXREG, 2, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xd8: /* SET (IX+d),B 3 */ - SETXXREG(3, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd8: /* SET (Ir+d),B 3 */ + INSTS_RSREG(SETXXREG, 3, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xd9: /* SET (IX+d),C 3 */ - SETXXREG(3, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xd9: /* SET (Ir+d),C 3 */ + INSTS_RSREG(SETXXREG, 3, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xda: /* SET (IX+d),D 3 */ - SETXXREG(3, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xda: /* SET (Ir+d),D 3 */ + INSTS_RSREG(SETXXREG, 3, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xdb: /* SET (IX+d),E 3 */ - SETXXREG(3, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xdb: /* SET (Ir+d),E 3 */ + INSTS_RSREG(SETXXREG, 3, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xdc: /* SET (IX+d),H 3 */ - SETXXREG(3, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xdc: /* SET (Ir+d),H 3 */ + INSTS_RSREG(SETXXREG, 3, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xdd: /* SET (IX+d),L 3 */ - SETXXREG(3, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xdd: /* SET (Ir+d),L 3 */ + INSTS_RSREG(SETXXREG, 3, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xde: /* SET (IX+d) 3 */ - SETXX(3, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xde: /* SET (Ir+d) 3 */ + INSTS_RS(SETXX, 3, WORD_OFF(iip2), 15, 2); break; - case 0xdf: /* SET (IX+d),A 3 */ - SETXXREG(3, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xdf: /* SET (Ir+d),A 3 */ + INSTS_RSREG(SETXXREG, 3, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xe0: /* SET (IX+d),B 4 */ - SETXXREG(4, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe0: /* SET (Ir+d),B 4 */ + INSTS_RSREG(SETXXREG, 4, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xe1: /* SET (IX+d),C 4 */ - SETXXREG(4, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe1: /* SET (Ir+d),C 4 */ + INSTS_RSREG(SETXXREG, 4, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xe2: /* SET (IX+d),D 4 */ - SETXXREG(4, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe2: /* SET (Ir+d),D 4 */ + INSTS_RSREG(SETXXREG, 4, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xe3: /* SET (IX+d),E 4 */ - SETXXREG(4, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe3: /* SET (Ir+d),E 4 */ + INSTS_RSREG(SETXXREG, 4, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xe4: /* SET (IX+d),H 4 */ - SETXXREG(4, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe4: /* SET (Ir+d),H 4 */ + INSTS_RSREG(SETXXREG, 4, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xe5: /* SET (IX+d),L 4 */ - SETXXREG(4, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe5: /* SET (Ir+d),L 4 */ + INSTS_RSREG(SETXXREG, 4, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xe6: /* SET (IX+d) 4 */ - SETXX(4, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe6: /* SET (Ir+d) 4 */ + INSTS_RS(SETXX, 4, WORD_OFF(iip2), 15, 2); break; - case 0xe7: /* SET (IX+d),A 4 */ - SETXXREG(4, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe7: /* SET (Ir+d),A 4 */ + INSTS_RSREG(SETXXREG, 4, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xe8: /* SET (IX+d),B 5 */ - SETXXREG(5, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe8: /* SET (Ir+d),B 5 */ + INSTS_RSREG(SETXXREG, 5, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xe9: /* SET (IX+d),C 5 */ - SETXXREG(5, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xe9: /* SET (Ir+d),C 5 */ + INSTS_RSREG(SETXXREG, 5, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xea: /* SET (IX+d),D 5 */ - SETXXREG(5, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xea: /* SET (Ir+d),D 5 */ + INSTS_RSREG(SETXXREG, 5, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xeb: /* SET (IX+d),E 5 */ - SETXXREG(5, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xeb: /* SET (Ir+d),E 5 */ + INSTS_RSREG(SETXXREG, 5, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xec: /* SET (IX+d),H 5 */ - SETXXREG(5, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xec: /* SET (Ir+d),H 5 */ + INSTS_RSREG(SETXXREG, 5, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xed: /* SET (IX+d),L 5 */ - SETXXREG(5, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xed: /* SET (Ir+d),L 5 */ + INSTS_RSREG(SETXXREG, 5, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xee: /* SET (IX+d) 5 */ - SETXX(5, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xee: /* SET (Ir+d) 5 */ + INSTS_RS(SETXX, 5, WORD_OFF(iip2), 15, 2); break; - case 0xef: /* SET (IX+d),A 5 */ - SETXXREG(5, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xef: /* SET (Ir+d),A 5 */ + INSTS_RSREG(SETXXREG, 5, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xf0: /* SET (IX+d),B 6 */ - SETXXREG(6, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf0: /* SET (Ir+d),B 6 */ + INSTS_RSREG(SETXXREG, 6, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xf1: /* SET (IX+d),C 6 */ - SETXXREG(6, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf1: /* SET (Ir+d),C 6 */ + INSTS_RSREG(SETXXREG, 6, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xf2: /* SET (IX+d),D 6 */ - SETXXREG(6, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf2: /* SET (Ir+d),D 6 */ + INSTS_RSREG(SETXXREG, 6, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xf3: /* SET (IX+d),E 6 */ - SETXXREG(6, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf3: /* SET (Ir+d),E 6 */ + INSTS_RSREG(SETXXREG, 6, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xf4: /* SET (IX+d),H 6 */ - SETXXREG(6, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf4: /* SET (Ir+d),H 6 */ + INSTS_RSREG(SETXXREG, 6, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xf5: /* SET (IX+d),L 6 */ - SETXXREG(6, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf5: /* SET (Ir+d),L 6 */ + INSTS_RSREG(SETXXREG, 6, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xf6: /* SET (IX+d) 6 */ - SETXX(6, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf6: /* SET (Ir+d) 6 */ + INSTS_RS(SETXX, 6, WORD_OFF(iip2), 15, 2); break; - case 0xf7: /* SET (IX+d),A 6 */ - SETXXREG(6, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf7: /* SET (Ir+d),A 6 */ + INSTS_RSREG(SETXXREG, 6, reg_a, WORD_OFF(iip2), 15, 2); break; - case 0xf8: /* SET (IX+d),B 7 */ - SETXXREG(7, reg_b, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf8: /* SET (Ir+d),B 7 */ + INSTS_RSREG(SETXXREG, 7, reg_b, WORD_OFF(iip2), 15, 2); break; - case 0xf9: /* SET (IX+d),C 7 */ - SETXXREG(7, reg_c, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xf9: /* SET (Ir+d),C 7 */ + INSTS_RSREG(SETXXREG, 7, reg_c, WORD_OFF(iip2), 15, 2); break; - case 0xfa: /* SET (IX+d),D 7 */ - SETXXREG(7, reg_d, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xfa: /* SET (Ir+d),D 7 */ + INSTS_RSREG(SETXXREG, 7, reg_d, WORD_OFF(iip2), 15, 2); break; - case 0xfb: /* SET (IX+d),E 7 */ - SETXXREG(7, reg_e, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xfb: /* SET (Ir+d),E 7 */ + INSTS_RSREG(SETXXREG, 7, reg_e, WORD_OFF(iip2), 15, 2); break; - case 0xfc: /* SET (IX+d),H 7 */ - SETXXREG(7, reg_h, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xfc: /* SET (Ir+d),H 7 */ + INSTS_RSREG(SETXXREG, 7, reg_h, WORD_OFF(iip2), 15, 2); break; - case 0xfd: /* SET (IX+d),L 7 */ - SETXXREG(7, reg_l, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xfd: /* SET (Ir+d),L 7 */ + INSTS_RSREG(SETXXREG, 7, reg_l, WORD_OFF(iip2), 15, 2); break; - case 0xfe: /* SET (IX+d) 7 */ - SETXX(7, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xfe: /* SET (Ir+d) 7 */ + INSTS_RS(SETXX, 7, WORD_OFF(iip2), 15, 2); break; - case 0xff: /* SET (IX+d),A 7 */ - SETXXREG(7, reg_a, IX_WORD_OFF(iip2), 4, 4, 15, 4); + case 0xff: /* SET (Ir+d),A 7 */ + INSTS_RSREG(SETXXREG, 7, reg_a, WORD_OFF(iip2), 15, 2); break; default: - INC_PC(4); + /* all 256 instances covered */ + break; } } -static void opcode_dd(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) +static void opcode_ed(uint8_t ip1, uint8_t ip2, uint8_t ip3, uint16_t ip12, uint16_t ip23) { switch (ip1) { - case 0x00: /* NOP */ - NOP(8, 2); + case 0x40: /* IN B BC */ + INBC(reg_b, 10, 2, 2); break; - case 0x01: /* LD BC # */ - LDW(ip23, reg_b, reg_c, 10, 0, 4); + case 0x41: /* OUT BC B */ + OUTBC(reg_b, 10, 2, 2); break; - case 0x02: /* LD (BC) A */ - STREG(BC_WORD(), reg_a, 8, 3, 2); + case 0x42: /* SBC HL BC */ + SBCHLREG(reg_b, reg_c); break; - case 0x03: /* INC BC */ - DECINC(INC_BC_WORD(), 10, 2); + case 0x43: /* LD (WORD) BC */ + STW(ip23, reg_b, reg_c, 4, 13, 3, 4); break; - case 0x04: /* INC B */ - INCREG(reg_b, 7, 2); + case 0x44: /* NEG */ + NEG(); break; - case 0x05: /* DEC B */ - DECREG(reg_b, 7, 2); + case 0x45: /* RETN */ + RETNI(); break; - case 0x06: /* LD B # */ - LDREG(reg_b, ip2, 4, 5, 3); + case 0x46: /* IM0 */ + IM(0); break; - case 0x07: /* RLCA */ - RLCA(8, 2); + case 0x47: /* LD I A */ + LDREG(reg_i, reg_a, 6, 3, 2); break; - case 0x08: /* EX AF AF' */ - EXAFAF(12, 2); + case 0x48: /* IN C BC */ + INBC(reg_c, 10, 2, 2); break; - case 0x09: /* ADD IX BC */ - ADDXXREG(reg_ixh, reg_ixl, reg_b, reg_c, 15, 2); + case 0x49: /* OUT BC C */ + OUTBC(reg_c, 10, 2, 2); break; - case 0x0a: /* LD A (BC) */ - LDREG(reg_a, LOAD(BC_WORD()), 8, 3, 2); + case 0x4a: /* ADC HL BC */ + ADCHLREG(reg_b, reg_c); break; - case 0x0b: /* DEC BC */ - DECINC(DEC_BC_WORD(), 10, 2); + case 0x4b: /* LD BC (WORD) */ + LDIND(ip23, reg_b, reg_c, 4, 4, 12, 4); break; - case 0x0c: /* INC C */ - INCREG(reg_c, 7, 2); + case 0x4c: /* undoc NEG */ + NEG(); break; - case 0x0d: /* DEC C */ - DECREG(reg_c, 7, 2); + case 0x4d: /* RETI */ + RETNI(); break; - case 0x0e: /* LD C # */ - LDREG(reg_c, ip2, 4, 5, 3); + case 0x4e: /* undoc IM0 */ + IM(0); break; - case 0x0f: /* RRCA */ - RRCA(8, 2); + case 0x4f: /* LD R A FIXME: Not emulated. */ + NOP(9, 2); break; - case 0x10: /* DJNZ */ - DJNZ(ip2, 3); + case 0x50: /* IN D BC */ + INBC(reg_d, 10, 2, 2); break; - case 0x11: /* LD DE # */ - LDW(ip23, reg_d, reg_e, 10, 0, 4); + case 0x51: /* OUT BC D */ + OUTBC(reg_d, 10, 2, 2); break; - case 0x12: /* LD (DE) A */ - STREG(DE_WORD(), reg_a, 8, 3, 2); - break; - case 0x13: /* INC DE */ - DECINC(INC_DE_WORD(), 10, 2); - break; - case 0x14: /* INC D */ - INCREG(reg_d, 7, 2); - break; - case 0x15: /* DEC D */ - DECREG(reg_d, 7, 2); - break; - case 0x16: /* LD D # */ - LDREG(reg_d, ip2, 4, 5, 3); - break; - case 0x17: /* RLA */ - RLA(8, 2); - break; - case 0x19: /* ADD IX DE */ - ADDXXREG(reg_ixh, reg_ixl, reg_d, reg_e, 15, 2); - break; - case 0x1a: /* LD A DE */ - LDREG(reg_a, LOAD(DE_WORD()), 8, 3, 2); - break; - case 0x1b: /* DEC DE */ - DECINC(DEC_DE_WORD(), 10, 2); - break; - case 0x1c: /* INC E */ - INCREG(reg_e, 7, 2); - break; - case 0x1d: /* DEC E */ - DECREG(reg_e, 7, 2); - break; - case 0x1e: /* LD E # */ - LDREG(reg_e, ip2, 4, 5, 3); - break; - case 0x1f: /* RRA */ - RRA(8, 2); - break; - case 0x20: /* JR NZ */ - BRANCH(!LOCAL_ZERO(), ip2, 3); - break; - case 0x21: /* LD IX # */ - LDW(ip23, reg_ixh, reg_ixl, 10, 4, 4); - break; - case 0x22: /* LD (WORD) IX */ - STW(ip23, reg_ixh, reg_ixl, 4, 9, 7, 4); - break; - case 0x23: /* INC IX */ - DECINC(INC_IX_WORD(), 10, 2); - break; - case 0x24: /* INC IXH */ - INCREG(reg_ixh, 7, 2); - break; - case 0x25: /* DEC IXH */ - DECREG(reg_ixh, 7, 2); - break; - case 0x26: /* LD IXH # */ - LDREG(reg_ixh, ip2, 4, 5, 3); - break; - case 0x27: /* DAA */ - DAA(8, 2); - break; - case 0x29: /* ADD IX IX */ - ADDXXREG(reg_ixh, reg_ixl, reg_ixh, reg_ixl, 15, 2); - break; - case 0x28: /* JR Z */ - BRANCH(LOCAL_ZERO(), ip2, 3); - break; - case 0x2a: /* LD IX (WORD) */ - LDIND(ip23, reg_ixh, reg_ixl, 4, 4, 12, 4); - break; - case 0x2b: /* DEC IX */ - DECINC(DEC_IX_WORD(), 10, 2); - break; - case 0x2c: /* INC IXL */ - INCREG(reg_ixl, 7, 2); - break; - case 0x2d: /* DEC IXL */ - DECREG(reg_ixl, 7, 2); - break; - case 0x2e: /* LD IXL # */ - LDREG(reg_ixl, ip2, 4, 5, 3); - break; - case 0x2f: /* CPL */ - CPL(8, 2); - break; - case 0x30: /* JR NC */ - BRANCH(!LOCAL_CARRY(), ip2, 3); - break; - case 0x31: /* LD SP # */ - LDSP(ip23, 10, 0, 4); - break; - case 0x32: /* LD (WORD) A */ - STREG(ip23, reg_a, 10, 7, 4); - break; - case 0x33: /* INC SP */ - DECINC(reg_sp++, 10, 2); - break; - case 0x34: /* INC (IX+d) */ - INCXXIND(IX_WORD_OFF(ip2), 4, 7, 12, 3); - break; - case 0x35: /* DEC (IX+d) */ - DECXXIND(IX_WORD_OFF(ip2), 4, 7, 12, 3); - break; - case 0x36: /* LD (IX+d) # */ - STREG(IX_WORD_OFF(ip2), ip3, 8, 11, 4); - break; - case 0x37: /* SCF */ - SCF(8, 2); - break; - case 0x38: /* JR C */ - BRANCH(LOCAL_CARRY(), ip2, 3); - break; - case 0x39: /* ADD IX SP */ - ADDXXSP(reg_ixh, reg_ixl, 15, 2); - break; - case 0x3a: /* LD A (WORD) */ - LDREG(reg_a, LOAD(ip23), 10, 7, 4); - break; - case 0x3b: /* DEC SP */ - DECINC(reg_sp--, 10, 2); - break; - case 0x3c: /* INC A */ - INCREG(reg_a, 7, 2); - break; - case 0x3d: /* DEC A */ - DECREG(reg_a, 7, 2); - break; - case 0x3e: /* LD A # */ - LDREG(reg_a, ip2, 4, 5, 3); - break; - case 0x3f: /* CCF */ - CCF(8, 2); - break; - case 0x40: /* LD B B */ - LDREG(reg_b, reg_b, 0, 4, 2); - break; - case 0x41: /* LD B C */ - LDREG(reg_b, reg_c, 0, 4, 2); - break; - case 0x42: /* LD B D */ - LDREG(reg_b, reg_d, 0, 4, 2); - break; - case 0x43: /* LD B E */ - LDREG(reg_b, reg_e, 0, 4, 2); - break; - case 0x44: /* LD B IXH */ - LDREG(reg_b, reg_ixh, 0, 4, 2); - break; - case 0x45: /* LD B IXL */ - LDREG(reg_b, reg_ixl, 0, 4, 2); - break; - case 0x46: /* LD B (IX+d) */ - LDREG(reg_b, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x47: /* LD B A */ - LDREG(reg_b, reg_a, 0, 4, 2); - break; - case 0x48: /* LD C B */ - LDREG(reg_c, reg_b, 0, 4, 2); - break; - case 0x49: /* LD C C */ - LDREG(reg_c, reg_c, 0, 4, 2); - break; - case 0x4a: /* LD C D */ - LDREG(reg_c, reg_d, 0, 4, 2); - break; - case 0x4b: /* LD C E */ - LDREG(reg_c, reg_e, 0, 4, 2); - break; - case 0x4c: /* LD C IXH */ - LDREG(reg_c, reg_ixh, 0, 4, 2); - break; - case 0x4d: /* LD C IXL */ - LDREG(reg_c, reg_ixl, 0, 4, 2); - break; - case 0x4e: /* LD C (IX+d) */ - LDREG(reg_c, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x4f: /* LD C A */ - LDREG(reg_c, reg_a, 0, 4, 2); - break; - case 0x50: /* LD D B */ - LDREG(reg_d, reg_b, 0, 4, 2); - break; - case 0x51: /* LD D C */ - LDREG(reg_d, reg_c, 0, 4, 2); - break; - case 0x52: /* LD D D */ - LDREG(reg_d, reg_d, 0, 4, 2); - break; - case 0x53: /* LD D E */ - LDREG(reg_d, reg_e, 0, 4, 2); - break; - case 0x54: /* LD D IXH */ - LDREG(reg_d, reg_ixh, 0, 4, 2); - break; - case 0x55: /* LD D L */ - LDREG(reg_d, reg_ixl, 0, 4, 2); - break; - case 0x56: /* LD D (IX+d) */ - LDREG(reg_d, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x57: /* LD D A */ - LDREG(reg_d, reg_a, 0, 4, 2); - break; - case 0x58: /* LD E B */ - LDREG(reg_e, reg_b, 0, 4, 2); - break; - case 0x59: /* LD E C */ - LDREG(reg_e, reg_c, 0, 4, 2); - break; - case 0x5a: /* LD E D */ - LDREG(reg_e, reg_d, 0, 4, 2); - break; - case 0x5b: /* LD E E */ - LDREG(reg_e, reg_e, 0, 4, 2); - break; - case 0x5c: /* LD E IXH */ - LDREG(reg_e, reg_ixh, 0, 4, 2); - break; - case 0x5d: /* LD E IXL */ - LDREG(reg_e, reg_ixl, 0, 4, 2); - break; - case 0x5e: /* LD E (IX+d) */ - LDREG(reg_e, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x5f: /* LD E A */ - LDREG(reg_e, reg_a, 0, 4, 2); - break; - case 0x60: /* LD IXH B */ - LDREG(reg_ixh, reg_b, 0, 4, 2); - break; - case 0x61: /* LD IXH C */ - LDREG(reg_ixh, reg_c, 0, 4, 2); - break; - case 0x62: /* LD IXH D */ - LDREG(reg_ixh, reg_d, 0, 4, 2); - break; - case 0x63: /* LD IXH E */ - LDREG(reg_ixh, reg_e, 0, 4, 2); - break; - case 0x64: /* LD IXH IXH */ - LDREG(reg_ixh, reg_ixh, 0, 4, 2); - break; - case 0x65: /* LD IXH IXL */ - LDREG(reg_ixh, reg_ixl, 0, 4, 2); - break; - case 0x66: /* LD H (IX+d) */ - LDREG(reg_h, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x67: /* LD IXH A */ - LDREG(reg_ixh, reg_a, 0, 4, 2); - break; - case 0x68: /* LD IXL B */ - LDREG(reg_ixl, reg_b, 0, 4, 2); - break; - case 0x69: /* LD IXL C */ - LDREG(reg_ixl, reg_c, 0, 4, 2); - break; - case 0x6a: /* LD IXL D */ - LDREG(reg_ixl, reg_d, 0, 4, 2); - break; - case 0x6b: /* LD IXL E */ - LDREG(reg_ixl, reg_e, 0, 4, 2); - break; - case 0x6c: /* LD IXL IXH */ - LDREG(reg_ixl, reg_ixh, 0, 4, 2); - break; - case 0x6d: /* LD IXL IXL */ - LDREG(reg_ixl, reg_ixl, 0, 4, 2); - break; - case 0x6e: /* LD L (IX+d) */ - LDREG(reg_l, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x6f: /* LD IXL A */ - LDREG(reg_ixl, reg_a, 0, 4, 2); - break; - case 0x70: /* LD (IX+d) B */ - STREG(IX_WORD_OFF(ip2), reg_b, 8, 11, 3); - break; - case 0x71: /* LD (IX+d) C */ - STREG(IX_WORD_OFF(ip2), reg_c, 8, 11, 3); - break; - case 0x72: /* LD (IX+d) D */ - STREG(IX_WORD_OFF(ip2), reg_d, 8, 11, 3); - break; - case 0x73: /* LD (IX+d) E */ - STREG(IX_WORD_OFF(ip2), reg_e, 8, 11, 3); - break; - case 0x74: /* LD (IX+d) H */ - STREG(IX_WORD_OFF(ip2), reg_h, 8, 11, 3); - break; - case 0x75: /* LD (IX+d) L */ - STREG(IX_WORD_OFF(ip2), reg_l, 8, 11, 3); - break; - case 0x76: /* HALT */ - HALT(); - break; - case 0x77: /* LD (IX+d) A */ - STREG(IX_WORD_OFF(ip2), reg_a, 8, 11, 3); - break; - case 0x78: /* LD A B */ - LDREG(reg_a, reg_b, 0, 4, 2); - break; - case 0x79: /* LD A C */ - LDREG(reg_a, reg_c, 0, 4, 2); - break; - case 0x7a: /* LD A D */ - LDREG(reg_a, reg_d, 0, 4, 2); - break; - case 0x7b: /* LD A E */ - LDREG(reg_a, reg_e, 0, 4, 2); - break; - case 0x7c: /* LD A IXH */ - LDREG(reg_a, reg_ixh, 0, 4, 2); - break; - case 0x7d: /* LD A IXL */ - LDREG(reg_a, reg_ixl, 0, 4, 2); - break; - case 0x7e: /* LD A (IX+d) */ - LDREG(reg_a, LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x7f: /* LD A A */ - LDREG(reg_a, reg_a, 0, 4, 2); - break; - case 0x80: /* ADD B */ - ADD(reg_b, 0, 4, 2); - break; - case 0x81: /* ADD C */ - ADD(reg_c, 0, 4, 2); - break; - case 0x82: /* ADD D */ - ADD(reg_d, 0, 4, 2); - break; - case 0x83: /* ADD E */ - ADD(reg_e, 0, 4, 2); - break; - case 0x84: /* ADD IXH */ - ADD(reg_ixh, 0, 4, 2); - break; - case 0x85: /* ADD IXL */ - ADD(reg_ixl, 0, 4, 2); - break; - case 0x86: /* ADD (IX+d) */ - ADD(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x87: /* ADD A */ - ADD(reg_a, 0, 4, 2); - break; - case 0x88: /* ADC B */ - ADC(reg_b, 0, 4, 2); - break; - case 0x89: /* ADC C */ - ADC(reg_c, 0, 4, 2); - break; - case 0x8a: /* ADC D */ - ADC(reg_d, 0, 4, 2); - break; - case 0x8b: /* ADC E */ - ADC(reg_e, 0, 4, 2); - break; - case 0x8c: /* ADC IXH */ - ADC(reg_ixh, 0, 4, 2); - break; - case 0x8d: /* ADC IXL */ - ADC(reg_ixl, 0, 4, 2); - break; - case 0x8e: /* ADC (IX+d) */ - ADC(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x8f: /* ADC A */ - ADC(reg_a, 0, 4, 2); - break; - case 0x90: /* SUB B */ - SUB(reg_b, 0, 4, 2); - break; - case 0x91: /* SUB C */ - SUB(reg_c, 0, 4, 2); - break; - case 0x92: /* SUB D */ - SUB(reg_d, 0, 4, 2); - break; - case 0x93: /* SUB E */ - SUB(reg_e, 0, 4, 2); - break; - case 0x94: /* SUB IXH */ - SUB(reg_ixh, 0, 4, 2); - break; - case 0x95: /* SUB IXL */ - SUB(reg_ixl, 0, 4, 2); - break; - case 0x96: /* SUB (IX+d) */ - SUB(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x97: /* SUB A */ - SUB(reg_a, 0, 4, 2); - break; - case 0x98: /* SBC B */ - SBC(reg_b, 0, 4, 2); - break; - case 0x99: /* SBC C */ - SBC(reg_c, 0, 4, 2); - break; - case 0x9a: /* SBC D */ - SBC(reg_d, 0, 4, 2); - break; - case 0x9b: /* SBC E */ - SBC(reg_e, 0, 4, 2); - break; - case 0x9c: /* SBC IXH */ - SBC(reg_ixh, 0, 4, 2); - break; - case 0x9d: /* SBC IXL */ - SBC(reg_ixl, 0, 4, 2); - break; - case 0x9e: /* SBC (IX+d) */ - SBC(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x9f: /* SBC A */ - SBC(reg_a, 0, 4, 2); - break; - case 0xa0: /* AND B */ - AND(reg_b, 0, 4, 2); - break; - case 0xa1: /* AND C */ - AND(reg_c, 0, 4, 2); - break; - case 0xa2: /* AND D */ - AND(reg_d, 0, 4, 2); - break; - case 0xa3: /* AND E */ - AND(reg_e, 0, 4, 2); - break; - case 0xa4: /* AND IXH */ - AND(reg_ixh, 0, 4, 2); - break; - case 0xa5: /* AND IXL */ - AND(reg_ixl, 0, 4, 2); - break; - case 0xa6: /* AND (IX+d) */ - AND(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0xa7: /* AND A */ - AND(reg_a, 0, 4, 2); - break; - case 0xa8: /* XOR B */ - XOR(reg_b, 0, 4, 2); - break; - case 0xa9: /* XOR C */ - XOR(reg_c, 0, 4, 2); - break; - case 0xaa: /* XOR D */ - XOR(reg_d, 0, 4, 2); - break; - case 0xab: /* XOR E */ - XOR(reg_e, 0, 4, 2); - break; - case 0xac: /* XOR IXH */ - XOR(reg_ixh, 0, 4, 2); - break; - case 0xad: /* XOR IXL */ - XOR(reg_ixl, 0, 4, 2); - break; - case 0xae: /* XOR (IX+d) */ - XOR(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0xaf: /* XOR A */ - XOR(reg_a, 0, 4, 2); - break; - case 0xb0: /* OR B */ - OR(reg_b, 0, 4, 2); - break; - case 0xb1: /* OR C */ - OR(reg_c, 0, 4, 2); - break; - case 0xb2: /* OR D */ - OR(reg_d, 0, 4, 2); - break; - case 0xb3: /* OR E */ - OR(reg_e, 0, 4, 2); - break; - case 0xb4: /* OR IXH */ - OR(reg_ixh, 0, 4, 2); - break; - case 0xb5: /* OR IXL */ - OR(reg_ixl, 0, 4, 2); - break; - case 0xb6: /* OR (IX+d) */ - OR(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0xb7: /* OR A */ - OR(reg_a, 0, 4, 2); - break; - case 0xb8: /* CP B */ - CP(reg_b, 0, 4, 2); - break; - case 0xb9: /* CP C */ - CP(reg_c, 0, 4, 2); - break; - case 0xba: /* CP D */ - CP(reg_d, 0, 4, 2); - break; - case 0xbb: /* CP E */ - CP(reg_e, 0, 4, 2); - break; - case 0xbc: /* CP IXH */ - CP(reg_ixh, 0, 4, 2); - break; - case 0xbd: /* CP IXL */ - CP(reg_ixl, 0, 4, 2); - break; - case 0xbe: /* CP (IX+d) */ - CP(LOAD(IX_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0xbf: /* CP A */ - CP(reg_a, 0, 4, 2); - break; - case 0xc1: /* POP BC */ - POP(reg_b, reg_c, 2); - break; - case 0xc5: /* PUSH BC */ - PUSH(reg_b, reg_c, 2); - break; - case 0xcb: /* OPCODE DD CB */ - opcode_dd_cb((BYTE)ip2, (BYTE)ip3, (WORD)ip23); - break; - case 0xd1: /* POP DE */ - POP(reg_d, reg_e, 2); - break; - case 0xd3: /* OUT A */ - OUTA(ip2, 8, 7, 3); - break; - case 0xd5: /* PUSH DE */ - PUSH(reg_d, reg_e, 2); - break; - case 0xd9: /* EXX */ - EXX(12, 2); - break; - case 0xdb: /* IN A */ - INA(ip2, 8, 7, 3); - break; - case 0xdd: /* Skip DD */ - NOP(4, 1); - break; - case 0xe1: /* POP IX */ - POP(reg_ixh, reg_ixl, 2); - break; - case 0xe3: /* EX IX (SP) */ - EXXXSP(reg_ixh, reg_ixl, 4, 4, 4, 4, 7, 2); - break; - case 0xe5: /* PUSH IX */ - PUSH(reg_ixh, reg_ixl, 2); - break; - case 0xe9: /* LD PC IX */ - JMP((IX_WORD()), 8); - break; - case 0xeb: - EXDEHL(8, 2); - break; - case 0xed: /* Skip DD */ - NOP(4, 1); - break; - case 0xf1: /* POP AF */ - POP(reg_a, reg_f, 2); - break; - case 0xf3: /* DI */ - DI(8, 2); - break; - case 0xf5: /* PUSH AF */ - PUSH(reg_a, reg_f, 2); - break; - case 0xf9: /* LD SP IX */ - LDSP(IX_WORD(), 4, 6, 2); - break; - case 0xfb: /* EI */ - EI(8, 2); - break; - case 0xfd: /* Skip DD */ - NOP(4, 1); - break; - default: -#ifdef DEBUG_Z80 - log_message(LOG_DEFAULT, - "%i PC %04x A%02x F%02x B%02x C%02x D%02x E%02x H%02x L%02x SP%04x OP DD %02x %02x %02x.", - (int)(CLK), (unsigned int)(z80_reg_pc), reg_a, reg_f, reg_b, reg_c, reg_d, reg_e, reg_h, reg_l, reg_sp, ip1, ip2, ip3); -#endif - INC_PC(2); - } -} - -static void opcode_ed(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) -{ - switch (ip1) { - case 0x40: /* IN B BC */ - INBC(reg_b, 4, 8, 2); - break; - case 0x41: /* OUT BC B */ - OUTBC(reg_b, 4, 8, 2); - break; - case 0x42: /* SBC HL BC */ - SBCHLREG(reg_b, reg_c); - break; - case 0x43: /* LD (WORD) BC */ - STW(ip23, reg_b, reg_c, 4, 13, 3, 4); - break; - case 0x44: /* NEG */ - NEG(); - break; - case 0x45: /* RETN */ - RETNI(); - break; - case 0x46: /* IM0 */ - IM(0); - break; - case 0x47: /* LD I A */ - LDREG(reg_i, reg_a, 6, 3, 2); - break; - case 0x48: /* IN C BC */ - INBC(reg_c, 4, 8, 2); - break; - case 0x49: /* OUT BC C */ - OUTBC(reg_c, 4, 8, 2); - break; - case 0x4a: /* ADC HL BC */ - ADCHLREG(reg_b, reg_c); - break; - case 0x4b: /* LD BC (WORD) */ - LDIND(ip23, reg_b, reg_c, 4, 4, 12, 4); - break; - case 0x4d: /* RETI */ - RETNI(); - break; - case 0x4f: /* LD R A FIXME: Not emulated. */ - NOP(8, 2); - break; - case 0x50: /* IN D BC */ - INBC(reg_d, 4, 8, 2); - break; - case 0x51: /* OUT BC D */ - OUTBC(reg_d, 4, 8, 2); - break; - case 0x52: /* SBC HL DE */ - SBCHLREG(reg_d, reg_e); - break; - case 0x53: /* LD (WORD) DE */ - STW(ip23, reg_d, reg_e, 4, 13, 3, 4); - break; - case 0x56: /* IM1 */ - IM(1); - break; - case 0x57: /* LD A I */ - LDAIR(reg_i); - break; - case 0x58: /* IN E BC */ - INBC(reg_e, 4, 8, 2); - break; - case 0x59: /* OUT BC E */ - OUTBC(reg_e, 4, 8, 2); - break; - case 0x5a: /* ADC HL DE */ - ADCHLREG(reg_d, reg_e); - break; - case 0x5b: /* LD DE (WORD) */ - LDIND(ip23, reg_d, reg_e, 4, 4, 12, 4); - break; - case 0x5e: /* IM2 */ - IM(2); - break; - case 0x5f: /* LD A R */ - LDAIR((BYTE)(CLK & 0xff)); - break; - case 0x60: /* IN H BC */ - INBC(reg_h, 4, 8, 2); - break; - case 0x61: /* OUT BC H */ - OUTBC(reg_h, 4, 8, 2); - break; - case 0x62: /* SBC HL HL */ - SBCHLREG(reg_h, reg_l); - break; - case 0x63: /* LD (WORD) HL */ - STW(ip23, reg_h, reg_l, 4, 13, 3, 4); - break; - case 0x67: /* RRD */ - RRD(); - break; - case 0x68: /* IN L BC */ - INBC(reg_l, 4, 8, 2); - break; - case 0x69: /* OUT BC L */ - OUTBC(reg_l, 4, 8, 2); - break; - case 0x6a: /* ADC HL HL */ - ADCHLREG(reg_h, reg_l); - break; - case 0x6b: /* LD HL (WORD) */ - LDIND(ip23, reg_h, reg_l, 4, 4, 12, 4); - break; - case 0x6f: /* RLD */ - RLD(); - break; - case 0x70: /* IN F BC */ - INBC0(4, 8, 2); - break; - case 0x71: /* OUT BC #0 */ - OUTBC(0, 4, 8, 2); - break; - case 0x72: /* SBC HL SP */ - SBCHLSP(); - break; - case 0x73: /* LD (WORD) SP */ - STSPW(ip23, 4, 13, 3, 4); - break; - case 0x78: /* IN A BC */ - INBC(reg_a, 4, 8, 2); - break; - case 0x79: /* OUT BC A */ - OUTBC(reg_a, 4, 8, 2); - break; - case 0x7a: /* ADC HL SP */ - ADCHLSP(); - break; - case 0x7b: /* LD SP (WORD) */ - LDSPIND(ip23, 4, 4, 12, 4); - break; - case 0xa0: /* LDI */ - LDDI(INC_DE_WORD(), INC_HL_WORD()); - break; - case 0xa1: /* CPI */ - CPDI(INC_HL_WORD()); - break; - case 0xa2: /* INI */ - INDI(INC_HL_WORD()); - break; - case 0xa3: /* OUTI */ - OUTDI(INC_HL_WORD()); - break; - case 0xa8: /* LDD */ - LDDI(DEC_DE_WORD(), DEC_HL_WORD()); - break; - case 0xa9: /* CPD */ - CPDI(DEC_HL_WORD()); - break; - case 0xaa: /* IND */ - INDI(DEC_HL_WORD()); - break; - case 0xab: /* OUTD */ - OUTDI(DEC_HL_WORD()); - break; - case 0xb0: /* LDIR */ - LDDIR(INC_DE_WORD(), INC_HL_WORD()); - break; - case 0xb1: /* CPIR */ - CPDIR(INC_HL_WORD()); - break; - case 0xb2: /* INIR */ - INDIR(INC_HL_WORD()); - break; - case 0xb3: /* OTIR */ - OTDIR(INC_HL_WORD()); - break; - case 0xb8: /* LDDR */ - LDDIR(DEC_DE_WORD(), DEC_HL_WORD()); - break; - case 0xb9: /* CPDR */ - CPDIR(DEC_HL_WORD()); - break; - case 0xba: /* INDR */ - INDIR(DEC_HL_WORD()); - break; - case 0xbb: /* OTDR */ - OTDIR(DEC_HL_WORD()); - break; - case 0xcb: /* NOP */ - NOP(8, 2); - break; - case 0xdd: /* NOP */ - NOP(8, 2); - break; - case 0xed: /* NOP */ - NOP(8, 2); - break; - case 0xfd: /* NOP */ - NOP(8, 2); - break; - default: -#ifdef DEBUG_Z80 - log_message(LOG_DEFAULT, - "%i PC %04x A%02x F%02x B%02x C%02x D%02x E%02x H%02x L%02x SP%04x OP ED %02x %02x %02x.", - (int)(CLK), (unsigned int)(z80_reg_pc), reg_a, reg_f, reg_b, reg_c, reg_d, reg_e, reg_h, reg_l, reg_sp, ip1, ip2, ip3); -#endif - INC_PC(2); - } -} - -static void opcode_fd_cb(BYTE iip2, BYTE iip3, WORD iip23) -{ - switch (iip3) { - case 0x00: /* RLC (IY+d),B */ - RLCXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x01: /* RLC (IY+d),C */ - RLCXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x02: /* RLC (IY+d),D */ - RLCXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x03: /* RLC (IY+d),E */ - RLCXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x04: /* RLC (IY+d),H */ - RLCXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x05: /* RLC (IY+d),L */ - RLCXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x06: /* RLC (IY+d) */ - RLCXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x07: /* RLC (IY+d),A */ - RLCXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x08: /* RRC (IY+d),B */ - RRCXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x09: /* RRC (IY+d),C */ - RRCXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0a: /* RRC (IY+d),D */ - RRCXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0b: /* RRC (IY+d),E */ - RRCXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0c: /* RRC (IY+d),H */ - RRCXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0d: /* RRC (IY+d),L */ - RRCXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0e: /* RRC (IY+d) */ - RRCXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x0f: /* RRC (IY+d),A */ - RRCXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x10: /* RL (IY+d),B */ - RLXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x11: /* RL (IY+d),C */ - RLXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x12: /* RL (IY+d),D */ - RLXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x13: /* RL (IY+d),E */ - RLXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x14: /* RL (IY+d),H */ - RLXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x15: /* RL (IY+d),L */ - RLXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x16: /* RL (IY+d) */ - RLXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x17: /* RL (IY+d),A */ - RLXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x18: /* RR (IY+d),B */ - RRXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x19: /* RR (IY+d),C */ - RRXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1a: /* RR (IY+d),D */ - RRXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1b: /* RR (IY+d),E */ - RRXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1c: /* RR (IY+d),H */ - RRXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1d: /* RR (IY+d),L */ - RRXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1e: /* RR (IY+d) */ - RRXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x1f: /* RR (IY+d),A */ - RRXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x20: /* SLA (IY+d),B */ - SLAXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x21: /* SLA (IY+d),C */ - SLAXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x22: /* SLA (IY+d),D */ - SLAXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x23: /* SLA (IY+d),E */ - SLAXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x24: /* SLA (IY+d),H */ - SLAXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x25: /* SLA (IY+d),L */ - SLAXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x26: /* SLA (IY+d) */ - SLAXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x27: /* SLA (IY+d),A */ - SLAXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x28: /* SRA (IY+d),B */ - SRAXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x29: /* SRA (IY+d),C */ - SRAXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2a: /* SRA (IY+d),D */ - SRAXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2b: /* SRA (IY+d),E */ - SRAXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2c: /* SRA (IY+d),H */ - SRAXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2d: /* SRA (IY+d),L */ - SRAXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2e: /* SRA (IY+d) */ - SRAXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x2f: /* SRA (IY+d),A */ - SRAXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x30: /* SLL (IY+d),B */ - SLLXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x31: /* SLL (IY+d),C */ - SLLXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x32: /* SLL (IY+d),D */ - SLLXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x33: /* SLL (IY+d),E */ - SLLXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x34: /* SLL (IY+d),H */ - SLLXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x35: /* SLL (IY+d),L */ - SLLXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x36: /* SLL (IY+d) */ - SLLXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x37: /* SLL (IY+d),A */ - SLLXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x38: /* SRL (IY+d),B */ - SRLXXREG(reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x39: /* SRL (IY+d),C */ - SRLXXREG(reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3a: /* SRL (IY+d),D */ - SRLXXREG(reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3b: /* SRL (IY+d),E */ - SRLXXREG(reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3c: /* SRL (IY+d),H */ - SRLXXREG(reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3d: /* SRL (IY+d),L */ - SRLXXREG(reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3e: /* SRL (IY+d) */ - SRLXX(IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x3f: /* SRL (IY+d),A */ - SRLXXREG(reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x40: /* BIT (IY+d) 0 */ - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - BIT(LOAD(IY_WORD_OFF(iip2)), 0, 8, 12, 4); - break; - case 0x48: /* BIT (IY+d) 1 */ - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - BIT(LOAD(IY_WORD_OFF(iip2)), 1, 8, 12, 4); - break; - case 0x50: /* BIT (IY+d) 2 */ - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - BIT(LOAD(IY_WORD_OFF(iip2)), 2, 8, 12, 4); - break; - case 0x58: /* BIT (IY+d) 3 */ - case 0x59: - case 0x5a: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: - BIT(LOAD(IY_WORD_OFF(iip2)), 3, 8, 12, 4); - break; - case 0x60: /* BIT (IY+d) 4 */ - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - BIT(LOAD(IY_WORD_OFF(iip2)), 4, 8, 12, 4); - break; - case 0x68: /* BIT (IY+d) 5 */ - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - BIT(LOAD(IY_WORD_OFF(iip2)), 5, 8, 12, 4); - break; - case 0x70: /* BIT (IY+d) 6 */ - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - BIT(LOAD(IY_WORD_OFF(iip2)), 6, 8, 12, 4); - break; - case 0x78: /* BIT (IY+d) 7 */ - case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: - BIT(LOAD(IY_WORD_OFF(iip2)), 7, 8, 12, 4); - break; - case 0x80: /* RES (IY+d),B 0 */ - RESXXREG(0, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x81: /* RES (IY+d),C 0 */ - RESXXREG(0, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x82: /* RES (IY+d),D 0 */ - RESXXREG(0, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x83: /* RES (IY+d),E 0 */ - RESXXREG(0, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x84: /* RES (IY+d),H 0 */ - RESXXREG(0, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x85: /* RES (IY+d),L 0 */ - RESXXREG(0, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x86: /* RES (IY+d) 0 */ - RESXX(0, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x87: /* RES (IY+d),A 0 */ - RESXXREG(0, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x88: /* RES (IY+d),B 1 */ - RESXXREG(1, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x89: /* RES (IY+d),C 1 */ - RESXXREG(1, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8a: /* RES (IY+d),D 1 */ - RESXXREG(1, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8b: /* RES (IY+d),E 1 */ - RESXXREG(1, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8c: /* RES (IY+d),H 1 */ - RESXXREG(1, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8d: /* RES (IY+d),L 1 */ - RESXXREG(1, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8e: /* RES (IY+d) 1 */ - RESXX(1, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x8f: /* RES (IY+d),A 1 */ - RESXXREG(1, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x90: /* RES (IY+d),B 2 */ - RESXXREG(2, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x91: /* RES (IY+d),C 2 */ - RESXXREG(2, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x92: /* RES (IY+d),D 2 */ - RESXXREG(2, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x93: /* RES (IY+d),E 2 */ - RESXXREG(2, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x94: /* RES (IY+d),H 2 */ - RESXXREG(2, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x95: /* RES (IY+d),L 2 */ - RESXXREG(2, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x96: /* RES (IY+d) 2 */ - RESXX(2, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x97: /* RES (IY+d),A 2 */ - RESXXREG(2, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x98: /* RES (IY+d),B 3 */ - RESXXREG(3, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x99: /* RES (IY+d),C 3 */ - RESXXREG(3, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9a: /* RES (IY+d),D 3 */ - RESXXREG(3, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9b: /* RES (IY+d),E 3 */ - RESXXREG(3, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9c: /* RES (IY+d),H 3 */ - RESXXREG(3, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9d: /* RES (IY+d),L 3 */ - RESXXREG(3, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9e: /* RES (IY+d) 3 */ - RESXX(3, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0x9f: /* RES (IY+d),A 3 */ - RESXXREG(3, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa0: /* RES (IY+d),B 4 */ - RESXXREG(4, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa1: /* RES (IY+d),C 4 */ - RESXXREG(4, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa2: /* RES (IY+d),D 4 */ - RESXXREG(4, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa3: /* RES (IY+d),E 4 */ - RESXXREG(4, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa4: /* RES (IY+d),H 4 */ - RESXXREG(4, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa5: /* RES (IY+d),L 4 */ - RESXXREG(4, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa6: /* RES (IY+d) 4 */ - RESXX(4, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa7: /* RES (IY+d),A 4 */ - RESXXREG(4, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa8: /* RES (IY+d),B 5 */ - RESXXREG(5, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xa9: /* RES (IY+d),C 5 */ - RESXXREG(5, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xaa: /* RES (IY+d),D 5 */ - RESXXREG(5, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xab: /* RES (IY+d),E 5 */ - RESXXREG(5, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xac: /* RES (IY+d),H 5 */ - RESXXREG(5, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xad: /* RES (IY+d),L 5 */ - RESXXREG(5, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xae: /* RES (IY+d) 5 */ - RESXX(5, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xaf: /* RES (IY+d),A 5 */ - RESXXREG(5, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb0: /* RES (IY+d),B 6 */ - RESXXREG(6, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb1: /* RES (IY+d),C 6 */ - RESXXREG(6, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb2: /* RES (IY+d),D 6 */ - RESXXREG(6, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb3: /* RES (IY+d),E 6 */ - RESXXREG(6, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb4: /* RES (IY+d),H 6 */ - RESXXREG(6, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb5: /* RES (IY+d),L 6 */ - RESXXREG(6, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb6: /* RES (IY+d) 6 */ - RESXX(6, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb7: /* RES (IY+d),A 6 */ - RESXXREG(6, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb8: /* RES (IY+d),B 7 */ - RESXXREG(7, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xb9: /* RES (IY+d),C 7 */ - RESXXREG(7, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xba: /* RES (IY+d),D 7 */ - RESXXREG(7, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xbb: /* RES (IY+d),E 7 */ - RESXXREG(7, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xbc: /* RES (IY+d),H 7 */ - RESXXREG(7, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xbd: /* RES (IY+d),L 7 */ - RESXXREG(7, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xbe: /* RES (IY+d) 7 */ - RESXX(7, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xbf: /* RES (IY+d),A 7 */ - RESXXREG(7, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc0: /* SET (IY+d),B 0 */ - SETXXREG(0, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc1: /* SET (IY+d),C 0 */ - SETXXREG(0, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc2: /* SET (IY+d),D 0 */ - SETXXREG(0, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc3: /* SET (IY+d),E 0 */ - SETXXREG(0, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc4: /* SET (IY+d),H 0 */ - SETXXREG(0, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc5: /* SET (IY+d),L 0 */ - SETXXREG(0, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc6: /* SET (IY+d) 0 */ - SETXX(0, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc7: /* SET (IY+d),A 0 */ - SETXXREG(0, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc8: /* SET (IY+d),B 1 */ - SETXXREG(1, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xc9: /* SET (IY+d),C 1 */ - SETXXREG(1, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xca: /* SET (IY+d),D 1 */ - SETXXREG(1, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xcb: /* SET (IY+d),E 1 */ - SETXXREG(1, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xcc: /* SET (IY+d),H 1 */ - SETXXREG(1, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xcd: /* SET (IY+d),L 1 */ - SETXXREG(1, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xce: /* SET (IY+d) 1 */ - SETXX(1, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xcf: /* SET (IY+d),A 1 */ - SETXXREG(1, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd0: /* SET (IY+d),B 2 */ - SETXXREG(2, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd1: /* SET (IY+d),C 2 */ - SETXXREG(2, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd2: /* SET (IY+d),D 2 */ - SETXXREG(2, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd3: /* SET (IY+d),E 2 */ - SETXXREG(2, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd4: /* SET (IY+d),H 2 */ - SETXXREG(2, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd5: /* SET (IY+d),L 2 */ - SETXXREG(2, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd6: /* SET (IY+d) 2 */ - SETXX(2, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd7: /* SET (IY+d),A 2 */ - SETXXREG(2, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd8: /* SET (IY+d),B 3 */ - SETXXREG(3, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xd9: /* SET (IY+d),C 3 */ - SETXXREG(3, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xda: /* SET (IY+d),D 3 */ - SETXXREG(3, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xdb: /* SET (IY+d),E 3 */ - SETXXREG(3, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xdc: /* SET (IY+d),H 3 */ - SETXXREG(3, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xdd: /* SET (IY+d),L 3 */ - SETXXREG(3, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xde: /* SET (IY+d) 3 */ - SETXX(3, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xdf: /* SET (IY+d),A 3 */ - SETXXREG(3, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe0: /* SET (IY+d),B 4 */ - SETXXREG(4, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe1: /* SET (IY+d),C 4 */ - SETXXREG(4, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe2: /* SET (IY+d),D 4 */ - SETXXREG(4, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe3: /* SET (IY+d),E 4 */ - SETXXREG(4, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe4: /* SET (IY+d),H 4 */ - SETXXREG(4, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe5: /* SET (IY+d),L 4 */ - SETXXREG(4, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe6: /* SET (IY+d) 4 */ - SETXX(4, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe7: /* SET (IY+d),A 4 */ - SETXXREG(4, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe8: /* SET (IY+d),B 5 */ - SETXXREG(5, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xe9: /* SET (IY+d),C 5 */ - SETXXREG(5, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xea: /* SET (IY+d),D 5 */ - SETXXREG(5, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xeb: /* SET (IY+d),E 5 */ - SETXXREG(5, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xec: /* SET (IY+d),H 5 */ - SETXXREG(5, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xed: /* SET (IY+d),L 5 */ - SETXXREG(5, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xee: /* SET (IY+d) 5 */ - SETXX(5, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xef: /* SET (IY+d),A 5 */ - SETXXREG(5, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf0: /* SET (IY+d),B 6 */ - SETXXREG(6, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf1: /* SET (IY+d),C 6 */ - SETXXREG(6, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf2: /* SET (IY+d),D 6 */ - SETXXREG(6, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf3: /* SET (IY+d),E 6 */ - SETXXREG(6, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf4: /* SET (IY+d),H 6 */ - SETXXREG(6, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf5: /* SET (IY+d),L 6 */ - SETXXREG(6, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf6: /* SET (IY+d) 6 */ - SETXX(6, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf7: /* SET (IY+d),A 6 */ - SETXXREG(6, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf8: /* SET (IY+d),B 7 */ - SETXXREG(7, reg_b, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xf9: /* SET (IY+d),C 7 */ - SETXXREG(7, reg_c, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xfa: /* SET (IY+d),D 7 */ - SETXXREG(7, reg_d, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xfb: /* SET (IY+d),E 7 */ - SETXXREG(7, reg_e, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xfc: /* SET (IY+d),H 7 */ - SETXXREG(7, reg_h, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xfd: /* SET (IY+d),L 7 */ - SETXXREG(7, reg_l, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xfe: /* SET (IY+d) 7 */ - SETXX(7, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - case 0xff: /* SET (IY+d),A 7 */ - SETXXREG(7, reg_a, IY_WORD_OFF(iip2), 4, 4, 15, 4); - break; - default: - INC_PC(4); - } -} - -static void opcode_fd(BYTE ip1, BYTE ip2, BYTE ip3, WORD ip12, WORD ip23) -{ - switch (ip1) { - case 0x00: /* NOP */ - NOP(8, 2); - break; - case 0x01: /* LD BC # */ - LDW(ip23, reg_b, reg_c, 10, 0, 4); - break; - case 0x02: /* LD (BC) A */ - STREG(BC_WORD(), reg_a, 8, 3, 2); - break; - case 0x03: /* INC BC */ - DECINC(INC_BC_WORD(), 10, 2); - break; - case 0x04: /* INC B */ - INCREG(reg_b, 7, 2); - break; - case 0x05: /* DEC B */ - DECREG(reg_b, 7, 2); - break; - case 0x06: /* LD B # */ - LDREG(reg_b, ip2, 4, 5, 3); - break; - case 0x07: /* RLCA */ - RLCA(8, 2); - break; - case 0x08: /* EX AF AF' */ - EXAFAF(12, 2); - break; - case 0x09: /* ADD IY BC */ - ADDXXREG(reg_iyh, reg_iyl, reg_b, reg_c, 15, 2); - break; - case 0x0a: /* LD A (BC) */ - LDREG(reg_a, LOAD(BC_WORD()), 8, 3, 2); - break; - case 0x0b: /* DEC BC */ - DECINC(DEC_BC_WORD(), 10, 2); - break; - case 0x0c: /* INC C */ - INCREG(reg_c, 7, 2); - break; - case 0x0d: /* DEC C */ - DECREG(reg_c, 7, 2); - break; - case 0x0e: /* LD C # */ - LDREG(reg_c, ip2, 4, 5, 3); - break; - case 0x0f: /* RRCA */ - RRCA(8, 2); - break; - case 0x10: /* DJNZ */ - DJNZ(ip2, 3); - break; - case 0x11: /* LD DE # */ - LDW(ip23, reg_d, reg_e, 10, 0, 4); - break; - case 0x12: /* LD (DE) A */ - STREG(DE_WORD(), reg_a, 8, 3, 2); - break; - case 0x13: /* INC DE */ - DECINC(INC_DE_WORD(), 10, 2); - break; - case 0x14: /* INC D */ - INCREG(reg_d, 7, 2); - break; - case 0x15: /* DEC D */ - DECREG(reg_d, 7, 2); - break; - case 0x16: /* LD D # */ - LDREG(reg_d, ip2, 4, 5, 3); - break; - case 0x17: /* RLA */ - RLA(8, 2); - break; - case 0x19: /* ADD IY DE */ - ADDXXREG(reg_iyh, reg_iyl, reg_d, reg_e, 15, 2); - break; - case 0x1a: /* LD A (DE) */ - LDREG(reg_a, LOAD(DE_WORD()), 8, 3, 2); - break; - case 0x1b: /* DEC DE */ - DECINC(DEC_DE_WORD(), 10, 2); - break; - case 0x1c: /* INC E */ - INCREG(reg_e, 7, 2); - break; - case 0x1d: /* DEC E */ - DECREG(reg_e, 7, 2); - break; - case 0x1e: /* LD E # */ - LDREG(reg_e, ip2, 4, 5, 3); - break; - case 0x1f: /* RRA */ - RRA(8, 2); - break; - case 0x20: /* JR NZ */ - BRANCH(!LOCAL_ZERO(), ip2, 3); - break; - case 0x21: /* LD IY # */ - LDW(ip23, reg_iyh, reg_iyl, 10, 4, 4); - break; - case 0x22: /* LD (WORD) IY */ - STW(ip23, reg_iyh, reg_iyl, 4, 9, 7, 4); - break; - case 0x23: /* INC IY */ - DECINC(INC_IY_WORD(), 10, 2); - break; - case 0x24: /* INC IYH */ - INCREG(reg_iyh, 7, 2); - break; - case 0x25: /* DEC IYH */ - DECREG(reg_iyh, 7, 2); - break; - case 0x26: /* LD IYH # */ - LDREG(reg_iyh, ip2, 4, 5, 3); - break; - case 0x27: /* DAA */ - DAA(8, 2); - break; - case 0x28: /* JR Z */ - BRANCH(LOCAL_ZERO(), ip2, 3); - break; - case 0x29: /* ADD IY IY */ - ADDXXREG(reg_iyh, reg_iyl, reg_iyh, reg_iyl, 15, 2); - break; - case 0x2a: /* LD IY (WORD) */ - LDIND(ip23, reg_iyh, reg_iyl, 4, 4, 12, 4); - break; - case 0x2b: /* DEC IY */ - DECINC(DEC_IY_WORD(), 10, 2); - break; - case 0x2c: /* INC IYL */ - INCREG(reg_iyl, 7, 2); - break; - case 0x2d: /* DEC IYL */ - DECREG(reg_iyl, 7, 2); - break; - case 0x2e: /* LD IYL # */ - LDREG(reg_iyl, ip2, 4, 5, 3); - break; - case 0x2f: /* CPL */ - CPL(8, 2); - break; - case 0x30: /* JR NC */ - BRANCH(!LOCAL_CARRY(), ip2, 3); - break; - case 0x31: /* LD SP # */ - LDSP(ip23, 10, 0, 4); - break; - case 0x32: /* LD (WORD) A */ - STREG(ip23, reg_a, 10, 7, 4); - break; - case 0x33: /* INC SP */ - DECINC(reg_sp++, 10, 2); - break; - case 0x34: /* INC (IY+d) */ - INCXXIND(IY_WORD_OFF(ip2), 4, 7, 12, 3); - break; - case 0x35: /* DEC (IY+d) */ - DECXXIND(IY_WORD_OFF(ip2), 4, 7, 12, 3); - break; - case 0x36: /* LD (IY+d) # */ - STREG(IY_WORD_OFF(ip2), ip3, 8, 11, 4); - break; - case 0x37: /* SCF */ - SCF(8, 2); - break; - case 0x38: /* JR C */ - BRANCH(LOCAL_CARRY(), ip2, 3); - break; - case 0x39: /* ADD IY SP */ - ADDXXSP(reg_iyh, reg_iyl, 15, 2); - break; - case 0x3a: /* LD A (WORD) */ - LDREG(reg_a, LOAD(ip23), 10, 7, 4); - break; - case 0x3b: /* DEC SP */ - DECINC(reg_sp--, 10, 2); - break; - case 0x3c: /* INC A */ - INCREG(reg_a, 7, 2); - break; - case 0x3d: /* DEC A */ - DECREG(reg_a, 7, 2); - break; - case 0x3e: /* LD A # */ - LDREG(reg_a, ip2, 4, 5, 3); - break; - case 0x3f: /* CCF */ - CCF(8, 2); - break; - case 0x40: /* LD B B */ - LDREG(reg_b, reg_b, 0, 4, 2); - break; - case 0x41: /* LD B C */ - LDREG(reg_b, reg_c, 0, 4, 2); - break; - case 0x42: /* LD B D */ - LDREG(reg_b, reg_d, 0, 4, 2); - break; - case 0x43: /* LD B E */ - LDREG(reg_b, reg_e, 0, 4, 2); - break; - case 0x44: /* LD B IYH */ - LDREG(reg_b, reg_iyh, 0, 4, 2); - break; - case 0x45: /* LD B IYL */ - LDREG(reg_b, reg_iyl, 0, 4, 2); - break; - case 0x46: /* LD B (IY+d) */ - LDREG(reg_b, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x47: /* LD B A */ - LDREG(reg_b, reg_a, 0, 4, 2); - break; - case 0x48: /* LD C B */ - LDREG(reg_c, reg_b, 0, 4, 2); - break; - case 0x49: /* LD C C */ - LDREG(reg_c, reg_c, 0, 4, 2); - break; - case 0x4a: /* LD C D */ - LDREG(reg_c, reg_d, 0, 4, 2); - break; - case 0x4b: /* LD C E */ - LDREG(reg_c, reg_e, 0, 4, 2); - break; - case 0x4c: /* LD C IYH */ - LDREG(reg_c, reg_iyh, 0, 4, 2); - break; - case 0x4d: /* LD C IYL */ - LDREG(reg_c, reg_iyl, 0, 4, 2); - break; - case 0x4e: /* LD C (IY+d) */ - LDREG(reg_c, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x4f: /* LD C A */ - LDREG(reg_c, reg_a, 0, 4, 2); - break; - case 0x50: /* LD D B */ - LDREG(reg_d, reg_b, 0, 4, 2); - break; - case 0x51: /* LD D C */ - LDREG(reg_d, reg_c, 0, 4, 2); - break; - case 0x52: /* LD D D */ - LDREG(reg_d, reg_d, 0, 4, 2); - break; - case 0x53: /* LD D E */ - LDREG(reg_d, reg_e, 0, 4, 2); - break; - case 0x54: /* LD D IYH */ - LDREG(reg_d, reg_iyh, 0, 4, 2); - break; - case 0x55: /* LD D IYL */ - LDREG(reg_d, reg_iyl, 0, 4, 2); - break; - case 0x56: /* LD D (IY+d) */ - LDREG(reg_d, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x57: /* LD D A */ - LDREG(reg_d, reg_a, 0, 4, 2); - break; - case 0x58: /* LD E B */ - LDREG(reg_e, reg_b, 0, 4, 2); - break; - case 0x59: /* LD E C */ - LDREG(reg_e, reg_c, 0, 4, 2); - break; - case 0x5a: /* LD E D */ - LDREG(reg_e, reg_d, 0, 4, 2); - break; - case 0x5b: /* LD E E */ - LDREG(reg_e, reg_e, 0, 4, 2); - break; - case 0x5c: /* LD E IYH */ - LDREG(reg_e, reg_iyh, 0, 4, 2); - break; - case 0x5d: /* LD E IYL */ - LDREG(reg_e, reg_iyl, 0, 4, 2); - break; - case 0x5e: /* LD E (IY+d) */ - LDREG(reg_e, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x5f: /* LD E A */ - LDREG(reg_e, reg_a, 0, 4, 2); - break; - case 0x60: /* LD IYH B */ - LDREG(reg_iyh, reg_b, 0, 4, 2); - break; - case 0x61: /* LD IYH C */ - LDREG(reg_iyh, reg_c, 0, 4, 2); - break; - case 0x62: /* LD IYH D */ - LDREG(reg_iyh, reg_d, 0, 4, 2); - break; - case 0x63: /* LD IYH E */ - LDREG(reg_iyh, reg_e, 0, 4, 2); - break; - case 0x64: /* LD IYH IYH */ - LDREG(reg_iyh, reg_iyh, 0, 4, 2); - break; - case 0x65: /* LD IYH IYL */ - LDREG(reg_iyh, reg_iyl, 0, 4, 2); - break; - case 0x66: /* LD H (IY+d) */ - LDREG(reg_h, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x67: /* LD IYH A */ - LDREG(reg_iyh, reg_a, 0, 4, 2); - break; - case 0x68: /* LD IYL B */ - LDREG(reg_iyl, reg_b, 0, 4, 2); - break; - case 0x69: /* LD IYL C */ - LDREG(reg_iyl, reg_c, 0, 4, 2); - break; - case 0x6a: /* LD IYL D */ - LDREG(reg_iyl, reg_d, 0, 4, 2); - break; - case 0x6b: /* LD IYL E */ - LDREG(reg_iyl, reg_e, 0, 4, 2); - break; - case 0x6c: /* LD IYL IYH */ - LDREG(reg_iyl, reg_iyh, 0, 4, 2); - break; - case 0x6d: /* LD IYL IYL */ - LDREG(reg_iyl, reg_iyl, 0, 4, 2); - break; - case 0x6e: /* LD L (IY+d) */ - LDREG(reg_l, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x6f: /* LD IYL A */ - LDREG(reg_iyl, reg_a, 0, 4, 2); - break; - case 0x70: /* LD (IY+d) B */ - STREG(IY_WORD_OFF(ip2), reg_b, 8, 11, 3); - break; - case 0x71: /* LD (IY+d) C */ - STREG(IY_WORD_OFF(ip2), reg_c, 8, 11, 3); - break; - case 0x72: /* LD (IY+d) D */ - STREG(IY_WORD_OFF(ip2), reg_d, 8, 11, 3); - break; - case 0x73: /* LD (IY+d) E */ - STREG(IY_WORD_OFF(ip2), reg_e, 8, 11, 3); - break; - case 0x74: /* LD (IY+d) H */ - STREG(IY_WORD_OFF(ip2), reg_h, 8, 11, 3); - break; - case 0x75: /* LD (IY+d) L */ - STREG(IY_WORD_OFF(ip2), reg_l, 8, 11, 3); - break; - case 0x76: /* HALT */ - HALT(); - break; - case 0x77: /* LD (IY+d) A */ - STREG(IY_WORD_OFF(ip2), reg_a, 8, 11, 3); - break; - case 0x78: /* LD A B */ - LDREG(reg_a, reg_b, 0, 4, 2); - break; - case 0x79: /* LD A C */ - LDREG(reg_a, reg_c, 0, 4, 2); - break; - case 0x7a: /* LD A D */ - LDREG(reg_a, reg_d, 0, 4, 2); - break; - case 0x7b: /* LD A E */ - LDREG(reg_a, reg_e, 0, 4, 2); - break; - case 0x7c: /* LD A IYH */ - LDREG(reg_a, reg_iyh, 0, 4, 2); - break; - case 0x7d: /* LD A IYL */ - LDREG(reg_a, reg_iyl, 0, 4, 2); - break; - case 0x7e: /* LD A (IY+d) */ - LDREG(reg_a, LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x7f: /* LD A A */ - LDREG(reg_a, reg_a, 0, 4, 2); - break; - case 0x80: /* ADD B */ - ADD(reg_b, 0, 4, 2); - break; - case 0x81: /* ADD C */ - ADD(reg_c, 0, 4, 2); - break; - case 0x82: /* ADD D */ - ADD(reg_d, 0, 4, 2); - break; - case 0x83: /* ADD E */ - ADD(reg_e, 0, 4, 2); - break; - case 0x84: /* ADD IYH */ - ADD(reg_iyh, 0, 4, 2); - break; - case 0x85: /* ADD IYL */ - ADD(reg_iyl, 0, 4, 2); - break; - case 0x86: /* ADD (IY+d) */ - ADD(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x87: /* ADD A */ - ADD(reg_a, 0, 4, 2); - break; - case 0x88: /* ADC B */ - ADC(reg_b, 0, 4, 2); - break; - case 0x89: /* ADC C */ - ADC(reg_c, 0, 4, 2); - break; - case 0x8a: /* ADC D */ - ADC(reg_d, 0, 4, 2); - break; - case 0x8b: /* ADC E */ - ADC(reg_e, 0, 4, 2); - break; - case 0x8c: /* ADC IYH */ - ADC(reg_iyh, 0, 4, 2); - break; - case 0x8d: /* ADC IYL */ - ADC(reg_iyl, 0, 4, 2); - break; - case 0x8e: /* ADC (IY+d) */ - ADC(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); - break; - case 0x8f: /* ADC A */ - ADC(reg_a, 0, 4, 2); - break; - case 0x90: /* SUB B */ - SUB(reg_b, 0, 4, 2); - break; - case 0x91: /* SUB C */ - SUB(reg_c, 0, 4, 2); - break; - case 0x92: /* SUB D */ - SUB(reg_d, 0, 4, 2); - break; - case 0x93: /* SUB E */ - SUB(reg_e, 0, 4, 2); + case 0x52: /* SBC HL DE */ + SBCHLREG(reg_d, reg_e); break; - case 0x94: /* SUB IYH */ - SUB(reg_iyh, 0, 4, 2); + case 0x53: /* LD (WORD) DE */ + STW(ip23, reg_d, reg_e, 4, 13, 3, 4); break; - case 0x95: /* SUB IYL */ - SUB(reg_iyl, 0, 4, 2); + case 0x54: /* undoc NEG */ + NEG(); break; - case 0x96: /* SUB (IY+d) */ - SUB(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x55: /* undoc RETN */ + RETNI(); break; - case 0x97: /* SUB A */ - SUB(reg_a, 0, 4, 2); + case 0x56: /* IM1 */ + IM(1); break; - case 0x98: /* SBC B */ - SBC(reg_b, 0, 4, 2); + case 0x57: /* LD A I */ + LDAIR(reg_i); break; - case 0x99: /* SBC C */ - SBC(reg_c, 0, 4, 2); + case 0x58: /* IN E BC */ + INBC(reg_e, 10, 2, 2); break; - case 0x9a: /* SBC D */ - SBC(reg_d, 0, 4, 2); + case 0x59: /* OUT BC E */ + OUTBC(reg_e, 10, 2, 2); break; - case 0x9b: /* SBC E */ - SBC(reg_e, 0, 4, 2); + case 0x5a: /* ADC HL DE */ + ADCHLREG(reg_d, reg_e); break; - case 0x9c: /* SBC IYH */ - SBC(reg_iyh, 0, 4, 2); + case 0x5b: /* LD DE (WORD) */ + LDIND(ip23, reg_d, reg_e, 4, 4, 12, 4); break; - case 0x9d: /* SBC IYL */ - SBC(reg_iyl, 0, 4, 2); + case 0x5c: /* undoc NEG */ + NEG(); break; - case 0x9e: /* SBC (IY+d) */ - SBC(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x5d: /* undoc RETN */ + RETNI(); break; - case 0x9f: /* SBC A */ - SBC(reg_a, 0, 4, 2); + case 0x5e: /* IM2 */ + IM(2); break; - case 0xa0: /* AND B */ - AND(reg_b, 0, 4, 2); + case 0x5f: /* LD A R */ + LDAIR((uint8_t)(CLK & 0xff)); break; - case 0xa1: /* AND C */ - AND(reg_c, 0, 4, 2); + case 0x60: /* IN H BC */ + INBC(reg_h, 10, 2, 2); break; - case 0xa2: /* AND D */ - AND(reg_d, 0, 4, 2); + case 0x61: /* OUT BC H */ + OUTBC(reg_h, 10, 2, 2); break; - case 0xa3: /* AND E */ - AND(reg_e, 0, 4, 2); + case 0x62: /* SBC HL HL */ + SBCHLREG(reg_h, reg_l); break; - case 0xa4: /* AND IYH */ - AND(reg_iyh, 0, 4, 2); + case 0x63: /* LD (WORD) HL */ + STW(ip23, reg_h, reg_l, 4, 13, 3, 4); break; - case 0xa5: /* AND IYL */ - AND(reg_iyl, 0, 4, 2); + case 0x64: /* undoc NEG */ + NEG(); break; - case 0xa6: /* AND (IY+d) */ - AND(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x65: /* undoc RETN */ + RETNI(); break; - case 0xa7: /* AND A */ - AND(reg_a, 0, 4, 2); + case 0x66: /* undoc IM0 */ + IM(0); break; - case 0xa8: /* XOR B */ - XOR(reg_b, 0, 4, 2); + case 0x67: /* RRD */ + RRD(); break; - case 0xa9: /* XOR C */ - XOR(reg_c, 0, 4, 2); + case 0x68: /* IN L BC */ + INBC(reg_l, 10, 2, 2); break; - case 0xaa: /* XOR D */ - XOR(reg_d, 0, 4, 2); + case 0x69: /* OUT BC L */ + OUTBC(reg_l, 10, 2, 2); break; - case 0xab: /* XOR E */ - XOR(reg_e, 0, 4, 2); + case 0x6a: /* ADC HL HL */ + ADCHLREG(reg_h, reg_l); break; - case 0xac: /* XOR IYH */ - XOR(reg_iyh, 0, 4, 2); + case 0x6b: /* LD HL (WORD) */ + LDIND(ip23, reg_h, reg_l, 4, 4, 12, 4); break; - case 0xad: /* XOR IYL */ - XOR(reg_iyl, 0, 4, 2); + case 0x6c: /* undoc NEG */ + NEG(); break; - case 0xae: /* XOR (IY+d) */ - XOR(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x6d: /* undoc RETN */ + RETNI(); break; - case 0xaf: /* XOR A */ - XOR(reg_a, 0, 4, 2); + case 0x6e: /* undoc IM0 */ + IM(0); break; - case 0xb0: /* OR B */ - OR(reg_b, 0, 4, 2); + case 0x6f: /* RLD */ + RLD(); break; - case 0xb1: /* OR C */ - OR(reg_c, 0, 4, 2); + case 0x70: /* IN F BC */ + INBC0(10, 2, 2); break; - case 0xb2: /* OR D */ - OR(reg_d, 0, 4, 2); + case 0x71: /* OUT BC #0 */ + OUTBC(0, 10, 2, 2); break; - case 0xb3: /* OR E */ - OR(reg_e, 0, 4, 2); + case 0x72: /* SBC HL SP */ + SBCHLSP(); break; - case 0xb4: /* OR IYH */ - OR(reg_iyh, 0, 4, 2); + case 0x73: /* LD (WORD) SP */ + STSPW(ip23, 4, 13, 3, 4); break; - case 0xb5: /* OR IYL */ - OR(reg_iyl, 0, 4, 2); + case 0x74: /* undoc NEG */ + NEG(); break; - case 0xb6: /* OR (IY+d) */ - OR(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x75: /* undoc RETN */ + RETNI(); break; - case 0xb7: /* OR A */ - OR(reg_a, 0, 4, 2); + case 0x76: /* undoc IM1 */ + IM(1); break; - case 0xb8: /* CP B */ - CP(reg_b, 0, 4, 2); + case 0x77: /* undoc NOP */ + NOP(8, 2); break; - case 0xb9: /* CP C */ - CP(reg_c, 0, 4, 2); + case 0x78: /* IN A BC */ + INBC(reg_a, 10, 2, 2); break; - case 0xba: /* CP D */ - CP(reg_d, 0, 4, 2); + case 0x79: /* OUT BC A */ + OUTBC(reg_a, 10, 2, 2); break; - case 0xbb: /* CP E */ - CP(reg_e, 0, 4, 2); + case 0x7a: /* ADC HL SP */ + ADCHLSP(); break; - case 0xbc: /* CP IYH */ - CP(reg_iyh, 0, 4, 2); + case 0x7b: /* LD SP (WORD) */ + LDSPIND(ip23, 4, 4, 12, 4); break; - case 0xbd: /* CP IYL */ - CP(reg_iyl, 0, 4, 2); + case 0x7c: /* undoc NEG */ + NEG(); break; - case 0xbe: /* CP (IY+d) */ - CP(LOAD(IY_WORD_OFF(ip2)), 8, 11, 3); + case 0x7d: /* undoc RETN */ + RETNI(); break; - case 0xbf: /* CP A */ - CP(reg_a, 0, 4, 2); + case 0x7e: /* undoc IM2 */ + IM(2); break; - case 0xc1: /* POP BC */ - POP(reg_b, reg_c, 2); + case 0x7f: /* undoc NOP */ + NOP(8, 2); break; - case 0xc5: /* PUSH BC */ - PUSH(reg_b, reg_c, 2); + case 0xa0: /* LDI */ + LDDI(INC_DE_WORD(), INC_HL_WORD()); break; - case 0xcb: /* OPCODE FD CB */ - opcode_fd_cb((BYTE)ip2, (BYTE)ip3, (WORD)ip23); + case 0xa1: /* CPI */ + CPDI(INC_HL_WORD(),reg_wz++); break; - case 0xd1: /* POP DE */ - POP(reg_d, reg_e, 2); + case 0xa2: /* INI */ + CLK_ADD(CLK, 4); + INDI(INC_HL_WORD()); break; - case 0xd3: /* OUT A */ - OUTA(ip2, 8, 7, 3); + case 0xa3: /* OUTI */ + OUTDI(INC_HL_WORD()); break; - case 0xd5: /* PUSH DE */ - PUSH(reg_d, reg_e, 2); + case 0xa8: /* LDD */ + LDDI(DEC_DE_WORD(), DEC_HL_WORD()); break; - case 0xd9: /* EXX */ - EXX(12, 2); + case 0xa9: /* CPD */ + CPDI(DEC_HL_WORD(),reg_wz--); break; - case 0xdb: /* IN A */ - INA(ip2, 8, 7, 3); + case 0xaa: /* IND */ + CLK_ADD(CLK, 4); + INDI(DEC_HL_WORD()); break; - case 0xdd: /* Skip FD */ - NOP(4, 1); + case 0xab: /* OUTD */ + OUTDI(DEC_HL_WORD()); break; - case 0xe1: /* POP IY */ - POP(reg_iyh, reg_iyl, 2); + case 0xb0: /* LDIR */ + LDDIR(INC_DE_WORD(), INC_HL_WORD()); break; - case 0xe3: /* EX IY (SP) */ - EXXXSP(reg_iyh, reg_iyl, 4, 4, 4, 4, 7, 2); + case 0xb1: /* CPIR */ + CPDIR(INC_HL_WORD()); break; - case 0xe5: /* PUSH IY */ - PUSH(reg_iyh, reg_iyl, 2); + case 0xb2: /* INIR */ + INDIR(INC_HL_WORD()); break; - case 0xe9: /* LD PC IY */ - JMP((IY_WORD()), 8); + case 0xb3: /* OTIR */ + OTDIR(INC_HL_WORD()); break; - case 0xeb: - EXDEHL(8, 2); + case 0xb8: /* LDDR */ + LDDIR(DEC_DE_WORD(), DEC_HL_WORD()); break; - case 0xed: /* Skip FD */ - NOP(4, 1); + case 0xb9: /* CPDR */ + CPDIR(DEC_HL_WORD()); break; - case 0xf1: /* POP AF */ - POP(reg_a, reg_f, 2); + case 0xba: /* INDR */ + INDIR(DEC_HL_WORD()); break; - case 0xf3: /* DI */ - DI(8, 2); + case 0xbb: /* OTDR */ + OTDIR(DEC_HL_WORD()); break; - case 0xf5: /* PUSH AF */ - PUSH(reg_a, reg_f, 2); + case 0xcb: /* NOP */ + NOP(8, 2); break; - case 0xf9: /* LD SP IY */ - LDSP(IY_WORD(), 4, 6, 2); + case 0xdd: /* NOP */ + NOP(8, 2); break; - case 0xfb: /* EI */ - EI(8, 2); + case 0xed: /* NOP */ + NOP(8, 2); break; - case 0xfd: /* Skip FD */ - NOP(4, 1); + case 0xfd: /* NOP */ + NOP(8, 2); break; default: + NOP(8, 2); #ifdef DEBUG_Z80 log_message(LOG_DEFAULT, - "%i PC %04x A%02x F%02x B%02x C%02x D%02x E%02x H%02x L%02x SP%04x OP FD %02x %02x %02x.", - (int)(CLK), (unsigned int)z80_reg_pc, reg_a, reg_f, reg_b, reg_c, reg_d, reg_e, reg_h, reg_l, reg_sp, ip1, ip2, ip3); + "%i PC %04x A%02x F%02x B%02x C%02x D%02x E%02x H%02x L%02x SP%04x OP ED %02x %02x %02x.", + (int)(CLK), (unsigned int)(z80_reg_pc), reg_a, reg_f, reg_b, reg_c, reg_d, reg_e, reg_h, reg_l, reg_sp, ip1, ip2, ip3); #endif - INC_PC(2); } } /* ------------------------------------------------------------------------- */ /* Z80 mainloop. */ +#undef INSTS +#define INSTS(INONE,IX,IY) \ + do { \ + switch (inst_mode) { \ + case INST_IX: \ + IX; \ + break; \ + case INST_IY: \ + IY; \ + break; \ + default: \ + INONE; \ + break; \ + } \ + } while (0) -void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *cpu_alarm_context) +/* use macros to reduce source code and make this more managable. */ +/* INSTS macro handles the base, 0xdd, and 0xfd opcodes. */ +/* When a 0xdd or 0xfd is encountered, inst_mode is set and the "next" + instruction is fetched but sets the proper addressing. */ +/* This lets us cover the undocuemented 0xdd and 0xfd opcodes easier too. */ +static void z80_maincpu_loop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *cpu_alarm_context) { opcode_t opcode; import_registers(); + Z80_SET_DMA_REQUEST(0) + do { while (CLK >= alarm_context_next_pending_clk(cpu_alarm_context)) { alarm_context_dispatch(cpu_alarm_context, CLK); @@ -5732,7 +4326,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c } } - SET_LAST_ADDR(reg_pc); + /* delay IFFs 2 instructions */ + iff1 = iff1_1; + iff2 = iff2_1; + iff1_1 = iff1_2; + iff2_1 = iff2_2; + + if (halt) { + CLK_ADD(CLK, 4); + cpu_int_status->num_dma_per_opcode = 0; + continue; + } + + SET_LAST_ADDR(z80_reg_pc); +fetchmore: FETCH_OPCODE(opcode); #ifdef VICE_DEBUG @@ -5754,7 +4361,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c LDW(p12, reg_b, reg_c, 10, 0, 3); break; case 0x02: /* LD (BC) A */ - STREG(BC_WORD(), reg_a, 4, 3, 1); + STREGWZ(BC_WORD(), reg_a, 4, 3, 1); break; case 0x03: /* INC BC */ DECINC(INC_BC_WORD(), 6, 1); @@ -5772,13 +4379,15 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c RLCA(4, 1); break; case 0x08: /* EX AF AF' */ - EXAFAF(8, 1); + EXAFAF(4, 1); break; - case 0x09: /* ADD HL BC */ - ADDXXREG(reg_h, reg_l, reg_b, reg_c, 11, 1); + case 0x09: /* ADD HL BC; ADD IX BC; ADD IY BC */ + INSTS(ADDXXREG(reg_h, reg_l, reg_b, reg_c, 11, 1), + ADDXXREG(reg_ixh, reg_ixl, reg_b, reg_c, 11, 1), + ADDXXREG(reg_iyh, reg_iyl, reg_b, reg_c, 11, 1)); break; case 0x0a: /* LD A (BC) */ - LDREG(reg_a, LOAD(BC_WORD()), 4, 3, 1); + LDREGWZ(reg_a, BC_WORD(), 4, 3, 1); break; case 0x0b: /* DEC BC */ DECINC(DEC_BC_WORD(), 6, 1); @@ -5802,7 +4411,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c LDW(p12, reg_d, reg_e, 10, 0, 3); break; case 0x12: /* LD (DE) A */ - STREG(DE_WORD(), reg_a, 4, 3, 1); + STREGWZ(DE_WORD(), reg_a, 4, 3, 1); break; case 0x13: /* INC DE */ DECINC(INC_DE_WORD(), 6, 1); @@ -5822,8 +4431,10 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x18: /* JR */ BRANCH(1, p1, 2); break; - case 0x19: /* ADD HL DE */ - ADDXXREG(reg_h, reg_l, reg_d, reg_e, 11, 1); + case 0x19: /* ADD HL DE; ADD IX DE; ADD IY DE */ + INSTS(ADDXXREG(reg_h, reg_l, reg_d, reg_e, 11, 1), + ADDXXREG(reg_ixh, reg_ixl, reg_d, reg_e, 11, 1), + ADDXXREG(reg_iyh, reg_iyl, reg_d, reg_e, 11, 1)); break; case 0x1a: /* LD A (DE) */ LDREG(reg_a, LOAD(DE_WORD()), 4, 3, 1); @@ -5846,23 +4457,35 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x20: /* JR NZ */ BRANCH(!LOCAL_ZERO(), p1, 2); break; - case 0x21: /* LD HL # */ - LDW(p12, reg_h, reg_l, 10, 0, 3); + case 0x21: /* LD HL # ; LD IX #; LD IY # */ + INSTS(LDW(p12, reg_h, reg_l, 10, 0, 3), + LDW(p12, reg_ixh, reg_ixl, 10, 0, 3), + LDW(p12, reg_iyh, reg_iyl, 10, 0, 3)); break; - case 0x22: /* LD (WORD) HL */ - STW(p12, reg_h, reg_l, 4, 9, 3, 3); + case 0x22: /* LD (WORD) HL; LD (WORD) IX; LD (WORD) IY */ + INSTS(STW(p12, reg_h, reg_l, 4, 9, 3, 3), + STW(p12, reg_ixh, reg_ixl, 4, 9, 3, 3), + STW(p12, reg_iyh, reg_iyl, 4, 9, 3, 3)); break; - case 0x23: /* INC HL */ - DECINC(INC_HL_WORD(), 6, 1); + case 0x23: /* INC HL ; INC IX; INC IY */ + INSTS(DECINC(INC_HL_WORD(), 6, 1), + DECINC(INC_IX_WORD(), 6, 1), + DECINC(INC_IY_WORD(), 6, 1)); break; - case 0x24: /* INC H */ - INCREG(reg_h, 4, 1); + case 0x24: /* INC H ; INC IXH ; INC IYH */ + INSTS(INCREG(reg_h, 4, 1), + INCREG(reg_ixh, 4, 1), + INCREG(reg_iyh, 4, 1)); break; - case 0x25: /* DEC H */ - DECREG(reg_h, 4, 1); + case 0x25: /* DEC H ; DEC IXH ; DEC IYH */ + INSTS(DECREG(reg_h, 4, 1), + DECREG(reg_ixh, 4, 1), + DECREG(reg_iyh, 4, 1)); break; - case 0x26: /* LD H # */ - LDREG(reg_h, p1, 4, 3, 2); + case 0x26: /* LD H # ; LD IXH # ; LD IYH # */ + INSTS(LDREG(reg_h, p1, 4, 3, 2), + LDREG(reg_ixh, p1, 4, 3, 2), + LDREG(reg_iyh, p1, 4, 3, 2)); break; case 0x27: /* DAA */ DAA(4, 1); @@ -5870,23 +4493,35 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x28: /* JR Z */ BRANCH(LOCAL_ZERO(), p1, 2); break; - case 0x29: /* ADD HL HL */ - ADDXXREG(reg_h, reg_l, reg_h, reg_l, 11, 1); + case 0x29: /* ADD HL HL ; ADD IX IX ; ADD IY IY */ + INSTS(ADDXXREG(reg_h, reg_l, reg_h, reg_l, 11, 1), + ADDXXREG(reg_ixh, reg_ixl, reg_ixh, reg_ixl, 11, 1), + ADDXXREG(reg_iyh, reg_iyl, reg_iyh, reg_iyl, 11, 1)); break; - case 0x2a: /* LD HL (WORD) */ - LDIND(p12, reg_h, reg_l, 4, 4, 8, 3); + case 0x2a: /* LD HL (WORD) ; LD IX (WORD) ; LD IY (WORD) */ + INSTS(LDIND(p12, reg_h, reg_l, 4, 4, 8, 3), + LDIND(p12, reg_ixh, reg_ixl, 4, 4, 8, 3), + LDIND(p12, reg_iyh, reg_iyl, 4, 4, 8, 3)); break; - case 0x2b: /* DEC HL */ - DECINC(DEC_HL_WORD(), 6, 1); + case 0x2b: /* DEC HL ; DEC IX ; DEC IY */ + INSTS(DECINC(DEC_HL_WORD(), 6, 1), + DECINC(DEC_IX_WORD(), 6, 1), + DECINC(DEC_IY_WORD(), 6, 1)); break; - case 0x2c: /* INC L */ - INCREG(reg_l, 4, 1); + case 0x2c: /* INC L ; INC IXL ; DEC IYL */ + INSTS(INCREG(reg_l, 4, 1), + INCREG(reg_ixl, 4, 1), + INCREG(reg_iyl, 4, 1)); break; - case 0x2d: /* DEC L */ - DECREG(reg_l, 4, 1); + case 0x2d: /* DEC L ; DEC IXL ; DEC IYL */ + INSTS(DECREG(reg_l, 4, 1), + DECREG(reg_ixl, 4, 1), + DECREG(reg_iyl, 4, 1)); break; - case 0x2e: /* LD L # */ - LDREG(reg_l, p1, 4, 3, 2); + case 0x2e: /* LD L # ; LD IXL # ; LD IYL # */ + INSTS(LDREG(reg_l, p1, 4, 3, 2), + LDREG(reg_ixl, p1, 4, 3, 2), + LDREG(reg_iyl, p1, 4, 3, 2)); break; case 0x2f: /* CPL */ CPL(4, 1); @@ -5898,19 +4533,25 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c LDSP(p12, 10, 0, 3); break; case 0x32: /* LD (WORD) A */ - STREG(p12, reg_a, 10, 3, 3); + STREGWZ(p12, reg_a, 10, 3, 3); break; case 0x33: /* INC SP */ DECINC(reg_sp++, 6, 1); break; - case 0x34: /* INC (HL) */ - INCXXIND(HL_WORD(), 4, 4, 3, 1); + case 0x34: /* INC (HL) ; INC (IX+d) ; INC (IY+d) */ + INSTS(INCXXIND(HL_WORD(), 4, 4, 3, 1), + INCXXIND(IX_WORD_OFF(p1), 0, 7, 12, 2), + INCXXIND(IY_WORD_OFF(p1), 0, 7, 12, 2)); break; - case 0x35: /* DEC (HL) */ - DECXXIND(HL_WORD(), 4, 4, 3, 1); + case 0x35: /* DEC (HL) ; DEC (IX+d) ; DEC (IY+d) */ + INSTS(DECXXIND(HL_WORD(), 4, 4, 3, 1), + DECXXIND(IX_WORD_OFF(p1), 0, 7, 12, 2), + DECXXIND(IY_WORD_OFF(p1), 0, 7, 12, 2)); break; - case 0x36: /* LD (HL) # */ - STREG(HL_WORD(), p1, 8, 2, 2); + case 0x36: /* LD (HL) # ; LD (IX+d) # ; LD (IY+d) # */ + INSTS(STREG(HL_WORD(), p1, 8, 2, 2), + STREG(IX_WORD_OFF(p1), p2, 8, 7, 3), + STREG(IY_WORD_OFF(p1), p2, 8, 7, 3)); break; case 0x37: /* SCF */ SCF(4, 1); @@ -5918,11 +4559,13 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x38: /* JR C */ BRANCH(LOCAL_CARRY(), p1, 2); break; - case 0x39: /* ADD HL SP */ - ADDXXSP(reg_h, reg_l, 11, 1); + case 0x39: /* ADD HL SP ; ADD IX SP ; ADD IY SP */ + INSTS(ADDXXSP(reg_h, reg_l, 11, 1), + ADDXXSP(reg_ixh, reg_ixl, 11, 1), + ADDXXSP(reg_iyh, reg_iyl, 11, 1)); break; case 0x3a: /* LD A (WORD) */ - LDREG(reg_a, LOAD(p12), 10, 3, 3); + LDREGWZ(reg_a, p12, 10, 3, 3); break; case 0x3b: /* DEC SP */ DECINC(reg_sp--, 6, 1); @@ -5951,14 +4594,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x43: /* LD B E */ LDREG(reg_b, reg_e, 0, 4, 1); break; - case 0x44: /* LD B H */ - LDREG(reg_b, reg_h, 0, 4, 1); + case 0x44: /* LD B H ; LD B IXH ; LD B IYH */ + INSTS(LDREG(reg_b, reg_h, 0, 4, 1), + LDREG(reg_b, reg_ixh, 0, 4, 1), + LDREG(reg_b, reg_iyh, 0, 4, 1)); break; - case 0x45: /* LD B L */ - LDREG(reg_b, reg_l, 0, 4, 1); + case 0x45: /* LD B L ; LD B IXL ; LD B IYL */ + INSTS(LDREG(reg_b, reg_l, 0, 4, 1), + LDREG(reg_b, reg_ixl, 0, 4, 1), + LDREG(reg_b, reg_iyl, 0, 4, 1)); break; - case 0x46: /* LD B (HL) */ - LDREG(reg_b, LOAD(HL_WORD()), 4, 3, 1); + case 0x46: /* LD B (HL) ; LD B (IX+d) ; LD B (IY+d) */ + INSTS(LDREG(reg_b, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_b, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_b, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x47: /* LD B A */ LDREG(reg_b, reg_a, 0, 4, 1); @@ -5975,14 +4624,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x4b: /* LD C E */ LDREG(reg_c, reg_e, 0, 4, 1); break; - case 0x4c: /* LD C H */ - LDREG(reg_c, reg_h, 0, 4, 1); + case 0x4c: /* LD C H ; LD C IXH ; LD C IYH */ + INSTS(LDREG(reg_c, reg_h, 0, 4, 1), + LDREG(reg_c, reg_ixh, 0, 4, 1), + LDREG(reg_c, reg_iyh, 0, 4, 1)); break; - case 0x4d: /* LD C L */ - LDREG(reg_c, reg_l, 0, 4, 1); + case 0x4d: /* LD C L ; LD C IXL ; LD C IYL */ + INSTS(LDREG(reg_c, reg_l, 0, 4, 1), + LDREG(reg_c, reg_ixl, 0, 4, 1), + LDREG(reg_c, reg_iyl, 0, 4, 1)); break; - case 0x4e: /* LD C (HL) */ - LDREG(reg_c, LOAD(HL_WORD()), 4, 3, 1); + case 0x4e: /* LD C (HL) ; LD C (IX+d) ; LD C (IY+d) */ + INSTS(LDREG(reg_c, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_c, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_c, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x4f: /* LD C A */ LDREG(reg_c, reg_a, 0, 4, 1); @@ -5999,14 +4654,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x53: /* LD D E */ LDREG(reg_d, reg_e, 0, 4, 1); break; - case 0x54: /* LD D H */ - LDREG(reg_d, reg_h, 0, 4, 1); + case 0x54: /* LD D H ; LD D IXH ; LD D IYH */ + INSTS(LDREG(reg_d, reg_h, 0, 4, 1), + LDREG(reg_d, reg_ixh, 0, 4, 1), + LDREG(reg_d, reg_iyh, 0, 4, 1)); break; - case 0x55: /* LD D L */ - LDREG(reg_d, reg_l, 0, 4, 1); + case 0x55: /* LD D L ; LD D IXL ; LD D IYL */ + INSTS(LDREG(reg_d, reg_l, 0, 4, 1), + LDREG(reg_d, reg_ixl, 0, 4, 1), + LDREG(reg_d, reg_iyl, 0, 4, 1)); break; - case 0x56: /* LD D (HL) */ - LDREG(reg_d, LOAD(HL_WORD()), 4, 3, 1); + case 0x56: /* LD D (HL) ; LD D (IX+d) ; LD D (IY+d) */ + INSTS(LDREG(reg_d, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_d, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_d, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x57: /* LD D A */ LDREG(reg_d, reg_a, 0, 4, 1); @@ -6023,89 +4684,141 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x5b: /* LD E E */ LDREG(reg_e, reg_e, 0, 4, 1); break; - case 0x5c: /* LD E H */ - LDREG(reg_e, reg_h, 0, 4, 1); + case 0x5c: /* LD E H ; LD E IXH ; LD E IYH */ + INSTS(LDREG(reg_e, reg_h, 0, 4, 1), + LDREG(reg_e, reg_ixh, 0, 4, 1), + LDREG(reg_e, reg_iyh, 0, 4, 1)); break; - case 0x5d: /* LD E L */ - LDREG(reg_e, reg_l, 0, 4, 1); + case 0x5d: /* LD E L ; LD E IXL ; LD E IYL */ + INSTS(LDREG(reg_e, reg_l, 0, 4, 1), + LDREG(reg_e, reg_ixl, 0, 4, 1), + LDREG(reg_e, reg_iyl, 0, 4, 1)); break; - case 0x5e: /* LD E (HL) */ - LDREG(reg_e, LOAD(HL_WORD()), 4, 3, 1); + case 0x5e: /* LD E (HL) ; LD E (IX+d) ; LD E (IY+d) */ + INSTS(LDREG(reg_e, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_e, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_e, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x5f: /* LD E A */ LDREG(reg_e, reg_a, 0, 4, 1); break; - case 0x60: /* LD H B */ - LDREG(reg_h, reg_b, 0, 4, 1); - break; - case 0x61: /* LD H C */ - LDREG(reg_h, reg_c, 0, 4, 1); - break; - case 0x62: /* LD H D */ - LDREG(reg_h, reg_d, 0, 4, 1); - break; - case 0x63: /* LD H E */ - LDREG(reg_h, reg_e, 0, 4, 1); - break; - case 0x64: /* LD H H */ - LDREG(reg_h, reg_h, 0, 4, 1); - break; - case 0x65: /* LD H L */ - LDREG(reg_h, reg_l, 0, 4, 1); - break; - case 0x66: /* LD H (HL) */ - LDREG(reg_h, LOAD(HL_WORD()), 4, 3, 1); - break; - case 0x67: /* LD H A */ - LDREG(reg_h, reg_a, 0, 4, 1); - break; - case 0x68: /* LD L B */ - LDREG(reg_l, reg_b, 0, 4, 1); - break; - case 0x69: /* LD L C */ - LDREG(reg_l, reg_c, 0, 4, 1); - break; - case 0x6a: /* LD L D */ - LDREG(reg_l, reg_d, 0, 4, 1); - break; - case 0x6b: /* LD L E */ - LDREG(reg_l, reg_e, 0, 4, 1); - break; - case 0x6c: /* LD L H */ - LDREG(reg_l, reg_h, 0, 4, 1); - break; - case 0x6d: /* LD L L */ - LDREG(reg_l, reg_l, 0, 4, 1); - break; - case 0x6e: /* LD L (HL) */ - LDREG(reg_l, LOAD(HL_WORD()), 4, 3, 1); - break; - case 0x6f: /* LD L A */ - LDREG(reg_l, reg_a, 0, 4, 1); - break; - case 0x70: /* LD (HL) B */ - STREG(HL_WORD(), reg_b, 4, 3, 1); - break; - case 0x71: /* LD (HL) C */ - STREG(HL_WORD(), reg_c, 4, 3, 1); - break; - case 0x72: /* LD (HL) D */ - STREG(HL_WORD(), reg_d, 4, 3, 1); - break; - case 0x73: /* LD (HL) E */ - STREG(HL_WORD(), reg_e, 4, 3, 1); - break; - case 0x74: /* LD (HL) H */ - STREG(HL_WORD(), reg_h, 4, 3, 1); - break; - case 0x75: /* LD (HL) L */ - STREG(HL_WORD(), reg_l, 4, 3, 1); + case 0x60: /* LD H B ; LD IXH B ; LD IYH B */ + INSTS(LDREG(reg_h, reg_b, 0, 4, 1), + LDREG(reg_ixh, reg_b, 0, 4, 1), + LDREG(reg_iyh, reg_b, 0, 4, 1)); + break; + case 0x61: /* LD H C ; LD IXH C ; LD IYH C */ + INSTS(LDREG(reg_h, reg_c, 0, 4, 1), + LDREG(reg_ixh, reg_c, 0, 4, 1), + LDREG(reg_iyh, reg_c, 0, 4, 1)); + break; + case 0x62: /* LD H D ; LD IXH D ; LD IYH D */ + INSTS(LDREG(reg_h, reg_d, 0, 4, 1), + LDREG(reg_ixh, reg_d, 0, 4, 1), + LDREG(reg_iyh, reg_d, 0, 4, 1)); + break; + case 0x63: /* LD H E ; LD IXH E ; LD IYH E */ + INSTS(LDREG(reg_h, reg_e, 0, 4, 1), + LDREG(reg_ixh, reg_e, 0, 4, 1), + LDREG(reg_iyh, reg_e, 0, 4, 1)); + break; + case 0x64: /* LD H H ; LD IXH IXH; LD IYH IYH */ + INSTS(LDREG(reg_h, reg_h, 0, 4, 1), + LDREG(reg_ixh, reg_ixh, 0, 4, 1), + LDREG(reg_iyh, reg_iyh, 0, 4, 1)); + break; + case 0x65: /* LD H L ; LD IXH IXL ; LD IYH IYL */ + INSTS(LDREG(reg_h, reg_l, 0, 4, 1), + LDREG(reg_ixh, reg_ixl, 0, 4, 1), + LDREG(reg_iyh, reg_iyl, 0, 4, 1)); + break; + case 0x66: /* LD H (HL) ; LD H (IX+d) ; LD H (IY+d) */ + INSTS(LDREG(reg_h, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_h, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_h, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); + break; + case 0x67: /* LD H A ; LD IXH A ; LD IYH A */ + INSTS(LDREG(reg_h, reg_a, 0, 4, 1), + LDREG(reg_ixh, reg_a, 0, 4, 1), + LDREG(reg_iyh, reg_a, 0, 4, 1)); + break; + case 0x68: /* LD L B ; LD IXH B ; LD IYH B */ + INSTS(LDREG(reg_l, reg_b, 0, 4, 1), + LDREG(reg_ixl, reg_b, 0, 4, 1), + LDREG(reg_iyl, reg_b, 0, 4, 1)); + break; + case 0x69: /* LD L C ; LD IXH C ; LD IYH C */ + INSTS(LDREG(reg_l, reg_c, 0, 4, 1), + LDREG(reg_ixl, reg_c, 0, 4, 1), + LDREG(reg_iyl, reg_c, 0, 4, 1)); + break; + case 0x6a: /* LD L D ; LD IXH D ; LD IYH D */ + INSTS(LDREG(reg_l, reg_d, 0, 4, 1), + LDREG(reg_ixl, reg_d, 0, 4, 1), + LDREG(reg_iyl, reg_d, 0, 4, 1)); + break; + case 0x6b: /* LD L E ; LD IXH E ; LD IYH E */ + INSTS(LDREG(reg_l, reg_e, 0, 4, 1), + LDREG(reg_ixl, reg_e, 0, 4, 1), + LDREG(reg_iyl, reg_e, 0, 4, 1)); + break; + case 0x6c: /* LD L H ; LD IXL LXH ; LD IYL IYH */ + INSTS(LDREG(reg_l, reg_h, 0, 4, 1), + LDREG(reg_ixl, reg_ixh, 0, 4, 1), + LDREG(reg_iyl, reg_iyh, 0, 4, 1)); + break; + case 0x6d: /* LD L L ; LD IXL IXL ; LD IYL IYL */ + INSTS(LDREG(reg_l, reg_l, 0, 4, 1), + LDREG(reg_ixl, reg_ixl, 0, 4, 1), + LDREG(reg_iyl, reg_iyl, 0, 4, 1)); + break; + case 0x6e: /* LD L (HL) ; LD L (IX+d) ; LD L (IY+d) */ + INSTS(LDREG(reg_l, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_l, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_l, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); + break; + case 0x6f: /* LD L A ; LD IXL A ; LD IYL A */ + INSTS(LDREG(reg_l, reg_a, 0, 4, 1), + LDREG(reg_ixl, reg_a, 0, 4, 1), + LDREG(reg_iyl, reg_a, 0, 4, 1)); + break; + case 0x70: /* LD (HL) B ; LD (IX+d) B ; LD (IY+d) B */ + INSTS(STREG(HL_WORD(), reg_b, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_b, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_b, 4, 11, 2)); + break; + case 0x71: /* LD (HL) C ; LD (IX+d) C ; LD (IY+d) C */ + INSTS(STREG(HL_WORD(), reg_c, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_c, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_c, 4, 11, 2)); + break; + case 0x72: /* LD (HL) D ; LD (IX+d) D ; LD (IY+d) D */ + INSTS(STREG(HL_WORD(), reg_d, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_d, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_d, 4, 11, 2)); + break; + case 0x73: /* LD (HL) E ; LD (IX+d) E ; LD (IY+d) E */ + INSTS(STREG(HL_WORD(), reg_e, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_e, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_e, 4, 11, 2)); + break; + case 0x74: /* LD (HL) H ; LD (IX+d) H ; LD (IY+d) H */ + INSTS(STREG(HL_WORD(), reg_h, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_h, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_h, 4, 11, 2)); + break; + case 0x75: /* LD (HL) L ; LD (IX+d) L ; LD (IY+d) L */ + INSTS(STREG(HL_WORD(), reg_l, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_l, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_l, 4, 11, 2)); break; case 0x76: /* HALT */ HALT(); break; - case 0x77: /* LD (HL) A */ - STREG(HL_WORD(), reg_a, 4, 3, 1); + case 0x77: /* LD (HL) A ; LD (IX+d) A ; LD (IY+d) A */ + INSTS(STREG(HL_WORD(), reg_a, 4, 3, 1), + STREG(IX_WORD_OFF(p1), reg_a, 4, 11, 2), + STREG(IY_WORD_OFF(p1), reg_a, 4, 11, 2)); break; case 0x78: /* LD A B */ LDREG(reg_a, reg_b, 0, 4, 1); @@ -6119,14 +4832,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x7b: /* LD A E */ LDREG(reg_a, reg_e, 0, 4, 1); break; - case 0x7c: /* LD A H */ - LDREG(reg_a, reg_h, 0, 4, 1); + case 0x7c: /* LD A H ; LD A IXH ; LD A IYH */ + INSTS(LDREG(reg_a, reg_h, 0, 4, 1), + LDREG(reg_a, reg_ixh, 0, 4, 1), + LDREG(reg_a, reg_iyh, 0, 4, 1)); break; - case 0x7d: /* LD A L */ - LDREG(reg_a, reg_l, 0, 4, 1); + case 0x7d: /* LD A L ; LD A IXL ; LD A IYL */ + INSTS(LDREG(reg_a, reg_l, 0, 4, 1), + LDREG(reg_a, reg_ixl, 0, 4, 1), + LDREG(reg_a, reg_iyl, 0, 4, 1)); break; - case 0x7e: /* LD A (HL) */ - LDREG(reg_a, LOAD(HL_WORD()), 4, 3, 1); + case 0x7e: /* LD A (HL) ; LD A (IX+d) ; LD A (IY+d) */ + INSTS(LDREG(reg_a, LOAD(HL_WORD()), 4, 3, 1), + LDREG(reg_a, LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + LDREG(reg_a, LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x7f: /* LD A A */ LDREG(reg_a, reg_a, 0, 4, 1); @@ -6143,14 +4862,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x83: /* ADD E */ ADD(reg_e, 0, 4, 1); break; - case 0x84: /* ADD H */ - ADD(reg_h, 0, 4, 1); + case 0x84: /* ADD H ; ADD IXH ; ADD IYH */ + INSTS(ADD(reg_h, 0, 4, 1), + ADD(reg_ixh, 0, 4, 1), + ADD(reg_iyh, 0, 4, 1)); break; - case 0x85: /* ADD L */ - ADD(reg_l, 0, 4, 1); + case 0x85: /* ADD L ; ADD IXL ; ADD IYL */ + INSTS(ADD(reg_l, 0, 4, 1), + ADD(reg_ixl, 0, 4, 1), + ADD(reg_iyl, 0, 4, 1)); break; - case 0x86: /* ADD (HL) */ - ADD(LOAD(HL_WORD()), 4, 3, 1); + case 0x86: /* ADD (HL) ; ADD (IX+d) ; ADD (IY+d) */ + INSTS(ADD(LOAD(HL_WORD()), 4, 3, 1), + ADD(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + ADD(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x87: /* ADD A */ ADD(reg_a, 0, 4, 1); @@ -6167,14 +4892,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x8b: /* ADC E */ ADC(reg_e, 0, 4, 1); break; - case 0x8c: /* ADC H */ - ADC(reg_h, 0, 4, 1); + case 0x8c: /* ADC H ; ADC IXH ; ADC IYH */ + INSTS(ADC(reg_h, 0, 4, 1), + ADC(reg_ixh, 0, 4, 1), + ADC(reg_iyh, 0, 4, 1)); break; - case 0x8d: /* ADC L */ - ADC(reg_l, 0, 4, 1); + case 0x8d: /* ADC L ; ADC IXL ; ADC IYL */ + INSTS(ADC(reg_l, 0, 4, 1), + ADC(reg_ixl, 0, 4, 1), + ADC(reg_iyl, 0, 4, 1)); break; - case 0x8e: /* ADC (HL) */ - ADC(LOAD(HL_WORD()), 4, 3, 1); + case 0x8e: /* ADC (HL) ; ADC (IX+d) ; ADC (IY+d) */ + INSTS(ADC(LOAD(HL_WORD()), 4, 3, 1), + ADC(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + ADC(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x8f: /* ADC A */ ADC(reg_a, 0, 4, 1); @@ -6191,14 +4922,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x93: /* SUB E */ SUB(reg_e, 0, 4, 1); break; - case 0x94: /* SUB H */ - SUB(reg_h, 0, 4, 1); + case 0x94: /* SUB H ; SUB IXH ; SUB IYH */ + INSTS(SUB(reg_h, 0, 4, 1), + SUB(reg_ixh, 0, 4, 1), + SUB(reg_iyh, 0, 4, 1)); break; - case 0x95: /* SUB L */ - SUB(reg_l, 0, 4, 1); + case 0x95: /* SUB L ; SUB IXL ; SUB IYL */ + INSTS(SUB(reg_l, 0, 4, 1), + SUB(reg_ixl, 0, 4, 1), + SUB(reg_iyl, 0, 4, 1)); break; - case 0x96: /* SUB (HL) */ - SUB(LOAD(HL_WORD()), 4, 3, 1); + case 0x96: /* SUB (HL) ; SUB (IX+d) ; SUB (IY+d) */ + INSTS(SUB(LOAD(HL_WORD()), 4, 3, 1), + SUB(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + SUB(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x97: /* SUB A */ SUB(reg_a, 0, 4, 1); @@ -6215,14 +4952,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0x9b: /* SBC E */ SBC(reg_e, 0, 4, 1); break; - case 0x9c: /* SBC H */ - SBC(reg_h, 0, 4, 1); + case 0x9c: /* SBC H ; SBC IXH ; SBC IYH */ + INSTS(SBC(reg_h, 0, 4, 1), + SBC(reg_ixh, 0, 4, 1), + SBC(reg_iyh, 0, 4, 1)); break; - case 0x9d: /* SBC L */ - SBC(reg_l, 0, 4, 1); + case 0x9d: /* SBC L ; SBC IXL ; SBC IYL */ + INSTS(SBC(reg_l, 0, 4, 1), + SBC(reg_ixl, 0, 4, 1), + SBC(reg_iyl, 0, 4, 1)); break; - case 0x9e: /* SBC (HL) */ - SBC(LOAD(HL_WORD()), 4, 3, 1); + case 0x9e: /* SBC (HL) ; SBC (IX+d) ; SBC (IY+d) */ + INSTS(SBC(LOAD(HL_WORD()), 4, 3, 1), + SBC(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + SBC(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0x9f: /* SBC A */ SBC(reg_a, 0, 4, 1); @@ -6239,14 +4982,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0xa3: /* AND E */ AND(reg_e, 0, 4, 1); break; - case 0xa4: /* AND H */ - AND(reg_h, 0, 4, 1); + case 0xa4: /* AND H ; AND IXH ; AND IYH */ + INSTS(AND(reg_h, 0, 4, 1), + AND(reg_ixh, 0, 4, 1), + AND(reg_iyh, 0, 4, 1)); break; - case 0xa5: /* AND L */ - AND(reg_l, 0, 4, 1); + case 0xa5: /* AND L ; AND IXL ; AND IYL */ + INSTS(AND(reg_l, 0, 4, 1), + AND(reg_ixl, 0, 4, 1), + AND(reg_iyl, 0, 4, 1)); break; - case 0xa6: /* AND (HL) */ - AND(LOAD(HL_WORD()), 4, 3, 1); + case 0xa6: /* AND (HL) ; AND (IX+d) ; AND (IY+d) */ + INSTS(AND(LOAD(HL_WORD()), 4, 3, 1), + AND(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + AND(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0xa7: /* AND A */ AND(reg_a, 0, 4, 1); @@ -6263,14 +5012,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0xab: /* XOR E */ XOR(reg_e, 0, 4, 1); break; - case 0xac: /* XOR H */ - XOR(reg_h, 0, 4, 1); + case 0xac: /* XOR H ; XOR IXH ; XOR IYH */ + INSTS(XOR(reg_h, 0, 4, 1), + XOR(reg_ixh, 0, 4, 1), + XOR(reg_iyh, 0, 4, 1)); break; - case 0xad: /* XOR L */ - XOR(reg_l, 0, 4, 1); + case 0xad: /* XOR L ; XOR IXL ; XOR IYL */ + INSTS(XOR(reg_l, 0, 4, 1), + XOR(reg_ixl, 0, 4, 1), + XOR(reg_iyl, 0, 4, 1)); break; - case 0xae: /* XOR (HL) */ - XOR(LOAD(HL_WORD()), 4, 3, 1); + case 0xae: /* XOR (HL) ; XOR (IX+d) ; XOR (IY+d) */ + INSTS(XOR(LOAD(HL_WORD()), 4, 3, 1), + XOR(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + XOR(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0xaf: /* XOR A */ XOR(reg_a, 0, 4, 1); @@ -6287,14 +5042,20 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0xb3: /* OR E */ OR(reg_e, 0, 4, 1); break; - case 0xb4: /* OR H */ - OR(reg_h, 0, 4, 1); + case 0xb4: /* OR H ; OR IXH ; OR IYH */ + INSTS(OR(reg_h, 0, 4, 1), + OR(reg_ixh, 0, 4, 1), + OR(reg_iyh, 0, 4, 1)); break; - case 0xb5: /* OR L */ - OR(reg_l, 0, 4, 1); + case 0xb5: /* OR L ; OR IYL ; OR IYL */ + INSTS(OR(reg_l, 0, 4, 1), + OR(reg_ixl, 0, 4, 1), + OR(reg_iyl, 0, 4, 1)); break; - case 0xb6: /* OR (HL) */ - OR(LOAD(HL_WORD()), 4, 3, 1); + case 0xb6: /* OR (HL) ; OR (IX+d) ; OR (IY+d) */ + INSTS(OR(LOAD(HL_WORD()), 4, 3, 1), + OR(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + OR(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0xb7: /* OR A */ OR(reg_a, 0, 4, 1); @@ -6311,20 +5072,26 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c case 0xbb: /* CP E */ CP(reg_e, 0, 4, 1); break; - case 0xbc: /* CP H */ - CP(reg_h, 0, 4, 1); + case 0xbc: /* CP H ; CP IXH ; CP IYH */ + INSTS(CP(reg_h, 0, 4, 1), + CP(reg_ixh, 0, 4, 1), + CP(reg_iyh, 0, 4, 1)); break; - case 0xbd: /* CP L */ - CP(reg_l, 0, 4, 1); + case 0xbd: /* CP L ; CP IXL ; CP IYL */ + INSTS(CP(reg_l, 0, 4, 1), + CP(reg_ixl, 0, 4, 1), + CP(reg_iyl, 0, 4, 1)); break; - case 0xbe: /* CP (HL) */ - CP(LOAD(HL_WORD()), 4, 3, 1); + case 0xbe: /* CP (HL) ; CP (IX+d) ; CP (IY+d) */ + INSTS(CP(LOAD(HL_WORD()), 4, 3, 1), + CP(LOAD(IX_WORD_OFF(p1)), 4, 11, 2), + CP(LOAD(IY_WORD_OFF(p1)), 4, 11, 2)); break; case 0xbf: /* CP A */ CP(reg_a, 0, 4, 1); break; case 0xc0: /* RET NZ */ - RET_COND(!LOCAL_ZERO(), 4, 4, 2, 5, 1); + RET_COND(!LOCAL_ZERO(), 5, 3, 3, 5, 1); break; case 0xc1: /* POP BC */ POP(reg_b, reg_c, 1); @@ -6336,7 +5103,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c JMP(p12, 10); break; case 0xc4: /* CALL NZ */ - CALL_COND(p12, !LOCAL_ZERO(), 3, 3, 4, 10, 3); + CALL_COND(p12, !LOCAL_ZERO(), 3, 3, 11, 10, 3); break; case 0xc5: /* PUSH BC */ PUSH(reg_b, reg_c, 1); @@ -6348,7 +5115,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x00, 3, 3, 5, 1); break; case 0xc8: /* RET Z */ - RET_COND(LOCAL_ZERO(), 4, 4, 2, 5, 1); + RET_COND(LOCAL_ZERO(), 5, 3, 3, 5, 1); break; case 0xc9: /* RET */ RET(4, 4, 2); @@ -6357,10 +5124,12 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c JMP_COND(p12, LOCAL_ZERO(), 10, 10); break; case 0xcb: /* OPCODE CB */ - opcode_cb((BYTE)p1, (BYTE)p2, (BYTE)p3, (WORD)p12, (WORD)p23); + INSTS(opcode_cb((uint8_t)p1, (uint8_t)p2, (uint8_t)p3, (uint16_t)p12, (uint16_t)p23), + opcode_ddfd_cb((uint8_t)p1, (uint8_t)p2, (uint16_t)p12), + opcode_ddfd_cb((uint8_t)p1, (uint8_t)p2, (uint16_t)p12)); break; case 0xcc: /* CALL Z */ - CALL_COND(p12, LOCAL_ZERO(), 3, 3, 4, 10, 3); + CALL_COND(p12, LOCAL_ZERO(), 3, 3, 11, 10, 3); break; case 0xcd: /* CALL */ CALL(p12, 3, 3, 11, 3); @@ -6372,7 +5141,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x08, 3, 3, 5, 1); break; case 0xd0: /* RET NC */ - RET_COND(!LOCAL_CARRY(), 4, 4, 2, 5, 1); + RET_COND(!LOCAL_CARRY(), 5, 3, 3, 5, 1); break; case 0xd1: /* POP DE */ POP(reg_d, reg_e, 1); @@ -6384,7 +5153,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c OUTA(p1, 4, 7, 2); break; case 0xd4: /* CALL NC */ - CALL_COND(p12, !LOCAL_CARRY(), 3, 3, 4, 10, 3); + CALL_COND(p12, !LOCAL_CARRY(), 3, 3, 11, 10, 3); break; case 0xd5: /* PUSH DE */ PUSH(reg_d, reg_e, 1); @@ -6396,10 +5165,10 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x10, 3, 3, 5, 1); break; case 0xd8: /* RET C */ - RET_COND(LOCAL_CARRY(), 4, 4, 2, 5, 1); + RET_COND(LOCAL_CARRY(), 5, 3, 3, 5, 1); break; case 0xd9: /* EXX */ - EXX(8, 1); + EXX(4, 1); break; case 0xda: /* JP C */ JMP_COND(p12, LOCAL_CARRY(), 10, 10); @@ -6408,10 +5177,10 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c INA(p1, 4, 7, 2); break; case 0xdc: /* CALL C */ - CALL_COND(p12, LOCAL_CARRY(), 3, 3, 4, 10, 3); + CALL_COND(p12, LOCAL_CARRY(), 3, 3, 11, 10, 3); break; case 0xdd: /* OPCODE DD */ - opcode_dd((BYTE)p1, (BYTE)p2, (BYTE)p3, (WORD)p12, (WORD)p23); + INSTS(inst_mode = INST_IX; CLK_ADD(CLK, 4); INC_PC(1); goto fetchmore, NOP(4,1), NOP(4,1)); break; case 0xde: /* SBC # */ SBC(p1, 4, 3, 2); @@ -6420,22 +5189,28 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x18, 3, 3, 5, 1); break; case 0xe0: /* RET PO */ - RET_COND(!LOCAL_PARITY(), 4, 4, 2, 5, 1); + RET_COND(!LOCAL_PARITY(), 5, 3, 3, 5, 1); break; - case 0xe1: /* POP HL */ - POP(reg_h, reg_l, 1); + case 0xe1: /* POP HL ; POP IX; POP IY */ + INSTS(POP(reg_h, reg_l, 1), + POP(reg_ixh, reg_ixl, 1), + POP(reg_iyh, reg_iyl, 1)); break; case 0xe2: /* JP PO */ JMP_COND(p12, !LOCAL_PARITY(), 10, 10); break; - case 0xe3: /* EX HL (SP) */ - EXXXSP(reg_h, reg_l, 4, 4, 4, 4, 3, 1); + case 0xe3: /* EX HL (SP) ; EX IX (SP) ; EX IY (SP) */ + INSTS(EXXXSP(reg_h, reg_l, 4, 4, 4, 4, 3, 1), + EXXXSP(reg_ixh, reg_ixl, 4, 4, 4, 4, 3, 1), + EXXXSP(reg_iyh, reg_iyl, 4, 4, 4, 4, 3, 1)); break; case 0xe4: /* CALL PO */ - CALL_COND(p12, !LOCAL_PARITY(), 3, 3, 4, 10, 3); + CALL_COND(p12, !LOCAL_PARITY(), 3, 3, 11, 10, 3); break; - case 0xe5: /* PUSH HL */ - PUSH(reg_h, reg_l, 1); + case 0xe5: /* PUSH HL ; PUSH IX; PUSH IY */ + INSTS(PUSH(reg_h, reg_l, 1), + PUSH(reg_ixh, reg_ixl, 1), + PUSH(reg_iyh, reg_iyl, 1)); break; case 0xe6: /* AND # */ AND(p1, 4, 3, 2); @@ -6444,10 +5219,12 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x20, 3, 3, 5, 1); break; case 0xe8: /* RET PE */ - RET_COND(LOCAL_PARITY(), 4, 4, 2, 5, 1); + RET_COND(LOCAL_PARITY(), 5, 3, 3, 5, 1); break; - case 0xe9: /* LD PC HL */ - JMP((HL_WORD()), 4); + case 0xe9: /* LD PC HL ; LD PC IX ; LD PC IY */ + INSTS(JMP((HL_WORD()), 4), + JMP((IX_WORD()), 4), + JMP((IY_WORD()), 4)); break; case 0xea: /* JP PE */ JMP_COND(p12, LOCAL_PARITY(), 10, 10); @@ -6456,10 +5233,10 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c EXDEHL(4, 1); break; case 0xec: /* CALL PE */ - CALL_COND(p12, LOCAL_PARITY(), 3, 3, 4, 10, 3); + CALL_COND(p12, LOCAL_PARITY(), 3, 3, 11, 10, 3); break; case 0xed: /* OPCODE ED */ - opcode_ed((BYTE)p1, (BYTE)p2, (BYTE)p3, (WORD)p12, (WORD)p23); + opcode_ed((uint8_t)p1, (uint8_t)p2, (uint8_t)p3, (uint16_t)p12, (uint16_t)p23); break; case 0xee: /* XOR # */ XOR(p1, 4, 3, 2); @@ -6468,7 +5245,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x28, 3, 3, 5, 1); break; case 0xf0: /* RET P */ - RET_COND(!LOCAL_SIGN(), 4, 4, 2, 5, 1); + RET_COND(!LOCAL_SIGN(), 5, 3, 3, 5, 1); break; case 0xf1: /* POP AF */ POP(reg_a, reg_f, 1); @@ -6480,7 +5257,7 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c DI(4, 1); break; case 0xf4: /* CALL P */ - CALL_COND(p12, !LOCAL_SIGN(), 3, 3, 4, 10, 3); + CALL_COND(p12, !LOCAL_SIGN(), 3, 3, 11, 10, 3); break; case 0xf5: /* PUSH AF */ PUSH(reg_a, reg_f, 1); @@ -6492,10 +5269,12 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c CALL(0x30, 3, 3, 5, 1); break; case 0xf8: /* RET M */ - RET_COND(LOCAL_SIGN(), 4, 4, 2, 5, 1); + RET_COND(LOCAL_SIGN(), 5, 3, 3, 5, 1); break; - case 0xf9: /* LD SP HL */ - LDSP(HL_WORD(), 4, 2, 1); + case 0xf9: /* LD SP HL ; LD SP IX ; LD SP IY */ + INSTS(LDSP(HL_WORD(), 4, 2, 1), + LDSP(IX_WORD(), 0, 6, 1), + LDSP(IY_WORD(), 0, 6, 1)); break; case 0xfa: /* JP M */ JMP_COND(p12, LOCAL_SIGN(), 10, 10); @@ -6504,10 +5283,10 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c EI(4, 1); break; case 0xfc: /* CALL M */ - CALL_COND(p12, LOCAL_SIGN(), 3, 3, 4, 10, 3); + CALL_COND(p12, LOCAL_SIGN(), 3, 3, 11, 10, 3); break; case 0xfd: /* OPCODE FD */ - opcode_fd((BYTE)p1, (BYTE)p2, (BYTE)p3, (WORD)p12, (WORD)p23); + INSTS(inst_mode = INST_IY; CLK_ADD(CLK, 4); INC_PC(1); goto fetchmore, NOP(4,1), NOP(4,1)); break; case 0xfe: /* CP # */ CP(p1, 4, 3, 2); @@ -6518,11 +5297,30 @@ void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *c } cpu_int_status->num_dma_per_opcode = 0; - } while (z80_started); + inst_mode = INST_NONE; + + if (maincpu_clk_limit && (CLK > maincpu_clk_limit)) { + log_error(LOG_DEFAULT, "cycle limit reached."); + archdep_vice_exit(1); + } + + } while (Z80_LOOP_COND); export_registers(); } + +/// z80core.c ends +/// +/// +/// + + +static void cpmcart_mainloop(interrupt_cpu_status_t *cpu_int_status, alarm_context_t *cpu_alarm_context) +{ + z80_maincpu_loop(cpu_int_status, cpu_alarm_context); +} + void cpmcart_check_and_run_z80(void) { if (z80_started) { @@ -6568,7 +5366,7 @@ void cpmcart_check_and_run_z80(void) DWORD | opcode address | last opcode address */ -static char snap_module_name[] = "CPMCART"; +static const char snap_module_name[] = "CPMCART"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -6583,7 +5381,7 @@ int cpmcart_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_DW(m, maincpu_clk) < 0 + || SMW_CLOCK(m, maincpu_clk) < 0 || SMW_B(m, reg_a) < 0 || SMW_B(m, reg_b) < 0 || SMW_B(m, reg_c) < 0 @@ -6611,9 +5409,9 @@ int cpmcart_snapshot_write_module(snapshot_t *s) || SMW_B(m, reg_f2) < 0 || SMW_B(m, reg_h2) < 0 || SMW_B(m, reg_l2) < 0 - || SMW_B(m, (BYTE)z80_started) < 0 - || SMW_DW(m, (DWORD)z80_last_opcode_info) < 0 - || SMW_DW(m, (DWORD)z80_last_opcode_addr) < 0) { + || SMW_B(m, (uint8_t)z80_started) < 0 + || SMW_DW(m, (uint32_t)z80_last_opcode_info) < 0 + || SMW_DW(m, (uint32_t)z80_last_opcode_addr) < 0) { snapshot_module_close(m); return -1; } @@ -6623,7 +5421,7 @@ int cpmcart_snapshot_write_module(snapshot_t *s) int cpmcart_snapshot_read_module(snapshot_t *s) { - BYTE major, minor; + uint8_t major, minor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &major, &minor); @@ -6633,18 +5431,17 @@ int cpmcart_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (major > SNAP_MAJOR || minor > SNAP_MINOR) { + if (snapshot_version_is_bigger(major, minor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; - } + } /* FIXME: This is a mighty kludge to prevent VIC-II from stealing the wrong number of cycles. */ maincpu_rmw_flag = 0; - /* XXX: Assumes `CLOCK' is the same size as a `DWORD'. */ if (0 - || SMR_DW(m, &maincpu_clk) < 0 + || SMR_CLOCK(m, &maincpu_clk) < 0 || SMR_B(m, ®_a) < 0 || SMR_B(m, ®_b) < 0 || SMR_B(m, ®_c) < 0 diff --git a/src/Emulators/vice/c64/cart/cpmcart.h b/src/Emulators/vice/c64/cart/cpmcart.h index 1b2c2e69..6f705755 100644 --- a/src/Emulators/vice/c64/cart/cpmcart.h +++ b/src/Emulators/vice/c64/cart/cpmcart.h @@ -39,26 +39,29 @@ extern struct z80_regs_s z80_regs; struct interrupt_cpu_status_s; struct alarm_context_s; -extern void cpmcart_reset(void); -extern int cpmcart_resources_init(void); -extern int cpmcart_cmdline_options_init(void); -extern int cpmcart_cart_enabled(void); +void cpmcart_reset(void); +int cpmcart_resources_init(void); +int cpmcart_cmdline_options_init(void); +int cpmcart_cart_enabled(void); #ifdef Z80_4MHZ -extern void cpmcart_clock_stretch(void); +void cpmcart_clock_stretch(void); #endif -extern void cpmcart_check_and_run_z80(void); +void cpmcart_check_and_run_z80(void); typedef int cpmcart_ba_check_callback_t (void); typedef void cpmcart_ba_steal_callback_t (void); -extern void cpmcart_ba_register(cpmcart_ba_check_callback_t *ba_check, +int cpmcart_enable(void); +int cpmcart_disable(void); + +void cpmcart_ba_register(cpmcart_ba_check_callback_t *ba_check, cpmcart_ba_steal_callback_t *ba_steal, int *ba_var, int ba_mask); -extern int cpmcart_snapshot_write_module(snapshot_t *s); -extern int cpmcart_snapshot_read_module(snapshot_t *s); +int cpmcart_snapshot_write_module(snapshot_t *s); +int cpmcart_snapshot_read_module(snapshot_t *s); #endif diff --git a/src/Emulators/vice/c64/cart/crt.c b/src/Emulators/vice/c64/cart/crt.c index 79086d0b..4db075a8 100644 --- a/src/Emulators/vice/c64/cart/crt.c +++ b/src/Emulators/vice/c64/cart/crt.c @@ -34,79 +34,16 @@ #include "cartridge.h" #include "crt.h" #include "log.h" +#include "machine.h" #include "resources.h" #include "vicetypes.h" -#include "c64cart.h" - -#define CARTRIDGE_INCLUDE_PRIVATE_API -#include "actionreplay.h" -#include "actionreplay2.h" -#include "actionreplay3.h" -#include "actionreplay4.h" -#include "atomicpower.h" -#include "c64-generic.h" -#include "c64tpi.h" -#include "comal80.h" -#include "capture.h" -#include "delaep256.h" -#include "delaep64.h" -#include "delaep7x8.h" -#include "diashowmaker.h" -#include "dinamic.h" -#include "easycalc.h" -#include "easyflash.h" -#include "epyxfastload.h" -#include "exos.h" -#include "expert.h" -#include "final.h" -#include "finalplus.h" -#include "final3.h" -#include "formel64.h" -#include "freezeframe.h" -#include "freezemachine.h" -#include "funplay.h" -#include "gamekiller.h" -#include "gmod2.h" -#include "gs.h" -#include "ide64.h" -#include "isepic.h" -#include "kcs.h" -#include "kingsoft.h" -#include "mach5.h" -#include "magicdesk.h" -#include "magicformel.h" -#include "magicvoice.h" -#include "mikroass.h" -#include "mmc64.h" -#include "mmcreplay.h" -#include "ocean.h" -#include "pagefox.h" -#include "prophet64.h" -#include "retroreplay.h" -#include "rexep256.h" -#include "rexutility.h" -#include "rgcd.h" -#include "rrnetmk3.h" -#include "ross.h" -#include "silverrock128.h" -#include "simonsbasic.h" -#include "stardos.h" -#include "stb.h" -#include "snapshot64.h" -#include "supergames.h" -#include "supersnapshot4.h" -#include "supersnapshot.h" -#include "superexplode5.h" -#include "warpspeed.h" -#include "westermann.h" -#include "zaxxon.h" +#include "c64cart.h" /* FIXME: for C64CART_IMAGE_LIMIT */ #include "util.h" -#undef CARTRIDGE_INCLUDE_PRIVATE_API /* #define DEBUGCRT */ #ifdef DEBUGCRT -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -114,16 +51,49 @@ /* * CRT image "strings". */ -const char CRT_HEADER[] = "C64 CARTRIDGE "; + + /*1234567890123456*/ +static const char CRT_HEADER_C64[] = "C64 CARTRIDGE "; +static const char CRT_HEADER_C128[] = "C128 CARTRIDGE "; +static const char CRT_HEADER_CBM2[] = "CBM2 CARTRIDGE "; +static const char CRT_HEADER_VIC20[] = "VIC20 CARTRIDGE "; +static const char CRT_HEADER_PLUS4[] = "PLUS4 CARTRIDGE "; + static const char CHIP_HEADER[] = "CHIP"; +static void expected_header_error(void) +{ + switch (machine_class) { + case VICE_MACHINE_C64: + case VICE_MACHINE_C64SC: + case VICE_MACHINE_SCPU64: + log_error(LOG_DEFAULT, "CRT header invalid (expected:'%s').", CRT_HEADER_C64); + break; + case VICE_MACHINE_C128: + log_error(LOG_DEFAULT, "CRT header invalid (expected:'%s' or '%s').", CRT_HEADER_C64, CRT_HEADER_C128); + break; + case VICE_MACHINE_CBM5x0: + case VICE_MACHINE_CBM6x0: + log_error(LOG_DEFAULT, "CRT header invalid (expected:'%s').", CRT_HEADER_CBM2); + break; + case VICE_MACHINE_VIC20: + log_error(LOG_DEFAULT, "CRT header invalid (expected:'%s').", CRT_HEADER_VIC20); + break; + case VICE_MACHINE_PLUS4: + log_error(LOG_DEFAULT, "CRT header invalid (expected:'%s').", CRT_HEADER_PLUS4); + break; + } +} + /* - Open a crt file and read header, return NULL on fault, fd otherwise + Open a crt file and read header + + return NULL on fault, fd otherwise */ -static FILE *crt_open(const char *filename, crt_header_t *header) +FILE *crt_open(const char *filename, crt_header_t *header) { - BYTE crt_header[0x40]; - DWORD skip; + uint8_t crt_header[0x40]; + uint32_t skip; FILE *fd; fd = fopen(filename, MODE_READ); @@ -138,10 +108,53 @@ static FILE *crt_open(const char *filename, crt_header_t *header) break; } - if (memcmp(crt_header, CRT_HEADER, 16)) { - log_error(LOG_DEFAULT, "CRT header invalid."); + header->machine = -1; + /*printf("CRT TAG:'%s'\n", crt_header);*/ + + if (memcmp(crt_header, CRT_HEADER_C64, 16) == 0) { + DBG(("Found header: '%s'\n", CRT_HEADER_C64)); + header->machine = VICE_MACHINE_C64; + if (!(machine_class == VICE_MACHINE_C64 || + machine_class == VICE_MACHINE_C64SC || + machine_class == VICE_MACHINE_C128 || + machine_class == VICE_MACHINE_SCPU64)) { + expected_header_error(); + break; + } + } else if (memcmp(crt_header, CRT_HEADER_C128, 16) == 0) { + DBG(("Found header: '%s'\n", CRT_HEADER_C128)); + header->machine = VICE_MACHINE_C128; + if (!(machine_class == VICE_MACHINE_C128)) { + expected_header_error(); + break; + } + } else if (memcmp(crt_header, CRT_HEADER_CBM2, 16) == 0) { + DBG(("Found header: '%s'\n", CRT_HEADER_CBM2)); + header->machine = VICE_MACHINE_CBM6x0; + if (!((machine_class == VICE_MACHINE_CBM5x0) || + (machine_class == VICE_MACHINE_CBM6x0))) { + expected_header_error(); + break; + } + } else if (memcmp(crt_header, CRT_HEADER_VIC20, 16) == 0) { + DBG(("Found header: '%s'\n", CRT_HEADER_VIC20)); + header->machine = VICE_MACHINE_VIC20; + if (!(machine_class == VICE_MACHINE_VIC20)) { + expected_header_error(); + break; + } + } else if (memcmp(crt_header, CRT_HEADER_PLUS4, 16) == 0) { + DBG(("Found header: '%s'\n", CRT_HEADER_PLUS4)); + header->machine = VICE_MACHINE_PLUS4; + if (!(machine_class == VICE_MACHINE_PLUS4)) { + expected_header_error(); + break; + } + } else { + log_error(LOG_DEFAULT, "no CRT header found."); break; } + DBG(("CRT Machine:'%d'", header->machine)); skip = util_be_buf_to_dword(&crt_header[0x10]); @@ -154,10 +167,12 @@ static FILE *crt_open(const char *filename, crt_header_t *header) header->version = util_be_buf_to_word(&crt_header[0x14]); header->type = util_be_buf_to_word(&crt_header[0x16]); + header->subtype = crt_header[0x1a]; header->exrom = crt_header[0x18]; header->game = crt_header[0x19]; memset(header->name, 0, sizeof(header->name)); - strncpy(header->name, (char*)&crt_header[0x20], sizeof(header->name) - 1); + strncpy(header->name, (char *)(crt_header + 0x20), + sizeof(header->name) - 1); fseek(fd, skip, SEEK_CUR); /* skip the rest */ @@ -172,6 +187,7 @@ static FILE *crt_open(const char *filename, crt_header_t *header) */ int crt_getid(const char *filename) { + int id; crt_header_t header; FILE *fd; @@ -183,15 +199,23 @@ int crt_getid(const char *filename) fclose(fd); - return header.type; + id = header.type; + + /* if we have loaded a C128 cartridge, convert the C128 crt id to something + else (that can coexist with C64 crt ids) */ + if (header.machine == VICE_MACHINE_C128) { + id = CARTRIDGE_C128_MAKEID(id); + } + + return id; } /* - Read and pharse chip header, return -1 on fault + Read and parse chip header, return -1 on fault */ int crt_read_chip_header(crt_chip_header_t *header, FILE *fd) { - BYTE chipheader[0x10]; + uint8_t chipheader[0x10]; if (fread(chipheader, sizeof(chipheader), 1, fd) < 1) { return -1; /* couldn't read header */ @@ -200,18 +224,23 @@ int crt_read_chip_header(crt_chip_header_t *header, FILE *fd) return -1; /* invalid header signature */ } + /* 1: grab size of chip packet from the file */ header->skip = util_be_buf_to_dword(&chipheader[4]); if (header->skip < sizeof(chipheader)) { return -1; /* invalid packet size */ } + /* 2: subtract header size, we now have the payload size */ header->skip -= sizeof(chipheader); /* without header */ header->size = util_be_buf_to_word(&chipheader[14]); if (header->size > header->skip) { return -1; /* rom bigger then total size?! */ } + /* 3: subtract ROM size, we get the unused portion at the end, + which we need to skip */ header->skip -= header->size; /* skip size after image */ + header->type = util_be_buf_to_word(&chipheader[8]); header->bank = util_be_buf_to_word(&chipheader[10]); header->start = util_be_buf_to_word(&chipheader[12]); @@ -225,7 +254,7 @@ int crt_read_chip_header(crt_chip_header_t *header, FILE *fd) /* Read chip data, return -1 on error */ -int crt_read_chip(BYTE *rawcart, int offset, crt_chip_header_t *chip, FILE *fd) +int crt_read_chip(uint8_t *rawcart, int offset, crt_chip_header_t *chip, FILE *fd) { if (offset + chip->size > C64CART_IMAGE_LIMIT) { return -1; /* overflow */ @@ -240,9 +269,9 @@ int crt_read_chip(BYTE *rawcart, int offset, crt_chip_header_t *chip, FILE *fd) /* Write chip header and data, return -1 on fault */ -int crt_write_chip(BYTE *data, crt_chip_header_t *header, FILE *fd) +int crt_write_chip(uint8_t *data, crt_chip_header_t *header, FILE *fd) { - BYTE chipheader[0x10]; + uint8_t chipheader[0x10]; memcpy(chipheader, CHIP_HEADER, 4); util_dword_to_be_buf(&chipheader[4], header->size + sizeof(chipheader)); @@ -261,12 +290,11 @@ int crt_write_chip(BYTE *data, crt_chip_header_t *header, FILE *fd) return 0; } -/* - Create crt file with header, return NULL on fault, fd otherwise -*/ -FILE *crt_create(const char *filename, int type, int exrom, int game, const char *name) + +/* create v2.0 header with machine id */ +FILE *crt_create_v20(const char *filename, int type, int subtype, int exrom, int game, const char *name, int machine) { - BYTE crt_header[0x40]; + uint8_t crt_header[0x40]; FILE *fd; if (filename == NULL) { @@ -280,13 +308,35 @@ FILE *crt_create(const char *filename, int type, int exrom, int game, const char } memset(&crt_header, 0, sizeof(crt_header)); - memcpy(crt_header, CRT_HEADER, 16); + + switch (machine) { + case VICE_MACHINE_C64: + case VICE_MACHINE_C64SC: + case VICE_MACHINE_SCPU64: + memcpy(crt_header, CRT_HEADER_C64, 16); + break; + case VICE_MACHINE_C128: + memcpy(crt_header, CRT_HEADER_C128, 16); + break; + case VICE_MACHINE_CBM5x0: + case VICE_MACHINE_CBM6x0: + memcpy(crt_header, CRT_HEADER_CBM2, 16); + break; + case VICE_MACHINE_VIC20: + memcpy(crt_header, CRT_HEADER_VIC20, 16); + break; + case VICE_MACHINE_PLUS4: + memcpy(crt_header, CRT_HEADER_PLUS4, 16); + break; + } + util_dword_to_be_buf(&crt_header[0x10], sizeof(crt_header)); - util_word_to_be_buf(&crt_header[0x14], 0x100); /* version */ - util_word_to_be_buf(&crt_header[0x16], (WORD)type); + util_word_to_be_buf(&crt_header[0x14], 0x0200); /* version */ + util_word_to_be_buf(&crt_header[0x16], (uint16_t)type); crt_header[0x18] = exrom ? 1 : 0; crt_header[0x19] = game ? 1 : 0; - strncpy((char*)&crt_header[0x20], name, sizeof(crt_header) - 0x20); + crt_header[0x1a] = subtype; + strncpy((char*)(crt_header + 0x20), name, sizeof(crt_header) - 0x20 - 1); if (fwrite(crt_header, sizeof(crt_header), 1, fd) < 1) { fclose(fd); @@ -296,243 +346,75 @@ FILE *crt_create(const char *filename, int type, int exrom, int game, const char return fd; } -/* - returns -1 on error, else a positive CRT ID +FILE *crt_create_vic20(const char *filename, int type, int subtype, const char *name) { + return crt_create_v20(filename, type, subtype, 0, 0, name, VICE_MACHINE_VIC20); +}; - FIXME: to simplify this function a little bit, all subfunctions should - also return the respective CRT ID on success -*/ -int crt_attach(const char *filename, BYTE *rawcart) +/* create v1.1 header with sub type */ +FILE *crt_create_v11(const char *filename, int type, int subtype, int exrom, int game, const char *name) { - crt_header_t header; - int rc, new_crttype; + uint8_t crt_header[0x40]; FILE *fd; - DBG(("crt_attach: %s\n", filename)); + if (filename == NULL) { + return NULL; + } - fd = crt_open(filename, &header); + fd = fopen(filename, MODE_WRITE); if (fd == NULL) { - return -1; + return NULL; } - new_crttype = header.type; - if (new_crttype & 0x8000) { - /* handle our negative test IDs */ - new_crttype -= 0x10000; + memset(&crt_header, 0, sizeof(crt_header)); + memcpy(crt_header, CRT_HEADER_C64, 16); /* FIXME */ + util_dword_to_be_buf(&crt_header[0x10], sizeof(crt_header)); + util_word_to_be_buf(&crt_header[0x14], 0x0101); /* version */ + util_word_to_be_buf(&crt_header[0x16], (uint16_t)type); + crt_header[0x18] = exrom ? 1 : 0; + crt_header[0x19] = game ? 1 : 0; + crt_header[0x1a] = subtype; + strncpy((char*)(crt_header + 0x20), name, sizeof(crt_header) - 0x20 - 1); + + if (fwrite(crt_header, sizeof(crt_header), 1, fd) < 1) { + fclose(fd); + return NULL; } - DBG(("crt_attach ID: %d\n", new_crttype)); -/* cart should always be detached. there is no reason for doing fancy checks - here, and it will cause problems incase a cart MUST be detached before - attaching another, or even itself. (eg for initialization reasons) + return fd; +} - most obvious reason: attaching a different ROM (software) for the same - cartridge (hardware) */ +/* + Create crt v1.0 file with header, return NULL on fault, fd otherwise +*/ +FILE *crt_create(const char *filename, int type, int exrom, int game, const char *name) +{ + uint8_t crt_header[0x40]; + FILE *fd; - cartridge_detach_image(new_crttype); + if (filename == NULL) { + return NULL; + } - switch (new_crttype) { - case CARTRIDGE_CRT: - rc = generic_crt_attach(fd, rawcart); - if (rc != CARTRIDGE_NONE) { - new_crttype = rc; - } - break; - case CARTRIDGE_ACTION_REPLAY: - rc = actionreplay_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ACTION_REPLAY2: - rc = actionreplay2_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ACTION_REPLAY3: - rc = actionreplay3_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ACTION_REPLAY4: - rc = actionreplay4_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ATOMIC_POWER: - rc = atomicpower_crt_attach(fd, rawcart); - break; - case CARTRIDGE_CAPTURE: - rc = capture_crt_attach(fd, rawcart); - break; - case CARTRIDGE_COMAL80: - rc = comal80_crt_attach(fd, rawcart); - break; - case CARTRIDGE_DELA_EP256: - rc = delaep256_crt_attach(fd, rawcart); - break; - case CARTRIDGE_DELA_EP64: - rc = delaep64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_DELA_EP7x8: - rc = delaep7x8_crt_attach(fd, rawcart); - break; - case CARTRIDGE_DIASHOW_MAKER: - rc = dsm_crt_attach(fd, rawcart); - break; - case CARTRIDGE_DINAMIC: - rc = dinamic_crt_attach(fd, rawcart); - break; - case CARTRIDGE_EASYCALC: - rc = easycalc_crt_attach(fd, rawcart); - break; - case CARTRIDGE_EASYFLASH: - rc = easyflash_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_EPYX_FASTLOAD: - rc = epyxfastload_crt_attach(fd, rawcart); - break; - case CARTRIDGE_EXOS: - rc = exos_crt_attach(fd, rawcart); - break; - case CARTRIDGE_EXPERT: - rc = expert_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_FINAL_I: - rc = final_v1_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FINAL_III: - rc = final_v3_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FINAL_PLUS: - rc = final_plus_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FORMEL64: - rc = formel64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FREEZE_FRAME: - rc = freezeframe_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FREEZE_MACHINE: - rc = freezemachine_crt_attach(fd, rawcart); - break; - case CARTRIDGE_FUNPLAY: - rc = funplay_crt_attach(fd, rawcart); - break; - case CARTRIDGE_GAME_KILLER: - rc = gamekiller_crt_attach(fd, rawcart); - break; - case CARTRIDGE_GMOD2: - rc = gmod2_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_GS: - rc = gs_crt_attach(fd, rawcart); - break; - case CARTRIDGE_IDE64: - rc = ide64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_IEEE488: - rc = tpi_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ISEPIC: - rc = isepic_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_KCS_POWER: - rc = kcs_crt_attach(fd, rawcart); - break; - case CARTRIDGE_KINGSOFT: - rc = kingsoft_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MACH5: - rc = mach5_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MAGIC_DESK: - rc = magicdesk_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MAGIC_FORMEL: - rc = magicformel_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MAGIC_VOICE: - rc = magicvoice_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MIKRO_ASSEMBLER: - rc = mikroass_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MMC64: - rc = mmc64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_MMC_REPLAY: - rc = mmcreplay_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_OCEAN: - rc = ocean_crt_attach(fd, rawcart); - break; - case CARTRIDGE_P64: - rc = p64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_PAGEFOX: - rc = pagefox_crt_attach(fd, rawcart); - break; - case CARTRIDGE_RETRO_REPLAY: - rc = retroreplay_crt_attach(fd, rawcart, filename); - break; - case CARTRIDGE_REX_EP256: - rc = rexep256_crt_attach(fd, rawcart); - break; - case CARTRIDGE_REX: - rc = rex_crt_attach(fd, rawcart); - break; - case CARTRIDGE_RGCD: - rc = rgcd_crt_attach(fd, rawcart); - break; -#ifdef HAVE_PCAP - case CARTRIDGE_RRNETMK3: - rc = rrnetmk3_crt_attach(fd, rawcart, filename); - break; -#endif - case CARTRIDGE_ROSS: - rc = ross_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SILVERROCK_128: - rc = silverrock128_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SIMONS_BASIC: - rc = simon_crt_attach(fd, rawcart); - break; - case CARTRIDGE_STARDOS: - rc = stardos_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SNAPSHOT64: - rc = snapshot64_crt_attach(fd, rawcart); - break; - case CARTRIDGE_STRUCTURED_BASIC: - rc = stb_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SUPER_GAMES: - rc = supergames_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SUPER_SNAPSHOT: - rc = supersnapshot_v4_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SUPER_SNAPSHOT_V5: - rc = supersnapshot_v5_crt_attach(fd, rawcart); - break; - case CARTRIDGE_SUPER_EXPLODE_V5: - rc = se5_crt_attach(fd, rawcart); - break; - case CARTRIDGE_WARPSPEED: - rc = warpspeed_crt_attach(fd, rawcart); - break; - case CARTRIDGE_WESTERMANN: - rc = westermann_crt_attach(fd, rawcart); - break; - case CARTRIDGE_ZAXXON: - rc = zaxxon_crt_attach(fd, rawcart); - break; - default: - archdep_startup_log_error("unknown CRT ID: %d\n", new_crttype); - rc = -1; - break; + fd = fopen(filename, MODE_WRITE); + + if (fd == NULL) { + return NULL; } - fclose(fd); + memset(&crt_header, 0, sizeof(crt_header)); + memcpy(crt_header, CRT_HEADER_C64, 16); /* FIXME */ + util_dword_to_be_buf(&crt_header[0x10], sizeof(crt_header)); + util_word_to_be_buf(&crt_header[0x14], 0x100); /* version */ + util_word_to_be_buf(&crt_header[0x16], (uint16_t)type); + crt_header[0x18] = exrom ? 1 : 0; + crt_header[0x19] = game ? 1 : 0; + strncpy((char*)(crt_header + 0x20), name, sizeof(crt_header) - 0x20 - 1); - if (rc == -1) { - DBG(("crt_attach error (%d)\n", rc)); - return -1; + if (fwrite(crt_header, sizeof(crt_header), 1, fd) < 1) { + fclose(fd); + return NULL; } - DBG(("crt_attach return ID: %d\n", new_crttype)); - return new_crttype; + + return fd; } diff --git a/src/Emulators/vice/c64/cart/crt.h b/src/Emulators/vice/c64/cart/crt.h index 0d7cc0f6..349acd87 100644 --- a/src/Emulators/vice/c64/cart/crt.h +++ b/src/Emulators/vice/c64/cart/crt.h @@ -31,26 +31,40 @@ #include "vicetypes.h" typedef struct crt_header_s { - WORD version; /* version */ - WORD type; /* type of cartridge */ + uint16_t version; /* version */ + uint16_t type; /* type of cartridge */ + uint8_t subtype; /* subtype/hardware revision of cartridge */ int exrom; /* exrom line status */ int game; /* game line status */ char name[32 + 1]; /* name of cartridge */ + /* following are not actually part of the header */ + int machine; /* detected machine for this crt file */ } crt_header_t; typedef struct crt_chip_header_s { - DWORD skip; /* bytes to skip after ROM */ - WORD type; /* chip type */ - WORD bank; /* bank number */ - WORD start; /* start address of ROM */ - WORD size; /* size of ROM in bytes */ + uint32_t skip; /* bytes to skip after ROM */ + uint16_t type; /* chip type */ + uint16_t bank; /* bank number */ + uint16_t start; /* start address of ROM */ + uint16_t size; /* size of ROM in bytes */ } crt_chip_header_t; -extern int crt_attach(const char *filename, BYTE *rawcart); -extern int crt_getid(const char *filename); -extern int crt_read_chip_header(crt_chip_header_t *header, FILE *fd); -extern int crt_read_chip(BYTE *rawcart, int offset, crt_chip_header_t *chip, FILE *fd); -extern FILE *crt_create(const char *filename, int type, int exrom, int game, const char *name); -extern int crt_write_chip(BYTE *data, crt_chip_header_t *header, FILE *fd); +FILE *crt_open(const char *filename, crt_header_t *header); +int crt_getid(const char *filename); +int crt_read_chip_header(crt_chip_header_t *header, FILE *fd); +int crt_read_chip(uint8_t *rawcart, int offset, crt_chip_header_t *chip, FILE *fd); +int crt_write_chip(uint8_t *data, crt_chip_header_t *header, FILE *fd); + +/* create classic v1.0 header */ +FILE *crt_create(const char *filename, int type, int exrom, int game, const char *name); + +/* create v1.1 header with sub type */ +FILE *crt_create_v11(const char *filename, int type, int subtype, int exrom, int game, const char *name); + +/* create 2.0 header */ +FILE *crt_create_v20(const char *filename, int type, int subtype, int exrom, int game, const char *name, int machine); + +/* convenience functions for VIC20 etc */ +FILE *crt_create_vic20(const char *filename, int type, int subtype, const char *name); #endif diff --git a/src/Emulators/vice/c64/cart/cs8900io.c b/src/Emulators/vice/c64/cart/cs8900io.c index 9805907d..dc2bc6bf 100644 --- a/src/Emulators/vice/c64/cart/cs8900io.c +++ b/src/Emulators/vice/c64/cart/cs8900io.c @@ -30,7 +30,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -51,10 +51,11 @@ #include "rawnet.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "uiapi.h" #include "util.h" +#include "cs8900io.h" + /* #define CS8900IO_DEBUG */ #ifdef CS8900IO_DEBUG @@ -72,14 +73,14 @@ */ static int should_activate = 0; -static log_t cs8900io_log = LOG_ERR; +static log_t cs8900io_log = LOG_DEFAULT; /* Flag: Can we even use CS8900 I/O, or is the hardware not available? */ static int cs8900io_cannot_use = 0; /* Flag: Do we have the CS8900 I/O enabled? */ static int cs8900io_enabled = 0; -static char *cs8900io_owner = NULL; +static const char *cs8900io_owner = NULL; static char *cs8900io_interface = NULL; @@ -87,6 +88,13 @@ static int cs8900io_init_done = 0; static int cs8900io_resources_init_done = 0; static int cs8900io_cmdline_init_done = 0; + +/** \brief Keep track of default IF used as a factory value + * + */ +static char *default_if; + + /* ------------------------------------------------------------------------- */ /* initialization and deinitialization functions */ @@ -103,7 +111,7 @@ static int cs8900io_activate(void) log_message(cs8900io_log, "cs8900io_activate()."); #endif - if (cs8900io_log != LOG_ERR) { + if (cs8900io_log != LOG_DEFAULT) { switch (cs8900_activate(cs8900io_interface)) { case -1: cs8900io_enabled = 0; @@ -111,7 +119,18 @@ static int cs8900io_activate(void) case -2: cs8900io_enabled = 0; cs8900io_cannot_use = 1; - ui_error("No PCAP library is installed, cannot use ethernet based devices."); + + ui_error("Failed to initialize ethernet cartridge emulation" + " using the system interface '%s'.\n\n" + "Troubleshooting:\n\n" + " - is '%s' the correct system interface for ethernet cartridge emulation?" + " If not, you need to change the ethernet device settings;\n\n" + " - if you are on Windows, make sure the pcap DLL is installed;\n\n" + " - if you are on Unix, make sure to either have TUN/TAP support," + " or that you have the permissions to use raw net" + " (if using libpcap);\n\n" + " - if you are on MacOS, you're on your own.", + cs8900io_interface, cs8900io_interface); return -1; } } else { @@ -132,7 +151,7 @@ static int cs8900io_deactivate(void) cs8900io_enabled = 0; should_activate = 0; /* FIXME: WTH check for cs8900io_log here? */ - if (cs8900io_log != LOG_ERR) { + if (cs8900io_log != LOG_DEFAULT) { return cs8900_deactivate(); } } @@ -185,7 +204,7 @@ void cs8900io_detach(void) /* ------------------------------------------------------------------------- */ /* ----- read byte from I/O range in VICE ----- */ -BYTE cs8900io_read(WORD io_address) +uint8_t cs8900io_read(uint16_t io_address) { if (!cs8900io_cannot_use) { return cs8900_read(io_address); @@ -194,13 +213,13 @@ BYTE cs8900io_read(WORD io_address) } /* ----- peek byte with no sideeffects from I/O range in VICE ----- */ -BYTE cs8900io_peek(WORD io_address) +uint8_t cs8900io_peek(uint16_t io_address) { return cs8900io_read(io_address); } /* ----- write byte to I/O range of VICE ----- */ -void cs8900io_store(WORD io_address, BYTE byte) +void cs8900io_store(uint16_t io_address, uint8_t byte) { if (!cs8900io_cannot_use) { cs8900_store(io_address, byte); @@ -223,7 +242,7 @@ int cs8900io_cart_enabled(void) return cs8900io_enabled; } -int cs8900io_enable(char *owner) +int cs8900io_enable(const char *owner) { if (!cs8900io_cannot_use) { if (!cs8900io_enabled) { @@ -232,7 +251,7 @@ int cs8900io_enable(char *owner) } cs8900io_enabled = 1; } else { - ui_error(translate_text(IDGS_CS8900_IN_USE_BY_S), cs8900io_owner); + ui_error("CS8900 already in use by %s.", cs8900io_owner); return -1; } cs8900io_reset(); @@ -287,8 +306,7 @@ static int set_cs8900io_interface(const char *name, void *param) } static resource_string_t resources_string[] = { - { "ETHERNET_INTERFACE", - ARCHDEP_ETHERNET_DEFAULT_DEVICE, RES_EVENT_NO, NULL, + { "ETHERNET_INTERFACE", NULL, RES_EVENT_NO, NULL, &cs8900io_interface, set_cs8900io_interface, NULL }, RESOURCE_STRING_LIST_END }; @@ -301,16 +319,20 @@ static const resource_int_t resources_int[] = { int cs8900io_resources_init(void) { - char *default_if = NULL; - if (!cs8900io_resources_init_done) { + if (rawnet_resources_init() < 0) { + return -1; + } + /* allocated in src/arch/shared/rawnetarch_unix/win32/c */ default_if = rawnet_get_standard_interface(); - if (default_if) { - resources_string[0].factory_value = default_if; + if (default_if == NULL) { + default_if = lib_strdup(ARCHDEP_ETHERNET_DEFAULT_DEVICE); } + resources_string[0].factory_value = default_if; + if (resources_register_string(resources_string) < 0 || resources_register_int(resources_int) < 0) { return -1; @@ -327,6 +349,12 @@ void cs8900io_resources_shutdown(void) lib_free(cs8900io_interface); cs8900io_interface = NULL; } + if (default_if != NULL) { + lib_free(default_if); + default_if = NULL; + } + + rawnet_resources_shutdown(); } /* ------------------------------------------------------------------------- */ @@ -334,16 +362,18 @@ void cs8900io_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-cs8900ioif", SET_RESOURCE, 1, + { "-ethernetioif", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ETHERNET_INTERFACE", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_ETHERNET_INTERFACE, - NULL, NULL }, + "", "Set the system ethernet interface" }, CMDLINE_LIST_END }; int cs8900io_cmdline_options_init(void) { + if (rawnet_cmdline_options_init() < 0) { + return -1; + } + if (!cs8900io_cmdline_init_done) { if (cmdline_register_options(cmdline_options) < 0) { return -1; @@ -353,4 +383,4 @@ int cs8900io_cmdline_options_init(void) return 0; } -#endif /* #ifdef HAVE_PCAP */ +#endif /* #ifdef HAVE_RAWNET */ diff --git a/src/Emulators/vice/c64/cart/cs8900io.h b/src/Emulators/vice/c64/cart/cs8900io.h index 557b6f8c..1e0e2ee6 100644 --- a/src/Emulators/vice/c64/cart/cs8900io.h +++ b/src/Emulators/vice/c64/cart/cs8900io.h @@ -30,26 +30,28 @@ #ifndef VICE_TFE_H #define VICE_TFE_H -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET + +#include #include "vicetypes.h" -extern int cs8900io_cart_enabled(void); +int cs8900io_cart_enabled(void); -extern void cs8900io_init(void); -extern int cs8900io_resources_init(void); -extern void cs8900io_resources_shutdown(void); -extern int cs8900io_cmdline_options_init(void); +void cs8900io_init(void); +int cs8900io_resources_init(void); +void cs8900io_resources_shutdown(void); +int cs8900io_cmdline_options_init(void); -extern void cs8900io_reset(void); -extern void cs8900io_detach(void); -extern int cs8900io_enable(char *owner); -extern int cs8900io_disable(void); +void cs8900io_reset(void); +void cs8900io_detach(void); +int cs8900io_enable(const char *owner); +int cs8900io_disable(void); -extern void cs8900io_store(WORD io_address, BYTE byte); -extern BYTE cs8900io_read(WORD io_address); -extern BYTE cs8900io_peek(WORD io_address); -extern int cs8900io_dump(void); +void cs8900io_store(uint16_t io_address, uint8_t byte); +uint8_t cs8900io_read(uint16_t io_address); +uint8_t cs8900io_peek(uint16_t io_address); +int cs8900io_dump(void); #endif #endif diff --git a/src/Emulators/vice/c64/cart/daa.c b/src/Emulators/vice/c64/cart/daa.c index f45067c6..5a34239c 100644 --- a/src/Emulators/vice/c64/cart/daa.c +++ b/src/Emulators/vice/c64/cart/daa.c @@ -28,7 +28,7 @@ #include "daa.h" #include "vicetypes.h" -const BYTE daa_reg_a[2048] = { +const uint8_t daa_reg_a[2048] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, @@ -287,7 +287,7 @@ const BYTE daa_reg_a[2048] = { 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99 }; -const BYTE daa_reg_f[2048] = { +const uint8_t daa_reg_f[2048] = { 0x44, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x00, 0x08, 0x0C, 0x10, 0x14, 0x14, 0x10, 0x14, 0x10, 0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, diff --git a/src/Emulators/vice/c64/cart/daa.h b/src/Emulators/vice/c64/cart/daa.h index db5c0a49..3f476de0 100644 --- a/src/Emulators/vice/c64/cart/daa.h +++ b/src/Emulators/vice/c64/cart/daa.h @@ -30,7 +30,7 @@ #include "vicetypes.h" -extern const BYTE daa_reg_a[]; -extern const BYTE daa_reg_f[]; +extern const uint8_t daa_reg_a[]; +extern const uint8_t daa_reg_f[]; #endif diff --git a/src/Emulators/vice/c64/cart/debugcart.c b/src/Emulators/vice/c64/cart/debugcart.c index 26c13e63..05b6a55b 100644 --- a/src/Emulators/vice/c64/cart/debugcart.c +++ b/src/Emulators/vice/c64/cart/debugcart.c @@ -32,30 +32,35 @@ #include "export.h" #include "lib.h" #include "resources.h" -#include "translate.h" #include "machine.h" #include "maincpu.h" +#include "archdep.h" + +#include "debugcart.h" static int debugcart_enabled = 0; /* ------------------------------------------------------------------------- */ /* a prototype is needed */ -static void debugcart_store(WORD addr, BYTE value); +static void debugcart_store(uint16_t addr, uint8_t value); +/* This is not a real cartridge, it is only used for debugging purposes */ static io_source_t debugcart_device = { - CARTRIDGE_NAME_DEBUGCART, - IO_DETACH_RESOURCE, - "DebugCartEnable", - 0xd7ff, 0xd7ff, 0xff, - 0, - debugcart_store, - NULL, /* read */ - NULL, /* peek */ - NULL, /* nothing to dump */ - CARTRIDGE_DEBUGCART, - 0, - 0 + CARTRIDGE_NAME_DEBUGCART, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "DebugCartEnable", /* resource to set to '0' */ + 0xd7ff, 0xd7ff, 0xff, /* range of the device, reg:$d7ff */ + 0, /* read is never valid, device is write only */ + debugcart_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_DEBUGCART, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *debugcart_list_item = NULL; @@ -66,12 +71,11 @@ static const export_resource_t export_res = { /* ------------------------------------------------------------------------- */ -static void debugcart_store(WORD addr, BYTE value) +static void debugcart_store(uint16_t addr, uint8_t value) { int n = (int)value; - /* FIXME: perhaps print a timestamp too */ - fprintf(stdout, "DBGCART: exit(%d)\n", n); - exit(n); + fprintf(stdout, "DBGCART: exit(%d) cycles elapsed: %"PRIu64"\n", n, maincpu_clk); + archdep_vice_exit(n); } /* ------------------------------------------------------------------------- */ @@ -108,6 +112,11 @@ static int set_debugcart_enabled(int value, void *param) return 0; } +void debugcart_detach(void) +{ + set_debugcart_enabled(0, NULL); +} + /* ------------------------------------------------------------------------- */ static const resource_int_t resources_i[] = { @@ -129,16 +138,12 @@ void debugcart_resources_shutdown(void) static const cmdline_option_t cart_cmdline_options[] = { - { "-debugcart", SET_RESOURCE, 0, + { "-debugcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DebugCartEnable", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DEBUGCART, - NULL, NULL }, - { "+debugcart", SET_RESOURCE, 0, + NULL, "Enable Debug cartridge" }, + { "+debugcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DebugCartEnable", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DEBUGCART, - NULL, NULL }, + NULL, "Disable Debug cartridge" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/c64/cart/debugcart.h b/src/Emulators/vice/c64/cart/debugcart.h index 666efef8..5e98d1e9 100644 --- a/src/Emulators/vice/c64/cart/debugcart.h +++ b/src/Emulators/vice/c64/cart/debugcart.h @@ -29,8 +29,9 @@ #include "vicetypes.h" -extern int debugcart_cmdline_options_init(void); -extern int debugcart_resources_init(void); -extern void debugcart_resources_shutdown(void); +int debugcart_cmdline_options_init(void); +int debugcart_resources_init(void); +void debugcart_resources_shutdown(void); +void debugcart_detach(void); #endif diff --git a/src/Emulators/vice/c64/cart/delaep256.c b/src/Emulators/vice/c64/cart/delaep256.c index aadebcd4..3565622a 100644 --- a/src/Emulators/vice/c64/cart/delaep256.c +++ b/src/Emulators/vice/c64/cart/delaep256.c @@ -70,11 +70,11 @@ /* ---------------------------------------------------------------------*/ static int currbank = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void delaep256_io1_store(WORD addr, BYTE value) +static void delaep256_io1_store(uint16_t addr, uint8_t value) { - BYTE bank, config; + uint8_t bank, config; regval = value; @@ -93,7 +93,7 @@ static void delaep256_io1_store(WORD addr, BYTE value) currbank = bank; } -static BYTE delaep256_io1_peek(WORD addr) +static uint8_t delaep256_io1_peek(uint16_t addr) { return regval; } @@ -109,18 +109,20 @@ static int delaep256_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t delaep256_device = { - CARTRIDGE_NAME_DELA_EP256, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - delaep256_io1_store, - NULL, - delaep256_io1_peek, - delaep256_dump, - CARTRIDGE_DELA_EP256, - 0, - 0 + CARTRIDGE_NAME_DELA_EP256, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, device is write only */ + delaep256_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + delaep256_io1_peek, /* peek function */ + delaep256_dump, /* device state information dump function */ + CARTRIDGE_DELA_EP256, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *delaep256_list_item = NULL; @@ -133,14 +135,14 @@ static const export_resource_t export_res = { void delaep256_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } -void delaep256_config_setup(BYTE *rawcart) +void delaep256_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 33); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } @@ -154,7 +156,7 @@ static int delaep256_common_attach(void) return 0; } -int delaep256_bin_attach(const char *filename, BYTE *rawcart) +int delaep256_bin_attach(const char *filename, uint8_t *rawcart) { int size = 0x42000; @@ -169,7 +171,7 @@ int delaep256_bin_attach(const char *filename, BYTE *rawcart) return -1; } -int delaep256_crt_attach(FILE *fd, BYTE *rawcart) +int delaep256_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -209,7 +211,7 @@ void delaep256_detach(void) ARRAY | ROML | 0.0+ | 262144 BYTES of ROML data */ -static char snap_module_name[] = "CARTDELAEP256"; +static const char snap_module_name[] = "CARTDELAEP256"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -225,7 +227,7 @@ int delaep256_snapshot_write_module(snapshot_t *s) if (0 || (SMW_B(m, regval) < 0) - || (SMW_B(m, (BYTE)currbank) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 32) < 0)) { snapshot_module_close(m); return -1; @@ -236,7 +238,7 @@ int delaep256_snapshot_write_module(snapshot_t *s) int delaep256_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -246,13 +248,13 @@ int delaep256_snapshot_read_module(snapshot_t *s) } /* Do not accept higher versions than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/delaep256.h b/src/Emulators/vice/c64/cart/delaep256.h index ff26c9b1..d6b5d5d3 100644 --- a/src/Emulators/vice/c64/cart/delaep256.h +++ b/src/Emulators/vice/c64/cart/delaep256.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void delaep256_config_init(void); -extern void delaep256_config_setup(BYTE *rawcart); -extern int delaep256_bin_attach(const char *filename, BYTE *rawcart); -extern int delaep256_crt_attach(FILE *fd, BYTE *rawcart); -extern void delaep256_detach(void); +void delaep256_config_init(void); +void delaep256_config_setup(uint8_t *rawcart); +int delaep256_bin_attach(const char *filename, uint8_t *rawcart); +int delaep256_crt_attach(FILE *fd, uint8_t *rawcart); +void delaep256_detach(void); struct snapshot_s; -extern int delaep256_snapshot_write_module(struct snapshot_s *s); -extern int delaep256_snapshot_read_module(struct snapshot_s *s); +int delaep256_snapshot_write_module(struct snapshot_s *s); +int delaep256_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/delaep64.c b/src/Emulators/vice/c64/cart/delaep64.c index 940f731c..f2252d45 100644 --- a/src/Emulators/vice/c64/cart/delaep64.c +++ b/src/Emulators/vice/c64/cart/delaep64.c @@ -95,11 +95,11 @@ static int currbank = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void delaep64_io1(BYTE value, unsigned int mode) +static void delaep64_io1(uint8_t value, unsigned int mode) { - BYTE bank, config; + uint8_t bank, config; regval = value; @@ -122,21 +122,21 @@ static void delaep64_io1(BYTE value, unsigned int mode) currbank = bank; } -static BYTE delaep64_io1_read(WORD addr) +static uint8_t delaep64_io1_read(uint16_t addr) { - BYTE value = vicii_read_phi1(); + uint8_t value = vicii_read_phi1(); delaep64_io1(value, CMODE_READ); return 0; } -static BYTE delaep64_io1_peek(WORD addr) +static uint8_t delaep64_io1_peek(uint16_t addr) { return regval; } -void delaep64_io1_store(WORD addr, BYTE value) +static void delaep64_io1_store(uint16_t addr, uint8_t value) { delaep64_io1(value, CMODE_WRITE); } @@ -152,18 +152,20 @@ static int delaep64_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t delaep64_device = { - CARTRIDGE_NAME_DELA_EP64, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - delaep64_io1_store, - delaep64_io1_read, - delaep64_io1_peek, - delaep64_dump, - CARTRIDGE_DELA_EP64, - 0, - 0 + CARTRIDGE_NAME_DELA_EP64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + delaep64_io1_store, /* store function */ + NULL, /* NO poke function */ + delaep64_io1_read, /* read function */ + delaep64_io1_peek, /* peek function */ + delaep64_dump, /* device state information dump function */ + CARTRIDGE_DELA_EP64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *delaep64_list_item = NULL; @@ -179,7 +181,7 @@ void delaep64_config_init(void) delaep64_io1(0, CMODE_READ); } -void delaep64_config_setup(BYTE *rawcart) +void delaep64_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 9); delaep64_io1(0, CMODE_READ); @@ -195,7 +197,7 @@ static int delaep64_common_attach(void) return 0; } -int delaep64_bin_attach(const char *filename, BYTE *rawcart) +int delaep64_bin_attach(const char *filename, uint8_t *rawcart) { int size = 0x12000; @@ -210,7 +212,7 @@ int delaep64_bin_attach(const char *filename, BYTE *rawcart) return -1; } -int delaep64_crt_attach(FILE *fd, BYTE *rawcart) +int delaep64_crt_attach(FILE *fd, uint8_t *rawcart) { int rom_size = -1; crt_chip_header_t chip; @@ -285,7 +287,7 @@ void delaep64_detach(void) ARRAY | ROML | 0.0+ | 73728 BYTES of ROML data */ -static char snap_module_name[] = "CARTDELAEP64"; +static const char snap_module_name[] = "CARTDELAEP64"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -301,7 +303,7 @@ int delaep64_snapshot_write_module(snapshot_t *s) if (0 || (SMW_B(m, regval) < 0) - || (SMW_B(m, (BYTE)currbank) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 9) < 0)) { snapshot_module_close(m); return -1; @@ -312,7 +314,7 @@ int delaep64_snapshot_write_module(snapshot_t *s) int delaep64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -322,13 +324,13 @@ int delaep64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/delaep64.h b/src/Emulators/vice/c64/cart/delaep64.h index 62d4a752..066236d9 100644 --- a/src/Emulators/vice/c64/cart/delaep64.h +++ b/src/Emulators/vice/c64/cart/delaep64.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void delaep64_config_init(void); -extern void delaep64_config_setup(BYTE *rawcart); -extern int delaep64_bin_attach(const char *filename, BYTE *rawcart); -extern int delaep64_crt_attach(FILE *fd, BYTE *rawcart); -extern void delaep64_detach(void); +void delaep64_config_init(void); +void delaep64_config_setup(uint8_t *rawcart); +int delaep64_bin_attach(const char *filename, uint8_t *rawcart); +int delaep64_crt_attach(FILE *fd, uint8_t *rawcart); +void delaep64_detach(void); struct snapshot_s; -extern int delaep64_snapshot_write_module(struct snapshot_s *s); -extern int delaep64_snapshot_read_module(struct snapshot_s *s); +int delaep64_snapshot_write_module(struct snapshot_s *s); +int delaep64_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/delaep7x8.c b/src/Emulators/vice/c64/cart/delaep7x8.c index 0fcd4724..b467bdd3 100644 --- a/src/Emulators/vice/c64/cart/delaep7x8.c +++ b/src/Emulators/vice/c64/cart/delaep7x8.c @@ -84,11 +84,11 @@ static int currbank = 0; -static BYTE regval = 0xfe; +static uint8_t regval = 0xfe; -static void delaep7x8_io1_store(WORD addr, BYTE value) +static void delaep7x8_io1_store(uint16_t addr, uint8_t value) { - BYTE bank, config, test_value; + uint8_t bank, config, test_value; regval = value; @@ -110,7 +110,7 @@ static void delaep7x8_io1_store(WORD addr, BYTE value) } } -static BYTE delaep7x8_io1_peek(WORD addr) +static uint8_t delaep7x8_io1_peek(uint16_t addr) { return regval; } @@ -126,18 +126,20 @@ static int delaep7x8_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t delaep7x8_device = { - CARTRIDGE_NAME_DELA_EP7x8, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - delaep7x8_io1_store, - NULL, - delaep7x8_io1_peek, - delaep7x8_dump, - CARTRIDGE_DELA_EP7x8, - 0, - 0 + CARTRIDGE_NAME_DELA_EP7x8, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, device is write only */ + delaep7x8_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + delaep7x8_io1_peek, /* peek function */ + delaep7x8_dump, /* device state information dump function */ + CARTRIDGE_DELA_EP7x8, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *delaep7x8_list_item = NULL; @@ -150,14 +152,14 @@ static const export_resource_t export_res = { void delaep7x8_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } -void delaep7x8_config_setup(BYTE *rawcart) +void delaep7x8_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 8); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } @@ -172,7 +174,7 @@ static int delaep7x8_common_attach(void) return 0; } -int delaep7x8_bin_attach(const char *filename, BYTE *rawcart) +int delaep7x8_bin_attach(const char *filename, uint8_t *rawcart) { int size = 0x10000; @@ -188,7 +190,7 @@ int delaep7x8_bin_attach(const char *filename, BYTE *rawcart) return -1; } -int delaep7x8_crt_attach(FILE *fd, BYTE *rawcart) +int delaep7x8_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -228,7 +230,7 @@ void delaep7x8_detach(void) ARRAY | ROML | 0.0+ | 65536 BYTES of ROML data */ -static char snap_module_name[] = "CARTDELAEP7X8"; +static const char snap_module_name[] = "CARTDELAEP7X8"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -244,7 +246,7 @@ int delaep7x8_snapshot_write_module(snapshot_t *s) if (0 || (SMW_B(m, regval) < 0) - || (SMW_B(m, (BYTE)currbank) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 8) < 0)) { snapshot_module_close(m); return -1; @@ -255,7 +257,7 @@ int delaep7x8_snapshot_write_module(snapshot_t *s) int delaep7x8_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -265,13 +267,13 @@ int delaep7x8_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/delaep7x8.h b/src/Emulators/vice/c64/cart/delaep7x8.h index f2a630a4..33713bba 100644 --- a/src/Emulators/vice/c64/cart/delaep7x8.h +++ b/src/Emulators/vice/c64/cart/delaep7x8.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void delaep7x8_config_init(void); -extern void delaep7x8_config_setup(BYTE *rawcart); -extern int delaep7x8_bin_attach(const char *filename, BYTE *rawcart); -extern int delaep7x8_crt_attach(FILE *fd, BYTE *rawcart); -extern void delaep7x8_detach(void); +void delaep7x8_config_init(void); +void delaep7x8_config_setup(uint8_t *rawcart); +int delaep7x8_bin_attach(const char *filename, uint8_t *rawcart); +int delaep7x8_crt_attach(FILE *fd, uint8_t *rawcart); +void delaep7x8_detach(void); struct snapshot_s; -extern int delaep7x8_snapshot_write_module(struct snapshot_s *s); -extern int delaep7x8_snapshot_read_module(struct snapshot_s *s); +int delaep7x8_snapshot_write_module(struct snapshot_s *s); +int delaep7x8_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/diashowmaker.c b/src/Emulators/vice/c64/cart/diashowmaker.c index 376596b7..4f64e24e 100644 --- a/src/Emulators/vice/c64/cart/diashowmaker.c +++ b/src/Emulators/vice/c64/cart/diashowmaker.c @@ -81,7 +81,12 @@ static int dsm_active = 0; -static BYTE dsm_io1_read(WORD addr) +/* We use the entire $de00-$deff range, even though the software only uses $de00, + * and we only react to address $de00, this is to fine tune the emulation when/if + * a working piece of software for the diashow maker shows up that uses an address + * other than $de00 + */ +static uint8_t dsm_io1_read(uint16_t addr) { DBG(("io1 r %04x\n", addr)); if (addr == 0) { @@ -92,12 +97,17 @@ static BYTE dsm_io1_read(WORD addr) return 0; /* invalid */ } -static BYTE dsm_io1_peek(WORD addr) +static uint8_t dsm_io1_peek(uint16_t addr) { return 0; } -static void dsm_io1_store(WORD addr, BYTE value) +/* We use the entire $de00-$deff range, even though the software only uses $de00, + * and we only react to address $de00, this is to fine tune the emulation when/if + * a working piece of software for the diashow maker shows up that uses an address + * other than $de00 + */ +static void dsm_io1_store(uint16_t addr, uint8_t value) { DBG(("io1 w %04x %02x\n", addr, value)); if (addr == 0) { @@ -115,18 +125,20 @@ static int dsm_dump(void) } static io_source_t dsm_io1_device = { - CARTRIDGE_NAME_DIASHOW_MAKER, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - dsm_io1_store, - dsm_io1_read, - dsm_io1_peek, - dsm_dump, - CARTRIDGE_DIASHOW_MAKER, - 0, - 0 + CARTRIDGE_NAME_DIASHOW_MAKER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, reg: $de00, unknown mirrors:$de01-$deff */ + 0, /* read is never valid */ + dsm_io1_store, /* store function */ + NULL, /* NO poke function */ + dsm_io1_read, /* read function */ + dsm_io1_peek, /* peek function */ + dsm_dump, /* device state information dump function */ + CARTRIDGE_DIASHOW_MAKER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *dsm_io1_list_item = NULL; @@ -151,7 +163,7 @@ void dsm_config_init(void) dsm_active = 1; } -void dsm_config_setup(BYTE *rawcart) +void dsm_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, DSM_CART_SIZE); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); @@ -170,7 +182,7 @@ static int dsm_common_attach(void) return 0; } -int dsm_bin_attach(const char *filename, BYTE *rawcart) +int dsm_bin_attach(const char *filename, uint8_t *rawcart) { DBG(("Diashow Maker: bin attach '%s'\n", filename)); if (util_file_load(filename, rawcart, DSM_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -180,7 +192,7 @@ int dsm_bin_attach(const char *filename, BYTE *rawcart) return dsm_common_attach(); } -int dsm_crt_attach(FILE *fd, BYTE *rawcart) +int dsm_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -216,7 +228,7 @@ void dsm_detach(void) ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTDSM"; +static const char snap_module_name[] = "CARTDSM"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -231,7 +243,7 @@ int dsm_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)dsm_active) < 0) + || (SMW_B(m, (uint8_t)dsm_active) < 0) || (SMW_BA(m, roml_banks, DSM_CART_SIZE) < 0)) { snapshot_module_close(m); return -1; @@ -242,7 +254,7 @@ int dsm_snapshot_write_module(snapshot_t *s) int dsm_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -252,13 +264,13 @@ int dsm_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &dsm_active) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/diashowmaker.h b/src/Emulators/vice/c64/cart/diashowmaker.h index d3690b73..1ff31a0d 100644 --- a/src/Emulators/vice/c64/cart/diashowmaker.h +++ b/src/Emulators/vice/c64/cart/diashowmaker.h @@ -31,16 +31,16 @@ #include "vicetypes.h" -extern void dsm_config_init(void); -extern void dsm_config_setup(BYTE *rawcart); -extern int dsm_bin_attach(const char *filename, BYTE *rawcart); -extern int dsm_crt_attach(FILE *fd, BYTE *rawcart); -extern void dsm_detach(void); -extern void dsm_freeze(void); +void dsm_config_init(void); +void dsm_config_setup(uint8_t *rawcart); +int dsm_bin_attach(const char *filename, uint8_t *rawcart); +int dsm_crt_attach(FILE *fd, uint8_t *rawcart); +void dsm_detach(void); +void dsm_freeze(void); struct snapshot_s; -extern int dsm_snapshot_write_module(struct snapshot_s *s); -extern int dsm_snapshot_read_module(struct snapshot_s *s); +int dsm_snapshot_write_module(struct snapshot_s *s); +int dsm_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/digimax.c b/src/Emulators/vice/c64/cart/digimax.c index 7e262bbe..be961f73 100644 --- a/src/Emulators/vice/c64/cart/digimax.c +++ b/src/Emulators/vice/c64/cart/digimax.c @@ -44,7 +44,6 @@ #include "sound.h" #include "uiapi.h" #include "util.h" -#include "translate.h" //#include "digimaxcore.c" @@ -79,113 +78,138 @@ */ /* This source file contains the sound core for the cartridge, - the shortbus and userport versions of the device, and is intended - to be included from a specific digimax device. */ + the shortbus and userport versions of the device, and is intended + to be included from a specific digimax device. */ /* Some prototypes are needed */ static int digimax_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); -static int digimax_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); -static void digimax_sound_machine_store(sound_t *psid, WORD addr, BYTE val); -static BYTE digimax_sound_machine_read(sound_t *psid, WORD addr); +static void digimax_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val); +static uint8_t digimax_sound_machine_read(sound_t *psid, uint16_t addr); static void digimax_sound_reset(sound_t *psid, CLOCK cpu_clk); +#ifdef SOUND_SYSTEM_FLOAT +static int digimax_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int digimax_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int digimax_sound_machine_cycle_based(void) { - return 0; + return 0; } static int digimax_sound_machine_channels(void) { - return 1; /* FIXME: needs to become stereo for stereo capable ports */ + return 4; } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the DigiMAX sound */ +static sound_chip_mixing_spec_t digimax_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* DAC 1 left channel volume % in case of stereo output, default output to left only */ + 0, /* DAC 1 right channel volume % in case of stereo output, default output to left only */ + }, + { + 100, /* DAC 2 left channel volume % in case of stereo output, default output to left only */ + 0, /* DAC 2 right channel volume % in case of stereo output, default output to left only */ + }, + { + 0, /* DAC 3 left channel volume % in case of stereo output, default output to right only */ + 100, /* DAC 3 right channel volume % in case of stereo output, default output to right only */ + }, + { + 0, /* DAC 4 left channel volume % in case of stereo output, default output to right only */ + 100, /* DAC 4 right channel volume % in case of stereo output, default output to right only */ + } +}; +#endif + +/* DigiMAX sound chip, as used in the IDE64-shortbus DigiMAX device, userport DigiMAX device and c64/c128 DigiMAX cartridge */ static sound_chip_t digimax_sound_chip = { - NULL, /* no open */ - digimax_sound_machine_init, - NULL, /* no close */ - digimax_sound_machine_calculate_samples, - digimax_sound_machine_store, - digimax_sound_machine_read, - digimax_sound_reset, - digimax_sound_machine_cycle_based, - digimax_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + digimax_sound_machine_init, /* sound chip init function */ + NULL, /* NO sound chip close function */ + digimax_sound_machine_calculate_samples, /* sound chip calculate samples function */ + digimax_sound_machine_store, /* sound chip store function */ + digimax_sound_machine_read, /* sound chip read function */ + digimax_sound_reset, /* sound chip reset function */ + digimax_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, chip is NOT cycle based */ + digimax_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 4 channels */ +#ifdef SOUND_SYSTEM_FLOAT + digimax_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* sound chip enabled flag, toggled upon device (de-)activation */ }; -static WORD digimax_sound_chip_offset = 0; +static uint16_t digimax_sound_chip_offset = 0; /* ---------------------------------------------------------------------*/ static sound_dac_t digimax_dac[4]; -static BYTE digimax_sound_data[4]; +static uint8_t digimax_sound_data[4]; struct digimax_sound_s { - BYTE voice0; - BYTE voice1; - BYTE voice2; - BYTE voice3; + uint8_t voice[4]; }; static struct digimax_sound_s snd; -static int digimax_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME: fix this for multichannel output */ +static int digimax_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) { - sound_dac_calculate_samples(&digimax_dac[0], pbuf, (int)snd.voice0 * 64, nr, soc, 1); - sound_dac_calculate_samples(&digimax_dac[1], pbuf, (int)snd.voice1 * 64, nr, soc, (soc > 1) ? 2 : 1); - sound_dac_calculate_samples(&digimax_dac[2], pbuf, (int)snd.voice2 * 64, nr, soc, 1); - sound_dac_calculate_samples(&digimax_dac[3], pbuf, (int)snd.voice3 * 64, nr, soc, (soc > 1) ? 2 : 1); - return nr; + sound_dac_calculate_samples(&digimax_dac[scc], pbuf, (int)snd.voice[scc] * 64, nr); + + return nr; +} +#else +static int digimax_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) +{ + sound_dac_calculate_samples(&digimax_dac[0], pbuf, (int)snd.voice[0] * 64, nr, soc, SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[1], pbuf, (int)snd.voice[1] * 64, nr, soc, (soc == SOUND_OUTPUT_STEREO) ? SOUND_CHANNEL_2 : SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[2], pbuf, (int)snd.voice[2] * 64, nr, soc, SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[3], pbuf, (int)snd.voice[3] * 64, nr, soc, (soc == SOUND_OUTPUT_STEREO) ? SOUND_CHANNEL_2 : SOUND_CHANNEL_1); + return nr; } +#endif static int digimax_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec) { - sound_dac_init(&digimax_dac[0], speed); - sound_dac_init(&digimax_dac[1], speed); - sound_dac_init(&digimax_dac[2], speed); - sound_dac_init(&digimax_dac[3], speed); - snd.voice0 = 0; - snd.voice1 = 0; - snd.voice2 = 0; - snd.voice3 = 0; - - return 1; + sound_dac_init(&digimax_dac[0], speed); + sound_dac_init(&digimax_dac[1], speed); + sound_dac_init(&digimax_dac[2], speed); + sound_dac_init(&digimax_dac[3], speed); + snd.voice[0] = 0; + snd.voice[1] = 0; + snd.voice[2] = 0; + snd.voice[3] = 0; + + return 1; } -static void digimax_sound_machine_store(sound_t *psid, WORD addr, BYTE val) +static void digimax_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val) { - switch (addr & 3) { - case 0: - snd.voice0 = val; - break; - case 1: - snd.voice1 = val; - break; - case 2: - snd.voice2 = val; - break; - case 3: - snd.voice3 = val; - break; - } + snd.voice[addr & 3] = val; } -static BYTE digimax_sound_machine_read(sound_t *psid, WORD addr) +static uint8_t digimax_sound_machine_read(sound_t *psid, uint16_t addr) { - return digimax_sound_data[addr & 3]; + return digimax_sound_data[addr & 3]; } static void digimax_sound_reset(sound_t *psid, CLOCK cpu_clk) { - snd.voice0 = 0; - snd.voice1 = 0; - snd.voice2 = 0; - snd.voice3 = 0; - digimax_sound_data[0] = 0; - digimax_sound_data[1] = 0; - digimax_sound_data[2] = 0; - digimax_sound_data[3] = 0; + snd.voice[0] = 0; + snd.voice[1] = 0; + snd.voice[2] = 0; + snd.voice[3] = 0; + digimax_sound_data[0] = 0; + digimax_sound_data[1] = 0; + digimax_sound_data[2] = 0; + digimax_sound_data[3] = 0; } @@ -212,22 +236,24 @@ static char *digimax_address_list = NULL; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void digimax_sound_store(WORD addr, BYTE value); -static BYTE digimax_sound_read(WORD addr); +static void digimax_sound_store(uint16_t addr, uint8_t value); +static uint8_t digimax_sound_read(uint16_t addr); static io_source_t digimax_device = { - CARTRIDGE_NAME_DIGIMAX, - IO_DETACH_RESOURCE, - "DIGIMAX", - 0xde00, 0xde03, 0x03, - 1, /* read is always valid */ - digimax_sound_store, - digimax_sound_read, - digimax_sound_read, - NULL, /* nothing to dump */ - CARTRIDGE_DIGIMAX, - 0, - 0 + CARTRIDGE_NAME_DIGIMAX, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "DIGIMAX", /* resource to set to '0' */ + 0xde00, 0xde03, 0x03, /* range for the device, regs:$de00-$de03, range for vic20 will be different */ + 1, /* read is always valid */ + digimax_sound_store, /* store function */ + NULL, /* NO poke function */ + digimax_sound_read, /* read function */ + digimax_sound_read, /* peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_DIGIMAX, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t * digimax_list_item = NULL; @@ -248,15 +274,15 @@ int digimax_cart_enabled(void) return digimax_sound_chip.chip_enabled; } -static void digimax_sound_store(WORD addr, BYTE value) +static void digimax_sound_store(uint16_t addr, uint8_t value) { digimax_sound_data[addr] = value; - sound_store((WORD)(digimax_sound_chip_offset | addr), value, 0); + sound_store((uint16_t)(digimax_sound_chip_offset | addr), value, 0); } -static BYTE digimax_sound_read(WORD addr) +static uint8_t digimax_sound_read(uint16_t addr) { - BYTE value = sound_read((WORD)(digimax_sound_chip_offset | addr), 0); + uint8_t value = sound_read((uint16_t)(digimax_sound_chip_offset | addr), 0); return value; } @@ -293,14 +319,6 @@ static int set_digimax_base(int val, void *param) return 0; } - if (addr == 0xffff) { - if (machine_class == VICE_MACHINE_VIC20) { - addr = 0x9800; - } else { - addr = 0xde00; - } - } - if (old) { set_digimax_enabled(0, NULL); } @@ -315,8 +333,8 @@ static int set_digimax_base(int val, void *param) case 0xdec0: case 0xdee0: if (machine_class != VICE_MACHINE_VIC20) { - digimax_device.start_address = (WORD)addr; - digimax_device.end_address = (WORD)(addr + 3); + digimax_device.start_address = (uint16_t)addr; + digimax_device.end_address = (uint16_t)(addr + 3); export_res.io1 = &digimax_device; export_res.io2 = NULL; } else { @@ -332,8 +350,8 @@ static int set_digimax_base(int val, void *param) case 0xdfc0: case 0xdfe0: if (machine_class != VICE_MACHINE_VIC20) { - digimax_device.start_address = (WORD)addr; - digimax_device.end_address = (WORD)(addr + 3); + digimax_device.start_address = (uint16_t)addr; + digimax_device.end_address = (uint16_t)(addr + 3); export_res.io1 = NULL; export_res.io2 = &digimax_device; } else { @@ -357,8 +375,8 @@ static int set_digimax_base(int val, void *param) case 0x9cc0: case 0x9ce0: if (machine_class == VICE_MACHINE_VIC20) { - digimax_device.start_address = (WORD)addr; - digimax_device.end_address = (WORD)(addr + 3); + digimax_device.start_address = (uint16_t)addr; + digimax_device.end_address = (uint16_t)(addr + 3); } else { return -1; } @@ -384,6 +402,11 @@ int digimax_enable(void) return resources_set_int("DIGIMAX", 1); } +int digimax_disable(void) +{ + return resources_set_int("DIGIMAX", 0); +} + void digimax_detach(void) { resources_set_int("DIGIMAX", 0); @@ -391,9 +414,13 @@ void digimax_detach(void) /* ---------------------------------------------------------------------*/ -static const resource_int_t resources_int[] = { +static resource_int_t resources_int[] = { { "DIGIMAX", 0, RES_EVENT_STRICT, (resource_value_t)0, &digimax_sound_chip.chip_enabled, set_digimax_enabled, NULL }, + /* + * The 'factory_value' gets set a proper default value for the current + * emu in digimix_resource_init() + */ { "DIGIMAXbase", 0xffff, RES_EVENT_NO, NULL, &digimax_address, set_digimax_base, NULL }, RESOURCE_INT_LIST_END @@ -401,6 +428,11 @@ static const resource_int_t resources_int[] = { int digimax_resources_init(void) { + if (machine_class == VICE_MACHINE_VIC20) { + resources_int[1].factory_value = 0x9800; + } else { + resources_int[1].factory_value = 0xde00; + } return resources_register_int(resources_int); } @@ -415,26 +447,20 @@ void digimax_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-digimax", SET_RESOURCE, 0, + { "-digimax", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DIGIMAX", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DIGIMAX, - NULL, NULL }, - { "+digimax", SET_RESOURCE, 0, + NULL, "Enable the DigiMAX cartridge" }, + { "+digimax", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DIGIMAX", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DIGIMAX, - NULL, NULL }, + NULL, "Disable the DigiMAX cartridge" }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-digimaxbase", SET_RESOURCE, 1, + { "-digimaxbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DIGIMAXbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_DIGIMAX_BASE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -449,11 +475,11 @@ int digimax_cmdline_options_init(void) if (machine_class == VICE_MACHINE_VIC20) { temp1 = util_gen_hex_address_list(0x9800, 0x9900, 0x20); temp2 = util_gen_hex_address_list(0x9c00, 0x9d00, 0x20); - digimax_address_list = util_concat(". (", temp1, "/", temp2, ")", NULL); + digimax_address_list = util_concat("Base address of the DigiMAX cartridge. (", temp1, "/", temp2, ")", NULL); lib_free(temp2); } else { temp1 = util_gen_hex_address_list(0xde00, 0xe000, 0x20); - digimax_address_list = util_concat(". (", temp1, ")", NULL); + digimax_address_list = util_concat("Base address of the DigiMAX cartridge. (", temp1, ")", NULL); } lib_free(temp1); @@ -476,7 +502,7 @@ int digimax_cmdline_options_init(void) BYTE | voice 3 | voice 3 data */ -static char snap_module_name[] = "CARTDIGIMAX"; +static const char snap_module_name[] = "CARTDIGIMAX"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -491,12 +517,12 @@ int digimax_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_DW(m, (DWORD)digimax_address) < 0) + || (SMW_DW(m, (uint32_t)digimax_address) < 0) || (SMW_BA(m, digimax_sound_data, 4) < 0) - || (SMW_B(m, snd.voice0) < 0) - || (SMW_B(m, snd.voice1) < 0) - || (SMW_B(m, snd.voice2) < 0) - || (SMW_B(m, snd.voice3) < 0)) { + || (SMW_B(m, snd.voice[0]) < 0) + || (SMW_B(m, snd.voice[1]) < 0) + || (SMW_B(m, snd.voice[2]) < 0) + || (SMW_B(m, snd.voice[3]) < 0)) { snapshot_module_close(m); return -1; } @@ -506,7 +532,7 @@ int digimax_snapshot_write_module(snapshot_t *s) int digimax_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int temp_digimax_address; @@ -517,7 +543,7 @@ int digimax_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -525,10 +551,10 @@ int digimax_snapshot_read_module(snapshot_t *s) if (0 || (SMR_DW_INT(m, &temp_digimax_address) < 0) || (SMR_BA(m, digimax_sound_data, 4) < 0) - || (SMR_B(m, &snd.voice0) < 0) - || (SMR_B(m, &snd.voice1) < 0) - || (SMR_B(m, &snd.voice2) < 0) - || (SMR_B(m, &snd.voice3) < 0)) { + || (SMR_B(m, &snd.voice[0]) < 0) + || (SMR_B(m, &snd.voice[1]) < 0) + || (SMR_B(m, &snd.voice[2]) < 0) + || (SMR_B(m, &snd.voice[3]) < 0)) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/digimax.h b/src/Emulators/vice/c64/cart/digimax.h index 80c8699f..9fa2c2ff 100644 --- a/src/Emulators/vice/c64/cart/digimax.h +++ b/src/Emulators/vice/c64/cart/digimax.h @@ -30,20 +30,21 @@ #include "vicetypes.h" #include "sound.h" -extern int digimax_cart_enabled(void); -extern int digimax_enable(void); -extern void digimax_detach(void); -extern void digimax_reset(void); +int digimax_cart_enabled(void); +int digimax_enable(void); +int digimax_disable(void); +void digimax_detach(void); +void digimax_reset(void); -extern int digimax_resources_init(void); -extern void digimax_resources_shutdown(void); -extern int digimax_cmdline_options_init(void); +int digimax_resources_init(void); +void digimax_resources_shutdown(void); +int digimax_cmdline_options_init(void); -extern void digimax_sound_chip_init(void); +void digimax_sound_chip_init(void); struct snapshot_s; -extern int digimax_snapshot_write_module(struct snapshot_s *s); -extern int digimax_snapshot_read_module(struct snapshot_s *s); +int digimax_snapshot_write_module(struct snapshot_s *s); +int digimax_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/dinamic.c b/src/Emulators/vice/c64/cart/dinamic.c index a33be960..d360ae79 100644 --- a/src/Emulators/vice/c64/cart/dinamic.c +++ b/src/Emulators/vice/c64/cart/dinamic.c @@ -64,7 +64,7 @@ static int currbank = 0; -static BYTE dinamic_io1_read(WORD addr) +static uint8_t dinamic_io1_read(uint16_t addr) { DBG(("@ $%04x io1 rd %04x (bank: %02x)\n", reg_pc, addr, addr & 0x0f)); if ((addr & 0x0f) == addr) { @@ -75,7 +75,7 @@ static BYTE dinamic_io1_read(WORD addr) return 0; } -static BYTE dinamic_io1_peek(WORD addr) +static uint8_t dinamic_io1_peek(uint16_t addr) { return 0; } @@ -89,18 +89,20 @@ static int dinamic_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t dinamic_io1_device = { - CARTRIDGE_NAME_DINAMIC, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* reads are never valid */ - NULL, - dinamic_io1_read, - dinamic_io1_peek, - dinamic_dump, - CARTRIDGE_DINAMIC, - 0, - 0 + CARTRIDGE_NAME_DINAMIC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$de0f, unknown mirrors:$de10-$deff */ + 0, /* reads are never valid */ + NULL, /* store function */ + NULL, /* NO poke function */ + dinamic_io1_read, /* read function */ + dinamic_io1_peek, /* peek function */ + dinamic_dump, /* device state information dump function */ + CARTRIDGE_DINAMIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *dinamic_io1_list_item = NULL; @@ -113,13 +115,13 @@ static const export_resource_t export_res = { void dinamic_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } -void dinamic_config_setup(BYTE *rawcart) +void dinamic_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 16); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -133,7 +135,7 @@ static int dinamic_common_attach(void) return 0; } -int dinamic_bin_attach(const char *filename, BYTE *rawcart) +int dinamic_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -141,7 +143,7 @@ int dinamic_bin_attach(const char *filename, BYTE *rawcart) return dinamic_common_attach(); } -int dinamic_crt_attach(FILE *fd, BYTE *rawcart) +int dinamic_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -179,7 +181,7 @@ void dinamic_detach(void) ARRAY | ROML | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTDINAMIC"; +static const char snap_module_name[] = "CARTDINAMIC"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -194,7 +196,7 @@ int dinamic_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)currbank) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 16) < 0)) { snapshot_module_close(m); return -1; @@ -205,7 +207,7 @@ int dinamic_snapshot_write_module(snapshot_t *s) int dinamic_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -215,7 +217,7 @@ int dinamic_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/dinamic.h b/src/Emulators/vice/c64/cart/dinamic.h index 80610436..26e5ee35 100644 --- a/src/Emulators/vice/c64/cart/dinamic.h +++ b/src/Emulators/vice/c64/cart/dinamic.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void dinamic_config_init(void); -extern void dinamic_config_setup(BYTE *rawcart); -extern int dinamic_bin_attach(const char *filename, BYTE *rawcart); -extern int dinamic_crt_attach(FILE *fd, BYTE *rawcart); -extern void dinamic_detach(void); +void dinamic_config_init(void); +void dinamic_config_setup(uint8_t *rawcart); +int dinamic_bin_attach(const char *filename, uint8_t *rawcart); +int dinamic_crt_attach(FILE *fd, uint8_t *rawcart); +void dinamic_detach(void); struct snapshot_s; -extern int dinamic_snapshot_write_module(struct snapshot_s *s); -extern int dinamic_snapshot_read_module(struct snapshot_s *s); +int dinamic_snapshot_write_module(struct snapshot_s *s); +int dinamic_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/dqbb.c b/src/Emulators/vice/c64/cart/dqbb.c index cc6126ec..df19dfc4 100644 --- a/src/Emulators/vice/c64/cart/dqbb.c +++ b/src/Emulators/vice/c64/cart/dqbb.c @@ -39,11 +39,12 @@ #include "cmdline.h" #include "export.h" #include "lib.h" +#include "log.h" #include "mem.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -52,22 +53,41 @@ #undef CARTRIDGE_INCLUDE_PRIVATE_API /* - "Double Quick Brown box" + (Double) Quick Brown Box - - 16k RAM + There have been 3 incarnations of this cartridge, and each was available in + various versions with different amount of memory: - The Double Quick Brown box is a banked memory system. - It uses a register at $de00 to control the areas used, the - read/write / read-only state and on/off of the cart. + 1st: "QBB" (Quick Brown Box) - C64 only, 8kb in the smallest variant + 2nd: "QBB-B" adds battery backup + 3rd: "DQBB" (Double Quick Brown Box) - adds C128 support, 16kb - This is done as follows: + The last incarnation has a switch to enable either C64 or C128 mode (see below) - bit 2: 1 = $A000-$BFFF mapped in, 0 = $A000-$BFFF not mapped in. + Write-Only register at $de00: + + bit 2: controls the /GAME line: + 1 = $A000-$BFFF mapped in (/GAME low) + 0 = $A000-$BFFF not mapped in (/GAME high) bit 4: 1 = read/write, 0 = read-only. - bit 7: 1 = cart off, 0 = cart on. + bit 6: controls the /EXROM line: (*) + 1 = /EXROM low + 0 = /EXROM low + bit 7: 1 = cart off, 0 = cart on. (register remains active) + + (*) The switch holds /EXROM low when in C64 position, so this bit can be + used to force the C128 into C64, when the switch is in C128 position. + + The remaining 4 bits are used for banking, consequently the largest available + variant had 256k RAM. Which variants actually existed for real remains unknown, + ads frequently mention all possible (16/32/64/128/256k) variants however. + + C128 mode (DQBB only): + + - ROM mapped to $8000-BFFF - The register is write-only. Attempting to read it will - only return random values. + A hardware RESET or power up clears all bits, so in C64 mode it will always + start with 8k mapped. The current emulation has the register mirrorred through the range of $de00-$deff @@ -76,18 +96,22 @@ /* #define DBGDQBB */ #ifdef DBGDQBB -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif +static log_t dqbb_log = LOG_DEFAULT; /*!< the log output for the dqbb_log */ + /* DQBB register bits */ -static int dqbb_a000_mapped; +static int dqbb_game; static int dqbb_readwrite; static int dqbb_off; +static int dqbb_exrom; +static int dqbb_bank; /* DQBB image. */ -static BYTE *dqbb_ram = NULL; +static uint8_t *dqbb_ram = NULL; static int dqbb_activate(void); static int dqbb_deactivate(void); @@ -99,7 +123,12 @@ static int dqbb_enabled = 0; /* Filename of the DQBB image. */ static char *dqbb_filename = NULL; -#define DQBB_RAM_SIZE 0x4000 +#define DQBB_RAM_SIZE (0x400 * 256) /* max. size */ + +static int dqbb_size; /* actual size */ +static int dqbb_bank_mask; + +static int dqbb_mode_switch; /* 0: C128, 1: C64 */ static int reg_value = 0; @@ -107,23 +136,25 @@ static int dqbb_write_image = 0; /* ------------------------------------------------------------------------- */ -static BYTE dqbb_io1_peek(WORD addr); -static void dqbb_io1_store(WORD addr, BYTE byte); +static uint8_t dqbb_io1_peek(uint16_t addr); +static void dqbb_io1_store(uint16_t addr, uint8_t byte); static int dqbb_dump(void); static io_source_t dqbb_io1_device = { - CARTRIDGE_NAME_DQBB, - IO_DETACH_RESOURCE, - "DQBB", - 0xde00, 0xdeff, 0x01, - 0, - dqbb_io1_store, - NULL, - dqbb_io1_peek, - dqbb_dump, - CARTRIDGE_DQBB, - 0, - 0 + CARTRIDGE_NAME_DQBB, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "DQBB", /* resource to set to '0' */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors: $de01-$deff */ + 0, /* read is never valid, device is write only */ + dqbb_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + dqbb_io1_peek, /* peek function */ + dqbb_dump, /* device state information dump function */ + CARTRIDGE_DQBB, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *dqbb_io1_list_item = NULL; @@ -141,31 +172,47 @@ int dqbb_cart_enabled(void) static void dqbb_change_config(void) { + int mode = CMODE_RAM; + if (dqbb_enabled) { - if (dqbb_off) { - cart_config_changed_slot1(2, 2, CMODE_READ); - } else { - if (dqbb_a000_mapped) { - cart_config_changed_slot1(1, 1, CMODE_READ); + if (!dqbb_off) { + /* The mode switch pulls exrom when in C64 position */ + if (dqbb_mode_switch || dqbb_exrom) { + if (dqbb_game) { + mode = CMODE_16KGAME; + } else { + mode = CMODE_8KGAME; + } } else { - cart_config_changed_slot1(0, 0, CMODE_READ); + if (dqbb_game) { + /* switch is in C128 position, and /GAME bit is set */ + mode = CMODE_ULTIMAX; + } } } - } else { - cart_config_changed_slot1(2, 2, CMODE_READ); } + + cart_config_changed_slot1(mode, mode, CMODE_READ); + DBG(("dqbb_change_config: 0x%02x (%s) mode:%d enable:%d off:%d game:%d exrom:%d", + (unsigned int)mode, cart_config_string(mode), dqbb_mode_switch, dqbb_enabled, + dqbb_off, dqbb_game, dqbb_exrom)); } -static void dqbb_io1_store(WORD addr, BYTE byte) +static void dqbb_io1_store(uint16_t addr, uint8_t byte) { - dqbb_a000_mapped = (byte & 4) >> 2; - dqbb_readwrite = (byte & 0x10) >> 4; - dqbb_off = (byte & 0x80) >> 7; + dqbb_game = (byte >> 2) & 1; + dqbb_readwrite = (byte >> 4) & 1; + dqbb_exrom = (byte >> 6) & 1; + dqbb_off = (byte >> 7) & 1; + dqbb_bank = (byte & 3) | ((byte >> 1) & 4) | ((byte >> 2) & 8); + dqbb_bank &= dqbb_bank_mask; + DBG(("dqbb_io1_store reg: 0x%02x enabled:%d r/w:%d bank:%d game:%d exrom:%d", + byte, dqbb_off, dqbb_readwrite, dqbb_bank, dqbb_game, dqbb_exrom)); dqbb_change_config(); reg_value = byte; } -static BYTE dqbb_io1_peek(WORD addr) +static uint8_t dqbb_io1_peek(uint16_t addr) { return reg_value; } @@ -175,24 +222,68 @@ static int dqbb_dump(void) mon_out("$A000-$BFFF RAM: %s, cart status: %s\n", (reg_value & 4) ? "mapped in" : "not mapped in", (reg_value & 0x80) ? ((reg_value & 0x10) ? "read/write" : "read-only") : "disabled"); + mon_out("current bank: %d of %d\n", dqbb_bank, dqbb_size / 16); return 0; } /* ------------------------------------------------------------------------- */ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void dqbb_powerup(void) +{ + DBG(("dqbb_powerup")); + if ((dqbb_filename != NULL) && (*dqbb_filename != 0)) { + /* do not init ram if a file is used for ram content (like battery backup) */ + return; + } + if (dqbb_ram) { + DBG(("dqbb_powerup ram clear")); + ram_init_with_pattern(dqbb_ram, DQBB_RAM_SIZE, &ramparam); + } +} + +void dqbb_shutdown(void) +{ + if (dqbb_ram) { + lib_free(dqbb_ram); + } +} + static int dqbb_activate(void) { + DBG(("dqbb_activate")); lib_free(dqbb_ram); dqbb_ram = lib_malloc(DQBB_RAM_SIZE); + ram_init_with_pattern(dqbb_ram, DQBB_RAM_SIZE, &ramparam); + + if (dqbb_log == LOG_DEFAULT) { + dqbb_log = log_open("DQBB"); + } if (!util_check_null_string(dqbb_filename)) { - if (util_file_load(dqbb_filename, dqbb_ram, DQBB_RAM_SIZE, UTIL_FILE_LOAD_RAW) < 0) { + if (util_file_load(dqbb_filename, dqbb_ram, dqbb_size * 0x400, UTIL_FILE_LOAD_RAW) < 0) { /* only create a new file if no file exists, so we dont accidently overwrite any files */ if (!util_file_exists(dqbb_filename)) { - if (util_file_save(dqbb_filename, dqbb_ram, DQBB_RAM_SIZE) < 0) { + if (util_file_save(dqbb_filename, dqbb_ram, dqbb_size * 0x400) < 0) { return -1; } + log_message(dqbb_log, "created '%s'", dqbb_filename); } + } else { + log_message(dqbb_log, "loaded '%s'", dqbb_filename); } } return 0; @@ -200,13 +291,14 @@ static int dqbb_activate(void) static int dqbb_deactivate(void) { + DBG(("dqbb_deactivate")); if (dqbb_ram == NULL) { return 0; } if (!util_check_null_string(dqbb_filename)) { if (dqbb_write_image) { - if (util_file_save(dqbb_filename, dqbb_ram, DQBB_RAM_SIZE) < 0) { + if (util_file_save(dqbb_filename, dqbb_ram, dqbb_size * 0x400) < 0) { return -1; } } @@ -223,6 +315,7 @@ static int dqbb_deactivate(void) static int set_dqbb_enabled(int value, void *param) { int val = value ? 1 : 0; + DBG(("set_dqbb_enabled: val:%d", val)); if ((!val) && (dqbb_enabled)) { cart_power_off(); @@ -247,6 +340,7 @@ static int set_dqbb_enabled(int value, void *param) dqbb_reset(); dqbb_change_config(); } + DBG(("set_dqbb_enabled: dqbb_enabled:%d", dqbb_enabled)); return 0; } @@ -280,6 +374,42 @@ static int set_dqbb_image_write(int val, void *param) return 0; } +static int set_dqbb_size(int val, void *param) +{ + DBG(("set_dqbb_size: val:%d", val)); + if (val != dqbb_size) { + if ((val == 16) || + (val == 32) || + (val == 64) || + (val == 128) || + (val == 256)) { + int was_enabled = dqbb_enabled; + dqbb_deactivate(); + dqbb_size = val; + dqbb_bank_mask = (val == 0) ? 0 : (val / 16) - 1; + if (was_enabled) { + dqbb_activate(); + } + DBG(("set_dqbb_size size: %d mask: 0x%02x", dqbb_size, (unsigned int)dqbb_bank_mask)); + } else { + DBG(("set_dqbb_size: (error) dqbb_size:%d", dqbb_size)); + return -1; + } + } + DBG(("set_dqbb_size: (ok) dqbb_size:%d", dqbb_size)); + return 0; +} + +static int set_dqbb_mode(int val, void *param) +{ + dqbb_mode_switch = (val == DQBB_MODE_C128) ? DQBB_MODE_C128 : DQBB_MODE_C64; + DBG(("set_dqbb_mode: val:%d dqbb_mode_switch: %s", val, dqbb_mode_switch == DQBB_MODE_C64 ? "C64" : "C128")); + if (dqbb_enabled) { + dqbb_change_config(); + } + return 0; +} + /* ---------------------------------------------------------------------*/ static const resource_string_t resources_string[] = { @@ -289,8 +419,12 @@ static const resource_string_t resources_string[] = { }; static const resource_int_t resources_int[] = { - { "DQBB", 0, RES_EVENT_STRICT, (resource_value_t)0, + { "DQBB", 0, RES_EVENT_SAME, NULL, &dqbb_enabled, set_dqbb_enabled, NULL }, + { "DQBBSize", 16, RES_EVENT_SAME, NULL, + &dqbb_size, set_dqbb_size, NULL }, + { "DQBBMode", DQBB_MODE_C64, RES_EVENT_SAME, NULL, + &dqbb_mode_switch, set_dqbb_mode, NULL }, { "DQBBImageWrite", 0, RES_EVENT_NO, NULL, &dqbb_write_image, set_dqbb_image_write, NULL }, RESOURCE_INT_LIST_END @@ -315,31 +449,27 @@ void dqbb_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-dqbb", SET_RESOURCE, 0, + { "-dqbb", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DQBB", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DQBB, - NULL, NULL }, - { "+dqbb", SET_RESOURCE, 0, + NULL, "Enable Double Quick Brown Box" }, + { "+dqbb", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DQBB", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DQBB, - NULL, NULL }, - { "-dqbbimage", SET_RESOURCE, 1, + NULL, "Disable Double Quick Brown Box" }, + { "-dqbbsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "DQBBSize", NULL, + "", "Set Double Quick Brown Box RAM size (16/32/64/128/256kiB)" }, + { "-dqbbmode", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "DQBBMode", NULL, + "", "Set Double Quick Brown Box mode switch (0: C128, 1:C64)" }, + { "-dqbbimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DQBBfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_DQBB_NAME, - NULL, NULL }, - { "-dqbbimagerw", SET_RESOURCE, 0, + "", "Specify Double Quick Brown Box filename" }, + { "-dqbbimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DQBBImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_DQBB_IMAGE, - NULL, NULL }, - { "+dqbbimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to DQBB image" }, + { "+dqbbimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DQBBImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_DQBB_IMAGE, - NULL, NULL }, + NULL, "Do not write to DQBB image" }, CMDLINE_LIST_END }; @@ -357,16 +487,21 @@ const char *dqbb_get_file_name(void) void dqbb_reset(void) { - dqbb_a000_mapped = 0; + dqbb_game = 0; dqbb_readwrite = 0; dqbb_off = 0; + dqbb_bank = 0; + dqbb_exrom = 0; + if (dqbb_enabled) { dqbb_change_config(); } } -void dqbb_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void dqbb_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { + /* FIXME: this doesn't incorporate the banking, nor C128 */ +#if 0 switch (addr & 0xf000) { case 0xb000: case 0xa000: @@ -379,6 +514,7 @@ void dqbb_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) default: break; } +#endif *base = NULL; *start = 0; *limit = 0; @@ -389,7 +525,7 @@ void dqbb_init_config(void) dqbb_reset(); } -void dqbb_config_setup(BYTE *rawcart) +void dqbb_config_setup(uint8_t *rawcart) { memcpy(dqbb_ram, rawcart, DQBB_RAM_SIZE); } @@ -409,9 +545,25 @@ int dqbb_enable(void) return 0; } -int dqbb_bin_attach(const char *filename, BYTE *rawcart) + +/** \brief Disable the cart + * + * Does the same as dqbb_detach(), but required for symmetry I suppose. + * + * \return 0 on success, -1 on failure + */ +int dqbb_disable(void) +{ + if (resources_set_int("DQBB", 0) < 0) { + return -1; + } + return 0; +} + + +int dqbb_bin_attach(const char *filename, uint8_t *rawcart) { - if (util_file_load(filename, rawcart, DQBB_RAM_SIZE, UTIL_FILE_LOAD_RAW) < 0) { + if (util_file_load(filename, rawcart, dqbb_size * 0x400, UTIL_FILE_LOAD_RAW) < 0) { return -1; } util_string_set(&dqbb_filename, filename); @@ -428,7 +580,7 @@ int dqbb_bin_save(const char *filename) return -1; } - if (util_file_save(filename, dqbb_ram, DQBB_RAM_SIZE) < 0) { + if (util_file_save(filename, dqbb_ram, dqbb_size * 0x400) < 0) { return -1; } return 0; @@ -441,44 +593,68 @@ int dqbb_flush_image(void) /* ------------------------------------------------------------------------- */ -BYTE dqbb_roml_read(WORD addr) +uint8_t dqbb_roml_read(uint16_t addr) { - return dqbb_ram[addr & 0x1fff]; + return dqbb_ram[(addr & 0x1fff) + (dqbb_bank * 0x4000)]; } -void dqbb_roml_store(WORD addr, BYTE byte) +void dqbb_roml_store(uint16_t addr, uint8_t byte) { if (dqbb_readwrite) { - dqbb_ram[addr & 0x1fff] = byte; + dqbb_ram[(addr & 0x1fff) + (dqbb_bank * 0x4000)] = byte; } mem_store_without_romlh(addr, byte); } -BYTE dqbb_romh_read(WORD addr) +uint8_t dqbb_romh_read(uint16_t addr) { - return dqbb_ram[(addr & 0x1fff) + 0x2000]; + return dqbb_ram[(addr & 0x1fff) + 0x2000 + (dqbb_bank * 0x4000)]; } -void dqbb_romh_store(WORD addr, BYTE byte) +void dqbb_romh_store(uint16_t addr, uint8_t byte) { if (dqbb_readwrite) { - dqbb_ram[(addr & 0x1fff) + 0x2000] = byte; + dqbb_ram[(addr & 0x1fff) + 0x2000 + (dqbb_bank * 0x4000)] = byte; } mem_store_without_romlh(addr, byte); } -int dqbb_peek_mem(WORD addr, BYTE *value) +int dqbb_peek_mem(uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { - *value = dqbb_ram[addr & 0x1fff]; + *value = dqbb_ram[(addr & 0x1fff) + (dqbb_bank * 0x4000)]; return CART_READ_VALID; } else if ((addr >= 0xa000) && (addr <= 0xbfff)) { - *value = dqbb_ram[(addr & 0x1fff) + 0x2000]; + *value = dqbb_ram[(addr & 0x1fff) + 0x2000 + (dqbb_bank * 0x4000)]; return CART_READ_VALID; } return CART_READ_THROUGH; } + +/* ------------------------------------------------------------------------- */ + +/* In C128 mode the RAM is mapped to $8000-$BFFF */ +int dqbb_c128_read(uint16_t addr, uint8_t *value) +{ + if ((addr >= 0x8000) && (addr <= 0xbfff)) { + *value = dqbb_ram[(addr & 0x3fff) + (dqbb_bank * 0x4000)]; + return CART_READ_VALID; /* read was valid */ + } + return CART_READ_THROUGH; +} + +int dqbb_c128_store(uint16_t addr, uint8_t value) +{ + if ((addr >= 0x8000) && (addr <= 0xbfff)) { + if (dqbb_readwrite) { + dqbb_ram[(addr & 0x3fff) + (dqbb_bank * 0x4000)] = value; + } + return 1; /* write was valid */ + } + return 0; /* write was invalid */ +} + /* ---------------------------------------------------------------------*/ /* CARTDQBB snapshot module format: @@ -487,15 +663,18 @@ int dqbb_peek_mem(WORD addr, BYTE *value) -------------------------------- BYTE | enabled | cartridge enabled flag BYTE | read write | read/write flag - BYTE | a000 map | $A000 mapped flag + BYTE | a000 map | $A000 mapped flag (GAME line) BYTE | off | dqbb off flag BYTE | register | register - ARRAY | RAM | 16768 BYTES of RAM data + BYTE | exrom | state of EXROM line + BYTE | size | RAM size in kb + BYTE | bank | selected ram bank + ARRAY | RAM | BYTES of RAM data */ -static char snap_module_name[] = "CARTDQBB"; +static const char snap_module_name[] = "CARTDQBB"; #define SNAP_MAJOR 0 -#define SNAP_MINOR 0 +#define SNAP_MINOR 1 int dqbb_snapshot_write_module(snapshot_t *s) { @@ -508,12 +687,16 @@ int dqbb_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)dqbb_enabled) < 0) - || (SMW_B(m, (BYTE)dqbb_readwrite) < 0) - || (SMW_B(m, (BYTE)dqbb_a000_mapped) < 0) - || (SMW_B(m, (BYTE)dqbb_off) < 0) - || (SMW_B(m, (BYTE)reg_value) < 0) - || (SMW_BA(m, dqbb_ram, DQBB_RAM_SIZE) < 0)) { + || (SMW_B(m, (uint8_t)dqbb_enabled) < 0) + || (SMW_B(m, (uint8_t)dqbb_readwrite) < 0) + || (SMW_B(m, (uint8_t)dqbb_game) < 0) + || (SMW_B(m, (uint8_t)dqbb_off) < 0) + || (SMW_B(m, (uint8_t)reg_value) < 0) + || (SMW_B(m, (uint8_t)dqbb_exrom) < 0) + || (SMW_B(m, (uint8_t)dqbb_size) < 0) + || (SMW_B(m, (uint8_t)dqbb_bank) < 0) + || (SMW_B(m, (uint8_t)dqbb_mode_switch) < 0) + || (SMW_BA(m, dqbb_ram, dqbb_size * 0x400) < 0)) { snapshot_module_close(m); return -1; } @@ -523,7 +706,7 @@ int dqbb_snapshot_write_module(snapshot_t *s) int dqbb_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -533,7 +716,7 @@ int dqbb_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; @@ -544,10 +727,14 @@ int dqbb_snapshot_read_module(snapshot_t *s) if (0 || (SMR_B_INT(m, &dqbb_enabled) < 0) || (SMR_B_INT(m, &dqbb_readwrite) < 0) - || (SMR_B_INT(m, &dqbb_a000_mapped) < 0) + || (SMR_B_INT(m, &dqbb_game) < 0) || (SMR_B_INT(m, &dqbb_off) < 0) || (SMR_B_INT(m, ®_value) < 0) - || (SMR_BA(m, dqbb_ram, DQBB_RAM_SIZE) < 0)) { + || (SMR_B_INT(m, &dqbb_exrom) < 0) + || (SMR_B_INT(m, &dqbb_size) < 0) + || (SMR_B_INT(m, &dqbb_bank) < 0) + || (SMR_B_INT(m, &dqbb_mode_switch) < 0) + || (SMR_BA(m, dqbb_ram, dqbb_size * 0x400) < 0)) { snapshot_module_close(m); lib_free(dqbb_ram); dqbb_ram = NULL; diff --git a/src/Emulators/vice/c64/cart/dqbb.h b/src/Emulators/vice/c64/cart/dqbb.h index 71b68d75..c6677689 100644 --- a/src/Emulators/vice/c64/cart/dqbb.h +++ b/src/Emulators/vice/c64/cart/dqbb.h @@ -35,31 +35,42 @@ #include "vicetypes.h" -extern int dqbb_cart_enabled(void); +#define DQBB_MODE_C64 1 +#define DQBB_MODE_C128 0 -extern int dqbb_resources_init(void); -extern void dqbb_resources_shutdown(void); -extern int dqbb_cmdline_options_init(void); -extern void dqbb_reset(void); -extern void dqbb_detach(void); -extern void dqbb_init_config(void); -extern int dqbb_enable(void); -extern void dqbb_config_setup(BYTE *rawcart); +int dqbb_cart_enabled(void); -extern BYTE dqbb_roml_read(WORD addr); -extern void dqbb_roml_store(WORD addr, BYTE byte); -extern BYTE dqbb_romh_read(WORD addr); -extern void dqbb_romh_store(WORD addr, BYTE byte); -extern int dqbb_peek_mem(WORD addr, BYTE *value); -extern void dqbb_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +int dqbb_resources_init(void); +void dqbb_resources_shutdown(void); +int dqbb_cmdline_options_init(void); -extern const char *dqbb_get_file_name(void); -extern int dqbb_bin_attach(const char *filename, BYTE *rawcart); -extern int dqbb_bin_save(const char *filename); -extern int dqbb_flush_image(void); +void dqbb_reset(void); +void dqbb_detach(void); +void dqbb_init_config(void); +int dqbb_enable(void); +int dqbb_disable(void); +void dqbb_config_setup(uint8_t *rawcart); + +uint8_t dqbb_roml_read(uint16_t addr); +void dqbb_roml_store(uint16_t addr, uint8_t byte); +uint8_t dqbb_romh_read(uint16_t addr); +void dqbb_romh_store(uint16_t addr, uint8_t byte); +int dqbb_peek_mem(uint16_t addr, uint8_t *value); +void dqbb_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +int dqbb_c128_read(uint16_t addr, uint8_t *value); +int dqbb_c128_store(uint16_t addr, uint8_t value); + +const char *dqbb_get_file_name(void); +int dqbb_bin_attach(const char *filename, uint8_t *rawcart); +int dqbb_bin_save(const char *filename); +int dqbb_flush_image(void); +void dqbb_powerup(void); +void dqbb_shutdown(void); struct snapshot_s; -extern int dqbb_snapshot_read_module(struct snapshot_s *s); -extern int dqbb_snapshot_write_module(struct snapshot_s *s); + +int dqbb_snapshot_read_module(struct snapshot_s *s); +int dqbb_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/drean.c b/src/Emulators/vice/c64/cart/drean.c new file mode 100644 index 00000000..2975cf51 --- /dev/null +++ b/src/Emulators/vice/c64/cart/drean.c @@ -0,0 +1,254 @@ +/* + * drean.c - Cartridge handling, Drean cart. (H.E.R.O., Le Mans...) + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define DREAN_DEBUG */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "drean.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +#ifdef DREAN_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + Argentinian (Drean) "H.E.R.O." Cartridge + + - ROM is always mapped in at $8000-$9FFF (8k game). + + - 1 register at io2 / dfff: + + bit 0-1 bank number + bit 5 exrom (1 = cart disabled) + + note: most of the above was guessed from the only existing ROM dump. maybe + more ROMs that used the same hardware show up, also the code is prepared + to easily add cartridges of the same type that use more banks. +*/ + +#define MAXBANKS 4 + +static uint8_t regval = 0; +static uint8_t bankmask = 0x03; + +static void drean_io2_store(uint16_t addr, uint8_t value) +{ + regval = value & (0x20 | bankmask); + cart_romlbank_set_slotmain(value & bankmask); + cart_set_port_game_slotmain(0); + if (value & 0x20) { + /* turn off cart ROM */ + cart_set_port_exrom_slotmain(0); + } else { + cart_set_port_exrom_slotmain(1); + } + cart_port_config_changed_slotmain(); + DBG(("DREAN: Addr: %04x Value: %02x Reg: %02x (Bank: %d of %d, %s)\n", addr, value, + regval, (regval & bankmask), bankmask + 1, (regval & 0x20) ? "disabled" : "enabled")); +} + +static uint8_t drean_io2_peek(uint16_t addr) +{ + return regval; +} + +static int drean_dump(void) +{ + mon_out("Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled"); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t drean_device = { + CARTRIDGE_NAME_DREAN, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid, reg is write only */ + drean_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* read function */ + drean_io2_peek, /* peek function */ + drean_dump, /* device state information dump function */ + CARTRIDGE_DREAN, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *drean_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_DREAN, 0, 1, NULL, &drean_device, CARTRIDGE_DREAN +}; + +/* ---------------------------------------------------------------------*/ + +void drean_config_init(void) +{ + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + drean_io2_store((uint16_t)0xdfff, 0); +} + +void drean_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000 * MAXBANKS); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int drean_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + drean_list_item = io_source_register(&drean_device); + return 0; +} + +int drean_bin_attach(const char *filename, uint8_t *rawcart) +{ + bankmask = 0x03; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return drean_common_attach(); +} + +int drean_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int lastbank = 0; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + if (chip.bank > lastbank) { + lastbank = chip.bank; + } + } + if (lastbank >= 4) { + /* more than 4 banks does not work */ + return -1; + } else { + /* max 4 banks */ + bankmask = 0x03; + } + return drean_common_attach(); +} + +void drean_detach(void) +{ + export_remove(&export_res); + io_source_unregister(drean_list_item); + drean_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 1 +#define SNAP_MODULE_NAME "CARTDREAN" + +int drean_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int drean_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (0 + || (SMR_B(m, ®val) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (drean_common_attach() == -1) { + return -1; + } + drean_io2_store(0xdfff, regval); + return 0; +} diff --git a/src/Emulators/vice/c64/cart/drean.h b/src/Emulators/vice/c64/cart/drean.h new file mode 100644 index 00000000..e12c9961 --- /dev/null +++ b/src/Emulators/vice/c64/cart/drean.h @@ -0,0 +1,45 @@ +/* + * drean.h - Cartridge handling, Drean cart. (H.E.R.O., Le Mans...) + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_DREAN_H +#define VICE_DREAN_H + +#include + +#include "vicetypes.h" + +void drean_config_init(void); +void drean_config_setup(uint8_t *rawcart); +int drean_bin_attach(const char *filename, uint8_t *rawcart); +int drean_crt_attach(FILE *fd, uint8_t *rawcart); +void drean_detach(void); + +struct snapshot_s; + +int drean_snapshot_write_module(struct snapshot_s *s); +int drean_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/ds12c887rtc.c b/src/Emulators/vice/c64/cart/ds12c887rtc.c index 62515ea7..8559eb4b 100644 --- a/src/Emulators/vice/c64/cart/ds12c887rtc.c +++ b/src/Emulators/vice/c64/cart/ds12c887rtc.c @@ -44,7 +44,6 @@ #include "sid.h" #include "snapshot.h" #include "uiapi.h" -#include "translate.h" #define RTC_RUNMODE_HALTED 0 #define RTC_RUNMODE_RUNNING 1 @@ -78,23 +77,25 @@ static int ds12c887rtc_accessed = 0; /* ---------------------------------------------------------------------*/ /* Some prototypes are needed */ -static BYTE ds12c887rtc_read(WORD addr); -static void ds12c887rtc_store(WORD addr, BYTE byte); +static uint8_t ds12c887rtc_read(uint16_t addr); +static void ds12c887rtc_store(uint16_t addr, uint8_t byte); static int ds12c887rtc_dump(void); static io_source_t ds12c887rtc_device = { - CARTRIDGE_NAME_DS12C887RTC, - IO_DETACH_RESOURCE, - "DS12C887RTC", - 0xde00, 0xde01, 0xff, - 0, - ds12c887rtc_store, - ds12c887rtc_read, - ds12c887rtc_read, - ds12c887rtc_dump, - CARTRIDGE_DS12C887RTC, - 0, - 0 + CARTRIDGE_NAME_DS12C887RTC, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "DS12C887RTC", /* resource to set to '0' */ + 0xde00, 0xde01, 0xff, /* range for the device, regs: $de00-$de01, range is different for vic20 */ + 0, /* read validity is determined by the device upon a read */ + ds12c887rtc_store, /* store function */ + NULL, /* NO poke function */ + ds12c887rtc_read, /* read function */ + ds12c887rtc_read, /* peek function */ + ds12c887rtc_dump, /* device state information dump function */ + CARTRIDGE_DS12C887RTC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ds12c887rtc_list_item = NULL; @@ -170,14 +171,6 @@ static int set_ds12c887rtc_base(int val, void *param) return 0; } - if (addr == 0xffff) { - if (machine_class == VICE_MACHINE_VIC20) { - addr = 0x9800; - } else { - addr = 0xde00; - } - } - if (old) { set_ds12c887rtc_enabled(0, NULL); } @@ -185,8 +178,8 @@ static int set_ds12c887rtc_base(int val, void *param) switch (addr) { case 0xde00: if (machine_class != VICE_MACHINE_VIC20) { - ds12c887rtc_device.start_address = (WORD)addr; - ds12c887rtc_device.end_address = (WORD)(addr + 1); + ds12c887rtc_device.start_address = (uint16_t)addr; + ds12c887rtc_device.end_address = (uint16_t)(addr + 1); export_res.io1 = &ds12c887rtc_device; export_res.io2 = NULL; } else { @@ -195,8 +188,8 @@ static int set_ds12c887rtc_base(int val, void *param) break; case 0xdf00: if (machine_class != VICE_MACHINE_VIC20) { - ds12c887rtc_device.start_address = (WORD)addr; - ds12c887rtc_device.end_address = (WORD)(addr + 1); + ds12c887rtc_device.start_address = (uint16_t)addr; + ds12c887rtc_device.end_address = (uint16_t)(addr + 1); export_res.io1 = NULL; export_res.io2 = &ds12c887rtc_device; } else { @@ -211,8 +204,8 @@ static int set_ds12c887rtc_base(int val, void *param) #endif case 0xd700: if (machine_class != VICE_MACHINE_VIC20) { - ds12c887rtc_device.start_address = (WORD)addr; - ds12c887rtc_device.end_address = (WORD)(addr + 1); + ds12c887rtc_device.start_address = (uint16_t)addr; + ds12c887rtc_device.end_address = (uint16_t)(addr + 1); export_res.io1 = NULL; export_res.io2 = NULL; } else { @@ -222,8 +215,8 @@ static int set_ds12c887rtc_base(int val, void *param) case 0xd500: case 0xd600: if (machine_class != VICE_MACHINE_VIC20 && machine_class != VICE_MACHINE_C128) { - ds12c887rtc_device.start_address = (WORD)addr; - ds12c887rtc_device.end_address = (WORD)(addr + 1); + ds12c887rtc_device.start_address = (uint16_t)addr; + ds12c887rtc_device.end_address = (uint16_t)(addr + 1); export_res.io1 = NULL; export_res.io2 = NULL; } else { @@ -233,8 +226,8 @@ static int set_ds12c887rtc_base(int val, void *param) case 0x9800: case 0x9c00: if (machine_class == VICE_MACHINE_VIC20) { - ds12c887rtc_device.start_address = (WORD)addr; - ds12c887rtc_device.end_address = (WORD)(addr + 1); + ds12c887rtc_device.start_address = (uint16_t)addr; + ds12c887rtc_device.end_address = (uint16_t)(addr + 1); } else { return -1; } @@ -274,6 +267,11 @@ int ds12c887rtc_enable(void) return resources_set_int("DS12C887RTC", 1); } +int ds12c887rtc_disable(void) +{ + return resources_set_int("DS12C887RTC", 0); +} + void ds12c887rtc_detach(void) { resources_set_int("DS12C887RTC", 0); @@ -286,7 +284,7 @@ static int ds12c887rtc_dump(void) return ds12c887_dump(ds12c887rtc_context); } -static BYTE ds12c887rtc_read(WORD addr) +static uint8_t ds12c887rtc_read(uint16_t addr) { if (addr & 1) { ds12c887rtc_accessed = 1; @@ -299,7 +297,7 @@ static BYTE ds12c887rtc_read(WORD addr) return 0; } -static void ds12c887rtc_store(WORD addr, BYTE byte) +static void ds12c887rtc_store(uint16_t addr, uint8_t byte) { if (addr & 1) { ds12c887_store_data(ds12c887rtc_context, byte); @@ -311,9 +309,10 @@ static void ds12c887rtc_store(WORD addr, BYTE byte) /* ---------------------------------------------------------------------*/ -static const resource_int_t resources_int[] = { +static resource_int_t resources_int[] = { { "DS12C887RTC", 0, RES_EVENT_STRICT, (resource_value_t)0, &ds12c887rtc_enabled, set_ds12c887rtc_enabled, NULL }, + /* 0xfff gets updated based on emu in resources_init() */ { "DS12C887RTCbase", 0xffff, RES_EVENT_NO, NULL, &ds12c887rtc_base_address, set_ds12c887rtc_base, NULL }, { "DS12C887RTCRunMode", RTC_RUNMODE_RUNNING, RES_EVENT_NO, NULL, @@ -325,6 +324,12 @@ static const resource_int_t resources_int[] = { int ds12c887rtc_resources_init(void) { + /* set proper default I/O-base */ + if (machine_class == VICE_MACHINE_VIC20) { + resources_int[1].factory_value = 0x9800; + } else { + resources_int[1].factory_value = 0xde00; + } return resources_register_int(resources_int); } @@ -340,46 +345,32 @@ void ds12c887rtc_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-ds12c887rtc", SET_RESOURCE, 0, + { "-ds12c887rtc", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTC", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DS12C887RTC, - NULL, NULL }, - { "+ds12c887rtc", SET_RESOURCE, 0, + NULL, "Enable the DS12C887 RTC cartridge" }, + { "+ds12c887rtc", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTC", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DS12C887RTC, - NULL, NULL }, - { "-ds12c887rtchalted", SET_RESOURCE, 0, + NULL, "Disable the DS12C887 RTC cartridge" }, + { "-ds12c887rtchalted", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTCRunMode", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DS12C887RTC_RUNMODE_HALTED, - NULL, NULL }, - { "-ds12c887rtcrunning", SET_RESOURCE, 0, + NULL, "Set the RTC oscillator to 'halted'" }, + { "-ds12c887rtcrunning", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTCRunMode", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DS12C887RTC_RUNMODE_RUNNING, - NULL, NULL }, - { "-ds12c887rtcsave", SET_RESOURCE, 0, + NULL, "Set the RTC oscillator to 'running'" }, + { "-ds12c887rtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTCSave", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DS12C887RTC_SAVE, - NULL, NULL }, - { "+ds12c887rtcsave", SET_RESOURCE, 0, + NULL, "Enable saving of the DS12C887 RTC data when changed." }, + { "+ds12c887rtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DS12C887RTCSave", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DS12C887RTC_SAVE, - NULL, NULL }, + NULL, "Disable saving of the DS12C887 RTC data when changed." }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-ds12c887rtcbase", SET_RESOURCE, 1, + { "-ds12c887rtcbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DS12C887RTCbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_DS12C887RTC_BASE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -390,11 +381,11 @@ int ds12c887rtc_cmdline_options_init(void) } if (machine_class == VICE_MACHINE_VIC20) { - base_cmdline_options[0].description = ". (0x9800/0x9C00)"; + base_cmdline_options[0].description = "Base address of the DS12C887 RTC cartridge. (0x9800/0x9C00)"; } else if (machine_class == VICE_MACHINE_C128) { - base_cmdline_options[0].description = ". (0xD700/0xDE00/0xDF00)"; + base_cmdline_options[0].description = "Base address of the DS12C887 RTC cartridge. (0xD700/0xDE00/0xDF00)"; } else { - base_cmdline_options[0].description = ". (0xD500/0xD600/0xD700/0xDE00/0xDF00)"; + base_cmdline_options[0].description = "Base address of the DS12C887 RTC cartridge. (0xD500/0xD600/0xD700/0xDE00/0xDF00)"; } return cmdline_register_options(base_cmdline_options); @@ -409,7 +400,7 @@ int ds12c887rtc_cmdline_options_init(void) DWORD | base | base address of the RTC */ -static char snap_module_name[] = "CARTDS12C887RTC"; +static const char snap_module_name[] = "CARTDS12C887RTC"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -423,7 +414,7 @@ int ds12c887rtc_snapshot_write_module(snapshot_t *s) return -1; } - if (SMW_DW(m, (DWORD)ds12c887rtc_base_address) < 0) { + if (SMW_DW(m, (uint32_t)ds12c887rtc_base_address) < 0) { snapshot_module_close(m); return -1; } @@ -435,7 +426,7 @@ int ds12c887rtc_snapshot_write_module(snapshot_t *s) int ds12c887rtc_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int temp_ds12c887rtc_address; @@ -446,7 +437,7 @@ int ds12c887rtc_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/ds12c887rtc.h b/src/Emulators/vice/c64/cart/ds12c887rtc.h index 9162136b..2a050387 100644 --- a/src/Emulators/vice/c64/cart/ds12c887rtc.h +++ b/src/Emulators/vice/c64/cart/ds12c887rtc.h @@ -30,21 +30,22 @@ #include "vicetypes.h" #include "sound.h" -extern int ds12c887rtc_cart_enabled(void); +int ds12c887rtc_cart_enabled(void); -extern void ds12c887rtc_reset(void); +void ds12c887rtc_reset(void); -extern int ds12c887rtc_enable(void); -extern void ds12c887rtc_detach(void); +int ds12c887rtc_enable(void); +int ds12c887rtc_disable(void); +void ds12c887rtc_detach(void); -extern int ds12c887rtc_resources_init(void); -extern void ds12c887rtc_resources_shutdown(void); +int ds12c887rtc_resources_init(void); +void ds12c887rtc_resources_shutdown(void); -extern int ds12c887rtc_cmdline_options_init(void); +int ds12c887rtc_cmdline_options_init(void); struct snapshot_s; -extern int ds12c887rtc_snapshot_write_module(struct snapshot_s *s); -extern int ds12c887rtc_snapshot_read_module(struct snapshot_s *s); +int ds12c887rtc_snapshot_write_module(struct snapshot_s *s); +int ds12c887rtc_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/easycalc.c b/src/Emulators/vice/c64/cart/easycalc.c index f738cf42..078e1b33 100644 --- a/src/Emulators/vice/c64/cart/easycalc.c +++ b/src/Emulators/vice/c64/cart/easycalc.c @@ -56,22 +56,24 @@ */ /* some prototypes are needed */ -static void easycalc_io1_store(WORD addr, BYTE val); +static void easycalc_io1_store(uint16_t addr, uint8_t val); static int easycalc_dump(void); static io_source_t easycalc_device = { - CARTRIDGE_NAME_EASYCALC, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - easycalc_io1_store, - NULL, /* no read */ - NULL, /* no peek */ - easycalc_dump, - CARTRIDGE_EASYCALC, - 0, - 0 + CARTRIDGE_NAME_EASYCALC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$de01, mirrors:$de02-$deff */ + 0, /* read is never valid, device is write only */ + easycalc_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + easycalc_dump, /* device state information dump function */ + CARTRIDGE_EASYCALC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *easycalc_list_item = NULL; @@ -84,14 +86,14 @@ static const export_resource_t export_res_easycalc = { void easycalc_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } -void easycalc_config_setup(BYTE *rawcart) +void easycalc_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x4000); - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } static int easycalc_common_attach(void) @@ -104,7 +106,7 @@ static int easycalc_common_attach(void) return 0; } -int easycalc_bin_attach(const char *filename, BYTE *rawcart) +int easycalc_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x6000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -112,7 +114,7 @@ int easycalc_bin_attach(const char *filename, BYTE *rawcart) return easycalc_common_attach(); } -int easycalc_crt_attach(FILE *fd, BYTE *rawcart) +int easycalc_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -159,7 +161,7 @@ void easycalc_detach(void) static int curbank = 0; -static void easycalc_io1_store(WORD addr, BYTE val) +static void easycalc_io1_store(uint16_t addr, uint8_t val) { curbank = (addr & 1) ? 1 : 0; @@ -182,7 +184,7 @@ static int easycalc_dump(void) ARRAY | ROMH | 16384 BYTES of ROMH data */ -static char snap_module_name[] = "CARTEASYCALC"; +static const char snap_module_name[] = "CARTEASYCALC"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -208,7 +210,7 @@ int easycalc_snapshot_write_module(snapshot_t *s) int easycalc_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -218,7 +220,7 @@ int easycalc_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/easycalc.h b/src/Emulators/vice/c64/cart/easycalc.h index d741ceda..6fcbf79d 100644 --- a/src/Emulators/vice/c64/cart/easycalc.h +++ b/src/Emulators/vice/c64/cart/easycalc.h @@ -34,13 +34,13 @@ struct snapshot_s; -extern void easycalc_config_init(void); -extern void easycalc_config_setup(BYTE *rawcart); -extern int easycalc_bin_attach(const char *filename, BYTE *rawcart); -extern int easycalc_crt_attach(FILE *fd, BYTE *rawcart); -extern void easycalc_detach(void); +void easycalc_config_init(void); +void easycalc_config_setup(uint8_t *rawcart); +int easycalc_bin_attach(const char *filename, uint8_t *rawcart); +int easycalc_crt_attach(FILE *fd, uint8_t *rawcart); +void easycalc_detach(void); -extern int easycalc_snapshot_write_module(struct snapshot_s *s); -extern int easycalc_snapshot_read_module(struct snapshot_s *s); +int easycalc_snapshot_write_module(struct snapshot_s *s); +int easycalc_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/easyflash.c b/src/Emulators/vice/c64/cart/easyflash.c index 57970711..de4997b5 100644 --- a/src/Emulators/vice/c64/cart/easyflash.c +++ b/src/Emulators/vice/c64/cart/easyflash.c @@ -47,9 +47,9 @@ #include "maincpu.h" #include "mem.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "util.h" #define EASYFLASH_N_BANK_BITS 6 @@ -70,10 +70,10 @@ static int easyflash_crt_write; static int easyflash_crt_optimize; /* backup of the registers */ -static BYTE easyflash_register_00, easyflash_register_02; +static uint8_t easyflash_register_00, easyflash_register_02; /* decoding table of the modes */ -static const BYTE easyflash_memconfig[] = { +static const uint8_t easyflash_memconfig[] = { /* bit3 = jumper, bit2 = mode, bit1 = !exrom, bit0 = game */ /* jumper off, mode 0, trough 00,01,10,11 in game/exrom bits */ @@ -95,8 +95,10 @@ static const BYTE easyflash_memconfig[] = { 2, 3, 0, 1, }; +#define CART_RAM_SIZE 256 + /* extra RAM */ -static BYTE easyflash_ram[256]; +static uint8_t easyflash_ram[CART_RAM_SIZE]; /* filename when attached */ static char *easyflash_filename = NULL; @@ -104,16 +106,116 @@ static int easyflash_filetype = 0; static const char STRING_EASYFLASH[] = CARTRIDGE_NAME_EASYFLASH; +static const unsigned char eapiam29f040[768] = { + 0x65, 0x61, 0x70, 0x69, 0xc1, 0x4d, + 0x2f, 0xcd, 0x32, 0x39, 0xc6, 0x30, 0x34, 0x30, + 0x20, 0xd6, 0x31, 0x2e, 0x34, 0x00, 0x08, 0x78, + 0xa5, 0x4b, 0x48, 0xa5, 0x4c, 0x48, 0xa9, 0x60, + 0x85, 0x4b, 0x20, 0x4b, 0x00, 0xba, 0xbd, 0x00, + 0x01, 0x85, 0x4c, 0xca, 0xbd, 0x00, 0x01, 0x85, + 0x4b, 0x18, 0x90, 0x70, 0x4c, 0x67, 0x01, 0x4c, + 0xa4, 0x01, 0x4c, 0x39, 0x02, 0x4c, 0x40, 0x02, + 0x4c, 0x44, 0x02, 0x4c, 0x4e, 0x02, 0x4c, 0x58, + 0x02, 0x4c, 0x8e, 0x02, 0x4c, 0xd9, 0x02, 0x4c, + 0xd9, 0x02, 0x8d, 0x02, 0xde, 0xa9, 0xaa, 0x8d, + 0x55, 0x85, 0xa9, 0x55, 0x8d, 0xaa, 0x82, 0xa9, + 0xa0, 0x8d, 0x55, 0x85, 0xad, 0xf2, 0xdf, 0x8d, + 0x00, 0xde, 0xa9, 0x00, 0x8d, 0xff, 0xff, 0xa2, + 0x07, 0x8e, 0x02, 0xde, 0x60, 0x8d, 0x02, 0xde, + 0xa9, 0xaa, 0x8d, 0x55, 0xe5, 0xa9, 0x55, 0x8d, + 0xaa, 0xe2, 0xa9, 0xa0, 0x8d, 0x55, 0xe5, 0xd0, + 0xdb, 0xa2, 0x55, 0x8e, 0xe3, 0xdf, 0x8c, 0xe4, + 0xdf, 0xa2, 0x85, 0x8e, 0x02, 0xde, 0x8d, 0xff, + 0xff, 0x4c, 0xbb, 0xdf, 0xad, 0xff, 0xff, 0x60, + 0xcd, 0xff, 0xff, 0x60, 0xa2, 0x6f, 0xa0, 0x7f, + 0xb1, 0x4b, 0x9d, 0x80, 0xdf, 0xdd, 0x80, 0xdf, + 0xd0, 0x21, 0x88, 0xca, 0x10, 0xf2, 0xa2, 0x00, + 0xe8, 0x18, 0xbd, 0x80, 0xdf, 0x65, 0x4b, 0x9d, + 0x80, 0xdf, 0xe8, 0xbd, 0x80, 0xdf, 0x65, 0x4c, + 0x9d, 0x80, 0xdf, 0xe8, 0xe0, 0x1e, 0xd0, 0xe8, + 0x18, 0x90, 0x06, 0xa9, 0x01, 0x8d, 0xb9, 0xdf, + 0x38, 0x68, 0x85, 0x4c, 0x68, 0x85, 0x4b, 0xb0, + 0x48, 0xa9, 0xaa, 0xa0, 0xe5, 0x20, 0xd5, 0xdf, + 0xa0, 0x85, 0x20, 0xd5, 0xdf, 0xa9, 0x55, 0xa2, + 0xaa, 0xa0, 0xe2, 0x20, 0xd7, 0xdf, 0xa2, 0xaa, + 0xa0, 0x82, 0x20, 0xd7, 0xdf, 0xa9, 0x90, 0xa0, + 0xe5, 0x20, 0xd5, 0xdf, 0xa0, 0x85, 0x20, 0xd5, + 0xdf, 0xad, 0x00, 0xa0, 0x8d, 0xf1, 0xdf, 0xae, + 0x01, 0xa0, 0x8e, 0xb9, 0xdf, 0xc9, 0x01, 0xd0, + 0x06, 0xe0, 0xa4, 0xd0, 0x02, 0xf0, 0x0c, 0xc9, + 0x20, 0xd0, 0x39, 0xe0, 0xe2, 0xd0, 0x35, 0xf0, + 0x02, 0xb0, 0x50, 0xad, 0x00, 0x80, 0xae, 0x01, + 0x80, 0xc9, 0x01, 0xd0, 0x06, 0xe0, 0xa4, 0xd0, + 0x02, 0xf0, 0x08, 0xc9, 0x20, 0xd0, 0x19, 0xe0, + 0xe2, 0xd0, 0x15, 0xa0, 0x3f, 0x8c, 0x00, 0xde, + 0xae, 0x02, 0x80, 0xd0, 0x13, 0xae, 0x02, 0xa0, + 0xd0, 0x12, 0x88, 0x10, 0xf0, 0x18, 0x90, 0x12, + 0xa9, 0x02, 0xd0, 0x0a, 0xa9, 0x03, 0xd0, 0x06, + 0xa9, 0x04, 0xd0, 0x02, 0xa9, 0x05, 0x8d, 0xb9, + 0xdf, 0x38, 0xa9, 0x00, 0x8d, 0x00, 0xde, 0xa0, + 0xe0, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0xa0, 0x80, + 0x20, 0xd7, 0xdf, 0xad, 0xb9, 0xdf, 0xb0, 0x08, + 0xae, 0xf1, 0xdf, 0xa0, 0x40, 0x28, 0x18, 0x60, + 0x28, 0x38, 0x60, 0x8d, 0xb7, 0xdf, 0x8e, 0xb9, + 0xdf, 0x8e, 0xed, 0xdf, 0x8c, 0xba, 0xdf, 0x08, + 0x78, 0x98, 0x29, 0xbf, 0x8d, 0xee, 0xdf, 0xa9, + 0x00, 0x8d, 0x00, 0xde, 0xa9, 0x85, 0xc0, 0xe0, + 0x90, 0x05, 0x20, 0xc1, 0xdf, 0xb0, 0x03, 0x20, + 0x9e, 0xdf, 0xa2, 0x14, 0x20, 0xec, 0xdf, 0xf0, + 0x06, 0xca, 0xd0, 0xf8, 0x18, 0x90, 0x63, 0xad, + 0xf2, 0xdf, 0x8d, 0x00, 0xde, 0x18, 0x90, 0x72, + 0x8d, 0xb7, 0xdf, 0x8e, 0xb9, 0xdf, 0x8c, 0xba, + 0xdf, 0x08, 0x78, 0x98, 0xc0, 0x80, 0xf0, 0x04, + 0xa0, 0xe0, 0xa9, 0xa0, 0x8d, 0xee, 0xdf, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xa9, 0xaa, 0x20, 0xd5, + 0xdf, 0xa9, 0x55, 0xa2, 0xaa, 0x88, 0x88, 0x88, + 0x20, 0xd7, 0xdf, 0xa9, 0x80, 0xc8, 0xc8, 0xc8, + 0x20, 0xd5, 0xdf, 0xa9, 0xaa, 0x20, 0xd5, 0xdf, + 0xa9, 0x55, 0xa2, 0xaa, 0x88, 0x88, 0x88, 0x20, + 0xd7, 0xdf, 0xad, 0xb7, 0xdf, 0x8d, 0x00, 0xde, + 0xa2, 0x00, 0x8e, 0xed, 0xdf, 0x88, 0x88, 0xa9, + 0x30, 0x20, 0xd7, 0xdf, 0xa9, 0xff, 0xaa, 0xa8, + 0xd0, 0x24, 0xad, 0xf2, 0xdf, 0x8d, 0x00, 0xde, + 0xa0, 0x80, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0xa0, + 0xe0, 0xa9, 0xf0, 0x20, 0xd7, 0xdf, 0x28, 0x38, + 0xb0, 0x02, 0x28, 0x18, 0xac, 0xba, 0xdf, 0xae, + 0xb9, 0xdf, 0xad, 0xb7, 0xdf, 0x60, 0x20, 0xec, + 0xdf, 0xf0, 0x09, 0xca, 0xd0, 0xf8, 0x88, 0xd0, + 0xf5, 0x18, 0x90, 0xce, 0xad, 0xf2, 0xdf, 0x8d, + 0x00, 0xde, 0x18, 0x90, 0xdd, 0x8d, 0xf2, 0xdf, + 0x8d, 0x00, 0xde, 0x60, 0xad, 0xf2, 0xdf, 0x60, + 0x8d, 0xf3, 0xdf, 0x8e, 0xe9, 0xdf, 0x8c, 0xea, + 0xdf, 0x60, 0x8e, 0xf4, 0xdf, 0x8c, 0xf5, 0xdf, + 0x8d, 0xf6, 0xdf, 0x60, 0xad, 0xf2, 0xdf, 0x8d, + 0x00, 0xde, 0x20, 0xe8, 0xdf, 0x8d, 0xb7, 0xdf, + 0x8e, 0xf0, 0xdf, 0x8c, 0xf1, 0xdf, 0xa9, 0x00, + 0x8d, 0xba, 0xdf, 0xf0, 0x3b, 0xad, 0xf4, 0xdf, + 0xd0, 0x10, 0xad, 0xf5, 0xdf, 0xd0, 0x08, 0xad, + 0xf6, 0xdf, 0xf0, 0x0b, 0xce, 0xf6, 0xdf, 0xce, + 0xf5, 0xdf, 0xce, 0xf4, 0xdf, 0x90, 0x45, 0x38, + 0xb0, 0x42, 0x8d, 0xb7, 0xdf, 0x8e, 0xf0, 0xdf, + 0x8c, 0xf1, 0xdf, 0xae, 0xe9, 0xdf, 0xad, 0xea, + 0xdf, 0xc9, 0xa0, 0x90, 0x02, 0x09, 0x40, 0xa8, + 0xad, 0xb7, 0xdf, 0x20, 0x80, 0xdf, 0xb0, 0x24, + 0xee, 0xe9, 0xdf, 0xd0, 0x19, 0xee, 0xea, 0xdf, + 0xad, 0xf3, 0xdf, 0x29, 0xe0, 0xcd, 0xea, 0xdf, + 0xd0, 0x0c, 0xad, 0xf3, 0xdf, 0x0a, 0x0a, 0x0a, + 0x8d, 0xea, 0xdf, 0xee, 0xf2, 0xdf, 0x18, 0xad, + 0xba, 0xdf, 0xf0, 0xa1, 0xac, 0xf1, 0xdf, 0xae, + 0xf0, 0xdf, 0xad, 0xb7, 0xdf, 0x60, 0xff, 0xff, + 0xff, 0xff +}; + /* ---------------------------------------------------------------------*/ -static void easyflash_io1_store(WORD addr, BYTE value) +static void easyflash_io1_store(uint16_t addr, uint8_t value) { - BYTE mem_mode; + uint8_t mem_mode; switch (addr & 2) { case 0: /* bank register */ - easyflash_register_00 = (BYTE)(value & EASYFLASH_BANK_MASK); + easyflash_register_00 = (uint8_t)(value & EASYFLASH_BANK_MASK); break; default: /* mode register */ @@ -128,62 +230,68 @@ static void easyflash_io1_store(WORD addr, BYTE value) cart_port_config_changed_slotmain(); } -static BYTE easyflash_io2_read(WORD addr) +static uint8_t easyflash_io2_read(uint16_t addr) { return easyflash_ram[addr & 0xff]; } -static void easyflash_io2_store(WORD addr, BYTE value) +static void easyflash_io2_store(uint16_t addr, uint8_t value) { easyflash_ram[addr & 0xff] = value; } /* ---------------------------------------------------------------------*/ -static BYTE easyflash_io1_peek(WORD addr) +static uint8_t easyflash_io1_peek(uint16_t addr) { return (addr & 2) ? easyflash_register_02 : easyflash_register_00; } static int easyflash_io1_dump(void) { - mon_out("Mode %i, LED %s, jumper %s\n", - easyflash_memconfig[(easyflash_jumper << 3) | (easyflash_register_02 & 0x07)], + mon_out("Mode: %s, Bank: %d, LED %s, jumper %s\n", + cart_config_string(easyflash_memconfig[(easyflash_jumper << 3) | (easyflash_register_02 & 0x07)]), + easyflash_register_00, (easyflash_register_02 & 0x80) ? "on" : "off", easyflash_jumper ? "on" : "off"); + mon_out("EAPI found: %s\n", (memcmp(&romh_banks[0x1800], "eapi", 4) == 0) ? "yes" : "no"); return 0; } /* ---------------------------------------------------------------------*/ static io_source_t easyflash_io1_device = { - CARTRIDGE_NAME_EASYFLASH, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0x03, - 0, - easyflash_io1_store, - NULL, - easyflash_io1_peek, - easyflash_io1_dump, - CARTRIDGE_EASYFLASH, - 0, - 0 + CARTRIDGE_NAME_EASYFLASH, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x03, /* range for the device, regs:$de00-$de03, mirrors:$de04-$deff */ + 0, /* read is never valid, regs are write only */ + easyflash_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + easyflash_io1_peek, /* peek function */ + easyflash_io1_dump, /* device state information dump function */ + CARTRIDGE_EASYFLASH, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t easyflash_io2_device = { - CARTRIDGE_NAME_EASYFLASH, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - easyflash_io2_store, - easyflash_io2_read, - easyflash_io2_read, /* same implementation */ - NULL, /* nothing to dump */ - CARTRIDGE_EASYFLASH, - 0, - 0 + CARTRIDGE_NAME_EASYFLASH, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + easyflash_io2_store, /* store function */ + NULL, /* NO poke function */ + easyflash_io2_read, /* read function */ + easyflash_io2_read, /* peek function, same implementation */ + NULL, /* device state information dump function */ + CARTRIDGE_EASYFLASH, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *easyflash_io1_list_item = NULL; @@ -213,7 +321,7 @@ static int set_easyflash_crt_optimize(int val, void *param) return 0; } -static int easyflash_write_chip_if_not_empty(FILE* fd, crt_chip_header_t *chip, BYTE* data) +static int easyflash_write_chip_if_not_empty(FILE* fd, crt_chip_header_t *chip, uint8_t *data) { int i; @@ -253,36 +361,24 @@ void easyflash_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-easyflashjumper", SET_RESOURCE, 0, + { "-easyflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashJumper", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_EASYFLASH_JUMPER, - NULL, NULL }, - { "+easyflashjumper", SET_RESOURCE, 0, + NULL, "Enable EasyFlash jumper" }, + { "+easyflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashJumper", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_EASYFLASH_JUMPER, - NULL, NULL }, - { "-easyflashcrtwrite", SET_RESOURCE, 0, + NULL, "Disable EasyFlash jumper" }, + { "-easyflashcrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashWriteCRT", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_EASYFLASH_CRT_WRITING, - NULL, NULL }, - { "+easyflashcrtwrite", SET_RESOURCE, 0, + NULL, "Enable writing to EasyFlash .crt image" }, + { "+easyflashcrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashWriteCRT", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_EASYFLASH_CRT_WRITING, - NULL, NULL }, - { "-easyflashcrtoptimize", SET_RESOURCE, 0, + NULL, "Disable writing to EasyFlash .crt image" }, + { "-easyflashcrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashOptimizeCRT", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_EASYFLASH_CRT_OPTIMIZE, - NULL, NULL }, - { "+easyflashcrtoptimize", SET_RESOURCE, 0, + NULL, "Enable EasyFlash .crt image optimize on write" }, + { "+easyflashcrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "EasyFlashOptimizeCRT", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_EASYFLASH_CRT_OPTIMIZE, - NULL, NULL }, + NULL, "Disable writing to EasyFlash .crt image" }, CMDLINE_LIST_END }; @@ -293,27 +389,27 @@ int easyflash_cmdline_options_init(void) /* ---------------------------------------------------------------------*/ -BYTE easyflash_roml_read(WORD addr) +uint8_t easyflash_roml_read(uint16_t addr) { return flash040core_read(easyflash_state_low, (easyflash_register_00 * 0x2000) + (addr & 0x1fff)); } -void easyflash_roml_store(WORD addr, BYTE value) +void easyflash_roml_store(uint16_t addr, uint8_t value) { flash040core_store(easyflash_state_low, (easyflash_register_00 * 0x2000) + (addr & 0x1fff), value); } -BYTE easyflash_romh_read(WORD addr) +uint8_t easyflash_romh_read(uint16_t addr) { return flash040core_read(easyflash_state_high, (easyflash_register_00 * 0x2000) + (addr & 0x1fff)); } -void easyflash_romh_store(WORD addr, BYTE value) +void easyflash_romh_store(uint16_t addr, uint8_t value) { flash040core_store(easyflash_state_high, (easyflash_register_00 * 0x2000) + (addr & 0x1fff), value); } -void easyflash_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void easyflash_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { if (easyflash_state_high && easyflash_state_high->flash_data && easyflash_state_low && easyflash_state_low->flash_data) { @@ -353,13 +449,38 @@ void easyflash_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void easyflash_powerup(void) +{ + /* fill easyflash ram with startup value(s). this shall not be zeros, see + * http://sourceforge.net/p/vice-emu/bugs/469/ + * + * FIXME: the real hardware likely behaves somewhat differently + */ + /*memset(easyflash_ram, 0xff, CART_RAM_SIZE);*/ + ram_init_with_pattern(easyflash_ram, CART_RAM_SIZE, &ramparam); +} + void easyflash_config_init(void) { - easyflash_io1_store((WORD)0xde00, 0); - easyflash_io1_store((WORD)0xde02, 0); + easyflash_io1_store((uint16_t)0xde00, 0); + easyflash_io1_store((uint16_t)0xde02, 0); } -void easyflash_config_setup(BYTE *rawcart) +void easyflash_config_setup(uint8_t *rawcart) { int i; @@ -373,22 +494,19 @@ void easyflash_config_setup(BYTE *rawcart) memcpy(easyflash_state_low->flash_data + i * 0x2000, rawcart + i * 0x4000, 0x2000); memcpy(easyflash_state_high->flash_data + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000); } - /* fill easyflash ram with startup value(s). this shall not be zeros, see - * http://sourceforge.net/p/vice-emu/bugs/469/ - * - * FIXME: the real hardware likely behaves somewhat differently - */ - memset(easyflash_ram, 0xff, 256); + /* * check for presence of EAPI */ if (memcmp(&romh_banks[0x1800], "eapi", 4) == 0) { - char eapi[17]; int i; - for (i = 0; i < 16; i++) { - eapi[i] = romh_banks[0x1804 + i] & 0x7f; + char eapi[17]; + int k; + for (k = 0; k < 16; k++) { + eapi[k] = romh_banks[0x1804 + k] & 0x7f; } - eapi[i] = 0; + eapi[k] = 0; log_message(LOG_DEFAULT, "EF: EAPI found (%s)", eapi); + memcpy(romh_banks + 0x1800, eapiam29f040, 768); } else { log_warning(LOG_DEFAULT, "EF: EAPI not found! Are you sure this is a proper EasyFlash image?"); } @@ -405,12 +523,12 @@ static int easyflash_common_attach(const char *filename) easyflash_io1_list_item = io_source_register(&easyflash_io1_device); easyflash_io2_list_item = io_source_register(&easyflash_io2_device); - easyflash_filename = lib_stralloc(filename); + easyflash_filename = lib_strdup(filename); return 0; } -int easyflash_bin_attach(const char *filename, BYTE *rawcart) +int easyflash_bin_attach(const char *filename, uint8_t *rawcart) { easyflash_filetype = 0; @@ -422,7 +540,7 @@ int easyflash_bin_attach(const char *filename, BYTE *rawcart) return easyflash_common_attach(filename); } -int easyflash_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int easyflash_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; @@ -492,8 +610,8 @@ int easyflash_bin_save(const char *filename) { FILE *fd; int i; - BYTE *low; - BYTE *high; + uint8_t *low; + uint8_t *high; if (filename == NULL) { return -1; @@ -523,7 +641,7 @@ int easyflash_crt_save(const char *filename) { FILE *fd; crt_chip_header_t chip; - BYTE *data; + uint8_t *data; int bank; fd = crt_create(filename, CARTRIDGE_EASYFLASH, 1, 0, STRING_EASYFLASH); @@ -570,8 +688,8 @@ int easyflash_crt_save(const char *filename) ARRAY | ROMH | 524288 BYTES of ROMH data */ -static char snap_module_name[] = "CARTEF"; -static char flash_snap_module_name[] = "FLASH040EF"; +static const char snap_module_name[] = "CARTEF"; +static const char flash_snap_module_name[] = "FLASH040EF"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -586,12 +704,12 @@ int easyflash_snapshot_write_module(snapshot_t *s, int save_cart_roms) } if (0 - || (SMW_B(m, (BYTE)easyflash_jumper) < 0) + || (SMW_B(m, (uint8_t)easyflash_jumper) < 0) || (SMW_B(m, easyflash_register_00) < 0) || (SMW_B(m, easyflash_register_02) < 0) - || (SMW_BA(m, easyflash_ram, 256) < 0) - || (save_cart_roms ? SMW_BA(m, roml_banks, 0x80000) : 1 < 0) - || (save_cart_roms ? SMW_BA(m, romh_banks, 0x80000) : 1 < 0)) { + || (SMW_BA(m, easyflash_ram, CART_RAM_SIZE) < 0) + || (save_cart_roms ? SMW_BA(m, roml_banks, 0x80000) : 1 < 0) + || (save_cart_roms ? SMW_BA(m, romh_banks, 0x80000) : 1 < 0)) { snapshot_module_close(m); return -1; } @@ -609,7 +727,7 @@ int easyflash_snapshot_write_module(snapshot_t *s, int save_cart_roms) int easyflash_snapshot_read_module(snapshot_t *s, int read_cart_roms) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -618,7 +736,7 @@ int easyflash_snapshot_read_module(snapshot_t *s, int read_cart_roms) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -627,9 +745,9 @@ int easyflash_snapshot_read_module(snapshot_t *s, int read_cart_roms) || (SMR_B_INT(m, &easyflash_jumper) < 0) || (SMR_B(m, &easyflash_register_00) < 0) || (SMR_B(m, &easyflash_register_02) < 0) - || (SMR_BA(m, easyflash_ram, 256) < 0) - || (read_cart_roms ? SMR_BA(m, roml_banks, 0x80000) : 1 < 0) - || (read_cart_roms ? SMR_BA(m, romh_banks, 0x80000) : 1 < 0)) { + || (SMR_BA(m, easyflash_ram, CART_RAM_SIZE) < 0) + || (read_cart_roms ? SMR_BA(m, roml_banks, 0x80000) : 1 < 0) + || (read_cart_roms ? SMR_BA(m, romh_banks, 0x80000) : 1 < 0)) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/easyflash.h b/src/Emulators/vice/c64/cart/easyflash.h index 7fcd859a..bc23e6b8 100644 --- a/src/Emulators/vice/c64/cart/easyflash.h +++ b/src/Emulators/vice/c64/cart/easyflash.h @@ -30,28 +30,29 @@ #include "vicetypes.h" -extern int easyflash_resources_init(void); -extern void easyflash_resources_shutdown(void); -extern int easyflash_cmdline_options_init(void); - -extern BYTE easyflash_roml_read(WORD addr); -extern void easyflash_roml_store(WORD addr, BYTE value); -extern BYTE easyflash_romh_read(WORD addr); -extern void easyflash_romh_store(WORD addr, BYTE value); -extern void easyflash_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); - -extern void easyflash_config_init(void); -extern void easyflash_config_setup(BYTE *rawcart); -extern int easyflash_bin_attach(const char *filename, BYTE *rawcart); -extern int easyflash_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern void easyflash_detach(void); -extern int easyflash_bin_save(const char *filename); -extern int easyflash_crt_save(const char *filename); -extern int easyflash_flush_image(void); +int easyflash_resources_init(void); +void easyflash_resources_shutdown(void); +int easyflash_cmdline_options_init(void); + +uint8_t easyflash_roml_read(uint16_t addr); +void easyflash_roml_store(uint16_t addr, uint8_t value); +uint8_t easyflash_romh_read(uint16_t addr); +void easyflash_romh_store(uint16_t addr, uint8_t value); +void easyflash_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +void easyflash_config_init(void); +void easyflash_config_setup(uint8_t *rawcart); +int easyflash_bin_attach(const char *filename, uint8_t *rawcart); +int easyflash_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +void easyflash_detach(void); +int easyflash_bin_save(const char *filename); +int easyflash_crt_save(const char *filename); +int easyflash_flush_image(void); +void easyflash_powerup(void); struct snapshot_s; -extern int easyflash_snapshot_write_module(struct snapshot_s *s, int save_cart_roms); -extern int easyflash_snapshot_read_module(struct snapshot_s *s, int read_cart_roms); +int easyflash_snapshot_write_module(struct snapshot_s *s, int save_cart_roms); +int easyflash_snapshot_read_module(struct snapshot_s *s, int read_cart_roms); #endif diff --git a/src/Emulators/vice/c64/cart/epyxfastload.c b/src/Emulators/vice/c64/cart/epyxfastload.c index 1f9d09c3..cb7b2f3f 100644 --- a/src/Emulators/vice/c64/cart/epyxfastload.c +++ b/src/Emulators/vice/c64/cart/epyxfastload.c @@ -94,19 +94,19 @@ static void epyxfastload_alarm_handler(CLOCK offset, void *data) /* ---------------------------------------------------------------------*/ -static BYTE epyxfastload_io1_read(WORD addr) +static uint8_t epyxfastload_io1_read(uint16_t addr) { /* IO1 discharges the capacitor, but does nothing else */ epyxfastload_trigger_access(); return 0; } -static BYTE epyxfastload_io1_peek(WORD addr) +static uint8_t epyxfastload_io1_peek(uint16_t addr) { return 0; } -static BYTE epyxfastload_io2_read(WORD addr) +static uint8_t epyxfastload_io2_read(uint16_t addr) { /* IO2 allows access to the last 256 bytes of the rom */ return roml_banks[0x1f00 + (addr & 0xff)]; @@ -122,33 +122,37 @@ static int epyxfastload_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t epyxfastload_io1_device = { - CARTRIDGE_NAME_EPYX_FASTLOAD, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - NULL, - epyxfastload_io1_read, - epyxfastload_io1_peek, - epyxfastload_dump, - CARTRIDGE_EPYX_FASTLOAD, - 0, - 0 + CARTRIDGE_NAME_EPYX_FASTLOAD, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke funtion */ + epyxfastload_io1_read, /* read function */ + epyxfastload_io1_peek, /* peek function */ + epyxfastload_dump, /* device state information dump function */ + CARTRIDGE_EPYX_FASTLOAD, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t epyxfastload_io2_device = { - CARTRIDGE_NAME_EPYX_FASTLOAD, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - NULL, - epyxfastload_io2_read, - epyxfastload_io2_read, - epyxfastload_dump, - CARTRIDGE_EPYX_FASTLOAD, - 0, - 0 + CARTRIDGE_NAME_EPYX_FASTLOAD, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + epyxfastload_io2_read, /* read function */ + epyxfastload_io2_read, /* peek function */ + epyxfastload_dump, /* device state information dump function */ + CARTRIDGE_EPYX_FASTLOAD, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *epyxfastload_io1_list_item = NULL; @@ -160,7 +164,7 @@ static const export_resource_t export_res_epyx = { /* ---------------------------------------------------------------------*/ -BYTE epyxfastload_roml_read(WORD addr) +uint8_t epyxfastload_roml_read(uint16_t addr) { /* ROML accesses also discharge the capacitor */ epyxfastload_trigger_access(); @@ -182,7 +186,7 @@ void epyxfastload_config_init(void) epyxrom_active = 1; } -void epyxfastload_config_setup(BYTE *rawcart) +void epyxfastload_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); @@ -206,7 +210,7 @@ static int epyxfastload_common_attach(void) return 0; } -int epyxfastload_bin_attach(const char *filename, BYTE *rawcart) +int epyxfastload_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -214,7 +218,7 @@ int epyxfastload_bin_attach(const char *filename, BYTE *rawcart) return epyxfastload_common_attach(); } -int epyxfastload_crt_attach(FILE *fd, BYTE *rawcart) +int epyxfastload_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -254,7 +258,7 @@ void epyxfastload_detach(void) ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTEPYX"; +static const char snap_module_name[] = "CARTEPYX"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -269,8 +273,8 @@ int epyxfastload_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)epyxrom_active) < 0) - || (SMW_DW(m, epyxrom_alarm_time) < 0) + || (SMW_B(m, (uint8_t)epyxrom_active) < 0) + || (SMW_CLOCK(m, epyxrom_alarm_time) < 0) || (SMW_BA(m, roml_banks, 0x2000) < 0)) { snapshot_module_close(m); return -1; @@ -281,7 +285,7 @@ int epyxfastload_snapshot_write_module(snapshot_t *s) int epyxfastload_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; CLOCK temp_clk; @@ -293,13 +297,13 @@ int epyxfastload_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &epyxrom_active) < 0) { goto fail; } @@ -308,7 +312,7 @@ int epyxfastload_snapshot_read_module(snapshot_t *s) } if (0 - || (SMR_DW(m, &temp_clk) < 0) + || (SMR_CLOCK(m, &temp_clk) < 0) || (SMR_BA(m, roml_banks, 0x2000) < 0)) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/epyxfastload.h b/src/Emulators/vice/c64/cart/epyxfastload.h index ceefd661..f54b5cc6 100644 --- a/src/Emulators/vice/c64/cart/epyxfastload.h +++ b/src/Emulators/vice/c64/cart/epyxfastload.h @@ -31,19 +31,19 @@ #include "vicetypes.h" -extern BYTE epyxfastload_roml_read(WORD addr); +uint8_t epyxfastload_roml_read(uint16_t addr); -extern void epyxfastload_reset(void); +void epyxfastload_reset(void); -extern void epyxfastload_config_init(void); -extern void epyxfastload_config_setup(BYTE *rawcart); -extern int epyxfastload_bin_attach(const char *filename, BYTE *rawcart); -extern int epyxfastload_crt_attach(FILE *fd, BYTE *rawcart); -extern void epyxfastload_detach(void); +void epyxfastload_config_init(void); +void epyxfastload_config_setup(uint8_t *rawcart); +int epyxfastload_bin_attach(const char *filename, uint8_t *rawcart); +int epyxfastload_crt_attach(FILE *fd, uint8_t *rawcart); +void epyxfastload_detach(void); struct snapshot_s; -extern int epyxfastload_snapshot_write_module(struct snapshot_s *s); -extern int epyxfastload_snapshot_read_module(struct snapshot_s *s); +int epyxfastload_snapshot_write_module(struct snapshot_s *s); +int epyxfastload_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/ethernetcart.c b/src/Emulators/vice/c64/cart/ethernetcart.c index 4d90f921..289755d8 100644 --- a/src/Emulators/vice/c64/cart/ethernetcart.c +++ b/src/Emulators/vice/c64/cart/ethernetcart.c @@ -26,7 +26,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -46,7 +46,6 @@ #include "rawnet.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "util.h" #define CARTRIDGE_INCLUDE_PRIVATE_API @@ -70,24 +69,26 @@ /* resources support functions */ /* Some prototypes are needed */ -static BYTE ethernetcart_read(WORD io_address); -static BYTE ethernetcart_peek(WORD io_address); -static void ethernetcart_store(WORD io_address, BYTE byte); +static uint8_t ethernetcart_read(uint16_t io_address); +static uint8_t ethernetcart_peek(uint16_t io_address); +static void ethernetcart_store(uint16_t io_address, uint8_t byte); static int ethernetcart_dump(void); static io_source_t ethernetcart_device = { - CARTRIDGE_NAME_ETHERNETCART, - IO_DETACH_RESOURCE, - "ETHERNETCART_ACTIVE", - 0xde00, 0xde0f, 0x0f, - 0, - ethernetcart_store, - ethernetcart_read, - ethernetcart_peek, - ethernetcart_dump, - CARTRIDGE_TFE, - 0, - 0 + CARTRIDGE_NAME_ETHERNETCART, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "ETHERNETCART_ACTIVE", /* resource to set to '0' */ + 0xde00, 0xde0f, 0x0f, /* range for the device, address start can be changed, range will be different for vic20 */ + 0, /* read validity is determined by the device upon a read */ + ethernetcart_store, /* store function */ + NULL, /* NO poke function */ + ethernetcart_read, /* read function */ + ethernetcart_peek, /* peek function */ + ethernetcart_dump, /* device state information dump function */ + CARTRIDGE_TFE, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static export_resource_t export_res = { @@ -143,39 +144,45 @@ void ethernetcart_detach(void) /* ------------------------------------------------------------------------- */ /* ----- read byte from I/O range in VICE ----- */ -static BYTE ethernetcart_read(WORD io_address) +static uint8_t ethernetcart_read(uint16_t io_address) { ethernetcart_device.io_source_valid = 1; if (ethernetcart_mode == ETHERNETCART_MODE_RRNET) { - io_address ^= 8; if (io_address < 2) { return 0; + /* FIXME: is this a mistake with return 0; being too early, or is + * the next line supposed to be commented out/deleted? + */ +#if 0 + ethernetcart_device.io_source_valid = 0; +#endif } + io_address ^= 8; } return cs8900io_read(io_address); } /* ----- peek byte with no sideeffects from I/O range in VICE ----- */ -static BYTE ethernetcart_peek(WORD io_address) +static uint8_t ethernetcart_peek(uint16_t io_address) { if (ethernetcart_mode == ETHERNETCART_MODE_RRNET) { - io_address ^= 8; if (io_address < 2) { return 0; } + io_address ^= 8; } return cs8900io_peek(io_address); } /* ----- write byte to I/O range of VICE ----- */ -static void ethernetcart_store(WORD io_address, BYTE byte) +static void ethernetcart_store(uint16_t io_address, uint8_t byte) { if (ethernetcart_mode == ETHERNETCART_MODE_RRNET) { - io_address ^= 8; if (io_address < 2) { return; } + io_address ^= 8; } cs8900io_store(io_address, byte); } @@ -183,8 +190,8 @@ static void ethernetcart_store(WORD io_address, BYTE byte) static int ethernetcart_dump(void) { mon_out("CS8900 mapped to $%04x ($%04x-$%04x), Mode: %s.\n", - ethernetcart_device.start_address & ~ethernetcart_device.address_mask, - ethernetcart_device.start_address + (ethernetcart_mode ? 2 : 0), + (unsigned int)(ethernetcart_device.start_address & ~ethernetcart_device.address_mask), + ethernetcart_device.start_address + (ethernetcart_mode ? 2U : 0U), ethernetcart_device.end_address, ethernetcart_mode ? "RR-Net" : "TFE" ); @@ -266,8 +273,8 @@ static int set_ethernetcart_base(int val, void *param) case 0xdee0: case 0xdef0: if (machine_class != VICE_MACHINE_VIC20) { - ethernetcart_device.start_address = (WORD)addr; - ethernetcart_device.end_address = (WORD)(addr + 0xf); + ethernetcart_device.start_address = (uint16_t)addr; + ethernetcart_device.end_address = (uint16_t)(addr + 0xf); export_res.io1 = ðernetcart_device; export_res.io2 = NULL; } else { @@ -291,8 +298,8 @@ static int set_ethernetcart_base(int val, void *param) case 0xdfe0: case 0xdff0: if (machine_class != VICE_MACHINE_VIC20) { - ethernetcart_device.start_address = (WORD)addr; - ethernetcart_device.end_address = (WORD)(addr + 0xf); + ethernetcart_device.start_address = (uint16_t)addr; + ethernetcart_device.end_address = (uint16_t)(addr + 0xf); export_res.io1 = NULL; export_res.io2 = ðernetcart_device; } else { @@ -332,8 +339,8 @@ static int set_ethernetcart_base(int val, void *param) case 0x9ce0: case 0x9cf0: if (machine_class == VICE_MACHINE_VIC20) { - ethernetcart_device.start_address = (WORD)addr; - ethernetcart_device.end_address = (WORD)(addr + 0xf); + ethernetcart_device.start_address = (uint16_t)addr; + ethernetcart_device.end_address = (uint16_t)(addr + 0xf); } else { return -1; } @@ -361,18 +368,34 @@ int ethernetcart_enable(void) return resources_set_int("ETHERNETCART_ACTIVE", 1); } -static const resource_int_t resources_int[] = { + +int ethernetcart_disable(void) +{ + return resources_set_int("ETHERNETCART_ACTIVE", 0); +} + + +static resource_int_t resources_int[] = { { "ETHERNETCART_ACTIVE", 0, RES_EVENT_STRICT, (resource_value_t)0, ðernetcart_enabled, set_ethernetcart_enabled, NULL }, - { "ETHERNETCARTBase", 0xffff, RES_EVENT_STRICT, (resource_value_t)0, + /* CAUTION: position is hardcoded below */ + { "ETHERNETCARTBase", 0xffff, RES_EVENT_STRICT, (resource_value_t)0xffff, ðernetcart_base, set_ethernetcart_base, NULL }, - { "ETHERNETCARTMode", ETHERNETCART_MODE_TFE, RES_EVENT_STRICT, (resource_value_t)0, + { "ETHERNETCARTMode", ETHERNETCART_MODE_RRNET, RES_EVENT_STRICT, (resource_value_t)ETHERNETCART_MODE_RRNET, ðernetcart_mode, set_ethernetcart_mode, NULL }, RESOURCE_INT_LIST_END }; int ethernetcart_resources_init(void) { + /* Set the default factory value depending on the machine. We do this + here so the default value will not end up in the config file. */ + if (machine_class == VICE_MACHINE_VIC20) { + resources_int[1].factory_value = 0x9800; + } else { + resources_int[1].factory_value = 0xde00; + } + if (cs8900io_resources_init() < 0) { return -1; } @@ -411,41 +434,29 @@ static int set_rrnet_enable(const char *value, void *extra_param) static const cmdline_option_t cmdline_options[] = { - { "-ethernetcart", SET_RESOURCE, 0, + { "-ethernetcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ETHERNETCART_ACTIVE", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_ETHERNETCART, - NULL, NULL }, - { "+ethernetcart", SET_RESOURCE, 0, + NULL, "Enable the Ethernet Cartridge (TFE/RR-Net/64NIC/FB-NET)" }, + { "+ethernetcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ETHERNETCART_ACTIVE", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_ETHERNETCART, - NULL, NULL }, - { "-tfe", CALL_FUNCTION, 0, + NULL, "Disable the Ethernet Cartridge (TFE/RR-Net/64NIC/FB-NET)" }, + { "-tfe", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, set_tfe_enable, NULL, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_TFE, - NULL, NULL }, - { "-rrnet", CALL_FUNCTION, 0, + NULL, "Enable the Ethernet Cartridge in TFE (\"The Final Ethernet\") compatible mode and set default I/O address" }, + { "-rrnet", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, set_rrnet_enable, NULL, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_RRNET, - NULL, NULL }, - { "-ethernetcartmode", SET_RESOURCE, 1, + NULL, "Enable the Ethernet Cartridge in RR-Net compatible mode and set default I/O address" }, + { "-ethernetcartmode", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ETHERNETCARTMode", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODE, IDCLS_ETHERNETCART_MODE, - NULL, NULL }, + "", "Mode of Ethernet Cartridge (0: TFE, 1: RR-Net)" }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-ethernetcartbase", SET_RESOURCE, 1, + { "-ethernetcartbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ETHERNETCARTBase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_ETHERNETCART_BASE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -464,11 +475,11 @@ int ethernetcart_cmdline_options_init(void) if (machine_class == VICE_MACHINE_VIC20) { temp1 = util_gen_hex_address_list(0x9800, 0x9900, 0x10); temp2 = util_gen_hex_address_list(0x9c00, 0x9d00, 0x10); - ethernetcart_address_list = util_concat(". (", temp1, "/", temp2, ")", NULL); + ethernetcart_address_list = util_concat("Base address of the Ethernet Cartridge. (", temp1, "/", temp2, ")", NULL); lib_free(temp2); } else { temp1 = util_gen_hex_address_list(0xde00, 0xe000, 0x10); - ethernetcart_address_list = util_concat(". (", temp1, ")", NULL); + ethernetcart_address_list = util_concat("Base address of the Ethernet Cartridge. (", temp1, ")", NULL); } lib_free(temp1); @@ -487,16 +498,16 @@ int ethernetcart_cmdline_options_init(void) /* FIXME: implement snapshot support */ int ethernetcart_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; - m = snapshot_module_create(s, SNAP_MODULE_NAME, - CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + m = snapshot_module_create(s, SNAP_MODULE_NAME, CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); if (m == NULL) { return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -511,7 +522,7 @@ int ethernetcart_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); @@ -534,4 +545,4 @@ int ethernetcart_snapshot_read_module(snapshot_t *s) #endif } -#endif /* #ifdef HAVE_PCAP */ +#endif /* #ifdef HAVE_RAWNET */ diff --git a/src/Emulators/vice/c64/cart/ethernetcart.h b/src/Emulators/vice/c64/cart/ethernetcart.h index 594e00b9..d3646499 100644 --- a/src/Emulators/vice/c64/cart/ethernetcart.h +++ b/src/Emulators/vice/c64/cart/ethernetcart.h @@ -24,10 +24,10 @@ * */ -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #else - #error ETHERNETCART.H should not be included if HAVE_PCAP is not defined! -#endif /* #ifdef HAVE_PCAP */ + #error ETHERNETCART.H should not be included if HAVE_RAWNET is not defined! +#endif /* #ifdef HAVE_RAWNET */ #ifndef CARTRIDGE_INCLUDE_PRIVATE_API #ifndef CARTRIDGE_INCLUDE_PUBLIC_API @@ -42,18 +42,19 @@ #define ETHERNETCART_MODE_RRNET 1 struct snapshot_s; -extern int ethernetcart_snapshot_read_module(struct snapshot_s *s); -extern int ethernetcart_snapshot_write_module(struct snapshot_s *s); +int ethernetcart_snapshot_read_module(struct snapshot_s *s); +int ethernetcart_snapshot_write_module(struct snapshot_s *s); -extern int ethernetcart_cart_enabled(void); +int ethernetcart_cart_enabled(void); -extern void ethernetcart_init(void); -extern int ethernetcart_resources_init(void); -extern void ethernetcart_resources_shutdown(void); -extern int ethernetcart_cmdline_options_init(void); +void ethernetcart_init(void); +int ethernetcart_resources_init(void); +void ethernetcart_resources_shutdown(void); +int ethernetcart_cmdline_options_init(void); -extern void ethernetcart_reset(void); -extern void ethernetcart_detach(void); -extern int ethernetcart_enable(void); +void ethernetcart_reset(void); +void ethernetcart_detach(void); +int ethernetcart_enable(void); +int ethernetcart_disable(void); #endif diff --git a/src/Emulators/vice/c64/cart/exos.c b/src/Emulators/vice/c64/cart/exos.c index 20084916..c267e06b 100644 --- a/src/Emulators/vice/c64/cart/exos.c +++ b/src/Emulators/vice/c64/cart/exos.c @@ -61,22 +61,22 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -BYTE exos_romh_read_hirom(WORD addr) +uint8_t exos_romh_read_hirom(uint16_t addr) { return romh_banks[(addr & 0x1fff)]; } -int exos_romh_phi1_read(WORD addr, BYTE *value) +int exos_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int exos_romh_phi2_read(WORD addr, BYTE *value) +int exos_romh_phi2_read(uint16_t addr, uint8_t *value) { return exos_romh_phi1_read(addr, value); } -int exos_peek_mem(export_t *export, WORD addr, BYTE *value) +int exos_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0xe000) { *value = romh_banks[addr & 0x1fff]; @@ -87,12 +87,12 @@ int exos_peek_mem(export_t *export, WORD addr, BYTE *value) void exos_config_init(void) { - cart_config_changed_slotmain(2, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); } /* ---------------------------------------------------------------------*/ -void exos_config_setup(BYTE *rawcart) +void exos_config_setup(uint8_t *rawcart) { memcpy(romh_banks, &rawcart[0], 0x2000); cart_config_changed_slotmain(2, 3, CMODE_READ); @@ -108,7 +108,7 @@ static int exos_common_attach(void) return 0; } -int exos_bin_attach(const char *filename, BYTE *rawcart) +int exos_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -117,7 +117,7 @@ int exos_bin_attach(const char *filename, BYTE *rawcart) return exos_common_attach(); } -int exos_crt_attach(FILE *fd, BYTE *rawcart) +int exos_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -150,7 +150,7 @@ void exos_detach(void) ARRAY | ROMH | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTEXOS"; +static const char snap_module_name[] = "CARTEXOS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -174,7 +174,7 @@ int exos_snapshot_write_module(snapshot_t *s) int exos_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -184,7 +184,7 @@ int exos_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/exos.h b/src/Emulators/vice/c64/cart/exos.h index e8d34a85..ce6b5b6d 100644 --- a/src/Emulators/vice/c64/cart/exos.h +++ b/src/Emulators/vice/c64/cart/exos.h @@ -34,19 +34,19 @@ struct snapshot_s; -extern BYTE exos_romh_read_hirom(WORD addr); -extern int exos_romh_phi1_read(WORD addr, BYTE *value); -extern int exos_romh_phi2_read(WORD addr, BYTE *value); -extern int exos_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern void exos_config_init(void); -extern void exos_reset(void); -extern void exos_config_setup(BYTE *rawcart); -extern int exos_bin_attach(const char *filename, BYTE *rawcart); -extern int exos_crt_attach(FILE *fd, BYTE *rawcart); -extern void exos_detach(void); - -extern int exos_snapshot_write_module(struct snapshot_s *s); -extern int exos_snapshot_read_module(struct snapshot_s *s); +uint8_t exos_romh_read_hirom(uint16_t addr); +int exos_romh_phi1_read(uint16_t addr, uint8_t *value); +int exos_romh_phi2_read(uint16_t addr, uint8_t *value); +int exos_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void exos_config_init(void); +void exos_reset(void); +void exos_config_setup(uint8_t *rawcart); +int exos_bin_attach(const char *filename, uint8_t *rawcart); +int exos_crt_attach(FILE *fd, uint8_t *rawcart); +void exos_detach(void); + +int exos_snapshot_write_module(struct snapshot_s *s); +int exos_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/expert.c b/src/Emulators/vice/c64/cart/expert.c index 91dce13c..da8ca6ea 100644 --- a/src/Emulators/vice/c64/cart/expert.c +++ b/src/Emulators/vice/c64/cart/expert.c @@ -43,9 +43,10 @@ #include "export.h" #include "interrupt.h" #include "lib.h" +#include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "crt.h" @@ -190,7 +191,6 @@ NMI entry from expert 2.70: #ifdef DBGEXPERT #define DBG(x) printf x -char *expert_mode[3]={"off", "prg", "on"}; #else #define DBG(x) #endif @@ -205,6 +205,8 @@ char *expert_mode[3]={"off", "prg", "on"}; #define EXPERT_OFF ((0 << 0) | (1 << 1)) /* ram */ #define EXPERT_ON ((1 << 0) | (1 << 1)) /* ultimax */ +const char * const expert_mode[3]={"off", "prg", "on"}; + static int cartmode = EXPERT_MODE_DEFAULT; static int expert_enabled = 0; static int expert_register_enabled = 0; @@ -212,7 +214,7 @@ static int expert_ram_writeable = 0; static int expert_ramh_enabled = 0; /* equals EXROM ? */ /* 8 KB RAM */ -static BYTE *expert_ram = NULL; +static uint8_t *expert_ram = NULL; static char *expert_filename = NULL; static int expert_filetype = 0; @@ -226,23 +228,26 @@ static int expert_load_image(void); /* ---------------------------------------------------------------------*/ -BYTE expert_io1_read(WORD addr); -BYTE expert_io1_peek(WORD addr); -void expert_io1_store(WORD addr, BYTE value); +static uint8_t expert_io1_read(uint16_t addr); +static uint8_t expert_io1_peek(uint16_t addr); +static void expert_io1_store(uint16_t addr, uint8_t value); +static int expert_dump(void); static io_source_t expert_io1_device = { - CARTRIDGE_NAME_EXPERT, - IO_DETACH_CART, - NULL, - 0xde00, 0xde01, 0xff, - 0, /* read is never valid */ - expert_io1_store, - expert_io1_read, - expert_io1_peek, - NULL, /* TODO: dump */ - CARTRIDGE_EXPERT, - 0, - 0 + CARTRIDGE_NAME_EXPERT, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xde01, 0xff, /* range for the device, regs:$de00-$de01 */ + 0, /* read is never valid */ + expert_io1_store, /* store function */ + NULL, /* NO poke function */ + expert_io1_read, /* read function */ + expert_io1_peek, /* peek function */ + expert_dump, /* device state information dump function */ + CARTRIDGE_EXPERT, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static const export_resource_t export_res = { @@ -299,11 +304,39 @@ static int expert_mode_changed(int mode, void *param) return 0; } +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void expert_powerup(void) +{ + DBG(("expert_powerup\n")); + if ((expert_filename != NULL) && (*expert_filename != 0)) { + /* do not init ram if a file is used for ram content (like battery backup) */ + return; + } + if (expert_ram) { + DBG(("expert_powerup ram clear\n")); + ram_init_with_pattern(expert_ram, EXPERT_RAM_SIZE, &ramparam); + } +} + static int expert_activate(void) { if (expert_ram == NULL) { expert_ram = lib_malloc(EXPERT_RAM_SIZE); } + ram_init_with_pattern(expert_ram, EXPERT_RAM_SIZE, &ramparam); if (!util_check_null_string(expert_filename)) { log_message(LOG_DEFAULT, "Reading Expert Cartridge image %s.", expert_filename); @@ -413,7 +446,7 @@ static int set_expert_filename(const char *name, void *param) /* ---------------------------------------------------------------------*/ -void expert_io1_store(WORD addr, BYTE value) +static void expert_io1_store(uint16_t addr, uint8_t value) { DBG(("EXPERT: io1 wr %04x (%d)\n", addr, value)); if ((cartmode == EXPERT_MODE_ON) && (expert_register_enabled == 1)) { @@ -424,7 +457,7 @@ void expert_io1_store(WORD addr, BYTE value) } } -BYTE expert_io1_read(WORD addr) +static uint8_t expert_io1_read(uint16_t addr) { expert_io1_device.io_source_valid = 0; DBG(("EXPERT: io1 rd %04x (%d)\n", addr, expert_ramh_enabled)); @@ -437,14 +470,23 @@ BYTE expert_io1_read(WORD addr) return 0; } -BYTE expert_io1_peek(WORD addr) +static uint8_t expert_io1_peek(uint16_t addr) { return 0; } +static int expert_dump(void) +{ + mon_out("Cartridge mode: %s, Register is %s\n", + expert_mode[cartmode], expert_register_enabled ? "enabled" : "disabled"); + mon_out("RAM: %s, %s\n", expert_ramh_enabled ? "mapped in" : "not mapped in", + expert_ram_writeable ? "writeable" : "readonly"); + return 0; +} + /* ---------------------------------------------------------------------*/ -BYTE expert_roml_read(WORD addr) +uint8_t expert_roml_read(uint16_t addr) { /* DBG(("EXPERT: set expert_roml_read: %x\n", addr)); */ if (cartmode == EXPERT_MODE_PRG) { @@ -456,7 +498,7 @@ BYTE expert_roml_read(WORD addr) } } -void expert_roml_store(WORD addr, BYTE value) +void expert_roml_store(uint16_t addr, uint8_t value) { /* DBG(("EXPERT: set expert_roml_store: %x\n", addr)); */ if (expert_ram_writeable) { @@ -473,7 +515,7 @@ void expert_roml_store(WORD addr, BYTE value) } } -BYTE expert_romh_read(WORD addr) +uint8_t expert_romh_read(uint16_t addr) { /* DBG(("EXPERT: set expert_romh_read: %x mode %d %02x %02x\n", addr, cartmode, expert_ram[0x1ffe], expert_ram[0x1fff])); */ if ((cartmode == EXPERT_MODE_ON) && expert_ramh_enabled) { @@ -483,7 +525,7 @@ BYTE expert_romh_read(WORD addr) } } -int expert_romh_phi1_read(WORD addr, BYTE *value) +int expert_romh_phi1_read(uint16_t addr, uint8_t *value) { if ((cartmode == EXPERT_MODE_ON) && expert_ramh_enabled) { *value = expert_ram[addr & 0x1fff]; @@ -492,12 +534,12 @@ int expert_romh_phi1_read(WORD addr, BYTE *value) return CART_READ_C64MEM; } -int expert_romh_phi2_read(WORD addr, BYTE *value) +int expert_romh_phi2_read(uint16_t addr, uint8_t *value) { return expert_romh_phi1_read(addr, value); } -int expert_peek_mem(WORD addr, BYTE *value) +int expert_peek_mem(uint16_t addr, uint8_t *value) { if (cartmode == EXPERT_MODE_PRG) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { @@ -541,7 +583,7 @@ void expert_freeze(void) } } -void expert_ack_nmi(void) +static void expert_ack_nmi(void) { if (cartmode == EXPERT_MODE_ON) { DBG(("EXPERT:ack nmi\n")); @@ -576,7 +618,7 @@ void expert_reset(void) /* ---------------------------------------------------------------------*/ -void expert_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void expert_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { switch (addr & 0xf000) { case 0xf000: @@ -615,7 +657,7 @@ void expert_config_init(void) } } -void expert_config_setup(BYTE *rawcart) +void expert_config_setup(uint8_t *rawcart) { memcpy(expert_ram, rawcart, EXPERT_RAM_SIZE); /* DBG(("ram %02x %02x\n", expert_ram[0x1ffe], expert_ram[0x1fff])); */ @@ -646,7 +688,7 @@ static int expert_common_attach(void) return -1; } -static int expert_bin_load(const char *filename, BYTE *rawcart) +static int expert_bin_load(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, EXPERT_RAM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -655,11 +697,12 @@ static int expert_bin_load(const char *filename, BYTE *rawcart) return 0; } -int expert_bin_attach(const char *filename, BYTE *rawcart) +int expert_bin_attach(const char *filename, uint8_t *rawcart) { if (expert_bin_load(filename, rawcart) < 0) { return -1; } + /* set the resource */ if (set_expert_filename(filename, NULL) < 0) { return -1; } @@ -694,7 +737,7 @@ int expert_bin_save(const char *filename) return 0; } -static int expert_crt_load(FILE *fd, BYTE *rawcart) +static int expert_crt_load(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -713,11 +756,12 @@ static int expert_crt_load(FILE *fd, BYTE *rawcart) return 0; } -int expert_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int expert_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { if (expert_crt_load(fd, rawcart) < 0) { return -1; } + /* set the resource */ if (set_expert_filename(filename, NULL) < 0) { return -1; } @@ -765,10 +809,12 @@ static int expert_load_image(void) FILE *fd; if (crt_getid(expert_filename) == CARTRIDGE_EXPERT) { + DBG(("EXPERT: detected .crt format\n")); fd = fopen(expert_filename, MODE_READ); res = expert_crt_load(fd, expert_ram); fclose(fd); } else { + DBG(("EXPERT: detected .bin format\n")); res = expert_bin_load(expert_filename, expert_ram); } return res; @@ -798,6 +844,18 @@ int expert_enable(void) return 0; } + +int expert_disable(void) +{ + DBG(("EXPERT: disable\n")); + if (resources_set_int("ExpertCartridgeEnabled", 0) < 0) { + return -1; + } + return 0; +} + + + /* ---------------------------------------------------------------------*/ /* CARTEXPERT snapshot module format: @@ -811,7 +869,7 @@ int expert_enable(void) ARRAY | RAM | 8192 BYTES of RAM data */ -static char snap_module_name[] = "CARTEXPERT"; +static const char snap_module_name[] = "CARTEXPERT"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -826,10 +884,10 @@ int expert_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)cartmode) < 0) - || (SMW_B(m, (BYTE)expert_register_enabled) < 0) - || (SMW_B(m, (BYTE)expert_ram_writeable) < 0) - || (SMW_B(m, (BYTE)expert_ramh_enabled) < 0) + || (SMW_B(m, (uint8_t)cartmode) < 0) + || (SMW_B(m, (uint8_t)expert_register_enabled) < 0) + || (SMW_B(m, (uint8_t)expert_ram_writeable) < 0) + || (SMW_B(m, (uint8_t)expert_ramh_enabled) < 0) || (SMW_BA(m, expert_ram, EXPERT_RAM_SIZE) < 0)) { snapshot_module_close(m); return -1; @@ -840,7 +898,7 @@ int expert_snapshot_write_module(snapshot_t *s) int expert_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -850,7 +908,7 @@ int expert_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; @@ -895,36 +953,24 @@ int expert_snapshot_read_module(snapshot_t *s) static const cmdline_option_t cmdline_options[] = { - { "-expert", SET_RESOURCE, 0, + { "-expert", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ExpertCartridgeEnabled", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_EXPERT_CART, - NULL, NULL }, - { "+expert", SET_RESOURCE, 0, + NULL, "Enable the Expert Cartridge" }, + { "+expert", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ExpertCartridgeEnabled", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_EXPERT_CART, - NULL, NULL }, - { "-expertimagename", SET_RESOURCE, 1, + NULL, "Disable the Expert Cartridge" }, + { "-expertimagename", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "Expertfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SET_EXPERT_FILENAME, - NULL, NULL }, - { "-expertimagerw", SET_RESOURCE, 0, + "", "Set Expert Cartridge image name" }, + { "-expertimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ExpertImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_EXPERT_IMAGE, - NULL, NULL }, - { "+expertimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to Expert Cartridge image" }, + { "+expertimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "ExpertImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_EXPERT_IMAGE, - NULL, NULL }, - { "-expertmode", SET_RESOURCE, 1, + NULL, "Do not write to Expert Cartridge image" }, + { "-expertmode", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ExpertCartridgeMode", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_MODE, IDCLS_SET_EXPERT_MODE, - NULL, NULL }, + "", "Set Expert Cartridge mode (0: Off, 1: Prg, 2: On)" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/c64/cart/expert.h b/src/Emulators/vice/c64/cart/expert.h index 11ee191f..4c8c27a2 100644 --- a/src/Emulators/vice/c64/cart/expert.h +++ b/src/Emulators/vice/c64/cart/expert.h @@ -39,41 +39,44 @@ #include "vicetypes.h" -extern BYTE expert_roml_read(WORD addr); -extern void expert_roml_store(WORD addr, BYTE value); -extern void expert_raml_store(WORD addr, BYTE value); -extern BYTE expert_romh_read(WORD addr); -extern int expert_romh_phi1_read(WORD addr, BYTE *value); -extern int expert_romh_phi2_read(WORD addr, BYTE *value); -extern int expert_peek_mem(WORD addr, BYTE *value); - -extern void expert_reset(void); -extern void expert_freeze(void); - -extern void expert_config_init(void); -extern void expert_config_setup(BYTE *rawcart); -extern int expert_bin_attach(const char *filename, BYTE *rawcart); -extern int expert_bin_save(const char *filename); -extern int expert_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern int expert_crt_save(const char *filename); -extern int expert_flush_image(void); - -extern void expert_detach(void); -extern int expert_enable(void); - -extern int expert_freeze_allowed(void); -extern int expert_cart_enabled(void); -extern void expert_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +uint8_t expert_roml_read(uint16_t addr); +void expert_roml_store(uint16_t addr, uint8_t value); +void expert_raml_store(uint16_t addr, uint8_t value); +uint8_t expert_romh_read(uint16_t addr); +int expert_romh_phi1_read(uint16_t addr, uint8_t *value); +int expert_romh_phi2_read(uint16_t addr, uint8_t *value); +int expert_peek_mem(uint16_t addr, uint8_t *value); + +void expert_reset(void); +void expert_freeze(void); + +void expert_config_init(void); +void expert_config_setup(uint8_t *rawcart); +int expert_bin_attach(const char *filename, uint8_t *rawcart); +int expert_bin_save(const char *filename); +int expert_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int expert_crt_save(const char *filename); +int expert_flush_image(void); + +void expert_detach(void); +int expert_enable(void); +int expert_disable(void); +void expert_powerup(void); + +int expert_freeze_allowed(void); +int expert_cart_enabled(void); +void expert_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); struct snapshot_s; -extern int expert_snapshot_write_module(struct snapshot_s *s); -extern int expert_snapshot_read_module(struct snapshot_s *s); -extern int expert_resources_init(void); -extern void expert_resources_shutdown(void); -extern int expert_cmdline_options_init(void); +int expert_snapshot_write_module(struct snapshot_s *s); +int expert_snapshot_read_module(struct snapshot_s *s); -extern const char *expert_get_file_name(void); +int expert_resources_init(void); +void expert_resources_shutdown(void); +int expert_cmdline_options_init(void); + +const char *expert_get_file_name(void); #endif /* VICE_EXPERT_H */ #endif /* CARTRIDGE_INCLUDE_PRIVATE_API */ diff --git a/src/Emulators/vice/c64/cart/final.c b/src/Emulators/vice/c64/cart/final.c index 2feb0414..ea955742 100644 --- a/src/Emulators/vice/c64/cart/final.c +++ b/src/Emulators/vice/c64/cart/final.c @@ -65,42 +65,46 @@ #endif /* some prototypes are needed */ -static BYTE final_v1_io1_read(WORD addr); -static BYTE final_v1_io1_peek(WORD addr); -static void final_v1_io1_store(WORD addr, BYTE value); -static BYTE final_v1_io2_read(WORD addr); -static BYTE final_v1_io2_peek(WORD addr); -static void final_v1_io2_store(WORD addr, BYTE value); +static uint8_t final_v1_io1_read(uint16_t addr); +static uint8_t final_v1_io1_peek(uint16_t addr); +static void final_v1_io1_store(uint16_t addr, uint8_t value); +static uint8_t final_v1_io2_read(uint16_t addr); +static uint8_t final_v1_io2_peek(uint16_t addr); +static void final_v1_io2_store(uint16_t addr, uint8_t value); static int final_v1_dump(void); static io_source_t final1_io1_device = { - CARTRIDGE_NAME_FINAL_I, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - final_v1_io1_store, - final_v1_io1_read, - final_v1_io1_peek, - final_v1_dump, - CARTRIDGE_FINAL_I, - 0, - 0 + CARTRIDGE_NAME_FINAL_I, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + final_v1_io1_store, /* store function */ + NULL, /* NO poke function */ + final_v1_io1_read, /* read function */ + final_v1_io1_peek, /* peek function */ + final_v1_dump, /* device state information dump function */ + CARTRIDGE_FINAL_I, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t final1_io2_device = { - CARTRIDGE_NAME_FINAL_I, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - final_v1_io2_store, - final_v1_io2_read, - final_v1_io2_peek, - final_v1_dump, - CARTRIDGE_FINAL_I, - 0, - 0 + CARTRIDGE_NAME_FINAL_I, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + final_v1_io2_store, /* store function */ + NULL, /* NO poke function */ + final_v1_io2_read, /* read function */ + final_v1_io2_peek, /* peek function */ + final_v1_dump, /* device state information dump function */ + CARTRIDGE_FINAL_I, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *final1_io1_list_item = NULL; @@ -114,7 +118,7 @@ static const export_resource_t export_res_v1 = { static int final_v1_active = 0; -static BYTE final_v1_io1_read(WORD addr) +static uint8_t final_v1_io1_read(uint16_t addr) { DBG(("disable %04x\n", addr)); cart_config_changed_slotmain(2, 2, CMODE_READ | CMODE_RELEASE_FREEZE); @@ -122,19 +126,19 @@ static BYTE final_v1_io1_read(WORD addr) return roml_banks[0x1e00 + (addr & 0xff)]; } -static BYTE final_v1_io1_peek(WORD addr) +static uint8_t final_v1_io1_peek(uint16_t addr) { return roml_banks[0x1e00 + (addr & 0xff)]; } -static void final_v1_io1_store(WORD addr, BYTE value) +static void final_v1_io1_store(uint16_t addr, uint8_t value) { DBG(("disable %04x %02x\n", addr, value)); cart_config_changed_slotmain(2, 2, CMODE_WRITE | CMODE_RELEASE_FREEZE); final_v1_active = 0; } -static BYTE final_v1_io2_read(WORD addr) +static uint8_t final_v1_io2_read(uint16_t addr) { DBG(("enable %04x\n", addr)); cart_config_changed_slotmain(1, 1, CMODE_READ | CMODE_RELEASE_FREEZE); @@ -142,12 +146,12 @@ static BYTE final_v1_io2_read(WORD addr) return roml_banks[0x1f00 + (addr & 0xff)]; } -static BYTE final_v1_io2_peek(WORD addr) +static uint8_t final_v1_io2_peek(uint16_t addr) { return roml_banks[0x1f00 + (addr & 0xff)]; } -static void final_v1_io2_store(WORD addr, BYTE value) +static void final_v1_io2_store(uint16_t addr, uint8_t value) { DBG(("enable %04x %02x\n", addr, value)); cart_config_changed_slotmain(1, 1, CMODE_WRITE | CMODE_RELEASE_FREEZE); @@ -163,12 +167,12 @@ static int final_v1_dump(void) /* ---------------------------------------------------------------------*/ -BYTE final_v1_roml_read(WORD addr) +uint8_t final_v1_roml_read(uint16_t addr) { return roml_banks[(addr & 0x1fff)]; } -BYTE final_v1_romh_read(WORD addr) +uint8_t final_v1_romh_read(uint16_t addr) { return romh_banks[(addr & 0x1fff)]; } @@ -178,22 +182,22 @@ BYTE final_v1_romh_read(WORD addr) void final_v1_freeze(void) { DBG(("freeze enable\n")); - cart_config_changed_slotmain(3, 3, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); final_v1_active = 1; cartridge_release_freeze(); } void final_v1_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); final_v1_active = 1; } -void final_v1_config_setup(BYTE *rawcart) +void final_v1_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); final_v1_active = 1; } @@ -211,7 +215,7 @@ static int final_v1_common_attach(void) return 0; } -int final_v1_bin_attach(const char *filename, BYTE *rawcart) +int final_v1_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -220,7 +224,7 @@ int final_v1_bin_attach(const char *filename, BYTE *rawcart) return final_v1_common_attach(); } -int final_v1_crt_attach(FILE *fd, BYTE *rawcart) +int final_v1_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -259,7 +263,7 @@ void final_v1_detach(void) ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTFINALV1"; +static const char snap_module_name[] = "CARTFINALV1"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -274,7 +278,7 @@ int final_v1_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)final_v1_active) < 0) + || (SMW_B(m, (uint8_t)final_v1_active) < 0) || (SMW_BA(m, roml_banks, 0x2000) < 0) || (SMW_BA(m, romh_banks, 0x2000) < 0)) { snapshot_module_close(m); @@ -286,7 +290,7 @@ int final_v1_snapshot_write_module(snapshot_t *s) int final_v1_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -296,13 +300,13 @@ int final_v1_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &final_v1_active) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/final.h b/src/Emulators/vice/c64/cart/final.h index d9cdc577..d4f96ed8 100644 --- a/src/Emulators/vice/c64/cart/final.h +++ b/src/Emulators/vice/c64/cart/final.h @@ -32,18 +32,18 @@ #include "vicetypes.h" -extern void final_v1_freeze(void); -extern BYTE final_v1_roml_read(WORD addr); -extern BYTE final_v1_romh_read(WORD addr); -extern void final_v1_config_init(void); -extern void final_v1_config_setup(BYTE *rawcart); -extern int final_v1_bin_attach(const char *filename, BYTE *rawcart); -extern int final_v1_crt_attach(FILE *fd, BYTE *rawcart); -extern void final_v1_detach(void); +void final_v1_freeze(void); +uint8_t final_v1_roml_read(uint16_t addr); +uint8_t final_v1_romh_read(uint16_t addr); +void final_v1_config_init(void); +void final_v1_config_setup(uint8_t *rawcart); +int final_v1_bin_attach(const char *filename, uint8_t *rawcart); +int final_v1_crt_attach(FILE *fd, uint8_t *rawcart); +void final_v1_detach(void); struct snapshot_s; -extern int final_v1_snapshot_write_module(struct snapshot_s *s); -extern int final_v1_snapshot_read_module(struct snapshot_s *s); +int final_v1_snapshot_write_module(struct snapshot_s *s); +int final_v1_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/final3.c b/src/Emulators/vice/c64/cart/final3.c index 7b2c4795..000c2f32 100644 --- a/src/Emulators/vice/c64/cart/final3.c +++ b/src/Emulators/vice/c64/cart/final3.c @@ -81,43 +81,47 @@ */ static int fc3_reg_enabled = 1; -static BYTE regval = 0; +static uint8_t regval = 0; static int fc3_rom_banks = 4; /* some prototypes are needed */ -static BYTE final_v3_io1_read(WORD addr); -static BYTE final_v3_io2_read(WORD addr); -static void final_v3_io2_store(WORD addr, BYTE value); +static uint8_t final_v3_io1_read(uint16_t addr); +static uint8_t final_v3_io2_read(uint16_t addr); +static void final_v3_io2_store(uint16_t addr, uint8_t value); static int final_v3_dump(void); static io_source_t final3_io1_device = { - CARTRIDGE_NAME_FINAL_III, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - NULL, - final_v3_io1_read, - final_v3_io1_read, /* peek */ - final_v3_dump, - CARTRIDGE_FINAL_III, - 0, - 0 + CARTRIDGE_NAME_FINAL_III, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + final_v3_io1_read, /* read function */ + final_v3_io1_read, /* peek function */ + final_v3_dump, /* device state information dump function */ + CARTRIDGE_FINAL_III, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t final3_io2_device = { - CARTRIDGE_NAME_FINAL_III, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - final_v3_io2_store, - final_v3_io2_read, - final_v3_io2_read, /* peek */ - final_v3_dump, - CARTRIDGE_FINAL_III, - 0, - 0 + CARTRIDGE_NAME_FINAL_III, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + final_v3_io2_store, /* store function */ + NULL, /* NO poke function */ + final_v3_io2_read, /* read function */ + final_v3_io2_read, /* peek function */ + final_v3_dump, /* device state information dump function */ + CARTRIDGE_FINAL_III, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *final3_io1_list_item = NULL; @@ -129,20 +133,20 @@ static const export_resource_t export_res_v3 = { /* ---------------------------------------------------------------------*/ -BYTE final_v3_io1_read(WORD addr) +uint8_t final_v3_io1_read(uint16_t addr) { return roml_banks[0x1e00 + (roml_bank << 13) + (addr & 0xff)]; } -BYTE final_v3_io2_read(WORD addr) +uint8_t final_v3_io2_read(uint16_t addr) { return roml_banks[0x1f00 + (roml_bank << 13) + (addr & 0xff)]; } -void final_v3_io2_store(WORD addr, BYTE value) +void final_v3_io2_store(uint16_t addr, uint8_t value) { unsigned int flags; - BYTE mode; + uint8_t mode; regval = value; @@ -176,23 +180,23 @@ void final_v3_freeze(void) fc3_reg_enabled = 1; /* note: freeze does NOT force a specific bank like some other carts do */ - cart_config_changed_slotmain(2, (BYTE)(3 | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_ULTIMAX | (roml_bank << CMODE_BANK_SHIFT)), CMODE_READ); } void final_v3_config_init(void) { fc3_reg_enabled = 1; - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } -void final_v3_config_setup(BYTE *rawcart) +void final_v3_config_setup(uint8_t *rawcart) { int i; for (i = 0; i <= fc3_rom_banks; i++) { memcpy(&roml_banks[0x2000 * i], &rawcart[0x0000 + (0x4000 * i)], 0x2000); memcpy(&romh_banks[0x2000 * i], &rawcart[0x2000 + (0x4000 * i)], 0x2000); } - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -209,7 +213,7 @@ static int final_v3_common_attach(void) return 0; } -int final_v3_bin_attach(const char *filename, BYTE *rawcart) +int final_v3_bin_attach(const char *filename, uint8_t *rawcart) { fc3_rom_banks = 4; if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -222,7 +226,7 @@ int final_v3_bin_attach(const char *filename, BYTE *rawcart) return final_v3_common_attach(); } -int final_v3_crt_attach(FILE *fd, BYTE *rawcart) +int final_v3_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i, banks = 0; @@ -269,12 +273,12 @@ void final_v3_detach(void) BYTE | register | 1.2 | register BYTE | reg enabled | 0.0+ | register enabled flag ARRAY | ROML | 1.1+ | 32768 or 131072 BYTES of ROML data - ARRAY | ROMH | 1.1+ | 32768 or 131072 BYTES of ROML data + ARRAY | ROMH | 1.1+ | 32768 or 131072 BYTES of ROML data Note: in 0.0 ROML and ROMH data was always 32768 BYTES. */ -static char snap_module_name[] = "CARTFC3"; +static const char snap_module_name[] = "CARTFC3"; #define SNAP_MAJOR 1 #define SNAP_MINOR 2 @@ -289,9 +293,9 @@ int final_v3_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)fc3_rom_banks) < 0 + || SMW_B(m, (uint8_t)fc3_rom_banks) < 0 || SMW_B(m, regval) < 0 - || SMW_B(m, (BYTE)fc3_reg_enabled) < 0 + || SMW_B(m, (uint8_t)fc3_reg_enabled) < 0 || SMW_BA(m, roml_banks, 0x2000 * fc3_rom_banks) < 0 || SMW_BA(m, romh_banks, 0x2000 * fc3_rom_banks) < 0) { snapshot_module_close(m); @@ -303,7 +307,7 @@ int final_v3_snapshot_write_module(snapshot_t *s) int final_v3_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -313,13 +317,13 @@ int final_v3_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 1.2 */ - if (SNAPVAL(vmajor, vminor, 1, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 1, 2)) { if (0 || SMR_B_INT(m, &fc3_rom_banks) < 0 || SMR_B(m, ®val) < 0) { @@ -335,7 +339,7 @@ int final_v3_snapshot_read_module(snapshot_t *s) } /* changed in 1.1 */ - if (SNAPVAL(vmajor, vminor, 1, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 1, 1)) { if (0 || SMR_BA(m, roml_banks, 0x2000 * fc3_rom_banks) < 0 || SMR_BA(m, romh_banks, 0x2000 * fc3_rom_banks) < 0) { diff --git a/src/Emulators/vice/c64/cart/final3.h b/src/Emulators/vice/c64/cart/final3.h index 959ad2a2..fc8fa95f 100644 --- a/src/Emulators/vice/c64/cart/final3.h +++ b/src/Emulators/vice/c64/cart/final3.h @@ -32,16 +32,16 @@ #include "vicetypes.h" -extern void final_v3_freeze(void); -extern void final_v3_config_init(void); -extern void final_v3_config_setup(BYTE *rawcart); -extern int final_v3_bin_attach(const char *filename, BYTE *rawcart); -extern int final_v3_crt_attach(FILE *fd, BYTE *rawcart); -extern void final_v3_detach(void); +void final_v3_freeze(void); +void final_v3_config_init(void); +void final_v3_config_setup(uint8_t *rawcart); +int final_v3_bin_attach(const char *filename, uint8_t *rawcart); +int final_v3_crt_attach(FILE *fd, uint8_t *rawcart); +void final_v3_detach(void); struct snapshot_s; -extern int final_v3_snapshot_write_module(struct snapshot_s *s); -extern int final_v3_snapshot_read_module(struct snapshot_s *s); +int final_v3_snapshot_write_module(struct snapshot_s *s); +int final_v3_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/finalplus.c b/src/Emulators/vice/c64/cart/finalplus.c index 8065a0f3..ab1f0d35 100644 --- a/src/Emulators/vice/c64/cart/finalplus.c +++ b/src/Emulators/vice/c64/cart/finalplus.c @@ -77,23 +77,25 @@ static int fcplus_roml; static int fcplus_romh; /* some prototypes are needed */ -static BYTE final_plus_io2_read(WORD addr); -static void final_plus_io2_store(WORD addr, BYTE value); +static uint8_t final_plus_io2_read(uint16_t addr); +static void final_plus_io2_store(uint16_t addr, uint8_t value); static int final_plus_dump(void); static io_source_t final_plus_io2_device = { - CARTRIDGE_NAME_FINAL_PLUS, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - final_plus_io2_store, - final_plus_io2_read, - final_plus_io2_read, - final_plus_dump, - CARTRIDGE_FINAL_PLUS, - 0, - 0 + CARTRIDGE_NAME_FINAL_PLUS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 1, /* read is always valid */ + final_plus_io2_store, /* store function */ + NULL, /* NO poke function */ + final_plus_io2_read, /* read function */ + final_plus_io2_read, /* peek function */ + final_plus_dump, /* device state information dump function */ + CARTRIDGE_FINAL_PLUS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *final_plus_io2_list_item = NULL; @@ -104,13 +106,13 @@ static const export_resource_t export_res_plus = { /* ---------------------------------------------------------------------*/ -BYTE final_plus_io2_read(WORD addr) +uint8_t final_plus_io2_read(uint16_t addr) { DBG(("io2 r %04x\n", addr)); - return ((fcplus_bit << 7) || (fcplus_roml << 6) || (fcplus_romh << 5) || (fcplus_enabled << 4)); + return ((fcplus_bit << 7) | (fcplus_roml << 6) | (fcplus_romh << 5) | (fcplus_enabled << 4)); } -void final_plus_io2_store(WORD addr, BYTE value) +void final_plus_io2_store(uint16_t addr, uint8_t value) { if (fcplus_enabled == 1) { fcplus_bit = (value >> 7) & 1; @@ -152,7 +154,7 @@ static int final_plus_dump(void) /* ---------------------------------------------------------------------*/ -BYTE final_plus_roml_read(WORD addr) +uint8_t final_plus_roml_read(uint16_t addr) { if (fcplus_roml == 1) { return roml_banks[(addr & 0x1fff)]; @@ -161,7 +163,7 @@ BYTE final_plus_roml_read(WORD addr) } } -BYTE final_plus_romh_read(WORD addr) +uint8_t final_plus_romh_read(uint16_t addr) { if ((fcplus_enabled == 1) && (fcplus_romh == 1)) { return romh_banks[(addr & 0x1fff)]; @@ -170,7 +172,7 @@ BYTE final_plus_romh_read(WORD addr) } } -BYTE final_plus_a000_bfff_read(WORD addr) +uint8_t final_plus_a000_bfff_read(uint16_t addr) { if ((fcplus_enabled == 1) && (fcplus_roml == 1)) { return roml_banks[0x2000 + (addr & 0x1fff)]; @@ -179,17 +181,17 @@ BYTE final_plus_a000_bfff_read(WORD addr) } } -int final_plus_romh_phi1_read(WORD addr, BYTE *value) +int final_plus_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int final_plus_romh_phi2_read(WORD addr, BYTE *value) +int final_plus_romh_phi2_read(uint16_t addr, uint8_t *value) { return final_plus_romh_phi1_read(addr, value); } -int final_plus_peek_mem(export_t *export, WORD addr, BYTE *value) +int final_plus_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (fcplus_roml == 1) { if (addr >= 0x8000 && addr <= 0x9fff) { @@ -215,7 +217,7 @@ int final_plus_peek_mem(export_t *export, WORD addr, BYTE *value) void final_plus_freeze(void) { DBG(("fc+ freeze\n")); - cart_config_changed_slotmain(0, 3, CMODE_READ | CMODE_RELEASE_FREEZE | CMODE_PHI2_RAM); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE | CMODE_PHI2_RAM); fcplus_enabled = 1; fcplus_roml = 1; fcplus_romh = 1; @@ -224,7 +226,7 @@ void final_plus_freeze(void) void final_plus_config_init(void) { DBG(("fc+ config init\n")); - cart_config_changed_slotmain(0, 3, CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_ULTIMAX, CMODE_READ | CMODE_PHI2_RAM); fcplus_enabled = 1; fcplus_roml = 1; fcplus_romh = 1; @@ -234,12 +236,12 @@ EPROM $2000-$4000 is visible at $e000-$ffff, if enabled EPROM $4000-$5fff is visible at $8000-$9fff, if enabled EPROM $6000-$7fff is visible at $a000-$bfff, if enabled */ -void final_plus_config_setup(BYTE *rawcart) +void final_plus_config_setup(uint8_t *rawcart) { DBG(("fc+ config setup\n")); memcpy(roml_banks, &rawcart[0x4000], 0x4000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(0, 3, CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_ULTIMAX, CMODE_READ | CMODE_PHI2_RAM); } /* ---------------------------------------------------------------------*/ @@ -255,7 +257,7 @@ static int final_plus_common_attach(void) return 0; } -int final_plus_bin_attach(const char *filename, BYTE *rawcart) +int final_plus_bin_attach(const char *filename, uint8_t *rawcart) { DBG(("fc+ bin attach\n")); @@ -270,7 +272,7 @@ int final_plus_bin_attach(const char *filename, BYTE *rawcart) return final_plus_common_attach(); } -int final_plus_crt_attach(FILE *fd, BYTE *rawcart) +int final_plus_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -311,7 +313,7 @@ void final_plus_detach(void) ARRAY | ROMH | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTFCP"; +static const char snap_module_name[] = "CARTFCP"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -326,10 +328,10 @@ int final_plus_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)fcplus_enabled) < 0) - || (SMW_B(m, (BYTE)fcplus_bit) < 0) - || (SMW_B(m, (BYTE)fcplus_roml) < 0) - || (SMW_B(m, (BYTE)fcplus_romh) < 0) + || (SMW_B(m, (uint8_t)fcplus_enabled) < 0) + || (SMW_B(m, (uint8_t)fcplus_bit) < 0) + || (SMW_B(m, (uint8_t)fcplus_roml) < 0) + || (SMW_B(m, (uint8_t)fcplus_romh) < 0) || (SMW_BA(m, roml_banks, 0x4000) < 0) || (SMW_BA(m, romh_banks, 0x2000) < 0)) { snapshot_module_close(m); @@ -341,7 +343,7 @@ int final_plus_snapshot_write_module(snapshot_t *s) int final_plus_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -351,7 +353,7 @@ int final_plus_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/finalplus.h b/src/Emulators/vice/c64/cart/finalplus.h index d562507b..dc96ba3d 100644 --- a/src/Emulators/vice/c64/cart/finalplus.h +++ b/src/Emulators/vice/c64/cart/finalplus.h @@ -34,21 +34,21 @@ struct snapshot_s; -extern void final_plus_freeze(void); -extern void final_plus_config_init(void); -extern void final_plus_config_setup(BYTE *rawcart); -extern int final_plus_bin_attach(const char *filename, BYTE *rawcart); -extern int final_plus_crt_attach(FILE *fd, BYTE *rawcart); -extern void final_plus_detach(void); - -extern BYTE final_plus_roml_read(WORD addr); -extern BYTE final_plus_romh_read(WORD addr); -extern BYTE final_plus_a000_bfff_read(WORD addr); -extern int final_plus_romh_phi1_read(WORD addr, BYTE *value); -extern int final_plus_romh_phi2_read(WORD addr, BYTE *value); -extern int final_plus_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern int final_plus_snapshot_write_module(struct snapshot_s *s); -extern int final_plus_snapshot_read_module(struct snapshot_s *s); +void final_plus_freeze(void); +void final_plus_config_init(void); +void final_plus_config_setup(uint8_t *rawcart); +int final_plus_bin_attach(const char *filename, uint8_t *rawcart); +int final_plus_crt_attach(FILE *fd, uint8_t *rawcart); +void final_plus_detach(void); + +uint8_t final_plus_roml_read(uint16_t addr); +uint8_t final_plus_romh_read(uint16_t addr); +uint8_t final_plus_a000_bfff_read(uint16_t addr); +int final_plus_romh_phi1_read(uint16_t addr, uint8_t *value); +int final_plus_romh_phi2_read(uint16_t addr, uint8_t *value); +int final_plus_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +int final_plus_snapshot_write_module(struct snapshot_s *s); +int final_plus_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/formel64.c b/src/Emulators/vice/c64/cart/formel64.c index c3641d39..ce07ce3d 100644 --- a/src/Emulators/vice/c64/cart/formel64.c +++ b/src/Emulators/vice/c64/cart/formel64.c @@ -104,23 +104,25 @@ bit0 ? /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void formel64_io2_store(WORD addr, BYTE value); -static BYTE formel64_io2_read(WORD addr); -static BYTE formel64_io2_peek(WORD addr); +static void formel64_io2_store(uint16_t addr, uint8_t value); +static uint8_t formel64_io2_read(uint16_t addr); +static uint8_t formel64_io2_peek(uint16_t addr); static io_source_t formel64_io2_device = { - CARTRIDGE_NAME_FORMEL64, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - formel64_io2_store, - formel64_io2_read, - formel64_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_FORMEL64, - 0, - 0 + CARTRIDGE_NAME_FORMEL64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$dfc0-$dfc3, mirrors:$df00-$dfbf & $dfc4-$dfff */ + 1, /* read is always valid */ + formel64_io2_store, /* store function */ + NULL, /* NO poke function */ + formel64_io2_read, /* read function */ + formel64_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_FORMEL64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *formel64_io2_list_item = NULL; @@ -140,7 +142,7 @@ static int f64_enabled = 1; static mc6821_state my6821; #ifdef LOG_PORTA -static void f64_print_pa(BYTE data) +static void f64_print_pa(uint8_t data) { DBG(("6821 PA %02x ", data)); DBG(("[??? %02x] ", data & 0xff)); @@ -148,9 +150,9 @@ static void f64_print_pa(BYTE data) #endif #ifdef LOG_PORTB -static void f64_print_pb(BYTE data) +static void f64_print_pb(uint8_t data) { - BYTE page; + uint8_t page; page = ((data >> 1) & 3); @@ -168,12 +170,12 @@ static void f64_set_pa(mc6821_state *ctx) DBG(("\n")); #endif parallel_cable_cpu_pulse(DRIVE_PC_FORMEL64); - parallel_cable_cpu_write(DRIVE_PC_FORMEL64, (BYTE)ctx->dataA); + parallel_cable_cpu_write(DRIVE_PC_FORMEL64, (uint8_t)ctx->dataA); } -static BYTE f64_get_pa(mc6821_state *ctx) +static uint8_t f64_get_pa(mc6821_state *ctx) { - BYTE data = 0xff; + uint8_t data = 0xff; parallel_cable_cpu_write(DRIVE_PC_FORMEL64, 0xff); data = parallel_cable_cpu_read(DRIVE_PC_FORMEL64, data); @@ -199,9 +201,9 @@ static void f64_set_pb(mc6821_state *ctx) #endif } -static BYTE f64_get_pb(mc6821_state *ctx) +static uint8_t f64_get_pb(mc6821_state *ctx) { - BYTE data = 0; + uint8_t data = 0; return data; } @@ -209,7 +211,7 @@ static BYTE f64_get_pb(mc6821_state *ctx) * ****************************************************************************/ -static BYTE formel64_io2_read(WORD addr) +static uint8_t formel64_io2_read(uint16_t addr) { int port, reg; @@ -221,7 +223,7 @@ static BYTE formel64_io2_read(WORD addr) return mc6821core_read(&my6821, port /* rs1 */, reg /* rs0 */); } -static BYTE formel64_io2_peek(WORD addr) +static uint8_t formel64_io2_peek(uint16_t addr) { int port, reg; @@ -231,7 +233,7 @@ static BYTE formel64_io2_peek(WORD addr) return mc6821core_peek(&my6821, port /* rs1 */, reg /* rs0 */); } -static void formel64_io2_store(WORD addr, BYTE value) +static void formel64_io2_store(uint16_t addr, uint8_t value) { int port, reg; @@ -246,7 +248,7 @@ static void formel64_io2_store(WORD addr, BYTE value) ****************************************************************************/ /* ---------------------------------------------------------------------*/ -BYTE formel64_romh_read(WORD addr) +uint8_t formel64_romh_read(uint16_t addr) { if (f64_enabled) { return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -254,7 +256,7 @@ BYTE formel64_romh_read(WORD addr) return mem_read_without_ultimax(addr); } -BYTE formel64_romh_read_hirom(WORD addr) +uint8_t formel64_romh_read_hirom(uint16_t addr) { if (f64_enabled) { return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -262,17 +264,17 @@ BYTE formel64_romh_read_hirom(WORD addr) return mem_read_without_ultimax(addr); } -int formel64_romh_phi1_read(WORD addr, BYTE *value) +int formel64_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int formel64_romh_phi2_read(WORD addr, BYTE *value) +int formel64_romh_phi2_read(uint16_t addr, uint8_t *value) { return formel64_romh_phi1_read(addr, value); } -int formel64_peek_mem(export_t *export, WORD addr, BYTE *value) +int formel64_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0xe000) { *value = romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -297,7 +299,7 @@ void formel64_config_init(void) my6821.get_pb = f64_get_pb; romh_bank = 2; - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(CMODE_ULTIMAX | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_ULTIMAX | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ); } void formel64_reset(void) @@ -306,7 +308,7 @@ void formel64_reset(void) mc6821core_reset(&my6821); } -void formel64_config_setup(BYTE *rawcart) +void formel64_config_setup(uint8_t *rawcart) { memcpy(romh_banks, rawcart, 0x8000); } @@ -321,7 +323,7 @@ static int formel64_common_attach(void) return 0; } -int formel64_bin_attach(const char *filename, BYTE *rawcart) +int formel64_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -333,7 +335,7 @@ int formel64_bin_attach(const char *filename, BYTE *rawcart) load CRT */ -int formel64_crt_attach(FILE *fd, BYTE *rawcart) +int formel64_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -382,7 +384,7 @@ void formel64_detach(void) BYTE | CB2 state | CB2 line state */ -static char snap_module_name[] = "CARTF64"; +static const char snap_module_name[] = "CARTF64"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -397,7 +399,7 @@ int formel64_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)f64_enabled) < 0) + || (SMW_B(m, (uint8_t)f64_enabled) < 0) || (SMW_BA(m, romh_banks, 0x8000) < 0)) { snapshot_module_close(m); return -1; @@ -412,7 +414,7 @@ int formel64_snapshot_write_module(snapshot_t *s) int formel64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -422,7 +424,7 @@ int formel64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -439,7 +441,7 @@ int formel64_snapshot_read_module(snapshot_t *s) snapshot_module_close(m); - parallel_cable_cpu_undump(DRIVE_PC_FORMEL64, (BYTE)my6821.dataA); + parallel_cable_cpu_undump(DRIVE_PC_FORMEL64, (uint8_t)my6821.dataA); return formel64_common_attach(); diff --git a/src/Emulators/vice/c64/cart/formel64.h b/src/Emulators/vice/c64/cart/formel64.h index f75e75a2..5834633d 100644 --- a/src/Emulators/vice/c64/cart/formel64.h +++ b/src/Emulators/vice/c64/cart/formel64.h @@ -34,20 +34,20 @@ struct snapshot_s; -extern BYTE formel64_romh_read(WORD addr); -extern BYTE formel64_romh_read_hirom(WORD addr); -extern int formel64_romh_phi1_read(WORD addr, BYTE *value); -extern int formel64_romh_phi2_read(WORD addr, BYTE *value); -extern int formel64_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern void formel64_config_init(void); -extern void formel64_reset(void); -extern void formel64_config_setup(BYTE *rawcart); -extern int formel64_bin_attach(const char *filename, BYTE *rawcart); -extern int formel64_crt_attach(FILE *fd, BYTE *rawcart); -extern void formel64_detach(void); - -extern int formel64_snapshot_write_module(struct snapshot_s *s); -extern int formel64_snapshot_read_module(struct snapshot_s *s); +uint8_t formel64_romh_read(uint16_t addr); +uint8_t formel64_romh_read_hirom(uint16_t addr); +int formel64_romh_phi1_read(uint16_t addr, uint8_t *value); +int formel64_romh_phi2_read(uint16_t addr, uint8_t *value); +int formel64_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void formel64_config_init(void); +void formel64_reset(void); +void formel64_config_setup(uint8_t *rawcart); +int formel64_bin_attach(const char *filename, uint8_t *rawcart); +int formel64_crt_attach(FILE *fd, uint8_t *rawcart); +void formel64_detach(void); + +int formel64_snapshot_write_module(struct snapshot_s *s); +int formel64_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/freezeframe.c b/src/Emulators/vice/c64/cart/freezeframe.c index ddae4cd1..3a527662 100644 --- a/src/Emulators/vice/c64/cart/freezeframe.c +++ b/src/Emulators/vice/c64/cart/freezeframe.c @@ -81,7 +81,7 @@ static int freezeframe_rom_8000 = 0; static int freezeframe_rom_e000 = 0; -static BYTE freezeframe_io1_read(WORD addr) +static uint8_t freezeframe_io1_read(uint16_t addr) { DBG(("io1 r %04x\n", addr)); if (addr == 0) { @@ -92,17 +92,17 @@ static BYTE freezeframe_io1_read(WORD addr) return 0; /* invalid */ } -static BYTE freezeframe_io1_peek(WORD addr) +static uint8_t freezeframe_io1_peek(uint16_t addr) { return 0; /* invalid */ } -static void freezeframe_io1_store(WORD addr, BYTE value) +static void freezeframe_io1_store(uint16_t addr, uint8_t value) { - DBG(("io1 %04x %02x\n", addr, value)); + DBG(("io1 w %04x %02x\n", addr, value)); } -static BYTE freezeframe_io2_read(WORD addr) +static uint8_t freezeframe_io2_read(uint16_t addr) { DBG(("io2 r %04x\n", addr)); if (addr == 0) { @@ -114,14 +114,14 @@ static BYTE freezeframe_io2_read(WORD addr) return 0; /* invalid */ } -static BYTE freezeframe_io2_peek(WORD addr) +static uint8_t freezeframe_io2_peek(uint16_t addr) { return 0; /* invalid */ } -static void freezeframe_io2_store(WORD addr, BYTE value) +static void freezeframe_io2_store(uint16_t addr, uint8_t value) { - DBG(("io2 %04x %02x\n", addr, value)); + DBG(("io2 w %04x %02x\n", addr, value)); } static int freezeframe_dump(void) @@ -133,33 +133,37 @@ static int freezeframe_dump(void) } static io_source_t freezeframe_io1_device = { - CARTRIDGE_NAME_FREEZE_FRAME, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - freezeframe_io1_store, - freezeframe_io1_read, - freezeframe_io1_peek, - freezeframe_dump, - CARTRIDGE_FREEZE_FRAME, - 0, - 0 + CARTRIDGE_NAME_FREEZE_FRAME, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, reg:$de00, unknown mirrors:$de01-$deff */ + 0, /* read is never valid */ + freezeframe_io1_store, /* store function */ + NULL, /* NO poke function */ + freezeframe_io1_read, /* read function */ + freezeframe_io1_peek, /* peek function */ + freezeframe_dump, /* device state information dump function */ + CARTRIDGE_FREEZE_FRAME, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t freezeframe_io2_device = { - CARTRIDGE_NAME_FREEZE_FRAME, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - freezeframe_io2_store, - freezeframe_io2_read, - freezeframe_io2_peek, - freezeframe_dump, - CARTRIDGE_FREEZE_FRAME, - 0, - 0 + CARTRIDGE_NAME_FREEZE_FRAME, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, reg:$df00, unknown mirrors:$df01-$dfff */ + 0, /* read is never valid */ + freezeframe_io2_store, /* store function */ + NULL, /* NO poke function */ + freezeframe_io2_read, /* read function */ + freezeframe_io2_peek, /* peek function */ + freezeframe_dump, /* device state information dump function */ + CARTRIDGE_FREEZE_FRAME, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *freezeframe_io1_list_item = NULL; @@ -174,23 +178,23 @@ static const export_resource_t export_res = { void freezeframe_freeze(void) { DBG(("Freeze Frame: freeze\n")); - cart_config_changed_slotmain(2, 3, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); freezeframe_rom_8000 = 1; freezeframe_rom_e000 = 1; } void freezeframe_config_init(void) { - cart_config_changed_slotmain(2, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME, CMODE_READ); freezeframe_rom_8000 = 1; freezeframe_rom_e000 = 0; } -void freezeframe_config_setup(BYTE *rawcart) +void freezeframe_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, FREEZE_FRAME_CART_SIZE); memcpy(romh_banks, rawcart, FREEZE_FRAME_CART_SIZE); - cart_config_changed_slotmain(2, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME, CMODE_READ); freezeframe_rom_8000 = 1; freezeframe_rom_e000 = 0; } @@ -209,7 +213,7 @@ static int freezeframe_common_attach(void) return 0; } -int freezeframe_bin_attach(const char *filename, BYTE *rawcart) +int freezeframe_bin_attach(const char *filename, uint8_t *rawcart) { DBG(("Freeze Frame: bin attach '%s'\n", filename)); if (util_file_load(filename, rawcart, FREEZE_FRAME_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -219,7 +223,7 @@ int freezeframe_bin_attach(const char *filename, BYTE *rawcart) return freezeframe_common_attach(); } -int freezeframe_crt_attach(FILE *fd, BYTE *rawcart) +int freezeframe_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -258,7 +262,7 @@ void freezeframe_detach(void) ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTFREEZEF"; +static const char snap_module_name[] = "CARTFREEZEF"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -273,8 +277,8 @@ int freezeframe_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)freezeframe_rom_8000) < 0) - || (SMW_B(m, (BYTE)freezeframe_rom_e000) < 0) + || (SMW_B(m, (uint8_t)freezeframe_rom_8000) < 0) + || (SMW_B(m, (uint8_t)freezeframe_rom_e000) < 0) || (SMW_BA(m, roml_banks, FREEZE_FRAME_CART_SIZE) < 0)) { snapshot_module_close(m); return -1; @@ -285,7 +289,7 @@ int freezeframe_snapshot_write_module(snapshot_t *s) int freezeframe_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -295,13 +299,13 @@ int freezeframe_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (0 || SMR_B_INT(m, &freezeframe_rom_8000) < 0 || SMR_B_INT(m, &freezeframe_rom_e000) < 0) { diff --git a/src/Emulators/vice/c64/cart/freezeframe.h b/src/Emulators/vice/c64/cart/freezeframe.h index 5455fdab..7afb6edd 100644 --- a/src/Emulators/vice/c64/cart/freezeframe.h +++ b/src/Emulators/vice/c64/cart/freezeframe.h @@ -31,16 +31,16 @@ #include "vicetypes.h" -extern void freezeframe_config_init(void); -extern void freezeframe_config_setup(BYTE *rawcart); -extern int freezeframe_bin_attach(const char *filename, BYTE *rawcart); -extern int freezeframe_crt_attach(FILE *fd, BYTE *rawcart); -extern void freezeframe_detach(void); -extern void freezeframe_freeze(void); +void freezeframe_config_init(void); +void freezeframe_config_setup(uint8_t *rawcart); +int freezeframe_bin_attach(const char *filename, uint8_t *rawcart); +int freezeframe_crt_attach(FILE *fd, uint8_t *rawcart); +void freezeframe_detach(void); +void freezeframe_freeze(void); struct snapshot_s; -extern int freezeframe_snapshot_write_module(struct snapshot_s *s); -extern int freezeframe_snapshot_read_module(struct snapshot_s *s); +int freezeframe_snapshot_write_module(struct snapshot_s *s); +int freezeframe_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/freezeframe2.c b/src/Emulators/vice/c64/cart/freezeframe2.c new file mode 100644 index 00000000..30ee13e0 --- /dev/null +++ b/src/Emulators/vice/c64/cart/freezeframe2.c @@ -0,0 +1,352 @@ +/* + * freezeframe2.c - Cartridge handling, Freeze Frame MK2/MK3 cart. + * + * Written by + * Groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "freezeframe2.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* #define FF2DEBUG */ + +#ifdef FF2DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + FIXME: this implementation is based on vague guesses on how the hardware + really works. + + Evesham Micros "Freeze Frame MK2" and "Freeze Frame MK3 (v1)" + + - 2 Buttons (Freeze, Reset) + - 16k ROM + + - reading io1 (the software uses de00 only it seems) + - disables cartridge ROM + - in freeze mode switch to 8k mode + + - reading io2 (the software uses df00 only it seems) + - switches to 16k game mode + - ROM bank 0 is mapped to 8000 + - ROM bank 1 is mapped to A000 + + - reset + - enables 8K game mode + - ROM bank 0 is mapped to 8000 + + - freeze + - enables ultimax mode + - ROM bank 0 is mapped to 8000 + - ROM bank 0 is mapped to E000 +*/ + +#define FREEZE_FRAME_MK2_CART_SIZE (16 * 0x400) + +static int roml_toggle = 0; /* when set, bank 1 will be used for roml */ +static int freezemode = 0; +/* ---------------------------------------------------------------------*/ + +static uint8_t freezeframe2_io1_read(uint16_t addr) +{ + DBG(("io1 r %04x\n", addr)); + /* if (addr == 0) */ { + if (freezemode == 1) { + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME, CMODE_READ); + DBG(("Freeze Frame MK2: switch to 8k in freeze mode\n")); + freezemode = 0; + } else { + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + DBG(("Freeze Frame MK2: disabled\n")); + } + } + + return 0; /* invalid */ +} + +static uint8_t freezeframe2_io1_peek(uint16_t addr) +{ + return 0; /* invalid */ +} + +static void freezeframe2_io1_store(uint16_t addr, uint8_t value) +{ + DBG(("io1 w %04x %02x\n", addr, value)); +} + +static uint8_t freezeframe2_io2_read(uint16_t addr) +{ + DBG(("io2 r %04x\n", addr)); + /* if (addr == 0) */ { + roml_toggle = 1; + cart_config_changed_slotmain(CMODE_RAM, CMODE_16KGAME, CMODE_READ); + DBG(("Freeze Frame MK2: switching to 16k game mapping\n")); + } + return 0; /* invalid */ +} + +static uint8_t freezeframe2_io2_peek(uint16_t addr) +{ + return 0; /* invalid */ +} + +static void freezeframe2_io2_store(uint16_t addr, uint8_t value) +{ + DBG(("io2 w %04x %02x\n", addr, value)); +} + +static io_source_t freezeframe2_io1_device = { + CARTRIDGE_NAME_FREEZE_FRAME_MK2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + freezeframe2_io1_store, /* store function */ + NULL, /* NO poke function */ + freezeframe2_io1_read, /* read function */ + freezeframe2_io1_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_FREEZE_FRAME_MK2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t freezeframe2_io2_device = { + CARTRIDGE_NAME_FREEZE_FRAME_MK2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + freezeframe2_io2_store, /* store function */ + NULL, /* NO poke function */ + freezeframe2_io2_read, /* read function */ + freezeframe2_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_FREEZE_FRAME_MK2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *freezeframe2_io1_list_item = NULL; +static io_source_list_t *freezeframe2_io2_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_FREEZE_FRAME_MK2, 1, 1, &freezeframe2_io1_device, &freezeframe2_io2_device, CARTRIDGE_FREEZE_FRAME_MK2 +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t freezeframe2_roml_read(uint16_t addr) +{ + if (roml_toggle) { + return romh_banks[addr & 0x1fff]; + } + return roml_banks[addr & 0x1fff]; +} + +/* ---------------------------------------------------------------------*/ + +void freezeframe2_reset(void) +{ + roml_toggle = 0; + freezemode = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME, CMODE_READ); + DBG(("Freeze Frame MK2: reset\n")); +} + +void freezeframe2_freeze(void) +{ + DBG(("Freeze Frame MK2: freeze\n")); + roml_toggle = 1; + freezemode = 1; + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); +} + +void freezeframe2_config_init(void) +{ + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME, CMODE_READ); +} + +void freezeframe2_config_setup(uint8_t *rawcart) +{ + roml_toggle = 0; + memcpy(roml_banks, rawcart, 0x2000); + memcpy(romh_banks, &rawcart[0x2000], 0x2000); + cart_config_changed_slotmain(CMODE_RAM, CMODE_8KGAME | (0 << CMODE_BANK_SHIFT), CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int freezeframe2_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + freezeframe2_io1_list_item = io_source_register(&freezeframe2_io1_device); + freezeframe2_io2_list_item = io_source_register(&freezeframe2_io2_device); + + return 0; +} + +int freezeframe2_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("Freeze Frame MK2: bin attach '%s'\n", filename)); + if (util_file_load(filename, rawcart, FREEZE_FRAME_MK2_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return freezeframe2_common_attach(); +} + +/* + * offset sig type bank start size chunklen + * $000040 CHIP ROM #000 $8000 $4000 $4010 + * + */ +int freezeframe2_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + DBG(("ffmk2 attach: chip.size %04x\n", chip.size)); + /* first the new format */ + if (chip.size == 0x4000) { + if ((chip.bank > 1) || (chip.start != 0x8000)) { + return -1; + } + if (crt_read_chip(rawcart, (chip.bank << 14), &chip, fd)) { + return -1; + } + } else { + return -1; + } + return freezeframe2_common_attach(); +} + +void freezeframe2_detach(void) +{ + export_remove(&export_res); + io_source_unregister(freezeframe2_io1_list_item); + io_source_unregister(freezeframe2_io2_list_item); + freezeframe2_io1_list_item = NULL; + freezeframe2_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTFREEZEM snapshot module format: + + type | name | version | description + -------------------------------------------- + BYTE | ROML toggle | 0.0+ | ROML toggle flag + BYTE | freeze mode | 0.0+ | flag: are we in freeze mode + ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data + ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data + */ + +static const char snap_module_name[] = "CARTFFMK2"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int freezeframe2_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)roml_toggle) < 0 + || SMW_B(m, (uint8_t)freezemode) < 0 + || SMW_BA(m, roml_banks, 0x2000) < 0 + || SMW_BA(m, romh_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int freezeframe2_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B_INT(m, &roml_toggle) < 0 + || SMR_B_INT(m, &freezemode) < 0) { + goto fail; + } + + if (0 + || SMR_BA(m, roml_banks, 0x2000) < 0 + || SMR_BA(m, romh_banks, 0x2000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return freezeframe2_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/freezeframe2.h b/src/Emulators/vice/c64/cart/freezeframe2.h new file mode 100644 index 00000000..ab19c684 --- /dev/null +++ b/src/Emulators/vice/c64/cart/freezeframe2.h @@ -0,0 +1,49 @@ +/* + * freezeframe2.h - Cartridge handling, Freeze Frame MK2/MK3 cart. + * + * Written by + * Groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_FREEZEFRAME2_H +#define VICE_FREEZEFRAME2_H + +#include + +#include "vicetypes.h" + +void freezeframe2_config_init(void); +void freezeframe2_config_setup(uint8_t *rawcart); +int freezeframe2_bin_attach(const char *filename, uint8_t *rawcart); +int freezeframe2_crt_attach(FILE *fd, uint8_t *rawcart); +void freezeframe2_detach(void); +void freezeframe2_freeze(void); +void freezeframe2_reset(void); + +uint8_t freezeframe2_roml_read(uint16_t addr); + +struct snapshot_s; + +int freezeframe2_snapshot_write_module(struct snapshot_s *s); +int freezeframe2_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/freezemachine.c b/src/Emulators/vice/c64/cart/freezemachine.c index 36e8223c..9c21780a 100644 --- a/src/Emulators/vice/c64/cart/freezemachine.c +++ b/src/Emulators/vice/c64/cart/freezemachine.c @@ -53,15 +53,14 @@ /* FIXME: this implementation is based on vague guesses on how the hardware - really works. remaining problems are: - - fastloader fails + really works. - Evesham Micros "Freeze Frame MK4" + Evesham Micros "Freeze Frame MK3 v2" - 2 Buttons (Freeze, Reset) - 16k ROM - Evesham Micros "Freeze Machine" + Evesham Micros "Freeze Frame MK4 LAZER", "Freeze Machine" - 2 Buttons (Freeze, Reset) - 7474, 74163, 2 * 7400, 7402 @@ -96,28 +95,28 @@ static int allow_toggle; /* ---------------------------------------------------------------------*/ -static BYTE freezemachine_io1_read(WORD addr) +static uint8_t freezemachine_io1_read(uint16_t addr) { DBG(("io1 r %04x\n", addr)); /* if (addr == 0) */ { roml_toggle = 1; - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(CMODE_16KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_16KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); DBG(("Freeze Machine: switching to 16k game mapping\n")); } return 0; /* invalid */ } -static BYTE freezemachine_io1_peek(WORD addr) +static uint8_t freezemachine_io1_peek(uint16_t addr) { return 0; /* invalid */ } -static void freezemachine_io1_store(WORD addr, BYTE value) +static void freezemachine_io1_store(uint16_t addr, uint8_t value) { - DBG(("io1 %04x %02x\n", addr, value)); + DBG(("io1 w %04x %02x\n", addr, value)); } -static BYTE freezemachine_io2_read(WORD addr) +static uint8_t freezemachine_io2_read(uint16_t addr) { DBG(("io2 r %04x\n", addr)); /* if (addr == 0) */ { @@ -128,44 +127,48 @@ static BYTE freezemachine_io2_read(WORD addr) return 0; /* invalid */ } -static BYTE freezemachine_io2_peek(WORD addr) +static uint8_t freezemachine_io2_peek(uint16_t addr) { return 0; /* invalid */ } -static void freezemachine_io2_store(WORD addr, BYTE value) +static void freezemachine_io2_store(uint16_t addr, uint8_t value) { - DBG(("io2 %04x %02x\n", addr, value)); + DBG(("io2 w %04x %02x\n", addr, value)); } static io_source_t freezemachine_io1_device = { - CARTRIDGE_NAME_FREEZE_MACHINE, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - freezemachine_io1_store, - freezemachine_io1_read, - freezemachine_io1_peek, - NULL, /* TODO: dump */ - CARTRIDGE_FREEZE_MACHINE, - 0, - 0 + CARTRIDGE_NAME_FREEZE_MACHINE, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + freezemachine_io1_store, /* store function */ + NULL, /* NO poke function */ + freezemachine_io1_read, /* read function */ + freezemachine_io1_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_FREEZE_MACHINE, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t freezemachine_io2_device = { - CARTRIDGE_NAME_FREEZE_MACHINE, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - freezemachine_io2_store, - freezemachine_io2_read, - freezemachine_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_FREEZE_MACHINE, - 0, - 0 + CARTRIDGE_NAME_FREEZE_MACHINE, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + freezemachine_io2_store, /* store function */ + NULL, /* NO poke function */ + freezemachine_io2_read, /* read function */ + freezemachine_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_FREEZE_MACHINE, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *freezemachine_io1_list_item = NULL; @@ -177,7 +180,7 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -BYTE freezemachine_roml_read(WORD addr) +uint8_t freezemachine_roml_read(uint16_t addr) { if (roml_toggle) { return romh_banks[(addr & 0x1fff) | (rom_A14 << 13)]; @@ -193,7 +196,7 @@ void freezemachine_reset(void) rom_A14 ^= 1; /* select other 16k ROM bank on every other reset */ } roml_toggle = 0; - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(CMODE_8KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_8KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); DBG(("Freeze Machine: reset (%d)\n", rom_A14)); } @@ -201,15 +204,15 @@ void freezemachine_freeze(void) { DBG(("Freeze Machine: freeze\n")); roml_toggle = 1; - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(CMODE_ULTIMAX | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_ULTIMAX | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_RELEASE_FREEZE); } void freezemachine_config_init(void) { - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(CMODE_8KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_8KGAME | (rom_A14 << CMODE_BANK_SHIFT)), CMODE_READ); } -void freezemachine_config_setup(BYTE *rawcart) +void freezemachine_config_setup(uint8_t *rawcart) { rom_A14 = allow_toggle; /* the following first reset will turn it to 0 again */ roml_toggle = 0; @@ -234,7 +237,7 @@ static int freezemachine_common_attach(void) return 0; } -int freezemachine_bin_attach(const char *filename, BYTE *rawcart) +int freezemachine_bin_attach(const char *filename, uint8_t *rawcart) { DBG(("Freeze Machine: bin attach '%s'\n", filename)); allow_toggle = 1; @@ -250,7 +253,7 @@ int freezemachine_bin_attach(const char *filename, BYTE *rawcart) /* * (old) wrong formats: - * + * * cartconv produced this until 2011: * * offset sig type bank start size chunklen @@ -268,15 +271,16 @@ int freezemachine_bin_attach(const char *filename, BYTE *rawcart) * $006070 CHIP ROM #001 $a000 $2000 $2010 (32k ROMs only) * * (new) correct format (since 12/2015): - * + * * offset sig type bank start size chunklen * $000040 CHIP ROM #000 $8000 $4000 $4010 * $004050 CHIP ROM #001 $8000 $4000 $4010 (32k ROMs only) * */ -int freezemachine_crt_attach(FILE *fd, BYTE *rawcart) +int freezemachine_crt_attach(FILE *fd, uint8_t *rawcart) { - int i, pos, banks, chips; + int i, banks, chips; + size_t pos; crt_chip_header_t chip; /* find out how many banks and chips are in the file */ @@ -363,7 +367,7 @@ void freezemachine_detach(void) ARRAY | ROMH | 0.0+ | 16384 BYTES of ROMH data */ -static char snap_module_name[] = "CARTFREEZEM"; +static const char snap_module_name[] = "CARTFREEZEM"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -378,9 +382,9 @@ int freezemachine_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)rom_A14) < 0 - || SMW_B(m, (BYTE)roml_toggle) < 0 - || SMW_B(m, (BYTE)allow_toggle) < 0 + || SMW_B(m, (uint8_t)rom_A14) < 0 + || SMW_B(m, (uint8_t)roml_toggle) < 0 + || SMW_B(m, (uint8_t)allow_toggle) < 0 || SMW_BA(m, roml_banks, 0x4000) < 0 || SMW_BA(m, romh_banks, 0x4000) < 0) { snapshot_module_close(m); @@ -392,7 +396,7 @@ int freezemachine_snapshot_write_module(snapshot_t *s) int freezemachine_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -402,7 +406,7 @@ int freezemachine_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -414,7 +418,7 @@ int freezemachine_snapshot_read_module(snapshot_t *s) } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &allow_toggle) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/freezemachine.h b/src/Emulators/vice/c64/cart/freezemachine.h index 69f8c9b9..85379d92 100644 --- a/src/Emulators/vice/c64/cart/freezemachine.h +++ b/src/Emulators/vice/c64/cart/freezemachine.h @@ -31,19 +31,19 @@ #include "vicetypes.h" -extern void freezemachine_config_init(void); -extern void freezemachine_config_setup(BYTE *rawcart); -extern int freezemachine_bin_attach(const char *filename, BYTE *rawcart); -extern int freezemachine_crt_attach(FILE *fd, BYTE *rawcart); -extern void freezemachine_detach(void); -extern void freezemachine_freeze(void); -extern void freezemachine_reset(void); +void freezemachine_config_init(void); +void freezemachine_config_setup(uint8_t *rawcart); +int freezemachine_bin_attach(const char *filename, uint8_t *rawcart); +int freezemachine_crt_attach(FILE *fd, uint8_t *rawcart); +void freezemachine_detach(void); +void freezemachine_freeze(void); +void freezemachine_reset(void); -extern BYTE freezemachine_roml_read(WORD addr); +uint8_t freezemachine_roml_read(uint16_t addr); struct snapshot_s; -extern int freezemachine_snapshot_write_module(struct snapshot_s *s); -extern int freezemachine_snapshot_read_module(struct snapshot_s *s); +int freezemachine_snapshot_write_module(struct snapshot_s *s); +int freezemachine_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/funplay.c b/src/Emulators/vice/c64/cart/funplay.c index 384b6cb5..06d5031b 100644 --- a/src/Emulators/vice/c64/cart/funplay.c +++ b/src/Emulators/vice/c64/cart/funplay.c @@ -82,20 +82,19 @@ value, or if perhaps game/exrom can be controlled separately. Since both available ROM files work correctly with a standard 8k game - config, it is assumed that this config is actually used by the + config, it is assumed that this config is actually used by the hardware. FIXME: much of the above described behaviour is guesswork, it should get - confirmed (and fixed) by someone who owns the cart (and then this + confirmed (and fixed) by someone who owns the cart (and then this message can be removed) */ static int currbank = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void funplay_io1_store(WORD addr, BYTE value) +static void funplay_io1_store(uint16_t addr, uint8_t value) { - addr &= 0xff; regval = value; currbank = ((value >> 3) & 7) | ((value & 1) << 3); cart_romlbank_set_slotmain(currbank); @@ -116,7 +115,7 @@ static void funplay_io1_store(WORD addr, BYTE value) /* printf("FUNPLAY: addr: $de%02x value: $%02x bank: $%02x\n", addr, value, currbank); */ } -static BYTE funplay_io1_peek(WORD addr) +static uint8_t funplay_io1_peek(uint16_t addr) { return regval; } @@ -130,18 +129,20 @@ static int funplay_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t funplay_device = { - CARTRIDGE_NAME_FUNPLAY, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - funplay_io1_store, - NULL, - funplay_io1_peek, - funplay_dump, - CARTRIDGE_FUNPLAY, - 0, - 0 + CARTRIDGE_NAME_FUNPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + funplay_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + funplay_io1_peek, /* peek function */ + funplay_dump, /* device state information dump function */ + CARTRIDGE_FUNPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *funplay_list_item = NULL; @@ -155,15 +156,15 @@ static const export_resource_t export_res = { void funplay_config_init(void) { /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); - funplay_io1_store((WORD)0xde00, 0); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + funplay_io1_store((uint16_t)0xde00, 0); } -void funplay_config_setup(BYTE *rawcart) +void funplay_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 16); /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -176,7 +177,7 @@ static int funplay_common_attach(void) return 0; } -int funplay_bin_attach(const char *filename, BYTE *rawcart) +int funplay_bin_attach(const char *filename, uint8_t *rawcart) { /* in a binary the banks are linear as usual */ if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -185,7 +186,7 @@ int funplay_bin_attach(const char *filename, BYTE *rawcart) return funplay_common_attach(); } -int funplay_crt_attach(FILE *fd, BYTE *rawcart) +int funplay_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; unsigned int bank; @@ -229,7 +230,7 @@ void funplay_detach(void) Note: 0.0 is incompatible with 1.0+ snapshots. */ -static char snap_module_name[] = "CARTFUNPLAY"; +static const char snap_module_name[] = "CARTFUNPLAY"; #define SNAP_MAJOR 1 #define SNAP_MINOR 1 @@ -245,7 +246,7 @@ int funplay_snapshot_write_module(snapshot_t *s) if (0 || SMW_B(m, regval) < 0 - || SMW_B(m, (BYTE)currbank) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 || SMW_BA(m, roml_banks, 0x2000 * 16) < 0) { snapshot_module_close(m); return -1; @@ -256,7 +257,7 @@ int funplay_snapshot_write_module(snapshot_t *s) int funplay_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -266,19 +267,19 @@ int funplay_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* Only accept compatible snapshots */ - if (!SNAPVAL(vmajor, vminor, 1, 0)) { + if (snapshot_version_is_smaller(vmajor, vminor, 1, 0)) { snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); goto fail; } /* new in 1.1 */ - if (SNAPVAL(vmajor, vminor, 1, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 1, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/funplay.h b/src/Emulators/vice/c64/cart/funplay.h index c965f6af..de824252 100644 --- a/src/Emulators/vice/c64/cart/funplay.h +++ b/src/Emulators/vice/c64/cart/funplay.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void funplay_config_init(void); -extern void funplay_config_setup(BYTE *rawcart); -extern int funplay_bin_attach(const char *filename, BYTE *rawcart); -extern int funplay_crt_attach(FILE *fd, BYTE *rawcart); -extern void funplay_detach(void); +void funplay_config_init(void); +void funplay_config_setup(uint8_t *rawcart); +int funplay_bin_attach(const char *filename, uint8_t *rawcart); +int funplay_crt_attach(FILE *fd, uint8_t *rawcart); +void funplay_detach(void); struct snapshot_s; -extern int funplay_snapshot_write_module(struct snapshot_s *s); -extern int funplay_snapshot_read_module(struct snapshot_s *s); +int funplay_snapshot_write_module(struct snapshot_s *s); +int funplay_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/gamekiller.c b/src/Emulators/vice/c64/cart/gamekiller.c index c701e0e4..b6d9c7c6 100644 --- a/src/Emulators/vice/c64/cart/gamekiller.c +++ b/src/Emulators/vice/c64/cart/gamekiller.c @@ -69,7 +69,7 @@ static int cartridge_disable_flag; -static void gamekiller_io1_store(WORD addr, BYTE value) +static void gamekiller_io1_store(uint16_t addr, uint8_t value) { DBG(("io1 %04x %02x\n", addr, value)); cartridge_disable_flag++; @@ -79,7 +79,7 @@ static void gamekiller_io1_store(WORD addr, BYTE value) } } -static void gamekiller_io2_store(WORD addr, BYTE value) +static void gamekiller_io2_store(uint16_t addr, uint8_t value) { DBG(("io2 %04x %02x\n", addr, value)); cartridge_disable_flag++; @@ -89,39 +89,43 @@ static void gamekiller_io2_store(WORD addr, BYTE value) } } -static BYTE gamekiller_peek(WORD addr) +static uint8_t gamekiller_peek(uint16_t addr) { return 0; } static io_source_t gamekiller_io1_device = { - CARTRIDGE_NAME_GAME_KILLER, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - gamekiller_io1_store, - NULL, - gamekiller_peek, - NULL, /* TODO: dump */ - CARTRIDGE_GAME_KILLER, - 0, - 0 + CARTRIDGE_NAME_GAME_KILLER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid. reg is write only */ + gamekiller_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + gamekiller_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_GAME_KILLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t gamekiller_io2_device = { - CARTRIDGE_NAME_GAME_KILLER, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - gamekiller_io2_store, - NULL, - gamekiller_peek, - NULL, /* TODO: dump */ - CARTRIDGE_GAME_KILLER, - 0, - 0 + CARTRIDGE_NAME_GAME_KILLER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + gamekiller_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + gamekiller_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_GAME_KILLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *gamekiller_io1_list_item = NULL; @@ -133,7 +137,7 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -int gamekiller_peek_mem(export_t *export, WORD addr, BYTE *value) +int gamekiller_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (cartridge_disable_flag <= 1) { if (addr >= 0xe000) { @@ -147,20 +151,20 @@ int gamekiller_peek_mem(export_t *export, WORD addr, BYTE *value) void gamekiller_freeze(void) { DBG(("Game Killer freeze\n")); - cart_config_changed_slotmain(3, 3, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); cartridge_disable_flag = 0; } void gamekiller_config_init(void) { - cart_config_changed_slotmain(3, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); cartridge_disable_flag = 0; } -void gamekiller_config_setup(BYTE *rawcart) +void gamekiller_config_setup(uint8_t *rawcart) { memcpy(romh_banks, rawcart, GAME_KILLER_CART_SIZE); - cart_config_changed_slotmain(3, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); cartridge_disable_flag = 0; } @@ -178,7 +182,7 @@ static int gamekiller_common_attach(void) return 0; } -int gamekiller_bin_attach(const char *filename, BYTE *rawcart) +int gamekiller_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, GAME_KILLER_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -187,7 +191,7 @@ int gamekiller_bin_attach(const char *filename, BYTE *rawcart) return gamekiller_common_attach(); } -int gamekiller_crt_attach(FILE *fd, BYTE *rawcart) +int gamekiller_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -225,7 +229,7 @@ void gamekiller_detach(void) ARRAY | ROMH | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTGK"; +static const char snap_module_name[] = "CARTGK"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -240,7 +244,7 @@ int gamekiller_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)cartridge_disable_flag) < 0) + || (SMW_B(m, (uint8_t)cartridge_disable_flag) < 0) || (SMW_BA(m, romh_banks, GAME_KILLER_CART_SIZE) < 0)) { snapshot_module_close(m); return -1; @@ -251,7 +255,7 @@ int gamekiller_snapshot_write_module(snapshot_t *s) int gamekiller_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -261,7 +265,7 @@ int gamekiller_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/gamekiller.h b/src/Emulators/vice/c64/cart/gamekiller.h index ef5e6196..57d10aee 100644 --- a/src/Emulators/vice/c64/cart/gamekiller.h +++ b/src/Emulators/vice/c64/cart/gamekiller.h @@ -34,16 +34,16 @@ struct snapshot_s; -extern int gamekiller_peek_mem(export_t *export, WORD addr, BYTE *value); +int gamekiller_peek_mem(export_t *export, uint16_t addr, uint8_t *value); -extern void gamekiller_config_init(void); -extern void gamekiller_config_setup(BYTE *rawcart); -extern int gamekiller_bin_attach(const char *filename, BYTE *rawcart); -extern int gamekiller_crt_attach(FILE *fd, BYTE *rawcart); -extern void gamekiller_detach(void); -extern void gamekiller_freeze(void); +void gamekiller_config_init(void); +void gamekiller_config_setup(uint8_t *rawcart); +int gamekiller_bin_attach(const char *filename, uint8_t *rawcart); +int gamekiller_crt_attach(FILE *fd, uint8_t *rawcart); +void gamekiller_detach(void); +void gamekiller_freeze(void); -extern int gamekiller_snapshot_write_module(struct snapshot_s *s); -extern int gamekiller_snapshot_read_module(struct snapshot_s *s); +int gamekiller_snapshot_write_module(struct snapshot_s *s); +int gamekiller_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/georam.c b/src/Emulators/vice/c64/cart/georam.c index 878c6b4f..6a4e0e86 100644 --- a/src/Emulators/vice/c64/cart/georam.c +++ b/src/Emulators/vice/c64/cart/georam.c @@ -40,10 +40,10 @@ #include "machine.h" #include "mem.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "georam.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -72,9 +72,6 @@ * * RAM size | $dfff * ------------------ - * 64k | $00-$03 - * 128k | $00-$07 - * 256k | $00-$0f * 512k | $00-$1f * 1024k | $00-$3f * 2048k | $00-$7f @@ -105,13 +102,13 @@ #define GEORAM_REG_PAGE_HIGH 0xff /* GEORAM registers */ -static BYTE georam[2]; +static uint8_t georam[2]; /* GEORAM image. */ -static BYTE *georam_ram = NULL; +static uint8_t *georam_ram = NULL; static int old_georam_ram_size = 0; -static log_t georam_log = LOG_ERR; +static log_t georam_log = LOG_DEFAULT; static int georam_activate(void); static int georam_deactivate(void); @@ -122,7 +119,7 @@ static int georam_enabled = 0; /* Size of the GEORAM. */ static int georam_size = 0; -/* Size of the GEORAM in KB. */ +/* Size of the GEORAM in KiB. */ static int georam_size_kb = 0; /* Filename of the GEORAM image. */ @@ -136,40 +133,44 @@ static int georam_io_swap = 0; /* ---------------------------------------------------------------------*/ -static BYTE georam_io1_read(WORD addr); -static void georam_io1_store(WORD addr, BYTE byte); -static BYTE georam_io2_peek(WORD addr); -static void georam_io2_store(WORD addr, BYTE byte); +static uint8_t georam_io1_read(uint16_t addr); +static void georam_io1_store(uint16_t addr, uint8_t byte); +static uint8_t georam_io2_peek(uint16_t addr); +static void georam_io2_store(uint16_t addr, uint8_t byte); static int georam_dump(void); static io_source_t georam_io1_device = { - CARTRIDGE_NAME_GEORAM, - IO_DETACH_RESOURCE, - "GEORAM", - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - georam_io1_store, - georam_io1_read, - georam_io1_read, - georam_dump, - CARTRIDGE_GEORAM, - 0, - 0 + CARTRIDGE_NAME_GEORAM, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "GEORAM", /* resource to set to '0' */ + 0xde00, 0xdeff, 0xff, /* range for the device, range is different for vic20 */ + 1, /* read is always valid */ + georam_io1_store, /* store function */ + NULL, /* NO poke function */ + georam_io1_read, /* read function */ + georam_io1_read, /* peek function */ + georam_dump, /* device state information dump function */ + CARTRIDGE_GEORAM, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t georam_io2_device = { - CARTRIDGE_NAME_GEORAM, - IO_DETACH_RESOURCE, - "GEORAM", - 0xdf80, 0xdfff, 0x7f, - 0, - georam_io2_store, - NULL, - georam_io2_peek, - georam_dump, - CARTRIDGE_GEORAM, - 0, - 0 + CARTRIDGE_NAME_GEORAM, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "GEORAM", /* resource to set to '0' */ + 0xdf80, 0xdfff, 0x01, /* range for the device, regs:$dffe-$dfff, mirrors:$df80-$dffd, range is different for vic20 */ + 0, /* read is never valid, regs are write only */ + georam_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + georam_io2_peek, /* peek function */ + georam_dump, /* device state information dump function */ + CARTRIDGE_GEORAM, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *georam_io1_list_item = NULL; @@ -186,21 +187,21 @@ int georam_cart_enabled(void) return georam_enabled; } -static BYTE georam_io1_read(WORD addr) +static uint8_t georam_io1_read(uint16_t addr) { - BYTE retval; + uint8_t retval; retval = georam_ram[(georam[1] * 16384) + (georam[0] * 256) + addr]; return retval; } -static void georam_io1_store(WORD addr, BYTE byte) +static void georam_io1_store(uint16_t addr, uint8_t byte) { georam_ram[(georam[1] * 16384) + (georam[0] * 256) + addr] = byte; } -static BYTE georam_io2_peek(WORD addr) +static uint8_t georam_io2_peek(uint16_t addr) { if (addr < 2) { return georam[addr & 1]; @@ -208,7 +209,7 @@ static BYTE georam_io2_peek(WORD addr) return 0; } -static void georam_io2_store(WORD addr, BYTE byte) +static void georam_io2_store(uint16_t addr, uint8_t byte) { if ((addr & 1) == 1) { while (byte > ((georam_size_kb / 16) - 1)) { @@ -226,12 +227,37 @@ static void georam_io2_store(WORD addr, BYTE byte) static int georam_dump(void) { - mon_out("Size: %d Kb, Bank: %d, Window: %d\n", georam_size_kb, georam[1], georam[0]); + mon_out("Size: %d KiB, Bank: %d, Window: %d\n", georam_size_kb, georam[1], georam[0]); return 0; } /* ------------------------------------------------------------------------- */ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void georam_powerup(void) +{ + if ((georam_filename != NULL) && (*georam_filename != 0)) { + /* do not init ram if a file is used for ram content (like battery backup) */ + return; + } + if (georam_ram) { + ram_init_with_pattern(georam_ram, georam_size, &ramparam); + } +} + static int georam_activate(void) { if (!georam_size) { @@ -242,12 +268,14 @@ static int georam_activate(void) /* Clear newly allocated RAM. */ if (georam_size > old_georam_ram_size) { - memset(georam_ram, 0, (size_t)(georam_size - old_georam_ram_size)); + /* memset(georam_ram, 0, (size_t)(georam_size - old_georam_ram_size)); */ + ram_init_with_pattern(&georam_ram[old_georam_ram_size], + (unsigned int)(georam_size - old_georam_ram_size), &ramparam); } old_georam_ram_size = georam_size; - log_message(georam_log, "%dKB unit installed.", georam_size >> 10); + log_message(georam_log, "%dKiB unit installed.", georam_size >> 10); if (!util_check_null_string(georam_filename)) { if (util_file_load(georam_filename, georam_ram, (size_t)georam_size, UTIL_FILE_LOAD_RAW) < 0) { @@ -338,9 +366,7 @@ static int set_georam_size(int val, void *param) } switch (val) { - case 64: - case 128: - case 256: + /* sizes smaller than 512k never existed */ case 512: case 1024: case 2048: @@ -419,12 +445,13 @@ static const resource_string_t resources_string[] = { }; static const resource_int_t resources_int[] = { - { "GEORAM", 0, RES_EVENT_STRICT, (resource_value_t)0, - &georam_enabled, set_georam_enabled, NULL }, { "GEORAMsize", 512, RES_EVENT_NO, NULL, &georam_size_kb, set_georam_size, NULL }, { "GEORAMImageWrite", 0, RES_EVENT_NO, NULL, &georam_write_image, set_georam_image_write, NULL }, + /* CAUTION: the order matters here, enable must happen last */ + { "GEORAM", 0, RES_EVENT_STRICT, (resource_value_t)0, + &georam_enabled, set_georam_enabled, NULL }, RESOURCE_INT_LIST_END }; @@ -459,51 +486,35 @@ void georam_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-georam", SET_RESOURCE, 0, + { "-georam", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAM", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_GEORAM, - NULL, NULL }, - { "+georam", SET_RESOURCE, 0, + NULL, "Enable the GEO-RAM expansion unit" }, + { "+georam", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAM", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_GEORAM, - NULL, NULL }, - { "-georamsize", SET_RESOURCE, 1, + NULL, "Disable the GEO-RAM expansion unit" }, + { "-georamsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "GEORAMsize", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_SIZE_IN_KB, IDCLS_GEORAM_SIZE, - NULL, NULL }, - { "-georamimage", SET_RESOURCE, 1, + "", "Size of the GEORAM expansion unit" }, + { "-georamimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "GEORAMfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_GEORAM_NAME, - NULL, NULL }, - { "-georamimagerw", SET_RESOURCE, 0, + "", "Specify name of GEORAM image" }, + { "-georamimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAMImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_GEORAM_IMAGE, - NULL, NULL }, - { "+georamimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to GEORAM image" }, + { "+georamimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAMImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_GEORAM_IMAGE, - NULL, NULL }, + NULL, "Do not write to GEORAM image" }, CMDLINE_LIST_END }; static const cmdline_option_t cmdline_mascuerade_options[] = { - { "-georamioswap", SET_RESOURCE, 0, + { "-georamioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAMIOSwap", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_SWAP_CART_IO, - NULL, NULL }, - { "+georamioswap", SET_RESOURCE, 0, + NULL, "Swap io mapping (map cart I/O-1 to VIC20 I/O-3 and cart I/O-2 to VIC20 I/O-2)" }, + { "+georamioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GEORAMIOSwap", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DONT_SWAP_CART_IO, - NULL, NULL }, + NULL, "Don't swap io mapping (map cart I/O-1 to VIC20 I/O-2 and cart I/O-2 to VIC20 I/O-3)" }, CMDLINE_LIST_END }; @@ -549,26 +560,37 @@ int georam_enable(void) return 0; } -void georam_config_setup(BYTE *rawcart) + +int georam_disable(void) +{ + return resources_set_int("GEORAM", 0); +} + + +void georam_config_setup(uint8_t *rawcart) { if (georam_size > 0) { memcpy(georam_ram, rawcart, georam_size); } } -int georam_bin_attach(const char *filename, BYTE *rawcart) +int georam_bin_attach(const char *filename, uint8_t *rawcart) { FILE *fd; - int size; + off_t size; fd = fopen(filename, MODE_READ); if (fd == NULL) { return -1; } - size = util_file_length(fd); + size = archdep_file_size(fd); + if (size < 0) { + fclose(fd); + return -1; + } fclose(fd); - if (set_georam_size(size / 1024, NULL) < 0) { + if (set_georam_size((uint32_t)(size / 1024), NULL) < 0) { return -1; } @@ -576,7 +598,7 @@ int georam_bin_attach(const char *filename, BYTE *rawcart) return -1; } - if (util_file_load(filename, rawcart, size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, (size_t)size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } @@ -612,12 +634,12 @@ int georam_flush_image(void) type | name | version | description --------------------------------------- BYTE | io swap | 0.1 | VIC20 I/O swap flag - DWORD | size | 0.0+ | size in KB + DWORD | size | 0.0+ | size in KiB ARRAY | regs | 0.0+ | 2 BYTES of register data ARRAY | RAM | 0.0+ | 65536, 131072, 262144, 524288, 1048576, 2097152 or 4194304 BYTES of RAM data */ -static char snap_module_name[] = "GEORAM"; +static const char snap_module_name[] = "GEORAM"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -632,7 +654,7 @@ int georam_write_snapshot_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)georam_io_swap) < 0 + || SMW_B(m, (uint8_t)georam_io_swap) < 0 || SMW_DW(m, (georam_size >> 10)) < 0 || SMW_BA(m, georam, sizeof(georam)) < 0 || SMW_BA(m, georam_ram, georam_size) < 0) { @@ -645,9 +667,9 @@ int georam_write_snapshot_module(snapshot_t *s) int georam_read_snapshot_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; - DWORD size; + uint32_t size; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -656,13 +678,13 @@ int georam_read_snapshot_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &georam_io_swap) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/georam.h b/src/Emulators/vice/c64/cart/georam.h index cd3df851..d0380c9e 100644 --- a/src/Emulators/vice/c64/cart/georam.h +++ b/src/Emulators/vice/c64/cart/georam.h @@ -31,24 +31,26 @@ struct snapshot_s; -extern void georam_init(void); -extern int georam_resources_init(void); -extern void georam_resources_shutdown(void); -extern int georam_cmdline_options_init(void); - -extern void georam_reset(void); -extern void georam_detach(void); -extern int georam_enable(void); - -extern int georam_read_snapshot_module(struct snapshot_s *s); -extern int georam_write_snapshot_module(struct snapshot_s *s); - -extern int georam_cart_enabled(void); -extern void georam_config_setup(BYTE *rawcart); - -extern const char *georam_get_file_name(void); -extern int georam_bin_attach(const char *filename, BYTE *rawcart); -extern int georam_bin_save(const char *filename); -extern int georam_flush_image(void); +void georam_init(void); +int georam_resources_init(void); +void georam_resources_shutdown(void); +int georam_cmdline_options_init(void); + +void georam_reset(void); +void georam_detach(void); +int georam_enable(void); +int georam_disable(void); +void georam_powerup(void); + +int georam_read_snapshot_module(struct snapshot_s *s); +int georam_write_snapshot_module(struct snapshot_s *s); + +int georam_cart_enabled(void); +void georam_config_setup(uint8_t *rawcart); + +const char *georam_get_file_name(void); +int georam_bin_attach(const char *filename, uint8_t *rawcart); +int georam_bin_save(const char *filename); +int georam_flush_image(void); #endif diff --git a/src/Emulators/vice/c64/cart/gmod2.c b/src/Emulators/vice/c64/cart/gmod2.c index d721a18a..3ae1886c 100644 --- a/src/Emulators/vice/c64/cart/gmod2.c +++ b/src/Emulators/vice/c64/cart/gmod2.c @@ -46,7 +46,6 @@ #include "monitor.h" #include "resources.h" #include "m93c86.h" -#include "translate.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" @@ -107,25 +106,28 @@ static const char STRING_GMOD2[] = CARTRIDGE_NAME_GMOD2; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE gmod2_io1_read(WORD addr); -static BYTE gmod2_io1_peek(WORD addr); -static void gmod2_io1_store(WORD addr, BYTE value); +static uint8_t gmod2_io1_read(uint16_t addr); +static uint8_t gmod2_io1_peek(uint16_t addr); +static void gmod2_io1_store(uint16_t addr, uint8_t value); static int gmod2_dump(void); static io_source_t gmod2_io1_device = { - CARTRIDGE_NAME_GMOD2, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - gmod2_io1_store, - gmod2_io1_read, - gmod2_io1_peek, - gmod2_dump, - CARTRIDGE_GMOD2, - 1, - 0 + CARTRIDGE_NAME_GMOD2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read validity is determined by the device upon a read */ + gmod2_io1_store, /* store function */ + NULL, /* NO poke function */ + gmod2_io1_read, /* read function */ + gmod2_io1_peek, /* peek function */ + gmod2_dump, /* device state information dump function */ + CARTRIDGE_GMOD2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; + static io_source_list_t *gmod2_io1_list_item = NULL; static const export_resource_t export_res = { @@ -134,25 +136,24 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -BYTE gmod2_io1_read(WORD addr) +uint8_t gmod2_io1_read(uint16_t addr) { gmod2_io1_device.io_source_valid = 0; - /* DBG(("io1 r %04x (cs:%d)\n", addr, eeprom_cs)); */ - gmod2_io1_device.io_source_valid = 1; if (eeprom_cs) { + gmod2_io1_device.io_source_valid = 1; return (m93c86_read_data() << 7) | (vicii_read_phi1() & 0x7f); } - return (vicii_read_phi1() & 0xff); + return 0; } -BYTE gmod2_io1_peek(WORD addr) +uint8_t gmod2_io1_peek(uint16_t addr) { return (m93c86_read_data() << 7); } -void gmod2_io1_store(WORD addr, BYTE value) +void gmod2_io1_store(uint16_t addr, uint8_t value) { int mode = CMODE_WRITE; @@ -170,22 +171,25 @@ void gmod2_io1_store(WORD addr, BYTE value) eeprom_cs = (value >> 6) & 1; eeprom_data = (value >> 4) & 1; eeprom_clock = (value >> 5) & 1; - m93c86_write_select((BYTE)eeprom_cs); + m93c86_write_select((uint8_t)eeprom_cs); if (eeprom_cs) { - m93c86_write_data((BYTE)(eeprom_data)); - m93c86_write_clock((BYTE)(eeprom_clock)); + m93c86_write_data((uint8_t)(eeprom_data)); + m93c86_write_clock((uint8_t)(eeprom_clock)); } - cart_config_changed_slotmain(CMODE_8KGAME, (BYTE)(gmod2_cmode | (gmod2_bank << CMODE_BANK_SHIFT)), mode); + cart_config_changed_slotmain(CMODE_8KGAME, (uint8_t)(gmod2_cmode | (gmod2_bank << CMODE_BANK_SHIFT)), mode); } /* ---------------------------------------------------------------------*/ -BYTE gmod2_roml_read(WORD addr) +uint8_t gmod2_roml_read(uint16_t addr) { - return flash040core_read(flashrom_state, (addr & 0x1fff) + (roml_bank << 13)); + if (gmod2_cmode == CMODE_8KGAME) { + return flash040core_read(flashrom_state, (addr & 0x1fff) + (roml_bank << 13)); + } + return ram_read(addr); } -void gmod2_romh_store(WORD addr, BYTE value) +void gmod2_romh_store(uint16_t addr, uint8_t value) { flash040core_store(flashrom_state, (addr & 0x1fff) + (roml_bank << 13), value); if (flashrom_state->flash_state != FLASH040_STATE_READ) { @@ -193,7 +197,7 @@ void gmod2_romh_store(WORD addr, BYTE value) } } -int gmod2_peek_mem(export_t *export, WORD addr, BYTE *value) +int gmod2_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0x8000 && addr <= 0x9fff) { *value = gmod2_roml_read(addr); @@ -202,19 +206,10 @@ int gmod2_peek_mem(export_t *export, WORD addr, BYTE *value) return CART_READ_THROUGH; } -void gmod2_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void gmod2_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { -#if 0 - if (flashrom_state && flashrom_state->flash_data) { + if (flashrom_state && flashrom_state->flash_data && gmod2_cmode == CMODE_8KGAME) { switch (addr & 0xe000) { - case 0xe000: - if (flashrom_state->flash_state == FLASH040_STATE_READ) { - *base = flashrom_state->flash_data + (roml_bank << 13) - 0xe000; - *start = 0xe000; - *limit = 0xfffd; - return; - } - break; case 0x8000: if (flashrom_state->flash_state == FLASH040_STATE_READ) { *base = flashrom_state->flash_data + (roml_bank << 13) - 0x8000; @@ -227,7 +222,6 @@ void gmod2_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) break; } } -#endif *base = NULL; *start = 0; *limit = 0; @@ -238,7 +232,7 @@ void gmod2_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) static int gmod2_dump(void) { /* FIXME: incomplete */ - mon_out("GAME/EXROM status: %s%s\n", + mon_out("GAME/EXROM status: %s%s\n", cart_config_string(gmod2_cmode), (gmod2_cmode == CMODE_ULTIMAX) ? " (Flash mode)" : ""); mon_out("ROM bank: %d\n", gmod2_bank); @@ -252,18 +246,18 @@ static int gmod2_dump(void) void gmod2_config_init(void) { gmod2_cmode = CMODE_8KGAME; - cart_config_changed_slotmain((BYTE)gmod2_cmode, (BYTE)gmod2_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)gmod2_cmode, (uint8_t)gmod2_cmode, CMODE_READ); eeprom_cs = 0; - m93c86_write_select((BYTE)eeprom_cs); + m93c86_write_select((uint8_t)eeprom_cs); flash040core_reset(flashrom_state); } void gmod2_reset(void) { gmod2_cmode = CMODE_8KGAME; - cart_config_changed_slotmain((BYTE)gmod2_cmode, (BYTE)gmod2_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)gmod2_cmode, (uint8_t)gmod2_cmode, CMODE_READ); eeprom_cs = 0; - m93c86_write_select((BYTE)eeprom_cs); + m93c86_write_select((uint8_t)eeprom_cs); /* on the real hardware pressing reset would NOT reset the flash statemachine, only a powercycle would help. we do it here anyway :) @@ -271,10 +265,10 @@ void gmod2_reset(void) flash040core_reset(flashrom_state); } -void gmod2_config_setup(BYTE *rawcart) +void gmod2_config_setup(uint8_t *rawcart) { gmod2_cmode = CMODE_8KGAME; - cart_config_changed_slotmain((BYTE)gmod2_cmode, (BYTE)gmod2_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)gmod2_cmode, (uint8_t)gmod2_cmode, CMODE_READ); flashrom_state = lib_malloc(sizeof(flash040_context_t)); flash040core_init(flashrom_state, maincpu_alarm_context, FLASH040_TYPE_NORMAL, roml_banks); @@ -307,6 +301,7 @@ static int set_gmod2_eeprom_filename(const char *name, void *param) static int set_gmod2_eeprom_rw(int val, void* param) { gmod2_eeprom_rw = val ? 1 : 0; + m93c86_set_image_rw(gmod2_eeprom_rw); return 0; } @@ -348,31 +343,21 @@ void gmod2_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-gmod2eepromimage", SET_RESOURCE, 1, + { "-gmod2eepromimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "GMod2EEPROMImage", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_P_FILE, IDCLS_SELECT_GMOD2_EEPROM_IMAGE, - NULL, NULL }, - { "-gmod2eepromrw", SET_RESOURCE, 0, + "", "Specify GMod2 EEPROM image filename" }, + { "-gmod2eepromrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GMod2EEPROMRW", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_GMOD2_EEPROM_WRITE_ENABLE, - NULL, NULL }, - { "+gmod2eepromrw", SET_RESOURCE, 0, + NULL, "Enable writes to GMod2 EEPROM image" }, + { "+gmod2eepromrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GMod2EEPROMRW", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_GMOD2_EEPROM_WRITE_DISABLE, - NULL, NULL }, - { "-gmod2flashwrite", SET_RESOURCE, 0, + NULL, "Disable writes to GMod2 EEPROM image" }, + { "-gmod2flashwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GMod2FlashWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SAVE_GMOD2_ROM_AT_EXIT, - NULL, NULL }, - { "+gmod2flashwrite", SET_RESOURCE, 0, + NULL, "Enable saving of the GMod2 ROM at exit" }, + { "+gmod2flashwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "GMod2FlashWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SAVE_GMOD2_ROM_AT_EXIT, - NULL, NULL }, + NULL, "Disable saving of the GMod2 ROM at exit" }, CMDLINE_LIST_END }; @@ -395,7 +380,7 @@ static int gmod2_common_attach(void) return 0; } -int gmod2_bin_attach(const char *filename, BYTE *rawcart) +int gmod2_bin_attach(const char *filename, uint8_t *rawcart) { gmod2_filetype = 0; gmod2_filename = NULL; @@ -405,11 +390,11 @@ int gmod2_bin_attach(const char *filename, BYTE *rawcart) } gmod2_filetype = CARTRIDGE_FILETYPE_BIN; - gmod2_filename = lib_stralloc(filename); + gmod2_filename = lib_strdup(filename); return gmod2_common_attach(); } -int gmod2_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int gmod2_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; int i; @@ -434,7 +419,7 @@ int gmod2_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) } gmod2_filetype = CARTRIDGE_FILETYPE_CRT; - gmod2_filename = lib_stralloc(filename); + gmod2_filename = lib_strdup(filename); return gmod2_common_attach(); } @@ -467,7 +452,7 @@ int gmod2_crt_save(const char *filename) { FILE *fd; crt_chip_header_t chip; - BYTE *data; + uint8_t *data; int i; fd = crt_create(filename, CARTRIDGE_GMOD2, 1, 0, STRING_GMOD2); @@ -480,7 +465,7 @@ int gmod2_crt_save(const char *filename) chip.size = 0x2000; chip.start = 0x8000; - data = &roml_banks[0x10000]; + data = roml_banks; for (i = 0; i < 64; i++) { chip.bank = i; /* bank */ @@ -506,6 +491,39 @@ int gmod2_flush_image(void) return -1; } +int gmod2_can_save_eeprom(void) +{ + return 1; +} + +int gmod2_can_flush_eeprom(void) +{ + if ((gmod2_eeprom_filename != NULL) && (*gmod2_eeprom_filename != 0)) { + return 1; + } + return 0; +} + +/** \brief Save a copy of the GMod2 EEPROM image to a file + * + * \param[in] filename filename for EEPROM image copy + * + * \return 0 on success, -1 on failre + */ +int gmod2_eeprom_save(const char *filename) +{ + return m93c86_save_image(filename); +} + +/** \brief FLush current contents of the GMod2 EEPROM to file + * + * \return 0 on success, -1 on failure + */ +int gmod2_flush_eeprom(void) +{ + return m93c86_flush_image(); +} + void gmod2_detach(void) { if (gmod2_flash_write && flashrom_state->flash_dirty) { @@ -525,12 +543,13 @@ void gmod2_detach(void) gmod2_enabled = 0; } + /* ---------------------------------------------------------------------*/ -static char snap_module_name[] = "CARTGMOD2"; -static char flash_snap_module_name[] = "FLASH040GMOD2"; +static const char snap_module_name[] = "CARTGMOD2"; +static const char flash_snap_module_name[] = "FLASH040GMOD2"; #define SNAP_MAJOR 0 -#define SNAP_MINOR 1 +#define SNAP_MINOR 2 int gmod2_snapshot_write_module(snapshot_t *s) { @@ -543,20 +562,25 @@ int gmod2_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)gmod2_cmode) < 0 - || SMW_B(m, (BYTE)gmod2_bank) < 0) { + || SMW_B(m, (uint8_t)gmod2_cmode) < 0 + || SMW_B(m, (uint8_t)gmod2_bank) < 0 + || SMW_BA(m, flashrom_state->flash_data, GMOD2_FLASH_SIZE) < 0) { snapshot_module_close(m); return -1; } snapshot_module_close(m); + if (m93c86_snapshot_write_module(s) < 0) { + return -1; + } + return flash040core_snapshot_write_module(s, flashrom_state, flash_snap_module_name); } int gmod2_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -565,20 +589,31 @@ int gmod2_snapshot_read_module(snapshot_t *s) return -1; } - /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + goto fail; + } + if (0 || SMR_B_INT(m, &gmod2_cmode) < 0 - || SMR_B_INT(m, &gmod2_bank) < 0) { + || SMR_B_INT(m, &gmod2_bank) < 0 + || SMR_BA(m, roml_banks, GMOD2_FLASH_SIZE) < 0) { goto fail; } snapshot_module_close(m); + if (m93c86_snapshot_read_module(s) < 0) { + return -1; + } + flashrom_state = lib_malloc(sizeof(flash040_context_t)); flash040core_init(flashrom_state, maincpu_alarm_context, FLASH040_TYPE_NORMAL, roml_banks); diff --git a/src/Emulators/vice/c64/cart/gmod2.h b/src/Emulators/vice/c64/cart/gmod2.h index ef622cf0..d3dab4df 100644 --- a/src/Emulators/vice/c64/cart/gmod2.h +++ b/src/Emulators/vice/c64/cart/gmod2.h @@ -23,7 +23,7 @@ * 02111-1307 USA. * */ - + #ifndef CARTRIDGE_INCLUDE_PRIVATE_API #ifndef CARTRIDGE_INCLUDE_PUBLIC_API #error "do not include this header directly, use c64cart.h instead." @@ -39,27 +39,32 @@ struct snapshot_s; -extern BYTE gmod2_roml_read(WORD addr); -extern void gmod2_romh_store(WORD addr, BYTE value); +uint8_t gmod2_roml_read(uint16_t addr); +void gmod2_romh_store(uint16_t addr, uint8_t value); + +int gmod2_peek_mem(export_t *export, uint16_t addr, uint8_t *value); +void gmod2_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern int gmod2_peek_mem(export_t *export, WORD addr, BYTE *value); -extern void gmod2_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +void gmod2_config_init(void); +void gmod2_reset(void); +void gmod2_config_setup(uint8_t *rawcart); +int gmod2_bin_attach(const char *filename, uint8_t *rawcart); +int gmod2_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int gmod2_bin_save(const char *filename); +int gmod2_crt_save(const char *filename); +int gmod2_flush_image(void); +void gmod2_detach(void); -extern void gmod2_config_init(void); -extern void gmod2_reset(void); -extern void gmod2_config_setup(BYTE *rawcart); -extern int gmod2_bin_attach(const char *filename, BYTE *rawcart); -extern int gmod2_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern int gmod2_bin_save(const char *filename); -extern int gmod2_crt_save(const char *filename); -extern int gmod2_flush_image(void); -extern void gmod2_detach(void); +int gmod2_eeprom_save(const char *filename); +int gmod2_flush_eeprom(void); +int gmod2_can_flush_eeprom(void); +int gmod2_can_save_eeprom(void); -extern int gmod2_cmdline_options_init(void); -extern int gmod2_resources_init(void); -extern void gmod2_resources_shutdown(void); +int gmod2_cmdline_options_init(void); +int gmod2_resources_init(void); +void gmod2_resources_shutdown(void); -extern int gmod2_snapshot_write_module(struct snapshot_s *s); -extern int gmod2_snapshot_read_module(struct snapshot_s *s); +int gmod2_snapshot_write_module(struct snapshot_s *s); +int gmod2_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/gmod3.c b/src/Emulators/vice/c64/cart/gmod3.c new file mode 100644 index 00000000..1993daed --- /dev/null +++ b/src/Emulators/vice/c64/cart/gmod3.c @@ -0,0 +1,664 @@ +/* + * gmod3.c - Cartridge handling, GMod3 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "c64cart.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64pla.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "export.h" +#include "lib.h" +#include "maincpu.h" +#include "monitor.h" +#include "resources.h" +#include "spi-flash.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "vicii-phi1.h" + +#define CARTRIDGE_INCLUDE_PRIVATE_API +#include "gmod3.h" +#undef CARTRIDGE_INCLUDE_PRIVATE_API + +/* + GMod3 (Individual Computers) + + 2/4/8/16Mb serial Flash + + see http://wiki.icomp.de/wiki/GMod3 + + IO1 + + on write: + + $DE00 Bank 0- 255 all versions + $DE01 Bank 256- 511 4MB and higher versions only + $DE02 Bank 512- 767 8MB and higher versions only + $DE03 Bank 768-1023 8MB and higher versions only + $DE04 Bank 1024-1279 16MB version only + $DE05 Bank 1280-1535 16MB version only + $DE06 Bank 1536-1791 16MB version only + $DE07 Bank 1792-2047 16MB version only + + the upper 3 bits of the bank are determined from the address, ie A0-A2 + + $DE08 bit7 1: bitbang mode enabled + bit6 exrom + bit5 hw vector replacing enabled + + on read: + + $DE00...$DE07 bit 0-7 - lower 8 bits of the current bank + $DE08...$DE0F bit 0,1,2 - upper 3 bits of the current bank + + if bitbang mode is enabled: + + on write: + + $DE00 bit6 Flash CS + bit5 Flash clock + bit4 Flash Din + + on read: + + $DExx bit7 Flash Dout +*/ + +/* #define DEBUGGMOD3 */ + +#ifdef DEBUGGMOD3 +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +#define GMOD3_2MB_FLASH_SIZE (2*1024*1024) +#define GMOD3_4MB_FLASH_SIZE (4*1024*1024) +#define GMOD3_8MB_FLASH_SIZE (8*1024*1024) +#define GMOD3_16MB_FLASH_SIZE (16*1024*1024) + +static uint8_t *gmod3_rom = NULL; +static uint32_t gmod3_flashsize = 0; + +static int gmod3_enabled = 0; + +static int gmod3_bitbang_enabled = 0; +static int gmod3_vectors_enabled = 0; + +/* current GAME/EXROM mode */ +static int gmod3_cmode = CMODE_8KGAME; + +/* current bank */ +static int gmod3_bank = 0; + +static char *gmod3_filename = NULL; +static int gmod3_filetype = 0; + +static char *gmod3_flash_filename = NULL; +static int gmod3_flash_write = 1; + +static int eeprom_cs = 1; /* active low */ +static int eeprom_data_in = 0; +static int eeprom_data_out = 0; +static int eeprom_clock = 0; + +static const char STRING_GMOD3[] = CARTRIDGE_NAME_GMOD3; + +/* ---------------------------------------------------------------------*/ + +/* some prototypes are needed */ +static uint8_t gmod3_io1_read(uint16_t addr); +static uint8_t gmod3_io1_peek(uint16_t addr); +static void gmod3_io1_store(uint16_t addr, uint8_t value); +static int gmod3_dump(void); + +static io_source_t gmod3_io1_device = { + CARTRIDGE_NAME_GMOD3, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$de01-$deff */ + 0, /* read validity is determined by the device upon a read */ + gmod3_io1_store, /* store function */ + NULL, /* NO poke function */ + gmod3_io1_read, /* read function */ + gmod3_io1_peek, /* peek function */ + gmod3_dump, /* device state information dump function */ + CARTRIDGE_GMOD3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *gmod3_io1_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_GMOD3, 1, 1, &gmod3_io1_device, NULL, CARTRIDGE_GMOD3 +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t gmod3_io1_read(uint16_t addr) +{ + gmod3_io1_device.io_source_valid = 0; + /* DBG(("io1 r %04x (cs:%d)\n", addr, eeprom_cs)); */ + + if (gmod3_bitbang_enabled) { + if (eeprom_cs == 0) { /* active low */ + gmod3_io1_device.io_source_valid = 1; + eeprom_data_out = spi_flash_read_data() << 7; + return eeprom_data_out; + } + } else { + if (/*(addr >= 0x00) &&*/ (addr <= 0x07)) { + gmod3_io1_device.io_source_valid = 1; + return gmod3_bank & 0xff; + } else if ((addr >= 0x08) && (addr <= 0x0f)) { + gmod3_io1_device.io_source_valid = 1; + return (gmod3_bank & 0x0700) >> 8; + } + } + return 0; /* FIXME */ +} + +uint8_t gmod3_io1_peek(uint16_t addr) +{ + if (gmod3_bitbang_enabled) { + if (eeprom_cs == 0) { /* active low */ + return eeprom_data_out; + } + } else { + if (/*(addr >= 0x00) &&*/ (addr <= 0x07)) { + return gmod3_bank & 0xff; + } else if ((addr >= 0x08) && (addr <= 0x0f)) { + return (gmod3_bank & 0x0700) >> 8; + } + } + return 0; +} + +void gmod3_io1_store(uint16_t addr, uint8_t value) +{ + int mode = CMODE_WRITE; + + DBG(("io1 w %04x %02x\n", addr, value)); + + addr &= 0xff; + + /* banking */ + if (/*(addr >= 0x00) &&*/ (addr <= 0x07)) { + if (gmod3_bitbang_enabled) { + eeprom_cs = ((value >> 6) & 1); /* active low */ + eeprom_clock = (value >> 5) & 1; + eeprom_data_in = (value >> 4) & 1; + + DBG(("io1 w %04x %02x (cs:%d data:%d clock:%d)\n", + addr, value, eeprom_cs, eeprom_data_in, eeprom_clock)); + } else { + gmod3_bank = value + ((addr & 0x07) << 8); + DBG(("io1 w %04x %02x (bank: %d)\n", + addr, value, gmod3_bank)); + } + } else if (addr == 0x08) { + gmod3_bitbang_enabled = (value >> 7) & 1; + gmod3_vectors_enabled = (value >> 5) & 1; + if ((value & 0x40) == 0x00) { + if (gmod3_vectors_enabled) { + gmod3_cmode = CMODE_ULTIMAX; + } else { + gmod3_cmode = CMODE_8KGAME; + } + } else if ((value & 0x40) == 0x40) { + gmod3_cmode = CMODE_RAM; + } + DBG(("io1 w %04x %02x (bitbang: %d vectors: %d mode: %d)\n", + addr, value, gmod3_bitbang_enabled, gmod3_vectors_enabled, gmod3_cmode)); + } + + spi_flash_write_select((uint8_t)eeprom_cs); + if (eeprom_cs == 0) { /* active low */ + spi_flash_write_data((uint8_t)(eeprom_data_in)); + spi_flash_write_clock((uint8_t)(eeprom_clock)); + } + cart_config_changed_slotmain(gmod3_cmode, + (uint8_t)(gmod3_cmode | (gmod3_bank << CMODE_BANK_SHIFT)), mode); +} + +/* ---------------------------------------------------------------------*/ + +uint8_t gmod3_roml_read(uint16_t addr) +{ + int mem_config = ((~pport.dir | pport.data) & 0x7); + if (!gmod3_vectors_enabled) { + return gmod3_rom[(addr & 0x1fff) + (gmod3_bank << 13)]; + } + /* handle fake ultimax */ + if ((mem_config == 7) || (mem_config == 3)) { + return gmod3_rom[(addr & 0x1fff) + (gmod3_bank << 13)]; + } + return ram_read(addr); +} + +static uint8_t vectors[8] = { 0x08, 0x00, 0x08, 0x00, 0x0c, 0x80, 0x0c, 0x00 }; + +uint8_t gmod3_romh_read(uint16_t addr) +{ + DBG(("gmod3_romh_read %04x\n", addr)); + if (addr >= 0xfff8 /*&& addr <= 0xffff*/) { + return vectors[addr & 7]; + } + return mem_read_without_ultimax(addr); +} + +/* VIC reads */ +int gmod3_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + return CART_READ_C64MEM; +} +/* CPU reads */ +int gmod3_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + return CART_READ_C64MEM; +} + +int gmod3_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if (addr >= 0x8000 && addr <= 0x9fff) { + *value = gmod3_roml_read(addr); + return CART_READ_VALID; + } + if (gmod3_vectors_enabled) { + if (addr >= 0xfff8 /*&& addr <= 0xffff*/) { + *value = gmod3_romh_read(addr); + return CART_READ_VALID; + } + } + return CART_READ_THROUGH; +} + +void gmod3_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ + /* TODO */ + *base = NULL; + *start = 0; + *limit = 0; +} + +/* ---------------------------------------------------------------------*/ + +static int gmod3_dump(void) +{ + /* FIXME: incomplete */ + mon_out("status: %s\n", gmod3_cmode == CMODE_RAM ? "disabled" : "8k Game"); + mon_out("ROM bank: %d\n", gmod3_bank); + mon_out("bitbang mode is %s\n", gmod3_bitbang_enabled ? "enabled" : "disabled"); + mon_out("hw vectors are %s\n", gmod3_vectors_enabled ? "enabled" : "disabled"); + mon_out("EEPROM CS: %d clock: %d data from flash: %d data to flash: %d \n", + eeprom_cs, eeprom_clock, eeprom_data_out, eeprom_data_in); + + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void gmod3_config_init(void) +{ + gmod3_cmode = CMODE_8KGAME; + cart_config_changed_slotmain((uint8_t)gmod3_cmode, (uint8_t)gmod3_cmode, CMODE_READ); + eeprom_cs = 1; /* active low */ + spi_flash_write_select((uint8_t)eeprom_cs); +} + +void gmod3_reset(void) +{ + gmod3_cmode = CMODE_8KGAME; + cart_config_changed_slotmain((uint8_t)gmod3_cmode, (uint8_t)gmod3_cmode, CMODE_READ); + eeprom_cs = 1; /* active low */ + spi_flash_write_select((uint8_t)eeprom_cs); + gmod3_bitbang_enabled = 0; + gmod3_vectors_enabled = 0; /* FIXME: this can be enabled at reset as a factory option */ + gmod3_bank = 0; +} + +void gmod3_config_setup(uint8_t *rawcart) +{ + gmod3_cmode = CMODE_8KGAME; + cart_config_changed_slotmain((uint8_t)gmod3_cmode, (uint8_t)gmod3_cmode, CMODE_READ); + + if (gmod3_rom == NULL) { + gmod3_rom = lib_malloc(GMOD3_16MB_FLASH_SIZE); + } + + spi_flash_set_image(gmod3_rom, gmod3_flashsize); + memcpy(gmod3_rom, rawcart, GMOD3_16MB_FLASH_SIZE); +} + +/* ---------------------------------------------------------------------*/ + +static int set_gmod3_flash_write(int val, void *param) +{ + gmod3_flash_write = val ? 1 : 0; + + return 0; +} + +static const resource_int_t resources_int[] = { + { "GMod3FlashWrite", 1, RES_EVENT_NO, NULL, + &gmod3_flash_write, set_gmod3_flash_write, NULL }, + RESOURCE_INT_LIST_END +}; + +int gmod3_resources_init(void) +{ + return resources_register_int(resources_int); +} + +void gmod3_resources_shutdown(void) +{ + lib_free(gmod3_flash_filename); +} + +/* ------------------------------------------------------------------------- */ + +static const cmdline_option_t cmdline_options[] = +{ + { "-gmod3flashwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "GMod3FlashWrite", (resource_value_t)1, + NULL, "Enable saving of the GMod3 ROM at exit" }, + { "+gmod3flashwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "GMod3FlashWrite", (resource_value_t)0, + NULL, "Disable saving of the GMod3 ROM at exit" }, + CMDLINE_LIST_END +}; + +int gmod3_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} + +static int gmod3_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + gmod3_io1_list_item = io_source_register(&gmod3_io1_device); + + gmod3_enabled = 1; + + return 0; +} + +int gmod3_bin_attach(const char *filename, uint8_t *rawcart) +{ + gmod3_filetype = 0; + gmod3_filename = NULL; + gmod3_flashsize = 0; + memset(rawcart, 0xff, GMOD3_16MB_FLASH_SIZE); + + if (util_file_load(filename, rawcart, GMOD3_16MB_FLASH_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, GMOD3_8MB_FLASH_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, GMOD3_4MB_FLASH_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, GMOD3_2MB_FLASH_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } else { + gmod3_flashsize = GMOD3_2MB_FLASH_SIZE; + } + } else { + gmod3_flashsize = GMOD3_4MB_FLASH_SIZE; + } + } else { + gmod3_flashsize = GMOD3_8MB_FLASH_SIZE; + } + } else { + gmod3_flashsize = GMOD3_16MB_FLASH_SIZE; + } + + gmod3_filetype = CARTRIDGE_FILETYPE_BIN; + gmod3_filename = lib_strdup(filename); + return gmod3_common_attach(); +} + +int gmod3_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) +{ + crt_chip_header_t chip; + int i; + + gmod3_filetype = 0; + gmod3_filename = NULL; + gmod3_flashsize = 0; + memset(rawcart, 0xff, GMOD3_16MB_FLASH_SIZE); + + for (i = 0; i < (GMOD3_16MB_FLASH_SIZE / 0x2000); i++) { /* FIXME */ + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.bank >= (GMOD3_16MB_FLASH_SIZE / 0x2000) || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + } + + i *= 0x2000; + if ((i != GMOD3_16MB_FLASH_SIZE) && + (i != GMOD3_8MB_FLASH_SIZE) && + (i != GMOD3_4MB_FLASH_SIZE) && + (i != GMOD3_2MB_FLASH_SIZE)) { + return -1; + } + + gmod3_flashsize = i; + gmod3_filetype = CARTRIDGE_FILETYPE_CRT; + gmod3_filename = lib_strdup(filename); + + return gmod3_common_attach(); +} + +int gmod3_bin_save(const char *filename) +{ + FILE *fd; + + if (filename == NULL) { + return -1; + } + + fd = fopen(filename, MODE_WRITE); + + if (fd == NULL) { + return -1; + } + + if (fwrite(gmod3_rom, 1, gmod3_flashsize, fd) != gmod3_flashsize) { + fclose(fd); + return -1; + } + + fclose(fd); + + return 0; +} + +int gmod3_crt_save(const char *filename) +{ + FILE *fd; + crt_chip_header_t chip; + uint8_t *data; + int i; + + fd = crt_create(filename, CARTRIDGE_GMOD3, 1, 0, STRING_GMOD3); + + if (fd == NULL) { + return -1; + } + + chip.type = 2; + chip.size = 0x2000; + chip.start = 0x8000; + + data = gmod3_rom; + + for (i = 0; i < (gmod3_flashsize / 0x2000); i++) { + chip.bank = i; /* bank */ + + if (crt_write_chip(data, &chip, fd)) { + fclose(fd); + return -1; + } + data += 0x2000; + } + + fclose(fd); + return 0; +} + +int gmod3_flush_image(void) +{ + if (gmod3_filetype == CARTRIDGE_FILETYPE_BIN) { + return gmod3_bin_save(gmod3_filename); + } else if (gmod3_filetype == CARTRIDGE_FILETYPE_CRT) { + return gmod3_crt_save(gmod3_filename); + } + return -1; +} + +void gmod3_detach(void) +{ + if (gmod3_flash_write /* && flashrom_state->flash_dirty */) { + gmod3_flush_image(); + } + + lib_free(gmod3_filename); + gmod3_filename = NULL; + + export_remove(&export_res); + io_source_unregister(gmod3_io1_list_item); + gmod3_io1_list_item = NULL; + + gmod3_enabled = 0; + + if (gmod3_rom) { + lib_free(gmod3_rom); + gmod3_rom = NULL; + } +} + +/* ---------------------------------------------------------------------*/ + +static const char snap_module_name[] = "CARTGMOD3"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int gmod3_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)gmod3_cmode) < 0 + || SMW_B(m, (uint8_t)gmod3_bank) < 0 + || SMW_BA(m, gmod3_rom, GMOD3_16MB_FLASH_SIZE) < 0 + ) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + return spi_flash_snapshot_write_module(s); +} + +int gmod3_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + goto fail; + } + + if (gmod3_rom == NULL) { + gmod3_rom = lib_malloc(GMOD3_16MB_FLASH_SIZE); + } + + if (0 + || SMR_B_INT(m, &gmod3_cmode) < 0 + || SMR_B_INT(m, &gmod3_bank) < 0 + || SMR_BA(m, gmod3_rom, GMOD3_16MB_FLASH_SIZE) < 0) { + goto fail; + } + + snapshot_module_close(m); + + if (spi_flash_snapshot_read_module(s) < 0) { + return -1; + } + + gmod3_common_attach(); + + /* set filetype to none */ + gmod3_filename = NULL; + gmod3_filetype = 0; + + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/gmod3.h b/src/Emulators/vice/c64/cart/gmod3.h new file mode 100644 index 00000000..fc3e0ade --- /dev/null +++ b/src/Emulators/vice/c64/cart/gmod3.h @@ -0,0 +1,67 @@ +/* + * gmod3.h - Cartridge handling, GMod3 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef CARTRIDGE_INCLUDE_PRIVATE_API +#ifndef CARTRIDGE_INCLUDE_PUBLIC_API +#error "do not include this header directly, use c64cart.h instead." +#endif +#endif + +#ifndef VICE_GMOD3_H +#define VICE_GMOD3_H + +#include + +#include "vicetypes.h" + +struct snapshot_s; + +uint8_t gmod3_roml_read(uint16_t addr); +uint8_t gmod3_romh_read(uint16_t addr); +int gmod3_romh_phi1_read(uint16_t addr, uint8_t *value); +int gmod3_romh_phi2_read(uint16_t addr, uint8_t *value); + +int gmod3_peek_mem(export_t *export, uint16_t addr, uint8_t *value); +void gmod3_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +void gmod3_config_init(void); +void gmod3_reset(void); +void gmod3_config_setup(uint8_t *rawcart); +int gmod3_bin_attach(const char *filename, uint8_t *rawcart); +int gmod3_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int gmod3_bin_save(const char *filename); +int gmod3_crt_save(const char *filename); +int gmod3_flush_image(void); +void gmod3_detach(void); + +int gmod3_cmdline_options_init(void); +int gmod3_resources_init(void); +void gmod3_resources_shutdown(void); + +int gmod3_snapshot_write_module(struct snapshot_s *s); +int gmod3_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/gs.c b/src/Emulators/vice/c64/cart/gs.c index 55829534..5cfba7e9 100644 --- a/src/Emulators/vice/c64/cart/gs.c +++ b/src/Emulators/vice/c64/cart/gs.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUGC64GS */ + #include "vice.h" #include @@ -36,49 +38,53 @@ #include "cartridge.h" #include "export.h" #include "gs.h" +#include "log.h" #include "monitor.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" +#ifdef DEBUGC64GS +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + /* C64GS (C64 Game System/System 3) Cartridge - - 512kb ROM (64*8k), mapped to $8000 in 8k game config + - 512kb ROM (64*8k), (permanently) mapped to $8000 in 8k game config - - reading from io1 switches to bank 0 + - on any access (read or write) to IO1, the lower 6 bits of the address will + be latched and used as the bank number - - writing to io1 switches banks. the lower 6 bits of the address are the - bank number + CAUTION: the above is confirmed to be correct from looking at the "C64GS 4in1" + cartridge, whether the same is true for the System 3 cartridges is unknown yet. */ static int currbank = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void gs_io1_store(WORD addr, BYTE value) +static void gs_io1_store(uint16_t addr, uint8_t value) { - addr &= 0xff; regval = value; currbank = addr & 0x3f; cart_romlbank_set_slotmain(currbank); - /* 8k config */ - cart_set_port_exrom_slotmain(1); - cart_set_port_game_slotmain(0); cart_port_config_changed_slotmain(); - /* printf("C64GS: w addr: $de%02x value: $%02x bank: $%02x\n", addr, value, currbank); */ + DBG(("C64GS: w addr: $de%02x bank: $%02x value: $%02x", addr, currbank, value)); } -static BYTE gs_io1_read(WORD addr) +static uint8_t gs_io1_read(uint16_t addr) { - currbank = 0; - /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); - /* printf("C64GS: r addr: $de%02x\n", addr); */ + currbank = addr & 0x3f; + cart_romlbank_set_slotmain(currbank); + cart_port_config_changed_slotmain(); + DBG(("C64GS: r addr: $de%02x bank: $%02x", addr, currbank)); return 0; } -static BYTE gs_io1_peek(WORD addr) +static uint8_t gs_io1_peek(uint16_t addr) { return regval; } @@ -92,18 +98,20 @@ static int gs_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t gs_device = { - CARTRIDGE_NAME_GS, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - gs_io1_store, - gs_io1_read, - gs_io1_peek, - gs_dump, - CARTRIDGE_GS, - 0, - 0 + CARTRIDGE_NAME_GS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x3f, /* range for the device, regs:$de00-$de3f, mirrors:$de40-$deff */ + 0, /* read is never valid */ + gs_io1_store, /* store function */ + NULL, /* NO poke function */ + gs_io1_read, /* read function */ + gs_io1_peek, /* peek function */ + gs_dump, /* device state information dump function */ + CARTRIDGE_GS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *gs_list_item = NULL; @@ -117,15 +125,15 @@ static const export_resource_t export_res = { void gs_config_init(void) { /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); - gs_io1_store((WORD)0xde00, 0); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + gs_io1_store((uint16_t)0xde00, 0); } -void gs_config_setup(BYTE *rawcart) +void gs_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 64); /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -138,7 +146,7 @@ static int gs_common_attach(void) return 0; } -int gs_bin_attach(const char *filename, BYTE *rawcart) +int gs_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -146,7 +154,7 @@ int gs_bin_attach(const char *filename, BYTE *rawcart) return gs_common_attach(); } -int gs_crt_attach(FILE *fd, BYTE *rawcart) +int gs_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -189,7 +197,7 @@ int gs_snapshot_write_module(snapshot_t *s) if (0 || (SMW_B(m, regval) < 0) - || (SMW_B(m, (BYTE)currbank) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 64) < 0)) { snapshot_module_close(m); return -1; @@ -201,7 +209,7 @@ int gs_snapshot_write_module(snapshot_t *s) int gs_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/c64/cart/gs.h b/src/Emulators/vice/c64/cart/gs.h index ae6d0bd2..fce093cc 100644 --- a/src/Emulators/vice/c64/cart/gs.h +++ b/src/Emulators/vice/c64/cart/gs.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void gs_config_init(void); -extern void gs_config_setup(BYTE *rawcart); -extern int gs_bin_attach(const char *filename, BYTE *rawcart); -extern int gs_crt_attach(FILE *fd, BYTE *rawcart); -extern void gs_detach(void); +void gs_config_init(void); +void gs_config_setup(uint8_t *rawcart); +int gs_bin_attach(const char *filename, uint8_t *rawcart); +int gs_crt_attach(FILE *fd, uint8_t *rawcart); +void gs_detach(void); struct snapshot_s; -extern int gs_snapshot_write_module(struct snapshot_s *s); -extern int gs_snapshot_read_module(struct snapshot_s *s); +int gs_snapshot_write_module(struct snapshot_s *s); +int gs_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/hyperbasic.c b/src/Emulators/vice/c64/cart/hyperbasic.c new file mode 100644 index 00000000..562f70ac --- /dev/null +++ b/src/Emulators/vice/c64/cart/hyperbasic.c @@ -0,0 +1,297 @@ +/* + * hyperbasic.c - Cartridge handling, Hyper BASIC cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#define HYPERBASIC_DEBUG + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "export.h" +#include "log.h" +#include "resources.h" +#include "hyperbasic.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +#ifdef HYPERBASIC_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + "HYPERBASIC" 64k Cartridge by "SHS-BUDE" + + - 64Kb (8 banks) + - ROM is always mapped in at $8000-$9FFF (8k game). + + - 1 register at io1 / de00: + + bit 0 - _CE for ROM2, 0 = enable (don't select both) + bit 1 - _CE for ROM1, 0 = enable (don't select both) + (bit 2 - probably unused) + (bit 3 - probably unused) + bit 4 - A13 + bit 5 - A14 + bit 6 and/or 7 - _EXROM, 0 = make cart visible +*/ + +#define NUMBANKS 8 + +static uint8_t regval = 0; + +static uint8_t disabled = 0; +static uint8_t curr_bank = 0; +static uint8_t enable1 = 0; +static uint8_t enable2 = 0; + +static void hyperbasic_io1_store(uint16_t addr, uint8_t value) +{ + regval = value; + disabled = ((value >> 7) & 1) & ((value >> 6) & 1); + enable1 = ((value >> 1) & 1) ^ 1; + enable2 = (value & 1) ^ 1; + curr_bank = (value >> 4) & 3; + + if (enable1 && enable2) { + /* both ROMs selected */ + log_message(LOG_DEFAULT, "Hyper-BASIC: WARNING! both ROMs are selected!"); + cart_set_port_exrom_slotmain(0); /* FIXME: this is not really what happens */ + } else if (!enable1 && !enable2) { + /* no ROM is selected */ + cart_set_port_exrom_slotmain(0); /* FIXME: this is not really what happens */ + } else { + /* FIXME: this is not really what happens */ + curr_bank += (enable2 << 2); + + DBG(("hyperbasic_io1_store %04x %02x (disabled:%d rom1CE:%d rom2CE:%d bank:%d)\n", + addr, value, disabled, enable1, enable2, curr_bank)); + + cart_set_port_exrom_slotmain(disabled ^ 1); + cart_romlbank_set_slotmain(curr_bank); + } + + cart_port_config_changed_slotmain(); +} + +static uint8_t hyperbasic_io1_peek(uint16_t addr) +{ + return regval; +} + +static int hyperbasic_dump(void) +{ + mon_out("Register: %02x\n", regval); + mon_out("Cartridge is %s\n", disabled ? "disabled" : "enabled"); + mon_out("ROM1: %s ROM2: %s (Bank: %d of 8)\n", + enable1 ? "selected" : "deselected", enable2 ? "selected" : "deselected", curr_bank); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t hyperbasic_device = { + CARTRIDGE_NAME_HYPERBASIC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + hyperbasic_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + hyperbasic_io1_peek, /* peek function */ + hyperbasic_dump, /* device state information dump function */ + CARTRIDGE_HYPERBASIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *hyperbasic_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_HYPERBASIC, 0, 1, &hyperbasic_device, NULL, CARTRIDGE_HYPERBASIC +}; + +/* ---------------------------------------------------------------------*/ + +void hyperbasic_reset(void) +{ + disabled = 0; + cart_set_port_exrom_slotmain(1); +} + +void hyperbasic_config_init(void) +{ + disabled = 0; + cart_config_changed_slotmain(CMODE_8KGAME + (3 << CMODE_BANK_SHIFT), CMODE_8KGAME + (3 << CMODE_BANK_SHIFT), CMODE_READ); +} + +void hyperbasic_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000 * NUMBANKS); + cart_config_changed_slotmain(CMODE_8KGAME + (3 << CMODE_BANK_SHIFT), CMODE_8KGAME + (3 << CMODE_BANK_SHIFT), CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int hyperbasic_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + hyperbasic_list_item = io_source_register(&hyperbasic_device); + return 0; +} + +int hyperbasic_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return hyperbasic_common_attach(); +} + +int hyperbasic_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int highbank = 0; + int numbanks = 0; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if ((chip.bank >= NUMBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) { + return -1; + } + if (chip.bank > highbank) { + highbank = chip.bank; + } + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + numbanks++; + } + + if ((highbank != (NUMBANKS - 1)) || (numbanks != NUMBANKS)) { + return -1; + } + + return hyperbasic_common_attach(); +} + +void hyperbasic_detach(void) +{ + export_remove(&export_res); + io_source_unregister(hyperbasic_list_item); + hyperbasic_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTHYPERBASIC snapshot module format: + + type | name | version | description + ----------------------------------------- + BYTE | regval | 0.0 | register + ARRAY | ROML | 0.0 | 65536 BYTES of ROML data + + */ + +static const char snap_module_name[] = "CARTHYPERBASIC"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int hyperbasic_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)regval) < 0 + || SMW_BA(m, roml_banks, 0x2000 * NUMBANKS) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int hyperbasic_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (SMR_B(m, ®val) < 0) { + goto fail; + } + + if (SMR_BA(m, roml_banks, 0x2000 * NUMBANKS) < 0) { + goto fail; + } + + snapshot_module_close(m); + + if (hyperbasic_common_attach() < 0) { + return -1; + } + hyperbasic_io1_store(0xde00, regval); + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/hyperbasic.h b/src/Emulators/vice/c64/cart/hyperbasic.h new file mode 100644 index 00000000..2c1fdaaf --- /dev/null +++ b/src/Emulators/vice/c64/cart/hyperbasic.h @@ -0,0 +1,50 @@ +/* + * hyperbasic.h - Cartridge handling, Hyper BASIC cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_HYPERBASIC_H +#define VICE_HYPERBASIC_H + +#include + +#include "vicetypes.h" + +void hyperbasic_reset(void); +void hyperbasic_config_init(void); +void hyperbasic_config_setup(uint8_t *rawcart); +int hyperbasic_bin_attach(const char *filename, uint8_t *rawcart); +int hyperbasic_crt_attach(FILE *fd, uint8_t *rawcart); +void hyperbasic_detach(void); + +int hyperbasic_cmdline_options_init(void); +int hyperbasic_resources_init(void); +void hyperbasic_resources_shutdown(void); + +struct snapshot_s; + +int hyperbasic_snapshot_write_module(struct snapshot_s *s); +int hyperbasic_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/ide64.c b/src/Emulators/vice/c64/cart/ide64.c index 49949b59..d9ce8e0c 100644 --- a/src/Emulators/vice/c64/cart/ide64.c +++ b/src/Emulators/vice/c64/cart/ide64.c @@ -37,11 +37,6 @@ #include #endif -/* VAC++ has off_t in sys/stat.h */ -#ifdef __IBMC__ -#include -#endif - #include #include #include @@ -69,23 +64,17 @@ #include "resources.h" #include "shortbus.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "vicesocket.h" #include "vicii-phi1.h" #ifdef IDE64_DEBUG -#define debug(x) log_debug(x) +#define debug(x) log_printf (x) #else #define debug(x) #endif -#ifndef HAVE_FSEEKO -#define fseeko(a, b, c) fseek(a, b, c) -#define ftello(a) ftell(a) -#endif - #define LATENCY_TIMER 4000 static int ide64_enabled = 0; @@ -100,7 +89,7 @@ static int current_cfg; static rtc_ds1202_1302_t *ds1302_context = NULL; /* */ -static BYTE kill_port; +static uint8_t kill_port; static struct drive_s { ata_drive_t *drv; @@ -115,7 +104,7 @@ static struct drive_s { static int idrive = 0; /* communication latch */ -static WORD out_d030, in_d030, idebus; +static uint16_t out_d030, in_d030, idebus; #ifdef HAVE_NETWORK static struct alarm_s *usb_alarm; @@ -123,8 +112,8 @@ static char *settings_usbserver_address = NULL; static vice_network_socket_t * usbserver_socket = NULL; static vice_network_socket_t * usbserver_asocket = NULL; static int settings_usbserver; -static BYTE ft245_rx[256], ft245_tx[128]; -static int ft245_rxp, ft245_rxl, ft245_txp; +static uint8_t ft245_rx[256], ft245_tx[128]; +static ssize_t ft245_rxp, ft245_rxl, ft245_txp; #else #define usbserver_activate(a) {} #endif @@ -143,116 +132,129 @@ static char *clockport_device_names = NULL; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void ide64_idebus_store(WORD addr, BYTE value); -static BYTE ide64_idebus_read(WORD addr); -static BYTE ide64_idebus_peek(WORD addr); +static void ide64_idebus_store(uint16_t addr, uint8_t value); +static uint8_t ide64_idebus_read(uint16_t addr); +static uint8_t ide64_idebus_peek(uint16_t addr); static int ide64_idebus_dump(void); -static void ide64_io_store(WORD addr, BYTE value); -static BYTE ide64_io_read(WORD addr); -static BYTE ide64_io_peek(WORD addr); +static void ide64_io_store(uint16_t addr, uint8_t value); +static uint8_t ide64_io_read(uint16_t addr); +static uint8_t ide64_io_peek(uint16_t addr); static int ide64_io_dump(void); -static void ide64_ft245_store(WORD addr, BYTE value); -static BYTE ide64_ft245_read(WORD addr); -static BYTE ide64_ft245_peek(WORD addr); -static void ide64_ds1302_store(WORD addr, BYTE value); -static BYTE ide64_ds1302_read(WORD addr); -static BYTE ide64_ds1302_peek(WORD addr); -static void ide64_romio_store(WORD addr, BYTE value); -static BYTE ide64_romio_read(WORD addr); -static BYTE ide64_romio_peek(WORD addr); -static BYTE ide64_clockport_read(WORD io_address); -static BYTE ide64_clockport_peek(WORD io_address); -static void ide64_clockport_store(WORD io_address, BYTE byte); +static void ide64_ft245_store(uint16_t addr, uint8_t value); +static uint8_t ide64_ft245_read(uint16_t addr); +static uint8_t ide64_ft245_peek(uint16_t addr); +static void ide64_ds1302_store(uint16_t addr, uint8_t value); +static uint8_t ide64_ds1302_read(uint16_t addr); +static uint8_t ide64_ds1302_peek(uint16_t addr); +static void ide64_romio_store(uint16_t addr, uint8_t value); +static uint8_t ide64_romio_read(uint16_t addr); +static uint8_t ide64_romio_peek(uint16_t addr); +static uint8_t ide64_clockport_read(uint16_t io_address); +static uint8_t ide64_clockport_peek(uint16_t io_address); +static void ide64_clockport_store(uint16_t io_address, uint8_t byte); +static int ide64_clockport_dump(void); static int ide64_rtc_dump(void); static io_source_t ide64_idebus_device = { - CARTRIDGE_NAME_IDE64 " IDE", - IO_DETACH_CART, - NULL, - 0xde20, 0xde2f, 0x0f, - 0, - ide64_idebus_store, - ide64_idebus_read, - ide64_idebus_peek, - ide64_idebus_dump, - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 " IDE", /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde20, 0xde2f, 0x0f, /* range for the device, regs:$de20-$de2f */ + 0, /* read validity is determined by the device upon a read */ + ide64_idebus_store, /* store function */ + NULL, /* NO poke function */ + ide64_idebus_read, /* read function */ + ide64_idebus_peek, /* peek function */ + ide64_idebus_dump, /* device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ide64_io_device = { - CARTRIDGE_NAME_IDE64 " I/O", - IO_DETACH_CART, - NULL, - 0xde30, 0xde37, 0x07, - 0, - ide64_io_store, - ide64_io_read, - ide64_io_peek, - ide64_io_dump, - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 " I/O", /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde30, 0xde37, 0x07, /* range for the device, regs:$de30-$de37 */ + 0, /* read validity is determined by the device upon a read */ + ide64_io_store, /* store function */ + NULL, /* NO poke function */ + ide64_io_read, /* read function */ + ide64_io_peek, /* peek function */ + ide64_io_dump, /* device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ide64_ft245_device = { - CARTRIDGE_NAME_IDE64 " FT245", - IO_DETACH_CART, - NULL, - 0xde5d, 0xde5e, 0x01, - 0, - ide64_ft245_store, - ide64_ft245_read, - ide64_ft245_peek, - NULL, /* TODO: dump */ - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 " FT245", /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde5d, 0xde5e, 0x01, /* range for the device, regs:$de5d-$de5e */ + 0, /* read validity is determined by the device upon a read */ + ide64_ft245_store, /* store function */ + NULL, /* NO poke function */ + ide64_ft245_read, /* read function */ + ide64_ft245_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ide64_ds1302_device = { - CARTRIDGE_NAME_IDE64 " DS1302", - IO_DETACH_CART, - NULL, - 0xde5f, 0xde5f, 0x00, - 0, - ide64_ds1302_store, - ide64_ds1302_read, - ide64_ds1302_peek, - ide64_rtc_dump, - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 " DS1302", /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde5f, 0xde5f, 0x00, /* range for the device, reg:$de5f */ + 0, /* read validity is determined by the device upon a read */ + ide64_ds1302_store, /* store function */ + NULL, /* NO poke function */ + ide64_ds1302_read, /* read function */ + ide64_ds1302_peek, /* peek function */ + ide64_rtc_dump, /* device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ide64_rom_device = { - CARTRIDGE_NAME_IDE64 " ROM", - IO_DETACH_CART, - NULL, - 0xde60, 0xdeff, 0xff, - 0, - ide64_romio_store, - ide64_romio_read, - ide64_romio_peek, - NULL, /* TODO: dump */ - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 " ROM", /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde60, 0xdeff, 0xff, /* range for the device, regs:$de60-$deff */ + 0, /* read validity is determined by the device upon a read */ + ide64_romio_store, /* store function */ + NULL, /* NO poke function */ + ide64_romio_read, /* read function */ + ide64_romio_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ide64_clockport_device = { - CARTRIDGE_NAME_IDE64 "Clockport", - IO_DETACH_RESOURCE, - "IDE64ClockPort", - 0xde00, 0xde0f, 0x0f, - 0, - ide64_clockport_store, - ide64_clockport_read, - ide64_clockport_peek, - NULL, /* TODO: dump */ - CARTRIDGE_IDE64, - 0, - 0 + CARTRIDGE_NAME_IDE64 "Clockport", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "IDE64ClockPort", /* resource to set to '0' */ + 0xde00, 0xde0f, 0x0f, /* range for the device, regs:$de00-$de0f */ + 0, /* read validity is determined by the device upon a read */ + ide64_clockport_store, /* store function */ + NULL, /* NO poke function */ + ide64_clockport_read, /* read function */ + ide64_clockport_peek, /* peek function */ + ide64_clockport_dump, /* device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ide64_idebus_list_item = NULL; @@ -285,7 +287,7 @@ static int clockport_activate(void) return 0; } - clockport_device = clockport_open_device(clockport_device_id, (char *)STRING_IDE64_CLOCKPORT); + clockport_device = clockport_open_device(clockport_device_id, STRING_IDE64_CLOCKPORT); if (!clockport_device) { return -1; } @@ -392,7 +394,7 @@ static void detect_ide64_image(struct drive_s *drive) { FILE *file; unsigned char header[24]; - int res; + size_t res; char *ext; ata_drive_geometry_t *geometry = &drive->detected; @@ -421,13 +423,13 @@ static void detect_ide64_image(struct drive_s *drive) drive->type = ATA_DRIVE_CF; ext = util_get_extension(drive->filename); if (ext) { - if (!strcasecmp(ext, "cfa")) { + if (!util_strcasecmp(ext, "cfa")) { drive->type = ATA_DRIVE_CF; - } else if (!strcasecmp(ext, "hdd")) { + } else if (!util_strcasecmp(ext, "hdd")) { drive->type = ATA_DRIVE_HDD; - } else if (!strcasecmp(ext, "fdd")) { + } else if (!util_strcasecmp(ext, "fdd")) { drive->type = ATA_DRIVE_FDD; - } else if (!strcasecmp(ext, "iso")) { + } else if (!util_strcasecmp(ext, "iso")) { drive->type = ATA_DRIVE_CD; } } @@ -462,8 +464,8 @@ static void detect_ide64_image(struct drive_s *drive) } } else { off_t size = 0; - if (fseeko(file, 0, SEEK_END) == 0) { - size = ftello(file); + if (archdep_fseeko(file, 0, SEEK_END) == 0) { + size = archdep_ftello(file); if (size < 0) { size = 0; } @@ -471,7 +473,7 @@ static void detect_ide64_image(struct drive_s *drive) geometry->cylinders = 0; geometry->heads = 0; geometry->sectors = 0; - geometry->size = size / ((drive->type == ATA_DRIVE_CD) ? 2048 : 512); + geometry->size = (int)(size / ((drive->type == ATA_DRIVE_CD) ? 2048 : 512)); } } @@ -496,7 +498,7 @@ static int set_cylinders(int cylinders, void *param) { struct drive_s *drive = &drives[vice_ptr_to_int(param)]; - if (cylinders > 65535 || cylinders < 1) { + if (cylinders > IDE64_CYLINDERS_MAX || cylinders < IDE64_CYLINDERS_MIN) { return -1; } @@ -511,7 +513,7 @@ static int set_heads(int heads, void *param) { struct drive_s *drive = &drives[vice_ptr_to_int(param)]; - if (heads > 16 || heads < 1) { + if (heads > IDE64_HEADS_MAX || heads < IDE64_HEADS_MIN) { return -1; } drive->settings.heads = heads; @@ -525,7 +527,7 @@ static int set_sectors(int sectors, void *param) { struct drive_s *drive = &drives[vice_ptr_to_int(param)]; - if (sectors > 63 || sectors < 1) { + if (sectors > IDE64_SECTORS_MAX || sectors < IDE64_SECTORS_MIN) { return -1; } drive->settings.sectors = sectors; @@ -585,7 +587,7 @@ static int set_version(int value, void *param) return -1; } usbserver_activate(settings_usbserver); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } return 0; } @@ -690,7 +692,7 @@ static int set_ide64_clockport_device(int val, void *param) } if (val != CLOCKPORT_DEVICE_NONE) { - clockport_device = clockport_open_device(val, (char *)STRING_IDE64_CLOCKPORT); + clockport_device = clockport_open_device(val, STRING_IDE64_CLOCKPORT); if (!clockport_device) { return -1; } @@ -830,169 +832,108 @@ int ide64_resources_shutdown(void) return 0; } -static const cmdline_option_t cmdline_options[] = { - { "-IDE64image1", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-IDE64image1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Image1", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_IDE64_NAME, - NULL, NULL }, - { "-IDE64image2", SET_RESOURCE, 1, + "", "Specify name of IDE64 image file" }, + { "-IDE64image2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Image2", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_IDE64_NAME, - NULL, NULL }, - { "-IDE64image3", SET_RESOURCE, 1, + "", "Specify name of IDE64 image file" }, + { "-IDE64image3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Image3", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_IDE64_NAME, - NULL, NULL }, - { "-IDE64image4", SET_RESOURCE, 1, + "", "Specify name of IDE64 image file" }, + { "-IDE64image4", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Image4", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_IDE64_NAME, - NULL, NULL }, - { "-IDE64cyl1", SET_RESOURCE, 1, + "", "Specify name of IDE64 image file" }, + { "-IDE64cyl1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Cylinders1", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_CYLINDERS_IDE64, - NULL, NULL }, - { "-IDE64cyl2", SET_RESOURCE, 1, + "", "Set number of cylinders for the IDE64 emulation. (1..65535)" }, + { "-IDE64cyl2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Cylinders2", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_CYLINDERS_IDE64, - NULL, NULL }, - { "-IDE64cyl3", SET_RESOURCE, 1, + "", "Set number of cylinders for the IDE64 emulation. (1..65535)" }, + { "-IDE64cyl3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Cylinders3", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_CYLINDERS_IDE64, - NULL, NULL }, - { "-IDE64cyl4", SET_RESOURCE, 1, + "", "Set number of cylinders for the IDE64 emulation. (1..65535)" }, + { "-IDE64cyl4", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Cylinders4", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_CYLINDERS_IDE64, - NULL, NULL }, - { "-IDE64hds1", SET_RESOURCE, 1, + "", "Set number of cylinders for the IDE64 emulation. (1..65535)" }, + { "-IDE64hds1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Heads1", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_HEADS_IDE64, - NULL, NULL }, - { "-IDE64hds2", SET_RESOURCE, 1, + "", "Set number of heads for the IDE64 emulation. (1..16)" }, + { "-IDE64hds2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Heads2", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_HEADS_IDE64, - NULL, NULL }, - { "-IDE64hds3", SET_RESOURCE, 1, + "", "Set number of heads for the IDE64 emulation. (1..16)" }, + { "-IDE64hds3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Heads3", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_HEADS_IDE64, - NULL, NULL }, - { "-IDE64hds4", SET_RESOURCE, 1, + "", "Set number of heads for the IDE64 emulation. (1..16)" }, + { "-IDE64hds4", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Heads4", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_HEADS_IDE64, - NULL, NULL }, - { "-IDE64sec1", SET_RESOURCE, 1, + "", "Set number of heads for the IDE64 emulation. (1..16)" }, + { "-IDE64sec1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Sectors1", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_SECTORS_IDE64, - NULL, NULL }, - { "-IDE64sec2", SET_RESOURCE, 1, + "", "Set number of sectors for the IDE64 emulation. (1..63)" }, + { "-IDE64sec2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Sectors2", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_SECTORS_IDE64, - NULL, NULL }, - { "-IDE64sec3", SET_RESOURCE, 1, + "", "Set number of sectors for the IDE64 emulation. (1..63)" }, + { "-IDE64sec3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Sectors3", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_SECTORS_IDE64, - NULL, NULL }, - { "-IDE64sec4", SET_RESOURCE, 1, + "", "Set number of sectors for the IDE64 emulation. (1..63)" }, + { "-IDE64sec4", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Sectors4", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_SET_AMOUNT_SECTORS_IDE64, - NULL, NULL }, - { "-IDE64autosize1", SET_RESOURCE, 0, + "", "Set number of sectors for the IDE64 emulation. (1..63)" }, + { "-IDE64autosize1", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize1", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "+IDE64autosize1", SET_RESOURCE, 0, + NULL, "Autodetect image size" }, + { "+IDE64autosize1", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize1", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_NO_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "-IDE64autosize2", SET_RESOURCE, 0, + NULL, "Do not autodetect geometry of formatted images" }, + { "-IDE64autosize2", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize2", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "+IDE64autosize2", SET_RESOURCE, 0, + NULL, "Autodetect image size" }, + { "+IDE64autosize2", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize2", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_NO_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "-IDE64autosize3", SET_RESOURCE, 0, + NULL, "Do not autodetect geometry of formatted images" }, + { "-IDE64autosize3", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize3", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "+IDE64autosize3", SET_RESOURCE, 0, + NULL, "Autodetect image size" }, + { "+IDE64autosize3", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize3", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_NO_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "-IDE64autosize4", SET_RESOURCE, 0, + NULL, "Do not autodetect geometry of formatted images" }, + { "-IDE64autosize4", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize4", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "+IDE64autosize4", SET_RESOURCE, 0, + NULL, "Autodetect image size" }, + { "+IDE64autosize4", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64AutodetectSize4", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_NO_AUTODETECT_IDE64_GEOMETRY, - NULL, NULL }, - { "-IDE64version", SET_RESOURCE, 1, + NULL, "Do not autodetect geometry of formatted images" }, + { "-IDE64version", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64Version", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VALUE, IDCLS_IDE64_VERSION, - NULL, NULL }, + "", "IDE64 cartridge version" }, #ifdef HAVE_NETWORK - { "-IDE64USB", SET_RESOURCE, 0, + { "-IDE64USB", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64USBServer", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_IDE64_USB_SERVER, - NULL, NULL }, - { "+IDE64USB", SET_RESOURCE, 0, + NULL, "Enable IDE64 USB server" }, + { "+IDE64USB", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64USBServer", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_IDE64_USB_SERVER, - NULL, NULL }, - { "-IDE64USBAddress", SET_RESOURCE, 1, + NULL, "Disable IDE64 USB server" }, + { "-IDE64USBAddress", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64USBServerAddress", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_IDE64_USB_SERVER_ADDRESS, - NULL, NULL }, + "", "IDE64 USB server address" }, #endif - { "-IDE64rtcsave", SET_RESOURCE, 0, + { "-IDE64rtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64RTCSave", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_IDE64_RTC_SAVE, - NULL, NULL }, - { "+IDE64rtcsave", SET_RESOURCE, 0, + NULL, "Enable saving of IDE64 RTC data when changed." }, + { "+IDE64rtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IDE64RTCSave", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_IDE64_RTC_SAVE, - NULL, NULL }, + NULL, "Disable saving of IDE64 RTC data when changed." }, CMDLINE_LIST_END }; static cmdline_option_t clockport_cmdline_options[] = { - { "-ide64clockportdevice", SET_RESOURCE, 1, + { "-ide64clockportdevice", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "IDE64ClockPort", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_DEVICE, IDCLS_CLOCKPORT_DEVICE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -1012,7 +953,7 @@ int ide64_cmdline_options_init(void) sprintf(number, "%d", clockport_supported_devices[0].id); - clockport_device_names = util_concat(". (", number, ": ", clockport_supported_devices[0].name, NULL); + clockport_device_names = util_concat("Clockport device. (", number, ": ", clockport_supported_devices[0].name, NULL); for (i = 1; clockport_supported_devices[i].name; ++i) { tmp = clockport_device_names; @@ -1036,7 +977,7 @@ void ide64_reset(void) } } -static BYTE ide64_idebus_read(WORD addr) +static uint8_t ide64_idebus_read(uint16_t addr) { in_d030 = ata_register_read(drives[idrive ^ 1].drv, addr, idebus); in_d030 = ata_register_read(drives[idrive].drv, addr, in_d030); @@ -1051,7 +992,7 @@ static BYTE ide64_idebus_read(WORD addr) return 0; } -static BYTE ide64_idebus_peek(WORD addr) +static uint8_t ide64_idebus_peek(uint16_t addr) { if (settings_version >= IDE64_VERSION_4_1) { return ata_register_peek(drives[idrive].drv, addr) | ata_register_peek(drives[idrive ^ 1].drv, addr); @@ -1059,7 +1000,7 @@ static BYTE ide64_idebus_peek(WORD addr) return 0; } -static void ide64_idebus_store(WORD addr, BYTE value) +static void ide64_idebus_store(uint16_t addr, uint8_t value) { switch (addr) { case 8: @@ -1077,7 +1018,7 @@ static void ide64_idebus_store(WORD addr, BYTE value) } } -static BYTE ide64_io_read(WORD addr) +static uint8_t ide64_io_read(uint16_t addr) { ide64_io_device.io_source_valid = 1; @@ -1086,7 +1027,7 @@ static BYTE ide64_io_read(WORD addr) if (settings_version >= IDE64_VERSION_4_1) { break; } - return (BYTE)in_d030; + return (uint8_t)in_d030; case 1: return in_d030 >> 8; case 2: @@ -1103,14 +1044,14 @@ static BYTE ide64_io_read(WORD addr) return 0; } -static BYTE ide64_io_peek(WORD addr) +static uint8_t ide64_io_peek(uint16_t addr) { switch (addr) { case 0: if (settings_version >= IDE64_VERSION_4_1) { break; } - return (BYTE)in_d030; + return (uint8_t)in_d030; case 1: return in_d030 >> 8; case 2: @@ -1126,7 +1067,7 @@ static BYTE ide64_io_peek(WORD addr) return 0; } -static void ide64_io_store(WORD addr, BYTE value) +static void ide64_io_store(uint16_t addr, uint8_t value) { switch (addr) { case 0: @@ -1143,7 +1084,7 @@ static void ide64_io_store(WORD addr, BYTE value) case 5: if (settings_version < IDE64_VERSION_4_1 && current_bank != ((addr ^ 2) & 3)) { current_bank = (addr ^ 2) & 3; - cart_config_changed_slotmain(0, (BYTE)(current_cfg | (current_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(0, (uint8_t)(current_cfg | (current_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); } return; } @@ -1158,8 +1099,7 @@ static void usb_receive(void) usbserver_asocket = vice_network_accept(usbserver_socket); } while (usbserver_asocket && vice_network_select_poll_one(usbserver_asocket) && reconnect--) { - int r; - r = vice_network_receive(usbserver_asocket, ft245_rx, sizeof(ft245_rx), 0); + ssize_t r = vice_network_receive(usbserver_asocket, ft245_rx, sizeof(ft245_rx), 0); if (r <= 0) { vice_network_socket_close(usbserver_asocket); if (vice_network_select_poll_one(usbserver_socket)) { @@ -1188,7 +1128,7 @@ static void usb_send(void) usbserver_asocket = vice_network_accept(usbserver_socket); } while (usbserver_asocket && reconnect--) { - int r = vice_network_send(usbserver_asocket, ft245_tx, ft245_txp, 0); + ssize_t r = vice_network_send(usbserver_asocket, ft245_tx, ft245_txp, 0); if (r > 0 && vice_network_send(usbserver_asocket, ft245_tx, 0, 0) < 0) { r = -1; } @@ -1220,7 +1160,7 @@ static void usb_send(void) } #endif -static BYTE ide64_ft245_read(WORD addr) +static uint8_t ide64_ft245_read(uint16_t addr) { if (settings_version >= IDE64_VERSION_4_1) { switch (addr ^ 1) { @@ -1254,7 +1194,7 @@ static BYTE ide64_ft245_read(WORD addr) return 0; } -static BYTE ide64_ft245_peek(WORD addr) +static uint8_t ide64_ft245_peek(uint16_t addr) { if (settings_version >= IDE64_VERSION_4_1) { switch (addr ^ 1) { @@ -1285,7 +1225,7 @@ static BYTE ide64_ft245_peek(WORD addr) return 0; } -static void ide64_ft245_store(WORD addr, BYTE value) +static void ide64_ft245_store(uint16_t addr, uint8_t value) { if (settings_version >= IDE64_VERSION_4_1) { switch (addr ^ 1) { @@ -1309,7 +1249,7 @@ static void ide64_ft245_store(WORD addr, BYTE value) return; } -static BYTE ide64_ds1302_read(WORD addr) +static uint8_t ide64_ds1302_read(uint16_t addr) { int i; @@ -1327,12 +1267,12 @@ static BYTE ide64_ds1302_read(WORD addr) return i; } -static BYTE ide64_ds1302_peek(WORD addr) +static uint8_t ide64_ds1302_peek(uint16_t addr) { return 0; } -static void ide64_ds1302_store(WORD addr, BYTE value) +static void ide64_ds1302_store(uint16_t addr, uint8_t value) { if (kill_port & 1) { return; @@ -1342,30 +1282,44 @@ static void ide64_ds1302_store(WORD addr, BYTE value) return; } -static BYTE ide64_clockport_read(WORD address) +static uint8_t ide64_clockport_read(uint16_t address) { + /* read from clockport device */ if (clockport_device) { + ide64_clockport_device.io_source_valid = 1; return clockport_device->read(address, &ide64_clockport_device.io_source_valid, clockport_device->device_context); } + /* read open clock port */ + ide64_clockport_device.io_source_valid = 0; return 0; } -static BYTE ide64_clockport_peek(WORD address) +static uint8_t ide64_clockport_peek(uint16_t address) { + /* read from clockport device */ if (clockport_device) { return clockport_device->peek(address, clockport_device->device_context); } return 0; } -static void ide64_clockport_store(WORD address, BYTE byte) +static void ide64_clockport_store(uint16_t address, uint8_t byte) { + /* write to clockport device */ if (clockport_device) { clockport_device->store(address, byte, clockport_device->device_context); } } -static BYTE ide64_romio_read(WORD addr) +static int ide64_clockport_dump(void) +{ + if (clockport_device) { + clockport_device->dump(clockport_device->device_context); + } + return 0; +} + +static uint8_t ide64_romio_read(uint16_t addr) { if (kill_port & 1) { ide64_rom_device.io_source_valid = 0; @@ -1376,7 +1330,7 @@ static BYTE ide64_romio_read(WORD addr) return roml_banks[addr | 0x1e00 | (current_bank << 14)]; } -static BYTE ide64_romio_peek(WORD addr) +static uint8_t ide64_romio_peek(uint16_t addr) { if (kill_port & 1) { return 0; @@ -1384,7 +1338,7 @@ static BYTE ide64_romio_peek(WORD addr) return roml_banks[addr | 0x1e00 | (current_bank << 14)]; } -static void ide64_romio_store(WORD addr, BYTE value) +static void ide64_romio_store(uint16_t addr, uint8_t value) { if (kill_port & 1) { return; @@ -1452,29 +1406,29 @@ static void ide64_romio_store(WORD addr, BYTE value) default: return; } - cart_config_changed_slotmain(0, (BYTE)(current_cfg | (current_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(0, (uint8_t)(current_cfg | (current_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); } -BYTE ide64_rom_read(WORD addr) +uint8_t ide64_rom_read(uint16_t addr) { return roml_banks[(addr & 0x3fff) | (roml_bank << 14)]; } -void ide64_rom_store(WORD addr, BYTE value) +void ide64_rom_store(uint16_t addr, uint8_t value) { } -BYTE ide64_ram_read(WORD addr) +uint8_t ide64_ram_read(uint16_t addr) { return export_ram0[addr & 0x7fff]; } -void ide64_ram_store(WORD addr, BYTE value) +void ide64_ram_store(uint16_t addr, uint8_t value) { export_ram0[addr & 0x7fff] = value; } -void ide64_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void ide64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { switch (addr & 0xf000) { case 0xf000: @@ -1524,7 +1478,7 @@ void ide64_config_init(void) struct drive_s *drive; debug("IDE64 init"); - cart_config_changed_slotmain(0, 0, CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ | CMODE_PHI2_RAM); current_bank = 0; current_cfg = 0; kill_port = 0; @@ -1532,7 +1486,7 @@ void ide64_config_init(void) for (i = 0; i < 4; i++) { drive = &drives[i]; - ata_update_timing(drive->drv, machine_get_cycles_per_second()); + ata_update_timing(drive->drv, (CLOCK)machine_get_cycles_per_second()); if (drive->update_needed) { drive->update_needed = 0; detect_ide64_image(drive); @@ -1542,7 +1496,7 @@ void ide64_config_init(void) } } -void ide64_config_setup(BYTE *rawcart) +void ide64_config_setup(uint8_t *rawcart) { debug("IDE64 setup"); memcpy(roml_banks, rawcart, 0x80000); @@ -1576,7 +1530,7 @@ void ide64_detach(void) debug("IDE64 detached"); } -static int ide64_common_attach(BYTE *rawcart, int detect) +static int ide64_common_attach(uint8_t *rawcart, int detect) { int i; @@ -1612,16 +1566,33 @@ static int ide64_common_attach(BYTE *rawcart, int detect) return ide64_register(); } -int ide64_bin_attach(const char *filename, BYTE *rawcart) +int ide64_bin_attach(const char *filename, uint8_t *rawcart) { - if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS | UTIL_FILE_LOAD_FILL) < 0) { + off_t len; + FILE *fd; + + fd = fopen(filename, MODE_READ); + if (fd == NULL) { + return -1; + } + len = archdep_file_size(fd); + if (len < 0) { + fclose(fd); return -1; } + fclose(fd); + + /* we accept 64k, 128k and full 512k images */ + if (len == 0x10000 || len == 0x20000 || len == 0x80000) { + if (util_file_load(filename, rawcart, (size_t)len, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } return ide64_common_attach(rawcart, 1); } -int ide64_crt_attach(FILE *fd, BYTE *rawcart) +int ide64_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -1660,7 +1631,7 @@ static int ide64_idebus_dump(void) static int ide64_io_dump(void) { - const char *configs[4] = { + static const char * const configs[4] = { "8k", "16k", "stnd", "open" }; mon_out("Version: %d, Mode: %s, ", settings_version >= IDE64_VERSION_4_1 ? 4 : 3, (kill_port & 1) ? "Disabled" : "Enabled"); @@ -1687,11 +1658,11 @@ static int ide64_rtc_dump(void) DWORD | config | current config DWORD | kill port | kill port flag DWORD | idrive | idrive - WORD | in d030 | input state of $d030 register - WORD | out d030 | output state of $d030 register + WORD | in d030 | input state of $d030 register + WORD | out d030 | output state of $d030 register */ -static char snap_module_name[] = "CARTIDE"; +static const char snap_module_name[] = "CARTIDE"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -1745,7 +1716,7 @@ int ide64_snapshot_write_module(snapshot_t *s) int ide64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int i; @@ -1767,7 +1738,7 @@ int ide64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; diff --git a/src/Emulators/vice/c64/cart/ide64.h b/src/Emulators/vice/c64/cart/ide64.h index 97df2d11..2025facf 100644 --- a/src/Emulators/vice/c64/cart/ide64.h +++ b/src/Emulators/vice/c64/cart/ide64.h @@ -29,32 +29,47 @@ #include "vicetypes.h" -extern int ide64_resources_init(void); -extern int ide64_resources_shutdown(void); -extern int ide64_cmdline_options_init(void); +extern char *ide64_image_file; -extern void ide64_reset(void); +int ide64_resources_init(void); +int ide64_resources_shutdown(void); +int ide64_cmdline_options_init(void); -extern void ide64_config_init(void); -extern void ide64_config_setup(BYTE *rawcart); -extern int ide64_bin_attach(const char *filename, BYTE *rawcart); -extern int ide64_crt_attach(FILE *fd, BYTE *rawcart); -extern char *ide64_image_file; -extern void ide64_detach(void); +void ide64_reset(void); + +void ide64_config_init(void); +void ide64_config_setup(uint8_t *rawcart); +int ide64_bin_attach(const char *filename, uint8_t *rawcart); +int ide64_crt_attach(FILE *fd, uint8_t *rawcart); +void ide64_detach(void); -extern BYTE ide64_rom_read(WORD addr); -extern BYTE ide64_ram_read(WORD addr); -extern void ide64_rom_store(WORD addr, BYTE value); -extern void ide64_ram_store(WORD addr, BYTE value); -extern void ide64_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +uint8_t ide64_rom_read(uint16_t addr); +uint8_t ide64_ram_read(uint16_t addr); +void ide64_rom_store(uint16_t addr, uint8_t value); +void ide64_ram_store(uint16_t addr, uint8_t value); +void ide64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); struct snapshot_s; -extern int ide64_snapshot_read_module(struct snapshot_s *s); -extern int ide64_snapshot_write_module(struct snapshot_s *s); + +int ide64_snapshot_read_module(struct snapshot_s *s); +int ide64_snapshot_write_module(struct snapshot_s *s); /* values to be used with IDE64Version resource */ -#define IDE64_VERSION_3 0 +#define IDE64_VERSION_3 0 #define IDE64_VERSION_4_1 1 #define IDE64_VERSION_4_2 2 +/* device numbers for IDE64 resources */ +#define IDE64_DEVICE_MIN 1 +#define IDE64_DEVICE_MAX 4 +#define IDE64_DEVICE_COUNT (IDE64_DEVICE_MAX - IDE64_DEVICE_MIN + 1) + +/* limits for the geometry resources (inclusive) */ +#define IDE64_CYLINDERS_MIN 1 +#define IDE64_CYLINDERS_MAX 65535 +#define IDE64_HEADS_MIN 1 +#define IDE64_HEADS_MAX 16 +#define IDE64_SECTORS_MIN 1 +#define IDE64_SECTORS_MAX 63 + #endif diff --git a/src/Emulators/vice/c64/cart/ieeeflash64.c b/src/Emulators/vice/c64/cart/ieeeflash64.c new file mode 100644 index 00000000..a21a0f09 --- /dev/null +++ b/src/Emulators/vice/c64/cart/ieeeflash64.c @@ -0,0 +1,718 @@ +/* + * ieeeflash64.c - IEEE Flash! 64 interface emulation + * + * Written by + * Christopher Bongaarts + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOT0_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOT0_API +#include "c64mem.h" +#include "c64memrom.h" +#include "c64rom.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "ieeeflash64.h" +#include "export.h" +#include "maincpu.h" +#include "drive.h" +#include "parallel.h" +#include "mc6821core.h" +#include "resources.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "lib.h" +#include "crt.h" +#include "monitor.h" + +/* + IEEE Flash! 64 - Skyles Electic Works + - IEEE interface for C64. Plugs into cartridge port; includes + pass-through connector. 4 DIP switches, 8K KERNAL replacement ROM, + 6821 PIA mapped at $de00. Replacement ROM has hooks to serial + routines that check DIP switches to route to IEEE routines or + original IEC routines. + + - 6821 pin mappings: + PA0-7 = IEEE data lines D1-8 + PB0 = dev8 switch + PB1 = dev9/10 switch + PB2 = dev4 switch + PB3 = IFC (reset) + PB4 = EOI + PB5 = DAV + PB6 = NRFD + PB7 = NDAC + CA2 = ATN + + 8K ROM + - ROM is mapped to $e000 using ultimax mode, but only when hiram is inactive + (the cartridge uses a clip to the inside of the computer for this) +*/ + +/* #define DEBUGTPI */ + +#ifdef DEBUGTPI +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +static int ieeeflash64_switch8 = 0; +static int ieeeflash64_switch910 = 0; +static int ieeeflash64_switch4 = 0; + +static int ieeeflash64_enabled = 0; + +static int ieeeflash64_extexrom = 0; +static int ieeeflash64_extgame = 0; + +static mc6821_state ieeeflash64_6821; + +/* bit positions in PIA port B for IEEE signals */ +#define PIA_EOI_BIT 0x10 +#define PIA_DAV_BIT 0x20 +#define PIA_NRFD_BIT 0x40 +#define PIA_NDAC_BIT 0x80 + +/* private ROM storage for slot0 API */ +#define IEEEFLASH64_ROM_SIZE 0x2000 +static uint8_t *ieeeflash64_rom = NULL; + +/* filename of kernal rom */ +static char *ieeeflash64_filename = NULL; + +/* forward decl needed by set_ieeeflash64_filename */ +static int set_ieeeflash64_enabled(int value, void *param); + +int ieeeflash64_cart_enabled(void) { + return ieeeflash64_enabled; +} + +static int ieeeflash64_set_switch8(int val, void *param) +{ + ieeeflash64_switch8 = val ? 1 : 0; + + return 0; +} + +static int ieeeflash64_set_switch910(int val, void *param) +{ + ieeeflash64_switch910 = val ? 1 : 0; + + return 0; +} + +static int ieeeflash64_set_switch4(int val, void *param) +{ + ieeeflash64_switch4 = val ? 1 : 0; + + return 0; +} + +static int set_ieeeflash64_filename(const char *name, void *param) +{ + int enabled; + + if (name != NULL && *name != '\0') { + if (util_check_filename_access(name) < 0) { + return -1; + } + } + DBG(("IEEEFlash64: set_name: %d '%s'\n", ieeeflash64_enabled, ieeeflash64_filename)); + + util_string_set(&ieeeflash64_filename, name); + resources_get_int("IEEEFlash64", &enabled); + + if (set_ieeeflash64_enabled(enabled, (void*)1) < 0) { + lib_free(ieeeflash64_filename); + ieeeflash64_filename = NULL; + DBG(("IEEEFlash64: set_name done (failed): %d '%s'\n", ieeeflash64_enabled, ieeeflash64_filename)); + return -1; + } + + DBG(("IEEEFlash64: set_name done: %d '%s'\n", ieeeflash64_enabled, ieeeflash64_filename)); + return 0; +} + +const char *ieeeflash64_get_file_name(void) +{ + return ieeeflash64_filename; +} + +/*! \brief integer resources used by the IEEE Flash 64 module */ +static const resource_int_t resources_int[] = { + { "IEEEFlash64Dev8", 0, RES_EVENT_NO, NULL, + &ieeeflash64_switch8, ieeeflash64_set_switch8, NULL }, + { "IEEEFlash64Dev910", 0, RES_EVENT_NO, NULL, + &ieeeflash64_switch910, ieeeflash64_set_switch910, NULL }, + { "IEEEFlash64Dev4", 0, RES_EVENT_NO, NULL, + &ieeeflash64_switch4, ieeeflash64_set_switch4, NULL }, + /* keeping "enable" resource last prevents unnecessary (re)init when loading config file */ + { "IEEEFlash64", 0, RES_EVENT_SAME, (resource_value_t)0, + &ieeeflash64_enabled, set_ieeeflash64_enabled, (void *)1 }, + RESOURCE_INT_LIST_END +}; + +static const resource_string_t resources_string[] = { + { "IEEEFlash64Image", "", RES_EVENT_NO, NULL, + &ieeeflash64_filename, set_ieeeflash64_filename, NULL }, + RESOURCE_STRING_LIST_END +}; + +/*! \brief initialize the ieee flash! 64 resources + \return + 0 on success, else -1. + + \remark + Registers the string and the integer resources +*/ +int ieeeflash64_resources_init(void) +{ + if (resources_register_string(resources_string) < 0) { + return -1; + } + return resources_register_int(resources_int); +} + +/*! \brief uninitialize the ieee flash 64 resources */ +void ieeeflash64_resources_shutdown(void) +{ + lib_free(ieeeflash64_filename); + ieeeflash64_filename = NULL; +} + +/* ------------------------------------------------------------------------- */ + +static const cmdline_option_t cmdline_options[] = +{ + { "-ieeeflash64", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64", (resource_value_t)1, + NULL, "Enable IEEE Flash! 64" }, + { "+ieeeflash64", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64", (resource_value_t)0, + NULL, "Disable IEEE Flash! 64" }, + { "-ieeeflash64dev8", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev8", (resource_value_t)0, + NULL, "Route device 8 to IEC bus" }, + { "+ieeeflash64dev8", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev8", (resource_value_t)1, + NULL, "Route device 8 to IEEE bus" }, + { "-ieeeflash64dev910", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev910", (resource_value_t)0, + NULL, "Route devices 9 and 10 to IEC bus" }, + { "+ieeeflash64dev910", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev910", (resource_value_t)1, + NULL, "Route devices 9 and 10 to IEEE bus" }, + { "-ieeeflash64dev4", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev4", (resource_value_t)0, + NULL, "Route device 4 to IEC bus" }, + { "+ieeeflash64dev4", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "IEEEFlash64Dev4", (resource_value_t)1, + NULL, "Route device 4 to IEEE bus" }, + { "-ieeeflash64image", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "IEEEFlash64Image", NULL, + "", "specify ieeeflash64 interface kernal image name" }, + CMDLINE_LIST_END +}; + +/* ---------------------------------------------------------------------*/ + +/*! \brief initialize the command-line options' + \return + 0 on success, else -1. + + \remark + Registers the command-line options +*/ +int ieeeflash64_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} +/* ---------------------------------------------------------------------*/ + +static void ieeeflash64_io1_store(uint16_t addr, uint8_t data); +static uint8_t ieeeflash64_io1_read(uint16_t addr); +static uint8_t ieeeflash64_io1_peek(uint16_t addr); +static int ieeeflash64_io1_dump(void); + +static io_source_t ieeeflash64_io1_device = { + CARTRIDGE_NAME_IEEEFLASH64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x03, /* range for the device, regs:$de00-$de03, mirrors:$de04-$deff */ + 1, /* read is always valid */ + ieeeflash64_io1_store, /* store function */ + NULL, /* NO poke function */ + ieeeflash64_io1_read, /* read function */ + ieeeflash64_io1_peek, /* peek function */ + ieeeflash64_io1_dump, /* device state information dump function */ + CARTRIDGE_IEEEFLASH64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *ieeeflash64_io_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_IEEEFLASH64, 1, 0, &ieeeflash64_io1_device, NULL, CARTRIDGE_IEEEFLASH64 +}; + +/* ---------------------------------------------------------------------*/ +/* the IEEE Flash just uses the PIA for its GPIO functions, so lets just + patch things in directly here. */ + +static void ieeeflash64_io1_store(uint16_t addr, uint8_t data) +{ + int port, reg; + + /* DBG(("PIA io1 w %02x (%02x)\n", addr, data)); */ + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + + mc6821core_store(&ieeeflash64_6821, port, reg, data); +} + +static uint8_t ieeeflash64_io1_read(uint16_t addr) +{ + int port, reg; + + /* DBG(("PIA io1 r %02x\n", addr)); */ + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + return mc6821core_read(&ieeeflash64_6821, port, reg); +} + +static uint8_t ieeeflash64_io1_peek(uint16_t addr) +{ + int port, reg; + + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + return mc6821core_peek(&ieeeflash64_6821, port, reg); +} + +static int ieeeflash64_io1_dump(void) +{ + mon_out("PIA io1\n"); + mc6821core_dump(&ieeeflash64_6821); + return 0; +} +/* ---------------------------------------------------------------------*/ + +static void pia_set_ca2(mc6821_state *ctx) +{ + parallel_cpu_set_atn((uint8_t)((ctx->CA2) ? 0 : 1)); +} + +static void pia_reset(void) +{ + /* assuming input after reset */ + parallel_cpu_set_atn(0); + parallel_cpu_set_ndac(0); + parallel_cpu_set_nrfd(0); + parallel_cpu_set_dav(0); + parallel_cpu_set_eoi(0); + parallel_cpu_set_bus(0xff); +} + +static uint8_t oldpa; + +static void pia_set_pa(mc6821_state *ctx) +{ + if (ctx->dataA != oldpa) { + parallel_cpu_set_bus(ctx->dataA); + oldpa = ctx->dataA; + } +} + +static void pia_set_pb(mc6821_state *ctx) +{ + uint8_t tmp = ~(ctx->dataB); + + DBG(("IEEEFLASH64: PIA write port B %02x [EOI=%d DAV=%d NRFD=%d NDAC=%d]\n", tmp, + tmp & PIA_EOI_BIT, tmp & PIA_DAV_BIT, tmp & PIA_NRFD_BIT, tmp & PIA_NDAC_BIT)); + + parallel_cpu_set_eoi((uint8_t)(tmp & PIA_EOI_BIT & ctx->ddrB)); + parallel_cpu_set_dav((uint8_t)(tmp & PIA_DAV_BIT & ctx->ddrB)); + parallel_cpu_set_nrfd((uint8_t)(tmp & PIA_NRFD_BIT & ctx->ddrB)); + parallel_cpu_set_ndac((uint8_t)(tmp & PIA_NDAC_BIT & ctx->ddrB)); +} + +static uint8_t pia_get_pa(mc6821_state *ctx) +{ + uint8_t byte; + + drive_cpu_execute_all(maincpu_clk); + + byte = (parallel_bus & ~ctx->ddrA) | (ctx->dataA & ctx->ddrA); + +#ifdef DEBUG +/* if (debug.ieee) { + printf("IEEEFlash64: read pia port A %x, parallel_bus=%x, gives %x.\n", + ctx->dataA, parallel_bus, (unsigned int)byte); + } */ +#endif + + return byte; +} + +static uint8_t pia_get_pb(mc6821_state *ctx) +{ + uint8_t byte; + + drive_cpu_execute_all(maincpu_clk); + + byte = 0xf8; + if (parallel_ndac) { + byte &= ~PIA_NDAC_BIT; + } + if (parallel_nrfd) { + byte &= ~PIA_NRFD_BIT; + } + if (parallel_dav) { + byte &= ~PIA_DAV_BIT; + } + if (parallel_eoi) { + byte &= ~PIA_EOI_BIT; + } + + /* reflect device routing switches 0 = "off" 1 = "on" */ + byte |= ieeeflash64_switch8; + byte |= ieeeflash64_switch910 << 1; + byte |= ieeeflash64_switch4 << 2; + + return byte; +} + +/* ------------------------------------------------------------------------- */ + +uint8_t ieeeflash64_romh_read_hirom(uint16_t addr) +{ + /*DBG(("IEEEFlash64(romh_read_hirom): %x\n", addr));*/ + uint8_t value = ieeeflash64_rom[(addr & 0x1fff)]; + /*DBG(("IEEEFlash64(romh_read_hirom): %04x returns %02x\n", addr, value));*/ + return value; +} + +int ieeeflash64_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + /*DBG(("IEEEFlash64(romh_phi1_read): %x\n", addr));*/ + return CART_READ_C64MEM; +} + +int ieeeflash64_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + /*DBG(("IEEEFlash64(romh_phi2_read): %x\n", addr));*/ + return ieeeflash64_romh_phi1_read(addr, value); +} + +int ieeeflash64_peek_mem(uint16_t addr, uint8_t *value) +{ + if (addr >= 0xe000) { + *value = ieeeflash64_rom[addr & 0x1fff]; + return CART_READ_VALID; + } + return CART_READ_THROUGH; +} + +/* ------------------------------------------------------------------------- */ + +static int set_ieeeflash64_enabled(int value, void *param) +{ + /* value = enabled(1)/disabled(0); param = attach/detach(0) vs enable/disable(1) */ + /* i dont really get what should be happening when on attach vs. enable - CAB */ + int val = value ? 1 : 0; + + DBG(("IEEEFlash64: set_enabled: (%p) '%s' %d to %d\n", param, ieeeflash64_filename, ieeeflash64_enabled, val)); + if (ieeeflash64_enabled && !val) { + /* enabled -> disabled */ + cart_power_off(); +#ifdef DEBUGTPI + if (ieeeflash64_io_list_item == NULL) { + DBG(("IEEEFlash64: BUG: ieeeflash64_enabled == 1 and ieeeflash64_list_item == NULL ?!\n")); + } +#endif + lib_free(ieeeflash64_rom); + ieeeflash64_rom = NULL; + export_remove(&export_res); + io_source_unregister(ieeeflash64_io_list_item); + ieeeflash64_io_list_item = NULL; + ieeeflash64_enabled = 0; + DBG(("IEEEFlash64: set_enabled unregistered\n")); + } else if (!ieeeflash64_enabled && val) { + /* disabled -> enabled */ + if (ieeeflash64_rom == NULL) { + ieeeflash64_rom = lib_malloc(IEEEFLASH64_ROM_SIZE); + } + if (param) { + /* if the param is != NULL, then we should load the default image file */ + if ((ieeeflash64_filename != NULL) && (*ieeeflash64_filename != 0)) { + DBG(("IEEEFlash64: attach default image\n")); + /* try .crt first */ + if ((cartridge_attach_image(CARTRIDGE_CRT, ieeeflash64_filename) < 0) && + (cartridge_attach_image(CARTRIDGE_IEEEFLASH64, ieeeflash64_filename) < 0)) { + DBG(("IEEEFlash64: set_enabled did not register (attach image failed)\n")); + lib_free(ieeeflash64_rom); + ieeeflash64_rom = NULL; + return -1; /* loading the default was requested, but file could not be loaded */ + } + /* ieeeflash64_enabled = 1; */ /* cartridge_attach_image will end up calling set_ieeeflash64_enabled again */ + DBG(("IEEEFlash64: attach succeeded\n")); + return 0; + } else { + return -1; /* loading the default was requested, but no filename was set */ + } + } else { + cart_power_off(); + /* if the param is == NULL, then we should actually set the resource */ + if (export_add(&export_res) < 0) { + DBG(("IEEEFlash64: set_enabled did not register (export add failed)\n")); + lib_free(ieeeflash64_rom); + ieeeflash64_rom = NULL; + return -1; + } else { + DBG(("IEEEFlash64: set_enabled registered\n")); + ieeeflash64_io_list_item = io_source_register(&ieeeflash64_io1_device); + ieeeflash64_enabled = 1; + } + } + } + + DBG(("IEEEFlash64: set_enabled done: (%p) '%s' %d : %d\n", ieeeflash64_rom, ieeeflash64_filename, val, ieeeflash64_enabled)); +#ifdef DEBUGTPI + if (ieeeflash64_rom != NULL) { + DBG(("IEEEFlash64: rom is defined, fffc=%02x%02x\n", ieeeflash64_rom[0x1ffd], ieeeflash64_rom[0x1ffc])); + } +#endif + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void ieeeflash64_passthrough_changed(export_t *ex) +{ + ieeeflash64_extexrom = ex->exrom; + ieeeflash64_extgame = ex->game; + DBG(("IEEE Flash 64 passthrough changed exrom: %d game: %d\n", ieeeflash64_extexrom, ieeeflash64_extgame)); + + /* cart_set_port_game_slot0(ieeeflash64_extgame); */ + cart_port_config_changed_slot0(); +} + +int ieeeflash64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ + if (addr >= 0xe000) { + /* DBG(("IEEEFlash64: MMU XLATE %x\n", addr)); */ + *base = ieeeflash64_rom - 0xe000; + *start = 0xe000; + *limit = 0xfffd; + return CART_READ_VALID; + } else { + return CART_READ_THROUGH; + } +} + +void ieeeflash64_config_init(export_t *ex) +{ + DBG(("ieeeflash64: ieeeflash64_config_init\n")); + + ieeeflash64_extexrom = (int)ex->exrom; + ieeeflash64_extgame = (int)ex->game; + + /* + cart_set_port_exrom_slot0(1); + cart_set_port_game_slot0(ieeeflash64_extgame); + */ + /*cart_port_config_changed_slot0();*/ + /* cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); */ + cart_config_changed_slot0(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +#ifdef DEBUGTPI + if (ieeeflash64_rom != NULL) { + DBG(("IEEEFlash64: rom is defined, fffc=%02x%02x\n", ieeeflash64_rom[0x1ffd], ieeeflash64_rom[0x1ffc])); + } +#endif + + /* stop 6821 from calling CA2 during reset */ + ieeeflash64_6821.set_ca2 = NULL; + ieeeflash64_6821.set_pa = NULL; + ieeeflash64_6821.set_pb = NULL; + ieeeflash64_6821.get_pa = NULL; + ieeeflash64_6821.get_pb = NULL; + mc6821core_reset(&ieeeflash64_6821); + ieeeflash64_6821.set_ca2 = pia_set_ca2; + ieeeflash64_6821.set_pa = pia_set_pa; + ieeeflash64_6821.set_pb = pia_set_pb; + ieeeflash64_6821.get_pa = pia_get_pa; + ieeeflash64_6821.get_pb = pia_get_pb; + pia_reset(); +} + +void ieeeflash64_config_setup(uint8_t *rawcart) +{ + DBG(("ieeeflash64: config_setup\n")); + memcpy(ieeeflash64_rom, rawcart, IEEEFLASH64_ROM_SIZE); + /* cart_config_changed_slotmain(2, 3, CMODE_READ); */ +#ifdef DEBUGTPI + if (ieeeflash64_rom != NULL) { + DBG(("IEEEFlash64: rom is defined, fffc=%02x%02x\n", ieeeflash64_rom[0x1ffd], ieeeflash64_rom[0x1ffc])); + } +#endif +} + +static int ieeeflash64_common_attach(void) +{ + DBG(("ieeeflash64: ieeeflash64_common_attach\n")); + return set_ieeeflash64_enabled(1, NULL); +} + +int ieeeflash64_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("ieeeflash64: ieeeflash64_bin_attach\n")); + + if (util_file_load(filename, rawcart, IEEEFLASH64_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + set_ieeeflash64_filename(filename, NULL); /* set the resource */ + return ieeeflash64_common_attach(); +} + +int ieeeflash64_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.size != IEEEFLASH64_ROM_SIZE) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + set_ieeeflash64_filename(filename, NULL); /* set the resource */ + return ieeeflash64_common_attach(); +} + +void ieeeflash64_detach(void) +{ + set_ieeeflash64_enabled(0, NULL); +} + +int ieeeflash64_enable(void) +{ + return set_ieeeflash64_enabled(1, (void*)1); +} + +int ieeeflash64_disable(void) +{ + return set_ieeeflash64_enabled(0, (void*)1); +} + +void ieeeflash64_reset(void) +{ + /* cart_config_changed_slot0(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); */ +} + +/* ---------------------------------------------------------------------*/ + +/* CARTIEEEFLASH64 snapshot module format: + + type | name | description + -------------------------- + ARRAY | ROMH | 8192 BYTES of ROMH data + */ +/* TODO: record more state */ +static const char snap_module_name[] = "CARTIEEEFLASH64"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int ieeeflash64_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (SMW_BA(m, ieeeflash64_rom, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + if (mc6821core_snapshot_write_data(&ieeeflash64_6821, m) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int ieeeflash64_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + set_ieeeflash64_enabled(1, NULL); + + if (SMR_BA(m, ieeeflash64_rom, 0x2000) < 0) { + goto fail; + } + + if (mc6821core_snapshot_read_data(&ieeeflash64_6821, m) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return ieeeflash64_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/ieeeflash64.h b/src/Emulators/vice/c64/cart/ieeeflash64.h new file mode 100644 index 00000000..5c9084d7 --- /dev/null +++ b/src/Emulators/vice/c64/cart/ieeeflash64.h @@ -0,0 +1,62 @@ +/* + * ieeeflash64.h - IEEE Flash! 64 interface emulation + * + * Written by + * Christopher Bongaarts + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_IEEEFLASH64_H +#define VICE_IEEEFLASH64_H + +#include + +#include "vicetypes.h" +#include "c64cart.h" + +struct snapshot_s; + +int ieeeflash64_cart_enabled(void); +int ieeeflash64_resources_init(void); +void ieeeflash64_resources_shutdown(void); +int ieeeflash64_cmdline_options_init(void); +void ieeeflash64_passthrough_changed(export_t *export); +int ieeeflash64_enable(void); +int ieeeflash64_disable(void); + +int ieeeflash64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); +uint8_t ieeeflash64_romh_read_hirom(uint16_t addr); +int ieeeflash64_romh_phi1_read(uint16_t addr, uint8_t *value); +int ieeeflash64_romh_phi2_read(uint16_t addr, uint8_t *value); +int ieeeflash64_peek_mem(uint16_t addr, uint8_t *value); + +void ieeeflash64_config_init(export_t *ex); +void ieeeflash64_reset(void); +void ieeeflash64_config_setup(uint8_t *rawcart); +int ieeeflash64_bin_attach(const char *filename, uint8_t *rawcart); +int ieeeflash64_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +void ieeeflash64_detach(void); +const char *ieeeflash64_get_file_name(void); + +int ieeeflash64_snapshot_write_module(struct snapshot_s *s); +int ieeeflash64_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/isepic.c b/src/Emulators/vice/c64/cart/isepic.c index fabe5d28..e980afbf 100644 --- a/src/Emulators/vice/c64/cart/isepic.c +++ b/src/Emulators/vice/c64/cart/isepic.c @@ -45,9 +45,9 @@ #include "machine.h" #include "mem.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -106,7 +106,7 @@ static int isepic_switch = 0; static int isepic_write_image = 0; /* 2 KB RAM */ -static BYTE *isepic_ram; +static uint8_t *isepic_ram; /* current page */ static unsigned int isepic_page = 0; @@ -130,42 +130,46 @@ static int isepic_state = ISEPIC_STATE_NMI_WAITING; /* ------------------------------------------------------------------------- */ /* some prototypes are needed */ -static BYTE isepic_io1_read(WORD addr); -static BYTE isepic_io1_peek(WORD addr); -static void isepic_io1_store(WORD addr, BYTE byte); -static BYTE isepic_io2_read(WORD addr); -static BYTE isepic_io2_peek(WORD addr); -static void isepic_io2_store(WORD addr, BYTE byte); +static uint8_t isepic_io1_read(uint16_t addr); +static uint8_t isepic_io1_peek(uint16_t addr); +static void isepic_io1_store(uint16_t addr, uint8_t byte); +static uint8_t isepic_io2_read(uint16_t addr); +static uint8_t isepic_io2_peek(uint16_t addr); +static void isepic_io2_store(uint16_t addr, uint8_t byte); static int isepic_dump(void); static io_source_t isepic_io1_device = { - CARTRIDGE_NAME_ISEPIC, - IO_DETACH_RESOURCE, - "IsepicCartridgeEnabled", - 0xde00, 0xdeff, 0x07, - 0, /* read is never valid */ - isepic_io1_store, - isepic_io1_read, - isepic_io1_peek, - isepic_dump, - CARTRIDGE_ISEPIC, - 0, - 0 + CARTRIDGE_NAME_ISEPIC, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "IsepicCartridgeEnabled", /* resource to set to '0' */ + 0xde00, 0xdeff, 0x07, /* range for the device, regs:$de00-$de07, mirrors:$de08-$deff */ + 0, /* read is never valid */ + isepic_io1_store, /* store function */ + NULL, /* NO poke function */ + isepic_io1_read, /* read function */ + isepic_io1_peek, /* peek function */ + isepic_dump, /* device state information dump function */ + CARTRIDGE_ISEPIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t isepic_io2_device = { - CARTRIDGE_NAME_ISEPIC, - IO_DETACH_RESOURCE, - "IsepicCartridgeEnabled", - 0xdf00, 0xdfff, 0xff, - 0, - isepic_io2_store, - isepic_io2_read, - isepic_io2_peek, - isepic_dump, - CARTRIDGE_ISEPIC, - 0, - 0 + CARTRIDGE_NAME_ISEPIC, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "IsepicCartridgeEnabled", /* resource to set to '0' */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read validity is determined by the device upon a read */ + isepic_io2_store, /* store function */ + NULL, /* NO poke function */ + isepic_io2_read, /* read function */ + isepic_io2_peek, /* peek function */ + isepic_dump, /* device state information dump function */ + CARTRIDGE_ISEPIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static const export_resource_t export_res = { @@ -177,6 +181,33 @@ static io_source_list_t *isepic_io2_list_item = NULL; /* ------------------------------------------------------------------------- */ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void isepic_powerup(void) +{ + DBG(("isepic_powerup")); + if ((isepic_filename != NULL) && (*isepic_filename != 0)) { + /* do not init ram if a file is used for ram content (like battery backup) */ + return; + } + if (isepic_ram) { + DBG(("isepic_powerup ram clear")); + ram_init_with_pattern(isepic_ram, ISEPIC_RAM_SIZE, &ramparam); + } +} + int isepic_cart_enabled(void) { if (isepic_enabled) { @@ -208,6 +239,7 @@ static int isepic_activate(void) if (isepic_ram == NULL) { isepic_ram = lib_malloc(ISEPIC_RAM_SIZE); } + ram_init_with_pattern(isepic_ram, ISEPIC_RAM_SIZE, &ramparam); if (!util_check_null_string(isepic_filename)) { log_message(LOG_DEFAULT, "Reading ISEPIC image %s.", isepic_filename); @@ -300,6 +332,18 @@ int isepic_enable(void) return 0; } + +int isepic_disable(void) +{ + DBG(("ISEPIC: disable\n")); + if (resources_set_int("IsepicCartridgeEnabled", 0) < 0) { + return -1; + } + return 0; +} + + + static int set_isepic_switch(int value, void *param) { int val = value ? 1 : 0; @@ -390,41 +434,27 @@ void isepic_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-isepic", SET_RESOURCE, 0, + { "-isepic", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicCartridgeEnabled", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_ISEPIC, - NULL, NULL }, - { "+isepic", SET_RESOURCE, 0, + NULL, "Enable the ISEPIC cartridge" }, + { "+isepic", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicCartridgeEnabled", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_ISEPIC, - NULL, NULL }, - { "-isepicimagename", SET_RESOURCE, 1, + NULL, "Disable the ISEPIC cartridge" }, + { "-isepicimagename", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "Isepicfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SET_ISEPIC_FILENAME, - NULL, NULL }, - { "-isepicimagerw", SET_RESOURCE, 0, + "", "Set ISEPIC image name" }, + { "-isepicimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_ISEPIC_IMAGE, - NULL, NULL }, - { "+isepicimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to ISEPIC image" }, + { "+isepicimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_ISEPIC_IMAGE, - NULL, NULL }, - { "-isepicswitch", SET_RESOURCE, 0, + NULL, "Do not write to ISEPIC image" }, + { "-isepicswitch", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicSwitch", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_ISEPIC_SWITCH, - NULL, NULL }, - { "+isepicswitch", SET_RESOURCE, 0, + NULL, "Enable the ISEPIC switch" }, + { "+isepicswitch", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "IsepicSwitch", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_ISEPIC_SWITCH, - NULL, NULL }, + NULL, "Disable the ISEPIC switch" }, CMDLINE_LIST_END }; @@ -435,7 +465,7 @@ int isepic_cmdline_options_init(void) /* ------------------------------------------------------------------------- */ -static BYTE isepic_io1_read(WORD addr) +static uint8_t isepic_io1_read(uint16_t addr) { DBG(("io1 r %04x (sw:%d)\n", addr, isepic_switch)); @@ -445,12 +475,12 @@ static BYTE isepic_io1_read(WORD addr) return 0; } -static BYTE isepic_io1_peek(WORD addr) +static uint8_t isepic_io1_peek(uint16_t addr) { return 0; } -static void isepic_io1_store(WORD addr, BYTE byte) +static void isepic_io1_store(uint16_t addr, uint8_t byte) { DBG(("io1 w %04x %02x (sw:%d)\n", addr, byte, isepic_switch)); @@ -459,9 +489,9 @@ static void isepic_io1_store(WORD addr, BYTE byte) } } -static BYTE isepic_io2_peek(WORD addr) +static uint8_t isepic_io2_peek(uint16_t addr) { - BYTE retval = 0; + uint8_t retval = 0; if (isepic_switch) { retval = isepic_ram[(isepic_page * 256) + (addr & 0xff)]; @@ -470,9 +500,9 @@ static BYTE isepic_io2_peek(WORD addr) return retval; } -static BYTE isepic_io2_read(WORD addr) +static uint8_t isepic_io2_read(uint16_t addr) { - BYTE retval = 0; + uint8_t retval = 0; DBG(("io2 r %04x (sw:%d) (p:%d)\n", addr, isepic_switch, isepic_page)); @@ -486,7 +516,7 @@ static BYTE isepic_io2_read(WORD addr) return retval; } -static void isepic_io2_store(WORD addr, BYTE byte) +static void isepic_io2_store(uint16_t addr, uint8_t byte) { DBG(("io2 w %04x %02x (sw:%d)\n", addr, byte, isepic_switch)); @@ -497,13 +527,13 @@ static void isepic_io2_store(WORD addr, BYTE byte) static int isepic_dump(void) { - mon_out("Page: %d, Switch: %d\n", isepic_page, isepic_switch); + mon_out("Page: %u, Switch: %d\n", isepic_page, isepic_switch); return 0; } /* ------------------------------------------------------------------------- */ -BYTE isepic_romh_read(WORD addr) +uint8_t isepic_romh_read(uint16_t addr) { if (isepic_state == ISEPIC_STATE_NMI_EXECUTING) { switch (addr) { @@ -516,7 +546,7 @@ BYTE isepic_romh_read(WORD addr) return mem_read_without_ultimax(addr); } -void isepic_romh_store(WORD addr, BYTE byte) +void isepic_romh_store(uint16_t addr, uint8_t byte) { if (isepic_state == ISEPIC_STATE_NMI_EXECUTING) { switch (addr) { @@ -524,12 +554,12 @@ void isepic_romh_store(WORD addr, BYTE byte) case 0xfffb: isepic_ram[(isepic_page * 256) + (addr & 0xff)] = byte; break; - } - } + } + } mem_store_without_ultimax(addr, byte); } -BYTE isepic_page_read(WORD addr) +uint8_t isepic_page_read(uint16_t addr) { if (isepic_switch && addr >= 0x8000 && addr < 0xa000 && isepic_state == ISEPIC_STATE_NMI_EXECUTING) { return isepic_ram[(isepic_page * 256) + (addr & 0xff)]; @@ -538,7 +568,7 @@ BYTE isepic_page_read(WORD addr) } } -void isepic_page_store(WORD addr, BYTE value) +void isepic_page_store(uint16_t addr, uint8_t value) { if (isepic_switch && addr >= 0x8000 && addr < 0xa000 && isepic_state == ISEPIC_STATE_NMI_EXECUTING) { isepic_ram[(isepic_page * 256) + (addr & 0xff)] = value; @@ -547,7 +577,7 @@ void isepic_page_store(WORD addr, BYTE value) } } -int isepic_romh_phi1_read(WORD addr, BYTE *value) +int isepic_romh_phi1_read(uint16_t addr, uint8_t *value) { if (isepic_state == ISEPIC_STATE_NMI_EXECUTING) { switch (addr) { @@ -560,12 +590,12 @@ int isepic_romh_phi1_read(WORD addr, BYTE *value) return CART_READ_C64MEM; } -int isepic_romh_phi2_read(WORD addr, BYTE *value) +int isepic_romh_phi2_read(uint16_t addr, uint8_t *value) { return isepic_romh_phi1_read(addr, value); } -int isepic_peek_mem(WORD addr, BYTE *value) +int isepic_peek_mem(uint16_t addr, uint8_t *value) { if (isepic_switch) { if ((addr >= 0x1000) && (addr <= 0xcfff)) { @@ -591,7 +621,7 @@ const char *isepic_get_file_name(void) return isepic_filename; } -void isepic_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void isepic_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { #if 0 switch (addr & 0xf000) { @@ -628,17 +658,17 @@ void isepic_config_init(void) void isepic_reset(void) { if (isepic_state == ISEPIC_STATE_NMI_EXECUTING) { - cart_config_changed_slot1(2, 2, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slot1(CMODE_RAM, CMODE_RAM, CMODE_READ | CMODE_RELEASE_FREEZE); isepic_state = ISEPIC_STATE_PROGRAMMING; } } -void isepic_config_setup(BYTE *rawcart) +void isepic_config_setup(uint8_t *rawcart) { memcpy(isepic_ram, rawcart, ISEPIC_RAM_SIZE); } -static int isepic_common_attach(BYTE *rawcart) +static int isepic_common_attach(uint8_t *rawcart) { if (resources_set_int("IsepicCartridgeEnabled", 1) < 0) { return -1; @@ -650,7 +680,7 @@ static int isepic_common_attach(BYTE *rawcart) return -1; } -static int isepic_bin_load(const char *filename, BYTE *rawcart) +static int isepic_bin_load(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, ISEPIC_RAM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -659,12 +689,13 @@ static int isepic_bin_load(const char *filename, BYTE *rawcart) return 0; } -int isepic_bin_attach(const char *filename, BYTE *rawcart) +int isepic_bin_attach(const char *filename, uint8_t *rawcart) { if (isepic_bin_load(filename, rawcart) < 0) { return -1; } + /* set the resource */ if (set_isepic_filename(filename, NULL) < 0) { return -1; } @@ -694,7 +725,7 @@ int isepic_bin_save(const char *filename) return 0; } -static int isepic_crt_load(FILE *fd, BYTE *rawcart) +static int isepic_crt_load(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -714,11 +745,12 @@ static int isepic_crt_load(FILE *fd, BYTE *rawcart) return 0; } -int isepic_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int isepic_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { if (isepic_crt_load(fd, rawcart) < 0) { return -1; } + /* set the resource */ if (set_isepic_filename(filename, NULL) < 0) { return -1; } @@ -795,7 +827,7 @@ void isepic_detach(void) ARRAY | RAM | 2048 BYTES of RAM data */ -static char snap_module_name[] = "CARTISEPIC"; +static const char snap_module_name[] = "CARTISEPIC"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -810,9 +842,9 @@ int isepic_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)isepic_enabled) < 0) - || (SMW_B(m, (BYTE)isepic_switch) < 0) - || (SMW_B(m, (BYTE)isepic_page) < 0) + || (SMW_B(m, (uint8_t)isepic_enabled) < 0) + || (SMW_B(m, (uint8_t)isepic_switch) < 0) + || (SMW_B(m, (uint8_t)isepic_page) < 0) || (SMW_BA(m, isepic_ram, ISEPIC_RAM_SIZE) < 0)) { snapshot_module_close(m); return -1; @@ -823,7 +855,7 @@ int isepic_snapshot_write_module(snapshot_t *s) int isepic_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -833,7 +865,7 @@ int isepic_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; diff --git a/src/Emulators/vice/c64/cart/isepic.h b/src/Emulators/vice/c64/cart/isepic.h index 4a41f9b3..6d8dc389 100644 --- a/src/Emulators/vice/c64/cart/isepic.h +++ b/src/Emulators/vice/c64/cart/isepic.h @@ -35,39 +35,42 @@ #include "vicetypes.h" -extern int isepic_cart_enabled(void); -extern int isepic_cart_active(void); -extern int isepic_freeze_allowed(void); -extern void isepic_freeze(void); -extern void isepic_reset(void); -extern void isepic_config_init(void); -extern void isepic_config_setup(BYTE *rawcart); +int isepic_cart_enabled(void); +int isepic_cart_active(void); +int isepic_freeze_allowed(void); +void isepic_freeze(void); +void isepic_reset(void); +void isepic_config_init(void); +void isepic_config_setup(uint8_t *rawcart); +void isepic_powerup(void); -extern int isepic_resources_init(void); -extern void isepic_resources_shutdown(void); -extern int isepic_cmdline_options_init(void); +int isepic_resources_init(void); +void isepic_resources_shutdown(void); +int isepic_cmdline_options_init(void); -extern BYTE isepic_romh_read(WORD addr); -extern void isepic_romh_store(WORD addr, BYTE byte); -extern BYTE isepic_page_read(WORD addr); -extern void isepic_page_store(WORD addr, BYTE byte); -extern int isepic_romh_phi1_read(WORD addr, BYTE *value); -extern int isepic_romh_phi2_read(WORD addr, BYTE *value); -extern int isepic_peek_mem(WORD addr, BYTE *value); -extern void isepic_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +uint8_t isepic_romh_read(uint16_t addr); +void isepic_romh_store(uint16_t addr, uint8_t byte); +uint8_t isepic_page_read(uint16_t addr); +void isepic_page_store(uint16_t addr, uint8_t byte); +int isepic_romh_phi1_read(uint16_t addr, uint8_t *value); +int isepic_romh_phi2_read(uint16_t addr, uint8_t *value); +int isepic_peek_mem(uint16_t addr, uint8_t *value); +void isepic_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern int isepic_bin_attach(const char *filename, BYTE *rawcart); -extern int isepic_bin_save(const char *filename); -extern int isepic_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern int isepic_crt_save(const char *filename); -extern int isepic_flush_image(void); -extern void isepic_detach(void); -extern int isepic_enable(void); +int isepic_bin_attach(const char *filename, uint8_t *rawcart); +int isepic_bin_save(const char *filename); +int isepic_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int isepic_crt_save(const char *filename); +int isepic_flush_image(void); +void isepic_detach(void); +int isepic_enable(void); +int isepic_disable(void); -extern const char *isepic_get_file_name(void); +const char *isepic_get_file_name(void); struct snapshot_s; -extern int isepic_snapshot_read_module(struct snapshot_s *s); -extern int isepic_snapshot_write_module(struct snapshot_s *s); + +int isepic_snapshot_read_module(struct snapshot_s *s); +int isepic_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/kcs.c b/src/Emulators/vice/c64/cart/kcs.c index 277ee888..bcdd1cc7 100644 --- a/src/Emulators/vice/c64/cart/kcs.c +++ b/src/Emulators/vice/c64/cart/kcs.c @@ -41,6 +41,7 @@ #include "log.h" #include "maincpu.h" #include "monitor.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" @@ -96,29 +97,31 @@ * */ +#define CART_RAM_SIZE 128 + static int config; -static BYTE kcs_io1_read(WORD addr) +static uint8_t kcs_io1_read(uint16_t addr) { config = (addr & 2) ? CMODE_RAM : CMODE_8KGAME; - cart_config_changed_slotmain((BYTE)config, (BYTE)config, CMODE_READ); + cart_config_changed_slotmain((uint8_t)config, (uint8_t)config, CMODE_READ); return roml_banks[0x1e00 + (addr & 0xff)]; } -static BYTE kcs_io1_peek(WORD addr) +static uint8_t kcs_io1_peek(uint16_t addr) { return roml_banks[0x1e00 + (addr & 0xff)]; } -static void kcs_io1_store(WORD addr, BYTE value) +static void kcs_io1_store(uint16_t addr, uint8_t value) { config = (addr & 2) ? CMODE_ULTIMAX : CMODE_16KGAME; - cart_config_changed_slotmain((BYTE)config, (BYTE)config, CMODE_WRITE); + cart_config_changed_slotmain((uint8_t)config, (uint8_t)config, CMODE_WRITE); } -static BYTE kcs_io2_read(WORD addr) +static uint8_t kcs_io2_read(uint16_t addr) { /* the software reads from df80 at beginning of nmi handler */ /* to determine the status of GAME and EXROM lines */ @@ -128,7 +131,7 @@ static BYTE kcs_io2_read(WORD addr) return export_ram0[addr & 0x7f]; } -static BYTE kcs_io2_peek(WORD addr) +static uint8_t kcs_io2_peek(uint16_t addr) { if (addr & 0x80) { return ((config & 2) ? 0x80 : 0) | ((config & 1) ? 0 : 0x40); /* DF80-DFFF actual config */ @@ -136,7 +139,7 @@ static BYTE kcs_io2_peek(WORD addr) return export_ram0[addr & 0x7f]; } -static void kcs_io2_store(WORD addr, BYTE value) +static void kcs_io2_store(uint16_t addr, uint8_t value) { if (addr & 0x80) { return; /* open area for GAME/EXROM status */ @@ -146,40 +149,44 @@ static void kcs_io2_store(WORD addr, BYTE value) static int kcs_io1_dump(void) { - mon_out("EXROM: %d GAME: %d (%s)\n", ((config >> 1) & 1), (config & 1) ^ 1, cart_config_string((BYTE)(config & 3))); + mon_out("EXROM: %d GAME: %d (%s)\n", ((config >> 1) & 1), (config & 1) ^ 1, cart_config_string((uint8_t)(config & 3))); return 0; } /* ---------------------------------------------------------------------*/ static io_source_t kcs_io1_device = { - CARTRIDGE_NAME_KCS_POWER, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - kcs_io1_store, - kcs_io1_read, - kcs_io1_peek, - kcs_io1_dump, - CARTRIDGE_KCS_POWER, - 0, - 0 + CARTRIDGE_NAME_KCS_POWER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + kcs_io1_store, /* store function */ + NULL, /* NO poke function */ + kcs_io1_read, /* read function */ + kcs_io1_peek, /* peek function */ + kcs_io1_dump, /* device state information dump function */ + CARTRIDGE_KCS_POWER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t kcs_io2_device = { - CARTRIDGE_NAME_KCS_POWER, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - kcs_io2_store, - kcs_io2_read, - kcs_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_KCS_POWER, - 0, - 0 + CARTRIDGE_NAME_KCS_POWER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + kcs_io2_store, /* store function */ + NULL, /* NO poke function */ + kcs_io2_read, /* read function */ + kcs_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_KCS_POWER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *kcs_io1_list_item = NULL; @@ -194,25 +201,44 @@ static const export_resource_t export_res_kcs = { void kcs_freeze(void) { config = CMODE_ULTIMAX; - cart_config_changed_slotmain((BYTE)config, (BYTE)config, CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain((uint8_t)config, (uint8_t)config, CMODE_READ | CMODE_RELEASE_FREEZE); } void kcs_config_init(void) { config = CMODE_16KGAME; - cart_config_changed_slotmain((BYTE)config, (BYTE)config, CMODE_READ); + cart_config_changed_slotmain((uint8_t)config, (uint8_t)config, CMODE_READ); } -void kcs_config_setup(BYTE *rawcart) +void kcs_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); config = CMODE_16KGAME; - cart_config_changed_slotmain((BYTE)config, (BYTE)config, CMODE_READ); + cart_config_changed_slotmain((uint8_t)config, (uint8_t)config, CMODE_READ); } /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void kcs_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + static int kcs_common_attach(void) { if (export_add(&export_res_kcs) < 0) { @@ -224,7 +250,7 @@ static int kcs_common_attach(void) return 0; } -int kcs_bin_attach(const char *filename, BYTE *rawcart) +int kcs_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -232,7 +258,7 @@ int kcs_bin_attach(const char *filename, BYTE *rawcart) return kcs_common_attach(); } -int kcs_crt_attach(FILE *fd, BYTE *rawcart) +int kcs_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -277,7 +303,7 @@ void kcs_detach(void) Note: in snapshots before 0.3 the RAM size was 8192. */ -static char snap_module_name[] = "CARTKCS"; +static const char snap_module_name[] = "CARTKCS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 3 @@ -292,7 +318,7 @@ int kcs_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)config) < 0 + || SMW_B(m, (uint8_t)config) < 0 || SMW_BA(m, roml_banks, 0x2000) < 0 || SMW_BA(m, romh_banks, 0x2000) < 0 || SMW_BA(m, export_ram0, 128) < 0) { @@ -305,9 +331,9 @@ int kcs_snapshot_write_module(snapshot_t *s) int kcs_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; - BYTE dummy; + uint8_t dummy; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -316,20 +342,20 @@ int kcs_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* added in 0.1, removed in 0.3 */ - if (SNAPVAL(vmajor, vminor, 0, 1) && !SNAPVAL(vmajor, vminor, 0, 3)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1) && snapshot_version_is_smaller(vmajor, vminor, 0, 3)) { if (SMR_B(m, &dummy) < 0) { goto fail; } } /* new in 0.2 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (SMR_B_INT(m, &config) < 0) { goto fail; } @@ -344,7 +370,7 @@ int kcs_snapshot_read_module(snapshot_t *s) } /* 0x80 in 0.3, 0x2000 before that */ - if (SNAPVAL(vmajor, vminor, 0, 3)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 3)) { if (SMR_BA(m, export_ram0, 128) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/kcs.h b/src/Emulators/vice/c64/cart/kcs.h index a6f80485..e519eb23 100644 --- a/src/Emulators/vice/c64/cart/kcs.h +++ b/src/Emulators/vice/c64/cart/kcs.h @@ -31,17 +31,18 @@ #include "vicetypes.h" -extern void kcs_freeze(void); +void kcs_freeze(void); -extern void kcs_config_init(void); -extern void kcs_config_setup(BYTE *rawcart); -extern int kcs_bin_attach(const char *filename, BYTE *rawcart); -extern int kcs_crt_attach(FILE *fd, BYTE *rawcart); -extern void kcs_detach(void); +void kcs_config_init(void); +void kcs_config_setup(uint8_t *rawcart); +int kcs_bin_attach(const char *filename, uint8_t *rawcart); +int kcs_crt_attach(FILE *fd, uint8_t *rawcart); +void kcs_detach(void); +void kcs_powerup(void); struct snapshot_s; -extern int kcs_snapshot_write_module(struct snapshot_s *s); -extern int kcs_snapshot_read_module(struct snapshot_s *s); +int kcs_snapshot_write_module(struct snapshot_s *s); +int kcs_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/kingsoft.c b/src/Emulators/vice/c64/cart/kingsoft.c index 36dfe2ba..8d140221 100644 --- a/src/Emulators/vice/c64/cart/kingsoft.c +++ b/src/Emulators/vice/c64/cart/kingsoft.c @@ -45,6 +45,9 @@ #include "util.h" #include "crt.h" +#include "kingsoft.h" + + /* Kingsoft Cartridge ("business basic" aka "s'more") @@ -85,18 +88,18 @@ static void setmode(int m) } } -static BYTE kingsoft_io1_read(WORD addr) +static uint8_t kingsoft_io1_read(uint16_t addr) { setmode(0); return 0; } -static void kingsoft_io1_store(WORD addr, BYTE value) +static void kingsoft_io1_store(uint16_t addr, uint8_t value) { setmode(1); } -static BYTE kingsoft_io1_peek(WORD addr) +static uint8_t kingsoft_io1_peek(uint16_t addr) { return mode; } @@ -110,18 +113,20 @@ static int kingsoft_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t kingsoft_device = { - CARTRIDGE_NAME_KINGSOFT, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - kingsoft_io1_store, - kingsoft_io1_read, - kingsoft_io1_peek, - kingsoft_dump, - CARTRIDGE_KINGSOFT, - 0, - 0 + CARTRIDGE_NAME_KINGSOFT, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + kingsoft_io1_store, /* store function */ + NULL, /* NO poke function */ + kingsoft_io1_read, /* read function */ + kingsoft_io1_peek, /* peek function */ + kingsoft_dump, /* device state information dump function */ + CARTRIDGE_KINGSOFT, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *kingsoft_list_item = NULL; @@ -133,13 +138,13 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -BYTE kingsoft_roml_read(WORD addr) +uint8_t kingsoft_roml_read(uint16_t addr) { return roml_banks[(addr & 0x1fff)]; } /* ROMH read - mapped to A000 in 16k, to E000 in ultimax */ -BYTE kingsoft_romh_read(WORD addr) +uint8_t kingsoft_romh_read(uint16_t addr) { return romh_banks[(addr & 0x1fff) + (mode << 13)]; } @@ -151,7 +156,7 @@ void kingsoft_config_init(void) setmode(0); } -void kingsoft_config_setup(BYTE *rawcart) +void kingsoft_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); @@ -169,7 +174,7 @@ static int kingsoft_common_attach(void) return 0; } -int kingsoft_bin_attach(const char *filename, BYTE *rawcart) +int kingsoft_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x6000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -177,7 +182,7 @@ int kingsoft_bin_attach(const char *filename, BYTE *rawcart) return kingsoft_common_attach(); } -int kingsoft_crt_attach(FILE *fd, BYTE *rawcart) +int kingsoft_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -215,7 +220,7 @@ void kingsoft_detach(void) ARRAY | ROMH | 16384 BYTES of ROMH data */ -static char snap_module_name[] = "CARTKINGSOFT"; +static const char snap_module_name[] = "CARTKINGSOFT"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -230,7 +235,7 @@ int kingsoft_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)mode) < 0) + || (SMW_B(m, (uint8_t)mode) < 0) || (SMW_BA(m, roml_banks, 0x2000) < 0) || (SMW_BA(m, romh_banks, 0x4000) < 0)) { snapshot_module_close(m); @@ -242,7 +247,7 @@ int kingsoft_snapshot_write_module(snapshot_t *s) int kingsoft_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -252,7 +257,7 @@ int kingsoft_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/kingsoft.h b/src/Emulators/vice/c64/cart/kingsoft.h index d0a6bc74..91fc965f 100644 --- a/src/Emulators/vice/c64/cart/kingsoft.h +++ b/src/Emulators/vice/c64/cart/kingsoft.h @@ -31,18 +31,18 @@ #include "vicetypes.h" -extern void kingsoft_config_init(void); -extern void kingsoft_config_setup(BYTE *rawcart); -extern int kingsoft_bin_attach(const char *filename, BYTE *rawcart); -extern int kingsoft_crt_attach(FILE *fd, BYTE *rawcart); -extern void kingsoft_detach(void); +void kingsoft_config_init(void); +void kingsoft_config_setup(uint8_t *rawcart); +int kingsoft_bin_attach(const char *filename, uint8_t *rawcart); +int kingsoft_crt_attach(FILE *fd, uint8_t *rawcart); +void kingsoft_detach(void); -extern BYTE kingsoft_roml_read(WORD addr); -extern BYTE kingsoft_romh_read(WORD addr); +uint8_t kingsoft_roml_read(uint16_t addr); +uint8_t kingsoft_romh_read(uint16_t addr); struct snapshot_s; -extern int kingsoft_snapshot_write_module(struct snapshot_s *s); -extern int kingsoft_snapshot_read_module(struct snapshot_s *s); +int kingsoft_snapshot_write_module(struct snapshot_s *s); +int kingsoft_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/ltkernal.c b/src/Emulators/vice/c64/cart/ltkernal.c new file mode 100644 index 00000000..7b056765 --- /dev/null +++ b/src/Emulators/vice/c64/cart/ltkernal.c @@ -0,0 +1,1423 @@ +/* + * ltkernal.c - Cartridge handling, Lt. Kernal Host Adapter + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cart.h" +#include "c64mem.h" +#include "c64cartmem.h" +#include "c64pla.h" +#include "c64-generic.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "ltkernal.h" +#include "maincpu.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "lib.h" +#include "machine.h" +#include "ram.h" +#include "resources.h" +#include "cmdline.h" +#include "maincpu.h" +#include "log.h" +#include "mc6821core.h" +#include "scsi.h" +#include "c64memrom.h" +#include "alarm.h" + +/* #define LTKLOG1 */ +/* #define LTKLOG2 */ +/* #define LTKDEBUGIO */ +/* #define LTKDEBUGMEM */ + +#define LOG LOG_DEFAULT + +#ifdef LTKDEBUGMEM +#define MDBG(_x_) log_message _x_ +#else +#define MDBG(_x_) +#endif + +#ifdef LTKDEBUGIO +#define IDBG(_x_) log_message _x_ +#else +#define IDBG(_x_) +#endif + +#ifdef LTKLOG1 +#define LOG1(_x_) log_message _x_ +#else +#define LOG1(_x_) +#endif + +#ifdef LTKLOG2 +#define LOG2(_x_) log_message _x_ +#else +#define LOG2(_x_) +#endif + +#define CRIT(_x_) log_error _x_ + +#if C64CART_ROM_LIMIT <= 16384 +#error C64CART_ROM_LIMIT is too small; it should be at least 16384. +#endif + +/* + +Lt. Kernal + +*** Brief IO explanation *** + +Write $3C to $Dx03 Enables stock kernal (sets CB2 high) +Write $34 to $Dx03 Enables upper RAM as kernal (sets CB2 low) + +Write $40 (bit 6) to $Dx02 enables writes to kernal and lower RAM to $8000-$9fff + only when the upper ram kernal is enabled +Clear $40 (bit 6) of $Dx02 disable writes to kernal and disables lower RAM + +If bit 6 of $Dx02 is 0 when bit 3 of $Dx03 is set, the system reset timer + is started and will assert in 57 cycles + Setting bit 6 of $Dx02 or clearing vit 2 of $Dx03 will cancel it + +Setting bit 6 of $Dx02 to 1 when $Dx03 bit 3 is low turns off ROM + +*** Detailed explanation *** + + The Lt. Kernal Host Adaptor (SCSI ID 7) looks on sector 0 of drive 0 (ID +0) to find the partition (LU or logical unit) information and DOS. The DOS +(official latest 7.2) is limited by the original cylinder/head/sector (CHS) +addressing schemes of legacy hard disks, but it doesn't use that when +accessing them; it uses the modern logical block address, although this may +have not been the case in the original version. The CHS is used when +configuring its filing system for each LU. You should never have a disk +configured with more than 15 heads or have the product of the heads and +sectors that exceeds 255 as it will cause data corruption. The DOS also cannot +access an LU which starts beyond cylinder 1023. The solution to this, at the +time, was to use more than one disk. This emulation supports up to 7 drives. +The Lt. Kernal sold in 20 MB and 40 MB versions, so these issues were never +addressed officially. The DOS install disks are keyed to the host adaptors and +hard disks (see LTKserial), so any additions or modifications were done by the +company, Xetec, and sent to the customer on new install disks. Unofficially, +to use a larger disk, the information on track 18, sector 18 of the first +install disk needs to be modified; LTKEDIT2 is a tool which does this. Be +warned it does not check for invalid information. Some of the configurations +LTKEDIT2 offers will cause data corruption as the CHS combinations are too +high. An easy and quick way to check this is to VALIDATE a new LU after +ACTIVATING it. + + The Lt. Kernal Host Adaptor uses the following registers: + + $DF00 = MC6821 Port A: Data and DDR + $DF01 = MC6821 Port A: Control + $DF02 = MC6821 Port B: Data and DDR + $DF03 = MC6821 Port B: Control + $DF04..7 = LTK Port and Freeze state + +MC6821 Port A connects to the SCSI data bus (inverted). Data is saved to hard +disk inverted to save data processing time. The adaptor doesn't use a proper +open-collector driver for the databus, rather a 74LS245 tri-state buffer (that +drives high signals rather than the line termination) controlled by the SCSI +IO line. The SCSI data bus is terminated by drive 0, while the SCSI RST, SEL, +ACK, and ATN signals are pulled up on the adaptor, therefore terminated there. +SCSI signals RST, SEL, and ACK are driven by proper open-collectors on the +adaptor. The DB25 connector on the adaptor is NOT a standard SCSI DB25. +Connecting anything other than an official Lt. Kernal drive will likely cause +damage to the host adaptor. + + signal meaning + ------ ------- + PA 7-0 /Data bus on SCSI (input/output) + CA2 Pulses SCSI ACK (low to high) + +MC6821 Port B connects to mostly the SCSI control bus. PB2.6 controls write +access to 16KiB SRAM. When low (0), no writes are permitted, when high (1) +writes are permitted to $8000-$9FFF AND $E000-$FFFF. Initially, this signal is +low, which keeps the boot ROM mapped to $8000-$9FFF (lower 4KiB for the C64, +upper 4KiB for the C128). Once a high (1) is written, the boot ROM is mapped +out permanently until a reset. CB2 controls which KERNAL is in place. A high +(1) uses the stock KERNAL while a low (0) maps in one of the 8K RAMs as the +KERNAL. The other RAM at $8000-$9FFF memory is ONLY mapped in when PB2.6 is +high (1). The HIRAM line from the PLA goes to the adaptor so it can determine +the proper write action to the main RAM or adaptor RAM. Writing a high (1) to +CB2 while PB2.6 is low (0) queues up a system reset. If CB2 is not set back +to a low (0) or PB2.6 to a high (1), a reset will be asserted in 57 cycles. +On startup, the existing kernal is copied and patched by the LTK DOS. On the +C64, all known kernal versions work, however in C128 mode, only the original +kernal is compatible with the latest LTK DOS (7.2). Make sure to use the +318020-03 kernal (also known as the first version). The LTK DOS overwrites +the new patches to the second and third kernal versions. +The LTK DOS (located at the beginning of the hard drive) is constantly loading +in different modules depending on the actions taken. For example, a call to +the kernal open function will result in the "open" code to be loaded off the +hard disk into the $8000-$9FFF area. This can result in a lot of hard disk +"thrashing" depending on the distance of current LU and the DOS. The LTK +offers the ability to create a "DOS image" (a copy of the DOS, but in a single +file) in each LU to reduce the hard disk seek times when accessing different +parts of LU and the DOS. This feature shouldn't be required in emulation as +the speed of the hard disk access is essentially instantaneous on modern +hardware. Other utilities such as DIR, and VALIDATE, load into $C000-CFFF. +Prior to this, the LTK saves those contents of memory into a reserved space in +the DOS and restores them once the utility has terminated. This may cause some +compatibility problems if you have interrupt or service vectors which point to +that area. + + signal meaning + ------ ------- + PB 7 /REQ on SCSI (input) + PB 6 SRAM control + PB 5 RST on SCSI (output) + PB 4 SEL on SCSI (output) + PB 3 /BUSY on SCSI (input) + PB 2 /CD on SCSI (input) + PB 1 /MSG on SCSI (input) + PB 0 /IO on SCSI (input) + CB2 KERNAL control + +$DF04 - $DF07: + +The LTK Port can be between 0 and 15. Only adaptors set to port 0 are allowed +to change the host configuration. + + bit meaning + --- ------- + 3-0 LTK port number (input) + 4 Freeze state (0: active, 1: inactive) + +*** C128 MMU *** + +The LTK cannot work on a real C128 without a MMU daughterboard. This board +is quite a simple in design, but requires a 10 pin ribbon cable back to the +LTK adapter (unlike the CMD SuperCPU daugthercard which has on board registers +to control the MMU behavior). On a C64, there is no ribbon cable, but 2 sets +of pins are shorted, and the HIRAM and CAEC lines are brought to the adapter. +Essentially, this daughterboard intercepts the pin 47 (C128/C64 mode) which +eventually goes to the PLA. The daughtercard processes the HIRAM line from the +CPU as well as the C128/C64, and MS1 lines from the MMU. +When in C64 mode, the HIRAM line is brought to the adapter where a 1 indicates +ROM access, and a 0 RAM access. However in C128 mode, MS1 (0=ROM or EXT +function) from the MMU is inverted and brought back to the adapter. +Once the address and psuedo HIRAM line is processed, the adapter will map +in either the $8000-$9fff or $e000-$ffff using a C64 cartridge mode (eg. +Ultimax) by placing the PLA in 64 mode. Since the output of the MMU to the PLA +is redirected, this can be switched for any memory access. In situations where +the daughtercard is not connected to the adapter, a pullup ensures the MMU +output always reaches the PLA undisturbed. +Other connections back to the adapter will relay that the system is actively +connected to the daughtercard (hence in a C128), so the adapter always boots +up using the second half of the boot ROM, which operates as an external +function ROM in C128 mode. The EXROM and GAME lines are set accordingly so the +system boots into C128 mode. +Given the above behavior, the LTK DOS must boot into C128 mode. To go to C64 +mode, the "go64" command can be used, but it does not perform the typical +stock routine. Here, it is redirected to create a C64 stlye boot ROM in RAM, +then the MMU is switched to C64 mode and the PC jumps to the $FFFC vector. +Since the adapter has the ability to reset the system. C128 mode can be +entered via C64 mode (via "go128") as a hard reset is asserted. + +*/ + +#define CART_RAM_SIZE (16 * 1024) + +/* largest supported HD in 512 bytes sectors for LTK for DOS up to 7.3 */ +#define ltk_imagesize (32 * 1024 * 1024 * 10 / 512) + +static int ltk_inserted = 0; + +static uint8_t ltk_rom; +static uint8_t ltk_raml; +static uint8_t ltk_ramh; +static uint8_t ltk_ramwrite; +static uint8_t ltk_freeze; +static uint8_t ltk_on; +static uint8_t ltk_in2; +struct alarm_s *ltk_alarm; +static CLOCK ltk_alarm_time; + +/* resources */ +static int ltk_io = 1; /* (0=$dexx, 1=$dfxx) */ +static int ltk_port = 0; +static char *ltk_serial = NULL; +static char *ltk_disk[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +static mc6821_state ltk_6821; + +/* some prototypes are needed */ +static uint8_t ltkernal_io_read(uint16_t addr); +static uint8_t ltkernal_io_peek(uint16_t addr); +static void ltkernal_io_store(uint16_t addr, uint8_t value); +static int ltkernal_io_dump(void); + +static io_source_t ltkernal_io_device = { + CARTRIDGE_NAME_LT_KERNAL, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0x07, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + ltkernal_io_store, /* store function */ + NULL, /* NO poke function */ + ltkernal_io_read, /* read function */ + ltkernal_io_peek, /* peek function */ + ltkernal_io_dump, /* device state information dump function */ + CARTRIDGE_LT_KERNAL, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *ltkernal_io_list_item = NULL; + +static const export_resource_t export_res_plus = { + CARTRIDGE_NAME_LT_KERNAL, 1, 1, NULL, <kernal_io_device, CARTRIDGE_LT_KERNAL +}; + +static const char ltk_scsi_name[] = {"LTKSCSI"}; +static scsi_context_t ltk_scsi; + +/* ---------------------------------------------------------------------*/ +static int ltkernal_check_scpu64(void) +{ + /* disable LTK completely under scpu64 */ + if ( machine_class == VICE_MACHINE_SCPU64 ) { + ltk_rom = 0; + ltk_raml = 0; + ltk_ramh = 0; + ltk_freeze = 0; + ltk_on = 0; + return 1; + } + + return 0; +} + +static void ltkernal_cancel_alarm(void) +{ + if (ltk_alarm_time != CLOCK_MAX) { + LOG2((LOG, "LTK RESET CANCELLED")); + alarm_unset(ltk_alarm); + ltk_alarm_time = CLOCK_MAX; + } +} + +static void ltkernal_alarm_handler(CLOCK offset, void *data) +{ + ltkernal_cancel_alarm(); + LOG2((LOG, "LTK RESET at 0x%04x", reg_pc)); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); +} + +static int ltkernal_registerio(void) +{ + LOG2((LOG, "LTK registerio")); + + if (ltkernal_io_list_item) { + return 0; + } + + if (export_add(&export_res_plus) < 0) { + return -1; + } + + if (ltk_io < LTKIO_DE00 || ltk_io > LTKIO_DF00) { + ltk_io = LTKIO_DF00; + } + + ltkernal_io_device.start_address = 0xde00 + ltk_io * 256; + ltkernal_io_device.end_address = ltkernal_io_device.start_address + 255; + + LOG1((LOG, "LTK IO is at $%02xxx", + (unsigned int)(ltk_io == LTKIO_DE00 ? 0xde : 0xdf))); + + ltkernal_io_list_item = io_source_register(<kernal_io_device); + + ltk_alarm = alarm_new(maincpu_alarm_context, "LTKResetAlarm", ltkernal_alarm_handler, NULL); + ltk_alarm_time = CLOCK_MAX; + + return 0; +} + +static void ltkernal_unregisterio(void) +{ + LOG2((LOG, "LTK unregisterio")); + + if (!ltkernal_io_list_item) { + return; + } + + export_remove(&export_res_plus); + io_source_unregister(ltkernal_io_list_item); + ltkernal_io_list_item = NULL; + alarm_destroy(ltk_alarm); +} + +static int set_port(int port, void *param) +{ + if (port < 0 || port > 15) { + return -1; + } + + ltk_port = port; + LOG1((LOG, "LTK port = %d", port)); + + return 0; +} + +static int set_io(int io, void *param) +{ + if (io < LTKIO_DE00 || io > LTKIO_DF00) { + return -1; + } + + ltk_io = io; + + if (ltk_inserted) { + ltkernal_unregisterio(); + if (ltkernal_registerio()) { + return -1; + } + } + + LOG1((LOG, "LTK IO = %d ($%02xxx)", io, + (unsigned int)(io == LTKIO_DE00 ? 0xde : 0xdf))); + + return 0; +} + +static const resource_int_t resources_int[] = { + { "LTKport", 0, RES_EVENT_NO, NULL, <k_port, set_port, 0 }, + { "LTKio", LTKIO_DF00, RES_EVENT_NO, NULL, <k_io, set_io, 0 }, + RESOURCE_INT_LIST_END +}; + +static int set_image_file(const char *name, void *param) +{ + int i = vice_ptr_to_int(param); + + if (i < 0 || i > 6) { + return -1; + } + + util_string_set(&(ltk_disk[i]), name); + LOG1((LOG, "LTK image[%d] = '%s'", i, name)); + + /* apply changes */ + if (ltk_inserted) { + scsi_image_detach(<k_scsi, i << 3); + scsi_image_attach(<k_scsi, i << 3, ltk_disk[i]); + } + + return 0; +} + +static int set_serial(const char *name, void *param) +{ + int l, i, j; + + if (!name) { + CRIT((LOG, "LTK serial number - nothing provided.")); + return 1; + } + + l = 0; + while (name[l]) { + l++; + } + + if (l != 8) { + CRIT((LOG, "LTK serial number '%s' is not 8 digits.", name)); + return 1; + } + + for (i = 0; i < 8; i++) { + j = name[i]; + if ( j < '0' || j > '9') { + CRIT((LOG, "LTK serial number '%s' has invalid character '%c'.", + name, j)); + return 1; + } + ltk_serial[i] = j; + } + + memcpy(&(roml_banks[10]), ltk_serial, 8); + memcpy(&(roml_banks[4096 + 10]), ltk_serial, 8); + LOG1((LOG, "LTK serial = '%s'", name)); + + return 0; +} + +static const resource_string_t resources_string[] = { + { "LTKimage0", "", RES_EVENT_NO, NULL, + &(ltk_disk[0]), set_image_file, (void *)0 }, + { "LTKimage1", "", RES_EVENT_NO, NULL, + &(ltk_disk[1]), set_image_file, (void *)1 }, + { "LTKimage2", "", RES_EVENT_NO, NULL, + &(ltk_disk[2]), set_image_file, (void *)2 }, + { "LTKimage3", "", RES_EVENT_NO, NULL, + &(ltk_disk[3]), set_image_file, (void *)3 }, + { "LTKimage4", "", RES_EVENT_NO, NULL, + &(ltk_disk[4]), set_image_file, (void *)4 }, + { "LTKimage5", "", RES_EVENT_NO, NULL, + &(ltk_disk[5]), set_image_file, (void *)5 }, + { "LTKimage6", "", RES_EVENT_NO, NULL, + &(ltk_disk[6]), set_image_file, (void *)6 }, + { "LTKserial", "87000000", RES_EVENT_NO, NULL, + <k_serial, set_serial, (void *)0 }, + RESOURCE_STRING_LIST_END +}; + +static const cmdline_option_t cmdline_options[] = +{ + { "-ltkimage0", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage0", NULL, + "", "Specify name of LTK image file 0" }, + { "-ltkimage1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage1", NULL, + "", "Specify name of LTK image file 1" }, + { "-ltkimage2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage2", NULL, + "", "Specify name of LTK image file 2" }, + { "-ltkimage3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage3", NULL, + "", "Specify name of LTK image file 3" }, + { "-ltkimage4", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage4", NULL, + "", "Specify name of LTK image file 4" }, + { "-ltkimage5", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage5", NULL, + "", "Specify name of LTK image file 5" }, + { "-ltkimage6", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKimage6", NULL, + "", "Specify name of LTK image file 6" }, + { "-ltkserial", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKserial", NULL, + "", "Specify LTK serial number (XXXXXXXX) to override the ROM" }, + { "-ltkport", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKport", NULL, + "", "Set LTK port number (0..15)" }, + { "-ltkio", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "LTKio", NULL, + "", "Set LTK IO page (0=$DExx, 1=$DFxx=default)" }, + CMDLINE_LIST_END +}; + +int ltkernal_cmdline_options_init(void) +{ + if (cmdline_register_options(cmdline_options) < 0) { + return -1; + } + + return 0; +} + +int ltkernal_resources_init(void) +{ + int i; + + LOG2((LOG, "LTK resource init")); + + if (ltkernal_check_scpu64()) { + return 0; + } + + ltk_serial = lib_strdup("00000000"); + + for (i = 0; i < 7; i++) { + ltk_disk[i] = NULL; + } + if (resources_register_string(resources_string) < 0) { + return -1; + } + if (resources_register_int(resources_int) < 0) { + return -1; + } + + return 0; +} + +int ltkernal_resources_shutdown(void) +{ + int i; + + LOG2((LOG, "LTK resource shutdown")); + + for (i = 0; i < 7; i++) { + if (ltk_disk[i]) { + lib_free(ltk_disk[i]); + } + ltk_disk[i] = NULL; + } + + if (ltk_serial) { + lib_free(ltk_serial); + } + ltk_serial = NULL; + + return 0; +} + +static void ltk_imageopenall(void) +{ + int32_t i; + + /* purge out any old or stall file handles */ + for (i = 0; i < 56; i++) { + ltk_scsi.file[i] = NULL; + } + + /* setup new ones */ + for (i = 0; i < 7; i++) { + scsi_image_attach(<k_scsi, i << 3, ltk_disk[i]); + } + + return; +} + +/* ---------------------------------------------------------------------*/ + +static uint8_t ltk_get_pa(mc6821_state *ctx) +{ + uint8_t val; + scsi_context_t *scsi = (scsi_context_t*)ctx->p; + + val = scsi_get_bus(scsi); + IDBG((LOG, "GET PA 0x%02x", val)); + + return val; +} + +static uint8_t ltk_get_pb(mc6821_state *ctx) +{ + uint8_t val; + scsi_context_t *scsi = (scsi_context_t*)ctx->p; + + scsi_process_noack(scsi); + ltk_in2 = (ltk_in2 & 0x70) | ((!scsi->req) << 7) | ((!scsi->bsyo) << 3) | + ((!scsi->cd) << 2) | ((!scsi->msg)<<1) | (!scsi->io); + val = ltk_in2; + + return val; +} + +static void ltk_set_ca2(mc6821_state *ctx) +{ + scsi_context_t *scsi = (scsi_context_t*)ctx->p; + + IDBG((LOG, "SET CA2 called at %04x", reg_pc)); + + if (ctx->CA2) { + scsi_process_ack(scsi); + } +} + +static uint8_t ltkernal_io_read(uint16_t addr) +{ + int port, reg; + uint8_t val = 0; + + if (ltk_on) { + IDBG((LOG, "--------------------")); + + if (addr & 0x4) { + val = (ltk_port & 15) | ( (!ltk_freeze) << 4 ); + } else { + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + val = mc6821core_read(<k_6821, port /* rs1 */, reg /* rs0 */); + } + + IDBG((LOG, "LTK io r %04x = %02x at 0x%04x", addr, val, reg_pc)); + } + + return val; +} + +static uint8_t ltkernal_io_peek(uint16_t addr) +{ + int port, reg; + uint8_t val = 0; + + if (ltk_on) { + if (addr & 0x4) { + val = (ltk_port & 15) | ( (!ltk_freeze) << 4 ); + } else { + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + val = mc6821core_peek(<k_6821, port /* rs1 */, reg /* rs0 */); + } + + IDBG((LOG, "LTK io p %04x = %02x at 0x%04x", addr, val, reg_pc)); + } + + return val; +} + +static void ltk_update_memflags(mc6821_state *ctx) +{ + uint8_t temp; + temp = (ctx->dataB & ctx->ddrB) | (ltk_in2 & (ctx->ddrB ^ 0xff)); + + ltk_ramwrite = (temp & 0x40) != 0; + /* once the lower ram is turned on ROM is permanently turned off */ + if (ltk_ramwrite) { + ltk_rom = 0; + } + + ltk_ramh = (!ctx->CB2) && (!ltk_rom); + /* low ram is only on when replacement kernal is on */ + ltk_raml = ltk_ramh && ltk_ramwrite; + + cart_port_config_changed_slotmain(); +} + +static void ltk_set_pa(mc6821_state *ctx) +{ + scsi_context_t *scsi = (scsi_context_t*)ctx->p; + + if (scsi_set_bus(scsi, ctx->dataA)) { + if (ctx->ctrlA & MC6821_CTRL_REG) { + CRIT((LOG, "Cannot set bus to %02x at %04x", ctx->dataA, reg_pc)); + } + } +} + +static void ltk_set_pb(mc6821_state *ctx) +{ + static uint16_t last = -1; + scsi_context_t *scsi = (scsi_context_t*)ctx->p; + + if (last == ctx->dataB) return; + last = ctx->dataB; + + scsi->sel = (ctx->dataB & 0x10) != 0; + scsi->rst = (ctx->dataB & 0x20) != 0; + scsi_process_noack(scsi); + + if (ctx->dataB & 0x40) { + ltkernal_cancel_alarm(); + IDBG((LOG, "LTK RAM ON at 0x%04x", reg_pc)); + } else { + IDBG((LOG, "LTK RAM OFF at 0x%04x", reg_pc)); + } + + ltk_update_memflags(ctx); +} + +static void ltk_set_cb2(mc6821_state *ctx) +{ + if (ctx->CB2) { + IDBG((LOG, "LTK STOCK KERNAL ON at 0x%04x", reg_pc)); + } else { + ltkernal_cancel_alarm(); + IDBG((LOG, "LTK STOCK KERNAL OFF at 0x%04x", reg_pc)); + } + + ltk_update_memflags(ctx); + + if ( !ltk_ramwrite && ctx->CB2) { + if (ltk_alarm_time == CLOCK_MAX) { + /* reset is scheduled in the next 57 cycles */ + LOG2((LOG, "LTK RESET SCHEDULED at 0x%04x", reg_pc)); + ltk_alarm_time = maincpu_clk + 57; + alarm_set(ltk_alarm, ltk_alarm_time); + } + } +} + +static void ltkernal_io_store(uint16_t addr, uint8_t value) +{ + int port, reg; + + if (ltk_on) { + IDBG((LOG, "--------------------")); + if (addr & 0x4) { + /* any writes to 4, 5, 6 or 7 turn off LTK I/O until reset */ +/* it turns out nothing happens when you write here. */ +/* + if (ltk_ramwrite) { + ltk_on = 0; + ltk_ramwrite = 0; + ltk_rom = 0; + ltk_raml = 0; + ltk_ramh = 0; + LOG1((LOG, "LTK OFF at %04x", reg_pc)); + } +*/ + } else { + port = (addr >> 1) & 1; /* rs1 */ + reg = (addr >> 0) & 1; /* rs0 */ + mc6821core_store(<k_6821, port /* rs1 */, reg /* rs0 */, value); + } + + IDBG((LOG, "LTK io w %04x < %02x at 0x%04x", addr, value, reg_pc)); + } +} + +static int ltkernal_io_dump(void) +{ + mon_out("IO mapped?: %s\n", ltk_on ? "Yes" : "No"); + mon_out("IO location: $%xxx\n", (unsigned int)(ltk_io == 0 ? 0xde : 0xdf )); + mon_out("Port number: %d\n", ltk_port); + mon_out("Freeze state: %s\n", ltk_freeze ? "Yes" : "No"); + mon_out("ROM mapped to $8000-$9FFF?: %s\n", ltk_rom ? "Yes" : "No"); + mon_out("RAM mapped to $8000-$9FFF?: %s\n", ltk_raml ? "Yes" : "No"); + mon_out("RAM mapped to $E000-$FFFF?: %s\n", ltk_ramh ? "Yes" : "No"); + mon_out("RAM write enabled?: %s\n", ltk_ramwrite ? "Yes" : "No"); + + mon_out("MC6821\n"); + mc6821core_dump(<k_6821); + + return 0; +} + +/* ---------------------------------------------------------------------*/ +int c128ltkernal_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit, int mem_config) +{ + /* unlike the c64 mmu_translate, here we only apply what we can and move + on. return a 1 if we did, or 0 if we didn't apply anything. */ + if (addr >= 0x8000 && addr <= 0x9fff) { + /* only map in ROM if external ROM access */ + if (ltk_rom && ((mem_config & 0x30) == 0x20)) { + *base = roml_banks + 0x1000 - 0x8000; + *start = 0x8000; + *limit = 0x9ffd; + return 1; + } else if (ltk_raml) { + /* RAM maps in whenever ltk_raml is active */ + *base = export_ram0 - 0x8000; + *start = 0x8000; + *limit = 0x9ffd; + return 1; + } + } else if (addr >= 0xe000) { + /* map in if either ROM or EXT FUNCTION; this is what the MMU + daughtercard checks for. */ + if ((ltk_ramh && ((mem_config & 0x20) == 0x00)) || (ltk_ramh && ltk_freeze )) { + *base = export_ram0 + 0x2000 - 0xe000; + *start = 0xe000; + *limit = 0xfffd; + return 1; + } + } + + /* nothing to apply here */ + return 0; +} + +uint8_t c128ltkernal_ram_read(uint16_t addr, uint8_t *value) +{ +/* called by all memory reads so limit it */ + if (addr >= 0x8000 && addr <= 0x9fff) { + if (ltk_raml) { + *value = export_ram0[(addr & 0x1fff)]; + MDBG((LOG, "LTK c128ltkernal_ram_read(RAM) %04x = %02x", + (int)addr, (int)*value)); + return 1; + } + } + + return 0; +} + +uint8_t c128ltkernal_ram_store(uint16_t addr, uint8_t value) +{ +/* called by all memory writes so limit it */ + if (addr >= 0x8000 && addr <= 0x9fff) { + if (ltk_raml && ltk_ramwrite) { + export_ram0[(addr & 0x1fff)] = value; + MDBG((LOG, "LTK c128ltkernal_ram_store(RAM) %04x = %02x", + (int)addr, (int)value)); + return 1; + } + } + + return 0; +} + +uint8_t c128ltkernal_roml_read(uint16_t addr, uint8_t *value) +{ +/* also called by $c000-$dfff memory so limit it */ + if (addr > 0x9fff || addr < 0x8000) { + return 0; + } + if (ltk_rom) { +/* for 128, the LTK upper 8K of ROM is used; only map that */ + *value = roml_banks[(addr & 0x0fff)|0x1000]; + MDBG((LOG, "LTK c128ltkernal_roml_read(ROM) %04x = %02x", + (int)addr, (int)*value)); + return 1; + } else if (ltk_raml) { + *value = export_ram0[(addr & 0x1fff)]; + MDBG((LOG, "LTK c128ltkernal_roml_read(RAM) %04x = %02x", + (int)addr, (int)*value)); + return 1; + } + return 0; +} + +uint8_t c128ltkernal_roml_store(uint16_t addr, uint8_t value) +{ + if (addr > 0x9fff || addr < 0x8000) { + return 0; + } + if (ltk_raml && ltk_ramwrite) { + export_ram0[(addr & 0x1fff)] = value; + MDBG((LOG, "LTK c128ltkernal_roml_store %04x = %02x", + (int)addr, (int)value)); + return 1; + } + return 0; +} + +uint8_t c128ltkernal_basic_hi_read(uint16_t addr, uint8_t *value) +{ + if (addr > 0x9fff || addr < 0x8000) { + return 0; + } + if (ltk_raml) { + *value = export_ram0[(addr & 0x1fff)]; + MDBG((LOG, "LTK c128ltkernal_basic_hi_read %04x = %02x", (int)addr, + (int)*value)); + return 1; + } + return 0; +} + +uint8_t c128ltkernal_basic_hi_store(uint16_t addr, uint8_t value) +{ + if (addr > 0x9fff || addr < 0x8000) { + return 0; + } + if (ltk_raml && ltk_ramwrite) { + export_ram0[(addr & 0x1fff)] = value; + MDBG((LOG, "LTK c128ltkernal_basic_hi_store %04x = %02x", (int)addr, + (int)value)); + return 1; + } + return 0; +} + +uint8_t c128ltkernal_hi_read(uint16_t addr, uint8_t *value) +{ + if (ltk_ramh) { + *value = export_ram0[0x2000|(addr & 0x1fff)]; + MDBG((LOG, "LTK c128ltkernal_hi_read %04x = %02x", (int)addr, (int)*value)); + return 1; + } + return 0; +} + +uint8_t c128ltkernal_hi_store(uint16_t addr, uint8_t value) +{ + if (ltk_ramh && ltk_ramwrite) { + export_ram0[0x2000|(addr & 0x1fff)] = value; + MDBG((LOG, "LTK c128ltkernal_hi_store %04x = %02x", (int)addr, (int)value)); + return 1; + } + return 0; +} + +void c128ltkernal_switch_mode(int mode) +{ + LOG2((LOG, "LTK switch mode %d", mode)); + + if ( mode ) { + /* reconfigure for c64 mode */ + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_ULTIMAX, CMODE_READ | + CMODE_PHI2_RAM); + } else { + /* reconfigure for c128 mode; boot via ext function rom */ + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + } +} + +int ltkernal_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ + /* the callers take care of most stuff here, but since this is both a + standard cart and ultimax, we have to handle those situations. + NOTE that the caller doesn't process the return value, so we have to + have some values set for base, start, and limit, which we do if all + else fails. */ + if (addr >= 0x8000 && addr <= 0x9fff) { + if (ltk_rom) { + *base = roml_banks - 0x8000; + } else if (ltk_raml) { + *base = export_ram0 - 0x8000; + } else { + /* include RAM to speed things up */ + *base = mem_ram; + } + *start = 0x8000; + *limit = 0x9ffd; + return CART_READ_VALID; + } else if (addr >= 0xe000) { + int p = (pport.dir & pport.data) | (~pport.dir & 7); + if ((ltk_ramh && (p & 2)) || (ltk_ramh && ltk_freeze )) { + *base = export_ram0 + 0x2000 - 0xe000; + } else if (p & 2) { +#if 0 + *base = c64memrom_kernal64_trap_rom - 0xe000; +#else + *base = (uint8_t*)(0 - 0xe000); + *base += (uintptr_t)c64memrom_kernal64_trap_rom; +#endif + } else { + /* include RAM to speed things up */ + *base = mem_ram; + } + *start = 0xe000; + *limit = 0xfffd; + return CART_READ_VALID; + } + + /* nothing to apply here, so use the slow mode */ + *base = NULL; + *start = 0; + *limit = 0; + return CART_READ_THROUGH; +} + +uint8_t ltkernal_roml_read(uint16_t addr) +{ + uint8_t val; + if (ltk_rom) { + val = roml_banks[(addr & 0x1fff)]; + } else if (ltk_raml) { + val = export_ram0[(addr & 0x1fff)]; + } else { + val = mem_read_without_ultimax(addr); + } + MDBG((LOG, "LTK roml_read %04x = %02x", addr, val)); + return val; +} + +uint8_t ltkernal_romh_read(uint16_t addr) +{ + uint8_t val; + int p = (pport.dir & pport.data) | (~pport.dir & 7); + if ((ltk_ramh && (p & 2)) || (ltk_ramh && ltk_freeze )) { + val = export_ram0[0x2000|(addr & 0x1fff)]; + } else { + val = mem_read_without_ultimax(addr); + } + MDBG((LOG, "LTK romh_read %04x = %02x roml=%d romh=%d romw=%d pport=%02x", + (int)addr, (int)val, (int)ltk_raml, (int)ltk_ramh, (int)ltk_ramwrite, + (int)pport.data)); + return val; +} + +void ltkernal_roml_store(uint16_t addr, uint8_t value) +{ + if (ltk_rom) { + ram_store(addr, value); + } else if (ltk_raml && ltk_ramwrite) { + export_ram0[(addr & 0x1fff)] = value; + } else { + ram_store(addr, value); + } +} + +void ltkernal_romh_store(uint16_t addr, uint8_t value) +{ + if (ltk_ramh && ltk_ramwrite) { + export_ram0[0x2000|(addr & 0x1fff)] = value; + } else { + ram_store(addr, value); + } + MDBG((LOG, "LTK romh_store %04x = %02x roml=%d romh=%d romw=%d pport=%02x", + (int)addr, (int)value, (int)ltk_raml, (int)ltk_ramh, (int)ltk_ramwrite, + (int)pport.data)); +} + +int ltkernal_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + int p; + if (ltk_rom) { + if (addr >= 0x8000 && addr <= 0x9fff) { + *value = roml_banks[addr & 0x1fff]; + return CART_READ_VALID; + } + } + if (ltk_raml) { + if (addr >= 0x8000 && addr <= 0x9fff) { + *value = export_ram0[addr & 0x1fff]; + return CART_READ_VALID; + } + } + if (ltk_ramh) { + if (addr >= 0xe000) { + *value = export_ram0[0x2000|(addr & 0x1fff)]; + return CART_READ_VALID; + } + } +/* Workaround needed when using monitor */ + p = (pport.dir & pport.data) | (~pport.dir & 7); + if (((p & 3) == 3) && (addr >= 0xa000 && addr <= 0xbfff)) { + *value = c64memrom_basic64_rom[addr & 0x1fff]; + return CART_READ_VALID; + } + if (((p & 2) == 2) && (addr >= 0xe000)) { + *value = c64memrom_kernal64_rom[addr & 0x1fff]; + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void ltkernal_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + +void ltkernal_freeze(void) +{ + MDBG((LOG, "LTK roml=%d romh=%d romw=%d pport=%02x", (int)ltk_raml, + (int)ltk_ramh, (int)ltk_ramwrite, (int)pport.data)); + if (ltk_ramh) { + LOG2((LOG, "LTK freeze")); + + ltk_freeze = 1; + ltk_rom = 0; + ltk_raml = 1; + ltk_ramh = 1; + ltk_ramwrite = 1; + } else { + LOG1((LOG, "LTK freeze but no LTK kernal in place; ignoring")); + } + cartridge_release_freeze(); +} + +void ltkernal_config_init(void) +{ + int32_t i; + LOG2((LOG, "LTK config init")); + + if (ltkernal_check_scpu64()) { + return; + } + + /* set default cart mode depending on machine type */ + if ( machine_class == VICE_MACHINE_C64SC || + machine_class == VICE_MACHINE_C64 ) { + c128ltkernal_switch_mode(1); + } else { + /* must be a c128 at this point */ + c128ltkernal_switch_mode(0); + } + + for (i = 0; i < 0x2000; i++) { + export_ram0[i] = (i >> 8) + 0x80; + export_ram0[0x2000|i] = (i >> 8) + 0xe0; + } + + /* defaults */ + /* ROM is on */ + ltk_rom = 1; + ltk_raml = 0; + ltk_ramh = 0; + + /* stop 6821 from calling CA2 during reset */ + ltk_6821.set_ca2 = NULL; + ltk_6821.set_pa = NULL; + ltk_6821.set_pb = NULL; + ltk_6821.set_cb2 = NULL; + ltk_6821.get_pa = NULL; + ltk_6821.get_pb = NULL; + mc6821core_reset(<k_6821); + ltk_6821.set_ca2 = ltk_set_ca2; + ltk_6821.set_pa = ltk_set_pa; + ltk_6821.set_pb = ltk_set_pb; + ltk_6821.set_cb2 = ltk_set_cb2; + ltk_6821.get_pa = ltk_get_pa; + ltk_6821.get_pb = ltk_get_pb; + ltk_6821.p = <k_scsi; + + /* SCSI register defaults */ + ltk_scsi.atn = 0; + ltk_scsi.rst = 0; + ltk_scsi.bsyi = 0; + ltk_scsi.ack = 0; + ltk_scsi.myname = (char *)ltk_scsi_name; + + ltk_in2 = 0xff - 0x40; /* make sure RAM is not enabled */ + + /* no freeze state */ + ltk_freeze = 0; + + /* ltk is mapped */ + ltk_on = 1; + + ltk_imageopenall(); + + scsi_process_noack(<k_scsi); +} + +void ltkernal_config_setup(uint8_t *rawcart) +{ + LOG2((LOG, "LTK config setup")); + + /* copy supplied ROM image to memory */ + memcpy(roml_banks, rawcart, 0x2000); + + /* copy in the LTK serial number */ + memcpy(&(roml_banks[10]), ltk_serial, 8); + memcpy(&(roml_banks[4096 + 10]), ltk_serial, 8); + + /* set default cart mode depending on machine type */ + if ( machine_class == VICE_MACHINE_C64SC || + machine_class == VICE_MACHINE_C64 ) { + c128ltkernal_switch_mode(1); + } else { + /* must be a c128 at this point */ + c128ltkernal_switch_mode(0); + } +} + +/* ---------------------------------------------------------------------*/ + +static int ltkernal_common_attach(void) +{ + LOG2((LOG, "LTK common attach")); + + if (ltkernal_check_scpu64()) { + return -1; + } + + scsi_reset(<k_scsi); + ltk_scsi.max_imagesize = ltk_imagesize; + ltk_scsi.limit_imagesize = ltk_imagesize; + ltk_scsi.msg_after_status = 1; + + if (ltkernal_registerio() < 0) { + return -1; + } + ltk_inserted = 1; + return 0; +} + +int ltkernal_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i; + + if (ltkernal_check_scpu64()) { + return -1; + } + + for (i = 0; i <= 0; i++) { + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank != 0 || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + } + + return ltkernal_common_attach(); +} + +int ltkernal_bin_attach(const char *filename, uint8_t *rawcart) +{ + LOG2((LOG, "LTK bin attach")); + + if (ltkernal_check_scpu64()) { + return -1; + } + + if (util_file_load(filename, rawcart, 0x2000, + UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return ltkernal_common_attach(); +} + +void ltkernal_detach(void) +{ + LOG2((LOG, "LTK detach")); + + scsi_image_detach_all(<k_scsi); + + ltkernal_unregisterio(); + ltk_inserted = 0; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTLTK snapshot module format: + + type | name | description + ------------------------------------ + BYTE | rom | ltk_rom + BYTE | raml | ltk_raml + BYTE | ramh | ltk_ramh + BYTE | ramwrite | ltk_ramwrite + BYTE | freeze | ltk_freeze + BYTE | on | ltk_on + BYTE | in2 | ltk_in2 + BYTE | io | ltk_io + BYTE | port | ltk_port + DWORD | alarm_time | ltk_alarm_time + ARRAY | ROML | 8192 BYTES of ROML data (boot rom, $8000-$9FFF) + ARRAY | export_ram0 | 16384 BYTES of export RAM data (RAML & RAMH) + MC6821 | SNAPSHOT6821 | ltk_6821 + SCSI | SNAPSHOTSCSI | ltk_scsi + +*/ + +static const char snap_module_name[] = "CARTLTK"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int ltkernal_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, ltk_rom) < 0) + || (SMW_B(m, ltk_raml) < 0) + || (SMW_B(m, ltk_ramh) < 0) + || (SMW_B(m, ltk_ramwrite) < 0) + || (SMW_B(m, ltk_freeze) < 0) + || (SMW_B(m, ltk_on) < 0) + || (SMW_B(m, ltk_in2) < 0) + || (SMW_DW(m, ltk_io) < 0) + || (SMW_DW(m, ltk_port) < 0) + || (SMW_CLOCK(m, ltk_alarm_time) < 0) + || (SMW_BA(m, roml_banks, 0x2000) < 0) + || (SMW_BA(m, export_ram0, 0x4000) < 0)) { + goto fail; + } + + if (mc6821core_snapshot_write_data(<k_6821, m) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return scsi_snapshot_write_module(<k_scsi, s); + +fail: + snapshot_module_close(m); + return -1; +} + +int ltkernal_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + ltkernal_detach(); + + if (0 + || (SMR_B(m, <k_rom) < 0) + || (SMR_B(m, <k_raml) < 0) + || (SMR_B(m, <k_ramh) < 0) + || (SMR_B(m, <k_ramwrite) < 0) + || (SMR_B(m, <k_freeze) < 0) + || (SMR_B(m, <k_on) < 0) + || (SMR_B(m, <k_in2) < 0) + || (SMR_DW_INT(m, <k_io) < 0) + || (SMR_DW_INT(m, <k_port) < 0) + || (SMR_CLOCK(m, <k_alarm_time) < 0) + || (SMR_BA(m, roml_banks, 0x2000) < 0) + || (SMR_BA(m, export_ram0, 0x4000) < 0)) { + goto fail; + } + + if (mc6821core_snapshot_read_data(<k_6821, m) < 0) { + goto fail; + } + + snapshot_module_close(m); + + if (scsi_snapshot_read_module(<k_scsi, s) < 0) { + return -1; + } + + ltk_imageopenall(); + + if (ltk_alarm_time < CLOCK_MAX) { + alarm_set(ltk_alarm, ltk_alarm_time); + } else { + alarm_unset(ltk_alarm); + } + + return ltkernal_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/ltkernal.h b/src/Emulators/vice/c64/cart/ltkernal.h new file mode 100644 index 00000000..fd04d203 --- /dev/null +++ b/src/Emulators/vice/c64/cart/ltkernal.h @@ -0,0 +1,83 @@ +/* + * ltkernal64.h - Cartridge handling, Final cart. + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_LTKERNAL_H +#define VICE_LTKERNAL_H + +#include "c64cart.h" + +struct snapshot_s; + +#define LTKIO_DE00 0 +#define LTKIO_DF00 1 + +/** \brief Lowest disk image number */ +#define LTK_HD_MIN 0 +/** \brief Highest disk image number */ +#define LTK_HD_MAX 6 +/** \brief Number of supported disk images */ +#define LTK_HD_COUNT (LTK_HD_MAX - LTK_HD_MIN + 1) + +/** \brief Lowest port number */ +#define LTK_PORT_MIN 0 +/** \brief Highest port number */ +#define LTK_PORT_MAX 15 + + +void ltkernal_freeze(void); +void ltkernal_powerup(void); +void ltkernal_config_init(void); +void ltkernal_config_setup(uint8_t *rawcart); +int ltkernal_bin_attach(const char *filename, uint8_t *rawcart); +void ltkernal_detach(void); +int ltkernal_crt_attach(FILE *fd, uint8_t *rawcart); + +uint8_t ltkernal_roml_read(uint16_t addr); +uint8_t ltkernal_romh_read(uint16_t addr); +void ltkernal_roml_store(uint16_t addr, uint8_t value); +void ltkernal_romh_store(uint16_t addr, uint8_t value); +int ltkernal_peek_mem(export_t *export, uint16_t addr, uint8_t *value); +int ltkernal_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +int c128ltkernal_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit, int mem_config); +uint8_t c128ltkernal_roml_read(uint16_t addr, uint8_t *value); +uint8_t c128ltkernal_roml_store(uint16_t addr, uint8_t value); +uint8_t c128ltkernal_basic_hi_read(uint16_t addr, uint8_t *value); +uint8_t c128ltkernal_basic_hi_store(uint16_t addr, uint8_t value); +uint8_t c128ltkernal_hi_read(uint16_t addr, uint8_t *value); +uint8_t c128ltkernal_hi_store(uint16_t addr, uint8_t value); +uint8_t c128ltkernal_ram_read(uint16_t addr, uint8_t *value); +uint8_t c128ltkernal_ram_store(uint16_t addr, uint8_t value); +void c128ltkernal_switch_mode(int mode); + +int ltkernal_cmdline_options_init(void); +int ltkernal_resources_init(void); +int ltkernal_resources_shutdown(void); + +int ltkernal_snapshot_write_module(struct snapshot_s *s); +int ltkernal_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/mach5.c b/src/Emulators/vice/c64/cart/mach5.c index c152390c..f71ca4e2 100644 --- a/src/Emulators/vice/c64/cart/mach5.c +++ b/src/Emulators/vice/c64/cart/mach5.c @@ -63,26 +63,26 @@ static int mach5_active = 0; -static BYTE mach5_io1_read(WORD addr) +static uint8_t mach5_io1_read(uint16_t addr) { /* DBG(("io1 rd %04x\n", addr)); */ return roml_banks[0x1e00 + (addr & 0xff)]; } -static void mach5_io1_store(WORD addr, BYTE value) +static void mach5_io1_store(uint16_t addr, uint8_t value) { DBG(("io1 st %04x %02x\n", addr, value)); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_WRITE); mach5_active = 1; } -static BYTE mach5_io2_read(WORD addr) +static uint8_t mach5_io2_read(uint16_t addr) { /* DBG(("io2 rd %04x\n", addr)); */ return roml_banks[0x1f00 + (addr & 0xff)]; } -static void mach5_io2_store(WORD addr, BYTE value) +static void mach5_io2_store(uint16_t addr, uint8_t value) { DBG(("%04x io2 st %04x %02x\n", reg_pc, addr, value)); cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_WRITE); @@ -99,33 +99,37 @@ static int mach5_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t mach5_io1_device = { - CARTRIDGE_NAME_MACH5, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - mach5_io1_store, - mach5_io1_read, - mach5_io1_read, - mach5_dump, - CARTRIDGE_MACH5, - 0, - 0 + CARTRIDGE_NAME_MACH5, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + mach5_io1_store, /* store function */ + NULL, /* NO poke function */ + mach5_io1_read, /* read function */ + mach5_io1_read, /* peek function */ + mach5_dump, /* device state information dump function */ + CARTRIDGE_MACH5, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mach5_io2_device = { - CARTRIDGE_NAME_MACH5, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - mach5_io2_store, - mach5_io2_read, - mach5_io2_read, - mach5_dump, - CARTRIDGE_MACH5, - 0, - 0 + CARTRIDGE_NAME_MACH5, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + mach5_io2_store, /* store function */ + NULL, /* NO poke function */ + mach5_io2_read, /* read function */ + mach5_io2_read, /* peek function */ + mach5_dump, /* device state information dump function */ + CARTRIDGE_MACH5, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *mach5_io1_list_item = NULL; @@ -143,7 +147,7 @@ void mach5_config_init(void) mach5_active = 1; } -void mach5_config_setup(BYTE *rawcart) +void mach5_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); @@ -162,7 +166,7 @@ static int mach5_common_attach(void) return 0; } -int mach5_bin_attach(const char *filename, BYTE *rawcart) +int mach5_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { if (util_file_load(filename, rawcart, 0x1000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -174,7 +178,7 @@ int mach5_bin_attach(const char *filename, BYTE *rawcart) return mach5_common_attach(); } -int mach5_crt_attach(FILE *fd, BYTE *rawcart) +int mach5_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -217,7 +221,7 @@ void mach5_detach(void) ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTMACH5"; +static const char snap_module_name[] = "CARTMACH5"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -232,7 +236,7 @@ int mach5_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)mach5_active) < 0 + || SMW_B(m, (uint8_t)mach5_active) < 0 || SMW_BA(m, roml_banks, 0x2000) < 0) { snapshot_module_close(m); return -1; @@ -243,7 +247,7 @@ int mach5_snapshot_write_module(snapshot_t *s) int mach5_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -253,13 +257,13 @@ int mach5_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &mach5_active) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/mach5.h b/src/Emulators/vice/c64/cart/mach5.h index dc6a655c..8f954e46 100644 --- a/src/Emulators/vice/c64/cart/mach5.h +++ b/src/Emulators/vice/c64/cart/mach5.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void mach5_config_init(void); -extern void mach5_config_setup(BYTE *rawcart); -extern int mach5_crt_attach(FILE *fd, BYTE *rawcart); -extern int mach5_bin_attach(const char *filename, BYTE *rawcart); -extern void mach5_detach(void); +void mach5_config_init(void); +void mach5_config_setup(uint8_t *rawcart); +int mach5_crt_attach(FILE *fd, uint8_t *rawcart); +int mach5_bin_attach(const char *filename, uint8_t *rawcart); +void mach5_detach(void); struct snapshot_s; -extern int mach5_snapshot_write_module(struct snapshot_s *s); -extern int mach5_snapshot_read_module(struct snapshot_s *s); +int mach5_snapshot_write_module(struct snapshot_s *s); +int mach5_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/magicdesk.c b/src/Emulators/vice/c64/cart/magicdesk.c index 61f624d8..d71466ee 100644 --- a/src/Emulators/vice/c64/cart/magicdesk.c +++ b/src/Emulators/vice/c64/cart/magicdesk.c @@ -52,18 +52,18 @@ #endif /* - "Magic Desk" Cartridge + "Magic Desk" Cartridge - - this cart comes in 3 sizes, 32Kb (4 banks), 64Kb (8 banks) and 128Kb (16 banks). - - supports "DDI Magic Cart" (32 banks, 256kb) - - supports "Magic Desk Clone" homebrew cart (64 banks, 512kb and 128banks, 1MB) + - this cart comes in 3 sizes, 32Kb (4 banks), 64Kb (8 banks) and 128Kb (16 banks). + - supports "DDI Magic Cart" (32 banks, 256kb) + - supports "Magic Desk Clone" homebrew cart (64 banks, 512kb and 128banks, 1MB) - - ROM is always mapped in at $8000-$9FFF (8k game). + - ROM is always mapped in at $8000-$9FFF (8k game). - - 1 register at io1 / de00: + - 1 register at io1 / de00: - bit 0-6 bank number - bit 7 exrom (1 = cart disabled) + bit 0-6 bank number + bit 7 exrom (1 = cart disabled) */ #define MAXBANKS 128 @@ -73,152 +73,153 @@ static uint8_t bankmask = 0x7f; static void magicdesk_io1_store(uint16_t addr, uint8_t value) { - regval = value & (0x80 | bankmask); - cart_romlbank_set_slotmain(value & bankmask); - cart_set_port_game_slotmain(0); - if (value & 0x80) { - /* turn off cart ROM */ - cart_set_port_exrom_slotmain(0); - } else { - cart_set_port_exrom_slotmain(1); - } - cart_port_config_changed_slotmain(); - DBG(("MAGICDESK: Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled")); + regval = value & (0x80 | bankmask); + cart_romlbank_set_slotmain(value & bankmask); + cart_set_port_game_slotmain(0); + if (value & 0x80) { + /* turn off cart ROM */ + cart_set_port_exrom_slotmain(0); + } else { + cart_set_port_exrom_slotmain(1); + } + cart_port_config_changed_slotmain(); + DBG(("MAGICDESK: Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled")); } static uint8_t magicdesk_io1_peek(uint16_t addr) { - return regval; + return regval; } static int magicdesk_dump(void) { - mon_out("Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled"); - return 0; + mon_out("Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled"); + return 0; } /* ---------------------------------------------------------------------*/ static io_source_t magicdesk_device = { - CARTRIDGE_NAME_MAGIC_DESK, /* name of the device */ - IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ - IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ - 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ - 0, /* read is never valid, reg is write only */ - magicdesk_io1_store, /* store function */ - NULL, /* NO poke function */ -// NULL, /* read function */ - magicdesk_io1_peek, /* peek function */ - magicdesk_dump, /* device state information dump function */ - CARTRIDGE_MAGIC_DESK, /* cartridge ID */ - IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ - 0 /* insertion order, gets filled in by the registration function */ + CARTRIDGE_NAME_MAGIC_DESK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + magicdesk_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* read function */ + magicdesk_io1_peek, /* peek function */ + magicdesk_dump, /* device state information dump function */ + CARTRIDGE_MAGIC_DESK, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *magicdesk_list_item = NULL; static const export_resource_t export_res = { - CARTRIDGE_NAME_MAGIC_DESK, 0, 1, &magicdesk_device, NULL, CARTRIDGE_MAGIC_DESK + CARTRIDGE_NAME_MAGIC_DESK, 0, 1, &magicdesk_device, NULL, CARTRIDGE_MAGIC_DESK }; /* ---------------------------------------------------------------------*/ void magicdesk_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); - magicdesk_io1_store((uint16_t)0xde00, 0); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + magicdesk_io1_store((uint16_t)0xde00, 0); } void magicdesk_config_setup(uint8_t *rawcart) { - memcpy(roml_banks, rawcart, 0x2000 * MAXBANKS); - cart_config_changed_slotmain(0, 0, CMODE_READ); + memcpy(roml_banks, rawcart, 0x2000 * MAXBANKS); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ static int magicdesk_common_attach(void) { - if (export_add(&export_res) < 0) { - return -1; - } - magicdesk_list_item = io_source_register(&magicdesk_device); - return 0; + if (export_add(&export_res) < 0) { + return -1; + } + magicdesk_list_item = io_source_register(&magicdesk_device); + return 0; } int magicdesk_bin_attach(const char *filename, uint8_t *rawcart) { - bankmask = 0x7f; - if (util_file_load(filename, rawcart, 0x100000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - bankmask = 0x3f; - if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - bankmask = 0x1f; - if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - bankmask = 0x0f; - if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - bankmask = 0x07; - if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - bankmask = 0x03; - if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - return -1; - } - } - } - } - } - } - return magicdesk_common_attach(); + bankmask = 0x7f; + if (util_file_load(filename, rawcart, 0x100000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x3f; + if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x1f; + if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x0f; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x03; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + } + } + } + return magicdesk_common_attach(); } int magicdesk_crt_attach(FILE *fd, uint8_t *rawcart) { - crt_chip_header_t chip; - int lastbank = 0; - - while (1) { - if (crt_read_chip_header(&chip, fd)) { - break; - } - if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) { - return -1; - } - if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { - return -1; - } - if (chip.bank > lastbank) { - lastbank = chip.bank; - } - } - if (lastbank >= 128) { - /* more than 128 banks does not work */ - return -1; - } else if (lastbank >= 64) { - /* min 65, max 128 banks */ - bankmask = 0x7f; - } else if (lastbank >= 32) { - /* min 33, max 64 banks */ - bankmask = 0x3f; - } else if (lastbank >= 16) { - /* min 17, max 32 banks */ - bankmask = 0x1f; - } else if (lastbank >= 8) { - /* min 9, max 16 banks */ - bankmask = 0x0f; - } else if (lastbank >= 4) { - /* min 5, max 8 banks */ - bankmask = 0x07; - } else { - /* max 4 banks */ - bankmask = 0x03; - } - return magicdesk_common_attach(); + crt_chip_header_t chip; + int lastbank = 0; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + if (chip.bank > lastbank) { + lastbank = chip.bank; + } + } + if (lastbank >= 128) { + /* more than 128 banks does not work */ + return -1; + } else if (lastbank >= 64) { + /* min 65, max 128 banks */ + bankmask = 0x7f; + } else if (lastbank >= 32) { + /* min 33, max 64 banks */ + bankmask = 0x3f; + } else if (lastbank >= 16) { + /* min 17, max 32 banks */ + bankmask = 0x1f; + } else if (lastbank >= 8) { + /* min 9, max 16 banks */ + bankmask = 0x0f; + } else if (lastbank >= 4) { + /* min 5, max 8 banks */ + bankmask = 0x07; + } else { + /* max 4 banks */ + bankmask = 0x03; + } + return magicdesk_common_attach(); } void magicdesk_detach(void) { - export_remove(&export_res); - io_source_unregister(magicdesk_list_item); - magicdesk_list_item = NULL; + export_remove(&export_res); + io_source_unregister(magicdesk_list_item); + magicdesk_list_item = NULL; } /* ---------------------------------------------------------------------*/ @@ -229,54 +230,54 @@ void magicdesk_detach(void) int magicdesk_snapshot_write_module(snapshot_t *s) { - snapshot_module_t *m; - - m = snapshot_module_create(s, SNAP_MODULE_NAME, - CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); - if (m == NULL) { - return -1; - } - - if (0 - || (SMW_B(m, (uint8_t)regval) < 0) - || (SMW_B(m, (uint8_t)bankmask) < 0) - || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { - snapshot_module_close(m); - return -1; - } - - snapshot_module_close(m); - return 0; + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; } int magicdesk_snapshot_read_module(snapshot_t *s) { - uint8_t vmajor, vminor; - snapshot_module_t *m; - - m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); - if (m == NULL) { - return -1; - } - - if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { - snapshot_module_close(m); - return -1; - } - - if (0 - || (SMR_B(m, ®val) < 0) - || (SMR_B(m, &bankmask) < 0) - || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { - snapshot_module_close(m); - return -1; - } - - snapshot_module_close(m); - - if (magicdesk_common_attach() == -1) { - return -1; - } - magicdesk_io1_store(0xde00, regval); - return 0; + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (0 + || (SMR_B(m, ®val) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (magicdesk_common_attach() == -1) { + return -1; + } + magicdesk_io1_store(0xde00, regval); + return 0; } diff --git a/src/Emulators/vice/c64/cart/magicdesk.h b/src/Emulators/vice/c64/cart/magicdesk.h index 9754c853..402db620 100644 --- a/src/Emulators/vice/c64/cart/magicdesk.h +++ b/src/Emulators/vice/c64/cart/magicdesk.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void magicdesk_config_init(void); -extern void magicdesk_config_setup(uint8_t *rawcart); -extern int magicdesk_bin_attach(const char *filename, uint8_t *rawcart); -extern int magicdesk_crt_attach(FILE *fd, uint8_t *rawcart); -extern void magicdesk_detach(void); +void magicdesk_config_init(void); +void magicdesk_config_setup(uint8_t *rawcart); +int magicdesk_bin_attach(const char *filename, uint8_t *rawcart); +int magicdesk_crt_attach(FILE *fd, uint8_t *rawcart); +void magicdesk_detach(void); struct snapshot_s; -extern int magicdesk_snapshot_write_module(struct snapshot_s *s); -extern int magicdesk_snapshot_read_module(struct snapshot_s *s); +int magicdesk_snapshot_write_module(struct snapshot_s *s); +int magicdesk_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/magicdesk16.c b/src/Emulators/vice/c64/cart/magicdesk16.c new file mode 100644 index 00000000..43bff5ac --- /dev/null +++ b/src/Emulators/vice/c64/cart/magicdesk16.c @@ -0,0 +1,298 @@ +/* + * magicdesk16.c - Cartridge handling, Magic Desk 16K cart. + * + * Original magicdesk.c Written by + * Marco van den Heuvel + + * 16K Mod Written by + * Salvo Cristaldi + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define MAGICDESK16_DEBUG */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "magicdesk16.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +#ifdef MAGICDESK16_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + "Magic Desk 16K" Cartridge + + - supports all "Magic Desk Clone" homebrew cart with 16k game config, up to 2 MB + + - ROM is always mapped in at $8000-$BFFF (16k game). + + - 1 register at io1 / de00: + + bit 0-6 bank number + bit 7 exrom (1 = cart disabled) +*/ + +#define MAXBANKS 128 + +static uint8_t regval = 0; +static uint8_t bankmask = 0x7f; + +static void magicdesk16_io1_store(uint16_t addr, uint8_t value) +{ + regval = value & (0x80 | bankmask); + cart_romhbank_set_slotmain(value & bankmask); + cart_romlbank_set_slotmain(value & bankmask); + cart_set_port_game_slotmain(0); + if (value & 0x80) { + /* turn off cart ROM */ + cart_set_port_exrom_slotmain(0); + cart_set_port_game_slotmain(0); + } else { + cart_set_port_exrom_slotmain(1); + cart_set_port_game_slotmain(1); + } + cart_port_config_changed_slotmain(); + DBG(("MAGICDESK16: Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled")); +} + +static uint8_t magicdesk16_io1_peek(uint16_t addr) +{ + return regval; +} + +static int magicdesk16_dump(void) +{ + mon_out("Reg: %02x (Bank: %d of %d, %s)\n", regval, (regval & bankmask), bankmask + 1, (regval & 0x80) ? "disabled" : "enabled"); + return 0; +} + + +/* ---------------------------------------------------------------------*/ + +static io_source_t magicdesk16_device = { + CARTRIDGE_NAME_MAGIC_DESK_16, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + magicdesk16_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* read function */ + magicdesk16_io1_peek, /* peek function */ + magicdesk16_dump, /* device state information dump function */ + CARTRIDGE_MAGIC_DESK_16, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *magicdesk16_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_MAGIC_DESK_16, 1, 1, &magicdesk16_device, NULL, CARTRIDGE_MAGIC_DESK_16 +}; + +/* ---------------------------------------------------------------------*/ + +void magicdesk16_config_init(void) +{ + magicdesk16_io1_store((uint16_t)0xde00, 0); +} + +void magicdesk16_config_setup(uint8_t *rawcart) +{ + for (int i=0; i< MAXBANKS; i++) { + memcpy(&roml_banks[i*0x2000], &rawcart[i*0x4000], 0x2000); + memcpy(&romh_banks[i*0x2000], &rawcart[0x2000 + i*0x4000], 0x2000); + } + +} + +/* ---------------------------------------------------------------------*/ + +static int magicdesk16_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + magicdesk16_list_item = io_source_register(&magicdesk16_device); + return 0; +} + +int magicdesk16_bin_attach(const char *filename, uint8_t *rawcart) +{ + bankmask = 0x7f; + if (util_file_load(filename, rawcart, 0x200000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x3f; + if (util_file_load(filename, rawcart, 0x100000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x1f; + if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x0f; + if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x03; + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x01; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + } + } + } + } + return magicdesk16_common_attach(); +} + +int magicdesk16_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int lastbank = 0; + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x4000)) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + if (chip.bank > lastbank) { + lastbank = chip.bank; + } + } + if (lastbank >= MAXBANKS) { + /* more than 128 banks does not work */ + return -1; + } else if (lastbank >= 64) { + /* min 65, max 128 banks */ + bankmask = 0x7f; + } else if (lastbank >= 32) { + /* min 33, max 64 banks */ + bankmask = 0x3f; + } else if (lastbank >= 16) { + /* min 17, max 32 banks */ + bankmask = 0x1f; + } else if (lastbank >= 8) { + /* min 9, max 16 banks */ + bankmask = 0x0f; + } else if (lastbank >= 4) { + /* min 5, max 8 banks */ + bankmask = 0x07; + } else if (lastbank >= 2) { + /* min 3, max 4 banks */ + bankmask = 0x03; + } else { + /* max 2 banks */ + bankmask = 0x01; + } + + return magicdesk16_common_attach(); +} + +void magicdesk16_detach(void) +{ + export_remove(&export_res); + io_source_unregister(magicdesk16_list_item); + magicdesk16_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 2 +#define SNAP_MODULE_NAME "CARTMD16" + +int magicdesk16_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int magicdesk16_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (0 + || (SMR_B(m, ®val) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (magicdesk16_common_attach() == -1) { + return -1; + } + magicdesk16_io1_store(0xde00, regval); + return 0; +} diff --git a/src/Emulators/vice/c64/cart/magicdesk16.h b/src/Emulators/vice/c64/cart/magicdesk16.h new file mode 100644 index 00000000..b77c1466 --- /dev/null +++ b/src/Emulators/vice/c64/cart/magicdesk16.h @@ -0,0 +1,45 @@ +/* + * magicdesk16.h - Cartridge handling, Magic Desk 16 cart. + * + * Written by + * Salvo Cristaldi + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_MAGICDESK16_H +#define VICE_MAGICDESK16_H + +#include + +#include "vicetypes.h" + +void magicdesk16_config_init(void); +void magicdesk16_config_setup(uint8_t *rawcart); +int magicdesk16_bin_attach(const char *filename, uint8_t *rawcart); +int magicdesk16_crt_attach(FILE *fd, uint8_t *rawcart); +void magicdesk16_detach(void); + +struct snapshot_s; + +int magicdesk16_snapshot_write_module(struct snapshot_s *s); +int magicdesk16_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/magicformel.c b/src/Emulators/vice/c64/cart/magicformel.c index e6f4b9d2..9f9a4cf9 100644 --- a/src/Emulators/vice/c64/cart/magicformel.c +++ b/src/Emulators/vice/c64/cart/magicformel.c @@ -123,49 +123,55 @@ CB2 - enable Cartridge (?) #include "machine.h" #include "magicformel.h" #include "mc6821core.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" /* ---------------------------------------------------------------------*/ +#define CART_RAM_SIZE (8 * 1024) /* some prototypes are needed */ -static void magicformel_io1_store(WORD addr, BYTE value); -static BYTE magicformel_io1_read(WORD addr); -static BYTE magicformel_io1_peek(WORD addr); -static void magicformel_io2_store(WORD addr, BYTE value); -static BYTE magicformel_io2_read(WORD addr); -static BYTE magicformel_io2_peek(WORD addr); +static void magicformel_io1_store(uint16_t addr, uint8_t value); +static uint8_t magicformel_io1_read(uint16_t addr); +static uint8_t magicformel_io1_peek(uint16_t addr); +static void magicformel_io2_store(uint16_t addr, uint8_t value); +static uint8_t magicformel_io2_read(uint16_t addr); +static uint8_t magicformel_io2_peek(uint16_t addr); static io_source_t magicformel_io1_device = { - CARTRIDGE_NAME_MAGIC_FORMEL, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - magicformel_io1_store, - magicformel_io1_read, - magicformel_io1_peek, - NULL, /* TODO: dump */ - CARTRIDGE_MAGIC_FORMEL, - 0, - 0 + CARTRIDGE_NAME_MAGIC_FORMEL, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read validity is determined by the device upon a read */ + magicformel_io1_store, /* store function */ + NULL, /* NO poke function */ + magicformel_io1_read, /* read function */ + magicformel_io1_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_MAGIC_FORMEL, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t magicformel_io2_device = { - CARTRIDGE_NAME_MAGIC_FORMEL, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - magicformel_io2_store, - magicformel_io2_read, - magicformel_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_MAGIC_FORMEL, - 0, - 0 + CARTRIDGE_NAME_MAGIC_FORMEL, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + magicformel_io2_store, /* store function */ + NULL, /* NO poke function */ + magicformel_io2_read, /* read function */ + magicformel_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_MAGIC_FORMEL, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *magicformel_io1_list_item = NULL; @@ -221,9 +227,9 @@ static void log_bank(int bank) static void change_config(void) { if (kernal_enabled || freeze_enabled) { - cart_config_changed_slotmain(2, (BYTE)(3 | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(2, (uint8_t)(3 | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); } else { - cart_config_changed_slotmain(2, (BYTE)(2 | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); + cart_config_changed_slotmain(2, (uint8_t)(2 | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_PHI2_RAM); } } @@ -246,7 +252,7 @@ static void freeze_flipflop(int reset, int freeze, int clear) ***************************************************************************/ #ifdef LOG_PORTS -static void mf_print_pa(BYTE data) +static void mf_print_pa(uint8_t data) { /* PA (Output Data) @@ -263,9 +269,9 @@ static void mf_print_pa(BYTE data) DBG(("[UNUSED %02x] ", (data) & 0xe0)); } -static void mf_print_pb(BYTE data) +static void mf_print_pb(uint8_t data) { - BYTE page; + uint8_t page; /* PB (Output Data) @@ -290,7 +296,7 @@ static void mf_print_pb(BYTE data) static void mf_set_pa(mc6821_state *ctx) { - BYTE data = ctx->dataA; + uint8_t data = ctx->dataA; #ifdef LOG_PORTS mf_print_pa(ctx->dataA); mf_print_pb(ctx->dataB); @@ -328,7 +334,7 @@ static void mf_set_pa(mc6821_state *ctx) static void mf_set_pb(mc6821_state *ctx) { - BYTE data = ctx->dataB; + uint8_t data = ctx->dataB; #ifdef LOG_PORTS mf_print_pa(ctx->dataA); mf_print_pb(ctx->dataB); @@ -387,7 +393,7 @@ static void mf_set_cb2(mc6821_state *ctx) * ****************************************************************************/ -static BYTE magicformel_io1_read(WORD addr) +static uint8_t magicformel_io1_read(uint16_t addr) { #ifdef DEBUG_IO1_NO_DISABLE if (1) { @@ -403,12 +409,12 @@ static BYTE magicformel_io1_read(WORD addr) return 0; } -static BYTE magicformel_io1_peek(WORD addr) +static uint8_t magicformel_io1_peek(uint16_t addr) { return export_ram0[(ram_page << 8) + (addr & 0xff)]; } -static void magicformel_io1_store(WORD addr, BYTE value) +static void magicformel_io1_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_IO1_NO_DISABLE if (1) { @@ -427,7 +433,7 @@ static void magicformel_io1_store(WORD addr, BYTE value) d1 goes to d7 */ -static BYTE magicformel_io2_read(WORD addr) +static uint8_t magicformel_io2_read(uint16_t addr) { int port, reg; @@ -439,7 +445,7 @@ static BYTE magicformel_io2_read(WORD addr) return mc6821core_read(&my6821, port /* rs1 */, reg /* rs0 */); } -static BYTE magicformel_io2_peek(WORD addr) +static uint8_t magicformel_io2_peek(uint16_t addr) { int port, reg; @@ -449,11 +455,11 @@ static BYTE magicformel_io2_peek(WORD addr) return mc6821core_peek(&my6821, port /* rs1 */, reg /* rs0 */); } -static void magicformel_io2_store(WORD addr, BYTE value) +static void magicformel_io2_store(uint16_t addr, uint8_t value) { int port; - WORD reg; - BYTE data; + uint16_t reg; + uint8_t data; data = (addr & 0x3f) | ((value & 2) << 6); /* d0..d5 d7 */ port = (addr >> 7) & 1; /* rs1 */ @@ -472,7 +478,7 @@ static void magicformel_io2_store(WORD addr, BYTE value) the "mf-windows" stuff only works if it reads RAM here, the freezer must however always read ROM */ -BYTE magicformel_romh_read(WORD addr) +uint8_t magicformel_romh_read(uint16_t addr) { if (freeze_enabled && addr >= 0xe000) { return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -480,7 +486,7 @@ BYTE magicformel_romh_read(WORD addr) return mem_read_without_ultimax(addr); } -BYTE magicformel_romh_read_hirom(WORD addr) +uint8_t magicformel_romh_read_hirom(uint16_t addr) { if (addr >= 0xe000) { return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -488,17 +494,17 @@ BYTE magicformel_romh_read_hirom(WORD addr) return mem_read_without_ultimax(addr); } -int magicformel_romh_phi1_read(WORD addr, BYTE *value) +int magicformel_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int magicformel_romh_phi2_read(WORD addr, BYTE *value) +int magicformel_romh_phi2_read(uint16_t addr, uint8_t *value) { return magicformel_romh_phi1_read(addr, value); } -int magicformel_peek_mem(export_t *export, WORD addr, BYTE *value) +int magicformel_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0xe000) { *value = romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; @@ -509,6 +515,25 @@ int magicformel_peek_mem(export_t *export, WORD addr, BYTE *value) /****************************************************************************/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void magicformel_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + /* ultimax, rom bank 1 */ void magicformel_freeze(void) { @@ -521,7 +546,7 @@ void magicformel_freeze(void) freeze_flipflop(0 /* reset */, 1 /* freeze */, my6821.CB2); - cart_config_changed_slotmain(2, (BYTE)(3 | ((romh_bank & 0x0f) << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_RELEASE_FREEZE); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_ULTIMAX | ((romh_bank & 0x0f) << CMODE_BANK_SHIFT)), CMODE_READ | CMODE_RELEASE_FREEZE); } void magicformel_config_init(void) @@ -537,7 +562,7 @@ void magicformel_config_init(void) freeze_flipflop(1 /* reset */, 0 /* freeze */, my6821.CB2); - cart_config_changed_slotmain(2, (BYTE)(3 | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(CMODE_ULTIMAX | (romh_bank << CMODE_BANK_SHIFT)), CMODE_READ); } void magicformel_reset(void) @@ -553,7 +578,7 @@ void magicformel_reset(void) mc6821core_reset(&my6821); } -void magicformel_config_setup(BYTE *rawcart) +void magicformel_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x20000); memcpy(romh_banks, rawcart, 0x20000); @@ -570,7 +595,7 @@ static int magicformel_common_attach(void) return 0; } -int magicformel_bin_attach(const char *filename, BYTE *rawcart) +int magicformel_bin_attach(const char *filename, uint8_t *rawcart) { hwversion = 2; if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -590,7 +615,7 @@ int magicformel_bin_attach(const char *filename, BYTE *rawcart) load CRT, handles 64k (v1.2), 64k+32k (v2.0), 64k+64k (v2.0) */ -int magicformel_crt_attach(FILE *fd, BYTE *rawcart) +int magicformel_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i, cnt = 0; @@ -611,14 +636,14 @@ int magicformel_crt_attach(FILE *fd, BYTE *rawcart) } if (cnt == 8) { - DBG(("MF: 64k ROM loaded.\n")); + DBG(("MF: 64KiB ROM loaded.\n")); hwversion = 0; } else if (cnt == 12) { - DBG(("MF: 64k+32k ROM loaded.\n")); + DBG(("MF: 64KiB+32KiB ROM loaded.\n")); hwversion = 1; memcpy(&rawcart[0x18000], &rawcart[0x10000], 0x8000); } else if (cnt == 16) { - DBG(("MF: 2*64k ROM loaded.\n")); + DBG(("MF: 2*64KiB ROM loaded.\n")); hwversion = 2; } else { return -1; @@ -661,7 +686,7 @@ void magicformel_detach(void) BYTE | CB2 state | CB2 line state */ -static char snap_module_name[] = "CARTMF"; +static const char snap_module_name[] = "CARTMF"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -676,12 +701,12 @@ int magicformel_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ram_page) < 0) - || (SMW_B(m, (BYTE)io1_enabled) < 0) - || (SMW_B(m, (BYTE)kernal_enabled) < 0) - || (SMW_B(m, (BYTE)freeze_enabled) < 0) - || (SMW_B(m, (BYTE)export_game) < 0) - || (SMW_B(m, (BYTE)hwversion) < 0) + || (SMW_B(m, (uint8_t)ram_page) < 0) + || (SMW_B(m, (uint8_t)io1_enabled) < 0) + || (SMW_B(m, (uint8_t)kernal_enabled) < 0) + || (SMW_B(m, (uint8_t)freeze_enabled) < 0) + || (SMW_B(m, (uint8_t)export_game) < 0) + || (SMW_B(m, (uint8_t)hwversion) < 0) || (SMW_BA(m, roml_banks, 0x20000) < 0) || (SMW_BA(m, export_ram0, 0x2000) < 0)) { goto fail; @@ -700,7 +725,7 @@ int magicformel_snapshot_write_module(snapshot_t *s) int magicformel_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -710,7 +735,7 @@ int magicformel_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/magicformel.h b/src/Emulators/vice/c64/cart/magicformel.h index 31e5892c..23efa433 100644 --- a/src/Emulators/vice/c64/cart/magicformel.h +++ b/src/Emulators/vice/c64/cart/magicformel.h @@ -34,21 +34,22 @@ struct snapshot_s; -extern BYTE magicformel_romh_read(WORD addr); -extern BYTE magicformel_romh_read_hirom(WORD addr); -extern int magicformel_romh_phi1_read(WORD addr, BYTE *value); -extern int magicformel_romh_phi2_read(WORD addr, BYTE *value); -extern int magicformel_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern void magicformel_freeze(void); -extern void magicformel_config_init(void); -extern void magicformel_reset(void); -extern void magicformel_config_setup(BYTE *rawcart); -extern int magicformel_bin_attach(const char *filename, BYTE *rawcart); -extern int magicformel_crt_attach(FILE *fd, BYTE *rawcart); -extern void magicformel_detach(void); - -extern int magicformel_snapshot_write_module(struct snapshot_s *s); -extern int magicformel_snapshot_read_module(struct snapshot_s *s); +uint8_t magicformel_romh_read(uint16_t addr); +uint8_t magicformel_romh_read_hirom(uint16_t addr); +int magicformel_romh_phi1_read(uint16_t addr, uint8_t *value); +int magicformel_romh_phi2_read(uint16_t addr, uint8_t *value); +int magicformel_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void magicformel_freeze(void); +void magicformel_config_init(void); +void magicformel_reset(void); +void magicformel_config_setup(uint8_t *rawcart); +int magicformel_bin_attach(const char *filename, uint8_t *rawcart); +int magicformel_crt_attach(FILE *fd, uint8_t *rawcart); +void magicformel_detach(void); +void magicformel_powerup(void); + +int magicformel_snapshot_write_module(struct snapshot_s *s); +int magicformel_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/magicvoice.c b/src/Emulators/vice/c64/cart/magicvoice.c index 482c3240..70d95018 100644 --- a/src/Emulators/vice/c64/cart/magicvoice.c +++ b/src/Emulators/vice/c64/cart/magicvoice.c @@ -55,7 +55,6 @@ #include "sound.h" #include "t6721.h" #include "tpi.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "crt.h" @@ -130,7 +129,7 @@ static t6721_state *t6721 = NULL; /* context for the t6721 chip */ static tpi_context_t *tpi_context = NULL; /* context for the TPI chip */ #define MV_ROM_SIZE 0x4000 -static BYTE mv_rom[MV_ROM_SIZE]; +static uint8_t *mv_rom = NULL; static int mv_extgame = 0, mv_extexrom = 0; static int mv_game = 1, mv_exrom = 1; @@ -168,7 +167,7 @@ static int fifo_reset = 0; static int DTRD = 0; -void update_dtrd(void) +static void update_dtrd(void) { #if 1 if (datainfifo > (FIFO_LEN - 4)) { @@ -180,7 +179,7 @@ void update_dtrd(void) } /* hooked to callback of t6721 chip */ -static BYTE read_data(t6721_state *t6721, unsigned int *bit) +static uint8_t read_data(t6721_state *state, unsigned int *bit) { *bit = 0; @@ -204,7 +203,7 @@ static BYTE read_data(t6721_state *t6721, unsigned int *bit) /* writes one bit to the FIFO */ -static BYTE write_bit_to_fifo(BYTE bit) +static uint8_t write_bit_to_fifo(uint8_t bit) { if (fifo_reset) { /* DBG(("SPEECH: first bit %04x %d\n", writeptr, bit)); */ @@ -249,10 +248,10 @@ static BYTE write_bit_to_fifo(BYTE bit) /* writes one nibble to the FIFO */ -static void write_data_nibble(BYTE nibble) +static void write_data_nibble(uint8_t nibble) { int i; - BYTE mask; + uint8_t mask; #ifdef FIFODEBUG /* DBG(("SPEECH: wr byte %04x\n", nibble)); */ @@ -260,7 +259,7 @@ static void write_data_nibble(BYTE nibble) #endif for (i = 0, mask = 1; i < 4; ++i, mask <<= 1) { - if (write_bit_to_fifo((BYTE)(nibble & mask))) { + if (write_bit_to_fifo((uint8_t)(nibble & mask))) { #ifdef FIFODEBUG DBG(("dtrd) { + if (old != state->dtrd) { #ifdef IRQDEBUG - DBG(("MV: set dtrd IRQ:%x\n", t6721->dtrd)); + DBG(("MV: set dtrd IRQ:%x\n", state->dtrd)); #endif -/* DTRD = t6721->dtrd; */ +/* DTRD = state->dtrd; */ update_dtrd(); - tpicore_set_int(tpi_context, NMI_DTRD, t6721->dtrd); - tpicore_set_int(tpi_context, NMI_DTRD, t6721->dtrd ^ 1); + tpicore_set_int(tpi_context, NMI_DTRD, state->dtrd); + tpicore_set_int(tpi_context, NMI_DTRD, state->dtrd ^ 1); #if 0 - if (t6721->dtrd) { + if (state->dtrd) { cart_trigger_nmi(); } else { cartridge_release_freeze(); } #endif - old = t6721->dtrd; + old = state->dtrd; } } /* hooked to callback of t6721 chip */ -static void set_apd(t6721_state *t6721) +static void set_apd(t6721_state *state) { - if (t6721->apd) { + if (state->apd) { fifo_reset = 1; /* set FIFO reset condition */ /* reset FIFO */ @@ -305,23 +304,23 @@ static void set_apd(t6721_state *t6721) update_dtrd(); } - DBG(("MV: set apd:%x\n", t6721->apd)); - /* tpicore_set_int(tpi_context, NMI_APD, t6721->apd ^ 1); */ + DBG(("MV: set apd:%x\n", state->apd)); + /* tpicore_set_int(tpi_context, NMI_APD, state->apd ^ 1); */ } /* hooked to callback of t6721 chip */ -static void set_eos(t6721_state *t6721) +static void set_eos(t6721_state *state) { - DBG(("MV: set eos:%x\n", t6721->eos)); - tpicore_set_int(tpi_context, NMI_EOS, t6721->eos ^ 1); - tpicore_set_int(tpi_context, NMI_EOS, t6721->eos); + DBG(("MV: set eos:%x\n", state->eos)); + tpicore_set_int(tpi_context, NMI_EOS, state->eos ^ 1); + tpicore_set_int(tpi_context, NMI_EOS, state->eos); } /***************************************************************************** LA05-124 Gate Array 4bit parallel to serial converter/buffer: - + 18 in t6721 DTRD 20 in t6721 phi2 6 in t6721 APD (reset, will also reset FIFO) @@ -370,7 +369,7 @@ static int ga_pc6; static int ga_pb5; static int ga_pb6; -void ga_reset(void) +static void ga_reset(void) { ga_pc6 = 0; ga_pb5 = 0; @@ -503,7 +502,7 @@ static void ga_memconfig_changed(int mode) mv_gameE000_enabled = 0; } - cart_config_changed_slot0((BYTE)((mv_mapped_game) | ((mv_mapped_exrom) << 1)), (BYTE)((mv_mapped_game) | ((mv_mapped_exrom) << 1)), mode); + cart_config_changed_slot0((uint8_t)((mv_mapped_game) | ((mv_mapped_exrom) << 1)), (uint8_t)((mv_mapped_game) | ((mv_mapped_exrom) << 1)), mode); #ifdef CFGDEBUG this = (ga_pb6 << 0) | (ga_pb5 << 1) | (ga_pc6 << 2) | (mv_exrom << 3); @@ -569,7 +568,7 @@ static void restore_int(unsigned int int_num, int value) DBG(("MV: tpi restore int %02x %02x\n", int_num, value)); } -static void reset(tpi_context_t *tpi_context) +static void reset(tpi_context_t *tpi_ctx) { DBG(("MV: tpi reset\n")); } @@ -596,9 +595,9 @@ static void reset(tpi_context_t *tpi_context) #define MV_EXROM_GAMECART 0 #endif -static BYTE read_pa(tpi_context_t *tpi_context) +static uint8_t read_pa(tpi_context_t *tpi_ctx) { - BYTE byte = 0; + uint8_t byte = 0; #ifdef USEPASSTHROUGHHACK if (cart_getid_slotmain() != CARTRIDGE_NONE) { /* passthrough */ @@ -614,19 +613,20 @@ static BYTE read_pa(tpi_context_t *tpi_context) byte |= ((t6721->eos ^ 1) << 6); /* !EOS = End of Speech from T6721 */ byte |= (DTRD << 7); /* DIR = Data in Ready from 40105 */ - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPA]) | (tpi_context->c_tpi[TPI_PA] & tpi_context->c_tpi[TPI_DDPA]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPA]) + | (tpi_ctx->c_tpi[TPI_PA] & tpi_ctx->c_tpi[TPI_DDPA]); /* DBG(("MV: read pa %02x\n", byte)); */ return byte; } -static void store_pa(tpi_context_t *tpi_context, BYTE byte) +static void store_pa(tpi_context_t *tpi_ctx, uint8_t byte) { - static BYTE last; + static uint8_t last; /* DBG(("MV: store pa %02x\n", byte)); */ if ((byte & 0x10)) { /* out: PB3..PB0 go to D3..D0*/ - write_data_nibble((BYTE)(last & 0x0f)); /* write nibble to FIFO */ + write_data_nibble((uint8_t)(last & 0x0f)); /* write nibble to FIFO */ } last = byte; } @@ -642,12 +642,12 @@ static void store_pa(tpi_context_t *tpi_context, BYTE byte) PB6 OUT? -> Gate Array (with pullup) PB7 IN: !EXROM <- Exrom of the MV Cartridge Port (with pullup) */ -static void store_pb(tpi_context_t *tpi_context, BYTE byte) +static void store_pb(tpi_context_t *tpi_ctx, uint8_t byte) { /* DBG(("MV: store pp %02x\n", byte)); */ t6721->wr = (byte >> 4) & 1; /* wr line */ /* out: PB3..PB0 go to D3..D0*/ - t6721_store(t6721, (BYTE)(byte & 0x0f)); + t6721_store(t6721, (uint8_t)(byte & 0x0f)); mv_passthrough_addr = (int)(byte & 0x0f) << 12; ga_pb5 = (byte >> 5) & 1; @@ -655,9 +655,9 @@ static void store_pb(tpi_context_t *tpi_context, BYTE byte) ga_memconfig_changed(CMODE_READ); } -static BYTE read_pb(tpi_context_t *tpi_context) +static uint8_t read_pb(tpi_context_t *tpi_ctx) { - BYTE byte = 0; + uint8_t byte = 0; byte |= t6721_read(t6721) & 0x0f; #if 0 @@ -676,7 +676,8 @@ static BYTE read_pb(tpi_context_t *tpi_context) /* DBG(("MV: read pb extexrom %d\n", mv_extexrom)); */ byte |= ((mv_extexrom ^ 1) << 7); #endif - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPB]) | (tpi_context->c_tpi[TPI_PB] & tpi_context->c_tpi[TPI_DDPB]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPB]) + | (tpi_ctx->c_tpi[TPI_PB] & tpi_ctx->c_tpi[TPI_DDPB]); return byte; } @@ -693,7 +694,7 @@ static BYTE read_pb(tpi_context_t *tpi_context) PC6 OUT: (CA) CA ? <-> Gate Array (with pullup) (toggles rom on/off ?) PC7 OUT: (CB) !EXROM -> C64 Cartridge Port */ -static void store_pc(tpi_context_t *tpi_context, BYTE byte) +static void store_pc(tpi_context_t *tpi_ctx, uint8_t byte) { /* this function is actually never used ? */ DBG(("MV: store pc %02x\n", byte)); @@ -712,44 +713,45 @@ static void store_pc(tpi_context_t *tpi_context, BYTE byte) #endif } -static BYTE read_pc(tpi_context_t *tpi_context) +static uint8_t read_pc(tpi_context_t *tpi_ctx) { - static BYTE byte = 0; + static uint8_t byte = 0; #if 0 /* IRQ inputs */ byte |= ((t6721->eos ^ 1) << 2); /* !EOS (End of Speech) */ byte |= (DTRD << 3); /* DIR (Data in Ready) */ #endif - byte = (byte & ~(tpi_context->c_tpi)[TPI_DDPC]) | (tpi_context->c_tpi[TPI_PC] & tpi_context->c_tpi[TPI_DDPC]); + byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPC]) + | (tpi_ctx->c_tpi[TPI_PC] & tpi_ctx->c_tpi[TPI_DDPC]); DBG(("MV: read pc %02x\n", byte)); return byte; } -static void set_ca(tpi_context_t *tpi_context, int a) +static void set_ca(tpi_context_t *tpi_ctx, int a) { /* DBG(("MV: set ca %02x\n", a)); */ ga_pc6 = (a != 0); ga_memconfig_changed(CMODE_READ); } -static void set_cb(tpi_context_t *tpi_context, int a) +static void set_cb(tpi_context_t *tpi_ctx, int a) { /* DBG(("MV: set cb %02x\n", a)); */ mv_exrom = (a == 0); ga_memconfig_changed(CMODE_READ); } -static void undump_pa(tpi_context_t *tpi_context, BYTE byte) +static void undump_pa(tpi_context_t *tpi_ctx, uint8_t byte) { DBG(("MV: undump pa %02x\n", byte)); } -static void undump_pb(tpi_context_t *tpi_context, BYTE byte) +static void undump_pb(tpi_context_t *tpi_ctx, uint8_t byte) { DBG(("MV: undump pb %02x\n", byte)); } -static void undump_pc(tpi_context_t *tpi_context, BYTE byte) +static void undump_pc(tpi_context_t *tpi_ctx, uint8_t byte) { DBG(("MV: undump pc %02x\n", byte)); } @@ -758,7 +760,7 @@ static void undump_pc(tpi_context_t *tpi_context, BYTE byte) I/O Area *****************************************************************************/ -static void magicvoice_io2_store(WORD addr, BYTE data) +static void magicvoice_io2_store(uint16_t addr, uint8_t data) { switch (addr & 7) { case 5: @@ -772,13 +774,13 @@ static void magicvoice_io2_store(WORD addr, BYTE data) case 6: break; } - tpicore_store(tpi_context, (WORD)(addr & 7), data); + tpicore_store(tpi_context, (uint16_t)(addr & 7), data); } -static BYTE magicvoice_io2_read(WORD addr) +static uint8_t magicvoice_io2_read(uint16_t addr) { - BYTE value = 0; - value = tpicore_read(tpi_context, (WORD)(addr & 7)); + uint8_t value = 0; + value = tpicore_read(tpi_context, (uint16_t)(addr & 7)); switch (addr & 7) { case 5: DBGREG(("MV: @:%04x io2 r %04x %02x (IRQ Mask)\n", reg_pc, addr, value)); @@ -803,9 +805,9 @@ static BYTE magicvoice_io2_read(WORD addr) return value; } -static BYTE magicvoice_io2_peek(WORD addr) +static uint8_t magicvoice_io2_peek(uint16_t addr) { - return tpicore_peek(tpi_context, (WORD)(addr & 7)); + return tpicore_peek(tpi_context, (uint16_t)(addr & 7)); } static int magicvoice_io2_dump(void) @@ -820,18 +822,20 @@ static int magicvoice_io2_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t magicvoice_io2_device = { - CARTRIDGE_NAME_MAGIC_VOICE, - IO_DETACH_CART, - NULL, - 0xdf80, 0xdfff, 0x07, - 1, /* read is always valid */ - magicvoice_io2_store, - magicvoice_io2_read, - magicvoice_io2_peek, - magicvoice_io2_dump, - CARTRIDGE_MAGIC_VOICE, - 0, - 0 + CARTRIDGE_NAME_MAGIC_VOICE, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf80, 0xdfff, 0x07, /* range for the device, regs:$df80-$df87, mirrors:$df88-$dfff */ + 1, /* read is always valid */ + magicvoice_io2_store, /* store function */ + NULL, /* NO poke function */ + magicvoice_io2_read, /* read function */ + magicvoice_io2_peek, /* peek function */ + magicvoice_io2_dump, /* device state information dump function */ + CARTRIDGE_MAGIC_VOICE, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *magicvoice_io2_list_item = NULL; @@ -844,11 +848,14 @@ static const export_resource_t export_res = { /* Some prototypes are needed */ static int magicvoice_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); static void magicvoice_sound_machine_close(sound_t *psid); -static int magicvoice_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); -static void magicvoice_sound_machine_store(sound_t *psid, WORD addr, BYTE byte); -static BYTE magicvoice_sound_machine_read(sound_t *psid, WORD addr); static void magicvoice_sound_machine_reset(sound_t *psid, CLOCK cpu_clk); +#ifdef SOUND_SYSTEM_FLOAT +static int magicvoice_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int magicvoice_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int magicvoice_sound_machine_cycle_based(void) { return 0; @@ -859,20 +866,34 @@ static int magicvoice_sound_machine_channels(void) return 1; } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the MagicVoice cartridge sound */ +static sound_chip_mixing_spec_t magicvoice_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* left channel volume % in case of stereo output, default output to both */ + 100 /* right channel volume % in case of stereo output, default output to both */ + } +}; +#endif + +/* MagicVoice cartridge sound chip */ static sound_chip_t magicvoice_sound_chip = { - NULL, /* no open */ - magicvoice_sound_machine_init, - magicvoice_sound_machine_close, - magicvoice_sound_machine_calculate_samples, - magicvoice_sound_machine_store, - magicvoice_sound_machine_read, - magicvoice_sound_machine_reset, - magicvoice_sound_machine_cycle_based, - magicvoice_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + magicvoice_sound_machine_init, /* sound chip init function */ + magicvoice_sound_machine_close, /* sound chip close function */ + magicvoice_sound_machine_calculate_samples, /* sound chip calculate samples function */ + NULL, /* NO sound chip store function */ + NULL, /* NO sound chip read function */ + magicvoice_sound_machine_reset, /* sound chip reset function, currently only used for debug */ + magicvoice_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, sound chip is NOT cycle based */ + magicvoice_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */ +#ifdef SOUND_SYSTEM_FLOAT + magicvoice_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* chip enabled, toggled when sound chip is (de-)activated */ }; -static WORD magicvoice_sound_chip_offset = 0; +static uint16_t magicvoice_sound_chip_offset = 0; void magicvoice_sound_chip_init(void) { @@ -886,7 +907,7 @@ int magicvoice_cart_enabled(void) /* ---------------------------------------------------------------------*/ -static BYTE read_remapped(WORD addr) +static uint8_t read_remapped(uint16_t addr) { addr &= 0x0fff; addr |= mv_passthrough_addr; @@ -896,7 +917,7 @@ static BYTE read_remapped(WORD addr) return romh_banks[addr & 0x1fff]; } -int magicvoice_ultimax_read(WORD addr, BYTE *value) +int magicvoice_ultimax_read(uint16_t addr, uint8_t *value) { if (mv_gameA000_at3000_enabled) { /* FIXME: hack! */ @@ -909,7 +930,7 @@ int magicvoice_ultimax_read(WORD addr, BYTE *value) return CART_READ_C64MEM; } -int magicvoice_roml_read(WORD addr, BYTE *value) +int magicvoice_roml_read(uint16_t addr, uint8_t *value) { #if 0 if ((mv_game8000_enabled) && (cart_getid_slotmain() != CARTRIDGE_NONE)) { @@ -929,7 +950,7 @@ int magicvoice_roml_read(WORD addr, BYTE *value) #endif } -int magicvoice_a000_bfff_read(WORD addr, BYTE *value) +int magicvoice_a000_bfff_read(uint16_t addr, uint8_t *value) { #if 0 if ((mv_gameA000_enabled) && (cart_getid_slotmain() != CARTRIDGE_NONE)) { @@ -969,7 +990,7 @@ int magicvoice_a000_bfff_read(WORD addr, BYTE *value) #endif } -int magicvoice_romh_read(WORD addr, BYTE *value) +int magicvoice_romh_read(uint16_t addr, uint8_t *value) { #if 0 if (addr == 0xfffa) { @@ -1007,7 +1028,7 @@ int magicvoice_romh_read(WORD addr, BYTE *value) #endif } -int magicvoice_romh_phi1_read(WORD addr, BYTE *value) +int magicvoice_romh_phi1_read(uint16_t addr, uint8_t *value) { if ((mv_gameE000_enabled) && (mv_extexrom == 0) && (mv_extgame == 1)) { /* real ultimax mode for game */ @@ -1016,7 +1037,7 @@ int magicvoice_romh_phi1_read(WORD addr, BYTE *value) return CART_READ_C64MEM; } -int magicvoice_romh_phi2_read(WORD addr, BYTE *value) +int magicvoice_romh_phi2_read(uint16_t addr, uint8_t *value) { if ((mv_gameE000_enabled) && (mv_extexrom == 0) && (mv_extgame == 1)) { /* real ultimax mode for game */ @@ -1025,7 +1046,7 @@ int magicvoice_romh_phi2_read(WORD addr, BYTE *value) return CART_READ_C64MEM; } -int magicvoice_peek_mem(WORD addr, BYTE *value) +int magicvoice_peek_mem(uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { if (mv_game8000_enabled) { @@ -1059,10 +1080,10 @@ int magicvoice_peek_mem(WORD addr, BYTE *value) return CART_READ_C64MEM; } -void magicvoice_passthrough_changed(export_t *export) +void magicvoice_passthrough_changed(export_t *ex) { - mv_extexrom = export->exrom; - mv_extgame = export->game; + mv_extexrom = ex->exrom; + mv_extgame = ex->game; DBG(("MV passthrough changed exrom: %d game: %d\n", mv_extexrom, mv_extgame)); ga_memconfig_changed(CMODE_READ); @@ -1088,19 +1109,27 @@ static int set_magicvoice_enabled(int value, void *param) io_source_unregister(magicvoice_io2_list_item); magicvoice_io2_list_item = NULL; magicvoice_sound_chip.chip_enabled = 0; + if (mv_rom) { + lib_free(mv_rom); + mv_rom = NULL; + } DBG(("MV: set_enabled unregistered\n")); } else if (!magicvoice_sound_chip.chip_enabled && val) { + if (mv_rom == NULL) { + mv_rom = lib_malloc(MV_ROM_SIZE); + } if (param) { /* if the param is != NULL, then we should load the default image file */ - if (magicvoice_filename) { - if (*magicvoice_filename) { - if (cartridge_attach_image(CARTRIDGE_MAGIC_VOICE, magicvoice_filename) < 0) { - DBG(("MV: set_enabled did not register\n")); - return -1; - } - /* magicvoice_sound_chip.chip_enabled = 1; */ /* cartridge_attach_image will end up calling set_magicvoice_enabled again */ - return 0; + if ((magicvoice_filename != NULL) && (*magicvoice_filename != 0)) { + if ((cartridge_attach_image(CARTRIDGE_CRT, magicvoice_filename) < 0) && + (cartridge_attach_image(CARTRIDGE_MAGIC_VOICE, magicvoice_filename) < 0)) { + DBG(("MV: set_enabled did not register\n")); + return -1; /* loading the default was requested, but file could not be loaded */ } + /* magicvoice_sound_chip.chip_enabled = 1; */ /* cartridge_attach_image will end up calling set_magicvoice_enabled again */ + return 0; + } else { + return -1; /* loading the default was requested, but no filename was set */ } } else { cart_power_off(); @@ -1174,21 +1203,15 @@ void magicvoice_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-magicvoiceimage", SET_RESOURCE, 1, + { "-magicvoiceimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MagicVoiceImage", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_MAGICVOICE_IMAGE_NAME, - NULL, NULL }, - { "-magicvoice", SET_RESOURCE, 0, + "", "Specify name of Magic Voice ROM image" }, + { "-magicvoice", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MagicVoiceCartridgeEnabled", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_MAGICVOICE, - NULL, NULL }, - { "+magicvoice", SET_RESOURCE, 0, + NULL, "Enable the Magic Voice cartridge" }, + { "+magicvoice", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MagicVoiceCartridgeEnabled", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_MAGICVOICE, - NULL, NULL }, + NULL, "Disable the Magic Voice cartridge" }, CMDLINE_LIST_END }; @@ -1211,7 +1234,7 @@ void magicvoice_shutdown(void) } } -void magicvoice_setup_context(machine_context_t *machine_context) +void magicvoice_setup_context(machine_context_t *machine_ctx) { DBG(("MV: setup_context\n")); @@ -1219,7 +1242,7 @@ void magicvoice_setup_context(machine_context_t *machine_context) tpi_context->prv = NULL; - tpi_context->context = (void *)machine_context; + tpi_context->context = (void *)machine_ctx; tpi_context->rmw_flag = &maincpu_rmw_flag; tpi_context->clk_ptr = &maincpu_clk; @@ -1261,7 +1284,7 @@ static void mv_ack_nmi(void) } #endif -int magicvoice_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +int magicvoice_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { switch (addr & 0xf000) { case 0xf000: @@ -1270,7 +1293,9 @@ int magicvoice_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li return CART_READ_THROUGH; /* "passthrough" */ } else { if (mv_romE000_enabled) { - *base = (BYTE *)(mv_rom - (BYTE *)0xc000); + /* *base = (uint8_t *)(mv_rom - (uint8_t *)0xc000); */ + *base = (uint8_t *)(0 - 0xc000); + *base += (uintptr_t)(mv_rom); *start = 0xe000; *limit = 0xfffd; return CART_READ_VALID; @@ -1290,7 +1315,9 @@ int magicvoice_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li return CART_READ_THROUGH_NO_ULTIMAX; /* "passthrough" */ } else { if (mv_romA000_enabled) { - *base = (BYTE *)(mv_rom - (BYTE *)0xa000); + /* *base = (uint8_t *)(mv_rom - (uint8_t *)0xa000); */ + *base = (uint8_t *)(0 - 0xa000); + *base += (uintptr_t)(mv_rom); *start = 0xa000; *limit = 0xbffd; return CART_READ_VALID; @@ -1327,12 +1354,12 @@ int magicvoice_mmu_translate(unsigned int addr, BYTE **base, int *start, int *li } /* called at reset */ -void magicvoice_config_init(export_t *export) +void magicvoice_config_init(export_t *ex) { DBG(("MV: magicvoice_config_init\n")); - mv_extexrom = export->exrom; - mv_extgame = export->game; + mv_extexrom = ex->exrom; + mv_extgame = ex->game; if (magicvoice_sound_chip.chip_enabled) { mv_exrom = 1; @@ -1344,7 +1371,7 @@ void magicvoice_config_init(export_t *export) } } -void magicvoice_config_setup(BYTE *rawcart) +void magicvoice_config_setup(uint8_t *rawcart) { DBG(("MV: magicvoice_config_setup\n")); memcpy(mv_rom, rawcart, 0x4000); @@ -1363,11 +1390,12 @@ static int magicvoice_common_attach(void) return set_magicvoice_enabled(1, NULL); } -int magicvoice_bin_attach(const char *filename, BYTE *rawcart) +int magicvoice_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, MV_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } + set_magicvoice_filename(filename, NULL); /* set the resource */ return magicvoice_common_attach(); } @@ -1392,7 +1420,7 @@ int magicvoice_bin_attach(const char *filename, BYTE *rawcart) * $000040 CHIP ROM #000 $8000 $4000 $4010 * */ -int magicvoice_crt_attach(FILE *fd, BYTE *rawcart) +int magicvoice_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { int i; crt_chip_header_t chip; @@ -1418,6 +1446,7 @@ int magicvoice_crt_attach(FILE *fd, BYTE *rawcart) if (i != 1 && i != 2) { return -1; } + set_magicvoice_filename(filename, NULL); /* set the resource */ return magicvoice_common_attach(); } @@ -1433,6 +1462,13 @@ int magicvoice_enable(void) return set_magicvoice_enabled(1, (void*)1); } +int magicvoice_disable(void) +{ + DBG(("MV: disable\n")); + return set_magicvoice_enabled(0, (void*)1); +} + + void magicvoice_init(void) { DBG(("MV: init\n")); @@ -1456,35 +1492,43 @@ void magicvoice_reset(void) /* ---------------------------------------------------------------------*/ -/* FIXME: what are these two about anyway ? */ -static BYTE magicvoice_sound_machine_read(sound_t *psid, WORD addr) +/* + called periodically for every sound fragment that is played +*/ +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +static int magicvoice_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) { - DBG(("MV: magicvoice_sound_machine_read\n")); + int i; + float *buffer; - return 0; /* ? */ -} + buffer = lib_malloc(nr * sizeof(float)); -static void magicvoice_sound_machine_store(sound_t *psid, WORD addr, BYTE byte) -{ - DBG(("MV: magicvoice_sound_machine_store\n")); -} + t6721_update_output(t6721, buffer, nr); -/* - called periodically for every sound fragment that is played -*/ -static int magicvoice_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) + /* mix generated samples to output */ + for (i = 0; i < nr; i++) { + pbuf[i] = buffer[i]; + } + + lib_free(buffer); + + return nr; +} +#else +static int magicvoice_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) { int i; - SWORD *buffer; + int16_t *buffer; - buffer = lib_malloc(nr * sizeof(SWORD)); + buffer = lib_malloc(nr * sizeof(int16_t)); t6721_update_output(t6721, buffer, nr); /* mix generated samples to output */ for (i = 0; i < nr; i++) { pbuf[i * soc] = sound_audio_mix(pbuf[i * soc], buffer[i]); - if (soc > 1) { + if (soc == SOUND_OUTPUT_STEREO) { pbuf[(i * soc) + 1] = sound_audio_mix(pbuf[(i * soc) + 1], buffer[i]); } } @@ -1493,6 +1537,7 @@ static int magicvoice_sound_machine_calculate_samples(sound_t **psid, SWORD *pbu return nr; } +#endif static void magicvoice_sound_machine_reset(sound_t *psid, CLOCK cpu_clk) { @@ -1522,8 +1567,6 @@ static void magicvoice_sound_machine_close(sound_t *psid) /* FIXME: implement snapshot support */ int magicvoice_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -1532,6 +1575,9 @@ int magicvoice_snapshot_write_module(snapshot_t *s) return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -1546,7 +1592,7 @@ int magicvoice_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/c64/cart/magicvoice.h b/src/Emulators/vice/c64/cart/magicvoice.h index 6f03e14e..f537b074 100644 --- a/src/Emulators/vice/c64/cart/magicvoice.h +++ b/src/Emulators/vice/c64/cart/magicvoice.h @@ -38,42 +38,44 @@ struct machine_context_s; -extern void magicvoice_reset(void); -extern int magicvoice_cart_enabled(void); +void magicvoice_reset(void); +int magicvoice_cart_enabled(void); -extern int magicvoice_a000_bfff_read(WORD addr, BYTE *value); -extern int magicvoice_roml_read(WORD addr, BYTE *value); -extern int magicvoice_romh_read(WORD addr, BYTE *value); -extern int magicvoice_ultimax_read(WORD addr, BYTE *value); -extern int magicvoice_romh_phi1_read(WORD addr, BYTE *value); -extern int magicvoice_romh_phi2_read(WORD addr, BYTE *value); -extern int magicvoice_peek_mem(WORD addr, BYTE *value); +int magicvoice_a000_bfff_read(uint16_t addr, uint8_t *value); +int magicvoice_roml_read(uint16_t addr, uint8_t *value); +int magicvoice_romh_read(uint16_t addr, uint8_t *value); +int magicvoice_ultimax_read(uint16_t addr, uint8_t *value); +int magicvoice_romh_phi1_read(uint16_t addr, uint8_t *value); +int magicvoice_romh_phi2_read(uint16_t addr, uint8_t *value); +int magicvoice_peek_mem(uint16_t addr, uint8_t *value); -extern void magicvoice_passthrough_changed(export_t *export); +void magicvoice_passthrough_changed(export_t *export); -extern void magicvoice_init(void); -extern void magicvoice_shutdown(void); +void magicvoice_init(void); +void magicvoice_shutdown(void); -extern void magicvoice_config_init(export_t *export); -extern void magicvoice_config_setup(BYTE *rawcart); -extern void magicvoice_setup_context(struct machine_context_s *machine_context); +void magicvoice_config_init(export_t *export); +void magicvoice_config_setup(uint8_t *rawcart); +void magicvoice_setup_context(struct machine_context_s *machine_context); -extern int magicvoice_resources_init(void); -extern void magicvoice_resources_shutdown(void); +int magicvoice_resources_init(void); +void magicvoice_resources_shutdown(void); -extern int magicvoice_cmdline_options_init(void); +int magicvoice_cmdline_options_init(void); -extern int magicvoice_bin_attach(const char *filename, BYTE *rawcart); -extern int magicvoice_crt_attach(FILE *fd, BYTE *rawcart); -extern int magicvoice_enable(void); -extern void magicvoice_detach(void); -extern const char *magicvoice_get_file_name(void); -extern int magicvoice_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +int magicvoice_bin_attach(const char *filename, uint8_t *rawcart); +int magicvoice_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int magicvoice_enable(void); +int magicvoice_disable(void); +void magicvoice_detach(void); +const char *magicvoice_get_file_name(void); +int magicvoice_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern void magicvoice_sound_chip_init(void); +void magicvoice_sound_chip_init(void); struct snapshot_s; -extern int magicvoice_snapshot_read_module(struct snapshot_s *s); -extern int magicvoice_snapshot_write_module(struct snapshot_s *s); + +int magicvoice_snapshot_read_module(struct snapshot_s *s); +int magicvoice_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/maxbasic.c b/src/Emulators/vice/c64/cart/maxbasic.c new file mode 100644 index 00000000..6f0d2fe3 --- /dev/null +++ b/src/Emulators/vice/c64/cart/maxbasic.c @@ -0,0 +1,260 @@ +/* + * maxbasic.c - Cartridge handling, max-basic cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64memrom.h" +#include "c64rom.h" +#include "cartio.h" +#include "cartridge.h" +#include "maxbasic.h" +#include "export.h" +#include "ram.h" +#include "resources.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + MAX Basic + + 16K ROM + - ROM is mapped to $8000 and $e000 using ultimax mode + + 2K RAM + - RAM is mapped to $0800 +*/ + +#define CART_RAM_SIZE (2 * 1024) + +static const export_resource_t export_res = { + CARTRIDGE_NAME_MAX_BASIC, 0, 1, NULL, NULL, CARTRIDGE_MAX_BASIC +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t maxbasic_0800_0fff_read(uint16_t addr) +{ + return export_ram0[addr & 0x07ff]; +} + +void maxbasic_0800_0fff_store(uint16_t addr, uint8_t value) +{ + export_ram0[addr & 0x07ff] = value; +} + +uint8_t maxbasic_roml_read(uint16_t addr) +{ + return roml_banks[(addr & 0x1fff)]; +} + +uint8_t maxbasic_romh_read(uint16_t addr) +{ + return romh_banks[(addr & 0x1fff)]; +} + +int maxbasic_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if (addr >= 0xe000) { + *value = romh_banks[addr & 0x1fff]; + return CART_READ_VALID; + } else if ((addr >= 0xa000) && (addr <= 0xbfff)) { + *value = roml_banks[addr & 0x1fff]; + return CART_READ_VALID; + } else if ((addr >= 0x0800) && (addr <= 0x0fff)) { + *value = export_ram0[addr & 0x07ff]; + return CART_READ_VALID; + } + return CART_READ_THROUGH; +} + +void maxbasic_config_init(void) +{ + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +void maxbasic_config_setup(uint8_t *rawcart) +{ + memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); + memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void maxbasic_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + +static int maxbasic_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + return 0; +} + +int maxbasic_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return maxbasic_common_attach(); +} + +int maxbasic_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i; + + for (i = 0; i < 2; i++) { + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart + (i * 0x2000), 0, &chip, fd)) { + return -1; + } + } + + return maxbasic_common_attach(); +} + +void maxbasic_detach(void) +{ + export_remove(&export_res); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTMAXBASIC snapshot module format: + + type | name | description + -------------------------- + ARRAY | ROML | 8192 BYTES of ROML data + ARRAY | ROMH | 8192 BYTES of ROMH data + ARRAY | RAM | 2048 BYTES of RAM data + */ + +static const char snap_module_name[] = "CARTMAXBASIC"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int maxbasic_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (SMW_BA(m, roml_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + if (SMW_BA(m, romh_banks, 0x2000) < 0) { + snapshot_module_close(m); + return -1; + } + + if (SMW_BA(m, export_ram0, 0x0800) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int maxbasic_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (SMR_BA(m, roml_banks, 0x2000) < 0) { + goto fail; + } + + if (SMR_BA(m, romh_banks, 0x2000) < 0) { + goto fail; + } + + if (SMR_BA(m, export_ram0, 0x0800) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return maxbasic_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/maxbasic.h b/src/Emulators/vice/c64/cart/maxbasic.h new file mode 100644 index 00000000..94b6846f --- /dev/null +++ b/src/Emulators/vice/c64/cart/maxbasic.h @@ -0,0 +1,54 @@ +/* + * maxbasic.h - Cartridge handling, max-basic cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_MAXBASIC_H +#define VICE_MAXBASIC_H + +#include + +#include "vicetypes.h" +#include "c64cart.h" + +struct snapshot_s; + +uint8_t maxbasic_0800_0fff_read(uint16_t addr); +void maxbasic_0800_0fff_store(uint16_t addr, uint8_t value); +uint8_t maxbasic_roml_read(uint16_t addr); +uint8_t maxbasic_romh_read(uint16_t addr); +int maxbasic_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void maxbasic_config_init(void); +void maxbasic_reset(void); +void maxbasic_config_setup(uint8_t *rawcart); +int maxbasic_bin_attach(const char *filename, uint8_t *rawcart); +int maxbasic_crt_attach(FILE *fd, uint8_t *rawcart); +void maxbasic_detach(void); +void maxbasic_powerup(void); + +int maxbasic_snapshot_write_module(struct snapshot_s *s); +int maxbasic_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/megabyter.c b/src/Emulators/vice/c64/cart/megabyter.c new file mode 100644 index 00000000..9f8c0812 --- /dev/null +++ b/src/Emulators/vice/c64/cart/megabyter.c @@ -0,0 +1,545 @@ + +/* + * megabyter.c - Cartridge handling of the megabyter cart. + * + * Written by + * Chester Kollschen + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "megabyter.h" +#include "export.h" +#include "flash800.h" +#include "lib.h" +#include "log.h" +#include "maincpu.h" +#include "mem.h" +#include "monitor.h" +#include "resources.h" +#include "snapshot.h" +#include "util.h" +#include "sysfile.h" + +/* + Protovision "Megabyter" + + - 1MiB Flash ROM (29F800CB) + + ROM is always banked to ROML, ie $8000 + + - two write-only Registers in IO1 + + $de00 - selects ROM bank + bit 7 unused + bit 0-6 bank 0-127 + + $de02 + bit 7 LED status (1: enabled) + bit 2-6 unused + bit 1 EXROM (0: low, 1: high) + bit 0 GAME (0: high, 1: low) +*/ + +/* #define DEBUG_MEGABYTER */ + +#ifdef DEBUG_MEGABYTER +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +#define MEGABYTER_BANK_BITS 7 +#define MEGABYTER_NUM_BANKS (1 << (MEGABYTER_BANK_BITS)) +#define MEGABYTER_BANK_MASK ((MEGABYTER_NUM_BANKS) -1) +#define MEGABYTER_BANK_SIZE 0x2000 +#define MEGABYTER_ROM_SIZE (MEGABYTER_NUM_BANKS * MEGABYTER_BANK_SIZE) + +/* the 29F800CB statemachine */ +static flash800_context_t *megabyter_state = NULL; + +/* writing back to crt enabled */ +static int megabyter_crt_write; + +/* optimizing crt enabled */ +static int megabyter_crt_optimize; + +/* backup of the registers */ +static uint8_t megabyter_register_00, megabyter_register_02; + +/* decoding table of the modes */ +static const uint8_t megabyter_memconfig[4] = { + CMODE_8KGAME, /* exrom=0, game=1 */ + CMODE_16KGAME, /* exrom=0, game=0 */ + CMODE_RAM, /* exrom=1, game=1 */ + CMODE_ULTIMAX /* exrom=1, game=0 */ +}; + +/* filename when attached */ +static char *megabyter_filename = NULL; +static int megabyter_filetype = 0; + +/* ---------------------------------------------------------------------*/ +static io_source_list_t *megabyter_io1_list_item = NULL; + +static void megabyter_io1_store(uint16_t addr, uint8_t value); +static uint8_t megabyter_io1_peek(uint16_t addr); +static int megabyter_io1_dump(void); + +static io_source_t megabyter_io1_device = { + CARTRIDGE_NAME_MEGABYTER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device */ + 0, /* read is never valid, device is write only */ + megabyter_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + megabyter_io1_peek, /* peek function */ + megabyter_io1_dump, /* device state information dump function */ + CARTRIDGE_MEGABYTER, /* cartridge ID */ + 0, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_MEGABYTER, 1, 1, &megabyter_io1_device, NULL, CARTRIDGE_MEGABYTER +}; + +static void megabyter_io1_store(uint16_t addr, uint8_t value) +{ + uint8_t mem_mode; + + /* only A1 is decoded */ + if (addr & 2) { + /* mode register */ + megabyter_register_02 = value & 0x83; /* we only remember led, mode, exrom, game */ + mem_mode = megabyter_memconfig[megabyter_register_02 & 0x03]; + cart_config_changed_slotmain(mem_mode, mem_mode, CMODE_READ); + /* TODO: change led */ + /* (value & 0x80) -> led on if true, led off if false */ + } else { + /* bank register */ + megabyter_register_00 = (uint8_t)(value & MEGABYTER_BANK_MASK); + } + + DBG(("Megabyter: addr:0x%04x, value:%02x (bank:%02x mode:%i LED:%i)", + addr | 0xde00u, value, megabyter_register_00, + megabyter_memconfig[megabyter_register_02 & 0x03], + megabyter_register_02 >> 7)); + + cart_romlbank_set_slotmain(megabyter_register_00); + cart_port_config_changed_slotmain(); +} + +/* ---------------------------------------------------------------------*/ + +static uint8_t megabyter_io1_peek(uint16_t addr) +{ + return (addr & 2) ? megabyter_register_02 : megabyter_register_00; +} + +static int megabyter_io1_dump(void) +{ + int config = megabyter_memconfig[megabyter_register_02 & 0x03]; + mon_out("Mode: %i (%s), LED is %s\n", + config, cart_config_string(config), + (megabyter_register_02 & 0x80) ? "on" : "off"); + return 0; +} + + +/* ---------------------------------------------------------------------*/ + +static int set_megabyter_crt_write(int val, void *param) +{ + megabyter_crt_write = val ? 1 : 0; + return 0; +} + +static int set_megabyter_crt_optimize(int val, void *param) +{ + megabyter_crt_optimize = val ? 1 : 0; + return 0; +} + +static int megabyter_write_chip_if_not_empty(FILE* fd, crt_chip_header_t *chip, uint8_t *data) +{ + int i; + + for (i = 0; i < chip->size; i++) { + if ((data[i] != 0xff) || (megabyter_crt_optimize == 0)) { + if (crt_write_chip(data, chip, fd)) { + return -1; + } + return 0; + } + } + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static const resource_int_t resources_int[] = { + { "MegabyterWriteCRT", 0, RES_EVENT_STRICT, (resource_value_t)0, + &megabyter_crt_write, set_megabyter_crt_write, NULL }, + { "MegabyterOptimizeCRT", 1, RES_EVENT_STRICT, (resource_value_t)1, + &megabyter_crt_optimize, set_megabyter_crt_optimize, NULL }, + RESOURCE_INT_LIST_END +}; + +int megabyter_resources_init(void) +{ + return resources_register_int(resources_int); +} + +void megabyter_resources_shutdown(void) +{ +} + +/* ---------------------------------------------------------------------*/ + +static const cmdline_option_t cmdline_options[] = +{ + { "-megabytercrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MegabyterWriteCRT", (resource_value_t)1, + NULL, "Enable writing to " CARTRIDGE_NAME_MEGABYTER " .crt image" }, + { "+megabytercrtwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MegabyterWriteCRT", (resource_value_t)0, + NULL, "Disable writing to " CARTRIDGE_NAME_MEGABYTER " .crt image" }, + { "-megabytercrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MegabyterOptimizeCRT", (resource_value_t)1, + NULL, "Enable " CARTRIDGE_NAME_MEGABYTER " .crt image optimize on write" }, + { "+megabytercrtoptimize", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "MegabyterOptimizeCRT", (resource_value_t)0, + NULL, "Disable optimizing " CARTRIDGE_NAME_MEGABYTER " .crt image on write" }, + CMDLINE_LIST_END +}; + +int megabyter_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} + +/* ---------------------------------------------------------------------*/ + +uint8_t megabyter_roml_read(uint16_t addr) +{ + return flash800core_read(megabyter_state, (megabyter_register_00 * MEGABYTER_BANK_SIZE) + (addr & 0x1fff)); +} + +void megabyter_roml_store(uint16_t addr, uint8_t value) +{ + flash800core_store(megabyter_state, (megabyter_register_00 * MEGABYTER_BANK_SIZE) + (addr & 0x1fff), value); +} + +void megabyter_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ + if (megabyter_state && megabyter_state->flash_data) { + switch (addr & 0xe000) { + case 0x8000: + if (megabyter_state->flash_state == FLASH800_STATE_READ) { + *base = megabyter_state->flash_data + (megabyter_register_00 * MEGABYTER_BANK_SIZE) - 0x8000; + *start = 0x8000; + *limit = 0x9ffd; + return; + } + break; + default: + break; + } + } + *base = NULL; + *start = 0; + *limit = 0; +} + +/* ---------------------------------------------------------------------*/ + +void megabyter_config_init(void) +{ + megabyter_io1_store((uint16_t)0xde00, 0); /* bank 0 */ + megabyter_io1_store((uint16_t)0xde02, 0); /* 8k game, LED off */ +} + +void megabyter_config_setup(uint8_t *rawcart) +{ + int i; + + megabyter_state = lib_malloc(sizeof(flash800_context_t)); + + flash800core_init(megabyter_state, maincpu_alarm_context, FLASH800_TYPE_CB, roml_banks); + + for (i = 0; i < MEGABYTER_NUM_BANKS; i++) { + memcpy(megabyter_state->flash_data + (i * MEGABYTER_BANK_SIZE), + rawcart + (i * MEGABYTER_BANK_SIZE), MEGABYTER_BANK_SIZE); + } +} + +/* ---------------------------------------------------------------------*/ + +static int megabyter_common_attach(const char *filename) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + megabyter_io1_list_item = io_source_register(&megabyter_io1_device); + megabyter_filename = lib_strdup(filename); + + return 0; +} + +int megabyter_bin_attach(const char *filename, uint8_t *rawcart) +{ + megabyter_filetype = CARTRIDGE_FILETYPE_NONE; + + if (util_file_load(filename, rawcart, MEGABYTER_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + megabyter_filetype = CARTRIDGE_FILETYPE_BIN; + return megabyter_common_attach(filename); +} + +int megabyter_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) +{ + crt_chip_header_t chip; + + megabyter_filetype = CARTRIDGE_FILETYPE_NONE; + memset(rawcart, 0xff, MEGABYTER_ROM_SIZE); /* empty flash */ + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.size == MEGABYTER_BANK_SIZE) { + if (chip.bank >= MEGABYTER_NUM_BANKS || !(chip.start == 0x8000)) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + } else { + return -1; + } + } + + megabyter_filetype = CARTRIDGE_FILETYPE_CRT; + return megabyter_common_attach(filename); +} + +void megabyter_detach(void) +{ + if (megabyter_crt_write) { + megabyter_flush_image(); + } + flash800core_shutdown(megabyter_state); + lib_free(megabyter_state); + lib_free(megabyter_filename); + megabyter_filename = NULL; + io_source_unregister(megabyter_io1_list_item); + megabyter_io1_list_item = NULL; + export_remove(&export_res); +} + +int megabyter_flush_image(void) +{ + if (megabyter_filename != NULL) { + if (megabyter_filetype == CARTRIDGE_FILETYPE_BIN) { + return megabyter_bin_save(megabyter_filename); + } else if (megabyter_filetype == CARTRIDGE_FILETYPE_CRT) { + return megabyter_crt_save(megabyter_filename); + } + return -1; + } + return -2; +} + +int megabyter_bin_save(const char *filename) +{ + FILE *fd; + int i; + uint8_t *data; + + if (filename == NULL) { + return -1; + } + + fd = fopen(filename, MODE_WRITE); + + if (fd == NULL) { + return -1; + } + + data = megabyter_state->flash_data; + + for (i = 0; i < MEGABYTER_NUM_BANKS; i++, data += MEGABYTER_BANK_SIZE) { + if (fwrite(data, 1, MEGABYTER_BANK_SIZE, fd) != MEGABYTER_BANK_SIZE) { + fclose(fd); + return -1; + } + } + + fclose(fd); + return 0; +} + +int megabyter_crt_save(const char *filename) +{ + FILE *fd; + crt_chip_header_t chip; + uint8_t *data; + int bank; + + fd = crt_create(filename, CARTRIDGE_MEGABYTER, 1, 0, CARTRIDGE_NAME_MEGABYTER); + + if (fd == NULL) { + return -1; + } + + chip.type = 2; + chip.size = MEGABYTER_BANK_SIZE; + + for (bank = 0; bank < MEGABYTER_NUM_BANKS; bank++) { + chip.bank = bank; + + data = megabyter_state->flash_data + (bank * MEGABYTER_BANK_SIZE); + chip.start = 0x8000; + if (megabyter_write_chip_if_not_empty(fd, &chip, data) != 0) { + fclose(fd); + return -1; + } + + } + fclose(fd); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTMEGABYTER snapshot module format: + + type | name | description + -------------------------------- + BYTE | register 0 | register 0 + BYTE | register 2 | register 2 + ARRAY | ROML | 1048576 BYTES of ROML data + */ + +static char snap_module_name[] = "CARTMEGABYTER"; +static char flash_snap_module_name[] = "FLASH800CB"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int megabyter_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, megabyter_register_00) < 0) + || (SMW_B(m, megabyter_register_02) < 0) + || (SMW_BA(m, roml_banks, MEGABYTER_ROM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (0 + || (flash800core_snapshot_write_module(s, megabyter_state, flash_snap_module_name) < 0)) { + return -1; + } + + return 0; +} + +int megabyter_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_B(m, &megabyter_register_00) < 0) + || (SMR_B(m, &megabyter_register_02) < 0) + || (SMR_BA(m, roml_banks, MEGABYTER_ROM_SIZE) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + megabyter_state = lib_malloc(sizeof(flash800_context_t)); + + flash800core_init(megabyter_state, maincpu_alarm_context, FLASH800_TYPE_CB, roml_banks); + + if (0 + || (flash800core_snapshot_read_module(s, megabyter_state, flash_snap_module_name) < 0)) { + flash800core_shutdown(megabyter_state); + lib_free(megabyter_state); + return -1; + } + + megabyter_common_attach("dummy"); + + /* remove dummy filename, set filetype to none */ + lib_free(megabyter_filename); + megabyter_filename = NULL; + megabyter_filetype = 0; + + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/megabyter.h b/src/Emulators/vice/c64/cart/megabyter.h new file mode 100644 index 00000000..60d5efc0 --- /dev/null +++ b/src/Emulators/vice/c64/cart/megabyter.h @@ -0,0 +1,55 @@ +/* + * megabyter.h - Cartridge handling of the megabyter cart. + * + * Written by + * Chester Kollschen + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_MEGABYTER_H +#define VICE_MEGABYTER_H + +#include "vicetypes.h" + +extern int megabyter_resources_init(void); +extern void megabyter_resources_shutdown(void); +extern int megabyter_cmdline_options_init(void); + +extern uint8_t megabyter_roml_read(uint16_t addr); +extern void megabyter_roml_store(uint16_t addr, uint8_t value); +extern void megabyter_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +extern void megabyter_config_init(void); +extern void megabyter_config_setup(uint8_t *rawcart); +extern int megabyter_bin_attach(const char *filename, uint8_t *rawcart); +extern int megabyter_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +extern void megabyter_detach(void); +extern int megabyter_bin_save(const char *filename); +extern int megabyter_crt_save(const char *filename); +extern int megabyter_flush_image(void); + +struct snapshot_s; + +extern int megabyter_snapshot_write_module(struct snapshot_s *s); +extern int megabyter_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/mikroass.c b/src/Emulators/vice/c64/cart/mikroass.c index 50430b7a..00542936 100644 --- a/src/Emulators/vice/c64/cart/mikroass.c +++ b/src/Emulators/vice/c64/cart/mikroass.c @@ -53,12 +53,12 @@ */ -static BYTE mikroass_io1_read(WORD addr) +static uint8_t mikroass_io1_read(uint16_t addr) { return roml_banks[0x1e00 + (addr & 0xff)]; } -static BYTE mikroass_io2_read(WORD addr) +static uint8_t mikroass_io2_read(uint16_t addr) { return roml_banks[0x1f00 + (addr & 0xff)]; } @@ -66,33 +66,37 @@ static BYTE mikroass_io2_read(WORD addr) /* ---------------------------------------------------------------------*/ static io_source_t mikroass_io1_device = { - CARTRIDGE_NAME_MIKRO_ASSEMBLER, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - NULL, - mikroass_io1_read, - mikroass_io1_read, - NULL, /* nothing to dump */ - CARTRIDGE_MIKRO_ASSEMBLER, - 0, - 0 + CARTRIDGE_NAME_MIKRO_ASSEMBLER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + mikroass_io1_read, /* read function */ + mikroass_io1_read, /* peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_MIKRO_ASSEMBLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mikroass_io2_device = { - CARTRIDGE_NAME_MIKRO_ASSEMBLER, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - NULL, - mikroass_io2_read, - mikroass_io2_read, - NULL, /* nothing to dump */ - CARTRIDGE_MIKRO_ASSEMBLER, - 0, - 0 + CARTRIDGE_NAME_MIKRO_ASSEMBLER, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + mikroass_io2_read, /* read function */ + mikroass_io2_read, /* peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_MIKRO_ASSEMBLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *mikroass_io1_list_item = NULL; @@ -106,13 +110,13 @@ static const export_resource_t export_res = { void mikroass_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } -void mikroass_config_setup(BYTE *rawcart) +void mikroass_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -127,7 +131,7 @@ static int mikroass_common_attach(void) return 0; } -int mikroass_bin_attach(const char *filename, BYTE *rawcart) +int mikroass_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -135,7 +139,7 @@ int mikroass_bin_attach(const char *filename, BYTE *rawcart) return mikroass_common_attach(); } -int mikroass_crt_attach(FILE *fd, BYTE *rawcart) +int mikroass_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -172,7 +176,7 @@ void mikroass_detach(void) ARRAY | ROML | 8192 BYTES of ROML data */ -static char snap_module_name[] = "CARTMIKROASS"; +static const char snap_module_name[] = "CARTMIKROASS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -196,7 +200,7 @@ int mikroass_snapshot_write_module(snapshot_t *s) int mikroass_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -206,7 +210,7 @@ int mikroass_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/mikroass.h b/src/Emulators/vice/c64/cart/mikroass.h index d31fb516..f5a5ff1c 100644 --- a/src/Emulators/vice/c64/cart/mikroass.h +++ b/src/Emulators/vice/c64/cart/mikroass.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void mikroass_config_init(void); -extern void mikroass_config_setup(BYTE *rawcart); -extern int mikroass_bin_attach(const char *filename, BYTE *rawcart); -extern int mikroass_crt_attach(FILE *fd, BYTE *rawcart); -extern void mikroass_detach(void); +void mikroass_config_init(void); +void mikroass_config_setup(uint8_t *rawcart); +int mikroass_bin_attach(const char *filename, uint8_t *rawcart); +int mikroass_crt_attach(FILE *fd, uint8_t *rawcart); +void mikroass_detach(void); struct snapshot_s; -extern int mikroass_snapshot_write_module(struct snapshot_s *s); -extern int mikroass_snapshot_read_module(struct snapshot_s *s); +int mikroass_snapshot_write_module(struct snapshot_s *s); +int mikroass_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/mmc64.c b/src/Emulators/vice/c64/cart/mmc64.c index c45a8637..62c999a2 100644 --- a/src/Emulators/vice/c64/cart/mmc64.c +++ b/src/Emulators/vice/c64/cart/mmc64.c @@ -52,7 +52,6 @@ #include "resources.h" #include "snapshot.h" #include "spi-sdcard.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -79,7 +78,7 @@ */ #ifdef MMC64DEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif @@ -110,7 +109,7 @@ static char *mmc64_image_filename = NULL; static int mmc64_bit7_unlocked = 0; /* Unlocking sequences buffer */ -static BYTE mmc64_unlocking[2] = { 0, 0 }; +static uint8_t mmc64_unlocking[2] = { 0, 0 }; /* BIOS changed flag */ static int mmc64_bios_changed = 0; @@ -122,14 +121,14 @@ static int mmc64_hw_flashjumper; /* status of the flash jumper */ static int mmc64_hw_writeprotect; /* Flags for the various control bits */ -static BYTE mmc64_active; -static BYTE mmc64_spi_mode; -static BYTE mmc64_extrom; -static BYTE mmc64_flashmode; -static BYTE mmc64_cport; -static BYTE mmc64_speed; -static BYTE mmc64_cardsel; -static BYTE mmc64_biossel; +static uint8_t mmc64_active; +static uint8_t mmc64_spi_mode; +static uint8_t mmc64_extrom; +static uint8_t mmc64_flashmode; +static uint8_t mmc64_cport; +static uint8_t mmc64_speed; +static uint8_t mmc64_cardsel; +static uint8_t mmc64_biossel; /* Status Bits */ /* $DF12 (R): MMC64 status register */ @@ -141,16 +140,16 @@ static BYTE mmc64_biossel; #define MMC_SPISTAT 0x01 /* bit 0: 0 = SPI ready, 1 = SPI busy */ /* Variables of the various status bits */ -static BYTE mmc64_extexrom = 0; -static BYTE mmc64_extgame = 0; +static uint8_t mmc64_extexrom = 0; +static uint8_t mmc64_extgame = 0; static int mmc64_revision; static int mmc64_sd_type = 0; -static BYTE mmc64_image_file_readonly = 0; +static uint8_t mmc64_image_file_readonly = 0; -static log_t mmc64_log = LOG_ERR; +static log_t mmc64_log = LOG_DEFAULT; -static BYTE mmc64_bios[0x2002]; +static uint8_t mmc64_bios[0x2002]; static int mmc64_bios_offset = 0; static int mmc64_bios_type = 0; @@ -164,79 +163,93 @@ static char *clockport_device_names = NULL; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void mmc64_clockport_enable_store(WORD addr, BYTE value); -static BYTE mmc64_clockport_enable_peek(WORD addr); -static void mmc64_io1_store(WORD addr, BYTE value); -static BYTE mmc64_io1_read(WORD addr); -static BYTE mmc64_io1_peek(WORD addr); -static void mmc64_io2_store(WORD addr, BYTE value); -static BYTE mmc64_io2_read(WORD addr); -static BYTE mmc64_io2_peek(WORD addr); +static void mmc64_clockport_enable_store(uint16_t addr, uint8_t value); +static uint8_t mmc64_clockport_enable_peek(uint16_t addr); +static void mmc64_io1_store(uint16_t addr, uint8_t value); +static uint8_t mmc64_io1_read(uint16_t addr); +static uint8_t mmc64_io1_peek(uint16_t addr); +static void mmc64_io2_store(uint16_t addr, uint8_t value); +static uint8_t mmc64_io2_read(uint16_t addr); +static uint8_t mmc64_io2_peek(uint16_t addr); static int mmc64_dump(void); -static BYTE mmc64_clockport_read(WORD io_address); -static BYTE mmc64_clockport_peek(WORD io_address); -static void mmc64_clockport_store(WORD io_address, BYTE byte); +static uint8_t mmc64_clockport_read(uint16_t io_address); +static uint8_t mmc64_clockport_peek(uint16_t io_address); +static void mmc64_clockport_store(uint16_t io_address, uint8_t byte); +static int mmc64_clockport_dump(void); static io_source_t mmc64_io1_clockport_enable_device = { - CARTRIDGE_NAME_MMC64 " Clockport enable", - IO_DETACH_RESOURCE, - "MMC64", - 0xde01, 0xde01, 0x01, - 0, - mmc64_clockport_enable_store, - NULL, /* read */ - mmc64_clockport_enable_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 0, - 0 + CARTRIDGE_NAME_MMC64 " Clockport enable", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64", /* resource to set to '0' */ + 0xde01, 0xde01, 0x01, /* range for the device, reg:$de01 */ + 0, /* read is never valid, reg is write only */ + mmc64_clockport_enable_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + mmc64_clockport_enable_peek, /* peek function */ + mmc64_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; -/* FIXME: register map doesnt show a register at $df21 - is this correct? */ +/* from http://www.schoenfeld.de/inside/mmc64doc.txt: + * + * $DE01 / $DF21(W)(*): bit 0: 0 = disable clock port, 1 = enable clockport + * + * (*) location depends on bit 3 of $DF11 + */ static io_source_t mmc64_io2_clockport_enable_device = { - CARTRIDGE_NAME_MMC64 " Clockport enable", - IO_DETACH_RESOURCE, - "MMC64", - 0xdf21, 0xdf21, 0x01, - 0, - mmc64_clockport_enable_store, - NULL, /* read */ - mmc64_clockport_enable_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 0, - 0 + CARTRIDGE_NAME_MMC64 " Clockport enable", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64", /* resource to set to '0' */ + 0xdf21, 0xdf21, 0x01, /* range for the device, reg:$df21 */ + 0, /* read is never valid, reg is write only */ + mmc64_clockport_enable_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + mmc64_clockport_enable_peek, /* peek function */ + mmc64_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mmc64_io1_clockport_device = { - CARTRIDGE_NAME_MMC64 " Clockport", - IO_DETACH_RESOURCE, - "MMC64ClockPort", - 0xde02, 0xde0f, 0x0f, - 0, - mmc64_clockport_store, - mmc64_clockport_read, - mmc64_clockport_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 0, - 0 + CARTRIDGE_NAME_MMC64 " Clockport", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64ClockPort", /* resource to set to '0' */ + 0xde02, 0xde0f, 0x0f, /* range for the device, regs:$de02-$de0f */ + 0, /* read validity is determined by the device upon a read */ + mmc64_clockport_store, /* store function */ + NULL, /* NO poke function */ + mmc64_clockport_read, /* read function */ + mmc64_clockport_peek, /* peek function */ + mmc64_clockport_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mmc64_io2_clockport_device = { - CARTRIDGE_NAME_MMC64 " Clockport", - IO_DETACH_RESOURCE, - "MMC64ClockPort", - 0xdf22, 0xdf2f, 0x0f, - 0, - mmc64_clockport_store, - mmc64_clockport_read, - mmc64_clockport_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 0, - 0 + CARTRIDGE_NAME_MMC64 " Clockport", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64ClockPort", /* resource to set to '0' */ + 0xdf22, 0xdf2f, 0x0f, /* range for the device, regs:$df22-$df2f */ + 0, /* read validity is determined by the device upon a read */ + mmc64_clockport_store, /* store function */ + NULL, /* NO poke function */ + mmc64_clockport_read, /* read function */ + mmc64_clockport_peek, /* peek function */ + mmc64_clockport_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t *mmc64_current_clockport_enable_device = &mmc64_io1_clockport_enable_device; @@ -252,33 +265,37 @@ static const export_resource_t export_cp_res = { #endif static io_source_t mmc64_io2_device = { - CARTRIDGE_NAME_MMC64, - IO_DETACH_RESOURCE, - "MMC64", - 0xdf10, 0xdf13, 0x03, - 0, - mmc64_io2_store, - mmc64_io2_read, - mmc64_io2_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 1, /* mask df10-df13 from passthrough */ - 0 + CARTRIDGE_NAME_MMC64, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64", /* resource to set to '0' */ + 0xdf10, 0xdf13, 0x03, /* range for the device, regs:$df10-$df13 */ + 0, /* read validity is determined by the device upon a read */ + mmc64_io2_store, /* store function */ + NULL, /* NO poke function */ + mmc64_io2_read, /* read function */ + mmc64_io2_peek, /* peek function */ + mmc64_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mmc64_io1_device = { - CARTRIDGE_NAME_MMC64, - IO_DETACH_RESOURCE, - "MMC64", - 0xde10, 0xde13, 0x03, - 0, - mmc64_io1_store, - mmc64_io1_read, - mmc64_io1_peek, - mmc64_dump, - CARTRIDGE_MMC64, - 0, - 0 + CARTRIDGE_NAME_MMC64, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMC64", /* resource to set to '0' */ + 0xde10, 0xde13, 0x03, /* range for the device, regs:$de10-$de13 */ + 0, /* read validity is determined by the device upon a read */ + mmc64_io1_store, /* store function */ + NULL, /* NO poke function */ + mmc64_io1_read, /* read function */ + mmc64_io1_peek, /* peek function */ + mmc64_dump, /* device state information dump function */ + CARTRIDGE_MMC64, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, every other cartridge is assumed to be attached to the passthrough port */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *mmc64_clockport_list_item = NULL; @@ -334,7 +351,7 @@ void mmc64_reset(void) cart_set_port_exrom_slot0(1); cart_port_config_changed_slot0(); #else - cart_config_changed_slot0(0, 0, CMODE_READ); + cart_config_changed_slot0(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); #endif } } @@ -384,7 +401,7 @@ static int set_mmc64_clockport_device(int val, void *param) } if (val != CLOCKPORT_DEVICE_NONE) { - clockport_device = clockport_open_device(val, (char *)STRING_MMC64); + clockport_device = clockport_open_device(val, STRING_MMC64); if (!clockport_device) { return -1; } @@ -403,7 +420,7 @@ static int clockport_activate(void) return 0; } - clockport_device = clockport_open_device(clockport_device_id, (char *)STRING_MMC64); + clockport_device = clockport_open_device(clockport_device_id, STRING_MMC64); if (!clockport_device) { return -1; } @@ -439,7 +456,9 @@ static int set_mmc64_enabled(int value, void *param) LOG(("MMC64: set_enabled(1) '%s'", mmc64_bios_filename)); if (mmc64_bios_filename) { if (*mmc64_bios_filename) { - if (cartridge_attach_image(CARTRIDGE_MMC64, mmc64_bios_filename) < 0) { + /* try .crt first */ + if ((cartridge_attach_image(CARTRIDGE_CRT, mmc64_bios_filename) < 0) && + (cartridge_attach_image(CARTRIDGE_MMC64, mmc64_bios_filename) < 0)) { LOG(("MMC64: set_enabled(1) did not register")); return -1; } @@ -553,7 +572,7 @@ static int set_mmc64_sd_type(int val, void *param) } mmc64_sd_type = val; - mmc_set_card_type((BYTE)val); + mmc_set_card_type((uint8_t)val); return 0; } @@ -613,7 +632,7 @@ static int set_mmc64_image_filename(const char *name, void *param) /* ---------------------------------------------------------------------*/ -int mmc64_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +int mmc64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { if (!mmc64_active && !mmc64_biossel) { switch (addr & 0xf000) { @@ -630,7 +649,7 @@ int mmc64_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) return CART_READ_THROUGH; } -void mmc64_config_init(export_t *export) +void mmc64_config_init(export_t *ex) { LOG(("MMC64 mmc64_config_init")); @@ -648,13 +667,13 @@ void mmc64_config_init(export_t *export) mmc64_extexrom = 0; mmc64_extgame = 0; #endif - mmc64_extexrom = export->exrom; - mmc64_extgame = export->game; + mmc64_extexrom = ex->exrom; + mmc64_extgame = ex->game; if (mmc64_enabled) { #if USEPASSTHROUGHHACK mmc64_io2_device.io_source_prio = 1; - cart_config_changed_slot0((BYTE)((0 << 1) | mmc64_extgame), (BYTE)((0 << 1) | mmc64_extgame), CMODE_READ); + cart_config_changed_slot0((uint8_t)((0 << 1) | mmc64_extgame), (uint8_t)((0 << 1) | mmc64_extgame), CMODE_READ); #else cart_config_changed_slot0(0, 0, CMODE_READ); #endif @@ -663,33 +682,33 @@ void mmc64_config_init(export_t *export) } } -void mmc64_passthrough_changed(export_t *export) +void mmc64_passthrough_changed(export_t *ex) { - mmc64_extexrom = export->exrom; - mmc64_extgame = export->game; + mmc64_extexrom = ex->exrom; + mmc64_extgame = ex->game; LOG(("MMC64 passthrough changed exrom: %d game: %d (mmc64_active: %d)", mmc64_extexrom, mmc64_extgame, mmc64_active)); if (!mmc64_active) { cart_set_port_game_slot0(mmc64_extgame); cart_port_config_changed_slot0(); } else { /* MMC64 is completely disabled */ - cart_config_changed_slot0((BYTE)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), (BYTE)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), CMODE_READ); + cart_config_changed_slot0((uint8_t)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), (uint8_t)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), CMODE_READ); } } -static void mmc64_clockport_enable_store(WORD addr, BYTE value) +static void mmc64_clockport_enable_store(uint16_t addr, uint8_t value) { if ((value & 1) != mmc64_clockport_enabled) { mmc64_clockport_enabled = value & 1; } } -static BYTE mmc64_clockport_enable_peek(WORD addr) +static uint8_t mmc64_clockport_enable_peek(uint16_t addr) { return mmc64_clockport_enabled; } -static void mmc64_reg_store(WORD addr, BYTE value, int active) +static void mmc64_reg_store(uint16_t addr, uint8_t value, int active) { switch (addr) { case 0: @@ -738,14 +757,14 @@ static void mmc64_reg_store(WORD addr, BYTE value, int active) LOG(("MMC64: mmc64_active %d", (((value >> 7)) & 1))); #endif - spi_mmc_card_selected_write((BYTE)(((value >> 1) ^ 1) & 1)); /* bit 1 */ - spi_mmc_enable_8mhz_write((BYTE)(((value >> 2)) & 1)); /* bit 2 */ + spi_mmc_card_selected_write((uint8_t)(((value >> 1) ^ 1) & 1)); /* bit 1 */ + spi_mmc_enable_8mhz_write((uint8_t)(((value >> 2)) & 1)); /* bit 2 */ mmc64_cport = (((value >> 3)) & 1); /* bit 3 */ if (mmc64_hw_flashjumper) { /* this bit can only be changed if the flashjumper is on */ mmc64_flashmode = (((value >> 4)) & 1); /* bit 4 */ } - spi_mmc_trigger_mode_write((BYTE)(((value >> 6)) & 1)); /* bit 6 */ + spi_mmc_trigger_mode_write((uint8_t)(((value >> 6)) & 1)); /* bit 6 */ mmc64_active = (((value >> 7)) & 1); /* bit 7 */ @@ -753,8 +772,8 @@ static void mmc64_reg_store(WORD addr, BYTE value, int active) if (mmc64_active) { /* cart_set_port_exrom_slot0(0); */ log_message(mmc64_log, "disabling MMC64 (exrom:%d game:%d) mmc64_active: %d", mmc64_extexrom, mmc64_extgame, mmc64_active); - cart_config_changed_slot0((BYTE)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), - (BYTE)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), CMODE_READ); + cart_config_changed_slot0((uint8_t)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), + (uint8_t)(((mmc64_extexrom ^ 1) << 1) | mmc64_extgame), CMODE_READ); mmc64_io2_device.io_source_prio = 0; } else { /* this controls the mapping of the MMC64 bios */ @@ -847,21 +866,21 @@ static void mmc64_reg_store(WORD addr, BYTE value, int active) } } -static void mmc64_io1_store(WORD addr, BYTE value) +static void mmc64_io1_store(uint16_t addr, uint8_t value) { if (mmc64_hw_flashjumper) { mmc64_reg_store(addr, value, 1); } } -static void mmc64_io2_store(WORD addr, BYTE value) +static void mmc64_io2_store(uint16_t addr, uint8_t value) { mmc64_reg_store(addr, value, mmc64_active ^ 1); } -static BYTE mmc64_io2_read(WORD addr) +static uint8_t mmc64_io2_read(uint16_t addr) { - BYTE value; + uint8_t value; if (mmc64_active) { /* MMC64 is completely disabled */ @@ -965,14 +984,14 @@ static BYTE mmc64_io2_read(WORD addr) return 0; } -static BYTE mmc64_io1_read(WORD addr) +static uint8_t mmc64_io1_read(uint16_t addr) { return mmc64_io2_read(addr); } -static BYTE mmc64_io2_peek(WORD addr) +static uint8_t mmc64_io2_peek(uint16_t addr) { - BYTE value = 0; + uint8_t value = 0; switch (addr) { case 0: @@ -1020,53 +1039,66 @@ static BYTE mmc64_io2_peek(WORD addr) return 0; } -static BYTE mmc64_io1_peek(WORD addr) +static uint8_t mmc64_io1_peek(uint16_t addr) { return mmc64_io2_peek(addr); } /* ---------------------------------------------------------------------*/ -static BYTE mmc64_clockport_read(WORD address) +static uint8_t mmc64_clockport_read(uint16_t address) { + if (address < 0x02) { + mmc64_current_clockport_device->io_source_valid = 0; + return 0; + } + /* read from clockport device */ if (clockport_device) { - if (address < 0x02) { - mmc64_current_clockport_device->io_source_valid = 0; - return 0; - } return clockport_device->read(address, &mmc64_current_clockport_device->io_source_valid, clockport_device->device_context); } + /* read open clock port */ + mmc64_current_clockport_device->io_source_valid = 1; return 0; } -static BYTE mmc64_clockport_peek(WORD address) +static uint8_t mmc64_clockport_peek(uint16_t address) { + if (address < 0x02) { + return 0; + } + /* read from clockport device */ if (clockport_device) { - if (address < 0x02) { - return 0; - } return clockport_device->peek(address, clockport_device->device_context); } return 0; } -static void mmc64_clockport_store(WORD address, BYTE byte) +static void mmc64_clockport_store(uint16_t address, uint8_t byte) { - if (clockport_device) { - if (address < 0x02) { - return; - } + if (address < 0x02) { + return; + } + /* write to clockport device */ + if (clockport_device) { clockport_device->store(address, byte, clockport_device->device_context); } } +static int mmc64_clockport_dump(void) +{ + if (clockport_device) { + clockport_device->dump(clockport_device->device_context); + } + return 0; +} + /* ---------------------------------------------------------------------*/ static int mmc64_dump(void) { mon_out("Clockport is %s.\n", mmc64_clockport_enabled ? "enabled" : "disabled"); - mon_out("Clockport mapped to $%04x.\n", mmc64_hw_clockport); + mon_out("Clockport mapped to $%04x.\n", (unsigned int)mmc64_hw_clockport); mon_out("Clockport device %s\n", clockport_device_id_to_name(clockport_device_id)); return 0; @@ -1074,7 +1106,7 @@ static int mmc64_dump(void) /* ---------------------------------------------------------------------*/ -int mmc64_roml_read(WORD addr, BYTE *value) +int mmc64_roml_read(uint16_t addr, uint8_t *value) { #if USEPASSTHROUGHHACK if (!mmc64_active && !mmc64_biossel) { @@ -1090,7 +1122,7 @@ int mmc64_roml_read(WORD addr, BYTE *value) #endif } -int mmc64_peek_mem(WORD addr, BYTE *value) +int mmc64_peek_mem(uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { if (!mmc64_active && !mmc64_biossel) { @@ -1101,7 +1133,7 @@ int mmc64_peek_mem(WORD addr, BYTE *value) return CART_READ_THROUGH; } -void mmc64_roml_store(WORD addr, BYTE byte) +void mmc64_roml_store(uint16_t addr, uint8_t byte) { /* if (addr == 0x8000) LOG(("roml w %04x %02x active: %d == 0 bios: %d == 0 flashjumper: %d == 1 flashmode: %d == 1\n", addr, byte, mmc64_active, mmc64_biossel, mmc64_hw_flashjumper, mmc64_flashmode)); */ if (!mmc64_active && !mmc64_biossel && mmc64_hw_flashjumper && mmc64_flashmode) { @@ -1166,76 +1198,50 @@ void mmc64_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-mmc64", SET_RESOURCE, 0, + { "-mmc64", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_MMC64, - NULL, NULL }, - { "+mmc64", SET_RESOURCE, 0, + NULL, "Enable the MMC64 expansion" }, + { "+mmc64", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_MMC64, - NULL, NULL }, - { "-mmc64bios", SET_RESOURCE, 1, + NULL, "Disable the MMC64 expansion" }, + { "-mmc64bios", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMC64BIOSfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_MMC64_BIOS_NAME, - NULL, NULL }, - { "-mmc64image", SET_RESOURCE, 1, + "", "Specify name of MMC64 BIOS image" }, + { "-mmc64image", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMC64imagefilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_MMC64_IMAGE_NAME, - NULL, NULL }, - { "-mmc64readonly", SET_RESOURCE, 0, + "", "Specify name of MMC64 image" }, + { "-mmc64readonly", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_RO", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_READONLY, - NULL, NULL }, - { "-mmc64readwrite", SET_RESOURCE, 0, + NULL, "Set the MMC64 card to read-only" }, + { "-mmc64readwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_RO", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_READWRITE, - NULL, NULL }, - { "-mmc64bioswrite", SET_RESOURCE, 0, + NULL, "Set the MMC64 card to read/write" }, + { "-mmc64bioswrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_bios_write", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_BIOS_WRITE, - NULL, NULL }, - { "-mmc64biosreadonly", SET_RESOURCE, 0, + NULL, "Save the MMC64 bios when changed" }, + { "-mmc64biosreadonly", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_bios_write", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_BIOS_READ_ONLY, - NULL, NULL }, - { "-mmc64flash", SET_RESOURCE, 0, + NULL, "Do not save the MMC64 bios when changed" }, + { "-mmc64flash", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_flashjumper", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_SET_FLASH_JUMPER, - NULL, NULL }, - { "+mmc64flash", SET_RESOURCE, 0, + NULL, "Set the MMC64 Flash Jumper" }, + { "+mmc64flash", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMC64_flashjumper", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC64_UNSET_FLASH_JUMPER, - NULL, NULL }, - { "-mmc64rev", SET_RESOURCE, 1, + NULL, "Remove the MMC64 Flash Jumper" }, + { "-mmc64rev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMC64_revision", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_REVISION, IDCLS_SPECIFY_MMC64_REVISION, - NULL, NULL }, - { "-mmc64sdtype", SET_RESOURCE, 1, + "", "Specify MMC64 revision (0: Rev A, 1: Rev B)" }, + { "-mmc64sdtype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMC64_sd_type", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_TYPE, IDCLS_SPECIFY_MMC64_SD_TYPE, - NULL, NULL }, + "", "Specify MMC64 SD type (0: auto, 1: MMC, 2: SD, 3: SDHC)" }, CMDLINE_LIST_END }; static cmdline_option_t clockport_cmdline_options[] = { - { "-mmc64clockportdevice", SET_RESOURCE, 1, + { "-mmc64clockportdevice", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMC64ClockPort", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_DEVICE, IDCLS_CLOCKPORT_DEVICE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -1251,7 +1257,7 @@ int mmc64_cmdline_options_init(void) sprintf(number, "%d", clockport_supported_devices[0].id); - clockport_device_names = util_concat(". (", number, ": ", clockport_supported_devices[0].name, NULL); + clockport_device_names = util_concat("Clockport device. (", number, ": ", clockport_supported_devices[0].name, NULL); for (i = 1; clockport_supported_devices[i].name; ++i) { tmp = clockport_device_names; @@ -1279,7 +1285,7 @@ void mmc64_init(void) mmc64_log = log_open("MMC64"); } -void mmc64_config_setup(BYTE *rawcart) +void mmc64_config_setup(uint8_t *rawcart) { memcpy(mmc64_bios, rawcart, 0x2000 + mmc64_bios_offset); } @@ -1292,7 +1298,7 @@ static int mmc64_common_attach(void) int mmc64_bin_save(const char *filename) { FILE *fd; - int ret; + size_t ret; if (filename == NULL) { return -1; @@ -1305,7 +1311,7 @@ int mmc64_bin_save(const char *filename) ret = fwrite(mmc64_bios, 1, 0x2000 + mmc64_bios_offset, fd); fclose(fd); - if (ret != 0x2000 + mmc64_bios_offset) { + if (ret != (0x2000 + mmc64_bios_offset)) { return -1; } mmc64_bios_changed = 0; @@ -1337,7 +1343,7 @@ int mmc64_crt_save(const char *filename) return 0; } -int mmc64_bin_attach(const char *filename, BYTE *rawcart) +int mmc64_bin_attach(const char *filename, uint8_t *rawcart) { int amount_read = 0; FILE *fd; @@ -1356,10 +1362,11 @@ int mmc64_bin_attach(const char *filename, BYTE *rawcart) mmc64_bios_offset = amount_read & 3; mmc64_bios_type = CARTRIDGE_FILETYPE_BIN; + set_mmc64_bios_filename(filename, NULL); /* set the resource */ return mmc64_common_attach(); } -int mmc64_crt_attach(FILE *fd, BYTE *rawcart) +int mmc64_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; @@ -1377,6 +1384,7 @@ int mmc64_crt_attach(FILE *fd, BYTE *rawcart) mmc64_bios_offset = 0; mmc64_bios_type = CARTRIDGE_FILETYPE_CRT; + set_mmc64_bios_filename(filename, NULL); /* set the resource */ return mmc64_common_attach(); } @@ -1400,6 +1408,11 @@ int mmc64_enable(void) return set_mmc64_enabled(1, (void*)1); } +int mmc64_disable(void) +{ + return set_mmc64_enabled(0, (void*)1); +} + /* ---------------------------------------------------------------------*/ /* snapshot support functions */ @@ -1433,7 +1446,7 @@ int mmc64_enable(void) BYTE | BIOS type | BIOS type */ -static char snap_module_name[] = "CARTMMC64"; +static const char snap_module_name[] = "CARTMMC64"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -1448,15 +1461,15 @@ int mmc64_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)mmc64_clockport_enabled) < 0 - || SMW_W(m, (WORD)mmc64_hw_clockport) < 0 - || SMW_B(m, (BYTE)mmc64_bios_write) < 0 - || SMW_B(m, (BYTE)mmc64_bit7_unlocked) < 0 + || SMW_B(m, (uint8_t)mmc64_clockport_enabled) < 0 + || SMW_W(m, (uint16_t)mmc64_hw_clockport) < 0 + || SMW_B(m, (uint8_t)mmc64_bios_write) < 0 + || SMW_B(m, (uint8_t)mmc64_bit7_unlocked) < 0 || SMW_B(m, mmc64_unlocking[0]) < 0 || SMW_B(m, mmc64_unlocking[1]) < 0 - || SMW_B(m, (BYTE)mmc64_bios_changed) < 0 - || SMW_B(m, (BYTE)mmc64_hw_flashjumper) < 0 - || SMW_B(m, (BYTE)mmc64_hw_writeprotect) < 0 + || SMW_B(m, (uint8_t)mmc64_bios_changed) < 0 + || SMW_B(m, (uint8_t)mmc64_hw_flashjumper) < 0 + || SMW_B(m, (uint8_t)mmc64_hw_writeprotect) < 0 || SMW_B(m, mmc64_active) < 0 || SMW_B(m, mmc64_spi_mode) < 0 || SMW_B(m, mmc64_extrom) < 0 @@ -1467,12 +1480,12 @@ int mmc64_snapshot_write_module(snapshot_t *s) || SMW_B(m, mmc64_biossel) < 0 || SMW_B(m, mmc64_extexrom) < 0 || SMW_B(m, mmc64_extgame) < 0 - || SMW_B(m, (BYTE)mmc64_revision) < 0 - || SMW_B(m, (BYTE)mmc64_sd_type) < 0 + || SMW_B(m, (uint8_t)mmc64_revision) < 0 + || SMW_B(m, (uint8_t)mmc64_sd_type) < 0 || SMW_B(m, mmc64_image_file_readonly) < 0 || SMW_BA(m, mmc64_bios, 0x2002) < 0 - || SMW_B(m, (BYTE)mmc64_bios_offset) < 0 - || SMW_B(m, (BYTE)mmc64_bios_type) < 0) { + || SMW_B(m, (uint8_t)mmc64_bios_offset) < 0 + || SMW_B(m, (uint8_t)mmc64_bios_type) < 0) { snapshot_module_close(m); return -1; } @@ -1482,7 +1495,7 @@ int mmc64_snapshot_write_module(snapshot_t *s) int mmc64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -1492,7 +1505,7 @@ int mmc64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/mmc64.h b/src/Emulators/vice/c64/cart/mmc64.h index 2803151e..ff5f8b65 100644 --- a/src/Emulators/vice/c64/cart/mmc64.h +++ b/src/Emulators/vice/c64/cart/mmc64.h @@ -34,49 +34,55 @@ #ifndef VICE_MMC64_H #define VICE_MMC64_H +#include + #include "vicetypes.h" #include "c64cart.h" #define MMC64_REV_A 0 #define MMC64_REV_B 1 -#define MMC64_TYPE_AUTO 0 -#define MMC64_TYPE_MMC 1 -#define MMC64_TYPE_SD 2 -#define MMC64_TYPE_SDHC 3 +enum { + MMC64_TYPE_AUTO = 0, + MMC64_TYPE_MMC, + MMC64_TYPE_SD, + MMC64_TYPE_SDHC +}; /* FIXME: remove global clockport related variables */ extern int mmc64_clockport_enabled; extern int mmc64_hw_clockport; -extern int mmc64_cart_enabled(void); -extern int mmc64_cart_active(void); -extern void mmc64_config_init(export_t *export); -extern int mmc64_roml_read(WORD addr, BYTE *byte); -extern void mmc64_roml_store(WORD addr, BYTE byte); -extern int mmc64_peek_mem(WORD addr, BYTE *value); -extern void mmc64_passthrough_changed(export_t *export); +int mmc64_cart_enabled(void); +int mmc64_cart_active(void); +void mmc64_config_init(export_t *export); +int mmc64_roml_read(uint16_t addr, uint8_t *byte); +void mmc64_roml_store(uint16_t addr, uint8_t byte); +int mmc64_peek_mem(uint16_t addr, uint8_t *value); +void mmc64_passthrough_changed(export_t *export); -extern void mmc64_config_setup(BYTE *rawcart); +void mmc64_config_setup(uint8_t *rawcart); -extern int mmc64_crt_attach(FILE *fd, BYTE *rawcart); -extern int mmc64_bin_attach(const char *filename, BYTE *rawcart); -extern int mmc64_bin_save(const char *filename); -extern int mmc64_crt_save(const char *filename); -extern int mmc64_flush_image(void); +int mmc64_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int mmc64_bin_attach(const char *filename, uint8_t *rawcart); +int mmc64_bin_save(const char *filename); +int mmc64_crt_save(const char *filename); +int mmc64_flush_image(void); -extern int mmc64_resources_init(void); -extern void mmc64_resources_shutdown(void); -extern int mmc64_cmdline_options_init(void); -extern void mmc64_init(void); -extern void mmc64_detach(void); -extern void mmc64_reset(void); -extern int mmc64_enable(void); -extern const char *mmc64_get_file_name(void); -extern int mmc64_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +int mmc64_resources_init(void); +void mmc64_resources_shutdown(void); +int mmc64_cmdline_options_init(void); +void mmc64_init(void); +void mmc64_detach(void); +void mmc64_reset(void); +int mmc64_enable(void); +int mmc64_disable(void); +const char *mmc64_get_file_name(void); +int mmc64_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); struct snapshot_s; -extern int mmc64_snapshot_read_module(struct snapshot_s *s); -extern int mmc64_snapshot_write_module(struct snapshot_s *s); + +int mmc64_snapshot_read_module(struct snapshot_s *s); +int mmc64_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/mmcreplay.c b/src/Emulators/vice/c64/cart/mmcreplay.c index 0388497d..be1e60f4 100644 --- a/src/Emulators/vice/c64/cart/mmcreplay.c +++ b/src/Emulators/vice/c64/cart/mmcreplay.c @@ -47,11 +47,11 @@ #include "machine.h" #include "maincpu.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "ser-eeprom.h" #include "snapshot.h" #include "spi-sdcard.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "vicii-phi1.h" @@ -66,52 +66,58 @@ #define MMCREPLAY_RAM_SIZE (1024 * 512) /* #define MMCRDEBUG */ -/* #define DEBUG_LOGBANKS */ /* log access to banked rom/ram */ -/* #define DEBUG_IOBANKS */ /* log access to banked rom/ram in io */ -/* #define LOG_MAPPER */ /* log memory map changes */ -/* #define LOG_CLOCKPORT */ /* log clockport i/o */ - -/* #define LOG_READ_DE00 */ -/* #define LOG_WRITE_DE00 */ -/* #define LOG_WRITE_DE01 */ - -/* #define LOG_READ_IO1_RAM */ -/* #define LOG_READ_IO1_ROM */ -/* #define LOG_READ_IO1_DISABLED */ -/* #define LOG_WRITE_IO1_RAM */ -/* #define LOG_WRITE_IO1_ROM */ -/* #define LOG_WRITE_IO1_DISABLED */ - -/* #define LOG_READ_DF10 */ -/* #define LOG_READ_DF11 */ -/* #define LOG_READ_DF12 */ -/* #define LOG_READ_DF13 */ - -/* #define LOG_WRITE_DF10 */ -/* #define LOG_WRITE_DF11 */ -/* #define LOG_WRITE_DF12 */ -/* #define LOG_WRITE_DF13 */ - -/* #define LOG_READ_IO2_RAM */ -/* #define LOG_READ_IO2_ROM */ -/* #define LOG_READ_IO2_DISABLED */ -/* #define LOG_WRITE_IO2_RAM */ -/* #define LOG_WRITE_IO2_ROM */ -/* #define LOG_WRITE_IO2_DISABLED */ +#ifdef MMCRDEBUG +#define DEBUG_LOGBANKS /* log access to banked rom/ram */ +#define DEBUG_IOBANKS /* log access to banked rom/ram in io */ +#define LOG_MAPPER /* log memory map changes */ +#define LOG_CLOCKPORT /* log clockport i/o */ + +#define LOG_READ_DE00 +#define LOG_WRITE_DE00 +#define LOG_WRITE_DE01 + +#define LOG_READ_IO1_RAM +#define LOG_READ_IO1_ROM +#define LOG_READ_IO1_DISABLED +#define LOG_WRITE_IO1_RAM +#define LOG_WRITE_IO1_ROM +#define LOG_WRITE_IO1_DISABLED + +#define LOG_READ_DF10 +#define LOG_READ_DF11 +#define LOG_READ_DF12 +#define LOG_READ_DF13 + +#define LOG_WRITE_DF10 +#define LOG_WRITE_DF11 +#define LOG_WRITE_DF12 +#define LOG_WRITE_DF13 + +#define LOG_READ_IO2_RAM +#define LOG_READ_IO2_ROM +#define LOG_READ_IO2_DISABLED +#define LOG_WRITE_IO2_RAM +/*#define LOG_WRITE_IO2_ROM*/ +#define LOG_WRITE_IO2_DISABLED + +/* define any of the following to force starting up in a specific configuration */ /* #define TEST_AR_MAPPER */ /* #define TEST_RR_MAPPER */ /* #define TEST_NORDIC_MAPPER */ /* #define TEST_SUPER_8KCRT */ /* #define TEST_SUPER_16KCRT */ /* #define TEST_RESCUE_MODE */ +#endif #ifdef MMCRDEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif +static int machine_mode = 1; /* 1: c64, 0: c128 */ + static int mmcr_enabled = 0; static int enable_rescue_mode = 0; static char *mmcr_card_filename = NULL; @@ -142,11 +148,11 @@ Reset button /* the 29F040 statemachine */ static flash040_context_t *flashrom_state = NULL; -static BYTE active_mode_phi1 = 0; -static BYTE active_mode_phi2 = 0; +static uint8_t active_mode_phi1 = 0; +static uint8_t active_mode_phi2 = 0; /* RAM */ -static BYTE *mmcr_ram = NULL; +static uint8_t *mmcr_ram = NULL; /* RAM banking.*/ static unsigned int raml_bank = 0, ramh_bank = 0; @@ -279,59 +285,65 @@ static char *clockport_device_names = NULL; /********************************************************************************************************************/ /* some prototypes are needed */ -static BYTE mmcreplay_io1_read(WORD addr); -static void mmcreplay_io1_store(WORD addr, BYTE value); -static BYTE mmcreplay_io2_read(WORD addr); -static void mmcreplay_io2_store(WORD addr, BYTE value); +static uint8_t mmcreplay_io1_read(uint16_t addr); +static void mmcreplay_io1_store(uint16_t addr, uint8_t value); +static uint8_t mmcreplay_io2_read(uint16_t addr); +static void mmcreplay_io2_store(uint16_t addr, uint8_t value); static int mmcreplay_dump(void); -static BYTE mmcreplay_clockport_read(WORD io_address); -static BYTE mmcreplay_clockport_peek(WORD io_address); -static void mmcreplay_clockport_store(WORD io_address, BYTE byte); +static uint8_t mmcreplay_clockport_read(uint16_t io_address); +static uint8_t mmcreplay_clockport_peek(uint16_t io_address); +static void mmcreplay_clockport_store(uint16_t io_address, uint8_t byte); static io_source_t mmcreplay_io1_device = { - CARTRIDGE_NAME_MMC_REPLAY, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - mmcreplay_io1_store, - mmcreplay_io1_read, - NULL, /* TODO: peek */ - mmcreplay_dump, - CARTRIDGE_MMC_REPLAY, - 0, - 0 + CARTRIDGE_NAME_MMC_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$de01, possible ram:$de02-$deff */ + 0, /* read validity is determined by the device upon a read */ + mmcreplay_io1_store, /* store function */ + NULL, /* NO poke function */ + mmcreplay_io1_read, /* read function */ + NULL, /* TODO: peek function */ + mmcreplay_dump, /* device state information dump function */ + CARTRIDGE_MMC_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mmcreplay_io2_device = { - CARTRIDGE_NAME_MMC_REPLAY, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - mmcreplay_io2_store, - mmcreplay_io2_read, - NULL, /* TODO: peek */ - mmcreplay_dump, - CARTRIDGE_MMC_REPLAY, - 0, - 0 + CARTRIDGE_NAME_MMC_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df10-$df13, mirrors:$df00-$df0f & $df14-$dfff */ + 0, /* read validity is determined by the device upon a read */ + mmcreplay_io2_store, /* store function */ + NULL, /* NO poke function */ + mmcreplay_io2_read, /* read function */ + NULL, /* TODO: peek function */ + mmcreplay_dump, /* device state information dump function */ + CARTRIDGE_MMC_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t mmcreplay_clockport_device = { - CARTRIDGE_NAME_MMC_REPLAY " Clockport", - IO_DETACH_RESOURCE, - "MMCRClockPort", - 0xde02, 0xde0f, 0x0f, - 0, - mmcreplay_clockport_store, - mmcreplay_clockport_read, - mmcreplay_clockport_peek, - mmcreplay_dump, - CARTRIDGE_MMC_REPLAY, - 0, - 0 + CARTRIDGE_NAME_MMC_REPLAY " Clockport", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "MMCRClockPort", /* resource to set to '0' */ + 0xde02, 0xde0f, 0x0f, /* range for the device, regs:$de02-$de0f */ + 0, /* read validity is determined by the device upon a read */ + mmcreplay_clockport_store, /* store function */ + NULL, /* NO poke function */ + mmcreplay_clockport_read, /* read function */ + mmcreplay_clockport_peek, /* peek function */ + mmcreplay_dump, /* device state information dump function */ + CARTRIDGE_MMC_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *mmcreplay_io1_list_item = NULL; @@ -344,18 +356,22 @@ static const export_resource_t export_res = { /********************************************************************************************************************/ +static void mmcreplay_set_stdcfg(void); + #ifdef LOG_MAPPER +void mmcreplay_dump_cfg(void); + void mmcreplay_dump_cfg(void) { static char dumpstr1[0x100]; static char dumpstr2[0x100]; static char ndumpstr[0x100]; - char *str_mapper[4] = { "MMCBIOS", "RR", "SUPER", "NORMAL" }; - char *str_config[4] = { "off", "ultimax", "8K Game", "16K Game" }; + static const char * const str_mapper[4] = { "MMCBIOS", "RR", "SUPER", "NORMAL" }; + static const char * const str_config[4] = { "off", "ultimax", "8K Game", "16K Game" }; int mapper, config; sprintf(ndumpstr, - "MMCREPLAY: cart active: %d disable rr rom/opt.mapping:%d rr regs active:%d extended mode:%d 16k mapping:%d RAM IO1 Mapping:%d RAM Banking:%d", + "MMCREPLAY: cart active: %u disable rr rom/opt.mapping:%u rr regs active:%u extended mode:%u 16k mapping:%u RAM IO1 Mapping:%u RAM Banking:%u", rr_active, disable_rr_rom, enable_rr_regs, enable_extended_mode, enable_16k_mapping, enable_ram_io1, allow_bank); if (strcmp(dumpstr1, ndumpstr) != 0) { @@ -402,16 +418,16 @@ void mmcreplay_dump_cfg(void) sprintf(romlbank, "(%d:%d)", roml_bank >> 3, roml_bank & 7); sprintf(romhbank, "(%d:%d)", romh_bank >> 3, romh_bank & 7); - sprintf(ramlbank, "(%d:%d)", raml_bank >> 3, raml_bank & 7); - sprintf(ramhbank, "(%d:%d)", ramh_bank >> 3, ramh_bank & 7); + sprintf(ramlbank, "(%u:%u)", raml_bank >> 3, raml_bank & 7); + sprintf(ramhbank, "(%u:%u)", ramh_bank >> 3, ramh_bank & 7); /* a000- bfff */ sprintf(ramA000bank, "(%d:%d)", ramA000_bank >> 3, ramA000_bank & 7); sprintf(romA000bank, "(%d:%d)", romA000_bank >> 3, romA000_bank & 7); /* FIXME: always = raml bank? */ - sprintf(io1bank, "(%d:%d)", io1_bank >> 3, io1_bank & 7); - sprintf(io2bank, "(%d:%d)", io2_bank >> 3, io2_bank & 7); - sprintf(io1rambank, "(%d:%d)", io1_ram_bank >> 3, io1_ram_bank & 7); - sprintf(io2rambank, "(%d:%d)", io2_ram_bank >> 3, io2_ram_bank & 7); + sprintf(io1bank, "(%u:%u)", io1_bank >> 3, io1_bank & 7); + sprintf(io2bank, "(%u:%u)", io2_bank >> 3, io2_bank & 7); + sprintf(io1rambank, "(%u:%u)", io1_ram_bank >> 3, io1_ram_bank & 7); + sprintf(io2rambank, "(%u:%u)", io2_ram_bank >> 3, io2_ram_bank & 7); str[0] = 0; switch (config) { @@ -561,23 +577,23 @@ Lets assume we have RAM enabled (bit 5 of $de00 = 1): Allowbank masks only banking bits A13-A15 in Super Mapper mode. */ -void mmcreplay_ramhbank_set(unsigned int bank) +static void mmcreplay_ramhbank_set(unsigned int bank) { ramh_bank = (int)bank; } -void mmcreplay_ramlbank_set(unsigned int bank) +static void mmcreplay_ramlbank_set(unsigned int bank) { raml_bank = (int)bank; } -void mmcreplay_io1bank_set(unsigned int bank, unsigned int rambank) +static void mmcreplay_io1bank_set(unsigned int bank, unsigned int rambank) { io1_bank = (int)bank; io1_ram_bank = (int)rambank; } -void mmcreplay_io2bank_set(unsigned int bank, unsigned int rambank) +static void mmcreplay_io2bank_set(unsigned int bank, unsigned int rambank) { io2_bank = (int)bank; io2_ram_bank = (int)rambank; @@ -646,10 +662,6 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze io1bank_ram = io1bank; io2bank_ram = io2bank; - /* FIXME */ - mapped_game = 1; - mapped_exrom = 1; - enable_raml = 0; enable_ramh = 0; @@ -772,7 +784,6 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze /* 16k game mode, ultimax */ /* ultimax, ram at $e000, rom at $8000, rom at $a000 */ mapped_game = 1; - mapped_exrom = 1; ultimax_mapping_hack = 1; if (enable_ram_io1) { @@ -893,11 +904,9 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze cartbankl = ((bank_address_16_18 << 3) | bank_address_13_15) & (0x3f); - cartbankh = cartbankl; rambankl = ((bank_address_16_18 << 3) | bank_address_13_15) & (0x3f); - rambankh = rambankl; io1bank = ((bank_address_16_18 << 3) | bank_address_13_15) & (0x3f); @@ -1068,7 +1077,7 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze enable_ramh = 0; } } - LOG(("raml:%d ramh:%d", enable_raml, enable_ramh)); + LOG(("raml:%u ramh:%u", enable_raml, enable_ramh)); } else if (disable_rr_rom) { /************************************************************************************************** * normal mapper @@ -1140,7 +1149,7 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze /* FIXME: add 64kb-rombank offset also for ram ? */ if (enable_extended_mode) { /* extended RR Mode */ - BYTE value = (enable_game) | /* bit 0 */ + uint8_t value = (enable_game) | /* bit 0 */ ((enable_exrom ^ 1) << 1) | /* bit 1 FIXME: is the bit inverted in the register ?! */ (rr_active_bit << 2) | /* bit 2 */ ((bank_address_13_15 & 3) << 3) | /* bit 3,4 */ @@ -1187,10 +1196,10 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze #endif } else { LOG(("rr mode 222 (not extended)")); - LOG(("enable_ram_io:%d", enable_ram_io)); + LOG(("enable_ram_io:%u", enable_ram_io)); /* action replay hack */ if (enable_ram_io) { - BYTE value = (enable_game) | /* bit 0 */ + uint8_t value = (enable_game) | /* bit 0 */ ((enable_exrom ^ 1) << 1) | /* bit 1 FIXME: is the bit inverted in the register ?! */ (((bank_address_13_15 & 3) << 3) | ((bank_address_13_15 & 4) << 5)) | /* bit 3,4,7 */ (enable_ram_io << 5) | /* bit 5 */ @@ -1204,9 +1213,9 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze enable_raml = 0; enable_ramh = 0; } - LOG(("enable_raml:%d", enable_raml)); + LOG(("enable_raml:%u", enable_raml)); - LOG(("enable_ram_io1:%d", enable_ram_io1)); + LOG(("enable_ram_io1:%u", enable_ram_io1)); if (enable_ram_io1) { enable_io1 = 1; enable_io2 = 0; @@ -1238,7 +1247,10 @@ static void mmcreplay_update_mapper_nolog(unsigned int wflag, int release_freeze wflag |= CMODE_RELEASE_FREEZE; } - cart_config_changed_slotmain(active_mode_phi1, active_mode_phi2, wflag); + if (machine_mode) { + /* c64 */ + cart_config_changed_slotmain(active_mode_phi1, active_mode_phi2, wflag); + } cart_romlbank_set_slotmain(cartbankl); cart_romhbank_set_slotmain(cartbankh); @@ -1269,9 +1281,9 @@ int iobank_write = 0; IO1 - $deXX ********************************************************************************************************************/ -BYTE mmcreplay_io1_read(WORD addr) +uint8_t mmcreplay_io1_read(uint16_t addr) { - BYTE value; + uint8_t value; mmcreplay_io1_device.io_source_valid = 0; @@ -1324,7 +1336,7 @@ BYTE mmcreplay_io1_read(WORD addr) #ifdef LOG_READ_IO1_RAM LOG(("MMCREPLAY: RAM IO1 RD %04x %02x (%02x:%04x)", addr, mmcr_ram[(addr & 0x1fff) + (io1_ram_bank << 13)], - io1_ram_bank, (addr & 0x1fff))); + io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif return mmcr_ram[(io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)]; @@ -1332,14 +1344,14 @@ BYTE mmcreplay_io1_read(WORD addr) #ifdef LOG_READ_IO1_ROM LOG(("MMCREPLAY: ROM IO1 RD %04x %02x (%02x:%04x)", addr, roml_banks[(addr & 0x1fff) + (io1_bank << 13)], io1_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); #endif return flash040core_read(flashrom_state, (io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)); } else { #ifdef LOG_READ_IO1_DISABLED LOG(("MMCREPLAY: DISABLED IO1 RD %04x %02x (%02x:%04x)", addr, roml_banks[(addr & 0x1fff) + (io1_bank << 13)], io1_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); #endif } } else { @@ -1351,7 +1363,7 @@ BYTE mmcreplay_io1_read(WORD addr) #ifdef LOG_READ_IO1_RAM LOG(("MMCREPLAY: RAM IO1 RD %04x %02x (%02x:%04x)", addr, mmcr_ram[(addr & 0x1fff) + (io1_ram_bank << 13)], - io1_ram_bank, (addr & 0x1fff))); + io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif return mmcr_ram[(io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)]; @@ -1359,21 +1371,21 @@ BYTE mmcreplay_io1_read(WORD addr) #ifdef LOG_READ_IO1_ROM LOG(("MMCREPLAY: ROM IO1 RD %04x %02x (%02x:%04x)", addr, roml_banks[(addr & 0x1fff) + (io1_bank << 13)], io1_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); #endif return flash040core_read(flashrom_state, (io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)); } else { #ifdef LOG_READ_IO1_DISABLED LOG(("MMCREPLAY: DISABLED IO1 RD %04x %02x (%02x:%04x)", addr, roml_banks[(addr & 0x1fff) + (io1_bank << 13)], io1_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); #endif } } return 0; } -void mmcreplay_io1_store(WORD addr, BYTE value) +void mmcreplay_io1_store(uint16_t addr, uint8_t value) { if (rr_active) { switch (addr & 0xff) { @@ -1401,7 +1413,8 @@ void mmcreplay_io1_store(WORD addr, BYTE value) enable_ram_io = (value >> 5) & 1; /* bit 5 */ enable_freeze_exit = (value >> 6) & 1; /* bit 6 */ #ifdef LOG_WRITE_DE00 - LOG(("MMCREPLAY: IO1 ST %04x %02x enable_game %x enable_exrom %x disable freezer regs %x bank_address_13_15 %x enable_ram_io %x enable_freeze_exit %x", addr, value, enable_game, enable_exrom, value & 4, bank_address_13_15, enable_ram_io, enable_freeze_exit)); + LOG(("MMCREPLAY: IO1 ST %04x %02x enable_game %x enable_exrom %x disable freezer regs %d bank_address_13_15 %x enable_ram_io %x enable_freeze_exit %x", + addr, value, enable_game, enable_exrom, (value >> 2) & 1, bank_address_13_15, enable_ram_io, enable_freeze_exit)); #endif mmcreplay_update_mapper(CMODE_WRITE, enable_freeze_exit); return; @@ -1449,7 +1462,8 @@ void mmcreplay_io1_store(WORD addr, BYTE value) } } #ifdef LOG_WRITE_DE01 - LOG(("MMCREPLAY: IO1 ST %04x %02x mmcr_clockport_enabled %x allow_bank %x no_freeze %x bank_address_13_15 %x enable_mmc_regs_pending %x enable_ram_io1 %x", addr, value, mmcr_clockport_enabled, allow_bank, no_freeze, bank_address_13_15, enable_mmc_regs_pending, enable_ram_io1)); + LOG(("MMCREPLAY: IO1 ST %04x %02x mmcr_clockport_enabled %d allow_bank %x no_freeze %x bank_address_13_15 %x enable_mmc_regs_pending %x enable_ram_io1 %x", + addr, value, mmcr_clockport_enabled, allow_bank, no_freeze, bank_address_13_15, enable_mmc_regs_pending, enable_ram_io1)); #endif mmcreplay_update_mapper(CMODE_WRITE, 0); return; @@ -1473,21 +1487,21 @@ void mmcreplay_io1_store(WORD addr, BYTE value) if (enable_ram_io) { #ifdef LOG_WRITE_IO1_RAM LOG(("store RAM IO1 %04x %02x (%02x:%04x)", addr, value, - io1_ram_bank, (addr & 0x1fff))); + io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif mmcr_ram[(io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)] = value; } else { #ifdef LOG_WRITE_IO1_ROM LOG(("store DISABLED RAM IO1 %04x %02x (%02x:%04x)", addr, - value, io1_ram_bank, (addr & 0x1fff))); + value, io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif flash040core_store(flashrom_state, (io1_ram_bank << 13) + 0x1e00 + (addr & 0xff), value); } } else { #ifdef LOG_WRITE_IO1_DISABLED LOG(("store DISABLED IO1 %04x %02x (%02x:%04x)", addr, value, - io1_bank, (addr & 0x1fff))); + io1_bank, (unsigned)(addr & 0x1fff))); #endif } } else { /* rr active */ @@ -1496,20 +1510,20 @@ void mmcreplay_io1_store(WORD addr, BYTE value) if (enable_ram_io) { #ifdef LOG_WRITE_IO1_RAM LOG(("store RAM IO1 %04x %02x (%02x:%04x)", addr, value, - io1_ram_bank, (addr & 0x1fff))); + io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif mmcr_ram[(io1_ram_bank << 13) + 0x1e00 + (addr & 0xff)] = value; } else { #ifdef LOG_WRITE_IO1_ROM LOG(("store DISABLED RAM IO1 %04x %02x (%02x:%04x)", addr, - value, io1_ram_bank, (addr & 0x1fff))); + value, io1_ram_bank, (unsigned)(addr & 0x1fff))); #endif flash040core_store(flashrom_state, (io1_ram_bank << 13) + 0x1e00 + (addr & 0xff), value); } } else { #ifdef LOG_WRITE_IO1_DISABLED LOG(("store DISABLED IO1 %04x %02x (%02x:%04x)", addr, value, - io1_bank, (addr & 0x1fff))); + io1_bank, (unsigned)(addr & 0x1fff))); #endif } } @@ -1519,9 +1533,9 @@ void mmcreplay_io1_store(WORD addr, BYTE value) IO2 - $dfXX ********************************************************************************************************************/ -BYTE mmcreplay_io2_read(WORD addr) +uint8_t mmcreplay_io2_read(uint16_t addr) { - BYTE value; + uint8_t value; mmcreplay_io2_device.io_source_valid = 0; @@ -1658,29 +1672,30 @@ BYTE mmcreplay_io2_read(WORD addr) #ifdef LOG_READ_IO2_RAM LOG(("MMCREPLAY: RAM IO2 RD %04x %02x (%02x:%04x)", addr, mmcr_ram[(addr & 0x1fff) + (io2_ram_bank << 13)], - io2_ram_bank, (addr & 0x1fff))); + io2_ram_bank, (unsigned)(addr & 0x1fff))); #endif return mmcr_ram[(io2_ram_bank << 13) + 0x1f00 + (addr & 0xff)]; } #ifdef LOG_READ_IO2_ROM LOG(("MMCREPLAY: ROM IO2 RD %04x %02x (%02x:%04x)", addr, roml_banks[(addr & 0x1fff) + (io2_bank << 13)], io2_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); #endif return flash040core_read(flashrom_state, (io2_ram_bank << 13) + 0x1f00 + (addr & 0xff)); } else { #ifdef LOG_READ_IO2_DISABLED LOG(("MMCREPLAY: DISABLED IO2 RD %04x %02x (%02x:%04x)", addr, roml_banks[(io2_ram_bank << 13) + 0x1f00 + (addr & 0xff)], - io2_bank, (addr & 0x1fff))); + io2_bank, (unsigned)(addr & 0x1fff))); #endif } return 0; } -void mmcreplay_io2_store(WORD addr, BYTE value) +void mmcreplay_io2_store(uint16_t addr, uint8_t value) { +/* LOG(("MMCREPLAY: IO2 ST %04x %02x", addr, value)); */ switch (addr & 0xff) { case 0x10: /* @@ -1722,10 +1737,10 @@ void mmcreplay_io2_store(WORD addr, BYTE value) LOG(("MMCREPLAY: IO2 ST %04x %02x disable_mmc_bios %x disable_rr_rom %x", addr, value, disable_mmc_bios, disable_rr_rom)); #endif - spi_mmc_card_selected_write((BYTE)(((value >> 1) ^ 1) & 1)); /* bit 1 */ - spi_mmc_enable_8mhz_write((BYTE)(((value >> 2)) & 1)); /* bit 2 */ + spi_mmc_card_selected_write((uint8_t)(((value >> 1) ^ 1) & 1)); /* bit 1 */ + spi_mmc_enable_8mhz_write((uint8_t)(((value >> 2)) & 1)); /* bit 2 */ /* bit 3,4 always 0 */ - spi_mmc_trigger_mode_write((BYTE)(((value >> 6)) & 1)); /* bit 6 */ + spi_mmc_trigger_mode_write((uint8_t)(((value >> 6)) & 1)); /* bit 6 */ /* bit 7 always 0 */ if (disable_mmc_bios) { /* if (enable_mmc_regs_pending) */ @@ -1783,7 +1798,7 @@ void mmcreplay_io2_store(WORD addr, BYTE value) * bit 5: data/ddr * bit 7: clk */ - eeprom_port_write((BYTE)((value >> 7) & 1), (BYTE)((value >> 5) & 1), + eeprom_port_write((uint8_t)((value >> 7) & 1), (uint8_t)((value >> 5) & 1), (value >> 1) & 1, (value >> 4) & 1); } @@ -1818,7 +1833,8 @@ void mmcreplay_io2_store(WORD addr, BYTE value) rr_active = 1; } #ifdef LOG_WRITE_DF13 - LOG(("MMCREPLAY: IO2 ST %04x %02x bank_address_16_18 %x enable_16k_mapping %x enable rr regs %x", addr, value, bank_address_16_18, enable_16k_mapping, ((value >> 6) & 1))); + LOG(("MMCREPLAY: IO2 ST %04x %02x bank_address_16_18 %x enable_16k_mapping %x enable rr regs %d", + addr, value, bank_address_16_18, enable_16k_mapping, ((value >> 6) & 1))); #endif mmcreplay_update_mapper(CMODE_WRITE, 0); return; @@ -1832,20 +1848,20 @@ void mmcreplay_io2_store(WORD addr, BYTE value) if (enable_ram_io) { #ifdef LOG_WRITE_IO2_RAM LOG(("MMCREPLAY: RAM IO2 ST %04x %02x (%02x:%04x)", addr, value, - io2_ram_bank, (addr & 0x1fff))); + io2_ram_bank, (unsigned)(addr & 0x1fff))); #endif mmcr_ram[(io2_ram_bank << 13) + 0x1f00 + (addr & 0xff)] = value; } else { #ifdef LOG_WRITE_IO2_ROM LOG(("MMCREPLAY: ROM IO2 ST %04x %02x (%02x:%04x)", - addr, value, io2_ram_bank, (addr & 0x1fff))); + addr, value, io2_ram_bank, (unsigned)(addr & 0x1fff))); #endif flash040core_store(flashrom_state, (io2_ram_bank << 13) + 0x1f00 + (addr & 0xff), value); } } else { #ifdef LOG_WRITE_IO2_DISABLED LOG(("MMCREPLAY: DISABLED IO2 ST %04x %02x (%02x:%04x)", addr, value, - io2_bank, (addr & 0x1fff))); + io2_bank, (unsigned)(addr & 0x1fff))); #endif } } @@ -1854,7 +1870,7 @@ void mmcreplay_io2_store(WORD addr, BYTE value) ClockPort ********************************************************************************************************************/ -static BYTE mmcreplay_clockport_read(WORD address) +static uint8_t mmcreplay_clockport_read(uint16_t address) { if (clockport_device) { if (address < 0x02) { @@ -1866,7 +1882,7 @@ static BYTE mmcreplay_clockport_read(WORD address) return 0; } -static BYTE mmcreplay_clockport_peek(WORD address) +static uint8_t mmcreplay_clockport_peek(uint16_t address) { if (clockport_device) { if (address < 0x02) { @@ -1877,7 +1893,7 @@ static BYTE mmcreplay_clockport_peek(WORD address) return 0; } -static void mmcreplay_clockport_store(WORD address, BYTE byte) +static void mmcreplay_clockport_store(uint16_t address, uint8_t byte) { if (clockport_device) { if (address < 0x02) { @@ -1913,7 +1929,7 @@ int logbank_write = 0; /* $1000-$7fff in ultimax mode - this is always regular ram */ -BYTE mmcreplay_1000_7fff_read(WORD addr) +uint8_t mmcreplay_1000_7fff_read(uint16_t addr) { #ifdef DEBUG_LOGBANKS if (logbank_read != (addr & 0xe000)) { @@ -1927,7 +1943,7 @@ BYTE mmcreplay_1000_7fff_read(WORD addr) return vicii_read_phi1(); } -void mmcreplay_1000_7fff_store(WORD addr, BYTE value) +void mmcreplay_1000_7fff_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_LOGBANKS if (logbank_write != (addr & 0xe000)) { @@ -1946,14 +1962,14 @@ void mmcreplay_1000_7fff_store(WORD addr, BYTE value) /* FIXME: something with checking pport.data is wrong, the seperate check for the rescue mode should not be necessary */ -BYTE mmcreplay_roml_read(WORD addr) +uint8_t mmcreplay_roml_read(uint16_t addr) { #ifdef DEBUG_LOGBANKS if (logbank_read != (addr & 0xe000)) { if (enable_raml) { LOG(("MMCREPLAY: RAML RD %04x %02x (%02x:%04x)", addr, mmcr_ram[(addr & 0x1fff) + (raml_bank << 13)], raml_bank, - (addr & 0x1fff))); + (unsigned)(addr & 0x1fff))); logbank_read = (addr & 0xe000); } else { /* @@ -1985,16 +2001,16 @@ BYTE mmcreplay_roml_read(WORD addr) /* FIXME: something with checking pport.data is wrong, the seperate check for the rescue mode should not be necessary */ -void mmcreplay_roml_store(WORD addr, BYTE value) +void mmcreplay_roml_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_LOGBANKS if (logbank_write != (addr & 0xe000)) { if (enable_raml) { LOG(("MMCREPLAY: RAML ST %04x %02x (%02x:%04x)", addr, value, - raml_bank, (addr & 0x1fff))); + raml_bank, (unsigned)(addr & 0x1fff))); } else { LOG(("MMCREPLAY: DISABLED! RAML ST %04x %02x (%02x:%04x)", addr, - value, raml_bank, (addr & 0x1fff))); + value, raml_bank, (unsigned)(addr & 0x1fff))); } logbank_write = (addr & 0xe000); } @@ -2025,7 +2041,7 @@ void mmcreplay_roml_store(WORD addr, BYTE value) /* $a000 in ultimax mode */ -BYTE mmcreplay_a000_bfff_read(WORD addr) +uint8_t mmcreplay_a000_bfff_read(uint16_t addr) { #ifdef DEBUG_LOGBANKS if (logbank_read != (addr & 0xe000)) { @@ -2048,7 +2064,7 @@ BYTE mmcreplay_a000_bfff_read(WORD addr) return vicii_read_phi1(); } -void mmcreplay_a000_bfff_store(WORD addr, BYTE value) +void mmcreplay_a000_bfff_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_LOGBANKS if (logbank_write != (addr & 0xe000)) { @@ -2088,7 +2104,7 @@ void mmcreplay_a000_bfff_store(WORD addr, BYTE value) $c000 in ultimax mode - this is always regular ram */ -BYTE mmcreplay_c000_cfff_read(WORD addr) +uint8_t mmcreplay_c000_cfff_read(uint16_t addr) { #ifdef DEBUG_LOGBANKS if (logbank_read != (addr & 0xe000)) { @@ -2102,7 +2118,7 @@ BYTE mmcreplay_c000_cfff_read(WORD addr) return vicii_read_phi1(); } -void mmcreplay_c000_cfff_store(WORD addr, BYTE value) +void mmcreplay_c000_cfff_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_LOGBANKS if (logbank_write != (addr & 0xe000)) { @@ -2119,7 +2135,7 @@ void mmcreplay_c000_cfff_store(WORD addr, BYTE value) ROMH - $a000 ($e000 in ultimax mode) */ -BYTE mmcreplay_romh_read(WORD addr) +uint8_t mmcreplay_romh_read(uint16_t addr) { #ifdef DEBUG_LOGBANKS if (logbank_read != (addr & 0xe000)) { @@ -2127,13 +2143,13 @@ BYTE mmcreplay_romh_read(WORD addr) if (addr < 0xfff0) { LOG(("MMCREPLAY: RAMH RD %04x %02x (%02x:%04x)", addr, mmcr_ram[(addr & 0x1fff) + (ramh_bank << 13)], - ramh_bank, (addr & 0x1fff))); + ramh_bank, (unsigned)(addr & 0x1fff))); logbank_read = (addr & 0xe000); } } else { LOG (("MMCREPLAY: ROMH RD %04x %02x (%02x:%04x)", addr, - roml_banks[(addr & 0x1fff) + (romh_bank << 13)], romh_bank, - (addr & 0x1fff))); + roml_banks[(addr & 0x1fff) + (romh_bank << 13)], (unsigned)romh_bank, + (unsigned)(addr & 0x1fff))); logbank_read = (addr & 0xe000); } } @@ -2158,16 +2174,16 @@ BYTE mmcreplay_romh_read(WORD addr) return flash040core_read(flashrom_state, (addr & 0x1fff) + (romh_bank << 13)); } -void mmcreplay_romh_store(WORD addr, BYTE value) +void mmcreplay_romh_store(uint16_t addr, uint8_t value) { #ifdef DEBUG_LOGBANKS if (logbank_write != (addr & 0xe000)) { if (enable_ramh) { LOG(("MMCREPLAY: RAMH ST %04x %02x (%02x:%04x)", addr, value, - ramh_bank, (addr & 0x1fff))); + ramh_bank, (unsigned)(addr & 0x1fff))); } else { LOG (("MMCREPLAY: DISABLED! RAMH ST %04x %02x (%02x:%04x)", addr, - value, ramh_bank, (addr & 0x1fff))); + value, ramh_bank, (unsigned)(addr & 0x1fff))); } logbank_write = (addr & 0xe000); } @@ -2187,16 +2203,88 @@ void mmcreplay_romh_store(WORD addr, BYTE value) } } -int mmcreplay_romh_phi1_read(WORD addr, BYTE *value) +int mmcreplay_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int mmcreplay_romh_phi2_read(WORD addr, BYTE *value) +int mmcreplay_romh_phi2_read(uint16_t addr, uint8_t *value) { return mmcreplay_romh_phi1_read(addr, value); } +/****************************************************************************** +C128 support + +FIXME: this is all just a draft and does not work. Generally what should happen + is: + +- the cartridge starts in C128 mode (working) +- it starts executing code from bank 7 (appears to be working) +- it should now show a menu in c128 mode (but it hangs before this) + +It is unknown how the I/O registers work in C128 mode. Perhaps at least some of +the banking is working. It's also possible that basically everything is working, +and a few things explicitly disabled. In any case, the C128 mode should be able +to start and run the C128-mode menu, and then also allow to switch to C64 mode. + +******************************************************************************/ + +/* FIXME: function ROM access in C128 mode + + The CBM Signature for C128 mode is at offset 0x2000 in the ROM. Also the + cartridge apparently starts in the last of 8 64k banks. + + lda #$01 + sta c128mode + + ; ? + lda #$04 + sta $d506 + lda #$0b + sta $ff00 + + + + ; ? + lda #$3a + sta $ff00 +*/ +uint8_t mmcreplay_c128_read(uint16_t addr, uint8_t *value) +{ + uint32_t romaddr; + +#if 0 +/* also called by $c000-$dfff memory so limit it */ + if (addr > 0x9fff || addr < 0x8000) { + return 0; /* read was invalid */ + } +#endif + +#if 1 + romaddr = addr & 0x7fff; + romaddr ^= 0x2000; + romaddr += 7 * 0x10000; +#endif + *value = roml_banks[romaddr]; + /*LOG(("mmcreplay_c128_read %04x %04x got %02x", addr, romaddr, *value));*/ + return 1; /* read was valid */ +} + +void mmcreplay_c128_switch_mode(int mode) +{ + LOG(("MMCREPLAY switch mode: %s", mode ? "c64" : "c128")); + machine_mode = mode; + if ( mode ) { + /* reconfigure for c64 mode */ + mmcreplay_set_stdcfg(); + mmcreplay_update_mapper(CMODE_READ, 0); + } else { + /* reconfigure for c128 mode; boot via ext function rom */ + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + } +} + /********************************************************************************************************************* *********************************************************************************************************************/ @@ -2208,7 +2296,7 @@ RETRO REPLAY: $de01 unset, $df10-$df13 registers disabled SUPER MAPPER: 16K mode, Standard cart mode, $df10-$df13 registers enabled */ -void mmcreplay_set_stdcfg(void) +static void mmcreplay_set_stdcfg(void) { enable_ram_io = 0; enable_ram_io1 = 0; @@ -2377,7 +2465,7 @@ void mmcreplay_freeze(void) /* we don't have a proper hook to release this bit after a while, * so we can only set it to 0 and hope for the best */ - /* freeze_pressed = 1; *//* (r) freeze button pressed. */ + /* freeze_pressed = 1; */ /* (r) freeze button pressed. */ freeze_pressed = 0; /* ^ bit 3: bank address 13 (W) */ /* ^ bit 4: bank address 14 (W) */ @@ -2462,7 +2550,7 @@ void mmcreplay_reset(void) mmcreplay_set_stdcfg(); if (enable_rescue_mode) { - log_debug("MMCREPLAY: Rescue Mode enabled"); + log_debug(LOG_DEFAULT, "MMCREPLAY: Rescue Mode enabled"); } mmcreplay_update_mapper(CMODE_READ, 0); @@ -2473,6 +2561,26 @@ void mmcreplay_reset(void) } } +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void mmcreplay_powerup(void) +{ + if (mmcr_ram) { + ram_init_with_pattern(mmcr_ram, MMCREPLAY_RAM_SIZE, &ramparam); + } +} void mmcreplay_config_init(void) { @@ -2505,8 +2613,9 @@ void mmcreplay_config_init(void) flash040core_reset(flashrom_state); } -void mmcreplay_config_setup(BYTE *rawcart) +void mmcreplay_config_setup(uint8_t *rawcart) { + LOG(("mmcreplay_config_setup")); memcpy(roml_banks, rawcart, MMCREPLAY_FLASHROM_SIZE); flashrom_state = lib_malloc(sizeof(flash040_context_t)); @@ -2514,6 +2623,7 @@ void mmcreplay_config_setup(BYTE *rawcart) memcpy(flashrom_state->flash_data, rawcart, MMCREPLAY_FLASHROM_SIZE); mmcr_ram = lib_malloc(MMCREPLAY_RAM_SIZE); + ram_init_with_pattern(mmcr_ram, MMCREPLAY_RAM_SIZE, &ramparam); mmcreplay_set_stdcfg(); mmcreplay_update_mapper(CMODE_READ, 0); @@ -2539,7 +2649,7 @@ static int set_mmcr_clockport_device(int val, void *param) } if (val != CLOCKPORT_DEVICE_NONE) { - clockport_device = clockport_open_device(val, (char *)STRING_MMC_REPLAY); + clockport_device = clockport_open_device(val, STRING_MMC_REPLAY); if (!clockport_device) { return -1; } @@ -2558,7 +2668,7 @@ static int clockport_activate(void) return 0; } - clockport_device = clockport_open_device(clockport_device_id, (char *)STRING_MMC_REPLAY); + clockport_device = clockport_open_device(clockport_device_id, STRING_MMC_REPLAY); if (!clockport_device) { return -1; } @@ -2602,31 +2712,24 @@ static int mmcreplay_common_attach(const char *filename) mmc_open_card_image(mmcr_card_filename, mmcr_card_rw); eeprom_open_image(mmcr_eeprom_filename, mmcr_eeprom_rw); - mmcr_filename = lib_stralloc(filename); + mmcr_filename = lib_strdup(filename); return 0; } -int mmcreplay_bin_attach(const char *filename, BYTE *rawcart) +int mmcreplay_bin_attach(const char *filename, uint8_t *rawcart) { - int len = 0; - FILE *fd; - mmcr_filetype = 0; mmcr_filename = NULL; if (util_file_load(filename, rawcart, MMCREPLAY_FLASHROM_SIZE, - UTIL_FILE_LOAD_SKIP_ADDRESS | UTIL_FILE_LOAD_FILL) < 0) { - return -1; - } - - fd = fopen(filename, "rb"); - len = util_file_length(fd); - fclose(fd); - - if (len == 0x10000) { - if (util_file_load(filename, &rawcart[7 * 0x10000], 0x10000, - UTIL_FILE_LOAD_SKIP_ADDRESS | UTIL_FILE_LOAD_FILL) < 0) { + UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + /* also try loading one 64k bank */ + if (util_file_load(filename, rawcart, 0x10000, + UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; + } else { + memcpy(&rawcart[7 * 0x10000], &rawcart[0], 0x10000); + memset(&rawcart[0], 0xff, 0x10000); } } @@ -2634,7 +2737,7 @@ int mmcreplay_bin_attach(const char *filename, BYTE *rawcart) return mmcreplay_common_attach(filename); } -int mmcreplay_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int mmcreplay_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; int i; @@ -2723,7 +2826,7 @@ int mmcreplay_crt_save(const char *filename) { FILE *fd; crt_chip_header_t chip; - BYTE *data; + uint8_t *data; int i, n = 0; fd = crt_create(filename, CARTRIDGE_MMC_REPLAY, 1, 0, STRING_MMC_REPLAY); @@ -2782,6 +2885,23 @@ int mmcreplay_flush_image(void) return -1; } +int mmcreplay_save_eeprom(const char *filename) +{ + log_error(LOG_DEFAULT, "FIXME: mmcreplay_save_eeprom not implemented"); + return -1; +} + +int mmcreplay_flush_eeprom(void) +{ + log_error(LOG_DEFAULT, "FIXME: mmcreplay_flush_eeprom not implemented"); + return -1; +} + +int mmcreplay_can_flush_eeprom(void) +{ + return 0; +} + void mmcreplay_detach(void) { if (mmcr_write_image && flashrom_state->flash_dirty) { @@ -2891,7 +3011,7 @@ static int set_mmcr_sd_type(int val, void* param) return -1; } mmcr_sd_type = val; - mmc_set_card_type((BYTE)val); + mmc_set_card_type((uint8_t)val); return 0; } @@ -2942,72 +3062,49 @@ void mmcreplay_resources_shutdown(void) clockport_device_names = NULL; } -static const cmdline_option_t cmdline_options[] = { - { "-mmcrrescue", SET_RESOURCE, 0, +static const cmdline_option_t cmdline_options[] = +{ + { "-mmcrrescue", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRRescueMode", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_RESCUE_MODE_ENABLE, - NULL, NULL }, - { "+mmcrrescue", SET_RESOURCE, 0, + NULL, "Enable MMC Replay rescue mode" }, + { "+mmcrrescue", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRRescueMode", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_RESCUE_MODE_DISABLE, - NULL, NULL }, - { "-mmcrimagerw", SET_RESOURCE, 0, + NULL, "Disable MMC Replay rescue mode" }, + { "-mmcrimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_MMC_REPLAY_IMAGE, - NULL, NULL }, - { "+mmcrimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to MMC Replay image" }, + { "+mmcrimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_MMC_REPLAY_IMAGE, - NULL, NULL }, - { "-mmcrcardimage", SET_RESOURCE, 1, + NULL, "Do not write to MMC Replay image" }, + { "-mmcrcardimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMCRCardImage", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_FILE, IDCLS_SELECT_MMC_REPLAY_CARD_IMAGE_FILENAME, - NULL, NULL }, - { "-mmcrcardrw", SET_RESOURCE, 0, + "", "Specify MMC Replay card image filename" }, + { "-mmcrcardrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRCardRW", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_CARD_WRITE_ENABLE, - NULL, NULL }, - { "+mmcrcardrw", SET_RESOURCE, 0, + NULL, "Enable writes to MMC Replay card image" }, + { "+mmcrcardrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCRCardRW", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_CARD_WRITE_DISABLE, - NULL, NULL }, - { "-mmcreepromimage", SET_RESOURCE, 1, + NULL, "Disable writes to MMC Replay card image" }, + { "-mmcreepromimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMCREEPROMImage", NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_P_FILE, IDCLS_SELECT_MMC_REPLAY_EEPROM_IMAGE, - NULL, NULL }, - { "-mmcreepromrw", SET_RESOURCE, 0, + "", "Specify MMC Replay EEPROM image filename" }, + { "-mmcreepromrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCREEPROMRW", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_EEPROM_WRITE_ENABLE, - NULL, NULL }, - { "+mmcreepromrw", SET_RESOURCE, 0, + NULL, "Enable writes to MMC Replay EEPROM image" }, + { "+mmcreepromrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MMCREEPROMRW", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MMC_REPLAY_EEPROM_WRITE_DISABLE, - NULL, NULL }, - { "-mmcrsdtype", SET_RESOURCE, 1, + NULL, "Disable writes to MMC Replay EEPROM image" }, + { "-mmcrsdtype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMCRSDType", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_TYPE, IDCLS_SELECT_MMC_REPLAY_SD_TYPE, - NULL, NULL }, + "", "Specify MMC Replay SD type (0: auto, 1: MMC, 2: SD, 3: SDHC)" }, CMDLINE_LIST_END }; static cmdline_option_t clockport_cmdline_options[] = { - { "-mmcrclockportdevice", SET_RESOURCE, 1, + { "-mmcrclockportdevice", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "MMCRClockPort", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_DEVICE, IDCLS_CLOCKPORT_DEVICE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -3023,7 +3120,7 @@ int mmcreplay_cmdline_options_init(void) sprintf(number, "%d", clockport_supported_devices[0].id); - clockport_device_names = util_concat(". (", number, ": ", clockport_supported_devices[0].name, NULL); + clockport_device_names = util_concat("Clockport device. (", number, ": ", clockport_supported_devices[0].name, NULL); for (i = 1; clockport_supported_devices[i].name; ++i) { tmp = clockport_device_names; @@ -3049,8 +3146,6 @@ int mmcreplay_cmdline_options_init(void) /* FIXME: implement snapshot support */ int mmcreplay_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -3059,6 +3154,9 @@ int mmcreplay_snapshot_write_module(snapshot_t *s) return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -3073,7 +3171,7 @@ int mmcreplay_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/c64/cart/mmcreplay.h b/src/Emulators/vice/c64/cart/mmcreplay.h index a5cac037..baf9f708 100644 --- a/src/Emulators/vice/c64/cart/mmcreplay.h +++ b/src/Emulators/vice/c64/cart/mmcreplay.h @@ -35,51 +35,63 @@ #include "vicetypes.h" -#define MMCR_TYPE_AUTO 0 -#define MMCR_TYPE_MMC 1 -#define MMCR_TYPE_SD 2 -#define MMCR_TYPE_SDHC 3 +enum { + MMCR_TYPE_AUTO = 0, + MMCR_TYPE_MMC, + MMCR_TYPE_SD, + MMCR_TYPE_SDHC +}; /* FIXME get rid of this */ #define MMCREPLAY_EEPROM_SIZE (1024) -extern BYTE mmcreplay_roml_read(WORD addr); -extern void mmcreplay_roml_store(WORD addr, BYTE value); -extern BYTE mmcreplay_romh_read(WORD addr); -extern void mmcreplay_romh_store(WORD addr, BYTE value); - -extern BYTE mmcreplay_1000_7fff_read(WORD addr); -extern void mmcreplay_1000_7fff_store(WORD addr, BYTE value); -extern BYTE mmcreplay_a000_bfff_read(WORD addr); -extern void mmcreplay_a000_bfff_store(WORD addr, BYTE value); -extern BYTE mmcreplay_c000_cfff_read(WORD addr); -extern void mmcreplay_c000_cfff_store(WORD addr, BYTE value); - -extern int mmcreplay_romh_phi1_read(WORD addr, BYTE *value); -extern int mmcreplay_romh_phi2_read(WORD addr, BYTE *value); - -extern void mmcreplay_freeze(void); -extern int mmcreplay_freeze_allowed(void); - -extern void mmcreplay_config_init(void); -extern void mmcreplay_reset(void); -extern void mmcreplay_config_setup(BYTE *rawcart); -extern int mmcreplay_bin_attach(const char *filename, BYTE *rawcart); -extern int mmcreplay_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern void mmcreplay_detach(void); -extern int mmcreplay_flush_image(void); -extern int mmcreplay_bin_save(const char *filename); -extern int mmcreplay_crt_save(const char *filename); - -extern int mmcreplay_resources_init(void); -extern void mmcreplay_resources_shutdown(void); -extern int mmcreplay_cmdline_options_init(void); - -extern int mmcreplay_cart_enabled(void); +uint8_t mmcreplay_roml_read(uint16_t addr); +void mmcreplay_roml_store(uint16_t addr, uint8_t value); +uint8_t mmcreplay_romh_read(uint16_t addr); +void mmcreplay_romh_store(uint16_t addr, uint8_t value); + +uint8_t mmcreplay_1000_7fff_read(uint16_t addr); +void mmcreplay_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t mmcreplay_a000_bfff_read(uint16_t addr); +void mmcreplay_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t mmcreplay_c000_cfff_read(uint16_t addr); +void mmcreplay_c000_cfff_store(uint16_t addr, uint8_t value); + +uint8_t mmcreplay_c128_read(uint16_t addr, uint8_t *value); +void mmcreplay_c128_switch_mode(int mode); + +int mmcreplay_romh_phi1_read(uint16_t addr, uint8_t *value); +int mmcreplay_romh_phi2_read(uint16_t addr, uint8_t *value); + +void mmcreplay_freeze(void); +int mmcreplay_freeze_allowed(void); + +void mmcreplay_config_init(void); +void mmcreplay_reset(void); +void mmcreplay_config_setup(uint8_t *rawcart); +int mmcreplay_bin_attach(const char *filename, uint8_t *rawcart); +int mmcreplay_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +void mmcreplay_detach(void); +int mmcreplay_flush_image(void); +int mmcreplay_bin_save(const char *filename); +int mmcreplay_crt_save(const char *filename); +void mmcreplay_powerup(void); + +int mmcreplay_save_eeprom(const char *filename); +int mmcreplay_flush_eeprom(void); +int mmcreplay_can_flush_eeprom(void); + +int mmcreplay_resources_init(void); +void mmcreplay_resources_shutdown(void); +int mmcreplay_cmdline_options_init(void); + +int mmcreplay_cart_enabled(void); extern int mmcr_clockport_enabled; /* FIXME */ struct snapshot_s; -extern int mmcreplay_snapshot_read_module(struct snapshot_s *s); -extern int mmcreplay_snapshot_write_module(struct snapshot_s *s); + +int mmcreplay_snapshot_read_module(struct snapshot_s *s); +int mmcreplay_snapshot_write_module(struct snapshot_s *s); #endif + diff --git a/src/Emulators/vice/c64/cart/multimax.c b/src/Emulators/vice/c64/cart/multimax.c new file mode 100644 index 00000000..36af76a7 --- /dev/null +++ b/src/Emulators/vice/c64/cart/multimax.c @@ -0,0 +1,337 @@ +/* + * multimax.c - Cartridge handling, MultiMAX cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64memrom.h" +#include "c64rom.h" +#include "cartio.h" +#include "cartridge.h" +#include "monitor.h" +#include "multimax.h" +#include "export.h" +#include "resources.h" +#include "ram.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" + +/* + MultiMAX + + 16MB ROM, 64*16K + - ROM is mapped to $8000 and $e000 using ultimax mode + + 2K RAM + - RAM is mapped to $0800 + + One register in the entire I/O1 (or extended RAM for the MAX Machine) space. + The register latches the lowbyte of the *address* (not the value written): + + bit 7 when set, a) the register is disabled and can only be + re-enabled by reset and b) the extra RAM is enabled and replaces + the register latch. + bit 0-5 select ROM bank 0-63 + + The menu software does this: + + lda $05 ; bank number + tax + sta $de80,x + sta $0880,x + + ... so it stores the bank number as a value and address, which indicates + that during development it was changed from value to address - which would + also explain the inconsistent documentation. + +*/ + +#define CART_RAM_SIZE (2 * 1024) + +static uint8_t currbank = 0; +static uint8_t reg_enabled = 1; + +/* this is used on regular C64s */ +static void multimax_io1_store(uint16_t addr, uint8_t value) +{ + /*printf("io1 w %04x %02x\n", addr, value);*/ + if (reg_enabled) { + currbank = addr & 0x3f; + reg_enabled = ((addr >> 7) & 1) ^ 1; + /*printf("Bank: %02x Register: %s RAM: %s\n", currbank, + reg_enabled ? "enabled" : "disabled", reg_enabled ? "disabled" : "enabled");*/ + } +} + +static int multimax_dump(void) +{ + mon_out("Register is %s.\n", reg_enabled ? "enabled" : "disabled"); + mon_out("Extra RAM is %s.\n", reg_enabled ? "disabled" : "enabled"); + mon_out("ROM Bank: %d\n", currbank); + return 0; +} + +static io_source_t multimax_device = { + CARTRIDGE_NAME_MULTIMAX, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + multimax_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + multimax_dump, /* device state information dump function */ + CARTRIDGE_MULTIMAX, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *multimax_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_MULTIMAX, 1, 1, &multimax_device, NULL, CARTRIDGE_MULTIMAX +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t multimax_0800_0fff_read(uint16_t addr) +{ + if (reg_enabled == 0) { + /*printf("ram r %04x %02x\n", addr, export_ram0[addr & 0x07ff]);*/ + return export_ram0[addr & 0x07ff]; + } + return vicii_read_phi1(); +} + +void multimax_0800_0fff_store(uint16_t addr, uint8_t value) +{ + if (reg_enabled) { + /*printf("reg w %04x %02x\n", addr, value);*/ + currbank = addr & 0x7f; + reg_enabled = ((addr >> 7) & 1) ^ 1; + /*printf("Bank: %02x Register: %s RAM: %s\n", currbank, + reg_enabled ? "enabled" : "disabled", reg_enabled ? "disabled" : "enabled");*/ + } else { + /*printf("ram w %04x %02x\n", addr, value);*/ + export_ram0[addr & 0x07ff] = value; + } +} + +uint8_t multimax_roml_read(uint16_t addr) +{ + return roml_banks[(addr & 0x1fff) + (currbank * 0x2000)]; +} + +uint8_t multimax_romh_read(uint16_t addr) +{ + return romh_banks[(addr & 0x1fff) + (currbank * 0x2000)]; +} + +int multimax_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if (addr >= 0xe000) { + *value = romh_banks[(addr & 0x1fff) + (currbank * 0x2000)]; + return CART_READ_VALID; + } else if ((addr >= 0xa000) && (addr <= 0xbfff)) { + *value = roml_banks[(addr & 0x1fff) + (currbank * 0x2000)]; + return CART_READ_VALID; + } else if ((addr >= 0x0800) && (addr <= 0x0fff)) { + *value = export_ram0[addr & 0x07ff]; + return CART_READ_VALID; + } + return CART_READ_THROUGH; +} + +void multimax_config_init(void) +{ + currbank = 0; + reg_enabled = 1; + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +void multimax_config_setup(uint8_t *rawcart) +{ + int i; + for (i = 0; i < 64; i++) { + memcpy(&roml_banks[0x0000 + (i * 0x2000)], &rawcart[0x0000 + (i * 0x4000)], 0x2000); + memcpy(&romh_banks[0x0000 + (i * 0x2000)], &rawcart[0x2000 + (i * 0x4000)], 0x2000); + } + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void multimax_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + +static int multimax_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + multimax_list_item = io_source_register(&multimax_device); + return 0; +} + +int multimax_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 1024 * 1024, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return multimax_common_attach(); +} + +int multimax_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i; + + for (i = 0; i < 64; i++) { + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.size != 0x4000) { + return -1; + } + + if (crt_read_chip(rawcart + (i * 0x4000), 0, &chip, fd)) { + return -1; + } + } + + return multimax_common_attach(); +} + +void multimax_detach(void) +{ + export_remove(&export_res); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTMULTIMAX snapshot module format: + + type | name | description + ------------------------------------------------------ + BYTE | currbank | current ROM bank + BYTE | reg_enabled | flag, is the register enabled? + ARRAY | ROML | 512K of ROML data + ARRAY | ROMH | 512K of ROMH data + ARRAY | RAM | 2048 BYTES of RAM data + */ + +static const char snap_module_name[] = "CARTMULTIMAX"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int multimax_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)currbank) < 0) + || (SMW_B(m, (uint8_t)reg_enabled) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * 64) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * 64) < 0) + || (SMW_BA(m, export_ram0, 0x0800) < 0)) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int multimax_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_B(m, &currbank) < 0) + || (SMR_B(m, ®_enabled) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * 64) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * 64) < 0) + || (SMR_BA(m, export_ram0, 0x0800) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + return multimax_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/multimax.h b/src/Emulators/vice/c64/cart/multimax.h new file mode 100644 index 00000000..0f947735 --- /dev/null +++ b/src/Emulators/vice/c64/cart/multimax.h @@ -0,0 +1,54 @@ +/* + * multimax.h - Cartridge handling, MultiMAX cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_MULTIMAX_H +#define VICE_MULTIMAX_H + +#include + +#include "vicetypes.h" +#include "c64cart.h" + +struct snapshot_s; + +uint8_t multimax_0800_0fff_read(uint16_t addr); +void multimax_0800_0fff_store(uint16_t addr, uint8_t value); +uint8_t multimax_roml_read(uint16_t addr); +uint8_t multimax_romh_read(uint16_t addr); +int multimax_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void multimax_config_init(void); +void multimax_reset(void); +void multimax_config_setup(uint8_t *rawcart); +int multimax_bin_attach(const char *filename, uint8_t *rawcart); +int multimax_crt_attach(FILE *fd, uint8_t *rawcart); +void multimax_detach(void); +void multimax_powerup(void); + +int multimax_snapshot_write_module(struct snapshot_s *s); +int multimax_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/ocean.c b/src/Emulators/vice/c64/cart/ocean.c index 6dd097f8..494de00f 100644 --- a/src/Emulators/vice/c64/cart/ocean.c +++ b/src/Emulators/vice/c64/cart/ocean.c @@ -92,15 +92,14 @@ /* ---------------------------------------------------------------------*/ -static BYTE currbank = 0; -static BYTE regval = 0; -static BYTE io1_mask = 0x3f; -static unsigned int cart_size = 0; +static uint8_t currbank = 0; +static uint8_t regval = 0; +static uint8_t io1_mask = 0x3f; +static uint32_t cart_size = 0; /* ---------------------------------------------------------------------*/ -static void ocean_io1_store(WORD addr, BYTE value) +static void ocean_io1_store(uint16_t addr, uint8_t value) { - addr &= 0xff; regval = value; currbank = value & io1_mask & 0x3f; @@ -108,7 +107,7 @@ static void ocean_io1_store(WORD addr, BYTE value) cart_port_config_changed_slotmain(); } -static BYTE ocean_io1_peek(WORD addr) +static uint8_t ocean_io1_peek(uint16_t addr) { return regval; } @@ -122,18 +121,20 @@ static int ocean_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t ocean_device = { - CARTRIDGE_NAME_OCEAN, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - ocean_io1_store, - NULL, - ocean_io1_peek, - ocean_dump, - CARTRIDGE_OCEAN, - 0, - 0 + CARTRIDGE_NAME_OCEAN, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid, regs are write only */ + ocean_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + ocean_io1_peek, /* peek function */ + ocean_dump, /* device state information dump function */ + CARTRIDGE_OCEAN, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ocean_list_item = NULL; @@ -144,7 +145,7 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -BYTE ocean_romh_read(WORD addr) +uint8_t ocean_romh_read(uint16_t addr) { /* 256 kB OCEAN carts may access memory either at $8000 or $a000 */ return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; @@ -152,34 +153,34 @@ BYTE ocean_romh_read(WORD addr) void ocean_config_init(void) { - ocean_io1_store((WORD)0xde00, 0); + ocean_io1_store((uint16_t)0xde00, 0); #ifdef ALWAYS16K /* Hack: using 16kB configuration, but some carts are 8kB only */ - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); #else if (cart_size == 0x80000) { /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } else { /* 16kB configuration */ - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } #endif } -void ocean_config_setup(BYTE *rawcart) +void ocean_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 64); #ifdef ALWAYS16K /* Hack: using 16kB configuration, but some carts are 8kB only */ - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); #else if (cart_size == 0x80000) { /* 8k configuration */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); } else { /* 16kB configuration */ - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } #endif } @@ -197,13 +198,13 @@ static int ocean_common_attach(void) /* ---------------------------------------------------------------------*/ /* HACK: 32k isnt really a valid size, see above */ -int ocean_cart_sizes[] = { 0x80000, 0x40000, 0x20000, 0x08000, 0 }; +static const uint32_t ocean_cart_sizes[] = { 0x80000, 0x40000, 0x20000, 0x08000, 0 }; -int ocean_bin_attach(const char *filename, BYTE *rawcart) +int ocean_bin_attach(const char *filename, uint8_t *rawcart) { int rc = -1; int i; - size_t size; + uint32_t size; for (i = 0; (size = ocean_cart_sizes[i]) != 0; i++) { rc = util_file_load(filename, rawcart, size, UTIL_FILE_LOAD_SKIP_ADDRESS); if (rc == 0) { @@ -220,9 +221,9 @@ int ocean_bin_attach(const char *filename, BYTE *rawcart) return rc; } -int ocean_crt_attach(FILE *fd, BYTE *rawcart) +int ocean_crt_attach(FILE *fd, uint8_t *rawcart) { - size_t rom_size; + uint32_t rom_size; crt_chip_header_t chip; rom_size = 0; @@ -265,7 +266,7 @@ void ocean_detach(void) ARRAY | ROML | 524288 BYTES of ROML data */ -static char snap_module_name[] = "CARTOCEAN"; +static const char snap_module_name[] = "CARTOCEAN"; #define SNAP_MAJOR 1 #define SNAP_MINOR 0 @@ -280,10 +281,10 @@ int ocean_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)currbank) < 0) - || (SMW_B(m, (BYTE)io1_mask) < 0) - || (SMW_B(m, (BYTE)regval) < 0) - || (SMW_DW(m, (DWORD)cart_size) < 0) + || (SMW_B(m, (uint8_t)currbank) < 0) + || (SMW_B(m, (uint8_t)io1_mask) < 0) + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_DW(m, (uint32_t)cart_size) < 0) || (SMW_BA(m, roml_banks, 0x2000 * 64) < 0)) { snapshot_module_close(m); return -1; @@ -294,7 +295,7 @@ int ocean_snapshot_write_module(snapshot_t *s) int ocean_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -304,7 +305,7 @@ int ocean_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -313,7 +314,7 @@ int ocean_snapshot_read_module(snapshot_t *s) || (SMR_B(m, &currbank) < 0) || (SMR_B(m, &io1_mask) < 0) || (SMR_B(m, ®val) < 0) - || (SMR_DW_UINT(m, &cart_size) < 0) + || (SMR_DW(m, &cart_size) < 0) || (SMR_BA(m, roml_banks, 0x2000 * 64) < 0)) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/ocean.h b/src/Emulators/vice/c64/cart/ocean.h index 03b0a2d4..a690c115 100644 --- a/src/Emulators/vice/c64/cart/ocean.h +++ b/src/Emulators/vice/c64/cart/ocean.h @@ -31,17 +31,17 @@ #include "vicetypes.h" -extern void ocean_config_setup(BYTE *rawcart); -extern void ocean_config_init(void); -extern int ocean_bin_attach(const char *filename, BYTE *rawcart); -extern int ocean_crt_attach(FILE *fd, BYTE *rawcart); -extern void ocean_detach(void); +void ocean_config_setup(uint8_t *rawcart); +void ocean_config_init(void); +int ocean_bin_attach(const char *filename, uint8_t *rawcart); +int ocean_crt_attach(FILE *fd, uint8_t *rawcart); +void ocean_detach(void); -extern BYTE ocean_romh_read(WORD addr); +uint8_t ocean_romh_read(uint16_t addr); struct snapshot_s; -extern int ocean_snapshot_write_module(struct snapshot_s *s); -extern int ocean_snapshot_read_module(struct snapshot_s *s); +int ocean_snapshot_write_module(struct snapshot_s *s); +int ocean_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/pagefox.c b/src/Emulators/vice/c64/cart/pagefox.c index 443e35ca..5dbeb964 100644 --- a/src/Emulators/vice/c64/cart/pagefox.c +++ b/src/Emulators/vice/c64/cart/pagefox.c @@ -40,11 +40,14 @@ #include "export.h" #include "lib.h" #include "monitor.h" +#include "ram.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #include "crt.h" +#include "pagefox.h" + /* Pagefox Cartridge @@ -86,14 +89,14 @@ #define PAGEFOX_RAMSIZE (32 * 1024) -static BYTE *pagefox_ram = NULL; +static uint8_t *pagefox_ram = NULL; static int pagefox_enabled = 0; static int currbank = 0; static int chipselect = 0; static int bankselect = 0; -static void pagefox_io1_store(WORD addr, BYTE value) +static void pagefox_io1_store(uint16_t addr, uint8_t value) { bankselect = ((value >> 1) & 1); chipselect = (value >> 2) & 3; @@ -112,7 +115,7 @@ static void pagefox_io1_store(WORD addr, BYTE value) cart_romlbank_set_slotmain(currbank & 3); } -static BYTE pagefox_io1_peek(WORD addr) +static uint8_t pagefox_io1_peek(uint16_t addr) { return (bankselect << 1) | (chipselect << 2) | ((pagefox_enabled ^ 1) << 4); } @@ -129,18 +132,20 @@ static int pagefox_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t pagefox_device = { - CARTRIDGE_NAME_PAGEFOX, - IO_DETACH_CART, - NULL, - 0xde80, 0xdeff, 0xff, - 0, - pagefox_io1_store, - NULL, - pagefox_io1_peek, - pagefox_dump, - CARTRIDGE_PAGEFOX, - 0, - 0 + CARTRIDGE_NAME_PAGEFOX, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde80, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de80, mirrors:$de81-$deff */ + 0, /* read is never valid, reg is write only */ + pagefox_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + pagefox_io1_peek, /* peek function */ + pagefox_dump, /* device state information dump function */ + CARTRIDGE_PAGEFOX, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *pagefox_list_item = NULL; @@ -152,7 +157,7 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ /* ROML read - mapped to 8000 in 8k,16k,ultimax */ -BYTE pagefox_roml_read(WORD addr) +uint8_t pagefox_roml_read(uint16_t addr) { if (chipselect == 2) { return pagefox_ram[0x0000 + (addr & 0x1fff) + (bankselect << 14)]; @@ -161,7 +166,7 @@ BYTE pagefox_roml_read(WORD addr) } /* ROML store - mapped to 8000 in ultimax mode */ -void pagefox_roml_store(WORD addr, BYTE value) +void pagefox_roml_store(uint16_t addr, uint8_t value) { /* printf("pagefox_roml_store chipselect: %d bankselect: %d %04x,%02x\n", chipselect, bankselect, addr, value); */ if (chipselect == 2) { @@ -170,7 +175,7 @@ void pagefox_roml_store(WORD addr, BYTE value) } /* ROMH read - mapped to A000 in 16k, to E000 in ultimax */ -BYTE pagefox_romh_read(WORD addr) +uint8_t pagefox_romh_read(uint16_t addr) { if (chipselect == 2) { return pagefox_ram[0x2000 + (addr & 0x1fff) + (bankselect << 14)]; @@ -178,7 +183,7 @@ BYTE pagefox_romh_read(WORD addr) return romh_banks[(addr & 0x1fff) + (romh_bank << 13)]; } -void pagefox_romh_store(WORD addr, BYTE value) +void pagefox_romh_store(uint16_t addr, uint8_t value) { /* printf("pagefox_romh_store chipselect: %d bankselect: %d %04x,%02x\n", chipselect, bankselect, addr, value); */ if (chipselect == 2) { @@ -188,12 +193,33 @@ void pagefox_romh_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void pagefox_powerup(void) +{ + if (pagefox_ram) { + ram_init_with_pattern(pagefox_ram, PAGEFOX_RAMSIZE, &ramparam); + } +} + void pagefox_config_init(void) { pagefox_io1_store(0xde80, 0x00); } -void pagefox_config_setup(BYTE *rawcart) +void pagefox_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); @@ -216,16 +242,18 @@ static int pagefox_common_attach(void) return 0; } -int pagefox_bin_attach(const char *filename, BYTE *rawcart) +int pagefox_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } - pagefox_ram = lib_malloc(PAGEFOX_RAMSIZE); + if (pagefox_ram == NULL) { + pagefox_ram = lib_malloc(PAGEFOX_RAMSIZE); + } return pagefox_common_attach(); } -int pagefox_crt_attach(FILE *fd, BYTE *rawcart) +int pagefox_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -242,7 +270,9 @@ int pagefox_crt_attach(FILE *fd, BYTE *rawcart) return -1; } } - pagefox_ram = lib_malloc(PAGEFOX_RAMSIZE); + if (pagefox_ram == NULL) { + pagefox_ram = lib_malloc(PAGEFOX_RAMSIZE); + } return pagefox_common_attach(); } @@ -252,6 +282,7 @@ void pagefox_detach(void) io_source_unregister(pagefox_list_item); pagefox_list_item = NULL; lib_free(pagefox_ram); + pagefox_ram = NULL; } /* ---------------------------------------------------------------------*/ @@ -267,7 +298,7 @@ void pagefox_detach(void) ARRAY | ROMH | 0.0+ | 32768 BYTES of ROMH data */ -static char snap_module_name[] = "CARTPAGEFOX"; +static const char snap_module_name[] = "CARTPAGEFOX"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -282,8 +313,8 @@ int pagefox_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)pagefox_enabled) < 0 - || SMW_B(m, (BYTE)currbank) < 0 + || SMW_B(m, (uint8_t)pagefox_enabled) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 || SMW_BA(m, pagefox_ram, PAGEFOX_RAMSIZE) < 0 || SMW_BA(m, roml_banks, 0x8000) < 0 || SMW_BA(m, romh_banks, 0x8000) < 0) { @@ -296,7 +327,7 @@ int pagefox_snapshot_write_module(snapshot_t *s) int pagefox_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -306,13 +337,13 @@ int pagefox_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &pagefox_enabled) < 0) { goto fail; } @@ -328,6 +359,7 @@ int pagefox_snapshot_read_module(snapshot_t *s) || SMR_BA(m, roml_banks, 0x8000) < 0 || SMR_BA(m, romh_banks, 0x8000) < 0) { lib_free(pagefox_ram); + pagefox_ram = NULL; goto fail; } diff --git a/src/Emulators/vice/c64/cart/pagefox.h b/src/Emulators/vice/c64/cart/pagefox.h index d3a2938f..3a3b91b8 100644 --- a/src/Emulators/vice/c64/cart/pagefox.h +++ b/src/Emulators/vice/c64/cart/pagefox.h @@ -31,20 +31,21 @@ #include "vicetypes.h" -extern void pagefox_config_init(void); -extern void pagefox_config_setup(BYTE *rawcart); -extern int pagefox_bin_attach(const char *filename, BYTE *rawcart); -extern int pagefox_crt_attach(FILE *fd, BYTE *rawcart); -extern void pagefox_detach(void); - -extern BYTE pagefox_roml_read(WORD addr); -extern void pagefox_roml_store(WORD addr, BYTE value); -extern BYTE pagefox_romh_read(WORD addr); -extern void pagefox_romh_store(WORD addr, BYTE value); +void pagefox_config_init(void); +void pagefox_config_setup(uint8_t *rawcart); +int pagefox_bin_attach(const char *filename, uint8_t *rawcart); +int pagefox_crt_attach(FILE *fd, uint8_t *rawcart); +void pagefox_detach(void); +void pagefox_powerup(void); + +uint8_t pagefox_roml_read(uint16_t addr); +void pagefox_roml_store(uint16_t addr, uint8_t value); +uint8_t pagefox_romh_read(uint16_t addr); +void pagefox_romh_store(uint16_t addr, uint8_t value); struct snapshot_s; -extern int pagefox_snapshot_write_module(struct snapshot_s *s); -extern int pagefox_snapshot_read_module(struct snapshot_s *s); +int pagefox_snapshot_write_module(struct snapshot_s *s); +int pagefox_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/partner64.c b/src/Emulators/vice/c64/cart/partner64.c new file mode 100644 index 00000000..0da93c9b --- /dev/null +++ b/src/Emulators/vice/c64/cart/partner64.c @@ -0,0 +1,323 @@ +/* + * partner64.c - Cartridge handling, Partner64 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "partner64.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "log.h" +#include "monitor.h" +#include "ram.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" + +#define DBGPARTNER + +#ifdef DBGPARTNER +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + Partner 64 (Timeworks) + + WARNING: all of the following is guesswork based on a disassembly and some + educated guessing + + - 16K ROM, ROML at $8000 and ROMH at $e000 + - 8K ROM at $a000 + + IO1 (writes): + + $de00 - disable cart + $def0 - disable cart + $def1 - enable cart + $deff - acknowledge freeze + +*/ + +#define CART_RAM_SIZE 0x2000 + +/* ---------------------------------------------------------------------*/ + +/* some prototypes are needed */ +static uint8_t partner64_io1_read(uint16_t addr); +static void partner64_io1_store(uint16_t addr, uint8_t value); +static int partner64_dump(void); + +static io_source_t partner64_io1_device = { + CARTRIDGE_NAME_PARTNER64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored by the write functions, reg:$de00, mirrors:$de01-$deff */ + 1, /* read is always valid */ + partner64_io1_store, /* store function */ + NULL, /* NO poke function */ + partner64_io1_read, /* read function */ + NULL, /* NO peek function */ + partner64_dump, /* device state information dump function */ + CARTRIDGE_PARTNER64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *partner64_io1_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_PARTNER64, 1, 1, &partner64_io1_device, NULL, CARTRIDGE_PARTNER64 +}; + +/* ---------------------------------------------------------------------*/ + +static void partner64_io1_store(uint16_t addr, uint8_t value) +{ + if (addr == 0x00) { + /* disable cartridge (before starting BASIC) (@ $8471) */ + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + } else if (addr == 0xf0) { + /* disable cartridge */ + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + } else if (addr == 0xf1) { + /* enable cartridge (@ $dec0)*/ + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); + } else if (addr == 0xff) { + /* enable cartridge (at freeze start) (@ $8012) */ + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ | CMODE_RELEASE_FREEZE); + } else { + DBG(("partner64_io1_store %04x %02x\n", addr, value)); + } +} + +static uint8_t partner64_io1_read(uint16_t addr) +{ + return roml_banks[(addr + 0x1e00) & 0x1fff]; +} + +static int partner64_dump(void) +{ + /* FIXME */ + return 0; +} + +/* ---------------------------------------------------------------------*/ + +uint8_t partner64_roml_read(uint16_t addr) +{ + return roml_banks[addr & 0x1fff]; +} + +uint8_t partner64_romh_read(uint16_t addr) +{ + return romh_banks[addr & 0x1fff]; +} + +uint8_t partner64_a000_bfff_read(uint16_t addr) +{ + return export_ram0[addr & 0x1fff]; +} + +void partner64_a000_bfff_store(uint16_t addr, uint8_t value) +{ + export_ram0[addr & 0x1fff] = value; +} + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void partner64_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + +void partner64_freeze(void) +{ + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +void partner64_config_init(void) +{ + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +void partner64_reset(void) +{ +} + +void partner64_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000); + memcpy(romh_banks, rawcart + 0x2000, 0x2000); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int partner64_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + partner64_io1_list_item = io_source_register(&partner64_io1_device); + + return 0; +} + +int partner64_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return partner64_common_attach(); +} + +int partner64_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i; + + for (i = 0; i < 2; i++) { + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank > 0 || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart + (i * 0x2000), 0, &chip, fd)) { + return -1; + } + } + + return partner64_common_attach(); +} + +void partner64_detach(void) +{ + io_source_unregister(partner64_io1_list_item); + partner64_io1_list_item = NULL; + export_remove(&export_res); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTAR snapshot module format: + + type | name | description + ---------------------------- + BYTE | active | cartridge is active + ARRAY | ROML | 8192 BYTES of ROML data + ARRAY | ROMH | 8192 BYTES of ROMH data + ARRAY | RAM | 8192 BYES of RAM data + */ + +static const char snap_module_name[] = "CARTPARTNER64"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int partner64_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_BA(m, roml_banks, 0x2000) < 0) + || (SMW_BA(m, romh_banks, 0x2000) < 0) + || (SMW_BA(m, export_ram0, 0x2000) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int partner64_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept higher versions than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_BA(m, roml_banks, 0x2000) < 0) + || (SMR_BA(m, romh_banks, 0x2000) < 0) + || (SMR_BA(m, export_ram0, 0x2000) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + return partner64_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/partner64.h b/src/Emulators/vice/c64/cart/partner64.h new file mode 100644 index 00000000..1d24533e --- /dev/null +++ b/src/Emulators/vice/c64/cart/partner64.h @@ -0,0 +1,54 @@ +/* + * partner64.h - Cartridge handling, Partner64 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_PARTNER64_H +#define VICE_PARTNER64_H + +#include + +#include "vicetypes.h" + +uint8_t partner64_roml_read(uint16_t addr); +uint8_t partner64_romh_read(uint16_t addr); +uint8_t partner64_a000_bfff_read(uint16_t addr); +void partner64_a000_bfff_store(uint16_t addr, uint8_t value); + +void partner64_freeze(void); + +void partner64_config_init(void); +void partner64_reset(void); +void partner64_config_setup(uint8_t *rawcart); +int partner64_bin_attach(const char *filename, uint8_t *rawcart); +int partner64_crt_attach(FILE *fd, uint8_t *rawcart); +void partner64_detach(void); +void partner64_powerup(void); + +struct snapshot_s; + +int partner64_snapshot_write_module(struct snapshot_s *s); +int partner64_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/profidos.c b/src/Emulators/vice/c64/cart/profidos.c new file mode 100644 index 00000000..7cf1f38a --- /dev/null +++ b/src/Emulators/vice/c64/cart/profidos.c @@ -0,0 +1,358 @@ +/* + * profidos.c - Cartridge handling, Profi-DOS cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64memrom.h" +#include "c64rom.h" +#include "cartio.h" +#include "cartridge.h" +#include "log.h" +#include "maincpu.h" +#include "monitor.h" +#include "profidos.h" +#include "export.h" +#include "resources.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* #define DEBUG_PROFIDOS */ + +#ifdef DEBUG_PROFIDOS +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* + Profi-DOS (REX Datentechnik) + + 16K ROM (27128) + + The ROM is connected like this: + + Port EPROM + + D7 => D6 + D6 => D4 + D5 => D7 + D4 => D5 + D3 => D0 + D2 => D3 + D1 => D1 + D0 => D2 + + A0 => A0 + A1 => A1 + A2 => A2 + A3 => A3 + A4 => A4 + A5 => A5 + A6 => A6 + A7 => A7 + A8 => A12 + A9 => A10 + A10 => A11 + A11 => A9 + A12 => A8 + A13 => A13 + + After reorganizing the ROM data as shown above, the first 8k bank of the ROM + contains the code. The second bank is used as a lookup table, and wired so + that when D0 becomes active (=0), then a counter is started which counts 4 + cycles. If during those 4 cycles D1 becomes active (=0), then the EPROM is + enabled and the cartridge enables ultimax mode for ROMH. This way the cart + can patch the kernal, without having an explicit enable mechanism - which + makes it hard to dump (you'll have to know the addresses where this happens) + + Any access (read or write) to IO2 ($dfxx) will disable the cartridge again. +*/ + +static int enabled = 0; +static CLOCK check_cycles = 0; + +static void profidos_io2_store(uint16_t addr, uint8_t value); +static uint8_t profidos_io2_read(uint16_t addr); +static int profidos_dump(void); + +static io_source_t profidos_io2_device = { + CARTRIDGE_NAME_PROFIDOS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is never valid */ + profidos_io2_store, /* store function */ + NULL, /* NO poke function */ + profidos_io2_read, /* read function */ + NULL, /* NO peek function */ + profidos_dump, /* device state information dump function */ + CARTRIDGE_PROFIDOS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_PROFIDOS, 0, 1, NULL, &profidos_io2_device, CARTRIDGE_PROFIDOS +}; + +static io_source_list_t *profidos_io2_list_item = NULL; + +/* ---------------------------------------------------------------------*/ + +static int profidos_dump(void) +{ + mon_out("enabled: %s\n", enabled ? "yes" : "no"); + return 0; +} + +static void profidos_io2_store(uint16_t addr, uint8_t value) +{ + DBG(("%08lx profidos_io2_store %04x %02x", maincpu_clk, addr, value)); + enabled = 0; +} + +static uint8_t profidos_io2_read(uint16_t addr) +{ + DBG(("%08lx profidos_io2_read %04x", maincpu_clk, addr)); + enabled = 0; + return 0; +} + +uint8_t profidos_romh_read_hirom(uint16_t addr) +{ + static int lastenabled = -1; + + /* second ROM bank contains 0xfe (D0 active), 0xfd (D1 active) + at the enable address + + e386: fe e387: fd + e5a8: fe e5a9: fd + e5ea: fe e5eb: fd + eb82: fe eb83: fd + eb8f: fe eb90: fd + eb91: fe eb92: fd + eb9f: fe eba0: fd + eba1: fe eba2: fd + f1cb: fe f1cc: fd + f3d5: fe f3d6: fd + f4c4: fe f4c5: fd + f615: fe f616: fd + fcea: fe fceb: fd + fd65: fe fd66: fd + fe73: fe fe74: fd + + */ + + if ((romh_banks[0x2000 + (addr & 0x1fff)] & 1) == 0) { + /* D0 is active -> start the enable counter */ + check_cycles = maincpu_clk; + DBG(("%08lx profidos_romh_read_hirom %04x enabled:%d %02x", + maincpu_clk, addr, enabled, romh_banks[0x2000 + (addr & 0x1fff)])); + } + if ((romh_banks[0x2000 + (addr & 0x1fff)] & 2) == 0) { + /* D1 is active -> enable the ROM */ + if ((maincpu_clk - check_cycles) <= 4) { + enabled = 1; + } + DBG(("%08lx profidos_romh_read_hirom %04x enabled:%d %02x", + maincpu_clk, addr, enabled, romh_banks[0x2000 + (addr & 0x1fff)])); + } + + if (enabled != lastenabled) { + DBG(("%08lx profidos_romh_read_hirom %04x enabled:%d %02x", + maincpu_clk, addr, enabled, romh_banks[0x2000 + (addr & 0x1fff)])); + lastenabled = enabled; + } + + if (enabled) { + return romh_banks[(addr & 0x1fff)]; + } + + return mem_read_without_ultimax(addr); +} + +int profidos_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + return CART_READ_C64MEM; +} + +int profidos_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + return profidos_romh_phi1_read(addr, value); +} + +int profidos_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if (addr >= 0xe000) { + *value = romh_banks[addr & 0x1fff]; + return CART_READ_VALID; + } + return CART_READ_THROUGH; +} + +void profidos_config_init(void) +{ + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +void profidos_reset(void) +{ + enabled = 0; + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +void profidos_config_setup(uint8_t *rawcart) +{ + memcpy(romh_banks, &rawcart[0], 0x4000); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int profidos_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + profidos_io2_list_item = io_source_register(&profidos_io2_device); + + return 0; +} + +int profidos_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return profidos_common_attach(); +} + +int profidos_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + int i, banks = 0; + + for (i = 0; i <= 2; i++) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.bank > 2 || chip.size != 0x2000) { + break; + } + + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + break; + } + ++banks; + } + + if (banks != 2) { + return -1; + } + + return profidos_common_attach(); +} + +void profidos_detach(void) +{ + export_remove(&export_res); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTPROFIDOS snapshot module format: + + type | name | description + -------------------------- + ARRAY | ROMH | $4000 BYTES of ROMH data + */ + +static const char snap_module_name[] = "CARTPROFIDOS"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int profidos_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (SMW_BA(m, romh_banks, 0x4000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int profidos_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (SMR_BA(m, romh_banks, 0x4000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return profidos_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/profidos.h b/src/Emulators/vice/c64/cart/profidos.h new file mode 100644 index 00000000..d711874b --- /dev/null +++ b/src/Emulators/vice/c64/cart/profidos.h @@ -0,0 +1,52 @@ +/* + * profidos.h - Cartridge handling, ProfiDOS cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_PROFIDOS_H +#define VICE_PROFIDOS_H + +#include + +#include "vicetypes.h" +#include "c64cart.h" + +struct snapshot_s; + +uint8_t profidos_romh_read_hirom(uint16_t addr); +int profidos_romh_phi1_read(uint16_t addr, uint8_t *value); +int profidos_romh_phi2_read(uint16_t addr, uint8_t *value); +int profidos_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void profidos_config_init(void); +void profidos_reset(void); +void profidos_config_setup(uint8_t *rawcart); +int profidos_bin_attach(const char *filename, uint8_t *rawcart); +int profidos_crt_attach(FILE *fd, uint8_t *rawcart); +void profidos_detach(void); + +int profidos_snapshot_write_module(struct snapshot_s *s); +int profidos_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/prophet64.c b/src/Emulators/vice/c64/cart/prophet64.c index deb72361..eb58c345 100644 --- a/src/Emulators/vice/c64/cart/prophet64.c +++ b/src/Emulators/vice/c64/cart/prophet64.c @@ -60,9 +60,9 @@ /* ---------------------------------------------------------------------*/ static int currbank = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void p64_io2_store(WORD addr, BYTE value) +static void p64_io2_store(uint16_t addr, uint8_t value) { regval = value; @@ -78,7 +78,7 @@ static void p64_io2_store(WORD addr, BYTE value) cart_romlbank_set_slotmain(value & 0x1f); } -static BYTE p64_io2_peek(WORD addr) +static uint8_t p64_io2_peek(uint16_t addr) { return regval; } @@ -92,18 +92,20 @@ static int p64_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t p64_device = { - CARTRIDGE_NAME_P64, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - p64_io2_store, - NULL, - p64_io2_peek, - p64_dump, - CARTRIDGE_P64, - 0, - 0 + CARTRIDGE_NAME_P64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid, reg is write only */ + p64_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + p64_io2_peek, /* peek function */ + p64_dump, /* device state information dump function */ + CARTRIDGE_P64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *p64_list_item = NULL; @@ -116,14 +118,14 @@ static const export_resource_t export_res = { void p64_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } -void p64_config_setup(BYTE *rawcart) +void p64_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, PROPHET64_CART_SIZE); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } @@ -140,7 +142,7 @@ static int p64_common_attach(void) return 0; } -int p64_bin_attach(const char *filename, BYTE *rawcart) +int p64_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, PROPHET64_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -149,10 +151,10 @@ int p64_bin_attach(const char *filename, BYTE *rawcart) return p64_common_attach(); } -int p64_crt_attach(FILE *fd, BYTE *rawcart) +int p64_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; - int i, cnt = 0; + int i; for (i = 0; i <= 0x1f; i++) { if (crt_read_chip_header(&chip, fd)) { @@ -166,7 +168,6 @@ int p64_crt_attach(FILE *fd, BYTE *rawcart) if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { return -1; } - cnt++; } return p64_common_attach(); @@ -190,7 +191,7 @@ void p64_detach(void) ARRAY | ROML | 0.0+ | 262144 BYTES of ROML data */ -static char snap_module_name[] = "CARTP64"; +static const char snap_module_name[] = "CARTP64"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -205,7 +206,7 @@ int p64_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)currbank) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 || SMW_B(m, regval) < 0 || SMW_BA(m, roml_banks, PROPHET64_CART_SIZE) < 0) { snapshot_module_close(m); @@ -217,7 +218,7 @@ int p64_snapshot_write_module(snapshot_t *s) int p64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -227,13 +228,13 @@ int p64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (0 || SMR_B_INT(m, &currbank) < 0 || SMR_B(m, ®val) < 0) { diff --git a/src/Emulators/vice/c64/cart/prophet64.h b/src/Emulators/vice/c64/cart/prophet64.h index 35060fbf..4de62e6b 100644 --- a/src/Emulators/vice/c64/cart/prophet64.h +++ b/src/Emulators/vice/c64/cart/prophet64.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void p64_config_init(void); -extern void p64_config_setup(BYTE *rawcart); -extern int p64_bin_attach(const char *filename, BYTE *rawcart); -extern int p64_crt_attach(FILE *fd, BYTE *rawcart); -extern void p64_detach(void); +void p64_config_init(void); +void p64_config_setup(uint8_t *rawcart); +int p64_bin_attach(const char *filename, uint8_t *rawcart); +int p64_crt_attach(FILE *fd, uint8_t *rawcart); +void p64_detach(void); struct snapshot_s; -extern int p64_snapshot_write_module(struct snapshot_s *s); -extern int p64_snapshot_read_module(struct snapshot_s *s); +int p64_snapshot_write_module(struct snapshot_s *s); +int p64_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/ramcart.c b/src/Emulators/vice/c64/cart/ramcart.c index e28faf1a..b3df3b27 100644 --- a/src/Emulators/vice/c64/cart/ramcart.c +++ b/src/Emulators/vice/c64/cart/ramcart.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUG_RAMCART */ + #include "vice.h" #include @@ -43,9 +45,9 @@ #include "machine.h" #include "mem.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "vicii-phi1.h" @@ -54,6 +56,12 @@ #include "ramcart.h" #undef CARTRIDGE_INCLUDE_PRIVATE_API +#ifdef DEBUG_RAMCART +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + /* "RamCart" @@ -104,13 +112,13 @@ */ /* RAMCART registers */ -static BYTE ramcart[2]; +static uint8_t ramcart[2]; /* RAMCART image. */ -static BYTE *ramcart_ram = NULL; +static uint8_t *ramcart_ram = NULL; static int old_ramcart_ram_size = 0; -static log_t ramcart_log = LOG_ERR; +static log_t ramcart_log = LOG_DEFAULT; static int ramcart_activate(void); static int ramcart_deactivate(void); @@ -137,41 +145,45 @@ static int ramcart_exrom_active = 0; /* ------------------------------------------------------------------------- */ -static BYTE ramcart_io1_peek(WORD addr); -static BYTE ramcart_io1_read(WORD addr); -static void ramcart_io1_store(WORD addr, BYTE byte); -static BYTE ramcart_io2_read(WORD addr); -static void ramcart_io2_store(WORD addr, BYTE byte); +static uint8_t ramcart_io1_peek(uint16_t addr); +static uint8_t ramcart_io1_read(uint16_t addr); +static void ramcart_io1_store(uint16_t addr, uint8_t byte); +static uint8_t ramcart_io2_read(uint16_t addr); +static void ramcart_io2_store(uint16_t addr, uint8_t byte); static int ramcart_dump(void); static io_source_t ramcart_io1_device = { - CARTRIDGE_NAME_RAMCART, - IO_DETACH_RESOURCE, - "RAMCART", - 0xde00, 0xdeff, 0x01, - 1, /* read is always valid */ - ramcart_io1_store, - ramcart_io1_read, - ramcart_io1_peek, - ramcart_dump, - CARTRIDGE_RAMCART, - 0, - 0 + CARTRIDGE_NAME_RAMCART, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "RAMCART", /* resource to set to '0' */ + 0xde00, 0xdeff, 0x01, /* range for the device, regs:$de00-$de01, mirrors:$de02-$deff */ + 1, /* read is always valid */ + ramcart_io1_store, /* store function */ + NULL, /* NO poke function */ + ramcart_io1_read, /* read function */ + ramcart_io1_peek, /* peek function */ + ramcart_dump, /* device state information dump function */ + CARTRIDGE_RAMCART, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ramcart_io2_device = { - CARTRIDGE_NAME_RAMCART, - IO_DETACH_RESOURCE, - "RAMCART", - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - ramcart_io2_store, - ramcart_io2_read, - ramcart_io2_read, - ramcart_dump, - CARTRIDGE_RAMCART, - 0, - 0 + CARTRIDGE_NAME_RAMCART, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "RAMCART", /* resource to set to '0' */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + ramcart_io2_store, /* store function */ + NULL, /* NO poke function */ + ramcart_io2_read, /* read function */ + ramcart_io2_read, /* peek function */ + ramcart_dump, /* device state information dump function */ + CARTRIDGE_RAMCART, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ramcart_io1_list_item = NULL; @@ -206,14 +218,14 @@ int ramcart_cart_enabled(void) return ramcart_enabled; } -static BYTE ramcart_io1_peek(WORD addr) +static uint8_t ramcart_io1_peek(uint16_t addr) { return ramcart[addr]; } -static BYTE ramcart_io1_read(WORD addr) +static uint8_t ramcart_io1_read(uint16_t addr) { - BYTE retval; + uint8_t retval; if (addr == 1 && ramcart_size_kb == 128) { retval = vicii_read_phi1() & 0x7e; @@ -225,7 +237,7 @@ static BYTE ramcart_io1_read(WORD addr) return retval; } -static void ramcart_io1_store(WORD addr, BYTE byte) +static void ramcart_io1_store(uint16_t addr, uint8_t byte) { if (addr == 1 && ramcart_size_kb == 128) { ramcart[1] = byte & 0x81; @@ -238,16 +250,16 @@ static void ramcart_io1_store(WORD addr, BYTE byte) } } -static BYTE ramcart_io2_read(WORD addr) +static uint8_t ramcart_io2_read(uint16_t addr) { - BYTE retval; + uint8_t retval; retval = ramcart_ram[((ramcart[1] & 1) << 16) + (ramcart[0] * 256) + (addr & 0xff)]; return retval; } -static void ramcart_io2_store(WORD addr, BYTE byte) +static void ramcart_io2_store(uint16_t addr, uint8_t byte) { ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256) + (addr & 0xff)] = byte; } @@ -266,7 +278,7 @@ static int ramcart_dump(void) bank += ramcart[0]; mon_out("RAM size: %s, bank: %d, status: %s\n", - (ramcart_size_kb == 128) ? "128Kb" : "64Kb", + (ramcart_size_kb == 128) ? "128KiB" : "64KiB", bank, (ramcart_readonly) ? ((mirrored) ? "read-only and mirrored at $8000-$80FF" : "read-only") : "read/write"); return 0; @@ -274,6 +286,20 @@ static int ramcart_dump(void) /* ------------------------------------------------------------------------- */ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + static int ramcart_activate(void) { if (!ramcart_size) { @@ -284,12 +310,16 @@ static int ramcart_activate(void) /* Clear newly allocated RAM. */ if (ramcart_size > old_ramcart_ram_size) { - memset(ramcart_ram, 0, (size_t)(ramcart_size - old_ramcart_ram_size)); + /* memset(ramcart_ram, 0, (size_t)(ramcart_size - old_ramcart_ram_size)); */ + ram_init_with_pattern(&ramcart_ram[old_ramcart_ram_size], + (unsigned int)(ramcart_size - old_ramcart_ram_size), &ramparam); + DBG(("ramcart clear offset: %x length: %x total size: %x old size: %x", + old_ramcart_ram_size, ramcart_size - old_ramcart_ram_size, ramcart_size, old_ramcart_ram_size)); } old_ramcart_ram_size = ramcart_size; - log_message(ramcart_log, "%dKB unit installed.", ramcart_size >> 10); + log_message(ramcart_log, "%dKiB unit installed.", ramcart_size >> 10); if (!util_check_null_string(ramcart_filename)) { if (util_file_load(ramcart_filename, ramcart_ram, (size_t)ramcart_size, UTIL_FILE_LOAD_RAW) < 0) { @@ -486,46 +516,30 @@ void ramcart_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-ramcart", SET_RESOURCE, 0, + { "-ramcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCART", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_RAMCART, - NULL, NULL }, - { "+ramcart", SET_RESOURCE, 0, + NULL, "Enable the RamCart expansion" }, + { "+ramcart", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCART", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_RAMCART, - NULL, NULL }, - { "-ramcartsize", SET_RESOURCE, 1, + NULL, "Disable the RamCart expansion" }, + { "-ramcartsize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "RAMCARTsize", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_SIZE_IN_KB, IDCLS_RAMCART_SIZE, - NULL, NULL }, - { "-ramcartimage", SET_RESOURCE, 1, + "", "Size of the RAMCART expansion. (64/128)" }, + { "-ramcartimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "RAMCARTfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_RAMCART_NAME, - NULL, NULL }, - { "-ramcartimagerw", SET_RESOURCE, 0, + "", "Specify name of RAMCART image" }, + { "-ramcartimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCARTImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_RAMCART_IMAGE, - NULL, NULL }, - { "+ramcartimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to RAMCart image" }, + { "+ramcartimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCARTImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_RAMCART_IMAGE, - NULL, NULL }, - { "-ramcartro", SET_RESOURCE, 0, + NULL, "Do not write to RAMCart image" }, + { "-ramcartro", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCART_RO", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RAMCART_READ_ONLY, - NULL, NULL }, - { "-ramcartrw", SET_RESOURCE, 0, + NULL, "Set the RAMCart switch to read-only" }, + { "-ramcartrw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RAMCART_RO", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RAMCART_READ_WRITE, - NULL, NULL }, + NULL, "Set the RAMCart switch to read/write" }, CMDLINE_LIST_END }; @@ -536,12 +550,12 @@ int ramcart_cmdline_options_init(void) /* ------------------------------------------------------------------------- */ -const char *ramcart_get_file_name(void) +const char *ramcart_get_filename_by_type(void) { return ramcart_filename; } -void ramcart_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void ramcart_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) { *base = &ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256)] - 0x8000; @@ -575,7 +589,7 @@ void ramcart_reset(void) ramcart[1] = 0; } -void ramcart_config_setup(BYTE *rawcart) +void ramcart_config_setup(uint8_t *rawcart) { memcpy(ramcart_ram, rawcart, ramcart_size); } @@ -593,7 +607,17 @@ int ramcart_enable(void) return 0; } -int ramcart_bin_attach(const char *filename, BYTE *rawcart) + +int ramcart_disable(void) +{ + if (resources_set_int("RAMCART", 0) < 0) { + return -1; + } + return 0; +} + + +int ramcart_bin_attach(const char *filename, uint8_t *rawcart) { int size = 128; @@ -634,7 +658,7 @@ int ramcart_flush_image(void) /* ------------------------------------------------------------------------- */ -BYTE ramcart_roml_read(WORD addr) +uint8_t ramcart_roml_read(uint16_t addr) { if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) { return ramcart_ram[((ramcart[1] & 1) * 65536) + (ramcart[0] * 256) + (addr & 0xff)]; @@ -642,13 +666,13 @@ BYTE ramcart_roml_read(WORD addr) return mem_ram[addr]; } -void ramcart_roml_store(WORD addr, BYTE byte) +void ramcart_roml_store(uint16_t addr, uint8_t byte) { /* FIXME: this can't be right */ mem_ram[addr] = byte; } -int ramcart_peek_mem(WORD addr, BYTE *value) +int ramcart_peek_mem(uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { if (ramcart_readonly == 1 && ramcart_size_kb == 128 && addr >= 0x8000 && addr <= 0x80ff) { @@ -673,7 +697,7 @@ int ramcart_peek_mem(WORD addr, BYTE *value) ARRAY | RAM | 65536 or 131072 BYTES of RAM data */ -static char snap_module_name[] = "CARTRAMCART"; +static const char snap_module_name[] = "CARTRAMCART"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -688,10 +712,10 @@ int ramcart_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_B(m, (BYTE)ramcart_enabled) < 0) - || (SMW_B(m, (BYTE)ramcart_readonly) < 0) - || (SMW_DW(m, (DWORD)ramcart_size) < 0) - || (SMW_B(m, (BYTE)ramcart_size_kb) < 0) + || (SMW_B(m, (uint8_t)ramcart_enabled) < 0) + || (SMW_B(m, (uint8_t)ramcart_readonly) < 0) + || (SMW_DW(m, (uint32_t)ramcart_size) < 0) + || (SMW_B(m, (uint8_t)ramcart_size_kb) < 0) || (SMW_BA(m, ramcart, 2) < 0) || (SMW_BA(m, ramcart_ram, ramcart_size) < 0)) { snapshot_module_close(m); @@ -703,7 +727,7 @@ int ramcart_snapshot_write_module(snapshot_t *s) int ramcart_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -713,7 +737,7 @@ int ramcart_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/ramcart.h b/src/Emulators/vice/c64/cart/ramcart.h index fd9e9665..3c2eb200 100644 --- a/src/Emulators/vice/c64/cart/ramcart.h +++ b/src/Emulators/vice/c64/cart/ramcart.h @@ -35,30 +35,32 @@ #include "vicetypes.h" -extern void ramcart_init(void); -extern int ramcart_resources_init(void); -extern void ramcart_resources_shutdown(void); -extern int ramcart_cmdline_options_init(void); +void ramcart_init(void); +int ramcart_resources_init(void); +void ramcart_resources_shutdown(void); +int ramcart_cmdline_options_init(void); -extern void ramcart_init_config(void); -extern void ramcart_config_setup(BYTE *rawcart); -extern void ramcart_reset(void); -extern void ramcart_detach(void); -extern int ramcart_enable(void); +void ramcart_init_config(void); +void ramcart_config_setup(uint8_t *rawcart); +void ramcart_reset(void); +void ramcart_detach(void); +int ramcart_enable(void); +int ramcart_disable(void); -extern BYTE ramcart_roml_read(WORD addr); -extern void ramcart_roml_store(WORD addr, BYTE byte); -extern int ramcart_peek_mem(WORD addr, BYTE *value); -extern void ramcart_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +uint8_t ramcart_roml_read(uint16_t addr); +void ramcart_roml_store(uint16_t addr, uint8_t byte); +int ramcart_peek_mem(uint16_t addr, uint8_t *value); +void ramcart_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern int ramcart_cart_enabled(void); -extern const char *ramcart_get_file_name(void); -extern int ramcart_bin_attach(const char *filename, BYTE *rawcart); -extern int ramcart_bin_save(const char *filename); -extern int ramcart_flush_image(void); +int ramcart_cart_enabled(void); +const char *ramcart_get_filename_by_type(void); +int ramcart_bin_attach(const char *filename, uint8_t *rawcart); +int ramcart_bin_save(const char *filename); +int ramcart_flush_image(void); struct snapshot_s; -extern int ramcart_snapshot_read_module(struct snapshot_s *s); -extern int ramcart_snapshot_write_module(struct snapshot_s *s); + +int ramcart_snapshot_read_module(struct snapshot_s *s); +int ramcart_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/ramlink.c b/src/Emulators/vice/c64/cart/ramlink.c new file mode 100644 index 00000000..5e5f709f --- /dev/null +++ b/src/Emulators/vice/c64/cart/ramlink.c @@ -0,0 +1,2243 @@ +/* + * ramlink.c - Cartridge handling, CMD Ramlink + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOT0_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOT0_API +#include "c64cart.h" +#include "c64mem.h" +#include "c64cartmem.h" +#include "c64pla.h" +#include "c64-generic.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "ramlink.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "lib.h" +#include "machine.h" +#include "ram.h" +#include "resources.h" +#include "cmdline.h" +#include "maincpu.h" +#include "log.h" +#include "i8255a.h" +#include "rtc/rtc-72421.h" +#include "drive.h" +#include "maincpu.h" +#include "drive/iec/cmdhd.h" +#include "vicii-phi1.h" + +/* #define RLLOG1 */ +/* #define RLLOG2 */ +/* #define RLDEBUGIO */ +/* #define RLDEBUGMEM */ + +#define LOG LOG_DEFAULT + +#ifdef RLDEBUGMEM +#define MDBG(_x_) log_message _x_ +#else +#define MDBG(_x_) +#endif + +#ifdef RLDEBUGIO +#define IDBG(_x_) log_message _x_ +#else +#define IDBG(_x_) +#endif + +#ifdef RLLOG1 +#define LOG1(_x_) log_message _x_ +#else +#define LOG1(_x_) +#endif + +#ifdef RLLOG2 +#define LOG2(_x_) log_message _x_ +#else +#define LOG2(_x_) +#endif + +#define CRIT(_x_) log_error _x_ + +#if C64CART_ROM_LIMIT <= 65536 +#error C64CART_ROM_LIMIT is too small; it should be at least 65536 +#endif + +/* + +to make crt: + +ramlink v1.40 +cartconv -t rl -i ramlink1.bin -o ramlink1.crt -n "CMD RAMLINK 1.40" + +ramlink v2.01 +cartconv -t rl -i ramlink2.bin -o ramlink2.crt -n "CMD RAMLINK 2.01" + +*/ + +extern unsigned int reg_pc; + +/* #define RAMLINKXL */ + +/* resources */ +static int rl_enabled = 0; +static int rl_write_image = 0; +static int rl_cardsizemb = 0; +static int rl_normal = 1; /* either 1=normal, 0=direct */ +static int rl_rtcsave = 0; +static char *rl_filename = NULL; +static char *rl_bios_filename = NULL; + +#define rl_kernbase64 (2*0x4000) +#define rl_kernbase128 (3*0x4000) + +/* internal stuff */ +static uint8_t rl_on = 0; +static uint8_t rl_dos = 0; +static uint8_t rl_mapped = 0; +static uint32_t rl_rombase = 0; +static uint32_t rl_kernbase = 0; +static uint32_t rl_rambase = 0; +static uint32_t rl_cardbase = 0; +static uint32_t rl_cardaddr = 0; +static uint32_t rl_io1mode = 7; /* initially unused mode */ +static rtc_72421_t *rl_rtc = NULL; +static i8255a_state rl_i8255a; +static uint8_t rl_i8255a_i[3]; +static uint8_t rl_i8255a_o[3]; +static uint8_t *rl_card = NULL; +static uint32_t rl_cardsize = 0; +static uint32_t rl_cardsize_old = 0; +static uint32_t rl_scanned = 0; +static uint32_t rl_reu_trap = 0; +static uint8_t *rl_ram = NULL; +static uint8_t *rl_rom = NULL; +static int rl_extexrom = 0; +static int rl_extgame = 0; +static int8_t rl_memmap[256]; + +/* some prototypes are needed */ +static uint8_t ramlink_io1_read(uint16_t addr); +static uint8_t ramlink_io1_peek(uint16_t addr); +static void ramlink_io1_store(uint16_t addr, uint8_t value); +static int ramlink_io1_dump(void); +static uint8_t ramlink_io2_peek(uint16_t addr); +static uint8_t ramlink_io2_40_43_read(uint16_t addr); +static uint8_t ramlink_io2_b0_bf_read(uint16_t addr); +static void ramlink_io2_20_22_store(uint16_t addr, uint8_t value); +static void ramlink_io2_40_43_store(uint16_t addr, uint8_t value); +static void ramlink_io2_60_60_store(uint16_t addr, uint8_t value); +static void ramlink_io2_70_70_store(uint16_t addr, uint8_t value); +static void ramlink_io2_7e_7f_store(uint16_t addr, uint8_t value); +static void ramlink_io2_80_9f_store(uint16_t addr, uint8_t value); +static void ramlink_io2_a0_a3_store(uint16_t addr, uint8_t value); +static void ramlink_io2_b0_bf_store(uint16_t addr, uint8_t value); +static void ramlink_io2_c0_c3_store(uint16_t addr, uint8_t value); +static int ramlink_io2_dump(void); + +static io_source_t ramlink_io1_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + ramlink_io1_store, /* store function */ + NULL, /* NO poke function */ + ramlink_io1_read, /* read function */ + ramlink_io1_peek, /* peek function */ + ramlink_io1_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_20_22_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf20, 0xdf22, 0xff, /* range for the device, regs:$df20-$df22 */ + 1, /* read is always valid */ + ramlink_io2_20_22_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_40_43_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf40, 0xdf43, 0xff, /* range for the device, regs:$df40-$df43 */ + 1, /* read is always valid */ + ramlink_io2_40_43_store, /* store function */ + NULL, /* NO poke function */ + ramlink_io2_40_43_read, /* read function */ + ramlink_io2_peek, /* peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_60_60_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf60, 0xdf60, 0xff, /* range for the device, regs:$df60-$df60 */ + 1, /* read is always valid */ + ramlink_io2_60_60_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_70_70_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf70, 0xdf70, 0xff, /* range for the device, regs:$df70-$df70 */ + 1, /* read is always valid */ + ramlink_io2_70_70_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_7e_7f_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf7e, 0xdf7f, 0xff, /* range for the device, regs:$df7e-$df7f */ + 1, /* read is always valid */ + ramlink_io2_7e_7f_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_80_9f_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf80, 0xdf9f, 0xff, /* range for the device, regs:$df80-$df9f */ + 1, /* read is always valid */ + ramlink_io2_80_9f_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_a0_a3_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdfa0, 0xdfa3, 0xff, /* range for the device, regs:$dfa0-$dfa3 */ + 1, /* read is always valid */ + ramlink_io2_a0_a3_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_b0_bf_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdfb0, 0xdfbf, 0xff, /* range for the device, regs:$dfb0-$dfbf */ + 1, /* read is always valid */ + ramlink_io2_b0_bf_store, /* store function */ + NULL, /* NO poke function */ + ramlink_io2_b0_bf_read, /* read function */ + ramlink_io2_peek, /* peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t ramlink_io2_c0_c3_device = { + CARTRIDGE_NAME_RAMLINK, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdfc0, 0xdfc3, 0xff, /* range for the device, regs:$dfc0-$dfc3 */ + 1, /* read is always valid */ + ramlink_io2_c0_c3_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* NO peek function */ + ramlink_io2_dump, /* device state information dump function */ + CARTRIDGE_RAMLINK, /* cartridge ID */ + IO_PRIO_HIGH, /* high priority, device reads first */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +#define RAMLINKIOS 10 + +static io_source_list_t *ramlink_list_items[RAMLINKIOS] = { NULL }; + +static io_source_t *ramlink_source_items[RAMLINKIOS] = { + &ramlink_io2_7e_7f_device, /* the order of the first two */ + &ramlink_io1_device, /* are important */ + &ramlink_io2_20_22_device, + &ramlink_io2_40_43_device, + &ramlink_io2_60_60_device, + &ramlink_io2_70_70_device, + &ramlink_io2_80_9f_device, + &ramlink_io2_a0_a3_device, + &ramlink_io2_b0_bf_device, + &ramlink_io2_c0_c3_device +}; + +static uint8_t (*ramlink_source_read_items[RAMLINKIOS])(uint16_t address) = { + NULL, /* the order of the first two */ + ramlink_io1_read, /* are important */ + NULL, + ramlink_io2_40_43_read, + NULL, + NULL, + NULL, + NULL, + ramlink_io2_b0_bf_read, + NULL +}; + +static void (*ramlink_source_store_items[RAMLINKIOS])(uint16_t address, uint8_t data) = { + ramlink_io2_7e_7f_store, /* the order of the first two */ + ramlink_io1_store, /* are important */ + ramlink_io2_20_22_store, + ramlink_io2_40_43_store, + ramlink_io2_60_60_store, + ramlink_io2_70_70_store, + ramlink_io2_80_9f_store, + ramlink_io2_a0_a3_store, + ramlink_io2_b0_bf_store, + ramlink_io2_c0_c3_store +}; + +static const export_resource_t export_res_plus[RAMLINKIOS] = { + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_7e_7f_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, &ramlink_io1_device, NULL, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_20_22_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_40_43_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_60_60_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_70_70_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_80_9f_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_a0_a3_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_b0_bf_device, CARTRIDGE_RAMLINK}, + {CARTRIDGE_NAME_RAMLINK, 1, 1, NULL, &ramlink_io2_c0_c3_device, CARTRIDGE_RAMLINK} +}; + +#define RAMLINKOTHERIOS 20 + +static int ramlink_devices_io1_count; +static int ramlink_devices_io1_georam; +static int ramlink_devices_io2_count; +static int ramlink_devices_io2_reu; +static int ramlink_devices_io2_georam; +static io_source_t ramlink_devices_io1_entry[RAMLINKOTHERIOS]; +static io_source_t *ramlink_devices_io1[RAMLINKOTHERIOS]; +static io_source_t ramlink_devices_io2_entry[RAMLINKOTHERIOS]; +static io_source_t *ramlink_devices_io2[RAMLINKOTHERIOS]; + +static void ramlink_scan_io(void) +{ + io_source_list_t *current; + + ramlink_devices_io1_georam = -1; + ramlink_devices_io2_reu = -1; + ramlink_devices_io2_georam = -1; + + /* find top of list for io1 */ + current = ramlink_list_items[1]->previous; + while (current->previous) { + current = current->previous; + } + + /* go down list copying pointers and data from all devices */ + ramlink_devices_io1_count = 0; + while (current) { + if (current->device) { + if (current->device->cart_id != CARTRIDGE_RAMLINK) { + LOG2((LOG, "RAMLINK: Scanning IO1 %s", current->device->name)); + ramlink_devices_io1[ramlink_devices_io1_count] = current->device; + memcpy(&(ramlink_devices_io1_entry[ramlink_devices_io1_count]), + current->device, sizeof(io_source_t)); + /* remember which is georam */ + if (current->device->cart_id == CARTRIDGE_GEORAM) { + ramlink_devices_io1_georam = ramlink_devices_io1_count; + LOG1((LOG, "RAMLINK: Found GEORAM IO1")); + } + ramlink_devices_io1_count++; + } + } + current = current->next; + } + + /* find top of list for io2 */ + current = ramlink_list_items[0]->previous; + while (current->previous) { + current = current->previous; + } + + /* go down list copying pointers and data from all devices */ + ramlink_devices_io2_count = 0; + while (current) { + if (current->device) { + if (current->device->cart_id != CARTRIDGE_RAMLINK) { + LOG2((LOG, "RAMLINK: Scanning IO2 %s", current->device->name)); + ramlink_devices_io2[ramlink_devices_io2_count] = current->device; + memcpy(&(ramlink_devices_io2_entry[ramlink_devices_io2_count]), + current->device, sizeof(io_source_t)); + /* remember which is georam */ + if (current->device->cart_id == CARTRIDGE_GEORAM) { + ramlink_devices_io2_georam = ramlink_devices_io2_count; + current->device->io_source_prio = IO_PRIO_LOW; + LOG1((LOG, "RAMLINK: Found GEORAM IO2")); + } + /* remember which is reu */ + if (current->device->cart_id == CARTRIDGE_REU) { + ramlink_devices_io2_reu = ramlink_devices_io2_count; + current->device->io_source_prio = IO_PRIO_LOW; + /* need to change end of IO for REU or else GEORAM may not + work depending on switch order */ + current->device->end_address = 0xdf7f; + LOG1((LOG, "RAMLINK: Found REU IO2")); + } + ramlink_devices_io2_count++; + } + } + current = current->next; + } + rl_scanned = 1; +} + +/* restore any modified IO resourcs back to their original values */ +static void ramlink_restore_io(void) +{ + int i; + + for (i = 0; i < ramlink_devices_io1_count; i++) { + memcpy(ramlink_devices_io1[i], &(ramlink_devices_io1_entry[i]), + sizeof(io_source_t)); + } + ramlink_devices_io1_count = 0; + for (i = 0; i < ramlink_devices_io2_count; i++) { + memcpy(ramlink_devices_io2[i], &(ramlink_devices_io2_entry[i]), + sizeof(io_source_t)); + } + ramlink_devices_io2_count = 0; + ramlink_devices_io1_georam = -1; + ramlink_devices_io2_reu = -1; + ramlink_devices_io2_georam = -1; +} + +/* turn off any other IO1 resources */ +static void ramlink_other1_off(void) +{ + int i; + + for (i = 0; i < ramlink_devices_io1_count; i++) { + /* skip georam */ + if (i == ramlink_devices_io1_georam) continue; + LOG2((LOG, "RAMLINK: OFF IO1 %s", ramlink_devices_io1[i]->name)); + ramlink_devices_io1[i]->read = NULL; + ramlink_devices_io1[i]->store = NULL; + } +} + +/* turn on any other IO1 resources */ +static void ramlink_other1_on(void) +{ + int i; + + for (i = 0; i < ramlink_devices_io1_count; i++) { + /* skip georam */ + if (i == ramlink_devices_io1_georam) continue; + LOG2((LOG, "RAMLINK: ON IO1 %s", ramlink_devices_io1[i]->name)); + ramlink_devices_io1[i]->read = ramlink_devices_io1_entry[i].read; + ramlink_devices_io1[i]->store = ramlink_devices_io1_entry[i].store; + } +} + +/* turn off REU by removing read/store pointers */ +static void ramlink_reu_off(void) +{ + if (ramlink_devices_io2_reu >= 0) { + ramlink_devices_io2[ramlink_devices_io2_reu]->read = NULL; + ramlink_devices_io2[ramlink_devices_io2_reu]->store = NULL; + IDBG((LOG, "RAMLINK: REU off")); + } +} + +/* turn on REU by restoring read/store pointers */ +static void ramlink_reu_on(void) +{ + if (ramlink_devices_io2_reu >= 0) { + ramlink_devices_io2[ramlink_devices_io2_reu]->read = + ramlink_devices_io2_entry[ramlink_devices_io2_reu].read; + ramlink_devices_io2[ramlink_devices_io2_reu]->store = + ramlink_devices_io2_entry[ramlink_devices_io2_reu].store; + IDBG((LOG, "RAMLINK: REU on")); + } +} + +/* turn off GEORAM IO1 by removing read/store pointers */ +static void ramlink_georam1_off(void) +{ + if (ramlink_devices_io1_georam >= 0) { + ramlink_devices_io1[ramlink_devices_io1_georam]->read = NULL; + ramlink_devices_io1[ramlink_devices_io1_georam]->store = NULL; + IDBG((LOG, "RAMLINK: GEORAM1 off")); + } +} + +/* turn off GEORAM IO2 by removing read/store pointers */ +static void ramlink_georam2_off(void) +{ + if (ramlink_devices_io2_georam >= 0) { + ramlink_devices_io2[ramlink_devices_io2_georam]->read = NULL; + ramlink_devices_io2[ramlink_devices_io2_georam]->store = NULL; + IDBG((LOG, "RAMLINK: GEORAM2 off")); + } +} + +/* turn on GEORAM IO1 by restoring read/store pointers */ +static void ramlink_georam1_on(void) +{ + if (ramlink_devices_io1_georam >= 0) { + ramlink_devices_io1[ramlink_devices_io1_georam]->read = + ramlink_devices_io1_entry[ramlink_devices_io1_georam].read; + ramlink_devices_io1[ramlink_devices_io1_georam]->store = + ramlink_devices_io1_entry[ramlink_devices_io1_georam].store; + IDBG((LOG, "RAMLINK: GEORAM2 on")); + } +} + +/* turn on GEORAM IO2 by restoring read/store pointers */ +static void ramlink_georam2_on(void) +{ + if (ramlink_devices_io2_georam >= 0) { + ramlink_devices_io2[ramlink_devices_io2_georam]->read = + ramlink_devices_io2_entry[ramlink_devices_io2_georam].read; + ramlink_devices_io2[ramlink_devices_io2_georam]->store = + ramlink_devices_io2_entry[ramlink_devices_io2_georam].store; + IDBG((LOG, "RAMLINK: GEORAM2 on")); + } +} + +/* turn off anything in RAMPORT */ +static void ramlink_ramport_off(void) +{ + ramlink_georam1_off(); +} + +/* turn on anything in RAMPORT */ +static void ramlink_ramport_on(void) +{ + ramlink_georam1_on(); +} + +/* turn off RL IO1 */ +static void ramlink_io1_off(void) +{ + ramlink_source_items[1]->read = NULL; + ramlink_source_items[1]->store = NULL; +} + +/* turn on RL IO1 */ +static void ramlink_io1_on(void) +{ + ramlink_source_items[1]->read = ramlink_source_read_items[1]; + ramlink_source_items[1]->store = ramlink_source_store_items[1]; +} + +/* turn off RL IO2 except $DF7E-$DF7F */ +static void ramlink_io2_off(void) +{ + int i; + + for (i=2;iread = NULL; + ramlink_source_items[i]->store = NULL; + } +} + +/* turn on RL IO2 */ +static void ramlink_io2_on(void) +{ + int i; + + for (i=2;iread = ramlink_source_read_items[i]; + ramlink_source_items[i]->store = ramlink_source_store_items[i]; + } +} + +/* Turn off RL except $DF7E-$DF7F */ +static void ramlink_off(void) +{ + ramlink_io1_off(); + ramlink_io2_off(); + if (rl_normal) { + ramlink_ramport_off(); + ramlink_reu_off(); + ramlink_georam2_off(); + } else { + ramlink_ramport_on(); + ramlink_reu_on(); + ramlink_georam2_on(); + } + ramlink_other1_on(); + rl_on = 0; + rl_dos = 0; + rl_reu_trap = 0; + cart_port_config_changed_slot0(); +} + +/* Turn on or off devices based on port access settings */ +static void ramlink_update_io1mode(void) +{ + if (rl_io1mode == 0) { /* internal RAM */ + ramlink_other1_off(); + ramlink_ramport_off(); + ramlink_io1_on(); + } else if ((rl_io1mode == 1) && (rl_cardsizemb != 0) && rl_card && + rl_enabled) { /* RAMCard */ + ramlink_other1_off(); + ramlink_ramport_off(); + ramlink_io1_on(); + } else if (rl_io1mode == 2) { /* GEORAM or RAMDRIVE */ + ramlink_other1_off(); + ramlink_io1_off(); + ramlink_ramport_on(); + } else { /* PASSTHRU */ + ramlink_ramport_off(); + ramlink_io1_off(); + ramlink_other1_on(); + } +} + +/* Turn on RL */ +static void ramlink_on(void) +{ + ramlink_io2_on(); + ramlink_reu_on(); + ramlink_georam2_on(); + ramlink_update_io1mode(); + rl_on = 1; + cart_port_config_changed_slot0(); +} + +/* ---------------------------------------------------------------------*/ +static int ramlink_registerio(void) +{ + int i; + + LOG2((LOG, "RAMLINK: registerio")); + + /* register anything that hasn't been registered */ + for (i = 0; i < RAMLINKIOS ; i++ ) { + if (!ramlink_list_items[i]) { + if (export_add(&export_res_plus[i]) < 0) { + return -1; + } + ramlink_list_items[i] = io_source_register(ramlink_source_items[i]); + } + } + + return 0; +} + +static void ramlink_unregisterio(void) +{ + int i; + + LOG2((LOG, "RAMLINK: unregisterio")); + + /* unregister anything that has been registered */ + for (i = 0; i < RAMLINKIOS ; i++ ) { + if (ramlink_list_items[i]) { + export_remove(&export_res_plus[i]); + io_source_unregister(ramlink_list_items[i]); + ramlink_list_items[i] = NULL; + } + } +} + +int ramlink_ram_save(const char *filename) +{ + if (rl_card == NULL) { + return -1; + } + + if (filename == NULL) { + return -1; + } + + if (!util_check_null_string(filename)) { + LOG1((LOG, "RAMLINK: Writing RAMLINK memory image %s.", filename)); + if (util_file_save(filename, rl_card, rl_cardsize) < 0) { + CRIT((LOG, "RAMLINK: Writing RAMLINK memory image %s failed.", + filename)); + return -1; + } + } + + return 0; +} + +int ramlink_can_save_ram_image(void) +{ + if (rl_filename == NULL) { + return 0; + } + return 1; +} + +int ramlink_flush_ram_image(void) +{ + if (ramlink_ram_save(rl_filename) < 0) { + return -1; + } + return 0; +} + +int ramlink_can_flush_ram_image(void) +{ + if (rl_filename == NULL) { + return 0; + } + return 1; +} + +/* save RAMCard image file if set to by resource */ +static int ramlink_save_ram_image(void) +{ + if (rl_write_image) { + return ramlink_flush_ram_image(); + } + + return 0; +} + +/* load RAMLINK RAM image file */ +static int ramlink_load_ram_image(void) +{ + if (rl_card == NULL) { + return -1; + } + + if (rl_filename == NULL) { + return -1; + } + + if (!util_check_null_string(rl_filename)) { + if (util_file_load(rl_filename, rl_card, (size_t)rl_cardsize, + UTIL_FILE_LOAD_RAW) < 0) { + CRIT((LOG, "RAMLINK: Reading RAMLINK memory image %s failed.", + rl_filename)); + /* only create a new file if no file exists, so we dont accidently + overwrite any files */ + if (!util_file_exists(rl_filename)) { + if (util_file_save(rl_filename, rl_card, rl_cardsize) < 0) { + CRIT((LOG, "RAMLINK: Creating RAMLINK memory image %s failed.", + rl_filename)); + return -1; + } + LOG1((LOG, "RAMLINK: Creating RAMLINK memory image %s.", rl_filename)); + } + return 0; + } + LOG1((LOG, "RAMLINK: Reading RAMLINK memory image %s.", rl_filename)); + } + + return 0; +} + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +static int ramlink_activate(void) +{ + i8255a_reset(&rl_i8255a); + + if (!rl_rtc) { + rl_rtc = rtc72421_init("RAMLINKRTC"); + } + + if (!rl_cardsize) { + rl_card = NULL; + return 0; + } + + rl_card = lib_realloc(rl_card, rl_cardsize); + + /* Clear newly allocated RAM. */ + if (rl_cardsize > rl_cardsize_old) { + /* memset(rl_card, 0, (size_t)(rl_cardsize - rl_cardsize_old)); */ + ram_init_with_pattern(&rl_card[rl_cardsize_old], + (unsigned int)(rl_cardsize - rl_cardsize_old), &ramparam); + } + + rl_cardsize_old = rl_cardsize; + + LOG1((LOG, "RAMLINK: %dMiB unit installed.", rl_cardsizemb)); + + return ramlink_load_ram_image(); +} + +static int ramlink_deactivate(void) +{ + int res = 0; + + if (rl_rtc) { + rtc72421_destroy(rl_rtc, rl_rtcsave); + rl_rtc = NULL; + } + + if (rl_card == NULL) { + return 0; + } + + res = ramlink_save_ram_image(); + + lib_free(rl_card); + rl_card = NULL; + + return res; +} + +static int set_enabled(int value, void *param) +{ + int val = value ? 1 : 0; + + LOG2((LOG, "RAMLINK: set_enabled %d", val)); + + if ((!val) && (rl_enabled)) { + cart_power_off(); + if (ramlink_deactivate() < 0) { + return -1; + } + ramlink_restore_io(); + ramlink_unregisterio(); + rl_enabled = 0; + cart_port_config_changed_slot0(); + } else if ((val) && (!rl_enabled)) { + /* activate ramlink */ + if (param) { + /* if the param is != NULL, then we should load the default image file */ + LOG1((LOG, "RAMLINK: set_enabled(1) '%s'", rl_bios_filename)); + if ((rl_bios_filename != NULL) && (*rl_bios_filename != 0)) { + /* try .crt image first */ + if ((cartridge_attach_image(CARTRIDGE_CRT, rl_bios_filename) < 0) && + (cartridge_attach_image(CARTRIDGE_RAMLINK, rl_bios_filename) < 0)) { + LOG1((LOG, "RAMLINK: set_enabled(1) did not register")); + return -1; /* loading the default was requested, file coult not be loaded */ + } + /* rl_enabled = 1; */ /* cartridge_attach_image will end up calling set_enabled again */ + return 0; + } else { + return -1; /* loading the default was requested, but no filename was set */ + } + } else { + cart_power_off(); + if (ramlink_activate() < 0) { + return -1; + } + ramlink_registerio(); + rl_enabled = 1; + rl_scanned = 0; + cart_port_config_changed_slot0(); + } + } + return 0; +} + +static int set_size(int size, void *param) +{ + int i; + + if (size < 0 || size > 64) { + return -1; + } + if (size != 1 && size != 2 && size != 3 && size != 4 && + size != 5 && size != 8 && size != 9 && size != 12 && + size != 13 && size != 16 && +#ifdef RAMLINKXL + size != 20 && size != 32 && + size != 36 && size != 48 && size != 52 && size != 64 && + size != 17 && size != 33 && size != 49 && +#endif + size != 0) { + return -1; + } + + if (rl_enabled) { + ramlink_deactivate(); + } + + rl_cardsizemb = size; + rl_cardsize = rl_cardsizemb << 20; + + /* setup a full map */ + for (i = 0; i < 64 ; i++) { + rl_memmap[i] = i; + } + + if (rl_cardsizemb <= 4) { + /* anything beyond size specified will be open */ + for (i = rl_cardsizemb; i < 4 ; i++) { + rl_memmap[i] = -1; + } + /* mirror to full 64MB range */ + for (i = 4; i < 64 ; i++) { + rl_memmap[i] = rl_memmap[ i & 3 ]; + } + } else if (rl_cardsizemb <= 16) { + /* assume remaining slots are open */ + for (i = rl_cardsizemb; i < 16 ; i++) { + rl_memmap[i] = -1; + } + /* for those that have an additional 1MB SIMM */ + if (rl_cardsizemb & 3) { + /* 5-7, 9-11, 13-15: show previous 1MB slot */ + for (i = rl_cardsizemb; i < ((rl_cardsizemb / 4) + 1) * 4 ; i++) { + rl_memmap[i] = rl_cardsizemb - 1; + } + } + /* mirror to full 64MB range */ + for (i = 16; i < 64 ; i++) { + rl_memmap[i] = rl_memmap[ i & 15 ]; + } + } else { + /* assume remaining slots are open */ + for (i = rl_cardsizemb; i < 64 ; i++) { + rl_memmap[i] = -1; + } + if ((rl_cardsizemb & 7) == 1) { + /* for those that have an additional 1MB SIMM */ + /* 18-31, 34-47, 50-63: show previous 1MB slot */ + for (i = rl_cardsizemb; i < ((rl_cardsizemb / 16) + 1) * 16 ; i++) { + rl_memmap[i] = rl_cardsizemb - 1; + } + } else if ((rl_cardsizemb & 7) == 4) { + /* for those that have an additional 4MB SIMM */ + /* 20-31, 36-47, 52-63: show previous 4MB slot */ + for (i = rl_cardsizemb; i < ((rl_cardsizemb / 16) + 1) * 16 ; i++) { + rl_memmap[i] = rl_cardsizemb - 4 + ( i & 3); + } + } + + } + +#if 0 + printf("* RL_MEMMAP:\n"); + for(i=0;i<64;i++) { + printf("%02x ",(unsigned int)rl_memmap[i]); + if (!((i+1)%16)) printf("\n"); + } +#endif + + if (rl_enabled) { + ramlink_activate(); + } + + LOG1((LOG, "RAMLINK: size = %d MiB", size)); + + return 0; +} + +static int set_mode(int value, void *param) +{ + if (value) { + rl_normal = RL_MODE_NORMAL; + } else { + rl_normal = RL_MODE_DIRECT; /* direct mode */ + } + + LOG1((LOG, "RAMLINK: mode = %s", rl_normal ? "Normal" : "Direct" )); + + return 0; +} + +static int set_rtcsave(int val, void *param) +{ + rl_rtcsave = val ? 1 : 0; + + return 0; +} + +static int set_image_write(int val, void *param) +{ + rl_write_image = val ? 1 : 0; + + return 0; +} + +static int set_bios_filename(const char *name, void *param) +{ + int enabled; + + if (name != NULL && *name != '\0') { + if (util_check_filename_access(name) < 0) { + return -1; + } + } + LOG1((LOG, "RAMLINK: set_bios_filename: %d '%s'", rl_enabled, rl_bios_filename)); + + util_string_set(&rl_bios_filename, name); + resources_get_int("RAMLINK", &enabled); + + /* if we are enabled, this will reload the BIOS */ + if (set_enabled(enabled, (void*)1) < 0) { + lib_free(rl_bios_filename); + rl_bios_filename = NULL; + LOG1((LOG, "RAMLINK: set_bios_filename done: %d 'NULL'", rl_enabled)); + return -1; + } + LOG1((LOG, "RAMLINK: set_bios_filename done: %d '%s'", rl_enabled, rl_bios_filename)); + + return 0; +} + +static int set_filename(const char *name, void *param) +{ + if (rl_filename != NULL && name != NULL && strcmp(name, rl_filename) == 0) { + return 0; + } + + if (name != NULL && *name != '\0') { + if (util_check_filename_access(name) < 0) { + return -1; + } + } + + if (rl_enabled) { + ramlink_deactivate(); + } + util_string_set(&rl_filename, name); + + if (rl_enabled) { + ramlink_activate(); + } + + LOG1((LOG, "RAMLINK: filename = '%s'", name)); + + return 0; +} + +static const resource_string_t resources_string[] = { + { "RAMLINKBIOSfilename", "", RES_EVENT_NO, NULL, + &rl_bios_filename, set_bios_filename, NULL }, + { "RAMLINKfilename", "", RES_EVENT_NO, NULL, + &rl_filename, set_filename, NULL }, + RESOURCE_STRING_LIST_END +}; + +static const resource_int_t resources_int[] = { + { "RAMLINKImageWrite", 0, RES_EVENT_NO, NULL, + &rl_write_image, set_image_write, NULL }, + { "RAMLINKsize", 16, RES_EVENT_NO, NULL, + &rl_cardsizemb, set_size, 0 }, + { "RAMLINKmode", RL_MODE_NORMAL, RES_EVENT_NO, NULL, + &rl_normal, set_mode, 0 }, + { "RAMLINKRTCSave", 0, RES_EVENT_NO, NULL, + &rl_rtcsave, set_rtcsave, 0 }, + /* keeping "enable" resource last prevents unnecessary (re)init when loading config file */ + { "RAMLINK", 0, RES_EVENT_STRICT, (resource_value_t)0, + &rl_enabled, set_enabled, (void *)1 }, + RESOURCE_INT_LIST_END +}; + +static const cmdline_option_t cmdline_options[] = +{ + { "-ramlink", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINK", (resource_value_t)1, + NULL, "Enable the " CARTRIDGE_NAME_RAMLINK " Unit" }, + { "+ramlink", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINK", (resource_value_t)0, + NULL, "Disable the " CARTRIDGE_NAME_RAMLINK " Unit" }, + { "-ramlinkbios", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RAMLINKBIOSfilename", NULL, + "", "Specify name of " CARTRIDGE_NAME_RAMLINK " BIOS image" }, + { "-ramlinkmode", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RAMLINKmode", NULL, + "", "RAMPort Mode (1=Normal, 0=Direct)" }, + { "-ramlinkrtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINKrtcsave", (resource_value_t)1, + NULL, "Enable saving of the RTC data when changed." }, + { "+ramlinkrtcsave", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINKrtcsave", (resource_value_t)0, + NULL, "Disable saving of the RTC data when changed." }, + { "-ramlinksize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RAMLINKsize", NULL, + "", CARTRIDGE_NAME_RAMLINK " RAMCARD size in MiB (0=Disabled)" }, + { "-ramlinkimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RAMLINKfilename", NULL, + "", "Specify name of " CARTRIDGE_NAME_RAMLINK " image" }, + { "-ramlinkimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINKImageWrite", (resource_value_t)1, + NULL, "Allow writing to " CARTRIDGE_NAME_RAMLINK " image" }, + { "+ramlinkimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RAMLINKImageWrite", (resource_value_t)0, + NULL, "Do not write to " CARTRIDGE_NAME_RAMLINK " image" }, + CMDLINE_LIST_END +}; + +int ramlink_cmdline_options_init(void) +{ + if (cmdline_register_options(cmdline_options) < 0) { + return -1; + } + + return 0; +} + +int ramlink_resources_init(void) +{ + LOG2((LOG, "RAMLINK: resource init")); + + rl_filename = NULL; + + if (resources_register_string(resources_string) < 0) { + return -1; + } + if (resources_register_int(resources_int) < 0) { + return -1; + } + + if (!rl_ram) { + rl_ram = lib_malloc(0x2000); + } + + if (!rl_rom) { + rl_rom = lib_malloc(0x10000); + } + + return 0; +} + +int ramlink_resources_shutdown(void) +{ + LOG2((LOG, "RAMLINK: resource shutdown")); + + if (rl_filename) { + lib_free(rl_filename); + rl_filename = NULL; + } + + if (rl_bios_filename) { + lib_free(rl_bios_filename); + rl_bios_filename = NULL; + } + + if (rl_card) { + lib_free(rl_card); + } + + if (rl_ram) { + lib_free(rl_ram); + rl_ram = NULL; + } + + if (rl_rom) { + lib_free(rl_rom); + rl_rom = NULL; + } + + return 0; +} + +const char *ramlink_get_ram_file_name(void) +{ + return rl_filename; +} + +int ramlink_cart_enabled(void) +{ + return rl_enabled; +} + +/* ---------------------------------------------------------------------*/ + +/* Makes sure all drive cpus are synced up with main CPU */ +/* The timing for the parallel transfers are pretty tight */ +static void ramlink_sync_cpus(void) { + if (maincpu_clk) { + drive_cpu_execute_all(maincpu_clk); + } +} + +/* i8255a interfacing */ +/* This is mostly for the parallel port */ +/* Port A is for CMD Parallel bus, input/output, data only */ +static void set_pa(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ +#ifdef RLLOG2 + static uint32_t calls=0; + + calls++; + if (!(calls & 0xffff)) { + LOG2((LOG,"RAMLINK: Total parallel writes = %u",calls)); + } +#endif + ramlink_sync_cpus(); + cmdbus.cpu_data = byte; + cmdbus_update(); +} + +static uint8_t get_pa(struct _i8255a_state *ctx, int8_t reg) +{ + uint8_t data; +#ifdef RLLOG2 + static uint32_t calls=0; + + calls++; + if (!(calls & 0xffff)) { + LOG2((LOG,"RAMLINK: Total parallel reads = %u",calls)); + } +#endif + ramlink_sync_cpus(); + if (reg == 0) { + /* if reg is 0, it is an actual read from the register */ + data = cmdbus.data; + } else { + /* otherwise it is a bus change; physically it is pulled up */ + data = 0xff; + } + + return data; +} + +/* Port B is for CMD Parallel bus (output only): + PB7 is /PREADY + PB6 is /PCLK + PB5 is /PATN + PB4 is ACTIVE LED (1=on) + PB3 is ERROR LED (1=on) + PB2 is SWAP9 button control + PB1 is SWAP8 button control + PB0 is system mode (1=128, 0=64) +*/ +static void set_pb(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ + int new, old; + + ramlink_sync_cpus(); + + /* see if bit 0 toggles */ + if ((rl_i8255a_o[1] ^ byte) & 0x01) { + /* use older value to avoid inversion */ + c128ramlink_switch_mode(rl_i8255a_o[1] & 0x01); + } + + /* check for patn change */ + old = rl_i8255a_o[1] & 0x20 ? 0 : 1; + new = byte & 0x20 ? 0 : 1; + + rl_i8255a_o[1] = byte; + cmdbus.cpu_bus = ( rl_i8255a_o[1] & 0xe0 ) | 0x1f; + cmdbus_patn_changed(new, old); + + cmdbus_update(); +} + +static uint8_t get_pb(struct _i8255a_state *ctx, int8_t reg) +{ + uint8_t data = 0xff; + + data = rl_i8255a_i[1]; + + return data; +} + +/* Port C is for CMD Parallel bus, and ROM addressing: + PC7 is PREADY (input) + PC6 is PCLK (input) + PC5 is SWAP9 control (input) + PC4 is SWAP8 control (input) + PC3 is ??? (output) + PC2 is ROM Bank (A2) (output) - not used + PC1 is ROM Bank (A1) (output) + PC0 is ROM Bank (A0) (output) +*/ +static void set_pc(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ + rl_i8255a_o[2] = byte; + + rl_rombase = ( rl_i8255a_o[2] & 3 ) * 0x4000; + cart_port_config_changed_slot0(); +} + +/* FIXME: SWAP8 and SWAP9 are ignored for now */ +static uint8_t get_pc(struct _i8255a_state *ctx, int8_t reg) +{ + uint8_t data = 0xff; + + ramlink_sync_cpus(); + data = ((cmdbus.bus ^ 0xff) & 0xc0) | (rl_i8255a_i[2] & 0x3f); + return data; +} + +static uint8_t ramlink_io1_read(uint16_t addr) +{ + uint8_t val = 0; + + if (rl_io1mode == 0) { + val = rl_ram[rl_rambase | (addr & 0xff)]; + IDBG((LOG, "RAMLINK: io1 r ram[%04x] = %02x at 0x%04x", rl_rambase | + (addr & 0xff), val, reg_pc)); + return val; + } else if (rl_io1mode == 1) { + if (rl_cardbase != -1) { + val = rl_card[rl_cardbase | (addr & 0xff)]; + IDBG((LOG, "RAMLINK: io1 r card[%06x] = %02x at 0x%04x", rl_cardbase | + (addr & 0xff), val, reg_pc)); + } else { + val = vicii_read_phi1(); + IDBG((LOG, "RAMLINK: io1 r card[%06x] = %02x at 0x%04x (open)", rl_cardbase | + (addr & 0xff), val, reg_pc)); + } + return val; + } + + IDBG((LOG, "RAMLINK: unhandled io1 r %04x at 0x%04x", addr, reg_pc)); + + return 255; +} + +static uint8_t ramlink_io2_40_43_read(uint16_t addr) +{ + uint8_t val = 0; + + IDBG((LOG, "--------------------")); + + val = i8255a_read(&rl_i8255a, addr & 3); + + IDBG((LOG, "RAMLINK: io2 r %04x = %02x at 0x%04x", addr, val, reg_pc)); + + return val; +} + + +static uint8_t ramlink_io2_b0_bf_read(uint16_t addr) +{ + uint8_t val = 0; + + IDBG((LOG, "--------------------")); + + if (rl_rtc) { + val = rtc72421_read(rl_rtc, addr & 15); + } + + IDBG((LOG, "RAMLINK: io2 r %04x = %02x at 0x%04x", addr, val, reg_pc)); + + return val; +} + +static uint8_t ramlink_io1_peek(uint16_t addr) +{ + return 0; +} + +static uint8_t ramlink_io2_peek(uint16_t addr) +{ + uint8_t val = 0; + + IDBG((LOG, "RAMLINK: io2 p %04x = %02x at 0x%04x", addr, val, reg_pc)); + + return val; +} + +static void ramlink_io1_store(uint16_t addr, uint8_t value) +{ +#ifdef RLDEBUGIO + uint8_t old_val; +#endif + if (rl_io1mode == 0) { +#ifdef RLDEBUGIO + old_val = rl_ram[rl_rambase | (addr & 0xff)]; +#endif + rl_ram[rl_rambase | (addr & 0xff)] = value; + IDBG((LOG, "RAMLINK: io1 w ram[%04x] < %02x (%02x) at 0x%04x", rl_rambase | + (addr & 0xff), value, old_val, reg_pc)); + return; + } else if (rl_io1mode == 1) { + if (rl_cardbase != -1) { +#ifdef RLDEBUGIO + old_val = rl_card[rl_cardbase | (addr & 0xff)]; +#endif + rl_card[rl_cardbase | (addr & 0xff)] = value; + IDBG((LOG, "RAMLINK: io1 w card[%06x] < %02x (%02x) at 0x%04x", rl_cardbase | + (addr & 0xff), value, old_val, reg_pc)); + } else { + IDBG((LOG, "RAMLINK: io1 w card[%06x] open bus at 0x%04x", rl_cardbase | + (addr & 0xff), reg_pc)); + } + return; + } + + IDBG((LOG, "RAMLINK: unhandled io1 w %04x (%02x) at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_20_22_store(uint16_t addr, uint8_t value) +{ + + IDBG((LOG, "--------------------")); + + switch (addr & 0x03) { + case 0: + rl_reu_trap = 0; + break; + case 1: + if (rl_reu_trap && (ramlink_devices_io2_reu >= 0)) { + ramlink_devices_io2_entry[ramlink_devices_io2_reu].store(1, value); + } + break; + case 2: + rl_reu_trap = 1; + break; + } + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_40_43_store(uint16_t addr, uint8_t value) +{ + + IDBG((LOG, "--------------------")); + + i8255a_store(&rl_i8255a, addr & 3, value); + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_60_60_store(uint16_t addr, uint8_t value) +{ + rl_dos = 1; + cart_port_config_changed_slot0(); + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_70_70_store(uint16_t addr, uint8_t value) +{ + rl_dos = 0; + cart_port_config_changed_slot0(); + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_7e_7f_store(uint16_t addr, uint8_t value) +{ + if (rl_on && (addr == 0x7f)) { + ramlink_off(); + } else if (addr == 0x7e) { +/* + if (!rl_scanned) { + ramlink_scan_io(); + } +*/ + ramlink_on(); + } + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_80_9f_store(uint16_t addr, uint8_t value) +{ + rl_rambase = (addr & 0x1f) << 8; + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_a0_a3_store(uint16_t addr, uint8_t value) +{ + int i; + + switch (addr & 3) { + case 0: + rl_cardaddr = (rl_cardaddr & 0xffff0000) | (value << 8); + break; + case 1: + rl_cardaddr = (rl_cardaddr & 0xff00ff00) | (value << 16); + break; + case 2: + rl_cardaddr = (rl_cardaddr & 0x00ffff00) | (value << 24); + break; + } + i = rl_memmap[(rl_cardaddr >> 20) & 63]; + /* if the memory re-mapping is set to -1, then the bus is open */ + if (i<0) { + rl_cardbase = -1; + } else { + rl_cardbase = (i << 20) | (rl_cardaddr & 0x0fffff); + } + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_b0_bf_store(uint16_t addr, uint8_t value) +{ + IDBG((LOG, "--------------------")); + + if (rl_rtc) { + rtc72421_write(rl_rtc, addr & 15, value); + } + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +static void ramlink_io2_c0_c3_store(uint16_t addr, uint8_t value) +{ + rl_io1mode = addr & 0x3; + ramlink_update_io1mode(); + + IDBG((LOG, "RAMLINK: io2 w %04x < %02x at 0x%04x", addr, value, reg_pc)); +} + +/* no dump here, it is just a window to variable memory sources */ +static int ramlink_io1_dump(void) +{ + return 0; +} + +static int ramlink_io2_dump(void) +{ + mon_out("IO mapped?: %s\n", rl_on ? "Yes" : "No"); + mon_out("DOS mapped?: %s\n", rl_dos ? "Yes" : "No"); + mon_out("Mode: %s\n", rl_normal ? "Normal" : "Direct"); + mon_out("RAMCard Size: %d MiB\n", rl_cardsizemb); + mon_out("IO1 source: %u\n", rl_io1mode); + mon_out("I8255A at $DF40\n"); + i8255a_dump(&rl_i8255a); + + return 0; +} + +/* ---------------------------------------------------------------------*/ +int c128ramlink_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit, int mem_config) +{ +#if 0 +/* for no-mmu testing */ + *base = 0; + *start = 0; + *limit = 0; + return 1; +#endif + + /* unlike the c64 mmu_translate, here we only apply what we can and move + on. return a 1 if we did, or 0 if we didn't apply anything. */ + if (!rl_mapped || !rl_enabled) { + return 0; + } + + if (addr >= 0x8000 && addr <= 0x9fff && + ( ((mem_config & 0x0c) == 0x08) || ((mem_config & 0x0c) == 0x04) ) ) { + if (rl_dos) { + *base = rl_rom + rl_rombase - 0x8000; + *start = 0x8000; + *limit = 0x9ffd; + return 1; + } + } else if (addr >= 0xa000 && addr <= 0xbfff && + ( ((mem_config & 0x0c) == 0x08) || ((mem_config & 0x0c) == 0x04) ) ) { + if (rl_dos) { + *base = rl_rom + rl_rombase + 0x2000 - 0xa000; + *start = 0xa000; + *limit = 0xbffd; + return 1; + } + } else if (addr >= 0xe000 && ((mem_config & 0x30) == 0x00)) { + if (rl_on) { + *base = rl_rom + rl_kernbase128 - 0xe000; + *start = 0xe000; + *limit = 0xfffd; + /* on the 128, RL doesn't map $fd00-$ff0f to avoid dealing with + international keyboard differences in all the ROMs */ + } else if (addr < 0xfd00) { + *base = rl_rom + rl_kernbase128 + 0x2000 - 0xe000; + *start = 0xe000; + *limit = 0xfcfd; + } else if (addr >= 0xff10) { + *base = rl_rom + rl_kernbase128 + 0x2000 - 0xe000; + *start = 0xff10; + *limit = 0xfffd; + } else { + return 0; + } + return 1; + } else if (addr >= 0xe000 && + ( ((mem_config & 0x30) == 0x20) || ((mem_config & 0x30) == 0x10) ) ) { + if (rl_on) { + /* switched kernal */ + /* for $e000-$ffff, ramlink exposes the switched kernal, but there are a couple holes: + $ff05-$ff0f, $fff0-$ffff */ + *base = rl_rom + rl_kernbase128 - 0xe000; + if (addr < 0xff00) { + *start = 0xe000; + *limit = 0xff00 - 3; + } else if (addr >= 0xff10 && addr < 0xfff0 ) { + *start = 0xff10; + *limit = 0xfff0 - 3; + } else { + return 0; + } + } else { + /* main kernal */ + /* for $e000-$ffff, ramlink exposes the main kernal, but there are a few holes: + $eb00-$ecff, $f7a0-$f7af, $fd00-$feff, $ff05-$ff0f, $ff50-$ff5f, $fff0-$ffff */ + *base = rl_rom + rl_kernbase128 + 0x2000 - 0xe000; + if (addr >= 0xe000 && addr < 0xeb00) { + *start = 0xe000; + *limit = 0xeb00 - 3; + } else if (addr >= 0xed00 && addr < 0xf7a0) { + *start = 0xed00; + *limit = 0xf7a0 - 3; + } else if (addr >= 0xf7b0 && addr < 0xfd00) { + *start = 0xf7b0; + *limit = 0xfd00 - 3; + } else if (addr >= 0xff10 && addr < 0xff50) { + *start = 0xff10; + *limit = 0xff50 - 3; + } else if (addr >= 0xff60 && addr < 0xfff0) { + *start = 0xff60; + *limit = 0xfff0 - 3; + } else { + return 0; + } + } + return 1; + } + + return 0; +} + +uint8_t c128ramlink_hi_read(uint16_t addr, uint8_t *value) +{ + /* check IO if not done already */ + if (!rl_scanned) { + ramlink_scan_io(); + ramlink_off(); + } + + if (rl_mapped) { + /* other wise pull from one of the ROMS */ + if (!rl_enabled) { + return 0; + } else if (rl_on) { + *value = rl_rom[rl_kernbase128 | (addr & 0x1fff)]; + /* on the 128, RL doesn't map $fd00-$ff0f to avoid dealing with + international keyboard differences in all the ROMs */ + } else if (addr < 0xfd00 || addr >= 0xff10) { + *value = rl_rom[rl_kernbase128 | 0x2000 | (addr & 0x1fff)]; + } else { + return 0; + } + MDBG((LOG, "RAMLINK: c128ramlink_hi_read %04x = %02x", (int)addr, (int)*value)); + return 1; + } + + return 0; +} + +uint8_t c128ramlink_roml_read(uint16_t addr, uint8_t *value) +{ + /* check IO if not done already */ + if (!rl_scanned) { + ramlink_scan_io(); + ramlink_off(); + } + + /* only expose ramlink banks if function rom is enabled */ + if (addr >= 0x8000 && addr <= 0xbfff && rl_mapped && rl_dos && rl_enabled) { + *value = rl_rom[rl_rombase | (addr & 0x3fff)]; + MDBG((LOG, "RAMLINK: c128ramlink_roml_read %04x = %02x", addr, *value)); + return 1; + } + + if (rl_mapped && rl_enabled && addr >= 0xe000) { + if (rl_on) { + /* switched kernal */ + /* for $e000-$ffff, ramlink exposes the switched kernal, but there are a couple holes: + $ff05-$ff0f, $fff0-$ffff */ + if ((addr >= 0xff00 && addr <= 0xff0f ) || + (addr >= 0xfff0 )) { + return 0; + } + *value = rl_rom[rl_kernbase128 | (addr & 0x1fff)]; + return 1; + } else { + /* main kernal */ + /* for $e000-$ffff, ramlink exposes the main kernal, but there are a few holes: + $eb00-$ecff, $f7a0-$f7af, $fd00-$feff, $ff05-$ff0f, $ff50-$ff5f, $fff0-$ffff */ + if ((addr >= 0xeb00 && addr <= 0xecff ) || + (addr >= 0xf7a0 && addr <= 0xf7af ) || + (addr >= 0xfd00 && addr <= 0xfeff ) || + (addr >= 0xff00 && addr <= 0xff0f ) || + (addr >= 0xff50 && addr <= 0xff5f ) || + (addr >= 0xfff0 )) { + return 0; + } + *value = rl_rom[rl_kernbase128 | 0x2000 | (addr & 0x1fff)]; + return 1; + } + } + + return 0; +} + +void c128ramlink_switch_mode(int mode) +{ + LOG2((LOG, "RAMLINK: switch mode %d", mode)); + + if ( mode ) { + /* reconfigure for c64 mode */ + cart_config_changed_slot0(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); + } else { + /* reconfigure for c128 mode */ + cart_config_changed_slot0(CMODE_RAM, CMODE_RAM, CMODE_READ); + } +} + +/* read 8000-9fff */ +int ramlink_roml_read(uint16_t addr, uint8_t *value) +{ + /* check IO if not done already */ + if (!rl_scanned) { + ramlink_scan_io(); + ramlink_off(); + } + + /* do not map this for super cpu */ + if (machine_class == VICE_MACHINE_SCPU64) { + return CART_READ_THROUGH; + } + + if (rl_mapped && rl_dos && rl_enabled) { + *value = rl_rom[rl_rombase | (addr & 0x1fff)]; + MDBG((LOG, "RAMLINK: roml_read %04x = %02x", addr, *value)); + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +/* read e000-efff */ +int ramlink_romh_read(uint16_t addr, uint8_t *value) +{ + /* check IO if not done already */ + if (!rl_scanned) { + ramlink_scan_io(); + ramlink_off(); + } + + /* It seems that rl_on has higher priority over $1, but NOT on addresses + 0xff00 - 0xff10 and 0xfff0 - 0xffff. */ + if (rl_mapped) { + int p = (pport.dir & pport.data) | (~pport.dir & 7); + /* other wise pull from one of the ROMS */ + if (!rl_enabled) { + return CART_READ_THROUGH; + } else if (rl_on && (addr < 0xff00 || (addr >= 0xff10 && addr < 0xfff0))) { + *value = rl_rom[rl_kernbase64 | (addr & 0x1fff)]; + } else if (p & 2) { + *value = rl_rom[rl_kernbase64 | 0x2000 | (addr & 0x1fff)]; + } else { + return CART_READ_THROUGH; + } + MDBG((LOG, "RAMLINK: romh_read %04x = %02x pport=%02x", + (unsigned int)addr, (unsigned int)*value, (unsigned int)(~pport.dir | pport.data))); + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +/* read a000-bfff */ +int ramlink_a000_bfff_read(uint16_t addr, uint8_t *value) +{ + /* check IO if not done already */ + if (!rl_scanned) { + ramlink_scan_io(); + ramlink_off(); + } + + /* do not map this for super cpu */ + if (machine_class == VICE_MACHINE_SCPU64) { + return CART_READ_THROUGH; + } + + if (rl_mapped && rl_dos && rl_enabled) { + *value = rl_rom[rl_rombase | 0x2000 | (addr & 0x1fff)]; + MDBG((LOG, "RAMLINK: rom_a000_read %04x = %02x", + (int)addr, (int)*value)); + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +int ramlink_peek_mem(uint16_t addr, uint8_t *value) +{ + if (machine_class == VICE_MACHINE_SCPU64) { + return CART_READ_THROUGH; + } + + if (!rl_mapped || !rl_enabled) { + return CART_READ_THROUGH; + } + + if (addr >= 0x8000 && addr <= 0x9fff) { + if (rl_dos) { + *value = rl_rom[rl_rombase | (addr & 0x3fff)]; + return CART_READ_VALID; + } + } else if (addr >= 0xa000 && addr <= 0xbfff) { + if (rl_dos) { + *value = rl_rom[rl_rombase | (addr & 0x3fff)]; + return CART_READ_VALID; + } + /* It seems that rl_on has higher priority over $1 */ + } else if (addr >= 0xe000) { + if (rl_on) { + *value = rl_rom[rl_kernbase64 | (addr & 0x1fff)]; + } else if ((~pport.dir | pport.data) & 2) { + *value = rl_rom[rl_kernbase64 | 0x2000 | (addr & 0x1fff)]; + } else { + return CART_READ_THROUGH; + } + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +/* ---------------------------------------------------------------------*/ + +int ramlink_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + return CART_READ_C64MEM; +} + +int ramlink_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + return ramlink_romh_phi1_read(addr, value); +} + +/* ---------------------------------------------------------------------*/ + +int ramlink_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ +/* + LOG2((LOG, "RAMLINK: mmu translate: addr=%04x (mapped=%d,on=%d,dos=%d,rombase=%04x)", addr,rl_mapped,rl_on,rl_dos,rl_rombase)); +*/ + + if (!rl_mapped || !rl_enabled) { + return CART_READ_THROUGH; + } + + if (addr >= 0x8000 && addr <= 0x9fff) { + if (rl_dos) { + *base = rl_rom + rl_rombase - 0x8000; + *start = 0x8000; + *limit = 0xa000 - 3; + return CART_READ_VALID; + } + } else if (addr >= 0xa000 && addr <= 0xbfff) { + if (rl_dos) { + *base = rl_rom + rl_rombase + 0x2000 - 0xa000; + *start = 0xa000; + *limit = 0xc000 - 3; + return CART_READ_VALID; + } + /* It seems that rl_on has higher priority over $1, but NOT on addresses + 0xff00 - 0xff10 and 0xfff0 - 0xffff. */ + } else if (addr >= 0xe000) { + int p = (pport.dir & pport.data) | (~pport.dir & 7); + if (rl_on && (addr < 0xff00 || (addr >= 0xff10 && addr < 0xfff0))) { + *base = rl_rom + rl_kernbase64 - 0xe000; + if (addr < 0xff00) { + *start = 0xe000; + *limit = 0xff00 - 3; + } else { + *start = 0xff10; + *limit = 0xfff0 - 3; + } + } else if (p & 2) { + *base = rl_rom + rl_kernbase64 + 0x2000 - 0xe000; + *start = 0xe000; + *limit = 0x10000 - 3; + } else { + return CART_READ_THROUGH; + } + return CART_READ_VALID; + } + + return CART_READ_THROUGH; +} + +void ramlink_passthrough_changed(export_t *ex) +{ + rl_extexrom = ex->exrom; + rl_extgame = ex->game; + + if (!rl_extexrom && rl_extgame) { + /* make sure passthough carts with ultimax get priority */ + rl_mapped = 0; + } else { + /* everything else stays in ultimax mode and we handle it later */ + rl_mapped = 1; + cart_set_port_exrom_slot0(0); + cart_set_port_game_slot0(1); + } + cart_port_config_changed_slot0(); +} + +/* used by c64cartmem.c to determine the original intended mode */ +int ramlink_cart_mode(void) +{ + return ( rl_extgame << 4 ) | ( rl_extexrom << 3 ) | + ( ( ~pport.dir | pport.data ) & 7 ); +} + +void ramlink_config_init(export_t *ex) +{ + int32_t i; + LOG2((LOG, "RAMLINK: config init")); + + rl_extexrom = ex->exrom; + rl_extgame = ex->game; + + /* set default cart mode depending on machine type */ + if ( machine_class == VICE_MACHINE_C128 ) { + c128ramlink_switch_mode(0); + } else { + /* everything else */ + c128ramlink_switch_mode(1); + } + + for (i = 0; i < 0x2000; i++) { + rl_ram[i] = (i >> 8); + } + + /* "pull-ups" */ + rl_i8255a_i[0] = 0xff; + rl_i8255a_i[1] = 0xff; + rl_i8255a_i[2] = 0xff; + + /* reset "previous" values */ + rl_i8255a_o[0] = 0xff; + rl_i8255a_o[1] = 0xff; + rl_i8255a_o[2] = 0xff; + + /* setup I8255A */ + rl_i8255a.set_pa = set_pa; + rl_i8255a.set_pb = set_pb; + rl_i8255a.set_pc = set_pc; + rl_i8255a.get_pa = get_pa; + rl_i8255a.get_pb = get_pb; + rl_i8255a.get_pc = get_pc; + + i8255a_reset(&rl_i8255a); + + /* make sure the parallel bus is updated */ + cmdbus_update(); +} + +void ramlink_config_setup(uint8_t *rawcart) +{ + LOG2((LOG, "RAMLINK: config setup")); + + /* copy supplied ROM image to memory */ + memcpy(rl_rom, rawcart, 0x10000); + + /* set default cart mode depending on machine type */ + if ( machine_class == VICE_MACHINE_C128 ) { + c128ramlink_switch_mode(0); + } else { + /* everything else */ + c128ramlink_switch_mode(1); + } +} + +/* ---------------------------------------------------------------------*/ + +static int ramlink_common_attach(void) +{ + LOG2((LOG, "RAMLINK: common attach")); + + if (ramlink_registerio() < 0) { + return -1; + } + set_enabled(1, NULL); + return 0; +} + +int ramlink_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) +{ + crt_chip_header_t chip; + int i; + + for (i = 0; i <= 8; i++) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.bank > 7 || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + } + set_bios_filename(filename, NULL); /* set the resource */ + return ramlink_common_attach(); +} + +int ramlink_bin_attach(const char *filename, uint8_t *rawcart) +{ + LOG2((LOG, "RAMLINK: bin attach")); + + /* just load the full 64 KiB */ + if (util_file_load(filename, rawcart, 0x10000, + UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + set_bios_filename(filename, NULL); /* set the resource */ + return ramlink_common_attach(); +} + +void ramlink_detach(void) +{ + LOG2((LOG, "RAMLINK: detach")); + + set_enabled(0, NULL); +} + +int ramlink_enable(void) +{ + /* this will reload the BIOS */ + return set_enabled(1, (void*)1); +} + +int ramlink_disable(void) +{ + return set_enabled(0, (void*)1); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTRAMLINK snapshot module format: + + type | name | description + ------------------------------------------------- + INT32 | cardsizemb | rl_cardsizemb + UINT32 | rombase | rl_rombase + UINT32 | kernbase | rl_kernbase + UINT32 | rambase | rl_rambase + UINT32 | cardaddr | rl_cardaddr + UINT32 | io1mode | rl_io1mode + UINT32 | reu_trap | rl_reu_trap + BYTE | on | rl_on + BYTE | dos | rl_dos + ARRAY | i8255a_i | 3 internal inputs for I8255A + ARRAY | i8255a_o | 3 internal outputs for I8255A + ARRAY | rom | rl_rom 64 KiB for firmware + ARRAY | ram | rl_ram 8 KiB for SRAM + I8255A | SNAPSHOTI8255A | rl_8255 + ARRAY | rl_card | Contents of RAMCARD (cardsibemb) in MiB +*/ + +static const char snap_module_name[] = "CARTRAMLINK"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int ramlink_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + LOG2((LOG, "RAMLINK: snapshot_write")); + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_DW(m, rl_cardsizemb) < 0) + || (SMW_DW(m, rl_rombase) < 0) + || (SMW_DW(m, rl_kernbase) < 0) + || (SMW_DW(m, rl_rambase) < 0) + || (SMW_DW(m, rl_cardaddr) < 0) + || (SMW_DW(m, rl_io1mode) < 0) + || (SMW_DW(m, rl_reu_trap) < 0) + || (SMW_B(m, rl_on) < 0) + || (SMW_B(m, rl_dos) < 0) + || (SMW_BA(m, rl_i8255a_i, 3) < 0) + || (SMW_BA(m, rl_i8255a_o, 3) < 0) + || (SMW_BA(m, rl_rom, 0x10000) < 0) + || (SMW_BA(m, rl_ram, 0x2000) < 0)) { + goto fail; + } + + if (i8255a_snapshot_write_data(&rl_i8255a, m) < 0) { + goto fail; + } + + if (SMW_BA(m, rl_card, rl_cardsize) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return 0; + +fail: + snapshot_module_close(m); + return -1; +} + +int ramlink_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + uint32_t size; + + LOG2((LOG, "RAMLINK: snapshot_read")); + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_DW(m, &size) < 0) + || (SMR_DW(m, &rl_rombase) < 0) + || (SMR_DW(m, &rl_kernbase) < 0) + || (SMR_DW(m, &rl_rambase) < 0) + || (SMR_DW(m, &rl_cardaddr) < 0) + || (SMR_DW(m, &rl_io1mode) < 0) + || (SMR_DW(m, &rl_reu_trap) < 0) + || (SMR_B(m, &rl_on) < 0) + || (SMR_B(m, &rl_dos) < 0) + || (SMR_BA(m, rl_i8255a_i, 3) < 0) + || (SMR_BA(m, rl_i8255a_o, 3) < 0) + || (SMR_BA(m, rl_rom, 0x10000) < 0) + || (SMR_BA(m, rl_ram, 0x2000) < 0)) { + goto fail; + } + + if (i8255a_snapshot_read_data(&rl_i8255a, m) < 0) { + goto fail; + } + + set_enabled(1, NULL); + + /* set ramcard size */ + set_size(size, NULL); + /* set the cardbase via a dummy write to the address system */ + ramlink_io2_a0_a3_store(0,3); + + if (SMR_BA(m, rl_card, rl_cardsize) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/ramlink.h b/src/Emulators/vice/c64/cart/ramlink.h new file mode 100644 index 00000000..f8131243 --- /dev/null +++ b/src/Emulators/vice/c64/cart/ramlink.h @@ -0,0 +1,77 @@ +/* + * ramlink.h - Cartridge handling, CMD Ramlink + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_RAMLINK_H +#define VICE_RAMLINK_H + +#define RL_MODE_DIRECT 0 +#define RL_MODE_NORMAL 1 + +#include "c64cart.h" + +struct snapshot_s; + +void ramlink_freeze(void); +void ramlink_config_init(export_t *ex); +void ramlink_config_setup(uint8_t *rawcart); +int ramlink_bin_attach(const char *filename, uint8_t *rawcart); +void ramlink_detach(void); +int ramlink_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int ramlink_cart_enabled(void); + +int ramlink_flush_ram_image(void); +const char *ramlink_get_ram_file_name(void); +int ramlink_ram_save(const char *filename); + +int ramlink_can_flush_ram_image(void); +int ramlink_can_save_ram_image(void); + +int ramlink_roml_read(uint16_t addr, uint8_t *value); +int ramlink_romh_read(uint16_t addr, uint8_t *value); +int ramlink_a000_bfff_read(uint16_t addr, uint8_t *value); +int ramlink_peek_mem(uint16_t addr, uint8_t *value); +int ramlink_romh_phi1_read(uint16_t addr, uint8_t *value); +int ramlink_romh_phi2_read(uint16_t addr, uint8_t *value); +int ramlink_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); +void c128ramlink_switch_mode(int mode); +int c128ramlink_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit, int mem_config); +uint8_t c128ramlink_hi_read(uint16_t addr, uint8_t *value); +uint8_t c128ramlink_roml_read(uint16_t addr, uint8_t *value); + +void ramlink_passthrough_changed(export_t *ex); +int ramlink_cart_mode(void); + +int ramlink_enable(void); +int ramlink_disable(void); + +int ramlink_cmdline_options_init(void); +int ramlink_resources_init(void); +int ramlink_resources_shutdown(void); + +int ramlink_snapshot_write_module(struct snapshot_s *s); +int ramlink_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/retroreplay.c b/src/Emulators/vice/c64/cart/retroreplay.c index 857610de..7ab74100 100644 --- a/src/Emulators/vice/c64/cart/retroreplay.c +++ b/src/Emulators/vice/c64/cart/retroreplay.c @@ -31,6 +31,7 @@ #include #include "archdep.h" +#include "alarm.h" #include "c64cart.h" #define CARTRIDGE_INCLUDE_SLOTMAIN_API #include "c64cartsystem.h" @@ -46,8 +47,8 @@ #include "lib.h" #include "maincpu.h" #include "monitor.h" +#include "ram.h" #include "resources.h" -#include "translate.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" @@ -86,6 +87,8 @@ #define DBG(x) #endif +#define CART_RAM_SIZE (32 * 1024) + /* Cart is activated. */ static int rr_active = 0; static int rr_clockport_enabled = 0; @@ -116,7 +119,7 @@ static int reu_mapping; static int rr_hw_flashjumper = 0; static int rr_hw_bankjumper = 0; static int rr_bios_write = 0; -static int rr_revision = 0; +static int rr_revision = RR_REV_RETRO_REPLAY; static int export_ram_at_a000 = 0; static unsigned int rom_offset = 0x10000; @@ -135,62 +138,73 @@ static clockport_device_t *clockport_device = NULL; static char *clockport_device_names = NULL; +static struct alarm_s *nofreeze_alarm; +static int freeze_button_pressed = 0; + /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE retroreplay_io1_read(WORD addr); -static void retroreplay_io1_store(WORD addr, BYTE value); -static BYTE retroreplay_io2_read(WORD addr); -static void retroreplay_io2_store(WORD addr, BYTE value); +static uint8_t retroreplay_io1_read(uint16_t addr); +static void retroreplay_io1_store(uint16_t addr, uint8_t value); +static uint8_t retroreplay_io2_read(uint16_t addr); +static void retroreplay_io2_store(uint16_t addr, uint8_t value); static int retroreplay_dump(void); -static BYTE retroreplay_clockport_read(WORD io_address); -static BYTE retroreplay_clockport_peek(WORD io_address); -static void retroreplay_clockport_store(WORD io_address, BYTE byte); +static uint8_t retroreplay_clockport_read(uint16_t io_address); +static uint8_t retroreplay_clockport_peek(uint16_t io_address); +static void retroreplay_clockport_store(uint16_t io_address, uint8_t byte); +static int retroreplay_clockport_dump(void); + static io_source_t retroreplay_io1_device = { - CARTRIDGE_NAME_RETRO_REPLAY, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - retroreplay_io1_store, - retroreplay_io1_read, - NULL, /* TODO: peek */ - retroreplay_dump, - CARTRIDGE_RETRO_REPLAY, - 1, - 0 + CARTRIDGE_NAME_RETRO_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range of the device, regs:$de00-$deff */ + 0, /* read validity is determined by the device upon a read */ + retroreplay_io1_store, /* store function */ + NULL, /* NO poke function */ + retroreplay_io1_read, /* read function */ + NULL, /* TODO: peek function */ + retroreplay_dump, /* device state information dump function */ + CARTRIDGE_RETRO_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t retroreplay_io2_device = { - CARTRIDGE_NAME_RETRO_REPLAY, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - retroreplay_io2_store, - retroreplay_io2_read, - NULL, /* TODO: peek */ - retroreplay_dump, - CARTRIDGE_RETRO_REPLAY, - 0, - 0 + CARTRIDGE_NAME_RETRO_REPLAY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read validity is determined by the device upon a read */ + retroreplay_io2_store, /* store function */ + NULL, /* NO poke function */ + retroreplay_io2_read, /* read function */ + NULL, /* TODO: peek function */ + retroreplay_dump, /* device state information dump function */ + CARTRIDGE_RETRO_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t retroreplay_clockport_io1_device = { - CARTRIDGE_NAME_RRNET " on " CARTRIDGE_NAME_RETRO_REPLAY " Clockport", - IO_DETACH_RESOURCE, - "RRClockPort", - 0xde02, 0xde0f, 0x0f, - 0, - retroreplay_clockport_store, - retroreplay_clockport_read, - retroreplay_clockport_peek, - retroreplay_dump, - CARTRIDGE_RETRO_REPLAY, - 0, - 0 + CARTRIDGE_NAME_RETRO_REPLAY " Clockport", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "RRClockPort", /* resource to set to '0' */ + 0xde02, 0xde0f, 0x0f, /* range for the device, regs:$de02-$de0f */ + 0, /* read validity is determined by the device upon a read */ + retroreplay_clockport_store, /* store function */ + NULL, /* NO poke function */ + retroreplay_clockport_read, /* read function */ + retroreplay_clockport_peek, /* peek function */ + retroreplay_clockport_dump, /* device state information dump function */ + CARTRIDGE_RETRO_REPLAY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *retroreplay_io1_list_item = NULL; @@ -203,49 +217,64 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -static BYTE retroreplay_clockport_read(WORD address) +static uint8_t retroreplay_clockport_read(uint16_t address) { - if (clockport_device) { - if (rr_clockport_enabled) { - if (address < 0x02) { - retroreplay_clockport_io1_device.io_source_valid = 0; - return 0; - } - return clockport_device->read(address, &retroreplay_clockport_io1_device.io_source_valid, clockport_device->device_context); + retroreplay_clockport_io1_device.io_source_valid = 0; + if (rr_clockport_enabled) { + if (address < 0x02) { + return 0; + } + retroreplay_clockport_io1_device.io_source_valid = 1; + /* read from clockport device */ + if (clockport_device) { + return clockport_device->read(address, + &retroreplay_clockport_io1_device.io_source_valid, + clockport_device->device_context); } + /* read open clock port */ + return 0; } return 0; } -static BYTE retroreplay_clockport_peek(WORD address) +static uint8_t retroreplay_clockport_peek(uint16_t address) { - if (clockport_device) { - if (rr_clockport_enabled) { - if (address < 0x02) { - return 0; - } + if (rr_clockport_enabled) { + if (address < 0x02) { + return 0; + } + /* read from clockport device */ + if (clockport_device) { return clockport_device->peek(address, clockport_device->device_context); } } return 0; } -static void retroreplay_clockport_store(WORD address, BYTE byte) +static void retroreplay_clockport_store(uint16_t address, uint8_t byte) { - if (clockport_device) { - if (rr_clockport_enabled) { - if (address < 0x02) { - return; - } - + if (rr_clockport_enabled) { + if (address < 0x02) { + return; + } + /* write to clockport device */ + if (clockport_device) { clockport_device->store(address, byte, clockport_device->device_context); } } } +static int retroreplay_clockport_dump(void) +{ + if (clockport_device) { + clockport_device->dump(clockport_device->device_context); + } + return 0; +} + /* ---------------------------------------------------------------------*/ -BYTE retroreplay_io1_read(WORD addr) +uint8_t retroreplay_io1_read(uint16_t addr) { retroreplay_io1_device.io_source_valid = 0; @@ -267,13 +296,15 @@ BYTE retroreplay_io1_read(WORD addr) case 0: case 1: retroreplay_io1_device.io_source_valid = 1; - return ((roml_bank & 3) << 3) | ((roml_bank & 4) << 5) | ((roml_bank & 8) << 2) | allow_bank | reu_mapping | rr_hw_flashjumper; + return ((roml_bank & 3) << 3) | ((roml_bank & 4) << 5) | + ((roml_bank & 8) << 2) | allow_bank | reu_mapping | + rr_hw_flashjumper | (freeze_button_pressed << 2); default: if (rr_clockport_enabled && (addr & 0xff) < 0x10) { return 0; } if ((reu_mapping) && (!rr_frozen)) { - if (export_ram || ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000)) { + if (export_ram || (/* (rr_revision == RR_REV_NORDIC_REPLAY) && */ export_ram_at_a000)) { retroreplay_io1_device.io_source_valid = 1; if (allow_bank) { return export_ram0[0x1e00 + (addr & 0xff) + ((roml_bank & 3) << 13)]; @@ -294,7 +325,7 @@ BYTE retroreplay_io1_read(WORD addr) return 0; } -void retroreplay_io1_store(WORD addr, BYTE value) +void retroreplay_io1_store(uint16_t addr, uint8_t value) { int mode = CMODE_WRITE; @@ -358,13 +389,18 @@ void retroreplay_io1_store(WORD addr, BYTE value) if (value & 0x20) { /* bit 5 */ mode |= CMODE_EXPORT_RAM; } + /* mode 0x22 is kinda broken in Retro Replay, mimic this here */ + if ((rr_revision == RR_REV_RETRO_REPLAY) && ((value & 0x67) == 0x22)) { + export_ram_at_a000 = 1; + rr_cmode = CMODE_RAM; + } } /* after freezing writing to bit 0 and 1 has no effect until freeze was acknowledged by setting bit 6 */ if (rr_frozen) { rr_cmode = CMODE_ULTIMAX; } - cart_config_changed_slotmain(CMODE_8KGAME, (BYTE)(rr_cmode | (rr_bank << CMODE_BANK_SHIFT)), mode); + cart_config_changed_slotmain(CMODE_8KGAME, (uint8_t)(rr_cmode | (rr_bank << CMODE_BANK_SHIFT)), mode); if (value & 4) { /* bit 2 */ rr_active = 0; @@ -414,9 +450,7 @@ void retroreplay_io1_store(WORD addr, BYTE value) cart_romhbank_set_slotmain(rr_bank); cart_romlbank_set_slotmain(rr_bank); cart_port_config_changed_slotmain(); - if (rr_clockport_enabled != (value & 1)) { - rr_clockport_enabled = value & 1; - } + rr_clockport_enabled = value & 1; } break; default: @@ -436,7 +470,7 @@ void retroreplay_io1_store(WORD addr, BYTE value) } } -BYTE retroreplay_io2_read(WORD addr) +uint8_t retroreplay_io2_read(uint16_t addr) { retroreplay_io2_device.io_source_valid = 0; @@ -444,7 +478,7 @@ BYTE retroreplay_io2_read(WORD addr) if (rr_active) { if ((!reu_mapping) && (!rr_frozen)) { - if (export_ram || ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000)) { + if (export_ram || (/* (rr_revision == RR_REV_NORDIC_REPLAY) && */ export_ram_at_a000)) { retroreplay_io2_device.io_source_valid = 1; if (allow_bank) { return export_ram0[0x1f00 + (addr & 0xff) + ((roml_bank & 3) << 13)]; @@ -464,7 +498,7 @@ BYTE retroreplay_io2_read(WORD addr) return 0; } -void retroreplay_io2_store(WORD addr, BYTE value) +void retroreplay_io2_store(uint16_t addr, uint8_t value) { DBG(("io2 w %04x %02x\n", addr, value)); @@ -483,7 +517,7 @@ void retroreplay_io2_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ -BYTE retroreplay_roml_read(WORD addr) +uint8_t retroreplay_roml_read(uint16_t addr) { /* in frozen state nothing is mapped to ROML */ if (rr_frozen) { @@ -507,7 +541,7 @@ BYTE retroreplay_roml_read(WORD addr) return flash040core_read(flashrom_state, rom_offset + (addr & 0x1fff) + (roml_bank << 13)); } -void retroreplay_roml_store(WORD addr, BYTE value) +void retroreplay_roml_store(uint16_t addr, uint8_t value) { /* DBG(("roml w %04x %02x ram:%d flash:%d\n", addr, value, export_ram, rr_hw_flashjumper)); */ if (export_ram) { @@ -523,7 +557,7 @@ void retroreplay_roml_store(WORD addr, BYTE value) } } -int retroreplay_roml_no_ultimax_store(WORD addr, BYTE value) +int retroreplay_roml_no_ultimax_store(uint16_t addr, uint8_t value) { /* DBG(("roml w %04x %02x ram:%d flash:%d\n", addr, value, export_ram, rr_hw_flashjumper)); */ if (rr_hw_flashjumper) { @@ -548,7 +582,7 @@ int retroreplay_roml_no_ultimax_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ -BYTE retroreplay_a000_bfff_read(WORD addr) +uint8_t retroreplay_a000_bfff_read(uint16_t addr) { if ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000) { if (rr_frozen) { @@ -563,7 +597,7 @@ BYTE retroreplay_a000_bfff_read(WORD addr) return vicii_read_phi1(); } -void retroreplay_a000_bfff_store(WORD addr, BYTE value) +void retroreplay_a000_bfff_store(uint16_t addr, uint8_t value) { if ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000) { if (rr_frozen) { @@ -578,7 +612,7 @@ void retroreplay_a000_bfff_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ -BYTE retroreplay_romh_read(WORD addr) +uint8_t retroreplay_romh_read(uint16_t addr) { if ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000) { if (rr_frozen) { @@ -586,7 +620,7 @@ BYTE retroreplay_romh_read(WORD addr) return flash040core_read(flashrom_state, rom_offset + (addr & 0x1fff) + (roml_bank << 13)); } else { /* if the "allow bank" bit is not set, and RAM is selected, then - bot 0 and bit 1 of the bank nr are inactive for selecting the ROMH bank */ + bit 0 and bit 1 of the bank nr are inactive for selecting the ROMH bank */ return flash040core_read(flashrom_state, rom_offset + (addr & 0x1fff) + ((roml_bank & ~3) << 13)); } } @@ -600,11 +634,11 @@ BYTE retroreplay_romh_read(WORD addr) return flash040core_read(flashrom_state, rom_offset + (addr & 0x1fff) + (roml_bank << 13)); } /* if the "allow bank" bit is not set, and RAM is selected, then - bot 0 and bit 1 of the bank nr are inactive for selecting the ROMH bank */ + bit 0 and bit 1 of the bank nr are inactive for selecting the ROMH bank */ return flash040core_read(flashrom_state, rom_offset + (addr & 0x1fff) + ((roml_bank & ~3) << 13)); } -void retroreplay_romh_store(WORD addr, BYTE value) +void retroreplay_romh_store(uint16_t addr, uint8_t value) { if ((rr_revision == RR_REV_NORDIC_REPLAY) && export_ram_at_a000) { if (!rr_frozen) { @@ -613,17 +647,19 @@ void retroreplay_romh_store(WORD addr, BYTE value) } else { export_ram0[addr & 0x1fff] = value; } + return; } } + mem_store_without_romlh(addr, value); } -int retroreplay_peek_mem(export_t *export, WORD addr, BYTE *value) +int retroreplay_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0x8000 && addr <= 0x9fff) { *value = retroreplay_roml_read(addr); return CART_READ_VALID; } - if (!(export->exrom) && (export->game)) { + if (!(ex->exrom) && (ex->game)) { if (addr >= 0xe000) { *value = retroreplay_romh_read(addr); return CART_READ_VALID; @@ -637,7 +673,7 @@ int retroreplay_peek_mem(export_t *export, WORD addr, BYTE *value) return CART_READ_THROUGH; } -void retroreplay_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void retroreplay_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { #if 0 if (flashrom_state && flashrom_state->flash_data) { @@ -697,17 +733,16 @@ void retroreplay_mmu_translate(unsigned int addr, BYTE **base, int *start, int * static int retroreplay_dump(void) { /* FIXME: incomplete */ + mon_out("Hardware Revision: %d (%s Replay).\n", rr_revision, rr_revision ? "Nordic" : "Retro"); mon_out("Retro Replay registers are %s.\n", rr_active ? "enabled" : "disabled"); mon_out("Clockport is %s.\n", rr_clockport_enabled ? "enabled" : "disabled"); - if (rr_clockport_enabled) { - mon_out("Clockport device: %s.\n", clockport_device_id_to_name(clockport_device_id)); - } + mon_out("Clockport device: %s.\n", clockport_device_id_to_name(clockport_device_id)); mon_out("Freeze status: %s.\n", rr_frozen ? "frozen" : "released"); mon_out("EXROM line: %s, GAME line: %s, Mode: %s\n", (rr_cmode & 2) ? "high" : "low", (rr_cmode & 1) ? "low" : "high", - cart_config_string((BYTE)(rr_cmode & 3))); + cart_config_string((uint8_t)(rr_cmode & 3))); mon_out("ROM bank: %d\n", (rr_bank)); /* FIXME: take system RAM and cart mode(s) into account here */ /* FIXME: this is very inaccurate */ @@ -720,6 +755,25 @@ static int retroreplay_dump(void) /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void retroreplay_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void retroreplay_freeze(void) { /* freeze button is disabled in flash mode */ @@ -727,13 +781,25 @@ void retroreplay_freeze(void) rr_active = 1; rr_frozen = 1; rr_cmode = CMODE_ULTIMAX; - cart_config_changed_slotmain((BYTE)rr_cmode, (BYTE)rr_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)rr_cmode, (uint8_t)rr_cmode, CMODE_READ); /* flash040core_reset(flashrom_state); */ } } +static void nofreeze_alarm_handler(CLOCK offset, void *data) +{ + freeze_button_pressed = 0; + alarm_unset(nofreeze_alarm); +} + int retroreplay_freeze_allowed(void) { + freeze_button_pressed = 1; + alarm_unset(nofreeze_alarm); + /* HACK: we keep the button pressed for 30 frames, because we do not get the + "release" event for the hotkey. this enables us to keep it pressed + continously when the hotkey is being held down */ + alarm_set(nofreeze_alarm, maincpu_clk + (312 * 65 * 30)); if (no_freeze) { return 0; } @@ -758,7 +824,7 @@ void retroreplay_config_init(void) } else { rr_cmode = CMODE_8KGAME; } - cart_config_changed_slotmain((BYTE)rr_cmode, (BYTE)rr_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)rr_cmode, (uint8_t)rr_cmode, CMODE_READ); flash040core_reset(flashrom_state); } @@ -774,7 +840,7 @@ void retroreplay_reset(void) } else { rr_cmode = CMODE_8KGAME; } - cart_config_changed_slotmain((BYTE)rr_cmode, (BYTE)rr_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)rr_cmode, (uint8_t)rr_cmode, CMODE_READ); /* on the real hardware pressing reset would NOT reset the flash statemachine, only a powercycle would help. we do it here anyway :) @@ -785,7 +851,7 @@ void retroreplay_reset(void) } } -void retroreplay_config_setup(BYTE *rawcart) +void retroreplay_config_setup(uint8_t *rawcart) { DBG(("retroreplay_config_setup bank jumper: %d offset: %08x\n", rr_hw_bankjumper, rom_offset)); @@ -794,7 +860,7 @@ void retroreplay_config_setup(BYTE *rawcart) } else { rr_cmode = CMODE_8KGAME; } - cart_config_changed_slotmain((BYTE)rr_cmode, (BYTE)rr_cmode, CMODE_READ); + cart_config_changed_slotmain((uint8_t)rr_cmode, (uint8_t)rr_cmode, CMODE_READ); flashrom_state = lib_malloc(sizeof(flash040_context_t)); flash040core_init(flashrom_state, maincpu_alarm_context, FLASH040_TYPE_010, roml_banks); @@ -873,7 +939,7 @@ static int set_rr_clockport_device(int val, void *param) } if (val != CLOCKPORT_DEVICE_NONE) { - clockport_device = clockport_open_device(val, (char *)STRING_RETRO_REPLAY); + clockport_device = clockport_open_device(val, STRING_RETRO_REPLAY); if (!clockport_device) { return -1; } @@ -892,7 +958,7 @@ static int clockport_activate(void) return 0; } - clockport_device = clockport_open_device(clockport_device_id, (char *)STRING_RETRO_REPLAY); + clockport_device = clockport_open_device(clockport_device_id, STRING_RETRO_REPLAY); if (!clockport_device) { return -1; } @@ -944,51 +1010,35 @@ void retroreplay_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-rrbioswrite", SET_RESOURCE, 0, + { "-rrbioswrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRBiosWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SAVE_RR_ROM_AT_EXIT, - NULL, NULL }, - { "+rrbioswrite", SET_RESOURCE, 0, + NULL, "Enable saving of the RR ROM at exit" }, + { "+rrbioswrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRBiosWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SAVE_RR_ROM_AT_EXIT, - NULL, NULL }, - { "-rrbankjumper", SET_RESOURCE, 0, + NULL, "Disable saving of the RR ROM at exit" }, + { "-rrbankjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRBankJumper", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_SET_RR_BANK_JUMPER, - NULL, NULL }, - { "+rrbankjumper", SET_RESOURCE, 0, + NULL, "Set RR Bank Jumper" }, + { "+rrbankjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRBankJumper", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_UNSET_RR_BANK_JUMPER, - NULL, NULL }, - { "-rrflashjumper", SET_RESOURCE, 0, + NULL, "Unset RR Bank Jumper" }, + { "-rrflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRFlashJumper", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_SET_RR_FLASH_JUMPER, - NULL, NULL }, - { "+rrflashjumper", SET_RESOURCE, 0, + NULL, "Set RR Flash Jumper" }, + { "+rrflashjumper", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRFlashJumper", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_UNSET_RR_FLASH_JUMPER, - NULL, NULL }, - { "-rrrev", SET_RESOURCE, 1, + NULL, "Unset RR Bank Jumper" }, + { "-rrrev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "RRrevision", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_REVISION, IDCLS_RR_REVISION, - NULL, NULL }, + "", "Set RR Revision (0: Retro Replay, 1: Nordic Replay)" }, CMDLINE_LIST_END }; static cmdline_option_t clockport_cmdline_options[] = { - { "-rrclockportdevice", SET_RESOURCE, 1, + { "-rrclockportdevice", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "RRClockPort", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_DEVICE, IDCLS_CLOCKPORT_DEVICE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -1004,7 +1054,7 @@ int retroreplay_cmdline_options_init(void) sprintf(number, "%d", clockport_supported_devices[0].id); - clockport_device_names = util_concat(". (", number, ": ", clockport_supported_devices[0].name, NULL); + clockport_device_names = util_concat("Clockport device. (", number, ": ", clockport_supported_devices[0].name, NULL); for (i = 1; clockport_supported_devices[i].name; ++i) { tmp = clockport_device_names; @@ -1036,12 +1086,14 @@ static int retroreplay_common_attach(void) rr_enabled = 1; + nofreeze_alarm = alarm_new(maincpu_alarm_context, "NoFreezeAlarm", nofreeze_alarm_handler, NULL); + return 0; } -int retroreplay_bin_attach(const char *filename, BYTE *rawcart) +int retroreplay_bin_attach(const char *filename, uint8_t *rawcart) { - int len = 0; + off_t len; FILE *fd; retroreplay_filetype = 0; @@ -1051,7 +1103,11 @@ int retroreplay_bin_attach(const char *filename, BYTE *rawcart) if (fd == NULL) { return -1; } - len = util_file_length(fd); + len = archdep_file_size(fd); + if (len < 0) { + fclose(fd); + return -1; + } fclose(fd); memset(rawcart, 0xff, 0x20000); @@ -1077,7 +1133,7 @@ int retroreplay_bin_attach(const char *filename, BYTE *rawcart) return -1; } retroreplay_filetype = CARTRIDGE_FILETYPE_BIN; - retroreplay_filename = lib_stralloc(filename); + retroreplay_filename = lib_strdup(filename); return retroreplay_common_attach(); } @@ -1085,7 +1141,7 @@ int retroreplay_bin_attach(const char *filename, BYTE *rawcart) a CRT may contain up to 16 8k chunks. 32K, 64K and 128K total are accepted. - 32K and 64K files will always get loaded into logical bank 0 */ -int retroreplay_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int retroreplay_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename, uint8_t revision) { crt_chip_header_t chip; int i; @@ -1114,7 +1170,9 @@ int retroreplay_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) } retroreplay_filetype = CARTRIDGE_FILETYPE_CRT; - retroreplay_filename = lib_stralloc(filename); + retroreplay_filename = lib_strdup(filename); + + rr_revision = (revision > 0) ? RR_REV_NORDIC_REPLAY : RR_REV_RETRO_REPLAY; return retroreplay_common_attach(); } @@ -1173,10 +1231,10 @@ int retroreplay_crt_save(const char *filename) { FILE *fd; crt_chip_header_t chip; - BYTE *data; + uint8_t *data; int i; - fd = crt_create(filename, CARTRIDGE_RETRO_REPLAY, 1, 0, STRING_RETRO_REPLAY); + fd = crt_create_v11(filename, CARTRIDGE_RETRO_REPLAY, rr_revision, 1, 0, STRING_RETRO_REPLAY); if (fd == NULL) { return -1; @@ -1273,8 +1331,8 @@ void retroreplay_detach(void) ARRAY | RAM | 0.0+ | 32768 BYTES of RAM data */ -static char snap_module_name[] = "CARTRR"; -static char flash_snap_module_name[] = "FLASH040RR"; +static const char snap_module_name[] = "CARTRR"; +static const char flash_snap_module_name[] = "FLASH040RR"; #define SNAP_MAJOR 0 #define SNAP_MINOR 3 @@ -1289,20 +1347,20 @@ int retroreplay_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)rr_revision) < 0 - || SMW_B(m, (BYTE)rr_active) < 0 - || SMW_B(m, (BYTE)rr_frozen) < 0 - || SMW_B(m, (BYTE)rr_cmode) < 0 - || SMW_B(m, (BYTE)rr_clockport_enabled) < 0 - || SMW_B(m, (BYTE)rr_bank) < 0 - || SMW_B(m, (BYTE)write_once) < 0 - || SMW_B(m, (BYTE)allow_bank) < 0 - || SMW_B(m, (BYTE)no_freeze) < 0 - || SMW_B(m, (BYTE)reu_mapping) < 0 - || SMW_B(m, (BYTE)export_ram_at_a000) < 0 - || SMW_B(m, (BYTE)rr_hw_flashjumper) < 0 - || SMW_B(m, (BYTE)rr_hw_bankjumper) < 0 - || SMW_DW(m, (DWORD)rom_offset) < 0 + || SMW_B(m, (uint8_t)rr_revision) < 0 + || SMW_B(m, (uint8_t)rr_active) < 0 + || SMW_B(m, (uint8_t)rr_frozen) < 0 + || SMW_B(m, (uint8_t)rr_cmode) < 0 + || SMW_B(m, (uint8_t)rr_clockport_enabled) < 0 + || SMW_B(m, (uint8_t)rr_bank) < 0 + || SMW_B(m, (uint8_t)write_once) < 0 + || SMW_B(m, (uint8_t)allow_bank) < 0 + || SMW_B(m, (uint8_t)no_freeze) < 0 + || SMW_B(m, (uint8_t)reu_mapping) < 0 + || SMW_B(m, (uint8_t)export_ram_at_a000) < 0 + || SMW_B(m, (uint8_t)rr_hw_flashjumper) < 0 + || SMW_B(m, (uint8_t)rr_hw_bankjumper) < 0 + || SMW_DW(m, (uint32_t)rom_offset) < 0 || SMW_BA(m, roml_banks, 0x20000) < 0 || SMW_BA(m, export_ram0, 0x8000) < 0) { snapshot_module_close(m); @@ -1316,9 +1374,9 @@ int retroreplay_snapshot_write_module(snapshot_t *s) int retroreplay_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; - DWORD temp_rom_offset; + uint32_t temp_rom_offset; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -1327,13 +1385,13 @@ int retroreplay_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &rr_revision) < 0) { goto fail; } @@ -1346,7 +1404,7 @@ int retroreplay_snapshot_read_module(snapshot_t *s) } /* new in 0.2 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (SMR_B_INT(m, &rr_frozen) < 0) { goto fail; } @@ -1355,7 +1413,7 @@ int retroreplay_snapshot_read_module(snapshot_t *s) } /* new in 0.3 */ - if (SNAPVAL(vmajor, vminor, 0, 3)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 3)) { if (SMR_B_INT(m, &rr_cmode) < 0) { goto fail; } @@ -1374,7 +1432,7 @@ int retroreplay_snapshot_read_module(snapshot_t *s) } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &export_ram_at_a000) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/retroreplay.h b/src/Emulators/vice/c64/cart/retroreplay.h index c54312d2..325c5899 100644 --- a/src/Emulators/vice/c64/cart/retroreplay.h +++ b/src/Emulators/vice/c64/cart/retroreplay.h @@ -30,6 +30,8 @@ #endif #endif +#ifdef CARTRIDGE_INCLUDE_PRIVATE_API + #ifndef VICE_RETROREPLAY_H #define VICE_RETROREPLAY_H @@ -39,39 +41,46 @@ struct snapshot_s; +uint8_t retroreplay_roml_read(uint16_t addr); +void retroreplay_roml_store(uint16_t addr, uint8_t value); +uint8_t retroreplay_a000_bfff_read(uint16_t addr); +void retroreplay_a000_bfff_store(uint16_t addr, uint8_t value); +int retroreplay_roml_no_ultimax_store(uint16_t addr, uint8_t value); +uint8_t retroreplay_romh_read(uint16_t addr); +void retroreplay_romh_store(uint16_t addr, uint8_t value); +int retroreplay_peek_mem(export_t *export, uint16_t addr, uint8_t *value); +void retroreplay_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +void retroreplay_freeze(void); +int retroreplay_freeze_allowed(void); + +void retroreplay_config_init(void); +void retroreplay_reset(void); +void retroreplay_config_setup(uint8_t *rawcart); +int retroreplay_bin_attach(const char *filename, uint8_t *rawcart); +int retroreplay_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename, uint8_t revision); +int retroreplay_bin_save(const char *filename); +int retroreplay_crt_save(const char *filename); +int retroreplay_flush_image(void); +void retroreplay_detach(void); +void retroreplay_powerup(void); + +int retroreplay_cart_enabled(void); + +int retroreplay_cmdline_options_init(void); +int retroreplay_resources_init(void); +void retroreplay_resources_shutdown(void); + +int retroreplay_snapshot_write_module(struct snapshot_s *s); +int retroreplay_snapshot_read_module(struct snapshot_s *s); + +#endif /* VICE_RETROREPLAY_H */ +#endif /* CARTRIDGE_INCLUDE_PRIVATE_API */ + +#ifndef VICE_RETROREPLAY_PUBLIC_H +#define VICE_RETROREPLAY_PUBLIC_H + #define RR_REV_RETRO_REPLAY 0 #define RR_REV_NORDIC_REPLAY 1 -extern BYTE retroreplay_roml_read(WORD addr); -extern void retroreplay_roml_store(WORD addr, BYTE value); -extern BYTE retroreplay_a000_bfff_read(WORD addr); -extern void retroreplay_a000_bfff_store(WORD addr, BYTE value); -extern int retroreplay_roml_no_ultimax_store(WORD addr, BYTE value); -extern BYTE retroreplay_romh_read(WORD addr); -extern void retroreplay_romh_store(WORD addr, BYTE value); -extern int retroreplay_peek_mem(export_t *export, WORD addr, BYTE *value); -extern void retroreplay_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); - -extern void retroreplay_freeze(void); -extern int retroreplay_freeze_allowed(void); - -extern void retroreplay_config_init(void); -extern void retroreplay_reset(void); -extern void retroreplay_config_setup(BYTE *rawcart); -extern int retroreplay_bin_attach(const char *filename, BYTE *rawcart); -extern int retroreplay_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern int retroreplay_bin_save(const char *filename); -extern int retroreplay_crt_save(const char *filename); -extern int retroreplay_flush_image(void); -extern void retroreplay_detach(void); - -extern int retroreplay_cart_enabled(void); - -extern int retroreplay_cmdline_options_init(void); -extern int retroreplay_resources_init(void); -extern void retroreplay_resources_shutdown(void); - -extern int retroreplay_snapshot_write_module(struct snapshot_s *s); -extern int retroreplay_snapshot_read_module(struct snapshot_s *s); - -#endif +#endif /* VICE_RETROREPLAY_PUBLIC_H */ diff --git a/src/Emulators/vice/c64/cart/reu.c b/src/Emulators/vice/c64/cart/reu.c index 4790ff61..cde5e071 100644 --- a/src/Emulators/vice/c64/cart/reu.c +++ b/src/Emulators/vice/c64/cart/reu.c @@ -1,12 +1,11 @@ -/*! \file reu.c \n - * \author Andreas Boose, Spiro Trikaliotis, Jouko Valta, Richard Hable, Ettore Perazzoli\n - * \brief REU emulation. +/** \file reu.c + * \brief REU emulation * - * reu.c - REU emulation. - * - * Written by - * Andreas Boose - * Spiro Trikaliotis + * \author Andreas Boose + * \author Spiro Trikaliotis + * \author Jouko Valta + * \author Richard Hable + * \author Ettore Perazzoli * * Additions upon extensive REU hardware testing: * Wolfgang Moser @@ -15,7 +14,9 @@ * Jouko Valta * Richard Hable * Ettore Perazzoli - * + */ + +/* * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -43,6 +44,7 @@ #include #include +#include "alarm.h" #include "archdep.h" #include "cartio.h" #include "cartridge.h" @@ -54,12 +56,13 @@ #include "machine.h" #include "maincpu.h" #include "mem.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" #define CARTRIDGE_INCLUDE_PRIVATE_API #include "reu.h" @@ -186,23 +189,23 @@ enum { /*! \brief define a complete set of REC registers */ struct rec_s { - BYTE status; /*!< status register at offset REU_REG_R_STATUS */ - BYTE command; /*!< command register at offset REU_REG_RW_COMMAND */ + uint8_t status; /*!< status register at offset REU_REG_R_STATUS */ + uint8_t command; /*!< command register at offset REU_REG_RW_COMMAND */ - WORD base_computer; /*!< C64 base address as defined at offsets REU_REG_RW_BASEADDR_LOW and REU_REG_RW_BASEADDR_HIGH */ - WORD base_reu; /*!< REU base address as defined at offsets REU_REG_RW_RAMADDR_LOW and REU_REG_RW_RAMADDR_HIGH */ - BYTE bank_reu; /*!< REU bank address as defined at offset REU_REG_RW_BANK */ - WORD transfer_length; /*!< transfer length as defined at offsets REU_REG_RW_BLOCKLEN_LOW and REU_REG_RW_BLOCKLEN_HIGH */ + uint16_t base_computer; /*!< C64 base address as defined at offsets REU_REG_RW_BASEADDR_LOW and REU_REG_RW_BASEADDR_HIGH */ + uint16_t base_reu; /*!< REU base address as defined at offsets REU_REG_RW_RAMADDR_LOW and REU_REG_RW_RAMADDR_HIGH */ + uint8_t bank_reu; /*!< REU bank address as defined at offset REU_REG_RW_BANK */ + uint16_t transfer_length; /*!< transfer length as defined at offsets REU_REG_RW_BLOCKLEN_LOW and REU_REG_RW_BLOCKLEN_HIGH */ - BYTE int_mask_reg; /*! interrupt mask register as defined at offset REU_REG_RW_INTERRUPT */ - BYTE address_control_reg; /*! address control register as defined at offset REU_REG_RW_ADDR_CONTROL */ + uint8_t int_mask_reg; /*! interrupt mask register as defined at offset REU_REG_RW_INTERRUPT */ + uint8_t address_control_reg; /*! address control register as defined at offset REU_REG_RW_ADDR_CONTROL */ /* shadow registers for implementing the "Half-Autoload-Bug" */ - WORD base_computer_shadow; /*!< shadow register of base_computer */ - WORD base_reu_shadow; /*!< shadow register of base_reu */ - BYTE bank_reu_shadow; /*!< shadow register of bank_reu */ - WORD transfer_length_shadow; /*!< shadow register of transfer_length */ + uint16_t base_computer_shadow; /*!< shadow register of base_computer */ + uint16_t base_reu_shadow; /*!< shadow register of base_reu */ + uint8_t bank_reu_shadow; /*!< shadow register of bank_reu */ + uint16_t transfer_length_shadow; /*!< shadow register of transfer_length */ }; /*! \brief a complete REC description */ @@ -214,8 +217,8 @@ struct rec_options_s { unsigned int dram_wrap_around; /*!< address where the dram address space has a wrap around */ unsigned int not_backedup_addresses; /*!< beginning from this address up to wrap_around, there is no DRAM at all */ unsigned int wrap_around_mask_when_storing; /*!< mask for the wrap around of REU address when putting result back in base_reu and bank_reu */ - BYTE reg_bank_unused; /*!< the unused bits (stuck at 1) of REU_REG_RW_BANK; for original REU, it is REU_REG_RW_BANK_UNUSED */ - BYTE status_preset; /*!< preset value for the status (can be 0 or REU_REG_R_STATUS_256K_CHIPS) */ + uint8_t reg_bank_unused; /*!< the unused bits (stuck at 1) of REU_REG_RW_BANK; for original REU, it is REU_REG_RW_BANK_UNUSED */ + uint8_t status_preset; /*!< preset value for the status (can be 0 or REU_REG_R_STATUS_256K_CHIPS) */ }; #define REU_REG_FIRST_UNUSED REU_REG_RW_UNUSED /*!< the highest address the used REU register occupy */ @@ -227,12 +230,12 @@ static struct rec_options_s rec_options; static int reu_dma_active = 0; /*! \brief pointer to a buffer which holds the REU image. */ -static BYTE *reu_ram = NULL; +static uint8_t *reu_ram = NULL; /*! \brief the old ram size of reu_ram. Used to determine if and how much of the buffer has to cleared when resizing the REU. */ static unsigned int old_reu_ram_size = 0; -static log_t reu_log = LOG_ERR; /*!< the log output for the REU */ +static log_t reu_log = LOG_DEFAULT; /*!< the log output for the REU */ static int reu_activate(void); static int reu_deactivate(void); @@ -241,40 +244,46 @@ static unsigned int reu_int_num; /*! \brief interface for BA interaction with CPU & VICII, used for x64sc */ struct reu_ba_s { - reu_ba_check_callback_t *check; - reu_ba_steal_callback_t *steal; - int *cpu_ba; - int cpu_ba_mask; - int enabled; - int delay, last_cycle; + reu_ba_check_callback_t *check; /*!< function that returns non zero when VICII uses the bus */ + reu_ba_steal_callback_t *steal; /*!< function that increments main clock as long as VICII uses the bus */ + int *cpu_ba; /*!< pointer to main cpu ba flags */ + int cpu_ba_mask; /*!< mask we should use in cpu_ba when REU DMA is active */ + /* internal */ + int enabled; /*!< flag that indicates if the above functions / variables have been registered, used to choose between x64 or x64sc hacks */ + int delay; + int last_cycle; }; static struct reu_ba_s reu_ba = { - NULL, NULL, NULL, 0, 0 + NULL, NULL, NULL, 0, 0, 0, 0 }; static int reu_write_image = 0; +static int floating_bus_value = 0xff; + /* ------------------------------------------------------------------------- */ /* some prototypes are needed */ -static void reu_io2_store(WORD addr, BYTE byte); -static BYTE reu_io2_read(WORD addr); -static BYTE reu_io2_peek(WORD addr); +static void reu_io2_store(uint16_t addr, uint8_t byte); +static uint8_t reu_io2_read(uint16_t addr); +static uint8_t reu_io2_peek(uint16_t addr); static io_source_t reu_io2_device = { - CARTRIDGE_NAME_REU, - IO_DETACH_RESOURCE, - "REU", - 0xdf00, 0xdfff, REU_REG_LAST_REG, - 0, - reu_io2_store, - reu_io2_read, - reu_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_REU, - IO_PRIO_HIGH, /* high priority so it will work together with cartridges like RR and SSV5 */ - 0 + CARTRIDGE_NAME_REU, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "REU", /* resource to set to '0' */ + 0xdf00, 0xdfff, REU_REG_LAST_REG, /* range for the device, regs:$df00-$df1f, mirrors:$df20-$dfff */ + 0, /* read validity is determined by the device upon a read */ + reu_io2_store, /* store function */ + NULL, /* NO poke function */ + reu_io2_read, /* read function */ + reu_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_REU, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *reu_list_item = NULL; @@ -333,6 +342,7 @@ int set_reu_enabled(int value, void *param) if (export_add(&export_res_reu) < 0) { return -1; } + reu_list_item = io_source_register(&reu_io2_device); reu_enabled = 1; } @@ -416,8 +426,8 @@ int set_reu_size(int val, void *param) case 8192: case 16384: rec_options.reg_bank_unused = 0; - rec_options.wrap_around_mask_when_storing = 0x00ffffff; - rec_options.dram_wrap_around = 0x01000000; + rec_options.dram_wrap_around = val * 1024; + rec_options.wrap_around_mask_when_storing = (val * 1024) - 1; break; default: log_message(reu_log, "Unknown REU size %d.", val); @@ -524,36 +534,24 @@ void reu_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-reu", SET_RESOURCE, 0, + { "-reu", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "REU", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_REU, - NULL, NULL }, - { "+reu", SET_RESOURCE, 0, + NULL, "Enable the RAM Expansion Unit" }, + { "+reu", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "REU", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_REU, - NULL, NULL }, - { "-reusize", SET_RESOURCE, 1, + NULL, "Disable the RAM Expansion Unit" }, + { "-reusize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "REUsize", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_SIZE_IN_KB, IDCLS_REU_SIZE, - NULL, NULL }, - { "-reuimage", SET_RESOURCE, 1, + "", "Size of the RAM expansion unit. (128/256/512/1024/2048/4096/8192/16384)" }, + { "-reuimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "REUfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_REU_NAME, - NULL, NULL }, - { "-reuimagerw", SET_RESOURCE, 0, + "", "Specify name of REU image" }, + { "-reuimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "REUImageWrite", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ALLOW_WRITING_TO_REU_IMAGE, - NULL, NULL }, - { "+reuimagerw", SET_RESOURCE, 0, + NULL, "Allow writing to REU image" }, + { "+reuimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "REUImageWrite", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DO_NOT_WRITE_TO_REU_IMAGE, - NULL, NULL }, + NULL, "Do not write to REU image" }, CMDLINE_LIST_END }; @@ -584,7 +582,7 @@ void reu_init(void) reu_int_num = interrupt_cpu_status_int_new(maincpu_int_status, "REU"); } -void reu_config_setup(BYTE *rawcart) +void reu_config_setup(uint8_t *rawcart) { if (reu_size > 0) { memcpy(reu_ram, rawcart, reu_size); /* FIXME */ @@ -621,8 +619,67 @@ void reu_reset(void) rec.address_control_reg = REU_REG_RW_ADDR_CONTROL_UNUSED_MASK; } +/* observed values from a 1764 REU with 256k */ +static RAMINITPARAM reuramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +static void invertblock(unsigned int addr, unsigned int len) +{ + unsigned int end = addr + len; + while (addr < end) { + if (addr >= reu_size) { + return; + } + reu_ram[addr] ^= 0xff; + addr++; + } +} + +static void reu_init_ram(void) +{ + unsigned int b, i; + DEBUG_LOG(DEBUG_LEVEL_REGISTER, (reu_log, "reu_init_ram")); + if (reu_ram) { + ram_init_with_pattern(reu_ram, reu_size, &reuramparam); + /* apply additional slightly odd invert pattern, observed by x1541 */ + for (b = 0; b < (reu_size >> 16); b += 4) { + for (i = 0; i < 2; i++) { + invertblock(0x002a00 + ((i + b) << 16), 0x2a00); + invertblock(0x008000 + ((i + b) << 16), 0x2c00); + invertblock(0x00d600 + ((i + b) << 16), 0x2a00); + } + for (i = 0; i < 2; i++) { + invertblock(0x020000 + ((i + b) << 16), 0x2a00); + invertblock(0x025400 + ((i + b) << 16), 0x2c00); + invertblock(0x02ac00 + ((i + b) << 16), 0x2a00); + } + } + } +} + +void reu_powerup(void) +{ + DEBUG_LOG(DEBUG_LEVEL_REGISTER, (reu_log, "reu_powerup")); + if ((reu_filename != NULL) && (*reu_filename != 0)) { + /* do not init ram if a file is used for ram content (like battery backup) */ + return; + } + reu_init_ram(); +} + static int reu_activate(void) { + DEBUG_LOG(DEBUG_LEVEL_REGISTER, (reu_log, "reu_activate")); if (!reu_size) { return 0; } @@ -630,13 +687,11 @@ static int reu_activate(void) reu_ram = lib_realloc(reu_ram, reu_size); /* Clear newly allocated RAM. */ - if (reu_size > old_reu_ram_size) { - memset(reu_ram, 0, (size_t)(reu_size - old_reu_ram_size)); - } + reu_init_ram(); old_reu_ram_size = reu_size; - log_message(reu_log, "%dKB unit installed.", reu_size >> 10); + log_message(reu_log, "%uKiB unit installed.", reu_size >> 10); LOGD("reu_filename=%s", reu_filename); @@ -694,19 +749,32 @@ int reu_enable(void) return set_reu_enabled(1, NULL); } -int reu_bin_attach(const char *filename, BYTE *rawcart) + +int reu_disable(void) +{ + set_reu_enabled(0, NULL); + reu_deactivate(); + return 0; +} + + +int reu_bin_attach(const char *filename, uint8_t *rawcart) { FILE *fd; - int size; + off_t size; fd = fopen(filename, MODE_READ); if (fd == NULL) { return -1; } - size = util_file_length(fd); + size = archdep_file_size(fd); + if (size < 0) { + fclose(fd); + return -1; + } fclose(fd); - if (set_reu_size(size / 1024, NULL) < 0) { + if (set_reu_size((uint32_t)size / 1024, NULL) < 0) { return -1; } @@ -714,7 +782,7 @@ int reu_bin_attach(const char *filename, BYTE *rawcart) return -1; } - if (util_file_load(filename, rawcart, size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + if (util_file_load(filename, rawcart, (size_t)size, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } @@ -750,21 +818,25 @@ int reu_flush_image(void) /* helper functions */ /*! \brief clock handling for x64 */ -inline static void reu_clk_inc_pre(void) +inline static void nonsc_reu_clk_inc_pre(void) { if (!reu_ba.enabled) { maincpu_clk++; - c64d_maincpu_clk++; + VICE_HOOK_CPU_CLK_INC(); } } /*! \brief clock handling for x64sc reu write */ -inline static void reu_clk_inc_post(void) +inline static void reu_clk_inc_post_write(void) { if (reu_ba.enabled) { maincpu_clk++; - c64d_maincpu_clk++; - if (reu_ba.check()) reu_ba.delay++; else reu_ba.delay = 0; + VICE_HOOK_CPU_CLK_INC(); + if (reu_ba.check()) { + reu_ba.delay++; + } else { + reu_ba.delay = 0; + } reu_ba.last_cycle = (reu_ba.delay > 1); if (reu_ba.last_cycle) { reu_ba.steal(); @@ -774,11 +846,13 @@ inline static void reu_clk_inc_post(void) } /*! \brief clock handling for x64sc reu read */ -inline static void reu_clk_inc_post2(void) +inline static void reu_clk_inc_post_read(void) { if (reu_ba.enabled) { + /* add one cycle */ maincpu_clk++; - c64d_maincpu_clk++; + VICE_HOOK_CPU_CLK_INC(); + /* steal more cycles while BA is pulled low by the VICII */ if (reu_ba.check()) { reu_ba.steal(); } @@ -799,9 +873,9 @@ inline static void reu_clk_inc_post2(void) \remark address must be in the valid range 0..0x1f */ -BYTE reu_read_without_sideeffects(WORD addr) +uint8_t reu_read_without_sideeffects(uint16_t addr) { - BYTE retval = 0xff; + uint8_t retval = 0xff; switch (addr) { case REU_REG_R_STATUS: @@ -858,7 +932,7 @@ BYTE reu_read_without_sideeffects(WORD addr) \remark address must be in the valid range 0..0x1f */ -static void reu_store_without_sideeffects(WORD addr, BYTE byte) +static void reu_store_without_sideeffects(uint16_t addr, uint8_t byte) { switch (addr) { case REU_REG_R_STATUS: @@ -911,9 +985,9 @@ static void reu_store_without_sideeffects(WORD addr, BYTE byte) \return The value the register has */ -static BYTE reu_io2_read(WORD addr) +static uint8_t reu_io2_read(uint16_t addr) { - BYTE retval = 0xff; + uint8_t retval = 0xff; if (reu_dma_active) { reu_io2_device.io_source_valid = 0; @@ -947,9 +1021,9 @@ static BYTE reu_io2_read(WORD addr) return retval; } -static BYTE reu_io2_peek(WORD addr) +static uint8_t reu_io2_peek(uint16_t addr) { - BYTE retval = 0xff; + uint8_t retval = 0xff; if (addr < REU_REG_FIRST_UNUSED) { retval = reu_read_without_sideeffects(addr); } @@ -965,7 +1039,7 @@ static BYTE reu_io2_peek(WORD addr) \param byte The value to set the register to */ -void reu_io2_store(WORD addr, BYTE byte) +void reu_io2_store(uint16_t addr, uint8_t byte) { if (!reu_dma_active && (addr < REU_REG_FIRST_UNUSED)) { reu_store_without_sideeffects(addr, byte); @@ -1029,7 +1103,6 @@ inline static unsigned int increment_reu_with_wrap_around(unsigned int reu_addr, if (next == rec_options.wrap_around) { next = 0; } - return (reu_addr & 0x00f80000) | next; } @@ -1047,7 +1120,7 @@ inline static unsigned int increment_reu_with_wrap_around(unsigned int reu_addr, If the location reu_addr is not backed up by DRAM, the store is simply ignored. */ -inline static void store_to_reu(unsigned int reu_addr, BYTE value) +inline static void store_to_reu(unsigned int reu_addr, uint8_t value) { reu_addr &= rec_options.dram_wrap_around - 1; if (reu_addr < rec_options.not_backedup_addresses) { @@ -1075,18 +1148,19 @@ inline static void store_to_reu(unsigned int reu_addr, BYTE value) \todo Check the values a real 17xx returns. */ -inline static BYTE read_from_reu(unsigned int reu_addr) +inline static uint8_t read_from_reu(unsigned int reu_addr) { - BYTE value = 0xff; /* dummy value to return if not DRAM is available */ + uint8_t value; reu_addr &= rec_options.dram_wrap_around - 1; if (reu_addr < rec_options.not_backedup_addresses) { + /* this is a valid read */ assert(reu_addr < reu_size); value = reu_ram[reu_addr]; } else { DEBUG_LOG(DEBUG_LEVEL_NO_DRAM, (reu_log, "--> read from REU address %05X, but no DRAM!", reu_addr)); + value = floating_bus_value; } - return value; } @@ -1110,7 +1184,7 @@ inline static BYTE read_from_reu(unsigned int reu_addr) if autoload is enabled, the shadow registers are written back to the REU registers. */ -static void reu_dma_update_regs(WORD host_addr, unsigned int reu_addr, int len, BYTE new_status_or_mask) +static void reu_dma_update_regs(uint16_t host_addr, unsigned int reu_addr, int len, uint8_t new_status_or_mask) { assert(len >= 1); assert(new_status_or_mask != 0); @@ -1179,15 +1253,10 @@ static void reu_dma_update_regs(WORD host_addr, unsigned int reu_addr, int len, \param len The transfer length of the operation */ -static void reu_dma_host_to_reu(WORD host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) +static void reu_dma_host_to_reu(uint16_t host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) { - BYTE value; - - //LOGD("reu_dma_host_to_reu: >>>>> host_addr=%04x reu_addr=%06x host_step=%d reu_step=%d len=%d (%x)", - // host_addr, reu_addr, host_step, reu_step, len, len); - - - DEBUG_LOG(DEBUG_LEVEL_TRANSFER_HIGH_LEVEL, (reu_log, "copy ext $%05X %s<= main $%04X%s, $%04X (%d) bytes.", + uint8_t value; + DEBUG_LOG(DEBUG_LEVEL_TRANSFER_HIGH_LEVEL, (reu_log, "copy ext $%05X %s<= main $%04X%s, $%04X (%d) bytes.", reu_addr, reu_step ? "" : "(fixed) ", host_addr, host_step ? "" : " (fixed)", len, len)); assert(((host_step == 0) || (host_step == 1))); @@ -1195,10 +1264,10 @@ static void reu_dma_host_to_reu(WORD host_addr, unsigned int reu_addr, int host_ assert(len >= 1); while (len) { - reu_clk_inc_pre(); + nonsc_reu_clk_inc_pre(); machine_handle_pending_alarms(0); - value = mem_read(host_addr); - reu_clk_inc_post2(); + value = mem_dma_read(host_addr); + reu_clk_inc_post_read(); DEBUG_LOG(DEBUG_LEVEL_TRANSFER_LOW_LEVEL, (reu_log, "Transferring byte: %x from main $%04X to ext $%05X.", value, host_addr, reu_addr)); store_to_reu(reu_addr, value); @@ -1208,6 +1277,8 @@ static void reu_dma_host_to_reu(WORD host_addr, unsigned int reu_addr, int host_ } DEBUG_LOG(DEBUG_LEVEL_REGISTER2, (reu_log, "END OF BLOCK")); reu_dma_update_regs(host_addr, reu_addr, ++len, REU_REG_R_STATUS_END_OF_BLOCK); + /* the last value written to the REU will stay in the latch that drives the bus */ + floating_bus_value = value; } /*! \brief DMA operation writing from the REU to the host @@ -1227,11 +1298,9 @@ static void reu_dma_host_to_reu(WORD host_addr, unsigned int reu_addr, int host_ \param len The transfer length of the operation */ -static void reu_dma_reu_to_host(WORD host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) +static void reu_dma_reu_to_host(uint16_t host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) { - BYTE value; -// LOGD("reu_dma_reu_to_host <<<<< host_addr=%04x reu_addr=%06x host_step=%d reu_step=%d len=%d ($%x)", -// host_addr, reu_addr, host_step, reu_step, len, len); + uint8_t value; DEBUG_LOG(DEBUG_LEVEL_TRANSFER_HIGH_LEVEL, (reu_log, "copy ext $%05X %s=> main $%04X%s, $%04X (%d) bytes.", reu_addr, reu_step ? "" : "(fixed) ", host_addr, host_step ? "" : " (fixed)", len, len)); @@ -1241,10 +1310,12 @@ static void reu_dma_reu_to_host(WORD host_addr, unsigned int reu_addr, int host_ while (len) { DEBUG_LOG(DEBUG_LEVEL_TRANSFER_LOW_LEVEL, (reu_log, "Transferring byte: %x from ext $%05X to main $%04X.", reu_ram[reu_addr % reu_size], reu_addr, host_addr)); - reu_clk_inc_pre(); - value = read_from_reu(reu_addr); - mem_store(host_addr, value); - reu_clk_inc_post(); + nonsc_reu_clk_inc_pre(); + /* after a transfer from REU to host, the last (pre)fetched value from valid + REU RAM stays in the latch that drives the bus. see comment below. */ + floating_bus_value = value = read_from_reu(reu_addr); + mem_dma_store(host_addr, value); + reu_clk_inc_post_write(); machine_handle_pending_alarms(0); host_addr = (host_addr + host_step) & 0xffff; reu_addr = increment_reu_with_wrap_around(reu_addr, reu_step); @@ -1252,10 +1323,15 @@ static void reu_dma_reu_to_host(WORD host_addr, unsigned int reu_addr, int host_ } if (reu_ba.enabled && reu_ba.last_cycle) { /* extra cycle if ended while BA set */ machine_handle_pending_alarms(0); - reu_clk_inc_post2(); + reu_clk_inc_post_read(); } DEBUG_LOG(DEBUG_LEVEL_REGISTER2, (reu_log, "END OF BLOCK")); reu_dma_update_regs(host_addr, reu_addr, ++len, REU_REG_R_STATUS_END_OF_BLOCK); + /* after a transfer from REU to host, the last (pre)fetched value from valid + REU RAM stays in the latch that drives the bus. we can use read_from_reu() + here without an additional check, since it checks for the valid range + internally and will return the latched value for invalid addresses. */ + floating_bus_value = read_from_reu(reu_addr); } /*! \brief DMA operation swaping data between host and REU @@ -1275,12 +1351,10 @@ static void reu_dma_reu_to_host(WORD host_addr, unsigned int reu_addr, int host_ \param len The transfer length of the operation */ -static void reu_dma_swap(WORD host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) -{ - BYTE value_from_reu; - BYTE value_from_c64; -// LOGD("reu_dma_swap <<< >>> host_addr=%04x reu_addr=%06x host_step=%d reu_step=%d len=%d (%x)", -// host_addr, reu_addr, host_step, reu_step, len, len); +static void reu_dma_swap(uint16_t host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) +{ + uint8_t value_from_reu; + uint8_t value_from_c64; DEBUG_LOG(DEBUG_LEVEL_TRANSFER_HIGH_LEVEL, (reu_log, "swap ext $%05X %s<=> main $%04X%s, $%04X (%d) bytes.", reu_addr, reu_step ? "" : "(fixed) ", host_addr, host_step ? "" : " (fixed)", len, len)); @@ -1290,15 +1364,15 @@ static void reu_dma_swap(WORD host_addr, unsigned int reu_addr, int host_step, i while (len) { value_from_reu = read_from_reu(reu_addr); - reu_clk_inc_pre(); + nonsc_reu_clk_inc_pre(); machine_handle_pending_alarms(0); - value_from_c64 = mem_read(host_addr); - reu_clk_inc_post2(); + value_from_c64 = mem_dma_read(host_addr); + reu_clk_inc_post_read(); DEBUG_LOG(DEBUG_LEVEL_TRANSFER_LOW_LEVEL, (reu_log, "Exchanging bytes: %x from main $%04X with %x from ext $%05X.", value_from_c64, host_addr, value_from_reu, reu_addr)); store_to_reu(reu_addr, value_from_c64); - mem_store(host_addr, value_from_reu); - reu_clk_inc_pre(); - reu_clk_inc_post(); + mem_dma_store(host_addr, value_from_reu); + nonsc_reu_clk_inc_pre(); + reu_clk_inc_post_write(); machine_handle_pending_alarms(0); host_addr = (host_addr + host_step) & 0xffff; reu_addr = increment_reu_with_wrap_around(reu_addr, reu_step); @@ -1306,7 +1380,7 @@ static void reu_dma_swap(WORD host_addr, unsigned int reu_addr, int host_step, i } if (reu_ba.enabled && reu_ba.last_cycle) { /* extra cycle if ended while BA set */ machine_handle_pending_alarms(0); /* likely needed, but not confirmed yet */ - reu_clk_inc_post2(); + reu_clk_inc_post_read(); } DEBUG_LOG(DEBUG_LEVEL_REGISTER2, (reu_log, "END OF BLOCK")); reu_dma_update_regs(host_addr, reu_addr, ++len, REU_REG_R_STATUS_END_OF_BLOCK); @@ -1329,12 +1403,12 @@ static void reu_dma_swap(WORD host_addr, unsigned int reu_addr, int host_step, i \param len The transfer length of the operation */ -static void reu_dma_compare(WORD host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) +static void reu_dma_compare(uint16_t host_addr, unsigned int reu_addr, int host_step, int reu_step, int len) { - BYTE value_from_reu; - BYTE value_from_c64; + uint8_t value_from_reu; + uint8_t value_from_c64; - BYTE new_status_or_mask = 0; + uint8_t new_status_or_mask = 0; DEBUG_LOG(DEBUG_LEVEL_TRANSFER_HIGH_LEVEL, (reu_log, "compare ext $%05X %s<=> main $%04X%s, $%04X (%d) bytes.", reu_addr, reu_step ? "" : "(fixed) ", host_addr, host_step ? "" : " (fixed)", len, len)); @@ -1349,11 +1423,11 @@ static void reu_dma_compare(WORD host_addr, unsigned int reu_addr, int host_step /* rec.status &= ~ (REU_REG_R_STATUS_VERIFY_ERROR | REU_REG_R_STATUS_END_OF_BLOCK); */ while (len) { - reu_clk_inc_pre(); + nonsc_reu_clk_inc_pre(); machine_handle_pending_alarms(0); value_from_reu = read_from_reu(reu_addr); - value_from_c64 = mem_read(host_addr); - reu_clk_inc_post2(); + value_from_c64 = mem_dma_read(host_addr); + reu_clk_inc_post_read(); DEBUG_LOG(DEBUG_LEVEL_TRANSFER_LOW_LEVEL, (reu_log, "Comparing bytes: %x from main $%04X with %x from ext $%05X.", value_from_c64, host_addr, value_from_reu, reu_addr)); reu_addr = increment_reu_with_wrap_around(reu_addr, reu_step); host_addr = (host_addr + host_step) & 0xffff; @@ -1368,9 +1442,9 @@ static void reu_dma_compare(WORD host_addr, unsigned int reu_addr, int host_step * the failed comparison happened on the last byte of the buffer. */ if (len >= 1) { - reu_clk_inc_pre(); + nonsc_reu_clk_inc_pre(); machine_handle_pending_alarms(0); - reu_clk_inc_post2(); + reu_clk_inc_post_read(); } break; } @@ -1392,7 +1466,7 @@ static void reu_dma_compare(WORD host_addr, unsigned int reu_addr, int host_step */ value_from_reu = read_from_reu(reu_addr); - value_from_c64 = mem_read(host_addr); + value_from_c64 = mem_dma_read(host_addr); DEBUG_LOG(DEBUG_LEVEL_TRANSFER_LOW_LEVEL, (reu_log, "Comparing bytes after verify error: %x from main $%04X with %x from ext $%05X.", value_from_c64, host_addr, value_from_reu, reu_addr)); if (value_from_reu == value_from_c64) { @@ -1428,41 +1502,45 @@ static void reu_dma_compare(WORD host_addr, unsigned int reu_addr, int host_step If it has been previously armed (with immediate == 0), then the DMA operation is executed. */ -void reu_dma(int immediate) +int reu_dma(int immediate) { static int delay = 0; LOGD("reu_dma immediate=%d", immediate); if (!reu_enabled) { - return; + return 0; } if (!immediate) { delay = 1; - return; + return 0; } else { if (!delay && immediate < 0) { - return; + return 0; } delay = 0; } if (reu_ba.enabled) { + /* REU DMA on x64sc */ /* signal CPU that BA is pulled low */ *(reu_ba.cpu_ba) |= reu_ba.cpu_ba_mask; reu_ba.delay = 0; reu_ba.last_cycle = 0; } else { + /* REU DMA on x64 */ /* start the operation right away */ reu_dma_start(); } + + return 1; } void reu_dma_start(void) { int len; int reu_step, host_step; - WORD host_addr; + uint16_t host_addr; unsigned int reu_addr; // LOGD("reu_dma_start"); @@ -1508,7 +1586,7 @@ void reu_dma_start(void) ARRAY | RAM | 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608 or 16777216 BYTES of RAM data */ -static char snap_module_name[] = "REU1764"; /*!< the name of the module for the snapshot */ +static const char snap_module_name[] = "REU1764"; /*!< the name of the module for the snapshot */ #define SNAP_MAJOR 0 /*!< version number for this module, major number */ #define SNAP_MINOR 0 /*!< version number for this module, minor number */ @@ -1518,7 +1596,7 @@ static char snap_module_name[] = "REU1764"; /*!< the name of the module for the compatible with the original implementation. Otherwise, we would have to change the version number. This way, it is much simpler. */ -typedef BYTE reu_as_stored_in_snapshot_t[16]; +typedef uint8_t reu_as_stored_in_snapshot_t[16]; /*! \brief write the REU module data to the snapshot \param s @@ -1532,7 +1610,7 @@ int reu_write_snapshot_module(snapshot_t *s, int store_reu_data) snapshot_module_t *m; reu_as_stored_in_snapshot_t reu; - WORD reu_address; + uint16_t reu_address; memset(reu, 0xff, sizeof reu); @@ -1587,12 +1665,12 @@ int reu_write_snapshot_module(snapshot_t *s, int store_reu_data) */ int reu_read_snapshot_module(snapshot_t *s, int read_reu_data) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; - DWORD size; + uint32_t size; reu_as_stored_in_snapshot_t reu; - WORD reu_address; + uint16_t reu_address; memset(reu, 0xff, sizeof reu); @@ -1602,7 +1680,7 @@ int reu_read_snapshot_module(snapshot_t *s, int read_reu_data) } /* Do not accept versions higher than current */ - if (major_version > SNAP_MAJOR || minor_version > SNAP_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/reu.h b/src/Emulators/vice/c64/cart/reu.h index e2cee899..8a3015ff 100644 --- a/src/Emulators/vice/c64/cart/reu.h +++ b/src/Emulators/vice/c64/cart/reu.h @@ -36,31 +36,33 @@ struct snapshot_s; -extern void reu_init(void); -extern int reu_resources_init(void); -extern void reu_resources_shutdown(void); -extern int reu_cmdline_options_init(void); +void reu_init(void); +int reu_resources_init(void); +void reu_resources_shutdown(void); +int reu_cmdline_options_init(void); typedef int reu_ba_check_callback_t (void); typedef void reu_ba_steal_callback_t (void); -extern void reu_ba_register(reu_ba_check_callback_t *ba_check, - reu_ba_steal_callback_t *ba_steal, - int *ba_var, int ba_mask); +void reu_ba_register(reu_ba_check_callback_t *ba_check, + reu_ba_steal_callback_t *ba_steal, + int *ba_var, int ba_mask); -extern void reu_reset(void); -extern void reu_dma(int immed); -extern void reu_dma_start(void); -extern void reu_detach(void); -extern int reu_enable(void); -extern int reu_read_snapshot_module(struct snapshot_s *s, int read_reu_data); -extern int reu_write_snapshot_module(struct snapshot_s *s, int store_reu_data); +void reu_reset(void); +int reu_dma(int immed); +void reu_dma_start(void); +void reu_detach(void); +int reu_enable(void); +int reu_disable(void); +int reu_read_snapshot_module(struct snapshot_s *s, int read_reu_data); +int reu_write_snapshot_module(struct snapshot_s *s, int store_reu_data); -extern int reu_cart_enabled(void); -extern void reu_config_setup(BYTE *rawcart); -extern const char *reu_get_file_name(void); -extern int reu_bin_attach(const char *filename, BYTE *rawcart); -extern int reu_bin_save(const char *filename); -extern int reu_flush_image(void); +int reu_cart_enabled(void); +void reu_config_setup(uint8_t *rawcart); +const char *reu_get_file_name(void); +int reu_bin_attach(const char *filename, uint8_t *rawcart); +int reu_bin_save(const char *filename); +int reu_flush_image(void); +void reu_powerup(void); #endif diff --git a/src/Emulators/vice/c64/cart/rexep256.c b/src/Emulators/vice/c64/cart/rexep256.c index d000ae56..d5f789be 100644 --- a/src/Emulators/vice/c64/cart/rexep256.c +++ b/src/Emulators/vice/c64/cart/rexep256.c @@ -79,15 +79,15 @@ /* ---------------------------------------------------------------------*/ -static WORD rexep256_eprom[8]; -static BYTE rexep256_eprom_roml_bank_offset[8]; -static BYTE regval = 0; +static uint16_t rexep256_eprom[8]; +static uint8_t rexep256_eprom_roml_bank_offset[8]; +static uint8_t regval = 0; /* ---------------------------------------------------------------------*/ -static void rexep256_io2_store(WORD addr, BYTE value) +static void rexep256_io2_store(uint16_t addr, uint8_t value) { - BYTE eprom_bank, test_value, eprom_part = 0; + uint8_t eprom_bank, test_value, eprom_part = 0; if ((addr & 0xff) == 0xa0) { regval = value; @@ -117,7 +117,7 @@ static void rexep256_io2_store(WORD addr, BYTE value) /* I'm unsure whether the register is write-only, but in this case it is assumed to be. */ -static BYTE rexep256_io2_read(WORD addr) +static uint8_t rexep256_io2_read(uint16_t addr) { if ((addr & 0xff) == 0xc0) { cart_set_port_exrom_slotmain(0); @@ -130,7 +130,7 @@ static BYTE rexep256_io2_read(WORD addr) return 0; } -static BYTE rexep256_io2_peek(WORD addr) +static uint8_t rexep256_io2_peek(uint16_t addr) { return regval; } @@ -146,18 +146,20 @@ static int rexep256_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t rexep256_device = { - CARTRIDGE_NAME_REX_EP256, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - rexep256_io2_store, - rexep256_io2_read, - rexep256_io2_peek, - rexep256_dump, - CARTRIDGE_REX_EP256, - 0, - 0 + CARTRIDGE_NAME_REX_EP256, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$dfa0/$dfc0/$dfe0 */ + 0, /* read is never valid, regs are write only */ + rexep256_io2_store, /* store function */ + NULL, /* NO poke function */ + rexep256_io2_read, /* read function */ + rexep256_io2_peek, /* peek function */ + rexep256_dump, /* device state information dump function */ + CARTRIDGE_REX_EP256, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *rexep256_list_item = NULL; @@ -170,14 +172,14 @@ static const export_resource_t export_res = { void rexep256_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } -void rexep256_config_setup(BYTE *rawcart) +void rexep256_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x42000); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); } @@ -192,7 +194,7 @@ static int rexep256_common_attach(void) } /* FIXME: handle the various combinations / possible file lengths */ -int rexep256_bin_attach(const char *filename, BYTE *rawcart) +int rexep256_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -200,7 +202,7 @@ int rexep256_bin_attach(const char *filename, BYTE *rawcart) return rexep256_common_attach(); } -int rexep256_crt_attach(FILE *fd, BYTE *rawcart) +int rexep256_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int rexep256_total_size = 0; @@ -269,7 +271,7 @@ void rexep256_detach(void) ARRAY | ROML | 0.0+ | 270336 BYTES of ROML data */ -static char snap_module_name[] = "CARTREXEP256"; +static const char snap_module_name[] = "CARTREXEP256"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -297,7 +299,7 @@ int rexep256_snapshot_write_module(snapshot_t *s) int rexep256_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -307,13 +309,13 @@ int rexep256_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/rexep256.h b/src/Emulators/vice/c64/cart/rexep256.h index 05429932..6fee0841 100644 --- a/src/Emulators/vice/c64/cart/rexep256.h +++ b/src/Emulators/vice/c64/cart/rexep256.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void rexep256_config_init(void); -extern void rexep256_config_setup(BYTE *rawcart); -extern int rexep256_bin_attach(const char *filename, BYTE *rawcart); -extern int rexep256_crt_attach(FILE *fd, BYTE *rawcart); -extern void rexep256_detach(void); +void rexep256_config_init(void); +void rexep256_config_setup(uint8_t *rawcart); +int rexep256_bin_attach(const char *filename, uint8_t *rawcart); +int rexep256_crt_attach(FILE *fd, uint8_t *rawcart); +void rexep256_detach(void); struct snapshot_s; -extern int rexep256_snapshot_write_module(struct snapshot_s *s); -extern int rexep256_snapshot_read_module(struct snapshot_s *s); +int rexep256_snapshot_write_module(struct snapshot_s *s); +int rexep256_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/rexramfloppy.c b/src/Emulators/vice/c64/cart/rexramfloppy.c new file mode 100644 index 00000000..20b75840 --- /dev/null +++ b/src/Emulators/vice/c64/cart/rexramfloppy.c @@ -0,0 +1,532 @@ +/* + * rexramfloppy.c - Cartridge handling, REX Ramfloppy cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "rexramfloppy.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "export.h" +#include "lib.h" +#include "monitor.h" +#include "ram.h" +#include "resources.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* 256KB of RAM */ +#define RRF_RAM_SIZE 256*1024 + +#define RRF_NO_FORCE_SAVE 0 +#define RRF_FORCE_SAVE 1 + +/* #define DEBUGRF */ + +#ifdef DEBUGRF +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + REX RAM-Floppy + + 8k ROM + 32k up to 256k RAM (Battery buffered) + + dfa0 (write) selects RAM bank + + df50 (read) toggles RAM writeable + dfc0 (read) toggles cartridge enable + dfe0 (read) toggles RAM enable + + TODO: + - implement the disable switch + - implement RAM size option +*/ + +static int ram_bank = 0; +static int ram_enabled = 0; +static int cart_enabled = 1; +static int ram_writeable = 0; + +/* RAM image. */ +static uint8_t *rexramfloppy_ram = NULL; + +/* Filename of the RAM image. */ +static char *rexramfloppy_filename = NULL; + +/* Write image on detach */ +static int rexramfloppy_write_image = 0; + +/* ---------------------------------------------------------------------*/ + +/* some prototypes are needed */ +static uint8_t rexramfloppy_io2_peek(uint16_t addr); +static uint8_t rexramfloppy_io2_read(uint16_t addr); +static void rexramfloppy_io2_store(uint16_t addr, uint8_t value); +static int rexramfloppy_dump(void); + +static io_source_t rexramfloppy_io2_device = { + CARTRIDGE_NAME_REX_RAMFLOPPY, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range of the device */ + 0, /* read validity is determined by the device upon a read */ + rexramfloppy_io2_store, /* store function */ + NULL, /* NO poke function */ + rexramfloppy_io2_read, /* read function */ + rexramfloppy_io2_peek, /* peek function */ + rexramfloppy_dump, /* device state information dump function */ + CARTRIDGE_REX_RAMFLOPPY, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *rexramfloppy_io2_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_REX_RAMFLOPPY, 0, 1, NULL, &rexramfloppy_io2_device, CARTRIDGE_REX_RAMFLOPPY +}; + +/* ---------------------------------------------------------------------*/ + +static uint8_t rexramfloppy_io2_peek(uint16_t addr) +{ + return 0; /* FIXME */ +} + +static uint8_t rexramfloppy_io2_read(uint16_t addr) +{ + + addr &= 0xff; + + switch (addr) { + case 0x50: + ram_writeable ^= 1; + break; + case 0xc0: + cart_enabled ^= 1; + if (cart_enabled) { + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + } else { + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_READ); + } + break; + case 0xe0: + ram_enabled ^= 1; + break; + default: + /* printf("io2 read %04x\n", addr); */ + break; + } + + return 0; +} + +static void rexramfloppy_io2_store(uint16_t addr, uint8_t value) +{ + + addr &= 0xff; + + switch (addr) { + case 0xa0: + ram_bank = (value & 7) | ((value & 0x30) >> 1); + break; + default: + /* printf("io2 write %04x %02x\n", addr, value); */ + break; + } +} + +static int rexramfloppy_dump(void) +{ + mon_out("mode: %s\n", (cart_enabled) ? "8K Game" : "RAM"); + mon_out("$8000-$9FFF: %s\n", (ram_enabled) ? "RAM" : "ROM"); + mon_out("RAM bank: %d\n", ram_bank); + mon_out("RAM writeable: %s\n", ram_writeable ? "yes" : "no"); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +uint8_t rexramfloppy_roml_read(uint16_t addr) +{ + if (ram_enabled) { + return rexramfloppy_ram[(addr & 0x1fff) + (ram_bank * 0x2000)]; + } + + return roml_banks[addr & 0x1fff]; +} + +void rexramfloppy_roml_store(uint16_t addr, uint8_t value) +{ + if (ram_enabled && ram_writeable) { + rexramfloppy_ram[(addr & 0x1fff) + (ram_bank * 0x2000)] = value; + } else { + mem_store_without_romlh(addr, value); + } +} + +/* ---------------------------------------------------------------------*/ + +void rexramfloppy_config_init(void) +{ + cart_enabled = 1; + ram_writeable = 0; + ram_enabled = 0; + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +void rexramfloppy_reset(void) +{ + cart_enabled = 1; + ram_writeable = 0; + ram_enabled = 0; +} + +void rexramfloppy_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000); + memset(export_ram0, 0xff, 0x2000 * 32); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int rexramfloppy_load_ram_image(void) +{ + if (!util_check_null_string(rexramfloppy_filename)) { + if (util_file_load(rexramfloppy_filename, rexramfloppy_ram, RRF_RAM_SIZE, UTIL_FILE_LOAD_RAW) < 0) { + /* only create a new file if no file exists, so we dont accidently overwrite any files */ + if (!util_file_exists(rexramfloppy_filename)) { + if (util_file_save(rexramfloppy_filename, rexramfloppy_ram, RRF_RAM_SIZE) < 0) { + return -1; + } + } + } + } + return 0; +} + +static int rexramfloppy_save_ram_image(int force) +{ + if (!util_check_null_string(rexramfloppy_filename)) { + if (rexramfloppy_write_image || force) { + if (util_file_save(rexramfloppy_filename, rexramfloppy_ram, RRF_RAM_SIZE) < 0) { + return -1; + } + } + } + return 0; +} + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +static int rexramfloppy_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + + rexramfloppy_ram = lib_malloc(RRF_RAM_SIZE); + ram_init_with_pattern(rexramfloppy_ram, RRF_RAM_SIZE, &ramparam); + + if (rexramfloppy_load_ram_image() < 0) { + lib_free(rexramfloppy_ram); + return -1; + } + + rexramfloppy_io2_list_item = io_source_register(&rexramfloppy_io2_device); + + return 0; +} + +int rexramfloppy_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + + return rexramfloppy_common_attach(); +} + +int rexramfloppy_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.bank > 0 || chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return rexramfloppy_common_attach(); +} + +void rexramfloppy_detach(void) +{ + export_remove(&export_res); + io_source_unregister(rexramfloppy_io2_list_item); + rexramfloppy_io2_list_item = NULL; + + rexramfloppy_save_ram_image(RRF_NO_FORCE_SAVE); + + lib_free(rexramfloppy_ram); + rexramfloppy_ram = NULL; +} + +int rexramfloppy_ram_flush(void) +{ + if (rexramfloppy_ram) { + return rexramfloppy_save_ram_image(RRF_FORCE_SAVE); + } + return 0; +} + +int rexramfloppy_can_flush_ram(void) +{ + if (rexramfloppy_ram) { + return 1; + } + return 0; +} + +int rexramfloppy_ram_save(const char *filename) +{ + if (!rexramfloppy_ram) { + return -1; + } + + if (filename == NULL) { + return -1; + } + + if (util_file_save(filename, rexramfloppy_ram, RRF_RAM_SIZE) < 0) { + return -1; + } + + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static int set_rexramfloppy_filename(const char *name, void *param) +{ + if (rexramfloppy_filename != NULL && name != NULL && strcmp(name, rexramfloppy_filename) == 0) { + return 0; + } + + if (name != NULL && *name != '\0') { + if (util_check_filename_access(name) < 0) { + return -1; + } + } + + if (rexramfloppy_ram) { + rexramfloppy_save_ram_image(RRF_NO_FORCE_SAVE); + util_string_set(&rexramfloppy_filename, name); + rexramfloppy_load_ram_image(); + } else { + util_string_set(&rexramfloppy_filename, name); + } + + return 0; +} + +static int set_rexramfloppy_image_write(int val, void *param) +{ + rexramfloppy_write_image = val ? 1 : 0; + + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static const resource_string_t resources_string[] = { + { "RRFfilename", "", RES_EVENT_NO, NULL, + &rexramfloppy_filename, set_rexramfloppy_filename, NULL }, + RESOURCE_STRING_LIST_END +}; + +static const resource_int_t resources_int[] = { + { "RRFImageWrite", 0, RES_EVENT_NO, NULL, + &rexramfloppy_write_image, set_rexramfloppy_image_write, NULL }, + RESOURCE_INT_LIST_END +}; + +int rexramfloppy_resources_init(void) +{ + if (resources_register_string(resources_string) < 0) { + return -1; + } + + return resources_register_int(resources_int); +} + +void rexramfloppy_resources_shutdown(void) +{ + lib_free(rexramfloppy_filename); + rexramfloppy_filename = NULL; +} + +/* ------------------------------------------------------------------------- */ + +static const cmdline_option_t cmdline_options[] = +{ + { "-rexramfloppyimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RRFfilename", NULL, + "", "Specify REX RAM-Floppy filename" }, + { "-rexramfloppyimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RRFImageWrite", (resource_value_t)1, + NULL, "Allow writing to REX RAM-Floppy image" }, + { "+rexramfloppyimagerw", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "RRFImageWrite", (resource_value_t)0, + NULL, "Do not write to REX RAM-Floppy image" }, + CMDLINE_LIST_END +}; + +int rexramfloppy_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} + +/* ------------------------------------------------------------------------- */ + +/* CARTRRF snapshot module format: + + type | name | description + --------------------------------- + BYTE | cart_enabled | cartridge active flag + BYTE | ram_enabled | RAM enabled at $8000 + BYTE | ram_writeable | RAM is writeable + BYTE | ram_bank | currently selected RAM bank + ARRAY | ROML | 8192 BYTES of ROML data + ARRAY | RAM | 256k BYTES of RAM data + */ + +static const char snap_module_name[] = "CARTRRF"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int rexramfloppy_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)cart_enabled) < 0) + || (SMW_B(m, (uint8_t)ram_enabled) < 0) + || (SMW_B(m, (uint8_t)ram_writeable) < 0) + || (SMW_B(m, (uint8_t)ram_bank) < 0) + || (SMW_BA(m, roml_banks, 0x2000) < 0) + || (SMW_BA(m, rexramfloppy_ram, 0x2000 * 32) < 0)) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int rexramfloppy_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_B_INT(m, &cart_enabled) < 0) + || (SMR_B_INT(m, &ram_enabled) < 0) + || (SMR_B_INT(m, &ram_writeable) < 0) + || (SMR_B_INT(m, &ram_bank) < 0) + || (SMR_BA(m, roml_banks, 0x2000) < 0) + || (SMR_BA(m, rexramfloppy_ram, 0x2000 * 32) < 0)) { + goto fail; + } + + if (rexramfloppy_common_attach() < 0) { + snapshot_module_close(m); + return -1; + } + + if (0 + || (SMR_BA(m, rexramfloppy_ram, 0x2000 * 32) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/rexramfloppy.h b/src/Emulators/vice/c64/cart/rexramfloppy.h new file mode 100644 index 00000000..0ef3af1d --- /dev/null +++ b/src/Emulators/vice/c64/cart/rexramfloppy.h @@ -0,0 +1,59 @@ +/* + * rexramfloppy.h - Cartridge handling, REX Ramfloppy cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_REXRAMFLOPPY_H +#define VICE_REXRAMFLOPPY_H + +#include + +#include "vicetypes.h" + +uint8_t rexramfloppy_roml_read(uint16_t addr); +void rexramfloppy_roml_store(uint16_t addr, uint8_t value); + +void rexramfloppy_reset(void); + +void rexramfloppy_config_init(void); +void rexramfloppy_config_setup(uint8_t *rawcart); +int rexramfloppy_bin_attach(const char *filename, uint8_t *rawcart); +int rexramfloppy_crt_attach(FILE *fd, uint8_t *rawcart); +void rexramfloppy_detach(void); + +int rexramfloppy_resources_init(void); +void rexramfloppy_resources_shutdown(void); +int rexramfloppy_cmdline_options_init(void); + +int rexramfloppy_ram_flush(void); +int rexramfloppy_ram_save(const char *filename); + +int rexramfloppy_can_flush_ram(void); + +struct snapshot_s; + +int rexramfloppy_snapshot_write_module(struct snapshot_s *s); +int rexramfloppy_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/rexutility.c b/src/Emulators/vice/c64/cart/rexutility.c index b2fa2c6c..349f9d38 100644 --- a/src/Emulators/vice/c64/cart/rexutility.c +++ b/src/Emulators/vice/c64/cart/rexutility.c @@ -54,7 +54,7 @@ static int rex_active = 0; -static BYTE rex_io2_read(WORD addr) +static uint8_t rex_io2_read(uint16_t addr) { if ((addr & 0xff) < 0xc0) { /* disable cartridge rom */ @@ -68,7 +68,7 @@ static BYTE rex_io2_read(WORD addr) return 0; } -static BYTE rex_io2_peek(WORD addr) +static uint8_t rex_io2_peek(uint16_t addr) { return 0; } @@ -83,18 +83,20 @@ static int rex_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t rex_device = { - CARTRIDGE_NAME_REX, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - NULL, - rex_io2_read, - rex_io2_peek, - rex_dump, - CARTRIDGE_REX, - 0, - 0 + CARTRIDGE_NAME_REX, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + rex_io2_read, /* read function */ + rex_io2_peek, /* peek function */ + rex_dump, /* device state information dump function */ + CARTRIDGE_REX, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *rex_list_item = NULL; @@ -107,14 +109,14 @@ static const export_resource_t export_res_rex = { void rex_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); rex_active = 1; } -void rex_config_setup(BYTE *rawcart) +void rex_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); rex_active = 1; } @@ -127,7 +129,7 @@ static int rex_common_attach(void) return 0; } -int rex_bin_attach(const char *filename, BYTE *rawcart) +int rex_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -135,7 +137,7 @@ int rex_bin_attach(const char *filename, BYTE *rawcart) return rex_common_attach(); } -int rex_crt_attach(FILE *fd, BYTE *rawcart) +int rex_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -171,7 +173,7 @@ void rex_detach(void) ARRAY | ROML | 0.0+ | 524288 BYTES of ROML data */ -static char snap_module_name[] = "CARTREXUTIL"; +static const char snap_module_name[] = "CARTREXUTIL"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -186,7 +188,7 @@ int rex_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)rex_active) < 0 + || SMW_B(m, (uint8_t)rex_active) < 0 || SMW_BA(m, roml_banks, 0x2000 * 64) < 0) { snapshot_module_close(m); return -1; @@ -197,7 +199,7 @@ int rex_snapshot_write_module(snapshot_t *s) int rex_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -207,13 +209,13 @@ int rex_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if ((vmajor != SNAP_MAJOR) || (vminor != SNAP_MINOR)) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &rex_active) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/rexutility.h b/src/Emulators/vice/c64/cart/rexutility.h index b6e2e313..e583359a 100644 --- a/src/Emulators/vice/c64/cart/rexutility.h +++ b/src/Emulators/vice/c64/cart/rexutility.h @@ -31,16 +31,16 @@ #include "vicetypes.h" -extern void rex_config_init(void); -extern void rex_config_setup(BYTE *rawcart); -extern int rex_crt_attach(FILE *fd, BYTE *rawbyte); -extern int rex_bin_attach(const char *filename, BYTE *rawcart); -extern void rex_detach(void); -extern void rex_config_init(void); +void rex_config_init(void); +void rex_config_setup(uint8_t *rawcart); +int rex_crt_attach(FILE *fd, uint8_t *rawbyte); +int rex_bin_attach(const char *filename, uint8_t *rawcart); +void rex_detach(void); +void rex_config_init(void); struct snapshot_s; -extern int rex_snapshot_write_module(struct snapshot_s *s); -extern int rex_snapshot_read_module(struct snapshot_s *s); +int rex_snapshot_write_module(struct snapshot_s *s); +int rex_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/rgcd.c b/src/Emulators/vice/c64/cart/rgcd.c index e8fb0e84..bbfd36b4 100644 --- a/src/Emulators/vice/c64/cart/rgcd.c +++ b/src/Emulators/vice/c64/cart/rgcd.c @@ -37,7 +37,9 @@ #include "c64mem.h" #include "cartio.h" #include "cartridge.h" +#include "cmdline.h" #include "export.h" +#include "resources.h" #include "rgcd.h" #include "monitor.h" #include "snapshot.h" @@ -61,55 +63,69 @@ bit 0-2 bank number bit 3 exrom (1 = cart rom and I/O disabled until reset/powercycle) + + the eprom cartridge by "hucky" works exactly the same, except the banks + are in reverse order. it is implemented as hardware revision 1. + + the Hucky cartridge may also be equipped with 8k, 16k or 32k EPROMs */ #define MAXBANKS 8 -static BYTE regval = 0; -static BYTE disabled = 0; +static uint8_t regval = 0; +static uint8_t disabled = 0; +static int rgcd_revision = 0; +static int bankmask = 7; -static void rgcd_io1_store(WORD addr, BYTE value) +static void rgcd_io1_store(uint16_t addr, uint8_t value) { regval = value & 0x0f; + if (rgcd_revision == RGCD_REV_HUCKY) { + value ^= 7; + } cart_set_port_game_slotmain(0); disabled |= (value & 0x08) ? 1 : 0; if (disabled) { /* turn off cart ROM */ cart_set_port_exrom_slotmain(0); } else { - cart_romlbank_set_slotmain(value & 0x07); + cart_romlbank_set_slotmain(value & bankmask); cart_set_port_exrom_slotmain(1); } cart_port_config_changed_slotmain(); - DBG(("RGCD: Reg: %02x (Bank: %d, %s)\n", regval, (regval & 0x07), disabled ? "disabled" : "enabled")); + DBG(("RGCD: Reg: %02x (Bank: %d of %d, %s)\n", + regval, (regval & bankmask), bankmask + 1, disabled ? "disabled" : "enabled")); } -static BYTE rgcd_io1_peek(WORD addr) +static uint8_t rgcd_io1_peek(uint16_t addr) { return regval; } static int rgcd_dump(void) { - mon_out("Reg: %02x (Bank: %d, %s)\n", regval, (regval & 0x07), disabled ? "disabled" : "enabled"); + mon_out("Reg: %02x (Bank: %d of %d, %s)\n", + regval, (regval & bankmask), bankmask + 1, disabled ? "disabled" : "enabled"); return 0; } /* ---------------------------------------------------------------------*/ static io_source_t rgcd_device = { - CARTRIDGE_NAME_RGCD, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - rgcd_io1_store, - NULL, - rgcd_io1_peek, - rgcd_dump, - CARTRIDGE_RGCD, - 0, - 0 + CARTRIDGE_NAME_RGCD, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + rgcd_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + rgcd_io1_peek, /* peek function */ + rgcd_dump, /* device state information dump function */ + CARTRIDGE_RGCD, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *rgcd_list_item = NULL; @@ -130,10 +146,10 @@ void rgcd_config_init(void) { disabled = 0; cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); - rgcd_io1_store((WORD)0xde00, 0); + rgcd_io1_store((uint16_t)0xde00, 0); } -void rgcd_config_setup(BYTE *rawcart) +void rgcd_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * MAXBANKS); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); @@ -141,6 +157,40 @@ void rgcd_config_setup(BYTE *rawcart) /* ---------------------------------------------------------------------*/ +static int set_rgcd_revision(int val, void *param) +{ + rgcd_revision = val ? 1 : 0; + return 0; +} + +static const resource_int_t resources_int[] = { + { "RGCDrevision", RGCD_REV_RGCD_64K, RES_EVENT_NO, NULL, + &rgcd_revision, set_rgcd_revision, NULL }, + RESOURCE_INT_LIST_END +}; + +int rgcd_resources_init(void) +{ + return resources_register_int(resources_int); +} + +void rgcd_resources_shutdown(void) +{ +} + +static const cmdline_option_t cmdline_options[] = +{ + { "-rgcdrev", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "RGCDrevision", NULL, + "", "Set RGCD Revision (0: RGCD 64K, 1: Hucky)" }, + CMDLINE_LIST_END +}; + +int rgcd_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} + static int rgcd_common_attach(void) { if (export_add(&export_res) < 0) { @@ -150,7 +200,7 @@ static int rgcd_common_attach(void) return 0; } -int rgcd_bin_attach(const char *filename, BYTE *rawcart) +int rgcd_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -158,21 +208,40 @@ int rgcd_bin_attach(const char *filename, BYTE *rawcart) return rgcd_common_attach(); } -int rgcd_crt_attach(FILE *fd, BYTE *rawcart) +int rgcd_crt_attach(FILE *fd, uint8_t *rawcart, uint8_t revision) { crt_chip_header_t chip; + int highbank = 0; while (1) { if (crt_read_chip_header(&chip, fd)) { break; } + printf("bank %d %04x %04x\n", chip.bank, chip.start, chip.size); if ((chip.bank >= MAXBANKS) || ((chip.start != 0x8000) && (chip.start != 0xa000)) || (chip.size != 0x2000)) { return -1; } + if (chip.bank > highbank) { + highbank = chip.bank; + } if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { return -1; } } + + if (revision > 0) { + rgcd_revision = RGCD_REV_HUCKY; + if ((highbank != 7) && (highbank != 3) && (highbank != 1) && (highbank != 0)) { + return -1; + } + bankmask = highbank; + } else { + if (highbank != 7) { + return -1; + } + bankmask = 7; + } + return rgcd_common_attach(); } @@ -191,14 +260,16 @@ void rgcd_detach(void) ---------------------------------------- BYTE | regval | 0.1+ | register BYTE | disabled | 0.2 | cartridge disabled flag + BYTE | revision | 0.3 | hw revision + BYTE | mask | 0.4 | bank mask ARRAY | ROML | 0.1+ | 65536 BYTES of ROML data Note: for some reason this module was created at rev 0.1, so there never was a 0.0 */ -static char snap_module_name[] = "CARTRGCD"; +static const char snap_module_name[] = "CARTRGCD"; #define SNAP_MAJOR 0 -#define SNAP_MINOR 2 +#define SNAP_MINOR 4 int rgcd_snapshot_write_module(snapshot_t *s) { @@ -211,8 +282,10 @@ int rgcd_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)regval) < 0 - || SMW_B(m, (BYTE)disabled) < 0 + || SMW_B(m, (uint8_t)regval) < 0 + || SMW_B(m, (uint8_t)disabled) < 0 + || SMW_B(m, (uint8_t)rgcd_revision) < 0 + || SMW_B(m, (uint8_t)bankmask) < 0 || SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) { snapshot_module_close(m); return -1; @@ -223,7 +296,7 @@ int rgcd_snapshot_write_module(snapshot_t *s) int rgcd_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -233,7 +306,7 @@ int rgcd_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -243,7 +316,7 @@ int rgcd_snapshot_read_module(snapshot_t *s) } /* new in 0.2 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (SMR_B(m, &disabled) < 0) { goto fail; } @@ -251,6 +324,24 @@ int rgcd_snapshot_read_module(snapshot_t *s) disabled = 0; } + /* new in 0.3 */ + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 3)) { + if (SMR_B_INT(m, &rgcd_revision) < 0) { + goto fail; + } + } else { + rgcd_revision = 0; + } + + /* new in 0.4 */ + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 4)) { + if (SMR_B_INT(m, &bankmask) < 0) { + goto fail; + } + } else { + bankmask = 7; + } + if (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/rgcd.h b/src/Emulators/vice/c64/cart/rgcd.h index a641df6f..70bbaf79 100644 --- a/src/Emulators/vice/c64/cart/rgcd.h +++ b/src/Emulators/vice/c64/cart/rgcd.h @@ -31,16 +31,23 @@ #include "vicetypes.h" -extern void rgcd_reset(void); -extern void rgcd_config_init(void); -extern void rgcd_config_setup(BYTE *rawcart); -extern int rgcd_bin_attach(const char *filename, BYTE *rawcart); -extern int rgcd_crt_attach(FILE *fd, BYTE *rawcart); -extern void rgcd_detach(void); +#define RGCD_REV_RGCD_64K 0 +#define RGCD_REV_HUCKY 1 + +void rgcd_reset(void); +void rgcd_config_init(void); +void rgcd_config_setup(uint8_t *rawcart); +int rgcd_bin_attach(const char *filename, uint8_t *rawcart); +int rgcd_crt_attach(FILE *fd, uint8_t *rawcart, uint8_t revision); +void rgcd_detach(void); + +int rgcd_cmdline_options_init(void); +int rgcd_resources_init(void); +void rgcd_resources_shutdown(void); struct snapshot_s; -extern int rgcd_snapshot_write_module(struct snapshot_s *s); -extern int rgcd_snapshot_read_module(struct snapshot_s *s); +int rgcd_snapshot_write_module(struct snapshot_s *s); +int rgcd_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/ross.c b/src/Emulators/vice/c64/cart/ross.c index 6259f73d..6578af1e 100644 --- a/src/Emulators/vice/c64/cart/ross.c +++ b/src/Emulators/vice/c64/cart/ross.c @@ -60,7 +60,7 @@ static int currbank = 0; static int ross_is_32k = 0; -static BYTE ross_io1_read(WORD addr) +static uint8_t ross_io1_read(uint16_t addr) { if (ross_is_32k) { cart_romhbank_set_slotmain(1); @@ -70,12 +70,12 @@ static BYTE ross_io1_read(WORD addr) return 0; } -static BYTE ross_io_peek(WORD addr) +static uint8_t ross_io_peek(uint16_t addr) { return 0; } -static BYTE ross_io2_read(WORD addr) +static uint8_t ross_io2_read(uint16_t addr) { cart_set_port_exrom_slotmain(0); cart_set_port_game_slotmain(0); @@ -86,7 +86,7 @@ static BYTE ross_io2_read(WORD addr) static int ross_dump(void) { mon_out("Size: %s, bank: %d\n", - (ross_is_32k) ? "32Kb" : "16Kb", + (ross_is_32k) ? "32KiB" : "16KiB", currbank); return 0; } @@ -94,33 +94,37 @@ static int ross_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t ross_io1_device = { - CARTRIDGE_NAME_ROSS, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - NULL, - ross_io1_read, - ross_io_peek, - ross_dump, - CARTRIDGE_ROSS, - 0, - 0 + CARTRIDGE_NAME_ROSS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + ross_io1_read, /* read function */ + ross_io_peek, /* peek function */ + ross_dump, /* device state information dump function */ + CARTRIDGE_ROSS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ross_io2_device = { - CARTRIDGE_NAME_ROSS, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - NULL, - ross_io2_read, - ross_io_peek, - ross_dump, - CARTRIDGE_ROSS, - 0, - 0 + CARTRIDGE_NAME_ROSS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignore, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + ross_io2_read, /* read function */ + ross_io_peek, /* peek function */ + ross_dump, /* device state information dump function */ + CARTRIDGE_ROSS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ross_io1_list_item = NULL; @@ -134,16 +138,16 @@ static const export_resource_t export_res = { void ross_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } -void ross_config_setup(BYTE *rawcart) +void ross_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); memcpy(&roml_banks[0x2000], &rawcart[0x4000], 0x2000); memcpy(&romh_banks[0x2000], &rawcart[0x6000], 0x2000); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); currbank = 0; } @@ -159,7 +163,7 @@ static int ross_common_attach(void) return 0; } -int ross_bin_attach(const char *filename, BYTE *rawcart) +int ross_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -172,7 +176,7 @@ int ross_bin_attach(const char *filename, BYTE *rawcart) return ross_common_attach(); } -int ross_crt_attach(FILE *fd, BYTE *rawcart) +int ross_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int amount = 0; @@ -222,7 +226,7 @@ void ross_detach(void) ARRAY | ROMH | 0.0+ | 16384 BYTES of ROMH data */ -static char snap_module_name[] = "CARTROSS"; +static const char snap_module_name[] = "CARTROSS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -237,8 +241,8 @@ int ross_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)ross_is_32k) < 0 - || SMW_B(m, (BYTE)currbank) < 0 + || SMW_B(m, (uint8_t)ross_is_32k) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 || SMW_BA(m, roml_banks, 0x4000) < 0 || SMW_BA(m, romh_banks, 0x4000) < 0) { snapshot_module_close(m); @@ -250,7 +254,7 @@ int ross_snapshot_write_module(snapshot_t *s) int ross_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -260,13 +264,13 @@ int ross_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &ross_is_32k) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/ross.h b/src/Emulators/vice/c64/cart/ross.h index 136df7b5..6bb97f4f 100644 --- a/src/Emulators/vice/c64/cart/ross.h +++ b/src/Emulators/vice/c64/cart/ross.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void ross_config_init(void); -extern void ross_config_setup(BYTE *rawcart); -extern int ross_bin_attach(const char *filename, BYTE *rawcart); -extern int ross_crt_attach(FILE *fd, BYTE *rawcart); -extern void ross_detach(void); +void ross_config_init(void); +void ross_config_setup(uint8_t *rawcart); +int ross_bin_attach(const char *filename, uint8_t *rawcart); +int ross_crt_attach(FILE *fd, uint8_t *rawcart); +void ross_detach(void); struct snapshot_s; -extern int ross_snapshot_write_module(struct snapshot_s *s); -extern int ross_snapshot_read_module(struct snapshot_s *s); +int ross_snapshot_write_module(struct snapshot_s *s); +int ross_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/rrnetmk3.c b/src/Emulators/vice/c64/cart/rrnetmk3.c index a65f0a19..8e894c9a 100644 --- a/src/Emulators/vice/c64/cart/rrnetmk3.c +++ b/src/Emulators/vice/c64/cart/rrnetmk3.c @@ -26,7 +26,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -51,7 +51,6 @@ #include "monitor.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -71,9 +70,9 @@ */ /* #define RRNETMK3DEBUG */ - + #ifdef RRNETMK3DEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif @@ -92,11 +91,11 @@ static int rrnetmk3_bios_changed = 0; static int rrnetmk3_hw_flashjumper = 0; /* status of the flash jumper */ -static BYTE rrnetmk3_biossel = 0; /* 0 = ROM is mapped */ +static uint8_t rrnetmk3_biossel = 0; /* 0 = ROM is mapped */ -static log_t rrnetmk3_log = LOG_ERR; +static log_t rrnetmk3_log = LOG_DEFAULT; -static BYTE rrnetmk3_bios[0x2002]; +static uint8_t rrnetmk3_bios[0x2002]; static int rrnetmk3_bios_offset = 0; static int rrnetmk3_bios_type = 0; @@ -105,42 +104,47 @@ static const char STRING_RRNETMK3[] = CARTRIDGE_NAME_RRNETMK3; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void rrnetmk3_io1_store(WORD addr, BYTE value); -static BYTE rrnetmk3_io1_peek(WORD addr); +static void rrnetmk3_io1_store(uint16_t addr, uint8_t value); +static uint8_t rrnetmk3_io1_peek(uint16_t addr); static int rrnetmk3_dump(void); -static BYTE rrnetmk3_cs8900_read(WORD io_address); -static BYTE rrnetmk3_cs8900_peek(WORD io_address); -static void rrnetmk3_cs8900_store(WORD io_address, BYTE byte); +static uint8_t rrnetmk3_cs8900_read(uint16_t io_address); +static uint8_t rrnetmk3_cs8900_peek(uint16_t io_address); +static void rrnetmk3_cs8900_store(uint16_t io_address, uint8_t byte); +static int rrnetmk3_cs8900_dump(void); static io_source_t rrnetmk3_io1_device = { - CARTRIDGE_NAME_RRNETMK3, - IO_DETACH_RESOURCE, - "RRNETMK3", - 0xde80, 0xde88, 0x88, /* FIXME */ - 0, - rrnetmk3_io1_store, - NULL, /* read */ - rrnetmk3_io1_peek, - rrnetmk3_dump, - CARTRIDGE_RRNETMK3, - 0, - 0 + CARTRIDGE_NAME_RRNETMK3, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "RRNETMK3", /* resource to set to '0' */ + 0xde80, 0xde88, 0xff, /* range for the device, regs:$de80/$de88 */ + 0, /* read is never valid, regs are write only */ + rrnetmk3_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + rrnetmk3_io1_peek, /* peek function */ + rrnetmk3_dump, /* device state information dump function */ + CARTRIDGE_RRNETMK3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t rrnetmk3_cs8900_io1_device = { - CARTRIDGE_NAME_RRNETMK3, - IO_DETACH_RESOURCE, - "RRNETMK3", - 0xde02, 0xde0f, 0x0f, - 0, - rrnetmk3_cs8900_store, - rrnetmk3_cs8900_read, - rrnetmk3_cs8900_peek, - rrnetmk3_dump, - CARTRIDGE_RRNETMK3, - 0, - 0 + CARTRIDGE_NAME_RRNETMK3, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "RRNETMK3", /* resource to set to '0' */ + 0xde02, 0xde0f, 0x0f, /* range for the device, regs:$de02-$de0f */ + 0, /* read validity is determined by the device upon a read */ + rrnetmk3_cs8900_store, /* store function */ + NULL, /* NO poke function */ + rrnetmk3_cs8900_read, /* read function */ + rrnetmk3_cs8900_peek, /* peek function */ + rrnetmk3_cs8900_dump, /* device state information dump function */ + CARTRIDGE_RRNETMK3, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *rrnetmk3_io1_list_item = NULL; @@ -159,7 +163,7 @@ void rrnetmk3_reset(void) if (rrnetmk3_enabled) { cs8900io_reset(); } - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(rrnetmk3_biossel ? CMODE_RAM : CMODE_8KGAME), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(rrnetmk3_biossel ? CMODE_RAM : CMODE_8KGAME), CMODE_READ); } static int set_rrnetmk3_flashjumper(int val, void *param) @@ -177,7 +181,7 @@ static int set_rrnetmk3_bios_write(int val, void *param) /* ---------------------------------------------------------------------*/ -int rrnetmk3_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +int rrnetmk3_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { if (!rrnetmk3_biossel) { switch (addr & 0xf000) { @@ -198,10 +202,10 @@ void rrnetmk3_config_init(void) { LOG(("RRNETMK3 rrnetmk3_config_init")); rrnetmk3_biossel = rrnetmk3_hw_flashjumper; /* disable bios at reset when flash jumper is set */ - cart_config_changed_slotmain(CMODE_RAM, (BYTE)(rrnetmk3_biossel ? CMODE_RAM : CMODE_8KGAME), CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, (uint8_t)(rrnetmk3_biossel ? CMODE_RAM : CMODE_8KGAME), CMODE_READ); } -static void rrnetmk3_io1_store(WORD addr, BYTE value) +static void rrnetmk3_io1_store(uint16_t addr, uint8_t value) { LOG(("RRNETMK3: IO1 ST %04x %02x", addr, value)); switch (addr) { @@ -218,7 +222,7 @@ static void rrnetmk3_io1_store(WORD addr, BYTE value) } } -static BYTE rrnetmk3_io1_peek(WORD addr) +static uint8_t rrnetmk3_io1_peek(uint16_t addr) { switch (addr) { case 0x80: /* ROM_ENABLE */ @@ -231,7 +235,7 @@ static BYTE rrnetmk3_io1_peek(WORD addr) /* ---------------------------------------------------------------------*/ -static BYTE rrnetmk3_cs8900_read(WORD address) +static uint8_t rrnetmk3_cs8900_read(uint16_t address) { if (address < 0x02) { rrnetmk3_cs8900_io1_device.io_source_valid = 0; @@ -245,7 +249,7 @@ static BYTE rrnetmk3_cs8900_read(WORD address) return cs8900io_read(address); } -static BYTE rrnetmk3_cs8900_peek(WORD address) +static uint8_t rrnetmk3_cs8900_peek(uint16_t address) { if (address < 0x02) { return 0; @@ -258,7 +262,7 @@ static BYTE rrnetmk3_cs8900_peek(WORD address) return cs8900io_read(address); } -static void rrnetmk3_cs8900_store(WORD address, BYTE byte) +static void rrnetmk3_cs8900_store(uint16_t address, uint8_t byte) { if (address < 0x02) { return; @@ -268,6 +272,12 @@ static void rrnetmk3_cs8900_store(WORD address, BYTE byte) cs8900io_store(address, byte); } +static int rrnetmk3_cs8900_dump(void) +{ + cs8900io_dump(); + return 0; +} + /* ---------------------------------------------------------------------*/ static int rrnetmk3_dump(void) @@ -280,7 +290,7 @@ static int rrnetmk3_dump(void) /* ---------------------------------------------------------------------*/ -int rrnetmk3_roml_read(WORD addr) +int rrnetmk3_roml_read(uint16_t addr) { if (!rrnetmk3_biossel) { return rrnetmk3_bios[(addr & 0x1fff) + rrnetmk3_bios_offset]; @@ -288,7 +298,7 @@ int rrnetmk3_roml_read(WORD addr) return mem_ram[addr]; } -int rrnetmk3_peek_mem(export_t *export, WORD addr, BYTE *value) +int rrnetmk3_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if ((addr >= 0x8000) && (addr <= 0x9fff)) { if (!rrnetmk3_biossel) { @@ -299,7 +309,7 @@ int rrnetmk3_peek_mem(export_t *export, WORD addr, BYTE *value) return CART_READ_THROUGH; } -int rrnetmk3_roml_store(WORD addr, BYTE byte) +int rrnetmk3_roml_store(uint16_t addr, uint8_t byte) { if (!rrnetmk3_biossel) { if (rrnetmk3_hw_flashjumper) { @@ -337,26 +347,18 @@ void rrnetmk3_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-rrnetmk3bioswrite", SET_RESOURCE, 0, + { "-rrnetmk3bioswrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRNETMK3_bios_write", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RRNETMK3_BIOS_WRITE, - NULL, NULL }, - { "+rrnetmk3bioswrite", SET_RESOURCE, 0, + NULL, "Save the RRNETMK3 bios when changed" }, + { "+rrnetmk3bioswrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRNETMK3_bios_write", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RRNETMK3_BIOS_READ_ONLY, - NULL, NULL }, - { "-rrnetmk3flash", SET_RESOURCE, 0, + NULL, "Do not save the RRNETMK3 bios when changed" }, + { "-rrnetmk3flash", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRNETMK3_flashjumper", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RRNETMK3_SET_FLASH_JUMPER, - NULL, NULL }, - { "+rrnetmk3flash", SET_RESOURCE, 0, + NULL, "Set the RRNETMK3 Flash Jumper" }, + { "+rrnetmk3flash", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "RRNETMK3_flashjumper", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_RRNETMK3_UNSET_FLASH_JUMPER, - NULL, NULL }, + NULL, "Remove the RRNETMK3 Flash Jumper" }, CMDLINE_LIST_END }; @@ -373,7 +375,7 @@ void rrnetmk3_init(void) cs8900io_init(); } -void rrnetmk3_config_setup(BYTE *rawcart) +void rrnetmk3_config_setup(uint8_t *rawcart) { memcpy(rrnetmk3_bios, rawcart, 0x2000 + rrnetmk3_bios_offset); } @@ -405,7 +407,7 @@ static int rrnetmk3_common_attach(void) int rrnetmk3_bin_save(const char *filename) { FILE *fd; - int ret; + size_t ret; if (filename == NULL) { return -1; @@ -418,7 +420,7 @@ int rrnetmk3_bin_save(const char *filename) ret = fwrite(rrnetmk3_bios, 1, 0x2000 + rrnetmk3_bios_offset, fd); fclose(fd); - if (ret != 0x2000 + rrnetmk3_bios_offset) { + if (ret != (0x2000 + rrnetmk3_bios_offset)) { return -1; } rrnetmk3_bios_changed = 0; @@ -450,7 +452,7 @@ int rrnetmk3_crt_save(const char *filename) return 0; } -int rrnetmk3_bin_attach(const char *filename, BYTE *rawcart) +int rrnetmk3_bin_attach(const char *filename, uint8_t *rawcart) { int amount_read = 0; FILE *fd; @@ -469,11 +471,11 @@ int rrnetmk3_bin_attach(const char *filename, BYTE *rawcart) rrnetmk3_bios_offset = amount_read & 3; rrnetmk3_bios_type = CARTRIDGE_FILETYPE_BIN; - rrnetmk3_bios_filename = lib_stralloc(filename); + rrnetmk3_bios_filename = lib_strdup(filename); return rrnetmk3_common_attach(); } -int rrnetmk3_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) +int rrnetmk3_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename) { crt_chip_header_t chip; @@ -491,7 +493,7 @@ int rrnetmk3_crt_attach(FILE *fd, BYTE *rawcart, const char *filename) rrnetmk3_bios_offset = 0; rrnetmk3_bios_type = CARTRIDGE_FILETYPE_CRT; - rrnetmk3_bios_filename = lib_stralloc(filename); + rrnetmk3_bios_filename = lib_strdup(filename); return rrnetmk3_common_attach(); } @@ -537,8 +539,6 @@ void rrnetmk3_detach(void) /* FIXME: implement snapshot support */ int rrnetmk3_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -547,6 +547,9 @@ int rrnetmk3_snapshot_write_module(snapshot_t *s) return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -561,7 +564,7 @@ int rrnetmk3_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/c64/cart/rrnetmk3.h b/src/Emulators/vice/c64/cart/rrnetmk3.h index f33a53b5..c68c9351 100644 --- a/src/Emulators/vice/c64/cart/rrnetmk3.h +++ b/src/Emulators/vice/c64/cart/rrnetmk3.h @@ -36,30 +36,31 @@ #include "vicetypes.h" #include "c64cart.h" -extern int rrnetmk3_cart_enabled(void); -extern void rrnetmk3_config_init(void); -extern int rrnetmk3_roml_read(WORD addr); -extern int rrnetmk3_roml_store(WORD addr, BYTE byte); -extern int rrnetmk3_peek_mem(export_t *export, WORD addr, BYTE *value); +int rrnetmk3_cart_enabled(void); +void rrnetmk3_config_init(void); +int rrnetmk3_roml_read(uint16_t addr); +int rrnetmk3_roml_store(uint16_t addr, uint8_t byte); +int rrnetmk3_peek_mem(export_t *export, uint16_t addr, uint8_t *value); -extern void rrnetmk3_config_setup(BYTE *rawcart); +void rrnetmk3_config_setup(uint8_t *rawcart); -extern int rrnetmk3_crt_attach(FILE *fd, BYTE *rawcart, const char *filename); -extern int rrnetmk3_bin_attach(const char *filename, BYTE *rawcart); -extern int rrnetmk3_bin_save(const char *filename); -extern int rrnetmk3_crt_save(const char *filename); -extern int rrnetmk3_flush_image(void); +int rrnetmk3_crt_attach(FILE *fd, uint8_t *rawcart, const char *filename); +int rrnetmk3_bin_attach(const char *filename, uint8_t *rawcart); +int rrnetmk3_bin_save(const char *filename); +int rrnetmk3_crt_save(const char *filename); +int rrnetmk3_flush_image(void); -extern int rrnetmk3_resources_init(void); -extern void rrnetmk3_resources_shutdown(void); -extern int rrnetmk3_cmdline_options_init(void); -extern void rrnetmk3_init(void); -extern void rrnetmk3_detach(void); -extern void rrnetmk3_reset(void); -extern int rrnetmk3_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +int rrnetmk3_resources_init(void); +void rrnetmk3_resources_shutdown(void); +int rrnetmk3_cmdline_options_init(void); +void rrnetmk3_init(void); +void rrnetmk3_detach(void); +void rrnetmk3_reset(void); +int rrnetmk3_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); struct snapshot_s; -extern int rrnetmk3_snapshot_read_module(struct snapshot_s *s); -extern int rrnetmk3_snapshot_write_module(struct snapshot_s *s); + +int rrnetmk3_snapshot_read_module(struct snapshot_s *s); +int rrnetmk3_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/sdbox.c b/src/Emulators/vice/c64/cart/sdbox.c new file mode 100644 index 00000000..610144ef --- /dev/null +++ b/src/Emulators/vice/c64/cart/sdbox.c @@ -0,0 +1,322 @@ +/* + * sdbox.c - Cartridge handling, SD-BOX cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define DEBUG_SDBOX */ + +#include "vice.h" + +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "sdbox.h" +#include "log.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +#ifdef DEBUG_SDBOX +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + "SD Box" + + - 128k ROM, 8*16kb banks (16k GAME mode) + + one register at de00: + + bit 0-3 ROM bank + bit 4 reset SD + bit 5 CE ROM + bit 6 EXROM + bit 7 register enable + + additionally there are 3 "ram cells" at de01-de03 + +*/ + +static uint8_t currbank = 0; +static uint8_t reg_enable = 1; + +static uint8_t regval = 0; +static uint8_t regs[4]; + +static uint8_t sdbox_io1_read(uint16_t addr) +{ + addr &= 0xff; + if (reg_enable) { + switch (addr) { + case 0: + DBG(("io1 read %02x %02x\n", addr, regs[addr])); + return regs[addr]; /* FIXME: is the register readable? */ + break; + case 1: + case 2: + case 3: + DBG(("io1 read %02x %02x\n", addr, regs[addr])); + return regs[addr]; + break; + default: + DBG(("io1 invalid read at %04x\n", addr)); + break; + } + } else { + DBG(("io1 read %02x (disabled)\n", addr)); + } + return 0; +} + +static void sdbox_io1_store(uint16_t addr, uint8_t value) +{ + uint8_t exrom; + addr &= 0xff; + if (reg_enable) { + switch (addr) { + case 0: + currbank = value & 0xf; + exrom = ((value >> 6) ^ 1) & 1; + if (exrom) { + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME | (currbank << CMODE_BANK_SHIFT), CMODE_WRITE); + } else { + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM | (currbank << CMODE_BANK_SHIFT), CMODE_WRITE); + } + reg_enable = (value >> 7) ^ 1; + regval = regs[addr] = value; + DBG(("io1 write %02x value: $%02x bank: %d exrom: %d\n", + addr, value, roml_bank, exrom)); + break; + case 1: + case 2: + case 3: + regs[addr] = value; + DBG(("io1 write %02x value: $%02x\n", addr, value)); + break; + default: + DBG(("io1 invalid write at %04x\n", addr)); + break; + } + } else { + DBG(("io1 write %02x value: $%02x (disabled)\n", addr, value)); + } +} + +static int sdbox_dump(void) +{ + mon_out("Register: %02x (%s)\n", regval, reg_enable ? "enabled" : "disabled"); + mon_out("ROM Bank: %d\n", currbank); + mon_out("on chip RAM: %02x %02x %02x\n", regs[1], regs[2], regs[3]); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t sdbox_device = { + CARTRIDGE_NAME_SDBOX, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 1, /* read is always valid */ + sdbox_io1_store, /* store function */ + NULL, /* NO poke function */ + sdbox_io1_read, /* read function */ + NULL, /* NO peek function */ + sdbox_dump, /* device state information dump function */ + CARTRIDGE_SDBOX, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *sdbox_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_SDBOX, 1, 1, &sdbox_device, NULL, CARTRIDGE_SDBOX +}; + +/* ---------------------------------------------------------------------*/ + +void sdbox_config_init(void) +{ + /* 16k configuration */ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + reg_enable = 1; + currbank = 0; +} + +void sdbox_powerup(void) +{ + memset(regs, 0, 4); +} + +void sdbox_config_setup(uint8_t *rawcart) +{ + int i; + for (i = 0; i < 8; i++) { + memcpy(&roml_banks[i * 0x2000], &rawcart[0x4000 * i], 0x2000); + memcpy(&romh_banks[i * 0x2000], &rawcart[0x2000 + (0x4000 * i)], 0x2000); + } + /* 16k configuration */ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ +static int sdbox_common_attach(void) +{ + if (export_add(&export_res) < 0) { + return -1; + } + sdbox_list_item = io_source_register(&sdbox_device); + return 0; +} + +int sdbox_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return sdbox_common_attach(); +} + +int sdbox_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if ((chip.bank > 7) || (chip.start != 0x8000) || (chip.size != 0x4000)) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + } + return sdbox_common_attach(); +} + +void sdbox_detach(void) +{ + io_source_unregister(sdbox_list_item); + sdbox_list_item = NULL; + export_remove(&export_res); +} + +/* ---------------------------------------------------------------------*/ + +/* CARTSDBOX snapshot module format: + + type | name | version | description + -------------------------------------- + BYTE | regval | 1.0 | register + BYTE | currbank | 1.0 | current bank + BYTE | reg_enable | 1.0 | flag: is the register enabled + BYTE | regs | 1.0 | 4 bytes of "RAM" + ARRAY | ROML | 1.0 | 8*8k BYTES of ROML data + ARRAY | ROMH | 1.0 | 8*8k BYTES of ROMH data + + */ + +static const char snap_module_name[] = "CARTSDBOX"; +#define SNAP_MAJOR 1 +#define SNAP_MINOR 0 + +int sdbox_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, regval) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 + || SMW_B(m, reg_enable) < 0 + || SMW_BA(m, regs, 4) < 0 + || SMW_BA(m, roml_banks, 0x2000 * 8) < 0 + || SMW_BA(m, romh_banks, 0x2000 * 8) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int sdbox_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + /* Only accept compatible snapshots */ + if (snapshot_version_is_smaller(vmajor, vminor, 1, 0)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + goto fail; + } + + if (0 + || SMR_B(m, ®val) < 0 + || SMR_B(m, &currbank) < 0 + || SMR_B(m, ®_enable) < 0 + || SMR_BA(m, regs, 4) < 0 + || SMR_BA(m, roml_banks, 0x2000 * 8) < 0 + || SMR_BA(m, romh_banks, 0x2000 * 8) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return sdbox_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/sdbox.h b/src/Emulators/vice/c64/cart/sdbox.h new file mode 100644 index 00000000..0cf37612 --- /dev/null +++ b/src/Emulators/vice/c64/cart/sdbox.h @@ -0,0 +1,46 @@ +/* + * sdbox.h - Cartridge handling, SD-BOX cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_SDBOX_H +#define VICE_SDBOX_H + +#include + +#include "vicetypes.h" + +void sdbox_config_init(void); +void sdbox_powerup(void); +void sdbox_config_setup(uint8_t *rawcart); +int sdbox_bin_attach(const char *filename, uint8_t *rawcart); +int sdbox_crt_attach(FILE *fd, uint8_t *rawcart); +void sdbox_detach(void); + +struct snapshot_s; + +int sdbox_snapshot_write_module(struct snapshot_s *s); +int sdbox_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/sfx_soundexpander.c b/src/Emulators/vice/c64/cart/sfx_soundexpander.c index cda159a2..93157e62 100644 --- a/src/Emulators/vice/c64/cart/sfx_soundexpander.c +++ b/src/Emulators/vice/c64/cart/sfx_soundexpander.c @@ -44,7 +44,14 @@ #include "snapshot.h" #include "sound.h" #include "uiapi.h" -#include "translate.h" + +/* #define DEBUG_SFX_SOUNDEXPANDER */ + +#ifdef DEBUG_SFX_SOUNDEXPANDER +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif /* Note: this cartridge has a passthrough port, which for some odd reason does @@ -65,26 +72,32 @@ static FM_OPL *YM3812_chip = NULL; /* ------------------------------------------------------------------------- */ /* some prototypes are needed */ -static void sfx_soundexpander_sound_store(WORD addr, BYTE value); -static BYTE sfx_soundexpander_sound_read(WORD addr); -static BYTE sfx_soundexpander_sound_peek(WORD addr); -static BYTE sfx_soundexpander_piano_read(WORD addr); +static void sfx_soundexpander_sound_store(uint16_t addr, uint8_t value); +static uint8_t sfx_soundexpander_sound_read(uint16_t addr); +static uint8_t sfx_soundexpander_sound_peek(uint16_t addr); + +#if 0 +static uint8_t sfx_soundexpander_piano_read(uint16_t addr); +#endif static io_source_t sfx_soundexpander_sound_device = { - CARTRIDGE_NAME_SFX_SOUND_EXPANDER, - IO_DETACH_RESOURCE, - "SFXSoundExpander", - 0xdf00, 0xdfff, 0x7f, - 0, - sfx_soundexpander_sound_store, - sfx_soundexpander_sound_read, - sfx_soundexpander_sound_peek, - NULL, /* TODO: dump */ - CARTRIDGE_SFX_SOUND_EXPANDER, - 0, - 0 + CARTRIDGE_NAME_SFX_SOUND_EXPANDER, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SFXSoundExpander", /* resource to set to '0' */ + 0xdf00, 0xdfff, 0x7f, /* range for the device, regs:$df40/$df50/$df60, mirrors:$dfc0/$dfd0/$dfe0, range is different for vic20 */ + 0, /* read validity is determined by the device upon a read */ + sfx_soundexpander_sound_store, /* store function */ + NULL, /* NO poke function */ + sfx_soundexpander_sound_read, /* read function */ + sfx_soundexpander_sound_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_SFX_SOUND_EXPANDER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; +#if 0 static io_source_t sfx_soundexpander_piano_device = { CARTRIDGE_NAME_SFX_SOUND_EXPANDER, IO_DETACH_RESOURCE, @@ -99,28 +112,40 @@ static io_source_t sfx_soundexpander_piano_device = { 0, 0 }; +#endif static io_source_list_t *sfx_soundexpander_sound_list_item = NULL; + +/* unused right now */ +#if 0 static io_source_list_t *sfx_soundexpander_piano_list_item = NULL; +#endif static const export_resource_t export_res_sound = { CARTRIDGE_NAME_SFX_SOUND_EXPANDER, 0, 0, NULL, &sfx_soundexpander_sound_device, CARTRIDGE_SFX_SOUND_EXPANDER }; +#if 0 static const export_resource_t export_res_piano = { CARTRIDGE_NAME_SFX_SOUND_EXPANDER, 0, 0, NULL, &sfx_soundexpander_piano_device, CARTRIDGE_SFX_SOUND_EXPANDER }; +#endif /* ------------------------------------------------------------------------- */ /* Some prototypes are needed */ static int sfx_soundexpander_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); static void sfx_soundexpander_sound_machine_close(sound_t *psid); -static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); -static void sfx_soundexpander_sound_machine_store(sound_t *psid, WORD addr, BYTE val); -static BYTE sfx_soundexpander_sound_machine_read(sound_t *psid, WORD addr); +static void sfx_soundexpander_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val); +static uint8_t sfx_soundexpander_sound_machine_read(sound_t *psid, uint16_t addr); static void sfx_soundexpander_sound_reset(sound_t *psid, CLOCK cpu_clk); +#ifdef SOUND_SYSTEM_FLOAT +static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int sfx_soundexpander_sound_machine_cycle_based(void) { return 0; @@ -131,23 +156,38 @@ static int sfx_soundexpander_sound_machine_channels(void) return 1; /* FIXME: needs to become stereo for stereo capable ports */ } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the SFX Sound Expander sound */ +static sound_chip_mixing_spec_t sfx_soundexpander_mixing_sound_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* left channel volume % in case of stereo output, default output to both */ + 100 /* right channel volume % in case of stereo output, default output to both */ + } +}; +#endif + +/* SFX Sound Expander cartridge sound chip */ static sound_chip_t sfx_soundexpander_sound_chip = { - NULL, /* no open */ - sfx_soundexpander_sound_machine_init, - sfx_soundexpander_sound_machine_close, - sfx_soundexpander_sound_machine_calculate_samples, - sfx_soundexpander_sound_machine_store, - sfx_soundexpander_sound_machine_read, - sfx_soundexpander_sound_reset, - sfx_soundexpander_sound_machine_cycle_based, - sfx_soundexpander_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + sfx_soundexpander_sound_machine_init, /* sound chip init function */ + sfx_soundexpander_sound_machine_close, /* sound chip close function */ + sfx_soundexpander_sound_machine_calculate_samples, /* sound chip calculate samples function */ + sfx_soundexpander_sound_machine_store, /* sound chip store function */ + sfx_soundexpander_sound_machine_read, /* sound chip read function */ + sfx_soundexpander_sound_reset, /* sound chip reset function */ + sfx_soundexpander_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, sound chip is NOT cycle based */ + sfx_soundexpander_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */ +#ifdef SOUND_SYSTEM_FLOAT + sfx_soundexpander_mixing_sound_spec, /* stereo mixing placement specs */ +#endif + 0 /* chip enabled, toggled when sound chip is (de-)activated */ }; -static WORD sfx_soundexpander_sound_chip_offset = 0; +static uint16_t sfx_soundexpander_sound_chip_offset = 0; void sfx_soundexpander_sound_chip_init(void) { + DBG(("sfx_soundexpander_sound_chip_init")); sfx_soundexpander_sound_chip_offset = sound_chip_register(&sfx_soundexpander_sound_chip); } @@ -163,38 +203,53 @@ int sfx_soundexpander_cart_enabled(void) static int set_sfx_soundexpander_enabled(int value, void *param) { int val = value ? 1 : 0; - + DBG(("set_sfx_soundexpander_enabled chip_enabled:%d value:%d", + sfx_soundexpander_sound_chip.chip_enabled, value)); if (sfx_soundexpander_sound_chip.chip_enabled != val) { if (val) { if (export_add(&export_res_sound) < 0) { return -1; } +#if 0 if (export_add(&export_res_piano) < 0) { return -1; } +#endif if (machine_class == VICE_MACHINE_VIC20) { if (sfx_soundexpander_io_swap) { sfx_soundexpander_sound_device.start_address = 0x9800; sfx_soundexpander_sound_device.end_address = 0x9bff; +#if 0 sfx_soundexpander_piano_device.start_address = 0x9800; sfx_soundexpander_piano_device.end_address = 0x9bff; +#endif } else { sfx_soundexpander_sound_device.start_address = 0x9c00; sfx_soundexpander_sound_device.end_address = 0x9fff; +#if 0 sfx_soundexpander_piano_device.start_address = 0x9c00; sfx_soundexpander_piano_device.end_address = 0x9fff; +#endif } } sfx_soundexpander_sound_list_item = io_source_register(&sfx_soundexpander_sound_device); +#if 0 sfx_soundexpander_piano_list_item = io_source_register(&sfx_soundexpander_piano_device); +#endif sfx_soundexpander_sound_chip.chip_enabled = 1; } else { export_remove(&export_res_sound); +#if 0 export_remove(&export_res_piano); +#endif io_source_unregister(sfx_soundexpander_sound_list_item); +#if 0 io_source_unregister(sfx_soundexpander_piano_list_item); +#endif sfx_soundexpander_sound_list_item = NULL; +#if 0 sfx_soundexpander_piano_list_item = NULL; +#endif sfx_soundexpander_sound_chip.chip_enabled = 0; } } @@ -246,6 +301,13 @@ int sfx_soundexpander_enable(void) return resources_set_int("SFXSoundExpander", 1); } + +int sfx_soundexpander_disable(void) +{ + return resources_set_int("SFXSoundExpander", 0); +} + + void sfx_soundexpander_detach(void) { resources_set_int("SFXSoundExpander", 0); @@ -285,36 +347,26 @@ void sfx_soundexpander_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-sfxse", SET_RESOURCE, 0, + { "-sfxse", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundExpander", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SFX_SE, - NULL, NULL }, - { "+sfxse", SET_RESOURCE, 0, + NULL, "Enable the SFX Sound Expander cartridge" }, + { "+sfxse", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundExpander", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SFX_SE, - NULL, NULL }, - { "-sfxsetype", SET_RESOURCE, 1, + NULL, "Disable the SFX Sound Expander cartridge" }, + { "-sfxsetype", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "SFXSoundExpanderChip", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_TYPE, IDCLS_SET_YM_CHIP_TYPE, - NULL, NULL }, + "", "Set YM chip type (3526 / 3812)" }, CMDLINE_LIST_END }; static const cmdline_option_t cmdline_mascuerade_options[] = { - { "-sfxseioswap", SET_RESOURCE, 0, + { "-sfxseioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundExpanderIOSwap", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MAP_CART_IO_2, - NULL, NULL }, - { "+sfxseioswap", SET_RESOURCE, 0, + NULL, "Swap io mapping (map cart I/O to VIC20 I/O-2)" }, + { "+sfxseioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundExpanderIOSwap", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MAP_CART_IO_3, - NULL, NULL }, + NULL, "Don't swap io mapping (map cart I/O to VIC20 I/O-3)" }, CMDLINE_LIST_END }; @@ -331,15 +383,38 @@ int sfx_soundexpander_cmdline_options_init(void) /* ---------------------------------------------------------------------*/ struct sfx_soundexpander_sound_s { - BYTE command; + uint8_t command; }; static struct sfx_soundexpander_sound_s snd; -static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) { int i; - SWORD *buffer; + int16_t *buffer; + + buffer = lib_malloc(nr * sizeof(int16_t)); + + if (sfx_soundexpander_chip == 3812 && YM3812_chip) { + ym3812_update_one(YM3812_chip, buffer, nr); + } else if (sfx_soundexpander_chip == 3526 && YM3526_chip) { + ym3526_update_one(YM3526_chip, buffer, nr); + } + + for (i = 0; i < nr; i++) { + pbuf[i] = buffer[i] / 32767.0; + } + lib_free(buffer); + + return nr; +} +#else +static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) +{ + int i; + int16_t *buffer; buffer = lib_malloc(nr * 2); @@ -351,7 +426,7 @@ static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, SWO for (i = 0; i < nr; i++) { pbuf[i * soc] = sound_audio_mix(pbuf[i * soc], buffer[i]); - if (soc > 1) { + if (soc == SOUND_OUTPUT_STEREO) { pbuf[(i * soc) + 1] = sound_audio_mix(pbuf[(i * soc) + 1], buffer[i]); } } @@ -359,15 +434,17 @@ static int sfx_soundexpander_sound_machine_calculate_samples(sound_t **psid, SWO return nr; } +#endif static int sfx_soundexpander_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec) { + DBG(("sfx_soundexpander_sound_machine_init sfx_soundexpander_chip:%d", sfx_soundexpander_chip)); if (sfx_soundexpander_chip == 3812) { if (YM3812_chip != NULL) { ym3812_shutdown(YM3812_chip); } YM3812_chip = ym3812_init((UINT32)3579545, (UINT32)speed); - } else { + } else if (sfx_soundexpander_chip == 3526) { if (YM3526_chip != NULL) { ym3526_shutdown(YM3526_chip); } @@ -390,7 +467,7 @@ static void sfx_soundexpander_sound_machine_close(sound_t *psid) } } -static void sfx_soundexpander_sound_machine_store(sound_t *psid, WORD addr, BYTE val) +static void sfx_soundexpander_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val) { snd.command = val; @@ -401,13 +478,13 @@ static void sfx_soundexpander_sound_machine_store(sound_t *psid, WORD addr, BYTE } } -static BYTE sfx_soundexpander_sound_machine_read(sound_t *psid, WORD addr) +static uint8_t sfx_soundexpander_sound_machine_read(sound_t *psid, uint16_t addr) { if (sfx_soundexpander_chip == 3812 && YM3812_chip) { - return ym3812_read(YM3812_chip, 1); + return ym3812_read(YM3812_chip, 0); } if (sfx_soundexpander_chip == 3526 && YM3526_chip) { - return ym3526_read(YM3526_chip, 1); + return ym3526_read(YM3526_chip, 0); } return 0; } @@ -423,7 +500,7 @@ static void sfx_soundexpander_sound_reset(sound_t *psid, CLOCK cpu_clk) /* ---------------------------------------------------------------------*/ -static void sfx_soundexpander_sound_store(WORD addr, BYTE value) +static void sfx_soundexpander_sound_store(uint16_t addr, uint8_t value) { if (addr == 0x40) { if (sfx_soundexpander_chip == 3812 && YM3812_chip) { @@ -437,9 +514,9 @@ static void sfx_soundexpander_sound_store(WORD addr, BYTE value) } } -static BYTE sfx_soundexpander_sound_read(WORD addr) +static uint8_t sfx_soundexpander_sound_read(uint16_t addr) { - BYTE value = 0; + uint8_t value = 0; sfx_soundexpander_sound_device.io_source_valid = 0; @@ -453,9 +530,9 @@ static BYTE sfx_soundexpander_sound_read(WORD addr) return value; } -static BYTE sfx_soundexpander_sound_peek(WORD addr) +static uint8_t sfx_soundexpander_sound_peek(uint16_t addr) { - BYTE value = 0; + uint8_t value = 0; if (addr == 0x40) { if (sfx_soundexpander_chip == 3812 && YM3812_chip) { @@ -467,15 +544,17 @@ static BYTE sfx_soundexpander_sound_peek(WORD addr) return value; } +#if 0 /* No piano keyboard is emulated currently, so we return 0xff */ -static BYTE sfx_soundexpander_piano_read(WORD addr) +static uint8_t sfx_soundexpander_piano_read(uint16_t addr) { sfx_soundexpander_piano_device.io_source_valid = 0; if ((addr & 16) == 0 && (addr & 8) == 8) { sfx_soundexpander_piano_device.io_source_valid = 1; } - return (BYTE)0xff; + return (uint8_t)0xff; } +#endif /* ---------------------------------------------------------------------*/ /* snapshot support functions */ @@ -1093,7 +1172,7 @@ static BYTE sfx_soundexpander_piano_read(WORD addr) DBL | freqbase | 0.0+ | freqbase */ -static char snap_module_name[] = "CARTSFXSE"; +static const char snap_module_name[] = "CARTSFXSE"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -1114,94 +1193,94 @@ int sfx_soundexpander_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)sfx_soundexpander_io_swap) < 0 - || SMW_DW(m, (DWORD)sfx_soundexpander_chip) < 0 - || SMW_B(m, (BYTE)snd.command) < 0) { + || SMW_B(m, (uint8_t)sfx_soundexpander_io_swap) < 0 + || SMW_DW(m, (uint32_t)sfx_soundexpander_chip) < 0 + || SMW_B(m, (uint8_t)snd.command) < 0) { goto fail; } for (x = 0; x < 9; x++) { for (y = 0; y < 2; y++) { if (0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].ar) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].dr) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].rr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].KSR) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].ksl) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].ksr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].mul) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].Cnt) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].Incr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].FB) < 0 - || SMW_DW(m, (DWORD)connect1_is_output0(chip->P_CH[x].SLOT[y].connect1)) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].op1_out[0]) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].op1_out[1]) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].CON) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_type) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].state) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].TL) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].TLL) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].volume) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].sl) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sh_ar) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sel_ar) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sh_dr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sel_dr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sh_rr) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].eg_sel_rr) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].key) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].SLOT[y].AMmask) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].SLOT[y].vib) < 0 - || SMW_W(m, (WORD)chip->P_CH[x].SLOT[y].wavetable) < 0) { + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].ar) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].dr) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].rr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].KSR) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].ksl) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].ksr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].mul) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].Cnt) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].Incr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].FB) < 0 + || SMW_DW(m, (uint32_t)connect1_is_output0(chip->P_CH[x].SLOT[y].connect1)) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].op1_out[0]) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].op1_out[1]) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].CON) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_type) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].state) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].TL) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].TLL) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].volume) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].sl) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sh_ar) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sel_ar) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sh_dr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sel_dr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sh_rr) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].eg_sel_rr) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].key) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].SLOT[y].AMmask) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].SLOT[y].vib) < 0 + || SMW_W(m, (uint16_t)chip->P_CH[x].SLOT[y].wavetable) < 0) { goto fail; } } if (0 - || SMW_DW(m, (DWORD)chip->P_CH[x].block_fnum) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].fc) < 0 - || SMW_DW(m, (DWORD)chip->P_CH[x].ksl_base) < 0 - || SMW_B(m, (BYTE)chip->P_CH[x].kcode) < 0) { + || SMW_DW(m, (uint32_t)chip->P_CH[x].block_fnum) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].fc) < 0 + || SMW_DW(m, (uint32_t)chip->P_CH[x].ksl_base) < 0 + || SMW_B(m, (uint8_t)chip->P_CH[x].kcode) < 0) { goto fail; } } if (0 - || SMW_DW(m, (DWORD)chip->eg_cnt) < 0 - || SMW_DW(m, (DWORD)chip->eg_timer) < 0 - || SMW_DW(m, (DWORD)chip->eg_timer_add) < 0 - || SMW_DW(m, (DWORD)chip->eg_timer_overflow) < 0 - || SMW_B(m, (BYTE)chip->rhythm) < 0) { + || SMW_DW(m, (uint32_t)chip->eg_cnt) < 0 + || SMW_DW(m, (uint32_t)chip->eg_timer) < 0 + || SMW_DW(m, (uint32_t)chip->eg_timer_add) < 0 + || SMW_DW(m, (uint32_t)chip->eg_timer_overflow) < 0 + || SMW_B(m, (uint8_t)chip->rhythm) < 0) { goto fail; } for (x = 0; x < 1024; x++) { - if (SMW_DW(m, (DWORD)chip->fn_tab[x]) < 0) { + if (SMW_DW(m, (uint32_t)chip->fn_tab[x]) < 0) { goto fail; } } if (0 - || SMW_B(m, (BYTE)chip->lfo_am_depth) < 0 - || SMW_B(m, (BYTE)chip->lfo_pm_depth_range) < 0 - || SMW_DW(m, (DWORD)chip->lfo_am_cnt) < 0 - || SMW_DW(m, (DWORD)chip->lfo_am_inc) < 0 - || SMW_DW(m, (DWORD)chip->lfo_pm_cnt) < 0 - || SMW_DW(m, (DWORD)chip->lfo_pm_inc) < 0 - || SMW_DW(m, (DWORD)chip->noise_rng) < 0 - || SMW_DW(m, (DWORD)chip->noise_p) < 0 - || SMW_DW(m, (DWORD)chip->noise_f) < 0 - || SMW_B(m, (BYTE)chip->wavesel) < 0 - || SMW_DW(m, (DWORD)chip->T[0]) < 0 - || SMW_DW(m, (DWORD)chip->T[1]) < 0 - || SMW_B(m, (BYTE)chip->st[0]) < 0 - || SMW_B(m, (BYTE)chip->st[1]) < 0 - || SMW_B(m, (BYTE)chip->type) < 0 - || SMW_B(m, (BYTE)chip->address) < 0 - || SMW_B(m, (BYTE)chip->status) < 0 - || SMW_B(m, (BYTE)chip->statusmask) < 0 - || SMW_B(m, (BYTE)chip->mode) < 0 - || SMW_DW(m, (DWORD)chip->clock) < 0 - || SMW_DW(m, (DWORD)chip->rate) < 0 + || SMW_B(m, (uint8_t)chip->lfo_am_depth) < 0 + || SMW_B(m, (uint8_t)chip->lfo_pm_depth_range) < 0 + || SMW_DW(m, (uint32_t)chip->lfo_am_cnt) < 0 + || SMW_DW(m, (uint32_t)chip->lfo_am_inc) < 0 + || SMW_DW(m, (uint32_t)chip->lfo_pm_cnt) < 0 + || SMW_DW(m, (uint32_t)chip->lfo_pm_inc) < 0 + || SMW_DW(m, (uint32_t)chip->noise_rng) < 0 + || SMW_DW(m, (uint32_t)chip->noise_p) < 0 + || SMW_DW(m, (uint32_t)chip->noise_f) < 0 + || SMW_B(m, (uint8_t)chip->wavesel) < 0 + || SMW_DW(m, (uint32_t)chip->T[0]) < 0 + || SMW_DW(m, (uint32_t)chip->T[1]) < 0 + || SMW_B(m, (uint8_t)chip->st[0]) < 0 + || SMW_B(m, (uint8_t)chip->st[1]) < 0 + || SMW_B(m, (uint8_t)chip->type) < 0 + || SMW_B(m, (uint8_t)chip->address) < 0 + || SMW_B(m, (uint8_t)chip->status) < 0 + || SMW_B(m, (uint8_t)chip->statusmask) < 0 + || SMW_B(m, (uint8_t)chip->mode) < 0 + || SMW_DW(m, (uint32_t)chip->clock) < 0 + || SMW_DW(m, (uint32_t)chip->rate) < 0 || SMW_DB(m, (double)chip->freqbase) < 0) { goto fail; } @@ -1215,7 +1294,7 @@ int sfx_soundexpander_snapshot_write_module(snapshot_t *s) int sfx_soundexpander_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int temp_chip; FM_OPL *chip = NULL; @@ -1229,13 +1308,13 @@ int sfx_soundexpander_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &sfx_soundexpander_io_swap) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/sfx_soundexpander.h b/src/Emulators/vice/c64/cart/sfx_soundexpander.h index 9d0862a1..fa887da7 100644 --- a/src/Emulators/vice/c64/cart/sfx_soundexpander.h +++ b/src/Emulators/vice/c64/cart/sfx_soundexpander.h @@ -30,19 +30,21 @@ #include "vicetypes.h" #include "sound.h" -extern int sfx_soundexpander_cart_enabled(void); -extern void sfx_soundexpander_reset(void); -extern int sfx_soundexpander_enable(void); -extern void sfx_soundexpander_detach(void); +int sfx_soundexpander_cart_enabled(void); +void sfx_soundexpander_reset(void); +int sfx_soundexpander_enable(void); +int sfx_soundexpander_disable(void); +void sfx_soundexpander_detach(void); -extern int sfx_soundexpander_resources_init(void); -extern void sfx_soundexpander_resources_shutdown(void); -extern int sfx_soundexpander_cmdline_options_init(void); +int sfx_soundexpander_resources_init(void); +void sfx_soundexpander_resources_shutdown(void); +int sfx_soundexpander_cmdline_options_init(void); -extern void sfx_soundexpander_sound_chip_init(void); +void sfx_soundexpander_sound_chip_init(void); struct snapshot_s; -extern int sfx_soundexpander_snapshot_read_module(struct snapshot_s *s); -extern int sfx_soundexpander_snapshot_write_module(struct snapshot_s *s); + +int sfx_soundexpander_snapshot_read_module(struct snapshot_s *s); +int sfx_soundexpander_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/sfx_soundsampler.c b/src/Emulators/vice/c64/cart/sfx_soundsampler.c index dd2e769b..15073154 100644 --- a/src/Emulators/vice/c64/cart/sfx_soundsampler.c +++ b/src/Emulators/vice/c64/cart/sfx_soundsampler.c @@ -46,47 +46,50 @@ #include "snapshot.h" #include "sound.h" #include "uiapi.h" -#include "translate.h" /* ------------------------------------------------------------------------- */ -static BYTE current_sample = 0x80; +static uint8_t current_sample = 0x80; /* ------------------------------------------------------------------------- */ /* some prototypes are needed */ -static void sfx_soundsampler_sound_store(WORD addr, BYTE value); -static BYTE sfx_soundsampler_sample_read(WORD addr); -static void sfx_soundsampler_latch_sample(WORD addr, BYTE value); +static void sfx_soundsampler_sound_store(uint16_t addr, uint8_t value); +static uint8_t sfx_soundsampler_sample_read(uint16_t addr); +static void sfx_soundsampler_latch_sample(uint16_t addr, uint8_t value); static io_source_t sfx_soundsampler_io1_device = { - CARTRIDGE_NAME_SFX_SOUND_SAMPLER, - IO_DETACH_RESOURCE, - "SFXSoundSampler", - 0xde00, 0xdeff, 0x01, - 0, - sfx_soundsampler_latch_sample, - NULL, - NULL, /* TODO: peek */ - NULL, /* nothing to dump */ - CARTRIDGE_SFX_SOUND_SAMPLER, - 0, - 0 + CARTRIDGE_NAME_SFX_SOUND_SAMPLER, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SFXSoundSampler", /* resource to set to '0' */ + 0xde00, 0xdeff, 0x00, /* range for the device, reg:$de00, mirrors:$de01-$deff, range is different on vic20 */ + 0, /* read is never valid, reg is write only */ + sfx_soundsampler_latch_sample, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + NULL, /* TODO: peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_SFX_SOUND_SAMPLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t sfx_soundsampler_io2_device = { - CARTRIDGE_NAME_SFX_SOUND_SAMPLER, - IO_DETACH_RESOURCE, - "SFXSoundSampler", - 0xdf00, 0xdfff, 0x01, - 1, - sfx_soundsampler_sound_store, - sfx_soundsampler_sample_read, - NULL, /* TODO: peek */ - NULL, /* nothing to dump */ - CARTRIDGE_SFX_SOUND_SAMPLER, - 0, - 0 + CARTRIDGE_NAME_SFX_SOUND_SAMPLER, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SFXSoundSampler", /* resource to set to '0' */ + 0xdf00, 0xdfff, 0x00, /* range for the device, reg:$df00, mirrors:$df01-$dfff, range is different on vic20 */ + 1, /* read is always valid */ + sfx_soundsampler_sound_store, /* store function */ + NULL, /* NO poke function */ + sfx_soundsampler_sample_read, /* read function */ + NULL, /* TODO: peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_SFX_SOUND_SAMPLER, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *sfx_soundsampler_io1_list_item = NULL; @@ -100,11 +103,16 @@ static const export_resource_t export_res = { /* Some prototypes are needed */ static int sfx_soundsampler_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); -static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); -static void sfx_soundsampler_sound_machine_store(sound_t *psid, WORD addr, BYTE val); -static BYTE sfx_soundsampler_sound_machine_read(sound_t *psid, WORD addr); +static void sfx_soundsampler_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val); +static uint8_t sfx_soundsampler_sound_machine_read(sound_t *psid, uint16_t addr); static void sfx_soundsampler_sound_reset(sound_t *psid, CLOCK cpu_clk); +#ifdef SOUND_SYSTEM_FLOAT +static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int sfx_soundsampler_sound_machine_cycle_based(void) { return 0; @@ -115,20 +123,34 @@ static int sfx_soundsampler_sound_machine_channels(void) return 1; } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the SFX Sound Sampler sound */ +static sound_chip_mixing_spec_t sfx_soundsampler_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* left channel volume % in case of stereo output, default output to both */ + 100 /* right channel volume % in case of stereo output, default output to both */ + } +}; +#endif + +/* SFX Sound Sampler cartridge sound chip */ static sound_chip_t sfx_soundsampler_sound_chip = { - NULL, /* no open */ - sfx_soundsampler_sound_machine_init, - NULL, /* no close */ - sfx_soundsampler_sound_machine_calculate_samples, - sfx_soundsampler_sound_machine_store, - sfx_soundsampler_sound_machine_read, - sfx_soundsampler_sound_reset, - sfx_soundsampler_sound_machine_cycle_based, - sfx_soundsampler_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + sfx_soundsampler_sound_machine_init, /* sound chip init function */ + NULL, /* NO sound chip close function */ + sfx_soundsampler_sound_machine_calculate_samples, /* sound chip calculate samples function */ + sfx_soundsampler_sound_machine_store, /* sound chip store function */ + sfx_soundsampler_sound_machine_read, /* sound chip read function */ + sfx_soundsampler_sound_reset, /* sound chip reset function */ + sfx_soundsampler_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, sound chip is NOT cycle based */ + sfx_soundsampler_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */ +#ifdef SOUND_SYSTEM_FLOAT + sfx_soundsampler_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* chip enabled, toggled when sound chip is (de-)activated */ }; -static WORD sfx_soundsampler_sound_chip_offset = 0; +static uint16_t sfx_soundsampler_sound_chip_offset = 0; static sound_dac_t sfx_soundsampler_dac; void sfx_soundsampler_sound_chip_init(void) @@ -212,6 +234,13 @@ int sfx_soundsampler_enable(void) return resources_set_int("SFXSoundSampler", 1); } + +int sfx_soundsampler_disable(void) +{ + return resources_set_int("SFXSoundSampler", 0); +} + + void sfx_soundsampler_detach(void) { resources_set_int("SFXSoundSampler", 0); @@ -247,31 +276,23 @@ void sfx_soundsampler_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-sfxss", SET_RESOURCE, 0, + { "-sfxss", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundSampler", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SFX_SS, - NULL, NULL }, - { "+sfxss", SET_RESOURCE, 0, + NULL, "Enable the SFX Sound Sampler cartridge" }, + { "+sfxss", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundSampler", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SFX_SS, - NULL, NULL }, + NULL, "Disable the SFX Sound Sampler cartridge" }, CMDLINE_LIST_END }; static const cmdline_option_t cmdline_mascuerade_options[] = { - { "-sfxssioswap", SET_RESOURCE, 0, + { "-sfxssioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundSamplerIOSwap", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MAP_CART_IO_2, - NULL, NULL }, - { "+sfxssioswap", SET_RESOURCE, 0, + NULL, "Swap io mapping (map cart I/O to VIC20 I/O-2)" }, + { "+sfxssioswap", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SFXSoundSamplerIOSwap", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_MAP_CART_IO_3, - NULL, NULL }, + NULL, "Don't swap io mapping (map cart I/O to VIC20 I/O-3)" }, CMDLINE_LIST_END }; @@ -287,36 +308,44 @@ int sfx_soundsampler_cmdline_options_init(void) /* ---------------------------------------------------------------------*/ -static void sfx_soundsampler_latch_sample(WORD addr, BYTE value) +static void sfx_soundsampler_latch_sample(uint16_t addr, uint8_t value) { current_sample = sampler_get_sample(SAMPLER_CHANNEL_DEFAULT); } -static BYTE sfx_soundsampler_sample_read(WORD addr) +static uint8_t sfx_soundsampler_sample_read(uint16_t addr) { return current_sample; } /* ---------------------------------------------------------------------*/ -static BYTE sfx_soundsampler_sound_data; +static uint8_t sfx_soundsampler_sound_data; -static void sfx_soundsampler_sound_store(WORD addr, BYTE value) +static void sfx_soundsampler_sound_store(uint16_t addr, uint8_t value) { sfx_soundsampler_sound_data = value; sound_store(sfx_soundsampler_sound_chip_offset, value, 0); } struct sfx_soundsampler_sound_s { - BYTE voice0; + uint8_t voice0; }; static struct sfx_soundsampler_sound_s snd; -static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) +{ + return sound_dac_calculate_samples(&sfx_soundsampler_dac, pbuf, (int)snd.voice0 * 128, nr); +} +#else +static int sfx_soundsampler_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) { - return sound_dac_calculate_samples(&sfx_soundsampler_dac, pbuf, (int)snd.voice0 * 128, nr, soc, (soc > 1) ? 3 : 1); + return sound_dac_calculate_samples(&sfx_soundsampler_dac, pbuf, (int)snd.voice0 * 128, nr, soc, (soc == SOUND_OUTPUT_STEREO) ? SOUND_CHANNELS_1_AND_2 : SOUND_CHANNEL_1); } +#endif static int sfx_soundsampler_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec) { @@ -326,12 +355,12 @@ static int sfx_soundsampler_sound_machine_init(sound_t *psid, int speed, int cyc return 1; } -static void sfx_soundsampler_sound_machine_store(sound_t *psid, WORD addr, BYTE val) +static void sfx_soundsampler_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val) { snd.voice0 = val; } -static BYTE sfx_soundsampler_sound_machine_read(sound_t *psid, WORD addr) +static uint8_t sfx_soundsampler_sound_machine_read(sound_t *psid, uint16_t addr) { return sfx_soundsampler_sound_data; } @@ -353,7 +382,7 @@ static void sfx_soundsampler_sound_reset(sound_t *psid, CLOCK cpu_clk) BYTE | sound data | 0.0+ | sound data */ -static char snap_module_name[] = "CARTSFXSS"; +static const char snap_module_name[] = "CARTSFXSS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -368,8 +397,8 @@ int sfx_soundsampler_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)sfx_soundsampler_io_swap) < 0 - || SMW_B(m, (BYTE)sfx_soundsampler_sound_data) < 0) { + || SMW_B(m, (uint8_t)sfx_soundsampler_io_swap) < 0 + || SMW_B(m, (uint8_t)sfx_soundsampler_sound_data) < 0) { snapshot_module_close(m); return -1; } @@ -379,7 +408,7 @@ int sfx_soundsampler_snapshot_write_module(snapshot_t *s) int sfx_soundsampler_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -389,13 +418,13 @@ int sfx_soundsampler_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &sfx_soundsampler_io_swap) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/sfx_soundsampler.h b/src/Emulators/vice/c64/cart/sfx_soundsampler.h index ad57b75c..f647ac9c 100644 --- a/src/Emulators/vice/c64/cart/sfx_soundsampler.h +++ b/src/Emulators/vice/c64/cart/sfx_soundsampler.h @@ -30,19 +30,21 @@ #include "vicetypes.h" #include "sound.h" -extern int sfx_soundsampler_cart_enabled(void); -extern void sfx_soundsampler_reset(void); -extern int sfx_soundsampler_enable(void); -extern void sfx_soundsampler_detach(void); +int sfx_soundsampler_cart_enabled(void); +void sfx_soundsampler_reset(void); +int sfx_soundsampler_enable(void); +int sfx_soundsampler_disable(void); +void sfx_soundsampler_detach(void); -extern int sfx_soundsampler_resources_init(void); -extern void sfx_soundsampler_resources_shutdown(void); -extern int sfx_soundsampler_cmdline_options_init(void); +int sfx_soundsampler_resources_init(void); +void sfx_soundsampler_resources_shutdown(void); +int sfx_soundsampler_cmdline_options_init(void); -extern void sfx_soundsampler_sound_chip_init(void); +void sfx_soundsampler_sound_chip_init(void); struct snapshot_s; -extern int sfx_soundsampler_snapshot_read_module(struct snapshot_s *s); -extern int sfx_soundsampler_snapshot_write_module(struct snapshot_s *s); + +int sfx_soundsampler_snapshot_read_module(struct snapshot_s *s); +int sfx_soundsampler_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/shortbus.c b/src/Emulators/vice/c64/cart/shortbus.c index 3501b9f4..83dacefb 100644 --- a/src/Emulators/vice/c64/cart/shortbus.c +++ b/src/Emulators/vice/c64/cart/shortbus.c @@ -34,10 +34,13 @@ #include "shortbus_digimax.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include "shortbus_etfe.h" #endif +#include "shortbus.h" + + /* TODO */ #if 0 #include "shortbus_duart.h" @@ -50,7 +53,7 @@ int shortbus_resources_init(void) return -1; } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (shortbus_etfe_resources_init() < 0) { return -1; } @@ -74,7 +77,7 @@ void shortbus_resources_shutdown(void) { shortbus_digimax_resources_shutdown(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET shortbus_etfe_resources_shutdown(); #endif @@ -92,7 +95,7 @@ int shortbus_cmdline_options_init(void) return -1; } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (shortbus_etfe_cmdline_options_init() < 0) { return -1; } @@ -112,11 +115,11 @@ int shortbus_cmdline_options_init(void) return 0; } -extern void shortbus_unregister(void) +void shortbus_unregister(void) { shortbus_digimax_unregister(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET shortbus_etfe_unregister(); #endif @@ -128,11 +131,11 @@ extern void shortbus_unregister(void) } -extern void shortbus_register(void) +void shortbus_register(void) { shortbus_digimax_register(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET shortbus_etfe_register(); #endif @@ -147,7 +150,7 @@ void shortbus_reset(void) { shortbus_digimax_reset(); -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET shortbus_etfe_reset(); #endif @@ -171,7 +174,7 @@ void shortbus_reset(void) BYTE | eth64 active | eth64 active flag */ -static char snap_module_name[] = "SHORTBUS"; +static const char snap_module_name[] = "SHORTBUS"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -186,7 +189,7 @@ int shortbus_write_snapshot_module(snapshot_t *s) devices[0] = 1; } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (shortbus_etfe_enabled()) { ++active_devices; devices[2] = 1; @@ -212,11 +215,11 @@ int shortbus_write_snapshot_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)active_devices) < 0 - || SMW_B(m, (BYTE)devices[0]) < 0 - || SMW_B(m, (BYTE)devices[1]) < 0 - || SMW_B(m, (BYTE)devices[2]) < 0 - || SMW_B(m, (BYTE)devices[3]) < 0) { + || SMW_B(m, (uint8_t)active_devices) < 0 + || SMW_B(m, (uint8_t)devices[0]) < 0 + || SMW_B(m, (uint8_t)devices[1]) < 0 + || SMW_B(m, (uint8_t)devices[2]) < 0 + || SMW_B(m, (uint8_t)devices[3]) < 0) { snapshot_module_close(m); return -1; } @@ -229,7 +232,7 @@ int shortbus_write_snapshot_module(snapshot_t *s) } } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (devices[2]) { if (shortbus_etfe_write_snapshot_module(s) < 0) { return -1; @@ -257,7 +260,7 @@ int shortbus_write_snapshot_module(snapshot_t *s) int shortbus_read_snapshot_module(snapshot_t *s) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; int active_devices; int devices[4]; @@ -269,7 +272,7 @@ int shortbus_read_snapshot_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (major_version > SNAP_MAJOR || minor_version > SNAP_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -289,14 +292,14 @@ int shortbus_read_snapshot_module(snapshot_t *s) if (devices[0]) { if (shortbus_digimax_read_snapshot_module(s) < 0) { return -1; - } + } } -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET if (devices[2]) { if (shortbus_etfe_read_snapshot_module(s) < 0) { return -1; - } + } } #endif @@ -305,12 +308,12 @@ int shortbus_read_snapshot_module(snapshot_t *s) if (devices[1]) { if (shortbus_duart_read_snapshot_module(s) < 0) { return -1; - } + } } if (devices[3]) { if (shortbus_eth64_read_snapshot_module(s) < 0) { return -1; - } + } } #endif } diff --git a/src/Emulators/vice/c64/cart/shortbus.h b/src/Emulators/vice/c64/cart/shortbus.h index e6326798..400e1a47 100644 --- a/src/Emulators/vice/c64/cart/shortbus.h +++ b/src/Emulators/vice/c64/cart/shortbus.h @@ -29,17 +29,17 @@ #include "vicetypes.h" -extern int shortbus_resources_init(void); -extern void shortbus_resources_shutdown(void); +int shortbus_resources_init(void); +void shortbus_resources_shutdown(void); -extern int shortbus_cmdline_options_init(void); +int shortbus_cmdline_options_init(void); -extern void shortbus_unregister(void); -extern void shortbus_register(void); +void shortbus_unregister(void); +void shortbus_register(void); -extern void shortbus_reset(void); +void shortbus_reset(void); -extern int shortbus_write_snapshot_module(snapshot_t *s); -extern int shortbus_read_snapshot_module(snapshot_t *s); +int shortbus_write_snapshot_module(snapshot_t *s); +int shortbus_read_snapshot_module(snapshot_t *s); #endif diff --git a/src/Emulators/vice/c64/cart/shortbus_digimax.c b/src/Emulators/vice/c64/cart/shortbus_digimax.c index 955c35f1..96f70d7f 100644 --- a/src/Emulators/vice/c64/cart/shortbus_digimax.c +++ b/src/Emulators/vice/c64/cart/shortbus_digimax.c @@ -37,7 +37,6 @@ #include "resources.h" #include "snapshot.h" #include "sound.h" -#include "translate.h" #include "util.h" //#include "digimaxcore.c" @@ -74,122 +73,147 @@ */ /* This source file contains the sound core for the cartridge, - the shortbus and userport versions of the device, and is intended - to be included from a specific digimax device. */ + the shortbus and userport versions of the device, and is intended + to be included from a specific digimax device. */ /* Some prototypes are needed */ static int digimax_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec); -static int digimax_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int sound_output_channels, int sound_chip_channels, int *delta_t); -static void digimax_sound_machine_store(sound_t *psid, WORD addr, BYTE val); -static BYTE digimax_sound_machine_read(sound_t *psid, WORD addr); +static void digimax_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val); +static uint8_t digimax_sound_machine_read(sound_t *psid, uint16_t addr); static void digimax_sound_reset(sound_t *psid, CLOCK cpu_clk); +#ifdef SOUND_SYSTEM_FLOAT +static int digimax_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int sound_chip_channels, CLOCK *delta_t); +#else +static int digimax_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int sound_output_channels, int sound_chip_channels, CLOCK *delta_t); +#endif + static int digimax_sound_machine_cycle_based(void) { - return 0; + return 0; } static int digimax_sound_machine_channels(void) { - return 1; /* FIXME: needs to become stereo for stereo capable ports */ + return 4; } +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the DigiMAX sound */ +static sound_chip_mixing_spec_t digimax_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* DAC 1 left channel volume % in case of stereo output, default output to left only */ + 0, /* DAC 1 right channel volume % in case of stereo output, default output to left only */ + }, + { + 100, /* DAC 2 left channel volume % in case of stereo output, default output to left only */ + 0, /* DAC 2 right channel volume % in case of stereo output, default output to left only */ + }, + { + 0, /* DAC 3 left channel volume % in case of stereo output, default output to right only */ + 100, /* DAC 3 right channel volume % in case of stereo output, default output to right only */ + }, + { + 0, /* DAC 4 left channel volume % in case of stereo output, default output to right only */ + 100, /* DAC 4 right channel volume % in case of stereo output, default output to right only */ + } +}; +#endif + +/* DigiMAX sound chip, as used in the IDE64-shortbus DigiMAX device, userport DigiMAX device and c64/c128 DigiMAX cartridge */ static sound_chip_t digimax_sound_chip = { - NULL, /* no open */ - digimax_sound_machine_init, - NULL, /* no close */ - digimax_sound_machine_calculate_samples, - digimax_sound_machine_store, - digimax_sound_machine_read, - digimax_sound_reset, - digimax_sound_machine_cycle_based, - digimax_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + digimax_sound_machine_init, /* sound chip init function */ + NULL, /* NO sound chip close function */ + digimax_sound_machine_calculate_samples, /* sound chip calculate samples function */ + digimax_sound_machine_store, /* sound chip store function */ + digimax_sound_machine_read, /* sound chip read function */ + digimax_sound_reset, /* sound chip reset function */ + digimax_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, chip is NOT cycle based */ + digimax_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 4 channels */ +#ifdef SOUND_SYSTEM_FLOAT + digimax_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* sound chip enabled flag, toggled upon device (de-)activation */ }; -static WORD digimax_sound_chip_offset = 0; +static uint16_t digimax_sound_chip_offset = 0; /* ---------------------------------------------------------------------*/ static sound_dac_t digimax_dac[4]; -static BYTE digimax_sound_data[4]; +static uint8_t digimax_sound_data[4]; struct digimax_sound_s { - BYTE voice0; - BYTE voice1; - BYTE voice2; - BYTE voice3; + uint8_t voice[4]; }; static struct digimax_sound_s snd; -static int digimax_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME: fix this for multichannel output */ +static int digimax_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) { - sound_dac_calculate_samples(&digimax_dac[0], pbuf, (int)snd.voice0 * 64, nr, soc, 1); - sound_dac_calculate_samples(&digimax_dac[1], pbuf, (int)snd.voice1 * 64, nr, soc, (soc > 1) ? 2 : 1); - sound_dac_calculate_samples(&digimax_dac[2], pbuf, (int)snd.voice2 * 64, nr, soc, 1); - sound_dac_calculate_samples(&digimax_dac[3], pbuf, (int)snd.voice3 * 64, nr, soc, (soc > 1) ? 2 : 1); - return nr; + sound_dac_calculate_samples(&digimax_dac[scc], pbuf, (int)snd.voice[scc] * 64, nr); + + return nr; +} +#else +static int digimax_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) +{ + sound_dac_calculate_samples(&digimax_dac[0], pbuf, (int)snd.voice[0] * 64, nr, soc, SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[1], pbuf, (int)snd.voice[1] * 64, nr, soc, (soc == SOUND_OUTPUT_STEREO) ? SOUND_CHANNEL_2 : SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[2], pbuf, (int)snd.voice[2] * 64, nr, soc, SOUND_CHANNEL_1); + sound_dac_calculate_samples(&digimax_dac[3], pbuf, (int)snd.voice[3] * 64, nr, soc, (soc == SOUND_OUTPUT_STEREO) ? SOUND_CHANNEL_2 : SOUND_CHANNEL_1); + return nr; } +#endif static int digimax_sound_machine_init(sound_t *psid, int speed, int cycles_per_sec) { - sound_dac_init(&digimax_dac[0], speed); - sound_dac_init(&digimax_dac[1], speed); - sound_dac_init(&digimax_dac[2], speed); - sound_dac_init(&digimax_dac[3], speed); - snd.voice0 = 0; - snd.voice1 = 0; - snd.voice2 = 0; - snd.voice3 = 0; - - return 1; + sound_dac_init(&digimax_dac[0], speed); + sound_dac_init(&digimax_dac[1], speed); + sound_dac_init(&digimax_dac[2], speed); + sound_dac_init(&digimax_dac[3], speed); + snd.voice[0] = 0; + snd.voice[1] = 0; + snd.voice[2] = 0; + snd.voice[3] = 0; + + return 1; } -static void digimax_sound_machine_store(sound_t *psid, WORD addr, BYTE val) +static void digimax_sound_machine_store(sound_t *psid, uint16_t addr, uint8_t val) { - switch (addr & 3) { - case 0: - snd.voice0 = val; - break; - case 1: - snd.voice1 = val; - break; - case 2: - snd.voice2 = val; - break; - case 3: - snd.voice3 = val; - break; - } + snd.voice[addr & 3] = val; } -static BYTE digimax_sound_machine_read(sound_t *psid, WORD addr) +static uint8_t digimax_sound_machine_read(sound_t *psid, uint16_t addr) { - return digimax_sound_data[addr & 3]; + return digimax_sound_data[addr & 3]; } static void digimax_sound_reset(sound_t *psid, CLOCK cpu_clk) { - snd.voice0 = 0; - snd.voice1 = 0; - snd.voice2 = 0; - snd.voice3 = 0; - digimax_sound_data[0] = 0; - digimax_sound_data[1] = 0; - digimax_sound_data[2] = 0; - digimax_sound_data[3] = 0; + snd.voice[0] = 0; + snd.voice[1] = 0; + snd.voice[2] = 0; + snd.voice[3] = 0; + digimax_sound_data[0] = 0; + digimax_sound_data[1] = 0; + digimax_sound_data[2] = 0; + digimax_sound_data[3] = 0; } - -/// digimaxcore.c starts +/// digimaxcore.c ends /// /// /// +#include "shortbus_digimax.h" /* Digimax Short Bus expansion @@ -205,7 +229,7 @@ static void digimax_sound_reset(sound_t *psid, CLOCK cpu_clk) /* This flag indicates if the IDE64 cart is active */ static int shortbus_digimax_host_active = 0; -/* This flag indicated if the expansion is active, +/* This flag indicates if the expansion is active, real activity depends on the 'host' active flag */ static int shortbus_digimax_expansion_active = 0; @@ -217,22 +241,24 @@ static char *shortbus_digimax_address_list = NULL; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static void shortbus_digimax_sound_store(WORD addr, BYTE value); -static BYTE shortbus_digimax_sound_read(WORD addr); +static void shortbus_digimax_sound_store(uint16_t addr, uint8_t value); +static uint8_t shortbus_digimax_sound_read(uint16_t addr); static io_source_t digimax_device = { - "ShortBus " CARTRIDGE_NAME_DIGIMAX, - IO_DETACH_RESOURCE, - "SBDIGIMAX", - 0xde40, 0xde47, 0x03, - 1, /* read is always valid */ - shortbus_digimax_sound_store, - shortbus_digimax_sound_read, - shortbus_digimax_sound_read, - NULL, /* nothing to dump */ - CARTRIDGE_IDE64, - 0, - 0 + "ShortBus " CARTRIDGE_NAME_DIGIMAX, /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SBDIGIMAX", /* resource to set to '0' */ + 0xde40, 0xde47, 0x03, /* range for the device, regs:$de40-$de43, mirrors:$de44-$de47 */ + 1, /* read is always valid */ + shortbus_digimax_sound_store, /* store function */ + NULL, /* NO poke function */ + shortbus_digimax_sound_read, /* read function */ + shortbus_digimax_sound_read, /* peek function */ + NULL, /* nothing to dump */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *shortbus_digimax_list_item = NULL; @@ -244,15 +270,15 @@ void shortbus_digimax_sound_chip_init(void) digimax_sound_chip_offset = sound_chip_register(&digimax_sound_chip); } -static void shortbus_digimax_sound_store(WORD addr, BYTE value) +static void shortbus_digimax_sound_store(uint16_t addr, uint8_t value) { digimax_sound_data[addr] = value; - sound_store((WORD)(digimax_sound_chip_offset | addr), value, 0); + sound_store((uint16_t)(digimax_sound_chip_offset | addr), value, 0); } -static BYTE shortbus_digimax_sound_read(WORD addr) +static uint8_t shortbus_digimax_sound_read(uint16_t addr) { - BYTE value = sound_read((WORD)(digimax_sound_chip_offset | addr), 0); + uint8_t value = sound_read((uint16_t)(digimax_sound_chip_offset | addr), 0); return value; } @@ -317,8 +343,8 @@ static int set_shortbus_digimax_base(int val, void *param) switch (addr) { case 0xde40: case 0xde48: - digimax_device.start_address = (WORD)addr; - digimax_device.end_address = (WORD)(addr + 3); + digimax_device.start_address = (uint16_t)addr; + digimax_device.end_address = (uint16_t)(addr + 3); break; default: return -1; @@ -362,26 +388,20 @@ void shortbus_digimax_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-sbdigimax", SET_RESOURCE, 0, + { "-sbdigimax", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SBDIGIMAX", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SHORTBUS_DIGIMAX, - NULL, NULL }, - { "+sbdigimax", SET_RESOURCE, 0, + NULL, "Enable the Short Bus DigiMAX expansion" }, + { "+sbdigimax", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SBDIGIMAX", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SHORTBUS_DIGIMAX, - NULL, NULL }, + NULL, "Disable the Short Bus DigiMAX expansion" }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-sbdigimaxbase", SET_RESOURCE, 1, + { "-sbdigimaxbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "SBDIGIMAXbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_SHORTBUS_DIGIMAX_BASE, - NULL, NULL }, + "", NULL }, CMDLINE_LIST_END }; @@ -394,7 +414,7 @@ int shortbus_digimax_cmdline_options_init(void) } temp1 = util_gen_hex_address_list(0xde40, 0xde50, 8); - shortbus_digimax_address_list = util_concat(". (", temp1, ")", NULL); + shortbus_digimax_address_list = util_concat("Base address of the Short Bus DigiMAX expansion. (", temp1, ")", NULL); lib_free(temp1); base_cmdline_options[0].description = shortbus_digimax_address_list; @@ -421,7 +441,7 @@ int shortbus_digimax_enabled(void) BYTE | voice 3 | voice 3 state */ -static char snap_module_name[] = "SHORTBUSDIGIMAX"; +static const char snap_module_name[] = "SHORTBUSDIGIMAX"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -436,12 +456,12 @@ int shortbus_digimax_write_snapshot_module(snapshot_t *s) } if (0 - || SMW_DW(m, (DWORD)shortbus_digimax_address) < 0 + || SMW_DW(m, (uint32_t)shortbus_digimax_address) < 0 || SMW_BA(m, digimax_sound_data, 4) < 0 - || SMW_B(m, snd.voice0) < 0 - || SMW_B(m, snd.voice1) < 0 - || SMW_B(m, snd.voice2) < 0 - || SMW_B(m, snd.voice3) < 0) { + || SMW_B(m, snd.voice[0]) < 0 + || SMW_B(m, snd.voice[1]) < 0 + || SMW_B(m, snd.voice[2]) < 0 + || SMW_B(m, snd.voice[3]) < 0) { snapshot_module_close(m); return -1; } @@ -451,7 +471,7 @@ int shortbus_digimax_write_snapshot_module(snapshot_t *s) int shortbus_digimax_read_snapshot_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int temp_digimax_address; @@ -462,7 +482,7 @@ int shortbus_digimax_read_snapshot_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -470,10 +490,10 @@ int shortbus_digimax_read_snapshot_module(snapshot_t *s) if (0 || SMR_DW_INT(m, &temp_digimax_address) < 0 || SMR_BA(m, digimax_sound_data, 4) < 0 - || SMR_B(m, &snd.voice0) < 0 - || SMR_B(m, &snd.voice1) < 0 - || SMR_B(m, &snd.voice2) < 0 - || SMR_B(m, &snd.voice3) < 0) { + || SMR_B(m, &snd.voice[0]) < 0 + || SMR_B(m, &snd.voice[1]) < 0 + || SMR_B(m, &snd.voice[2]) < 0 + || SMR_B(m, &snd.voice[3]) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/shortbus_digimax.h b/src/Emulators/vice/c64/cart/shortbus_digimax.h index c1d84470..edf47578 100644 --- a/src/Emulators/vice/c64/cart/shortbus_digimax.h +++ b/src/Emulators/vice/c64/cart/shortbus_digimax.h @@ -30,21 +30,21 @@ #include "snapshot.h" #include "vicetypes.h" -extern int shortbus_digimax_resources_init(void); -extern void shortbus_digimax_resources_shutdown(void); +int shortbus_digimax_resources_init(void); +void shortbus_digimax_resources_shutdown(void); -extern int shortbus_digimax_cmdline_options_init(void); +int shortbus_digimax_cmdline_options_init(void); -extern void shortbus_digimax_unregister(void); -extern void shortbus_digimax_register(void); +void shortbus_digimax_unregister(void); +void shortbus_digimax_register(void); -extern void shortbus_digimax_reset(void); +void shortbus_digimax_reset(void); -extern void shortbus_digimax_sound_chip_init(void); +void shortbus_digimax_sound_chip_init(void); -extern int shortbus_digimax_enabled(void); +int shortbus_digimax_enabled(void); -extern int shortbus_digimax_write_snapshot_module(snapshot_t *s); -extern int shortbus_digimax_read_snapshot_module(snapshot_t *s); +int shortbus_digimax_write_snapshot_module(snapshot_t *s); +int shortbus_digimax_read_snapshot_module(snapshot_t *s); #endif diff --git a/src/Emulators/vice/c64/cart/shortbus_etfe.c b/src/Emulators/vice/c64/cart/shortbus_etfe.c index a25685b5..0deb492d 100644 --- a/src/Emulators/vice/c64/cart/shortbus_etfe.c +++ b/src/Emulators/vice/c64/cart/shortbus_etfe.c @@ -26,7 +26,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -41,9 +41,10 @@ #include "monitor.h" #include "resources.h" #include "snapshot.h" -#include "translate.h" #include "util.h" +#include "shortbus_etfe.h" + /* "The Shortbus ETFE "Final Ethernet" device @@ -55,24 +56,26 @@ /* resources support functions */ /* Some prototypes are needed */ -static BYTE shortbus_etfe_read(WORD io_address); -static BYTE shortbus_etfe_peek(WORD io_address); -static void shortbus_etfe_store(WORD io_address, BYTE byte); +static uint8_t shortbus_etfe_read(uint16_t io_address); +static uint8_t shortbus_etfe_peek(uint16_t io_address); +static void shortbus_etfe_store(uint16_t io_address, uint8_t byte); static int shortbus_etfe_dump(void); static io_source_t shortbus_etfe_device = { - "Shortbus ETFE", - IO_DETACH_RESOURCE, - "SBETFE", - 0xde00, 0xde0f, 0x0f, - 0, - shortbus_etfe_store, - shortbus_etfe_read, - shortbus_etfe_peek, - shortbus_etfe_dump, - CARTRIDGE_IDE64, - 0, - 0 + "Shortbus ETFE", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "SBETFE", /* resource to set to '0' */ + 0xde00, 0xde0f, 0x0f, /* range for the device, regs:$de00-$de0f */ + 0, /* read validity determined by the device upon a read */ + shortbus_etfe_store, /* store function */ + NULL, /* NO poke function */ + shortbus_etfe_read, /* read function */ + shortbus_etfe_peek, /* peek function */ + shortbus_etfe_dump, /* device state information dump function */ + CARTRIDGE_IDE64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; /* current configurations */ @@ -84,15 +87,13 @@ static io_source_list_t *shortbus_etfe_list_item = NULL; /* This flag indicates if the IDE64 cart is active */ static int shortbus_etfe_host_active = 0; -/* This flag indicated if the expansion is active, +/* This flag indicates if the expansion is active, real activity depends on the 'host' active flag */ static int shortbus_etfe_expansion_active = 0; /* ETFE address */ static int shortbus_etfe_address; -static char *shortbus_etfe_address_list = NULL; - /* ---------------------------------------------------------------------*/ void shortbus_etfe_unregister(void) @@ -174,8 +175,8 @@ static int set_shortbus_etfe_base(int val, void *param) case 0xde00: case 0xde10: case 0xdf00: - shortbus_etfe_device.start_address = (WORD)addr; - shortbus_etfe_device.end_address = (WORD)(addr + 0xf); + shortbus_etfe_device.start_address = (uint16_t)addr; + shortbus_etfe_device.end_address = (uint16_t)(addr + 0xf); break; default: return -1; @@ -218,36 +219,26 @@ int shortbus_etfe_resources_init(void) void shortbus_etfe_resources_shutdown(void) { cs8900io_resources_shutdown(); - - if (shortbus_etfe_address_list) { - lib_free(shortbus_etfe_address_list); - } } /* ---------------------------------------------------------------------*/ static const cmdline_option_t cmdline_options[] = { - { "-sbetfe", SET_RESOURCE, 0, + { "-sbetfe", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SBETFE", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SHORTBUS_ETFE, - NULL, NULL }, - { "+sbtfe", SET_RESOURCE, 0, - NULL, NULL, "SBTFE", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SHORTBUS_ETFE, - NULL, NULL }, + NULL, "Enable the Short Bus ETFE expansion" }, + { "+sbetfe", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "SBETFE", (resource_value_t)0, + NULL, "Disable the Short Bus ETFE expansion" }, CMDLINE_LIST_END }; static cmdline_option_t base_cmdline_options[] = { - { "-sbtfebase", SET_RESOURCE, 1, - NULL, NULL, "SBTFEbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_BASE_ADDRESS, IDCLS_SHORTBUS_ETFE_BASE, - NULL, NULL }, + { "-sbetfebase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "SBETFEbase", NULL, + "", "Base address of the Short Bus ETFE expansion. (56832: $de00, 56848: $de10, 57088: $df00)" }, CMDLINE_LIST_END }; @@ -257,10 +248,6 @@ int shortbus_etfe_cmdline_options_init(void) return -1; } - shortbus_etfe_address_list = lib_stralloc(". (56832: $de00, 56848: $de10, 57088: $df00)"); - - base_cmdline_options[0].description = shortbus_etfe_address_list; - if (cs8900io_cmdline_options_init() < 0) { return -1; } @@ -276,7 +263,7 @@ int shortbus_etfe_enabled(void) /* ------------------------------------------------------------------------- */ /* ----- read byte from I/O range in VICE ----- */ -static BYTE shortbus_etfe_read(WORD io_address) +static uint8_t shortbus_etfe_read(uint16_t io_address) { shortbus_etfe_device.io_source_valid = 1; @@ -284,13 +271,13 @@ static BYTE shortbus_etfe_read(WORD io_address) } /* ----- peek byte with no sideeffects from I/O range in VICE ----- */ -static BYTE shortbus_etfe_peek(WORD io_address) +static uint8_t shortbus_etfe_peek(uint16_t io_address) { return cs8900io_peek(io_address); } /* ----- write byte to I/O range of VICE ----- */ -static void shortbus_etfe_store(WORD io_address, BYTE byte) +static void shortbus_etfe_store(uint16_t io_address, uint8_t byte) { cs8900io_store(io_address, byte); } @@ -298,7 +285,7 @@ static void shortbus_etfe_store(WORD io_address, BYTE byte) static int shortbus_etfe_dump(void) { mon_out("CS8900 mapped to $%04x ($%04x-$%04x).\n", - shortbus_etfe_device.start_address & ~shortbus_etfe_device.address_mask, + (unsigned int)(shortbus_etfe_device.start_address & ~shortbus_etfe_device.address_mask), shortbus_etfe_device.start_address, shortbus_etfe_device.end_address); @@ -339,7 +326,7 @@ int shortbus_etfe_read_snapshot_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); @@ -362,4 +349,4 @@ int shortbus_etfe_read_snapshot_module(snapshot_t *s) #endif } -#endif /* #ifdef HAVE_PCAP */ +#endif /* #ifdef HAVE_RAWNET */ diff --git a/src/Emulators/vice/c64/cart/shortbus_etfe.h b/src/Emulators/vice/c64/cart/shortbus_etfe.h index 210a20d0..3e9134ad 100644 --- a/src/Emulators/vice/c64/cart/shortbus_etfe.h +++ b/src/Emulators/vice/c64/cart/shortbus_etfe.h @@ -27,29 +27,29 @@ * */ -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #else - #error TFE.H should not be included if HAVE_PCAP is not defined! -#endif /* #ifdef HAVE_PCAP */ + #error TFE.H should not be included if HAVE_RAWNET is not defined! +#endif /* #ifdef HAVE_RAWNET */ #ifndef VICE_SHORTBUS_ETFE_H #define VICE_SHORTBUS_ETFE_H #include "snapshot.h" -extern int shortbus_etfe_resources_init(void); -extern void shortbus_etfe_resources_shutdown(void); +int shortbus_etfe_resources_init(void); +void shortbus_etfe_resources_shutdown(void); -extern int shortbus_etfe_cmdline_options_init(void); +int shortbus_etfe_cmdline_options_init(void); -extern void shortbus_etfe_unregister(void); -extern void shortbus_etfe_register(void); +void shortbus_etfe_unregister(void); +void shortbus_etfe_register(void); -extern void shortbus_etfe_reset(void); +void shortbus_etfe_reset(void); -extern int shortbus_etfe_enabled(void); +int shortbus_etfe_enabled(void); -extern int shortbus_etfe_write_snapshot_module(snapshot_t *s); -extern int shortbus_etfe_read_snapshot_module(snapshot_t *s); +int shortbus_etfe_write_snapshot_module(snapshot_t *s); +int shortbus_etfe_read_snapshot_module(snapshot_t *s); #endif diff --git a/src/Emulators/vice/c64/cart/silverrock128.c b/src/Emulators/vice/c64/cart/silverrock128.c index 5d1fffd8..8b55b5b9 100644 --- a/src/Emulators/vice/c64/cart/silverrock128.c +++ b/src/Emulators/vice/c64/cart/silverrock128.c @@ -202,15 +202,15 @@ #include "crt.h" -static const BYTE bank_seq[] = {0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15}; -/* static const BYTE bank_val[] = {0x00, 0x80, 0x10, 0x90, 0x20, 0xa0, 0x30, 0xb0, 0x40, 0xc0, 0x50, 0xd0, 0x60, 0xe0, 0x70, 0xf0}; */ +static const uint8_t bank_seq[] = {0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15}; +/* static const uint8_t bank_val[] = {0x00, 0x80, 0x10, 0x90, 0x20, 0xa0, 0x30, 0xb0, 0x40, 0xc0, 0x50, 0xd0, 0x60, 0xe0, 0x70, 0xf0}; */ -static BYTE regval = 0; +static uint8_t regval = 0; static int currbank = 0; -static void silverrock128_io1_store(WORD addr, BYTE value) +static void silverrock128_io1_store(uint16_t addr, uint8_t value) { - BYTE bank_number, bank_index; + uint8_t bank_number, bank_index; if (addr == 0x0) { /* Cartridge HW rev01 (or HW rev02 adressing first bank (special case)) */ @@ -219,7 +219,7 @@ static void silverrock128_io1_store(WORD addr, BYTE value) } else { if (addr <= 0x0f) { /* Cartridge HW rev02 */ - bank_number = (BYTE)addr; + bank_number = (uint8_t)addr; /* safe check that we've done things right... */ bank_index = ((value & 0xf0) >> 4); if (bank_number != bank_seq[bank_index]) { @@ -235,7 +235,7 @@ static void silverrock128_io1_store(WORD addr, BYTE value) currbank = bank_number; } -static BYTE silverrock128_io1_peek(WORD addr) +static uint8_t silverrock128_io1_peek(uint16_t addr) { return regval; } @@ -251,18 +251,20 @@ static int silverrock128_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t silverrock128_device = { - CARTRIDGE_NAME_SILVERROCK_128, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - silverrock128_io1_store, - NULL, - silverrock128_io1_peek, - silverrock128_dump, - CARTRIDGE_SILVERROCK_128, - 0, - 0 + CARTRIDGE_NAME_SILVERROCK_128, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read is never valid, regs are write only */ + silverrock128_io1_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + silverrock128_io1_peek, /* peek function */ + silverrock128_dump, /* device state information dump function */ + CARTRIDGE_SILVERROCK_128, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *silverrock128_list_item = NULL; @@ -279,7 +281,7 @@ void silverrock128_config_init(void) cart_romlbank_set_slotmain(0); } -void silverrock128_config_setup(BYTE *rawcart) +void silverrock128_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000 * 33); cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); @@ -296,7 +298,7 @@ static int silverrock128_common_attach(void) return 0; } -int silverrock128_bin_attach(const char *filename, BYTE *rawcart) +int silverrock128_bin_attach(const char *filename, uint8_t *rawcart) { int size = 0x42000; @@ -311,7 +313,7 @@ int silverrock128_bin_attach(const char *filename, BYTE *rawcart) return -1; } -int silverrock128_crt_attach(FILE *fd, BYTE *rawcart) +int silverrock128_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -350,7 +352,7 @@ void silverrock128_detach(void) ARRAY | ROML | 0.0+ | 262144 BYTES of ROML data */ -static char snap_module_name[] = "CARTSILVERROCK128"; +static const char snap_module_name[] = "CARTSILVERROCK128"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -366,7 +368,7 @@ int silverrock128_snapshot_write_module(snapshot_t *s) if (0 || SMW_B(m, regval) < 0 - || SMW_B(m, (BYTE)currbank) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 || SMW_BA(m, roml_banks, 0x2000 * 32) < 0) { snapshot_module_close(m); return -1; @@ -377,7 +379,7 @@ int silverrock128_snapshot_write_module(snapshot_t *s) int silverrock128_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -387,13 +389,13 @@ int silverrock128_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B(m, ®val) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/silverrock128.h b/src/Emulators/vice/c64/cart/silverrock128.h index 4f1c7072..bdbea810 100644 --- a/src/Emulators/vice/c64/cart/silverrock128.h +++ b/src/Emulators/vice/c64/cart/silverrock128.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void silverrock128_config_init(void); -extern void silverrock128_config_setup(BYTE *rawcart); -extern int silverrock128_bin_attach(const char *filename, BYTE *rawcart); -extern int silverrock128_crt_attach(FILE *fd, BYTE *rawcart); -extern void silverrock128_detach(void); +void silverrock128_config_init(void); +void silverrock128_config_setup(uint8_t *rawcart); +int silverrock128_bin_attach(const char *filename, uint8_t *rawcart); +int silverrock128_crt_attach(FILE *fd, uint8_t *rawcart); +void silverrock128_detach(void); struct snapshot_s; -extern int silverrock128_snapshot_write_module(struct snapshot_s *s); -extern int silverrock128_snapshot_read_module(struct snapshot_s *s); +int silverrock128_snapshot_write_module(struct snapshot_s *s); +int silverrock128_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/simonsbasic.c b/src/Emulators/vice/c64/cart/simonsbasic.c index 98fe1c07..57994c62 100644 --- a/src/Emulators/vice/c64/cart/simonsbasic.c +++ b/src/Emulators/vice/c64/cart/simonsbasic.c @@ -1,5 +1,5 @@ /* - * simonsbasic.c - Cartridge handling, Simons Basic cart. + * simonsbasic.c - Cartridge handling, Simons' Basic cart. * * Written by * Groepaz @@ -44,7 +44,7 @@ #include "crt.h" /* - Simon's Basic Cartridge + Simons' Basic Cartridge - 16kb ROM @@ -54,19 +54,19 @@ static int simon_a000 = 0; -static BYTE simon_io1_read(WORD addr) +static uint8_t simon_io1_read(uint16_t addr) { cart_config_changed_slotmain(0, 0, CMODE_READ); simon_a000 = 0; return 0; } -static BYTE simon_io1_peek(WORD addr) +static uint8_t simon_io1_peek(uint16_t addr) { return 0; } -static void simon_io1_store(WORD addr, BYTE value) +static void simon_io1_store(uint16_t addr, uint8_t value) { cart_config_changed_slotmain(1, 1, CMODE_WRITE); simon_a000 = 1; @@ -83,17 +83,20 @@ static int simon_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t simon_device = { - CARTRIDGE_NAME_SIMONS_BASIC, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - simon_io1_store, - simon_io1_read, - simon_io1_peek, - simon_dump, - CARTRIDGE_SIMONS_BASIC, - 0 + CARTRIDGE_NAME_SIMONS_BASIC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + simon_io1_store, /* store function */ + NULL, /* NO poke function */ + simon_io1_read, /* read function */ + simon_io1_peek, /* peek function */ + simon_dump, /* device state information dump function */ + CARTRIDGE_SIMONS_BASIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *simon_list_item = NULL; @@ -106,15 +109,15 @@ static const export_resource_t export_res_simon = { void simon_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); simon_a000 = 1; } -void simon_config_setup(BYTE *rawcart) +void simon_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); simon_a000 = 1; } @@ -127,7 +130,7 @@ static int simon_common_attach(void) return 0; } -int simon_bin_attach(const char *filename, BYTE *rawcart) +int simon_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -135,7 +138,7 @@ int simon_bin_attach(const char *filename, BYTE *rawcart) return simon_common_attach(); } -int simon_crt_attach(FILE *fd, BYTE *rawcart) +int simon_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -175,7 +178,7 @@ void simon_detach(void) ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTSIMON"; +static const char snap_module_name[] = "CARTSIMON"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -190,7 +193,7 @@ int simon_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)simon_a000) < 0 + || SMW_B(m, (uint8_t)simon_a000) < 0 || SMW_BA(m, roml_banks, 0x2000) < 0 || SMW_BA(m, romh_banks, 0x2000) < 0) { snapshot_module_close(m); @@ -202,7 +205,7 @@ int simon_snapshot_write_module(snapshot_t *s) int simon_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -212,13 +215,13 @@ int simon_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &simon_a000) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/simonsbasic.h b/src/Emulators/vice/c64/cart/simonsbasic.h index 79650165..7544c1b6 100644 --- a/src/Emulators/vice/c64/cart/simonsbasic.h +++ b/src/Emulators/vice/c64/cart/simonsbasic.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void simon_config_setup(BYTE *rawcart); -extern int simon_bin_attach(const char *filename, BYTE *rawcart); -extern int simon_crt_attach(FILE *fd, BYTE *rawcart); -extern void simon_detach(void); -extern void simon_config_init(void); +void simon_config_setup(uint8_t *rawcart); +int simon_bin_attach(const char *filename, uint8_t *rawcart); +int simon_crt_attach(FILE *fd, uint8_t *rawcart); +void simon_detach(void); +void simon_config_init(void); struct snapshot_s; -extern int simon_snapshot_write_module(struct snapshot_s *s); -extern int simon_snapshot_read_module(struct snapshot_s *s); +int simon_snapshot_write_module(struct snapshot_s *s); +int simon_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/snapshot64.c b/src/Emulators/vice/c64/cart/snapshot64.c index 9d50886d..b6a8006f 100644 --- a/src/Emulators/vice/c64/cart/snapshot64.c +++ b/src/Emulators/vice/c64/cart/snapshot64.c @@ -79,28 +79,30 @@ #define DBG(x) #endif -static BYTE romconfig = 0; +static uint8_t romconfig = 0; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE snapshot64_io2_read(WORD addr); -static BYTE snapshot64_io2_peek(WORD addr); -static void snapshot64_io2_store(WORD addr, BYTE value); +static uint8_t snapshot64_io2_read(uint16_t addr); +static uint8_t snapshot64_io2_peek(uint16_t addr); +static void snapshot64_io2_store(uint16_t addr, uint8_t value); static io_source_t ss64_io2_device = { - CARTRIDGE_NAME_SNAPSHOT64, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - snapshot64_io2_store, - snapshot64_io2_read, - snapshot64_io2_peek, - NULL, /* TODO: dump */ - CARTRIDGE_SNAPSHOT64, - 0, - 0 + CARTRIDGE_NAME_SNAPSHOT64, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + snapshot64_io2_store, /* store function */ + NULL, /* NO poke function */ + snapshot64_io2_read, /* read function */ + snapshot64_io2_peek, /* peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_SNAPSHOT64, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ss64_io2_list_item = NULL; @@ -115,24 +117,24 @@ static void enable_rom(int enable, int mode) { romconfig = enable; if (enable == 0) { - cart_config_changed_slotmain(2, 2, mode); + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, mode); } else { - cart_config_changed_slotmain(3, 3, mode); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, mode); } } -BYTE snapshot64_io2_read(WORD addr) +uint8_t snapshot64_io2_read(uint16_t addr) { /* DBG(("io2 rd %04x (%02x)\n", addr, romconfig)); */ return 0; } -BYTE snapshot64_io2_peek(WORD addr) +uint8_t snapshot64_io2_peek(uint16_t addr) { return romconfig; } -void snapshot64_io2_store(WORD addr, BYTE value) +void snapshot64_io2_store(uint16_t addr, uint8_t value) { /* DBG(("io2 wr %04x %02x\n", addr, value)); */ enable_rom(0, CMODE_WRITE); @@ -140,12 +142,12 @@ void snapshot64_io2_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ -BYTE snapshot64_roml_read(WORD addr) +uint8_t snapshot64_roml_read(uint16_t addr) { return roml_banks[addr & 0x0fff]; } -BYTE snapshot64_romh_read(WORD addr) +uint8_t snapshot64_romh_read(uint16_t addr) { return roml_banks[addr & 0x0fff]; } @@ -164,7 +166,7 @@ void snapshot64_config_init(void) enable_rom(0, CMODE_READ); } -void snapshot64_config_setup(BYTE *rawcart) +void snapshot64_config_setup(uint8_t *rawcart) { DBG(("SNAPSHOT64: config setup\n")); memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x1000); @@ -183,7 +185,7 @@ static int snapshot64_common_attach(void) return 0; } -int snapshot64_bin_attach(const char *filename, BYTE *rawcart) +int snapshot64_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x1000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -191,7 +193,7 @@ int snapshot64_bin_attach(const char *filename, BYTE *rawcart) return snapshot64_common_attach(); } -int snapshot64_crt_attach(FILE *fd, BYTE *rawcart) +int snapshot64_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -227,7 +229,7 @@ void snapshot64_detach(void) ARRAY | ROML | 4096 BYTES of ROML data */ -static char snap_module_name[] = "CARTSNAP64"; +static const char snap_module_name[] = "CARTSNAP64"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -253,7 +255,7 @@ int snapshot64_snapshot_write_module(snapshot_t *s) int snapshot64_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -263,7 +265,7 @@ int snapshot64_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/snapshot64.h b/src/Emulators/vice/c64/cart/snapshot64.h index e34a709a..5d7518ca 100644 --- a/src/Emulators/vice/c64/cart/snapshot64.h +++ b/src/Emulators/vice/c64/cart/snapshot64.h @@ -29,21 +29,21 @@ #include "vicetypes.h" -extern BYTE snapshot64_roml_read(WORD addr); -extern BYTE snapshot64_romh_read(WORD addr); +uint8_t snapshot64_roml_read(uint16_t addr); +uint8_t snapshot64_romh_read(uint16_t addr); -extern void snapshot64_freeze(void); +void snapshot64_freeze(void); -extern void snapshot64_config_init(void); -extern void snapshot64_config_setup(BYTE *rawcart); -extern int snapshot64_bin_attach(const char *filename, BYTE *rawcart); -extern int snapshot64_crt_attach(FILE *f, BYTE *rawcart); +void snapshot64_config_init(void); +void snapshot64_config_setup(uint8_t *rawcart); +int snapshot64_bin_attach(const char *filename, uint8_t *rawcart); +int snapshot64_crt_attach(FILE *f, uint8_t *rawcart); -extern void snapshot64_detach(void); +void snapshot64_detach(void); struct snapshot_s; -extern int snapshot64_snapshot_write_module(struct snapshot_s *s); -extern int snapshot64_snapshot_read_module(struct snapshot_s *s); +int snapshot64_snapshot_write_module(struct snapshot_s *s); +int snapshot64_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/stardos.c b/src/Emulators/vice/c64/cart/stardos.c index 2ca98649..1346480c 100644 --- a/src/Emulators/vice/c64/cart/stardos.c +++ b/src/Emulators/vice/c64/cart/stardos.c @@ -61,6 +61,8 @@ the second rom bank contains a kernal replacement. the necessary select signal comes from a clip that has to be installed inside of the c64. + + the original EPROM has D1 and D2 swapped around. */ /* #define DBGSTARDOS */ @@ -175,29 +177,29 @@ static void cap_discharge(void) cap_trigger_access(); } -static BYTE stardos_io1_read(WORD addr) +static uint8_t stardos_io1_read(uint16_t addr) { cap_charge(); return 0; } -static void stardos_io1_store(WORD addr, BYTE value) +static void stardos_io1_store(uint16_t addr, uint8_t value) { cap_charge(); } -static BYTE stardos_io_peek(WORD addr) +static uint8_t stardos_io_peek(uint16_t addr) { return roml_enable; } -static BYTE stardos_io2_read(WORD addr) +static uint8_t stardos_io2_read(uint16_t addr) { cap_discharge(); return 0; } -static void stardos_io2_store(WORD addr, BYTE value) +static void stardos_io2_store(uint16_t addr, uint8_t value) { cap_discharge(); } @@ -212,35 +214,37 @@ static int stardos_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t stardos_io1_device = { - CARTRIDGE_NAME_STARDOS, - IO_DETACH_CART, - NULL, -/* 0xde61, 0xde61, 0x01, */ - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - stardos_io1_store, - stardos_io1_read, - stardos_io_peek, - stardos_dump, - CARTRIDGE_STARDOS, - 0, - 0 + CARTRIDGE_NAME_STARDOS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid */ + stardos_io1_store, /* store function */ + NULL, /* NO poke function */ + stardos_io1_read, /* read function */ + stardos_io_peek, /* peek function */ + stardos_dump, /* device state information dump function */ + CARTRIDGE_STARDOS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t stardos_io2_device = { - CARTRIDGE_NAME_STARDOS, - IO_DETACH_CART, - NULL, -/* 0xdfa1, 0xdfa1, 0x01, */ - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - stardos_io2_store, - stardos_io2_read, - stardos_io_peek, - stardos_dump, - CARTRIDGE_STARDOS, - 0, - 0 + CARTRIDGE_NAME_STARDOS, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + stardos_io2_store, /* store function */ + NULL, /* NO poke function */ + stardos_io2_read, /* read function */ + stardos_io_peek, /* peek function */ + stardos_dump, /* device state information dump function */ + CARTRIDGE_STARDOS, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *stardos_io1_list_item = NULL; @@ -252,7 +256,7 @@ static const export_resource_t export_res = { /* ---------------------------------------------------------------------*/ -BYTE stardos_roml_read(WORD addr) +uint8_t stardos_roml_read(uint16_t addr) { if (roml_enable) { if ((pport.data & 1) == 1) { @@ -262,7 +266,7 @@ BYTE stardos_roml_read(WORD addr) return mem_read_without_ultimax(addr); } -BYTE stardos_romh_read(WORD addr) +uint8_t stardos_romh_read(uint16_t addr) { if ((pport.data & 2) == 2) { return romh_banks[(addr & 0x1fff)]; @@ -270,17 +274,17 @@ BYTE stardos_romh_read(WORD addr) return mem_read_without_ultimax(addr); } -int stardos_romh_phi1_read(WORD addr, BYTE *value) +int stardos_romh_phi1_read(uint16_t addr, uint8_t *value) { return CART_READ_C64MEM; } -int stardos_romh_phi2_read(WORD addr, BYTE *value) +int stardos_romh_phi2_read(uint16_t addr, uint8_t *value) { return stardos_romh_phi1_read(addr, value); } -int stardos_peek_mem(export_t *export, WORD addr, BYTE *value) +int stardos_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (roml_enable) { if (addr >= 0x8000 && addr <= 0x9fff) { @@ -299,7 +303,7 @@ void stardos_config_init(void) { flipflop(); cap_trigger_access(); - cart_config_changed_slotmain(2, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -313,12 +317,12 @@ void stardos_reset(void) } #endif -void stardos_config_setup(BYTE *rawcart) +void stardos_config_setup(uint8_t *rawcart) { memcpy(roml_banks, &rawcart[0], 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(2, 3, CMODE_READ); + cart_config_changed_slotmain(CMODE_RAM, CMODE_ULTIMAX, CMODE_READ); } /* ---------------------------------------------------------------------*/ @@ -338,7 +342,7 @@ static int stardos_common_attach(void) return 0; } -int stardos_bin_attach(const char *filename, BYTE *rawcart) +int stardos_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -347,7 +351,7 @@ int stardos_bin_attach(const char *filename, BYTE *rawcart) return stardos_common_attach(); } -int stardos_crt_attach(FILE *fd, BYTE *rawcart) +int stardos_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -396,9 +400,9 @@ int stardos_snapshot_write_module(snapshot_t *s) } if (0 - || (SMW_DW(m, stardos_alarm_time) < 0) - || (SMW_DW(m, (DWORD)cap_voltage) < 0) - || (SMW_B(m, (BYTE)roml_enable) < 0) + || (SMW_CLOCK(m, stardos_alarm_time) < 0) + || (SMW_DW(m, (uint32_t)cap_voltage) < 0) + || (SMW_B(m, (uint8_t)roml_enable) < 0) || (SMW_BA(m, roml_banks, 0x2000) < 0) || (SMW_BA(m, romh_banks, 0x2000) < 0)) { snapshot_module_close(m); @@ -411,7 +415,7 @@ int stardos_snapshot_write_module(snapshot_t *s) int stardos_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; CLOCK temp_clk; @@ -426,7 +430,7 @@ int stardos_snapshot_read_module(snapshot_t *s) } if (0 - || (SMR_DW(m, &temp_clk) < 0) + || (SMR_CLOCK(m, &temp_clk) < 0) || (SMR_DW_INT(m, &cap_voltage) < 0) || (SMR_B_INT(m, &roml_enable) < 0) || (SMR_BA(m, roml_banks, 0x2000) < 0) diff --git a/src/Emulators/vice/c64/cart/stardos.h b/src/Emulators/vice/c64/cart/stardos.h index 37ebe28b..e531db2d 100644 --- a/src/Emulators/vice/c64/cart/stardos.h +++ b/src/Emulators/vice/c64/cart/stardos.h @@ -33,20 +33,20 @@ struct snapshot_s; -extern BYTE stardos_roml_read(WORD addr); -extern BYTE stardos_romh_read(WORD addr); -extern int stardos_romh_phi1_read(WORD addr, BYTE *value); -extern int stardos_romh_phi2_read(WORD addr, BYTE *value); -extern int stardos_peek_mem(export_t *export, WORD addr, BYTE *value); - -extern void stardos_config_init(void); -extern void stardos_reset(void); -extern void stardos_config_setup(BYTE *rawcart); -extern int stardos_bin_attach(const char *filename, BYTE *rawcart); -extern int stardos_crt_attach(FILE *fd, BYTE *rawcart); -extern void stardos_detach(void); - -extern int stardos_snapshot_write_module(struct snapshot_s *s); -extern int stardos_snapshot_read_module(struct snapshot_s *s); +uint8_t stardos_roml_read(uint16_t addr); +uint8_t stardos_romh_read(uint16_t addr); +int stardos_romh_phi1_read(uint16_t addr, uint8_t *value); +int stardos_romh_phi2_read(uint16_t addr, uint8_t *value); +int stardos_peek_mem(export_t *export, uint16_t addr, uint8_t *value); + +void stardos_config_init(void); +void stardos_reset(void); +void stardos_config_setup(uint8_t *rawcart); +int stardos_bin_attach(const char *filename, uint8_t *rawcart); +int stardos_crt_attach(FILE *fd, uint8_t *rawcart); +void stardos_detach(void); + +int stardos_snapshot_write_module(struct snapshot_s *s); +int stardos_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/stb.c b/src/Emulators/vice/c64/cart/stb.c index 022f713a..e8a5e6e2 100644 --- a/src/Emulators/vice/c64/cart/stb.c +++ b/src/Emulators/vice/c64/cart/stb.c @@ -52,24 +52,26 @@ /* ---------------------------------------------------------------------*/ -static BYTE stb_io1_read(WORD addr); -static BYTE stb_io1_peek(WORD addr); -static void stb_io1_store(WORD addr, BYTE value); +static uint8_t stb_io1_read(uint16_t addr); +static uint8_t stb_io1_peek(uint16_t addr); +static void stb_io1_store(uint16_t addr, uint8_t value); static int stb_dump(void); static io_source_t stb_device = { - CARTRIDGE_NAME_STRUCTURED_BASIC, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, /* read is never valid */ - stb_io1_store, - stb_io1_read, - stb_io1_peek, - stb_dump, - CARTRIDGE_STRUCTURED_BASIC, - 0, - 0 + CARTRIDGE_NAME_STRUCTURED_BASIC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x03, /* range for the device, regs:$de00-$de03, mirrors:$de04-$deff */ + 0, /* read is never valid, regs are write only */ + stb_io1_store, /* store function */ + NULL, /* NO poke function */ + stb_io1_read, /* read function */ + stb_io1_peek, /* peek function */ + stb_dump, /* device state information dump function */ + CARTRIDGE_STRUCTURED_BASIC, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *stb_list_item = NULL; @@ -83,7 +85,7 @@ static const export_resource_t export_res = { static int stb_bank = 0; static int stb_active = 0; -static void stb_io(WORD addr) +static void stb_io(uint16_t addr) { switch (addr & 3) { /* normal config: bank 0 visible */ @@ -110,18 +112,18 @@ static void stb_io(WORD addr) } } -static BYTE stb_io1_read(WORD addr) +static uint8_t stb_io1_read(uint16_t addr) { stb_io(addr); return 0; } -static BYTE stb_io1_peek(WORD addr) +static uint8_t stb_io1_peek(uint16_t addr) { return 0; } -static void stb_io1_store(WORD addr, BYTE value) +static void stb_io1_store(uint16_t addr, uint8_t value) { stb_io(addr); } @@ -140,18 +142,18 @@ static int stb_dump(void) void stb_config_init(void) { /* turn on normal config: bank 0 */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); stb_bank = 0; stb_active = 1; } -void stb_config_setup(BYTE *rawcart) +void stb_config_setup(uint8_t *rawcart) { /* copy banks 0 and 1 */ memcpy(roml_banks, rawcart, 0x4000); /* turn on normal config: bank 0 */ - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); stb_bank = 0; stb_active = 1; } @@ -170,7 +172,7 @@ static int stb_common_attach(void) return 0; } -int stb_bin_attach(const char *filename, BYTE *rawcart) +int stb_bin_attach(const char *filename, uint8_t *rawcart) { /* load file into cartridge address space */ if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_RAW) < 0) { @@ -180,7 +182,7 @@ int stb_bin_attach(const char *filename, BYTE *rawcart) return stb_common_attach(); } -int stb_crt_attach(FILE *fd, BYTE *rawcart) +int stb_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -219,7 +221,7 @@ void stb_detach(void) ARRAY | ROML | 0.0+ | 16384 BYTES of ROML data */ -static char snap_module_name[] = "CARTSTB"; +static const char snap_module_name[] = "CARTSTB"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -234,8 +236,8 @@ int stb_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)stb_bank) < 0 - || SMW_B(m, (BYTE)stb_active) < 0 + || SMW_B(m, (uint8_t)stb_bank) < 0 + || SMW_B(m, (uint8_t)stb_active) < 0 || SMW_BA(m, roml_banks, 0x4000) < 0) { snapshot_module_close(m); return -1; @@ -246,7 +248,7 @@ int stb_snapshot_write_module(snapshot_t *s) int stb_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -256,13 +258,13 @@ int stb_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (0 || SMR_B_INT(m, &stb_bank) < 0 || SMR_B_INT(m, &stb_active) < 0) { diff --git a/src/Emulators/vice/c64/cart/stb.h b/src/Emulators/vice/c64/cart/stb.h index b1efe487..8f0a7d05 100644 --- a/src/Emulators/vice/c64/cart/stb.h +++ b/src/Emulators/vice/c64/cart/stb.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void stb_config_init(void); -extern void stb_config_setup(BYTE *rawcart); -extern int stb_bin_attach(const char *filename, BYTE *rawcart); -extern int stb_crt_attach(FILE *fd, BYTE *rawcart); -extern void stb_detach(void); +void stb_config_init(void); +void stb_config_setup(uint8_t *rawcart); +int stb_bin_attach(const char *filename, uint8_t *rawcart); +int stb_crt_attach(FILE *fd, uint8_t *rawcart); +void stb_detach(void); struct snapshot_s; -extern int stb_snapshot_write_module(struct snapshot_s *s); -extern int stb_snapshot_read_module(struct snapshot_s *s); +int stb_snapshot_write_module(struct snapshot_s *s); +int stb_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/superexplode5.c b/src/Emulators/vice/c64/cart/superexplode5.c index 7851d4d7..e5f80a70 100644 --- a/src/Emulators/vice/c64/cart/superexplode5.c +++ b/src/Emulators/vice/c64/cart/superexplode5.c @@ -30,6 +30,7 @@ #include #include +#include "alarm.h" #define CARTRIDGE_INCLUDE_SLOTMAIN_API #include "c64cartsystem.h" #undef CARTRIDGE_INCLUDE_SLOTMAIN_API @@ -37,11 +38,13 @@ #include "cartio.h" #include "cartridge.h" #include "export.h" +#include "maincpu.h" #include "monitor.h" #include "snapshot.h" #include "superexplode5.h" #include "vicetypes.h" #include "util.h" +#include "vicii-phi1.h" #include "crt.h" /* @@ -59,6 +62,11 @@ controlregister is $df00: bit 7 selects bank + the ROM at $8000 is enabled / disabled the following way: + - if either IO1, ROMLO or RESET are active (=0), then EXROM becomes active (=0) + - if all of the above are inactive (=1) then a capacitor is being charged, + and EXROM becomes inactive (=1) after roughly 300ms + this is a very strange cartridge, almost no information about it seems to exist, from http://www.mayhem64.co.uk/cartpower.htm: @@ -89,6 +97,8 @@ */ /* #define SE5_DEBUG */ +/* #define SE5_DEBUG_RW */ +/* #define SE5_DEBUG_CHARGE */ #ifdef SE5_DEBUG #define DBG(x) printf x @@ -96,80 +106,212 @@ #define DBG(x) #endif +#ifdef SE5_DEBUG_RW +#define DBGRW(x) printf x +#else +#define DBGRW(x) +#endif + +#ifdef SE5_DEBUG_CHARGE +#define DBGCH(x) printf x +#else +#define DBGCH(x) +#endif + #define SE5_CART_SIZE (2 * 0x2000) /* ---------------------------------------------------------------------*/ static int se5_bank = 0; +static int se5_rom_enabled = 0; + +static int se5_cap_charge = 0; + +struct alarm_s *se5_alarm; +static CLOCK se5_alarm_time; +static CLOCK se5_charge_time; + +#define CHARGEMAX (90 * 3) /* ~ 300ms */ +#define DECHARGESTEPS 3 /* should discharge in ~90 steps */ +#define LOWTHRESHOLD 5 +#define HIGHTHRESHOLD (CHARGEMAX - 5) + +static void flipflop(void) +{ +#ifdef SE5_DEBUG + int old = se5_rom_enabled; +#endif + int mode; + if (se5_cap_charge < LOWTHRESHOLD) { + se5_rom_enabled = 1; + } + if (se5_cap_charge > HIGHTHRESHOLD) { + se5_rom_enabled = 0; + } + mode = se5_rom_enabled ? CMODE_8KGAME : CMODE_RAM; + mode |= se5_bank << CMODE_BANK_SHIFT; + cart_config_changed_slotmain(mode, mode, CMODE_READ); +#ifdef SE5_DEBUG + if (old != se5_rom_enabled) { + DBG(("%08lx SE5: flipflop (rom:%d charge:%d)\n", maincpu_clk, se5_rom_enabled, se5_cap_charge)); + } +#endif +} + +static void cap_trigger_access(void) +{ + alarm_unset(se5_alarm); + se5_alarm_time = CLOCK_MAX; + + if (se5_cap_charge < CHARGEMAX) { + se5_alarm_time = maincpu_clk + 1; + alarm_set(se5_alarm, se5_alarm_time); + } + DBGCH(("%08lx SE5: is fully charged (idle) (rom:%d charge:%d)\n", maincpu_clk, se5_rom_enabled, se5_cap_charge)); +} + +static void se5_alarm_handler(CLOCK offset, void *data) +{ + if (maincpu_clk >= se5_charge_time) { + se5_cap_charge++; + if (se5_cap_charge > CHARGEMAX) { + se5_cap_charge = CHARGEMAX; + } + } + DBGCH(("%08lx SE5: charge idle (rom:%d charge:%d)\n", maincpu_clk, se5_rom_enabled, se5_cap_charge)); + flipflop(); + cap_trigger_access(); +} + +static void cap_discharge(void) +{ + se5_cap_charge -= DECHARGESTEPS; + if (se5_cap_charge < 0) { + se5_cap_charge = 0; + } + DBGCH(("%08lx SE5: discharge (rom:%d charge:%d)\n", maincpu_clk , se5_rom_enabled, se5_cap_charge)); + /* put first alarm a few cycles ahead, so we dont have to fiddle with alternating + charge/discharge while the discharge loop is executed */ + se5_charge_time = maincpu_clk + 10; + flipflop(); + cap_trigger_access(); +} + +/* ---------------------------------------------------------------------*/ + +static void se5_io1_store(uint16_t addr, uint8_t value) +{ + DBGRW(("%08lx io1 wr %04x %02x %d\n",maincpu_clk ,addr, value, se5_cap_charge)); + cap_discharge(); +} + +static uint8_t se5_io1_read(uint16_t addr) +{ + DBGRW(("%08lx io1 rd %04x %d\n",maincpu_clk, addr, se5_cap_charge)); + cap_discharge(); + return vicii_read_phi1(); +} -static void se5_io2_store(WORD addr, BYTE value) +static uint8_t se5_io1_peek(uint16_t addr) { - DBG(("io2 wr %04x %02x\n", addr, value)); + DBGRW(("io1 rd %04x\n", addr)); + return 0; +} + +static void se5_io2_store(uint16_t addr, uint8_t value) +{ + DBGRW(("io2 wr %04x %02x\n", addr, value)); se5_bank = (value & 0x80) ? 1 : 0; - cart_romlbank_set_slotmain(se5_bank); + flipflop(); } -static BYTE se5_io2_read(WORD addr) +static uint8_t se5_io2_read(uint16_t addr) { addr |= 0xdf00; - return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; + return roml_banks[(addr & 0x1fff) + (se5_bank << 13)]; } static int se5_dump(void) { mon_out("Bank: %d\n", se5_bank); + mon_out("ROM is %s\n", se5_rom_enabled ? "enabled" : "disabled"); return 0; } /* ---------------------------------------------------------------------*/ +static io_source_t se5_io1_device = { + CARTRIDGE_NAME_SUPER_EXPLODE_V5, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x01, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + se5_io1_store, /* store function */ + NULL, /* NO poke function */ + se5_io1_read, /* read function */ + se5_io1_peek, /* NO peek function */ + se5_dump, /* device state information dump function */ + CARTRIDGE_SUPER_EXPLODE_V5, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + static io_source_t se5_io2_device = { - CARTRIDGE_NAME_SUPER_EXPLODE_V5, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is alway valid */ - se5_io2_store, - se5_io2_read, - NULL, - se5_dump, - CARTRIDGE_SUPER_EXPLODE_V5, - 0, - 0 + CARTRIDGE_NAME_SUPER_EXPLODE_V5, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + se5_io2_store, /* store function */ + NULL, /* NO poke function */ + se5_io2_read, /* read function */ + NULL, /* NO peek function */ + se5_dump, /* device state information dump function */ + CARTRIDGE_SUPER_EXPLODE_V5, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; +static io_source_list_t *se5_io1_list_item = NULL; static io_source_list_t *se5_io2_list_item = NULL; static const export_resource_t export_res = { - CARTRIDGE_NAME_SUPER_EXPLODE_V5, 0, 1, NULL, &se5_io2_device, CARTRIDGE_SUPER_EXPLODE_V5 + CARTRIDGE_NAME_SUPER_EXPLODE_V5, 1, 1, &se5_io1_device, &se5_io2_device, CARTRIDGE_SUPER_EXPLODE_V5 }; /* ---------------------------------------------------------------------*/ -BYTE se5_roml_read(WORD addr) +uint8_t se5_roml_read(uint16_t addr) { - if (addr < 0x9f00) { - return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; - } else { - return ram_read(addr); - /* return mem_read_without_ultimax(addr); */ - } + DBGRW(("%08lx se5_roml_read %04x %d\n", maincpu_clk, addr, se5_cap_charge)); + cap_discharge(); + return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } /* ---------------------------------------------------------------------*/ +void se5_reset(void) +{ + se5_cap_charge = 0; + se5_charge_time = maincpu_clk + 10; + flipflop(); + cap_trigger_access(); +} + void se5_config_init(void) { - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); se5_bank = 0; } -void se5_config_setup(BYTE *rawcart) +void se5_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, SE5_CART_SIZE); - cart_config_changed_slotmain(0, 0, CMODE_READ); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); cart_romlbank_set_slotmain(0); se5_bank = 0; } @@ -182,12 +324,16 @@ static int se5_common_attach(void) return -1; } + se5_io1_list_item = io_source_register(&se5_io1_device); se5_io2_list_item = io_source_register(&se5_io2_device); + se5_alarm = alarm_new(maincpu_alarm_context, "SE5RomAlarm", se5_alarm_handler, NULL); + se5_alarm_time = CLOCK_MAX; + return 0; } -int se5_bin_attach(const char *filename, BYTE *rawcart) +int se5_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, SE5_CART_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -196,10 +342,10 @@ int se5_bin_attach(const char *filename, BYTE *rawcart) return se5_common_attach(); } -int se5_crt_attach(FILE *fd, BYTE *rawcart) +int se5_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; - int i, cnt = 0; + int i; for (i = 0; i <= 0x01; i++) { if (crt_read_chip_header(&chip, fd)) { @@ -213,7 +359,6 @@ int se5_crt_attach(FILE *fd, BYTE *rawcart) if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { return -1; } - cnt++; } return se5_common_attach(); @@ -221,7 +366,10 @@ int se5_crt_attach(FILE *fd, BYTE *rawcart) void se5_detach(void) { + alarm_destroy(se5_alarm); export_remove(&export_res); + io_source_unregister(se5_io1_list_item); + se5_io1_list_item = NULL; io_source_unregister(se5_io2_list_item); se5_io2_list_item = NULL; } @@ -236,7 +384,7 @@ void se5_detach(void) ARRAY | ROML | 0.0+ | 16384 BYTES of ROML data */ -static char snap_module_name[] = "CARTSE5"; +static const char snap_module_name[] = "CARTSE5"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -251,7 +399,7 @@ int se5_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)se5_bank) < 0 + || SMW_B(m, (uint8_t)se5_bank) < 0 || SMW_BA(m, roml_banks, SE5_CART_SIZE) < 0) { snapshot_module_close(m); return -1; @@ -262,7 +410,7 @@ int se5_snapshot_write_module(snapshot_t *s) int se5_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -272,13 +420,13 @@ int se5_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &se5_bank) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/superexplode5.h b/src/Emulators/vice/c64/cart/superexplode5.h index 78ecd049..1e49b226 100644 --- a/src/Emulators/vice/c64/cart/superexplode5.h +++ b/src/Emulators/vice/c64/cart/superexplode5.h @@ -31,16 +31,17 @@ #include "vicetypes.h" -extern void se5_config_init(void); -extern void se5_config_setup(BYTE *rawcart); -extern int se5_bin_attach(const char *filename, BYTE *rawcart); -extern int se5_crt_attach(FILE *fd, BYTE *rawcart); -extern void se5_detach(void); -extern BYTE se5_roml_read(WORD addr); +void se5_config_init(void); +void se5_config_setup(uint8_t *rawcart); +int se5_bin_attach(const char *filename, uint8_t *rawcart); +int se5_crt_attach(FILE *fd, uint8_t *rawcart); +void se5_detach(void); +uint8_t se5_roml_read(uint16_t addr); +void se5_reset(void); struct snapshot_s; -extern int se5_snapshot_write_module(struct snapshot_s *s); -extern int se5_snapshot_read_module(struct snapshot_s *s); +int se5_snapshot_write_module(struct snapshot_s *s); +int se5_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/supergames.c b/src/Emulators/vice/c64/cart/supergames.c index 50535c5c..2e241c30 100644 --- a/src/Emulators/vice/c64/cart/supergames.c +++ b/src/Emulators/vice/c64/cart/supergames.c @@ -66,9 +66,9 @@ static int currbank = 0; static int currmode = 0; static int reglatched = 0; -static BYTE regval = 0; +static uint8_t regval = 0; -static void supergames_io2_store(WORD addr, BYTE value) +static void supergames_io2_store(uint16_t addr, uint8_t value) { if (reglatched == 0) { regval = value; @@ -87,7 +87,7 @@ static void supergames_io2_store(WORD addr, BYTE value) } } -static BYTE supergames_io2_peek(WORD addr) +static uint8_t supergames_io2_peek(uint16_t addr) { return regval; } @@ -102,18 +102,20 @@ static int supergames_dump(void) /* ---------------------------------------------------------------------*/ static io_source_t supergames_device = { - CARTRIDGE_NAME_SUPER_GAMES, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - supergames_io2_store, - NULL, - supergames_io2_peek, - supergames_dump, - CARTRIDGE_SUPER_GAMES, - 0, - 0 + CARTRIDGE_NAME_SUPER_GAMES, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid, reg is write only */ + supergames_io2_store, /* store function */ + NULL, /* NO poke function */ + NULL, /* NO read function */ + supergames_io2_peek, /* peek function */ + supergames_dump, /* device state information dump function */ + CARTRIDGE_SUPER_GAMES, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *supergames_list_item = NULL; @@ -131,7 +133,7 @@ void supergames_config_init(void) supergames_io2_store(0xdf00, 0); } -void supergames_config_setup(BYTE *rawcart) +void supergames_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); @@ -156,7 +158,7 @@ static int supergames_common_attach(void) return 0; } -int supergames_bin_attach(const char *filename, BYTE *rawcart) +int supergames_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -164,7 +166,7 @@ int supergames_bin_attach(const char *filename, BYTE *rawcart) return supergames_common_attach(); } -int supergames_crt_attach(FILE *fd, BYTE *rawcart) +int supergames_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -199,13 +201,13 @@ void supergames_detach(void) ------------------------------------------- BYTE | mode | 0.2 | current mode BYTE | regval | 0.2 | register - BYTE | bank | 0.0+ | current bank + BYTE | bank | 0.0+ | current bank BYTE | reg latched | 0.1 | register latched flag ARRAY | ROML | 0.0+ | 32768 BYTES of ROML data ARRAY | ROMH | 0.0+ | 32768 BYTES of ROMH data */ -static char snap_module_name[] = "CARTSUPERGAMES"; +static const char snap_module_name[] = "CARTSUPERGAMES"; #define SNAP_MAJOR 0 #define SNAP_MINOR 2 @@ -220,10 +222,10 @@ int supergames_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)currmode) < 0 + || SMW_B(m, (uint8_t)currmode) < 0 || SMW_B(m, regval) < 0 - || SMW_B(m, (BYTE)currbank) < 0 - || SMW_B(m, (BYTE)reglatched) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 + || SMW_B(m, (uint8_t)reglatched) < 0 || SMW_BA(m, roml_banks, 0x8000) < 0 || SMW_BA(m, romh_banks, 0x8000) < 0) { snapshot_module_close(m); @@ -235,7 +237,7 @@ int supergames_snapshot_write_module(snapshot_t *s) int supergames_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -245,13 +247,13 @@ int supergames_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.2 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (0 || SMR_B_INT(m, &currmode) < 0 || SMR_B(m, ®val) < 0) { @@ -267,7 +269,7 @@ int supergames_snapshot_read_module(snapshot_t *s) } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (SMR_B_INT(m, ®latched) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/supergames.h b/src/Emulators/vice/c64/cart/supergames.h index 8200dfd9..b6ce95e2 100644 --- a/src/Emulators/vice/c64/cart/supergames.h +++ b/src/Emulators/vice/c64/cart/supergames.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void supergames_config_init(void); -extern void supergames_config_setup(BYTE *rawcart); -extern int supergames_bin_attach(const char *filename, BYTE *rawcart); -extern int supergames_crt_attach(FILE *fd, BYTE *rawcart); -extern void supergames_detach(void); +void supergames_config_init(void); +void supergames_config_setup(uint8_t *rawcart); +int supergames_bin_attach(const char *filename, uint8_t *rawcart); +int supergames_crt_attach(FILE *fd, uint8_t *rawcart); +void supergames_detach(void); struct snapshot_s; -extern int supergames_snapshot_write_module(struct snapshot_s *s); -extern int supergames_snapshot_read_module(struct snapshot_s *s); +int supergames_snapshot_write_module(struct snapshot_s *s); +int supergames_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/supersnapshot.c b/src/Emulators/vice/c64/cart/supersnapshot.c index a6746e4a..39376df2 100644 --- a/src/Emulators/vice/c64/cart/supersnapshot.c +++ b/src/Emulators/vice/c64/cart/supersnapshot.c @@ -39,10 +39,10 @@ #include "cmdline.h" #include "export.h" #include "monitor.h" +#include "ram.h" #include "resources.h" #include "snapshot.h" #include "supersnapshot.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" #include "crt.h" @@ -72,35 +72,40 @@ bit 0 GAME (0: low, 1: high) */ +#define CART_RAM_SIZE (32 * 1024) + /* Super Snapshot configuration flags. */ -static BYTE romconfig = 9; +static uint8_t romconfig = 9; static int ram_bank = 0; /* Version 5 supports 4 - 8Kb RAM banks. */ static int currbank = 0; static int currreg = 0; static int ss_32k_enabled = 0; static int ss_rom_disabled = 0; +static int ss_rom_banks = 4; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE supersnapshot_v5_io1_read(WORD addr); -static BYTE supersnapshot_v5_io1_peek(WORD addr); -static void supersnapshot_v5_io1_store(WORD addr, BYTE value); +static uint8_t supersnapshot_v5_io1_read(uint16_t addr); +static uint8_t supersnapshot_v5_io1_peek(uint16_t addr); +static void supersnapshot_v5_io1_store(uint16_t addr, uint8_t value); static int supersnapshot_v5_dump(void); static io_source_t ss5_device = { - CARTRIDGE_NAME_SUPER_SNAPSHOT_V5, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 0, - supersnapshot_v5_io1_store, - supersnapshot_v5_io1_read, - supersnapshot_v5_io1_peek, - supersnapshot_v5_dump, - CARTRIDGE_SUPER_SNAPSHOT_V5, - 0, - 0 + CARTRIDGE_NAME_SUPER_SNAPSHOT_V5, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 0, /* read validity is determined by the device upon a read */ + supersnapshot_v5_io1_store, /* store function */ + NULL, /* NO poke function */ + supersnapshot_v5_io1_read, /* read function */ + supersnapshot_v5_io1_peek, /* peek function */ + supersnapshot_v5_dump, /* device state information dump function */ + CARTRIDGE_SUPER_SNAPSHOT_V5, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ss5_list_item = NULL; @@ -111,21 +116,12 @@ static const export_resource_t export_res_v5 = { /* ---------------------------------------------------------------------*/ -static BYTE supersnapshot_v5_io1_read(WORD addr) +static uint8_t supersnapshot_v5_io1_read(uint16_t addr) { ss5_device.io_source_valid = 1; if (!ss_rom_disabled) { - switch (roml_bank) { - case 0: - return roml_banks[0x1e00 + (addr & 0xff)]; - case 1: - return roml_banks[0x1e00 + (addr & 0xff) + 0x2000]; - case 2: - return roml_banks[0x1e00 + (addr & 0xff) + 0x4000]; - case 3: - return roml_banks[0x1e00 + (addr & 0xff) + 0x6000]; - } + return roml_banks[0x1e00 + (addr & 0xff) + (roml_bank << 13)]; } ss5_device.io_source_valid = 0; @@ -133,22 +129,12 @@ static BYTE supersnapshot_v5_io1_read(WORD addr) return 0; } -static BYTE supersnapshot_v5_io1_peek(WORD addr) +static uint8_t supersnapshot_v5_io1_peek(uint16_t addr) { - switch (roml_bank) { - case 0: - return roml_banks[0x1e00 + (addr & 0xff)]; - case 1: - return roml_banks[0x1e00 + (addr & 0xff) + 0x2000]; - case 2: - return roml_banks[0x1e00 + (addr & 0xff) + 0x4000]; - case 3: - return roml_banks[0x1e00 + (addr & 0xff) + 0x6000]; - } - return 0; + return roml_banks[0x1e00 + (addr & 0xff) + (roml_bank << 13)]; } -static void supersnapshot_v5_io1_store(WORD addr, BYTE value) +static void supersnapshot_v5_io1_store(uint16_t addr, uint8_t value) { if (!ss_rom_disabled) { int mode = CMODE_WRITE; @@ -161,8 +147,11 @@ static void supersnapshot_v5_io1_store(WORD addr, BYTE value) } romconfig = ((value & 1) ^ 1) | ((value & 2) ^ 2); - currbank = ((value >> 2) & 0x1) | (((value >> 4) & 0x1) << 1) /* | (((value >> 5) & 0x1) << 2)*/; + currbank = ((value >> 2) & 0x1) | (((value >> 4) & 0x1) << 1); ram_bank = ss_32k_enabled ? currbank : 0; /* Select RAM banknr. */ + if (ss_rom_banks == 8) { + currbank |= (((value >> 5) & 0x1) << 2); + } ss_rom_disabled = ((value >> 3) & 0x1); romconfig |= (currbank << CMODE_BANK_SHIFT); if (((value >> 1) & 1) == 0) { @@ -174,16 +163,16 @@ static void supersnapshot_v5_io1_store(WORD addr, BYTE value) static int supersnapshot_v5_dump(void) { - mon_out("Register: $%02x (%s)\n", currreg, (ss_rom_disabled) ? "disabled" : "enabled"); - mon_out(" EXROM: %d GAME: %d (%s)\n", ((romconfig >> 1) & 1), (romconfig & 1) ^ 1, cart_config_string((BYTE)(romconfig & 3))); - mon_out(" ROM %s, Bank: %d\n", (ss_rom_disabled) ? "disabled" : "enabled", currbank); - mon_out(" RAM %s, Bank: %d\n", (export_ram) ? "enabled" : "disabled", ram_bank); + mon_out("Register: $%02x (%s)\n", (unsigned int)currreg, (ss_rom_disabled) ? "disabled" : "enabled"); + mon_out(" EXROM: %d GAME: %d (%s)\n", ((romconfig >> 1) & 1), (romconfig & 1) ^ 1, cart_config_string((uint8_t)(romconfig & 3))); + mon_out(" ROM %s, Bank: %d of %d\n", (ss_rom_disabled) ? "disabled" : "enabled", currbank, ss_rom_banks); + mon_out(" RAM %s, Bank: %d of %d\n", (export_ram) ? "enabled" : "disabled", ram_bank, ss_32k_enabled ? 4 : 1); return 0; } /* ---------------------------------------------------------------------*/ -BYTE supersnapshot_v5_roml_read(WORD addr) +uint8_t supersnapshot_v5_roml_read(uint16_t addr) { if (export_ram) { return export_ram0[(addr & 0x1fff) + (ram_bank << 13)]; @@ -195,14 +184,14 @@ BYTE supersnapshot_v5_roml_read(WORD addr) return 0; /* FIXME: open bus? */ } -void supersnapshot_v5_roml_store(WORD addr, BYTE value) +void supersnapshot_v5_roml_store(uint16_t addr, uint8_t value) { if (export_ram) { export_ram0[(addr & 0x1fff) + (ram_bank << 13)] = value; } } -void supersnapshot_v5_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit) +void supersnapshot_v5_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) { switch (addr & 0xe000) { case 0x8000: @@ -224,6 +213,25 @@ void supersnapshot_v5_mmu_translate(unsigned int addr, BYTE **base, int *start, /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void supersnapshot_v5_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void supersnapshot_v5_freeze(void) { ss_rom_disabled = 0; /* enable the register */ @@ -233,20 +241,17 @@ void supersnapshot_v5_freeze(void) void supersnapshot_v5_config_init(void) { ss_rom_disabled = 0; /* enable the register */ - supersnapshot_v5_io1_store((WORD)0xde00, 2); + supersnapshot_v5_io1_store((uint16_t)0xde00, 0); /* start up in ultimax mode! */ } -void supersnapshot_v5_config_setup(BYTE *rawcart) +void supersnapshot_v5_config_setup(uint8_t *rawcart) { - memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); - memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); - memcpy(&roml_banks[0x2000], &rawcart[0x4000], 0x2000); - memcpy(&romh_banks[0x2000], &rawcart[0x6000], 0x2000); - memcpy(&roml_banks[0x4000], &rawcart[0x8000], 0x2000); - memcpy(&romh_banks[0x4000], &rawcart[0xa000], 0x2000); - memcpy(&roml_banks[0x6000], &rawcart[0xc000], 0x2000); - memcpy(&romh_banks[0x6000], &rawcart[0xe000], 0x2000); - supersnapshot_v5_io1_store((WORD)0xde00, 2); + int i; + for (i = 0; i < 8; i++) { + memcpy(&roml_banks[0x2000 * i], &rawcart[0x0000 + (0x4000 * i)], 0x2000); + memcpy(&romh_banks[0x2000 * i], &rawcart[0x2000 + (0x4000 * i)], 0x2000); + } + supersnapshot_v5_io1_store((uint16_t)0xde00, 2); } /* ---------------------------------------------------------------------*/ @@ -262,26 +267,31 @@ static int supersnapshot_v5_common_attach(void) return 0; } -int supersnapshot_v5_bin_attach(const char *filename, BYTE *rawcart) +int supersnapshot_v5_bin_attach(const char *filename, uint8_t *rawcart) { + ss_rom_banks = 4; if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - return -1; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + ss_rom_banks = 8; } return supersnapshot_v5_common_attach(); } -int supersnapshot_v5_crt_attach(FILE *fd, BYTE *rawcart) +int supersnapshot_v5_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; - for (i = 0; i < 4; i++) { + ss_rom_banks = 4; + for (i = 0; i < 8; i++) { if (crt_read_chip_header(&chip, fd)) { - return -1; + break; } - if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 3) { + if (chip.start != 0x8000 || chip.size != 0x4000 || chip.bank > 7) { return -1; } @@ -290,6 +300,11 @@ int supersnapshot_v5_crt_attach(FILE *fd, BYTE *rawcart) } } + if (!((i == 4) || (i == 8))) { + return -1; + } + ss_rom_banks = i; + return supersnapshot_v5_common_attach(); } @@ -330,16 +345,12 @@ void supersnapshot_v5_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-ssramexpansion", SET_RESOURCE, 0, + { "-ssramexpansion", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SSRamExpansion", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SS_RAM_EXPANSION, - NULL, NULL }, - { "+ssramexpansion", SET_RESOURCE, 0, + NULL, "Enable SS 32KiB RAM expansion" }, + { "+ssramexpansion", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "SSRamExpansion", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SS_RAM_EXPANSION, - NULL, NULL }, + NULL, "Disable SS 32KiB RAM expansion" }, CMDLINE_LIST_END }; @@ -359,18 +370,20 @@ int supersnapshot_v5_cmdline_options_init(void) BYTE | RAM bank | 0.0+ | current RAM bank BYTE | 32K enabled | 0.1+ | 32KB enabled flag BYTE | ROM disable | 0.1+ | ROM disable flag - ARRAY | ROML | 0.0+ | 32768 BYTES of ROML data - ARRAY | ROMH | 0.0+ | 32768 BYTES of ROMH data + BYTE | ROM banks | 0.3 | number of ROM banks (4 or 8) + ARRAY | ROML | 0.0+ | 0x8000 or 0x10000 BYTES of ROML data + ARRAY | ROMH | 0.0+ | 0x8000 or 0x10000 BYTES of ROMH data ARRAY | RAM | 0.0+ | 32768 BYTES of RAM data */ -static char snap_module_name[] = "CARTSS5"; +static const char snap_module_name[] = "CARTSS5"; #define SNAP_MAJOR 0 -#define SNAP_MINOR 2 +#define SNAP_MINOR 3 int supersnapshot_v5_snapshot_write_module(snapshot_t *s) { snapshot_module_t *m; + unsigned int rom_bank_size = ss_rom_banks * 0x2000; m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); @@ -379,14 +392,15 @@ int supersnapshot_v5_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)currbank) < 0 - || SMW_B(m, (BYTE)currreg) < 0 + || SMW_B(m, (uint8_t)currbank) < 0 + || SMW_B(m, (uint8_t)currreg) < 0 || SMW_B(m, romconfig) < 0 - || SMW_B(m, (BYTE)ram_bank) < 0 - || SMW_B(m, (BYTE)ss_32k_enabled) < 0 - || SMW_B(m, (BYTE)ss_rom_disabled) < 0 - || SMW_BA(m, roml_banks, 0x8000) < 0 - || SMW_BA(m, romh_banks, 0x8000) < 0 + || SMW_B(m, (uint8_t)ram_bank) < 0 + || SMW_B(m, (uint8_t)ss_32k_enabled) < 0 + || SMW_B(m, (uint8_t)ss_rom_disabled) < 0 + || SMW_B(m, (uint8_t)ss_rom_banks) < 0 + || SMW_BA(m, roml_banks, rom_bank_size) < 0 + || SMW_BA(m, romh_banks, rom_bank_size) < 0 || SMW_BA(m, export_ram0, 0x8000) < 0) { snapshot_module_close(m); return -1; @@ -397,8 +411,9 @@ int supersnapshot_v5_snapshot_write_module(snapshot_t *s) int supersnapshot_v5_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; + unsigned int rom_bank_size; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -407,13 +422,13 @@ int supersnapshot_v5_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.2 */ - if (SNAPVAL(vmajor, vminor, 0, 2)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 2)) { if (0 || SMR_B_INT(m, &currbank) < 0 || SMR_B_INT(m, &currreg) < 0) { @@ -431,7 +446,7 @@ int supersnapshot_v5_snapshot_read_module(snapshot_t *s) } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (0 || SMR_B_INT(m, &ss_32k_enabled) < 0 || SMR_B_INT(m, &ss_rom_disabled) < 0) { @@ -442,9 +457,21 @@ int supersnapshot_v5_snapshot_read_module(snapshot_t *s) ss_rom_disabled = 0; } + /* new in 0.3 */ + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 3)) { + if (0 + || SMR_B_INT(m, &ss_rom_banks) < 0) { + goto fail; + } + } else { + ss_rom_banks = 4; + } + + rom_bank_size = ss_rom_banks * 0x2000; + if (0 - || SMR_BA(m, roml_banks, 0x8000) < 0 - || SMR_BA(m, romh_banks, 0x8000) < 0 + || SMR_BA(m, roml_banks, rom_bank_size) < 0 + || SMR_BA(m, romh_banks, rom_bank_size) < 0 || SMR_BA(m, export_ram0, 0x8000) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/supersnapshot.h b/src/Emulators/vice/c64/cart/supersnapshot.h index a6711083..b967bf00 100644 --- a/src/Emulators/vice/c64/cart/supersnapshot.h +++ b/src/Emulators/vice/c64/cart/supersnapshot.h @@ -29,25 +29,26 @@ #include "vicetypes.h" -extern BYTE supersnapshot_v5_roml_read(WORD addr); -extern void supersnapshot_v5_roml_store(WORD addr, BYTE value); -extern void supersnapshot_v5_mmu_translate(unsigned int addr, BYTE **base, int *start, int *limit); +uint8_t supersnapshot_v5_roml_read(uint16_t addr); +void supersnapshot_v5_roml_store(uint16_t addr, uint8_t value); +void supersnapshot_v5_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); -extern void supersnapshot_v5_freeze(void); +void supersnapshot_v5_freeze(void); -extern void supersnapshot_v5_config_init(void); -extern void supersnapshot_v5_config_setup(BYTE *rawcart); -extern int supersnapshot_v5_bin_attach(const char *filename, BYTE *rawcart); -extern int supersnapshot_v5_crt_attach(FILE *fd, BYTE *rawcart); -extern void supersnapshot_v5_detach(void); +void supersnapshot_v5_config_init(void); +void supersnapshot_v5_config_setup(uint8_t *rawcart); +int supersnapshot_v5_bin_attach(const char *filename, uint8_t *rawcart); +int supersnapshot_v5_crt_attach(FILE *fd, uint8_t *rawcart); +void supersnapshot_v5_detach(void); +void supersnapshot_v5_powerup(void); -extern int supersnapshot_v5_resources_init(void); -extern void supersnapshot_v5_resources_shutdown(void); -extern int supersnapshot_v5_cmdline_options_init(void); +int supersnapshot_v5_resources_init(void); +void supersnapshot_v5_resources_shutdown(void); +int supersnapshot_v5_cmdline_options_init(void); struct snapshot_s; -extern int supersnapshot_v5_snapshot_write_module(struct snapshot_s *s); -extern int supersnapshot_v5_snapshot_read_module(struct snapshot_s *s); +int supersnapshot_v5_snapshot_write_module(struct snapshot_s *s); +int supersnapshot_v5_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/supersnapshot4.c b/src/Emulators/vice/c64/cart/supersnapshot4.c index cba438e5..4606b3fe 100644 --- a/src/Emulators/vice/c64/cart/supersnapshot4.c +++ b/src/Emulators/vice/c64/cart/supersnapshot4.c @@ -38,6 +38,7 @@ #include "cartridge.h" #include "export.h" #include "log.h" +#include "ram.h" #include "snapshot.h" #include "supersnapshot4.h" #include "vicetypes.h" @@ -94,45 +95,51 @@ #define DBG(x) #endif +#define CART_RAM_SIZE (8 * 1024) + /* Super Snapshot configuration flags. */ -static BYTE ramconfig = 0xff, romconfig = 9; +static uint8_t ramconfig = 0xff, romconfig = 9; /* ---------------------------------------------------------------------*/ /* some prototypes are needed */ -static BYTE supersnapshot_v4_io1_read(WORD addr); -static void supersnapshot_v4_io1_store(WORD addr, BYTE value); -static BYTE supersnapshot_v4_io2_read(WORD addr); -static void supersnapshot_v4_io2_store(WORD addr, BYTE value); +static uint8_t supersnapshot_v4_io1_read(uint16_t addr); +static void supersnapshot_v4_io1_store(uint16_t addr, uint8_t value); +static uint8_t supersnapshot_v4_io2_read(uint16_t addr); +static void supersnapshot_v4_io2_store(uint16_t addr, uint8_t value); static io_source_t ss4_io1_device = { - CARTRIDGE_NAME_SUPER_SNAPSHOT, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - supersnapshot_v4_io1_store, - supersnapshot_v4_io1_read, - NULL, - NULL, /* TODO: dump */ - CARTRIDGE_SUPER_SNAPSHOT, - 0, - 0 + CARTRIDGE_NAME_SUPER_SNAPSHOT, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + supersnapshot_v4_io1_store, /* store function */ + NULL, /* NO poke function */ + supersnapshot_v4_io1_read, /* read function */ + NULL, /* TODO: peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_SUPER_SNAPSHOT, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t ss4_io2_device = { - CARTRIDGE_NAME_SUPER_SNAPSHOT, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, - supersnapshot_v4_io2_store, - supersnapshot_v4_io2_read, - NULL, - NULL, /* TODO: dump */ - CARTRIDGE_SUPER_SNAPSHOT, - 0, - 0 + CARTRIDGE_NAME_SUPER_SNAPSHOT, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + supersnapshot_v4_io2_store, /* store function */ + NULL, /* NO poke function */ + supersnapshot_v4_io2_read, /* read function */ + NULL, /* TODO: peek function */ + NULL, /* TODO: device state information dump function */ + CARTRIDGE_SUPER_SNAPSHOT, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *ss4_io1_list_item = NULL; @@ -145,20 +152,18 @@ static const export_resource_t export_res_v4 = { /* ---------------------------------------------------------------------*/ -BYTE supersnapshot_v4_io1_read(WORD addr) +uint8_t supersnapshot_v4_io1_read(uint16_t addr) { return export_ram0[0x1e00 + (addr & 0xff)]; } -void supersnapshot_v4_io1_store(WORD addr, BYTE value) +void supersnapshot_v4_io1_store(uint16_t addr, uint8_t value) { export_ram0[0x1e00 + (addr & 0xff)] = value; } -BYTE supersnapshot_v4_io2_read(WORD addr) +uint8_t supersnapshot_v4_io2_read(uint16_t addr) { - ss4_io2_device.io_source_valid = 1; - if ((addr & 0xff) == 1) { return ramconfig; } @@ -167,7 +172,7 @@ BYTE supersnapshot_v4_io2_read(WORD addr) return roml_banks[(addr & 0x1fff) + (0x2000 * roml_bank)]; } -void supersnapshot_v4_io2_store(WORD addr, BYTE value) +void supersnapshot_v4_io2_store(uint16_t addr, uint8_t value) { DBG(("SS4: io2 w %04x %02x\n", addr, value)); @@ -177,7 +182,7 @@ void supersnapshot_v4_io2_store(WORD addr, BYTE value) #ifdef DBGSS4 if (value & ~(0x80 | 0x08 | 0x04 | 0x02 | 0x01)) { DBG(("poof!\n")); - exit(-1); + archdep_vice_exit(-1); } #endif mode |= ((ramconfig == 0) ? CMODE_EXPORT_RAM : 0); @@ -205,7 +210,7 @@ void supersnapshot_v4_io2_store(WORD addr, BYTE value) /* old code, remove this if the above seems to work ok */ #if 0 - romconfig = (BYTE)((value == 2) ? 1 : (1 | (1 << CMODE_BANK_SHIFT))); + romconfig = (uint8_t)((value == 2) ? 1 : (1 | (1 << CMODE_BANK_SHIFT))); mode = mode | ((ramconfig == 0) ? CMODE_EXPORT_RAM : 0); if ((value & 0x7f) == 0) { romconfig = 3; @@ -223,7 +228,7 @@ void supersnapshot_v4_io2_store(WORD addr, BYTE value) /* mode |= CMODE_PHI2_RAM; */ } #endif - cart_config_changed_slotmain((BYTE)(romconfig & 3), romconfig, mode); + cart_config_changed_slotmain((uint8_t)(romconfig & 3), romconfig, mode); } if ((addr & 0xff) == 1) { int mode = CMODE_WRITE; @@ -240,13 +245,13 @@ void supersnapshot_v4_io2_store(WORD addr, BYTE value) romconfig &= ~(1 << 1); /* exrom */ mode &= ~(CMODE_EXPORT_RAM); } - cart_config_changed_slotmain((BYTE)(romconfig & 3), romconfig, mode); + cart_config_changed_slotmain((uint8_t)(romconfig & 3), romconfig, mode); } } /* ---------------------------------------------------------------------*/ -BYTE supersnapshot_v4_roml_read(WORD addr) +uint8_t supersnapshot_v4_roml_read(uint16_t addr) { if (export_ram) { return export_ram0[addr & 0x1fff]; @@ -255,7 +260,7 @@ BYTE supersnapshot_v4_roml_read(WORD addr) return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } -void supersnapshot_v4_roml_store(WORD addr, BYTE value) +void supersnapshot_v4_roml_store(uint16_t addr, uint8_t value) { if (export_ram) { export_ram0[addr & 0x1fff] = value; @@ -264,17 +269,36 @@ void supersnapshot_v4_roml_store(WORD addr, BYTE value) /* ---------------------------------------------------------------------*/ +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + +void supersnapshot_v4_powerup(void) +{ + ram_init_with_pattern(export_ram0, CART_RAM_SIZE, &ramparam); +} + void supersnapshot_v4_freeze(void) { - cart_config_changed_slotmain(3, 3, CMODE_READ | CMODE_EXPORT_RAM); + cart_config_changed_slotmain(CMODE_ULTIMAX, CMODE_ULTIMAX, CMODE_READ | CMODE_EXPORT_RAM); } void supersnapshot_v4_config_init(void) { - cart_config_changed_slotmain(1 | (1 << CMODE_BANK_SHIFT), 1 | (1 << CMODE_BANK_SHIFT), CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME | (1 << CMODE_BANK_SHIFT), CMODE_16KGAME | (1 << CMODE_BANK_SHIFT), CMODE_READ); } -void supersnapshot_v4_config_setup(BYTE *rawcart) +void supersnapshot_v4_config_setup(uint8_t *rawcart) { memcpy(&roml_banks[0x0000], &rawcart[0x0000], 0x2000); memcpy(&romh_banks[0x0000], &rawcart[0x2000], 0x2000); @@ -295,7 +319,7 @@ static int supersnapshot_v4_common_attach(void) return 0; } -int supersnapshot_v4_bin_attach(const char *filename, BYTE *rawcart) +int supersnapshot_v4_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -315,7 +339,7 @@ int supersnapshot_v4_bin_attach(const char *filename, BYTE *rawcart) * $006070 CHIP ROM #003 $8000 $2000 $2010 * * cartconv produced this from 2011 to 12/2015: - * + * * offset sig type bank start size chunklen * $000040 CHIP ROM #000 $8000 $2000 $2010 * $002050 CHIP ROM #000 $a000 $2000 $2010 @@ -329,9 +353,10 @@ int supersnapshot_v4_bin_attach(const char *filename, BYTE *rawcart) * $004050 CHIP ROM #001 $8000 $4000 $4010 * */ -int supersnapshot_v4_crt_attach(FILE *fd, BYTE *rawcart) +int supersnapshot_v4_crt_attach(FILE *fd, uint8_t *rawcart) { - int i, pos, banks, chips; + int i, banks, chips; + size_t pos; crt_chip_header_t chip; /* find out how many banks and chips are in the file */ @@ -409,7 +434,7 @@ void supersnapshot_v4_detach(void) ARRAY | RAM | 8192 BYTES of RAM data */ -static char snap_module_name[] = "CARTSS4"; +static const char snap_module_name[] = "CARTSS4"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -438,7 +463,7 @@ int supersnapshot_v4_snapshot_write_module(snapshot_t *s) int supersnapshot_v4_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -448,7 +473,7 @@ int supersnapshot_v4_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/supersnapshot4.h b/src/Emulators/vice/c64/cart/supersnapshot4.h index ca07b35e..b162a790 100644 --- a/src/Emulators/vice/c64/cart/supersnapshot4.h +++ b/src/Emulators/vice/c64/cart/supersnapshot4.h @@ -30,21 +30,22 @@ #include "vicetypes.h" -extern BYTE supersnapshot_v4_roml_read(WORD addr); -extern void supersnapshot_v4_roml_store(WORD addr, BYTE value); +uint8_t supersnapshot_v4_roml_read(uint16_t addr); +void supersnapshot_v4_roml_store(uint16_t addr, uint8_t value); -extern void supersnapshot_v4_freeze(void); +void supersnapshot_v4_freeze(void); -extern void supersnapshot_v4_config_init(void); -extern void supersnapshot_v4_config_setup(BYTE *rawcart); -extern int supersnapshot_v4_bin_attach(const char *filename, BYTE *rawcart); -extern int supersnapshot_v4_crt_attach(FILE *fd, BYTE *rawcart); +void supersnapshot_v4_config_init(void); +void supersnapshot_v4_config_setup(uint8_t *rawcart); +int supersnapshot_v4_bin_attach(const char *filename, uint8_t *rawcart); +int supersnapshot_v4_crt_attach(FILE *fd, uint8_t *rawcart); -extern void supersnapshot_v4_detach(void); +void supersnapshot_v4_detach(void); +void supersnapshot_v4_powerup(void); struct snapshot_s; -extern int supersnapshot_v4_snapshot_write_module(struct snapshot_s *s); -extern int supersnapshot_v4_snapshot_read_module(struct snapshot_s *s); +int supersnapshot_v4_snapshot_write_module(struct snapshot_s *s); +int supersnapshot_v4_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/turtlegraphics.c b/src/Emulators/vice/c64/cart/turtlegraphics.c new file mode 100644 index 00000000..352a097a --- /dev/null +++ b/src/Emulators/vice/c64/cart/turtlegraphics.c @@ -0,0 +1,249 @@ +/* + * turtlegraphics.c - Cartridge handling, HES Turtle Graphics II cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "cartio.h" +#include "cartridge.h" +#include "export.h" +#include "monitor.h" +#include "snapshot.h" +#include "turtlegraphics.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* Turtle Graphics II IO1 logic for the roml range $8000-$9fff +* +* - RESET will enable bank 0 +* - Any read/write access to IO/1 will enable bank 1 +*/ + +/* ---------------------------------------------------------------------*/ + +static uint8_t turtlegraphics_io1_read(uint16_t addr); +static uint8_t turtlegraphics_io1_peek(uint16_t addr); +static void turtlegraphics_io1_store(uint16_t addr, uint8_t value); +static int turtlegraphics_dump(void); + +static io_source_t turtlegraphics_device = { + CARTRIDGE_NAME_STRUCTURED_BASIC, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0x01, /* range for the device, regs:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, regs are write only */ + turtlegraphics_io1_store, /* store function */ + NULL, /* NO poke function */ + turtlegraphics_io1_read, /* read function */ + turtlegraphics_io1_peek, /* peek function */ + turtlegraphics_dump, /* device state information dump function */ + CARTRIDGE_TURTLE_GRAPHICS_II, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *turtlegraphics_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_TURTLE_GRAPHICS_II, 1, 0, &turtlegraphics_device, NULL, CARTRIDGE_TURTLE_GRAPHICS_II +}; + +/* ---------------------------------------------------------------------*/ + +static int turtlegraphics_bank = 0; + +static uint8_t turtlegraphics_io1_read(uint16_t addr) +{ + turtlegraphics_bank = 1; + cart_config_changed_slotmain(0 | (1 << CMODE_BANK_SHIFT), 0 | (1 << CMODE_BANK_SHIFT), CMODE_READ); + return 0; +} + +static uint8_t turtlegraphics_io1_peek(uint16_t addr) +{ + return 0; +} + +static void turtlegraphics_io1_store(uint16_t addr, uint8_t value) +{ + turtlegraphics_bank = 1; + cart_config_changed_slotmain(0 | (1 << CMODE_BANK_SHIFT), 0 | (1 << CMODE_BANK_SHIFT), CMODE_READ); +} + +static int turtlegraphics_dump(void) +{ + mon_out("bank: %d\n", turtlegraphics_bank); + return 0; +} + +/* ---------------------------------------------------------------------*/ + +void turtlegraphics_config_init(void) +{ + /* turn on normal config: bank 0 */ + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + turtlegraphics_bank = 0; +} + +void turtlegraphics_config_setup(uint8_t *rawcart) +{ + /* copy banks 0 and 1 */ + memcpy(roml_banks, rawcart, 0x4000); + + /* turn on normal config: bank 0 */ + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + turtlegraphics_bank = 0; +} + +/* ---------------------------------------------------------------------*/ + +static int turtlegraphics_common_attach(void) +{ + /* add export */ + if (export_add(&export_res) < 0) { + return -1; + } + + turtlegraphics_list_item = io_source_register(&turtlegraphics_device); + + return 0; +} + +int turtlegraphics_bin_attach(const char *filename, uint8_t *rawcart) +{ + /* load file into cartridge address space */ + if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_RAW) < 0) { + return -1; + } + + return turtlegraphics_common_attach(); +} + +int turtlegraphics_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + + if (chip.start != 0x8000 || chip.size != 0x2000 || chip.bank > 1) { + return -1; + } + + if (crt_read_chip(rawcart, chip.bank << 13, &chip, fd)) { + return -1; + } + } + + return turtlegraphics_common_attach(); +} + +void turtlegraphics_detach(void) +{ + export_remove(&export_res); + io_source_unregister(turtlegraphics_list_item); + turtlegraphics_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTSTB snapshot module format: + + type | name | version | description + -------------------------------------- + BYTE | bank | 0.1 | current bank + BYTE | active | 0.1 | cartridge active flag + ARRAY | ROML | 0.0+ | 16384 BYTES of ROML data + */ + +static const char snap_module_name[] = "CARTSTB"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int turtlegraphics_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)turtlegraphics_bank) < 0 + || SMW_BA(m, roml_banks, 0x4000) < 0) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int turtlegraphics_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B_INT(m, &turtlegraphics_bank) < 0) { + goto fail; + } + + if (SMR_BA(m, roml_banks, 0x4000) < 0) { + goto fail; + } + + snapshot_module_close(m); + + return turtlegraphics_common_attach(); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/turtlegraphics.h b/src/Emulators/vice/c64/cart/turtlegraphics.h new file mode 100644 index 00000000..7d22aabd --- /dev/null +++ b/src/Emulators/vice/c64/cart/turtlegraphics.h @@ -0,0 +1,45 @@ +/* + * turtlegraphics.h - Cartridge handling, HES Turtle Graphics II cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_TURTLEGRAPHICS_H +#define VICE_TURTLEGRAPHICS_H + +#include + +#include "vicetypes.h" + +void turtlegraphics_config_init(void); +void turtlegraphics_config_setup(uint8_t *rawcart); +int turtlegraphics_bin_attach(const char *filename, uint8_t *rawcart); +int turtlegraphics_crt_attach(FILE *fd, uint8_t *rawcart); +void turtlegraphics_detach(void); + +struct snapshot_s; + +int turtlegraphics_snapshot_write_module(struct snapshot_s *s); +int turtlegraphics_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/uc1.c b/src/Emulators/vice/c64/cart/uc1.c new file mode 100644 index 00000000..c90f8d9c --- /dev/null +++ b/src/Emulators/vice/c64/cart/uc1.c @@ -0,0 +1,724 @@ +/* + * uc1.c - Cartridge handling, Universal Cartridge 1. + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +/* +#define UC1_DEBUG +*/ + + + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "c64cart.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64pla.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "export.h" +#include "lib.h" +#include "maincpu.h" +#include "monitor.h" +#include "resources.h" +#include "ram.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" +#include "uc1.h" + + + +#ifdef UC1_DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + + + + +#define MAXBANKS 8 /* ROM banks (16K each) */ +#define CART_RAM_SIZE (32 * 1024) /* RAM size */ + + + +#define EXROM(regv) ((regv & 0x80) ? 1:0) +#define GAME(regv) ((regv & 0x40) ? 1:0) +#define RAMSEL(regv) ((regv & 0x20) ? 1:0) +#define RAMWRE(regv) ((regv & 0x10) ? 1:0) +#define IOENA(regv) ((regv & 0x08) ? 0:1) + + + + +/* + "UC-1" Cartridge + + - this cart comes in 3 ROM sizes, 32Kb (2 banks), 64Kb (4 banks) and 128Kb (8 banks).. + - this cart comes with 32K SRAM + + - ROM is after reset mapped in at $8000-$BFFF (16k game). + + - 1 register at io1 / de00: + + Bit 0-2 bank number + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - EPROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) +*/ + + +#define CRT_OFF 0xC0 +#define CRT_8K 0x40 +#define CRT_16K 0x00 +#define CRT_ULTI 0x80 + + +/*-- UC register and bank mask -----*/ +static uint8_t regval = 0; +static uint8_t bankmask = 0x07; +static uint8_t cmode = 0; + +/*-- for performace reason pre calculated flags -----*/ +static int write_ram = 0; /* from $4000 to $7FFF and $8000 to $BFFF */ +static int read_ram = 0; + +/*-- FAKE ULTIMAX (only while mode write RAM) -----*/ +static int fakeUlti = 0; +static int read_l = 0; +static int read_h = 0; + + +/* 32 KB RAM */ +static uint8_t *cart_ram = NULL; + + + + +/* + *-- Set UC register at IO1 ----- + */ +static void uc1_io1_storeReg(uint8_t value) +{ + unsigned int wflag = 0; + uint8_t mode = 0; + uint8_t mode_phi1 = 0; + uint8_t mode_phi2 = 0; + + regval = value; + cmode = value & 0xC0; + + if(cmode == CRT_8K) { + /*-- 8K selected -----*/ + mode = CMODE_8KGAME; + read_l = 1; + read_h = 0; + } else if(cmode == CRT_16K) { + /*-- 16K selected -----*/ + mode = CMODE_16KGAME; + read_l = 1; + read_h = 1; + } else if(cmode == CRT_ULTI) { + /*-- UltiMax selected -----*/ + mode = CMODE_ULTIMAX; + read_l = 1; + read_h = 1; + } else { + /*-- CRT_OFF -----*/ + mode = CMODE_RAM; + read_l = 0; + read_h = 0; + } + mode_phi1 = mode; /* VIC */ + mode_phi2 = mode; /* CPU */ + + if(RAMWRE(regval) && cmode != CRT_OFF && cart_ram != NULL) { + /*-- RAM writable -----*/ + mode_phi2 = CMODE_ULTIMAX; /* FAKE UltiMax */ + wflag |= CMODE_WRITE; + wflag |= CMODE_EXPORT_RAM; + write_ram = 1; + } else { + /*-- RAM readonly -----*/ + wflag |= CMODE_READ; + write_ram = 0; + } + + if(RAMSEL(regval) && cart_ram != NULL) { + /*-- RAM selected -----*/ + wflag |= CMODE_EXPORT_RAM; + read_ram = 1; + } else { + /*-- ROM selected -----*/ + read_ram = 0; + } + + cart_config_changed_slotmain(mode_phi1, mode_phi2, wflag); + cart_romlbank_set_slotmain(value & bankmask); + cart_romhbank_set_slotmain(value & bankmask); + + if(cmode == CRT_OFF) { + cart_set_port_game_slotmain(0); + cart_set_port_exrom_slotmain(0); + cart_port_config_changed_slotmain(); + write_ram = 0; + fakeUlti = 0; + } else if(write_ram == 0) { + /*-- normal mode -----*/ + write_ram = 0; + fakeUlti = 0; + } else { + /*-- SRAM write - fake UltiMax -----*/ + DBG(("-FAKE UTLIMAX-")); + fakeUlti = 1; + write_ram = 1; + } + export_ram = write_ram | read_ram; + + DBG(("UC1 reg: %02x bank: %d (%d banks), %s, %s, %s, %s, %s, %s", + regval, (regval & bankmask), bankmask + 1, + EXROM(regval) ? "EXROM" : "/EXROM", + GAME(regval) ? "GAME" : "/GAME", + ( EXROM(regval) && GAME(regval)) ? "DISABLED" : + (!EXROM(regval) && GAME(regval)) ? "8KB" : + (!EXROM(regval) && !GAME(regval)) ? "16KB" : "Ultimax", + RAMSEL(regval) ? "RAM" : "ROM", + RAMWRE(regval) ? "write enabled" : "write disabled", + IOENA(regval) ? "IO enabled" : "IO disabled") + ); +} + +static void resetRegister(void) +{ + uc1_io1_storeReg(0); +} + +/* + *-- Set UC register at IO1 ----- + */ +static void uc1_io1_store(uint16_t addr, uint8_t value) +{ + if(IOENA(regval)) { + uc1_io1_storeReg(value); + } +} + +static uint8_t uc1_io1_peek(uint16_t addr) +{ + return regval; +} + +static uint8_t uc1_io1_read(uint16_t addr) +{ + return 0; +} + +static int uc1_dump(void) +{ + mon_out("UC1 reg: %02x (bank: %d (%d banks), %s, %s, %s, %s, %s, %s)\n", + regval, (regval & bankmask), bankmask + 1, + EXROM(regval) ? "EXROM" : "/EXROM", + GAME(regval) ? "GAME" : "/GAME", + ( EXROM(regval) && GAME(regval)) ? "DISABLED" : + (!EXROM(regval) && GAME(regval)) ? "8KB" : + (!EXROM(regval) && !GAME(regval)) ? "16KB" : "Ultimax", + RAMSEL(regval) ? "RAM" : "ROM", + RAMWRE(regval) ? "write enabled" : "write disabled", + IOENA(regval) ? "IO enabled" : "IO disabled" + ); + return 0; +} + +/* ---------------------------------------------------------------------*/ + + +/* + *-- get cart pointer l ----- + */ +static inline uint8_t *get_mem_l(uint16_t addr, bool ram) +{ + if (ram) { + return cart_ram + (addr & 0x1fff) + ((roml_bank & 1) << 14); + } + return roml_banks + ((addr & 0x1fff) + (roml_bank << 13)); +} + +/* + *-- get cart pointer h ----- + */ +static inline uint8_t *get_mem_h(uint16_t addr, bool ram) +{ + if (ram) { + return cart_ram + (addr & 0x1fff) + 0x2000 + ((roml_bank & 1) << 14); + } + return romh_banks + ((addr & 0x1fff) + (roml_bank << 13)); +} + +/* + *-- read ROM-L or RAM-L ----- + */ +static inline uint8_t read_cart_l(uint16_t addr) +{ + return *(get_mem_l(addr, read_ram)); +} + +/* + *-- read ROM-H or RAM-H ----- + */ +static inline uint8_t read_cart_h(uint16_t addr) +{ + return *(get_mem_h(addr, read_ram)); +} + +/* + *-- write ROM-L or RAM-L ----- + */ +static inline void write_cart_l(uint16_t addr, uint8_t value) +{ + if (write_ram) { + *(get_mem_l(addr, 1)) = value; + } +} + +/* + *-- write ROM-H or RAM-H ----- + */ +static inline void write_cart_h(uint16_t addr, uint8_t value) +{ + if (write_ram) { + *(get_mem_h(addr, 1)) = value; + } +} + + + +/* + *-- read ROM-L or RAM-L if active ----- + */ +uint8_t uc1_roml_read(uint16_t addr) +{ + return read_cart_l(addr); +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +void uc1_roml_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + } +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +int uc1_roml_no_ultimax_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + return 1; + } + return 0; +} + + +/* + *-- read ROM-H or RAM-H if active ----- + */ +uint8_t uc1_romh_read(uint16_t addr) +{ + if(read_h) { + return read_cart_h(addr); + } + return mem_read_without_ultimax(addr); +} + +/* + *-- write RAM-H if active ----- + */ +void uc1_romh_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + + +/* VIC reads */ +int uc1_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + +/* CPU reads */ +int uc1_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + + +/* + read from cart memory for monitor (without side effects) + + the majority of carts can use the generic fallback, custom functions + must be provided by those carts where either: + - the cart is not in "Main Slot" + - "fake ultimax" mapping is used + - memory can not be read without side effects +*/ +int uc1_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if(addr >= 0xE000) { + if(cmode == CRT_ULTI && read_h) { + *value = uc1_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0xA000 && addr < 0xC000) { + if(cmode == CRT_16K && read_h) { + *value = uc1_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0x8000) { + if(read_l) { + *value = uc1_roml_read(addr); + return CART_READ_VALID; + } + } + + DBG(("uc1_peek_mem(read_through): $%04X", addr)); + return CART_READ_THROUGH; +} + +/* + *-- FAKE ULTIMAX for write into 16K range: $4,$5,$6,$7 ----- + */ +void uc1_1000_7fff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + if (addr >= 0x6000) { + write_cart_h(addr, value); + } else if (addr >= 0x4000) { + write_cart_l(addr, value); + } + if (addr >= 0x8000) { + DBG(("uc1_1000_7fff_store(): $%04X (%02X)", addr, value)); + } + mem_store_without_ultimax(addr, value); + } +} + +/* + $1000-$7fff in ultimax mode - this is always regular ram +*/ +uint8_t uc1_1000_7fff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* + $a000 in ultimax mode +*/ +uint8_t uc1_a000_bfff_read(uint16_t addr) +{ + if (cmode == CRT_16K) { + return read_cart_h(addr); + } + if (cmode == CRT_8K) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +void uc1_a000_bfff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + +/* + $c000 in ultimax mode - this is always regular ram +*/ +uint8_t uc1_c000_cfff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t uc1_device = { + CARTRIDGE_NAME_UC1, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc1_io1_store, /* store function */ + NULL, /* NO poke function */ + uc1_io1_read, /* read function */ + uc1_io1_peek, /* peek function */ + uc1_dump, /* device state information dump function */ + CARTRIDGE_UC1, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + + +static io_source_list_t *uc1_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_UC1, 0, 1, &uc1_device, NULL, CARTRIDGE_UC1 +}; + + + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + + +/* ---------------------------------------------------------------------*/ + +void uc1_powerup(void) +{ + resetRegister(); +} + +void uc1_config_init(void) +{ +/* + wflag: + bit 4 0x10 - trigger nmi after config changed + bit 3 0x08 - export ram enabled + bit 2 0x04 - vic phi2 mode (always sees ram if set) + bit 1 0x02 - release freeze (stop asserting NMI) + bit 0 0x01 - r/w flag +*/ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + + resetRegister(); +} + +void uc1_reset(void) +{ + resetRegister(); +} + +void uc1_config_setup(uint8_t *rawcart) +{ + int i; + + for (i = 0; i < MAXBANKS; i++) { /* split interleaved low and high banks */ + memcpy(roml_banks + i * 0x2000, rawcart + i * 0x4000, 0x2000); + memcpy(romh_banks + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000); + } + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int uc1_common_attach(void) +{ + uc1_io1_storeReg(regval); + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (export_add(&export_res) < 0) { + return -1; + } + uc1_list_item = io_source_register(&uc1_device); + return 0; +} + +int uc1_bin_attach(const char *filename, uint8_t *rawcart) +{ + regval = 0; + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x03; + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x01; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + return uc1_common_attach(); +} + +int uc1_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + regval = 0; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if (chip.size == 0x2000) { + if (chip.bank >= MAXBANKS || !(chip.start == 0x8000 || chip.start == 0xa000 || chip.start == 0xe000)) { + return -1; + } + if (crt_read_chip(rawcart, (chip.bank << 14) | (chip.start & 0x2000), &chip, fd)) { + return -1; + } + } else if (chip.size == 0x4000) { + if (chip.bank >= MAXBANKS || chip.start != 0x8000) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + } else { + return -1; + } + } + return uc1_common_attach(); +} + +void uc1_detach(void) +{ + export_remove(&export_res); + io_source_unregister(uc1_list_item); + uc1_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 2 +#define SNAP_MODULE_NAME "CARTUC1" + +int uc1_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int uc1_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + if (cart_ram == NULL) { + return -1; + } + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (0 + || (SMR_B(m, ®val) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (uc1_common_attach() == -1) { + return -1; + } + uc1_io1_store(0xde00, regval); + return 0; +} diff --git a/src/Emulators/vice/c64/cart/uc1.h b/src/Emulators/vice/c64/cart/uc1.h new file mode 100644 index 00000000..7c4c62ef --- /dev/null +++ b/src/Emulators/vice/c64/cart/uc1.h @@ -0,0 +1,67 @@ +/* + * uc1.h - Cartridge handling, Universal Cartridge 1 + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_UC1_H +#define VICE_UC1_H + +#include + +#include "vicetypes.h" + +void uc1_config_init(void); +void uc1_config_setup(uint8_t *rawcart); + +int uc1_bin_attach(const char *filename, uint8_t *rawcart); +int uc1_crt_attach(FILE *fd, uint8_t *rawcart); +void uc1_detach(void); + +uint8_t uc1_roml_read(uint16_t addr); +uint8_t uc1_romh_read(uint16_t addr); +int uc1_roml_no_ultimax_store(uint16_t addr, uint8_t value); +int uc1_romh_phi1_read(uint16_t addr, uint8_t *value); +int uc1_romh_phi2_read(uint16_t addr, uint8_t *value); +void uc1_roml_store(uint16_t addr, uint8_t value); +void uc1_romh_store(uint16_t addr, uint8_t value); + +uint8_t uc1_1000_7fff_read(uint16_t addr); +void uc1_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t uc1_a000_bfff_read(uint16_t addr); +void uc1_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t uc1_c000_cfff_read(uint16_t addr); +void uc1_c000_cfff_store(uint16_t addr, uint8_t value); + +int uc1_peek_mem(export_t *ex, uint16_t addr, uint8_t *value); + + +void uc1_reset(void); +void uc1_powerup(void); + +struct snapshot_s; + +int uc1_snapshot_write_module(struct snapshot_s *s); +int uc1_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/uc2.c b/src/Emulators/vice/c64/cart/uc2.c new file mode 100644 index 00000000..8236ecd9 --- /dev/null +++ b/src/Emulators/vice/c64/cart/uc2.c @@ -0,0 +1,859 @@ +/* + * uc2.c - Cartridge handling, Universal Cartridge 2 + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + + + +/* #define UC2_DEBUG */ + + + + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "c64cart.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64pla.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "export.h" +#include "lib.h" +#include "maincpu.h" +#include "monitor.h" +#include "resources.h" +#include "ram.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" +#include "uc2.h" + + + +#ifdef UC2_DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + + + + +#define MAXBANKS 32 /* ROM banks (16K each, 512K) */ +#define CART_RAM_SIZE (512 * 1024) /* RAM size 512K */ + + + +#define EXROM(regv) ((regv & 0x80) ? 1:0) +#define GAME(regv) ((regv & 0x40) ? 1:0) +#define RAMSEL(regv) ((regv & 0x20) ? 1:0) +#define RAMWRE(regv) ((regv & 0x10) ? 1:0) +#define IOENA(regv) ((regv & 0x08) ? 0:1) +#define MAXM(regv) ((regv & 0x04) ? 1:0) + + + + +/* + "UC-2" Cartridge + + this cart comes in 3 ROM sizes, 128Kb (8 banks), 256Kb (16 banks) and 512Kb (32 banks).. + - this cart comes with 512K SRAM + + - ROM is after reset mapped in at $8000-$BFFF (16k game cart). + + - 2 register at io1 / De02,DE03. + (register are write and readable) + + Register A (IO1:$DE02): + Bit 0-4 bank number + + Register B (IO1:$DE03): + Bit 2 MAX machine flag + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - EPROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) +*/ + + +#define CRT_OFF 0xC0 +#define CRT_8K 0x40 +#define CRT_16K 0x00 +#define CRT_ULTI 0x80 + + +/*-- UC register and bank mask ----- */ +static uint8_t regA = 0; +static uint8_t regB = 0; +static uint8_t bankmask = 0x1F; +static uint8_t cmode = 0; +static uint8_t ucmode = 2; + +/*-- for performace reason pre calculated flags ----- */ +static int write_ram = 0; /* from $4000 to $7FFF and $8000 to $BFFF */ +static int read_ram = 0; + +/*-- FAKE ULTIMAX (only while mode write RAM) ----- */ +static int fakeUlti = 0; +static int read_l = 0; +static int read_h = 0; + + +/* 512 KB RAM */ +static uint8_t *cart_ram = NULL; + + + + +/* + *-- Set UC register A ----- + */ +static inline void uc2_io1_storeA(uint8_t value) +{ + regA = value & 0x1F; + cart_romlbank_set_slotmain(regA & bankmask); + cart_romhbank_set_slotmain(regA & bankmask); + + DBG(("UC2 reg-A: %02x (bank: %d (%d banks))", + regA, (regA & bankmask), bankmask + 1) + ); +} + +/* + *-- Set UC register B ----- + */ +static inline void uc2_io1_storeB(uint8_t value) +{ + unsigned int wflag = 0; + uint8_t mode = 0; + uint8_t mode_phi1 = 0; + uint8_t mode_phi2 = 0; + + regB = value; + cmode = value & 0xC0; + + if(cmode == CRT_8K) { + /*-- 8K selected ----- */ + mode = CMODE_8KGAME; + read_l = 1; + read_h = 0; + } else if(cmode == CRT_16K) { + /*-- 16K selected ----- */ + mode = CMODE_16KGAME; + read_l = 1; + read_h = 1; + } else if(cmode == CRT_ULTI) { + /*-- UltiMax selected ----- */ + mode = CMODE_ULTIMAX; + read_l = 1; + read_h = 1; + } else { + /*-- CRT_OFF ----- */ + mode = CMODE_RAM; + read_l = 0; + read_h = 0; + } + mode_phi1 = mode; /* VIC */ + mode_phi2 = mode; /* CPU */ + + if(RAMWRE(regB) && cmode != CRT_OFF && cart_ram != NULL) { + /*-- RAM writable -----*/ + mode_phi2 = CMODE_ULTIMAX; /* FAKE UltiMax */ + wflag |= CMODE_WRITE; + wflag |= CMODE_EXPORT_RAM; + write_ram = 1; + } else { + /*-- RAM readonly -----*/ + wflag |= CMODE_READ; + write_ram = 0; + } + if(RAMSEL(regB) && cart_ram != NULL) { + /*-- RAM selected -----*/ + wflag |= CMODE_EXPORT_RAM; + read_ram = 1; + } else { + /*-- ROM selected -----*/ + read_ram = 0; + } + + cart_config_changed_slotmain(mode_phi1, mode_phi2, wflag); + cart_romlbank_set_slotmain(regA & bankmask); + cart_romhbank_set_slotmain(regA & bankmask); + + if(cmode == CRT_OFF) { + cart_set_port_game_slotmain(0); + cart_set_port_exrom_slotmain(0); + cart_port_config_changed_slotmain(); + write_ram = 0; + fakeUlti = 0; + } else if(write_ram == 0) { + /*-- normal mode -----*/ + write_ram = 0; + fakeUlti = 0; + } else { + /*-- SRAM write - fake UltiMax -----*/ + DBG(("-FAKE UTLIMAX-")); + fakeUlti = 1; + write_ram = 1; + } + export_ram = write_ram | read_ram; + + DBG(("UC2 reg-B: %02x %s, %s, %s, %s, %s, %s", regB, + EXROM(regB) ? "EXROM" : "/EXROM", + GAME(regB) ? "GAME" : "/GAME", + ( EXROM(regB) && GAME(regB)) ? "DISABLED" : + (!EXROM(regB) && GAME(regB)) ? "8KB" : + (!EXROM(regB) && !GAME(regB)) ? "16KB" : "Ultimax", + RAMSEL(regB) ? "RAM" : "ROM", + RAMWRE(regB) ? "write enabled" : "write disabled", + IOENA(regB) ? "IO enabled" : "IO disabled") + ); +} +static void resetRegister(void) +{ + uc2_io1_storeA(0); + uc2_io1_storeB(0); +} + +/* + *-- Set UC register at IO1 ----- + */ +static void uc2_io1_store(uint16_t addr, uint8_t value) +{ + if(IOENA(regB)) { + switch(addr & 0x3) { + case 2: /* register A */ + uc2_io1_storeA(value); + break; + case 3: /* register B */ + uc2_io1_storeB(value); + break; + } + } +} + +static uint8_t uc2_io1_peek(uint16_t addr) +{ + if(IOENA(regB)) { + switch(addr & 0x3) { + case 2: /* register A */ + return(regA); + case 3: /* register B */ + return(regB); + } + } + return 0xff; +} +static uint8_t uc15_io1_peek(uint16_t addr) +{ + return 0xff; +} + +static uint8_t uc2_io1_read(uint16_t addr) +{ + return uc2_io1_peek(addr); +} +static uint8_t uc15_io1_read(uint16_t addr) +{ + return uc15_io1_peek(addr); +} + +static int uc2_dump(void) +{ + mon_out("UC2 reg: %02x (bank: %d (%d banks), %s, %s, %s, %s, %s, %s)\n", + regA, (regA & bankmask), bankmask + 1, + EXROM(regB) ? "EXROM" : "/EXROM", + GAME(regB) ? "GAME" : "/GAME", + ( EXROM(regB) && GAME(regB)) ? "DISABLED" : + (!EXROM(regB) && GAME(regB)) ? "8KB" : + (!EXROM(regB) && !GAME(regB)) ? "16KB" : "Ultimax", + RAMSEL(regB) ? "RAM" : "ROM", + RAMWRE(regB) ? "write enabled" : "write disabled", + IOENA(regB) ? "IO enabled" : "IO disabled" + ); + return 0; +} + +/* ---------------------------------------------------------------------*/ + + +/* + *-- get cart pointer l ----- + */ +static inline uint8_t *get_mem_l(uint16_t addr, bool ram) +{ + if (ram && cart_ram != NULL) { + return cart_ram + (addr & 0x1fff) + (regA << 14); + } + return roml_banks + ((addr & 0x1fff) + (regA << 13)); +} + +/* + *-- get cart pointer h ----- + */ +static inline uint8_t *get_mem_h(uint16_t addr, bool ram) +{ + if (ram && cart_ram != NULL) { + return cart_ram + (addr & 0x1fff) + 0x2000 + (regA << 14); + } + return romh_banks + ((addr & 0x1fff) + (regA << 13)); +} + +/* + *-- read ROM-L or RAM-L ----- + */ +static inline uint8_t read_cart_l(uint16_t addr) +{ +#ifdef UC2_DEBUG2 + if (read_ram) { + if((addr & 0xFFF) == 0) { + DBG(("read RAM-L: $%04X (%02X)", addr, *(get_mem_l(addr, read_ram)))); + } + } +#endif + return *(get_mem_l(addr, read_ram)); +} + +/* + *-- read ROM-H or RAM-H ----- + */ +static inline uint8_t read_cart_h(uint16_t addr) +{ +#ifdef UC2_DEBUG2 + if (read_ram) { + if((addr & 0xFFF) == 0) { + DBG(("read RAM-H: $%04X (%02X)", addr, *(get_mem_h(addr, read_ram)))); + } + } +#endif + return *(get_mem_h(addr, read_ram)); +} + +/* + *-- write ROM-L or RAM-L ----- + */ +static inline void write_cart_l(uint16_t addr, uint8_t value) +{ + if (write_ram) { +#ifdef UC2_DEBUG + if((addr & 0xFFF) == 0) { + DBG(("write RAM-L: $%04X, %02X", addr, value)); + } +#endif + *(get_mem_l(addr, 1)) = value; + } +} + +/* + *-- write ROM-H or RAM-H ----- + */ +static inline void write_cart_h(uint16_t addr, uint8_t value) +{ + if (write_ram) { +#ifdef UC2_DEBUG + if((addr & 0xFFF) == 0) { + DBG(("write RAM-H: $%04X, %02X", addr, value)); + } +#endif + *(get_mem_h(addr, 1)) = value; + } +} + + + +/* + *-- read ROM-L or RAM-L if active ----- + */ +uint8_t uc2_roml_read(uint16_t addr) +{ + return read_cart_l(addr); +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +void uc2_roml_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + } +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +int uc2_roml_no_ultimax_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + return 1; + } + return 0; +} + + +/* + *-- read ROM-H or RAM-H if active ----- + */ +uint8_t uc2_romh_read(uint16_t addr) +{ + if(read_h) { + return read_cart_h(addr); + } + return mem_read_without_ultimax(addr); +} + +/* + *-- write RAM-H if active ----- + */ +void uc2_romh_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + + +/* VIC reads */ +int uc2_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + /*-- ROM-H: 2000-3FFF,6000-7FFF,A000-BFFF,E000-FFFF -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} +/* CPU reads */ +int uc2_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + /*-- ROM-H: 2000-3FFF,6000-7FFF,A000-BFFF,E000-FFFF -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + + +/* + read from cart memory for monitor (without side effects) + + the majority of carts can use the generic fallback, custom functions + must be provided by those carts where either: + - the cart is not in "Main Slot" + - "fake ultimax" mapping is used + - memory can not be read without side effects +*/ +int uc2_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if(addr >= 0xE000) { + /*-- Kernal: E000-FFFF -----*/ + if(cmode == CRT_ULTI && read_h) { + *value = uc2_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0xA000 && addr < 0xC000) { + /*-- ROM-H: A000-BFFF -----*/ + if(cmode == CRT_16K && read_h) { + *value = uc2_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0x8000) { + /*-- ROM-L: 8000-9FFF -----*/ + if(read_l) { + *value = uc2_roml_read(addr); + return CART_READ_VALID; + } + } + + DBG(("uc2_peek_mem(read_through): $%04X ", addr)); + return CART_READ_THROUGH; +} + +/* + *-- FAKE ULTIMAX for write into 16K range: $4,$5,$6,$7 ----- + */ +void uc2_1000_7fff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + if (addr >= 0x6000) { + write_cart_h(addr, value); + } else if (addr >= 0x4000) { + write_cart_l(addr, value); + } + if (addr >= 0x8000) { + DBG(("uc2_1000_7fff_store(): $%04X (%02X)", addr, value)); + } + mem_store_without_ultimax(addr, value); + } +} + +/* + $1000-$7fff in ultimax mode - this is always regular ram +*/ +uint8_t uc2_1000_7fff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* + $a000 in ultimax mode +*/ +uint8_t uc2_a000_bfff_read(uint16_t addr) +{ + if (cmode == CRT_16K) { + return read_cart_h(addr); + } + if (cmode == CRT_8K) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +void uc2_a000_bfff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + +/* + $c000 in ultimax mode - this is always regular ram +*/ +uint8_t uc2_c000_cfff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t uc2_device = { + CARTRIDGE_NAME_UC2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc2_io1_store, /* store function */ + NULL, /* NO poke function */ + uc2_io1_read, /* read function */ + uc2_io1_peek, /* peek function */ + uc2_dump, /* device state information dump function */ + CARTRIDGE_UC2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; +static const export_resource_t export_res_uc2 = { + CARTRIDGE_NAME_UC2, 0, 1, &uc2_device, NULL, CARTRIDGE_UC2 +}; + +static io_source_t uc15_device = { + CARTRIDGE_NAME_UC15, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc2_io1_store, /* store function */ + NULL, /* NO poke function */ + uc15_io1_read, /* read function */ + uc15_io1_peek, /* peek function */ + uc2_dump, /* device state information dump function */ + CARTRIDGE_UC15, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; +static const export_resource_t export_res_uc15 = { + CARTRIDGE_NAME_UC15, 0, 1, &uc15_device, NULL, CARTRIDGE_UC15 +}; + + +static io_source_list_t *uc_list_item = NULL; + + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + + +/* ---------------------------------------------------------------------*/ + +void uc2_powerup(void) +{ + resetRegister(); +} + +void uc2_config_init(void) +{ +/* + wflag: + bit 4 0x10 - trigger nmi after config changed + bit 3 0x08 - export ram enabled + bit 2 0x04 - vic phi2 mode (always sees ram if set) + bit 1 0x02 - release freeze (stop asserting NMI) + bit 0 0x01 - r/w flag +*/ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + + resetRegister(); +} + +void uc2_reset(void) +{ + resetRegister(); +} + +void uc2_config_setup(uint8_t *rawcart) +{ + int i; + + for (i = 0; i < MAXBANKS; i++) { /* split interleaved low and high banks */ + memcpy(roml_banks + i * 0x2000, rawcart + i * 0x4000, 0x2000); + memcpy(romh_banks + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000); + } + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int uc2_common_attach(void) +{ + uc2_io1_storeA(regA); + uc2_io1_storeB(regB); + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if(ucmode == 2) { + if (export_add(&export_res_uc2) < 0) { + return -1; + } + uc_list_item = io_source_register(&uc2_device); + } else { + if (export_add(&export_res_uc15) < 0) { + return -1; + } + uc_list_item = io_source_register(&uc15_device); + } + return 0; +} + +static int bin_attach(const char *filename, uint8_t *rawcart) +{ + bankmask = 0x1f; + if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x0f; + if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + return uc2_common_attach(); +} + +static int crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if (chip.size == 0x2000) { + if (chip.bank >= MAXBANKS || !(chip.start == 0x8000 || chip.start == 0xa000 || chip.start == 0xe000)) { + return -1; + } + if (crt_read_chip(rawcart, (chip.bank << 14) | (chip.start & 0x2000), &chip, fd)) { + return -1; + } + } else if (chip.size == 0x4000) { + if (chip.bank >= MAXBANKS || chip.start != 0x8000) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + } else { + return -1; + } + } + return uc2_common_attach(); +} + + +int uc2_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("UC2 attach BIN file")); + ucmode = 2; + return bin_attach(filename, rawcart); +} + +int uc15_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("UC15 attach BIN file")); + ucmode = 1; + return bin_attach(filename, rawcart); +} + +int uc2_crt_attach(FILE *fd, uint8_t *rawcart) +{ + DBG(("UC2 attach CRT file")); + ucmode = 2; + return crt_attach(fd, rawcart); +} + +int uc15_crt_attach(FILE *fd, uint8_t *rawcart) +{ + DBG(("UC15 attach CRT file")); + ucmode = 1; + return crt_attach(fd, rawcart); +} + +void uc2_detach(void) +{ + lib_free(cart_ram); + cart_ram = NULL; + + + if(ucmode == 2) { + export_remove(&export_res_uc2); + } + else { + export_remove(&export_res_uc15); + } + io_source_unregister(uc_list_item); + uc_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 2 +#define SNAP_MODULE_NAME "CARTUC2" + +int uc2_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regA) < 0) + || (SMW_B(m, (uint8_t)regB) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int uc2_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + if (cart_ram == NULL) { + return -1; + } + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (0 + || (SMR_B(m, ®A) < 0) + || (SMR_B(m, ®B) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (uc2_common_attach() == -1) { + return -1; + } + return 0; +} diff --git a/src/Emulators/vice/c64/cart/uc2.h b/src/Emulators/vice/c64/cart/uc2.h new file mode 100644 index 00000000..e1368460 --- /dev/null +++ b/src/Emulators/vice/c64/cart/uc2.h @@ -0,0 +1,69 @@ +/* + * uc2.h - Cartridge handling, Universal Cartridge 2. + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_UC2_H +#define VICE_UC2_H + +#include + +#include "vicetypes.h" + +void uc2_config_init(void); +void uc2_config_setup(uint8_t *rawcart); + +int uc15_bin_attach(const char *filename, uint8_t *rawcart); +int uc15_crt_attach(FILE *fd, uint8_t *rawcart); +int uc2_bin_attach(const char *filename, uint8_t *rawcart); +int uc2_crt_attach(FILE *fd, uint8_t *rawcart); +void uc2_detach(void); + +uint8_t uc2_roml_read(uint16_t addr); +uint8_t uc2_romh_read(uint16_t addr); +int uc2_roml_no_ultimax_store(uint16_t addr, uint8_t value); +int uc2_romh_phi1_read(uint16_t addr, uint8_t *value); +int uc2_romh_phi2_read(uint16_t addr, uint8_t *value); +void uc2_roml_store(uint16_t addr, uint8_t value); +void uc2_romh_store(uint16_t addr, uint8_t value); + +int uc2_peek_mem(export_t *ex, uint16_t addr, uint8_t *value); + +uint8_t uc2_1000_7fff_read(uint16_t addr); +void uc2_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t uc2_a000_bfff_read(uint16_t addr); +void uc2_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t uc2_c000_cfff_read(uint16_t addr); +void uc2_c000_cfff_store(uint16_t addr, uint8_t value); + + +void uc2_reset(void); +void uc2_powerup(void); + +struct snapshot_s; + +int uc2_snapshot_write_module(struct snapshot_s *s); +int uc2_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/cart/warpspeed.c b/src/Emulators/vice/c64/cart/warpspeed.c index ce41d5a8..d61307fc 100644 --- a/src/Emulators/vice/c64/cart/warpspeed.c +++ b/src/Emulators/vice/c64/cart/warpspeed.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUG_WARPSPEED */ + #include "vice.h" #include @@ -44,12 +46,21 @@ #include "warpspeed.h" #include "crt.h" +#ifdef DEBUG_WARPSPEED +#define DBG(x) printf x +#else +#define DBG(x) +#endif + /* Warpspeed - 16k ROM - uses full io1/io2 + the cartridge uses two j/k flipflops to enable/disable the ROM. simply said + it works like this: + io1 - read: ROM (offset $1e00) - write: enable rom at 8000 @@ -57,43 +68,71 @@ io2 - read: ROM (offset $1f00) - write: disable rom at 8000 + + however, in reality its like this (for writing): + + to enable the cartridge: + - write access in IO1 + - write access outside of IO2 + (two write accesses in IO1 will work) + + to disable the cartridge: + - write access outside of IO1 + - write access in IO2 + (two write accesses in IO2 will work) + + to toggle the ROM enabled state: + - write access to IO1 + - write access to IO2 + + the software uses "indexed INC abs" to do the switching, which is why the + simplified version also works. + + Note: the actual cartridge contains both a C64 and a C128 ROM, which can + be selected with a switch. We implement them as if these two ROMs were + different cartridges - this way they can be selected by using the other + .crt file, instead of having to flip the switch in the user interface. */ /* some prototypes are needed */ -static BYTE warpspeed_io1_read(WORD addr); -static void warpspeed_io1_store(WORD addr, BYTE value); -static BYTE warpspeed_io2_read(WORD addr); -static void warpspeed_io2_store(WORD addr, BYTE value); +static uint8_t warpspeed_io1_read(uint16_t addr); +static void warpspeed_io1_store(uint16_t addr, uint8_t value); +static uint8_t warpspeed_io2_read(uint16_t addr); +static void warpspeed_io2_store(uint16_t addr, uint8_t value); static int warpspeed_dump(void); static io_source_t warpspeed_io1_device = { - CARTRIDGE_NAME_WARPSPEED, - IO_DETACH_CART, - NULL, - 0xde00, 0xdeff, 0xff, - 1, /* read is always valid */ - warpspeed_io1_store, - warpspeed_io1_read, - warpspeed_io1_read, - warpspeed_dump, - CARTRIDGE_WARPSPEED, - 0, - 0 + CARTRIDGE_NAME_WARPSPEED, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, regs:$de00-$deff */ + 1, /* read is always valid */ + warpspeed_io1_store, /* store function */ + NULL, /* NO poke function */ + warpspeed_io1_read, /* read function */ + warpspeed_io1_read, /* peek function */ + warpspeed_dump, /* device state information dump function */ + CARTRIDGE_WARPSPEED, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t warpspeed_io2_device = { - CARTRIDGE_NAME_WARPSPEED, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 1, /* read is always valid */ - warpspeed_io2_store, - warpspeed_io2_read, - warpspeed_io2_read, - warpspeed_dump, - CARTRIDGE_WARPSPEED, - 0, - 0 + CARTRIDGE_NAME_WARPSPEED, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 1, /* read is always valid */ + warpspeed_io2_store, /* store function */ + NULL, /* NO poke function */ + warpspeed_io2_read, /* read function */ + warpspeed_io2_read, /* peek function */ + warpspeed_dump, /* device state information dump function */ + CARTRIDGE_WARPSPEED, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *warpspeed_io1_list_item = NULL; @@ -101,33 +140,79 @@ static io_source_list_t *warpspeed_io2_list_item = NULL; /* ---------------------------------------------------------------------*/ -static int warpspeed_8000 = 0; - -static BYTE warpspeed_io1_read(WORD addr) +static uint8_t warpspeed_io1_read(uint16_t addr) { return roml_banks[0x1e00 + (addr & 0xff)]; } -static void warpspeed_io1_store(WORD addr, BYTE value) +static uint8_t warpspeed_io2_read(uint16_t addr) { - cart_config_changed_slotmain(1, 1, CMODE_WRITE); - warpspeed_8000 = 1; + return roml_banks[0x1f00 + (addr & 0xff)]; } -static BYTE warpspeed_io2_read(WORD addr) +#define LASTWRITE_IO1 0 +#define LASTWRITE_IO2 1 +#define LASTWRITE_NOTIO 2 + +static int warpspeed_enabled = 0; +static int warpspeed_lastwrite = 0; + +/* FIXME: this should be called on *any other* write access. we cant really do + that right now with the cartridge system :( fortunately the warpspeed + cartridge software does not rely on this, so it works anyway */ +#if 0 +void warpspeed_no_io_store(uint16_t addr, uint8_t value) { - return roml_banks[0x1f00 + (addr & 0xff)]; + /* if last write did go to IO1, enable the cartridge */ + if (warpspeed_lastwrite == LASTWRITE_IO1) { + DBG(("warpspeed_io1_store %04x %02x - lastwrite: IO1 rom: enabling\n", addr, value)); + warpspeed_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + } + warpspeed_lastwrite = LASTWRITE_NOTIO; +} +#endif + +static void warpspeed_io1_store(uint16_t addr, uint8_t value) +{ + /* if last write did go to IO1, enable the cartridge */ + if (warpspeed_lastwrite == LASTWRITE_IO1) { + DBG(("warpspeed_io1_store de%02x %02x - lastwrite: IO1 rom: enabling\n", addr, value)); + warpspeed_enabled = 1; + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + } +#ifdef DEBUG_WARPSPEED + else { + DBG(("warpspeed_io1_store de%02x %02x - lastwrite: not IO1 rom: %s (no change)\n", + addr, value, warpspeed_enabled ? "enabled" : "disabled")); + } +#endif + warpspeed_lastwrite = LASTWRITE_IO1; } -static void warpspeed_io2_store(WORD addr, BYTE value) +static void warpspeed_io2_store(uint16_t addr, uint8_t value) { - cart_config_changed_slotmain(2, 2, CMODE_WRITE); - warpspeed_8000 = 0; + /* if last write did not go to IO1, disable the cartridge */ + if (warpspeed_lastwrite != LASTWRITE_IO1) { + DBG(("warpspeed_io2_store df%02x %02x - lastwrite: not IO1 rom: disabling\n", addr, value)); + warpspeed_enabled = 0; + } else if (warpspeed_lastwrite == LASTWRITE_IO1) { + /* if last write did go to IO1, then toggle the cartridge enabled status */ + warpspeed_enabled ^= 1; + DBG(("warpspeed_io2_store df%02x %02x - lastwrite: IO1 rom: toggling (now: %s)\n", + addr, value, warpspeed_enabled ? "enabled" : "disabled")); + } + if (warpspeed_enabled) { + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + } else { + cart_config_changed_slotmain(CMODE_RAM, CMODE_RAM, CMODE_RAM); + } + warpspeed_lastwrite = LASTWRITE_IO2; } static int warpspeed_dump(void) { - mon_out("$8000-$9FFF ROM: %s\n", (warpspeed_8000) ? "enabled" : "disabled"); + mon_out("$8000-$9FFF ROM: %s\n", (warpspeed_enabled) ? "enabled" : "disabled"); return 0; } @@ -139,19 +224,23 @@ static const export_resource_t export_res_warpspeed = { }; /* ---------------------------------------------------------------------*/ +void warpspeed_reset(void) +{ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + warpspeed_enabled = 1; + warpspeed_lastwrite = 0; +} void warpspeed_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); - warpspeed_8000 = 1; + warpspeed_reset(); } -void warpspeed_config_setup(BYTE *rawcart) +void warpspeed_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(1, 1, CMODE_READ); - warpspeed_8000 = 1; + warpspeed_reset(); } static int warpspeed_common_attach(void) @@ -166,7 +255,7 @@ static int warpspeed_common_attach(void) return 0; } -int warpspeed_bin_attach(const char *filename, BYTE *rawcart) +int warpspeed_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -174,7 +263,7 @@ int warpspeed_bin_attach(const char *filename, BYTE *rawcart) return warpspeed_common_attach(); } -int warpspeed_crt_attach(FILE *fd, BYTE *rawcart) +int warpspeed_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -213,7 +302,7 @@ void warpspeed_detach(void) ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTWARP"; +static const char snap_module_name[] = "CARTWARP"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -228,7 +317,7 @@ int warpspeed_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)warpspeed_8000) < 0 + || SMW_B(m, (uint8_t)warpspeed_enabled) < 0 || SMW_BA(m, roml_banks, 0x2000) < 0 || SMW_BA(m, romh_banks, 0x2000) < 0) { snapshot_module_close(m); @@ -240,7 +329,7 @@ int warpspeed_snapshot_write_module(snapshot_t *s) int warpspeed_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -250,18 +339,18 @@ int warpspeed_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { - if (SMR_B_INT(m, &warpspeed_8000) < 0) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { + if (SMR_B_INT(m, &warpspeed_enabled) < 0) { goto fail; } } else { - warpspeed_8000 = 0; + warpspeed_enabled = 0; } if (0 diff --git a/src/Emulators/vice/c64/cart/warpspeed.h b/src/Emulators/vice/c64/cart/warpspeed.h index 0d2d7274..dfc22bde 100644 --- a/src/Emulators/vice/c64/cart/warpspeed.h +++ b/src/Emulators/vice/c64/cart/warpspeed.h @@ -31,15 +31,16 @@ #include "vicetypes.h" -extern void warpspeed_config_setup(BYTE *rawcart); -extern int warpspeed_bin_attach(const char *filename, BYTE *rawcart); -extern int warpspeed_crt_attach(FILE *fd, BYTE *rawcart); -extern void warpspeed_detach(void); -extern void warpspeed_config_init(void); +void warpspeed_config_setup(uint8_t *rawcart); +int warpspeed_bin_attach(const char *filename, uint8_t *rawcart); +int warpspeed_crt_attach(FILE *fd, uint8_t *rawcart); +void warpspeed_detach(void); +void warpspeed_config_init(void); +void warpspeed_reset(void); struct snapshot_s; -extern int warpspeed_snapshot_write_module(struct snapshot_s *s); -extern int warpspeed_snapshot_read_module(struct snapshot_s *s); +int warpspeed_snapshot_write_module(struct snapshot_s *s); +int warpspeed_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/westermann.c b/src/Emulators/vice/c64/cart/westermann.c index efa15896..f04480ab 100644 --- a/src/Emulators/vice/c64/cart/westermann.c +++ b/src/Emulators/vice/c64/cart/westermann.c @@ -54,23 +54,25 @@ */ /* some prototypes are needed */ -static BYTE westermann_io2_read(WORD addr); -static BYTE westermann_io2_peek(WORD addr); +static uint8_t westermann_io2_read(uint16_t addr); +static uint8_t westermann_io2_peek(uint16_t addr); static int westermann_dump(void); static io_source_t westermann_device = { - CARTRIDGE_NAME_WESTERMANN, - IO_DETACH_CART, - NULL, - 0xdf00, 0xdfff, 0xff, - 0, /* read is never valid */ - NULL, - westermann_io2_read, - westermann_io2_peek, - westermann_dump, - CARTRIDGE_WESTERMANN, - 0, - 0 + CARTRIDGE_NAME_WESTERMANN, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, address is ignored, reg:$df00, mirrors:$df01-$dfff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + westermann_io2_read, /* read function */ + westermann_io2_peek, /* peek function */ + westermann_dump, /* device state information dump function */ + CARTRIDGE_WESTERMANN, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *westermann_list_item = NULL; @@ -83,14 +85,14 @@ static const export_resource_t export_res_westermann = { static int westermann_a000 = 0; -static BYTE westermann_io2_read(WORD addr) +static uint8_t westermann_io2_read(uint16_t addr) { cart_config_changed_slotmain(0, 0, CMODE_READ); westermann_a000 = 0; return 0; } -static BYTE westermann_io2_peek(WORD addr) +static uint8_t westermann_io2_peek(uint16_t addr) { return 0; } @@ -106,15 +108,15 @@ static int westermann_dump(void) void westermann_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); westermann_a000 = 1; } -void westermann_config_setup(BYTE *rawcart) +void westermann_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x2000); - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); westermann_a000 = 1; } @@ -128,7 +130,7 @@ static int westermann_common_attach(void) return 0; } -int westermann_bin_attach(const char *filename, BYTE *rawcart) +int westermann_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x4000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; @@ -136,7 +138,7 @@ int westermann_bin_attach(const char *filename, BYTE *rawcart) return westermann_common_attach(); } -int westermann_crt_attach(FILE *fd, BYTE *rawcart) +int westermann_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; @@ -173,7 +175,7 @@ void westermann_detach(void) ARRAY | ROMH | 0.0+ | 8192 BYTES of ROMH data */ -static char snap_module_name[] = "CARTWEST"; +static const char snap_module_name[] = "CARTWEST"; #define SNAP_MAJOR 0 #define SNAP_MINOR 1 @@ -188,7 +190,7 @@ int westermann_snapshot_write_module(snapshot_t *s) } if (0 - || SMW_B(m, (BYTE)westermann_a000) < 0 + || SMW_B(m, (uint8_t)westermann_a000) < 0 || SMW_BA(m, roml_banks, 0x2000) < 0 || SMW_BA(m, romh_banks, 0x2000) < 0) { snapshot_module_close(m); @@ -200,7 +202,7 @@ int westermann_snapshot_write_module(snapshot_t *s) int westermann_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -216,7 +218,7 @@ int westermann_snapshot_read_module(snapshot_t *s) } /* new in 0.1 */ - if (SNAPVAL(vmajor, vminor, 0, 1)) { + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { if (SMR_B_INT(m, &westermann_a000) < 0) { goto fail; } diff --git a/src/Emulators/vice/c64/cart/westermann.h b/src/Emulators/vice/c64/cart/westermann.h index 3aa829dc..76a23ae0 100644 --- a/src/Emulators/vice/c64/cart/westermann.h +++ b/src/Emulators/vice/c64/cart/westermann.h @@ -31,15 +31,15 @@ #include "vicetypes.h" -extern void westermann_config_setup(BYTE *rawcart); -extern int westermann_bin_attach(const char *filename, BYTE *rawcart); -extern int westermann_crt_attach(FILE *fd, BYTE *rawcart); -extern void westermann_detach(void); -extern void westermann_config_init(void); +void westermann_config_setup(uint8_t *rawcart); +int westermann_bin_attach(const char *filename, uint8_t *rawcart); +int westermann_crt_attach(FILE *fd, uint8_t *rawcart); +void westermann_detach(void); +void westermann_config_init(void); struct snapshot_s; -extern int westermann_snapshot_write_module(struct snapshot_s *s); -extern int westermann_snapshot_read_module(struct snapshot_s *s); +int westermann_snapshot_write_module(struct snapshot_s *s); +int westermann_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/zaxxon.c b/src/Emulators/vice/c64/cart/zaxxon.c index 489dc00b..55c730d8 100644 --- a/src/Emulators/vice/c64/cart/zaxxon.c +++ b/src/Emulators/vice/c64/cart/zaxxon.c @@ -55,13 +55,13 @@ static const export_resource_t export_res = { CARTRIDGE_NAME_ZAXXON, 1, 1, NULL, NULL, CARTRIDGE_ZAXXON }; -BYTE zaxxon_roml_read(WORD addr) +uint8_t zaxxon_roml_read(uint16_t addr) { cart_romhbank_set_slotmain((addr & 0x1000) ? 1 : 0); return roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; } -int zaxxon_peek_mem(export_t *export, WORD addr, BYTE *value) +int zaxxon_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) { if (addr >= 0x8000 && addr <= 0x9fff) { *value = roml_banks[(addr & 0x1fff) + (roml_bank << 13)]; @@ -76,14 +76,14 @@ int zaxxon_peek_mem(export_t *export, WORD addr, BYTE *value) void zaxxon_config_init(void) { - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } -void zaxxon_config_setup(BYTE *rawcart) +void zaxxon_config_setup(uint8_t *rawcart) { memcpy(roml_banks, rawcart, 0x2000); memcpy(romh_banks, &rawcart[0x2000], 0x4000); - cart_config_changed_slotmain(1, 1, CMODE_READ); + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); } static int zaxxon_common_attach(void) @@ -96,7 +96,7 @@ static int zaxxon_common_attach(void) } /* accept 20k (4k+16k) and 24k (8k+16k) binaries */ -int zaxxon_bin_attach(const char *filename, BYTE *rawcart) +int zaxxon_bin_attach(const char *filename, uint8_t *rawcart) { if (util_file_load(filename, rawcart, 0x6000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { if (util_file_load(filename, rawcart, 0x5000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { @@ -107,7 +107,7 @@ int zaxxon_bin_attach(const char *filename, BYTE *rawcart) return zaxxon_common_attach(); } -int zaxxon_crt_attach(FILE *fd, BYTE *rawcart) +int zaxxon_crt_attach(FILE *fd, uint8_t *rawcart) { crt_chip_header_t chip; int i; @@ -163,7 +163,7 @@ void zaxxon_detach(void) ARRAY | ROMH | 16384 BYTES of ROMH data */ -static char snap_module_name[] = "CARTZAXXON"; +static const char snap_module_name[] = "CARTZAXXON"; #define SNAP_MAJOR 0 #define SNAP_MINOR 0 @@ -189,7 +189,7 @@ int zaxxon_snapshot_write_module(snapshot_t *s) int zaxxon_snapshot_read_module(snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -199,7 +199,7 @@ int zaxxon_snapshot_read_module(snapshot_t *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/cart/zaxxon.h b/src/Emulators/vice/c64/cart/zaxxon.h index cf481239..72d676b9 100644 --- a/src/Emulators/vice/c64/cart/zaxxon.h +++ b/src/Emulators/vice/c64/cart/zaxxon.h @@ -34,16 +34,16 @@ struct snapshot_s; -extern BYTE zaxxon_roml_read(WORD addr); -extern int zaxxon_peek_mem(export_t *export, WORD addr, BYTE *value); +uint8_t zaxxon_roml_read(uint16_t addr); +int zaxxon_peek_mem(export_t *export, uint16_t addr, uint8_t *value); -extern void zaxxon_config_init(void); -extern void zaxxon_config_setup(BYTE *rawcart); -extern int zaxxon_bin_attach(const char *filename, BYTE *rawcart); -extern int zaxxon_crt_attach(FILE *fd, BYTE *rawcart); -extern void zaxxon_detach(void); +void zaxxon_config_init(void); +void zaxxon_config_setup(uint8_t *rawcart); +int zaxxon_bin_attach(const char *filename, uint8_t *rawcart); +int zaxxon_crt_attach(FILE *fd, uint8_t *rawcart); +void zaxxon_detach(void); -extern int zaxxon_snapshot_write_module(struct snapshot_s *s); -extern int zaxxon_snapshot_read_module(struct snapshot_s *s); +int zaxxon_snapshot_write_module(struct snapshot_s *s); +int zaxxon_snapshot_read_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/cart/zippcode48.c b/src/Emulators/vice/c64/cart/zippcode48.c new file mode 100644 index 00000000..fee74ff7 --- /dev/null +++ b/src/Emulators/vice/c64/cart/zippcode48.c @@ -0,0 +1,364 @@ +/* + * zippcode48.c - Cartridge handling, ZIPP-CODE 48 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#include "alarm.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "cartio.h" +#include "cartridge.h" +#include "zippcode48.h" +#include "export.h" +#include "maincpu.h" +#include "monitor.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" +#include "crt.h" + +/* + "ZIPP-CODE-48" + + - 8k (?) ROM mapped to $8000 in 8k game mode (needs to be confirmed) + - 9e00-9eff is also mapped to de00-deff + - IO1 reads enable the cartridge + - IO2 reads disable the cartridge +*/ + +/* #define ZIPP_USE_CAP */ + +#ifdef ZIPP_USE_CAP + +/* This constant defines the number of cycles it takes to recharge it. */ +#define ZIPP_ROM_CYCLES (63*312*100) + +struct alarm_s *zipprom_alarm; + +static CLOCK zipprom_alarm_time; + +#endif + +static int zipprom_active = 1; + +static void zippcode48_trigger_access(void) +{ +#ifdef ZIPP_USE_CAP + /* Discharge virtual capacitor, enable rom */ + alarm_unset(zipprom_alarm); + zipprom_alarm_time = maincpu_clk + ZIPP_ROM_CYCLES; + alarm_set(zipprom_alarm, zipprom_alarm_time); +#endif + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + zipprom_active = 1; +} + +#ifdef ZIPP_USE_CAP +static void zippcode48_alarm_handler(CLOCK offset, void *data) +{ + /* Virtual capacitor charged, disable rom */ + alarm_unset(zipprom_alarm); + zipprom_alarm_time = CLOCK_MAX; + cart_config_changed_slotmain(2, 2, CMODE_READ); + zipprom_active = 0; +} +#endif + +static void zippcode48_trigger_noaccess(void) +{ +#ifdef ZIPP_USE_CAP + /* Virtual capacitor charged, disable rom */ + alarm_unset(zipprom_alarm); + zipprom_alarm_time = CLOCK_MAX; +#endif + cart_config_changed_slotmain(2, 2, CMODE_READ); + zipprom_active = 0; +} + +/* ---------------------------------------------------------------------*/ + +static uint8_t zippcode48_io1_read(uint16_t addr) +{ + /* IO1 discharges the capacitor, but does nothing else */ + zippcode48_trigger_access(); + /* IO1 allows access to the second last 256 bytes of the rom */ + return roml_banks[0x1e00 + (addr & 0xff)]; +} + +static uint8_t zippcode48_io1_peek(uint16_t addr) +{ + /* IO1 allows access to the second last 256 bytes of the rom */ + return roml_banks[0x1e00 + (addr & 0xff)]; +} + +static uint8_t zippcode48_io2_read(uint16_t addr) +{ + zippcode48_trigger_noaccess(); + return 0; +} + +static uint8_t zippcode48_io2_peek(uint16_t addr) +{ + return 0; +} + +static int zippcode48_dump(void) +{ + mon_out("ROM at $8000-$9FFF: %s\n", (zipprom_active) ? "enabled" : "disabled"); + + return 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t zippcode48_io1_device = { + CARTRIDGE_NAME_ZIPPCODE48, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 1, /* read is always valid */ + NULL, /* NO store function */ + NULL, /* NO poke funtion */ + zippcode48_io1_read, /* read function */ + zippcode48_io1_peek, /* peek function */ + zippcode48_dump, /* device state information dump function */ + CARTRIDGE_ZIPPCODE48, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_t zippcode48_io2_device = { + CARTRIDGE_NAME_ZIPPCODE48, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xdf00, 0xdfff, 0xff, /* range for the device, regs:$df00-$dfff */ + 0, /* read is never valid */ + NULL, /* NO store function */ + NULL, /* NO poke function */ + zippcode48_io2_read, /* read function */ + zippcode48_io2_peek, /* peek function */ + zippcode48_dump, /* device state information dump function */ + CARTRIDGE_ZIPPCODE48, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + +static io_source_list_t *zippcode48_io1_list_item = NULL; +static io_source_list_t *zippcode48_io2_list_item = NULL; + +static const export_resource_t export_res_zipp = { + CARTRIDGE_NAME_ZIPPCODE48, 0, 1, &zippcode48_io1_device, &zippcode48_io2_device, CARTRIDGE_ZIPPCODE48 +}; + +/* ---------------------------------------------------------------------*/ + +uint8_t zippcode48_roml_read(uint16_t addr) +{ + /* ROML accesses also discharge the capacitor */ + zippcode48_trigger_access(); + + return roml_banks[(addr & 0x1fff)]; +} + +/* ---------------------------------------------------------------------*/ + +void zippcode48_reset(void) +{ + /* RESET discharges the capacitor so the rom is visible */ + zippcode48_trigger_access(); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); +} + +void zippcode48_config_init(void) +{ + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + zipprom_active = 1; +} + +void zippcode48_config_setup(uint8_t *rawcart) +{ + memcpy(roml_banks, rawcart, 0x2000); + cart_config_changed_slotmain(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ); + zipprom_active = 1; +} + +/* ---------------------------------------------------------------------*/ + +static int zippcode48_common_attach(void) +{ + if (export_add(&export_res_zipp) < 0) { + return -1; + } + +#ifdef ZIPP_USE_CAP + zipprom_alarm = alarm_new(maincpu_alarm_context, "ZIPPCartRomAlarm", zippcode48_alarm_handler, NULL); + zipprom_alarm_time = CLOCK_MAX; +#endif + zippcode48_io1_list_item = io_source_register(&zippcode48_io1_device); + zippcode48_io2_list_item = io_source_register(&zippcode48_io2_device); + + return 0; +} + +int zippcode48_bin_attach(const char *filename, uint8_t *rawcart) +{ + if (util_file_load(filename, rawcart, 0x2000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return zippcode48_common_attach(); +} + +int zippcode48_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + if (crt_read_chip_header(&chip, fd)) { + return -1; + } + + if (chip.size != 0x2000) { + return -1; + } + + if (crt_read_chip(rawcart, 0, &chip, fd)) { + return -1; + } + + return zippcode48_common_attach(); +} + +void zippcode48_detach(void) +{ +#ifdef ZIPP_USE_CAP + alarm_destroy(zipprom_alarm); +#endif + export_remove(&export_res_zipp); + io_source_unregister(zippcode48_io1_list_item); + io_source_unregister(zippcode48_io2_list_item); + zippcode48_io1_list_item = NULL; + zippcode48_io2_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +/* CARTZIPP snapshot module format: + + type | name | version | description + -------------------------------------- + BYTE | active | 0.1 | cartridge active flag + DWORD | alarm | 0.0+ | alarm time + ARRAY | ROML | 0.0+ | 8192 BYTES of ROML data + */ + +static const char snap_module_name[] = "CARTZIPP"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 1 + +int zippcode48_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)zipprom_active) < 0) +#ifdef ZIPP_USE_CAP + || (SMW_DW(m, zipprom_alarm_time) < 0) +#endif + || (SMW_BA(m, roml_banks, 0x2000) < 0)) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int zippcode48_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + +#ifdef ZIPP_USE_CAP + CLOCK temp_clk; +#endif + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + /* new in 0.1 */ + if (!snapshot_version_is_smaller(vmajor, vminor, 0, 1)) { + if (SMR_B_INT(m, &zipprom_active) < 0) { + goto fail; + } + } else { + zipprom_active = 0; + } + + if (0 +#ifdef ZIPP_USE_CAP + || (SMR_DW(m, &temp_clk) < 0) +#endif + || (SMR_BA(m, roml_banks, 0x2000) < 0)) { + goto fail; + } + + snapshot_module_close(m); + + if (zippcode48_common_attach() < 0) { + return -1; + } + +#ifdef ZIPP_USE_CAP + if (temp_clk < CLOCK_MAX) { + zipprom_alarm_time = temp_clk; + alarm_set(zipprom_alarm, zipprom_alarm_time); + } +#endif + return 0; + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/c64/cart/zippcode48.h b/src/Emulators/vice/c64/cart/zippcode48.h new file mode 100644 index 00000000..e32a913d --- /dev/null +++ b/src/Emulators/vice/c64/cart/zippcode48.h @@ -0,0 +1,49 @@ +/* + * zippcode48.h - Cartridge handling, ZIPP-CODE 48 cart. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_ZIPPCODE48_H +#define VICE_ZIPPCODE48_H + +#include + +#include "vicetypes.h" + +uint8_t zippcode48_roml_read(uint16_t addr); + +void zippcode48_reset(void); + +void zippcode48_config_init(void); +void zippcode48_config_setup(uint8_t *rawcart); +int zippcode48_bin_attach(const char *filename, uint8_t *rawcart); +int zippcode48_crt_attach(FILE *fd, uint8_t *rawcart); +void zippcode48_detach(void); + +struct snapshot_s; + +int zippcode48_snapshot_write_module(struct snapshot_s *s); +int zippcode48_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/c64/patchrom.c b/src/Emulators/vice/c64/patchrom.c index 5427708b..4f7eced2 100644 --- a/src/Emulators/vice/c64/patchrom.c +++ b/src/Emulators/vice/c64/patchrom.c @@ -46,7 +46,9 @@ #include "patchrom.h" #include "vicetypes.h" +#ifdef RETRODEBUGGER #include "ViceWrapper.h" +#endif /* RETRODEBUGGER */ /* * By an option on the x64 command line you can patch between the @@ -460,8 +462,10 @@ static const unsigned short patch_bytes[] = { 0, 00 }; +#ifdef RETRODEBUGGER void c64d_patch_kernal_fast_boot(); void c64d_un_patch_kernal_fast_boot(); +#endif /* RETRODEBUGGER */ int patch_rom_idx(int rev) { @@ -470,21 +474,24 @@ int patch_rom_idx(int rev) short bytes, n, i = 0; WORD a; +#ifdef RETRODEBUGGER c64d_un_patch_kernal_fast_boot(); +#endif /* RETRODEBUGGER */ - if (c64rom_get_kernal_chksum_id(&sum, &curr) < 0) { + if (c64rom_get_kernal_chksum_id(&sum, &curr, NULL) < 0) { /* VICE 3.10: + sha1hash out (NULL = don't want it) */ log_error(LOG_DEFAULT, "ROM not patched: Unknown Kernal image. ID: %d ($%02X) Sum: %d ($%04X).", curr, curr, sum, sum); return -1; } - log_verbose("Trying Kernal ROM patch: id:%d/sum:%d to id:%d.", curr, sum, rev); - - if (rev == curr) - { - log_verbose("ROM not patched: Already revision #%d.", curr); - if (c64d_patch_kernal_fast_boot_flag) - { - c64d_patch_kernal_fast_boot(); - } + log_verbose(LOG_DEFAULT, "Trying Kernal ROM patch: id:%d/sum:%d to id:%d.", curr, sum, rev); + + if (rev == curr) { + log_verbose(LOG_DEFAULT, "ROM not patched: Already revision #%d.", curr); +#ifdef RETRODEBUGGER + if (c64d_patch_kernal_fast_boot_flag) + { + c64d_patch_kernal_fast_boot(); + } +#endif /* RETRODEBUGGER */ return 0; } if (rev < 0) { @@ -523,7 +530,7 @@ int patch_rom_idx(int rev) while ((bytes = patch_bytes[i++]) > 0) { a = (WORD)patch_bytes[i++]; - log_verbose(" %.4X (%d byte%s)", a & 0xFFFF, bytes, ((bytes > 1) ? "s" : "")); + log_verbose(LOG_DEFAULT, " %.4X (%d byte%s)", a & 0xFFFF, bytes, ((bytes > 1) ? "s" : "")); i += (bytes * rev); /* select patch */ for (n = bytes; n--; ) { @@ -532,11 +539,13 @@ int patch_rom_idx(int rev) i += (bytes * (PATCH_VERSIONS - rev)); /* skip patch */ } - - if (c64d_patch_kernal_fast_boot_flag) - { - c64d_patch_kernal_fast_boot(); - } - + +#ifdef RETRODEBUGGER + if (c64d_patch_kernal_fast_boot_flag) + { + c64d_patch_kernal_fast_boot(); + } +#endif /* RETRODEBUGGER */ + return 0; } diff --git a/src/Emulators/vice/c64/plus256k.c b/src/Emulators/vice/c64/plus256k.c index 63852bf9..6edb1cef 100644 --- a/src/Emulators/vice/c64/plus256k.c +++ b/src/Emulators/vice/c64/plus256k.c @@ -44,7 +44,6 @@ #include "resources.h" #include "reu.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" @@ -52,9 +51,9 @@ #include "vicii-mem.h" /* PLUS256K registers */ -static BYTE plus256k_reg = 0; +static uint8_t plus256k_reg = 0; -static log_t plus256k_log = LOG_ERR; +static log_t plus256k_log = LOG_DEFAULT; static int plus256k_activate(void); static int plus256k_deactivate(void); @@ -69,16 +68,16 @@ static int plus256k_protected = 0; /* Filename of the +256K image. */ static char *plus256k_filename = NULL; -BYTE *plus256k_ram = NULL; +uint8_t *plus256k_ram = NULL; /* ------------------------------------------------------------------------- */ -static BYTE plus256k_peek(WORD addr) +static uint8_t plus256k_peek(uint16_t addr) { return plus256k_reg; } -static BYTE plus256k_ff_read(WORD addr) +static uint8_t plus256k_ff_read(uint16_t addr) { return 0xff; } @@ -92,7 +91,7 @@ static int plus256k_dump(void) return 0; } -static void plus256k_vicii_store(WORD addr, BYTE value) +static void plus256k_vicii_store(uint16_t addr, uint8_t value) { int new_bank; @@ -109,34 +108,39 @@ static void plus256k_vicii_store(WORD addr, BYTE value) } } +/* When the +256K device is active, this device is used instead of the default VICII device */ static io_source_t vicii_d000_device = { - "VIC-II", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd000, 0xd0ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - 1, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II", /* name of the device */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd000, 0xd0ff, 0x3f, /* range for the device, regs:$d000-$d03f, mirrors:$d040-$d0ff */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* device state information dump function */ + 0, /* dummy (not a cartridge) */ + IO_PRIO_HIGH, /* high priority, device is never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t vicii_d100_device = { - "+256K", - IO_DETACH_RESOURCE, - "PLUS256K", - 0xd100, 0xd1ff, 1, - 1, /* read is always valid */ - plus256k_vicii_store, - plus256k_ff_read, - plus256k_peek, - plus256k_dump, - CARTRIDGE_PLUS256K, - 0, - 0 + "+256K", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "PLUS256K", /* resource to set to '0' */ + 0xd100, 0xd1ff, 0x00, /* range for the device, address is ignored, reg:$d100, mirrors:$d101-$d1ff */ + 1, /* read is always valid */ + plus256k_vicii_store, /* store function */ + NULL, /* NO poke function */ + plus256k_ff_read, /* read function */ + plus256k_peek, /* peek function */ + plus256k_dump, /* device state information dump function */ + CARTRIDGE_PLUS256K, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *vicii_d000_list_item = NULL; @@ -155,7 +159,7 @@ int set_plus256k_enabled(int value, int disable_reset) return -1; } if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } plus256k_enabled = 0; return 0; @@ -164,7 +168,7 @@ int set_plus256k_enabled(int value, int disable_reset) return -1; } if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } plus256k_enabled = 1; return 0; @@ -214,11 +218,9 @@ void plus256k_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-plus256kimage", SET_RESOURCE, 1, + { "-plus256kimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "PLUS256Kfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_PLUS256K_NAME, - NULL, NULL }, + "", "Specify name of PLUS256K image" }, CMDLINE_LIST_END }; @@ -293,7 +295,7 @@ static int plus256k_deactivate(void) io_source_unregister(vicii_d100_list_item); vicii_d100_list_item = NULL; } - c64io_vicii_init(); + c64io_vicii_reinit(); return 0; } @@ -306,12 +308,12 @@ void plus256k_shutdown(void) /* ------------------------------------------------------------------------- */ -void plus256k_ram_low_store(WORD addr, BYTE value) +void plus256k_ram_low_store(uint16_t addr, uint8_t value) { plus256k_ram[(plus256k_low_bank << 16) + addr] = value; } -void plus256k_ram_high_store(WORD addr, BYTE value) +void plus256k_ram_high_store(uint16_t addr, uint8_t value) { plus256k_ram[(plus256k_high_bank << 16) + addr] = value; if (addr == 0xff00) { @@ -319,12 +321,21 @@ void plus256k_ram_high_store(WORD addr, BYTE value) } } -BYTE plus256k_ram_low_read(WORD addr) +void plus256k_ram_inject(uint16_t addr, uint8_t value) +{ + if (addr < 0x1000) { + plus256k_ram_low_store(addr, value); + } else { + plus256k_ram_high_store(addr, value); + } +} + +uint8_t plus256k_ram_low_read(uint16_t addr) { return plus256k_ram[(plus256k_low_bank << 16) + addr]; } -BYTE plus256k_ram_high_read(WORD addr) +uint8_t plus256k_ram_high_read(uint16_t addr) { return plus256k_ram[(plus256k_high_bank * 0x10000) + addr]; } @@ -361,10 +372,10 @@ int plus256k_snapshot_write(struct snapshot_s *s) if (0 || SMW_B (m, plus256k_reg) < 0 - || SMW_B (m, (BYTE)plus256k_video_bank) < 0 - || SMW_B (m, (BYTE)plus256k_low_bank) < 0 - || SMW_B (m, (BYTE)plus256k_high_bank) < 0 - || SMW_B (m, (BYTE)plus256k_protected) < 0 + || SMW_B (m, (uint8_t)plus256k_video_bank) < 0 + || SMW_B (m, (uint8_t)plus256k_low_bank) < 0 + || SMW_B (m, (uint8_t)plus256k_high_bank) < 0 + || SMW_B (m, (uint8_t)plus256k_protected) < 0 || SMW_BA(m, plus256k_ram, 0x40000) < 0) { snapshot_module_close(m); return -1; @@ -376,7 +387,7 @@ int plus256k_snapshot_write(struct snapshot_s *s) int plus256k_snapshot_read(struct snapshot_s *s) { snapshot_module_t *m; - BYTE vmajor, vminor; + uint8_t vmajor, vminor; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -385,7 +396,7 @@ int plus256k_snapshot_read(struct snapshot_s *s) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } @@ -405,7 +416,7 @@ int plus256k_snapshot_read(struct snapshot_s *s) } return snapshot_module_close(m); - + fail: if (m != NULL) { snapshot_module_close(m); diff --git a/src/Emulators/vice/c64/plus256k.h b/src/Emulators/vice/c64/plus256k.h index f969453a..957681af 100644 --- a/src/Emulators/vice/c64/plus256k.h +++ b/src/Emulators/vice/c64/plus256k.h @@ -32,21 +32,22 @@ extern int plus256k_enabled; -extern int plus256k_resources_init(void); -extern void plus256k_resources_shutdown(void); -extern int plus256k_cmdline_options_init(void); -extern void plus256k_init(void); -extern void plus256k_reset(void); -extern void plus256k_shutdown(void); - -extern void plus256k_ram_low_store(WORD addr, BYTE value); -extern void plus256k_ram_high_store(WORD addr, BYTE value); -extern BYTE plus256k_ram_low_read(WORD addr); -extern BYTE plus256k_ram_high_read(WORD addr); - -extern int set_plus256k_enabled(int value, int disable_reset); - -extern int plus256k_snapshot_write(struct snapshot_s *s); -extern int plus256k_snapshot_read(struct snapshot_s *s); +int plus256k_resources_init(void); +void plus256k_resources_shutdown(void); +int plus256k_cmdline_options_init(void); +void plus256k_init(void); +void plus256k_reset(void); +void plus256k_shutdown(void); + +void plus256k_ram_inject(uint16_t addr, uint8_t value); +void plus256k_ram_low_store(uint16_t addr, uint8_t value); +void plus256k_ram_high_store(uint16_t addr, uint8_t value); +uint8_t plus256k_ram_low_read(uint16_t addr); +uint8_t plus256k_ram_high_read(uint16_t addr); + +int set_plus256k_enabled(int value, int disable_reset); + +int plus256k_snapshot_write(struct snapshot_s *s); +int plus256k_snapshot_read(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/plus60k.c b/src/Emulators/vice/c64/plus60k.c index 8ad41a5b..a98e34af 100644 --- a/src/Emulators/vice/c64/plus60k.c +++ b/src/Emulators/vice/c64/plus60k.c @@ -91,7 +91,6 @@ #include "resources.h" #include "plus60k.h" #include "snapshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" @@ -99,9 +98,9 @@ #include "vicii-mem.h" /* PLUS60K registers */ -static BYTE plus60k_reg = 0; +static uint8_t plus60k_reg = 0; -static log_t plus60k_log = LOG_ERR; +static log_t plus60k_log = LOG_DEFAULT; static int plus60k_activate(void); static int plus60k_deactivate(void); @@ -113,7 +112,7 @@ int plus60k_base = 0xd100; /* Filename of the +60K image. */ static char *plus60k_filename = NULL; -static BYTE *plus60k_ram; +static uint8_t *plus60k_ram; static int plus60k_dump(void) { @@ -121,79 +120,89 @@ static int plus60k_dump(void) return 0; } -static BYTE plus60k_ff_read(WORD addr) +static uint8_t plus60k_ff_read(uint16_t addr) { return 0xff; } -static BYTE plus60k_peek(WORD addr) +static uint8_t plus60k_peek(uint16_t addr) { return plus60k_reg << 7; } -static void plus60k_vicii_store(WORD addr, BYTE value) +static void plus60k_vicii_store(uint16_t addr, uint8_t value) { plus60k_reg = (value & 0x80) >> 7; } +/* When the +60K device is active and the device base is at $d040, this device is used instead of the default VICII device */ static io_source_t vicii_d000_device = { - "VIC-II", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd000, 0xd03f, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II", /* name of the device */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd000, 0xd03f, 0x3f, /* range for the device, regs:$d000-$d03f */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* device state information dump function */ + 0, /* dummy (not a cartridge) */ + IO_PRIO_HIGH, /* high priority, device is never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; +/* When the +60K device is active and the device base is at $d100, this device is used instead of the default VICII device */ static io_source_t vicii_d000_full_device = { - "VIC-II", - IO_DETACH_CART, /* dummy */ - NULL, /* dummy */ - 0xd000, 0xd0ff, 0x3f, - 1, /* read is always valid */ - vicii_store, - vicii_read, - vicii_peek, - vicii_dump, - 0, /* dummy (not a cartridge) */ - IO_PRIO_HIGH, /* priority, device and mirrors never involved in collisions */ - 0 + "VIC-II", /* name of the device */ + IO_DETACH_NEVER, /* chip is never involved in collisions, so no detach */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xd000, 0xd0ff, 0x3f, /* range for the device, regs:$d000-$d03f, mirrors:$d040-$d0ff */ + 1, /* read is always valid */ + vicii_store, /* store function */ + NULL, /* NO poke function */ + vicii_read, /* read function */ + vicii_peek, /* peek function */ + vicii_dump, /* device state information dump function */ + 0, /* dummy (not a cartridge) */ + IO_PRIO_HIGH, /* high priority, device and mirrors are never involved in collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t vicii_d040_device = { - "+60K", - IO_DETACH_RESOURCE, - "PLUS60K", - 0xd040, 0xd0ff, 1, - 1, /* read is always valid */ - plus60k_vicii_store, - plus60k_ff_read, - plus60k_peek, - plus60k_dump, - CARTRIDGE_PLUS60K, - IO_PRIO_NORMAL, - 0 + "+60K", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "PLUS60K", /* resource to set to '0' */ + 0xd040, 0xd0ff, 0x00, /* range for the device, address is ignored, reg:$d040, mirrors:$d041-$d0ff */ + 1, /* read is always valid */ + plus60k_vicii_store, /* store function */ + NULL, /* NO poke function */ + plus60k_ff_read, /* read function */ + plus60k_peek, /* peek function */ + plus60k_dump, /* device state information dump function */ + CARTRIDGE_PLUS60K, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_t vicii_d100_device = { - "+60K", - IO_DETACH_RESOURCE, - "PLUS60K", - 0xd100, 0xd1ff, 1, - 1, /* read is always valid */ - plus60k_vicii_store, - plus60k_ff_read, - plus60k_peek, - plus60k_dump, - CARTRIDGE_PLUS60K, - IO_PRIO_NORMAL, - 0 + "+60K", /* name of the device */ + IO_DETACH_RESOURCE, /* use resource to detach the device when involved in a read-collision */ + "PLUS60K", /* resource to set to '0' */ + 0xd100, 0xd1ff, 0x00, /* range for the device, address is ignored, reg:$d100, mirrors:$d101-$d1ff */ + 1, /* read is always valid */ + plus60k_vicii_store, /* store function */ + NULL, /* NO poke function */ + plus60k_ff_read, /* read function */ + plus60k_peek, /* peek function */ + plus60k_dump, /* device state information dump function */ + CARTRIDGE_PLUS60K, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ }; static io_source_list_t *vicii_d000_list_item = NULL; @@ -215,7 +224,7 @@ int set_plus60k_enabled(int value, int disable_reset) } if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } plus60k_enabled = 0; return 0; @@ -225,7 +234,7 @@ int set_plus60k_enabled(int value, int disable_reset) } plus60k_enabled = 1; if (!disable_reset) { - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); } return 0; } @@ -265,7 +274,8 @@ static int set_plus60k_base(int val, void *param) case 0xd100: break; default: - log_message(plus60k_log, "Unknown PLUS60K base address $%X.", val); + log_message(plus60k_log, "Unknown PLUS60K base address $%X.", + (unsigned int)val); return -1; } @@ -310,16 +320,12 @@ void plus60k_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { - { "-plus60kimage", SET_RESOURCE, 1, + { "-plus60kimage", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "PLUS60Kfilename", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_PLUS60K_NAME, - NULL, NULL }, - { "-plus60kbase", SET_RESOURCE, 1, + "", "Specify name of PLUS60K image" }, + { "-plus60kbase", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "PLUS60Kbase", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_BASE_ADDRESS, IDCLS_PLUS60K_BASE, - NULL, NULL }, + "", "Base address of the PLUS60K expansion. (0xD040/0xD100)" }, CMDLINE_LIST_END }; @@ -403,7 +409,7 @@ static int plus60k_deactivate(void) io_source_unregister(vicii_d100_list_item); vicii_d100_list_item = NULL; } - c64io_vicii_init(); + c64io_vicii_reinit(); return 0; } @@ -417,27 +423,27 @@ void plus60k_shutdown(void) /* ------------------------------------------------------------------------- */ -static void plus60k_memory_store(WORD addr, BYTE value) +static void plus60k_memory_store(uint16_t addr, uint8_t value) { plus60k_ram[addr - 0x1000] = value; } -static void vicii_mem_vbank_store_wrapper(WORD addr, BYTE value) +static void vicii_mem_vbank_store_wrapper(uint16_t addr, uint8_t value) { vicii_mem_vbank_store(addr, value); } -static void vicii_mem_vbank_39xx_store_wrapper(WORD addr, BYTE value) +static void vicii_mem_vbank_39xx_store_wrapper(uint16_t addr, uint8_t value) { vicii_mem_vbank_39xx_store(addr, value); } -static void vicii_mem_vbank_3fxx_store_wrapper(WORD addr, BYTE value) +static void vicii_mem_vbank_3fxx_store_wrapper(uint16_t addr, uint8_t value) { vicii_mem_vbank_3fxx_store(addr, value); } -static void ram_hi_store_wrapper(WORD addr, BYTE value) +static void ram_hi_store_wrapper(uint16_t addr, uint8_t value) { ram_hi_store(addr, value); } @@ -453,27 +459,27 @@ static store_func_ptr_t plus60k_mem_write_tab[] = { plus60k_memory_store }; -void plus60k_vicii_mem_vbank_store(WORD addr, BYTE value) +void plus60k_vicii_mem_vbank_store(uint16_t addr, uint8_t value) { plus60k_mem_write_tab[plus60k_reg](addr, value); } -void plus60k_vicii_mem_vbank_39xx_store(WORD addr, BYTE value) +void plus60k_vicii_mem_vbank_39xx_store(uint16_t addr, uint8_t value) { plus60k_mem_write_tab[plus60k_reg + 2](addr, value); } -void plus60k_vicii_mem_vbank_3fxx_store(WORD addr, BYTE value) +void plus60k_vicii_mem_vbank_3fxx_store(uint16_t addr, uint8_t value) { plus60k_mem_write_tab[plus60k_reg + 4](addr, value); } -void plus60k_ram_hi_store(WORD addr, BYTE value) +void plus60k_ram_hi_store(uint16_t addr, uint8_t value) { plus60k_mem_write_tab[plus60k_reg + 6](addr, value); } -BYTE plus60k_ram_read(WORD addr) +uint8_t plus60k_ram_read(uint16_t addr) { if (plus60k_enabled && addr >= 0x1000 && plus60k_reg == 1) { return plus60k_ram[addr - 0x1000]; @@ -482,7 +488,7 @@ BYTE plus60k_ram_read(WORD addr) } } -void plus60k_ram_store(WORD addr, BYTE value) +void plus60k_ram_store(uint16_t addr, uint8_t value) { if (plus60k_enabled && addr >= 0x1000 && plus60k_reg == 1) { plus60k_ram[addr - 0x1000] = value; @@ -491,6 +497,11 @@ void plus60k_ram_store(WORD addr, BYTE value) } } +void plus60k_ram_inject(uint16_t addr, uint8_t value) +{ + plus60k_ram_store(addr, value); +} + /* ------------------------------------------------------------------------- */ /* PLUS60K snapshot module format: @@ -519,7 +530,7 @@ int plus60k_snapshot_write(struct snapshot_s *s) } if (0 - || SMW_W (m, (WORD)plus60k_base) < 0 + || SMW_W (m, (uint16_t)plus60k_base) < 0 || SMW_B (m, plus60k_reg) < 0 || SMW_BA(m, plus60k_ram, 0xf000) < 0) { snapshot_module_close(m); @@ -532,7 +543,7 @@ int plus60k_snapshot_write(struct snapshot_s *s) int plus60k_snapshot_read(struct snapshot_s *s) { snapshot_module_t *m; - BYTE vmajor, vminor; + uint8_t vmajor, vminor; m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); @@ -541,7 +552,7 @@ int plus60k_snapshot_read(struct snapshot_s *s) } /* Do not accept versions higher than current */ - if ((vmajor != SNAP_MAJOR) || (vminor != SNAP_MINOR)) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } diff --git a/src/Emulators/vice/c64/plus60k.h b/src/Emulators/vice/c64/plus60k.h index 405d1f33..321f1b7e 100644 --- a/src/Emulators/vice/c64/plus60k.h +++ b/src/Emulators/vice/c64/plus60k.h @@ -31,23 +31,25 @@ extern int plus60k_enabled; extern int plus60k_base; -extern int plus60k_resources_init(void); -extern void plus60k_resources_shutdown(void); -extern int plus60k_cmdline_options_init(void); -extern void plus60k_init(void); -extern void plus60k_reset(void); -extern void plus60k_shutdown(void); - -extern void plus60k_vicii_mem_vbank_store(WORD addr, BYTE value); -extern void plus60k_vicii_mem_vbank_39xx_store(WORD addr, BYTE value); -extern void plus60k_vicii_mem_vbank_3fxx_store(WORD addr, BYTE value); -extern void plus60k_ram_hi_store(WORD addr, BYTE value); -extern BYTE plus60k_ram_read(WORD addr); -extern void plus60k_ram_store(WORD addr, BYTE value); - -extern int set_plus60k_enabled(int value, int disable_reset); - -extern int plus60k_snapshot_write(struct snapshot_s *s); -extern int plus60k_snapshot_read(struct snapshot_s *s); + +int plus60k_resources_init(void); +void plus60k_resources_shutdown(void); +int plus60k_cmdline_options_init(void); +void plus60k_init(void); +void plus60k_reset(void); +void plus60k_shutdown(void); + +void plus60k_ram_inject(uint16_t addr, uint8_t value); +void plus60k_vicii_mem_vbank_store(uint16_t addr, uint8_t value); +void plus60k_vicii_mem_vbank_39xx_store(uint16_t addr, uint8_t value); +void plus60k_vicii_mem_vbank_3fxx_store(uint16_t addr, uint8_t value); +void plus60k_ram_hi_store(uint16_t addr, uint8_t value); +uint8_t plus60k_ram_read(uint16_t addr); +void plus60k_ram_store(uint16_t addr, uint8_t value); + +int set_plus60k_enabled(int value, int disable_reset); + +int plus60k_snapshot_write(struct snapshot_s *s); +int plus60k_snapshot_read(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/c64/psid.c b/src/Emulators/vice/c64/psid.c index fc79f0fc..dae38c5b 100644 --- a/src/Emulators/vice/c64/psid.c +++ b/src/Emulators/vice/c64/psid.c @@ -39,10 +39,8 @@ #include "lib.h" #include "log.h" #include "machine.h" -#include "patchrom.h" #include "psid.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "vsidui.h" @@ -51,39 +49,38 @@ static int mus_load_file(const char* filename, int ispsid); -static log_t vlog = LOG_ERR; +static log_t vlog = LOG_DEFAULT; typedef struct psid_s { /* PSID data */ - BYTE is_rsid; - WORD version; - WORD data_offset; - WORD load_addr; - WORD init_addr; - WORD play_addr; - WORD songs; - WORD start_song; - DWORD speed; + uint8_t is_rsid; + uint16_t version; + uint16_t data_offset; + uint16_t load_addr; + uint16_t init_addr; + uint16_t play_addr; + uint16_t songs; + uint16_t start_song; + uint32_t speed; /* psid v3 allows all 32 bytes to be used with no zero termination */ - BYTE name[32 + 1]; - BYTE author[32 + 1]; - BYTE copyright[32 + 1]; - WORD flags; - BYTE start_page; - BYTE max_pages; - WORD reserved; - WORD data_size; - BYTE data[65536]; + uint8_t name[32 + 1]; + uint8_t author[32 + 1]; + uint8_t copyright[32 + 1]; + uint16_t flags; + uint8_t start_page; + uint8_t max_pages; + uint16_t reserved; + uint16_t data_size; + uint8_t data[65536]; /* Non-PSID data */ - DWORD frames_played; - WORD load_last_addr; + uint32_t frames_played; + uint16_t load_last_addr; } psid_t; #define PSID_V1_DATA_OFFSET 0x76 #define PSID_V2_DATA_OFFSET 0x7c -int psid_ui_set_tune(int tune, void *param); static psid_t* psid = NULL; static int psid_tune = 0; /* currently selected tune, 0: default 1: first, 2: second, etc */ @@ -92,27 +89,29 @@ static int keepenv = 0; static int firstfile = 0; static int psid_tune_cmdline = 0; - struct kernal_s { const char *name; int rev; }; +/* NOTE: this table is duplicated in c64-cmdline-options.c */ static struct kernal_s kernal_match[] = { - { "1", C64_KERNAL_REV1 }, - { "2", C64_KERNAL_REV2 }, - { "3", C64_KERNAL_REV3 }, - { "67", C64_KERNAL_SX64 }, - { "sx", C64_KERNAL_SX64 }, - { "100", C64_KERNAL_4064 }, + { "0", C64_KERNAL_JAP }, + { "jap", C64_KERNAL_JAP }, + { "1", C64_KERNAL_REV1 }, + { "2", C64_KERNAL_REV2 }, + { "3", C64_KERNAL_REV3 }, + { "67", C64_KERNAL_SX64 }, + { "sx", C64_KERNAL_SX64 }, + { "39", C64_KERNAL_GS64 }, + { "gs", C64_KERNAL_GS64 }, + { "100", C64_KERNAL_4064 }, { "4064", C64_KERNAL_4064 }, { NULL, C64_KERNAL_UNKNOWN } }; static int set_kernal_revision(const char *param, void *extra_param) { - WORD sum; /* ROM checksum */ - int id; /* ROM identification number */ int rev = C64_KERNAL_UNKNOWN; int i = 0; @@ -127,25 +126,20 @@ static int set_kernal_revision(const char *param, void *extra_param) i++; } while ((rev == C64_KERNAL_UNKNOWN) && (kernal_match[i].name != NULL)); - if(!c64rom_isloaded()) { - kernal_revision = rev; - return 0; + log_verbose(LOG_DEFAULT, "set_kernal_revision (\"-kernalrev\") val:'%s' rev: %d", param, rev); + + if (rev == C64_KERNAL_UNKNOWN) { + log_error(LOG_DEFAULT, "invalid kernal revision (%d)", rev); + return -1; } - if (c64rom_get_kernal_chksum_id(&sum, &id) < 0) { - id = C64_KERNAL_UNKNOWN; - kernal_revision = id; - } else { - if (patch_rom_idx(rev) >= 0) { - kernal_revision = rev; - } else { - kernal_revision = id; - } + if (resources_set_int("KernalRev", rev) < 0) { + log_error(LOG_DEFAULT, "failed to set kernal revision (%d)", rev); } + return 0; } - static int set_keepenv(int val, void *param) { keepenv = val ? 1 : 0; @@ -183,56 +177,37 @@ static int cmdline_psid_tune(const char *param, void *extra_param) static const cmdline_option_t cmdline_options[] = { /* The Video Standard options are copied from the machine files. */ - { "-pal", SET_RESOURCE, 0, + { "-pal", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MachineVideoStandard", (resource_value_t)MACHINE_SYNC_PAL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_PAL_SYNC_FACTOR, - NULL, NULL }, - { "-ntsc", SET_RESOURCE, 0, + NULL, "Use PAL sync factor" }, + { "-ntsc", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MachineVideoStandard", (resource_value_t)MACHINE_SYNC_NTSC, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_NTSC_SYNC_FACTOR, - NULL, NULL }, - { "-ntscold", SET_RESOURCE, 0, + NULL, "Use NTSC sync factor" }, + { "-ntscold", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MachineVideoStandard", (resource_value_t)MACHINE_SYNC_NTSCOLD, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_OLD_NTSC_SYNC_FACTOR, - NULL, NULL }, - { "-paln", SET_RESOURCE, 0, + NULL, "Use old NTSC sync factor" }, + { "-paln", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "MachineVideoStandard", (resource_value_t)MACHINE_SYNC_PALN, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_USE_PALN_SYNC_FACTOR, - NULL, NULL }, - { "-keepenv", CALL_FUNCTION, 0, + NULL, "Use PAL-N sync factor" }, + { "-keepenv", CALL_FUNCTION, CMDLINE_ATTRIB_NONE, cmdline_keepenv, NULL, NULL, NULL, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_OVERWRITE_PSID_SETTINGS, - NULL, NULL }, - { "-tune", CALL_FUNCTION, 1, + NULL, "Override PSID settings for Video standard and SID model" }, + { "-tune", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cmdline_psid_tune, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NUMBER, IDCLS_SPECIFY_PSID_TUNE_NUMBER, - NULL, NULL }, - { "-kernal", SET_RESOURCE, 1, + "", "Specify PSID tune " }, + { "-kernal", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KernalName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_KERNAL_ROM_NAME, - NULL, NULL }, - { "-basic", SET_RESOURCE, 1, + "", "Specify name of Kernal ROM image" }, + { "-basic", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "BasicName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_BASIC_ROM_NAME, - NULL, NULL }, - { "-chargen", SET_RESOURCE, 1, + "", "Specify name of BASIC ROM image" }, + { "-chargen", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "ChargenName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_CHARGEN_ROM_NAME, - NULL, NULL }, - { "-kernalrev", CALL_FUNCTION, 1, + "", "Specify name of character generator ROM image" }, + { "-kernalrev", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, set_kernal_revision, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_REVISION, IDCLS_PATCH_KERNAL_TO_REVISION, - NULL, NULL }, + "", "Patch the Kernal ROM to the specified " + "(0/jap: japanese 1: rev. 1, 2: rev. 2, 3: rev. 3, 39/gs: C64 GS, 67/sx: sx64, 100/4064: 4064)" }, CMDLINE_LIST_END }; @@ -241,9 +216,9 @@ int psid_cmdline_options_init(void) return cmdline_register_options(cmdline_options); } -static WORD psid_extract_word(BYTE** buf) +static uint16_t psid_extract_word(uint8_t **buf) { - WORD word = (*buf)[0] << 8 | (*buf)[1]; + uint16_t word = (*buf)[0] << 8 | (*buf)[1]; *buf += 2; return word; } @@ -251,8 +226,8 @@ static WORD psid_extract_word(BYTE** buf) int psid_load_file(const char* filename) { FILE* f; - BYTE buf[PSID_V2_DATA_OFFSET + 2]; - BYTE* ptr = buf; + uint8_t buf[PSID_V2_DATA_OFFSET + 2]; + uint8_t *ptr = buf; unsigned int length; /* HACK: the selected tune number is handled by the "PSIDtune" resource, which @@ -270,7 +245,7 @@ int psid_load_file(const char* filename) firstfile = 1; } - if (vlog == LOG_ERR) { + if (vlog == LOG_DEFAULT) { vlog = log_open("Vsid"); } @@ -337,6 +312,9 @@ int psid_load_file(const char* filename) psid->start_song = 1; } + vsid_ui_display_nr_of_tunes(psid->songs); + vsid_ui_set_default_tune(psid->start_song); + /* Check for SIDPLAYER MUS files. */ if (psid->flags & 0x01) { zfile_fclose(f); @@ -359,7 +337,7 @@ int psid_load_file(const char* filename) } /* Read binary C64 data. */ - psid->data_size = (WORD)fread(psid->data, 1, sizeof(psid->data), f); + psid->data_size = (uint16_t)fread(psid->data, 1, sizeof(psid->data), f); psid->load_last_addr = (psid->load_addr + psid->data_size - 1); if (ferror(f)) { @@ -368,7 +346,7 @@ int psid_load_file(const char* filename) } if (!feof(f)) { - log_error(vlog, "More than 64K PSID data."); + log_error(vlog, "More than 64KiB PSID data."); goto fail; } @@ -457,19 +435,19 @@ void psid_shutdown(void) /* Use CBM80 vector to start PSID driver. This is a simple method to transfer control to the PSID driver while running in a pure C64 environment. */ -static int psid_set_cbm80(WORD vec, WORD addr) +static int psid_set_cbm80(uint16_t vec, uint16_t addr) { unsigned int i; - BYTE cbm80[] = { 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc2, 0xcd, 0x38, 0x30 }; + uint8_t cbm80[] = { 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc2, 0xcd, 0x38, 0x30 }; cbm80[0] = vec & 0xff; cbm80[1] = vec >> 8; for (i = 0; i < sizeof(cbm80); i++) { /* make backup of original content at 0x8000 */ - ram_store((WORD)(addr + i), ram_read((WORD)(0x8000 + i))); + ram_store((uint16_t)(addr + i), ram_read((uint16_t)(0x8000 + i))); /* copy header */ - ram_store((WORD)(0x8000 + i), cbm80[i]); + ram_store((uint16_t)(0x8000 + i), cbm80[i]); } return i; @@ -480,8 +458,8 @@ void psid_init_tune(int install_driver_hook) int start_song = psid_tune; int sync, sid_model; int i; - WORD reloc_addr; - WORD addr; + uint16_t reloc_addr; + uint16_t addr; int speedbit; char* irq; char irq_str[20]; @@ -495,7 +473,10 @@ void psid_init_tune(int install_driver_hook) reloc_addr = psid->start_page << 8; - log_message(vlog, "Driver=$%04X, Image=$%04X-$%04X, Init=$%04X, Play=$%04X", reloc_addr, psid->load_addr, psid->load_addr + psid->data_size - 1, psid->init_addr, psid->play_addr); + log_message(vlog, "Driver=$%04X, Image=$%04X-$%04X, Init=$%04X, Play=$%04X", + reloc_addr, psid->load_addr, + (unsigned int)(psid->load_addr + psid->data_size - 1), + psid->init_addr, psid->play_addr); /* PAL/NTSC. */ resources_get_int("MachineVideoStandard", &sync); @@ -543,22 +524,29 @@ void psid_init_tune(int install_driver_hook) } else { // if (machine_class == VICE_MACHINE_VSID) { // char * driver_info_text; -// driver_info_text = lib_msprintf("Driver=$%04X, Image=$%04X-$%04X, Init=$%04X, Play=$%04X", reloc_addr, psid->load_addr, -// psid->load_addr + psid->data_size - 1, psid->init_addr, psid->play_addr); +// driver_info_text = lib_msprintf("Driver=$%04X, Image=$%04X-$%04X, Init=$%04X, Play=$%04X", +// reloc_addr, psid->load_addr, +// psid->load_addr + psid->data_size - 1U, +// psid->init_addr, psid->play_addr); // vsid_ui_setdrv(driver_info_text); // lib_free(driver_info_text); -// } -// vsid_ui_display_name((char *)(psid->name)); -// vsid_ui_display_author((char *)(psid->author)); -// vsid_ui_display_copyright((char *)(psid->copyright)); // -// vsid_ui_display_sync(sync); -// vsid_ui_display_sid_model(sid_model); -// vsid_ui_display_irqtype(irq_str); -// vsid_ui_display_tune_nr(start_song); -// vsid_ui_set_default_tune(psid->start_song); -// vsid_ui_display_nr_of_tunes(psid->songs); -// vsid_ui_display_time(0); +// vsid_ui_set_driver_addr(reloc_addr); +// vsid_ui_set_load_addr(psid->load_addr); +// vsid_ui_set_init_addr(psid->init_addr); +// vsid_ui_set_play_addr(psid->play_addr); +// vsid_ui_set_data_size(psid->data_size); +// vsid_ui_set_default_tune(psid->start_song); +// vsid_ui_display_name((char *)(psid->name)); +// vsid_ui_display_author((char *)(psid->author)); +// vsid_ui_display_copyright((char *)(psid->copyright)); +// vsid_ui_display_sync(sync); +// vsid_ui_display_sid_model(sid_model); +// vsid_ui_display_irqtype(irq_str); +// vsid_ui_display_nr_of_tunes(psid->songs); +// vsid_ui_display_tune_nr(start_song); +// vsid_ui_display_time(0); +// } } /* Store parameters for PSID player. */ @@ -567,20 +555,21 @@ void psid_init_tune(int install_driver_hook) addr = reloc_addr + 3 + 9; /* CBM80 reset vector. */ - addr += psid_set_cbm80((WORD)(reloc_addr + 9), addr); + addr += psid_set_cbm80((uint16_t)(reloc_addr + 9), addr); - ram_store(addr, (BYTE)(start_song)); + ram_store(addr, (uint8_t)(start_song)); } /* put song number into address 780/1/2 (A/X/Y) for use by BASIC tunes */ - ram_store(780, (BYTE)(start_song - 1)); - ram_store(781, (BYTE)(start_song - 1)); - ram_store(782, (BYTE)(start_song - 1)); + ram_store(780, (uint8_t)(start_song - 1)); + ram_store(781, (uint8_t)(start_song - 1)); + ram_store(782, (uint8_t)(start_song - 1)); /* force flag in c64 memory, many sids reads it and must be set AFTER the sid flag is read */ - ram_store((WORD)(0x02a6), (BYTE)(sync == MACHINE_SYNC_NTSC ? 0 : 1)); + ram_store((uint16_t)(0x02a6), (uint8_t)(sync == MACHINE_SYNC_NTSC ? 0 : 1)); } -int psid_basic_rsid_to_autostart(WORD *address, BYTE **data, WORD *length) { +int psid_basic_rsid_to_autostart(uint16_t *address, uint8_t **data, uint16_t *length) +{ if (psid && psid->is_rsid && psid->flags & 0x02) { *address = psid->load_addr; *data = psid->data; @@ -605,11 +594,11 @@ void psid_set_tune(int tune) /* used for setting the PSIDtune resource */ int psid_ui_set_tune(int tune, void *param) { - psid_tune = (int)(tune == -1) ? 0 : (int)tune; + psid_tune = (tune == -1) ? 0 : tune; psid_set_tune(psid_tune); vsync_suspend_speed_eval(); - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); return 0; } @@ -623,14 +612,14 @@ int psid_tunes(int* default_tune) void psid_init_driver(void) { - BYTE psid_driver[] = { + uint8_t psid_driver[] = { #include "psiddrv.h" }; char *psid_reloc = (char *)psid_driver; int psid_size; - WORD reloc_addr; - WORD addr; + uint16_t reloc_addr; + uint16_t addr; int i; int sync; int sid2loc, sid3loc; @@ -663,19 +652,19 @@ void psid_init_driver(void) resources_set_int("SidStereo", 0); if (psid->version >= 3) { sid2loc = 0xd000 | ((psid->reserved >> 4) & 0x0ff0); - log_message(vlog, "2nd SID at $%04x", sid2loc); + log_message(vlog, "2nd SID at $%04x", (unsigned int)sid2loc); if (((sid2loc >= 0xd420 && sid2loc < 0xd800) || sid2loc >= 0xde00) && (sid2loc & 0x10) == 0) { resources_set_int("SidStereo", 1); - resources_set_int("SidStereoAddressStart", sid2loc); + resources_set_int("Sid2AddressStart", sid2loc); } sid3loc = 0xd000 | ((psid->reserved << 4) & 0x0ff0); if (sid3loc != 0xd000) { - log_message(vlog, "3rd SID at $%04x", sid3loc); + log_message(vlog, "3rd SID at $%04x", (unsigned int)sid3loc); if (((sid3loc >= 0xd420 && sid3loc < 0xd800) || sid3loc >= 0xde00) && (sid3loc & 0x10) == 0) { resources_set_int("SidStereo", 2); - resources_set_int("SidTripleAddressStart", sid3loc); + resources_set_int("Sid3AddressStart", sid3loc); } } } @@ -699,13 +688,14 @@ void psid_init_driver(void) /* Clear low memory to minimize the damage of PSIDs doing bad reads. */ for (addr = 0; addr < 0x0800; addr++) { - ram_store(addr, (BYTE)0x00); + ram_store(addr, (uint8_t)0x00); } /* Relocation of C64 PSID driver code. */ reloc_addr = psid->start_page << 8; psid_size = sizeof(psid_driver); - log_message(vlog, "PSID free pages: $%04x-$%04x", reloc_addr, (reloc_addr + (psid->max_pages << 8)) -1); + log_message(vlog, "PSID free pages: $%04x-$%04x", + reloc_addr, (reloc_addr + (psid->max_pages << 8)) - 1U); if (!reloc65((char **)&psid_reloc, &psid_size, reloc_addr)) { log_error(vlog, "Relocation."); @@ -714,33 +704,33 @@ void psid_init_driver(void) } for (i = 0; i < psid_size; i++) { - ram_store((WORD)(reloc_addr + i), psid_reloc[i]); + ram_store((uint16_t)(reloc_addr + i), psid_reloc[i]); } /* Store binary C64 data. */ for (i = 0; i < psid->data_size; i++) { - ram_store((WORD)(psid->load_addr + i), psid->data[i]); + ram_store((uint16_t)(psid->load_addr + i), psid->data[i]); } /* Skip JMP and CBM80 reset vector. */ addr = reloc_addr + 3 + 9 + 9; /* Store parameters for PSID player. */ - ram_store(addr++, (BYTE)(0)); - ram_store(addr++, (BYTE)(psid->songs)); - ram_store(addr++, (BYTE)(psid->load_addr & 0xff)); - ram_store(addr++, (BYTE)(psid->load_addr >> 8)); - ram_store(addr++, (BYTE)(psid->init_addr & 0xff)); - ram_store(addr++, (BYTE)(psid->init_addr >> 8)); - ram_store(addr++, (BYTE)(psid->play_addr & 0xff)); - ram_store(addr++, (BYTE)(psid->play_addr >> 8)); - ram_store(addr++, (BYTE)(psid->speed & 0xff)); - ram_store(addr++, (BYTE)((psid->speed >> 8) & 0xff)); - ram_store(addr++, (BYTE)((psid->speed >> 16) & 0xff)); - ram_store(addr++, (BYTE)(psid->speed >> 24)); - ram_store(addr++, (BYTE)((int)sync == MACHINE_SYNC_PAL ? 1 : 0)); - ram_store(addr++, (BYTE)(psid->load_last_addr & 0xff)); - ram_store(addr++, (BYTE)(psid->load_last_addr >> 8)); + ram_store(addr++, (uint8_t)(0)); + ram_store(addr++, (uint8_t)(psid->songs)); + ram_store(addr++, (uint8_t)(psid->load_addr & 0xff)); + ram_store(addr++, (uint8_t)(psid->load_addr >> 8)); + ram_store(addr++, (uint8_t)(psid->init_addr & 0xff)); + ram_store(addr++, (uint8_t)(psid->init_addr >> 8)); + ram_store(addr++, (uint8_t)(psid->play_addr & 0xff)); + ram_store(addr++, (uint8_t)(psid->play_addr >> 8)); + ram_store(addr++, (uint8_t)(psid->speed & 0xff)); + ram_store(addr++, (uint8_t)((psid->speed >> 8) & 0xff)); + ram_store(addr++, (uint8_t)((psid->speed >> 16) & 0xff)); + ram_store(addr++, (uint8_t)(psid->speed >> 24)); + ram_store(addr++, (uint8_t)((int)sync == MACHINE_SYNC_PAL ? 1 : 0)); + ram_store(addr++, (uint8_t)(psid->load_last_addr & 0xff)); + ram_store(addr++, (uint8_t)(psid->load_last_addr >> 8)); } unsigned int psid_increment_frames(void) @@ -758,7 +748,7 @@ unsigned int psid_increment_frames(void) * compute sidplayer (.mus/.str) support * * to minimize code duplication and to simplify the integration with the rest - * of the code, the sidplayer data is simply converted into PSID like format + * of the code, the sidplayer data is simply converted into PSID like format * at load time. heavily inspired by the respective code in libsidplay2. ******************************************************************************/ @@ -779,7 +769,7 @@ unsigned int psid_increment_frames(void) static void mus_install(void) { - WORD dest; + uint16_t dest; /* Install MUS player #1. */ dest = ((mus_driver[1] << 8) | mus_driver[0]) - MUS_IMAGE_START; memcpy(psid->data + dest, mus_driver + 2, sizeof(mus_driver) - 2); @@ -847,7 +837,7 @@ static const unsigned char *copystring(unsigned char *d, const unsigned char *s) ++s; } *d = 0; - charset_petconvstring(d, 1); + charset_petconvstring(d, CONVERT_TO_ASCII); return s + 1; } @@ -881,8 +871,9 @@ static int mus_load_file(const char* filename, int ispsid) { char *strname; FILE *f; - int n, stereo = 0; - int mus_datalen; + int stereo = 0; + size_t n; + size_t mus_datalen; if (!(f = zfile_fopen(filename, MODE_READ))) { return -1; @@ -908,7 +899,7 @@ static int mus_load_file(const char* filename, int ispsid) /* FIXME: the psid file format specification does not tell how to handle stereo sidplayer tunes when they are in psid format */ if (!ispsid) { - strname = lib_stralloc(filename); + strname = lib_strdup(filename); n = strlen(strname) - 4; strcpy(strname + n, ".str"); @@ -922,7 +913,7 @@ static int mus_load_file(const char* filename, int ispsid) } lib_free(strname); /* only extract credits if this is NOT a psid file */ - mus_extract_credits(psid->data, mus_datalen); + mus_extract_credits(psid->data, (int)mus_datalen); } mus_install(); diff --git a/src/Emulators/vice/c64/psid.h b/src/Emulators/vice/c64/psid.h index c027513e..cd31a1fe 100644 --- a/src/Emulators/vice/c64/psid.h +++ b/src/Emulators/vice/c64/psid.h @@ -29,16 +29,18 @@ #include "vicetypes.h" -extern int psid_resources_init(void); -extern int psid_cmdline_options_init(void); -extern void psid_shutdown(void); -extern int psid_load_file(const char* filename); -extern void psid_init_tune(int install_driver_hook); -extern void psid_set_tune(int tune); -extern int psid_tunes(int* default_tune); -extern int psid_basic_rsid_to_autostart(WORD *address, BYTE **data, WORD *length); -extern void psid_init_driver(void); -extern unsigned int psid_increment_frames(void); -extern int reloc65(char** buf, int* fsize, int addr); + +int psid_resources_init(void); +int psid_cmdline_options_init(void); +void psid_shutdown(void); +int psid_load_file(const char* filename); +void psid_init_tune(int install_driver_hook); +void psid_set_tune(int tune); +int psid_tunes(int* default_tune); +int psid_basic_rsid_to_autostart(uint16_t *address, uint8_t **data, uint16_t *length); +void psid_init_driver(void); +unsigned int psid_increment_frames(void); +int reloc65(char** buf, int* fsize, int addr); +int psid_ui_set_tune(int, void *param); #endif diff --git a/src/Emulators/vice/c64/psiddrv.h b/src/Emulators/vice/c64/psiddrv.h index ada641d8..c1820907 100644 --- a/src/Emulators/vice/c64/psiddrv.h +++ b/src/Emulators/vice/c64/psiddrv.h @@ -1,55 +1,28 @@ - 0x01, 0x00, 0x6f, 0x36, 0x35, 0x00, 0x03, 0x00, - 0x00, 0x10, 0x35, 0x01, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0x00, 0x70, 0x73, 0x69, 0x64, - 0x64, 0x72, 0x76, 0x2e, 0x6f, 0x36, 0x35, 0x00, - 0x1c, 0x03, 0x44, 0x61, 0x67, 0x20, 0x4c, 0x65, - 0x6d, 0x20, 0x3c, 0x72, 0x65, 0x73, 0x69, 0x64, - 0x40, 0x6e, 0x69, 0x6d, 0x72, 0x6f, 0x64, 0x2e, - 0x6e, 0x6f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x2b, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x11, 0x11, 0x2b, 0x11, 0x31, 0x11, - 0xa9, 0x00, 0x8d, 0x1a, 0xd0, 0xad, 0x19, 0xd0, - 0x8d, 0x19, 0xd0, 0xa9, 0x7f, 0x8d, 0x0d, 0xdc, - 0x8d, 0x0d, 0xdd, 0xad, 0x0d, 0xdc, 0xad, 0x0d, - 0xdd, 0xa2, 0x08, 0xbd, 0x0c, 0x10, 0x9d, 0x00, - 0x80, 0xca, 0x10, 0xf7, 0xad, 0x18, 0x10, 0xc9, - 0x03, 0x90, 0x14, 0xd0, 0x07, 0xad, 0x17, 0x10, - 0xc9, 0x1a, 0x90, 0x0b, 0xa2, 0x05, 0xbd, 0x25, - 0x10, 0x9d, 0x14, 0x03, 0xca, 0x10, 0xf7, 0xa9, - 0x1b, 0xa2, 0x00, 0x8d, 0x11, 0xd0, 0x8e, 0x12, - 0xd0, 0xad, 0x21, 0x10, 0xf0, 0x06, 0xa9, 0x25, - 0xa2, 0x40, 0xd0, 0x04, 0xa9, 0x95, 0xa2, 0x42, - 0x8d, 0x04, 0xdc, 0x8e, 0x05, 0xdc, 0xa9, 0x0f, - 0x8d, 0x18, 0xd4, 0xac, 0x15, 0x10, 0x88, 0xcc, - 0x16, 0x10, 0x90, 0x02, 0xa0, 0x00, 0x98, 0x48, - 0xad, 0x1c, 0x10, 0xf0, 0x27, 0xae, 0x1c, 0x10, - 0x20, 0xf9, 0x10, 0x8d, 0x24, 0x10, 0xc0, 0x20, - 0x90, 0x02, 0xa0, 0x1f, 0xa9, 0x00, 0xaa, 0x38, - 0x2a, 0x90, 0x02, 0x2a, 0xe8, 0x88, 0x10, 0xf8, - 0x3d, 0x1d, 0x10, 0xd0, 0x07, 0xa9, 0x81, 0x8d, - 0x1a, 0xd0, 0xd0, 0x0a, 0xa9, 0x81, 0xa2, 0x01, - 0x8d, 0x0d, 0xdc, 0x8e, 0x0e, 0xdc, 0xa9, 0x2f, - 0x85, 0x00, 0xad, 0x1a, 0x10, 0xae, 0x23, 0x10, - 0x20, 0xf9, 0x10, 0x85, 0x01, 0x68, 0xaa, 0xa8, - 0x20, 0xf3, 0x10, 0xad, 0x1c, 0x10, 0xf0, 0x04, - 0xa9, 0x36, 0x85, 0x01, 0x58, 0x4c, 0xf0, 0x10, - 0x6c, 0x19, 0x10, 0x6c, 0x1b, 0x10, 0xc9, 0xe0, - 0x90, 0x03, 0xa9, 0x35, 0x60, 0xc9, 0xd0, 0x90, - 0x03, 0xa9, 0x34, 0x60, 0xe0, 0xa0, 0x90, 0x03, - 0xa9, 0x36, 0x60, 0xa9, 0x37, 0x60, 0xad, 0x1c, - 0x10, 0xf0, 0x0c, 0xad, 0x24, 0x10, 0x85, 0x01, - 0x20, 0xf6, 0x10, 0xa9, 0x36, 0x85, 0x01, 0xad, - 0x19, 0xd0, 0x8d, 0x19, 0xd0, 0xad, 0x0d, 0xdc, - 0x68, 0xa8, 0x68, 0xaa, 0x68, 0x40, 0x2c, 0x0d, - 0xdd, 0x40, 0x00, 0x00, 0x0b, 0x82, 0x1b, 0x82, - 0x02, 0x82, 0x02, 0x82, 0x1e, 0x82, 0x09, 0x82, - 0x09, 0x82, 0x09, 0x82, 0x13, 0x82, 0x1a, 0x82, - 0x04, 0x82, 0x09, 0x82, 0x05, 0x82, 0x03, 0x82, - 0x03, 0x82, 0x15, 0x82, 0x1a, 0x82, 0x03, 0x82, - 0x03, 0x82, 0x08, 0x82, 0x03, 0x82, 0x0a, 0x82, - 0x03, 0x82, 0x03, 0x82, 0x1b, 0x82, 0x05, 0x82, + 0x01, 0x00, 0x6f, 0x36, 0x35, 0x00, 0x03, 0x00, 0x00, 0x10, 0x35, 0x01, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x70, 0x73, 0x69, 0x64, + 0x64, 0x72, 0x76, 0x2e, 0x6f, 0x36, 0x35, 0x00, 0x1c, 0x03, 0x44, 0x61, 0x67, 0x20, 0x4c, 0x65, + 0x6d, 0x20, 0x3c, 0x72, 0x65, 0x73, 0x69, 0x64, 0x40, 0x6e, 0x69, 0x6d, 0x72, 0x6f, 0x64, 0x2e, + 0x6e, 0x6f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x2b, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x2b, 0x11, 0x31, 0x11, + 0xa9, 0x00, 0x8d, 0x1a, 0xd0, 0xad, 0x19, 0xd0, 0x8d, 0x19, 0xd0, 0xa9, 0x7f, 0x8d, 0x0d, 0xdc, + 0x8d, 0x0d, 0xdd, 0xad, 0x0d, 0xdc, 0xad, 0x0d, 0xdd, 0xa2, 0x08, 0xbd, 0x0c, 0x10, 0x9d, 0x00, + 0x80, 0xca, 0x10, 0xf7, 0xad, 0x18, 0x10, 0xc9, 0x03, 0x90, 0x14, 0xd0, 0x07, 0xad, 0x17, 0x10, + 0xc9, 0x1a, 0x90, 0x0b, 0xa2, 0x05, 0xbd, 0x25, 0x10, 0x9d, 0x14, 0x03, 0xca, 0x10, 0xf7, 0xa9, + 0x1b, 0xa2, 0x00, 0x8d, 0x11, 0xd0, 0x8e, 0x12, 0xd0, 0xad, 0x21, 0x10, 0xf0, 0x06, 0xa9, 0x25, + 0xa2, 0x40, 0xd0, 0x04, 0xa9, 0x95, 0xa2, 0x42, 0x8d, 0x04, 0xdc, 0x8e, 0x05, 0xdc, 0xa9, 0x0f, + 0x8d, 0x18, 0xd4, 0xac, 0x15, 0x10, 0x88, 0xcc, 0x16, 0x10, 0x90, 0x02, 0xa0, 0x00, 0x98, 0x48, + 0xad, 0x1c, 0x10, 0xf0, 0x27, 0xae, 0x1c, 0x10, 0x20, 0xf9, 0x10, 0x8d, 0x24, 0x10, 0xc0, 0x20, + 0x90, 0x02, 0xa0, 0x1f, 0xa9, 0x00, 0xaa, 0x38, 0x2a, 0x90, 0x02, 0x2a, 0xe8, 0x88, 0x10, 0xf8, + 0x3d, 0x1d, 0x10, 0xd0, 0x07, 0xa9, 0x81, 0x8d, 0x1a, 0xd0, 0xd0, 0x0a, 0xa9, 0x81, 0xa2, 0x01, + 0x8d, 0x0d, 0xdc, 0x8e, 0x0e, 0xdc, 0xa9, 0x2f, 0x85, 0x00, 0xad, 0x1a, 0x10, 0xae, 0x23, 0x10, + 0x20, 0xf9, 0x10, 0x85, 0x01, 0x68, 0xaa, 0xa8, 0x20, 0xf3, 0x10, 0xad, 0x1c, 0x10, 0xf0, 0x04, + 0xa9, 0x36, 0x85, 0x01, 0x58, 0x4c, 0xf0, 0x10, 0x6c, 0x19, 0x10, 0x6c, 0x1b, 0x10, 0xc9, 0xe0, + 0x90, 0x03, 0xa9, 0x35, 0x60, 0xc9, 0xd0, 0x90, 0x03, 0xa9, 0x34, 0x60, 0xe0, 0xa0, 0x90, 0x03, + 0xa9, 0x36, 0x60, 0xa9, 0x37, 0x60, 0xad, 0x1c, 0x10, 0xf0, 0x0c, 0xad, 0x24, 0x10, 0x85, 0x01, + 0x20, 0xf6, 0x10, 0xa9, 0x36, 0x85, 0x01, 0xad, 0x19, 0xd0, 0x8d, 0x19, 0xd0, 0xad, 0x0d, 0xdc, + 0x68, 0xa8, 0x68, 0xaa, 0x68, 0x40, 0x2c, 0x0d, 0xdd, 0x40, 0x00, 0x00, 0x0b, 0x82, 0x1b, 0x82, + 0x02, 0x82, 0x02, 0x82, 0x1e, 0x82, 0x09, 0x82, 0x09, 0x82, 0x09, 0x82, 0x13, 0x82, 0x1a, 0x82, + 0x04, 0x82, 0x09, 0x82, 0x05, 0x82, 0x03, 0x82, 0x03, 0x82, 0x15, 0x82, 0x1a, 0x82, 0x03, 0x82, + 0x03, 0x82, 0x08, 0x82, 0x03, 0x82, 0x0a, 0x82, 0x03, 0x82, 0x03, 0x82, 0x1b, 0x82, 0x05, 0x82, 0x05, 0x82, 0x00, 0x00, 0x00, 0x00, diff --git a/src/Emulators/vice/core/ata.c b/src/Emulators/vice/core/ata.c index 5b04342a..f22bc4b0 100644 --- a/src/Emulators/vice/core/ata.c +++ b/src/Emulators/vice/core/ata.c @@ -31,11 +31,6 @@ #include #endif -/* VAC++ has off_t in sys/stat.h */ -#ifdef __IBMC__ -#include -#endif - #include #include @@ -50,11 +45,6 @@ #include "maincpu.h" #include "monitor.h" -#ifndef HAVE_FSEEKO -#define fseeko(a, b, c) fseek(a, b, c) -#define ftello(a) ftell(a) -#endif - #define ATA_UNC 0x40 #define ATA_IDNF 0x10 #define ATA_ABRT 0x04 @@ -75,19 +65,19 @@ #define setb(a, b, c) {result[(a) * 2 + (b) / 8] |= (c) ? (1 << ((b) & 7)) : 0; } struct ata_drive_s { - BYTE error; - BYTE features; - BYTE sector_count, sector_count_internal; - BYTE sector; - WORD cylinder; - BYTE head; + uint8_t error; + uint8_t features; + uint8_t sector_count, sector_count_internal; + uint8_t sector; + uint16_t cylinder; + uint8_t head; int lba, dev, legacy; - BYTE control; - BYTE cmd; - BYTE power; - BYTE packet[12]; + uint8_t control; + uint8_t cmd; + uint8_t power; + uint8_t packet[12]; int bufp; - BYTE *buffer; + uint8_t *buffer; FILE *file; char *filename; char *myname; @@ -114,29 +104,34 @@ struct ata_drive_s { CLOCK cycles_1s; }; -static const BYTE identify[128] = { +static const uint8_t identify[128] = { + // 0x00 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x32, 0x31, 0x31, 0x38, 0x30, 0x30, 0x32, 0x20, 0x20, 0x20, 0x20, + // 0x20 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x36, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x56, 0x45, 0x43, 0x48, 0x2d, 0x44, 0x44, 0x20, 0x20, + // 0x40 0x20, 0x20, 0x41, 0x4b, 0x54, 0x4a, 0x52, 0x41, 0x5a, 0x20, 0x4f, 0x53, 0x54, 0x4c, 0x28, 0x20, 0x4f, 0x53, 0x49, 0x43, 0x53, 0x2f, 0x4e, 0x49, 0x55, 0x47, 0x41, 0x4c, 0x29, 0x52, 0x01, 0x00, + // 0x60 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x04, 0x00, 0x10, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x01, + // 0x78 (120) 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static void ident_update_string(BYTE *b, char *s, int n) +static void ident_update_string(uint8_t *b, char *s, int n) { int i; @@ -146,7 +141,7 @@ static void ident_update_string(BYTE *b, char *s, int n) } } -static void ata_change_power_mode(ata_drive_t *drv, BYTE value) +static void ata_change_power_mode(ata_drive_t *drv, uint8_t value) { if (drv->power == 0x00 && value != 0x00) { drv->busy |= 1; @@ -252,7 +247,7 @@ static int seek_sector(ata_drive_t *drv) drv->busy |= 2; alarm_set(drv->head_alarm, maincpu_clk + (CLOCK)(abs(drv->pos - lba) * drv->seek_time / drv->geometry.size)); ata_change_power_mode(drv, 0xff); - if (fseeko(drv->file, (off_t)lba * drv->sector_size, SEEK_SET)) { + if (archdep_fseeko(drv->file, (off_t)lba * drv->sector_size, SEEK_SET)) { drv->error = drv->atapi ? 0x54 : ATA_IDNF; } drv->pos = lba; @@ -349,7 +344,7 @@ static int write_sector(ata_drive_t *drv) void ata_reset(ata_drive_t *drv) { - BYTE oldcmd = drv->cmd; + uint8_t oldcmd = drv->cmd; drive_diag(drv); @@ -574,9 +569,9 @@ void ata_shutdown(ata_drive_t *drv) lib_free(drv); } -static void ata_execute_command(ata_drive_t *drv, BYTE value) +static void ata_execute_command(ata_drive_t *drv, uint8_t value) { - BYTE result[512]; + uint8_t result[512]; int i; if (drv->cmd == 0xe6) { @@ -857,9 +852,9 @@ static void ata_execute_command(ata_drive_t *drv, BYTE value) return; } -static void atapi_execute_command(ata_drive_t *drv, BYTE value) +static void atapi_execute_command(ata_drive_t *drv, uint8_t value) { - BYTE result[512]; + uint8_t result[512]; int i; if (drv->cmd == 0xe6 && value != 0x08) { @@ -947,7 +942,7 @@ static void atapi_execute_command(ata_drive_t *drv, BYTE value) static void atapi_packet_execute_command(ata_drive_t *drv) { - BYTE result[12]; + uint8_t result[12]; int len; drv->bufp = drv->sector_size; @@ -1051,9 +1046,9 @@ static void atapi_packet_execute_command(ata_drive_t *drv) return; } -WORD ata_register_read(ata_drive_t *drv, WORD addr, WORD bus) +uint16_t ata_register_read(ata_drive_t *drv, uint16_t addr, uint16_t bus) { - WORD res; + uint16_t res; if (drv->type == ATA_DRIVE_NONE) { return bus; @@ -1149,7 +1144,7 @@ WORD ata_register_read(ata_drive_t *drv, WORD addr, WORD bus) } } -WORD ata_register_peek(ata_drive_t *drv, WORD addr) +uint16_t ata_register_peek(ata_drive_t *drv, uint16_t addr) { if (addr == 0) { return 0; @@ -1161,17 +1156,17 @@ WORD ata_register_peek(ata_drive_t *drv, WORD addr) } -void ata_register_store(ata_drive_t *drv, WORD addr, WORD value) +void ata_register_store(ata_drive_t *drv, uint16_t addr, uint16_t value) { if (drv->type == ATA_DRIVE_NONE) { return; } - if (addr != 0 && addr != 14 && !(addr == 7 && drv->atapi && (BYTE)value == 0x08)) { + if (addr != 0 && addr != 14 && !(addr == 7 && drv->atapi && (uint8_t)value == 0x08)) { if (drv->busy || drv->bufp < drv->sector_size) { return; } } - if (drv->cmd == 0xe6 && addr != 14 && !(addr == 6 && drv->atapi) && !(addr == 7 && drv->atapi && (BYTE)value == 0x08)) { + if (drv->cmd == 0xe6 && addr != 14 && !(addr == 6 && drv->atapi) && !(addr == 7 && drv->atapi && (uint8_t)value == 0x08)) { return; } switch (addr) { @@ -1217,13 +1212,13 @@ void ata_register_store(ata_drive_t *drv, WORD addr, WORD value) } return; case 1: - drv->features = (BYTE)value; + drv->features = (uint8_t)value; return; case 2: - drv->sector_count = (BYTE)value; + drv->sector_count = (uint8_t)value; return; case 3: - drv->sector = (BYTE)value; + drv->sector = (uint8_t)value; return; case 4: drv->cylinder = (drv->cylinder & 0xff00) | (value & 0xff); @@ -1240,11 +1235,11 @@ void ata_register_store(ata_drive_t *drv, WORD addr, WORD value) } return; case 7: - if (drv->dev == drv->slave || (BYTE)value == 0x90) { + if (drv->dev == drv->slave || (uint8_t)value == 0x90) { if (drv->atapi) { - atapi_execute_command(drv, (BYTE)value); + atapi_execute_command(drv, (uint8_t)value); } else { - ata_execute_command(drv, (BYTE)value); + ata_execute_command(drv, (uint8_t)value); } } return; @@ -1254,7 +1249,7 @@ void ata_register_store(ata_drive_t *drv, WORD addr, WORD value) ata_reset(drv); debug((drv->log, "SOFTWARE RESET")); } - drv->control = (BYTE)value; + drv->control = (uint8_t)value; return; } return; @@ -1287,7 +1282,12 @@ void ata_image_attach(ata_drive_t *drv, char *filename, ata_drive_type_t type, a drv->geometry.heads = identify[6]; drv->geometry.sectors = identify[12]; drv->geometry.size = drv->geometry.cylinders * drv->geometry.heads * drv->geometry.sectors; - if ((identify[99] & 0x02) && (identify[120] || identify[121] || identify[122] || identify[123])) { + if ((identify[99] & 0x02) && + /* 0x78 (120): 0x00, 0x40, 0x00, 0x00 */ + ((identify[120] != /* DISABLES CODE */ (0) ) || + (identify[121] != 0) || + (identify[122] != 0) || + (identify[123] != 0))) { drv->geometry.size = identify[120]; drv->geometry.size |= identify[121] << 8; drv->geometry.size |= identify[122] << 16; @@ -1308,9 +1308,13 @@ void ata_image_attach(ata_drive_t *drv, char *filename, ata_drive_type_t type, a if (drv->file) { if (drv->atapi) { - log_message(drv->log, "Attached `%s' %u sectors total.", drv->filename, drv->geometry.size); + log_message(drv->log, "Attached `%s' %u sectors total.", + drv->filename, (unsigned int)drv->geometry.size); } else { - log_message(drv->log, "Attached `%s' %i/%i/%i CHS geometry, %u sectors total.", drv->filename, drv->geometry.cylinders, drv->geometry.heads, drv->geometry.sectors, drv->geometry.size); + log_message(drv->log, + "Attached `%s' %i/%i/%i CHS geometry, %u sectors total.", + drv->filename, drv->geometry.cylinders, drv->geometry.heads, + drv->geometry.sectors, (unsigned int)drv->geometry.size); } } else { if (drv->filename && drv->filename[0] && drv->type != ATA_DRIVE_NONE) { @@ -1371,9 +1375,9 @@ int ata_register_dump(ata_drive_t *drv) int ata_snapshot_write_module(ata_drive_t *drv, snapshot_t *s) { snapshot_module_t *m; - DWORD spindle_clk = CLOCK_MAX; - DWORD head_clk = CLOCK_MAX; - DWORD standby_clk = CLOCK_MAX; + CLOCK spindle_clk = CLOCK_MAX; + CLOCK head_clk = CLOCK_MAX; + CLOCK standby_clk = CLOCK_MAX; off_t pos = 0; m = snapshot_module_create(s, drv->myname, @@ -1392,7 +1396,7 @@ int ata_snapshot_write_module(ata_drive_t *drv, snapshot_t *s) standby_clk = drv->standby_alarm->context->pending_alarms[drv->standby_alarm->pending_idx].clk; } if (drv->file) { - pos = ftello(drv->file); + pos = archdep_ftello(drv->file); if (pos < 0) { pos = 0; } @@ -1400,9 +1404,9 @@ int ata_snapshot_write_module(ata_drive_t *drv, snapshot_t *s) SMW_STR(m, drv->filename); SMW_DW(m, drv->type); - SMW_W(m, (WORD)drv->geometry.cylinders); - SMW_B(m, (BYTE)drv->geometry.heads); - SMW_B(m, (BYTE)drv->geometry.sectors); + SMW_W(m, (uint16_t)drv->geometry.cylinders); + SMW_B(m, (uint8_t)drv->geometry.heads); + SMW_B(m, (uint8_t)drv->geometry.sectors); SMW_DW(m, drv->geometry.size); SMW_B(m, drv->error); SMW_B(m, drv->features); @@ -1410,24 +1414,24 @@ int ata_snapshot_write_module(ata_drive_t *drv, snapshot_t *s) SMW_B(m, drv->sector_count_internal); SMW_B(m, drv->sector); SMW_W(m, drv->cylinder); - SMW_B(m, (BYTE)(drv->head | (drv->dev << 4) | (drv->lba << 6) | drv->legacy)); + SMW_B(m, (uint8_t)(drv->head | (drv->dev << 4) | (drv->lba << 6) | drv->legacy)); SMW_B(m, drv->control); SMW_B(m, drv->cmd); SMW_B(m, drv->power); SMW_BA(m, drv->packet, sizeof(drv->packet)); - SMW_W(m, (WORD)drv->bufp); + SMW_W(m, (uint16_t)drv->bufp); SMW_BA(m, drv->buffer, drv->sector_size); - SMW_W(m, (WORD)drv->cylinders); - SMW_B(m, (BYTE)drv->heads); - SMW_B(m, (BYTE)drv->sectors); + SMW_W(m, (uint16_t)drv->cylinders); + SMW_B(m, (uint8_t)drv->heads); + SMW_B(m, (uint8_t)drv->sectors); SMW_DW(m, drv->pos); - SMW_DW(m, pos / drv->sector_size); - SMW_B(m, (BYTE)drv->wcache); - SMW_B(m, (BYTE)drv->lookahead); - SMW_B(m, (BYTE)drv->busy); - SMW_DW(m, spindle_clk); - SMW_DW(m, head_clk); - SMW_DW(m, standby_clk); + SMW_DW(m, (uint32_t)(pos / drv->sector_size)); + SMW_B(m, (uint8_t)drv->wcache); + SMW_B(m, (uint8_t)drv->lookahead); + SMW_B(m, (uint8_t)drv->busy); + SMW_CLOCK(m, spindle_clk); + SMW_CLOCK(m, head_clk); + SMW_CLOCK(m, standby_clk); SMW_DW(m, drv->standby); SMW_DW(m, drv->standby_max); @@ -1436,12 +1440,12 @@ int ata_snapshot_write_module(ata_drive_t *drv, snapshot_t *s) int ata_snapshot_read_module(ata_drive_t *drv, snapshot_t *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; char *filename = NULL; - DWORD spindle_clk; - DWORD head_clk; - DWORD standby_clk; + CLOCK spindle_clk; + CLOCK head_clk; + CLOCK standby_clk; int pos, type; m = snapshot_module_open(s, drv->myname, &vmajor, &vminor); @@ -1449,16 +1453,24 @@ int ata_snapshot_read_module(ata_drive_t *drv, snapshot_t *s) return -1; } - if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + if (!snapshot_version_is_equal(vmajor, vminor, CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); snapshot_module_close(m); return -1; } SMR_STR(m, &filename); if (!drv->filename || strcmp(filename, drv->filename)) { + log_warning(drv->log, "IDE image filename mismatch. expected: %s got: %s\n", + filename, drv->filename); + /* FIXME: this is really retarded - we should instead identify the image by + making a checksum instead of using the filename */ +#if 1 + snapshot_set_error(SNAPSHOT_ATA_IMAGE_FILENAME_MISMATCH); lib_free(filename); snapshot_module_close(m); return -1; +#endif } lib_free(filename); SMR_DW_INT(m, &type); @@ -1532,9 +1544,9 @@ int ata_snapshot_read_module(ata_drive_t *drv, snapshot_t *s) drv->lookahead = 1; } SMR_B_INT(m, &drv->busy); - SMR_DW(m, &spindle_clk); - SMR_DW(m, &head_clk); - SMR_DW(m, &standby_clk); + SMR_CLOCK(m, &spindle_clk); + SMR_CLOCK(m, &head_clk); + SMR_CLOCK(m, &standby_clk); SMR_DW_INT(m, &drv->standby); SMR_DW_INT(m, &drv->standby_max); drv->busy &= 0x03; @@ -1555,7 +1567,7 @@ int ata_snapshot_read_module(ata_drive_t *drv, snapshot_t *s) } if (drv->file) { - fseeko(drv->file, (off_t)pos * drv->sector_size, SEEK_SET); + archdep_fseeko(drv->file, (off_t)pos * drv->sector_size, SEEK_SET); } if (!drv->atapi) { /* atapi supports disc change events */ drv->readonly = 1; /* make sure for ata that there's no filesystem corruption */ diff --git a/src/Emulators/vice/core/ata.h b/src/Emulators/vice/core/ata.h index 24efad22..b298d004 100644 --- a/src/Emulators/vice/core/ata.h +++ b/src/Emulators/vice/core/ata.h @@ -38,20 +38,21 @@ typedef struct ata_drive_geometry_s { int cylinders, heads, sectors, size; } ata_drive_geometry_t; -extern ata_drive_t *ata_init(int drive); -extern void ata_shutdown(ata_drive_t *drv); -extern void ata_register_store(ata_drive_t *cdrive, WORD addr, WORD value); -extern WORD ata_register_read(ata_drive_t *cdrive, WORD addr, WORD bus); -extern WORD ata_register_peek(ata_drive_t *cdrive, WORD addr); -extern int ata_register_dump(ata_drive_t *cdrive); -extern void ata_image_attach(ata_drive_t *cdrive, char *filename, ata_drive_type_t type, ata_drive_geometry_t geometry); -extern void ata_image_detach(ata_drive_t *cdrive); -extern int ata_image_change(ata_drive_t *cdrive, char *filename, ata_drive_type_t type, ata_drive_geometry_t geometry); -extern void ata_reset(ata_drive_t *cdrive); +ata_drive_t *ata_init(int drive); +void ata_shutdown(ata_drive_t *drv); +void ata_register_store(ata_drive_t *cdrive, uint16_t addr, uint16_t value); +uint16_t ata_register_read(ata_drive_t *cdrive, uint16_t addr, uint16_t bus); +uint16_t ata_register_peek(ata_drive_t *cdrive, uint16_t addr); +int ata_register_dump(ata_drive_t *cdrive); +void ata_image_attach(ata_drive_t *cdrive, char *filename, ata_drive_type_t type, ata_drive_geometry_t geometry); +void ata_image_detach(ata_drive_t *cdrive); +int ata_image_change(ata_drive_t *cdrive, char *filename, ata_drive_type_t type, ata_drive_geometry_t geometry); +void ata_reset(ata_drive_t *cdrive); void ata_update_timing(ata_drive_t *drv, CLOCK cycles_1s); struct snapshot_s; -extern int ata_snapshot_read_module(ata_drive_t *drv, struct snapshot_s *s); -extern int ata_snapshot_write_module(ata_drive_t *drv, struct snapshot_s *s); + +int ata_snapshot_read_module(ata_drive_t *drv, struct snapshot_s *s); +int ata_snapshot_write_module(ata_drive_t *drv, struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/core/ciacore.c b/src/Emulators/vice/core/ciacore.c index e146f9a5..a481219b 100644 --- a/src/Emulators/vice/core/ciacore.c +++ b/src/Emulators/vice/core/ciacore.c @@ -8,6 +8,7 @@ * Ettore Perazzoli * Andreas Boose * Alexander Bluhm + * Olaf Seibert * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -32,7 +33,7 @@ /* #define DEBUG_CIA */ #ifdef DEBUG_CIA -#define DBG(_x_) log_debug _x_ +#define DBG(_x_) log_printf _x_ #else #define DBG(_x_) #endif @@ -43,7 +44,6 @@ #include #include "cia.h" -#include "clkguard.h" #include "ciatimer.h" #include "interrupt.h" #include "lib.h" @@ -53,17 +53,111 @@ #include "vicetypes.h" #include "c64.h" // c64d - +#include "vice_debugger_hook.h" #define STORE_OFFSET 1 #define READ_OFFSET 0 -#define CIAT_STOPPED 0 -#define CIAT_RUNNING 1 -#define CIAT_COUNTTA 2 +/* + * Values for field sdr_delay. + * + * Each group of bits is either some event that needs to happen in the near + * future, where ...0 is the time when it happens. + * + * Or it is something that happened in the near past, where the number + * increases every clock tick. + * + * As long as the sdr_alarm is active, they will be shifted LEFT one position + * each time it is called (and the bits moving into the next group are + * cleared), which is once per clock until no longer needed. + * Flags are added as needed to schedule tasks in the future. + * + * It's like a software version of a mercury delay line (or several in + * parallel). It avoids needing several alarm callbacks, where you're + * not quite sure of the ordering if they are for the same cycle. + * + * Not all bits are actually used, but using groups of 4 makes it + * easier to understand the value when printed. + */ +#define CIA_SDR_TOGGLE_CNT2 0x0001u /* countdown to toggling CNT */ +#define CIA_SDR_TOGGLE_CNT1 0x0002u +#define CIA_SDR_TOGGLE_CNT0 0x0004u +#define CIA_SDR_TOGGLE_CNT_1 0x0008u /* _1 = -1 */ + +#define CIA_SDR_NOGGLE_CNT2 0x0010u /* countdown to NOT toggling CNT */ +#define CIA_SDR_NOGGLE_CNT1 0x0020u +#define CIA_SDR_NOGGLE_CNT0 0x0040u +#define CIA_SDR_NOGGLE_CNT_1 0x0080u + +#define CIA_SDR_SET_SDR_IRQ3 0x0100u /* countdown to setting the SDR IRQ */ +#define CIA_SDR_SET_SDR_IRQ2 0x0200u +#define CIA_SDR_SET_SDR_IRQ1 0x0400u +#define CIA_SDR_SET_SDR_IRQ0 0x0800u + +#define CIA_SDR_CNT0 0x1000u /* history of the CNT output value */ +#define CIA_SDR_CNT1 0x2000u /* After all these bits are set or */ +#define CIA_SDR_CNT2 0x4000u /* reset, we can stop updating them */ +#define CIA_SDR_CNT3 0x8000u /* until CNT is toggled. */ + +#define CIA_SDR_SET3 0x00010000u /* countdown to setting shifter */ +#define CIA_SDR_SET2 0x00020000u /* from SDR */ +#define CIA_SDR_SET1 0x00040000u +#define CIA_SDR_SET0 0x00080000u + +#define CIA_SDR_LEFTMOST 0x00100000u + +#define CIA_SDR_CLEAR (CIA_SDR_NOGGLE_CNT2 | CIA_SDR_SET_SDR_IRQ3 | \ + CIA_SDR_CNT0 | CIA_SDR_SET3 | CIA_SDR_LEFTMOST) + +#define CIA_SDR_ACTIVE (CIA_SDR_TOGGLE_CNT2 | CIA_SDR_TOGGLE_CNT1 | \ + CIA_SDR_TOGGLE_CNT0 | CIA_SDR_TOGGLE_CNT_1 | \ + CIA_SDR_NOGGLE_CNT2 | CIA_SDR_NOGGLE_CNT1 | \ + CIA_SDR_NOGGLE_CNT0 | CIA_SDR_NOGGLE_CNT_1 | \ + CIA_SDR_SET_SDR_IRQ3 | CIA_SDR_SET_SDR_IRQ2 | \ + CIA_SDR_SET_SDR_IRQ1 | CIA_SDR_SET_SDR_IRQ0 | \ + CIA_SDR_SET3 | CIA_SDR_SET2 | \ + CIA_SDR_SET1 | CIA_SDR_SET0) + +#define ALL_SDR_CNT (CIA_SDR_CNT0|CIA_SDR_CNT1|CIA_SDR_CNT2|CIA_SDR_CNT3) + +#define ALL_SDR_TOGGLE_CNT (CIA_SDR_TOGGLE_CNT2 | CIA_SDR_TOGGLE_CNT1 | \ + CIA_SDR_TOGGLE_CNT0 | CIA_SDR_TOGGLE_CNT_1) +#define ALL_SDR_NOGGLE_CNT (CIA_SDR_NOGGLE_CNT2 | CIA_SDR_NOGGLE_CNT1 | \ + CIA_SDR_NOGGLE_CNT0 | CIA_SDR_NOGGLE_CNT_1) + +/* + * Here are the flag bits for ifr_delay. + */ + +#define CIA_IRQ_ACK1 0x0001 /* ClearIcr0 Countdown to ack-ing (resetting) irq source bits */ +#define CIA_IRQ_ACK0 0x0002 /* ClearIcr1 */ +#define CIA_IRQ_ACK_1 0x0004 /* ClearIcr2 */ +#define CIA_IRQ_ACK_2 0x0008 + +#define CIA_IRQ_D7SET1 0x0010 /* SetIcr0 Countdown to setting D7 in IFR */ +#define CIA_IRQ_D7SET0 0x0020 /* SetIcr1 */ +#define CIA_IRQ_D7SET_1 0x0040 + +#define CIA_IRQ_RAISE1 0x0100 /* Interrupt0 Countdown to raising interrupt */ +#define CIA_IRQ_RAISE0 0x0200 /* Interrupt1 */ +#define CIA_IRQ_RAISE_1 0x0400 + +#define CIA_IRQ_READ0 0x1000 /* ReadIcr0 How long since ICR was read */ +#define CIA_IRQ_READ1 0x2000 /* ReadIcr1 */ +#define CIA_IRQ_READ2 0x4000 /* ReadIcr2 */ + +#define CIA_IRQ_CLEAR (CIA_IRQ_ACK_2 | \ + CIA_IRQ_D7SET_1 | \ + CIA_IRQ_RAISE_1 | \ + CIA_IRQ_READ2) + +#define USE_IRQ_RAISE0_SHORTCUT 1 /* Documented at location of use */ static void ciacore_intta(CLOCK offset, void *data); static void ciacore_inttb(CLOCK offset, void *data); +static void ciacore_intsdr(CLOCK offset, void *data); +static void schedule_sdr_alarm(cia_context_t *cia_context, CLOCK rclk, uint32_t feed); +static void cia_set_irq_flag(cia_context_t *cia_context, CLOCK rclk, unsigned int bits); /* The following is an attempt in rewriting the interrupt defines into @@ -74,7 +168,7 @@ static void ciacore_inttb(CLOCK offset, void *data); one could also remove MYCIA_INT as it is also known... */ /* new semantics and as inline function, value can be replaced by 0/1 */ -static inline void my_set_int(cia_context_t *cia_context, int value, +static inline void my_set_int(cia_context_t *cia_context, bool value, CLOCK rclk) { #ifdef CIA_TIMER_DEBUG @@ -83,18 +177,62 @@ static inline void my_set_int(cia_context_t *cia_context, int value, rclk, (value)); } #endif - if ((value)) { - /* cia_context->irqflags |= 0x80; */ - (cia_context->cia_set_int_clk)(cia_context, cia_context->irq_line, - (rclk)); - cia_context->irq_enabled = 1; - - //LOGD("trigger Cia IRQ check by debugger"); - cia_context->c64d_irq_flag = 1; - + (cia_context->cia_set_int_clk)(cia_context, value, rclk); + cia_context->irq_enabled = value; + + // c64d: C64 debugger + if (value) { + VICE_HOOK_CIA_IRQ_FLAG_SET(cia_context); + } +} + +/* ------------------------------------------------------------------------- */ + +/* + * Return the clock when this alarm is due. + * Alarms for clock N run after CPU accesses for that clock. + * If the alarm is not set, returns 0. + */ +inline static CLOCK alarm_clk(alarm_t *alarm) +{ + alarm_context_t *context; + int idx; + + context = alarm->context; + idx = alarm->pending_idx; + + if (idx >= 0) { + return context->pending_alarms[idx].clk; } else { - (cia_context->cia_set_int_clk)(cia_context, 0, (rclk)); - cia_context->irq_enabled = 0; + return 0; + } +} + +/* + * To be called only during CPU access to the registers. + * + * Run any pending alarms that should have run before the current clock cycle. + * Alarms scheduled for cycle N run AFTER CPU accesses of cycle N. + * Therefore we only run alarms < clk, i.e. alarms that should have run + * up to and including the previous cycle. + * + * The normal execution run uses "clk >= alarm...", but since we're running + * this during CPU access, here we use "clk > ...". + * + * In some cases, clk here differs from the global clock by some offset + * (due to ->write_offset). The dispatch function needs the proper clock + * value to calculate the offset parameter to the alarm callbacks. + * So we need an offset here to re-calculate the correct clk. + * + * NOTE: cia_update_ta() and _tb() actually run their own alarms including + * those for the end of the current cycle. + * Unlike those ad-hoc functions, this one runs the alarms in their correct + * relative time order. + */ +inline static void run_pending_alarms(CLOCK clk, int offset, alarm_context_t *alarm_context) +{ + while (clk > alarm_context_next_pending_clk(alarm_context)) { + alarm_context_dispatch(alarm_context, clk + offset); } } @@ -107,12 +245,7 @@ inline static void check_ciatodalarm(cia_context_t *cia_context, CLOCK rclk) { if (!memcmp(cia_context->todalarm, cia_context->c_cia + CIA_TOD_TEN, sizeof(cia_context->todalarm))) { - cia_context->irqflags |= CIA_IM_TOD; - if (cia_context->c_cia[CIA_ICR] & CIA_IM_TOD) { - cia_context->irqflags |= 0x80; - my_set_int(cia_context, cia_context->irq_line, - *(cia_context->clk_ptr)); - } + cia_set_irq_flag(cia_context, rclk, CIA_IM_TOD); } } @@ -127,7 +260,7 @@ static void cia_do_update_ta(cia_context_t *cia_context, CLOCK rclk) int n; if ((n = ciat_update(cia_context->ta, rclk))) { - cia_context->irqflags |= CIA_IM_TA; + cia_set_irq_flag(cia_context, rclk, CIA_IM_TA); cia_context->tat = (cia_context->tat + n) & 1; } } @@ -137,7 +270,7 @@ static void cia_do_update_tb(cia_context_t *cia_context, CLOCK rclk) int n; if ((n = ciat_update(cia_context->tb, rclk))) { - cia_context->irqflags |= CIA_IM_TB; + cia_set_irq_flag(cia_context, rclk, CIA_IM_TB); if (cia_context->model == CIA_MODEL_6526 && cia_context->rdi == rclk - 1) { /* flag the timer B bug */ @@ -154,7 +287,7 @@ static void cia_do_step_tb(cia_context_t *cia_context, CLOCK rclk) int n; if ((n = ciat_single_step(cia_context->tb, rclk))) { - cia_context->irqflags |= CIA_IM_TB; + cia_set_irq_flag(cia_context, rclk, CIA_IM_TB); cia_context->tbt = (cia_context->tbt + n) & 1; } } @@ -163,13 +296,20 @@ static void cia_do_step_tb(cia_context_t *cia_context, CLOCK rclk) * Those functions are called everywhere but in the alarm functions. */ - void cia_update_ta(cia_context_t *cia_context, CLOCK rclk) { CLOCK tmp, last_tmp; + /* + * This is essentially the same idea as run_pending_alarms() + * except it runs the alarms a cycle further (due to <=) to the current + * cycle. + * Fortunately ciacore_intta() either unsets or reschedules the + * alarm so it won't run twice. + */ last_tmp = 0; tmp = ciat_alarm_clk(cia_context->ta); + while (tmp <= rclk) { ciacore_intta(*(cia_context->clk_ptr) - tmp, (void *)cia_context); last_tmp = tmp; @@ -179,16 +319,25 @@ void cia_update_ta(cia_context_t *cia_context, CLOCK rclk) if (last_tmp != rclk) { cia_do_update_ta(cia_context, rclk); } + } void cia_update_tb(cia_context_t *cia_context, CLOCK rclk) { CLOCK tmp, last_tmp; - if ((cia_context->c_cia[CIA_CRB] & 0x41) == 0x41) { + if ((cia_context->c_cia[CIA_CRB] & (CIA_CRB_INMODE_TA|CIA_CR_START)) + == (CIA_CRB_INMODE_TA|CIA_CR_START)) { cia_update_ta(cia_context, rclk); } + /* + * This is essentially the same idea as run_pending_alarms() + * except it runs the alarms a cycle further (due to <=) to the current + * cycle. + * Fortunately ciacore_inttb() either unsets or reschedules the + * alarm so it won't run twice. + */ last_tmp = 0; tmp = ciat_alarm_clk(cia_context->tb); while (tmp <= rclk) { @@ -202,99 +351,285 @@ void cia_update_tb(cia_context_t *cia_context, CLOCK rclk) } } +#if defined(IFR_DEBUG) +static void dump_ifr_delay(const char *name, uint32_t delay) +{ +#define DO_BIT(name) if (delay & name) fprintf(stderr, #name " ") + fprintf(stderr, "%s: ", name); + DO_BIT(CIA_IRQ_ACK1); + DO_BIT(CIA_IRQ_ACK0); + DO_BIT(CIA_IRQ_ACK_1); + DO_BIT(CIA_IRQ_ACK_2); + DO_BIT(CIA_IRQ_D7SET1); + DO_BIT(CIA_IRQ_D7SET0); + DO_BIT(CIA_IRQ_D7SET_1); + DO_BIT(CIA_IRQ_RAISE1); + DO_BIT(CIA_IRQ_RAISE0); + DO_BIT(CIA_IRQ_RAISE_1); + DO_BIT(CIA_IRQ_READ0); + DO_BIT(CIA_IRQ_READ1); + DO_BIT(CIA_IRQ_READ2); + fprintf(stderr, "\n"); +#undef DO_BIT +} +#endif /* IFR_DEBUG */ + /* - * set interrupt line + * This function is called to catch up on changes to the Interrupt Flag + * Register; one cycle at a time. It is for things we didn't do immediately + * because they are delayed wrt the action that triggers them. */ -static void cia_do_set_int(cia_context_t *cia_context, CLOCK rclk) +static void cia_run_ifr_cycle(cia_context_t *cia_context) { -#if 0 - if ((cia_context->model == CIA_MODEL_6526) - && (cia_context->rdi == rclk - 1) - && (cia_context->irq_line != IK_NMI)) { - /* FIXME explanation */ - return; - } + uint32_t delay = cia_context->ifr_delay; + CLOCK rclk = cia_context->ifr_clock; -#endif + /* Not done here but in cia_set_irq_flag() + cia_context->ack_irqflags &= ~cia_context->new_irqflags;*/ - if ((cia_context->rdi == rclk - 1) - && (cia_context->model == CIA_MODEL_6526A)) { - /* Interrupt delayed by 1/2 cycle if acknowledged on assert */ - rclk++; + if (cia_context->model != CIA_MODEL_6526) { /* new fast CIA */ + if ((delay & CIA_IRQ_ACK0) != 0) { + cia_context->irqflags &= ~cia_context->ack_irqflags; + cia_context->ack_irqflags = 0; + } + } else { /* old slow CIA */ + if ((delay & CIA_IRQ_ACK0) != 0) { + cia_context->irqflags &= ~cia_context->ack_irqflags; + cia_context->irqflags &= ~CIA_IM_SET; + cia_context->ack_irqflags = 0; + } } - if (!(cia_context->irqflags & cia_context->c_cia[CIA_ICR] & 0x7f)) { - /* no interrupts */ - return; + /* Not done here but in cia_do_update_tb() + if (bTimerBbug && (cia_context->new_irqflags & 2) !=0 && ClockReadICR == CurrentClock && (delay & (ReadIcr1)) == 0) { + cia_context->ack_irqflags |= CIA_IM_TB; + } */ + /* Not done here but in cia_set_irq_flag() + cia_context->irqflags |= cia_context->new_irqflags; */ + + if (cia_context->new_irqflags & cia_context->c_cia[CIA_ICR] & 0x1F) { + if (cia_context->model != CIA_MODEL_6526) { /* new CIA */ + if (cia_context->rdi + 1 == rclk) { + /* TEST TLR's CIA read DC0D (icr) when Timer counts to zero; + * Used by testprogs/interrupts/irqnmi/cia-int-irq-new.prg + * Used by testprogs/interrupts/irqnmi/cia-int-nmi-new.prg */ + delay |= CIA_IRQ_RAISE1; + delay |= CIA_IRQ_D7SET1; + } else { + delay |= CIA_IRQ_RAISE0; + delay |= CIA_IRQ_D7SET0; + } + } else { /* Old CIA */ + delay |= CIA_IRQ_RAISE1; + delay |= CIA_IRQ_D7SET1; + } } - if ((cia_context->model != CIA_MODEL_6526A) && (cia_context->rdi == rclk)) { - /* FIXME explanation */ - return; + /* Check for interrupt condition */ + if ((delay & CIA_IRQ_D7SET0) != 0) { + cia_context->irqflags |= CIA_IM_SET; } - if (cia_context->model != CIA_MODEL_6526A) { - /* interrupts are delayed by 1 clk on old CIAs */ - rclk++; + if (delay & CIA_IRQ_RAISE0) { + my_set_int(cia_context, true, rclk); } - if (cia_context->irqflags & CIA_IM_TBB) { - /* timer b bug */ - cia_context->irqflags &= ~(CIA_IM_TBB | CIA_IM_TB); - } + cia_context->new_irqflags = 0; - my_set_int(cia_context, cia_context->irq_line, rclk); - cia_context->irqflags |= 0x80; + delay <<= 1; + delay &= ~CIA_IRQ_CLEAR; + cia_context->ifr_delay = delay; + cia_context->ifr_clock++; } -/* ------------------------------------------------------------------------- */ - -static void ciacore_clk_overflow_callback(CLOCK sub, void *data) +/* + * Only run the IFR delay pipeline once per cycle. + * Timer A/B need to be updated first. + * SDR, TOD and idle alarms can run after, and check before calling here. + * + * If we want to look at the updated ICR after this (such as when the cpu + * accesses it), you must make sure that all relevant alarms have alreay run + * before this. + * + * If we're not sure we are going to be called in the next cycle, + * work ahead; only do the things that cannot be done later, just + * before looking at it again: + * i.e. do trigger irq, don't change registers. + * cia_ifr_catchup() will be called later which will do the rest + * (and possibly duplicate some). + */ +#define CIA_IFR_CURRENT 0x01 +#define CIA_IFR_NEXT 0x02 +#define CIA_IFR_CUR_NXT 0x03 +static void cia_ifr_current(cia_context_t *cia_context, CLOCK rclk, int what) { - cia_context_t *cia_context; - - cia_context = (cia_context_t *)data; + /* + * Check if Timer A/B alarms for this cycle are still scheduled. + * This check should be needed if all callers are careful, + * but is left as a consistency check. + * Another consistency check could be that ->ifr_clock == rclk. + */ + if (ciat_alarm_clk(cia_context->ta) != rclk && + ciat_alarm_clk(cia_context->tb) != rclk) { + if (what & CIA_IFR_CURRENT) { + cia_run_ifr_cycle(cia_context); + } - if (cia_context->enabled == 0) { - return; + if (what & CIA_IFR_NEXT) { + uint32_t delay = cia_context->ifr_delay; + /* Look 1 tick into the future */ + if (delay & CIA_IRQ_RAISE0) { +#if USE_IRQ_RAISE0_SHORTCUT + /* + * We can safely schedule the IRQ/NMI 1 cycle into the future. + * There are cases where CIA_IRQ_RAISE0 is cleared (can happen + * when writing CIA_ICR or reading it), but in those cases + * another CIA_IFR_CURRENT has been done before, which does a + * shift of the delay word. So the RAISE0 there would be a + * RAISE1 (or higher) here. + */ + my_set_int(cia_context, true, rclk + 1); +#else + /* + * Instead of scheduling the interrupt "ahead of time", we + * can also cause the delay line to run in the next cycle, + * using the idle alarm. + * This variant must always work too (if it doesn't, + * there is something subtly wrong which could fail too in + * other cases). + */ + alarm_set(cia_context->idle_alarm, rclk + 1); +#endif + } + /* Look 2 ticks into the future */ + else if (delay & CIA_IRQ_RAISE1) { + /* + * This case is pretty rare, but the Lorenz imr.prg "set imr + * clock 3" test (for old CIAs) triggers it. + */ + alarm_set(cia_context->idle_alarm, rclk + 1); + } + } + } else { + /* + * This case should not happen; if it does, some logic has to be + * adjusted so that this function is called only after updating the + * timers (which reschedules their alarms to some later time). + */ } +} - /* we assume that sub has already been substracted from myclk */ - cia_update_ta(cia_context, *(cia_context->clk_ptr) + sub); - cia_update_tb(cia_context, *(cia_context->clk_ptr) + sub); - - ciat_prevent_clock_overflow(cia_context->ta, sub); - ciat_prevent_clock_overflow(cia_context->tb, sub); +/* + * Catch up on the IFR delay pipeline, if it is behind. + * This function is safe to call more than once. + * It must be called before cia_ifr_current(). + * + * It knows how to shortcut doing all clock iterations, if no more + * changes can happen. + */ +static void cia_ifr_catchup(cia_context_t *cia_context, CLOCK rclk) +{ + if (cia_context->ifr_clock < rclk) { + while ((cia_context->ifr_delay || + cia_context->new_irqflags || + cia_context->ack_irqflags) && + cia_context->ifr_clock < rclk) { + cia_run_ifr_cycle(cia_context); + } - if (cia_context->rdi > sub) { - cia_context->rdi -= sub; - } else { - cia_context->rdi = 0; + cia_context->ifr_clock = rclk; } +} - if (cia_context->read_clk > sub) { - cia_context->read_clk -= sub; - } else { - cia_context->read_clk = 0; - } +/* + * Set a flag in the Interrupt Flag Register. + * + * Unlike earlier versions of this code, it doesn't immediately signal an + * interrupt to the CPU. This is to be done later (as late as possible in + * the same cycle, and precisely one time) in cia_run_ifr_cycle(). + * + * This is normally done by calling, after any function that may get here: + * + * cia_ifr_catchup(); + * cia_ifr_current(CIA_IFR_CUR_NXT); (possibly for CUR and NEXT separately) + * + * cia_ifr_catchup() is safe to call multiple times (but must be called once + * before cia_ifr_current()), + * but cia_ifr_current() must NOT be called more than once for a cycle! + * + * Timer A and B alarm code wants to run before cpu access in the same cycle, + * but alarms actually run after cpu access. So various places call code + * to update the timers before taking other action, such as calling + * cia_ifr_current(). + * (So strictly speaking, cia_ifr_current() ought not need to check for TA or TB + * alarms being pending?) + * SDR, TOD and idle alarms are happy to run after the cpu access, + * so cia_ifr_current() doesn't check for them. + * + * Functions that call here are: + * + * - check_ciatodalarm() + * - ciacore_inttod() + * - ciacore_inttod_entry() ok, from alarm + * - cia_do_update_ta() + * - cia_update_ta() + * - cia_update_tb() + * - ciacore_update_pb67() + * - ciacore_store_internal() ok, CPU access + * - ciacore_store_internal() see ^ + * - ciacore_read() ok, CPU access + * - ciacore_update_pb67() see ^ + * - ciacore_read() see ^ + * - ciacore_store_internal() see ^ + * - ciacore_intta() + * - cia_update_ta() see ^ + * - ciacore_intta_entry() ok, from alarm + * - cia_do_update_tb() + * - cia_update_tb() see ^ + * - ciacore_intta() see ^ + * - ciacore_inttb() + * - cia_update_tb() see ^ + * - ciacore_inttb_entry() ok, from alarm + * - cia_do_step_tb(), + * - ciacore_intta() see ^ + * - ciacore_set_flag() ok, from extern + * - ciacore_set_sdr() ok, from extern + * - ciacore_intsdr(), + * - ciacore_intsdr_entry() ok, from alarm + */ +static void cia_set_irq_flag(cia_context_t *cia_context, CLOCK rclk, unsigned int bits) +{ + cia_ifr_catchup(cia_context, rclk); - if (cia_context->todclk) { - cia_context->todclk -= sub; - } + cia_context->irqflags |= bits; + cia_context->new_irqflags |= bits; + /* Done here instead of doing all new bits at once in cia_run_ifr_cycle(): */ + cia_context->ack_irqflags &= ~bits; } + /* -------------------------------------------------------------------------- */ void ciacore_disable(cia_context_t *cia_context) { -#ifdef USE_IDLE_CALLBACK alarm_unset(cia_context->idle_alarm); -#endif alarm_unset(cia_context->ta_alarm); alarm_unset(cia_context->tb_alarm); alarm_unset(cia_context->tod_alarm); - cia_context->enabled = 0; + alarm_unset(cia_context->sdr_alarm); + cia_context->enabled = false; } +/* + we must take care to choose a value which is small enough so the counters do + not fall behind too much to cause a significant peak in cpu usage, and one + that is big enough so the overall performance impact is not too big. + it seems reasonable to also consider how peaks in cpu usage interact with + automatic framerate adjustment, so choosing a value that makes sure a more + or less constant amount of cpu time per frame is consumed is a good idea. + (about 20000 cycles are a full PAL frame on the C64, making sure that we do + not fall behind one frame at all seems a good idea.) + */ +#define CIA_MAX_IDLE_CYCLES 5000 void ciacore_reset(cia_context_t *cia_context) { @@ -311,7 +646,13 @@ void ciacore_reset(cia_context_t *cia_context) ciat_reset(cia_context->ta, *(cia_context->clk_ptr)); ciat_reset(cia_context->tb, *(cia_context->clk_ptr)); - cia_context->sdr_valid = 0; + cia_context->sdr_valid = false; + cia_context->sdr_force_finish = false; + cia_context->sdr_delay = CIA_SDR_CNT0|CIA_SDR_CNT1|CIA_SDR_CNT2|CIA_SDR_CNT3; + + cia_context->sp_in_state = true; + cia_context->cnt_in_state = true; + cia_context->cnt_out_state = true; memset(cia_context->todalarm, 0, sizeof(cia_context->todalarm)); cia_context->todlatched = 0; @@ -323,19 +664,131 @@ void ciacore_reset(cia_context_t *cia_context) cia_context->todtickcounter = 0; cia_context->irqflags = 0; + cia_context->ack_irqflags = 0; + cia_context->new_irqflags = 0; cia_context->irq_enabled = 0; - my_set_int(cia_context, 0, *(cia_context->clk_ptr)); + cia_context->ifr_clock = 0; + cia_context->ifr_delay = 0; + my_set_int(cia_context, false, *(cia_context->clk_ptr)); + + /* these must be 0xff, or programs relying on the initial value may not + work correctly, see bug #1143 */ cia_context->old_pa = 0xff; cia_context->old_pb = 0xff; (cia_context->do_reset_cia)(cia_context); - cia_context->enabled = 1; + cia_context->enabled = true; + + /* + * A reset also resets the system clock, so any existing alarms + * (except the one set above) at this time would now be invalid. + */ + alarm_set(cia_context->idle_alarm, + *(cia_context->clk_ptr) + CIA_MAX_IDLE_CYCLES); + alarm_unset(cia_context->ta_alarm); + alarm_unset(cia_context->tb_alarm); + alarm_unset(cia_context->sdr_alarm); } +/* + * https://sourceforge.net/p/vice-emu/bugs/1219 + */ +static inline void strange_extra_sdr_flags(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) +{ + if ((byte & CIA_CRA_SPMODE_OUT) == CIA_CRA_SPMODE_IN) { + /* Switching from output to input */ + bool forceFinish = false; + uint32_t cnt_wanted; + uint32_t sdr_delay = cia_context->sdr_delay; + uint32_t cnt_delay = sdr_delay; + + if (cia_context->model == CIA_MODEL_6526) { + cnt_wanted = (CIA_SDR_CNT0 | CIA_SDR_CNT1 | CIA_SDR_CNT2); + } else { + cnt_wanted = ( CIA_SDR_CNT1 | CIA_SDR_CNT2); + } + forceFinish = (cnt_delay & cnt_wanted) != cnt_wanted; + + if (!forceFinish) { + if (cia_context->sr_bits != 2 && + !(sdr_delay & CIA_SDR_TOGGLE_CNT2) && + !(sdr_delay & CIA_SDR_TOGGLE_CNT1) && + (sdr_delay & CIA_SDR_TOGGLE_CNT0)) { + forceFinish = true; + } + } + + cia_context->sdr_force_finish = forceFinish; + } else { + /* Switching from input to output */ + + /* + * Act on positive incoming CNT flank. + * This doesn't really belong here. And does it even happen? + */ + if (!cia_context->cnt_out_state && cia_context->sr_bits != 0) { + cia_context->shifter <<= 1; + } + + if (cia_context->sdr_force_finish) { + schedule_sdr_alarm(cia_context, rclk, CIA_SDR_SET_SDR_IRQ2); + cia_context->sdr_force_finish = false; + } + } +} -static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE byte) +/* + * Update bits 6 and 7 of Port B, depending on if the timer(s) are set + * to output to them. + * + * Mostly identical to reading CIA_PRB. + */ +static inline bool ciacore_update_pb67(cia_context_t *cia_context, CLOCK rclk) +{ + uint8_t byte; + bool current_called = false; + + byte = cia_context->c_cia[CIA_PRB] | ~(cia_context->c_cia[CIA_DDRB]); + + if ((cia_context->c_cia[CIA_CRA] + | cia_context->c_cia[CIA_CRB]) & CIA_CR_PBON) { + if (cia_context->c_cia[CIA_CRA] & CIA_CR_PBON) { + cia_update_ta(cia_context, rclk); + byte &= 0xbf; + if ((cia_context->c_cia[CIA_CRA] & CIA_CR_OUTMODE_TOGGLE) + ? cia_context->tat + : ciat_is_underflow_clk(cia_context->ta, rclk)) { + byte |= 0x40; /* PB6 for timer A */ + } + } + if (cia_context->c_cia[CIA_CRB] & CIA_CR_PBON) { + cia_update_tb(cia_context, rclk); + byte &= 0x7f; + if (((cia_context->c_cia[CIA_CRB] & CIA_CR_OUTMODE_TOGGLE) + ? cia_context->tbt + : ciat_is_underflow_clk(cia_context->tb, rclk))) { + byte |= 0x80; /* PB7 for timer B */ + } + } + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + /* We called these functions already: caller should not! */ + current_called = true; + } + + if (byte != cia_context->old_pb) { + (cia_context->store_ciapb)(cia_context, + *(cia_context->clk_ptr), + byte); + cia_context->old_pb = byte; + } + + return current_called; +} + +static void ciacore_store_internal(cia_context_t *cia_context, uint16_t addr, uint8_t byte) { CLOCK rclk; @@ -344,6 +797,8 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b /* stores have a one-cycle offset if CLK++ happens before store */ rclk = *(cia_context->clk_ptr) - cia_context->write_offset; + run_pending_alarms(rclk, cia_context->write_offset, cia_context->tb_alarm->context); + #ifdef CIA_TIMER_DEBUG if (cia_context->debugFlag) { log_message(cia_context->log, "store cia[%02x] %02x @ clk=%d", @@ -366,31 +821,8 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b case CIA_PRB: /* port B */ case CIA_DDRB: cia_context->c_cia[addr] = byte; - byte = cia_context->c_cia[CIA_PRB] | ~(cia_context->c_cia[CIA_DDRB]); - if ((cia_context->c_cia[CIA_CRA] - | cia_context->c_cia[CIA_CRB]) & 0x02) { - if (cia_context->c_cia[CIA_CRA] & 0x02) { - cia_update_ta(cia_context, rclk); - byte &= 0xbf; - if (((cia_context->c_cia[CIA_CRA] & 0x04) ? cia_context->tat - : ciat_is_underflow_clk(cia_context->ta, rclk))) { - byte |= 0x40; - } - } - if (cia_context->c_cia[CIA_CRB] & 0x02) { - cia_update_tb(cia_context, rclk); - byte &= 0x7f; - if (((cia_context->c_cia[CIA_CRB] & 0x04) ? cia_context->tbt - : ciat_is_underflow_clk(cia_context->tb, rclk))) { - byte |= 0x80; - } - } - } - if (byte != cia_context->old_pb) { - (cia_context->store_ciapb)(cia_context, *(cia_context->clk_ptr), - byte); - cia_context->old_pb = byte; - } + ciacore_update_pb67(cia_context, rclk); + if (addr == CIA_PRB) { (cia_context->pulse_ciapc)(cia_context, rclk); } @@ -398,19 +830,27 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b case CIA_TAL: cia_update_ta(cia_context, rclk); - ciat_set_latchlo(cia_context->ta, rclk, (BYTE)byte); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + ciat_set_latchlo(cia_context->ta, rclk, (uint8_t)byte); break; case CIA_TBL: cia_update_tb(cia_context, rclk); - ciat_set_latchlo(cia_context->tb, rclk, (BYTE)byte); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + ciat_set_latchlo(cia_context->tb, rclk, (uint8_t)byte); break; case CIA_TAH: cia_update_ta(cia_context, rclk); - ciat_set_latchhi(cia_context->ta, rclk, (BYTE)byte); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + ciat_set_latchhi(cia_context->ta, rclk, (uint8_t)byte); break; case CIA_TBH: cia_update_tb(cia_context, rclk); - ciat_set_latchhi(cia_context->tb, rclk, (BYTE)byte); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + ciat_set_latchhi(cia_context->tb, rclk, (uint8_t)byte); break; /* @@ -429,7 +869,8 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b byte &= 0x9f; /* Flip AM/PM on hour 12 */ /* Flip AM/PM only when writing time, not when writing alarm */ - if ((byte & 0x1f) == 0x12 && !(cia_context->c_cia[CIA_CRB] & 0x80)) { + if ((byte & 0x1f) == 0x12 && + (cia_context->c_cia[CIA_CRB] & CIA_CRB_ALARM) == CIA_CRB_ALARM_TOD) { byte ^= 0x80; } } else if (addr == CIA_TOD_MIN) { @@ -441,78 +882,73 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b } { - char changed; - if (cia_context->c_cia[CIA_CRB] & 0x80) { + bool changed; + if (cia_context->c_cia[CIA_CRB] & CIA_CRB_ALARM_ALARM) { /* set alarm */ changed = cia_context->todalarm[addr - CIA_TOD_TEN] != byte; cia_context->todalarm[addr - CIA_TOD_TEN] = byte; } else { /* set time */ if (addr == CIA_TOD_TEN) { - /* apparently the tickcounter is reset to 0 when the clock + /* the tickcounter is kept clear while the clock is not running and then restarted by writing to the 10th seconds register */ if (cia_context->todstopped) { cia_context->todtickcounter = 0; + cia_context->todstopped = 0; } - cia_context->todstopped = 0; } if (addr == CIA_TOD_HR) { cia_context->todstopped = 1; } changed = cia_context->c_cia[addr] != byte; - cia_context->c_cia[addr] = byte; + if (changed) { + cia_context->c_cia[addr] = byte; + } } if (changed) { check_ciatodalarm(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); } } break; case CIA_SDR: /* Serial Port output buffer */ - cia_context->c_cia[addr] = byte; - if ((cia_context->c_cia[CIA_CRA] & 0x40) == 0x40) { - cia_context->sdr_valid = 1; - cia_update_ta(cia_context, rclk); - ciat_set_alarm(cia_context->ta, rclk); -#if 0 - if (cia_context->sr_bits <= 8) { -/* - if (!(cia_context->sr_bits)) { - (cia_context->store_sdr)(cia[CIA_SDR]); - } -*/ - if (cia_context->sr_bits < 8) { - /* switch timer A alarm on again, if necessary */ -/* FIXME - update_cia(rclk); - if (cia_tau) { - my_set_tai_clk(cia_tau + 1); - } -*/ - } - - cia_context->sr_bits += 8; -#if defined (CIA_TIMER_DEBUG) - if (cia_context->debugFlag) { - log_message(cia_context->log, "start SDR rclk=%d.", - rclk); - } -#endif - } -#endif + DBG(("write SDR(1) %s: %02x, sr_bits %2u, shifter %04x sdr_valid %d rclk %lu\n", + cia_context->myname, byte, cia_context->sr_bits, + cia_context->shifter, cia_context->sdr_valid, rclk)); + if ((cia_context->c_cia[CIA_CRA] & (CIA_CRA_SPMODE)) == + (CIA_CRA_SPMODE_OUT)) { + /* + * There should be a 2 clock delay before this is effective. + * That makes a difference in case there is a Timer A underflow + * in between. + * That also means that if the TA underflow isn't in the near + * future, we could do a shortcut and set the shifter + * directly. This is for later. + */ + schedule_sdr_alarm(cia_context, rclk, CIA_SDR_SET1); } + DBG(("write SDR(2) %s: %02x, sr_bits %2u, shifter %04x sdr_valid %d\n", + cia_context->myname, byte, cia_context->sr_bits, + cia_context->shifter, cia_context->sdr_valid)); + cia_context->c_cia[addr] = byte; break; /* Interrupts */ case CIA_ICR: /* Interrupt Control Register */ - CIAT_LOGIN(("store_icr: rclk=%d, byte=%02x", rclk, byte)); + CIAT_LOGIN(("store_icr: rclk=%lu, byte=%02x", rclk, byte)); cia_update_ta(cia_context, rclk); cia_update_tb(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CURRENT); + + #if defined (CIA_TIMER_DEBUG) if (cia_context->debugFlag) { log_message(cia_context->log, "cia set CIA_ICR: 0x%x.", byte); @@ -525,18 +961,45 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b cia_context->c_cia[CIA_ICR] &= ~(byte & 0x7f); } + if ((cia_context->irqflags & cia_context->c_cia[CIA_ICR] & 0x7F) != 0) { + /* Both pending interrupts and currently active interrupts + * are never cancelled or cleared. */ + if (cia_context->irq_enabled == 0) { + if (cia_context->model != CIA_MODEL_6526) { /* new CIA */ + if ((cia_context->ifr_delay & CIA_IRQ_READ1) == 0) { + cia_context->ifr_delay |= CIA_IRQ_RAISE0; + cia_context->ifr_delay |= CIA_IRQ_D7SET0; + } + } else { /* old CIA */ + cia_context->ifr_delay |= CIA_IRQ_RAISE1; + cia_context->ifr_delay |= CIA_IRQ_D7SET1; + } + } + } else { + if (cia_context->model == CIA_MODEL_6526) { + /* This relates to "old" CIA 6526. + * Currently active interrupts are never cleared. + * Setting RAISE1 (as above) in one cycle and clearing it + * here (as RAISE0) in the next cycle can potentially happen; + * and it also needs a read of the ICR 2 cycles ago. + * hmmmm... NOTE_1. + * However I can't think of any RMW instruction to do this. + */ + if ((cia_context->ifr_delay & CIA_IRQ_ACK_1) != 0) { + cia_context->ifr_delay &= ~(CIA_IRQ_RAISE0); + cia_context->ifr_delay &= ~(CIA_IRQ_D7SET0); + } + } + } + #if defined(CIA_TIMER_DEBUG) if (cia_context->debugFlag) { log_message(cia_context->log, - " set icr: ifr & ier & 0x7f -> %02x, int=%02x.", + " set icr: ifr & ier & 0x7f -> %02x, ier=%02x, ifr=%02x.", cia_context->c_cia[CIA_ICR] & cia_context->irqflags - & 0x7f, cia_context->irqflags); + & 0x7f, cia_context->c_cia[CIA_ICR], cia_context->irqflags); } #endif - if (cia_context->c_cia[CIA_ICR] & cia_context->irqflags & 0x7f) { - cia_do_set_int(cia_context, rclk + 1); - } - if (cia_context->c_cia[CIA_ICR] & CIA_IM_TA) { ciat_set_alarm(cia_context->ta, rclk); } @@ -544,15 +1007,34 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b ciat_set_alarm(cia_context->tb, rclk); } + cia_ifr_current(cia_context, rclk, CIA_IFR_NEXT); CIAT_LOGOUT(("")); break; case CIA_CRA: /* control register A */ - if ((byte & 1) && !(cia_context->c_cia[CIA_CRA] & 1)) { + cia_update_ta(cia_context, rclk); + + if ((byte & CIA_CR_START) && + !(cia_context->c_cia[CIA_CRA] & CIA_CR_START)) { + /* Starting timer A */ cia_context->tat = 1; } - cia_update_ta(cia_context, rclk); + /* Is the serial I/O direction changing? */ + if ((byte ^ cia_context->c_cia[CIA_CRA]) & CIA_CRA_SPMODE) { + strange_extra_sdr_flags(cia_context, rclk, byte); + cia_context->sr_bits = 0; + cia_context->sdr_valid = false; + cia_context->sdr_delay &= ~(ALL_SDR_TOGGLE_CNT|ALL_SDR_NOGGLE_CNT); + + if (!cia_context->cnt_out_state) { + cia_context->cnt_out_state = true; + if (cia_context->set_cnt) { + (cia_context->set_cnt)(cia_context, rclk, true); + } + /* TODO: timers driven by positive CNT edge */ + } + } ciat_set_ctrl(cia_context->ta, rclk, byte); @@ -581,10 +1063,14 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b #endif cia_context->c_cia[addr] = byte & 0xef; /* remove strobe */ + if (!ciacore_update_pb67(cia_context, rclk)) { + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + } break; case CIA_CRB: /* control register B */ - if ((byte & 1) && !(cia_context->c_cia[CIA_CRB] & 1)) { + if ((byte & 1) && !(cia_context->c_cia[CIA_CRB] & CIA_CR_START)) { cia_context->tbt = 1; } @@ -592,10 +1078,10 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b cia_update_tb(cia_context, rclk); /* bit 5 is set when single-stepping is set */ - if (byte & 0x40) { + if (byte & CIA_CRB_INMODE_TA) { /* we count ta - so we enable that */ ciat_set_alarm(cia_context->ta, rclk); - ciat_set_ctrl(cia_context->tb, rclk, (BYTE)(byte | 0x20)); + ciat_set_ctrl(cia_context->tb, rclk, (uint8_t)(byte | 0x20)); /* 0x20 = CIA_CRB_INMODE_CNT or CIAT_PHI2IN */ } else { ciat_set_ctrl(cia_context->tb, rclk, byte); } @@ -617,6 +1103,11 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b /* bit 5 & 6 timer count mode */ cia_context->c_cia[addr] = byte & 0xef; /* remove strobe */ + + if (!ciacore_update_pb67(cia_context, rclk)) { + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + } break; default: @@ -624,7 +1115,7 @@ static void ciacore_store_internal(cia_context_t *cia_context, WORD addr, BYTE b } /* switch */ } -void ciacore_store(cia_context_t *cia_context, WORD addr, BYTE value) +void ciacore_store(cia_context_t *cia_context, uint16_t addr, uint8_t value) { if (cia_context->pre_store != NULL) { (cia_context->pre_store)(); @@ -642,12 +1133,12 @@ void ciacore_store(cia_context_t *cia_context, WORD addr, BYTE value) /* ------------------------------------------------------------------------- */ -BYTE ciacore_read(cia_context_t *cia_context, WORD addr) +uint8_t ciacore_read(cia_context_t *cia_context, uint16_t addr) { #if defined(CIA_TIMER_DEBUG) - BYTE cia_read_(cia_context_t *, WORD addr); - BYTE tmp = cia_read_(cia_context, addr); + uint8_t cia_read_(cia_context_t *, uint16_t addr); + uint8_t tmp = cia_read_(cia_context, addr); if (cia_context->debugFlag) { log_message(cia_context->log, "read cia[%x] returns %02x @ clk=%d.", @@ -656,11 +1147,11 @@ BYTE ciacore_read(cia_context_t *cia_context, WORD addr) return tmp; } -BYTE cia_read_(cia_context_t *cia_context, WORD addr) +uint8_t cia_read_(cia_context_t *cia_context, uint16_t addr) { #endif - BYTE byte = 0xff; + uint8_t byte = 0xff; CLOCK rclk; addr &= 0xf; @@ -677,6 +1168,8 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) (cia_context->pre_read)(); } + run_pending_alarms(rclk, READ_OFFSET, cia_context->tb_alarm->context); + switch (addr) { case CIA_PRA: /* port A */ /* WARNING: this pin reads the voltage of the output pins, not @@ -692,24 +1185,33 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) expected due to excessive load. */ byte = (cia_context->read_ciapb)(cia_context); (cia_context->pulse_ciapc)(cia_context, rclk); + + /* Mostly identical to ciacore_update_pb67() */ if ((cia_context->c_cia[CIA_CRA] - | cia_context->c_cia[CIA_CRB]) & 0x02) { - if (cia_context->c_cia[CIA_CRA] & 0x02) { + | cia_context->c_cia[CIA_CRB]) & CIA_CR_PBON) { + + if (cia_context->c_cia[CIA_CRA] & CIA_CR_PBON) { cia_update_ta(cia_context, rclk); byte &= 0xbf; - if (((cia_context->c_cia[CIA_CRA] & 0x04) ? cia_context->tat - : ciat_is_underflow_clk(cia_context->ta, rclk))) { - byte |= 0x40; + if (((cia_context->c_cia[CIA_CRA] & CIA_CR_OUTMODE_TOGGLE) + ? cia_context->tat + : ciat_is_underflow_clk(cia_context->ta, rclk))) { + byte |= 0x40; /* PB6 for timer A */ } } - if (cia_context->c_cia[CIA_CRB] & 0x02) { + + if (cia_context->c_cia[CIA_CRB] & CIA_CR_PBON) { cia_update_tb(cia_context, rclk); byte &= 0x7f; - if (((cia_context->c_cia[CIA_CRB] & 0x04) ? cia_context->tbt - : ciat_is_underflow_clk(cia_context->tb, rclk))) { - byte |= 0x80; + if (((cia_context->c_cia[CIA_CRB] & CIA_CR_OUTMODE_TOGGLE) + ? cia_context->tbt + : ciat_is_underflow_clk(cia_context->tb, rclk))) { + byte |= 0x80; /* PB7 for timer B */ } } + + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); } cia_context->last_read = byte; return byte; @@ -718,6 +1220,8 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) /* Timers */ case CIA_TAL: /* timer A low */ cia_update_ta(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); cia_context->last_read = ciat_read_timer(cia_context->ta, rclk) & 0xff; return cia_context->last_read; @@ -725,6 +1229,8 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) case CIA_TAH: /* timer A high */ cia_update_ta(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); cia_context->last_read = (ciat_read_timer(cia_context->ta, rclk) >> 8) & 0xff; return cia_context->last_read; @@ -732,6 +1238,8 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) case CIA_TBL: /* timer B low */ cia_update_tb(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); cia_context->last_read = ciat_read_timer(cia_context->tb, rclk) & 0xff; return cia_context->last_read; @@ -739,6 +1247,8 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) case CIA_TBH: /* timer B high */ cia_update_tb(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); cia_context->last_read = (ciat_read_timer(cia_context->tb, rclk) >> 8) & 0xff; return cia_context->last_read; @@ -769,39 +1279,46 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) break; case CIA_SDR: /* Serial Port Shift Register */ - (cia_context->read_sdr)(cia_context); + if (cia_context->read_sdr) { + (cia_context->read_sdr)(cia_context); + } cia_context->last_read = cia_context->c_cia[CIA_SDR]; return cia_context->last_read; break; /* Interrupts */ - case CIA_ICR: /* Interrupt Flag Register */ + case CIA_ICR: /* Interrupt Control/Mask/Flag Register */ { - BYTE t = 0; - - CIAT_LOGIN(("read_icr: rclk=%d, rdi=%d", rclk, cia_context->rdi)); + uint8_t result = 0; - cia_context->rdi = rclk; + CIAT_LOGIN(("read_icr: A rclk=%lu, rdi=%lu", rclk, cia_context->rdi)); cia_update_ta(cia_context, rclk); cia_update_tb(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CURRENT); + + cia_context->rdi = rclk; + (cia_context->read_ciaicr)(cia_context); #ifdef CIA_TIMER_DEBUG if (cia_context->debugFlag) { log_message(cia_context->log, - "cia read intfl: rclk=%d, alarm_ta=%d, alarm_tb=%d, ciaint=%02x", - rclk, cia_tai, cia_tbi, - (int)(cia_context->irqflags)); + "read_icr: rclk=%lu, alarm_ta=%lu, alarm_tb=%lu, ciaint=%02x", + rclk, + ciat_alarm_clk(cia_context->ta), + ciat_alarm_clk(cia_context->tb), + cia_context->irqflags); } #endif ciat_set_alarm(cia_context->ta, rclk); ciat_set_alarm(cia_context->tb, rclk); - CIAT_LOG(("read_icr -> ta alarm at %d, tb at %d", + CIAT_LOG(("read_icr -> ta alarm at %lu, tb at %lu", ciat_alarm_clk(cia_context->ta), ciat_alarm_clk(cia_context->tb))); @@ -810,191 +1327,134 @@ BYTE cia_read_(cia_context_t *cia_context, WORD addr) cia_context->irqflags &= ~(CIA_IM_TBB | CIA_IM_TB); } - t = cia_context->irqflags; - - CIAT_LOG(("read intfl gives ciaint=%02x -> %02x " - "sr_bits=%d, rclk=%d", - cia_context->irqflags, t, cia_context->sr_bits, rclk)); - - cia_context->irqflags = 0; - my_set_int(cia_context, 0, rclk); - - CIAT_LOGOUT(("")); - - cia_context->last_read = t; - - return t; - } - break; - - case CIA_CRA: /* Control Register A */ - cia_update_ta(cia_context, rclk); - cia_context->last_read = (cia_context->c_cia[CIA_CRA] & 0xfe) - | ciat_is_running(cia_context->ta, rclk); - return cia_context->last_read; - break; - - case CIA_CRB: /* Control Register B */ - cia_update_tb(cia_context, rclk); - cia_context->last_read = (cia_context->c_cia[CIA_CRB] & 0xfe) - | ciat_is_running(cia_context->tb, rclk); - return cia_context->last_read; - break; - } /* switch */ - - cia_context->last_read = cia_context->c_cia[addr]; - return (cia_context->c_cia[addr]); -} - -BYTE ciacore_peek(cia_context_t *cia_context, WORD addr) -{ - /* This code assumes that update_cia is a projector - called at - * the same cycle again it doesn't change anything. This way - * it does not matter if we call it from peek first in the monitor - * and probably the same cycle again when the CPU runs on... - */ - CLOCK rclk; - BYTE byte; - - addr &= 0xf; - - if (cia_context->pre_peek != NULL) { - (cia_context->pre_peek)(); - } - - rclk = *(cia_context->clk_ptr) - READ_OFFSET; - - switch (addr) { - case CIA_PRA: /* port A */ - /* WARNING: this pin reads the voltage of the output pins, not - the ORA value. Value read might be different from what is - expected due to excessive load. */ - return (cia_context->read_ciapa)(cia_context); - break; - case CIA_PRB: /* port B */ - /* WARNING: this pin reads the voltage of the output pins, not - the ORA value. Value read might be different from what is - expected due to excessive load. */ - byte = (cia_context->read_ciapb)(cia_context); - /* (cia_context->pulse_ciapc)(rclk); */ - if ((cia_context->c_cia[CIA_CRA] | cia_context->c_cia[CIA_CRB]) & 0x02) { - if (cia_context->c_cia[CIA_CRA] & 0x02) { - cia_update_ta(cia_context, rclk); - byte &= 0xbf; - if (((cia_context->c_cia[CIA_CRA] & 0x04) ? cia_context->tat - : ciat_is_underflow_clk(cia_context->ta, rclk))) { - byte |= 0x40; - } - } - if (cia_context->c_cia[CIA_CRB] & 0x02) { - cia_update_tb(cia_context, rclk); - byte &= 0x7f; - if (((cia_context->c_cia[CIA_CRB] & 0x04) ? cia_context->tbt - : ciat_is_underflow_clk(cia_context->tb, rclk))) { - byte |= 0x80; + if (cia_context->model != CIA_MODEL_6526) /* new fast CIA */ + { + if ((cia_context->ifr_delay & CIA_IRQ_RAISE0) != 0) { + if ((cia_context->irqflags & 0x1f) != 0) { + cia_context->irqflags |= CIA_IM_SET; + } } - } - } - return byte; - break; - /* Timers */ - case CIA_TAL: /* timer A low */ - cia_update_ta(cia_context, rclk); - return ciat_read_timer(cia_context->ta, rclk) & 0xff; - break; - case CIA_TAH: /* timer A high */ - cia_update_ta(cia_context, rclk); - return (ciat_read_timer(cia_context->ta, rclk) >> 8) & 0xff; - break; - - case CIA_TBL: /* timer B low */ - cia_update_tb(cia_context, rclk); - return ciat_read_timer(cia_context->tb, rclk) & 0xff; - break; - - case CIA_TBH: /* timer B high */ - cia_update_tb(cia_context, rclk); - return (ciat_read_timer(cia_context->tb, rclk) >> 8) & 0xff; - break; - - /* - * TOD clock is latched by reading Hours, and released - * upon reading Tenths of Seconds. The counter itself - * keeps ticking all the time. - * Also note that this latching is different from the input one. - */ - case CIA_TOD_TEN: /* Time Of Day clock 1/10 s */ - case CIA_TOD_SEC: /* Time Of Day clock sec */ - case CIA_TOD_MIN: /* Time Of Day clock min */ - case CIA_TOD_HR: /* Time Of Day clock hour */ - if (cia_context->todlatched) { - return cia_context->todlatch[addr - CIA_TOD_TEN]; - } - return cia_context->c_cia[addr]; - - case CIA_SDR: /* Serial Port Shift Register */ - (cia_context->read_sdr)(cia_context); - return cia_context->c_cia[CIA_SDR]; - break; - - /* Interrupts */ - - case CIA_ICR: /* Interrupt Flag Register */ - { - BYTE t = 0; - - CIAT_LOGIN(("peek_icr: rclk=%d, rdi=%d", rclk, cia_context->rdi)); - - /* cia_context->rdi = rclk; */ - - cia_update_ta(cia_context, rclk); - cia_update_tb(cia_context, rclk); - - /* read_ciaicr(); */ - -#ifdef CIA_TIMER_DEBUG - if (cia_context->debugFlag) { - log_message(cia_context->log, - "cia read intfl: rclk=%d, alarm_ta=%d, alarm_tb=%d, ciaint=%02x", - rclk, cia_tai, cia_tbi, (int)(cia_context->irqflags)); + if ((cia_context->irqflags & 0x9F) != 0) { + cia_context->ack_irqflags |= ((cia_context->irqflags & 0x9F) | 0x80); + } + cia_context->ifr_delay |= CIA_IRQ_ACK1; + cia_context->ifr_delay &= ~(CIA_IRQ_RAISE0); + cia_context->ifr_delay &= ~(CIA_IRQ_D7SET0); + result = cia_context->irqflags; + } else { + cia_context->ifr_delay |= CIA_IRQ_ACK1; + cia_context->ifr_delay &= ~(CIA_IRQ_RAISE0); + result = cia_context->irqflags; + cia_context->irqflags &= CIA_IM_SET; + cia_context->new_irqflags = 0; + /* ack_irqflags effectively isn't used for old CIAs */ } -#endif - ciat_set_alarm(cia_context->ta, rclk); - ciat_set_alarm(cia_context->tb, rclk); + cia_context->ifr_delay |= CIA_IRQ_READ0; - CIAT_LOG(("peek_icr -> ta alarm at %d, tb at %d", - ciat_alarm_clk(cia_context->ta), - ciat_alarm_clk(cia_context->tb))); + my_set_int(cia_context, false, rclk); - t = cia_context->irqflags; + CIAT_LOG(("read_icr: Z gives ciaint=%02x -> %02x " + "sr_bits=%u, rclk=%lu", + (uint8_t)cia_context->irqflags, result, cia_context->sr_bits, rclk)); + cia_ifr_current(cia_context, rclk, CIA_IFR_NEXT); - CIAT_LOG(("peek intfl gives ciaint=%02x -> %02x " - "sr_bits=%d, rclk=%d", - cia_context->irqflags, t, cia_context->sr_bits, rclk)); -/* - cia_context->irqflags = 0; - my_set_int(0, rclk + 1); -*/ CIAT_LOGOUT(("")); - return (t); + cia_context->last_read = result; + + return result; } + break; + case CIA_CRA: /* Control Register A */ cia_update_ta(cia_context, rclk); - return (cia_context->c_cia[CIA_CRA] & 0xfe) | ciat_is_running(cia_context->ta, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + cia_context->last_read = (cia_context->c_cia[CIA_CRA] & ~CIA_CR_START) + | ciat_is_running(cia_context->ta, rclk); + return cia_context->last_read; break; case CIA_CRB: /* Control Register B */ cia_update_tb(cia_context, rclk); - return (cia_context->c_cia[CIA_CRB] & 0xfe) | ciat_is_running(cia_context->tb, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + cia_context->last_read = (cia_context->c_cia[CIA_CRB] & ~CIA_CR_START) + | ciat_is_running(cia_context->tb, rclk); + return cia_context->last_read; break; } /* switch */ + cia_context->last_read = cia_context->c_cia[addr]; return (cia_context->c_cia[addr]); } +/* FIXME: this function should return the current state of the registers + without affecting the state of the emulation. */ +uint8_t ciacore_peek(cia_context_t *cia_context, uint16_t addr) +{ + uint8_t ret; + + addr &= 0xf; + + switch (addr) { + /* reading the ports should have no side effects, we do however have + to use the read function to update the port lines. + */ + case CIA_PRA: + case CIA_PRB: + /* reading the DDR should have no side effects */ + case CIA_DDRA: + case CIA_DDRB: + /* reading the timer values should have no side effects, we do however + have to use the read function to update the timers + */ + case CIA_TAL: + case CIA_TAH: + case CIA_TBL: + case CIA_TBH: + ret = ciacore_read(cia_context, addr); + break; + /* reading the hours and tenth secs latches/unlatches the TOD, so we + directly return the counter values here */ + case CIA_TOD_TEN: + case CIA_TOD_SEC: + case CIA_TOD_MIN: + case CIA_TOD_HR: + ret = cia_context->c_cia[addr]; + break; + /* Serial Port Shift Register + * FIXME: does reading SDR have side effects? do we need to update it? + */ + case CIA_SDR: + ret = cia_context->c_cia[CIA_SDR]; + break; + /* reading ICR will clear it + * FIXME: this is likely broken + */ + case CIA_ICR: + ret = cia_context->irqflags; + break; + /* reading the control registers should have no side effects, we do however + have to use the read function to update the timers for bit 0 + */ + case CIA_CRA: + case CIA_CRB: + ret = ciacore_read(cia_context, addr); + break; + } + + /* FIXME: perhaps we need to restore some of the state from before reading. + * needs testing. + * NOTE: cia_context->last_read is only used to handle RMW instructions, + * since we only ever call this function in between instructions, + * we dont have to restore it's value. + */ + return ret; +} + BYTE c64d_iecbus_cpu_peek_conf1(); extern int c64iec_active; @@ -1184,68 +1644,71 @@ static void ciacore_intta(CLOCK offset, void *data) rclk = *(cia_context->clk_ptr) - offset; - CIAT_LOGIN(("ciaTimerA ciacore_intta: myclk=%d rclk=%d", + CIAT_LOGIN(("ciaTimerA ciacore_intta: myclk=%lu rclk=%lu", *(cia_context->clk_ptr), rclk)); -#if 0 - if ((n = ciat_update(cia_context->ta, rclk)) - && (cia_context->rdi != rclk - 1)) { - cia_context->irqflags |= CIA_IM_TA; - cia_context->tat = (cia_context->tat + n) & 1; - } -#else - cia_do_update_ta(cia_context, rclk); -#endif + cia_do_update_ta(cia_context, rclk); /* may set CIA_IM_TA */ ciat_ack_alarm(cia_context->ta, rclk); CIAT_LOG(( - "ciacore_intta(rclk = %u, tal = %u, cra=%02x, int=%02x, ier=%02x.", + "ciacore_intta(rclk = %lu, tal = %lu, cra=%02x, int=%02x, ier=%02x.", rclk, ciat_read_latch(cia_context->ta, rclk), cia_context->c_cia[CIA_CRA], cia_context->irqflags, cia_context->c_cia[CIA_ICR])); /* cia_context->tat = (cia_context->tat + 1) & 1; */ - if ((cia_context->c_cia[CIA_CRA] & 0x29) == 0x01) { + if ((cia_context->c_cia[CIA_CRA] & (CIA_CRA_INMODE|CIA_CR_RUNMODE|CIA_CR_START)) + == (CIA_CRA_INMODE_PHI2|CIA_CR_RUNMODE_CONTINUOUS|CIA_CR_START)) { /* if we do not need alarm, no PB6, no shift register, and not timer B - counting timer A, then we can savely skip alarms... */ + counting timer A, then we can safely skip alarms... */ if (((cia_context->c_cia[CIA_ICR] & CIA_IM_TA) && - (!(cia_context->irqflags & 0x80))) - || (cia_context->c_cia[CIA_CRA] & 0x42) - || (cia_context->c_cia[CIA_CRB] & 0x40)) { + (!(cia_context->irqflags & CIA_IM_SET))) + || (cia_context->c_cia[CIA_CRA] & (CIA_CRA_SPMODE|CIA_CRA_INMODE)) /* != CIA_CRA_SPMODE_IN|CIA_CRA_INMODE_PHI2 */ + || (cia_context->c_cia[CIA_CRB] & CIA_CRB_INMODE_TA)) { ciat_set_alarm(cia_context->ta, rclk); } } - if (cia_context->c_cia[CIA_CRA] & 0x40) { - if (cia_context->sr_bits) { - CIAT_LOG(("rclk=%d SDR: timer A underflow, bits=%d", - rclk, cia_context->sr_bits)); - - if (!(--(cia_context->sr_bits))) { - cia_context->irqflags |= CIA_IM_SDR; - /*printf("%s: rclk=%d, store_sdr(%02x, '%c'\n", - cia_context->myname, - rclk, cia_context->shifter);*/ - (cia_context->store_sdr)(cia_context, cia_context->shifter); + if ((cia_context->c_cia[CIA_CRA] & CIA_CRA_SPMODE_OUT)) { + /* + * ~1.5 cycle delay until CNT is toggled. + */ + if (cia_context->sr_bits != 0 || cia_context->sdr_valid) { + uint32_t event = CIA_SDR_TOGGLE_CNT1; + /* + * If the clock pulses come too close together, we can't detect + * the transition of the timer A output any more... + * (This is generally only relevant if the timer starts at 0000) + */ + if (cia_context->sdr_delay & (CIA_SDR_TOGGLE_CNT0|CIA_SDR_NOGGLE_CNT0)) { + event = CIA_SDR_NOGGLE_CNT1; } - } - if ((!(cia_context->sr_bits)) && cia_context->sdr_valid) { - cia_context->shifter = cia_context->c_cia[CIA_SDR]; - cia_context->sdr_valid = 0; - cia_context->sr_bits = 14; + schedule_sdr_alarm(cia_context, rclk, event); } } - if ((cia_context->c_cia[CIA_CRB] & 0x41) == 0x41) { + + if ((cia_context->c_cia[CIA_CRB] & (CIA_CRB_INMODE_TA|CIA_CR_START)) == (CIA_CRB_INMODE_TA|CIA_CR_START)) { cia_update_tb(cia_context, rclk); cia_do_step_tb(cia_context, rclk); } - cia_do_set_int(cia_context, rclk); - CIAT_LOGOUT(("")); } +/* + * Entry point for alarm callbacks. + */ +static void ciacore_intta_entry(CLOCK offset, void *data) +{ + cia_context_t *cia_context = (cia_context_t *)data; + CLOCK rclk = *(cia_context->clk_ptr) - offset; + + ciacore_intta(offset, data); + + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); +} /* * Timer B can run in 2 (4) modes @@ -1262,7 +1725,7 @@ static void ciacore_inttb(CLOCK offset, void *data) rclk = *(cia_context->clk_ptr) - offset; - CIAT_LOGIN(("ciaTimerB int_myciatb: myclk=%d, rclk=%d", + CIAT_LOGIN(("ciaTimerB int_myciatb: myclk=%lu, rclk=%lu", *(cia_context->clk_ptr), rclk)); cia_do_update_tb(cia_context, rclk); @@ -1270,48 +1733,298 @@ static void ciacore_inttb(CLOCK offset, void *data) ciat_ack_alarm(cia_context->tb, rclk); CIAT_LOG(( - "timer B ciacore_inttb(rclk=%d, crb=%d, int=%02x, ier=%02x).", + "timer B ciacore_inttb(rclk=%lu, crb=%d, int=%02x, ier=%02x).", rclk, cia_context->c_cia[CIA_CRB], cia_context->irqflags, cia_context->c_cia[CIA_ICR])); /* cia_context->tbt = (cia_context->tbt + 1) & 1; */ /* running and continous, then next alarm */ - if ((cia_context->c_cia[CIA_CRB] & 0x69) == 0x01) { + if ((cia_context->c_cia[CIA_CRB] & (CIA_CRB_INMODE|CIA_CR_RUNMODE|CIA_CR_START)) == + (CIA_CRB_INMODE_PHI2|CIA_CR_RUNMODE_CONTINUOUS|CIA_CR_START)) { /* if no interrupt flag we can safely skip alarms */ if (cia_context->c_cia[CIA_ICR] & CIA_IM_TB) { ciat_set_alarm(cia_context->tb, rclk); } } - cia_do_set_int(cia_context, rclk); - CIAT_LOGOUT(("")); } +/* + * Entry point for alarm callbacks. + */ +static void ciacore_inttb_entry(CLOCK offset, void *data) +{ + cia_context_t *cia_context = (cia_context_t *)data; + CLOCK rclk = *(cia_context->clk_ptr) - offset; + + ciacore_inttb(offset, data); + + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); +} + /* ------------------------------------------------------------------------- */ -void ciacore_set_flag(cia_context_t *cia_context) +/* + * The next several functions can be called from outside the CIA + * to set the FLAG, CNT or SP input lines, or the whole SDR at once + * (which is cheating). + */ + +static void ciacore_async_interrupt(cia_context_t *cia_context, int flag) { - cia_context->irqflags |= CIA_IM_FLG; - if (cia_context->c_cia[CIA_ICR] & CIA_IM_FLG) { - cia_context->irqflags |= 0x80; - my_set_int(cia_context, cia_context->irq_line, - *(cia_context->clk_ptr)); + /* + * This is for when an external signal has come in, + * which doesn't synchronize with our internal activities. + */ + CLOCK rclk = *(cia_context->clk_ptr); + + cia_set_irq_flag(cia_context, rclk, flag); + + /* + * Leave calling cia_ifr_current() to the idle (or another) alarm, + * since we're totally async here. + */ + CLOCK idleclk = alarm_clk(cia_context->idle_alarm); + if (idleclk > rclk + 1) { + /* + * If not already scheduled for the near future, re-schedule + * it sooner. We could schedule it for rclk+0 if we could be + * sure it won't be scheduled twice then (but we can't). + */ + alarm_set(cia_context->idle_alarm, rclk + 1); + } else { + DBG(("ciacore_async_interrupt: idleclk == rclk + %ld", (long)(idleclk - rclk))); } } -void ciacore_set_sdr(cia_context_t *cia_context, BYTE data) +void ciacore_set_flag(cia_context_t *cia_context) +{ + DBG(("ciacore_set_flag")); + ciacore_async_interrupt(cia_context, CIA_IM_FLG); +} + +/* + * Shortcut to shift a whole byte into the shift register all at once + * instead of bit-by-bit. + */ +void ciacore_set_sdr(cia_context_t *cia_context, uint8_t data) { - if (!(cia_context->c_cia[CIA_CRA] & 0x40)) { + if ((cia_context->c_cia[CIA_CRA] & CIA_CRA_SPMODE) == CIA_CRA_SPMODE_IN) { + cia_context->c_cia[CIA_SDR] = data; - cia_context->irqflags |= CIA_IM_SDR; - if (cia_context->c_cia[CIA_ICR] & CIA_IM_SDR) { - cia_context->irqflags |= 0x80; - my_set_int(cia_context, cia_context->irq_line, - *(cia_context->clk_ptr)); + DBG(("ciacore_set_sdr %s: %02x", cia_context->myname, data)); + + /* + * For more cycle-exactness, something like + * cia_context->sdr_delay |= CIA_SDR_SET_SDR_IRQ2; + * and enable the sdr_alarm ? + */ + ciacore_async_interrupt(cia_context, CIA_IM_SDR); + + alarm_unset(cia_context->sdr_alarm); + } +} + +void ciacore_set_cnt(cia_context_t *cia_context, bool data) +{ + /* Is the CNT input changing? */ + if (data != cia_context->cnt_in_state) { + /* Is the shift register set to input? */ + if ((cia_context->c_cia[CIA_CRA] & CIA_CRA_SPMODE) == CIA_CRA_SPMODE_IN) { + /* Is this the right way to start shifting a byte? */ + if (!data && cia_context->sr_bits == 0) { + cia_context->sr_bits = 16; + } + + cia_context->sr_bits--; + + /* Is it rising? */ + if (data) { + /* Shift register */ + cia_context->shifter <<= 1; + /* https://www.forum64.de/index.php?thread/109935-mos6526-cia-detailed-test-vectors-and-models/&pageNo=2 + * "My impression was that after the positive edge of CNT the + * CIA samples SP on the second rising edge of PHI2 following + * the next falling edge of PHI2. That's true even if CNT goes + * low again before this time (but a second rising edge of CNT + * before the data is sampled seems to kill the cycle). This + * would suggest that it takes 1,5 (best case) to 3,5 (worst + * case) PHI2 cycles to sample the data, depending on the phase + * difference between PHI2 and CNT. And I could in fact + * "reliably" transfer data into the SR with about double the + * nominal rate (that it, 2 x PHI2 instead of 4 x) when I + * aligned CNT to just before the negative PHI2 edges." + * + * We ignore that for now and sample and shift immediately. + */ + cia_context->shifter |= cia_context->sp_in_state; + + if (cia_context->sr_bits == 0) { + ciacore_set_sdr(cia_context, cia_context->shifter & 0xFF); + /* Most likely not needed: + * cia_context->sr_bits = 16; + * because it's set to 16 anyway on the next falling edge. + */ + } + } + } + /* TODO: Handle Timer B if it is in CNT pulse counting mode */ + cia_context->cnt_in_state = data; + } +} + +void ciacore_set_sp(cia_context_t *cia_context, bool data) +{ + cia_context->sp_in_state = data & 1; +} + +/* ------------------------------------------------------------------------- */ + +/* + * Schedule a new alarm, for the current cycle. + * That means it should normally be invoked only from a CPU register access, + * not from an alarm. + */ +static void schedule_sdr_alarm(cia_context_t *cia_context, CLOCK rclk, uint32_t feed) +{ + cia_context->sdr_delay |= feed; + alarm_set(cia_context->sdr_alarm, rclk); +} + +/* + * Alarm to handle the shift register for some cycles after TA reaches 0000. + * + * We need to make sure that if this alarm and also ciacore_intta + * is scheduled for the same clock, that TA is handled first. + * If this one runs first, ciacore_intta will schedule another run of intsdr + * for the same cycle... + */ +static void ciacore_intsdr(CLOCK offset, void *data) +{ + cia_context_t *cia_context = (cia_context_t *)data; + CLOCK rclk = *(cia_context->clk_ptr) - offset; + uint32_t feed = 0; + + DBG(("ciacore_intsdr: sr_bits %u, shifter %04x sdr_valid %d sdr_delay %05x\n", cia_context->sr_bits, cia_context->shifter, cia_context->sdr_valid, cia_context->sdr_delay)); + + if (alarm_clk(cia_context->ta_alarm) == rclk) { + /* INT TA scheduled at the same clock cycle - do that one first */ + ciacore_intta(offset, data); + } + + if (cia_context->sdr_delay & CIA_SDR_SET0) { + if (cia_context->sr_bits == 0) { + cia_context->sr_bits = 16; + cia_context->shifter = cia_context->c_cia[CIA_SDR] << 1; + } else if (cia_context->sr_bits == 1) { + /* If this case is even possible, because when sr_bits + * is decremented to 1 at TA underflow, + * the value is loaded already and sr_bits is set to 17. + */ + cia_context->shifter |= cia_context->c_cia[CIA_SDR]; + cia_context->sr_bits = 17; + } else { + cia_context->sdr_valid = true; + } + } + + if (cia_context->sdr_delay & CIA_SDR_TOGGLE_CNT0) { + /* + * TODO: should this condition be re-checked here, or should the + * event bit be cleared when it becomes false elsewhere? + *if (cia_context->sr_bits || cia_context->sdr_valid) + */ + { + CIAT_LOG(("rclk=%lu SDR: timer A underflow, bits=%u", + rclk, cia_context->sr_bits)); + + if (cia_context->sr_bits && (--cia_context->sr_bits & 1)) { + + /*printf("%s: rclk=%d, store_sdr(%02x, '%c'\n", + cia_context->myname, + rclk, cia_context->shifter);*/ + + if (cia_context->set_sp) { + /* Note: the bit that's just left of the byte */ + bool bit = (cia_context->shifter >> 8) & 1; + (cia_context->set_sp)(cia_context, rclk, bit); + } + cia_context->cnt_out_state = false; + if (cia_context->set_cnt) { + (cia_context->set_cnt)(cia_context, rclk, false); + } + + if (cia_context->sr_bits == 1) { + DBG(("(store_sdr) %s: %04x %02x rclk %lu\n", cia_context->myname, cia_context->shifter, cia_context->shifter>>8, rclk)); + (cia_context->store_sdr)(cia_context, (cia_context->shifter >> 8) & 0xFF); + /* IFR/IRQ requires 2 cycle delay */ + feed |= CIA_SDR_SET_SDR_IRQ2; + /* TODO: maybe unset the other SET_SDR_IRQx bits? */ + + if (cia_context->sdr_valid) { + cia_context->shifter |= cia_context->c_cia[CIA_SDR]; + cia_context->sdr_valid = false; + cia_context->sr_bits = 17; + } + } + } else { + /* So either sr_bits was 0, or after decrementing it is even. */ + cia_context->shifter <<= 1; + + cia_context->cnt_out_state = true; + if (cia_context->set_cnt) { + (cia_context->set_cnt)(cia_context, rclk, true); + } + } + } + DBG(("ciacore_intta(2): sr_bits %u, shifter %04x sdr_valid %d\n", cia_context->sr_bits, cia_context->shifter, cia_context->sdr_valid)); + } + + if (cia_context->sdr_delay & CIA_SDR_SET_SDR_IRQ0) { + DBG(("ciacore_intsdr: set CIA_IM_SDR %lu\n", rclk)); + cia_set_irq_flag(cia_context, rclk, CIA_IM_SDR); + } + + cia_context->sdr_delay |= feed; + cia_context->sdr_delay <<= 1; + cia_context->sdr_delay &= ~CIA_SDR_CLEAR; + + if (cia_context->cnt_out_state) { + cia_context->sdr_delay |= CIA_SDR_CNT0; + } + + bool active = (cia_context->sdr_delay & CIA_SDR_ACTIVE) != 0; + if (!active) { + uint32_t all_cnt = cia_context->sdr_delay & ALL_SDR_CNT; + + if (all_cnt != 0 && all_cnt != ALL_SDR_CNT) { + active = true; } } + if (active) { + alarm_set(cia_context->sdr_alarm, rclk + 1); + } else { + alarm_unset(cia_context->sdr_alarm); + } +} + +/* + * Entry point for alarm callbacks. + */ +static void ciacore_intsdr_entry(CLOCK offset, void *data) +{ + cia_context_t *cia_context = (cia_context_t *)data; + CLOCK rclk = *(cia_context->clk_ptr) - offset; + + ciacore_intsdr(offset, data); + + cia_ifr_catchup(cia_context, rclk); + if (cia_context->ifr_clock == rclk) { /* don't call it twice */ + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + } } /* ------------------------------------------------------------------------- */ @@ -1322,7 +2035,7 @@ void ciacore_set_sdr(cia_context_t *cia_context, BYTE data) static void ciacore_inttod(CLOCK offset, void *data) { - int t0, t1, t2, t3, t4, t5, t6, pm, update = 0; + int ts, sl, sh, ml, mh, hl, hh, pm, update = 0; CLOCK rclk, tclk; cia_context_t *cia_context = (cia_context_t *)data; @@ -1336,7 +2049,7 @@ static void ciacore_inttod(CLOCK offset, void *data) return; } - /* set up new int + /* set up new int the time between power ticks should be ticks_per_sec / power_freq in reality the deviation can be quite large in small time frames, but is very accurate in longer time frames. we try to maintain a stable tick @@ -1375,69 +2088,76 @@ static void ciacore_inttod(CLOCK offset, void *data) alarm_set(cia_context->tod_alarm, cia_context->todclk); if (!(cia_context->todstopped)) { - /* count 50/60 hz ticks */ - cia_context->todtickcounter++; - /* wild assumption: counter is 3 bits and is not reset elsewhere */ - /* FIXME: this doesnt seem to be 100% correct - apparently it is reset - in some cases */ - cia_context->todtickcounter &= 7; - - /* if the counter matches the TOD frequency ... */ - if (cia_context->todtickcounter == - ((cia_context->c_cia[CIA_CRA] & 0x80) ? 5 : 6)) { - /* reset the counter and update the timer */ + /* + * The divider which divides the 50 or 60 Hz power supply ticks into + * 10 Hz uses a 3-bit ring counter, which goes 000, 001 011, 111, 110, + * 100. + * For 50 Hz: matches at 110 (like "4") + * For 60 Hz: matches at 100 (like "5") + * (the middle bit of the match value is CRA7) + * After a match there is a 1 tick delay (until the next power supply + * tick) and then the 1/10 seconds counter increases, and the ring + * resets to 000. + */ + update = (cia_context->todtickcounter == + ((cia_context->c_cia[CIA_CRA] & CIA_CRA_TODIN_50HZ) ? 4 : 5)); + + if (update) { + /* Reset the counter */ cia_context->todtickcounter = 0; - update = 1; + } else { + /* Count 50/60 Hz power supply ticks */ + cia_context->todtickcounter++; + /* Ring counter of 3 bits has 6 states */ + if (cia_context->todtickcounter > 5) + cia_context->todtickcounter = 0; } } if (update) { /* advance the counters. - * - individual counters are all 4 bit + * - individual counters are 4 bit + * except for sh and mh which are 3 bits */ - t0 = cia_context->c_cia[CIA_TOD_TEN] & 0x0f; - t1 = cia_context->c_cia[CIA_TOD_SEC] & 0x0f; - t2 = (cia_context->c_cia[CIA_TOD_SEC] >> 4) & 0x0f; - t3 = cia_context->c_cia[CIA_TOD_MIN] & 0x0f; - t4 = (cia_context->c_cia[CIA_TOD_MIN] >> 4) & 0x0f; - t5 = cia_context->c_cia[CIA_TOD_HR] & 0x0f; - t6 = (cia_context->c_cia[CIA_TOD_HR] >> 4) & 0x01; + ts = cia_context->c_cia[CIA_TOD_TEN] & 0x0f; + sl = cia_context->c_cia[CIA_TOD_SEC] & 0x0f; + sh = (cia_context->c_cia[CIA_TOD_SEC] >> 4) & 0x07; + ml = cia_context->c_cia[CIA_TOD_MIN] & 0x0f; + mh = (cia_context->c_cia[CIA_TOD_MIN] >> 4) & 0x07; + hl = cia_context->c_cia[CIA_TOD_HR] & 0x0f; + hh = (cia_context->c_cia[CIA_TOD_HR] >> 4) & 0x01; pm = cia_context->c_cia[CIA_TOD_HR] & 0x80; /* tenth seconds (0-9) */ - t0 = (t0 + 1) & 0x0f; - if (t0 == 10) { - t0 = 0; + ts = (ts + 1) & 0x0f; + if (ts == 10) { + ts = 0; /* seconds (0-59) */ - t1 = (t1 + 1) & 0x0f; /* x0...x9 */ - if (t1 == 10) { - t1 = 0; - t2 = (t2 + 1) & 0x07; /* 0x...5x */ - if (t2 == 6) { - t2 = 0; + sl = (sl + 1) & 0x0f; /* x0...x9 */ + if (sl == 10) { + sl = 0; + sh = (sh + 1) & 0x07; /* 0x...5x */ + if (sh == 6) { + sh = 0; /* minutes (0-59) */ - t3 = (t3 + 1) & 0x0f; /* x0...x9 */ - if (t3 == 10) { - t3 = 0; - t4 = (t4 + 1) & 0x07; /* 0x...5x */ - if (t4 == 6) { - t4 = 0; + ml = (ml + 1) & 0x0f; /* x0...x9 */ + if (ml == 10) { + ml = 0; + mh = (mh + 1) & 0x07; /* 0x...5x */ + if (mh == 6) { + mh = 0; /* hours (1-12) */ - t5 = (t5 + 1) & 0x0f; - if (t6) { - /* toggle the am/pm flag when going from 11 to 12 (!) */ - if (t5 == 2) { - pm ^= 0x80; - } - /* wrap 12h -> 1h (FIXME: when hour became x3 ?) */ - if (t5 == 3) { - t5 = 1; - t6 = 0; - } + /* flip from 09:59:59 to 10:00:00 */ + /* or from 12:59:59 to 01:00:00 */ + if (((hh == 1) && (hl == 2)) + || ((hh == 0) && (hl == 9))) { + hl = hh; + hh ^= 1; } else { - if (t5 == 10) { - t5 = 0; - t6 = 1; + hl = (hl + 1) & 0x0f; + /* toggle the am/pm flag when reaching 12 */ + if ((hh == 1) && (hl == 2)) { + pm ^= 0x80; } } } @@ -1452,12 +2172,12 @@ static void ciacore_inttod(CLOCK offset, void *data) cia_context->c_cia[CIA_TOD_MIN], cia_context->c_cia[CIA_TOD_SEC], cia_context->c_cia[CIA_TOD_TEN], - pm ? "pm" : "am", t6, t5, t4, t3, t2, t1, t0)); + pm ? "pm" : "am", hh, hl, mh, ml, sh, sl, ts)); - cia_context->c_cia[CIA_TOD_TEN] = t0; - cia_context->c_cia[CIA_TOD_SEC] = t1 | (t2 << 4); - cia_context->c_cia[CIA_TOD_MIN] = t3 | (t4 << 4); - cia_context->c_cia[CIA_TOD_HR] = t5 | (t6 << 4) | pm; + cia_context->c_cia[CIA_TOD_TEN] = ts; + cia_context->c_cia[CIA_TOD_SEC] = sl | (sh << 4); + cia_context->c_cia[CIA_TOD_MIN] = ml | (mh << 4); + cia_context->c_cia[CIA_TOD_HR] = hl | (hh << 4) | pm; /* check alarm */ check_ciatodalarm(cia_context, rclk); @@ -1465,9 +2185,25 @@ static void ciacore_inttod(CLOCK offset, void *data) } #undef TODRANDOM +/* + * Entry point for alarm callbacks. + */ +static void ciacore_inttod_entry(CLOCK offset, void *data) +{ + cia_context_t *cia_context = (cia_context_t *)data; + CLOCK rclk = *(cia_context->clk_ptr) - offset; + + ciacore_inttod(offset, data); + + cia_ifr_catchup(cia_context, rclk); + if (cia_context->ifr_clock == rclk) { /* don't call it twice */ + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + } +} + void ciacore_setup_context(cia_context_t *cia_context) { - cia_context->log = LOG_ERR; + cia_context->log = LOG_DEFAULT; cia_context->read_clk = 0; cia_context->read_offset = 0; cia_context->last_read = 0; @@ -1475,20 +2211,6 @@ void ciacore_setup_context(cia_context_t *cia_context) cia_context->model = 0; } -#define USE_IDLE_CALLBACK - -#ifdef USE_IDLE_CALLBACK -/* - we must take care to choose a value which is small enough so the counters do - not fall behind too much to cause a significant peak in cpu usage, and one - that is big enough so the overall performance impact is not too big. - it seems reasonable to also consider how peaks in cpu usage interact with - automatic framerate adjustment, so choosing a value that makes sure a more - or less constant amount of cpu time per frame is consumed is a good idea. - (about 20000 cycles are a full PAL frame on the C64, making sure that we do - not fall behind one frame at all seems a good idea.) - */ -#define CIA_MAX_IDLE_CYCLES 5000 /* this callback takes care of the problem that when ciat_update has to catch up with an excessive amount of clock cycles it will consume a lot of cpu @@ -1505,17 +2227,26 @@ static void ciacore_idle(CLOCK offset, void *data) clk = *(cia_context->clk_ptr); rclk = clk - offset; -/* printf("ciacore_idle: clk=%d rclk=%d\n", clk, rclk); */ +/* printf("ciacore_idle: clk=%lu rclk=%lu\n", clk, rclk); */ cia_update_ta(cia_context, rclk); cia_update_tb(cia_context, rclk); + /* + * Schedule another idle alarm far in the future. + * Do it before running the ifr delay line, in case that it wants + * to schedule it for sooner (we don't want to override that here). + */ alarm_set(cia_context->idle_alarm, rclk + CIA_MAX_IDLE_CYCLES); + + cia_ifr_catchup(cia_context, rclk); + if (cia_context->ifr_clock == rclk) { /* don't call it twice */ + cia_ifr_current(cia_context, rclk, CIA_IFR_CUR_NXT); + } } -#endif void ciacore_init(cia_context_t *cia_context, alarm_context_t *alarm_context, - interrupt_cpu_status_t *int_status, clk_guard_t *clk_guard) + interrupt_cpu_status_t *int_status) { char *buffer; @@ -1525,34 +2256,40 @@ void ciacore_init(cia_context_t *cia_context, alarm_context_t *alarm_context, ciat_init_table(); cia_context->log = log_open(cia_context->myname); -#ifdef USE_IDLE_CALLBACK + buffer = lib_msprintf("%s_IDLE", cia_context->myname); - cia_context->idle_alarm = alarm_new(alarm_context, buffer, ciacore_idle, + cia_context->idle_alarm = alarm_new(alarm_context, buffer, + ciacore_idle, (void *)cia_context); lib_free(buffer); - alarm_set(cia_context->idle_alarm, *(cia_context->clk_ptr) + CIA_MAX_IDLE_CYCLES); -#endif + buffer = lib_msprintf("%s_TA", cia_context->myname); - cia_context->ta_alarm = alarm_new(alarm_context, buffer, ciacore_intta, + cia_context->ta_alarm = alarm_new(alarm_context, buffer, + ciacore_intta_entry, (void *)cia_context); lib_free(buffer); buffer = lib_msprintf("%s_TB", cia_context->myname); - cia_context->tb_alarm = alarm_new(alarm_context, buffer, ciacore_inttb, + cia_context->tb_alarm = alarm_new(alarm_context, buffer, + ciacore_inttb_entry, (void *)cia_context); lib_free(buffer); buffer = lib_msprintf("%s_TOD", cia_context->myname); - cia_context->tod_alarm = alarm_new(alarm_context, buffer, ciacore_inttod, + cia_context->tod_alarm = alarm_new(alarm_context, buffer, + ciacore_inttod_entry, + (void *)cia_context); + lib_free(buffer); + + buffer = lib_msprintf("%s_SDR", cia_context->myname); + cia_context->sdr_alarm = alarm_new(alarm_context, buffer, + ciacore_intsdr_entry, (void *)cia_context); lib_free(buffer); cia_context->int_num = interrupt_cpu_status_int_new(int_status, cia_context->myname); - clk_guard_add_callback(clk_guard, ciacore_clk_overflow_callback, - cia_context); - buffer = lib_msprintf("%s_TA", cia_context->myname); ciat_init(cia_context->ta, buffer, *(cia_context->clk_ptr), cia_context->ta_alarm); @@ -1562,9 +2299,17 @@ void ciacore_init(cia_context_t *cia_context, alarm_context_t *alarm_context, ciat_init(cia_context->tb, buffer, *(cia_context->clk_ptr), cia_context->tb_alarm); lib_free(buffer); - + + /* Clear the optional callbacks */ + cia_context->set_sp = NULL; + cia_context->set_cnt = NULL; + + /* This is not internal state, so does not get reset on RESET */ + cia_context->sp_in_state = true; + cia_context->cnt_in_state = true; + // c64d: C64 debugger - cia_context->c64d_irq_flag = 0; + VICE_HOOK_CIA_IRQ_FLAG_CLEAR(cia_context); } void ciacore_shutdown(cia_context_t *cia_context) @@ -1580,11 +2325,11 @@ void ciacore_shutdown(cia_context_t *cia_context) /* The dump format has a module header and the data generated by the * chip... * - * The version of this dump description is 2.2 + * The version of this dump description is 2.5 */ #define CIA_DUMP_VER_MAJOR 2 -#define CIA_DUMP_VER_MINOR 2 +#define CIA_DUMP_VER_MINOR 5 /* * The dump data: @@ -1638,20 +2383,40 @@ void ciacore_shutdown(cia_context_t *cia_context) * BYTE irq_enabled IRQ enabled * * BYTE todtickcounter TOD tick counter + * + * These bits have been added in V2.3 + * + * BYTE SHIFTER_HI high byte of SHIFTER + * BYTE SDR_ALARM if an sdr_alarm is pending and when + * BYTE SP_CNT_IN input state of SP and CNT + * + * These bits have been added in V2.4 + * + * DWORD SDR_DELAY event/history bits for the serial data register + * BYTE SP_CNT_OUT output state of SP and CNT + * + * These bits have been added in V2.5 + * + * DWORD IFR_DELAY event/history bits for the interrupt flag reg. + * BYTE ACK_IRQFLAGS flags in IFR to acknowledge, i.e. clear. + * BYTE NEW_IRQFLAGS new flags in IFR that were set recently. */ /* FIXME!!! Error check. */ int ciacore_snapshot_write_module(cia_context_t *cia_context, snapshot_t *s) { + CLOCK rclk = *(cia_context->clk_ptr); snapshot_module_t *m; - int byte; + uint8_t byte; - cia_update_ta(cia_context, *(cia_context->clk_ptr)); - cia_update_tb(cia_context, *(cia_context->clk_ptr)); + cia_update_ta(cia_context, rclk); + cia_update_tb(cia_context, rclk); + cia_ifr_catchup(cia_context, rclk); + cia_ifr_current(cia_context, rclk, CIA_IFR_CURRENT); m = snapshot_module_create(s, cia_context->myname, - (BYTE)CIA_DUMP_VER_MAJOR, - (BYTE)CIA_DUMP_VER_MINOR); + (uint8_t)CIA_DUMP_VER_MAJOR, + (uint8_t)CIA_DUMP_VER_MINOR); if (m == NULL) { return -1; } @@ -1659,7 +2424,7 @@ int ciacore_snapshot_write_module(cia_context_t *cia_context, snapshot_t *s) #ifdef cia_DUMP_DEBUG log_message(cia_context->log, "clk=%d, cra=%02x, crb=%02x, tas=%d, tbs=%d", - *(cia_context->clk_ptr), cia[CIA_CRA], cia[CIA_CRB], cia_tas, + rclk, cia[CIA_CRA], cia[CIA_CRB], cia_tas, cia_tbs); log_message(cia_context->log, "tai=%d, tau=%d, tac=%04x, tal=%04x", cia_tai, cia_tau, cia_tac, cia_tal); @@ -1670,70 +2435,105 @@ int ciacore_snapshot_write_module(cia_context_t *cia_context, snapshot_t *s) cia_context->c_cia[CIA_ICR]); #endif - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_PRA])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_PRB])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_DDRA])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_DDRB])); - SMW_W(m, ciat_read_timer(cia_context->ta, *(cia_context->clk_ptr))); - SMW_W(m, ciat_read_timer(cia_context->tb, *(cia_context->clk_ptr))); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_TOD_TEN])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_TOD_SEC])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_TOD_MIN])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_TOD_HR])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_SDR])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_ICR])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_CRA])); - SMW_B(m, (BYTE)(cia_context->c_cia[CIA_CRB])); - - SMW_W(m, ciat_read_latch(cia_context->ta, *(cia_context->clk_ptr))); - SMW_W(m, ciat_read_latch(cia_context->tb, *(cia_context->clk_ptr))); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_PRA])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_PRB])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_DDRA])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_DDRB])); + SMW_W(m, ciat_read_timer(cia_context->ta, rclk)); + SMW_W(m, ciat_read_timer(cia_context->tb, rclk)); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_TOD_TEN])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_TOD_SEC])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_TOD_MIN])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_TOD_HR])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_SDR])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_ICR])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_CRA])); + SMW_B(m, (uint8_t)(cia_context->c_cia[CIA_CRB])); + + SMW_W(m, ciat_read_latch(cia_context->ta, rclk)); + SMW_W(m, ciat_read_latch(cia_context->tb, rclk)); SMW_B(m, ciacore_peek(cia_context, CIA_ICR)); /* Bits 2 & 3 are compatibility to snapshot format v1.0 */ - SMW_B(m, (BYTE)((cia_context->tat ? 0x40 : 0) + SMW_B(m, (uint8_t)((cia_context->tat ? 0x40 : 0) | (cia_context->tbt ? 0x80 : 0) | (ciat_is_underflow_clk(cia_context->ta, - *(cia_context->clk_ptr)) ? 0x04 : 0) - | (ciat_is_underflow_clk(cia_context->tb, *(cia_context->clk_ptr)) + rclk) ? 0x04 : 0) + | (ciat_is_underflow_clk(cia_context->tb, rclk) ? 0x08 : 0))); - SMW_B(m, (BYTE)cia_context->sr_bits); + SMW_B(m, (uint8_t)cia_context->sr_bits); SMW_B(m, cia_context->todalarm[0]); SMW_B(m, cia_context->todalarm[1]); SMW_B(m, cia_context->todalarm[2]); SMW_B(m, cia_context->todalarm[3]); if (cia_context->rdi) { - if ((*(cia_context->clk_ptr) - cia_context->rdi) > 120) { + if ((rclk - cia_context->rdi) > 120) { byte = 0; } else { - byte = *(cia_context->clk_ptr) + 128 - cia_context->rdi; + byte = rclk + 128 - cia_context->rdi; } } else { byte = 0; } - SMW_B(m, (BYTE)(byte)); + SMW_B(m, byte); - SMW_B(m, (BYTE)((cia_context->todlatched ? 1 : 0) + SMW_B(m, (uint8_t)((cia_context->todlatched ? 1 : 0) | (cia_context->todstopped ? 2 : 0))); SMW_B(m, cia_context->todlatch[0]); SMW_B(m, cia_context->todlatch[1]); SMW_B(m, cia_context->todlatch[2]); SMW_B(m, cia_context->todlatch[3]); - SMW_DW(m, (cia_context->todclk - *(cia_context->clk_ptr))); + SMW_CLOCK(m, (cia_context->todclk - rclk)); - ciat_save_snapshot(cia_context->ta, *(cia_context->clk_ptr), m, + ciat_save_snapshot(cia_context->ta, rclk, m, (CIA_DUMP_VER_MAJOR << 8) | CIA_DUMP_VER_MINOR); - ciat_save_snapshot(cia_context->tb, *(cia_context->clk_ptr), m, + ciat_save_snapshot(cia_context->tb, rclk, m, (CIA_DUMP_VER_MAJOR << 8) | CIA_DUMP_VER_MINOR); - SMW_B(m, cia_context->shifter); - SMW_B(m, (BYTE)(cia_context->sdr_valid)); + SMW_B(m, cia_context->shifter & 0xFF); + SMW_B(m, (uint8_t)(cia_context->sdr_valid)); /* This has to be tested */ SMW_B(m, cia_context->irq_enabled); SMW_B(m, cia_context->todtickcounter); + SMW_B(m, (cia_context->shifter >> 8) & 0xFF); /* SHIFTER_HI */ + + CLOCK sdr_alarm_pending = alarm_clk(cia_context->sdr_alarm); + if (sdr_alarm_pending > 0) { + byte = 1 + sdr_alarm_pending - rclk; + } else { + byte = 0; + } + SMW_B(m, byte); /* SDR_ALARM */ + + byte = (cia_context->sp_in_state ? 0x80 : 0) + | (cia_context->cnt_in_state ? 0x40 : 0) + | (cia_context->sdr_force_finish ? 0x20 : 0); + + SMW_B(m, byte); /* SP_CNT_IN */ + + /* 2.4 */ + + SMW_DW(m, cia_context->sdr_delay); /* SDR_DELAY */ + + byte = /* (cia_context->sp_out_state ? 0x80 : 0) + | */ (cia_context->cnt_out_state ? 0x40 : 0); + + SMW_B(m, byte); /* SP_CNT_OUT */ + + /* 2.5 */ + + SMW_DW(m, cia_context->ifr_delay); /* IFR_DELAY */ + SMW_DB(m, cia_context->ack_irqflags); /* ACK_IRQFLAGS */ + SMW_DB(m, cia_context->new_irqflags); /* NEW_IRQFLAGS */ + /* + * We don't need to save ifr_clock, since we made sure it + * is up to date, i.e. equal to rclk. + */ + snapshot_module_close(m); return 0; @@ -1741,12 +2541,12 @@ int ciacore_snapshot_write_module(cia_context_t *cia_context, snapshot_t *s) int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) { - BYTE vmajor, vminor; - BYTE byte; - DWORD dword; + uint8_t vmajor, vminor; + uint8_t byte; + CLOCK qword; CLOCK rclk = *(cia_context->clk_ptr); snapshot_module_t *m; - WORD cia_tal, cia_tbl, cia_tac, cia_tbc; + uint16_t cia_tal, cia_tbl, cia_tac, cia_tbc; m = snapshot_module_open(s, cia_context->myname, &vmajor, &vminor); @@ -1768,6 +2568,7 @@ int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) ciat_set_ctrl(cia_context->ta, *(cia_context->clk_ptr), 0); ciat_set_ctrl(cia_context->tb, *(cia_context->clk_ptr), 0); alarm_unset(cia_context->tod_alarm); + alarm_unset(cia_context->sdr_alarm); { SMR_B(m, &(cia_context->c_cia[CIA_PRA])); @@ -1843,8 +2644,8 @@ int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) SMR_B(m, &(cia_context->todlatch[2])); SMR_B(m, &(cia_context->todlatch[3])); - SMR_DW(m, &dword); - cia_context->todclk = *(cia_context->clk_ptr) + dword; + SMR_CLOCK(m, &qword); /* TOD_TICKS */ + cia_context->todclk = *(cia_context->clk_ptr) + qword; alarm_set(cia_context->tod_alarm, cia_context->todclk); /* timer switch-on code from store_cia[CIA_CRA/CRB] */ @@ -1864,12 +2665,6 @@ int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) ciat_load_snapshot(cia_context->tb, rclk, cia_tbc, cia_tbl, cia_context->c_cia[CIA_CRB], m, (vmajor << 8) | vminor); - if (vminor > 1) { - SMR_B(m, &(cia_context->shifter)); - SMR_B(m, &byte); - cia_context->sdr_valid = byte; - } - #ifdef cia_DUMP_DEBUG log_message(cia_context->log, "clk=%d, cra=%02x, crb=%02x, tas=%d, tbs=%d", *(cia_context->clk_ptr), cia[CIA_CRA], cia[CIA_CRB], cia_tas, @@ -1880,19 +2675,66 @@ int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) cia_tbi, cia_tbu, cia_tbc, cia_tbl); #endif - if (SMR_B(m, &(cia_context->irq_enabled)) < 0) { - /* old (buggy) way to restore interrupt */ - /* still enabled; will be fixed in 1.13.x */ - cia_context->irq_enabled = (cia_context->c_cia[CIA_ICR] & 0x80) ? 1 : 0; + if (vminor > 1) { + SMR_B(m, &byte); + cia_context->shifter = byte; + SMR_B(m, &byte); + cia_context->sdr_valid = byte; + + if (SMR_B(m, &(cia_context->irq_enabled)) < 0) { + /* old (buggy) way to restore interrupt */ + /* still enabled; will be fixed in 1.13.x */ + cia_context->irq_enabled = (cia_context->c_cia[CIA_ICR] & CIA_IM_SET) ? 1 : 0; + } + + if (cia_context->irq_enabled) { + (cia_context->cia_restore_int)(cia_context, 1); + } else { + (cia_context->cia_restore_int)(cia_context, 0); + } + + SMR_B(m, &(cia_context->todtickcounter)); } - if (cia_context->irq_enabled) { - (cia_context->cia_restore_int)(cia_context, cia_context->irq_line); - } else { - (cia_context->cia_restore_int)(cia_context, 0); + if (vminor > 2) { + SMR_B(m, &byte); /* SHIFTER_HI */ + cia_context->shifter |= byte << 8; + + SMR_B(m, &byte); /* SDR_ALARM */ + if (byte) { + alarm_set(cia_context->sdr_alarm, rclk + byte - 1); + } + + SMR_B(m, &byte); /* SP_CNT_IN */ + cia_context->sp_in_state = (byte & 0x80) != 0; + cia_context->cnt_in_state = (byte & 0x40) != 0; + cia_context->sdr_force_finish = (byte & 0x20) != 0; + } + + if (vminor > 3) { + uint32_t dword; + SMR_DW(m, &dword); /* SDR_DELAY */ + cia_context->sdr_delay = dword; + + SMR_B(m, &byte); /* SP_CNT_OUT */ + /* cia_context->sp_out_state = (byte & 0x80) != 0; */ + cia_context->cnt_out_state = (byte & 0x40) != 0; } - SMR_B(m, &(cia_context->todtickcounter)); + if (vminor > 4) { + uint32_t dword; + + SMR_DW(m, &dword); /* IFR_DELAY */ + cia_context->ifr_delay = dword; + cia_context->ifr_clock = rclk + 1; + + SMR_B(m, &byte); /* ACK_IRQFLAGS */ + cia_context->ack_irqflags = byte; + SMR_B(m, &byte); /* NEW_IRQFLAGS */ + cia_context->new_irqflags = byte; + + cia_ifr_current(cia_context, rclk, CIA_IFR_NEXT); + } if (snapshot_module_close(m) < 0) { return -1; @@ -1903,21 +2745,84 @@ int ciacore_snapshot_read_module(cia_context_t *cia_context, snapshot_t *s) int ciacore_dump(cia_context_t *cia_context) { - mon_out("ICR: %02x CTRLA: %02x CTRLB: %02x\n\n", ciacore_peek(cia_context, 0x0d), ciacore_peek(cia_context, 0x0e), ciacore_peek(cia_context, 0x0f)); - mon_out("ICR write: %02x Timer A IRQ: %s Timer B IRQ: %s TOD IRQ: %s Serial IRQ: %s Cassette IRQ: %s\n\n", - cia_context->c_cia[CIA_ICR], - (cia_context->c_cia[CIA_ICR] & 1) ? "on" : "off", - (cia_context->c_cia[CIA_ICR] & (1<<1)) ? "on" : "off", - (cia_context->c_cia[CIA_ICR] & (1<<2)) ? "on" : "off", - (cia_context->c_cia[CIA_ICR] & (1<<3)) ? "on" : "off", - (cia_context->c_cia[CIA_ICR] & (1<<4)) ? "on" : "off"); - mon_out("Port A: %02x DDR: %02x\n", ciacore_peek(cia_context, 0x00), ciacore_peek(cia_context, 0x02)); - mon_out("Port B: %02x DDR: %02x\n", ciacore_peek(cia_context, 0x01), ciacore_peek(cia_context, 0x03)); - mon_out("Timer A: %04x\n", ciacore_peek(cia_context, 0x04) + (ciacore_peek(cia_context, 0x05) << 8)); - mon_out("Timer B: %04x\n", ciacore_peek(cia_context, 0x06) + (ciacore_peek(cia_context, 0x07) << 8)); - mon_out("TOD Time: %02x:%02x:%02x.%x (%s)\n", ciacore_peek(cia_context, 0x0b) & 0x7f, ciacore_peek(cia_context, 0x0a), ciacore_peek(cia_context, 0x09), ciacore_peek(cia_context, 0x08), ciacore_peek(cia_context, 0x0b) & 0x80 ? "pm" : "am"); - mon_out("TOD Alarm: %02x:%02x:%02x.%x (%s)\n", cia_context->todalarm[0x0b - CIA_TOD_TEN] & 0x7f, cia_context->todalarm[0x0a - CIA_TOD_TEN], cia_context->todalarm[0x09 - CIA_TOD_TEN], cia_context->todalarm[0x08 - CIA_TOD_TEN], cia_context->todalarm[0x0b - CIA_TOD_TEN] & 0x80 ? "pm" : "am"); - mon_out("\nSynchronous Serial I/O Data Buffer: %02x\n", ciacore_peek(cia_context, 0x0c)); + char *s; + CLOCK clk = *(cia_context->clk_ptr); + + mon_out("ICR: %02x (mask: %02x) CTRLA: %02x CTRLB: %02x, delay: %04x rclk-%d to_ack: %02x\n", + ciacore_peek(cia_context, 0x0d), + cia_context->c_cia[CIA_ICR], + ciacore_peek(cia_context, 0x0e), + ciacore_peek(cia_context, 0x0f), + cia_context->ifr_delay, + (int)(clk - cia_context->ifr_clock), + cia_context->ack_irqflags); + + mon_out("\nPort A: %02x DDR: %02x\n", + ciacore_peek(cia_context, 0x00), + ciacore_peek(cia_context, 0x02)); + mon_out("Port B: %02x DDR: %02x\n", + ciacore_peek(cia_context, 0x01), + ciacore_peek(cia_context, 0x03)); + + mon_out("\nTimer A IRQ: %s running: %s mode: %s\n", + (cia_context->c_cia[CIA_ICR] & 1) ? "on" : "off", + ciacore_peek(cia_context, 0x0e) & 1 ? "yes" : "no", + ciacore_peek(cia_context, 0x0e) & (1 << 3) ? "one-shot" : "continuous"); + mon_out("Timer A counts: %s PB6 output: %s (%s)\n", + ciacore_peek(cia_context, 0x0e) & (1 << 5) ? "CNT transitions" : "System clock", + ciacore_peek(cia_context, 0x0e) & (1 << 1) ? "yes" : "no", + ciacore_peek(cia_context, 0x0e) & (1 << 2) ? "Toggle" : "Pulse"); + mon_out("Timer A: %04x (latched %04x)\n", + (unsigned int)(ciacore_peek(cia_context, 0x04) + (ciacore_peek(cia_context, 0x05) << 8)), + cia_context->ta->latch); + + mon_out("Timer B IRQ: %s running: %s mode: %s\n", + (cia_context->c_cia[CIA_ICR] & (1 << 1)) ? "on" : "off", + ciacore_peek(cia_context, 0x0f) & 1 ? "yes" : "no", + ciacore_peek(cia_context, 0x0f) & (1 << 3) ? "one-shot" : "continuous"); + switch (ciacore_peek(cia_context, 0x0f) & (3 << 5)) { + default: + case (0 << 5): s = "System clock"; break; + case (1 << 5): s = "CNT transitions"; break; + case (2 << 5): s = "Timer A undeflows"; break; + case (3 << 5): s = "Timer A undeflows with CNT"; break; + } + mon_out("Timer B counts: %s PB7 output: %s (%s)\n", + s, + ciacore_peek(cia_context, 0x0f) & (1 << 1) ? "yes" : "no", + ciacore_peek(cia_context, 0x0f) & (1 << 2) ? "Toggle" : "Pulse"); + mon_out("Timer B: %04x (latched %04x)\n", + (unsigned int)(ciacore_peek(cia_context, 0x06) + (ciacore_peek(cia_context, 0x07) << 8)), + cia_context->tb->latch); + + mon_out("\nTOD IRQ: %s latched: %s running: %s mode: %sHz\n", + (cia_context->c_cia[CIA_ICR] & (1<<2)) ? "on" : "off", + cia_context->todlatched ? "yes" : "no", + cia_context->todstopped ? "no" : "yes", + ciacore_peek(cia_context, 0x0e) & (1 << 7) ? "50" : "60"); + mon_out("TOD Time: %02x:%02x:%02x.%x (%s)\n", + ciacore_peek(cia_context, 0x0b) & 0x7fU, + ciacore_peek(cia_context, 0x0a), + ciacore_peek(cia_context, 0x09), + ciacore_peek(cia_context, 0x08), + ciacore_peek(cia_context, 0x0b) & 0x80 ? "pm" : "am"); + mon_out("TOD Alarm: %02x:%02x:%02x.%x (%s)\n", + cia_context->todalarm[0x0b - CIA_TOD_TEN] & 0x7fU, + cia_context->todalarm[0x0a - CIA_TOD_TEN], + cia_context->todalarm[0x09 - CIA_TOD_TEN], + cia_context->todalarm[0x08 - CIA_TOD_TEN], + cia_context->todalarm[0x0b - CIA_TOD_TEN] & 0x80 ? "pm" : "am"); + + mon_out("\nShift Register IRQ: %s mode: %s\n", + (cia_context->c_cia[CIA_ICR] & (1<<3)) ? "on" : "off", + ciacore_peek(cia_context, 0x0e) & (1 << 6) ? "output" : "input"); + mon_out("Shift Register Data Buffer: %02x\n", + ciacore_peek(cia_context, 0x0c)); + mon_out("Timer A SDR: delay %05x\n", cia_context->sdr_delay); + + mon_out("\nFLAG1 IRQ: %s\n", + (cia_context->c_cia[CIA_ICR] & (1<<4)) ? "on" : "off"); + return 0; } diff --git a/src/Emulators/vice/core/ciatimer.c b/src/Emulators/vice/core/ciatimer.c index 23f82db6..7e2d5405 100644 --- a/src/Emulators/vice/core/ciatimer.c +++ b/src/Emulators/vice/core/ciatimer.c @@ -43,7 +43,6 @@ static int ciat_logfl = 0; /* 0 means logging disabled */ static int logtab = 0; static const char spaces[] = " "; -/* extern int traceflg; */ void ciat_login(const char *format, ...) { @@ -166,7 +165,7 @@ void ciat_init_table(void) */ void ciat_init(ciat_t *state, const char *name, CLOCK cclk, alarm_t *alarm) { - CIAT_LOGIN(("%s init: cclk=%d", name, cclk)); + CIAT_LOGIN(("%s init: cclk=%lu", name, cclk)); state->name = name; state->clk = cclk; @@ -181,7 +180,7 @@ void ciat_init(ciat_t *state, const char *name, CLOCK cclk, alarm_t *alarm) /* timer reset */ void ciat_reset(ciat_t *state, CLOCK cclk) { - CIAT_LOGIN(("%s reset: cclk=%d", state->name, cclk)); + CIAT_LOGIN(("%s reset: cclk=%lu", state->name, cclk)); /* FIXME? */ state->clk = cclk; @@ -216,12 +215,12 @@ void ciat_save_snapshot(ciat_t *cia_state, CLOCK cclk, snapshot_module_t *m, if (ver >= 0x100) { /* major 1, minor >= 1 */ /* cnt & latch are saved from cia module already */ - SMW_W(m, ((WORD)(cia_state->state))); + SMW_W(m, ((uint16_t)(cia_state->state))); } } -void ciat_load_snapshot(ciat_t *state, CLOCK cclk, WORD cnt, WORD latch, - BYTE cr, snapshot_module_t *m, int ver) +void ciat_load_snapshot(ciat_t *state, CLOCK cclk, uint16_t cnt, uint16_t latch, + uint8_t cr, snapshot_module_t *m, int ver) { /* cnt & latch are read from cia module already */ state->clk = cclk; diff --git a/src/Emulators/vice/core/ciatimer.h b/src/Emulators/vice/core/ciatimer.h index f14445f9..a2e1bb8e 100644 --- a/src/Emulators/vice/core/ciatimer.h +++ b/src/Emulators/vice/core/ciatimer.h @@ -71,13 +71,13 @@ /***************************************************************************/ /* types */ -typedef WORD ciat_tstate_t; /* 16 bit type */ +typedef uint16_t ciat_tstate_t; /* 16 bit type */ typedef struct ciat_s { const char *name; /* name of timer */ ciat_tstate_t state; /* timer bits */ - WORD latch; - WORD cnt; + uint16_t latch; + uint16_t cnt; CLOCK alarmclk; CLOCK clk; alarm_t *alarm; @@ -88,7 +88,7 @@ typedef struct ciat_s { extern ciat_tstate_t ciat_table[CIAT_TABLEN]; -extern void ciat_init_table(void); +void ciat_init_table(void); /***************************************************************************/ @@ -114,11 +114,11 @@ extern void ciat_init_table(void); #ifdef CIAT_NEED_LOG -extern void ciat_login(const char *format, ...); -extern void ciat_logout(const char *format, ...); -extern void ciat_log(const char *format, ...); +void ciat_login(const char *format, ...) VICE_ATTR_PRINTF; +void ciat_logout(const char *format, ...) VICE_ATTR_PRINTF; +void ciat_log(const char *format, ...) VICE_ATTR_PRINTF; -extern void ciat_print_state(const ciat_t *state); +void ciat_print_state(const ciat_t *state); #endif @@ -156,14 +156,14 @@ _CIAT_FUNC void ciat_set_alarm(ciat_t *state, CLOCK cclk) { CLOCK tmp = 0; CLOCK aclk = state->clk; - WORD cnt = state->cnt; + uint16_t cnt = state->cnt; ciat_tstate_t t = state->state; - CIAT_LOGIN(("%s set_alarm: cclk=%d, latch=%d", + CIAT_LOGIN(("%s set_alarm: cclk=%lu, latch=%d", state->name, cclk, state->latch)); while (1) { - CIAT_LOG(("- state->clk=%d cnt=%d state=%04x", aclk, cnt, t)); + CIAT_LOG(("- state->clk=%lu cnt=%d state=%04x", aclk, cnt, t)); if (((t & (CIAT_CR_START | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3 | CIAT_COUNT @@ -235,7 +235,8 @@ _CIAT_FUNC CLOCK ciat_alarm_clk(ciat_t *state) _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) { - int n, m; + int n; + CLOCK m; ciat_tstate_t t = state->state; /* printf("%s update: state->clk=%d cclk=%d, state=%d, cnt=%d, latch=%d\n", @@ -254,11 +255,11 @@ _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) n = 0; - CIAT_LOGIN(("%s update: cclk=%d, latch=%d", + CIAT_LOGIN(("%s update: cclk=%lu, latch=%d", state->name, cclk, state->latch)); while (state->clk < cclk) { - CIAT_LOG(("- clk=%d cnt=%d state=%04x", state->clk, state->cnt, t)); + CIAT_LOG(("- clk=%lu cnt=%d state=%04x", state->clk, state->cnt, t)); if (((t & (CIAT_CR_START | CIAT_CR_FLOAD | CIAT_LOAD1 | CIAT_PHI2IN | CIAT_COUNT2 | CIAT_COUNT3 | CIAT_COUNT @@ -271,7 +272,7 @@ _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) && (!(t & CIAT_ONESHOT))))) { /* warp counting */ if (state->clk + state->cnt > cclk) { - state->cnt -= ((WORD)(cclk - state->clk)); + state->cnt -= ((uint16_t)(cclk - state->clk)); state->clk = cclk; } else { if (t & (CIAT_CR_ONESHOT | CIAT_ONESHOT0)) { @@ -282,7 +283,7 @@ _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) state->clk = state->clk + state->cnt; state->cnt = 0; /* n++; */ - if (((WORD)(cclk - state->clk)) >= state->latch + 1) { + if (((uint16_t)(cclk - state->clk)) >= state->latch + 1) { m = (cclk - state->clk) / (state->latch + 1); n += m; state->clk += m * (state->latch + 1); @@ -340,7 +341,7 @@ _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) state->state = t; - CIAT_LOG(("-> state->clk=%d cnt=%d, latch=%d, state=%04x", + CIAT_LOG(("-> state->clk=%lu cnt=%d, latch=%d, state=%04x", state->clk, state->cnt, state->latch, t)); CIAT_LOGOUT(("-> n=%d", n)); @@ -353,26 +354,26 @@ _CIAT_FUNC int ciat_update(ciat_t *state, CLOCK cclk) */ /* read timer value - ciat_update _must_ have been called before! */ -_CIAT_FUNC WORD ciat_read_latch(ciat_t *state, CLOCK cclk) +_CIAT_FUNC uint16_t ciat_read_latch(ciat_t *state, CLOCK cclk) { return state->latch; } /* read timer value - ciat_update _must_ have been called before! */ -_CIAT_FUNC WORD ciat_read_timer(ciat_t *state, CLOCK cclk) +_CIAT_FUNC uint16_t ciat_read_timer(ciat_t *state, CLOCK cclk) { return state->cnt; } /* check whether underflow clk - ciat_update _must_ have been called before! Code mostly from ciat_read_timer */ -_CIAT_FUNC WORD ciat_is_underflow_clk(ciat_t *state, CLOCK cclk) +_CIAT_FUNC uint16_t ciat_is_underflow_clk(ciat_t *state, CLOCK cclk) { return (state->state & CIAT_OUT) ? 1 : 0; } /* return 1 when the timer is running - update must have ... */ -_CIAT_FUNC WORD ciat_is_running(ciat_t *state, CLOCK cclk) +_CIAT_FUNC uint16_t ciat_is_running(ciat_t *state, CLOCK cclk) { return (state->state & CIAT_CR_START) ? 1 : 0; } @@ -388,9 +389,9 @@ _CIAT_FUNC int ciat_single_step(ciat_t *state, CLOCK cclk) return 0; } -_CIAT_FUNC void ciat_set_latchhi(ciat_t *state, CLOCK cclk, BYTE byte) +_CIAT_FUNC void ciat_set_latchhi(ciat_t *state, CLOCK cclk, uint8_t byte) { - CIAT_LOGIN(("%s set_latchhi: cclk=%d, byte=%02x", state->name, cclk, byte)); + CIAT_LOGIN(("%s set_latchhi: cclk=%lu, byte=%02x", state->name, cclk, byte)); state->latch = (state->latch & 0xff) | (byte << 8); if ((state->state & CIAT_LOAD) || !(state->state & CIAT_CR_START)) { state->cnt = state->latch; @@ -402,7 +403,7 @@ _CIAT_FUNC void ciat_set_latchhi(ciat_t *state, CLOCK cclk, BYTE byte) CIAT_LOGOUT(("")); } -_CIAT_FUNC void ciat_set_latchlo(ciat_t *state, CLOCK cclk, BYTE byte) +_CIAT_FUNC void ciat_set_latchlo(ciat_t *state, CLOCK cclk, uint8_t byte) { CIAT_LOGIN(("%s set_latchlo(byte=%02x)", state->name, byte)); @@ -419,9 +420,9 @@ _CIAT_FUNC void ciat_set_latchlo(ciat_t *state, CLOCK cclk, BYTE byte) /* needs update before */ -_CIAT_FUNC void ciat_set_ctrl(ciat_t *state, CLOCK cclk, BYTE byte) +_CIAT_FUNC void ciat_set_ctrl(ciat_t *state, CLOCK cclk, uint8_t byte) { - CIAT_LOGIN(("%s set_ctrl: cclk=%d, byte=%02x", + CIAT_LOGIN(("%s set_ctrl: cclk=%lu, byte=%02x", state->name, cclk, byte)); /* bit 0= start/stop, 3=oneshot 4=force load, 5=0:count phi2 1:singlestep */ state->state &= ~(CIAT_CR_MASK); @@ -434,7 +435,7 @@ _CIAT_FUNC void ciat_set_ctrl(ciat_t *state, CLOCK cclk, BYTE byte) _CIAT_FUNC void ciat_ack_alarm(ciat_t *state, CLOCK cclk) { - CIAT_LOGIN(("%s ack_alarm: cclk=%d, alarmclk=%d", + CIAT_LOGIN(("%s ack_alarm: cclk=%lu, alarmclk=%lu", state->name, cclk, state->alarmclk)); alarm_unset(state->alarm); @@ -448,30 +449,30 @@ _CIAT_FUNC void ciat_ack_alarm(ciat_t *state, CLOCK cclk) /* We don't want inline definitions: just provide the prototypes. */ -extern void ciat_ack_alarm(ciat_t *state, CLOCK cclk); -extern void ciat_set_ctrl(ciat_t *state, CLOCK cclk, BYTE byte); -extern void ciat_set_latchlo(ciat_t *state, CLOCK cclk, BYTE byte); -extern void ciat_set_latchhi(ciat_t *state, CLOCK cclk, BYTE byte); -extern int ciat_single_step(ciat_t *state, CLOCK cclk); -extern WORD ciat_read_timer(ciat_t *state, CLOCK cclk); -extern WORD ciat_read_latch(ciat_t *state, CLOCK cclk); -extern int ciat_update(ciat_t *state, CLOCK cclk); -extern CLOCK ciat_alarm_clk(ciat_t *state); -extern void ciat_set_alarm(ciat_t *state, CLOCK clk); +void ciat_ack_alarm(ciat_t *state, CLOCK cclk); +void ciat_set_ctrl(ciat_t *state, CLOCK cclk, uint8_t byte); +void ciat_set_latchlo(ciat_t *state, CLOCK cclk, uint8_t byte); +void ciat_set_latchhi(ciat_t *state, CLOCK cclk, uint8_t byte); +int ciat_single_step(ciat_t *state, CLOCK cclk); +uint16_t ciat_read_timer(ciat_t *state, CLOCK cclk); +uint16_t ciat_read_latch(ciat_t *state, CLOCK cclk); +int ciat_update(ciat_t *state, CLOCK cclk); +CLOCK ciat_alarm_clk(ciat_t *state); +void ciat_set_alarm(ciat_t *state, CLOCK clk); -extern WORD ciat_is_underflow_clk(ciat_t *state, CLOCK cclk); -extern WORD ciat_is_running(ciat_t *state, CLOCK cclk); +uint16_t ciat_is_underflow_clk(ciat_t *state, CLOCK cclk); +uint16_t ciat_is_running(ciat_t *state, CLOCK cclk); #endif /* defined INLINE_CIAT_FUNCS || defined _CIATIMER_C */ -extern void ciat_init(ciat_t *state, const char *name, CLOCK cclk, - alarm_t *alarm); -extern void ciat_reset(ciat_t *state, CLOCK cclk); -extern void ciat_prevent_clock_overflow(ciat_t *state, CLOCK sub); +void ciat_init(ciat_t *state, const char *name, CLOCK cclk, + alarm_t *alarm); +void ciat_reset(ciat_t *state, CLOCK cclk); +void ciat_prevent_clock_overflow(ciat_t *state, CLOCK sub); -extern void ciat_save_snapshot(ciat_t *cia_state, CLOCK cclk, - struct snapshot_module_s *m, int ver); -extern void ciat_load_snapshot(ciat_t *state, CLOCK cclk, WORD cnt, WORD latch, - BYTE cr, struct snapshot_module_s *m, int ver); +void ciat_save_snapshot(ciat_t *cia_state, CLOCK cclk, + struct snapshot_module_s *m, int ver); +void ciat_load_snapshot(ciat_t *state, CLOCK cclk, uint16_t cnt, uint16_t latch, + uint8_t cr, struct snapshot_module_s *m, int ver); #endif diff --git a/src/Emulators/vice/core/cs8900.c b/src/Emulators/vice/core/cs8900.c index b843feae..986023e8 100644 --- a/src/Emulators/vice/core/cs8900.c +++ b/src/Emulators/vice/core/cs8900.c @@ -27,7 +27,7 @@ #include "vice.h" -#ifdef HAVE_PCAP +#ifdef HAVE_RAWNET #include #include @@ -46,6 +46,7 @@ #include "rawnetarch.h" #include "resources.h" #include "snapshot.h" +#include "vicetypes.h" #include "util.h" /* FIXME: @@ -68,18 +69,18 @@ /* ------------------------------------------------------------------------- */ /* variables needed */ -static log_t cs8900_log = LOG_ERR; +static log_t cs8900_log = LOG_DEFAULT; /* status which received packages to accept This is used in cs8900_should_accept(). */ -static BYTE cs8900_ia_mac[6] = { 0, 0, 0, 0, 0, 0 }; +static uint8_t cs8900_ia_mac[6] = { 0, 0, 0, 0, 0, 0 }; /* remember the value of the hash mask */ -static DWORD cs8900_hash_mask[2]; +static uint32_t cs8900_hash_mask[2]; /* reveiver setup */ -static WORD cs8900_recv_control = 0; /* copy of CC_RXCTL (contains all bits below) */ +static uint16_t cs8900_recv_control = 0; /* copy of CC_RXCTL (contains all bits below) */ static int cs8900_recv_broadcast = 0; /* broadcast */ static int cs8900_recv_mac = 0; /* individual address (IA) */ static int cs8900_recv_multicast = 0; /* multicast if address passes the hash filter */ @@ -96,7 +97,7 @@ static int cs8900_recv_hashfilter = 0; /* accept if IA passes the hash filter */ #define CS8900_COUNT_IO_REGISTER 0x10 /* we have 16 I/O register */ -static BYTE *cs8900 = NULL; +static uint8_t *cs8900 = NULL; /* RW: RXTXDATA = DE00/DE01 RW: RXTXDATA2 = DE02/DE03 (for 32-bit-operation) @@ -140,15 +141,15 @@ static BYTE *cs8900 = NULL; #define MAX_PACKETPAGE_ARRAY 0x1000 /* 4 KB */ -static BYTE *cs8900_packetpage = NULL; +static uint8_t *cs8900_packetpage = NULL; -static WORD cs8900_packetpage_ptr = 0; +static uint16_t cs8900_packetpage_ptr = 0; /* Makros for reading and writing the PacketPage register: */ #define GET_PP_8(_xxx_) (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), cs8900_packetpage[_xxx_]) -#define GET_PP_16(_xxx_) (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), assert((_xxx_ & 1) == 0), ((WORD)cs8900_packetpage[_xxx_]) | ((WORD)cs8900_packetpage[_xxx_ + 1] << 8)) +#define GET_PP_16(_xxx_) (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), assert((_xxx_ & 1) == 0), ((uint16_t)cs8900_packetpage[_xxx_]) | ((uint16_t)cs8900_packetpage[_xxx_ + 1] << 8)) #define GET_PP_32(_xxx_) \ (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), assert((_xxx_ & 3) == 0), \ @@ -246,13 +247,13 @@ static WORD cs8900_packetpage_ptr = 0; /* ------------------------------------------------------------------------- */ /* more variables needed */ -static WORD tx_buffer = CS8900_PP_ADDR_TX_FRAMELOC; -static WORD rx_buffer = CS8900_PP_ADDR_RXSTATUS; +static uint16_t tx_buffer = CS8900_PP_ADDR_TX_FRAMELOC; +static uint16_t rx_buffer = CS8900_PP_ADDR_RXSTATUS; -static WORD tx_count = 0; -static WORD rx_count = 0; -static WORD tx_length = 0; -static WORD rx_length = 0; +static uint16_t tx_count = 0; +static uint16_t rx_count = 0; +static uint16_t tx_length = 0; +static uint16_t rx_length = 0; #define CS8900_TX_IDLE 0 #define CS8900_TX_GOT_CMD 1 @@ -315,10 +316,10 @@ static char *debug_outbuffer(const int length, const unsigned char * const buffe static void cs8900_set_tx_status(int ready, int error) { - WORD old_status = GET_PP_16(CS8900_PP_ADDR_SE_BUSST); + uint16_t old_status = GET_PP_16(CS8900_PP_ADDR_SE_BUSST); /* mask out TxBidErr and Rdy4TxNOW */ - WORD new_status = old_status & ~0x180; + uint16_t new_status = old_status & ~0x180; if (ready) { new_status |= 0x100; /* set Rdy4TxNOW */ } @@ -630,11 +631,11 @@ int cs8900_should_accept(unsigned char *buffer, int length, int *phashed, int *p /* &broadcast - set if dest. address is a broadcast address */ /* &crc_error - set if received frame had a CRC error */ -static WORD cs8900_receive(void) +static uint16_t cs8900_receive(void) { - WORD ret_val = 0x0004; + uint16_t ret_val = 0x0004; - BYTE buffer[MAX_RXLENGTH]; + uint8_t buffer[MAX_RXLENGTH]; int len; int hashed; @@ -642,7 +643,7 @@ static WORD cs8900_receive(void) int rx_ok; int correct_mac; int broadcast; - int multicast; + int multicast = 0; /* avoid warning */ int crc_error; int newframe; @@ -741,7 +742,7 @@ static WORD cs8900_receive(void) /* ------------------------------------------------------------------------- */ /* TX/RX buffer handling */ -static void cs8900_write_tx_buffer(BYTE value, int odd_address) +static void cs8900_write_tx_buffer(uint8_t value, int odd_address) { /* write tx data only if valid buffer is ready */ if (tx_state != CS8900_TX_READ_BUSST) { @@ -758,7 +759,7 @@ static void cs8900_write_tx_buffer(BYTE value, int odd_address) #endif /* always write LH, LH... to tx buffer */ - WORD addr = tx_buffer; + uint16_t addr = tx_buffer; if (odd_address) { addr++; tx_buffer += 2; @@ -782,7 +783,7 @@ static void cs8900_write_tx_buffer(BYTE value, int odd_address) #endif } else { /* send frame */ - WORD txcmd = GET_PP_16(CS8900_PP_ADDR_CC_TXCMD); + uint16_t txcmd = GET_PP_16(CS8900_PP_ADDR_CC_TXCMD); rawnet_arch_transmit( txcmd & 0x0100 ? 1 : 0, /* FORCE: Delete waiting frames in transmit buffer */ txcmd & 0x0200 ? 1 : 0, /* ONECOLL: Terminate after just one collision */ @@ -804,7 +805,7 @@ static void cs8900_write_tx_buffer(BYTE value, int odd_address) } } -static BYTE cs8900_read_rx_buffer(int odd_address) +static uint8_t cs8900_read_rx_buffer(int odd_address) { if (rx_state != CS8900_RX_GOT_FRAME) { #ifdef CS8900_DEBUG_WARN_RXTX @@ -826,8 +827,8 @@ static BYTE cs8900_read_rx_buffer(int odd_address) CS8900_PP_ADDR_RX_FRAMELOC+4: proceed - */ - WORD addr = odd_address ? 1 : 0; - BYTE value; + uint16_t addr = odd_address ? 1 : 0; + uint8_t value; /* read RXSTATUS or RX_LENGTH */ if (rx_count < 4) { @@ -876,10 +877,10 @@ static BYTE cs8900_read_rx_buffer(int odd_address) /* This is called *after* the relevant octets are written */ -static void cs8900_sideeffects_write_pp(WORD ppaddress, int odd_address) +static void cs8900_sideeffects_write_pp(uint16_t ppaddress, int odd_address) { const char *on_off[2] = { "on", "off" }; - WORD content = GET_PP_16( ppaddress ); + uint16_t content = GET_PP_16( ppaddress ); assert((ppaddress & 1) == 0); @@ -944,7 +945,7 @@ static void cs8900_sideeffects_write_pp(WORD ppaddress, int odd_address) case CS8900_PP_ADDR_TXCMD: { if (odd_address) { - WORD txcommand = GET_PP_16(CS8900_PP_ADDR_TXCMD); + uint16_t txcommand = GET_PP_16(CS8900_PP_ADDR_TXCMD); /* already transmitting? */ if (tx_state == CS8900_TX_READ_BUSST) { @@ -969,8 +970,8 @@ static void cs8900_sideeffects_write_pp(WORD ppaddress, int odd_address) case CS8900_PP_ADDR_TXLENGTH: { if (odd_address && (tx_state == CS8900_TX_GOT_CMD)) { - WORD txlength = GET_PP_16(CS8900_PP_ADDR_TXLENGTH); - WORD txcommand = GET_PP_16(CS8900_PP_ADDR_CC_TXCMD); + uint16_t txlength = GET_PP_16(CS8900_PP_ADDR_TXLENGTH); + uint16_t txcommand = GET_PP_16(CS8900_PP_ADDR_CC_TXCMD); if (txlength < 4) { /* frame to short */ @@ -1009,7 +1010,7 @@ static void cs8900_sideeffects_write_pp(WORD ppaddress, int odd_address) case CS8900_PP_ADDR_LOG_ADDR_FILTER + 6: { unsigned int pos = 8 * (ppaddress - CS8900_PP_ADDR_LOG_ADDR_FILTER + odd_address); - DWORD *p = (pos < 32) ? &cs8900_hash_mask[0] : &cs8900_hash_mask[1]; + uint32_t *p = (pos < 32) ? &cs8900_hash_mask[0] : &cs8900_hash_mask[1]; *p &= ~(0xFF << pos); /* clear out relevant bits */ *p |= GET_PP_8(ppaddress + odd_address) << pos; @@ -1042,7 +1043,7 @@ static void cs8900_sideeffects_write_pp(WORD ppaddress, int odd_address) /* This is called *before* the relevant octets are read */ -static void cs8900_sideeffects_read_pp(WORD ppaddress, int odd_address) +static void cs8900_sideeffects_read_pp(uint16_t ppaddress, int odd_address) { switch (ppaddress) { case CS8900_PP_ADDR_SE_RXEVENT: @@ -1062,7 +1063,7 @@ static void cs8900_sideeffects_read_pp(WORD ppaddress, int odd_address) #endif } else { /* perform frame reception */ - WORD ret_val = cs8900_receive(); + uint16_t ret_val = cs8900_receive(); /* RXSTATUS and RXEVENT are the same, except that RXSTATUS buffers the old value while RXEVENT sets a new value whenever it is called @@ -1082,7 +1083,7 @@ static void cs8900_sideeffects_read_pp(WORD ppaddress, int odd_address) if (odd_address) { /* read busst before transmit condition is fullfilled */ if (tx_state == CS8900_TX_GOT_LEN) { - WORD bus_status = GET_PP_16(CS8900_PP_ADDR_SE_BUSST); + uint16_t bus_status = GET_PP_16(CS8900_PP_ADDR_SE_BUSST); /* check Rdy4TXNow flag */ if ((bus_status & 0x100) == 0x100) { @@ -1105,9 +1106,9 @@ static void cs8900_sideeffects_read_pp(WORD ppaddress, int odd_address) /* read/write from packet page register */ /* read a register from packet page */ -static WORD cs8900_read_register(WORD ppaddress) +static uint16_t cs8900_read_register(uint16_t ppaddress) { - WORD value = GET_PP_16(ppaddress); + uint16_t value = GET_PP_16(ppaddress); /* --- check the register address --- */ if (ppaddress < 0x100) { @@ -1117,7 +1118,7 @@ static WORD cs8900_read_register(WORD ppaddress) } } else if (ppaddress < 0x120) { /* --- read control register range --- */ - WORD regNum = ppaddress - 0x100; + uint16_t regNum = ppaddress - 0x100; regNum &= ~1; regNum++; @@ -1138,7 +1139,7 @@ static WORD cs8900_read_register(WORD ppaddress) assert((value & 0x3f) == regNum); } else if (ppaddress < 0x140) { /* --- read status register range --- */ - WORD regNum = ppaddress - 0x120; + uint16_t regNum = ppaddress - 0x120; regNum &= ~1; #ifdef CS8900_DEBUG_REGISTERS @@ -1215,7 +1216,7 @@ static WORD cs8900_read_register(WORD ppaddress) return value; } -static void cs8900_write_register(WORD ppaddress, WORD value) +static void cs8900_write_register(uint16_t ppaddress, uint16_t value) { /* --- write bus interface register range --- */ if (ppaddress < 0x100) { @@ -1238,7 +1239,7 @@ static void cs8900_write_register(WORD ppaddress, WORD value) } } else if (ppaddress < 0x120) { /* --- write to control register range --- */ - WORD regNum = ppaddress - 0x100; + uint16_t regNum = ppaddress - 0x100; regNum &= ~1; regNum += 1; @@ -1334,8 +1335,8 @@ static void cs8900_auto_incr_pp_ptr(void) /* perform auto increment of packet page pointer */ if ((cs8900_packetpage_ptr & PP_PTR_AUTO_INCR_FLAG) == PP_PTR_AUTO_INCR_FLAG) { /* pointer is always increment by one on real HW */ - WORD ptr = cs8900_packetpage_ptr & PP_PTR_ADDR_MASK; - WORD flags = cs8900_packetpage_ptr & PP_PTR_FLAG_MASK; + uint16_t ptr = cs8900_packetpage_ptr & PP_PTR_ADDR_MASK; + uint16_t flags = cs8900_packetpage_ptr & PP_PTR_FLAG_MASK; ptr++; cs8900_packetpage_ptr = ptr | flags; @@ -1345,16 +1346,16 @@ static void cs8900_auto_incr_pp_ptr(void) /* ------------------------------------------------------------------------- */ /* read/write CS8900 registers from VICE */ -#define LO_BYTE(x) (BYTE)((x) & 0xff) -#define HI_BYTE(x) (BYTE)(((x) >> 8) & 0xff) -#define LOHI_WORD(x, y) ((WORD)(x) | (((WORD)(y)) << 8 )) +#define LO_uint8_t(x) (uint8_t)((x) & 0xff) +#define HI_uint8_t(x) (uint8_t)(((x) >> 8) & 0xff) +#define LOHI_uint16_t(x, y) ((uint16_t)(x) | (((uint16_t)(y)) << 8 )) /* ----- read byte from I/O range in VICE ----- */ -BYTE cs8900_read(WORD io_address) +uint8_t cs8900_read(uint16_t io_address) { - BYTE retval, lo, hi; - WORD word_value; - WORD reg_base; + uint8_t retval, lo, hi; + uint16_t word_value; + uint16_t reg_base; assert(cs8900); assert(cs8900_packetpage); @@ -1373,7 +1374,7 @@ BYTE cs8900_read(WORD io_address) word_value = cs8900_packetpage_ptr; } else { /* read a register from packet page */ - WORD ppaddress = 0; + uint16_t ppaddress = 0; /* determine read addr in packet page */ switch (reg_base) { @@ -1414,8 +1415,8 @@ BYTE cs8900_read(WORD io_address) } /* extract return value from word_value */ - lo = LO_BYTE(word_value); - hi = HI_BYTE(word_value); + lo = LO_uint8_t(word_value); + hi = HI_uint8_t(word_value); if ((io_address & 1) == 0) { /* low byte on even address */ retval = lo; @@ -1436,11 +1437,11 @@ BYTE cs8900_read(WORD io_address) } /* ----- peek byte without side effects from I/O range in VICE ----- */ -BYTE cs8900_peek(WORD io_address) +uint8_t cs8900_peek(uint16_t io_address) { - BYTE retval, lo, hi; - WORD word_value; - WORD reg_base; + uint8_t retval, lo, hi; + uint16_t word_value; + uint16_t reg_base; assert(cs8900); assert(cs8900_packetpage); @@ -1459,7 +1460,7 @@ BYTE cs8900_peek(WORD io_address) word_value = cs8900_packetpage_ptr; } else { /* read a register from packet page */ - WORD ppaddress = 0; + uint16_t ppaddress = 0; /* determine read addr in packet page */ switch (reg_base) { @@ -1493,8 +1494,8 @@ BYTE cs8900_peek(WORD io_address) } /* extract return value from word_value */ - lo = LO_BYTE(word_value); - hi = HI_BYTE(word_value); + lo = LO_uint8_t(word_value); + hi = HI_uint8_t(word_value); if ((io_address & 1) == 0) { /* low byte on even address */ retval = lo; @@ -1506,10 +1507,10 @@ BYTE cs8900_peek(WORD io_address) } /* ----- write byte to I/O range of VICE ----- */ -void cs8900_store(WORD io_address, BYTE byte) +void cs8900_store(uint16_t io_address, uint8_t byte) { - WORD reg_base; - WORD word_value; + uint16_t reg_base; + uint16_t word_value; assert(cs8900); assert(cs8900_packetpage); @@ -1531,10 +1532,10 @@ void cs8900_store(WORD io_address, BYTE byte) /* combine stored value with new written byte */ if ((io_address & 1) == 0) { /* overwrite low byte */ - word_value = LOHI_WORD(byte, cs8900[reg_base + 1]); + word_value = LOHI_uint16_t(byte, cs8900[reg_base + 1]); } else { /* overwrite high byte */ - word_value = LOHI_WORD(cs8900[reg_base], byte); + word_value = LOHI_uint16_t(cs8900[reg_base], byte); } if (reg_base == CS8900_ADDR_PP_PTR) { @@ -1553,7 +1554,7 @@ void cs8900_store(WORD io_address, BYTE byte) /* write a register */ /*! \TODO: Find a reasonable default */ - WORD ppaddress = CS8900_PP_ADDR_PRODUCTID; + uint16_t ppaddress = CS8900_PP_ADDR_PRODUCTID; /* now determine address of write in packet page */ switch (reg_base) { @@ -1601,15 +1602,17 @@ void cs8900_store(WORD io_address, BYTE byte) } /* update cs8900 registers */ - cs8900[reg_base] = LO_BYTE(word_value); - cs8900[reg_base + 1] = HI_BYTE(word_value); + cs8900[reg_base] = LO_uint8_t(word_value); + cs8900[reg_base + 1] = HI_uint8_t(word_value); } int cs8900_dump(void) { /* FIXME: this is incomplete */ mon_out("Link status: %s\n", (GET_PP_16(CS8900_PP_ADDR_SE_LINEST) & 0x80) ? "up" : "no link"); - mon_out("Package Page Ptr: $%04X (autoincrement %s)\n", cs8900_packetpage_ptr & PP_PTR_ADDR_MASK, (cs8900_packetpage_ptr & PP_PTR_AUTO_INCR_FLAG) != 0 ? "enabled" : "disabled"); + mon_out("Package Page Ptr: $%04X (autoincrement %s)\n", + (unsigned int)(cs8900_packetpage_ptr & PP_PTR_ADDR_MASK), + (cs8900_packetpage_ptr & PP_PTR_AUTO_INCR_FLAG) != 0 ? "enabled" : "disabled"); return 0; } @@ -1623,8 +1626,6 @@ int cs8900_dump(void) /* FIXME: implement snapshot support */ int cs8900_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -1632,7 +1633,9 @@ int cs8900_snapshot_write_module(snapshot_t *s) if (m == NULL) { return -1; } - + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -1647,7 +1650,7 @@ int cs8900_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); @@ -1670,4 +1673,4 @@ int cs8900_snapshot_read_module(snapshot_t *s) #endif } -#endif /* #ifdef HAVE_PCAP */ +#endif /* #ifdef HAVE_RAWNET */ diff --git a/src/Emulators/vice/core/cs8900.h b/src/Emulators/vice/core/cs8900.h index 1e84c2ec..ef21965b 100644 --- a/src/Emulators/vice/core/cs8900.h +++ b/src/Emulators/vice/core/cs8900.h @@ -24,9 +24,11 @@ * */ -#ifndef HAVE_PCAP - #error CS8900.H should not be included if HAVE_PCAP is not defined! -#endif /* #ifdef HAVE_PCAP */ +#include + +#ifndef HAVE_RAWNET + #error CS8900.H should not be included if HAVE_RAWNET is not defined! +#endif /* #ifdef HAVE_RAWNET */ #ifndef VICE_CS8900_H #define VICE_CS8900_H @@ -34,20 +36,20 @@ #include "vicetypes.h" struct snapshot_s; -extern int cs8900_snapshot_read_module(struct snapshot_s *s); -extern int cs8900_snapshot_write_module(struct snapshot_s *s); +int cs8900_snapshot_read_module(struct snapshot_s *s); +int cs8900_snapshot_write_module(struct snapshot_s *s); -extern int cs8900_init(void); -extern void cs8900_reset(void); +int cs8900_init(void); +void cs8900_reset(void); -extern int cs8900_activate(const char *net_interface); -extern int cs8900_deactivate(void); -extern void cs8900_shutdown(void); +int cs8900_activate(const char *net_interface); +int cs8900_deactivate(void); +void cs8900_shutdown(void); -extern BYTE cs8900_read(WORD io_address); -extern BYTE cs8900_peek(WORD io_address); -extern void cs8900_store(WORD io_address, BYTE byte); -extern int cs8900_dump(void); +uint8_t cs8900_read(uint16_t io_address); +uint8_t cs8900_peek(uint16_t io_address); +void cs8900_store(uint16_t io_address, uint8_t byte); +int cs8900_dump(void); /* This is a helper for cs8900_receive() to determine if the received frame should be accepted @@ -57,6 +59,6 @@ extern int cs8900_dump(void); from rawnet_arch_receive() if necessary, and must be registered using rawnet_set_should_accept_func at init time. */ -extern int cs8900_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast); +int cs8900_should_accept(unsigned char *buffer, int length, int *phashed, int *phash_index, int *pcorrect_mac, int *pbroadcast, int *pmulticast); #endif diff --git a/src/Emulators/vice/core/flash040core.c b/src/Emulators/vice/core/flash040core.c index f2e40861..4187f36a 100644 --- a/src/Emulators/vice/core/flash040core.c +++ b/src/Emulators/vice/core/flash040core.c @@ -37,27 +37,22 @@ #include "maincpu.h" #include "snapshot.h" #include "vicetypes.h" +#include "vice_debugger_hook.h" /* -------------------------------------------------------------------------- */ /* #define FLASH_DEBUG_ENABLED */ #ifdef FLASH_DEBUG_ENABLED -#define FLASH_DEBUG(x) log_debug x +#define FLASH_DEBUG(x) log_printf x #else #define FLASH_DEBUG(x) #endif -/* Timeout after sector erase command (datasheet states 50us) */ -#define ERASE_SECTOR_TIMEOUT_CYCLES 50 -/* Time taken by sector & chip erase (FIXME: numbers pulled from a hat) */ -#define ERASE_SECTOR_CYCLES 1012 -#define ERASE_CHIP_CYCLES 8192 - struct flash_types_s { - BYTE manufacturer_ID; - BYTE device_ID; - BYTE device_ID_addr; + uint8_t manufacturer_ID; + uint8_t device_ID; + uint8_t device_ID_addr; unsigned int size; unsigned int sector_mask; unsigned int sector_size; @@ -66,42 +61,50 @@ struct flash_types_s { unsigned int magic_2_addr; unsigned int magic_1_mask; unsigned int magic_2_mask; - BYTE status_toggle_bits; + uint8_t status_toggle_bits; + unsigned int erase_sector_timeout_cycles; + unsigned int erase_sector_cycles; + unsigned int erase_chip_cycles; }; typedef struct flash_types_s flash_types_t; static const flash_types_t flash_types[FLASH040_TYPE_NUM] = { - /* 29F040 */ + /* AM29F040 */ { 0x01, 0xa4, 1, 0x80000, 0x70000, 0x10000, 16, 0x5555, 0x2aaa, 0x7fff, 0x7fff, - 0x40 }, - /* 29F040B */ + 0x40, + 80, 2000000, 14000000}, /* may take up to 30s and 120s */ + /* AM29F040B */ { 0x01, 0xa4, 1, 0x80000, 0x70000, 0x10000, 16, 0x555, 0x2aa, 0x7ff, 0x7ff, - 0x40 }, + 0x40, + 50, 1000000, 8000000}, /* may take up to 8s and 64s */ /* 29F010 */ { 0x01, 0x20, 1, 0x20000, 0x1c000, 0x04000, 14, 0x5555, 0x2aaa, 0x7fff, 0x7fff, - 0x40 }, + 0x40, + 80, 1000000, 1000000 }, /* may take up to 15s */ /* 29F032B with A0/1 swap */ { 0x01, 0x41, 1, 0x400000, 0x3f0000, 0x10000, 16, 0x556, 0x2a9, 0x7ff, 0x7ff, - 0x44 }, + 0x44, + 50, 1000000, 64000000 }, /* may take up to 8s */ /* Spansion S29GL064N */ { 0x01, 0x7e, 2, 0x800000, /* FIXME: some models support non-uniform sector layout */ 0x7f0000, 0x10000, 16, 0xaaa, 0x555, 0xfff, 0xfff, - 0x40 }, + 0x40, + 50, 500000, 64000000}, /* may take up to 3.5s and 128s */ }; /* -------------------------------------------------------------------------- */ @@ -144,7 +147,7 @@ inline static void flash_add_sector_to_erase_mask(flash040_context_t *flash040_c { unsigned int sector_num = flash_addr_to_sector_number(flash040_context, addr); - flash040_context->erase_mask[sector_num >> 3] |= (BYTE)(1 << (sector_num & 0x7)); + flash040_context->erase_mask[sector_num >> 3] |= (uint8_t)(1 << (sector_num & 0x7)); } inline static void flash_erase_sector(flash040_context_t *flash040_context, unsigned int sector) @@ -166,10 +169,10 @@ inline static void flash_erase_chip(flash040_context_t *flash040_context) flash040_context->flash_dirty = 1; } -inline static int flash_program_byte(flash040_context_t *flash040_context, unsigned int addr, BYTE byte) +inline static int flash_program_byte(flash040_context_t *flash040_context, unsigned int addr, uint8_t byte) { - BYTE old_data = flash040_context->flash_data[addr]; - BYTE new_data = old_data & byte; + uint8_t old_data = flash040_context->flash_data[addr]; + uint8_t new_data = old_data & byte; FLASH_DEBUG(("Programming 0x%05x with 0x%02x (%02x->%02x)", addr, byte, old_data, old_data & byte)); flash040_context->program_byte = byte; @@ -182,7 +185,7 @@ inline static int flash_program_byte(flash040_context_t *flash040_context, unsig inline static int flash_write_operation_status(flash040_context_t *flash040_context) { return ((flash040_context->program_byte ^ 0x80) & 0x80) /* DQ7 = inverse of programmed data */ - | ((maincpu_clk & 2) << 5) /* DQ6 = toggle bit (2 us) */ + | ((int)(maincpu_clk & 2) << 5) /* DQ6 = toggle bit (2 us) */ | (1 << 5) /* DQ5 = timeout */ ; } @@ -211,7 +214,7 @@ inline static int flash_erase_operation_status(flash040_context_t *flash040_cont static void erase_alarm_handler(CLOCK offset, void *data) { unsigned int i, j; - BYTE m; + uint8_t m; flash040_context_t *flash040_context = (flash040_context_t *)data; alarm_unset(flash040_context->erase_alarm); @@ -220,13 +223,16 @@ static void erase_alarm_handler(CLOCK offset, void *data) switch (flash040_context->flash_state) { case FLASH040_STATE_SECTOR_ERASE_TIMEOUT: + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_sector_cycles); + flash040_context->flash_state = FLASH040_STATE_SECTOR_ERASE; + break; case FLASH040_STATE_SECTOR_ERASE: for (i = 0; i < (8 * FLASH040_ERASE_MASK_SIZE); ++i) { j = i >> 3; - m = (BYTE)(1 << (i & 0x7)); + m = (uint8_t)(1 << (i & 0x7)); if (flash040_context->erase_mask[j] & m) { flash_erase_sector(flash040_context, i); - flash040_context->erase_mask[j] &= (BYTE) ~m; + flash040_context->erase_mask[j] &= (uint8_t) ~m; break; } } @@ -236,7 +242,7 @@ static void erase_alarm_handler(CLOCK offset, void *data) } if (m != 0) { - alarm_set(flash040_context->erase_alarm, maincpu_clk + ERASE_SECTOR_CYCLES); + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_sector_cycles); } else { flash040_context->flash_state = flash040_context->flash_base_state; } @@ -256,7 +262,7 @@ static void erase_alarm_handler(CLOCK offset, void *data) /* -------------------------------------------------------------------------- */ static void flash040core_store_internal(flash040_context_t *flash040_context, - unsigned int addr, BYTE byte) + unsigned int addr, uint8_t byte) { #ifdef FLASH_DEBUG_ENABLED flash040_state_t old_state = flash040_context->flash_state; @@ -333,12 +339,12 @@ static void flash040core_store_internal(flash040_context_t *flash040_context, if (flash_magic_1(flash040_context, addr) && (byte == 0x10)) { flash040_context->flash_state = FLASH040_STATE_CHIP_ERASE; flash040_context->program_byte = 0; - alarm_set(flash040_context->erase_alarm, maincpu_clk + ERASE_CHIP_CYCLES); + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_chip_cycles); } else if (byte == 0x30) { flash_add_sector_to_erase_mask(flash040_context, addr); flash040_context->program_byte = 0; flash040_context->flash_state = FLASH040_STATE_SECTOR_ERASE_TIMEOUT; - alarm_set(flash040_context->erase_alarm, maincpu_clk + ERASE_SECTOR_TIMEOUT_CYCLES); + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_sector_timeout_cycles); } else { flash040_context->flash_state = flash040_context->flash_base_state; } @@ -365,7 +371,7 @@ static void flash040core_store_internal(flash040_context_t *flash040_context, case FLASH040_STATE_SECTOR_ERASE_SUSPEND: if (byte == 0x30) { flash040_context->flash_state = FLASH040_STATE_SECTOR_ERASE; - alarm_set(flash040_context->erase_alarm, maincpu_clk + ERASE_SECTOR_CYCLES); + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_sector_cycles); } break; @@ -390,23 +396,22 @@ static void flash040core_store_internal(flash040_context_t *flash040_context, /* -------------------------------------------------------------------------- */ -void flash040core_store(flash040_context_t *flash040_context, unsigned int addr, BYTE byte) +void flash040core_store(flash040_context_t *flash040_context, unsigned int addr, uint8_t byte) { if (maincpu_rmw_flag) { maincpu_clk--; - c64d_maincpu_clk--; + VICE_HOOK_CPU_CLK_DEC(); flash040core_store_internal(flash040_context, addr, flash040_context->last_read); maincpu_clk++; - c64d_maincpu_clk++; + VICE_HOOK_CPU_CLK_INC(); } flash040core_store_internal(flash040_context, addr, byte); } - -BYTE flash040core_read(flash040_context_t *flash040_context, unsigned int addr) +uint8_t flash040core_read(flash040_context_t *flash040_context, unsigned int addr) { - BYTE value; + uint8_t value; #ifdef FLASH_DEBUG_ENABLED flash040_state_t old_state = flash040_context->flash_state; #endif @@ -459,7 +464,7 @@ BYTE flash040core_read(flash040_context_t *flash040_context, unsigned int addr) return value; } -BYTE flash040core_peek(flash040_context_t *flash040_context, unsigned int addr) +uint8_t flash040core_peek(flash040_context_t *flash040_context, unsigned int addr) { return flash040_context->flash_data[addr]; } @@ -476,7 +481,7 @@ void flash040core_reset(flash040_context_t *flash040_context) void flash040core_init(struct flash040_context_s *flash040_context, struct alarm_context_s *alarm_context, - flash040_type_t type, BYTE *data) + flash040_type_t type, uint8_t *data) { FLASH_DEBUG(("Init")); flash040_context->flash_data = data; @@ -502,15 +507,15 @@ void flash040core_shutdown(flash040_context_t *flash040_context) int flash040core_snapshot_write_module(snapshot_t *s, flash040_context_t *flash040_context, const char *name) { snapshot_module_t *m; - BYTE state, base_state; + uint8_t state, base_state; m = snapshot_module_create(s, name, FLASH040_DUMP_VER_MAJOR, FLASH040_DUMP_VER_MINOR); if (m == NULL) { return -1; } - state = (BYTE)(flash040_context->flash_state); - base_state = (BYTE)(flash040_context->flash_base_state); + state = (uint8_t)(flash040_context->flash_state); + base_state = (uint8_t)(flash040_context->flash_base_state); if (0 || (SMW_B(m, state) < 0) @@ -528,7 +533,7 @@ int flash040core_snapshot_write_module(snapshot_t *s, flash040_context_t *flash0 int flash040core_snapshot_read_module(snapshot_t *s, flash040_context_t *flash040_context, const char *name) { - BYTE vmajor, vminor, state, base_state; + uint8_t vmajor, vminor, state, base_state; snapshot_module_t *m; m = snapshot_module_open(s, name, &vmajor, &vminor); @@ -562,7 +567,7 @@ int flash040core_snapshot_read_module(snapshot_t *s, flash040_context_t *flash04 case FLASH040_STATE_SECTOR_ERASE: case FLASH040_STATE_CHIP_ERASE: /* the alarm timing is not saved, just use some value for now */ - alarm_set(flash040_context->erase_alarm, maincpu_clk + ERASE_SECTOR_CYCLES); + alarm_set(flash040_context->erase_alarm, maincpu_clk + flash_types[flash040_context->flash_type].erase_sector_cycles); break; default: diff --git a/src/Emulators/vice/core/flash800core.c b/src/Emulators/vice/core/flash800core.c new file mode 100644 index 00000000..ba1e7d6f --- /dev/null +++ b/src/Emulators/vice/core/flash800core.c @@ -0,0 +1,543 @@ +/* + * flash800core.c - (MX)29F800C[TB] Flash emulation (preliminary, incomplete). + * + * Written by + * Hannu Nuotio + * Extended by + * Marko Makela + * Extended by + * Chester Kollschen + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "alarm.h" +#include "flash800.h" +#include "lib.h" +#include "log.h" +#include "maincpu.h" +#include "snapshot.h" +#include "vicetypes.h" + +/* -------------------------------------------------------------------------- */ + +/* #define FLASH_DEBUG_ENABLED */ + +#ifdef FLASH_DEBUG_ENABLED +#define FLASH_DEBUG(x) log_printf x +#else +#define FLASH_DEBUG(x) +#endif + +struct flash_types_s { + uint8_t manufacturer_ID; + uint8_t device_ID; + uint8_t device_ID_addr; + unsigned int size; + unsigned int sector_mask; + unsigned int sector_size; + unsigned int sector_shift; + unsigned int magic_1_addr; + unsigned int magic_2_addr; + unsigned int magic_1_mask; + unsigned int magic_2_mask; + uint8_t status_toggle_bits; + unsigned int erase_sector_timeout_cycles; + unsigned int erase_sector_cycles; + unsigned int erase_chip_cycles; +}; +typedef struct flash_types_s flash_types_t; + +static const flash_types_t flash_types[FLASH800_TYPE_NUM] = { + /* MX29F800CB */ + { 0xc2, 0x58, 1, + 0x100000, + 0x0f0000, 0x010000, 16, + 0xaaa, 0x555, 0xfff, 0xfff, + 0x40, + 40, 700000, 8000000}, /* may take up to 15s and 32s */ +}; + +/* -------------------------------------------------------------------------- */ + +inline static int flash_magic_1(flash800_context_t *flash800_context, unsigned int addr) +{ + return ((addr & flash_types[flash800_context->flash_type].magic_1_mask) == flash_types[flash800_context->flash_type].magic_1_addr); +} + +inline static int flash_magic_2(flash800_context_t *flash800_context, unsigned int addr) +{ + return ((addr & flash_types[flash800_context->flash_type].magic_2_mask) == flash_types[flash800_context->flash_type].magic_2_addr); +} + +inline static void flash_clear_erase_mask(flash800_context_t *flash800_context) +{ + int i; + + for (i = 0; i < FLASH800_ERASE_MASK_SIZE; ++i) { + flash800_context->erase_mask[i] = 0; + } +} + +inline static unsigned int flash_sector_to_addr(flash800_context_t *flash800_context, unsigned int sector) +{ + unsigned int sector_size = flash_types[flash800_context->flash_type].sector_size; + + return sector * sector_size; +} + +inline static unsigned int flash_addr_to_sector_number(flash800_context_t *flash800_context, unsigned int addr) +{ + unsigned int sector_addr = flash_types[flash800_context->flash_type].sector_mask & addr; + unsigned int sector_shift = flash_types[flash800_context->flash_type].sector_shift; + + return sector_addr >> sector_shift; +} + +inline static void flash_add_sector_to_erase_mask(flash800_context_t *flash800_context, unsigned int addr) +{ + unsigned int sector_num = flash_addr_to_sector_number(flash800_context, addr); + + flash800_context->erase_mask[sector_num >> 3] |= (uint8_t)(1 << (sector_num & 0x7)); +} + +inline static void flash_erase_sector(flash800_context_t *flash800_context, unsigned int sector) +{ + unsigned int sector_size = flash_types[flash800_context->flash_type].sector_size; + unsigned int sector_addr; + + sector_addr = flash_sector_to_addr(flash800_context, sector); + + FLASH_DEBUG(("Erasing 0x%x - 0x%x", sector_addr, sector_addr + sector_size - 1)); + memset(&(flash800_context->flash_data[sector_addr]), 0xff, sector_size); + flash800_context->flash_dirty = 1; +} + +inline static void flash_erase_chip(flash800_context_t *flash800_context) +{ + FLASH_DEBUG(("Erasing chip")); + memset(flash800_context->flash_data, 0xff, flash_types[flash800_context->flash_type].size); + flash800_context->flash_dirty = 1; +} + +inline static int flash_program_byte(flash800_context_t *flash800_context, unsigned int addr, uint8_t byte) +{ + uint8_t old_data = flash800_context->flash_data[addr]; + uint8_t new_data = old_data & byte; + + FLASH_DEBUG(("Programming 0x%05x with 0x%02x (%02x->%02x)", addr, byte, old_data, old_data & byte)); + flash800_context->program_byte = byte; + flash800_context->flash_data[addr] = new_data; + flash800_context->flash_dirty = 1; + + return (new_data == byte) ? 1 : 0; +} + +inline static int flash_write_operation_status(flash800_context_t *flash800_context) +{ + return ((flash800_context->program_byte ^ 0x80) & 0x80) /* DQ7 = inverse of programmed data */ + | (((unsigned int)maincpu_clk & 2) << 5) /* DQ6 = toggle bit (2 us) */ + | (1 << 5) /* DQ5 = timeout */ + ; +} + +inline static int flash_erase_operation_status(flash800_context_t *flash800_context) +{ + int v; + + /* DQ6 = toggle bit */ + v = flash800_context->program_byte; + + /* toggle the toggle bit(s) */ + /* FIXME better toggle bit II emulation */ + flash800_context->program_byte ^= flash_types[flash800_context->flash_type].status_toggle_bits; + + /* DQ3 = sector erase timer */ + if (flash800_context->flash_state != FLASH800_STATE_SECTOR_ERASE_TIMEOUT) { + v |= 0x08; + } + + return v; +} + +/* -------------------------------------------------------------------------- */ + +static void erase_alarm_handler(CLOCK offset, void *data) +{ + unsigned int i, j; + uint8_t m; + flash800_context_t *flash800_context = (flash800_context_t *)data; + + alarm_unset(flash800_context->erase_alarm); + + FLASH_DEBUG(("Erase alarm, state %i", (int)flash800_context->flash_state)); + + switch (flash800_context->flash_state) { + case FLASH800_STATE_SECTOR_ERASE_TIMEOUT: + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_sector_cycles); + flash800_context->flash_state = FLASH800_STATE_SECTOR_ERASE; + break; + case FLASH800_STATE_SECTOR_ERASE: + for (i = 0; i < (8 * FLASH800_ERASE_MASK_SIZE); ++i) { + j = i >> 3; + m = (uint8_t)(1 << (i & 0x7)); + if (flash800_context->erase_mask[j] & m) { + flash_erase_sector(flash800_context, i); + flash800_context->erase_mask[j] &= (uint8_t) ~m; + break; + } + } + + for (i = 0, m = 0; i < FLASH800_ERASE_MASK_SIZE; ++i) { + m |= flash800_context->erase_mask[i]; + } + + if (m != 0) { + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_sector_cycles); + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_CHIP_ERASE: + flash_erase_chip(flash800_context); + flash800_context->flash_state = flash800_context->flash_base_state; + break; + + default: + FLASH_DEBUG(("Erase alarm - error, state %i unhandled!", (int)flash800_context->flash_state)); + break; + } +} + +/* -------------------------------------------------------------------------- */ + +static void flash800core_store_internal(flash800_context_t *flash800_context, + unsigned int addr, uint8_t byte) +{ +#ifdef FLASH_DEBUG_ENABLED + flash800_state_t old_state = flash800_context->flash_state; + flash800_state_t old_base_state = flash800_context->flash_base_state; +#endif + + switch (flash800_context->flash_state) { + case FLASH800_STATE_READ: + if (flash_magic_1(flash800_context, addr) && (byte == 0xaa)) { + flash800_context->flash_state = FLASH800_STATE_MAGIC_1; + } + break; + + case FLASH800_STATE_MAGIC_1: + if (flash_magic_2(flash800_context, addr) && (byte == 0x55)) { + flash800_context->flash_state = FLASH800_STATE_MAGIC_2; + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_MAGIC_2: + if (flash_magic_1(flash800_context, addr)) { + switch (byte) { + case 0x90: + flash800_context->flash_state = FLASH800_STATE_AUTOSELECT; + flash800_context->flash_base_state = FLASH800_STATE_AUTOSELECT; + break; + case 0xf0: + flash800_context->flash_state = FLASH800_STATE_READ; + flash800_context->flash_base_state = FLASH800_STATE_READ; + break; + case 0xa0: + flash800_context->flash_state = FLASH800_STATE_BYTE_PROGRAM; + break; + case 0x80: + flash800_context->flash_state = FLASH800_STATE_ERASE_MAGIC_1; + break; + default: + flash800_context->flash_state = flash800_context->flash_base_state; + break; + } + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_BYTE_PROGRAM: + if (flash_program_byte(flash800_context, addr, byte)) { + /* The byte program time is short enough to ignore */ + flash800_context->flash_state = flash800_context->flash_base_state; + } else { + flash800_context->flash_state = FLASH800_STATE_BYTE_PROGRAM_ERROR; + } + break; + + case FLASH800_STATE_ERASE_MAGIC_1: + if (flash_magic_1(flash800_context, addr) && (byte == 0xaa)) { + flash800_context->flash_state = FLASH800_STATE_ERASE_MAGIC_2; + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_ERASE_MAGIC_2: + if (flash_magic_2(flash800_context, addr) && (byte == 0x55)) { + flash800_context->flash_state = FLASH800_STATE_ERASE_SELECT; + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_ERASE_SELECT: + if (flash_magic_1(flash800_context, addr) && (byte == 0x10)) { + flash800_context->flash_state = FLASH800_STATE_CHIP_ERASE; + flash800_context->program_byte = 0; + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_chip_cycles); + } else if (byte == 0x30) { + flash_add_sector_to_erase_mask(flash800_context, addr); + flash800_context->program_byte = 0; + flash800_context->flash_state = FLASH800_STATE_SECTOR_ERASE_TIMEOUT; + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_sector_timeout_cycles); + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + } + break; + + case FLASH800_STATE_SECTOR_ERASE_TIMEOUT: + if (byte == 0x30) { + flash_add_sector_to_erase_mask(flash800_context, addr); + } else { + flash800_context->flash_state = flash800_context->flash_base_state; + flash_clear_erase_mask(flash800_context); + alarm_unset(flash800_context->erase_alarm); + } + break; + + case FLASH800_STATE_SECTOR_ERASE: + /* TODO not all models support suspending */ + if (byte == 0xb0) { + flash800_context->flash_state = FLASH800_STATE_SECTOR_ERASE_SUSPEND; + alarm_unset(flash800_context->erase_alarm); + } + break; + + case FLASH800_STATE_SECTOR_ERASE_SUSPEND: + if (byte == 0x30) { + flash800_context->flash_state = FLASH800_STATE_SECTOR_ERASE; + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_sector_cycles); + } + break; + + case FLASH800_STATE_BYTE_PROGRAM_ERROR: + case FLASH800_STATE_AUTOSELECT: + if (flash_magic_1(flash800_context, addr) && (byte == 0xaa)) { + flash800_context->flash_state = FLASH800_STATE_MAGIC_1; + } + if (byte == 0xf0) { + flash800_context->flash_state = FLASH800_STATE_READ; + flash800_context->flash_base_state = FLASH800_STATE_READ; + } + break; + + case FLASH800_STATE_CHIP_ERASE: + default: + break; + } + + FLASH_DEBUG(("Write %02x to %05x, state %i->%i (base state %i->%i)", byte, addr, (int)old_state, (int)flash800_context->flash_state, (int)old_base_state, (int)flash800_context->flash_base_state)); +} + +/* -------------------------------------------------------------------------- */ + +void flash800core_store(flash800_context_t *flash800_context, unsigned int addr, uint8_t byte) +{ + if (maincpu_rmw_flag) { + maincpu_clk--; + flash800core_store_internal(flash800_context, addr, flash800_context->last_read); + maincpu_clk++; + } + + flash800core_store_internal(flash800_context, addr, byte); +} + +uint8_t flash800core_read(flash800_context_t *flash800_context, unsigned int addr) +{ + uint8_t value; +#ifdef FLASH_DEBUG_ENABLED + flash800_state_t old_state = flash800_context->flash_state; +#endif + + switch (flash800_context->flash_state) { + case FLASH800_STATE_AUTOSELECT: + + if ((addr & 0xff) == 0) { + value = flash_types[flash800_context->flash_type].manufacturer_ID; + } else if ((addr & 0xff) == flash_types[flash800_context->flash_type].device_ID_addr) { + value = flash_types[flash800_context->flash_type].device_ID; + } else if ((addr & 0xff) == 2) { + value = 0; + } else { + value = flash800_context->flash_data[addr]; + } + break; + + case FLASH800_STATE_BYTE_PROGRAM_ERROR: + value = flash_write_operation_status(flash800_context); + break; + + case FLASH800_STATE_SECTOR_ERASE_SUSPEND: + case FLASH800_STATE_CHIP_ERASE: + case FLASH800_STATE_SECTOR_ERASE: + case FLASH800_STATE_SECTOR_ERASE_TIMEOUT: + value = flash_erase_operation_status(flash800_context); + break; + + default: + /* The state doesn't reset if a read occurs during a command sequence */ + /* fall through */ + case FLASH800_STATE_READ: + value = flash800_context->flash_data[addr]; + break; + } + +#ifdef FLASH_DEBUG_ENABLED + if (old_state != FLASH800_STATE_READ) { + FLASH_DEBUG(("Read %02x from %05x, state %i->%i", value, addr, (int)old_state, (int)flash800_context->flash_state)); + } +#endif + + flash800_context->last_read = value; + return value; +} + +uint8_t flash800core_peek(flash800_context_t *flash800_context, unsigned int addr) +{ + return flash800_context->flash_data[addr]; +} + +void flash800core_reset(flash800_context_t *flash800_context) +{ + FLASH_DEBUG(("Reset")); + flash800_context->flash_state = FLASH800_STATE_READ; + flash800_context->flash_base_state = FLASH800_STATE_READ; + flash800_context->program_byte = 0; + flash_clear_erase_mask(flash800_context); + alarm_unset(flash800_context->erase_alarm); +} + +void flash800core_init(struct flash800_context_s *flash800_context, + struct alarm_context_s *alarm_context, + flash800_type_t type, uint8_t *data) +{ + FLASH_DEBUG(("Init")); + flash800_context->flash_data = data; + flash800_context->flash_type = type; + flash800_context->flash_state = FLASH800_STATE_READ; + flash800_context->flash_base_state = FLASH800_STATE_READ; + flash800_context->program_byte = 0; + flash_clear_erase_mask(flash800_context); + flash800_context->flash_dirty = 0; + flash800_context->erase_alarm = alarm_new(alarm_context, "Flash800Alarm", erase_alarm_handler, flash800_context); +} + +void flash800core_shutdown(flash800_context_t *flash800_context) +{ + FLASH_DEBUG(("Shutdown")); +} + +/* -------------------------------------------------------------------------- */ + +#define FLASH800_DUMP_VER_MAJOR 2 +#define FLASH800_DUMP_VER_MINOR 0 + +int flash800core_snapshot_write_module(snapshot_t *s, flash800_context_t *flash800_context, const char *name) +{ + snapshot_module_t *m; + uint8_t state, base_state; + + m = snapshot_module_create(s, name, FLASH800_DUMP_VER_MAJOR, FLASH800_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + state = (uint8_t)(flash800_context->flash_state); + base_state = (uint8_t)(flash800_context->flash_base_state); + + if (0 + || (SMW_B(m, state) < 0) + || (SMW_B(m, base_state) < 0) + || (SMW_B(m, flash800_context->program_byte) < 0) + || (SMW_BA(m, flash800_context->erase_mask, FLASH800_ERASE_MASK_SIZE) < 0) + || (SMW_B(m, flash800_context->last_read) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int flash800core_snapshot_read_module(snapshot_t *s, flash800_context_t *flash800_context, const char *name) +{ + uint8_t vmajor, vminor, state, base_state; + snapshot_module_t *m; + + m = snapshot_module_open(s, name, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if (vmajor != FLASH800_DUMP_VER_MAJOR) { + snapshot_module_close(m); + return -1; + } + + if (0 + || (SMR_B(m, &state) < 0) + || (SMR_B(m, &base_state) < 0) + || (SMR_B(m, &(flash800_context->program_byte)) < 0) + || (SMR_BA(m, flash800_context->erase_mask, FLASH800_ERASE_MASK_SIZE) < 0) + || (SMR_B(m, &(flash800_context->last_read)) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + flash800_context->flash_state = (flash800_state_t)state; + flash800_context->flash_base_state = (flash800_state_t)base_state; + + /* Restore alarm if needed */ + switch (flash800_context->flash_state) { + case FLASH800_STATE_SECTOR_ERASE_TIMEOUT: + case FLASH800_STATE_SECTOR_ERASE: + case FLASH800_STATE_CHIP_ERASE: + /* the alarm timing is not saved, just use some value for now */ + alarm_set(flash800_context->erase_alarm, maincpu_clk + flash_types[flash800_context->flash_type].erase_sector_cycles); + break; + + default: + break; + } + + return 0; +} diff --git a/src/Emulators/vice/core/fmopl.c b/src/Emulators/vice/core/fmopl.c index da80662f..a50a1504 100644 --- a/src/Emulators/vice/core/fmopl.c +++ b/src/Emulators/vice/core/fmopl.c @@ -80,13 +80,11 @@ Revision History: #include "fmopl.h" #include "lib.h" +#include "maincpu.h" #include "snapshot.h" #include "log.h" -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif #define FINAL_SH (0) #define MAXOUT (+32767) @@ -109,7 +107,7 @@ Revision History: /* sinwave entries */ #define SIN_BITS 10 -#define SIN_LEN (1 << SIN_BITS) +#define SIN_LEN (1u << SIN_BITS) #define SIN_MASK (SIN_LEN - 1) #define TL_RES_LEN (256) /* 8 bits addressing (real chip) */ @@ -329,13 +327,13 @@ static const double mul_tab[16] = { * TL_RES_LEN - sinus resolution (X axis) */ #define TL_TAB_LEN (12 * 2 * TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; +static signed int *tl_tab = NULL; #define ENV_QUIET (TL_TAB_LEN >> 4) /* sin waveform table in 'decibel' scale */ /* four waveforms on OPL2 type chips */ -static unsigned int sin_tab[SIN_LEN * 16]; +static unsigned int *sin_tab = NULL; /* LFO Amplitude Modulation table (verified on real YM3812) 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples @@ -454,6 +452,42 @@ static signed int output[1]; static UINT32 LFO_AM; static INT32 LFO_PM; +/* ---------------------------------------------------------------------*/ +/* timer support functions */ + +static int OPLTimerOver(FM_OPL *OPL, int c); + +static UINT32 fmopl_timer_80 = 0; +static UINT32 fmopl_timer_320 = 0; + +void fmopl_set_machine_parameter(long clock_rate) +{ + fmopl_timer_80 = (UINT32)(clock_rate * 80 / 1000000); + fmopl_timer_320 = (UINT32)(clock_rate * 320 / 1000000); +} + +static void fmopl_alarm_A(CLOCK offset, void *data) +{ + FM_OPL *OPL = (FM_OPL *)data; + CLOCK new_start = maincpu_clk - offset + ((256 - OPL->T[0]) * fmopl_timer_80); + + alarm_unset(OPL->fmopl_alarm[0]); + alarm_set(OPL->fmopl_alarm[0], new_start); + OPLTimerOver(OPL, 0); +} + +static void fmopl_alarm_B(CLOCK offset, void *data) +{ + FM_OPL *OPL = (FM_OPL *)data; + CLOCK new_start = maincpu_clk - offset + ((256 - OPL->T[1]) * fmopl_timer_320); + + alarm_unset(OPL->fmopl_alarm[1]); + alarm_set(OPL->fmopl_alarm[1], new_start); + OPLTimerOver(OPL, 1); +} + +/* ---------------------------------------------------------------------*/ + inline static int limit(int val, int max, int min) { if (val > max) { @@ -918,6 +952,15 @@ static int init_tables(void) signed int n; double o, m; + if (tl_tab == NULL) { + tl_tab = lib_malloc(TL_TAB_LEN * sizeof(signed int)); + } + + if (sin_tab == NULL) { + sin_tab = lib_malloc(SIN_LEN * 4 * sizeof(unsigned int)); + } + + for (x = 0; x < TL_RES_LEN; x++) { m = (1 << 16) / pow(2, (x + 1) * (ENV_STEP / 4.0) / 8.0); m = floor(m); @@ -1011,6 +1054,15 @@ static int init_tables(void) static void OPLCloseTable( void ) { + if (tl_tab) { + lib_free(tl_tab); + tl_tab = NULL; + } + + if (sin_tab) { + lib_free(sin_tab); + sin_tab = NULL; + } } static void OPL_initalize(FM_OPL *OPL) @@ -1175,10 +1227,18 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) } break; case 0x02: /* Timer 1 */ - OPL->T[0] = (256 - v) * 4; + OPL->T[0] = v; + if (OPL->fmopl_alarm_pending[0]) { + alarm_unset(OPL->fmopl_alarm[0]); + alarm_set(OPL->fmopl_alarm[0], maincpu_clk + ((256 - v) * fmopl_timer_80)); + } break; case 0x03: /* Timer 2 */ - OPL->T[1] = (256 - v) * 16; + OPL->T[1] = v; + if (OPL->fmopl_alarm_pending[1]) { + alarm_unset(OPL->fmopl_alarm[1]); + alarm_set(OPL->fmopl_alarm[1], maincpu_clk + ((256 - v) * fmopl_timer_320)); + } break; case 0x04: /* IRQ clear / mask and Timer enable */ if (v & 0x80) { /* IRQ flag clear */ @@ -1200,6 +1260,38 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v) if (OPL->st[0] != st1) { OPL->st[0] = st1; } + + /* Timer 1 changes */ + if ((v & 0x40) == 0) { + if ((v & 1) == 0) { + if (OPL->fmopl_alarm_pending[0]) { + alarm_unset(OPL->fmopl_alarm[0]); + OPL->fmopl_alarm_pending[0] = 0; + } + } else { + if (OPL->fmopl_alarm_pending[0]) { + alarm_unset(OPL->fmopl_alarm[0]); + } + alarm_set(OPL->fmopl_alarm[0], maincpu_clk + ((256 - OPL->T[0]) * fmopl_timer_80)); + OPL->fmopl_alarm_pending[0] = 1; + } + } + + /* Timer 2 changes */ + if ((v & 0x20) == 0) { + if ((v & 2) == 0) { + if (OPL->fmopl_alarm_pending[1]) { + alarm_unset(OPL->fmopl_alarm[1]); + OPL->fmopl_alarm_pending[1] = 0; + } + } else { + if (OPL->fmopl_alarm_pending[1]) { + alarm_unset(OPL->fmopl_alarm[1]); + } + alarm_set(OPL->fmopl_alarm[1], maincpu_clk + ((256 - OPL->T[1]) * fmopl_timer_320)); + OPL->fmopl_alarm_pending[1] = 1; + } + } } break; case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ @@ -1439,6 +1531,14 @@ static void OPLResetChip(FM_OPL *OPL) CH->SLOT[s].connect1 = &output[0]; } } + + if (OPL->fmopl_alarm_pending[0]) { + alarm_unset(OPL->fmopl_alarm[0]); + } + + if (OPL->fmopl_alarm_pending[1]) { + alarm_unset(OPL->fmopl_alarm[1]); + } } /* Create one of virtual YM3812/YM3526 */ @@ -1475,6 +1575,11 @@ static FM_OPL *OPLCreate(UINT32 clock, UINT32 rate, int type) OPL->clock = clock; OPL->rate = rate; + OPL->fmopl_alarm[0] = alarm_new(maincpu_alarm_context, "FMOPL Timer A", fmopl_alarm_A, (void *)OPL); + OPL->fmopl_alarm[1] = alarm_new(maincpu_alarm_context, "FMOPL Timer B", fmopl_alarm_B, (void *)OPL); + OPL->fmopl_alarm_pending[0] = 0; + OPL->fmopl_alarm_pending[1] = 0; + /* init global tables */ OPL_initalize(OPL); @@ -1484,6 +1589,16 @@ static FM_OPL *OPLCreate(UINT32 clock, UINT32 rate, int type) /* Destroy one of virtual YM3812 */ static void OPLDestroy(FM_OPL *OPL) { + if (OPL->fmopl_alarm_pending[0]) { + alarm_unset(OPL->fmopl_alarm[0]); + } + alarm_destroy(OPL->fmopl_alarm[0]); + + if (OPL->fmopl_alarm_pending[1]) { + alarm_unset(OPL->fmopl_alarm[1]); + } + alarm_destroy(OPL->fmopl_alarm[1]); + OPL_UnLockTable(); lib_free(OPL); } diff --git a/src/Emulators/vice/core/fmopl.h b/src/Emulators/vice/core/fmopl.h index 0795b4db..6a2ac31f 100644 --- a/src/Emulators/vice/core/fmopl.h +++ b/src/Emulators/vice/core/fmopl.h @@ -1,16 +1,18 @@ #ifndef VICE_FMOPL_H #define VICE_FMOPL_H +#include "alarm.h" + /* select output bits size of output : 8 or 16 */ #define OPL_SAMPLE_BITS 16 /* compiler dependence */ -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ +typedef uint8_t UINT8; /* unsigned 8bit */ +typedef uint16_t UINT16; /* unsigned 16bit */ +typedef uint32_t UINT32; /* unsigned 32bit */ +typedef int8_t INT8; /* signed 8bit */ +typedef int16_t INT16; /* signed 16bit */ +typedef int32_t INT32; /* signed 32bit */ typedef INT16 OPLSAMPLE; @@ -93,6 +95,8 @@ typedef struct fm_opl_f { UINT32 T[2]; /* timer counters */ UINT8 st[2]; /* timer enable */ + alarm_t *fmopl_alarm[2]; /* timer alarms */ + UINT8 fmopl_alarm_pending[2]; /* timer alarms pending */ UINT8 type; /* chip type */ UINT8 address; /* address register */ @@ -112,14 +116,14 @@ typedef struct fm_opl_f { * 'clock' is the chip clock in Hz * 'rate' is sampling rate */ -extern FM_OPL *ym3812_init(UINT32 clock, UINT32 rate); +FM_OPL *ym3812_init(UINT32 clock, UINT32 rate); -extern void ym3812_shutdown(FM_OPL *chip); -extern void ym3812_reset_chip(FM_OPL *chip); -extern int ym3812_write(FM_OPL *chip, int a, int v); -extern unsigned char ym3812_read(FM_OPL *chip, int a); -extern unsigned char ym3812_peek(FM_OPL *chip, int a); -extern int ym3812_timer_over(FM_OPL *chip, int c); +void ym3812_shutdown(FM_OPL *chip); +void ym3812_reset_chip(FM_OPL *chip); +int ym3812_write(FM_OPL *chip, int a, int v); +unsigned char ym3812_read(FM_OPL *chip, int a); +unsigned char ym3812_peek(FM_OPL *chip, int a); +int ym3812_timer_over(FM_OPL *chip, int c); /* * Generate samples for one of the YM3812's @@ -128,7 +132,7 @@ extern int ym3812_timer_over(FM_OPL *chip, int c); * '*buffer' is the output buffer pointer * 'length' is the number of samples that should be generated */ -extern void ym3812_update_one(FM_OPL *chip, OPLSAMPLE *buffer, int length); +void ym3812_update_one(FM_OPL *chip, OPLSAMPLE *buffer, int length); /* * Initialize YM3526 emulator. @@ -137,18 +141,21 @@ extern void ym3812_update_one(FM_OPL *chip, OPLSAMPLE *buffer, int length); * 'clock' is the chip clock in Hz * 'rate' is sampling rate */ -extern FM_OPL *ym3526_init(UINT32 clock, UINT32 rate); +FM_OPL *ym3526_init(UINT32 clock, UINT32 rate); -extern void ym3526_shutdown(FM_OPL *chip); -extern void ym3526_reset_chip(FM_OPL *chip); -extern int ym3526_write(FM_OPL *chip, int a, int v); -extern unsigned char ym3526_read(FM_OPL *chip, int a); -extern unsigned char ym3526_peek(FM_OPL *chip, int a); -extern int ym3526_timer_over(FM_OPL *chip, int c); +void ym3526_shutdown(FM_OPL *chip); +void ym3526_reset_chip(FM_OPL *chip); +int ym3526_write(FM_OPL *chip, int a, int v); +unsigned char ym3526_read(FM_OPL *chip, int a); +unsigned char ym3526_peek(FM_OPL *chip, int a); +int ym3526_timer_over(FM_OPL *chip, int c); struct snapshot_s; -extern int ym3526_snapshot_read_module(struct snapshot_s *s); -extern int ym3526_snapshot_write_module(struct snapshot_s *s); + +int ym3526_snapshot_read_module(struct snapshot_s *s); +int ym3526_snapshot_write_module(struct snapshot_s *s); + +void fmopl_set_machine_parameter(long clock_rate); /* * Generate samples for one of the YM3526's @@ -157,10 +164,10 @@ extern int ym3526_snapshot_write_module(struct snapshot_s *s); * '*buffer' is the output buffer pointer * 'length' is the number of samples that should be generated */ -extern void ym3526_update_one(FM_OPL *chip, OPLSAMPLE *buffer, int length); +void ym3526_update_one(FM_OPL *chip, OPLSAMPLE *buffer, int length); -extern int connect1_is_output0(int *connect); -extern void set_connect1(FM_OPL *chip, int x, int y, int output0); +int connect1_is_output0(int *connect); +void set_connect1(FM_OPL *chip, int x, int y, int output0); #endif /* VICE_FMOPL_H */ diff --git a/src/Emulators/vice/core/i8255a.c b/src/Emulators/vice/core/i8255a.c new file mode 100644 index 00000000..6342805c --- /dev/null +++ b/src/Emulators/vice/core/i8255a.c @@ -0,0 +1,235 @@ +/* + * i8255a.c - Intel 8255a + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* + +Currently used by: + +cmdhd + +*/ + +#include "vice.h" + +#include "log.h" +#include "vicetypes.h" +#include "snapshot.h" +#include "monitor.h" +#include "i8255a.h" + +/* #define I8255ALOG */ +/* #define I8255ADBG */ + +#define LOG LOG_DEFAULT + +#ifdef I8255ALOG +#define LOG1(_x_) log_message _x_ +#else +#define LOG1(_x_) +#endif + +#ifdef i8255ADBG +#define DBG(_x_) log_message _x_ +#else +#define DBG(_x_) +#endif + +#define CRIT(_x_) log_error _x_ + +void i8255a_reset(i8255a_state *ctx) +{ + ctx->ctrl = 0x1b; + ctx->data[0] = 0; + ctx->data[1] = 0; + ctx->data[2] = 0; + + /* on reset relay inputs to outputs */ + if (ctx->get_pa && ctx->set_pa) { + ctx->set_pa(ctx, ctx->get_pa(ctx, 0), 0); + } + if (ctx->get_pb && ctx->set_pb) { + ctx->set_pb(ctx, ctx->get_pb(ctx, 1), 1); + } + if (ctx->get_pc && ctx->set_pc) { + ctx->set_pc(ctx, ctx->get_pc(ctx, 2), 2); + } +} + +uint8_t i8255a_read(i8255a_state *ctx, int8_t reg) +{ + uint8_t data = 0xff; + + switch(reg & 3) { + case 0: + if (ctx->ctrl & I8255A_G1_PA) { + if (ctx->get_pa) { + data = ctx->get_pa(ctx, reg); + } + } else { + data = ctx->data[0]; + } + break; + case 1: + if (ctx->ctrl & I8255A_G2_PB) { + if (ctx->get_pb) { + data = ctx->get_pb(ctx, reg); + } + } else { + data = ctx->data[1]; + } + break; + case 2: + if (ctx->ctrl & (I8255A_G2_PC | I8255A_G1_PC)) { + if (ctx->get_pc) { + data = ctx->get_pc(ctx, reg); + } + } + if (!(ctx->ctrl & I8255A_G2_PC)) { + data = (data & 0xf0) | (ctx->data[2] & 0x0f); + } + if (!(ctx->ctrl & I8255A_G1_PC)) { + data = (data & 0x0f) | (ctx->data[2] & 0xf0); + } + break; + } + return data; +} + +uint8_t i8255a_peek(i8255a_state *ctx, int8_t reg) +{ + if ((reg & 3) == 3) { + return ctx->ctrl; + } else { + return i8255a_read(ctx, reg | 4); + } +} + +void i8255a_store(i8255a_state *ctx, int8_t reg, uint8_t data) +{ + reg = reg & 3; + switch (reg) { + case 0: + ctx->data[0] = data; + if (!(ctx->ctrl & I8255A_G1_PA) && ctx->set_pa) { + ctx->set_pa(ctx, ctx->data[0], 0); + } + break; + case 1: + ctx->data[1] = data; + if (!(ctx->ctrl & I8255A_G2_PB) && ctx->set_pb) { + ctx->set_pb(ctx, ctx->data[1], 1); + } + break; + case 3: + if (!(data & I8255A_MODE)) { + break; + } + if ( (data & I8255A_G2_MS) || (data & I8255A_G1_MS) ) { + CRIT((LOG,"I8255A: Unsupported mode set.")); + } + ctx->ctrl = data; + if (!(ctx->ctrl & I8255A_G1_PA) && ctx->set_pa) { + ctx->set_pa(ctx, ctx->data[0], 3); + } else if ((ctx->ctrl & I8255A_G1_PA) && ctx->set_pa) { + ctx->set_pa(ctx, ctx->get_pa(ctx, 3), 3); + } + if (!(ctx->ctrl & I8255A_G2_PB) && ctx->set_pb) { + ctx->set_pb(ctx, ctx->data[1], 3); + } else if ((ctx->ctrl & I8255A_G2_PB) && ctx->set_pb) { + ctx->set_pb(ctx, ctx->get_pb(ctx, 3), 3); + } + /* fall through */ + case 2: + if (reg == 2) { + ctx->data[2] = data; + } else { + data = ctx->data[2]; + } + /* if both upper and lower port c are inputs, we are done */ + if ((ctx->ctrl & I8255A_G2_PC) && (ctx->ctrl & I8255A_G1_PC)) { + if (reg == 3) { + ctx->set_pc(ctx, ctx->get_pc(ctx, 3), 3); + } + break; + } + /* one or more is an output; grab from port c if one is an input */ + if (ctx->ctrl & (I8255A_G2_PC | I8255A_G1_PC)) { + if (ctx->get_pc) { + data = ctx->get_pc(ctx, reg); + } + } + if (!(ctx->ctrl & I8255A_G2_PC)) { + data = (data & 0xf0) | (ctx->data[2] & 0x0f); + } + if (!(ctx->ctrl & I8255A_G1_PC)) { + data = (data & 0x0f) | (ctx->data[2] & 0xf0); + } + if (ctx->set_pc) { + ctx->set_pc(ctx, data, reg); + } + break; + } +} + +int i8255a_snapshot_write_data(i8255a_state *ctx, snapshot_module_t *m) +{ + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, ctx->ctrl) < 0 + || SMW_BA(m, ctx->data, 3) < 0) { + return -1; + } + + return 0; +} + +int i8255a_snapshot_read_data(i8255a_state *ctx, snapshot_module_t *m) +{ + if (m == NULL) { + return -1; + } + + if (0 + || SMR_B(m, &ctx->ctrl) < 0 + || SMR_BA(m, ctx->data, 3) < 0) { + return -1; + } + + return 0; +} + +int i8255a_dump(i8255a_state *ctx) +{ + mon_out("Port A: %02x\n", i8255a_peek(ctx, 0)); + mon_out("Port B: %02x\n", i8255a_peek(ctx, 1)); + mon_out("Port C: %02x\n", i8255a_peek(ctx, 2)); + mon_out("CONTRL: %02x\n", i8255a_peek(ctx, 3)); + + return 0; +} diff --git a/src/Emulators/vice/core/i8255a.h b/src/Emulators/vice/core/i8255a.h new file mode 100644 index 00000000..9f867e32 --- /dev/null +++ b/src/Emulators/vice/core/i8255a.h @@ -0,0 +1,73 @@ +/* + * i8255a.h - Intel 8255a + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_I8255A_H_ +#define VICE_I8255A_H_ + +#include "vicetypes.h" + +/* control register bit masks */ + +#define I8255A_G2_PC 0x01 +#define I8255A_G2_PB 0x02 +#define I8255A_G2_MS 0x04 +#define I8255A_G1_PC 0x08 +#define I8255A_G1_PA 0x10 +#define I8255A_G1_MS 0x60 +#define I8255A_MODE 0x80 + +#define I8255A_BS 0x01 + +typedef struct _i8255a_state { + uint8_t ctrl; + uint8_t data[3]; + + /* hooks that set the i/o lines */ + void (*set_pa)(struct _i8255a_state*, uint8_t, int8_t); + void (*set_pb)(struct _i8255a_state*, uint8_t, int8_t); + void (*set_pc)(struct _i8255a_state*, uint8_t, int8_t); + + /* hooks that read the status of i/o lines */ + uint8_t (*get_pa)(struct _i8255a_state*, int8_t); + uint8_t (*get_pb)(struct _i8255a_state*, int8_t); + uint8_t (*get_pc)(struct _i8255a_state*, int8_t); + + /* parent context that may be used by the hooks */ + void *p; +} i8255a_state; + +struct snapshot_module_s; + +void i8255a_reset(i8255a_state *ctx); +uint8_t i8255a_read(i8255a_state *ctx, int8_t reg); +uint8_t i8255a_peek(i8255a_state *ctx, int8_t reg); +void i8255a_store(i8255a_state *ctx, int8_t reg, uint8_t data); +int i8255a_dump(i8255a_state *ctx); + +int i8255a_snapshot_write_data(i8255a_state *ctx, struct snapshot_module_s *m); +int i8255a_snapshot_read_data(i8255a_state *ctx, struct snapshot_module_s *m); + +#endif diff --git a/src/Emulators/vice/core/m93c86.c b/src/Emulators/vice/core/m93c86.c index e13403bb..f17bef0b 100644 --- a/src/Emulators/vice/core/m93c86.c +++ b/src/Emulators/vice/core/m93c86.c @@ -26,7 +26,7 @@ /* this implements the M93C86 EEPROM in 16 bit mode as used by the GMod2 cartridge. - other types (M93C86-x M93C76-x M93C66-x M93C56-x M93C46-x) can probably be + other types (M93C86-x M93C76-x M93C66-x M93C56-x M93C46-x) can probably be supported with some reworking too (if we ever need it) */ /* #define M93C86DEBUG */ @@ -35,15 +35,18 @@ #include #include /* for memset */ +#include +#include #include "log.h" #include "m93c86.h" +#include "resources.h" #include "snapshot.h" #include "vicetypes.h" #include "util.h" #ifdef M93C86DEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif @@ -54,7 +57,13 @@ /* Image file */ static FILE *m93c86_image_file = NULL; -static BYTE m93c86_data[M93C86_SIZE]; +static uint8_t m93c86_data[M93C86_SIZE]; + +/** \brief Flag indicating if the file was opened read/write + * + * Used to determine if flushing the EEPROM data can be done. + */ +static bool eeprom_file_rw = false; static int eeprom_cs = 0; static int eeprom_clock = 0; @@ -90,6 +99,7 @@ static int ready_busy_status = 1; #define STATUSREADY 1 #define STATUSBUSY 0 + static void reset_input_shiftreg(void) { /* clear input shift register */ @@ -97,7 +107,7 @@ static void reset_input_shiftreg(void) input_count = 0; } -BYTE m93c86_read_data(void) +uint8_t m93c86_read_data(void) { if (eeprom_cs == 1) { switch (command) { @@ -123,14 +133,14 @@ BYTE m93c86_read_data(void) } } -void m93c86_write_data(BYTE value) +void m93c86_write_data(uint8_t value) { if (eeprom_cs == 1) { eeprom_data_in = value; } } -void m93c86_write_select(BYTE value) +void m93c86_write_select(uint8_t value) { /* Each instruction is preceded by a rising edge on Chip Select Input with Serial Clock being held low. */ if ((eeprom_cs == 0) && (value == 1) && (eeprom_clock == 0)) { @@ -154,7 +164,7 @@ void m93c86_write_select(BYTE value) } } -void m93c86_write_clock(BYTE value) +void m93c86_write_clock(uint8_t value) { /* rising edge of clock will read one bit from data input */ if ((eeprom_cs == 1) && (value == 1) && (eeprom_clock == 0)) { @@ -257,6 +267,20 @@ void m93c86_write_clock(BYTE value) command = 0; LOG(("CMD: write enable")); break; + case CMDERASE: + if (write_enable_status == 0) { + log_error(LOG_DEFAULT, "EEPROM: write not permitted for CMD 'erase'"); + reset_input_shiftreg(); + command = 0; + } else { + addr = ((input_shiftreg >> 0) & 0x3ff); + ready_busy_status = STATUSBUSY; + reset_input_shiftreg(); + m93c86_data[(addr << 1)] = 0xff; + m93c86_data[(addr << 1) + 1] = 0xff; + LOG(("CMD: erase addr %04x", addr)); + } + break; case CMDERAL: if (write_enable_status == 0) { log_error(LOG_DEFAULT, "EEPROM: write not permitted for CMD 'erase all'"); @@ -314,15 +338,22 @@ void m93c86_write_clock(BYTE value) eeprom_clock = value; } +void m93c86_set_image_rw(int rw) +{ + eeprom_file_rw = (bool)rw; +} + int m93c86_open_image(char *name, int rw) { char *m93c86_image_filename = name; + eeprom_file_rw = (bool)rw; + if (m93c86_image_filename != NULL) { /* FIXME */ } else { /* FIXME */ - log_debug("eeprom card image name not set"); + log_debug(LOG_DEFAULT, "eeprom card image name not set"); return 0; } @@ -338,25 +369,81 @@ int m93c86_open_image(char *name, int rw) m93c86_image_file = fopen(m93c86_image_filename, "rb"); if (m93c86_image_file == NULL) { - log_debug("could not open eeprom card image: %s", m93c86_image_filename); + log_debug(LOG_DEFAULT, "could not open eeprom card image: %s", m93c86_image_filename); return -1; } else { if (fread(m93c86_data, 1, M93C86_SIZE, m93c86_image_file) == 0) { - log_debug("could not read eeprom card image: %s", m93c86_image_filename); + log_debug(LOG_DEFAULT, "could not read eeprom card image: %s", m93c86_image_filename); } fseek(m93c86_image_file, 0, SEEK_SET); - log_debug("opened eeprom card image (ro): %s", m93c86_image_filename); + log_debug(LOG_DEFAULT, "opened eeprom card image (ro): %s", m93c86_image_filename); } } else { if (fread(m93c86_data, 1, M93C86_SIZE, m93c86_image_file) == 0) { - log_debug("could not read eeprom card image: %s", m93c86_image_filename); + log_debug(LOG_DEFAULT, "could not read eeprom card image: %s", m93c86_image_filename); } fseek(m93c86_image_file, 0, SEEK_SET); - log_debug("opened eeprom card image (rw): %s", m93c86_image_filename); + log_debug(LOG_DEFAULT, "opened eeprom card image (rw): %s", m93c86_image_filename); } return 0; } +/** \brief Save copy of image to file + * + * \param[in] name file to write copy to + * + * \return 0 on success, -1 on failure + */ +int m93c86_save_image(const char *name) +{ + FILE *fp; + + if (name == NULL || *name == '\0') { + log_debug(LOG_DEFAULT, "error: eeprom card image filename is NULL or empty"); + return -1; + } + + fp = fopen(name, "wb"); + if (fp == NULL) { + log_debug(LOG_DEFAULT, "could not open file '%s' for writing: errno %d (%s)", + name, errno, strerror(errno)); + return -1; + } + + if (fwrite(m93c86_data, 1u, M93C86_SIZE, fp) != M93C86_SIZE) { + log_debug(LOG_DEFAULT, "error while writing eeprom card image: errno %d (%s)", + errno, strerror(errno)); + fclose(fp); + return -1; + } + fclose(fp); + return 0; +} + +/** \brief Flush eeprom card image file + * + * \return 0 on success, -1 on failure + */ +int m93c86_flush_image(void) +{ + if (m93c86_image_file == NULL) { + log_debug(LOG_DEFAULT, "cannot flush eeprom card image: file not opened"); + return -1; + } + if (!eeprom_file_rw) { + log_debug(LOG_DEFAULT, "cannot flush read-only eeprom card image"); + return -1; + } + fseek(m93c86_image_file, 0, SEEK_SET); + if (fwrite(m93c86_data, 1, M93C86_SIZE, m93c86_image_file) == 0) { + log_debug(LOG_DEFAULT, "failed to flush eeprom card image: %d (%s)", + errno, strerror(errno)); + return -1; + } + fflush(m93c86_image_file); + return 0; +} + void m93c86_close_image(int rw) { /* unmount EEPROM image */ @@ -364,7 +451,7 @@ void m93c86_close_image(int rw) if (rw) { fseek(m93c86_image_file, 0, SEEK_SET); if (fwrite(m93c86_data, 1, M93C86_SIZE, m93c86_image_file) == 0) { - log_debug("could not write eeprom card image"); + log_debug(LOG_DEFAULT, "could not write eeprom card image"); } } fclose(m93c86_image_file); @@ -376,14 +463,11 @@ void m93c86_close_image(int rw) /* snapshot support functions */ #define CART_DUMP_VER_MAJOR 0 -#define CART_DUMP_VER_MINOR 0 +#define CART_DUMP_VER_MINOR 1 #define SNAP_MODULE_NAME "M93C86" -/* FIXME: implement snapshot support */ int m93c86_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -392,39 +476,75 @@ int m93c86_snapshot_write_module(snapshot_t *s) return -1; } - if (0) { + if (0 + || SMW_B(m, eeprom_cs) < 0 + || SMW_B(m, eeprom_clock) < 0 + || SMW_B(m, eeprom_data_in) < 0 + || SMW_B(m, eeprom_data_out) < 0 + || SMW_B(m, input_shiftreg) < 0 + || SMW_B(m, input_count) < 0 + || SMW_B(m, output_shiftreg) < 0 + || SMW_B(m, output_count) < 0 + || SMW_B(m, command) < 0 + || SMW_B(m, addr) < 0 + || SMW_B(m, data0) < 0 + || SMW_B(m, data1) < 0 + || SMW_B(m, write_enable_status) < 0 + || SMW_B(m, ready_busy_status) < 0 + || SMW_BA(m, m93c86_data, M93C86_SIZE) < 0) { snapshot_module_close(m); return -1; } snapshot_module_close(m); return 0; -#endif } int m93c86_snapshot_read_module(snapshot_t *s) { - return -1; -#if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; + int rw; + + /* FIXME: currently m93c86 is used exclusively in gmod2, so this is not a + * problem - however, the whole global context should go into a + * struct at some point, and this rw flag too :) */ + resources_get_int("GMod2EEPROMRW", &rw); m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); if (m == NULL) { return -1; } - if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR)) { snapshot_module_close(m); return -1; } - if (0) { + m93c86_close_image(rw); + + if (0 + || SMR_B_INT(m, &eeprom_cs) < 0 + || SMR_B_INT(m, &eeprom_clock) < 0 + || SMR_B_INT(m, &eeprom_data_in) < 0 + || SMR_B_INT(m, &eeprom_data_out) < 0 + || SMR_B_INT(m, (int*)&input_shiftreg) < 0 + || SMR_B_INT(m, (int*)&input_count) < 0 + || SMR_B_INT(m, (int*)&output_shiftreg) < 0 + || SMR_B_INT(m, (int*)&output_count) < 0 + || SMR_B_INT(m, &command) < 0 + || SMR_B_INT(m, &addr) < 0 + || SMR_B_INT(m, &data0) < 0 + || SMR_B_INT(m, &data1) < 0 + || SMR_B_INT(m, &write_enable_status) < 0 + || SMR_B_INT(m, &ready_busy_status) < 0 + || SMR_BA(m, m93c86_data, M93C86_SIZE) < 0) { snapshot_module_close(m); return -1; } snapshot_module_close(m); + return 0; -#endif } diff --git a/src/Emulators/vice/core/m93c86.h b/src/Emulators/vice/core/m93c86.h index 439f04e6..b9f3d625 100644 --- a/src/Emulators/vice/core/m93c86.h +++ b/src/Emulators/vice/core/m93c86.h @@ -29,16 +29,20 @@ #include "vicetypes.h" -extern BYTE m93c86_read_data(void); -extern void m93c86_write_data(BYTE value); -extern void m93c86_write_select(BYTE value); -extern void m93c86_write_clock(BYTE value); +uint8_t m93c86_read_data(void); +void m93c86_write_data(uint8_t value); +void m93c86_write_select(uint8_t value); +void m93c86_write_clock(uint8_t value); -extern int m93c86_open_image(char *name, int rw); -extern void m93c86_close_image(int rw); +int m93c86_open_image(char *name, int rw); +int m93c86_save_image(const char *name); +int m93c86_flush_image(void); +void m93c86_close_image(int rw); +void m93c86_set_image_rw(int rw); struct snapshot_s; -extern int m93c86_snapshot_read_module(struct snapshot_s *s); -extern int m93c86_snapshot_write_module(struct snapshot_s *s); + +int m93c86_snapshot_read_module(struct snapshot_s *s); +int m93c86_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/core/mc6821core.c b/src/Emulators/vice/core/mc6821core.c index adbf9ab0..7989e430 100644 --- a/src/Emulators/vice/core/mc6821core.c +++ b/src/Emulators/vice/core/mc6821core.c @@ -31,8 +31,8 @@ /* #define MC6821_DEBUG */ #ifdef MC6821_DEBUG -#include -#define DBG(x) printf x +#include +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -41,6 +41,7 @@ #include "mc6821core.h" #include "snapshot.h" +#include "monitor.h" void mc6821core_reset(mc6821_state *ctx) { @@ -72,9 +73,9 @@ void mc6821core_reset(mc6821_state *ctx) } } -BYTE mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) +uint8_t mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) { - BYTE data = 0; + uint8_t data = 0; if (port == 0) { /* MC6821 Port A */ @@ -86,7 +87,6 @@ BYTE mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) /* data port */ data = ctx->dataA & ctx->ddrA; - /* FIXME: CA2 output mode 0x08 */ if (ctx->CA2state == 1) { ctx->CA2 = 0; if (ctx->set_ca2) { @@ -101,13 +101,11 @@ BYTE mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) data |= 0xff & ~(ctx->ddrA); } - /* FIXME: CA2 output mode 0x08 */ if (ctx->CA2state == 1) { ctx->CA2 = 1; if (ctx->set_ca2) { ctx->set_ca2(ctx); } - ctx->CA2state = 0; } /* irq flags are cleared when reading output port */ @@ -141,9 +139,9 @@ BYTE mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) return data; } -BYTE mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) +uint8_t mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) { - BYTE data = 0; + uint8_t data = 0; if (port == 0) { /* MC6821 Port A */ @@ -153,11 +151,9 @@ BYTE mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) } else { if (ctx->ctrlA & MC6821_CTRL_REG) { data = ctx->dataA; -#if 0 if (ctx->get_pa) { data = ctx->get_pa(ctx); } -#endif } else { data = ctx->ddrA; } @@ -170,11 +166,9 @@ BYTE mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) } else { if (ctx->ctrlB & MC6821_CTRL_REG) { data = ctx->dataB; -#if 0 if (ctx->get_pb) { data = ctx->get_pb(ctx); } -#endif } else { data = ctx->ddrB; } @@ -183,49 +177,51 @@ BYTE mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */) return data; } -void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, BYTE data) +void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, uint8_t data) { if (port == 0) { /* MC6821 Port A */ if (reg == 1) { /* control register */ - /* DBG(("MC6821: PA CTRL %02x\n", data)); */ + /* DBG(("MC6821: PA CTRL %02x", data)); */ ctx->ctrlA = data; if (data & MC6821_CTRL_C2DDR) { /* CA2 is output */ switch (data & MC6821_CTRL_C2MODE) { case MC6821_CTRL_C2_RESET_C2: - ctx->CA2 = 0; - /* update CA2 immediately */ - if (ctx->set_ca2) { + /* update CA2 immediately only if it changed */ + if (ctx->set_ca2 && ctx->CA2) { + ctx->CA2 = 0; ctx->set_ca2(ctx); } + ctx->CA2state = 0; break; case MC6821_CTRL_C2_SET_C2: - ctx->CA2 = 1; - /* update CA2 immediately */ - if (ctx->set_ca2) { + /* update CA2 immediately only if it changed */ + if (ctx->set_ca2 && !ctx->CA2) { + ctx->CA2 = 1; ctx->set_ca2(ctx); } + ctx->CA2state = 0; break; case MC6821_CTRL_C2_STROBE_C: - DBG(("MC6821: PA CTRL unimplemented output mode %02x for CA2\n", data & MC6821_CTRL_C2MODE)); + DBG(("MC6821: PA CTRL unimplemented output mode %02x for CA2", data & MC6821_CTRL_C2MODE)); + ctx->CA2state = 0; break; case MC6821_CTRL_C2_STROBE_E: - DBG(("MC6821: PA CTRL FIXME output mode %02x for CA2\n", data & MC6821_CTRL_C2MODE)); ctx->CA2state = 1; break; } } else { /* CA2 is input */ if (data & MC6821_CTRL_C2_IRQEN) { - DBG(("MC6821: PA CTRL unimplemented irq mode %02x for CA2\n", data & MC6821_CTRL_C2MODE)); + DBG(("MC6821: PA CTRL unimplemented irq mode %02x for CA2", data & MC6821_CTRL_C2MODE)); } } } else { if (ctx->ctrlA & MC6821_CTRL_REG) { /* output register */ - /* DBG(("MC6821: PA DATA %02x\n",data)); */ + /* DBG(("MC6821: PA DATA %02x",data)); */ ctx->dataA = data; if (ctx->set_pa) { @@ -233,7 +229,7 @@ void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, } } else { /* data direction register */ - /* DBG(("MC6821: PA DDR %02x\n",data)); */ + /* DBG(("MC6821: PA DDR %02x",data)); */ ctx->ddrA = data; /* update port if ddr changes */ if (ctx->set_pa) { @@ -245,7 +241,7 @@ void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, /* MC6821 Port B */ if (reg == 1) { /* control register */ - DBG(("MC6821: PB CTRL %02x\n", data)); + DBG(("MC6821: PB CTRL %02x", data)); ctx->ctrlB = data; if (data & MC6821_CTRL_C2DDR) { /* CB2 is output */ @@ -265,17 +261,17 @@ void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, } break; case MC6821_CTRL_C2_STROBE_C: - DBG(("MC6821: PB CTRL unimplemented output mode %02x for CB2\n", data & MC6821_CTRL_C2MODE)); + DBG(("MC6821: PB CTRL unimplemented output mode %02x for CB2", data & MC6821_CTRL_C2MODE)); break; case MC6821_CTRL_C2_STROBE_E: - DBG(("MC6821: PB CTRL FIXME output mode %02x for CB2\n", data & MC6821_CTRL_C2MODE)); + DBG(("MC6821: PB CTRL FIXME output mode %02x for CB2", data & MC6821_CTRL_C2MODE)); ctx->CB2state = 1; break; } } else { /* CB2 is input */ if (data & MC6821_CTRL_C2_IRQEN) { - DBG(("MC6821: PB CTRL unimplemented irq mode %02x for CB2\n", data & MC6821_CTRL_C2MODE)); + DBG(("MC6821: PB CTRL unimplemented irq mode %02x for CB2", data & MC6821_CTRL_C2MODE)); } } } else { @@ -306,7 +302,7 @@ void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, } } else { /* data direction register */ - DBG(("MC6821: PB DDR %02x\n", data)); + DBG(("MC6821: PB DDR %02x", data)); ctx->ddrB = data; /* update port if ddr changes */ if (ctx->set_pb) { @@ -343,16 +339,16 @@ int mc6821core_snapshot_write_data(mc6821_state *ctx, snapshot_module_t *m) } if (0 - || SMW_B(m, (BYTE)ctx->ctrlA) < 0 - || SMW_B(m, (BYTE)ctx->ctrlB) < 0 - || SMW_B(m, (BYTE)ctx->dataA) < 0 - || SMW_B(m, (BYTE)ctx->dataB) < 0 - || SMW_B(m, (BYTE)ctx->ddrA) < 0 - || SMW_B(m, (BYTE)ctx->ddrB) < 0 - || SMW_B(m, (BYTE)ctx->CA2) < 0 - || SMW_B(m, (BYTE)ctx->CA2state) < 0 - || SMW_B(m, (BYTE)ctx->CB2) < 0 - || SMW_B(m, (BYTE)ctx->CB2state) < 0) { + || SMW_B(m, (uint8_t)ctx->ctrlA) < 0 + || SMW_B(m, (uint8_t)ctx->ctrlB) < 0 + || SMW_B(m, (uint8_t)ctx->dataA) < 0 + || SMW_B(m, (uint8_t)ctx->dataB) < 0 + || SMW_B(m, (uint8_t)ctx->ddrA) < 0 + || SMW_B(m, (uint8_t)ctx->ddrB) < 0 + || SMW_B(m, (uint8_t)ctx->CA2) < 0 + || SMW_B(m, (uint8_t)ctx->CA2state) < 0 + || SMW_B(m, (uint8_t)ctx->CB2) < 0 + || SMW_B(m, (uint8_t)ctx->CB2state) < 0) { return -1; } @@ -381,3 +377,13 @@ int mc6821core_snapshot_read_data(mc6821_state *ctx, snapshot_module_t *m) return 0; } + +int mc6821core_dump(mc6821_state *ctx) +{ + mon_out("Port A: %02x DDR: %02x REG: %02x CTRL: %02x\n", + mc6821core_peek(ctx, 0, 0), ctx->ddrA, ctx->dataA, ctx->ctrlA); + mon_out("Port B: %02x DDR: %02x REG: %02x CTRL: %02x\n", + mc6821core_peek(ctx, 1, 0), ctx->ddrB, ctx->dataB, ctx->ctrlB); + + return 0; +} diff --git a/src/Emulators/vice/core/mc6821core.h b/src/Emulators/vice/core/mc6821core.h index 78cfb9cc..747b652b 100644 --- a/src/Emulators/vice/core/mc6821core.h +++ b/src/Emulators/vice/core/mc6821core.h @@ -62,13 +62,13 @@ #define MC6821_CTRL_C1_IRQLOHI 0x02 typedef struct _mc6821_state { - BYTE ctrlA; - BYTE dataA; - BYTE ddrA; + uint8_t ctrlA; + uint8_t dataA; + uint8_t ddrA; - BYTE ctrlB; - BYTE dataB; - BYTE ddrB; + uint8_t ctrlB; + uint8_t dataB; + uint8_t ddrB; int CA2; int CA2state; @@ -87,16 +87,16 @@ typedef struct _mc6821_state { void (*set_cb2)(struct _mc6821_state*); /* hooks that read the status of i/o lines */ - BYTE (*get_pa)(struct _mc6821_state*); - BYTE (*get_pb)(struct _mc6821_state*); + uint8_t (*get_pa)(struct _mc6821_state*); + uint8_t (*get_pb)(struct _mc6821_state*); void *p; /* parent context that may be used by the hooks */ } mc6821_state; void mc6821core_reset(mc6821_state *ctx); -BYTE mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */); -BYTE mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */); -void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, BYTE data); +uint8_t mc6821core_read(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */); +uint8_t mc6821core_peek(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */); +void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, uint8_t data); /* Signal values (for signaling edges on the control lines) */ #define MC6821_SIGNAL_CA1 0 @@ -104,6 +104,7 @@ void mc6821core_store(mc6821_state *ctx, int port /* rs1 */, int reg /* rs0 */, #define MC6821_SIGNAL_CB1 2 #define MC6821_SIGNAL_CB2 3 void mc6821core_set_signal(mc6821_state *ctx, int line); +int mc6821core_dump(mc6821_state *ctx); struct snapshot_module_s; diff --git a/src/Emulators/vice/core/riotcore.c b/src/Emulators/vice/core/riotcore.c index e0c29528..f1fb158a 100644 --- a/src/Emulators/vice/core/riotcore.c +++ b/src/Emulators/vice/core/riotcore.c @@ -1,5 +1,5 @@ /* - * riotcore.c - Core functions for RIOT emulation. + * riotcore.c - Core functions for 6532 RAM Input/Output Timer (RIOT) emulation. * * Written by * Andre Fachat @@ -30,9 +30,9 @@ #include #include "alarm.h" -#include "clkguard.h" #include "lib.h" #include "log.h" +#include "monitor.h" #include "riot.h" #include "snapshot.h" #include "vicetypes.h" @@ -42,7 +42,7 @@ static const int divider[] = { 1, 8, 64, 1024 }; -static void update_irq(riot_context_t *riot_context, BYTE new_irqfl) +static void update_irq(riot_context_t *riot_context, uint8_t new_irqfl) { int new_irqline; @@ -62,7 +62,7 @@ static void update_irq(riot_context_t *riot_context, BYTE new_irqfl) void riotcore_signal(riot_context_t *riot_context, int sig, int type) { - BYTE newirq = riot_context->r_irqfl & 0xbf; + uint8_t newirq = riot_context->r_irqfl & 0xbf; /* You better not call that twice with the same flag - the IRQ * will be set twice... */ @@ -79,7 +79,7 @@ void riotcore_signal(riot_context_t *riot_context, int sig, int type) static void update_timer(riot_context_t *riot_context) { - int underfl = (*(riot_context->clk_ptr) - riot_context->r_write_clk) + CLOCK underfl = (*(riot_context->clk_ptr) - riot_context->r_write_clk) / riot_context->r_divider; if (underfl > riot_context->r_N) { @@ -92,27 +92,6 @@ static void update_timer(riot_context_t *riot_context) - riot_context->r_write_clk) & 0xff00; } -static void riotcore_clk_overflow_callback(CLOCK sub, void *data) -{ - riot_context_t *riot_context; - - riot_context = (riot_context_t *)data; - - if (riot_context->enabled == 0) { - return; - } - - update_timer(riot_context); - - riot_context->r_write_clk -= sub; - - if (riot_context->read_clk > sub) { - riot_context->read_clk -= sub; - } else { - riot_context->read_clk = 0; - } -} - void riotcore_disable(riot_context_t *riot_context) { alarm_unset(riot_context->alarm); @@ -148,7 +127,7 @@ void riotcore_reset(riot_context_t *riot_context) riot_context->enabled = 1; } -void riotcore_store(riot_context_t *riot_context, WORD addr, BYTE byte) +void riotcore_store(riot_context_t *riot_context, uint16_t addr, uint8_t byte) { CLOCK rclk; @@ -211,7 +190,7 @@ void riotcore_store(riot_context_t *riot_context, WORD addr, BYTE byte) } } - update_irq(riot_context, (BYTE)(newirq)); + update_irq(riot_context, (uint8_t)(newirq)); if (!(riot_context->r_irqen)) { alarm_unset(riot_context->alarm); @@ -227,11 +206,11 @@ void riotcore_store(riot_context_t *riot_context, WORD addr, BYTE byte) } } -BYTE riotcore_read(riot_context_t *riot_context, WORD addr) +uint8_t riotcore_read(riot_context_t *riot_context, uint16_t addr) { #ifdef MYRIOT_TIMER_DEBUG - BYTE myriot_read_(riot_context_t *, WORD); - BYTE retv = myriot_read_(riot_context, addr); + uint8_t myriot_read_(riot_context_t *, uint16_t); + uint8_t retv = myriot_read_(riot_context, addr); addr &= 0x1f; if ((addr > 3 && addr < 10) || app_resources.debugFlag) { log_message(riot_context->log, @@ -241,7 +220,8 @@ BYTE riotcore_read(riot_context_t *riot_context, WORD addr) } return retv; } -BYTE myriot_read_(riot_context_t *riot_context, WORD addr) + +uint8_t myriot_read_(riot_context_t *riot_context, uint16_t addr) { #endif CLOCK rclk; @@ -284,7 +264,7 @@ BYTE myriot_read_(riot_context_t *riot_context, WORD addr) log_warning(riot_context->log, "read timer @%d not yet implemented\n", addr); */ - update_irq(riot_context, (BYTE)(riot_context->r_irqfl & 0x7f)); + update_irq(riot_context, (uint8_t)(riot_context->r_irqfl & 0x7f)); update_timer(riot_context); @@ -297,7 +277,7 @@ BYTE myriot_read_(riot_context_t *riot_context, WORD addr) alarm_unset(riot_context->alarm); } - riot_context->last_read = (BYTE)(riot_context->r_N + riot_context->last_read = (uint8_t)(riot_context->r_N - (rclk - riot_context->r_write_clk) / riot_context->r_divider); return riot_context->last_read; @@ -314,17 +294,17 @@ BYTE myriot_read_(riot_context_t *riot_context, WORD addr) + riot_context->r_N * riot_context->r_divider); } - update_irq(riot_context, (BYTE)(riot_context->r_irqfl & 0xbf)); + update_irq(riot_context, (uint8_t)(riot_context->r_irqfl & 0xbf)); } return 0xff; } /* read from I/O without side effects */ /* FIXME: check if this is working correctly */ -BYTE riotcore_peek(riot_context_t *riot_context, WORD addr) +uint8_t riotcore_peek(riot_context_t *riot_context, uint16_t addr) { CLOCK rclk = *(riot_context->clk_ptr); /* FIXME */ - BYTE ret = 0xff; + uint8_t ret = 0xff; addr &= 0x1f; @@ -332,20 +312,20 @@ BYTE riotcore_peek(riot_context_t *riot_context, WORD addr) if ((addr & 0x04) == 0) { /* I/O */ switch (addr & 3) { case 0: /* ORA */ - ret = riot_context->read_pra(riot_context); /* FIXME */ + ret = riot_context->riot_io[0]; /* FIXME */ break; case 1: /* DDRA */ ret = riot_context->riot_io[1]; break; case 2: /* ORB */ - ret = riot_context->read_prb(riot_context); /* FIXME */ + ret = riot_context->riot_io[2]; /* FIXME */ break; case 3: /* DDRB */ ret = riot_context->riot_io[3]; break; } } else if ((addr & 0x05) == 0x04) { /* read timer */ - ret = (BYTE)(riot_context->r_N - (rclk - riot_context->r_write_clk) / riot_context->r_divider); + ret = (uint8_t)(riot_context->r_N - (rclk - riot_context->r_write_clk) / riot_context->r_divider); } else if ((addr & 0x05) == 0x05) { /* read irq flag */ ret = riot_context->r_irqfl; } @@ -354,7 +334,12 @@ BYTE riotcore_peek(riot_context_t *riot_context, WORD addr) void riotcore_dump(riot_context_t *riot_context) { - /* TODO: implement dump feature */ + CLOCK rclk = *(riot_context->clk_ptr); /* FIXME */ + unsigned int timer = (uint8_t)(riot_context->r_N - (rclk - riot_context->r_write_clk) / riot_context->r_divider); + mon_out("ORA: $%02x DDRA: $%02x\n", riot_context->riot_io[0], riot_context->riot_io[1]); + mon_out("ORB: $%02x DDRB: $%02x\n", riot_context->riot_io[2], riot_context->riot_io[3]); + mon_out("Timer: $%04x\n", timer); + mon_out("IRQ Flags: $%02x\n", riot_context->r_irqfl); } static void riotcore_int_riot(CLOCK offset, void *data) @@ -365,12 +350,12 @@ static void riotcore_int_riot(CLOCK offset, void *data) alarm_unset(riot_context->alarm); - update_irq(riot_context, (BYTE)(riot_context->r_irqfl | 0x80)); + update_irq(riot_context, (uint8_t)(riot_context->r_irqfl | 0x80)); } void riotcore_setup_context(riot_context_t *riot_context) { - riot_context->log = LOG_ERR; + riot_context->log = LOG_DEFAULT; riot_context->read_clk = 0; riot_context->read_offset = 0; riot_context->last_read = 0; @@ -380,7 +365,7 @@ void riotcore_setup_context(riot_context_t *riot_context) } void riotcore_init(riot_context_t *riot_context, - alarm_context_t *alarm_context, clk_guard_t *clk_guard, + alarm_context_t *alarm_context, unsigned int number) { char *buffer; @@ -391,9 +376,6 @@ void riotcore_init(riot_context_t *riot_context, riot_context->alarm = alarm_new(alarm_context, buffer, riotcore_int_riot, riot_context); lib_free(buffer); - - clk_guard_add_callback(clk_guard, riotcore_clk_overflow_callback, - riot_context); } void riotcore_shutdown(riot_context_t *riot_context) @@ -452,11 +434,11 @@ int riotcore_snapshot_write_module(riot_context_t *riot_context, snapshot_t *p) || SMW_B(m, riot_context->riot_io[2]) < 0 || SMW_B(m, riot_context->riot_io[3]) < 0 || SMW_B(m, riot_context->r_edgectrl) < 0 - || SMW_B(m, (BYTE)(riot_context->r_irqfl | (riot_context->r_irqline ? 1 : 0))) < 0 - || SMW_B(m, (BYTE)(riot_context->r_N - (*(riot_context->clk_ptr) - riot_context->r_write_clk) / riot_context->r_divider)) < 0 - || SMW_W(m, (WORD)(riot_context->r_divider)) < 0 - || SMW_W(m, (BYTE)((*(riot_context->clk_ptr) - riot_context->r_write_clk) % riot_context->r_divider)) < 0 - || SMW_B(m, (BYTE)(riot_context->r_irqen ? 1 : 0)) < 0) { + || SMW_B(m, (uint8_t)(riot_context->r_irqfl | (riot_context->r_irqline ? 1 : 0))) < 0 + || SMW_B(m, (uint8_t)(riot_context->r_N - (*(riot_context->clk_ptr) - riot_context->r_write_clk) / riot_context->r_divider)) < 0 + || SMW_W(m, (uint16_t)(riot_context->r_divider)) < 0 + || SMW_W(m, (uint8_t)((*(riot_context->clk_ptr) - riot_context->r_write_clk) % riot_context->r_divider)) < 0 + || SMW_B(m, (uint8_t)(riot_context->r_irqen ? 1 : 0)) < 0) { snapshot_module_close(m); return -1; } @@ -466,11 +448,11 @@ int riotcore_snapshot_write_module(riot_context_t *riot_context, snapshot_t *p) int riotcore_snapshot_read_module(riot_context_t *riot_context, snapshot_t *p) { - BYTE vmajor, vminor; - BYTE byte_r_N; - BYTE byte; - WORD word_r_divider; - WORD word_r_write_clk; + uint8_t vmajor, vminor; + uint8_t byte_r_N; + uint8_t byte; + uint16_t word_r_divider; + uint16_t word_r_write_clk; snapshot_module_t *m; m = snapshot_module_open(p, riot_context->myname, &vmajor, &vminor); @@ -482,7 +464,7 @@ int riotcore_snapshot_read_module(riot_context_t *riot_context, snapshot_t *p) } /* Do not accept versions higher than current */ - if (vmajor > RIOT_DUMP_VER_MAJOR || vminor > RIOT_DUMP_VER_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, RIOT_DUMP_VER_MAJOR, RIOT_DUMP_VER_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; diff --git a/src/Emulators/vice/core/rtc-72421.c b/src/Emulators/vice/core/rtc-72421.c new file mode 100644 index 00000000..8da70b25 --- /dev/null +++ b/src/Emulators/vice/core/rtc-72421.c @@ -0,0 +1,571 @@ +/* + * rtc-72421.c - RTC-72421 RTC emulation. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include "rtc-72421.h" +#include "lib.h" +#include "rtc.h" +#include "snapshot.h" + +#include + +/* The RTC-72421 is a 4bit address/data line RTC module, + * The RTC has the following features: + * - Real-Time Clock Counts seconds, minutes, hours, date of the month, + * months, and years + * - All registers are decimal + */ + +/* The RTC-72421 has the following clock registers: + * + * register 0 : bits 3-0 seconds + * + * register 1 : bit 3 0 + * bits 2-0 10 seconds + * + * register 2 : bits 3-0 minutes + * + * register 3 : bit 3 0 + * bits 2-0 10 minutes + * + * register 4 : bits 3-0 hours + * + * register 5 : bit 3 24/12 hour selection (0 = 12 hour, 1 = 24 hour) + * bit 2 AM/PM indication bit (1 when in 12 hour mode, otherwise 0) + * bits 1-0 10 hours + * + * register 6 : bits 3-0 day of the month + * + * register 7 : bits 3-2 leapyear indicator + * bits 1-0 10 day of the month + * + * register 8 : bits 3-0 months + * + * register 9 : bits 3-1 0 + * bit 0 10 months + * + * register A : bits 3-0 years + * + * register B : bits 3-0 10 years + * + * register C : bit 3 0 + * bits 2-0 weekdays + * + * register D : bits 3-0 0 + * + * register E : bits 3-0 0 + * + * register F : bit 3 0 + * bit 2 AM/PM selector + * bit 1 Clock Halt + * bit 0 0 + */ + +/* This module is currently used in the following emulated hardware: + * CMDHD + * RAMLINK + */ + +/* ---------------------------------------------------------------------------------------------------- */ + +rtc_72421_t *rtc72421_init(char *device) +{ + rtc_72421_t *retval = lib_calloc(1, sizeof(rtc_72421_t)); + int loaded = rtc_load_context(device, 0, 0); + + if (loaded) { + retval->offset = rtc_get_loaded_offset(); + retval->day_offset = rtc_get_loaded_day_offset(); + } else { + retval->offset = 0; + retval->day_offset = 0; + } + retval->old_offset = retval->offset; + retval->day = ( 7 + rtc_get_weekday(rtc_get_latch(retval->offset)) + retval->day_offset ) % 7; + + retval->hour24 = 0; + retval->device = lib_strdup(device); + + return retval; +} + +void rtc72421_destroy(rtc_72421_t *context, int save) +{ + if (save) { + if (context->old_offset != context->offset) { + rtc_save_context(NULL, 0, NULL, 0, context->device, context->offset); /* RD: 3.10 added day_offset; RD's rtc.c is still 3.1 (6-arg) */ + } + } + lib_free(context->device); + lib_free(context); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +uint8_t rtc72421_read(rtc_72421_t *context, uint8_t address) +{ + uint8_t retval = 0; + time_t latch = (context->stop) ? context->latch : rtc_get_latch(context->offset); + + switch (address & 0xf) { + case RTC72421_REGISTER_SECONDS: + retval = rtc_get_second(latch, 0); + retval %= 10; + break; + case RTC72421_REGISTER_10SECONDS: + retval = rtc_get_second(latch, 0); + retval /= 10; + break; + case RTC72421_REGISTER_MINUTES: + retval = rtc_get_minute(latch, 0); + retval %= 10; + break; + case RTC72421_REGISTER_10MINUTES: + retval = rtc_get_minute(latch, 0); + retval /= 10; + break; + case RTC72421_REGISTER_HOURS: + if (context->hour24) { + retval = rtc_get_hour(latch, 0); + } else { + retval = rtc_get_hour_am_pm(latch, 0); + retval &= 0x0f; + } + retval %= 10; + break; + case RTC72421_REGISTER_10HOURS: + if (context->hour24) { + retval = rtc_get_hour(latch, 0); + retval /= 10; + } else { + retval = rtc_get_hour_am_pm(latch, 0); + if (retval >= 32) { + retval = (retval & 31) / 10; + retval |= 4; + } else { + retval /= 10; + } + } + break; + case RTC72421_REGISTER_WEEKDAYS: + retval = rtc_get_weekday(latch); + /* apply day offset */ + if (context->stop) { + retval = ( 7 + retval + context->day_latch ) % 7; + } else { + retval = ( 7 + retval + context->day_offset ) % 7; + } + break; + case RTC72421_REGISTER_MONTHDAYS: + retval = rtc_get_day_of_month(latch, 0); + retval %= 10; + break; + case RTC72421_REGISTER_10MONTHDAYS: + retval = rtc_get_day_of_month(latch, 0); + retval /= 10; + break; + case RTC72421_REGISTER_MONTHS: + retval = rtc_get_month(latch, 0); + retval %= 10; + break; + case RTC72421_REGISTER_10MONTHS: + retval = rtc_get_month(latch, 0); + retval /= 10; + break; + case RTC72421_REGISTER_YEARS: + retval = rtc_get_year(latch, 0); + retval %= 10; + break; + case RTC72421_REGISTER_10YEARS: + retval = rtc_get_year(latch, 0); + retval /= 10; + break; + case RTC72421_REGISTER_CTRL1: + /* RAMLINK writes/reads data to this register to detect the + presence of the rtc */ + retval = context->control[1]; + break; + case RTC72421_REGISTER_CTRL2: + retval = context->hour24 ? 2 : 0; + retval |= context->stop ? 1 : 0; + break; + } + return retval; +} + + +#define LIMIT_9(x) (x > 9) ? 9 : x + +void rtc72421_write(rtc_72421_t *context, uint8_t address, uint8_t data) +{ + time_t latch = (context->stop) ? context->latch : rtc_get_latch(context->offset); + uint8_t real_data = data & 0xf; + uint8_t new_data; + int8_t day; + + switch (address & 0xf) { + case RTC72421_REGISTER_SECONDS: + new_data = rtc_get_second(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_second(new_data, latch, 0); + } else { + context->offset = rtc_set_second(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_10SECONDS: + new_data = rtc_get_second(latch, 0); + new_data %= 10; + new_data += ((real_data & 7) * 10); + if (context->stop) { + context->latch = rtc_set_latched_second(new_data, latch, 0); + } else { + context->offset = rtc_set_second(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_MINUTES: + new_data = rtc_get_minute(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_minute(new_data, latch, 0); + } else { + context->offset = rtc_set_minute(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_10MINUTES: + new_data = rtc_get_minute(latch, 0); + new_data %= 10; + new_data += ((real_data & 7) * 10); + if (context->stop) { + context->latch = rtc_set_latched_minute(new_data, latch, 0); + } else { + context->offset = rtc_set_minute(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_HOURS: + if (context->hour24) { + new_data = rtc_get_hour(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_hour(new_data, latch, 0); + } else { + context->offset = rtc_set_hour(new_data, context->offset, 0); + } + } else { + new_data = rtc_get_hour_am_pm(latch, 0); + if (new_data >= 32) { + new_data -= 32; + new_data /= 10; + new_data *= 10; + new_data += (LIMIT_9(real_data) + 32); + } else { + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + } + if (context->stop) { + context->latch = rtc_set_latched_hour_am_pm(new_data, latch, 0); + } else { + context->offset = rtc_set_hour_am_pm(new_data, context->offset, 0); + } + } + break; + case RTC72421_REGISTER_10HOURS: + /* FIXME: I don't think this is correct */ + if (real_data & 8) { + new_data = rtc_get_hour(latch, 0); + new_data %= 10; + new_data += ((real_data & 3) * 10); + context->hour24 = 1; + if (context->stop) { + context->latch = rtc_set_latched_hour(new_data, latch, 0); + } else { + context->offset = rtc_set_hour(new_data, context->offset, 0); + } + } else { + real_data &= 7; + new_data = rtc_get_hour_am_pm(latch, 0); + if (new_data >= 32) { + new_data -= 32; + } + new_data %= 10; + new_data += ((real_data & 3) * 10); + if (real_data & 4) { + new_data += 32; + } + context->hour24 = 0; + if (context->stop) { + context->latch = rtc_set_latched_hour_am_pm(new_data, latch, 0); + } else { + context->offset = rtc_set_hour_am_pm(new_data, context->offset, 0); + } + } + break; + case RTC72421_REGISTER_WEEKDAYS: + /* We can't figure out the offset until the full date is set, and + we don't know how the date will be filled, so we keep a short + term register "day" to remember and adjust the day_offset on + every other register write. Eventually, it will be set correctly. */ + if (real_data > 6) { + real_data = 6; + } + context->day = real_data; + break; + case RTC72421_REGISTER_MONTHDAYS: + new_data = rtc_get_day_of_month(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_day_of_month(new_data, latch, 0); + } else { + context->offset = rtc_set_day_of_month(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_10MONTHDAYS: + new_data = rtc_get_day_of_month(latch, 0); + new_data %= 10; + new_data += ((real_data & 3) * 10); + if (context->stop) { + context->latch = rtc_set_latched_day_of_month(new_data, latch, 0); + } else { + context->offset = rtc_set_day_of_month(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_MONTHS: + new_data = rtc_get_month(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_month(new_data, latch, 0); + } else { + context->offset = rtc_set_month(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_10MONTHS: + new_data = rtc_get_month(latch, 0); + new_data %= 10; + new_data += ((real_data & 1) * 10); + if (context->stop) { + context->latch = rtc_set_latched_month(new_data, latch, 0); + } else { + context->offset = rtc_set_month(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_YEARS: + new_data = rtc_get_year(latch, 0); + new_data /= 10; + new_data *= 10; + new_data += LIMIT_9(real_data); + if (context->stop) { + context->latch = rtc_set_latched_year(new_data, latch, 0); + } else { + context->offset = rtc_set_year(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_10YEARS: + new_data = rtc_get_year(latch, 0); + new_data %= 10; + new_data += (LIMIT_9(real_data) * 10); + if (context->stop) { + context->latch = rtc_set_latched_year(new_data, latch, 0); + } else { + context->offset = rtc_set_year(new_data, context->offset, 0); + } + break; + case RTC72421_REGISTER_CTRL0: + context->control[0] = real_data; + break; + case RTC72421_REGISTER_CTRL1: + /* RAMLINK writes/reads data to this register to detect the + presence of the rtc */ + context->control[1] = real_data; + break; + case RTC72421_REGISTER_CTRL2: + context->control[2] = real_data; + context->hour24 = (real_data & 4) ? 1: 0; + if (real_data & 2) { + context->stop = 1; + context->latch = rtc_get_latch(context->offset); + } else { + /* problem here, we have to do this only if we were previously + stopped, otherwise we mess up the counter */ + if (context->stop) { + context->stop = 0; + context->offset = context->offset - + (rtc_get_latch(0) - (context->latch - context->offset)); + } + } + break; + } + /* after every register write, recalculate the day_offset */ + day = rtc_get_weekday(latch); + if (context->stop) { + context->day_latch = context->day - day; + } else { + context->day_offset = context->day - day; + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* RTC_72421 snapshot module format: + + type | name | description + -------------------------------- + BYTE | stop | stop flag + BYTE | 24 hours | 24 hours flag + BYTE | day offset | offset for day of week + BYTE | day latch | latch for day of week + BYTE | day | day of week (needed for above 2) + DWORD | latch hi | high DWORD of latch offset + DWORD | latch lo | low DWORD of latch offset + DWORD | offset hi | high DWORD of RTC offset + DWORD | offset lo | low DWORD of RTC offset + DWORD | old offset hi | high DWORD of old RTC offset + DWORD | old offset lo | low DWORD of old RTC offset + STRING | device | device name string + */ + +static const char snap_module_name[] = "RTC_72421"; +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int rtc72421_write_snapshot(rtc_72421_t *context, snapshot_t *s) +{ + uint32_t latch_lo = 0; + uint32_t latch_hi = 0; + uint32_t offset_lo = 0; + uint32_t offset_hi = 0; + uint32_t old_offset_lo = 0; + uint32_t old_offset_hi = 0; + snapshot_module_t *m; + + /* time_t can be either 32bit or 64bit, so we save as 64bit */ +#if (SIZE_OF_TIME_T == 8) + latch_hi = (uint32_t)(context->latch >> 32); + latch_lo = (uint32_t)(context->latch & 0xffffffff); + offset_hi = (uint32_t)(context->offset >> 32); + offset_lo = (uint32_t)(context->offset & 0xffffffff); + old_offset_hi = (uint32_t)(context->old_offset >> 32); + old_offset_lo = (uint32_t)(context->old_offset & 0xffffffff); +#else + latch_lo = (uint32_t)context->latch; + offset_lo = (uint32_t)context->offset; + old_offset_lo = (uint32_t)context->old_offset; +#endif + + m = snapshot_module_create(s, snap_module_name, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, (uint8_t)context->stop) < 0 + || SMW_B(m, (uint8_t)context->hour24) < 0 + || SMW_B(m, (uint8_t)context->day_offset) < 0 + || SMW_B(m, (uint8_t)context->day_latch) < 0 + || SMW_B(m, (uint8_t)context->day) < 0 + || SMW_DW(m, latch_hi) < 0 + || SMW_DW(m, latch_lo) < 0 + || SMW_DW(m, offset_hi) < 0 + || SMW_DW(m, offset_lo) < 0 + || SMW_DW(m, old_offset_hi) < 0 + || SMW_DW(m, old_offset_lo) < 0 + || SMW_STR(m, context->device) < 0) { + snapshot_module_close(m); + return -1; + } + return snapshot_module_close(m); +} + +int rtc72421_read_snapshot(rtc_72421_t *context, snapshot_t *s) +{ + uint32_t latch_lo = 0; + uint32_t latch_hi = 0; + uint32_t offset_lo = 0; + uint32_t offset_hi = 0; + uint32_t old_offset_lo = 0; + uint32_t old_offset_hi = 0; + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, snap_module_name, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || SMR_B_INT(m, &context->stop) < 0 + || SMR_B_INT(m, &context->hour24) < 0 + || SMR_B_INT(m, &context->day_offset) < 0 + || SMR_B_INT(m, &context->day_latch) < 0 + || SMR_B(m, &context->day) < 0 + || SMR_DW(m, &latch_hi) < 0 + || SMR_DW(m, &latch_lo) < 0 + || SMR_DW(m, &offset_hi) < 0 + || SMR_DW(m, &offset_lo) < 0 + || SMR_DW(m, &old_offset_hi) < 0 + || SMR_DW(m, &old_offset_lo) < 0 + || SMR_STR(m, &context->device) < 0) { + goto fail; + } + +#if (SIZE_OF_TIME_T == 8) + context->latch = (time_t)(latch_hi) << 32; + context->latch |= latch_lo; + context->offset = (time_t)(offset_hi) << 32; + context->offset |= offset_lo; + context->old_offset = (time_t)(old_offset_hi) << 32; + context->old_offset |= old_offset_lo; +#else + context->latch = latch_lo; + context->offset = offset_lo; + context->old_offset = old_offset_lo; +#endif + + return snapshot_module_close(m); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/core/rtc-72421.h b/src/Emulators/vice/core/rtc-72421.h new file mode 100644 index 00000000..05a878bf --- /dev/null +++ b/src/Emulators/vice/core/rtc-72421.h @@ -0,0 +1,76 @@ +/* + * rtc-72421.h - RTC-72421 RTC emulation. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_RTC72421_H +#define VICE_RTC72421_H + +#include + +#include "snapshot.h" +#include "vicetypes.h" + +typedef struct rtc_72421_s { + int stop; + int hour24; + int day_offset; + int day_latch; + time_t latch; + time_t offset; + time_t old_offset; + uint8_t control[3]; + uint8_t day; + char *device; +} rtc_72421_t; + +enum { + RTC72421_REGISTER_SECONDS = 0, + RTC72421_REGISTER_10SECONDS, + RTC72421_REGISTER_MINUTES, + RTC72421_REGISTER_10MINUTES, + RTC72421_REGISTER_HOURS, + RTC72421_REGISTER_10HOURS, + RTC72421_REGISTER_MONTHDAYS, + RTC72421_REGISTER_10MONTHDAYS, + RTC72421_REGISTER_MONTHS, + RTC72421_REGISTER_10MONTHS, + RTC72421_REGISTER_YEARS, + RTC72421_REGISTER_10YEARS, + RTC72421_REGISTER_WEEKDAYS, + RTC72421_REGISTER_CTRL0, + RTC72421_REGISTER_CTRL1, + RTC72421_REGISTER_CTRL2 +}; + +rtc_72421_t *rtc72421_init(char *device); +void rtc72421_destroy(rtc_72421_t *context, int save); + +uint8_t rtc72421_read(rtc_72421_t *context, uint8_t address); +void rtc72421_write(rtc_72421_t *context, uint8_t address, uint8_t data); + +int rtc72421_write_snapshot(rtc_72421_t *context, snapshot_t *s); +int rtc72421_read_snapshot(rtc_72421_t *context, snapshot_t *s); + +#endif diff --git a/src/Emulators/vice/core/rtc/rtc-72421.h b/src/Emulators/vice/core/rtc/rtc-72421.h new file mode 100644 index 00000000..05a878bf --- /dev/null +++ b/src/Emulators/vice/core/rtc/rtc-72421.h @@ -0,0 +1,76 @@ +/* + * rtc-72421.h - RTC-72421 RTC emulation. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_RTC72421_H +#define VICE_RTC72421_H + +#include + +#include "snapshot.h" +#include "vicetypes.h" + +typedef struct rtc_72421_s { + int stop; + int hour24; + int day_offset; + int day_latch; + time_t latch; + time_t offset; + time_t old_offset; + uint8_t control[3]; + uint8_t day; + char *device; +} rtc_72421_t; + +enum { + RTC72421_REGISTER_SECONDS = 0, + RTC72421_REGISTER_10SECONDS, + RTC72421_REGISTER_MINUTES, + RTC72421_REGISTER_10MINUTES, + RTC72421_REGISTER_HOURS, + RTC72421_REGISTER_10HOURS, + RTC72421_REGISTER_MONTHDAYS, + RTC72421_REGISTER_10MONTHDAYS, + RTC72421_REGISTER_MONTHS, + RTC72421_REGISTER_10MONTHS, + RTC72421_REGISTER_YEARS, + RTC72421_REGISTER_10YEARS, + RTC72421_REGISTER_WEEKDAYS, + RTC72421_REGISTER_CTRL0, + RTC72421_REGISTER_CTRL1, + RTC72421_REGISTER_CTRL2 +}; + +rtc_72421_t *rtc72421_init(char *device); +void rtc72421_destroy(rtc_72421_t *context, int save); + +uint8_t rtc72421_read(rtc_72421_t *context, uint8_t address); +void rtc72421_write(rtc_72421_t *context, uint8_t address, uint8_t data); + +int rtc72421_write_snapshot(rtc_72421_t *context, snapshot_t *s); +int rtc72421_read_snapshot(rtc_72421_t *context, snapshot_t *s); + +#endif diff --git a/src/Emulators/vice/core/scsi.c b/src/Emulators/vice/core/scsi.c new file mode 100644 index 00000000..d3d74d0e --- /dev/null +++ b/src/Emulators/vice/core/scsi.c @@ -0,0 +1,1020 @@ +/* + * scsi.c - SCSI disk emulation + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif + +#define _FILE_OFFSET_BITS 64 + +#include +#include + +#include "archdep.h" +#include "lib.h" +#include "log.h" +#include "vicetypes.h" +#include "snapshot.h" +#include "scsi.h" + +/* #define SCSILOG1 */ +/* #define SCSILOG2 */ +/* #define SCSIDBG */ + +#define LOG LOG_DEFAULT + +#ifdef SCSILOG1 +#define LOG1(_x_) log_message _x_ +#else +#define LOG1(_x_) +#endif + +#ifdef SCSILOG2 +#define LOG2(_x_) log_message _x_ +#else +#define LOG2(_x_) +#endif + +#ifdef SCSIDBG +#define SDBG(_x_) log_message _x_ +#else +#define SDBG(_x_) +#endif + +#define CRIT(_x_) log_error _x_ + +#define MAXIDS 7 +#define MAXLUNS 8 + +static off_t scsi_getmaxsize(struct scsi_context_s *context) +{ + off_t work; + + /* make sure the target and lun are valid */ + if (context->target >= MAXIDS || context->lun >= MAXLUNS) { + return 0; + } + + /* make sure there is a file associated with the target and lun */ + if (context->file[(context->target << 3) | context->lun]) { + if (!context->max_imagesize) { + /* if the max length setting is zero, return the image length */ + work = archdep_file_size(context->file[(context->target << 3) | context->lun]); + /* turn the file size into 512 byte sectors */ + work = (work >> 9) + (work & 511 ? 1 : 0); + return work; + } else { + /* other wise, return the setting itself */ + return context->max_imagesize; + } + } + + /* not a valid file, return 0 */ + return 0; +} + +static int32_t scsi_imagecheck(struct scsi_context_s *context) +{ + if (context->target >= MAXIDS || context->lun >= MAXLUNS) { + return 1; + } + + if (!context->file[(context->target << 3) | context->lun]) { + if ( context->target == 0 && context->lun == 0 && + !(context->log & SCSI_LOG_NODISK0) ) { + CRIT((LOG, "SCSI: no image attached to disk 0;" + " expect unusual results and/or hangs" )); + context->log |= SCSI_LOG_NODISK0; + } + return 2; + } + + return 0; +} + +int scsi_image_detach(struct scsi_context_s *context, int disk) +{ + if (disk < 0 || disk > 55) { + return 2; + } + + if (context->file[disk]) { + fclose(context->file[disk]); + context->file[disk] = NULL; + return 0; + } + + return 1; +} + +void scsi_image_detach_all(struct scsi_context_s *context) +{ + int32_t i; + + for (i = 0; i < 56; i++) { + scsi_image_detach(context, i); + } + + return; +} + +int scsi_image_attach(struct scsi_context_s *context, int disk, char *filename) +{ + if (disk < 0 || disk > 55) { + return 2; + } + + scsi_image_detach(context, disk); + context->file[disk] = fopen(filename, "rb+"); + + if (context->file[disk]) { + setbuf(context->file[disk], NULL); + return 0; + } else { + return 1; + } +} + +int32_t scsi_image_read(struct scsi_context_s *context) +{ + int32_t i; + FILE *fhd; + + if (scsi_imagecheck(context)) { + return -1; + } + + fhd = context->file[(context->target << 3) | context->lun]; + + if (archdep_fseeko(fhd, (off_t)context->address * 512, SEEK_SET) < 0) { + CRIT((LOG, "SCSI: error seeking disk %d at sector 0x%x", + context->target, context->address)); + return -3; + } + + if (fread(context->data_buf, 512, 1, fhd) < 1) { + if (!feof(fhd)) { + CRIT((LOG, "SCSI: error reading disk %d at sector 0x%x", + context->target, context->address)); + return -4; + } + + /* if there is a read beyond the EOF, fill it with zeros and say it + is good */ + for ( i = 0; i < 512; i++) { + context->data_buf[i] = 0; + } + } + + LOG2((LOG, "SCSI: read disk %d at sector 0x%x", context->target, + context->address)); + + /* if the user provides it, call a function to modify the data before + it goes back to the host */ + if (context->user_read) { + context->user_read(context); + } + + return 0; +} + +int32_t scsi_image_write(struct scsi_context_s *context) +{ + FILE *fhd; + + if (scsi_imagecheck(context)) { + return -1; + } + + /* if the user provides it, call a function to modify the data before + it writes to disk */ + if (context->user_write) { + context->user_write(context); + } + + fhd = context->file[(context->target << 3) | context->lun]; + + if (archdep_fseeko(fhd, (off_t)context->address * 512, SEEK_SET) < 0) { + CRIT((LOG, "SCSI: error seeking disk %d at sector 0x%x", + context->target, context->address)); + return -3; + } + + if (fwrite(context->data_buf, 512, 1, fhd) < 1) { + CRIT((LOG, "SCSI: error writing disk %d at sector 0x%x", + context->target, context->address)); + return -4; + } + fflush(fhd); + + LOG2((LOG, "SCSI: write disk %d at sector 0x%x", context->target, + context->address)); + + return 0; +} + +/* default format handler */ +/* We don't actually format the disk, we just zero out the first sector */ +static void scsi_format_sector0(struct scsi_context_s *context) +{ + int32_t i; + + context->address = 0; + + for (i = 0; i < 512; i++) { + context->data_buf[i] = 0; + } + + scsi_image_write(context); +} + +uint8_t scsi_get_bus(struct scsi_context_s *context) +{ + return context->databus; +} + +int scsi_set_bus(struct scsi_context_s *context, uint8_t value) +{ + if (!context->io) { + context->databus = value; + return 0; + } else { + return 1; + } +} + +void scsi_process_noack(struct scsi_context_s *context) +{ + int32_t i, t, n; + + SDBG((LOG, "SCSI: process noack state=%02x %02x", context->state, + context->databus)); + + /* handle reset condition */ + if (context->rst) { + context->cmd_size = 256; + context->target = 255; + context->bsyo = 0; + context->req = 0; + context->io = 0; + context->cd = 0; + context->msg = 0; + context->seq = 0; + context->link = 0; + context->state = SCSI_STATE_BUSFREE; + return; + } + + if (context->state != SCSI_STATE_BUSFREE) { + return; + } + + /* handle SELECTION phase here */ + if (context->sel && !context->bsyo) { + /* obtain target */ + context->target = 0; + /* remove initiator from list */ + t = (context->databus ^ 0xff) & 0x7f; + n = 0; + i = 0; + while (t) { + if (t & 1) { + context->target = i; + n++; + } + t = t >> 1; + i++; + } + if (n==1 && context->target < 7) { + context->bsyo = 1; + context->req = 0; + context->seq = 0; + SDBG((LOG, "SCSI: TARGET=%02x", context->target)); + } else { + /* Not asking for single ID or < 7, don't respond */ + context->target = 255; + context->cmd_size = 256; + } + return; + } else if (context->sel && context->bsyo) { + /* do nothing, we are asserting BSY waiting for SEL to drop */ + SDBG((LOG, "SCSI: waiting for SEL to drop")); + } else if (!context->sel && context->bsyo && + context->state == SCSI_STATE_BUSFREE) { + /* initiator has dropped SEL, we switch to command mode, keep + BSY set */ + SDBG((LOG, "SCSI: ready for command")); + context->state = SCSI_STATE_COMMAND; + context->cmd_size = 256; + context->req = 1; + } + +} + +/* LTK DOS only seems to send out commands: + TEST UNIT READY (0) - from boot rom + REZERO UNIT (1) - from boot rom + READ (8) - from boot rom and DOS + WRITE (10) - DOS + I'll keep other stuff since it is for CMD HD emulation. + May also add to DOS in future. +*/ + +void scsi_process_ack(struct scsi_context_s *context) +{ + uint8_t data = context->databus ^ 0xff; + uint8_t byte; + off_t j; + int32_t i; + unsigned char VENDORID[9] = "VICEEMUL"; /* 8 chars */ + unsigned char PRODID[17] = "SCSI Image File "; /* 16 chars */ + char *REVISION; /* 4 chars */ + + SDBG((LOG, "SCSI: process ack state=%02x", context->state)); + + if (context->state == SCSI_STATE_BUSFREE) { + return; + } + + if (context->state == SCSI_STATE_STATUS) { + context->cd = 1; + if (context->link) { + context->seq = 0; + context->state = SCSI_STATE_COMMAND; + context->io = 0; + } else { + if (context->msg_after_status) { + /* LTK expects drive to go to MESSAGEIN after STATUS instead + of BUSFREE */ + context->state = SCSI_STATE_MESSAGEIN; + context->io = 1; + context->msg = 1; + context->databus = 0 ^ 0xff; /* just incase we set it 0 */ + } else { + context->state = SCSI_STATE_BUSFREE; + context->req = 0; + context->io = 0; + context->msg = 0; + context->cd = 0; + } + context->bsyo = 0; + goto out; + } + } + + if (context->state == SCSI_STATE_MESSAGEIN) { + context->state = SCSI_STATE_BUSFREE; + context->req = 0; + context->bsyo = 0; + context->io = 0; + context->msg = 0; + context->cd = 0; + goto out; + } + + if (context->state == SCSI_STATE_DATAOUT) { + do { + context->io = 0; + context->cd = 0; + context->data_buf[context->seq] = data; + SDBG((LOG, "SCSI: DATAOUT[%02x]=%02x", context->seq, + context->data_buf[context->seq])); + context->seq++; + if (context->seq >= context->data_max) { + /* write if WRITE command */ + if (context->command == SCSI_COMMAND_WRITE_6 || + context->command == SCSI_COMMAND_WRITE_10 || + context->command == SCSI_COMMAND_WRITE_VERIFY) { + if (scsi_image_write(context)) { + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + context->seq = 0; + context->blocks--; + context->address++; + /* count down the number of blocks received, keep going + if necessary */ + if (!context->blocks) { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + if (context->address >= scsi_getmaxsize(context)) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_LOGICALBLOCKADDRESSOUTOFRANGE; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + } else if (context->command == SCSI_COMMAND_FORMAT_UNIT) { + for (i = 0; i < 4; i++) { + if (context->data_buf[i]) { + break; + } + } + /* can read defect list header, but it has to be all + zeros */ + if (i != 4) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_INVALIDFIELDINPARAMETERLIST; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + } else { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + context->user_format(context); + } + } else if (context->command == SCSI_COMMAND_REASSIGN_BLOCKS) { + /* accept defect list, just don't do anything about it */ + if (context->seq == 4) { + context->seq = ((context->data_buf[0] << 24)| + (context->data_buf[1] << 16)| + (context->data_buf[2] << 8)| + (context->data_buf[3])) + 4; + if (context->seq > 512) { + context->seq = 512; + } + } else { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + } + } else { + /* otherwise, finish up */ + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + } + } + } while (0); + } + + if (context->state == SCSI_STATE_COMMAND) { + do { + context->io = 0; + context->cd = 1; + context->cmd_buf[context->seq] = data; + SDBG((LOG, "SCSI: COMMAND[%u]=%02x", context->seq, data)); + + if (context->seq == 0) { + context->command = context->cmd_buf[0]; + switch (context->command) { + case SCSI_COMMAND_TEST_UNIT_READY: + /* fall through */ + case SCSI_COMMAND_REZERO_UNIT: + /* fall through */ + case SCSI_COMMAND_REQUEST_SENSE: + /* fall through */ + case SCSI_COMMAND_FORMAT_UNIT: + /* fall through */ + case SCSI_COMMAND_REASSIGN_BLOCKS: + /* fall through */ + case SCSI_COMMAND_READ_6: + /* fall through */ + case SCSI_COMMAND_WRITE_6: + /* fall through */ + case SCSI_COMMAND_INQUIRY: + /* fall through */ + case SCSI_COMMAND_MODE_SENSE: + /* fall through */ + case SCSI_COMMAND_START_STOP: + /* fall through */ + case SCSI_COMMAND_SEND_DIAGNOSTIC: + context->cmd_size = 6; + break; + case SCSI_COMMAND_READ_CAPACITY: + /* fall through */ + case SCSI_COMMAND_READ_10: + /* fall through */ + case SCSI_COMMAND_WRITE_10: + /* fall through */ + case SCSI_COMMAND_MODE_SENSE_10: + /* fall through */ + case SCSI_COMMAND_WRITE_VERIFY: + /* fall through */ + case SCSI_COMMAND_VERIFY: + context->cmd_size = 10; + break; + default: + CRIT((LOG, "SCSI: Unknown Command=%0x", + context->cmd_buf[0])); + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + } + context->seq++; + if (context->seq >= context->cmd_size) { + switch (context->command) { + case SCSI_COMMAND_TEST_UNIT_READY: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[5] & 1; + if (scsi_imagecheck(context)) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + } else { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + } + break; + case SCSI_COMMAND_REQUEST_SENSE: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[5] & 1; + context->data_max = context->cmd_buf[4]; + if (!context->data_max) { + context->data_max = 4; + } + if (context->data_max > 18) { + context->data_max = 18; + } + for (i = 0; i < 512; i++) { + context->data_buf[i] = 0; + } + context->data_buf[0] = 0x80 | 0x70; + context->data_buf[1] = 0x00; + context->data_buf[2] = context->sensekey; + context->data_buf[12] = context->asc; + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + case SCSI_COMMAND_REASSIGN_BLOCKS: + context->state = SCSI_STATE_DATAOUT; + context->data_max = 4; + context->seq = 0; + break; + case SCSI_COMMAND_READ_6: + /* fall through */ + case SCSI_COMMAND_READ_10: + context->lun = (context->cmd_buf[1] >> 5) & 7; + if (context->command == SCSI_COMMAND_READ_6) { + context->link = context->cmd_buf[5] & 1; + context->address = ((context->cmd_buf[1] & 0x1f) << 16)| + (context->cmd_buf[2] << 8)|(context->cmd_buf[3]); + context->blocks = context->cmd_buf[4]; + /* if blocks=0, it really means 256 */ + if (!context->blocks) { + context->blocks = 256; + } + } else { + context->link = context->cmd_buf[9] & 1; + context->address = (context->cmd_buf[2] << 24)| + (context->cmd_buf[3] << 16)| + (context->cmd_buf[4] << 8)|(context->cmd_buf[5]); + context->blocks = (context->cmd_buf[7] << 8)| + (context->cmd_buf[8]); + /* if blocks=0, it really means 0 */ + if (!context->blocks) { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + } + context->data_max = 512; + if (context->address >= scsi_getmaxsize(context)) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_LOGICALBLOCKADDRESSOUTOFRANGE; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + if (!scsi_image_read(context)) { + context->state = SCSI_STATE_DATAIN; + context->seq = 0; + } else { + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + } + break; + case SCSI_COMMAND_WRITE_6: + /* fall through */ + case SCSI_COMMAND_WRITE_10: + /* fall through */ + case SCSI_COMMAND_WRITE_VERIFY: + context->lun = (context->cmd_buf[1] >> 5) & 7; + if (context->command == SCSI_COMMAND_WRITE_6) { + context->link = context->cmd_buf[5] & 1; + context->address = ((context->cmd_buf[1] & 0x1f) << 16)| + (context->cmd_buf[2] << 8)|(context->cmd_buf[3]); + context->blocks = context->cmd_buf[4]; + /* if blocks=0, it really means 256 */ + if (!context->blocks) { + context->blocks = 256; + } + } else { + context->link = context->cmd_buf[9] & 1; + context->address = (context->cmd_buf[2] << 24)| + (context->cmd_buf[3] << 16)| + (context->cmd_buf[4] << 8)|(context->cmd_buf[5]); + context->blocks = (context->cmd_buf[7] << 8)| + (context->cmd_buf[8]); + /* if blocks=0, it really means 0 */ + if (!context->blocks) { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + } + context->data_max = 512; + if (context->address >= scsi_getmaxsize(context)) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_LOGICALBLOCKADDRESSOUTOFRANGE; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + if (!scsi_imagecheck(context)) { + context->state = SCSI_STATE_DATAOUT; + context->seq = 0; + } else { + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + } + break; + case SCSI_COMMAND_INQUIRY: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[5] & 1; + context->data_max = context->cmd_buf[4]; /* usually 96 */ + for (i = 0; i < 512; i++) { + context->data_buf[i] = 0; + } + if (scsi_imagecheck(context)) { + context->data_buf[0] = 0x60; + } else { + context->data_buf[0] = 0x00; + } + context->data_buf[1] = 0x00; /* not removable */ + context->data_buf[2] = 0x01; /* SCSI 1 */ + context->data_buf[3] = 0x02; + context->data_buf[4] = 92; /* no additional data */ + context->data_buf[5] = 0x00; /* res */ + context->data_buf[6] = 0x00; /* res */ + context->data_buf[7] = 0x00; /* no reladr, wbus32, wbus16, + sync, linked, cmdque, or sftre */ + for (i = 0; i < 8; i++) { + context->data_buf[i + 8] = VENDORID[i]; + } + for (i = 0; i < 16; i++) { + context->data_buf[i + 16] = PRODID[i]; + } + REVISION = lib_msprintf("%s ", VERSION); + for (i = 0; i < 4; i++) { + context->data_buf[i + 32] = REVISION[i]; + } + lib_free(REVISION); + context->state = SCSI_STATE_DATAIN; + context->seq = 0; + break; + case SCSI_COMMAND_READ_CAPACITY: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[9] & 1; + context->data_max = 8; + j = scsi_getmaxsize(context); + if (j == 0) { + i = 0; + } else { +/* Limit size returned as some tools can't handle large disks */ + if (j > context->limit_imagesize) { + j = context->limit_imagesize; + } + i = 512; +/* SCSI spec says return last accessable block number */ + j--; + } + context->data_buf[0] = (j >> 24) & 255; + context->data_buf[1] = (j >> 16) & 255; + context->data_buf[2] = (j >> 8) & 255; + context->data_buf[3] = j & 255; + context->data_buf[4] = (i >> 24) & 255; + context->data_buf[5] = (i >> 16) & 255; + context->data_buf[6] = (i >> 8) & 255; + context->data_buf[7] = i & 255; + context->state = SCSI_STATE_DATAIN; + context->seq = 0; + break; + case SCSI_COMMAND_MODE_SENSE: + /* fall through */ + case SCSI_COMMAND_MODE_SENSE_10: + context->state = SCSI_STATE_DATAIN; + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->seq = 0; + if (context->command == SCSI_COMMAND_MODE_SENSE) { + context->data_max = context->cmd_buf[4]; + context->link = context->cmd_buf[5] & 1; + } else { + context->data_max = (context->cmd_buf[7] << 8)| + (context->cmd_buf[8]); + if (context->data_max > 255) { + context->data_max = 255; + } + context->link = context->cmd_buf[9] & 1; + } + for (i = 0; i < 512; i++) { + context->data_buf[i] = 0; + } +/* CMD drive info tool looks at page 20h, so lets put that one in */ + switch (context->cmd_buf[2]) { + case 0x00 | 0x20: + context->data_buf[3] = 1; + REVISION = lib_msprintf("%s-%s", VERSION, "SCSI"); + for (i = 0; i < context->data_max - (3 + 1 + 3) && + REVISION[i]; i++) { + context->data_buf[3 + 1 + 3 + i] = REVISION[i]; + } + lib_free(REVISION); + context->data_buf[3 + 1 + 2] = i; + break; + default: + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_INVALIDFIELDINCDB; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + break; + case SCSI_COMMAND_FORMAT_UNIT: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[5] & 1; + /* check if fmtdata is set, move on to dataout */ + if ((context->cmd_buf[1] & 0x17) == 0x10) { + context->state = SCSI_STATE_DATAOUT; + context->seq = 0; + context->data_max = 4; + /* cmplist can be anything, but list format must be 0 */ + } else if ((context->cmd_buf[1] & 0x17) == 0x00) { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + context->user_format(context); + } else { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_INVALIDFIELDINPARAMETERLIST; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + } + break; + case SCSI_COMMAND_REZERO_UNIT: + /* fall through */ + case SCSI_COMMAND_START_STOP: + /* fall through */ + case SCSI_COMMAND_SEND_DIAGNOSTIC: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[5] & 1; + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + case SCSI_COMMAND_VERIFY: + context->lun = (context->cmd_buf[1] >> 5) & 7; + context->link = context->cmd_buf[9] & 1; + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + } + } while (0); + } + + if (context->state == SCSI_STATE_DATAIN) { + do { + if (context->seq >= context->data_max) { + /* reload more data if READ command */ + if (context->command == SCSI_COMMAND_READ_6 || + context->command == SCSI_COMMAND_READ_10) { + context->seq = 0; + context->blocks--; + context->address++; + /* count down the number of blocks sent, keep going if + necessary */ + if (!context->blocks) { + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + /* if we are out of range, report an error */ + if (context->address >= scsi_getmaxsize(context)) { + context->sensekey = SCSI_SENSEKEY_ILLEGALREQUEST; + context->asc = SCSI_SASC_LOGICALBLOCKADDRESSOUTOFRANGE; + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + /* read it, report error if a problem */ + if (scsi_image_read(context)) { + context->status = SCSI_STATUS_CHECKCONDITION; + context->state = SCSI_STATE_STATUS; + break; + } + /* all is good, keep state the same */ + } else { + /* otherwise, finish up */ + context->status = SCSI_STATUS_GOOD; + context->state = SCSI_STATE_STATUS; + break; + } + /* never gets here */ + } + byte = context->data_buf[context->seq]; + SDBG((LOG, "SCSI: DATAIN[%02x]=%02x", context->seq, + context->data_buf[context->seq])); + context->seq++; + context->databus = byte ^ 0xff; + context->io = 1; + context->cd = 0; + } while (0); + } + + if (context->state == SCSI_STATE_STATUS) { + byte = (context->status << 1) | 0; + SDBG((LOG, "SCSI: STATUS=%02x", context->status)); + context->io = 1; + context->databus = byte ^ 0xff; + context->cd = 1; + } + + if (context->state == SCSI_STATE_DATAOUT) { + context->cd = 0; + } + +out: + return; +} + +void scsi_reset(struct scsi_context_s *context) +{ + context->max_imagesize = 512 * 1024 * 1024 / 512; + context->limit_imagesize = 512 * 1024 * 1024 / 512; + context->rst = 1; + scsi_process_noack(context); + context->rst = 0; + context->msg_after_status = 0; + context->user_format = scsi_format_sector0; + context->user_read = NULL; + context->user_write = NULL; + context->log = 0; + + return; +} + +/* ---------------------------------------------------------------------*/ + +/* SCSI snapshot module format: + + type | name | description + ----------------------------------------------------- + BYTE | state | state + BYTE | target | target + BYTE | databus | databus + BYTE | ack | ack + BYTE | req | req + BYTE | bsyi | bsyi + BYTE | bsyo | bsyo + BYTE | sel | sel + BYTE | rst | rst + BYTE | atn | atn + BYTE | cd | cd + bYTE | io | io + BYTE | msg | msg + BYTE | link | link + BYTE | status | status + BYTE | lun | lun + BYTE | command | command + BYTE | sensekey | sensekey + BYTE | asc | asc + BYTE | msg_after_status | msg_after_status + DWORD | seq | seq + DWORD | cmd_size | cmd_size + DWORD | address | address + DWORD | blocks | blocks + DWORD | data_max | data_max + DWORD | max_imagesize | max_imagesize + ARRAY | cmd_buf | 256 bytes of cmd_buf + ARRAY | data_buf | 512 bytes of data_buf + +*/ + +#define SNAP_MAJOR 0 +#define SNAP_MINOR 0 + +int scsi_snapshot_write_module(struct scsi_context_s *context, snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, context->myname, SNAP_MAJOR, SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)context->state) < 0) + || (SMW_B(m, (uint8_t)context->target) < 0) + || (SMW_B(m, (uint8_t)context->databus) < 0) + || (SMW_B(m, (uint8_t)context->ack) < 0) + || (SMW_B(m, (uint8_t)context->req) < 0) + || (SMW_B(m, (uint8_t)context->bsyi) < 0) + || (SMW_B(m, (uint8_t)context->bsyo) < 0) + || (SMW_B(m, (uint8_t)context->sel) < 0) + || (SMW_B(m, (uint8_t)context->rst) < 0) + || (SMW_B(m, (uint8_t)context->atn) < 0) + || (SMW_B(m, (uint8_t)context->cd) < 0) + || (SMW_B(m, (uint8_t)context->io) < 0) + || (SMW_B(m, (uint8_t)context->msg) < 0) + || (SMW_B(m, (uint8_t)context->link) < 0) + || (SMW_B(m, (uint8_t)context->status) < 0) + || (SMW_B(m, (uint8_t)context->lun) < 0) + || (SMW_B(m, (uint8_t)context->command) < 0) + || (SMW_B(m, (uint8_t)context->sensekey) < 0) + || (SMW_B(m, (uint8_t)context->asc) < 0) + || (SMW_B(m, (uint8_t)context->msg_after_status) < 0) + || (SMW_DW(m, (uint32_t)context->seq) < 0) + || (SMW_DW(m, (uint32_t)context->cmd_size) < 0) + || (SMW_DW(m, (uint32_t)context->address) < 0) + || (SMW_DW(m, (uint32_t)context->blocks) < 0) + || (SMW_DW(m, (uint32_t)context->data_max) < 0) + || (SMW_DW(m, (uint32_t)context->max_imagesize) < 0) + || (SMW_BA(m, context->cmd_buf, 256) < 0) + || (SMW_BA(m, context->data_buf, 512) < 0)) { + snapshot_module_close(m); + return -1; + } + + return snapshot_module_close(m); +} + +int scsi_snapshot_read_module(struct scsi_context_s *context, snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, context->myname, &vmajor, &vminor); + + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + goto fail; + } + + if (0 + || (SMR_B(m, &context->state) < 0) + || (SMR_B(m, &context->target) < 0) + || (SMR_B(m, &context->databus) < 0) + || (SMR_B(m, &context->ack) < 0) + || (SMR_B(m, &context->req) < 0) + || (SMR_B(m, &context->bsyi) < 0) + || (SMR_B(m, &context->bsyo) < 0) + || (SMR_B(m, &context->sel) < 0) + || (SMR_B(m, &context->rst) < 0) + || (SMR_B(m, &context->atn) < 0) + || (SMR_B(m, &context->cd) < 0) + || (SMR_B(m, &context->io) < 0) + || (SMR_B(m, &context->msg) < 0) + || (SMR_B(m, &context->link) < 0) + || (SMR_B(m, &context->status) < 0) + || (SMR_B(m, &context->lun) < 0) + || (SMR_B(m, &context->command) < 0) + || (SMR_B(m, &context->sensekey) < 0) + || (SMR_B(m, &context->asc) < 0) + || (SMR_B(m, &context->msg_after_status) < 0) + || (SMR_DW(m, &context->seq) < 0) + || (SMR_DW(m, &context->cmd_size) < 0) + || (SMR_DW(m, &context->address) < 0) + || (SMR_DW(m, &context->blocks) < 0) + || (SMR_DW(m, &context->data_max) < 0) + || (SMR_DW(m, &context->max_imagesize) < 0) + || (SMR_BA(m, context->cmd_buf, 256) < 0) + || (SMR_BA(m, context->data_buf, 512) < 0)) { + goto fail; + } + + return snapshot_module_close(m); + +fail: + snapshot_module_close(m); + return -1; +} diff --git a/src/Emulators/vice/core/scsi.h b/src/Emulators/vice/core/scsi.h new file mode 100644 index 00000000..f4e2a66f --- /dev/null +++ b/src/Emulators/vice/core/scsi.h @@ -0,0 +1,224 @@ +/* + * scsi.h - SCSI disk emulation + * + * Written by + * Roberto Muscedere + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_SCSI_H +#define VICE_SCSI_H + +#include "vicetypes.h" + +struct scsi_context_s; + +typedef struct scsi_context_s { + char *myname; + uint8_t state; + uint8_t target; + uint8_t databus; + uint8_t ack; + uint8_t req; + uint8_t bsyi; + uint8_t bsyo; + uint8_t sel; + uint8_t rst; + uint8_t atn; + uint8_t cd; + uint8_t io; + uint8_t msg; + uint32_t seq; + uint32_t cmd_size; + uint32_t address; + uint32_t blocks; + uint32_t data_max; + uint8_t link; + uint8_t status; + uint8_t lun; + uint8_t command; + uint8_t sensekey; + uint8_t asc; + uint8_t cmd_buf[256]; + uint8_t data_buf[512]; + uint8_t msg_after_status; + uint32_t max_imagesize; /* in 512 byte sectors */ + uint32_t limit_imagesize; /* in 512 byte sectors */ + uint32_t log; + FILE *file[56]; + void *p; + void (*user_format)(struct scsi_context_s *); + void (*user_read)(struct scsi_context_s *); + void (*user_write)(struct scsi_context_s *); +} scsi_context_t; + +/* From SCSI-1 standard: + +============================================================================== + Signal +----------- +MSG C/D I/O Phase Name Direction Of Transfer Comment +------------------------------------------------------------------------------ + 0 0 0 DATA OUT Initiator to target \ Data + 0 0 1 DATA IN Initiator from target / Phase + 0 1 0 COMMAND Initiator to target + 0 1 1 STATUS Initiator from target + 1 0 0 * + 1 0 1 * + 1 1 0 MESSAGE OUT Initiator to target \ Message + 1 1 1 MESSAGE IN Initiator from target / Phase +============================================================================== + +*/ + +#define SCSI_STATE_DATAOUT 0x00 +#define SCSI_STATE_DATAIN 0x01 +#define SCSI_STATE_COMMAND 0x02 +#define SCSI_STATE_STATUS 0x03 +#define SCSI_STATE_MESSAGEOUT 0x04 +#define SCSI_STATE_MESSAGEIN 0x05 +#define SCSI_STATE_BUSFREE 0x10 +#define SCSI_STATE_SELECTION 0x20 + +/* will be bitshifted left by 1 before sent: see table 14-2 of scsi spec */ +#define SCSI_STATUS_GOOD 0x00 +#define SCSI_STATUS_CHECKCONDITION 0x01 +#define SCSI_STATUS_CONDITIONMET 0x02 +#define SCSI_STATUS_BUSY 0x04 +#define SCSI_STATUS_INTERMEDIATE 0x08 +#define SCSI_STATUS_INTERMEDIATECONDITIONMET 0x0A +#define SCSI_STATUS_RESERVATIONCONFLICT 0x0C +#define SCSI_STATUS_COMMANDTERMINATED 0x11 +#define SCSI_STATUS_QUEUEFULL 0x14 + +#define SCSI_SENSEKEY_NOSENSE 0x00 +#define SCSI_SENSEKEY_RECOVEREDERROR 0x01 +#define SCSI_SENSEKEY_NOTREADY 0x02 +#define SCSI_SENSEKEY_MEDIUMERROR 0x03 +#define SCSI_SENSEKEY_HARDWAREERROR 0x04 +#define SCSI_SENSEKEY_ILLEGALREQUEST 0x05 +#define SCSI_SENSEKEY_UNITATTENTION 0x06 +#define SCSI_SENSEKEY_DATAPROTECT 0x07 +#define SCSI_SENSEKEY_BLANKCHECK 0x08 +#define SCSI_SENSEKEY_VENDORSPECIFIC 0x09 +#define SCSI_SENSEKEY_COPYABORTED 0x0a +#define SCSI_SENSEKEY_ABORTEDCOMMAND 0x0b +#define SCSI_SENSEKEY_EQUAL 0x0c +#define SCSI_SENSEKEY_VOLUMEOVERFLOW 0x0d +#define SCSI_SENSEKEY_MISCOMPARE 0x0e +#define SCSI_SENSEKEY_COMPLETED 0x0f + +#define SCSI_SASC_LOGICALBLOCKADDRESSOUTOFRANGE 0x21 +#define SCSI_SASC_INVALIDFIELDINCDB 0x24 +#define SCSI_SASC_INVALIDFIELDINPARAMETERLIST 0x26 + +#define SCSI_LOG_NODISK0 0x01 + +/* commands that have full or limited implementation known + to be used by LTK and CMD HDs */ +#define SCSI_COMMAND_TEST_UNIT_READY 0x00 +#define SCSI_COMMAND_REZERO_UNIT 0x01 +#define SCSI_COMMAND_REQUEST_SENSE 0x03 +#define SCSI_COMMAND_FORMAT_UNIT 0x04 +#define SCSI_COMMAND_REASSIGN_BLOCKS 0x07 +#define SCSI_COMMAND_READ_6 0x08 +#define SCSI_COMMAND_WRITE_6 0x0a +#define SCSI_COMMAND_INQUIRY 0x12 +#define SCSI_COMMAND_MODE_SENSE 0x1a +#define SCSI_COMMAND_START_STOP 0x1b +#define SCSI_COMMAND_SEND_DIAGNOSTIC 0x1d +#define SCSI_COMMAND_READ_CAPACITY 0x25 +#define SCSI_COMMAND_READ_10 0x28 +#define SCSI_COMMAND_WRITE_10 0x2a +#define SCSI_COMMAND_VERIFY 0x2f +#define SCSI_COMMAND_MODE_SENSE_10 0x5a + +/* commands users have requested to be implemented */ +#define SCSI_COMMAND_WRITE_VERIFY 0x2e + +/* unimplemented commands */ +#define SCSI_COMMAND_READ_BLOCK_LIMITS 0x05 +#define SCSI_COMMAND_SEEK_6 0x0b +#define SCSI_COMMAND_READ_REVERSE 0x0f +#define SCSI_COMMAND_WRITE_FILEMARKS 0x10 +#define SCSI_COMMAND_SPACE 0x11 +#define SCSI_COMMAND_RECOVER_BUFFERED_DATA 0x14 +#define SCSI_COMMAND_MODE_SELECT 0x15 +#define SCSI_COMMAND_RESERVE 0x16 +#define SCSI_COMMAND_RELEASE 0x17 +#define SCSI_COMMAND_COPY 0x18 +#define SCSI_COMMAND_ERASE 0x19 +#define SCSI_COMMAND_RECEIVE_DIAGNOSTIC 0x1c +#define SCSI_COMMAND_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_COMMAND_SET_WINDOW 0x24 +#define SCSI_COMMAND_SEEK_10 0x2b +#define SCSI_COMMAND_SEARCH_HIGH 0x30 +#define SCSI_COMMAND_SEARCH_EQUAL 0x31 +#define SCSI_COMMAND_SEARCH_LOW 0x32 +#define SCSI_COMMAND_SET_LIMITS 0x33 +#define SCSI_COMMAND_PRE_FETCH 0x34 +#define SCSI_COMMAND_READ_POSITION 0x34 +#define SCSI_COMMAND_SYNCHRONIZE_CACHE 0x35 +#define SCSI_COMMAND_LOCK_UNLOCK_CACHE 0x36 +#define SCSI_COMMAND_READ_DEFECT_DATA 0x37 +#define SCSI_COMMAND_MEDIUM_SCAN 0x38 +#define SCSI_COMMAND_COMPARE 0x39 +#define SCSI_COMMAND_COPY_VERIFY 0x3a +#define SCSI_COMMAND_WRITE_BUFFER 0x3b +#define SCSI_COMMAND_READ_BUFFER 0x3c +#define SCSI_COMMAND_UPDATE_BLOCK 0x3d +#define SCSI_COMMAND_READ_LONG 0x3e +#define SCSI_COMMAND_WRITE_LONG 0x3f +#define SCSI_COMMAND_CHANGE_DEFINITION 0x40 +#define SCSI_COMMAND_WRITE_SAME 0x41 +#define SCSI_COMMAND_READ_TOC 0x43 +#define SCSI_COMMAND_LOG_SELECT 0x4c +#define SCSI_COMMAND_LOG_SENSE 0x4d +#define SCSI_COMMAND_MODE_SELECT_10 0x55 +#define SCSI_COMMAND_RESERVE_10 0x56 +#define SCSI_COMMAND_RELEASE_10 0x57 +#define SCSI_COMMAND_PERSISTENT_RESERVE_IN 0x5e +#define SCSI_COMMAND_PERSISTENT_RESERVE_OUT 0x5f +#define SCSI_COMMAND_MOVE_MEDIUM 0xa5 +#define SCSI_COMMAND_READ_12 0xa8 +#define SCSI_COMMAND_WRITE_12 0xaa +#define SCSI_COMMAND_WRITE_VERIFY_12 0xae +#define SCSI_COMMAND_SEARCH_HIGH_12 0xb0 +#define SCSI_COMMAND_SEARCH_EQUAL_12 0xb1 +#define SCSI_COMMAND_SEARCH_LOW_12 0xb2 +#define SCSI_COMMAND_READ_ELEMENT_STATUS 0xb8 +#define SCSI_COMMAND_SEND_VOLUME_TAG 0xb6 +#define SCSI_COMMAND_WRITE_LONG_2 0xea + +int scsi_image_detach(struct scsi_context_s *context, int disk); +void scsi_image_detach_all(struct scsi_context_s *context); +int scsi_image_attach(struct scsi_context_s *context, int disk, char *filename); +int32_t scsi_image_read(struct scsi_context_s *context); +int32_t scsi_image_write(struct scsi_context_s *context); +uint8_t scsi_get_bus(struct scsi_context_s *context); +int scsi_set_bus(struct scsi_context_s *context, uint8_t value); +void scsi_process_noack(struct scsi_context_s *context); +void scsi_process_ack(struct scsi_context_s *context); +void scsi_reset(struct scsi_context_s *context); +int scsi_snapshot_write_module(struct scsi_context_s *context, snapshot_t *s); +int scsi_snapshot_read_module(struct scsi_context_s *context, snapshot_t *s); + +#endif diff --git a/src/Emulators/vice/core/ser-eeprom.c b/src/Emulators/vice/core/ser-eeprom.c index 1b8962aa..537ad41b 100644 --- a/src/Emulators/vice/core/ser-eeprom.c +++ b/src/Emulators/vice/core/ser-eeprom.c @@ -41,7 +41,7 @@ /* #define LOG_COMMANDS */ /* log eeprom commands */ #ifdef EEPROMDEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif @@ -61,12 +61,16 @@ static FILE *eeprom_image_file = NULL; #define EEPROM_INCA1_DATA 6 static unsigned int eeprom_mode = EEPROM_IDLE; -static BYTE eeprom_data[EEPROM_SIZE]; +static uint8_t eeprom_data[EEPROM_SIZE]; static unsigned int eeprom_readpos = 0; static unsigned int eeprom_status = 0; static unsigned int eeprom_readbit = 0; +static const uint8_t bits[8] = { + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 +}; + /* TODO */ void eeprom_data_readadvance(void) @@ -75,15 +79,14 @@ void eeprom_data_readadvance(void) eeprom_readpos &= ((EEPROM_SIZE * 8) - 1); /* wrap at 8*1024 bit */ } -BYTE eeprom_data_readbyte(void) +uint8_t eeprom_data_readbyte(void) { return eeprom_data[(eeprom_readpos >> 3) & 0x3ff]; /* FIXME: wraparound at 0x100 ?! */ } -BYTE eeprom_data_readbit(void) +uint8_t eeprom_data_readbit(void) { - BYTE value; - static BYTE bits[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + uint8_t value; int bitpos; bitpos = eeprom_readpos & 7; value = eeprom_data_readbyte(); @@ -101,7 +104,7 @@ BYTE eeprom_data_readbit(void) return 0; } -BYTE eeprom_data_read(void) +uint8_t eeprom_data_read(void) { return eeprom_readbit; } @@ -128,9 +131,8 @@ void eeprom_cmd_reset (void) memset(eeprom_cmdbuf, 0, 4); } -void eeprom_cmd_write(BYTE value) +void eeprom_cmd_write(uint8_t value) { - static BYTE bits[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /*LOG(("EEPROM: eeprom_cmd_write bit: %d:%02x",eeprom_cmdbit,value));*/ if (value) { eeprom_cmdval |= bits[eeprom_cmdbit]; @@ -162,10 +164,9 @@ void eeprom_seq_reset(void) memset(eeprom_seqbuf, 0, 4); } -void eeprom_seq_write(BYTE value) +void eeprom_seq_write(uint8_t value) { - static BYTE bits[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; -/*LOG(("EEPROM: eeprom_seq_write bit: %d:%02x",eeprom_seqbit,value));*/ + /*LOG(("EEPROM: eeprom_seq_write bit: %d:%02x",eeprom_seqbit,value));*/ if (value) { eeprom_seqval |= bits[eeprom_seqbit]; eeprom_seqbuf[eeprom_seqpos] = eeprom_seqval; @@ -182,33 +183,33 @@ void eeprom_seq_write(BYTE value) } } -int eeprom_execute_command(int eeprom_mode) +int eeprom_execute_command(int mode) { if ((eeprom_cmdbit != 0) || (eeprom_cmdpos == 0)) { -/*LOG(("eeprom mode:%02x %02x %02x",eeprom_mode,eeprom_cmdbit,eeprom_cmdpos)); */ - return eeprom_mode; +/*LOG(("eeprom mode:%02x %02x %02x",mode,eeprom_cmdbit,eeprom_cmdpos)); */ + return mode; } -/*LOG(("eeprom CMD:%02x mode:%02x %02x %02x",eeprom_cmdbuf[0],eeprom_mode,eeprom_cmdbit,eeprom_cmdpos)); */ +/*LOG(("eeprom CMD:%02x mode:%02x %02x %02x",eeprom_cmdbuf[0],mode,eeprom_cmdbit,eeprom_cmdpos)); */ switch (eeprom_cmdbuf[0]) { case 0xa0: /* set read/write position, switches to write mode */ switch (eeprom_cmdpos) { case 1: - if (eeprom_mode != EEPROM_INSEQ) { + if (mode != EEPROM_INSEQ) { break; } /*LOG(("eeprom CMDA0 (%02x) %02x",eeprom_cmdbuf[0],eeprom_cmdbuf[1]));*/ - eeprom_mode = EEPROM_INCA0; + mode = EEPROM_INCA0; break; case 2: - if (eeprom_mode != EEPROM_INCA0) { + if (mode != EEPROM_INCA0) { break; } /*LOG(("eeprom CMDA0 pos %02x (%02x)",eeprom_cmdbuf[0],eeprom_cmdbuf[1])); */ - eeprom_mode = EEPROM_INCA0_DATA; + mode = EEPROM_INCA0_DATA; eeprom_readpos = (eeprom_cmdbuf[1] << 3); break; default: - if (eeprom_mode != EEPROM_INCA0_DATA) { + if (mode != EEPROM_INCA0_DATA) { break; } #ifdef LOG_WRITE_BYTES @@ -223,18 +224,18 @@ int eeprom_execute_command(int eeprom_mode) case 0xa1: switch (eeprom_cmdpos) { case 1: - if (eeprom_mode != EEPROM_INSEQ) { + if (mode != EEPROM_INSEQ) { break; } #ifdef LOG_COMMANDS LOG(("eeprom CMDA1 (%02x) %02x", eeprom_cmdbuf[0], eeprom_cmdbuf[1])); #endif - eeprom_mode = EEPROM_INCA1_DATA; + mode = EEPROM_INCA1_DATA; eeprom_readpos = ((eeprom_cmdbuf[1]) & 0x03ff) << 3; break; default: - if (eeprom_mode != EEPROM_INCA1_DATA) { + if (mode != EEPROM_INCA1_DATA) { break; } #ifdef LOG_COMMANDS @@ -249,10 +250,10 @@ int eeprom_execute_command(int eeprom_mode) /*LOG(("eeprom cmd %d:%02x %02x",eeprom_cmdpos,eeprom_cmdbuf[0],eeprom_cmdbuf[1]));*/ break; } - return eeprom_mode; + return mode; } -void eeprom_port_write(BYTE clk, BYTE data, int ddr, int status) +void eeprom_port_write(uint8_t clk, uint8_t data, int ddr, int status) { int nextmode; @@ -390,7 +391,7 @@ int eeprom_open_image(char *name, int rw) /* FIXME */ } else { /* FIXME */ - log_debug("eeprom card image name not set"); + log_debug(LOG_DEFAULT, "eeprom card image name not set"); return 0; } @@ -406,21 +407,21 @@ int eeprom_open_image(char *name, int rw) eeprom_image_file = fopen(eeprom_image_filename, "rb"); if (eeprom_image_file == NULL) { - log_debug("could not open eeprom card image: %s", eeprom_image_filename); + log_debug(LOG_DEFAULT, "could not open eeprom card image: %s", eeprom_image_filename); return -1; } else { if (fread(eeprom_data, 1, EEPROM_SIZE, eeprom_image_file) == 0) { - log_debug("could not read eeprom card image: %s", eeprom_image_filename); + log_debug(LOG_DEFAULT, "could not read eeprom card image: %s", eeprom_image_filename); } fseek(eeprom_image_file, 0, SEEK_SET); - log_debug("opened eeprom card image (ro): %s", eeprom_image_filename); + log_debug(LOG_DEFAULT, "opened eeprom card image (ro): %s", eeprom_image_filename); } } else { if (fread(eeprom_data, 1, EEPROM_SIZE, eeprom_image_file) == 0) { - log_debug("could not read eeprom card image: %s", eeprom_image_filename); + log_debug(LOG_DEFAULT, "could not read eeprom card image: %s", eeprom_image_filename); } fseek(eeprom_image_file, 0, SEEK_SET); - log_debug("opened eeprom card image (rw): %s", eeprom_image_filename); + log_debug(LOG_DEFAULT, "opened eeprom card image (rw): %s", eeprom_image_filename); } return 0; } @@ -432,7 +433,7 @@ void eeprom_close_image(int rw) if (rw) { fseek(eeprom_image_file, 0, SEEK_SET); if (fwrite(eeprom_data, 1, EEPROM_SIZE, eeprom_image_file) == 0) { - log_debug("could not write eeprom card image"); + log_debug(LOG_DEFAULT, "could not write eeprom card image"); } } fclose(eeprom_image_file); @@ -450,8 +451,6 @@ void eeprom_close_image(int rw) /* FIXME: implement snapshot support */ int eeprom_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -460,6 +459,9 @@ int eeprom_snapshot_write_module(snapshot_t *s) return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -474,7 +476,7 @@ int eeprom_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/core/ser-eeprom.h b/src/Emulators/vice/core/ser-eeprom.h index 6e7066bb..3d72bab4 100644 --- a/src/Emulators/vice/core/ser-eeprom.h +++ b/src/Emulators/vice/core/ser-eeprom.h @@ -29,21 +29,22 @@ #include "vicetypes.h" -extern void eeprom_data_readadvance(void); -extern BYTE eeprom_data_readbyte(void); -extern BYTE eeprom_data_readbit(void); -extern BYTE eeprom_data_read(void); -extern void eeprom_cmd_reset(void); -extern void eeprom_cmd_write(BYTE value); -extern void eeprom_seq_reset(void); -extern void eeprom_seq_write(BYTE value); -extern int eeprom_execute_command(int eeprom_mode); -extern void eeprom_port_write(BYTE clk, BYTE data, int ddr, int status); -extern int eeprom_open_image(char *name, int rw); -extern void eeprom_close_image(int rw); +void eeprom_data_readadvance(void); +uint8_t eeprom_data_readbyte(void); +uint8_t eeprom_data_readbit(void); +uint8_t eeprom_data_read(void); +void eeprom_cmd_reset(void); +void eeprom_cmd_write(uint8_t value); +void eeprom_seq_reset(void); +void eeprom_seq_write(uint8_t value); +int eeprom_execute_command(int eeprom_mode); +void eeprom_port_write(uint8_t clk, uint8_t data, int ddr, int status); +int eeprom_open_image(char *name, int rw); +void eeprom_close_image(int rw); struct snapshot_s; -extern int eeprom_snapshot_read_module(struct snapshot_s *s); -extern int eeprom_snapshot_write_module(struct snapshot_s *s); + +int eeprom_snapshot_read_module(struct snapshot_s *s); +int eeprom_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/core/spi-flash.c b/src/Emulators/vice/core/spi-flash.c new file mode 100644 index 00000000..d15a7c44 --- /dev/null +++ b/src/Emulators/vice/core/spi-flash.c @@ -0,0 +1,407 @@ +/* + * spi-flash.c + * + * Written by + * Groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +/* this implements the EN25QH128A EEPROM as used by the GMod3 cartridge. + see http://wiki.icomp.de/wiki/GMod3 + + FIXME: only a couple commands are implemented, barely enough to make the + examples in the ICOMP repository work, see https://svn.icomp.de/svn/gmod3/ + */ + +#define SPIFLASHDEBUG + +#include "vice.h" + +#include +#include /* for memset */ + +#include "log.h" +#include "spi-flash.h" +#include "resources.h" +#include "snapshot.h" +#include "vicetypes.h" +#include "util.h" + +#ifdef SPIFLASHDEBUG +#define LOG(_x_) log_printf _x_ +#else +#define LOG(_x_) +#endif + +#define MAX_ROM_SIZE (16 * 1024 * 1024) +#define MAX_ROM_64K_PAGES (MAX_ROM_SIZE / (64 * 1024)) + +#define SPI_2MB_FLASH_SIZE (2*1024*1024) +#define SPI_4MB_FLASH_SIZE (4*1024*1024) +#define SPI_8MB_FLASH_SIZE (8*1024*1024) +#define SPI_16MB_FLASH_SIZE (16*1024*1024) + +static uint8_t *spi_flash_data = NULL; +static uint32_t spi_flash_size = 0; + +static int eeprom_cs = 0; +static int eeprom_clock = 0; +static int eeprom_data_in = 0; +static int eeprom_data_out = 0; + +static unsigned int input_shiftreg = 0; +static unsigned int input_count = 0; +static unsigned int output_shiftreg = 0; +static unsigned int output_count = 0; + +static unsigned int command = 0; +static unsigned int addr = 0; + +static int write_enable_status = 0; +static int ready_busy_status = 1; + +#define FLASH_CMD_PAGE_PROGRAM 0x02 +#define FLASH_CMD_READ_DATA 0x03 +#define FLASH_CMD_READ_STATUS 0x05 +#define FLASH_CMD_WRITE_ENABLE 0x06 +#define FLASH_CMD_BLOCK_ERASE 0xd8 /* 64k erase blocks */ +#define FLASH_CMD_REMS 0x9f + +#define STATUSREADY 1 +#define STATUSBUSY 0 + +static void reset_input_shiftreg(void) +{ + /* LOG(("reset_input_shiftreg")); */ + /* clear input shift register */ + input_shiftreg = 0; + input_count = 0; +} + +static void reset_output_shiftreg(void) +{ + /* LOG(("reset_output_shiftreg")); */ + /* clear output shift register */ + output_shiftreg = 0; + output_count = 0; +} + +static void shift_input_shiftreg(void) +{ + /* shift internal shift register */ + input_shiftreg <<= 1; + /* put bit from input to shift register */ + input_shiftreg |= eeprom_data_in; + input_count++; + /* LOG(("shift_input_shiftreg %d %02x", input_count, input_shiftreg)); */ +} + +static void shift_output_shiftreg(void) +{ + if (output_count) { + /* LOG(("shift_output_shiftreg %d %08x", output_count, output_shiftreg)); */ + /* put bit from shift register to output */ + eeprom_data_out = (output_shiftreg >> 31) & 1; + /* shift internal shift register */ + output_shiftreg <<= 1; + output_count--; + } else { + eeprom_data_out = 0; + } +} + +uint8_t spi_flash_read_data(void) +{ + if (eeprom_cs == 0) { + /* LOG(("spi_flash_read_data %d", eeprom_data_out)); */ + return eeprom_data_out; + } + return 0; +} + +void spi_flash_write_data(uint8_t value) +{ + if (eeprom_cs == 0) { + /* LOG(("spi_flash_write_data %d", value)); */ + eeprom_data_in = value; + } +} + +void spi_flash_write_select(uint8_t value) +{ + /* LOG(("spi_flash_write_select %d", value)); */ + + /* Each instruction is preceded by a rising edge on Chip Select Input with Serial Clock being held low. */ + if ((eeprom_cs == 1) && (value == 0) /* && (eeprom_clock == 0) */) { + LOG(("spi_flash_write_select raising edge (select)")); + reset_input_shiftreg(); + reset_output_shiftreg(); + } else if ((eeprom_cs == 0) && (value == 1)) { + LOG(("spi_flash_write_select falling edge (deselect) command %02x", command)); + switch(command) { + case FLASH_CMD_REMS: + break; + case FLASH_CMD_READ_STATUS: + break; + case FLASH_CMD_BLOCK_ERASE: + addr = (input_shiftreg & 0xff0000) & (spi_flash_size - 1); + LOG(("executing command FLASH_CMD_BLOCK_ERASE %08x (addr:%08x)", + input_shiftreg, addr)); + memset(spi_flash_data + addr, 0xff, 0x10000); + command = STATUSBUSY; + break; + case FLASH_CMD_WRITE_ENABLE: + LOG(("executing command FLASH_CMD_WRITE_ENABLE")); + write_enable_status = 1; + break; + case FLASH_CMD_PAGE_PROGRAM: + LOG(("executing command FLASH_CMD_PAGE_PROGRAM")); + command = STATUSBUSY; + break; + case FLASH_CMD_READ_DATA: + LOG(("closing command FLASH_CMD_READ_DATA")); + command = STATUSBUSY; + break; + default: + log_error(LOG_DEFAULT, "spi_flash_write_select: unknown flash command: %02x", command); + break; + } + } + eeprom_cs = value; +} + +void spi_flash_write_clock(uint8_t value) +{ + /* LOG(("spi_flash_write_clock %d", value)); */ + + /* rising edge of clock will read one bit from data input */ + if ((eeprom_cs == 0) && (value == 1) && (eeprom_clock == 0)) { + + shift_input_shiftreg(); + switch (input_count) { + case 8: + /* LOG(("got byte 1: %02x\n", input_shiftreg)); */ + if (command == FLASH_CMD_PAGE_PROGRAM) { + addr &= (spi_flash_size - 1); + LOG(("writing byte: %02x->%02x %08x", + spi_flash_data[addr], + spi_flash_data[addr] & input_shiftreg, + addr)); + spi_flash_data[addr] &= input_shiftreg; + addr++; + reset_input_shiftreg(); + } else if (command == FLASH_CMD_READ_DATA) { + addr &= (spi_flash_size - 1); + output_shiftreg = spi_flash_data[addr] << 24; + output_count = 8; + LOG(("reading byte: %02x %08x", output_shiftreg, addr)); + addr++; + reset_input_shiftreg(); + } else { + switch(input_shiftreg) { + case FLASH_CMD_REMS: + LOG(("got cmd FLASH_CMD_REMS")); + command = FLASH_CMD_REMS; + break; + case FLASH_CMD_READ_STATUS: + LOG(("got cmd FLASH_CMD_READ_STATUS")); + command = FLASH_CMD_READ_STATUS; + /* reading stats will work without deselecting first */ + output_shiftreg = 0x01000000; + output_count = (1 * 8); + break; + case FLASH_CMD_BLOCK_ERASE: + LOG(("got cmd FLASH_CMD_BLOCK_ERASE")); + command = FLASH_CMD_BLOCK_ERASE; + break; + case FLASH_CMD_WRITE_ENABLE: + LOG(("got cmd FLASH_CMD_WRITE_ENABLE")); + command = FLASH_CMD_WRITE_ENABLE; + break; + case FLASH_CMD_PAGE_PROGRAM: + LOG(("got cmd FLASH_CMD_PAGE_PROGRAM")); + command = FLASH_CMD_PAGE_PROGRAM; + break; + case FLASH_CMD_READ_DATA: + LOG(("got cmd FLASH_CMD_READ_DATA")); + command = FLASH_CMD_READ_DATA; + break; + default: + log_error(LOG_DEFAULT, "spi_flash_write_clock: unknown flash command: %02x\n", input_shiftreg); + reset_input_shiftreg(); + break; + } + } + break; + case 16: + /* LOG(("got byte 2: %04x\n", input_shiftreg)); */ + break; + case 24: + /* LOG(("got byte 3: %06x\n", input_shiftreg)); */ + break; + case 32: + /* LOG(("got byte 4: %08x\n", input_shiftreg)); */ + + switch(command) { + /* reading id will work without deselecting first */ + case FLASH_CMD_REMS: + /* + 0: manufacturer ID ($1c) + 1: device ID ($70) + 2: capacity ($18/24 - 2^24, 16MB) + */ + switch (spi_flash_size) { + case SPI_2MB_FLASH_SIZE: + output_shiftreg = 0x1c700300; + break; + case SPI_4MB_FLASH_SIZE: + output_shiftreg = 0x1c700600; + break; + case SPI_8MB_FLASH_SIZE: + output_shiftreg = 0x1c700c00; + break; + case SPI_16MB_FLASH_SIZE: + output_shiftreg = 0x1c701800; + break; + default: + LOG(("unsupported flash size: %08x", spi_flash_size)); + output_shiftreg = 0x1c701800; /* FIXME */ + break; + } + output_count = (3 * 8); + command = STATUSBUSY; + LOG(("executing command FLASH_CMD_REMS")); + break; + case FLASH_CMD_BLOCK_ERASE: + LOG(("got addr command FLASH_CMD_BLOCK_ERASE %08x", input_shiftreg)); + break; + case FLASH_CMD_PAGE_PROGRAM: + LOG(("got addr command FLASH_CMD_PAGE_PROGRAM %08x", input_shiftreg)); + addr = input_shiftreg & (spi_flash_size - 1); + reset_input_shiftreg(); + break; + case FLASH_CMD_READ_DATA: + LOG(("got addr command FLASH_CMD_READ_DATA %08x", input_shiftreg)); + addr = input_shiftreg & (spi_flash_size - 1); + output_shiftreg = spi_flash_data[addr] << 24; + output_count = 8; + LOG(("reading byte: %02x %08x", output_shiftreg, addr)); + addr++; + reset_input_shiftreg(); + break; + default: + log_error(LOG_DEFAULT, "spi_flash_write_clock: unknown flash command: %02x\n", input_shiftreg); + reset_input_shiftreg(); + break; + } + + break; + } + shift_output_shiftreg(); + } + + eeprom_clock = value; +} + +void spi_flash_set_image(uint8_t *img, uint32_t size) +{ + spi_flash_data = img; + spi_flash_size = size; +} + +/* ---------------------------------------------------------------------*/ +/* snapshot support functions */ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 1 +#define SNAP_MODULE_NAME "EN25QH128A" + +int spi_flash_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, eeprom_cs) < 0 + || SMW_B(m, eeprom_clock) < 0 + || SMW_B(m, eeprom_data_in) < 0 + || SMW_B(m, eeprom_data_out) < 0 + || SMW_B(m, input_shiftreg) < 0 + || SMW_B(m, input_count) < 0 + || SMW_B(m, output_shiftreg) < 0 + || SMW_B(m, output_count) < 0 + || SMW_B(m, command) < 0 + || SMW_B(m, addr) < 0 + || SMW_B(m, write_enable_status) < 0 + || SMW_B(m, ready_busy_status) < 0 + || SMW_BA(m, spi_flash_data, MAX_ROM_SIZE) < 0) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int spi_flash_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + /* Do not accept versions higher than current */ + if (snapshot_version_is_bigger(vmajor, vminor, CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (0 + || SMR_B_INT(m, &eeprom_cs) < 0 + || SMR_B_INT(m, &eeprom_clock) < 0 + || SMR_B_INT(m, &eeprom_data_in) < 0 + || SMR_B_INT(m, &eeprom_data_out) < 0 + || SMR_B_INT(m, (int*)&input_shiftreg) < 0 + || SMR_B_INT(m, (int*)&input_count) < 0 + || SMR_B_INT(m, (int*)&output_shiftreg) < 0 + || SMR_B_INT(m, (int*)&output_count) < 0 + || SMR_B_INT(m, (int*)&command) < 0 + || SMR_B_INT(m, (int*)&addr) < 0 + || SMR_B_INT(m, &write_enable_status) < 0 + || SMR_B_INT(m, &ready_busy_status) < 0 + || SMR_BA(m, spi_flash_data, MAX_ROM_SIZE) < 0) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + return 0; +} diff --git a/src/Emulators/vice/core/spi-flash.h b/src/Emulators/vice/core/spi-flash.h new file mode 100644 index 00000000..5c491f6a --- /dev/null +++ b/src/Emulators/vice/core/spi-flash.h @@ -0,0 +1,44 @@ +/* + * spi-flash.h + * + * Written by + * Groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_SPI_FLASH +#define VICE_SPI_FLASH + +#include "vicetypes.h" + +uint8_t spi_flash_read_data(void); +void spi_flash_write_data(uint8_t value); +void spi_flash_write_select(uint8_t value); +void spi_flash_write_clock(uint8_t value); + +void spi_flash_set_image(uint8_t *img, uint32_t size); + +struct snapshot_s; + +int spi_flash_snapshot_read_module(struct snapshot_s *s); +int spi_flash_snapshot_write_module(struct snapshot_s *s); + +#endif diff --git a/src/Emulators/vice/core/spi-sdcard.c b/src/Emulators/vice/core/spi-sdcard.c index de62e186..52978834 100644 --- a/src/Emulators/vice/core/spi-sdcard.c +++ b/src/Emulators/vice/core/spi-sdcard.c @@ -46,7 +46,7 @@ /*#define DEBUG_SPI*/ #ifdef SPIDEBUG -#define LOG(_x_) log_debug _x_ +#define LOG(_x_) log_printf _x_ #else #define LOG(_x_) #endif @@ -84,11 +84,11 @@ typedef signed long SLWORD; #ifdef HAVE_64BIT_TYPES typedef LWORD sd_addr_t; #else -typedef DWORD sd_addr_t; +typedef uint32_t sd_addr_t; #endif -void spi_mmc_trigger_mode_write(BYTE value); -BYTE spi_mmc_trigger_mode_read(void); +void spi_mmc_trigger_mode_write(uint8_t value); +uint8_t spi_mmc_trigger_mode_read(void); static int mmc_card_type = CARD_TYPE_MMC; static int mmc_card_rw = 0; @@ -102,11 +102,11 @@ static sd_addr_t mmc_image_pointer; /* write sequence counter */ static unsigned int mmc_write_sequence; -static BYTE mmc_card_inserted; -static BYTE mmc_card_state; -static BYTE mmc_card_reset_count; +static uint8_t mmc_card_inserted; +static uint8_t mmc_card_state; +static uint8_t mmc_card_reset_count; -static DWORD mmc_block_size; +static uint32_t mmc_block_size; /* Gets set when dummy byte is read */ static unsigned int mmc_read_firstbyte; @@ -130,13 +130,13 @@ static void mmc_clear_cmd_buffer(void) /* MMC SPI data read port buffering */ static int mmc_read_buffer_readptr = 0, mmc_read_buffer_writeptr = 0; -BYTE mmc_read_buffer[0x1000]; /* FIXME */ +uint8_t mmc_read_buffer[0x1000]; /* FIXME */ -static void mmc_read_buffer_set(BYTE * data, int size) +static void mmc_read_buffer_set(uint8_t * data, int size) { /*LOG(("MMC mmc_read_buffer_set %04x:%02x",mmc_read_buffer_writeptr,size));*/ while (size) { - BYTE value; + uint8_t value; value = *data++; mmc_read_buffer[mmc_read_buffer_writeptr] = value; @@ -147,9 +147,9 @@ static void mmc_read_buffer_set(BYTE * data, int size) } } -static BYTE mmc_read_buffer_getbyte(void) +static uint8_t mmc_read_buffer_getbyte(void) { - BYTE value = 0; /* FIXME */ + uint8_t value = 0; /* FIXME */ if (mmc_read_buffer_readptr != mmc_read_buffer_writeptr) { value = mmc_read_buffer[mmc_read_buffer_readptr]; @@ -185,42 +185,42 @@ static void mmc_reset_card(void) /* TODO */ /* 0 = card inserted, 1 = no card inserted (R) */ -BYTE spi_mmc_card_inserted(void) +uint8_t spi_mmc_card_inserted(void) { - BYTE value = mmc_card_inserted; + uint8_t value = mmc_card_inserted; #ifdef TEST_MMC_ALWAYS_NOCARD value = MMC_CARD_NOTINSERTED; #endif return value; } -BYTE spi_mmc_set_card_inserted(BYTE value) +static uint8_t spi_mmc_set_card_inserted(uint8_t value) { - BYTE oldvalue = spi_mmc_card_inserted(); + uint8_t oldvalue = spi_mmc_card_inserted(); mmc_card_inserted = value; return oldvalue; } -BYTE mmc_set_card_type(BYTE value) +uint8_t mmc_set_card_type(uint8_t value) { - BYTE oldvalue = mmc_card_type; + uint8_t oldvalue = mmc_card_type; mmc_card_type = value; return oldvalue; } /* TODO */ /* 0 = SPI ready, 1 = SPI busy */ -BYTE spi_mmc_busy(void) +uint8_t spi_mmc_busy(void) { - BYTE value = 0; + uint8_t value = 0; return value; } /* TODO */ /* 0 = card write enabled, 1 = card write disabled (R) */ -BYTE spi_mmc_card_write_enabled(void) +uint8_t spi_mmc_card_write_enabled(void) { - BYTE value = mmc_card_rw; + uint8_t value = mmc_card_rw; #ifdef TEST_MMC_ALWAYS_READONLY value = 1; #endif @@ -230,41 +230,42 @@ BYTE spi_mmc_card_write_enabled(void) /* TODO */ static int spi_mmc_card_selected = 0; -BYTE spi_mmc_card_selected_read(void) +uint8_t spi_mmc_card_selected_read(void) { /*LOG(("MMC spi_mmc_card_selected_read %02x",spi_mmc_card_selected));*/ return spi_mmc_card_selected; } /* TODO */ -void spi_mmc_card_selected_write(BYTE value) +void spi_mmc_card_selected_write(uint8_t value) { spi_mmc_card_selected = value; /*LOG(("MMC spi_mmc_card_selected_write %02x",spi_mmc_card_selected));*/ } /* TODO */ -BYTE spi_mmc_enable_8mhz_read(void) +uint8_t spi_mmc_enable_8mhz_read(void) { - BYTE value = 0; + uint8_t value = 0; + return value; } /* TODO */ -void spi_mmc_enable_8mhz_write(BYTE value) +void spi_mmc_enable_8mhz_write(uint8_t value) { } /* 0 = SPI write trigger mode, 1 = SPI read trigger mode */ -static BYTE spi_mmc_trigger_mode = 0; +static uint8_t spi_mmc_trigger_mode = 0; /* TODO */ -BYTE spi_mmc_trigger_mode_read(void) +uint8_t spi_mmc_trigger_mode_read(void) { return spi_mmc_trigger_mode; } /* TODO */ -void spi_mmc_trigger_mode_write(BYTE value) +void spi_mmc_trigger_mode_write(uint8_t value) { spi_mmc_trigger_mode = value; } @@ -272,7 +273,7 @@ void spi_mmc_trigger_mode_write(BYTE value) /* TODO */ /* FIXME: wrap strcpy/strcat into macros so they are removed when not debugging */ -BYTE spi_mmc_data_read(void) +uint8_t spi_mmc_data_read(void) { #ifdef DEBUG_SPI char logstr[0x100]; @@ -436,7 +437,7 @@ BYTE spi_mmc_data_read(void) if (!spi_mmc_card_inserted() && mmc_card_state != MMC_CARD_DUMMY_READ) { - BYTE val; + uint8_t val; val = mmc_read_buffer_getbyte(); #ifdef DEBUG_SPI LOG(("%s %08x of %04x:", logstr, @@ -533,36 +534,36 @@ static void mmc_execute_cmd(void) switch (mmc_cmd_buffer[1]) { case 0xff: #ifdef DEBUG_MMC - log_debug("Hard reset received"); + log_debug(LOG_DEFAULT, "Hard reset received"); #endif mmc_card_state = MMC_CARD_IDLE; break; case 0x40: /* CMD00 Reset */ #ifdef DEBUG_MMC - log_debug("CMD00 Reset received"); + log_debug(LOG_DEFAULT, "CMD00 Reset received"); #endif mmc_reset_card(); mmc_card_state = MMC_CARD_RESET; break; case 0x41: /* CMD01 Init */ #ifdef DEBUG_MMC - log_debug("CMD01 Init received"); + log_debug(LOG_DEFAULT, "CMD01 Init received"); #endif mmc_card_state = MMC_CARD_INIT; break; case 0x48: /* CMD8 ? */ #ifdef DEBUG_MMC - log_debug("CMD8 ? received"); + log_debug(LOG_DEFAULT, "CMD8 ? received"); #endif if (mmc_card_type == CARD_TYPE_MMC) { /* MMC */ - BYTE cmdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; mmc_read_buffer_set(cmdresp, 0x200); } else { /* SD v2 */ - BYTE cmdresp[0x10] = { 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 1; mmc_read_buffer_set(cmdresp, 0x200); @@ -570,10 +571,10 @@ static void mmc_execute_cmd(void) break; case 0x49: /* CMD9 send CSD */ #ifdef DEBUG_MMC - log_debug("CMD9 send CSD received"); + log_debug(LOG_DEFAULT, "CMD9 send CSD received"); #endif if (!spi_mmc_card_inserted()) { - BYTE csdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t csdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; mmc_read_buffer_set(csdresp, 0x200); @@ -584,10 +585,10 @@ static void mmc_execute_cmd(void) break; case 0x4a: /* CMD9 send CID */ #ifdef DEBUG_MMC - log_debug("CMD10 send CID received"); + log_debug(LOG_DEFAULT, "CMD10 send CID received"); #endif if (!spi_mmc_card_inserted()) { - BYTE cidresp[0x10] = + uint8_t cidresp[0x10] = { 0, 0, 0, 0, 1+'v'-'a', 1+'i'-'a', 1+'c'-'a', 1+'e'-'a', '2', '3', /* "viceemu" */ 0, 0, 0, 0, 0 }; @@ -604,13 +605,13 @@ static void mmc_execute_cmd(void) break; case 0x4c: /* CMD12 Stop */ #ifdef DEBUG_MMC - log_debug("CMD12 Stop received"); + log_debug(LOG_DEFAULT, "CMD12 Stop received"); #endif mmc_card_state = MMC_CARD_IDLE; break; case 0x50: /* CMD16 Set Block Size */ #ifdef DEBUG_MMC - log_debug("CMD16-AAAA Set Block Size received"); + log_debug(LOG_DEFAULT, "CMD16-AAAA Set Block Size received"); #endif mmc_card_state = MMC_CARD_IDLE; mmc_block_size = @@ -621,7 +622,7 @@ static void mmc_execute_cmd(void) break; case 0x51: #ifdef DEBUG_MMC - log_debug("CMD17-AAAA Block Read received"); + log_debug(LOG_DEFAULT, "CMD17-AAAA Block Read received"); #endif if (!spi_mmc_card_inserted()) { mmc_card_state = MMC_CARD_READ; @@ -630,19 +631,19 @@ static void mmc_execute_cmd(void) mmc_current_address_pointer = mmc_get_addr(&status); if (status) { #ifdef DEBUG_MMC - log_debug("Address Overflow: %08x", mmc_current_address_pointer); + log_debug(LOG_DEFAULT, "Address Overflow: %08x", mmc_current_address_pointer); #endif mmc_card_state = MMC_CARD_DUMMY_READ; } else { #ifdef DEBUG_MMC - log_debug("Address: %08x", mmc_current_address_pointer); + log_debug(LOG_DEFAULT, "Address: %08x", mmc_current_address_pointer); #endif if (fseek(mmc_image_file, mmc_current_address_pointer, SEEK_SET) != 0) { mmc_card_state = MMC_CARD_DUMMY_READ; } else { - BYTE readbuf[0x1000]; /* FIXME */ + uint8_t readbuf[0x1000]; /* FIXME */ #ifdef DEBUG_MMC - log_debug("Buffering: %08x", mmc_current_address_pointer); + log_debug(LOG_DEFAULT, "Buffering: %08x", mmc_current_address_pointer); #endif fseek(mmc_image_file, mmc_current_address_pointer, SEEK_SET); if (!feof(mmc_image_file)) { @@ -651,7 +652,7 @@ static void mmc_execute_cmd(void) mmc_read_buffer_writeptr = 0; mmc_read_buffer_set(readbuf, mmc_block_size); #ifdef DEBUG_MMC - log_debug("Buffered: %02x %02x", readbuf[0], readbuf[1]); + log_debug(LOG_DEFAULT, "Buffered: %02x %02x", readbuf[0], readbuf[1]); #endif } else { /* FIXME: handle error */ @@ -665,7 +666,7 @@ static void mmc_execute_cmd(void) } break; case 0x58: -/*log_debug("CMD Block Write received");*/ +/*log_debug(LOG_DEFAULT, "CMD Block Write received");*/ if (!spi_mmc_card_inserted() && mmc_block_size > 0) { #ifdef DEBUG_MMC LOG(("MMC CMD Block Write Address: %08x", @@ -676,7 +677,7 @@ static void mmc_execute_cmd(void) mmc_write_sequence = 0; mmc_card_state = MMC_CARD_DUMMY_WRITE; #ifdef DEBUG_MMC - log_debug("Address Overflow: %08x", mmc_current_address_pointer); + log_debug(LOG_DEFAULT, "Address Overflow: %08x", mmc_current_address_pointer); #endif } else { mmc_write_sequence = 0; @@ -689,9 +690,9 @@ static void mmc_execute_cmd(void) break; case 0x69: /* ACMD41 ? */ { - BYTE cmdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #ifdef DEBUG_MMC - log_debug("ACMD41 ? received"); + log_debug(LOG_DEFAULT, "ACMD41 ? received"); #endif mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; @@ -700,11 +701,11 @@ static void mmc_execute_cmd(void) break; case 0x77: /* CMD77 ? */ #ifdef DEBUG_MMC - log_debug("CMD77 ? received"); + log_debug(LOG_DEFAULT, "CMD77 ? received"); #endif if (mmc_card_type != CARD_TYPE_MMC) { /* SD v2 only */ - BYTE cmdresp[0x10] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; mmc_read_buffer_set(cmdresp, 0x200); @@ -712,17 +713,17 @@ static void mmc_execute_cmd(void) break; case 0x7a: /* CMD58 ? */ #ifdef DEBUG_MMC - log_debug("CMD58 ? received"); + log_debug(LOG_DEFAULT, "CMD58 ? received"); #endif if (mmc_card_type == CARD_TYPE_SDHC) { /* SDHC */ - BYTE cmdresp[0x10] = { 0, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 0, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; mmc_read_buffer_set(cmdresp, 0x200); } else { /* SD */ - BYTE cmdresp[0x10] = { 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t cmdresp[0x10] = { 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; mmc_card_state = MMC_CARD_READ; mmc_read_firstbyte = 0; mmc_read_buffer_set(cmdresp, 0x200); @@ -790,7 +791,7 @@ static void mmc_write_to_cmd_buffer(unsigned char mmcreplay_cmd_char) } } -static void mmc_write_to_mmc(BYTE value) +static void mmc_write_to_mmc(uint8_t value) { switch (mmc_write_sequence) { case 0: @@ -821,7 +822,7 @@ static void mmc_write_to_mmc(BYTE value) } /* TODO */ -void spi_mmc_data_write(BYTE value) +void spi_mmc_data_write(uint8_t value) { if (mmc_card_state == MMC_CARD_WRITE || mmc_card_state == MMC_CARD_DUMMY_WRITE) { @@ -895,8 +896,6 @@ void mmc_close_card_image(void) /* FIXME: implement snapshot support */ int mmc_snapshot_write_module(snapshot_t *s) { - return -1; -#if 0 snapshot_module_t *m; m = snapshot_module_create(s, SNAP_MODULE_NAME, @@ -904,6 +903,9 @@ int mmc_snapshot_write_module(snapshot_t *s) if (m == NULL) { return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); @@ -919,7 +921,7 @@ int mmc_snapshot_read_module(snapshot_t *s) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/core/spi-sdcard.h b/src/Emulators/vice/core/spi-sdcard.h index f00f1d8d..ece6cf57 100644 --- a/src/Emulators/vice/core/spi-sdcard.h +++ b/src/Emulators/vice/core/spi-sdcard.h @@ -32,25 +32,26 @@ #include "vicetypes.h" -extern void spi_mmc_trigger_mode_write(BYTE value); -extern BYTE spi_mmc_trigger_mode_read(void); -extern BYTE spi_mmc_card_inserted(void); -extern BYTE spi_mmc_busy(void); -extern BYTE spi_mmc_card_write_enabled(void); -extern BYTE spi_mmc_card_selected_read(void); -extern void spi_mmc_card_selected_write(BYTE value); -extern BYTE spi_mmc_enable_8mhz_read(void); -extern void spi_mmc_enable_8mhz_write(BYTE value); -extern BYTE spi_mmc_trigger_mode_read(void); -extern void spi_mmc_trigger_mode_write(BYTE value); -extern BYTE spi_mmc_data_read(void); -extern void spi_mmc_data_write(BYTE value); -extern int mmc_open_card_image(char *name, int rw); -extern void mmc_close_card_image(void); -extern BYTE mmc_set_card_type(BYTE value); +void spi_mmc_trigger_mode_write(uint8_t value); +uint8_t spi_mmc_trigger_mode_read(void); +uint8_t spi_mmc_card_inserted(void); +uint8_t spi_mmc_busy(void); +uint8_t spi_mmc_card_write_enabled(void); +uint8_t spi_mmc_card_selected_read(void); +void spi_mmc_card_selected_write(uint8_t value); +uint8_t spi_mmc_enable_8mhz_read(void); +void spi_mmc_enable_8mhz_write(uint8_t value); +uint8_t spi_mmc_trigger_mode_read(void); +void spi_mmc_trigger_mode_write(uint8_t value); +uint8_t spi_mmc_data_read(void); +void spi_mmc_data_write(uint8_t value); +int mmc_open_card_image(char *name, int rw); +void mmc_close_card_image(void); +uint8_t mmc_set_card_type(uint8_t value); struct snapshot_s; -extern int mmc_snapshot_read_module(struct snapshot_s *s); -extern int mmc_snapshot_write_module(struct snapshot_s *s); + +int mmc_snapshot_read_module(struct snapshot_s *s); +int mmc_snapshot_write_module(struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/core/t6721.c b/src/Emulators/vice/core/t6721.c index fcce214d..5dcf73d2 100644 --- a/src/Emulators/vice/core/t6721.c +++ b/src/Emulators/vice/core/t6721.c @@ -49,13 +49,10 @@ */ -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif /* #define T6721DEBUG */ -#define WRITEWAVFILE 0 /* write "test.wav" containing all generated output */ +#define WRITEWAVFILE 1 /* write "test.wav" containing all generated output */ #ifdef T6721DEBUG #define DBG(x) DBG_STATUS(); printf x; @@ -71,7 +68,7 @@ #define PARCOR_OUTPUT_HZ (8000) #define PARCOR_BUFFER_LEN (0x400) -SWORD ringbuffer[PARCOR_BUFFER_LEN]; /* FIXME */ +int16_t ringbuffer[PARCOR_BUFFER_LEN]; /* FIXME */ int ringbuffer_rptr = 0; int ringbuffer_wptr = 0; int phrase_sample_len = 0; @@ -85,18 +82,18 @@ float upsmpcnt = 0; float upsmp = 0; struct param_s { - BYTE energy; - BYTE pitch; - SWORD k[10]; + uint8_t energy; + uint8_t pitch; + int16_t k[10]; }; typedef struct param_s param_t; -static param_t p_from = { 0, 0x21 }; -static param_t p_to = { 0, 0x21 }; +static param_t p_from = { 0, 0x21, { 0 } }; +static param_t p_to = { 0, 0x21, { 0 } }; static double p_z[11] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; /* FIXME: MOVE parcor parameters: energy + pitch + k1..10 */ -static WORD parcor_param[1 + 1 + 10]; +static uint16_t parcor_param[1 + 1 + 10]; /* words that use 48bits/frame: @@ -144,7 +141,7 @@ static const int parcor_param_len[2][1 + 1 + 10] = { */ { 7, 7, 10, 10, 10, 8, 8, 8, 7, 7, 7, 7 } }; -static WORD chip_buf = 0; +static uint16_t chip_buf = 0; static int chip_bit_i = 0; static int param_i = 0; @@ -165,7 +162,7 @@ static void set_playing(t6721_state *t6721, int playing); static FILE *wav_fp = NULL; static size_t wavsize = 0; -static const BYTE wav_header[] = { +static const uint8_t wav_header[] = { 'R', 'I', 'F', 'F', 0, 0, 0, 0, /* filesize - 8 */ 'W', 'A', 'V', 'E', @@ -194,7 +191,7 @@ static int write_header(void) static int fix_header(void) { size_t temp; - BYTE b[4] = { 0, 0, 0, 0 }; + uint8_t b[4] = { 0, 0, 0, 0 }; fseek(wav_fp, 4, SEEK_SET); @@ -246,19 +243,18 @@ static int wav_create_file(const char *filename) } atexit(wav_close_file); - return write_header(); } -static int wav_write_sample(SWORD data) +static int wav_write_sample(int16_t data) { - BYTE d; + uint8_t d; if (wav_fp == NULL) { wav_create_file("test.wav"); } - d = (BYTE)(data & 0xff); + d = (uint8_t)(data & 0xff); if (fwrite(&d, 1, 1, wav_fp) < 1) { return 1; @@ -266,7 +262,7 @@ static int wav_write_sample(SWORD data) wavsize++; - d = (BYTE)((data >> 8) & 0xff); + d = (uint8_t)((data >> 8) & 0xff); if (fwrite(&d, 1, 1, wav_fp) < 1) { return 1; @@ -294,7 +290,7 @@ static void ringbuffer_reset(void) write one 8000khz sample to the output ringbuffer returns 1 on error, 0 on success */ -static int parcor_output_sample(t6721_state *t6721, SWORD value) +static int parcor_output_sample(t6721_state *t6721, int16_t value) { int next_wptr; @@ -318,13 +314,14 @@ static int parcor_output_sample(t6721_state *t6721, SWORD value) /* render one output sample */ -SWORD output_update_sample(t6721_state *t6721) +#ifdef SOUND_SYSTEM_FLOAT +static float output_update_sample(t6721_state *t6721) { static float from, to; int next_rptr; - SWORD this; + float this; - this = (SWORD) ((from * (1.0f - upsmpcnt)) + (to * upsmpcnt)); + this = ((from * (1.0f - upsmpcnt)) + (to * upsmpcnt)) / 32767.0; upsmpcnt += (1.0f / upsmp); if (upsmpcnt >= 1.0f) { @@ -353,8 +350,45 @@ SWORD output_update_sample(t6721_state *t6721) return this; } +#else +static int16_t output_update_sample(t6721_state *t6721) +{ + static float from, to; + int next_rptr; + int16_t this; -static int framestretch[0x10] = + this = (int16_t)((from * (1.0f - upsmpcnt)) + (to * upsmpcnt)); + + upsmpcnt += (1.0f / upsmp); + if (upsmpcnt >= 1.0f) { + upsmpcnt -= 1.0f; + from = to; + if (ringbuffer_state == RBSTATE_STOP) { + if (phrase_sample_len > RBSTATE_DELAY_SAMPLES) { + ringbuffer_state = RBSTATE_PLAY; + } + } else { + if (phrase_sample_len > 0) { + next_rptr = ringbuffer_rptr + 1; + if (next_rptr == PARCOR_BUFFER_LEN) { + next_rptr = 0; + } + if (next_rptr != ringbuffer_wptr) { + ringbuffer_rptr = next_rptr; + phrase_sample_len--; + } + } else { + ringbuffer_state = RBSTATE_STOP; + } + } + to = (float) ringbuffer[ringbuffer_rptr]; + } + + return this; +} +#endif + +static const int framestretch[0x10] = { 100, /* 0 : 1,0 */ 70, /* 1 : 0,7 (1.4% faster) */ @@ -405,14 +439,14 @@ static int render_subframe(t6721_state *t6721, int sub_i, int voiced) static double phase = 0.0; double energy = ((p_from.energy * (8 - sub_i)) + (p_to.energy * sub_i)) / (8.0 * 127.0); - BYTE pitch; + uint8_t pitch; double phase_inc; double k[10]; double sample, data; - SWORD output; + int16_t output; if (voiced) { pitch = ((p_from.pitch * (8 - sub_i)) + (p_to.pitch * sub_i)) / 8; @@ -452,7 +486,7 @@ static int render_subframe(t6721_state *t6721, int sub_i, int voiced) } /* scale to 16bit */ - output = (SWORD)(data * (8192.0f + 2048.0f)); + output = (int16_t)(data * (8192.0f + 2048.0f)); if (parcor_output_sample(t6721, output)) { return 1; @@ -479,17 +513,17 @@ static int render_silence(t6721_state *t6721) render one PARCOR frame returns 1 on error, 0 on success ------------------------------------------------------------------------- */ -static int parcor_render_frame(t6721_state *t6721, WORD *new_param) +static int parcor_render_frame(t6721_state *t6721, uint16_t *new_param) { int i, voiced, silent; - BYTE new_pitch; + uint8_t new_pitch; - new_pitch = (BYTE)PARMVALUE(t6721, 1); + new_pitch = (uint8_t)PARMVALUE(t6721, 1); voiced = (new_pitch > 0); memcpy(&p_from, &p_to, sizeof(p_from)); - p_to.energy = (BYTE)PARMVALUE(t6721, 0); + p_to.energy = (uint8_t)PARMVALUE(t6721, 0); silent = ((new_pitch == 0x7e) && (p_to.energy == 1)); if (!voiced && !silent) { @@ -500,7 +534,7 @@ static int parcor_render_frame(t6721_state *t6721, WORD *new_param) if (!silent) { for (i = 0; i < (voiced ? (12 - 2) : (6 - 2)); ++i) { - p_to.k[i] = (SWORD)(new_param[i + 2]); + p_to.k[i] = (int16_t)(new_param[i + 2]); } for (i = 0; i < 8; ++i) { @@ -776,7 +810,30 @@ void t6721_update_ticks(t6721_state *t6721, int ticks) float up2smp = 0; /* render num samples into output buffer, run remaining cycles (if any) */ -void t6721_update_output(t6721_state *t6721, SWORD *buf, int num) +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +void t6721_update_output(t6721_state *t6721, float *buf, int num) +{ + int i; + int cycles; + + cycles = (int)((num * up2smp) - t6721->cycles_done); + if (cycles > 0) { + /* run chip for remaining cycles */ + t6721_update_ticks(t6721, cycles); + t6721->cycles_done = 0; + } else { + /* carry over remaining cycles to next sound frame */ + t6721->cycles_done = 0 - cycles; + } + + /* render output samples */ + for (i = 0; i < num; i++) { + *buf++ = output_update_sample(t6721); + } +} +#else +void t6721_update_output(t6721_state *t6721, int16_t *buf, int num) { int i; int cycles; @@ -796,6 +853,7 @@ void t6721_update_output(t6721_state *t6721, SWORD *buf, int num) *buf++ = output_update_sample(t6721); } } +#endif /***************************************************************************** Chip Command Handling @@ -804,7 +862,7 @@ void t6721_update_output(t6721_state *t6721, SWORD *buf, int num) /* when the WR pin goes high, d0..d3 from data are read by ("written to") the chip */ -void t6721_store(t6721_state *t6721, BYTE data) +void t6721_store(t6721_state *t6721, uint8_t data) { /* DBG(("write %2x\n", data)); */ /* an actual store is performed on Lo->HI transition of WR */ @@ -941,7 +999,7 @@ void t6721_store(t6721_state *t6721, BYTE data) t6721->wr_last = t6721->wr; } -BYTE t6721_read(t6721_state *t6721) +uint8_t t6721_read(t6721_state *t6721) { int data; @@ -1017,16 +1075,16 @@ int t6721_dump(t6721_state *t6721) /* FIXME: implement snapshot support */ int t6721_snapshot_write_module(snapshot_t *s, t6721_state *t6721) { - return -1; -#if 0 snapshot_module_t *m; - m = snapshot_module_create(s, SNAP_MODULE_NAME, - CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + m = snapshot_module_create(s, SNAP_MODULE_NAME, CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); if (m == NULL) { return -1; } + snapshot_set_error(SNAPSHOT_MODULE_NOT_IMPLEMENTED); + return -1; +#if 0 if (0) { snapshot_module_close(m); return -1; @@ -1041,7 +1099,7 @@ int t6721_snapshot_read_module(snapshot_t *s, t6721_state *t6721) { return -1; #if 0 - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); diff --git a/src/Emulators/vice/core/t6721.h b/src/Emulators/vice/core/t6721.h index 673e5aef..6e3c435e 100644 --- a/src/Emulators/vice/core/t6721.h +++ b/src/Emulators/vice/core/t6721.h @@ -155,28 +155,36 @@ typedef struct _t6721_state { int cycles_done; /* number of cycles the chip has run since last update_output */ - BYTE (*read_data)(struct _t6721_state*, unsigned int *bit); /* input: DI */ + uint8_t (*read_data)(struct _t6721_state*, unsigned int *bit); /* input: DI */ void (*set_apd)(struct _t6721_state*); void (*set_eos)(struct _t6721_state*); void (*set_dtrd)(struct _t6721_state*); } t6721_state; -extern void t6721_reset(t6721_state *t6721); -extern void t6721_sound_machine_init(t6721_state *t6721, int samples_per_sec, int cycles_per_sec); -extern void t6721_sound_machine_init_vbr(t6721_state *t6721, int speed, int cycles_per_sec, int factor); +void t6721_reset(t6721_state *t6721); +void t6721_sound_machine_init(t6721_state *t6721, int samples_per_sec, int cycles_per_sec); +void t6721_sound_machine_init_vbr(t6721_state *t6721, int speed, int cycles_per_sec, int factor); + /* read/write from/to d0..d3 */ -extern BYTE t6721_read(t6721_state *t6721); /* read from d0..d3 (status) */ -extern void t6721_store(t6721_state *t6721, BYTE data); /* store to d0..d3 (command) */ +uint8_t t6721_read(t6721_state *t6721); /* read from d0..d3 (status) */ +void t6721_store(t6721_state *t6721, uint8_t data); /* store to d0..d3 (command) */ + /* run chip for N cpu/system cycles */ -extern void t6721_update_tick(t6721_state *t6721); -extern void t6721_update_ticks(t6721_state *t6721, int ticks); +void t6721_update_tick(t6721_state *t6721); +void t6721_update_ticks(t6721_state *t6721, int ticks); + /* update output sound buffer, run chip (remaining ticks) */ -extern void t6721_update_output(t6721_state *t6721, SWORD *buf, int num); +#ifdef SOUND_SYSTEM_FLOAT +void t6721_update_output(t6721_state *t6721, float *buf, int num); +#else +void t6721_update_output(t6721_state *t6721, int16_t *buf, int num); +#endif -extern int t6721_dump(t6721_state *t6721); +int t6721_dump(t6721_state *t6721); struct snapshot_s; -extern int t6721_snapshot_read_module(struct snapshot_s *s, t6721_state *t6721); -extern int t6721_snapshot_write_module(struct snapshot_s *s, t6721_state *t6721); + +int t6721_snapshot_read_module(struct snapshot_s *s, t6721_state *t6721); +int t6721_snapshot_write_module(struct snapshot_s *s, t6721_state *t6721); #endif diff --git a/src/Emulators/vice/core/tpicore.c b/src/Emulators/vice/core/tpicore.c index af0505b1..82f62de3 100644 --- a/src/Emulators/vice/core/tpicore.c +++ b/src/Emulators/vice/core/tpicore.c @@ -51,7 +51,7 @@ #define IS_CB_TOGGLE_MODE() ((tpi_context->c_tpi[TPI_CREG] & 0xc0) == 0x00) -static const BYTE pow2[] = { 1, 2, 4, 8, 16 }; +static const uint8_t pow2[] = { 1, 2, 4, 8, 16 }; static int mytpi_debug = 0; @@ -62,7 +62,7 @@ static void set_latch_bit(tpi_context_t *tpi_context, int bit) { if (mytpi_debug && !(bit & irq_latches)) { log_message(tpi_context->log, "set_latch_bit(%02x, mask=%02x)", - bit, irq_mask); + (unsigned int)bit, irq_mask); } irq_latches |= bit; @@ -93,8 +93,7 @@ static void pop_irq_state(tpi_context_t *tpi_context) if (mytpi_debug) { log_message(tpi_context->log, "pop_irq_state(latches=%02x, stack=%02x, active=%02x)", - (int)irq_latches, (int)(tpi_context->irq_stack), - (int)irq_active); + irq_latches, tpi_context->irq_stack, irq_active); } if (irq_priority) { if (tpi_context->irq_stack) { @@ -111,7 +110,7 @@ static void pop_irq_state(tpi_context_t *tpi_context) ? tpi_context->irq_line : 0); } -static BYTE push_irq_state(tpi_context_t *tpi_context) +static uint8_t push_irq_state(tpi_context_t *tpi_context) { int old_active; @@ -120,8 +119,7 @@ static BYTE push_irq_state(tpi_context_t *tpi_context) if (mytpi_debug) { log_message(tpi_context->log, "push_irq_state(latches=%02x, act=%02x, stack=%02x mask=%02x).", - (int)irq_latches, (int)irq_active, - (int)(tpi_context->irq_stack), (int)irq_mask); + irq_latches, irq_active, tpi_context->irq_stack, irq_mask); } irq_latches &= ~irq_active; @@ -166,7 +164,7 @@ void tpicore_reset(tpi_context_t *tpi_context) (tpi_context->reset)(tpi_context); } -void tpicore_store(tpi_context_t *tpi_context, WORD addr, BYTE byte) +void tpicore_store(tpi_context_t *tpi_context, uint16_t addr, uint8_t byte) { if (tpi_context->rmw_flag) { (*(tpi_context->clk_ptr))--; @@ -252,9 +250,9 @@ void tpicore_store(tpi_context_t *tpi_context, WORD addr, BYTE byte) tpi_context->c_tpi[addr] = byte; } -BYTE tpicore_read(tpi_context_t *tpi_context, WORD addr) +uint8_t tpicore_read(tpi_context_t *tpi_context, uint16_t addr) { - BYTE byte = 0xff; + uint8_t byte = 0xff; addr &= 0x07; @@ -293,9 +291,9 @@ BYTE tpicore_read(tpi_context_t *tpi_context, WORD addr) } /* FIXME: peek into register without any side effect */ -BYTE tpicore_peek(tpi_context_t *tpi_context, WORD addr) +uint8_t tpicore_peek(tpi_context_t *tpi_context, uint16_t addr) { - BYTE byte = 0xff; + uint8_t byte = 0xff; addr &= 0x07; switch (addr) { @@ -441,7 +439,7 @@ int tpicore_snapshot_write_module(tpi_context_t *tpi_context, snapshot_t *p) || SMW_B(m, tpi_context->c_tpi[TPI_CREG]) < 0 || SMW_B(m, tpi_context->c_tpi[TPI_AIR]) < 0 || SMW_B(m, tpi_context->irq_stack) < 0 - || SMW_B(m, (BYTE)((tpi_context->ca_state ? 0x80 : 0) | (tpi_context->cb_state ? 0x40 : 0))) < 0) { + || SMW_B(m, (uint8_t)((tpi_context->ca_state ? 0x80 : 0) | (tpi_context->cb_state ? 0x40 : 0))) < 0) { snapshot_module_close(m); return -1; } @@ -451,8 +449,8 @@ int tpicore_snapshot_write_module(tpi_context_t *tpi_context, snapshot_t *p) int tpicore_snapshot_read_module(tpi_context_t *tpi_context, snapshot_t *p) { - BYTE vmajor, vminor; - BYTE byte; + uint8_t vmajor, vminor; + uint8_t byte; snapshot_module_t *m; (tpi_context->restore_int)(tpi_context->tpi_int_num, 0); /* just in case */ @@ -463,7 +461,7 @@ int tpicore_snapshot_read_module(tpi_context_t *tpi_context, snapshot_t *p) } /* Do not accept versions higher than current */ - if (vmajor > TPI_DUMP_VER_MAJOR || vminor > TPI_DUMP_VER_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, TPI_DUMP_VER_MAJOR, TPI_DUMP_VER_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; @@ -528,7 +526,7 @@ int tpicore_dump(tpi_context_t *tpi_context) mon_out("Port B: %02x\n", tpi_context->c_tpi[TPI_PB]); mon_out("Port Direction A: %02x\n", tpi_context->c_tpi[TPI_DDPA]); mon_out("Port Direction B: %02x\n", tpi_context->c_tpi[TPI_DDPB]); - mon_out("Interrupt latch: %02x\n", irq_latches & 0x1f); + mon_out("Interrupt latch: %02x\n", irq_latches & 0x1fU); mon_out("Interrupt active: %s\n", irq_active ? "yes" : "no"); mon_out("Active Interrupt: %02x\n", tpi_context->c_tpi[TPI_AIR]); } else { diff --git a/src/Emulators/vice/core/viacore.c b/src/Emulators/vice/core/viacore.c index f5f75cf0..4aa55848 100644 --- a/src/Emulators/vice/core/viacore.c +++ b/src/Emulators/vice/core/viacore.c @@ -4,6 +4,7 @@ * Written by * Andre Fachat * Andreas Boose + * Olaf Seibert * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -29,9 +30,9 @@ #include #include +#include #include "alarm.h" -#include "clkguard.h" #include "interrupt.h" #include "lib.h" #include "log.h" @@ -39,6 +40,7 @@ #include "snapshot.h" #include "vicetypes.h" #include "via.h" +#include "vice_debugger_hook.h" #undef byte @@ -54,31 +56,50 @@ * * A new function for signaling rising/falling edges on the * control lines is introduced: - * myvia_signal(VIA_SIG_[CA1|CA2|CB1|CB2], VIA_SIG_[RISE|FALL]) + * viacore_signal(VIA_SIG_[CA1|CA2|CB1|CB2], VIA_SIG_[RISE|FALL]) * which signals the corresponding edge to the VIA. The constants * are defined in via.h. * - * Except for shift register and input latching everything should be ok now. + * Except for shift register affecting CB1/CB2 (and associated IFR bits), + * T2 counting PB6 pulses, and input latching everything should be ok now. + * T1 affecting PB7 doesn't seem to work (properly), though. */ /* Timer debugging */ /*#define MYVIA_TIMER_DEBUG */ -/* when PB7 is really used, set this - to enable pulse output from the timer. - Otherwise PB7 state is computed only - when port B is read - - not yet implemented */ -#define MYVIA_NEED_PB7 /* When you really need latching, define this. - It implies additional READ_PR* when - writing the snapshot. When latching is - enabled: it reads the port when enabling, + When latching is enabled: + it reads the port when enabling, and when an active C*1 transition occurs. + Both conditions must be true at the same time! It does not read the port when reading the port register. Side-effects beware! */ /* FIXME: this doesnt even work anymore */ /* #define MYVIA_NEED_LATCHING */ +/* + * Add consistency checks to verify that CPU access for clock N + * occurs before the alarm for clock N. + */ +#define CHECK_CPU_VS_ALARM_CLOCKS 0 +#define VIADEBUG 0 + +#if VIADEBUG > 0 +# define VIALOG(...) fprintf(stderr, __VA_ARGS__) +#else +# define VIALOG(...) +#endif +#if VIADEBUG > 1 +# define VIALOG2(...) fprintf(stderr, __VA_ARGS__) +#else +# define VIALOG2(...) +#endif +#if VIADEBUG > 8 +# define VIALOG9(...) fprintf(stderr, __VA_ARGS__) +#else +# define VIALOG9(...) +#endif + /* * local functions */ @@ -86,23 +107,35 @@ #define IS_CA2_OUTPUT() ((via_context->via[VIA_PCR] & 0x0c) == 0x0c) #define IS_CA2_INDINPUT() ((via_context->via[VIA_PCR] & 0x0a) == 0x02) #define IS_CA2_HANDSHAKE() ((via_context->via[VIA_PCR] & 0x0c) == 0x08) -#define IS_CA2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0x0e) == 0x09) +#define IS_CA2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0x0e) == 0x0A) #define IS_CA2_TOGGLE_MODE() ((via_context->via[VIA_PCR] & 0x0e) == 0x08) #define IS_CB2_OUTPUT() ((via_context->via[VIA_PCR] & 0xc0) == 0xc0) #define IS_CB2_INDINPUT() ((via_context->via[VIA_PCR] & 0xa0) == 0x20) #define IS_CB2_HANDSHAKE() ((via_context->via[VIA_PCR] & 0xc0) == 0x80) -#define IS_CB2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0xe0) == 0x90) +#define IS_CB2_PULSE_MODE() ((via_context->via[VIA_PCR] & 0xe0) == 0xA0) #define IS_CB2_TOGGLE_MODE() ((via_context->via[VIA_PCR] & 0xe0) == 0x80) #define IS_PA_INPUT_LATCH() (via_context->via[VIA_ACR] & 0x01) #define IS_PB_INPUT_LATCH() (via_context->via[VIA_ACR] & 0x02) +#define IS_SR_SHIFTING_OUT() (((via_context->via[VIA_ACR]) & 0x10)) +#define IS_SR_SHIFT_OUT_BY_T2() (((via_context->via[VIA_ACR]) & 0x1c) == 0x14) +#define IS_SR_FREE_RUNNING() (((via_context->via[VIA_ACR]) & 0x1c) == 0x10) + +#define IS_SR_SHIFT_IN_BY_EXT(byte) (((byte) & 0x1c) == 0x0C) +#define IS_SR_T2_CONTROLLED(byte) ((((byte) & 0x0c) == 0x04) || (((byte) & 0x1c) == 0x10)) /* SR modes 0x04, 0x14, 0x10 */ +#define IS_T2_PULSE_COUNTING(byte) (((byte) & VIA_ACR_T2_CONTROL) == VIA_ACR_T2_COUNTPB6) +#define IS_T2_TIMER(byte) (((byte) & VIA_ACR_T2_CONTROL) == VIA_ACR_T2_TIMER) + /* * 01apr98 a.fachat * * One-shot Timing (partly from 6522-VIA.txt): + +---- memory access for clock N + |/--- alarm call for clock N + vv +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ 02 --+ +-+ +-+ +-+ +-+ +-+ +-#-+ +-+ +-+ +-+ +-+ +-+ +- | | | @@ -120,10 +153,10 @@ |<---- N + 1.5 CYCLES ----->|<--- N + 2 cycles ---> +---+ myviat*u* clk ------------------------------------------+ +-------- - | - | - call of - int_myvia* + ^ + | + call of + viacore_t2_zero_alarm here real myviatau value = myviatau* + TAUOFFSET @@ -136,12 +169,32 @@ * PB7 output is still to be implemented */ -/* timer values do not depend on a certain value here, but PB7 does... */ -#define TAUOFFSET (-1) - +/* + * Timing as can be observed by the CPU. + * Alarms for rclock N run after CPU accesses for rclock N. + +rclk 1 2 3 4 5 6 7 8 9 10 11 12 + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +T2 1207 1206 1205 1204 1203 1202 1201 1200 11FF 1107 1106 1105 +SR 80... 01... + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +CB1 1... 0... +CB2 0... 1... +IFR 0..+SR? +T2 +SR? + +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ + ^ ^ ^ + t2_zero_alarm ---+ | | + t2_underflow_alarm ----+ | + t2_shift_alarm --------------+ + */ -static void viacore_intt1(CLOCK offset, void *data); -static void viacore_intt2(CLOCK offset, void *data); +static void viacore_t1_zero_alarm(CLOCK offset, void *data); +static void viacore_t2_zero_alarm(CLOCK offset, void *data); +static void viacore_t2_underflow_alarm(CLOCK offset, void *data); +static void do_shiftregister(CLOCK offset, via_context_t *via_context); +inline static void schedule_t2_zero_alarm(via_context_t *via_context, CLOCK rclk); +static void viacore_cache_cb12_io_status(via_context_t *via_context); +static void set_cb2_output_state(via_context_t *via_context, uint8_t pcr, int offset); static void via_restore_int(via_context_t *via_context, int value) @@ -149,47 +202,122 @@ static void via_restore_int(via_context_t *via_context, int value) (via_context->restore_int)(via_context, via_context->int_num, value); } -inline static void update_myviairq(via_context_t *via_context) +inline static void update_myviairq_rclk(via_context_t *via_context, CLOCK rclk) { (via_context->set_int)(via_context, via_context->int_num, (via_context->ifr & via_context->ier & 0x7f) - ? via_context->irq_line : 0, *(via_context->clk_ptr)); + ? 1 : 0, + rclk); } -inline static void update_myviairq_rclk(via_context_t *via_context, CLOCK rclk) +inline static void update_myviairq(via_context_t *via_context) { - (via_context->set_int)(via_context, via_context->int_num, - (via_context->ifr & via_context->ier & 0x7f) - ? via_context->irq_line : 0, rclk); + update_myviairq_rclk(via_context, *(via_context->clk_ptr)); } -/* the next two are used in myvia_read() */ +#define FULL_CYCLE_2 2 + +/* the next two are used in viacore_read() */ -inline static CLOCK myviata(via_context_t *via_context) +/* + * Get the current Timer 1 value. + * + * The datasheet claims: + * Only in continuous mode, T1 reloads from the latch after it shows underflow (FFFF). + * A full cycle of T1 therefore takes (tal + 2) cycles: N, N-1, ..., 1, , 0, FFFF. + * FULL_CYCLE_2 is the name of this 2, to make it clear where it occurs. + * + * In practice it seems that this happens also in one-shot mode. + * + * t1reload is used to indicate when T1 gets/was reloaded from the latch. + * + * t1reload is used for several purposes: + * - the next time T1 gets reloaded and will raise the T1 IRQ some time before; + * t1zero is set in this case (alarm time when IRQ is raised; because it is an + * alarm it has to be set to the cycle before the CPU must see it). + * - the previous time it was reloaded (if no more IRQ is wanted); + * t1zero is 0 in this case. + * + * If the current clock (rclk) has not yet rached t1reload, the difference -2 + * is the clock value. Minus 2 to reach 0 and FFFF. + * + * T1: 3 2 1 0 FFFF 42 + * ^ ^ + * rclk t1zero t1reload + * + * Otherwise, calculate the total time since the last reload. + * We take the remainder of this elapsed time when dividing by the full cycle time. + * The timer is the start value minus the partial cycle completed. + * + * t1reload might as well be called t1_reload_time. + * + * T1 can be in one-shot VIA_ACR_T1_ONE_SHOT or continuous mode VIA_ACR_T1_FREE_RUN. + * + * The interval timer one-shot mode allows generation of a single interrupt for + * each timer load operation. After underflow, the timer is reloaded from + * the latch. (contrary to the datasheet...) + * + * If used, PB7 is used in pulse mode: set low when T1 starts from the latch, + * and high (essentially also a toggle) when the IRQ happens. + * + * In the free-running mode the interrupt flag is set and the signal on PB7 is + * inverted each time the counter reaches zero. After FFFF, the latch is + * reloaded into the timer. + */ +inline static uint16_t viacore_t1(via_context_t *via_context, CLOCK rclk) { - if (*(via_context->clk_ptr) < via_context->tau - TAUOFFSET) { - return via_context->tau - TAUOFFSET - *(via_context->clk_ptr) - 2; - } else { - return (via_context->tal - (*(via_context->clk_ptr) - via_context->tau - + TAUOFFSET) % (via_context->tal + 2)); + if (rclk < via_context->t1reload) { + return via_context->t1reload - rclk - FULL_CYCLE_2; + } else { /* always reload from latch, contrary to datasheet */ + unsigned int full_cycle = via_context->tal + FULL_CYCLE_2; + CLOCK time_past_last_reload = rclk - (via_context->t1reload); + unsigned int partial_cycle = time_past_last_reload % full_cycle; + + return via_context->tal - partial_cycle; } } -inline static CLOCK myviatb(via_context_t *via_context) +#define TBI_OFFSET 1 + +#define SR_PHI2_FIRST_OFFSET 3 +#define SR_PHI2_NEXT_OFFSET 1 + +/* + * Get the current T2 value. + * + * When counting PB6 pulses, the value is actually stored in t2ch/t2cl. + * Otherwise it counts down at clock speed and that is optimized. + * + * If t2xx00 == true, then t2zero is the next time that T2 will be xx00. + * so t2ch is needed to fill in xx. + * The t2_zero_alarm is set. + * If t2xx00 == false, t2zero indicates when T2 will be / was last 0000, + * given the current rclk we calculate the current full T2 value. + * The t2_zero_alarm is not set. + * + * If the shift register mode sets the timer in 8-bit mode, t2xx00 must be true. + * + * In 16-bit mode, t2xx00 *may* be false. This is typically after the T2 IRQ has + * triggered. But it may also be true. In that case, it will keep setting + * t2_zero_alarms, until xx00 counts down to 0000. Then t2xx00 will become false + * and t2_zero_alarms will be turned off. + * + * To be run from cpu access only, not from an alarm? + */ +inline static uint16_t viacore_t2(via_context_t *via_context, CLOCK rclk) { - CLOCK t2; + uint16_t t2; - if (via_context->via[VIA_ACR] & 0x20) { + if (via_context->via[VIA_ACR] & VIA_ACR_T2_COUNTPB6) { t2 = (via_context->t2ch << 8) | via_context->t2cl; + VIALOG2("viacore_t2: countpb6: %04x\n", t2); } else { - t2 = via_context->tbu - *(via_context->clk_ptr) - 2; - - if (via_context->tbi) { - BYTE t2hi = via_context->t2ch; + t2 = via_context->t2zero - rclk; + VIALOG2("viacore_t2: timer: %04x\n", t2); - if (*(via_context->clk_ptr) == via_context->tbi + 1) { - t2hi--; - } + if (via_context->t2xx00) { + uint8_t t2hi = via_context->t2ch; + VIALOG2(" : timer: %04x t2xx00:t2ch: %02x rclk %04lu t2xx00 %d t2_zero %lu\n", t2, t2hi, rclk, via_context->t2xx00, via_context->t2zero); t2 = (t2hi << 8) | (t2 & 0xff); } @@ -198,47 +326,45 @@ inline static CLOCK myviatb(via_context_t *via_context) return t2; } -inline static void update_myviatal(via_context_t *via_context, CLOCK rclk) +/* + * Set the new value of tal from the via's latch register. + * + * It has to make sure that rclk < t1reload, so that reading T1 in viacore_t1() + * does not depend on the newly updated latch value yet. + * That value will only be loaded into the timer after the next underflow. + */ +inline static void update_via_t1_latch(via_context_t *via_context, CLOCK rclk) { - via_context->pb7x = 0; - via_context->pb7xx = 0; - - if (rclk > via_context->tau) { - int nuf = (via_context->tal + 1 + rclk - via_context->tau) - / (via_context->tal + 2); - - if (!(via_context->via[VIA_ACR] & 0x40)) { - /* one shot mode */ - if (((nuf - via_context->pb7sx) > 1) || (!(via_context->pb7))) { - via_context->pb7o = 1; - via_context->pb7sx = 0; - } - } - via_context->pb7 ^= (nuf & 1); - - via_context->tau = TAUOFFSET + via_context->tal + 2 - + (rclk - (rclk - via_context->tau + TAUOFFSET) - % (via_context->tal + 2)); - if (rclk == via_context->tau - via_context->tal - 1) { - via_context->pb7xx = 1; + if (rclk >= via_context->t1reload) { + unsigned int full_cycle = via_context->tal + FULL_CYCLE_2; + CLOCK time_past_last_reload = rclk - (via_context->t1reload); + /* + * Calculate the number of full T1 cycles, rounded way up, + * to get t1reload ahead of rclk, but at most by 1 full_cycle. + */ + CLOCK nuf = 1 + (time_past_last_reload / full_cycle); + via_context->t1reload += nuf * full_cycle; + + if (!(rclk < via_context->t1reload) || + !(rclk + full_cycle >= via_context->t1reload)) { + VIALOG("update_via_t1_latch: t1reload too far into the future: rclk %lu, t1reload %lu, full_cycle %u, T1 %04x, nuf %lu\n", rclk, via_context->t1reload, full_cycle, viacore_t1(via_context, rclk), nuf); } } - if (via_context->tau == rclk) { - via_context->pb7x = 1; - } - via_context->tal = via_context->via[VIA_T1LL] + (via_context->via[VIA_T1LH] << 8); + VIALOG2("tal %u (0x%04x)\n", via_context->tal, via_context->tal); } /* ------------------------------------------------------------------------- */ void viacore_disable(via_context_t *via_context) { - alarm_unset(via_context->t1_alarm); - alarm_unset(via_context->t2_alarm); - alarm_unset(via_context->sr_alarm); - via_context->enabled = 0; + alarm_unset(via_context->t1_zero_alarm); + alarm_unset(via_context->t2_zero_alarm); + alarm_unset(via_context->t2_underflow_alarm); + alarm_unset(via_context->t2_shift_alarm); + alarm_unset(via_context->phi2_sr_alarm); + via_context->enabled = false; } /* @@ -267,53 +393,55 @@ void viacore_reset(via_context_t *via_context) via_context->tal = 0xffff; via_context->t2cl = 0xff; via_context->t2ch = 0xff; - via_context->tau = *(via_context->clk_ptr); - via_context->tbu = *(via_context->clk_ptr); + via_context->t1reload = *(via_context->clk_ptr); + via_context->t2zero = *(via_context->clk_ptr); via_context->read_clk = 0; via_context->ier = 0; via_context->ifr = 0; - via_context->pb7 = 0; - via_context->pb7x = 0; - via_context->pb7o = 0; - via_context->pb7xx = 0; - via_context->pb7sx = 0; + via_context->t1_pb7 = 0x80; - via_context->shift_state = 0; + via_context->shift_state = FINISHED_SHIFTING; /* not shifting */ + via_context->t2_irq_allowed = false; /* disable vice interrupts */ - via_context->tai = 0; - via_context->tbi = 0; - alarm_unset(via_context->t1_alarm); - alarm_unset(via_context->t2_alarm); - alarm_unset(via_context->sr_alarm); + via_context->t1zero = 0; + via_context->t2xx00 = false; + alarm_unset(via_context->t1_zero_alarm); + alarm_unset(via_context->t2_zero_alarm); + alarm_unset(via_context->t2_underflow_alarm); + alarm_unset(via_context->t2_shift_alarm); + alarm_unset(via_context->phi2_sr_alarm); update_myviairq(via_context); - via_context->oldpa = 0xff; - via_context->oldpb = 0xff; + via_context->oldpa = 0; + via_context->oldpb = 0; - via_context->ca2_state = 1; - via_context->cb2_state = 1; - (via_context->set_ca2)(via_context, via_context->ca2_state); /* input = high */ - (via_context->set_cb2)(via_context, via_context->cb2_state); /* input = high */ + via_context->ca2_out_state = true; + via_context->cb1_out_state = true; + via_context->cb2_out_state = true; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); /* input = high */ + (via_context->set_cb2)(via_context, via_context->cb2_out_state, 0); /* input = high */ - if (via_context && via_context->reset) { + if (via_context->reset) { (via_context->reset)(via_context); } - via_context->enabled = 1; + viacore_cache_cb12_io_status(via_context); + + via_context->enabled = true; } void viacore_signal(via_context_t *via_context, int line, int edge) { switch (line) { case VIA_SIG_CA1: - if ((edge ? 1 : 0) == (via_context->via[VIA_PCR] & 0x01)) { - if (IS_CA2_TOGGLE_MODE() && !(via_context->ca2_state)) { - via_context->ca2_state = 1; - (via_context->set_ca2)(via_context, via_context->ca2_state); + if ((edge ? 1 : 0) == (via_context->via[VIA_PCR] & VIA_PCR_CA1_CONTROL)) { + if (IS_CA2_TOGGLE_MODE() && !(via_context->ca2_out_state)) { + via_context->ca2_out_state = true; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); } via_context->ifr |= VIA_IM_CA1; update_myviairq(via_context); @@ -325,7 +453,7 @@ void viacore_signal(via_context_t *via_context, int line, int edge) } break; case VIA_SIG_CA2: - if (!(via_context->via[VIA_PCR] & 0x08)) { + if ((via_context->via[VIA_PCR] & VIA_PCR_CA2_I_OR_O) == VIA_PCR_CA2_INPUT) { via_context->ifr |= (((edge << 2) ^ via_context->via[VIA_PCR]) & 0x04) ? 0 : VIA_IM_CA2; @@ -333,32 +461,176 @@ void viacore_signal(via_context_t *via_context, int line, int edge) } break; case VIA_SIG_CB1: - if ((edge ? 0x10 : 0) == (via_context->via[VIA_PCR] & 0x10)) { - if (IS_CB2_TOGGLE_MODE() && !(via_context->cb2_state)) { - via_context->cb2_state = 1; - (via_context->set_cb2)(via_context, via_context->cb2_state); - } - via_context->ifr |= VIA_IM_CB1; - update_myviairq(via_context); -#ifdef MYVIA_NEED_LATCHING - if (IS_PB_INPUT_LATCH()) { - via_context->ilb = (via_context->read_prb)(via_context); - } -#endif - } + viacore_set_cb1(via_context, edge); break; case VIA_SIG_CB2: - if (!(via_context->via[VIA_PCR] & 0x80)) { - via_context->ifr |= (((edge << 6) - ^ via_context->via[VIA_PCR]) & 0x40) ? - 0 : VIA_IM_CB2; - update_myviairq(via_context); - } + viacore_set_cb2(via_context, edge); break; } } -void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) +/* + * Return the clock when this alarm is due. + * Alarms for clock N run after CPU accesses for that clock. + * If the alarm is not set, returns 0. + */ +inline static CLOCK alarm_clk(alarm_t *alarm) +{ + alarm_context_t *context; + int idx; + + context = alarm->context; + idx = alarm->pending_idx; + + if (idx >= 0) { + return context->pending_alarms[idx].clk; + } else { + return 0; + } +} + +#if CHECK_CPU_VS_ALARM_CLOCKS +static CLOCK last_alarm_clock; +static CLOCK last_cpu_clock; +#endif + +/* + * To be called only during CPU access to the registers. + * + * Run any pending alarms that should have run before the current clock cycle. + * Alarms scheduled for cycle N run AFTER CPU accesses of cycle N. + * Therefore we only run alarms < clk, i.e. alarms that should have run + * up to and including the previous cycle. + * + * The normal execution run uses "clk >= alarm...", but since we're running + * this during CPU access, here we use "clk > ...". + * + * In some cases, clk here differs from the global clock by some offset + * (due to ->write_offset). The dispatch function needs the proper clock + * value to calculate the offset parameter to the alarm callbacks. + * So we need an offset here to re-calculate the correct clk. + */ +inline static void run_pending_alarms(CLOCK clk, int offset, alarm_context_t *alarm_context) +{ + while (clk > alarm_context_next_pending_clk(alarm_context)) { + VIALOG2("run_pending_alarms: %lu\n", clk); +#if CHECK_CPU_VS_ALARM_CLOCKS + /* catch-up alarms don't count for checking which runs before which. */ + last_cpu_clock = 0; +#endif + alarm_context_dispatch(alarm_context, clk + offset); +#if CHECK_CPU_VS_ALARM_CLOCKS + last_alarm_clock = 0; +#endif + } +} + +inline static int alarm_is_pending(alarm_t *alarm) +{ + return alarm->pending_idx >= 0; +} + +inline static void alarm_set_if_not_pending(alarm_t *alarm, CLOCK cpu_clk) +{ + if (!alarm_is_pending(alarm)) { + alarm_set(alarm, cpu_clk); + } +} + +/* + * Before calling this, make sure that t2cl and t2ch are the correct T2 + * values for time rclk. + * + * Schedules an alarm for when T2 sets the interrupt flag (t2_zero_alarm). + * t2xx00 is made true to indicate that T2 is in 8-bit mode + * OR the next 0000 value should cause an IRQ. + * + * If there is an underflow alarm scheduled, cancel it, since the underflow + * doesn't happen. Also it would wrongly re-schedule the t2_zero_alarm. + * + * See also viacore_t2() and comments. + */ +inline static void schedule_t2_zero_alarm(via_context_t *via_context, CLOCK rclk) +{ + VIALOG2("schedule_t2_zero_alarm: T1CL=%02x; t2_zero_alarm %lu, rclk %lu (t2_underflow_alarm: %lu)\n", via_context->t2cl, via_context->t2zero, rclk, alarm_clk(via_context->t2_underflow_alarm)); + + via_context->t2zero = rclk + via_context->t2cl; + via_context->t2xx00 = true; + + alarm_unset(via_context->t2_underflow_alarm); + alarm_set(via_context->t2_zero_alarm, via_context->t2zero); +} + +/* + * Potentially enable the shifting of SR, by setting the shift_state, + * in reaction to a read or write of the shift register. + * Depending on the mode (phi2), will set an alarm to do the shifting. + * For other modes, the alarm is already managed elsewhere + * (such as with the T2 alarms). + */ +static inline void setup_shifting(via_context_t *via_context, CLOCK rclk) +{ + uint8_t acr = via_context->via[VIA_ACR]; + + switch (acr & VIA_ACR_SR_CONTROL) { + case VIA_ACR_SR_DISABLED: + /* + * Writing to SR while disabled apparently doesn't "start" the + * shift counter. viasr18.prg fails if you do that. + * But probably this doesn't *stop* it either. + * viasr18.prg works either way (disabling or doing nothing). + */ + VIALOG2("setup_shifting: disabled (do not change state %d)\n", via_context->shift_state); + /* via_context->shift_state = FINISHED_SHIFTING; */ + break; + case VIA_ACR_SR_IN_T2: + case VIA_ACR_SR_OUT_T2: + /* + * Rockwell says that this happens, Commodore/MOS doesn't mention it + * (in VIA_ACR_SR_IN/OUT_T2 modes): + * + * "The shifting operation is triggered by the read or write of + * the SR if the SR flag is set in the IFR. Otherwise the first + * shift will occur at the next time-out of T2 after a read or + * write of the SR." + * + * If we believe the timing diagram, this happens on the 3rd + * next positive flank of phi2. + * + * We just wait for T2 to underflow. + */ + case VIA_ACR_SR_IN_CB1: + case VIA_ACR_SR_OUT_CB1: + if (via_context->shift_state == FINISHED_SHIFTING) { + VIALOG2("setup_shifting: enable (change state 16 to 0)\n"); + via_context->shift_state = START_SHIFTING; + } + break; + case VIA_ACR_SR_IN_PHI2: + case VIA_ACR_SR_OUT_PHI2: + if (via_context->shift_state == FINISHED_SHIFTING) { + VIALOG2("setup_shifting: enable (change state 16 to 0)\n"); + via_context->shift_state = START_SHIFTING; + /* + * The phi2_sr_alarm triggers every cycle. If we just start shifting, + * don't do the first shift in the same cycle. + */ + alarm_set(via_context->phi2_sr_alarm, rclk + 1); + } + break; + + case VIA_ACR_SR_OUT_FREE_T2: + VIALOG2("setup_shifting: enable free running (change state %d to %d)\n", via_context->shift_state, via_context->shift_state & 0x0F); + /* Make sure it's < 16 and preserve even/oddness */ + via_context->shift_state &= 0x0F; + break; + } +} + +/* + * The CPU writes a byte to the VIA. + */ +void viacore_store(via_context_t *via_context, uint16_t addr, uint8_t byte) { CLOCK rclk; @@ -371,9 +643,21 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) /* stores have a one-cycle offset if CLK++ happens before store */ rclk = *(via_context->clk_ptr) - via_context->write_offset; + VIALOG2("viacore_store: rclk=%lu\n", rclk); +#if CHECK_CPU_VS_ALARM_CLOCKS + last_cpu_clock = rclk; + if (last_cpu_clock == last_alarm_clock) { + VIALOG("cpu access after alarm %lu UNEXPECTED\n", rclk); + } +#endif addr &= 0xf; + if (addr == VIA_PRB || (addr >= VIA_T1CL && addr <= VIA_IER)) { + run_pending_alarms(rclk, via_context->write_offset, via_context->alarm_context); + /* run_pending_alarms(rclk, 0, via_context->alarm_context); */ + } + switch (addr) { /* these are done with saving the value */ case VIA_PRA: /* port A */ @@ -382,15 +666,16 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) via_context->ifr &= ~VIA_IM_CA2; } if (IS_CA2_HANDSHAKE()) { - via_context->ca2_state = 0; - (via_context->set_ca2)(via_context, via_context->ca2_state); + via_context->ca2_out_state = false; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); if (IS_CA2_PULSE_MODE()) { - via_context->ca2_state = 1; - (via_context->set_ca2)(via_context, via_context->ca2_state); + /* This is a bit soon... should be a clock later */ + via_context->ca2_out_state = true; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); } } if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) { - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); } /* fall through */ @@ -412,32 +697,36 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) via_context->ifr &= ~VIA_IM_CB2; } if (IS_CB2_HANDSHAKE()) { - via_context->cb2_state = 0; - (via_context->set_cb2)(via_context, via_context->cb2_state); + via_context->cb2_out_state = 0; + (via_context->set_cb2)(via_context, via_context->cb2_out_state, via_context->write_offset); if (IS_CB2_PULSE_MODE()) { - via_context->cb2_state = 1; - (via_context->set_cb2)(via_context, via_context->cb2_state); + /* FIXME: This pulse is a bit short... */ + via_context->cb2_out_state = 1; + (via_context->set_cb2)(via_context, via_context->cb2_out_state, 0); } } if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) { - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); } /* fall through */ case VIA_DDRB: via_context->via[addr] = byte; byte = via_context->via[VIA_PRB] | ~(via_context->via[VIA_DDRB]); + if (via_context->via[VIA_ACR] & VIA_ACR_T1_PB7_USED) { + byte = (byte & 0x7f) | via_context->t1_pb7; + } (via_context->store_prb)(via_context, byte, via_context->oldpb, addr); via_context->oldpb = byte; break; case VIA_SR: /* Serial Port output buffer */ via_context->via[addr] = byte; - /* shift state can only be reset once 8 bits are complete */ + VIALOG2("writ VIA_SR : rclk %lu SR %02x shift_state %d\n", rclk, via_context->via[addr], via_context->shift_state); + setup_shifting(via_context, rclk); if (via_context->ifr & VIA_IM_SR) { via_context->ifr &= ~VIA_IM_SR; - update_myviairq(via_context); - via_context->shift_state = 0; + update_myviairq_rclk(via_context, rclk); } (via_context->store_sr)(via_context, byte); @@ -448,29 +737,35 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) case VIA_T1CL: case VIA_T1LL: via_context->via[VIA_T1LL] = byte; - update_myviatal(via_context, rclk); + update_via_t1_latch(via_context, rclk); break; case VIA_T1CH: /* Write timer A high */ via_context->via[VIA_T1LH] = byte; - update_myviatal(via_context, rclk); - /* load counter with latch value */ - via_context->tau = rclk + via_context->tal + 3 + TAUOFFSET; - via_context->tai = rclk + via_context->tal + 2; - alarm_set(via_context->t1_alarm, via_context->tai); + update_via_t1_latch(via_context, rclk); + /* + * Load counter with latch value (next time it will read that value); + * add 1 because this value is to be observed in the NEXT cycle. + * + * Each write allows 1 IRQ. This is purely indicated by t1zero. + * Unlike timer 2, we don't need a separate t1_irq_allowed. + */ + via_context->t1reload = rclk+1 + via_context->tal + FULL_CYCLE_2; + via_context->t1zero = rclk+1 + via_context->tal ; + VIALOG2("write VIA_T1CH: set t1_zero_alarm t1zero=%lu, t1reload %lu\n", via_context->t1zero, via_context->t1reload); + alarm_set(via_context->t1_zero_alarm, via_context->t1zero); /* set pb7 state */ - via_context->pb7 = 0; - via_context->pb7o = 0; + via_context->t1_pb7 = 0; /* Clear T1 interrupt */ via_context->ifr &= ~VIA_IM_T1; - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); break; case VIA_T1LH: /* Write timer A high order latch */ via_context->via[addr] = byte; - update_myviatal(via_context, rclk); + update_via_t1_latch(via_context, rclk); /* CAUTION: according to the synertek notes, writing to T1LH does NOT change the interrupt flags. however, not doing so breaks eg @@ -480,41 +775,63 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) /* Clear T1 interrupt */ via_context->ifr &= ~VIA_IM_T1; - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); break; case VIA_T2LL: /* Write timer 2 low latch */ + VIALOG2("write VIA_T2LL: %02x\n", byte); via_context->via[VIA_T2LL] = byte; + /* + * Rules for Shift out under control of T2: + * - writing in the latch here will only take effect on the counter and + * the time of the t2_underflow_alarm at the next T2 underflow; + * - only writing the SR can start the shifting, and the first bit + * is shifted out at the next T2L underflow. Until then T2L is counting + * down as usual, and it can be higher than this new latch value. + */ (via_context->store_t2l)(via_context, byte); break; case VIA_T2CH: /* Write timer 2 high counter/latch */ /* update counter and latch values */ + VIALOG2("write VIA_T2CH: %02x at %lu\n", byte, rclk); via_context->via[VIA_T2LH] = byte; via_context->t2cl = via_context->via[VIA_T2LL]; via_context->t2ch = byte; /* start T2 only in timer mode, leave unchanged in pulse counting mode */ - if (!(via_context->via[VIA_ACR] & 0x20)) { - /* set the next alarm to the low latch value as timer cascading mode change - matters at each underflow of the T2 low counter */ - via_context->tbu = rclk + via_context->t2cl + 3; - via_context->tbi = rclk + via_context->t2cl + 1; - alarm_set(via_context->t2_alarm, via_context->tbi); + if (!(via_context->via[VIA_ACR] & VIA_ACR_T2_COUNTPB6)) { + /* + * Set the next alarm to the low latch value as timer cascading + * mode change matters at each underflow of the T2 low counter. + */ + /* Since starting the countdown takes a cycle, pretend + * it is 1 clock later than it really is. In the next cycle we + * should observe the starting value. + */ + schedule_t2_zero_alarm(via_context, rclk + 1); + VIALOG2(" now T2: %04x\n", viacore_t2(via_context, rclk+1)); + } else { + VIALOG2(" don't start t2_zero_alarm because ACR=%02x\n", via_context->via[VIA_ACR]); } /* Clear T2 interrupt */ via_context->ifr &= ~VIA_IM_T2; - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); + /* Each write to T2H allows one interrupt to occur */ + via_context->t2_irq_allowed = true; break; /* Interrupts */ case VIA_IFR: /* 6522 Interrupt Flag Register */ via_context->ifr &= ~byte; - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); - /* FIXME: clearing any timer interrupt should set the relevant timer alarm */ + /* FIXME: + * clearing any timer interrupt should set the relevant timer alarm. + * (It is unclear what was meant with that... + */ break; case VIA_IER: /* Interrupt Enable Register */ @@ -525,139 +842,176 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) /* clear interrupts */ via_context->ier &= ~byte; } - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); break; /* Control */ case VIA_ACR: /* bit 7 timer 1 output to PB7 */ - update_myviatal(via_context, rclk); - if ((via_context->via[VIA_ACR] ^ byte) & 0x80) { - if (byte & 0x80) { - via_context->pb7 = 1 ^ via_context->pb7x; + VIALOG2("write VIA_ACR: %02x\n", byte); + if ((via_context->via[VIA_ACR] ^ byte) & VIA_ACR_T1_PB7_USED) { + /* On the rising edge of the VIA_ACR_T1_PB7_USED bit, set PB7 high */ + if (byte & VIA_ACR_T1_PB7_USED) { + via_context->t1_pb7 = 0x80; } } - if ((via_context->via[VIA_ACR] ^ byte) & 0x40) { - via_context->pb7 ^= via_context->pb7sx; - if ((byte & 0x40)) { - if (via_context->pb7x || via_context->pb7xx) { - if (via_context->tal) { - via_context->pb7o = 1; - } else { - via_context->pb7o = 0; - if ((via_context->via[VIA_ACR] & 0x80) - && via_context->pb7x - && (!(via_context->pb7xx))) { - via_context->pb7 ^= 1; - } - } - } - } - } - via_context->pb7sx = via_context->pb7x; /* bit 1, 0 latch enable port B and A */ #ifdef MYVIA_NEED_LATCHING - /* switch on port A latching - FIXME: is this ok? */ - if ((!(via_context->via[addr] & 1)) && (byte & 1)) { - via_context->ila = (via_context->read_pra)(via_context, addr); + /* + * If all conditions for latching become true now, + * store the port's input value into the latch. + */ + if ((!(via_context->via[addr] & VIA_ACR_PA_LATCH)) && + (byte & VIA_ACR_PA_LATCH)) { + if (via_context->ifr & VIA_IM_CA1) { + via_context->ila = (via_context->read_pra)(via_context, addr); + } } - /* switch on port B latching - FIXME: is this ok? */ - if ((!(via_context->via[addr] & 2)) && (byte & 2)) { - via_context->ilb = (via_context->read_prb)(via_context); + /* switch on port B latching, same as for port A */ + if ((!(via_context->via[addr] & VIA_ACR_PB_LATCH)) && + (byte & VIA_ACR_PB_LATCH)) { + if (via_context->ifr & VIA_IM_CB1) { + via_context->ilb = (via_context->read_prb)(via_context); + } } #endif + int t2_startup_delay = 0; + int restart_t2_alarms = 0; + /* switch between timer and pulse counting mode if bit 5 changes */ - if ((via_context->via[VIA_ACR] ^ byte) & 0x20) { - if (byte & 0x20) { - /* Pulse counting mode: set t2 to the current T2 value; + if ((via_context->via[VIA_ACR] ^ byte) & VIA_ACR_T2_CONTROL) { + if (byte & VIA_ACR_T2_COUNTPB6) { + /* Pulse counting mode: set t2 to the current T2 value; PB6 should always update t2 and update irq on underflow */ - CLOCK stop = myviatb(via_context); - via_context->t2cl = (BYTE)(stop & 0xff); - via_context->t2ch = (BYTE)((stop >> 8) & 0xff); + /* Just like starting T2 takes a cycle, so does stopping: + * it decrements one further tick. + */ + CLOCK stop = viacore_t2(via_context, rclk) - 1; + via_context->t2cl = (uint8_t)(stop & 0xff); + via_context->t2ch = (uint8_t)((stop >> 8) & 0xff); /* stop alarm to prevent t2 and T2 updates */ - alarm_unset(via_context->t2_alarm); - via_context->tbi = 0; + alarm_unset(via_context->t2_zero_alarm); + via_context->t2xx00 = false; + + /* + * FIXME re t2xx00 above: is 8-bit mode handled correctly + * when in pulse counting mode? Probably not. Currently + * this is not relevant since we never detect pulses so + * the timer is stopped. + */ } else { - /* Timer mode; set the next alarm to the low latch value as timer cascading mode change - matters at each underflow of the T2 low counter */ - via_context->tbu = rclk + via_context->t2cl + 3; - via_context->tbi = rclk + via_context->t2cl + 1; - alarm_set(via_context->t2_alarm, via_context->tbi); + /* + * Timer mode; set the next alarm to the low latch value as + * timer cascading mode change matters at each underflow of + * the T2 low counter. + * + * Since the timer takes a clock cycle before it starts + * decrementing, we should wait until then to start it. + * Or, since we can't have a bus cycle reading the timer in + * this same clock tick, we set the timer 1 too high right + * now. + */ + restart_t2_alarms++; + t2_startup_delay++; } } - /* handle the t2 alarm for the serial shift register - * - * FIXME: it is not clear what happens when pulse counting mode is - * selected for t2 - */ - if ((byte & 0x20) == 0) { - if (((byte & 0x0c) == 0x04) || /* FIXME: shift register under t2 control */ - ((byte & 0x1c) == 0x10)) { /* FIXME: shift register free running at t2 rate */ - /* Timer mode; set the next alarm to the low latch value as timer cascading mode change - matters at each underflow of the T2 low counter */ - via_context->tbu = rclk + via_context->t2cl + 3; - via_context->tbi = rclk + via_context->t2cl + 1; - alarm_set(via_context->t2_alarm, via_context->tbi); + /* bit 4, 3, 2 shift register control */ + switch (byte & VIA_ACR_SR_CONTROL) { + case VIA_ACR_SR_DISABLED: + alarm_unset(via_context->phi2_sr_alarm); + /* "In this mode the SR Interrupt Flag is disabled + * (held to a logic 0)." + */ + if (via_context->ifr & VIA_IM_SR) { + via_context->ifr &= ~VIA_IM_SR; + update_myviairq_rclk(via_context, rclk); } + set_cb2_output_state(via_context, via_context->via[VIA_PCR], + via_context->write_offset); + break; + case VIA_ACR_SR_IN_T2: + case VIA_ACR_SR_OUT_T2: + case VIA_ACR_SR_OUT_FREE_T2: + alarm_unset(via_context->phi2_sr_alarm); + /* + * Timer now in 8-bit mode. This requires the t2_zero_alarm. + * If OLD SR state was NOT T2-controlled, we may need to re-arm + * the t2_zero_alarm again: if the timer reached 0000 it would + * be unset by now. + * But only if NEW state is timer mode (not pulse counting). + */ + restart_t2_alarms = + restart_t2_alarms || + (!IS_SR_T2_CONTROLLED(via_context->via[VIA_ACR]) && + IS_T2_TIMER(byte)); + break; + case VIA_ACR_SR_IN_PHI2: + case VIA_ACR_SR_OUT_PHI2: + /* Only schedule the alarm if it isn't scheduled already */ + alarm_set_if_not_pending(via_context->phi2_sr_alarm, rclk + SR_PHI2_FIRST_OFFSET); + break; + case VIA_ACR_SR_IN_CB1: + case VIA_ACR_SR_OUT_CB1: /* TODO: Out not emulated */ + alarm_unset(via_context->phi2_sr_alarm); + break; } - /* bit 4, 3, 2 shift register control */ - if ((byte & 0x0c) == 0x08) { - /* shift under control of phi2 */ - if ((byte & 0x10) == 0x10) { - alarm_set(via_context->sr_alarm, rclk + 3); /* FIXME */ - } else { - alarm_set(via_context->sr_alarm, rclk + 3); /* FIXME */ - } - } else { - /* when disabled or external clock, stop the alarm */ - alarm_unset(via_context->sr_alarm); + if (restart_t2_alarms && + !alarm_is_pending(via_context->t2_zero_alarm) && + !alarm_is_pending(via_context->t2_underflow_alarm)) { + CLOCK current = viacore_t2(via_context, rclk); + VIALOG2("set ACR: clock corr : %04lx offset: %d\n", current, + t2_startup_delay); + /* Timer mode; set the next alarm to the low latch value as + * timer cascading mode change matters at each underflow of + * the T2 low counter. + */ + via_context->t2cl = current & 0xFF; + via_context->t2ch = current >> 8; + schedule_t2_zero_alarm(via_context, rclk + t2_startup_delay); } via_context->via[addr] = byte; + viacore_cache_cb12_io_status(via_context); (via_context->store_acr)(via_context, byte); break; case VIA_PCR: - + VIALOG2("write VIA_PCR: %02x\n", byte); /* bit 7, 6, 5 CB2 handshake/interrupt control */ /* bit 4 CB1 interrupt control */ /* bit 3, 2, 1 CA2 handshake/interrupt control */ /* bit 0 CA1 interrupt control */ - if ((byte & 0x0e) == 0x0c) { /* set output low */ - via_context->ca2_state = 0; + if ((byte & VIA_PCR_CA2_CONTROL) == VIA_PCR_CA2_LOW_OUTPUT) { + /* set output low */ + via_context->ca2_out_state = false; } else - if ((byte & 0x0e) == 0x0e) { /* set output high */ - via_context->ca2_state = 1; + if ((byte & VIA_PCR_CA2_CONTROL) == VIA_PCR_CA2_HIGH_OUTPUT) { + /* set output high */ + via_context->ca2_out_state = true; } else { /* set to toggle/pulse/input */ /* FIXME: is this correct if handshake is already active? */ - via_context->ca2_state = 1; + via_context->ca2_out_state = true; } - (via_context->set_ca2)(via_context, via_context->ca2_state); + (via_context->set_ca2)(via_context, via_context->ca2_out_state); - if ((byte & 0xe0) == 0xc0) { /* set output low */ - via_context->cb2_state = 0; - } else - if ((byte & 0xe0) == 0xe0) { /* set output high */ - via_context->cb2_state = 1; - } else { /* set to toggle/pulse/input */ - /* FIXME: is this correct if handshake is already active? */ - via_context->cb2_state = 1; + /* Shift register control overrides CB2 control */ + if ((via_context->via[VIA_ACR] & VIA_ACR_SR_CONTROL) == + VIA_ACR_SR_DISABLED) { + set_cb2_output_state(via_context, byte, via_context->write_offset); } - (via_context->set_cb2)(via_context, via_context->cb2_state); (via_context->store_pcr)(via_context, byte, addr); via_context->via[addr] = byte; - + viacore_cache_cb12_io_status(via_context); break; default: @@ -668,23 +1022,30 @@ void viacore_store(via_context_t *via_context, WORD addr, BYTE byte) /* ------------------------------------------------------------------------- */ -BYTE viacore_read(via_context_t *via_context, WORD addr) +/* + * The CPU reads a byte from the VIA. + */ +uint8_t viacore_read(via_context_t *via_context, uint16_t addr) { #ifdef MYVIA_TIMER_DEBUG - BYTE viacore_read_(via_context_t *via_context, WORD); - BYTE retv = myvia_read_(via_context, addr); + uint8_t viacore_read_(via_context_t *via_context, uint16_t); + uint8_t retv = myvia_read_(via_context, addr); addr &= 0x0f; if ((addr > 3 && addr < 10) || app_resources.debugFlag) { log_message(via_context->log, - "myvia_read(%x) -> %02x, clk=%d", addr, retv, + "viacore_read(%x) -> %02x, clk=%ld", addr, retv, *(via_context->clk_ptr)); } return retv; } -BYTE viacore_read_(via_context_t *via_context, WORD addr) + +uint8_t viacore_read_(via_context_t *via_context, uint16_t addr) { #endif - BYTE byte = 0xff; + uint8_t byte = 0xff; +#ifdef MYVIA_NEED_LATCHING + uint8_t tmpifr; +#endif CLOCK rclk; addr &= 0xf; @@ -692,82 +1053,99 @@ BYTE viacore_read_(via_context_t *via_context, WORD addr) via_context->read_clk = *(via_context->clk_ptr); via_context->read_offset = 0; rclk = *(via_context->clk_ptr); + VIALOG2("viacore_read_: rclk=%lu\n", rclk); +#if CHECK_CPU_VS_ALARM_CLOCKS + last_cpu_clock = rclk; + if (last_cpu_clock == last_alarm_clock) { + VIALOG("cpu read access after alarm %lu UNEXPECTED!!\n", rclk); + } +#endif - if (addr >= VIA_T1CL && addr <= VIA_IER) { - if (via_context->tai && (via_context->tai < *(via_context->clk_ptr))) { - viacore_intt1(*(via_context->clk_ptr) - via_context->tai, - (void *)via_context); - } - if (via_context->tbi && (via_context->tbi < *(via_context->clk_ptr))) { - viacore_intt2(*(via_context->clk_ptr) - via_context->tbi, - (void *)via_context); - } + if (addr == VIA_PRB || (addr >= VIA_T1CL && addr <= VIA_IER)) { + run_pending_alarms(rclk, 0, via_context->alarm_context); } switch (addr) { case VIA_PRA: /* port A */ +#ifdef MYVIA_NEED_LATCHING + tmpifr = via_context->ifr; +#endif via_context->ifr &= ~VIA_IM_CA1; + /* (VIA_PCR_CA2_I_OR_O | VIA_PCR_CA2_INDEPENDENT_INTERRUPT) != + * (VIA_PCR_CA2_INPUT | VIA_PCR_CA2_INDEPENDENT_INTERRUPT) */ if ((via_context->via[VIA_PCR] & 0x0a) != 0x02) { via_context->ifr &= ~VIA_IM_CA2; } if (IS_CA2_HANDSHAKE()) { - via_context->ca2_state = 0; - (via_context->set_ca2)(via_context, via_context->ca2_state); + via_context->ca2_out_state = false; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); if (IS_CA2_PULSE_MODE()) { - via_context->ca2_state = 1; - (via_context->set_ca2)(via_context, via_context->ca2_state); + via_context->ca2_out_state = true; + (via_context->set_ca2)(via_context, via_context->ca2_out_state); } } if (via_context->ier & (VIA_IM_CA1 | VIA_IM_CA2)) { - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); } + goto via_pra_nhs; + /* falls through but skips tmpifr = ... */ case VIA_PRA_NHS: /* port A, no handshake */ /* WARNING: this pin reads the voltage of the output pins, not the ORA value as the other port. Value read might be different from what is expected due to excessive load. */ #ifdef MYVIA_NEED_LATCHING - if (IS_PA_INPUT_LATCH()) { + tmpifr = via_context->ifr; +#endif + via_pra_nhs: +#ifdef MYVIA_NEED_LATCHING + /* If all latching conditions are (still) true, the input value + * has been latched when they became true, and we use it here. */ + if (IS_PA_INPUT_LATCH() && (tmpifr & VIA_IM_CA1)) { byte = via_context->ila; - } else { + } else +#endif + { byte = (via_context->read_pra)(via_context, addr); + /* + * Currently the latch is transparent, so there is no need + * to store the byte into it. That will happen next time + * when its conditions become true. + */ } -#else - byte = (via_context->read_pra)(via_context, addr); -#endif - via_context->ila = byte; via_context->last_read = byte; return byte; case VIA_PRB: /* port B */ +#ifdef MYVIA_NEED_LATCHING + tmpifr = via_context->ifr; +#endif via_context->ifr &= ~VIA_IM_CB1; + /* (VIA_PCR_CB2_I_OR_O | VIA_PCR_CB2_INDEPENDENT_INTERRUPT) != + * (VIA_PCR_CB2_INPUT | VIA_PCR_CB2_INDEPENDENT_INTERRUPT) */ if ((via_context->via[VIA_PCR] & 0xa0) != 0x20) { via_context->ifr &= ~VIA_IM_CB2; } if (via_context->ier & (VIA_IM_CB1 | VIA_IM_CB2)) { - update_myviairq(via_context); + update_myviairq_rclk(via_context, rclk); } - /* WARNING: this pin reads the ORA for output pins, not + /* WARNING: this port reads the ORB for output pins, not the voltage on the pins as the other port. */ #ifdef MYVIA_NEED_LATCHING - if (IS_PB_INPUT_LATCH()) { + if (IS_PB_INPUT_LATCH() && (tmpifr & VIA_IM_CB1)) { byte = via_context->ilb; - } else { + } else +#endif + { byte = (via_context->read_prb)(via_context); + /* Same comment about transparent latch as for PA */ } -#else - byte = (via_context->read_prb)(via_context); -#endif - via_context->ilb = byte; byte = (byte & ~(via_context->via[VIA_DDRB])) | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]); - if (via_context->via[VIA_ACR] & 0x80) { - update_myviatal(via_context, rclk); - byte = (byte & 0x7f) - | (((via_context->pb7 ^ via_context->pb7x) - | via_context->pb7o) ? 0x80 : 0); + if (via_context->via[VIA_ACR] & VIA_ACR_T1_PB7_USED) { + byte = (byte & 0x7f) | via_context->t1_pb7; } via_context->last_read = byte; return byte; @@ -776,30 +1154,32 @@ BYTE viacore_read_(via_context_t *via_context, WORD addr) case VIA_T1CL /*TIMER_AL */: /* timer A low counter */ via_context->ifr &= ~VIA_IM_T1; - update_myviairq(via_context); - via_context->last_read = (BYTE)(myviata(via_context) & 0xff); + update_myviairq_rclk(via_context, rclk); + via_context->last_read = (uint8_t)(viacore_t1(via_context, rclk) & 0xff); return via_context->last_read; case VIA_T1CH /*TIMER_AH */: /* timer A high counter */ - via_context->last_read = (BYTE)((myviata(via_context) >> 8) & 0xff); + via_context->last_read = (uint8_t)((viacore_t1(via_context, rclk) >> 8) & 0xff); return via_context->last_read; case VIA_T2CL /*TIMER_BL */: /* timer B low counter */ via_context->ifr &= ~VIA_IM_T2; - update_myviairq(via_context); - via_context->last_read = (BYTE)(myviatb(via_context) & 0xff); + update_myviairq_rclk(via_context, rclk); + via_context->last_read = (uint8_t)(viacore_t2(via_context, rclk) & 0xff); + VIALOG2("read VIA_T2CL: %02x\n", via_context->last_read); return via_context->last_read; case VIA_T2CH /*TIMER_BH */: /* timer B high counter */ - via_context->last_read = (BYTE)((myviatb(via_context) >> 8) & 0xff); + via_context->last_read = (uint8_t)((viacore_t2(via_context, rclk) >> 8) & 0xff); return via_context->last_read; case VIA_SR: /* Serial Port Shift Register */ /* shift state can only be reset once 8 bits are complete */ + VIALOG2("read VIA_SR : rclk %lu SR %02x shift_state %d\n", rclk, via_context->via[addr], via_context->shift_state); + setup_shifting(via_context, rclk); if (via_context->ifr & VIA_IM_SR) { via_context->ifr &= ~VIA_IM_SR; - update_myviairq(via_context); - via_context->shift_state = 0; + update_myviairq_rclk(via_context, rclk); } via_context->last_read = via_context->via[addr]; return via_context->last_read; @@ -808,15 +1188,17 @@ BYTE viacore_read_(via_context_t *via_context, WORD addr) case VIA_IFR: /* Interrupt Flag Register */ { - BYTE t = via_context->ifr; + uint8_t t = via_context->ifr; if (via_context->ifr & via_context->ier /*[VIA_IER] */) { t |= 0x80; } via_context->last_read = t; + VIALOG2("read VIA_IFR: %02x at %lu\n", t, rclk); return (t); } - case VIA_IER: /* 6522 Interrupt Control Register */ + case VIA_IER: /* 6522 Interrupt Enable Register */ + /* CBM datasheet says that bit 7 reads as logic 0, Rockwell says 1 */ via_context->last_read = (via_context->ier /*[VIA_IER] */ | 0x80); return via_context->last_read; } @@ -828,7 +1210,7 @@ BYTE viacore_read_(via_context_t *via_context, WORD addr) /* return value of a register without side effects */ /* FIXME: this is buggy/incomplete */ -BYTE viacore_peek(via_context_t *via_context, WORD addr) +uint8_t viacore_peek(via_context_t *via_context, uint16_t addr) { addr &= 0xf; @@ -837,44 +1219,38 @@ BYTE viacore_peek(via_context_t *via_context, WORD addr) case VIA_PRA: case VIA_PRA_NHS: /* port A, no handshake */ { - BYTE byte; + uint8_t byte; /* WARNING: this pin reads the voltage of the output pins, not the ORA value as the other port. Value read might be different from what is expected due to excessive load. */ #ifdef MYVIA_NEED_LATCHING - if (IS_PA_INPUT_LATCH()) { + if (IS_PA_INPUT_LATCH() && (via_context->ifr & VIA_IM_CA1)) { byte = via_context->ila; - } else { + } else +#endif + { /* FIXME: side effects ? */ byte = (via_context->read_pra)(via_context, addr); } -#else - /* FIXME: side effects ? */ - byte = (via_context->read_pra)(via_context, addr); -#endif return byte; } case VIA_PRB: /* port B */ { - BYTE byte; + uint8_t byte; #ifdef MYVIA_NEED_LATCHING - if (IS_PB_INPUT_LATCH()) { + if (IS_PB_INPUT_LATCH() && (via_context->ifr & VIA_IM_CB1)) { byte = via_context->ilb; - } else { + } else +#endif + { /* FIXME: side effects ? */ byte = (via_context->read_prb)(via_context); } -#else - /* FIXME: side effects ? */ - byte = (via_context->read_prb)(via_context); -#endif byte = (byte & ~(via_context->via[VIA_DDRB])) | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]); - if (via_context->via[VIA_ACR] & 0x80) { - /* update_myviatal(via_context, rclk); */ - byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x) - | via_context->pb7o) ? 0x80 : 0); + if (via_context->via[VIA_ACR] & VIA_ACR_T1_PB7_USED) { + byte = (byte & 0x7f) | via_context->t1_pb7; } return byte; } @@ -885,25 +1261,25 @@ BYTE viacore_peek(via_context_t *via_context, WORD addr) /* Timers */ case VIA_T1CL /*TIMER_AL */: /* timer A low */ - return (BYTE)(myviata(via_context) & 0xff); + return (uint8_t)(viacore_t1(via_context, *(via_context->clk_ptr)) & 0xff); case VIA_T1CH /*TIMER_AH */: /* timer A high */ - return (BYTE)((myviata(via_context) >> 8) & 0xff); + return (uint8_t)((viacore_t1(via_context, *(via_context->clk_ptr)) >> 8) & 0xff); case VIA_T1LL: /* timer A low order latch */ case VIA_T1LH: /* timer A high order latch */ break; case VIA_T2CL /*TIMER_BL */: /* timer B low */ - return (BYTE)(myviatb(via_context) & 0xff); + return (uint8_t)(viacore_t2(via_context, *(via_context->clk_ptr)) & 0xff); case VIA_T2CH /*TIMER_BH */: /* timer B high */ - return (BYTE)((myviatb(via_context) >> 8) & 0xff); + return (uint8_t)((viacore_t2(via_context, *(via_context->clk_ptr)) >> 8) & 0xff); case VIA_IFR: /* Interrupt Flag Register */ return via_context->ifr; - case VIA_IER: /* 6522 Interrupt Control Register */ + case VIA_IER: /* 6522 Interrupt Enable Register */ return via_context->ier | 0x80; case VIA_PCR: @@ -944,8 +1320,7 @@ BYTE c64d_viacore_peek(via_context_t *via_context, WORD addr) byte = (byte & ~(via_context->via[VIA_DDRB])) | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]); if (via_context->via[VIA_ACR] & 0x80) { - byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x) - | via_context->pb7o) ? 0x80 : 0); + byte = (byte & 0x7f) | via_context->t1_pb7; /* VICE 3.10: pb7/pb7x/pb7o -> t1_pb7 */ } return byte; } @@ -953,18 +1328,18 @@ BYTE c64d_viacore_peek(via_context_t *via_context, WORD addr) /* Timers */ case VIA_T1CL /*TIMER_AL */ : /* timer A low */ - return (BYTE)(myviata(via_context) & 0xff); + return (BYTE)(viacore_t1(via_context, rclk) & 0xff); case VIA_T2CL /*TIMER_BL */ : /* timer B low */ - return (BYTE)(myviatb(via_context) & 0xff); + return (BYTE)(viacore_t2(via_context, rclk) & 0xff); /* Timers */ case VIA_T1CH /*TIMER_AH */ : /* timer A high */ - return (BYTE)((myviata(via_context) >> 8) & 0xff); + return (BYTE)((viacore_t1(via_context, rclk) >> 8) & 0xff); case VIA_T2CH /*TIMER_BH */ : /* timer B high */ - return (BYTE)((myviatb(via_context) >> 8) & 0xff); + return (BYTE)((viacore_t2(via_context, rclk) >> 8) & 0xff); case VIA_SR: /* Serial Port Shift Register */ return via_context->via[addr]; @@ -996,88 +1371,294 @@ BYTE c64d_viacore_peek(via_context_t *via_context, WORD addr) /* ------------------------------------------------------------------------- */ -static void viacore_intt1(CLOCK offset, void *data) +/* + * This alarm takes care of generating the T1 IRQ: VIA_IM_T1. + * It also toggles PB7. + * It runs after the T1 reads 0000. + */ +static void viacore_t1_zero_alarm(CLOCK offset, void *data) { CLOCK rclk; via_context_t *via_context = (via_context_t *)data; rclk = *(via_context->clk_ptr) - offset; + VIALOG2("viacore_t1_zero_alarm (%s) after T1=%04x\n", via_context->myname, viacore_t1(via_context, rclk)); -#ifdef MYVIA_TIMER_DEBUG - if (app_resources.debugFlag) { - log_message(via_context->log, "myvia timer A interrupt"); - } -#endif - - if (!(via_context->via[VIA_ACR] & 0x40)) { /* one-shot mode */ -#ifdef MYVIA_TIMER_DEBUG - log_message(via_context->log, - "MYVIA Timer A interrupt -- one-shot mode: next int won't happen"); -#endif - alarm_unset(via_context->t1_alarm); - via_context->tai = 0; + if (!(via_context->via[VIA_ACR] & VIA_ACR_T1_FREE_RUN)) { /* one-shot mode */ + VIALOG2("MYVIA Timer A interrupt -- one-shot mode: next int won't happen, t1zero := 0\n"); + alarm_unset(via_context->t1_zero_alarm); + via_context->t1zero = 0; } else { /* continuous mode */ - /* load counter with latch value */ - via_context->tai += via_context->tal + 2; - alarm_set(via_context->t1_alarm, via_context->tai); + /* we want another alarm for the next T1 interrupt */ + unsigned int full_cycle = via_context->tal + FULL_CYCLE_2; + via_context->t1zero += full_cycle; + alarm_set(via_context->t1_zero_alarm, via_context->t1zero); - /* Let tau also keep up with the cpu clock - this should avoid "% (via_context->tal + 2)" case */ - via_context->tau += via_context->tal + 2; + /* Let t1reload also keep up with the cpu clock; + this should avoid `% full_cycle` case. */ + via_context->t1reload += full_cycle; + + VIALOG2("viacore_t1_zero_alarm: re-set t1_zero_alarm at %lu, tal=%04x, t1reload=%lu\n", via_context->t1zero, via_context->tal, via_context->t1reload); } + + via_context->t1_pb7 ^= 0x80; + VIALOG2("viacore_t1_zero_alarm: set VIA_IM_T1\n"); via_context->ifr |= VIA_IM_T1; - update_myviairq_rclk(via_context, rclk); + /* It takes an extra cycle after the flag before the interrupt happens */ + update_myviairq_rclk(via_context, rclk + 1); +} + +/* ------------------------------------------------------------------------- */ + +/* + * Set the state of the CB2 output, if not controlled by the + * shift register. + */ +static void set_cb2_output_state(via_context_t *via_context, uint8_t pcr, int offset) +{ + uint8_t mode = pcr & VIA_PCR_CB2_CONTROL; + + if ((mode & VIA_PCR_CB2_I_OR_O) == VIA_PCR_CB2_INPUT) { + /* + * Don't lose our input, but do output a 1 + * for if somebody is listening. + */ + via_context->cb2_out_state = true; + (via_context->set_cb2)(via_context, true, offset); + } else { + switch (mode) { + case VIA_PCR_CB2_LOW_OUTPUT: + /* set output low */ + via_context->cb2_out_state = false; + break; + case VIA_PCR_CB2_HIGH_OUTPUT: + case VIA_PCR_CB2_PULSE_OUTPUT: + case VIA_PCR_CB2_HANDSHAKE_OUTPUT: + default: + /* FIXME: is this correct if handshake is already active? */ + via_context->cb2_out_state = true; + break; + } + (via_context->set_cb2)(via_context, via_context->cb2_out_state, offset); + } +} - /* TODO: toggle PB7? */ - /*(viaier & VIA_IM_T1) ? 1:0; */ +/* + * Because CB1 and CB2 can be used individually, or controlled by the + * shift register, determining if they are input or output is a bit + * complex. So we do it only once: here. + * + * To be called if either the ACR or the PCR changes. + */ + +static void viacore_cache_cb12_io_status(via_context_t *via_context) +{ + const uint8_t acr = via_context->via[VIA_ACR]; + const uint8_t pcr = via_context->via[VIA_PCR]; + + const bool cb1_drives_shifting = /* mask out the in/out bit */ + ((acr & VIA_ACR_SR_CONTROL & 0x0C) == VIA_ACR_SR_IN_CB1) || + ((acr & VIA_ACR_SR_CONTROL) == VIA_ACR_SR_DISABLED); + + const bool sr_is_input = + ((acr & VIA_ACR_SR_OUT) == VIA_ACR_SR_IN) && + ((acr & VIA_ACR_SR_CONTROL) != VIA_ACR_SR_DISABLED); + + const bool cb2_is_input = + (pcr & VIA_PCR_CB2_I_OR_O) == VIA_PCR_CB2_INPUT; + + /* + * If the shift register is disabled, it does apparently shift on CB1 + * pulses, but CB2 in/out status would be controlled in the PCR. + */ + via_context->cb1_is_input = cb1_drives_shifting; + via_context->cb2_is_input = sr_is_input || cb2_is_input; + + /* + * If shifting is idle, set CB1 to idle state 1 when it is an output. + */ + if (via_context->set_cb1 && + !via_context->cb1_is_input && + via_context->shift_state == FINISHED_SHIFTING) { + (via_context->set_cb1)(via_context, 1); + } } +/* ------------------------------------------------------------------------- */ + + +/* + * CB1 is the clock line for the shift register in/output, CB2. + * If MYVIA_NEED_LATCHING: It can also function to activate the latch on Port B. + */ + +void viacore_set_cb1(via_context_t *via_context, bool data) { + /* + * Is the shift register set to be under external control? + * Is the CB1 input changing? + */ + if (data != via_context->cb1_in_state) { + if (via_context->cb1_is_input) { + /* FIXME: Is this the right way to start shifting a byte? */ + if (!data && via_context->shift_state == FINISHED_SHIFTING) { + via_context->shift_state = START_SHIFTING; + } + + via_context->shift_state++; + + /* Is it rising? */ + if (data) { + /* Shift register IN; TODO: check this is the mode */ + via_context->via[VIA_SR] <<= 1; + via_context->via[VIA_SR] |= via_context->cb2_in_state; + + if (via_context->shift_state == FINISHED_SHIFTING) { + viacore_set_sr(via_context, via_context->via[VIA_SR]); + via_context->shift_state = START_SHIFTING; + } + } else { + /* TODO: the case of + * VIA_ACR_SR_OUT_CB1 0x1C + * mode 7 Shift out under control of an External Pulse + * which happens on the falling edge of CB1. + * (maybe keep separate cb1_drives_shifting flag?) +From http://forum.6502.org/viewtopic.php?f=4&t=7241&start=15#p94001 +The CB1 pad also works as the shift clock from/to the outerworld +when enabling "10) shift register", and that's why we have _another_ +(conceptually different) edge detector sensing the CB1 pad, +gated with PHI0=1 AND PHI2=1. + +If ACR4=0, the shift register shifts in, and the detector scans for CB1 rising edge. +If ACR4=1, the shift register shifts out, and the detector scans for CB1 falling edge. + +Low_active signal SR_CB1_DET# generated by the detector tells "22) shift register control" +to shift/count the next Bit. + */ + /* If shifting OUT, do it here */ + } + } + + via_context->cb1_in_state = (data != 0); + } + + /* + * Doing this unconditionally seems wrong, because then it doesn't + * actually detect edges. But having it inside the condition that + * checks for a changed input breaks SpeedDOS+. + */ + if (true) { + const uint8_t pcr = via_context->via[VIA_PCR]; + bool edge = (pcr & VIA_PCR_CB1_CONTROL) == VIA_PCR_CB1_POS_ACTIVE_EDGE; + + if (data == edge) { + if (IS_CB2_TOGGLE_MODE() && !(via_context->cb2_out_state)) { + via_context->cb2_out_state = 1; + (via_context->set_cb2)(via_context, via_context->cb2_out_state, 0); + } + /* Trigger CB1 interrupt */ + via_context->ifr |= VIA_IM_CB1; + update_myviairq(via_context); +#ifdef MYVIA_NEED_LATCHING + if (IS_PB_INPUT_LATCH()) { + via_context->ilb = (via_context->read_prb)(via_context); + } +#endif + } + } +} + +void viacore_set_cb2(via_context_t *via_context, bool data) +{ + if (via_context->cb2_is_input && + data != via_context->cb2_in_state) { + via_context->cb2_in_state = !!data; + + const uint8_t pcr = via_context->via[VIA_PCR]; + bool edge = (pcr & VIA_PCR_CB2_INPUT_POS_ACTIVE_EDGE) != 0; + + if (data == edge) { + /* Trigger CB2 interrupt */ + via_context->ifr |= VIA_IM_CB2; + update_myviairq(via_context); + } + } +} + + + /* WARNING: this is a hack, used to interface with c64fastiec.c, c128fastiec.c */ -void viacore_set_sr(via_context_t *via_context, BYTE data) +void viacore_set_sr(via_context_t *via_context, uint8_t data) { - if (!(via_context->via[VIA_ACR] & 0x10) && (via_context->via[VIA_ACR] & 0x0c)) { + if (!(via_context->via[VIA_ACR] & VIA_ACR_SR_OUT) && + (via_context->via[VIA_ACR] & 0x0c)) { via_context->via[VIA_SR] = data; + /* TODO: Setting VIA_IM_SR may need a delay of 1 clock */ via_context->ifr |= VIA_IM_SR; update_myviairq(via_context); - via_context->shift_state = 15; + via_context->shift_state = FINISHED_SHIFTING; + + VIALOG2("burstmodehack engaged... data %02x\n", data); } } -static inline void do_shiftregister(CLOCK offset, void *data) +/* ------------------------------------------------------------------------- */ + +/* T2 can be switched between 8 and 16 bit modes ad-hoc, any time, by setting + the shifter to be controlled by T2 via selecting the relevant ACR shift + register operating mode. + This change affects how the next T2 low underflow is handled. + + This alarm should be enabled only when the timer is in 8-bit mode, or still + has to generate its first IRQ (reach its first 16-bit underflow). + But not if T2 is in pulse counting mode. + + Alarm functions for cycle N are called after the CPU has run the memory + access for cycle N. Furthermore they are typically run after the whole + instruction so offset tells you how many cycles to go back. + + Called due to t2_zero_alarm. + */ +static void viacore_t2_zero_alarm(CLOCK offset, void *data) { CLOCK rclk; via_context_t *via_context = (via_context_t *)data; + rclk = *(via_context->clk_ptr) - offset; + VIALOG2("viacore_t2_zero_alarm %2x %2x t2xx00 %d offset %lu rclk %lu after T2=%04x\n", via_context->t2ch, via_context->t2cl, via_context->t2xx00, offset, rclk, viacore_t2(via_context, rclk)); - if (via_context->shift_state < 16) { - /* FIXME: CB1 should be toggled, and interrupt flag set according to edge detection in PCR */ - if (via_context->shift_state & 1) { - if (via_context->via[VIA_ACR] & 0x10) { - /* FIXME: shift out */ - via_context->via[VIA_SR] = ((via_context->via[VIA_SR] << 1 ) & 0xfe) | ((via_context->via[VIA_SR] >> 7) & 1); - } else { - /* shift in */ - /* FIXME: we should read CB2 here instead of 1, but CB2 state must not be controlled by PCR - until the signalling function is correct with shifter active, just use 1 instead */ - via_context->via[VIA_SR] = (via_context->via[VIA_SR] << 1 ) | 1; - } - } - via_context->shift_state += 1; - /* next shifter bit; set SR interrupt if 8 bits are complete */ - if (via_context->shift_state == 16) { - via_context->ifr |= VIA_IM_SR; - update_myviairq_rclk(via_context, rclk); - via_context->shift_state = 0; - } + /* T2 low count underflow always decreases T2 high count */ + via_context->t2ch--; + VIALOG2("viacore_t2_zero_alarm %2x %2x (decremented) offset %lu rclk %lu\n", via_context->t2ch, via_context->t2cl, offset, rclk); + + /* + * 16 bit timer underflow generates an interrupt. + * Q: Can 16 bit underflow generate an IRQ in 8 bit mode? + * 8 bit underflow does not. + * A: YES. See viavarious/via20 + */ + + if (via_context->t2ch == 0xff && via_context->t2_irq_allowed) { + /* + * At this point, we check t2_irq_allowed; + * each write to T2H is supposed to trigger no more than one IRQ. + */ + via_context->ifr |= VIA_IM_T2; + update_myviairq_rclk(via_context, rclk); + via_context->t2_irq_allowed = false; + VIALOG2("viacore_t2_zero_alarm set VIA_IM_T2 at (after) %lu\n", rclk); } + + alarm_unset(via_context->t2_zero_alarm); + alarm_set(via_context->t2_underflow_alarm, rclk + 1); } -/* T2 can be switched between 8 and 16 bit modes ad-hoc, any time, by setting - the shifter to be controlled by T2 via selecting the relevant ACR shift - register operating mode. - This change affects how the next T2 low underflow is handled */ -static void viacore_intt2(CLOCK offset, void *data) +/* + * Called after T2 underflows (i.e. it has shown xxFF), and it has + * to decide if the latch gets reloaded into the counter, or not. + * If so, there may be a shift action another cycle later. + */ +static void viacore_t2_underflow_alarm(CLOCK offset, void *data) { CLOCK rclk; int next_alarm; @@ -1085,11 +1666,6 @@ static void viacore_intt2(CLOCK offset, void *data) rclk = *(via_context->clk_ptr) - offset; -#ifdef MYVIA_TIMER_DEBUG - if (app_resources.debugFlag) { - log_message(via_context->log, "MYVIA timer B interrupt."); - } -#endif /* If the shifter is under T2 control, the T2 timer works differently, and have a period of T2 low. T2 high is still cascaded though and decreases at each T2 low underflow */ if ((via_context->via[VIA_ACR] & 0x0c) == 0x04) { @@ -1097,96 +1673,225 @@ static void viacore_intt2(CLOCK offset, void *data) via_context->t2cl = via_context->via[VIA_T2LL]; /* set next alarm to T2 low period */ - next_alarm = via_context->via[VIA_T2LL] + 2; + next_alarm = via_context->via[VIA_T2LL] + FULL_CYCLE_2; /* T2 acts as a pulse generator for CB1 - every second underflow is a pulse updating the shift register, + every second underflow is a pulse updating the shift register, until all 8 bits are complete */ - do_shiftregister(offset, data); - } else if ((via_context->via[VIA_ACR] & 0x1c) == 0x10) { + alarm_set(via_context->t2_shift_alarm, rclk + 1); + } else if (IS_SR_FREE_RUNNING()) { + /* Free-running output */ + /* Should we copy the latch to T2 low, as above? */ + via_context->t2cl = via_context->via[VIA_T2LL]; /* set next alarm to T2 low period */ - next_alarm = via_context->via[VIA_T2LL] + 2; + next_alarm = via_context->via[VIA_T2LL] + FULL_CYCLE_2; /* same as above, except bits will we clocked out CB2 repeatedly without * stopping after 8 bits */ - do_shiftregister(offset, data); + alarm_set(via_context->t2_shift_alarm, rclk + 1); } else { /* 16 bit timer mode; it is guaranteed that T2 low is in underflow */ via_context->t2cl = 0xff; - /* set next alarm to 256 cycles later, until t2 high underflow */ - next_alarm = (via_context->t2ch) ? 256 : 0; + /* Set next alarm to 256 cycles later, until t2 high underflow. + * Each write to T2H should generate only one irq at the first underflow. + * If we don't need another IRQ, don't re-arm the alarm. + */ + next_alarm = (via_context->t2ch != 0xff) ? 256 : 0; } - /* T2 low count underflow always decreases T2 high count */ - via_context->t2ch--; - - /* set the next T2 low underflow alarm, or turn off the alarm */ + /* set the next T2 low zero alarm, or turn off the alarm */ if (next_alarm) { - via_context->tbu += next_alarm; - via_context->tbi += next_alarm; - alarm_set(via_context->t2_alarm, via_context->tbi); + via_context->t2zero += next_alarm; + via_context->t2xx00 = true; + alarm_set(via_context->t2_zero_alarm, via_context->t2zero); } else { - alarm_unset(via_context->t2_alarm); - via_context->tbi = 0; + alarm_unset(via_context->t2_zero_alarm); + /* + * Switch to 16-bit counter calculation. + * This is ok since the current clock is 1 after t2_zero, + * and T2 reads 0xFFFF aka -1. + */ + via_context->t2xx00 = false; } - /* 16 bit timer underflow generates an interrupt */ - /* FIXME: does 16 bit underflow generate an IRQ in 8 bit mode? 8 bit underflow does not */ - /* FIXME: no IRQ when shift register is in free running mode? */ - if (via_context->t2ch == 0xff) { - via_context->ifr |= VIA_IM_T2; - update_myviairq_rclk(via_context, rclk); - } + alarm_unset(via_context->t2_underflow_alarm); } -/* alarm callback for the case when the shift register is under phi2 control */ -static void viacore_intsr(CLOCK offset, void *data) +/* + * This function is there to delay the actual shifting of the shift + * register. It is supposed to shift AFTER Timer 2 has been reloaded from + * the latch. + * + * Whether there is a shift at all, depends on the ACR. + * It is so far unknown if + * - the decision is made (based on the ACR), and if yes, then there is always + * a shift later + * or + * - the decision to shift (or not) is made after the delay and then in happens + * immediately. + * + * There might be a difference if the ACR is written to at an unfortuate moment. + * + * This code implements the first version. + * (Simulation of the VIA from https://github.com/hoglet67/BeebFpga/blob/master/src/common/m6522.vhd + * suggests that reloading from the latch and the shift + * either both happen, or both don't happen) + */ + +/* + * Alarm callback for the case when the shift register is delayed by 1 clock. + * + * Called due to t2_shift_alarm. + */ +static void viacore_t2_shift_alarm(CLOCK offset, void *data) { - CLOCK rclk; via_context_t *via_context = (via_context_t *)data; - rclk = *(via_context->clk_ptr) - offset; - do_shiftregister(offset, data); - alarm_set(via_context->sr_alarm, rclk + 1); + +#if CHECK_CPU_VS_ALARM_CLOCKS + CLOCK rclk = *(via_context->clk_ptr) - offset; + last_alarm_clock = rclk; + if (last_cpu_clock == last_alarm_clock) { + VIALOG9("alarm after cpu access %lu (expected)\n", rclk); + } +#endif + + VIALOG2("viacore_shift_alarm: offset %ld rclk %lu SR %02x shift_state %d\n", (int64_t)offset, rclk, via_context->via[VIA_SR], via_context->shift_state); + do_shiftregister(offset, via_context); + alarm_unset(via_context->t2_shift_alarm); } -static void viacore_clk_overflow_callback(CLOCK sub, void *data) +static inline void do_shiftregister(CLOCK offset, via_context_t *via_context) { - via_context_t *via_context; + CLOCK rclk; + rclk = *(via_context->clk_ptr) - offset; - via_context = (via_context_t *)data; + VIALOG2("do_shiftregister: ->shift_state = %d %02x %lu\n", via_context->shift_state, via_context->via[VIA_SR], rclk); + if (via_context->shift_state < FINISHED_SHIFTING) { + /* + * When shifting out, it shifts first and then waits (holding the + * value), but when shifting in, it waits first and then shifts. + * + * Input bits are sampled on the RISING edge of the clock (CB1) + * (and they change at the falling edge). + * + *> Something seems off though: + *> https://twitter.com/RueNahcMohr/status/1571705526911905793: + *>* -When you access the shift register, it starts another transfer cycle, NOT. + *>* It gets ready to. The timer has to hit zero before it starts. + *>* THEN the first cycle is with CB1 _HIGH_! (same as idle..) + *> + *> Are the even and odd actions swapped? + *> Then we also need to set CB1 high again when shifting finishes. + *> It seems to imply 9 timer underflows per byte, though. + *> Also, via_sr tests which read out the SR would fail; it would + *> need decoupling of the shifting from CB1's falling edge and its + *> change in the CB2 output (the latter should stay at the falling edge). + *> On the other hand, this is probably about IN_T2, not OUT_T2, and that + *> is not covered by our tests. + * + * We should not be getting here if we are shifting in or out under + * control of CB1 (or is disabled). + */ + const uint8_t acr = via_context->via[VIA_ACR]; + const int shift_out = acr & VIA_ACR_SR_OUT; + + if ((via_context->shift_state & 1) == 0) { + /* Even state: set CB1 low, in the right modes. */ + if (!via_context->cb1_is_input) { + if (via_context->set_cb1) { + (via_context->set_cb1)(via_context, 0); + } + /* FIXME: and set interrupt flag according to + * edge detection in PCR? In hardware, there is also a special + * SR-related edge detector which triggers the actual shifting + * and counting, the code for which is cut short and + * duplicated here. */ + } - if (via_context->enabled == 0) { - return; - } + if (shift_out) { + /* Shift out */ + int cb2 = (via_context->via[VIA_SR] >> 7) & 1; + via_context->via[VIA_SR] = (via_context->via[VIA_SR] << 1) | cb2; + /* According to Rockwell figure 26, after CB1 is set low, + * 1 clock later CB2 is set (and presumably the shift happens). + * Commodore figure 11 shows first CB2 being set and ~half a clock + * later CB1 goes low. + */ + via_context->cb2_out_state = cb2; + /* + * For sound output we need to have an accurate clock, with offset + * taken into account. + */ + (via_context->set_cb2)(via_context, cb2, (int)offset); + } + } else { + /* Odd state: set CB1 high, in the right modes. */ + if (!via_context->cb1_is_input) { + if (via_context->set_cb1) { + (via_context->set_cb1)(via_context, 1); + } + /* FIXME: and set interrupt flag according to + * edge detection in PCR? */ + } -#if 0 - via_context->tau = via_context->tal + 2 - - ((*(via_context->clk_ptr) + sub - via_context->tau) - % (via_context->tal + 2)); + if (!shift_out) { + /* Shift in */ + via_context->via[VIA_SR] = (via_context->via[VIA_SR] << 1) + | via_context->cb2_in_state; + } + } - via_context->tbu = via_context->tbl + 2 - - ((*(via_context->clk_ptr) + sub - via_context->tbu) - % (via_context->tbl + 2)); -#else - via_context->tau -= sub; - via_context->tbu -= sub; -#endif + /* + * "(shift on CB1 rising edge should occur even in SR disabled mode). " + * comment from https://github.com/mikestir/fpga-bbc + * also mentioned by Rockwell but not CBM/MOS. + */ - if (via_context->tai) { - via_context->tai -= sub; - } + via_context->shift_state += 1; + /* next shifter bit; set SR interrupt if 8 bits are complete */ + if (via_context->shift_state == FINISHED_SHIFTING) { + /* In free running mode, the counter is "disabled" and no + * SR interrupt flags are set. + * We have no test case for this. + * Nor for a case where a "disabled" counter is switched to + * a mode with "enabled" counter. + */ + if (IS_SR_FREE_RUNNING()) { + via_context->shift_state = START_SHIFTING; + } else { + via_context->ifr |= VIA_IM_SR; + update_myviairq_rclk(via_context, rclk); - if (via_context->tbi) { - via_context->tbi -= sub; + if (via_context->sr_underflow) { + via_context->sr_underflow(via_context); + } + } + } } +} - if (via_context->read_clk > sub) { - via_context->read_clk -= sub; - } else { - via_context->read_clk = 0; +/* alarm callback for the case when the shift register is under phi2 control */ +static void viacore_phi2_sr_alarm(CLOCK offset, void *data) +{ + CLOCK rclk; + via_context_t *via_context = (via_context_t *)data; + rclk = *(via_context->clk_ptr) - offset; +#if CHECK_CPU_VS_ALARM_CLOCKS + last_alarm_clock = rclk; + if (last_cpu_clock == last_alarm_clock) { + VIALOG9("alarm after cpu access %lu (expected)\n", rclk); } +#endif /* CHECK_CPU_VS_ALARM_CLOCKS */ + VIALOG2("viacore_phi2_sr_alarm: offset %ld rclk %lu SR %02x shift_state %d\n", (int64_t)offset, rclk, via_context->via[VIA_SR], via_context->shift_state); + do_shiftregister(offset, data); + /* + * Possible optimization: don't re-arm the alarm when the shifting is done. + * Difficulty: When arming it again later, the correct start-up delay must + * be used. + */ + alarm_set(via_context->phi2_sr_alarm, rclk + SR_PHI2_NEXT_OFFSET); } void viacore_setup_context(via_context_t *via_context) @@ -1196,7 +1901,7 @@ void viacore_setup_context(via_context_t *via_context) via_context->read_clk = 0; via_context->read_offset = 0; via_context->last_read = 0; - via_context->log = LOG_ERR; + via_context->log = LOG_DEFAULT; via_context->my_module_name_alt1 = NULL; via_context->my_module_name_alt2 = NULL; @@ -1211,36 +1916,50 @@ void viacore_setup_context(via_context_t *via_context) via_context->via[5] = via_context->via[7] = 223; /* my vic20 gives 223 here (gpz) */ via_context->via[8] = 0xff; via_context->via[9] = 0xff; + + /* Not internal but external state, really, so not set on reset */ + via_context->cb1_in_state = true; + via_context->cb2_in_state = true; + + via_context->sr_underflow = NULL; + via_context->set_cb1 = NULL; + via_context->t2_irq_allowed = false; } void viacore_init(via_context_t *via_context, alarm_context_t *alarm_context, - interrupt_cpu_status_t *int_status, clk_guard_t *clk_guard) + interrupt_cpu_status_t *int_status) { char *buffer; - if (via_context->log == LOG_ERR) { + if (via_context->log == LOG_DEFAULT) { via_context->log = log_open(via_context->my_module_name); } - - // c64d: C64 debugger - via_context->c64d_irq_flagged = 0; - - - buffer = lib_msprintf("%sT1", via_context->myname); - via_context->t1_alarm = alarm_new(alarm_context, buffer, viacore_intt1, via_context); + VICE_HOOK_VIA_IRQ_FLAG_CLEAR(via_context); + + via_context->alarm_context = alarm_context; + + buffer = lib_msprintf("%sT1zero", via_context->myname); + via_context->t1_zero_alarm = alarm_new(alarm_context, buffer, viacore_t1_zero_alarm, via_context); + lib_free(buffer); + + buffer = lib_msprintf("%sT2zero", via_context->myname); + via_context->t2_zero_alarm = alarm_new(alarm_context, buffer, viacore_t2_zero_alarm, via_context); + lib_free(buffer); + + buffer = lib_msprintf("%sT2uflow", via_context->myname); + via_context->t2_underflow_alarm = alarm_new(alarm_context, buffer, viacore_t2_underflow_alarm, via_context); lib_free(buffer); - buffer = lib_msprintf("%sT2", via_context->myname); - via_context->t2_alarm = alarm_new(alarm_context, buffer, viacore_intt2, via_context); + buffer = lib_msprintf("%sT2SR", via_context->myname); + via_context->t2_shift_alarm = alarm_new(alarm_context, buffer, viacore_t2_shift_alarm, via_context); lib_free(buffer); buffer = lib_msprintf("%sSR", via_context->myname); - via_context->sr_alarm = alarm_new(alarm_context, buffer, viacore_intsr, via_context); + via_context->phi2_sr_alarm = alarm_new(alarm_context, buffer, viacore_phi2_sr_alarm, via_context); lib_free(buffer); via_context->int_num = interrupt_cpu_status_int_new(int_status, via_context->myname); - clk_guard_add_callback(clk_guard, viacore_clk_overflow_callback, via_context); } void viacore_shutdown(via_context_t *via_context) @@ -1257,32 +1976,41 @@ void viacore_shutdown(via_context_t *via_context) /* The name of the modul must be defined before including this file. */ #define VIA_DUMP_VER_MAJOR 2 -#define VIA_DUMP_VER_MINOR 1 +#define VIA_DUMP_VER_MINOR 2 /* * The dump data: * + * Minor version 1: + * * UBYTE ORA * UBYTE DDRA * UBYTE ORB * UBYTE DDRB - * UWORD T1L - * UWORD T1C + * UWORD T1L word1 via_context->tal + * UWORD T1C word2 viacore_t1() * UBYTE T2LL * UBYTE T2LH * UBYTE T2CL * UBYTE T2CH - * UWORD T2C + * UWORD T2C word3 viacore_t2() + * UBYTE 0x80:t1zero | 0x40:t2xx00 byte1 * UBYTE SR * UBYTE ACR * UBYTE PCR * UBYTE IFR active interrupts * UBYTE IER interrupt masks - * UBYTE PB7 bit 7 = pb7 state + * UBYTE PB7 byte4 bit 7 = pb7 state * UBYTE SRHBITS shift register state helper - * UBYTE CABSTATE bit 7 = ca2 state, bi 6 = cb2 state + * UBYTE CABSTATE byte6 bit 7 = ca2 state, bit6 = cb2 state, bi5 = cb1 * UBYTE ILA input latch port A * UBYTE ILB input latch port B + * + * Minor version 2 adds: + * + * UBYTE t2_irq_allowed + * UBYTE t2_underflow_alarm 0 if not; 1+time delta if set. + * UBYTE t2_shift_alarm 0 if not; 1+time delta if set. */ /* FIXME!!! Error check. */ @@ -1290,15 +2018,10 @@ void viacore_shutdown(via_context_t *via_context) int viacore_snapshot_write_module(via_context_t *via_context, snapshot_t *s) { snapshot_module_t *m; + CLOCK rclk = *(via_context->clk_ptr); + uint8_t byte4; - if (via_context->tai && (via_context->tai <= *(via_context->clk_ptr))) { - viacore_intt1(*(via_context->clk_ptr) - via_context->tai, - (void *)via_context); - } - if (via_context->tbi && (via_context->tbi <= *(via_context->clk_ptr))) { - viacore_intt2(*(via_context->clk_ptr) - via_context->tbi, - (void *)via_context); - } + run_pending_alarms(rclk, 0, via_context->alarm_context); m = snapshot_module_create(s, via_context->my_module_name, VIA_DUMP_VER_MAJOR, VIA_DUMP_VER_MINOR); @@ -1306,45 +2029,70 @@ int viacore_snapshot_write_module(via_context_t *via_context, snapshot_t *s) return -1; } + byte4 = via_context->t1_pb7 & 0x80; + if (0 || SMW_B(m, via_context->via[VIA_PRA]) < 0 || SMW_B(m, via_context->via[VIA_DDRA]) < 0 || SMW_B(m, via_context->via[VIA_PRB]) < 0 || SMW_B(m, via_context->via[VIA_DDRB]) < 0 - || SMW_W(m, (WORD)(via_context->tal)) < 0 - || SMW_W(m, (WORD)myviata(via_context)) < 0 + || SMW_W(m, (uint16_t)(via_context->tal)) < 0 + || SMW_W(m, (uint16_t)viacore_t1(via_context, rclk)) < 0 || SMW_B(m, via_context->via[VIA_T2LL]) < 0 || SMW_B(m, via_context->via[VIA_T2LH]) < 0 || SMW_B(m, via_context->t2cl) < 0 || SMW_B(m, via_context->t2ch) < 0 - || SMW_W(m, (WORD)myviatb(via_context)) < 0 - || SMW_B(m, (BYTE)((via_context->tai ? 0x80 : 0) | (via_context->tbi ? 0x40 : 0))) < 0 + || SMW_W(m, (uint16_t)viacore_t2(via_context, *(via_context->clk_ptr))) < 0 + || SMW_B(m, (uint8_t)((via_context->t1zero ? 0x80 : 0) | (via_context->t2xx00 ? 0x40 : 0))) < 0 || SMW_B(m, via_context->via[VIA_SR]) < 0 || SMW_B(m, via_context->via[VIA_ACR]) < 0 || SMW_B(m, via_context->via[VIA_PCR]) < 0 - || SMW_B(m, (BYTE)(via_context->ifr)) < 0 - || SMW_B(m, (BYTE)(via_context->ier)) < 0 - /* FIXME! */ - || SMW_B(m, (BYTE)((((via_context->pb7 ^ via_context->pb7x) | via_context->pb7o) ? 0x80 : 0))) < 0 + || SMW_B(m, (uint8_t)(via_context->ifr)) < 0 + || SMW_B(m, (uint8_t)(via_context->ier)) < 0 + || SMW_B(m, byte4) < 0 /* SRHBITS */ - || SMW_B(m, (BYTE)via_context->shift_state) < 0 - || SMW_B(m, (BYTE)((via_context->ca2_state ? 0x80 : 0) | (via_context->cb2_state ? 0x40 : 0))) < 0 + || SMW_B(m, (uint8_t)via_context->shift_state) < 0 + || SMW_B(m, (uint8_t)((via_context->ca2_out_state ? 0x80 : 0) | + (via_context->cb2_out_state ? 0x40 : 0) | + (via_context->cb2_in_state ? 0x40 : 0) | + (via_context->cb1_in_state ? 0x20 : 0) | + (via_context->cb1_out_state ? 0x20 : 0))) < 0 || SMW_B(m, via_context->ila) < 0 || SMW_B(m, via_context->ilb) < 0) { snapshot_module_close(m); return -1; } + /* Add stuff for minor version 2 */ + uint8_t m2_t2_underflow_alarm, m2_t2_shift_alarm; + CLOCK tmpclock; + + tmpclock = alarm_clk(via_context->t2_underflow_alarm); + m2_t2_underflow_alarm = tmpclock ? 1 + tmpclock - rclk + : 0; + tmpclock = alarm_clk(via_context->t2_shift_alarm); + m2_t2_shift_alarm = tmpclock ? 1 + tmpclock - rclk + : 0; + + if (0 + || SMW_B(m, via_context->t2_irq_allowed) < 0 + || SMW_B(m, m2_t2_underflow_alarm) < 0 + || SMW_B(m, m2_t2_shift_alarm) < 0) { + snapshot_module_close(m); + return -1; + } + return snapshot_module_close(m); } int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) { - BYTE vmajor, vminor; - BYTE byte; - BYTE byte1, byte2, byte3, byte4, byte5, byte6; - WORD word1, word2, word3; - WORD addr; + uint8_t vmajor, vminor; + uint8_t byte; + uint8_t byte1, byte2, byte3, byte4, byte5, byte6; + uint16_t word1, word2, word3; + uint16_t addr; + uint8_t m2_t2_irq_allowed, m2_t2_underflow_alarm, m2_t2_shift_alarm; CLOCK rclk = *(via_context->clk_ptr); snapshot_module_t *m; @@ -1377,18 +2125,20 @@ int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) return -1; } /* Do not accept versions higher than current */ - if (vminor > VIA_DUMP_VER_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, VIA_DUMP_VER_MAJOR, VIA_DUMP_VER_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; } - alarm_unset(via_context->t1_alarm); - alarm_unset(via_context->t2_alarm); - alarm_unset(via_context->sr_alarm); + alarm_unset(via_context->t1_zero_alarm); + alarm_unset(via_context->t2_zero_alarm); + alarm_unset(via_context->t2_underflow_alarm); + alarm_unset(via_context->t2_shift_alarm); /* TODO: load from snapshot */ + alarm_unset(via_context->phi2_sr_alarm); - via_context->tai = 0; - via_context->tbi = 0; + via_context->t1zero = 0; + via_context->t2xx00 = false; if (0 || SMR_B(m, &(via_context->via[VIA_PRA])) < 0 @@ -1418,6 +2168,16 @@ int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) snapshot_module_close(m); return -1; } + /* Read minor version 2 data */ + if (0 + || SMR_B(m, &m2_t2_irq_allowed) < 0 + || SMR_B(m, &m2_t2_underflow_alarm) < 0 + || SMR_B(m, &m2_t2_shift_alarm) < 0) { + /* Set defaults. This will be some level of imperfect state restoration */ + m2_t2_irq_allowed = 1; + m2_t2_underflow_alarm = 0; + m2_t2_shift_alarm = 0; + } addr = VIA_DDRA; byte = via_context->via[VIA_PRA] | ~(via_context->via[VIA_DDRA]); @@ -1433,28 +2193,31 @@ int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) via_context->via[VIA_T1LL] = via_context->tal & 0xff; via_context->via[VIA_T1LH] = (via_context->tal >> 8) & 0xff; - via_context->tau = rclk + word2 + 2 /* 3 */ + TAUOFFSET; - via_context->tai = rclk + word2 + 1; + via_context->t1reload = rclk + word2 + FULL_CYCLE_2 /* 3 */; + via_context->t1zero = rclk + word2 + 0 /* 1 */; - via_context->tbu = rclk + word3 + 2 /* 3 */; - via_context->tbi = rclk + word3 + 0; + /* word3 is the effective value of T2 */ + /* I think t2xx00 and t2zero are set wrong; should probably use word3 & 0xFF */ + via_context->t2zero = rclk + (word3 & 0xFF); + via_context->t2xx00 = true; if (byte1 & 0x80) { - alarm_set(via_context->t1_alarm, via_context->tai); + alarm_set(via_context->t1_zero_alarm, via_context->t1zero); } else { - via_context->tai = 0; + via_context->t1zero = 0; } - if ((byte1 & 0x40) || + if ((byte1 & 0x40) || ((via_context->via[VIA_ACR] & 0x1c) == 0x04) || ((via_context->via[VIA_ACR] & 0x1c) == 0x10) || ((via_context->via[VIA_ACR] & 0x1c) == 0x14)){ - alarm_set(via_context->t2_alarm, via_context->tbi); + alarm_set(via_context->t2_zero_alarm, via_context->t2zero); } else { - via_context->tbi = 0; + via_context->t2zero = rclk + word3; + via_context->t2xx00 = 0; } /* FIXME: SR alarm */ if ((via_context->via[VIA_ACR] & 0x0c) == 0x08) { - alarm_set(via_context->sr_alarm, rclk + 1); + alarm_set(via_context->phi2_sr_alarm, rclk + 1); } via_context->ifr = byte2; @@ -1462,14 +2225,24 @@ int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) via_restore_int(via_context, via_context->ifr & via_context->ier & 0x7f); - /* FIXME! */ - via_context->pb7 = byte4 ? 1 : 0; - via_context->pb7x = 0; - via_context->pb7o = 0; + via_context->t1_pb7 = byte4 & 0x80; via_context->shift_state = byte5; - via_context->ca2_state = byte6 & 0x80; - via_context->cb2_state = byte6 & 0x40; + via_context->ca2_out_state = (byte6 & 0x80) != 0; + via_context->cb2_out_state = (byte6 & 0x40) != 0; + via_context->cb2_in_state = (byte6 & 0x20) != 0; + via_context->cb1_in_state = (byte6 & 0x10) != 0; + via_context->cb1_out_state = (byte6 & 0x08) != 0; + + via_context->t2_irq_allowed = m2_t2_irq_allowed; + + if (m2_t2_underflow_alarm) { + alarm_set(via_context->t2_underflow_alarm, rclk + m2_t2_underflow_alarm - 1); + } + + if (m2_t2_shift_alarm) { + alarm_set(via_context->t2_shift_alarm, rclk + m2_t2_shift_alarm - 1); + } /* undump_pcr also restores the ca2_state/cb2_state effects if necessary; i.e. calls set_c*2(c*2_state) if necessary */ @@ -1485,24 +2258,58 @@ int viacore_snapshot_read_module(via_context_t *via_context, snapshot_t *s) byte = via_context->via[addr]; (via_context->undump_acr)(via_context, byte); + viacore_cache_cb12_io_status(via_context); + return snapshot_module_close(m); } int viacore_dump(via_context_t *via_context) { mon_out("Port A: %02x DDR: %02x no HS: %02x\n", - viacore_peek(via_context, 0x01), viacore_peek(via_context, 0x03), viacore_peek(via_context, 0x0f)); - mon_out("Port B: %02x DDR: %02x\n", viacore_peek(via_context, 0x00), viacore_peek(via_context, 0x02)); - mon_out("Timer 1: %04x Latch: %04x\n", viacore_peek(via_context, 0x04) + (viacore_peek(via_context, 0x05) * 256), - viacore_peek(via_context, 0x06) + (viacore_peek(via_context, 0x07) * 256)); - mon_out("Timer 2: %04x\n", viacore_peek(via_context, 0x08) + (viacore_peek(via_context, 0x09) * 256)); - mon_out("Aux. control: %02x\n", viacore_peek(via_context, 0x0b)); - mon_out("Per. control: %02x\n", viacore_peek(via_context, 0x0c)); - mon_out("IRQ flags: %02x\n", viacore_peek(via_context, 0x0d)); - mon_out("IRQ enable: %02x\n", viacore_peek(via_context, 0x0e)); - mon_out("\nSynchronous Serial I/O Data Buffer: %02x (%s, shifting %s)\n", - viacore_peek(via_context, 0x0a), + viacore_peek(via_context, VIA_PRA), viacore_peek(via_context, VIA_DDRA), viacore_peek(via_context, VIA_PRA_NHS)); + mon_out("Port B: %02x DDR: %02x\n", viacore_peek(via_context, VIA_PRB), viacore_peek(via_context, VIA_DDRB)); + mon_out("Timer 1: %04x Latch: %04x\n", viacore_peek(via_context, VIA_T1CL) + (viacore_peek(via_context, VIA_T1CH) * 256U), + viacore_peek(via_context, VIA_T1LL) + (viacore_peek(via_context, VIA_T1LH) * 256U)); + mon_out("Timer 2: %04x Latch: %02x t2_zero_alarm: +%"PRIu64" (idx %d)\n", + viacore_peek(via_context, VIA_T2CL) + (viacore_peek(via_context, VIA_T2CH) * 256U), + via_context->via[VIA_T2LL], + alarm_clk(via_context->t2_zero_alarm) - *(via_context->clk_ptr), + via_context->t2_zero_alarm->pending_idx); + mon_out("Aux. control: %02x\n", viacore_peek(via_context, VIA_ACR)); + mon_out("Per. control: %02x\n", viacore_peek(via_context, VIA_PCR)); + mon_out("IRQ flags: %02x\n", viacore_peek(via_context, VIA_IFR)); + mon_out("IRQ enable: %02x\n", viacore_peek(via_context, VIA_IER)); + mon_out("\nShift Register: %02x (%s, shifting %s, count=%d)\n", + viacore_peek(via_context, VIA_SR), ((via_context->via[VIA_ACR] & 0x1c) == 0) ? "disabled" : "enabled", - (via_context->via[VIA_ACR] & 0x10) ? "out" : "in"); + (via_context->via[VIA_ACR] & 0x10) ? "out" : "in", + via_context->shift_state); + mon_out("t1zero: %"PRIu64" (clock+%ld), t1reload: %"PRIu64" (clock+%ld)\n", + via_context->t1zero, + (long)(via_context->t1zero - *(via_context->clk_ptr)), + via_context->t1reload, + (long)(via_context->t1reload - *(via_context->clk_ptr))); + mon_out("t1_pb7: %02x\n", (uint8_t)via_context->t1_pb7); + mon_out("t2xx00: %d, t2zero: %"PRIu64" (clock+%ld)\n", + via_context->t2xx00, + via_context->t2zero, + (long)(via_context->t2zero - *(via_context->clk_ptr))); + if (alarm_is_pending(via_context->t2_underflow_alarm)) { + mon_out("t2_underflow_alarm: %"PRIu64" (clock+%ld)\n", + alarm_clk(via_context->t2_underflow_alarm), + (long)(alarm_clk(via_context->t2_underflow_alarm) - *(via_context->clk_ptr))); + } + if (alarm_is_pending(via_context->t2_underflow_alarm)) { + mon_out("t2_shift_alarm: %"PRIu64" (clock+%ld)\n", + alarm_clk(via_context->t2_shift_alarm), + (long)(alarm_clk(via_context->t2_shift_alarm) - *(via_context->clk_ptr))); + } + if (alarm_is_pending(via_context->phi2_sr_alarm)) { + mon_out("phi2_sr_alarm: %"PRIu64" (clock+%ld)\n", + alarm_clk(via_context->phi2_sr_alarm), + (long)(alarm_clk(via_context->phi2_sr_alarm) - *(via_context->clk_ptr))); + } + return 0; } + diff --git a/src/Emulators/vice/diag/c64_diag_586220_harness.c b/src/Emulators/vice/diag/c64_diag_586220_harness.c index c3b2c0ad..94011347 100644 --- a/src/Emulators/vice/diag/c64_diag_586220_harness.c +++ b/src/Emulators/vice/diag/c64_diag_586220_harness.c @@ -30,20 +30,38 @@ #include #include "c64_diag_586220_harness.h" +#include "c64.h" +#include "cia.h" #include "datasette.h" +#include "machine.h" +#include "tapeport.h" #include "vicetypes.h" +#include "log.h" -static BYTE c64_diag_userport_pax = 0; -static BYTE c64_diag_userport_pbx = 0; -static BYTE c64_diag_userport_sp1 = 0; -static BYTE c64_diag_userport_sp2 = 0; -static BYTE c64_diag_tapeport = 0; -static BYTE c64_diag_joyport0 = 0; -static BYTE c64_diag_joyport1 = 0; -static BYTE c64_diag_keyboard_pax = 0; -static BYTE c64_diag_keyboard_pbx = 0; -static BYTE c64_diag_serial = 0; -static BYTE c64_diag_switches = 0; +/*#define DEBUG_DIAG_586220*/ + +#ifdef DEBUG_DIAG_586220 +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +static uint8_t c64_diag_userport_pax = 0; +static uint8_t c64_diag_userport_pbx = 0; +static uint8_t c64_diag_userport_sp1 = 0; +static uint8_t c64_diag_userport_sp2 = 0; + +static uint8_t c64_diag_tapeport = 0; +static uint8_t c64_diag_switches = 0; + +static uint8_t c64_diag_joyport0 = 0; +static uint8_t c64_diag_joyport1 = 0; +static uint8_t c64_diag_joyvalue = 0; + +static uint8_t c64_diag_keyboard_pax = 0; +static uint8_t c64_diag_keyboard_pbx = 0; + +static uint8_t c64_diag_serial = 0; void c64_diag_586220_init(void) { @@ -60,42 +78,119 @@ void c64_diag_586220_init(void) c64_diag_switches = 0; } -void c64_diag_586220_store_userport_pax(BYTE val) + +/* USERPORT connector + +PIN | PIN | NOTES +----------------- + 4 | 6 | CNT1 <-> CNT2 + 5 | 7 | SP1 <-> SP2 + 9 | M | PA3 <-> PA2 + B | 8 | FLAG2 <- PC2 + + C | H | PB0 <-> PB4 + D | J | PB1 <-> PB5 + E | K | PB2 <-> PB6 + F | L | PB3 <-> PB7 + +no data lines go to other ports + +*/ + +/* called by userport_diag_586220_harness_store_paX() */ +void c64_diag_586220_store_userport_pax(uint8_t val) { c64_diag_userport_pax = val; + DBG(("c64_diag_586220_store_userport_pax %02x", val)); } - -void c64_diag_586220_store_userport_pbx(BYTE val) +/* called by userport_diag_586220_harness_store_pbx() */ +void c64_diag_586220_store_userport_pbx(uint8_t val) { c64_diag_userport_pbx = val; } - -void c64_diag_586220_store_userport_sp(BYTE port, BYTE val) +/* called by userport_diag_586220_harness_store_spX */ +void c64_diag_586220_store_userport_sp(uint8_t port, uint8_t val) { + DBG(("c64_diag_586220_store_userport_sp port:%d val:%02x", port, val)); if (!port) { - c64_diag_userport_sp1 = val; - } else { + ciacore_set_sdr(machine_context.cia2, val); c64_diag_userport_sp2 = val; + } else { + ciacore_set_sdr(machine_context.cia1, val); + c64_diag_userport_sp1 = val; } } -void c64_diag_586220_store_tapeport(BYTE pin, BYTE val) +/* called from userport_diag_586220_harness_read_paX */ +uint8_t c64_diag_586220_read_userport_pax(void) +{ + uint8_t retval; + + retval = (c64_diag_userport_pax & 4) << 1; /* bit2 -> bit3 */ + retval |= (c64_diag_userport_pax & 8) >> 1; /* bit3 -> bit2 */ + + retval ^= 0x0c; + + DBG(("c64_diag_586220_read_userport_pax %02x", retval)); + return retval; +} +/* called from userport_diag_586220_harness_read_pbx */ +uint8_t c64_diag_586220_read_userport_pbx(void) +{ + uint8_t retval; + + retval = (c64_diag_userport_pbx >> 4) & 0x0f; /* bit4-7 -> bit0-3 */ + retval |= (c64_diag_userport_pbx & 0x0f) << 4; /* bit0-3 -> bit4-7 */ + + return retval; +} +/* called from userport_diag_586220_harness_read_spX */ +uint8_t c64_diag_586220_read_userport_sp(uint8_t port) +{ + DBG(("c64_diag_586220_read_userport_sp port:%d val:%02x", + port, port ? c64_diag_userport_sp2 : c64_diag_userport_sp1)); + if (!port) { + return c64_diag_userport_sp1; + } + return c64_diag_userport_sp2; +} + + +/* TAPE connector + +PIN | CABLE | NOTES +------------------- +C-3 | 7 | Motor | Joyport Switches control (MOTOR) can ground the line +D-4 | 6 | Read | loops to 4 (READ <-> SENSE) +E-5 | 5 | Write | Joyport Switches control (WRITE) can ground the line +F-6 | 4 | Sense | loops to 6 (SENSE <-> READ) + +*/ + +/* called from tape_diag_586220_harness... */ +void c64_diag_586220_store_tapeport(uint8_t pin, uint8_t val) { c64_diag_tapeport &= ~(1 << pin); c64_diag_tapeport |= (val << pin); switch (pin) { + /* motor <-> write */ case C64_DIAG_TAPEPORT_MOTOR: - machine_set_tape_write_in(val); - break; - case C64_DIAG_TAPEPORT_READ: - machine_set_tape_sense(val); + DBG(("c64_diag_586220_store_tapeport motor:%d",val)); + machine_set_tape_write_in(TAPEPORT_PORT_1, val); break; case C64_DIAG_TAPEPORT_WRITE: - machine_set_tape_motor_in(val); + DBG(("c64_diag_586220_store_tapeport write:%d",val)); + machine_set_tape_motor_in(TAPEPORT_PORT_1, val); + break; + /* read <-> sense */ + case C64_DIAG_TAPEPORT_READ: + DBG(("c64_diag_586220_store_tapeport read:%d\n",val)); + machine_set_tape_sense(TAPEPORT_PORT_1, val); break; case C64_DIAG_TAPEPORT_SENSE: - machine_trigger_flux_change(val); + DBG(("c64_diag_586220_store_tapeport sense:%d\n",val)); + machine_set_tape_read_in(TAPEPORT_PORT_1, val); break; } @@ -106,86 +201,79 @@ void c64_diag_586220_store_tapeport(BYTE pin, BYTE val) } } -void c64_diag_586220_store_joyport_dig(BYTE port, BYTE val) -{ - if (!port) { - c64_diag_joyport0 = val; - } else { - c64_diag_joyport1 = val; - } -} - -void c64_diag_586220_store_keyboard(BYTE port, BYTE val) -{ - if (!port) { - c64_diag_keyboard_pax = val; - } else { - c64_diag_keyboard_pbx = val; - } -} - -void c64_diag_586220_store_serial(BYTE val) +#if 0 +/* TODO: unused */ +uint8_t c64_diag_586220_read_tapeport(uint8_t pin) { - c64_diag_serial = val; -} - -BYTE c64_diag_586220_read_userport_pax(void) -{ - BYTE retval; + uint8_t retval; - retval = (c64_diag_userport_pax & 4) << 1; - retval |= (c64_diag_userport_pax & 2) >> 1; + retval = c64_diag_tapeport & 0xf5; + retval |= (c64_diag_tapeport & 8) >> 2; + retval |= (c64_diag_tapeport & 2) << 2; + retval &= (1 << pin); return retval; } +#endif -BYTE c64_diag_586220_read_userport_pbx(void) -{ - BYTE retval; +/* JOYSTICK connector - retval = c64_diag_userport_pbx >> 4; - retval |= (c64_diag_userport_pbx & 0xf) << 4; +when enabled, via the analog switch connected to the tape port, bits0-4 of the +two joystick ports are connected 1:1 - return retval; -} +*/ -BYTE c64_diag_586220_read_userport_sp(BYTE port) +/* called by harness_store_dig */ +void c64_diag_586220_store_joyport_dig(uint8_t port, uint8_t val) { + /*DBG(("c64_diag_586220_store_joyport_dig port:%d val:%02x", port, val));*/ if (!port) { - return c64_diag_userport_sp2; + c64_diag_joyport0 = val; + } else { + c64_diag_joyport1 = val; } - return c64_diag_userport_sp1; + c64_diag_joyvalue = val; } -BYTE c64_diag_586220_read_tapeport(BYTE pin) -{ - BYTE retval; - - retval = c64_diag_tapeport & 0xf5; - retval |= (c64_diag_tapeport & 8) >> 2; - retval |= (c64_diag_tapeport & 2) << 2; - retval &= (1 << pin); - - return retval; -} - -BYTE c64_diag_586220_read_joyport_dig(BYTE port) +/* called by harness_read_dig */ +uint8_t c64_diag_586220_read_joyport_dig(uint8_t port) { + /*DBG(("c64_diag_586220_read_joyport_dig port:%d",port));*/ if (c64_diag_switches) { +#if 0 if (!port) { return c64_diag_joyport1; } return c64_diag_joyport0; +#endif + return c64_diag_joyvalue; } - return 0; + return 0xff; } -BYTE c64_diag_586220_read_joyport_pot(void) +/* called by harness_read_potX */ +uint8_t c64_diag_586220_read_joyport_pot(void) { - return 0xff; + /* resistor value for all resistors is 120Ohm */ + /* diag expects 0x58...0x78 */ + return 0x60; } -BYTE c64_diag_586220_read_keyboard(BYTE port) + +/* KEYBOARD connector */ + +/* TODO: unused */ +void c64_diag_586220_store_keyboard(uint8_t port, uint8_t val) +{ + if (!port) { + c64_diag_keyboard_pax = val; + } else { + c64_diag_keyboard_pbx = val; + } +} + +/* TODO: unused */ +uint8_t c64_diag_586220_read_keyboard(uint8_t port) { if (!port) { return c64_diag_keyboard_pbx; @@ -193,14 +281,41 @@ BYTE c64_diag_586220_read_keyboard(BYTE port) return c64_diag_keyboard_pax; } -BYTE c64_diag_586220_read_serial(void) + +/* IEC connector + +PIN | CABLE | NOTES +-------------------------------------------------------------------------------- +1-5 | SRQIN - DATA | SRQIN->CIA1 FLAG DATA->CIA2 PA5/PA7 +3-4 | ATN - CLOCK | + +*/ + +/* TODO: unused */ +void c64_diag_586220_store_serial(uint8_t val) { - BYTE retval; + /* Bit 7 Serial Bus Data Input + Bit 6 Serial Bus Clock Pulse Input + Bit 5 Serial Bus Data Output + Bit 4 Serial Bus Clock Pulse Output + Bit 3 Serial Bus ATN Signal Output */ + DBG(("c64_diag_586220_store_serial %02x", val)); + c64_diag_serial = val; +} - retval = (c64_diag_serial & 8) >> 3; - retval |= (c64_diag_serial & 4) >> 1; - retval |= (c64_diag_serial & 2) << 1; - retval |= (c64_diag_serial & 1) << 3; +/* TODO: unused */ +uint8_t c64_diag_586220_read_serial(void) +{ + uint8_t retval; + retval = ((c64_diag_serial >> 3) & 1) << 6; /* ATN Output -> Clock Input */ + retval |= ((c64_diag_serial >> 5) & 1) << 7; /* Data Output -> SRQIN */ + /* Bit 7 Serial Bus Data Input + Bit 6 Serial Bus Clock Pulse Input + Bit 5 Serial Bus Data Output + Bit 4 Serial Bus Clock Pulse Output + Bit 3 Serial Bus ATN Signal Output */ + DBG(("c64_diag_586220_read_serial %02x (%02x)", c64_diag_serial, retval)); return retval; } + diff --git a/src/Emulators/vice/diag/c64_diag_586220_harness.h b/src/Emulators/vice/diag/c64_diag_586220_harness.h index 954296ab..4ca525f0 100644 --- a/src/Emulators/vice/diag/c64_diag_586220_harness.h +++ b/src/Emulators/vice/diag/c64_diag_586220_harness.h @@ -84,28 +84,28 @@ #define C64_DIAG_SERIAL_CLK 2 #define C64_DIAG_SERIAL_DATA 3 -extern void c64_diag_586220_init(void); +void c64_diag_586220_init(void); -extern void c64_diag_586220_store_userport_pax(BYTE val); -extern BYTE c64_diag_586220_read_userport_pax(void); -extern void c64_diag_586220_store_userport_pbx(BYTE val); -extern BYTE c64_diag_586220_read_userport_pbx(void); +void c64_diag_586220_store_userport_pax(uint8_t val); +uint8_t c64_diag_586220_read_userport_pax(void); +void c64_diag_586220_store_userport_pbx(uint8_t val); +uint8_t c64_diag_586220_read_userport_pbx(void); -extern void c64_diag_586220_store_userport_sp(BYTE port, BYTE val); -extern BYTE c64_diag_586220_read_userport_sp(BYTE port); +void c64_diag_586220_store_userport_sp(uint8_t port, uint8_t val); +uint8_t c64_diag_586220_read_userport_sp(uint8_t port); -extern void c64_diag_586220_store_tapeport(BYTE pin, BYTE val); -extern BYTE c64_diag_586220_read_tapeport(BYTE pin); +void c64_diag_586220_store_tapeport(uint8_t pin, uint8_t val); +uint8_t c64_diag_586220_read_tapeport(uint8_t pin); -extern void c64_diag_586220_store_joyport_dig(BYTE port, BYTE val); -extern BYTE c64_diag_586220_read_joyport_dig(BYTE port); +void c64_diag_586220_store_joyport_dig(uint8_t port, uint8_t val); +uint8_t c64_diag_586220_read_joyport_dig(uint8_t port); -extern BYTE c64_diag_586220_read_joyport_pot(void); +uint8_t c64_diag_586220_read_joyport_pot(void); -extern void c64_diag_586220_store_keyboard(BYTE port, BYTE val); -extern BYTE c64_diag_586220_read_keyboard(BYTE port); +void c64_diag_586220_store_keyboard(uint8_t port, uint8_t val); +uint8_t c64_diag_586220_read_keyboard(uint8_t port); -extern void c64_diag_586220_store_serial(BYTE val); -extern BYTE c64_diag_586220_read_serial(void); +void c64_diag_586220_store_serial(uint8_t val); +uint8_t c64_diag_586220_read_serial(void); #endif diff --git a/src/Emulators/vice/diskimage/c1541.c b/src/Emulators/vice/diskimage/c1541.c index ba6bfa4c..78f2e981 100644 --- a/src/Emulators/vice/diskimage/c1541.c +++ b/src/Emulators/vice/diskimage/c1541.c @@ -2027,8 +2027,8 @@ static int copy_cmd(int nargs, char **args) "the destination must be a drive if multiple sources are specified\n"); return FD_BADDEV; } - dest_name_ascii = lib_stralloc(args[nargs - 1]); - dest_name_petscii = lib_stralloc(dest_name_ascii); + dest_name_ascii = lib_strdup(args[nargs - 1]); + dest_name_petscii = lib_strdup(dest_name_ascii); charset_petconvstring((BYTE *)dest_name_petscii, 0); dest_unit = drive_index + UNIT_MIN; } else { @@ -2038,8 +2038,8 @@ static int copy_cmd(int nargs, char **args) "the destination must be a drive if multiple sources are specified\n"); return FD_BADDEV; } - dest_name_ascii = lib_stralloc(p); - dest_name_petscii = lib_stralloc(dest_name_ascii); + dest_name_ascii = lib_strdup(p); + dest_name_petscii = lib_strdup(dest_name_ascii); charset_petconvstring((BYTE *)dest_name_petscii, 0); } else { dest_name_ascii = dest_name_petscii = NULL; @@ -2063,13 +2063,13 @@ static int copy_cmd(int nargs, char **args) src_unit = extract_unit_from_file_name(args[i], &p); if (src_unit <= 0) { - src_name_ascii = lib_stralloc(args[i]); + src_name_ascii = lib_strdup(args[i]); src_unit = drive_index + UNIT_MIN; } else { if (check_drive_ready(src_unit - UNIT_MIN) < 0) { return FD_NOTREADY; } - src_name_ascii = lib_stralloc(p); + src_name_ascii = lib_strdup(p); } if (!is_valid_cbm_file_name(src_name_ascii)) { @@ -2080,7 +2080,7 @@ static int copy_cmd(int nargs, char **args) continue; } - src_name_petscii = lib_stralloc(src_name_ascii); + src_name_petscii = lib_strdup(src_name_ascii); charset_petconvstring((BYTE *)src_name_petscii, 0); if (vdrive_iec_open(drives[src_unit - UNIT_MIN], (BYTE *)src_name_petscii, @@ -2922,9 +2922,9 @@ static int read_cmd(int nargs, char **args) } if (p == NULL) { - src_name_ascii = lib_stralloc(args[1]); + src_name_ascii = lib_strdup(args[1]); } else { - src_name_ascii = lib_stralloc(p); + src_name_ascii = lib_strdup(p); } if (!is_valid_cbm_file_name(src_name_ascii)) { @@ -2934,7 +2934,7 @@ static int read_cmd(int nargs, char **args) return FD_BADNAME; } - src_name_petscii = lib_stralloc(src_name_ascii); + src_name_petscii = lib_strdup(src_name_ascii); charset_petconvstring((BYTE *)src_name_petscii, 0); if (vdrive_iec_open(drives[dnr], (BYTE *)src_name_petscii, @@ -2960,7 +2960,7 @@ static int read_cmd(int nargs, char **args) char *open_petscii_name; dest_name_ascii = args[2]; - open_petscii_name = lib_stralloc(dest_name_ascii); + open_petscii_name = lib_strdup(dest_name_ascii); charset_petconvstring((BYTE *)open_petscii_name, 0); finfo = fileio_open(open_petscii_name, NULL, format, FILEIO_COMMAND_WRITE, FILEIO_TYPE_PRG); @@ -3095,7 +3095,7 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) if (geosFileStruc == GEOS_FILE_STRUC_SEQ) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: GEOS_FILE_STRUC_SEQ (%d:%d)", infoTrk, infoSec); + log_debug(LOG_DEFAULT, "DEBUG: GEOS_FILE_STRUC_SEQ (%d:%d)", infoTrk, infoSec); #endif /* sequential file contained in cvt file * since vlir block is the first data block simply put it to @@ -3127,7 +3127,7 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) } } else if (geosFileStruc == GEOS_FILE_STRUC_VLIR) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: GEOS_FILE_STRUC_VLIR (%d:%d)", infoTrk, infoSec); + log_debug(LOG_DEFAULT, "DEBUG: GEOS_FILE_STRUC_VLIR (%d:%d)", infoTrk, infoSec); #endif /* The vlir block in cvt files is a conversion of the vlir * block on cbm disks. @@ -3143,7 +3143,7 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) } #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR scan record chains"); + log_debug(LOG_DEFAULT, "DEBUG: VLIR scan record chains"); #endif /* Replace the TS-chain-origins with NoOfBlocks/BytesInLastSector */ @@ -3157,13 +3157,13 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) while (aktTrk != 0 && vlirIdx <= 254) { if (aktTrk != 0) { /* Record exists and is not empty */ #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR IDX %d", vlirIdx); + log_debug(LOG_DEFAULT, "DEBUG: VLIR IDX %d", vlirIdx); #endif NoOfChains++; while (aktTrk != 0) { /* Read the chain and collect No Of Blocks */ #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); + log_debug(LOG_DEFAULT, "DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); #endif if (vdrive_read_sector(drives[unit], block, aktTrk, aktSec) != 0) { @@ -3211,7 +3211,7 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) } #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR output record chains"); + log_debug(LOG_DEFAULT, "DEBUG: VLIR output record chains"); #endif /* now output the record chains (leave the TS-Pointers since they are usesless now) */ @@ -3222,13 +3222,13 @@ int internal_read_geos_file(int unit, FILE* outf, char* src_name_ascii) while (aktTrk != 0 && vlirIdx <= 254) { if (aktTrk != 0) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR IDX %d", vlirIdx); + log_debug(LOG_DEFAULT, "DEBUG: VLIR IDX %d", vlirIdx); #endif NoOfChains--; /* Record exists */ while (aktTrk != 0) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); + log_debug(LOG_DEFAULT, "DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); #endif if (vdrive_read_sector(drives[unit], block, aktTrk, aktSec) != 0) { fprintf(stderr, @@ -3294,7 +3294,7 @@ static int read_geos_cmd(int nargs, char **args) "missing filename\n"); return FD_BADNAME; } else { - src_name_ascii = lib_stralloc(p); + src_name_ascii = lib_strdup(p); } if (!is_valid_cbm_file_name(src_name_ascii)) { @@ -3304,7 +3304,7 @@ static int read_geos_cmd(int nargs, char **args) return FD_BADNAME; } - src_name_petscii = lib_stralloc(src_name_ascii); + src_name_petscii = lib_strdup(src_name_ascii); charset_petconvstring((BYTE *)src_name_petscii, 0); if (vdrive_iec_open(drives[dev], (BYTE *)src_name_petscii, @@ -3478,7 +3478,7 @@ static int internal_write_geos_file(int unit, FILE* f) if (geosFileStruc == GEOS_FILE_STRUC_SEQ) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: GEOS_FILE_STRUC_SEQ (%d:%d)", vlirTrk, vlirSec); + log_debug(LOG_DEFAULT, "DEBUG: GEOS_FILE_STRUC_SEQ (%d:%d)", vlirTrk, vlirSec); #endif /* normal seq file (rest like standard files) */ lastTrk = vlirTrk; @@ -3531,7 +3531,7 @@ static int internal_write_geos_file(int unit, FILE* f) } } else if (geosFileStruc == GEOS_FILE_STRUC_VLIR) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: GEOS_FILE_STRUC_VLIR (%d:%d)", vlirTrk, vlirSec); + log_debug(LOG_DEFAULT, "DEBUG: GEOS_FILE_STRUC_VLIR (%d:%d)", vlirTrk, vlirSec); #endif /* in a cvt file containing a vlir file the vlir block contains * a pair (NoOfBlocksForChain, BytesInLastBlock + 2) for every vlir @@ -3544,7 +3544,7 @@ static int internal_write_geos_file(int unit, FILE* f) while (vlirIdx <= 254) { if (vlirBlock[vlirIdx] != 0) { #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR IDX %d (%d:%d)", vlirIdx, vlirTrk, vlirSec); + log_debug(LOG_DEFAULT, "DEBUG: VLIR IDX %d (%d:%d)", vlirIdx, vlirTrk, vlirSec); #endif lastTrk = vlirTrk; lastSec = vlirSec; @@ -3588,7 +3588,7 @@ static int internal_write_geos_file(int unit, FILE* f) /* write it to disk */ #ifdef DEBUG_DRIVE - log_debug("DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); + log_debug(LOG_DEFAULT, "DEBUG: VLIR BLOCK (%d:%d)", aktTrk, aktSec); #endif if (vdrive_write_sector(drives[unit], block, aktTrk, aktSec) != 0) { @@ -3660,11 +3660,11 @@ static int write_geos_cmd(int nargs, char **args) slashp = strrchr(args[1], '/'); if (slashp == NULL) { - dest_name_ascii = lib_stralloc(args[1]); + dest_name_ascii = lib_strdup(args[1]); } else { - dest_name_ascii = lib_stralloc(slashp + 1); + dest_name_ascii = lib_strdup(slashp + 1); } - dest_name_petscii = lib_stralloc(dest_name_ascii); + dest_name_petscii = lib_strdup(dest_name_ascii); charset_petconvstring((BYTE *)dest_name_petscii, 0); if (vdrive_iec_open(drives[dev], (BYTE *)dest_name_petscii, @@ -3706,7 +3706,7 @@ static int write_geos_cmd(int nargs, char **args) 30); #ifdef DEBUG_DRIVE - log_debug("DEBUG: closing, write DIR slot (%d %d) and BAM.", + log_debug(LOG_DEFAULT, "DEBUG: closing, write DIR slot (%d %d) and BAM.", dir.track, dir.sector); #endif vdrive_write_sector(drives[dev], dir.buffer, dir.track, dir.sector); @@ -3750,7 +3750,7 @@ static int rename_cmd(int nargs, char **args) } else { return FD_BADDEV; } - src_name = lib_stralloc(p); + src_name = lib_strdup(p); unit = extract_unit_from_file_name(args[2], &p); @@ -3761,7 +3761,7 @@ static int rename_cmd(int nargs, char **args) } else { return FD_BADDEV; } - dest_name = lib_stralloc(p); + dest_name = lib_strdup(p); dev = dest_unit - UNIT_MIN; @@ -4104,7 +4104,7 @@ static int unlynx_loop(FILE *f, FILE *f2, vdrive_t *vdrive, long dentries) printf("writing file '%s' to image\n", cname); - cmd_parse.parsecmd = lib_stralloc(cname); + cmd_parse.parsecmd = lib_strdup(cname); cmd_parse.secondary = 1; cmd_parse.parselength = (unsigned int)strlen(cname); cmd_parse.readmode = CBMDOS_FAM_WRITE; @@ -4361,7 +4361,7 @@ static int write_cmd(int nargs, char **args) return FD_BADDEV; } if (p != NULL && *p != '\0') { - dest_name = lib_stralloc(p); + dest_name = lib_strdup(p); } else { dest_name = NULL; } @@ -4396,7 +4396,7 @@ static int write_cmd(int nargs, char **args) } if (dest_name == NULL) { - dest_name = lib_stralloc((char *)(finfo->name)); + dest_name = lib_strdup((char *)(finfo->name)); dest_len = finfo->length; } else { dest_len = (unsigned int)strlen(dest_name); @@ -4583,7 +4583,7 @@ static int raw_cmd(int nargs, char **args) /* Write to the command channel. */ if (nargs >= 2) { - char *command = lib_stralloc(args[1]); + char *command = lib_strdup(args[1]); charset_petconvstring((BYTE *)command, 0); vdrive_command_execute(vdrive, (BYTE *)command, (unsigned int)strlen(command)); diff --git a/src/Emulators/vice/diskimage/diskimage.c b/src/Emulators/vice/diskimage/diskimage.c index 6b666202..7aae267f 100644 --- a/src/Emulators/vice/diskimage/diskimage.c +++ b/src/Emulators/vice/diskimage/diskimage.c @@ -29,7 +29,7 @@ /* #define DEBUG_DISKIMAGE */ #ifdef DEBUG_DISKIMAGE -#define DBG(x) log_debug x +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -48,7 +48,6 @@ #include "fsimage.h" #include "lib.h" #include "log.h" -#include "rawimage.h" #include "realimage.h" #include "vicetypes.h" #include "p64.h" @@ -87,7 +86,9 @@ unsigned int disk_image_speed_map(unsigned int format, unsigned int track) /* single sided format, these are straight forward */ case DISK_IMAGE_TYPE_D67: case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_P64: return (track < 31) + (track < 25) + (track < 18); @@ -116,7 +117,7 @@ unsigned int disk_image_speed_map(unsigned int format, unsigned int track) default: log_message(disk_image_log, - "Unknown disk type %i. Cannot calculate zone speed", + "Unknown disk type %u. Cannot calculate zone speed", format); break; } @@ -129,30 +130,31 @@ unsigned int disk_image_speed_map(unsigned int format, unsigned int track) /** \brief Sectors per speed zone for D64/D71 images */ static const unsigned int sector_map_d64[SPEED_ZONE_COUNT] = { - 17, /* tracks 1-17, 36-52 (D71 only) */ - 18, /* tracks 18-24, 53-59 (D71 only) */ - 19, /* track 25-30, 60-65 (D71 only) */ - 21 /* tracks 31-[35-40], 66-70 (D71 only) */ + 17, /* tracks 31-[35-40], 66-70 (D71 only) */ + 18, /* track 25-30, 60-65 (D71 only) */ + 19, /* tracks 18-24, 53-59 (D71 only) */ + 21 /* tracks 1-17, 36-52 (D71 only) */ }; /** \brief Sectors per speed zone for D67 images */ +/* the 2040 tried to squeeze one more sector into speed zone 2 */ static const unsigned int sector_map_d67[SPEED_ZONE_COUNT] = { - 17, /* tracks 1-17 */ - 18, /* tracks 18-24 */ - 20, /* track 25-30 */ - 21 /* tracks 31-[35-40} */ + 17, /* tracks 31-[35-40} */ + 18, /* track 25-30 */ + 20, /* tracks 18-24 */ + 21 /* tracks 1-17 */ }; /** \brief Sectors per speed zone for D80/D82 images */ static const unsigned int sector_map_d80[SPEED_ZONE_COUNT] = { - 23, /* tracks 1-39, 78-116 (D82 only) */ - 25, /* tracks 40-53, 117-130 (D82 only) */ - 27, /* tracks 54-64, 131,141 (D82 only) */ - 29 /* tracks 65-77, 142-154 (D82 only) */ + 23, /* tracks 65-77, 142-154 (D82 only) */ + 25, /* tracks 54-64, 131,141 (D82 only) */ + 27, /* tracks 40-53, 117-130 (D82 only) */ + 29 /* tracks 1-39, 78-116 (D82 only) */ }; @@ -165,13 +167,14 @@ static const unsigned int sector_map_d80[SPEED_ZONE_COUNT] = { * * \return number of sectors or 0 on error */ - unsigned int disk_image_sector_per_track(unsigned int format, unsigned int track) { switch (format) { case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_P64: case DISK_IMAGE_TYPE_D71: @@ -184,7 +187,7 @@ unsigned int disk_image_sector_per_track(unsigned int format, return sector_map_d80[disk_image_speed_map(format, track)]; default: log_message(disk_image_log, - "Unknown disk type %i. Cannot calculate sectors per track", + "Unknown disk type %u. Cannot calculate sectors per track", format); } return 0; @@ -195,14 +198,36 @@ unsigned int disk_image_sector_per_track(unsigned int format, /** \brief Size of a raw (GCR) track in bytes in a D64 image per speed zone */ -static const unsigned int raw_track_size_d64[4] = { - 6250, 6666, 7142, 7692 +static const unsigned int raw_track_size_d64[SPEED_ZONE_COUNT] = { + 6250, /* (50000 bits) tracks 31-[35-40], 66-70 (D71 only) */ + 6666, /* (53333 bits) track 25-30, 60-65 (D71 only) */ + 7142, /* (57143 bits) tracks 18-24, 53-59 (D71 only) */ + 7692 /* (61538 bits) tracks 1-17, 36-52 (D71 only) */ +}; + +/** \brief Size of a raw (GCR) track in bytes in a D67 image per speed zone + */ +/* the 2040 tried to squeeze one more sector into speed zone 2 */ +/* FIXME: D67 has 20 sectors per track for speed zone 2, + D64/D71 has 19 sectors for that speed zone + + note: the number of GCR bits per track "should" be the same as in D64, + as that is pretty much defined by the clock and rotation speed. + */ +static const unsigned int raw_track_size_d67[SPEED_ZONE_COUNT] = { + 6250, /* tracks 31-[35-40} */ + 6666, /* track 25-30 */ + 7142, /* tracks 18-24 */ /* FIXME: is this correct? */ + 7692 /* tracks 1-17 */ }; /** \brief Size of a raw (GCR) track in bytes in a D80 image per speed zone */ -static const unsigned int raw_track_size_d80[4] = { - 9375, 10000, 10714, 11538 +static const unsigned int raw_track_size_d80[SPEED_ZONE_COUNT] = { + 9375, /* tracks 65-77, 142-154 (D82 only) */ + 10000, /* tracks 54-64, 131,141 (D82 only) */ + 10714, /* tracks 40-53, 117-130 (D82 only) */ + 11538 /* tracks 1-39, 78-116 (D82 only) */ }; @@ -218,23 +243,23 @@ unsigned int disk_image_raw_track_size(unsigned int format, { switch (format) { case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: /* FIXME: X64 can contain a lot of different formats, not just D64 (BW) */ +#endif case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_P64: case DISK_IMAGE_TYPE_D71: case DISK_IMAGE_TYPE_G71: - case DISK_IMAGE_TYPE_D67: /* XXX: D67 has 20 sectors per track for - speed zone 2, D64/D71 has 19 sectors - for that speed zone, so is this - correct? (BW) */ return raw_track_size_d64[disk_image_speed_map(format, track)]; + case DISK_IMAGE_TYPE_D67: + return raw_track_size_d67[disk_image_speed_map(format, track)]; case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: return raw_track_size_d80[disk_image_speed_map(format, track)]; default: log_message(disk_image_log, - "Unknown disk type %i. Cannot calculate raw size of track", + "Unknown disk type %u. Cannot calculate raw size of track", format); } return 1; @@ -244,26 +269,102 @@ unsigned int disk_image_raw_track_size(unsigned int format, /* Gap between sectors */ static const unsigned int gap_size_d64[4] = { - 9, 12, 17, 8 + 9, /* (72 bits) tracks 31-[35-40], 66-70 (D71 only) */ + 12, /* (96 bits) track 25-30, 60-65 (D71 only) */ + 17, /* (136 bits) tracks 18-24, 53-59 (D71 only) */ + 8 /* (64 bits) tracks 1-17, 36-52 (D71 only) */ +}; + +/* the 2040 tried to squeeze one more sector into speed zone 2 */ +/* FIXME: D67 has 20 sectors per track for speed zone 2, + * D64/D71 has 19 sectors for that speed zone */ +static const unsigned int gap_size_d67[4] = { + 9, /* tracks 31-[35-40} */ + 12, /* track 25-30 */ + 4, /* tracks 18-24 */ /* FIXME: is this correct? */ + 8 /* tracks 1-17 */ }; unsigned int disk_image_gap_size(unsigned int format, unsigned int track) { switch (format) { case DISK_IMAGE_TYPE_D64: - case DISK_IMAGE_TYPE_X64: +#ifdef HAVE_X64_IMAGE + case DISK_IMAGE_TYPE_X64: /* FIXME: X64 can contain a lot of different + formats, not just D64 (BW) */ +#endif case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_P64: case DISK_IMAGE_TYPE_D71: case DISK_IMAGE_TYPE_G71: - case DISK_IMAGE_TYPE_D67: return gap_size_d64[disk_image_speed_map(format, track)]; + case DISK_IMAGE_TYPE_D67: + return gap_size_d67[disk_image_speed_map(format, track)]; case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: return 25; default: log_message(disk_image_log, - "Unknown disk type %i. Cannot calculate gap size", + "Unknown disk type %u. Cannot calculate gap size", + format); + } + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* Gap between header and sector */ + +unsigned int disk_image_header_gap_size(unsigned int format, unsigned int track) +{ + switch (format) { + case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE + case DISK_IMAGE_TYPE_X64: /* FIXME: X64 can contain a lot of different + formats, not just D64 (BW) */ +#endif + case DISK_IMAGE_TYPE_G64: + case DISK_IMAGE_TYPE_P64: + case DISK_IMAGE_TYPE_D71: + case DISK_IMAGE_TYPE_G71: + return 9; + case DISK_IMAGE_TYPE_D67: + return 4; /* FIXME: is this correct ? */ + case DISK_IMAGE_TYPE_D80: + case DISK_IMAGE_TYPE_D82: + /* FIXME */ + default: + log_message(disk_image_log, + "Unknown disk type %u. Cannot calculate header gap size", + format); + } + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* length of a SYNC */ + +/* FIXME: the value of 5 bytes for sync is also hardcoded in gcr.c */ +unsigned int disk_image_sync_size(unsigned int format, unsigned int track) +{ + switch (format) { + case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE + case DISK_IMAGE_TYPE_X64: /* FIXME: X64 can contain a lot of different + formats, not just D64 (BW) */ +#endif + case DISK_IMAGE_TYPE_G64: + case DISK_IMAGE_TYPE_P64: + case DISK_IMAGE_TYPE_D71: + case DISK_IMAGE_TYPE_G71: + return 5; /* 40 bits */ + case DISK_IMAGE_TYPE_D67: + return 5; /* FIXME: is this correct ? */ + case DISK_IMAGE_TYPE_D80: + case DISK_IMAGE_TYPE_D82: + /* FIXME */ + default: + log_message(disk_image_log, + "Unknown disk type %u. Cannot calculate sync size", format); } return 1; @@ -307,13 +408,17 @@ static const char *disk_image_type(const disk_image_t *image) case DISK_IMAGE_TYPE_D67: return "D67"; case DISK_IMAGE_TYPE_G64: return "G64"; case DISK_IMAGE_TYPE_P64: return "P64"; +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: return "X64"; +#endif case DISK_IMAGE_TYPE_D71: return "D71"; case DISK_IMAGE_TYPE_G71: return "G71"; case DISK_IMAGE_TYPE_D81: return "D81"; case DISK_IMAGE_TYPE_D1M: return "D1M"; case DISK_IMAGE_TYPE_D2M: return "D2M"; case DISK_IMAGE_TYPE_D4M: return "D4M"; + case DISK_IMAGE_TYPE_DHD: return "DHD"; + case DISK_IMAGE_TYPE_D90: return "D90"; default: return NULL; } } @@ -326,7 +431,7 @@ static const char *disk_image_type(const disk_image_t *image) * \param[in] unit unit the image is attached to */ void disk_image_attach_log(const disk_image_t *image, signed int lognum, - unsigned int unit) + unsigned int unit, unsigned int drive) { const char *type = disk_image_type(image); @@ -336,15 +441,9 @@ void disk_image_attach_log(const disk_image_t *image, signed int lognum, switch (image->device) { case DISK_IMAGE_DEVICE_FS: - log_verbose("Unit %d: %s disk image attached: %s.", - unit, type, fsimage_name_get(image)); - break; -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - log_verbose("Unit %d: %s disk attached (drive: %s).", - unit, type, rawimage_name_get(image)); + log_verbose(LOG_DEFAULT, "Unit %u drive %u: %s disk image attached: %s.", + unit, drive, type, fsimage_name_get(image)); break; -#endif } } @@ -356,7 +455,7 @@ void disk_image_attach_log(const disk_image_t *image, signed int lognum, * \param[in] unit unit the image is detached from */ void disk_image_detach_log(const disk_image_t *image, signed int lognum, - unsigned int unit) + unsigned int unit, unsigned int drive) { const char *type = disk_image_type(image); @@ -366,15 +465,9 @@ void disk_image_detach_log(const disk_image_t *image, signed int lognum, switch (image->device) { case DISK_IMAGE_DEVICE_FS: - log_verbose("Unit %d: %s disk image detached: %s.", - unit, type, fsimage_name_get(image)); + log_verbose(LOG_DEFAULT, "Unit %u drive %u: %s disk image detached: %s.", + unit, drive, type, fsimage_name_get(image)); break; -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - log_verbose("Unit %d: %s disk detached (drive: %s).", - unit, type, rawimage_name_get(image)); - break; -#endif } } /*-----------------------------------------------------------------------*/ @@ -419,20 +512,14 @@ int disk_image_fsimage_create(const char *name, unsigned int type) return fsimage_create(name, type); } -/*-----------------------------------------------------------------------*/ - -void disk_image_rawimage_name_set(disk_image_t *image, const char *name) +int disk_image_fsimage_create_dxm(const char *name, const char *diskname, unsigned int type) { -#ifdef HAVE_RAWDRIVE - rawimage_name_set(image, name); -#endif + return fsimage_create_dxm(name, diskname, type); } -void disk_image_rawimage_driver_name_set(disk_image_t *image) +int disk_image_fsimage_create_dhd(const char *name, const char *diskname, unsigned int type) { -#ifdef HAVE_RAWDRIVE - rawimage_driver_name_set(image); -#endif + return fsimage_create_dhd(name, diskname, type); } /*-----------------------------------------------------------------------*/ @@ -443,11 +530,6 @@ void disk_image_name_set(disk_image_t *image, const char *name) case DISK_IMAGE_DEVICE_FS: fsimage_name_set(image, name); break; -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rawimage_name_set(image, name); - break; -#endif } } @@ -466,7 +548,9 @@ const char *disk_image_name_get(const disk_image_t *image) disk_image_t *disk_image_create(void) { - return (disk_image_t *)lib_malloc(sizeof(disk_image_t)); + disk_image_t *image = lib_malloc(sizeof *image); + image->p64 = NULL; + return image; } void disk_image_destroy(disk_image_t *image) @@ -482,18 +566,13 @@ void disk_image_media_create(disk_image_t *image) case DISK_IMAGE_DEVICE_FS: fsimage_media_create(image); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: realimage_media_create(image); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rawimage_media_create(image); - break; #endif default: - log_error(disk_image_log, "Unknown image device %i.", image->device); + log_error(disk_image_log, "Unknown image device %u.", image->device); } } @@ -507,18 +586,13 @@ void disk_image_media_destroy(disk_image_t *image) case DISK_IMAGE_DEVICE_FS: fsimage_media_destroy(image); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: realimage_media_destroy(image); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rawimage_media_destroy(image); - break; #endif default: - log_error(disk_image_log, "Unknown image device %i.", image->device); + log_error(disk_image_log, "Unknown image device %u.", image->device); } } @@ -534,18 +608,13 @@ int disk_image_open(disk_image_t *image) case DISK_IMAGE_DEVICE_FS: rc = fsimage_open(image); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: rc = realimage_open(image); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rc = rawimage_open(image); - break; #endif default: - log_error(disk_image_log, "Unknown image device %i.", image->device); + log_error(disk_image_log, "Unknown image device %u.", image->device); rc = -1; } @@ -565,18 +634,13 @@ int disk_image_close(disk_image_t *image) case DISK_IMAGE_DEVICE_FS: rc = fsimage_close(image); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: rc = realimage_close(image); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rc = rawimage_close(image); - break; #endif default: - log_error(disk_image_log, "Unknown image device %i.", image->device); + log_error(disk_image_log, "Unknown image device %u.", image->device); rc = -1; } @@ -585,7 +649,7 @@ int disk_image_close(disk_image_t *image) /*-----------------------------------------------------------------------*/ -int disk_image_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t *dadr) +int disk_image_read_sector(const disk_image_t *image, uint8_t *buf, const disk_addr_t *dadr) { int rc = 0; @@ -593,25 +657,20 @@ int disk_image_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr case DISK_IMAGE_DEVICE_FS: rc = fsimage_read_sector(image, buf, dadr); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: rc = realimage_read_sector(image, buf, dadr); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rc = rawimage_read_sector(image, buf, dadr); - break; #endif default: - log_error(disk_image_log, "Unknown image device %i.", image->device); + log_error(disk_image_log, "Unknown image device %u.", image->device); rc = -1; } return rc; } -int disk_image_write_sector(disk_image_t *image, const BYTE *buf, const disk_addr_t *dadr) +int disk_image_write_sector(disk_image_t *image, const uint8_t *buf, const disk_addr_t *dadr) { int rc = 0; @@ -624,18 +683,13 @@ int disk_image_write_sector(disk_image_t *image, const BYTE *buf, const disk_add case DISK_IMAGE_DEVICE_FS: rc = fsimage_write_sector(image, buf, dadr); break; -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE case DISK_IMAGE_DEVICE_REAL: rc = realimage_write_sector(image, buf, dadr); break; -#endif -#ifdef HAVE_RAWDRIVE - case DISK_IMAGE_DEVICE_RAW: - rc = rawimage_write_sector(image, buf, dadr); - break; #endif default: - log_error(disk_image_log, "Unknow image device %i.", image->device); + log_error(disk_image_log, "Unknow image device %u.", image->device); rc = -1; } @@ -693,37 +747,38 @@ void disk_image_init(void) disk_image_log = log_open("Disk Access"); fsimage_create_init(); fsimage_init(); -#ifdef HAVE_OPENCBM +#ifdef HAVE_REALDEVICE realimage_init(); #endif -#ifdef HAVE_RAWDRIVE - rawimage_init(); -#endif } int disk_image_resources_init(void) { -#ifdef HAVE_RAWDRIVE - if (rawimage_resources_init() < 0) { - return -1; - } -#endif return 0; } void disk_image_resources_shutdown(void) { -#ifdef HAVE_RAWDRIVE - rawimage_resources_shutdown(); -#endif } int disk_image_cmdline_options_init(void) { -#ifdef HAVE_RAWDRIVE - if (rawimage_cmdline_options_init() < 0) { - return -1; - } + return 0; +} + +/*-----------------------------------------------------------------------*/ + +off_t disk_image_size(const disk_image_t *image) +{ + switch (image->device) { + case DISK_IMAGE_DEVICE_FS: + return fsimage_size(image); +#ifdef HAVE_REALDEVICE + case DISK_IMAGE_DEVICE_REAL: + break; #endif + default: + log_error(disk_image_log, "Unknown image device %u.", image->device); + } return 0; } diff --git a/src/Emulators/vice/diskimage/fsimage-check.c b/src/Emulators/vice/diskimage/fsimage-check.c index fe12b6b9..9a9328b9 100644 --- a/src/Emulators/vice/diskimage/fsimage-check.c +++ b/src/Emulators/vice/diskimage/fsimage-check.c @@ -27,6 +27,8 @@ #include "vice.h" +#include + #include "diskconstants.h" #include "diskimage.h" #include "fsimage-check.h" @@ -50,13 +52,15 @@ int fsimage_check_sector(const disk_image_t *image, unsigned int track, { unsigned int sectors = 0, i; - if (track < 1) { + if (image->type != DISK_IMAGE_TYPE_D90 && track < 1) { return FSIMAGE_BAD_TRKNUM; } switch (image->type) { case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif if (track > MAX_TRACKS_1541) { return FSIMAGE_BAD_TRKNUM; } @@ -177,6 +181,31 @@ int fsimage_check_sector(const disk_image_t *image, unsigned int track, } sectors = (track - 1) * 256 + sector; break; + case DISK_IMAGE_TYPE_DHD: + /* for DHD images, just assume track/sector can be 16 bits each, + which gives us LARGE disks */ + if (track > 0xffff) { + return FSIMAGE_BAD_TRKNUM; + } + if (sector > 0xffff) { + return FSIMAGE_BAD_SECNUM; + } + sectors = (track - 1) * 65536 + sector; + break; + case DISK_IMAGE_TYPE_D90: + /* track 0 is allowed here as the fdc passes it */ + if (track > image->tracks) { + return FSIMAGE_BAD_TRKNUM; + } + if (sector >= image->sectors) { + return FSIMAGE_BAD_SECNUM; + } + /* use the mapping found in the FDC: + sectors = track * (image->sectors >> 5) + (sector >> 5); + sectors = (sectors << 5) + (sector & 31); + we use a more optimized function here */ + sectors = track * (image->sectors & (~31)) + sector; + break; default: return -1; } diff --git a/src/Emulators/vice/diskimage/fsimage-check.h b/src/Emulators/vice/diskimage/fsimage-check.h index a817ea6f..a56127e9 100644 --- a/src/Emulators/vice/diskimage/fsimage-check.h +++ b/src/Emulators/vice/diskimage/fsimage-check.h @@ -40,7 +40,6 @@ struct disk_image_s; -extern int fsimage_check_sector(const struct disk_image_s *image, unsigned int track, - unsigned int sector); +int fsimage_check_sector(const struct disk_image_s *image, unsigned int track, unsigned int sector); #endif diff --git a/src/Emulators/vice/diskimage/fsimage-create.c b/src/Emulators/vice/diskimage/fsimage-create.c index 7e839fc5..1115fff4 100644 --- a/src/Emulators/vice/diskimage/fsimage-create.c +++ b/src/Emulators/vice/diskimage/fsimage-create.c @@ -73,17 +73,19 @@ static log_t createdisk_log = LOG_DEFAULT; */ static int fsimage_create_dxx(disk_image_t *image) { - unsigned int size, i, size2; - BYTE block[256]; + unsigned int size, i; + uint8_t block[256]; fsimage_t *fsimage = image->media.fsimage; int rc = 0; memset(block, 0, sizeof(block)); - size = 0; size2 = 0; + size = 0; switch (image->type) { case DISK_IMAGE_TYPE_D64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif size = D64_FILE_SIZE_35; break; case DISK_IMAGE_TYPE_D67: @@ -101,31 +103,24 @@ static int fsimage_create_dxx(disk_image_t *image) case DISK_IMAGE_TYPE_D82: size = D82_FILE_SIZE; break; + case DISK_IMAGE_TYPE_D90: + /* use D9090 for default D90 size */ + size = D9090_FILE_SIZE; + break; case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: break; case DISK_IMAGE_TYPE_P64: break; - case DISK_IMAGE_TYPE_D1M: - size = D1M_FILE_SIZE; - size2 = 40 * 256; - break; - case DISK_IMAGE_TYPE_D2M: - size = D2M_FILE_SIZE; - size2 = 80 * 256; - break; - case DISK_IMAGE_TYPE_D4M: - size = D4M_FILE_SIZE; - size2 = 160 * 256; - break; default: log_error(createdisk_log, "Wrong image type. Cannot create disk image."); return -1; } +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { - BYTE header[X64_HEADER_LENGTH]; + uint8_t header[X64_HEADER_LENGTH]; memset(header, 0, X64_HEADER_LENGTH); @@ -145,8 +140,8 @@ static int fsimage_create_dxx(disk_image_t *image) fsimage->name); } } - - for (i = 0; i < ((size - size2) / 256); i++) { +#endif + for (i = 0; i < (size / 256); i++) { if (fwrite(block, 256, 1, fsimage->fd) < 1) { log_error(createdisk_log, "Cannot seek to end of disk image `%s'.", @@ -155,48 +150,275 @@ static int fsimage_create_dxx(disk_image_t *image) break; } } - if (!rc && size2) { - for (i = 0; i < size2 / 256; i++) { - memset(block, 0, 256); - if (i == 5) { - memset(block, 255, 224); - block[0] = 0x00; + return rc; +} + + +/** \brief Create a DxM disk image on the host file system + * + * This handles any 'FD2000 or FD4000 disk image supported by VICE. + * + * \param[in] name disk image name/path + * \param[in] diskname disk name and id + * \param[in] type disk image type + * + * \return 0 on success, < 0 on failure + */ +int fsimage_create_dxm(const char *name, const char *diskname, unsigned int type) +{ + FILE *fd = NULL; + unsigned int size = 0; + unsigned int partblock = 0; + uint8_t block[256]; + int rc = 0; + char *dname, *comma; + uint8_t id[2]; + unsigned int i, j; + + memset(block, 0, sizeof(block)); + size = 0; + + fd = fopen(name, MODE_WRITE); + + if (fd == NULL) { + log_error(createdisk_log, "Cannot create disk image `%s'.", name); + return -1; + } + + switch (type) { + case DISK_IMAGE_TYPE_D1M: + size = D1M_FILE_SIZE; + partblock = 0x0c85; + break; + case DISK_IMAGE_TYPE_D2M: + size = D2M_FILE_SIZE; + partblock = 0x1905; + break; + case DISK_IMAGE_TYPE_D4M: + size = D4M_FILE_SIZE; + partblock = 0x3205; + break; + default: + log_error(createdisk_log, + "Wrong image type. Cannot create disk image."); + return -1; + } + + comma = strchr(diskname, ','); + if (comma != NULL) { + if (comma != diskname) { + dname = lib_malloc(comma - diskname + 1); + memcpy(dname, diskname, comma - diskname); + dname[comma - diskname] = '\0'; + } else { + dname = lib_strdup(" "); + } + if (comma[1] != '\0') { + id[0] = comma[1]; + if (comma[2] != '\0') { + id[1] = comma[2]; + } else { + id[1] = ' '; + } + } else { + id[1] = id[0] = ' '; + } + } else { + dname = lib_strdup(diskname); + id[1] = id[0] = ' '; + } + + for (i = 0; i < size / 256; i++) { + memset(block, 0, 256); + /* block 1 */ + if (i == 1) { + block[0x00] = 0x01; + block[0x01] = 0x22; + block[0x02] = 0x48; + for (j = 0; dname[j]; j++) { + block[0x04 + j] = dname[j]; + } + for (;j < 18; j++) { + block[0x04 + j] = 0xa0; + } + block[0x16] = id[0]; + block[0x17] = id[1]; + block[0x18] = 0xa0; + block[0x19] = 0x31; + block[0x1a] = 0x48; + block[0x1b] = 0xa0; + block[0x1c] = 0xa0; + block[0x20] = 0x01; + block[0x21] = 0x01; + } else if (i == 2) { + block[0x02] = 0x48; + block[0x03] = 0xb7; + block[0x04] = id[0]; + block[0x05] = id[1]; + block[0x06] = 0xc0; + switch (type) { + case DISK_IMAGE_TYPE_D1M: + block[0x08] = 0x0c; + break; + case DISK_IMAGE_TYPE_D2M: + block[0x08] = 0x19; + break; + default: + block[0x08] = 0x32; + } + block[0x24] = 0x1f; + for (j = 0x25; j < 256; j++) { + block[j] = 0xff; + } + } else if (i >= 3 && i < 0x22) { + memset(block, 0xff, 256); + } else if (i == 0x22) { + block[0x01] = 0xff; + } else if (i == partblock) { + memset(block, 0xff, 224); + block[0x00] = 0x00; block[0x38] = 0x00; + block[0x39] = 0x00; block[0x70] = 0x00; + switch (type) { + case DISK_IMAGE_TYPE_D1M: + block[0x71] = 0x06; + block[0xa9] = 0x40; + break; + case DISK_IMAGE_TYPE_D2M: + block[0x71] = 0x0c; + block[0xa9] = 0x80; + break; + default: + block[0x71] = 0x19; + block[0xa9] = 0x00; + } block[0xa8] = 0x00; - block[0x39] = 0x00; - block[0x71] = (size - size2) >> 17; - block[0xa9] = (size - size2) >> 9; - block[0xe2] = 1; - block[0xe3] = 1; - memcpy(block + 0xf0, "\x43\x4d\x44\x20\x46\x44\x20\x53\x45\x52\x49\x45\x53\x20\x20\x20", 16); - } else if (i == 8) { + block[0xe2] = 0x01; + block[0xe3] = 0x01; + block[0xf0] = 0x43; + block[0xf1] = 0x4d; + block[0xf2] = 0x44; + block[0xf3] = 0x20; + block[0xf4] = 0x46; + block[0xf5] = 0x44; + block[0xf6] = 0x20; + block[0xf7] = 0x53; + block[0xf8] = 0x45; + block[0xf9] = 0x52; + block[0xfa] = 0x49; + block[0xfb] = 0x45; + block[0xfc] = 0x53; + block[0xfd] = 0x20; + block[0xfe] = 0x20; + block[0xff] = 0x20; + } else if (i == partblock + 3) { block[0x00] = 0x01; block[0x01] = 0x01; block[0x02] = 0xff; - memcpy(block + 5, "\x53\x59\x53\x54\x45\x4d\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0", 16); + block[0x05] = 0x53; + block[0x06] = 0x59; + block[0x07] = 0x53; + block[0x08] = 0x54; + block[0x09] = 0x45; + block[0x0a] = 0x4d; + for (j = 0; j < 10; j++) { + block[0x0b + j] = 0xa0; + } block[0x22] = 0x01; - memcpy(block + 0x25, "\x50\x41\x52\x54\x49\x54\x49\x4f\x4e\x20\x31\xa0\xa0\xa0\xa0\xa0", 16); - block[0x3e] = (size - size2) >> 17; - block[0x3f] = (size - size2) >> 9; - } else if (i > 8 && i < 11) { + block[0x25] = 0x50; + block[0x26] = 0x41; + block[0x27] = 0x52; + block[0x28] = 0x54; + block[0x29] = 0x49; + block[0x2a] = 0x54; + block[0x2b] = 0x49; + block[0x2c] = 0x4f; + block[0x2d] = 0x4e; + block[0x2e] = 0x20; + block[0x2f] = 0x31; + for (j = 0; j < 5; j++) { + block[0x30 + j] = 0xa0; + } + switch (type) { + case DISK_IMAGE_TYPE_D1M: + block[0x3e] = 0x06; + block[0x3f] = 0x00; + break; + case DISK_IMAGE_TYPE_D2M: + block[0x3e] = 0x0c; + block[0x3f] = 0x80; + break; + default: + block[0x3e] = 0x19; + block[0x3f] = 0x00; + } + } else if (i == partblock + 4) { + block[0x00] = 0x01; + block[0x01] = 0x02; + } else if (i == partblock + 5) { block[0x00] = 0x01; - block[0x01] = i - 7; - } else if (i == 11) { + block[0x01] = 0x03; + } else if (i == partblock + 6) { block[0x01] = 0xff; } - if (fwrite(block, 256, 1, fsimage->fd) < 1) { + if (fwrite(block, 256, 1, fd) < 1) { log_error(createdisk_log, "Cannot seek to end of disk image `%s'.", - fsimage->name); + name); rc = -1; break; } - } } + lib_free(dname); + fclose(fd); + return rc; } +/** \brief Create a DHD (hard)disk image on the host file system + * + * This handles CMD HD (hard)disk images supported by VICE. + * + * FIXME: Right now this simply creates a zero-byte file, which then has to be + * partitioned/formatted using the CMD tools. + * + * FIXME: Once creating formatted images was implemented, the type and number + * of params passed to this function perhaps needs to be adjusted. In + * that case make sure to fix them the entire call chain. Maybe even the + * UIs will have to be updated so extra parameters can be provided. + * + * \param[in] name disk image name/path + * \param[in] diskname disk name and id + * \param[in] type disk image type + * + * \return 0 on success, < 0 on failure + */ +int fsimage_create_dhd(const char *name, const char *diskname, unsigned int type) +{ + FILE *fd = NULL; + int rc = 0; + + fd = fopen(name, MODE_WRITE); + + if (fd == NULL) { + log_error(createdisk_log, "Cannot create hard disk image `%s'.", name); + return -1; + } + + switch (type) { + case DISK_IMAGE_TYPE_DHD: + break; + default: + log_error(createdisk_log, + "Wrong image type. Cannot create hard disk image."); + return -1; + } + + fclose(fd); + + return rc; +} /** \brief Create a G64 disk image on the host file system * @@ -206,14 +428,14 @@ static int fsimage_create_dxx(disk_image_t *image) */ static int fsimage_create_gcr(disk_image_t *image) { - BYTE gcr_header[12], gcr_track[NUM_MAX_BYTES_TRACK + 2], *gcrptr; - BYTE gcr_track_p[84 * 2 * 4]; - BYTE gcr_speed_p[84 * 2 * 4]; + uint8_t gcr_header[12], gcr_track[NUM_MAX_BYTES_TRACK + 2], *gcrptr; + uint8_t gcr_track_p[84 * 2 * 4]; + uint8_t gcr_speed_p[84 * 2 * 4]; unsigned int track, sector, num_tracks, max_tracks; fsimage_t *fsimage; gcr_header_t header; - BYTE rawdata[256]; - int gap; + uint8_t rawdata[256]; + int gap, headergap, synclen; fsimage = image->media.fsimage; @@ -260,8 +482,10 @@ static int fsimage_create_gcr(disk_image_t *image) header.id2 = 0xa0; for (track = 1; track <= num_tracks; track++) { gap = disk_image_gap_size(image->type, track); + headergap = disk_image_header_gap_size(image->type, track); + synclen = disk_image_sync_size(image->type, track); gcrptr = gcr_track; - util_word_to_le_buf(gcrptr, (WORD)disk_image_raw_track_size(image->type, track)); + util_word_to_le_buf(gcrptr, (uint16_t)disk_image_raw_track_size(image->type, track)); gcrptr += 2; memset(gcrptr, 0x55, NUM_MAX_BYTES_TRACK); if (image->type == DISK_IMAGE_TYPE_G71) { @@ -289,8 +513,8 @@ static int fsimage_create_gcr(disk_image_t *image) sector++) { DBG(("%d ", sector)); header.sector = sector; - gcr_convert_sector_to_GCR(rawdata, gcrptr, &header, 9, 5, CBMDOS_FDC_ERR_OK); - gcrptr += SECTOR_GCR_SIZE_WITH_HEADER + 9 + gap + 5; + gcr_convert_sector_to_GCR(rawdata, gcrptr, &header, headergap, synclen, CBMDOS_FDC_ERR_OK); + gcrptr += SECTOR_GCR_SIZE_WITH_HEADER + headergap + gap + (synclen * 2); } DBG(("(gap: %d)\n", gap)); if (fwrite((char *)gcr_track, sizeof(gcr_track), 1, fsimage->fd) < 1) { @@ -312,13 +536,13 @@ static int fsimage_create_p64(disk_image_t *image) { TP64MemoryStream P64MemoryStreamInstance; TP64Image P64Image; - BYTE gcr_track[NUM_MAX_BYTES_TRACK], *gcrptr; + uint8_t gcr_track[NUM_MAX_BYTES_TRACK], *gcrptr; unsigned int track, sector; fsimage_t *fsimage; int rc = -1; gcr_header_t header; - BYTE rawdata[256]; - int gap; + uint8_t rawdata[256]; + int gap, headergap, synclen; fsimage = image->media.fsimage; @@ -328,8 +552,10 @@ static int fsimage_create_p64(disk_image_t *image) header.id2 = 0xa0; for (track = 1; track <= NUM_TRACKS_1541; track++) { gap = disk_image_gap_size(image->type, track); + headergap = disk_image_header_gap_size(image->type, track); + synclen = disk_image_sync_size(image->type, track); gcrptr = gcr_track; - util_word_to_le_buf(gcrptr, (WORD)disk_image_raw_track_size(image->type, track)); + util_word_to_le_buf(gcrptr, (uint16_t)disk_image_raw_track_size(image->type, track)); gcrptr += 2; memset(gcrptr, 0x55, NUM_MAX_BYTES_TRACK - 2); @@ -338,9 +564,9 @@ static int fsimage_create_p64(disk_image_t *image) sector < disk_image_sector_per_track(image->type, track); sector++) { header.sector = sector; - gcr_convert_sector_to_GCR(rawdata, gcrptr, &header, 9, 5, CBMDOS_FDC_ERR_OK); + gcr_convert_sector_to_GCR(rawdata, gcrptr, &header, headergap, synclen, CBMDOS_FDC_ERR_OK); - gcrptr += SECTOR_GCR_SIZE_WITH_HEADER + 9 + gap + 5; + gcrptr += SECTOR_GCR_SIZE_WITH_HEADER + headergap + gap + (synclen * 2); } P64PulseStreamConvertFromGCR(&P64Image.PulseStreams[0][track << 1], (void*)&gcr_track[0], disk_image_raw_track_size(image->type, track) << 3); } @@ -385,7 +611,7 @@ int fsimage_create(const char *name, unsigned int type) image->device = DISK_IMAGE_DEVICE_FS; image->type = type; - fsimage->name = lib_stralloc(name); + fsimage->name = lib_strdup(name); fsimage->fd = fopen(name, MODE_WRITE); if (fsimage->fd == NULL) { @@ -398,7 +624,9 @@ int fsimage_create(const char *name, unsigned int type) } switch (type) { +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_D64: case DISK_IMAGE_TYPE_D67: case DISK_IMAGE_TYPE_D71: @@ -408,6 +636,7 @@ int fsimage_create(const char *name, unsigned int type) case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: + case DISK_IMAGE_TYPE_D90: rc = fsimage_create_dxx(image); break; case DISK_IMAGE_TYPE_G64: diff --git a/src/Emulators/vice/diskimage/fsimage-create.h b/src/Emulators/vice/diskimage/fsimage-create.h index 3b342b39..5e4d1352 100644 --- a/src/Emulators/vice/diskimage/fsimage-create.h +++ b/src/Emulators/vice/diskimage/fsimage-create.h @@ -32,8 +32,10 @@ #ifndef VICE_FSIMAGE_CREATE_H #define VICE_FSIMAGE_CREATE_H -extern void fsimage_create_init(void); +void fsimage_create_init(void); -extern int fsimage_create(const char *name, unsigned int type); +int fsimage_create(const char *name, unsigned int type); +int fsimage_create_dxm(const char *name, const char *diskname, unsigned int type); +int fsimage_create_dhd(const char *name, const char *diskname, unsigned int type); #endif diff --git a/src/Emulators/vice/diskimage/fsimage-dxx.c b/src/Emulators/vice/diskimage/fsimage-dxx.c index 1decc0a3..30089df7 100644 --- a/src/Emulators/vice/diskimage/fsimage-dxx.c +++ b/src/Emulators/vice/diskimage/fsimage-dxx.c @@ -31,6 +31,7 @@ #include "diskconstants.h" #include "diskimage.h" +#include "drive.h" #include "cbmdos.h" #include "fsimage-dxx.h" #include "fsimage.h" @@ -41,7 +42,7 @@ #include "util.h" #include "x64.h" -static log_t fsimage_dxx_log = LOG_ERR; +static log_t fsimage_dxx_log = LOG_DEFAULT; int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, const disk_track_t *raw) @@ -49,7 +50,7 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, unsigned int track, sector, max_sector = 0, error_info_created = 0; int sectors, res; long offset; - BYTE *buffer; + uint8_t *buffer; fsimage_t *fsimage = image->media.fsimage; fdc_err_t rf; @@ -58,7 +59,7 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, max_sector = disk_image_sector_per_track(image->type, track); sectors = disk_image_check_sector(image, track, 0); if (sectors < 0) { - log_error(fsimage_dxx_log, "Track: %i out of bounds.", track); + log_error(fsimage_dxx_log, "Track: %u out of bounds.", track); return -1; } @@ -76,17 +77,17 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, buffer = lib_calloc(max_sector, 256); for (sector = 0; sector < max_sector; sector++) { - rf = gcr_read_sector(raw, &buffer[sector * 256], (BYTE)sector); + rf = gcr_read_sector(raw, &buffer[sector * 256], (uint8_t)sector); if (rf != CBMDOS_FDC_ERR_OK) { log_error(fsimage_dxx_log, - "Could not find data sector of T:%d S:%d.", + "Could not find data sector of T:%u S:%u.", track, sector); if (fsimage->error_info.map == NULL) { /* create map if does not exists */ int newlen = disk_image_check_sector(image, image->tracks, 0); if (newlen >= 0) { newlen += disk_image_sector_per_track(image->type, image->tracks); fsimage->error_info.map = lib_malloc(newlen); - memset(fsimage->error_info.map, (BYTE)CBMDOS_FDC_ERR_OK, newlen); + memset(fsimage->error_info.map, (uint8_t)CBMDOS_FDC_ERR_OK, newlen); fsimage->error_info.len = newlen; fsimage->error_info.dirty = 1; error_info_created = 1; @@ -94,20 +95,21 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, } } if (fsimage->error_info.map != NULL) { - if (fsimage->error_info.map[sectors + sector] != (BYTE)rf) { - fsimage->error_info.map[sectors + sector] = (BYTE)rf; + if (fsimage->error_info.map[sectors + sector] != (uint8_t)rf) { + fsimage->error_info.map[sectors + sector] = (uint8_t)rf; fsimage->error_info.dirty = 1; } } } offset = sectors * 256; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } - +#endif if (util_fpwrite(fsimage->fd, buffer, max_sector * 256, offset) < 0) { - log_error(fsimage_dxx_log, "Error writing T:%i to disk image.", + log_error(fsimage_dxx_log, "Error writing T:%u to disk image.", track); lib_free(buffer); return -1; @@ -117,10 +119,11 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, if (fsimage->error_info.dirty) { offset = fsimage->error_info.len * 256 + sectors; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } - +#endif fsimage->error_info.dirty = 0; if (error_info_created) { res = util_fpwrite(fsimage->fd, fsimage->error_info.map, @@ -130,38 +133,41 @@ int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, max_sector, offset); } if (res < 0) { - log_error(fsimage_dxx_log, "Error writing T:%i error info to disk image.", - track); + log_error(fsimage_dxx_log, + "Error writing T:%u error info to disk image.", + track); return -1; } } } /* Make sure the stream is visible to other readers. */ - LOGD("fflush(fsimage->fd)"); fflush(fsimage->fd); return 0; } int fsimage_read_dxx_image(const disk_image_t *image) { - BYTE buffer[256], *bam_id; - int gap; + uint8_t buffer[256], *bam_id; + int gap, headergap, synclen; unsigned int track, sector, track_size; gcr_header_t header; fdc_err_t rf; - int double_sided = 0; + int image_has_two_single_sides = 0; + int double_sided_drive = 0; fsimage_t *fsimage = image->media.fsimage; unsigned int max_sector; - BYTE *ptr; + uint8_t *ptr; int half_track; int sectors; long offset; + unsigned long trackoffset = 0; + uint8_t *tempgcr; if (image->type == DISK_IMAGE_TYPE_D80 || image->type == DISK_IMAGE_TYPE_D82) { - sectors = disk_image_check_sector(image, BAM_TRACK_8050, BAM_SECTOR_8050); - bam_id = &buffer[BAM_ID_8050]; + sectors = disk_image_check_sector(image, HDR_TRACK_8050, HDR_SECTOR_8050); + bam_id = &buffer[HDR_ID_8050]; } else { sectors = disk_image_check_sector(image, BAM_TRACK_1541, BAM_SECTOR_1541); bam_id = &buffer[BAM_ID_1541]; @@ -170,12 +176,48 @@ int fsimage_read_dxx_image(const disk_image_t *image) bam_id[0] = bam_id[1] = 0xa0; if (sectors >= 0) { util_fpread(fsimage->fd, buffer, 256, sectors << 8); + } else { + return -1; } header.id1 = bam_id[0]; header.id2 = bam_id[1]; /* check double sided images */ - double_sided = (image->type == DISK_IMAGE_TYPE_D71) && !(buffer[0x03] & 0x80); + image_has_two_single_sides = (image->type == DISK_IMAGE_TYPE_D71) && !(buffer[0x03] & 0x80); + double_sided_drive = (drive_get_disk_drive_type(image->device) == DRIVE_TYPE_1571) || + (drive_get_disk_drive_type(image->device) == DRIVE_TYPE_1571CR); + + /* special case for 1571: if we are inserting a d64 image into a 1571, fill + the second side with "unformatted" data */ + if (double_sided_drive && (image->type != DISK_IMAGE_TYPE_D71)) { + for (header.track = track = 1; track <= image->max_half_tracks / 2; track++, header.track++) { + half_track = (36 + track) * 2 - 2; + + track_size = disk_image_raw_track_size(image->type, track); + if (image->gcr->tracks[half_track].data == NULL) { + image->gcr->tracks[half_track].data = lib_malloc(track_size); + } else if (image->gcr->tracks[half_track].size != (int)track_size) { + image->gcr->tracks[half_track].data = lib_realloc(image->gcr->tracks[half_track].data, track_size); + } + ptr = image->gcr->tracks[half_track].data; + image->gcr->tracks[half_track].size = track_size; + /* regular track */ + memset(ptr, 0, track_size); + + /* Clear odd track */ + half_track++; + + /* create an (empty) half track */ + if (image->gcr->tracks[half_track].data == NULL) { + image->gcr->tracks[half_track].data = lib_malloc(track_size); + } else if (image->gcr->tracks[half_track].size != (int)track_size) { + image->gcr->tracks[half_track].data = lib_realloc(image->gcr->tracks[half_track].data, track_size); + } + image->gcr->tracks[half_track].size = track_size; + ptr = image->gcr->tracks[half_track].data; + memset(ptr, 0, track_size); + } + } for (header.track = track = 1; track <= image->max_half_tracks / 2; track++, header.track++) { half_track = track * 2 - 2; @@ -190,7 +232,13 @@ int fsimage_read_dxx_image(const disk_image_t *image) image->gcr->tracks[half_track].size = track_size; if (track <= image->tracks) { - if (double_sided && track == 36) { + /* get temp buffer */ + ptr = tempgcr = lib_malloc(track_size); + + /* special case for second side of the 1571. If each side was formatted + separately in one-sided mode, we must start from track 1 again and use + the ID from the BAM on the second side. */ + if (image_has_two_single_sides && track == 36) { sectors = disk_image_check_sector(image, BAM_TRACK_1571 + 35, BAM_SECTOR_1571); buffer[BAM_ID_1571] = buffer[BAM_ID_1571 + 1] = 0xa0; @@ -203,6 +251,8 @@ int fsimage_read_dxx_image(const disk_image_t *image) } gap = disk_image_gap_size(image->type, track); + headergap = disk_image_header_gap_size(image->type, track); + synclen = disk_image_sync_size(image->type, track); max_sector = disk_image_sector_per_track(image->type, track); @@ -213,10 +263,11 @@ int fsimage_read_dxx_image(const disk_image_t *image) sectors = disk_image_check_sector(image, track, sector); offset = sectors * 256; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } - +#endif if (sectors >= 0) { rf = CBMDOS_FDC_ERR_DRIVE; if (util_fpread(fsimage->fd, buffer, 256, offset) >= 0) { @@ -225,58 +276,126 @@ int fsimage_read_dxx_image(const disk_image_t *image) } } header.sector = sector; - gcr_convert_sector_to_GCR(buffer, ptr, &header, 9, 5, rf); + gcr_convert_sector_to_GCR(buffer, ptr, &header, headergap, synclen, rf); } - ptr += SECTOR_GCR_SIZE_WITH_HEADER + 9 + gap + 5; + ptr += SECTOR_GCR_SIZE_WITH_HEADER + headergap + gap + (synclen * 2); } + +#if 0 + /* copy gcr data to buffer (this creates perfectly aligned tracks) */ + ptr = image->gcr->tracks[half_track].data; + memcpy(ptr, tempgcr, track_size); +#else + /* copy gcr data to final buffer with offset + wraparound */ + /* On real disks, the track skew depends on many factors of which + none is exactly defined: the mechanical properties of the drive, + and last not least the code used for formatting the disk. Thus + the offset we use here is somewhat arbitrary, the choosen values + are tweaked to be somewhat close to what the skew1.prg program + shows for the first few tracks. */ + trackoffset += (ptr - tempgcr) - gap; /* bytes we have written */ + trackoffset += (track_size * 100) / 270; /* time it takes to step */ + trackoffset %= track_size; + /*printf("track: %2u sectors: %2u size: %5u offset: %5lu\n", track, max_sector, track_size, trackoffset);*/ + ptr = image->gcr->tracks[half_track].data; + memset(ptr, 0x55, track_size); + memcpy(ptr + trackoffset, tempgcr, track_size - trackoffset); + memcpy(ptr, tempgcr + (track_size - trackoffset), track_size - (track_size - trackoffset)); +#endif + lib_free(tempgcr); } else { memset(ptr, 0x55, track_size); } /* Clear odd track */ half_track++; +#if 0 + /* this does not work for some reason (skew.d64 fails) */ if (image->gcr->tracks[half_track].data) { - lib_free(image->gcr->tracks[half_track].data); - image->gcr->tracks[half_track].data = NULL; - image->gcr->tracks[half_track].size = 0; + image->gcr->tracks[half_track].size = track_size; + ptr = image->gcr->tracks[half_track].data; + memset(ptr, 0, track_size); + } +#else + /* create an (empty) half track */ + if (image->gcr->tracks[half_track].data == NULL) { + image->gcr->tracks[half_track].data = lib_malloc(track_size); + } else if (image->gcr->tracks[half_track].size != (int)track_size) { + image->gcr->tracks[half_track].data = lib_realloc(image->gcr->tracks[half_track].data, track_size); } + image->gcr->tracks[half_track].size = track_size; + ptr = image->gcr->tracks[half_track].data; + memset(ptr, 0, track_size); +#endif + } return 0; } -int fsimage_dxx_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t *dadr) +int fsimage_dxx_read_sector(const disk_image_t *image, uint8_t *buf, const disk_addr_t *dadr) { int sectors; long offset; fsimage_t *fsimage = image->media.fsimage; fdc_err_t rf; + int harderror; sectors = disk_image_check_sector(image, dadr->track, dadr->sector); + /* printf("%d:%d = %d sectors image->gcr:%p\n", dadr->track, dadr->sector, sectors, image->gcr); */ + if (sectors < 0) { - log_error(fsimage_dxx_log, "Track %i, Sector %i out of bounds.", + log_error(fsimage_dxx_log, "Track %u, Sector %u out of bounds.", dadr->track, dadr->sector); return -1; } offset = sectors * 256; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } +#endif - if (image->gcr == NULL) { - if (util_fpread(fsimage->fd, buf, 256, offset) < 0) { - log_error(fsimage_dxx_log, - "Error reading T:%i S:%i from disk image.", - dadr->track, dadr->sector); - return -1; + /* first check hard errors, if there is such hard error, then skip the + reading and do not update the buffer */ + harderror = 0; + if (fsimage->error_info.map) { + harderror = 1; + rf = fsimage->error_info.map[sectors]; + /* these are soft errors, let rf=0 pass for a read */ + if ((rf == 0) || (rf == 1) || (rf == 5) || (rf == 7) || (rf == 8)) { + harderror = 0; + } + } + + if (harderror == 0) { + if (image->gcr == NULL) { + if (util_fpread(fsimage->fd, buf, 256, offset) < 0) { + log_error(fsimage_dxx_log, + "Error reading T:%u S:%u from disk image.", + dadr->track, dadr->sector); + return -1; + } else { + rf = fsimage->error_info.map ? fsimage->error_info.map[sectors] : CBMDOS_FDC_ERR_OK; + } } else { - rf = fsimage->error_info.map ? fsimage->error_info.map[sectors] : CBMDOS_FDC_ERR_OK; + rf = gcr_read_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (uint8_t)dadr->sector); + /* HACK: if the image has an error map, and the "FDC" did not detect an + error in the GCR stream, use the error from the error map instead. + FIXME: what should really be done is encoding the errors from the + error map into the GCR stream. this is a lot more effort and will + give the exact same results, so i will leave it to someone else :) + */ + /* printf("read sector %d:%d returned: %d", dadr->track, dadr->sector, rf); */ + if (fsimage->error_info.map && (rf == CBMDOS_FDC_ERR_OK)) { + rf = fsimage->error_info.map[sectors]; + /* printf(" error map: %d", rf); */ + } + /* printf("\n"); */ } - } else { - rf = gcr_read_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (BYTE)dadr->sector); } switch (rf) { @@ -309,7 +428,7 @@ int fsimage_dxx_read_sector(const disk_image_t *image, BYTE *buf, const disk_add } } -int fsimage_dxx_write_sector(disk_image_t *image, const BYTE *buf, const disk_addr_t *dadr) +int fsimage_dxx_write_sector(disk_image_t *image, const uint8_t *buf, const disk_addr_t *dadr) { int sectors; long offset; @@ -320,37 +439,40 @@ int fsimage_dxx_write_sector(disk_image_t *image, const BYTE *buf, const disk_ad sectors = disk_image_check_sector(image, dadr->track, dadr->sector); if (sectors < 0) { - log_error(fsimage_dxx_log, "Track: %i, Sector: %i out of bounds.", + log_error(fsimage_dxx_log, "Track: %u, Sector: %u out of bounds.", dadr->track, dadr->sector); return -1; } offset = sectors * 256; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } - +#endif if (util_fpwrite(fsimage->fd, buf, 256, offset) < 0) { - log_error(fsimage_dxx_log, "Error writing T:%i S:%i to disk image.", + log_error(fsimage_dxx_log, "Error writing T:%u S:%u to disk image.", dadr->track, dadr->sector); return -1; } if (image->gcr != NULL) { - gcr_write_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (BYTE)dadr->sector); + gcr_write_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (uint8_t)dadr->sector); } if ((fsimage->error_info.map != NULL) && (fsimage->error_info.map[sectors] != CBMDOS_FDC_ERR_OK)) { offset = fsimage->error_info.len * 256 + sectors; +#ifdef HAVE_X64_IMAGE if (image->type == DISK_IMAGE_TYPE_X64) { offset += X64_HEADER_LENGTH; } - +#endif fsimage->error_info.map[sectors] = CBMDOS_FDC_ERR_OK; if (util_fpwrite(fsimage->fd, &fsimage->error_info.map[sectors], 1, offset) < 0) { - log_error(fsimage_dxx_log, "Error writing T:%i S:%i error info to disk image.", - dadr->track, dadr->sector); + log_error(fsimage_dxx_log, + "Error writing T:%u S:%u error info to disk image.", + dadr->track, dadr->sector); } } diff --git a/src/Emulators/vice/diskimage/fsimage-dxx.h b/src/Emulators/vice/diskimage/fsimage-dxx.h index e06ce219..46808090 100644 --- a/src/Emulators/vice/diskimage/fsimage-dxx.h +++ b/src/Emulators/vice/diskimage/fsimage-dxx.h @@ -33,14 +33,15 @@ struct disk_image_s; struct disk_track_s; struct disk_addr_s; -extern void fsimage_dxx_init(void); +void fsimage_dxx_init(void); -extern int fsimage_read_dxx_image(const disk_image_t *image); +int fsimage_read_dxx_image(const disk_image_t *image); + +int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, + const struct disk_track_s *raw); +int fsimage_dxx_read_sector(const struct disk_image_s *image, uint8_t *buf, + const struct disk_addr_s *dadr); +int fsimage_dxx_write_sector(struct disk_image_s *image, const uint8_t *buf, + const struct disk_addr_s *dadr); -extern int fsimage_dxx_write_half_track(disk_image_t *image, unsigned int half_track, - const struct disk_track_s *raw); -extern int fsimage_dxx_read_sector(const struct disk_image_s *image, BYTE *buf, - const struct disk_addr_s *dadr); -extern int fsimage_dxx_write_sector(struct disk_image_s *image, const BYTE *buf, - const struct disk_addr_s *dadr); #endif diff --git a/src/Emulators/vice/diskimage/fsimage-gcr.c b/src/Emulators/vice/diskimage/fsimage-gcr.c index 561fc89c..21389e6c 100644 --- a/src/Emulators/vice/diskimage/fsimage-gcr.c +++ b/src/Emulators/vice/diskimage/fsimage-gcr.c @@ -41,10 +41,10 @@ #include "util.h" -static log_t fsimage_gcr_log = LOG_ERR; -static const BYTE gcr_image_header_expected_1541[] = +static log_t fsimage_gcr_log = LOG_DEFAULT; +static const uint8_t gcr_image_header_expected_1541[] = { 0x47, 0x43, 0x52, 0x2D, 0x31, 0x35, 0x34, 0x31, 0x00 }; -static const BYTE gcr_image_header_expected_1571[] = +static const uint8_t gcr_image_header_expected_1571[] = { 0x47, 0x43, 0x52, 0x2D, 0x31, 0x35, 0x37, 0x31, 0x00 }; /*-----------------------------------------------------------------------*/ @@ -55,13 +55,20 @@ int fsimage_read_gcr_image(const disk_image_t *image) unsigned int half_track; for (half_track = 0; half_track < MAX_GCR_TRACKS; half_track++) { + /* free existing track */ if (image->gcr->tracks[half_track].data) { lib_free(image->gcr->tracks[half_track].data); image->gcr->tracks[half_track].data = NULL; image->gcr->tracks[half_track].size = 0; } + /* load new track from image */ if (half_track < image->max_half_tracks) { fsimage_gcr_read_half_track(image, half_track + 2, &image->gcr->tracks[half_track]); + } else { + /* create empty tracks for non existing tracks */ + image->gcr->tracks[half_track].size = disk_image_raw_track_size(image->type, half_track / 2); + image->gcr->tracks[half_track].data = lib_malloc(image->gcr->tracks[half_track].size); + memset(image->gcr->tracks[half_track].data, 0, image->gcr->tracks[half_track].size); } } return 0; @@ -70,9 +77,9 @@ int fsimage_read_gcr_image(const disk_image_t *image) /* Seek to half track */ static long fsimage_gcr_seek_half_track(fsimage_t *fsimage, unsigned int half_track, - WORD *max_track_length, BYTE *num_half_tracks) + uint16_t *max_track_length, uint8_t *num_half_tracks) { - BYTE buf[12]; + uint8_t buf[12]; if (fsimage->fd == NULL) { log_error(fsimage_gcr_log, "Attempt to read without disk image."); @@ -118,12 +125,12 @@ static long fsimage_gcr_seek_half_track(fsimage_t *fsimage, unsigned int half_tr int fsimage_gcr_read_half_track(const disk_image_t *image, unsigned int half_track, disk_track_t *raw) { - WORD track_len; - BYTE buf[4]; + uint16_t track_len; + uint8_t buf[4]; long offset; fsimage_t *fsimage; - WORD max_track_length; - BYTE num_half_tracks; + uint16_t max_track_length; + uint8_t num_half_tracks; fsimage = image->media.fsimage; @@ -178,12 +185,14 @@ static int fsimage_gcr_read_track(const disk_image_t *image, unsigned int track, int fsimage_gcr_write_half_track(disk_image_t *image, unsigned int half_track, const disk_track_t *raw) { - int gap, extend = 0, res; - WORD max_track_length; - BYTE buf[4]; + int gap; + int extend = 0; + long res; + uint16_t max_track_length; + uint8_t buf[4]; long offset; fsimage_t *fsimage; - BYTE num_half_tracks; + uint8_t num_half_tracks; fsimage = image->media.fsimage; @@ -216,7 +225,7 @@ int fsimage_gcr_write_half_track(disk_image_t *image, unsigned int half_track, } if (raw->data != NULL) { - util_word_to_le_buf(buf, (WORD)raw->size); + util_word_to_le_buf(buf, (uint16_t)raw->size); if (util_fpwrite(fsimage->fd, buf, 2, offset) < 0) { log_error(fsimage_gcr_log, "Could not write GCR disk image."); @@ -232,7 +241,7 @@ int fsimage_gcr_write_half_track(disk_image_t *image, unsigned int half_track, gap = max_track_length - raw->size; if (gap > 0) { - BYTE *padding = lib_calloc(1, gap); + uint8_t *padding = lib_calloc(1, gap); res = fwrite(padding, gap, 1, fsimage->fd); lib_free(padding); if (res < 1) { @@ -242,7 +251,12 @@ int fsimage_gcr_write_half_track(disk_image_t *image, unsigned int half_track, } if (extend) { - util_dword_to_le_buf(buf, offset); + /* FIXME: danger zone: 'DWORD' is a loose term, doesn't indicate + * a size, just that's the next bigger size of 'WORD'. + * Probably these terms are taken from the horrible Win API. + * -- compyx 2020-07-24 + */ + util_dword_to_le_buf(buf, (uint32_t)offset); if (util_fpwrite(fsimage->fd, buf, 4, 12 + (half_track - 2) * 4) < 0) { log_error(fsimage_gcr_log, "Could not write GCR disk image."); return -1; @@ -271,13 +285,13 @@ static int fsimage_gcr_write_track(disk_image_t *image, unsigned int track, /*-----------------------------------------------------------------------*/ /* Read a sector from the GCR disk image. */ -int fsimage_gcr_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t *dadr) +int fsimage_gcr_read_sector(const disk_image_t *image, uint8_t *buf, const disk_addr_t *dadr) { fdc_err_t rf; if (dadr->track > image->tracks) { log_error(fsimage_gcr_log, - "Track %i out of bounds. Cannot read GCR track.", + "Track %u out of bounds. Cannot read GCR track.", dadr->track); return -1; } @@ -290,14 +304,14 @@ int fsimage_gcr_read_sector(const disk_image_t *image, BYTE *buf, const disk_add if (raw.data == NULL) { return CBMDOS_IPE_NOT_READY; } - rf = gcr_read_sector(&raw, buf, (BYTE)dadr->sector); + rf = gcr_read_sector(&raw, buf, (uint8_t)dadr->sector); lib_free(raw.data); } else { - rf = gcr_read_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (BYTE)dadr->sector); + rf = gcr_read_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (uint8_t)dadr->sector); } if (rf != CBMDOS_FDC_ERR_OK) { log_error(fsimage_gcr_log, - "Cannot find track: %i sector: %i within GCR image.", + "Cannot find track: %u sector: %u within GCR image.", dadr->track, dadr->sector); switch (rf) { case CBMDOS_FDC_ERR_HEADER: @@ -333,12 +347,12 @@ int fsimage_gcr_read_sector(const disk_image_t *image, BYTE *buf, const disk_add /*-----------------------------------------------------------------------*/ /* Write a sector to the GCR disk image. */ -int fsimage_gcr_write_sector(disk_image_t *image, const BYTE *buf, +int fsimage_gcr_write_sector(disk_image_t *image, const uint8_t *buf, const disk_addr_t *dadr) { if (dadr->track > image->tracks) { log_error(fsimage_gcr_log, - "Track %i out of bounds. Cannot write GCR sector", + "Track %u out of bounds. Cannot write GCR sector", dadr->track); return -1; } @@ -349,9 +363,9 @@ int fsimage_gcr_write_sector(disk_image_t *image, const BYTE *buf, || raw.data == NULL) { return -1; } - if (gcr_write_sector(&raw, buf, (BYTE)dadr->sector) != CBMDOS_FDC_ERR_OK) { + if (gcr_write_sector(&raw, buf, (uint8_t)dadr->sector) != CBMDOS_FDC_ERR_OK) { log_error(fsimage_gcr_log, - "Could not find track %i sector %i in disk image", + "Could not find track %u sector %u in disk image", dadr->track, dadr->sector); lib_free(raw.data); return -1; @@ -362,15 +376,15 @@ int fsimage_gcr_write_sector(disk_image_t *image, const BYTE *buf, } lib_free(raw.data); } else { - if (gcr_write_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (BYTE)dadr->sector) != CBMDOS_FDC_ERR_OK) { + if (gcr_write_sector(&image->gcr->tracks[(dadr->track * 2) - 2], buf, (uint8_t)dadr->sector) != CBMDOS_FDC_ERR_OK) { log_error(fsimage_gcr_log, - "Could not find track %i sector %i in disk image", + "Could not find track %u sector %u in disk image", dadr->track, dadr->sector); return -1; } if (fsimage_gcr_write_track(image, dadr->track, &image->gcr->tracks[(dadr->track * 2) - 2]) < 0) { log_error(fsimage_gcr_log, - "Failed writing track %i to disk image.", dadr->track); + "Failed writing track %u to disk image.", dadr->track); return -1; } } diff --git a/src/Emulators/vice/diskimage/fsimage-gcr.h b/src/Emulators/vice/diskimage/fsimage-gcr.h index 4543ed97..76a8f9f2 100644 --- a/src/Emulators/vice/diskimage/fsimage-gcr.h +++ b/src/Emulators/vice/diskimage/fsimage-gcr.h @@ -33,18 +33,18 @@ struct disk_image_s; struct disk_track_s; struct disk_addr_s; -extern void fsimage_gcr_init(void); +void fsimage_gcr_init(void); -extern int fsimage_read_gcr_image(const disk_image_t *image); +int fsimage_read_gcr_image(const disk_image_t *image); -extern int fsimage_gcr_read_sector(const struct disk_image_s *image, BYTE *buf, - const struct disk_addr_s *dadr); -extern int fsimage_gcr_write_sector(struct disk_image_s *image, const BYTE *buf, - const struct disk_addr_s *dadr); -extern int fsimage_gcr_read_half_track(const struct disk_image_s *image, - unsigned int half_track, - struct disk_track_s *raw); -extern int fsimage_gcr_write_half_track(struct disk_image_s *image, - unsigned int half_track, const struct disk_track_s *raw); +int fsimage_gcr_read_sector(const struct disk_image_s *image, uint8_t *buf, + const struct disk_addr_s *dadr); +int fsimage_gcr_write_sector(struct disk_image_s *image, const uint8_t *buf, + const struct disk_addr_s *dadr); +int fsimage_gcr_read_half_track(const struct disk_image_s *image, + unsigned int half_track, + struct disk_track_s *raw); +int fsimage_gcr_write_half_track(struct disk_image_s *image, + unsigned int half_track, const struct disk_track_s *raw); #endif diff --git a/src/Emulators/vice/diskimage/fsimage-p64.c b/src/Emulators/vice/diskimage/fsimage-p64.c index 66c80a57..d462bd32 100644 --- a/src/Emulators/vice/diskimage/fsimage-p64.c +++ b/src/Emulators/vice/diskimage/fsimage-p64.c @@ -29,6 +29,7 @@ #include #include +#include "archdep.h" #include "diskconstants.h" #include "diskimage.h" #include "fsimage-p64.h" @@ -41,7 +42,7 @@ #include "util.h" #include "p64.h" -static log_t fsimage_p64_log = LOG_ERR; +static log_t fsimage_p64_log = LOG_DEFAULT; /*-----------------------------------------------------------------------*/ /* Intial P64 buffer setup. */ @@ -50,16 +51,21 @@ int fsimage_read_p64_image(const disk_image_t *image) { TP64MemoryStream P64MemoryStreamInstance; PP64Image P64Image = (void*)image->p64; - int lSize, rc; + int rc; + off_t lSize; void *buffer; fsimage_t *fsimage; fsimage = image->media.fsimage; - lSize = util_file_length(fsimage->fd); - buffer = lib_malloc(lSize); - if (util_fpread(fsimage->fd, buffer, lSize, 0) < 0) { + lSize = archdep_file_size(fsimage->fd); + if (lSize < 0) { + log_error(fsimage_p64_log, "Failed to get size of P64 disk image."); + return -1; + } + buffer = lib_malloc((size_t)lSize); + if (util_fpread(fsimage->fd, buffer, (size_t)lSize, 0) < 0) { lib_free(buffer); log_error(fsimage_p64_log, "Could not read P64 disk image."); return -1; @@ -68,7 +74,7 @@ int fsimage_read_p64_image(const disk_image_t *image) /*num_tracks = image->tracks;*/ P64MemoryStreamCreate(&P64MemoryStreamInstance); - P64MemoryStreamWrite(&P64MemoryStreamInstance, buffer, lSize); + P64MemoryStreamWrite(&P64MemoryStreamInstance, buffer, (p64_uint32_t)lSize); P64MemoryStreamSeek(&P64MemoryStreamInstance, 0); if (P64ImageReadFromStream(P64Image, &P64MemoryStreamInstance)) { rc = 0; @@ -129,7 +135,9 @@ int fsimage_p64_read_half_track(const disk_image_t *image, unsigned int half_tra } if (half_track > 84) { - log_error(fsimage_p64_log, "Half track %i out of bounds. Cannot read P64 track.", half_track); + log_error(fsimage_p64_log, + "Half track %u out of bounds. Cannot read P64 track.", + half_track); return -1; } @@ -166,7 +174,9 @@ int fsimage_p64_write_half_track(disk_image_t *image, unsigned int half_track, } if (half_track > 84) { - log_error(fsimage_p64_log, "Half track %i out of bounds. Cannot write P64 track.", half_track); + log_error(fsimage_p64_log, + "Half track %u out of bounds. Cannot write P64 track.", + half_track); return -1; } if (raw->data == NULL) { @@ -175,11 +185,15 @@ int fsimage_p64_write_half_track(disk_image_t *image, unsigned int half_track, P64PulseStreamConvertFromGCR(&P64Image->PulseStreams[0][half_track], (void*)raw->data, raw->size << 3); + return 0; + /* image flush will happen on close; added by Roberto Muscedere on 20210125 */ +#if 0 return fsimage_write_p64_image(image); +#endif } static int fsimage_p64_write_track(disk_image_t *image, unsigned int track, - int gcr_track_size, BYTE *gcr_track_start_ptr) + int gcr_track_size, uint8_t *gcr_track_start_ptr) { PP64Image P64Image = (void*)image->p64; @@ -189,26 +203,34 @@ static int fsimage_p64_write_track(disk_image_t *image, unsigned int track, } if (track > 42) { - log_error(fsimage_p64_log, "Track %i out of bounds. Cannot write P64 track.", track); + log_error(fsimage_p64_log, + "Track %u out of bounds. Cannot write P64 track.", + track); return -1; } P64PulseStreamConvertFromGCR(&P64Image->PulseStreams[0][track << 1], (void*)gcr_track_start_ptr, gcr_track_size << 3); + return 0; + /* image flush will happen on close; added by Roberto Muscedere on 20210125 */ +#if 0 return fsimage_write_p64_image(image); +#endif } /*-----------------------------------------------------------------------*/ /* Read a sector from the P64 disk image. */ -int fsimage_p64_read_sector(const disk_image_t *image, BYTE *buf, +int fsimage_p64_read_sector(const disk_image_t *image, uint8_t *buf, const disk_addr_t *dadr) { fdc_err_t rf; disk_track_t raw; if (dadr->track > 42) { - log_error(fsimage_p64_log, "Track %i out of bounds. Cannot read P64 track.", dadr->track); + log_error(fsimage_p64_log, + "Track %u out of bounds. Cannot read P64 track.", + dadr->track); return -1; } @@ -219,10 +241,12 @@ int fsimage_p64_read_sector(const disk_image_t *image, BYTE *buf, return CBMDOS_IPE_NOT_READY; } - rf = gcr_read_sector(&raw, buf, (BYTE)dadr->sector); + rf = gcr_read_sector(&raw, buf, (uint8_t)dadr->sector); lib_free(raw.data); if (rf != CBMDOS_FDC_ERR_OK) { - log_error(fsimage_p64_log, "Cannot find track: %i sector: %i within P64 image.", dadr->track, dadr->sector); + log_error(fsimage_p64_log, + "Cannot find track: %u sector: %u within P64 image.", + dadr->track, dadr->sector); switch (rf) { case CBMDOS_FDC_ERR_HEADER: return CBMDOS_IPE_READ_ERROR_BNF; /* 20 */ @@ -257,30 +281,38 @@ int fsimage_p64_read_sector(const disk_image_t *image, BYTE *buf, /*-----------------------------------------------------------------------*/ /* Write a sector to the P64 disk image. */ -int fsimage_p64_write_sector(disk_image_t *image, const BYTE *buf, +int fsimage_p64_write_sector(disk_image_t *image, const uint8_t *buf, const disk_addr_t *dadr) { disk_track_t raw; if (dadr->track > 42) { - log_error(fsimage_p64_log, "Track %i out of bounds. Cannot write P64 sector", dadr->track); + log_error(fsimage_p64_log, + "Track %u out of bounds. Cannot write P64 sector", + dadr->track); return -1; } if (fsimage_p64_read_track(image, dadr->track, &raw) < 0 || raw.data == NULL) { - log_error(fsimage_p64_log, "Cannot read track %i from P64 image.", dadr->track); + log_error(fsimage_p64_log, + "Cannot read track %u from P64 image.", + dadr->track); return -1; } - if (gcr_write_sector(&raw, buf, (BYTE)dadr->sector) != CBMDOS_FDC_ERR_OK) { - log_error(fsimage_p64_log, "Could not find track %i sector %i in disk image", dadr->track, dadr->sector); + if (gcr_write_sector(&raw, buf, (uint8_t)dadr->sector) != CBMDOS_FDC_ERR_OK) { + log_error(fsimage_p64_log, + "Could not find track %u sector %u in disk image", + dadr->track, dadr->sector); lib_free(raw.data); return -1; } if (fsimage_p64_write_track(image, dadr->track, raw.size, raw.data) < 0) { - log_error(fsimage_p64_log, "Failed writing track %i to disk image.", dadr->track); + log_error(fsimage_p64_log, + "Failed writing track %u to disk image.", + dadr->track); lib_free(raw.data); return -1; } diff --git a/src/Emulators/vice/diskimage/fsimage-p64.h b/src/Emulators/vice/diskimage/fsimage-p64.h index 20ad344e..7fb01353 100644 --- a/src/Emulators/vice/diskimage/fsimage-p64.h +++ b/src/Emulators/vice/diskimage/fsimage-p64.h @@ -33,20 +33,21 @@ struct disk_image_s; struct disk_track_s; struct disk_addr_s; -extern void fsimage_p64_init(void); - -extern int fsimage_read_p64_image(const disk_image_t *image); - -extern int fsimage_write_p64_image(const disk_image_t *image); - -extern int fsimage_p64_read_half_track(const struct disk_image_s *image, - unsigned int half_track, - struct disk_track_s *raw); -extern int fsimage_p64_write_half_track(struct disk_image_s *image, - unsigned int half_track, - const struct disk_track_s *raw); -extern int fsimage_p64_read_sector(const struct disk_image_s *image, BYTE *buf, - const struct disk_addr_s *dadr); -extern int fsimage_p64_write_sector(struct disk_image_s *image, const BYTE *buf, - const struct disk_addr_s *dadr); +void fsimage_p64_init(void); + +int fsimage_read_p64_image(const disk_image_t *image); + +int fsimage_write_p64_image(const disk_image_t *image); + +int fsimage_p64_read_half_track(const struct disk_image_s *image, + unsigned int half_track, + struct disk_track_s *raw); +int fsimage_p64_write_half_track(struct disk_image_s *image, + unsigned int half_track, + const struct disk_track_s *raw); +int fsimage_p64_read_sector(const struct disk_image_s *image, uint8_t *buf, + const struct disk_addr_s *dadr); +int fsimage_p64_write_sector(struct disk_image_s *image, const uint8_t *buf, + const struct disk_addr_s *dadr); + #endif diff --git a/src/Emulators/vice/diskimage/fsimage-probe.c b/src/Emulators/vice/diskimage/fsimage-probe.c index 6f099bb8..7676209e 100644 --- a/src/Emulators/vice/diskimage/fsimage-probe.c +++ b/src/Emulators/vice/diskimage/fsimage-probe.c @@ -29,6 +29,8 @@ #include #include +#include "archdep.h" +#include "crt.h" #include "diskconstants.h" #include "diskimage.h" #include "gcr.h" @@ -38,6 +40,7 @@ #include "fsimage.h" #include "lib.h" #include "log.h" +#include "machine-drive.h" #include "vicetypes.h" #include "util.h" #include "x64.h" @@ -54,7 +57,7 @@ #define IS_D2M_LEN(x) (((x) == D2M_FILE_SIZE) || ((x) == D2M_FILE_SIZE_E)) #define IS_D4M_LEN(x) (((x) == D4M_FILE_SIZE) || ((x) == D4M_FILE_SIZE_E)) -static log_t disk_image_probe_log = LOG_ERR; +static log_t disk_image_probe_log = LOG_DEFAULT; static void disk_image_check_log(disk_image_t *image, const char *type) { @@ -62,7 +65,7 @@ static void disk_image_check_log(disk_image_t *image, const char *type) fsimage = image->media.fsimage; - log_verbose("%s disk image recognised: %s, %d tracks%s", + log_verbose(LOG_DEFAULT, "%s disk image recognised: %s, %u tracks%s", type, fsimage->name, image->tracks, image->read_only ? " (read only)." : "."); } @@ -70,7 +73,7 @@ static void disk_image_check_log(disk_image_t *image, const char *type) static int disk_image_check_min_block(unsigned int blk, unsigned int length) { if (blk < length) { - log_error(disk_image_probe_log, "Cannot read block %d.", blk); + log_error(disk_image_probe_log, "Cannot read block %u.", blk); return -1; } return 0; @@ -84,13 +87,15 @@ static int disk_image_check_for_d64(disk_image_t *image) and compare this with the size of the given image. */ int checkimage_tracks, checkimage_errorinfo; - size_t countbytes, checkimage_blocks, checkimage_realsize; + size_t countbytes, checkimage_blocks; + off_t checkimage_realsize; fsimage_t *fsimage; fsimage = image->media.fsimage; checkimage_errorinfo = 0; - checkimage_realsize = util_file_length(fsimage->fd); + + checkimage_realsize = archdep_file_size(fsimage->fd); checkimage_tracks = NUM_TRACKS_1541; /* start at track 35 */ checkimage_blocks = D64_FILE_SIZE_35 / 256; @@ -133,7 +138,7 @@ static int disk_image_check_for_d64(disk_image_t *image) if (checkimage_errorinfo) { fsimage->error_info.map = lib_calloc(1, checkimage_blocks); - fsimage->error_info.len = checkimage_blocks; + fsimage->error_info.len = (int)checkimage_blocks; if (util_fpread(fsimage->fd, fsimage->error_info.map, checkimage_blocks, 256 * checkimage_blocks) < 0) { return 0; } @@ -149,12 +154,12 @@ static int disk_image_check_for_d67(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; - if (!(IS_D67_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D67_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -192,13 +197,13 @@ static int disk_image_check_for_d71(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; size_t checkimage_realsize; int checkimage_errorinfo; fsimage = image->media.fsimage; - checkimage_realsize = util_file_length(fsimage->fd); + checkimage_realsize = archdep_file_size(fsimage->fd); checkimage_errorinfo = 0; if (!(IS_D71_LEN(checkimage_realsize))) { @@ -240,14 +245,14 @@ static int disk_image_check_for_d81(disk_image_t *image) unsigned int blk = 0; char *ext; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; int checkimage_errorinfo; unsigned int checkimage_blocks; fsimage = image->media.fsimage; - if (!(IS_D81_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D81_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -323,12 +328,12 @@ static int disk_image_check_for_d80(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; - if (!(IS_D80_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D80_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -365,12 +370,12 @@ static int disk_image_check_for_d82(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; - if (!(IS_D82_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D82_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -403,9 +408,10 @@ static int disk_image_check_for_d82(disk_image_t *image) return 1; } +#ifdef HAVE_X64_IMAGE static int disk_image_check_for_x64(disk_image_t *image) { - BYTE header[X64_HEADER_LENGTH]; + uint8_t header[X64_HEADER_LENGTH]; fsimage_t *fsimage; fsimage = image->media.fsimage; @@ -434,6 +440,7 @@ static int disk_image_check_for_x64(disk_image_t *image) disk_image_check_log(image, "X64"); return 1; } +#endif static int disk_image_check_for_gcr(disk_image_t *image) { @@ -441,10 +448,10 @@ static int disk_image_check_for_gcr(disk_image_t *image) /* if 0'ed because of: 'if (max_track_length > NUM_MAX_MEM_BYTES_TRACK) {' further down below - */ + */ WORD max_track_length; #endif - BYTE header[32]; + uint8_t header[32]; fsimage_t *fsimage; fsimage = image->media.fsimage; @@ -461,7 +468,7 @@ static int disk_image_check_for_gcr(disk_image_t *image) return 0; } -/* used to be +/* used to be if (header[9] < 1 || header[9] > MAX_GCR_TRACKS * 2) { however, header[] is of type BYTE and MAX_GCR_TRACKS is 140 */ @@ -499,7 +506,7 @@ static int disk_image_check_for_gcr(disk_image_t *image) static int disk_image_check_for_p64(disk_image_t *image) { - BYTE header[8]; + uint8_t header[8]; fsimage_t *fsimage; fsimage = image->media.fsimage; @@ -533,13 +540,13 @@ static int disk_image_check_for_d1m(disk_image_t *image) unsigned int blk = 0; char *ext; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; /* reject files with unknown size */ - if (!(IS_D1M_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D1M_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -584,12 +591,12 @@ static int disk_image_check_for_d2m(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; - if (!(IS_D2M_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D2M_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -627,13 +634,13 @@ static int disk_image_check_for_d4m(disk_image_t *image) { unsigned int blk = 0; size_t len; - BYTE block[256]; + uint8_t block[256]; fsimage_t *fsimage; fsimage = image->media.fsimage; image->tracks = NUM_TRACKS_2000; - if (!(IS_D4M_LEN(util_file_length(fsimage->fd)))) { + if (!(IS_D4M_LEN(archdep_file_size(fsimage->fd)))) { return 0; } @@ -667,6 +674,122 @@ static int disk_image_check_for_d4m(disk_image_t *image) return 1; } +static int disk_image_check_for_dhd(disk_image_t *image) +{ + off_t blk = 0; + uint8_t sector[512]; + fsimage_t *fsimage; + off_t pos; + unsigned char hdmagic[16] = {0x43, 0x4d, 0x44, 0x20, 0x48, 0x44, 0x20, 0x20, + 0x8d, 0x03, 0x88, 0x8e, 0x02, 0x88, 0xea, 0x60}; + + fsimage = image->media.fsimage; + image->tracks = 65535; + + blk = archdep_file_size(fsimage->fd); + + /* only allow blank images to be attached if the CMDHD rom is loaded */ + if (blk == 0) { + if (!machine_drive_rom_check_loaded(DISK_IMAGE_TYPE_DHD)) { + goto good; + } + log_error(disk_image_probe_log, + "Sorry, you can't attach an empty DHD image unless " \ + "the CMDHD boot ROM is loaded."); + return 0; + } + + /* next make sure the file is a multiple of 256 bytes and greater than + equal 73728 bytes (which is the smallest possible running DHD image */ + /* we used to look for multiples of 512 bytes, but writes of 256 bytes + to expanding images in vdrive might make this fail. */ + /* FIXME: perhaps this can be made more strict to prevent false positives? */ + if ((blk % 256 != 0) || ( blk < 73728 )) { + return 0; + } + + /* since the size check(s) are weak, check CRT header to prevent CRT files + being detected as DHD images (bug #1489). having a crt header at the start + of a DHD container seems unlikely enough for this to work fine. */ + if (crt_getid(image->media.fsimage->name) >= 0) { + log_error(disk_image_probe_log, "trying to attach a CRT file as DHD image, aborting."); + return 0; + } + /* FIXME: perhaps other headers (g64, t64, p64...) need to be checked here */ + + /* if the CMDHD rom is loaded, allow it regardless */ + if (!machine_drive_rom_check_loaded(DISK_IMAGE_TYPE_DHD)) { + goto good; + } + + /* at this point, make sure the image is good for vdrive */ + + /* look for configuration block */ + rewind(fsimage->fd); + /* start at LBA 2 or 1024 */ + pos = 1024; + + while ( pos < blk ) { + if (archdep_fseeko(fsimage->fd, pos, SEEK_SET)) { + /* hit the end of file */ + break; + } + if (fread(sector, 512, 1, fsimage->fd) != 1) { + /* hit the end of file */ + break; + } + /* otherwise check the cmd sig */ + if ( memcmp(&(sector[0x1f0]), hdmagic, 16) == 0 ) { + goto good; + } + /* try next 128 sectors of 64 KiB bytes */ + pos += 65536; + } + /* hit the end of file */ + + /* no good */ + return 0; + +good: + /* image is allowed */ + image->type = DISK_IMAGE_TYPE_DHD; + image->max_half_tracks = 0; + + disk_image_check_log(image, "DHD"); + return 1; +} + +static int disk_image_check_for_d90(disk_image_t *image) +{ + off_t blk = 0; + fsimage_t *fsimage; + + fsimage = image->media.fsimage; + + /* get file size */ + blk = archdep_file_size(fsimage->fd); + + /* only allow true D9090/D9060 image sizes right now */ + if (blk == D9060_FILE_SIZE) { + /* D9060 has 4 heads */ + image->sectors = 4 * 32; + } else if (blk == D9090_FILE_SIZE) { + /* D9090 has 6 heads */ + image->sectors = 6 * 32; + } else { + return 0; + } + + /* set max track, for now; it starts at 0 */ + image->tracks = 152; + + /* image is allowed */ + image->type = DISK_IMAGE_TYPE_D90; + image->max_half_tracks = 0; + + disk_image_check_log(image, "D90"); + return 1; +} int fsimage_probe(disk_image_t *image) { @@ -694,9 +817,11 @@ int fsimage_probe(disk_image_t *image) if (disk_image_check_for_gcr(image)) { return 0; } +#ifdef HAVE_X64_IMAGE if (disk_image_check_for_x64(image)) { return 0; } +#endif if (disk_image_check_for_d1m(image)) { return 0; } @@ -706,6 +831,12 @@ int fsimage_probe(disk_image_t *image) if (disk_image_check_for_d4m(image)) { return 0; } + if (disk_image_check_for_d90(image)) { + return 0; + } + if (disk_image_check_for_dhd(image)) { + return 0; + } return -1; } diff --git a/src/Emulators/vice/diskimage/fsimage-probe.h b/src/Emulators/vice/diskimage/fsimage-probe.h index c5109533..796ccde3 100644 --- a/src/Emulators/vice/diskimage/fsimage-probe.h +++ b/src/Emulators/vice/diskimage/fsimage-probe.h @@ -29,7 +29,7 @@ struct disk_image_s; -extern void fsimage_probe_init(void); -extern int fsimage_probe(struct disk_image_s *image); +void fsimage_probe_init(void); +int fsimage_probe(struct disk_image_s *image); #endif diff --git a/src/Emulators/vice/diskimage/fsimage.c b/src/Emulators/vice/diskimage/fsimage.c index 790d1673..27207216 100644 --- a/src/Emulators/vice/diskimage/fsimage.c +++ b/src/Emulators/vice/diskimage/fsimage.c @@ -58,7 +58,7 @@ void fsimage_name_set(disk_image_t *image, const char *name) fsimage = image->media.fsimage; - fsimage->name = lib_stralloc(name); + fsimage->name = lib_strdup(name); } @@ -72,9 +72,9 @@ const char *fsimage_name_get(const disk_image_t *image) { fsimage_t *fsimage; - fsimage = image->media.fsimage; + fsimage = image ? image->media.fsimage : NULL; - return fsimage->name; + return fsimage ? fsimage->name : NULL; } @@ -125,10 +125,25 @@ void fsimage_media_destroy(disk_image_t *image) int fsimage_open(disk_image_t *image) { fsimage_t *fsimage; + size_t length; + unsigned int isdir; fsimage = image->media.fsimage; fsimage->error_info.map = NULL; + /* stat file to find out if it exists or if it is a directory */ + if (archdep_stat(fsimage->name, &length, &isdir) < 0) { + log_error(fsimage_log, "Cannot open file `%s'.", fsimage->name); + return -1; + } + + /* it exists, is it a directory? */ + if (isdir) { + log_error(fsimage_log, "Cannot open directory `%s' as an image.", fsimage->name); + return -1; + } + + /* proceed with normal opening */ if (image->read_only) { fsimage->fd = zfile_fopen(fsimage->name, MODE_READ); } else { @@ -166,9 +181,10 @@ int fsimage_close(disk_image_t *image) return -1; } -/* if (image->type == DISK_IMAGE_TYPE_P64) { + /* flush the image when closed; added by Roberto Muscedere on 20210125 */ + if (image->type == DISK_IMAGE_TYPE_P64) { fsimage_write_p64_image(image); - }*/ + } if (fsimage->error_info.map) { lib_free(fsimage->error_info.map); @@ -182,13 +198,13 @@ int fsimage_close(disk_image_t *image) /*-----------------------------------------------------------------------*/ -int fsimage_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t *dadr) +int fsimage_read_sector(const disk_image_t *image, uint8_t *buf, const disk_addr_t *dadr) { fsimage_t *fsimage; fsimage = image->media.fsimage; - if (fsimage->fd == NULL) { + if (fsimage == NULL || fsimage->fd == NULL) { log_error(fsimage_log, "Attempt to read without disk image."); return CBMDOS_IPE_NOT_READY; } @@ -200,10 +216,14 @@ int fsimage_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t case DISK_IMAGE_TYPE_D81: case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: + case DISK_IMAGE_TYPE_DHD: + case DISK_IMAGE_TYPE_D90: return fsimage_dxx_read_sector(image, buf, dadr); case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: @@ -212,13 +232,13 @@ int fsimage_read_sector(const disk_image_t *image, BYTE *buf, const disk_addr_t return fsimage_p64_read_sector(image, buf, dadr); default: log_error(fsimage_log, - "Unknown disk image type %i. Cannot read sector.", + "Unknown disk image type %u. Cannot read sector.", image->type); return CBMDOS_IPE_NOT_READY; } } -int fsimage_write_sector(disk_image_t *image, const BYTE *buf, +int fsimage_write_sector(disk_image_t *image, const uint8_t *buf, const disk_addr_t *dadr) { fsimage_t *fsimage; @@ -237,10 +257,14 @@ int fsimage_write_sector(disk_image_t *image, const BYTE *buf, case DISK_IMAGE_TYPE_D81: case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: + case DISK_IMAGE_TYPE_DHD: + case DISK_IMAGE_TYPE_D90: if (fsimage_dxx_write_sector(image, buf, dadr) < 0) { return -1; } @@ -273,3 +297,13 @@ void fsimage_init(void) fsimage_p64_init(); fsimage_probe_init(); } + +/*-----------------------------------------------------------------------*/ + +off_t fsimage_size(const disk_image_t *image) +{ + fsimage_t *fsimage; + + fsimage = image->media.fsimage; + return archdep_file_size(fsimage->fd); +} diff --git a/src/Emulators/vice/diskimage/fsimage.h b/src/Emulators/vice/diskimage/fsimage.h index 6e3b610b..79bfb703 100644 --- a/src/Emulators/vice/diskimage/fsimage.h +++ b/src/Emulators/vice/diskimage/fsimage.h @@ -38,26 +38,27 @@ typedef struct fsimage_s { FILE *fd; char *name; struct { - BYTE *map; + uint8_t *map; int dirty; int len; } error_info; } fsimage_t; -extern void fsimage_init(void); +void fsimage_init(void); -extern void fsimage_name_set(struct disk_image_s *image, const char *name); -extern const char *fsimage_name_get(const struct disk_image_s *image); -extern void *fsimage_fd_get(const disk_image_t *image); -extern void fsimage_media_create(struct disk_image_s *image); -extern void fsimage_media_destroy(struct disk_image_s *image); +void fsimage_name_set(struct disk_image_s *image, const char *name); +const char *fsimage_name_get(const struct disk_image_s *image); +void *fsimage_fd_get(const disk_image_t *image); +void fsimage_media_create(struct disk_image_s *image); +void fsimage_media_destroy(struct disk_image_s *image); -extern int fsimage_open(struct disk_image_s *image); -extern int fsimage_close(struct disk_image_s *image); -extern int fsimage_read_sector(const struct disk_image_s *image, BYTE *buf, - const struct disk_addr_s *dadr); -extern int fsimage_write_sector(struct disk_image_s *image, const BYTE *buf, - const struct disk_addr_s *dadr); +int fsimage_open(struct disk_image_s *image); +int fsimage_close(struct disk_image_s *image); +int fsimage_read_sector(const struct disk_image_s *image, uint8_t *buf, + const struct disk_addr_s *dadr); +int fsimage_write_sector(struct disk_image_s *image, const uint8_t *buf, + const struct disk_addr_s *dadr); +off_t fsimage_size(const disk_image_t *image); #endif diff --git a/src/Emulators/vice/diskimage/rawimage.c b/src/Emulators/vice/diskimage/rawimage.c index 0a14a6f3..8e64d7bc 100644 --- a/src/Emulators/vice/diskimage/rawimage.c +++ b/src/Emulators/vice/diskimage/rawimage.c @@ -39,7 +39,6 @@ #include "log.h" #include "rawimage.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" #include "util.h" @@ -55,7 +54,7 @@ void rawimage_name_set(disk_image_t *image, const char *name) rawimage = image->media.rawimage; - rawimage->name = lib_stralloc(name); + rawimage->name = lib_strdup(name); } const char *rawimage_name_get(const disk_image_t *image) @@ -172,10 +171,7 @@ void rawimage_resources_shutdown(void) static const cmdline_option_t cmdline_options[] = { { "-rawdrive", SET_RESOURCE, 1, - NULL, NULL, "RawDriveDriver", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SET_RAW_DRIVE_DEVICE, - NULL, NULL }, + NULL, NULL, "RawDriveDriver", NULL, N_(""), N_("Set raw drive device name")}, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/diskimage/realimage.h b/src/Emulators/vice/diskimage/realimage.h index 76f56a1e..9d296fb5 100644 --- a/src/Emulators/vice/diskimage/realimage.h +++ b/src/Emulators/vice/diskimage/realimage.h @@ -38,14 +38,15 @@ typedef struct realimage_s { } realimage_t; -extern void realimage_init(void); - -extern int realimage_open(struct disk_image_s *image); -extern int realimage_close(struct disk_image_s *image); -extern int realimage_read_sector(const struct disk_image_s *image, BYTE *buf, - const struct disk_addr_s *dadr); -extern int realimage_write_sector(struct disk_image_s *image, const BYTE *buf, - const struct disk_addr_s *dadr); -extern void realimage_media_create(struct disk_image_s *image); -extern void realimage_media_destroy(struct disk_image_s *image); +void realimage_init(void); + +int realimage_open(struct disk_image_s *image); +int realimage_close(struct disk_image_s *image); +int realimage_read_sector(const struct disk_image_s *image, uint8_t *buf, + const struct disk_addr_s *dadr); +int realimage_write_sector(struct disk_image_s *image, const uint8_t *buf, + const struct disk_addr_s *dadr); +void realimage_media_create(struct disk_image_s *image); +void realimage_media_destroy(struct disk_image_s *image); + #endif diff --git a/src/Emulators/vice/diskimage/x64.h b/src/Emulators/vice/diskimage/x64.h index 82388cfc..4c56eaf8 100644 --- a/src/Emulators/vice/diskimage/x64.h +++ b/src/Emulators/vice/diskimage/x64.h @@ -27,6 +27,10 @@ #ifndef VICE_X64_H #define VICE_X64_H +#include "vice.h" + +#ifdef HAVE_X64_IMAGE + #define X64_HEADER_MAGIC_OFFSET 0 /* Length 4 bytes */ #define X64_HEADER_MAGIC_1 'C' #define X64_HEADER_MAGIC_2 (0x15) @@ -42,3 +46,5 @@ #define X64_HEADER_LENGTH 64 #endif + +#endif diff --git a/src/Emulators/vice/drive/drive-check.c b/src/Emulators/vice/drive/drive-check.c index 53c1c958..7c26458e 100644 --- a/src/Emulators/vice/drive/drive-check.c +++ b/src/Emulators/vice/drive/drive-check.c @@ -30,9 +30,11 @@ #include "drive.h" #include "drivetypes.h" #include "iecdrive.h" +#include "machine.h" #include "machine-drive.h" +#include "resources.h" - +/* FIXME: what is the difference between drive_check_ieee and drive_check_old ? */ static unsigned int drive_check_ieee(unsigned int type) { switch (type) { @@ -43,13 +45,14 @@ static unsigned int drive_check_ieee(unsigned int type) case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: + case DRIVE_TYPE_9000: return 1; } return 0; } -static unsigned int drive_check_iec(unsigned int type) +int drive_check_iec(int type) { switch (type) { case DRIVE_TYPE_1540: @@ -61,6 +64,7 @@ static unsigned int drive_check_iec(unsigned int type) case DRIVE_TYPE_1581: case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: + case DRIVE_TYPE_CMDHD: return 1; } @@ -76,12 +80,53 @@ unsigned int drive_check_old(unsigned int type) case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: + case DRIVE_TYPE_9000: return 1; } return 0; } +/* return number of heads for given drive */ +unsigned int drive_get_num_heads(unsigned int type) +{ + switch (type) { + case DRIVE_TYPE_1571: + case DRIVE_TYPE_1571CR: + case DRIVE_TYPE_1581: + case DRIVE_TYPE_2000: + case DRIVE_TYPE_4000: + case DRIVE_TYPE_1001: + case DRIVE_TYPE_8250: + return 2; /* double sided */ + } + return 1; /* single sided */ +} + +/* return number of physical half tracks for given drive */ +unsigned int drive_get_half_tracks(unsigned int type) +{ + switch (type) { + /* 'old' drives with DD mech */ + case DRIVE_TYPE_2040: + case DRIVE_TYPE_3040: + case DRIVE_TYPE_4040: + return 70; + /* drives with QD mechs */ + case DRIVE_TYPE_1001: + case DRIVE_TYPE_8050: + case DRIVE_TYPE_8250: + return 77 * 2; + /* we dont actually have halftracks on 3.5" */ + case DRIVE_TYPE_1581: + case DRIVE_TYPE_2000: + case DRIVE_TYPE_4000: + return 83 * 2; + } + /* 'new' drives with DD mech */ + return 84; +} + unsigned int drive_check_dual(unsigned int type) { switch (type) { @@ -134,25 +179,6 @@ int drive_check_type(unsigned int drive_type, unsigned int dnr) return 0; } - if (drive_check_dual(drive_type)) { - if (is_drive1(dnr)) { - /* Dual drives only supported on even device numbers. */ - return 0; - } else { - if (drive_context[mk_drive1(dnr)]->drive->type != DRIVE_TYPE_NONE) { - /* Disable dual drive if second device is enabled. */ - return 0; - } - } - } else { - if (is_drive1(dnr)) { - if (drive_check_dual(drive_context[mk_drive0(dnr)]->drive->type)) { - /* Disable second device if dual drive is enabled. */ - return drive_type == DRIVE_TYPE_NONE; - } - } - } - if (machine_drive_rom_check_loaded(drive_type) < 0) { return 0; } @@ -260,6 +286,10 @@ int drive_check_extend_policy(int drive_type) case DRIVE_TYPE_1571: case DRIVE_TYPE_1571CR: case DRIVE_TYPE_2031: + /* case DISK_IMAGE_TYPE_D1M: */ /* FIXME: will be always extended */ + /* case DISK_IMAGE_TYPE_D2M: */ /* FIXME: will be always extended */ + /* case DISK_IMAGE_TYPE_D4M: */ /* FIXME: will be always extended */ + /* case DRIVE_TYPE_1581: */ /* FIXME: will be always extended */ return 1; } return 0; @@ -326,3 +356,58 @@ int drive_check_stardos(int drive_type) } return 0; } + +int drive_check_dolphindos3(int drive_type) +{ + /* FIXME: is this correct? */ + switch (drive_type) { + case DRIVE_TYPE_1540: + case DRIVE_TYPE_1541: + case DRIVE_TYPE_1541II: + return 1; + } + return 0; +} + + +/** \brief Check if \a drive_type supports a real-time clock + * + * \param[in] drive_type drive type + * + * \return bool + */ +int drive_check_rtc(int drive_type) +{ + switch (drive_type) { + case DRIVE_TYPE_2000: /* fall through */ + case DRIVE_TYPE_4000: + case DRIVE_TYPE_CMDHD: + return 1; + default: + return 0; + } +} + +int drive_get_type_by_devnr(int devnr) +{ + int iecdevice = 0; + int fsdevice; + int drivetype; + + if (/* FIXME: xvic has its own IEC code and doesn't use "BusDevice[8-11]" */ + (machine_class != VICE_MACHINE_VIC20)) { + resources_get_int_sprintf("BusDevice%i", &iecdevice, devnr); + resources_get_int_sprintf("FileSystemDevice%i", &fsdevice, devnr); + } + resources_get_int_sprintf("Drive%iType", &drivetype, devnr); + if (iecdevice) { + return fsdevice; + } else { + return drivetype; + } +} + +int drive_is_dualdrive_by_devnr(int devnr) +{ + return drive_check_dual(drive_get_type_by_devnr(devnr)); +} diff --git a/src/Emulators/vice/drive/drive-check.h b/src/Emulators/vice/drive/drive-check.h index 26dbf8fb..74481ca6 100644 --- a/src/Emulators/vice/drive/drive-check.h +++ b/src/Emulators/vice/drive/drive-check.h @@ -27,9 +27,11 @@ #ifndef VICE_DRIVE_CHECK_H #define VICE_DRIVE_CHECK_H -extern unsigned int drive_check_bus(unsigned int drive_type, - unsigned int bus_map); -extern unsigned int drive_check_old(unsigned int type); -extern unsigned int drive_check_dual(unsigned int type); +unsigned int drive_check_bus(unsigned int drive_type, unsigned int bus_map); +unsigned int drive_check_old(unsigned int type); +unsigned int drive_check_dual(unsigned int type); + +unsigned int drive_get_num_heads(unsigned int type); +unsigned int drive_get_half_tracks(unsigned int type); #endif diff --git a/src/Emulators/vice/drive/drive-cmdline-options.c b/src/Emulators/vice/drive/drive-cmdline-options.c index 8d8bb841..b429afde 100644 --- a/src/Emulators/vice/drive/drive-cmdline-options.c +++ b/src/Emulators/vice/drive/drive-cmdline-options.c @@ -25,6 +25,8 @@ * */ +#define DEBUGDRIVE + #include "vice.h" #include @@ -35,77 +37,63 @@ #include "lib.h" #include "machine.h" #include "machine-drive.h" -#include "translate.h" - -static const cmdline_option_t cmdline_options[] = { - { "-truedrive", SET_RESOURCE, 0, - NULL, NULL, "DriveTrueEmulation", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_TRUE_DRIVE, - NULL, NULL }, - { "+truedrive", SET_RESOURCE, 0, - NULL, NULL, "DriveTrueEmulation", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_TRUE_DRIVE, - NULL, NULL }, - { "-drivesound", SET_RESOURCE, 0, + +#ifdef DEBUGDRIVE +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +static const cmdline_option_t cmdline_options[] = +{ + { "-drivesound", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DriveSoundEmulation", (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_SOUND, - NULL, NULL }, - { "+drivesound", SET_RESOURCE, 0, + NULL, "Enable sound emulation of disk drives" }, + { "+drivesound", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "DriveSoundEmulation", (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_SOUND, - NULL, NULL }, - { "-drivesoundvolume", SET_RESOURCE, 1, + NULL, "Disable sound emulation of disk drives" }, + { "-drivesoundvolume", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DriveSoundEmulationVolume", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_VOLUME, IDCLS_SET_DRIVE_SOUND_VOLUME, - NULL, NULL }, + "", "Set volume for disk drive sound emulation (0-4000)" }, CMDLINE_LIST_END }; -static cmdline_option_t cmd_drive[] = { - { NULL, SET_RESOURCE, 1, +static cmdline_option_t cmd_drive[] = +{ + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, NULL, NULL, + "", NULL }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_COMBO, - IDCLS_P_TYPE, IDCLS_SET_DRIVE_TYPE, - NULL, NULL }, - { NULL, SET_RESOURCE, 1, + "", "Set drive 40 track extension policy (0: never, 1: ask, 2: on access)" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_SET_DRIVE_EXTENSION_POLICY, - NULL, NULL }, - { NULL, SET_RESOURCE, 1, + "", "Set drive idling method (0: no traps, 1: skip cycles, 2: trap idle)" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_SET_IDLE_METHOD, - NULL, NULL }, - { NULL, SET_RESOURCE, 1, + "", "Set drive rpm (30000 = 300rpm)" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_RPM, IDCLS_SET_DRIVE_RPM, - NULL, NULL }, - { NULL, SET_RESOURCE, 1, + "", "Set drive wobble frequency" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_WOBBLE, IDCLS_SET_DRIVE_WOBBLE, - NULL, NULL }, + "", "Set drive wobble amplitude" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, NULL, (void *)1, + NULL, "Enable hardware-level emulation of disk drive" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, NULL, (void *)0, + NULL, "Disable hardware-level emulation of disk drive" }, CMDLINE_LIST_END }; static cmdline_option_t cmd_drive_rtc[] = { - { NULL, SET_RESOURCE, 0, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RTC_SAVE, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable saving of FD2000/4000 RTC data when changed." }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RTC_SAVE, - NULL, NULL }, + NULL, "Disable saving of FD2000/4000 RTC data when changed." }, CMDLINE_LIST_END }; @@ -120,15 +108,15 @@ typedef struct machine_drives_s { #define DRIVES_C64DTV 3 #define DRIVES_C64 4 -static char *drives[] = { - ", 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250", - ", 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1551: CBM 1551, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000)", - ", 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1573: CBM 1571CR, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250)", - ", 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000)", - ", 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250)" +static const char * const drives[] = { + "Set drive type (0: no drive, 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250, 9000: CBM D9090/60)", + "Set drive type (0: no drive, 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1551: CBM 1551, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 4844: CMD HD)", + "Set drive type (0: no drive, 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1573: CBM 1571CR, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 4844: CMD HD, 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250, 9000: CBM D9090/60)", + "Set drive type (0: no drive, 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 4844: CMD HD)", + "Set drive type (0: no drive, 1540: CBM 1540, 1541: CBM 1541, 1542: CBM 1541-II, 1570: CBM 1570, 1571: CBM 1571, 1581: CBM 1581, 2000: CMD FD-2000, 4000: CMD FD-4000, 4844: CMD HD, 2031: CBM 2031, 2040: CBM 2040, 3040: CBM 3040, 4040: CBM 4040, 1001: CBM 1001, 8050: CBM 8050, 8250: CBM 8250, 9000: CBM D9090/D9060)" }; -static machine_drives_t machine_drives[] = { +static const machine_drives_t machine_drives[] = { { VICE_MACHINE_C64, DRIVES_C64 }, { VICE_MACHINE_C128, DRIVES_C128 }, { VICE_MACHINE_VIC20, DRIVES_C64 }, @@ -145,12 +133,11 @@ static machine_drives_t machine_drives[] = { int drive_cmdline_options_init(void) { - unsigned int dnr, i, j; - char *found_string = NULL; + int dnr, i, j; + const char *found_string = NULL; int has_iec; switch (machine_class) { - case VICE_MACHINE_NONE: case VICE_MACHINE_PET: case VICE_MACHINE_CBM5x0: case VICE_MACHINE_CBM6x0: @@ -161,7 +148,7 @@ int drive_cmdline_options_init(void) has_iec = 1; } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { cmd_drive[0].name = lib_msprintf("-drive%itype", dnr + 8); cmd_drive[0].resource_name = lib_msprintf("Drive%iType", dnr + 8); for (j = 0; machine_drives[j].machine != 0; j++) { @@ -172,7 +159,7 @@ int drive_cmdline_options_init(void) if (found_string) { cmd_drive[0].description = found_string; } else { - cmd_drive[0].description = ")"; + cmd_drive[0].description = "Set drive type (0: no drive)"; } cmd_drive[1].name = lib_msprintf("-drive%iextend", dnr + 8); cmd_drive[1].resource_name @@ -183,9 +170,18 @@ int drive_cmdline_options_init(void) cmd_drive[3].name = lib_msprintf("-drive%irpm", dnr + 8); cmd_drive[3].resource_name = lib_msprintf("Drive%iRPM", dnr + 8); - cmd_drive[4].name = lib_msprintf("-drive%iwobble", dnr + 8); + cmd_drive[4].name = lib_msprintf("-drive%iwobblefrequency", dnr + 8); cmd_drive[4].resource_name - = lib_msprintf("Drive%iWobble", dnr + 8); + = lib_msprintf("Drive%iWobbleFrequency", dnr + 8); + cmd_drive[5].name = lib_msprintf("-drive%iwobbleamplitude", dnr + 8); + cmd_drive[5].resource_name + = lib_msprintf("Drive%iWobbleAmplitude", dnr + 8); + cmd_drive[6].name = lib_msprintf("-drive%itruedrive", dnr + 8); + cmd_drive[6].resource_name + = lib_msprintf("Drive%iTrueEmulation", dnr + 8); + cmd_drive[7].name = lib_msprintf("+drive%itruedrive", dnr + 8); + cmd_drive[7].resource_name + = lib_msprintf("Drive%iTrueEmulation", dnr + 8); if (has_iec) { cmd_drive_rtc[0].name = lib_msprintf("-drive%irtcsave", dnr + 8); @@ -202,7 +198,7 @@ int drive_cmdline_options_init(void) return -1; } - for (i = 0; i < 5; i++) { + for (i = 0; i < 8; i++) { lib_free(cmd_drive[i].name); lib_free(cmd_drive[i].resource_name); } diff --git a/src/Emulators/vice/drive/drive-cmdline-options.h b/src/Emulators/vice/drive/drive-cmdline-options.h index dee36eeb..55fb5f21 100644 --- a/src/Emulators/vice/drive/drive-cmdline-options.h +++ b/src/Emulators/vice/drive/drive-cmdline-options.h @@ -28,6 +28,6 @@ #ifndef VICE_DRIVE_CMDLINE_OPTIONS_H #define VICE_DRIVE_CMDLINE_OPTIONS_H -extern int drive_cmdline_options_init(void); +int drive_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/drive/drive-overflow.c b/src/Emulators/vice/drive/drive-overflow.c deleted file mode 100644 index f900171f..00000000 --- a/src/Emulators/vice/drive/drive-overflow.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * drive-overflow.c - * - * Written by - * Andreas Boose - * - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - -#include "vice.h" - -#include "alarm.h" -#include "clkguard.h" -#include "drive-overflow.h" -#include "drive.h" -#include "drivetypes.h" -#include "interrupt.h" -#include "log.h" -#include "rotation.h" - - -static void drive_clk_overflow_callback(CLOCK sub, void *data) -{ - unsigned int dnr; - drive_t *drive; - - dnr = vice_ptr_to_uint(data); - drive = drive_context[dnr]->drive; - - rotation_rotate_disk(drive); - - rotation_overflow_callback(sub, dnr); - - if (drive->attach_clk > (CLOCK)0) { - drive->attach_clk -= sub; - } - if (drive->detach_clk > (CLOCK)0) { - drive->detach_clk -= sub; - } - if (drive->attach_detach_clk > (CLOCK)0) { - drive->attach_detach_clk -= sub; - } - if (drive->led_last_change_clk > (CLOCK)0) { - drive->led_last_change_clk -= sub; - } - if (drive->led_last_uiupdate_clk > (CLOCK)0) { - drive->led_last_uiupdate_clk -= sub; - } - - alarm_context_time_warp(drive_context[dnr]->cpu->alarm_context, sub, -1); - interrupt_cpu_status_time_warp(drive_context[dnr]->cpu->int_status, sub, - -1); -} - -void drive_overflow_init(void) -{ - unsigned int dnr; - - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - clk_guard_add_callback(drive_context[dnr]->cpu->clk_guard, - drive_clk_overflow_callback, uint_to_void_ptr(dnr)); - } -} diff --git a/src/Emulators/vice/drive/drive-resources.c b/src/Emulators/vice/drive/drive-resources.c index e633ec54..7d8ec778 100644 --- a/src/Emulators/vice/drive/drive-resources.c +++ b/src/Emulators/vice/drive/drive-resources.c @@ -24,10 +24,13 @@ * */ +/* #define DEBUGDRIVE */ + #include "vice.h" #include +#include "attach.h" #include "drive-check.h" #include "drive-resources.h" #include "drive.h" @@ -44,48 +47,62 @@ #include "machine-bus.h" #include "machine-drive.h" #include "resources.h" -#include "vdrive-bam.h" - +#include "vicetypes.h" +#include "vdrive.h" -/* Is true drive emulation switched on? */ -static int drive_true_emulation; +#ifdef DEBUGDRIVE +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif /* Is drive sound emulation switched on? */ int drive_sound_emulation; + /* volume of the drive sound */ int drive_sound_emulation_volume; static int set_drive_true_emulation(int val, void *param) { unsigned int dnr; - drive_t *drive; + unsigned int thistde = val ? 1 : 0; + unsigned int thisdnr = vice_ptr_to_int(param); - drive_true_emulation = val ? 1 : 0; + DBG(("set_drive_true_emulation unit %u enabled: %u", thisdnr + 8, thistde)); - machine_bus_status_truedrive_set((unsigned int)drive_true_emulation); + /* always enable TDE on both units of a drive */ + diskunit_context[thisdnr]->drives[0]->true_emulation = thistde; + diskunit_context[thisdnr]->drives[1]->true_emulation = thistde; - if (val) { - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - if (drive->type != DRIVE_TYPE_NONE) { - drive->enable = 1; - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_reset_clk(drive_context[dnr]); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + machine_bus_status_truedrive_set(dnr + 8, diskunit_context[dnr]->drives[0]->true_emulation); + } + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + if (diskunit_context[dnr]->drives[0]->true_emulation) { + diskunit_context_t *unit = diskunit_context[dnr]; + + vdrive_flush(dnr + 8); + if (unit->type != DRIVE_TYPE_NONE) { + unit->enable = 1; + /* reset drive CPU */ + if (unit->type == DRIVE_TYPE_2000 || + unit->type == DRIVE_TYPE_4000 || + unit->type == DRIVE_TYPE_CMDHD) { + drivecpu65c02_reset_clk(unit); } else { - drivecpu_reset_clk(drive_context[dnr]); + drivecpu_reset_clk(unit); } } - } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive_enable(drive_context[dnr]); - } - } else { - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - drive_disable(drive_context[dnr]); + drive_enable(diskunit_context[dnr]); + } else { + drive_disable(diskunit_context[dnr]); + vdrive_refresh(dnr + 8); +#if 0 if (drive->image != NULL) { - vdrive_bam_reread_bam(dnr + 8); + /* TODO: drive 1? */ + vdrive_bam_reread_bam(dnr + 8, 0); } +#endif } } return 0; @@ -100,7 +117,7 @@ static int set_drive_sound_emulation(int val, void *param) static int set_drive_sound_emulation_volume(int val, void *param) { - if ((val < 0) || (val > 4000)) { + if ((val < 0) || (val > DRIVE_SOUND_VOLUME_MAX)) { return -1; } drive_sound_emulation_volume = val; @@ -113,7 +130,9 @@ static int set_drive_extend_image_policy(int val, void *param) case DRIVE_EXTEND_NEVER: case DRIVE_EXTEND_ASK: case DRIVE_EXTEND_ACCESS: - drive_context[vice_ptr_to_int(param)]->drive->extend_image_policy = val; + /* TODO: add resource for drive 1 */ + diskunit_context[vice_ptr_to_int(param)]->drives[0]->extend_image_policy = val; + diskunit_context[vice_ptr_to_int(param)]->drives[1]->extend_image_policy = val; return 0; default: return -1; @@ -122,17 +141,27 @@ static int set_drive_extend_image_policy(int val, void *param) static int drive_resources_type(int val, void *param) { - unsigned int type, dnr; + unsigned int type, current; + int dnr; int busses; - drive_t *drive, *drive0; + diskunit_context_t *unit; + drive_t *drive; char *rtc_device = NULL; dnr = vice_ptr_to_uint(param); - drive = drive_context[dnr]->drive; + unit = diskunit_context[dnr]; + drive = unit->drives[0]; type = (unsigned int)val; busses = iec_available_busses(); + /* first of all, detach any disk images, so we don't end up with images + attached to drives that do not support them */ + if (file_system_get_vdrive(dnr + 8) != NULL) { + file_system_detach_disk(dnr + 8, 0); + file_system_detach_disk(dnr + 8, 1); + } + /* if bus for drive type is not allowed, set to default value for bus */ if (!drive_check_bus(type, busses)) { if (busses & IEC_BUS_IEC) { @@ -140,48 +169,14 @@ static int drive_resources_type(int val, void *param) } else if (busses & IEC_BUS_IEEE) { type = DRIVE_TYPE_2031; + } else + if (busses & IEC_BUS_TCBM) { + type = DRIVE_TYPE_1551; } else { type = DRIVE_TYPE_NONE; } } - if (is_drive0(dnr)) { - if (drive_check_dual(type)) { - int drive1 = mk_drive1(dnr); - - /* dual disk drives disable second emulated unit */ - log_warning(drive->log, - "Dual disk drive %d disables emulated drive %d", dnr, drive1); - - drive_resources_type(DRIVE_TYPE_NONE, int_to_void_ptr(drive1)); - } - } else { - drive0 = drive_context[mk_drive0(dnr)]->drive; - if (drive0->enable && drive_check_dual(drive0->type)) { - /* dual disk drives disable second emulated unit */ - log_warning(drive->log, - "Dual disk drive %d disables emulated drive %d", mk_drive0(dnr), dnr); - - type = DRIVE_TYPE_NONE; - } - } - - if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) { - if (drive->type != DRIVE_TYPE_2000 && drive->type != DRIVE_TYPE_4000) { - rtc_device = lib_msprintf("FD%d", dnr + 8); - drive->ds1216 = ds1216e_init(rtc_device); - drive->ds1216->hours12 = 1; - lib_free(rtc_device); - } - } else { - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - if (drive->ds1216) { - ds1216e_destroy(drive->ds1216, drive->rtc_save); - drive->ds1216 = NULL; - } - } - } - switch (type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: @@ -193,6 +188,7 @@ static int drive_resources_type(int val, void *param) case DRIVE_TYPE_1581: case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: + case DRIVE_TYPE_CMDHD: case DRIVE_TYPE_2031: case DRIVE_TYPE_1001: case DRIVE_TYPE_2040: @@ -200,31 +196,53 @@ static int drive_resources_type(int val, void *param) case DRIVE_TYPE_4040: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - if (drive->type != type) { + case DRIVE_TYPE_9000: + current = unit->type; + /* make sure the switch is successful before moving on */ + if (drive_set_disk_drive_type(type, diskunit_context[dnr]) < 0) { + return -1; + } + /* allocate or unallocate rtc module for FD2K/4K */ + if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) { + if (current != DRIVE_TYPE_2000 && current != DRIVE_TYPE_4000) { + rtc_device = lib_msprintf("FD%d", dnr + 8); + unit->ds1216 = ds1216e_init(rtc_device); + unit->ds1216->hours12 = 1; + lib_free(rtc_device); + } + } else { + if (current == DRIVE_TYPE_2000 || current == DRIVE_TYPE_4000) { + if (unit->ds1216) { + ds1216e_destroy(unit->ds1216, unit->rtc_save); + unit->ds1216 = NULL; + } + } + } + if (current != type) { + /* the drives that support half tracks are all single drives */ drive->current_half_track = 2 * 18; if ((type == DRIVE_TYPE_1001) || (type == DRIVE_TYPE_8050) || (type == DRIVE_TYPE_8250)) { drive->current_half_track = 2 * 38; + } else if (type == DRIVE_TYPE_9000) { + drive->current_half_track = 2 * 76; } } - drive->type = type; - if (drive_true_emulation) { - drive->enable = 1; - drive_enable(drive_context[dnr]); + if (drive->true_emulation) { + unit->enable = 1; + drive_enable(diskunit_context[dnr]); /* 1551 drive does not use the IEC bus */ machine_bus_status_drivetype_set(dnr + 8, drive_check_bus(type, IEC_BUS_IEC)); - } else { - drive_enable_update_ui(drive_context[dnr]); } - drive_set_disk_drive_type(type, drive_context[dnr]); - driverom_initialize_traps(drive); + drive_enable_update_ui(diskunit_context[dnr]); + driverom_initialize_traps(diskunit_context[dnr]); machine_drive_idling_method(dnr); return 0; case DRIVE_TYPE_NONE: - drive->type = type; - drive_disable(drive_context[dnr]); + unit->type = type; + drive_disable(diskunit_context[dnr]); machine_bus_status_drivetype_set(dnr + 8, 0); return 0; default: @@ -240,11 +258,12 @@ static resource_int_t res_drive_type[] = { int drive_resources_type_init(unsigned int default_type) { - unsigned int dnr, type; - drive_t *drive; + unsigned int type; + int dnr; + + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; if (dnr == 0) { type = default_type; } else { @@ -253,8 +272,8 @@ int drive_resources_type_init(unsigned int default_type) res_drive_type[0].name = lib_msprintf("Drive%iType", dnr + 8); res_drive_type[0].factory_value = (int)type; - res_drive_type[0].value_ptr = (int *)&(drive->type); - res_drive_type[0].param = uint_to_void_ptr(dnr); + res_drive_type[0].value_ptr = (int *)&(unit->type); + res_drive_type[0].param = vice_int_to_ptr(dnr); if (resources_register_int(res_drive_type) < 0) { return -1; @@ -268,11 +287,8 @@ int drive_resources_type_init(unsigned int default_type) static int set_drive_idling_method(int val, void *param) { - unsigned int dnr; - drive_t *drive; - - dnr = vice_ptr_to_uint(param); - drive = drive_context[dnr]->drive; + unsigned int dnr = vice_ptr_to_uint(param); + diskunit_context_t *unit = diskunit_context[dnr]; /* FIXME: Maybe we should call `drive_cpu_execute()' here? */ switch (val) { @@ -284,56 +300,86 @@ static int set_drive_idling_method(int val, void *param) return -1; } - drive->idling_method = val; + unit->idling_method = val; if (!rom_loaded) { return 0; } - driverom_initialize_traps(drive); + driverom_initialize_traps(unit); + return 0; } static int set_drive_rpm(int val, void *param) { unsigned int dnr; - drive_t *drive; + drive_t *drive, *drive1; + + if ((val < 0) || (val > DRIVE_RPM_MAX)) { + return -1; + } dnr = vice_ptr_to_uint(param); - drive = drive_context[dnr]->drive; + drive = diskunit_context[dnr]->drives[0]; + drive1 = diskunit_context[dnr]->drives[1]; drive->rpm = val; + drive1->rpm = val; + return 0; } -static int set_drive_rpm_wobble(int val, void *param) +static int set_drive_wobble_frequency(int val, void *param) { unsigned int dnr; - drive_t *drive; + drive_t *drive, *drive1; + + if ((val < 0) || (val > DRIVE_WOBBLE_FREQ_MAX)) { + return -1; + } dnr = vice_ptr_to_uint(param); - drive = drive_context[dnr]->drive; + drive = diskunit_context[dnr]->drives[0]; + drive1 = diskunit_context[dnr]->drives[1]; - drive->rpm_wobble = val; + drive->wobble_frequency = val; + drive1->wobble_frequency = val; + return 0; +} + +static int set_drive_wobble_amplitude(int val, void *param) +{ + unsigned int dnr; + drive_t *drive, *drive1; + + if ((val < 0) || (val > DRIVE_WOBBLE_AMPLITUDE_MAX)) { + return -1; + } + + dnr = vice_ptr_to_uint(param); + drive = diskunit_context[dnr]->drives[0]; + drive1 = diskunit_context[dnr]->drives[1]; + + drive->wobble_amplitude = val; + drive1->wobble_amplitude = val; return 0; } static int set_drive_rtc_save(int val, void *param) { unsigned int dnr; - drive_t *drive; + diskunit_context_t *unit; dnr = vice_ptr_to_uint(param); - drive = drive_context[dnr]->drive; + unit = diskunit_context[dnr]; - drive->rtc_save = val ? 1 : 0; + unit->rtc_save = val ? 1 : 0; return 0; } static const resource_int_t resources_int[] = { - { "DriveTrueEmulation", 1, RES_EVENT_STRICT, (resource_value_t)1, - &drive_true_emulation, set_drive_true_emulation, NULL }, { "DriveSoundEmulation", 0, RES_EVENT_NO, (resource_value_t)0, &drive_sound_emulation, set_drive_sound_emulation, NULL }, { "DriveSoundEmulationVolume", 1000, RES_EVENT_NO, (resource_value_t)1000, @@ -342,14 +388,18 @@ static const resource_int_t resources_int[] = { }; static resource_int_t res_drive[] = { - { NULL, DRIVE_EXTEND_NEVER, RES_EVENT_SAME, NULL, + { NULL, DRIVE_EXTEND_ASK, RES_EVENT_SAME, NULL, NULL, set_drive_extend_image_policy, NULL }, { NULL, DRIVE_IDLE_NO_IDLE, RES_EVENT_SAME, NULL, NULL, set_drive_idling_method, NULL }, - { NULL, 30000, RES_EVENT_SAME, NULL, + { NULL, DRIVE_RPM_DEFAULT, RES_EVENT_SAME, NULL, NULL, set_drive_rpm, NULL }, - { NULL, 50, RES_EVENT_SAME, NULL, - NULL, set_drive_rpm_wobble, NULL }, + { NULL, DRIVE_WOBBLE_FREQ_DEFAULT, RES_EVENT_SAME, NULL, + NULL, set_drive_wobble_frequency, NULL }, + { NULL, DRIVE_WOBBLE_AMPLITUDE_DEFAULT, RES_EVENT_SAME, NULL, + NULL, set_drive_wobble_amplitude, NULL }, + { NULL, 1, RES_EVENT_STRICT, NULL, + NULL, set_drive_true_emulation, NULL }, RESOURCE_INT_LIST_END }; @@ -361,13 +411,11 @@ static resource_int_t res_drive_rtc[] = { int drive_resources_init(void) { - unsigned int dnr; - drive_t *drive; + int dnr; int has_iec; int i; switch (machine_class) { - case VICE_MACHINE_NONE: case VICE_MACHINE_PET: case VICE_MACHINE_CBM5x0: case VICE_MACHINE_CBM6x0: @@ -378,26 +426,34 @@ int drive_resources_init(void) has_iec = 1; } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + drive_t *drive0 = unit->drives[0]; + /* TODO: add resources for drive 1 */ res_drive[0].name = lib_msprintf("Drive%iExtendImagePolicy", dnr + 8); - res_drive[0].value_ptr = (int *)&(drive->extend_image_policy); - res_drive[0].param = uint_to_void_ptr(dnr); + res_drive[0].value_ptr = (int *)&(drive0->extend_image_policy); + res_drive[0].param = vice_uint_to_ptr(dnr); res_drive[1].name = lib_msprintf("Drive%iIdleMethod", dnr + 8); - res_drive[1].value_ptr = &(drive->idling_method); - res_drive[1].param = uint_to_void_ptr(dnr); + res_drive[1].value_ptr = &(unit->idling_method); + res_drive[1].param = vice_uint_to_ptr(dnr); res_drive[2].name = lib_msprintf("Drive%iRPM", dnr + 8); - res_drive[2].value_ptr = &(drive->rpm); - res_drive[2].param = uint_to_void_ptr(dnr); - res_drive[3].name = lib_msprintf("Drive%iWobble", dnr + 8); - res_drive[3].value_ptr = &(drive->rpm_wobble); - res_drive[3].param = uint_to_void_ptr(dnr); + res_drive[2].value_ptr = &(drive0->rpm); + res_drive[2].param = vice_uint_to_ptr(dnr); + res_drive[3].name = lib_msprintf("Drive%iWobbleFrequency", dnr + 8); + res_drive[3].value_ptr = &(drive0->wobble_frequency); + res_drive[3].param = vice_uint_to_ptr(dnr); + res_drive[4].name = lib_msprintf("Drive%iWobbleAmplitude", dnr + 8); + res_drive[4].value_ptr = &(drive0->wobble_amplitude); + res_drive[4].param = vice_uint_to_ptr(dnr); + res_drive[5].name = lib_msprintf("Drive%iTrueEmulation", dnr + 8); + res_drive[5].value_ptr = &(drive0->true_emulation); + res_drive[5].param = vice_uint_to_ptr(dnr); if (has_iec) { res_drive_rtc[0].name = lib_msprintf("Drive%iRTCSave", dnr + 8); - res_drive_rtc[0].value_ptr = &(drive->rtc_save); - res_drive_rtc[0].param = uint_to_void_ptr(dnr); + res_drive_rtc[0].value_ptr = &(unit->rtc_save); + res_drive_rtc[0].param = vice_uint_to_ptr(dnr); if (resources_register_int(res_drive_rtc) < 0) { return -1; } @@ -407,7 +463,7 @@ int drive_resources_init(void) return -1; } - for (i = 0; i < 4; i++) { + for (i = 0; i <= 5; i++) { lib_free(res_drive[i].name); } if (has_iec) { @@ -429,16 +485,3 @@ void drive_resources_shutdown(void) { machine_drive_resources_shutdown(); } - -/* FIXME: (re)move this! */ -#ifdef ANDROID_COMPILE -void loader_set_drive_true_emulation(int val) -{ - set_drive_true_emulation(val, 0); -} - -int loader_get_drive_true_emulation() -{ - return drive_true_emulation; -} -#endif diff --git a/src/Emulators/vice/drive/drive-resources.h b/src/Emulators/vice/drive/drive-resources.h index 214d7858..3d2868be 100644 --- a/src/Emulators/vice/drive/drive-resources.h +++ b/src/Emulators/vice/drive/drive-resources.h @@ -27,7 +27,10 @@ #ifndef VICE_DRIVE_RESOURCES_H #define VICE_DRIVE_RESOURCES_H -extern int drive_resources_init(void); -extern void drive_resources_shutdown(void); +extern int drive_sound_emulation; +extern int drive_sound_emulation_volume; + +int drive_resources_init(void); +void drive_resources_shutdown(void); #endif diff --git a/src/Emulators/vice/drive/drive-snapshot.c b/src/Emulators/vice/drive/drive-snapshot.c index b506c0f9..c25611c8 100644 --- a/src/Emulators/vice/drive/drive-snapshot.c +++ b/src/Emulators/vice/drive/drive-snapshot.c @@ -3,6 +3,7 @@ * * Written by * Andreas Boose + * groepaz * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -24,6 +25,8 @@ * */ +/* #define DEBUG_DRIVESNAPSHOT */ + #include "vice.h" #include @@ -58,10 +61,13 @@ #include "p64.h" #include "ViceWrapper.h" -/* Currently the drive snapshot only handles 2 drives. */ +#ifdef DEBUG_DRIVESNAPSHOT +#define DBG(x) printf x +#else +#define DBG(x) +#endif -/* Logging. */ -static log_t drive_snapshot_log = LOG_ERR; +static log_t drive_snapshot_log = LOG_DEFAULT; static int drive_snapshot_write_image_module(snapshot_t *s, unsigned int dnr); static int drive_snapshot_write_gcrimage_module(snapshot_t *s, @@ -104,190 +110,196 @@ Type DWORD 2 drive type */ -#define DRIVE_SNAP_MAJOR 1 -#define DRIVE_SNAP_MINOR 4 +#define DRIVE_SNAP_MAJOR 2 +#define DRIVE_SNAP_MINOR 0 int drive_snapshot_write_module(snapshot_t *s, int save_disks, int save_roms) { - int i; - char snap_module_name[] = "DRIVE"; + int unr, dnr; + char snap_module_name[8]; snapshot_module_t *m; - DWORD rotation_table_ptr[DRIVE_NUM]; - BYTE GCR_image[4], P64_image[4]; - int drive_true_emulation; + uint32_t rotation_table_ptr[NUM_DISK_UNITS]; + int has_tde[NUM_DISK_UNITS]; + int has_drives[NUM_DISK_UNITS]; int sync_factor; + diskunit_context_t *unit; drive_t *drive; - resources_get_int("DriveTrueEmulation", &drive_true_emulation); - - if (vdrive_snapshot_module_write(s, drive_true_emulation ? 10 : 8) < 0) { + /* write vdrive info */ + if (vdrive_snapshot_module_write(s) < 0) { return -1; } - if (!drive_true_emulation) { - return 0; - } - drive_gcr_data_writeback_all(); + rotation_table_get(rotation_table_ptr); /* FIXME: should this not be per drive rather than unit? */ - rotation_table_get(rotation_table_ptr); + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + unit = diskunit_context[unr]; - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - GCR_image[i] = (drive->GCR_image_loaded == 0 || !save_disks) ? 0 : 1; - P64_image[i] = (drive->P64_image_loaded == 0 || !save_disks) ? 0 : 1; - } - - m = snapshot_module_create(s, snap_module_name, DRIVE_SNAP_MAJOR, - DRIVE_SNAP_MINOR); - if (m == NULL) { - return -1; - } + /* write info that is common for one unit */ + sprintf(snap_module_name, "DRIVE%i", 8 + unr); + m = snapshot_module_create(s, snap_module_name, DRIVE_SNAP_MAJOR, DRIVE_SNAP_MINOR); + if (m == NULL) { + return -1; + } - resources_get_int("MachineVideoStandard", &sync_factor); + has_drives[unr] = drive_is_dualdrive_by_devnr(unr + 8) ? 2 : 1; - if (SMW_DW(m, (DWORD)sync_factor) < 0) { - if (m != NULL) { - snapshot_module_close(m); - } - return -1; - } + resources_get_int_sprintf("Drive%iTrueEmulation", &has_tde[unr], unr + 8); - /* TODO: NUM_DRIVES drives instead of 2 */ - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; if (0 - || SMW_DW(m, (DWORD)(drive->attach_clk)) < 0 - || SMW_B(m, (BYTE)(drive->byte_ready_level)) < 0 - || SMW_B(m, (BYTE)(drive->clock_frequency)) < 0 - || SMW_W(m, (WORD)(drive->current_half_track + (drive->side * DRIVE_HALFTRACKS_1571))) < 0 - || SMW_DW(m, (DWORD)(drive->detach_clk)) < 0 - || SMW_B(m, (BYTE)0) < 0 - || SMW_B(m, (BYTE)0) < 0 - || SMW_B(m, (BYTE)(drive->extend_image_policy)) < 0 - || SMW_DW(m, (DWORD)(drive->GCR_head_offset)) < 0 - || SMW_B(m, (BYTE)(drive->GCR_read)) < 0 - || SMW_B(m, (BYTE)(drive->GCR_write_value)) < 0 - || SMW_B(m, (BYTE)(drive->idling_method)) < 0 - || SMW_B(m, (BYTE)(drive->parallel_cable)) < 0 - || SMW_B(m, (BYTE)(drive->read_only)) < 0 - || SMW_DW(m, (DWORD)(rotation_table_ptr[i])) < 0 - || SMW_DW(m, (DWORD)(drive->type)) < 0 - - /* rotation */ - || SMW_DW(m, (DWORD)(drive->snap_accum)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_rotation_last_clk)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_bit_counter)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_zero_count)) < 0 - || SMW_W(m, (WORD)(drive->snap_last_read_data)) < 0 - || SMW_B(m, (BYTE)(drive->snap_last_write_data)) < 0 - || SMW_DW(m, (BYTE)(drive->snap_seed)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_speed_zone)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_ue7_dcba)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_ue7_counter)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_uf4_counter)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_fr_randcount)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_filter_counter)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_filter_state)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_filter_last_state)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_write_flux)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_PulseHeadPosition)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_xorShift32)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_so_delay)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_cycle_index)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_ref_advance)) < 0 - || SMW_DW(m, (DWORD)(drive->snap_req_ref_cycles)) < 0 - + || SMW_B(m, (uint8_t)has_tde[unr]) < 0 + || SMW_B(m, (uint8_t)has_drives[unr]) < 0 ) { if (m != NULL) { snapshot_module_close(m); } return -1; } - } - /* new snapshot members */ - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (0 - || SMW_DW(m, (DWORD)(drive->attach_detach_clk)) < 0 - ) { - if (m != NULL) { - snapshot_module_close(m); + DBG(("writing snapshot module: '%s' with TDE %s, Drives: %i\n", + snap_module_name, has_tde[unr] ? "enabled" : "disabled", has_drives[unr])); + + if (has_tde[unr]) { + + /* FIXME: does this really have to go into the drive snapshot? */ + resources_get_int("MachineVideoStandard", &sync_factor); + if (SMW_DW(m, (uint32_t)sync_factor) < 0) { + if (m != NULL) { + snapshot_module_close(m); + } + return -1; } - return -1; - } - } - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (0 - || SMW_B(m, (BYTE)(drive->byte_ready_edge)) < 0 - || SMW_B(m, (BYTE)(drive->byte_ready_active)) < 0 - ) { - if (m != NULL) { - snapshot_module_close(m); + for (dnr = 0; dnr < has_drives[unr]; dnr++) { + /* write info for each individual drive */ + drive = unit->drives[dnr]; + DBG(("unit %i drive %d (%p)\n", unr + 8, dnr, (void *)drive)); + if (0 + || SMW_CLOCK(m, drive->attach_clk) < 0 + || SMW_B(m, (uint8_t)(drive->byte_ready_level)) < 0 + || SMW_B(m, (uint8_t)(unit->clock_frequency)) < 0 + || SMW_W(m, (uint16_t)(drive->current_half_track + (drive->side * DRIVE_HALFTRACKS_1571))) < 0 + || SMW_CLOCK(m, drive->detach_clk) < 0 + || SMW_B(m, (uint8_t)(drive->extend_image_policy)) < 0 + || SMW_DW(m, (uint32_t)(drive->GCR_head_offset)) < 0 + || SMW_B(m, (uint8_t)(drive->GCR_read)) < 0 + || SMW_B(m, (uint8_t)(drive->GCR_write_value)) < 0 + || SMW_B(m, (uint8_t)(unit->idling_method)) < 0 + || SMW_B(m, (uint8_t)(unit->parallel_cable)) < 0 + || SMW_B(m, (uint8_t)(drive->read_only)) < 0 + || SMW_DW(m, (uint32_t)(rotation_table_ptr[unr])) < 0 + || SMW_DW(m, (uint32_t)(unit->type)) < 0 + + /* rotation */ + || SMW_DW(m, (uint32_t)(drive->snap_accum)) < 0 + || SMW_CLOCK(m, drive->snap_rotation_last_clk) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_bit_counter)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_zero_count)) < 0 + || SMW_W(m, (uint16_t)(drive->snap_last_read_data)) < 0 + || SMW_B(m, (uint8_t)(drive->snap_last_write_data)) < 0 + || SMW_DW(m, (uint8_t)(drive->snap_seed)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_speed_zone)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_ue7_dcba)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_ue7_counter)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_uf4_counter)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_fr_randcount)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_filter_counter)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_filter_state)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_filter_last_state)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_write_flux)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_PulseHeadPosition)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_xorShift32)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_so_delay)) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_cycle_index)) < 0 + || SMW_CLOCK(m, drive->snap_ref_advance) < 0 + || SMW_DW(m, (uint32_t)(drive->snap_req_ref_cycles)) < 0 + || SMW_CLOCK(m, drive->attach_detach_clk) < 0 + || SMW_B(m, (uint8_t)(drive->byte_ready_edge)) < 0 + || SMW_B(m, (uint8_t)(drive->byte_ready_active)) < 0 + ) { + if (m != NULL) { + snapshot_module_close(m); + } + return -1; + } } + } + + if (snapshot_module_close(m) < 0) { return -1; } - } - if (snapshot_module_close(m) < 0) { - return -1; } - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (drive->enable) { - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - if (drivecpu65c02_snapshot_write_module(drive_context[i], s) < 0) { - return -1; + /* save state of drive CPUs to snapshot */ + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + if (has_tde[unr]) { + /* FIXME: what about the second drive of a unit? */ + unit = diskunit_context[unr]; + + if (unit->enable) { + DBG(("drive CPU unit %i\n", unr +8)); + if (unit->type == DRIVE_TYPE_2000 || + unit->type == DRIVE_TYPE_4000 || + unit->type == DRIVE_TYPE_CMDHD) { + if (drivecpu65c02_snapshot_write_module(diskunit_context[unr], s) < 0) { + return -1; + } + } else { + if (drivecpu_snapshot_write_module(diskunit_context[unr], s) < 0) { + return -1; + } } - } else { - if (drivecpu_snapshot_write_module(drive_context[i], s) < 0) { + if (machine_drive_snapshot_write(diskunit_context[unr], s) < 0) { return -1; } } - if (machine_drive_snapshot_write(drive_context[i], s) < 0) { - return -1; + } + } + + /* put disk images to snapshot */ + if (save_disks) { + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + /* FIXME: what about the second drive of a unit? */ + /* FIXME: shouldnt we save the image also for vdrive? */ + if (has_tde[unr]) { + /* FIXME: is this correct? does the submodule save 2 images or do we have to do it here? */ + for (dnr = 0; dnr < has_drives[unr]; dnr++) { + drive = diskunit_context[unr]->drives[dnr]; + DBG(("drive image unit %i drive %i\n", unr + 8, dnr)); + if (drive->GCR_image_loaded > 0) { + DBG(("gcr image unit %i drive %i\n", unr + 8, dnr)); + if (drive_snapshot_write_gcrimage_module(s, unr) < 0) { + return -1; + } + } else if (drive->P64_image_loaded > 0) { + DBG(("p64 image unit %i drive %i\n", unr + 8, dnr)); + if (drive_snapshot_write_p64image_module(s, unr) < 0) { + return -1; + } + } else { + DBG(("common image unit %i drive %i\n", unr + 8, dnr)); + if (drive_snapshot_write_image_module(s, unr) < 0) { + return -1; + } + } + } } } } - if (save_disks) { - if (GCR_image[0] > 0) { - if (drive_snapshot_write_gcrimage_module(s, 0) < 0) { - return -1; - } - } else if (P64_image[0] > 0) { - if (drive_snapshot_write_p64image_module(s, 0) < 0) { - return -1; - } - } else { - if (drive_snapshot_write_image_module(s, 0) < 0) { - return -1; - } - } - if (GCR_image[1] > 0) { - if (drive_snapshot_write_gcrimage_module(s, 1) < 0) { - return -1; - } - } else if (P64_image[1] > 0) { - if (drive_snapshot_write_p64image_module(s, 1) < 0) { - return -1; - } - } else { - if (drive_snapshot_write_image_module(s, 1) < 0) { - return -1; - } - } - } - - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (save_roms && drive->enable) { - if (driverom_snapshot_write(s, drive) < 0) { - return -1; + /* put drive roms to snapshot */ + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + if (has_tde[unr]) { + unit = diskunit_context[unr]; + drive = unit->drives[0]; + + if (save_roms && unit->enable) { + DBG(("drive ROM unit %i\n", unr + 8)); + if (driverom_snapshot_write(s, drive) < 0) { + return -1; + } } } } @@ -297,399 +309,272 @@ int drive_snapshot_write_module(snapshot_t *s, int save_disks, int save_roms) int drive_snapshot_read_module(snapshot_t *s, int read_roms, int read_disks) { - BYTE major_version, minor_version; - int i; + uint8_t major_version, minor_version; + int unr, dnr; snapshot_module_t *m; - char snap_module_name[] = "DRIVE"; - DWORD rotation_table_ptr[DRIVE_NUM]; - CLOCK attach_clk[DRIVE_NUM]; - CLOCK detach_clk[DRIVE_NUM]; - CLOCK attach_detach_clk[DRIVE_NUM]; - int drive_true_emulation; + char snap_module_name[8]; + uint32_t rotation_table_ptr[NUM_DISK_UNITS]; + int has_tde[NUM_DISK_UNITS]; + CLOCK attach_clk[NUM_DISK_UNITS]; + CLOCK detach_clk[NUM_DISK_UNITS]; + CLOCK attach_detach_clk[NUM_DISK_UNITS]; int sync_factor; drive_t *drive; - int dummy; - int half_track[DRIVE_NUM]; - - m = snapshot_module_open(s, snap_module_name, - &major_version, &minor_version); - if (m == NULL) { - /* If this module is not found true emulation is off. */ - resources_set_int("DriveTrueEmulation", 0); - return 0; - } + diskunit_context_t *unit; + int half_track[NUM_DISK_UNITS]; + int has_drives[NUM_DISK_UNITS]; drive_gcr_data_writeback_all(); - if (major_version > DRIVE_SNAP_MAJOR || minor_version > DRIVE_SNAP_MINOR) { - log_error(drive_snapshot_log, - "Snapshot module version (%d.%d) newer than %d.%d.", - major_version, minor_version, - DRIVE_SNAP_MAJOR, DRIVE_SNAP_MINOR); - } + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + unit = diskunit_context[unr]; + + /* read info that is common for one unit */ + sprintf(snap_module_name, "DRIVE%i", 8 + unr); + m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); + if (m == NULL) { + /* If this module is not found true emulation is off. */ + /*resources_set_int("DriveTrueEmulation", 0);*/ + resources_set_int_sprintf("Drive%iTrueEmulation", 0, unr + 8); + has_tde[unr] = 0; + continue; + } - /* If this module exists true emulation is enabled. */ - /* XXX drive_true_emulation = 1 */ - resources_set_int("DriveTrueEmulation", 1); + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(major_version, minor_version, DRIVE_SNAP_MAJOR, DRIVE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + snapshot_module_close(m); + return -1; + } - if (SMR_DW_INT(m, &sync_factor) < 0) { - snapshot_module_close(m); - return -1; - } + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(major_version, minor_version, DRIVE_SNAP_MAJOR, DRIVE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + snapshot_module_close(m); + return -1; + } - /* TODO: NUM_DRIVES drives instead of 2 */ - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - - /* Partially read 1.0 snapshots */ - if (major_version == 1 && minor_version == 0) { - if (0 - || SMR_DW_UL(m, &(drive->snap_accum)) < 0 - || SMR_DW(m, &(attach_clk[i])) < 0 - || SMR_DW_INT(m, &dummy) < 0 - || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 - || SMR_B_INT(m, &(drive->clock_frequency)) < 0 - || SMR_W_INT(m, &half_track[i]) < 0 - || SMR_DW(m, &(detach_clk[i])) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 - || SMR_B_INT(m, &dummy) < 0 - || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 - || SMR_B(m, &(drive->GCR_read)) < 0 - || SMR_B(m, &(drive->GCR_write_value)) < 0 - || SMR_B_INT(m, &(drive->idling_method)) < 0 - || SMR_B_INT(m, &dummy) < 0 - || SMR_B_INT(m, &(drive->parallel_cable)) < 0 - || SMR_B_INT(m, &(drive->read_only)) < 0 - || SMR_DW(m, &(drive->snap_rotation_last_clk)) < 0 - || SMR_DW(m, &rotation_table_ptr[i]) < 0 - || SMR_DW_UINT(m, &(drive->type)) < 0 - ) { - snapshot_module_close(m); - return -1; - } + if (0 + || SMR_B_INT(m, &has_tde[unr]) < 0 + || SMR_B_INT(m, &has_drives[unr]) < 0 + ) { + snapshot_module_close(m); + return -1; + } + resources_set_int_sprintf("Drive%iTrueEmulation", has_tde[unr], unr + 8); - /* Partially read 1.1 snapshots */ - } else if (major_version == 1 && minor_version == 1) { - if (0 - || SMR_DW(m, &(attach_clk[i])) < 0 - || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 - || SMR_B_INT(m, &(drive->clock_frequency)) < 0 - || SMR_W_INT(m, &half_track[i]) < 0 - || SMR_DW(m, &(detach_clk[i])) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 - || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 - || SMR_B(m, &(drive->GCR_read)) < 0 - || SMR_B(m, &(drive->GCR_write_value)) < 0 - || SMR_B_INT(m, &(drive->idling_method)) < 0 - || SMR_B_INT(m, &(drive->parallel_cable)) < 0 - || SMR_B_INT(m, &(drive->read_only)) < 0 - || SMR_DW(m, &rotation_table_ptr[i]) < 0 - || SMR_DW_UINT(m, &(drive->type)) < 0 - - || SMR_DW_UL(m, &(drive->snap_accum)) < 0 - || SMR_DW(m, &(drive->snap_rotation_last_clk)) < 0 - || SMR_DW_INT(m, &(drive->snap_bit_counter)) < 0 - || SMR_DW_INT(m, &(drive->snap_zero_count)) < 0 - || SMR_W_INT(m, &(drive->snap_last_read_data)) < 0 - || SMR_B(m, &(drive->snap_last_write_data)) < 0 - || SMR_DW_INT(m, &(drive->snap_seed)) < 0 - ) { - snapshot_module_close(m); - return -1; - } + DBG(("reading snapshot module: '%s' with TDE %s, Drives: %i\n", + snap_module_name, has_tde[unr] ? "enabled" : "disabled", has_drives[unr])); - /* Partially read 1.2 snapshots */ - } else if (major_version == 1 && minor_version == 2) { - if (0 - || SMR_DW(m, &(attach_clk[i])) < 0 - || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 - || SMR_B_INT(m, &(drive->clock_frequency)) < 0 - || SMR_W_INT(m, &half_track[i]) < 0 - || SMR_DW(m, &(detach_clk[i])) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 - || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 - || SMR_B(m, &(drive->GCR_read)) < 0 - || SMR_B(m, &(drive->GCR_write_value)) < 0 - || SMR_B_INT(m, &(drive->idling_method)) < 0 - || SMR_B_INT(m, &(drive->parallel_cable)) < 0 - || SMR_B_INT(m, &(drive->read_only)) < 0 - || SMR_DW(m, &rotation_table_ptr[i]) < 0 - || SMR_DW_UINT(m, &(drive->type)) < 0 - - || SMR_DW_UL(m, &(drive->snap_accum)) < 0 - || SMR_DW(m, &(drive->snap_rotation_last_clk)) < 0 - || SMR_DW_INT(m, &(drive->snap_bit_counter)) < 0 - || SMR_DW_INT(m, &(drive->snap_zero_count)) < 0 - || SMR_W_INT(m, &(drive->snap_last_read_data)) < 0 - || SMR_B(m, &(drive->snap_last_write_data)) < 0 - || SMR_DW_INT(m, &(drive->snap_seed)) < 0 - || SMR_DW(m, &(drive->snap_speed_zone)) < 0 - || SMR_DW(m, &(drive->snap_ue7_dcba)) < 0 - || SMR_DW(m, &(drive->snap_ue7_counter)) < 0 - || SMR_DW(m, &(drive->snap_uf4_counter)) < 0 - || SMR_DW(m, &(drive->snap_fr_randcount)) < 0 - || SMR_DW(m, &(drive->snap_filter_counter)) < 0 - || SMR_DW(m, &(drive->snap_filter_state)) < 0 - || SMR_DW(m, &(drive->snap_filter_last_state)) < 0 - || SMR_DW(m, &(drive->snap_write_flux)) < 0 - || SMR_DW(m, &(drive->snap_PulseHeadPosition)) < 0 - || SMR_DW(m, &(drive->snap_xorShift32)) < 0 - ) { - snapshot_module_close(m); - return -1; - } - } else if (major_version == 1 && minor_version == 3) { - if (0 - || SMR_DW(m, &(attach_clk[i])) < 0 - || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 - || SMR_B_INT(m, &(drive->clock_frequency)) < 0 - || SMR_W_INT(m, &half_track[i]) < 0 - || SMR_DW(m, &(detach_clk[i])) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 - || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 - || SMR_B(m, &(drive->GCR_read)) < 0 - || SMR_B(m, &(drive->GCR_write_value)) < 0 - || SMR_B_INT(m, &(drive->idling_method)) < 0 - || SMR_B_INT(m, &(drive->parallel_cable)) < 0 - || SMR_B_INT(m, &(drive->read_only)) < 0 - || SMR_DW(m, &rotation_table_ptr[i]) < 0 - || SMR_DW_UINT(m, &(drive->type)) < 0 - - || SMR_DW_UL(m, &(drive->snap_accum)) < 0 - || SMR_DW(m, &(drive->snap_rotation_last_clk)) < 0 - || SMR_DW_INT(m, &(drive->snap_bit_counter)) < 0 - || SMR_DW_INT(m, &(drive->snap_zero_count)) < 0 - || SMR_W_INT(m, &(drive->snap_last_read_data)) < 0 - || SMR_B(m, &(drive->snap_last_write_data)) < 0 - || SMR_DW_INT(m, &(drive->snap_seed)) < 0 - || SMR_DW(m, &(drive->snap_speed_zone)) < 0 - || SMR_DW(m, &(drive->snap_ue7_dcba)) < 0 - || SMR_DW(m, &(drive->snap_ue7_counter)) < 0 - || SMR_DW(m, &(drive->snap_uf4_counter)) < 0 - || SMR_DW(m, &(drive->snap_fr_randcount)) < 0 - || SMR_DW(m, &(drive->snap_filter_counter)) < 0 - || SMR_DW(m, &(drive->snap_filter_state)) < 0 - || SMR_DW(m, &(drive->snap_filter_last_state)) < 0 - || SMR_DW(m, &(drive->snap_write_flux)) < 0 - || SMR_DW(m, &(drive->snap_PulseHeadPosition)) < 0 - || SMR_DW(m, &(drive->snap_xorShift32)) < 0 - || SMR_DW(m, &(drive->snap_so_delay)) < 0 - ) { + if (has_tde[unr]) { + + /* FIXME: does this really have to go into the drive snapshot? */ + if (SMR_DW_INT(m, &sync_factor) < 0) { snapshot_module_close(m); return -1; } - } else { - if (0 - || SMR_DW(m, &(attach_clk[i])) < 0 - || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 - || SMR_B_INT(m, &(drive->clock_frequency)) < 0 - || SMR_W_INT(m, &half_track[i]) < 0 - || SMR_DW(m, &(detach_clk[i])) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B(m, (BYTE *)&dummy) < 0 - || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 - || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 - || SMR_B(m, &(drive->GCR_read)) < 0 - || SMR_B(m, &(drive->GCR_write_value)) < 0 - || SMR_B_INT(m, &(drive->idling_method)) < 0 - || SMR_B_INT(m, &(drive->parallel_cable)) < 0 - || SMR_B_INT(m, &(drive->read_only)) < 0 - || SMR_DW(m, &rotation_table_ptr[i]) < 0 - || SMR_DW_UINT(m, &(drive->type)) < 0 - - || SMR_DW_UL(m, &(drive->snap_accum)) < 0 - || SMR_DW(m, &(drive->snap_rotation_last_clk)) < 0 - || SMR_DW_INT(m, &(drive->snap_bit_counter)) < 0 - || SMR_DW_INT(m, &(drive->snap_zero_count)) < 0 - || SMR_W_INT(m, &(drive->snap_last_read_data)) < 0 - || SMR_B(m, &(drive->snap_last_write_data)) < 0 - || SMR_DW_INT(m, &(drive->snap_seed)) < 0 - || SMR_DW(m, &(drive->snap_speed_zone)) < 0 - || SMR_DW(m, &(drive->snap_ue7_dcba)) < 0 - || SMR_DW(m, &(drive->snap_ue7_counter)) < 0 - || SMR_DW(m, &(drive->snap_uf4_counter)) < 0 - || SMR_DW(m, &(drive->snap_fr_randcount)) < 0 - || SMR_DW(m, &(drive->snap_filter_counter)) < 0 - || SMR_DW(m, &(drive->snap_filter_state)) < 0 - || SMR_DW(m, &(drive->snap_filter_last_state)) < 0 - || SMR_DW(m, &(drive->snap_write_flux)) < 0 - || SMR_DW(m, &(drive->snap_PulseHeadPosition)) < 0 - || SMR_DW(m, &(drive->snap_xorShift32)) < 0 - || SMR_DW(m, &(drive->snap_so_delay)) < 0 - || SMR_DW(m, &(drive->snap_cycle_index)) < 0 - || SMR_DW(m, &(drive->snap_ref_advance)) < 0 - || SMR_DW(m, &(drive->snap_req_ref_cycles)) < 0 - ) { - snapshot_module_close(m); - return -1; + + for (dnr = 0; dnr < has_drives[unr]; dnr++) { + /* read info for each individual drive */ + drive = unit->drives[dnr]; + DBG(("unit %i drive %d (%p)\n", unr + 8, dnr, (void *)drive)); + + if (0 + || SMR_CLOCK(m, &(attach_clk[unr])) < 0 + || SMR_B_INT(m, (int *)&(drive->byte_ready_level)) < 0 + || SMR_B_INT(m, &(unit->clock_frequency)) < 0 + || SMR_W_INT(m, &half_track[unr]) < 0 + || SMR_CLOCK(m, &(detach_clk[unr])) < 0 + || SMR_B_INT(m, &(drive->extend_image_policy)) < 0 + || SMR_DW_UINT(m, &(drive->GCR_head_offset)) < 0 + || SMR_B(m, &(drive->GCR_read)) < 0 + || SMR_B(m, &(drive->GCR_write_value)) < 0 + || SMR_B_INT(m, &(unit->idling_method)) < 0 + || SMR_B_INT(m, &(unit->parallel_cable)) < 0 + || SMR_B_INT(m, &(drive->read_only)) < 0 + || SMR_DW(m, &rotation_table_ptr[unr]) < 0 + || SMR_DW_UINT(m, &(unit->type)) < 0 + + || SMR_DW_UL(m, &(drive->snap_accum)) < 0 + || SMR_CLOCK(m, &(drive->snap_rotation_last_clk)) < 0 + || SMR_DW_INT(m, &(drive->snap_bit_counter)) < 0 + || SMR_DW_INT(m, &(drive->snap_zero_count)) < 0 + || SMR_W_INT(m, &(drive->snap_last_read_data)) < 0 + || SMR_B(m, &(drive->snap_last_write_data)) < 0 + || SMR_DW_INT(m, &(drive->snap_seed)) < 0 + || SMR_DW(m, &(drive->snap_speed_zone)) < 0 + || SMR_DW(m, &(drive->snap_ue7_dcba)) < 0 + || SMR_DW(m, &(drive->snap_ue7_counter)) < 0 + || SMR_DW(m, &(drive->snap_uf4_counter)) < 0 + || SMR_DW(m, &(drive->snap_fr_randcount)) < 0 + || SMR_DW(m, &(drive->snap_filter_counter)) < 0 + || SMR_DW(m, &(drive->snap_filter_state)) < 0 + || SMR_DW(m, &(drive->snap_filter_last_state)) < 0 + || SMR_DW(m, &(drive->snap_write_flux)) < 0 + || SMR_DW(m, &(drive->snap_PulseHeadPosition)) < 0 + || SMR_DW(m, &(drive->snap_xorShift32)) < 0 + || SMR_DW(m, &(drive->snap_so_delay)) < 0 + || SMR_DW(m, &(drive->snap_cycle_index)) < 0 + || SMR_CLOCK(m, &(drive->snap_ref_advance)) < 0 + || SMR_DW(m, &(drive->snap_req_ref_cycles)) < 0 + || SMR_CLOCK(m, &(attach_detach_clk[unr])) < 0 + || SMR_B_INT(m, (int *)&(drive->byte_ready_edge)) < 0 + || SMR_B_INT(m, (int *)&(drive->byte_ready_active)) < 0 + ) { + snapshot_module_close(m); + return -1; + } } } + snapshot_module_close(m); + m = NULL; } - /* this one is new, so don't test so stay compatible with old snapshots */ - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - SMR_DW(m, &(attach_detach_clk[i])); - } - - /* these are even newer */ - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - SMR_B_INT(m, (int *)&(drive->byte_ready_edge)); - SMR_B_INT(m, (int *)&(drive->byte_ready_active)); - } - - snapshot_module_close(m); - m = NULL; - + DBG(("set rotation tables\n")); rotation_table_set(rotation_table_ptr); - drive = drive_context[0]->drive; - switch (drive->type) { - case DRIVE_TYPE_1540: - case DRIVE_TYPE_1541: - case DRIVE_TYPE_1541II: - case DRIVE_TYPE_1551: - case DRIVE_TYPE_1570: - case DRIVE_TYPE_1571: - case DRIVE_TYPE_1571CR: - case DRIVE_TYPE_1581: - case DRIVE_TYPE_2000: - case DRIVE_TYPE_4000: - case DRIVE_TYPE_2031: - case DRIVE_TYPE_1001: - case DRIVE_TYPE_2040: - case DRIVE_TYPE_3040: - case DRIVE_TYPE_4040: - case DRIVE_TYPE_8050: - case DRIVE_TYPE_8250: - drive->enable = 1; - machine_drive_rom_setup_image(0); - drivemem_init(drive_context[0], drive->type); - resources_set_int("Drive8IdleMethod", drive->idling_method); - driverom_initialize_traps(drive); - drive_set_active_led_color(drive->type, 0); - machine_bus_status_drivetype_set(8, 1); - break; - case DRIVE_TYPE_NONE: - drive_disable(drive_context[0]); - machine_bus_status_drivetype_set(8, 0); - break; - default: - return -1; - } - - drive = drive_context[1]->drive; - switch (drive->type) { - case DRIVE_TYPE_1540: - case DRIVE_TYPE_1541: - case DRIVE_TYPE_1541II: - case DRIVE_TYPE_1551: - case DRIVE_TYPE_1570: - case DRIVE_TYPE_1571: - case DRIVE_TYPE_1581: - case DRIVE_TYPE_2000: - case DRIVE_TYPE_4000: - case DRIVE_TYPE_2031: - case DRIVE_TYPE_1001: - /* drive 1 does not allow dual disk drive */ - drive->enable = 1; - machine_drive_rom_setup_image(1); - drivemem_init(drive_context[1], drive->type); - resources_set_int("Drive9IdleMethod", drive->idling_method); - driverom_initialize_traps(drive); - drive_set_active_led_color(drive->type, 1); - machine_bus_status_drivetype_set(9, 1); - break; - case DRIVE_TYPE_NONE: - case DRIVE_TYPE_8050: - case DRIVE_TYPE_8250: - drive_disable(drive_context[1]); - machine_bus_status_drivetype_set(9, 0); - break; - default: - return -1; + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + if (has_tde[unr]) { + unit = diskunit_context[unr]; + switch (unit->type) { + case DRIVE_TYPE_1540: + case DRIVE_TYPE_1541: + case DRIVE_TYPE_1541II: + case DRIVE_TYPE_1551: + case DRIVE_TYPE_1570: + case DRIVE_TYPE_1571: + case DRIVE_TYPE_1571CR: + case DRIVE_TYPE_1581: + case DRIVE_TYPE_2000: + case DRIVE_TYPE_4000: + case DRIVE_TYPE_CMDHD: + case DRIVE_TYPE_2031: + case DRIVE_TYPE_1001: + case DRIVE_TYPE_2040: + case DRIVE_TYPE_3040: + case DRIVE_TYPE_4040: + case DRIVE_TYPE_8050: + case DRIVE_TYPE_8250: + case DRIVE_TYPE_9000: + unit->enable = 1; + machine_drive_rom_setup_image(unr); + drivemem_init(unit); + resources_set_int_sprintf("Drive%iIdleMethod", unit->idling_method, unr + 8); + driverom_initialize_traps(unit); + drive_set_active_led_color(unit->type, 0); + machine_bus_status_drivetype_set(8 + unr, 1); + break; + case DRIVE_TYPE_NONE: + drive_disable(unit); + machine_bus_status_drivetype_set(8 + unr, 0); + break; + default: + return -1; + } + } } /* Clear parallel cable before undumping parallel port values. */ - for (i = 0; i < DRIVE_PC_NUM; i++) { - parallel_cable_drive_write(i, 0xff, PARALLEL_WRITE, 0); - parallel_cable_drive_write(i, 0xff, PARALLEL_WRITE, 1); + DBG(("set parallel cables\n")); + for (unr = 0; unr < DRIVE_PC_NUM; unr++) { + parallel_cable_drive_write(unr, 0xff, PARALLEL_WRITE, 0); + parallel_cable_drive_write(unr, 0xff, PARALLEL_WRITE, 1); } - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (drive->enable) { - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - if (drivecpu65c02_snapshot_read_module(drive_context[i], s) < 0) { + /* get state of drive CPUs */ + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + if (has_tde[unr]) { + /* FIXME: what about the second drive of a unit? */ + unit = diskunit_context[unr]; + + if (unit->enable) { + DBG(("drive CPU unit %i\n", unr +8)); + if (unit->type == DRIVE_TYPE_2000 || + unit->type == DRIVE_TYPE_4000 || + unit->type == DRIVE_TYPE_CMDHD) { + if (drivecpu65c02_snapshot_read_module(diskunit_context[unr], s) < 0) { + return -1; + } + } else { + if (drivecpu_snapshot_read_module(diskunit_context[unr], s) < 0) { + return -1; + } + } + if (machine_drive_snapshot_read(diskunit_context[unr], s) < 0) { return -1; } - } else { - if (drivecpu_snapshot_read_module(drive_context[i], s) < 0) { + } + } + } + + /* get image(s) */ + if (read_disks) { + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + /* FIXME: what about the second drive of a unit? */ + /* FIXME: shouldnt we save the image also for vdrive? */ + if (has_tde[unr]) { + /* FIXME: is this correct? does the submodule save 2 images or do we have to do it here? */ + for (dnr = 0; dnr < has_drives[unr]; dnr++) { + DBG(("drive image unit %i drive %i\n", unr + 8, dnr)); + if (drive_snapshot_read_image_module(s, unr) < 0 + || drive_snapshot_read_gcrimage_module(s, unr) < 0 + || drive_snapshot_read_p64image_module(s, unr) < 0) { return -1; } } - if (machine_drive_snapshot_read(drive_context[i], s) < 0) { - return -1; + } + } + } + + /* get drive roms */ + if (read_roms) { + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + if (has_tde[unr]) { + unit = diskunit_context[unr]; + drive = unit->drives[0]; + if (/*save_roms &&*/ unit->enable) { + DBG(("drive ROM unit %i\n", unr + 8)); + if (driverom_snapshot_read(s, drive) < 0) { + return -1; + } } } } + } - if (read_disks) - { - if (drive_snapshot_read_image_module(s, 0) < 0 - || drive_snapshot_read_gcrimage_module(s, 0) < 0 - || drive_snapshot_read_p64image_module(s, 0) < 0) { - return -1; - } - if (drive_snapshot_read_image_module(s, 1) < 0 - || drive_snapshot_read_gcrimage_module(s, 1) < 0 - || drive_snapshot_read_p64image_module(s, 1) < 0) { - return -1; - } - } - - if (read_roms) - { - if (driverom_snapshot_read(s, drive_context[0]->drive) < 0) { - return -1; - } - if (driverom_snapshot_read(s, drive_context[1]->drive) < 0) { - return -1; - } - } - - for (i = 0; i < 2; i++) { - drive = drive_context[i]->drive; - if (drive->type != DRIVE_TYPE_NONE) { - drive_enable(drive_context[i]); - drive->attach_clk = attach_clk[i]; - drive->detach_clk = detach_clk[i]; - drive->attach_detach_clk = attach_detach_clk[i]; + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + /* FIXME: what about the second drive of a unit? */ + unit = diskunit_context[unr]; + drive = unit->drives[0]; + + if (unit->type != DRIVE_TYPE_NONE) { + DBG(("enable drive %d\n", 8 + unr)); + drive_enable(diskunit_context[unr]); + drive->attach_clk = attach_clk[unr]; + drive->detach_clk = detach_clk[unr]; + drive->attach_detach_clk = attach_detach_clk[unr]; } } - for (i = 0; i < 2; i++) { + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { int side = 0; - drive = drive_context[i]->drive; - if (drive->type == DRIVE_TYPE_1570 - || drive->type == DRIVE_TYPE_1571 - || drive->type == DRIVE_TYPE_1571CR) { - if (half_track[i] > (DRIVE_HALFTRACKS_1571 + 1)) { - side = 1; - half_track[i] -= DRIVE_HALFTRACKS_1571; + unit = diskunit_context[unr]; + drive = unit->drives[0]; + /* FIXME: what about the current track in a virtual drive? */ + if (has_tde[unr]) { + if (unit->type == DRIVE_TYPE_1570 + || unit->type == DRIVE_TYPE_1571 + || unit->type == DRIVE_TYPE_1571CR) { + if (half_track[unr] > (DRIVE_HALFTRACKS_1571 + 1)) { + side = 1; + half_track[unr] -= DRIVE_HALFTRACKS_1571; + } } + DBG(("set half track for drive %d\n", 8 + unr)); + /* FIXME: what about the second drive of a unit? */ + drive_set_half_track(half_track[unr], side, drive); + resources_set_int("MachineVideoStandard", sync_factor); } - drive_set_half_track(half_track[i], side, drive); - resources_set_int("MachineVideoStandard", sync_factor); } /* stop currently active drive sounds (bug #3539422) @@ -697,16 +582,17 @@ int drive_snapshot_read_module(snapshot_t *s, int read_roms, int read_disks) * want/need to save a snapshot of its current state too */ drive_sound_stop(); - + DBG(("update IEC ports\n")); iec_update_ports_embedded(); + DBG(("update drive ui\n")); drive_update_ui_status(); - resources_get_int("DriveTrueEmulation", &drive_true_emulation); - - if (vdrive_snapshot_module_read(s, drive_true_emulation ? 10 : 8) < 0) { + DBG(("read vdrive snapshot module\n")); + if (vdrive_snapshot_module_read(s) < 0) { return -1; } + DBG(("drive_snapshot_read_module done\n")); return 0; } @@ -729,18 +615,19 @@ static int drive_snapshot_write_image_module(snapshot_t *s, unsigned int dnr) { char snap_module_name[10]; snapshot_module_t *m; - BYTE sector_data[0x100]; - WORD word; + uint8_t sector_data[0x100]; + uint16_t word; disk_addr_t dadr; int rc; drive_t *drive; - drive = drive_context[dnr]->drive; + /* TODO: drive 1? */ + drive = diskunit_context[dnr]->drives[0]; - if (drive->image == NULL) { - sprintf(snap_module_name, "NOIMAGE%i", dnr); + if (drive->image == NULL || diskunit_context[dnr]->type == DRIVE_TYPE_CMDHD) { + sprintf(snap_module_name, "NOIMAGE%u", dnr); } else { - sprintf(snap_module_name, "IMAGE%i", dnr); + sprintf(snap_module_name, "IMAGE%u", dnr); } m = snapshot_module_create(s, snap_module_name, IMAGE_SNAP_MAJOR, @@ -749,7 +636,7 @@ static int drive_snapshot_write_image_module(snapshot_t *s, unsigned int dnr) return -1; } - if (drive->image == NULL) { + if (drive->image == NULL || diskunit_context[dnr]->type == DRIVE_TYPE_CMDHD) { if (snapshot_module_close(m) < 0) { return -1; } @@ -785,32 +672,37 @@ static int drive_snapshot_write_image_module(snapshot_t *s, unsigned int dnr) static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; char snap_module_name[10]; - WORD word; + uint16_t word; char *filename = NULL; char *request_str; int len = 0; FILE *fp; - BYTE sector_data[0x100]; + uint8_t sector_data[0x100]; disk_addr_t dadr; int rc; drive_t *drive; - drive = drive_context[dnr]->drive; + /* TODO: drive 1? */ + drive = diskunit_context[dnr]->drives[0]; - sprintf(snap_module_name, "NOIMAGE%i", dnr); + sprintf(snap_module_name, "NOIMAGE%u", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); if (m != NULL) { - file_system_detach_disk(dnr + 8); + /* do not detach an existing DHD image as they aren't saved in the snapshot */ + if (diskunit_context[dnr]->type != DRIVE_TYPE_CMDHD) { + file_system_detach_disk(dnr + 8, 0); + } + file_system_detach_disk(dnr + 8, 1); snapshot_module_close(m); return 0; } - sprintf(snap_module_name, "IMAGE%i", dnr); + sprintf(snap_module_name, "IMAGE%u", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); @@ -818,11 +710,18 @@ static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) return 0; } - if (major_version > IMAGE_SNAP_MAJOR || minor_version > IMAGE_SNAP_MINOR) { - log_error(drive_snapshot_log, - "Snapshot module version (%d.%d) newer than %d.%d.", - major_version, minor_version, - IMAGE_SNAP_MAJOR, IMAGE_SNAP_MINOR); + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(major_version, minor_version, IMAGE_SNAP_MAJOR, IMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + snapshot_module_close(m); + return -1; + } + + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(major_version, minor_version, IMAGE_SNAP_MAJOR, IMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + snapshot_module_close(m); + return -1; } if (SMR_W(m, &word) < 0) { @@ -840,6 +739,9 @@ static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) case 8250: len = D82_FILE_SIZE; break; + case 9000: + len = drive->image->tracks * drive->image->sectors * 256; + break; default: log_error(drive_snapshot_log, "Snapshot of disk image unknown (type %d)", @@ -870,14 +772,15 @@ static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) fclose(fp); lib_free(filename); - if (file_system_attach_disk(dnr + 8, filename) < 0) { + if (file_system_attach_disk(dnr + 8, 0, filename) < 0) { log_error(drive_snapshot_log, "Invalid Disk Image"); lib_free(filename); snapshot_module_close(m); return -1; } + /* TODO: drive 1 */ - request_str = lib_msprintf("Disk image unit #%d imported from snapshot", + request_str = lib_msprintf("Disk image unit #%u imported from snapshot", dnr + 8); zfile_close_action(filename, ZFILE_REQUEST, request_str); lib_free(request_str); @@ -900,8 +803,6 @@ static int drive_snapshot_read_image_module(snapshot_t *s, unsigned int dnr) } } - vdrive_bam_reread_bam(dnr + 8); - snapshot_module_close(m); m = NULL; @@ -918,13 +819,13 @@ static int drive_snapshot_write_gcrimage_module(snapshot_t *s, unsigned int dnr) { char snap_module_name[10]; snapshot_module_t *m; - BYTE *data; + uint8_t *data; unsigned int i; drive_t *drive; - DWORD num_half_tracks, track_size; + uint32_t num_half_tracks, track_size; - drive = drive_context[dnr]->drive; - sprintf(snap_module_name, "GCRIMAGE%i", dnr); + drive = diskunit_context[dnr]->drives[0]; + sprintf(snap_module_name, "GCRIMAGE%u", dnr); m = snapshot_module_create(s, snap_module_name, GCRIMAGE_SNAP_MAJOR, GCRIMAGE_SNAP_MINOR); @@ -945,7 +846,7 @@ static int drive_snapshot_write_gcrimage_module(snapshot_t *s, unsigned int dnr) data = drive->gcr->tracks[i].data; track_size = data ? drive->gcr->tracks[i].size : 0; if (0 - || SMW_DW(m, (DWORD)track_size) < 0 + || SMW_DW(m, (uint32_t)track_size) < 0 || (track_size && SMW_BA(m, data, track_size) < 0) ) { break; @@ -961,16 +862,16 @@ static int drive_snapshot_write_gcrimage_module(snapshot_t *s, unsigned int dnr) static int drive_snapshot_read_gcrimage_module(snapshot_t *s, unsigned int dnr) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; char snap_module_name[10]; - BYTE *data; + uint8_t *data; unsigned int i; drive_t *drive; - DWORD num_half_tracks, track_size; + uint32_t num_half_tracks, track_size; - drive = drive_context[dnr]->drive; - sprintf(snap_module_name, "GCRIMAGE%i", dnr); + drive = diskunit_context[dnr]->drives[0]; + sprintf(snap_module_name, "GCRIMAGE%u", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); @@ -978,15 +879,19 @@ static int drive_snapshot_read_gcrimage_module(snapshot_t *s, unsigned int dnr) return 0; } - if (major_version != GCRIMAGE_SNAP_MAJOR - || minor_version != GCRIMAGE_SNAP_MINOR) { - log_error(drive_snapshot_log, - "Snapshot module version (%d.%d) not supported.", - major_version, minor_version); + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(major_version, minor_version, GCRIMAGE_SNAP_MAJOR, GCRIMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; } + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(major_version, minor_version, GCRIMAGE_SNAP_MAJOR, GCRIMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + snapshot_module_close(m); + return -1; + } if (0 || SMR_DW(m, &num_half_tracks) < 0 @@ -1053,8 +958,8 @@ static int drive_snapshot_write_p64image_module(snapshot_t *s, unsigned int dnr) TP64MemoryStream P64MemoryStreamInstance; PP64Image P64Image; - drive = drive_context[dnr]->drive; - sprintf(snap_module_name, "P64IMAGE%i", dnr); + drive = diskunit_context[dnr]->drives[0]; + sprintf(snap_module_name, "P64IMAGE%u", dnr); m = snapshot_module_create(s, snap_module_name, GCRIMAGE_SNAP_MAJOR, GCRIMAGE_SNAP_MINOR); @@ -1098,17 +1003,17 @@ static int drive_snapshot_write_p64image_module(snapshot_t *s, unsigned int dnr) static int drive_snapshot_read_p64image_module(snapshot_t *s, unsigned int dnr) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; char snap_module_name[10]; - BYTE *tmpbuf; + uint8_t *tmpbuf; drive_t *drive; TP64MemoryStream P64MemoryStreamInstance; PP64Image P64Image; - DWORD size; + uint32_t size; - drive = drive_context[dnr]->drive; - sprintf(snap_module_name, "P64IMAGE%i", dnr); + drive = diskunit_context[dnr]->drives[0]; + sprintf(snap_module_name, "P64IMAGE%u", dnr); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); @@ -1125,12 +1030,18 @@ static int drive_snapshot_read_p64image_module(snapshot_t *s, unsigned int dnr) return -1; } - if (major_version > P64IMAGE_SNAP_MAJOR - || minor_version > P64IMAGE_SNAP_MINOR) { - log_error(drive_snapshot_log, - "Snapshot module version (%d.%d) newer than %d.%d.", - major_version, minor_version, - P64IMAGE_SNAP_MAJOR, P64IMAGE_SNAP_MINOR); + /* reject snapshot modules newer than what we can handle (this VICE is too old) */ + if (snapshot_version_is_bigger(major_version, minor_version, P64IMAGE_SNAP_MAJOR, P64IMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + snapshot_module_close(m); + return -1; + } + + /* reject snapshot modules older than what we can handle (the snapshot is too old) */ + if (snapshot_version_is_smaller(major_version, minor_version, P64IMAGE_SNAP_MAJOR, P64IMAGE_SNAP_MINOR)) { + snapshot_set_error(SNAPSHOT_MODULE_INCOMPATIBLE); + snapshot_module_close(m); + return -1; } if (SMR_DW(m, &size) < 0) { diff --git a/src/Emulators/vice/drive/drive-snapshot.h b/src/Emulators/vice/drive/drive-snapshot.h index 79773c8d..682d5ce8 100644 --- a/src/Emulators/vice/drive/drive-snapshot.h +++ b/src/Emulators/vice/drive/drive-snapshot.h @@ -29,7 +29,7 @@ struct snapshot_s; -extern int drive_snapshot_write_module(struct snapshot_s *s, int save_disks, int save_roms); -extern int drive_snapshot_read_module(struct snapshot_s *s, int read_roms, int read_disks); +int drive_snapshot_write_module(struct snapshot_s *s, int save_disks, int save_roms); +int drive_snapshot_read_module(struct snapshot_s *s, int read_roms, int read_disks); #endif diff --git a/src/Emulators/vice/drive/drive-sound.c b/src/Emulators/vice/drive/drive-sound.c index a58b4949..f4e97ade 100644 --- a/src/Emulators/vice/drive/drive-sound.c +++ b/src/Emulators/vice/drive/drive-sound.c @@ -28,6 +28,7 @@ #include "archdep.h" #include "drive.h" +#include "drive-resources.h" #include "drive-sound.h" #include "sound.h" @@ -1420,38 +1421,97 @@ static const signed char bump[] = { static const signed char nosound[1] = { 0 }; -STATIC_PROTOTYPE sound_chip_t drive_sound; +static sound_chip_t drive_sound; -static WORD drive_sound_offset; -static const signed char *step[DRIVE_NUM]; -static const signed char *motor[DRIVE_NUM]; -static int stepvol[DRIVE_NUM]; -static int motorvol[DRIVE_NUM]; +static uint16_t drive_sound_offset; +static const signed char *step[NUM_DISK_UNITS]; +static const signed char *motor[NUM_DISK_UNITS]; +static int stepvol[NUM_DISK_UNITS]; +static int motorvol[NUM_DISK_UNITS]; static int cycles_per_sec = 1000000; static int sample_rate = 22050; /* resources */ -extern int drive_sound_emulation; -extern int drive_sound_emulation_volume; +#ifdef SOUND_SYSTEM_FLOAT +/* FIXME */ +static int drive_sound_machine_calculate_samples(sound_t **psid, float *pbuf, int nr, int scc, CLOCK *delta_t) +{ + int i, j, nos = 0; + static int div = 0; + float m, s; + + for (i = 0; i < nr; i++) { + pbuf[i] = 0.0; + + for (j = 0; j < NUM_DISK_UNITS; j++) { + m = ((((*motor[j]) * motorvol[j]) * drive_sound_emulation_volume) >> 8) / 32767.0; + s = ((((*step[j]) * stepvol[j]) * drive_sound_emulation_volume) >> 8) / 32767.0; -static int drive_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, int nr, int soc, int scc, int *delta_t) + pbuf[i] += m; + pbuf[i] += s; + } + div += 44100; + while (div >= sample_rate) { + div -= sample_rate; + nos = 1; + for (j = 0; j < NUM_DISK_UNITS; j++) { + motor[j]++; + if (motor[j] == &spinup[sizeof(spinup)]) { + motor[j] = hum; + } + if (motor[j] == &hum[sizeof(hum)]) { + motor[j] = hum; + } + if (motor[j] == &spindown[sizeof(spindown)]) { + motor[j] = nosound; + } + if (motor[j] == nosound + 1) { + motor[j] = nosound; + } else { + nos = 0; + } + step[j]++; + if (step[j] == &stepping[sizeof(stepping)]) { + step[j] = nosound; + } + if (step[j] == &stepping2[sizeof(stepping2)]) { + step[j] = nosound; + } + if (step[j] == &bump[sizeof(bump)]) { + step[j] = nosound; + } + if (step[j] == nosound + 1) { + step[j] = nosound; + } else { + nos = 0; + } + } + } + } + if (nos) { + drive_sound.chip_enabled = 0; + } + return nr; +} +#else +static int drive_sound_machine_calculate_samples(sound_t **psid, int16_t *pbuf, int nr, int soc, int scc, CLOCK *delta_t) { int i, j, nos = 0; static int div = 0; int m, s; for (i = 0; i < nr; i++) { - for (j = 0; j < DRIVE_NUM; j++) { + for (j = 0; j < NUM_DISK_UNITS; j++) { m = (((*motor[j]) * motorvol[j]) * drive_sound_emulation_volume) >> 8; s = (((*step[j]) * stepvol[j]) * drive_sound_emulation_volume) >> 8; switch (soc) { default: - case 1: + case SOUND_OUTPUT_MONO: pbuf[i] = sound_audio_mix(pbuf[i], m); pbuf[i] = sound_audio_mix(pbuf[i], s); break; - case 2: + case SOUND_OUTPUT_STEREO: pbuf[i * 2] = sound_audio_mix(pbuf[i * 2], m); pbuf[i * 2] = sound_audio_mix(pbuf[i * 2], s); pbuf[i * 2 + 1] = sound_audio_mix(pbuf[i * 2 + 1], m); @@ -1463,7 +1523,7 @@ static int drive_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, in while (div >= sample_rate) { div -= sample_rate; nos = 1; - for (j = 0; j < DRIVE_NUM; j++) { + for (j = 0; j < NUM_DISK_UNITS; j++) { motor[j]++; if (motor[j] == &spinup[sizeof(spinup)]) { motor[j] = hum; @@ -1502,6 +1562,7 @@ static int drive_sound_machine_calculate_samples(sound_t **psid, SWORD *pbuf, in } return nr; } +#endif static int drive_sound_machine_init(sound_t *psid, int speed, int cycles) { @@ -1510,10 +1571,6 @@ static int drive_sound_machine_init(sound_t *psid, int speed, int cycles) return 1; } -static void drive_sound_reset(sound_t *psid, CLOCK cpu_clk) -{ -} - static int drive_sound_machine_cycle_based(void) { return 0; @@ -1524,26 +1581,31 @@ static int drive_sound_machine_channels(void) return 1; } -static void drive_sound_machine_store(sound_t *psid, WORD addr, BYTE val) -{ -} - -static BYTE drive_sound_machine_read(sound_t *psid, WORD addr) -{ - return 0; -} +#ifdef SOUND_SYSTEM_FLOAT +/* stereo mixing placement of the drive sound */ +static sound_chip_mixing_spec_t drive_sound_mixing_spec[SOUND_CHIP_CHANNELS_MAX] = { + { + 100, /* left channel volume % in case of stereo output, default output to both */ + 100 /* right channel volume % in case of stereo output, default output to both */ + } +}; +#endif +/* Drive sound 'chip', emulates the sound of a 1541 disk drive */ static sound_chip_t drive_sound = { - NULL, /* no open */ - drive_sound_machine_init, - NULL, /* no close */ - drive_sound_machine_calculate_samples, - drive_sound_machine_store, - drive_sound_machine_read, - drive_sound_reset, - drive_sound_machine_cycle_based, - drive_sound_machine_channels, - 0 /* chip enabled */ + NULL, /* NO sound chip open function */ + drive_sound_machine_init, /* sound chip init function */ + NULL, /* NO sound chip close function */ + drive_sound_machine_calculate_samples, /* sound chip calculate samples function */ + NULL, /* NO sound chip store function */ + NULL, /* NO sound chip read function */ + NULL, /* NO sound chip reset function */ + drive_sound_machine_cycle_based, /* sound chip 'is_cycle_based()' function, chip is NOT cycle based */ + drive_sound_machine_channels, /* sound chip 'get_amount_of_channels()' function, sound chip has 1 channel */ +#ifdef SOUND_SYSTEM_FLOAT + drive_sound_mixing_spec, /* stereo mixing placement specs */ +#endif + 0 /* sound chip enabled flag, toggled upon device (de-)activation */ }; void drive_sound_update(int i, int unit) @@ -1552,7 +1614,7 @@ void drive_sound_update(int i, int unit) drive_sound.chip_enabled = 0; return; } - sound_store((WORD)drive_sound_offset, 0, 0); + sound_store((uint16_t)drive_sound_offset, 0, 0); switch (i) { case DRIVE_SOUND_MOTOR_ON: motor[unit] = spinup; @@ -1571,7 +1633,7 @@ void drive_sound_head(int track, int dir, int unit) drive_sound.chip_enabled = 0; return; } - sound_store((WORD)drive_sound_offset, 0, 0); + sound_store((uint16_t)drive_sound_offset, 0, 0); stepvol[unit] = 100 - track; if (track == 2 && dir == -1) { if (step[unit] == nosound) { @@ -1587,7 +1649,7 @@ void drive_sound_head(int track, int dir, int unit) void drive_sound_stop(void) { int i; - for (i = 0; i < DRIVE_NUM; i++) { + for (i = 0; i < NUM_DISK_UNITS; i++) { motor[i] = nosound; step[i] = nosound; stepvol[i] = 0; @@ -1600,7 +1662,7 @@ void drive_sound_init(void) int i; drive_sound_stop(); drive_sound_offset = sound_chip_register(&drive_sound); - for (i = 0; i < DRIVE_NUM; i++) { + for (i = 0; i < NUM_DISK_UNITS; i++) { motorvol[i] = 10; } } diff --git a/src/Emulators/vice/drive/drive-writeprotect.c b/src/Emulators/vice/drive/drive-writeprotect.c index 3334a00d..07411213 100644 --- a/src/Emulators/vice/drive/drive-writeprotect.c +++ b/src/Emulators/vice/drive/drive-writeprotect.c @@ -52,12 +52,14 @@ BYTE c64d_drive_writeprotect_sense_peek(drive_t *dptr) } /// -BYTE drive_writeprotect_sense(drive_t *dptr) +uint8_t drive_writeprotect_sense(drive_t *dptr) { + CLOCK clk = *(dptr->diskunit->clk_ptr); + /* Clear the write protection bit for the time the disk is pulled out on detach. */ if (dptr->detach_clk != (CLOCK)0) { - if (*(dptr->clk) - dptr->detach_clk < DRIVE_DETACH_DELAY) { + if (clk - dptr->detach_clk < DRIVE_DETACH_DELAY) { return 0x0; } dptr->detach_clk = (CLOCK)0; @@ -65,7 +67,7 @@ BYTE drive_writeprotect_sense(drive_t *dptr) /* Set the write protection bit for the minimum time until a new disk can be inserted. */ if (dptr->attach_detach_clk != (CLOCK)0) { - if (*(dptr->clk) - dptr->attach_detach_clk + if (clk - dptr->attach_detach_clk < DRIVE_ATTACH_DETACH_DELAY) { return 0x10; } @@ -74,7 +76,7 @@ BYTE drive_writeprotect_sense(drive_t *dptr) /* Clear the write protection bit for the time the disk is put in on attach. */ if (dptr->attach_clk != (CLOCK)0) { - if (*(dptr->clk) - dptr->attach_clk < DRIVE_ATTACH_DELAY) { + if (clk - dptr->attach_clk < DRIVE_ATTACH_DELAY) { return 0x0; } dptr->attach_clk = (CLOCK)0; diff --git a/src/Emulators/vice/drive/drive-writeprotect.h b/src/Emulators/vice/drive/drive-writeprotect.h index 7ee96078..8439fe24 100644 --- a/src/Emulators/vice/drive/drive-writeprotect.h +++ b/src/Emulators/vice/drive/drive-writeprotect.h @@ -31,6 +31,6 @@ struct drive_s; -extern BYTE drive_writeprotect_sense(struct drive_s *dptr); +uint8_t drive_writeprotect_sense(struct drive_s *dptr); #endif diff --git a/src/Emulators/vice/drive/drive.c b/src/Emulators/vice/drive/drive.c index 49612f33..1c6dd070 100644 --- a/src/Emulators/vice/drive/drive.c +++ b/src/Emulators/vice/drive/drive.c @@ -36,6 +36,8 @@ - check for byte ready *within* `BVC', `BVS' and `PHP'. - serial bus handling might be faster. */ +/* #define DEBUG_DRIVE */ + #include "vice.h" #include @@ -45,10 +47,10 @@ #include #include "attach.h" +#include "archdep.h" #include "diskconstants.h" #include "diskimage.h" #include "drive-check.h" -#include "drive-overflow.h" #include "drive.h" #include "drivecpu.h" #include "drivecpu65c02.h" @@ -66,79 +68,90 @@ #include "maincpu.h" #include "resources.h" #include "rotation.h" +#include "sound.h" #include "vicetypes.h" #include "uiapi.h" #include "ds1216e.h" #include "drive-sound.h" #include "p64.h" #include "monitor.h" +#include "monitor_network.h" +#include "monitor_binary.h" +#include "vsync.h" + +#ifdef DEBUG_DRIVE +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif static int drive_init_was_called = 0; -drive_context_t *drive_context[DRIVE_NUM]; +diskunit_context_t *diskunit_context[NUM_DISK_UNITS]; /* Generic drive logging goes here. */ -static log_t drive_log = LOG_ERR; +static log_t drive_log = LOG_DEFAULT; /* If nonzero, at least one vaild drive ROM has already been loaded. */ int rom_loaded = 0; /* ------------------------------------------------------------------------- */ -static int drive_led_color[DRIVE_NUM]; +static int drive_led_color[NUM_DISK_UNITS]; +static bool is_jammed[NUM_DISK_UNITS] = { false, false, false, false }; +static char *jam_reason[NUM_DISK_UNITS] = { NULL, NULL, NULL, NULL }; +static int jam_action = MACHINE_JAM_ACTION_DIALOG; /* ------------------------------------------------------------------------- */ -void drive_set_disk_memory(BYTE *id, unsigned int track, unsigned int sector, - struct drive_context_s *drv) +void drive_set_disk_memory(uint8_t *id, unsigned int track, unsigned int sector, + struct diskunit_context_s *unit) { - drive_t *drive; - - drive = drv->drive; - - if (drive->type == DRIVE_TYPE_1540 - || drive->type == DRIVE_TYPE_1541 - || drive->type == DRIVE_TYPE_1541II - || drive->type == DRIVE_TYPE_1570 - || drive->type == DRIVE_TYPE_1571 - || drive->type == DRIVE_TYPE_1571CR) { - drv->drive->drive_ram[0x12] = id[0]; - drv->drive->drive_ram[0x13] = id[1]; - drv->drive->drive_ram[0x16] = id[0]; - drv->drive->drive_ram[0x17] = id[1]; - drv->drive->drive_ram[0x18] = track; - drv->drive->drive_ram[0x19] = sector; - drv->drive->drive_ram[0x22] = track; + if (unit->type == DRIVE_TYPE_1540 + || unit->type == DRIVE_TYPE_1541 + || unit->type == DRIVE_TYPE_1541II + || unit->type == DRIVE_TYPE_1570 + || unit->type == DRIVE_TYPE_1571 + || unit->type == DRIVE_TYPE_1571CR) { + unit->drive_ram[0x12] = id[0]; + unit->drive_ram[0x13] = id[1]; + unit->drive_ram[0x16] = id[0]; + unit->drive_ram[0x17] = id[1]; + unit->drive_ram[0x18] = track; + unit->drive_ram[0x19] = sector; + unit->drive_ram[0x22] = track; } } -void drive_set_last_read(unsigned int track, unsigned int sector, BYTE *buffer, - struct drive_context_s *drv) +void drive_set_last_read(unsigned int track, unsigned int sector, uint8_t *buffer, + struct diskunit_context_s *unit) { drive_t *drive; int side = 0; - drive = drv->drive; + drive = unit->drives[0]; + /* TODO: drive 1 ? */ drive_gcr_data_writeback(drive); - if (drive->type == DRIVE_TYPE_1570 - || drive->type == DRIVE_TYPE_1571 - || drive->type == DRIVE_TYPE_1571CR) { + if (unit->type == DRIVE_TYPE_1570 + || unit->type == DRIVE_TYPE_1571 + || unit->type == DRIVE_TYPE_1571CR) { if (track > (DRIVE_HALFTRACKS_1571 / 2)) { track -= (DRIVE_HALFTRACKS_1571 / 2); side = 1; } } + /* TODO: drive 1 ? */ drive_set_half_track(track * 2, side, drive); - if (drive->type == DRIVE_TYPE_1540 - || drive->type == DRIVE_TYPE_1541 - || drive->type == DRIVE_TYPE_1541II - || drive->type == DRIVE_TYPE_1570 - || drive->type == DRIVE_TYPE_1571 - || drive->type == DRIVE_TYPE_1571CR) { - memcpy(&(drv->drive->drive_ram[0x0400]), buffer, 256); + if (unit->type == DRIVE_TYPE_1540 + || unit->type == DRIVE_TYPE_1541 + || unit->type == DRIVE_TYPE_1541II + || unit->type == DRIVE_TYPE_1570 + || unit->type == DRIVE_TYPE_1571 + || unit->type == DRIVE_TYPE_1571CR) { + memcpy(&(unit->drive_ram[0x0400]), buffer, 256); } } @@ -148,7 +161,7 @@ void drive_set_last_read(unsigned int track, unsigned int sector, BYTE *buffer, once before anything else). Return 0 on success, -1 on error. */ int drive_init(void) { - unsigned int dnr; + unsigned int unit; drive_t *drive; if (rom_loaded) { @@ -162,19 +175,30 @@ int drive_init(void) drive_log = log_open("Drive"); - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { + for (unit = 0; unit < NUM_DISK_UNITS; unit++) { + diskunit_context_t *diskunit = diskunit_context[unit]; char *logname; + unsigned int d; - drive = drive_context[dnr]->drive; - logname = lib_msprintf("Drive %i", dnr + 8); - drive->log = log_open(logname); + logname = lib_msprintf("Unit %u", unit + 8); + diskunit->log = log_open(logname); lib_free(logname); - drive_clk[dnr] = 0L; - drive->clk = &drive_clk[dnr]; - drive->mynumber = dnr; + diskunit_clk[unit] = 0L; + + for (d = 0; d < NUM_DRIVES; d++) { + drive = diskunit->drives[d]; + + drive->drive = d; + drive->diskunit = diskunit_context[unit]; + } + } + /* NOTE: this will not actually load the images yet, only check of the ROMs exist */ + driverom_load_images(); + /* Do not error out if _SOME_ images are not found, ie. FD2K/4K, CMDHD */ +#if 0 if (driverom_load_images() < 0) { resources_set_int("Drive8Type", DRIVE_TYPE_NONE); resources_set_int("Drive9Type", DRIVE_TYPE_NONE); @@ -182,80 +206,92 @@ int drive_init(void) resources_set_int("Drive11Type", DRIVE_TYPE_NONE); return -1; } +#endif - log_message(drive_log, "Finished loading ROM images."); - rom_loaded = 1; + rom_loaded = 1; /* mark drive ROMs being tested OK */ - drive_overflow_init(); + for (unit = 0; unit < NUM_DISK_UNITS; unit++) { + diskunit_context_t *diskunit = diskunit_context[unit]; + drive = diskunit->drives[0]; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + machine_drive_port_default(diskunit); - machine_drive_port_default(drive_context[dnr]); - - if (drive_check_type(drive->type, dnr) < 1) { - resources_set_int_sprintf("Drive%iType", DRIVE_TYPE_NONE, dnr + 8); + if (drive_check_type(diskunit->type, unit) < 1) { + resources_set_int_sprintf("Drive%uType", DRIVE_TYPE_NONE, unit + 8); } - machine_drive_rom_setup_image(dnr); + /* This will trigger loading the ROM if needed */ + machine_drive_rom_setup_image(unit); } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - drive->gcr = gcr_create_image(); - drive->p64 = lib_calloc(1, sizeof(TP64Image)); - P64ImageCreate(drive->p64); - drive->byte_ready_level = 1; - drive->byte_ready_edge = 1; - drive->GCR_dirty_track = 0; - drive->GCR_dirty_track_for_snapshot = 0; - drive->GCR_dirty_track_needs_refresh = 0; - drive->GCR_write_value = 0x55; - drive->GCR_track_start_ptr = NULL; - drive->GCR_current_track_size = 0; - drive->attach_clk = (CLOCK)0; - drive->detach_clk = (CLOCK)0; - drive->attach_detach_clk = (CLOCK)0; - drive->old_led_status = 0; - drive->old_half_track = 0; - drive->side = 0; - drive->GCR_image_loaded = 0; - drive->P64_image_loaded = 0; - drive->P64_dirty = 0; - drive->P64_dirty_for_snapshot = 0; - drive->read_only = 0; - drive->clock_frequency = 1; - drive->led_last_change_clk = *(drive->clk); - drive->led_last_uiupdate_clk = *(drive->clk); - drive->led_active_ticks = 0; - - rotation_reset(drive); - - /* Position the R/W head on the directory track. */ - drive_set_half_track(36, 0, drive); - drive_set_active_led_color(drive->type, dnr); + log_verbose(drive_log, "Finished loading ROM images."); + + for (unit = 0; unit < NUM_DISK_UNITS; unit++) { + diskunit_context_t *diskunit = diskunit_context[unit]; + int d; + + for (d = 0; d < NUM_DRIVES; d++) { + drive = diskunit->drives[d]; + + drive->gcr = gcr_create_image(); + drive->p64 = lib_calloc(1, sizeof(TP64Image)); + P64ImageCreate(drive->p64); + drive->byte_ready_level = 1; + drive->byte_ready_edge = 1; + drive->GCR_dirty_track = 0; + drive->GCR_dirty_track_for_snapshot = 0; + drive->GCR_dirty_track_needs_refresh = 0; + drive->GCR_write_value = 0x55; + drive->GCR_track_start_ptr = NULL; + drive->GCR_current_track_size = 0; + drive->attach_clk = (CLOCK)0; + drive->detach_clk = (CLOCK)0; + drive->attach_detach_clk = (CLOCK)0; + drive->old_led_status = 0; + drive->old_half_track = 0; + drive->side = 0; + drive->GCR_image_loaded = 0; + drive->P64_image_loaded = 0; + drive->P64_dirty = 0; + drive->P64_dirty_for_snapshot = 0; + drive->read_only = 0; + drive->led_last_change_clk = *(diskunit->clk_ptr); + drive->led_last_uiupdate_clk = *(diskunit->clk_ptr); + drive->led_active_ticks = 0; + drive->read_write_mode = 1; + + /* Position the R/W head on the directory track. */ + drive_set_half_track(36, 0, drive); + drive_set_active_led_color(diskunit->type, unit); + } } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - driverom_initialize_traps(drive); + for (unit = 0; unit < NUM_DISK_UNITS; unit++) { + diskunit_context_t *diskunit = diskunit_context[unit]; + drive = diskunit->drives[0]; - drivesync_clock_frequency(drive->type, drive); + driverom_initialize_traps(diskunit); - rotation_init((drive->clock_frequency == 2) ? 1 : 0, dnr); + /* Sets diskunit->clock_frequency */ + drivesync_clock_frequency(diskunit, diskunit->type); + + /* TODO: rotation code is not drive1 aware */ + rotation_init((diskunit->clock_frequency == 2) ? 1 : 0, unit); + rotation_reset(drive); - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_init(drive_context[dnr], drive->type); + if (diskunit->type == DRIVE_TYPE_2000 || diskunit->type == DRIVE_TYPE_4000 || + diskunit->type == DRIVE_TYPE_CMDHD) { + drivecpu65c02_init(diskunit, diskunit->type); } else { - drivecpu_init(drive_context[dnr], drive->type); + drivecpu_init(diskunit, diskunit->type); } /* Make sure the sync factor is acknowledged correctly. */ - drivesync_factor(drive_context[dnr]); + drivesync_factor(diskunit); /* Make sure the traps are moved as needed. */ - if (drive->enable) { - drive_enable(drive_context[dnr]); + if (diskunit->enable) { + drive_enable(diskunit); } } @@ -264,34 +300,53 @@ int drive_init(void) void drive_shutdown(void) { - unsigned int dnr; + unsigned int unr, dnr; if (!drive_init_was_called) { /* happens at the -help command line command*/ return; } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - if (drive_context[dnr]->drive->type == DRIVE_TYPE_2000 || drive_context[dnr]->drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_shutdown(drive_context[dnr]); + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + diskunit_context_t *unit = diskunit_context[unr]; + + if (unit->type == DRIVE_TYPE_2000 || unit->type == DRIVE_TYPE_4000 || + unit->type == DRIVE_TYPE_CMDHD) { + drivecpu65c02_shutdown(diskunit_context[unr]); } else { - drivecpu_shutdown(drive_context[dnr]); - } - if (drive_context[dnr]->drive->gcr) { - gcr_destroy_image(drive_context[dnr]->drive->gcr); + drivecpu_shutdown(diskunit_context[unr]); } - if (drive_context[dnr]->drive->p64) { - P64ImageDestroy(drive_context[dnr]->drive->p64); - lib_free(drive_context[dnr]->drive->p64); + + if (unit->ds1216) { + ds1216e_destroy(unit->ds1216, unit->rtc_save); + unit->ds1216 = NULL; } - if (drive_context[dnr]->drive->ds1216) { - ds1216e_destroy(drive_context[dnr]->drive->ds1216, drive_context[dnr]->drive->rtc_save); + + for (dnr = 0; dnr < NUM_DRIVES; dnr++) { + drive_t *drive = unit->drives[dnr]; + + if (drive->gcr) { + gcr_destroy_image(drive->gcr); + } + if (drive->p64) { + P64ImageDestroy(drive->p64); + lib_free(drive->p64); + drive->p64 = NULL; + } } } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - lib_free(drive_context[dnr]->drive); - lib_free(drive_context[dnr]); + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + diskunit_context_t *unit = diskunit_context[unr]; + + for (dnr = 0; dnr < NUM_DRIVES; dnr++) { + drive_t *drive = unit->drives[dnr]; + + lib_free(drive); + unit->drives[dnr] = NULL; + } + lib_free(unit); + diskunit_context[unr] = NULL; } } @@ -303,7 +358,6 @@ void drive_set_active_led_color(unsigned int type, unsigned int dnr) case DRIVE_TYPE_1551: /* green power, red drive, horizontal, round */ case DRIVE_TYPE_1570: /* green power, red drive, horizontal, round */ case DRIVE_TYPE_2031: /* green power, red drive, horizontal, round */ - case DRIVE_TYPE_1001: /* green power, red drive, horizontal, round */ drive_led_color[dnr] = DRIVE_LED1_RED; break; case DRIVE_TYPE_1571: /* red power, green drive, horizontal, line */ @@ -314,16 +368,36 @@ void drive_set_active_led_color(unsigned int type, unsigned int dnr) break; case DRIVE_TYPE_2000: /* red power, green activity, red error, horizontal, line */ case DRIVE_TYPE_4000: /* red power, green activity, red error, horizontal, line */ + case DRIVE_TYPE_CMDHD: /* red power, green activity, red error, horizontal, line */ + drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_RED; + break; + case DRIVE_TYPE_2040: /* red drive0, red error, red drive1, triangle, round */ + case DRIVE_TYPE_3040: /* red drive0, red error, red drive1, triangle, round */ + case DRIVE_TYPE_4040: /* red drive0, red error, red drive1, triangle, round */ + case DRIVE_TYPE_8050: /* green drive0, green power/red error, green drive1, very flat triangle, round */ + /* Some drives have red drive0/1 */ + case DRIVE_TYPE_1001: /* green power/red error, red drive, horizontal, round */ + /* drive_led_color[dnr] = DRIVE_LED1_RED | DRIVE_LED2_RED; + * We lie here and give the LEDs different colours. + * The GUI can show only 2 LEDs (one for each drive) instead + * of 3. It does take 2 values, but they are displayed + * (mixed) in the same place. I guess it's thinking of + * 2-colour LEDs. + * So if both are set to red, we can't distinguish between + * activity and error. Since it seems worse to make the + * error LED green, I chose to make the activity green. + * As soon as the GUI can show all 3 leds, we can make them + * the right colours. + */ drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_RED; break; - case DRIVE_TYPE_2040: /* red drive1, red power, red drive2, horizontal, round */ - case DRIVE_TYPE_3040: /* red drive1, red power, red drive2, horizontal, round */ - case DRIVE_TYPE_4040: /* red drive1, red power, red drive2, horizontal, round */ - case DRIVE_TYPE_8050: /* red drive1, green power, red drive2, horizontal, round */ + case DRIVE_TYPE_9000: /* red drive1, green power, red drive2, horizontal, round */ drive_led_color[dnr] = DRIVE_LED1_RED | DRIVE_LED2_RED; break; - case DRIVE_TYPE_8250: /* red green, green power,green, horizontal, round */ - drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_GREEN; /* only the LP version is RED */ + case DRIVE_TYPE_8250: /* red drive0, green power/red error, green drive1, horizontal, round */ + /* drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_GREEN; * only the LP version is RED */ + /* The same note as for 8050. */ + drive_led_color[dnr] = DRIVE_LED1_GREEN | DRIVE_LED2_RED; break; default: drive_led_color[dnr] = DRIVE_LED1_RED; @@ -331,11 +405,10 @@ void drive_set_active_led_color(unsigned int type, unsigned int dnr) } } -int drive_set_disk_drive_type(unsigned int type, struct drive_context_s *drv) +int drive_set_disk_drive_type(unsigned int type, struct diskunit_context_s *drv) { unsigned int dnr; - drive_t *drive; - drive_t *drive1; + drive_t *drive0, *drive1; dnr = drv->mynumber; @@ -343,36 +416,29 @@ int drive_set_disk_drive_type(unsigned int type, struct drive_context_s *drv) return -1; } - drive = drv->drive; - rotation_rotate_disk(drive); + drive0 = drv->drives[0]; + drive1 = drv->drives[1]; - drivesync_clock_frequency(type, drive); + /* TODO: drive 1? */ + rotation_rotate_disk(drive0); + drivesync_clock_frequency(drv, type); rotation_init(0, dnr); - drive->type = type; - if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) { + drv->type = type; + if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000 || + type == DRIVE_TYPE_CMDHD) { drivecpu65c02_setup_context(drv, 0); } else { drivecpu_setup_context(drv, 0); } - drive->side = 0; + drive0->side = 0; + drive1->side = 0; machine_drive_rom_setup_image(dnr); drivesync_factor(drv); drive_set_active_led_color(type, dnr); - /* set up (relatively) easy detection of dual drives */ - drive1 = drive_context[mk_drive1(dnr)]->drive; - drive->drive0 = NULL; - drive1->drive1 = NULL; - if (is_drive0(dnr) && drive_check_dual(type)) { - drive->drive1 = drive1; - drive1->drive0 = drive; - } else { - drive->drive1 = NULL; - drive1->drive0 = NULL; - } - - if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000) { + if (type == DRIVE_TYPE_2000 || type == DRIVE_TYPE_4000 || + type == DRIVE_TYPE_CMDHD) { drivecpu65c02_init(drv, type); } else { drivecpu_init(drv, type); @@ -383,45 +449,46 @@ int drive_set_disk_drive_type(unsigned int type, struct drive_context_s *drv) int drive_get_disk_drive_type(int dnr) { - if (dnr >= 0 && dnr < DRIVE_NUM) { - return drive_context[dnr]->drive->type; + if (dnr >= 0 && dnr < NUM_DISK_UNITS) { + return diskunit_context[dnr]->type; } return DRIVE_TYPE_NONE; } -void drive_enable_update_ui(drive_context_t *drv) +void drive_enable_update_ui(diskunit_context_t *drv) { int i; - unsigned int enabled_drives = 0; + unsigned int enabled_units = 0; - for (i = 0; i < DRIVE_NUM; i++) { + for (i = 0; i < NUM_DISK_UNITS; i++) { unsigned int the_drive; - drive_t *drive = drive_context[i]->drive; + diskunit_context_t *unit = diskunit_context[i]; + /* TODO: drive 1 */ + drive_t *drive = unit->drives[0]; the_drive = 1 << i; - if (drive->enable || (drive->drive0 && drive->drive0->enable)) { - enabled_drives |= the_drive; + if (unit->enable) { + enabled_units |= the_drive; drive->old_led_status = -1; drive->old_half_track = -1; drive->old_side = -1; } } - ui_enable_drive_status(enabled_drives, + ui_enable_drive_status(enabled_units, drive_led_color); } /* Activate full drive emulation. */ -int drive_enable(drive_context_t *drv) +int drive_enable(diskunit_context_t *drv) { int drive_true_emulation = 0; unsigned int dnr; - drive_t *drive; + unsigned int drive; dnr = drv->mynumber; - drive = drv->drive; /* This must come first, because this might be called before the drive initialization. */ @@ -429,26 +496,31 @@ int drive_enable(drive_context_t *drv) return -1; } - resources_get_int("DriveTrueEmulation", &drive_true_emulation); + DBG(("drive_enable unit: %d", 8 + drv->mynumber)); + resources_get_int_sprintf("Drive%uTrueEmulation", &drive_true_emulation, 8 + drv->mynumber); /* Always disable kernal traps. */ if (!drive_true_emulation) { return 0; } - if (drive->type == DRIVE_TYPE_NONE) { + if (drv->type == DRIVE_TYPE_NONE) { return 0; } /* Recalculate drive geometry. */ - if (drive->image != NULL) { - drive_image_attach(drive->image, dnr + 8); + for (drive = 0; drive < NUM_DRIVES; drive++) { + if (drv->drives[drive]->image != NULL) { + drive_image_attach(drv->drives[drive]->image, dnr, drive); + } } /* resync */ drv->cpu->stop_clk = *(drv->clk_ptr); - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { + if (drv->type == DRIVE_TYPE_2000 || + drv->type == DRIVE_TYPE_4000 || + drv->type == DRIVE_TYPE_CMDHD) { drivecpu65c02_wake_up(drv); } else { drivecpu_wake_up(drv); @@ -460,28 +532,30 @@ int drive_enable(drive_context_t *drv) } /* Disable full drive emulation. */ -void drive_disable(drive_context_t *drv) +void drive_disable(diskunit_context_t *drv) { int drive_true_emulation = 0; - drive_t *drive; - - drive = drv->drive; + unsigned int drive; /* This must come first, because this might be called before the true drive initialization. */ - drive->enable = 0; + drv->enable = 0; - resources_get_int("DriveTrueEmulation", &drive_true_emulation); + DBG(("drive_disable unit: %u", 8 + drv->mynumber)); + resources_get_int_sprintf("Drive%uTrueEmulation", &drive_true_emulation, 8 + drv->mynumber); if (rom_loaded) { - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { + if (drv->type == DRIVE_TYPE_2000 || drv->type == DRIVE_TYPE_4000 || + drv->type == DRIVE_TYPE_CMDHD) { drivecpu65c02_sleep(drv); } else { drivecpu_sleep(drv); } machine_drive_port_default(drv); - drive_gcr_data_writeback(drive); + for (drive = 0; drive < NUM_DRIVES; drive++) { + drive_gcr_data_writeback(drv->drives[drive]); + } } /* Make sure the UI is updated. */ @@ -490,76 +564,145 @@ void drive_disable(drive_context_t *drv) monitor_interface_t *drive_cpu_monitor_interface_get(unsigned int dnr) { - return drive_context[dnr]->cpu->monitor_interface; + return diskunit_context[dnr]->cpu->monitor_interface; } void drive_cpu_early_init_all(void) { unsigned int dnr; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - machine_drive_init(drive_context[dnr]); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + machine_drive_init(diskunit_context[dnr]); } } -void drive_cpu_prevent_clk_overflow_all(CLOCK sub) +/* reset one drive only */ +void drive_cpu_trigger_reset(unsigned int dnr) { - unsigned int dnr; + unsigned int d; + diskunit_context_t *unit = diskunit_context[dnr]; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive_t *drive = drive_context[dnr]->drive; - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_prevent_clk_overflow(drive_context[dnr], sub); - } else { - drivecpu_prevent_clk_overflow(drive_context[dnr], sub); - } + if (unit->type == DRIVE_TYPE_2000 || + unit->type == DRIVE_TYPE_4000 || + unit->type == DRIVE_TYPE_CMDHD) { + drivecpu65c02_reset(diskunit_context[dnr]); + } else { + drivecpu_reset(diskunit_context[dnr]); } -} -void drive_cpu_trigger_reset(unsigned int dnr) -{ - drive_t *drive = drive_context[dnr]->drive; - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_trigger_reset(dnr); - } else { - drivecpu_trigger_reset(dnr); + for (d = 0; d < NUM_DRIVES; d++) { + drive_t *drive = unit->drives[d]; + + drive->led_last_change_clk = *(unit->clk_ptr); + drive->led_last_uiupdate_clk = *(unit->clk_ptr); + drive->led_active_ticks = 0; } + + is_jammed[dnr] = false; } /* called by machine_specific_reset() */ +/* reset all drives */ void drive_reset(void) { unsigned int dnr; - drive_t *drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + drive_cpu_trigger_reset(dnr); + } +} - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; +/* NOTE: this function is very similar to machine_jam - in case the behavior + changes, change machine_jam too */ +unsigned int drive_jam(int mynumber, const char *format, ...) +{ + va_list ap; + ui_jam_action_t ret = JAM_NONE; + + /* always ignore subsequent JAMs. reset would clear the flag again, not + * setting it when going to the monitor would just repeatedly pop up the + * jam dialog (until reset) + */ + if (is_jammed[mynumber]) { + return JAM_NONE; + } - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { - drivecpu65c02_reset(drive_context[dnr]); - } else { - drivecpu_reset(drive_context[dnr]); + is_jammed[mynumber] = true; + + va_start(ap, format); + if (jam_reason[mynumber]) { + lib_free(jam_reason[mynumber]); + jam_reason[mynumber] = NULL; + } + jam_reason[mynumber] = lib_mvsprintf(format, ap); + va_end(ap); + + log_message(LOG_DEFAULT, "*** %s", jam_reason[mynumber]); + + vsync_suspend_speed_eval(); + sound_suspend(); + + /* FIXME: perhaps we want a seperate setting for drives? */ + resources_get_int("JAMAction", &jam_action); + + if (jam_action == MACHINE_JAM_ACTION_DIALOG) { + if (monitor_is_remote() || monitor_is_binary()) { + if (monitor_is_remote()) { + ret = monitor_network_ui_jam_dialog("%s", jam_reason[mynumber]); + } + + if (monitor_is_binary()) { + ret = monitor_binary_ui_jam_dialog("%s", jam_reason[mynumber]); + } + } else if (!console_mode) { + ret = ui_jam_dialog("%s", jam_reason[mynumber]); } + } else if (jam_action == MACHINE_JAM_ACTION_QUIT) { + archdep_vice_exit(EXIT_SUCCESS); + } else { + int actions[4] = { + -1, UI_JAM_MONITOR, UI_JAM_RESET_CPU, UI_JAM_POWER_CYCLE + }; + ret = actions[jam_action - 1]; + } - drive->led_last_change_clk = *(drive->clk); - drive->led_last_uiupdate_clk = *(drive->clk); - drive->led_active_ticks = 0; + switch (ret) { + case UI_JAM_RESET_CPU: + return JAM_RESET_CPU; + case UI_JAM_POWER_CYCLE: + return JAM_POWER_CYCLE; + case UI_JAM_MONITOR: + return JAM_MONITOR; + default: + break; } + return JAM_NONE; +} + +bool drive_is_jammed(int mynumber) +{ + return is_jammed[mynumber]; +} + +char *drive_jam_reason(int mynumber) +{ + return jam_reason[mynumber]; } /* Move the head to half track `num'. */ void drive_set_half_track(int num, int side, drive_t *dptr) { - int tmp; - if ((dptr->type == DRIVE_TYPE_1540 - || dptr->type == DRIVE_TYPE_1541 - || dptr->type == DRIVE_TYPE_1541II - || dptr->type == DRIVE_TYPE_1551 - || dptr->type == DRIVE_TYPE_1570 - || dptr->type == DRIVE_TYPE_2031) && (num > DRIVE_HALFTRACKS_1541)) { + unsigned int type = dptr->diskunit->type; + int tmp; + + if ((type == DRIVE_TYPE_1540 + || type == DRIVE_TYPE_1541 + || type == DRIVE_TYPE_1541II + || type == DRIVE_TYPE_1551 + || type == DRIVE_TYPE_1570 + || type == DRIVE_TYPE_2031) && (num > DRIVE_HALFTRACKS_1541)) { num = DRIVE_HALFTRACKS_1541; } - if ((dptr->type == DRIVE_TYPE_1571 || dptr->type == DRIVE_TYPE_1571CR) + if ((type == DRIVE_TYPE_1571 || type == DRIVE_TYPE_1571CR) && (num > DRIVE_HALFTRACKS_1571)) { num = DRIVE_HALFTRACKS_1571; } @@ -600,17 +743,19 @@ void drive_set_half_track(int num, int side, drive_t *dptr) for `step' are `+1', '+2' and `-1'. */ void drive_move_head(int step, drive_t *drive) { + if ((step < -1) || (step > 1)) { + log_warning(drive_log, "ambiguous step count (%d)", step); + } drive_gcr_data_writeback(drive); - drive_sound_head(drive->current_half_track, step, drive->mynumber); + drive_sound_head(drive->current_half_track, step, drive->diskunit->mynumber); drive_set_half_track(drive->current_half_track + step, drive->side, drive); } void drive_gcr_data_writeback(drive_t *drive) { // LOGD("drive_gcr_data_writeback, drive->image=%x", drive->image); - - int extend; - unsigned int half_track, track; + + unsigned int half_track, track, end_half_track; int tmp; if (drive->image == NULL) { @@ -632,47 +777,81 @@ void drive_gcr_data_writeback(drive_t *drive) LOGD("drive_gcr_data_writeback: DIRTY TRACK: current_half_track=%d half_track=%d", drive->current_half_track, half_track); - if ((drive->image->type == DISK_IMAGE_TYPE_G64) - || (drive->image->type == DISK_IMAGE_TYPE_G71)) { + /* always write track to GCR images, no need to extend the image */ + if ((drive->image->type == DISK_IMAGE_TYPE_G64) || + (drive->image->type == DISK_IMAGE_TYPE_G71)) { disk_image_write_half_track(drive->image, half_track, &drive->gcr->tracks[half_track - 2]); drive->GCR_dirty_track = 0; return; } - + /* writing beyond max tracks allowed in this image is not possible */ if (half_track > drive->image->max_half_tracks) { drive->GCR_dirty_track = 0; return; } + /* when trying beyond the image, check if we should extend the image */ + DBG(("check track: %u > drive->image->tracks: %u", track, drive->image->tracks)); if (track > drive->image->tracks) { + /* FIXME: doublesided images cant be extended with this logic, so + never do it */ + if ((drive->image->type == DISK_IMAGE_TYPE_D71) || +#ifdef HAVE_X64_IMAGE + (drive->image->type == DISK_IMAGE_TYPE_X64) || +#endif + (drive->image->type == DISK_IMAGE_TYPE_D81)) { + drive->ask_extend_disk_image = DRIVE_EXTEND_ASK; + drive->GCR_dirty_track = 0; + return; + } + /* depending on the selected extend policy, ask or never/always extend */ switch (drive->extend_image_policy) { case DRIVE_EXTEND_NEVER: - drive->ask_extend_disk_image = 1; + drive->ask_extend_disk_image = DRIVE_EXTEND_ASK; drive->GCR_dirty_track = 0; return; case DRIVE_EXTEND_ASK: - if (drive->ask_extend_disk_image == 1) { - extend = ui_extend_image_dialog(); - if (extend == 0) { + if (drive->ask_extend_disk_image == DRIVE_EXTEND_ASK) { + if (ui_extend_image_dialog() == 0) { drive->GCR_dirty_track = 0; - drive->ask_extend_disk_image = 0; + drive->ask_extend_disk_image = DRIVE_EXTEND_NEVER; return; } - drive->ask_extend_disk_image = 2; - } else if (drive->ask_extend_disk_image == 0) { + drive->ask_extend_disk_image = DRIVE_EXTEND_ACCESS; + } else if (drive->ask_extend_disk_image == DRIVE_EXTEND_NEVER) { drive->GCR_dirty_track = 0; return; } break; case DRIVE_EXTEND_ACCESS: - drive->ask_extend_disk_image = 1; + drive->ask_extend_disk_image = DRIVE_EXTEND_ASK; break; } + /* determine the desired new size of the image. usually we want either + 35, 40 or 42 tracks */ + if (drive->image->tracks <= 35) { + /* usually extend from 35 to 40 tracks */ + end_half_track = 2 + (40 * 2); + } else if (drive->image->tracks <= 40) { + /* next size is 42 tracks (usually the maximum) */ + end_half_track = 2 + (42 * 2); + } else { + /* beyond this, extend one track. this should never happen */ + end_half_track = half_track + 2; + } + /* write all tracks up to the end of the image */ + DBG(("extend track: %u drive->image->max_half_tracks: %u drive->image->tracks: %u", track, drive->image->max_half_tracks, drive->image->tracks)); + while (half_track < end_half_track) { + DBG(("write halftrack: %u end: %u track: %u", half_track, end_half_track, half_track / 2)); + disk_image_write_half_track(drive->image, half_track, &drive->gcr->tracks[half_track - 2]); + half_track += 2; + } + } else { + /* write (only) the requested track */ + DBG(("write track: %u drive->image->max_half_tracks: %u drive->image->tracks: %u", track, drive->image->max_half_tracks, drive->image->tracks)); + disk_image_write_half_track(drive->image, half_track, &drive->gcr->tracks[half_track - 2]); } - disk_image_write_half_track(drive->image, half_track, - &drive->gcr->tracks[half_track - 2]); - drive->GCR_dirty_track = 0; } @@ -681,20 +860,20 @@ void drive_gcr_data_writeback_all(void) // LOGD("drive_gcr_data_writeback_all"); drive_t *drive; - unsigned int i; - - for (i = 0; i < DRIVE_NUM; i++) { - if (drive_context[i] == NULL) - continue; - drive = drive_context[i]->drive; - if (drive == NULL) - continue; - drive_gcr_data_writeback(drive); - if (drive->P64_image_loaded && drive->image && drive->image->p64) { - if (drive->image->type == DISK_IMAGE_TYPE_P64) { - if (drive->P64_dirty) { - drive->P64_dirty = 0; - disk_image_write_p64_image(drive->image); + unsigned int i, j; + + for (i = 0; i < NUM_DISK_UNITS; i++) { + for (j = 0; j < 2; j++) { + drive = diskunit_context[i]->drives[j]; + if (drive) { + drive_gcr_data_writeback(drive); + if (drive->P64_image_loaded && drive->image && drive->image->p64) { + if (drive->image->type == DISK_IMAGE_TYPE_P64) { + if (drive->P64_dirty) { + drive->P64_dirty = 0; + disk_image_write_p64_image(drive->image); + } + } } } } @@ -703,55 +882,61 @@ void drive_gcr_data_writeback_all(void) /* ------------------------------------------------------------------------- */ -static void drive_led_update(drive_t *drive, drive_t *drive0) +static void drive_led_update(diskunit_context_t *unit, drive_t *drive, int base) { int my_led_status = 0; CLOCK led_period; - unsigned int led_pwm; + int led_pwm1; /* Actually update the LED status only if the `trap idle' idling method is being used, as the LED status could be incorrect otherwise. */ - if (drive0->idling_method != DRIVE_IDLE_SKIP_CYCLES) { + if (unit->idling_method != DRIVE_IDLE_SKIP_CYCLES) { my_led_status = drive->led_status; } /* Update remaining led clock ticks. */ if (drive->led_status & 1) { - drive->led_active_ticks += *(drive0->clk) + drive->led_active_ticks += *(unit->clk_ptr) - drive->led_last_change_clk; } - drive->led_last_change_clk = *(drive0->clk); + drive->led_last_change_clk = *(unit->clk_ptr); - led_period = *(drive0->clk) - drive->led_last_uiupdate_clk; - drive->led_last_uiupdate_clk = *(drive0->clk); + led_period = *(unit->clk_ptr) - drive->led_last_uiupdate_clk; + drive->led_last_uiupdate_clk = *(unit->clk_ptr); if (led_period == 0) { return; } if (drive->led_active_ticks > led_period) { - /* during startup it has been observer that led_pwm > 1000, + /* during startup it has been observed that led_pwm1 > 1000, which potentially breaks several UIs */ /* this also happens when the drive is reset from UI and the LED was on */ - led_pwm = 1000; + led_pwm1 = 1000; } else { - led_pwm = drive->led_active_ticks * 1000 / led_period; + led_pwm1 = (int)((drive->led_active_ticks * 1000) / led_period); + /* With the 1541's real LED, the human eye perceives brightness much earlier in the PWM + * duty cycle range; the blog post at + * https://blog.mbedded.ninja/programming/firmware/controlling-led-brightness-using-pwm/ + * describes this. so adjust our output intensity level to compensate, using a square + * root power function to produce higher RGB outputs at lower PWM duty cycle levels. */ + led_pwm1 = 1000 * sqrt((float) led_pwm1 / 1000.0); } - assert(led_pwm <= MAX_PWM); - if (led_pwm > MAX_PWM) { - led_pwm = MAX_PWM; + assert(led_pwm1 <= MAX_PWM); + if (led_pwm1 > MAX_PWM) { + led_pwm1 = MAX_PWM; } drive->led_active_ticks = 0; - if (led_pwm != drive->led_last_pwm + if (led_pwm1 != drive->led_last_pwm || my_led_status != drive->old_led_status) { - ui_display_drive_led(drive->mynumber, led_pwm, + ui_display_drive_led(drive->diskunit->mynumber, base, led_pwm1, (my_led_status & 2) ? 1000 : 0); - drive->led_last_pwm = led_pwm; + drive->led_last_pwm = led_pwm1; drive->old_led_status = my_led_status; } } @@ -766,26 +951,29 @@ void drive_update_ui_status(void) } /* Update the LEDs and the track indicators. */ - for (i = 0; i < DRIVE_NUM; i++) { - drive_t *drive = drive_context[i]->drive; - drive_t *drive0 = drive->drive0; - int dual = drive0 && drive0->enable; - - if (drive->enable || dual) { - if (!drive0) { - drive0 = drive; + for (i = 0; i < NUM_DISK_UNITS; i++) { + diskunit_context_t *unit = diskunit_context[i]; + drive_t *drive0 = unit->drives[0]; + drive_t *drive1 = unit->drives[1]; + + if (unit->enable) { + + drive_led_update(unit, drive0, 0); + if (drive0->current_half_track != drive0->old_half_track + || drive0->side != drive0->old_side) { + drive0->old_half_track = drive0->current_half_track; + drive0->old_side = drive0->side; + ui_display_drive_track(i, 0, drive0->current_half_track, drive0->side); } - - drive_led_update(drive, drive0); - - if (drive->current_half_track != drive->old_half_track - || drive->side != drive->old_side) { - drive->old_half_track = drive->current_half_track; - drive->old_side = drive->side; - dual = dual || drive->drive1; /* also include drive 0 */ - ui_display_drive_track(i, - dual ? 0 : 8, - drive->current_half_track + (drive->side * DRIVE_HALFTRACKS_1571)); + /* update LED and track of the second drive for dual drives */ + if (drive_check_dual(unit->type)) { + drive_led_update(unit, drive1, 1); + if (drive1->current_half_track != drive1->old_half_track + || drive1->side != drive1->old_side) { + drive1->old_half_track = drive1->current_half_track; + drive1->old_side = drive1->side; + ui_display_drive_track(i, 1, drive1->current_half_track, drive1->side); + } } } } @@ -793,27 +981,28 @@ void drive_update_ui_status(void) int drive_num_leds(unsigned int dnr) { - drive_t *drive = drive_context[dnr]->drive; + diskunit_context_t *unit = diskunit_context[dnr]; - switch (drive->type) { + switch (unit->type) { case DRIVE_TYPE_2040: case DRIVE_TYPE_3040: case DRIVE_TYPE_4040: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: + case DRIVE_TYPE_9000: case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: + case DRIVE_TYPE_CMDHD: return 2; default: return 1; } } -void drive_cpu_execute_one(drive_context_t *drv, CLOCK clk_value) +void drive_cpu_execute_one(diskunit_context_t *drv, CLOCK clk_value) { - drive_t *drive = drv->drive; - - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { + if (drv->type == DRIVE_TYPE_2000 || drv->type == DRIVE_TYPE_4000 || + drv->type == DRIVE_TYPE_CMDHD) { drivecpu65c02_execute(drv, clk_value); } else { drivecpu_execute(drv, clk_value); @@ -823,21 +1012,20 @@ void drive_cpu_execute_one(drive_context_t *drv, CLOCK clk_value) void drive_cpu_execute_all(CLOCK clk_value) { unsigned int dnr; - drive_t *drive; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - if (drive->enable) { - drive_cpu_execute_one(drive_context[dnr], clk_value); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + + if (unit->enable) { + drive_cpu_execute_one(unit, clk_value); } } } -void drive_cpu_set_overflow(drive_context_t *drv) +void drive_cpu_set_overflow(diskunit_context_t *drv) { - drive_t *drive = drv->drive; - - if (drive->type == DRIVE_TYPE_2000 || drive->type == DRIVE_TYPE_4000) { + if (drv->type == DRIVE_TYPE_2000 || drv->type == DRIVE_TYPE_4000 || + drv->type == DRIVE_TYPE_CMDHD) { /* nothing */ } else { drivecpu_set_overflow(drv); @@ -851,17 +1039,20 @@ void drive_vsync_hook(void) drive_update_ui_status(); - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive_t *drive = drive_context[dnr]->drive; - if (drive->enable) { - if (drive->idling_method != DRIVE_IDLE_SKIP_CYCLES) { - drive_cpu_execute_one(drive_context[dnr], maincpu_clk); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + drive_t *drive = unit->drives[0]; + + if (unit->enable) { + if (unit->idling_method != DRIVE_IDLE_SKIP_CYCLES) { + drive_cpu_execute_one(diskunit_context[dnr], maincpu_clk); } - if (drive->idling_method == DRIVE_IDLE_NO_IDLE) { + if (unit->idling_method == DRIVE_IDLE_NO_IDLE) { /* if drive is never idle, also rotate the disk. this prevents * huge peaks in cpu usage when the drive must catch up with * a longer period of time. */ + /* TODO: drive 1 */ rotation_rotate_disk(drive); } /* printf("drive_vsync_hook drv %d @clk:%d\n", dnr, maincpu_clk); */ @@ -871,12 +1062,22 @@ void drive_vsync_hook(void) /* ------------------------------------------------------------------------- */ -static void drive_setup_context_for_drive(drive_context_t *drv, - unsigned int dnr) +static void drive_setup_context_for_unit(diskunit_context_t *drv, + unsigned int unr) { - drv->mynumber = dnr; - drv->drive = lib_calloc(1, sizeof(drive_t)); - drv->clk_ptr = &drive_clk[dnr]; + unsigned int d; + + drv->mynumber = unr; + + for (d = 0; d < NUM_DRIVES; d++) { + drv->drives[d] = lib_calloc(1, sizeof(drive_t)); + /* TODO: init functions for allocated memory */ + drv->drives[d]->image = NULL; + drv->drives[d]->diskunit = drv; + drv->drives[d]->drive = d; + } + + drv->clk_ptr = &diskunit_clk[unr]; drivecpu_setup_context(drv, 1); /* no need for 65c02, only allocating common stuff */ @@ -885,59 +1086,79 @@ static void drive_setup_context_for_drive(drive_context_t *drv, void drive_setup_context(void) { - unsigned int dnr; + unsigned int unr; + + for (unr = 0; unr < NUM_DISK_UNITS; unr++) { + diskunit_context[unr] = lib_calloc(1, sizeof(diskunit_context_t)); + drive_setup_context_for_unit(diskunit_context[unr], unr); + } +} - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive_context[dnr] = lib_calloc(1, sizeof(drive_context_t)); - drive_setup_context_for_drive(drive_context[dnr], dnr); +int drive_has_buttons(unsigned int dnr) +{ + diskunit_context_t *unit = diskunit_context[dnr]; + if (unit->type == DRIVE_TYPE_2000 || unit->type == DRIVE_TYPE_4000) { + /* single swap */ + return DRIVE_BUTTON_SWAP_SINGLE; + } else if (unit->type == DRIVE_TYPE_CMDHD) { + /* write protect, swap 8, swap 9 */ + return DRIVE_BUTTON_WRITE_PROTECT | DRIVE_BUTTON_SWAP_8 | DRIVE_BUTTON_SWAP_9; } + return 0; +} + +void drive_cpu_trigger_reset_button(unsigned int dnr, unsigned int button) +{ + diskunit_context_t *unit = diskunit_context[dnr]; + unit->button = button; + drive_cpu_trigger_reset(dnr); } ////// /// c64 debugger -drive_context_t *c64d_get_drive_context(int driveId) +diskunit_context_t *c64d_get_drive_context(int driveId) { - return drive_context[driveId]; + return diskunit_context[driveId]; } int c64d_get_drive_current_halftrack(int driveId) { - drive_context_t *drv = drive_context[driveId]; - if (drv == NULL || drv->drive == NULL) + diskunit_context_t *drv = diskunit_context[driveId]; + if (drv == NULL || drv->drives[0] == NULL) return 0; - return drv->drive->current_half_track; + return drv->drives[0]->current_half_track; } disk_image_t *c64d_get_drive_disk_image(int driveId) { -// if (drive_context == NULL) // this is static, no need to check +// if (diskunit_context == NULL) // this is static, no need to check // return NULL; - drive_context_t *drv = drive_context[driveId]; - if (drv == NULL || drv->drive == NULL) + diskunit_context_t *drv = diskunit_context[driveId]; + if (drv == NULL || drv->drives[0] == NULL) return NULL; -// LOGD("c64d_get_drive_disk_image: attach_clk=%d", drv->drive->attach_clk); -// LOGD("c64d_get_drive_disk_image: detach_clk=%d", drv->drive->detach_clk); +// LOGD("c64d_get_drive_disk_image: attach_clk=%d", drv->drives[0]->attach_clk); +// LOGD("c64d_get_drive_disk_image: detach_clk=%d", drv->drives[0]->detach_clk); - disk_image_t *diskImage = drv->drive->image; -// LOGD("diskImage=%x di->gcr=%x gcr=%x", diskImage, diskImage ? diskImage->gcr : 0, drv->drive->gcr); + disk_image_t *diskImage = drv->drives[0]->image; +// LOGD("diskImage=%x di->gcr=%x gcr=%x", diskImage, diskImage ? diskImage->gcr : 0, drv->drives[0]->gcr); return diskImage; } unsigned int c64d_get_drive_is_disk_attached(int driveId) { - drive_context_t *drv = drive_context[driveId]; - if (drv == NULL || drv->drive == NULL) + diskunit_context_t *drv = diskunit_context[driveId]; + if (drv == NULL || drv->drives[0] == NULL) { LOGError("c64d_get_drive_is_disk_attached: no drive context"); return 0; } - if (drv->drive->GCR_image_loaded || drv->drive->P64_image_loaded) + if (drv->drives[0]->GCR_image_loaded || drv->drives[0]->P64_image_loaded) return 1; return 0; @@ -945,27 +1166,27 @@ unsigned int c64d_get_drive_is_disk_attached(int driveId) void c64d_set_drive_half_track(int driveId, int halfTrack) { - drive_context_t *drv = drive_context[driveId]; - drive_set_half_track(halfTrack, 0, drv->drive); + diskunit_context_t *drv = diskunit_context[driveId]; + drive_set_half_track(halfTrack, 0, drv->drives[0]); } void c64d_set_drive_disk_memory(int driveId, BYTE *id, unsigned int track, unsigned int sector) { - drive_context_t *drv = drive_context[driveId]; + diskunit_context_t *drv = diskunit_context[driveId]; drive_set_disk_memory(id, track, sector, drv); } gcr_t *c64d_get_drive_disk_gcr(int driveId) { -// if (drive_context == NULL) // this is static, no need to check +// if (diskunit_context == NULL) // this is static, no need to check // return NULL; - drive_context_t *drv = drive_context[driveId]; - if (drv == NULL || drv->drive == NULL) + diskunit_context_t *drv = diskunit_context[driveId]; + if (drv == NULL || drv->drives[0] == NULL) return NULL; - gcr_t *diskGCR = drv->drive->gcr; -// LOGD("gcr=%x", drv->drive->gcr); + gcr_t *diskGCR = drv->drives[0]->gcr; +// LOGD("gcr=%x", drv->drives[0]->gcr); return diskGCR; } @@ -985,7 +1206,7 @@ disk_image_t *c64d_read_disk_image(char *fileName) disk_image_media_create(diskImage); - disk_image_fsimage_name_set(diskImage, lib_stralloc(fileName)); + disk_image_fsimage_name_set(diskImage, lib_strdup(fileName)); if (disk_image_open(diskImage) < 0) { diff --git a/src/Emulators/vice/drive/drive.h b/src/Emulators/vice/drive/drive.h index 9859bf54..e0cc8dd6 100644 --- a/src/Emulators/vice/drive/drive.h +++ b/src/Emulators/vice/drive/drive.h @@ -29,15 +29,51 @@ #ifndef VICE_DRIVE_H #define VICE_DRIVE_H +/* #define DRIVE_EXPERIMENTAL_DEVICES */ + +#ifdef HAVE_EXPERIMENTAL_DEVICES +#define DRIVE_EXPERIMENTAL_DEVICES +#endif + #include "vicetypes.h" -#include "ds1216e.h" //rtc/ +#include "ds1216e.h" #include "p64.h" -#define DRIVE_NUM 4 +/** \brief Number of supported disk units + */ +#define NUM_DISK_UNITS 4 + +/** \brief Minimum drive unit number + */ +#define DRIVE_UNIT_MIN 8 + +/** \brief Maximum drive unit number + */ +#define DRIVE_UNIT_MAX (DRIVE_UNIT_MIN + NUM_DISK_UNITS - 1) + +/** \brief Default drive unit number + */ +#define DRIVE_UNIT_DEFAULT DRIVE_UNIT_MIN + +/** \brief Minimum drive number + */ +#define DRIVE_NUMBER_MIN 0 + +/** \brief Maximum drive number + */ +#define DRIVE_NUMBER_MAX 1 + +#define NUM_DRIVES 2 + +/** \brief Default drive number + */ +#define DRIVE_NUMBER_DEFAULT DRIVE_NUMBER_MIN + #define MAX_PWM 1000 #define DRIVE_ROM_SIZE 0x8000 -#define DRIVE_RAM_SIZE 0xc000 +/* Upped to 64K due to CMD HD */ +#define DRIVE_RAM_SIZE 0x10000 /* Extended disk image handling. */ #define DRIVE_EXTEND_NEVER 0 @@ -49,29 +85,73 @@ #define DRIVE_IDLE_SKIP_CYCLES 1 #define DRIVE_IDLE_TRAP_IDLE 2 -/* Drive type. */ -#define DRIVE_TYPE_NONE 0 -#define DRIVE_TYPE_ANY 9999 - -#define DRIVE_TYPE_1540 1540 -#define DRIVE_TYPE_1541 1541 -#define DRIVE_TYPE_1541II 1542 -#define DRIVE_TYPE_1551 1551 -#define DRIVE_TYPE_1570 1570 -#define DRIVE_TYPE_1571 1571 -#define DRIVE_TYPE_1571CR 1573 -#define DRIVE_TYPE_1581 1581 -#define DRIVE_TYPE_2000 2000 -#define DRIVE_TYPE_4000 4000 -#define DRIVE_TYPE_2031 2031 -#define DRIVE_TYPE_2040 2040 /* DOS 1 dual floppy drive, 170k/disk */ -#define DRIVE_TYPE_3040 3040 /* DOS 2.0 dual floppy drive, 170k/disk */ -#define DRIVE_TYPE_4040 4040 /* DOS 2.5 dual floppy drive, 170k/disk */ -#define DRIVE_TYPE_1001 1001 /* DOS 2.7 single floppy drive, 1M/disk */ -#define DRIVE_TYPE_8050 8050 /* DOS 2.7 dual floppy drive, 0.5M/disk */ -#define DRIVE_TYPE_8250 8250 /* DOS 2.7 dual floppy drive, 1M/disk */ - -#define DRIVE_TYPE_NUM 17 +/* Drive type ID's and names. When adding things here, please also update + * the `drive_type_info_list` array in src/drive/drive.c to keep UI's current + */ +#define DRIVE_TYPE_NONE 0 +#define DRIVE_NAME_NONE "None" + +#define DRIVE_TYPE_ANY 9999 +#define DRIVE_NAME_ANY "Any" + +#define DRIVE_TYPE_1540 1540 +#define DRIVE_NAME_1540 "CBM 1540" + +#define DRIVE_TYPE_1541 1541 +#define DRIVE_NAME_1541 "CBM 1541" + +#define DRIVE_TYPE_1541II 1542 +#define DRIVE_NAME_1541II "CBM 1541-II" + +#define DRIVE_TYPE_1551 1551 +#define DRIVE_NAME_1551 "CBM 1551" + +#define DRIVE_TYPE_1570 1570 +#define DRIVE_NAME_1570 "CBM 1570" + +#define DRIVE_TYPE_1571 1571 +#define DRIVE_NAME_1571 "CBM 1571" + +#define DRIVE_TYPE_1571CR 1573 +#define DRIVE_NAME_1571CR "CBM 1571 CR" + +#define DRIVE_TYPE_1581 1581 +#define DRIVE_NAME_1581 "CBM 1581" + +#define DRIVE_TYPE_2000 2000 +#define DRIVE_NAME_2000 "CMD FD-2000" + +#define DRIVE_TYPE_4000 4000 +#define DRIVE_NAME_4000 "CMD FD-4000" + +#define DRIVE_TYPE_2031 2031 +#define DRIVE_NAME_2031 "CBM 2031" + +#define DRIVE_TYPE_2040 2040 /* DOS 1 dual floppy drive, 170k/disk */ +#define DRIVE_NAME_2040 "CBM 2040" + +#define DRIVE_TYPE_3040 3040 /* DOS 2.0 dual floppy drive, 170k/disk */ +#define DRIVE_NAME_3040 "CBM 3040" + +#define DRIVE_TYPE_4040 4040 /* DOS 2.5 dual floppy drive, 170k/disk */ +#define DRIVE_NAME_4040 "CBM 4040" + +#define DRIVE_TYPE_1001 1001 /* DOS 2.7 single floppy drive, 1M/disk */ +#define DRIVE_NAME_1001 "CBM SFD-1001" + +#define DRIVE_TYPE_8050 8050 /* DOS 2.7 dual floppy drive, 0.5M/disk */ +#define DRIVE_NAME_8050 "CBM 8050" + +#define DRIVE_TYPE_8250 8250 /* DOS 2.7 dual floppy drive, 1M/disk */ +#define DRIVE_NAME_8250 "CBM 8250" + +#define DRIVE_TYPE_9000 9000 /* DOS 3.0 hard drive */ +#define DRIVE_NAME_9000 "CBM D9090/60" + +#define DRIVE_TYPE_CMDHD 4844 /* ASCII for HD */ +#define DRIVE_NAME_CMDHD "CMD HD" + +#define DRIVE_TYPE_NUM 19 /* max. half tracks */ #define DRIVE_HALFTRACKS_1541 84 @@ -84,6 +164,27 @@ #define DRIVE_LED2_RED 0 #define DRIVE_LED2_GREEN 2 +/* maximum number of LEDs per drive (not unit!) */ +#define DRIVE_LEDS_MAX 2 + +/* Drive button masks for drive_has_buttons() + * + * CMD devices 2000, 4000 and HD (200?) have buttons + */ + +/** \brief Drive has write protect button */ +#define DRIVE_BUTTON_WRITE_PROTECT 0x01 + +/** \brief Drive has SWAP 8 button */ +#define DRIVE_BUTTON_SWAP_8 0x02 + +/** \brief Drive has SWAP 9 button */ +#define DRIVE_BUTTON_SWAP_9 0x04 + +/** \brief Drive has single SWAP button */ +#define DRIVE_BUTTON_SWAP_SINGLE 0x08 + + /* Number of cycles before an attached disk becomes visible to the R/W head. This is mostly to make routines that auto-detect disk changes happy. */ #define DRIVE_ATTACH_DELAY (3 * 600000) @@ -100,54 +201,61 @@ #define DRIVE_PC_STANDARD 1 /* speed-dos userport cable */ #define DRIVE_PC_DD3 2 /* dolphin-dos 3 userport cable */ #define DRIVE_PC_FORMEL64 3 /* formel 64 cartridge */ +#define DRIVE_PC_21SEC_BACKUP 4 /* 21 second backup userport cable */ + +#define DRIVE_PC_NUM 5 + +#define DRIVE_RPM_ONE 100 /* 1 RPM */ +#define DRIVE_RPM_MAX 32000 /* 320 RPM */ +#define DRIVE_RPM_MIN 28000 /* 280 RPM */ +#define DRIVE_RPM_DEFAULT 30000 /* 300 RPM */ -#define DRIVE_PC_NUM 4 +#define DRIVE_WOBBLE_FREQ_ONE 1000 /* 1 Hz */ +#define DRIVE_WOBBLE_FREQ_MAX 50000 /* 50 Hz */ +#define DRIVE_WOBBLE_FREQ_DEFAULT 75 /* .075 Hz */ + +#define DRIVE_WOBBLE_AMPLITUDE_ONE 1000 /* +/- 1 RPM */ +#define DRIVE_WOBBLE_AMPLITUDE_MAX 5000 /* +/- 5 RPM */ +#define DRIVE_WOBBLE_AMPLITUDE_DEFAULT 200 /* +/- 0.2 RPM */ + +#define DRIVE_SOUND_VOLUME_ONE 4000 /* 100% */ +#define DRIVE_SOUND_VOLUME_MAX 4000 /* 100% */ +#define DRIVE_SOUND_VOLUME_DEFAULT 1000 /* 25% */ /* ------------------------------------------------------------------------- */ +typedef struct drive_type_info_s { + const char *name; + int id; +} drive_type_info_t; + + struct gcr_s; struct disk_image_s; typedef struct drive_s { - unsigned int mynumber; + unsigned int drive; /* DRIVE_NUMBER_MIN ... DRIVE_NUMBER_MAX */ - /* Pointer to the drive clock. */ - CLOCK *clk; + /* Pointer to the containing diskunit_context */ + struct diskunit_context_s *diskunit; int led_status; CLOCK led_last_change_clk; CLOCK led_last_uiupdate_clk; CLOCK led_active_ticks; - unsigned int led_last_pwm; + CLOCK led_last_pwm; /* Current half track on which the R/W head is positioned. */ int current_half_track; + /* last clock and new value for stepper position */ CLOCK stepper_last_change_clk; int stepper_new_position; - /* Is this drive enabled? */ - unsigned int enable; - - /* What drive type we have to emulate? */ - unsigned int type; - /* Disk side. */ unsigned int side; - /* What idling method? (See `DRIVE_IDLE_*') */ - int idling_method; - - /* FD2000/4000 RTC save? */ - int rtc_save; - - /* pointers for detecting dual drives and finding the other one */ - /* (only needed as long as we abuse the odd devices for drive 1:) */ - struct drive_s *drive0; - struct drive_s *drive1; - int trap, trapcont; - /* Byte ready line. */ unsigned int byte_ready_level; unsigned int byte_ready_edge; @@ -160,10 +268,10 @@ typedef struct drive_s { int GCR_dirty_track_needs_refresh; /* GCR value being written to the disk. */ - BYTE GCR_write_value; + uint8_t GCR_write_value; /* Pointer to the start of the GCR data of this track. */ - BYTE *GCR_track_start_ptr; + uint8_t *GCR_track_start_ptr; /* Size of the GCR data for the current track. */ unsigned int GCR_current_track_size; @@ -171,14 +279,14 @@ typedef struct drive_s { /* Offset of the R/W head on the current track (bytes). */ unsigned int GCR_head_offset; - /* Are we in read or write mode? */ + /* Are we in read or write mode? 0 is write, <>0 is read */ int read_write_mode; /* Activates the byte ready line. */ int byte_ready_active; - - /* Clock frequency of this drive in 1MHz units. */ - int clock_frequency; +#define BRA_BYTE_READY 0x02 /* chosen for the bit in the VIA2 PCR register */ +#define BRA_MOTOR_ON 0x04 /* chosen for the bit in the VIA2 PB register */ +#define BRA_LED 0x08 /* Tick when the disk image was attached. */ CLOCK attach_clk; @@ -191,31 +299,31 @@ typedef struct drive_s { CLOCK attach_detach_clk; /* Byte to read from r/w head. */ - BYTE GCR_read; + uint8_t GCR_read; /* Only used for snapshot */ unsigned long snap_accum; CLOCK snap_rotation_last_clk; int snap_last_read_data; - BYTE snap_last_write_data; + uint8_t snap_last_write_data; int snap_bit_counter; int snap_zero_count; int snap_seed; - DWORD snap_speed_zone; - DWORD snap_ue7_dcba; - DWORD snap_ue7_counter; - DWORD snap_uf4_counter; - DWORD snap_fr_randcount; - DWORD snap_filter_counter; - DWORD snap_filter_state; - DWORD snap_filter_last_state; - DWORD snap_write_flux; - DWORD snap_PulseHeadPosition; - DWORD snap_xorShift32; - DWORD snap_so_delay; - DWORD snap_cycle_index; - DWORD snap_ref_advance; - DWORD snap_req_ref_cycles; + uint32_t snap_speed_zone; + uint32_t snap_ue7_dcba; + uint32_t snap_ue7_counter; + uint32_t snap_uf4_counter; + uint32_t snap_fr_randcount; + uint32_t snap_filter_counter; + uint32_t snap_filter_state; + uint32_t snap_filter_last_state; + uint32_t snap_write_flux; + uint32_t snap_PulseHeadPosition; + uint32_t snap_xorShift32; + uint32_t snap_so_delay; + uint32_t snap_cycle_index; + CLOCK snap_ref_advance; + uint32_t snap_req_ref_cycles; /* IF: requested additional R cycles */ int req_ref_cycles; @@ -247,16 +355,10 @@ typedef struct drive_s { /* What extension policy? */ int extend_image_policy; - /* Flag: What parallel cable do we emulate? */ - int parallel_cable; - /* If the user does not want to extend the disk image and `ask mode' is selected this flag gets cleared. */ int ask_extend_disk_image; - /* Drive-specific logging goes here. */ - signed int log; - /* Pointer to the attached disk image. */ struct disk_image_s *image; @@ -265,95 +367,92 @@ typedef struct drive_s { PP64Image p64; - /* Which RAM expansion is enabled? */ - int drive_ram2_enabled, drive_ram4_enabled, drive_ram6_enabled, - drive_ram8_enabled, drive_rama_enabled; - - /* Is the Professional DOS extension enabled? */ - int profdos; - /* Is the Supercard+ extension enabled? */ - int supercard; - /* Is the StarDOS extension enabled? */ - int stardos; - - /* RTC context */ - rtc_ds1216e_t *ds1216; - - /* Current ROM image. */ - BYTE rom[DRIVE_ROM_SIZE]; - - /* Current trap ROM image. */ - BYTE trap_rom[DRIVE_ROM_SIZE]; - - /* Drive RAM */ - BYTE drive_ram[DRIVE_RAM_SIZE]; - /* rotations per minute (300rpm = 30000) */ int rpm; - int rpm_wobble; + + /* state of the wobble emulation */ + float wobble_sin_count; + int wobble_factor; /* calculated factor used in the rotation code */ + int wobble_frequency; /* from the resource */ + int wobble_amplitude; /* from the resource */ + int true_emulation; /* from the resource */ + } drive_t; -extern CLOCK drive_clk[DRIVE_NUM]; +extern CLOCK diskunit_clk[NUM_DISK_UNITS]; /* Drive context structure for low-level drive emulation. Full definition in drivetypes.h */ -struct drive_context_s; -extern struct drive_context_s *drive_context[DRIVE_NUM]; +#include "drivetypes.h" +extern struct diskunit_context_s *diskunit_context[NUM_DISK_UNITS]; extern int rom_loaded; -extern int drive_init(void); -extern int drive_enable(struct drive_context_s *drv); -extern void drive_disable(struct drive_context_s *drv); -extern void drive_move_head(int step, struct drive_s *drive); +int drive_init(void); +int drive_enable(struct diskunit_context_s *drv); +void drive_disable(struct diskunit_context_s *drv); +void drive_move_head(int step, struct drive_s *drive); + /* Don't use these pointers before the context is set up! */ -extern struct monitor_interface_s *drive_cpu_monitor_interface_get(unsigned int dnr); -extern void drive_cpu_early_init_all(void); -extern void drive_cpu_prevent_clk_overflow_all(CLOCK sub); -extern void drive_cpu_trigger_reset(unsigned int dnr); -extern void drive_reset(void); -extern void drive_shutdown(void); -extern void drive_cpu_execute_one(struct drive_context_s *drv, CLOCK clk_value); -extern void drive_cpu_execute_all(CLOCK clk_value); -extern void drive_cpu_set_overflow(struct drive_context_s *drv); -extern void drive_vsync_hook(void); -extern int drive_get_disk_drive_type(int dnr); -extern void drive_enable_update_ui(struct drive_context_s *drv); -extern void drive_update_ui_status(void); -extern void drive_gcr_data_writeback(struct drive_s *drive); -extern void drive_gcr_data_writeback_all(void); -extern void drive_set_active_led_color(unsigned int type, unsigned int dnr); -extern int drive_set_disk_drive_type(unsigned int drive_type, - struct drive_context_s *drv); - -extern void drive_set_half_track(int num, int side, drive_t *dptr); -extern void drive_set_machine_parameter(long cycles_per_sec); -extern void drive_set_disk_memory(BYTE *id, unsigned int track, - unsigned int sector, - struct drive_context_s *drv); -extern void drive_set_last_read(unsigned int track, unsigned int sector, - BYTE *buffer, struct drive_context_s *drv); - -extern int drive_check_type(unsigned int drive_type, unsigned int dnr); -extern int drive_check_extend_policy(int drive_type); -extern int drive_check_idle_method(int drive_type); -extern int drive_check_expansion(int drive_type); -extern int drive_check_expansion2000(int drive_type); -extern int drive_check_expansion4000(int drive_type); -extern int drive_check_expansion6000(int drive_type); -extern int drive_check_expansion8000(int drive_type); -extern int drive_check_expansionA000(int drive_type); -extern int drive_check_parallel_cable(int drive_type); -extern int drive_check_extend_policy(int drive_type); -extern int drive_check_profdos(int drive_type); -extern int drive_check_supercard(int drive_type); -extern int drive_check_stardos(int drive_type); - -extern int drive_num_leds(unsigned int dnr); - -extern void drive_setup_context(void); - -extern int drive_resources_type_init(unsigned int default_type); +struct monitor_interface_s *drive_cpu_monitor_interface_get(unsigned int dnr); + +void drive_cpu_early_init_all(void); +void drive_cpu_trigger_reset(unsigned int dnr); +void drive_reset(void); +void drive_shutdown(void); +void drive_cpu_execute_one(struct diskunit_context_s *drv, CLOCK clk_value); +void drive_cpu_execute_all(CLOCK clk_value); +void drive_cpu_set_overflow(struct diskunit_context_s *drv); +void drive_vsync_hook(void); +int drive_get_disk_drive_type(int dnr); +void drive_enable_update_ui(struct diskunit_context_s *drv); +void drive_update_ui_status(void); +void drive_gcr_data_writeback(struct drive_s *drive); +void drive_gcr_data_writeback_all(void); +void drive_set_active_led_color(unsigned int type, unsigned int dnr); +int drive_set_disk_drive_type(unsigned int drive_type, + struct diskunit_context_s *drv); + +void drive_set_half_track(int num, int side, drive_t *dptr); +void drive_set_machine_parameter(long cycles_per_sec); +void drive_set_disk_memory(uint8_t *id, unsigned int track, + unsigned int sector, + struct diskunit_context_s *drv); +void drive_set_last_read(unsigned int track, unsigned int sector, + uint8_t *buffer, struct diskunit_context_s *drv); + +int drive_check_type(unsigned int drive_type, unsigned int dnr); +int drive_check_extend_policy(int drive_type); +int drive_check_idle_method(int drive_type); +int drive_check_expansion(int drive_type); +int drive_check_expansion2000(int drive_type); +int drive_check_expansion4000(int drive_type); +int drive_check_expansion6000(int drive_type); +int drive_check_expansion8000(int drive_type); +int drive_check_expansionA000(int drive_type); +int drive_check_parallel_cable(int drive_type); +int drive_check_extend_policy(int drive_type); +int drive_check_dolphindos3(int drive_type); +int drive_check_profdos(int drive_type); +int drive_check_supercard(int drive_type); +int drive_check_stardos(int drive_type); +int drive_check_rtc(int drive_type); +int drive_check_iec(int drive_type); +int drive_num_leds(unsigned int dnr); + +int drive_get_type_by_devnr(int devnr); +int drive_is_dualdrive_by_devnr(int devnr); + +void drive_setup_context(void); + +int drive_resources_type_init(unsigned int default_type); + +int drive_has_buttons(unsigned int dnr); +void drive_cpu_trigger_reset_button(unsigned int dnr, unsigned int button); + +unsigned int drive_jam(int mynumber, const char *format, ...) VICE_ATTR_PRINTF2; +bool drive_is_jammed(int mynumber); +char *drive_jam_reason(int mynumber); #endif diff --git a/src/Emulators/vice/drive/drivecpu.c b/src/Emulators/vice/drive/drivecpu.c index 5e3df711..bc0087ff 100644 --- a/src/Emulators/vice/drive/drivecpu.c +++ b/src/Emulators/vice/drive/drivecpu.c @@ -35,7 +35,6 @@ #include "6510core.h" #include "alarm.h" -#include "clkguard.h" #include "debug.h" #include "drive.h" #include "drivecpu.h" @@ -47,12 +46,14 @@ #include "log.h" #include "machine-drive.h" #include "machine.h" +#include "mainlock.h" #include "mem.h" #include "monitor.h" #include "mos6510.h" #include "rotation.h" #include "snapshot.h" #include "vicetypes.h" +#include "uiapi.h" #include "via.h" #include "ViceWrapper.h" @@ -61,7 +62,7 @@ // // TODO: the c64 debugger has hardcoded drive context 0 only (drive 8, no multiple drives supported yet). -// look at lines such drive_context[0]->via1d1541->c64d_irq_flagged ... +// look at lines such diskunit_context[0]->via1d1541->c64d_irq_flagged ... int _c64d_new_drive_pc = -1; int _c64d_new_drive_dnr = -1; @@ -69,15 +70,15 @@ int _c64d_new_drive_dnr = -1; // /* Global clock counters. */ -CLOCK drive_clk[DRIVE_NUM]; +CLOCK diskunit_clk[NUM_DISK_UNITS]; -static void drive_jam(drive_context_t *drv); +static void drivecpu_jam(diskunit_context_t *drv); static void drivecpu_set_bank_base(void *context); -static interrupt_cpu_status_t *drivecpu_int_status_ptr[DRIVE_NUM]; +static interrupt_cpu_status_t *drivecpu_int_status_ptr[NUM_DISK_UNITS]; -void drivecpu_setup_context(struct drive_context_s *drv, int i) +void drivecpu_setup_context(struct diskunit_context_s *drv, int i) { monitor_interface_t *mi; drivecpu_context_t *cpu; @@ -101,8 +102,8 @@ void drivecpu_setup_context(struct drive_context_s *drv, int i) cpu->d_bank_start = 0; cpu->pageone = NULL; if (i) { - cpu->snap_module_name = lib_msprintf("DRIVECPU%d", drv->mynumber); - cpu->identification_string = lib_msprintf("DRIVE#%d", drv->mynumber + 8); + cpu->snap_module_name = lib_msprintf("DRIVECPU%u", drv->mynumber); + cpu->identification_string = lib_msprintf("DRIVE#%u", drv->mynumber + 8); cpu->monitor_interface = monitor_interface_new(); } mi = cpu->monitor_interface; @@ -114,44 +115,53 @@ void drivecpu_setup_context(struct drive_context_s *drv, int i) mi->z80_cpu_regs = NULL; mi->h6809_cpu_regs = NULL; mi->int_status = cpu->int_status; - mi->clk = &(drive_clk[drv->mynumber]); + mi->clk = &(diskunit_clk[drv->mynumber]); mi->current_bank = 0; mi->mem_bank_list = NULL; + mi->mem_bank_list_nos = NULL; mi->mem_bank_from_name = NULL; mi->get_line_cycle = NULL; + mi->mem_bank_read = drivemem_bank_read; mi->mem_bank_peek = drivemem_bank_peek; mi->mem_bank_write = drivemem_bank_store; + mi->mem_bank_poke = drivemem_bank_poke; + mi->mem_ioreg_list_get = drivemem_ioreg_list_get; mi->toggle_watchpoints_func = drivemem_toggle_watchpoints; mi->set_bank_base = drivecpu_set_bank_base; cpu->monspace = monitor_diskspace_mem(drv->mynumber); if (i) { - drv->cpu->clk_guard = clk_guard_new(drv->clk_ptr, CLOCK_MAX - CLKGUARD_SUB_MIN); - drv->cpu->alarm_context = alarm_context_new(drv->cpu->identification_string); } } /* ------------------------------------------------------------------------- */ -#define LOAD(a) (*drv->cpud->read_func_ptr[(a) >> 8])(drv, (WORD)(a)) -#define LOAD_ZERO(a) (*drv->cpud->read_func_ptr[0])(drv, (WORD)(a)) +#define LOAD(a) (*drv->cpud->read_func_ptr[(a) >> 8])(drv, (uint16_t)(a)) +#define LOAD_ZERO(a) (*drv->cpud->read_func_ptr[0])(drv, (uint16_t)(a)) #define LOAD_ADDR(a) (LOAD((a)) | (LOAD((a) + 1) << 8)) #define LOAD_ZERO_ADDR(a) (LOAD_ZERO((a)) | (LOAD_ZERO((a) + 1) << 8)) -#define STORE(a, b) (*drv->cpud->store_func_ptr[(a) >> 8])(drv, (WORD)(a), (BYTE)(b)) -#define STORE_ZERO(a, b) (*drv->cpud->store_func_ptr[0])(drv, (WORD)(a), (BYTE)(b)) +#define STORE(a, b) (*drv->cpud->store_func_ptr[(a) >> 8])(drv, (uint16_t)(a), (uint8_t)(b)) +#define STORE_ZERO(a, b) (*drv->cpud->store_func_ptr[0])(drv, (uint16_t)(a), (uint8_t)(b)) + +#define LOAD_DUMMY(a) (*drv->cpud->read_func_ptr_dummy[(a) >> 8])(drv, (uint16_t)(a)) +#define LOAD_ZERO_DUMMY(a) (*drv->cpud->read_func_ptr_dummy[0])(drv, (uint16_t)(a)) +#define LOAD_ADDR_DUMMY(a) (LOAD_DUMMY((a)) | (LOAD_DUMMY((a) + 1) << 8)) +#define LOAD_ZERO_ADDR_DUMMY(a) (LOAD_ZERO_DUMMY((a)) | (LOAD_ZERO_DUMMY((a) + 1) << 8)) +#define STORE_DUMMY(a, b) (*drv->cpud->store_func_ptr_dummy[(a) >> 8])(drv, (uint16_t)(a), (uint8_t)(b)) +#define STORE_ZERO_DUMMY(a, b) (*drv->cpud->store_func_ptr_dummy[0])(drv, (uint16_t)(a), (uint8_t)(b)) #define JUMP(addr) \ do { \ reg_pc = (unsigned int)(addr); \ if (reg_pc >= cpu->d_bank_limit || reg_pc < cpu->d_bank_start) { \ - BYTE *p = drv->cpud->read_base_tab_ptr[reg_pc >> 8]; \ + uint8_t *p = drv->cpud->read_base_tab_ptr[reg_pc >> 8]; \ cpu->d_bank_base = p; \ \ if (p != NULL) { \ - DWORD limits = drv->cpud->read_limit_tab_ptr[reg_pc >> 8]; \ + uint32_t limits = drv->cpud->read_limit_tab_ptr[reg_pc >> 8]; \ cpu->d_bank_limit = limits & 0xffff; \ cpu->d_bank_start = limits >> 16; \ } else { \ @@ -163,18 +173,20 @@ void drivecpu_setup_context(struct drive_context_s *drv, int i) /* ------------------------------------------------------------------------- */ -static void cpu_reset(drive_context_t *drv) +static void cpu_reset(diskunit_context_t *drv) { int preserve_monitor; preserve_monitor = drv->cpu->int_status->global_pending_int & IK_MONITOR; - log_message(drv->drive->log, "RESET."); + log_message(drv->log, "RESET."); + ui_display_reset(drv->mynumber + DRIVE_UNIT_MIN, 0); interrupt_cpu_status_reset(drv->cpu->int_status); *(drv->clk_ptr) = 6; - rotation_reset(drv->drive); + rotation_reset(drv->drives[0]); + rotation_reset(drv->drives[1]); machine_drive_reset(drv); if (preserve_monitor) { @@ -182,14 +194,15 @@ static void cpu_reset(drive_context_t *drv) } } -void drivecpu_reset_clk(drive_context_t *drv) +void drivecpu_reset_clk(diskunit_context_t *drv) { drv->cpu->last_clk = maincpu_clk; drv->cpu->last_exc_cycles = 0; drv->cpu->stop_clk = 0; } -void drivecpu_reset(drive_context_t *drv) +/* called by drive_reset() (via machine_specific_reset()) */ +void drivecpu_reset(diskunit_context_t *drv) { int preserve_monitor; @@ -208,18 +221,19 @@ void drivecpu_reset(drive_context_t *drv) interrupt_trigger_reset(drv->cpu->int_status, *(drv->clk_ptr)); } +/* called by drive_cpu_trigger_reset() */ void drivecpu_trigger_reset(unsigned int dnr) { - interrupt_trigger_reset(drivecpu_int_status_ptr[dnr], drive_clk[dnr] + 1); + interrupt_trigger_reset(drivecpu_int_status_ptr[dnr], diskunit_clk[dnr] + 1); } -void drivecpu_set_overflow(drive_context_t *drv) +void drivecpu_set_overflow(diskunit_context_t *drv) { drivecpu_context_t *cpu = drv->cpu; cpu->cpu_regs.p |= P_OVERFLOW; } -void drivecpu_shutdown(drive_context_t *drv) +void drivecpu_shutdown(diskunit_context_t *drv) { drivecpu_context_t *cpu; @@ -228,9 +242,6 @@ void drivecpu_shutdown(drive_context_t *drv) if (cpu->alarm_context != NULL) { alarm_context_destroy(cpu->alarm_context); } - if (cpu->clk_guard != NULL) { - clk_guard_destroy(cpu->clk_guard); - } monitor_interface_destroy(cpu->monitor_interface); interrupt_cpu_status_destroy(cpu->int_status); @@ -245,56 +256,35 @@ void drivecpu_shutdown(drive_context_t *drv) lib_free(cpu); } -void drivecpu_init(drive_context_t *drv, int type) +/* TODO: check type is already set, and remove type from parameters */ +void drivecpu_init(diskunit_context_t *drv, int type) { - drivemem_init(drv, type); + drivemem_init(drv); drivecpu_reset(drv); } -inline void drivecpu_wake_up(drive_context_t *drv) +inline void drivecpu_wake_up(diskunit_context_t *drv) { /* FIXME: this value could break some programs, or be way too high for others. Maybe we should put it into a user-definable resource. */ if (maincpu_clk - drv->cpu->last_clk > 0xffffff && *(drv->clk_ptr) > 934639) { - log_message(drv->drive->log, "Skipping cycles."); + log_message(drv->log, "Skipping cycles."); drv->cpu->last_clk = maincpu_clk; } } -inline void drivecpu_sleep(drive_context_t *drv) +inline void drivecpu_sleep(diskunit_context_t *drv) { /* Currently does nothing. But we might need this hook some day. */ } -/* Make sure the drive clock counters never overflow; return nonzero if - they have been decremented to prevent overflow. */ -CLOCK drivecpu_prevent_clk_overflow(drive_context_t *drv, CLOCK sub) -{ - if (sub != 0) { - /* First, get in sync with what the main CPU has done. Notice that - `clk' has already been decremented at this point. */ - if (drv->drive->enable) { - if (drv->cpu->last_clk < sub) { - /* Hm, this is kludgy. :-( */ - drive_cpu_execute_all(maincpu_clk + sub); - } - drv->cpu->last_clk -= sub; - } else { - drv->cpu->last_clk = maincpu_clk; - } - } - - /* Then, check our own clock counters. */ - return clk_guard_prevent_overflow(drv->cpu->clk_guard); -} - /* Handle a ROM trap. */ -inline static DWORD drive_trap_handler(drive_context_t *drv) +inline static uint32_t drive_trap_handler(diskunit_context_t *drv) { - if (MOS6510_REGS_GET_PC(&(drv->cpu->cpu_regs)) == (WORD)drv->drive->trap) { - MOS6510_REGS_SET_PC(&(drv->cpu->cpu_regs), drv->drive->trapcont); - if (drv->drive->idling_method == DRIVE_IDLE_TRAP_IDLE) { + if (MOS6510_REGS_GET_PC(&(drv->cpu->cpu_regs)) == (uint16_t)drv->trap) { + MOS6510_REGS_SET_PC(&(drv->cpu->cpu_regs), drv->trapcont); + if (drv->idling_method == DRIVE_IDLE_TRAP_IDLE) { CLOCK next_clk; next_clk = alarm_context_next_pending_clk(drv->cpu->alarm_context); @@ -307,7 +297,7 @@ inline static DWORD drive_trap_handler(drive_context_t *drv) } return 0; } - return (DWORD)-1; + return (uint32_t)-1; } static void drive_generic_dma(void) @@ -371,10 +361,6 @@ inline static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs, return 0; } -/* MPi: For some reason MSVC is generating a compiler fatal error when optimising this function? */ -#ifdef _MSC_VER -#pragma optimize("",off) -#endif /* -------------------------------------------------------------------------- */ /* Execute up to the current main CPU clock value. This automatically calculates the corresponding number of clock ticks in the drive. */ @@ -388,7 +374,7 @@ inline static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs, #define flag_z (cpu->cpu_regs.z) #define flag_n (cpu->cpu_regs.n) -void c64d_get_drivecpu_regs_internal(drive_context_t *drv, uint8 *a, uint8 *x, uint8 *y, uint8 *p, uint8 *sp, uint16 *pc) +void c64d_get_drivecpu_regs_internal(diskunit_context_t *drv, uint8 *a, uint8 *x, uint8 *y, uint8 *p, uint8 *sp, uint16 *pc) { drivecpu_context_t *cpu = drv->cpu; @@ -413,10 +399,10 @@ void c64d_get_drivecpu_regs_internal(drive_context_t *drv, uint8 *a, uint8 *x, u } -void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) +void drivecpu_execute(diskunit_context_t *drv, CLOCK clk_value) { CLOCK cycles; - int tcycles; + CLOCK tcycles; drivecpu_context_t *cpu; cpu = drv->cpu; @@ -439,11 +425,8 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) cpu->cycle_accum &= 0xffff; } - /* Run drive CPU emulation until the stop_clk clock has been reached. - * There appears to be a nasty 32-bit overflow problem here, so we - * paper over it by only considering subtractions of 2nd complement - * integers. */ - while ((int) (*(drv->clk_ptr) - cpu->stop_clk) < 0) { + /* Run drive CPU emulation until the stop_clk clock has been reached. */ + while (*drv->clk_ptr < cpu->stop_clk) { /* Include the 6502/6510 CPU emulation core. */ #define CLK (*(drv->clk_ptr)) @@ -457,7 +440,15 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) #define ALARM_CONTEXT (cpu->alarm_context) -#define JAM() drive_jam(drv) +#define ORIGIN_MEMSPACE (drv->mynumber + e_disk8_space) + +#define CPU_LOG_ID (drv->log) +/* #define ANE_LOG_LEVEL ane_log_level */ +/* #define LXA_LOG_LEVEL lxa_log_level */ + +#define CPU_IS_JAMMED cpu->is_jammed + +#define JAM() drivecpu_jam(drv) #define ROM_TRAP_ALLOWED() 1 @@ -471,15 +462,15 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) #define drivecpu_byte_ready_egde_clear() \ do { \ - drv->drive->byte_ready_edge = 0; \ + drv->drives[0]->byte_ready_edge = 0; \ } while (0) #define drivecpu_rotate() \ do { \ - rotation_rotate_disk(drv->drive); \ + rotation_rotate_disk(drv->drives[0]); \ } while (0) -#define drivecpu_byte_ready() (drv->drive->byte_ready_edge) +#define drivecpu_byte_ready() (drv->drives[0]->byte_ready_edge) #define cpu_reset() (cpu_reset)(drv) #define bank_limit (cpu->d_bank_limit) @@ -494,49 +485,68 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) /// /// /// 6510core.c starts here - - /* - * 6510core.c - MOS6510 emulation core. - * - * Written by - * Ettore Perazzoli - * Andreas Boose - * - * DTV sections written by - * M.Kiesel - * Hannu Nuotio - * - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - - /* This file is included by CPU definition files */ - /* (maincpu.c, drivecpu.c, ...) */ - +/* + * 6510core.c - MOS6510 emulation core. + * + * Written by + * Ettore Perazzoli + * Andreas Boose + * + * DTV sections written by + * M.Kiesel + * Hannu Nuotio + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* This file is included by CPU definition files */ +/* c64dtvcpu.c -> maincpu.c + c64cpu.c -> maincpu.c + c128cpu.c -> maincpu.c + cbm2cpu.c -> maincpu.c + petcpu.c -> maincpu.c + plus4cpu.c -> maincpu.c + drivecpu.c +*/ + #ifdef DRIVE_CPU #define CPU_STR "Drive CPU" #else #define CPU_STR "Main CPU" #endif - + +#ifndef CPU_LOG_ID +#define CPU_LOG_ID LOG_DEFAULT +#ifdef _MSC_VER +#pragma message ("Warning: CPU_LOG_ID not defined, using LOG_DEFAULT by default") +#else +#warning "CPU_LOG_ID not defined, using LOG_DEFAULT by default" +#endif +#endif + #include "traps.h" - + +#ifndef DRIVE_CPU +#include "profiler.h" +#endif + #ifndef C64DTV /* The C64DTV can use different shadow registers for accu read/write. */ /* For standard 6510, this is not the case. */ @@ -554,15 +564,15 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) #define CLK_ABS_I_STORE2 2 #define CLK_STACK_PUSH 1 #define CLK_STACK_PULL 2 -#define CLK_ABS_RMW2 3 -#define CLK_ABS_I_RMW2 3 #define CLK_ZERO_I_STORE 2 #define CLK_ZERO_I2 2 -#define CLK_ZERO_RMW 3 -#define CLK_ZERO_I_RMW 4 -#define CLK_IND_X_RMW 3 -#define CLK_IND_Y_RMW1 1 -#define CLK_IND_Y_RMW2 3 +/* #define CLK_ABS_RMW2 3 */ +/* #define CLK_ABS_I_RMW2 3 */ +/* #define CLK_ZERO_RMW 3 */ +/* #define CLK_ZERO_I_RMW 4 */ +/* #define CLK_IND_X_RMW 3 */ +/* #define CLK_IND_Y_RMW1 1 */ +/* #define CLK_IND_Y_RMW2 3 */ #define CLK_BRANCH2 1 #define CLK_INT_CYCLE 1 #define CLK_JSR_INT_CYCLE 1 @@ -571,7 +581,7 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) #define IRQ_CYCLES 7 #define NMI_CYCLES 7 -#endif +#endif /* !C64DTV */ #define RESET_CYCLES 6 /* ------------------------------------------------------------------------- */ @@ -588,11 +598,15 @@ void drivecpu_execute(drive_context_t *drv, CLOCK clk_value) /* Backup for non-variable cycle CPUs. */ #ifndef CLK_ADD -#define CLK_ADD(clock, amount) clock += (amount) +#define CLK_ADD(clock, amount) ((clock) += (amount)) +#endif + +#ifndef CLK_ADD_DUMMY +#define CLK_ADD_DUMMY(clock, amount) CLK_ADD(clock, amount) #endif #ifndef REWIND_FETCH_OPCODE -#define REWIND_FETCH_OPCODE(clock) clock -= 2 +#define REWIND_FETCH_OPCODE(clock) ((clock) -= 2) #endif /* ------------------------------------------------------------------------- */ @@ -827,15 +841,54 @@ JUMP(GLOBAL_REGS.pc); \ #define IMPORT_REGISTERS() #define EXPORT_REGISTERS() #endif /* !DRIVE_CPU */ - - /* Stack operations. */ - + +/* Stack operations. */ + +/* CAUTION: use STORE/LOAD macros instead of directly accessing the memory, + else checkpoints may not trigger */ +#if 0 #ifndef PUSH -#define PUSH(val) ((PAGE_ONE)[(reg_sp--)] = ((BYTE)(val))) +#define PUSH(val) ((PAGE_ONE)[(reg_sp--)] = ((uint8_t)(val))) #endif #ifndef PULL #define PULL() ((PAGE_ONE)[(++reg_sp)]) #endif +#else +#ifndef PUSH +#define PUSH(val) { STORE(0x100 + reg_sp, (val)); reg_sp--; } +#endif +#ifndef PULL +#define PULL() (++reg_sp, LOAD(0x100 + reg_sp)) +#endif +#endif + +#if !defined(DRIVE_CPU) +#define CHECK_PROFILE_INTERRUPT(dest_addr, handler) \ +do { \ + profile_int(dest_addr, handler, reg_sp + 1, CLK - profiling_clock_start); \ +} while (0) + +#define CHECK_PROFILE_JSR(dest_addr) \ + do { \ + profile_jsr(dest_addr, reg_pc, reg_sp); \ +} while (0) + +#define CHECK_PROFILE_RTS() \ + do { \ + profile_rtx(reg_sp); \ + } while (0) + +#define CHECK_PROFILE_RTI() \ + do { \ + profile_rtx(reg_sp + 1); \ + } while (0) + +#else +#define CHECK_PROFILE_INTERRUPT(dest_addr, handler) +#define CHECK_PROFILE_JSR(dest_addr) +#define CHECK_PROFILE_RTS() +#define CHECK_PROFILE_RTI() +#endif /* Drive CPU stack annotation: after PUSH, reg_sp has been decremented */ #define C64D_DRIVE_ANNOTATE_PUSH(entry_type, irq_source, origin) \ @@ -878,237 +931,334 @@ debug_text("*** BRK"); \ execute NMI. NMI can take over an in progress IRQ. */ /* FIXME: LOCAL_STATUS() should check byte ready first. */ #define DO_INTERRUPT(int_kind) \ -do { \ -BYTE ik = (int_kind); \ -\ -if (ik & (IK_IRQ | IK_IRQPEND | IK_NMI)) { \ -if (((ik & IK_NMI) \ -&& interrupt_check_nmi_delay(CPU_INT_STATUS, CLK)) \ -|| ((ik & (IK_IRQ | IK_IRQPEND)) && (!LOCAL_INTERRUPT() \ -|| OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ -&& interrupt_check_irq_delay(CPU_INT_STATUS, CLK))) { \ -if (monitor_mask[CALLER] & (MI_STEP)) { \ -monitor_check_icount_interrupt(); \ -} \ -if (NMI_CYCLES == 7) { \ -FETCH_PARAM(reg_pc); /* dummy reads */ \ -CLK_ADD(CLK, 1); \ -FETCH_PARAM(reg_pc); \ -CLK_ADD(CLK, 1); \ -} \ -LOCAL_SET_BREAK(0); \ -/* Detect IRQ source for annotation */ \ -c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ -if (drive_context[0]->via1d1541->c64d_irq_flagged) \ - c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_VIA1; \ -else if (drive_context[0]->via2->c64d_irq_flagged) \ - c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_VIA2; \ -else if (ik & (IK_IRQ | IK_IRQPEND)) \ - c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_IEC; \ -PUSH(reg_pc >> 8); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_PCH, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -PUSH(reg_pc & 0xff); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_PCL, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -CLK_ADD(CLK, 2); \ -PUSH(LOCAL_STATUS()); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_STATUS, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ -CLK_ADD(CLK, 1); \ -LOCAL_SET_INTERRUPT(1); \ -CPU_DELAY_CLK; /* process alarms for cartridge freeze */ \ -PROCESS_ALARMS; \ -if ((CPU_INT_STATUS->global_pending_int & IK_NMI) \ -&& (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ -/* Re-annotate as NMI */ \ -if (c64d_drive_cpu_stack_entry_types) { \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ -} \ -TRACE_NMI(CLK - NMI_CYCLES + 2); \ -interrupt_ack_nmi(CPU_INT_STATUS); \ -JUMP(LOAD_ADDR(0xfffa)); \ -} else { \ -TRACE_IRQ(CLK - IRQ_CYCLES + 2); \ -interrupt_ack_irq(CPU_INT_STATUS); \ -JUMP(LOAD_ADDR(0xfffe)); \ -} \ -SET_LAST_OPCODE(0); \ -CLK_ADD(CLK, 2); \ -} \ -} \ -if (ik & (IK_TRAP | IK_RESET)) { \ -if (ik & IK_TRAP) { \ -EXPORT_REGISTERS(); \ -interrupt_do_trap(CPU_INT_STATUS, (WORD)reg_pc); \ -IMPORT_REGISTERS(); \ -if (CPU_INT_STATUS->global_pending_int & IK_RESET) { \ -ik |= IK_RESET; \ -} \ -} \ -if (ik & IK_RESET) { \ -interrupt_ack_reset(CPU_INT_STATUS); \ -cpu_reset(); \ -bank_start = bank_limit = 0; /* prevent caching */ \ -JUMP(LOAD_ADDR(0xfffc)); \ -DMA_ON_RESET; \ -} \ -} \ -if (ik & (IK_MONITOR | IK_DMA)) { \ -if (ik & IK_MONITOR) { \ -if (monitor_force_import(CALLER)) { \ -IMPORT_REGISTERS(); \ -} \ -if (monitor_mask[CALLER]) { \ -EXPORT_REGISTERS(); \ -} \ -if (monitor_mask[CALLER] & (MI_STEP)) { \ -monitor_check_icount((WORD)reg_pc); \ -IMPORT_REGISTERS(); \ -} \ -if (monitor_mask[CALLER] & (MI_BREAK)) { \ -if (monitor_check_breakpoints(CALLER, (WORD)reg_pc)) { \ -monitor_startup(CALLER); \ -IMPORT_REGISTERS(); \ -} \ -} \ -if (monitor_mask[CALLER] & (MI_WATCH)) { \ -monitor_check_watchpoints(LAST_OPCODE_ADDR, (WORD)reg_pc); \ -IMPORT_REGISTERS(); \ -} \ -} \ -if (ik & IK_DMA) { \ -EXPORT_REGISTERS(); \ -DMA_FUNC; \ -interrupt_ack_dma(CPU_INT_STATUS); \ -IMPORT_REGISTERS(); \ -} \ -} \ -} while (0) - - /* ------------------------------------------------------------------------- */ - - /* Addressing modes. For convenience, page boundary crossing cycles and - ``idle'' memory reads are handled here as well. */ - + do { \ + uint8_t ik = (int_kind); \ + uint16_t addr, handler_vector; \ + \ + if (ik & (IK_IRQ | IK_IRQPEND | IK_NMI)) { \ + if (((ik & IK_NMI) \ + && interrupt_check_nmi_delay(CPU_INT_STATUS, CLK)) \ + || ((ik & (IK_IRQ | IK_IRQPEND)) && (!LOCAL_INTERRUPT() \ + || OPINFO_DISABLES_IRQ(LAST_OPCODE_INFO)) \ + && interrupt_check_irq_delay(CPU_INT_STATUS, CLK))) { \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + if (NMI_CYCLES == 7) { \ + FETCH_PARAM_DUMMY(reg_pc); /* dummy reads */ \ + CLK_ADD(CLK, 1); \ + FETCH_PARAM_DUMMY(reg_pc); \ + CLK_ADD(CLK, 1); \ + } \ + LOCAL_SET_BREAK(0); \ + /* c64d: detect drive IRQ source for stack annotation */ \ + c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_UNKNOWN; \ + if (diskunit_context[0]->via1d1541->c64d_irq_flagged) \ + c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_VIA1; \ + else if (diskunit_context[0]->via2->c64d_irq_flagged) \ + c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_VIA2; \ + else if (ik & (IK_IRQ | IK_IRQPEND)) \ + c64d_drive_irqbrk_irq_source = C64D_IRQ_SOURCE_IEC; \ + PUSH(reg_pc >> 8); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_PCH, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + PUSH(reg_pc & 0xff); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_PCL, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + CLK_ADD(CLK, 2); \ + PUSH(LOCAL_STATUS()); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_IRQ_STATUS, c64d_drive_irqbrk_irq_source, LAST_OPCODE_ADDR); \ + CLK_ADD(CLK, 1); \ + LOCAL_SET_INTERRUPT(1); \ + CPU_DELAY_CLK; /* process alarms for cartridge freeze */ \ + PROCESS_ALARMS; \ + if ((CPU_INT_STATUS->global_pending_int & IK_NMI) \ + && (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ + /* c64d: re-annotate stack entries as NMI */ \ + if (c64d_drive_cpu_stack_entry_types) { \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ + } \ + TRACE_NMI(CLK - NMI_CYCLES + 2); \ + interrupt_ack_nmi(CPU_INT_STATUS); \ + handler_vector = 0xfffa; \ + } else { \ + TRACE_IRQ(CLK - IRQ_CYCLES + 2); \ + interrupt_ack_irq(CPU_INT_STATUS); \ + handler_vector = 0xfffe; \ + } \ + addr = LOAD_ADDR(handler_vector); \ + CHECK_PROFILE_INTERRUPT(addr, handler_vector); \ + JUMP(addr); \ + SET_LAST_OPCODE(0); \ + CLK_ADD(CLK, 2); \ + } \ + } \ + if (ik & (IK_TRAP | IK_RESET)) { \ + if (ik & IK_TRAP) { \ + EXPORT_REGISTERS(); \ + interrupt_do_trap(CPU_INT_STATUS, (uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + if (CPU_INT_STATUS->global_pending_int & IK_RESET) { \ + ik |= IK_RESET; \ + } \ + } \ + if (ik & IK_RESET) { \ + cpu_reset(); \ + interrupt_ack_reset(CPU_INT_STATUS); \ + bank_start = bank_limit = 0; /* prevent caching */ \ + LOCAL_SET_INTERRUPT(1); \ + CPU_IS_JAMMED = 0; \ + DMA_ON_RESET; \ + addr = LOAD_ADDR(0xfffc); \ + CHECK_PROFILE_INTERRUPT(addr, 0xfffc); \ + JUMP(addr); \ + } \ + } \ + if (ik & (IK_MONITOR | IK_DMA)) { \ + if (ik & IK_MONITOR) { \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + EXPORT_REGISTERS(); \ + monitor_check_icount((uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_BREAK)) { \ + EXPORT_REGISTERS(); \ + if (monitor_check_breakpoints(CALLER, (uint16_t)reg_pc)) { \ + monitor_startup(CALLER); \ + } \ + IMPORT_REGISTERS(); \ + } \ + if (monitor_mask[CALLER] & (MI_WATCH)) { \ + EXPORT_REGISTERS(); \ + monitor_check_watchpoints(LAST_OPCODE_ADDR, (uint16_t)reg_pc); \ + IMPORT_REGISTERS(); \ + } \ + } \ + if (ik & IK_DMA) { \ + EXPORT_REGISTERS(); \ + DMA_FUNC; \ + interrupt_ack_dma(CPU_INT_STATUS); \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + +/* ------------------------------------------------------------------------- */ + +/* FIXME: we need to check if this shortcut will not make checkpoints not + trigger in certain cases. */ +#if 0 #define FETCH_PARAM(addr) ((((int)(addr)) < bank_limit) ? bank_base[(addr)] : LOAD(addr)) - +#define FETCH_PARAM_DUMMY(addr) ((((int)(addr)) < bank_limit) ? bank_base[(addr)] : LOAD_DUMMY(addr)) +#else +#define FETCH_PARAM(addr) (LOAD(addr)) +#define FETCH_PARAM_DUMMY(addr) (LOAD_DUMMY(addr)) +#endif + +/* Addressing modes. For convenience, page boundary crossing cycles and + ``idle'' memory reads are handled here as well. */ + #define LOAD_ABS(addr) LOAD(addr) - -#define LOAD_ABS_X(addr) \ -((((addr) & 0xff) + reg_x_read) > 0xff \ -? (LOAD(((addr) & 0xff00) | (((addr) + reg_x_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD((addr) + reg_x_read)) \ -: LOAD((addr) + reg_x_read)) - -#define LOAD_ABS_X_RMW(addr) \ -(LOAD(((addr) & 0xff00) | (((addr) + reg_x_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD((addr) + reg_x_read)) - -#define LOAD_ABS_Y(addr) \ -((((addr) & 0xff) + reg_y_read) > 0xff \ -? (LOAD(((addr) & 0xff00) | (((addr) + reg_y_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD((addr) + reg_y_read)) \ -: LOAD((addr) + reg_y_read)) - -#define LOAD_ABS_Y_RMW(addr) \ -(LOAD(((addr) & 0xff00) | (((addr) + reg_y_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD((addr) + reg_y_read)) - + +#define LOAD_ABS_X(addr) \ + ((((addr) & 0xff) + reg_x_read) > 0xff \ + ? (LOAD_DUMMY(((addr) & 0xff00) | (((addr) + reg_x_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD((addr) + reg_x_read)) \ + : LOAD((addr) + reg_x_read)) + +#define NOOP_LOAD_ABS_X(addr) \ + ((((addr) & 0xff) + reg_x_read) > 0xff \ + ? (LOAD_DUMMY(((addr) & 0xff00) | (((addr) + reg_x_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD_DUMMY((addr) + reg_x_read)) \ + : LOAD_DUMMY((addr) + reg_x_read)) + +#define LOAD_ABS_X_RMW(addr) \ + (LOAD_DUMMY(((addr) & 0xff00) | (((addr) + reg_x_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD((addr) + reg_x_read)) + +#define LOAD_ABS_Y(addr) \ + ((((addr) & 0xff) + reg_y_read) > 0xff \ + ? (LOAD_DUMMY(((addr) & 0xff00) | (((addr) + reg_y_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD((addr) + reg_y_read)) \ + : LOAD((addr) + reg_y_read)) + +#define LOAD_ABS_Y_RMW(addr) \ + (LOAD_DUMMY(((addr) & 0xff00) | (((addr) + reg_y_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD((addr) + reg_y_read)) + +#if 0 #define LOAD_IND_X(addr) (CLK_ADD(CLK, 3), LOAD(LOAD_ZERO_ADDR((addr) + reg_x_read))) - +#else +#define LOAD_IND_X(addr) \ + (CLK_ADD(CLK, 3), \ + LOAD_ZERO_DUMMY(addr), \ + tmpa = LOAD_ZERO((addr + reg_x_read) & 0xff), \ + tmpa |= (LOAD_ZERO(((addr + reg_x_read) + 1) & 0xff) << 8), \ + LOAD(tmpa)) + +#endif + +#if 0 #define LOAD_IND_Y(addr) \ -(CLK_ADD(CLK, 2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y_read) > 0xff \ -? (LOAD((LOAD_ZERO_ADDR((addr)) & 0xff00) \ -| ((LOAD_ZERO_ADDR((addr)) + reg_y_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD(LOAD_ZERO_ADDR((addr)) + reg_y_read)) \ -: LOAD(LOAD_ZERO_ADDR((addr)) + reg_y_read)) - + (CLK_ADD(CLK, 2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y_read) > 0xff \ + ? (LOAD((LOAD_ZERO_ADDR((addr)) & 0xff00) \ + | ((LOAD_ZERO_ADDR((addr)) + reg_y_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD(LOAD_ZERO_ADDR((addr)) + reg_y_read)) \ + : LOAD(LOAD_ZERO_ADDR((addr)) + reg_y_read)) +#else +#define LOAD_IND_Y(addr) \ + (CLK_ADD(CLK, 2), \ + tmpa = LOAD_ZERO(addr), \ + tmpa |= (LOAD_ZERO((addr + 1)) << 8), \ + ((((tmpa & 0xff) + reg_y_read) > 0xff) ? \ + (CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD_DUMMY((tmpa & 0xff00) | ((tmpa + reg_y_read) & 0xff)), \ + LOAD(tmpa + reg_y_read)) : \ + LOAD(tmpa + reg_y_read))) +#endif + +#if 0 #define LOAD_ZERO_X(addr) (LOAD_ZERO((addr) + reg_x_read)) - +#define NOOP_LOAD_ZERO_X(addr) (LOAD_ZERO((addr) + reg_x_read)) + #define LOAD_ZERO_Y(addr) (LOAD_ZERO((addr) + reg_y_read)) - +#else +#define LOAD_ZERO_X(addr) \ + (LOAD_ZERO_DUMMY(addr), \ + LOAD_ZERO(addr + reg_x_read)) + +#define NOOP_LOAD_ZERO_X(addr) \ + (LOAD_ZERO_DUMMY(addr), \ + LOAD_ZERO_DUMMY(addr + reg_x_read)) + +#define LOAD_ZERO_Y(addr) \ + (LOAD_ZERO_DUMMY(addr), \ + LOAD_ZERO(addr + reg_y_read)) +#endif + +#if 0 #define LOAD_IND_Y_BANK(addr) \ -(CLK_ADD(CLK, 2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y_read) > 0xff \ -? (LOAD_IND((LOAD_ZERO_ADDR((addr)) & 0xff00) \ -| ((LOAD_ZERO_ADDR((addr)) + reg_y_read) & 0xff)), \ -CLK_ADD(CLK, CLK_INT_CYCLE), \ -LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y_read)) \ -: LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y_read)) - + (CLK_ADD(CLK, 2), ((LOAD_ZERO_ADDR((addr)) & 0xff) + reg_y_read) > 0xff \ + ? (LOAD_IND((LOAD_ZERO_ADDR((addr)) & 0xff00) \ + | ((LOAD_ZERO_ADDR((addr)) + reg_y_read) & 0xff)), \ + CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y_read)) \ + : LOAD_IND(LOAD_ZERO_ADDR((addr)) + reg_y_read)) +#else +#define LOAD_IND_Y_BANK(addr) \ + (CLK_ADD(CLK, 2), \ + tmpa = LOAD_ZERO(addr), \ + tmpa |= (LOAD_ZERO(addr + 1) << 8), \ + ((((tmpa & 0xff) + reg_y_read) > 0xff) ? \ + (CLK_ADD(CLK, CLK_INT_CYCLE), \ + LOAD_DUMMY((tmpa & 0xff00) | ((tmpa + reg_y_read) & 0xff)), \ + LOAD_IND(tmpa + reg_y_read)) : \ + LOAD_IND(tmpa + reg_y_read))) +#endif + #define STORE_ABS(addr, value, inc) \ -do { \ -CLK_ADD(CLK, (inc)); \ -STORE((addr), (value)); \ -} while (0) - -#define STORE_ABS_X(addr, value, inc) \ -do { \ -CLK_ADD(CLK, (inc) - 2); \ -LOAD((((addr) + reg_x_read) & 0xff) | ((addr) & 0xff00)); \ -CLK_ADD(CLK, 2); \ -STORE((addr) + reg_x_read, (value)); \ -} while (0) - + do { \ + CLK_ADD(CLK, (inc)); \ + STORE((addr), (value)); \ + } while (0) + +#define STORE_ABS_X(addr, value, inc) \ + do { \ + CLK_ADD(CLK, (inc) - 2); \ + LOAD_DUMMY((((addr) + reg_x_read) & 0xff) | ((addr) & 0xff00)); \ + CLK_ADD(CLK, 2); \ + STORE((addr) + reg_x_read, (value)); \ + } while (0) + #define STORE_ABS_X_RMW(addr, value, inc) \ -do { \ -CLK_ADD(CLK, (inc)); \ -STORE((addr) + reg_x_read, (value)); \ -} while (0) - -#define STORE_ABS_SH_X(addr, value, inc) \ -do { \ -unsigned int tmp2; \ -\ -CLK_ADD(CLK, (inc) - 2); \ -LOAD((((addr) + reg_x_read) & 0xff) | ((addr) & 0xff00)); \ -CLK_ADD(CLK, 2); \ -tmp2 = (addr) + reg_x_read; \ -if (((addr) & 0xff) + reg_x_read > 0xff) { \ -tmp2 = (tmp2 & 0xff) | ((value) << 8); \ -} \ -STORE(tmp2, (value)); \ -} while (0) - -#define STORE_ABS_Y(addr, value, inc) \ -do { \ -CLK_ADD(CLK, (inc) - 2); \ -LOAD((((addr) + reg_y_read) & 0xff) | ((addr) & 0xff00)); \ -CLK_ADD(CLK, 2); \ -STORE((addr) + reg_y_read, (value)); \ -} while (0) - + do { \ + CLK_ADD(CLK, (inc)); \ + STORE((addr) + reg_x_read, (value)); \ + } while (0) + +#define STORE_ABS_SH_X(addr, value, inc) \ + do { \ + unsigned int tmp2; \ + \ + CLK_ADD(CLK, (inc) - 2); \ + LOAD_DUMMY((((addr) + reg_x_read) & 0xff) | ((addr) & 0xff00)); \ + CLK_ADD(CLK, 2); \ + tmp2 = (addr) + reg_x_read; \ + if (((addr) & 0xff) + reg_x_read > 0xff) { \ + tmp2 = (tmp2 & 0xff) | ((value) << 8); \ + } \ + STORE(tmp2, (value)); \ + } while (0) + +#define STORE_ABS_Y(addr, value, inc) \ + do { \ + CLK_ADD(CLK, (inc) - 2); \ + LOAD_DUMMY((((addr) + reg_y_read) & 0xff) | ((addr) & 0xff00)); \ + CLK_ADD(CLK, 2); \ + STORE((addr) + reg_y_read, (value)); \ + } while (0) + #define STORE_ABS_Y_RMW(addr, value, inc) \ -do { \ -CLK_ADD(CLK, (inc)); \ -STORE((addr) + reg_y_read, (value)); \ -} while (0) - -#define STORE_ABS_SH_Y(addr, value, inc) \ -do { \ -unsigned int tmp2; \ -\ -CLK_ADD(CLK, (inc) - 2); \ -LOAD((((addr) + reg_y_read) & 0xff) | ((addr) & 0xff00)); \ -CLK_ADD(CLK, 2); \ -tmp2 = (addr) + reg_y_read; \ -if (((addr) & 0xff) + reg_y_read > 0xff) { \ -tmp2 = (tmp2 & 0xff) | ((value) << 8); \ -} \ -STORE(tmp2, (value)); \ -} while (0) - + do { \ + CLK_ADD(CLK, (inc)); \ + STORE((addr) + reg_y_read, (value)); \ + } while (0) + +#define STORE_ABS_SH_Y(addr, value, inc) \ + do { \ + unsigned int tmp2; \ + \ + CLK_ADD(CLK, (inc) - 2); \ + LOAD_DUMMY((((addr) + reg_y_read) & 0xff) | ((addr) & 0xff00)); \ + CLK_ADD(CLK, 2); \ + tmp2 = (addr) + reg_y_read; \ + if (((addr) & 0xff) + reg_y_read > 0xff) { \ + tmp2 = (tmp2 & 0xff) | ((value) << 8); \ + } \ + STORE(tmp2, (value)); \ + } while (0) + #define INC_PC(value) (reg_pc += (value)) - - /* ------------------------------------------------------------------------- */ - - /* Opcodes. */ - - /* + +/* macros to perform the dummy writes for RMW instructions. revert to the + functions that do not actually perform the write when weirdo behaviour + shows up */ + +#if 1 + +#define DUMMY_STORE_ABS_RMW(addr, value) \ + do { \ + STORE_DUMMY(addr, value); \ + } while (0) + +#define DUMMY_STORE_ABS_X_RMW(addr, value) \ + do { \ + STORE_DUMMY((addr) + reg_x_read, (value)); \ + } while (0) + +#define DUMMY_STORE_ABS_Y_RMW(addr, value) \ + do { \ + STORE_DUMMY((addr) + reg_y_read, (value)); \ + } while (0) +#else + +/* FIXME: trigger write checkpoints */ +#define DUMMY_STORE_ABS_RMW(addr, value) +#define DUMMY_STORE_ABS_X_RMW(addr, value) +#define DUMMY_STORE_ABS_Y_RMW(addr, value) + +#endif +/* ------------------------------------------------------------------------- */ + +/* Opcodes. */ + +/* A couple of caveats about PC: - the VIC-II emulation requires PC to be incremented before the first @@ -1155,110 +1305,167 @@ INC_PC(pc_inc); } while (0) #define ANC(value, pc_inc) \ -do { \ -BYTE tmp = (BYTE)(reg_a_read & (value)); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -LOCAL_SET_CARRY(LOCAL_SIGN()); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint8_t tmp = (uint8_t)(reg_a_read & (value)); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + LOCAL_SET_CARRY(LOCAL_SIGN()); \ + INC_PC(pc_inc); \ + } while (0) + #define AND(value, clk_inc, pc_inc) \ -do { \ -BYTE tmp = (BYTE)(reg_a_read & (value)); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - - /* - The result of the ANE opcode is A = ((A | CONST) & X & IMM), with CONST apparently - being both chip- and temperature dependent. - - The commonly used value for CONST in various documents is 0xee, which is however - not to be taken for granted (as it is unstable). see here: - http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,_ANE) - - as seen in the list, there are several possible values, and its origin is still - kinda unknown. instead of the commonly used 0xee we use 0xff here, since this - will make the only known occurance of this opcode in actual code work. see here: - https://sourceforge.net/tracker/?func=detail&aid=2110948&group_id=223021&atid=1057617 - - FIXME: in the unlikely event that other code surfaces that depends on another - CONST value, it probably has to be made configureable somehow if no value can - be found that works for both. - */ - + do { \ + uint8_t tmp = (uint8_t)(reg_a_read & (value)); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + + +/* +The result of the ANE opcode is A = ((A | CONST) & X & IMM), with CONST apparently +being both chip- and temperature dependent. There is also a dependency on the RDY +line, ie somehow bit4 and bit0 are affected in the cycle when a DMA starts. + +The commonly used value for CONST in various documents is 0xee, which is however +not to be taken for granted (as it is unstable). see here: +http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,_ANE) + +as seen in the list, there are several possible values, and its origin is still +kinda unknown. instead of the commonly used 0xee we use 0xef here, since this +appears to work with all known occurances of this opcode in real code: + +known occurances of this opcode in actual code are: + +- spectipede (original tape), use of ANE is unstable. bits 7,6,5,0 MUST be set + in the magic constant (that makes it not work with the common 0xee, but 0xef + works) +- turrican 3 (by smash designs), use of ANE is unstable. bits 6,1,0 MUST be set + in the magic constant (that makes it not work with the common 0xee, but 0xef + works) +- the ocean/imagine tape loader (yie ar kung fu, rambo first blood part ii, + comic bakery), use of ANE is stable. + +also see here: + +https://sourceforge.net/tracker/?func=detail&aid=2110948&group_id=223021&atid=1057617 + +FIXME: in the unlikely event that other code surfaces that depends on another +CONST value, it probably has to be made configureable somehow if no value can +be found that works for both. + +FIXME: perhaps we really have to add some randomness to (some) bits +*/ + +#define ANE_MAGIC 0xef +#define ANE_RDY_MAGIC 0xee + +#ifndef ANE_LOG_LEVEL +#define ANE_LOG_LEVEL 0 +#ifdef _MSC_VER +#pragma message ("Warning: ANE_LOG_LEVEL not defined, disabling by default") +#else +#warning "ANE_LOG_LEVEL not defined, disabling by default" +#endif +#endif + +#if 1 +#define ANE_LOGGING(rdy) \ + do { \ + unsigned int result = ((reg_a_read | (rdy ? ANE_RDY_MAGIC : ANE_MAGIC)) & reg_x_read & p1); \ + unsigned int unstablebits = ((reg_a_read ^ 0xff) & (p1 & reg_x_read)); \ + if ((ANE_LOG_LEVEL == 2) || ((ANE_LOG_LEVEL == 1) && (unstablebits != 0))) { \ + if (unstablebits == 0) { \ + log_warning(CPU_LOG_ID, "$%04x ANE #$%02x ; A=$%02x X=$%02x -> A=$%02x%s", \ + reg_pc, p1, reg_a_read, reg_x_read, result, rdy ? " (RDY cycle)" : ""); \ + } else { \ + log_warning(CPU_LOG_ID, "$%04x ANE #$%02x ; A=$%02x X=$%02x -> A=$%02x (unstable bits: %c%c%c%c%c%c%c%c)%s", \ + reg_pc, p1, reg_a_read, reg_x_read, result, \ + unstablebits & 0x80 ? '*' : '.', unstablebits & 0x40 ? '*' : '.', \ + unstablebits & 0x20 ? '*' : '.', unstablebits & 0x10 ? '*' : '.', \ + unstablebits & 0x08 ? '*' : '.', unstablebits & 0x04 ? '*' : '.', \ + unstablebits & 0x02 ? '*' : '.', unstablebits & 0x01 ? '*' : '.', \ + rdy ? " (RDY cycle)" : "" \ + ); \ + } \ + } \ + } while (0) +#else +#define ANE_LOGGING(rdy) +#endif + #ifndef ANE -#define ANE(value, pc_inc) \ -do { \ -BYTE tmp = ((reg_a_read | 0xff) & reg_x_read & ((BYTE)(value))); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(pc_inc); \ -} while (0) +#define ANE(value, pc_inc) \ + do { \ + uint8_t tmp = ((reg_a_read | ANE_MAGIC) & reg_x_read & ((uint8_t)(value))); \ + ANE_LOGGING(0); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + } while (0) #endif /* The fanciest opcode ever... ARR! */ #define ARR(value, pc_inc) \ -do { \ -unsigned int tmp; \ -\ -tmp = reg_a_read & (value); \ -if (LOCAL_DECIMAL()) { \ -int tmp_2 = tmp; \ -tmp_2 |= (reg_p & P_CARRY) << 8; \ -tmp_2 >>= 1; \ -LOCAL_SET_SIGN(LOCAL_CARRY()); \ -LOCAL_SET_ZERO(!tmp_2); \ -LOCAL_SET_OVERFLOW((tmp_2 ^ tmp) & 0x40); \ -if (((tmp & 0xf) + (tmp & 0x1)) > 0x5) { \ -tmp_2 = (tmp_2 & 0xf0) | ((tmp_2 + 0x6) & 0xf); \ -} \ -if (((tmp & 0xf0) + (tmp & 0x10)) > 0x50) { \ -tmp_2 = (tmp_2 & 0x0f) | ((tmp_2 + 0x60) & 0xf0); \ -LOCAL_SET_CARRY(1); \ -} else { \ -LOCAL_SET_CARRY(0); \ -} \ -reg_a_write(tmp_2); \ -} else { \ -tmp |= (reg_p & P_CARRY) << 8; \ -tmp >>= 1; \ -LOCAL_SET_NZ(tmp); \ -LOCAL_SET_CARRY(tmp & 0x40); \ -LOCAL_SET_OVERFLOW((tmp & 0x40) ^ ((tmp & 0x20) << 1)); \ -reg_a_write(tmp); \ -} \ -INC_PC(pc_inc); \ -} while (0) - -#define ASL(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp_value, tmp_addr; \ -\ -tmp_addr = (addr); \ -tmp_value = load_func(tmp_addr); \ -LOCAL_SET_CARRY(tmp_value & 0x80); \ -tmp_value = (tmp_value << 1) & 0xff; \ -LOCAL_SET_NZ(tmp_value); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp_value, clk_inc); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + unsigned int tmp; \ + \ + tmp = reg_a_read & (value); \ + if (LOCAL_DECIMAL()) { \ + int tmp_2 = tmp; \ + tmp_2 |= (reg_p & P_CARRY) << 8; \ + tmp_2 >>= 1; \ + LOCAL_SET_SIGN(LOCAL_CARRY()); \ + LOCAL_SET_ZERO(!tmp_2); \ + LOCAL_SET_OVERFLOW((tmp_2 ^ tmp) & 0x40); \ + if (((tmp & 0xf) + (tmp & 0x1)) > 0x5) { \ + tmp_2 = (tmp_2 & 0xf0) | ((tmp_2 + 0x6) & 0xf); \ + } \ + if (((tmp & 0xf0) + (tmp & 0x10)) > 0x50) { \ + tmp_2 = (tmp_2 & 0x0f) | ((tmp_2 + 0x60) & 0xf0); \ + LOCAL_SET_CARRY(1); \ + } else { \ + LOCAL_SET_CARRY(0); \ + } \ + reg_a_write(tmp_2); \ + } else { \ + tmp |= (reg_p & P_CARRY) << 8; \ + tmp >>= 1; \ + LOCAL_SET_NZ(tmp); \ + LOCAL_SET_CARRY(tmp & 0x40); \ + LOCAL_SET_OVERFLOW((tmp & 0x40) ^ ((tmp & 0x20) << 1)); \ + reg_a_write(tmp); \ + } \ + INC_PC(pc_inc); \ + } while (0) + +#define ASL(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp_value, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp_value = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp_value); \ + LOCAL_SET_CARRY(tmp_value & 0x80); \ + tmp_value = (tmp_value << 1) & 0xff; \ + LOCAL_SET_NZ(tmp_value); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp_value, 1); \ + } while (0) + #define ASL_A() \ -do { \ -BYTE tmp = reg_a_read; \ -LOCAL_SET_CARRY(tmp & 0x80); \ -tmp <<= 1; \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(1); \ -} while (0) - + do { \ + uint8_t tmp = reg_a_read; \ + LOCAL_SET_CARRY(tmp & 0x80); \ + tmp <<= 1; \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(1); \ + } while (0) + #define ASR(value, pc_inc) \ do { \ unsigned int tmp = reg_a_read & (value); \ @@ -1282,74 +1489,78 @@ INC_PC(pc_inc); \ } while (0) #ifndef C64DTV -#define BRANCH(cond, value) \ -do { \ -INC_PC(2); \ -\ -if (cond) { \ -unsigned int dest_addr = reg_pc + (signed char)(value); \ -\ -FETCH_PARAM(reg_pc); \ -CLK_ADD(CLK, CLK_BRANCH2); \ -if ((reg_pc ^ dest_addr) & 0xff00) { \ -LOAD((reg_pc & 0xff00) | (dest_addr & 0xff)); \ -CLK_ADD(CLK, CLK_BRANCH2); \ -} else { \ -OPCODE_DELAYS_INTERRUPT(); \ -} \ -JUMP(dest_addr & 0xffff); \ -} \ -} while (0) +#define BRANCH(cond, value) \ + do { \ + INC_PC(2); \ + \ + if (cond) { \ + unsigned int dest_addr = reg_pc + (signed char)(value); \ + \ + FETCH_PARAM_DUMMY(reg_pc); \ + CLK_ADD(CLK, CLK_BRANCH2); \ + if ((reg_pc ^ dest_addr) & 0xff00) { \ + LOAD_DUMMY((reg_pc & 0xff00) | (dest_addr & 0xff)); \ + CLK_ADD(CLK, CLK_BRANCH2); \ + } else { \ + OPCODE_DELAYS_INTERRUPT(); \ + } \ + JUMP(dest_addr & 0xffff); \ + } \ + } while (0) #endif #define BRK() \ -do { \ -EXPORT_REGISTERS(); \ -INC_PC(2); \ -LOCAL_SET_BREAK(1); \ -PUSH(reg_pc >> 8); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -PUSH(reg_pc & 0xff); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -CLK_ADD(CLK, CLK_BRK - 3); \ -PUSH(LOCAL_STATUS()); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_STATUS, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -CLK_ADD(CLK, 1); \ -CPU_DELAY_CLK /* process alarms for cartridge freeze */ \ -PROCESS_ALARMS \ -if ((CPU_INT_STATUS->global_pending_int & IK_NMI) \ -&& (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ -/* BRK transformed into NMI — re-annotate */ \ -if (c64d_drive_cpu_stack_entry_types) { \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ - c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ -} \ -LOCAL_SET_INTERRUPT(1); \ -TRACE_NMI(CLK - CLK_BRK); \ -if (monitor_mask[CALLER] & (MI_STEP)) { \ -monitor_check_icount_interrupt(); \ -} \ -interrupt_ack_nmi(CPU_INT_STATUS); \ -JUMP(LOAD_ADDR(0xfffa)); \ -} else if ((CPU_INT_STATUS->global_pending_int & (IK_IRQ | IK_IRQPEND)) \ -&& !LOCAL_INTERRUPT() && (CLK >= (CPU_INT_STATUS->irq_clk + INTERRUPT_DELAY))) { \ -LOCAL_SET_INTERRUPT(1); \ -TRACE_IRQ(CLK - CLK_BRK); \ -if (monitor_mask[CALLER] & (MI_STEP)) { \ -monitor_check_icount_interrupt(); \ -} \ -interrupt_ack_irq(CPU_INT_STATUS); \ -JUMP(LOAD_ADDR(0xfffe)); \ -} else { \ -TRACE_BRK(); \ -LOCAL_SET_INTERRUPT(1); \ -JUMP(LOAD_ADDR(0xfffe)); \ -} \ -CLK_ADD(CLK, 2); \ -} while (0) - -#define CLC() \ + do { \ + uint16_t addr, handler_vector; \ + EXPORT_REGISTERS(); \ + INC_PC(2); \ + LOCAL_SET_BREAK(1); \ + PUSH(reg_pc >> 8); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + PUSH(reg_pc & 0xff); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + CLK_ADD(CLK, CLK_BRK - 3); \ + PUSH(LOCAL_STATUS()); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_BRK_STATUS, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + CLK_ADD(CLK, 1); \ + CPU_DELAY_CLK /* process alarms for cartridge freeze */ \ + PROCESS_ALARMS \ + if ((CPU_INT_STATUS->global_pending_int & IK_NMI) \ + && (CLK >= (CPU_INT_STATUS->nmi_clk + INTERRUPT_DELAY))) { \ + /* c64d: BRK transformed into NMI -- re-annotate */ \ + if (c64d_drive_cpu_stack_entry_types) { \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 3)] = C64D_STACK_ENTRY_NMI_PCH; \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 2)] = C64D_STACK_ENTRY_NMI_PCL; \ + c64d_drive_cpu_stack_entry_types[(uint8_t)(reg_sp + 1)] = C64D_STACK_ENTRY_NMI_STATUS; \ + } \ + LOCAL_SET_INTERRUPT(1); \ + TRACE_NMI(CLK - CLK_BRK); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_nmi(CPU_INT_STATUS); \ + handler_vector = 0xfffa; \ + } else if ((CPU_INT_STATUS->global_pending_int & (IK_IRQ | IK_IRQPEND)) \ + && !LOCAL_INTERRUPT() && (CLK >= (CPU_INT_STATUS->irq_clk + INTERRUPT_DELAY))) { \ + LOCAL_SET_INTERRUPT(1); \ + TRACE_IRQ(CLK - CLK_BRK); \ + if (monitor_mask[CALLER] & (MI_STEP)) { \ + monitor_check_icount_interrupt(); \ + } \ + interrupt_ack_irq(CPU_INT_STATUS); \ + handler_vector = 0xfffe; \ + } else { \ + TRACE_BRK(); \ + LOCAL_SET_INTERRUPT(1); \ + handler_vector = 0xfffe; \ + } \ + addr = LOAD_ADDR(handler_vector); \ + CHECK_PROFILE_INTERRUPT(addr, handler_vector); \ + JUMP(addr); \ + CLK_ADD(CLK, 2); \ + } while (0) + +#define CLC() \ do { \ INC_PC(1); \ LOCAL_SET_CARRY(0); \ @@ -1399,65 +1610,68 @@ INC_PC(pc_inc); \ } while (0) #define CPY(value, clk_inc, pc_inc) \ -do { \ -unsigned int tmp; \ -\ -tmp = reg_y_read - (value); \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_NZ(tmp & 0xff); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - -#define DCP(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp_addr; \ -\ -tmp_addr = (addr); \ -CLK_ADD(CLK, (clk_inc1)); \ -tmp = load_func(tmp_addr); \ -tmp = (tmp - 1) & 0xff; \ -LOCAL_SET_CARRY(reg_a_read >= tmp); \ -LOCAL_SET_NZ((reg_a_read - tmp)); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, (clk_inc2)); \ -RMW_FLAG = 0; \ -} while (0) - -#define DCP_IND_Y(addr) \ -do { \ -unsigned int tmp; \ -unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ -\ -CLK_ADD(CLK, 2); \ -LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -tmp_addr += reg_y_read; \ -tmp = LOAD(tmp_addr); \ -tmp = (tmp - 1) & 0xff; \ -LOCAL_SET_CARRY(reg_a_read >= tmp); \ -LOCAL_SET_NZ((reg_a_read - tmp)); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -STORE_ABS(tmp_addr, tmp, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - -#define DEC(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp_addr; \ -\ -tmp_addr = (addr); \ -tmp = load_func(tmp_addr); \ -tmp = (tmp - 1) & 0xff; \ -LOCAL_SET_NZ(tmp); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, (clk_inc)); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + unsigned int tmp; \ + \ + tmp = reg_y_read - (value); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define DCP(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + CLK_ADD(CLK, (clk_inc1)); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + tmp = (tmp - 1) & 0xff; \ + LOCAL_SET_CARRY(reg_a_read >= tmp); \ + LOCAL_SET_NZ((reg_a_read - tmp)); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + +#define DCP_IND_Y(addr) \ + do { \ + unsigned int tmp; \ + unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ + \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + tmp_addr += reg_y_read; \ + tmp = LOAD(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(tmp_addr, tmp); \ + tmp = (tmp - 1) & 0xff; \ + LOCAL_SET_CARRY(reg_a_read >= tmp); \ + LOCAL_SET_NZ((reg_a_read - tmp)); \ + INC_PC(2); \ + STORE_ABS(tmp_addr, tmp, 1); \ + } while (0) + +#define DEC(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + tmp = (tmp - 1) & 0xff; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + #define DEX() \ do { \ reg_x_write(reg_x_read - 1); \ @@ -1473,27 +1687,29 @@ INC_PC(1); \ } while (0) #define EOR(value, clk_inc, pc_inc) \ -do { \ -BYTE tmp = (BYTE)(reg_a_read ^ (value)); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - -#define INC(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp_addr; \ -\ -tmp_addr = (addr); \ -tmp = (load_func(tmp_addr) + 1) & 0xff; \ -LOCAL_SET_NZ(tmp); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, (clk_inc)); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + uint8_t tmp = (uint8_t)(reg_a_read ^ (value)); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define INC(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + tmp = (tmp + 1) & 0xff; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + #define INX() \ do { \ reg_x_write(reg_x_read + 1); \ @@ -1502,98 +1718,113 @@ INC_PC(1); \ } while (0) #define INY() \ -do { \ -reg_y_write(reg_y_read + 1); \ -LOCAL_SET_NZ(reg_y_read); \ -INC_PC(1); \ -} while (0) - -#define ISB(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -BYTE my_src; \ -int my_addr = (addr); \ -\ -CLK_ADD(CLK, (clk_inc1)); \ -my_src = load_func(my_addr); \ -my_src = (my_src + 1) & 0xff; \ -SBC(my_src, 0, 0); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(my_addr, my_src, clk_inc2); \ -RMW_FLAG = 0; \ -} while (0) - -#define ISB_IND_Y(addr) \ -do { \ -BYTE my_src; \ -int my_addr = LOAD_ZERO_ADDR(addr); \ -\ -CLK_ADD(CLK, 2); \ -LOAD((my_addr & 0xff00) | ((my_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -my_addr += reg_y_read; \ -my_src = LOAD(my_addr); \ -my_src = (my_src + 1) & 0xff; \ -SBC(my_src, 0, 0); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -STORE_ABS(my_addr, my_src, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - - /* The 0x02 JAM opcode is also used to patch the ROM. The function trap_handler() + do { \ + reg_y_write(reg_y_read + 1); \ + LOCAL_SET_NZ(reg_y_read); \ + INC_PC(1); \ + } while (0) + +#define ISB(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + uint8_t my_src; \ + int my_addr = (addr); \ + \ + CLK_ADD(CLK, (clk_inc1)); \ + my_src = load_func(my_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(my_addr, my_src); \ + my_src = (my_src + 1) & 0xff; \ + SBC(my_src, 0, 0); \ + INC_PC(pc_inc); \ + store_func(my_addr, my_src, 1); \ + } while (0) + +#define ISB_IND_Y(addr) \ + do { \ + uint8_t my_src; \ + int my_addr = LOAD_ZERO_ADDR(addr); \ + \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((my_addr & 0xff00) | ((my_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + my_addr += reg_y_read; \ + my_src = LOAD(my_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(my_addr, my_src); \ + my_src = (my_src + 1) & 0xff; \ + SBC(my_src, 0, 0); \ + INC_PC(2); \ + STORE_ABS(my_addr, my_src, 1); \ + } while (0) + +/* The 0x02 JAM opcode is also used to patch the ROM. The function trap_handler() returns nonzero if this is not a patch, but a `real' JAM instruction. */ - -#define JAM_02() \ -do { \ -DWORD trap_result; \ -EXPORT_REGISTERS(); \ -if (!ROM_TRAP_ALLOWED() || (trap_result = ROM_TRAP_HANDLER()) == (DWORD)-1) { \ -REWIND_FETCH_OPCODE(CLK); \ -JAM(); \ -} else { \ -if (trap_result) { \ -REWIND_FETCH_OPCODE(CLK); \ -SET_OPCODE(trap_result); \ -IMPORT_REGISTERS(); \ -goto trap_skipped; \ -} else { \ -IMPORT_REGISTERS(); \ -} \ -} \ -} while (0) - + +#define JAM_02() \ + do { \ + uint32_t trap_result; \ + EXPORT_REGISTERS(); \ + if (!ROM_TRAP_ALLOWED() || (trap_result = ROM_TRAP_HANDLER()) == (uint32_t)-1) { \ + CPU_IS_JAMMED = 1; \ + REWIND_FETCH_OPCODE(CLK); \ + JAM(); \ + } else { \ + if (trap_result) { \ + REWIND_FETCH_OPCODE(CLK); \ + SET_OPCODE(trap_result); \ + IMPORT_REGISTERS(); \ + goto trap_skipped; \ + } else { \ + IMPORT_REGISTERS(); \ + } \ + } \ + } while (0) + #define JMP(addr) \ do { \ JUMP(addr); \ } while (0) #define JMP_IND() \ -do { \ -WORD dest_addr; \ -dest_addr = LOAD(p2); \ -CLK_ADD(CLK, 1); \ -dest_addr |= (LOAD((p2 & 0xff00) | ((p2 + 1) & 0xff)) << 8); \ -CLK_ADD(CLK, 1); \ -JUMP(dest_addr); \ -} while (0) - + do { \ + uint16_t dest_addr; \ + dest_addr = LOAD(p2); \ + CLK_ADD(CLK, 1); \ + dest_addr |= (LOAD((p2 & 0xff00) | ((p2 + 1) & 0xff)) << 8); \ + CLK_ADD(CLK, 1); \ + JUMP(dest_addr); \ + } while (0) + +/* HACK: fix JSR MSB in monitor CPU history */ +#if defined(FEATURE_CPUMEMHISTORY) && !defined(DRIVE_CPU) +#define JSR_FIXUP_MSB(x) monitor_cpuhistory_fix_p2(x) +#else +#define JSR_FIXUP_MSB(x) +#endif + #define JSR() \ -do { \ -unsigned int tmp_addr; \ -\ -CLK_ADD(CLK, 1); \ -INC_PC(2); \ -CLK_ADD(CLK, 2); \ -PUSH(((reg_pc) >> 8) & 0xff); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -PUSH((reg_pc) & 0xff); \ -C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ -tmp_addr = (p1 | (FETCH_PARAM(reg_pc) << 8)); \ -CLK_ADD(CLK, CLK_JSR_INT_CYCLE); \ -JUMP(tmp_addr); \ -} while (0) - + do { \ + uint8_t addr_msb; \ + unsigned int tmp_addr; \ + \ + LOAD_DUMMY(0x100 + reg_sp); \ + CLK_ADD(CLK, 1); \ + INC_PC(2); \ + CLK_ADD(CLK, 2); \ + PUSH(((reg_pc) >> 8) & 0xff); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCH, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + PUSH((reg_pc) & 0xff); \ + C64D_DRIVE_ANNOTATE_PUSH(C64D_STACK_ENTRY_JSR_PCL, C64D_IRQ_SOURCE_UNKNOWN, LAST_OPCODE_ADDR); \ + addr_msb = LOAD(reg_pc); \ + JSR_FIXUP_MSB(addr_msb); \ + tmp_addr = (p1 | (addr_msb << 8)); \ + CLK_ADD(CLK, CLK_JSR_INT_CYCLE); \ + CHECK_PROFILE_JSR(tmp_addr); \ + JUMP(tmp_addr); \ + } while (0) + #define LAS(value, clk_inc, pc_inc) \ do { \ reg_sp = reg_sp & (value); \ @@ -1605,87 +1836,139 @@ INC_PC(pc_inc); \ } while (0) #define LAX(value, clk_inc, pc_inc) \ -do { \ -BYTE tmp = (value); \ -reg_x_write(tmp); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint8_t tmp = (value); \ + reg_x_write(tmp); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + #define LDA(value, clk_inc, pc_inc) \ -do { \ -BYTE tmp = (BYTE)(value); \ -reg_a_write(tmp); \ -CLK_ADD(CLK, (clk_inc)); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint8_t tmp = (uint8_t)(value); \ + reg_a_write(tmp); \ + CLK_ADD(CLK, (clk_inc)); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + } while (0) + #define LDX(value, clk_inc, pc_inc) \ -do { \ -reg_x_write((BYTE)(value)); \ -LOCAL_SET_NZ(reg_x_read); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + reg_x_write((uint8_t)(value)); \ + LOCAL_SET_NZ(reg_x_read); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + #define LDY(value, clk_inc, pc_inc) \ -do { \ -reg_y_write((BYTE)(value)); \ -LOCAL_SET_NZ(reg_y_read); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - -#define LSR(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp_addr; \ -\ -tmp_addr = (addr); \ -tmp = load_func(tmp_addr); \ -LOCAL_SET_CARRY(tmp & 0x01); \ -tmp >>= 1; \ -LOCAL_SET_NZ(tmp); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, clk_inc); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + reg_y_write((uint8_t)(value)); \ + LOCAL_SET_NZ(reg_y_read); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + +#define LSR(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + tmp >>= 1; \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + #define LSR_A() \ -do { \ -unsigned int tmp = reg_a_read; \ -LOCAL_SET_CARRY(tmp & 0x01); \ -tmp >>= 1; \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(1); \ -} while (0) - - /* Note: this is not always exact, as this opcode can be quite unstable! - Moreover, the behavior is different from the one described in 64doc. */ + do { \ + unsigned int tmp = reg_a_read; \ + LOCAL_SET_CARRY(tmp & 0x01); \ + tmp >>= 1; \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(1); \ + } while (0) + +/* +The result of the LXA opcode is A = X = ((A | CONST) & IMM), with CONST apparently +being both chip- and temperature dependent. There is also a dependency on the RDY +line, ie somehow bit4 and bit0 are affected in the cycle when a DMA starts. + +The commonly used value for CONST in various documents is 0xee, which is however +not to be taken for granted (as it is unstable). + +FIXME: in the unlikely event that other code surfaces that depends on another +CONST value, it probably has to be made configureable somehow if no value can +be found that works for both. + +FIXME: perhaps we really have to add some randomness to (some) bits +*/ + +#define LXA_MAGIC 0xee /* needs to be 0xee for wizball */ +#define LXA_RDY_MAGIC 0xee + +#ifndef LXA_LOG_LEVEL +#define LXA_LOG_LEVEL 0 +#ifdef _MSC_VER +#pragma message ("Warning: LXA_LOG_LEVEL not defined, disabling by default") +#else +#warning "LXA_LOG_LEVEL not defined, disabling by default" +#endif +#endif + +#if 1 +#define LXA_LOGGING(rdy) \ + do { \ + unsigned int result = (reg_a_read | (rdy ? LXA_RDY_MAGIC : LXA_MAGIC)) & p1; \ + unsigned int unstablebits = (reg_a_read ^ 0xff) & p1; \ + if ((LXA_LOG_LEVEL == 2) || ((LXA_LOG_LEVEL == 1) && (unstablebits != 0))) { \ + if (unstablebits == 0) { \ + log_warning(CPU_LOG_ID, "$%04x LAX #$%02x ; A=$%02x -> A=X=$%02x%s", \ + reg_pc, p1, reg_a_read, result, rdy ? " (RDY cycle)" : ""); \ + } else { \ + log_warning(CPU_LOG_ID, "$%04x LAX #$%02x ; A=$%02x -> A=X=$%02x (unstable bits: %c%c%c%c%c%c%c%c)%s", \ + reg_pc, p1, reg_a_read, result, \ + unstablebits & 0x80 ? '*' : '.', unstablebits & 0x40 ? '*' : '.', \ + unstablebits & 0x20 ? '*' : '.', unstablebits & 0x10 ? '*' : '.', \ + unstablebits & 0x08 ? '*' : '.', unstablebits & 0x04 ? '*' : '.', \ + unstablebits & 0x02 ? '*' : '.', unstablebits & 0x01 ? '*' : '.', \ + rdy ? " (RDY cycle)" : "" \ + ); \ + } \ + } \ + } while (0) +#else +#define LXA_LOGGING(rdy) +#endif + #ifndef LXA -#define LXA(value, pc_inc) \ -do { \ -BYTE tmp = ((reg_a_read | 0xee) & ((BYTE)(value))); \ -reg_x_write(tmp); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(pc_inc); \ -} while (0) +#define LXA(value, pc_inc) \ + do { \ + uint8_t tmp = ((reg_a_read | LXA_MAGIC) & ((uint8_t)(value))); \ + LXA_LOGGING(0); \ + reg_x_write(tmp); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(pc_inc); \ + } while (0) #endif #define ORA(value, clk_inc, pc_inc) \ -do { \ -BYTE tmp = (BYTE)(reg_a_read | (value)); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -CLK_ADD(CLK, (clk_inc)); \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint8_t tmp = (uint8_t)(reg_a_read | (value)); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + CLK_ADD(CLK, (clk_inc)); \ + INC_PC(pc_inc); \ + } while (0) + #define NOOP(clk_inc, pc_inc) (CLK_ADD(CLK, (clk_inc)), INC_PC(pc_inc)) #define NOOP_IMM(pc_inc) INC_PC(pc_inc) @@ -1698,12 +1981,12 @@ INC_PC(3); \ } while (0) #define NOOP_ABS_X() \ -do { \ -LOAD_ABS_X(p2); \ -CLK_ADD(CLK, 1); \ -INC_PC(3); \ -} while (0) - + do { \ + NOOP_LOAD_ABS_X(p2); \ + CLK_ADD(CLK, 1); \ + INC_PC(3); \ + } while (0) + #define NOP() NOOP_IMM(1) #define PHA() \ @@ -1723,195 +2006,210 @@ INC_PC(1); \ } while (0) #define PLA() \ -do { \ -BYTE tmp; \ -CLK_ADD(CLK, CLK_STACK_PULL); \ -tmp = PULL(); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -INC_PC(1); \ -} while (0) - - /* FIXME: Rotate disk before executing LOCAL_SET_STATUS(). */ + do { \ + uint8_t tmp; \ + CLK_ADD(CLK, CLK_STACK_PULL); \ + LOAD_DUMMY(0x100 + reg_sp); \ + tmp = PULL(); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + INC_PC(1); \ + } while (0) + +/* FIXME: Rotate disk before executing LOCAL_SET_STATUS(). */ #define PLP() \ -do { \ -BYTE s = PULL(); \ -\ -if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) { \ -OPCODE_ENABLES_IRQ(); \ -} else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) { \ -OPCODE_DISABLES_IRQ(); \ -} \ -CLK_ADD(CLK, CLK_STACK_PULL); \ -LOCAL_SET_STATUS(s); \ -INC_PC(1); \ -} while (0) - -#define RLA(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp2, tmp_addr; \ -\ -tmp_addr = (addr); \ -CLK_ADD(CLK, (clk_inc1)); \ -tmp = ((load_func(tmp_addr) << 1) | (reg_p & P_CARRY)); \ -LOCAL_SET_CARRY(tmp & 0x100); \ -tmp2 = reg_a_read & tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, clk_inc2); \ -RMW_FLAG = 0; \ -} while (0) - -#define RLA_IND_Y(addr) \ -do { \ -unsigned int tmp, tmp2; \ -unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ -\ -CLK_ADD(CLK, 2); \ -LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -tmp_addr += reg_y_read; \ -tmp = ((LOAD(tmp_addr) << 1) | (reg_p & P_CARRY)); \ -LOCAL_SET_CARRY(tmp & 0x100); \ -tmp2 = reg_a_read & tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -STORE_ABS(tmp_addr, tmp, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - -#define ROL(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp_addr; \ -\ -tmp_addr = (addr); \ -tmp = load_func(tmp_addr); \ -tmp = (tmp << 1) | (reg_p & P_CARRY); \ -LOCAL_SET_CARRY(tmp & 0x100); \ -LOCAL_SET_NZ(tmp & 0xff); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, clk_inc); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + uint8_t s; \ + LOAD_DUMMY(0x100 + reg_sp); \ + s = PULL(); \ + \ + if (!(s & P_INTERRUPT) && LOCAL_INTERRUPT()) { \ + OPCODE_ENABLES_IRQ(); \ + } else if ((s & P_INTERRUPT) && !LOCAL_INTERRUPT()) { \ + OPCODE_DISABLES_IRQ(); \ + } \ + CLK_ADD(CLK, CLK_STACK_PULL); \ + LOCAL_SET_STATUS(s); \ + INC_PC(1); \ + } while (0) + +#define RLA(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp2, tmp_addr; \ + \ + tmp_addr = (addr); \ + CLK_ADD(CLK, (clk_inc1)); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + tmp = ((tmp << 1) | (reg_p & P_CARRY)); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + tmp2 = reg_a_read & tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + +#define RLA_IND_Y(addr) \ + do { \ + unsigned int tmp, tmp2; \ + unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ + \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + tmp_addr += reg_y_read; \ + tmp = LOAD(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(tmp_addr, tmp); \ + tmp = ((tmp << 1) | (reg_p & P_CARRY)); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + tmp2 = reg_a_read & tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(2); \ + STORE_ABS(tmp_addr, tmp, 1); \ + } while (0) + +#define ROL(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp_addr; \ + \ + tmp_addr = (addr); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + tmp = (tmp << 1) | (reg_p & P_CARRY); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + #define ROL_A() \ -do { \ -unsigned int tmp = reg_a_read << 1; \ -\ -tmp |= (reg_p & P_CARRY); \ -reg_a_write(tmp); \ -LOCAL_SET_NZ(tmp); \ -LOCAL_SET_CARRY(tmp & 0x100); \ -INC_PC(1); \ -} while (0) - -#define ROR(addr, clk_inc, pc_inc, load_func, store_func) \ -do { \ -unsigned int src, tmp_addr; \ -\ -tmp_addr = (addr); \ -src = load_func(tmp_addr); \ -if (reg_p & P_CARRY) { \ -src |= 0x100; \ -} \ -LOCAL_SET_CARRY(src & 0x01); \ -src >>= 1; \ -LOCAL_SET_NZ(src); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, src, (clk_inc)); \ -RMW_FLAG = 0; \ -} while (0) - + do { \ + unsigned int tmp = reg_a_read << 1; \ + \ + tmp |= (reg_p & P_CARRY); \ + reg_a_write(tmp); \ + LOCAL_SET_NZ(tmp); \ + LOCAL_SET_CARRY(tmp & 0x100); \ + INC_PC(1); \ + } while (0) + +#define ROR(addr, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int src, tmp_addr; \ + \ + tmp_addr = (addr); \ + src = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, src); \ + if (reg_p & P_CARRY) { \ + src |= 0x100; \ + } \ + LOCAL_SET_CARRY(src & 0x01); \ + src >>= 1; \ + LOCAL_SET_NZ(src); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, src, 1); \ + } while (0) + #define ROR_A() \ -do { \ -unsigned int tmp = reg_a_read, tmp2; \ -tmp2 = (tmp >> 1) | (reg_p << 7); \ -LOCAL_SET_CARRY(tmp & 0x01); \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -INC_PC(1); \ -} while (0) - -#define RRA(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -BYTE src; \ -unsigned int my_temp, tmp_addr; \ -\ -CLK_ADD(CLK, (clk_inc1)); \ -tmp_addr = (addr); \ -src = load_func(tmp_addr); \ -my_temp = src >> 1; \ -if (reg_p & P_CARRY) { \ -my_temp |= 0x80; \ -} \ -LOCAL_SET_CARRY(src & 0x1); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -ADC(my_temp, 0, 0); \ -store_func(tmp_addr, my_temp, clk_inc2); \ -RMW_FLAG = 0; \ -} while (0) - -#define RRA_IND_Y(addr) \ -do { \ -BYTE src; \ -unsigned int my_tmp_addr; \ -unsigned int my_temp; \ -\ -CLK_ADD(CLK, 2); \ -my_tmp_addr = LOAD_ZERO_ADDR(addr); \ -LOAD((my_tmp_addr & 0xff00) | ((my_tmp_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -my_tmp_addr += reg_y_read; \ -src = LOAD(my_tmp_addr); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -my_temp = src >> 1; \ -if (reg_p & P_CARRY) { \ -my_temp |= 0x80; \ -} \ -LOCAL_SET_CARRY(src & 0x1); \ -ADC(my_temp, 0, 0); \ -STORE_ABS(my_tmp_addr, my_temp, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - - /* RTI does must not use `OPCODE_ENABLES_IRQ()' even if the I flag changes + do { \ + unsigned int tmp = reg_a_read, tmp2; \ + tmp2 = (tmp >> 1) | (reg_p << 7); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(1); \ + } while (0) + +#define RRA(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + uint8_t src; \ + unsigned int my_temp, tmp_addr; \ + \ + tmp_addr = (addr); \ + CLK_ADD(CLK, (clk_inc1)); \ + src = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, src); \ + my_temp = src >> 1; \ + if (reg_p & P_CARRY) { \ + my_temp |= 0x80; \ + } \ + LOCAL_SET_CARRY(src & 0x1); \ + INC_PC(pc_inc); \ + ADC(my_temp, 0, 0); \ + store_func(tmp_addr, my_temp, 1); \ + } while (0) + +#define RRA_IND_Y(addr) \ + do { \ + uint8_t src; \ + unsigned int my_tmp_addr; \ + unsigned int my_temp; \ + \ + my_tmp_addr = LOAD_ZERO_ADDR(addr); \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((my_tmp_addr & 0xff00) | ((my_tmp_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + my_tmp_addr += reg_y_read; \ + src = LOAD(my_tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(my_tmp_addr, src); \ + INC_PC(2); \ + my_temp = src >> 1; \ + if (reg_p & P_CARRY) { \ + my_temp |= 0x80; \ + } \ + LOCAL_SET_CARRY(src & 0x1); \ + ADC(my_temp, 0, 0); \ + STORE_ABS(my_tmp_addr, my_temp, 1); \ + } while (0) + +/* RTI does must not use `OPCODE_ENABLES_IRQ()' even if the I flag changes from 1 to 0 because the value of I is set 3 cycles before the end of the opcode, and thus the 6510 has enough time to call the interrupt routine as soon as the opcode ends, if necessary. */ - /* FIXME: Rotate disk before executing LOCAL_SET_STATUS(). */ -#define RTI() \ -do { \ -WORD tmp; \ -\ -CLK_ADD(CLK, CLK_RTI); \ -tmp = (WORD)PULL(); \ -LOCAL_SET_STATUS((BYTE)tmp); \ -tmp = (WORD)PULL(); \ -tmp |= (WORD)PULL() << 8; \ -JUMP(tmp); \ -} while (0) - +/* FIXME: Rotate disk before executing LOCAL_SET_STATUS(). */ +#define RTI() \ + do { \ + uint16_t tmp; \ + \ + CHECK_PROFILE_RTI(); \ + CLK_ADD(CLK, CLK_RTI); \ + LOAD_DUMMY(0x100 + reg_sp); \ + tmp = (uint16_t)PULL(); \ + LOCAL_SET_STATUS((uint8_t)tmp); \ + tmp = (uint16_t)PULL(); \ + tmp |= (uint16_t)PULL() << 8; \ + JUMP(tmp); \ + } while (0) + #define RTS() \ -do { \ -WORD tmp; \ -\ -CLK_ADD(CLK, CLK_RTS); \ -tmp = PULL(); \ -tmp = tmp | (PULL() << 8); \ -JUMP(tmp); \ -FETCH_PARAM(reg_pc); \ -CLK_ADD(CLK, CLK_INT_CYCLE); \ -INC_PC(1); \ -} while (0) - + do { \ + uint16_t tmp; \ + \ + CHECK_PROFILE_RTS(); \ + CLK_ADD(CLK, CLK_RTS); \ + LOAD_DUMMY(0x100 + reg_sp); \ + tmp = PULL(); \ + tmp = tmp | (PULL() << 8); \ + JUMP(tmp); \ + FETCH_PARAM(reg_pc); \ + CLK_ADD(CLK, CLK_INT_CYCLE); \ + INC_PC(1); \ + } while (0) + #define SAX(addr, clk_inc1, clk_inc2, pc_inc) \ do { \ unsigned int tmp; \ @@ -1931,36 +2229,36 @@ INC_PC(pc_inc); \ } while (0) #define SBC(value, clk_inc, pc_inc) \ -do { \ -WORD src, tmp; \ -\ -src = (WORD)(value); \ -CLK_ADD(CLK, (clk_inc)); \ -tmp = reg_a_read - src - ((reg_p & P_CARRY) ? 0 : 1); \ -if (reg_p & P_DECIMAL) { \ -unsigned int tmp_a; \ -tmp_a = (reg_a_read & 0xf) - (src & 0xf) - ((reg_p & P_CARRY) ? 0 : 1); \ -if (tmp_a & 0x10) { \ -tmp_a = ((tmp_a - 6) & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0) - 0x10); \ -} else { \ -tmp_a = (tmp_a & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0)); \ -} \ -if (tmp_a & 0x100) { \ -tmp_a -= 0x60; \ -} \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_NZ(tmp & 0xff); \ -LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ -reg_a_write((BYTE) tmp_a); \ -} else { \ -LOCAL_SET_NZ(tmp & 0xff); \ -LOCAL_SET_CARRY(tmp < 0x100); \ -LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ -reg_a_write((BYTE) tmp); \ -} \ -INC_PC(pc_inc); \ -} while (0) - + do { \ + uint16_t src, tmp; \ + \ + src = (uint16_t)(value); \ + CLK_ADD(CLK, (clk_inc)); \ + tmp = reg_a_read - src - ((reg_p & P_CARRY) ? 0 : 1); \ + if (reg_p & P_DECIMAL) { \ + unsigned int tmp_a; \ + tmp_a = (reg_a_read & 0xf) - (src & 0xf) - ((reg_p & P_CARRY) ? 0 : 1); \ + if (tmp_a & 0x10) { \ + tmp_a = ((tmp_a - 6) & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0) - 0x10); \ + } else { \ + tmp_a = (tmp_a & 0xf) | ((reg_a_read & 0xf0) - (src & 0xf0)); \ + } \ + if (tmp_a & 0x100) { \ + tmp_a -= 0x60; \ + } \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ + reg_a_write((uint8_t) tmp_a); \ + } else { \ + LOCAL_SET_NZ(tmp & 0xff); \ + LOCAL_SET_CARRY(tmp < 0x100); \ + LOCAL_SET_OVERFLOW(((reg_a_read ^ tmp) & 0x80) && ((reg_a_read ^ src) & 0x80)); \ + reg_a_write((uint8_t) tmp); \ + } \ + INC_PC(pc_inc); \ + } while (0) + #define SBX(value, pc_inc) \ do { \ unsigned int tmp; \ @@ -2005,24 +2303,24 @@ STORE_ABS_SH_Y(tmp, reg_a_read & reg_x_read & ((tmp >> 8) + 1), CLK_ABS_I_STORE2 } while (0) #define SHA_IND_Y(addr) \ -do { \ -unsigned int tmp; \ -BYTE val; \ -\ -CLK_ADD(CLK, 2); \ -tmp = LOAD_ZERO_ADDR(addr); \ -LOAD((tmp & 0xff00) | ((tmp + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_W); \ -val = reg_a_read & reg_x_read & ((tmp >> 8) + 1); \ -if ((tmp & 0xff) + reg_y_read > 0xff) { \ -tmp = ((tmp + reg_y_read) & 0xff) | (val << 8); \ -} else { \ -tmp += reg_y_read; \ -} \ -INC_PC(2); \ -STORE(tmp, val); \ -} while (0) - + do { \ + unsigned int tmp; \ + uint8_t val; \ + \ + tmp = LOAD_ZERO_ADDR(addr); \ + CLK_ADD(CLK, 2); \ + LOAD((tmp & 0xff00) | ((tmp + reg_y_read) & 0xff)); \ + CLK_ADD(CLK, CLK_IND_Y_W); \ + val = reg_a_read & reg_x_read & ((tmp >> 8) + 1); \ + if ((tmp & 0xff) + reg_y_read > 0xff) { \ + tmp = ((tmp + reg_y_read) & 0xff) | (val << 8); \ + } else { \ + tmp += reg_y_read; \ + } \ + INC_PC(2); \ + STORE(tmp, val); \ + } while (0) + #define SHX_ABS_Y(addr) \ do { \ unsigned int tmp; \ @@ -2042,98 +2340,102 @@ STORE_ABS_SH_X(tmp, reg_y_read & ((tmp >> 8) + 1), CLK_ABS_I_STORE2); \ } while (0) #define SHS_ABS_Y(addr) \ -do { \ -int tmp = (addr); \ -\ -INC_PC(3); \ -STORE_ABS_SH_Y(tmp, reg_a_read & reg_x_read & ((tmp >> 8) + 1), CLK_ABS_I_STORE2); \ -reg_sp = reg_a_read & reg_x_read; \ -} while (0) - -#define SLO(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -BYTE tmp, tmp2; \ -int tmp_addr; \ -\ -CLK_ADD(CLK, (clk_inc1)); \ -tmp_addr = (addr); \ -tmp = load_func(tmp_addr); \ -LOCAL_SET_CARRY(tmp & 0x80); \ -tmp <<= 1; \ -tmp2 = reg_a_read | tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, clk_inc2); \ -RMW_FLAG = 0; \ -} while (0) - -#define SLO_IND_Y(addr) \ -do { \ -BYTE tmp, tmp2; \ -unsigned int tmp_addr; \ -\ -CLK_ADD(CLK, 2); \ -tmp_addr = LOAD_ZERO_ADDR(addr); \ -LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -tmp_addr += reg_y_read; \ -tmp = LOAD(tmp_addr); \ -LOCAL_SET_CARRY(tmp & 0x80); \ -tmp <<= 1; \ -tmp2 = reg_a_read | tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -STORE_ABS(tmp_addr, tmp, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - -#define SRE(addr, clk_inc1, clk_inc2, pc_inc, load_func, store_func) \ -do { \ -unsigned int tmp, tmp2; \ -unsigned int tmp_addr; \ -\ -CLK_ADD(CLK, (clk_inc1)); \ -tmp_addr = (addr); \ -tmp = load_func(tmp_addr); \ -LOCAL_SET_CARRY(tmp & 0x01); \ -tmp >>= 1; \ -tmp2 = reg_a_read ^ tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(pc_inc); \ -store_func(tmp_addr, tmp, clk_inc2); \ -RMW_FLAG = 0; \ -} while (0) - -#define SRE_IND_Y(addr) \ -do { \ -unsigned int tmp, tmp2; \ -unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ -\ -CLK_ADD(CLK, 2); \ -LOAD((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_RMW1); \ -tmp_addr += reg_y_read; \ -tmp = LOAD(tmp_addr); \ -LOCAL_SET_CARRY(tmp & 0x01); \ -tmp >>= 1; \ -tmp2 = reg_a_read ^ tmp; \ -reg_a_write(tmp2); \ -LOCAL_SET_NZ(tmp2); \ -RMW_FLAG = 1; \ -INC_PC(2); \ -STORE_ABS(tmp_addr, tmp, CLK_IND_Y_RMW2); \ -RMW_FLAG = 0; \ -} while (0) - -#define STA(addr, clk_inc1, clk_inc2, pc_inc, store_func) \ -do { \ -unsigned int tmp; \ + do { \ + int tmp = (addr); \ + \ + INC_PC(3); \ + STORE_ABS_SH_Y(tmp, reg_a_read & reg_x_read & ((tmp >> 8) + 1), CLK_ABS_I_STORE2); \ + reg_sp = reg_a_read & reg_x_read; \ + } while (0) + +#define SLO(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + uint8_t tmp, tmp2; \ + int tmp_addr; \ + \ + tmp_addr = (addr); \ + CLK_ADD(CLK, (clk_inc1)); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + LOCAL_SET_CARRY(tmp & 0x80); \ + tmp <<= 1; \ + tmp2 = reg_a_read | tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + +#define SLO_IND_Y(addr) \ + do { \ + uint8_t tmp, tmp2; \ + unsigned int tmp_addr; \ + \ + tmp_addr = LOAD_ZERO_ADDR(addr); \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + tmp_addr += reg_y_read; \ + tmp = LOAD(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(tmp_addr, tmp); \ + LOCAL_SET_CARRY(tmp & 0x80); \ + tmp <<= 1; \ + tmp2 = reg_a_read | tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(2); \ + STORE_ABS(tmp_addr, tmp, 1); \ + } while (0) + +#define SRE(addr, clk_inc1, pc_inc, load_func, store_func, dummy_func) \ + do { \ + unsigned int tmp, tmp2; \ + unsigned int tmp_addr; \ + \ + tmp_addr = (addr); \ + CLK_ADD(CLK, (clk_inc1)); \ + tmp = load_func(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + dummy_func(tmp_addr, tmp); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + tmp >>= 1; \ + tmp2 = reg_a_read ^ tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(pc_inc); \ + store_func(tmp_addr, tmp, 1); \ + } while (0) + +#define SRE_IND_Y(addr) \ + do { \ + unsigned int tmp, tmp2; \ + unsigned int tmp_addr = LOAD_ZERO_ADDR(addr); \ + \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((tmp_addr & 0xff00) | ((tmp_addr + reg_y_read) & 0xff)); \ + CLK_ADD_DUMMY(CLK, 1); \ + tmp_addr += reg_y_read; \ + tmp = LOAD(tmp_addr); \ + CLK_ADD(CLK, 1); \ + CLK_ADD_DUMMY(CLK, 1); \ + DUMMY_STORE_ABS_RMW(tmp_addr, tmp); \ + LOCAL_SET_CARRY(tmp & 0x01); \ + tmp >>= 1; \ + tmp2 = reg_a_read ^ tmp; \ + reg_a_write(tmp2); \ + LOCAL_SET_NZ(tmp2); \ + INC_PC(2); \ + STORE_ABS(tmp_addr, tmp, 1); \ + } while (0) + +#define STA(addr, clk_inc1, clk_inc2, pc_inc, store_func) \ +do { \ +unsigned int tmp; \ \ CLK_ADD(CLK, (clk_inc1)); \ tmp = (addr); \ @@ -2149,17 +2451,17 @@ INC_PC(pc_inc); \ } while (0) #define STA_IND_Y(addr) \ -do { \ -unsigned int tmp; \ -\ -CLK_ADD(CLK, 2); \ -tmp = LOAD_ZERO_ADDR(addr); \ -LOAD_IND((tmp & 0xff00) | ((tmp + reg_y_read) & 0xff)); \ -CLK_ADD(CLK, CLK_IND_Y_W); \ -INC_PC(2); \ -STORE_IND(tmp + reg_y_read, reg_a_read); \ -} while (0) - + do { \ + unsigned int tmp; \ + \ + tmp = LOAD_ZERO_ADDR(addr); \ + CLK_ADD(CLK, 2); \ + LOAD_DUMMY((tmp & 0xff00) | ((tmp + reg_y_read) & 0xff)); \ + CLK_ADD(CLK, CLK_IND_Y_W); \ + INC_PC(2); \ + STORE_IND(tmp + reg_y_read, reg_a_read); \ + } while (0) + #define STX(addr, clk_inc, pc_inc) \ do { \ unsigned int tmp; \ @@ -2229,108 +2531,108 @@ INC_PC(1); \ } while (0) #define TYA() \ -do { \ -reg_a_write(reg_y_read); \ -LOCAL_SET_NZ(reg_y_read); \ -INC_PC(1); \ -} while (0) - - - /* ------------------------------------------------------------------------- */ - - static const BYTE fetch_tab[] = { - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* $00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $00 */ - /* $10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $10 */ - /* $20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $20 */ - /* $30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $30 */ - /* $40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $40 */ - /* $50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $50 */ - /* $60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $60 */ - /* $70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $70 */ - /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $80 */ - /* $90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $90 */ - /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $A0 */ - /* $B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $B0 */ - /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $C0 */ - /* $D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $D0 */ - /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $E0 */ - /* $F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 /* $F0 */ - }; - + do { \ + reg_a_write(reg_y_read); \ + LOCAL_SET_NZ(reg_y_read); \ + INC_PC(1); \ + } while (0) + + +/* ------------------------------------------------------------------------- */ + +static const uint8_t fetch_tab[] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* $00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $00 */ + /* $10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $10 */ + /* $20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $20 */ + /* $30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $30 */ + /* $40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $40 */ + /* $50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $50 */ + /* $60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $60 */ + /* $70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $70 */ + /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $80 */ + /* $90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $90 */ + /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $A0 */ + /* $B0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $B0 */ + /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $C0 */ + /* $D0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, /* $D0 */ + /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* $E0 */ + /* $F0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 /* $F0 */ +}; + #ifndef C64DTV /* C64DTV opcode_t & fetch are defined in c64dtvcpu.c */ #ifdef CPU_8502 /* 8502 specific opcode fetch */ - - static const BYTE rewind_fetch_tab[] = { - /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* $00 */ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $00 */ - /* $10 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $10 */ - /* $20 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $20 */ - /* $30 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $30 */ - /* $40 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $40 */ - /* $50 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $50 */ - /* $60 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $60 */ - /* $70 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $70 */ - /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $80 */ - /* $90 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $90 */ - /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $A0 */ - /* $B0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $B0 */ - /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $C0 */ - /* $D0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $D0 */ - /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $E0 */ - /* $F0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $F0 */ - }; - + +static const uint8_t rewind_fetch_tab[] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* $00 */ 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $00 */ + /* $10 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $10 */ + /* $20 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $20 */ + /* $30 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $30 */ + /* $40 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $40 */ + /* $50 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $50 */ + /* $60 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $60 */ + /* $70 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $70 */ + /* $80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $80 */ + /* $90 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $90 */ + /* $A0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $A0 */ + /* $B0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $B0 */ + /* $C0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $C0 */ + /* $D0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $D0 */ + /* $E0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $E0 */ + /* $F0 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* $F0 */ +}; + #if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS - -#define opcode_t DWORD - + +#define opcode_t uint32_t + #define FETCH_OPCODE(o) \ -do { \ -if (((int)reg_pc) < bank_limit) { \ -o = (*((DWORD *)(bank_base + reg_pc)) & 0xffffff); \ -if (rewind_fetch_tab[o & 0xff]) { \ -opcode_cycle[0] = vicii_check_memory_refresh(CLK); \ -CLK_ADD(CLK, 1); \ -opcode_cycle[1] = vicii_check_memory_refresh(CLK); \ -CLK_ADD(CLK, 1); \ -} else { \ -opcode_cycle[0] = 0; \ -opcode_cycle[1] = 0; \ -CLK_ADD(CLK, 2); \ -} \ -if (fetch_tab[o & 0xff]) { \ -CLK_ADD(CLK, 1); \ -} \ -} else { \ -maincpu_stretch = 0; \ -o = LOAD(reg_pc); \ -if (rewind_fetch_tab[o & 0xff]) { \ -opcode_cycle[0] = maincpu_stretch; \ -if (opcode_cycle[0] == 0) { \ -opcode_cycle[0] = vicii_check_memory_refresh(CLK); \ -} \ -CLK_ADD(CLK, 1); \ -maincpu_stretch = 0; \ -o |= LOAD(reg_pc + 1) << 8; \ -opcode_cycle[1] = maincpu_stretch; \ -if (opcode_cycle[1] == 0) { \ -opcode_cycle[1] = vicii_check_memory_refresh(CLK); \ -} \ -CLK_ADD(CLK, 1); \ -} else { \ -CLK_ADD(CLK, 1); \ -o |= LOAD(reg_pc + 1) << 8; \ -CLK_ADD(CLK, 1); \ -} \ -if (fetch_tab[o & 0xff]) { \ -o |= (LOAD(reg_pc + 2) << 16); \ -CLK_ADD(CLK, 1); \ -} \ -} \ -} while (0) - + do { \ + if (((int)reg_pc) < bank_limit) { \ + o = (*((uint32_t *)(bank_base + reg_pc)) & 0xffffff); \ + if (rewind_fetch_tab[o & 0xff]) { \ + opcode_cycle[0] = vicii_check_memory_refresh(CLK); \ + CLK_ADD(CLK, 1); \ + opcode_cycle[1] = vicii_check_memory_refresh(CLK); \ + CLK_ADD(CLK, 1); \ + } else { \ + opcode_cycle[0] = 0; \ + opcode_cycle[1] = 0; \ + CLK_ADD(CLK, 2); \ + } \ + if (fetch_tab[o & 0xff]) { \ + CLK_ADD(CLK, 1); \ + } \ + } else { \ + maincpu_stretch = 0; \ + o = LOAD(reg_pc); \ + if (rewind_fetch_tab[o & 0xff]) { \ + opcode_cycle[0] = maincpu_stretch; \ + if (opcode_cycle[0] == 0) { \ + opcode_cycle[0] = vicii_check_memory_refresh(CLK); \ + } \ + CLK_ADD(CLK, 1); \ + maincpu_stretch = 0; \ + o |= LOAD(reg_pc + 1) << 8; \ + opcode_cycle[1] = maincpu_stretch; \ + if (opcode_cycle[1] == 0) { \ + opcode_cycle[1] = vicii_check_memory_refresh(CLK); \ + } \ + CLK_ADD(CLK, 1); \ + } else { \ + CLK_ADD(CLK, 1); \ + o |= LOAD(reg_pc + 1) << 8; \ + CLK_ADD(CLK, 1); \ + } \ + if (fetch_tab[o & 0xff]) { \ + o |= (LOAD(reg_pc + 2) << 16); \ + CLK_ADD(CLK, 1); \ + } \ + } \ + } while (0) + #define p0 (opcode & 0xff) #define p1 ((opcode >> 8) & 0xff) #define p2 (opcode >> 8) @@ -2338,14 +2640,14 @@ CLK_ADD(CLK, 1); \ #else /* WORDS_BIGENDIAN || !ALLOW_UNALIGNED_ACCESS */ #define opcode_t \ -struct { \ -BYTE ins; \ -union { \ -BYTE op8[2]; \ -WORD op16; \ -} op; \ -} - + struct { \ + uint8_t ins; \ + union { \ + uint8_t op8[2]; \ + uint16_t op16; \ + } op; \ + } + #define FETCH_OPCODE(o) \ do { \ if (((int)reg_pc) < bank_limit) { \ @@ -2406,40 +2708,40 @@ CLK_ADD(CLK, 1); \ #else /* !CPU_8502 */ #if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS - -#define opcode_t DWORD - + +#define opcode_t uint32_t + #define FETCH_OPCODE(o) \ -do { \ -if (((int)reg_pc) < bank_limit) { \ -o = (*((DWORD *)(bank_base + reg_pc)) & 0xffffff); \ -CLK_ADD(CLK, 2); \ -if (fetch_tab[o & 0xff]) { \ -CLK_ADD(CLK, 1); \ -} \ -} else { \ -o = LOAD(reg_pc); \ -CLK_ADD(CLK, 1); \ -o |= LOAD(reg_pc + 1) << 8; \ -CLK_ADD(CLK, 1); \ -if (fetch_tab[o & 0xff]) { \ -o |= (LOAD(reg_pc + 2) << 16); \ -CLK_ADD(CLK, 1); \ -} \ -} \ -} while (0) + do { \ + if (((int)reg_pc) < bank_limit) { \ + o = (*((uint32_t *)(bank_base + reg_pc)) & 0xffffff); \ + CLK_ADD(CLK, 2); \ + if (fetch_tab[o & 0xff]) { \ + CLK_ADD(CLK, 1); \ + } \ + } else { \ + o = LOAD(reg_pc); \ + CLK_ADD(CLK, 1); \ + o |= LOAD(reg_pc + 1) << 8; \ + CLK_ADD(CLK, 1); \ + if (fetch_tab[o & 0xff]) { \ + o |= (LOAD(reg_pc + 2) << 16); \ + CLK_ADD(CLK, 1); \ + } \ + } \ + } while (0) -#define C64D_FETCH_OPCODE_LOAD(o) \ -do { \ -o = LOAD(reg_pc); \ -CLK_ADD(CLK,1); \ -o |= LOAD(reg_pc + 1) << 8; \ -CLK_ADD(CLK,1); \ -if (fetch_tab[o & 0xff]) { \ -o |= (LOAD(reg_pc + 2) << 16); \ -CLK_ADD(CLK,1); \ -} \ -} while (0) +#define C64D_FETCH_OPCODE_LOAD(o) \ + do { \ + o = LOAD(reg_pc); \ + CLK_ADD(CLK,1); \ + o |= LOAD(reg_pc + 1) << 8; \ + CLK_ADD(CLK,1); \ + if (fetch_tab[o & 0xff]) { \ + o |= (LOAD(reg_pc + 2) << 16); \ + CLK_ADD(CLK,1); \ + } \ + } while (0) #define p0 (opcode & 0xff) #define p1 ((opcode >> 8) & 0xff) @@ -2448,14 +2750,14 @@ CLK_ADD(CLK,1); \ #else /* WORDS_BIGENDIAN || !ALLOW_UNALIGNED_ACCESS */ #define opcode_t \ -struct { \ -BYTE ins; \ -union { \ -BYTE op8[2]; \ -WORD op16; \ -} op; \ -} - + struct { \ + uint8_t ins; \ + union { \ + uint8_t op8[2]; \ + uint16_t op16; \ + } op; \ + } + #define FETCH_OPCODE(o) \ do { \ if (((int)reg_pc) < bank_limit) { \ @@ -2471,1226 +2773,1304 @@ CLK_ADD(CLK, 1); \ (o).op.op16 = LOAD(reg_pc + 1); \ CLK_ADD(CLK, 1); \ if (fetch_tab[(o).ins]) { \ -(o).op.op16 |= (LOAD(reg_pc + 2) << 8); \ -CLK_ADD(CLK, 1); \ -} \ -} \ -} while (0) - -#define C64D_FETCH_OPCODE_LOAD(o) \ -do { \ -(o).ins = LOAD(reg_pc); \ -CLK_ADD(CLK,1); \ -(o).op.op16 = LOAD(reg_pc + 1); \ -CLK_ADD(CLK,1); \ -if (fetch_tab[(o).ins]) { \ -(o).op.op16 |= (LOAD(reg_pc + 2) << 8); \ -CLK_ADD(CLK,1); \ -} \ -} while (0) - -#define p0 (opcode.ins) -#define p2 (opcode.op.op16) - -#ifdef WORDS_BIGENDIAN -# define p1 (opcode.op.op8[1]) -#else -# define p1 (opcode.op.op8[0]) -#endif - -#endif /* !WORDS_BIGENDIAN */ -#endif - - /* SET_OPCODE for traps */ -#if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS -#define SET_OPCODE(o) (opcode) = o -#else -#if !defined WORDS_BIGENDIAN -#define SET_OPCODE(o) \ -do { \ -opcode.ins = (o) & 0xff; \ -opcode.op.op8[0] = ((o) >> 8) & 0xff; \ -opcode.op.op8[1] = ((o) >> 16) & 0xff; \ -} while (0) -#else -#define SET_OPCODE(o) \ -do { \ -opcode.ins = (o) & 0xff; \ -opcode.op.op8[1] = ((o) >> 8) & 0xff; \ -opcode.op.op8[0] = ((o) >> 16) & 0xff; \ -} while (0) -#endif - -#endif - -#endif /* !C64DTV */ - - /* ------------------------------------------------------------------------ */ - - /* Here, the CPU is emulated. */ - - { -// LOGD("drive pc=%4.4x", reg_pc); - - /* handle 8502 fast mode refresh cycles */ - CPU_REFRESH_CLK - - /* handle any extra cpu switches */ -#ifdef CHECK_AND_RUN_ALTERNATE_CPU - CHECK_AND_RUN_ALTERNATE_CPU -#endif - - CPU_DELAY_CLK - - PROCESS_ALARMS - - { - enum cpu_int pending_interrupt; - - if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) - && (CPU_INT_STATUS->global_pending_int & IK_IRQPEND) - && CPU_INT_STATUS->irq_pending_clk <= CLK) { - interrupt_ack_irq(CPU_INT_STATUS); - } - - pending_interrupt = CPU_INT_STATUS->global_pending_int; - if (pending_interrupt != IK_NONE) - { - DO_INTERRUPT(pending_interrupt); - - // c64 debugger - check interrupt breakpoints when irq is ack'ed - if ((pending_interrupt & IK_IRQ) && ((reg_p & P_INTERRUPT) == P_INTERRUPT)) - { - if (c64d_drive1541_is_checking_irq_breakpoints_enabled() == 1) - { - if (drive_context[0]->via1d1541->c64d_irq_flagged == 1) - { - drive_context[0]->via1d1541->c64d_irq_flagged = 0; - c64d_drive1541_check_irqvia1_breakpoint(); - } - else if (drive_context[0]->via2->c64d_irq_flagged == 1) - { - drive_context[0]->via2->c64d_irq_flagged = 0; - c64d_drive1541_check_irqvia2_breakpoint(); - } - else - { - // must be IEC? // TODO: confirm this - c64d_drive1541_check_irqiec_breakpoint(); - } - } - } - // - - if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) - && CPU_INT_STATUS->global_pending_int & IK_IRQPEND) { - CPU_INT_STATUS->global_pending_int &= ~IK_IRQPEND; - } - CPU_DELAY_CLK - - PROCESS_ALARMS - } - } - - // c64d - if (_c64d_new_drive_pc == -1) - { - viceCurrentDiskPC[0] = reg_pc; - } - else - { - viceCurrentDiskPC[0] = _c64d_new_drive_pc; - cpu->cpu_regs.pc = _c64d_new_drive_pc; - reg_pc = _c64d_new_drive_pc; - } - // - - { - if (c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_INSTRUCTION - && c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_CYCLE) - { - // c64d check PC breakpoint after IRQ or trap - c64d_drive1541_check_pc_breakpoint(reg_pc); - viceCurrentDiskPC[0] = reg_pc; - c64d_debug_pause_check(0); - } - } - - { - opcode_t opcode; -#ifdef VICE_DEBUG - CLOCK debug_clk; -#ifdef DRIVE_CPU - debug_clk = CLK; -#else - debug_clk = maincpu_clk; -#endif -#endif - -#ifdef FEATURE_CPUMEMHISTORY -#ifndef DRIVE_CPU - memmap_state |= (MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); -#endif -#endif - SET_LAST_ADDR(reg_pc); - - - // c64d: TODO: forcing reg_pc does not work with FETCH_OPCODE due to bank_base mismatch. how to fix this? - -// if (_c64d_new_drive_pc == -1) -// { -// FETCH_OPCODE(opcode); -// } -// else - { - C64D_FETCH_OPCODE_LOAD(opcode); - - _c64d_new_drive_pc = -1; - } - - - -#ifdef FEATURE_CPUMEMHISTORY -#ifndef DRIVE_CPU -#ifndef C64DTV - /* HACK to cope with FETCH_OPCODE optimization in x64 */ - if (((int)reg_pc) < bank_limit) { - memmap_mark_read(reg_pc); - } -#endif - if (p0 == 0x20) { - monitor_cpuhistory_store(reg_pc, p0, p1, LOAD(reg_pc + 2), reg_a_read, reg_x_read, reg_y_read, reg_sp, LOCAL_STATUS()); - } else { - monitor_cpuhistory_store(reg_pc, p0, p1, p2 >> 8, reg_a_read, reg_x_read, reg_y_read, reg_sp, LOCAL_STATUS()); - } - memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); -#endif -#endif - -#ifdef VICE_DEBUG -#ifdef DRIVE_CPU - if (TRACEFLG) { - BYTE op = (BYTE)(p0); - BYTE lo = (BYTE)(p1); - BYTE hi = (BYTE)(p2 >> 8); - - debug_drive((DWORD)(reg_pc), debug_clk, - mon_disassemble_to_string(e_disk8_space, - reg_pc, op, - lo, hi, 0, 1, "6502"), - reg_a_read, reg_x_read, reg_y_read, reg_sp, drv->mynumber + 8); - } -#else - if (TRACEFLG) { - BYTE op = (BYTE)(p0); - BYTE lo = (BYTE)(p1); - BYTE hi = (BYTE)(p2 >> 8); - - if (op == 0x20) { - hi = LOAD(reg_pc + 2); - } - - debug_maincpu((DWORD)(reg_pc), debug_clk, - mon_disassemble_to_string(e_comp_space, - reg_pc, op, - lo, hi, 0, 1, "6502"), - reg_a_read, reg_x_read, reg_y_read, reg_sp); - } - if (debug.perform_break_into_monitor) { - monitor_startup_trap(); - debug.perform_break_into_monitor = 0; - } -#endif -#endif - - trap_skipped: - SET_LAST_OPCODE(p0); - - switch (p0) { - case 0x00: /* BRK */ - BRK(); - break; - - case 0x01: /* ORA ($nn,X) */ - ORA(LOAD_IND_X(p1), 1, 2); - break; - - case 0x02: /* JAM - also used for traps */ - STATIC_ASSERT(TRAP_OPCODE == 0x02); - JAM_02(); - break; - - case 0x22: /* JAM */ - case 0x52: /* JAM */ - case 0x62: /* JAM */ - case 0x72: /* JAM */ - case 0x92: /* JAM */ - case 0xb2: /* JAM */ - case 0xd2: /* JAM */ - case 0xf2: /* JAM */ -#ifndef C64DTV - case 0x12: /* JAM */ - case 0x32: /* JAM */ - case 0x42: /* JAM */ -#endif - REWIND_FETCH_OPCODE(CLK); - JAM(); - break; - -#ifdef C64DTV - /* These opcodes are defined in c64/c64dtvcpu.c */ - case 0x12: /* BRA */ - BRANCH(1, p1); - break; - - case 0x32: /* SAC */ - SAC(p1); - break; - - case 0x42: /* SIR */ - SIR(p1); - break; -#endif - - case 0x03: /* SLO ($nn,X) */ - SLO(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0x04: /* NOOP $nn */ - case 0x44: /* NOOP $nn */ - case 0x64: /* NOOP $nn */ - NOOP(1, 2); - break; - - case 0x05: /* ORA $nn */ - ORA(LOAD_ZERO(p1), 1, 2); - break; - - case 0x06: /* ASL $nn */ - ASL(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x07: /* SLO $nn */ - SLO(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x08: /* PHP */ -#ifdef DRIVE_CPU - drivecpu_rotate(); - if (drivecpu_byte_ready()) { - drivecpu_byte_ready_egde_clear(); - LOCAL_SET_OVERFLOW(1); - } -#endif - PHP(); - break; - - case 0x09: /* ORA #$nn */ - ORA(p1, 0, 2); - break; - - case 0x0a: /* ASL A */ - ASL_A(); - break; - - case 0x0b: /* ANC #$nn */ - ANC(p1, 2); - break; - - case 0x0c: /* NOOP $nnnn */ - NOOP_ABS(); - break; - - case 0x0d: /* ORA $nnnn */ - ORA(LOAD(p2), 1, 3); - break; - - case 0x0e: /* ASL $nnnn */ - ASL(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x0f: /* SLO $nnnn */ - SLO(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x10: /* BPL $nnnn */ - BRANCH(!LOCAL_SIGN(), p1); - break; - - case 0x11: /* ORA ($nn),Y */ - ORA(LOAD_IND_Y(p1), 1, 2); - break; - - case 0x13: /* SLO ($nn),Y */ - SLO_IND_Y(p1); - break; - - case 0x14: /* NOOP $nn,X */ - case 0x34: /* NOOP $nn,X */ - case 0x54: /* NOOP $nn,X */ - case 0x74: /* NOOP $nn,X */ - case 0xd4: /* NOOP $nn,X */ - case 0xf4: /* NOOP $nn,X */ - NOOP(CLK_NOOP_ZERO_X, 2); - break; - - case 0x15: /* ORA $nn,X */ - ORA(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0x16: /* ASL $nn,X */ - ASL((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x17: /* SLO $nn,X */ - SLO((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x18: /* CLC */ - CLC(); - break; - - case 0x19: /* ORA $nnnn,Y */ - ORA(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0x1a: /* NOOP */ - case 0x3a: /* NOOP */ - case 0x5a: /* NOOP */ - case 0x7a: /* NOOP */ - case 0xda: /* NOOP */ - case 0xfa: /* NOOP */ - NOOP_IMM(1); - break; - - case 0x1b: /* SLO $nnnn,Y */ - SLO(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); - break; - - case 0x1c: /* NOOP $nnnn,X */ - case 0x3c: /* NOOP $nnnn,X */ - case 0x5c: /* NOOP $nnnn,X */ - case 0x7c: /* NOOP $nnnn,X */ - case 0xdc: /* NOOP $nnnn,X */ - case 0xfc: /* NOOP $nnnn,X */ - NOOP_ABS_X(); - break; - - case 0x1d: /* ORA $nnnn,X */ - ORA(LOAD_ABS_X(p2), 1, 3); - break; - - case 0x1e: /* ASL $nnnn,X */ - ASL(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x1f: /* SLO $nnnn,X */ - SLO(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x20: /* JSR $nnnn */ - JSR(); - break; - - case 0x21: /* AND ($nn,X) */ - AND(LOAD_IND_X(p1), 1, 2); - break; - - case 0x23: /* RLA ($nn,X) */ - RLA(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0x24: /* BIT $nn */ - BIT(LOAD_ZERO(p1), 2); - break; - - case 0x25: /* AND $nn */ - AND(LOAD_ZERO(p1), 1, 2); - break; - - case 0x26: /* ROL $nn */ - ROL(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x27: /* RLA $nn */ - RLA(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x28: /* PLP */ - PLP(); - break; - - case 0x29: /* AND #$nn */ - AND(p1, 0, 2); - break; - - case 0x2a: /* ROL A */ - ROL_A(); - break; - - case 0x2b: /* ANC #$nn */ - ANC(p1, 2); - break; - - case 0x2c: /* BIT $nnnn */ - BIT(LOAD(p2), 3); - break; - - case 0x2d: /* AND $nnnn */ - AND(LOAD(p2), 1, 3); - break; - - case 0x2e: /* ROL $nnnn */ - ROL(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x2f: /* RLA $nnnn */ - RLA(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x30: /* BMI $nnnn */ - BRANCH(LOCAL_SIGN(), p1); - break; - - case 0x31: /* AND ($nn),Y */ - AND(LOAD_IND_Y(p1), 1, 2); - break; - - case 0x33: /* RLA ($nn),Y */ - RLA_IND_Y(p1); - break; - - case 0x35: /* AND $nn,X */ - AND(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0x36: /* ROL $nn,X */ - ROL((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x37: /* RLA $nn,X */ - RLA((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x38: /* SEC */ - SEC(); - break; - - case 0x39: /* AND $nnnn,Y */ - AND(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0x3b: /* RLA $nnnn,Y */ - RLA(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); - break; - - case 0x3d: /* AND $nnnn,X */ - AND(LOAD_ABS_X(p2), 1, 3); - break; - - case 0x3e: /* ROL $nnnn,X */ - ROL(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x3f: /* RLA $nnnn,X */ - RLA(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x40: /* RTI */ - RTI(); - break; - - case 0x41: /* EOR ($nn,X) */ - EOR(LOAD_IND_X(p1), 1, 2); - break; - - case 0x43: /* SRE ($nn,X) */ - SRE(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0x45: /* EOR $nn */ - EOR(LOAD_ZERO(p1), 1, 2); - break; - - case 0x46: /* LSR $nn */ - LSR(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x47: /* SRE $nn */ - SRE(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x48: /* PHA */ - PHA(); - break; - - case 0x49: /* EOR #$nn */ - EOR(p1, 0, 2); - break; - - case 0x4a: /* LSR A */ - LSR_A(); - break; - - case 0x4b: /* ASR #$nn */ - ASR(p1, 2); - break; - - case 0x4c: /* JMP $nnnn */ - JMP(p2); - break; - - case 0x4d: /* EOR $nnnn */ - EOR(LOAD(p2), 1, 3); - break; - - case 0x4e: /* LSR $nnnn */ - LSR(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x4f: /* SRE $nnnn */ - SRE(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x50: /* BVC $nnnn */ -#ifdef DRIVE_CPU - CLK_ADD(CLK, -1); - drivecpu_rotate(); - if (drivecpu_byte_ready()) { - drivecpu_byte_ready_egde_clear(); - LOCAL_SET_OVERFLOW(1); - } - CLK_ADD(CLK, 1); -#endif - BRANCH(!LOCAL_OVERFLOW(), p1); - break; - - case 0x51: /* EOR ($nn),Y */ - EOR(LOAD_IND_Y(p1), 1, 2); - break; - - case 0x53: /* SRE ($nn),Y */ - SRE_IND_Y(p1); - break; - - case 0x55: /* EOR $nn,X */ - EOR(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0x56: /* LSR $nn,X */ - LSR((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x57: /* SRE $nn,X */ - SRE((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x58: /* CLI */ - CLI(); - break; - - case 0x59: /* EOR $nnnn,Y */ - EOR(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0x5b: /* SRE $nnnn,Y */ - SRE(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); - break; - - case 0x5d: /* EOR $nnnn,X */ - EOR(LOAD_ABS_X(p2), 1, 3); - break; - - case 0x5e: /* LSR $nnnn,X */ - LSR(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x5f: /* SRE $nnnn,X */ - SRE(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x60: /* RTS */ - RTS(); - break; - - case 0x61: /* ADC ($nn,X) */ - ADC(LOAD_IND_X(p1), 1, 2); - break; - - case 0x63: /* RRA ($nn,X) */ - RRA(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0x65: /* ADC $nn */ - ADC(LOAD_ZERO(p1), 1, 2); - break; - - case 0x66: /* ROR $nn */ - ROR(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x67: /* RRA $nn */ - RRA(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x68: /* PLA */ - PLA(); - break; - - case 0x69: /* ADC #$nn */ - ADC(p1, 0, 2); - break; - - case 0x6a: /* ROR A */ - ROR_A(); - break; - - case 0x6b: /* ARR #$nn */ - ARR(p1, 2); - break; - - case 0x6c: /* JMP ($nnnn) */ - JMP_IND(); - break; - - case 0x6d: /* ADC $nnnn */ - ADC(LOAD(p2), 1, 3); - break; - - case 0x6e: /* ROR $nnnn */ - ROR(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x6f: /* RRA $nnnn */ - RRA(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0x70: /* BVS $nnnn */ -#ifdef DRIVE_CPU - CLK_ADD(CLK, -1); - drivecpu_rotate(); - if (drivecpu_byte_ready()) { - drivecpu_byte_ready_egde_clear(); - LOCAL_SET_OVERFLOW(1); - } - CLK_ADD(CLK, 1); -#endif - BRANCH(LOCAL_OVERFLOW(), p1); - break; - - case 0x71: /* ADC ($nn),Y */ - ADC(LOAD_IND_Y(p1), 1, 2); - break; - - case 0x73: /* RRA ($nn),Y */ - RRA_IND_Y(p1); - break; - - case 0x75: /* ADC $nn,X */ - ADC(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0x76: /* ROR $nn,X */ - ROR((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x77: /* RRA $nn,X */ - RRA((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0x78: /* SEI */ - SEI(); - break; - - case 0x79: /* ADC $nnnn,Y */ - ADC(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0x7b: /* RRA $nnnn,Y */ - RRA(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); - break; - - case 0x7d: /* ADC $nnnn,X */ - ADC(LOAD_ABS_X(p2), 1, 3); - break; - - case 0x7e: /* ROR $nnnn,X */ - ROR(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x7f: /* RRA $nnnn,X */ - RRA(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0x80: /* NOOP #$nn */ - case 0x82: /* NOOP #$nn */ - case 0x89: /* NOOP #$nn */ - case 0xc2: /* NOOP #$nn */ - case 0xe2: /* NOOP #$nn */ - NOOP_IMM(2); - break; - - case 0x81: /* STA ($nn,X) */ - STA(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, 1, 2, STORE_ABS); - break; - - case 0x83: /* SAX ($nn,X) */ - SAX(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, 1, 2); - break; - - case 0x84: /* STY $nn */ - STY_ZERO(p1, 1, 2); - break; - - case 0x85: /* STA $nn */ - STA_ZERO(p1, 1, 2); - break; - - case 0x86: /* STX $nn */ - STX_ZERO(p1, 1, 2); - break; - - case 0x87: /* SAX $nn */ - SAX_ZERO(p1, 1, 2); - break; - - case 0x88: /* DEY */ - DEY(); - break; - - case 0x8a: /* TXA */ - TXA(); - break; - - case 0x8b: /* ANE #$nn */ - ANE(p1, 2); - break; - - case 0x8c: /* STY $nnnn */ - STY(p2, 1, 3); - break; - - case 0x8d: /* STA $nnnn */ - STA(p2, 0, 1, 3, STORE_ABS); - break; - - case 0x8e: /* STX $nnnn */ - STX(p2, 1, 3); - break; - - case 0x8f: /* SAX $nnnn */ - SAX(p2, 0, 1, 3); - break; - - case 0x90: /* BCC $nnnn */ - BRANCH(!LOCAL_CARRY(), p1); - break; - - case 0x91: /* STA ($nn),Y */ - STA_IND_Y(p1); - break; - - case 0x93: /* SHA ($nn),Y */ - SHA_IND_Y(p1); - break; - - case 0x94: /* STY $nn,X */ - STY_ZERO(p1 + reg_x_read, CLK_ZERO_I_STORE, 2); - break; - - case 0x95: /* STA $nn,X */ - STA_ZERO(p1 + reg_x_read, CLK_ZERO_I_STORE, 2); - break; - - case 0x96: /* STX $nn,Y */ - STX_ZERO(p1 + reg_y_read, CLK_ZERO_I_STORE, 2); - break; - - case 0x97: /* SAX $nn,Y */ - SAX((p1 + reg_y_read) & 0xff, 0, CLK_ZERO_I_STORE, 2); - break; - - case 0x98: /* TYA */ - TYA(); - break; - - case 0x99: /* STA $nnnn,Y */ - STA(p2, 0, CLK_ABS_I_STORE2, 3, STORE_ABS_Y); - break; - - case 0x9a: /* TXS */ - TXS(); - break; - - case 0x9b: /* SHS $nnnn,Y */ -#ifdef C64DTV - NOOP_ABS_Y(); -#else - SHS_ABS_Y(p2); -#endif - break; - - case 0x9c: /* SHY $nnnn,X */ - SHY_ABS_X(p2); - break; - - case 0x9d: /* STA $nnnn,X */ - STA(p2, 0, CLK_ABS_I_STORE2, 3, STORE_ABS_X); - break; - - case 0x9e: /* SHX $nnnn,Y */ - SHX_ABS_Y(p2); - break; - - case 0x9f: /* SHA $nnnn,Y */ - SHA_ABS_Y(p2); - break; - - case 0xa0: /* LDY #$nn */ - LDY(p1, 0, 2); - break; - - case 0xa1: /* LDA ($nn,X) */ - LDA(LOAD_IND_X(p1), 1, 2); - break; - - case 0xa2: /* LDX #$nn */ - LDX(p1, 0, 2); - break; - - case 0xa3: /* LAX ($nn,X) */ - LAX(LOAD_IND_X(p1), 1, 2); - break; - - case 0xa4: /* LDY $nn */ - LDY(LOAD_ZERO(p1), 1, 2); - break; - - case 0xa5: /* LDA $nn */ - LDA(LOAD_ZERO(p1), 1, 2); - break; - - case 0xa6: /* LDX $nn */ - LDX(LOAD_ZERO(p1), 1, 2); - break; - - case 0xa7: /* LAX $nn */ - LAX(LOAD_ZERO(p1), 1, 2); - break; - - case 0xa8: /* TAY */ - TAY(); - break; - - case 0xa9: /* LDA #$nn */ - LDA(p1, 0, 2); - break; - - case 0xaa: /* TAX */ - TAX(); - break; - - case 0xab: /* LXA #$nn */ - LXA(p1, 2); - break; - - case 0xac: /* LDY $nnnn */ - LDY(LOAD(p2), 1, 3); - break; - - case 0xad: /* LDA $nnnn */ - LDA(LOAD(p2), 1, 3); - break; - - case 0xae: /* LDX $nnnn */ - LDX(LOAD(p2), 1, 3); - break; - - case 0xaf: /* LAX $nnnn */ - LAX(LOAD(p2), 1, 3); - break; - - case 0xb0: /* BCS $nnnn */ - BRANCH(LOCAL_CARRY(), p1); - break; - - case 0xb1: /* LDA ($nn),Y */ - LDA(LOAD_IND_Y_BANK(p1), 1, 2); - break; - - case 0xb3: /* LAX ($nn),Y */ - LAX(LOAD_IND_Y(p1), 1, 2); - break; - - case 0xb4: /* LDY $nn,X */ - LDY(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0xb5: /* LDA $nn,X */ - LDA(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0xb6: /* LDX $nn,Y */ - LDX(LOAD_ZERO_Y(p1), CLK_ZERO_I2, 2); - break; - - case 0xb7: /* LAX $nn,Y */ - LAX(LOAD_ZERO_Y(p1), CLK_ZERO_I2, 2); - break; - - case 0xb8: /* CLV */ - CLV(); - break; - - case 0xb9: /* LDA $nnnn,Y */ - LDA(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0xba: /* TSX */ - TSX(); - break; - - case 0xbb: /* LAS $nnnn,Y */ - LAS(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0xbc: /* LDY $nnnn,X */ - LDY(LOAD_ABS_X(p2), 1, 3); - break; - - case 0xbd: /* LDA $nnnn,X */ - LDA(LOAD_ABS_X(p2), 1, 3); - break; - - case 0xbe: /* LDX $nnnn,Y */ - LDX(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0xbf: /* LAX $nnnn,Y */ - LAX(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0xc0: /* CPY #$nn */ - CPY(p1, 0, 2); - break; - - case 0xc1: /* CMP ($nn,X) */ - CMP(LOAD_IND_X(p1), 1, 2); - break; - - case 0xc3: /* DCP ($nn,X) */ - DCP(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0xc4: /* CPY $nn */ - CPY(LOAD_ZERO(p1), 1, 2); - break; - - case 0xc5: /* CMP $nn */ - CMP(LOAD_ZERO(p1), 1, 2); - break; - - case 0xc6: /* DEC $nn */ - DEC(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xc7: /* DCP $nn */ - DCP(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xc8: /* INY */ - INY(); - break; - - case 0xc9: /* CMP #$nn */ - CMP(p1, 0, 2); - break; - - case 0xca: /* DEX */ - DEX(); - break; - - case 0xcb: /* SBX #$nn */ - SBX(p1, 2); - break; - - case 0xcc: /* CPY $nnnn */ - CPY(LOAD(p2), 1, 3); - break; - - case 0xcd: /* CMP $nnnn */ - CMP(LOAD(p2), 1, 3); - break; - - case 0xce: /* DEC $nnnn */ - DEC(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0xcf: /* DCP $nnnn */ - DCP(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0xd0: /* BNE $nnnn */ - BRANCH(!LOCAL_ZERO(), p1); - break; - - case 0xd1: /* CMP ($nn),Y */ - CMP(LOAD_IND_Y(p1), 1, 2); - break; - - case 0xd3: /* DCP ($nn),Y */ - DCP_IND_Y(p1); - break; - - case 0xd5: /* CMP $nn,X */ - CMP(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0xd6: /* DEC $nn,X */ - DEC((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0xd7: /* DCP $nn,X */ - DCP((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0xd8: /* CLD */ - CLD(); - break; - - case 0xd9: /* CMP $nnnn,Y */ - CMP(LOAD_ABS_Y(p2), 1, 3); - break; - - case 0xdb: /* DCP $nnnn,Y */ - DCP(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); - break; - - case 0xdd: /* CMP $nnnn,X */ - CMP(LOAD_ABS_X(p2), 1, 3); - break; - - case 0xde: /* DEC $nnnn,X */ - DEC(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0xdf: /* DCP $nnnn,X */ - DCP(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); - break; - - case 0xe0: /* CPX #$nn */ - CPX(p1, 0, 2); - break; - - case 0xe1: /* SBC ($nn,X) */ - SBC(LOAD_IND_X(p1), 1, 2); - break; - - case 0xe3: /* ISB ($nn,X) */ - ISB(LOAD_ZERO_ADDR(p1 + reg_x_read), 3, CLK_IND_X_RMW, 2, LOAD_ABS, STORE_ABS); - break; - - case 0xe4: /* CPX $nn */ - CPX(LOAD_ZERO(p1), 1, 2); - break; - - case 0xe5: /* SBC $nn */ - SBC(LOAD_ZERO(p1), 1, 2); - break; - - case 0xe6: /* INC $nn */ - INC(p1, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xe7: /* ISB $nn */ - ISB(p1, 0, CLK_ZERO_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xe8: /* INX */ - INX(); - break; - - case 0xe9: /* SBC #$nn */ - SBC(p1, 0, 2); - break; - - case 0xea: /* NOP */ - NOP(); - break; - - case 0xeb: /* USBC #$nn (same as SBC) */ - SBC(p1, 0, 2); - break; - - case 0xec: /* CPX $nnnn */ - CPX(LOAD(p2), 1, 3); - break; - - case 0xed: /* SBC $nnnn */ - SBC(LOAD(p2), 1, 3); - break; - - case 0xee: /* INC $nnnn */ - INC(p2, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0xef: /* ISB $nnnn */ - ISB(p2, 0, CLK_ABS_RMW2, 3, LOAD_ABS, STORE_ABS); - break; - - case 0xf0: /* BEQ $nnnn */ - BRANCH(LOCAL_ZERO(), p1); - break; - - case 0xf1: /* SBC ($nn),Y */ - SBC(LOAD_IND_Y(p1), 1, 2); - break; - - case 0xf3: /* ISB ($nn),Y */ - ISB_IND_Y(p1); - break; - - case 0xf5: /* SBC $nn,X */ - SBC(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); - break; - - case 0xf6: /* INC $nn,X */ - INC((p1 + reg_x_read) & 0xff, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xf7: /* ISB $nn,X */ - ISB((p1 + reg_x_read) & 0xff, 0, CLK_ZERO_I_RMW, 2, LOAD_ZERO, STORE_ABS); - break; - - case 0xf8: /* SED */ - SED(); +(o).op.op16 |= (LOAD(reg_pc + 2) << 8); \ +CLK_ADD(CLK, 1); \ +} \ +} \ +} while (0) + +#define C64D_FETCH_OPCODE_LOAD(o) \ +do { \ +(o).ins = LOAD(reg_pc); \ +CLK_ADD(CLK,1); \ +(o).op.op16 = LOAD(reg_pc + 1); \ +CLK_ADD(CLK,1); \ +if (fetch_tab[(o).ins]) { \ +(o).op.op16 |= (LOAD(reg_pc + 2) << 8); \ +CLK_ADD(CLK,1); \ +} \ +} while (0) + +#define p0 (opcode.ins) +#define p2 (opcode.op.op16) + +#ifdef WORDS_BIGENDIAN +# define p1 (opcode.op.op8[1]) +#else +# define p1 (opcode.op.op8[0]) +#endif + +#endif /* !WORDS_BIGENDIAN */ +#endif + + /* SET_OPCODE for traps */ +#if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS +#define SET_OPCODE(o) (opcode) = o +#else +#if !defined WORDS_BIGENDIAN +#define SET_OPCODE(o) \ +do { \ +opcode.ins = (o) & 0xff; \ +opcode.op.op8[0] = ((o) >> 8) & 0xff; \ +opcode.op.op8[1] = ((o) >> 16) & 0xff; \ +} while (0) +#else +#define SET_OPCODE(o) \ +do { \ +opcode.ins = (o) & 0xff; \ +opcode.op.op8[1] = ((o) >> 8) & 0xff; \ +opcode.op.op8[0] = ((o) >> 16) & 0xff; \ +} while (0) +#endif + +#endif + +#endif /* !C64DTV */ + +/* ------------------------------------------------------------------------ */ + +/* Here, the CPU is emulated. */ + +{ +// LOGD("drive pc=%4.4x", reg_pc); +#ifndef CPU_IS_JAMMED + static int cpu_is_jammed = 0; +#define CPU_IS_JAMMED cpu_is_jammed +#ifdef _MSC_VER +#pragma message ("Warning: CPU_IS_JAMMED not defined, using default (internal)") +#else +#warning "CPU_IS_JAMMED not defined, using default (internal)" +#endif +#endif + unsigned int tmpa; /* needed for some of the opcode macros */ +#if !defined(DRIVE_CPU) + CLOCK profiling_clock_start; +#endif + + /* handle 8502 fast mode refresh cycles */ + CPU_REFRESH_CLK + + /* handle any extra cpu switches */ +#ifdef CHECK_AND_RUN_ALTERNATE_CPU + CHECK_AND_RUN_ALTERNATE_CPU +#endif + CPU_DELAY_CLK + + PROCESS_ALARMS + + /* HACK: when the CPU is jammed, no interrupts are served, the only way + to recover is reset. so we clear the interrupt flags and force + acknowledging them here in this case. */ + if (CPU_IS_JAMMED) { + interrupt_ack_irq(CPU_INT_STATUS); + CPU_INT_STATUS->global_pending_int &= ~(IK_IRQ | IK_NMI); + if (CPU_INT_STATUS->global_pending_int & IK_RESET) { + CPU_IS_JAMMED = 0; + } + } + + { + enum cpu_int pending_interrupt; + + if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) + && (CPU_INT_STATUS->global_pending_int & IK_IRQPEND) + && CPU_INT_STATUS->irq_pending_clk <= CLK) { + interrupt_ack_irq(CPU_INT_STATUS); + } + + pending_interrupt = CPU_INT_STATUS->global_pending_int; + if (pending_interrupt != IK_NONE) { +#if !defined(DRIVE_CPU) + profiling_clock_start = CLK; +#endif + + DO_INTERRUPT(pending_interrupt); + + // c64 debugger - check interrupt breakpoints when irq is ack'ed + if ((pending_interrupt & IK_IRQ) && ((reg_p & P_INTERRUPT) == P_INTERRUPT)) + { + if (c64d_drive1541_is_checking_irq_breakpoints_enabled() == 1) + { + if (diskunit_context[0]->via1d1541->c64d_irq_flagged == 1) + { + diskunit_context[0]->via1d1541->c64d_irq_flagged = 0; + c64d_drive1541_check_irqvia1_breakpoint(); + } + else if (diskunit_context[0]->via2->c64d_irq_flagged == 1) + { + diskunit_context[0]->via2->c64d_irq_flagged = 0; + c64d_drive1541_check_irqvia2_breakpoint(); + } + else + { + // must be IEC? // TODO: confirm this + c64d_drive1541_check_irqiec_breakpoint(); + } + } + } + // + + if (!(CPU_INT_STATUS->global_pending_int & IK_IRQ) + && CPU_INT_STATUS->global_pending_int & IK_IRQPEND) { + CPU_INT_STATUS->global_pending_int &= ~IK_IRQPEND; + } + CPU_DELAY_CLK + + PROCESS_ALARMS + } + } + + // c64d + if (_c64d_new_drive_pc == -1) + { + viceCurrentDiskPC[0] = reg_pc; + } + else + { + viceCurrentDiskPC[0] = _c64d_new_drive_pc; + cpu->cpu_regs.pc = _c64d_new_drive_pc; + reg_pc = _c64d_new_drive_pc; + } + // + + { + if (c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_INSTRUCTION + && c64d_debug_mode != DEBUGGER_MODE_RUN_ONE_CYCLE) + { + // c64d check PC breakpoint after IRQ or trap + c64d_drive1541_check_pc_breakpoint(reg_pc); + viceCurrentDiskPC[0] = reg_pc; + c64d_debug_pause_check(0); + } + } + + { + opcode_t opcode; +#ifdef VICE_DEBUG + CLOCK debug_clk; +#ifdef DRIVE_CPU + debug_clk = CLK; +#else + debug_clk = maincpu_clk; +#endif +#endif + +#ifdef FEATURE_CPUMEMHISTORY + CLOCK history_clk; +#ifndef DRIVE_CPU + history_clk = maincpu_clk; + memmap_state |= (MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); +#else + history_clk = CLK; +#endif +#endif + +#if !defined(DRIVE_CPU) + profiling_clock_start = CLK; + if (maincpu_profiling) { + profile_sample_start(reg_pc); + } +#endif + SET_LAST_ADDR(reg_pc); + + /* c64d: forcing reg_pc does not work with FETCH_OPCODE due to bank_base + * mismatch, so RD uses C64D_FETCH_OPCODE_LOAD (LOAD-based) here. + * HACK (3.10): when "jammed" the real CPU stops fetching; our code may + * rely on a fetch happening, so we remember the last opcode and force it. */ + { + static uint8_t lastop; + C64D_FETCH_OPCODE_LOAD(opcode); + if (!CPU_IS_JAMMED) { + lastop = p0; + } else { + SET_OPCODE(lastop); + } + _c64d_new_drive_pc = -1; + } +#ifdef FEATURE_CPUMEMHISTORY +#ifndef DRIVE_CPU +#ifndef C64DTV + /* HACK to cope with FETCH_OPCODE optimization in x64 */ + if (((int)reg_pc) < bank_limit) { + memmap_mark_read(reg_pc); + } +#endif +#endif + /* If reg_pc >= bank_limit then JSR (0x20) hasn't load p2 yet. + The earlier LOAD(reg_pc+2) hack can break stealing badly. + The fixing is now handled in JSR(). */ + monitor_cpuhistory_store(history_clk, reg_pc, p0, p1, p2 >> 8, reg_a_read, reg_x_read, reg_y_read, reg_sp, LOCAL_STATUS(), ORIGIN_MEMSPACE); +#ifndef DRIVE_CPU + memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); +#endif +#endif + +#ifdef VICE_DEBUG +#ifdef DRIVE_CPU + if (TRACEFLG) { + uint8_t op = (uint8_t)(p0); + uint8_t lo = (uint8_t)(p1); + uint8_t hi = (uint8_t)(p2 >> 8); + + debug_drive((uint32_t)(reg_pc), debug_clk, + mon_disassemble_to_string(e_disk8_space, + reg_pc, op, + lo, hi, 0, 1, "6502"), + reg_a_read, reg_x_read, reg_y_read, reg_sp, drv->mynumber + 8); + } +#else + if (TRACEFLG) { + uint8_t op = (uint8_t)(p0); + uint8_t lo = (uint8_t)(p1); + uint8_t hi = (uint8_t)(p2 >> 8); + + if (op == 0x20) { + hi = LOAD(reg_pc + 2); /* FIXME: this triggers watchpoints eventually */ + } + + debug_maincpu((uint32_t)(reg_pc), debug_clk, + mon_disassemble_to_string(e_comp_space, + reg_pc, op, + lo, hi, 0, 1, "6502"), + reg_a_read, reg_x_read, reg_y_read, reg_sp); + } + if (debug.perform_break_into_monitor) { + monitor_startup_trap(); + debug.perform_break_into_monitor = 0; + } +#endif +#endif + + trap_skipped: + SET_LAST_OPCODE(p0); + + switch (p0) { + case 0x00: /* BRK */ + BRK(); break; - case 0xf9: /* SBC $nnnn,Y */ - SBC(LOAD_ABS_Y(p2), 1, 3); + case 0x01: /* ORA ($nn,X) */ + ORA(LOAD_IND_X(p1), 1, 2); break; - case 0xfb: /* ISB $nnnn,Y */ - ISB(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW); + case 0x02: /* JAM - also used for traps */ + STATIC_ASSERT(TRAP_OPCODE == 0x02); + JAM_02(); break; - case 0xfd: /* SBC $nnnn,X */ - SBC(LOAD_ABS_X(p2), 1, 3); + case 0x22: /* JAM */ + case 0x52: /* JAM */ + case 0x62: /* JAM */ + case 0x72: /* JAM */ + case 0x92: /* JAM */ + case 0xb2: /* JAM */ + case 0xd2: /* JAM */ + case 0xf2: /* JAM */ +#ifndef C64DTV + case 0x12: /* JAM */ + case 0x32: /* JAM */ + case 0x42: /* JAM */ +#endif + CPU_IS_JAMMED = 1; + REWIND_FETCH_OPCODE(CLK); + JAM(); + break; + +#ifdef C64DTV + /* These opcodes are defined in c64/c64dtvcpu.c */ + case 0x12: /* BRA */ + BRANCH(1, p1); break; - case 0xfe: /* INC $nnnn,X */ - INC(p2, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); + case 0x32: /* SAC */ + SAC(p1); break; - case 0xff: /* ISB $nnnn,X */ - ISB(p2, 0, CLK_ABS_I_RMW2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW); + case 0x42: /* SIR */ + SIR(p1); break; - } - } - } +#endif + + case 0x03: /* SLO ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + SLO(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x04: /* NOOP $nn */ + case 0x44: /* NOOP $nn */ + case 0x64: /* NOOP $nn */ + NOOP(1, 2); + break; + + case 0x05: /* ORA $nn */ + ORA(LOAD_ZERO(p1), 1, 2); + break; + + case 0x06: /* ASL $nn */ + ASL(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x07: /* SLO $nn */ + SLO(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x08: /* PHP */ +#ifdef DRIVE_CPU + drivecpu_rotate(); + if (drivecpu_byte_ready()) { + drivecpu_byte_ready_egde_clear(); + LOCAL_SET_OVERFLOW(1); + } +#endif + PHP(); + break; + + case 0x09: /* ORA #$nn */ + ORA(p1, 0, 2); + break; + + case 0x0a: /* ASL A */ + ASL_A(); + break; + + case 0x0b: /* ANC #$nn */ + case 0x2b: /* ANC #$nn */ + ANC(p1, 2); + break; + + case 0x0c: /* NOOP $nnnn */ + NOOP_ABS(); + break; + + case 0x0d: /* ORA $nnnn */ + ORA(LOAD(p2), 1, 3); + break; + + case 0x0e: /* ASL $nnnn */ + ASL(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x0f: /* SLO $nnnn */ + SLO(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x10: /* BPL $nnnn */ + BRANCH(!LOCAL_SIGN(), p1); + break; + + case 0x11: /* ORA ($nn),Y */ + ORA(LOAD_IND_Y(p1), 1, 2); + break; + + case 0x13: /* SLO ($nn),Y */ + SLO_IND_Y(p1); + break; + + case 0x14: /* NOOP $nn,X */ + case 0x34: /* NOOP $nn,X */ + case 0x54: /* NOOP $nn,X */ + case 0x74: /* NOOP $nn,X */ + case 0xd4: /* NOOP $nn,X */ + case 0xf4: /* NOOP $nn,X */ + NOOP((NOOP_LOAD_ZERO_X(p1), CLK_NOOP_ZERO_X), 2); + break; + + case 0x15: /* ORA $nn,X */ + ORA(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0x16: /* ASL $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + ASL((p1 + reg_x_read) & 0xff, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x17: /* SLO $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + SLO((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x18: /* CLC */ + CLC(); + break; + + case 0x19: /* ORA $nnnn,Y */ + ORA(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0x1a: /* NOOP */ + case 0x3a: /* NOOP */ + case 0x5a: /* NOOP */ + case 0x7a: /* NOOP */ + case 0xda: /* NOOP */ + case 0xfa: /* NOOP */ + NOOP_IMM(1); + break; + + case 0x1b: /* SLO $nnnn,Y */ + SLO(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0x1c: /* NOOP $nnnn,X */ + case 0x3c: /* NOOP $nnnn,X */ + case 0x5c: /* NOOP $nnnn,X */ + case 0x7c: /* NOOP $nnnn,X */ + case 0xdc: /* NOOP $nnnn,X */ + case 0xfc: /* NOOP $nnnn,X */ + NOOP_ABS_X(); + break; + + case 0x1d: /* ORA $nnnn,X */ + ORA(LOAD_ABS_X(p2), 1, 3); + break; + + case 0x1e: /* ASL $nnnn,X */ + ASL(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x1f: /* SLO $nnnn,X */ + SLO(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x20: /* JSR $nnnn */ + JSR(); + break; + + case 0x21: /* AND ($nn,X) */ + AND(LOAD_IND_X(p1), 1, 2); + break; + + case 0x23: /* RLA ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + RLA(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x24: /* BIT $nn */ + BIT(LOAD_ZERO(p1), 2); + break; + + case 0x25: /* AND $nn */ + AND(LOAD_ZERO(p1), 1, 2); + break; + + case 0x26: /* ROL $nn */ + ROL(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x27: /* RLA $nn */ + RLA(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x28: /* PLP */ + PLP(); + break; + + case 0x29: /* AND #$nn */ + AND(p1, 0, 2); + break; + + case 0x2a: /* ROL A */ + ROL_A(); + break; + + case 0x2c: /* BIT $nnnn */ + BIT(LOAD(p2), 3); + break; + + case 0x2d: /* AND $nnnn */ + AND(LOAD(p2), 1, 3); + break; + + case 0x2e: /* ROL $nnnn */ + ROL(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x2f: /* RLA $nnnn */ + RLA(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x30: /* BMI $nnnn */ + BRANCH(LOCAL_SIGN(), p1); + break; + + case 0x31: /* AND ($nn),Y */ + AND(LOAD_IND_Y(p1), 1, 2); + break; + + case 0x33: /* RLA ($nn),Y */ + RLA_IND_Y(p1); + break; + + case 0x35: /* AND $nn,X */ + AND(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0x36: /* ROL $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + ROL((p1 + reg_x_read) & 0xff, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x37: /* RLA $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + RLA((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x38: /* SEC */ + SEC(); + break; + + case 0x39: /* AND $nnnn,Y */ + AND(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0x3b: /* RLA $nnnn,Y */ + RLA(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0x3d: /* AND $nnnn,X */ + AND(LOAD_ABS_X(p2), 1, 3); + break; + + case 0x3e: /* ROL $nnnn,X */ + ROL(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x3f: /* RLA $nnnn,X */ + RLA(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x40: /* RTI */ + RTI(); + break; + + case 0x41: /* EOR ($nn,X) */ + EOR(LOAD_IND_X(p1), 1, 2); + break; + + case 0x43: /* SRE ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + SRE(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x45: /* EOR $nn */ + EOR(LOAD_ZERO(p1), 1, 2); + break; + + case 0x46: /* LSR $nn */ + LSR(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x47: /* SRE $nn */ + SRE(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x48: /* PHA */ + PHA(); + break; + + case 0x49: /* EOR #$nn */ + EOR(p1, 0, 2); + break; + + case 0x4a: /* LSR A */ + LSR_A(); + break; + + case 0x4b: /* ASR #$nn */ + ASR(p1, 2); + break; + + case 0x4c: /* JMP $nnnn */ + JMP(p2); + break; + + case 0x4d: /* EOR $nnnn */ + EOR(LOAD(p2), 1, 3); + break; + + case 0x4e: /* LSR $nnnn */ + LSR(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x4f: /* SRE $nnnn */ + SRE(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x50: /* BVC $nnnn */ +#ifdef DRIVE_CPU + CLK_ADD(CLK, -1); + drivecpu_rotate(); + if (drivecpu_byte_ready()) { + drivecpu_byte_ready_egde_clear(); + LOCAL_SET_OVERFLOW(1); + } + CLK_ADD(CLK, 1); +#endif + BRANCH(!LOCAL_OVERFLOW(), p1); + break; + + case 0x51: /* EOR ($nn),Y */ + EOR(LOAD_IND_Y(p1), 1, 2); + break; + + case 0x53: /* SRE ($nn),Y */ + SRE_IND_Y(p1); + break; + + case 0x55: /* EOR $nn,X */ + EOR(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0x56: /* LSR $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + LSR((p1 + reg_x_read) & 0xff, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x57: /* SRE $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + SRE((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x58: /* CLI */ + CLI(); + break; + + case 0x59: /* EOR $nnnn,Y */ + EOR(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0x5b: /* SRE $nnnn,Y */ + SRE(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0x5d: /* EOR $nnnn,X */ + EOR(LOAD_ABS_X(p2), 1, 3); + break; + + case 0x5e: /* LSR $nnnn,X */ + LSR(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x5f: /* SRE $nnnn,X */ + SRE(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x60: /* RTS */ + RTS(); + break; + + case 0x61: /* ADC ($nn,X) */ + ADC(LOAD_IND_X(p1), 1, 2); + break; + + case 0x63: /* RRA ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + RRA(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x65: /* ADC $nn */ + ADC(LOAD_ZERO(p1), 1, 2); + break; + + case 0x66: /* ROR $nn */ + ROR(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x67: /* RRA $nn */ + RRA(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x68: /* PLA */ + PLA(); + break; + + case 0x69: /* ADC #$nn */ + ADC(p1, 0, 2); + break; + + case 0x6a: /* ROR A */ + ROR_A(); + break; + + case 0x6b: /* ARR #$nn */ + ARR(p1, 2); + break; + + case 0x6c: /* JMP ($nnnn) */ + JMP_IND(); + break; + + case 0x6d: /* ADC $nnnn */ + ADC(LOAD(p2), 1, 3); + break; + + case 0x6e: /* ROR $nnnn */ + ROR(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x6f: /* RRA $nnnn */ + RRA(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x70: /* BVS $nnnn */ +#ifdef DRIVE_CPU + CLK_ADD(CLK, -1); + drivecpu_rotate(); + if (drivecpu_byte_ready()) { + drivecpu_byte_ready_egde_clear(); + LOCAL_SET_OVERFLOW(1); + } + CLK_ADD(CLK, 1); +#endif + BRANCH(LOCAL_OVERFLOW(), p1); + break; + + case 0x71: /* ADC ($nn),Y */ + ADC(LOAD_IND_Y(p1), 1, 2); + break; + + case 0x73: /* RRA ($nn),Y */ + RRA_IND_Y(p1); + break; + + case 0x75: /* ADC $nn,X */ + ADC(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0x76: /* ROR $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + ROR((p1 + reg_x_read) & 0xff, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x77: /* RRA $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + RRA((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0x78: /* SEI */ + SEI(); + break; + + case 0x79: /* ADC $nnnn,Y */ + ADC(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0x7b: /* RRA $nnnn,Y */ + RRA(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0x7d: /* ADC $nnnn,X */ + ADC(LOAD_ABS_X(p2), 1, 3); + break; + + case 0x7e: /* ROR $nnnn,X */ + ROR(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x7f: /* RRA $nnnn,X */ + RRA(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0x80: /* NOOP #$nn */ + case 0x82: /* NOOP #$nn */ + case 0x89: /* NOOP #$nn */ + case 0xc2: /* NOOP #$nn */ + case 0xe2: /* NOOP #$nn */ + NOOP_IMM(2); + break; + + case 0x81: /* STA ($nn,X) */ + STA((LOAD_ZERO_DUMMY(p1), LOAD_ZERO_ADDR(p1 + reg_x_read)), 3, 1, 2, STORE_ABS); + break; + + case 0x83: /* SAX ($nn,X) */ + SAX((LOAD_ZERO_DUMMY(p1), LOAD_ZERO_ADDR(p1 + reg_x_read)), 3, 1, 2); + break; + + case 0x84: /* STY $nn */ + STY_ZERO(p1, 1, 2); + break; + + case 0x85: /* STA $nn */ + STA_ZERO(p1, 1, 2); + break; + + case 0x86: /* STX $nn */ + STX_ZERO(p1, 1, 2); + break; + + case 0x87: /* SAX $nn */ + SAX_ZERO(p1, 1, 2); + break; + + case 0x88: /* DEY */ + DEY(); + break; + + case 0x8a: /* TXA */ + TXA(); + break; + + case 0x8b: /* ANE #$nn */ + ANE(p1, 2); + break; + + case 0x8c: /* STY $nnnn */ + STY(p2, 1, 3); + break; + + case 0x8d: /* STA $nnnn */ + STA(p2, 0, 1, 3, STORE_ABS); + break; + + case 0x8e: /* STX $nnnn */ + STX(p2, 1, 3); + break; + + case 0x8f: /* SAX $nnnn */ + SAX(p2, 0, 1, 3); + break; + + case 0x90: /* BCC $nnnn */ + BRANCH(!LOCAL_CARRY(), p1); + break; + + case 0x91: /* STA ($nn),Y */ + STA_IND_Y(p1); + break; + + case 0x93: /* SHA ($nn),Y */ + SHA_IND_Y(p1); + break; + + case 0x94: /* STY $nn,X */ + STY_ZERO((LOAD_ZERO_DUMMY(p1), p1 + reg_x_read), CLK_ZERO_I_STORE, 2); + break; + + case 0x95: /* STA $nn,X */ + STA_ZERO((LOAD_ZERO_DUMMY(p1), p1 + reg_x_read), CLK_ZERO_I_STORE, 2); + break; + + case 0x96: /* STX $nn,Y */ + STX_ZERO((LOAD_ZERO_DUMMY(p1), p1 + reg_y_read), CLK_ZERO_I_STORE, 2); + break; + + case 0x97: /* SAX $nn,Y */ + SAX((LOAD_ZERO_DUMMY(p1), (p1 + reg_y_read) & 0xff), 0, CLK_ZERO_I_STORE, 2); + break; + + case 0x98: /* TYA */ + TYA(); + break; + + case 0x99: /* STA $nnnn,Y */ + STA(p2, 0, CLK_ABS_I_STORE2, 3, STORE_ABS_Y); + break; + + case 0x9a: /* TXS */ + TXS(); + break; + + case 0x9b: /* SHS $nnnn,Y */ +#ifdef C64DTV + NOOP_ABS_Y(); +#else + SHS_ABS_Y(p2); +#endif + break; + + case 0x9c: /* SHY $nnnn,X */ + SHY_ABS_X(p2); + break; + + case 0x9d: /* STA $nnnn,X */ + STA(p2, 0, CLK_ABS_I_STORE2, 3, STORE_ABS_X); + break; + + case 0x9e: /* SHX $nnnn,Y */ + SHX_ABS_Y(p2); + break; + + case 0x9f: /* SHA $nnnn,Y */ + SHA_ABS_Y(p2); + break; + + case 0xa0: /* LDY #$nn */ + LDY(p1, 0, 2); + break; + + case 0xa1: /* LDA ($nn,X) */ + LDA(LOAD_IND_X(p1), 1, 2); + break; + + case 0xa2: /* LDX #$nn */ + LDX(p1, 0, 2); + break; + + case 0xa3: /* LAX ($nn,X) */ + LAX(LOAD_IND_X(p1), 1, 2); + break; + + case 0xa4: /* LDY $nn */ + LDY(LOAD_ZERO(p1), 1, 2); + break; + + case 0xa5: /* LDA $nn */ + LDA(LOAD_ZERO(p1), 1, 2); + break; + + case 0xa6: /* LDX $nn */ + LDX(LOAD_ZERO(p1), 1, 2); + break; + + case 0xa7: /* LAX $nn */ + LAX(LOAD_ZERO(p1), 1, 2); + break; + + case 0xa8: /* TAY */ + TAY(); + break; + + case 0xa9: /* LDA #$nn */ + LDA(p1, 0, 2); + break; + + case 0xaa: /* TAX */ + TAX(); + break; + + case 0xab: /* LXA #$nn */ + LXA(p1, 2); + break; + + case 0xac: /* LDY $nnnn */ + LDY(LOAD(p2), 1, 3); + break; + + case 0xad: /* LDA $nnnn */ + LDA(LOAD(p2), 1, 3); + break; + + case 0xae: /* LDX $nnnn */ + LDX(LOAD(p2), 1, 3); + break; + + case 0xaf: /* LAX $nnnn */ + LAX(LOAD(p2), 1, 3); + break; + + case 0xb0: /* BCS $nnnn */ + BRANCH(LOCAL_CARRY(), p1); + break; + + case 0xb1: /* LDA ($nn),Y */ + LDA(LOAD_IND_Y_BANK(p1), 1, 2); + break; + + case 0xb3: /* LAX ($nn),Y */ + LAX(LOAD_IND_Y(p1), 1, 2); + break; + + case 0xb4: /* LDY $nn,X */ + LDY(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0xb5: /* LDA $nn,X */ + LDA(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0xb6: /* LDX $nn,Y */ + LDX(LOAD_ZERO_Y(p1), CLK_ZERO_I2, 2); + break; + + case 0xb7: /* LAX $nn,Y */ + LAX(LOAD_ZERO_Y(p1), CLK_ZERO_I2, 2); + break; + + case 0xb8: /* CLV */ + CLV(); + break; + + case 0xb9: /* LDA $nnnn,Y */ + LDA(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xba: /* TSX */ + TSX(); + break; + + case 0xbb: /* LAS $nnnn,Y */ + LAS(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xbc: /* LDY $nnnn,X */ + LDY(LOAD_ABS_X(p2), 1, 3); + break; + + case 0xbd: /* LDA $nnnn,X */ + LDA(LOAD_ABS_X(p2), 1, 3); + break; + + case 0xbe: /* LDX $nnnn,Y */ + LDX(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xbf: /* LAX $nnnn,Y */ + LAX(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xc0: /* CPY #$nn */ + CPY(p1, 0, 2); + break; + + case 0xc1: /* CMP ($nn,X) */ + CMP(LOAD_IND_X(p1), 1, 2); + break; + + case 0xc3: /* DCP ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + DCP(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xc4: /* CPY $nn */ + CPY(LOAD_ZERO(p1), 1, 2); + break; + + case 0xc5: /* CMP $nn */ + CMP(LOAD_ZERO(p1), 1, 2); + break; + + case 0xc6: /* DEC $nn */ + DEC(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xc7: /* DCP $nn */ + DCP(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xc8: /* INY */ + INY(); + break; + + case 0xc9: /* CMP #$nn */ + CMP(p1, 0, 2); + break; + + case 0xca: /* DEX */ + DEX(); + break; + + case 0xcb: /* SBX #$nn */ + SBX(p1, 2); + break; + + case 0xcc: /* CPY $nnnn */ + CPY(LOAD(p2), 1, 3); + break; + + case 0xcd: /* CMP $nnnn */ + CMP(LOAD(p2), 1, 3); + break; + + case 0xce: /* DEC $nnnn */ + DEC(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xcf: /* DCP $nnnn */ + DCP(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xd0: /* BNE $nnnn */ + BRANCH(!LOCAL_ZERO(), p1); + break; + + case 0xd1: /* CMP ($nn),Y */ + CMP(LOAD_IND_Y(p1), 1, 2); + break; + + case 0xd3: /* DCP ($nn),Y */ + DCP_IND_Y(p1); + break; + + case 0xd5: /* CMP $nn,X */ + CMP(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0xd6: /* DEC $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + DEC((p1 + reg_x_read) & 0xff, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xd7: /* DCP $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + DCP((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xd8: /* CLD */ + CLD(); + break; + + case 0xd9: /* CMP $nnnn,Y */ + CMP(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xdb: /* DCP $nnnn,Y */ + DCP(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0xdd: /* CMP $nnnn,X */ + CMP(LOAD_ABS_X(p2), 1, 3); + break; + + case 0xde: /* DEC $nnnn,X */ + DEC(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0xdf: /* DCP $nnnn,X */ + DCP(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0xe0: /* CPX #$nn */ + CPX(p1, 0, 2); + break; + + case 0xe1: /* SBC ($nn,X) */ + SBC(LOAD_IND_X(p1), 1, 2); + break; + + case 0xe3: /* ISB ($nn,X) */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + ISB(LOAD_ZERO_ADDR(p1 + reg_x_read), 2, 2, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xe4: /* CPX $nn */ + CPX(LOAD_ZERO(p1), 1, 2); + break; + + case 0xe5: /* SBC $nn */ + SBC(LOAD_ZERO(p1), 1, 2); + break; + + case 0xe6: /* INC $nn */ + INC(p1, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xe7: /* ISB $nn */ + ISB(p1, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xe8: /* INX */ + INX(); + break; + + case 0xe9: /* SBC #$nn */ + SBC(p1, 0, 2); + break; + + case 0xea: /* NOP */ + NOP(); + break; + + case 0xeb: /* USBC #$nn (same as SBC) */ + SBC(p1, 0, 2); + break; + + case 0xec: /* CPX $nnnn */ + CPX(LOAD(p2), 1, 3); + break; + + case 0xed: /* SBC $nnnn */ + SBC(LOAD(p2), 1, 3); + break; + + case 0xee: /* INC $nnnn */ + INC(p2, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xef: /* ISB $nnnn */ + ISB(p2, 0, 3, LOAD_ABS, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xf0: /* BEQ $nnnn */ + BRANCH(LOCAL_ZERO(), p1); + break; + + case 0xf1: /* SBC ($nn),Y */ + SBC(LOAD_IND_Y(p1), 1, 2); + break; + + case 0xf3: /* ISB ($nn),Y */ + ISB_IND_Y(p1); + break; + + case 0xf5: /* SBC $nn,X */ + SBC(LOAD_ZERO_X(p1), CLK_ZERO_I2, 2); + break; + + case 0xf6: /* INC $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + INC((p1 + reg_x_read) & 0xff, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xf7: /* ISB $nn,X */ + LOAD_ZERO_DUMMY(p1); + CLK_ADD_DUMMY(CLK, 1); + ISB((p1 + reg_x_read) & 0xff, 0, 2, LOAD_ZERO, STORE_ABS, DUMMY_STORE_ABS_RMW); + break; + + case 0xf8: /* SED */ + SED(); + break; + + case 0xf9: /* SBC $nnnn,Y */ + SBC(LOAD_ABS_Y(p2), 1, 3); + break; + + case 0xfb: /* ISB $nnnn,Y */ + ISB(p2, 0, 3, LOAD_ABS_Y_RMW, STORE_ABS_Y_RMW, DUMMY_STORE_ABS_Y_RMW); + break; + + case 0xfd: /* SBC $nnnn,X */ + SBC(LOAD_ABS_X(p2), 1, 3); + break; + + case 0xfe: /* INC $nnnn,X */ + INC(p2, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + + case 0xff: /* ISB $nnnn,X */ + ISB(p2, 0, 3, LOAD_ABS_X_RMW, STORE_ABS_X_RMW, DUMMY_STORE_ABS_X_RMW); + break; + } + +#if !defined(DRIVE_CPU) + if (maincpu_profiling) { + profile_sample_finish(CLK - profiling_clock_start, 0 /* stolen_cycles */); + } +#endif + + } +} + - /// 6510core.c ends here + /// /// @@ -3741,13 +4121,9 @@ opcode.op.op8[0] = ((o) >> 16) & 0xff; \ drivecpu_sleep(drv); } -#ifdef _MSC_VER -#pragma optimize("",on) -#endif - /* ------------------------------------------------------------------------- */ -void c64d_interrupt_drivecpu_trigger_trap(drive_context_t *drv, +void c64d_interrupt_drivecpu_trigger_trap(diskunit_context_t *drv, void (*trap_func)(WORD, void *data), void *data); @@ -3755,7 +4131,7 @@ void _c64d_set_drive_pc_trap(WORD addr, void *data) { WORD newpc = _c64d_new_drive_pc; - drive_context[_c64d_new_drive_dnr]->cpu->cpu_regs.pc = newpc; + diskunit_context[_c64d_new_drive_dnr]->cpu->cpu_regs.pc = newpc; _c64d_new_drive_pc = -1; } @@ -3774,7 +4150,7 @@ uint8 _c64d_new_drive_register_a, _c64d_new_drive_register_x, _c64d_new_drive_re void _c64d_set_drive_register_a_trap(WORD addr, void *data) { - drive_context_t *trapDriveContext = (drive_context_t *)data; + diskunit_context_t *trapDriveContext = (diskunit_context_t *)data; trapDriveContext->cpu->cpu_regs.a = _c64d_new_drive_register_a; @@ -3785,12 +4161,12 @@ void c64d_set_drive_register_a(int driveNr, uint8 a) { _c64d_new_drive_register_a = a; - c64d_interrupt_drivecpu_trigger_trap(drive_context[driveNr], _c64d_set_drive_register_a_trap, (void*)(drive_context[driveNr])); + c64d_interrupt_drivecpu_trigger_trap(diskunit_context[driveNr], _c64d_set_drive_register_a_trap, (void*)(diskunit_context[driveNr])); } void _c64d_set_drive_register_x_trap(WORD addr, void *data) { - drive_context_t *trapDriveContext = (drive_context_t *)data; + diskunit_context_t *trapDriveContext = (diskunit_context_t *)data; trapDriveContext->cpu->cpu_regs.x = _c64d_new_drive_register_x; @@ -3801,12 +4177,12 @@ void c64d_set_drive_register_x(int driveNr, uint8 x) { _c64d_new_drive_register_x = x; - c64d_interrupt_drivecpu_trigger_trap(drive_context[driveNr], _c64d_set_drive_register_x_trap, (void*)(drive_context[driveNr])); + c64d_interrupt_drivecpu_trigger_trap(diskunit_context[driveNr], _c64d_set_drive_register_x_trap, (void*)(diskunit_context[driveNr])); } void _c64d_set_drive_register_y_trap(WORD addr, void *data) { - drive_context_t *trapDriveContext = (drive_context_t *)data; + diskunit_context_t *trapDriveContext = (diskunit_context_t *)data; trapDriveContext->cpu->cpu_regs.y = _c64d_new_drive_register_y; @@ -3817,12 +4193,12 @@ void c64d_set_drive_register_y(int driveNr, uint8 y) { _c64d_new_drive_register_y = y; - c64d_interrupt_drivecpu_trigger_trap(drive_context[driveNr], _c64d_set_drive_register_y_trap, (void*)(drive_context[driveNr])); + c64d_interrupt_drivecpu_trigger_trap(diskunit_context[driveNr], _c64d_set_drive_register_y_trap, (void*)(diskunit_context[driveNr])); } void _c64d_set_drive_register_p_trap(WORD addr, void *data) { - drive_context_t *trapDriveContext = (drive_context_t *)data; + diskunit_context_t *trapDriveContext = (diskunit_context_t *)data; trapDriveContext->cpu->cpu_regs.p = _c64d_new_drive_register_p; @@ -3833,12 +4209,12 @@ void c64d_set_drive_register_p(int driveNr, uint8 p) { _c64d_new_drive_register_p = p; - c64d_interrupt_drivecpu_trigger_trap(drive_context[driveNr], _c64d_set_drive_register_p_trap, (void*)(drive_context[driveNr])); + c64d_interrupt_drivecpu_trigger_trap(diskunit_context[driveNr], _c64d_set_drive_register_p_trap, (void*)(diskunit_context[driveNr])); } void _c64d_set_drive_register_sp_trap(WORD addr, void *data) { - drive_context_t *trapDriveContext = (drive_context_t *)data; + diskunit_context_t *trapDriveContext = (diskunit_context_t *)data; trapDriveContext->cpu->cpu_regs.sp = _c64d_new_drive_register_sp; @@ -3849,37 +4225,37 @@ void c64d_set_drive_register_sp(int driveNr, uint8 sp) { _c64d_new_drive_register_sp = sp; - c64d_interrupt_drivecpu_trigger_trap(drive_context[driveNr], _c64d_set_drive_register_sp_trap, (void*)(drive_context[driveNr])); + c64d_interrupt_drivecpu_trigger_trap(diskunit_context[driveNr], _c64d_set_drive_register_sp_trap, (void*)(diskunit_context[driveNr])); } void c64d_set_drivecpu_regs_no_trap(int driveNr, uint8 a, uint8 x, uint8 y, uint8 p, uint8 sp) { - drive_context[driveNr]->cpu->cpu_regs.a = a; - drive_context[driveNr]->cpu->cpu_regs.x = x; - drive_context[driveNr]->cpu->cpu_regs.y = y; - drive_context[driveNr]->cpu->cpu_regs.p = p; - drive_context[driveNr]->cpu->cpu_regs.sp = sp; + diskunit_context[driveNr]->cpu->cpu_regs.a = a; + diskunit_context[driveNr]->cpu->cpu_regs.x = x; + diskunit_context[driveNr]->cpu->cpu_regs.y = y; + diskunit_context[driveNr]->cpu->cpu_regs.p = p; + diskunit_context[driveNr]->cpu->cpu_regs.sp = sp; } void c64d_set_drivecpu_pc_no_trap(int driveNr, uint16 pc) { - drive_context[driveNr]->cpu->cpu_regs.pc = pc; + diskunit_context[driveNr]->cpu->cpu_regs.pc = pc; } static void drivecpu_set_bank_base(void *context) { - drive_context_t *drv; + diskunit_context_t *drv; drivecpu_context_t *cpu; - drv = (drive_context_t *)context; + drv = (diskunit_context_t *)context; cpu = drv->cpu; JUMP(reg_pc); } /* Inlining this fuction makes no sense and would only bloat the code. */ -static void drive_jam(drive_context_t *drv) +static void drivecpu_jam(diskunit_context_t *drv) { unsigned int tmp; char *dname = " Drive"; @@ -3887,7 +4263,7 @@ static void drive_jam(drive_context_t *drv) cpu = drv->cpu; - switch (drv->drive->type) { + switch (drv->type) { case DRIVE_TYPE_1540: dname = " 1540"; break; @@ -3933,19 +4309,22 @@ static void drive_jam(drive_context_t *drv) case DRIVE_TYPE_8250: dname = " 8250"; break; + case DRIVE_TYPE_9000: + dname = " D9090/60"; + break; } - tmp = machine_jam("%s CPU: JAM at $%04X ", dname, (int)reg_pc); + tmp = drive_jam(drv->mynumber, "%s (%u) CPU: JAM at $%04X ", dname, drv->mynumber + 8, (unsigned int)reg_pc); switch (tmp) { - case JAM_RESET: + case JAM_RESET_CPU: reg_pc = 0xeaa0; drivecpu_set_bank_base((void *)drv); - machine_trigger_reset(MACHINE_RESET_MODE_SOFT); + machine_trigger_reset(MACHINE_RESET_MODE_RESET_CPU); break; - case JAM_HARD_RESET: + case JAM_POWER_CYCLE: reg_pc = 0xeaa0; drivecpu_set_bank_base((void *)drv); - machine_trigger_reset(MACHINE_RESET_MODE_HARD); + machine_trigger_reset(MACHINE_RESET_MODE_POWER_CYCLE); break; case JAM_MONITOR: monitor_startup(drv->cpu->monspace); @@ -3958,9 +4337,9 @@ static void drive_jam(drive_context_t *drv) /* ------------------------------------------------------------------------- */ #define SNAP_MAJOR 1 -#define SNAP_MINOR 1 +#define SNAP_MINOR 3 -int drivecpu_snapshot_write_module(drive_context_t *drv, snapshot_t *s) +int drivecpu_snapshot_write_module(diskunit_context_t *drv, snapshot_t *s) { snapshot_module_t *m; drivecpu_context_t *cpu; @@ -3968,24 +4347,25 @@ int drivecpu_snapshot_write_module(drive_context_t *drv, snapshot_t *s) cpu = drv->cpu; m = snapshot_module_create(s, drv->cpu->snap_module_name, - ((BYTE)(SNAP_MAJOR)), ((BYTE)(SNAP_MINOR))); + ((uint8_t)(SNAP_MAJOR)), ((uint8_t)(SNAP_MINOR))); if (m == NULL) { return -1; } if (0 - || SMW_DW(m, (DWORD) *(drv->clk_ptr)) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_A(&(cpu->cpu_regs))) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_X(&(cpu->cpu_regs))) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_Y(&(cpu->cpu_regs))) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_SP(&(cpu->cpu_regs))) < 0 - || SMW_W(m, (WORD)MOS6510_REGS_GET_PC(&(cpu->cpu_regs))) < 0 - || SMW_B(m, (BYTE)MOS6510_REGS_GET_STATUS(&(cpu->cpu_regs))) < 0 - || SMW_DW(m, (DWORD)(cpu->last_opcode_info)) < 0 - || SMW_DW(m, (DWORD)(cpu->last_clk)) < 0 - || SMW_DW(m, (DWORD)(cpu->cycle_accum)) < 0 - || SMW_DW(m, (DWORD)(cpu->last_exc_cycles)) < 0 - || SMW_DW(m, (DWORD)(cpu->stop_clk)) < 0 + || SMW_CLOCK(m, *(drv->clk_ptr)) < 0 + || SMW_B(m, (uint8_t)MOS6510_REGS_GET_A(&(cpu->cpu_regs))) < 0 + || SMW_B(m, (uint8_t)MOS6510_REGS_GET_X(&(cpu->cpu_regs))) < 0 + || SMW_B(m, (uint8_t)MOS6510_REGS_GET_Y(&(cpu->cpu_regs))) < 0 + || SMW_B(m, (uint8_t)MOS6510_REGS_GET_SP(&(cpu->cpu_regs))) < 0 + || SMW_W(m, (uint16_t)MOS6510_REGS_GET_PC(&(cpu->cpu_regs))) < 0 + || SMW_B(m, (uint16_t)MOS6510_REGS_GET_STATUS(&(cpu->cpu_regs))) < 0 + || SMW_DW(m, (uint32_t)(cpu->last_opcode_info)) < 0 + || SMW_CLOCK(m, cpu->last_clk) < 0 + || SMW_CLOCK(m, cpu->cycle_accum) < 0 + || SMW_CLOCK(m, cpu->last_exc_cycles) < 0 + || SMW_CLOCK(m, cpu->stop_clk) < 0 + || SMW_B(m, cpu->cpu_last_data) < 0 ) { goto fail; } @@ -3994,28 +4374,28 @@ int drivecpu_snapshot_write_module(drive_context_t *drv, snapshot_t *s) goto fail; } - if (drv->drive->type == DRIVE_TYPE_1540 - || drv->drive->type == DRIVE_TYPE_1541 - || drv->drive->type == DRIVE_TYPE_1541II - || drv->drive->type == DRIVE_TYPE_1551 - || drv->drive->type == DRIVE_TYPE_1570 - || drv->drive->type == DRIVE_TYPE_1571 - || drv->drive->type == DRIVE_TYPE_1571CR - || drv->drive->type == DRIVE_TYPE_2031) { - if (SMW_BA(m, drv->drive->drive_ram, 0x800) < 0) { + if (drv->type == DRIVE_TYPE_1540 + || drv->type == DRIVE_TYPE_1541 + || drv->type == DRIVE_TYPE_1541II + || drv->type == DRIVE_TYPE_1551 + || drv->type == DRIVE_TYPE_1570 + || drv->type == DRIVE_TYPE_1571 + || drv->type == DRIVE_TYPE_1571CR + || drv->type == DRIVE_TYPE_2031) { + if (SMW_BA(m, drv->drive_ram, 0x800) < 0) { goto fail; } } - if (drv->drive->type == DRIVE_TYPE_1581 - || drv->drive->type == DRIVE_TYPE_2000 - || drv->drive->type == DRIVE_TYPE_4000) { - if (SMW_BA(m, drv->drive->drive_ram, 0x2000) < 0) { + if (drv->type == DRIVE_TYPE_1581 + || drv->type == DRIVE_TYPE_2000 + || drv->type == DRIVE_TYPE_4000) { + if (SMW_BA(m, drv->drive_ram, 0x2000) < 0) { goto fail; } } - if (drive_check_old(drv->drive->type)) { - if (SMW_BA(m, drv->drive->drive_ram, 0x1100) < 0) { + if (drive_check_old(drv->type)) { + if (SMW_BA(m, drv->drive_ram, 0x1100) < 0) { goto fail; } } @@ -4033,12 +4413,12 @@ int drivecpu_snapshot_write_module(drive_context_t *drv, snapshot_t *s) return -1; } -int drivecpu_snapshot_read_module(drive_context_t *drv, snapshot_t *s) +int drivecpu_snapshot_read_module(diskunit_context_t *drv, snapshot_t *s) { - BYTE major, minor; + uint8_t major, minor; snapshot_module_t *m; - BYTE a, x, y, sp, status; - WORD pc; + uint8_t a, x, y, sp, status; + uint16_t pc; drivecpu_context_t *cpu; cpu = drv->cpu; @@ -4053,7 +4433,7 @@ int drivecpu_snapshot_read_module(drive_context_t *drv, snapshot_t *s) /* XXX: Assumes `CLOCK' is the same size as a `DWORD'. */ if (0 - || SMR_DW(m, drv->clk_ptr) < 0 + || SMR_CLOCK(m, drv->clk_ptr) < 0 || SMR_B(m, &a) < 0 || SMR_B(m, &x) < 0 || SMR_B(m, &y) < 0 @@ -4061,10 +4441,11 @@ int drivecpu_snapshot_read_module(drive_context_t *drv, snapshot_t *s) || SMR_W(m, &pc) < 0 || SMR_B(m, &status) < 0 || SMR_DW_UINT(m, &(cpu->last_opcode_info)) < 0 - || SMR_DW(m, &(cpu->last_clk)) < 0 - || SMR_DW(m, &(cpu->cycle_accum)) < 0 - || SMR_DW(m, &(cpu->last_exc_cycles)) < 0 - || SMR_DW(m, &(cpu->stop_clk)) < 0 + || SMR_CLOCK(m, &(cpu->last_clk)) < 0 + || SMR_CLOCK(m, &(cpu->cycle_accum)) < 0 + || SMR_CLOCK(m, &(cpu->last_exc_cycles)) < 0 + || SMR_CLOCK(m, &(cpu->stop_clk)) < 0 + || SMR_B(m, &(cpu->cpu_last_data)) < 0 ) { goto fail; } @@ -4076,7 +4457,7 @@ int drivecpu_snapshot_read_module(drive_context_t *drv, snapshot_t *s) MOS6510_REGS_SET_PC(&(cpu->cpu_regs), pc); MOS6510_REGS_SET_STATUS(&(cpu->cpu_regs), status); - log_message(drv->drive->log, "RESET (For undump)."); + log_message(drv->log, "RESET (For undump)."); interrupt_cpu_status_reset(cpu->int_status); @@ -4086,29 +4467,29 @@ int drivecpu_snapshot_read_module(drive_context_t *drv, snapshot_t *s) goto fail; } - if (drv->drive->type == DRIVE_TYPE_1540 - || drv->drive->type == DRIVE_TYPE_1541 - || drv->drive->type == DRIVE_TYPE_1541II - || drv->drive->type == DRIVE_TYPE_1551 - || drv->drive->type == DRIVE_TYPE_1570 - || drv->drive->type == DRIVE_TYPE_1571 - || drv->drive->type == DRIVE_TYPE_1571CR - || drv->drive->type == DRIVE_TYPE_2031) { - if (SMR_BA(m, drv->drive->drive_ram, 0x800) < 0) { + if (drv->type == DRIVE_TYPE_1540 + || drv->type == DRIVE_TYPE_1541 + || drv->type == DRIVE_TYPE_1541II + || drv->type == DRIVE_TYPE_1551 + || drv->type == DRIVE_TYPE_1570 + || drv->type == DRIVE_TYPE_1571 + || drv->type == DRIVE_TYPE_1571CR + || drv->type == DRIVE_TYPE_2031) { + if (SMR_BA(m, drv->drive_ram, 0x800) < 0) { goto fail; } } - if (drv->drive->type == DRIVE_TYPE_1581 - || drv->drive->type == DRIVE_TYPE_2000 - || drv->drive->type == DRIVE_TYPE_4000) { - if (SMR_BA(m, drv->drive->drive_ram, 0x2000) < 0) { + if (drv->type == DRIVE_TYPE_1581 + || drv->type == DRIVE_TYPE_2000 + || drv->type == DRIVE_TYPE_4000) { + if (SMR_BA(m, drv->drive_ram, 0x2000) < 0) { goto fail; } } - if (drive_check_old(drv->drive->type)) { - if (SMR_BA(m, drv->drive->drive_ram, 0x1100) < 0) { + if (drive_check_old(drv->type)) { + if (SMR_BA(m, drv->drive_ram, 0x1100) < 0) { goto fail; } } diff --git a/src/Emulators/vice/drive/drivecpu.h b/src/Emulators/vice/drive/drivecpu.h index a9a3ebc5..d3243855 100644 --- a/src/Emulators/vice/drive/drivecpu.h +++ b/src/Emulators/vice/drive/drivecpu.h @@ -37,27 +37,26 @@ #define OPINFO_NUMBER(opinfo) \ ((opinfo) & OPINFO_NUMBER_MSK) -struct drive_context_s; +struct diskunit_context_s; struct interrupt_cpu_status_s; struct monitor_interface_s; struct snapshot_s; -extern void drivecpu_setup_context(struct drive_context_s *drv, int i); - -extern void drivecpu_init(struct drive_context_s *drv, int type); -extern void drivecpu_reset(struct drive_context_s *drv); -extern void drivecpu_sleep(struct drive_context_s *drv); -extern void drivecpu_wake_up(struct drive_context_s *drv); -extern CLOCK drivecpu_prevent_clk_overflow(struct drive_context_s *drv, CLOCK sub); -extern void drivecpu_shutdown(struct drive_context_s *drv); -extern void drivecpu_reset_clk(struct drive_context_s *drv); -extern void drivecpu_trigger_reset(unsigned int dnr); -extern void drivecpu_set_overflow(struct drive_context_s *drv); - -extern void drivecpu_execute(struct drive_context_s *drv, CLOCK clk_value); -extern int drivecpu_snapshot_write_module(struct drive_context_s *drv, - struct snapshot_s *s); -extern int drivecpu_snapshot_read_module(struct drive_context_s *drv, - struct snapshot_s *s); +void drivecpu_setup_context(struct diskunit_context_s *drv, int i); + +void drivecpu_init(struct diskunit_context_s *drv, int type); +void drivecpu_reset(struct diskunit_context_s *drv); +void drivecpu_sleep(struct diskunit_context_s *drv); +void drivecpu_wake_up(struct diskunit_context_s *drv); +void drivecpu_shutdown(struct diskunit_context_s *drv); +void drivecpu_reset_clk(struct diskunit_context_s *drv); +void drivecpu_trigger_reset(unsigned int dnr); +void drivecpu_set_overflow(struct diskunit_context_s *drv); + +void drivecpu_execute(struct diskunit_context_s *drv, CLOCK clk_value); +int drivecpu_snapshot_write_module(struct diskunit_context_s *drv, + struct snapshot_s *s); +int drivecpu_snapshot_read_module(struct diskunit_context_s *drv, + struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/drive/drivecpu65c02.c b/src/Emulators/vice/drive/drivecpu65c02.c index 431d32a0..7b6509c8 100644 --- a/src/Emulators/vice/drive/drivecpu65c02.c +++ b/src/Emulators/vice/drive/drivecpu65c02.c @@ -1,8 +1,7 @@ -/* - * drivecpu65c02.c - R65C02 processor emulation of CMD fd2000/4000 disk drives. +/** \file drivecpu65c02.c + * \brief 65C02 processor emulation of CMD FD2000/4000 and HD drives * - * Written by - * Kajtar Zsolt + * \author Kajtar Zsolt * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -31,7 +30,6 @@ #include "6510core.h" /* using 6510core.h because the registers are the same */ #include "alarm.h" -#include "clkguard.h" #include "debug.h" #include "drive.h" #include "drivecpu65c02.h" @@ -49,15 +47,16 @@ #include "rotation.h" #include "snapshot.h" #include "vicetypes.h" +#include "uiapi.h" #define DRIVE_CPU static void drivecpu65c02_set_bank_base(void *context); -static interrupt_cpu_status_t *drivecpu_int_status_ptr[DRIVE_NUM]; +static interrupt_cpu_status_t *drivecpu_int_status_ptr[NUM_DISK_UNITS]; -void drivecpu65c02_setup_context(struct drive_context_s *drv, int i) +void drivecpu65c02_setup_context(struct diskunit_context_s *drv, int i) { monitor_interface_t *mi; drivecpu_context_t *cpu; @@ -81,8 +80,8 @@ void drivecpu65c02_setup_context(struct drive_context_s *drv, int i) cpu->d_bank_start = 0; cpu->pageone = NULL; if (i) { - cpu->snap_module_name = lib_msprintf("DRIVECPU%d", drv->mynumber); - cpu->identification_string = lib_msprintf("DRIVE#%d", drv->mynumber + 8); + cpu->snap_module_name = lib_msprintf("DRIVECPU%u", drv->mynumber); + cpu->identification_string = lib_msprintf("DRIVE#%u", drv->mynumber + 8); cpu->monitor_interface = monitor_interface_new(); } mi = cpu->monitor_interface; @@ -94,44 +93,46 @@ void drivecpu65c02_setup_context(struct drive_context_s *drv, int i) mi->z80_cpu_regs = NULL; mi->h6809_cpu_regs = NULL; mi->int_status = cpu->int_status; - mi->clk = &(drive_clk[drv->mynumber]); + mi->clk = &(diskunit_clk[drv->mynumber]); mi->current_bank = 0; mi->mem_bank_list = NULL; + mi->mem_bank_list_nos = NULL; mi->mem_bank_from_name = NULL; mi->get_line_cycle = NULL; + mi->mem_bank_read = drivemem_bank_read; mi->mem_bank_peek = drivemem_bank_peek; mi->mem_bank_write = drivemem_bank_store; + mi->mem_bank_poke = drivemem_bank_poke; + mi->mem_ioreg_list_get = drivemem_ioreg_list_get; mi->toggle_watchpoints_func = drivemem_toggle_watchpoints; mi->set_bank_base = drivecpu65c02_set_bank_base; cpu->monspace = monitor_diskspace_mem(drv->mynumber); if (i) { - drv->cpu->clk_guard = clk_guard_new(drv->clk_ptr, CLOCK_MAX - CLKGUARD_SUB_MIN); - drv->cpu->alarm_context = alarm_context_new(drv->cpu->identification_string); } } /* ------------------------------------------------------------------------- */ -#define LOAD(a) (*drv->cpud->read_func_ptr[(a) >> 8])(drv, (WORD)(a)) -#define LOAD_ZERO(a) (*drv->cpud->read_func_ptr[0])(drv, (WORD)(a)) +#define LOAD(a) (*drv->cpud->read_func_ptr[(a) >> 8])(drv, (uint16_t)(a)) +#define LOAD_ZERO(a) (*drv->cpud->read_func_ptr[0])(drv, (uint16_t)(a)) #define LOAD_ADDR(a) (LOAD((a)) | (LOAD((a) + 1) << 8)) #define LOAD_ZERO_ADDR(a) (LOAD_ZERO((a)) | (LOAD_ZERO((a) + 1) << 8)) -#define STORE(a, b) (*drv->cpud->store_func_ptr[(a) >> 8])(drv, (WORD)(a), (BYTE)(b)) -#define STORE_ZERO(a, b) (*drv->cpud->store_func_ptr[0])(drv, (WORD)(a), (BYTE)(b)) +#define STORE(a, b) (*drv->cpud->store_func_ptr[(a) >> 8])(drv, (uint16_t)(a), (uint8_t)(b)) +#define STORE_ZERO(a, b) (*drv->cpud->store_func_ptr[0])(drv, (uint16_t)(a), (uint8_t)(b)) #define JUMP(addr) \ do { \ reg_pc = (unsigned int)(addr); \ if (reg_pc >= cpu->d_bank_limit || reg_pc < cpu->d_bank_start) { \ - BYTE *p = drv->cpud->read_base_tab_ptr[reg_pc >> 8]; \ + uint8_t *p = drv->cpud->read_base_tab_ptr[reg_pc >> 8]; \ cpu->d_bank_base = p; \ \ if (p != NULL) { \ - DWORD limits = drv->cpud->read_limit_tab_ptr[reg_pc >> 8]; \ + uint32_t limits = drv->cpud->read_limit_tab_ptr[reg_pc >> 8]; \ cpu->d_bank_limit = limits & 0xffff; \ cpu->d_bank_start = limits >> 16; \ } else { \ @@ -143,18 +144,20 @@ void drivecpu65c02_setup_context(struct drive_context_s *drv, int i) /* ------------------------------------------------------------------------- */ -static void cpu_reset(drive_context_t *drv) +static void cpu_reset(diskunit_context_t *drv) { int preserve_monitor; preserve_monitor = drv->cpu->int_status->global_pending_int & IK_MONITOR; - log_message(drv->drive->log, "RESET."); + log_message(drv->log, "RESET."); + ui_display_reset(drv->mynumber + DRIVE_UNIT_MIN, 0); interrupt_cpu_status_reset(drv->cpu->int_status); *(drv->clk_ptr) = 6; - rotation_reset(drv->drive); + rotation_reset(drv->drives[0]); + rotation_reset(drv->drives[1]); machine_drive_reset(drv); if (preserve_monitor) { @@ -162,14 +165,14 @@ static void cpu_reset(drive_context_t *drv) } } -void drivecpu65c02_reset_clk(drive_context_t *drv) +void drivecpu65c02_reset_clk(diskunit_context_t *drv) { drv->cpu->last_clk = maincpu_clk; drv->cpu->last_exc_cycles = 0; drv->cpu->stop_clk = 0; } -void drivecpu65c02_reset(drive_context_t *drv) +void drivecpu65c02_reset(diskunit_context_t *drv) { int preserve_monitor; @@ -190,10 +193,10 @@ void drivecpu65c02_reset(drive_context_t *drv) void drivecpu65c02_trigger_reset(unsigned int dnr) { - interrupt_trigger_reset(drivecpu_int_status_ptr[dnr], drive_clk[dnr] + 1); + interrupt_trigger_reset(drivecpu_int_status_ptr[dnr], diskunit_clk[dnr] + 1); } -void drivecpu65c02_shutdown(drive_context_t *drv) +void drivecpu65c02_shutdown(diskunit_context_t *drv) { drivecpu_context_t *cpu; @@ -202,9 +205,6 @@ void drivecpu65c02_shutdown(drive_context_t *drv) if (cpu->alarm_context != NULL) { alarm_context_destroy(cpu->alarm_context); } - if (cpu->clk_guard != NULL) { - clk_guard_destroy(cpu->clk_guard); - } monitor_interface_destroy(cpu->monitor_interface); interrupt_cpu_status_destroy(cpu->int_status); @@ -219,56 +219,36 @@ void drivecpu65c02_shutdown(drive_context_t *drv) lib_free(cpu); } -void drivecpu65c02_init(drive_context_t *drv, int type) +/* TODO: check type is always already set, and remove it as parameter */ +void drivecpu65c02_init(diskunit_context_t *drv, int type) { - drivemem_init(drv, type); + drv->type = type; + drivemem_init(drv); drivecpu65c02_reset(drv); } -void drivecpu65c02_wake_up(drive_context_t *drv) +void drivecpu65c02_wake_up(diskunit_context_t *drv) { /* FIXME: this value could break some programs, or be way too high for others. Maybe we should put it into a user-definable resource. */ if (maincpu_clk - drv->cpu->last_clk > 0xffffff && *(drv->clk_ptr) > 934639) { - log_message(drv->drive->log, "Skipping cycles."); + log_message(drv->log, "Skipping cycles."); drv->cpu->last_clk = maincpu_clk; } } -void drivecpu65c02_sleep(drive_context_t *drv) +void drivecpu65c02_sleep(diskunit_context_t *drv) { /* Currently does nothing. But we might need this hook some day. */ } -/* Make sure the drive clock counters never overflow; return nonzero if - they have been decremented to prevent overflow. */ -CLOCK drivecpu65c02_prevent_clk_overflow(drive_context_t *drv, CLOCK sub) -{ - if (sub != 0) { - /* First, get in sync with what the main CPU has done. Notice that - `clk' has already been decremented at this point. */ - if (drv->drive->enable) { - if (drv->cpu->last_clk < sub) { - /* Hm, this is kludgy. :-( */ - drive_cpu_execute_all(maincpu_clk + sub); - } - drv->cpu->last_clk -= sub; - } else { - drv->cpu->last_clk = maincpu_clk; - } - } - - /* Then, check our own clock counters. */ - return clk_guard_prevent_overflow(drv->cpu->clk_guard); -} - /* Handle a ROM trap. */ -inline static DWORD drive_trap_handler(drive_context_t *drv) +inline static uint32_t drive_trap_handler(diskunit_context_t *drv) { - if (R65C02_REGS_GET_PC(&(drv->cpu->cpu_R65C02_regs)) == (WORD)drv->drive->trap) { - R65C02_REGS_SET_PC(&(drv->cpu->cpu_R65C02_regs), drv->drive->trapcont); - if (drv->drive->idling_method == DRIVE_IDLE_TRAP_IDLE) { + if (R65C02_REGS_GET_PC(&(drv->cpu->cpu_R65C02_regs)) == (uint16_t)drv->trap) { + R65C02_REGS_SET_PC(&(drv->cpu->cpu_R65C02_regs), drv->trapcont); + if (drv->idling_method == DRIVE_IDLE_TRAP_IDLE) { CLOCK next_clk; next_clk = alarm_context_next_pending_clk(drv->cpu->alarm_context); @@ -281,7 +261,7 @@ inline static DWORD drive_trap_handler(drive_context_t *drv) } return 0; } - return (DWORD)-1; + return (uint32_t)-1; } static void drive_generic_dma(void) @@ -349,17 +329,12 @@ inline static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs, #define CPU_R65C02 1 #define CPU_65SC02 2 -/* MPi: For some reason MSVC is generating a compiler fatal error when optimising this function? */ -#ifdef _MSC_VER -#pragma optimize("",off) -#endif -/* -------------------------------------------------------------------------- */ /* Execute up to the current main CPU clock value. This automatically calculates the corresponding number of clock ticks in the drive. */ -void drivecpu65c02_execute(drive_context_t *drv, CLOCK clk_value) +void drivecpu65c02_execute(diskunit_context_t *drv, CLOCK clk_value) { CLOCK cycles; - int tcycles; + CLOCK tcycles; drivecpu_context_t *cpu; int cpu_type = CPU_R65C02; @@ -371,6 +346,7 @@ void drivecpu65c02_execute(drive_context_t *drv, CLOCK clk_value) #define reg_p (cpu->cpu_R65C02_regs.p) #define flag_z (cpu->cpu_R65C02_regs.z) #define flag_n (cpu->cpu_R65C02_regs.n) +#define ORIGIN_MEMSPACE (drv->mynumber + e_disk8_space) cpu = drv->cpu; @@ -2086,9 +2062,9 @@ opcode.op.op8[0] = ((o) >> 16) & 0xff; \ } #endif if (p0 == 0x20) { - monitor_cpuhistory_store(reg_pc, p0, p1, LOAD(reg_pc + 2), reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS()); + monitor_cpuhistory_store(CLK, reg_pc, p0, p1, LOAD(reg_pc + 2), reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS(), ORIGIN_MEMSPACE); /* VICE 3.10: + cycle (CLK) and origin (MEMSPACE) */ } else { - monitor_cpuhistory_store(reg_pc, p0, p1, p2 >> 8, reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS()); + monitor_cpuhistory_store(CLK, reg_pc, p0, p1, p2 >> 8, reg_a, reg_x, reg_y, reg_sp, LOCAL_STATUS(), ORIGIN_MEMSPACE); } memmap_state &= ~(MEMMAP_STATE_INSTR | MEMMAP_STATE_OPCODE); #endif @@ -3032,18 +3008,15 @@ opcode.op.op8[0] = ((o) >> 16) & 0xff; \ drivecpu65c02_sleep(drv); } -#ifdef _MSC_VER -#pragma optimize("",on) -#endif /* ------------------------------------------------------------------------- */ static void drivecpu65c02_set_bank_base(void *context) { - drive_context_t *drv; + diskunit_context_t *drv; drivecpu_context_t *cpu; - drv = (drive_context_t *)context; + drv = (diskunit_context_t *)context; cpu = drv->cpu; JUMP(reg_pc); @@ -3052,9 +3025,9 @@ static void drivecpu65c02_set_bank_base(void *context) /* ------------------------------------------------------------------------- */ #define SNAP_MAJOR 1 -#define SNAP_MINOR 1 +#define SNAP_MINOR 3 -int drivecpu65c02_snapshot_write_module(drive_context_t *drv, snapshot_t *s) +int drivecpu65c02_snapshot_write_module(diskunit_context_t *drv, snapshot_t *s) { snapshot_module_t *m; drivecpu_context_t *cpu; @@ -3062,24 +3035,25 @@ int drivecpu65c02_snapshot_write_module(drive_context_t *drv, snapshot_t *s) cpu = drv->cpu; m = snapshot_module_create(s, drv->cpu->snap_module_name, - ((BYTE)(SNAP_MAJOR)), ((BYTE)(SNAP_MINOR))); + ((uint8_t)(SNAP_MAJOR)), ((uint8_t)(SNAP_MINOR))); if (m == NULL) { return -1; } if (0 - || SMW_DW(m, (DWORD) *(drv->clk_ptr)) < 0 - || SMW_B(m, (BYTE)R65C02_REGS_GET_A(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_B(m, (BYTE)R65C02_REGS_GET_X(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_B(m, (BYTE)R65C02_REGS_GET_Y(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_B(m, (BYTE)R65C02_REGS_GET_SP(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_W(m, (WORD)R65C02_REGS_GET_PC(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_B(m, (BYTE)R65C02_REGS_GET_STATUS(&(cpu->cpu_R65C02_regs))) < 0 - || SMW_DW(m, (DWORD)(cpu->last_opcode_info)) < 0 - || SMW_DW(m, (DWORD)(cpu->last_clk)) < 0 - || SMW_DW(m, (DWORD)(cpu->cycle_accum)) < 0 - || SMW_DW(m, (DWORD)(cpu->last_exc_cycles)) < 0 - || SMW_DW(m, (DWORD)(cpu->stop_clk)) < 0 + || SMW_DW(m, (uint32_t) *(drv->clk_ptr)) < 0 + || SMW_B(m, (uint8_t)R65C02_REGS_GET_A(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_B(m, (uint8_t)R65C02_REGS_GET_X(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_B(m, (uint8_t)R65C02_REGS_GET_Y(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_B(m, (uint8_t)R65C02_REGS_GET_SP(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_W(m, (uint16_t)R65C02_REGS_GET_PC(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_B(m, (uint8_t)R65C02_REGS_GET_STATUS(&(cpu->cpu_R65C02_regs))) < 0 + || SMW_DW(m, (uint32_t)(cpu->last_opcode_info)) < 0 + || SMW_DW(m, (uint32_t)(cpu->last_clk)) < 0 + || SMW_DW(m, (uint32_t)(cpu->cycle_accum)) < 0 + || SMW_DW(m, (uint32_t)(cpu->last_exc_cycles)) < 0 + || SMW_DW(m, (uint32_t)(cpu->stop_clk)) < 0 + || SMW_B(m, cpu->cpu_last_data) < 0 ) { goto fail; } @@ -3088,9 +3062,15 @@ int drivecpu65c02_snapshot_write_module(drive_context_t *drv, snapshot_t *s) goto fail; } - if (drv->drive->type == DRIVE_TYPE_2000 - || drv->drive->type == DRIVE_TYPE_4000) { - if (SMW_BA(m, drv->drive->drive_ram, 0x2000) < 0) { + if (drv->type == DRIVE_TYPE_2000 + || drv->type == DRIVE_TYPE_4000) { + if (SMW_BA(m, drv->drive_ram, 0x2000) < 0) { + goto fail; + } + } + + if (drv->type == DRIVE_TYPE_CMDHD) { + if (SMW_BA(m, drv->drive_ram, 0x10000) < 0) { goto fail; } } @@ -3108,12 +3088,12 @@ int drivecpu65c02_snapshot_write_module(drive_context_t *drv, snapshot_t *s) return -1; } -int drivecpu65c02_snapshot_read_module(drive_context_t *drv, snapshot_t *s) +int drivecpu65c02_snapshot_read_module(diskunit_context_t *drv, snapshot_t *s) { - BYTE major, minor; + uint8_t major, minor; snapshot_module_t *m; - BYTE a, x, y, sp, status; - WORD pc; + uint8_t a, x, y, sp, status; + uint16_t pc; drivecpu_context_t *cpu; cpu = drv->cpu; @@ -3128,7 +3108,7 @@ int drivecpu65c02_snapshot_read_module(drive_context_t *drv, snapshot_t *s) /* XXX: Assumes `CLOCK' is the same size as a `DWORD'. */ if (0 - || SMR_DW(m, drv->clk_ptr) < 0 + || SMR_CLOCK(m, drv->clk_ptr) < 0 || SMR_B(m, &a) < 0 || SMR_B(m, &x) < 0 || SMR_B(m, &y) < 0 @@ -3136,10 +3116,11 @@ int drivecpu65c02_snapshot_read_module(drive_context_t *drv, snapshot_t *s) || SMR_W(m, &pc) < 0 || SMR_B(m, &status) < 0 || SMR_DW_UINT(m, &(cpu->last_opcode_info)) < 0 - || SMR_DW(m, &(cpu->last_clk)) < 0 - || SMR_DW(m, &(cpu->cycle_accum)) < 0 - || SMR_DW(m, &(cpu->last_exc_cycles)) < 0 - || SMR_DW(m, &(cpu->stop_clk)) < 0 + || SMR_CLOCK(m, &(cpu->last_clk)) < 0 + || SMR_CLOCK(m, &(cpu->cycle_accum)) < 0 + || SMR_CLOCK(m, &(cpu->last_exc_cycles)) < 0 + || SMR_CLOCK(m, &(cpu->stop_clk)) < 0 + || SMR_B(m, &(cpu->cpu_last_data)) < 0 ) { goto fail; } @@ -3151,7 +3132,7 @@ int drivecpu65c02_snapshot_read_module(drive_context_t *drv, snapshot_t *s) R65C02_REGS_SET_PC(&(cpu->cpu_R65C02_regs), pc); R65C02_REGS_SET_STATUS(&(cpu->cpu_R65C02_regs), status); - log_message(drv->drive->log, "RESET (For undump)."); + log_message(drv->log, "RESET (For undump)."); interrupt_cpu_status_reset(cpu->int_status); @@ -3161,9 +3142,15 @@ int drivecpu65c02_snapshot_read_module(drive_context_t *drv, snapshot_t *s) goto fail; } - if (drv->drive->type == DRIVE_TYPE_2000 - || drv->drive->type == DRIVE_TYPE_4000) { - if (SMR_BA(m, drv->drive->drive_ram, 0x2000) < 0) { + if (drv->type == DRIVE_TYPE_2000 + || drv->type == DRIVE_TYPE_4000) { + if (SMR_BA(m, drv->drive_ram, 0x2000) < 0) { + goto fail; + } + } + + if (drv->type == DRIVE_TYPE_CMDHD) { + if (SMR_BA(m, drv->drive_ram, 0x10000) < 0) { goto fail; } } diff --git a/src/Emulators/vice/drive/drivecpu65c02.h b/src/Emulators/vice/drive/drivecpu65c02.h index 90743d2f..ace4eccd 100644 --- a/src/Emulators/vice/drive/drivecpu65c02.h +++ b/src/Emulators/vice/drive/drivecpu65c02.h @@ -36,24 +36,23 @@ #define OPINFO_NUMBER(opinfo) \ ((opinfo) & OPINFO_NUMBER_MSK) -struct drive_context_s; +struct diskunit_context_s; struct interrupt_cpu_status_s; struct monitor_interface_s; struct snapshot_s; -extern void drivecpu65c02_setup_context(struct drive_context_s *drv, int i); +void drivecpu65c02_setup_context(struct diskunit_context_s *drv, int i); -extern void drivecpu65c02_init(struct drive_context_s *drv, int type); -extern void drivecpu65c02_reset(struct drive_context_s *drv); -extern void drivecpu65c02_sleep(struct drive_context_s *drv); -extern void drivecpu65c02_wake_up(struct drive_context_s *drv); -extern CLOCK drivecpu65c02_prevent_clk_overflow(struct drive_context_s *drv, CLOCK sub); -extern void drivecpu65c02_shutdown(struct drive_context_s *drv); -extern void drivecpu65c02_reset_clk(struct drive_context_s *drv); -extern void drivecpu65c02_trigger_reset(unsigned int dnr); +void drivecpu65c02_init(struct diskunit_context_s *drv, int type); +void drivecpu65c02_reset(struct diskunit_context_s *drv); +void drivecpu65c02_sleep(struct diskunit_context_s *drv); +void drivecpu65c02_wake_up(struct diskunit_context_s *drv); +void drivecpu65c02_shutdown(struct diskunit_context_s *drv); +void drivecpu65c02_reset_clk(struct diskunit_context_s *drv); +void drivecpu65c02_trigger_reset(unsigned int dnr); -extern void drivecpu65c02_execute(struct drive_context_s *drv, CLOCK clk_value); -extern int drivecpu65c02_snapshot_write_module(struct drive_context_s *drv, struct snapshot_s *s); -extern int drivecpu65c02_snapshot_read_module(struct drive_context_s *drv, struct snapshot_s *s); +void drivecpu65c02_execute(struct diskunit_context_s *drv, CLOCK clk_value); +int drivecpu65c02_snapshot_write_module(struct diskunit_context_s *drv, struct snapshot_s *s); +int drivecpu65c02_snapshot_read_module(struct diskunit_context_s *drv, struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/drive/driveimage.c b/src/Emulators/vice/drive/driveimage.c index 80438ac1..2c81df1e 100644 --- a/src/Emulators/vice/drive/driveimage.c +++ b/src/Emulators/vice/drive/driveimage.c @@ -42,79 +42,120 @@ /* Logging goes here. */ static log_t driveimage_log = LOG_DEFAULT; -static int drive_check_image_format(unsigned int format, unsigned int dnr) +int drive_image_type_to_drive_type(unsigned int type) { - drive_t *drive; + switch (type) { + case DISK_IMAGE_TYPE_G64: + case DISK_IMAGE_TYPE_P64: + case DISK_IMAGE_TYPE_D64: + return DRIVE_TYPE_1541II; + case DISK_IMAGE_TYPE_G71: + case DISK_IMAGE_TYPE_D71: + return DRIVE_TYPE_1571; + case DISK_IMAGE_TYPE_D81: + return DRIVE_TYPE_1581; + case DISK_IMAGE_TYPE_D1M: + case DISK_IMAGE_TYPE_D2M: + return DRIVE_TYPE_2000; + case DISK_IMAGE_TYPE_D4M: + return DRIVE_TYPE_4000; + case DISK_IMAGE_TYPE_D67: + return DRIVE_TYPE_2040; + case DISK_IMAGE_TYPE_D80: + return DRIVE_TYPE_8050; + case DISK_IMAGE_TYPE_D82: + return DRIVE_TYPE_8250; + case DISK_IMAGE_TYPE_D90: + return DRIVE_TYPE_9000; + case DISK_IMAGE_TYPE_DHD: + return DRIVE_TYPE_CMDHD; + } + return DRIVE_TYPE_NONE; +} - drive = drive_context[dnr]->drive; +int drive_check_image_format(unsigned int format, unsigned int dnr) +{ + diskunit_context_t *unit = diskunit_context[dnr]; switch (format) { case DISK_IMAGE_TYPE_D64: case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_P64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: - if (drive->type != DRIVE_TYPE_1540 - && drive->type != DRIVE_TYPE_1541 - && drive->type != DRIVE_TYPE_1541II - && drive->type != DRIVE_TYPE_1551 - && drive->type != DRIVE_TYPE_1570 - && drive->type != DRIVE_TYPE_1571 - && drive->type != DRIVE_TYPE_1571CR - && drive->type != DRIVE_TYPE_2031 - && drive->type != DRIVE_TYPE_2040 /* FIXME: only read compat */ - && drive->type != DRIVE_TYPE_3040 - && drive->type != DRIVE_TYPE_4040) { +#endif + if (unit->type != DRIVE_TYPE_1540 + && unit->type != DRIVE_TYPE_1541 + && unit->type != DRIVE_TYPE_1541II + && unit->type != DRIVE_TYPE_1551 + && unit->type != DRIVE_TYPE_1570 + && unit->type != DRIVE_TYPE_1571 + && unit->type != DRIVE_TYPE_1571CR + && unit->type != DRIVE_TYPE_2031 + && unit->type != DRIVE_TYPE_2040 /* FIXME: only read compat */ + && unit->type != DRIVE_TYPE_3040 + && unit->type != DRIVE_TYPE_4040) { return -1; } break; case DISK_IMAGE_TYPE_G71: - if ((drive->type != DRIVE_TYPE_1571) - && (drive->type != DRIVE_TYPE_1571CR)) { + if ((unit->type != DRIVE_TYPE_1571) + && (unit->type != DRIVE_TYPE_1571CR)) { return -1; } break; case DISK_IMAGE_TYPE_D67: /* New drives and 2031, 3040 and 4040 are only read compatible. */ - if (drive->type != DRIVE_TYPE_1540 - && drive->type != DRIVE_TYPE_1541 - && drive->type != DRIVE_TYPE_1541II - && drive->type != DRIVE_TYPE_1551 - && drive->type != DRIVE_TYPE_1570 - && drive->type != DRIVE_TYPE_1571 - && drive->type != DRIVE_TYPE_1571CR - && drive->type != DRIVE_TYPE_2031 - && drive->type != DRIVE_TYPE_2040 - && drive->type != DRIVE_TYPE_3040 - && drive->type != DRIVE_TYPE_4040) { + if (unit->type != DRIVE_TYPE_1540 + && unit->type != DRIVE_TYPE_1541 + && unit->type != DRIVE_TYPE_1541II + && unit->type != DRIVE_TYPE_1551 + && unit->type != DRIVE_TYPE_1570 + && unit->type != DRIVE_TYPE_1571 + && unit->type != DRIVE_TYPE_1571CR + && unit->type != DRIVE_TYPE_2031 + && unit->type != DRIVE_TYPE_2040 + && unit->type != DRIVE_TYPE_3040 + && unit->type != DRIVE_TYPE_4040) { return -1; } break; case DISK_IMAGE_TYPE_D71: - if (drive->type != DRIVE_TYPE_1571 - && drive->type != DRIVE_TYPE_1571CR) { + if (unit->type != DRIVE_TYPE_1571 + && unit->type != DRIVE_TYPE_1571CR) { return -1; } break; case DISK_IMAGE_TYPE_D81: - if (drive->type != DRIVE_TYPE_1581 - && drive->type != DRIVE_TYPE_2000 - && drive->type != DRIVE_TYPE_4000) { + if (unit->type != DRIVE_TYPE_1581 + && unit->type != DRIVE_TYPE_2000 + && unit->type != DRIVE_TYPE_4000) { return -1; } break; case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: - if ((drive->type != DRIVE_TYPE_1001) - && (drive->type != DRIVE_TYPE_8050) - && (drive->type != DRIVE_TYPE_8250)) { + if ((unit->type != DRIVE_TYPE_1001) + && (unit->type != DRIVE_TYPE_8050) + && (unit->type != DRIVE_TYPE_8250)) { + return -1; + } + break; + case DISK_IMAGE_TYPE_D90: + if (unit->type != DRIVE_TYPE_9000) { return -1; } break; case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: - if (drive->type != DRIVE_TYPE_2000 - && drive->type != DRIVE_TYPE_4000) { + if (unit->type != DRIVE_TYPE_2000 + && unit->type != DRIVE_TYPE_4000) { + return -1; + } + break; + case DISK_IMAGE_TYPE_DHD: + if (unit->type != DRIVE_TYPE_CMDHD) { return -1; } break; @@ -125,28 +166,28 @@ static int drive_check_image_format(unsigned int format, unsigned int dnr) } /* Attach a disk image to the true drive emulation. */ -int drive_image_attach(disk_image_t *image, unsigned int unit) +int drive_image_attach(disk_image_t *image, unsigned int unit, unsigned int drv) { unsigned int dnr; drive_t *drive; - if (unit < 8 || unit >= 8 + DRIVE_NUM) { + if (unit < 8 || unit >= 8 + NUM_DISK_UNITS) { return -1; } dnr = unit - 8; - drive = drive_context[dnr]->drive; + drive = diskunit_context[dnr]->drives[drv]; if (drive_check_image_format(image->type, dnr) < 0) { return -1; } drive->read_only = image->read_only; - drive->attach_clk = drive_clk[dnr]; + drive->attach_clk = diskunit_clk[dnr]; if (drive->detach_clk > (CLOCK)0) { - drive->attach_detach_clk = drive_clk[dnr]; + drive->attach_detach_clk = diskunit_clk[dnr]; } - drive->ask_extend_disk_image = 1; + drive->ask_extend_disk_image = DRIVE_EXTEND_ASK; switch (image->type) { case DISK_IMAGE_TYPE_D64: @@ -154,9 +195,11 @@ int drive_image_attach(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_D71: case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: +#endif case DISK_IMAGE_TYPE_P64: - disk_image_attach_log(image, driveimage_log, unit); + disk_image_attach_log(image, driveimage_log, unit, drv); break; default: return -1; @@ -195,17 +238,19 @@ int drive_image_attach(disk_image_t *image, unsigned int unit) } /* Detach a disk image from the true drive emulation. */ -int drive_image_detach(disk_image_t *image, unsigned int unit) +int drive_image_detach(disk_image_t *image, unsigned int unit, unsigned int drv) { unsigned int dnr, i; + diskunit_context_t *diskunit; drive_t *drive; - if (unit < 8 || unit >= 8 + DRIVE_NUM) { + if (unit < 8 || unit >= 8 + NUM_DISK_UNITS) { return -1; } dnr = unit - 8; - drive = drive_context[dnr]->drive; + diskunit = diskunit_context[dnr]; + drive = diskunit->drives[drv]; if (drive->image != NULL) { switch (image->type) { @@ -215,8 +260,10 @@ int drive_image_detach(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: case DISK_IMAGE_TYPE_P64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: - disk_image_detach_log(image, driveimage_log, unit); +#endif + disk_image_detach_log(image, driveimage_log, unit, drv); break; default: return -1; @@ -226,7 +273,7 @@ int drive_image_detach(disk_image_t *image, unsigned int unit) if (drive->P64_image_loaded && drive->P64_dirty) { drive->P64_dirty = 0; if (disk_image_write_p64_image(drive->image) < 0) { - log_error(drive->log, "Cannot write disk image back."); + log_error(diskunit->log, "Cannot write disk image back."); } } else { drive_gcr_data_writeback(drive); @@ -239,7 +286,7 @@ int drive_image_detach(disk_image_t *image, unsigned int unit) drive->gcr->tracks[i].size = 0; } } - drive->detach_clk = drive_clk[dnr]; + drive->detach_clk = diskunit_clk[dnr]; drive->GCR_image_loaded = 0; drive->P64_image_loaded = 0; drive->GCR_dirty_track_for_snapshot = 1; diff --git a/src/Emulators/vice/drive/driveimage.h b/src/Emulators/vice/drive/driveimage.h index 672cda92..1870172d 100644 --- a/src/Emulators/vice/drive/driveimage.h +++ b/src/Emulators/vice/drive/driveimage.h @@ -30,10 +30,12 @@ struct disk_image_s; struct drive_s; -extern void drive_image_init(void); -extern void drive_image_init_track_size_d64(struct drive_s *drive); +void drive_image_init(void); +void drive_image_init_track_size_d64(struct drive_s *drive); +int drive_check_image_format(unsigned int format, unsigned int dnr); +int drive_image_type_to_drive_type(unsigned int type); -extern int drive_image_attach(struct disk_image_s *image, unsigned int unit); -extern int drive_image_detach(struct disk_image_s *image, unsigned int unit); +int drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive); +int drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive); #endif diff --git a/src/Emulators/vice/drive/drivemem.c b/src/Emulators/vice/drive/drivemem.c index 94ebe7b7..aff54615 100644 --- a/src/Emulators/vice/drive/drivemem.c +++ b/src/Emulators/vice/drive/drivemem.c @@ -30,6 +30,7 @@ #include #include +#include "cartio.h" #include "ciad.h" #include "drive.h" #include "drivemem.h" @@ -40,81 +41,117 @@ #include "machine-drive.h" #include "mem.h" #include "monitor.h" -#include "riotd.h" +#include "riot.h" #include "tpid.h" #include "vicetypes.h" #include "via1d1541.h" #include "via4000.h" #include "viad.h" +#include "pc8477.h" +#include "wd1770.h" +#include "cmdhd.h" + +/* #define DEBUG_DRIVEMEM */ + +#ifdef DEBUG_DRIVEMEM +#define LOG(x) log_printf x +#else +#define LOG(x) +#endif #include "ViceWrapper.h" +#include "vice_debugger_hook.h" static drive_read_func_t *read_tab_watch[0x101]; static drive_store_func_t *store_tab_watch[0x101]; +/* Current watchpoint state. + 0 = no watchpoints + bit0; 1 = watchpoints active + bit1; 2 = watchpoints trigger on dummy accesses +*/ +static int watchpoints_active = 0; + /* ------------------------------------------------------------------------- */ /* Common memory access. */ -static BYTE drive_read_free(drive_context_t *drv, WORD address) +static uint8_t drive_read_free(diskunit_context_t *drv, uint16_t address) { - c64d_mark_drive1541_cell_read(address); + VICE_HOOK_DRIVE_CELL_READ(address); - return address >> 8; + LOG(("%04x %02x drive_read_free", address, drv->cpu->cpu_last_data)); + return drv->cpu->cpu_last_data; } -static void drive_store_free(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_free(diskunit_context_t *drv, uint16_t address, uint8_t value) { - c64d_mark_drive1541_cell_write(address, value); - + VICE_HOOK_DRIVE_CELL_WRITE(address, value); + + drv->cpu->cpu_last_data = value; return; } -BYTE drive_peek_free(drive_context_t *drv, WORD address) +uint8_t drive_peek_free(diskunit_context_t *drv, uint16_t address) { - return 0; + LOG(("%04x %02x drive_peek_free", address, drv->cpu->cpu_last_data)); + return drv->cpu->cpu_last_data; } /* ------------------------------------------------------------------------- */ /* Watchpoint memory access. */ -static BYTE drive_zero_read_watch(drive_context_t *drv, WORD addr) +static uint8_t drive_zero_read_watch(diskunit_context_t *drv, uint16_t addr) { addr &= 0xff; monitor_watch_push_load_addr(addr, drv->cpu->monspace); - return drv->cpud->read_tab[0][0](drv, addr); + return drv->cpu->cpu_last_data = drv->cpud->read_tab[0][0](drv, addr); } -static void drive_zero_store_watch(drive_context_t *drv, WORD addr, BYTE value) +static void drive_zero_store_watch(diskunit_context_t *drv, uint16_t addr, uint8_t value) { addr &= 0xff; + drv->cpu->cpu_last_data = value; monitor_watch_push_store_addr(addr, drv->cpu->monspace); drv->cpud->store_tab[0][0](drv, addr, value); } -static BYTE drive_read_watch(drive_context_t *drv, WORD address) +static uint8_t drive_read_watch(diskunit_context_t *drv, uint16_t address) { + LOG(("%04x %02x drive_read_watch\n", address, drv->cpud->read_tab[0][address >> 8](drv, address))); monitor_watch_push_load_addr(address, drv->cpu->monspace); - return drv->cpud->read_tab[0][address >> 8](drv, address); + return drv->cpu->cpu_last_data = drv->cpud->read_tab[0][address >> 8](drv, address); } -static void drive_store_watch(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_watch(diskunit_context_t *drv, uint16_t address, uint8_t value) { + drv->cpu->cpu_last_data = value; monitor_watch_push_store_addr(address, drv->cpu->monspace); drv->cpud->store_tab[0][address >> 8](drv, address, value); } void drivemem_toggle_watchpoints(int flag, void *context) { - drive_context_t *drv = (drive_context_t *)context; + diskunit_context_t *drv = (diskunit_context_t *)context; if (flag) { drv->cpud->read_func_ptr = read_tab_watch; drv->cpud->store_func_ptr = store_tab_watch; + if (flag > 1) { + /* enable watchpoints on dummy accesses */ + drv->cpud->read_func_ptr_dummy = read_tab_watch; + drv->cpud->store_func_ptr_dummy = store_tab_watch; + } else { + drv->cpud->read_func_ptr_dummy = drv->cpud->read_tab[0]; + drv->cpud->store_func_ptr_dummy = drv->cpud->store_tab[0]; + } } else { drv->cpud->read_func_ptr = drv->cpud->read_tab[0]; drv->cpud->store_func_ptr = drv->cpud->store_tab[0]; + drv->cpud->read_func_ptr_dummy = drv->cpud->read_tab[0]; + drv->cpud->store_func_ptr_dummy = drv->cpud->store_tab[0]; } + watchpoints_active = flag; } /* ------------------------------------------------------------------------- */ @@ -124,7 +161,7 @@ void drivemem_set_func(drivecpud_context_t *cpud, drive_read_func_t *read_func, drive_store_func_t *store_func, drive_peek_func_t *peek_func, - BYTE *base, DWORD limit) + uint8_t *base, uint32_t limit) { unsigned int i; @@ -156,30 +193,36 @@ void drivemem_set_func(drivecpud_context_t *cpud, /* ------------------------------------------------------------------------- */ /* This is the external interface for banked memory access. */ -BYTE drivemem_bank_read(int bank, WORD addr, void *context) +uint8_t drivemem_bank_read(int bank, uint16_t addr, void *context) { - drive_context_t *drv = (drive_context_t *)context; + diskunit_context_t *drv = (diskunit_context_t *)context; return drv->cpud->read_func_ptr[addr >> 8](drv, addr); } -BYTE drivemem_bank_peek(int bank, WORD addr, void *context) +/* used by monitor when sfx off */ +uint8_t drivemem_bank_peek(int bank, uint16_t addr, void *context) { - drive_context_t *drv = (drive_context_t *)context; + diskunit_context_t *drv = (diskunit_context_t *)context; return drv->cpud->peek_func_ptr[addr >> 8](drv, addr); } -void drivemem_bank_store(int bank, WORD addr, BYTE value, void *context) +void drivemem_bank_store(int bank, uint16_t addr, uint8_t value, void *context) { - drive_context_t *drv = (drive_context_t *)context; - + diskunit_context_t *drv = (diskunit_context_t *)context; drv->cpud->store_func_ptr[addr >> 8](drv, addr, value); } +/* used by monitor when sfx off */ +void drivemem_bank_poke(int bank, uint16_t addr, uint8_t value, void *context) +{ + drivemem_bank_store(bank, addr, value, context); +} + /* ------------------------------------------------------------------------- */ -void drivemem_init(drive_context_t *drv, unsigned int type) +void drivemem_init(diskunit_context_t *unit) { int i; @@ -193,20 +236,22 @@ void drivemem_init(drive_context_t *drv, unsigned int type) } } - drivemem_set_func(drv->cpud, 0x00, 0x101, drive_read_free, drive_store_free, drive_peek_free, NULL, 0); + drivemem_set_func(unit->cpud, 0x00, 0x101, drive_read_free, drive_store_free, drive_peek_free, NULL, 0); - machine_drive_mem_init(drv, type); + machine_drive_mem_init(unit, unit->type); - drv->cpud->read_tab[0][0x100] = drv->cpud->read_tab[0][0]; - drv->cpud->store_tab[0][0x100] = drv->cpud->store_tab[0][0]; - drv->cpud->peek_tab[0][0x100] = drv->cpud->peek_tab[0][0]; + unit->cpud->read_tab[0][0x100] = unit->cpud->read_tab[0][0]; + unit->cpud->store_tab[0][0x100] = unit->cpud->store_tab[0][0]; + unit->cpud->peek_tab[0][0x100] = unit->cpud->peek_tab[0][0]; - drv->cpud->read_func_ptr = drv->cpud->read_tab[0]; - drv->cpud->store_func_ptr = drv->cpud->store_tab[0]; - drv->cpud->peek_func_ptr = drv->cpud->peek_tab[0]; + unit->cpud->read_func_ptr = unit->cpud->read_tab[0]; + unit->cpud->store_func_ptr = unit->cpud->store_tab[0]; + unit->cpud->read_func_ptr_dummy = unit->cpud->read_tab[0]; + unit->cpud->store_func_ptr_dummy = unit->cpud->store_tab[0]; + unit->cpud->peek_func_ptr = unit->cpud->peek_tab[0]; - drv->cpud->read_base_tab_ptr = drv->cpud->read_base_tab[0]; - drv->cpud->read_limit_tab_ptr = drv->cpud->read_limit_tab[0]; + unit->cpud->read_base_tab_ptr = unit->cpud->read_base_tab[0]; + unit->cpud->read_limit_tab_ptr = unit->cpud->read_limit_tab[0]; } mem_ioreg_list_t *drivemem_ioreg_list_get(void *context) @@ -214,38 +259,48 @@ mem_ioreg_list_t *drivemem_ioreg_list_get(void *context) unsigned int type; mem_ioreg_list_t *drivemem_ioreg_list = NULL; - type = ((drive_context_t *)context)->drive->type; + type = ((diskunit_context_t *)context)->type; switch (type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: case DRIVE_TYPE_2031: - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA1", 0x1800, 0x180f, via1d1541_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA2", 0x1c00, 0x1c0f, via2d_dump, context); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA1", 0x1800, 0x180f, via1d1541_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA2", 0x1c00, 0x1c0f, via2d_dump, context, IO_MIRROR_NONE); break; case DRIVE_TYPE_1551: - mon_ioreg_add_list(&drivemem_ioreg_list, "TPI", 0x4000, 0x4007, tpid_dump, context); + mon_ioreg_add_list(&drivemem_ioreg_list, "TPI", 0x4000, 0x4007, tpid_dump, context, IO_MIRROR_NONE); break; case DRIVE_TYPE_1570: case DRIVE_TYPE_1571: + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA1", 0x1800, 0x180f, via1d1541_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA2", 0x1c00, 0x1c0f, via2d_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "WD1770", 0x2000, 0x2003, wd1770d_dump, context, IO_MIRROR_NONE); /* FIXME: register dump function */ + mon_ioreg_add_list(&drivemem_ioreg_list, "CIA", 0x4000, 0x400f, cia1571_dump, context, IO_MIRROR_NONE); + break; case DRIVE_TYPE_1571CR: - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA1", 0x1800, 0x180f, via1d1541_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA2", 0x1c00, 0x1c0f, via2d_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "WD1770", 0x2000, 0x2003, NULL, context); /* FIXME: register dump function */ - mon_ioreg_add_list(&drivemem_ioreg_list, "CIA", 0x4000, 0x400f, cia1571_dump, context); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA1", 0x1800, 0x180f, via1d1541_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA2", 0x1c00, 0x1c0f, via2d_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "WD1770", 0x2000, 0x2003, wd1770d_dump, context, IO_MIRROR_NONE); /* FIXME: register dump function */ + mon_ioreg_add_list(&drivemem_ioreg_list, "MOS5710", 0x4000, 0x401f, mos5710_dump, context, IO_MIRROR_NONE); break; case DRIVE_TYPE_1581: - mon_ioreg_add_list(&drivemem_ioreg_list, "CIA", 0x4000, 0x400f, cia1581_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "WD1770", 0x6000, 0x6003, NULL, context); /* FIXME: register dump function */ + mon_ioreg_add_list(&drivemem_ioreg_list, "CIA", 0x4000, 0x400f, cia1581_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "WD1770", 0x6000, 0x6003, wd1770d_dump, context, IO_MIRROR_NONE); /* FIXME: register dump function */ break; case DRIVE_TYPE_2000: - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x4000, 0x400f, via4000_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "DP8473", 0x4e00, 0x4e07, NULL, context); /* FIXME: register dump function */ + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x4000, 0x400f, via4000_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "DP8473", 0x4e00, 0x4e07, pc8477d_dump, context, IO_MIRROR_NONE); /* FIXME: register dump function */ break; case DRIVE_TYPE_4000: - mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x4000, 0x400f, via4000_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "PC8477", 0x4e00, 0x4e07, NULL, context); /* FIXME: register dump function */ + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x4000, 0x400f, via4000_dump, context, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "PC8477", 0x4e00, 0x4e07, pc8477d_dump, context, IO_MIRROR_NONE); /* FIXME: register dump function */ + break; + case DRIVE_TYPE_CMDHD: + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x8000, 0x800f, viacore_dump, ((diskunit_context_t *)context)->cmdhd->via10, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "VIA", 0x8400, 0x840f, viacore_dump, ((diskunit_context_t *)context)->cmdhd->via9, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "I8255A", 0x8800, 0x8803, i8255a_dump, ((diskunit_context_t *)context)->cmdhd->i8255a, IO_MIRROR_NONE); break; case DRIVE_TYPE_2040: case DRIVE_TYPE_3040: @@ -253,11 +308,12 @@ mem_ioreg_list_t *drivemem_ioreg_list_get(void *context) case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - mon_ioreg_add_list(&drivemem_ioreg_list, "RIOT1", 0x0200, 0x021f, riot1_dump, context); - mon_ioreg_add_list(&drivemem_ioreg_list, "RIOT2", 0x0280, 0x029f, riot2_dump, context); + case DRIVE_TYPE_9000: + mon_ioreg_add_list(&drivemem_ioreg_list, "RIOT1", 0x0200, 0x021f, riotcore_dump, ((diskunit_context_t *)context)->riot1, IO_MIRROR_NONE); + mon_ioreg_add_list(&drivemem_ioreg_list, "RIOT2", 0x0280, 0x029f, riotcore_dump, ((diskunit_context_t *)context)->riot2, IO_MIRROR_NONE); break; default: - log_error(LOG_ERR, "DRIVEMEM: Unknown drive type `%i'.", type); + log_error(LOG_DEFAULT, "DRIVEMEM: Unknown drive type `%u'.", type); break; } return drivemem_ioreg_list; diff --git a/src/Emulators/vice/drive/drivemem.h b/src/Emulators/vice/drive/drivemem.h index 1276882b..9884e7cd 100644 --- a/src/Emulators/vice/drive/drivemem.h +++ b/src/Emulators/vice/drive/drivemem.h @@ -30,30 +30,30 @@ #include "drivetypes.h" #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct drivecpud_context_s; struct mem_ioreg_list_s; -extern void drivemem_toggle_watchpoints(int flag, void *context); -extern BYTE drivemem_bank_read(int bank, WORD addr, void *context); -extern BYTE drivemem_bank_peek(int bank, WORD addr, void *context); -extern void drivemem_bank_store(int bank, WORD addr, BYTE value, void *context); -extern void drivemem_init(struct drive_context_s *drv, unsigned int type); -extern void drivemem_set_func(struct drivecpud_context_s *cpud, - unsigned int start, unsigned int stop, - drive_read_func_t *read_func, - drive_store_func_t *store_func, - drive_peek_func_t *peek_func, - BYTE *base, DWORD limit); - -extern struct mem_ioreg_list_s *drivemem_ioreg_list_get(void *context); - -extern BYTE drive_read_rom(struct drive_context_s *drv, - WORD address); -extern BYTE drive_peek_rom(drive_context_t *drv, WORD address); -extern BYTE drive_peek_free(drive_context_t *drv, WORD address); - -extern BYTE drive_read_rom_ds1216(struct drive_context_s *drv, - WORD address); +extern uint8_t drive_cpu_last_data; + +void drivemem_toggle_watchpoints(int flag, void *context); +uint8_t drivemem_bank_read(int bank, uint16_t addr, void *context); +uint8_t drivemem_bank_peek(int bank, uint16_t addr, void *context); +void drivemem_bank_store(int bank, uint16_t addr, uint8_t value, void *context); +void drivemem_bank_poke(int bank, uint16_t addr, uint8_t value, void *context); +void drivemem_init(struct diskunit_context_s *drv); +void drivemem_set_func(struct drivecpud_context_s *cpud, + unsigned int start, unsigned int stop, + drive_read_func_t *read_func, + drive_store_func_t *store_func, + drive_peek_func_t *peek_func, + uint8_t *base, uint32_t limit); + +struct mem_ioreg_list_s *drivemem_ioreg_list_get(void *context); + +extern uint8_t drive_read_rom(diskunit_context_t *drv, uint16_t address); +extern uint8_t drive_peek_free(diskunit_context_t *drv, uint16_t address); + +extern uint8_t drive_read_rom_ds1216(diskunit_context_t *drv, uint16_t address); #endif diff --git a/src/Emulators/vice/drive/driverom.c b/src/Emulators/vice/drive/driverom.c index 6242f476..abab8cd6 100644 --- a/src/Emulators/vice/drive/driverom.c +++ b/src/Emulators/vice/drive/driverom.c @@ -24,6 +24,8 @@ * */ +/* #define DBGDRIVEROM */ + #include "vice.h" #include @@ -33,6 +35,7 @@ #include "drivetypes.h" #include "driverom.h" #include "log.h" +#include "machine-bus.h" #include "machine-drive.h" #include "resources.h" #include "sysfile.h" @@ -40,6 +43,12 @@ #include "vicetypes.h" #include "snapshot.h" +#ifdef DBGDRIVEROM +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + /* patch for 1541 driverom at $EAAF */ /* skips RAM and ROM check for fast drive reset */ /* @@ -64,17 +73,88 @@ static log_t driverom_log; /* If nonzero, we are far enough in init that we can load ROMs. */ static int drive_rom_load_ok = 0; +/* like driverom_load, but doesn't actually load anything, and only tests if the + file exists and matches the given size(s) */ +int driverom_test_load(const char *resource_name, unsigned int *loaded, + int min, int max, const char *name, + unsigned int type, unsigned int *size) +{ + const char *rom_name = NULL; + int filesize; + unsigned int dnr; + + DBG(("driverom_test_load res:%s loaded:%u min:%d max:%d name:%s type:%u size:%u", + resource_name, *loaded, min, max, name, type, size ? *size : 0)); + + if (!drive_rom_load_ok) { + return 0; + } + + resources_get_string(resource_name, &rom_name); + + DBG(("driverom_test_load rom_name: %s", rom_name)); + + if (size != NULL) { + *size = 0; + } + if (loaded != NULL) { + *loaded = 0; + } + + filesize = sysfile_locate(rom_name, "DRIVES", NULL); + + if (filesize < 0) { +#if 1 + log_error(driverom_log, "%s ROM image not found. " + "Hardware-level %s emulation is not available.", name, name); +#endif + goto exiterror; + } + + if ((min < max)) { + if ((filesize > max)) { +#if 1 + log_error(driverom_log, "%s ROM image too large. " + "Hardware-level %s emulation is not available.", name, name); +#endif + goto exiterror; + } + } + + if (loaded != NULL) { + *loaded = 1; + } + if (size != NULL) { + *size = (unsigned int)filesize; + } + return 0; + +exiterror: +#if 1 + /* FIXME: this should probably no more happen here */ + /* disable the drives that used the ROM which could not be loaded */ + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + if (unit->type == type) { + unit->type = DRIVE_TYPE_NONE; + drive_disable(diskunit_context[dnr]); + machine_bus_status_drivetype_set(dnr + 8, 0); + } + } +#endif + return -1; +} -int driverom_load(const char *resource_name, BYTE *drive_rom, unsigned +int driverom_load(const char *resource_name, uint8_t *drive_rom, unsigned int *loaded, int min, int max, const char *name, - unsigned int type, unsigned int *size) + unsigned int type, unsigned int *size) { const char *rom_name = NULL; int filesize; unsigned int dnr; - drive_t *drive; - LOGD("driverom_load: '%s'", resource_name); + DBG(("driverom_load res:%s loaded:%u min:%d max:%d name:%s type:%u size:%u", + resource_name, *loaded, min, max, name, type, size ? *size : 0)); if (!drive_rom_load_ok) { return 0; @@ -82,33 +162,59 @@ int driverom_load(const char *resource_name, BYTE *drive_rom, unsigned resources_get_string(resource_name, &rom_name); - filesize = sysfile_load(rom_name, drive_rom, min, max); + DBG(("driverom_load rom_name: %s", rom_name)); + + if (size != NULL) { + *size = 0; + } + if (loaded != NULL) { + *loaded = 0; + } + + filesize = sysfile_load(rom_name, "DRIVES", drive_rom, min, max); if (filesize < 0) { log_error(driverom_log, "%s ROM image not found. " "Hardware-level %s emulation is not available.", name, name); + goto exiterror; + } - if (size != NULL) { - *size = 0; - } - return -1; - } *loaded = 1; if (size != NULL) { *size = (unsigned int)filesize; } - if (filesize <= min && min < max) { - memcpy(drive_rom, &drive_rom[max - min], min); + + /* Align to the end of available space */ + if ((filesize <= min) && (min < max)) { + DBG(("driverom_load align drive rom")); + /* sysfile_load loaded the block to the top end of the buffer */ + memmove(drive_rom, &drive_rom[max - min], min); } - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + /* reset all drives that use the loaded ROM */ + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; - if (drive->type == type) { + if (unit->type == type) { + DBG(("driverom_load prepare drive rom and reset")); machine_drive_rom_setup_image(dnr); + driverom_initialize_traps(diskunit_context[dnr]); + drive_cpu_trigger_reset(dnr); } } return 0; + +exiterror: + /* disable the drives that used the ROM which could not be loaded */ + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; + if (unit->type == type) { + unit->type = DRIVE_TYPE_NONE; + drive_disable(diskunit_context[dnr]); + machine_bus_status_drivetype_set(dnr + 8, 0); + } + } + return -1; } int driverom_load_images(void) @@ -127,76 +233,79 @@ int driverom_load_images(void) return 0; } -void driverom_initialize_traps(drive_t *drive) +void driverom_initialize_traps(diskunit_context_t *unit) { - memcpy(drive->trap_rom, drive->rom, DRIVE_ROM_SIZE); + memcpy(unit->trap_rom, unit->rom, DRIVE_ROM_SIZE); + + unit->trap = -1; + unit->trapcont = -1; - drive->trap = -1; - drive->trapcont = -1; + DBG(("driverom_initialize_traps type: %u trap idle: %s", unit->type, + unit->idling_method == DRIVE_IDLE_TRAP_IDLE ? "enabled" : "disabled")); - if (drive->idling_method != DRIVE_IDLE_TRAP_IDLE) { + if (unit->idling_method != DRIVE_IDLE_TRAP_IDLE) { return; } - switch (drive->type) { + switch (unit->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: case DRIVE_TYPE_1570: case DRIVE_TYPE_1571: case DRIVE_TYPE_1571CR: - drive->trap = 0xec9b; - drive->trapcont = 0xebff; + unit->trap = 0xec9b; + unit->trapcont = 0xebff; break; case DRIVE_TYPE_1551: - drive->trap = 0xead9; - drive->trapcont = 0xeabd; + unit->trap = 0xead9; + unit->trapcont = 0xeabd; break; case DRIVE_TYPE_1581: - drive->trap = 0xb158; - drive->trapcont = 0xb105; + unit->trap = 0xb158; + unit->trapcont = 0xb105; break; case DRIVE_TYPE_2000: - drive->trap = 0xf3c0; - drive->trapcont = 0xf368; + unit->trap = 0xf3c0; + unit->trapcont = 0xf368; break; case DRIVE_TYPE_4000: - drive->trap = 0xf3ec; - drive->trapcont = 0xf394; + unit->trap = 0xf3ec; + unit->trapcont = 0xf394; break; case DRIVE_TYPE_2031: - drive->trap = 0xece9; - drive->trapcont = 0xec4d; + unit->trap = 0xece9; + unit->trapcont = 0xec4d; break; case DRIVE_TYPE_2040: - drive->trap = 0xe2d3; - drive->trapcont = 0xe27e; + unit->trap = 0xe2d3; + unit->trapcont = 0xe27e; break; case DRIVE_TYPE_3040: - drive->trap = 0xd508; - drive->trapcont = 0xd4b8; + unit->trap = 0xd508; + unit->trapcont = 0xd4b8; break; case DRIVE_TYPE_4040: - drive->trap = 0xd507; - drive->trapcont = 0xd4b7; + unit->trap = 0xd507; + unit->trapcont = 0xd4b7; break; default: break; } - if (drive->trap >= 0 - && drive->trap_rom[drive->trap - 0x8000] == 0x4c - && drive->trap_rom[drive->trap - 0x8000 + 1] == (drive->trapcont & 0xff) - && drive->trap_rom[drive->trap - 0x8000 + 2] == (drive->trapcont >> 8)) { - drive->trap_rom[drive->trap - 0x8000] = TRAP_OPCODE; - if (drive->type == DRIVE_TYPE_1551) { - drive->trap_rom[0xeabf - 0x8000] = 0xea; - drive->trap_rom[0xeac0 - 0x8000] = 0xea; - drive->trap_rom[0xead0 - 0x8000] = 0x08; + if (unit->trap >= 0 + && unit->trap_rom[unit->trap - 0x8000] == 0x4c + && unit->trap_rom[unit->trap - 0x8000 + 1] == (unit->trapcont & 0xff) + && unit->trap_rom[unit->trap - 0x8000 + 2] == (unit->trapcont >> 8)) { + unit->trap_rom[unit->trap - 0x8000] = TRAP_OPCODE; + if (unit->type == DRIVE_TYPE_1551) { + unit->trap_rom[0xeabf - 0x8000] = 0xea; + unit->trap_rom[0xeac0 - 0x8000] = 0xea; + unit->trap_rom[0xead0 - 0x8000] = 0x08; } return; } - drive->trap = -1; - drive->trapcont = -1; + unit->trap = -1; + unit->trapcont = -1; } /* -------------------------------------------------------------------- */ @@ -204,14 +313,16 @@ void driverom_initialize_traps(drive_t *drive) #define ROM_SNAP_MAJOR 1 #define ROM_SNAP_MINOR 0 +/* TODO: pass diskunit_context_t as parameter instead */ int driverom_snapshot_write(snapshot_t *s, const drive_t *drive) { char snap_module_name[10]; snapshot_module_t *m; - const BYTE *base; + diskunit_context_t *unit = drive->diskunit; + const uint8_t *base; int len; - sprintf(snap_module_name, "DRIVEROM%i", drive->mynumber); + sprintf(snap_module_name, "DRIVEROM%u", drive->diskunit->mynumber); m = snapshot_module_create(s, snap_module_name, ROM_SNAP_MAJOR, ROM_SNAP_MINOR); @@ -219,69 +330,77 @@ int driverom_snapshot_write(snapshot_t *s, const drive_t *drive) return -1; } - switch (drive->type) { + switch (unit->type) { case DRIVE_TYPE_1540: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1540_SIZE; break; case DRIVE_TYPE_1541: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1541_SIZE; break; case DRIVE_TYPE_1541II: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1541II_SIZE; break; case DRIVE_TYPE_1551: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1551_SIZE; break; case DRIVE_TYPE_1570: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1570_SIZE; break; case DRIVE_TYPE_1571: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1571_SIZE; break; case DRIVE_TYPE_1571CR: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1571CR_SIZE; break; case DRIVE_TYPE_1581: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1581_SIZE; break; case DRIVE_TYPE_2000: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM2000_SIZE; break; case DRIVE_TYPE_4000: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM4000_SIZE; break; + case DRIVE_TYPE_CMDHD: + base = &(unit->rom[0x4000]); + len = DRIVE_ROMCMDHD_SIZE; + break; case DRIVE_TYPE_2031: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM2031_SIZE; break; case DRIVE_TYPE_2040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]); len = DRIVE_ROM2040_SIZE; break; case DRIVE_TYPE_3040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]); len = DRIVE_ROM3040_SIZE; break; case DRIVE_TYPE_4040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]); len = DRIVE_ROM4040_SIZE; break; case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1001_SIZE; break; + case DRIVE_TYPE_9000: + base = &(unit->rom[0x4000]); + len = DRIVE_ROM9000_SIZE; + break; default: return -1; } @@ -298,13 +417,14 @@ int driverom_snapshot_write(snapshot_t *s, const drive_t *drive) int driverom_snapshot_read(snapshot_t *s, drive_t *drive) { - BYTE major_version, minor_version; + uint8_t major_version, minor_version; snapshot_module_t *m; + diskunit_context_t *unit = drive->diskunit; char snap_module_name[10]; - BYTE *base; + uint8_t *base; int len; - sprintf(snap_module_name, "DRIVEROM%i", drive->mynumber); + sprintf(snap_module_name, "DRIVEROM%u", drive->diskunit->mynumber); m = snapshot_module_open(s, snap_module_name, &major_version, &minor_version); if (m == NULL) { @@ -312,7 +432,7 @@ int driverom_snapshot_read(snapshot_t *s, drive_t *drive) } /* Do not accept versions higher than current */ - if (major_version > ROM_SNAP_MAJOR || minor_version > ROM_SNAP_MINOR) { + if (snapshot_version_is_bigger(major_version, minor_version, ROM_SNAP_MAJOR, ROM_SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); log_error(driverom_log, "Snapshot module version (%d.%d) newer than %d.%d.", @@ -322,69 +442,77 @@ int driverom_snapshot_read(snapshot_t *s, drive_t *drive) return -1; } - switch (drive->type) { + switch (unit->type) { case DRIVE_TYPE_1540: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1540_SIZE; break; case DRIVE_TYPE_1541: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1541_SIZE; break; case DRIVE_TYPE_1541II: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1541II_SIZE; break; case DRIVE_TYPE_1551: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1551_SIZE; break; case DRIVE_TYPE_1570: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1570_SIZE; break; case DRIVE_TYPE_1571: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1571_SIZE; break; case DRIVE_TYPE_1571CR: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1571CR_SIZE; break; case DRIVE_TYPE_1581: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM1581_SIZE; break; case DRIVE_TYPE_2000: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM2000_SIZE; break; case DRIVE_TYPE_4000: - base = drive->rom; + base = unit->rom; len = DRIVE_ROM4000_SIZE; break; + case DRIVE_TYPE_CMDHD: + base = &(unit->rom[0x4000]); + len = DRIVE_ROMCMDHD_SIZE; + break; case DRIVE_TYPE_2031: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM2031_SIZE; break; case DRIVE_TYPE_2040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]); len = DRIVE_ROM2040_SIZE; break; case DRIVE_TYPE_3040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]); len = DRIVE_ROM3040_SIZE; break; case DRIVE_TYPE_4040: - base = &(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]); + base = &(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]); len = DRIVE_ROM4040_SIZE; break; case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - base = &(drive->rom[0x4000]); + base = &(unit->rom[0x4000]); len = DRIVE_ROM1001_SIZE; break; + case DRIVE_TYPE_9000: + base = &(unit->rom[0x4000]); + len = DRIVE_ROM9000_SIZE; + break; default: return -1; } @@ -396,7 +524,7 @@ int driverom_snapshot_read(snapshot_t *s, drive_t *drive) return -1; } - machine_drive_rom_do_checksum(drive->mynumber); + machine_drive_rom_do_checksum(drive->diskunit->mynumber); return snapshot_module_close(m); } diff --git a/src/Emulators/vice/drive/driverom.h b/src/Emulators/vice/drive/driverom.h index 29ecce31..c9e510a4 100644 --- a/src/Emulators/vice/drive/driverom.h +++ b/src/Emulators/vice/drive/driverom.h @@ -30,6 +30,7 @@ #include "vicetypes.h" struct drive_s; +struct diskunit_context_s; struct snapshot_s; #define DRIVE_ROM1540_SIZE 0x4000 @@ -45,19 +46,57 @@ struct snapshot_s; #define DRIVE_ROM1581_SIZE 0x8000 #define DRIVE_ROM2000_SIZE 0x8000 #define DRIVE_ROM4000_SIZE 0x8000 +#define DRIVE_ROMCMDHD_SIZE 0x4000 #define DRIVE_ROM2031_SIZE 0x4000 #define DRIVE_ROM1001_SIZE 0x4000 /* same as ROM8050 and ROM8250 !*/ +#define DRIVE_ROM9000_SIZE 0x4000 #define DRIVE_ROM2040_SIZE 0x2000 #define DRIVE_ROM3040_SIZE 0x3000 #define DRIVE_ROM4040_SIZE 0x3000 -extern void driverom_init(void); -extern void driverom_initialize_traps(struct drive_s *drive); -extern int driverom_load(const char *resource_name, BYTE *drive_rom, unsigned - int *loaded, int min, int max, const char *name, - unsigned int type, unsigned int *size); -extern int driverom_load_images(void); -extern int driverom_snapshot_write(struct snapshot_s *s, const struct drive_s *drive); -extern int driverom_snapshot_read(struct snapshot_s *s, struct drive_s *drive); +void driverom_init(void); +void driverom_initialize_traps(struct diskunit_context_s *drive); +int driverom_load(const char *resource_name, uint8_t *drive_rom, unsigned + int *loaded, int min, int max, const char *name, + unsigned int type, unsigned int *size); +int driverom_test_load(const char *resource_name, unsigned int *loaded, + int min, int max, const char *name, + unsigned int type, unsigned int *size); +int driverom_load_images(void); +int driverom_snapshot_write(struct snapshot_s *s, const struct drive_s *drive); +int driverom_snapshot_read(struct snapshot_s *s, struct drive_s *drive); + +/* 1001 Images have the low and high part combined */ +#define DRIVE_ROM1001_NAME "dos1001-901887+8-01.bin" + +/* 2031 Images have the low and high part combined */ +#define DRIVE_ROM2031_NAME "dos2031-901484-03+05.bin" + +/* 2040 Images have the low and high parts combined */ +#define DRIVE_ROM2040_NAME "dos2040-901468-06+07.bin" + +/* 3040 Images have the three parts combined */ +#define DRIVE_ROM3040_NAME "dos3040-901468-11-13.bin" + +/* 4040 Images have the three parts combined */ +#define DRIVE_ROM4040_NAME "dos4040-901468-14-16.bin" + +/* 90x0 Images have the low and high parts combined */ +#define DRIVE_ROM9000_NAME "dos9000-300516+7-revC.bin" + +/* 154x Images have the low and high part combined */ +#define DRIVE_ROM1540_NAME "dos1540-325302+3-01.bin" +#define DRIVE_ROM1541_NAME "dos1541-325302-01+901229-05.bin" +#define DRIVE_ROM1541II_NAME "dos1541ii-251968-03.bin" + +#define DRIVE_ROM1551_NAME "dos1551-318008-01.bin" +#define DRIVE_ROM1570_NAME "dos1570-315090-01.bin" +#define DRIVE_ROM1571_NAME "dos1571-310654-05.bin" +#define DRIVE_ROM1571CR_NAME "dos1571cr-318047-01.bin" +#define DRIVE_ROM1581_NAME "dos1581-318045-02.bin" + +#define DRIVE_ROM2000_NAME "dos2000-cs-33cc6f.bin" +#define DRIVE_ROM4000_NAME "dos4000-fd-350022.bin" +#define DRIVE_ROMCMDHD_NAME "bootromCMDHD-v2-80.bin" #endif diff --git a/src/Emulators/vice/drive/drivesync.c b/src/Emulators/vice/drive/drivesync.c index 0d612424..ac79dc90 100644 --- a/src/Emulators/vice/drive/drivesync.c +++ b/src/Emulators/vice/drive/drivesync.c @@ -26,7 +26,7 @@ #include "vice.h" -#if !defined(__BEOS__) || !defined(WORDS_BIGENDIAN) +#if !defined(BEOS_COMPULE) || !defined(WORDS_BIGENDIAN) #include #endif @@ -38,15 +38,15 @@ static unsigned int sync_factor; -static void drive_sync_cpu_set_factor(drive_context_t *drv, - unsigned int sync_factor) +static void drive_sync_cpu_set_factor(diskunit_context_t *drv, + unsigned int sf) { - drv->cpud->sync_factor = sync_factor; + drv->cpud->sync_factor = sf; } -void drivesync_factor(struct drive_context_s *drv) +void drivesync_factor(struct diskunit_context_s *drv) { - drive_sync_cpu_set_factor(drv, drv->drive->clock_frequency + drive_sync_cpu_set_factor(drv, drv->clock_frequency * sync_factor); } @@ -56,34 +56,34 @@ void drive_set_machine_parameter(long cycles_per_sec) sync_factor = (unsigned int)floor(65536.0 * (1000000.0 / ((double)cycles_per_sec))); - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drivesync_factor(drive_context[dnr]); + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + drivesync_factor(diskunit_context[dnr]); } } -void drivesync_set_1571(int new_sync, struct drive_context_s *drv) +void drivesync_set_1571(struct diskunit_context_s *drv, int new_sync) { unsigned int dnr; dnr = drv->mynumber; if (rom_loaded) { - rotation_rotate_disk(drv->drive); + rotation_rotate_disk(drv->drives[0]); rotation_init(new_sync ? 1 : 0, dnr); - drv->drive->clock_frequency = (new_sync) ? 2 : 1; + drv->clock_frequency = (new_sync) ? 2 : 1; drivesync_factor(drv); } } -void drivesync_set_4000(struct drive_context_s *drv, int new_sync) +void drivesync_set_4000(struct diskunit_context_s *drv, int new_sync) { - if (rom_loaded && drv->drive->type == DRIVE_TYPE_4000) { - drv->drive->clock_frequency = (new_sync) ? 4 : 2; + if (rom_loaded && drv->type == DRIVE_TYPE_4000) { + drv->clock_frequency = (new_sync) ? 4 : 2; drivesync_factor(drv); } } -void drivesync_clock_frequency(unsigned int type, drive_t *drive) +void drivesync_clock_frequency(diskunit_context_t *unit, unsigned int type) { switch (type) { case DRIVE_TYPE_1540: @@ -92,13 +92,14 @@ void drivesync_clock_frequency(unsigned int type, drive_t *drive) case DRIVE_TYPE_1570: case DRIVE_TYPE_1571: case DRIVE_TYPE_1571CR: - drive->clock_frequency = 1; + unit->clock_frequency = 1; break; case DRIVE_TYPE_1551: case DRIVE_TYPE_1581: case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: - drive->clock_frequency = 2; + case DRIVE_TYPE_CMDHD: + unit->clock_frequency = 2; break; case DRIVE_TYPE_2031: case DRIVE_TYPE_2040: @@ -107,9 +108,10 @@ void drivesync_clock_frequency(unsigned int type, drive_t *drive) case DRIVE_TYPE_1001: case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - drive->clock_frequency = 1; + case DRIVE_TYPE_9000: + unit->clock_frequency = 1; break; default: - drive->clock_frequency = 1; + unit->clock_frequency = 1; } } diff --git a/src/Emulators/vice/drive/drivesync.h b/src/Emulators/vice/drive/drivesync.h index 8c89461d..f51dceba 100644 --- a/src/Emulators/vice/drive/drivesync.h +++ b/src/Emulators/vice/drive/drivesync.h @@ -28,12 +28,11 @@ #define VICE_DRIVESYNC_H struct drive_s; -struct drive_context_s; +struct diskunit_context_s; -extern void drivesync_factor(struct drive_context_s *drv); -extern void drivesync_set_1571(int new_sync, struct drive_context_s *drv); -extern void drivesync_set_4000(struct drive_context_s *drv, int new_sync); -extern void drivesync_clock_frequency(unsigned int type, - struct drive_s *drive); +void drivesync_factor(struct diskunit_context_s *drv); +void drivesync_set_1571(struct diskunit_context_s *drv, int new_sync); +void drivesync_set_4000(struct diskunit_context_s *drv, int new_sync); +void drivesync_clock_frequency(struct diskunit_context_s *drive, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/drivetypes.h b/src/Emulators/vice/drive/drivetypes.h index c4bcb52e..35439de6 100644 --- a/src/Emulators/vice/drive/drivetypes.h +++ b/src/Emulators/vice/drive/drivetypes.h @@ -35,21 +35,21 @@ /* * The philosophy behind this approach is that only the drive module knows - * the exact layout of the drive_context_t structure. Therefore only include + * the exact layout of the diskunit_context_t structure. Therefore only include * drivetypes.h from source files within the drive module. All other modules * only need to use pointers transparently, which only requires a forward - * declaration of struct drive_context_s (see below). + * declaration of struct diskunit_context_s (see below). */ -struct drive_context_s; /* forward declaration */ +struct diskunit_context_s; /* forward declaration */ struct monitor_interface_s; /* This defines the memory access for the drive CPU. */ -typedef BYTE drive_read_func_t (struct drive_context_s *, WORD); +typedef uint8_t drive_read_func_t (struct diskunit_context_s *, uint16_t); typedef drive_read_func_t *drive_read_func_ptr_t; -typedef void drive_store_func_t (struct drive_context_s *, WORD, BYTE); +typedef void drive_store_func_t (struct diskunit_context_s *, uint16_t, uint8_t); typedef drive_store_func_t *drive_store_func_ptr_t; -typedef BYTE drive_peek_func_t (struct drive_context_s *, WORD); +typedef uint8_t drive_peek_func_t (struct diskunit_context_s *, uint16_t); typedef drive_peek_func_t *drive_peek_func_ptr_t; /* @@ -62,14 +62,15 @@ typedef struct drivecpu_context_s { memory is executed. We can emulate the RMW bug of the 6502 this way. */ int rmw_flag; /* init to 0 */ + /* Last data read/write by the cpu, this value lingers on the C(PU)-bus and + gets used when the CPU reads from unconnected space on the C(PU)-bus */ + uint8_t cpu_last_data; + /* Interrupt/alarm status. */ struct interrupt_cpu_status_s *int_status; struct alarm_context_s *alarm_context; - /* Clk guard. */ - struct clk_guard_s *clk_guard; - struct monitor_interface_s *monitor_interface; /* Value of clk for the last time mydrive_cpu_execute() was called. */ @@ -82,7 +83,7 @@ typedef struct drivecpu_context_s { CLOCK stop_clk; CLOCK cycle_accum; - BYTE *d_bank_base; + uint8_t *d_bank_base; unsigned int d_bank_start; unsigned int d_bank_limit; @@ -92,11 +93,14 @@ typedef struct drivecpu_context_s { /* Address of the last executed opcode. This is used by watchpoints. */ unsigned int last_opcode_addr; + /* jam flag */ + int is_jammed; + /* Public copy of the registers. */ mos6510_regs_t cpu_regs; R65C02_regs_t cpu_R65C02_regs; - BYTE *pageone; /* init to NULL */ + uint8_t *pageone; /* init to NULL */ int monspace; /* init to e_disk[89]_space */ @@ -116,16 +120,18 @@ typedef struct drivecpud_context_s { /* Pointers to the currently used memory read and write tables. */ drive_read_func_ptr_t *read_func_ptr; drive_store_func_ptr_t *store_func_ptr; + drive_read_func_ptr_t *read_func_ptr_dummy; + drive_store_func_ptr_t *store_func_ptr_dummy; drive_peek_func_ptr_t *peek_func_ptr; - BYTE **read_base_tab_ptr; - DWORD *read_limit_tab_ptr; + uint8_t **read_base_tab_ptr; + uint32_t *read_limit_tab_ptr; /* Memory read and write tables. */ drive_read_func_t *read_tab[1][0x101]; drive_store_func_t *store_tab[1][0x101]; drive_peek_func_t *peek_tab[1][0x101]; - BYTE *read_base_tab[1][0x101]; - DWORD read_limit_tab[1][0x101]; + uint8_t *read_base_tab[1][0x101]; + uint32_t read_limit_tab[1][0x101]; int sync_factor; } drivecpud_context_t; @@ -136,25 +142,17 @@ typedef struct drivecpud_context_s { */ typedef struct drivefunc_context_s { - void (*parallel_set_bus)(BYTE); - void (*parallel_set_eoi)(BYTE); /* we may be able to eleminate these... */ - void (*parallel_set_dav)(BYTE); - void (*parallel_set_ndac)(BYTE); - void (*parallel_set_nrfd)(BYTE); + void (*parallel_set_bus)(uint8_t); + void (*parallel_set_eoi)(uint8_t); /* we may be able to eleminate these... */ + void (*parallel_set_dav)(uint8_t); + void (*parallel_set_ndac)(uint8_t); + void (*parallel_set_nrfd)(uint8_t); } drivefunc_context_t; -extern drivefunc_context_t drive_funcs[DRIVE_NUM]; +extern const drivefunc_context_t drive_funcs[NUM_DISK_UNITS]; /* - * Helper macros for dual disk drives. - */ -#define is_drive0(d) (!is_drive1(d)) -#define is_drive1(d) ((d) & 1) -#define mk_drive0(d) ((d) & ~1) -#define mk_drive1(d) ((d) | 1) - -/* - * The context for an entire drive. + * The context for an entire disk unit (may have 1 or 2 drives). */ struct cia_context_s; @@ -163,11 +161,12 @@ struct tpi_context_s; struct via_context_s; struct pc8477_s; struct wd1770_s; +struct cmdhd_context_s; -typedef struct drive_context_s { - int mynumber; /* init to [0123] */ - CLOCK *clk_ptr; /* shortcut to drive_clk[mynumber] */ - struct drive_s *drive; +typedef struct diskunit_context_s { + unsigned int mynumber; /* 0 ... NUM_DISK_UNITS-1 */ + CLOCK *clk_ptr; /* shortcut to drive_clk[mynumber] */ + struct drive_s *drives[NUM_DRIVES]; struct drivecpu_context_s *cpu; struct drivecpud_context_s *cpud; @@ -183,6 +182,75 @@ typedef struct drive_context_s { struct tpi_context_s *tpid; struct pc8477_s *pc8477; struct wd1770_s *wd1770; -} drive_context_t; + struct cmdhd_context_s *cmdhd; + + /* Here is some data which used to be stored in drives[0]. */ + + /* Is this drive enabled for True Drive Emulation? */ + unsigned int enable; + + /* What drive type we have to emulate? */ + unsigned int type; + + /* Clock frequency of this disk unit in 1MHz units. */ + int clock_frequency; + + /* What idling method? (See `DRIVE_IDLE_*') */ + int idling_method; + + /* Flag: What parallel cable do we emulate? */ + int parallel_cable; + + /* FIXME: since those are basically exclusive, we should refactor the + * following into a single variable/resource.... */ + + /* Is the Professional DOS extension enabled? */ + int profdos; + /* Is the Supercard+ extension enabled? */ + int supercard; + /* Is the StarDOS extension enabled? */ + int stardos; + /* Is the DolphinDOS3 extension enabled? */ + int dolphindos3; + + /* RTC context */ + rtc_ds1216e_t *ds1216; + + /* FD2000/4000 RTC save? */ + int rtc_save; + + /* CMDHD allow for disk expansion or keep fixed, 0=expand, other = max size */ + /* value is in 512 byte sectors */ + unsigned int fixed_size; + + /* Hack to hold the ASCII value of the fixed_size resource above in bytes */ + /* string is a numeric value in bytes with an optional suffix: K, M, G */ + /* may also be hex with 0x prefix, or octal with 0 prefix */ + char *fixed_size_text; + + /* Drive-specific logging goes here. */ + signed int log; + + /* state of buttons on reset, if any */ + int button; + + /* Which RAM expansion is enabled? */ + int drive_ram2_enabled, drive_ram4_enabled, drive_ram6_enabled, + drive_ram8_enabled, drive_rama_enabled; + + /* Current ROM image. */ + uint8_t rom[DRIVE_ROM_SIZE]; + + /* What ROM type do we have loaded? */ + unsigned int rom_type; + + /* Current trap ROM image. */ + uint8_t trap_rom[DRIVE_ROM_SIZE]; + int trap, trapcont; + + /* Drive RAM */ + uint8_t drive_ram[DRIVE_RAM_SIZE]; + +} diskunit_context_t; #endif diff --git a/src/Emulators/vice/drive/iec-c64exp.h b/src/Emulators/vice/drive/iec-c64exp.h index e66dae96..5641a2d2 100644 --- a/src/Emulators/vice/drive/iec-c64exp.h +++ b/src/Emulators/vice/drive/iec-c64exp.h @@ -27,13 +27,13 @@ #ifndef VICE_IEC_C64EXP_H #define VICE_IEC_C64EXP_H -struct drive_context_s; +struct diskunit_context_s; -extern int iec_c64exp_resources_init(void); -extern void iec_c64exp_resources_shutdown(void); -extern int iec_c64exp_cmdline_options_init(void); -extern void iec_c64exp_init(struct drive_context_s *drv); -extern void iec_c64exp_reset(struct drive_context_s *drv); -extern void iec_c64exp_mem_init(struct drive_context_s *drv, unsigned int type); +int iec_c64exp_resources_init(void); +void iec_c64exp_resources_shutdown(void); +int iec_c64exp_cmdline_options_init(void); +void iec_c64exp_init(struct diskunit_context_s *drv); +void iec_c64exp_reset(struct diskunit_context_s *drv); +void iec_c64exp_mem_init(struct diskunit_context_s *drv, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/iec.h b/src/Emulators/vice/drive/iec.h index 4882ceea..391c7413 100644 --- a/src/Emulators/vice/drive/iec.h +++ b/src/Emulators/vice/drive/iec.h @@ -30,26 +30,26 @@ #include "vicetypes.h" struct disk_image_s; -struct drive_context_s; +struct diskunit_context_s; struct snapshot_s; -extern int iec_drive_resources_init(void); -extern void iec_drive_resources_shutdown(void); -extern int iec_drive_cmdline_options_init(void); -extern void iec_drive_init(struct drive_context_s *drv); -extern void iec_drive_shutdown(struct drive_context_s *drv); -extern void iec_drive_reset(struct drive_context_s *drv); -extern void iec_drive_mem_init(struct drive_context_s *drv, unsigned int type); -extern void iec_drive_setup_context(struct drive_context_s *drv); -extern void iec_drive_idling_method(unsigned int dnr); -extern void iec_drive_rom_load(void); -extern void iec_drive_rom_setup_image(unsigned int dnr); -extern int iec_drive_rom_check_loaded(unsigned int type); -extern void iec_drive_rom_do_checksum(unsigned int dnr); -extern int iec_drive_snapshot_read(struct drive_context_s *ctxptr, struct snapshot_s *s); -extern int iec_drive_snapshot_write(struct drive_context_s *ctxptr, struct snapshot_s *s); -extern int iec_drive_image_attach(struct disk_image_s *image, unsigned int unit); -extern int iec_drive_image_detach(struct disk_image_s *image, unsigned int unit); -extern void iec_drive_port_default(struct drive_context_s *drv); +int iec_drive_resources_init(void); +void iec_drive_resources_shutdown(void); +int iec_drive_cmdline_options_init(void); +void iec_drive_init(struct diskunit_context_s *drv); +void iec_drive_shutdown(struct diskunit_context_s *drv); +void iec_drive_reset(struct diskunit_context_s *drv); +void iec_drive_mem_init(struct diskunit_context_s *drv, unsigned int type); +void iec_drive_setup_context(struct diskunit_context_s *drv); +void iec_drive_idling_method(unsigned int dnr); +void iec_drive_rom_load(void); +void iec_drive_rom_setup_image(unsigned int dnr); +int iec_drive_rom_check_loaded(unsigned int type); +void iec_drive_rom_do_checksum(unsigned int dnr); +int iec_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s); +int iec_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s); +int iec_drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive); +int iec_drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive); +void iec_drive_port_default(struct diskunit_context_s *drv); #endif diff --git a/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.c b/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.c index c643262e..1c523b73 100644 --- a/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.c +++ b/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.c @@ -32,71 +32,60 @@ #include "cmdline.h" #include "drive.h" #include "lib.h" -#include "translate.h" -static const cmdline_option_t cmdline_options[] = { - { "-profdos1571", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-profdos1571", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DriveProfDOS1571Name", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_PROFDOS_1571_ROM_NAME, - NULL, NULL }, - { "-supercard", SET_RESOURCE, 1, + "", "Specify name of Professional DOS 1571 ROM image" }, + { "-supercard", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DriveSuperCardName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_SUPERCARD_ROM_NAME, - NULL, NULL }, - { "-stardos", SET_RESOURCE, 1, + "", "Specify name of Supercard+ ROM image" }, + { "-stardos", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DriveStarDosName", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_STARDOS_ROM_NAME, - NULL, NULL }, + "", "Specify name of StarDOS ROM image" }, CMDLINE_LIST_END }; -static cmdline_option_t cmd_drive[] = { - { NULL, SET_RESOURCE, 1, +static cmdline_option_t cmd_drive[] = +{ + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_TYPE, IDCLS_PAR_CABLE_C64EXP_TYPE, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + "", "Set parallel cable type (0: none, 1: standard, 2: Dolphin DOS 3, 3: Formel 64)" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_PROFDOS, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable Professional DOS" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_PROFDOS, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable Professional DOS" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_SUPERCARD, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable Supercard+" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_SUPERCARD, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable Supercard+" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_STARDOS, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable StarDOS" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_STARDOS, - NULL, NULL }, + NULL, "Disable StarDOS" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, NULL, (void *)1, + NULL, "Enable DolphinDOS3" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, NULL, (void *)0, + NULL, "Disable DolphinDOS3" }, CMDLINE_LIST_END }; int c64exp_cmdline_options_init(void) { - unsigned int dnr, i; + int dnr; + + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + int i; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { cmd_drive[0].name = lib_msprintf("-parallel%i", dnr + 8); cmd_drive[0].resource_name = lib_msprintf("Drive%iParallelCable", dnr + 8); @@ -118,12 +107,18 @@ int c64exp_cmdline_options_init(void) cmd_drive[6].name = lib_msprintf("+drive%istardos", dnr + 8); cmd_drive[6].resource_name = lib_msprintf("Drive%iStarDos", dnr + 8); + cmd_drive[7].name = lib_msprintf("-drive%idd3", dnr + 8); + cmd_drive[7].resource_name + = lib_msprintf("Drive%iDolphinDos3", dnr + 8); + cmd_drive[8].name = lib_msprintf("+drive%idd3", dnr + 8); + cmd_drive[8].resource_name + = lib_msprintf("Drive%iDolphinDos3", dnr + 8); if (cmdline_register_options(cmd_drive) < 0) { return -1; } - for (i = 0; i < 7; i++) { + for (i = 0; i < 9; i++) { lib_free(cmd_drive[i].name); lib_free(cmd_drive[i].resource_name); } diff --git a/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.h b/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.h index d78b482c..4d4516ec 100644 --- a/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.h +++ b/src/Emulators/vice/drive/iec/c64exp/c64exp-cmdline-options.h @@ -27,6 +27,6 @@ #ifndef VICE_C64EXP_CMDLINE_OPTIONS_H #define VICE_C64EXP_CMDLINE_OPTIONS_H -extern int c64exp_cmdline_options_init(void); +int c64exp_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.c b/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.c index 9b70750f..f0758561 100644 --- a/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.c +++ b/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.c @@ -25,71 +25,105 @@ */ #include "vice.h" - #include -#include "c64exp-resources.h" #include "drive.h" #include "drivemem.h" +#include "init.h" #include "lib.h" #include "profdos.h" #include "resources.h" #include "stardos-exp.h" #include "supercard.h" +#include "vicetypes.h" +#include "uiapi.h" +#include "userport.h" #include "util.h" +#include "c64exp-resources.h" + +/* #define DEBUG_C64EXP */ + +#ifdef DEBUG_C64EXP +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif static char *profdos_1571_name = NULL; static char *supercard_name = NULL; static char *stardos_name = NULL; - -static void set_drive_ram(unsigned int dnr) -{ - drive_t *drive = drive_context[dnr]->drive; - - if (drive->type != DRIVE_TYPE_1570 && drive->type != DRIVE_TYPE_1571 - && drive->type != DRIVE_TYPE_1571CR) { - return; - } - - drivemem_init(drive_context[dnr], drive->type); - - return; -} - static int set_drive_parallel_cable(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; + int userport_device = -1; switch (val) { case DRIVE_PC_NONE: case DRIVE_PC_STANDARD: case DRIVE_PC_DD3: case DRIVE_PC_FORMEL64: + case DRIVE_PC_21SEC_BACKUP: break; default: return -1; } - drive->parallel_cable = val; - set_drive_ram(vice_ptr_to_uint(param)); + unit->parallel_cable = val; + /* don't reset CMDHD drives */ + if (unit->type != DRIVE_TYPE_CMDHD) { + drivemem_init(unit); + } + + /* some magic to automatically insert or remove the parallel cable into/from the user port */ + resources_get_int("UserportDevice", &userport_device); + + if ((val == DRIVE_PC_NONE) && (userport_device == USERPORT_DEVICE_DRIVE_PAR_CABLE)) { + int hasparcable = 0; + int dnr; + /* check if any drive has a parallel cable enabled */ + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + int cable; + resources_get_int_sprintf("Drive%iParallelCable", &cable, dnr + 8); + if (cable != DRIVE_PC_NONE) { + hasparcable = 1; + } + } + /* if no drive uses parallel cable, disable it in the userport settings */ + if (hasparcable == 0) { + resources_set_int("UserportDevice", USERPORT_DEVICE_NONE); + } + } else if (val != DRIVE_PC_NONE) { + if (userport_device == USERPORT_DEVICE_NONE) { + resources_set_int("UserportDevice", USERPORT_DEVICE_DRIVE_PAR_CABLE); + } else if (userport_device != USERPORT_DEVICE_DRIVE_PAR_CABLE) { + if (init_main_is_done()) { + ui_message("Warning: the user port is already being used for another device.\n" + "To be able to use the parallel cable, you must also set up the user port accordingly."); + } + } + } return 0; } static int set_drive_profdos(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; + + DBG(("set_drive_profdos profdos:%d", val)); - drive->profdos = val ? 1 : 0; - set_drive_ram(vice_ptr_to_uint(param)); + unit->profdos = val ? 1 : 0; + drivemem_init(unit); return 0; } static int set_profdos_1571_name(const char *val, void *param) { + DBG(("set_profdos_1571_name name:%s", val)); + if (util_string_set(&profdos_1571_name, val)) { return 0; } @@ -99,10 +133,10 @@ static int set_profdos_1571_name(const char *val, void *param) static int set_drive_supercard(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->supercard = val ? 1 : 0; - set_drive_ram(vice_ptr_to_uint(param)); + unit->supercard = val ? 1 : 0; + drivemem_init(unit); return 0; } @@ -118,9 +152,9 @@ static int set_supercard_name(const char *val, void *param) static int set_drive_stardos(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->stardos = val ? 1 : 0; + unit->stardos = val ? 1 : 0; return 0; } @@ -134,6 +168,15 @@ static int set_stardos_name(const char *val, void *param) return stardos_exp_load(stardos_name); } +static int set_drive_dd3(int val, void *param) +{ + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; + + unit->dolphindos3 = val ? 1 : 0; + + return 0; +} + static resource_int_t res_drive[] = { { NULL, DRIVE_PC_NONE, RES_EVENT_SAME, NULL, NULL, set_drive_parallel_cable, NULL }, @@ -143,6 +186,8 @@ static resource_int_t res_drive[] = { NULL, set_drive_supercard, NULL }, { NULL, 0, RES_EVENT_SAME, NULL, NULL, set_drive_stardos, NULL }, + { NULL, 0, RES_EVENT_SAME, NULL, + NULL, set_drive_dd3, NULL }, RESOURCE_INT_LIST_END }; @@ -153,30 +198,32 @@ static const resource_string_t resources_string[] = { "DriveSuperCardName", "", RES_EVENT_NO, NULL, &supercard_name, set_supercard_name, NULL }, { "DriveStarDosName", "", RES_EVENT_NO, NULL, - &supercard_name, set_stardos_name, NULL }, + &stardos_name, set_stardos_name, NULL }, RESOURCE_STRING_LIST_END }; int c64exp_resources_init(void) { - unsigned int dnr; - drive_t *drive; + int dnr; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; res_drive[0].name = lib_msprintf("Drive%iParallelCable", dnr + 8); - res_drive[0].value_ptr = &(drive->parallel_cable); - res_drive[0].param = uint_to_void_ptr(dnr); + res_drive[0].value_ptr = &(unit->parallel_cable); + res_drive[0].param = vice_uint_to_ptr(dnr); res_drive[1].name = lib_msprintf("Drive%iProfDOS", dnr + 8); - res_drive[1].value_ptr = &(drive->profdos); - res_drive[1].param = uint_to_void_ptr(dnr); + res_drive[1].value_ptr = &(unit->profdos); + res_drive[1].param = vice_uint_to_ptr(dnr); res_drive[2].name = lib_msprintf("Drive%iSuperCard", dnr + 8); - res_drive[2].value_ptr = &(drive->supercard); - res_drive[2].param = uint_to_void_ptr(dnr); + res_drive[2].value_ptr = &(unit->supercard); + res_drive[2].param = vice_uint_to_ptr(dnr); res_drive[3].name = lib_msprintf("Drive%iStarDos", dnr + 8); - res_drive[3].value_ptr = &(drive->stardos); - res_drive[3].param = uint_to_void_ptr(dnr); + res_drive[3].value_ptr = &(unit->stardos); + res_drive[3].param = vice_uint_to_ptr(dnr); + res_drive[4].name = lib_msprintf("Drive%iDolphinDos3", dnr + 8); + res_drive[4].value_ptr = &(unit->dolphindos3); + res_drive[4].param = vice_uint_to_ptr(dnr); if (resources_register_int(res_drive) < 0) { return -1; @@ -186,6 +233,7 @@ int c64exp_resources_init(void) lib_free(res_drive[1].name); lib_free(res_drive[2].name); lib_free(res_drive[3].name); + lib_free(res_drive[4].name); } return resources_register_string(resources_string); diff --git a/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.h b/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.h index f7314591..6f6ab75c 100644 --- a/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.h +++ b/src/Emulators/vice/drive/iec/c64exp/c64exp-resources.h @@ -27,7 +27,7 @@ #ifndef VICE_C64EXP_RESOURCES_H #define VICE_C64EXP_RESOURCES_H -extern int c64exp_resources_init(void); -extern void c64exp_resources_shutdown(void); +int c64exp_resources_init(void); +void c64exp_resources_shutdown(void); #endif diff --git a/src/Emulators/vice/drive/iec/c64exp/dolphindos3.c b/src/Emulators/vice/drive/iec/c64exp/dolphindos3.c index d8a74d5c..95defdd1 100644 --- a/src/Emulators/vice/drive/iec/c64exp/dolphindos3.c +++ b/src/Emulators/vice/drive/iec/c64exp/dolphindos3.c @@ -28,7 +28,7 @@ /* #define DD3_DEBUG */ #ifdef DD3_DEBUG -#define DBG(x) printf x +#define DBG(x) log_printf x #else #define DBG(x) #endif @@ -46,26 +46,34 @@ #include "log.h" #include "mc6821core.h" -static mc6821_state my6821[DRIVE_NUM]; +/* + * - 6821 mapped to $5000-$5fff for the parallel cable + * - 8k extra RAM at $6000-$7fff + * - 32k DOS ROM at $8000-$ffff + * + * x64sc -drive8type 1541 -drive8ram6000 -drive8dd3 -kernal kernal -dos1541 1541 -parallel8 "2" -userportdevice "21" foo.d64 + */ + +static mc6821_state my6821[NUM_DISK_UNITS]; /*-----------------------------------------------------------------------*/ /* MC6821 hooks */ static void dd3_set_pa(mc6821_state *ctx) { - unsigned int dnr = (unsigned int)(((drive_context_t *)(ctx->p))->mynumber); + unsigned int dnr = (unsigned int)(((diskunit_context_t *)(ctx->p))->mynumber); parallel_cable_drive_write(DRIVE_PC_DD3, ctx->dataA, PARALLEL_WRITE, dnr); - /* DBG(("DD3 (%d) 6821 PA WR %02x\n", dnr, ctx->dataA)); */ + /* DBG(("DD3 (%d) 6821 PA WR %02x", dnr, ctx->dataA)); */ } -static BYTE dd3_get_pa(mc6821_state *ctx) +static uint8_t dd3_get_pa(mc6821_state *ctx) { - unsigned int dnr = (unsigned int)(((drive_context_t *)(ctx->p))->mynumber); - BYTE data; + unsigned int dnr = (unsigned int)(((diskunit_context_t *)(ctx->p))->mynumber); + uint8_t data; int hs = 0; /* output all pins that are in input mode as 1 first */ - parallel_cable_drive_write(DRIVE_PC_DD3, (BYTE)((~ctx->ddrA) | ctx->dataA), PARALLEL_WRITE, dnr); + parallel_cable_drive_write(DRIVE_PC_DD3, (uint8_t)((~ctx->ddrA) | ctx->dataA), PARALLEL_WRITE, dnr); /* FIXME: this is an ugly hack */ hs = 0; @@ -75,38 +83,38 @@ static BYTE dd3_get_pa(mc6821_state *ctx) data = parallel_cable_drive_read(DRIVE_PC_DD3, hs); - DBG(("DD3 6821 PA RD %02x CTRLA %02x CA2 %02x\n", data, ctx->ctrlA, ctx->CA2)); + DBG(("DD3 6821 PA RD %02x CTRLA %02x CA2 %02x", data, ctx->ctrlA, ctx->CA2)); return data; } static void dd3_set_ca2(mc6821_state *ctx) { /* used for handshaking */ - DBG(("DD3 6821 CA2 WR %02x\n", ctx->CA2)); + DBG(("DD3 6821 CA2 WR %02x", ctx->CA2)); } static void dd3_set_pb(mc6821_state *ctx) { /* nothing here ? */ - DBG(("DD3 6821 PB WR %02x\n", ctx->dataB)); + DBG(("DD3 6821 PB WR %02x", ctx->dataB)); } -static BYTE dd3_get_pb(mc6821_state *ctx) +static uint8_t dd3_get_pb(mc6821_state *ctx) { - BYTE data = 0xff; /* unconnected pins return 1 */ - DBG(("DD3 6821 PB RD %02x\n", data)); + uint8_t data = 0xff; /* unconnected pins return 1 */ + DBG(("DD3 6821 PB RD %02x", data)); return data; } static void dd3_set_cb2(mc6821_state *ctx) { /* nothing here ? */ - DBG(("DD3 6821 CB2 WR %02x\n", ctx->CB2)); + DBG(("DD3 6821 CB2 WR %02x", ctx->CB2)); } /*-----------------------------------------------------------------------*/ -static void mc6821_store(drive_context_t *drv, WORD addr, BYTE byte) +static void mc6821_store(diskunit_context_t *drv, uint16_t addr, uint8_t byte) { int port, reg; @@ -115,7 +123,7 @@ static void mc6821_store(drive_context_t *drv, WORD addr, BYTE byte) mc6821core_store(&my6821[drv->mynumber], port /* rs1 */, reg /* rs0 */, byte); } -static BYTE mc6821_read(drive_context_t *drv, WORD addr) +static uint8_t mc6821_read(diskunit_context_t *drv, uint16_t addr) { int port, reg; @@ -124,7 +132,7 @@ static BYTE mc6821_read(drive_context_t *drv, WORD addr) return mc6821core_read(&my6821[drv->mynumber], port /* rs1 */, reg /* rs0 */); } -static BYTE mc6821_peek(drive_context_t *drv, WORD addr) +static uint8_t mc6821_peek(diskunit_context_t *drv, uint16_t addr) { int port, reg; @@ -135,14 +143,23 @@ static BYTE mc6821_peek(drive_context_t *drv, WORD addr) /*-----------------------------------------------------------------------*/ -void dd3_set_signal(drive_context_t *drv) +/* gets called by host parallel_cable_cpu_pulse() */ +void dd3_set_signal(diskunit_context_t *drv) { + /* only call if this drive has the dd3 parallel cable */ + if (drv->parallel_cable != DRIVE_PC_DD3) { + return; + } /* DBG(("DD3 (%d) 6821 SIGNAL\n", dnr)); */ mc6821core_set_signal(&my6821[drv->mynumber], MC6821_SIGNAL_CA1); } -void dd3_init(drive_context_t *drv) +/* CAUTION: gets called no matter if dd3 is enabled or not */ +void dd3_init(diskunit_context_t *drv) { + if (!drv->dolphindos3) { + return; + } my6821[drv->mynumber].p = (void*)drv; my6821[drv->mynumber].set_pa = dd3_set_pa; my6821[drv->mynumber].set_pb = dd3_set_pb; @@ -152,16 +169,21 @@ void dd3_init(drive_context_t *drv) my6821[drv->mynumber].set_cb2 = dd3_set_cb2; } -void dd3_reset(drive_context_t *drv) +/* CAUTION: gets called no matter if dd3 is enabled or not */ +void dd3_reset(diskunit_context_t *drv) { + if (!drv->dolphindos3) { + return; + } mc6821core_reset(&my6821[drv->mynumber]); } -void dd3_mem_init(struct drive_context_s *drv, unsigned int type) +/* CAUTION: gets called no matter if dd3 is enabled or not */ +void dd3_mem_init(struct diskunit_context_s *drv, unsigned int type) { drivecpud_context_t *cpud = drv->cpud; - if (drv->drive->parallel_cable != DRIVE_PC_DD3) { + if (!drv->dolphindos3) { return; } diff --git a/src/Emulators/vice/drive/iec/c64exp/dolphindos3.h b/src/Emulators/vice/drive/iec/c64exp/dolphindos3.h index 3d21f340..38e26163 100644 --- a/src/Emulators/vice/drive/iec/c64exp/dolphindos3.h +++ b/src/Emulators/vice/drive/iec/c64exp/dolphindos3.h @@ -28,11 +28,12 @@ #ifndef VICE_DD3_H #define VICE_DD3_H -struct drive_context_s; -extern void dd3_init(struct drive_context_s *drv); -extern void dd3_reset(struct drive_context_s *drv); -extern void dd3_mem_init(struct drive_context_s *drv, unsigned int type); +struct diskunit_context_s; -extern void dd3_set_signal(struct drive_context_s *drive_context); +void dd3_init(struct diskunit_context_s *drv); +void dd3_reset(struct diskunit_context_s *drv); +void dd3_mem_init(struct diskunit_context_s *drv, unsigned int type); + +void dd3_set_signal(struct diskunit_context_s *diskunit_context); #endif diff --git a/src/Emulators/vice/drive/iec/c64exp/iec-c64exp.c b/src/Emulators/vice/drive/iec/c64exp/iec-c64exp.c index 4e95ae24..c0d88503 100644 --- a/src/Emulators/vice/drive/iec/c64exp/iec-c64exp.c +++ b/src/Emulators/vice/drive/iec/c64exp/iec-c64exp.c @@ -26,6 +26,7 @@ #include "vice.h" +#include "iec-c64exp.h" #include "c64exp-cmdline-options.h" #include "c64exp-resources.h" #include "drivetypes.h" @@ -34,6 +35,13 @@ #include "stardos-exp.h" #include "supercard.h" +/* #define DEBUG_IECEXT */ + +#ifdef DEBUG_IECEXT +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif int iec_c64exp_resources_init(void) { @@ -50,24 +58,30 @@ int iec_c64exp_cmdline_options_init(void) return c64exp_cmdline_options_init(); } -void iec_c64exp_init(struct drive_context_s *drv) +void iec_c64exp_init(struct diskunit_context_s *drv) { + DBG(("iec_c64exp_init profdos:%d supercard:%d stardos:%d dd3:%d", + drv->profdos, drv->supercard, drv->stardos, drv->dolphindos3)); dd3_init(drv); profdos_init(drv); stardos_exp_init(drv); supercard_init(drv); } -void iec_c64exp_reset(struct drive_context_s *drv) +void iec_c64exp_reset(struct diskunit_context_s *drv) { + DBG(("iec_c64exp_reset profdos:%d supercard:%d stardos:%d dd3:%d", + drv->profdos, drv->supercard, drv->stardos, drv->dolphindos3)); dd3_reset(drv); profdos_reset(drv); stardos_exp_reset(drv); supercard_reset(drv); } -void iec_c64exp_mem_init(struct drive_context_s *drv, unsigned int type) +void iec_c64exp_mem_init(struct diskunit_context_s *drv, unsigned int type) { + DBG(("iec_c64exp_mem_init profdos:%d supercard:%d stardos:%d dd3:%d", + drv->profdos, drv->supercard, drv->stardos, drv->dolphindos3)); dd3_mem_init(drv, type); profdos_mem_init(drv, type); stardos_exp_mem_init(drv, type); diff --git a/src/Emulators/vice/drive/iec/c64exp/profdos.c b/src/Emulators/vice/drive/iec/c64exp/profdos.c index 27e6496d..4b83a381 100644 --- a/src/Emulators/vice/drive/iec/c64exp/profdos.c +++ b/src/Emulators/vice/drive/iec/c64exp/profdos.c @@ -39,16 +39,32 @@ #include "resources.h" #include "util.h" +/* #define DEBUG_PROFDOS */ -#define PROFDOS_ROM_SIZE 0x2000 +#ifdef DEBUG_PROFDOS +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +/* + * - extra 8k RAM at $4000 + * - extra 8k ROM at $6000 + * - 32k DOS ROM at $8000 + * + * x64sc -drive8type 1571 -drive8ram4000 -drive8profdos -profdos1571 ROM -kernal Kernal -dos1571 1571 -parallel8 "1" -userportdevice "21" foo.d64 + */ -static BYTE profdos_1571_rom[PROFDOS_ROM_SIZE]; +/* FIXME: should be dynamically allocated */ +#define PROFDOS_ROM_SIZE 0x2000 +static uint8_t profdos_1571_rom[PROFDOS_ROM_SIZE]; -static unsigned int profdos_al[DRIVE_NUM]; +static unsigned int profdos_al[NUM_DISK_UNITS]; int profdos_load_1571(const char *name) { + DBG(("profdos_load_1571 '%s'", name)); if (util_check_null_string(name)) { return 0; } @@ -57,36 +73,43 @@ int profdos_load_1571(const char *name) PROFDOS_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { return -1; } - + DBG(("profdos_load_1571 ok")); return 0; } -static BYTE profdos_read(drive_context_t *drv, WORD addr) +/* $6000-$6fff extra 8k "decoder" rom (first 4k) */ +static uint8_t profdos_read(diskunit_context_t *drv, uint16_t addr) { - return profdos_1571_rom[addr & 0x1fff]; +/* DBG(("profdos_read %04x", addr)); */ + return (drv->cpu->cpu_last_data = profdos_1571_rom[addr & 0x1fff]); } -static BYTE profdos_read2(drive_context_t *drv, WORD addr) +/* $7000-$7fff extra 8k "decoder" rom (second 4k) */ +static uint8_t profdos_read2(diskunit_context_t *drv, uint16_t addr) { + /*DBG(("profdos2_read %04x", addr));*/ if (addr >= 0x7000) { if (!(addr & 0x0800)) { - addr = (WORD)((addr & 0xff0f) | (profdos_al[drv->mynumber] << 4)); + addr = (uint16_t)((addr & 0xff0f) | (profdos_al[drv->mynumber] << 4)); } else { - addr = (WORD)((addr & 0xff00) + addr = (uint16_t)((addr & 0xff00) | (profdos_al[drv->mynumber] << 4) | ((addr >> 4) & 15)); } profdos_al[drv->mynumber] = addr & 15; } - return profdos_1571_rom[addr & 0x1fff]; + return (drv->cpu->cpu_last_data = profdos_1571_rom[addr & 0x1fff]); } -void profdos_mem_init(struct drive_context_s *drv, unsigned int type) +/* CAUTION: gets called no matter if profdos is enabled or not */ +void profdos_mem_init(struct diskunit_context_s *drv, unsigned int type) { drivecpud_context_t *cpud = drv->cpud; - if (!drv->drive->profdos) { + DBG(("profdos_mem_init (profdos:%d)", drv->profdos)); + if (!drv->profdos) { + DBG(("profdos_mem_init skipped!")); return; } @@ -103,11 +126,23 @@ void profdos_mem_init(struct drive_context_s *drv, unsigned int type) } } -void profdos_init(drive_context_t *drv) +/* CAUTION: gets called no matter if profdos is enabled or not */ +void profdos_init(diskunit_context_t *drv) { + DBG(("profdos_init (profdos:%d)", drv->profdos)); + if (!drv->profdos) { + DBG(("profdos_init skipped!")); + return; + } } -void profdos_reset(drive_context_t *drv) +/* CAUTION: gets called no matter if profdos is enabled or not */ +void profdos_reset(diskunit_context_t *drv) { + DBG(("profdos_reset (profdos:%d)", drv->profdos)); + if (!drv->profdos) { + DBG(("profdos_reset skipped!")); + return; + } profdos_al[drv->mynumber] = 0; } diff --git a/src/Emulators/vice/drive/iec/c64exp/profdos.h b/src/Emulators/vice/drive/iec/c64exp/profdos.h index 42a10689..faf2f174 100644 --- a/src/Emulators/vice/drive/iec/c64exp/profdos.h +++ b/src/Emulators/vice/drive/iec/c64exp/profdos.h @@ -29,15 +29,15 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; -extern int profdos_cmdline_options_init(void); +int profdos_cmdline_options_init(void); -extern void profdos_init(struct drive_context_s *drv); -extern void profdos_reset(struct drive_context_s *drv); +void profdos_init(struct diskunit_context_s *drv); +void profdos_reset(struct diskunit_context_s *drv); -extern int profdos_load_1571(const char *name); +int profdos_load_1571(const char *name); -extern void profdos_mem_init(struct drive_context_s *drv, unsigned int type); +void profdos_mem_init(struct diskunit_context_s *drv, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/iec/c64exp/stardos-exp.c b/src/Emulators/vice/drive/iec/c64exp/stardos-exp.c index ef855476..656a7046 100644 --- a/src/Emulators/vice/drive/iec/c64exp/stardos-exp.c +++ b/src/Emulators/vice/drive/iec/c64exp/stardos-exp.c @@ -1,117 +1,132 @@ -/* - * stardos-exp.c - StarDOS emulation. - * - * Written by - * groepaz - * - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - -#include "vice.h" - -#include -#include - -#include "cmdline.h" -#include "drive.h" -#include "drivemem.h" -#include "drivetypes.h" -#include "lib.h" -#include "log.h" -#include "stardos-exp.h" -#include "resources.h" -#include "util.h" - -/* #define DEBUGSD */ - -#ifdef DEBUGSD -#define DBG(x) printf x -#else -#define DBG(x) -#endif - -/* - StarDOS - - - 8k additional ROM at $A000-$Bfff - - to test use: - - x64sc -cartstar StarDosCartRomV1-4-decoded.bin -stardos stardos1541romv1-4-a000-decoded.bin -dos1541 stardos1541romv1-4-e000-decoded.bin -drive8stardos - - */ - -#define STARDOS_ROM_SIZE 0x2000 - -static BYTE stardos_rom[STARDOS_ROM_SIZE]; - -int stardos_exp_load(const char *name) -{ - DBG(("stardos_exp_load <%s>\n", name)); - - if (util_check_null_string(name)) { - return 0; - } - - if (util_file_load(name, stardos_rom, - STARDOS_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { - return -1; - } - return 0; -} - -static BYTE stardos_exp_read(drive_context_t *drv, WORD addr) -{ - DBG(("stardos_exp_read <%04x> <%02x>\n", addr, stardos_rom[addr & 0x1fff])); - return stardos_rom[addr & 0x1fff]; -} - -void stardos_exp_mem_init(struct drive_context_s *drv, unsigned int type) -{ - drivecpud_context_t *cpud = drv->cpud; - - DBG(("stardos_exp_mem_init \n", type, drv->drive->stardos)); - if (!drv->drive->stardos) { - return; - } - - /* Setup additional stardos rom */ - switch (type) { - case DRIVE_TYPE_1540: - case DRIVE_TYPE_1541: - case DRIVE_TYPE_1541II: - /* FIXME: StarDOS for 157x exists apparently, needs more research */ - /* case DRIVE_TYPE_1570: - case DRIVE_TYPE_1571: - case DRIVE_TYPE_1571CR: */ - drivemem_set_func(cpud, 0xA0, 0xC0, stardos_exp_read, NULL, NULL, stardos_rom, 0xa000bffd); - break; - default: - break; - } -} - -void stardos_exp_init(drive_context_t *drv) -{ -} - -void stardos_exp_reset(drive_context_t *drv) -{ -} +/* + * stardos-exp.c - StarDOS emulation. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "cmdline.h" +#include "drive.h" +#include "drivemem.h" +#include "drivetypes.h" +#include "lib.h" +#include "log.h" +#include "stardos-exp.h" +#include "resources.h" +#include "util.h" + +/* #define DEBUGSD */ + +#ifdef DEBUGSD +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* + StarDOS + + the original EPROM has A10 and A11 swapped around. + + the EPROM contains 16k: + + - 8k additional ROM at $A000-$Bfff + - 8k patched upper DOS ROM ($E000-$FFFF) + + to test use: + + x64sc -default -drive8type 1541 \ + -cartstar StarDosCartRomV1-4-decoded.bin \ + -dos1541 stardosdriverom.bin \ + -stardos stardos1541romv1-4-a000-decoded.bin \ + -drive8stardos + + stardosdriverom.bin should combine the lower half of the original DOS plus + the upper half of the stardos ROM + + */ + +#define STARDOS_ROM_SIZE 0x2000 + +static uint8_t stardos_rom[STARDOS_ROM_SIZE]; + +int stardos_exp_load(const char *name) +{ + DBG(("stardos_exp_load <%s>\n", name)); + + if (util_check_null_string(name)) { + return 0; + } + + if (util_file_load(name, stardos_rom, + STARDOS_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + return 0; +} + +static uint8_t stardos_exp_read(diskunit_context_t *drv, uint16_t addr) +{ + DBG(("stardos_exp_read <%04x> <%02x>\n", addr, stardos_rom[addr & 0x1fff])); + return drv->cpu->cpu_last_data = stardos_rom[addr & 0x1fff]; +} + +/* CAUTION: gets called no matter if stardos is enabled or not */ +void stardos_exp_mem_init(struct diskunit_context_s *drv, unsigned int type) +{ + drivecpud_context_t *cpud = drv->cpud; + + DBG(("stardos_exp_mem_init \n", type, drv->stardos)); + if (!drv->stardos) { + return; + } + + /* Setup additional stardos rom */ + switch (type) { + case DRIVE_TYPE_1540: + case DRIVE_TYPE_1541: + case DRIVE_TYPE_1541II: + /* FIXME: StarDOS for 157x exists apparently, needs more research */ + /* case DRIVE_TYPE_1570: + case DRIVE_TYPE_1571: + case DRIVE_TYPE_1571CR: */ + drivemem_set_func(cpud, 0xA0, 0xC0, stardos_exp_read, NULL, NULL, stardos_rom, 0xa000bffd); + break; + default: + break; + } +} + +/* CAUTION: gets called no matter if stardos is enabled or not */ +void stardos_exp_init(diskunit_context_t *drv) +{ +} + +/* CAUTION: gets called no matter if stardos is enabled or not */ +void stardos_exp_reset(diskunit_context_t *drv) +{ +} diff --git a/src/Emulators/vice/drive/iec/c64exp/stardos-exp.h b/src/Emulators/vice/drive/iec/c64exp/stardos-exp.h index 0bf52542..0dfa8f1a 100644 --- a/src/Emulators/vice/drive/iec/c64exp/stardos-exp.h +++ b/src/Emulators/vice/drive/iec/c64exp/stardos-exp.h @@ -1,43 +1,43 @@ -/* - * stardos-exp.h - StarDOS emulation. - * - * Written by - * groepaz - * - * This file is part of VICE, the Versatile Commodore Emulator. - * See README for copyright notice. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA. - * - */ - -#ifndef VICE_STARDOS_EXP_H -#define VICE_STARDOS_EXP_H - -#include "vicetypes.h" - -struct drive_context_s; - -extern int stardos_exp_cmdline_options_init(void); - -extern void stardos_exp_init(struct drive_context_s *drv); -extern void stardos_exp_reset(struct drive_context_s *drv); - -extern int stardos_exp_load(const char *name); - -extern void stardos_exp_mem_init(struct drive_context_s *drv, unsigned int type); - -#endif +/* + * stardos-exp.h - StarDOS emulation. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_STARDOS_EXP_H +#define VICE_STARDOS_EXP_H + +#include "vicetypes.h" + +struct diskunit_context_s; + +int stardos_exp_cmdline_options_init(void); + +void stardos_exp_init(struct diskunit_context_s *drv); +void stardos_exp_reset(struct diskunit_context_s *drv); + +int stardos_exp_load(const char *name); + +void stardos_exp_mem_init(struct diskunit_context_s *drv, unsigned int type); + +#endif diff --git a/src/Emulators/vice/drive/iec/c64exp/supercard.c b/src/Emulators/vice/drive/iec/c64exp/supercard.c index abfce146..fcd9a729 100644 --- a/src/Emulators/vice/drive/iec/c64exp/supercard.c +++ b/src/Emulators/vice/drive/iec/c64exp/supercard.c @@ -62,7 +62,7 @@ #define SUPERCARD_ROM_SIZE 0x2000 -static BYTE supercard_rom[SUPERCARD_ROM_SIZE]; +static uint8_t supercard_rom[SUPERCARD_ROM_SIZE]; int supercard_load(const char *name) { @@ -79,19 +79,20 @@ int supercard_load(const char *name) return 0; } -static BYTE supercard_read(drive_context_t *drv, WORD addr) +static uint8_t supercard_read(diskunit_context_t *drv, uint16_t addr) { DBG(("supercard_read <%04x> <%02x>\n", addr, supercard_rom[addr & 0x07ff])); - return supercard_rom[addr & 0x07ff]; + return drv->cpu->cpu_last_data = supercard_rom[addr & 0x07ff]; } -void supercard_mem_init(struct drive_context_s *drv, unsigned int type) +/* CAUTION: gets called no matter if supercard is enabled or not */ +void supercard_mem_init(struct diskunit_context_s *drv, unsigned int type) { drivecpud_context_t *cpud = drv->cpud; - DBG(("supercard_mem_init \n", type, drv->drive->supercard)); + DBG(("supercard_mem_init \n", type, drv->supercard)); - if (!drv->drive->supercard) { + if (!drv->supercard) { return; } @@ -110,10 +111,12 @@ void supercard_mem_init(struct drive_context_s *drv, unsigned int type) } } -void supercard_init(drive_context_t *drv) +/* CAUTION: gets called no matter if supercard is enabled or not */ +void supercard_init(diskunit_context_t *drv) { } -void supercard_reset(drive_context_t *drv) +/* CAUTION: gets called no matter if supercard is enabled or not */ +void supercard_reset(diskunit_context_t *drv) { } diff --git a/src/Emulators/vice/drive/iec/c64exp/supercard.h b/src/Emulators/vice/drive/iec/c64exp/supercard.h index 11422055..779a23f0 100644 --- a/src/Emulators/vice/drive/iec/c64exp/supercard.h +++ b/src/Emulators/vice/drive/iec/c64exp/supercard.h @@ -29,15 +29,15 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; -extern int supercard_cmdline_options_init(void); +int supercard_cmdline_options_init(void); -extern void supercard_init(struct drive_context_s *drv); -extern void supercard_reset(struct drive_context_s *drv); +void supercard_init(struct diskunit_context_s *drv); +void supercard_reset(struct diskunit_context_s *drv); -extern int supercard_load(const char *name); +int supercard_load(const char *name); -extern void supercard_mem_init(struct drive_context_s *drv, unsigned int type); +void supercard_mem_init(struct diskunit_context_s *drv, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/iec/cia1571d.c b/src/Emulators/vice/drive/iec/cia1571d.c index cba5544b..d0d0d061 100644 --- a/src/Emulators/vice/drive/iec/cia1571d.c +++ b/src/Emulators/vice/drive/iec/cia1571d.c @@ -41,48 +41,140 @@ typedef struct drivecia1571_context_s { unsigned int number; - struct drive_s *drive; + struct diskunit_context_s *diskunit; } drivecia1571_context_t; -void cia1571_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void cia1571_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; ciacore_store(ctxptr->cia1571, addr, data); } -BYTE cia1571_read(drive_context_t *ctxptr, WORD addr) +uint8_t cia1571_read(diskunit_context_t *ctxptr, uint16_t addr) { - return ciacore_read(ctxptr->cia1571, addr); + return ctxptr->cpu->cpu_last_data = ciacore_read(ctxptr->cia1571, addr); } -BYTE cia1571_peek(drive_context_t *ctxptr, WORD addr) +uint8_t cia1571_peek(diskunit_context_t *ctxptr, uint16_t addr) { return ciacore_peek(ctxptr->cia1571, addr); } -int cia1571_dump(drive_context_t *ctxptr, WORD addr) +int cia1571_dump(diskunit_context_t *ctxptr, uint16_t addr) { ciacore_dump(ctxptr->cia1571); return 0; } +/* + FIXME: the actual memory map is quite wild with the mos5710: + + A 15 14 13 12 10 4 3 + CIA 0 1 0 0 x 0 x 4x0x 4x2x 4x4x 4x6x 4x8x 4xax 4xcx 4xex + FDC2 0 1 0 0 0 1 x 401x 403x 405x 407x 409x 40bx 40dx 40fx + 411x 413x 415x 417x 419x 41bx 41dx 41fx + 421x 423x 425x 427x 429x 42bx 42dx 42fx + 431x 433x 435x 437x 439x 43bx 43dx 43fx + 481x 483x 485x 487x 489x 48bx 48dx 48fx + 491x 493x 495x 497x 499x 49bx 49dx 49fx + 4a1x 4a3x 4a5x 4a7x 4a9x 4abx 4adx 4afx + 4b1x 4b3x 4b5x 4b7x 4b9x 4bbx 4bdx 4bfx +*/ +/* FIXME: need to confirm how it actually mirrors on the real drive */ +void mos5710_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) +{ + if ((addr & 0x1f) > 0x0f) { + /* TODO: extra MFM registers */ + } else { + /* HACK HACK: (partially) implemented are registers 0x0c, 0x0d, 0x0e */ + ctxptr->cpu->cpu_last_data = data; + /* the following lets us use the regular CIA emulation */ + switch (addr & 0x0f) { + case 0x0c: + break; + case 0x0d: + if (data & 0x80) { + data &= 0x88; /* only allow SR IRQ */ + } + break; + case 0x0e: + data &= 0x40; /* only SR Input/Output is implemented (?) */ + data |= 0x01; /* force timer running */ + break; + default: + return; /* all other registers are not implemented */ + } + ciacore_store(ctxptr->cia1571, addr & 0x0f, data); + } +} + +/* FIXME: need to confirm how it actually mirrors on the real drive */ +uint8_t mos5710_read(diskunit_context_t *ctxptr, uint16_t addr) +{ + if ((addr & 0x1f) > 0x0f) { + /* TODO: extra MFM registers */ + return ctxptr->cpu->cpu_last_data = 0; + } + + /* the following lets us use the regular CIA emulation */ + switch (addr & 0x0f) { + case 0x0c: + case 0x0d: + case 0x0e: + break; + default: + return 0xff; /* FIXME: all other registers are not implemented */ + } + + return ctxptr->cpu->cpu_last_data = ciacore_read(ctxptr->cia1571, addr & 0x0f); +} + +/* FIXME: need to confirm how it actually mirrors on the real drive */ +uint8_t mos5710_peek(diskunit_context_t *ctxptr, uint16_t addr) +{ + if ((addr & 0x1f) > 0x0f) { + /* TODO: extra MFM registers */ + return 0; + } + + /* the following lets us use the regular CIA emulation */ + switch (addr & 0x0f) { + case 0x0c: + case 0x0d: + case 0x0e: + break; + default: + return 0xff; /* FIXME: all other registers are not implemented */ + } + + return ciacore_peek(ctxptr->cia1571, addr & 0x0f); +} + +int mos5710_dump(diskunit_context_t *ctxptr, uint16_t addr) +{ + ciacore_dump(ctxptr->cia1571); + /* TODO: extra MFM registers */ + return 0; +} + static void cia_set_int_clk(cia_context_t *cia_context, int value, CLOCK clk) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(cia_context->context); + dc = (diskunit_context_t *)(cia_context->context); - interrupt_set_irq(drive_context->cpu->int_status, cia_context->int_num, + interrupt_set_irq(dc->cpu->int_status, cia_context->int_num, value, clk); } static void cia_restore_int(cia_context_t *cia_context, int value) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(cia_context->context); + dc = (diskunit_context_t *)(cia_context->context); - interrupt_restore_irq(drive_context->cpu->int_status, (int)(cia_context->int_num), value); + interrupt_restore_irq(dc->cpu->int_status, (int)(cia_context->int_num), value); } @@ -100,59 +192,59 @@ static void pulse_ciapc(cia_context_t *cia_context, CLOCK rclk) ciap = (drivecia1571_context_t *)(cia_context->prv); - if (ciap->drive->parallel_cable == DRIVE_PC_STANDARD) { + if (ciap->diskunit->parallel_cable == DRIVE_PC_STANDARD) { parallel_cable_drive_write(DRIVE_PC_STANDARD, 0, PARALLEL_HS, ciap->number); } } -static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { } -static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { drivecia1571_context_t *ciap; ciap = (drivecia1571_context_t *)(cia_context->prv); - if (ciap->drive->parallel_cable == DRIVE_PC_STANDARD) { + if (ciap->diskunit->parallel_cable == DRIVE_PC_STANDARD) { parallel_cable_drive_write(DRIVE_PC_STANDARD, byte, PARALLEL_WRITE, ciap->number); } } -static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { } -static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { drivecia1571_context_t *ciap; ciap = (drivecia1571_context_t *)(cia_context->prv); - if (ciap->drive->parallel_cable == DRIVE_PC_STANDARD) { + if (ciap->diskunit->parallel_cable == DRIVE_PC_STANDARD) { parallel_cable_drive_write(DRIVE_PC_STANDARD, byte, PARALLEL_WRITE, ciap->number); } } -static BYTE read_ciapa(cia_context_t *cia_context) +static uint8_t read_ciapa(cia_context_t *cia_context) { - return (BYTE)((0xff & ~(cia_context->c_cia[CIA_DDRA])) + return (uint8_t)((0xff & ~(cia_context->c_cia[CIA_DDRA])) | (cia_context->c_cia[CIA_PRA] & cia_context->c_cia[CIA_DDRA])); } -static BYTE read_ciapb(cia_context_t *cia_context) +static uint8_t read_ciapb(cia_context_t *cia_context) { drivecia1571_context_t *ciap; - BYTE byte = 0xff; + uint8_t byte = 0xff; ciap = (drivecia1571_context_t *)(cia_context->prv); - if (ciap->drive->parallel_cable == DRIVE_PC_STANDARD) { - byte = parallel_cable_drive_read(ciap->drive->parallel_cable, 1); + if (ciap->diskunit->parallel_cable == DRIVE_PC_STANDARD) { + byte = parallel_cable_drive_read(ciap->diskunit->parallel_cable, 1); } - return (BYTE)((byte & ~(cia_context->c_cia[CIA_DDRB])) + return (uint8_t)((byte & ~(cia_context->c_cia[CIA_DDRB])) | (cia_context->c_cia[CIA_PRB] & cia_context->c_cia[CIA_DDRB])); } @@ -164,22 +256,22 @@ static void read_sdr(cia_context_t *cia_context) { } -static void store_sdr(cia_context_t *cia_context, BYTE byte) +static void store_sdr(cia_context_t *cia_context, uint8_t byte) { drivecia1571_context_t *cia1571p; cia1571p = (drivecia1571_context_t *)(cia_context->prv); - iec_fast_drive_write((BYTE)byte, cia1571p->number); + iec_fast_drive_write((uint8_t)byte, cia1571p->number); } -void cia1571_init(drive_context_t *ctxptr) +void cia1571_init(diskunit_context_t *ctxptr) { ciacore_init(ctxptr->cia1571, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void cia1571_setup_context(drive_context_t *ctxptr) +void cia1571_setup_context(diskunit_context_t *ctxptr) { drivecia1571_context_t *cia1571p; cia_context_t *cia; @@ -189,7 +281,7 @@ void cia1571_setup_context(drive_context_t *ctxptr) cia->prv = lib_malloc(sizeof(drivecia1571_context_t)); cia1571p = (drivecia1571_context_t *)(cia->prv); - cia1571p->number = (unsigned int)(ctxptr->mynumber); + cia1571p->number = ctxptr->mynumber; cia->context = (void *)ctxptr; @@ -202,9 +294,9 @@ void cia1571_setup_context(drive_context_t *ctxptr) cia->debugFlag = 0; cia->irq_line = IK_IRQ; - cia->myname = lib_msprintf("CIA1571D%d", ctxptr->mynumber); + cia->myname = lib_msprintf("CIA1571D%u", ctxptr->mynumber); - cia1571p->drive = ctxptr->drive; + cia1571p->diskunit = ctxptr; cia->undump_ciapa = undump_ciapa; cia->undump_ciapb = undump_ciapb; diff --git a/src/Emulators/vice/drive/iec/cia1581d.c b/src/Emulators/vice/drive/iec/cia1581d.c index c2346ef6..d6f42388 100644 --- a/src/Emulators/vice/drive/iec/cia1581d.c +++ b/src/Emulators/vice/drive/iec/cia1581d.c @@ -50,22 +50,23 @@ typedef struct drivecia1581_context_s { } drivecia1581_context_t; -void cia1581_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void cia1581_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; ciacore_store(ctxptr->cia1581, addr, data); } -BYTE cia1581_read(drive_context_t *ctxptr, WORD addr) +uint8_t cia1581_read(diskunit_context_t *ctxptr, uint16_t addr) { - return ciacore_read(ctxptr->cia1581, addr); + return ctxptr->cpu->cpu_last_data = ciacore_read(ctxptr->cia1581, addr); } -BYTE cia1581_peek(drive_context_t *ctxptr, WORD addr) +uint8_t cia1581_peek(diskunit_context_t *ctxptr, uint16_t addr) { return ciacore_peek(ctxptr->cia1581, addr); } -int cia1581_dump(drive_context_t *ctxptr, WORD addr) +int cia1581_dump(diskunit_context_t *ctxptr, uint16_t addr) { ciacore_dump(ctxptr->cia1581); return 0; @@ -73,21 +74,21 @@ int cia1581_dump(drive_context_t *ctxptr, WORD addr) static void cia_set_int_clk(cia_context_t *cia_context, int value, CLOCK clk) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(cia_context->context); + dc = (diskunit_context_t *)(cia_context->context); - interrupt_set_irq(drive_context->cpu->int_status, cia_context->int_num, + interrupt_set_irq(dc->cpu->int_status, cia_context->int_num, value, clk); } static void cia_restore_int(cia_context_t *cia_context, int value) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(cia_context->context); + dc = (diskunit_context_t *)(cia_context->context); - interrupt_restore_irq(drive_context->cpu->int_status, (int)(cia_context->int_num), value); + interrupt_restore_irq(dc->cpu->int_status, (int)(cia_context->int_num), value); } /************************************************************************* @@ -111,7 +112,7 @@ static void pulse_ciapc(cia_context_t *cia_context, CLOCK rclk) #define PRE_READ_CIA #define PRE_PEEK_CIA -static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE b) +static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t b) { drivecia1581_context_t *cia1581p; @@ -120,17 +121,17 @@ static void undump_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE b) cia1581p->drive->led_status = (b & 0x40) ? 1 : 0; } -static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE b) +static void undump_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t b) { } -static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { drivecia1581_context_t *cia1581p; - drive_context_t *drive; + diskunit_context_t *drive; cia1581p = (drivecia1581_context_t *)(cia_context->prv); - drive = (drive_context_t *)(cia_context->context); + drive = (diskunit_context_t *)(cia_context->context); wd1770_set_side(drive->wd1770, (byte & 0x01) ? 0 : 1); wd1770_set_motor(drive->wd1770, (byte & 0x04) ? 0 : 1); @@ -143,7 +144,7 @@ static void store_ciapa(cia_context_t *cia_context, CLOCK rclk, BYTE byte) cia1581p->drive->led_last_change_clk = *(cia_context->clk_ptr); } -static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) +static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, uint8_t byte) { drivecia1581_context_t *cia1581p; @@ -151,71 +152,71 @@ static void store_ciapb(cia_context_t *cia_context, CLOCK rclk, BYTE byte) if (byte != cia_context->old_pb) { if (cia1581p->iecbus != NULL) { - BYTE *drive_bus, *drive_data; + uint8_t *drive_bus, *drive_data; unsigned int unit; drive_bus = &(cia1581p->iecbus->drv_bus[cia1581p->number + 8]); drive_data = &(cia1581p->iecbus->drv_data[cia1581p->number + 8]); - *drive_data = (BYTE)~byte; - *drive_bus = (BYTE)(((((*drive_data) << 3) & 0x40) + *drive_data = (uint8_t)~byte; + *drive_bus = (uint8_t)(((((*drive_data) << 3) & 0x40) | (((*drive_data) << 6) & (((*drive_data) | cia1581p->iecbus->cpu_bus) << 3) & 0x80))); cia1581p->iecbus->cpu_port = cia1581p->iecbus->cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { cia1581p->iecbus->cpu_port &= cia1581p->iecbus->drv_bus[unit]; } cia1581p->iecbus->drv_port = - (BYTE)((((cia1581p->iecbus->cpu_port >> 4) & 0x4) + (uint8_t)((((cia1581p->iecbus->cpu_port >> 4) & 0x4) | (cia1581p->iecbus->cpu_port >> 7) | ((cia1581p->iecbus->cpu_bus << 3) & 0x80))); } else { - iec_drive_write((BYTE)(~byte), cia1581p->number); + iec_drive_write((uint8_t)(~byte), cia1581p->number); } iec_fast_drive_direction(byte & 0x20, cia1581p->number); } } -static BYTE read_ciapa(cia_context_t *cia_context) +static uint8_t read_ciapa(cia_context_t *cia_context) { - drive_context_t *drive_context; + diskunit_context_t *dc; drivecia1581_context_t *cia1581p; - BYTE tmp; + uint8_t tmp; cia1581p = (drivecia1581_context_t *)(cia_context->prv); - drive_context = (drive_context_t *)(cia_context->context); + dc = (diskunit_context_t *)(cia_context->context); - tmp = (BYTE)(8 * (cia1581p->number)); + tmp = (uint8_t)(8 * (cia1581p->number)); - if (!wd1770_disk_change(drive_context->wd1770)) { + if (!wd1770_disk_change(dc->wd1770)) { tmp |= 0x80; } - return (BYTE)((tmp & ~(cia_context->c_cia[CIA_DDRA])) + return (uint8_t)((tmp & ~(cia_context->c_cia[CIA_DDRA])) | (cia_context->c_cia[CIA_PRA] & cia_context->c_cia[CIA_DDRA])); } -static BYTE read_ciapb(cia_context_t *cia_context) +static uint8_t read_ciapb(cia_context_t *cia_context) { drivecia1581_context_t *cia1581p; cia1581p = (drivecia1581_context_t *)(cia_context->prv); if (cia1581p->iecbus != NULL) { - BYTE *drive_port; + uint8_t *drive_port; drive_port = &(cia1581p->iecbus->drv_port); - return (BYTE)((((cia_context->c_cia[CIA_PRB] & 0x1a) + return (uint8_t)((((cia_context->c_cia[CIA_PRB] & 0x1a) | (*drive_port)) ^ 0x85) | (cia1581p->drive->read_only ? 0 : 0x40)); } else { - return (BYTE)((((cia_context->c_cia[CIA_PRB] & 0x1a) + return (uint8_t)((((cia_context->c_cia[CIA_PRB] & 0x1a) | iec_drive_read(cia1581p->number)) ^ 0x85) | (cia1581p->drive->read_only ? 0 : 0x40)); } @@ -229,7 +230,7 @@ static void read_sdr(cia_context_t *cia_context) { } -static void store_sdr(cia_context_t *cia_context, BYTE byte) +static void store_sdr(cia_context_t *cia_context, uint8_t byte) { drivecia1581_context_t *cia1581p; @@ -238,13 +239,13 @@ static void store_sdr(cia_context_t *cia_context, BYTE byte) iec_fast_drive_write(byte, cia1581p->number); } -void cia1581_init(drive_context_t *ctxptr) +void cia1581_init(diskunit_context_t *ctxptr) { ciacore_init(ctxptr->cia1581, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void cia1581_setup_context(drive_context_t *ctxptr) +void cia1581_setup_context(diskunit_context_t *ctxptr) { drivecia1581_context_t *cia1581p; cia_context_t *cia; @@ -254,7 +255,7 @@ void cia1581_setup_context(drive_context_t *ctxptr) cia->prv = lib_malloc(sizeof(drivecia1581_context_t)); cia1581p = (drivecia1581_context_t *)(cia->prv); - cia1581p->number = (unsigned int)(ctxptr->mynumber); + cia1581p->number = ctxptr->mynumber; cia->context = (void *)ctxptr; @@ -268,9 +269,9 @@ void cia1581_setup_context(drive_context_t *ctxptr) cia->debugFlag = 0; cia->irq_line = IK_IRQ; - cia->myname = lib_msprintf("CIA1581D%d", ctxptr->mynumber); + cia->myname = lib_msprintf("CIA1581D%u", ctxptr->mynumber); - cia1581p->drive = ctxptr->drive; + cia1581p->drive = ctxptr->drives[0]; cia1581p->iecbus = iecbus_drive_port(); cia->undump_ciapa = undump_ciapa; diff --git a/src/Emulators/vice/drive/iec/ciad.h b/src/Emulators/vice/drive/iec/ciad.h index 25f932e9..77a87fc5 100644 --- a/src/Emulators/vice/drive/iec/ciad.h +++ b/src/Emulators/vice/drive/iec/ciad.h @@ -31,24 +31,29 @@ struct cia_context_s; struct cia_initdesc_s; -struct drive_context_s; - -extern void cia1571_setup_context(struct drive_context_s *ctxptr); -extern void cia1581_setup_context(struct drive_context_s *ctxptr); - -extern void cia1571_init(struct drive_context_s *ctxptr); -extern void cia1571_store(struct drive_context_s *ctxptr, WORD addr, BYTE value); -extern BYTE cia1571_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE cia1571_peek(struct drive_context_s *ctxptr, WORD addr); -extern int cia1571_dump(struct drive_context_s *ctxptr, WORD addr); - -extern void cia1581_init(struct drive_context_s *ctxptr); -extern void cia1581_store(struct drive_context_s *ctxptr, WORD addr, BYTE value); -extern BYTE cia1581_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE cia1581_peek(struct drive_context_s *ctxptr, WORD addr); -extern int cia1581_dump(struct drive_context_s *ctxptr, WORD addr); - -extern void cia1571_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); -extern void cia1581_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); +struct diskunit_context_s; + +void cia1571_setup_context(struct diskunit_context_s *ctxptr); +void cia1581_setup_context(struct diskunit_context_s *ctxptr); + +void cia1571_init(struct diskunit_context_s *ctxptr); +void cia1571_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t value); +uint8_t cia1571_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t cia1571_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int cia1571_dump(struct diskunit_context_s *ctxptr, uint16_t addr); + +void mos5710_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t value); +uint8_t mos5710_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t mos5710_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int mos5710_dump(struct diskunit_context_s *ctxptr, uint16_t addr); + +void cia1581_init(struct diskunit_context_s *ctxptr); +void cia1581_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t value); +uint8_t cia1581_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t cia1581_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int cia1581_dump(struct diskunit_context_s *ctxptr, uint16_t addr); + +void cia1571_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); +void cia1581_set_timing(struct cia_context_s *cia_context, int tickspersec, int powerfreq); #endif diff --git a/src/Emulators/vice/drive/iec/cmdhd.c b/src/Emulators/vice/drive/iec/cmdhd.c new file mode 100644 index 00000000..5658eca3 --- /dev/null +++ b/src/Emulators/vice/drive/iec/cmdhd.c @@ -0,0 +1,1628 @@ +/* + * cmdhd.c - Whole CMDHD emulation + * + * Written by + * Roberto Muscedere (rmusced@uwindsor.ca) + * + * Based on old code by + * Kajtar Zsolt + * Andreas Boose + * Andre Fachat + * Daniel Sladic + * Ettore Perazzoli + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "diskimage.h" +#include "debug.h" +#include "drive.h" +#include "drivesync.h" +#include "drivetypes.h" +#include "iecbus.h" +#include "iecdrive.h" +#include "interrupt.h" +#include "lib.h" +#include "vicetypes.h" +#include "cmdhd.h" +#include "util.h" +#include "diskimage/fsimage.h" +#include "rtc/rtc-72421.h" +#include "resources.h" + +#define LOG LOG_DEFAULT + +/* #define CMDLOG */ +/* #define CMDIO */ +/* #define CMDBUS */ + +#ifdef CMDLOG +#define CLOG(_x_) log_message _x_ +#else +#define CLOG(_x_) +#endif + +#ifdef CMDIO +#define IDBG(_x_) log_message _x_ +#else +#define IDBG(_x_) +#endif + +#ifdef CMDBUS +#define BLOG(_x_) log_message _x_ +#else +#define BLOG(_x_) +#endif + +#define CRIT(_x_) log_error _x_ + +#define iecbus (viap->v_iecbus) + +cmdbus_t cmdbus; + +typedef struct drivevia_context_s { + unsigned int number; + struct drive_s *drive; + struct iecbus_s *v_iecbus; +} drivevia_context_t; + +/* Although SCSI can be a multi-master bus, CMD HD's assume they are the +masters so we won't implement all the possible varitions, just a "target" +device that will respond to all (0-6) IDs and 0-7 LUNs for each */ +/* Latest boot rom (2.8) and even earlier have a bug when deleting partitions +across multiple drives */ +/* Although we can support up to 55 (tested), deleting partitions corrupts +the data so we will not allow this, at least for now */ +/* SCSI states are setup to reflect the register values coming out of U13 to +simplify the interface */ +/* All signals asserted high here, opposite in physical implementation + (open-collector/drain etc) + + SEL BSY IO MSG CD U9-PB2-0 PHASE + 0 0 X X X X BUSFREE + 0 1 X X X X ARBITRATION + 1 0 X X X X SELECTION (phase 1) + 1 1 X X X X SELECTION (phase 2) + 0 1 0 0 0 0 DATA-OUT + 0 1 0 0 1 1 COMMAND + 0 1 1 0 0 4 DATA-IN + 0 1 1 0 1 5 STATUS + 0 1 0 1 1 3 MESSAGE-OUT + 0 1 1 1 1 7 MESSAGE-IN + +*/ + +#define CMD_STATE_DATAOUT 0x00 +#define CMD_STATE_COMMAND 0x01 +#define CMD_STATE_DATAIN 0x04 +#define CMD_STATE_STATUS 0x05 +#define CMD_STATE_MESSAGEOUT 0x03 +#define CMD_STATE_MESSAGEIN 0x07 + +# undef DEBUG_IEC_DRV_WRITE +# undef DEBUG_IEC_DRV_READ + +#ifdef DEBUG + +# define DEBUG_IEC_DRV_WRITE(_data) my_debug_iec_drv_write(_data) +# define DEBUG_IEC_DRV_READ(_data) my_debug_iec_drv_read(_data) + +#else + +# define DEBUG_IEC_DRV_WRITE(_data) +# define DEBUG_IEC_DRV_READ(_data) + +#endif + +#ifdef DEBUG + +#include "log.h" + +static void my_debug_iec_drv_write(unsigned int data) +{ + if (debug.iec) { + uint8_t value = data; + static uint8_t oldvalue = 0; + + if (value != oldvalue) { + oldvalue = value; + + log_debug(LOG_DEFAULT, "$1800 store: %s %s %s", + value & 0x02 ? "DATA OUT" : " ", + value & 0x08 ? "CLK OUT" : " ", + value & 0x10 ? "ATNA " : " " + ); + } + } +} + +static void my_debug_iec_drv_read(unsigned int data) +{ + if (debug.iec) { + uint8_t value = data; + static uint8_t oldvalue = { 0 }; + const char * data_correct = ""; + + if (value != oldvalue) { + unsigned int atn = value & 0x80 ? 1 : 0; + unsigned int atna = value & 0x10 ? 1 : 0; + unsigned int ddata = value & 0x01 ? 1 : 0; + + oldvalue = value; + + if (atn && atna) { + if (!ddata) { + data_correct = " ***** ERROR: ATN, ATNA & DATA! *****"; + } + } + + log_debug(LOG_DEFAULT, "$1800 read: %s %s %s %s %s %s%s", + value & 0x02 ? "DATA OUT" : " ", + value & 0x08 ? "CLK OUT" : " ", + value & 0x10 ? "ATNA " : " ", + + value & 0x01 ? "DATA IN" : " ", + value & 0x04 ? "CLK IN" : " ", + value & 0x80 ? "ATN" : " ", + data_correct + ); + } + } +} +#endif + +/* copy some functions here so we don't make them external */ +static uint8_t drive_read_rom(diskunit_context_t *drv, uint16_t address) +{ + return drv->rom[address & 0x7fff]; +} + +static uint8_t drive_read_ram(diskunit_context_t *drv, uint16_t address) +{ + return drv->drive_ram[address]; +} + +static void drive_store_ram(diskunit_context_t *drv, uint16_t address, uint8_t value) +{ + drv->drive_ram[address] = value; +} + +static void reset_alarm_handler(CLOCK offset, void *data) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)data; + + CLOG((LOG, "CMDHD: alarm triggered at %lu; releasing buttons", + *(hd->mycontext->clk_ptr))); + /* stop pressing WP, SWAP8, and SWAP9 buttons */ + hd->i8255a_i[1] |= (0x08 | 0x04 | 0x02); + /* update in drive context too */ + hd->mycontext->button = 0; + + alarm_unset(hd->reset_alarm); +} + +/* returns 0 if block has CMCHD signature at end */ +static int cmdhd_has_sig(unsigned char *buf) +{ + unsigned char hdmagic[16]={0x43, 0x4d, 0x44, 0x20, 0x48, 0x44, 0x20, 0x20, + 0x8d, 0x03, 0x88, 0x8e, 0x02, 0x88, 0xea, 0x60}; + return memcmp(&(buf[0xf0]), hdmagic, 16); +} + +static void cmdhd_scsiread(struct scsi_context_s *scsi) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p); + drive_t *dc = (drive_t *)(hd->mycontext->drives[0]); + int unit = hd->mycontext->mynumber + 8; + int track; + + /* update track info on status bar; never 100 or above */ + track = (scsi->address * 200) / (hd->imagesize + 1); + if (track >= 200) { + track = 199; + } + dc->current_half_track = track; + + /* leave if we are not the first disk */ + if (scsi->target !=0 || scsi->lun != 0 ) { + return; + } + + /* correct device number on the fly since it is stored on HD not by switch or EEPROM */ + if (hd->baselba != UINT32_MAX && scsi->address == hd->baselba + 2) { + /* make sure it has the CMD signature first */ + if (!cmdhd_has_sig(&(scsi->data_buf[256]))) { + /* if it isn't what was defined by vice, set it to it */ + if ( (scsi->data_buf[0x1e1] != unit) || + (scsi->data_buf[0x1e4] != unit) ) { + /* tell the user it is happening */ + CLOG((LOG, "CMDHD: drive number is now %d; was %d in config block", + unit, (int)scsi->data_buf[0x1e1])); + scsi->data_buf[0x1e1] = unit; + scsi->data_buf[0x1e4] = unit; + } + } else { + /* block we had on record no longer has signature, invalidate it */ + hd->baselba = UINT32_MAX; + } + } +} + +static void cmdhd_scsiwrite(struct scsi_context_s *scsi) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p); + drive_t *dc = (drive_t *)(hd->mycontext->drives[0]); + uint32_t temp; + + /* keep track of the maximum lba written to */ + temp = scsi->address + 1; + if (temp > hd->imagesize) { + hd->imagesize = temp; + } + + /* update track info on status bar */ + dc->current_half_track = (scsi->address * 200) / (hd->imagesize + 1); +} + +/* We don't actually format the disk, we just remove the 16 byte CMD signature */ +static void cmdhd_scsiformat(struct scsi_context_s *scsi) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(scsi->p); + int i; + + /* leave if we are not the first disk */ + if (scsi->target !=0 || scsi->lun != 0 ) { + return; + } + + /* correct device number on the fly since it is stored on HD not by switch or EEPROM */ + /* figure out where to start looking */ + if (hd->baselba != UINT32_MAX) { + /* use what we already have if we found it before */ + if (hd->baselba < hd->imagesize) { + scsi->address = hd->baselba + 2; + } else { + /* other wise, start from scratch */ + hd->baselba = UINT32_MAX; + scsi->address = 2; + } + } else { + scsi->address = 2; + } + /* start searching, every 128 LBAs starting from 2 or known base */ + while (scsi->address < hd->imagesize) { + /* stop if we hit the end of the file */ + if (scsi_image_read(scsi) < 0) { + break; + } + /* check for the CMD sig */ + if (!cmdhd_has_sig(&(scsi->data_buf[256]))) { + hd->baselba = scsi->address - 2; + /* we found it, zero it out */ + for (i = 0; i < 16; i++) { + scsi->data_buf[0x1f0 + i] = 0; + } + /* write it back */ + scsi_image_write(scsi); + break; + } + /* otherwise, keep looking */ + scsi->address += 128; + } +} + +/* Set all the inputs high, like the pull-up resistors do */ +void cmdbus_init(void) +{ + int i; + + cmdbus.cpu_data = 0xff; + cmdbus.cpu_bus = 0xff; + cmdbus.data = 0xff; + cmdbus.bus = 0xff; + for (i = 0; i < NUM_DISK_UNITS; i++) { + cmdbus.drv_data[i] = 0xff; + cmdbus.drv_bus[i] = 0xff; + } +} + +/* Calculate the data/bus values */ +void cmdbus_update(void) +{ + int i; + + /* only allow devices to impact the bus if bit 0 is set on bus part */ + if (cmdbus.cpu_bus & 1) { + cmdbus.bus = cmdbus.cpu_bus; + cmdbus.data = cmdbus.cpu_data; + } else { + cmdbus.bus = 0xff; + cmdbus.data = 0xff; + } + for (i = 0; i < NUM_DISK_UNITS; i++) { + /* only allow devices to impact the bus if bit 0 is set on bus part */ + /* and if the parallel cable is not set to none */ + if ((cmdbus.drv_bus[i] & 1) && (diskunit_context[i]->parallel_cable)) { + cmdbus.bus &= cmdbus.drv_bus[i]; + cmdbus.data &= cmdbus.drv_data[i]; + } + } + + BLOG((LOG, "CMDBUS PREADY=%s PCLK=%s PATN=%s", cmdbus.bus & 0x80 ? "LOW " : "HIGH", + cmdbus.bus & 0x40 ? "LOW " : "HIGH", cmdbus.bus & 0x20 ? "LOW " : "HIGH")); +} + +/* U11 or i8255a interfacing */ +/* Port A is for CMD Parallel bus, input/output, data only */ +static void set_pa(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p); + + cmdbus.drv_data[hd->mycontext->mynumber] = byte; + cmdbus_update(); +} + +static uint8_t get_pa(struct _i8255a_state *ctx, int8_t reg) +{ + uint8_t data = 0xff; + + if (reg == 0) { + /* if reg is 0, it is an actual read from the register */ + data = cmdbus.data; + } else { + /* otherwise it is a bus change; physically it is pulled up */ + data = 0xff; + } + + return data; +} + +/* Port B is for CMD Parallel bus the buttons (input only): + PB7 is PATN + PB6 is PCLK + PB5 is not referenced + PB4 is not referenced + PB3 is WP (active low) + PB2 is SWAP9 (active low) + PB1 is SWAP8 (active low) + PB0 is PREADY +*/ +static void set_pb(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p); + + hd->i8255a_o[1] = byte; +} + +static uint8_t get_pb(struct _i8255a_state *ctx, int8_t reg) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p); + uint8_t data = 0xff; + + data = ((~cmdbus.bus << 2) & 0x80) | /* PATN */ + (~cmdbus.bus & 0x40) | /* PCLK */ + ((~cmdbus.bus >> 7) & 0x01) | /* PREADY */ + (hd->i8255a_i[1] & 0x3e); /* Everything else */ + + return data; +} + +/* Called to deal with how PATN changes PREADY */ +/* "new" and "old", 0 or 1, are PATN, not /PATN */ +/* CMDHD's have a circuit which drives /PREADY */ +/* It has a FF where PC7 controls /CLR and PATN is the CLK */ +/* The output is NANDed with PATN which drives /PREADY */ +/* /PREADY is also connected to a buffer (OC) driven by PC7 */ +static int cmdhd_patn_changed(unsigned int unit, int new, int old) +{ + cmdhd_context_t *hd; + int t; + + /* standard unit range check */ + if (unit < 8 || unit > 8 + NUM_DISK_UNITS) { + return -1; + } + + /* check context */ + if (!diskunit_context[unit - 8]) { + return -1; + } + + if (diskunit_context[unit - 8]->type != DRIVE_TYPE_CMDHD) { + return -1; + } + + /* get context */ + hd = diskunit_context[unit - 8]->cmdhd; + + /* leave if no HD contxt provided */ + if (!hd) { + return -1; + } + + /* The drive type is a CMDHD by this point */ + + if ((hd->i8255a_o[2] & 0x80) == 0) { + /* when PC7 is 0, PREADYFF becomes 0 */ + hd->preadyff = 0; + } else if (old == 0 && new == 1) { + /* on rising edge of PATN, PREADYFF = 1 */ + hd->preadyff = 1; + } + /* /PREADY = !(NEWATN & PREADYFF) */ + t = !(new & hd->preadyff); + /* The OC buffer */ + if ((hd->i8255a_o[2] & 0x80) == 0) { + t = 0; + } + + cmdbus.drv_bus[unit - 8] = (cmdbus.drv_bus[unit - 8] & 0x7f) | (t << 7); + + return 0; +} + +/* Update ALL TDE units when PATN changed */ +/* called from ramlink */ +void cmdbus_patn_changed(int new, int old) +{ + int unit; + + for (unit = 8; unit < 8 + NUM_DISK_UNITS; unit++ ) { + cmdhd_patn_changed(unit, new, old); + } +} + +/* Port C is for CMD Parallel bus, SCSI, and memory control (output only): + PC7 is for used for driving PREADY + PC6 is /PCLK + PC5 is /PEXT + PC4 is SCSI BSY + PC3 is SCSI RST + PC2 is SCSI ATN + PC1 is RAM mapping + PC0 is ROM control +*/ +static void set_pc(struct _i8255a_state *ctx, uint8_t byte, int8_t reg) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p); + scsi_context_t *scsi = (scsi_context_t*)(hd->scsi); + int t; + int mynumber = hd->mycontext->mynumber; + + hd->i8255a_o[2] = byte; + scsi->atn = ((hd->i8255a_o[2] & 4)!=0); + scsi->rst = ((hd->i8255a_o[2] & 8)!=0); + scsi->bsyi = ((hd->i8255a_o[2] & 16)!=0); + scsi_process_noack(scsi); + + /* get the PATN state (from /PATN) */ + t = (cmdbus.bus) & 0x20 ? 0 : 1; + + /* adjust /PREADY */ + cmdhd_patn_changed(mynumber + 8, t, t); + + /* update bus */ + cmdbus.drv_bus[mynumber] = + (cmdbus.drv_bus[mynumber] & 0xa0) | /* old /PREADY and /PATN */ + (hd->i8255a_o[2] & 0x40) | /* /PCLK */ + ((hd->i8255a_o[2] & 0x20)>>1) | /* /PEXT */ + 0x0f; /* everything else */ + cmdbus_update(); +} + +static uint8_t get_pc(struct _i8255a_state *ctx, int8_t reg) +{ + cmdhd_context_t *hd = (cmdhd_context_t*)(ctx->p); + uint8_t data = 0xff; + + data = hd->i8255a_i[2]; + + return data; +} + +static void updateleds(diskunit_context_t *ctxptr) +{ + ctxptr->drives[0]->led_status = (ctxptr->cmdhd->LEDs & 0x02) ? 0 : 2; + ctxptr->drives[0]->led_status |= (ctxptr->cmdhd->LEDs & 0x01) ? 0 : 1; +} + +void cmdhd_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) +{ +#ifdef CMDIO + static uint8_t oldd; + static uint16_t olda; + static CLOCK oldc = 0; + drivecpu_context_t *cpu = ctxptr->cpu; +#define storedebug() \ +if (olda != addr || olds != data) { \ + IDBG((LOG, "CMDHD: IO write %02x to %04x PC=%04x CYCLE=%u", data, addr, \ + cpu->cpu_R65C02_regs.pc, *(ctxptr->clk_ptr)-oldc); \ + old=data; \ + olda=addr; \ + oldc=*(ctxptr->clk_ptr); \ +} +#else +#define storedebug() +#endif + ctxptr->cpu->cpu_last_data = data; + /* Decode bits 15-12 */ + switch ( (addr >> 12) & 15 ) { + case 0x4: + case 0x5: + case 0x6: + case 0x7: + /* Since the ROM wants to read/write from the RAM from 0xC000-0xFFFF, + when 0x8802.1 = 0, RAM from 0xC000-0xFFFF maps to 0x4000-0x7FFF */ + if (ctxptr->cmdhd->i8255a_o[2]&2) { + drive_store_ram(ctxptr, (addr & 0x3fff) | 0x4000, data ); + } else { + drive_store_ram(ctxptr, (addr & 0x3fff) | 0xC000, data ); + } + break; + case 0x8: + /* Decode bits 11-8 */ + /* Since the kernel is loaded into RAM from the HD on startup, if + 0x8F00.5=0 then the memory (not IO) above 0x8000 is protected from + being written to */ + switch ((addr >> 8) & 15) { + case 0x0: /* 0x80xx U10 */ + case 0x1: /* 0x81xx U10 */ + storedebug() + viacore_store(ctxptr->cmdhd->via10, addr & 15, data); + break; + case 0x4: /* 0x84xx U9 */ + case 0x5: /* 0x85xx U9 */ + storedebug() + viacore_store(ctxptr->cmdhd->via9, addr & 15, data); + break; + case 0x8: /* 0x88xx U11 */ + case 0x9: /* 0x89xx U11 */ + storedebug() + i8255a_store(ctxptr->cmdhd->i8255a, addr & 3, data); + break; + case 0xc: /* 0x8cxx */ + case 0xd: /* 0x8dxx */ + storedebug() + rtc72421_write(ctxptr->cmdhd->rtc, addr & 15, data); + break; + case 0xf: /* 0x8fxx U20 */ + /* Although page 0x8F is RAM, all writes go to U20 */ + /* OS often reads from 0x8f00 to get past values to OR/AND them */ + storedebug() + ctxptr->cmdhd->LEDs = data; + drive_store_ram(ctxptr, (addr & 255) | 0x8f00, data); + updateleds(ctxptr); + break; + case 0xe: /* 0x8exx unprotected RAM */ + drive_store_ram(ctxptr, (addr & 255) | 0x8e00, data); + break; + default: + /* Everything else writes to RAM if switch is on */ + if (ctxptr->cmdhd->LEDs&32) { + drive_store_ram(ctxptr, addr, data); + } + break; + } + break; + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + if (ctxptr->cmdhd->LEDs&32) { + drive_store_ram(ctxptr, addr, data); + } + break; + } + return; +} + +uint8_t cmdhd_read(diskunit_context_t *ctxptr, uint16_t addr) +{ +#ifdef CMDIO + static CLOCK oldc = 0; + drivecpu_context_t *cpu = ctxptr->cpu; +#define readdebug() \ + IDBG((LOG, "CMDHD: IO read %02x from %04x PC=%04x CYCLE=%u", data, addr, \ + cpu->cpu_R65C02_regs.pc, *(ctxptr->clk_ptr)-oldc); \ + oldc=*(ctxptr->clk_ptr); +#else +#define readdebug() +#endif + uint8_t data; + + /* Decode bits 15-12 */ + switch ( (addr >> 12) & 15 ) { + case 0x4: + case 0x5: + case 0x6: + case 0x7: + /* Since the ROM wants to read/write from the RAM from 0xC000-0xFFFF, + when 0x8802.1 = 0, RAM from 0xC000-0xFFFF maps to 0x4000-0x7FFF */ + if (ctxptr->cmdhd->i8255a_o[2]&2) { + return ctxptr->cpu->cpu_last_data = drive_read_ram(ctxptr, (addr & 0x3fff) | 0x4000 ); + } else { + return ctxptr->cpu->cpu_last_data = drive_read_ram(ctxptr, (addr & 0x3fff) | 0xC000 ); + } + break; + case 0x8: + /* Decode bits 11-8 */ + switch ((addr >> 8) & 15) { + case 0x0: /* 0x80xx U10 */ + case 0x1: /* 0x81xx U10 */ + data = viacore_read(ctxptr->cmdhd->via10, addr & 15); + readdebug() + return ctxptr->cpu->cpu_last_data = data; + break; + case 0x4: /* 0x84xx U9 */ + case 0x5: /* 0x85xx U9 */ + data = viacore_read(ctxptr->cmdhd->via9, addr & 15); + readdebug() + return ctxptr->cpu->cpu_last_data = data; + break; + case 0x8: /* 0x88xx U11 */ + case 0x9: /* 0x89xx U11 */ + data = i8255a_read(ctxptr->cmdhd->i8255a, addr & 3); + readdebug() + return ctxptr->cpu->cpu_last_data = data; + break; + case 0xc: /* 0x8cxx */ + case 0xd: /* 0x8dxx */ + data = rtc72421_read(ctxptr->cmdhd->rtc, addr & 15); + readdebug() + return ctxptr->cpu->cpu_last_data = data; + break; + default: + return ctxptr->cpu->cpu_last_data = drive_read_ram(ctxptr, addr); + break; + } + break; + case 0x9: + case 0xa: + case 0xb: + return ctxptr->cpu->cpu_last_data = drive_read_ram(ctxptr, addr); + break; + case 0xc: + case 0xd: + case 0xe: + case 0xf: + /* ROM is enabled when 0x8802.0 is 1, else RAM */ + if (ctxptr->cmdhd->i8255a_o[2]&1) { + return ctxptr->cpu->cpu_last_data = drive_read_rom(ctxptr, addr & 0x3fff ); + } else { + return ctxptr->cpu->cpu_last_data = drive_read_ram(ctxptr, addr); + } + break; + } + return 0; +} + +uint8_t cmdhd_peek(diskunit_context_t *ctxptr, uint16_t addr) +{ + return 0; +} + +int cmdhd_dump(diskunit_context_t *ctxptr, uint16_t addr) +{ + return 0; +} + +static void set_ca2(via_context_t *via_context, int state) +{ +} + +static void set_cb2(via_context_t *via_context, int state, int offset) +{ +} + +static void set_int(via_context_t *via_context, unsigned int int_num, + int value, CLOCK rclk) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + diskunit_context_t *dc = (diskunit_context_t *)(hd->mycontext); + + interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk); +} + +static void restore_int(via_context_t *via_context, unsigned int int_num, + int value) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + diskunit_context_t *dc = (diskunit_context_t *)(hd->mycontext); + + interrupt_restore_irq(dc->cpu->int_status, int_num, value); +} + +static void undump_pra(via_context_t *via_context, uint8_t byte) +{ +} + +static void undump_prb10(via_context_t *via_context, uint8_t byte) +{ + drivevia_context_t *viap = (drivevia_context_t *)(via_context->prv); + + if (iecbus != NULL) { + uint8_t *drive_bus, *drive_data; + unsigned int unit; + + drive_bus = &(iecbus->drv_bus[viap->number + 8]); + drive_data = &(iecbus->drv_data[viap->number + 8]); + + *drive_data = ~byte; + *drive_bus = ((((*drive_data) << 3) & 0x40) + | (((*drive_data) << 6) + & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80)); + + iecbus->cpu_port = iecbus->cpu_bus; + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { + iecbus->cpu_port &= iecbus->drv_bus[unit]; + } + + iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4) + | (iecbus->cpu_port >> 7) + | ((iecbus->cpu_bus << 3) & 0x80)); + } else { + iec_drive_write((uint8_t)(~byte), viap->number); + } +} + +static void store_pra9(via_context_t *via_context, uint8_t byte, uint8_t oldpa, + uint16_t addr) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + scsi_context_t *scsi = (scsi_context_t*)(hd->scsi); + scsi_set_bus(scsi, byte); + + if (scsi->state!=SCSI_STATE_BUSFREE && ((addr & 0xf) == VIA_PRA) ) { + scsi_process_ack(scsi); + } else { + scsi_process_noack(scsi); + } +} + +static uint8_t read_pra9(via_context_t *via_context, uint16_t addr) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + scsi_context_t *scsi = (scsi_context_t*)(hd->scsi); + uint8_t byte; + + byte = scsi_get_bus(scsi); + if (scsi->state!=SCSI_STATE_BUSFREE && ((addr & 0xf) == VIA_PRA) ) { + scsi_process_ack(scsi); + } else { + scsi_process_noack(scsi); + } + return byte; +} + +static void store_prb9(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb, + uint16_t addr) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + scsi_context_t *scsi = (scsi_context_t*)(hd->scsi); + + scsi->sel = (byte & 0x10) ? 1 : 0; + hd->scsi_dir = (byte & 0x08) ? 1 : 0; + scsi_process_noack(scsi); + IDBG((LOG, "CMDHD: sprb9: SEL=%d BSY=%d DATA=%02x RST=%d", + scsi->sel, scsi->bsyo, byte, scsi->rst)); +} + +static uint8_t read_prb9(via_context_t *via_context) +{ + cmdhd_context_t *hd = (cmdhd_context_t *)via_context->context; + scsi_context_t *scsi = (scsi_context_t*)(hd->scsi); + uint8_t temp, state; + + scsi_process_noack(scsi); + IDBG((LOG, "CMDHD: rprb9: SEL=%d BSY=%d REQ=%d", scsi->sel, scsi->bsyo, scsi->req)); + if ( (via_context->via[VIA_PCR] & 0xf0) == 0xf0 ) { + temp=(scsi->sel) & (scsi->bsyo); + } else { + temp=(!scsi->sel) & (scsi->bsyo); + } + + /* mask scsi state to cmd specific pld value */ + switch (scsi->state) + { + case SCSI_STATE_DATAOUT: + state = CMD_STATE_DATAOUT; + break; + case SCSI_STATE_DATAIN: + state = CMD_STATE_DATAIN; + break; + case SCSI_STATE_COMMAND: + state = CMD_STATE_COMMAND; + break; + case SCSI_STATE_STATUS: + state = CMD_STATE_STATUS; + break; + case SCSI_STATE_MESSAGEOUT: + state = CMD_STATE_MESSAGEOUT; + break; + case SCSI_STATE_MESSAGEIN: + state = CMD_STATE_MESSAGEIN; + break; + default: + state = CMD_STATE_STATUS; + } + + return (scsi->req << 7) | (scsi->ack << 6) | (temp << 5) | (scsi->sel << 4) | + (hd->scsi_dir << 3) | (state & 7); +} + +static uint8_t read_prb10(via_context_t *via_context) +{ + uint8_t byte; + drivevia_context_t *viap; + + viap = (drivevia_context_t *)(via_context->prv); + + if (iecbus != NULL) { + byte = (((via_context->via[VIA_PRB] & 0x1a) + | iecbus->drv_port) ^ 0x85); + } else { + byte = (((via_context->via[VIA_PRB] & 0x1a) + | iec_drive_read(viap->number)) ^ 0x85); + } + + DEBUG_IEC_DRV_READ(byte); + + DEBUG_IEC_BUS_READ(byte); + + return byte; +} + +static void store_prb10(via_context_t *via_context, uint8_t byte, uint8_t oldpb, + uint16_t addr) +{ + drivevia_context_t *viap; + + viap = (drivevia_context_t *)(via_context->prv); + + if (byte != oldpb) { + DEBUG_IEC_DRV_WRITE(byte); + + if (iecbus != NULL) { + uint8_t *drive_data, *drive_bus; + unsigned int unit; + + drive_bus = &(iecbus->drv_bus[viap->number + 8]); + drive_data = &(iecbus->drv_data[viap->number + 8]); + + *drive_data = ~byte; + *drive_bus = ((((*drive_data) << 3) & 0x40) + | (((*drive_data) << 6) + & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80)); + + iecbus->cpu_port = iecbus->cpu_bus; + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { + iecbus->cpu_port &= iecbus->drv_bus[unit]; + } + + iecbus->drv_port = (((iecbus->cpu_port >> 4) & 0x4) + | (iecbus->cpu_port >> 7) + | ((iecbus->cpu_bus << 3) & 0x80)); + + DEBUG_IEC_BUS_WRITE(iecbus->drv_port); + } else { + iec_drive_write((uint8_t)(~byte), viap->number); + DEBUG_IEC_BUS_WRITE(~byte); + } + + iec_fast_drive_direction(byte & 0x20, viap->number); + } +} + +static void undump_prb(via_context_t *via_context, uint8_t byte) +{ +} + +static void store_pra10(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb, + uint16_t addr) +{ +} + +static void undump_pcr(via_context_t *via_context, uint8_t byte) +{ +} + +static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr) +{ + return byte; +} + +static void undump_acr(via_context_t *via_context, uint8_t byte) +{ +} + +static void store_acr(via_context_t *via_context, uint8_t byte) +{ +} + +static void store_sr(via_context_t *via_context, uint8_t byte) +{ +} + +static void store_sr10(via_context_t *via_context, uint8_t byte) +{ + drivevia_context_t *viap; + + viap = (drivevia_context_t *)(via_context->prv); + + iec_fast_drive_write(byte, viap->number); +} + +static void store_t2l(via_context_t *via_context, uint8_t byte) +{ +} + +static void reset(via_context_t *via_context) +{ +} + +static uint8_t read_pra10(via_context_t *via_context, uint16_t addr) +{ + return 255; +} + +void cmdhd_setup_context(diskunit_context_t *ctxptr) +{ + drivevia_context_t *via10p; + via_context_t *via10, *via9; + scsi_context_t *scsi; + i8255a_state *i8255a; + char *name = NULL; + + CLOG((LOG, "CMDHD: setup_context")); + + ctxptr->drives[0]->side = 0; + + ctxptr->cmdhd = lib_calloc(1, sizeof(cmdhd_context_t)); + ctxptr->cmdhd->myname = lib_msprintf("CMDHD%u", ctxptr->mynumber); + ctxptr->cmdhd->mycontext = ctxptr; + + ctxptr->cmdhd->image = NULL; + + /* Clear struct as snapshot code may write uninitialized values. */ + ctxptr->cmdhd->via10 = lib_calloc(1, sizeof(via_context_t)); + via10 = ctxptr->cmdhd->via10; + + via10->prv = lib_malloc(sizeof(drivevia_context_t)); + via10p = (drivevia_context_t *)(via10->prv); + via10p->number = ctxptr->mynumber; + + via10->context = (void *)ctxptr->cmdhd; + + via10->rmw_flag = &(ctxptr->cpu->rmw_flag); + via10->clk_ptr = ctxptr->clk_ptr; + + via10->myname = lib_msprintf("CMDHD%uVIA10", ctxptr->mynumber); + via10->my_module_name = lib_msprintf("CMDHD%uVIA10", ctxptr->mynumber); + + viacore_setup_context(via10); + + via10->my_module_name_alt1 = lib_msprintf("CMDHDVIA10-%u", ctxptr->mynumber); + via10->my_module_name_alt2 = lib_msprintf("CMDHDVIA10"); + + via10->irq_line = IK_IRQ; + + via10p->drive = ctxptr->drives[0]; + via10p->v_iecbus = iecbus_drive_port(); + + via10->undump_pra = undump_pra; + via10->undump_prb = undump_prb10; + via10->undump_pcr = undump_pcr; + via10->undump_acr = undump_acr; + via10->store_pra = store_pra10; + via10->store_prb = store_prb10; + via10->store_pcr = store_pcr; + via10->store_acr = store_acr; + via10->store_sr = store_sr10; + via10->store_t2l = store_t2l; + via10->read_pra = read_pra10; + via10->read_prb = read_prb10; + via10->set_int = set_int; + via10->restore_int = restore_int; + via10->set_ca2 = set_ca2; + via10->set_cb2 = set_cb2; + via10->reset = reset; + + ctxptr->cmdhd->via9 = lib_calloc(1, sizeof(via_context_t)); + via9 = ctxptr->cmdhd->via9; + + via9->context = (void *)ctxptr->cmdhd; + + via9->rmw_flag = &(ctxptr->cpu->rmw_flag); + via9->clk_ptr = ctxptr->clk_ptr; + + via9->myname = lib_msprintf("CMDHD%uVIA9", ctxptr->mynumber); + via9->my_module_name = lib_msprintf("CMDHD%uVIA9", ctxptr->mynumber); + + viacore_setup_context(via9); + + via9->my_module_name_alt1 = lib_msprintf("CMDHDVIA9-%u", ctxptr->mynumber); + via9->my_module_name_alt2 = lib_msprintf("CMDHDVIA9"); + + via9->irq_line = IK_IRQ; + + via9->undump_pra = undump_pra; + via9->undump_prb = undump_prb; + via9->undump_pcr = undump_pcr; + via9->undump_acr = undump_acr; + via9->store_pra = store_pra9; + via9->store_prb = store_prb9; + via9->store_pcr = store_pcr; + via9->store_acr = store_acr; + via9->store_sr = store_sr; + via9->store_t2l = store_t2l; + via9->read_pra = read_pra9; + via9->read_prb = read_prb9; + via9->set_int = set_int; + via9->restore_int = restore_int; + via9->set_ca2 = set_ca2; + via9->set_cb2 = set_cb2; + via9->reset = reset; + + ctxptr->cmdhd->scsi = lib_calloc(1, sizeof(scsi_context_t)); + scsi = ctxptr->cmdhd->scsi; + scsi->p = ctxptr->cmdhd; + scsi->myname = lib_msprintf("CMDHD%uSCSI", ctxptr->mynumber); + + ctxptr->cmdhd->i8255a = lib_calloc(1, sizeof(i8255a_state)); + i8255a = ctxptr->cmdhd->i8255a; + i8255a->p = ctxptr->cmdhd; + i8255a->set_pa = set_pa; + i8255a->set_pb = set_pb; + i8255a->set_pc = set_pc; + i8255a->get_pa = get_pa; + i8255a->get_pb = get_pb; + i8255a->get_pc = get_pc; + + name = lib_msprintf("CMDHD%uRTC", ctxptr->mynumber); + ctxptr->cmdhd->rtc = rtc72421_init(name); + lib_free(name); + + ctxptr->cmdhd->rtc->stop = 0; + + name = lib_msprintf("%sEXEC", ctxptr->cmdhd->myname); + ctxptr->cmdhd->reset_alarm = alarm_new(ctxptr->cpu->alarm_context, name, + reset_alarm_handler, ctxptr->cmdhd); + lib_free(name); + + /* reset attachment counter for warning messages */ + ctxptr->cmdhd->numattached = 0; +} + +void cmdhd_init(diskunit_context_t *ctxptr) +{ + scsi_context_t *scsi = (scsi_context_t*)(ctxptr->cmdhd->scsi); + + CLOG((LOG, "CMDHD: init")); + + /* init via cores */ + viacore_init(ctxptr->cmdhd->via9, ctxptr->cpu->alarm_context, + ctxptr->cpu->int_status); + viacore_init(ctxptr->cmdhd->via10, ctxptr->cpu->alarm_context, + ctxptr->cpu->int_status); + + /* reset scsi system */ + scsi_reset(scsi); + /* change any defaults */ + /* grab value from unit structure as it is likely it is initialized + before the drive init is run */ + scsi->max_imagesize = diskunit_context[ctxptr->mynumber]->fixed_size; + /* don't allow more than a 24-bit value -2 to be returned on disk query + as this will cause problems for CMDHD tools */ + scsi->limit_imagesize = 0xfffffe; + /* CMDHD can handle 56 drives, but the latest boot rom has a bug which + corrupts data when deleting partitions that span across disk + boundaries. However, there are a number of users who want multiple + device and LUN support, so we will make it adaptive. */ + /* Setup SCSI user functions */ + scsi->user_format = cmdhd_scsiformat; + scsi->user_read = cmdhd_scsiread; + scsi->user_write = cmdhd_scsiwrite; + + ctxptr->cmdhd->preadyff = 1; +} + +void cmdhd_shutdown(cmdhd_context_t *hd) +{ + CLOG((LOG, "CMDHD: shutdown")); + + /* leave if no context provided */ + if (!hd) { + return; + } + + rtc72421_destroy(hd->rtc, hd->mycontext->rtc_save); + /* Don't know if we need this, so why is it even available? */ +/* alarm_destroy(hd->reset_alarm); */ + viacore_shutdown(hd->via9); + viacore_shutdown(hd->via10); + lib_free(hd->scsi->myname); + lib_free(hd->scsi); + lib_free(hd->i8255a); + lib_free(hd->myname); + lib_free(hd); +} + +/* Function to find the baselba of the CMD partition. We need this so we + can modify the device number of the drive as it is stored on disk. */ +static void cmdhd_findbaselba(cmdhd_context_t *hd) +{ + uint32_t i; + disk_addr_t dadr; + unsigned char buf[256]; + int rlpresent; + + CLOG((LOG, "CMDHD: findbaselba")); + + /* leave if no context provided */ + if (!hd) { + return; + } + + /* reset value to invalid */ + hd->baselba = UINT32_MAX; + + /* leave if no image provided */ + if (!hd->image) { + return; + } + + /* look for configuration block */ + i = 2; + /* start at LBA 2 as in 512-byte blocks */ + while (i < hd->imagesize) { + /* translate to T/S for DHD images, ie. 65536 for each */ + dadr.track = (i / 32768) + 1; + dadr.sector = (i % 32768) * 2 + 1; + /* read the sector */ + if (disk_image_read_sector(hd->image, buf, &dadr) < 0) { + /* hit the end of file */ + break; + } + /* otherwise check the CMD sig */ + if (!cmdhd_has_sig(buf)) { + /* if it has it, update the offset */ + hd->baselba = i - 2; + /* quit */ + break; + } + /* try next 128 sectors */ + i += 128; + } + + CLOG((LOG, "CMDHD: findbaselba=%u", hd->baselba)); + + /* check if RAMLINK is enabled */ + rlpresent = 0; + resources_get_int("RAMLINK", &rlpresent); + + if (!hd->mycontext->parallel_cable && rlpresent) { + hd->mycontext->parallel_cable = 1; + CRIT((LOG, "CMDHD: RAMLink detected. Drive %u 'parallel cable' set to 'standard'.", + hd->mycontext->mynumber + 8)); + } +} + +void cmdhd_reset(cmdhd_context_t *hd) +{ + CLOCK c; + size_t i; + int unit; + + CLOG((LOG, "CMDHD: reset")); + + /* leave if no context provided */ + if (!hd) { + return; + } + + /* reset vias */ + viacore_reset(hd->via9); + viacore_reset(hd->via10); + + /* setup default inputs to U11 (pullups/downs) */ + hd->i8255a_i[0] = 0xff; + hd->i8255a_i[1] = 0x7f; + hd->i8255a_i[2] = 0xe3; + hd->scsi_dir = 0; + + /* check RAM for CMC signature */ + /* The HD ROM does a series of hardware checks on reset if it doesn't + find a signature in memory. Otherwise it skips to the boot loader. + If the user holds down a button on reset, we need to set the alarm + to remove the button press based on this. So on a cold reset, wait + about 8M cycles, where as if it is a soft reset, wait 500K cycles. */ + c = *(hd->mycontext->clk_ptr) + + cmdhd_has_sig(&(hd->mycontext->drive_ram[0x9000])) ? 8000000 : 500000; + CLOG((LOG, "CMDHD: alarm set for %lu from %lu", c, *(hd->mycontext->clk_ptr))); + alarm_set(hd->reset_alarm, c); + + /* look for base lba as it may have changed on reset */ + cmdhd_findbaselba(hd); + + /* check if write protect button is pressed */ + if (hd->mycontext->button & 1) { + hd->i8255a_i[1] &= 0xf7; + CLOG((LOG, "CMDHD: WP pressed down")); + } + /* check if swap8 button is pressed */ + if (hd->mycontext->button & 2) { + hd->i8255a_i[1] &= 0xfd; + CLOG((LOG, "CMDHD: SWAP8 pressed down")); + } + /* check if swap9 button is pressed */ + if (hd->mycontext->button & 4) { + hd->i8255a_i[1] &= 0xfb; + CLOG((LOG, "CMDHD: SWAP9 pressed down")); + } + + /* count the number of connected drives */ + unit = 0; + for (i = 0; i < 56; i++) { + if (hd->scsi->file[i]) { + unit++; + } + } + + /* if the image size is too small, put the drive in installation mode */ + /* but if there is more than one drive connect, go to normal mode */ + if (hd->imagesize < 144) { + if (unit == 1) { + hd->i8255a_i[1] &= 0xf9; + CRIT((LOG, "CMDHD: Image size too small, starting up in installation mode.")); + if (hd->mycontext->parallel_cable) { + hd->mycontext->parallel_cable = 0; + CRIT((LOG, "CMDHD: Drive %u 'parallel cable' set to none. Set it back to 'standard' when", + hd->mycontext->mynumber + 8)); + CRIT((LOG, "CMDHD: HDDOS installation is complete.")); + } + } else { + /* remove scsi ID 0 */ + hd->scsi->file[0] = NULL; + } + } + + /* make sure the cmdbus isn't held down */ + unit = hd->mycontext->mynumber; + cmdbus.drv_data[unit] = 0xff; + cmdbus.drv_bus[unit] = 0xff; + + /* propogate inputs to output */ + i8255a_reset(hd->i8255a); + + /* reset attachment counter for warning messages */ + hd->numattached = 1; +} + +int cmdhd_attach_image(disk_image_t *image, unsigned int unit) +{ + cmdhd_context_t *hd; + char *basename, *testname; + size_t i, j; + FILE *test; + off_t filelength; + + CLOG((LOG, "CMDHD: attach_image")); + + /* standard unit range check */ + if (unit < 8 || unit > 8 + NUM_DISK_UNITS) { + return -1; + } + + /* make sure this is a DHD image */ + switch (image->type) { + case DISK_IMAGE_TYPE_DHD: + disk_image_attach_log(image, LOG, unit, 0); + break; + default: + return -1; + } + + /* get context */ + hd = diskunit_context[unit - 8]->cmdhd; + + /* leave if no context provided */ + if (!hd) { + return -1; + } + + /* record passed values */ + hd->image = image; + hd->imagesize = (uint32_t)(disk_image_size(image) >> 9); + + /* leave if there is a problem getting the image size */ + if (hd->imagesize == UINT32_MAX) { + return -1; + } + + /* copy file FD to the scsi module */ + hd->scsi->file[0] = image->media.fsimage->fd; + + /* find the base lba */ + cmdhd_findbaselba(hd); + + /* look to see if there are more files with the same base + name, but different extensions: s10, s11, ..., s20, ..., s67 + s */ + /* copy the file name */ + basename = lib_strdup(image->media.fsimage->name); + + /* make sure it ends in some form of DHD */ + i = strlen(basename); + if (i > 0 && + (basename[i - 1] == 'd' || basename[i - 1] == 'D') && + (basename[i - 2] == 'h' || basename[i - 2] == 'H') && + (basename[i - 3] == 'd' || basename[i - 3] == 'D')) { + /* strip off the last 2 letters */ + basename[i - 2] = 0; + /* change the first D to an S */ + basename[i - 3] = (basename[i - 3] & ~31) | 'S'; + /* cycle through all of them S01-S67 */ + for (i = 0; i < 7; i++) { + /* skip first disk as it has a DHD extension */ + for (j = (i == 0); j < 8; j++) { + /* generate the name */ + testname = lib_msprintf("%s%" PRI_SIZE_T "%1" PRI_SIZE_T, + basename, i, j); + /* open the file */ + test = fopen(testname, "rb+"); + if (test) { + /* if it is there, check the length */ + filelength = archdep_file_size(test); + /* must be multiple of 512 */ + if ((filelength % 512) == 0) { + /* set the FILE pointer */ + hd->scsi->file[(i << 3) | j] = test; + } else { + /* otherwise make sure it is zero */ + hd->scsi->file[(i << 3) | j] = NULL; + fclose(test); + } + } + /* release any memory */ + lib_free(testname); + } + } + } else { + /* otherwise clear out SCSI resources just in case */ + for (i = 1; i < 56; i++) { + hd->scsi->file[i] = NULL; + } + } + + /* release any more memory */ + lib_free(basename); + + /* don't do this yet as a lot of 3rd party CMD tools don't expect this */ +#if 0 + /* attaching a new disk requires a device reset */ + drive_cpu_trigger_reset(unit - 8); +#endif + + /* process attachment counter for warning messages */ + hd->numattached++; + + if (hd->numattached > 1) { + CRIT((LOG, "CMDHD: Attaching a new DHD normally requires the drive to be manually reset as")); + CRIT((LOG, "CMDHD: the HDDOS is not designed to detect this. Exceptions are when handling")); + CRIT((LOG, "CMDHD: removable media on SCSI IDs other than 0 (ie. changing .S?? files).")); + } + + return 0; +} + +int cmdhd_detach_image(disk_image_t *image, unsigned int unit) +{ + cmdhd_context_t *hd; + int32_t i; + + CLOG((LOG, "CMDHD: detach_image")); + + /* standard unit range check */ + if (image == NULL || unit < 8 || unit > 8 + NUM_DISK_UNITS) { + return -1; + } + + /* make sure this is a DHD image */ + switch (image->type) { + case DISK_IMAGE_TYPE_DHD: + disk_image_detach_log(image, LOG, unit, 0); + break; + default: + return -1; + } + + /* get context */ + hd = diskunit_context[unit - 8]->cmdhd; + + /* leave if no context provided */ + if (!hd) { + return -1; + } + + /* remove all image settings in this context */ + hd->image = NULL; + hd->imagesize = 0; + hd->baselba = UINT32_MAX; + hd->scsi->file[0] = NULL; + + /* close all additional SCSI ID files */ + for (i = 1; i < 56; i++) { + /* if it isn't NULL, it must be a file */ + if (hd->scsi->file[i]) { + /* close it and set to NULL */ + fclose(hd->scsi->file[i]); + hd->scsi->file[i] = NULL; + } + } + + /* make sure the cmdbus isn't held down */ + cmdbus.drv_data[unit - 8] = 0xff; + cmdbus.drv_bus[unit - 8] = 0xff; + + return 0; +} + +int cmdhd_update_maxsize(unsigned int size, unsigned int unit) +{ + cmdhd_context_t *hd; + + /* standard unit range check */ + if (unit < 8 || unit > 8 + NUM_DISK_UNITS) { + return -1; + } + + /* get context */ + hd = diskunit_context[unit - 8]->cmdhd; + + /* leave if no context provided */ + if (!hd) { + return -1; + } + + hd->scsi->max_imagesize = size; + return 0; +} + +#define CMDHD_SNAP_MAJOR 1 +#define CMDHD_SNAP_MINOR 0 + +int cmdhd_snapshot_write_module(cmdhd_context_t *drv, struct snapshot_s *s) +{ + snapshot_module_t *m; + + CLOG((LOG, "CMDHD: snapshot_write_module")); + + m = snapshot_module_create(s, drv->myname, CMDHD_SNAP_MAJOR, CMDHD_SNAP_MINOR); + + if (m == NULL) { + return -1; + } + + if (0 + || SMW_B(m, drv->LEDs) < 0 + || SMW_BA(m, drv->i8255a_i, 3) < 0 + || SMW_BA(m, drv->i8255a_o, 3) < 0 + || SMW_B(m, drv->scsi_dir) < 0 + || SMW_B(m, drv->preadyff) < 0 ) { + snapshot_module_close(m); + return -1; + } + + if (i8255a_snapshot_write_data(drv->i8255a, m) < 0) { + snapshot_module_close(m); + return -1; + } + + if (snapshot_module_close(m) < 0) { + return -1; + } + + if (viacore_snapshot_write_module(drv->via9, s) < 0) { + return -1; + } + + if (viacore_snapshot_write_module(drv->via10, s) < 0) { + return -1; + } + + if (scsi_snapshot_write_module(drv->scsi, s) < 0) { + return -1; + } + + if (rtc72421_write_snapshot(drv->rtc, s) < 0) { + return -1; + } + + return 0; +} + +int cmdhd_snapshot_read_module(cmdhd_context_t *drv, struct snapshot_s *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + CLOG((LOG, "CMDHD: snapshot_read_module")); + + m = snapshot_module_open(s, drv->myname, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + /* Do not accept higher versions than current */ + if (snapshot_version_is_bigger(vmajor, vminor, CMDHD_SNAP_MAJOR, CMDHD_SNAP_MAJOR)) { + snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); + snapshot_module_close(m); + return -1; + } + + if (0 + || SMR_B(m, &drv->LEDs) < 0 + || SMR_BA(m, drv->i8255a_i, 3) < 0 + || SMR_BA(m, drv->i8255a_o, 3) < 0 + || SMR_B(m, &drv->scsi_dir) < 0 + || SMR_B(m, &drv->preadyff) < 0 ) { + snapshot_module_close(m); + return -1; + } + + if (i8255a_snapshot_read_data(drv->i8255a, m) < 0) { + snapshot_module_close(m); + return -1; + } + + if (snapshot_module_close(m) < 0) { + return -1; + } + + alarm_unset(drv->reset_alarm); + + if (viacore_snapshot_read_module(drv->via9, s) < 0) { + return -1; + } + + if (viacore_snapshot_read_module(drv->via10, s) < 0) { + return -1; + } + + if (scsi_snapshot_read_module(drv->scsi, s) < 0) { + return -1; + } + + if (rtc72421_read_snapshot(drv->rtc, s) < 0) { + return -1; + } + + return 0; +} + diff --git a/src/Emulators/vice/drive/iec/cmdhd.h b/src/Emulators/vice/drive/iec/cmdhd.h new file mode 100644 index 00000000..2140853a --- /dev/null +++ b/src/Emulators/vice/drive/iec/cmdhd.h @@ -0,0 +1,110 @@ +/* + * cmdhd.h - Whole CMDHD emulation + * + * Written by + * Roberto Muscedere (muscedereroberto@gmail.com) + * + * Based on old code by + * Kajtar Zsolt + * Andre Fachat + * Andreas Boose + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_CMDHD_H +#define VICE_CMDHD_H + +#include "vicetypes.h" +#include "diskimage.h" +#include "rtc-72421.h" +#include "alarm.h" +#include "via.h" +#include "scsi.h" +#include "i8255a.h" + +struct diskunit_context_s; +struct via_context_s; + +typedef struct cmdhd_context_s { + char *myname; + struct diskunit_context_s *mycontext; + struct via_context_s *via9; + struct via_context_s *via10; + struct scsi_context_s *scsi; + rtc_72421_t *rtc; + uint8_t LEDs; + uint32_t imagesize; + uint32_t baselba; + alarm_t *reset_alarm; + struct disk_image_s *image; + i8255a_state *i8255a; + uint8_t i8255a_i[3]; + uint8_t i8255a_o[3]; + uint8_t scsi_dir; + uint8_t preadyff; + uint8_t numattached; +} cmdhd_context_t; + +typedef struct cmdhd_context_s cmdhd_context_t; + +void cmdhd_shutdown(struct cmdhd_context_s *ctxptr); +void cmdhd_setup_context(struct diskunit_context_s *ctxptr); +void cmdhd_init(struct diskunit_context_s *ctxptr); +void cmdhd_reset(struct cmdhd_context_s *ctxptr); +void cmdhd_reset_soft(diskunit_context_t *drv); + +void cmdhd_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t cmdhd_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t cmdhd_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int cmdhd_dump(diskunit_context_t *ctxptr, uint16_t addr); +int cmdhd_attach_image(disk_image_t *image, unsigned int unit); +int cmdhd_detach_image(disk_image_t *image, unsigned int unit); +int cmdhd_update_maxsize(unsigned int size, unsigned int unit); + +int cmdhd_snapshot_write_module(cmdhd_context_t *drv, struct snapshot_s *s); +int cmdhd_snapshot_read_module(cmdhd_context_t *drv, struct snapshot_s *s); + +typedef struct cmdbus_s { +/* device 8 references 0 */ + uint8_t drv_bus[NUM_DISK_UNITS]; +/* + bit 7 is /PREADY + bit 6 is /PCLK + bit 5 is /PATN + bit 4 is /PEXT + bit 3..1 is 1 + bit 0 is 1 (if it is 0, then it will not contribute to the bus when + cmdbus_update is called) +*/ + uint8_t drv_data[NUM_DISK_UNITS]; + uint8_t cpu_bus; /* same as drv_bus */ + uint8_t cpu_data; + uint8_t bus; /* same as drv_bus */ + uint8_t data; +} cmdbus_t; + +extern cmdbus_t cmdbus; + +void cmdbus_init(void); +void cmdbus_update(void); +void cmdbus_patn_changed(int new, int old); + +#endif diff --git a/src/Emulators/vice/drive/iec/fdd.c b/src/Emulators/vice/drive/iec/fdd.c index 1ba34873..c61a9689 100644 --- a/src/Emulators/vice/drive/iec/fdd.c +++ b/src/Emulators/vice/drive/iec/fdd.c @@ -29,18 +29,33 @@ #include #include -#include "diskimage.h" #include "lib.h" +#include "log.h" #include "vicetypes.h" #include "fdd.h" +#include "diskconstants.h" #include "diskimage.h" #include "drive.h" #include "snapshot.h" +/* 3.5" mechs are usually specified for 80 physical tracks. However, using track + 81 is usually no problem at all on any combination of mech and disk. Often + also track 82 works. On good quality drives even track 83 is ok. + Most importantly, track 81 is not uncommon "in the wild": + - the FD2000/4000 ROMS write to track 81 with zeros when formatting for 1581 + disks (TODO: test and handle this without breaking the upper tracks) + - Wheels "MakeSysDisk" puts its copyright info on track 81 + + FIXME: images are always "extended" without asking + +*/ +#define FDD_MAX_TRACK (80 + 3) +#define FDD_NUM_TRACKS (80 + 3) + const int fdd_data_rates[4] = { 500, 300, 250, 1000 }; /* kbit/s */ #define INDEXLEN (16) static void fdd_flush_raw(fd_drive_t *drv); -static WORD *crc1021 = NULL; +static uint16_t *crc1021 = NULL; struct fd_drive_s { char *myname; @@ -60,7 +75,8 @@ struct fd_drive_s { int head_invert; int disk_rate; int image_sectors; - int index_count; + unsigned int index_count; + /*int write_beyond;*/ /* flag to see if we writing D?M data to a D81 image */ drive_t *drive; struct disk_image_s *image; struct { @@ -68,20 +84,21 @@ struct fd_drive_s { int size; int track_head; int dirty; - BYTE *data; - BYTE *sync; + uint8_t *data; + uint8_t *sync; } raw; }; fd_drive_t *fdd_init(int num, drive_t *drive) { fd_drive_t *drv = lib_malloc(sizeof(fd_drive_t)); + memset(drv, 0, sizeof(fd_drive_t)); drv->myname = lib_msprintf("FDD%d", num); drv->image = NULL; drv->number = num & 3; drv->motor = 0; drv->track = 0; - drv->tracks = 80; + drv->tracks = FDD_NUM_TRACKS; drv->sectors = 10; drv->sector_size = 2; drv->head_invert = 1; @@ -90,6 +107,10 @@ fd_drive_t *fdd_init(int num, drive_t *drive) drv->rate = 2; drv->image_sectors = 40; drv->drive = drive; + /* TODO: What about the other fields in raw? */ + drv->raw.data = NULL; + drv->raw.sync = NULL; + /*drv->write_beyond = 0;*/ return drv; } @@ -98,7 +119,7 @@ static void fdd_init_crc1021(void) unsigned int i, j; unsigned int w; - crc1021 = lib_malloc(256 * sizeof(WORD)); + crc1021 = lib_malloc(256 * sizeof(uint16_t)); for (i = 0; i < 256; i++) { w = i << 8; for (j = 0; j < 8; j++) { @@ -109,7 +130,7 @@ static void fdd_init_crc1021(void) w <<= 1; } } - crc1021[i] = (WORD)w; + crc1021[i] = (uint16_t)w; } } @@ -118,6 +139,12 @@ void fdd_shutdown(fd_drive_t *drv) if (!drv) { return; } + /* clean up memory from CRC tables */ + if (crc1021) { + lib_free(crc1021); + /* prevent multiple instances of fdd_shutdown to unallocate this table */ + crc1021 = NULL; + } lib_free(drv->myname); lib_free(drv); } @@ -130,7 +157,7 @@ void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image) drv->image = image; switch (image->type) { case DISK_IMAGE_TYPE_D1M: - drv->tracks = 81; + drv->tracks = 80 + 3; /* FIXME */ drv->sectors = 10; drv->sector_size = 2; drv->head_invert = 1; @@ -141,7 +168,7 @@ void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image) drv->image_sectors = 256; break; case DISK_IMAGE_TYPE_D2M: - drv->tracks = 81; + drv->tracks = 80 + 3; /* FIXME */ drv->sectors = 10; drv->sector_size = 3; drv->head_invert = 1; @@ -152,7 +179,7 @@ void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image) drv->image_sectors = 256; break; case DISK_IMAGE_TYPE_D4M: - drv->tracks = 81; + drv->tracks = 80 + 3; /* FIXME */ drv->sectors = 20; drv->sector_size = 3; drv->head_invert = 1; @@ -164,7 +191,13 @@ void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image) break; case DISK_IMAGE_TYPE_D81: default: - drv->tracks = 80; +#if 0 + /* Normally, the value below would be 80, but the FD2K/4K ROMS + write to sector 81 with zeros when formatting for 1581 disks. + By setting it to 81, we later detect this and error out + appropriately so the format command will work. */ +#endif + drv->tracks = MAX_TRACKS_1581; drv->sectors = 10; drv->sector_size = 2; drv->head_invert = 1; @@ -181,6 +214,7 @@ void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image) drv->raw.track_head = -1; drv->raw.dirty = 0; drv->raw.head = 0; + /*drv->write_beyond = 0;*/ drv->disk_change = 1; drv->write_protect = (int)(image->read_only); @@ -203,7 +237,7 @@ void fdd_image_detach(fd_drive_t *drv) #define fdd_raw_write(b) \ { \ drv->raw.data[p] = b; \ - drv->raw.sync[p >> 3] &= (BYTE)(0xff7f >> (p & 7)); \ + drv->raw.sync[p >> 3] &= (uint8_t)(0xff7f >> (p & 7)); \ p++; \ if (p >= drv->raw.size) { \ p = 0; \ @@ -213,26 +247,26 @@ void fdd_image_detach(fd_drive_t *drv) #define fdd_raw_write_sync(b) \ { \ drv->raw.data[p] = b; \ - drv->raw.sync[p >> 3] |= (BYTE)(0x80 >> (p & 7)); \ + drv->raw.sync[p >> 3] |= (uint8_t)(0x80 >> (p & 7)); \ p++; \ if (p >= drv->raw.size) { \ p = 0; \ } \ } -inline WORD fdd_crc(WORD crc, BYTE b) +inline uint16_t fdd_crc(uint16_t crc, uint8_t b) { if (!crc1021) { fdd_init_crc1021(); } - return (WORD)(crc1021[(crc >> 8) ^ b] ^ (crc << 8)); + return (uint16_t)(crc1021[(crc >> 8) ^ b] ^ (crc << 8)); } static void fdd_flush_raw(fd_drive_t *drv) { int i, j, s, p, step, d; - BYTE *data; - WORD w; + uint8_t *data; + uint16_t w; disk_addr_t dadr; if (!drv->raw.dirty) { @@ -241,7 +275,7 @@ static void fdd_flush_raw(fd_drive_t *drv) drv->raw.dirty = 0; if (drv->raw.track_head / 2 < drv->tracks && drv->image) { -#if FDD_DEBUG +#ifdef FDD_DEBUG for (i = 0; i < drv->raw.size; i++) { if (!(i & 15)) { printf("%04x: ", i); @@ -345,7 +379,7 @@ static void fdd_flush_raw(fd_drive_t *drv) } break; case 12: - data[d++] = (BYTE)w; + data[d++] = (uint8_t)w; if (d >= (128 << drv->sector_size)) { step++; } @@ -362,6 +396,24 @@ static void fdd_flush_raw(fd_drive_t *drv) dadr.sector = dadr.sector % (unsigned int)(drv->image_sectors); for (j = 0; j < (1 << drv->sector_size); j += 2) { +#if 0 + /* FD2000 and FD4000 drives will expect to read back a formatted + track 81 on a D81 image, but this is beyond the image spec. + We will track if the data wasn't all zeros here, and error + out in the read process (below) later. */ + if (dadr.track >= 81 && drv->image->type == DISK_IMAGE_TYPE_D81 + && !drv->write_beyond) { + for (c = 0; c < 256 ; c++ ) { + if (data[j * 128 + c]) { + drv->write_beyond = 1; + break; + } + } + } else { + disk_image_write_sector(drv->image, data + j * 128, &dadr); + drv->write_beyond = 0; + } +#endif disk_image_write_sector(drv->image, data + j * 128, &dadr); dadr.sector = (dadr.sector + 1) % (unsigned int)(drv->image_sectors); if (!dadr.sector) { @@ -383,8 +435,8 @@ static void fdd_flush_raw(fd_drive_t *drv) static void fdd_update_raw(fd_drive_t *drv) { int i, j, s, p, res; - BYTE buffer[256]; - WORD crc; + uint8_t buffer[256]; + uint16_t crc; disk_addr_t dadr; if (drv->track * 2 + drv->head == drv->raw.track_head) { @@ -427,21 +479,41 @@ static void fdd_update_raw(fd_drive_t *drv) fdd_raw_write_sync(0xa1); } fdd_raw_write(0xfe); /* ID mark */ - fdd_raw_write((BYTE)(drv->track)); - crc = fdd_crc(0xb230, (BYTE)drv->track); - fdd_raw_write((BYTE)(drv->head ^ drv->head_invert)); - crc = fdd_crc(crc, (BYTE)(drv->head ^ drv->head_invert)); - fdd_raw_write((BYTE)(s + 1)); - crc = fdd_crc(crc, (BYTE)(s + 1)); - fdd_raw_write((BYTE)(drv->sector_size)); - crc = fdd_crc(crc, (BYTE)drv->sector_size); - fdd_raw_write((BYTE)(crc >> 8)); - fdd_raw_write((BYTE)crc); + fdd_raw_write((uint8_t)(drv->track)); + crc = fdd_crc(0xb230, (uint8_t)drv->track); + fdd_raw_write((uint8_t)(drv->head ^ drv->head_invert)); + crc = fdd_crc(crc, (uint8_t)(drv->head ^ drv->head_invert)); + fdd_raw_write((uint8_t)(s + 1)); + crc = fdd_crc(crc, (uint8_t)(s + 1)); + fdd_raw_write((uint8_t)(drv->sector_size)); + crc = fdd_crc(crc, (uint8_t)drv->sector_size); + fdd_raw_write((uint8_t)(crc >> 8)); + fdd_raw_write((uint8_t)crc); for (i = 0; i < drv->gap2; i++) { fdd_raw_write(0x4e); } crc = 0xe295; for (j = 0; j < (1 << drv->sector_size); j += 2) { +#if 0 + /* FD2000 and FD4000 drives will expect to read back a formatted + track 81 on a D81 image, but this is beyond the image spec. + If any data other than zero was written, error out on the + track read. We do this by not creating the MFM structure for + the whole track. */ + if (dadr.track >= 81 && drv->image->type == DISK_IMAGE_TYPE_D81) { + if (drv->write_beyond) { + /* remove all MFM data from the track */ + memset(drv->raw.data, 0x4e, (size_t)(drv->raw.size)); + memset(drv->raw.sync, 0, (size_t)((drv->raw.size + 7) >> 3)); + drv->write_beyond = 0; + return; + } + memset(buffer, 0, 256); + res = 0; + } else { + res = disk_image_read_sector(drv->image, buffer, &dadr); + } +#endif res = disk_image_read_sector(drv->image, buffer, &dadr); if (res < 0) { return; @@ -464,13 +536,13 @@ static void fdd_update_raw(fd_drive_t *drv) dadr.track++; } } - fdd_raw_write((BYTE)(crc >> 8)); - fdd_raw_write((BYTE)(crc & 0xff)); + fdd_raw_write((uint8_t)(crc >> 8)); + fdd_raw_write((uint8_t)(crc & 0xff)); for (i = 0; i < drv->gap3; i++) { fdd_raw_write(0x4e); /* GAP 3 */ } } -#if FDD_DEBUG +#ifdef FDD_DEBUG for (i = 0; i < drv->raw.size; i++) { if (!(i & 15)) { printf("%04x: ", i); @@ -484,14 +556,23 @@ static void fdd_update_raw(fd_drive_t *drv) } } -int fdd_rotate(fd_drive_t *drv, int bytes) +uint64_t fdd_rotate(fd_drive_t *drv, uint64_t bytes_in) { + uint64_t bytes; + if (!drv || !drv->motor || !drv->image) { - return bytes; + return bytes_in; + } + + for (bytes = bytes_in; bytes > INT32_MAX; bytes -= INT32_MAX) + { + drv->index_count += (drv->raw.head + INT32_MAX) / drv->raw.size; + drv->raw.head = (drv->raw.head + INT32_MAX) % drv->raw.size; } drv->index_count += (drv->raw.head + bytes) / drv->raw.size; drv->raw.head = (drv->raw.head + bytes) % drv->raw.size; - return bytes; + + return bytes_in; } int fdd_index(fd_drive_t *drv) @@ -510,7 +591,7 @@ void fdd_index_count_reset(fd_drive_t *drv) drv->index_count = 0; } -int fdd_index_count(fd_drive_t *drv) +unsigned int fdd_index_count(fd_drive_t *drv) { if (!drv) { return 0; @@ -542,9 +623,9 @@ int fdd_disk_change(fd_drive_t *drv) return drv->disk_change; } -WORD fdd_read(fd_drive_t *drv) +uint16_t fdd_read(fd_drive_t *drv) { - WORD data; + uint16_t data; int p; if (!drv || !drv->motor) { @@ -554,7 +635,7 @@ WORD fdd_read(fd_drive_t *drv) if (drv->disk_rate == drv->rate) { fdd_update_raw(drv); - data = (WORD)drv->raw.data[p]; + data = (uint16_t)drv->raw.data[p]; if (drv->raw.sync[p >> 3] & (0x80 >> (p & 7))) { data |= 0x100; } @@ -570,7 +651,7 @@ WORD fdd_read(fd_drive_t *drv) return data; } -int fdd_write(fd_drive_t *drv, WORD data) +int fdd_write(fd_drive_t *drv, uint16_t data) { int p; @@ -581,11 +662,11 @@ int fdd_write(fd_drive_t *drv, WORD data) p = drv->raw.head; if (drv->disk_rate == drv->rate) { - drv->raw.data[p] = (BYTE)data; + drv->raw.data[p] = (uint8_t)data; if (data & 0x100) { - drv->raw.sync[p >> 3] |= (BYTE)(0x80 >> (p & 7)); + drv->raw.sync[p >> 3] |= (uint8_t)(0x80 >> (p & 7)); } else { - drv->raw.sync[p >> 3] &= (BYTE)(0xff7f >> (p & 7)); + drv->raw.sync[p >> 3] &= (uint8_t)(0xff7f >> (p & 7)); } drv->raw.dirty = 1; } @@ -611,6 +692,7 @@ void fdd_seek_pulse(fd_drive_t *drv, int dir) if (!drv) { return; } + if (drv->motor) { drv->track += dir ? 1 : -1; } @@ -620,10 +702,28 @@ void fdd_seek_pulse(fd_drive_t *drv, int dir) if (drv->track < 0) { drv->track = 0; } - if (drv->track > 82) { - drv->track = 82; + if (drv->track > FDD_MAX_TRACK) { + drv->track = FDD_MAX_TRACK; } drv->drive->current_half_track = (drv->track + 1) * 2; +#if 0 + printf("track:%d (half:%d) img tracks: %u (max half:%u)\n", + drv->track, drv->drive->current_half_track, + drv->image->tracks, drv->image->max_half_tracks); +#endif + if (drv->image) { + /* don't do check on the "image" tracks here since this value for the + CMDFDs is logical not physical */ + if (drv->image->type != DISK_IMAGE_TYPE_D1M && + drv->image->type != DISK_IMAGE_TYPE_D2M && + drv->image->type != DISK_IMAGE_TYPE_D4M) { + if (drv->drive->current_half_track > (drv->image->tracks * 2)) { + log_warning(LOG_DEFAULT, "disk image will get extended (%d tracks)", + drv->drive->current_half_track / 2); + /* FIXME: actually extend the image here */ + } + } + } } void fdd_select_head(fd_drive_t *drv, int head) @@ -664,26 +764,26 @@ int fdd_snapshot_write_module(fd_drive_t *drv, struct snapshot_s *s) } if (0 - || SMW_B(m, (BYTE)drv->number) < 0 - || SMW_B(m, (BYTE)drv->disk_change) < 0 - || SMW_B(m, (BYTE)drv->write_protect) < 0 - || SMW_B(m, (BYTE)drv->track) < 0 - || SMW_B(m, (BYTE)drv->tracks) < 0 - || SMW_B(m, (BYTE)drv->head) < 0 - || SMW_B(m, (BYTE)drv->sectors) < 0 - || SMW_B(m, (BYTE)drv->motor) < 0 - || SMW_B(m, (BYTE)drv->rate) < 0 - || SMW_B(m, (BYTE)drv->sector_size) < 0 - || SMW_B(m, (BYTE)drv->iso) < 0 - || SMW_B(m, (BYTE)drv->gap2) < 0 - || SMW_B(m, (BYTE)drv->gap3) < 0 - || SMW_B(m, (BYTE)drv->head_invert) < 0 - || SMW_B(m, (BYTE)drv->disk_rate) < 0 - || SMW_DW(m, (DWORD)drv->image_sectors) < 0 - || SMW_DW(m, (DWORD)drv->index_count) < 0 - || SMW_DW(m, (BYTE)drv->raw.head) < 0 - || SMW_B(m, (BYTE)drv->raw.track_head) < 0 - || SMW_B(m, (BYTE)drv->raw.dirty) < 0 + || SMW_B(m, (uint8_t)drv->number) < 0 + || SMW_B(m, (uint8_t)drv->disk_change) < 0 + || SMW_B(m, (uint8_t)drv->write_protect) < 0 + || SMW_B(m, (uint8_t)drv->track) < 0 + || SMW_B(m, (uint8_t)drv->tracks) < 0 + || SMW_B(m, (uint8_t)drv->head) < 0 + || SMW_B(m, (uint8_t)drv->sectors) < 0 + || SMW_B(m, (uint8_t)drv->motor) < 0 + || SMW_B(m, (uint8_t)drv->rate) < 0 + || SMW_B(m, (uint8_t)drv->sector_size) < 0 + || SMW_B(m, (uint8_t)drv->iso) < 0 + || SMW_B(m, (uint8_t)drv->gap2) < 0 + || SMW_B(m, (uint8_t)drv->gap3) < 0 + || SMW_B(m, (uint8_t)drv->head_invert) < 0 + || SMW_B(m, (uint8_t)drv->disk_rate) < 0 + || SMW_DW(m, (uint32_t)drv->image_sectors) < 0 + || SMW_DW(m, (uint32_t)drv->index_count) < 0 + || SMW_DW(m, (uint8_t)drv->raw.head) < 0 + || SMW_B(m, (uint8_t)drv->raw.track_head) < 0 + || SMW_B(m, (uint8_t)drv->raw.dirty) < 0 || SMW_BA(m, drv->raw.data, (unsigned int)drv->raw.size) < 0 || SMW_BA(m, drv->raw.sync, (unsigned int)((drv->raw.size + 7) >> 3)) < 0) { snapshot_module_close(m); @@ -697,7 +797,7 @@ int fdd_snapshot_write_module(fd_drive_t *drv, struct snapshot_s *s) int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; m = snapshot_module_open(s, drv->myname, &vmajor, &vminor); @@ -706,7 +806,7 @@ int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s) } /* Do not accept versions higher than current */ - if (vmajor > FDD_SNAP_MAJOR || vminor > FDD_SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, FDD_SNAP_MAJOR, FDD_SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; @@ -729,7 +829,7 @@ int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s) || SMR_B_INT(m, &drv->head_invert) < 0 || SMR_B_INT(m, &drv->disk_rate) < 0 || SMR_DW_INT(m, &drv->image_sectors) < 0 - || SMR_DW_INT(m, &drv->index_count) < 0 + || SMR_DW_UINT(m, &drv->index_count) < 0 || SMR_DW_INT(m, &drv->raw.head) < 0 || SMR_B_INT(m, &drv->raw.track_head) < 0 || SMR_B_INT(m, &drv->raw.dirty) < 0) { @@ -740,14 +840,14 @@ int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s) if (drv->track < 0) { drv->track = 0; } - if (drv->track > 82) { - drv->track = 82; + if (drv->track > FDD_MAX_TRACK) { + drv->track = FDD_MAX_TRACK; } if (drv->tracks < 0) { drv->tracks = 0; } - if (drv->tracks > 82) { - drv->tracks = 82; + if (drv->tracks > FDD_NUM_TRACKS) { + drv->tracks = FDD_NUM_TRACKS; } drv->head &= 1; drv->motor &= 1; diff --git a/src/Emulators/vice/drive/iec/fdd.h b/src/Emulators/vice/drive/iec/fdd.h index d32b339d..7e41c611 100644 --- a/src/Emulators/vice/drive/iec/fdd.h +++ b/src/Emulators/vice/drive/iec/fdd.h @@ -35,27 +35,28 @@ struct snapshot_s; typedef struct fd_drive_s fd_drive_t; extern const int fdd_data_rates[4]; -extern fd_drive_t *fdd_init(int num, struct drive_s *drive); -extern void fdd_shutdown(fd_drive_t *drv); +fd_drive_t *fdd_init(int num, struct drive_s *drive); +void fdd_shutdown(fd_drive_t *drv); -extern void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image); -extern void fdd_image_detach(fd_drive_t *drv); -extern WORD fdd_read(fd_drive_t *drv); -extern int fdd_write(fd_drive_t *drv, WORD data); -extern void fdd_flush(fd_drive_t *drv); -extern void fdd_seek_pulse(fd_drive_t *drv, int dir); -extern void fdd_select_head(fd_drive_t *drv, int head); -extern void fdd_set_motor(fd_drive_t *drv, int motor); -extern void fdd_set_rate(fd_drive_t *drv, int rate); -extern int fdd_rotate(fd_drive_t *drv, int bytes); -extern int fdd_index(fd_drive_t *drv); -extern void fdd_index_count_reset(fd_drive_t *drv); -extern int fdd_index_count(fd_drive_t *drv); -extern int fdd_track0(fd_drive_t *drv); -extern int fdd_write_protect(fd_drive_t *drv); -extern int fdd_disk_change(fd_drive_t *drv); -extern WORD fdd_crc(WORD crc, BYTE b); +void fdd_image_attach(fd_drive_t *drv, struct disk_image_s *image); +void fdd_image_detach(fd_drive_t *drv); +uint16_t fdd_read(fd_drive_t *drv); +int fdd_write(fd_drive_t *drv, uint16_t data); +void fdd_flush(fd_drive_t *drv); +void fdd_seek_pulse(fd_drive_t *drv, int dir); +void fdd_select_head(fd_drive_t *drv, int head); +void fdd_set_motor(fd_drive_t *drv, int motor); +void fdd_set_rate(fd_drive_t *drv, int rate); +uint64_t fdd_rotate(fd_drive_t *drv, uint64_t bytes); +int fdd_index(fd_drive_t *drv); +void fdd_index_count_reset(fd_drive_t *drv); +unsigned int fdd_index_count(fd_drive_t *drv); +int fdd_track0(fd_drive_t *drv); +int fdd_write_protect(fd_drive_t *drv); +int fdd_disk_change(fd_drive_t *drv); +uint16_t fdd_crc(uint16_t crc, uint8_t b); + +int fdd_snapshot_write_module(fd_drive_t *drv, struct snapshot_s *s); +int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s); -extern int fdd_snapshot_write_module(fd_drive_t *drv, struct snapshot_s *s); -extern int fdd_snapshot_read_module(fd_drive_t *drv, struct snapshot_s *s); #endif diff --git a/src/Emulators/vice/drive/iec/glue1571.h b/src/Emulators/vice/drive/iec/glue1571.h index ff75b380..92e61ce8 100644 --- a/src/Emulators/vice/drive/iec/glue1571.h +++ b/src/Emulators/vice/drive/iec/glue1571.h @@ -29,6 +29,6 @@ struct drive_s; -extern void glue1571_side_set(unsigned int side, struct drive_s *drive); +void glue1571_side_set(unsigned int side, struct drive_s *drive); #endif diff --git a/src/Emulators/vice/drive/iec/iec-cmdline-options.c b/src/Emulators/vice/drive/iec/iec-cmdline-options.c index f5da2f19..7a0a7e8a 100644 --- a/src/Emulators/vice/drive/iec/iec-cmdline-options.c +++ b/src/Emulators/vice/drive/iec/iec-cmdline-options.c @@ -32,111 +32,84 @@ #include "drive.h" #include "iec-cmdline-options.h" #include "lib.h" -#include "translate.h" -static const cmdline_option_t cmdline_options[] = { - { "-dos1540", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-dos1540", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1540", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1540_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1541", SET_RESOURCE, 1, + "", "Specify name of 1540 DOS ROM image" }, + { "-dos1541", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1541", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1541_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1541II", SET_RESOURCE, 1, - NULL, NULL, "DosName1541II", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1541_II_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1570", SET_RESOURCE, 1, + "", "Specify name of 1541 DOS ROM image" }, + { "-dos1541II", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "DosName1541ii", NULL, + "", "Specify name of 1541-II DOS ROM image" }, + { "-dos1570", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1570", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1570_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1571", SET_RESOURCE, 1, + "", "Specify name of 1570 DOS ROM image" }, + { "-dos1571", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1571", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1571_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1581", SET_RESOURCE, 1, + "", "Specify name of 1571 DOS ROM image" }, + { "-dos1581", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1581", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1581_DOS_ROM_NAME, - NULL, NULL }, - { "-dos2000", SET_RESOURCE, 1, + "", "Specify name of 1581 DOS ROM image" }, + { "-dos2000", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName2000", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_2000_DOS_ROM_NAME, - NULL, NULL }, - { "-dos4000", SET_RESOURCE, 1, + "", "Specify name of 2000 DOS ROM image" }, + { "-dos4000", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName4000", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_4000_DOS_ROM_NAME, - NULL, NULL }, + "", "Specify name of 4000 DOS ROM image" }, + { "-dosCMDHD", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "DosNameCMDHD", NULL, + "", "Specify name of CMD HD Boot ROM image" }, CMDLINE_LIST_END }; -static cmdline_option_t cmd_drive[] = { - { NULL, SET_RESOURCE, 0, +static cmdline_option_t cmd_drive[] = +{ + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RAM_2000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable 8KiB RAM expansion at $2000-$3FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RAM_2000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable 8KiB RAM expansion at $2000-$3FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RAM_4000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable 8KiB RAM expansion at $4000-$5FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RAM_4000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable 8KiB RAM expansion at $4000-$5FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RAM_6000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable 8KiB RAM expansion at $6000-$7FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RAM_6000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable 8KiB RAM expansion at $6000-$7FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RAM_8000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable 8KiB RAM expansion at $8000-$9FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RAM_8000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Disable 8KiB RAM expansion at $8000-$9FFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_DRIVE_RAM_A000, - NULL, NULL }, - { NULL, SET_RESOURCE, 0, + NULL, "Enable 8KiB RAM expansion at $A000-$BFFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, NULL, (void *)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_DRIVE_RAM_A000, - NULL, NULL }, + NULL, "Disable 8KiB RAM expansion at $A000-$BFFF" }, + { NULL, SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, NULL, NULL, + "", "Fixed Disk Size" }, CMDLINE_LIST_END }; int iec_cmdline_options_init(void) { - unsigned int dnr, i; + int dnr; + + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + int i; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { cmd_drive[0].name = lib_msprintf("-drive%iram2000", dnr + 8); cmd_drive[0].resource_name = lib_msprintf("Drive%iRAM2000", dnr + 8); @@ -167,12 +140,15 @@ int iec_cmdline_options_init(void) cmd_drive[9].name = lib_msprintf("+drive%irama000", dnr + 8); cmd_drive[9].resource_name = lib_msprintf("Drive%iRAMA000", dnr + 8); + cmd_drive[10].name = lib_msprintf("-drive%ifixedsize", dnr + 8); + cmd_drive[10].resource_name + = lib_msprintf("Drive%iFixedSize", dnr + 8); if (cmdline_register_options(cmd_drive) < 0) { return -1; } - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { lib_free(cmd_drive[i].name); lib_free(cmd_drive[i].resource_name); } diff --git a/src/Emulators/vice/drive/iec/iec-cmdline-options.h b/src/Emulators/vice/drive/iec/iec-cmdline-options.h index a88bc326..2dd1ce06 100644 --- a/src/Emulators/vice/drive/iec/iec-cmdline-options.h +++ b/src/Emulators/vice/drive/iec/iec-cmdline-options.h @@ -27,6 +27,6 @@ #ifndef VICE_IEC_CMDLINE_OPTIONS_H #define VICE_IEC_CMDLINE_OPTIONS_H -extern int iec_cmdline_options_init(void); +int iec_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/drive/iec/iec-resources.c b/src/Emulators/vice/drive/iec/iec-resources.c index 77d4fd22..c62d49ad 100644 --- a/src/Emulators/vice/drive/iec/iec-resources.c +++ b/src/Emulators/vice/drive/iec/iec-resources.c @@ -27,6 +27,9 @@ #include "vice.h" #include +#include +#include +#include #include "drive.h" #include "drivemem.h" @@ -38,6 +41,7 @@ #include "resources.h" #include "traps.h" #include "util.h" +#include "cmdhd.h" static char *dos_rom_name_1540 = NULL; static char *dos_rom_name_1541 = NULL; @@ -47,16 +51,17 @@ static char *dos_rom_name_1571 = NULL; static char *dos_rom_name_1581 = NULL; static char *dos_rom_name_2000 = NULL; static char *dos_rom_name_4000 = NULL; +static char *dos_rom_name_CMDHD = NULL; static void set_drive_ram(unsigned int dnr) { - drive_t *drive = drive_context[dnr]->drive; + diskunit_context_t *unit = diskunit_context[dnr]; - if (drive->type == DRIVE_TYPE_NONE) { + if (unit->type == DRIVE_TYPE_NONE) { return; } - drivemem_init(drive_context[dnr], drive->type); + drivemem_init(unit); return; } @@ -133,69 +138,202 @@ static int set_dos_rom_name_4000(const char *val, void *param) return iecrom_load_4000(); } +static int set_dos_rom_name_CMDHD(const char *val, void *param) +{ + if (util_string_set(&dos_rom_name_CMDHD, val)) { + return 0; + } + + return iecrom_load_CMDHD(); +} + +static int set_drive_fixed(const char *val, void *param) +{ + char *end; + int shift; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; + unsigned long long int work; + char suffix; + size_t len = 0; + char *check_string = NULL; + char last_char = 0; + int i; +#if 0 + unsigned long long int calc; + char text[50]; + int tp = 0; +#endif + + /* check if the given string is null */ + if (!util_check_null_string(val)) { + + /* duplicate the string so we can work on it */ + check_string = lib_strdup(val); + + /* remove any spaces */ + util_remove_spaces(check_string); + + /* check if last character is a k, m or g */ + len = strlen(check_string); + if (!len) { + lib_free(check_string); + return -1; + } + last_char = util_toupper(check_string[len - 1]); + if (last_char == 'K' || last_char == 'M' || last_char == 'G') { + check_string[len - 1] = 0; + } + + /* now check if the left over string is a number */ + len = strlen(check_string); + for (i = 0; i < len; i++) { + if (!isdigit((unsigned char)check_string[i])) { + lib_free(check_string); + return -1; + } + } + + /* string is a valid input, free the check string and proceed with the rest of the code */ + lib_free(check_string); + } + + /* free existing ASCII value of resource */ + if (unit->fixed_size_text) { + lib_free(unit->fixed_size_text); + } + + + /* turn whatever we are given into a number */ + errno = 0; + work = strtoll(val, &end, 0); + + /* if it is good, and the remaining pointer is good, process any suffix */ + if (!errno && end) { + /* skip any spaces */ + while (*end == ' ') { + end++; + } + /* check for 3 suffixes */ + suffix = util_toupper(*end); + if (suffix == 'K') { + shift = 10; + } else if (suffix == 'M') { + shift = 20; + } else if (suffix == 'G') { + shift = 30; + } else { + shift = 0; + suffix = 0; + } +#if 0 + /* make my own ascii output since lib_msprintf("%"PRIu64"%c", work, suffix) + doesn't work on windows at all */ + text[tp++] = 0; + text[tp++] = suffix; + + /* generate ascii output in reverse order */ + calc = work; + while (calc && tp < 48) { + text[tp++] = (calc % 10) + '0'; + calc = calc / 10; + } + + /* allocate and copy back in proper order */ + unit->fixed_size_text = lib_malloc(tp); + for (i = 0; i < tp; i++) { + unit->fixed_size_text[i] = text[tp - 1 - i]; + } +#else + /* just copy what was passed */ + unit->fixed_size_text = lib_strdup(val); +#endif + + /* apply change */ + work = work << shift; + /* make it terms of 512 byte units */ + unit->fixed_size = (unsigned int)(work >> 9); + /* round up if need be */ + if (work & 511) { + unit->fixed_size++; + } + } else { + /* if any conversion errors happen, just make it 0 */ + unit->fixed_size = 0; + /* generate a new ascii representation of the full value */ + unit->fixed_size_text = lib_msprintf("0"); + } + + /* tell the CMDHD, if there is one, the updated value */ + cmdhd_update_maxsize(unit->fixed_size, vice_ptr_to_uint(param) + 8); + + return 0; +} + static int set_drive_ram2(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->drive_ram2_enabled = val ? 1 : 0; + unit->drive_ram2_enabled = val ? 1 : 0; set_drive_ram(vice_ptr_to_uint(param)); return 0; } static int set_drive_ram4(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->drive_ram4_enabled = val ? 1 : 0; + unit->drive_ram4_enabled = val ? 1 : 0; set_drive_ram(vice_ptr_to_uint(param)); return 0; } static int set_drive_ram6(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->drive_ram6_enabled = val ? 1 : 0; + unit->drive_ram6_enabled = val ? 1 : 0; set_drive_ram(vice_ptr_to_uint(param)); return 0; } static int set_drive_ram8(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->drive_ram8_enabled = val ? 1 : 0; + unit->drive_ram8_enabled = val ? 1 : 0; set_drive_ram(vice_ptr_to_uint(param)); return 0; } static int set_drive_rama(int val, void *param) { - drive_t *drive = drive_context[vice_ptr_to_uint(param)]->drive; + diskunit_context_t *unit = diskunit_context[vice_ptr_to_uint(param)]; - drive->drive_rama_enabled = val ? 1 : 0; + unit->drive_rama_enabled = val ? 1 : 0; set_drive_ram(vice_ptr_to_uint(param)); return 0; } static const resource_string_t resources_string[] = { - { "DosName1540", "dos1540", RES_EVENT_NO, NULL, + { "DosName1540", DRIVE_ROM1540_NAME, RES_EVENT_NO, NULL, /* FIXME: should be same but names may differ */ &dos_rom_name_1540, set_dos_rom_name_1540, NULL }, - { "DosName1541", "dos1541", RES_EVENT_NO, NULL, + { "DosName1541", DRIVE_ROM1541_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1541, set_dos_rom_name_1541, NULL }, - { "DosName1541ii", "d1541II", RES_EVENT_NO, NULL, + { "DosName1541ii", DRIVE_ROM1541II_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1541ii, set_dos_rom_name_1541ii, NULL }, - { "DosName1570", "dos1570", RES_EVENT_NO, NULL, + { "DosName1570", DRIVE_ROM1570_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1570, set_dos_rom_name_1570, NULL }, - { "DosName1571", "dos1571", RES_EVENT_NO, NULL, + { "DosName1571", DRIVE_ROM1571_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1571, set_dos_rom_name_1571, NULL }, - { "DosName1581", "dos1581", RES_EVENT_NO, NULL, + { "DosName1581", DRIVE_ROM1581_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1581, set_dos_rom_name_1581, NULL }, - { "DosName2000", "dos2000", RES_EVENT_NO, NULL, + { "DosName2000", DRIVE_ROM2000_NAME, RES_EVENT_NO, NULL, &dos_rom_name_2000, set_dos_rom_name_2000, NULL }, - { "DosName4000", "dos4000", RES_EVENT_NO, NULL, + { "DosName4000", DRIVE_ROM4000_NAME, RES_EVENT_NO, NULL, &dos_rom_name_4000, set_dos_rom_name_4000, NULL }, + { "DosNameCMDHD", DRIVE_ROMCMDHD_NAME, RES_EVENT_NO, NULL, + &dos_rom_name_CMDHD, set_dos_rom_name_CMDHD, NULL }, RESOURCE_STRING_LIST_END }; @@ -213,29 +351,34 @@ static resource_int_t res_drive[] = { RESOURCE_INT_LIST_END }; +static resource_string_t res_string[] = { + { NULL, "8G", RES_EVENT_SAME, NULL, + NULL, set_drive_fixed, NULL }, + RESOURCE_STRING_LIST_END +}; + int iec_resources_init(void) { - unsigned int dnr; - drive_t *drive; + int dnr; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + diskunit_context_t *unit = diskunit_context[dnr]; res_drive[0].name = lib_msprintf("Drive%iRAM2000", dnr + 8); - res_drive[0].value_ptr = &(drive->drive_ram2_enabled); - res_drive[0].param = uint_to_void_ptr(dnr); + res_drive[0].value_ptr = &(unit->drive_ram2_enabled); + res_drive[0].param = vice_uint_to_ptr(dnr); res_drive[1].name = lib_msprintf("Drive%iRAM4000", dnr + 8); - res_drive[1].value_ptr = &(drive->drive_ram4_enabled); - res_drive[1].param = uint_to_void_ptr(dnr); + res_drive[1].value_ptr = &(unit->drive_ram4_enabled); + res_drive[1].param = vice_uint_to_ptr(dnr); res_drive[2].name = lib_msprintf("Drive%iRAM6000", dnr + 8); - res_drive[2].value_ptr = &(drive->drive_ram6_enabled); - res_drive[2].param = uint_to_void_ptr(dnr); + res_drive[2].value_ptr = &(unit->drive_ram6_enabled); + res_drive[2].param = vice_uint_to_ptr(dnr); res_drive[3].name = lib_msprintf("Drive%iRAM8000", dnr + 8); - res_drive[3].value_ptr = &(drive->drive_ram8_enabled); - res_drive[3].param = uint_to_void_ptr(dnr); + res_drive[3].value_ptr = &(unit->drive_ram8_enabled); + res_drive[3].param = vice_uint_to_ptr(dnr); res_drive[4].name = lib_msprintf("Drive%iRAMA000", dnr + 8); - res_drive[4].value_ptr = &(drive->drive_rama_enabled); - res_drive[4].param = uint_to_void_ptr(dnr); + res_drive[4].value_ptr = &(unit->drive_rama_enabled); + res_drive[4].param = vice_uint_to_ptr(dnr); if (resources_register_int(res_drive) < 0) { return -1; @@ -246,6 +389,19 @@ int iec_resources_init(void) lib_free(res_drive[2].name); lib_free(res_drive[3].name); lib_free(res_drive[4].name); + + res_string[0].name = lib_msprintf("Drive%iFixedSize", dnr + 8); + res_string[0].value_ptr = &(unit->fixed_size_text); + res_string[0].param = vice_uint_to_ptr(dnr); + unit->fixed_size_text = NULL; + unit->fixed_size = 0; + + if (resources_register_string(res_string) < 0) { + return -1; + } + + lib_free(res_string[0].name); + } if (resources_register_string(resources_string) < 0) { @@ -265,4 +421,5 @@ void iec_resources_shutdown(void) lib_free(dos_rom_name_1581); lib_free(dos_rom_name_2000); lib_free(dos_rom_name_4000); + lib_free(dos_rom_name_CMDHD); } diff --git a/src/Emulators/vice/drive/iec/iec-resources.h b/src/Emulators/vice/drive/iec/iec-resources.h index c9c631bb..fd327731 100644 --- a/src/Emulators/vice/drive/iec/iec-resources.h +++ b/src/Emulators/vice/drive/iec/iec-resources.h @@ -27,7 +27,7 @@ #ifndef VICE_IEC_RESOURCES_H #define VICE_IEC_RESOURCES_H -extern int iec_resources_init(void); -extern void iec_resources_shutdown(void); +int iec_resources_init(void); +void iec_resources_shutdown(void); #endif diff --git a/src/Emulators/vice/drive/iec/iec.c b/src/Emulators/vice/drive/iec/iec.c index 098a9f87..393f2c3f 100644 --- a/src/Emulators/vice/drive/iec/iec.c +++ b/src/Emulators/vice/drive/iec/iec.c @@ -47,6 +47,7 @@ #include "wd1770.h" #include "via4000.h" #include "pc8477.h" +#include "cmdhd.h" /* Pointer to the IEC bus structure. */ @@ -68,7 +69,7 @@ int iec_drive_cmdline_options_init(void) return iec_cmdline_options_init(); } -void iec_drive_init(struct drive_context_s *drv) +void iec_drive_init(struct diskunit_context_s *drv) { iecrom_init(); via1d1541_init(drv); @@ -77,60 +78,73 @@ void iec_drive_init(struct drive_context_s *drv) via4000_init(drv); wd1770d_init(drv); pc8477d_init(drv); + /* due to the complexity of the CMD HD memory addressing and IO, + we keep the setup of it in separate functions */ + cmdhd_init(drv); } -void iec_drive_reset(struct drive_context_s *drv) +/* called by machine_drive_reset() */ +void iec_drive_reset(struct diskunit_context_s *drv) { - if (drv->drive->type == DRIVE_TYPE_1540 - || drv->drive->type == DRIVE_TYPE_1541 - || drv->drive->type == DRIVE_TYPE_1541II - || drv->drive->type == DRIVE_TYPE_1570 - || drv->drive->type == DRIVE_TYPE_1571 - || drv->drive->type == DRIVE_TYPE_1571CR) { + if (drv->type == DRIVE_TYPE_1540 + || drv->type == DRIVE_TYPE_1541 + || drv->type == DRIVE_TYPE_1541II + || drv->type == DRIVE_TYPE_1570 + || drv->type == DRIVE_TYPE_1571 + || drv->type == DRIVE_TYPE_1571CR) { viacore_reset(drv->via1d1541); } else { viacore_disable(drv->via1d1541); } - if (drv->drive->type == DRIVE_TYPE_1570 - || drv->drive->type == DRIVE_TYPE_1571 - || drv->drive->type == DRIVE_TYPE_1571CR) { + if (drv->type == DRIVE_TYPE_1570 + || drv->type == DRIVE_TYPE_1571 + || drv->type == DRIVE_TYPE_1571CR) { ciacore_reset(drv->cia1571); } else { ciacore_disable(drv->cia1571); } - if (drv->drive->type == DRIVE_TYPE_1581) { + if (drv->type == DRIVE_TYPE_1581) { ciacore_reset(drv->cia1581); wd1770_reset(drv->wd1770); } else { ciacore_disable(drv->cia1581); } - if (drv->drive->type == DRIVE_TYPE_2000 - || drv->drive->type == DRIVE_TYPE_4000) { + if (drv->type == DRIVE_TYPE_2000 + || drv->type == DRIVE_TYPE_4000) { viacore_reset(drv->via4000); - pc8477_reset(drv->pc8477, drv->drive->type == DRIVE_TYPE_4000); + pc8477_reset(drv->pc8477, drv->type == DRIVE_TYPE_4000); } else { viacore_disable(drv->via4000); } + + if (drv->type == DRIVE_TYPE_CMDHD ) { + /* due to the complexity of the CMD HD memory addressing and IO, + we keep the setup of it in separate functions */ + cmdhd_reset(drv->cmdhd); + } } -void iec_drive_mem_init(struct drive_context_s *drv, unsigned int type) +void iec_drive_mem_init(struct diskunit_context_s *drv, unsigned int type) { memiec_init(drv, type); } -void iec_drive_setup_context(struct drive_context_s *drv) +void iec_drive_setup_context(struct diskunit_context_s *drv) { via1d1541_setup_context(drv); cia1571_setup_context(drv); cia1581_setup_context(drv); via4000_setup_context(drv); pc8477_setup_context(drv); + /* due to the complexity of the CMD HD memory addressing and IO, + we keep the setup of it in separate functions */ + cmdhd_setup_context(drv); } -void iec_drive_shutdown(struct drive_context_s *drv) +void iec_drive_shutdown(struct diskunit_context_s *drv) { viacore_shutdown(drv->via1d1541); ciacore_shutdown(drv->cia1571); @@ -138,19 +152,28 @@ void iec_drive_shutdown(struct drive_context_s *drv) viacore_shutdown(drv->via4000); wd1770_shutdown(drv->wd1770); pc8477_shutdown(drv->pc8477); + /* due to the complexity of the CMD HD memory addressing and IO, + we keep the setup of it in separate functions */ + cmdhd_shutdown(drv->cmdhd); + /* free existing ASCII value of resource */ + if (drv->fixed_size_text) { + lib_free(drv->fixed_size_text); + drv->fixed_size_text = NULL; + } } void iec_drive_idling_method(unsigned int dnr) { char *tmp; - tmp = lib_msprintf("Drive%iIdleMethod", dnr + 8); + tmp = lib_msprintf("Drive%uIdleMethod", dnr + 8); resources_touch(tmp); lib_free(tmp); } +/* test all ROMs for existence, size */ void iec_drive_rom_load(void) { iecrom_load_1540(); @@ -161,13 +184,16 @@ void iec_drive_rom_load(void) iecrom_load_1581(); iecrom_load_2000(); iecrom_load_4000(); + iecrom_load_CMDHD(); } +/* setup (=load) the ROM for a given disk unit nr */ void iec_drive_rom_setup_image(unsigned int dnr) { - iecrom_setup_image(drive_context[dnr]->drive); + iecrom_setup_image(diskunit_context[dnr]); } +/* check if the drive ROM is available for a given drive type, returns -1 on error */ int iec_drive_rom_check_loaded(unsigned int type) { return iecrom_check_loaded(type); @@ -175,13 +201,13 @@ int iec_drive_rom_check_loaded(unsigned int type) void iec_drive_rom_do_checksum(unsigned int dnr) { - iecrom_do_checksum(drive_context[dnr]->drive); + iecrom_do_checksum(diskunit_context[dnr]); } -int iec_drive_snapshot_read(struct drive_context_s *ctxptr, +int iec_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - switch (ctxptr->drive->type) { + switch (ctxptr->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: @@ -213,6 +239,11 @@ int iec_drive_snapshot_read(struct drive_context_s *ctxptr, return -1; } break; + case DRIVE_TYPE_CMDHD: + if (cmdhd_snapshot_read_module(ctxptr->cmdhd, s) < 0) { + return -1; + } + break; default: break; } @@ -220,10 +251,10 @@ int iec_drive_snapshot_read(struct drive_context_s *ctxptr, return 0; } -int iec_drive_snapshot_write(struct drive_context_s *ctxptr, +int iec_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - switch (ctxptr->drive->type) { + switch (ctxptr->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: @@ -255,6 +286,11 @@ int iec_drive_snapshot_write(struct drive_context_s *ctxptr, return -1; } break; + case DRIVE_TYPE_CMDHD: + if (cmdhd_snapshot_write_module(ctxptr->cmdhd, s) < 0) { + return -1; + } + break; default: break; } @@ -262,17 +298,25 @@ int iec_drive_snapshot_write(struct drive_context_s *ctxptr, return 0; } -int iec_drive_image_attach(struct disk_image_s *image, unsigned int unit) +int iec_drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return wd1770_attach_image(image, unit) & pc8477_attach_image(image, unit); + if (drive) { + return -1; + } + return wd1770_attach_image(image, unit) & pc8477_attach_image(image, unit) & + cmdhd_attach_image(image, unit); } -int iec_drive_image_detach(struct disk_image_s *image, unsigned int unit) +int iec_drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return wd1770_detach_image(image, unit) & pc8477_detach_image(image, unit); + if (drive) { + return -1; + } + return wd1770_detach_image(image, unit) & pc8477_detach_image(image, unit) & + cmdhd_detach_image(image, unit); } -void iec_drive_port_default(struct drive_context_s *drv) +void iec_drive_port_default(struct diskunit_context_s *drv) { drive_iecbus = iecbus_drive_port(); diff --git a/src/Emulators/vice/drive/iec/iecrom.c b/src/Emulators/vice/drive/iec/iecrom.c index d75a9c7e..f9f7ad06 100644 --- a/src/Emulators/vice/drive/iec/iecrom.c +++ b/src/Emulators/vice/drive/iec/iecrom.c @@ -37,31 +37,23 @@ #include "resources.h" #include "sysfile.h" +/* #define DEBUG_IECROM */ + +#ifdef DEBUG_IECROM +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + #define DRIVE_ROM1541_CHECKSUM 1991711 +/* NOTE: 1571CR is handled in iec128dcr/iec128dcrrom.c */ /* Logging goes here. */ static log_t iecrom_log; -static BYTE drive_rom1540[DRIVE_ROM1540_SIZE_EXPANDED]; -static BYTE drive_rom1541[DRIVE_ROM1541_SIZE_EXPANDED]; -static BYTE drive_rom1541ii[DRIVE_ROM1541II_SIZE_EXPANDED]; - -#ifdef USE_EMBEDDED -#include "drivedos1570.h" -#include "drivedos1571.h" -#include "drivedos1581.h" -#else -static BYTE drive_rom1570[DRIVE_ROM1570_SIZE]; -static BYTE drive_rom1571[DRIVE_ROM1571_SIZE]; -static BYTE drive_rom1581[DRIVE_ROM1581_SIZE]; -#endif - -static BYTE drive_rom2000[DRIVE_ROM2000_SIZE]; -static BYTE drive_rom4000[DRIVE_ROM4000_SIZE]; - -/* If nonzero, the ROM image has been loaded. */ +/* If nonzero, the ROM image is available */ static unsigned int rom1540_loaded = 0; static unsigned int rom1541_loaded = 0; static unsigned int rom1541ii_loaded = 0; @@ -70,21 +62,22 @@ static unsigned int rom1571_loaded = 0; static unsigned int rom1581_loaded = 0; static unsigned int rom2000_loaded = 0; static unsigned int rom4000_loaded = 0; +static unsigned int romCMDHD_loaded = 0; -static unsigned int drive_rom1540_size; -static unsigned int drive_rom1541_size; -static unsigned int drive_rom1541ii_size; +static unsigned int drive_rom1540_size = 0; +static unsigned int drive_rom1541_size = 0; +static unsigned int drive_rom1541ii_size = 0; - -static int iecrom_do_1541_checksum(void) +static int iecrom_do_1541_checksum(diskunit_context_t *unit) { unsigned int i; unsigned long s; + DBG(("iecrom_do_1541_checksum type: %04x", unit->type)); /* Calculate ROM checksum. */ for (i = DRIVE_ROM1541_SIZE_EXPANDED - drive_rom1541_size, s = 0; i < DRIVE_ROM1541_SIZE_EXPANDED; i++) { - s += drive_rom1541[i]; + s += unit->rom[i]; } if (s != DRIVE_ROM1541_CHECKSUM) { @@ -94,23 +87,24 @@ static int iecrom_do_1541_checksum(void) return 0; } +/* test ROM for existence, size */ int iecrom_load_1540(void) { - return driverom_load("DosName1540", drive_rom1540, &rom1540_loaded, + return driverom_test_load("DosName1540", &rom1540_loaded, DRIVE_ROM1540_SIZE, DRIVE_ROM1540_SIZE_EXPANDED, "1540", DRIVE_TYPE_1540, &drive_rom1540_size); } int iecrom_load_1541(void) { - return driverom_load("DosName1541", drive_rom1541, &rom1541_loaded, + return driverom_test_load("DosName1541", &rom1541_loaded, DRIVE_ROM1541_SIZE, DRIVE_ROM1541_SIZE_EXPANDED, "1541", DRIVE_TYPE_1541, &drive_rom1541_size); } int iecrom_load_1541ii(void) { - return driverom_load("DosName1541ii", drive_rom1541ii, + return driverom_test_load("DosName1541ii", &rom1541ii_loaded, DRIVE_ROM1541II_SIZE, DRIVE_ROM1541II_SIZE_EXPANDED, "1541-II", DRIVE_TYPE_1541II, &drive_rom1541ii_size); @@ -118,96 +112,129 @@ int iecrom_load_1541ii(void) int iecrom_load_1570(void) { - return driverom_load("DosName1570", drive_rom1570, &rom1570_loaded, + return driverom_test_load("DosName1570", &rom1570_loaded, DRIVE_ROM1570_SIZE, DRIVE_ROM1570_SIZE, "1570", DRIVE_TYPE_1570, NULL); } int iecrom_load_1571(void) { - return driverom_load("DosName1571", drive_rom1571, &rom1571_loaded, + return driverom_test_load("DosName1571", &rom1571_loaded, DRIVE_ROM1571_SIZE, DRIVE_ROM1571_SIZE, "1571", DRIVE_TYPE_1571, NULL); } int iecrom_load_1581(void) { - return driverom_load("DosName1581", drive_rom1581, &rom1581_loaded, + return driverom_test_load("DosName1581", &rom1581_loaded, DRIVE_ROM1581_SIZE, DRIVE_ROM1581_SIZE, "1581", DRIVE_TYPE_1581, NULL); } int iecrom_load_2000(void) { - return driverom_load("DosName2000", drive_rom2000, &rom2000_loaded, + return driverom_test_load("DosName2000", &rom2000_loaded, DRIVE_ROM2000_SIZE, DRIVE_ROM2000_SIZE, "2000", DRIVE_TYPE_2000, NULL); } int iecrom_load_4000(void) { - return driverom_load("DosName4000", drive_rom4000, &rom4000_loaded, + return driverom_test_load("DosName4000", &rom4000_loaded, DRIVE_ROM4000_SIZE, DRIVE_ROM4000_SIZE, "4000", DRIVE_TYPE_4000, NULL); } -void iecrom_setup_image(drive_t *drive) +int iecrom_load_CMDHD(void) +{ + return driverom_test_load("DosNameCMDHD", &romCMDHD_loaded, + DRIVE_ROMCMDHD_SIZE, DRIVE_ROMCMDHD_SIZE, "CMDHD", DRIVE_TYPE_CMDHD, NULL); +} + +/* setup (=load) the ROM for a given disk unit */ +void iecrom_setup_image(diskunit_context_t *unit) { + unsigned int loaded = 0; + DBG(("iecrom_setup_image type %04x rom_loaded:%d rom_type: %04x", unit->type, rom_loaded, unit->rom_type)); if (rom_loaded) { - switch (drive->type) { - case DRIVE_TYPE_1540: - if (drive_rom1540_size <= DRIVE_ROM1540_SIZE) { - memcpy(drive->rom, &drive_rom1540[DRIVE_ROM1540_SIZE], - DRIVE_ROM1540_SIZE); - memcpy(&(drive->rom[DRIVE_ROM1540_SIZE]), - &drive_rom1540[DRIVE_ROM1540_SIZE], - DRIVE_ROM1540_SIZE); - } else { - memcpy(drive->rom, drive_rom1540, - DRIVE_ROM1540_SIZE_EXPANDED); - } - break; - case DRIVE_TYPE_1541: - if (drive_rom1541_size <= DRIVE_ROM1541_SIZE) { - memcpy(drive->rom, &drive_rom1541[DRIVE_ROM1541_SIZE], - DRIVE_ROM1541_SIZE); - memcpy(&(drive->rom[DRIVE_ROM1541_SIZE]), - &drive_rom1541[DRIVE_ROM1541_SIZE], - DRIVE_ROM1541_SIZE); - } else { - memcpy(drive->rom, drive_rom1541, - DRIVE_ROM1541_SIZE_EXPANDED); - } - break; - case DRIVE_TYPE_1541II: - if (drive_rom1541ii_size <= DRIVE_ROM1541II_SIZE) { - memcpy(drive->rom, &drive_rom1541ii[DRIVE_ROM1541II_SIZE], - DRIVE_ROM1541II_SIZE); - memcpy(&(drive->rom[DRIVE_ROM1541II_SIZE]), - &drive_rom1541ii[DRIVE_ROM1541II_SIZE], - DRIVE_ROM1541II_SIZE); - } else { - memcpy(drive->rom, drive_rom1541ii, - DRIVE_ROM1541II_SIZE_EXPANDED); - } - break; - case DRIVE_TYPE_1570: - memcpy(drive->rom, drive_rom1570, DRIVE_ROM1570_SIZE); - break; - case DRIVE_TYPE_1571: - memcpy(drive->rom, drive_rom1571, DRIVE_ROM1571_SIZE); - break; - case DRIVE_TYPE_1581: - memcpy(drive->rom, drive_rom1581, DRIVE_ROM1581_SIZE); - break; - case DRIVE_TYPE_2000: - memcpy(drive->rom, drive_rom2000, DRIVE_ROM2000_SIZE); - break; - case DRIVE_TYPE_4000: - memcpy(drive->rom, drive_rom4000, DRIVE_ROM4000_SIZE); - break; - default: - /* NOP */ - break; + + if (unit->rom_type != unit->type) { + /* set this here to avoid recursion */ + unit->rom_type = unit->type; + + switch (unit->type) { + case DRIVE_TYPE_1540: + driverom_load("DosName1540", unit->rom, &loaded, + DRIVE_ROM1540_SIZE, DRIVE_ROM1540_SIZE_EXPANDED, "1540", + DRIVE_TYPE_1540, &drive_rom1540_size); + if (drive_rom1540_size <= DRIVE_ROM1540_SIZE) { + /* ROM was loaded to the upper part of the buffer */ + memcpy(unit->rom, &unit->rom[DRIVE_ROM1540_SIZE], + DRIVE_ROM1540_SIZE); + } + break; + case DRIVE_TYPE_1541: + driverom_load("DosName1541", unit->rom, &loaded, + DRIVE_ROM1541_SIZE, DRIVE_ROM1541_SIZE_EXPANDED, "1541", + DRIVE_TYPE_1541, &drive_rom1541_size); + if (drive_rom1541_size <= DRIVE_ROM1541_SIZE) { + /* ROM was loaded to the upper part of the buffer */ + memcpy(unit->rom, &unit->rom[DRIVE_ROM1541_SIZE], + DRIVE_ROM1541_SIZE); + } + break; + case DRIVE_TYPE_1541II: + driverom_load("DosName1541ii", unit->rom, &loaded, + DRIVE_ROM1541II_SIZE, DRIVE_ROM1541II_SIZE_EXPANDED, "1541-II", + DRIVE_TYPE_1541II, &drive_rom1541ii_size); + if (drive_rom1541ii_size <= DRIVE_ROM1541II_SIZE) { + /* ROM was loaded to the upper part of the buffer */ + memcpy(unit->rom, &unit->rom[DRIVE_ROM1541II_SIZE], + DRIVE_ROM1541II_SIZE); + } + break; + + case DRIVE_TYPE_1570: + driverom_load("DosName1570", unit->rom, &loaded, + DRIVE_ROM1570_SIZE, DRIVE_ROM1570_SIZE, "1570", + DRIVE_TYPE_1570, NULL); + break; + case DRIVE_TYPE_1571: + driverom_load("DosName1571", unit->rom, &loaded, + DRIVE_ROM1571_SIZE, DRIVE_ROM1571_SIZE, "1571", + DRIVE_TYPE_1571, NULL); + break; + case DRIVE_TYPE_1581: + driverom_load("DosName1581", unit->rom, &loaded, + DRIVE_ROM1581_SIZE, DRIVE_ROM1581_SIZE, "1581", + DRIVE_TYPE_1581, NULL); + break; + case DRIVE_TYPE_2000: + driverom_load("DosName2000", unit->rom, &loaded, + DRIVE_ROM2000_SIZE, DRIVE_ROM2000_SIZE, "2000", + DRIVE_TYPE_2000, NULL); + break; + case DRIVE_TYPE_4000: + driverom_load("DosName4000", unit->rom, &loaded, + DRIVE_ROM4000_SIZE, DRIVE_ROM4000_SIZE, "4000", + DRIVE_TYPE_4000, NULL); + break; + case DRIVE_TYPE_CMDHD: + driverom_load("DosNameCMDHD", unit->rom, &loaded, + DRIVE_ROMCMDHD_SIZE, DRIVE_ROMCMDHD_SIZE, "CMDHD", + DRIVE_TYPE_CMDHD, NULL); + break; + + default: + /* NOP */ + break; + } + + /* if loading failed, set rom type to 0 */ + if (!loaded) { + unit->rom_type = 0; + } } + } } +/* check if the drive ROM is available for a given drive type, returns -1 on error */ int iecrom_check_loaded(unsigned int type) { switch (type) { @@ -253,10 +280,15 @@ int iecrom_check_loaded(unsigned int type) return -1; } break; + case DRIVE_TYPE_CMDHD: + if (romCMDHD_loaded < 1 && rom_loaded) { + return -1; + } + break; case DRIVE_TYPE_ANY: if ((!rom1540_loaded && !rom1541_loaded && !rom1541ii_loaded && !rom1570_loaded && !rom1571_loaded && !rom1581_loaded && !rom2000_loaded) - && !rom4000_loaded && rom_loaded) { + && !rom4000_loaded && !romCMDHD_loaded && rom_loaded) { return -1; } break; @@ -267,10 +299,12 @@ int iecrom_check_loaded(unsigned int type) return 0; } -void iecrom_do_checksum(drive_t *drive) +/* perform checksum check on ROM for given disk unit nr */ +void iecrom_do_checksum(diskunit_context_t *unit) { - if (drive->type == DRIVE_TYPE_1541) { - iecrom_do_1541_checksum(); + DBG(("iecrom_do_checksum type: %04x", unit->type)); + if (unit->type == DRIVE_TYPE_1541) { + iecrom_do_1541_checksum(unit); } } diff --git a/src/Emulators/vice/drive/iec/iecrom.h b/src/Emulators/vice/drive/iec/iecrom.h index a5a8bbc9..bd7521de 100644 --- a/src/Emulators/vice/drive/iec/iecrom.h +++ b/src/Emulators/vice/drive/iec/iecrom.h @@ -29,20 +29,21 @@ #include "vicetypes.h" -struct drive_s; +struct diskunit_context_s; -extern void iecrom_init(void); -extern void iecrom_setup_image(struct drive_s *drive); -extern int iecrom_check_loaded(unsigned int type); -extern void iecrom_do_checksum(struct drive_s *drive); +void iecrom_init(void); +void iecrom_setup_image(struct diskunit_context_s *unit); +int iecrom_check_loaded(unsigned int type); +void iecrom_do_checksum(struct diskunit_context_s *unit); -extern int iecrom_load_1540(void); -extern int iecrom_load_1541(void); -extern int iecrom_load_1541ii(void); -extern int iecrom_load_1570(void); -extern int iecrom_load_1571(void); -extern int iecrom_load_1581(void); -extern int iecrom_load_2000(void); -extern int iecrom_load_4000(void); +int iecrom_load_1540(void); +int iecrom_load_1541(void); +int iecrom_load_1541ii(void); +int iecrom_load_1570(void); +int iecrom_load_1571(void); +int iecrom_load_1581(void); +int iecrom_load_2000(void); +int iecrom_load_4000(void); +int iecrom_load_CMDHD(void); #endif diff --git a/src/Emulators/vice/drive/iec/memiec.c b/src/Emulators/vice/drive/iec/memiec.c index 644f6c46..32a2d62b 100644 --- a/src/Emulators/vice/drive/iec/memiec.c +++ b/src/Emulators/vice/drive/iec/memiec.c @@ -40,65 +40,111 @@ #include "wd1770.h" #include "via4000.h" #include "pc8477.h" +#include "cmdhd.h" #include "SYS_Types.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" -BYTE drive_read_rom(drive_context_t *drv, WORD address) +/* #define DEBUG_MEMIEC */ + +#ifdef DEBUG_MEMIEC +#define LOG(x) log_printf x +#else +#define LOG(x) +#endif + +uint8_t drive_read_rom(diskunit_context_t *drv, uint16_t address) { - return drv->drive->rom[address & 0x7fff]; + LOG(("%04x %02x drive_read_rom\n", address, drv->rom[address & 0x7fff])); + return drv->cpu->cpu_last_data = drv->rom[address & 0x7fff]; } -BYTE drive_read_rom_ds1216(drive_context_t *drv, WORD address) +static uint8_t drive_peek_rom(diskunit_context_t *drv, uint16_t address) { - return ds1216e_read(drv->drive->ds1216, address, drv->drive->rom[address & 0x7fff]); + LOG(("%04x %02x drive_peek_rom\n", address, drv->rom[address & 0x7fff])); + return drv->rom[address & 0x7fff]; } -static BYTE drive_read_ram(drive_context_t *drv, WORD address) +uint8_t drive_read_rom_ds1216(diskunit_context_t *drv, uint16_t address) { - c64d_mark_drive1541_cell_read(address); + return drv->cpu->cpu_last_data = ds1216e_read(drv->ds1216, address, drv->rom[address & 0x7fff]); +} - return drv->drive->drive_ram[address]; +static uint8_t drive_peek_rom_ds1216(diskunit_context_t *drv, uint16_t address) +{ + return ds1216e_read(drv->ds1216, address, drv->rom[address & 0x7fff]); } -static void drive_store_ram(drive_context_t *drv, WORD address, BYTE value) +static uint8_t drive_read_ram(diskunit_context_t *drv, uint16_t address) { - c64d_mark_drive1541_cell_write(address, value); + VICE_HOOK_DRIVE_CELL_READ(address); - drv->drive->drive_ram[address] = value; + LOG(("%04x %02x drive_read_ram\n", address, drv->drive_ram[address])); + return drv->cpu->cpu_last_data = drv->drive_ram[address]; } -static BYTE drive_read_1541ram(drive_context_t *drv, WORD address) +static uint8_t drive_peek_ram(diskunit_context_t *drv, uint16_t address) { - c64d_mark_drive1541_cell_read(address); - - return drv->drive->drive_ram[address & 0x7ff]; + LOG(("%04x %02x drive_peek_ram\n", address, drv->drive_ram[address])); + return drv->drive_ram[address]; } -static void drive_store_1541ram(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_ram(diskunit_context_t *drv, uint16_t address, uint8_t value) { - c64d_mark_drive1541_cell_write(address, value); - - drv->drive->drive_ram[address & 0x7ff] = value; + VICE_HOOK_DRIVE_CELL_WRITE(address, value); + + drv->cpu->cpu_last_data = value; + drv->drive_ram[address] = value; } -static BYTE drive_read_zero(drive_context_t *drv, WORD address) +static uint8_t drive_read_1541ram(diskunit_context_t *drv, uint16_t address) { - c64d_mark_drive1541_cell_read(address); - - return drv->drive->drive_ram[address & 0xff]; + VICE_HOOK_DRIVE_CELL_READ(address); + + LOG(("%04x %02x drive_read_1541ram\n", address, drv->drive_ram[address & 0x7ff])); + return drv->cpu->cpu_last_data = drv->drive_ram[address & 0x7ff]; +} + +static uint8_t drive_peek_1541ram(diskunit_context_t *drv, uint16_t address) +{ + LOG(("%04x %02x drive_peek_1541ram\n", address, drv->drive_ram[address & 0x7ff])); + return drv->drive_ram[address & 0x7ff]; +} + +static void drive_store_1541ram(diskunit_context_t *drv, uint16_t address, uint8_t value) +{ + VICE_HOOK_DRIVE_CELL_WRITE(address, value); + + drv->cpu->cpu_last_data = value; + drv->drive_ram[address & 0x7ff] = value; +} + +static uint8_t drive_read_zero(diskunit_context_t *drv, uint16_t address) +{ + VICE_HOOK_DRIVE_CELL_READ(address); + + LOG(("%04x %02x drive_read_zero\n", address, drv->drive_ram[address & 0xffu])); + return drv->cpu->cpu_last_data = drv->drive_ram[address & 0xffu]; +} + +static uint8_t drive_peek_zero(diskunit_context_t *drv, uint16_t address) +{ + LOG(("%04x %02x drive_peek_zero\n", address, drv->drive_ram[address & 0xffu])); + return drv->drive_ram[address & 0xffu]; } -static void drive_store_zero(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_zero(diskunit_context_t *drv, uint16_t address, uint8_t value) { - c64d_mark_drive1541_cell_write(address, value); + VICE_HOOK_DRIVE_CELL_WRITE(address, value); - drv->drive->drive_ram[address & 0xff] = value; + drv->cpu->cpu_last_data = value; + drv->drive_ram[address & 0xffu] = value; } /* ------------------------------------------------------------------------- */ -void memiec_init(struct drive_context_s *drv, unsigned int type) +void memiec_init(struct diskunit_context_s *drv, unsigned int type) { drivecpud_context_t *cpud = drv->cpud; @@ -106,87 +152,144 @@ void memiec_init(struct drive_context_s *drv, unsigned int type) case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: - drv->cpu->pageone = drv->drive->drive_ram + 0x100; - drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive->drive_ram, 0x000007fd); - drivemem_set_func(cpud, 0x01, 0x08, drive_read_1541ram, drive_store_1541ram, NULL, &drv->drive->drive_ram[0x0100], 0x000007fd); + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x08, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, &drv->drive_ram[0x0100], 0); drivemem_set_func(cpud, 0x18, 0x1c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); drivemem_set_func(cpud, 0x1c, 0x20, via2d_read, via2d_store, via2d_peek, NULL, 0); - if (drv->drive->drive_ram2_enabled) { - drivemem_set_func(cpud, 0x20, 0x40, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x2000], 0x20003ffd); + if (drv->drive_ram2_enabled) { + drivemem_set_func(cpud, 0x20, 0x40, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x2000], 0); } else { - drivemem_set_func(cpud, 0x20, 0x28, drive_read_1541ram, drive_store_1541ram, NULL, drv->drive->drive_ram, 0x200027fd); + drivemem_set_func(cpud, 0x20, 0x28, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, drv->drive_ram, 0); drivemem_set_func(cpud, 0x38, 0x3c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); drivemem_set_func(cpud, 0x3c, 0x40, via2d_read, via2d_store, via2d_peek, NULL, 0); } - if (drv->drive->drive_ram4_enabled) { - drivemem_set_func(cpud, 0x40, 0x60, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x4000], 0x40005ffd); + if (drv->drive_ram4_enabled) { + drivemem_set_func(cpud, 0x40, 0x60, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x4000], 0); } else { - drivemem_set_func(cpud, 0x40, 0x48, drive_read_1541ram, drive_store_1541ram, NULL, drv->drive->drive_ram, 0x400047fd); + drivemem_set_func(cpud, 0x40, 0x48, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, drv->drive_ram, 0); drivemem_set_func(cpud, 0x58, 0x5c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); drivemem_set_func(cpud, 0x5c, 0x60, via2d_read, via2d_store, via2d_peek, NULL, 0); } - if (drv->drive->drive_ram6_enabled) { - drivemem_set_func(cpud, 0x60, 0x80, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x6000], 0x60007ffd); + if (drv->drive_ram6_enabled) { + drivemem_set_func(cpud, 0x60, 0x80, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x6000], 0); } else { - drivemem_set_func(cpud, 0x60, 0x68, drive_read_1541ram, drive_store_1541ram, NULL, drv->drive->drive_ram, 0x600067fd); + drivemem_set_func(cpud, 0x60, 0x68, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, drv->drive_ram, 0); drivemem_set_func(cpud, 0x78, 0x7c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); drivemem_set_func(cpud, 0x7c, 0x80, via2d_read, via2d_store, via2d_peek, NULL, 0); } - if (drv->drive->drive_ram8_enabled) { - drivemem_set_func(cpud, 0x80, 0xa0, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x8000], 0x80009ffd); + if (drv->drive_ram8_enabled) { + drivemem_set_func(cpud, 0x80, 0xa0, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x8000], 0); } else { - drivemem_set_func(cpud, 0x80, 0xa0, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x80009ffd); + drivemem_set_func(cpud, 0x80, 0xa0, drive_read_rom, NULL, drive_peek_rom, drv->trap_rom, 0); } - if (drv->drive->drive_rama_enabled) { - drivemem_set_func(cpud, 0xa0, 0xc0, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0xa000], 0xa000bffd); + if (drv->drive_rama_enabled) { + drivemem_set_func(cpud, 0xa0, 0xc0, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0xa000], 0); } else { - drivemem_set_func(cpud, 0xa0, 0xc0, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x2000], 0xa000bffd); + drivemem_set_func(cpud, 0xa0, 0xc0, drive_read_rom, NULL, drive_peek_rom, &drv->trap_rom[0x2000], 0); } - drivemem_set_func(cpud, 0xc0, 0x100, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x4000], 0xc000fffd); + drivemem_set_func(cpud, 0xc0, 0x100, drive_read_rom, NULL, drive_peek_rom, &drv->trap_rom[0x4000], 0); break; case DRIVE_TYPE_1570: case DRIVE_TYPE_1571: - case DRIVE_TYPE_1571CR: - drv->cpu->pageone = drv->drive->drive_ram + 0x100; - drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive->drive_ram, 0x000007fd); - drivemem_set_func(cpud, 0x01, 0x08, drive_read_1541ram, drive_store_1541ram, NULL, &drv->drive->drive_ram[0x0100], 0x000007fd); - drivemem_set_func(cpud, 0x08, 0x10, drive_read_1541ram, drive_store_1541ram, NULL, drv->drive->drive_ram, 0x08000ffd); + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x08, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, &drv->drive_ram[0x0100], 0); + drivemem_set_func(cpud, 0x08, 0x10, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, drv->drive_ram, 0); drivemem_set_func(cpud, 0x18, 0x1c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); drivemem_set_func(cpud, 0x1c, 0x20, via2d_read, via2d_store, via2d_peek, NULL, 0); drivemem_set_func(cpud, 0x20, 0x30, wd1770d_read, wd1770d_store, wd1770d_peek, NULL, 0); - if (drv->drive->drive_ram4_enabled) { + if (drv->drive_ram4_enabled) { drivemem_set_func(cpud, 0x40, 0x48, cia1571_read, cia1571_store, cia1571_peek, NULL, 0); - drivemem_set_func(cpud, 0x48, 0x60, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x4000], 0x48005ffd); + drivemem_set_func(cpud, 0x48, 0x60, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x4000], 0); } else { drivemem_set_func(cpud, 0x40, 0x60, cia1571_read, cia1571_store, cia1571_peek, NULL, 0); } - if (drv->drive->drive_ram6_enabled) { - drivemem_set_func(cpud, 0x60, 0x80, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x6000], 0x60007ffd); + if (drv->drive_ram6_enabled) { + drivemem_set_func(cpud, 0x60, 0x80, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x6000], 0); } else { drivemem_set_func(cpud, 0x60, 0x80, cia1571_read, cia1571_store, cia1571_peek, NULL, 0); } - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000fffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, drive_peek_rom, drv->trap_rom, 0); + break; + case DRIVE_TYPE_1571CR: + /* The mos5710 IC in the 1571CR drive implements: + + - a partial CIA + - additional MFM registers at $4010 + - address decoder + + Address Decoder: + + A 15 14 13 12 10 4 3 + RAM 0 0 0 0 x x x 0xxx + VIA1 0 0 0 1 0 x x 10xx 11xx 12xx 13xx 18xx 19xx 1axx 1bxx + VIA2 0 0 0 1 1 x x 14xx 15xx 16xx 17xx 1cxx 1dxx 1exx 1fxx + FDC 0 0 1 0 x 0 0 2x00-2x07 2x20-2x27 2x40-2x47 2x60-2x67 2x80-2x87 2xa0-2xa7 2xc0-2xc7 2xe0-2xe7 + CIA 0 1 0 0 x 0 x 4x0x 4x2x 4x4x 4x6x 4x8x 4xax 4xcx 4xex + FDC2 0 1 0 0 0 1 x 401x 403x 405x 407x 409x 40bx 40dx 40fx + 411x 413x 415x 417x 419x 41bx 41dx 41fx + 421x 423x 425x 427x 429x 42bx 42dx 42fx + 431x 433x 435x 437x 439x 43bx 43dx 43fx + 481x 483x 485x 487x 489x 48bx 48dx 48fx + 491x 493x 495x 497x 499x 49bx 49dx 49fx + 4a1x 4a3x 4a5x 4a7x 4a9x 4abx 4adx 4afx + 4b1x 4b3x 4b5x 4b7x 4b9x 4bbx 4bdx 4bfx + RAM 0 1 1 x x x x 6xxx 7xxx + */ + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x08, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, &drv->drive_ram[0x0100], 0); + drivemem_set_func(cpud, 0x08, 0x10, drive_read_1541ram, drive_store_1541ram, drive_peek_1541ram, drv->drive_ram, 0); + drivemem_set_func(cpud, 0x10, 0x14, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); + drivemem_set_func(cpud, 0x14, 0x18, via2d_read, via2d_store, via2d_peek, NULL, 0); + drivemem_set_func(cpud, 0x18, 0x1c, via1d1541_read, via1d1541_store, via1d1541_peek, NULL, 0); + drivemem_set_func(cpud, 0x1c, 0x20, via2d_read, via2d_store, via2d_peek, NULL, 0); + drivemem_set_func(cpud, 0x20, 0x30, wd1770d_read, wd1770d_store, wd1770d_peek, NULL, 0); + /* FIXME: the following is very incorrect */ + if (drv->drive_ram4_enabled) { + drivemem_set_func(cpud, 0x40, 0x48, mos5710_read, mos5710_store, mos5710_peek, NULL, 0); + drivemem_set_func(cpud, 0x48, 0x60, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x4000], 0); + } else { + drivemem_set_func(cpud, 0x40, 0x60, mos5710_read, mos5710_store, mos5710_peek, NULL, 0); + } + if (drv->drive_ram6_enabled) { + drivemem_set_func(cpud, 0x60, 0x80, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x6000], 0); + } else { + drivemem_set_func(cpud, 0x60, 0x80, mos5710_read, mos5710_store, mos5710_peek, NULL, 0); + } + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, drive_peek_rom, drv->trap_rom, 0); break; + /* FIXME: check open-i/o behaviour for 1581/65C02, see bug #2113 */ case DRIVE_TYPE_1581: - drv->cpu->pageone = drv->drive->drive_ram + 0x100; - drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive->drive_ram, 0x00001ffd); - drivemem_set_func(cpud, 0x01, 0x20, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x0100], 0x00001ffd); + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x20, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x0100], 0x00001ffd); drivemem_set_func(cpud, 0x40, 0x60, cia1581_read, cia1581_store, cia1581_peek, NULL, 0); drivemem_set_func(cpud, 0x60, 0x80, wd1770d_read, wd1770d_store, wd1770d_peek, NULL, 0); - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000fffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, drive_peek_rom, drv->trap_rom, 0x8000fffd); break; + /* FIXME: check open-i/o behaviour for FD/65C02, see bug #2113 */ case DRIVE_TYPE_2000: case DRIVE_TYPE_4000: - drv->cpu->pageone = drv->drive->drive_ram + 0x100; - drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive->drive_ram, 0x00003ffd); - drivemem_set_func(cpud, 0x01, 0x40, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x0100], 0x00003ffd); + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x40, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x0100], 0x00003ffd); drivemem_set_func(cpud, 0x40, 0x4c, via4000_read, via4000_store, via4000_peek, NULL, 0); drivemem_set_func(cpud, 0x4e, 0x50, pc8477d_read, pc8477d_store, pc8477d_peek, NULL, 0); - drivemem_set_func(cpud, 0x50, 0x80, drive_read_ram, drive_store_ram, NULL, &drv->drive->drive_ram[0x5000], 0x50007ffd); - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000fffd); + drivemem_set_func(cpud, 0x50, 0x80, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x5000], 0x50007ffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, drive_peek_rom, drv->trap_rom, 0x8000fffd); /* for performance reasons it's only this page */ - drivemem_set_func(cpud, 0xf0, 0xf1, drive_read_rom_ds1216, NULL, NULL, &drv->drive->trap_rom[0x7000], 0x8000fffd); + drivemem_set_func(cpud, 0xf0, 0xf1, drive_read_rom_ds1216, NULL, drive_peek_rom_ds1216, &drv->trap_rom[0x7000], 0x8000fffd); break; + /* FIXME: check open-i/o behaviour for CMDHD/65C02, see bug #2113 */ + case DRIVE_TYPE_CMDHD: + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, drive_peek_zero, NULL, 0); + drivemem_set_func(cpud, 0x01, 0x40, drive_read_ram, drive_store_ram, drive_peek_ram, &drv->drive_ram[0x0100], 0x00003ffd); + /* CMDHD uses a lot of weird registers to mamage the memory above 0x4000 + so the granularity here doesn't work. We just group it all together */ + drivemem_set_func(cpud, 0x40, 0x100, cmdhd_read, cmdhd_store, NULL, NULL, 0x0000fffd); default: return; } @@ -194,7 +297,7 @@ void memiec_init(struct drive_context_s *drv, unsigned int type) /// c64d /// 1541 peek -uint8 c64d_peek_mem_drive_internal(drive_context_t *drv, uint16 addr) +uint8 c64d_peek_mem_drive_internal(diskunit_context_t *drv, uint16 addr) { //#define LOAD(a) (drv->cpud->read_func[(a) >> 8](drv, (WORD)(a))) //#define LOAD_ZERO(a) (drv->cpud->read_func[0](drv, (WORD)(a))) @@ -207,7 +310,7 @@ uint8 c64d_peek_mem_drive_internal(drive_context_t *drv, uint16 addr) if (addr < 0x0800) { - return drv->drive->drive_ram[addr & 0x7ff]; + return drv->drive_ram[addr & 0x7ff]; } if (addr >= 0x0800 && addr < 0x1800) @@ -227,13 +330,13 @@ uint8 c64d_peek_mem_drive_internal(drive_context_t *drv, uint16 addr) if (addr >= 0x8000) { - return drv->drive->rom[addr & 0x7fff]; //this marks cell read: drive_read_rom(drv, addr); + return drv->rom[addr & 0x7fff]; //this marks cell read: drive_read_rom(drv, addr); } return drive_peek_free(drv, addr); //drv->cpud->read_func[(addr) >> 8](drv, (WORD)addr); } -void c64d_peek_memory_drive_internal(drive_context_t *drv, BYTE *memoryBuffer, int addrStart, int addrEnd) +void c64d_peek_memory_drive_internal(diskunit_context_t *drv, BYTE *memoryBuffer, int addrStart, int addrEnd) { int addr; uint8 *bufPtr = memoryBuffer + addrStart; @@ -243,23 +346,23 @@ void c64d_peek_memory_drive_internal(drive_context_t *drv, BYTE *memoryBuffer, i } } -void c64d_copy_ram_memory_drive_internal(drive_context_t *drv, BYTE *memoryBuffer, int addrStart, int addrEnd) +void c64d_copy_ram_memory_drive_internal(diskunit_context_t *drv, BYTE *memoryBuffer, int addrStart, int addrEnd) { int addr; uint8 *bufPtr = memoryBuffer + addrStart; for (addr = addrStart; addr < addrEnd; addr++) { - *bufPtr++ = drv->drive->drive_ram[addr]; + *bufPtr++ = drv->drive_ram[addr]; } } -void c64d_peek_whole_map_drive_internal(drive_context_t *drv, uint8 *memoryBuffer) +void c64d_peek_whole_map_drive_internal(diskunit_context_t *drv, uint8 *memoryBuffer) { int addr; uint8 *bufPtr = memoryBuffer; for (addr = 0; addr < 0x0800; addr++) { - *bufPtr++ = drv->drive->drive_ram[addr]; + *bufPtr++ = drv->drive_ram[addr]; } // if (addr >= 0x0800 && addr < 0x1800) @@ -278,11 +381,11 @@ void c64d_peek_whole_map_drive_internal(drive_context_t *drv, uint8 *memoryBuffe } } -uint8 c64d_mem_ram_read_drive_internal(drive_context_t *drv, uint16 addr) +uint8 c64d_mem_ram_read_drive_internal(diskunit_context_t *drv, uint16 addr) { if (addr < 0x0800) { - return drv->drive->drive_ram[addr & 0x7ff]; + return drv->drive_ram[addr & 0x7ff]; } // if (addr >= 0x0800) // && addr < 0x1800) @@ -291,19 +394,19 @@ uint8 c64d_mem_ram_read_drive_internal(drive_context_t *drv, uint16 addr) } } -void c64d_copy_mem_ram_drive_internal(drive_context_t *drv, uint8 *memoryBuffer) +void c64d_copy_mem_ram_drive_internal(diskunit_context_t *drv, uint8 *memoryBuffer) { int addr; uint8 *bufPtr = memoryBuffer; for (addr = 0; addr < 0x0800; addr++) { - *bufPtr++ = drv->drive->drive_ram[addr]; + *bufPtr++ = drv->drive_ram[addr]; } } -void c64d_mem_ram_write_drive_internal(drive_context_t *drv, uint16 addr, uint8 value) +void c64d_mem_ram_write_drive_internal(diskunit_context_t *drv, uint16 addr, uint8 value) { - drv->drive->drive_ram[addr & 0x7ff] = value; + drv->drive_ram[addr & 0x7ff] = value; } diff --git a/src/Emulators/vice/drive/iec/memiec.h b/src/Emulators/vice/drive/iec/memiec.h index e5d8eafb..bccd5ac4 100644 --- a/src/Emulators/vice/drive/iec/memiec.h +++ b/src/Emulators/vice/drive/iec/memiec.h @@ -29,9 +29,9 @@ #include "SYS_Types.h" -struct drive_context_s; +struct diskunit_context_s; struct mem_ioreg_list_s; -extern void memiec_init(struct drive_context_s *drv, unsigned int type); +void memiec_init(struct diskunit_context_s *drv, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/iec/pc8477.c b/src/Emulators/vice/drive/iec/pc8477.c index a0672c1c..55d92f25 100644 --- a/src/Emulators/vice/drive/iec/pc8477.c +++ b/src/Emulators/vice/drive/iec/pc8477.c @@ -26,9 +26,9 @@ #include "vice.h" +#include #include -#include "clkguard.h" #include "diskimage.h" #include "drive.h" #include "drivetypes.h" @@ -39,6 +39,9 @@ #include "alarm.h" #include "drivesync.h" #include "fdd.h" +#include "monitor.h" + +/* #define PC8477_DEBUG */ #ifdef PC8477_DEBUG #define debug(_x_) log_message _x_ @@ -46,8 +49,8 @@ #define debug(_x_) #endif -#define STEP_RATE ((16 - drv->step_rate) * drv->mycontext->drive->clock_frequency * 500000 / drv->rate) -#define BYTE_RATE (drv->mycontext->drive->clock_frequency * 8000 / drv->rate) +#define STEP_RATE ((16 - drv->step_rate) * drv->mycontext->clock_frequency * 500000 / drv->rate) +#define BYTE_RATE (drv->mycontext->clock_frequency * 8000 / drv->rate) typedef enum pc8477_state_e { PC8477_WAIT, PC8477_COMMAND, PC8477_READ, PC8477_WRITE, PC8477_EXEC, PC8477_RESULT @@ -117,9 +120,9 @@ enum pc8477_flags_e { }; static const struct { - BYTE mask; + uint8_t mask; pc8477_cmd_t command; - BYTE len, rlen, flags; + uint8_t len, rlen, flags; } pc8477_commands[15] = { {0x1f, PC8477_CMD_READ_DATA, 9, 7, PC8477_FLAGS_DS | PC8477_FLAGS_HDS | PC8477_FLAGS_MOT}, {0xbf, PC8477_CMD_READ_ID, 2, 7, PC8477_FLAGS_DS | PC8477_FLAGS_HDS | PC8477_FLAGS_MOT}, @@ -143,7 +146,7 @@ struct pc8477_s { pc8477_cmd_t command; pc8477_state_t state; int int_step, sub_step; - struct drive_context_s *mycontext; + struct diskunit_context_s *mycontext; /* Floppy drives */ struct { @@ -167,25 +170,25 @@ struct pc8477_s { CLOCK clk, motor_clk; /* Registers */ - BYTE st[4]; - BYTE dor, tdr; + uint8_t st[4]; + uint8_t dor, tdr; int step_rate, motor_off_time, motor_on_time, nodma; int rate; int sector; /* sector register */ - int is8477; /* dp8473 or pc 8477 */ + int is8477; /* dp8473=0 or pc8477!=0 */ alarm_t *seek_alarm; int byte_count; int fifop, fifop2, fifo_size, fifo_fill; - BYTE fifo[16]; + uint8_t fifo[16]; int cmdp, cmd_size; - BYTE cmd[9]; + uint8_t cmd[9]; int resp, res_size; - BYTE res[10]; + uint8_t res[10]; }; -static log_t pc8477_log = LOG_ERR; +static log_t pc8477_log = LOG_DEFAULT; /*-----------------------------------------------------------------------*/ @@ -204,7 +207,11 @@ static void seek_alarm_handler(CLOCK offset, void *data) drv->fdds[i].seeking = 1; if (drv->fdds[i].recalibrating && drv->fdds[i].seek_pulses == 0 && !fdd_track0(drv->fdds[i].fdd)) { - drv->st[0] |= PC8477_ST0_EC; + /* CMD FD2000's mechanism also sets bit 5 and 6 on + recalibration timeout, it is hard coded in ROM to check for + $71 on result (@ $878a) and try again */ + /* The FD4000 uses 85 pulses, so this shouldn't timeout */ + drv->st[0] |= (PC8477_ST0_EC | 0x60); } break; } @@ -226,40 +233,25 @@ static void seek_alarm_handler(CLOCK offset, void *data) } } -/* Clock overflow handling. */ -static void clk_overflow_callback(CLOCK sub, void *data) -{ - pc8477_t *drv = (pc8477_t *)data; - - if (drv->clk > (CLOCK) 0) { - drv->clk -= sub; - } - if (drv->motor_clk > (CLOCK) 0) { - drv->motor_clk -= sub; - } -} - /* Functions using drive context. */ -void pc8477d_init(drive_context_t *drv) +void pc8477d_init(diskunit_context_t *drv) { char *name; - if (pc8477_log == LOG_ERR) { + if (pc8477_log == LOG_DEFAULT) { pc8477_log = log_open("PC8477"); } - clk_guard_add_callback(drv->cpu->clk_guard, clk_overflow_callback, drv->pc8477); - name = lib_msprintf("%sEXEC", drv->pc8477->myname); drv->pc8477->seek_alarm = alarm_new(drv->cpu->alarm_context, name, seek_alarm_handler, drv->pc8477); lib_free(name); } -void pc8477_setup_context(drive_context_t *drv) +void pc8477_setup_context(diskunit_context_t *drv) { int i; drv->pc8477 = lib_calloc(1, sizeof(pc8477_t)); - drv->pc8477->myname = lib_msprintf("PC8477_%d", drv->mynumber); + drv->pc8477->myname = lib_msprintf("PC8477_%u", drv->mynumber); for (i = 0; i < 4; i++) { drv->pc8477->fdds[i].num = i; drv->pc8477->fdds[i].fdd = NULL; @@ -268,7 +260,7 @@ void pc8477_setup_context(drive_context_t *drv) } drv->pc8477->fdds[0].motor_on = (pc8477_motor_on_callback_t)drivesync_set_4000; drv->pc8477->fdds[0].motor_on_data = (void *)drv; - drv->pc8477->fdds[1].fdd = fdd_init(1, drv->drive); + drv->pc8477->fdds[1].fdd = fdd_init(1, drv->drives[0]); drv->pc8477->fdds[1].motor_on = (pc8477_motor_on_callback_t)fdd_set_motor; drv->pc8477->fdds[1].motor_on_data = (void *)drv->pc8477->fdds[1].fdd; drv->pc8477->mycontext = drv; @@ -302,20 +294,25 @@ static void pc8477_result(pc8477_t *drv) case PC8477_CMD_SENSE_INTERRUPT: drv->res[0] = drv->st[0]; drv->res[1] = drv->current->track; + debug((pc8477_log, "RESULT: %02x %02x", drv->res[0], drv->res[1])); return; case PC8477_CMD_VERSION: drv->res[0] = 0x90; + debug((pc8477_log, "RESULT: %02x", drv->res[0])); return; case PC8477_CMD_NSC: drv->res[0] = 0x72; + debug((pc8477_log, "RESULT: %02x", drv->res[0])); return; case PC8477_CMD_SENSE_DRIVE_STATUS: drv->res[0] = drv->st[3] | 0x20 | (drv->is8477 ? 0x08 : 0) | (fdd_track0(drv->fdd) ? PC8477_ST3_TK0 : 0) | (fdd_write_protect(drv->fdd) ? PC8477_ST3_WP : 0); + debug((pc8477_log, "RESULT: %02x", drv->res[0])); return; case PC8477_CMD_READ_ID: memcpy(drv->res, drv->st, 3); + debug((pc8477_log, "RESULT: %02x %02x %02x %02x %02x %02x", drv->res[0], drv->res[1], drv->res[2], drv->res[3], drv->res[4], drv->res[5])); return; case PC8477_CMD_RECALIBRATE: return; @@ -333,25 +330,29 @@ static void pc8477_result(pc8477_t *drv) drv->res[7] |= (drv->fdds[1].perpendicular ? 0x04 : 0); drv->res[7] |= (drv->fdds[2].perpendicular ? 0x08 : 0); drv->res[7] |= (drv->fdds[3].perpendicular ? 0x10 : 0); + debug((pc8477_log, "RESULT: %02x %02x %02x %02x %02x %02x %02x", drv->res[0], drv->res[1], drv->res[2], drv->res[3], drv->res[4], drv->res[5], drv->res[6])); /* TODO */ return; case PC8477_CMD_SET_TRACK: drv->res[0] = drv->current->track >> ((drv->cmd[1] & 4) ? 8 : 0); + debug((pc8477_log, "RESULT: %02x", drv->res[0])); return; case PC8477_CMD_READ_DATA: case PC8477_CMD_WRITE_DATA: case PC8477_CMD_FORMAT_A_TRACK: memcpy(drv->res, drv->st, 3); memcpy(drv->res + 3, drv->cmd + 2, 4); + debug((pc8477_log, "RESULT: %02x %02x %02x %02x %02x %02x", drv->res[0], drv->res[1], drv->res[2], drv->res[3], drv->res[4], drv->res[5])); return; default: drv->res[0] = drv->st[0]; + debug((pc8477_log, "RESULT: %02x", drv->res[0])); } } static int pc8477_micro_find_sync(pc8477_t *drv) { - WORD w; + uint16_t w; while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { if (fdd_index_count(drv->fdd) > 1) { @@ -389,11 +390,11 @@ static int pc8477_micro_find_sync(pc8477_t *drv) static int pc8477_micro_readid(pc8477_t *drv) { - BYTE b; + uint8_t b; while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { drv->clk += BYTE_RATE; - b = (BYTE)fdd_read(drv->fdd); + b = (uint8_t)fdd_read(drv->fdd); switch (drv->sub_step) { case 0: /* track */ drv->res[3] = b; @@ -467,6 +468,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->st[1] |= PC8477_ST1_MA; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 1: while (*drv->mycontext->clk_ptr >= drv->clk + BYTE_RATE) { res = pc8477_micro_find_sync(drv); @@ -483,6 +485,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) } drv->sub_step = 0; drv->int_step++; + /* fall through */ case 2: res = pc8477_micro_readid(drv); if (res > 0) { @@ -496,7 +499,8 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) return PC8477_EXEC; case PC8477_CMD_RECALIBRATE: debug((pc8477_log, "RECALIBRATE #%d", drv->current->num)); - drv->current->seek_pulses = drv->is8477 ? -77 : -85; + /* the pc8477 returns -85, the dp8473 returns -77 */ + drv->current->seek_pulses = drv->is8477 ? -85 : -77; drv->current->track = 0; drv->current->recalibrating = 1; if (!drv->seeking_active) { @@ -553,6 +557,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->st[1] |= PC8477_ST1_MA; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 1: res = pc8477_micro_find_sync(drv); if (res < 0) { @@ -566,6 +571,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->st[1] |= PC8477_ST1_ND; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 2: res = pc8477_micro_readid(drv); if (res > 0) { @@ -594,6 +600,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->byte_count = 128 << drv->res[6]; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 3: res = pc8477_micro_find_sync(drv); if (res < 0) { @@ -618,7 +625,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) break; case 4: drv->clk += BYTE_RATE; - drv->fifo[drv->fifop2] = (BYTE)fdd_read(drv->fdd); + drv->fifo[drv->fifop2] = (uint8_t)fdd_read(drv->fdd); drv->fifop2++; if (drv->fifop2 >= drv->fifo_size) { drv->fifop2 = 0; @@ -636,6 +643,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) break; } drv->int_step++; + /* fall through */ case 5: if (drv->fifo_fill) { drv->clk += fdd_rotate(drv->fdd, (*drv->mycontext->clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; @@ -663,6 +671,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->sector = drv->cmd[4]; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 1: res = pc8477_micro_find_sync(drv); if (res < 0) { @@ -676,6 +685,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->st[1] |= PC8477_ST1_ND; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 2: res = pc8477_micro_readid(drv); if (res > 0) { @@ -709,6 +719,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->byte_count = 128 << drv->res[6]; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 3: res = pc8477_micro_find_sync(drv); if (res < 0) { @@ -745,6 +756,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) break; } drv->int_step++; + /* fall through */ case 5: if (drv->cmd[6] != drv->sector) { drv->sector++; @@ -767,6 +779,7 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) drv->sector = 0; drv->sub_step = 0; drv->int_step++; + /* fall through */ case 1: drv->clk += BYTE_RATE; fdd_read(drv->fdd); @@ -958,14 +971,14 @@ static pc8477_state_t pc8477_execute(pc8477_t *drv) default: break; } - debug((pc8477_log, "invalid command %02x", drv->cmd[0])); + debug((pc8477_log, "invalid command %02x", drv->command)); drv->command = PC8477_CMD_INVALID; drv->st[0] = drv->st[3] | 0x80; /* invalid command */ drv->res_size = 1; return PC8477_RESULT; } -static void pc8477_store(pc8477_t *drv, WORD addr, BYTE byte) +static void pc8477_store(pc8477_t *drv, uint16_t addr, uint8_t byte) { int i; @@ -1010,7 +1023,7 @@ static void pc8477_store(pc8477_t *drv, WORD addr, BYTE byte) drv->res_size = pc8477_commands[i].rlen; drv->state = PC8477_COMMAND; drv->cmd_flags = pc8477_commands[i].flags; - /* fall through */ + /* fall through */ case PC8477_COMMAND: if (drv->cmdp < drv->cmd_size) { drv->cmd[drv->cmdp++] = byte; @@ -1071,9 +1084,9 @@ static void pc8477_store(pc8477_t *drv, WORD addr, BYTE byte) } } -static BYTE pc8477_read(pc8477_t *drv, WORD addr) +static uint8_t pc8477_read(pc8477_t *drv, uint16_t addr) { - BYTE result = 0; + uint8_t result = 0; if (drv->state == PC8477_EXEC || drv->state == PC8477_READ || drv->state == PC8477_WRITE) { drv->state = pc8477_execute(drv); @@ -1155,9 +1168,9 @@ static BYTE pc8477_read(pc8477_t *drv, WORD addr) } /* read from I/O without side effects */ -static BYTE pc8477_peek(pc8477_t *drv, WORD addr) +static uint8_t pc8477_peek(pc8477_t *drv, uint16_t addr) { - BYTE result = 0; + uint8_t result = 0; switch (addr) { case 2: @@ -1219,6 +1232,19 @@ static BYTE pc8477_peek(pc8477_t *drv, WORD addr) return result; } +void pc8477d_dump(diskunit_context_t *ctx) +{ + int i; + pc8477_t *drv = ctx->pc8477; + mon_out("Type: %s\n", drv->is8477 ? "pc8477" : "dp8473"); + mon_out("Rate: %dkHz\n", drv->rate); + for (i = 0; i < 4; i++) { + mon_out("FDD #%d:\n", i); + mon_out(" Track:%d (seeking:%s)\n", drv->fdds[i].track, drv->fdds[i].seeking ? "yes" : "no"); + mon_out(" Motor:%s\n", drv->fdds[i].motor_on_out ? "on" : "off"); + } +} + void pc8477_reset(pc8477_t *drv, int is8477) { int i; @@ -1248,26 +1274,27 @@ int pc8477_irq(pc8477_t *drv) return drv->irq; } -void pc8477d_store(drive_context_t *drv, WORD addr, BYTE byte) +void pc8477d_store(diskunit_context_t *drv, uint16_t addr, uint8_t byte) { - pc8477_store(drv->pc8477, (WORD)(addr & 7), byte); + drv->cpu->cpu_last_data = byte; + pc8477_store(drv->pc8477, (uint16_t)(addr & 7), byte); } -BYTE pc8477d_read(drive_context_t *drv, WORD addr) +uint8_t pc8477d_read(diskunit_context_t *drv, uint16_t addr) { - return pc8477_read(drv->pc8477, (WORD)(addr & 7)); + return drv->cpu->cpu_last_data = pc8477_read(drv->pc8477, (uint16_t)(addr & 7)); } -BYTE pc8477d_peek(drive_context_t *drv, WORD addr) +uint8_t pc8477d_peek(diskunit_context_t *drv, uint16_t addr) { - return pc8477_peek(drv->pc8477, (WORD)(addr & 7)); + return pc8477_peek(drv->pc8477, (uint16_t)(addr & 7)); } /*-----------------------------------------------------------------------*/ int pc8477_attach_image(disk_image_t *image, unsigned int unit) { - if (unit < 8 || unit > 8 + DRIVE_NUM) { + if (unit < 8 || unit > 8 + NUM_DISK_UNITS) { return -1; } @@ -1276,19 +1303,19 @@ int pc8477_attach_image(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: - disk_image_attach_log(image, pc8477_log, unit); + disk_image_attach_log(image, pc8477_log, unit, 0); break; default: return -1; } - fdd_image_attach(drive_context[unit - 8]->pc8477->fdds[1].fdd, image); + fdd_image_attach(diskunit_context[unit - 8]->pc8477->fdds[1].fdd, image); return 0; } int pc8477_detach_image(disk_image_t *image, unsigned int unit) { - if (image == NULL || unit < 8 || unit > 8 + DRIVE_NUM) { + if (image == NULL || unit < 8 || unit > 8 + NUM_DISK_UNITS) { return -1; } @@ -1297,12 +1324,12 @@ int pc8477_detach_image(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_D1M: case DISK_IMAGE_TYPE_D2M: case DISK_IMAGE_TYPE_D4M: - disk_image_detach_log(image, pc8477_log, unit); + disk_image_detach_log(image, pc8477_log, unit, 0); break; default: return -1; } - fdd_image_detach(drive_context[unit - 8]->pc8477->fdds[1].fdd); + fdd_image_detach(diskunit_context[unit - 8]->pc8477->fdds[1].fdd); return 0; } diff --git a/src/Emulators/vice/drive/iec/pc8477.h b/src/Emulators/vice/drive/iec/pc8477.h index 1b60fe61..fa8ebc4c 100644 --- a/src/Emulators/vice/drive/iec/pc8477.h +++ b/src/Emulators/vice/drive/iec/pc8477.h @@ -30,22 +30,24 @@ #include "vicetypes.h" struct disk_image_s; -struct drive_context_s; +struct diskunit_context_s; typedef void (*pc8477_motor_on_callback_t)(void *data, int signal); typedef struct pc8477_s pc8477_t; /* FIXME: whats the deal with the different prefixes? */ -extern void pc8477d_init(struct drive_context_s *drv); -extern void pc8477_shutdown(pc8477_t *drv); - -extern void pc8477_setup_context(struct drive_context_s *drv); -extern void pc8477d_store(struct drive_context_s *drv, WORD addr, BYTE byte); -extern BYTE pc8477d_read(struct drive_context_s *drv, WORD addr); -extern BYTE pc8477d_peek(struct drive_context_s *drv, WORD addr); -extern void pc8477_reset(pc8477_t *drv, int is8477); -extern int pc8477_irq(pc8477_t *drv); - -extern int pc8477_attach_image(struct disk_image_s *image, unsigned int unit); -extern int pc8477_detach_image(struct disk_image_s *image, unsigned int unit); +void pc8477d_init(struct diskunit_context_s *drv); +void pc8477_shutdown(pc8477_t *drv); + +void pc8477_setup_context(struct diskunit_context_s *drv); +void pc8477d_store(struct diskunit_context_s *drv, uint16_t addr, uint8_t byte); +uint8_t pc8477d_read(struct diskunit_context_s *drv, uint16_t addr); +uint8_t pc8477d_peek(struct diskunit_context_s *drv, uint16_t addr); +void pc8477d_dump(struct diskunit_context_s *drv); + +void pc8477_reset(pc8477_t *drv, int is8477); +int pc8477_irq(pc8477_t *drv); + +int pc8477_attach_image(struct disk_image_s *image, unsigned int unit); +int pc8477_detach_image(struct disk_image_s *image, unsigned int unit); #endif diff --git a/src/Emulators/vice/drive/iec/via1d1541.c b/src/Emulators/vice/drive/iec/via1d1541.c index 0df770cb..c8962f73 100644 --- a/src/Emulators/vice/drive/iec/via1d1541.c +++ b/src/Emulators/vice/drive/iec/via1d1541.c @@ -47,40 +47,43 @@ #include "viad.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" #define iecbus (via1p->v_iecbus) typedef struct drivevia1_context_s { unsigned int number; - struct drive_s *drive; + struct drive_s *drive; /* TODO: remove when no longer needed */ + struct diskunit_context_s *diskunit; int parallel_id; int v_parieee_is_out; /* init to 1 */ struct iecbus_s *v_iecbus; } drivevia1_context_t; -void via1d1541_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void via1d1541_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { - c64d_mark_drive1541_cell_write(addr, data); + VICE_HOOK_DRIVE_CELL_WRITE(addr, data); + ctxptr->cpu->cpu_last_data = data; viacore_store(ctxptr->via1d1541, addr, data); } -BYTE via1d1541_read(drive_context_t *ctxptr, WORD addr) +uint8_t via1d1541_read(diskunit_context_t *ctxptr, uint16_t addr) { - c64d_mark_drive1541_cell_read(addr); - - return viacore_read(ctxptr->via1d1541, addr); + VICE_HOOK_DRIVE_CELL_READ(addr); + + return ctxptr->cpu->cpu_last_data = viacore_read(ctxptr->via1d1541, addr); } -BYTE via1d1541_peek(drive_context_t *ctxptr, WORD addr) +uint8_t via1d1541_peek(diskunit_context_t *ctxptr, uint16_t addr) { return viacore_peek(ctxptr->via1d1541, addr); } -int via1d1541_dump(drive_context_t *ctxptr, WORD addr) +int via1d1541_dump(diskunit_context_t *ctxptr, uint16_t addr) { - viacore_dump(((drive_context_t*)ctxptr)->via1d1541); + viacore_dump(((diskunit_context_t*)ctxptr)->via1d1541); return 0; } @@ -88,56 +91,57 @@ static void set_ca2(via_context_t *via_context, int state) { } -static void set_cb2(via_context_t *via_context, int state) +static void set_cb2(via_context_t *via_context, int state, int offset) { } static void set_int(via_context_t *via_context, unsigned int int_num, int value, CLOCK rclk) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *) via_context->context; - if (c64d_is_debug_on_drive1541()) + if (VICE_HOOK_DRIVE_IS_DEBUG()) { - via_context->c64d_irq_flagged = 1; + VICE_HOOK_VIA_IRQ_FLAG_SET(via_context); } - - interrupt_set_irq(drive_context->cpu->int_status, int_num, value, rclk); + + interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk); } static void restore_int(via_context_t *via_context, unsigned int int_num, int value) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *) via_context->context; - interrupt_restore_irq(drive_context->cpu->int_status, int_num, value); + interrupt_restore_irq(dc->cpu->int_status, int_num, value); } -static void undump_pra(via_context_t *via_context, BYTE byte) +static void undump_pra(via_context_t *via_context, uint8_t byte) { drivevia1_context_t *via1p; - drive_context_t *drive_context; + diskunit_context_t *dc; via1p = (drivevia1_context_t *)(via_context->prv); - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *) via_context->context; - if (via1p->drive->type == DRIVE_TYPE_1570 - || via1p->drive->type == DRIVE_TYPE_1571 - || via1p->drive->type == DRIVE_TYPE_1571CR) { - drivesync_set_1571(byte & 0x20, drive_context); + if (dc->type == DRIVE_TYPE_1570 + || dc->type == DRIVE_TYPE_1571 + || dc->type == DRIVE_TYPE_1571CR) { + drivesync_set_1571(dc, byte & 0x20); glue1571_side_set((byte >> 2) & 1, via1p->drive); } else { - switch (via1p->drive->parallel_cable) { + switch (via1p->diskunit->parallel_cable) { case DRIVE_PC_STANDARD: + case DRIVE_PC_21SEC_BACKUP: case DRIVE_PC_FORMEL64: - if (via1p->drive->type == DRIVE_TYPE_1540 - || via1p->drive->type == DRIVE_TYPE_1541 - || via1p->drive->type == DRIVE_TYPE_1541II) { - parallel_cable_drive_write(via1p->drive->parallel_cable, byte, + if (dc->type == DRIVE_TYPE_1540 + || dc->type == DRIVE_TYPE_1541 + || dc->type == DRIVE_TYPE_1541II) { + parallel_cable_drive_write(dc->parallel_cable, byte, PARALLEL_WRITE, via1p->number); } break; @@ -145,20 +149,21 @@ static void undump_pra(via_context_t *via_context, BYTE byte) } } -static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa_value, - WORD addr) +static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t oldpa_value, + uint16_t addr) { drivevia1_context_t *via1p; - drive_context_t *drive_context; + diskunit_context_t *dc; via1p = (drivevia1_context_t *)(via_context->prv); - drive_context = (drive_context_t *)(via_context->context); + /* dc = (diskunit_context_t *)(via_context->context); */ + dc = via1p->diskunit; - if (via1p->drive->type == DRIVE_TYPE_1570 - || via1p->drive->type == DRIVE_TYPE_1571 - || via1p->drive->type == DRIVE_TYPE_1571CR) { + if (dc->type == DRIVE_TYPE_1570 + || dc->type == DRIVE_TYPE_1571 + || dc->type == DRIVE_TYPE_1571CR) { if ((oldpa_value ^ byte) & 0x20) { - drivesync_set_1571(byte & 0x20, drive_context); + drivesync_set_1571(dc, byte & 0x20); } if ((oldpa_value ^ byte) & 0x04) { glue1571_side_set((byte >> 2) & 1, via1p->drive); @@ -167,13 +172,14 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa_value, iec_fast_drive_direction(byte & 2, via1p->number); } } else { - switch (via1p->drive->parallel_cable) { + switch (dc->parallel_cable) { case DRIVE_PC_STANDARD: + case DRIVE_PC_21SEC_BACKUP: case DRIVE_PC_FORMEL64: - if (via1p->drive->type == DRIVE_TYPE_1540 - || via1p->drive->type == DRIVE_TYPE_1541 - || via1p->drive->type == DRIVE_TYPE_1541II) { - parallel_cable_drive_write(via1p->drive->parallel_cable, byte, + if (dc->type == DRIVE_TYPE_1540 + || dc->type == DRIVE_TYPE_1541 + || dc->type == DRIVE_TYPE_1541II) { + parallel_cable_drive_write(dc->parallel_cable, byte, (((addr == VIA_PRA) && ((via_context->via[VIA_PCR] & 0xe) == 0xa)) ? PARALLEL_WRITE_HS : PARALLEL_WRITE), via1p->number); @@ -183,14 +189,14 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa_value, } } -static void undump_prb(via_context_t *via_context, BYTE byte) +static void undump_prb(via_context_t *via_context, uint8_t byte) { drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); if (iecbus != NULL) { - BYTE *drive_bus, *drive_data; + uint8_t *drive_bus, *drive_data; unsigned int unit; drive_bus = &(iecbus->drv_bus[via1p->number + 8]); @@ -202,7 +208,7 @@ static void undump_prb(via_context_t *via_context, BYTE byte) & ((~(*drive_data) ^ iecbus->cpu_bus) << 3) & 0x80)); iecbus->cpu_port = iecbus->cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { iecbus->cpu_port &= iecbus->drv_bus[unit]; } @@ -210,12 +216,12 @@ static void undump_prb(via_context_t *via_context, BYTE byte) | (iecbus->cpu_port >> 7) | ((iecbus->cpu_bus << 3) & 0x80)); } else { - iec_drive_write((BYTE)(~byte), via1p->number); + iec_drive_write((uint8_t)(~byte), via1p->number); } } -static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, - WORD addr) +static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb, + uint16_t addr) { drivevia1_context_t *via1p; @@ -225,7 +231,7 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, DEBUG_IEC_DRV_WRITE(byte); if (iecbus != NULL) { - BYTE *drive_data, *drive_bus; + uint8_t *drive_data, *drive_bus; unsigned int unit; drive_bus = &(iecbus->drv_bus[via1p->number + 8]); @@ -234,10 +240,10 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, *drive_data = ~byte; *drive_bus = ((((*drive_data) << 3) & 0x40) | (((*drive_data) << 6) - & ((~(*drive_data) ^ iecbus->cpu_bus) << 3) & 0x80)); + & ((uint32_t)(~(*drive_data) ^ iecbus->cpu_bus) << 3) & 0x80)); iecbus->cpu_port = iecbus->cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { iecbus->cpu_port &= iecbus->drv_bus[unit]; } @@ -247,13 +253,13 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, DEBUG_IEC_BUS_WRITE(iecbus->drv_port); } else { - iec_drive_write((BYTE)(~byte), via1p->number); + iec_drive_write((uint8_t)(~byte), via1p->number); DEBUG_IEC_BUS_WRITE(~byte); } } } -static void undump_pcr(via_context_t *via_context, BYTE byte) +static void undump_pcr(via_context_t *via_context, uint8_t byte) { #if 0 drivevia1_context_t *via1p; @@ -267,24 +273,24 @@ static void undump_pcr(via_context_t *via_context, BYTE byte) #endif } -static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) +static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr) { return byte; } -static void undump_acr(via_context_t *via_context, BYTE byte) +static void undump_acr(via_context_t *via_context, uint8_t byte) { } -static void store_acr(via_context_t *via_context, BYTE byte) +static void store_acr(via_context_t *via_context, uint8_t byte) { } -static void store_sr(via_context_t *via_context, BYTE byte) +static void store_sr(via_context_t *via_context, uint8_t byte) { } -static void store_t2l(via_context_t *via_context, BYTE byte) +static void store_t2l(via_context_t *via_context, uint8_t byte) { } @@ -292,17 +298,17 @@ static void reset(via_context_t *via_context) { } -static BYTE read_pra(via_context_t *via_context, WORD addr) +static uint8_t read_pra(via_context_t *via_context, uint16_t addr) { - BYTE byte; + uint8_t byte; drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); - if (via1p->drive->type == DRIVE_TYPE_1570 - || via1p->drive->type == DRIVE_TYPE_1571 - || via1p->drive->type == DRIVE_TYPE_1571CR) { - BYTE tmp; + if (via1p->diskunit->type == DRIVE_TYPE_1570 + || via1p->diskunit->type == DRIVE_TYPE_1571 + || via1p->diskunit->type == DRIVE_TYPE_1571CR) { + uint8_t tmp; rotation_rotate_disk(via1p->drive); tmp = (via1p->drive->byte_ready_level ? 0 : 0x80) | (via1p->drive->current_half_track == 2 ? 0 : 1); @@ -310,10 +316,11 @@ static BYTE read_pra(via_context_t *via_context, WORD addr) | (via_context->via[VIA_PRA] & via_context->via[VIA_DDRA]); } - switch (via1p->drive->parallel_cable) { + switch (via1p->diskunit->parallel_cable) { case DRIVE_PC_STANDARD: + case DRIVE_PC_21SEC_BACKUP: case DRIVE_PC_FORMEL64: - byte = parallel_cable_drive_read(via1p->drive->parallel_cable, + byte = parallel_cable_drive_read(via1p->diskunit->parallel_cable, (((addr == VIA_PRA) && (via_context->via[VIA_PCR] & 0xe) == 0xa)) ? 1 : 0); break; default: @@ -328,7 +335,7 @@ static BYTE read_pra(via_context_t *via_context, WORD addr) BYTE c64d_peek_via1d1541_pra(via_context_t *via_context); BYTE c64d_peek_via1d1541_prb(via_context_t *via_context); -BYTE c64d_via1d1541_peek(drive_context_t *ctxptr, WORD addr) +BYTE c64d_via1d1541_peek(diskunit_context_t *ctxptr, WORD addr) { WORD addr_via = addr & 0x0f; @@ -345,8 +352,7 @@ BYTE c64d_via1d1541_peek(drive_context_t *ctxptr, WORD addr) if (via_context->via[VIA_ACR] & 0x80) { - byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x) - | via_context->pb7o) ? 0x80 : 0); + byte = (byte & 0x7f) | via_context->t1_pb7; /* VICE 3.10: pb7/pb7x/pb7o -> t1_pb7 */ } return byte; @@ -363,9 +369,9 @@ BYTE c64d_peek_via1d1541_pra(via_context_t *via_context) via1p = (drivevia1_context_t *)(via_context->prv); - if (via1p->drive->type == DRIVE_TYPE_1570 - || via1p->drive->type == DRIVE_TYPE_1571 - || via1p->drive->type == DRIVE_TYPE_1571CR) + if (via1p->diskunit->type == DRIVE_TYPE_1570 + || via1p->diskunit->type == DRIVE_TYPE_1571 + || via1p->diskunit->type == DRIVE_TYPE_1571CR) { BYTE tmp; tmp = (via1p->drive->byte_ready_level ? 0 : 0x80) | (via1p->drive->current_half_track == 2 ? 0 : 1); @@ -391,10 +397,10 @@ BYTE c64d_peek_via1d1541_pra(via_context_t *via_context) } -static BYTE read_prb(via_context_t *via_context) +static uint8_t read_prb(via_context_t *via_context) { - BYTE byte; - BYTE orval; + uint8_t byte; + uint8_t orval; drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); @@ -442,13 +448,13 @@ BYTE c64d_peek_via1d1541_prb(via_context_t *via_context) return byte; } -void via1d1541_init(drive_context_t *ctxptr) +void via1d1541_init(diskunit_context_t *ctxptr) { viacore_init(ctxptr->via1d1541, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void via1d1541_setup_context(drive_context_t *ctxptr) +void via1d1541_setup_context(diskunit_context_t *ctxptr) { drivevia1_context_t *via1p; via_context_t *via; @@ -466,17 +472,19 @@ void via1d1541_setup_context(drive_context_t *ctxptr) via->rmw_flag = &(ctxptr->cpu->rmw_flag); via->clk_ptr = ctxptr->clk_ptr; - via->myname = lib_msprintf("1541Drive%dVia1", ctxptr->mynumber); - via->my_module_name = lib_msprintf("1541VIA1D%d", ctxptr->mynumber); + via->myname = lib_msprintf("1541Drive%uVia1", ctxptr->mynumber); + via->my_module_name = lib_msprintf("1541VIA1D%u", ctxptr->mynumber); viacore_setup_context(via); - via->my_module_name_alt1 = lib_msprintf("VIA1D%d", ctxptr->mynumber); + via->my_module_name_alt1 = lib_msprintf("VIA1D%u", ctxptr->mynumber); via->my_module_name_alt2 = lib_msprintf("VIA1D1541"); via->irq_line = IK_IRQ; - via1p->drive = ctxptr->drive; + via1p->drive = ctxptr->drives[0]; + via1p->diskunit = ctxptr; + iecbus = iecbus_drive_port(); via->undump_pra = undump_pra; diff --git a/src/Emulators/vice/drive/iec/via1d1541.h b/src/Emulators/vice/drive/iec/via1d1541.h index 2a6b2cb8..04fb2d4c 100644 --- a/src/Emulators/vice/drive/iec/via1d1541.h +++ b/src/Emulators/vice/drive/iec/via1d1541.h @@ -30,16 +30,19 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct via_context_s; -extern void via1d1541_setup_context(struct drive_context_s *ctxptr); -extern void via1d1541_init(struct drive_context_s *ctxptr); +void via1d1541_setup_context(struct diskunit_context_s *ctxptr); +void via1d1541_init(struct diskunit_context_s *ctxptr); -extern void via1d1541_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE via1d1541_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE via1d1541_peek(struct drive_context_s *ctxptr, WORD addr); -extern int via1d1541_dump(drive_context_t *ctxptr, WORD addr); -extern BYTE c64d_via1d1541_peek(struct drive_context_s *ctxptr, WORD addr); +void via1d1541_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t via1d1541_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t via1d1541_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int via1d1541_dump(diskunit_context_t *ctxptr, uint16_t addr); + +#ifdef RETRODEBUGGER +uint8_t c64d_via1d1541_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +#endif #endif diff --git a/src/Emulators/vice/drive/iec/via4000.c b/src/Emulators/vice/drive/iec/via4000.c index 466cdb68..07b6b14a 100644 --- a/src/Emulators/vice/drive/iec/via4000.c +++ b/src/Emulators/vice/drive/iec/via4000.c @@ -59,22 +59,23 @@ typedef struct drivevia_context_s { } drivevia_context_t; -void via4000_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void via4000_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; viacore_store(ctxptr->via4000, addr, data); } -BYTE via4000_read(drive_context_t *ctxptr, WORD addr) +uint8_t via4000_read(diskunit_context_t *ctxptr, uint16_t addr) { - return viacore_read(ctxptr->via4000, addr); + return ctxptr->cpu->cpu_last_data = viacore_read(ctxptr->via4000, addr); } -BYTE via4000_peek(drive_context_t *ctxptr, WORD addr) +uint8_t via4000_peek(diskunit_context_t *ctxptr, uint16_t addr) { return viacore_peek(ctxptr->via4000, addr); } -int via4000_dump(drive_context_t *ctxptr, WORD addr) +int via4000_dump(diskunit_context_t *ctxptr, uint16_t addr) { viacore_dump(ctxptr->via4000); return 0; @@ -84,32 +85,32 @@ static void set_ca2(via_context_t *via_context, int state) { } -static void set_cb2(via_context_t *via_context, int state) +static void set_cb2(via_context_t *via_context, int state, int offset) { } static void set_int(via_context_t *via_context, unsigned int int_num, int value, CLOCK rclk) { - drive_context_t *drive_context = (drive_context_t *)(via_context->context); + diskunit_context_t *dc = (diskunit_context_t *)(via_context->context); - interrupt_set_irq(drive_context->cpu->int_status, int_num, value, rclk); + interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk); } static void restore_int(via_context_t *via_context, unsigned int int_num, int value) { - drive_context_t *drive_context = (drive_context_t *)(via_context->context); + diskunit_context_t *dc = (diskunit_context_t *)(via_context->context); - interrupt_restore_irq(drive_context->cpu->int_status, int_num, value); + interrupt_restore_irq(dc->cpu->int_status, int_num, value); } -static void undump_pra(via_context_t *via_context, BYTE byte) +static void undump_pra(via_context_t *via_context, uint8_t byte) { drivevia_context_t *viap = (drivevia_context_t *)(via_context->prv); if (iecbus != NULL) { - BYTE *drive_bus, *drive_data; + uint8_t *drive_bus, *drive_data; unsigned int unit; drive_bus = &(iecbus->drv_bus[viap->number + 8]); @@ -121,7 +122,7 @@ static void undump_pra(via_context_t *via_context, BYTE byte) & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80)); iecbus->cpu_port = iecbus->cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { iecbus->cpu_port &= iecbus->drv_bus[unit]; } @@ -129,12 +130,12 @@ static void undump_pra(via_context_t *via_context, BYTE byte) | (iecbus->cpu_port >> 7) | ((iecbus->cpu_bus << 3) & 0x80)); } else { - iec_drive_write((BYTE)(~byte), viap->number); + iec_drive_write((uint8_t)(~byte), viap->number); } } -static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa, - WORD addr) +static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t oldpa, + uint16_t addr) { drivevia_context_t *viap; @@ -144,7 +145,7 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa, DEBUG_IEC_DRV_WRITE(byte); if (iecbus != NULL) { - BYTE *drive_data, *drive_bus; + uint8_t *drive_data, *drive_bus; unsigned int unit; drive_bus = &(iecbus->drv_bus[viap->number + 8]); @@ -156,7 +157,7 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa, & (((*drive_data) | iecbus->cpu_bus) << 3) & 0x80)); iecbus->cpu_port = iecbus->cpu_bus; - for (unit = 4; unit < 8 + DRIVE_NUM; unit++) { + for (unit = 4; unit < 8 + NUM_DISK_UNITS; unit++) { iecbus->cpu_port &= iecbus->drv_bus[unit]; } @@ -166,7 +167,7 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa, DEBUG_IEC_BUS_WRITE(iecbus->drv_port); } else { - iec_drive_write((BYTE)(~byte), viap->number); + iec_drive_write((uint8_t)(~byte), viap->number); DEBUG_IEC_BUS_WRITE(~byte); } @@ -174,7 +175,7 @@ static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa, } } -static void undump_prb(via_context_t *via_context, BYTE byte) +static void undump_prb(via_context_t *via_context, uint8_t byte) { drivevia_context_t *viap; @@ -184,8 +185,8 @@ static void undump_prb(via_context_t *via_context, BYTE byte) viap->drive->led_status |= (byte & 0x20) ? 2 : 0; } -static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, - WORD addr) +static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb, + uint16_t addr) { drivevia_context_t *viap; @@ -195,33 +196,33 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, viap->drive->led_status |= (byte & 0x20) ? 2 : 0; } -static void undump_pcr(via_context_t *via_context, BYTE byte) +static void undump_pcr(via_context_t *via_context, uint8_t byte) { } -static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) +static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr) { return byte; } -static void undump_acr(via_context_t *via_context, BYTE byte) +static void undump_acr(via_context_t *via_context, uint8_t byte) { } -static void store_acr(via_context_t *via_context, BYTE byte) +static void store_acr(via_context_t *via_context, uint8_t byte) { } -static void store_sr(via_context_t *via_context, BYTE byte) +static void store_sr(via_context_t *via_context, uint8_t byte) { drivevia_context_t *viap; viap = (drivevia_context_t *)(via_context->prv); - iec_fast_drive_write((BYTE)(~byte), viap->number); + iec_fast_drive_write((uint8_t)(~byte), viap->number); } -static void store_t2l(via_context_t *via_context, BYTE byte) +static void store_t2l(via_context_t *via_context, uint8_t byte) { } @@ -229,9 +230,9 @@ static void reset(via_context_t *via_context) { } -static BYTE read_pra(via_context_t *via_context, WORD addr) +static uint8_t read_pra(via_context_t *via_context, uint16_t addr) { - BYTE byte; + uint8_t byte; drivevia_context_t *viap; viap = (drivevia_context_t *)(via_context->prv); @@ -251,27 +252,27 @@ static BYTE read_pra(via_context_t *via_context, WORD addr) return byte; } -static BYTE read_prb(via_context_t *via_context) +static uint8_t read_prb(via_context_t *via_context) { - BYTE byte; + uint8_t byte; drivevia_context_t *viap; - drive_context_t *drive; + diskunit_context_t *drive; viap = (drivevia_context_t *)(via_context->prv); - drive = (drive_context_t *)(via_context->context); + drive = (diskunit_context_t *)(via_context->context); byte = (viap->number << 3) | (pc8477_irq(drive->pc8477) ? 0x80 : 0); return byte; } -void via4000_init(drive_context_t *ctxptr) +void via4000_init(diskunit_context_t *ctxptr) { viacore_init(ctxptr->via4000, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void via4000_setup_context(drive_context_t *ctxptr) +void via4000_setup_context(diskunit_context_t *ctxptr) { drivevia_context_t *viap; via_context_t *via; @@ -289,17 +290,17 @@ void via4000_setup_context(drive_context_t *ctxptr) via->rmw_flag = &(ctxptr->cpu->rmw_flag); via->clk_ptr = ctxptr->clk_ptr; - via->myname = lib_msprintf("4000Drive%dVia1", ctxptr->mynumber); - via->my_module_name = lib_msprintf("4000VIA1D%d", ctxptr->mynumber); + via->myname = lib_msprintf("4000Drive%uVia1", ctxptr->mynumber); + via->my_module_name = lib_msprintf("4000VIA1D%u", ctxptr->mynumber); viacore_setup_context(via); - via->my_module_name_alt1 = lib_msprintf("VIA1D%d", ctxptr->mynumber); + via->my_module_name_alt1 = lib_msprintf("VIA1D%u", ctxptr->mynumber); via->my_module_name_alt2 = lib_msprintf("VIA4000"); via->irq_line = IK_IRQ; - viap->drive = ctxptr->drive; + viap->drive = ctxptr->drives[0]; iecbus = iecbus_drive_port(); via->undump_pra = undump_pra; diff --git a/src/Emulators/vice/drive/iec/via4000.h b/src/Emulators/vice/drive/iec/via4000.h index 8bc8dd9e..ac66c388 100644 --- a/src/Emulators/vice/drive/iec/via4000.h +++ b/src/Emulators/vice/drive/iec/via4000.h @@ -33,15 +33,15 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct via_context_s; -extern void via4000_setup_context(struct drive_context_s *ctxptr); -extern void via4000_init(struct drive_context_s *ctxptr); +void via4000_setup_context(struct diskunit_context_s *ctxptr); +void via4000_init(struct diskunit_context_s *ctxptr); -extern void via4000_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE via4000_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE via4000_peek(struct drive_context_s *ctxptr, WORD addr); -extern int via4000_dump(drive_context_t *ctxptr, WORD addr); +void via4000_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t via4000_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t via4000_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int via4000_dump(diskunit_context_t *ctxptr, uint16_t addr); #endif diff --git a/src/Emulators/vice/drive/iec/wd1770.c b/src/Emulators/vice/drive/iec/wd1770.c index 36a73d5b..0d8fd933 100644 --- a/src/Emulators/vice/drive/iec/wd1770.c +++ b/src/Emulators/vice/drive/iec/wd1770.c @@ -29,7 +29,6 @@ #include #include -#include "clkguard.h" #include "diskimage.h" #include "drive.h" #include "drivetypes.h" @@ -38,6 +37,7 @@ #include "wd1770.h" #include "fdd.h" #include "lib.h" +#include "monitor.h" #include "snapshot.h" /* FIXME: msvc sux at var arg defines */ @@ -56,6 +56,7 @@ static const int wd1770_step_rate[2][4] = { {6000, 12000, 2000, 3000}, /* WD1772 */ }; +/* Macros for wd1770_t *drv; */ #define SETTLING (drv->clock_frequency * 30000) #define BYTE_RATE (drv->clock_frequency * 8000 / 250) #define STEP_RATE (drv->clock_frequency * wd1770_step_rate[drv->is1772][drv->cmd & WD_R]) @@ -121,9 +122,9 @@ typedef enum wd_cmd_e { /* WD1770/1772 commands, masks, types */ static const struct { - BYTE mask; + uint8_t mask; wd_cmd_t command; - BYTE type; + uint8_t type; } wd_commands[11]={ {0xf0, WD_RESTORE , 1}, {0xf0, WD_SEEK , 1}, @@ -142,8 +143,8 @@ struct wd1770_s { char *myname; /* WD1770/1772 registers. */ - BYTE data, track, sector, status, cmd; - WORD crc; + uint8_t data, track, sector, status, cmd; + uint16_t crc; /* Command and type */ wd_cmd_t command; @@ -153,7 +154,7 @@ struct wd1770_s { fd_drive_t *fdd; int step; int byte_count; - int tmp; + unsigned int tmp; int direction; int clock_frequency; /* MHz of main CPU*/ @@ -165,37 +166,31 @@ struct wd1770_s { int is1772; }; -static log_t wd1770_log = LOG_ERR; +static log_t wd1770_log = LOG_DEFAULT; /*-----------------------------------------------------------------------*/ /* WD1770 external interface. */ -/* Clock overflow handling. */ -static void clk_overflow_callback(CLOCK sub, void *data) +/* Functions using disk unit context. */ +void wd1770d_init(diskunit_context_t *drv) { - wd1770_t *drv = (wd1770_t *)data; - - if (drv->clk > (CLOCK) 0) { - drv->clk -= sub; - } -} - -/* Functions using drive context. */ -void wd1770d_init(drive_context_t *drv) -{ - if (wd1770_log == LOG_ERR) { + if (wd1770_log == LOG_DEFAULT) { wd1770_log = log_open("WD1770"); } drv->wd1770 = lib_calloc(1, sizeof(wd1770_t)); - drv->wd1770->myname = lib_msprintf("WD1770%d", drv->mynumber); - drv->wd1770->fdd = fdd_init(4 * drv->mynumber, drv->drive); + drv->wd1770->myname = lib_msprintf("WD1770%u", drv->mynumber); + drv->wd1770->fdd = fdd_init(4 * drv->mynumber, drv->drives[0]); drv->wd1770->cpu_clk_ptr = drv->clk_ptr; drv->wd1770->is1772 = 0; drv->wd1770->clock_frequency = 2; - - clk_guard_add_callback(drv->cpu->clk_guard, clk_overflow_callback, - drv->wd1770); + /* + * Programming note: we should be able to get the clock_frequency from + * drv->clock_frequency. However we are called only once at the beginning, + * for any type of drive, and not when a drive of our type is actually + * connected. It just so happens that all drives with a wd177x have + * this clock frequency. + */ } void wd1770_shutdown(wd1770_t *drv) @@ -208,7 +203,7 @@ void wd1770_shutdown(wd1770_t *drv) /* Execute microcode */ static void wd1770_execute(wd1770_t *drv) { - int res; + unsigned int res; for (;; ) { switch (drv->type) { @@ -217,6 +212,7 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= fdd_index(drv->fdd) ? WD_IP : 0; drv->status |= fdd_track0(drv->fdd) ? WD_T0 : 0; drv->status |= fdd_write_protect(drv->fdd) ? WD_WP : 0; + /* fall through */ case 0: /* idle */ if (*drv->cpu_clk_ptr < drv->clk + PREPARE) { return; @@ -242,6 +238,7 @@ static void wd1770_execute(wd1770_t *drv) drv->status &= ~(WD_CRC | WD_SE | WD_DRQ); drv->irq = 0; drv->step++; + /* fall through */ case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; @@ -251,12 +248,14 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; + /* fall through */ case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; + /* fall through */ case 3: switch (drv->command) { case WD_STEP: @@ -270,6 +269,7 @@ static void wd1770_execute(wd1770_t *drv) case WD_RESTORE: drv->track = 0xff; drv->data = 0x00; + /* fall through */ default: drv->step++; continue; @@ -283,9 +283,11 @@ static void wd1770_execute(wd1770_t *drv) } drv->direction = (drv->data > drv->track); drv->step++; + /* fall through */ case 5: drv->track += drv->direction ? 1 : -1; drv->step++; + /* fall through */ case 6: if (fdd_track0(drv->fdd) && !drv->direction) { drv->track = 0; @@ -294,6 +296,7 @@ static void wd1770_execute(wd1770_t *drv) } fdd_seek_pulse(drv->fdd, drv->direction); drv->step++; + /* fall through */ case 7: if (*drv->cpu_clk_ptr < drv->clk + STEP_RATE) { return; @@ -304,12 +307,14 @@ static void wd1770_execute(wd1770_t *drv) continue; } drv->step++; + /* fall through */ case 8: if (!(drv->cmd & WD_V)) { drv->type = -1; break; } drv->step++; + /* fall through */ case 9: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; @@ -318,6 +323,7 @@ static void wd1770_execute(wd1770_t *drv) fdd_index_count_reset(drv->fdd); drv->sync = 0; drv->step++; + /* fall through */ case 10: if (fdd_index_count(drv->fdd) >= 6) { drv->status |= WD_SE; @@ -339,6 +345,7 @@ static void wd1770_execute(wd1770_t *drv) drv->crc = 0xb230; drv->byte_count = 6; drv->step++; + /* fall through */ case 11: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; @@ -349,7 +356,7 @@ static void wd1770_execute(wd1770_t *drv) drv->step--; continue; } - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); if (--drv->byte_count) { continue; } @@ -373,6 +380,7 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= WD_BSY; drv->status &= ~(WD_DRQ | WD_LD | WD_RNF | WD_RT | WD_WP); drv->step++; + /* fall through */ case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; @@ -382,24 +390,28 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; + /* fall through */ case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; + /* fall through */ case 3: if (!(drv->cmd & WD_E)) { drv->step += 2; continue; } drv->step++; + /* fall through */ case 4: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; } drv->clk += SETTLING; drv->step++; + /* fall through */ case 5: if (drv->command == WD_WRITE_SECTOR && fdd_write_protect(drv->fdd)) { drv->status |= WD_WP; @@ -409,6 +421,7 @@ static void wd1770_execute(wd1770_t *drv) fdd_index_count_reset(drv->fdd); drv->sync = 0; drv->step++; + /* fall through */ case 6: if (fdd_index_count(drv->fdd) >= 5) { drv->status |= WD_RNF; @@ -430,6 +443,7 @@ static void wd1770_execute(wd1770_t *drv) drv->crc = 0xb230; drv->byte_count = 6; drv->step++; + /* fall through */ case 7: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; @@ -447,7 +461,7 @@ static void wd1770_execute(wd1770_t *drv) if (drv->byte_count == 3) { drv->tmp = res; } - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); if (--drv->byte_count) { continue; } @@ -465,6 +479,7 @@ static void wd1770_execute(wd1770_t *drv) } drv->byte_count = 43; drv->step++; + /* fall through */ case 8: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; @@ -480,15 +495,16 @@ static void wd1770_execute(wd1770_t *drv) if (!drv->sync) { drv->crc = 0xffff; } - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); drv->sync = (res == 0x1a1); continue; } } - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); drv->status |= ((res & 0xff) == 0xf8) ? WD_RT : 0; drv->byte_count = (128 << drv->tmp) + 2; drv->step++; + /* fall through */ case 9: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; @@ -499,7 +515,7 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; drv->data = res; } - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); if (--drv->byte_count) { continue; } @@ -541,10 +557,11 @@ static void wd1770_execute(wd1770_t *drv) continue; } res = ((drv->cmd & WD_A) ? 0xf8 : 0xfb) | (drv->dden ? 0x100 : 0); - fdd_write(drv->fdd, (BYTE)res); - drv->crc = fdd_crc(drv->crc, (BYTE)res); + fdd_write(drv->fdd, res); + drv->crc = fdd_crc(drv->crc, res); drv->byte_count = (128 << drv->tmp) + 3; drv->step++; + /* fall through */ case 11: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; @@ -555,10 +572,10 @@ static void wd1770_execute(wd1770_t *drv) fdd_write(drv->fdd, 0xff); break; case 1: - fdd_write(drv->fdd, (BYTE)(drv->crc & 0xff)); + fdd_write(drv->fdd, drv->crc & 0xff); continue; case 2: - fdd_write(drv->fdd, (BYTE)(drv->crc >> 8)); + fdd_write(drv->fdd, drv->crc >> 8); continue; default: drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; @@ -586,6 +603,7 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= WD_BSY; drv->status &= ~(WD_DRQ | WD_LD | WD_RNF | WD_CRC); drv->step++; + /* fall through */ case 1: if ((drv->cmd & WD_H) || (drv->status & WD_MO)) { drv->status |= WD_MO; @@ -595,24 +613,28 @@ static void wd1770_execute(wd1770_t *drv) drv->status |= WD_MO; fdd_index_count_reset(drv->fdd); drv->step++; + /* fall through */ case 2: drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; if (fdd_index_count(drv->fdd) < 6) { return; } drv->step++; + /* fall through */ case 3: if (!(drv->cmd & WD_E)) { drv->step += 2; continue; } drv->step++; + /* fall through */ case 4: if (*drv->cpu_clk_ptr < drv->clk + SETTLING) { return; } drv->clk += SETTLING; drv->step++; + /* fall through */ case 5: fdd_index_count_reset(drv->fdd); drv->sync = 0; @@ -632,6 +654,7 @@ static void wd1770_execute(wd1770_t *drv) drv->step++; continue; } + /* fall through */ case 6: if (fdd_index_count(drv->fdd) < 1) { drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; @@ -645,7 +668,7 @@ static void wd1770_execute(wd1770_t *drv) return; } drv->clk += BYTE_RATE; - drv->data = (BYTE)fdd_read(drv->fdd); + drv->data = fdd_read(drv->fdd); drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; continue; case 7: @@ -668,13 +691,14 @@ static void wd1770_execute(wd1770_t *drv) drv->crc = 0xb230; drv->byte_count = 6; drv->step++; + /* fall through */ case 8: if (*drv->cpu_clk_ptr < drv->clk + BYTE_RATE) { return; } drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; drv->clk += BYTE_RATE; - drv->data = (BYTE)fdd_read(drv->fdd); + drv->data = fdd_read(drv->fdd); if (drv->byte_count == 6) { drv->sector = drv->data; } @@ -702,6 +726,7 @@ static void wd1770_execute(wd1770_t *drv) drv->byte_count = 0; drv->tmp = 0; drv->step++; + /* fall through */ case 10: if (fdd_index_count(drv->fdd) < 1) { drv->clk += fdd_rotate(drv->fdd, (*drv->cpu_clk_ptr - drv->clk) / BYTE_RATE) * BYTE_RATE; @@ -718,7 +743,7 @@ static void wd1770_execute(wd1770_t *drv) drv->clk += BYTE_RATE; res = drv->data; if (drv->byte_count) { - fdd_write(drv->fdd, (BYTE)(drv->crc & 0xff)); + fdd_write(drv->fdd, drv->crc & 0xff); drv->byte_count--; } else { drv->status |= (drv->status & WD_DRQ) ? WD_LD : WD_DRQ; @@ -739,6 +764,7 @@ static void wd1770_execute(wd1770_t *drv) drv->crc = 0xffff; drv->tmp = 1; } + /* fall through */ case 0xfc: res |= 0x100; } @@ -762,9 +788,9 @@ static void wd1770_execute(wd1770_t *drv) } } if (drv->tmp) { - drv->crc = fdd_crc(drv->crc, (BYTE)res); + drv->crc = fdd_crc(drv->crc, res); } - fdd_write(drv->fdd, (BYTE)res); + fdd_write(drv->fdd, res); drv->data = 0; } continue; @@ -792,7 +818,7 @@ static void wd1770_execute(wd1770_t *drv) /*-----------------------------------------------------------------------*/ /* WD1770 register read/write access. */ -static void wd1770_store(wd1770_t *drv, WORD addr, BYTE byte) +static void wd1770_store(wd1770_t *drv, uint16_t addr, uint8_t byte) { int i; @@ -860,7 +886,7 @@ static void wd1770_store(wd1770_t *drv, WORD addr, BYTE byte) } } -static BYTE wd1770_read(wd1770_t *drv, WORD addr) +static uint8_t wd1770_read(wd1770_t *drv, uint16_t addr) { wd1770_execute(drv); @@ -880,7 +906,7 @@ static BYTE wd1770_read(wd1770_t *drv, WORD addr) } /* read from I/O without side effects */ -static BYTE wd1770_peek(wd1770_t *drv, WORD addr) +static uint8_t wd1770_peek(wd1770_t *drv, uint16_t addr) { switch (addr) { case WD_STATUS: @@ -895,6 +921,13 @@ static BYTE wd1770_peek(wd1770_t *drv, WORD addr) return 0; } +void wd1770d_dump(diskunit_context_t *ctx) +{ + wd1770_t *drv = ctx->wd1770; + mon_out("Track:%d Sector:%d\n", drv->track, drv->sector); + mon_out("Status:$%02x Data:$%02x\n", drv->status, drv->data); +} + void wd1770_reset(wd1770_t *drv) { drv->type = 0; @@ -911,39 +944,39 @@ void wd1770_reset(wd1770_t *drv) int wd1770_attach_image(disk_image_t *image, unsigned int unit) { - if (unit < 8 || unit > 8 + DRIVE_NUM) { + if (unit < 8 || unit > 8 + NUM_DISK_UNITS) { return -1; } switch (image->type) { case DISK_IMAGE_TYPE_D81: case DISK_IMAGE_TYPE_D1M: - disk_image_attach_log(image, wd1770_log, unit); + disk_image_attach_log(image, wd1770_log, unit, 0); break; default: return -1; } - fdd_image_attach(drive_context[unit - 8]->wd1770->fdd, image); + fdd_image_attach(diskunit_context[unit - 8]->wd1770->fdd, image); return 0; } int wd1770_detach_image(disk_image_t *image, unsigned int unit) { - if (image == NULL || unit < 8 || unit > 8 + DRIVE_NUM) { + if (image == NULL || unit < 8 || unit > 8 + NUM_DISK_UNITS) { return -1; } switch (image->type) { case DISK_IMAGE_TYPE_D81: case DISK_IMAGE_TYPE_D1M: - disk_image_detach_log(image, wd1770_log, unit); + disk_image_detach_log(image, wd1770_log, unit, 0); break; default: return -1; } - fdd_image_detach(drive_context[unit - 8]->wd1770->fdd); + fdd_image_detach(diskunit_context[unit - 8]->wd1770->fdd); return 0; } @@ -962,19 +995,20 @@ int wd1770_disk_change(wd1770_t *drv) return fdd_disk_change(drv->fdd); } -void wd1770d_store(drive_context_t *drv, WORD addr, BYTE byte) +void wd1770d_store(diskunit_context_t *drv, uint16_t addr, uint8_t byte) { - wd1770_store(drv->wd1770, (WORD)(addr & 3), byte); + drv->cpu->cpu_last_data = byte; + wd1770_store(drv->wd1770, (uint16_t)(addr & 3), byte); } -BYTE wd1770d_read(drive_context_t *drv, WORD addr) +uint8_t wd1770d_read(diskunit_context_t *drv, uint16_t addr) { - return wd1770_read(drv->wd1770, (WORD)(addr & 3)); + return drv->cpu->cpu_last_data = wd1770_read(drv->wd1770, (uint16_t)(addr & 3)); } -BYTE wd1770d_peek(drive_context_t *drv, WORD addr) +uint8_t wd1770d_peek(diskunit_context_t *drv, uint16_t addr) { - return wd1770_peek(drv->wd1770, (WORD)(addr & 3)); + return wd1770_peek(drv->wd1770, (uint16_t)(addr & 3)); } #define WD1770_SNAP_MAJOR 1 @@ -997,17 +1031,17 @@ int wd1770_snapshot_write_module(wd1770_t *drv, struct snapshot_s *s) || SMW_B(m, drv->status) < 0 || SMW_B(m, drv->cmd) < 0 || SMW_W(m, drv->crc) < 0 - || SMW_B(m, (BYTE)drv->command) < 0 + || SMW_B(m, (uint8_t)drv->command) < 0 || SMW_DW(m, drv->type) < 0 || SMW_DW(m, drv->step) < 0 || SMW_DW(m, drv->byte_count) < 0 || SMW_DW(m, drv->tmp) < 0 || SMW_DW(m, drv->direction) < 0 - || SMW_DW(m, drv->clk) < 0 - || SMW_B(m, (BYTE)drv->irq) < 0 - || SMW_B(m, (BYTE)drv->dden) < 0 - || SMW_B(m, (BYTE)drv->sync) < 0 - || SMW_B(m, (BYTE)drv->is1772) < 0) { + || SMW_CLOCK(m, drv->clk) < 0 + || SMW_B(m, (uint8_t)drv->irq) < 0 + || SMW_B(m, (uint8_t)drv->dden) < 0 + || SMW_B(m, (uint8_t)drv->sync) < 0 + || SMW_B(m, (uint8_t)drv->is1772) < 0) { snapshot_module_close(m); return -1; } @@ -1021,7 +1055,7 @@ int wd1770_snapshot_write_module(wd1770_t *drv, struct snapshot_s *s) int wd1770_snapshot_read_module(wd1770_t *drv, struct snapshot_s *s) { - BYTE vmajor, vminor; + uint8_t vmajor, vminor; snapshot_module_t *m; int command; @@ -1031,7 +1065,7 @@ int wd1770_snapshot_read_module(wd1770_t *drv, struct snapshot_s *s) } /* Do not accept higher versions than current */ - if (vmajor > WD1770_SNAP_MAJOR || vminor > WD1770_SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, WD1770_SNAP_MAJOR, WD1770_SNAP_MAJOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); snapshot_module_close(m); return -1; @@ -1048,9 +1082,9 @@ int wd1770_snapshot_read_module(wd1770_t *drv, struct snapshot_s *s) || SMR_DW_INT(m, &drv->type) < 0 || SMR_DW_INT(m, &drv->step) < 0 || SMR_DW_INT(m, &drv->byte_count) < 0 - || SMR_DW_INT(m, &drv->tmp) < 0 + || SMR_DW_INT(m, (int *)(&drv->tmp)) < 0 || SMR_DW_INT(m, &drv->direction) < 0 - || SMR_DW(m, &drv->clk) < 0 + || SMR_CLOCK(m, &drv->clk) < 0 || SMR_B_INT(m, &drv->irq) < 0 || SMR_B_INT(m, &drv->dden) < 0 || SMR_B_INT(m, &drv->sync) < 0 diff --git a/src/Emulators/vice/drive/iec/wd1770.h b/src/Emulators/vice/drive/iec/wd1770.h index c61b8cfe..500f9157 100644 --- a/src/Emulators/vice/drive/iec/wd1770.h +++ b/src/Emulators/vice/drive/iec/wd1770.h @@ -30,25 +30,29 @@ #include "vicetypes.h" struct disk_image_s; -struct drive_context_s; +struct diskunit_context_s; struct snapshot_s; typedef struct wd1770_s wd1770_t; /* FIXME: whats the deal with the different prefixes? */ -extern void wd1770d_init(struct drive_context_s *drv); -extern void wd1770_shutdown(wd1770_t *drv); - -extern int wd1770_attach_image(struct disk_image_s *image, unsigned int unit); -extern int wd1770_detach_image(struct disk_image_s *image, unsigned int unit); - -extern int wd1770_disk_change(wd1770_t *drv); -extern void wd1770d_store(struct drive_context_s *drv, WORD addr, BYTE byte); -extern BYTE wd1770d_read(struct drive_context_s *drv, WORD addr); -extern BYTE wd1770d_peek(struct drive_context_s *drv, WORD addr); -extern void wd1770_reset(wd1770_t *drv); -extern void wd1770_set_side(wd1770_t *drv, int side); -extern void wd1770_set_motor(wd1770_t *drv, int on); - -extern int wd1770_snapshot_write_module(wd1770_t *drv, struct snapshot_s *s); -extern int wd1770_snapshot_read_module(wd1770_t *drv, struct snapshot_s *s); +void wd1770d_init(struct diskunit_context_s *drv); +void wd1770_shutdown(wd1770_t *drv); + +int wd1770_attach_image(struct disk_image_s *image, unsigned int unit); +int wd1770_detach_image(struct disk_image_s *image, unsigned int unit); + +int wd1770_disk_change(wd1770_t *drv); +void wd1770d_store(struct diskunit_context_s *drv, uint16_t addr, uint8_t byte); +uint8_t wd1770d_read(struct diskunit_context_s *drv, uint16_t addr); +uint8_t wd1770d_peek(struct diskunit_context_s *drv, uint16_t addr); +void wd1770d_dump(struct diskunit_context_s *drv); + +void wd1770_reset(wd1770_t *drv); + +void wd1770_set_side(wd1770_t *drv, int side); +void wd1770_set_motor(wd1770_t *drv, int on); + +int wd1770_snapshot_write_module(wd1770_t *drv, struct snapshot_s *s); +int wd1770_snapshot_read_module(wd1770_t *drv, struct snapshot_s *s); + #endif diff --git a/src/Emulators/vice/drive/iecieee.h b/src/Emulators/vice/drive/iecieee.h index 575c57f5..fbe20903 100644 --- a/src/Emulators/vice/drive/iecieee.h +++ b/src/Emulators/vice/drive/iecieee.h @@ -29,17 +29,17 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct snapshot_s; -extern void iecieee_drive_init(struct drive_context_s *drv); -extern void iecieee_drive_shutdown(struct drive_context_s *drv); -extern void iecieee_drive_reset(struct drive_context_s *drv); -extern void iecieee_drive_setup_context(struct drive_context_s *drv); +void iecieee_drive_init(struct diskunit_context_s *drv); +void iecieee_drive_shutdown(struct diskunit_context_s *drv); +void iecieee_drive_reset(struct diskunit_context_s *drv); +void iecieee_drive_setup_context(struct diskunit_context_s *drv); -extern int iecieee_drive_snapshot_read(struct drive_context_s *ctxptr, - struct snapshot_s *s); -extern int iecieee_drive_snapshot_write(struct drive_context_s *ctxptr, - struct snapshot_s *s); -#endif +int iecieee_drive_snapshot_read(struct diskunit_context_s *ctxptr, + struct snapshot_s *s); +int iecieee_drive_snapshot_write(struct diskunit_context_s *ctxptr, + struct snapshot_s *s); +#endif diff --git a/src/Emulators/vice/drive/iecieee/iecieee.c b/src/Emulators/vice/drive/iecieee/iecieee.c index 6235d2c2..7bc4bf02 100644 --- a/src/Emulators/vice/drive/iecieee/iecieee.c +++ b/src/Emulators/vice/drive/iecieee/iecieee.c @@ -34,19 +34,19 @@ #include "viad.h" #include "drive-sound.h" -void iecieee_drive_init(struct drive_context_s *drv) +void iecieee_drive_init(struct diskunit_context_s *drv) { via2d_init(drv); } -void iecieee_drive_shutdown(struct drive_context_s *drv) +void iecieee_drive_shutdown(struct diskunit_context_s *drv) { viacore_shutdown(drv->via2); } -void iecieee_drive_reset(struct drive_context_s *drv) +void iecieee_drive_reset(struct diskunit_context_s *drv) { - switch (drv->drive->type) { + switch (drv->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: @@ -63,15 +63,15 @@ void iecieee_drive_reset(struct drive_context_s *drv) } } -void iecieee_drive_setup_context(struct drive_context_s *drv) +void iecieee_drive_setup_context(struct diskunit_context_s *drv) { via2d_setup_context(drv); } -int iecieee_drive_snapshot_read(struct drive_context_s *ctxptr, +int iecieee_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - switch (ctxptr->drive->type) { + switch (ctxptr->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: @@ -90,10 +90,10 @@ int iecieee_drive_snapshot_read(struct drive_context_s *ctxptr, return 0; } -int iecieee_drive_snapshot_write(struct drive_context_s *ctxptr, +int iecieee_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - switch (ctxptr->drive->type) { + switch (ctxptr->type) { case DRIVE_TYPE_1540: case DRIVE_TYPE_1541: case DRIVE_TYPE_1541II: diff --git a/src/Emulators/vice/drive/iecieee/via2d.c b/src/Emulators/vice/drive/iecieee/via2d.c index 7d68950b..6cec9303 100644 --- a/src/Emulators/vice/drive/iecieee/via2d.c +++ b/src/Emulators/vice/drive/iecieee/via2d.c @@ -33,13 +33,20 @@ #define OLDCODE 0 /* set to 1 to use the old ca2/cb2 handling code */ /* #define DEBUG_VIA2 */ +/* #define DEBUG_STEP */ #ifdef DEBUG_VIA2 -#define DBG(_x_) log_debug _x_ +#define DBG(_x_) log_printf _x_ #else #define DBG(_x_) #endif +#ifdef DEBUG_STEP +#define DBGSTEP(_x_) log_printf _x_ +#else +#define DBGSTEP(_x_) +#endif + #include "vice.h" #include @@ -50,6 +57,7 @@ #include "interrupt.h" #include "lib.h" #include "log.h" +#include "monitor.h" #include "rotation.h" #include "vicetypes.h" #include "via.h" @@ -57,6 +65,7 @@ #include "drive-sound.h" #include "ViceWrapper.h" +#include "vice_debugger_hook.h" typedef struct drivevia2_context_s { unsigned int number; @@ -71,22 +80,22 @@ static void set_ca2(via_context_t *via_context, int state) drive_t *drv; via2p = (drivevia2_context_t *)(via_context->prv); drv = via2p->drive; - curr = ((drv->byte_ready_active >> 1) & 1); + curr = ((drv->byte_ready_active >> 1) & 1); /* selects BRA_BYTE_READY */ if (state != curr) { DBG(("VIA2: set_ca2 (%d to %d) (byte rdy)", curr, state)); rotation_rotate_disk(drv); drv->byte_ready_active &= ~(1 << 1); drv->byte_ready_active |= state << 1; if (drv->byte_ready_edge) { - drive_context_t *drive_context = (drive_context_t *)(via_context->context); - drive_cpu_set_overflow(drive_context); + diskunit_context_t *dc = (diskunit_context_t *)(via_context->context); + drive_cpu_set_overflow(dc); drv->byte_ready_edge = 0; } } #endif } -static void set_cb2(via_context_t *via_context, int state) +static void set_cb2(via_context_t *via_context, int state, int offset) { #if !OLDCODE int curr; @@ -107,44 +116,56 @@ static void set_cb2(via_context_t *via_context, int state) static void set_int(via_context_t *via_context, unsigned int int_num, int value, CLOCK rclk) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *)(via_context->context); - interrupt_set_irq(drive_context->cpu->int_status, int_num, value, rclk); + interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk); } static void restore_int(via_context_t *via_context, unsigned int int_num, int value) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *)(via_context->context); - interrupt_restore_irq(drive_context->cpu->int_status, int_num, value); + interrupt_restore_irq(dc->cpu->int_status, int_num, value); } -void via2d_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void via2d_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { - c64d_mark_drive1541_cell_write(addr, data); - + VICE_HOOK_DRIVE_CELL_WRITE(addr, data); + + ctxptr->cpu->cpu_last_data = data; viacore_store(ctxptr->via2, addr, data); } -BYTE via2d_read(drive_context_t *ctxptr, WORD addr) +uint8_t via2d_read(diskunit_context_t *ctxptr, uint16_t addr) { - c64d_mark_drive1541_cell_read(addr); - - return viacore_read(ctxptr->via2, addr); + VICE_HOOK_DRIVE_CELL_READ(addr); + + return ctxptr->cpu->cpu_last_data = viacore_read(ctxptr->via2, addr); } -BYTE via2d_peek(drive_context_t *ctxptr, WORD addr) +uint8_t via2d_peek(diskunit_context_t *ctxptr, uint16_t addr) { return viacore_peek(ctxptr->via2, addr); } -int via2d_dump(drive_context_t *ctxptr, WORD addr) +int via2d_dump(diskunit_context_t *ctxptr, uint16_t addr) { + const int speeds[4] = {250000, 266667, 285714, 307692}; + drivevia2_context_t *via2p = (drivevia2_context_t *)(ctxptr->via2->prv); + drive_t *drv = via2p->drive; + int track_number = drv->current_half_track; + int zone = (ctxptr->via2->via[VIA_PRB] >> 5) & 3; + viacore_dump(ctxptr->via2); + mon_out("\nHead is on track: %d.%d (%s at %dbps, speed zone %d)\n", + track_number / 2, (track_number & 1) * 5, + ((ctxptr->via2->via[VIA_PCR] & 0xe0) == 0xe0) ? "reading" : "writing", + speeds[zone], zone + ); return 0; } @@ -158,33 +179,37 @@ void via2d_update_pcr(int pcrval, drive_t *dptr) int bra = dptr->byte_ready_active; rotation_rotate_disk(dptr); dptr->read_write_mode = pcrval & 0x20; - dptr->byte_ready_active = (bra & ~0x02) | (pcrval & 0x02); + DBG(("via2d.c: via2d_update_pcr: drv->read_write_mode = %x", drv->read_write_mode)) +#define PCR_BYTE_READY BRA_BYTE_READY /* 0x02 */ + dptr->byte_ready_active = (bra & ~BRA_BYTE_READY) | (pcrval & PCR_BYTE_READY); } -static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa_value, - WORD addr) +static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t oldpa_value, + uint16_t addr) { drivevia2_context_t *via2p; via2p = (drivevia2_context_t *)(via_context->prv); rotation_rotate_disk(via2p->drive); + /* See comments about Port A latching at read_pra() */ via2p->drive->GCR_write_value = byte; via2p->drive->byte_ready_level = 0; } -static void undump_pra(via_context_t *via_context, BYTE byte) +static void undump_pra(via_context_t *via_context, uint8_t byte) { } -static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, - WORD addr) +static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t poldpb, + uint16_t addr) { drivevia2_context_t *via2p = (drivevia2_context_t *)(via_context->prv); drive_t *drv = via2p->drive; int bra; + int track_number, new_stepper_position, old_stepper_position, step_count; DBG(("VIA2: store_prb (%02x to %02x) clock:%d", poldpb, byte, *(via_context->clk_ptr))); @@ -206,43 +231,53 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, suggests a binary counter circuitry, but that is not the case, the similarity is just a side effect. Note, how switching the drive motor on/off may move the stepper motor as well. */ - /* Process stepper motor if the drive motor is on */ - if (byte & 0x4) { - - /* vice track numbering starts with 2... we need the real, physical track number */ - int track_number = drv->current_half_track - 2; - /* the new coil line activated */ - int new_stepper_position = byte & 3; - - /* - track halftrack stepper - log. log.phys. position - 1 2 0 0 - 1.5 3 1 1 - 2 4 2 2 - 2.5 5 3 3 - 3 6 4 0 - 3.5 7 5 1 - ... */ - - int old_stepper_position = track_number & 3; + /* vice track numbering starts with 2... we need the real, physical track number */ + track_number = drv->current_half_track - 2; + + /* the new coil line activated */ + new_stepper_position = byte & 3; + + /* + track halftrack stepper + log. log.phys. position + 1 2 0 0 + 1.5 3 1 1 + 2 4 2 2 + 2.5 5 3 3 + 3 6 4 0 + 3.5 7 5 1 + ... */ + + old_stepper_position = track_number & 3; + + /* the steps travelled and the direction */ + /* int step_count = (drv->stepper_new_position - old_stepper_position) & 3; */ + step_count = (new_stepper_position - old_stepper_position) & 3; + if (step_count == 3) { + step_count = -1; + } + /* Process stepper motor if the drive motor is on */ + if (byte & 0x4) { +#ifdef DEBUG_STEP + if (new_stepper_position != old_stepper_position) { + DBGSTEP(("trk: %d.%d, old: %d new: %d steps: %d", + (track_number+1) / 2, (track_number+1) & 1, + old_stepper_position, new_stepper_position, + step_count + )); + } +#endif /* FIXME: emulating the mechanical delay with such naive approach does - not work, as the actual step is delayed to the next write to pb. - regardless how long that will take. for one example that does - not work like this, see bug #508 + not work, as the actual step is delayed to the next write to pb. + regardless how long that will take. for one example that does + not work like this, see bug #508 - FIXME: we should implement the intended behaviour using an alarm - instead. - */ + FIXME: we should implement the intended behaviour using an alarm + instead. + */ - /* the steps travelled and the direction */ - /* int step_count = (drv->stepper_new_position - old_stepper_position) & 3; */ - int step_count = (new_stepper_position - old_stepper_position) & 3; - if (step_count == 3) { - step_count = -1; - } /* minimal simulation of mechanical delay. @@ -250,7 +285,7 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, - startup time, the time it takes from changing the coils to when the head starts moving. - seek time, the time it takes the head to move from track to track - - settle time, the time it takes from stopping the head to being + - settle time, the time it takes from stopping the head to being able to read reliably. the simplified emulation here only simulates startup time, and then @@ -263,7 +298,7 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, /* Action Replay 6: 8333 = 8.3ms Cauldron/The Dreams: 7734 = 7.7ms - fastest usable stepping speed seems to be around 4096 = 4.1ms + fastest usable stepping speed seems to be around 4096 = 4.1ms min delay so we dont get a step at reset 700 = 0.7ms */ /* if ((*(via_context->clk_ptr) - drv->stepper_last_change_clk) >= 2000) */ { @@ -277,8 +312,8 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, allowing it always does more harm than good, so we should simply ignore this condition for the time being. */ if ((step_count == 1) || (step_count == -1)) { - DBG(("VIA2: store_prb drive_move_head(%d) (%02x to %02x) clk:%d delay:%d", - step_count, poldpb, byte, *(via_context->clk_ptr), + DBG(("VIA2: store_prb drive_move_head(%d) (%02x to %02x) clk:%d delay:%d", + step_count, poldpb, byte, *(via_context->clk_ptr), (*(via_context->clk_ptr) - drv->stepper_last_change_clk))); drive_move_head(step_count, drv); } @@ -293,37 +328,52 @@ static void store_prb(via_context_t *via_context, BYTE byte, BYTE poldpb, if ((poldpb ^ byte) & 0x60) { /* Zone bits */ rotation_speed_zone_set((byte >> 5) & 0x3, via2p->number); } - if ((poldpb ^ byte) & 0x04) { /* Motor on/off */ +#define PB_MOTOR_ON BRA_MOTOR_ON + if ((poldpb ^ byte) & PB_MOTOR_ON) { /* Motor on/off */ drive_sound_update((byte & 4) ? DRIVE_SOUND_MOTOR_ON : DRIVE_SOUND_MOTOR_OFF, via2p->number); bra = drv->byte_ready_active; - drv->byte_ready_active = (bra & ~0x04) | (byte & 0x04); - if ((byte & 0x04) != 0) { + drv->byte_ready_active = (bra & ~BRA_MOTOR_ON) | (byte & BRA_MOTOR_ON); + if ((byte & BRA_MOTOR_ON) != 0) { rotation_begins(drv); } else { if (drv->byte_ready_edge) { - drive_context_t *drive_context = (drive_context_t *)(via_context->context); - drive_cpu_set_overflow(drive_context); + diskunit_context_t *dc = (diskunit_context_t *)(via_context->context); + drive_cpu_set_overflow(dc); drv->byte_ready_edge = 0; } } +/* enable this for experimental fix related to extra stepping when the motor + is turned on. (bug #1083 "Primitive 7 Sins") */ +#if 1 + if (new_stepper_position != old_stepper_position) { + if ((byte & 0x04) != 0) { +#ifdef DEBUG_STEP + DBGSTEP(("motor: %d trk: %d.%d, old: %d new: %d steps: %d", + byte & 0x04, (track_number+1) / 2, (track_number+1) & 1, + old_stepper_position, new_stepper_position, step_count)); +#endif + drive_move_head(step_count, drv); + } + } +#endif } drv->byte_ready_level = 0; } -static void undump_prb(via_context_t *via_context, BYTE byte) +static void undump_prb(via_context_t *via_context, uint8_t byte) { drivevia2_context_t *via2p; via2p = (drivevia2_context_t *)(via_context->prv); - via2p->drive->led_status = (byte & 8) ? 1 : 0; - rotation_speed_zone_set((byte >> 5) & 0x3, via2p->number); + via2p->drive->led_status = (byte & 0x08) ? 1 : 0; + rotation_speed_zone_set((byte >> 5) & 0x03, via2p->number); via2p->drive->byte_ready_active - = (via2p->drive->byte_ready_active & ~0x04) | (byte & 0x04); + = (via2p->drive->byte_ready_active & ~BRA_MOTOR_ON) | (byte & BRA_MOTOR_ON); } -static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) +static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr) { drivevia2_context_t *via2p; @@ -333,7 +383,7 @@ static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) #if OLDCODE /* FIXME: this should use via_set_ca2() and via_set_cb2() */ if (byte != via_context->via[VIA_PCR]) { - BYTE tmp = byte; + uint8_t tmp = byte; /* first set bit 1 and 5 to the real output values */ if ((byte & 0x0c) != 0x0c) { /* CA2 not lo or hi output */ tmp |= 0x02; /* byte ready */ @@ -352,7 +402,7 @@ static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) return byte; } -static void undump_pcr(via_context_t *via_context, BYTE byte) +static void undump_pcr(via_context_t *via_context, uint8_t byte) { drivevia2_context_t *via2p; @@ -361,19 +411,19 @@ static void undump_pcr(via_context_t *via_context, BYTE byte) via2d_update_pcr(byte, via2p->drive); } -static void undump_acr(via_context_t *via_context, BYTE byte) +static void undump_acr(via_context_t *via_context, uint8_t byte) { } -static void store_acr(via_context_t *via_context, BYTE byte) +static void store_acr(via_context_t *via_context, uint8_t byte) { } -static void store_sr(via_context_t *via_context, BYTE byte) +static void store_sr(via_context_t *via_context, uint8_t byte) { } -static void store_t2l(via_context_t *via_context, BYTE byte) +static void store_t2l(via_context_t *via_context, uint8_t byte) { } @@ -400,9 +450,39 @@ BYTE c64d_peek_via2d_pra(via_context_t *via_context) return byte; } -static BYTE read_pra(via_context_t *via_context, WORD addr) -{ - BYTE byte; +/* + * Read the byte from the disk's read head as it has gone through a serial + * to parallel shift register. + * + * The 1541 DOS code enables latching of the VIA's Port A, but this is + * currently not emulated. Effectively, the drive-dependent code handles + * latching this value (GCR_read), which in hardware happens in the VIA (port + * A), and the handshake signal that it has been read (effectively, calling + * this function which clears byte_ready_level). + * + * The BYTE READY output from the PLA, that is connected to the SO (Set + * Overflow) pin on the CPU, also connects to the VIA's CA1 handshake / latch + * pin. This would activate the latch. When the CPU reads from port A, CA2 + * signals back to the drive hardware that it has been read (that line is + * labeled SOE, possibly SO Enable, enabling output to Set Overflow / CA1 + * again). This corresponds to clearing byte_ready_level as below. + * + * "UC2 is a VIA also. [...] During a read operation serial data is received + * from the read amplifier circuits on D-IN input on pin 24 of the PLA. The PLA + * shift register converts serial data into parallel data that is latched at + * the parallel port (YB0-YB7). The microprocessor reads the parallel PLA + * output by reading Port A of UC2 when BYTE READY on pin 39 goes "low"." + * (1540-1541_Disk_Drive_Service_Manual_Preliminary_314002-01_(1985_Apr).pdf + * p.14) + * + * This wording suggests that the PLA latches so latching in the VIA again + * would not really be needed. However the schematic on the next page, for + * pre-PLA hardware, shows a 74LS164 (8-Bit Serial In/Parallel Out Shift Register) + * and it would not be latched. SOE indeed affects BYTE READY. + */ +static uint8_t read_pra(via_context_t *via_context, uint16_t addr) { + /* GCR data port */ + uint8_t byte; drivevia2_context_t *via2p; via2p = (drivevia2_context_t *)(via_context->prv); @@ -414,15 +494,18 @@ static BYTE read_pra(via_context_t *via_context, WORD addr) byte = ((via2p->drive->GCR_read & ~(via_context->via[VIA_DDRA])) | (via_context->via[VIA_PRA] & via_context->via[VIA_DDRA])); - +#if 0 + printf("(%u)%02x", via2p->drive->GCR_head_offset/8, via2p->drive->GCR_read); + if (byte != via2p->drive->GCR_read) printf("[%02x]", byte); +#endif via2p->drive->byte_ready_level = 0; return byte; } -static BYTE read_prb(via_context_t *via_context) +static uint8_t read_prb(via_context_t *via_context) { - BYTE byte; + uint8_t byte; drivevia2_context_t *via2p; via2p = (drivevia2_context_t *)(via_context->prv); @@ -439,6 +522,10 @@ static BYTE read_prb(via_context_t *via_context) DBG(("read_prb %02x pb:%02x ddr:%02x",byte,via_context->via[VIA_PRB],via_context->via[VIA_DDRB])); + /* + * See comments about port A latching at read_pra(); + * clearing byte_ready_level here may be wrong. + */ via2p->drive->byte_ready_level = 0; return byte; @@ -465,7 +552,7 @@ BYTE c64d_peek_via2d_prb(via_context_t *via_context) } -BYTE c64d_via2d_peek(drive_context_t *ctxptr, WORD addr) +BYTE c64d_via2d_peek(diskunit_context_t *ctxptr, WORD addr) { WORD addr_via = addr & 0x0f; @@ -484,8 +571,7 @@ BYTE c64d_via2d_peek(drive_context_t *ctxptr, WORD addr) if (via_context->via[VIA_ACR] & 0x80) { - byte = (byte & 0x7f) | (((via_context->pb7 ^ via_context->pb7x) - | via_context->pb7o) ? 0x80 : 0); + byte = (byte & 0x7f) | via_context->t1_pb7; /* VICE 3.10: pb7/pb7x/pb7o -> t1_pb7 */ } return byte; @@ -496,13 +582,13 @@ BYTE c64d_via2d_peek(drive_context_t *ctxptr, WORD addr) -void via2d_init(drive_context_t *ctxptr) +void via2d_init(diskunit_context_t *ctxptr) { viacore_init(ctxptr->via2, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void via2d_setup_context(drive_context_t *ctxptr) +void via2d_setup_context(diskunit_context_t *ctxptr) { drivevia2_context_t *via2p; via_context_t *via; @@ -515,15 +601,15 @@ void via2d_setup_context(drive_context_t *ctxptr) via2p = (drivevia2_context_t *)(via->prv); via2p->number = ctxptr->mynumber; - via2p->drive = ctxptr->drive; + via2p->drive = ctxptr->drives[0]; via->context = (void *)ctxptr; via->rmw_flag = &(ctxptr->cpu->rmw_flag); via->clk_ptr = ctxptr->clk_ptr; - via->myname = lib_msprintf("Drive%dVia2", via2p->number); - via->my_module_name = lib_msprintf("VIA2D%d", via2p->number); + via->myname = lib_msprintf("Drive%uVia2", via2p->number); + via->my_module_name = lib_msprintf("VIA2D%u", via2p->number); viacore_setup_context(via); diff --git a/src/Emulators/vice/drive/ieee.h b/src/Emulators/vice/drive/ieee.h index 6b1ffb68..caff04a5 100644 --- a/src/Emulators/vice/drive/ieee.h +++ b/src/Emulators/vice/drive/ieee.h @@ -30,31 +30,26 @@ #include "vicetypes.h" struct disk_image_s; -struct drive_context_s; +struct diskunit_context_s; struct snapshot_s; -extern int ieee_drive_resources_init(void); -extern void ieee_drive_resources_shutdown(void); -extern int ieee_drive_cmdline_options_init(void); -extern void ieee_drive_init(struct drive_context_s *drv); -extern void ieee_drive_shutdown(struct drive_context_s *drv); -extern void ieee_drive_reset(struct drive_context_s *drv); -extern void ieee_drive_mem_init(struct drive_context_s *drv, unsigned int type); -extern void ieee_drive_setup_context(struct drive_context_s *drv); -extern void ieee_drive_rom_load(void); -extern void ieee_drive_rom_setup_image(unsigned int dnr); -extern int ieee_drive_rom_check_loaded(unsigned int type); -extern void ieee_drive_rom_do_checksum(unsigned int dnr); -extern int ieee_drive_snapshot_read(struct drive_context_s *ctxptr, - struct snapshot_s *s); -extern int ieee_drive_snapshot_write(struct drive_context_s *ctxptr, - struct snapshot_s *s); -extern int ieee_drive_image_attach(struct disk_image_s *image, - unsigned int unit); -extern int ieee_drive_image_detach(struct disk_image_s *image, - unsigned int unit); +int ieee_drive_resources_init(void); +void ieee_drive_resources_shutdown(void); +int ieee_drive_cmdline_options_init(void); +void ieee_drive_init(struct diskunit_context_s *drv); +void ieee_drive_shutdown(struct diskunit_context_s *drv); +void ieee_drive_reset(struct diskunit_context_s *drv); +void ieee_drive_mem_init(struct diskunit_context_s *drv, unsigned int type); +void ieee_drive_setup_context(struct diskunit_context_s *drv); +void ieee_drive_rom_load(void); +void ieee_drive_rom_setup_image(unsigned int dnr); +int ieee_drive_rom_check_loaded(unsigned int type); +void ieee_drive_rom_do_checksum(unsigned int dnr); +int ieee_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s); +int ieee_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s); +int ieee_drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive); +int ieee_drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive); -extern void ieee_drive_parallel_set_atn(int state, struct drive_context_s *drv); +void ieee_drive_parallel_set_atn(int state, struct diskunit_context_s *drv); #endif - diff --git a/src/Emulators/vice/drive/ieee/fdc.c b/src/Emulators/vice/drive/ieee/fdc.c index 12c01c49..ec0dc83a 100644 --- a/src/Emulators/vice/drive/ieee/fdc.c +++ b/src/Emulators/vice/drive/ieee/fdc.c @@ -1,9 +1,12 @@ /* - * fdc.c - 1001/8x50 FDC emulation + * fdc.c - 1001/8x50/90x0 FDC emulation * * Written by * Andre Fachat * + * D9090/D9060 portions by + * Roberto Muscedere + * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -31,7 +34,6 @@ #include "alarm.h" #include "attach.h" -#include "clkguard.h" #include "diskimage.h" #include "drive-check.h" #include "drive.h" @@ -43,8 +45,9 @@ #include "vicetypes.h" -#undef FDC_DEBUG +/* #define FDC_DEBUG */ +#define DOS_IS_90(type) (type == DRIVE_TYPE_9000) #define DOS_IS_80(type) (type == DRIVE_TYPE_8050 || type == DRIVE_TYPE_8250 || type == DRIVE_TYPE_1001) #define DOS_IS_40(type) (type == DRIVE_TYPE_4040) #define DOS_IS_30(type) (type == DRIVE_TYPE_3040) @@ -52,16 +55,16 @@ /************************************************************************/ -#define NUM_FDC DRIVE_NUM +#define NUM_FDC NUM_DISK_UNITS /* dual disk drives */ -static log_t fdc_log = LOG_ERR; +static log_t fdc_log = LOG_DEFAULT; typedef struct fdc_t { int fdc_state; alarm_t *fdc_alarm; CLOCK alarm_clk; - BYTE *buffer; - BYTE *iprom; + uint8_t *buffer; + uint8_t *iprom; unsigned int drive_type; unsigned int num_drives; unsigned int last_track; @@ -71,59 +74,59 @@ typedef struct fdc_t { disk_image_t *realimage; } fdc_t; -static fdc_t fdc[NUM_FDC]; +/* + * The fdc[] array contains an fdc_t struct for every drive, i.e. two structs + * for every unit, as each unit could be dual drive. + */ +static fdc_t fdc[NUM_FDC][2]; void fdc_reset(unsigned int fnum, unsigned int drive_type) { - fdc_t *thefdc = &fdc[fnum]; - int drive1 = mk_drive1(fnum); + fdc_t *thefdc0 = &fdc[fnum][0]; + fdc_t *thefdc1 = &fdc[fnum][1]; disk_image_t *saved_image0, *saved_image1; #ifdef FDC_DEBUG - log_message(fdc_log, "fdc_reset: drive %d type=%d\n", fnum, drive_type); + log_message(fdc_log, "fdc_reset: drive %u type=%u", fnum, drive_type); #endif - saved_image0 = fdc[fnum].realimage; - saved_image1 = NULL; + saved_image0 = thefdc0->realimage; + saved_image1 = thefdc1->realimage; /* detach disk images */ - if (thefdc->image) { - thefdc->wps_change = 0; - fdc_detach_image(thefdc->image, fnum + 8); - } - if (thefdc->num_drives == 2) { - saved_image1 = fdc[drive1].realimage; - if (fdc[drive1].image) { - fdc[drive1].wps_change = 0; - fdc_detach_image(fdc[drive1].image, drive1 + 8); - } + if (thefdc0->image) { + thefdc0->wps_change = 0; + fdc_detach_image(thefdc0->image, fnum + 8, 0); + } + if (thefdc1->image) { + thefdc1->wps_change = 0; + fdc_detach_image(thefdc1->image, fnum + 8, 1); } if (drive_check_old(drive_type)) { - thefdc->drive_type = drive_type; - thefdc->num_drives = is_drive1(fnum) ? 1 : - drive_check_dual(drive_type) ? 2 : 1; - thefdc->fdc_state = FDC_RESET0; - alarm_set(thefdc->fdc_alarm, drive_clk[fnum] + 20); + thefdc0->drive_type = drive_type; + thefdc0->num_drives = drive_check_dual(drive_type) ? 2 : 1; + thefdc0->fdc_state = FDC_RESET0; + alarm_set(thefdc0->fdc_alarm, diskunit_clk[fnum] + 20); } else { - thefdc->drive_type = DRIVE_TYPE_NONE; - alarm_unset(thefdc->fdc_alarm); - thefdc->fdc_state = FDC_UNUSED; - thefdc->num_drives = 0; + thefdc0->drive_type = DRIVE_TYPE_NONE; + alarm_unset(thefdc0->fdc_alarm); + thefdc0->fdc_state = FDC_UNUSED; + thefdc0->num_drives = 0; } /* re-attach disk images */ if (saved_image0) { #ifdef FDC_DEBUG - printf("ieee/fdc.c:fdc_reset dev %d type %d drive 0 re-attach image %p (drive: %p)\n", fnum + 8, drive_type, saved_image0, drive_context[fnum]->drive->image); + log_message(fdc_log, "ieee/fdc.c:fdc_reset dev %u type %u drive 0 re-attach image %p (drive: %p)", fnum + 8, drive_type, saved_image0, diskunit_context[fnum]->drives[0]->image); #endif - fdc_attach_image(saved_image0, fnum + 8); + fdc_attach_image(saved_image0, fnum + 8, 0); } if (saved_image1) { #ifdef FDC_DEBUG - printf("ieee/fdc.c:fdc_reset dev %d type %d drive 1 re-attach image %p (drive: %p)\n", fnum + 8, drive_type, saved_image0, drive_context[drive1]->drive->image); + log_message(fdc_log, "ieee/fdc.c:fdc_reset dev %u type %u drive 1 re-attach image %p (drive: %p)", fnum + 8, drive_type, saved_image0, diskunit_context[fnum+1]->drives[1]->image); #endif - fdc_attach_image(saved_image1, drive1 + 8); + fdc_attach_image(saved_image1, fnum + 8, 1); } } @@ -131,17 +134,21 @@ void fdc_reset(unsigned int fnum, unsigned int drive_type) * Format a disk in DOS1 format */ -static BYTE fdc_do_format_D20(fdc_t *fdc, unsigned int fnum, unsigned int dnr, +static uint8_t fdc_do_format_D20(unsigned int fnum, unsigned int dnr, unsigned int track, unsigned int sector, - int buf, BYTE *header) + int buf, uint8_t *header) { int i; int ret; - BYTE rc = 0; + uint8_t rc = 0; disk_addr_t dadr; - BYTE sector_data[256]; + uint8_t sector_data[256]; + + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][dnr]; + + if (!memcmp(sysfdc->iprom + 0x2040, &sysfdc->buffer[0x100], 0x200)) { - if (!memcmp(fdc[fnum].iprom + 0x2040, &fdc[fnum].buffer[0x100], 0x200)) { static const unsigned int sectorchangeat[4] = { 0, 17, 24, 30 }; static const unsigned int nsecs[] = { 21, 20, 18, 17 }; unsigned int ntracks, nsectors = 0; @@ -152,11 +159,11 @@ static BYTE fdc_do_format_D20(fdc_t *fdc, unsigned int fnum, unsigned int dnr, */ #ifdef FDC_DEBUG log_message(fdc_log, "format code: "); - log_message(fdc_log, " track=%d, sector=%d", track, sector); + log_message(fdc_log, " track=%u, sector=%u", track, sector); log_message(fdc_log, " id=%02x,%02x (%c%c)", header[0], header[1], header[0], header[1]); #endif - if (fdc[dnr].image->read_only) { + if (imgfdc->image->read_only) { rc = FDC_ERR_WPROT; return rc; } @@ -172,14 +179,14 @@ static BYTE fdc_do_format_D20(fdc_t *fdc, unsigned int fnum, unsigned int dnr, } } #ifdef FDC_DEBUG - log_message(fdc_log, " track %d, -> %d sectors", + log_message(fdc_log, " track %u, -> %u sectors", dadr.track, nsectors); #endif for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { - ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); + ret = disk_image_write_sector(imgfdc->image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, - "Could not update T:%d S:%d on disk image.", + "Could not update T:%u S:%u on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DCHECK; break; @@ -187,7 +194,7 @@ static BYTE fdc_do_format_D20(fdc_t *fdc, unsigned int fnum, unsigned int dnr, } } - file_system_bam_set_disk_id(dnr + 8, header); + file_system_bam_set_disk_id(fnum + 8, dnr, header); } if (!rc) { rc = FDC_ERR_OK; @@ -200,31 +207,35 @@ static BYTE fdc_do_format_D20(fdc_t *fdc, unsigned int fnum, unsigned int dnr, * Format a disk in DOS2 format */ -static BYTE fdc_do_format_D40(fdc_t *fdc, unsigned int fnum, unsigned int dnr, +static uint8_t fdc_do_format_D40(unsigned int fnum, unsigned int dnr, unsigned int track, unsigned int sector, - int buf, BYTE *header) + int buf, uint8_t *header) { int i; int ret; - BYTE rc = 0; + uint8_t rc = 0; disk_addr_t dadr; - BYTE sector_data[256]; + uint8_t sector_data[256]; + + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][dnr]; + + if (!memcmp(sysfdc->iprom + 0x1000, &sysfdc->buffer[0x100], 0x200)) { - if (!memcmp(fdc[fnum].iprom + 0x1000, &fdc[fnum].buffer[0x100], 0x200)) { static const unsigned int sectorchangeat[4] = { 0, 17, 24, 30 }; unsigned int ntracks, nsectors = 0; #ifdef FDC_DEBUG log_message(fdc_log, "format code: "); log_message(fdc_log, " secs per track: %d %d %d %d", - fdc[fnum].buffer[0x99], fdc[fnum].buffer[0x9a], - fdc[fnum].buffer[0x9b], fdc[fnum].buffer[0x9c]); - log_message(fdc_log, " track=%d, sector=%d", + sysfdc->buffer[0x99], sysfdc->buffer[0x9a], + sysfdc->buffer[0x9b], sysfdc->buffer[0x9c]); + log_message(fdc_log, " track=%u, sector=%u", track, sector); log_message(fdc_log, " id=%02x,%02x (%c%c)", header[0], header[1], header[0], header[1]); #endif - if (fdc[dnr].image->read_only) { + if (imgfdc->image->read_only) { rc = FDC_ERR_WPROT; return rc; } @@ -235,19 +246,19 @@ static BYTE fdc_do_format_D40(fdc_t *fdc, unsigned int fnum, unsigned int dnr, for (ret = 0, dadr.track = 1; ret == 0 && dadr.track <= ntracks; dadr.track++) { for (i = 3; i >= 0; i--) { if (dadr.track > sectorchangeat[i]) { - nsectors = fdc[fnum].buffer[0x99 + 3 - i]; + nsectors = sysfdc->buffer[0x99 + 3 - i]; break; } } #ifdef FDC_DEBUG - log_message(fdc_log, " track %d, -> %d sectors", + log_message(fdc_log, " track %u, -> %u sectors", dadr.track, nsectors); #endif for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { - ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); + ret = disk_image_write_sector(imgfdc->image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, - "Could not update T:%d S:%d on disk image.", + "Could not update T:%u S:%u on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DCHECK; break; @@ -255,7 +266,7 @@ static BYTE fdc_do_format_D40(fdc_t *fdc, unsigned int fnum, unsigned int dnr, } } - file_system_bam_set_disk_id(dnr + 8, header); + file_system_bam_set_disk_id(fnum + 8, dnr, header); } if (!rc) { rc = FDC_ERR_OK; @@ -268,70 +279,74 @@ static BYTE fdc_do_format_D40(fdc_t *fdc, unsigned int fnum, unsigned int dnr, * Format a disk in DOS2/80 track format */ -static BYTE fdc_do_format_D80(fdc_t *fdc, unsigned int fnum, unsigned int dnr, +static uint8_t fdc_do_format_D80(unsigned int fnum, unsigned int dnr, unsigned int track, unsigned int sector, - int buf, BYTE *header) + int buf, uint8_t *header) { int i; int ret; - BYTE rc = 0; + uint8_t rc = 0; disk_addr_t dadr; - BYTE sector_data[256]; + uint8_t sector_data[256]; + + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][dnr]; + + if (!memcmp(sysfdc->iprom, &sysfdc->buffer[0x100], 0x300)) { - if (!memcmp(fdc[fnum].iprom, &fdc[fnum].buffer[0x100], 0x300)) { unsigned int ntracks, nsectors = 0; /* detected format code */ #ifdef FDC_DEBUG log_message(fdc_log, "format code: "); log_message(fdc_log, " track for zones side 0: %d %d %d %d", - fdc[fnum].buffer[0xb0], fdc[fnum].buffer[0xb1], - fdc[fnum].buffer[0xb2], fdc[fnum].buffer[0xb3]); + sysfdc->buffer[0xb0], sysfdc->buffer[0xb1], + sysfdc->buffer[0xb2], sysfdc->buffer[0xb3]); log_message(fdc_log, " track for zones side 1: %d %d %d %d", - fdc[fnum].buffer[0xb4], fdc[fnum].buffer[0xb5], - fdc[fnum].buffer[0xb6], fdc[fnum].buffer[0xb7]); + sysfdc->buffer[0xb4], sysfdc->buffer[0xb5], + sysfdc->buffer[0xb6], sysfdc->buffer[0xb7]); log_message(fdc_log, " secs per track: %d %d %d %d", - fdc[fnum].buffer[0x99], fdc[fnum].buffer[0x9a], - fdc[fnum].buffer[0x9b], fdc[fnum].buffer[0x9c]); + sysfdc->buffer[0x99], sysfdc->buffer[0x9a], + sysfdc->buffer[0x9b], sysfdc->buffer[0x9c]); log_message(fdc_log, " vars: 870=%d 873=%d 875=%d", - fdc[fnum].buffer[0x470], fdc[fnum].buffer[0x473], - fdc[fnum].buffer[0x475]); - log_message(fdc_log, " track=%d, sector=%d", + sysfdc->buffer[0x470], sysfdc->buffer[0x473], + sysfdc->buffer[0x475]); + log_message(fdc_log, " track=%u, sector=%u", track, sector); log_message(fdc_log, " id=%02x,%02x (%c%c)", header[0], header[1], header[0], header[1]); log_message(fdc_log, " sides=%d", - fdc[fnum].buffer[0xac]); + sysfdc->buffer[0xac]); #endif - if (fdc[dnr].image->read_only) { + if (imgfdc->image->read_only) { rc = FDC_ERR_WPROT; return rc; } - ntracks = (fdc[fnum].buffer[0xac] > 1) ? 154 : 77; + ntracks = (sysfdc->buffer[0xac] > 1) ? 154 : 77; memset(sector_data, 0, 256); for (ret = 0, dadr.track = 1; ret == 0 && dadr.track <= ntracks; dadr.track++) { if (dadr.track < 78) { for (i = 3; i >= 0; i--) { - if (dadr.track < fdc[fnum].buffer[0xb0 + i]) { - nsectors = fdc[fnum].buffer[0x99 + i]; + if (dadr.track < sysfdc->buffer[0xb0 + i]) { + nsectors = sysfdc->buffer[0x99 + i]; break; } } } else { for (i = 3; i >= 0; i--) { - if (dadr.track < fdc[fnum].buffer[0xb4 + i]) { - nsectors = fdc[fnum].buffer[0x99 + i]; + if (dadr.track < sysfdc->buffer[0xb4 + i]) { + nsectors = sysfdc->buffer[0x99 + i]; break; } } } for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { - ret = disk_image_write_sector(fdc[dnr].image, sector_data, + ret = disk_image_write_sector(imgfdc->image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, - "Could not update T:%d S:%d on disk image.", + "Could not update T:%u S:%u on disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DCHECK; break; @@ -339,7 +354,65 @@ static BYTE fdc_do_format_D80(fdc_t *fdc, unsigned int fnum, unsigned int dnr, } } - file_system_bam_set_disk_id(dnr + 8, header); + file_system_bam_set_disk_id(fnum + 8, dnr, header); + } + if (!rc) { + rc = FDC_ERR_OK; + } + + return rc; +} + +/***************************************************************************** + * Format a hard disk in DOS3/90 track format + */ + +static uint8_t fdc_do_format_D90(unsigned int fnum, unsigned int dnr, + unsigned int track, unsigned int sector, + int buf, uint8_t *header) +{ + int ret; + uint8_t rc = 0; + disk_addr_t dadr; + uint8_t sector_data[256]; + + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][dnr]; + + if (1) { + unsigned int ntracks, nsectors = 0; + /* detected format code */ + if (imgfdc->image->read_only) { + rc = FDC_ERR_WPROT; + return rc; + } + ntracks = sysfdc->buffer[0x9a]; + nsectors = sysfdc->buffer[0x9d] << 5; + +#ifdef FDC_DEBUG + log_message(fdc_log, "format command: "); + log_message(fdc_log, " tracks=%u, sectors=%u", + ntracks + 1, nsectors); +#endif + + memset(sector_data, 0, 256); + + for (ret = 0, dadr.track = 1; ret == 0 && dadr.track <= ntracks; dadr.track++) { + for (dadr.sector = 0; dadr.sector < nsectors; dadr.sector++) { + ret = disk_image_write_sector(imgfdc->image, sector_data, + &dadr); + if (ret < 0) { + log_error(LOG_DEFAULT, + "Could not update T:%u S:%u on disk image.", + dadr.track, dadr.sector); + /* save back the track/sector where the issue happened */ + header[2] = dadr.track; + header[3] = dadr.sector; + rc = FDC_ERR_DCHECK; + break; + } + } + } } if (!rc) { rc = FDC_ERR_OK; @@ -352,15 +425,15 @@ static BYTE fdc_do_format_D80(fdc_t *fdc, unsigned int fnum, unsigned int dnr, * execute an FDC job sent by the main CPU */ #ifdef FDC_DEBUG -static BYTE fdc_do_job_(unsigned int fnum, int buf, - unsigned int drv, BYTE job, BYTE *header); +static uint8_t fdc_do_job_(unsigned int fnum, int buf, + unsigned int drv, uint8_t job, uint8_t *header); #endif -static BYTE fdc_do_job(unsigned int fnum, int buf, - unsigned int drv, BYTE job, BYTE *header) +static uint8_t fdc_do_job(unsigned int fnum, int buf, + unsigned int drv, uint8_t job, uint8_t *header) { #ifdef FDC_DEBUG - BYTE retval = fdc_do_job_(fnum, buf, drv, job, header); + uint8_t retval = fdc_do_job_(fnum, buf, drv, job, header); const char *jobs[] = { "Read", "Write", "Verify", "Seek", "Bump", "Jump", "ExecWhenRdy", "--" }; @@ -370,103 +443,201 @@ static BYTE fdc_do_job(unsigned int fnum, int buf, "BLENGTH", "ID", "FSPEED", "DRIVE", "DECODE" }; - log_message(fdc_log, " fdc_do_job (%s %02x) -> %02x (%s)\n", + log_message(fdc_log, " fdc_do_job (%s %02x) -> %02x (%s)", jobs[(job >> 4) & 7], job, retval, - (retval <= 16) ? errors[retval] : "Unknown"); + (retval <= 14) ? errors[retval] : "Unknown"); return retval; } -static BYTE fdc_do_job_(unsigned int fnum, int buf, - unsigned int drv, BYTE job, BYTE *header) +static uint8_t fdc_do_job_(unsigned int fnum, int buf, + unsigned int drv, uint8_t job, uint8_t *header) { #endif - unsigned int dnr; - BYTE rc; + uint8_t rc; int ret; int i; disk_addr_t dadr; - BYTE *base; - BYTE sector_data[256]; - BYTE disk_id[2]; + uint8_t *base; + uint8_t sector_data[256]; + uint8_t disk_id[2]; drive_t *drive; + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][drv]; + dadr.track = header[2]; dadr.sector = header[3]; - /* determine drive/disk image to use */ - if (drv < fdc[fnum].num_drives) { - dnr = fnum + drv; - } else { - /* drive 1 on a single disk drive */ - return FDC_ERR_SYNC; - } - rc = 0; - base = &(fdc[fnum].buffer[(buf + 1) << 8]); + base = &(sysfdc->buffer[(buf + 1) << 8]); #ifdef FDC_DEBUG - log_message(fdc_log, "do job %02x, buffer %d ($%04x): d%d t%d s%d, " - "image=%p, type=%04d", - job, buf, (buf + 1) << 8, dnr, dadr.track, dadr.sector, - fdc[dnr].image, - fdc[dnr].image ? fdc[dnr].image->type : 0); + log_message(fdc_log, "do job %02x, buffer %d ($%04x): d%u t%u s%u, " + "image=%p, type=%04u", + job, buf, (unsigned int)(buf + 1) << 8, drv, dadr.track, dadr.sector, + imgfdc->image, + imgfdc->image ? imgfdc->image->type : 0); #endif - if (fdc[dnr].image == NULL && job != 0xd0) { + if (imgfdc->image == NULL && job != 0xd0) { #ifdef FDC_DEBUG - log_message(fdc_log, "dnr=%d, image=NULL -> no disk!", dnr); + log_message(fdc_log, "dnr=%u, image=NULL -> no disk!", drv); #endif return FDC_ERR_SYNC; } - file_system_bam_get_disk_id(dnr + 8, disk_id); + file_system_bam_get_disk_id(fnum + 8, drv, disk_id); +#ifdef FDC_DEBUG + log_message(fdc_log, "fdc_do_job_: header '%c%c', disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif switch (job) { case 0x80: /* read */ - if (header[0] != disk_id[0] || header[1] != disk_id[1]) { - rc = FDC_ERR_ID; - break; - } - ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr); - if (ret < 0) { - log_error(LOG_DEFAULT, - "Cannot read T:%d S:%d from disk image.", - dadr.track, dadr.sector); - rc = FDC_ERR_DRIVE; - } else { - memcpy(base, sector_data, 256); + if (DOS_IS_90(sysfdc->drive_type)) { rc = FDC_ERR_OK; + /* the HD fdc can transfer more than one block */ + for (i = sysfdc->buffer[0xa0]; i>0; i--) { + if (dadr.track > imgfdc->image->tracks) { + /* save back the track/sector where the issue happened */ + header[2] = dadr.track; + header[3] = dadr.sector; + rc = FDC_ERR_DRIVE; + break; + } + ret = disk_image_read_sector(imgfdc->image, sector_data, &dadr); + if (ret < 0) { + log_error(LOG_DEFAULT, + "Cannot read T:%u S:%u from disk image.", + dadr.track, dadr.sector); + /* save back the track/sector where the issue happened */ + header[2] = dadr.track; + header[3] = dadr.sector; + rc = FDC_ERR_DRIVE; + break; + } else { + memcpy(base, sector_data, 256); + } + dadr.sector++; + if (dadr.sector >= imgfdc->image->sectors) { + dadr.sector = 0; + dadr.track++; + } + /* check cycle buffer flag */ + if (sysfdc->buffer[0xa3]) { + buf++; + if (buf == 15) { + buf = 0; + } + base = &(sysfdc->buffer[(buf + 1) << 8]); + } + } + } else { + if (header[0] != disk_id[0] || header[1] != disk_id[1]) { +#ifdef FDC_DEBUG + log_message(fdc_log, "do job read: header '%c%c' != disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif + rc = FDC_ERR_ID; + break; + } + ret = disk_image_read_sector(imgfdc->image, sector_data, &dadr); + if (ret < 0) { + log_error(LOG_DEFAULT, + "Cannot read T:%u S:%u from disk image.", + dadr.track, dadr.sector); + rc = FDC_ERR_DRIVE; + } else { + memcpy(base, sector_data, 256); + rc = FDC_ERR_OK; + } } break; case 0x90: /* write */ - if (header[0] != disk_id[0] || header[1] != disk_id[1]) { - rc = FDC_ERR_ID; - break; - } - if (fdc[dnr].image->read_only) { - rc = FDC_ERR_WPROT; - break; - } - memcpy(sector_data, base, 256); - ret = disk_image_write_sector(fdc[dnr].image, sector_data, &dadr); - if (ret < 0) { - log_error(LOG_DEFAULT, - "Could not update T:%d S:%d on disk image.", - dadr.track, dadr.sector); - rc = FDC_ERR_DRIVE; - } else { + if (DOS_IS_90(sysfdc->drive_type)) { + if (imgfdc->image->read_only) { + rc = FDC_ERR_WPROT; + break; + } rc = FDC_ERR_OK; + /* the HD fdc can transfer more than one block */ + for (i = sysfdc->buffer[0xa0]; i>0; i--) { + if (dadr.track > imgfdc->image->tracks) { + /* save back the track/sector where the issue happened */ + header[2] = dadr.track; + header[3] = dadr.sector; + rc = FDC_ERR_DRIVE; + break; + } + memcpy(sector_data, base, 256); + ret = disk_image_write_sector(imgfdc->image, sector_data, &dadr); + if (ret < 0) { + log_error(LOG_DEFAULT, + "Could not update T:%u S:%u on disk image.", + dadr.track, dadr.sector); + /* save back the track/sector where the issue happened */ + header[2] = dadr.track; + header[3] = dadr.sector; + rc = FDC_ERR_DRIVE; + break; + } + dadr.sector++; + if (dadr.sector >= imgfdc->image->sectors) { + dadr.sector = 0; + dadr.track++; + } + /* check cycle buffer flag */ + if (sysfdc->buffer[0xa3]) { + buf++; + if (buf == 15) { + buf = 0; + } + base = &(sysfdc->buffer[(buf + 1) << 8]); + } + } + } else { + if (header[0] != disk_id[0] || header[1] != disk_id[1]) { +#ifdef FDC_DEBUG + log_message(fdc_log, "do job write: header '%c%c' != disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif + rc = FDC_ERR_ID; + break; + } + if (imgfdc->image->read_only) { + rc = FDC_ERR_WPROT; + break; + } + memcpy(sector_data, base, 256); + ret = disk_image_write_sector(imgfdc->image, sector_data, &dadr); + if (ret < 0) { + log_error(LOG_DEFAULT, + "Could not update T:%u S:%u on disk image.", + dadr.track, dadr.sector); + rc = FDC_ERR_DRIVE; + } else { + rc = FDC_ERR_OK; + } } break; case 0xA0: /* verify */ + if (DOS_IS_90(sysfdc->drive_type)) { + /* the fdc just does a read, doesn't compare anything */ + rc = FDC_ERR_OK; + break; + } if (header[0] != disk_id[0] || header[1] != disk_id[1]) { +#ifdef FDC_DEBUG + log_message(fdc_log, "do job verify: header '%c%c' != disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif rc = FDC_ERR_ID; break; } - ret = disk_image_read_sector(fdc[dnr].image, sector_data, &dadr); + ret = disk_image_read_sector(imgfdc->image, sector_data, &dadr); if (ret < 0) { log_error(LOG_DEFAULT, - "Cannot read T:%d S:%d from disk image.", + "Cannot read T:%u S:%u from disk image.", dadr.track, dadr.sector); rc = FDC_ERR_DRIVE; } else { @@ -485,41 +656,45 @@ static BYTE fdc_do_job_(unsigned int fnum, int buf, } break; case 0xB0: /* seek - move to track and read ID(?) */ +#ifdef FDC_DEBUG + log_message(fdc_log, "do job seek: header was '%c%c' becomes disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif header[0] = disk_id[0]; header[1] = disk_id[1]; - /* header[2] = fdc[dnr].last_track; */ + /* header[2] = fdc[dnri].last_track; */ dadr.track = header[2]; header[3] = 1; rc = FDC_ERR_OK; break; case 0xC0: /* bump (to track 0 and back to 18?) */ dadr.track = 1; - if (DOS_IS_20(fdc[fnum].drive_type)) { + if (DOS_IS_20(sysfdc->drive_type)) { header[2] = 18; } rc = FDC_ERR_OK; break; case 0xD0: /* jump to buffer - but we do not emulate FDC CPU */ #ifdef FDC_DEBUG - log_message(fdc_log, "exec buffer %d ($%04x): %02x %02x %02x %02x %02x", - buf, (buf + 1) << 8, + log_message(fdc_log, "exec buffer %d ($%04x): %02x %02x %02x %02x", + buf, (unsigned int)(buf + 1) << 8, base[0], base[1], base[2], base[3] ); #endif - if (DOS_IS_40(fdc[fnum].drive_type) - || DOS_IS_30(fdc[fnum].drive_type)) { - if (!memcmp(fdc[fnum].iprom + 0x12f8, &fdc[fnum].buffer[0x100], + if (DOS_IS_40(sysfdc->drive_type) + || DOS_IS_30(sysfdc->drive_type)) { + if (!memcmp(sysfdc->iprom + 0x12f8, &sysfdc->buffer[0x100], 0x100)) { - fdc[fnum].fdc_state = FDC_RESET2; + sysfdc->fdc_state = FDC_RESET2; return 0; } } - if (DOS_IS_80(fdc[fnum].drive_type)) { - static const BYTE jumpseq[] = { + if (DOS_IS_80(sysfdc->drive_type) || DOS_IS_90(sysfdc->drive_type)) { + static const uint8_t jumpseq[] = { 0x78, 0x6c, 0xfc, 0xff }; - if (!memcmp(jumpseq, &fdc[fnum].buffer[0x100], 4)) { - fdc[fnum].fdc_state = FDC_RESET0; + if (!memcmp(jumpseq, &sysfdc->buffer[0x100], 4)) { + sysfdc->fdc_state = FDC_RESET0; return 0; } } @@ -530,33 +705,47 @@ static BYTE fdc_do_job_(unsigned int fnum, int buf, formatted */ /* we have to check for standard format code that is copied to buffers 0-3 */ - if (DOS_IS_80(fdc[fnum].drive_type)) { - rc = fdc_do_format_D80(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); + if (DOS_IS_80(sysfdc->drive_type)) { + rc = fdc_do_format_D80(fnum, drv, dadr.track, dadr.sector, buf, header); } else - if (DOS_IS_40(fdc[fnum].drive_type) - || DOS_IS_30(fdc[fnum].drive_type)) { - rc = fdc_do_format_D40(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); + if (DOS_IS_40(sysfdc->drive_type) + || DOS_IS_30(sysfdc->drive_type)) { + rc = fdc_do_format_D40(fnum, drv, dadr.track, dadr.sector, buf, header); } else - if (DOS_IS_20(fdc[fnum].drive_type)) { - rc = fdc_do_format_D20(fdc, fnum, dnr, dadr.track, dadr.sector, buf, header); + if (DOS_IS_20(sysfdc->drive_type)) { + rc = fdc_do_format_D20(fnum, drv, dadr.track, dadr.sector, buf, header); } else { rc = FDC_ERR_DRIVE; } break; case 0xF0: if (header[0] != disk_id[0] || header[1] != disk_id[1]) { +#ifdef FDC_DEBUG + log_message(fdc_log, "do job F0: header '%c%c' != disk_id '%c%c'", + header[0], header[1], disk_id[0], disk_id[1]); +#endif rc = FDC_ERR_ID; break; } /* try to read block header from disk */ rc = FDC_ERR_OK; break; + case 0xC4: + /* HD low-level format, not DOS data at all */ + if (DOS_IS_90(sysfdc->drive_type)) { + rc = fdc_do_format_D90(fnum, drv, dadr.track, dadr.sector, buf, header); + } + break; + case 0xC8: /* SASI bus reset */ + case 0xB8: /* Unknown vendor command */ + rc = FDC_ERR_OK; + break; } - drive = drive_context[dnr]->drive; + drive = diskunit_context[fnum]->drives[drv]; drive->current_half_track = 2 * dadr.track; - fdc[dnr].last_track = dadr.track; - fdc[dnr].last_sector = dadr.sector; + imgfdc->last_track = dadr.track; + imgfdc->last_sector = dadr.sector; return rc; } @@ -567,115 +756,153 @@ static void int_fdc(CLOCK offset, void *data) CLOCK rclk; int i, j; drive_t *drive; - unsigned int fnum; - drive_context_t *drv = (drive_context_t *)data; + diskunit_context_t *drv = (diskunit_context_t *)data; + unsigned int fnum = drv->mynumber; - fnum = drv->mynumber; - rclk = drive_clk[fnum] - offset; + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][1]; + + rclk = diskunit_clk[fnum] - offset; #ifdef FDC_DEBUG - if (fdc[fnum].fdc_state < FDC_RUN) { - static int old_state[NUM_FDC] = { -1, -1 }; - if (fdc[fnum].fdc_state != old_state[fnum]) - log_message(fdc_log, "int_fdc%d %d: state=%d\n", - fnum, rclk, fdc[fnum].fdc_state); + static int old_state[NUM_FDC] = { -1, -1 }; + if (sysfdc->fdc_state < FDC_RUN) { + if (sysfdc->fdc_state != old_state[fnum]) { + log_message(fdc_log, "int_fdc%u %u: state=%d", + fnum, rclk, sysfdc->fdc_state); } - old_state[fnum] = fdc[fnum].fdc_state; + old_state[fnum] = sysfdc->fdc_state; } #endif - switch (fdc[fnum].fdc_state) { + switch (sysfdc->fdc_state) { case FDC_RESET0: - drive = drive_context[fnum]->drive; - if (DOS_IS_80(fdc[fnum].drive_type)) { + drive = diskunit_context[fnum]->drives[0]; + if (DOS_IS_80(sysfdc->drive_type)) { drive->current_half_track = 2 * 38; - fdc[fnum].buffer[0] = 2; + sysfdc->buffer[0] = 2; + } else if (DOS_IS_90(sysfdc->drive_type)) { + drive->current_half_track = 2 * (153/2); + sysfdc->buffer[0] = 2; } else { drive->current_half_track = 2 * 18; - fdc[fnum].buffer[0] = 0x3f; + sysfdc->buffer[0] = 0x3f; } - if (DOS_IS_20(fdc[fnum].drive_type)) { - fdc[fnum].fdc_state = FDC_RUN; + if (DOS_IS_20(sysfdc->drive_type)) { + sysfdc->fdc_state = FDC_RUN; } else { - fdc[fnum].fdc_state++; + sysfdc->fdc_state++; } - fdc[fnum].alarm_clk = rclk + 2000; - alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk); + sysfdc->alarm_clk = rclk + 2000; + alarm_set(sysfdc->fdc_alarm, sysfdc->alarm_clk); break; case FDC_RESET1: - if (DOS_IS_80(fdc[fnum].drive_type)) { - if (fdc[fnum].buffer[0] == 0) { - fdc[fnum].buffer[0] = 1; - fdc[fnum].fdc_state++; + if (DOS_IS_80(sysfdc->drive_type) || DOS_IS_90(sysfdc->drive_type)) { + if (sysfdc->buffer[0] == 0) { + sysfdc->buffer[0] = 1; + sysfdc->fdc_state++; } } else { - if (fdc[fnum].buffer[3] == 0xd0) { - fdc[fnum].buffer[3] = 0; - fdc[fnum].fdc_state++; + if (sysfdc->buffer[3] == 0xd0) { + sysfdc->buffer[3] = 0; + sysfdc->fdc_state++; } } - fdc[fnum].alarm_clk = rclk + 2000; - alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk); + sysfdc->alarm_clk = rclk + 2000; + alarm_set(sysfdc->fdc_alarm, sysfdc->alarm_clk); break; case FDC_RESET2: - if (DOS_IS_80(fdc[fnum].drive_type)) { - if (fdc[fnum].buffer[0] == 0) { + if (DOS_IS_80(sysfdc->drive_type)) { + if (sysfdc->buffer[0] == 0) { /* emulate routine written to buffer RAM */ - fdc[fnum].buffer[1] = 0x0e; - fdc[fnum].buffer[2] = 0x2d; + sysfdc->buffer[1] = 0x0e; + sysfdc->buffer[2] = 0x2d; /* number of sides on disk drive */ - fdc[fnum].buffer[0xac] = - (fdc[fnum].drive_type == DRIVE_TYPE_8050) ? 1 : 2; + sysfdc->buffer[0xac] = + (sysfdc->drive_type == DRIVE_TYPE_8050) ? 1 : 2; /* 0 = 4040 (2A), 1 = 8x80 (2C) drive type */ - fdc[fnum].buffer[0xea] = 1; - fdc[fnum].buffer[0xee] = 5; /* 3 for 4040, 5 for 8x50 */ - fdc[fnum].buffer[0] = 3; /* 5 for 4040, 3 for 8x50 */ + sysfdc->buffer[0xea] = 1; + sysfdc->buffer[0xee] = 5; /* 3 for 4040, 5 for 8x50 */ + sysfdc->buffer[0] = 3; /* 5 for 4040, 3 for 8x50 */ - fdc[fnum].fdc_state = FDC_RUN; - fdc[fnum].alarm_clk = rclk + 10000; + sysfdc->fdc_state = FDC_RUN; + sysfdc->alarm_clk = rclk + 10000; } else { - fdc[fnum].alarm_clk = rclk + 2000; + sysfdc->alarm_clk = rclk + 2000; } - } else - if (DOS_IS_40(fdc[fnum].drive_type) - || DOS_IS_30(fdc[fnum].drive_type) + } else if (DOS_IS_90(sysfdc->drive_type)) { + if (sysfdc->buffer[0] == 0) { + /* emulate routine written to buffer RAM */ + sysfdc->buffer[0xa1] = 0x00; + sysfdc->buffer[0xa0] = 0x01; + sysfdc->buffer[0xa2] = 0x01; + /* disk geometry */ + /* heads */ + if (sysfdc->image) { + sysfdc->buffer[0x9d] = sysfdc->image->sectors >> 5; + } else { + sysfdc->buffer[0x9d] = 1; + } + sysfdc->buffer[0x9b] = sysfdc->buffer[0x9d] - 1; + /* sectors */ + sysfdc->buffer[0x9e] = 32; + sysfdc->buffer[0x9c] = 32 - 1; + /* tracks */ + if (sysfdc->image) { + sysfdc->buffer[0x9a] = sysfdc->image->tracks; + } else { + sysfdc->buffer[0x9a] = 0; + } + /* other */ + sysfdc->buffer[0x9f] = 4; + sysfdc->buffer[0] = 1; + + sysfdc->fdc_state = FDC_RUN; + sysfdc->alarm_clk = rclk + 10000; + } else { + sysfdc->alarm_clk = rclk + 2000; + } + } else if (DOS_IS_40(sysfdc->drive_type) + || DOS_IS_30(sysfdc->drive_type) ) { - if (fdc[fnum].buffer[0] == 0) { - fdc[fnum].buffer[0] = 0x0f; - fdc[fnum].fdc_state = FDC_RUN; - fdc[fnum].alarm_clk = rclk + 10000; + if (sysfdc->buffer[0] == 0) { + sysfdc->buffer[0] = 0x0f; + sysfdc->fdc_state = FDC_RUN; + sysfdc->alarm_clk = rclk + 10000; } else { - fdc[fnum].alarm_clk = rclk + 2000; + sysfdc->alarm_clk = rclk + 2000; } } - alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk); + alarm_set(sysfdc->fdc_alarm, sysfdc->alarm_clk); break; case FDC_RUN: - /* check write protect switch */ - if (fdc[fnum].wps_change) { - fdc[fnum].buffer[0xA6] = 1; - fdc[fnum].wps_change--; + /* do not do this for D9090/60 */ + if (!DOS_IS_90(sysfdc->drive_type)) { + /* check write protect switch */ + if (sysfdc->wps_change) { + sysfdc->buffer[0xA6] = 1; + sysfdc->wps_change--; #ifdef FDC_DEBUG - log_message(fdc_log, "Detect Unit %d Drive %d wps change", - fnum + 8, fnum); + log_message(fdc_log, "Detect Unit %u Drive 0 wps change", + fnum + 8); #endif - } - if (fdc[fnum].num_drives == 2) { - if (fdc[mk_drive1(fnum)].wps_change) { - fdc[fnum].buffer[0xA6 + 1] = 1; - fdc[mk_drive1(fnum)].wps_change--; + } + if (sysfdc->num_drives == 2) { + if (imgfdc->wps_change) { + sysfdc->buffer[0xA6 + 1] = 1; + imgfdc->wps_change--; #ifdef FDC_DEBUG - log_message(fdc_log, "Detect Unit %d Drive 1 wps change", - fnum + 8); + log_message(fdc_log, "Detect Unit %u Drive 1 wps change", + fnum + 8); #endif + } } } - /* check buffers */ for (i = 14; i >= 0; i--) { /* job there? */ - if (fdc[fnum].buffer[i + 3] > 127) { + if (sysfdc->buffer[i + 3] > 127) { /* pointer to buffer/block header: +0 = ID1 +1 = ID2 @@ -684,130 +911,134 @@ static void int_fdc(CLOCK offset, void *data) */ j = 0x21 + (i << 3); #ifdef FDC_DEBUG - log_message(fdc_log, "D/Buf %d/%x: Job code %02x t:%02d s:%02d", fnum, i, fdc[fnum].buffer[i + 3], - fdc[fnum].buffer[j + 2], fdc[fnum].buffer[j + 3]); + log_message(fdc_log, "D/Buf %u/%d: Job code %02x t:%02d s:%02d", fnum, i, sysfdc->buffer[i + 3], + sysfdc->buffer[j + 2], sysfdc->buffer[j + 3]); #endif - fdc[fnum].buffer[i + 3] = + sysfdc->buffer[i + 3] = fdc_do_job(fnum, /* FDC# */ i, /* buffer# */ - (unsigned int)fdc[fnum].buffer[i + 3] & 1, + (unsigned int)sysfdc->buffer[i + 3] & 1, /* drive */ - (BYTE)(fdc[fnum].buffer[i + 3] & 0xfe), + (uint8_t)(sysfdc->buffer[i + 3] & 0xfe), /* job code */ - &(fdc[fnum].buffer[j]) /* header */ + &(sysfdc->buffer[j]) /* header */ ); } } - /* check "move head", by half tracks I guess... */ - for (i = 0; i < 2; i++) { - if (fdc[fnum].buffer[i + 0xa1]) { + /* do not do this for D9090/60 */ + if (!DOS_IS_90(sysfdc->drive_type)) { + /* check "move head", by half tracks I guess... */ + for (i = 0; i < 2; i++) { + if (sysfdc->buffer[i + 0xa1]) { #ifdef FDC_DEBUG - log_message(fdc_log, "D %d: move head %d", - fnum, fdc[fnum].buffer[i + 0xa1]); + log_message(fdc_log, "D %u: move head %d", + fnum, sysfdc->buffer[i + 0xa1]); #endif - fdc[fnum].buffer[i + 0xa1] = 0; + sysfdc->buffer[i + 0xa1] = 0; + } } + sysfdc->alarm_clk = rclk + 30000; + } else { + sysfdc->alarm_clk = rclk + 2000; } - fdc[fnum].alarm_clk = rclk + 30000; - alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk); /* job loop */ break; } -} - -static void clk_overflow_callback(CLOCK sub, void *data) -{ - unsigned int fnum; - - fnum = vice_ptr_to_uint(data); - - if (fdc[fnum].fdc_state != FDC_UNUSED) { - if (fdc[fnum].alarm_clk > sub) { - fdc[fnum].alarm_clk -= sub; - } else { - fdc[fnum].alarm_clk = 0; - } - } + alarm_set(sysfdc->fdc_alarm, sysfdc->alarm_clk); } /* FIXME: hack, because 0x4000 is only ok for 1001/8050/8250. fdc.c:fdc_do_job() adds an offset for 2040/3040/4040 by itself :-( Why donlly get a table for that...! */ -void fdc_init(drive_context_t *drv) +void fdc_init(diskunit_context_t *drv) { unsigned int fnum = drv->mynumber; - BYTE *buffermem = drv->drive->drive_ram + 0x100; - BYTE *ipromp = &(drv->drive->rom[0x4000]); + uint8_t *buffermem = drv->drive_ram + 0x100; + uint8_t *ipromp = &(drv->rom[0x4000]); char *buffer; - fdc[fnum].buffer = buffermem; - fdc[fnum].iprom = ipromp; + fdc_t *sysfdc = &fdc[fnum][0]; + fdc_t *imgfdc = &fdc[fnum][1]; + + sysfdc->buffer = buffermem; + sysfdc->iprom = ipromp; - if (fdc_log == LOG_ERR) { + /* defensive. should not be used so trigger segfault */ + imgfdc->buffer = NULL; + imgfdc->iprom = NULL; + + if (fdc_log == LOG_DEFAULT) { fdc_log = log_open("fdc"); } #ifdef FDC_DEBUG - log_message(fdc_log, "fdc_init(drive %d)", fnum); + log_message(fdc_log, "fdc_init(drive %u)", fnum); #endif - buffer = lib_msprintf("fdc%i", drv->mynumber); - fdc[fnum].fdc_alarm = alarm_new(drv->cpu->alarm_context, buffer, int_fdc, + buffer = lib_msprintf("fdc%u", drv->mynumber); + sysfdc->fdc_alarm = alarm_new(drv->cpu->alarm_context, buffer, int_fdc, drv); lib_free(buffer); - - clk_guard_add_callback(drv->cpu->clk_guard, clk_overflow_callback, - uint_to_void_ptr(drv->mynumber)); } /************************************************************************/ -int fdc_attach_image(disk_image_t *image, unsigned int unit) +int fdc_attach_image(disk_image_t *image, unsigned int unit, unsigned int drive) { - int drive_no, imgno; + fdc_t *sysfdc, *imgfdc; #ifdef FDC_DEBUG - log_message(fdc_log, "fdc_attach_image(image=%p, unit=%d)", - image, unit); + log_message(fdc_log, "fdc_attach_image(image=%p, unit=%u, drive=%u)", + image, unit, drive); #endif - if (unit < 8 || unit >= 8 + DRIVE_NUM) { + if (unit < 8 || unit >= 8 + NUM_DISK_UNITS) { return -1; } - - { - int drive0 = mk_drive0(unit - 8); - - if (fdc[drive0].num_drives == 2) { - drive_no = drive0; - } else { - drive_no = unit - 8; - } + if (drive > 1) { + return -1; } - imgno = unit - 8; + sysfdc = &fdc[unit - 8][0]; + imgfdc = &fdc[unit - 8][drive]; /* FIXME: hack - we need to save the image to be able to re-attach when the disk drive type changes, in particular from the initial DRIVE_TYPE_NONE to a proper drive. */ - fdc[imgno].realimage = image; + imgfdc->realimage = image; - if (fdc[drive_no].drive_type == DRIVE_TYPE_NONE) { + if (sysfdc->drive_type == DRIVE_TYPE_NONE) { +#ifdef FDC_DEBUG + log_message(fdc_log, "Could not attach image type %u to disk #%u without type.", + image->type, unit); +#endif return -1; } - if (fdc[drive_no].drive_type == DRIVE_TYPE_8050 - || fdc[drive_no].drive_type == DRIVE_TYPE_8250 - || fdc[drive_no].drive_type == DRIVE_TYPE_1001) { + if (sysfdc->drive_type == DRIVE_TYPE_8050 + || sysfdc->drive_type == DRIVE_TYPE_8250 + || sysfdc->drive_type == DRIVE_TYPE_1001) { switch (image->type) { case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: - disk_image_attach_log(image, fdc_log, unit); + disk_image_attach_log(image, fdc_log, unit, drive); + break; + default: +#ifdef FDC_DEBUG + log_message(fdc_log, "Could not attach image type %u to disk %u.", + image->type, sysfdc->drive_type); +#endif + return -1; + } + } else if (sysfdc->drive_type == DRIVE_TYPE_9000) { + switch (image->type) { + case DISK_IMAGE_TYPE_D90: + disk_image_attach_log(image, fdc_log, unit, drive); break; default: #ifdef FDC_DEBUG - log_message(fdc_log, "Could not attach image type %d to disk %d.", - image->type, fdc[drive_no].drive_type); + log_message(fdc_log, "Could not attach image type %u to disk %u.", + image->type, sysfdc->drive_type); #endif return -1; } @@ -818,57 +1049,61 @@ int fdc_attach_image(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: case DISK_IMAGE_TYPE_P64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: - disk_image_attach_log(image, fdc_log, unit); +#endif + disk_image_attach_log(image, fdc_log, unit, drive); break; default: #ifdef FDC_DEBUG - log_message(fdc_log, "Could not attach image type %d to disk %d.", - image->type, fdc[drive_no].drive_type); + log_message(fdc_log, "Could not attach image type %u to disk %u.", + image->type, sysfdc->drive_type); #endif return -1; } } - fdc[imgno].wps_change += 2; - fdc[imgno].image = image; + imgfdc->wps_change += 2; + imgfdc->image = image; return 0; } -int fdc_detach_image(disk_image_t *image, unsigned int unit) +int fdc_detach_image(disk_image_t *image, unsigned int unit, unsigned int drive) { - int drive_no, imgno; + fdc_t *sysfdc, *imgfdc; #ifdef FDC_DEBUG - log_message(fdc_log, "fdc_detach_image(image=%p, unit=%d)", - image, unit); + log_message(fdc_log, "fdc_detach_image(image=%p, unit=%u, drive=%u)", + image, unit, drive); #endif - if (image == NULL || unit < 8 || unit >= (8 + DRIVE_NUM)) { + if (image == NULL || unit < 8 || unit >= (8 + NUM_DISK_UNITS)) { return -1; } - - { - int drive0 = mk_drive0(unit - 8); - - if (fdc[drive0].num_drives == 2) { - drive_no = drive0; - } else { - drive_no = unit - 8; - } + if (drive > 1) { + return -1; } - imgno = unit - 8; + sysfdc = &fdc[unit - 8][0]; + imgfdc = &fdc[unit - 8][drive]; - fdc[imgno].realimage = NULL; + imgfdc->realimage = NULL; - if (fdc[drive_no].drive_type == DRIVE_TYPE_8050 - || fdc[drive_no].drive_type == DRIVE_TYPE_8250 - || fdc[drive_no].drive_type == DRIVE_TYPE_1001) { + if (sysfdc->drive_type == DRIVE_TYPE_8050 + || sysfdc->drive_type == DRIVE_TYPE_8250 + || sysfdc->drive_type == DRIVE_TYPE_1001) { switch (image->type) { case DISK_IMAGE_TYPE_D80: case DISK_IMAGE_TYPE_D82: - disk_image_detach_log(image, fdc_log, unit); + disk_image_detach_log(image, fdc_log, unit, drive); + break; + default: + return -1; + } + } else if (sysfdc->drive_type == DRIVE_TYPE_9000) { + switch (image->type) { + case DISK_IMAGE_TYPE_D90: + disk_image_detach_log(image, fdc_log, unit, drive); break; default: return -1; @@ -880,16 +1115,18 @@ int fdc_detach_image(disk_image_t *image, unsigned int unit) case DISK_IMAGE_TYPE_G64: case DISK_IMAGE_TYPE_G71: case DISK_IMAGE_TYPE_P64: +#ifdef HAVE_X64_IMAGE case DISK_IMAGE_TYPE_X64: - disk_image_detach_log(image, fdc_log, unit); +#endif + disk_image_detach_log(image, fdc_log, unit, drive); break; default: return -1; } } - fdc[imgno].wps_change += 2; - fdc[imgno].image = NULL; + imgfdc->wps_change += 2; + imgfdc->image = NULL; return 0; } @@ -916,7 +1153,10 @@ int fdc_snapshot_write_module(snapshot_t *p, int fnum) snapshot_module_t *m; char *name; - if (fdc[fnum].fdc_state == FDC_UNUSED) { + fdc_t *sysfdc = &fdc[fnum][0]; + /* fdc_t *imgfdc = &fdc[fnum][1]; */ + + if (sysfdc->fdc_state == FDC_UNUSED) { return 0; } @@ -930,15 +1170,16 @@ int fdc_snapshot_write_module(snapshot_t *p, int fnum) return -1; } + /* TODO: drive 1 */ if (0 - || SMW_B(m, (BYTE)(fdc[fnum].fdc_state)) < 0 + || SMW_B(m, (uint8_t)(sysfdc->fdc_state)) < 0 /* clk till next invocation */ - || SMW_DW(m, (DWORD)(fdc[fnum].alarm_clk - drive_clk[fnum])) < 0 + || SMW_DW(m, (uint32_t)(sysfdc->alarm_clk - diskunit_clk[fnum])) < 0 /* number of drives - so far 1 only */ || SMW_B(m, 1) < 0 /* last accessed track/sector */ - || SMW_B(m, ((BYTE)(fdc[fnum].last_track))) < 0 - || SMW_B(m, ((BYTE)(fdc[fnum].last_sector))) < 0) { + || SMW_B(m, ((uint8_t)(sysfdc->last_track))) < 0 + || SMW_B(m, ((uint8_t)(sysfdc->last_sector))) < 0) { snapshot_module_close(m); return -1; } @@ -948,12 +1189,15 @@ int fdc_snapshot_write_module(snapshot_t *p, int fnum) int fdc_snapshot_read_module(snapshot_t *p, int fnum) { - BYTE vmajor, vminor; - BYTE byte, ndrv; - DWORD dword; + uint8_t vmajor, vminor; + uint8_t byte, ndrv; + uint32_t dword; snapshot_module_t *m; char *name; - BYTE ltrack, lsector; + uint8_t ltrack, lsector; + + fdc_t *sysfdc = &fdc[fnum][0]; + /*fdc_t *imgfdc = &fdc[fnum][1];*/ name = lib_msprintf("FDC%d", fnum); @@ -966,11 +1210,12 @@ int fdc_snapshot_read_module(snapshot_t *p, int fnum) } /* Do not accept versions higher than current */ - if (vmajor > SNAP_MAJOR || vminor > SNAP_MINOR) { + if (snapshot_version_is_bigger(vmajor, vminor, SNAP_MAJOR, SNAP_MINOR)) { snapshot_set_error(SNAPSHOT_MODULE_HIGHER_VERSION); goto fail; } + /* TODO: drive 1 */ if (0 || SMR_B(m, &byte) < 0 /* clk till next invocation */ @@ -985,14 +1230,14 @@ int fdc_snapshot_read_module(snapshot_t *p, int fnum) if (byte > FDC_LAST_STATE) { goto fail; } - fdc[fnum].fdc_state = byte; + sysfdc->fdc_state = byte; - fdc[fnum].alarm_clk = drive_clk[fnum] + dword; - alarm_set(fdc[fnum].fdc_alarm, fdc[fnum].alarm_clk); + sysfdc->alarm_clk = diskunit_clk[fnum] + dword; + alarm_set(sysfdc->fdc_alarm, sysfdc->alarm_clk); /* last accessed track/sector */ - fdc[fnum].last_track = ltrack; - fdc[fnum].last_sector = lsector; + sysfdc->last_track = ltrack; + sysfdc->last_sector = lsector; if (ndrv > 1) { /* ignore drv 0 values */ diff --git a/src/Emulators/vice/drive/ieee/fdc.h b/src/Emulators/vice/drive/ieee/fdc.h index 68a25005..8fcc1f90 100644 --- a/src/Emulators/vice/drive/ieee/fdc.h +++ b/src/Emulators/vice/drive/ieee/fdc.h @@ -30,7 +30,7 @@ #include "vicetypes.h" struct disk_image_s; -struct drive_context_s; +struct diskunit_context_s; struct snapshot_s; /* FDC states */ @@ -57,13 +57,13 @@ struct snapshot_s; #define FDC_ERR_DRIVE 15 #define FDC_ERR_DECODE 16 -extern void fdc_init(struct drive_context_s *drv); -extern void fdc_reset(unsigned int fnum, unsigned int enabled); +void fdc_init(struct diskunit_context_s *drv); +void fdc_reset(unsigned int fnum, unsigned int enabled); -extern int fdc_snapshot_read_module(struct snapshot_s *s, int drv); -extern int fdc_snapshot_write_module(struct snapshot_s *s, int drv); +int fdc_snapshot_read_module(struct snapshot_s *s, int drv); +int fdc_snapshot_write_module(struct snapshot_s *s, int drv); -extern int fdc_attach_image(struct disk_image_s *image, unsigned int unit); -extern int fdc_detach_image(struct disk_image_s *image, unsigned int unit); +int fdc_attach_image(struct disk_image_s *image, unsigned int unit, unsigned int drive); +int fdc_detach_image(struct disk_image_s *image, unsigned int unit, unsigned int drive); #endif diff --git a/src/Emulators/vice/drive/ieee/ieee-cmdline-options.c b/src/Emulators/vice/drive/ieee/ieee-cmdline-options.c index 2aa81a12..8f99d9ab 100644 --- a/src/Emulators/vice/drive/ieee/ieee-cmdline-options.c +++ b/src/Emulators/vice/drive/ieee/ieee-cmdline-options.c @@ -32,34 +32,27 @@ #include "lib.h" #include "cmdline.h" #include "ieee-cmdline-options.h" -#include "translate.h" -static const cmdline_option_t cmdline_options[] = { - { "-dos2031", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-dos2031", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName2031", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_2031_DOS_ROM_NAME, - NULL, NULL }, - { "-dos2040", SET_RESOURCE, 1, + "", "Specify name of 2031 DOS ROM image" }, + { "-dos2040", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName2040", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_2040_DOS_ROM_NAME, - NULL, NULL }, - { "-dos3040", SET_RESOURCE, 1, + "", "Specify name of 2040 DOS ROM image" }, + { "-dos3040", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName3040", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_3040_DOS_ROM_NAME, - NULL, NULL }, - { "-dos4040", SET_RESOURCE, 1, + "", "Specify name of 3040 DOS ROM image" }, + { "-dos4040", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName4040", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_4040_DOS_ROM_NAME, - NULL, NULL }, - { "-dos1001", SET_RESOURCE, 1, + "", "Specify name of 4040 DOS ROM image" }, + { "-dos1001", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "DosName1001", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_SPECIFY_1001_DOS_ROM_NAME, - NULL, NULL }, + "", "Specify name of 1001/8050/8250 DOS ROM image" }, + { "-dos9000", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "DosName9000", NULL, + "", "Specify name of D9090/D9060 DOS ROM image" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/drive/ieee/ieee-cmdline-options.h b/src/Emulators/vice/drive/ieee/ieee-cmdline-options.h index 987e25f4..7797c5bb 100644 --- a/src/Emulators/vice/drive/ieee/ieee-cmdline-options.h +++ b/src/Emulators/vice/drive/ieee/ieee-cmdline-options.h @@ -27,6 +27,6 @@ #ifndef VICE_IEEE_CMDLINE_OPTIONS_H #define VICE_IEEE_CMDLINE_OPTIONS_H -extern int ieee_cmdline_options_init(void); +int ieee_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/drive/ieee/ieee-resources.c b/src/Emulators/vice/drive/ieee/ieee-resources.c index 00ba103d..6b97c2db 100644 --- a/src/Emulators/vice/drive/ieee/ieee-resources.c +++ b/src/Emulators/vice/drive/ieee/ieee-resources.c @@ -43,6 +43,7 @@ static char *dos_rom_name_1001 = NULL; static char *dos_rom_name_2040 = NULL; static char *dos_rom_name_3040 = NULL; static char *dos_rom_name_4040 = NULL; +static char *dos_rom_name_9000 = NULL; static int set_dos_rom_name_2040(const char *val, void *param) { @@ -80,6 +81,15 @@ static int set_dos_rom_name_1001(const char *val, void *param) return ieeerom_load_1001(); } +static int set_dos_rom_name_9000(const char *val, void *param) +{ + if (util_string_set(&dos_rom_name_9000, val)) { + return 0; + } + + return ieeerom_load_9000(); +} + static int set_dos_rom_name_2031(const char *val, void *param) { if (util_string_set(&dos_rom_name_2031, val)) { @@ -90,17 +100,19 @@ static int set_dos_rom_name_2031(const char *val, void *param) } static const resource_string_t resources_string[] = { - { "DosName2031", "dos2031", RES_EVENT_NO, NULL, + { "DosName2031", DRIVE_ROM2031_NAME, RES_EVENT_NO, NULL, /* FIXME: should be same but names may differ */ &dos_rom_name_2031, set_dos_rom_name_2031, NULL }, - { "DosName2040", "dos2040", RES_EVENT_NO, NULL, + { "DosName2040", DRIVE_ROM2040_NAME, RES_EVENT_NO, NULL, &dos_rom_name_2040, set_dos_rom_name_2040, NULL }, - { "DosName3040", "dos3040", RES_EVENT_NO, NULL, + { "DosName3040", DRIVE_ROM3040_NAME, RES_EVENT_NO, NULL, &dos_rom_name_3040, set_dos_rom_name_3040, NULL }, - { "DosName4040", "dos4040", RES_EVENT_NO, NULL, + { "DosName4040", DRIVE_ROM4040_NAME, RES_EVENT_NO, NULL, &dos_rom_name_4040, set_dos_rom_name_4040, NULL }, - { "DosName1001", "dos1001", RES_EVENT_NO, NULL, + { "DosName1001", DRIVE_ROM1001_NAME, RES_EVENT_NO, NULL, &dos_rom_name_1001, set_dos_rom_name_1001, NULL }, + { "DosName9000", DRIVE_ROM9000_NAME, RES_EVENT_NO, NULL, + &dos_rom_name_9000, set_dos_rom_name_9000, NULL }, RESOURCE_STRING_LIST_END }; @@ -116,4 +128,5 @@ void ieee_resources_shutdown(void) lib_free(dos_rom_name_2040); lib_free(dos_rom_name_3040); lib_free(dos_rom_name_4040); + lib_free(dos_rom_name_9000); } diff --git a/src/Emulators/vice/drive/ieee/ieee-resources.h b/src/Emulators/vice/drive/ieee/ieee-resources.h index cfcd6316..0e0e0fbb 100644 --- a/src/Emulators/vice/drive/ieee/ieee-resources.h +++ b/src/Emulators/vice/drive/ieee/ieee-resources.h @@ -27,7 +27,7 @@ #ifndef VICE_IEEE_RESOURCES_H #define VICE_IEEE_RESOURCES_H -extern int ieee_resources_init(void); -extern void ieee_resources_shutdown(void); +int ieee_resources_init(void); +void ieee_resources_shutdown(void); #endif diff --git a/src/Emulators/vice/drive/ieee/ieee.c b/src/Emulators/vice/drive/ieee/ieee.c index 97bdb9fa..72a4fdb9 100644 --- a/src/Emulators/vice/drive/ieee/ieee.c +++ b/src/Emulators/vice/drive/ieee/ieee.c @@ -58,7 +58,7 @@ int ieee_drive_cmdline_options_init(void) return ieee_cmdline_options_init(); } -void ieee_drive_init(struct drive_context_s *drv) +void ieee_drive_init(struct diskunit_context_s *drv) { ieeerom_init(); via1d2031_init(drv); @@ -67,41 +67,41 @@ void ieee_drive_init(struct drive_context_s *drv) riot2_init(drv); } -void ieee_drive_shutdown(struct drive_context_s *drv) +void ieee_drive_shutdown(struct diskunit_context_s *drv) { viacore_shutdown(drv->via1d2031); riotcore_shutdown(drv->riot1); riotcore_shutdown(drv->riot2); } -void ieee_drive_reset(struct drive_context_s *drv) +void ieee_drive_reset(struct diskunit_context_s *drv) { - if (drv->drive->type == DRIVE_TYPE_2031) { + if (drv->type == DRIVE_TYPE_2031) { viacore_reset(drv->via1d2031); } else { viacore_disable(drv->via1d2031); } - if (drive_check_old(drv->drive->type)) { - fdc_reset(drv->mynumber, drv->drive->type); + if (drive_check_old(drv->type)) { + fdc_reset(drv->mynumber, drv->type); riotcore_reset(drv->riot1); riotcore_reset(drv->riot2); } else { /* alarm is unset by fdc_reset */ - fdc_reset(drv->mynumber, drv->drive->type); + fdc_reset(drv->mynumber, drv->type); riotcore_disable(drv->riot1); riotcore_disable(drv->riot2); } } -void ieee_drive_mem_init(struct drive_context_s *drv, unsigned int type) +void ieee_drive_mem_init(struct diskunit_context_s *drv, unsigned int type) { memieee_init(drv, type); } -void ieee_drive_setup_context(struct drive_context_s *drv) +void ieee_drive_setup_context(struct diskunit_context_s *drv) { - if (drv->mynumber < DRIVE_NUM) { + if (drv->mynumber < NUM_DISK_UNITS) { *drv->func = drive_funcs[drv->mynumber]; } @@ -110,6 +110,7 @@ void ieee_drive_setup_context(struct drive_context_s *drv) riot2_setup_context(drv); } +/* test all ROMs for existence, size */ void ieee_drive_rom_load(void) { ieeerom_load_2031(); @@ -117,32 +118,36 @@ void ieee_drive_rom_load(void) ieeerom_load_3040(); ieeerom_load_4040(); ieeerom_load_1001(); + ieeerom_load_9000(); } +/* setup (=load) the ROM for a given disk unit nr */ void ieee_drive_rom_setup_image(unsigned int dnr) { - ieeerom_setup_image(drive_context[dnr]->drive); + ieeerom_setup_image(diskunit_context[dnr]); } +/* check if the drive ROM is available for a given drive type, returns -1 on error */ int ieee_drive_rom_check_loaded(unsigned int type) { return ieeerom_check_loaded(type); } +/* perform checksum check on ROM for given disk unit nr */ void ieee_drive_rom_do_checksum(unsigned int dnr) { } -int ieee_drive_snapshot_read(struct drive_context_s *ctxptr, +int ieee_drive_snapshot_read(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - if (ctxptr->drive->type == DRIVE_TYPE_2031) { + if (ctxptr->type == DRIVE_TYPE_2031) { if (viacore_snapshot_read_module(ctxptr->via1d2031, s) < 0) { return -1; } } - if (drive_check_old(ctxptr->drive->type)) { + if (drive_check_old(ctxptr->type)) { if (riotcore_snapshot_read_module(ctxptr->riot1, s) < 0 || riotcore_snapshot_read_module(ctxptr->riot2, s) < 0 || fdc_snapshot_read_module(s, ctxptr->mynumber) < 0) { @@ -153,16 +158,16 @@ int ieee_drive_snapshot_read(struct drive_context_s *ctxptr, return 0; } -int ieee_drive_snapshot_write(struct drive_context_s *ctxptr, +int ieee_drive_snapshot_write(struct diskunit_context_s *ctxptr, struct snapshot_s *s) { - if (ctxptr->drive->type == DRIVE_TYPE_2031) { + if (ctxptr->type == DRIVE_TYPE_2031) { if (viacore_snapshot_write_module(ctxptr->via1d2031, s) < 0) { return -1; } } - if (drive_check_old(ctxptr->drive->type)) { + if (drive_check_old(ctxptr->type)) { if (riotcore_snapshot_write_module(ctxptr->riot1, s) < 0 || riotcore_snapshot_write_module(ctxptr->riot2, s) < 0 || fdc_snapshot_write_module(s, ctxptr->mynumber) < 0) { @@ -173,17 +178,17 @@ int ieee_drive_snapshot_write(struct drive_context_s *ctxptr, return 0; } -int ieee_drive_image_attach(struct disk_image_s *image, unsigned int unit) +int ieee_drive_image_attach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return fdc_attach_image(image, unit); + return fdc_attach_image(image, unit, drive); } -int ieee_drive_image_detach(struct disk_image_s *image, unsigned int unit) +int ieee_drive_image_detach(struct disk_image_s *image, unsigned int unit, unsigned int drive) { - return fdc_detach_image(image, unit); + return fdc_detach_image(image, unit, drive); } -void ieee_drive_parallel_set_atn(int state, drive_context_t *drv) +void ieee_drive_parallel_set_atn(int state, diskunit_context_t *drv) { via1d2031_set_atn(drv->via1d2031, state); riot2_set_atn(drv->riot2, state); diff --git a/src/Emulators/vice/drive/ieee/ieeerom.c b/src/Emulators/vice/drive/ieee/ieeerom.c index 5c66b052..2f299716 100644 --- a/src/Emulators/vice/drive/ieee/ieeerom.c +++ b/src/Emulators/vice/drive/ieee/ieeerom.c @@ -41,93 +41,129 @@ /* Logging goes here. */ static log_t ieeerom_log; -#ifdef USE_EMBEDDED -#include "drivedos2031.h" -#include "drivedos1001.h" -#include "drivedos2040.h" -#include "drivedos3040.h" -#include "drivedos4040.h" -#else -static BYTE drive_rom2031[DRIVE_ROM2031_SIZE]; -static BYTE drive_rom1001[DRIVE_ROM1001_SIZE]; -static BYTE drive_rom2040[DRIVE_ROM2040_SIZE]; -static BYTE drive_rom3040[DRIVE_ROM3040_SIZE]; -static BYTE drive_rom4040[DRIVE_ROM4040_SIZE]; -#endif - -/* If nonzero, the ROM image has been loaded. */ +/* If nonzero, the ROM image is available */ static unsigned int rom2031_loaded = 0; static unsigned int rom2040_loaded = 0; static unsigned int rom3040_loaded = 0; static unsigned int rom4040_loaded = 0; static unsigned int rom1001_loaded = 0; +static unsigned int rom9000_loaded = 0; +/* test ROM for existence, size */ int ieeerom_load_2031(void) { - return driverom_load("DosName2031", drive_rom2031, &rom2031_loaded, + return driverom_test_load("DosName2031", &rom2031_loaded, DRIVE_ROM2031_SIZE, DRIVE_ROM2031_SIZE, "2031", DRIVE_TYPE_2031, NULL); } int ieeerom_load_2040(void) { - return driverom_load("DosName2040", drive_rom2040, &rom2040_loaded, + return driverom_test_load("DosName2040", &rom2040_loaded, DRIVE_ROM2040_SIZE, DRIVE_ROM2040_SIZE, "2040", DRIVE_TYPE_2040, NULL); } int ieeerom_load_3040(void) { - return driverom_load("DosName3040", drive_rom3040, &rom3040_loaded, + return driverom_test_load("DosName3040", &rom3040_loaded, DRIVE_ROM3040_SIZE, DRIVE_ROM3040_SIZE, "3040", DRIVE_TYPE_3040, NULL); } int ieeerom_load_4040(void) { - return driverom_load("DosName4040", drive_rom4040, &rom4040_loaded, + return driverom_test_load("DosName4040", &rom4040_loaded, DRIVE_ROM4040_SIZE, DRIVE_ROM4040_SIZE, "4040", DRIVE_TYPE_4040, NULL); } int ieeerom_load_1001(void) { - return driverom_load("DosName1001", drive_rom1001, &rom1001_loaded, + return driverom_test_load("DosName1001", &rom1001_loaded, DRIVE_ROM1001_SIZE, DRIVE_ROM1001_SIZE, "1001/8050/8250", DRIVE_TYPE_1001, NULL); } -void ieeerom_setup_image(drive_t *drive) +int ieeerom_load_9000(void) { + return driverom_test_load("DosName9000", &rom9000_loaded, + DRIVE_ROM9000_SIZE, DRIVE_ROM9000_SIZE, "D9090/9060", + DRIVE_TYPE_9000, NULL); +} + +/* setup (=load) the ROM for a given disk unit */ +void ieeerom_setup_image(diskunit_context_t *unit) +{ + unsigned int loaded = 0; if (rom_loaded) { - switch (drive->type) { - case DRIVE_TYPE_2031: - memcpy(&(drive->rom[0x4000]), drive_rom2031, - DRIVE_ROM2031_SIZE); - break; - case DRIVE_TYPE_2040: - memcpy(&(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]), - drive_rom2040, DRIVE_ROM2040_SIZE); - break; - case DRIVE_TYPE_3040: - memcpy(&(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]), - drive_rom3040, DRIVE_ROM3040_SIZE); - break; - case DRIVE_TYPE_4040: - memcpy(&(drive->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]), - drive_rom4040, DRIVE_ROM4040_SIZE); - break; - case DRIVE_TYPE_1001: - case DRIVE_TYPE_8050: - case DRIVE_TYPE_8250: - memcpy(&(drive->rom[0x4000]), drive_rom1001, - DRIVE_ROM1001_SIZE); - break; + if (unit->rom_type != unit->type) { + /* set this here to avoid recursion */ + unit->rom_type = unit->type; + + switch (unit->type) { + case DRIVE_TYPE_2031: + driverom_load("DosName2031", unit->rom, &rom2031_loaded, + DRIVE_ROM2031_SIZE, DRIVE_ROM2031_SIZE, "2031", + DRIVE_TYPE_2031, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[0x4000]), unit->rom, + DRIVE_ROM2031_SIZE); + break; + case DRIVE_TYPE_2040: + driverom_load("DosName2040", unit->rom, &rom2040_loaded, + DRIVE_ROM2040_SIZE, DRIVE_ROM2040_SIZE, "2040", + DRIVE_TYPE_2040, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM2040_SIZE]), + unit->rom, DRIVE_ROM2040_SIZE); + break; + case DRIVE_TYPE_3040: + driverom_load("DosName3040", unit->rom, &rom3040_loaded, + DRIVE_ROM3040_SIZE, DRIVE_ROM3040_SIZE, "3040", + DRIVE_TYPE_3040, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM3040_SIZE]), + unit->rom, DRIVE_ROM3040_SIZE); + break; + case DRIVE_TYPE_4040: + driverom_load("DosName4040", unit->rom, &rom4040_loaded, + DRIVE_ROM4040_SIZE, DRIVE_ROM4040_SIZE, "4040", + DRIVE_TYPE_4040, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[DRIVE_ROM_SIZE - DRIVE_ROM4040_SIZE]), + unit->rom, DRIVE_ROM4040_SIZE); + break; + case DRIVE_TYPE_1001: + case DRIVE_TYPE_8050: + case DRIVE_TYPE_8250: + driverom_load("DosName1001", unit->rom, &rom1001_loaded, + DRIVE_ROM1001_SIZE, DRIVE_ROM1001_SIZE, "1001/8050/8250", + DRIVE_TYPE_1001, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[0x4000]), unit->rom, + DRIVE_ROM1001_SIZE); + break; + case DRIVE_TYPE_9000: + driverom_load("DosName9000", unit->rom, &rom9000_loaded, + DRIVE_ROM9000_SIZE, DRIVE_ROM9000_SIZE, "D9090/9060", + DRIVE_TYPE_9000, NULL); + /* ROM was loaded to the lower part of the buffer */ + memcpy(&(unit->rom[0x4000]), unit->rom, + DRIVE_ROM9000_SIZE); + break; + } + + /* if loading failed, set rom type to 0 */ + if (!loaded) { + unit->rom_type = 0; + } } } } +/* check if the drive ROM is available for a given drive type, returns -1 on error */ int ieeerom_check_loaded(unsigned int type) { switch (type) { @@ -160,9 +196,15 @@ int ieeerom_check_loaded(unsigned int type) return -1; } break; + case DRIVE_TYPE_9000: + if (rom9000_loaded < 1 && rom_loaded) { + return -1; + } + break; case DRIVE_TYPE_ANY: if ((!rom2031_loaded && !rom2040_loaded && !rom3040_loaded - && !rom4040_loaded && !rom1001_loaded) && rom_loaded) { + && !rom4040_loaded && !rom1001_loaded && !rom9000_loaded ) + && rom_loaded) { return -1; } break; diff --git a/src/Emulators/vice/drive/ieee/ieeerom.h b/src/Emulators/vice/drive/ieee/ieeerom.h index ab766346..7bc20cd4 100644 --- a/src/Emulators/vice/drive/ieee/ieeerom.h +++ b/src/Emulators/vice/drive/ieee/ieeerom.h @@ -31,14 +31,15 @@ struct drive_s; -extern void ieeerom_init(void); -extern void ieeerom_setup_image(struct drive_s *drive); -extern int ieeerom_check_loaded(unsigned int type); +void ieeerom_init(void); +void ieeerom_setup_image(struct diskunit_context_s *drive); +int ieeerom_check_loaded(unsigned int type); -extern int ieeerom_load_2031(void); -extern int ieeerom_load_1001(void); -extern int ieeerom_load_2040(void); -extern int ieeerom_load_3040(void); -extern int ieeerom_load_4040(void); +int ieeerom_load_2031(void); +int ieeerom_load_1001(void); +int ieeerom_load_2040(void); +int ieeerom_load_3040(void); +int ieeerom_load_4040(void); +int ieeerom_load_9000(void); #endif diff --git a/src/Emulators/vice/drive/ieee/memieee.c b/src/Emulators/vice/drive/ieee/memieee.c index 921a6b0a..1d72cbe5 100644 --- a/src/Emulators/vice/drive/ieee/memieee.c +++ b/src/Emulators/vice/drive/ieee/memieee.c @@ -43,38 +43,41 @@ // return drv->drive->rom[address & 0x7fff]; //} -static BYTE drive_read_2031ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_2031ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[address & 0x7ff]; + return drv->cpu->cpu_last_data = drv->drive_ram[address & 0x7ff]; } -static void drive_store_2031ram(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_2031ram(diskunit_context_t *drv, uint16_t address, uint8_t value) { - drv->drive->drive_ram[address & 0x7ff] = value; + drv->cpu->cpu_last_data = value; + drv->drive_ram[address & 0x7ff] = value; } -static BYTE drive_read_zero(drive_context_t *drv, WORD address) +static uint8_t drive_read_zero(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[address & 0xff]; + return drv->cpu->cpu_last_data = drv->drive_ram[address & 0xff]; } -static void drive_store_zero(drive_context_t *drv, WORD address, BYTE value) +static void drive_store_zero(diskunit_context_t *drv, uint16_t address, uint8_t value) { - drv->drive->drive_ram[address & 0xff] = value; + drv->cpu->cpu_last_data = value; + drv->drive_ram[address & 0xff] = value; } /* SFD1001 specific memory. */ -static BYTE drive_read_1001_io(drive_context_t *drv, WORD address) +static uint8_t drive_read_1001_io(diskunit_context_t *drv, uint16_t address) { if (address & 0x80) { - return riot2_read(drv, address); + return drv->cpu->cpu_last_data = riot2_read(drv, address); } - return riot1_read(drv, address); + return drv->cpu->cpu_last_data = riot1_read(drv, address); } -static void drive_store_1001_io(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_1001_io(diskunit_context_t *drv, uint16_t address, uint8_t byte) { + drv->cpu->cpu_last_data = byte; if (address & 0x80) { riot2_store(drv, address, byte); } else { @@ -82,7 +85,7 @@ static void drive_store_1001_io(drive_context_t *drv, WORD address, BYTE byte) } } -static BYTE drive_peek_1001_io(drive_context_t *drv, WORD address) +static uint8_t drive_peek_1001_io(diskunit_context_t *drv, uint16_t address) { if (address & 0x80) { return riot2_peek(drv, address); @@ -90,198 +93,230 @@ static BYTE drive_peek_1001_io(drive_context_t *drv, WORD address) return riot1_peek(drv, address); } -static BYTE drive_read_1001zero_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_1001zero_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[address & 0xff]; + return drv->cpu->cpu_last_data = drv->drive_ram[address & 0xff]; } -static void drive_store_1001zero_ram(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_1001zero_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[address & 0xff] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[address & 0xff] = byte; } -static BYTE drive_read_1001buffer1_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_1001buffer1_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[(address & 0x7ff) + 0x100]; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x100]; +} +static void drive_store_1001buffer1_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) +{ + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x100] = byte; } -static void drive_store_1001buffer1_ram(drive_context_t *drv, WORD address, BYTE byte) +static uint8_t drive_read_1001buffer2_ram(diskunit_context_t *drv, uint16_t address) { - drv->drive->drive_ram[(address & 0x7ff) + 0x100] = byte; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x500]; +} +static void drive_store_1001buffer2_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) +{ + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x500] = byte; } -static BYTE drive_read_1001buffer2_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_1001buffer3_ram(diskunit_context_t *drv, uint16_t address) +{ + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x900]; +} +static void drive_store_1001buffer3_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - return drv->drive->drive_ram[(address & 0x7ff) + 0x900]; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x900] = byte; } -static void drive_store_1001buffer2_ram(drive_context_t *drv, WORD address, BYTE byte) +static uint8_t drive_read_1001buffer4_ram(diskunit_context_t *drv, uint16_t address) +{ + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0xd00]; +} +static void drive_store_1001buffer4_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[(address & 0x7ff) + 0x900] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0xd00] = byte; } -static BYTE drive_read_2040buffer1_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_2040buffer1_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[(address & 0x3ff) + 0x100]; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x100]; } -static void drive_store_2040buffer1_ram(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_2040buffer1_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[(address & 0x3ff) + 0x100] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x100] = byte; } -static BYTE drive_read_2040buffer2_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_2040buffer2_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[(address & 0x3ff) + 0x500]; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x500]; } -static void drive_store_2040buffer2_ram(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_2040buffer2_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[(address & 0x3ff) + 0x500] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x500] = byte; } -static BYTE drive_read_2040buffer3_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_2040buffer3_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[(address & 0x3ff) + 0x900]; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0x900]; } -static void drive_store_2040buffer3_ram(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_2040buffer3_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[(address & 0x3ff) + 0x900] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0x900] = byte; } -static BYTE drive_read_2040buffer4_ram(drive_context_t *drv, WORD address) +static uint8_t drive_read_2040buffer4_ram(diskunit_context_t *drv, uint16_t address) { - return drv->drive->drive_ram[(address & 0x3ff) + 0xd00]; + return drv->cpu->cpu_last_data = drv->drive_ram[(address & 0x3ff) + 0xd00]; } -static void drive_store_2040buffer4_ram(drive_context_t *drv, WORD address, BYTE byte) +static void drive_store_2040buffer4_ram(diskunit_context_t *drv, uint16_t address, uint8_t byte) { - drv->drive->drive_ram[(address & 0x3ff) + 0xd00] = byte; + drv->cpu->cpu_last_data = byte; + drv->drive_ram[(address & 0x3ff) + 0xd00] = byte; } -void memieee_init(struct drive_context_s *drv, unsigned int type) +void memieee_init(struct diskunit_context_s *drv, unsigned int type) { drivecpud_context_t *cpud = drv->cpud; switch (type) { - case DRIVE_TYPE_2031: - drv->cpu->pageone = drv->drive->drive_ram + 0x100; - drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive->drive_ram, 0x000007fd); - drivemem_set_func(cpud, 0x01, 0x08, drive_read_2031ram, drive_store_2031ram, NULL, &drv->drive->drive_ram[0x0100], 0x000007fd); + case DRIVE_TYPE_2031: + drv->cpu->pageone = drv->drive_ram + 0x100; + drivemem_set_func(cpud, 0x00, 0x01, drive_read_zero, drive_store_zero, NULL, drv->drive_ram, 0x000007fd); + drivemem_set_func(cpud, 0x01, 0x08, drive_read_2031ram, drive_store_2031ram, NULL, &drv->drive_ram[0x0100], 0x000007fd); drivemem_set_func(cpud, 0x18, 0x1c, via1d2031_read, via1d2031_store, via1d2031_peek, NULL, 0); drivemem_set_func(cpud, 0x1c, 0x20, via2d_read, via2d_store, via2d_peek, NULL, 0); - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000bffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->trap_rom, 0x8000bffd); return; + + /* The 2040/3040/4040/1001/8050/8250/9090/9060 have 256 byte at $00xx, + mirrored at $01xx, $04xx, $05xx, $08xx, $09xx, $0cxx, $0dxx. + (From the 2 RIOT's 128 byte RAM each. The RIOT's I/O fill + the gaps, x00-7f the first and x80-ff the second, at + $02xx, $03xx, $06xx, $07xx, $0axx, $0bxx, $0exx, $0fxx). + Then we have 4k of buffers, at $1000-13ff, 2000-23ff, 3000-33ff + and 4000-43ff, each mirrored at $x400-$x7ff, $x800-$xbff, + and $xc00-$xfff. */ + case DRIVE_TYPE_1001: - drv->cpu->pageone = drv->drive->drive_ram; - drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x000000fd); + drv->cpu->pageone = drv->drive_ram; + drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x000000fd); drivemem_set_func(cpud, 0x02, 0x04, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x040004fd); + drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x040004fd); drivemem_set_func(cpud, 0x06, 0x08, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x080008fd); + drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x080008fd); drivemem_set_func(cpud, 0x0a, 0x0c, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x0c000cfd); + drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x0c000cfd); drivemem_set_func(cpud, 0x0e, 0x10, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x10, 0x18, drive_read_1001buffer1_ram, drive_store_1001buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x100017fd); - drivemem_set_func(cpud, 0x18, 0x20, drive_read_1001buffer1_ram, drive_store_1001buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x18001ffd); - drivemem_set_func(cpud, 0x20, 0x28, drive_read_1001buffer1_ram, drive_store_1001buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x200027fd); - drivemem_set_func(cpud, 0x28, 0x30, drive_read_1001buffer1_ram, drive_store_1001buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x28002ffd); - drivemem_set_func(cpud, 0x30, 0x38, drive_read_1001buffer2_ram, drive_store_1001buffer2_ram, NULL, &drv->drive->drive_ram[0x0900], 0x300037fd); - drivemem_set_func(cpud, 0x38, 0x40, drive_read_1001buffer2_ram, drive_store_1001buffer2_ram, NULL, &drv->drive->drive_ram[0x0900], 0x38003ffd); - drivemem_set_func(cpud, 0x40, 0x48, drive_read_1001buffer2_ram, drive_store_1001buffer2_ram, NULL, &drv->drive->drive_ram[0x0900], 0x400047fd); - drivemem_set_func(cpud, 0x48, 0x50, drive_read_1001buffer2_ram, drive_store_1001buffer2_ram, NULL, &drv->drive->drive_ram[0x0900], 0x48004ffd); - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000fffd); + drivemem_set_func(cpud, 0x10, 0x20, drive_read_1001buffer1_ram, drive_store_1001buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x10001ffd); + drivemem_set_func(cpud, 0x20, 0x30, drive_read_1001buffer2_ram, drive_store_1001buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x20002ffd); + drivemem_set_func(cpud, 0x30, 0x40, drive_read_1001buffer3_ram, drive_store_1001buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x30003ffd); + drivemem_set_func(cpud, 0x40, 0x50, drive_read_1001buffer4_ram, drive_store_1001buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x40004ffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->trap_rom, 0x8000fffd); return; case DRIVE_TYPE_8050: case DRIVE_TYPE_8250: - drv->cpu->pageone = drv->drive->drive_ram; - drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x000000fd); + case DRIVE_TYPE_9000: + drv->cpu->pageone = drv->drive_ram; + drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x000000fd); drivemem_set_func(cpud, 0x02, 0x04, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x040004fd); + drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x040004fd); drivemem_set_func(cpud, 0x06, 0x08, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x080008fd); + drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x080008fd); drivemem_set_func(cpud, 0x0a, 0x0c, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x0c000cfd); + drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x0c000cfd); drivemem_set_func(cpud, 0x0e, 0x10, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x10, 0x14, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x100013fd); - drivemem_set_func(cpud, 0x14, 0x18, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x140017fd); - drivemem_set_func(cpud, 0x18, 0x1c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x18001bfd); - drivemem_set_func(cpud, 0x1c, 0x20, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x1c001ffd); - drivemem_set_func(cpud, 0x20, 0x34, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x200023fd); - drivemem_set_func(cpud, 0x24, 0x38, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x240027fd); - drivemem_set_func(cpud, 0x28, 0x3c, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x28002bfd); - drivemem_set_func(cpud, 0x2c, 0x40, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x2c002ffd); - drivemem_set_func(cpud, 0x30, 0x34, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x300033fd); - drivemem_set_func(cpud, 0x34, 0x38, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x340037fd); - drivemem_set_func(cpud, 0x38, 0x3c, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x38003bfd); - drivemem_set_func(cpud, 0x3c, 0x40, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x3c003ffd); - drivemem_set_func(cpud, 0x40, 0x44, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x400043fd); - drivemem_set_func(cpud, 0x44, 0x48, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x440047fd); - drivemem_set_func(cpud, 0x48, 0x4c, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x48004bfd); - drivemem_set_func(cpud, 0x4c, 0x50, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x4c004ffd); - drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->drive->trap_rom, 0x8000fffd); + drivemem_set_func(cpud, 0x10, 0x14, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x100013fd); + drivemem_set_func(cpud, 0x14, 0x18, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x140017fd); + drivemem_set_func(cpud, 0x18, 0x1c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x18001bfd); + drivemem_set_func(cpud, 0x1c, 0x20, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x1c001ffd); + drivemem_set_func(cpud, 0x20, 0x34, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x200023fd); + drivemem_set_func(cpud, 0x24, 0x38, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x240027fd); + drivemem_set_func(cpud, 0x28, 0x3c, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x28002bfd); + drivemem_set_func(cpud, 0x2c, 0x40, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x2c002ffd); + drivemem_set_func(cpud, 0x30, 0x34, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x300033fd); + drivemem_set_func(cpud, 0x34, 0x38, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x340037fd); + drivemem_set_func(cpud, 0x38, 0x3c, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x38003bfd); + drivemem_set_func(cpud, 0x3c, 0x40, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x3c003ffd); + drivemem_set_func(cpud, 0x40, 0x44, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x400043fd); + drivemem_set_func(cpud, 0x44, 0x48, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x440047fd); + drivemem_set_func(cpud, 0x48, 0x4c, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x48004bfd); + drivemem_set_func(cpud, 0x4c, 0x50, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x4c004ffd); + drivemem_set_func(cpud, 0x80, 0x100, drive_read_rom, NULL, NULL, drv->trap_rom, 0x8000fffd); return; case DRIVE_TYPE_2040: - drivemem_set_func(cpud, 0x60, 0x80, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x2000], 0x60007ffd); - drivemem_set_func(cpud, 0xe0, 0x100, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x2000], 0xe000fffd); + drivemem_set_func(cpud, 0x60, 0x80, drive_read_rom, NULL, NULL, &drv->trap_rom[0x6000], 0x60007ffd); + drivemem_set_func(cpud, 0xe0, 0x100, drive_read_rom, NULL, NULL, &drv->trap_rom[0x6000], 0xe000fffd); break; case DRIVE_TYPE_3040: case DRIVE_TYPE_4040: - drivemem_set_func(cpud, 0x50, 0x80, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x1000], 0x50007ffd); - drivemem_set_func(cpud, 0xd0, 0x100, drive_read_rom, NULL, NULL, &drv->drive->trap_rom[0x1000], 0xd000fffd); + drivemem_set_func(cpud, 0x50, 0x80, drive_read_rom, NULL, NULL, &drv->trap_rom[0x5000], 0x50007ffd); + drivemem_set_func(cpud, 0xd0, 0x100, drive_read_rom, NULL, NULL, &drv->trap_rom[0x5000], 0xd000fffd); break; default: return; } - drv->cpu->pageone = drv->drive->drive_ram; - drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x000000fd); + drv->cpu->pageone = drv->drive_ram; + drivemem_set_func(cpud, 0x00, 0x02, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x000000fd); drivemem_set_func(cpud, 0x02, 0x04, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x040004fd); + drivemem_set_func(cpud, 0x04, 0x06, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x040004fd); drivemem_set_func(cpud, 0x06, 0x08, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x080008fd); + drivemem_set_func(cpud, 0x08, 0x0a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x080008fd); drivemem_set_func(cpud, 0x0a, 0x0c, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x0c000cfd); + drivemem_set_func(cpud, 0x0c, 0x0e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x0c000cfd); drivemem_set_func(cpud, 0x0e, 0x10, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x10, 0x14, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x100013fd); - drivemem_set_func(cpud, 0x14, 0x18, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x140017fd); - drivemem_set_func(cpud, 0x18, 0x1c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x18001bfd); - drivemem_set_func(cpud, 0x1c, 0x20, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x1c001ffd); - drivemem_set_func(cpud, 0x20, 0x34, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x200023fd); - drivemem_set_func(cpud, 0x24, 0x38, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x240027fd); - drivemem_set_func(cpud, 0x28, 0x3c, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x28002bfd); - drivemem_set_func(cpud, 0x2c, 0x40, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0x2c002ffd); - drivemem_set_func(cpud, 0x30, 0x34, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x300033fd); - drivemem_set_func(cpud, 0x34, 0x38, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x340037fd); - drivemem_set_func(cpud, 0x38, 0x3c, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x38003bfd); - drivemem_set_func(cpud, 0x3c, 0x40, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0x3c003ffd); - drivemem_set_func(cpud, 0x40, 0x44, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x400043fd); - drivemem_set_func(cpud, 0x44, 0x48, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x440047fd); - drivemem_set_func(cpud, 0x48, 0x4c, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x48004bfd); - drivemem_set_func(cpud, 0x4c, 0x50, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0x4c004ffd); - drivemem_set_func(cpud, 0x80, 0x82, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x000000fd); + drivemem_set_func(cpud, 0x10, 0x14, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x100013fd); + drivemem_set_func(cpud, 0x14, 0x18, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x140017fd); + drivemem_set_func(cpud, 0x18, 0x1c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x18001bfd); + drivemem_set_func(cpud, 0x1c, 0x20, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x1c001ffd); + drivemem_set_func(cpud, 0x20, 0x34, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x200023fd); + drivemem_set_func(cpud, 0x24, 0x38, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x240027fd); + drivemem_set_func(cpud, 0x28, 0x3c, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x28002bfd); + drivemem_set_func(cpud, 0x2c, 0x40, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0x2c002ffd); + drivemem_set_func(cpud, 0x30, 0x34, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x300033fd); + drivemem_set_func(cpud, 0x34, 0x38, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x340037fd); + drivemem_set_func(cpud, 0x38, 0x3c, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x38003bfd); + drivemem_set_func(cpud, 0x3c, 0x40, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0x3c003ffd); + drivemem_set_func(cpud, 0x40, 0x44, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x400043fd); + drivemem_set_func(cpud, 0x44, 0x48, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x440047fd); + drivemem_set_func(cpud, 0x48, 0x4c, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x48004bfd); + drivemem_set_func(cpud, 0x4c, 0x50, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0x4c004ffd); + drivemem_set_func(cpud, 0x80, 0x82, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x000000fd); drivemem_set_func(cpud, 0x82, 0x84, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x84, 0x86, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x040004fd); + drivemem_set_func(cpud, 0x84, 0x86, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x040004fd); drivemem_set_func(cpud, 0x86, 0x88, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x88, 0x8a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x080008fd); + drivemem_set_func(cpud, 0x88, 0x8a, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x080008fd); drivemem_set_func(cpud, 0x8a, 0x8c, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x8c, 0x8e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive->drive_ram, 0x0c000cfd); + drivemem_set_func(cpud, 0x8c, 0x8e, drive_read_1001zero_ram, drive_store_1001zero_ram, NULL, drv->drive_ram, 0x0c000cfd); drivemem_set_func(cpud, 0x8e, 0x90, drive_read_1001_io, drive_store_1001_io, drive_peek_1001_io, NULL, 0); - drivemem_set_func(cpud, 0x90, 0x94, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x900093fd); - drivemem_set_func(cpud, 0x94, 0x98, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x940097fd); - drivemem_set_func(cpud, 0x98, 0x9c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x98009bfd); - drivemem_set_func(cpud, 0x9c, 0xa0, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive->drive_ram[0x0100], 0x9c009ffd); - drivemem_set_func(cpud, 0xa0, 0xb4, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0xa000a3fd); - drivemem_set_func(cpud, 0xa4, 0xb8, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0xa400a7fd); - drivemem_set_func(cpud, 0xa8, 0xbc, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0xa800abfd); - drivemem_set_func(cpud, 0xac, 0xc0, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive->drive_ram[0x0500], 0xac00affd); - drivemem_set_func(cpud, 0xb0, 0xb4, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0xb000b3fd); - drivemem_set_func(cpud, 0xb4, 0xb8, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0xb400b7fd); - drivemem_set_func(cpud, 0xb8, 0xbc, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0xb800bbfd); - drivemem_set_func(cpud, 0xbc, 0xc0, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive->drive_ram[0x0900], 0xbc00bffd); - drivemem_set_func(cpud, 0xc0, 0xc4, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0xc000c3fd); - drivemem_set_func(cpud, 0xc4, 0xc8, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0xc400c7fd); - drivemem_set_func(cpud, 0xc8, 0xcc, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0xc800cbfd); - drivemem_set_func(cpud, 0xcc, 0xd0, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive->drive_ram[0x0d00], 0xcc00cffd); + drivemem_set_func(cpud, 0x90, 0x94, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x900093fd); + drivemem_set_func(cpud, 0x94, 0x98, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x940097fd); + drivemem_set_func(cpud, 0x98, 0x9c, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x98009bfd); + drivemem_set_func(cpud, 0x9c, 0xa0, drive_read_2040buffer1_ram, drive_store_2040buffer1_ram, NULL, &drv->drive_ram[0x0100], 0x9c009ffd); + drivemem_set_func(cpud, 0xa0, 0xb4, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0xa000a3fd); + drivemem_set_func(cpud, 0xa4, 0xb8, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0xa400a7fd); + drivemem_set_func(cpud, 0xa8, 0xbc, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0xa800abfd); + drivemem_set_func(cpud, 0xac, 0xc0, drive_read_2040buffer2_ram, drive_store_2040buffer2_ram, NULL, &drv->drive_ram[0x0500], 0xac00affd); + drivemem_set_func(cpud, 0xb0, 0xb4, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0xb000b3fd); + drivemem_set_func(cpud, 0xb4, 0xb8, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0xb400b7fd); + drivemem_set_func(cpud, 0xb8, 0xbc, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0xb800bbfd); + drivemem_set_func(cpud, 0xbc, 0xc0, drive_read_2040buffer3_ram, drive_store_2040buffer3_ram, NULL, &drv->drive_ram[0x0900], 0xbc00bffd); + drivemem_set_func(cpud, 0xc0, 0xc4, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0xc000c3fd); + drivemem_set_func(cpud, 0xc4, 0xc8, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0xc400c7fd); + drivemem_set_func(cpud, 0xc8, 0xcc, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0xc800cbfd); + drivemem_set_func(cpud, 0xcc, 0xd0, drive_read_2040buffer4_ram, drive_store_2040buffer4_ram, NULL, &drv->drive_ram[0x0d00], 0xcc00cffd); } diff --git a/src/Emulators/vice/drive/ieee/memieee.h b/src/Emulators/vice/drive/ieee/memieee.h index 125bc5d6..93aa4de4 100644 --- a/src/Emulators/vice/drive/ieee/memieee.h +++ b/src/Emulators/vice/drive/ieee/memieee.h @@ -27,8 +27,8 @@ #ifndef VICE_MEMIEEE_H #define VICE_MEMIEEE_H -struct drive_context_s; +struct diskunit_context_s; -extern void memieee_init(struct drive_context_s *drv, unsigned int type); +void memieee_init(struct diskunit_context_s *drv, unsigned int type); #endif diff --git a/src/Emulators/vice/drive/ieee/riot1d.c b/src/Emulators/vice/drive/ieee/riot1d.c index 59da4060..2c9a1ab0 100644 --- a/src/Emulators/vice/drive/ieee/riot1d.c +++ b/src/Emulators/vice/drive/ieee/riot1d.c @@ -38,28 +38,22 @@ #include "vicetypes.h" -void riot1_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void riot1_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; riotcore_store(ctxptr->riot1, addr, data); } -BYTE riot1_read(drive_context_t *ctxptr, WORD addr) +uint8_t riot1_read(diskunit_context_t *ctxptr, uint16_t addr) { - return riotcore_read(ctxptr->riot1, addr); + return ctxptr->cpu->cpu_last_data = riotcore_read(ctxptr->riot1, addr); } -BYTE riot1_peek(drive_context_t *ctxptr, WORD addr) +uint8_t riot1_peek(diskunit_context_t *ctxptr, uint16_t addr) { return riotcore_peek(ctxptr->riot1, addr); } -int riot1_dump(drive_context_t *ctxptr, WORD addr) -{ - /* TODO: implement dump feature */ - /* riotcore_dump(ctxptr->riot1, addr); */ - return -1; -} - static void set_irq(riot_context_t *riot_context, int fl, CLOCK clk) { } @@ -68,30 +62,30 @@ static void restore_irq(riot_context_t *riot_context, int fl) { } -static void undump_pra(riot_context_t *riot_context, BYTE byte) +static void undump_pra(riot_context_t *riot_context, uint8_t byte) { } -static void store_pra(riot_context_t *riot_context, BYTE byte) +static void store_pra(riot_context_t *riot_context, uint8_t byte) { } -static void undump_prb(riot_context_t *riot_context, BYTE byte) +static void undump_prb(riot_context_t *riot_context, uint8_t byte) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); - drive_context->func->parallel_set_bus(byte); + dc->func->parallel_set_bus(byte); } -static void store_prb(riot_context_t *riot_context, BYTE byte) +static void store_prb(riot_context_t *riot_context, uint8_t byte) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); - drive_context->func->parallel_set_bus((BYTE)(parallel_atn ? 0xff : byte)); + dc->func->parallel_set_bus((uint8_t)(parallel_atn ? 0xff : byte)); } void riot1_set_pardata(riot_context_t *riot_context) @@ -104,25 +98,25 @@ static void reset(riot_context_t *riot_context) store_prb(riot_context, 0xff); } -static BYTE read_pra(riot_context_t *riot_context) +static uint8_t read_pra(riot_context_t *riot_context) { return (parallel_bus & ~(riot_context->riot_io)[1]) | (riot_context->riot_io[0] & riot_context->riot_io[1]); } -static BYTE read_prb(riot_context_t *riot_context) +static uint8_t read_prb(riot_context_t *riot_context) { return (0xff & ~(riot_context->riot_io)[3]) | (riot_context->riot_io[2] & riot_context->riot_io[3]); } -void riot1_init(drive_context_t *ctxptr) +void riot1_init(diskunit_context_t *ctxptr) { riotcore_init(ctxptr->riot1, ctxptr->cpu->alarm_context, - ctxptr->cpu->clk_guard, ctxptr->mynumber); + ctxptr->mynumber); } -void riot1_setup_context(drive_context_t *ctxptr) +void riot1_setup_context(diskunit_context_t *ctxptr) { riot_context_t *riot; @@ -137,7 +131,7 @@ void riot1_setup_context(drive_context_t *ctxptr) riotcore_setup_context(riot); - riot->myname = lib_msprintf("RIOT1D%d", ctxptr->mynumber); + riot->myname = lib_msprintf("RIOT1D%u", ctxptr->mynumber); riot->undump_pra = undump_pra; riot->undump_prb = undump_prb; diff --git a/src/Emulators/vice/drive/ieee/riot2d.c b/src/Emulators/vice/drive/ieee/riot2d.c index d60a4063..73e04030 100644 --- a/src/Emulators/vice/drive/ieee/riot2d.c +++ b/src/Emulators/vice/drive/ieee/riot2d.c @@ -41,66 +41,59 @@ typedef struct driveriot2_context_s { - unsigned int number; - BYTE drivenumberjumper; - struct drive_s *drive; + uint8_t drivenumberjumper; + drive_t *drives[2]; int r_atn_active; /* init to 0 */ unsigned int int_num; } driveriot2_context_t; -void riot2_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void riot2_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; riotcore_store(ctxptr->riot2, addr, data); } -BYTE riot2_read(drive_context_t *ctxptr, WORD addr) +uint8_t riot2_read(diskunit_context_t *ctxptr, uint16_t addr) { - return riotcore_read(ctxptr->riot2, addr); + return ctxptr->cpu->cpu_last_data = riotcore_read(ctxptr->riot2, addr); } -BYTE riot2_peek(drive_context_t *ctxptr, WORD addr) +uint8_t riot2_peek(diskunit_context_t *ctxptr, uint16_t addr) { return riotcore_peek(ctxptr->riot2, addr); } -int riot2_dump(drive_context_t *ctxptr, WORD addr) -{ - /* TODO: implement dump feature */ - /* riotcore_dump(ctxptr->riot2, addr); */ - return -1; -} - static void set_irq(riot_context_t *riot_context, int fl, CLOCK clk) { - drive_context_t *drive_context; + diskunit_context_t *dc; driveriot2_context_t *riot2p; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); riot2p = (driveriot2_context_t *)(riot_context->prv); - interrupt_set_irq(drive_context->cpu->int_status, (riot2p->int_num), + interrupt_set_irq(dc->cpu->int_status, (riot2p->int_num), (fl) ? IK_IRQ : 0, clk); } static void restore_irq(riot_context_t *riot_context, int fl) { - drive_context_t *drive_context; + diskunit_context_t *dc; driveriot2_context_t *riot2p; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); riot2p = (driveriot2_context_t *)(riot_context->prv); - interrupt_restore_irq(drive_context->cpu->int_status, riot2p->int_num, + interrupt_restore_irq(dc->cpu->int_status, riot2p->int_num, (fl) ? IK_IRQ : 0); } -static void set_handshake(riot_context_t *riot_context, BYTE pa) +static void set_handshake(riot_context_t *riot_context, uint8_t pa) { - drive_context_t *drive_context; + diskunit_context_t *dc; driveriot2_context_t *riot2p; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); riot2p = (driveriot2_context_t *)(riot_context->prv); /* IEEE handshake logic (named as in schematics): @@ -112,24 +105,24 @@ static void set_handshake(riot_context_t *riot_context, BYTE pa) RFDO = (/ATN == ATNA) & RFDO -> to IEEE via MC3446 */ /* RFDO = (/ATN == ATNA) & RFDO */ - drive_context->func->parallel_set_nrfd((char)( + dc->func->parallel_set_nrfd((char)( !(((riot2p->r_atn_active ? 1 : 0) == (pa & 1)) && (pa & 4)) )); /* DACO = /DACO & (ATNA | ATN) */ - drive_context->func->parallel_set_ndac((char)( + dc->func->parallel_set_ndac((char)( !((!(pa & 2)) && ((pa & 1) || (!(riot2p->r_atn_active)))) )); } void riot2_set_atn(riot_context_t *riot_context, int state) { - drive_context_t *drive_context; + diskunit_context_t *dc; driveriot2_context_t *riot2p; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); riot2p = (driveriot2_context_t *)(riot_context->prv); - if (drive_check_old(riot2p->drive->type)) { + if (drive_check_old(dc->type)) { if (riot2p->r_atn_active && !state) { riotcore_signal(riot_context, RIOT_SIG_PA7, RIOT_SIG_FALL); } else @@ -137,28 +130,28 @@ void riot2_set_atn(riot_context_t *riot_context, int state) riotcore_signal(riot_context, RIOT_SIG_PA7, RIOT_SIG_RISE); } riot2p->r_atn_active = state; - riot1_set_pardata(drive_context->riot1); + riot1_set_pardata(dc->riot1); set_handshake(riot_context, riot_context->old_pa); } } -static void undump_pra(riot_context_t *riot_context, BYTE byte) +static void undump_pra(riot_context_t *riot_context, uint8_t byte) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); /* bit 0 = atna */ set_handshake(riot_context, byte); - drive_context->func->parallel_set_eoi((BYTE)(!(byte & 0x08))); - drive_context->func->parallel_set_dav((BYTE)(!(byte & 0x10))); + dc->func->parallel_set_eoi((uint8_t)(!(byte & 0x08))); + dc->func->parallel_set_dav((uint8_t)(!(byte & 0x10))); } -static void store_pra(riot_context_t *riot_context, BYTE byte) +static void store_pra(riot_context_t *riot_context, uint8_t byte) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); /* bit 0 = atna */ /* bit 1 = /daco */ @@ -166,13 +159,14 @@ static void store_pra(riot_context_t *riot_context, BYTE byte) /* bit 3 = eoio */ /* bit 4 = davo */ set_handshake(riot_context, byte); /* handle atna, nrfd, ndac */ - drive_context->func->parallel_set_eoi((BYTE)(!(byte & 0x08))); - drive_context->func->parallel_set_dav((BYTE)(!(byte & 0x10))); + dc->func->parallel_set_eoi((uint8_t)(!(byte & 0x08))); + dc->func->parallel_set_dav((uint8_t)(!(byte & 0x10))); } -static void undump_prb(riot_context_t *riot_context, BYTE byte) +static void undump_prb(riot_context_t *riot_context, uint8_t byte) { driveriot2_context_t *riot2p; + drive_t *drive; riot2p = (driveriot2_context_t *)(riot_context->prv); @@ -180,22 +174,30 @@ static void undump_prb(riot_context_t *riot_context, BYTE byte) /* bit 4 Act LED 0 */ /* bit 5 Error LED */ - /* 1001 only needs LED 0 and Error LED */ - riot2p->drive->led_status = (byte >> 4) & 0x03; + /* + * SFD-1001 only needs LED 0 and Error LED, but the drives[1] structure + * is attached anyway. + */ + drive = riot2p->drives[0]; + drive->led_status = (byte >> 4) & 0x03; - if ((is_drive0(riot2p->number)) && (drive_check_dual(riot2p->drive->type))) { - drive_context[mk_drive1(riot2p->number)]->drive->led_status - = ((byte & 8) ? 1 : 0) | ((byte & 32) ? 2 : 0); + if (drive->led_status & 1) { + drive->led_active_ticks += *(riot_context->clk_ptr) + - drive->led_last_change_clk; } + drive->led_last_change_clk = *(riot_context->clk_ptr); - if (riot2p->drive->led_status & 1) { - riot2p->drive->led_active_ticks += *(riot_context->clk_ptr) - - riot2p->drive->led_last_change_clk; + drive = riot2p->drives[1]; + drive->led_status = (byte >> 3) & 0x01; + + if (drive->led_status & 1) { + drive->led_active_ticks += *(riot_context->clk_ptr) + - drive->led_last_change_clk; } - riot2p->drive->led_last_change_clk = *(riot_context->clk_ptr); + drive->led_last_change_clk = *(riot_context->clk_ptr); } -static void store_prb(riot_context_t *riot_context, BYTE byte) +static void store_prb(riot_context_t *riot_context, uint8_t byte) { driveriot2_context_t *riot2p; @@ -206,36 +208,34 @@ static void store_prb(riot_context_t *riot_context, BYTE byte) /* bit 5 Error LED */ /* 1001 only needs LED 0 and Error LED */ - riot2p->drive->led_status = (byte >> 4) & 0x03; - - if ((is_drive0(riot2p->number)) && (drive_check_dual(riot2p->drive->type))) { - drive_context[mk_drive1(riot2p->number)]->drive->led_status - = ((byte & 8) ? 1 : 0) | ((byte & 32) ? 2 : 0); - } + riot2p->drives[0]->led_status = (byte >> 4) & 0x03; + riot2p->drives[1]->led_status = (byte >> 3) & 0x01; } static void reset(riot_context_t *riot_context) { - drive_context_t *drive_context; + diskunit_context_t *dc; driveriot2_context_t *riot2p; - drive_context = (drive_context_t *)(riot_context->context); + dc = (diskunit_context_t *)(riot_context->context); riot2p = (driveriot2_context_t *)(riot_context->prv); riot2p->r_atn_active = 0; - drive_context->func->parallel_set_dav(0); - drive_context->func->parallel_set_eoi(0); + dc->func->parallel_set_dav(0); + dc->func->parallel_set_eoi(0); set_handshake(riot_context, riot_context->old_pa); /* 1001 only needs LED 0 and Error LED */ - riot2p->drive->led_status = 3; + riot2p->drives[0]->led_status = 3; + riot2p->drives[1]->led_status = 1; } -static BYTE read_pra(riot_context_t *riot_context) +static uint8_t read_pra(riot_context_t *riot_context) { - BYTE byte = 0xff; + uint8_t byte = 0xff; + if (!parallel_atn) { byte -= 0x80; } @@ -249,10 +249,10 @@ static BYTE read_pra(riot_context_t *riot_context) | ((riot_context->riot_io)[0] & (riot_context->riot_io)[1]); } -static BYTE read_prb(riot_context_t *riot_context) +static uint8_t read_prb(riot_context_t *riot_context) { driveriot2_context_t *riot2p; - BYTE byte = 0xff - 7; + uint8_t byte = 0xff - 7; riot2p = (driveriot2_context_t *)(riot_context->prv); @@ -270,13 +270,13 @@ static BYTE read_prb(riot_context_t *riot_context) | ((riot_context->riot_io)[2] & (riot_context->riot_io)[3]); } -void riot2_init(drive_context_t *ctxptr) +void riot2_init(diskunit_context_t *ctxptr) { riotcore_init(ctxptr->riot2, ctxptr->cpu->alarm_context, - ctxptr->cpu->clk_guard, ctxptr->mynumber); + ctxptr->mynumber); } -void riot2_setup_context(drive_context_t *ctxptr) +void riot2_setup_context(diskunit_context_t *ctxptr) { riot_context_t *riot; driveriot2_context_t *riot2p; @@ -286,7 +286,6 @@ void riot2_setup_context(drive_context_t *ctxptr) riot->prv = lib_malloc(sizeof(driveriot2_context_t)); riot2p = (driveriot2_context_t *)(riot->prv); - riot2p->number = ctxptr->mynumber; riot2p->drivenumberjumper = ctxptr->mynumber & 0x07; /* 3 bits */ riot->context = (void *)ctxptr; @@ -296,9 +295,10 @@ void riot2_setup_context(drive_context_t *ctxptr) riotcore_setup_context(riot); - riot->myname = lib_msprintf("RIOT2D%d", ctxptr->mynumber); + riot->myname = lib_msprintf("RIOT2D%u", ctxptr->mynumber); - riot2p->drive = ctxptr->drive; + riot2p->drives[0] = ctxptr->drives[0]; + riot2p->drives[1] = ctxptr->drives[1]; riot2p->r_atn_active = 0; riot2p->int_num = interrupt_cpu_status_int_new(ctxptr->cpu->int_status, ctxptr->riot2->myname); diff --git a/src/Emulators/vice/drive/ieee/riotd.h b/src/Emulators/vice/drive/ieee/riotd.h index 93fe8980..9745b524 100644 --- a/src/Emulators/vice/drive/ieee/riotd.h +++ b/src/Emulators/vice/drive/ieee/riotd.h @@ -30,27 +30,25 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct riot_context_s; -extern void riot1_setup_context(struct drive_context_s *ctxptr); -extern void riot2_setup_context(struct drive_context_s *ctxptr); +void riot1_setup_context(struct diskunit_context_s *ctxptr); +void riot2_setup_context(struct diskunit_context_s *ctxptr); -extern void riot2_set_atn(struct riot_context_s *riot_context, int state); -extern void riot1_set_atn(struct riot_context_s *riot_context, BYTE state); +void riot2_set_atn(struct riot_context_s *riot_context, int state); +void riot1_set_atn(struct riot_context_s *riot_context, uint8_t state); -extern void riot1_set_pardata(struct riot_context_s *riot_context); +void riot1_set_pardata(struct riot_context_s *riot_context); -extern void riot1_init(struct drive_context_s *ctxptr); -extern void riot1_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE riot1_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE riot1_peek(struct drive_context_s *ctxptr, WORD addr); -extern int riot1_dump(struct drive_context_s *ctxptr, WORD addr); +void riot1_init(struct diskunit_context_s *ctxptr); +void riot1_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t riot1_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t riot1_peek(struct diskunit_context_s *ctxptr, uint16_t addr); -extern void riot2_init(struct drive_context_s *ctxptr); -extern void riot2_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE riot2_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE riot2_peek(struct drive_context_s *ctxptr, WORD addr); -extern int riot2_dump(struct drive_context_s *ctxptr, WORD addr); +void riot2_init(struct diskunit_context_s *ctxptr); +void riot2_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t riot2_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t riot2_peek(struct diskunit_context_s *ctxptr, uint16_t addr); #endif diff --git a/src/Emulators/vice/drive/ieee/via1d2031.c b/src/Emulators/vice/drive/ieee/via1d2031.c index 4558fe63..8da39a36 100644 --- a/src/Emulators/vice/drive/ieee/via1d2031.c +++ b/src/Emulators/vice/drive/ieee/via1d2031.c @@ -48,23 +48,24 @@ typedef struct drivevia1_context_s { unsigned int number; - BYTE drivenumberjumper; - struct drive_s *drive; + uint8_t drivenumberjumper; + struct diskunit_context_s *diskunit; int v_parieee_is_out; /* init to 1 */ } drivevia1_context_t; -void via1d2031_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void via1d2031_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; viacore_store(ctxptr->via1d2031, addr, data); } -BYTE via1d2031_read(drive_context_t *ctxptr, WORD addr) +uint8_t via1d2031_read(diskunit_context_t *ctxptr, uint16_t addr) { - return viacore_read(ctxptr->via1d2031, addr); + return ctxptr->cpu->cpu_last_data = viacore_read(ctxptr->via1d2031, addr); } -BYTE via1d2031_peek(drive_context_t *ctxptr, WORD addr) +uint8_t via1d2031_peek(diskunit_context_t *ctxptr, uint16_t addr) { return viacore_peek(ctxptr->via1d2031, addr); } @@ -73,35 +74,35 @@ static void set_ca2(via_context_t *via_context, int state) { } -static void set_cb2(via_context_t *via_context, int state) +static void set_cb2(via_context_t *via_context, int state, int offset) { } static void set_int(via_context_t *via_context, unsigned int int_num, int value, CLOCK rclk) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *)(via_context->context); - interrupt_set_irq(drive_context->cpu->int_status, int_num, value, rclk); + interrupt_set_irq(dc->cpu->int_status, int_num, value, rclk); } static void restore_int(via_context_t *via_context, unsigned int int_num, int value) { - drive_context_t *drive_context; + diskunit_context_t *dc; - drive_context = (drive_context_t *)(via_context->context); + dc = (diskunit_context_t *)(via_context->context); - interrupt_restore_irq(drive_context->cpu->int_status, int_num, value); + interrupt_restore_irq(dc->cpu->int_status, int_num, value); } -#define parallel_drivex_set_bus(a) (((drive_context_t *)(via_context->context))->func->parallel_set_bus(a)) -#define parallel_drivex_set_eoi(a) (((drive_context_t *)(via_context->context))->func->parallel_set_eoi(a)) -#define parallel_drivex_set_dav(a) (((drive_context_t *)(via_context->context))->func->parallel_set_dav(a)) -#define parallel_drivex_set_ndac(a) (((drive_context_t *)(via_context->context))->func->parallel_set_ndac(a)) -#define parallel_drivex_set_nrfd(a) (((drive_context_t *)(via_context->context))->func->parallel_set_nrfd(a)) +#define parallel_drivex_set_bus(a) (((diskunit_context_t *)(via_context->context))->func->parallel_set_bus(a)) +#define parallel_drivex_set_eoi(a) (((diskunit_context_t *)(via_context->context))->func->parallel_set_eoi(a)) +#define parallel_drivex_set_dav(a) (((diskunit_context_t *)(via_context->context))->func->parallel_set_dav(a)) +#define parallel_drivex_set_ndac(a) (((diskunit_context_t *)(via_context->context))->func->parallel_set_ndac(a)) +#define parallel_drivex_set_nrfd(a) (((diskunit_context_t *)(via_context->context))->func->parallel_set_nrfd(a)) void via1d2031_set_atn(via_context_t *via_context, int state) @@ -110,15 +111,15 @@ void via1d2031_set_atn(via_context_t *via_context, int state) via1p = (drivevia1_context_t *)(via_context->prv); - if (via1p->drive->type == DRIVE_TYPE_2031) { + if (via1p->diskunit->type == DRIVE_TYPE_2031) { viacore_signal(via_context, VIA_SIG_CA1, state ? VIA_SIG_RISE : 0); - parallel_drivex_set_nrfd((BYTE)(((!parieee_is_out) + parallel_drivex_set_nrfd((uint8_t)(((!parieee_is_out) && (!(via_context->oldpb & 0x02))) || (parallel_atn && (!(via_context->oldpb & 0x01))) || ((!parallel_atn) && (via_context->oldpb & 0x01)))); - parallel_drivex_set_ndac((BYTE)(((!parieee_is_out) + parallel_drivex_set_ndac((uint8_t)(((!parieee_is_out) && (!(via_context->oldpb & 0x04))) || (parallel_atn && (!(via_context->oldpb & 0x01))) @@ -127,78 +128,78 @@ void via1d2031_set_atn(via_context_t *via_context, int state) } } -static void undump_pra(via_context_t *via_context, BYTE byte) +static void undump_pra(via_context_t *via_context, uint8_t byte) { drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); - parallel_drivex_set_bus((BYTE)(parieee_is_out ? byte : 0xff)); + parallel_drivex_set_bus((uint8_t)(parieee_is_out ? byte : 0xff)); } -static void store_pra(via_context_t *via_context, BYTE byte, BYTE oldpa_value, - WORD addr) +static void store_pra(via_context_t *via_context, uint8_t byte, uint8_t oldpa_value, + uint16_t addr) { drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); - parallel_drivex_set_bus((BYTE)(parieee_is_out ? byte : 0xff)); + parallel_drivex_set_bus((uint8_t)(parieee_is_out ? byte : 0xff)); } -static void undump_prb(via_context_t *via_context, BYTE byte) +static void undump_prb(via_context_t *via_context, uint8_t byte) { drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); parieee_is_out = byte & 0x10; - parallel_drivex_set_bus((BYTE)(parieee_is_out + parallel_drivex_set_bus((uint8_t)(parieee_is_out ? via_context->oldpa : 0xff)); - parallel_drivex_set_eoi((BYTE)(parieee_is_out && !(byte & 0x08))); - parallel_drivex_set_dav((BYTE)(parieee_is_out && !(byte & 0x40))); - parallel_drivex_set_ndac((BYTE)(((!parieee_is_out) + parallel_drivex_set_eoi((uint8_t)(parieee_is_out && !(byte & 0x08))); + parallel_drivex_set_dav((uint8_t)(parieee_is_out && !(byte & 0x40))); + parallel_drivex_set_ndac((uint8_t)(((!parieee_is_out) && (!(byte & 0x04))) || (parallel_atn && (!(byte & 0x01))) || ((!parallel_atn) && (byte & 0x01)))); - parallel_drivex_set_nrfd((BYTE)(((!parieee_is_out) + parallel_drivex_set_nrfd((uint8_t)(((!parieee_is_out) && (!(byte & 0x02))) || (parallel_atn && (!(byte & 0x01))) || ((!parallel_atn) && (byte & 0x01)))); } -static void store_prb(via_context_t *via_context, BYTE byte, BYTE p_oldpb, - WORD addr) +static void store_prb(via_context_t *via_context, uint8_t byte, uint8_t p_oldpb, + uint16_t addr) { drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); if (byte != p_oldpb) { - BYTE tmp = ~byte; + uint8_t tmp = ~byte; parieee_is_out = byte & 0x10; - parallel_drivex_set_bus((BYTE)(parieee_is_out + parallel_drivex_set_bus((uint8_t)(parieee_is_out ? via_context->oldpa : 0xff)); if (parieee_is_out) { - parallel_drivex_set_eoi((BYTE)(tmp & 0x08)); - parallel_drivex_set_dav((BYTE)(tmp & 0x40)); + parallel_drivex_set_eoi((uint8_t)(tmp & 0x08)); + parallel_drivex_set_dav((uint8_t)(tmp & 0x40)); } else { parallel_drivex_set_eoi(0); parallel_drivex_set_dav(0); } - parallel_drivex_set_nrfd((BYTE)(((!parieee_is_out) && (tmp & 0x02)) + parallel_drivex_set_nrfd((uint8_t)(((!parieee_is_out) && (tmp & 0x02)) || (parallel_atn && (tmp & 0x01)) || ((!parallel_atn) && (byte & 0x01)))); - parallel_drivex_set_ndac((BYTE)(((!parieee_is_out) && (tmp & 0x04)) + parallel_drivex_set_ndac((uint8_t)(((!parieee_is_out) && (tmp & 0x04)) || (parallel_atn && (tmp & 0x01)) || ((!parallel_atn) && (byte & 0x01)))); } } -static void undump_pcr(via_context_t *via_context, BYTE byte) +static void undump_pcr(via_context_t *via_context, uint8_t byte) { #if 0 drivevia1_context_t *via1p; @@ -212,24 +213,24 @@ static void undump_pcr(via_context_t *via_context, BYTE byte) #endif } -static BYTE store_pcr(via_context_t *via_context, BYTE byte, WORD addr) +static uint8_t store_pcr(via_context_t *via_context, uint8_t byte, uint16_t addr) { return byte; } -static void undump_acr(via_context_t *via_context, BYTE byte) +static void undump_acr(via_context_t *via_context, uint8_t byte) { } -static void store_acr(via_context_t *via_context, BYTE byte) +static void store_acr(via_context_t *via_context, uint8_t byte) { } -static void store_sr(via_context_t *via_context, BYTE byte) +static void store_sr(via_context_t *via_context, uint8_t byte) { } -static void store_t2l(via_context_t *via_context, BYTE byte) +static void store_t2l(via_context_t *via_context, uint8_t byte) { } @@ -248,9 +249,9 @@ static void reset(via_context_t *via_context) parieee_is_out = 1; } -static BYTE read_pra(via_context_t *via_context, WORD addr) +static uint8_t read_pra(via_context_t *via_context, uint16_t addr) { - BYTE byte; + uint8_t byte; drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); @@ -261,9 +262,9 @@ static BYTE read_pra(via_context_t *via_context, WORD addr) | (via_context->via[VIA_PRA] & via_context->via[VIA_DDRA]); } -static BYTE read_prb(via_context_t *via_context) +static uint8_t read_prb(via_context_t *via_context) { - BYTE byte; + uint8_t byte; drivevia1_context_t *via1p; via1p = (drivevia1_context_t *)(via_context->prv); @@ -293,7 +294,7 @@ static BYTE read_prb(via_context_t *via_context) byte = (byte & ~(via_context->via[VIA_DDRB])) | (via_context->via[VIA_PRB] & via_context->via[VIA_DDRB]); - if (!(via_context->ca2_state)) { + if (!(via_context->ca2_out_state)) { /* ???? */ byte &= 0xf8; /* device-no switches */ byte += via1p->drivenumberjumper; /* byte & 3 + 8 -> device-no */ } @@ -301,13 +302,13 @@ static BYTE read_prb(via_context_t *via_context) return byte; } -void via1d2031_init(drive_context_t *ctxptr) +void via1d2031_init(diskunit_context_t *ctxptr) { viacore_init(ctxptr->via1d2031, ctxptr->cpu->alarm_context, - ctxptr->cpu->int_status, ctxptr->cpu->clk_guard); + ctxptr->cpu->int_status); } -void via1d2031_setup_context(drive_context_t *ctxptr) +void via1d2031_setup_context(diskunit_context_t *ctxptr) { drivevia1_context_t *via1p; via_context_t *via; @@ -326,16 +327,16 @@ void via1d2031_setup_context(drive_context_t *ctxptr) via->rmw_flag = &(ctxptr->cpu->rmw_flag); via->clk_ptr = ctxptr->clk_ptr; - via->myname = lib_msprintf("2031Drive%dVia1", ctxptr->mynumber); - via->my_module_name = lib_msprintf("2031VIA1D%d", ctxptr->mynumber); + via->myname = lib_msprintf("2031Drive%uVia1", ctxptr->mynumber); + via->my_module_name = lib_msprintf("2031VIA1D%u", ctxptr->mynumber); viacore_setup_context(via); - via->my_module_name_alt1 = lib_msprintf("VIA1D%d", ctxptr->mynumber); + via->my_module_name_alt1 = lib_msprintf("VIA1D%u", ctxptr->mynumber); via->irq_line = IK_IRQ; - via1p->drive = ctxptr->drive; + via1p->diskunit = ctxptr; via1p->v_parieee_is_out = 1; via->undump_pra = undump_pra; diff --git a/src/Emulators/vice/drive/ieee/via1d2031.h b/src/Emulators/vice/drive/ieee/via1d2031.h index 04b5ebaf..786afd87 100644 --- a/src/Emulators/vice/drive/ieee/via1d2031.h +++ b/src/Emulators/vice/drive/ieee/via1d2031.h @@ -30,16 +30,16 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct via_context_s; -extern void via1d2031_setup_context(struct drive_context_s *ctxptr); +void via1d2031_setup_context(struct diskunit_context_s *ctxptr); -extern void via1d2031_init(struct drive_context_s *ctxptr); -extern void via1d2031_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE via1d2031_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE via1d2031_peek(struct drive_context_s *ctxptr, WORD addr); +void via1d2031_init(struct diskunit_context_s *ctxptr); +void via1d2031_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t via1d2031_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t via1d2031_peek(struct diskunit_context_s *ctxptr, uint16_t addr); -extern void via1d2031_set_atn(struct via_context_s *via_context, int state); +void via1d2031_set_atn(struct via_context_s *via_context, int state); #endif diff --git a/src/Emulators/vice/drive/rotation.c b/src/Emulators/vice/drive/rotation.c index 19030630..5450f1a4 100644 --- a/src/Emulators/vice/drive/rotation.c +++ b/src/Emulators/vice/drive/rotation.c @@ -37,19 +37,22 @@ #include "rotation.h" #include "vicetypes.h" #include "p64.h" +#include "vice_debugger_hook.h" #include +#include #define ACCUM_MAX 0x10000 #define ROTATION_TABLE_SIZE 0x1000 + struct rotation_s { - DWORD accum; + uint32_t accum; CLOCK rotation_last_clk; unsigned int last_read_data; - BYTE last_write_data; + uint8_t last_write_data; int bit_counter; int zero_count; @@ -59,7 +62,7 @@ struct rotation_s { int ue7_dcba; /* UE7 input BA, counter b1/b0, connected to UCD4 PB6/PB5, DC=0 */ int ue7_counter; /* UE7 4 bit counter state */ int uf4_counter; /* UF4 4 bit counter state */ - DWORD fr_randcount; /* counter distance of the last real flux reversal detected from the disk */ + uint32_t fr_randcount; /* counter distance of the last real flux reversal detected from the disk */ int filter_counter; /* flux filter ignore cycle count */ int filter_state; /* flux filter current state */ @@ -69,20 +72,20 @@ struct rotation_s { int so_delay; /* so signal delay */ - DWORD cycle_index; /* cycle_index */ + uint32_t cycle_index; /* cycle_index */ - int ref_advance; /* reference cycles already simulated, e.g. when emulating bus delay */ + CLOCK ref_advance; /* reference cycles already simulated, e.g. when emulating bus delay */ - DWORD PulseHeadPosition; + uint32_t PulseHeadPosition; - DWORD seed; + uint32_t seed; - DWORD xorShift32; + uint32_t xorShift32; }; typedef struct rotation_s rotation_t; -static rotation_t rotation[DRIVE_NUM]; +static rotation_t rotation[NUM_DISK_UNITS]; /* Speed (in bps) of the disk in the 4 disk areas. */ static const unsigned int rot_speed_bps[2][4] = { { 250000, 266667, 285714, 307692 }, @@ -111,7 +114,7 @@ void rotation_reset(drive_t *drive) { unsigned int dnr; - dnr = drive->mynumber; + dnr = drive->diskunit->mynumber; rotation[dnr].last_read_data = 0; rotation[dnr].last_write_data = 0; @@ -119,7 +122,7 @@ void rotation_reset(drive_t *drive) rotation[dnr].accum = 0; rotation[dnr].seed = 0; rotation[dnr].xorShift32 = 0x1234abcd; - rotation[dnr].rotation_last_clk = *(drive->clk); + rotation[dnr].rotation_last_clk = *(drive->diskunit->clk_ptr); rotation[dnr].ue7_counter = 0; rotation[dnr].uf4_counter = 0; rotation[dnr].fr_randcount = 0; @@ -141,17 +144,20 @@ void rotation_speed_zone_set(unsigned int zone, unsigned int dnr) rotation[dnr].ue7_dcba = zone & 3; } -void rotation_table_get(DWORD *rotation_table_ptr) +void rotation_table_get(uint32_t *rotation_table_ptr) { - unsigned int dnr; + unsigned int dnr, j; drive_t *drive; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; - + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { rotation_table_ptr[dnr] = rotation[dnr].speed_zone; - drive->snap_accum = rotation[dnr].accum; + /* Only 1 drive is really supported... */ + for (j = 0; j < 1; j++) { + drive = diskunit_context[dnr]->drives[j]; + + + drive->snap_accum = (uint32_t)(rotation[dnr].accum); drive->snap_rotation_last_clk = rotation[dnr].rotation_last_clk; drive->snap_last_read_data = rotation[dnr].last_read_data; drive->snap_last_write_data = rotation[dnr].last_write_data; @@ -173,20 +179,23 @@ void rotation_table_get(DWORD *rotation_table_ptr) drive->snap_cycle_index = rotation[dnr].cycle_index; drive->snap_ref_advance = rotation[dnr].ref_advance; drive->snap_req_ref_cycles = drive->req_ref_cycles; + } } } -void rotation_table_set(DWORD *rotation_table_ptr) +void rotation_table_set(uint32_t *rotation_table_ptr) { - unsigned int dnr; + unsigned int dnr, j; drive_t *drive; - for (dnr = 0; dnr < DRIVE_NUM; dnr++) { - drive = drive_context[dnr]->drive; + for (dnr = 0; dnr < NUM_DISK_UNITS; dnr++) { + /* Only 1 drive is really supported... */ + for (j = 0; j < 1; j++) { + drive = diskunit_context[dnr]->drives[j]; rotation[dnr].speed_zone = rotation_table_ptr[dnr]; - rotation[dnr].accum = drive->snap_accum; + rotation[dnr].accum = (uint32_t)(drive->snap_accum); rotation[dnr].rotation_last_clk = drive->snap_rotation_last_clk; rotation[dnr].last_read_data = drive->snap_last_read_data; rotation[dnr].last_write_data = drive->snap_last_write_data; @@ -208,6 +217,7 @@ void rotation_table_set(DWORD *rotation_table_ptr) rotation[dnr].cycle_index = drive->snap_cycle_index; rotation[dnr].ref_advance = drive->snap_ref_advance; drive->req_ref_cycles = drive->snap_req_ref_cycles; + } } } @@ -257,7 +267,7 @@ inline static void write_next_bit(drive_t *dptr, int value) // note, the below does not include sides: int tmp = (dptr->image && dptr->image->type == DISK_IMAGE_TYPE_G71) ? DRIVE_HALFTRACKS_1571 : 70; int current_track = (dptr->current_half_track-2)/2; LOGD("write_next_bit: dptr->current_half_track=%d current_track=%d", dptr->current_half_track, current_track); - c64d_mark_drive1541_contents_track_dirty(current_track); + VICE_HOOK_DRIVE_TRACK_DIRTY(current_track); } inline static int read_next_bit(drive_t *dptr) @@ -284,15 +294,15 @@ inline static int read_next_bit(drive_t *dptr) return (dptr->GCR_track_start_ptr[byte_offset] >> bit) & 1; } -inline static SDWORD RANDOM_nextInt(rotation_t *rptr) +inline static int32_t RANDOM_nextInt(rotation_t *rptr) { - DWORD bits = rptr->seed >> 15; + uint32_t bits = rptr->seed >> 15; rptr->seed ^= rptr->accum; rptr->seed = rptr->seed << 17 | bits; - return (SDWORD) rptr->seed; + return (int32_t) rptr->seed; } -inline static DWORD RANDOM_nextUInt(rotation_t *rptr) +inline static uint32_t RANDOM_nextUInt(rotation_t *rptr) { rptr->xorShift32 ^= (rptr->xorShift32 << 13); rptr->xorShift32 ^= (rptr->xorShift32 >> 17); @@ -301,31 +311,59 @@ inline static DWORD RANDOM_nextUInt(rotation_t *rptr) void rotation_begins(drive_t *dptr) { - unsigned int dnr = dptr->mynumber; - rotation[dnr].rotation_last_clk = *(dptr->clk); + /* + * FIXME: does this mean that rotation of both drives in a unit is the same? + * Fortunately the dual drives are not emulated at this level; + * the 2nd CPU is emulated abstractly. + */ + unsigned int dnr = dptr->diskunit->mynumber; + rotation[dnr].rotation_last_clk = *(dptr->diskunit->clk_ptr); rotation[dnr].cycle_index = 0; } +/* calculate wobble factor from the respective resources */ +static void rotation_do_wobble(drive_t *dptr) +{ + /* cpu cycles since last call */ + CLOCK cpu_cycles = *(dptr->diskunit->clk_ptr) - + rotation[dptr->diskunit->mynumber].rotation_last_clk; + + /* FIXME: we should introduce random deviation too */ +#if 0 + int wobble_rand_freq = 10000, wobble_rand_cycles = 10000; + int freqrand, cyclesrand; + + freqrand = wobble_rand_freq ? lib_unsigned_rand(0, wobble_rand_freq) - (wobble_rand_freq / 2) : 0; + cyclesrand = wobble_rand_cycles ? lib_unsigned_rand(0, wobble_rand_cycles) - (wobble_rand_cycles / 2) : 0; + dptr->wobble_sin_count += ((uint64_t)cpu_cycles * (dptr->wobble_frequency + freqrand)) / 10000000000.0f; + if (dptr->wobble_sin_count > (2 * M_PI)) { + dptr->wobble_sin_count -= (2 * M_PI); + } + dptr->wobble_factor = (int)((dptr->wobble_amplitude + cyclesrand) * sinf(dptr->wobble_sin_count)); +#else + dptr->wobble_sin_count += dptr->wobble_frequency * ((((uint64_t)cpu_cycles) * (2.0f * M_PI)) / 1000000000.0f); + if (dptr->wobble_sin_count > (2 * M_PI)) { + dptr->wobble_sin_count -= (2 * M_PI); + } + dptr->wobble_factor = (int)(0.5f + ((sinf(dptr->wobble_sin_count) * ((float)dptr->wobble_amplitude * 32.0f)) / 3.0f)); +#endif +} + /******************************************************************************* * 1541 circuit simulation for GCR-based images (.g64), * see 1541 circuit description in this file for details ******************************************************************************/ -static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) +static void rotation_1541_gcr(drive_t *dptr, CLOCK ref_cycles) { rotation_t *rptr; int clk_ref_per_rev, cyc_act_frv; - unsigned int todo; - SDWORD delta; - DWORD count_new_bitcell, cyc_sum_frv /*, sum_new_bitcell*/; - unsigned int dnr = dptr->mynumber; - int wobble; -#ifdef _MSC_VER - __int64 tmp = 30000UL; -#else - unsigned long long tmp = 30000UL; -#endif + CLOCK todo; + int32_t delta; + uint32_t count_new_bitcell, cyc_sum_frv /*, sum_new_bitcell*/; + unsigned int dnr = dptr->diskunit->mynumber; + uint64_t tmp = 30000UL; - rptr = &rotation[dptr->mynumber]; + rptr = &rotation[dnr]; /* drive speed is 300RPM, that is 300/60=5 revolutions per second * reference clock is 16MHz, one revolution has 16MHz/5 reference cycles @@ -340,10 +378,10 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) * in reality the constant offset can be relatively large, but does not * change a lot over time, so the random offset is rather small. */ - wobble = dptr->rpm_wobble ? lib_unsigned_rand(0, dptr->rpm_wobble) - (dptr->rpm_wobble / 2) : 0; + tmp *= clk_ref_per_rev; - tmp /= dptr->rpm + wobble; - clk_ref_per_rev = (int)tmp; + tmp /= dptr->rpm; + clk_ref_per_rev = (int)tmp + dptr->wobble_factor; /* cell cycles for the actual flux reversal period, it is 1 now, but could be different with variable density */ cyc_act_frv = 1; @@ -361,7 +399,7 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) /* calculate how much cycles can we do in one single pass */ todo = 1; delta = count_new_bitcell - rptr->accum; - if ((delta > 0) && ((cyc_sum_frv << 1) <= (DWORD)delta)) { + if ((delta > 0) && ((cyc_sum_frv << 1) <= (uint32_t)delta)) { todo = delta / cyc_sum_frv; if (ref_cycles < (int)todo) { todo = ref_cycles; @@ -438,11 +476,11 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) } else { if (++rptr->bit_counter == 8) { rptr->bit_counter = 0; - dptr->GCR_read = (BYTE) rptr->last_read_data; + dptr->GCR_read = (uint8_t) rptr->last_read_data; rptr->last_write_data = dptr->GCR_read; /* BYTE READY signal if enabled */ - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { rptr->so_delay = 16 - ((rptr->cycle_index + (todo - 1)) & 15); if (rptr->so_delay < 10) { rptr->so_delay += 16; @@ -477,7 +515,7 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) /* calculate how much cycles can we do in one single pass */ todo = 1; delta = count_new_bitcell - rptr->accum; - if ((delta > 0) && ((cyc_sum_frv << 1) <= (DWORD)delta)) { + if ((delta > 0) && ((cyc_sum_frv << 1) <= (uint32_t)delta)) { todo = delta / cyc_sum_frv; if (ref_cycles < (int)todo) { todo = ref_cycles; @@ -532,7 +570,7 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) rptr->last_write_data = dptr->GCR_write_value; /* BYTE READY signal if enabled */ - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { rptr->so_delay = 16 - ((rptr->cycle_index + (todo - 1)) & 15); if (rptr->so_delay < 10) { rptr->so_delay += 16; @@ -550,14 +588,15 @@ static void rotation_1541_gcr(drive_t *dptr, int ref_cycles) static void rotation_1541_gcr_cycle(drive_t *dptr) { - rotation_t *rptr = &rotation[dptr->mynumber]; + rotation_t *rptr = &rotation[dptr->diskunit->mynumber]; CLOCK cpu_cycles; - int ref_cycles, ref_advance_cycles; + CLOCK ref_cycles, ref_advance_cycles; CLOCK one_rotation = rptr->frequency ? 400000 : 200000; /* cpu cycles since last call */ - cpu_cycles = *(dptr->clk) - rptr->rotation_last_clk; - rptr->rotation_last_clk = *(dptr->clk); + CLOCK clk = *(dptr->diskunit->clk_ptr); + cpu_cycles = clk - rptr->rotation_last_clk; + rptr->rotation_last_clk = clk; /* modulo, at least one revolution, but not more than two */ while (cpu_cycles > one_rotation * 2) { cpu_cycles -= one_rotation; @@ -592,15 +631,31 @@ static void rotation_1541_gcr_cycle(drive_t *dptr) * see 1541 circuit description in this file for details ******************************************************************************/ +/* Calculate delta to the next NRZI transition flux pulse */ +static inline int rotation_p64_get_delta(drive_t *dptr) +{ + rotation_t *rptr = &rotation[dptr->diskunit->mynumber]; + PP64PulseStream P64PulseStream = &dptr->p64->PulseStreams[dptr->side][dptr->current_half_track]; + + /* normal case */ + if (P64PulseStream->CurrentIndex >= 0) { + return P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position - rptr->PulseHeadPosition; + } + + /* wrap around */ + /* FIXME: this is incorrect, see https://sourceforge.net/p/vice-emu/bugs/1305/ */ + return P64PulseSamplesPerRotation - rptr->PulseHeadPosition; +} + /* FIXME: RPM related resources "DriveXRPM" and "DriveXwobble" are ignored for p64 */ -static void rotation_1541_p64(drive_t *dptr, int ref_cycles) +static void rotation_1541_p64(drive_t *dptr, CLOCK ref_cycles) { rotation_t *rptr; PP64PulseStream P64PulseStream; - DWORD DeltaPositionToNextPulse, ToDo; + CLOCK DeltaPositionToNextPulse, ToDo; - rptr = &rotation[dptr->mynumber]; + rptr = &rotation[dptr->diskunit->mynumber]; P64PulseStream = &dptr->p64->PulseStreams[dptr->side][dptr->current_half_track]; @@ -625,12 +680,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) } } - /* Calculate delta to the next NRZI transition flux pulse */ - if (P64PulseStream->CurrentIndex >= 0) { - DeltaPositionToNextPulse = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position - rptr->PulseHeadPosition; - } else { - DeltaPositionToNextPulse = P64PulseSamplesPerRotation - rptr->PulseHeadPosition; - } + DeltaPositionToNextPulse = rotation_p64_get_delta(dptr); if (dptr->read_write_mode) { while (ref_cycles > 0) { @@ -674,6 +724,8 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) { /* Clock logic */ + /* update UE7 before a possible reset of decoder to start with requested speedzone instead of todo value */ + rptr->ue7_counter += ToDo; /* 2.5 microseconds filter */ rptr->filter_counter += (rptr->filter_counter < 40) ? ToDo : 0; if (((rptr->filter_counter >= 40) && (rptr->filter_state != rptr->filter_last_state))) { @@ -693,7 +745,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) /* Increment the pulse divider clock until the speed zone pulse divider clock threshold value is reached, which is: ** 16-(CurrentSpeedZone & 3), and each overflow, increment the pulse counter clock until the 4th pulse is reached */ - rptr->ue7_counter += ToDo; + if (rptr->ue7_counter == 16) { rptr->ue7_counter = rptr->ue7_dcba; @@ -714,7 +766,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) if (++rptr->bit_counter == 8) { rptr->bit_counter = 0; - dptr->GCR_read = (BYTE) rptr->last_read_data; + dptr->GCR_read = (uint8_t) rptr->last_read_data; /* tlr claims that the write register is loaded at every * byte boundary, and since the bus is shared, it's reasonable @@ -722,7 +774,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) rptr->last_write_data = dptr->GCR_read; /* BYTE READY signal if enabled */ - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { rptr->so_delay = 16 - ((rptr->cycle_index + (ToDo - 1)) & 15); if (rptr->so_delay < 10) { rptr->so_delay += 16; @@ -751,33 +803,25 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) (P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position < rptr->PulseHeadPosition)) { P64PulseStream->CurrentIndex = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Next; } - if (P64PulseStream->CurrentIndex >= 0) { - DeltaPositionToNextPulse = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position - rptr->PulseHeadPosition; - } else { - DeltaPositionToNextPulse = P64PulseSamplesPerRotation - rptr->PulseHeadPosition; - } + DeltaPositionToNextPulse = rotation_p64_get_delta(dptr); } /* Next NRZI transition flux pulse handling */ if (!DeltaPositionToNextPulse) { if ((P64PulseStream->CurrentIndex >= 0) && (P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position == rptr->PulseHeadPosition)) { - DWORD Strength = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Strength; + uint32_t Strength = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Strength; /* Forward pulse high hit to the decoder logic */ if ((Strength == 0xffffffffUL) || /* Strong pulse */ - (((DWORD)(RANDOM_nextInt(rptr) ^ 0x80000000UL)) < Strength)) { /* Weak pulse */ + (((uint32_t)(RANDOM_nextInt(rptr) ^ 0x80000000UL)) < Strength)) { /* Weak pulse */ rptr->filter_state ^= 1; rptr->filter_counter = 0; } P64PulseStream->CurrentIndex = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Next; } - if (P64PulseStream->CurrentIndex >= 0) { - DeltaPositionToNextPulse = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position - rptr->PulseHeadPosition; - } else { - DeltaPositionToNextPulse = P64PulseSamplesPerRotation - rptr->PulseHeadPosition; - } + DeltaPositionToNextPulse = rotation_p64_get_delta(dptr); } } /****************************************************************************************************************************************/ @@ -852,7 +896,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) rptr->last_write_data = dptr->GCR_write_value; /* BYTE READY signal if enabled */ - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { rptr->so_delay = 16 - ((rptr->cycle_index + (ToDo - 1)) & 15); if (rptr->so_delay < 10) { rptr->so_delay += 16; @@ -907,11 +951,7 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) } /* Calculate new delta */ - if (P64PulseStream->CurrentIndex >= 0) { - DeltaPositionToNextPulse = P64PulseStream->Pulses[P64PulseStream->CurrentIndex].Position - rptr->PulseHeadPosition; - } else { - DeltaPositionToNextPulse = P64PulseSamplesPerRotation - rptr->PulseHeadPosition; - } + DeltaPositionToNextPulse = rotation_p64_get_delta(dptr); } /****************************************************************************************************************************************/ @@ -923,14 +963,15 @@ static void rotation_1541_p64(drive_t *dptr, int ref_cycles) static void rotation_1541_p64_cycle(drive_t *dptr) { - rotation_t *rptr = &rotation[dptr->mynumber]; + rotation_t *rptr = &rotation[dptr->diskunit->mynumber]; CLOCK cpu_cycles; - int ref_cycles, ref_advance_cycles; + CLOCK ref_cycles, ref_advance_cycles; CLOCK one_rotation = rptr->frequency ? 400000 : 200000; /* cpu cycles since last call */ - cpu_cycles = *(dptr->clk) - rptr->rotation_last_clk; - rptr->rotation_last_clk = *(dptr->clk); + CLOCK clk = *(dptr->diskunit->clk_ptr); + cpu_cycles = clk - rptr->rotation_last_clk; + rptr->rotation_last_clk = clk; /* modulo, at least one revolution, but not more than two */ while (cpu_cycles > one_rotation * 2) { cpu_cycles -= one_rotation; @@ -942,6 +983,7 @@ static void rotation_1541_p64_cycle(drive_t *dptr) /* add additional R cycles requested; R must be less than a complete C cycle */ ref_advance_cycles = dptr->req_ref_cycles; + dptr->req_ref_cycles = 0; ref_advance_cycles &= 15; ref_cycles += ref_advance_cycles; @@ -961,35 +1003,31 @@ static void rotation_1541_p64_cycle(drive_t *dptr) } /******************************************************************************* - * very simple and fast emulation for perfect images like those comming from + * very simple and fast emulation for perfect images like those coming from * dxx files ******************************************************************************/ static void rotation_1541_simple(drive_t *dptr) { rotation_t *rptr; CLOCK delta; - int tdelta; + CLOCK tdelta; int bits_moved = 0; -#ifdef _MSC_VER - __int64 tmp = 1000000UL; -#else - unsigned long long tmp = 1000000UL; -#endif + uint64_t tmp = 1000000UL; unsigned long rpmscale; - int wobble; dptr->req_ref_cycles = 0; - rptr = &rotation[dptr->mynumber]; + rptr = &rotation[dptr->diskunit->mynumber]; /* Calculate the number of bits that have passed under the R/W head since the last time. */ - delta = *(dptr->clk) - rptr->rotation_last_clk; - rptr->rotation_last_clk = *(dptr->clk); + CLOCK clk = *(dptr->diskunit->clk_ptr); + delta = clk - rptr->rotation_last_clk; + rptr->rotation_last_clk = clk; - wobble = dptr->rpm_wobble ? lib_unsigned_rand(0, dptr->rpm_wobble) - (dptr->rpm_wobble / 2) : 0; + tmp += ((long)dptr->wobble_factor * 1000000L) / 3200000L; tmp *= 30000UL; - tmp /= (dptr->rpm + wobble); + tmp /= dptr->rpm; rpmscale = (unsigned long)(tmp); while (delta > 0) { @@ -1034,12 +1072,12 @@ static void rotation_1541_simple(drive_t *dptr) if (~last_read_data & 0x1ff80) { if (++bit_counter == 8) { bit_counter = 0; - dptr->GCR_read = (BYTE) (last_read_data >> 7); + dptr->GCR_read = (uint8_t) (last_read_data >> 7); /* tlr claims that the write register is loaded at every * byte boundary, and since the bus is shared, it's reasonable * to guess that it would be loaded with whatever was last read. */ rptr->last_write_data = dptr->GCR_read; - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { dptr->byte_ready_edge = 1; dptr->byte_ready_level = 1; } @@ -1070,7 +1108,7 @@ static void rotation_1541_simple(drive_t *dptr) if (++rptr->bit_counter == 8) { rptr->bit_counter = 0; rptr->last_write_data = dptr->GCR_write_value; - if ((dptr->byte_ready_active & 2) != 0) { + if ((dptr->byte_ready_active & BRA_BYTE_READY) != 0) { dptr->byte_ready_edge = 1; dptr->byte_ready_level = 1; } @@ -1087,11 +1125,13 @@ static void rotation_1541_simple(drive_t *dptr) ******************************************************************************/ void rotation_rotate_disk(drive_t *dptr) { - if ((dptr->byte_ready_active & 4) == 0) { + if ((dptr->byte_ready_active & BRA_MOTOR_ON) == 0) { dptr->req_ref_cycles = 0; return; } + rotation_do_wobble(dptr); + if (dptr->complicated_image_loaded) { /* stuff that needs complex and slow emulation */ if (dptr->P64_image_loaded) { @@ -1111,9 +1151,9 @@ void rotation_rotate_disk(drive_t *dptr) The return value corresponds to bit#7 of VIA2 PRB. This means 0x0 is returned when sync is found and 0x80 is returned when no sync is found. */ -BYTE rotation_sync_found(drive_t *dptr) +uint8_t rotation_sync_found(drive_t *dptr) { - unsigned int dnr = dptr->mynumber; + unsigned int dnr = dptr->diskunit->mynumber; if (dptr->read_write_mode == 0 || dptr->attach_clk != (CLOCK)0) { return 0x80; @@ -1124,14 +1164,16 @@ BYTE rotation_sync_found(drive_t *dptr) void rotation_byte_read(drive_t *dptr) { + CLOCK clk = *(dptr->diskunit->clk_ptr); + if (dptr->attach_clk != (CLOCK)0) { - if (*(dptr->clk) - dptr->attach_clk < DRIVE_ATTACH_DELAY) { + if (clk - dptr->attach_clk < DRIVE_ATTACH_DELAY) { dptr->GCR_read = 0; } else { dptr->attach_clk = (CLOCK)0; } } else if (dptr->attach_detach_clk != (CLOCK)0) { - if (*(dptr->clk) - dptr->attach_detach_clk < DRIVE_ATTACH_DETACH_DELAY) { + if (clk - dptr->attach_detach_clk < DRIVE_ATTACH_DETACH_DELAY) { dptr->GCR_read = 0; } else { dptr->attach_detach_clk = (CLOCK)0; diff --git a/src/Emulators/vice/drive/rotation.h b/src/Emulators/vice/drive/rotation.h index c1370b80..e80259d2 100644 --- a/src/Emulators/vice/drive/rotation.h +++ b/src/Emulators/vice/drive/rotation.h @@ -34,16 +34,16 @@ struct drive_s; /* 875ns delay (14*62.5ns R cycles) for data bus read access */ #define BUS_READ_DELAY 14 -extern void rotation_init(int freq, unsigned int dnr); -extern void rotation_reset(struct drive_s *drive); -extern void rotation_speed_zone_set(unsigned int zone, unsigned int dnr); -extern void rotation_table_get(DWORD *rotation_table_ptr); -extern void rotation_table_set(DWORD *rotation_table_ptr); -extern void rotation_overflow_callback(CLOCK sub, unsigned int dnr); -extern void rotation_change_mode(unsigned int dnr); -extern void rotation_begins(struct drive_s *dptr); -extern void rotation_rotate_disk(struct drive_s *dptr); -extern BYTE rotation_sync_found(struct drive_s *dptr); -extern void rotation_byte_read(struct drive_s *dptr); +void rotation_init(int freq, unsigned int dnr); +void rotation_reset(struct drive_s *drive); +void rotation_speed_zone_set(unsigned int zone, unsigned int dnr); +void rotation_table_get(uint32_t *rotation_table_ptr); +void rotation_table_set(uint32_t *rotation_table_ptr); +void rotation_overflow_callback(CLOCK sub, unsigned int dnr); +void rotation_change_mode(unsigned int dnr); +void rotation_begins(struct drive_s *dptr); +void rotation_rotate_disk(struct drive_s *dptr); +uint8_t rotation_sync_found(struct drive_s *dptr); +void rotation_byte_read(struct drive_s *dptr); #endif diff --git a/src/Emulators/vice/drive/tcbm/tpid.c b/src/Emulators/vice/drive/tcbm/tpid.c index d8ae3a1c..d6274f02 100644 --- a/src/Emulators/vice/drive/tcbm/tpid.c +++ b/src/Emulators/vice/drive/tcbm/tpid.c @@ -45,22 +45,23 @@ typedef struct drivetpi_context_s { } drivetpi_context_t; -void tpid_store(drive_context_t *ctxptr, WORD addr, BYTE data) +void tpid_store(diskunit_context_t *ctxptr, uint16_t addr, uint8_t data) { + ctxptr->cpu->cpu_last_data = data; tpicore_store(ctxptr->tpid, addr, data); } -BYTE tpid_read(drive_context_t *ctxptr, WORD addr) +uint8_t tpid_read(diskunit_context_t *ctxptr, uint16_t addr) { - return tpicore_read(ctxptr->tpid, addr); + return ctxptr->cpu->cpu_last_data = tpicore_read(ctxptr->tpid, addr); } -BYTE tpid_peek(drive_context_t *ctxptr, WORD addr) +uint8_t tpid_peek(diskunit_context_t *ctxptr, uint16_t addr) { return tpicore_peek(ctxptr->tpid, addr); } -int tpid_dump(drive_context_t *ctxptr, WORD addr) +int tpid_dump(diskunit_context_t *ctxptr, uint16_t addr) { tpicore_dump(ctxptr->tpid); return 0; @@ -93,7 +94,7 @@ static void reset(tpi_context_t *tpi_context) plus4tcbm_update_pc(0xff, tpip->number); } -static void store_pa(tpi_context_t *tpi_context, BYTE byte) +static void store_pa(tpi_context_t *tpi_context, uint8_t byte) { drivetpi_context_t *tpip; @@ -102,7 +103,7 @@ static void store_pa(tpi_context_t *tpi_context, BYTE byte) plus4tcbm_update_pa(byte, tpip->number); } -static void store_pb(tpi_context_t *tpi_context, BYTE byte) +static void store_pb(tpi_context_t *tpi_context, uint8_t byte) { drivetpi_context_t *tpip; @@ -113,15 +114,15 @@ static void store_pb(tpi_context_t *tpi_context, BYTE byte) tpip->drive->GCR_write_value = byte; } -static void undump_pa(tpi_context_t *tpi_context, BYTE byte) +static void undump_pa(tpi_context_t *tpi_context, uint8_t byte) { } -static void undump_pb(tpi_context_t *tpi_context, BYTE byte) +static void undump_pb(tpi_context_t *tpi_context, uint8_t byte) { } -static void store_pc(tpi_context_t *tpi_context, BYTE byte) +static void store_pc(tpi_context_t *tpi_context, uint8_t byte) { drivetpi_context_t *tpip; @@ -136,14 +137,14 @@ static void store_pc(tpi_context_t *tpi_context, BYTE byte) } } -static void undump_pc(tpi_context_t *tpi_context, BYTE byte) +static void undump_pc(tpi_context_t *tpi_context, uint8_t byte) { } -static BYTE read_pa(tpi_context_t *tpi_context) +static uint8_t read_pa(tpi_context_t *tpi_context) { /* TCBM data port */ - BYTE byte; + uint8_t byte; drivetpi_context_t *tpip; tpip = (drivetpi_context_t *)(tpi_context->prv); @@ -156,10 +157,10 @@ static BYTE read_pa(tpi_context_t *tpi_context) return byte; } -static BYTE read_pb(tpi_context_t *tpi_context) +static uint8_t read_pb(tpi_context_t *tpi_context) { /* GCR data port */ - BYTE byte; + uint8_t byte; drivetpi_context_t *tpip; tpip = (drivetpi_context_t *)(tpi_context->prv); @@ -174,10 +175,10 @@ static BYTE read_pb(tpi_context_t *tpi_context) return byte; } -static BYTE read_pc(tpi_context_t *tpi_context) +static uint8_t read_pc(tpi_context_t *tpi_context) { /* TCBM control / GCR data control */ - BYTE byte; + uint8_t byte; drivetpi_context_t *tpip; tpip = (drivetpi_context_t *)(tpi_context->prv); @@ -199,7 +200,7 @@ static BYTE read_pc(tpi_context_t *tpi_context) return byte; } -void tpid_init(drive_context_t *ctxptr) +void tpid_init(diskunit_context_t *ctxptr) { tpi_context_t *tpi_context; @@ -208,7 +209,7 @@ void tpid_init(drive_context_t *ctxptr) tpi_context->log = log_open(tpi_context->myname); } -void tpid_setup_context(drive_context_t *ctxptr) +void tpid_setup_context(diskunit_context_t *ctxptr) { drivetpi_context_t *tpip; tpi_context_t *tpi; @@ -225,14 +226,14 @@ void tpid_setup_context(drive_context_t *ctxptr) tpi->rmw_flag = &(ctxptr->cpu->rmw_flag); tpi->clk_ptr = ctxptr->clk_ptr; - tpi->myname = lib_msprintf("Drive%dTPI", ctxptr->mynumber); + tpi->myname = lib_msprintf("Drive%uTPI", ctxptr->mynumber); tpicore_setup_context(tpi); tpi->tpi_int_num = interrupt_cpu_status_int_new(ctxptr->cpu->int_status, tpi->myname); tpi->irq_line = IK_IRQ; - tpip->drive = ctxptr->drive; + tpip->drive = ctxptr->drives[0]; tpi->store_pa = store_pa; tpi->store_pb = store_pb; diff --git a/src/Emulators/vice/drive/tcbm/tpid.h b/src/Emulators/vice/drive/tcbm/tpid.h index 077b5a52..2371bf0f 100644 --- a/src/Emulators/vice/drive/tcbm/tpid.h +++ b/src/Emulators/vice/drive/tcbm/tpid.h @@ -29,15 +29,15 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct tpi_context_s; -extern void tpid_setup_context(struct drive_context_s *ctxptr); +void tpid_setup_context(struct diskunit_context_s *ctxptr); -extern void tpid_init(struct drive_context_s *ctxptr); -extern void tpid_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE tpid_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE tpid_peek(struct drive_context_s *ctxptr, WORD addr); -extern int tpid_dump(drive_context_t *ctxptr, WORD addr); +void tpid_init(struct diskunit_context_s *ctxptr); +void tpid_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t tpid_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t tpid_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int tpid_dump(diskunit_context_t *ctxptr, uint16_t addr); #endif diff --git a/src/Emulators/vice/drive/viad.h b/src/Emulators/vice/drive/viad.h index fd6ca5f3..f17a84b9 100644 --- a/src/Emulators/vice/drive/viad.h +++ b/src/Emulators/vice/drive/viad.h @@ -30,18 +30,21 @@ #include "vicetypes.h" -struct drive_context_s; +struct diskunit_context_s; struct drive_s; -extern void via2d_setup_context(struct drive_context_s *ctxptr); +void via2d_setup_context(struct diskunit_context_s *ctxptr); -extern void via2d_init(struct drive_context_s *ctxptr); -extern void via2d_store(struct drive_context_s *ctxptr, WORD addr, BYTE byte); -extern BYTE via2d_read(struct drive_context_s *ctxptr, WORD addr); -extern BYTE via2d_peek(struct drive_context_s *ctxptr, WORD addr); -extern int via2d_dump(struct drive_context_s *ctxptr, WORD addr); -extern BYTE c64d_via2d_peek(struct drive_context_s *ctxptr, WORD addr); +void via2d_init(struct diskunit_context_s *ctxptr); +void via2d_store(struct diskunit_context_s *ctxptr, uint16_t addr, uint8_t byte); +uint8_t via2d_read(struct diskunit_context_s *ctxptr, uint16_t addr); +uint8_t via2d_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +int via2d_dump(struct diskunit_context_s *ctxptr, uint16_t addr); -extern void via2d_update_pcr(int pcrval, struct drive_s *dptr); +void via2d_update_pcr(int pcrval, struct drive_s *dptr); + +#ifdef RETRODEBUGGER +uint8_t c64d_via2d_peek(struct diskunit_context_s *ctxptr, uint16_t addr); +#endif #endif diff --git a/src/Emulators/vice/fileio/cbmfile.c b/src/Emulators/vice/fileio/cbmfile.c index 852528e6..9689c511 100644 --- a/src/Emulators/vice/fileio/cbmfile.c +++ b/src/Emulators/vice/fileio/cbmfile.c @@ -24,26 +24,35 @@ * */ +/* #define DEBUGCBMFILE */ + #include "vice.h" #include #include +#include "archdep.h" #include "cbmdos.h" -#include "cbmfile.h" #include "charset.h" #include "fileio.h" -#include "ioutil.h" #include "lib.h" #include "rawfile.h" #include "vicetypes.h" +#include "cbmfile.h" + +#ifdef DEBUGCBMFILE +#define DBG(x) printf x +#else +#define DBG(x) +#endif static char *cbmfile_find_file(const char *fsname, const char *path) { - struct ioutil_dir_s *ioutil_dir; - BYTE *name1, *name2; - char *name, *retname = NULL; + archdep_dir_t *host_dir; + uint8_t *name1, *name2; + const char *name; + char *retname = NULL; const char *open_path; open_path = path; @@ -51,9 +60,9 @@ static char *cbmfile_find_file(const char *fsname, const char *path) open_path = ""; } - ioutil_dir = ioutil_opendir(open_path); + host_dir = archdep_opendir(open_path, ARCHDEP_OPENDIR_ALL_FILES); - if (ioutil_dir == NULL) { + if (host_dir == NULL) { return NULL; } @@ -62,7 +71,7 @@ static char *cbmfile_find_file(const char *fsname, const char *path) while (1) { unsigned int equal; - name = ioutil_readdir(ioutil_dir); + name = archdep_readdir(host_dir); if (name == NULL) { break; @@ -74,13 +83,13 @@ static char *cbmfile_find_file(const char *fsname, const char *path) lib_free(name2); if (equal > 0) { - retname = lib_stralloc(name); + retname = lib_strdup(name); break; } } lib_free(name1); - ioutil_closedir(ioutil_dir); + archdep_closedir(host_dir); return retname; } @@ -88,15 +97,15 @@ static char *cbmfile_find_file(const char *fsname, const char *path) fileio_info_t *cbmfile_open(const char *file_name, const char *path, unsigned int command, unsigned int type) { - BYTE *cbm_name; + uint8_t *cbm_name; fileio_info_t *info; struct rawfile_info_s *rawfile; char *fsname, *rname; - fsname = lib_stralloc(file_name); + fsname = lib_strdup(file_name); if (!(command & FILEIO_COMMAND_FSNAME)) { - charset_petconvstring((BYTE *)fsname, 1); + charset_petconvstring((uint8_t *)fsname, CONVERT_TO_ASCII); } if (cbmdos_parse_wildcard_check(fsname, (unsigned int)strlen(fsname))) { @@ -117,10 +126,10 @@ fileio_info_t *cbmfile_open(const char *file_name, const char *path, return NULL; } - cbm_name = (BYTE *)lib_stralloc(file_name); + cbm_name = (uint8_t *)lib_strdup(file_name); if (command & FILEIO_COMMAND_FSNAME) { - charset_petconvstring(cbm_name, 0); + charset_petconvstring(cbm_name, CONVERT_TO_PETSCII); } info = lib_malloc(sizeof(fileio_info_t)); @@ -138,12 +147,12 @@ void cbmfile_close(fileio_info_t *info) rawfile_destroy(info->rawfile); } -unsigned int cbmfile_read(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int cbmfile_read(fileio_info_t *info, uint8_t *buf, unsigned int len) { return rawfile_read(info->rawfile, buf, len); } -unsigned int cbmfile_write(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int cbmfile_write(fileio_info_t *info, uint8_t *buf, unsigned int len) { return rawfile_write(info->rawfile, buf, len); } @@ -159,11 +168,13 @@ unsigned int cbmfile_rename(const char *src_name, const char *dst_name, char *src_cbm, *dst_cbm; unsigned int rc; - src_cbm = lib_stralloc(src_name); - dst_cbm = lib_stralloc(dst_name); + DBG(("cbmfile_rename '%s' to '%s'\n", src_name, dst_name)); + + src_cbm = lib_strdup(src_name); + dst_cbm = lib_strdup(dst_name); - charset_petconvstring((BYTE *)src_cbm, 1); - charset_petconvstring((BYTE *)dst_cbm, 1); + charset_petconvstring((uint8_t *)src_cbm, CONVERT_TO_ASCII); + charset_petconvstring((uint8_t *)dst_cbm, CONVERT_TO_ASCII); rc = rawfile_rename(src_cbm, dst_cbm, path); @@ -178,8 +189,8 @@ unsigned int cbmfile_scratch(const char *file_name, const char *path) char *src_cbm; unsigned int rc; - src_cbm = lib_stralloc(file_name); - charset_petconvstring((BYTE *)src_cbm, 1); + src_cbm = lib_strdup(file_name); + charset_petconvstring((uint8_t *)src_cbm, CONVERT_TO_ASCII); rc = rawfile_remove(src_cbm, path); @@ -192,3 +203,13 @@ unsigned int cbmfile_get_bytes_left(struct fileio_info_s *info) { return rawfile_get_bytes_left(info->rawfile); } + +unsigned int cbmfile_seek(struct fileio_info_s *info, off_t offset, int whence) +{ + return rawfile_seek(info->rawfile, offset, whence); +} + +unsigned int cbmfile_tell(struct fileio_info_s *info) +{ + return rawfile_tell(info->rawfile); +} diff --git a/src/Emulators/vice/fileio/cbmfile.h b/src/Emulators/vice/fileio/cbmfile.h index 3ebd4fdd..ec99b62b 100644 --- a/src/Emulators/vice/fileio/cbmfile.h +++ b/src/Emulators/vice/fileio/cbmfile.h @@ -31,19 +31,21 @@ struct fileio_info_s; -extern struct fileio_info_s *cbmfile_open(const char *file_name, - const char *path, - unsigned int command, - unsigned int type); -extern void cbmfile_close(struct fileio_info_s *info); -extern unsigned int cbmfile_read(struct fileio_info_s *info, BYTE *buf, - unsigned int len); -extern unsigned int cbmfile_write(struct fileio_info_s *info, BYTE *buf, - unsigned int len); -extern unsigned int cbmfile_ferror(struct fileio_info_s *info); -extern unsigned int cbmfile_rename(const char *src_name, const char *dst_name, - const char *path); -extern unsigned int cbmfile_scratch(const char *file_name, const char *path); -extern unsigned int cbmfile_get_bytes_left(struct fileio_info_s *info); +struct fileio_info_s *cbmfile_open(const char *file_name, + const char *path, + unsigned int command, + unsigned int type); +void cbmfile_close(struct fileio_info_s *info); +unsigned int cbmfile_read(struct fileio_info_s *info, uint8_t *buf, + unsigned int len); +unsigned int cbmfile_write(struct fileio_info_s *info, uint8_t *buf, + unsigned int len); +unsigned int cbmfile_ferror(struct fileio_info_s *info); +unsigned int cbmfile_rename(const char *src_name, const char *dst_name, + const char *path); +unsigned int cbmfile_scratch(const char *file_name, const char *path); +unsigned int cbmfile_get_bytes_left(struct fileio_info_s *info); +unsigned int cbmfile_seek(struct fileio_info_s *info, off_t offset, int whence); +unsigned int cbmfile_tell(struct fileio_info_s *info); #endif diff --git a/src/Emulators/vice/fileio/fileio.c b/src/Emulators/vice/fileio/fileio.c index ea80448c..91ab634c 100644 --- a/src/Emulators/vice/fileio/fileio.c +++ b/src/Emulators/vice/fileio/fileio.c @@ -24,6 +24,8 @@ * */ +/* #define DEBUGFILEIO */ + #include "vice.h" #include @@ -35,20 +37,29 @@ #include "vicetypes.h" #include "util.h" +#ifdef DEBUGFILEIO +#define DBG(x) printf x +#else +#define DBG(x) +#endif fileio_info_t *fileio_open(const char *file_name, const char *path, unsigned int format, unsigned int command, - unsigned int type) + unsigned int type, int *reclenp) { fileio_info_t *info = NULL; char *new_file, *new_path; + if (file_name == NULL || *file_name == '\0') { + return NULL; + } + if ((command & FILEIO_COMMAND_FSNAME) && path == NULL) { util_fname_split(file_name, &new_path, &new_file); } else { - new_file = lib_stralloc(file_name); + new_file = lib_strdup(file_name); if (path != NULL) { - new_path = lib_stralloc(path); + new_path = lib_strdup(path); } else { new_path = NULL; } @@ -56,7 +67,7 @@ fileio_info_t *fileio_open(const char *file_name, const char *path, do { if (format & FILEIO_FORMAT_P00) { - info = p00_open(new_file, new_path, command, type); + info = p00_open(new_file, new_path, command, type, reclenp); } if (info != NULL) { @@ -65,6 +76,9 @@ fileio_info_t *fileio_open(const char *file_name, const char *path, if (format & FILEIO_FORMAT_RAW) { info = cbmfile_open(new_file, new_path, command, type); + if (reclenp) { + *reclenp = 0; + } } if (info != NULL) { @@ -94,7 +108,7 @@ void fileio_close(fileio_info_t *info) } } -unsigned int fileio_read(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int fileio_read(fileio_info_t *info, uint8_t *buf, unsigned int len) { switch (info->format) { case FILEIO_FORMAT_RAW: @@ -106,7 +120,7 @@ unsigned int fileio_read(fileio_info_t *info, BYTE *buf, unsigned int len) return 0; } -unsigned int fileio_write(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int fileio_write(fileio_info_t *info, uint8_t *buf, unsigned int len) { switch (info->format) { case FILEIO_FORMAT_RAW: @@ -130,6 +144,30 @@ unsigned int fileio_get_bytes_left(fileio_info_t *info) return 0; } +unsigned int fileio_seek(fileio_info_t *info, off_t offset, int whence) +{ + switch (info->format) { + case FILEIO_FORMAT_RAW: + return cbmfile_seek(info, offset, whence); + case FILEIO_FORMAT_P00: + return p00_seek(info, offset, whence); + } + + return 0; +} + +unsigned int fileio_tell(fileio_info_t *info) +{ + switch (info->format) { + case FILEIO_FORMAT_RAW: + return cbmfile_tell(info); + case FILEIO_FORMAT_P00: + return p00_tell(info); + } + + return 0; +} + unsigned int fileio_ferror(fileio_info_t *info) { switch (info->format) { @@ -147,6 +185,8 @@ unsigned int fileio_rename(const char *src_name, const char *dest_name, { unsigned int rc = FILEIO_FILE_NOT_FOUND; + DBG(("fileio_rename '%s' to '%s'\n", src_name, dest_name)); + if (format & FILEIO_FORMAT_P00) { rc = p00_rename(src_name, dest_name, path); } diff --git a/src/Emulators/vice/fileio/p00.c b/src/Emulators/vice/fileio/p00.c index a4a4ffe8..d8909f70 100644 --- a/src/Emulators/vice/fileio/p00.c +++ b/src/Emulators/vice/fileio/p00.c @@ -39,7 +39,6 @@ #include "archdep.h" #include "cbmdos.h" #include "fileio.h" -#include "ioutil.h" #include "lib.h" #include "log.h" #include "p00.h" @@ -51,9 +50,9 @@ /* P00 Header structure: typedef struct { - BYTE Magic[8]; + uint8_t Magic[8]; char CbmName[17]; - BYTE RecordSize; + uint8_t RecordSize; } X00HDR; */ #define P00_HDR_MAGIC_OFFSET 0 @@ -65,7 +64,7 @@ #define P00_HDR_LEN 26 -static const BYTE p00_hdr_magic_string[8] = "C64File"; +static const unsigned char p00_hdr_magic_string[8] = "C64File"; /* FIXME: There should be an enum for file types. */ static int p00_check_name(const char *name) @@ -77,7 +76,7 @@ static int p00_check_name(const char *name) return -1; } - if (!isdigit((int)p[1]) || !isdigit((int)p[2])) { + if (!isdigit((unsigned char)p[1]) || !isdigit((unsigned char)p[2])) { return -1; } @@ -102,10 +101,10 @@ static int p00_check_name(const char *name) return t; } -static int p00_read_header(struct rawfile_info_s *info, BYTE *cbmname_return, - unsigned int *recsize_return) +static int p00_read_header(struct rawfile_info_s *info, uint8_t *cbmname_return, + int *recsize_return) { - BYTE hdr[P00_HDR_LEN]; + uint8_t hdr[P00_HDR_LEN]; if (rawfile_read(info, hdr, P00_HDR_LEN) != P00_HDR_LEN) { return -1; @@ -119,25 +118,25 @@ static int p00_read_header(struct rawfile_info_s *info, BYTE *cbmname_return, memcpy(cbmname_return, hdr + P00_HDR_CBMNAME_OFFSET, P00_HDR_CBMNAME_LEN); if (recsize_return != NULL) { - *recsize_return = (unsigned int)hdr[P00_HDR_RECORDSIZE_OFFSET]; + *recsize_return = (int)hdr[P00_HDR_RECORDSIZE_OFFSET]; } return 0; } -static int p00_write_header(struct rawfile_info_s *info, const BYTE *cbmname, - BYTE recsize) +static int p00_write_header(struct rawfile_info_s *info, const uint8_t *cbmname, + uint8_t recsize) { - BYTE hdr[P00_HDR_LEN]; + uint8_t hdr[P00_HDR_LEN]; memset(hdr, 0, sizeof(hdr)); memcpy(hdr + P00_HDR_MAGIC_OFFSET, p00_hdr_magic_string, P00_HDR_MAGIC_LEN); memcpy(hdr + P00_HDR_CBMNAME_OFFSET, cbmname, P00_HDR_CBMNAME_LEN); - hdr[P00_HDR_RECORDSIZE_OFFSET] = (BYTE)recsize; + hdr[P00_HDR_RECORDSIZE_OFFSET] = (uint8_t)recsize; - if (rawfile_seek_set(info, 0) != 0) { + if (rawfile_seek(info, 0, SEEK_SET) != 0) { return -1; } @@ -148,7 +147,7 @@ static int p00_write_header(struct rawfile_info_s *info, const BYTE *cbmname, return 0; } -static void p00_pad_a0(BYTE *slot) +static void p00_pad_a0(uint8_t *slot) { unsigned int index; @@ -161,20 +160,20 @@ static void p00_pad_a0(BYTE *slot) static char *p00_file_find(const char *file_name, const char *path) { - struct ioutil_dir_s *ioutil_dir; + archdep_dir_t *host_dir; struct rawfile_info_s *rawfile; - BYTE p00_header_file_name[P00_HDR_CBMNAME_LEN]; - char *name, *alloc_name = NULL; + uint8_t p00_header_file_name[P00_HDR_CBMNAME_LEN]; + const char *name; + char *alloc_name = NULL; int rc; - ioutil_dir = ioutil_opendir(path); - - if (ioutil_dir == NULL) { + host_dir = archdep_opendir(path, ARCHDEP_OPENDIR_ALL_FILES); + if (host_dir == NULL) { return NULL; } while (1) { - name = ioutil_readdir(ioutil_dir); + name = archdep_readdir(host_dir); if (name == NULL) { break; @@ -189,10 +188,10 @@ static char *p00_file_find(const char *file_name, const char *path) continue; } - rc = p00_read_header(rawfile, (BYTE *)p00_header_file_name, NULL); + rc = p00_read_header(rawfile, (uint8_t *)p00_header_file_name, NULL); if (rc >= 0) { - BYTE *cname; + uint8_t *cname; unsigned int equal; p00_pad_a0(p00_header_file_name); @@ -201,7 +200,7 @@ static char *p00_file_find(const char *file_name, const char *path) lib_free(cname); if (equal > 0) { - alloc_name = lib_stralloc(name); + alloc_name = lib_strdup(name); } else { rc = -1; } @@ -214,7 +213,7 @@ static char *p00_file_find(const char *file_name, const char *path) } } - ioutil_closedir(ioutil_dir); + archdep_closedir(host_dir); return alloc_name; } @@ -252,7 +251,7 @@ static int p00_reduce_filename_p00(char *filename, int len) } for (i = len - 1; i >= 0; i--) { - if (isalpha((int) filename[i])) { + if (isalpha((unsigned char) filename[i])) { if (p00_eliminate_char_p00(filename, i) <= 8) { return 8; } @@ -282,11 +281,11 @@ static char *p00_evaluate_name(const char *name, int length) filename[j++] = '_'; break; default: - if (islower((int)name[i])) { + if (islower((unsigned char)name[i])) { filename[j++] = util_toupper(name[i]); break; } - if (isalnum((int)name[i])) { + if (isalnum((unsigned char)name[i])) { filename[j++] = name[i]; break; } @@ -304,7 +303,7 @@ static char *p00_evaluate_name(const char *name, int length) return filename; } -static char *p00_filename_create(const char *file_name, unsigned int type) +char *p00_filename_create(const char *file_name, unsigned int type) { char *p00name, *main_name; const char *typeext = NULL; @@ -336,7 +335,7 @@ static char *p00_filename_create(const char *file_name, unsigned int type) break; } - p00name = util_concat(main_name, FSDEV_EXT_SEP_STR, typeext, "00", NULL); + p00name = util_concat(main_name, ".", typeext, "00", NULL); lib_free(main_name); return p00name; @@ -354,7 +353,7 @@ static char *p00_file_create(const char *file_name, const char *path, if (util_file_exists(p00name) == 0) { break; } - sprintf(&p00name[strlen(p00name) - 2], "%02i", i); + sprintf(&p00name[strlen(p00name) - 2], "%02u", i); } if (i >= 100) { @@ -365,30 +364,40 @@ static char *p00_file_create(const char *file_name, const char *path, } fileio_info_t *p00_open(const char *file_name, const char *path, - unsigned int command, unsigned int open_type) + unsigned int command, unsigned int open_type, + int *reclenp) { char rname[20]; /* FIXME */ fileio_info_t *info; struct rawfile_info_s *rawfile; char *fname = NULL; int type; + int reclen = 0; if (command & FILEIO_COMMAND_FSNAME) { - fname = lib_stralloc(file_name); + fname = lib_strdup(file_name); } else { switch (command & FILEIO_COMMAND_MASK) { case FILEIO_COMMAND_STAT: case FILEIO_COMMAND_READ: + case FILEIO_COMMAND_READ_WRITE: case FILEIO_COMMAND_APPEND: case FILEIO_COMMAND_APPEND_READ: fname = p00_file_find(file_name, path); break; case FILEIO_COMMAND_WRITE: + case FILEIO_COMMAND_OVERWRITE: fname = p00_file_create(file_name, path, open_type); break; } } + if (fname == NULL && + (command & FILEIO_COMMAND_MASK) == FILEIO_COMMAND_READ_WRITE) { + fname = p00_file_create(file_name, path, open_type); + command = (command & ~FILEIO_COMMAND_MASK) | FILEIO_COMMAND_WRITE; + } + if (fname == NULL) { return NULL; } @@ -405,14 +414,15 @@ fileio_info_t *p00_open(const char *file_name, const char *path, switch (command & FILEIO_COMMAND_MASK) { case FILEIO_COMMAND_STAT: case FILEIO_COMMAND_READ: - if (type < 0 || p00_read_header(rawfile, (BYTE *)rname, NULL) < 0) { + case FILEIO_COMMAND_READ_WRITE: + if (type < 0 || p00_read_header(rawfile, (uint8_t *)rname, &reclen) < 0) { rawfile_destroy(rawfile); return NULL; } break; case FILEIO_COMMAND_APPEND: case FILEIO_COMMAND_APPEND_READ: - if (type < 0 || p00_read_header(rawfile, (BYTE *)rname, NULL) < 0) { + if (type < 0 || p00_read_header(rawfile, (uint8_t *)rname, &reclen) < 0) { rawfile_destroy(rawfile); return NULL; } @@ -423,17 +433,30 @@ fileio_info_t *p00_open(const char *file_name, const char *path, */ break; case FILEIO_COMMAND_WRITE: + case FILEIO_COMMAND_OVERWRITE: + reclen = reclenp ? *reclenp : 0; memset(rname, 0, sizeof(rname)); strncpy(rname, file_name, 16); - if (p00_write_header(rawfile, (BYTE *)rname, 0) < 0) { + if (p00_write_header(rawfile, (uint8_t *)rname, reclen) < 0) { rawfile_destroy(rawfile); return NULL; } break; } + if (open_type == FILEIO_TYPE_REL && reclenp) { + if (*reclenp == 0) { + *reclenp = reclen; + } else if (*reclenp != reclen) { + /* The given record length does not match the stored record + * length */ + log_verbose(LOG_DEFAULT, "p00_open: record size: found %d != expected %d => record size mismatch\n", reclen, *reclenp); + return NULL; + } + } + info = lib_malloc(sizeof(fileio_info_t)); - info->name = (BYTE *)lib_stralloc(rname); + info->name = (uint8_t *)lib_strdup(rname); info->length = (unsigned int)strlen((char *)(info->name)); info->type = (unsigned int)type; info->format = FILEIO_FORMAT_P00; @@ -447,12 +470,12 @@ void p00_close(fileio_info_t *info) rawfile_destroy(info->rawfile); } -unsigned int p00_read(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int p00_read(fileio_info_t *info, uint8_t *buf, unsigned int len) { return rawfile_read(info->rawfile, buf, len); } -unsigned int p00_write(fileio_info_t *info, BYTE *buf, unsigned int len) +unsigned int p00_write(fileio_info_t *info, uint8_t *buf, unsigned int len) { return rawfile_write(info->rawfile, buf, len); } @@ -499,7 +522,7 @@ unsigned int p00_rename(const char *src_name, const char *dst_name, memset(rname, 0, sizeof(rname)); strncpy(rname, dst_name, 16); - if (p00_write_header(rawfile, (BYTE *)rname, 0) < 0) { + if (p00_write_header(rawfile, (uint8_t *)rname, 0) < 0) { rawfile_destroy(rawfile); lib_free(p00_src); return FILEIO_FILE_NOT_FOUND; @@ -544,3 +567,24 @@ unsigned int p00_get_bytes_left(struct fileio_info_s *info) { return rawfile_get_bytes_left(info->rawfile); } + +unsigned int p00_seek(struct fileio_info_s *info, off_t offset, int whence) +{ + if (whence == SEEK_SET) { + offset += P00_HDR_LEN; + } + + /* Note: this has no protection against seeking into the P00 header */ + + return rawfile_seek(info->rawfile, offset, whence); +} + +unsigned int p00_tell(struct fileio_info_s *info) +{ + long pos = rawfile_tell(info->rawfile); + + if (pos == -1) + return -1; + + return (unsigned int)pos - P00_HDR_LEN; +} diff --git a/src/Emulators/vice/fileio/p00.h b/src/Emulators/vice/fileio/p00.h index 55825e76..868ad957 100644 --- a/src/Emulators/vice/fileio/p00.h +++ b/src/Emulators/vice/fileio/p00.h @@ -38,17 +38,22 @@ struct fileio_info_s; -extern struct fileio_info_s *p00_open(const char *file_name, const char *path, - unsigned int command, unsigned int type); -extern void p00_close(struct fileio_info_s *info); -extern unsigned int p00_read(struct fileio_info_s *info, BYTE *buf, - unsigned int len); -extern unsigned int p00_write(struct fileio_info_s *info, BYTE *buf, - unsigned int len); -extern unsigned int p00_ferror(struct fileio_info_s *info); -extern unsigned int p00_rename(const char *src_name, const char *dest_name, - const char *path); -extern unsigned int p00_scratch(const char *file_name, const char *path); -extern unsigned int p00_get_bytes_left(struct fileio_info_s *info); +struct fileio_info_s *p00_open(const char *file_name, const char *path, + unsigned int command, unsigned int type, + int *reclenp); +void p00_close(struct fileio_info_s *info); +unsigned int p00_read(struct fileio_info_s *info, uint8_t *buf, + unsigned int len); +unsigned int p00_write(struct fileio_info_s *info, uint8_t *buf, + unsigned int len); +unsigned int p00_ferror(struct fileio_info_s *info); +unsigned int p00_rename(const char *src_name, const char *dest_name, + const char *path); +unsigned int p00_scratch(const char *file_name, const char *path); +unsigned int p00_get_bytes_left(struct fileio_info_s *info); +unsigned int p00_seek(struct fileio_info_s *info, off_t offset, int whence); +unsigned int p00_tell(struct fileio_info_s *info); + +char *p00_filename_create(const char *filename, unsigned int type); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-close.c b/src/Emulators/vice/fsdevice/fsdevice-close.c index ef6cdcc4..0d971cbe 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-close.c +++ b/src/Emulators/vice/fsdevice/fsdevice-close.c @@ -39,8 +39,9 @@ #include "cbmdos.h" #include "fileio.h" #include "fsdevice-close.h" +#include "fsdevice-read.h" #include "fsdevicetypes.h" -#include "ioutil.h" +#include "archdep.h" #include "tape.h" #include "vdrive.h" @@ -49,35 +50,38 @@ int fsdevice_close(vdrive_t *vdrive, unsigned int secondary) { bufinfo_t *bufinfo; - bufinfo = fsdevice_dev[vdrive->unit - 8].bufinfo; + bufinfo = &fsdevice_dev[vdrive->unit - 8].bufinfo[secondary]; if (secondary == 15) { fsdevice_error(vdrive, CBMDOS_IPE_OK); return FLOPPY_COMMAND_OK; } - switch (bufinfo[secondary].mode) { + switch (bufinfo->mode) { + case Relative: + fsdevice_relative_pad_record(bufinfo); + /* fall through */ case Write: case Read: case Append: - if (bufinfo[secondary].tape->name) { - tape_image_close(bufinfo[secondary].tape); + if (bufinfo->tape->name) { + tape_image_close(bufinfo->tape); } else { - if (bufinfo[secondary].fileio_info != NULL) { - fileio_close(bufinfo[secondary].fileio_info); - bufinfo[secondary].fileio_info = NULL; + if (bufinfo->fileio_info != NULL) { + fileio_close(bufinfo->fileio_info); + bufinfo->fileio_info = NULL; } else { return FLOPPY_ERROR; } } break; case Directory: - if (bufinfo[secondary].ioutil_dir == NULL) { + if (bufinfo->host_dir == NULL) { return FLOPPY_ERROR; } - ioutil_closedir(bufinfo[secondary].ioutil_dir); - bufinfo[secondary].ioutil_dir = NULL; + archdep_closedir(bufinfo->host_dir); + bufinfo->host_dir = NULL; break; } diff --git a/src/Emulators/vice/fsdevice/fsdevice-close.h b/src/Emulators/vice/fsdevice/fsdevice-close.h index a4c9fb39..f187c8ad 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-close.h +++ b/src/Emulators/vice/fsdevice/fsdevice-close.h @@ -31,6 +31,6 @@ struct vdrive_s; -extern int fsdevice_close(struct vdrive_s *vdrive, unsigned int secondary); +int fsdevice_close(struct vdrive_s *vdrive, unsigned int secondary); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.c b/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.c index b5a2da1f..e0ddc24e 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.c +++ b/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.c @@ -32,171 +32,127 @@ #include "archdep.h" #include "cmdline.h" #include "fsdevice.h" -#include "ioutil.h" #include "lib.h" #include "resources.h" -#include "translate.h" #include "vicetypes.h" +#include "fsdevice-cmdline-options.h" + + static int cmdline_fsdirectory(const char *param, void *extra_param) { unsigned int unit; - char *directory; + char directory[ARCHDEP_PATH_MAX]; unit = vice_ptr_to_uint(extra_param); - directory = lib_malloc(ioutil_maxpathlen()); - strcpy(directory, param); - strcat(directory, FSDEV_DIR_SEP_STR); + snprintf(directory, ARCHDEP_PATH_MAX - 1U, "%s%s", param, ARCHDEP_DIR_SEP_STR); + directory[sizeof(directory) - 1] = '\0'; fsdevice_set_directory(directory, unit); - - lib_free(directory); - return 0; } -static const cmdline_option_t cmdline_options[] = { - { "-fs8", CALL_FUNCTION, 1, - cmdline_fsdirectory, (void *)8, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_USE_AS_DIRECTORY_FSDEVICE_8, - NULL, NULL }, - { "-fs9", CALL_FUNCTION, 1, - cmdline_fsdirectory, (void *)9, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_USE_AS_DIRECTORY_FSDEVICE_9, - NULL, NULL }, - { "-fs10", CALL_FUNCTION, 1, - cmdline_fsdirectory, (void *)10, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_USE_AS_DIRECTORY_FSDEVICE_10, - NULL, NULL }, - { "-fs11", CALL_FUNCTION, 1, - cmdline_fsdirectory, (void *)11, NULL, NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_NAME, IDCLS_USE_AS_DIRECTORY_FSDEVICE_11, - NULL, NULL }, - { "-fs8convertp00", SET_RESOURCE, 0, +static const cmdline_option_t cmdline_options[] = +{ + /* NOTE: although we use CALL_FUNCTION, we put the resource that will be + modified into the array - this helps reconstructing the cmdline */ + { "-fs8", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cmdline_fsdirectory, (void *)8, "FSDevice8Dir", NULL, + "", "Use as directory for file system device #8" }, + { "-fs9", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cmdline_fsdirectory, (void *)9, "FSDevice9Dir", NULL, + "", "Use as directory for file system device #9" }, + { "-fs10", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cmdline_fsdirectory, (void *)10, "FSDevice10Dir", NULL, + "", "Use as directory for file system device #10" }, + { "-fs11", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cmdline_fsdirectory, (void *)11, "FSDevice11Dir", NULL, + "", "Use as directory for file system device #11" }, + { "-fs8convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8ConvertP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_8_CONVERT_P00, - NULL, NULL }, - { "+fs8convertp00", SET_RESOURCE, 0, + NULL, "Enable on-read support for P00 files on drive 8" }, + { "+fs8convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8ConvertP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_8_CONVERT_P00, - NULL, NULL }, - { "-fs9convertp00", SET_RESOURCE, 0, + NULL, "Disable on-read support for P00 files on drive 8" }, + { "-fs9convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9ConvertP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_9_CONVERT_P00, - NULL, NULL }, - { "+fs9convertp00", SET_RESOURCE, 0, + NULL, "Enable on-read support for P00 files on drive 9" }, + { "+fs9convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9ConvertP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_9_CONVERT_P00, - NULL, NULL }, - { "-fs10convertp00", SET_RESOURCE, 0, + NULL, "Disable on-read support for P00 files on drive 9" }, + { "-fs10convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10ConvertP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_10_CONVERT_P00, - NULL, NULL }, - { "+fs10convertp00", SET_RESOURCE, 0, + NULL, "Enable on-read support for P00 files on drive 10" }, + { "+fs10convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10ConvertP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_10_CONVERT_P00, - NULL, NULL }, - { "-fs11convertp00", SET_RESOURCE, 0, + NULL, "Disable on-read support for P00 files on drive 10" }, + { "-fs11convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11ConvertP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_11_CONVERT_P00, - NULL, NULL }, - { "+fs11convertp00", SET_RESOURCE, 0, + NULL, "Enable on-read support for P00 files on drive 11" }, + { "+fs11convertp00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11ConvertP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_11_CONVERT_P00, - NULL, NULL }, - { "-fs8savep00", SET_RESOURCE, 0, + NULL, "Disable on-read support for P00 files on drive 11" }, + { "-fs8savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8SaveP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_8_SAVE_P00, - NULL, NULL }, - { "+fs8savep00", SET_RESOURCE, 0, + NULL, "Enable saving of P00 files on drive 8" }, + { "+fs8savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8SaveP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_8_SAVE_P00, - NULL, NULL }, - { "-fs9savep00", SET_RESOURCE, 0, + NULL, "Disable saving of P00 files on drive 8" }, + { "-fs9savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9SaveP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_9_SAVE_P00, - NULL, NULL }, - { "+fs9savep00", SET_RESOURCE, 0, + NULL, "Enable saving of P00 files on drive 9" }, + { "+fs9savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9SaveP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_9_SAVE_P00, - NULL, NULL }, - { "-fs10savep00", SET_RESOURCE, 0, + NULL, "Disable saving of P00 files on drive 9" }, + { "-fs10savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10SaveP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_10_SAVE_P00, - NULL, NULL }, - { "+fs10savep00", SET_RESOURCE, 0, + NULL, "Enable saving of P00 files on drive 10" }, + { "+fs10savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10SaveP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_10_SAVE_P00, - NULL, NULL }, - { "-fs11savep00", SET_RESOURCE, 0, + NULL, "Disable saving of P00 files on drive 10" }, + { "-fs11savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11SaveP00", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_11_SAVE_P00, - NULL, NULL }, - { "+fs11savep00", SET_RESOURCE, 0, + NULL, "Enable saving of P00 files on drive 11" }, + { "+fs11savep00", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11SaveP00", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_11_SAVE_P00, - NULL, NULL }, - { "-fs8hidecbm", SET_RESOURCE, 0, + NULL, "Disable saving of P00 files on drive 11" }, + { "-fs8hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8HideCBMFiles", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_8_HIDE_CBM, - NULL, NULL }, - { "+fs8hidecbm", SET_RESOURCE, 0, + NULL, "Hide CBM files (only show P00 files) for drive 8" }, + { "+fs8hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice8HideCBMFiles", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_FSDEVICE_8_HIDE_CBM, - NULL, NULL }, - { "-fs9hidecbm", SET_RESOURCE, 0, + NULL, "Do not hide CBM files (show all files) for drive 8" }, + { "-fs9hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9HideCBMFiles", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_9_HIDE_CBM, - NULL, NULL }, - { "+fs9hidecbm", SET_RESOURCE, 0, + NULL, "Hide CBM files (only show P00 files) for drive 9" }, + { "+fs9hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice9HideCBMFiles", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_FSDEVICE_9_HIDE_CBM, - NULL, NULL }, - { "-fs10hidecbm", SET_RESOURCE, 0, + NULL, "Do not hide CBM files (show all files) for drive 9" }, + { "-fs10hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10HideCBMFiles", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_10_HIDE_CBM, - NULL, NULL }, - { "+fs10hidecbm", SET_RESOURCE, 0, + NULL, "Hide CBM files (only show P00 files) for drive 10" }, + { "+fs10hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice10HideCBMFiles", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_FSDEVICE_10_HIDE_CBM, - NULL, NULL }, - { "-fs11hidecbm", SET_RESOURCE, 0, + NULL, "Do not hide CBM files (show all files) for drive 10" }, + { "-fs11hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11HideCBMFiles", (resource_value_t)1, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_ENABLE_FSDEVICE_11_HIDE_CBM, - NULL, NULL }, - { "+fs11hidecbm", SET_RESOURCE, 0, + NULL, "Hide CBM files (only show P00 files) for drive 11" }, + { "+fs11hidecbm", SET_RESOURCE, CMDLINE_ATTRIB_NONE, NULL, NULL, "FSDevice11HideCBMFiles", (resource_value_t)0, - USE_PARAM_STRING, USE_DESCRIPTION_ID, - IDCLS_UNUSED, IDCLS_DISABLE_FSDEVICE_11_HIDE_CBM, - NULL, NULL }, + NULL, "Do not hide CBM files (show all files) for drive 11" }, + { "-fslongnames", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "FSDeviceLongNames", (resource_value_t)1, + NULL, "Allow filenames longer than 16 characters" }, + { "+fslongnames", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "FSDeviceLongNames", (resource_value_t)0, + NULL, "Do not allow filenames longer than 16 characters" }, + { "-fsoverwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "FSDeviceOverwrite", (resource_value_t)1, + NULL, "Overwrite files without using SAVE\"@0:name\"" }, + { "+fsoverwrite", SET_RESOURCE, CMDLINE_ATTRIB_NONE, + NULL, NULL, "FSDeviceOverwrite", (resource_value_t)0, + NULL, "Refuse to overwrite files without using SAVE\"@0:name\"" }, CMDLINE_LIST_END }; diff --git a/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.h b/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.h index 163778f9..3649a33b 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.h +++ b/src/Emulators/vice/fsdevice/fsdevice-cmdline-options.h @@ -27,6 +27,6 @@ #ifndef VICE_FSDEVICE_CMDLINE_OPTIONS_H #define VICE_FSDEVICE_CMDLINE_OPTIONS_H -extern int fsdevice_cmdline_options_init(void); +int fsdevice_cmdline_options_init(void); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-filename.c b/src/Emulators/vice/fsdevice/fsdevice-filename.c new file mode 100644 index 00000000..7a43af4c --- /dev/null +++ b/src/Emulators/vice/fsdevice/fsdevice-filename.c @@ -0,0 +1,311 @@ +/* + * fsdevice-filename.c - File system device. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define DEBUGFILENAME */ + +#include "vice.h" + +#include + +#include "archdep.h" +#include "charset.h" +#include "fsdevicetypes.h" +#include "lib.h" +#include "log.h" +#include "resources.h" +#include "vdrive.h" + +#include "fsdevice-filename.h" + + +#ifdef DEBUGFILENAME +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* A lot of programs will not work right with filenames that are longer than 16 + characters, so we must shorten them somehow. unfortunately this is less than + trivial :/ + + - when creating a new file, we can just pad the name to 16 characters. this + is pretty much what a real CBM drive would do and should cause no side + effects. + + - when listing the directory, we create a short filename using a simple + algorithm: + + - count the number of files that are the same for the first 14 chars + - replace the last two chars by a) a marker that represents the counter for + the current file and b) a character that is valid in a petscii filename, + but invalid on the host filesystem. + + for example: + + 1234567890123456789012 1234567890123456 + testfoobartestest.prg becomes testfoobartest0/ + testfoobartestAB.prg becomes testfoobartest1/ + + - when opening an existing file, we iterate through the current work + directory, convert each filename to a short name using the algorithm above, + and then compare if the result matches the filename we want to open. if so, + we can use the long name of the file to open it. + + all functions below should be completely transparent (ie not change the + provided names in any way) when "FSDeviceLongNames" is set to "1". + +*/ + +/* character to be used as a marker for long names. this must be a valid character + in a petscii filename, but an invalid character in the host filesystem. in + practise that means we have to use the forward slash, as this is the only + invalid character in filenames on linux. */ +#define LONGNAMEMARKER '/' + +/* + convert real (long) name into shortened representation + + mode 0 - name is ASCII + 1 - name is PETSCII +*/ + +#define MAXDIRPOSMARK (10+26+26) + +static int _limit_longname(archdep_dir_t *archdep_dir, vdrive_t *vdrive, char *longname, int mode) +{ + const char *direntry; + char newname[ARCHDEP_PATH_MAX]; + int longnames; + int dirpos = 0; + int tmppos; + char *dirposmark[2] = { + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}; + + DBG(("limit_longname enter '%s' mode: %d\n", longname, mode)); + if (resources_get_int("FSDeviceLongNames", &longnames) < 0) { + return -1; + } + + if (!longnames) { + if (strlen(longname) > 16) { + tmppos = archdep_telldir(archdep_dir); + archdep_rewinddir(archdep_dir); + + while(1) { + direntry = archdep_readdir(archdep_dir); + if (direntry == NULL) { + break; + } + strcpy(newname, direntry); + if (mode) { + charset_petconvstring((uint8_t *)newname, CONVERT_TO_PETSCII); /* ASCII name to PETSCII */ + } + if (!strncmp(newname, longname, 14)) { + dirpos++; + /* handle max count */ + if (dirpos == MAXDIRPOSMARK) { + log_error(LOG_DEFAULT, "could not make a unique short name for '%s'", longname); + archdep_seekdir(archdep_dir, tmppos); + return -1; + } + DBG(("limit_longname found partial '%s'\n", longname)); + } + DBG(("limit_longname>%d '%s'->'%s' (%s)\n", dirpos, direntry, newname, longname)); + if (!strcmp(newname, longname)) { + DBG(("limit_longname found full '%s'\n", longname)); + longname[14] = dirposmark[mode][dirpos]; + longname[15] = LONGNAMEMARKER; + longname[16] = 0; + break; + } + } + archdep_seekdir(archdep_dir, tmppos); + } + } + DBG(("limit_longname return '%s'\n", longname)); + + return 0; +} + +static int limit_longname(vdrive_t *vdrive, char *longname, int mode) +{ + archdep_dir_t *archdep_dir; + char *prefix; + int ret = -1; + + prefix = fsdevice_get_path(vdrive->unit); + DBG(("limit_longname path '%s'\n", prefix)); + + archdep_dir = archdep_opendir(prefix, ARCHDEP_OPENDIR_ALL_FILES); + if (archdep_dir != NULL) { + ret = _limit_longname(archdep_dir, vdrive, longname, mode); + archdep_closedir(archdep_dir); + } + return ret; +} + +/* + convert shortened name into the actual (long) name + + mode 0 - name is ASCII + 1 - name is PETSCII +*/ + +static char *expand_shortname(vdrive_t *vdrive, char *shortname, int mode) +{ + archdep_dir_t *host_dir; + const char *direntry; + char *prefix; + char *longname; + int longnames; + + if (resources_get_int("FSDeviceLongNames", &longnames) < 0) { + longnames = 0; + } + + DBG(("expand_shortname shortname '%s' mode: %d\n", shortname, mode)); + + /* get a buffer for the new name */ + longname = lib_malloc(ARCHDEP_PATH_MAX); + + if (!longnames) { + prefix = fsdevice_get_path(vdrive->unit); + DBG(("expand_shortname path '%s'\n", prefix)); + + host_dir = archdep_opendir(prefix, ARCHDEP_OPENDIR_ALL_FILES); + if (host_dir == NULL) { + return NULL; + } + + while(1) { + direntry = archdep_readdir(host_dir); + if (direntry == NULL) { + break; + } + /* create the short name for this entry and see if it matches */ + strcpy(longname, direntry); + _limit_longname(host_dir, vdrive, longname, 0); + if (mode) { + charset_petconvstring((uint8_t *)longname, CONVERT_TO_PETSCII); /* ASCII name to PETSCII */ + } + DBG(("expand_shortname>'%s'->'%s'('%s')\n", direntry, longname, shortname)); + if (!strcmp(longname, shortname)) { + strcpy(longname, direntry); + if (mode) { + charset_petconvstring((uint8_t *)longname, CONVERT_TO_PETSCII); /* ASCII name to PETSCII */ + } + archdep_closedir(host_dir); + return longname; + } + } + archdep_closedir(host_dir); + } + /* copy original string to the new name */ + strcpy(longname, shortname); + DBG(("expand_shortname return '%s'\n", longname)); + return longname; +} + + +/* takes a short name and returns a pointer to a long name + + shortname: pointer to PETSCII string (filename) +*/ +char *fsdevice_expand_shortname(vdrive_t *vdrive, char *name) +{ +#ifdef DEBUGFILENAME + char *ptr = expand_shortname(vdrive, name, 1); + DBG(("fsdevice_expand_shortname '%s' (%02x) -> '%s'\n", name, (unsigned char)name[14], ptr)); + return ptr; +#else + return expand_shortname(vdrive, name, 1); +#endif +} + +/* takes a short name and returns a pointer to a long name + + shortname: pointer to ASCII string (filename) +*/ +char *fsdevice_expand_shortname_ascii(vdrive_t *vdrive, char *name) +{ +#ifdef DEBUGFILENAME + char *ptr = expand_shortname(vdrive, name, 1); + DBG(("fsdevice_expand_shortname_ascii '%s' (%02x) -> '%s'\n", name, (unsigned char)name[14], ptr)); + return ptr; +#else + return expand_shortname(vdrive, name, 0); +#endif +} + + +/* limit a filename length to 16 characters. works in-place, ie it changes + the input string + + used when listing the directory, in this case we must create a unique short + name that can be expanded to the full long name later. + + name: pointer to PETSCII string (filename) +*/ +int fsdevice_limit_namelength(vdrive_t *vdrive, uint8_t *name) +{ + return limit_longname(vdrive, (char*)name, 1); +} + +/* limit a filename length to 16 characters. works in-place, ie it changes + the input string + + used when listing the directory, in this case we must create a unique short + name that can be expanded to the full long name later. + + name: pointer to ASCII string (filename) +*/ +int fsdevice_limit_namelength_ascii(vdrive_t *vdrive, char *name) +{ + return limit_longname(vdrive, name, 0); +} + +/* limit a filename length to 16 characters. works in-place, ie it changes + the input string + + used when creating a file. in this case we can simply cut off the long + name after 16 chars - just like a real CBM drive would do. +*/ +int fsdevice_limit_createnamelength(vdrive_t *vdrive, char *name) +{ + int longnames; + + if (resources_get_int("FSDeviceLongNames", &longnames) < 0) { + return -1; + } + + if (!longnames) { + if (strlen((char*)name) > 16) { + name[16] = 0; + } + } + return 0; +} diff --git a/src/Emulators/vice/fsdevice/fsdevice-filename.h b/src/Emulators/vice/fsdevice/fsdevice-filename.h new file mode 100644 index 00000000..74e8397e --- /dev/null +++ b/src/Emulators/vice/fsdevice/fsdevice-filename.h @@ -0,0 +1,41 @@ +/* + * fsdevice-filename.h - File system device. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_FSDEVICE_FILENAME_H +#define VICE_FSDEVICE_FILENAME_H + + +#include "vdrive.h" + +int fsdevice_limit_createnamelength(vdrive_t *vdrive, char *name); + +int fsdevice_limit_namelength(vdrive_t *vdrive, uint8_t *name); +int fsdevice_limit_namelength_ascii(vdrive_t *vdrive, char *name); + +char *fsdevice_expand_shortname(vdrive_t *vdrive, char *name); +char *fsdevice_expand_shortname_ascii(vdrive_t *vdrive, char *name); + +#endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-flush.c b/src/Emulators/vice/fsdevice/fsdevice-flush.c index fa9da9ec..c8d9d2e1 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-flush.c +++ b/src/Emulators/vice/fsdevice/fsdevice-flush.c @@ -33,27 +33,40 @@ * */ +/* #define DEBUGFLUSH */ + #include "vice.h" #include #include #include +#include #include "archdep.h" #include "cbmdos.h" #include "charset.h" #include "fileio.h" #include "fsdevice-flush.h" +#include "fsdevice-filename.h" +#include "fsdevice-read.h" #include "fsdevice-resources.h" #include "fsdevice.h" #include "fsdevicetypes.h" -#include "ioutil.h" #include "lib.h" #include "log.h" #include "vicetypes.h" +#include "util.h" #include "vdrive-command.h" #include "vdrive.h" +#ifdef DEBUGFLUSH +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +#define DRIVE_UNIT_MIN 8 + static int fsdevice_flush_reset(void) { return CBMDOS_IPE_DOS_VERSION; @@ -63,19 +76,27 @@ static int fsdevice_flush_cd(vdrive_t* vdrive, char *arg) { int er; + DBG(("fsdevice_flush_cd '%s'\n", arg)); + + /* guard against NULL */ + if (arg == NULL) { + return CBMDOS_IPE_SYNTAX; + } + /* arrow left also works for dir up */ - if (!strcmp("_", arg)) { + if (strcmp("_", arg) == 0) { arg = ".."; } er = CBMDOS_IPE_OK; - if (ioutil_chdir(fsdevice_get_path(vdrive->unit)) || ioutil_chdir(arg)) { + if ((archdep_chdir(fsdevice_get_path(vdrive->unit)) != 0) + || (archdep_chdir(arg) != 0)) { er = CBMDOS_IPE_NOT_FOUND; - if (ioutil_errno(IOUTIL_ERRNO_EPERM)) { + if (errno == EPERM) { er = CBMDOS_IPE_PERMISSION; } } else { /* get full path and save */ - arg = ioutil_current_dir(); + arg = archdep_current_dir(); fsdevice_set_directory(arg, vdrive->unit); lib_free(arg); } @@ -88,28 +109,46 @@ static int fsdevice_flush_cdup(vdrive_t* vdrive) return fsdevice_flush_cd(vdrive, ".."); } -static int fsdevice_flush_mkdir(char *arg) + +/** \brief Create directory \a arg + * + * \param[in] vdrive vdrive reference + * \param[in] arg directory name + * + * \return CBMDOS error code + */ +static int fsdevice_flush_mkdir(vdrive_t *vdrive, char *arg) { int er; + char *prefix; + char *path; + + DBG(("fsdevice_flush_mkdir '%s'\n", arg)); + + /* get proper FS device path */ + prefix = fsdevice_get_path(vdrive->unit); + + /* construct absolute path */ + path = util_concat(prefix, ARCHDEP_DIR_SEP_STR, arg, NULL); er = CBMDOS_IPE_OK; - if (ioutil_mkdir(arg, IOUTIL_MKDIR_RWXUG)) { + if (archdep_mkdir(path, ARCHDEP_MKDIR_RWXUG)) { er = CBMDOS_IPE_INVAL; - if (ioutil_errno(IOUTIL_ERRNO_EEXIST)) { + if (errno == EEXIST) { er = CBMDOS_IPE_FILE_EXISTS; - } - if (ioutil_errno(IOUTIL_ERRNO_EACCES)) { + } else if (errno == EACCES) { er = CBMDOS_IPE_PERMISSION; - } - if (ioutil_errno(IOUTIL_ERRNO_ENOENT)) { + } else if (errno == ENOENT) { er = CBMDOS_IPE_NOT_FOUND; } } + lib_free(path); + return er; } -static int fsdevice_flush_partition(vdrive_t* vdrive, char* arg) +static int fsdevice_flush_partition(vdrive_t *vdrive, char* arg) { char* comma; int er; @@ -124,7 +163,7 @@ static int fsdevice_flush_partition(vdrive_t* vdrive, char* arg) for (i = 0; i < 4 && *comma++; i++) { } if (i == 4 && *comma++ == ',' && *comma++ == 'c' && !*comma) { - er = fsdevice_flush_mkdir(arg); + er = fsdevice_flush_mkdir(vdrive, arg); } else { er = CBMDOS_IPE_SYNTAX; } @@ -132,26 +171,55 @@ static int fsdevice_flush_partition(vdrive_t* vdrive, char* arg) return er; } -static int fsdevice_flush_remove(char *arg) + +/** \brief Remove directory \a arg + * + * \param[in] vdrive vdrive reference + * \param[in] arg directory to remove + * + * \return CBMDOS error code + */ +static int fsdevice_flush_rmdir(vdrive_t *vdrive, char *arg) { - int er; + int er = CBMDOS_IPE_OK; - er = CBMDOS_IPE_OK; - if (ioutil_remove(arg)) { + /* if no dir is set via 'FSDevice[8=11]Dir' this returns '.' */ + char *prefix = fsdevice_get_path(vdrive->unit); + + /* since the cwd can differ from the FSDeviceDir, we need to obtain the + * absolute path to the directory to remove. + */ + char *path = util_concat(prefix, ARCHDEP_DIR_SEP_STR, arg, NULL); + + DBG(("fsdevice_flush_rmdir '%s'\n", arg)); + + /* FIXME: rmdir() can set a lot of different errors codes, so this probably + * is a little naive + */ + if (archdep_rmdir(path) != 0) { er = CBMDOS_IPE_NOT_EMPTY; - if (ioutil_errno(IOUTIL_ERRNO_EPERM)) { + if (errno == EPERM) { er = CBMDOS_IPE_PERMISSION; } } + DBG(("fsdevice_flush_rmdir %d: %s\n", errno, strerror(errno))); + + lib_free(path); return er; } static int fsdevice_flush_rename(vdrive_t *vdrive, char *realarg) { - char *src, *dest, *tmp; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; + char *src, *dest, *tmp, *realsrc; unsigned int format = 0, rc; + DBG(("fsdevice_flush_rename '%s'\n", realarg)); + + fsdevice_dev[dnr].track = 0; + fsdevice_dev[dnr].sector = 0; + tmp = strchr(realarg, '='); if (tmp == NULL) { @@ -169,14 +237,20 @@ static int fsdevice_flush_rename(vdrive_t *vdrive, char *realarg) src = &tmp[1]; dest = realarg; - if (fsdevice_convert_p00_enabled[(vdrive->unit) - 8]) { + if (fsdevice_convert_p00_enabled[(vdrive->unit) - DRIVE_UNIT_MIN]) { format |= FILEIO_FORMAT_P00; } - if (!fsdevice_hide_cbm_files_enabled[vdrive->unit - 8]) { + if (!fsdevice_hide_cbm_files_enabled[vdrive->unit - DRIVE_UNIT_MIN]) { format |= FILEIO_FORMAT_RAW; } - rc = fileio_rename(src, dest, fsdevice_get_path(vdrive->unit), format); + realsrc = fsdevice_expand_shortname(vdrive, src); + fsdevice_limit_createnamelength(vdrive, dest); + + DBG(("fsdevice_flush_rename '%s' to '%s'\n", realsrc, dest)); + rc = fileio_rename(realsrc, dest, fsdevice_get_path(vdrive->unit), format); + + lib_free(realsrc); switch (rc) { case FILEIO_FILE_NOT_FOUND: @@ -192,73 +266,43 @@ static int fsdevice_flush_rename(vdrive_t *vdrive, char *realarg) static int fsdevice_flush_scratch(vdrive_t *vdrive, char *realarg) { + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int format = 0, rc; - if (realarg[0] == '\0') { + /* FIXME: we need to handle a comma seperated list of files to scratch */ + DBG(("fsdevice_flush_scratch '%s'\n", realarg)); + + /* set number of scratched files = 0 */ + fsdevice_dev[dnr].track = 0; + fsdevice_dev[dnr].sector = 0; + + if (realarg == NULL || *realarg == '\0') { return CBMDOS_IPE_SYNTAX; } - if (fsdevice_convert_p00_enabled[(vdrive->unit) - 8]) { + if (fsdevice_convert_p00_enabled[(vdrive->unit) - DRIVE_UNIT_MIN]) { format |= FILEIO_FORMAT_P00; } - if (!fsdevice_hide_cbm_files_enabled[vdrive->unit - 8]) { + if (!fsdevice_hide_cbm_files_enabled[vdrive->unit - DRIVE_UNIT_MIN]) { format |= FILEIO_FORMAT_RAW; } rc = fileio_scratch(realarg, fsdevice_get_path(vdrive->unit), format); switch (rc) { - case FILEIO_FILE_NOT_FOUND: - return CBMDOS_IPE_NOT_FOUND; case FILEIO_FILE_PERMISSION: return CBMDOS_IPE_PERMISSION; + case FILEIO_FILE_NOT_FOUND: + /* return "files scratched" even when no files were scratched */ + return CBMDOS_IPE_DELETED; case FILEIO_FILE_SCRATCHED: + fsdevice_dev[dnr].track = 1; /* FIXME: number of files that were scratched */ return CBMDOS_IPE_DELETED; } return CBMDOS_IPE_OK; } -/* - fake drive memory access -*/ - -/* M-R - Memory Read */ -static int fsdevice_flush_mr(vdrive_t *vdrive, char *realarg) -{ - unsigned int dnr = vdrive->unit - 8; - unsigned int length; - WORD addr; - - addr = fsdevice_dev[dnr].cmdbuf[3] | (fsdevice_dev[dnr].cmdbuf[4] << 8); - length = 6 + ((realarg != NULL) ? strlen(realarg) : 0); /* FIXME */ - return vdrive_command_memory_read(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); -} - -/* M-W - Memory Write */ -static int fsdevice_flush_mw(vdrive_t *vdrive, char *realarg) -{ - unsigned int dnr = vdrive->unit - 8; - unsigned int length; - WORD addr; - - addr = fsdevice_dev[dnr].cmdbuf[3] | (fsdevice_dev[dnr].cmdbuf[4] << 8); - length = 6 + ((realarg != NULL) ? strlen(realarg) : 0); /* FIXME */ - return vdrive_command_memory_write(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); -} - -/* M-E - Memory Execute */ -static int fsdevice_flush_me(vdrive_t *vdrive, char *realarg) -{ - unsigned int dnr = vdrive->unit - 8; - unsigned int length; - WORD addr; - - addr = fsdevice_dev[dnr].cmdbuf[3] | (fsdevice_dev[dnr].cmdbuf[4] << 8); - length = 5 + ((realarg != NULL) ? strlen(realarg) : 0); /* FIXME */ - return vdrive_command_memory_exec(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); -} - /* fake block access */ @@ -343,13 +387,15 @@ static unsigned int get_bammask(unsigned int trk, unsigned int sec) /* B-A - Block Allocate */ static int fsdevice_flush_ba(vdrive_t *vdrive, char *realarg) { - unsigned int dnr = vdrive->unit - 8; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int drv, trk, sec; unsigned int bamptr, bammask; int err = CBMDOS_IPE_OK; get4args(realarg, &drv, &trk, &sec, NULL); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-A: %d %d %d (block access needs disk image)", drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-A: %u %u %u (block access needs disk image)", + drv, trk, sec); bamptr = get_bamptr(trk, sec); bammask = get_bammask(trk, sec); @@ -384,12 +430,14 @@ static int fsdevice_flush_ba(vdrive_t *vdrive, char *realarg) /* B-F - Block Free */ static int fsdevice_flush_bf(vdrive_t *vdrive, char *realarg) { - unsigned int dnr = vdrive->unit - 8; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int drv, trk, sec; unsigned int bamptr, bammask; get4args(realarg, &drv, &trk, &sec, NULL); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-F: %d %d %d (block access needs disk image)", drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-F: %u %u %u (block access needs disk image)", + drv, trk, sec); bamptr = get_bamptr(trk, sec); bammask = get_bammask(trk, sec); @@ -403,17 +451,21 @@ static int fsdevice_flush_bp(vdrive_t *vdrive, char *realarg) { unsigned int chn, pos; get4args(realarg, &chn, &pos, NULL, NULL); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-P: %d %d (block access needs disk image)", chn, pos); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-P: %u %u (block access needs disk image)", + chn, pos); return CBMDOS_IPE_OK; } /* B-E - Block Execute */ static int fsdevice_flush_be(vdrive_t *vdrive, char *realarg) { - unsigned int dnr = vdrive->unit - 8; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int chn, drv, trk, sec; get4args(realarg, &chn, &drv, &trk, &sec); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-E: %d %d %d %d (needs TDE)", chn, drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-E: %u %u %u %u (needs TDE)", + chn, drv, trk, sec); fsdevice_dev[dnr].track = trk; fsdevice_dev[dnr].sector = sec; return CBMDOS_IPE_OK; @@ -422,10 +474,12 @@ static int fsdevice_flush_be(vdrive_t *vdrive, char *realarg) /* B-W - Block Read */ static int fsdevice_flush_br(vdrive_t *vdrive, char *realarg) { - unsigned int dnr = vdrive->unit - 8; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int chn, drv, trk, sec; get4args(realarg, &chn, &drv, &trk, &sec); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-R: %d %d %d %d (block access needs disk image)", chn, drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-R: %u %u %u %u (block access needs disk image)", + chn, drv, trk, sec); fsdevice_dev[dnr].track = trk; fsdevice_dev[dnr].sector = sec; return CBMDOS_IPE_OK; @@ -434,11 +488,13 @@ static int fsdevice_flush_br(vdrive_t *vdrive, char *realarg) /* U1, like B-R */ static int fsdevice_flush_u1(vdrive_t *vdrive, char *realarg) { - unsigned int dnr = vdrive->unit - 8; + unsigned int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int chn, drv, trk, sec; get4args(realarg, &chn, &drv, &trk, &sec); - log_message(LOG_DEFAULT, "Fsdevice: Warning - U1: %d %d %d %d (block access needs disk image)", chn, drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - U1: %u %u %u %u (block access needs disk image)", + chn, drv, trk, sec); fsdevice_dev[dnr].track = trk; fsdevice_dev[dnr].sector = sec; @@ -448,11 +504,13 @@ static int fsdevice_flush_u1(vdrive_t *vdrive, char *realarg) /* B-W - Block Write */ static int fsdevice_flush_bw(vdrive_t *vdrive, char *realarg) { - int dnr = vdrive->unit - 8; + int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int chn, drv, trk, sec; get4args(realarg, &chn, &drv, &trk, &sec); - log_message(LOG_DEFAULT, "Fsdevice: Warning - B-W: %d %d %d %d (block access needs disk image)", chn, drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - B-W: %u %u %u %u (block access needs disk image)", + chn, drv, trk, sec); fsdevice_dev[dnr].track = trk; fsdevice_dev[dnr].sector = sec; @@ -462,11 +520,13 @@ static int fsdevice_flush_bw(vdrive_t *vdrive, char *realarg) /* U2, like B-W */ static int fsdevice_flush_u2(vdrive_t *vdrive, char *realarg) { - int dnr = vdrive->unit - 8; + int dnr = vdrive->unit - DRIVE_UNIT_MIN; unsigned int chn, drv, trk, sec; get4args(realarg, &chn, &drv, &trk, &sec); - log_message(LOG_DEFAULT, "Fsdevice: Warning - U2: %d %d %d %d (block access needs disk image)", chn, drv, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - U2: %u %u %u %u (block access needs disk image)", + chn, drv, trk, sec); fsdevice_dev[dnr].track = trk; fsdevice_dev[dnr].sector = sec; @@ -476,7 +536,7 @@ static int fsdevice_flush_u2(vdrive_t *vdrive, char *realarg) /* I - Initialize Disk */ static int fsdevice_flush_initialize(vdrive_t *vdrive) { - int dnr = vdrive->unit - 8; + int dnr = vdrive->unit - DRIVE_UNIT_MIN; fsdevice_dev[dnr].track = 1; fsdevice_dev[dnr].sector = 0; @@ -487,7 +547,7 @@ static int fsdevice_flush_initialize(vdrive_t *vdrive) /* V - Validate Disk */ static int fsdevice_flush_validate(vdrive_t *vdrive) { - int dnr = vdrive->unit - 8; + int dnr = vdrive->unit - DRIVE_UNIT_MIN; fsdevice_dev[dnr].track = 1; fsdevice_dev[dnr].sector = 0; @@ -498,7 +558,7 @@ static int fsdevice_flush_validate(vdrive_t *vdrive) /* N - Format Disk */ static int fsdevice_flush_new(vdrive_t *vdrive, char *realarg) { - int dnr = vdrive->unit - 8; + int dnr = vdrive->unit - DRIVE_UNIT_MIN; fsdevice_dev[dnr].track = 1; fsdevice_dev[dnr].sector = 0; @@ -506,20 +566,94 @@ static int fsdevice_flush_new(vdrive_t *vdrive, char *realarg) return CBMDOS_IPE_OK; } +/* P - Position in RELative file */ +static int fsdevice_flush_position(vdrive_t *vdrive, char *buf, int length) +{ + int dnr = vdrive->unit - DRIVE_UNIT_MIN; + bufinfo_t *bufinfo; + unsigned int channel = buf[1] & 0x0F, + rec_lo = buf[2] & 0xFF, rec_hi = buf[3] & 0xFF, + position = buf[4] & 0xFF; + int recno; + + /* P [] */ + switch (length) { + case 1: /* no channel was specified; return NO CHANNEL */ + return CBMDOS_IPE_NO_CHANNEL; + case 2: /* default the record number to 1 */ + rec_lo = 1; + /* fall through */ + case 3: /* default the record number's high byte to 0 */ + rec_hi = 0; + /* fall through */ + case 4: /* default the position to 1 */ + position = 1; + default: + /* make compiler happy */ + break; + } + + recno = rec_hi * 256 + rec_lo; + + /* Convert 1-based numbers to 0-based */ + if (position > 0) + position--; + if (recno > 0) + recno--; + + DBG(("fsdevice_flush_position: secadr=%d recno=%d pos=%d\n", channel, recno, position)); + bufinfo = &fsdevice_dev[dnr].bufinfo[channel]; + + return fsdevice_relative_switch_record(vdrive, bufinfo, recno, position); +} + void fsdevice_flush(vdrive_t *vdrive, unsigned int secondary) { unsigned int dnr; - char *cmd, *realarg, *arg; - char *cbmcmd; + char *cmd, *realarg, *arg, *realname; + char cbmcmd[ARCHDEP_PATH_MAX]; int er = CBMDOS_IPE_SYNTAX; - dnr = vdrive->unit - 8; + dnr = vdrive->unit - DRIVE_UNIT_MIN; if ((secondary != 15) || (!(fsdevice_dev[dnr].cptr))) { return; } - cbmcmd = lib_malloc(ioutil_maxpathlen()); + /* + '41 '71 '81 FD + m-r lo hi len * * * * memory read + m-w lo hi len * * * * memory write + m-e lo hi * * * * memory execute + + */ + + /* don't change anything about the cmdbuf for M-* commands */ + if (fsdevice_dev[dnr].cmdbuf[0] == 'M' + && fsdevice_dev[dnr].cmdbuf[1] == '-' ) { + unsigned int length; + uint16_t addr; + bufferinfo_t *p = &vdrive->buffers[15]; + + addr = fsdevice_dev[dnr].cmdbuf[3] | (fsdevice_dev[dnr].cmdbuf[4] << 8); + length = fsdevice_dev[dnr].cptr; + + if (fsdevice_dev[dnr].cmdbuf[2] == 'R') { + er = vdrive_command_memory_read(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); + /* don't set status for M-R, return memory data */ + length = fsdevice_dev[dnr].cmdbuf[5]; + memcpy(fsdevice_dev[dnr].errorl, p->buffer, length + 1); + fsdevice_dev[dnr].elen = length + 1; + fsdevice_dev[dnr].eptr = 0; + } else if (fsdevice_dev[dnr].cmdbuf[2] == 'W') { + er = vdrive_command_memory_write(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); + fsdevice_error(vdrive, er); + } else if (fsdevice_dev[dnr].cmdbuf[2] == 'E') { + er = vdrive_command_memory_exec(vdrive, &fsdevice_dev[dnr].cmdbuf[5], addr, length); + fsdevice_error(vdrive, er); + } + goto leave; + } /* FIXME: Use `vdrive_command_parse()'! */ /* remove trailing cr */ @@ -531,66 +665,111 @@ void fsdevice_flush(vdrive_t *vdrive, unsigned int secondary) fsdevice_dev[dnr].cmdbuf[fsdevice_dev[dnr].cptr] = 0; strcpy(cbmcmd, (char *)(fsdevice_dev[dnr].cmdbuf)); - charset_petconvstring((BYTE *)cbmcmd, 1); /* CBM name to FSname */ + charset_petconvstring((uint8_t *)cbmcmd, CONVERT_TO_ASCII); /* CBM name to FSname */ cmd = cbmcmd; while (*cmd == ' ') { cmd++; } + /* arg points to the ASCII string after the colon */ arg = strchr(cbmcmd, ':'); - if (arg != NULL) { *arg++ = '\0'; } + /* realarg points to the PETSCII string after the colon */ realarg = strchr((char *)(fsdevice_dev[dnr].cmdbuf), ':'); - if (realarg != NULL) { *realarg++ = '\0'; } + DBG(("fsdevice_flush arg:'%s' realarg:'%s'\n", arg, realarg)); + /* - i - v - n - r - s - c - - b-r chn drv trk sec - u1 chn drv trk sec - b-w chn drv trk sec - u2 chn drv trk sec - b-p chn pos - b-a drv trk sec - b-f drv trk sec - b-e chn drv trk sec - - m-r lo hi len - m-w lo hi len - m-e lo hi - - u9/ui switch mode - u:/uj reset - - cd - cd_ - cd:_ - / - md - rd + '41 '71 '81 FD + i * * * * initialize disk + v * * * * validate BAM + n:diskname,id * * * * format disk + r:newname=oldname * * * * rename file + s:name1,name2,name3 * * * * delete file + c:newname=oldname * * * * copy file (or concat files) + d: n/a n/a n/a n/a backup + + p chn lo hi pos * * * * pointer positioning (REL) + + b-r chn drv trk sec * * * * block-read + u1 chn drv trk sec * * * * " + ua chn drv trk sec * * * " + b-R chn drv trk sec n/a n/a * block-read without range check + b-w chn drv trk sec * * * * block-write + u2 chn drv trk sec * * * * " + ub chn drv trk sec * * * " + b-W chn drv trk sec n/a n/a * block-write without range check + b-p chn pos * * * * buffer-pointer + b-a drv trk sec * * * * block-allocate + b-f drv trk sec * * * * block-free + b-e chn drv trk sec * * * * block execute + + u9/ui * * * * switch mode (NMI,warmstart) + u:/uj * * * * reset (powerup) + + u3/uc * * * * start at $0500 + u4/ud * * * * start at $0503 + u5/ue * * * * start at $0506 + u6/uf * * * * start at $0509 + u7/ug * * * * start at $050c + u8/uh * * * * start at $050f + + u0 n/a * * * restore user jumptable + u0>mode n/a * n/a n/a switch 1541/71 mode + u0>side n/a * n/a n/a select active disk side + u0>devnr n/a * n/a n/a set device nr. + u0+cmd n/a n/a * * burst utility cmd + + cd n/a n/a n/a * change directory + cd_ n/a n/a n/a + cd:_ n/a n/a n/a * + + /:name trk src lenlo lenhi,c n/a n/a * partition (create) + /:name n/a n/a * partition (activate) + + md n/a n/a n/a * make directory + rd n/a n/a n/a * remove directory + + cp n/a n/a n/a * change partition + g-p n/a n/a n/a * get partition info + + t-ra n/a n/a n/a * read RTC (ascii format) + t-wa n/a n/a n/a * write RTC (ascii format) + t-rd n/a n/a n/a * read RTC (decimal ormat) + t-wd n/a n/a n/a * write RTC (decimal format) + + r-h: n/a n/a n/a * change directory header + l: n/a n/a n/a * (un)lock file (toggle) + w- n/a n/a n/a * set disk write protection + s- n/a n/a n/a * swap device nr. + g-d n/a n/a n/a * get disk change status + */ - if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "M-R", 3)) { - er = fsdevice_flush_mr(vdrive, realarg); - } else if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "M-W", 3)) { - er = fsdevice_flush_mw(vdrive, realarg); - } else if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "M-E", 3)) { - er = fsdevice_flush_me(vdrive, realarg); - } else if (!strcmp(cmd, "u1")) { + if (!strcmp(cmd, "u0")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u1") || !strcmp(cmd, "ua")) { er = fsdevice_flush_u1(vdrive, realarg); - } else if (!strcmp(cmd, "u2")) { + } else if (!strcmp(cmd, "u2") || !strcmp(cmd, "ub")) { er = fsdevice_flush_u2(vdrive, realarg); + } else if (!strcmp(cmd, "u3") || !strcmp(cmd, "uc")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u4") || !strcmp(cmd, "ud")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u5") || !strcmp(cmd, "ue")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u6") || !strcmp(cmd, "uf")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u7") || !strcmp(cmd, "ug")) { + /* FIXME: not implemented */ + } else if (!strcmp(cmd, "u8") || !strcmp(cmd, "uh")) { + /* FIXME: not implemented */ } else if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "B-A", 3)) { er = fsdevice_flush_ba(vdrive, realarg); } else if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "B-F", 3)) { @@ -604,7 +783,9 @@ void fsdevice_flush(vdrive_t *vdrive, unsigned int secondary) } else if (!strncmp((char *)(fsdevice_dev[dnr].cmdbuf), "B-E", 3)) { er = fsdevice_flush_be(vdrive, realarg); } else if (!strcmp(cmd, "cd")) { - er = fsdevice_flush_cd(vdrive, arg); + realname = fsdevice_expand_shortname_ascii(vdrive, arg); + er = fsdevice_flush_cd(vdrive, realname); + lib_free(realname); } else if (!strcmp((char *)(fsdevice_dev[dnr].cmdbuf), "CD_")) { er = fsdevice_flush_cdup(vdrive); } else if (!strcmp((char *)(fsdevice_dev[dnr].cmdbuf), "CD:_")) { @@ -612,9 +793,14 @@ void fsdevice_flush(vdrive_t *vdrive, unsigned int secondary) } else if (*cmd == '/') { er = fsdevice_flush_partition(vdrive, arg); } else if (!strcmp(cmd, "md")) { - er = fsdevice_flush_mkdir(arg); + /* FIXME: is this really correct? perhaps we must consider a full path + here and only limit the last portion? */ + fsdevice_limit_createnamelength(vdrive, arg); + er = fsdevice_flush_mkdir(vdrive, arg); } else if (!strcmp(cmd, "rd")) { - er = fsdevice_flush_remove(arg); + realname = fsdevice_expand_shortname_ascii(vdrive, arg); + er = fsdevice_flush_rmdir(vdrive, realname); + lib_free(realname); } else if ((!strcmp(cmd, "ui")) || (!strcmp(cmd, "u9"))) { er = fsdevice_flush_reset(); } else if ((!strcmp(cmd, "uj")) || (!strcmp(cmd, "u:"))) { @@ -627,27 +813,36 @@ void fsdevice_flush(vdrive_t *vdrive, unsigned int secondary) er = fsdevice_flush_new(vdrive, realarg); } else if (*cmd == 'r' && arg != NULL) { er = fsdevice_flush_rename(vdrive, realarg); + } else if (*cmd == 'c' && arg != NULL) { + /* FIXME: not implemented */ + } else if (*cmd == 'p') { + er = fsdevice_flush_position(vdrive, + (char *)(fsdevice_dev[dnr].cmdbuf), + fsdevice_dev[dnr].cptr); } else if (*cmd == 's' && arg != NULL) { + /* FIXME: a comma seperated list of files is not handled at all */ + realname = fsdevice_expand_shortname(vdrive, realarg); er = fsdevice_flush_scratch(vdrive, realarg); + lib_free(realname); } fsdevice_error(vdrive, er); - fsdevice_dev[dnr].cptr = 0; +leave: - lib_free(cbmcmd); + fsdevice_dev[dnr].cptr = 0; } -int fsdevice_flush_write_byte(vdrive_t *vdrive, BYTE data) +int fsdevice_flush_write_byte(vdrive_t *vdrive, uint8_t data) { unsigned int dnr; int rc; - dnr = vdrive->unit - 8; + dnr = vdrive->unit - DRIVE_UNIT_MIN; rc = SERIAL_OK; /* FIXME: Consider the real size of the input buffer. */ - if (fsdevice_dev[dnr].cptr < ioutil_maxpathlen() - 1) { + if (fsdevice_dev[dnr].cptr < (ARCHDEP_PATH_MAX - 1U)) { fsdevice_dev[dnr].cmdbuf[(fsdevice_dev[dnr].cptr)++] = data; rc = SERIAL_OK; } else { diff --git a/src/Emulators/vice/fsdevice/fsdevice-flush.h b/src/Emulators/vice/fsdevice/fsdevice-flush.h index b245cbb1..f4d8430d 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-flush.h +++ b/src/Emulators/vice/fsdevice/fsdevice-flush.h @@ -29,6 +29,6 @@ struct vdrive_s; -extern void fsdevice_flush(struct vdrive_s *vdrive, unsigned int secondary); +void fsdevice_flush(struct vdrive_s *vdrive, unsigned int secondary); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-open.c b/src/Emulators/vice/fsdevice/fsdevice-open.c index 258ba622..49b3f8a2 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-open.c +++ b/src/Emulators/vice/fsdevice/fsdevice-open.c @@ -1,18 +1,17 @@ -/* - * fsdevice-open.c - File system device. - * - * Written by - * Andreas Boose - * - * Based on old code by - * Teemu Rantanen - * Jarkko Sonninen - * Jouko Valta - * Olaf Seibert - * Andre Fachat - * Ettore Perazzoli - * pottendo +/** \file fsdevice-open.c + * \brief File system device * + * \author Andreas Boose + * \author Teemu Rantanen + * \author Jarkko Sonninen + * \author Jouko Valta + * \author Olaf Seibert + * \author Andre Fachat + * \author Ettore Perazzoli + * \author pottendo + */ + +/* * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * @@ -35,7 +34,7 @@ #include "vice.h" -/* #define DEBUG_DRIVE */ +/* #define DEBUG_DRIVEOPEN */ #include #include @@ -46,26 +45,71 @@ #include "cbmdos.h" #include "charset.h" #include "fileio.h" -#include "fsdevice-open.h" +#include "fsdevice-filename.h" +#include "fsdevice-read.h" #include "fsdevice-resources.h" #include "fsdevice-write.h" #include "fsdevicetypes.h" -#include "ioutil.h" #include "lib.h" #include "log.h" +#include "resources.h" #include "tape.h" #include "vdrive-command.h" #include "vdrive.h" #include "util.h" +#include "fsdevice-open.h" + +#ifdef DEBUG_DRIVEOPEN +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +/* shorten the path shown in the disk header to 16 characters */ +static uint8_t *makeshortheader(uint8_t *p) +{ + int longnames = 0; + size_t n; + uint8_t *d; + + if (resources_get_int("FSDeviceLongNames", &longnames) < 0) { + return p; + } + n = strlen((char*)p); + if (!longnames && (n > 16)) { + d = p + (n - 1); /* point to last char */ + /* scan backwards until path seperator */ + while (d != p) { + if (*d == ARCHDEP_DIR_SEP_CHR) { + d++; n = 0; + /* copy last part to the beginning */ + while (d) { + p[n] = *d; + n++; + if (n == 16) { + break; + } + d++; + } + p[n] = 0; + return p; + } + d--; + } + /* if for some reason the above fails, hard-limit to 16 chars */ + p[16] = 0; + } + return p; +} static int fsdevice_open_directory(vdrive_t *vdrive, unsigned int secondary, bufinfo_t *bufinfo, cbmdos_cmd_parse_t *cmd_parse, char *rname) { - struct ioutil_dir_s *ioutil_dir; + archdep_dir_t *host_dir; char *mask; - BYTE *p; + uint8_t *p; int i; if ((secondary != 0) || (bufinfo[secondary].mode != Read)) { @@ -77,60 +121,69 @@ static int fsdevice_open_directory(vdrive_t *vdrive, unsigned int secondary, mask = rname; } - /* Test on wildcards. */ - if (cbmdos_parse_wildcard_check(mask, (unsigned int)strlen(mask))) { - if (*mask == '/') { + /* Test if a pattern was given (even the NUL one that matches nothing) */ + if (cmd_parse->parselength > 0) { + if (mask[0] == '/') { strcpy(bufinfo[secondary].dirmask, mask + 1); *mask++ = 0; } else { + /* For the NUL pattern, use a character that can't appear + * in file names: the directory separator. */ + if (!mask[0]) { + mask = ARCHDEP_DIR_SEP_STR; + } strcpy(bufinfo[secondary].dirmask, mask); lib_free(cmd_parse->parsecmd); - cmd_parse->parsecmd = lib_stralloc(fsdevice_get_path(vdrive->unit)); + cmd_parse->parsecmd = lib_strdup(fsdevice_get_path(vdrive->unit)); } } else { bufinfo[secondary].dirmask[0] = '\0'; if (!*(cmd_parse->parsecmd)) { lib_free(cmd_parse->parsecmd); - cmd_parse->parsecmd = lib_stralloc(fsdevice_get_path(vdrive->unit)); + cmd_parse->parsecmd = lib_strdup(fsdevice_get_path(vdrive->unit)); } } /* trying to open */ - ioutil_dir = ioutil_opendir((char *)(cmd_parse->parsecmd)); - if (ioutil_dir == NULL) { - for (p = (BYTE *)(cmd_parse->parsecmd); *p; p++) { - if (isupper((int)*p)) { - *p = tolower((int)*p); + host_dir = archdep_opendir((char *)(cmd_parse->parsecmd), ARCHDEP_OPENDIR_ALL_FILES); + if (host_dir == NULL) { + for (p = (uint8_t *)(cmd_parse->parsecmd); *p; p++) { + if (isupper((unsigned char)*p)) { + *p = tolower((unsigned char)*p); } } - ioutil_dir = ioutil_opendir((char *)(cmd_parse->parsecmd)); - if (ioutil_dir == NULL) { + host_dir = archdep_opendir((char *)(cmd_parse->parsecmd), ARCHDEP_OPENDIR_ALL_FILES); + if (host_dir == NULL) { fsdevice_error(vdrive, CBMDOS_IPE_NOT_FOUND); return FLOPPY_ERROR; } } strcpy(bufinfo[secondary].dir, cmd_parse->parsecmd); /* - * Start Address, Line Link and Line number 0 + * Start Address, Line Link and Line number 1 (=partition 1) */ p = bufinfo[secondary].name; - + /* start address = 0x0401 */ *p++ = 1; *p++ = 4; - + /* who knows why this is 0x0101 ? */ *p++ = 1; *p++ = 1; - - *p++ = 0; + /* CMD puts the partition number here, it shouldn't be 0 (like on 1541) so + programs that expect a CMD device are happy with it */ + *p++ = 1; *p++ = 0; - *p++ = (BYTE)0x12; /* Reverse on */ + *p++ = (uint8_t)0x12; /* Reverse on */ *p++ = '"'; strcpy((char *)p, bufinfo[secondary].dir); /* Dir name */ - charset_petconvstring((BYTE *)p, 0); /* ASCII name to PETSCII */ + charset_petconvstring((uint8_t *)p, CONVERT_TO_PETSCII); /* ASCII name to PETSCII */ i = 0; + + makeshortheader(p); + while (*p) { ++p; i++; @@ -139,19 +192,27 @@ static int fsdevice_open_directory(vdrive_t *vdrive, unsigned int secondary, *p++ = ' '; i++; } + + /* put the drive-unit and drive number into the "format id" */ *p++ = '"'; *p++ = ' '; - *p++ = 'V'; - *p++ = 'I'; - *p++ = 'C'; - *p++ = 'E'; - *p++ = ' '; + if (vdrive->unit < 10) { + *p++ = ' '; + *p++ = '#'; + *p++ = '0' + vdrive->unit; + } else { + *p++ = '#'; + *p++ = '1'; + *p++ = '0' + (vdrive->unit - 10); + } + *p++ = ':'; + *p++ = '0'; *p++ = 0; bufinfo[secondary].buflen = (int)(p - bufinfo[secondary].name); bufinfo[secondary].bufp = bufinfo[secondary].name; bufinfo[secondary].mode = Directory; - bufinfo[secondary].ioutil_dir = ioutil_dir; + bufinfo[secondary].host_dir = host_dir; bufinfo[secondary].eof = 0; return FLOPPY_COMMAND_OK; @@ -162,9 +223,11 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse, char *rname) { char *comma; + char *newrname; tape_image_t *tape; unsigned int format = 0; fileio_info_t *finfo; + int fileio_command; if (fsdevice_convert_p00_enabled[(vdrive->unit) - 8]) { format |= FILEIO_FORMAT_P00; @@ -195,14 +258,30 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, /* Open file for write mode access. */ if (bufinfo[secondary].mode == Write) { + if (fsdevice_save_p00_enabled[vdrive->unit - 8]) { format = FILEIO_FORMAT_P00; } else { format = FILEIO_FORMAT_RAW; } + DBG(("fsdevice_open_file write '%s'\n", rname)); + fsdevice_limit_createnamelength(vdrive, rname); + DBG(("fsdevice_open_file write limited: '%s'\n", rname)); + + if (cmd_parse->atsign) { + /* TODO: maybe rename to a backup name */ + DBG(("fsdevice_open_file overwrite @'%s'\n", rname)); + fileio_command = FILEIO_COMMAND_OVERWRITE; + } else if (fsdevice_overwrite_existing_files) { + fileio_command = FILEIO_COMMAND_OVERWRITE; + } else { + fileio_command = FILEIO_COMMAND_WRITE; + } + finfo = fileio_open(rname, fsdevice_get_path(vdrive->unit), format, - FILEIO_COMMAND_WRITE, bufinfo[secondary].type); + fileio_command, bufinfo[secondary].type, + &bufinfo[secondary].reclen); if (finfo != NULL) { bufinfo[secondary].fileio_info = finfo; @@ -216,9 +295,14 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, if (bufinfo[secondary].mode == Append) { /* Open file for append mode access. */ - finfo = fileio_open(rname, fsdevice_get_path(vdrive->unit), format, + DBG(("fsdevice_open_file append '%s'\n", rname)); + newrname = fsdevice_expand_shortname(vdrive, rname); + DBG(("fsdevice_open_file append expanded '%s'\n", newrname)); + finfo = fileio_open(newrname, fsdevice_get_path(vdrive->unit), format, FILEIO_COMMAND_APPEND_READ, - bufinfo[secondary].type); + bufinfo[secondary].type, + &bufinfo[secondary].reclen); + lib_free(newrname); if (finfo != NULL) { bufinfo[secondary].fileio_info = finfo; @@ -230,13 +314,13 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, } } - /* Open file for read mode access. */ + /* Open file for read or relative mode access. */ tape = bufinfo[secondary].tape; tape->name = util_concat(fsdevice_get_path(vdrive->unit), - FSDEV_DIR_SEP_STR, rname, NULL); - charset_petconvstring((BYTE *)(tape->name) + + ARCHDEP_DIR_SEP_STR, rname, NULL); + charset_petconvstring((uint8_t *)(tape->name) + strlen(fsdevice_get_path(vdrive->unit)) + - strlen(FSDEV_DIR_SEP_STR), 1); + strlen(ARCHDEP_DIR_SEP_STR), CONVERT_TO_ASCII); tape->read_only = 1; /* Prepare for buffered reads */ bufinfo[secondary].isbuffered = 0; @@ -246,7 +330,7 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, tape->name = NULL; } else { tape_file_record_t *r; - static BYTE startaddr[2]; + static uint8_t startaddr[2]; tape_seek_start(tape); tape_seek_to_file(tape, 0); r = tape_get_current_file_record(tape); @@ -262,12 +346,29 @@ static int fsdevice_open_file(vdrive_t *vdrive, unsigned int secondary, return FLOPPY_COMMAND_OK; } - finfo = fileio_open(rname, fsdevice_get_path(vdrive->unit), format, - FILEIO_COMMAND_READ, bufinfo[secondary].type); + + DBG(("fsdevice_open_file read '%s'\n", rname)); + newrname = fsdevice_expand_shortname(vdrive, rname); + DBG(("fsdevice_open_file read expanded '%s'\n", newrname)); + + fileio_command = + bufinfo[secondary].mode == Relative ? FILEIO_COMMAND_READ_WRITE + : FILEIO_COMMAND_READ; + + finfo = fileio_open(newrname, fsdevice_get_path(vdrive->unit), format, + fileio_command, bufinfo[secondary].type, + &bufinfo[secondary].reclen); + + lib_free(newrname); if (finfo != NULL) { bufinfo[secondary].fileio_info = finfo; fsdevice_error(vdrive, CBMDOS_IPE_OK); + + if (bufinfo[secondary].mode == Relative) { + fsdevice_relative_switch_record(vdrive, &bufinfo[secondary], 0, 0); + } + return FLOPPY_COMMAND_OK; } @@ -284,18 +385,16 @@ static int fsdevice_open_buffer(vdrive_t *vdrive, unsigned int secondary, return FLOPPY_COMMAND_OK; } -int fsdevice_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, +int fsdevice_open(vdrive_t *vdrive, const uint8_t *name, unsigned int length, unsigned int secondary, cbmdos_cmd_parse_t *cmd_parse_ext) { - char *rname; + char rname[ARCHDEP_PATH_MAX]; int status = 0, rc; unsigned int i; cbmdos_cmd_parse_t cmd_parse; bufinfo_t *bufinfo; -#ifdef DEBUG_DRIVE - log_debug("fsdevice_open name:'%s'", name); -#endif + DBG(("fsdevice_open name:'%s' (secondary:%u)\n", name, secondary)); bufinfo = fsdevice_dev[vdrive->unit - 8].bufinfo; @@ -309,37 +408,55 @@ int fsdevice_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, } return status; } - cmd_parse.cmd = name; cmd_parse.cmdlength = length; cmd_parse.secondary = secondary; + DBG(("fsdevice_open cmd_parse '%s'\n", name)); + rc = cbmdos_command_parse(&cmd_parse); if (rc != SERIAL_OK) { status = SERIAL_ERROR; goto out; } - bufinfo[secondary].type = cmd_parse.filetype; + /* + Check for '@0:filename' or '@:filename'. Must include a ':'. + (original filename starts with '@', but parsed version doesn't) + '@filename' will open a file starting with '@'! + */ + if (length > 0 && name[0] == '@' && + !(cmd_parse.parselength > 0 && cmd_parse.parsecmd[0] == '@')) { + cmd_parse.atsign = 1; + } - rname = lib_malloc(ioutil_maxpathlen()); + bufinfo[secondary].type = cmd_parse.filetype; + bufinfo[secondary].reclen = cmd_parse.recordlength; + bufinfo[secondary].num_records = -1; cmd_parse.parsecmd[cmd_parse.parselength] = 0; strncpy(rname, cmd_parse.parsecmd, cmd_parse.parselength + 1); /* CBM name to FSname */ - charset_petconvstring((BYTE *)(cmd_parse.parsecmd), 1); - - switch (cmd_parse.readmode) { - case CBMDOS_FAM_WRITE: - bufinfo[secondary].mode = Write; - break; - case CBMDOS_FAM_READ: - bufinfo[secondary].mode = Read; - break; - case CBMDOS_FAM_APPEND: - bufinfo[secondary].mode = Append; - break; + charset_petconvstring((uint8_t *)(cmd_parse.parsecmd), CONVERT_TO_ASCII); + DBG(("fsdevice_open rname: %s\n", rname)); + + if (cmd_parse.filetype == CBMDOS_FT_REL) { + /* REL files override whatever rwmode has been inferred by + * parsecmd() */ + bufinfo[secondary].mode = Relative; + } else { + switch (cmd_parse.readmode) { + case CBMDOS_FAM_WRITE: + bufinfo[secondary].mode = Write; + break; + case CBMDOS_FAM_READ: + bufinfo[secondary].mode = Read; + break; + case CBMDOS_FAM_APPEND: + bufinfo[secondary].mode = Append; + break; + } } /* @@ -350,7 +467,9 @@ int fsdevice_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, not found" - so it is the best we can do in that case, too. */ if (strlen((const char*)name) != length) { - log_message(LOG_DEFAULT, "Fsdevice: Warning - filename '%s' with bogus length '%d'.", cmd_parse.parsecmd, length); + log_message(LOG_DEFAULT, + "Fsdevice: Warning - filename '%s' with bogus length '%u'.", + cmd_parse.parsecmd, length); status = CBMDOS_IPE_NOT_FOUND; goto out; } @@ -363,8 +482,6 @@ int fsdevice_open(vdrive_t *vdrive, const BYTE *name, unsigned int length, status = fsdevice_open_file(vdrive, secondary, bufinfo, &cmd_parse, rname); } - lib_free(rname); - if (status != FLOPPY_COMMAND_OK) { goto out; } diff --git a/src/Emulators/vice/fsdevice/fsdevice-open.h b/src/Emulators/vice/fsdevice/fsdevice-open.h index 2339e1ae..9f814001 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-open.h +++ b/src/Emulators/vice/fsdevice/fsdevice-open.h @@ -32,8 +32,8 @@ struct cbmdos_cmd_parse_s; struct vdrive_s; -extern int fsdevice_open(struct vdrive_s *vdrive, const BYTE *name, - unsigned int length, unsigned int secondary, - struct cbmdos_cmd_parse_s *cmd_parse_ext); +int fsdevice_open(struct vdrive_s *vdrive, const uint8_t *name, + unsigned int length, unsigned int secondary, + struct cbmdos_cmd_parse_s *cmd_parse_ext); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-read.c b/src/Emulators/vice/fsdevice/fsdevice-read.c index aecd99e6..4cf4c35e 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-read.c +++ b/src/Emulators/vice/fsdevice/fsdevice-read.c @@ -8,7 +8,7 @@ * Teemu Rantanen * Jarkko Sonninen * Jouko Valta - * Olaf Seibert + * Olaf Seibert * Andre Fachat * Ettore Perazzoli * pottendo @@ -41,17 +41,27 @@ #include "archdep.h" #include "cbmdos.h" #include "fileio.h" -#include "fsdevice-read.h" +#include "fsdevice-filename.h" #include "fsdevice-resources.h" #include "fsdevicetypes.h" -#include "ioutil.h" #include "lib.h" #include "tape.h" #include "vicetypes.h" #include "vdrive.h" +#include "fsdevice-read.h" + + +/* #define REL_DEBUG */ -static int command_read(bufinfo_t *bufinfo, BYTE *data) +#ifdef REL_DEBUG +# define DBG(x) log_printf x +# include "log.h" +#else +# define DBG(x) +#endif + +static int command_read(bufinfo_t *bufinfo, uint8_t *data) { if (bufinfo->tape->name) { if (bufinfo->buflen > 0) { @@ -155,18 +165,229 @@ static int command_read(bufinfo_t *bufinfo, BYTE *data) return FLOPPY_ERROR; } +void fsdevice_relative_pad_record(bufinfo_t *bufinfo) +{ + if (bufinfo->record_is_dirty) { + uint8_t filler = 0x00; + + /* + * Mixing reading and writing of a single record isn't + * allowed on a real drive, but try to support it anyway. + */ + if (bufinfo->isbuffered) { + fileio_seek(bufinfo->fileio_info, -1, SEEK_CUR); + bufinfo->position_in_record--; + bufinfo->isbuffered = 0; + } + + /* + * Fill the remainder of the record, from the current + * position to the end, with 00. + */ + while (bufinfo->position_in_record < bufinfo->reclen) { + fileio_write(bufinfo->fileio_info, &filler, 1); + bufinfo->position_in_record++; + } + + bufinfo->record_is_dirty = 0; + } +} + +int fsdevice_relative_switch_record(vdrive_t *vdrive, bufinfo_t *bufinfo, + int record, int pos) +{ + int rec_len = bufinfo->reclen; + int fserror = CBMDOS_IPE_OK; + unsigned int file_off; + + DBG(("fsdevice_relative_switch_record: rec_len=%d %d.%d", + rec_len, record, pos)); + + if (rec_len == 0) { + fsdevice_error(vdrive, CBMDOS_IPE_NO_RECORD); + return SERIAL_ERROR; + } else if (pos >= rec_len) { + fsdevice_error(vdrive, CBMDOS_IPE_OVERFLOW); + return SERIAL_ERROR; + } + + /* + * If we get here for the first time, calculate how many + * records there are in the file. + */ + if (bufinfo->num_records <= 0) { + off_t nbytes; + fileio_seek(bufinfo->fileio_info, 0, SEEK_SET); + nbytes = fileio_get_bytes_left(bufinfo->fileio_info); + bufinfo->num_records = (int)((nbytes + bufinfo->reclen - 1) / + bufinfo->reclen); + DBG(("fsdevice_relative_switch_record: num_records=%d", + bufinfo->num_records)); + } + + file_off = record * rec_len + pos; + + /* + * If we switch to a DIFFERENT record, the current one is finished + * and we need to mark the end of the record as such. + */ + if (record != bufinfo->current_record) { + fsdevice_relative_pad_record(bufinfo); + } + + fileio_seek(bufinfo->fileio_info, file_off, SEEK_SET); + bufinfo->isbuffered = 0; + + if (record >= bufinfo->num_records) { + /* + * Don't actually extend the file yet. + * That happens when the user writes a byte. + */ + + if (record > 0) { + fserror = CBMDOS_IPE_NO_RECORD; + bufinfo->current_record_length = 0; + } + + /* + * What error should we give if ALSO pos > 0? + */ + } + + bufinfo->current_record = record; + bufinfo->position_in_record = pos; + bufinfo->iseof = 0; + + /* + * Detect the length of the new current record. + * Just wastefully read the whole thing byte by byte, + * and remember where the last non-00 byte is. + */ + if (fserror == CBMDOS_IPE_OK) { + int testpos; + + /* Records can never be completely empty. */ + bufinfo->current_record_length = pos + 1; + + for (testpos = pos; testpos < bufinfo->reclen; testpos++) { + uint8_t testbyte; + int len; + + len = fileio_read(bufinfo->fileio_info, &testbyte, 1); + + if (len == 1 && testbyte != 0) { + bufinfo->current_record_length = testpos + 1; + } + } + + fileio_seek(bufinfo->fileio_info, file_off, SEEK_SET); + DBG(("fsdevice_relative_switch_record: current_record_length=%d", + bufinfo->current_record_length)); + } + + if (fserror != CBMDOS_IPE_OK) { + fsdevice_error(vdrive, fserror); + return SERIAL_ERROR; + } + + return SERIAL_OK; +} + +static int relative_read(vdrive_t *vdrive, bufinfo_t *bufinfo, uint8_t *data) +{ + if (bufinfo->current_record >= bufinfo->num_records) { + *data = 0x0d; + DBG(("relative_read: store '%c' %02x CBMDOS_IPE_NO_RECORD", *data, *data)); + fsdevice_error(vdrive, CBMDOS_IPE_NO_RECORD); + return SERIAL_EOF; + } + + /* + * Reading past one record gets us to the next (unlike writing). + */ + if (bufinfo->iseof) { + int err = fsdevice_relative_switch_record(vdrive, bufinfo, bufinfo->current_record + 1, 0); + DBG(("relative_read: iseof, skip to next record")); + if (err) { + return SERIAL_OK; + } + } + + /* + * If we switch from writing to reading, there must have been an + * UNLISTEN in between. Since we have no callback for it, + * check it in this way. + */ +#if 1 + if (bufinfo->record_is_dirty) { + int err = fsdevice_relative_switch_record(vdrive, bufinfo, bufinfo->current_record + 1, 0); + DBG(("relative_read: record_is_dirty, switching to read, skip to next record")); + if (err) { + return SERIAL_OK; + } + } +#endif + + /* If this is our first read, read in first byte */ + if (!bufinfo->isbuffered) { + if (bufinfo->position_in_record < bufinfo->current_record_length) { + DBG(("relative_read: !isbuffered, read a byte")); + bufinfo->iseof = !fileio_read(bufinfo->fileio_info, &(bufinfo->buffered), 1); + bufinfo->position_in_record++; + } else { + *data = 0x0d; + return SERIAL_ERROR; + } + /* We shouldn't get an EOF at this point */ + /* Check for errors */ + if (fileio_ferror(bufinfo->fileio_info)) { + *data = 0x0d; + return SERIAL_ERROR; + } + } + + /* Place it in the output field */ + *data = bufinfo->buffered; + DBG(("relative_read: store '%c' %02x", *data, *data)); + + if (bufinfo->position_in_record < bufinfo->current_record_length) { + /* DBG(("relative_read: record not exhausted (%d < %d), read a byte to buffer", bufinfo->position_in_record, bufinfo->current_record_length)); */ + /* Read the next buffer; if nothing read, set EOF signal */ + bufinfo->iseof = !fileio_read(bufinfo->fileio_info, &(bufinfo->buffered), 1); + bufinfo->position_in_record++; + /* Check for errors */ + if (fileio_ferror(bufinfo->fileio_info)) { + return SERIAL_ERROR; + } + /* Indicate we have something in the buffer for the next read */ + bufinfo->isbuffered = 1; + } else { + DBG(("relative_read: record exhausted, set iseof and !isbuffered")); + bufinfo->iseof = 1; + bufinfo->isbuffered = 0; + } + + /* If the EOF was signaled, return a CBM EOF */ + if (bufinfo->iseof) { + DBG(("relative_read: return SERIAL_EOF")); + return SERIAL_EOF; + } + + /* If not, return OK */ + return SERIAL_OK; +} + static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, - BYTE *data, unsigned int secondary) + uint8_t *data, unsigned int secondary) { int i, l, f, statrc; - unsigned int blocks; - char *direntry; - unsigned int filelen, isdir; + unsigned long blocks; + const char *direntry; + size_t filelen; + unsigned int isdir; fileio_info_t *finfo = NULL; unsigned int format = 0; - char *buf; - - buf = lib_malloc(ioutil_maxpathlen()); + char buf[ARCHDEP_PATH_MAX]; bufinfo->bufp = bufinfo->name; @@ -186,10 +407,10 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, replaced by some regex functions... */ f = 1; do { - BYTE *p; + uint8_t *p; finfo = NULL; - direntry = ioutil_readdir(bufinfo->ioutil_dir); + direntry = archdep_readdir(bufinfo->host_dir); if (direntry == NULL) { break; @@ -197,7 +418,7 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, finfo = fileio_open(direntry, bufinfo->dir, format, FILEIO_COMMAND_STAT | FILEIO_COMMAND_FSNAME, - FILEIO_TYPE_PRG); + FILEIO_TYPE_PRG, NULL); if (finfo == NULL) { continue; @@ -211,39 +432,62 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, l = (int)strlen(bufinfo->dirmask); + /* fix 2 bugs: + * - pattern A*Z would not match AZZ because it jumped to the first Z + * only. + * - pattern FOO* didn't match filename FOO + */ + for (p = finfo->name, i = 0; *p && bufinfo->dirmask[i] && i < l; i++) { if (bufinfo->dirmask[i] == '?') { p++; } else if (bufinfo->dirmask[i] == '*') { - if (!(bufinfo->dirmask[i + 1])) { + if (bufinfo->dirmask[i + 1] == '\0') { f = 0; break; } /* end mask */ - while (*p && (*p != bufinfo->dirmask[i + 1])) { - p++; + /* Handle ONE * followed by text but no more (like 1581): + * When at the * in A*XYZ, skip to 3 positions before + * the end of the file name to try to match XYZ. */ + size_t rest_of_filename = strlen((const char *)p); + size_t rest_of_pattern = strlen(&bufinfo->dirmask[i + 1]); + + if (rest_of_filename < rest_of_pattern) { + break; /* no match: file name too short */ } + p = p + rest_of_filename - rest_of_pattern; } else { if (*p != bufinfo->dirmask[i]) { break; } p++; } - if ((!*p) && (!(bufinfo->dirmask[i + 1]))) { + if (*p == '\0' && bufinfo->dirmask[i + 1] == '\0') { f = 0; break; } } + /* Check for an edge case missed by the loop: + * pattern "FOO*" should match filename "FOO". */ + if (f > 0 && + *p == '\0' && + bufinfo->dirmask[i ] == '*' && + bufinfo->dirmask[i + 1] == '\0') { + f = 0; + } if (f > 0) { fileio_close(finfo); } } while (f); if (direntry != NULL) { - BYTE *p = bufinfo->name; + uint8_t *p = bufinfo->name; + int splatfile = 0; + int protectfile = 0; strcpy(buf, bufinfo->dir); - strcat(buf, FSDEV_DIR_SEP_STR); + strcat(buf, ARCHDEP_DIR_SEP_STR); strcat(buf, direntry); /* Line link, Length and spaces */ @@ -251,15 +495,24 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, *p++ = 1; *p++ = 1; - statrc = ioutil_stat(buf, &filelen, &isdir); - if (statrc == 0) { - blocks = (filelen + 253) / 254; - } else { - blocks = 0; /* this file can't be opened */ + statrc = archdep_stat(buf, &filelen, &isdir); + if (statrc != 0) { + /* this file can't be opened */ + splatfile = 1; + protectfile = 1; + } + + if (archdep_access(buf, ARCHDEP_ACCESS_W_OK)) { + /* this file is read only */ + protectfile = 1; } + blocks = (filelen + 253) / 254; if (blocks > 0xffff) { blocks = 0xffff; /* Limit file size to 16 bits. */ + /* this file is too large, guard it against opening */ + splatfile = 1; + protectfile = 1; } SET_LO_HI(p, blocks); @@ -280,6 +533,8 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, *p++ = '"'; + fsdevice_limit_namelength(vdrive, finfo->name); + for (i = 0; finfo->name[i] && (*p = finfo->name[i]); ++i, ++p) { } @@ -294,7 +549,7 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, *p++ = 'I'; *p++ = 'R'; } else { - if (blocks) { + if (splatfile == 0) { *p++ = ' '; /* normal file */ } else { *p++ = '*'; /* splat file */ @@ -328,7 +583,7 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, } } - if (ioutil_access(buf, IOUTIL_ACCESS_W_OK)) { + if (protectfile) { *p++ = '<'; /* read-only file */ } @@ -346,14 +601,14 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, bufinfo->buflen = (int)(p - bufinfo->name); } else { - BYTE *p = bufinfo->name; + uint8_t *p = bufinfo->name; /* EOF => End file */ *p++ = 1; *p++ = 1; - *p++ = 0; - *p++ = 0; + *p++ = 255; /* 65535 blocks free */ + *p++ = 255; memcpy(p, "BLOCKS FREE.", 12); p += 12; memset(p, ' ', 13); @@ -367,15 +622,13 @@ static void command_directory_get(vdrive_t *vdrive, bufinfo_t *bufinfo, if (finfo != NULL) { fileio_close(finfo); } - - lib_free(buf); } static int command_directory(vdrive_t *vdrive, bufinfo_t *bufinfo, - BYTE *data, unsigned int secondary) + uint8_t *data, unsigned int secondary) { - if (bufinfo->ioutil_dir == NULL) { + if (bufinfo->host_dir == NULL) { return FLOPPY_ERROR; } @@ -399,7 +652,7 @@ static int command_directory(vdrive_t *vdrive, bufinfo_t *bufinfo, return SERIAL_OK; } -int fsdevice_read(vdrive_t *vdrive, BYTE *data, unsigned int secondary) +int fsdevice_read(vdrive_t *vdrive, uint8_t *data, unsigned int secondary) { bufinfo_t *bufinfo = &(fsdevice_dev[vdrive->unit - 8].bufinfo[secondary]); @@ -413,6 +666,8 @@ int fsdevice_read(vdrive_t *vdrive, BYTE *data, unsigned int secondary) return FLOPPY_ERROR; case Read: return command_read(bufinfo, data); + case Relative: + return relative_read(vdrive, bufinfo, data); case Directory: return command_directory(vdrive, bufinfo, data, secondary); } diff --git a/src/Emulators/vice/fsdevice/fsdevice-read.h b/src/Emulators/vice/fsdevice/fsdevice-read.h index 9682b56c..20e80b29 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-read.h +++ b/src/Emulators/vice/fsdevice/fsdevice-read.h @@ -30,8 +30,13 @@ #include "vicetypes.h" struct vdrive_s; +struct bufinfo_s; -extern int fsdevice_read(struct vdrive_s *vdrive, BYTE *data, - unsigned int secondary); +int fsdevice_read(struct vdrive_s *vdrive, uint8_t *data, + unsigned int secondary); +void fsdevice_relative_pad_record(struct bufinfo_s *bufinfo); +int fsdevice_relative_switch_record(struct vdrive_s *vdrive, + struct bufinfo_s *bufinfo, + int record, int pos); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-resources.c b/src/Emulators/vice/fsdevice/fsdevice-resources.c index f57c766c..b78d5efd 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-resources.c +++ b/src/Emulators/vice/fsdevice/fsdevice-resources.c @@ -40,6 +40,8 @@ int fsdevice_convert_p00_enabled[4]; int fsdevice_save_p00_enabled[4]; int fsdevice_hide_cbm_files_enabled[4]; char *fsdevice_dir[4] = { NULL, NULL, NULL, NULL }; +int fsdevice_allow_long_names; +int fsdevice_overwrite_existing_files; static int set_fsdevice_convert_p00(int val, void *param) @@ -72,16 +74,28 @@ static int set_fsdevice_hide_cbm_files(int val, void *param) return 0; } +static int set_fsdevice_allow_long_names(int val, void *param) +{ + fsdevice_allow_long_names = val ? 1 : 0; + return 0; +} + +static int set_fsdevice_overwrite_existing_files(int val, void *param) +{ + fsdevice_overwrite_existing_files = val ? 1 : 0; + return 0; +} + /* ------------------------------------------------------------------------- */ static const resource_string_t resources_string[] = { - { "FSDevice8Dir", FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, + { "FSDevice8Dir", ARCHDEP_FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, (void *)&fsdevice_dir[0], set_fsdevice_dir, (void *)8 }, - { "FSDevice9Dir", FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, + { "FSDevice9Dir", ARCHDEP_FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, (void *)&fsdevice_dir[1], set_fsdevice_dir, (void *)9 }, - { "FSDevice10Dir", FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, + { "FSDevice10Dir", ARCHDEP_FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, (void *)&fsdevice_dir[2], set_fsdevice_dir, (void *)10 }, - { "FSDevice11Dir", FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, + { "FSDevice11Dir", ARCHDEP_FSDEVICE_DEFAULT_DIR, RES_EVENT_NO, NULL, (void *)&fsdevice_dir[3], set_fsdevice_dir, (void *)11 }, RESOURCE_STRING_LIST_END }; @@ -123,6 +137,12 @@ static const resource_int_t resources_int[] = { { "FSDevice11HideCBMFiles", 0, RES_EVENT_NO, NULL, &fsdevice_hide_cbm_files_enabled[3], set_fsdevice_hide_cbm_files, (void *)11 }, + { "FSDeviceLongNames", 0, RES_EVENT_NO, NULL, + &fsdevice_allow_long_names, + set_fsdevice_allow_long_names, NULL }, + { "FSDeviceOverwrite", 0, RES_EVENT_NO, NULL, + &fsdevice_overwrite_existing_files, + set_fsdevice_overwrite_existing_files, NULL }, RESOURCE_INT_LIST_END }; diff --git a/src/Emulators/vice/fsdevice/fsdevice-resources.h b/src/Emulators/vice/fsdevice/fsdevice-resources.h index fca4e821..03227e98 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-resources.h +++ b/src/Emulators/vice/fsdevice/fsdevice-resources.h @@ -31,5 +31,6 @@ extern int fsdevice_convert_p00_enabled[4]; extern int fsdevice_save_p00_enabled[4]; extern int fsdevice_hide_cbm_files_enabled[4]; extern char *fsdevice_dir[4]; +extern int fsdevice_overwrite_existing_files; #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice-write.c b/src/Emulators/vice/fsdevice/fsdevice-write.c index 49bad83f..a3d2a0c5 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-write.c +++ b/src/Emulators/vice/fsdevice/fsdevice-write.c @@ -39,31 +39,126 @@ #include "fileio.h" #include "fsdevice-flush.h" +#include "fsdevice-read.h" #include "fsdevice-write.h" #include "fsdevicetypes.h" #include "vicetypes.h" #include "vdrive.h" +#include "vdrive/vdrive-command.h" +/* #define REL_DEBUG */ -int fsdevice_write(struct vdrive_s *vdrive, BYTE data, unsigned int secondary) +#ifdef REL_DEBUG +# define DBG(x) log_printf x +# include "log.h" +#else +# define DBG(x) +#endif + +static void fsdevice_rel_listen(vdrive_t *vdrive, bufinfo_t *bufinfo, unsigned int secondary) +{ + DBG(("fsdevice_rel_listen: dirty record: %d", bufinfo->record_is_dirty)); + /* + * Only move to next record if the sector is dirty (indicates + * we just wrote something) and if this is a REL file. + * All "overflows" are handled in the write routine. + * This should probably be better located in an "unlisten" + * callback, but there is none. + */ + if (bufinfo->record_is_dirty) { + fsdevice_relative_switch_record(vdrive, bufinfo, bufinfo->current_record + 1, 0); + } +} + +void fsdevice_listen(vdrive_t *vdrive, unsigned int secondary) +{ + bufinfo_t *bufinfo = &fsdevice_dev[vdrive->unit - 8].bufinfo[secondary]; + + if (bufinfo->mode == Relative) { + fsdevice_rel_listen(vdrive, bufinfo, secondary); + } +} + +static void fsdevice_relfile_extend_if_needed(bufinfo_t *bufinfo) +{ + if (bufinfo->current_record >= bufinfo->num_records) { + uint8_t filler = 0xFF; + unsigned int oldpos = fileio_tell(bufinfo->fileio_info); + + DBG(("fsdevice_relfile_extend_if_needed: curr=%d, num=%d oldpos=%u", + bufinfo->current_record, bufinfo->num_records, oldpos)); + + while (bufinfo->current_record >= bufinfo->num_records) { + unsigned int file_off = bufinfo->num_records * bufinfo->reclen; + + DBG(("fsdevice_relfile_extend_if_needed: filler at %u", + file_off)); + fileio_seek(bufinfo->fileio_info, file_off, SEEK_SET); + fileio_write(bufinfo->fileio_info, &filler, 1); + + bufinfo->num_records++; + } + + /* Seek back to old position, for example when position_in_record > 0 */ + fileio_seek(bufinfo->fileio_info, oldpos, SEEK_SET); + } +} + +int fsdevice_write(struct vdrive_s *vdrive, uint8_t data, unsigned int secondary) { bufinfo_t *bufinfo; - bufinfo = fsdevice_dev[vdrive->unit - 8].bufinfo; + bufinfo = &fsdevice_dev[vdrive->unit - 8].bufinfo[secondary]; if (secondary == 15) { return fsdevice_flush_write_byte(vdrive, data); } - if (bufinfo[secondary].mode != Write - && bufinfo[secondary].mode != Append) { - return SERIAL_ERROR; + switch (bufinfo->mode) { + case Write: + case Append: + case Relative: + break; + default: + return SERIAL_ERROR; } - if (bufinfo[secondary].fileio_info != NULL) { + if (bufinfo->fileio_info != NULL) { unsigned int len; - len = fileio_write(bufinfo[secondary].fileio_info, &data, 1); + if (bufinfo->mode == Relative) { + if (bufinfo->position_in_record >= bufinfo->reclen) { + DBG(("fsdevice_write: OVERFLOW in recno:%d position_in_record:%d reclen:%d %02x '%c'", + bufinfo->current_record, bufinfo->position_in_record, + bufinfo->reclen, data, data)); + fsdevice_error(vdrive, CBMDOS_IPE_OVERFLOW); + return SERIAL_ERROR; + } + + /* + * Mixing reading and writing of a single record isn't + * allowed on a real drive, but try to support it anyway. + */ + if (bufinfo->isbuffered) { + fileio_seek(bufinfo->fileio_info, -1, SEEK_CUR); + bufinfo->position_in_record--; + bufinfo->isbuffered = 0; + } + + fsdevice_relfile_extend_if_needed(bufinfo); + + bufinfo->record_is_dirty++; + bufinfo->position_in_record++; + + if (bufinfo->position_in_record > bufinfo->current_record_length) { + bufinfo->current_record_length = bufinfo->position_in_record; + } + } + + DBG(("fsdevice_write: recno:%d position_in_record:%d %02x '%c'", + bufinfo->current_record, bufinfo->position_in_record-1, + data, data)); + len = fileio_write(bufinfo->fileio_info, &data, 1); if (len == 0) { return SERIAL_ERROR; diff --git a/src/Emulators/vice/fsdevice/fsdevice-write.h b/src/Emulators/vice/fsdevice/fsdevice-write.h index e367e8e8..1b522ca4 100644 --- a/src/Emulators/vice/fsdevice/fsdevice-write.h +++ b/src/Emulators/vice/fsdevice/fsdevice-write.h @@ -30,8 +30,10 @@ #include "vicetypes.h" struct vdrive_s; +struct bufinfo_s; -extern int fsdevice_write(struct vdrive_s *vdrive, BYTE data, - unsigned int secondary); +void fsdevice_listen(struct vdrive_s *vdrive, unsigned int secondary); +int fsdevice_write(struct vdrive_s *vdrive, uint8_t data, + unsigned int secondary); #endif diff --git a/src/Emulators/vice/fsdevice/fsdevice.c b/src/Emulators/vice/fsdevice/fsdevice.c index 62712c86..106cad87 100644 --- a/src/Emulators/vice/fsdevice/fsdevice.c +++ b/src/Emulators/vice/fsdevice/fsdevice.c @@ -33,12 +33,15 @@ * */ +/* #define DEBUG_FSDEVICE */ + #include "vice.h" #include #include #include +#include "archdep.h" #include "attach.h" #include "cbmdos.h" #include "fileio.h" @@ -50,7 +53,6 @@ #include "fsdevice-write.h" #include "fsdevice.h" #include "fsdevicetypes.h" -#include "ioutil.h" #include "lib.h" #include "log.h" #include "machine-bus.h" @@ -59,6 +61,11 @@ #include "vdrive-command.h" #include "vdrive.h" +#ifdef DEBUG_FSDEVICE +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif fsdevice_dev_t fsdevice_dev[FSDEVICE_DEVICE_MAX]; @@ -70,10 +77,10 @@ void fsdevice_set_directory(char *filename, unsigned int unit) case 9: case 10: case 11: - resources_set_string_sprintf("FSDevice%iDir", filename, unit); + resources_set_string_sprintf("FSDevice%uDir", filename, unit); break; default: - log_message(LOG_DEFAULT, "Invalid unit number %d.", unit); + log_message(LOG_DEFAULT, "Invalid unit number %u.", unit); } return; } @@ -88,7 +95,8 @@ char *fsdevice_get_path(unsigned int unit) return fsdevice_dir[unit - 8]; default: log_error(LOG_DEFAULT, - "fsdevice_get_path() called with invalid device %d.", unit); + "fsdevice_get_path() called with invalid device %u", + unit); break; } return NULL; @@ -97,7 +105,7 @@ char *fsdevice_get_path(unsigned int unit) void fsdevice_error(vdrive_t *vdrive, int code) { unsigned int dnr; - static int last_code[4]; + static int last_code[FSDEVICE_DEVICE_MAX]; const char *message; unsigned int trk = 0, sec = 0; @@ -109,6 +117,10 @@ void fsdevice_error(vdrive_t *vdrive, int code) return; } + if (dnr >= FSDEVICE_DEVICE_MAX) { + return; + } + last_code[dnr] = code; if (code != CBMDOS_IPE_MEMORY_READ) { @@ -123,12 +135,16 @@ void fsdevice_error(vdrive_t *vdrive, int code) sec = fsdevice_dev[dnr].sector; } - sprintf(fsdevice_dev[dnr].errorl, "%02d,%s,%02d,%02d\015", code, message, trk, sec); + sprintf(fsdevice_dev[dnr].errorl, + "%02d,%s,%02u,%02u\015", + code, message, trk, sec); fsdevice_dev[dnr].elen = (unsigned int)strlen(fsdevice_dev[dnr].errorl); if (code && code != CBMDOS_IPE_DOS_VERSION) { - log_message(LOG_DEFAULT, "Fsdevice: ERR = %02d, %s, %02d, %02d", code, message, trk, sec); + log_message(LOG_DEFAULT, + "Fsdevice: ERR = %02d, %s, %02u, %02u", + code, message, trk, sec); } } else { memcpy(fsdevice_dev[dnr].errorl, vdrive->mem_buf, vdrive->mem_length); @@ -138,7 +154,7 @@ void fsdevice_error(vdrive_t *vdrive, int code) fsdevice_dev[dnr].eptr = 0; } -int fsdevice_error_get_byte(vdrive_t *vdrive, BYTE *data) +int fsdevice_error_get_byte(vdrive_t *vdrive, uint8_t *data) { unsigned int dnr; int rc; @@ -150,7 +166,7 @@ int fsdevice_error_get_byte(vdrive_t *vdrive, BYTE *data) fsdevice_error(vdrive, CBMDOS_IPE_OK); } - *data = (BYTE)(fsdevice_dev[dnr].errorl)[(fsdevice_dev[dnr].eptr)++]; + *data = (uint8_t)(fsdevice_dev[dnr].errorl)[(fsdevice_dev[dnr].eptr)++]; if (fsdevice_dev[dnr].eptr >= fsdevice_dev[dnr].elen) { fsdevice_error(vdrive, CBMDOS_IPE_OK); rc = SERIAL_EOF; @@ -158,7 +174,7 @@ int fsdevice_error_get_byte(vdrive_t *vdrive, BYTE *data) #if 0 if (fsdevice_dev[dnr].eptr < fsdevice_dev[dnr].elen) { - *data = (BYTE)(fsdevice_dev[dnr].errorl)[(fsdevice_dev[dnr].eptr)++]; + *data = (uint8_t)(fsdevice_dev[dnr].errorl)[(fsdevice_dev[dnr].eptr)++]; rc = SERIAL_OK; } else { fsdevice_error(vdrive, CBMDOS_IPE_OK); @@ -170,15 +186,17 @@ int fsdevice_error_get_byte(vdrive_t *vdrive, BYTE *data) return rc; } -int fsdevice_attach(unsigned int device, const char *name) +int fsdevice_attach(unsigned int device, unsigned int drive, const char *name) { vdrive_t *vdrive; + DBG(("fsdevice_attach device: %u drive: %u name: %s", device, drive, name)); + vdrive = file_system_get_vdrive(device); if (machine_bus_device_attach(device, name, fsdevice_read, fsdevice_write, fsdevice_open, fsdevice_close, - fsdevice_flush, NULL)) { + fsdevice_flush, fsdevice_listen)) { return 1; } @@ -190,15 +208,12 @@ int fsdevice_attach(unsigned int device, const char *name) void fsdevice_init(void) { unsigned int i, j; - unsigned int maxpathlen; - - maxpathlen = ioutil_maxpathlen(); for (i = 0; i < FSDEVICE_DEVICE_MAX; i++) { bufinfo_t *bufinfo; - fsdevice_dev[i].errorl = lib_calloc(1, maxpathlen); - fsdevice_dev[i].cmdbuf = lib_calloc(1, maxpathlen); + fsdevice_dev[i].errorl = lib_calloc(1, ARCHDEP_PATH_MAX); + fsdevice_dev[i].cmdbuf = lib_calloc(1, ARCHDEP_PATH_MAX); fsdevice_dev[i].cptr = 0; @@ -206,9 +221,9 @@ void fsdevice_init(void) for (j = 0; j < FSDEVICE_BUFFER_MAX; j++) { bufinfo[j].tape = lib_calloc(1, sizeof(tape_image_t)); - bufinfo[j].dir = lib_calloc(1, maxpathlen); - bufinfo[j].name = lib_calloc(1, maxpathlen); - bufinfo[j].dirmask = lib_calloc(1, maxpathlen); + bufinfo[j].dir = lib_calloc(1, ARCHDEP_PATH_MAX); + bufinfo[j].name = lib_calloc(1, ARCHDEP_PATH_MAX); + bufinfo[j].dirmask = lib_calloc(1, ARCHDEP_PATH_MAX); } } } diff --git a/src/Emulators/vice/fsdevice/fsdevicetypes.h b/src/Emulators/vice/fsdevice/fsdevicetypes.h index a85ab3dc..04f7aa33 100644 --- a/src/Emulators/vice/fsdevice/fsdevicetypes.h +++ b/src/Emulators/vice/fsdevice/fsdevicetypes.h @@ -28,6 +28,7 @@ #define VICE_FSDEVICETYPES_H #include "vicetypes.h" +#include "archdep_dir.h" #define FSDEVICE_BUFFER_MAX 16 #define FSDEVICE_DEVICE_MAX 4 @@ -36,29 +37,34 @@ #define FSDEVICE_SECTOR_MAX 32 enum fsmode { - Write, Read, Append, Directory + Write, Read, Append, Directory, Relative }; struct fileio_info_s; -struct ioutil_dir_s; struct tape_image_s; struct bufinfo_s { struct fileio_info_s *fileio_info; - struct ioutil_dir_s *ioutil_dir; + archdep_dir_t *host_dir; struct tape_image_s *tape; enum fsmode mode; char *dir; - BYTE *name; + uint8_t *name; int buflen; - BYTE *bufp; + uint8_t *bufp; int eof; - int reclen; int type; - BYTE buffered; /* Buffered Byte: Added to buffer reads to remove buffering from iec code */ + uint8_t buffered; /* Buffered Byte: Added to buffer reads to remove buffering from iec code */ int isbuffered; /* TRUE is a byte exists in the buffer above */ int iseof; /* TRUE if an EOF is detected on a buffered read */ char *dirmask; + /* REL file support */ + int reclen; + int num_records; + int current_record; /* 0-based */ + int position_in_record; /* 0-based */ + int current_record_length; + int record_is_dirty; }; typedef struct bufinfo_s bufinfo_t; @@ -67,10 +73,10 @@ struct fsdevice_dev_s { unsigned int elen; char *errorl; unsigned int cptr; - BYTE *cmdbuf; + uint8_t *cmdbuf; bufinfo_t bufinfo[FSDEVICE_BUFFER_MAX]; int track, sector; /* fake track/sector pointer */ - BYTE bam[(FSDEVICE_TRACK_MAX * FSDEVICE_SECTOR_MAX) >> 3]; /* fake bam */ + uint8_t bam[(FSDEVICE_TRACK_MAX * FSDEVICE_SECTOR_MAX) >> 3]; /* fake bam */ }; typedef struct fsdevice_dev_s fsdevice_dev_t; @@ -78,9 +84,9 @@ extern fsdevice_dev_t fsdevice_dev[FSDEVICE_DEVICE_MAX]; struct vdrive_s; -extern void fsdevice_error(struct vdrive_s *vdrive, int code); -extern char *fsdevice_get_path(unsigned int unit); -extern int fsdevice_error_get_byte(struct vdrive_s *vdrive, BYTE *data); -extern int fsdevice_flush_write_byte(struct vdrive_s *vdrive, BYTE data); +void fsdevice_error(struct vdrive_s *vdrive, int code); +char *fsdevice_get_path(unsigned int unit); +int fsdevice_error_get_byte(struct vdrive_s *vdrive, uint8_t *data); +int fsdevice_flush_write_byte(struct vdrive_s *vdrive, uint8_t data); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/artstudiodrv.c b/src/Emulators/vice/gfxoutputdrv/artstudiodrv.c new file mode 100644 index 00000000..acc8b2a4 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/artstudiodrv.c @@ -0,0 +1,678 @@ +/* + * artstudiodrv.c - Create a c64 artstudio type file. + * + * Written by + * Marco van den Heuvel + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#include "archdep.h" +#include "cmdline.h" +#include "lib.h" +#include "log.h" +#include "machine.h" +#include "mem.h" +#include "gfxoutput.h" +#include "nativedrv.h" +#include "palette.h" +#include "resources.h" +#include "screenshot.h" +#include "vicetypes.h" +#include "uiapi.h" +#include "util.h" +#include "vsync.h" + +/* + TODO: + + when all is done, remove #if 0'ed code +*/ + +#define ARTSTUDIO_SCREEN_PIXEL_WIDTH 320 +#define ARTSTUDIO_SCREEN_PIXEL_HEIGHT 200 + +#define ARTSTUDIO_SCREEN_BYTE_WIDTH ARTSTUDIO_SCREEN_PIXEL_WIDTH / 8 +#define ARTSTUDIO_SCREEN_BYTE_HEIGHT ARTSTUDIO_SCREEN_PIXEL_HEIGHT / 8 + +/* define offsets in the artstudio file */ +#define VIDEORAM_OFFSET 0x1f42 +#define BITMAP_OFFSET 2 +#define ARTSTUDIO_SIZE 9002 + 7 + +static gfxoutputdrv_t artstudio_drv; + +/* ------------------------------------------------------------------------ */ + +static int oversize_handling; +static int undersize_handling; +static int multicolor_handling; +static int ted_lum_handling; +#if 0 +static int crtc_text_color; +static uint8_t crtc_fgcolor; +#endif + +static int set_oversize_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_OVERSIZE_SCALE: + case NATIVE_SS_OVERSIZE_CROP_LEFT_TOP: + case NATIVE_SS_OVERSIZE_CROP_CENTER_TOP: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_TOP: + case NATIVE_SS_OVERSIZE_CROP_LEFT_CENTER: + case NATIVE_SS_OVERSIZE_CROP_CENTER: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_CENTER: + case NATIVE_SS_OVERSIZE_CROP_LEFT_BOTTOM: + case NATIVE_SS_OVERSIZE_CROP_CENTER_BOTTOM: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_BOTTOM: + break; + default: + return -1; + } + + oversize_handling = val; + + return 0; +} + +static int set_undersize_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_UNDERSIZE_SCALE: + case NATIVE_SS_UNDERSIZE_BORDERIZE: + break; + default: + return -1; + } + + undersize_handling = val; + + return 0; +} + +static int set_multicolor_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_MC2HR_BLACK_WHITE: + case NATIVE_SS_MC2HR_2_COLORS: + case NATIVE_SS_MC2HR_4_COLORS: + case NATIVE_SS_MC2HR_GRAY: + case NATIVE_SS_MC2HR_DITHER: + break; + default: + return -1; + } + + multicolor_handling = val; + + return 0; +} + +static int set_ted_lum_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_TED_LUM_IGNORE: + case NATIVE_SS_TED_LUM_DITHER: + break; + default: + return -1; + } + + ted_lum_handling = val; + + return 0; +} + +#if 0 +static int set_crtc_text_color(int val, void *param) +{ + switch (val) { + case NATIVE_SS_CRTC_WHITE: + crtc_fgcolor = 1; + break; + case NATIVE_SS_CRTC_AMBER: + crtc_fgcolor = 8; + break; + case NATIVE_SS_CRTC_GREEN: + crtc_fgcolor = 5; + break; + default: + return -1; + } + + crtc_text_color = val; + + return 0; +} +#endif + +static const resource_int_t resources_int[] = { + { "OCPOversizeHandling", NATIVE_SS_OVERSIZE_SCALE, RES_EVENT_NO, NULL, + &oversize_handling, set_oversize_handling, NULL }, + { "OCPUndersizeHandling", NATIVE_SS_UNDERSIZE_BORDERIZE, RES_EVENT_NO, NULL, + &undersize_handling, set_undersize_handling, NULL }, + { "OCPMultiColorHandling", NATIVE_SS_MC2HR_DITHER, RES_EVENT_NO, NULL, + &multicolor_handling, set_multicolor_handling, NULL }, + RESOURCE_INT_LIST_END +}; + +static const resource_int_t resources_int_plus4[] = { + { "OCPTEDLumHandling", NATIVE_SS_TED_LUM_DITHER, RES_EVENT_NO, NULL, + &ted_lum_handling, set_ted_lum_handling, NULL }, + RESOURCE_INT_LIST_END +}; + +#if 0 +static const resource_int_t resources_int_crtc[] = { + { "OCPCRTCTextColor", NATIVE_SS_CRTC_WHITE, RES_EVENT_NO, NULL, + &crtc_text_color, set_crtc_text_color, NULL }, + RESOURCE_INT_LIST_END +}; +#endif + +static int artstudiodrv_resources_init(void) +{ + if (machine_class == VICE_MACHINE_PLUS4) { + if (resources_register_int(resources_int_plus4) < 0) { + return -1; + } + } +#if 0 + if (machine_class == VICE_MACHINE_PET || machine_class == VICE_MACHINE_CBM6x0) { + if (resources_register_int(resources_int_crtc) < 0) { + return -1; + } + } +#endif + return resources_register_int(resources_int); +} + +static const cmdline_option_t cmdline_options[] = +{ + { "-ocpoversize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "OCPOversizeHandling", NULL, + "", "Select the way the oversized input should be handled," + " (0: scale down, 1: crop left top, 2: crop center top, 3: crop right top," + " 4: crop left center, 5: crop center, 6: crop right center, 7: crop left bottom," + " 8: crop center bottom, 9: crop right bottom)" }, + { "-ocpundersize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "OCPUndersizeHandling", NULL, + "", "Select the way the undersized input should be handled," + " (0: scale up, 1: borderize)" }, + { "-ocpmc", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "OCPMultiColorHandling", NULL, + "", "Select the way the multicolor to hires should be handled," + " (0: b&w, 1: 2 colors, 2: 4 colors, 3: gray scale, 4: best cell colors)" }, + CMDLINE_LIST_END +}; + +static const cmdline_option_t cmdline_options_plus4[] = +{ + { "-ocptedlum", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "OCPTEDLumHandling", NULL, + "", "Select the way the TED luminosity should be handled, (0: ignore, 1: dither)" }, + CMDLINE_LIST_END +}; + +#if 0 +static const cmdline_option_t cmdline_options_crtc[] = +{ + { "-ocpcrtctextcolor", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "OCPCRTCTextColor", NULL, + "", "Select the CRTC text color (0: white, 1: amber, 2: green)" }, + CMDLINE_LIST_END +}; +#endif + +static int artstudiodrv_cmdline_options_init(void) +{ + if (machine_class == VICE_MACHINE_PLUS4) { + if (cmdline_register_options(cmdline_options_plus4) < 0) { + return -1; + } + } +#if 0 + if (machine_class == VICE_MACHINE_PET || machine_class == VICE_MACHINE_CBM6x0) { + if (cmdline_register_options(cmdline_options_crtc) < 0) { + return -1; + } + } +#endif + return cmdline_register_options(cmdline_options); +} + +/* ------------------------------------------------------------------------ */ + +static void artstudio_check_and_correct_cell(native_data_t *source) +{ + native_data_t *dest = lib_malloc(sizeof(native_data_t)); + int i, j, k, l; + native_color_sort_t *colors = NULL; + + dest->xsize = 8; + dest->ysize = 8; + dest->colormap = lib_malloc(8 * 8); + + for (i = 0; i < ARTSTUDIO_SCREEN_BYTE_HEIGHT; i++) { + for (j = 0; j < ARTSTUDIO_SCREEN_BYTE_WIDTH; j++) { + /* get block */ + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + dest->colormap[(k * 8) + l] = + source->colormap[(i * 8 * ARTSTUDIO_SCREEN_PIXEL_WIDTH) + (j * 8) + + (k * ARTSTUDIO_SCREEN_PIXEL_WIDTH) + l]; + } + } + /* if there are more than 2 colors in the block, re-render it using + the two most used colors in the block */ + colors = native_sort_colors_colormap(dest, 16); + if (colors[2].amount != 0) { + colors[2].color = 255; + vicii_color_to_nearest_vicii_color_colormap(dest, colors); + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + source->colormap[(i * 8 * ARTSTUDIO_SCREEN_PIXEL_WIDTH) + (j * 8) + + (k * ARTSTUDIO_SCREEN_PIXEL_WIDTH) + l] = + dest->colormap[(k * 8) + l]; + } + } + } + lib_free(colors); + } + } + lib_free(dest->colormap); + lib_free(dest); +} + +static int artstudio_render_and_save(native_data_t *source) +{ + FILE *fd; + char *filename_ext = NULL; + uint8_t *filebuffer = NULL; + uint8_t *result = NULL; + int i, j, k, l; + int m = 0; + int n = 0; + int retval = 0; + uint8_t fgcolor = 0; + uint8_t bgcolor; + uint8_t colorbyte; + + /* allocate file buffer */ + filebuffer = lib_malloc(ARTSTUDIO_SIZE); + + /* clear filebuffer */ + memset(filebuffer, 0, ARTSTUDIO_SIZE); + + /* set load addy */ + filebuffer[0] = 0x00; + filebuffer[1] = 0x20; + + for (i = 0; i < ARTSTUDIO_SCREEN_BYTE_HEIGHT; i++) { + for (j = 0; j < ARTSTUDIO_SCREEN_BYTE_WIDTH; j++) { + fgcolor = bgcolor = 255; + for (k = 0; k < 8; k++) { + filebuffer[BITMAP_OFFSET + m] = 0; + for (l = 0; l < 8; l++) { + colorbyte = source->colormap[(i * ARTSTUDIO_SCREEN_PIXEL_WIDTH * 8) + + (j * 8) + (k * ARTSTUDIO_SCREEN_PIXEL_WIDTH) + l]; + if ((colorbyte != fgcolor) && (fgcolor == 255)) { + fgcolor = colorbyte; + } else if ((colorbyte != bgcolor) && (colorbyte != fgcolor) && (bgcolor == 255)) { + bgcolor = colorbyte; + } + if (colorbyte == fgcolor) { + filebuffer[BITMAP_OFFSET + m] |= (1 << (7 - l)); + } + } + m++; + } + filebuffer[VIDEORAM_OFFSET + n++] = ((fgcolor & 0xf) << 4) | (bgcolor & 0xf); + } + } + + filename_ext = util_add_extension_const(source->filename, artstudio_drv.default_extension); + + fd = fopen(filename_ext, MODE_WRITE); + if (fd == NULL) { + retval = -1; + } + + if (retval != -1) { + if (fwrite(filebuffer, ARTSTUDIO_SIZE, 1, fd) < 1) { + retval = -1; + } + } + + if (fd != NULL) { + fclose(fd); + } + + lib_free(source->colormap); + lib_free(source); + lib_free(filename_ext); + lib_free(filebuffer); + lib_free(result); + + return retval; +} + +/* ------------------------------------------------------------------------ */ + +static int artstudio_multicolor_render(native_data_t *data) +{ + native_color_sort_t *color_order = NULL; + + switch (multicolor_handling) { + case NATIVE_SS_MC2HR_BLACK_WHITE: + vicii_color_to_vicii_bw_colormap(data); + break; + case NATIVE_SS_MC2HR_GRAY: + vicii_color_to_vicii_gray_colormap(data); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_2_COLORS: + color_order = native_sort_colors_colormap(data, 16); + color_order[2].color = 255; + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_4_COLORS: + color_order = native_sort_colors_colormap(data, 16); + color_order[4].color = 255; + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_DITHER: + color_order = native_sort_colors_colormap(data, 16); + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + default: + return -1; + break; + } + return 0; +} + +static int artstudio_vicii_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; + uint8_t mc; + uint8_t eb; + uint8_t bm; + uint8_t blank; + + mc = (regs[0x16] & 0x10) >> 4; + eb = (regs[0x11] & 0x40) >> 6; + bm = (regs[0x11] & 0x20) >> 5; + + blank = (regs[0x11] & 0x10) >> 4; + + if (!blank) { + ui_error("Screen is blanked, no picture to save"); + return -1; + } + + switch (mc << 2 | eb << 1 | bm) { + case 0: /* normal text mode */ + data = native_vicii_text_mode_render(screenshot, filename); + break; + case 1: /* hires bitmap mode */ + data = native_vicii_hires_bitmap_mode_render(screenshot, filename); + break; + case 2: /* extended background mode */ + data = native_vicii_extended_background_mode_render(screenshot, filename); + break; + case 4: /* multicolor text mode */ + data = native_vicii_multicolor_text_mode_render(screenshot, filename); + break; + case 5: /* multicolor bitmap mode */ + data = native_vicii_multicolor_bitmap_mode_render(screenshot, filename); + break; + default: /* illegal modes (3, 6 and 7) */ + ui_error("Illegal mode, no saving will be done"); + return -1; + break; + } +#endif + data = native_vicii_render(screenshot, filename); + if (data == NULL) { + return -1; + } + if (data->mc_data_present) { + if (artstudio_multicolor_render(data) != 0) { + return -1; + } + } + return artstudio_render_and_save(data); +} + +/* ------------------------------------------------------------------------ */ + +static int artstudio_ted_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; + uint8_t mc; + uint8_t eb; + uint8_t bm; + + mc = (regs[0x07] & 0x10) >> 4; + eb = (regs[0x06] & 0x40) >> 6; + bm = (regs[0x06] & 0x20) >> 5; + + switch (mc << 2 | eb << 1 | bm) { + case 0: /* normal text mode */ + data = native_ted_text_mode_render(screenshot, filename); + break; + case 1: /* hires bitmap mode */ + data = native_ted_hires_bitmap_mode_render(screenshot, filename); + break; + case 2: /* extended background mode */ + data = native_ted_extended_background_mode_render(screenshot, filename); + break; + case 4: /* multicolor text mode */ + ui_error("This screen saver is a WIP, it doesn't support multicolor text mode (yet)"); + return -1; + break; + case 5: /* multicolor bitmap mode */ + data = native_ted_multicolor_bitmap_mode_render(screenshot, filename); + break; + default: /* illegal modes (3, 6 and 7) */ + ui_error("Illegal mode, no saving will be done"); + return -1; + break; + } +#endif + data = native_ted_render(screenshot, filename); + if (data == NULL) { + return -1; + } + ted_color_to_vicii_color_colormap(data, ted_lum_handling); + if (data->mc_data_present) { + if (artstudio_multicolor_render(data) != 0) { + return -1; + } + } + return artstudio_render_and_save(data); +} + +/* ------------------------------------------------------------------------ */ + +static int artstudio_vic_save(screenshot_t *screenshot, const char *filename) +{ + uint8_t *regs = screenshot->video_regs; + native_data_t *data = native_vic_render(screenshot, filename); + native_color_sort_t *color_order = NULL; + uint8_t bordercolor = regs[0xf] & 7; + + if (data == NULL) { + return -1; + } + + vic_color_to_vicii_color_colormap(data); + + if (data->xsize != ARTSTUDIO_SCREEN_PIXEL_WIDTH || data->ysize != ARTSTUDIO_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, ARTSTUDIO_SCREEN_PIXEL_WIDTH, ARTSTUDIO_SCREEN_PIXEL_HEIGHT, + bordercolor, oversize_handling, undersize_handling); + } + + if (data->mc_data_present) { + switch (multicolor_handling) { + case NATIVE_SS_MC2HR_BLACK_WHITE: + vicii_color_to_vicii_bw_colormap(data); + break; + case NATIVE_SS_MC2HR_GRAY: + vicii_color_to_vicii_gray_colormap(data); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_2_COLORS: + color_order = native_sort_colors_colormap(data, 16); + color_order[2].color = 255; + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_4_COLORS: + color_order = native_sort_colors_colormap(data, 16); + color_order[4].color = 255; + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + case NATIVE_SS_MC2HR_DITHER: + color_order = native_sort_colors_colormap(data, 16); + vicii_color_to_nearest_vicii_color_colormap(data, color_order); + lib_free(color_order); + artstudio_check_and_correct_cell(data); + break; + default: + return -1; + break; + } + } + return artstudio_render_and_save(data); +} + +/* ------------------------------------------------------------------------ */ + +static int artstudio_crtc_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = native_crtc_render(screenshot, filename); + + if (data == NULL) { + return -1; + } + + if (data->xsize != ARTSTUDIO_SCREEN_PIXEL_WIDTH || data->ysize != ARTSTUDIO_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, ARTSTUDIO_SCREEN_PIXEL_WIDTH, ARTSTUDIO_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); + } + return artstudio_render_and_save(data); +} + +/* ------------------------------------------------------------------------ */ + +static int artstudio_vdc_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; + + if (regs[25] & 0x80) { + ui_error("VDC bitmap mode screenshot saving not implemented yet"); + return -1; + } +#endif + data = native_vdc_render(screenshot, filename); + if (data == NULL) { + return -1; + } + vdc_color_to_vicii_color_colormap(data); + if (data->xsize != ARTSTUDIO_SCREEN_PIXEL_WIDTH || data->ysize != ARTSTUDIO_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, ARTSTUDIO_SCREEN_PIXEL_WIDTH, ARTSTUDIO_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); + } + return artstudio_render_and_save(data); +} + +/* ------------------------------------------------------------------------ */ + +static int artstudiodrv_save(screenshot_t *screenshot, const char *filename) +{ + if (!(strcmp(screenshot->chipid, "VICII"))) { + return artstudio_vicii_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "VDC"))) { + return artstudio_vdc_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "CRTC"))) { + return artstudio_crtc_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "TED"))) { + return artstudio_ted_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "VIC"))) { + return artstudio_vic_save(screenshot, filename); + } + ui_error("Unknown graphics chip"); + return -1; +} + +static gfxoutputdrv_t artstudio_drv = +{ + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, + "ARTSTUDIO", + "OCP Artstudio screenshot", + "ocp", + NULL, /* formatlist */ + NULL, + NULL, + NULL, + NULL, + artstudiodrv_save, + NULL, + NULL, + artstudiodrv_resources_init, + artstudiodrv_cmdline_options_init +#ifdef FEATURE_CPUMEMHISTORY + , NULL +#endif +}; + +void gfxoutput_init_artstudio(int help) +{ + gfxoutput_register(&artstudio_drv); +} diff --git a/src/Emulators/vice/gfxoutputdrv/artstudiodrv.h b/src/Emulators/vice/gfxoutputdrv/artstudiodrv.h new file mode 100644 index 00000000..e69de29b diff --git a/src/Emulators/vice/gfxoutputdrv/bmpdrv.c b/src/Emulators/vice/gfxoutputdrv/bmpdrv.c index 7f80edcd..da0c1739 100644 --- a/src/Emulators/vice/gfxoutputdrv/bmpdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/bmpdrv.c @@ -47,13 +47,13 @@ typedef struct gfxoutputdrv_data_s { FILE *fd; char *ext_filename; - BYTE *data; - BYTE *bmp_data; + uint8_t *data; + uint8_t *bmp_data; int line; unsigned int bpp; } gfxoutputdrv_data_t; -STATIC_PROTOTYPE gfxoutputdrv_t bmp_drv; +static gfxoutputdrv_t bmp_drv; static int bmpdrv_bytes_per_row(screenshot_t *screenshot) { @@ -61,7 +61,7 @@ static int bmpdrv_bytes_per_row(screenshot_t *screenshot) return (bits_per_row / 32 + (bits_per_row % 32 != 0)) * 4; } -static DWORD bmpdrv_bmp_size(screenshot_t *screenshot) +static uint32_t bmpdrv_bmp_size(screenshot_t *screenshot) { return BMP_HDR_OFFSET + bmpdrv_bytes_per_row(screenshot) * screenshot->height; } @@ -69,7 +69,7 @@ static DWORD bmpdrv_bmp_size(screenshot_t *screenshot) static int bmpdrv_write_file_header(screenshot_t *screenshot) { gfxoutputdrv_data_t *sdata; - BYTE header[14]; + uint8_t header[14]; sdata = screenshot->gfxoutputdrv_data; @@ -96,8 +96,8 @@ static int bmpdrv_write_file_header(screenshot_t *screenshot) static int bmpdrv_write_bitmap_info(screenshot_t *screenshot) { - BYTE binfo[40]; - BYTE *bcolor; + uint8_t binfo[40]; + uint8_t *bcolor; unsigned int i; memset(binfo, 0, sizeof(binfo)); @@ -232,7 +232,7 @@ static int bmpdrv_write(screenshot_t *screenshot) for (i = 0; i < (int)screenshot->width / 8; i++) { - BYTE b = 0; + uint8_t b = 0; for (j = 0; j < 8; j++) { b |= sdata->data[i * 8 + j] ? (1 << (7 - j)) : 0; } @@ -308,7 +308,7 @@ static int bmpdrv_save(screenshot_t *screenshot, const char *filename) #ifdef FEATURE_CPUMEMHISTORY static FILE *bmpdrv_memmap_fd; static char *bmpdrv_memmap_ext_filename; -static BYTE *bmpdrv_memmap_bmp_data; +static uint8_t *bmpdrv_memmap_bmp_data; static int bmpdrv_memmap_bytes_per_row(int x_size) { @@ -331,15 +331,15 @@ static int bmpdrv_close_memmap(int x_size, int y_size) return res; } -static DWORD bmpdrv_memmap_bmp_size(int x_size, int y_size) +static uint32_t bmpdrv_memmap_bmp_size(int x_size, int y_size) { return 14 + 40 + 4 * 256 + bmpdrv_memmap_bytes_per_row(x_size) * y_size; } -static int bmpdrv_memmap_write_bitmap_info(int x_size, int y_size, BYTE *palette) +static int bmpdrv_memmap_write_bitmap_info(int x_size, int y_size, uint8_t *palette) { - BYTE binfo[40]; - BYTE *bcolor; + uint8_t binfo[40]; + uint8_t *bcolor; unsigned int i; memset(binfo, 0, sizeof(binfo)); @@ -388,7 +388,7 @@ static int bmpdrv_memmap_write_bitmap_info(int x_size, int y_size, BYTE *palette static int bmpdrv_memmap_write_file_header(int x_size, int y_size) { - BYTE header[14]; + uint8_t header[14]; memset(header, 0, sizeof(header)); @@ -406,7 +406,7 @@ static int bmpdrv_memmap_write_file_header(int x_size, int y_size) return 0; } -static int bmpdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE *palette) +static int bmpdrv_open_memmap(const char *filename, int x_size, int y_size, uint8_t *palette) { bmpdrv_memmap_ext_filename = util_add_extension_const(filename, bmp_drv.default_extension); @@ -434,13 +434,13 @@ static int bmpdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE return 0; } -static void bmpdrv_write_memmap(int line, int x_size, int y_size, BYTE *gfx) +static void bmpdrv_write_memmap(int line, int x_size, int y_size, uint8_t *gfx) { int bmp_width = bmpdrv_memmap_bytes_per_row(x_size); memcpy(bmpdrv_memmap_bmp_data + (y_size - 1 - line) * bmp_width, gfx + (line * x_size), x_size); } -static int bmpdrv_memmap_save(const char *filename, int x_size, int y_size, BYTE *gfx, BYTE *palette) +static int bmpdrv_memmap_save(const char *filename, int x_size, int y_size, uint8_t *gfx, uint8_t *palette) { int line; @@ -462,6 +462,7 @@ static int bmpdrv_memmap_save(const char *filename, int x_size, int y_size, BYTE static gfxoutputdrv_t bmp_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, "BMP", "BMP screenshot", "bmp", diff --git a/src/Emulators/vice/gfxoutputdrv/bmpdrv.h b/src/Emulators/vice/gfxoutputdrv/bmpdrv.h index 9c8e1da6..9f7b4275 100644 --- a/src/Emulators/vice/gfxoutputdrv/bmpdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/bmpdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_BMPDRV_H #define VICE_BMPDRV_H -extern void gfxoutput_init_bmp(int help); +void gfxoutput_init_bmp(int help); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/doodledrv.c b/src/Emulators/vice/gfxoutputdrv/doodledrv.c index 5a44a4e5..f3834260 100644 --- a/src/Emulators/vice/gfxoutputdrv/doodledrv.c +++ b/src/Emulators/vice/gfxoutputdrv/doodledrv.c @@ -41,7 +41,6 @@ #include "palette.h" #include "resources.h" #include "screenshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" @@ -215,38 +214,23 @@ static int doodledrv_resources_init(void) static const cmdline_option_t cmdline_options[] = { { "-doodleoversize", SET_RESOURCE, 1, - NULL, NULL, "DoodleOversizeHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_OVERSIZED_HANDLING, - NULL, NULL }, + NULL, NULL, "DoodleOversizeHandling", NULL, N_(""), N_("Select the way the oversized input should be handled, (0: scale down, 1: crop left top, 2: crop center top, 3: crop right top, 4: crop left center, 5: crop center, 6: crop right center, 7: crop left bottom, 8: crop center bottom, 9: crop right bottom)")}, { "-doodleundersize", SET_RESOURCE, 1, - NULL, NULL, "DoodleUndersizeHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_UNDERSIZED_HANDLING, - NULL, NULL }, + NULL, NULL, "DoodleUndersizeHandling", NULL, N_(""), N_("Select the way the undersized input should be handled, (0: scale up, 1: borderize)")}, { "-doodlemc", SET_RESOURCE, 1, - NULL, NULL, "DoodleMultiColorHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_MULTICOLOR_HANDLING, - NULL, NULL }, + NULL, NULL, "DoodleMultiColorHandling", NULL, N_(""), N_("Select the way the multicolor to hires should be handled, (0: b&w, 1: 2 colors, 2: 4 colors, 3: gray scale, 4: best cell colors)")}, CMDLINE_LIST_END }; static const cmdline_option_t cmdline_options_plus4[] = { { "-doodletedlum", SET_RESOURCE, 1, - NULL, NULL, "DoodleTEDLumHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_TED_LUM_HANDLING, - NULL, NULL }, + NULL, NULL, "DoodleTEDLumHandling", NULL, N_(""), N_("Select the way the TED luminosity should be handled, (0: ignore, 1: dither)")}, CMDLINE_LIST_END }; static const cmdline_option_t cmdline_options_crtc[] = { { "-doodlecrtctextcolor", SET_RESOURCE, 1, - NULL, NULL, "DoodleCRTCTextColor", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_COLOR, IDCLS_CRTC_TEXT_COLOR, - NULL, NULL }, + NULL, NULL, "DoodleCRTCTextColor", NULL, N_(""), N_("Select the CRTC text color (0: white, 1: amber, 2: green)")}, CMDLINE_LIST_END }; @@ -625,7 +609,7 @@ static int doodle_vic_save(screenshot_t *screenshot, const char *filename, int c static int doodle_crtc_save(screenshot_t *screenshot, const char *filename, int compress) { - native_data_t *data = native_crtc_render(screenshot, filename, crtc_fgcolor); + native_data_t *data = native_crtc_render(screenshot, filename); /* VICE 3.10: dropped fgcolor arg */ if (data == NULL) { return -1; @@ -703,17 +687,18 @@ static int doodledrv_compressed_save(screenshot_t *screenshot, const char *filen static gfxoutputdrv_t doodle_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, /* VICE 3.10: new leading type field */ "DOODLE", "C64 doodle screenshot", "dd", NULL, /* formatlist */ - NULL, - NULL, - NULL, - NULL, - doodledrv_save, - NULL, - NULL, + NULL, /* open */ + NULL, /* close */ + NULL, /* write */ + NULL, /* save */ + doodledrv_save, /* save_native */ + NULL, /* record */ + NULL, /* shutdown */ doodledrv_resources_init, doodledrv_cmdline_options_init #ifdef FEATURE_CPUMEMHISTORY @@ -723,19 +708,20 @@ static gfxoutputdrv_t doodle_drv = static gfxoutputdrv_t doodle_compressed_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, /* VICE 3.10: new leading type field */ "DOODLE_COMPRESSED", "C64 compressed doodle screenshot", "jj", NULL, /* formatlist */ - NULL, - NULL, - NULL, - NULL, - doodledrv_compressed_save, - NULL, - NULL, - NULL, - NULL + NULL, /* open */ + NULL, /* close */ + NULL, /* write */ + NULL, /* save */ + doodledrv_compressed_save, /* save_native */ + NULL, /* record */ + NULL, /* shutdown */ + NULL, /* resources_init */ + NULL /* cmdline_options_init */ #ifdef FEATURE_CPUMEMHISTORY , NULL #endif diff --git a/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.c b/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.c new file mode 100644 index 00000000..c77b0f90 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.c @@ -0,0 +1,1498 @@ +/** \file ffmpegexedrv.c + * \brie Movie driver using FFMPEG executable + * + * \author Andreas Matthies + * \author groepaz@gmx.net + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* + This is a video output driver implemented to replace the original FFMPEG + driver. Instead of linking in the libraries, this one calls the ffmpeg + executable and pipes the data to it. + + bugs/open ends: + - audio-only saving does not work correctly, apparently due to how the codecs + are being listed (and somehow the results come out wrong) + - there should probably be an endianess conversion for the audio stream + - there should probably be a check that makes sure "ffmpeg" exists and + can be executed + - the available codecs/containers should get queried from the ffmpeg binary + + * https://ffmpeg.org/ffmpeg.html + * https://ffmpeg.org/~michael/nut.txt + * https://github.com/lu-zero/nut/blob/master/src/ + * https://gist.github.com/victusfate/b1fbc822957020bfc063 + + */ + +/* #define DEBUG_FFMPEG */ +/* #define DEBUG_FFMPEG_FRAMES */ + +#include "vice.h" + +#include + +#include +#include +#include +#include +#include +#if !defined(WINDOWS_COMPILE) +#include /* RD: read/write/close/pipe for the ffmpeg pipe (not pulled in via UNIX_COMPILE) */ +#endif + +#include "archdep.h" +#include "archdep_sleep.h" +#include "cmdline.h" +#include "coproc.h" +#include "ffmpegexedrv.h" +#include "gfxoutput.h" +#include "lib.h" +#include "log.h" +#include "machine.h" +#include "palette.h" +#include "resources.h" +#include "screenshot.h" +#include "soundmovie.h" +#include "uiapi.h" +#include "util.h" +#include "vicesocket.h" + +/* #define VICE_IS_SERVER */ + +#ifdef DEBUG_FFMPEG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + +#ifdef DEBUG_FFMPEG_FRAMES +#define DBGFRAMES(x) log_printf x +#else +#define DBGFRAMES(x) +#endif + +#define AV_CODEC_ID_NONE 0 +#define AV_CODEC_ID_MP2 1 +#define AV_CODEC_ID_MP3 2 +#define AV_CODEC_ID_FLAC 3 +#define AV_CODEC_ID_PCM_S16LE 4 +#define AV_CODEC_ID_AAC 5 +#define AV_CODEC_ID_AC3 6 +#define AV_CODEC_ID_MPEG4 7 +#define AV_CODEC_ID_MPEG1VIDEO 8 +#define AV_CODEC_ID_FFV1 9 +#define AV_CODEC_ID_H264 10 +#define AV_CODEC_ID_THEORA 11 +#define AV_CODEC_ID_H265 12 + +/* FIXME: check/fix make sure this returns valid ffmpeg vcodec/acodec strings */ +static char *av_codec_get_option(int id) +{ + switch(id) { + case AV_CODEC_ID_NONE: return "none"; + case AV_CODEC_ID_MP2: return "mp2"; + case AV_CODEC_ID_MP3: return "mp3"; + case AV_CODEC_ID_FLAC: return "flac"; + case AV_CODEC_ID_PCM_S16LE: return "s16le"; + case AV_CODEC_ID_AAC: return "aac"; + case AV_CODEC_ID_AC3: return "ac3"; + case AV_CODEC_ID_MPEG4: return "mpeg4"; + case AV_CODEC_ID_MPEG1VIDEO: return "mpeg1video"; + case AV_CODEC_ID_FFV1: return "ffv1"; + case AV_CODEC_ID_H264: return "h264"; + case AV_CODEC_ID_THEORA: return "theora"; + case AV_CODEC_ID_H265: return "h265"; + default: return "unknown"; + } +} + +/******************************************************************************/ + +/* FIXME: some SDL UIs use ffmpegdrv_formatlist directly */ +#define ffmpegexedrv_formatlist ffmpegdrv_formatlist + +static gfxoutputdrv_codec_t mp4_audio_codeclist[] = { + { AV_CODEC_ID_AAC, "AAC" }, + { AV_CODEC_ID_MP3, "MP3" }, + { AV_CODEC_ID_AC3, "AC3" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t mp4_video_codeclist[] = { + { AV_CODEC_ID_H264, "H264" }, + { AV_CODEC_ID_H265, "H265" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t ogg_audio_codeclist[] = { + { AV_CODEC_ID_FLAC, "FLAC" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t ogg_video_codeclist[] = { + { AV_CODEC_ID_THEORA, "Theora" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t avi_audio_codeclist[] = { + { AV_CODEC_ID_MP2, "MP2" }, + { AV_CODEC_ID_MP3, "MP3" }, + { AV_CODEC_ID_FLAC, "FLAC" }, + { AV_CODEC_ID_PCM_S16LE, "PCM uncompressed" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t avi_video_codeclist[] = { + { AV_CODEC_ID_MPEG4, "MPEG4 (DivX)" }, + { AV_CODEC_ID_MPEG1VIDEO, "MPEG1" }, + { AV_CODEC_ID_FFV1, "FFV1 (lossless)" }, + { AV_CODEC_ID_H264, "H264" }, + { AV_CODEC_ID_THEORA, "Theora" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t mp3_audio_codeclist[] = { + { AV_CODEC_ID_MP3, "mp3" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t mp2_audio_codeclist[] = { + { AV_CODEC_ID_MP2, "mp2" }, + { 0, NULL } +}; + +#if 0 +static gfxoutputdrv_codec_t none_codeclist[] = { + { AV_CODEC_ID_NONE, "" }, + { 0, NULL } +}; +#endif + +#define VIDEO_OPTIONS \ + (GFXOUTPUTDRV_HAS_AUDIO_CODECS | \ + GFXOUTPUTDRV_HAS_VIDEO_CODECS | \ + GFXOUTPUTDRV_HAS_AUDIO_BITRATE | \ + GFXOUTPUTDRV_HAS_VIDEO_BITRATE | \ + GFXOUTPUTDRV_HAS_HALF_VIDEO_FRAMERATE) + +#define AUDIO_OPTIONS \ + (GFXOUTPUTDRV_HAS_AUDIO_CODECS | \ + GFXOUTPUTDRV_HAS_AUDIO_BITRATE) + +/* formatlist is filled from with available formats and codecs at init time */ +gfxoutputdrv_format_t *ffmpegexedrv_formatlist = NULL; +static gfxoutputdrv_format_t output_formats_to_test[] = +{ + { "mp4", mp4_audio_codeclist, mp4_video_codeclist, VIDEO_OPTIONS }, + { "ogg", ogg_audio_codeclist, ogg_video_codeclist, VIDEO_OPTIONS }, + { "avi", avi_audio_codeclist, avi_video_codeclist, VIDEO_OPTIONS }, + { "matroska", mp4_audio_codeclist, mp4_video_codeclist, VIDEO_OPTIONS }, + { "wav", avi_audio_codeclist, NULL, AUDIO_OPTIONS }, + { "mp3", mp3_audio_codeclist, NULL, AUDIO_OPTIONS }, /* formats expects png which fails in VICE */ + { "mp2", mp2_audio_codeclist, NULL, AUDIO_OPTIONS }, + { NULL, NULL, NULL, 0 } +}; + +/******************************************************************************/ + +/* general */ +static int file_init_done; + +#define DUMMY_FRAMES_VIDEO 1 +#define DUMMY_FRAMES_AUDIO ((int)round(fps * (double)AUDIO_SKIP_SECONDS)) + +#define AUDIO_SKIP_SECONDS 4 + +#define SOCKETS_RANGE_FIRST 53248 +#define SOCKETS_RANGE_LAST 57343 +static int current_video_port = SOCKETS_RANGE_FIRST; +static int current_audio_port = SOCKETS_RANGE_FIRST + 1; + +/* input video stream */ +#define INPUT_VIDEO_BPP 3 + +static double time_base; +static double fps; /* frames per second */ +static uint64_t framecounter = 0; /* number of processed video frames */ + +typedef struct { + uint8_t *data; + int linesize; +} VIDEOFrame; +static VIDEOFrame *video_st_frame; + +/* input audio stream */ +#define AUDIO_BUFFER_SAMPLES 0x400 +#define AUDIO_BUFFER_MAX_CHANNELS 2 + +static soundmovie_buffer_t ffmpegexedrv_audio_in; +static int audio_init_done; +static int audio_is_open; +static int audio_has_codec = -1; +static uint64_t audio_input_counter = 0; /* total samples played */ +static int audio_input_sample_rate = -1; /* samples per second */ +static int audio_input_channels = -1; + +/* output video */ +static int video_init_done; +static int video_is_open; +static int video_has_codec = -1; +static int video_width = -1; +static int video_height = -1; + +/* ffmpeg interface */ +static int ffmpeg_stdin = 0; +static int ffmpeg_stdout = 0; +static vice_pid_t ffmpeg_pid = 0; + +static vice_network_socket_t *ffmpeg_video_socket = NULL; +static vice_network_socket_t *ffmpeg_audio_socket = NULL; +#ifdef VICE_IS_SERVER +static vice_network_socket_t *ffmpeg_video_listen_socket = NULL; +static vice_network_socket_t *ffmpeg_audio_listen_socket = NULL; +#endif +static char *outfilename = NULL; + +log_t ffmpeg_log = LOG_DEFAULT; + +/******************************************************************************/ + +static int ffmpegexedrv_init_file(void); +static void ffmpegexedrv_shutdown(void); + +/******************************************************************************/ +/* resources */ + +static char *ffmpegexe_format = NULL; /* FFMPEGFormat */ +static int format_index; /* FFMPEGFormat */ +static int audio_codec; +static int video_codec; +static int audio_bitrate; +static int video_bitrate; +static int video_halve_framerate; + +static int set_container_format(const char *val, void *param) +{ + int i; + + /* kludge to prevent crash at startup when using --help on the commandline */ + if (ffmpegexedrv_formatlist == NULL) { + return 0; + } + + format_index = -1; + + for (i = 0; ffmpegexedrv_formatlist[i].name != NULL; i++) { + if (strcmp(val, ffmpegexedrv_formatlist[i].name) == 0) { + format_index = i; + } + } + + if (format_index < 0) { + return -1; + } + + if (ffmpegexe_format) { + lib_free(ffmpegexe_format); + ffmpegexe_format = NULL; + } + util_string_set(&ffmpegexe_format, val); + + return 0; +} + +static int set_audio_bitrate(int val, void *param) +{ + audio_bitrate = val; + + if ((audio_bitrate < VICE_FFMPEG_AUDIO_RATE_MIN) + || (audio_bitrate > VICE_FFMPEG_AUDIO_RATE_MAX)) { + audio_bitrate = VICE_FFMPEG_AUDIO_RATE_DEFAULT; + } + return 0; +} + +static int set_video_bitrate(int val, void *param) +{ + video_bitrate = val; + + if ((video_bitrate < VICE_FFMPEG_VIDEO_RATE_MIN) + || (video_bitrate > VICE_FFMPEG_VIDEO_RATE_MAX)) { + video_bitrate = VICE_FFMPEG_VIDEO_RATE_DEFAULT; + } + return 0; +} + +static int set_audio_codec(int val, void *param) +{ + audio_codec = val; + return 0; +} + +static int set_video_codec(int val, void *param) +{ + video_codec = val; + return 0; +} + +static int set_video_halve_framerate(int value, void *param) +{ + int val = value ? 1 : 0; + + if (video_halve_framerate != val && screenshot_is_recording()) { + ui_error("Can't change framerate while recording. Try again later."); + return 0; + } + + video_halve_framerate = val; + + return 0; +} + +/*---------- Resources ------------------------------------------------*/ + +static const resource_string_t resources_string[] = { +/* FIXME: register only here, not in the internal ffmpeg driver */ + { "FFMPEGFormat", "mp4", RES_EVENT_NO, NULL, + &ffmpegexe_format, set_container_format, NULL }, + RESOURCE_STRING_LIST_END +}; + +static const resource_int_t resources_int[] = { +/* FIXME: register only here, not in the internal ffmpeg driver */ + { "FFMPEGAudioBitrate", VICE_FFMPEG_AUDIO_RATE_DEFAULT, + RES_EVENT_NO, NULL, + &audio_bitrate, set_audio_bitrate, NULL }, + { "FFMPEGVideoBitrate", VICE_FFMPEG_VIDEO_RATE_DEFAULT, + RES_EVENT_NO, NULL, + &video_bitrate, set_video_bitrate, NULL }, + { "FFMPEGAudioCodec", AV_CODEC_ID_AAC, RES_EVENT_NO, NULL, + &audio_codec, set_audio_codec, NULL }, + { "FFMPEGVideoCodec", AV_CODEC_ID_H264, RES_EVENT_NO, NULL, + &video_codec, set_video_codec, NULL }, + { "FFMPEGVideoHalveFramerate", 0, RES_EVENT_NO, NULL, + &video_halve_framerate, set_video_halve_framerate, NULL }, + RESOURCE_INT_LIST_END +}; + +/* Driver API gfxoutputdrv_t.resources_init */ +static int ffmpegexedrv_resources_init(void) +{ + ffmpeg_log = log_open("FFMPEG"); + + if (resources_register_string(resources_string) < 0) { + return -1; + } + + return resources_register_int(resources_int); +} + +/*---------- Commandline options --------------------------------------*/ + +static const cmdline_option_t cmdline_options[] = +{ +/* FIXME: register only here, not in the internal ffmpeg driver */ + { "-ffmpegaudiobitrate", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "FFMPEGAudioBitrate", NULL, + "", "Set bitrate for audio stream in media file" }, + { "-ffmpegvideobitrate", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "FFMPEGVideoBitrate", NULL, + "", "Set bitrate for video stream in media file" }, + CMDLINE_LIST_END +}; + +/* Driver API gfxoutputdrv_t.cmdline_options_init */ +static int ffmpegexedrv_cmdline_options_init(void) +{ + return cmdline_register_options(cmdline_options); +} + +/*---------------------------------------------------------------------*/ + +static void log_resource_values(const char *func) +{ + DBG(("%s FFMPEGFormat:%s", func, ffmpegexe_format)); + DBG(("%s FFMPEGVideoCodec:%d:'%s'", func, video_codec, av_codec_get_option(video_codec))); + DBG(("%s FFMPEGVideoBitrate:%d", func, video_bitrate)); + DBG(("%s FFMPEGAudioCodec:%d:'%s'", func, audio_codec, av_codec_get_option(audio_codec))); + DBG(("%s FFMPEGAudioBitrate:%d", func, audio_bitrate)); + DBG(("%s FFMPEGVideoHalveFramerate:%d", func, video_halve_framerate)); +} + +static void prepare_port_numbers(void) +{ + current_video_port += 2; + current_audio_port += 2; + if (current_audio_port > SOCKETS_RANGE_LAST) { + current_video_port = SOCKETS_RANGE_FIRST; + current_audio_port = SOCKETS_RANGE_FIRST + 1; + } + log_message(ffmpeg_log, "prepare_port_numbers %d:%d", current_video_port, current_audio_port); +} + +static ssize_t write_video_frame(VIDEOFrame *pic) +{ + ssize_t len = INPUT_VIDEO_BPP * video_height * video_width; + ssize_t res; + + if ((video_has_codec > 0) && (video_codec != AV_CODEC_ID_NONE)) { + if (ffmpeg_video_socket == 0) { + log_error(ffmpeg_log, "FFMPEG: write_video_frame ffmpeg_video_socket is 0 (framecount:%"PRIu64")", framecounter); + return -1; + } + res = vice_network_send(ffmpeg_video_socket, pic->data, len, 0 /* flags */); + if (res < 0) { + return -1; + } + return len - res; + } + return 0; +} + +static int write_initial_video_frames(void) +{ + int len; + int frm; + /* clear frame */ + len = INPUT_VIDEO_BPP * video_height * video_width; + DBG(("video len:%d (%d)", len, len * DUMMY_FRAMES_VIDEO)); + memset(video_st_frame->data, 0, len); + for (frm = 0; frm < DUMMY_FRAMES_VIDEO; frm++) { + if (write_video_frame(video_st_frame) < 0) { + return -1; + } + } + return 0; +} + +static int write_initial_audio_frames(void) +{ + ssize_t len; + int frm; + ssize_t res; + + /* clear frame */ + len = (sizeof(uint16_t) * audio_input_sample_rate) / fps; + if (video_halve_framerate) { + len /= 2; + } + DBG(("audio len:%zd (%zd)", len, len * DUMMY_FRAMES_AUDIO)); + memset(ffmpegexedrv_audio_in.buffer, 0, len); + for (frm = 0; frm < DUMMY_FRAMES_AUDIO; frm++) { + res = vice_network_send(ffmpeg_audio_socket, ffmpegexedrv_audio_in.buffer, len, 0 /* flags */); + if (res != len) { + log_error(ffmpeg_log, "ffmpegexedrv: Error writing to AUDIO socket"); + return -1; + } + if (audio_input_channels == 2) { + /* stereo - send twice the amount of data */ + res = vice_network_send(ffmpeg_audio_socket, ffmpegexedrv_audio_in.buffer, len, 0 /* flags */); + if (res != len) { + log_error(ffmpeg_log, "ffmpegexedrv: Error writing to AUDIO socket"); + return -1; + } + } + } + return 0; +} + +#ifdef VICE_IS_SERVER +/* Try to find two ports that we can use. This doesn't work as expected :/ */ +static void find_ports(void) +{ + int port; + for (port = 49152; port < 65535; port++) { + vice_network_socket_address_t *ad = NULL; + vice_network_socket_t *s = NULL; + ad = vice_network_address_generate("127.0.0.1", port); + if (!ad) { + log_error(ffmpeg_log, "Bad device name (port:%d).\n", port); + } + /* connect socket */ + s = vice_network_server(ad); + if (!s) { + log_error(ffmpeg_log, "Bad port number (port:%d).\n", port); + } else { + /*log_error(ffmpeg_log, "Good port number (port:%d).\n", port);*/ + vice_network_socket_close(s); + } + if (ad) { + vice_network_address_close(ad); + } + } +} +#endif + +static int test_ffmpeg_executable(void) +{ +#if 0 + int ret; + char *argv[5]; + /* `exec*()' does not want these to be constant... */ + argv[0] = lib_strdup("ffmpeg"); + argv[1] = lib_strdup("-hide_banner"); + argv[2] = lib_strdup("-loglevel"); + argv[3] = lib_strdup("quiet"); + argv[4] = NULL; + + ret = archdep_spawn("ffmpeg", argv, NULL, NULL); + + lib_free(argv[0]); + lib_free(argv[1]); + lib_free(argv[2]); + lib_free(argv[3]); + + /* NOTE: ffmpeg returns 1 (not 0) on success */ + if (ret != 1) { + log_error(ffmpeg_log, "ffmpeg executable can not be started. (ret:%d)", ret); + return -1; + } + return 0; +#else + static int test_stdin = -1; + static int test_stdout = -1; + static vice_pid_t test_pid = VICE_PID_INVALID; + int res = -1; + size_t n; + static char output[0x40]; + static char command[0x40] = { + "ffmpeg 2>&1" /* redirect stderr to stdout. this better works on the big 3 */ + }; + /* kill old process in case it is still running for whatever reason */ + if (test_pid != VICE_PID_INVALID) { + kill_coproc(test_pid); + test_pid = VICE_PID_INVALID; + } + if (test_stdin != -1) { + close(test_stdin); + test_stdin = -1; + } + if (test_stdout != -1) { + close(test_stdout); + test_stdout = -1; + } + DBG(("test_ffmpeg_executable: '%s'", command)); + /*log_printf("fork command:%s", command);*/ + if (fork_coproc(&test_stdin, &test_stdout, command, &test_pid) < 0) { + log_error(ffmpeg_log, "Cannot fork ffmpeg process '%s'.", command); + goto testend; + } + /*log_printf("test_ffmpeg_executable pid:%d stdin:%d stdout:%d", test_pid, test_stdin, test_stdout);*/ +#ifdef WINDOWS_COMPILE + if (test_pid == VICE_PID_INVALID) { + log_error(ffmpeg_log, "Cannot fork ffmpeg process '%s' (pid == NULL).", command); +#else + if (test_pid <= 0) { + log_error(ffmpeg_log, "Cannot fork ffmpeg process '%s' (pid <= 0).", command); +#endif + goto testend; + } + + /* FIXME: stdout is 0 on error ? */ + if (test_stdout) { + memset(output, 0, 0x40); + n = read(test_stdout, output, 0x3f); + /*log_printf("test_ffmpeg_executable got: '%s'", output);*/ + output[6] = 0; + if ((n >= 6) && !strcmp("ffmpeg", output)) { + res = 0; + /*log_printf("test_ffmpeg_executable tested ok");*/ + } + } + if (res < 0) { + log_error(ffmpeg_log, "ffmpeg not found.\n"); + } +testend: + /* kill new process */ + if (test_pid != VICE_PID_INVALID) { + kill_coproc(test_pid); + test_pid = VICE_PID_INVALID; + } + if (test_stdin != -1) { + close(test_stdin); + test_stdin = -1; + } + if (test_stdout != -1) { + close(test_stdout); + test_stdout = -1; + } + return res; +#endif +} + +static int start_ffmpeg_executable(void) +{ + char fpsstring[0x20]; + char *dot; + static char command[0x400]; + static char tempcommand[0x400]; + int n; + int audio_connected = 0; + int video_connected = 0; + + log_resource_values(__FUNCTION__); + + /* FPS of the input, including "half framerate" */ + sprintf(fpsstring, "%f", fps); + dot = strchr(fpsstring,','); + if (dot) { + *dot = '.'; + } + + strcpy(command, + "ffmpeg " + "-nostdin " + /* Caution: at least on windows we must avoid that the ffmpeg + executable produces output on stdout - if it does, the process + may block and wait for ffmpeg_stderr being read */ + "-hide_banner " +#ifdef DEBUG_FFMPEG + /* "-loglevel trace " */ + "-loglevel verbose " + /* "-loglevel error " */ +#else + "-loglevel quiet " +#endif + ); + + /* options to define the input video format */ + if ((video_has_codec > 0) && (video_codec != AV_CODEC_ID_NONE)) { + sprintf(tempcommand, + "-f rawvideo " + "-pixel_format rgb24 " + "-framerate %s " /* exact fps */ + "-r %s " /* exact fps */ + "-s %dx%d " /* size */ + /*"-readrate_initial_burst 0 "*/ /* no initial burst read */ + /*"-readrate 1 "*/ /* Read input at native frame rate */ + "-thread_queue_size 512 " +#ifdef VICE_IS_SERVER + "-i tcp://127.0.0.1:%d " +#else + "-i tcp://127.0.0.1:%d?listen " +#endif + , fpsstring, fpsstring + , video_width, video_height + , current_video_port + ); + strcat(command, tempcommand); + } + + /* options to define the input audio format */ + if ((audio_has_codec > 0) && (audio_codec != AV_CODEC_ID_NONE)) { + sprintf(tempcommand, + "-f s16le " /* input audio stream format */ + "-acodec pcm_s16le " /* audio codec */ + "-ac %d " /* input audio channels */ + "-ar %d " /* input audio stream sample rate */ + "-ss %d " /* skip seconds at start */ + "-thread_queue_size 512 " +#ifdef VICE_IS_SERVER + "-i tcp://127.0.0.1:%d " +#else + "-i tcp://127.0.0.1:%d?listen " +#endif + , audio_input_channels + , audio_input_sample_rate + , AUDIO_SKIP_SECONDS + , current_audio_port + ); + strcat(command, tempcommand); + } + + /* options for the output file */ + sprintf(tempcommand, + "-y " /* overwrite existing file */ + "-f %s " /* outfile format/container */ + "-shortest " /* Finish encoding when the shortest output stream ends. */ + /*"-shortest_buf_duration 1 "*/ /* the maximum duration of buffered frames in seconds */ + , ffmpegexe_format /* outfile format/container */ + ); + strcat(command, tempcommand); + /* options for the output file (video) */ + if ((video_has_codec > 0) && (video_codec != AV_CODEC_ID_NONE)) { + sprintf(tempcommand, + "-framerate %s " /* exact fps */ + "-r %s " /* exact fps */ + "-vcodec %s " /* outfile video codec */ + "-b:v %d " /* outfile video bitrate */ + , fpsstring, fpsstring + , av_codec_get_option(video_codec) /* outfile video codec */ + , video_bitrate /* outfile video bitrate */ + ); + strcat(command, tempcommand); + } + /* options for the output file (audio) */ + if ((audio_has_codec > 0) && (audio_codec != AV_CODEC_ID_NONE)) { + sprintf(tempcommand, + "-acodec %s " /* outfile audio codec */ + "-b:a %d " /* outfile audio bitrate */ + , av_codec_get_option(audio_codec) /* outfile audio codec */ + , audio_bitrate /* outfile audio bitrate */ + ); + strcat(command, tempcommand); + } + + /* last not least the output file name */ + strcat(command, outfilename ? outfilename : "outfile.avi"); + +#ifndef VICE_IS_SERVER + /* kill old process in case it is still running for whatever reason */ + if (ffmpeg_pid != 0) { + kill_coproc(ffmpeg_pid); + ffmpeg_pid = 0; + } + + /*DBG(("forking ffmpeg: '%s'", command));*/ + if (fork_coproc(&ffmpeg_stdin, &ffmpeg_stdout, command, &ffmpeg_pid) < 0) { + log_error(ffmpeg_log, "Cannot fork process '%s'.", command); + return -1; + } +#endif + + if ((video_has_codec > 0) && (video_codec != AV_CODEC_ID_NONE)) { + vice_network_socket_address_t *ad = NULL; + ad = vice_network_address_generate("127.0.0.1", current_video_port); + if (!ad) { + log_error(ffmpeg_log, "Bad device name.\n"); + return -1; + } + /* connect socket */ + for (n = 0; n < 200; n++) { +#ifdef VICE_IS_SERVER + ffmpeg_video_listen_socket = vice_network_server(ad); + if (!ffmpeg_video_listen_socket) { +#else + ffmpeg_video_socket = vice_network_client(ad); + if (!ffmpeg_video_socket) { +#endif + /*log_error(ffmpeg_log, "ffmpegexedrv: Error connecting AUDIO socket");*/ + archdep_usleep(1000); + } else { + log_message(ffmpeg_log, "ffmpegexedrv: VIDEO connected"); + video_connected = 1; + break; + } + } + if (!video_connected) { + log_error(ffmpeg_log, "ffmpegexedrv: Error connecting VIDEO socket"); + return -1; + } + } + +#ifndef VICE_IS_SERVER + if (write_initial_video_frames() < 0) { + return -1; + } +#endif + + if ((audio_has_codec > 0) && (audio_codec != AV_CODEC_ID_NONE)) { + vice_network_socket_address_t *ad = NULL; + ad = vice_network_address_generate("127.0.0.1", current_audio_port); + if (!ad) { + log_error(ffmpeg_log, "Bad device name.\n"); + return -1; + } + /* connect socket */ + for (n = 0; n < 200; n++) { +#ifdef VICE_IS_SERVER + ffmpeg_audio_listen_socket = vice_network_server(ad); + if (!ffmpeg_audio_listen_socket) { +#else + ffmpeg_audio_socket = vice_network_client(ad); + if (!ffmpeg_audio_socket) { +#endif + /*log_error(ffmpeg_log, "ffmpegexedrv: Error connecting AUDIO socket");*/ + archdep_usleep(1000); + } else { + log_message(ffmpeg_log, "ffmpegexedrv: AUDIO connected"); + audio_connected = 1; + break; + } + } + if (!audio_connected) { + log_error(ffmpeg_log, "ffmpegexedrv: Error connecting AUDIO socket"); + return -1; + } + } + +#ifndef VICE_IS_SERVER + if (write_initial_audio_frames() < 0) { + return -1; + } +#endif + +#ifdef VICE_IS_SERVER + /* kill old process in case it is still running for whatever reason */ + if (ffmpeg_pid != 0) { + kill_coproc(ffmpeg_pid); + ffmpeg_pid = 0; + } + /*DBG(("forking ffmpeg: '%s'", command));*/ + if (fork_coproc(&ffmpeg_stdin, &ffmpeg_stdout, command, &ffmpeg_pid) < 0) { + log_error(ffmpeg_log, "Cannot fork process '%s'.", command); + return -1; + } + + do { + int audio_available = 0; + int video_available = 0; + + /*archdep_sleep(1);*/ + if (ffmpeg_audio_socket != NULL) { + audio_available = vice_network_select_poll_one(ffmpeg_audio_socket); + DBG(("ffmpeg_audio_socket available: %d", audio_available)); + } else if (ffmpeg_audio_listen_socket != NULL) { + /* we have no connection yet, allow for connection */ + + if (vice_network_select_poll_one(ffmpeg_audio_listen_socket)) { + ffmpeg_audio_socket = vice_network_accept(ffmpeg_audio_listen_socket); + write_initial_audio_frames(); + } + DBG(("ffmpeg_audio_socket connected: %p", ffmpeg_audio_socket)); + } + if (ffmpeg_video_socket != NULL) { + video_available = vice_network_select_poll_one(ffmpeg_video_socket); + DBG(("ffmpeg_video_socket available: %d", video_available)); + } else if (ffmpeg_video_listen_socket != NULL) { + /* we have no connection yet, allow for connection */ + + if (vice_network_select_poll_one(ffmpeg_video_listen_socket)) { + ffmpeg_video_socket = vice_network_accept(ffmpeg_video_listen_socket); + if (write_initial_video_frames() < 0) { + return -1; + } + } + DBG(("ffmpeg_video_socket connected: %p", ffmpeg_video_socket)); + } + } while ((ffmpeg_audio_socket == NULL) || (ffmpeg_video_socket == NULL)); +#endif + + log_message(ffmpeg_log, "ffmpegexedrv: pipes are ready"); + return 0; +} + +static void close_video_stream(void) +{ + if (ffmpeg_video_socket != NULL) { + vice_network_socket_close(ffmpeg_video_socket); + ffmpeg_video_socket = NULL; + } +} + +static void close_audio_stream(void) +{ + if (ffmpeg_audio_socket != NULL) { + vice_network_socket_close(ffmpeg_audio_socket); + ffmpeg_audio_socket = NULL; + } +} + +static void close_stream(void) +{ + if (ffmpeg_video_socket != NULL) { + vice_network_socket_close(ffmpeg_video_socket); + ffmpeg_video_socket = NULL; + } + if (ffmpeg_audio_socket != NULL) { + vice_network_socket_close(ffmpeg_audio_socket); + ffmpeg_audio_socket = NULL; + } +#ifdef VICE_IS_SERVER + if (ffmpeg_video_listen_socket != NULL) { + vice_network_socket_close(ffmpeg_video_listen_socket); + ffmpeg_video_listen_socket = NULL; + } + if (ffmpeg_audio_listen_socket != NULL) { + vice_network_socket_close(ffmpeg_audio_listen_socket); + ffmpeg_audio_listen_socket = NULL; + } +#endif + if (ffmpeg_stdin != -1) { + close(ffmpeg_stdin); + ffmpeg_stdin = -1; + } + if (ffmpeg_stdout != -1) { + close(ffmpeg_stdout); + ffmpeg_stdout = -1; + } + /* do not kill ffmpeg here, it should die when the streams close. if it is + killed early the resulting file will be broken */ +#if 0 + if (ffmpeg_pid != 0) { + kill_coproc(ffmpeg_pid); + ffmpeg_pid = 0; + } +#endif + + prepare_port_numbers(); +} + +/***************************************************************************** + audio stream encoding + *****************************************************************************/ + +/* called by ffmpegexedrv_init_video -> ffmpegexedrv_init_file */ +static int ffmpegexedrv_open_audio(void) +{ + size_t audio_inbuf_size; + DBG(("ffmpegexedrv_open_audio (%d,%d)", audio_input_channels, AUDIO_BUFFER_MAX_CHANNELS)); + /*assert((audio_input_channels > 0));*/ + /*if (audio_input_channels < 1) { + log_warning(ffmpeg_log, "ffmpegexedrv_open_audio audio_input_channels < 1 (%d,%d)", audio_input_channels, AUDIO_BUFFER_MAX_CHANNELS); + }*/ + + audio_is_open = 1; + + /* FIXME: audio_input_channels NOT ready yet */ + ffmpegexedrv_audio_in.size = AUDIO_BUFFER_SAMPLES; + ffmpegexedrv_audio_in.used = 0; + /* audio_inbuf_size = AUDIO_BUFFER_SAMPLES * sizeof(int16_t) * audio_input_channels; */ + audio_inbuf_size = AUDIO_BUFFER_SAMPLES * sizeof(int16_t) * AUDIO_BUFFER_MAX_CHANNELS; + + ffmpegexedrv_audio_in.buffer = lib_malloc(audio_inbuf_size); + if (ffmpegexedrv_audio_in.buffer == NULL) { + log_error(ffmpeg_log, "ffmpegexedrv: Error allocating audio buffer (%u bytes)", (unsigned)audio_inbuf_size); + return -1; + } + return 0; +} + +static void ffmpegexedrv_close_audio(void) +{ + DBG(("ffmpegexedrv_close_audio")); + + close_audio_stream(); + + audio_input_sample_rate = -1; + audio_is_open = 0; + audio_input_counter = 0; + + if (ffmpegexedrv_audio_in.buffer) { + lib_free(ffmpegexedrv_audio_in.buffer); + } + ffmpegexedrv_audio_in.buffer = NULL; + ffmpegexedrv_audio_in.size = 0; +} + +/* Soundmovie API soundmovie_funcs_t.init */ +/* called via ffmpegexedrv_soundmovie_funcs->init */ +static int ffmpegexe_soundmovie_init(int speed, int channels, soundmovie_buffer_t ** audio_in) +{ + DBG(("ffmpegexe_soundmovie_init(speed: %d channels: %d)", speed, channels)); + + audio_init_done = 1; + + *audio_in = &ffmpegexedrv_audio_in; + (*audio_in)->used = 0; + + audio_input_sample_rate = speed; + audio_input_channels = channels; + +#if 0 + if (video_init_done) { + ffmpegexedrv_init_file(); + } +#endif + + return start_ffmpeg_executable(); +} + +/* Soundmovie API soundmovie_funcs_t.encode */ +/* called via ffmpegexedrv_soundmovie_funcs->encode */ +/* triggered by soundffmpegaudio->write */ +static int ffmpegexe_soundmovie_encode(soundmovie_buffer_t *audio_in) +{ + ssize_t res; +#ifdef DEBUG_FFMPEG_FRAMES + double frametime = (double)framecounter / fps; + double audiotime = (double)audio_input_counter / (double)audio_input_sample_rate; + if (audio_in) { + DBGFRAMES(("ffmpegexe_soundmovie_encode(framecount:%lu, audiocount:%lu frametime:%f, audiotime:%f size:%d used:%d)", + framecounter, audio_input_counter, frametime, audiotime, audio_in->size, audio_in->used)); + } else { + DBG(("ffmpegexe_soundmovie_encode (NULL)")); + } +#endif + + if (ffmpeg_audio_socket == 0) { + log_error(ffmpeg_log, "FFMPEG: ffmpegexe_soundmovie_encode ffmpeg_audio_socket is 0 (framecount:%"PRIu64")", audio_input_counter); + return 0; + } + + if ((audio_has_codec > 0) && (audio_codec != AV_CODEC_ID_NONE)) { + /* FIXME: we might have an endianess problem here, we might have to swap lo/hi on BE machines */ + if (audio_input_channels == 1) { + res = vice_network_send(ffmpeg_audio_socket, &audio_in->buffer[0], audio_in->used * 2, 0 /* flags */); + if (res != audio_in->used * 2) { + return -1; + } + audio_input_counter += audio_in->used; + } else if (audio_input_channels == 2) { + res = vice_network_send(ffmpeg_audio_socket, &audio_in->buffer[0], audio_in->used * 2, 0 /* flags */); + if (res != audio_in->used * 2) { + return -1; + } + audio_input_counter += audio_in->used / 2; + } else { + return -1; + } + } + + audio_in->used = 0; + return 0; +} + +/* Soundmovie API soundmovie_funcs_t.close */ +/* called via ffmpegexedrv_soundmovie_funcs->close */ +static void ffmpegexe_soundmovie_close(void) +{ + DBG(("ffmpegexe_soundmovie_close")); + /* just stop the whole recording */ + screenshot_stop_recording(); +} + +static soundmovie_funcs_t ffmpegexedrv_soundmovie_funcs = { + ffmpegexe_soundmovie_init, + ffmpegexe_soundmovie_encode, + ffmpegexe_soundmovie_close +}; + +/***************************************************************************** + video stream encoding + *****************************************************************************/ + +static int video_fill_rgb_image(screenshot_t *screenshot, VIDEOFrame *pic) +{ + int x, y; + int dx, dy; + int colnum; + int bufferoffset; + int x_dim = screenshot->width; + int y_dim = screenshot->height; + int pix = 0; + /* center the screenshot in the video */ + pic->linesize = video_width * INPUT_VIDEO_BPP; + dx = (video_width - x_dim) / 2; + dy = (video_height - y_dim) / 2; + bufferoffset = screenshot->x_offset + (dx < 0 ? -dx : 0) + + (screenshot->y_offset + (dy < 0 ? -dy : 0)) * screenshot->draw_buffer_line_size; + + for (y = 0; y < video_height; y++) { + for (x = 0; x < video_width; x++) { + colnum = screenshot->draw_buffer[bufferoffset + x]; + pic->data[pix + INPUT_VIDEO_BPP * x] = screenshot->palette->entries[colnum].red; + pic->data[pix + INPUT_VIDEO_BPP * x + 1] = screenshot->palette->entries[colnum].green; + pic->data[pix + INPUT_VIDEO_BPP * x + 2] = screenshot->palette->entries[colnum].blue; + } + bufferoffset += screenshot->draw_buffer_line_size; + pix += pic->linesize; + } + + return 0; +} + +/* called by ffmpegexedrv_open_video() */ +static VIDEOFrame* video_alloc_picture(int bpp, int width, int height) +{ + VIDEOFrame *picture; + + picture = lib_malloc(sizeof(VIDEOFrame)); + if (!picture) { + return NULL; + } + picture->data = lib_malloc(bpp * width * height); + if (!picture->data) { + lib_free(picture); + log_debug(ffmpeg_log, "ffmpegexedrv: Could not allocate frame data"); + return NULL; + } + + picture->linesize = width; + return picture; +} + +static void video_free_picture(VIDEOFrame *picture) +{ + lib_free(picture->data); + lib_free(picture); +} + +/* called by ffmpegexedrv_init_file */ +static int ffmpegexedrv_open_video(void) +{ + DBG(("ffmpegexedrv_open_video w:%d h:%d", video_width, video_height)); + + video_is_open = 1; + + /* allocate the encoded raw picture */ + video_st_frame = video_alloc_picture(INPUT_VIDEO_BPP, video_width, video_height); + if (!video_st_frame) { + log_debug(ffmpeg_log, "ffmpegexedrv: could not allocate picture"); + return -1; + } + + return 0; +} + +/* called by ffmpegexedrv_close() */ +static void ffmpegexedrv_close_video(void) +{ + DBG(("ffmpegexedrv_close_video")); + close_video_stream(); + video_is_open = 0; + if (video_st_frame) { + video_free_picture(video_st_frame); + video_st_frame = NULL; + } + framecounter = 0; +} + +/* called by ffmpegexedrv_save */ +static void ffmpegexedrv_init_video(screenshot_t *screenshot) +{ + DBG(("ffmpegexedrv_init_video")); + video_init_done = 1; + + /* resolution should be a multiple of 16 */ + /* video_fill_rgb_image only implements cutting so */ + /* adding black border was removed */ + video_width = screenshot->width & ~0xf; + video_height = screenshot->height & ~0xf; + /* frames per second */ + log_resource_values(__FUNCTION__); + + DBG(("ffmpegexedrv_init_video w:%d h:%d (halve framerate:%d)", + video_width, video_height, video_halve_framerate)); + time_base = machine_get_cycles_per_frame() + / (double)(video_halve_framerate ? + machine_get_cycles_per_second() / 2 : + machine_get_cycles_per_second()); + fps = 1.0f / time_base; + DBG(("ffmpegexedrv_init_video fps: %f timebase: %f", fps, time_base)); + framecounter = 0; + + ffmpegexedrv_init_file(); +} + + +/*****************************************************************************/ + +/* called by ffmpegexedrv_init_video */ +static int ffmpegexedrv_init_file(void) +{ + DBG(("ffmpegexedrv_init_file")); +#if 0 + if (!video_init_done || !audio_init_done) { + return 0; + } +#endif + + if (ffmpegexedrv_open_video() < 0) { + screenshot_stop_recording(); + ui_error("ffmpegexedrv: Cannot open video stream"); + return -1; + } + + if (ffmpegexedrv_open_audio() < 0) { + screenshot_stop_recording(); + ui_error("ffmpegexedrv: Cannot open audio stream"); + return -1; + } + + log_debug(ffmpeg_log, "ffmpegexedrv: Initialized file successfully"); + + /*start_ffmpeg_executable();*/ + + file_init_done = 1; + + return 0; +} + +/* Driver API gfxoutputdrv_t.save */ +/* called once to start recording video+audio */ +static int ffmpegexedrv_save(screenshot_t *screenshot, const char *filename) +{ + gfxoutputdrv_format_t *format; + + DBG(("ffmpegexedrv_save(%s)", filename)); + + audio_init_done = 0; + video_init_done = 0; + file_init_done = 0; + + if (test_ffmpeg_executable() < 0) { + screenshot_stop_recording(); + archdep_sleep(1); + if (test_ffmpeg_executable() < 0) { + archdep_sleep(1); + if (test_ffmpeg_executable() < 0) { + ui_error("ffmpeg executable could not be started."); + /* Do not return -1, since that would just pop up a second error message, + which will eventually appear behind the main window, and make the UI + seem to hang. We can do this, since there is no further error handling + depending on the return value. */ + return 0; + } + } + } + + log_resource_values(__FUNCTION__); + + DBG(("FFMPEGFormat:%s (format_index:%d)", ffmpegexe_format, format_index)); + + if (format_index < 0) { + return -1; + } + + format = &ffmpegexedrv_formatlist[format_index]; + + audio_has_codec = (format->audio_codecs != NULL); + /* the codec from resource */ + DBG(("ffmpegexedrv_save(audio_has_codec: %d audio_codec:%d:%s)", + audio_has_codec, audio_codec, av_codec_get_option(audio_codec))); + + video_has_codec = (format->video_codecs != NULL); + /* the codec from resource */ + DBG(("ffmpegexedrv_save(video_has_codec: %d video_codec:%d:%s)", + video_has_codec, video_codec, av_codec_get_option(video_codec))); + + outfilename = lib_strdup(filename); + + ffmpegexedrv_init_video(screenshot); + + soundmovie_start(&ffmpegexedrv_soundmovie_funcs); + + return 0; +} + +/* Driver API gfxoutputdrv_t.close */ +static int ffmpegexedrv_close(screenshot_t *screenshot) +{ + DBG(("ffmpegexedrv_close")); + + soundmovie_stop(); + + ffmpegexedrv_close_video(); + ffmpegexedrv_close_audio(); + + /* free the streams */ + close_stream(); + + log_debug(ffmpeg_log, "ffmpegexedrv: Closed successfully"); + + file_init_done = 0; + + if (outfilename) { + lib_free(outfilename); + outfilename = NULL; + } + + return 0; +} + +/* Driver API gfxoutputdrv_t.record */ +/* triggered by screenshot_record, periodically called to output video data stream */ +static int ffmpegexedrv_record(screenshot_t *screenshot) +{ + double frametime = (double)framecounter / fps; + double audiotime = (double)audio_input_counter / (double)audio_input_sample_rate; + DBGFRAMES(("ffmpegexedrv_record(framecount:%lu, audiocount:%lu frametime:%f, audiotime:%f)", + framecounter, audio_input_counter, frametime, audiotime)); + /* log_resource_values(__FUNCTION__); */ + + framecounter++; + + if (video_halve_framerate && (framecounter & 1)) { + /* drop every second frame */ + return 0; + } + + if (video_halve_framerate) { + frametime /= 2; + } + + /* the video is ahead */ + if (frametime > (audiotime + (time_base * 1.5f))) { + /* drop one frame */ + framecounter--; + DBG(("video is ahead, dropping a frame (framecount:%lu, audiocount:%lu frametime:%f, audiotime:%f)", + framecounter, audio_input_counter, frametime, audiotime)); + return 0; + } + + /*DBGFRAMES(("ffmpegexedrv_record (%u)", framecounter));*/ + video_fill_rgb_image(screenshot, video_st_frame); + + if (write_video_frame(video_st_frame) < 0) { + return -1; + } + + /* the video is late */ + if (frametime < (audiotime - (time_base * 1.5f))) { + /* insert one frame */ + framecounter++; + DBG(("video is late, inserting a frame (framecount:%lu, audiocount:%lu frametime:%f, audiotime:%f)", + framecounter, audio_input_counter, frametime, audiotime)); + if (write_video_frame(video_st_frame) < 0) { + return -1; + } + } + return 0; +} + +/* Driver API gfxoutputdrv_t.write */ +static int ffmpegexedrv_write(screenshot_t *screenshot) +{ + DBG(("ffmpegexedrv_write")); + return 0; +} + +/******************************************************************************/ + +static gfxoutputdrv_t ffmpegexe_drv = { + GFXOUTPUTDRV_TYPE_VIDEO, + "FFMPEG", + "FFMPEG (Executable)", + NULL, + NULL, /* filled in get_formats_and_codecs */ + NULL, /* open */ + ffmpegexedrv_close, + ffmpegexedrv_write, + ffmpegexedrv_save, + NULL, + ffmpegexedrv_record, + ffmpegexedrv_shutdown, + ffmpegexedrv_resources_init, + ffmpegexedrv_cmdline_options_init +#ifdef FEATURE_CPUMEMHISTORY + , NULL +#endif +}; + +/* gfxoutputdrv_t.shutdown */ +static void ffmpegexedrv_shutdown(void) +{ + int i = 0; + + DBG(("ffmpegexedrv_shutdown")); + + /* kill old process in case it is still running for whatever reason */ + if (ffmpeg_pid != 0) { + kill_coproc(ffmpeg_pid); + ffmpeg_pid = 0; + } + + if (ffmpegexe_drv.formatlist != NULL) { + + while (ffmpegexe_drv.formatlist[i].name != NULL) { + lib_free(ffmpegexe_drv.formatlist[i].name); + if (ffmpegexe_drv.formatlist[i].audio_codecs != NULL) { + lib_free(ffmpegexe_drv.formatlist[i].audio_codecs); + } + if (ffmpegexe_drv.formatlist[i].video_codecs != NULL) { + lib_free(ffmpegexe_drv.formatlist[i].video_codecs); + } + i++; + } + if (ffmpegexe_drv.formatlist) { + lib_free(ffmpegexe_drv.formatlist); + ffmpegexe_drv.formatlist = NULL; + } + } +/* ??? this is actually ffmpegexe_drv.formatlist + if (ffmpegexedrv_formatlist) { + lib_free(ffmpegexedrv_formatlist); + } +*/ + + if (ffmpegexe_format) { + lib_free(ffmpegexe_format); + ffmpegexe_format = NULL; + } +} + +/* FIXME: This should interrogate the ffmpeg binary and list all available + formats and codecs */ +static void get_formats_and_codecs(void) +{ + int i, j, ai = 0, vi = 0, f; + gfxoutputdrv_codec_t *audio_codec_list; + gfxoutputdrv_codec_t *video_codec_list; + gfxoutputdrv_codec_t *ac, *vc; + + f = 0; + ffmpegexedrv_formatlist = lib_malloc(sizeof(gfxoutputdrv_format_t)); + + for (i = 0; output_formats_to_test[i].name != NULL; i++) { + audio_codec_list = NULL; + video_codec_list = NULL; + if (output_formats_to_test[i].audio_codecs != NULL) { + ai = 0; + audio_codec_list = lib_malloc(sizeof(gfxoutputdrv_codec_t)); + ac = output_formats_to_test[i].audio_codecs; + for (j = 0; ac[j].name != NULL; j++) { + DBG(("audio_codec_list[%d].name='%s'\n", ai, ac[j].name)); + audio_codec_list[ai++] = ac[j]; + audio_codec_list = lib_realloc(audio_codec_list, (ai + 1) * sizeof(gfxoutputdrv_codec_t)); + } + audio_codec_list[ai].name = NULL; + } + if (output_formats_to_test[i].video_codecs != NULL) { + vi = 0; + video_codec_list = lib_malloc(sizeof(gfxoutputdrv_codec_t)); + vc = output_formats_to_test[i].video_codecs; + for (j = 0; vc[j].name != NULL; j++) { + DBG(("video_codec_list[%d].name='%s'", vi, output_formats_to_test[i].video_codecs[j].name)); + video_codec_list[vi++] = output_formats_to_test[i].video_codecs[j]; + video_codec_list = lib_realloc(video_codec_list, (vi + 1) * sizeof(gfxoutputdrv_codec_t)); + } + video_codec_list[vi].name = NULL; + } + if (((audio_codec_list == NULL) || (ai > 0)) && ((video_codec_list == NULL) || (vi > 0))) { + ffmpegexedrv_formatlist[f].flags = output_formats_to_test[i].flags; + ffmpegexedrv_formatlist[f].name = lib_strdup(output_formats_to_test[i].name); + DBG(("ffmpegexedrv_formatlist[%d].name='%s'", f, ffmpegexedrv_formatlist[f].name)); + ffmpegexedrv_formatlist[f].audio_codecs = audio_codec_list; + ffmpegexedrv_formatlist[f++].video_codecs = video_codec_list; + ffmpegexedrv_formatlist = lib_realloc(ffmpegexedrv_formatlist, (f + 1) * sizeof(gfxoutputdrv_format_t)); + } + } + ffmpegexedrv_formatlist[f].name = NULL; + ffmpegexe_drv.formatlist = ffmpegexedrv_formatlist; +} + +/* public, init this output driver */ +void gfxoutput_init_ffmpegexe(int help) +{ + if (help) { + gfxoutput_register(&ffmpegexe_drv); + return; + } + + get_formats_and_codecs(); + + gfxoutput_register(&ffmpegexe_drv); +} diff --git a/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.h b/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.h new file mode 100644 index 00000000..b62523d0 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/ffmpegexedrv.h @@ -0,0 +1,38 @@ +/* + * ffmpegexedrv.h - Movie driver using FFMPEG executable + * + * Written by + * groepaz@gmx.net + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_FFMPEGEXEDRV_H +#define VICE_FFMPEGEXEDRV_H + +#include "screenshot.h" +#include "gfxoutput.h" + +void gfxoutput_init_ffmpegexe(int help); + +/* deprecated access for UIs that do not use the gfxoutputdrv->formatlist yet: */ +extern gfxoutputdrv_format_t *ffmpegdrv_formatlist; + +#endif diff --git a/src/Emulators/vice/gfxoutputdrv/gfxoutput.c b/src/Emulators/vice/gfxoutputdrv/gfxoutput.c index 4c5473cb..aee7d325 100644 --- a/src/Emulators/vice/gfxoutputdrv/gfxoutput.c +++ b/src/Emulators/vice/gfxoutputdrv/gfxoutput.c @@ -47,17 +47,8 @@ #include "pngdrv.h" #endif -#ifdef HAVE_JPEG -#include "jpegdrv.h" -#endif - -#ifdef HAVE_FFMPEG -#include "ffmpegdrv.h" -#endif - -#ifdef HAVE_QUICKTIME -#include "quicktimedrv.h" -#endif +#include "ffmpegexedrv.h" +#include "zmbvdrv.h" struct gfxoutputdrv_list_s { struct gfxoutputdrv_s *drv; @@ -67,7 +58,7 @@ typedef struct gfxoutputdrv_list_s gfxoutputdrv_list_t; static gfxoutputdrv_list_t *gfxoutputdrv_list = NULL; static int gfxoutputdrv_list_count = 0; -static log_t gfxoutput_log = LOG_ERR; +static log_t gfxoutput_log = LOG_DEFAULT; static gfxoutputdrv_list_t *gfxoutputdrv_list_iter = NULL; @@ -104,28 +95,30 @@ int gfxoutput_early_init(int help) /* on early init for "-help" commandline, some initialization is skipped by the individual drivers */ - gfxoutput_init_bmp(help); - gfxoutput_init_doodle(help); - gfxoutput_init_koala(help); -//#ifdef HAVE_GIF -// gfxoutput_init_gif(help); -//#endif - gfxoutput_init_iff(help); -//#ifdef HAVE_JPEG -// gfxoutput_init_jpeg(help); -//#endif - gfxoutput_init_pcx(help); + + /* common image formats */ #ifdef HAVE_PNG gfxoutput_init_png(help); #endif - gfxoutput_init_ppm(help); -#ifdef HAVE_FFMPEG - gfxoutput_init_ffmpeg(help); -#endif -#ifdef HAVE_QUICKTIME - gfxoutput_init_quicktime(help); + gfxoutput_init_bmp(help); +#ifdef HAVE_GIF + gfxoutput_init_gif(help); #endif + /* slightly less common image formats */ + gfxoutput_init_iff(help); + gfxoutput_init_pcx(help); + gfxoutput_init_ppm(help); + + /* video related */ + gfxoutput_init_zmbv(help); + gfxoutput_init_ffmpegexe(help); + + /* C64 formats */ gfxoutput_init_godot(help); + gfxoutput_init_artstudio(help); + gfxoutput_init_koala(help); + /* VIC20 formats */ + gfxoutput_init_minipaint(help); return 0; } diff --git a/src/Emulators/vice/gfxoutputdrv/gifdrv.c b/src/Emulators/vice/gfxoutputdrv/gifdrv.c index 656b8802..3f3891ad 100644 --- a/src/Emulators/vice/gfxoutputdrv/gifdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/gifdrv.c @@ -40,6 +40,8 @@ #include "vicetypes.h" #include "util.h" +#include "gifdrv.h" + #if GIFLIB_MAJOR >= 5 #define VICE_EGifOpenFileName(x, y, z) EGifOpenFileName(x, y, z) #define VICE_MakeMapObject GifMakeMapObject @@ -192,7 +194,7 @@ static int gifdrv_close_memmap(void) return 0; } -static int gifdrv_write_memmap(int line, int x_size, BYTE *gfx) +static int gifdrv_write_memmap(int line, int x_size, uint8_t *gfx) { if (EGifPutLine(gifdrv_memmap_fd, gfx+(line*x_size), x_size)==GIF_ERROR) return -1; @@ -200,7 +202,7 @@ static int gifdrv_write_memmap(int line, int x_size, BYTE *gfx) return 0; } -static int gifdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE *palette) +static int gifdrv_open_memmap(const char *filename, int x_size, int y_size, uint8_t *palette) { unsigned int i; GifColorType ColorMap256[256]; @@ -241,7 +243,7 @@ static int gifdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE return 0; } -static int gifdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE *gfx, BYTE *palette) +static int gifdrv_save_memmap(const char *filename, int x_size, int y_size, uint8_t *gfx, uint8_t *palette) { int line; @@ -262,6 +264,7 @@ static int gifdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE static gfxoutputdrv_t gif_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, "GIF", "GIF screenshot", "gif", @@ -280,7 +283,7 @@ static gfxoutputdrv_t gif_drv = #endif }; -void gfxoutput_init_gif(void) +void gfxoutput_init_gif(int help) /* VICE 3.10: + help arg (unused here, matches other drivers) */ { gfxoutput_register(&gif_drv); } diff --git a/src/Emulators/vice/gfxoutputdrv/gifdrv.h b/src/Emulators/vice/gfxoutputdrv/gifdrv.h new file mode 100644 index 00000000..4dc1e93d --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/gifdrv.h @@ -0,0 +1,32 @@ +/* + * gifdrv.h - Create a GIF file. + * + * Written by + * Marco van den Heuvel + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_GIFDRV_H +#define VICE_GIFDRV_H + +void gfxoutput_init_gif(int help); + +#endif diff --git a/src/Emulators/vice/gfxoutputdrv/godotdrv.c b/src/Emulators/vice/gfxoutputdrv/godotdrv.c index 8df8c042..634e5553 100644 --- a/src/Emulators/vice/gfxoutputdrv/godotdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/godotdrv.c @@ -45,13 +45,13 @@ typedef struct gfxoutputdrv_data_s { FILE *fd; char *ext_filename; - BYTE *data; + uint8_t *data; unsigned int line; unsigned int count; unsigned int byte; } gfxoutputdrv_data_t; -STATIC_PROTOTYPE gfxoutputdrv_t godot_drv; +static gfxoutputdrv_t godot_drv; static int godotdrv_write_file_header(screenshot_t *screenshot) { @@ -63,7 +63,10 @@ static int godotdrv_write_file_header(screenshot_t *screenshot) } return 0; } - if (fprintf(fd, "GOD1%c%c%c%c", 0, 0, screenshot->width / 8, screenshot->height / 8) < 0) { + if (fprintf(fd, "GOD1%c%c%c%c", + 0, 0, + (int)(screenshot->width / 8), + (int)(screenshot->height / 8)) < 0) { return -1; } return 0; @@ -198,6 +201,7 @@ static int godotdrv_save(screenshot_t *screenshot, const char *filename) static gfxoutputdrv_t godot_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, "4BT", "Godot screenshot", "4bt", diff --git a/src/Emulators/vice/gfxoutputdrv/godotdrv.h b/src/Emulators/vice/gfxoutputdrv/godotdrv.h index 80300e76..329f844d 100644 --- a/src/Emulators/vice/gfxoutputdrv/godotdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/godotdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_GODOTDRV_H #define VICE_GODOTDRV_H -extern void gfxoutput_init_godot(int help); +void gfxoutput_init_godot(int help); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/iffdrv.c b/src/Emulators/vice/gfxoutputdrv/iffdrv.c index 54edd8ba..5a10c415 100644 --- a/src/Emulators/vice/gfxoutputdrv/iffdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/iffdrv.c @@ -44,20 +44,20 @@ typedef struct gfxoutputdrv_data_s { FILE *fd; char *ext_filename; - BYTE *data; - BYTE *iff_data; + uint8_t *data; + uint8_t *iff_data; unsigned int line; int iff_rowbytes; } gfxoutputdrv_data_t; -STATIC_PROTOTYPE gfxoutputdrv_t iff_drv; +static gfxoutputdrv_t iff_drv; -static BYTE powers[8]= { 1,2,4,8,16,32,64,128 }; +static uint8_t powers[8]= { 1, 2, 4, 8, 16, 32, 64, 128 }; static int iffdrv_write_file_header(screenshot_t *screenshot) { gfxoutputdrv_data_t *sdata; - BYTE header[836]; + uint8_t header[836]; int i; int totalsize; @@ -83,11 +83,11 @@ static int iffdrv_write_file_header(screenshot_t *screenshot) header[14] = 'H'; header[15] = 'D'; util_dword_to_be_buf(&header[16], 20); - util_word_to_be_buf(&header[20], (WORD)(screenshot->width)); - util_word_to_be_buf(&header[22], (WORD)(screenshot->height)); + util_word_to_be_buf(&header[20], (uint16_t)(screenshot->width)); + util_word_to_be_buf(&header[22], (uint16_t)(screenshot->height)); header[28] = 8; - util_word_to_be_buf(&header[36], (WORD)(screenshot->width)); - util_word_to_be_buf(&header[38], (WORD)(screenshot->height)); + util_word_to_be_buf(&header[36], (uint16_t)(screenshot->width)); + util_word_to_be_buf(&header[38], (uint16_t)(screenshot->height)); header[40] = 'C'; header[41] = 'M'; header[42] = 'A'; @@ -151,7 +151,7 @@ static int iffdrv_open(screenshot_t *screenshot, const char *filename) return 0; } -static void iff_c2p(BYTE *chunky, BYTE *planar, int amount, int plane) +static void iff_c2p(uint8_t *chunky, uint8_t *planar, int amount, int plane) { int i; @@ -220,7 +220,7 @@ static int iffdrv_save(screenshot_t *screenshot, const char *filename) #ifdef FEATURE_CPUMEMHISTORY static FILE *iffdrv_memmap_fd; static char *iffdrv_memmap_ext_filename; -static BYTE *iffdrv_memmap_iff_data; +static uint8_t *iffdrv_memmap_iff_data; static int iffdrv_memmap_iff_rowbytes; static int iffdrv_close_memmap(void) @@ -232,7 +232,7 @@ static int iffdrv_close_memmap(void) return 0; } -static int iffdrv_write_memmap(int line, int x_size, BYTE *gfx) +static int iffdrv_write_memmap(int line, int x_size, uint8_t *gfx) { int j; @@ -245,9 +245,9 @@ static int iffdrv_write_memmap(int line, int x_size, BYTE *gfx) return 0; } -static int iffdrv_write_file_header_memmap(int x_size, int y_size, BYTE *palette) +static int iffdrv_write_file_header_memmap(int x_size, int y_size, uint8_t *palette) { - BYTE header[836]; + uint8_t header[836]; int i; int totalsize; @@ -271,11 +271,11 @@ static int iffdrv_write_file_header_memmap(int x_size, int y_size, BYTE *palette header[14] = 'H'; header[15] = 'D'; util_dword_to_be_buf(&header[16], 20); - util_word_to_be_buf(&header[20], (WORD)(x_size)); - util_word_to_be_buf(&header[22], (WORD)(y_size)); + util_word_to_be_buf(&header[20], (uint16_t)(x_size)); + util_word_to_be_buf(&header[22], (uint16_t)(y_size)); header[28] = 8; - util_word_to_be_buf(&header[36], (WORD)(x_size)); - util_word_to_be_buf(&header[38], (WORD)(y_size)); + util_word_to_be_buf(&header[36], (uint16_t)(x_size)); + util_word_to_be_buf(&header[38], (uint16_t)(y_size)); header[40] = 'C'; header[41] = 'M'; header[42] = 'A'; @@ -305,7 +305,7 @@ static int iffdrv_write_file_header_memmap(int x_size, int y_size, BYTE *palette return 0; } -static int iffdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE *palette) +static int iffdrv_open_memmap(const char *filename, int x_size, int y_size, uint8_t *palette) { iffdrv_memmap_ext_filename = util_add_extension_const(filename, iff_drv.default_extension); iffdrv_memmap_fd = fopen(iffdrv_memmap_ext_filename, "wb"); @@ -326,7 +326,7 @@ static int iffdrv_open_memmap(const char *filename, int x_size, int y_size, BYTE return 0; } -static int iffdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE *gfx, BYTE *palette) +static int iffdrv_save_memmap(const char *filename, int x_size, int y_size, uint8_t *gfx, uint8_t *palette) { int line; @@ -348,6 +348,7 @@ static int iffdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE static gfxoutputdrv_t iff_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, "IFF", "IFF screenshot", "iff", diff --git a/src/Emulators/vice/gfxoutputdrv/iffdrv.h b/src/Emulators/vice/gfxoutputdrv/iffdrv.h index 1d2b217a..32c2981e 100644 --- a/src/Emulators/vice/gfxoutputdrv/iffdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/iffdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_IFFDRV_H #define VICE_IFFDRV_H -extern void gfxoutput_init_iff(int help); +void gfxoutput_init_iff(int help); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/jpegdrv.c b/src/Emulators/vice/gfxoutputdrv/jpegdrv.c index dc2f0eb5..328c77d8 100644 --- a/src/Emulators/vice/gfxoutputdrv/jpegdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/jpegdrv.c @@ -215,6 +215,7 @@ static int jpegdrv_save_memmap(const char *filename, int x_size, int y_size, BYT static gfxoutputdrv_t jpeg_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, /* VICE 3.10: new leading type field */ "JPEG", "JPEG screenshot", "jpg", @@ -233,7 +234,7 @@ static gfxoutputdrv_t jpeg_drv = #endif }; -void gfxoutput_init_jpeg(void) +void gfxoutput_init_jpeg(int help) /* VICE 3.10: + help arg (unused here, matches other drivers) */ { gfxoutput_register(&jpeg_drv); } diff --git a/src/Emulators/vice/gfxoutputdrv/jpegdrv.h b/src/Emulators/vice/gfxoutputdrv/jpegdrv.h index 8a40610a..78d3f79d 100644 --- a/src/Emulators/vice/gfxoutputdrv/jpegdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/jpegdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_JPEGDRV_H #define VICE_JPEGDRV_H -extern void gfxoutput_init_jpeg(void); +extern void gfxoutput_init_jpeg(int help); /* VICE 3.10: + help arg */ #endif diff --git a/src/Emulators/vice/gfxoutputdrv/koaladrv.c b/src/Emulators/vice/gfxoutputdrv/koaladrv.c index 83f97c9c..fa014d0c 100644 --- a/src/Emulators/vice/gfxoutputdrv/koaladrv.c +++ b/src/Emulators/vice/gfxoutputdrv/koaladrv.c @@ -3,6 +3,7 @@ * * Written by * Marco van den Heuvel + * groepaz * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -41,24 +42,15 @@ #include "palette.h" #include "resources.h" #include "screenshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" #include "vsync.h" /* TODO: - * - add VICII FLI / mixed mode handling - * - add VICII super hires handling - * - add VICII super hires FLI handling - * - add VDC text mode - * - add VDC bitmap mode - * - add TED FLI / mixed mode handling - * - add TED multi-color text mode - * - add VIC mixed mode handling - * - add possible CRTC mixed mode handling - * - add C64DTV specific modes handling - */ + + when all is done, remove #if 0'ed code +*/ #define KOALA_SCREEN_PIXEL_WIDTH 320 #define KOALA_SCREEN_PIXEL_HEIGHT 200 @@ -71,17 +63,19 @@ #define SCREENRAM_OFFSET 8002 #define VIDEORAM_OFFSET 9002 #define BGCOLOR_OFFSET 10002 +#define KOALA_SIZE 10003 -STATIC_PROTOTYPE gfxoutputdrv_t koala_drv; -STATIC_PROTOTYPE gfxoutputdrv_t koala_compressed_drv; +static gfxoutputdrv_t koala_drv; /* ------------------------------------------------------------------------ */ static int oversize_handling; static int undersize_handling; static int ted_lum_handling; +#if 0 static int crtc_text_color; -static BYTE crtc_fgcolor; +static uint8_t crtc_fgcolor; +#endif static int set_oversize_handling(int val, void *param) { @@ -136,6 +130,7 @@ static int set_ted_lum_handling(int val, void *param) return 0; } +#if 0 static int set_crtc_text_color(int val, void *param) { switch (val) { @@ -156,26 +151,29 @@ static int set_crtc_text_color(int val, void *param) return 0; } +#endif static const resource_int_t resources_int[] = { { "KoalaOversizeHandling", NATIVE_SS_OVERSIZE_SCALE, RES_EVENT_NO, NULL, &oversize_handling, set_oversize_handling, NULL }, - { "KoalaUndersizeHandling", NATIVE_SS_UNDERSIZE_SCALE, RES_EVENT_NO, NULL, + { "KoalaUndersizeHandling", NATIVE_SS_UNDERSIZE_BORDERIZE, RES_EVENT_NO, NULL, &undersize_handling, set_undersize_handling, NULL }, RESOURCE_INT_LIST_END }; static const resource_int_t resources_int_plus4[] = { - { "KoalaTEDLumHandling", NATIVE_SS_TED_LUM_IGNORE, RES_EVENT_NO, NULL, + { "KoalaTEDLumHandling", NATIVE_SS_TED_LUM_DITHER, RES_EVENT_NO, NULL, &ted_lum_handling, set_ted_lum_handling, NULL }, RESOURCE_INT_LIST_END }; +#if 0 static const resource_int_t resources_int_crtc[] = { { "KoalaCRTCTextColor", NATIVE_SS_CRTC_WHITE, RES_EVENT_NO, NULL, &crtc_text_color, set_crtc_text_color, NULL }, RESOURCE_INT_LIST_END }; +#endif static int koaladrv_resources_init(void) { @@ -184,47 +182,49 @@ static int koaladrv_resources_init(void) return -1; } } - +#if 0 if (machine_class == VICE_MACHINE_CBM6x0 || machine_class == VICE_MACHINE_PET) { if (resources_register_int(resources_int_crtc) < 0) { return -1; } } - +#endif return resources_register_int(resources_int); } -static const cmdline_option_t cmdline_options[] = { - { "-koalaoversize", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options[] = +{ + { "-koalaoversize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KoalaOversizeHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_OVERSIZED_HANDLING, - NULL, NULL }, - { "-koalaundersize", SET_RESOURCE, 1, + "", "Select the way the oversized input should be handled," + " (0: scale down, 1: crop left top, 2: crop center top, 3: crop right top," + " 4: crop left center, 5: crop center, 6: crop right center, 7: crop left bottom," + " 8: crop center bottom, 9: crop right bottom)" }, + { "-koalaundersize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KoalaUndersizeHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_UNDERSIZED_HANDLING, - NULL, NULL }, + "", "Select the way the undersized input should be handled," + " (0: scale up, 1: borderize)" }, CMDLINE_LIST_END }; -static const cmdline_option_t cmdline_options_plus4[] = { - { "-koalatedlum", SET_RESOURCE, 1, +static const cmdline_option_t cmdline_options_plus4[] = +{ + { "-koalatedlum", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KoalaTEDLumHandling", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_METHOD, IDCLS_TED_LUM_HANDLING, - NULL, NULL }, + "", "Select the way the TED luminosity should be handled," + " (0: ignore, 1: dither)" }, CMDLINE_LIST_END }; -static const cmdline_option_t cmdline_options_crtc[] = { - { "-koalacrtctextcolor", SET_RESOURCE, 1, +#if 0 +static const cmdline_option_t cmdline_options_crtc[] = +{ + { "-koalacrtctextcolor", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, NULL, NULL, "KoalaCRTCTextColor", NULL, - USE_PARAM_ID, USE_DESCRIPTION_ID, - IDCLS_P_COLOR, IDCLS_CRTC_TEXT_COLOR, - NULL, NULL }, + "", "Select the CRTC text color (0: white, 1: amber, 2: green)" }, CMDLINE_LIST_END }; +#endif static int koaladrv_cmdline_options_init(void) { @@ -233,300 +233,221 @@ static int koaladrv_cmdline_options_init(void) return -1; } } - +#if 0 if (machine_class == VICE_MACHINE_CBM6x0 || machine_class == VICE_MACHINE_PET) { if (cmdline_register_options(cmdline_options_crtc) < 0) { return -1; } } - +#endif return cmdline_register_options(cmdline_options); } /* ------------------------------------------------------------------------ */ +/* make all pixels double pixels */ static void koala_multicolorize_colormap(native_data_t *source) { int i, j; for (i = 0; i < KOALA_SCREEN_PIXEL_HEIGHT; i++) { for (j = 0; j < (KOALA_SCREEN_PIXEL_WIDTH / 2); j++) { - source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH) + (j * 2) + 1] = source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH) + (j * 2)]; + source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH) + (j * 2) + 1] = + source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH) + (j * 2)]; } } } -static void koala_check_and_correct_cell(native_data_t *source, BYTE bgcolor) +/* find the best background color. for this we pick the color that appears + most often in blocks that contain 4, or more, colors */ +static uint8_t koala_find_bgcolor(native_data_t *source) { native_data_t *dest = lib_malloc(sizeof(native_data_t)); - int i, j, k, l, bgcolor_included; - native_color_sort_t *colors = NULL; + native_color_sort_t *blockcolors = NULL; + native_color_sort_t bgcolors[16]; + int i, j, k, l, c; + uint8_t bgcolor, amount; + /* color map for one block */ dest->xsize = 8; dest->ysize = 8; dest->colormap = lib_malloc(8 * 8); + for (c = 0; c < 16; c++) { + bgcolors[c].amount = 0; + bgcolors[c].color = c; + } + for (i = 0; i < KOALA_SCREEN_BYTE_HEIGHT; i++) { for (j = 0; j < KOALA_SCREEN_BYTE_WIDTH; j++) { + /* get block */ for (k = 0; k < 8; k++) { for (l = 0; l < 8; l++) { - dest->colormap[(k * 8) + l] = source->colormap[(i * 8 * KOALA_SCREEN_PIXEL_WIDTH) + (j * 8) + (k * KOALA_SCREEN_PIXEL_WIDTH) + l]; - } - } - colors = native_sort_colors_colormap(dest, 16); - bgcolor_included = 0; - for (l = 0; l < 4; l++) { - if (colors[l].amount != 0 && colors[l].color == bgcolor) { - bgcolor_included = 1; + dest->colormap[(k * 8) + l] = + source->colormap[(i * 8 * KOALA_SCREEN_PIXEL_WIDTH) + (j * 8) + + (k * KOALA_SCREEN_PIXEL_WIDTH) + l]; } } - if (bgcolor_included == 0) { - colors[3].amount = colors[2].amount; - colors[3].color = colors[2].color; - colors[2].amount = colors[1].amount; - colors[2].color = colors[1].color; - colors[1].amount = colors[0].amount; - colors[1].color = colors[0].color; - colors[0].amount = 8000; - colors[0].color = bgcolor; - } - if (colors[4].amount != 0) { - colors[4].color = 255; - vicii_color_to_nearest_vicii_color_colormap(dest, colors); - for (k = 0; k < 8; k++) { - for (l = 0; l < 8; l++) { - source->colormap[(i * 8 * KOALA_SCREEN_PIXEL_WIDTH) + (j * 8) + (k * KOALA_SCREEN_PIXEL_WIDTH) + l] = dest->colormap[(k * 8) + l]; + blockcolors = native_sort_colors_colormap(dest, 16); + if (blockcolors[3].amount != 0) { + /* 4 or more colors in this block, add them to the pool of + colors we pick the background color from */ + for (c = 0; c < 16; c++) { + if (blockcolors[c].amount != 0) { + bgcolors[blockcolors[c].color].amount++; } } } - lib_free(colors); + lib_free(blockcolors); + } + } + + /* pick the most used color from the pool */ + amount = bgcolors[0].amount; + bgcolor = 0; + for (c = 1; c < 16; c++) { + if (amount < bgcolors[c].amount) { + amount = bgcolors[c].amount; + bgcolor = c; } } + lib_free(dest->colormap); lib_free(dest); + return bgcolor; } -static int koala_render_and_save(native_data_t *source, int compress) +/* fix/re-render the picture according to the multicolor restrictions, one + common background color, plus 3 colors per block */ +static void koala_check_and_correct_cell(native_data_t *source, uint8_t bgcolor) { - FILE *fd; - char *filename_ext = NULL; - BYTE *filebuffer = NULL; - BYTE *result = NULL; + native_data_t *dest = lib_malloc(sizeof(native_data_t)); int i, j, k, l; - int m = 0; - int n = 0; - int retval = 0; - BYTE color1 = 255; - BYTE color2 = 255; - BYTE color3 = 255; - BYTE colorbyte; - BYTE bgcolor; - native_color_sort_t *color_order = NULL; - - /* allocate file buffer */ - filebuffer = lib_malloc(10003); - - /* clear filebuffer */ - memset(filebuffer, 0, 10003); - - /* set load addy */ - filebuffer[0] = 0x00; - filebuffer[1] = 0x60; - - /* make multicolor */ - koala_multicolorize_colormap(source); - - /* find out bgcolor */ - color_order = native_sort_colors_colormap(source, 16); - bgcolor = color_order[0].color; - lib_free(color_order); + native_color_sort_t *colors = NULL; + native_color_sort_t cellcolors[16]; - /* check and correct cells */ - koala_check_and_correct_cell(source, bgcolor); + dest->xsize = 8; + dest->ysize = 8; + dest->colormap = lib_malloc(8 * 8); for (i = 0; i < KOALA_SCREEN_BYTE_HEIGHT; i++) { for (j = 0; j < KOALA_SCREEN_BYTE_WIDTH; j++) { + /* get block */ for (k = 0; k < 8; k++) { - filebuffer[BITMAP_OFFSET + m] = 0; - for (l = 0; l < 4; l++) { - colorbyte = source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH * 8) + (j * 8) + (k * KOALA_SCREEN_PIXEL_WIDTH) + (l * 2)]; - if (k == 0 && l == 0) { - color1 = 255; - color2 = 255; - color3 = 255; - } - if (colorbyte != bgcolor) { - if (color1 == 255) { - color1 = colorbyte; - } else { - if (color1 != colorbyte && color2 == 255) { - color2 = colorbyte; - } else { - if (color2 != colorbyte && color3 == 255) { - color3 = colorbyte; - } - } - } - } - if (colorbyte != bgcolor) { - if (colorbyte == color1) { - filebuffer[BITMAP_OFFSET + m] |= (1 << ((3 - l) * 2)); - } - if (colorbyte == color2) { - filebuffer[BITMAP_OFFSET + m] |= (2 << ((3 - l) * 2)); - } else { - filebuffer[BITMAP_OFFSET + m] |= (3 << ((3 - l) * 2)); - } - } + for (l = 0; l < 8; l++) { + dest->colormap[(k * 8) + l] = + source->colormap[(i * 8 * KOALA_SCREEN_PIXEL_WIDTH) + (j * 8) + + (k * KOALA_SCREEN_PIXEL_WIDTH) + l]; } - m++; } - filebuffer[SCREENRAM_OFFSET + n] = ((color1 & 0xf) << 4) | (color2 & 0xf); - filebuffer[VIDEORAM_OFFSET + n++] = color3 & 0xf; - } - } - filebuffer[BGCOLOR_OFFSET] = bgcolor; - - if (compress) { - filename_ext = util_add_extension_const(source->filename, koala_compressed_drv.default_extension); - } else { - filename_ext = util_add_extension_const(source->filename, koala_drv.default_extension); - } - - fd = fopen(filename_ext, MODE_WRITE); - if (fd == NULL) { - retval = -1; - } - - if (retval != -1) { - if (compress) { - result = lib_malloc(10003 * 4); - j = 0; - i = 2; - result[j++] = 0; - result[j++] = 0x60; - while (i < 9999) { - if (filebuffer[i] == filebuffer[i + 1] && filebuffer[i] == filebuffer[i + 2] && filebuffer[i] == filebuffer[i + 3]) { - result[j++] = 0xFE; - result[j] = filebuffer[i]; - k = 4; - i += 4; - while (k != 0xFF && i < 10003 && result[j] == filebuffer[i]) { - i++; - k++; - } - j++; - result[j++] = k; - } else { - if (filebuffer[i] == 0xFE) { - result[j++] = 0xFE; - result[j++] = 0xFE; - result[j++] = 0x01; - i++; - } else { - result[j++] = filebuffer[i++]; - } + colors = native_sort_colors_colormap(dest, 16); + /* the first color is expected to be the background color in the + next step. so put it first, followed by the other colors */ + cellcolors[0].amount = 8000; + cellcolors[0].color = bgcolor; + for (l = 0, k = 1; l < 16; l++) { + if (colors[l].color != bgcolor) { + cellcolors[k].color = colors[l].color; + cellcolors[k].amount = colors[l].amount; + k++; } } - while (i < 10003) { - result[j++] = filebuffer[i++]; - } - if (fwrite(result, j, 1, fd) < 1) { - retval = -1; - } - } else { - if (fwrite(filebuffer, 10003, 1, fd) < 1) { - retval = -1; + /* re-render the block using the background color and the 3 most + used color in that block */ + cellcolors[4].color = 255; /* mark end of list */ + vicii_color_to_nearest_vicii_color_colormap(dest, cellcolors); + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + source->colormap[(i * 8 * KOALA_SCREEN_PIXEL_WIDTH) + (j * 8) + + (k * KOALA_SCREEN_PIXEL_WIDTH) + l] = + dest->colormap[(k * 8) + l]; + } } + lib_free(colors); } } - - if (fd != NULL) { - fclose(fd); - } - - lib_free(source->colormap); - lib_free(source); - lib_free(filename_ext); - lib_free(filebuffer); - lib_free(result); - - return retval; + lib_free(dest->colormap); + lib_free(dest); } -static int koala_direct_save(native_data_t *source, int compress, BYTE bgcolor) +static int koala_render_and_save(native_data_t *source) { FILE *fd; char *filename_ext = NULL; - BYTE *filebuffer = NULL; - BYTE *result = NULL; + uint8_t *filebuffer = NULL; + uint8_t *result = NULL; int i, j, k, l; int m = 0; int n = 0; int retval = 0; - BYTE color1 = 255; - BYTE color2 = 255; - BYTE color3 = 255; - BYTE colorbyte; + uint8_t color1; + uint8_t color2; + uint8_t color3; + uint8_t colorbyte; + uint8_t bgcolor; + uint8_t gfxbits; /* allocate file buffer */ - filebuffer = lib_malloc(10003); + filebuffer = lib_malloc(KOALA_SIZE); /* clear filebuffer */ - memset(filebuffer, 0, 10003); + memset(filebuffer, 0, KOALA_SIZE); /* set load addy */ filebuffer[0] = 0x00; filebuffer[1] = 0x60; + /* make all pixels multicolor */ + koala_multicolorize_colormap(source); + + /* find out bgcolor */ + bgcolor = koala_find_bgcolor(source); + + /* check and correct cells */ + koala_check_and_correct_cell(source, bgcolor); + for (i = 0; i < KOALA_SCREEN_BYTE_HEIGHT; i++) { for (j = 0; j < KOALA_SCREEN_BYTE_WIDTH; j++) { + /* one block */ + color1 = color2 = color3 = 255; for (k = 0; k < 8; k++) { - filebuffer[BITMAP_OFFSET + m] = 0; + gfxbits = 0; for (l = 0; l < 4; l++) { - colorbyte = source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH * 8) + (j * 8) + (k * KOALA_SCREEN_PIXEL_WIDTH) + (l * 2)]; - if (k == 0 && l == 0) { - color1 = 255; - color2 = 255; - color3 = 255; - } + gfxbits <<= 2; + colorbyte = source->colormap[(i * KOALA_SCREEN_PIXEL_WIDTH * 8) + (j * 8) + + (k * KOALA_SCREEN_PIXEL_WIDTH) + (l * 2)]; + /* remember the used colors in this block. so we can assign + the bits */ if (colorbyte != bgcolor) { if (color1 == 255) { color1 = colorbyte; - } else { - if (color1 != colorbyte && color2 == 255) { - color2 = colorbyte; - } else { - if (color2 != colorbyte && color3 == 255) { - color3 = colorbyte; - } - } + } else if ((color1 != colorbyte) && (color2 == 255)) { + color2 = colorbyte; + } else if ((color1 != colorbyte) && (color2 != colorbyte) && (color3 == 255)) { + color3 = colorbyte; } } - if (colorbyte != bgcolor) { - if (colorbyte == color1) { - filebuffer[BITMAP_OFFSET + m] |= (1 << ((3 - l) * 2)); - } - if (colorbyte == color2) { - filebuffer[BITMAP_OFFSET + m] |= (2 << ((3 - l) * 2)); - } else { - filebuffer[BITMAP_OFFSET + m] |= (3 << ((3 - l) * 2)); - } + /* assign the bits */ + if (colorbyte == color1) { + gfxbits |= 1; + } else if (colorbyte == color2) { + gfxbits |= 2; + } else if (colorbyte == color3) { + gfxbits |= 3; } } + filebuffer[BITMAP_OFFSET + m] = gfxbits; m++; } + /* put the colors into video ram and color ram buffers */ filebuffer[SCREENRAM_OFFSET + n] = ((color1 & 0xf) << 4) | (color2 & 0xf); - filebuffer[VIDEORAM_OFFSET + n++] = color3 & 0xf; + filebuffer[VIDEORAM_OFFSET + n] = color3 & 0xf; + n++; } } filebuffer[BGCOLOR_OFFSET] = bgcolor; - if (compress) { - filename_ext = util_add_extension_const(source->filename, koala_compressed_drv.default_extension); - } else { - filename_ext = util_add_extension_const(source->filename, koala_drv.default_extension); - } + filename_ext = util_add_extension_const(source->filename, koala_drv.default_extension); fd = fopen(filename_ext, MODE_WRITE); if (fd == NULL) { @@ -534,45 +455,8 @@ static int koala_direct_save(native_data_t *source, int compress, BYTE bgcolor) } if (retval != -1) { - if (compress) { - result = lib_malloc(10003 * 4); - j = 0; - i = 2; - result[j++] = 0; - result[j++] = 0x60; - while (i < 9999) { - if (filebuffer[i] == filebuffer[i + 1] && filebuffer[i] == filebuffer[i + 2] && filebuffer[i] == filebuffer[i + 3]) { - result[j++] = 0xFE; - result[j] = filebuffer[i]; - k = 4; - i += 4; - while (k != 0xFF && i < 10003 && result[j] == filebuffer[i]) { - i++; - k++; - } - j++; - result[j++] = k; - } else { - if (filebuffer[i] == 0xFE) { - result[j++] = 0xFE; - result[j++] = 0xFE; - result[j++] = 0x01; - i++; - } else { - result[j++] = filebuffer[i++]; - } - } - } - while (i < 10003) { - result[j++] = filebuffer[i++]; - } - if (fwrite(result, j, 1, fd) < 1) { - retval = -1; - } - } else { - if (fwrite(filebuffer, 10003, 1, fd) < 1) { - retval = -1; - } + if (fwrite(filebuffer, KOALA_SIZE, 1, fd) < 1) { + retval = -1; } } @@ -591,14 +475,15 @@ static int koala_direct_save(native_data_t *source, int compress, BYTE bgcolor) /* ------------------------------------------------------------------------ */ -static int koala_vicii_save(screenshot_t *screenshot, const char *filename, int compress) +static int koala_vicii_save(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE mc; - BYTE eb; - BYTE bm; - BYTE blank; native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; + uint8_t mc; + uint8_t eb; + uint8_t bm; + uint8_t blank; mc = (regs[0x16] & 0x10) >> 4; eb = (regs[0x11] & 0x40) >> 6; @@ -614,41 +499,42 @@ static int koala_vicii_save(screenshot_t *screenshot, const char *filename, int switch (mc << 2 | eb << 1 | bm) { case 0: /* normal text mode */ data = native_vicii_text_mode_render(screenshot, filename); - return koala_render_and_save(data, compress); break; case 1: /* hires bitmap mode */ data = native_vicii_hires_bitmap_mode_render(screenshot, filename); - return koala_render_and_save(data, compress); break; case 2: /* extended background mode */ data = native_vicii_extended_background_mode_render(screenshot, filename); - return koala_render_and_save(data, compress); break; case 4: /* multicolor text mode */ data = native_vicii_multicolor_text_mode_render(screenshot, filename); - return koala_render_and_save(data, compress); break; case 5: /* multicolor bitmap mode */ data = native_vicii_multicolor_bitmap_mode_render(screenshot, filename); - return koala_direct_save(data, compress, (BYTE)(regs[0x21] & 0xf)); break; default: /* illegal modes (3, 6 and 7) */ ui_error("Illegal mode, no saving will be done"); return -1; break; } - return 0; +#endif + data = native_vicii_render(screenshot, filename); + if (data == NULL) { + return -1; + } + return koala_render_and_save(data); } /* ------------------------------------------------------------------------ */ -static int koala_ted_save(screenshot_t *screenshot, const char *filename, int compress) +static int koala_ted_save(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE mc; - BYTE eb; - BYTE bm; native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; + uint8_t mc; + uint8_t eb; + uint8_t bm; mc = (regs[0x07] & 0x10) >> 4; eb = (regs[0x06] & 0x40) >> 6; @@ -657,18 +543,12 @@ static int koala_ted_save(screenshot_t *screenshot, const char *filename, int co switch (mc << 2 | eb << 1 | bm) { case 0: /* normal text mode */ data = native_ted_text_mode_render(screenshot, filename); - ted_color_to_vicii_color_colormap(data, ted_lum_handling); - return koala_render_and_save(data, compress); break; case 1: /* hires bitmap mode */ data = native_ted_hires_bitmap_mode_render(screenshot, filename); - ted_color_to_vicii_color_colormap(data, ted_lum_handling); - return koala_render_and_save(data, compress); break; case 2: /* extended background mode */ data = native_ted_extended_background_mode_render(screenshot, filename); - ted_color_to_vicii_color_colormap(data, ted_lum_handling); - return koala_render_and_save(data, compress); break; case 4: /* multicolor text mode */ ui_error("This screen saver is a WIP, it doesn't support multicolor text mode (yet)"); @@ -676,23 +556,28 @@ static int koala_ted_save(screenshot_t *screenshot, const char *filename, int co break; case 5: /* multicolor bitmap mode */ data = native_ted_multicolor_bitmap_mode_render(screenshot, filename); - ted_color_to_vicii_color_colormap(data, ted_lum_handling); - return koala_render_and_save(data, compress); break; default: /* illegal modes (3, 6 and 7) */ ui_error("Illegal mode, no saving will be done"); return -1; break; } - return 0; +#endif + data = native_ted_render(screenshot, filename); + if (data == NULL) { + return -1; + } + ted_color_to_vicii_color_colormap(data, ted_lum_handling); + return koala_render_and_save(data); } /* ------------------------------------------------------------------------ */ -static int koala_vic_save(screenshot_t *screenshot, const char *filename, int compress) +static int koala_vic_save(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; + uint8_t *regs = screenshot->video_regs; native_data_t *data = native_vic_render(screenshot, filename); + uint8_t bordercolor = regs[0xf] & 7; if (data == NULL) { return -1; @@ -700,45 +585,55 @@ static int koala_vic_save(screenshot_t *screenshot, const char *filename, int co vic_color_to_vicii_color_colormap(data); - if (data->xsize != KOALA_SCREEN_PIXEL_WIDTH || data->ysize != KOALA_SCREEN_PIXEL_HEIGHT) { - data = native_resize_colormap(data, KOALA_SCREEN_PIXEL_WIDTH, KOALA_SCREEN_PIXEL_HEIGHT, (BYTE)(regs[0xf] & 7), oversize_handling, undersize_handling); + if ((data->xsize != KOALA_SCREEN_PIXEL_WIDTH) || (data->ysize != KOALA_SCREEN_PIXEL_HEIGHT)) { + data = native_resize_colormap(data, KOALA_SCREEN_PIXEL_WIDTH, KOALA_SCREEN_PIXEL_HEIGHT, + bordercolor, oversize_handling, undersize_handling); } - return koala_render_and_save(data, compress); + return koala_render_and_save(data); } /* ------------------------------------------------------------------------ */ -static int koala_crtc_save(screenshot_t *screenshot, const char *filename, int compress) +static int koala_crtc_save(screenshot_t *screenshot, const char *filename) { - native_data_t *data = native_crtc_render(screenshot, filename, crtc_fgcolor); - + native_data_t *data = native_crtc_render(screenshot, filename); if (data == NULL) { return -1; } if (data->xsize != KOALA_SCREEN_PIXEL_WIDTH || data->ysize != KOALA_SCREEN_PIXEL_HEIGHT) { - data = native_resize_colormap(data, KOALA_SCREEN_PIXEL_WIDTH, KOALA_SCREEN_PIXEL_HEIGHT, 0, oversize_handling, undersize_handling); + data = native_resize_colormap(data, KOALA_SCREEN_PIXEL_WIDTH, KOALA_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); } - return koala_render_and_save(data, compress); + return koala_render_and_save(data); } /* ------------------------------------------------------------------------ */ -static int koala_vdc_save(screenshot_t *screenshot, const char *filename, int compress) +static int koala_vdc_save(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; native_data_t *data = NULL; +#if 0 + uint8_t *regs = screenshot->video_regs; if (regs[25] & 0x80) { ui_error("VDC bitmap mode screenshot saving not implemented yet"); return -1; - } else { - data = native_vdc_text_mode_render(screenshot, filename); - vdc_color_to_vicii_color_colormap(data); - return koala_render_and_save(data, compress); } - return -1; + data = native_vdc_text_mode_render(screenshot, filename); +#endif + data = native_vdc_render(screenshot, filename); + if (data == NULL) { + return -1; + } + + vdc_color_to_vicii_color_colormap(data); + if (data->xsize != KOALA_SCREEN_PIXEL_WIDTH || data->ysize != KOALA_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, KOALA_SCREEN_PIXEL_WIDTH, KOALA_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); + } + return koala_render_and_save(data); } /* ------------------------------------------------------------------------ */ @@ -746,40 +641,19 @@ static int koala_vdc_save(screenshot_t *screenshot, const char *filename, int co static int koaladrv_save(screenshot_t *screenshot, const char *filename) { if (!(strcmp(screenshot->chipid, "VICII"))) { - return koala_vicii_save(screenshot, filename, 0); - } - if (!(strcmp(screenshot->chipid, "VDC"))) { - return koala_vdc_save(screenshot, filename, 0); - } - if (!(strcmp(screenshot->chipid, "CRTC"))) { - return koala_crtc_save(screenshot, filename, 0); - } - if (!(strcmp(screenshot->chipid, "TED"))) { - return koala_ted_save(screenshot, filename, 0); - } - if (!(strcmp(screenshot->chipid, "VIC"))) { - return koala_vic_save(screenshot, filename, 0); - } - ui_error("Unknown graphics chip"); - return -1; -} - -static int koaladrv_compressed_save(screenshot_t *screenshot, const char *filename) -{ - if (!(strcmp(screenshot->chipid, "VICII"))) { - return koala_vicii_save(screenshot, filename, 1); + return koala_vicii_save(screenshot, filename); } if (!(strcmp(screenshot->chipid, "VDC"))) { - return koala_vdc_save(screenshot, filename, 1); + return koala_vdc_save(screenshot, filename); } if (!(strcmp(screenshot->chipid, "CRTC"))) { - return koala_crtc_save(screenshot, filename, 1); + return koala_crtc_save(screenshot, filename); } if (!(strcmp(screenshot->chipid, "TED"))) { - return koala_ted_save(screenshot, filename, 1); + return koala_ted_save(screenshot, filename); } if (!(strcmp(screenshot->chipid, "VIC"))) { - return koala_vic_save(screenshot, filename, 1); + return koala_vic_save(screenshot, filename); } ui_error("Unknown graphics chip"); return -1; @@ -787,8 +661,9 @@ static int koaladrv_compressed_save(screenshot_t *screenshot, const char *filena static gfxoutputdrv_t koala_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, "KOALA", - "C64 koala screenshot", + "Koalapainter screenshot", "koa", NULL, /* formatlist */ NULL, @@ -805,28 +680,7 @@ static gfxoutputdrv_t koala_drv = #endif }; -static gfxoutputdrv_t koala_compressed_drv = -{ - "KOALA_COMPRESSED", - "C64 compressed koala screenshot", - "gg", - NULL, /* formatlist */ - NULL, - NULL, - NULL, - NULL, - koaladrv_compressed_save, - NULL, - NULL, - NULL, - NULL -#ifdef FEATURE_CPUMEMHISTORY - , NULL -#endif -}; - void gfxoutput_init_koala(int help) { gfxoutput_register(&koala_drv); - gfxoutput_register(&koala_compressed_drv); } diff --git a/src/Emulators/vice/gfxoutputdrv/minipaintdrv.c b/src/Emulators/vice/gfxoutputdrv/minipaintdrv.c new file mode 100644 index 00000000..bc647732 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/minipaintdrv.c @@ -0,0 +1,842 @@ +/* + * minipaintdrv.c - Create a vic20 minipaint type file. + * + * Written by + * groepaz + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#include "vice.h" + +#include +#include +#include + +#include "archdep.h" +#include "cmdline.h" +#include "lib.h" +#include "log.h" +#include "machine.h" +#include "mem.h" +#include "gfxoutput.h" +#include "nativedrv.h" +#include "palette.h" +#include "resources.h" +#include "screenshot.h" +#include "vicetypes.h" +#include "uiapi.h" +#include "util.h" +#include "vsync.h" + +/* #define DEBUGMINIPAINT */ + +#ifdef DEBUGMINIPAINT +#define DBG(_x_) printf _x_ +#else +#define DBG(_x_) +#endif + +/* + Minipaint format saver, this uses a standard vic20 screen with 16 pixel + high characters in the following configuration: + + 900f bit3 (inverted mode) = 1 (normal video) + + multicolor blocks: + + 00 bgcolor 900f bit 7-4 (colors 0...15) + 01 bordercolor 900f bit 2-0 (colors 0..7) + 10 charcolor cram bit 2-0 bit 3 = 1 (colors 0..7) + 11 auxcolor 900e bit 6-4 (colors 0...15) + + hires blocks: + + 0 bgcolor 900f bit 7-4 (colors 0...15) + 1 charcolor cram bit 2-0 bit 3 = 0 (colors 0..7) + + colors (all) (bg and aux only) + + 0 - black 8 - orange + 1 - white 9 - light orange + 2 - red 10 - pink + 3 - cyan 11 - light cyan + 4 - magenta 12 - light magenta + 5 - green 13 - light green + 6 - blue 14 - light blue + 7 - yellow 15 - light yellow + + TODO: + - hires blocks are not handled yet + - the algorithm for finding the best shared colors could be improved +*/ + +#define VIC_NUM_COLORS_BG_AUX 16 + +#define MINIPAINT_SCREEN_PIXEL_WIDTH 160 +#define MINIPAINT_SCREEN_PIXEL_HEIGHT 192 + +#define MINIPAINT_BLOCK_WIDTH 8 +#define MINIPAINT_BLOCK_HEIGHT 16 + +#define MINIPAINT_SCREEN_CHARS_WIDTH (MINIPAINT_SCREEN_PIXEL_WIDTH / MINIPAINT_BLOCK_WIDTH) +#define MINIPAINT_SCREEN_CHARS_HEIGHT (MINIPAINT_SCREEN_PIXEL_HEIGHT / MINIPAINT_BLOCK_HEIGHT) + +/* define offsets in the minipaint file */ +#define AUXCOLOR_OFFSET 15 +#define BGCOLOR_OFFSET 16 +#define BITMAP_OFFSET 17 +#define VIDEORAM_OFFSET 3857 +#define DISPLAYER_OFFSET 3977 +#define MINIPAINT_SIZE 4097 + +static gfxoutputdrv_t minipaint_drv; + +static unsigned char headerdata[17] = { + 0xf1, 0x10, 0x0c, 0x12, 0xd8, 0x07, 0x9e, 0x20, 0x38, 0x35, 0x38, 0x34, 0x00, 0x00, 0x00, 0x60, 0x0d +}; +static unsigned char displaycode[120] = { + 0x18, 0xA9, 0x10, 0xA8, 0x99, 0xF0, 0x0F, 0x69, 0x0C, 0x90, 0x02, 0xE9, 0xEF, 0xC8, 0xD0, 0xF4, + 0xA0, 0x05, 0x18, 0xB9, 0xE4, 0xED, 0x79, 0xFA, 0x21, 0x99, 0x00, 0x90, 0x88, 0x10, 0xF3, 0xAD, + 0x0E, 0x90, 0x29, 0x0F, 0x0D, 0x0E, 0x12, 0x8D, 0x0E, 0x90, 0xAD, 0x0F, 0x12, 0x8D, 0x0F, 0x90, + 0xA9, 0x10, 0x85, 0xFB, 0xA9, 0x12, 0x85, 0xFC, 0xA9, 0x00, 0x85, 0xFD, 0xA9, 0x11, 0x85, 0xFE, + 0xA2, 0x0F, 0xA0, 0x00, 0xB1, 0xFB, 0x91, 0xFD, 0xC8, 0xD0, 0xF9, 0xE6, 0xFC, 0xE6, 0xFE, 0xCA, + 0xD0, 0xF2, 0xA2, 0x00, 0xA0, 0x00, 0xBD, 0x10, 0x21, 0xE8, 0x99, 0x00, 0x94, 0xC8, 0x4A, 0x4A, + 0x4A, 0x4A, 0x99, 0x00, 0x94, 0xC8, 0xC0, 0xF0, 0xD0, 0xEC, 0x20, 0xE4, 0xFF, 0xF0, 0xFB, 0x4C, + 0x32, 0xFD, 0x02, 0xFE, 0xFE, 0xEB, 0x00, 0x0C +}; + +static unsigned char hiresmap[MINIPAINT_SCREEN_CHARS_HEIGHT][MINIPAINT_SCREEN_CHARS_WIDTH]; +static int containshires; + +/* ------------------------------------------------------------------------ */ + +static int oversize_handling; +static int undersize_handling; +static int ted_lum_handling; + +static int set_oversize_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_OVERSIZE_SCALE: + case NATIVE_SS_OVERSIZE_CROP_LEFT_TOP: + case NATIVE_SS_OVERSIZE_CROP_CENTER_TOP: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_TOP: + case NATIVE_SS_OVERSIZE_CROP_LEFT_CENTER: + case NATIVE_SS_OVERSIZE_CROP_CENTER: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_CENTER: + case NATIVE_SS_OVERSIZE_CROP_LEFT_BOTTOM: + case NATIVE_SS_OVERSIZE_CROP_CENTER_BOTTOM: + case NATIVE_SS_OVERSIZE_CROP_RIGHT_BOTTOM: + break; + default: + return -1; + } + + oversize_handling = val; + + return 0; +} + +static int set_undersize_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_UNDERSIZE_SCALE: + case NATIVE_SS_UNDERSIZE_BORDERIZE: + break; + default: + return -1; + } + + undersize_handling = val; + + return 0; +} + +static int set_ted_lum_handling(int val, void *param) +{ + switch (val) { + case NATIVE_SS_TED_LUM_IGNORE: + case NATIVE_SS_TED_LUM_DITHER: + break; + default: + return -1; + } + + ted_lum_handling = val; + + return 0; +} + +static const resource_int_t resources_int[] = { + { "MiniPaintOversizeHandling", NATIVE_SS_OVERSIZE_SCALE, RES_EVENT_NO, NULL, + &oversize_handling, set_oversize_handling, NULL }, + { "MiniPaintUndersizeHandling", NATIVE_SS_UNDERSIZE_BORDERIZE, RES_EVENT_NO, NULL, + &undersize_handling, set_undersize_handling, NULL }, + RESOURCE_INT_LIST_END +}; + +static const resource_int_t resources_int_plus4[] = { + { "MiniPaintTEDLumHandling", NATIVE_SS_TED_LUM_DITHER, RES_EVENT_NO, NULL, + &ted_lum_handling, set_ted_lum_handling, NULL }, + RESOURCE_INT_LIST_END +}; + +static int minipaintdrv_resources_init(void) +{ + if (machine_class == VICE_MACHINE_PLUS4) { + if (resources_register_int(resources_int_plus4) < 0) { + return -1; + } + } + return resources_register_int(resources_int); +} + +static const cmdline_option_t cmdline_options[] = +{ + { "-minipaintoversize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MiniPaintOversizeHandling", NULL, + "", "Select the way the oversized input should be handled," + " (0: scale down, 1: crop left top, 2: crop center top, 3: crop right top," + " 4: crop left center, 5: crop center, 6: crop right center, 7: crop left bottom," + " 8: crop center bottom, 9: crop right bottom)" }, + { "-minipaintundersize", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MiniPaintUndersizeHandling", NULL, + "", "Select the way the undersized input should be handled," + " (0: scale up, 1: borderize)" }, + CMDLINE_LIST_END +}; + +static const cmdline_option_t cmdline_options_plus4[] = +{ + { "-minipainttedlum", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS, + NULL, NULL, "MiniPaintTEDLumHandling", NULL, + "", "Select the way the TED luminosity should be handled," + " (0: ignore, 1: dither)" }, + CMDLINE_LIST_END +}; + +static int minipaintdrv_cmdline_options_init(void) +{ + if (machine_class == VICE_MACHINE_PLUS4) { + if (cmdline_register_options(cmdline_options_plus4) < 0) { + return -1; + } + } + return cmdline_register_options(cmdline_options); +} + +/* ------------------------------------------------------------------------ */ + +#define UNASSIGNED_COLOR 16 + +/* a block is considered a hires block if not all odd and even pixels are the + same color, we have exactly two colors in this block, and no color index + is > 7 */ +static void minipaint_find_hires_colors(native_data_t *source, uint8_t *bgcolor) +{ + native_data_t *dest = lib_malloc(sizeof(native_data_t)); + native_color_sort_t *blockcolors = NULL; + native_color_sort_t bgcolors[VIC_NUM_COLORS_BG_AUX]; + int screeny, screenx, blocky, blockx, c, c1, c2, ishires; + uint8_t amount; + + /* color map for one block */ + dest->xsize = MINIPAINT_BLOCK_WIDTH; + dest->ysize = MINIPAINT_BLOCK_HEIGHT; + dest->colormap = lib_malloc(MINIPAINT_BLOCK_WIDTH * MINIPAINT_BLOCK_HEIGHT); + + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + bgcolors[c].amount = 0; + bgcolors[c].color = c; + } + + for (screeny = 0; screeny < MINIPAINT_SCREEN_CHARS_HEIGHT; screeny++) { + for (screenx = 0; screenx < MINIPAINT_SCREEN_CHARS_WIDTH; screenx++) { + /* get block */ + for (blocky = 0; (blocky < MINIPAINT_BLOCK_HEIGHT); blocky++) { + for (blockx = 0; (blockx < MINIPAINT_BLOCK_WIDTH); blockx++) { + dest->colormap[(blocky * MINIPAINT_BLOCK_WIDTH) + blockx] = + source->colormap[(screeny * MINIPAINT_BLOCK_HEIGHT * MINIPAINT_SCREEN_PIXEL_WIDTH) + + (screenx * MINIPAINT_BLOCK_WIDTH) + + (blocky * MINIPAINT_SCREEN_PIXEL_WIDTH) + blockx]; + } + } + + /* check all pixels in the block, if we find an odd and even pixel + with different color, then this can be a hires block */ + ishires = 0; + for (blocky = 0; (blocky < MINIPAINT_BLOCK_HEIGHT) && (ishires == 0); blocky++) { + for (blockx = 0; (blockx < MINIPAINT_BLOCK_WIDTH) && (ishires == 0); blockx++) { + c1 = dest->colormap[(blocky * MINIPAINT_BLOCK_WIDTH) + blockx]; + blockx++; + c2 = dest->colormap[(blocky * MINIPAINT_BLOCK_WIDTH) + blockx]; + if (c1 != c2) { + ishires = 1; + } + } + } + + if (ishires) { + blockcolors = native_sort_colors_colormap(dest, VIC_NUM_COLORS_BG_AUX); + if ((blockcolors[1].amount > 0) && (blockcolors[2].amount == 0)) { + /* exactly two colors in this block */ + + /* if both colors are > 7, then this can not be a hires block */ + if (!((blockcolors[1].color > 7) && (blockcolors[0].color > 7))) { + containshires = 1; + hiresmap[screeny][screenx] = (blockcolors[1].color << 4) | blockcolors[0].color; + + /* add them to the pool of colors we pick the background color from */ + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + /* skip if the color was already assigned in a previous pass */ + if ((*bgcolor != UNASSIGNED_COLOR) && (blockcolors[c].color == *bgcolor)){ + continue; + } + if (blockcolors[c].amount != 0) { + bgcolors[blockcolors[c].color].amount++; + } + } + } + } + lib_free(blockcolors); + } + } + } + + /* pick the most used colors from the pool */ + if (*bgcolor == UNASSIGNED_COLOR) { + amount = 0; + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + if (amount < bgcolors[c].amount) { + amount = bgcolors[c].amount; + *bgcolor = c; + } else if ((amount == bgcolors[c].amount) && (c > *bgcolor)) { + /* if we find another color that has been used exactly + as often, prefer the color with higher color index - + this will pick colors > 7 for background in this case */ + *bgcolor = c; + } + } + if (*bgcolor != UNASSIGNED_COLOR) { + bgcolors[*bgcolor].amount = 0; + } + } + + DBG(("selected hires bg: %d\n", *bgcolor)); + + lib_free(dest->colormap); + lib_free(dest); +} + +/* find the best shared colors. for this we pick the colors that appear + most often in blocks that contain (pass), or more, colors */ +static void minipaint_find_shared_colors_pass(native_data_t *source, + uint8_t *bgcolor, uint8_t *auxcolor, uint8_t *bordercolor, int pass, int auxbg) +{ + native_data_t *dest = lib_malloc(sizeof(native_data_t)); + native_color_sort_t *blockcolors = NULL; + native_color_sort_t bgcolors[VIC_NUM_COLORS_BG_AUX]; + int i, j, k, l, c; + uint8_t amount; + + /* color map for one block */ + dest->xsize = MINIPAINT_BLOCK_WIDTH; + dest->ysize = MINIPAINT_BLOCK_HEIGHT; + dest->colormap = lib_malloc(MINIPAINT_BLOCK_WIDTH * MINIPAINT_BLOCK_HEIGHT); + + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + bgcolors[c].amount = 0; + bgcolors[c].color = c; + } + + for (i = 0; i < MINIPAINT_SCREEN_CHARS_HEIGHT; i++) { + for (j = 0; j < MINIPAINT_SCREEN_CHARS_WIDTH; j++) { + if (hiresmap[i][j] == 0) { + /* get block */ + for (k = 0; k < MINIPAINT_BLOCK_HEIGHT; k++) { + for (l = 0; l < MINIPAINT_BLOCK_WIDTH; l++) { + dest->colormap[(k * MINIPAINT_BLOCK_WIDTH) + l] = + source->colormap[(i * MINIPAINT_BLOCK_HEIGHT * MINIPAINT_SCREEN_PIXEL_WIDTH) + + (j * MINIPAINT_BLOCK_WIDTH) + + (k * MINIPAINT_SCREEN_PIXEL_WIDTH) + l]; + } + } + blockcolors = native_sort_colors_colormap(dest, VIC_NUM_COLORS_BG_AUX); + if (blockcolors[pass - 1].amount != 0) { + /* (pass-1) or more colors in this block, add them to the pool of + colors we pick the background color from */ + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + /* skip if the color was already assigned in a previous pass */ + if (((*bordercolor != UNASSIGNED_COLOR) && (blockcolors[c].color == *bordercolor)) || + ((*bgcolor != UNASSIGNED_COLOR) && (blockcolors[c].color == *bgcolor)) || + ((*auxcolor != UNASSIGNED_COLOR) && (blockcolors[c].color == *auxcolor))){ + continue; + } + /* if we are looking for an aux/bg color, skip if the color + index is less than 8 */ + if (auxbg && (blockcolors[c].color < 8)) { + continue; + } + if (blockcolors[c].amount != 0) { + bgcolors[blockcolors[c].color].amount++; + } + } + } + lib_free(blockcolors); + } + } + } +#ifdef DEBUGMINIPAINT + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + DBG(("%d col: %d amount :%d\n", c, bgcolors[c].color, bgcolors[c].amount)); + } +#endif + /* pick the most used colors from the pool */ + if (*bgcolor == UNASSIGNED_COLOR) { + amount = 0; + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + if (amount < bgcolors[c].amount) { + amount = bgcolors[c].amount; + *bgcolor = c; + } + } + if (*bgcolor != UNASSIGNED_COLOR) { + bgcolors[*bgcolor].amount = 0; + } + } + + if (*auxcolor == UNASSIGNED_COLOR) { + amount = 0; + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + if (amount < bgcolors[c].amount) { + amount = bgcolors[c].amount; + *auxcolor = c; + } + } + if (*auxcolor != UNASSIGNED_COLOR) { + bgcolors[*auxcolor].amount = 0; + } + } + + if (*bordercolor == UNASSIGNED_COLOR) { + amount = 0; + for (c = 0; c < VIC_NUM_COLORS_BG_AUX; c++) { + if (amount < bgcolors[c].amount) { + amount = bgcolors[c].amount; + *bordercolor = c; + } + } + if (*bordercolor != UNASSIGNED_COLOR) { + bgcolors[*bordercolor].amount = 0; + } + } + + DBG(("pass %d - border: %d bg: %d aux: %d\n", pass, *bordercolor, *bgcolor, *auxcolor)); + + lib_free(dest->colormap); + lib_free(dest); +} + +static void minipaint_find_shared_colors(native_data_t *source, uint8_t *bgcolor, uint8_t *auxcolor, uint8_t *bordercolor) +{ + uint8_t color0, color1, color2; + color0 = color1 = color2 = UNASSIGNED_COLOR; + + /* test for hires blocks and bg color */ + minipaint_find_hires_colors(source, &color0); + /* test blocks for colors > 8 first to find bg- and aux color */ + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 4, 1); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 3, 1); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 2, 1); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 1, 1); + /* now test all remaining colors */ + color2 = UNASSIGNED_COLOR; + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 4, 0); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 3, 0); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 2, 0); + minipaint_find_shared_colors_pass(source, &color0, &color1, &color2, 1, 0); + + *bgcolor = color0 & 0x0f; + *auxcolor = color1 & 0x0f; + *bordercolor = color2 & 0x07; +} + +/* fix/re-render the picture according to the multicolor restrictions, + (three shared colors, plus one colors per block) or in hires */ + +static void minipaint_check_and_correct_cell(native_data_t *source, uint8_t bgcolor, uint8_t auxcolor, uint8_t bordercolor) +{ + native_data_t *dest = lib_malloc(sizeof(native_data_t)); + int i, j, k, l; + native_color_sort_t *colors = NULL; + native_color_sort_t cellcolors[VIC_NUM_COLORS_BG_AUX]; + + dest->xsize = MINIPAINT_BLOCK_WIDTH; + dest->ysize = MINIPAINT_BLOCK_HEIGHT; + dest->colormap = lib_malloc(MINIPAINT_BLOCK_WIDTH * MINIPAINT_BLOCK_HEIGHT); + + for (i = 0; i < MINIPAINT_SCREEN_CHARS_HEIGHT; i++) { + for (j = 0; j < MINIPAINT_SCREEN_CHARS_WIDTH; j++) { + /* get block */ + for (k = 0; k < MINIPAINT_BLOCK_HEIGHT; k++) { + for (l = 0; l < MINIPAINT_BLOCK_WIDTH; l++) { + dest->colormap[(k * MINIPAINT_BLOCK_WIDTH) + l] = + source->colormap[(i * MINIPAINT_BLOCK_HEIGHT * MINIPAINT_SCREEN_PIXEL_WIDTH) + + (j * MINIPAINT_BLOCK_WIDTH) + + (k * MINIPAINT_SCREEN_PIXEL_WIDTH) + l]; + } + } + colors = native_sort_colors_colormap(dest, VIC_NUM_COLORS_BG_AUX); + + if (hiresmap[i][j]) { + /* the first color is expected to be the background color in the + next step. so put it first, followed by the other colors */ + cellcolors[0].amount = MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_SCREEN_PIXEL_HEIGHT; + cellcolors[0].color = bgcolor; + + for (l = 0, k = 1; k < VIC_NUM_COLORS_BG_AUX; l++) { + if (colors[l].color != bgcolor) { + cellcolors[k].color = colors[l].color; + cellcolors[k].amount = colors[l].amount; + k++; + } + } + /* re-render the block using the background color and the most + used color in that block */ + cellcolors[2].color = 255; /* mark end of list */ + } else { + /* the first color is expected to be the background color in the + next step. so put it first, followed by the other colors */ + cellcolors[0].amount = MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_SCREEN_PIXEL_HEIGHT; + cellcolors[0].color = bgcolor; + cellcolors[1].amount = MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_SCREEN_PIXEL_HEIGHT; + cellcolors[1].color = auxcolor; + cellcolors[2].amount = MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_SCREEN_PIXEL_HEIGHT; + cellcolors[2].color = bordercolor; + + for (l = 0, k = 3; k < VIC_NUM_COLORS_BG_AUX; l++) { + if ((colors[l].color != bordercolor) && + (colors[l].color != bgcolor) && + (colors[l].color != auxcolor)) { + cellcolors[k].color = colors[l].color; + cellcolors[k].amount = colors[l].amount; + k++; + } + } + /* re-render the block using the background color and the 3 most + used color in that block */ + cellcolors[4].color = 255; /* mark end of list */ + } + + /* do the rendering */ + vic_color_to_nearest_vic_color_colormap(dest, cellcolors); + for (k = 0; k < MINIPAINT_BLOCK_HEIGHT; k++) { + for (l = 0; l < MINIPAINT_BLOCK_WIDTH; l++) { + source->colormap[(i * MINIPAINT_BLOCK_HEIGHT * MINIPAINT_SCREEN_PIXEL_WIDTH) + + (j * MINIPAINT_BLOCK_WIDTH) + + (k * MINIPAINT_SCREEN_PIXEL_WIDTH) + l] = + dest->colormap[(k * MINIPAINT_BLOCK_WIDTH) + l]; + } + } + lib_free(colors); + } + } + lib_free(dest->colormap); + lib_free(dest); +} + +static int minipaint_render_and_save(native_data_t *source, int original_bordercolor) +{ + FILE *fd; + char *filename_ext = NULL; + uint8_t *filebuffer = NULL; + uint8_t *result = NULL; + int i, j, k, l; + int m = 0; + int n = 0; + int retval = 0; + uint8_t color1; + uint8_t colorbyte; + uint8_t bgcolor; + uint8_t gfxbits; + uint8_t auxcolor; + uint8_t bordercolor; + + /* allocate file buffer */ + filebuffer = lib_malloc(MINIPAINT_SIZE); + + /* clear filebuffer */ + memset(filebuffer, 0, MINIPAINT_SIZE); + + memset(hiresmap, 0, MINIPAINT_SCREEN_CHARS_HEIGHT * MINIPAINT_SCREEN_CHARS_WIDTH); + containshires = 0; + + /* find best shared colors to use */ + minipaint_find_shared_colors(source, &bgcolor, &auxcolor, &bordercolor); + + /* when its safe to do so, use the original bordercolor. since we are trying + a best effort generic conversion, we can't directly use the real border + color and only use it as a hint. */ + DBG(("bordercolor: %d original bordercolor: %d\n", bordercolor, original_bordercolor)); + if (original_bordercolor != bordercolor) { + if (auxcolor == original_bordercolor) { + auxcolor = bordercolor; + bordercolor = original_bordercolor; + DBG(("auxcolor == original_bordercolor, aux: %d border: %d\n", auxcolor, bordercolor)); + } else if (bgcolor == original_bordercolor) { + /* if the picture contains hires blocks, then we can not change the bgcolor */ + if (containshires == 0) { + bgcolor = bordercolor; + bordercolor = original_bordercolor; + DBG(("bgcolor == original_bordercolor, bgcolor: %d border: %d\n", bgcolor, bordercolor)); + } + } + } + DBG(("using bg: %d border: %d aux: %d\n", bgcolor, bordercolor, auxcolor)); + + /* check and correct cells */ + minipaint_check_and_correct_cell(source, bgcolor, auxcolor, bordercolor); + + for (j = 0; j < MINIPAINT_SCREEN_CHARS_WIDTH; j++) { + for (i = 0; i < MINIPAINT_SCREEN_CHARS_HEIGHT; i++) { + /* one block */ + n = (i * MINIPAINT_SCREEN_CHARS_WIDTH) + j; + color1 = 0; + if (hiresmap[i][j]) { + for (k = 0; k < MINIPAINT_BLOCK_HEIGHT; k++) { + gfxbits = 0; + for (l = 0; l < MINIPAINT_BLOCK_WIDTH; l++) { + gfxbits <<= 1; + colorbyte = source->colormap[(i * MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_BLOCK_HEIGHT) + + (j * MINIPAINT_BLOCK_WIDTH) + + (k * MINIPAINT_SCREEN_PIXEL_WIDTH) + l]; + /* assign the bits */ + if (colorbyte != bgcolor) { + gfxbits |= 1; + color1 = colorbyte; + } + } + filebuffer[BITMAP_OFFSET + m] = gfxbits; + m++; + } + } else { + for (k = 0; k < MINIPAINT_BLOCK_HEIGHT; k++) { + gfxbits = 0; + for (l = 0; l < (MINIPAINT_BLOCK_WIDTH / 2); l++) { + gfxbits <<= 2; + colorbyte = source->colormap[(i * MINIPAINT_SCREEN_PIXEL_WIDTH * MINIPAINT_BLOCK_HEIGHT) + + (j * MINIPAINT_BLOCK_WIDTH) + + (k * MINIPAINT_SCREEN_PIXEL_WIDTH) + (l * 2)]; + /* assign the bits */ + if (colorbyte == bordercolor) { + gfxbits |= 1; + } else if (colorbyte == auxcolor) { + gfxbits |= 3; + } else if (colorbyte != bgcolor) { + gfxbits |= 2; + color1 = colorbyte; + } + } + filebuffer[BITMAP_OFFSET + m] = gfxbits; + m++; + } + } + if (n & 1) { + filebuffer[VIDEORAM_OFFSET + (n >> 1)] |= ((color1 & 0x7) << 4) | (hiresmap[i][j] ? 0 : 0x80); + } else { + filebuffer[VIDEORAM_OFFSET + (n >> 1)] |= ((color1 & 0x7) << 0) | (hiresmap[i][j] ? 0 : 0x08); + } + } + } + + memcpy(filebuffer, headerdata, 17); + memcpy(&filebuffer[DISPLAYER_OFFSET], displaycode, 120); + filebuffer[AUXCOLOR_OFFSET] = auxcolor << 4; + filebuffer[BGCOLOR_OFFSET] = (bgcolor << 4) | bordercolor | (1 << 3); + + filename_ext = util_add_extension_const(source->filename, minipaint_drv.default_extension); + + fd = fopen(filename_ext, MODE_WRITE); + if (fd == NULL) { + retval = -1; + } + + if (retval != -1) { + if (fwrite(filebuffer, MINIPAINT_SIZE, 1, fd) < 1) { + retval = -1; + } + } + + if (fd != NULL) { + fclose(fd); + } + + lib_free(source->colormap); + lib_free(source); + lib_free(filename_ext); + lib_free(filebuffer); + lib_free(result); + + return retval; +} + +/* ------------------------------------------------------------------------ */ + +static int minipaint_vicii_save(screenshot_t *screenshot, const char *filename) +{ + uint8_t *regs = screenshot->video_regs; + native_data_t *data = NULL; + uint8_t bordercolor = regs[0x20] & 0xf; + data = native_vicii_render(screenshot, filename); + if (data == NULL) { + return -1; + } + vicii_color_to_vic_color_colormap(data); + if ((data->xsize != MINIPAINT_SCREEN_PIXEL_WIDTH) || (data->ysize != MINIPAINT_SCREEN_PIXEL_HEIGHT)) { + data = native_resize_colormap(data, MINIPAINT_SCREEN_PIXEL_WIDTH, MINIPAINT_SCREEN_PIXEL_HEIGHT, + bordercolor, oversize_handling, undersize_handling); + } + return minipaint_render_and_save(data, 0); +} + +/* ------------------------------------------------------------------------ */ + +static int minipaint_ted_save(screenshot_t *screenshot, const char *filename) +{ + uint8_t *regs = screenshot->video_regs; + native_data_t *data = NULL; + uint8_t bordercolor = regs[0x19]; + data = native_ted_render(screenshot, filename); + if (data == NULL) { + return -1; + } + ted_color_to_vic_color_colormap(data, ted_lum_handling); + if ((data->xsize != MINIPAINT_SCREEN_PIXEL_WIDTH) || (data->ysize != MINIPAINT_SCREEN_PIXEL_HEIGHT)) { + data = native_resize_colormap(data, MINIPAINT_SCREEN_PIXEL_WIDTH, MINIPAINT_SCREEN_PIXEL_HEIGHT, + bordercolor, oversize_handling, undersize_handling); + } + return minipaint_render_and_save(data, 0); +} + +/* ------------------------------------------------------------------------ */ + +static int minipaint_vic_save(screenshot_t *screenshot, const char *filename) +{ + uint8_t *regs = screenshot->video_regs; + native_data_t *data; + uint8_t bordercolor = regs[0xf] & 7; + + DBG(("original VIC colors: background: %d border: %d aux: %d\n", regs[0xf] >> 4, regs[0xf] & 7, regs[0xe] >> 4)); + + data = native_vic_render(screenshot, filename); + if (data == NULL) { + return -1; + } + + if ((data->xsize != MINIPAINT_SCREEN_PIXEL_WIDTH) || (data->ysize != MINIPAINT_SCREEN_PIXEL_HEIGHT)) { + data = native_resize_colormap(data, MINIPAINT_SCREEN_PIXEL_WIDTH, MINIPAINT_SCREEN_PIXEL_HEIGHT, + bordercolor, oversize_handling, undersize_handling); + } + return minipaint_render_and_save(data, bordercolor); +} + +/* ------------------------------------------------------------------------ */ + +static int minipaint_crtc_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = native_crtc_render(screenshot, filename); + if (data == NULL) { + return -1; + } + + if (data->xsize != MINIPAINT_SCREEN_PIXEL_WIDTH || data->ysize != MINIPAINT_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, MINIPAINT_SCREEN_PIXEL_WIDTH, MINIPAINT_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); + } + return minipaint_render_and_save(data, 0); +} + +/* ------------------------------------------------------------------------ */ + +static int minipaint_vdc_save(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = NULL; + data = native_vdc_render(screenshot, filename); + if (data == NULL) { + return -1; + } + + vdc_color_to_vic_color_colormap(data); + if (data->xsize != MINIPAINT_SCREEN_PIXEL_WIDTH || data->ysize != MINIPAINT_SCREEN_PIXEL_HEIGHT) { + data = native_resize_colormap(data, MINIPAINT_SCREEN_PIXEL_WIDTH, MINIPAINT_SCREEN_PIXEL_HEIGHT, + 0, oversize_handling, undersize_handling); + } + return minipaint_render_and_save(data, 0); +} + +/* ------------------------------------------------------------------------ */ + +static int minipaintdrv_save(screenshot_t *screenshot, const char *filename) +{ + if (!(strcmp(screenshot->chipid, "VICII"))) { + return minipaint_vicii_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "VDC"))) { + return minipaint_vdc_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "CRTC"))) { + return minipaint_crtc_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "TED"))) { + return minipaint_ted_save(screenshot, filename); + } + if (!(strcmp(screenshot->chipid, "VIC"))) { + return minipaint_vic_save(screenshot, filename); + } + ui_error("Unknown graphics chip"); + return -1; +} + +static gfxoutputdrv_t minipaint_drv = +{ + GFXOUTPUTDRV_TYPE_SCREENSHOT_NATIVE, + "MINIPAINT", + "MiniPaint screenshot", + "prg", + NULL, /* formatlist */ + NULL, + NULL, + NULL, + NULL, + minipaintdrv_save, + NULL, + NULL, + minipaintdrv_resources_init, + minipaintdrv_cmdline_options_init +#ifdef FEATURE_CPUMEMHISTORY + , NULL +#endif +}; + +void gfxoutput_init_minipaint(int help) +{ + gfxoutput_register(&minipaint_drv); +} diff --git a/src/Emulators/vice/gfxoutputdrv/minipaintdrv.h b/src/Emulators/vice/gfxoutputdrv/minipaintdrv.h new file mode 100644 index 00000000..e69de29b diff --git a/src/Emulators/vice/gfxoutputdrv/miniz.c b/src/Emulators/vice/gfxoutputdrv/miniz.c new file mode 100644 index 00000000..875cc580 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/miniz.c @@ -0,0 +1,2095 @@ +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib +//#define MINIZ_NO_MALLOC + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +static mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s +{ + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. +// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +static int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +static int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +static int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +static int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +static int mz_deflateEnd(mz_streamp pStream); + +// Initializes a decompressor. +static int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +static int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +static int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +static int mz_inflateEnd(mz_streamp pStream); + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). +enum +{ + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); + +enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else +enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + +// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. +typedef enum +{ + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum +{ + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +static tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. +static tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +static mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED +static mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; + +#include +#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) (void)x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER + #define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) + #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else + #define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +// ------------------- zlib-style API's + +static mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + return (s2 << 16) + s1; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } +static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } + +static int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +static int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +static int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; +} + +static int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; + for ( ; ; ) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +static int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +static int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +static int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +static int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +static int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +#endif //MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// ------------------- Low-level Compression (independent from all decompression API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, + 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, + 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, + 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, + 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, + 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, + 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, + 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7 }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. +typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; mz_uint32 total = 0; if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) do { \ + mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) { \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); } \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) + { + mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } + } + else + { + mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef _MSC_VER +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) +#else +#define TDEFL_READ_UNALIGNED_WORD(p) ({ \ + mz_uint16 w; \ + memcpy(&w, (p), 2); \ + w; \ +}) +#endif + +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; + q = (const mz_uint16*)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) + { + *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (probe_len > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + + while (lookahead_size >= 4) + { + int k8_cond; + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if ((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) { + mz_uint32 dw; + probe_pos &= TDEFL_LZ_DICT_SIZE_MASK; + memcpy(&dw, d->m_dict + probe_pos, 4); + k8_cond = ((dw & 0xFFFFFF) == first_trigram); + } else { + k8_cond = 0; + } + + if (k8_cond) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) + { + int n; + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +static tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +static tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; + d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +static mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). +static mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif //MINIZ_NO_ZLIB_APIS + + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + 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 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. + + For more information, please refer to +*/ diff --git a/src/Emulators/vice/gfxoutputdrv/nativedrv.c b/src/Emulators/vice/gfxoutputdrv/nativedrv.c index f8937c60..6fca0c44 100644 --- a/src/Emulators/vice/gfxoutputdrv/nativedrv.c +++ b/src/Emulators/vice/gfxoutputdrv/nativedrv.c @@ -3,6 +3,7 @@ * * Written by * Marco van den Heuvel + * groepaz * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -31,7 +32,6 @@ #include #include "archdep.h" -#include "cmdline.h" #include "lib.h" #include "log.h" #include "machine.h" @@ -41,13 +41,33 @@ #include "palette.h" #include "resources.h" #include "screenshot.h" -#include "translate.h" #include "vicetypes.h" #include "uiapi.h" #include "util.h" #include "vsync.h" -void native_smooth_scroll_borderize_colormap(native_data_t *source, BYTE bordercolor, BYTE xcover, BYTE ycover) +/* #define DEBUGNATIVEDRV */ + +#ifdef DEBUGNATIVEDRV +#define DBG(_x_) printf _x_ +#else +#define DBG(_x_) +#endif + +#define VIC_NUM_COLORS 16 +#define VICII_NUM_COLORS 16 + +/* + TODO: + + disable debug output + test vic screenshots, fix automatic positioning of the gfx window + test vdc screenshots, fix automatic positioning of the gfx window + test crts screenshots, fix automatic positioning of the gfx window + when all is done, remove #if 0'ed code +*/ + +void native_smooth_scroll_borderize_colormap(native_data_t *source, uint8_t bordercolor, uint8_t xcover, uint8_t ycover) { int i, j, k; int xstart = 0; @@ -57,6 +77,9 @@ void native_smooth_scroll_borderize_colormap(native_data_t *source, BYTE borderc int ysize; int yendamount = 0; + DBG(("native_smooth_scroll_borderize_colormap bordercolor: %d xcover: %d ycover: %d\n", + bordercolor, xcover, ycover)); + if (xcover == 255) { xstart = 0; xsize = source->xsize; @@ -109,7 +132,7 @@ void native_smooth_scroll_borderize_colormap(native_data_t *source, BYTE borderc } } -native_data_t *native_borderize_colormap(native_data_t *source, BYTE bordercolor, int xsize, int ysize) +native_data_t *native_borderize_colormap(native_data_t *source, uint8_t bordercolor, int xsize, int ysize) { int i, j, k, l; int xstart = 0; @@ -118,6 +141,9 @@ native_data_t *native_borderize_colormap(native_data_t *source, BYTE bordercolor int yendamount = 0; native_data_t *dest = lib_malloc(sizeof(native_data_t)); + DBG(("native_borderize_colormap bordercolor: %d xsize: %d ysize: %d\n", + bordercolor, xsize, ysize)); + dest->filename = source->filename; if (source->xsize < xsize) { @@ -178,7 +204,7 @@ native_data_t *native_borderize_colormap(native_data_t *source, BYTE bordercolor return dest; } -native_data_t *native_crop_and_borderize_colormap(native_data_t *source, BYTE bordercolor, int xsize, int ysize, int oversize_handling) +native_data_t *native_crop_and_borderize_colormap(native_data_t *source, uint8_t bordercolor, int xsize, int ysize, int oversize_handling) { int startx; int starty; @@ -188,6 +214,9 @@ native_data_t *native_crop_and_borderize_colormap(native_data_t *source, BYTE bo int i, j, k, l; native_data_t *dest = lib_malloc(sizeof(native_data_t)); + DBG(("native_crop_and_borderize_colormap bordercolor: %d xsize: %d ysize: %d oversize handling: %d\n", + bordercolor, xsize, ysize, oversize_handling)); + dest->filename = source->filename; startx = (xsize - source->xsize) / 2; @@ -318,6 +347,9 @@ native_data_t *native_scale_colormap(native_data_t *source, int xsize, int ysize int i, j; int xmult, ymult; + DBG(("native_scale_colormap xsize: %d ysize: %d\n", xsize, ysize)); + DBG((" source xsize: %d ysize: %d\n", source->xsize, source->ysize)); + dest->filename = source->filename; dest->xsize = xsize; @@ -330,7 +362,8 @@ native_data_t *native_scale_colormap(native_data_t *source, int xsize, int ysize for (i = 0; i < ysize; i++) { for (j = 0; j < xsize; j++) { - dest->colormap[(i * xsize) + j] = source->colormap[(((i * ymult) >> 8) * source->xsize) + ((j * xmult) >> 8)]; + dest->colormap[(i * xsize) + j] = + source->colormap[(((i * ymult) >> 8) * source->xsize) + ((j * xmult) >> 8)]; } } @@ -340,11 +373,15 @@ native_data_t *native_scale_colormap(native_data_t *source, int xsize, int ysize return dest; } -native_data_t *native_resize_colormap(native_data_t *source, int xsize, int ysize, BYTE bordercolor, int oversize_handling, int undersize_handling) +/* scale and/or crop and/or borderize according to the options */ +native_data_t *native_resize_colormap(native_data_t *source, int xsize, int ysize, uint8_t bordercolor, int oversize_handling, int undersize_handling) { native_data_t *data = source; int mc_data_present = source->mc_data_present; + DBG(("native_crop_and_borderize_colormap bordercolor: %d xsize: %d ysize: %d oversize handling: %d undersize handling: %d\n", + bordercolor, xsize, ysize, oversize_handling, undersize_handling)); + if (data->xsize > xsize) { if (oversize_handling == NATIVE_SS_OVERSIZE_SCALE) { data = native_scale_colormap(data, xsize, data->ysize); @@ -385,7 +422,7 @@ native_data_t *native_resize_colormap(native_data_t *source, int xsize, int ysiz native_color_sort_t *native_sort_colors_colormap(native_data_t *source, int color_amount) { int i, j; - BYTE color; + uint8_t color; int highest; int amount; int highestindex = 0; @@ -420,7 +457,43 @@ native_color_sort_t *native_sort_colors_colormap(native_data_t *source, int colo return colors; } -static BYTE vicii_color_bw_translate[16] = { +/* returns 1 if any 8x8 cell contains more than two colors */ +int native_is_colormap_multicolor(native_data_t *source) +{ + int blocksx = source->xsize / 8; + int blocksy = source->ysize / 8; + int i, j, k, l; + int multicolor = 0; + native_data_t *dest = lib_malloc(sizeof(native_data_t)); + native_color_sort_t *colors = NULL; + + dest->xsize = 8; + dest->ysize = 8; + dest->colormap = lib_malloc(8 * 8); + + for (i = 0; (i < blocksy) && (multicolor == 0); i++) { + for (j = 0; (j < blocksx) && (multicolor == 0); j++) { + /* get block */ + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + dest->colormap[(k * 8) + l] = + source->colormap[(i * 8 * source->xsize) + (j * 8) + + (k * source->xsize) + l]; + } + } + colors = native_sort_colors_colormap(dest, 16); + if (colors[2].amount > 0) { + multicolor = 1; + } + lib_free(colors); + } + } + lib_free(dest->colormap); + lib_free(dest); + return multicolor; +} + +static uint8_t vicii_color_bw_translate[VICII_NUM_COLORS] = { 0, /* vicii black (0) -> vicii black (0) */ 1, /* vicii white (1) -> vicii white (1) */ 0, /* vicii red (2) -> vicii black (0) */ @@ -439,7 +512,7 @@ static BYTE vicii_color_bw_translate[16] = { 1 /* vicii light gray (F) -> vicii white (1) */ }; -static inline BYTE vicii_color_to_bw(BYTE color) +static inline uint8_t vicii_color_to_bw(uint8_t color) { return vicii_color_bw_translate[color]; } @@ -455,7 +528,7 @@ void vicii_color_to_vicii_bw_colormap(native_data_t *source) } } -static BYTE vicii_color_gray_translate[16] = { +static uint8_t vicii_color_gray_translate[VICII_NUM_COLORS] = { 0x0, /* vicii black (0) -> vicii black (0) */ 0xF, /* vicii white (1) -> vicii light gray (F) */ 0xB, /* vicii red (2) -> vicii dark gray (B) */ @@ -474,7 +547,7 @@ static BYTE vicii_color_gray_translate[16] = { 0xF /* vicii light gray (F) -> vicii light gray (F) */ }; -static inline BYTE vicii_color_to_gray(BYTE color) +static inline uint8_t vicii_color_to_gray(uint8_t color) { return vicii_color_gray_translate[color]; } @@ -490,61 +563,95 @@ void vicii_color_to_vicii_gray_colormap(native_data_t *source) } } -static BYTE vicii_closest_color[16][16] = { +/* most similar -> least similar color */ +static uint8_t vicii_closest_color[VICII_NUM_COLORS][VICII_NUM_COLORS] = { /* vicii black (0) */ { 0, 9, 11, 2, 6, 8, 5, 12, 4, 10, 14, 3, 13, 15, 7, 1 }, - /* vicii white (1) */ { 1, 15, 13, 7, 3, 10, 14, 12, 4, 5, 11, 8, 6, 2, 9, 0 }, - /* vicii red (2) */ { 2, 8, 9, 11, 0, 10, 12, 5, 4, 6, 7, 14, 15, 3, 13, 1 }, - /* vicii cyan (3) */ { 3, 13, 14, 15, 12, 10, 5, 7, 4, 11, 1, 6, 8, 9, 2, 0 }, - /* vicii purple (4) */ { 4, 10, 12, 11, 15, 14, 6, 8, 2, 3, 13, 9, 7, 5, 1, 0 }, - /* vicii green (5) */ { 5, 11, 12, 8, 9, 3, 10, 2, 13, 7, 14, 15, 0, 4, 6, 1 }, - /* vicii blue (6) */ { 6, 11, 9, 0, 4, 12, 14, 2, 8, 10, 3, 5, 13, 15, 7, 1 }, - /* vicii yellow (7) */ { 7, 13, 15, 10, 3, 12, 1, 5, 8, 4, 14, 11, 2, 9, 6, 0 }, - /* vicii orange (8) */ { 8, 2, 9, 11, 10, 5, 12, 4, 0, 7, 6, 15, 3, 14, 13, 1 }, - /* vicii brown (9) */ { 9, 11, 2, 0, 8, 6, 5, 12, 4, 10, 14, 3, 15, 13, 7, 1 }, - /* vicii light red (10) */ { 10, 12, 4, 15, 7, 8, 3, 11, 13, 14, 2, 5, 9, 1, 6, 0 }, - /* vicii dark gray (11) */ { 11, 9, 12, 6, 2, 8, 5, 0, 4, 10, 14, 3, 15, 13, 7, 1 }, - /* vicii medium gray (12) */ { 12, 10, 4, 3, 14, 11, 15, 5, 13, 8, 9, 6, 7, 2, 1, 0 }, - /* vicii light green (13) */ { 13, 3, 15, 7, 12, 15, 1, 10, 5, 4, 11, 8, 9, 2, 6, 0 }, - /* vicii light blue (14) */ { 14, 3, 12, 11, 4, 13, 6, 11, 10, 5, 9, 1, 7, 8, 2, 0 }, - /* vicii light gray (15) */ { 15, 13, 3, 12, 14, 10, 7, 1, 4, 5, 11, 8, 6, 9, 2, 0 } }; +/* + 0 - black 8 - orange + 1 - white 9 - light orange (brown) + 2 - red 10 - pink + 3 - cyan 11 - light cyan (dark gray) + 4 - magenta 12 - light magenta (medium gray) + 5 - green 13 - light green + 6 - blue 14 - light blue + 7 - yellow 15 - light yellow (light gray) + + FIXME: this table needs tweaking/fixing +*/ +/* most similar -> least similar color */ +static uint8_t vic_closest_color[VIC_NUM_COLORS][VIC_NUM_COLORS] = { + /* vicii black (0) */ + { 0, 11, 2, 6, 8, 5, 12, 4, 10, 9, 14, 3, 13, 15, 7, 1 }, + /* vicii white (1) */ + { 1, 15, 9, 13, 7, 3, 10, 14, 12, 4, 5, 11, 8, 6, 2, 0 }, + /* vicii red (2) */ + { 2, 8, 9, 11, 0, 10, 12, 5, 4, 6, 7, 14, 15, 3, 13, 1 }, + /* vicii cyan (3) */ + { 3, 13, 14, 15, 12, 10, 5, 7, 4, 11, 1, 6, 8, 9, 2, 0 }, + /* vicii purple (4) */ + { 4, 10, 12, 11, 15, 14, 6, 8, 2, 3, 13, 9, 7, 5, 1, 0 }, + /* vicii green (5) */ + { 5, 11, 12, 8, 9, 3, 10, 2, 13, 7, 14, 15, 0, 4, 6, 1 }, + /* vicii blue (6) */ + { 6, 11, 9, 0, 4, 12, 14, 2, 8, 10, 3, 5, 13, 15, 7, 1 }, + /* vicii yellow (7) */ + { 7, 13, 15, 10, 3, 12, 1, 5, 8, 4, 14, 11, 2, 9, 6, 0 }, + /* vicii orange (8) */ + { 8, 2, 9, 11, 10, 5, 12, 4, 0, 7, 6, 15, 3, 14, 13, 1 }, + /* vicii brown (9) */ + { 9, 11, 2, 0, 8, 6, 5, 12, 4, 10, 14, 3, 15, 13, 7, 1 }, + /* vicii light red (10) */ + { 10, 12, 4, 15, 7, 8, 3, 11, 13, 14, 2, 5, 9, 1, 6, 0 }, + /* vicii dark gray (11) */ + { 11, 9, 12, 6, 2, 8, 5, 0, 4, 10, 14, 3, 15, 13, 7, 1 }, + /* vicii medium gray (12) */ + { 12, 10, 4, 3, 14, 11, 15, 5, 13, 8, 9, 6, 7, 2, 1, 0 }, + /* vicii light green (13) */ + { 13, 3, 15, 7, 12, 15, 1, 10, 5, 4, 11, 8, 9, 2, 6, 0 }, + /* vicii light blue (14) */ + { 14, 3, 12, 11, 4, 13, 6, 11, 10, 5, 9, 1, 7, 8, 2, 0 }, + /* vicii light yellow (15) */ + { 15, 13, 3, 7, 1, 12, 14, 10, 4, 5, 11, 8, 6, 9, 2, 0 } +}; -static inline BYTE vicii_color_to_nearest_color(BYTE color, native_color_sort_t *altcolors) +/* altcolors[n].color == 255 marks the end of the list */ +static inline uint8_t vicii_color_to_nearest_color(uint8_t color, native_color_sort_t *altcolors) { int i, j; - for (i = 0; i < 16; i++) { + for (i = 0; i < VICII_NUM_COLORS; i++) { for (j = 0; altcolors[j].color != 255; j++) { if (vicii_closest_color[color][i] == altcolors[j].color) { return vicii_closest_color[color][i]; @@ -560,19 +667,263 @@ void vicii_color_to_nearest_vicii_color_colormap(native_data_t *source, native_c for (i = 0; i < source->ysize; i++) { for (j = 0; j < source->xsize; j++) { - source->colormap[(i * source->xsize) + j] = vicii_color_to_nearest_color(source->colormap[(i * source->xsize) + j], colors); + source->colormap[(i * source->xsize) + j] = + vicii_color_to_nearest_color(source->colormap[(i * source->xsize) + j], colors); + } + } +} + +/* altcolors[n].color == 255 marks the end of the list */ +static inline uint8_t vic_color_to_nearest_color(uint8_t color, native_color_sort_t *altcolors) +{ + int i, j; + + for (i = 0; i < VIC_NUM_COLORS; i++) { + for (j = 0; altcolors[j].color != 255; j++) { + if (vic_closest_color[color][i] == altcolors[j].color) { + return vic_closest_color[color][i]; + } + } + } + return 0; +} + +void vic_color_to_nearest_vic_color_colormap(native_data_t *source, native_color_sort_t *colors) +{ + int i, j; + + for (i = 0; i < source->ysize; i++) { + for (j = 0; j < source->xsize; j++) { + source->colormap[(i * source->xsize) + j] = + vic_color_to_nearest_color(source->colormap[(i * source->xsize) + j], colors); } } } /* ------------------------------------------------------------------------ */ +static native_data_t *native_generic_render(screenshot_t *screenshot, const char *filename, int xsize, int ysize, int xstep) +{ + native_data_t *data = lib_malloc(sizeof(native_data_t)); + int i, j; + int leftborder, topborder; + uint8_t *linebuffer; + + DBG(("native_generic_render xsize: %d ysize: %d xstep: %d\n", xsize, ysize, xstep)); + data->filename = filename; + + /* size of the native picture */ + data->xsize = xsize; + data->ysize = ysize; + data->colormap = lib_malloc(data->xsize * data->ysize); + + linebuffer = lib_malloc(screenshot->width * screenshot->height); + + DBG(("screenshot->width: %u\n", screenshot->width)); + DBG(("screenshot->height: %u\n", screenshot->height)); + DBG(("screenshot->max_width: %u\n", screenshot->max_width)); + DBG(("screenshot->x_offset: %u\n", screenshot->x_offset)); + DBG(("screenshot->first_displayed_line: %u\n", screenshot->first_displayed_line)); + DBG(("screenshot->gfx_position.x %u\n", screenshot->gfx_position.x)); + DBG(("screenshot->gfx_position.y %u\n", screenshot->gfx_position.y)); + + leftborder = screenshot->gfx_position.x; + topborder = screenshot->gfx_position.y - screenshot->first_displayed_line; + + DBG((" leftborder: %d\n", leftborder)); + DBG((" topborder: %d\n", topborder)); + + /* get screenshot data in palette format */ + for (i = 0; i < data->ysize; i++) { + (screenshot->convert_line)(screenshot, + linebuffer + (i * screenshot->width), + i + topborder, SCREENSHOT_MODE_PALETTE); + } + + /* create picture in the native size of the videochip, without border */ + for (i = 0; i < data->ysize; i++) { + for (j = 0; j < data->xsize; j++) { + data->colormap[(i * data->xsize) + (j)] = + linebuffer[(i * screenshot->width) + ((j * xstep) + leftborder)]; + } + } + data->mc_data_present = native_is_colormap_multicolor(data); + DBG((" mc_data_present: %d\n", data->mc_data_present)); + + return data; +} + +native_data_t *native_vicii_render(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = native_generic_render(screenshot, filename, 320, 200, 1); + uint8_t *regs = screenshot->video_regs; + if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + } + return data; +} + +native_data_t *native_ted_render(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data = native_generic_render(screenshot, filename, 320, 200, 1); + uint8_t *regs = screenshot->video_regs; + uint8_t brdrcolor = regs[0x19] & 0x7f; /* TED border color (matches 3.10) */ + if (((regs[0x07] & 8) == 0) || ((regs[0x06] & 8) == 0)) { + native_smooth_scroll_borderize_colormap(data, brdrcolor, (uint8_t)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (uint8_t)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); + } + return data; +} + +native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data; + uint8_t *regs = screenshot->video_regs; + int xsize, ysize; + xsize = (regs[0x02] & 0x7f) * 8; /* columns */ + ysize = ((regs[0x03] & 0x7e) >> 1) * 8; /* rows */ + if (regs[0x03] & 1) { + ysize <<= 1; /* 16 pixel high chars */ + } + DBG(("native_vic_render columns: %d rows: %d char height: %d\n", + regs[0x02] & 0x7f, (regs[0x03] & 0x7e) >> 1, (regs[0x03] & 1) ? 16 : 8)); + data = native_generic_render(screenshot, filename, xsize, ysize, 2); + return data; +} + +/* FIXME: + screenshot->gfx_position.x/y does not match actual black border + + "hre" and "petdww_ram" is broken +*/ +native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data; + uint8_t *regs = screenshot->video_regs; + uint8_t *petdww_ram = screenshot->bitmap_ptr; + int xsize; + int ysize; + uint8_t invert; + uint8_t charheight, charwidth; + int hre = 0; +#if 0 + int base; + int chars = 1; + int col80; +#endif + + DBG(("screenshot->bitmap_low_ptr[0]: %d\n", screenshot->bitmap_low_ptr[0])); + DBG(("screenshot->bitmap_high_ptr[0]: %d\n", screenshot->bitmap_high_ptr[0])); + DBG(("1: %d\n", regs[0x01])); + DBG(("2: %d\n", regs[0x02])); + DBG(("3: %d\n", regs[0x03])); + DBG(("4: %d\n", regs[0x04])); + DBG(("5: %d\n", regs[0x05])); + DBG(("6: %d\n", regs[0x06])); + DBG(("7: %d\n", regs[0x07])); + DBG(("8: %d\n", regs[0x08])); + DBG(("9: %d\n", regs[0x09])); + + xsize = regs[0x01]; + if (screenshot->bitmap_low_ptr[0] == 80) { + xsize <<= 1; + } + + ysize = regs[0x06]; + invert = (regs[0x0c] & 0x10) >> 4; + + if (!invert) { /* On 8296 only! */ + hre = 1; +#if 0 + chars = 0; +#endif + invert = 1; + } + + /* charheight = screenshot->bitmap_high_ptr[0]; */ + charwidth = 8; /* is this correct? */ + charheight = regs[0x09] + 1; /* FIXME: handle inter-character gap */ + + DBG(("chars x: %d w: %d\n", xsize, charwidth)); + DBG(("chars y: %d h: %d\n", ysize, charheight)); + + if (hre) { + xsize = 512; + ysize = 256; + } else { + xsize = xsize * charwidth; + ysize = ysize * charheight; + } + + if (petdww_ram) { + /* FIXME: + * If we're in an 80 column screen we need to + * horizontally double all pixels, since DWW + * only has 40 characters worth of pixels. + */ + } + DBG(("xsize: %d\n", xsize)); + DBG(("ysize: %d\n", ysize)); + + /* FIXME: this should be defined elsewhere in the crtc code */ + if (regs[0x01] == 40) { + screenshot->gfx_position.y = 41; + } else { + screenshot->gfx_position.y = 28; + } + screenshot->gfx_position.x = 33; + + data = native_generic_render(screenshot, filename, xsize, ysize, 1); + return data; +} + +/* FIXME: + screenshot->gfx_position.x/y does not match actual black border +*/ +native_data_t *native_vdc_render(screenshot_t *screenshot, const char *filename) +{ + native_data_t *data; + uint8_t *regs = screenshot->video_regs; + int xsize, ysize; + uint8_t displayed_chars_h = regs[1]; + uint8_t displayed_chars_v = regs[6]; + uint8_t scanlines_per_char = (regs[9] & 0x1f) + 1; + /* uint8_t char_h_size_alloc = regs[22] & 0xf; */ + /* uint8_t char_h_size_displayed = (regs[22] & 0xf0) >> 4; */ + uint8_t char_h_size = (regs[22] & 0x0f); + uint8_t char_h_double_pixel = ((regs[25] & 0x10) ? 2 : 1); + uint8_t top_border_chars_h; + + DBG(("native_vdc_render displayed_chars_h: %u\n", displayed_chars_h)); + DBG((" displayed_chars_v: %u\n", displayed_chars_v)); + DBG((" char_h_size_displayed: %u\n", (regs[22] & 0xf0) >> 4)); + DBG((" char_h_size: %u\n", char_h_size)); + DBG((" scanlines_per_char: %u\n", scanlines_per_char)); + DBG((" char_h_double_pixel: %u\n", char_h_double_pixel)); + DBG((" 3: %u\n", regs[3])); + DBG((" 4: %u\n", regs[4])); + DBG((" 5: %u\n", regs[5])); + DBG((" 6: %u\n", regs[6])); + + xsize = displayed_chars_h * char_h_size * char_h_double_pixel; + ysize = displayed_chars_v * scanlines_per_char; + + DBG((" xsize: %d\n", xsize)); + DBG((" ysize: %d\n", ysize)); + + /* FIXME: this should be set elsewhere in the vdc code */ + top_border_chars_h = ((regs[4] - displayed_chars_v) / 2) - 1; /* FIXME: is this correct? */ + screenshot->gfx_position.y = top_border_chars_h * scanlines_per_char; + + data = native_generic_render(screenshot, filename, xsize, ysize, 1); + return data; +} + native_data_t *native_vicii_text_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -601,17 +952,17 @@ native_data_t *native_vicii_text_mode_render(screenshot_t *screenshot, const cha } } if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, (BYTE)(regs[0x20] & 0xf), (BYTE)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (BYTE)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); } return data; } native_data_t *native_vicii_extended_background_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -639,19 +990,19 @@ native_data_t *native_vicii_extended_background_mode_render(screenshot_t *screen } } if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, (BYTE)(regs[0x20] & 0xf), (BYTE)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (BYTE)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); } return data; } native_data_t *native_vicii_multicolor_text_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE color0; - BYTE color1; - BYTE color2; - BYTE color3; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t color0; + uint8_t color1; + uint8_t color2; + uint8_t color3; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -706,17 +1057,17 @@ native_data_t *native_vicii_multicolor_text_mode_render(screenshot_t *screenshot } } if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, (BYTE)(regs[0x20] & 0xf), (BYTE)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (BYTE)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); } return data; } native_data_t *native_vicii_hires_bitmap_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -748,19 +1099,19 @@ native_data_t *native_vicii_hires_bitmap_mode_render(screenshot_t *screenshot, c } } if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, (BYTE)(regs[0x20] & 0xf), (BYTE)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (BYTE)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); } return data; } native_data_t *native_vicii_multicolor_bitmap_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE color0; - BYTE color1; - BYTE color2; - BYTE color3; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t color0; + uint8_t color1; + uint8_t color2; + uint8_t color3; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -807,14 +1158,14 @@ native_data_t *native_vicii_multicolor_bitmap_mode_render(screenshot_t *screensh } } if (((regs[0x16] & 8) == 0) || ((regs[0x11] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, (BYTE)(regs[0x20] & 0xf), (BYTE)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (BYTE)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); + native_smooth_scroll_borderize_colormap(data, (uint8_t)(regs[0x20] & 0xf), (uint8_t)((regs[0x16] & 8) ? 255 : regs[0x16] & 7), (uint8_t)((regs[0x11] & 8) ? 255 : regs[0x11] & 7)); } return data; } /* ------------------------------------------------------------------------ */ -static BYTE ted_vicii_translate[16] = { +static uint8_t ted_vicii_translate[16] = { 0x0, /* ted black (0) -> vicii black (0) */ 0x1, /* ted white (1) -> vicii white (1) */ 0x2, /* ted red (2) -> vicii red (2) */ @@ -833,12 +1184,36 @@ static BYTE ted_vicii_translate[16] = { 0xD /* ted light green (F) -> vicii light green (D) */ }; -static BYTE ted_to_vicii_color(BYTE color) +static uint8_t ted_vic_translate[16] = { + 0x0, /* ted black (0) -> vic black (0) */ + 0x1, /* ted white (1) -> vic white (1) */ + 0x2, /* ted red (2) -> vic red (2) */ + 0x3, /* ted cyan (3) -> vic cyan (3) */ + 0x4, /* ted purple (4) -> vic purple (4) */ + 0x5, /* ted green (5) -> vic green (5) */ + 0x6, /* ted blue (6) -> vic blue (6) */ + 0x7, /* ted yellow (7) -> vic yellow (7) */ + 0x8, /* ted orange (8) -> vic orange (8) */ + 0x9, /* ted brown (9) -> vic brown (9) */ + 0xF, /* ted yellow-green (A) -> vic light yellow(F) */ + 0xA, /* ted pink (B) -> vic light red (A) */ + 0xB, /* ted blue-green (C) -> vic light cyan (B) */ + 0xE, /* ted light blue (D) -> vic light blue (E) */ + 0x6, /* ted dark blue (E) -> vic blue (6) */ + 0xD /* ted light green (F) -> vic light green (D) */ +}; + +static uint8_t ted_to_vicii_color(uint8_t color) { return ted_vicii_translate[color]; } -static BYTE ted_lum_vicii_translate[16 * 8] = { +static uint8_t ted_to_vic_color(uint8_t color) +{ + return ted_vic_translate[color]; +} + +static uint8_t ted_lum_vicii_translate[16 * 8] = { 0x0, /* ted black L0 (0) -> vicii black (0) */ 0x9, /* ted white L0 (1) -> vicii brown (9) */ 0x2, /* ted red L0 (2) -> vicii red (2) */ @@ -976,7 +1351,146 @@ static BYTE ted_lum_vicii_translate[16 * 8] = { 0xD /* ted light green L7 (F) -> vicii light green (D) */ }; -static BYTE ted_lum_to_vicii_color(BYTE color, BYTE lum) +/* TODO: this table needs more tweaking */ +static uint8_t ted_lum_vic_translate[16 * 8] = { + 0x0, /* ted black L0 (0) -> vic black (0) */ + 0x0, /* ted white L0 (1) -> vic black (0) */ + 0x2, /* ted red L0 (2) -> vic red (2) */ + 0x3, /* ted cyan L0 (3) -> vic cyan (3) */ + 0x6, /* ted purple L0 (4) -> vic blue (6) */ + 0x0, /* ted green L0 (5) -> vic black (0) */ + 0x6, /* ted blue L0 (6) -> vic blue (6) */ + 0x0, /* ted yellow L0 (7) -> vic black (0) */ + 0x0, /* ted orange L0 (8) -> vic black (0) */ + 0x0, /* ted brown L0 (9) -> vic black (0) */ + 0x0, /* ted yellow-green L0 (A) -> vic black (0) */ + 0x0, /* ted pink L0 (B) -> vic black (0) */ + 0x0, /* ted blue-green L0 (C) -> vic black (0) */ + 0x6, /* ted light blue L0 (D) -> vic blue (6) */ + 0x6, /* ted dark blue L0 (E) -> vic blue (6) */ + 0x0, /* ted light green L0 (F) -> vic black (0) */ + + 0x0, /* ted black L1 (0) -> vic black (0) */ + 0x0, /* ted white L1 (1) -> vic black (0) */ + 0x2, /* ted red L1 (2) -> vic red (2) */ + 0x3, /* ted cyan L1 (3) -> vic cyan (C) */ + 0x6, /* ted purple L1 (4) -> vic blue (6) */ + 0x0, /* ted green L1 (5) -> vic black (0) */ + 0x6, /* ted blue L1 (6) -> vic blue (6) */ + 0x0, /* ted yellow L1 (7) -> vic black (0) */ + 0x2, /* ted orange L1 (8) -> vic red (2) */ + 0x0, /* ted brown L1 (9) -> vic black (0) */ + 0x0, /* ted yellow-green L1 (A) -> vic black (0) */ + 0x2, /* ted pink L1 (B) -> vic red (2) */ + 0x6, /* ted blue-green L1 (C) -> vic blue (6) */ + 0x6, /* ted light blue L1 (D) -> vic blue (6) */ + 0x6, /* ted dark blue L1 (E) -> vic blue (6) */ + 0x5, /* ted light green L1 (F) -> vic green (5) */ + + 0x0, /* ted black L2 (0) -> vic black (0) */ + 0x0, /* ted white L2 (1) -> vic black (0) */ + 0x2, /* ted red L2 (2) -> vic red (2) */ + 0x3, /* ted cyan L2 (3) -> vic cyan (3) */ + 0x4, /* ted purple L2 (4) -> vic purple (4) */ + 0x9, /* ted green L2 (5) -> vic black (0) */ + 0x6, /* ted blue L2 (6) -> vic blue (6) */ + 0x0, /* ted yellow L2 (7) -> vic black (0) */ + 0x2, /* ted orange L2 (8) -> vic red (2) */ + 0x0, /* ted brown L2 (9) -> vic black (0) */ + 0x0, /* ted yellow-green L2 (A) -> vic black (0) */ + 0x2, /* ted pink L2 (B) -> vic red (2) */ + 0x6, /* ted blue-green L2 (C) -> vic blue (6) */ + 0x6, /* ted light blue L2 (D) -> vic blue (6) */ + 0x6, /* ted dark blue L2 (E) -> vic blue (6) */ + 0x5, /* ted light green L2 (F) -> vic green (5) */ + + 0x0, /* ted black L3 (0) -> vic black (0) */ + 0x0, /* ted white L3 (1) -> vic black (0) */ + 0x2, /* ted red L3 (2) -> vic red (2) */ + 0x3, /* ted cyan L3 (3) -> vic cyan (3) */ + 0x4, /* ted purple L3 (4) -> vic purple (4) */ + 0x0, /* ted green L3 (5) -> vic black (0) */ + 0x6, /* ted blue L3 (6) -> vic blue (6) */ + 0x0, /* ted yellow L3 (7) -> vic black (0) */ + 0x8, /* ted orange L3 (8) -> vic orange (8) */ + 0x8, /* ted brown L3 (9) -> vic orange (8) */ + 0x0, /* ted yellow-green L3 (A) -> vic black (0) */ + 0x4, /* ted pink L3 (B) -> vic purple (4) */ + 0x6, /* ted blue-green L3 (C) -> vic blue (6) */ + 0x6, /* ted light blue L3 (D) -> vic blue (6) */ + 0x6, /* ted dark blue L3 (E) -> vic blue (6) */ + 0x5, /* ted light green L3 (F) -> vic green (5) */ + + 0x0, /* ted black L4 (0) -> vic black (0) */ + 0x1, /* ted white L4 (1) -> vic white (1) */ + 0xA, /* ted red L4 (2) -> vic pink (A) */ + 0xE, /* ted cyan L4 (3) -> vic light blue (E) */ + 0x4, /* ted purple L4 (4) -> vic purple (4) */ + 0x5, /* ted green L4 (5) -> vic green (5) */ + 0xE, /* ted blue L4 (6) -> vic light blue (E) */ + 0x5, /* ted yellow L4 (7) -> vic green (5) */ + 0xA, /* ted orange L4 (8) -> vic pink (A) */ + 0x8, /* ted brown L4 (9) -> vic orange (8) */ + 0x5, /* ted yellow-green L4 (A) -> vic green (5) */ + 0x4, /* ted pink L4 (B) -> vic purple (4) */ + 0x3, /* ted blue-green L4 (C) -> vic cyan (3) */ + 0xE, /* ted light blue L4 (D) -> vic light blue (E) */ + 0xE, /* ted dark blue L4 (E) -> vic light blue (E) */ + 0x5, /* ted light green L4 (F) -> vic green (5) */ + + 0x0, /* ted black L5 (0) -> vic black (0) */ + 0x1, /* ted white L5 (1) -> vic white (1) */ + 0xA, /* ted red L5 (2) -> vic pink (A) */ + 0x3, /* ted cyan L5 (3) -> vic cyan (3) */ + 0xC, /* ted purple L5 (4) -> vic light purple(C) */ + 0x5, /* ted green L5 (5) -> vic green (5) */ + 0xE, /* ted blue L5 (6) -> vic light blue (E) */ + 0x5, /* ted yellow L5 (7) -> vic green (5) */ + 0xA, /* ted orange L5 (8) -> vic pink (A) */ + 0xA, /* ted brown L5 (9) -> vic pink (A) */ + 0x5, /* ted yellow-green L5 (A) -> vic green (5) */ + 0xA, /* ted pink L5 (B) -> vic pink (A) */ + 0x3, /* ted blue-green L5 (C) -> vic cyan (3) */ + 0xE, /* ted light blue L5 (D) -> vic light blue (E) */ + 0xE, /* ted dark blue L5 (E) -> vic light blue (E) */ + 0x5, /* ted light green L5 (F) -> vic green (5) */ + + 0x0, /* ted black L6 (0) -> vic black (0) */ + 0x1, /* ted white L6 (1) -> vic white (1) */ + 0xA, /* ted red L6 (2) -> vic pink (A) */ + 0x3, /* ted cyan L6 (3) -> vic cyan (3) */ + 0xC, /* ted purple L6 (4) -> vic light purple(C) */ + 0xD, /* ted green L6 (5) -> vic light green (D) */ + 0xE, /* ted blue L6 (6) -> vic light blue (E) */ + 0x7, /* ted yellow L6 (7) -> vic yellow (7) */ + 0xA, /* ted orange L6 (8) -> vic pink (A) */ + 0xA, /* ted brown L6 (9) -> vic pink (A) */ + 0x7, /* ted yellow-green L6 (A) -> vic yellow (7) */ + 0xA, /* ted pink L6 (B) -> vic pink (A) */ + 0x3, /* ted blue-green L6 (C) -> vic cyan (3) */ + 0xE, /* ted light blue L6 (D) -> vic light blue (E) */ + 0xE, /* ted dark blue L6 (E) -> vic light blue (E) */ + 0x7, /* ted light green L6 (F) -> vic yellow (7) */ + + 0x0, /* ted black L7 (0) -> vic black (0) */ + 0x1, /* ted white L7 (1) -> vic white (1) */ + 0x1, /* ted red L7 (2) -> vic white (1) */ + 0x1, /* ted cyan L7 (3) -> vic white (1) */ + 0x1, /* ted purple L7 (4) -> vic white (1) */ + 0xD, /* ted green L7 (5) -> vic light green (D) */ + 0x1, /* ted blue L7 (6) -> vic white (1) */ + 0x7, /* ted yellow L7 (7) -> vic yellow (7) */ + 0x9, /* ted orange L7 (8) -> vic light orange(9) */ + 0x7, /* ted brown L7 (9) -> vic yellow (7) */ + 0x7, /* ted yellow-green L7 (A) -> vic yellow (7) */ + 0x1, /* ted pink L7 (B) -> vic white (1) */ + 0xD, /* ted blue-green L7 (C) -> vic light green (D) */ + 0x1, /* ted light blue L7 (D) -> vic white (1) */ + 0x1, /* ted dark blue L7 (E) -> vic white (1) */ + 0xD /* ted light green L7 (F) -> vic light green (D) */ +}; + +static uint8_t ted_lum_to_vicii_color(uint8_t color, uint8_t lum) { return ted_lum_vicii_translate[(lum * 16) + color]; } @@ -984,15 +1498,41 @@ static BYTE ted_lum_to_vicii_color(BYTE color, BYTE lum) void ted_color_to_vicii_color_colormap(native_data_t *source, int ted_lum_handling) { int i, j; - BYTE colorbyte; + uint8_t colorbyte; + + for (i = 0; i < source->ysize; i++) { + for (j = 0; j < source->xsize; j++) { + colorbyte = source->colormap[(i * source->xsize) + j]; + if (ted_lum_handling == NATIVE_SS_TED_LUM_DITHER) { + source->colormap[(i * source->xsize) + j] = + ted_lum_to_vicii_color((uint8_t)(colorbyte & 0xf), (uint8_t)(colorbyte >> 4)); + } else { + source->colormap[(i * source->xsize) + j] = + ted_to_vicii_color((uint8_t)(colorbyte & 0xf)); + } + } + } +} + +static uint8_t ted_lum_to_vic_color(uint8_t color, uint8_t lum) +{ + return ted_lum_vic_translate[(lum * 16) + color]; +} + +void ted_color_to_vic_color_colormap(native_data_t *source, int ted_lum_handling) +{ + int i, j; + uint8_t colorbyte; for (i = 0; i < source->ysize; i++) { for (j = 0; j < source->xsize; j++) { colorbyte = source->colormap[(i * source->xsize) + j]; if (ted_lum_handling == NATIVE_SS_TED_LUM_DITHER) { - source->colormap[(i * source->xsize) + j] = ted_lum_to_vicii_color((BYTE)(colorbyte & 0xf), (BYTE)(colorbyte >> 4)); + source->colormap[(i * source->xsize) + j] = + ted_lum_to_vic_color((uint8_t)(colorbyte & 0xf), (uint8_t)(colorbyte >> 4)); } else { - source->colormap[(i * source->xsize) + j] = ted_to_vicii_color((BYTE)(colorbyte & 0xf)); + source->colormap[(i * source->xsize) + j] = + ted_to_vic_color((uint8_t)(colorbyte & 0xf)); } } } @@ -1000,11 +1540,11 @@ void ted_color_to_vicii_color_colormap(native_data_t *source, int ted_lum_handli native_data_t *native_ted_text_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; - BYTE brdrcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; + uint8_t brdrcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -1043,18 +1583,18 @@ native_data_t *native_ted_text_mode_render(screenshot_t *screenshot, const char } } if (((regs[0x07] & 8) == 0) || ((regs[0x06] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, brdrcolor, (BYTE)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (BYTE)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); + native_smooth_scroll_borderize_colormap(data, brdrcolor, (uint8_t)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (uint8_t)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); } return data; } native_data_t *native_ted_extended_background_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; - BYTE brdrcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; + uint8_t brdrcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -1088,18 +1628,18 @@ native_data_t *native_ted_extended_background_mode_render(screenshot_t *screensh } } if (((regs[0x07] & 8) == 0) || ((regs[0x06] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, brdrcolor, (BYTE)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (BYTE)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); + native_smooth_scroll_borderize_colormap(data, brdrcolor, (uint8_t)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (uint8_t)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); } return data; } native_data_t *native_ted_hires_bitmap_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; - BYTE brdrcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; + uint8_t brdrcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -1132,20 +1672,20 @@ native_data_t *native_ted_hires_bitmap_mode_render(screenshot_t *screenshot, con } } if (((regs[0x07] & 8) == 0) || ((regs[0x06] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, brdrcolor, (BYTE)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (BYTE)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); + native_smooth_scroll_borderize_colormap(data, brdrcolor, (uint8_t)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (uint8_t)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); } return data; } native_data_t *native_ted_multicolor_bitmap_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE color0; - BYTE color1; - BYTE color2; - BYTE color3; - BYTE brdrcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t color0; + uint8_t color1; + uint8_t color2; + uint8_t color3; + uint8_t brdrcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -1192,14 +1732,14 @@ native_data_t *native_ted_multicolor_bitmap_mode_render(screenshot_t *screenshot } } if (((regs[0x07] & 8) == 0) || ((regs[0x06] & 8) == 0)) { - native_smooth_scroll_borderize_colormap(data, brdrcolor, (BYTE)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (BYTE)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); + native_smooth_scroll_borderize_colormap(data, brdrcolor, (uint8_t)((regs[0x07] & 8) ? 255 : regs[0x07] & 7), (uint8_t)((regs[0x06] & 8) ? 255 : regs[0x06] & 7)); } return data; } /* ------------------------------------------------------------------------ */ -static BYTE vic_vicii_translate[16] = { +static uint8_t vic_vicii_translate[VIC_NUM_COLORS] = { 0x0, /* vic black (0) -> vicii black (0) */ 0x1, /* vic white (1) -> vicii white (1) */ 0x2, /* vic red (2) -> vicii red (2) */ @@ -1210,15 +1750,34 @@ static BYTE vic_vicii_translate[16] = { 0x7, /* vic yellow (7) -> vicii yellow (7) */ 0x8, /* vic orange (8) -> vicii orange (8) */ 0x8, /* vic light orange (9) -> vicii orange (8) */ - 0x8, /* vic pink (A) -> vicii orange (8) */ + 0xa, /* vic pink (A) -> vicii light red (a) */ 0xD, /* vic light cyan (B) -> vicii light green (D) */ 0x4, /* vic light purple (C) -> vicii purple (4) */ 0xD, /* vic light green (D) -> vicii light green (D) */ 0xE, /* vic light blue (E) -> vicii light blue (E) */ - 0x7 /* vic light yellow (F) -> vicii yellow (7) */ + 0xF /* vic light yellow (F) -> vicii light grey (F) */ +}; + +static uint8_t vicii_vic_translate[VICII_NUM_COLORS] = { + 0x0, /* vicii black (0) -> vic black (0) */ + 0x1, /* vicii white (1) -> vic white (1) */ + 0x2, /* vicii red (2) -> vic red (2) */ + 0x3, /* vicii cyan (3) -> vic cyan (3) */ + 0x4, /* vicii purple (4) -> vic purple (4) */ + 0x5, /* vicii green (5) -> vic green (5) */ + 0x6, /* vicii blue (6) -> vic blue (6) */ + 0x7, /* vicii yellow (7) -> vic yellow (7) */ + 0x9, /* vicii orange (8) -> vic light orange (9) */ + 0x8, /* vicii brown (9) -> vic orange (8) */ + 0xa, /* vicii light red (A) -> vic pink (a) */ + 0x2, /* vicii dark gray (B) -> vic red (2) */ + 0x8, /* vicii medium gray (C) -> vic orange (8) */ + 0xd, /* vicii light green (D) -> vic light green (d) */ + 0xe, /* vicii light blue (E) -> vic light blue (e) */ + 0xf /* vicii light gray (F) -> vic light yellow (f) */ }; -static inline BYTE vic_to_vicii_color(BYTE color) +static inline uint8_t vic_to_vicii_color(uint8_t color) { return vic_vicii_translate[color]; } @@ -1229,23 +1788,42 @@ void vic_color_to_vicii_color_colormap(native_data_t *source) for (i = 0; i < source->ysize; i++) { for (j = 0; j < source->xsize; j++) { - source->colormap[(i * source->xsize) + j] = vic_to_vicii_color(source->colormap[(i * source->xsize) + j]); + source->colormap[(i * source->xsize) + j] = + vic_to_vicii_color(source->colormap[(i * source->xsize) + j]); + } + } +} + +static inline uint8_t vicii_to_vic_color(uint8_t color) +{ + return vicii_vic_translate[color]; +} + +void vicii_color_to_vic_color_colormap(native_data_t *source) +{ + int i, j; + + for (i = 0; i < source->ysize; i++) { + for (j = 0; j < source->xsize; j++) { + source->colormap[(i * source->xsize) + j] = + vicii_to_vic_color(source->colormap[(i * source->xsize) + j]); } } } +#if 0 native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; - BYTE brdrcolor; - BYTE auxcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; + uint8_t brdrcolor; + uint8_t auxcolor; int i, j, k, l; native_data_t *data; - BYTE xsize; - BYTE ysize; + uint8_t xsize; + uint8_t ysize; xsize = regs[0x02] & 0x7f; ysize = (regs[0x03] & 0x7e) >> 1; @@ -1317,8 +1895,9 @@ native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename) } return data; } - +#endif /* ------------------------------------------------------------------------ */ +#if 0 #define MA_WIDTH 64 #define MA_LO (MA_WIDTH - 1) /* 6 bits */ @@ -1326,17 +1905,17 @@ native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename) native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename, int crtc_fgcolor) { - BYTE *regs = screenshot->video_regs; - BYTE *petdww_ram = screenshot->bitmap_ptr; - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; + uint8_t *regs = screenshot->video_regs; + uint8_t *petdww_ram = screenshot->bitmap_ptr; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; int x, y, k, l; native_data_t *data; - BYTE xsize; - BYTE ysize; - BYTE invert; - BYTE charheight; + uint8_t xsize; + uint8_t ysize; + uint8_t invert; + uint8_t charheight; int base; int shiftand; int chars = 1; @@ -1424,12 +2003,12 @@ native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename for (k = 0; k < charheight; k++) { bitmap = 0; if (chars) { - BYTE chr = screenshot->screen_ptr[scr_rel & shiftand]; + uint8_t chr = screenshot->screen_ptr[scr_rel & shiftand]; bitmap = screenshot->chargen_ptr[(chr * 16) + k]; } if (petdww_ram && k < 8) { int addr = (k * 1024) + ((scr_rel >> col80) & 0x3FF); - BYTE b = petdww_ram[addr]; + uint8_t b = petdww_ram[addr]; /* * If we're in an 80 column screen we need to * horizontally double all pixels, since DWW @@ -1480,10 +2059,10 @@ native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename } return data; } - +#endif /* ------------------------------------------------------------------------ */ -static BYTE vdc_vicii_translate[16] = { +static uint8_t vdc_vicii_translate[16] = { 0x0, /* vdc black (0) -> vicii black (0) */ 0xB, /* vdc dark gray (1) -> vicii dark gray (B) */ 0x6, /* vdc dark blue (2) -> vicii blue (6) */ @@ -1502,7 +2081,26 @@ static BYTE vdc_vicii_translate[16] = { 0x1 /* vdc white (F) -> vicii white (1) */ }; -static inline BYTE vdc_to_vicii_color(BYTE color) +static uint8_t vdc_vic_translate[16] = { + 0x0, /* vdc black (0) -> vic black (0) */ + 0x0, /* vdc dark gray (1) -> vic black (0) */ + 0x6, /* vdc dark blue (2) -> vic blue (6) */ + 0xe, /* vdc light blue (3) -> vic light blue (e) */ + 0x5, /* vdc dark green (4) -> vic green (5) */ + 0xd, /* vdc light green (5) -> vic light green (d) */ + 0x3, /* vdc dark cyan (6) -> vic cyan (3) */ + 0xb, /* vdc light cyan (7) -> vic light cyan (b) */ + 0x2, /* vdc dark red (8) -> vic red (2) */ + 0xa, /* vdc light red (9) -> vic pink (a) */ + 0x4, /* vdc dark purple (A) -> vic purple (4) */ + 0xc, /* vdc light purple (B) -> vic light purple(c) */ + 0x7, /* vdc dark yellow (C) -> vic yellow (7) */ + 0xe, /* vdc light yellow (D) -> vic light yellow(e) */ + 0xe, /* vdc light gray (E) -> vic light yellow(e) */ + 0x1 /* vdc white (F) -> vic white (1) */ +}; + +static inline uint8_t vdc_to_vicii_color(uint8_t color) { return vdc_vicii_translate[color]; } @@ -1513,22 +2111,40 @@ void vdc_color_to_vicii_color_colormap(native_data_t *source) for (i = 0; i < source->ysize; i++) { for (j = 0; j < source->xsize; j++) { - source->colormap[(i * source->xsize) + j] = vdc_to_vicii_color(source->colormap[(i * source->xsize) + j]); + source->colormap[(i * source->xsize) + j] = + vdc_to_vicii_color(source->colormap[(i * source->xsize) + j]); + } + } +} + +static inline uint8_t vdc_to_vic_color(uint8_t color) +{ + return vdc_vic_translate[color]; +} + +void vdc_color_to_vic_color_colormap(native_data_t *source) +{ + int i, j; + + for (i = 0; i < source->ysize; i++) { + for (j = 0; j < source->xsize; j++) { + source->colormap[(i * source->xsize) + j] = + vdc_to_vic_color(source->colormap[(i * source->xsize) + j]); } } } native_data_t *native_vdc_text_mode_render(screenshot_t *screenshot, const char *filename) { - BYTE *regs = screenshot->video_regs; - BYTE displayed_chars_h = regs[1]; - BYTE displayed_chars_v = regs[6]; + uint8_t *regs = screenshot->video_regs; + uint8_t displayed_chars_h = regs[1]; + uint8_t displayed_chars_v = regs[6]; /* BYTE scanlines_per_char = (regs[9] & 0x1f) + 1; BYTE char_h_size_alloc = regs[22] & 0xf; BYTE char_h_size_displayed = (regs[22] & 0xf0) >> 4; */ - BYTE bitmap; - BYTE fgcolor; - BYTE bgcolor; + uint8_t bitmap; + uint8_t fgcolor; + uint8_t bgcolor; int i, j, k, l; native_data_t *data = lib_malloc(sizeof(native_data_t)); @@ -1579,217 +2195,3 @@ native_data_t *native_vdc_text_mode_render(screenshot_t *screenshot, const char } return data; } - -/* - ------------------------ - | Register Definitions | - ------------------------ - -Reg# 7 6 5 4 3 2 1 0 Description Notes -------- ---- ---- ---- ---- ---- ---- ---- ---- ------------------------ ----- - 1 HzD7 HzD6 HzD5 HzD4 HzD3 HzD2 HzD1 HzD0 Horizontal Displayed ^1 - 6 VeD7 VeD6 VeD5 VeD4 VeD3 VeD2 VeD1 VeD0 Vertical Displayed ^3 - 9 .... .... .... CTV4 CTV3 CTV2 CTV1 CTV0 Character Total Vertical ^5 - 12 Ds15 Ds14 Ds13 Ds12 Ds11 Ds10 Ds09 Ds08 Display Start Adrs (Hi) ^7 - 13 Ds07 Ds06 Ds05 Ds04 Ds03 Ds02 Ds01 Ds00 Display Start Adrs (Lo) ^7 - 20 At15 At14 At13 At12 At11 At10 At09 At08 Attribute Start Adrs (Hi) ^7 - 21 At07 At06 At05 At04 At03 At02 At01 At00 Attribute Start Adrs (Lo) ^7 - 22 HcP3 HcP2 HcP1 HcP0 IcS3 IcS2 IcS1 IcS0 Hz Chr Pxl Ttl/IChar Spc ^A - 23 .... .... .... VcP4 VcP3 VcP2 VcP1 VcP0 Vert. Character Pxl Spc ^5 - 24 BlkM RvsS Vss5 Vss4 Vss3 Vss2 Vss1 Vss0 Block/Rvs Scr/V. Scroll ^9^B^C - 25 Text Atri Semi Dble Hss3 Hss2 Hss1 Hss0 Diff. Mode Sw/H. Scroll ^D,^E - 26 Fgd3 Fgd2 Fgd1 Fgd0 Bgd3 Bgd2 Bgd1 Bgd0 ForeGround/BackGround Col ^F - 27 Rin7 Rin6 Rin5 Rin4 Rin3 Rin2 Rin1 Rin0 Row/Adrs. Increment ^G - 28 CSa2 CSa1 CSa0 RamT .... .... .... .... Character Set Addrs/Ram ^H,^I - 34 DeB7 DeB6 DeB5 DeB4 DeB3 DeB2 DeB1 DeB0 Display Enable Begin ^J - 35 DeE7 DeE6 DeE5 DeE4 DeE3 DeE2 DeE1 DeE0 Display Enable End ^J - - +-----------------+ - | Register Usage: | - +-----------------+ - ---- Register #1: Horizontal Displayed - - These two register function to define the display width of the screen. -Register 0 will contain the number of characters minus 1 between sucessive -horizontal sync pulses, the horizontal border and the interval between -horizontal sync pulses. The normal value for this is usually set to 126. -Register 1 specifies how many of the positions as specified in register 0 can -actually be used to display characters. The default value for this is 80. -The VDC can take values less than 80 and thus, will only display that many -characters. A useful effect can be a sweep from the right by incrementing -the value here from 1 to 80. Register #2 specifies the starting character -position at which the vertical sync pulse begins. Thus, it also determines -where on the active screen characters appear. A default value of 102, -increasing the value moves the screen to the left, decreasing it moves it to -the right. - - Register #6: Vertical Displayed - - Register #4 of this register determines the total number of screen rows, -including the rows for the active display, and the top and bottom borders in -addition to that of the vertical sync width. The value held here is normally -a value of 32 for NTSC systems (US Standard) or 39 for PAL(European) systems. -Register #5 holds in bits 0-4 a "fine-adjust" where any extra scan lines that -are necessary to make up the display can be specified here. The value here is -normally a 0 in both the NTSC and PAL initializations by the kernal and bits -5-7 are unused, always returning a binary 1111. Register #6 specifies the total -number of the vertical character positions (as set in Register 4) that can be -used for actual display of characters. Thus, this register usually holds a -value of 25 for a standard 25-row display. - -^5 : Register #9: Total Scan Lines Per Character ----- - - Bits 0-4 of this register are the only relevant ones, the rest returning a -binary 1. Bits 0-4 determine the character height in scan-lines of displayed -characters and allow up to scan-line heights of 32 scan lines. The VDC normally -sets aside 16 bytes for each character (normally, each byte is equivlent to -1 scan line) so the value here could be increased to 16-1 and a double-height -character set could be loaded in. Note, however that values less than 16 will -tell the VDC to use a 8,192 byte character set (normal) while specifying values -greater than 16 will make it use 32 bytes per character even if some of the -bytes are not used. - -^7 : Register #12: Display Start Address (Hi) ----- Register #13: Display Start Address (Lo) - Register #20: Attribute Start Addrs (Hi) - Register #21: Attribute Start Addrs (Lo) - - Note first, that all of these registers are grouped in Hi byte, Lo byte order -which is usually different from the 6502 convention of low byte, hi byte (ie: -in normal 6502 ml, $c000 is stored as $00 $c0, however in the 8563 it would be -stored as $c0 $00). Registers 12 and 13 determine, where in VDC memory the -8563 is the start of the screen. Incrementing this value by 80 (the number of -characters per line) and with a little additional work can provide a very -effecient way of having a screen that "seems" to be larger than just 80x25. -The cursor position in registers 14 and 15 reflect the actual character in -memory that the cursor currently lies over. If it's not on the display screen, -then it is not displayed. Registers 20 and 21 reflect where in the 8563 memory -attribute memory is held. Attribute memory refers to the character attributes -such as flash, inverse video, color etc that can be set for each character. - -^A : Register #22: Character Horizontal Size Control ----- - - Bits 0-3 of this register determines how many horizontal pixels are used -for each displayed character. Values greater than 8 here result in apparent -gaps in the display. Inter-character spacing can be achieved by setting this -value greater than that of bits 4-7. Bits 4-7 determine the width of each -character position in pixels. Thus, while bits 0-3 allocate n-pixels, bits -4-7 specify how many of those pixels are used for character display. - -^B : Register #24:5 Reverse Screen Bit ----- Register #24:6 Blink Rate for Characters. - - Bit #6 specifies for the VDC for all pixels normally unset on the VDC screen -to be set, and all set pixels to be unset. Bit #5 specifies the blink rate -for all characters with the blink attribute. Setting this to a binary 1 -specifies a blink rate of 1/32 the refresh rate, while a binary 0 is equivlant -to a blink rate 1/16th of the refresh rate. - -^C : Register #24:0-4 Vertical Smooth Scroll ----- - - The 8563 provides for a smooth scroll, allowing bits 0-4 to function as an -indicator of the number of bits to scroll the screen vertically upward. - -^D : Register #25:7 Text or Graphics Mode Indicator Bit ----- Register #25:6 Monochrome Mode Bit - Register #25:5 Semi-Graphics Mode - Register #25:4 Double-Pixel Mode - - The 8563 allows the implementation of a graphics mode, in where all of the 16k -of the screen may be bit-mapped sequentially resulting in a resolution of -640x200 (see Craig Bruce's 8563 Line-Plotting routine in the first issue for a -more detailed explanation of this feature). Setting this bit to 1 specifies -graphics mode, binary 0 indicates text mode. Bit 6 indicates to the 8563 where -to obtain its color information etc, about the characters. Bit 6 when it is a -binary 0 results in the 8563 taking it's color information from bits 4-7 of -register 26. When this bit is a binary 1, the attribute memory is used to -obtain color, flash, reverse information. Also note than when this bit is a -binary 1 that only the first of the two character sets is available. Bit #5 -indicates a semi-graphics mode that allows the rightmost pixel of any characters -to be repeated through-out the intercharacter spacing gap. Activating it on the -normal display will result in what appears to be a "digital" character font. The -8563 with bit #4 allows a pixel-double feature which results in all displayed -horizontal pixels having twice their usual size. Thus, a 40 column screen is -easily obtainable although the values in registers #00-#02 must be halved. - -^E : Register #25: Horizontal Smooth Control ----- - - This register is analogous to register #24 Vertical Smooth Control and -functions similairly. Increasing this bits moves the screen one pixel to the -right, while decreasing them moves the screen one pixel to the left. - -^F : Register #26: ForeGround / BackGround Color Register ----- - - This register, in bits 0-3 specifies the background color of the display while -bits 4-7 specify the foreground character colors when attributes are disabled -(via bit 6 of register #25). Note, these are not the usual C= colors but are -instead organized as follows: - - Bit Value Decimal Value Color - ---------------------------------- +-----------------------------+ - %0000 0 / $00 Black | Note: Bit 0 = Intensity | - %0001 1 / $01 Dark Gray | Bit 1 = Blue | - %0010 2 / $02 Dark Blue | RGBI Bit 2 = Green | - %0011 3 / $03 Light Blue | Bit 3 = Red | - %0100 4 / $04 Dark Green | | - %0101 5 / $05 Light Green +-----------------------------+ - %0110 6 / $06 Dark Cyan - %0111 7 / $07 Light Cyan - %1000 8 / $08 Dark Red - %1001 9 / $09 Light Red - %1010 10 / $0A Dark Purple - %1011 11 / $0B Light Purple - %1100 12 / $0C Dark Yellow - %1101 13 / $0D Light Yellow - %1110 14 / $0E Light Gray (Dark White) - %1111 15 / $0F White - -^G : Register #27: Row Address Display Increment ----- - - This register specifies the number of bytes to skip, when displaying -characters on the 8563 screen. Normally, this byte holds a value of $00 -indicating no bytes to skip; however typically programs that "scroll" the -screen do so by setting this to 80 or 160 allowing the program to then alter -the Screen Start (Registers #12 and #13) and appear to "scroll". Note the -normal C= 128 Kernal Screen Editor does not support this function. - -^H : Register #28:7-5 Character Set Address ----- - - These bits indicate the address of screen memory * 8k. Thus the values in -these bits may be multiplied by 8192 to obtain the starting character set -position (normall these bits hold a value of $01 indicating the character -set begins at 8192). Note that the character set is not in ROM, but is usually -copied to 8192 when the computer is first turned on and the 8563 is initialized. -(Examine the INIT80 routine at $CE0C in bank 15). - - +--------------------------+ - | 8563 Memory Organization | - +--------------------------+ - - Normally, the extra memory of the C=128's equipped with 64k goes unused (48k -worth) unless programs like Basic-8 etc, take advantage of it. There are various -mod files describing the upgrade from 16k to 64k and it is _strongly_ advised -(although the author has not yet done so) and be aware that ***OPENING YOUR -COMPUTER JUST TO LOOK, YOU MAY MESS IT UP*** and it is _strongly_ advised that -you contact a person experienced with electronics to perform the upgrade for -you. Note also that some mail order companies are offering an "up-grade board" -which plugs into the 8563 slot and does not involve desoldering the RAM chips. - - Now, the 8563 uses the 16k of memory (it ignores the extra 48k of memory when -it's got 64k, thus the following applies also to the 8563's equipped with 64k -of memory) and normally, has the following memory map: - - $0000 - $07ff - Screen Memory - $0800 - $0fff - Attribute Memory - $1000 - $1fff - Unused - $2000 - $2fff - UpperCase / Graphic Character Set (Char Set #1) - $3000 - $3fff - LowerCase / UpperCase Character Set (Char Set #2) -*/ diff --git a/src/Emulators/vice/gfxoutputdrv/nativedrv.h b/src/Emulators/vice/gfxoutputdrv/nativedrv.h index c0e9788e..7271c532 100644 --- a/src/Emulators/vice/gfxoutputdrv/nativedrv.h +++ b/src/Emulators/vice/gfxoutputdrv/nativedrv.h @@ -3,6 +3,7 @@ * * Written by * Marco van den Heuvel + * groepaz * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. @@ -31,7 +32,7 @@ #include "vicetypes.h" typedef struct native_data_s { - BYTE *colormap; + uint8_t *colormap; int xsize; int ysize; int mc_data_present; @@ -39,45 +40,42 @@ typedef struct native_data_s { } native_data_t; typedef struct native_color_sort_s { - BYTE color; + uint8_t color; int amount; } native_color_sort_t; -extern void gfxoutput_init_doodle(int help); -extern void gfxoutput_init_koala(int help); +void gfxoutput_init_artstudio(int help); +void gfxoutput_init_koala(int help); +void gfxoutput_init_minipaint(int help); -extern void native_smooth_scroll_borderize_colormap(native_data_t *source, BYTE bordercolor, BYTE xcover, BYTE ycover); -extern native_data_t *native_borderize_colormap(native_data_t *source, BYTE bordercolor, int xsize, int ysize); -extern native_data_t *native_crop_and_borderize_colormap(native_data_t *source, BYTE bordercolor, int xsize, int ysize, int oversize_handling); -extern native_data_t *native_scale_colormap(native_data_t *source, int xsize, int ysize); -extern native_data_t *native_resize_colormap(native_data_t *source, int xsize, int ysize, BYTE bordercolor, int oversize_handling, int undersize_handling); -extern native_color_sort_t *native_sort_colors_colormap(native_data_t *source, int color_amount); +/* void native_smooth_scroll_borderize_colormap(native_data_t *source, uint8_t bordercolor, uint8_t xcover, uint8_t ycover); */ +native_data_t *native_borderize_colormap(native_data_t *source, uint8_t bordercolor, int xsize, int ysize); +native_data_t *native_crop_and_borderize_colormap(native_data_t *source, uint8_t bordercolor, int xsize, int ysize, int oversize_handling); +native_data_t *native_scale_colormap(native_data_t *source, int xsize, int ysize); +native_data_t *native_resize_colormap(native_data_t *source, int xsize, int ysize, uint8_t bordercolor, int oversize_handling, int undersize_handling); +native_color_sort_t *native_sort_colors_colormap(native_data_t *source, int color_amount); +int native_is_colormap_multicolor(native_data_t *source); -extern void vicii_color_to_vicii_bw_colormap(native_data_t *source); -extern void vicii_color_to_vicii_gray_colormap(native_data_t *source); -extern void vicii_color_to_nearest_vicii_color_colormap(native_data_t *source, native_color_sort_t *colors); +void vicii_color_to_vicii_bw_colormap(native_data_t *source); +void vicii_color_to_vicii_gray_colormap(native_data_t *source); +void vicii_color_to_nearest_vicii_color_colormap(native_data_t *source, native_color_sort_t *colors); -extern void ted_color_to_vicii_color_colormap(native_data_t *source, int ted_lum_handling); +void vic_color_to_nearest_vic_color_colormap(native_data_t *source, native_color_sort_t *colors); -extern void vic_color_to_vicii_color_colormap(native_data_t *source); +void ted_color_to_vicii_color_colormap(native_data_t *source, int ted_lum_handling); +void ted_color_to_vic_color_colormap(native_data_t *source, int ted_lum_handling); -extern void vdc_color_to_vicii_color_colormap(native_data_t *source); +void vic_color_to_vicii_color_colormap(native_data_t *source); -extern native_data_t *native_vicii_text_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_vicii_extended_background_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_vicii_multicolor_text_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_vicii_hires_bitmap_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_vicii_multicolor_bitmap_mode_render(screenshot_t *screenshot, const char *filename); +void vicii_color_to_vic_color_colormap(native_data_t *source); -extern native_data_t *native_ted_text_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_ted_extended_background_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_ted_hires_bitmap_mode_render(screenshot_t *screenshot, const char *filename); -extern native_data_t *native_ted_multicolor_bitmap_mode_render(screenshot_t *screenshot, const char *filename); +void vdc_color_to_vicii_color_colormap(native_data_t *source); +void vdc_color_to_vic_color_colormap(native_data_t *source); -extern native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename); - -extern native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename, int crtc_fgcolor); - -extern native_data_t *native_vdc_text_mode_render(screenshot_t *screenshot, const char *filename); +native_data_t *native_vicii_render(screenshot_t *screenshot, const char *filename); +native_data_t *native_ted_render(screenshot_t *screenshot, const char *filename); +native_data_t *native_vic_render(screenshot_t *screenshot, const char *filename); +native_data_t *native_vdc_render(screenshot_t *screenshot, const char *filename); +native_data_t *native_crtc_render(screenshot_t *screenshot, const char *filename); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/pcxdrv.c b/src/Emulators/vice/gfxoutputdrv/pcxdrv.c index ce41ad50..5a048c3a 100644 --- a/src/Emulators/vice/gfxoutputdrv/pcxdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/pcxdrv.c @@ -44,16 +44,16 @@ typedef struct gfxoutputdrv_data_s { FILE *fd; char *ext_filename; - BYTE *data; - BYTE *pcx_data; + uint8_t *data; + uint8_t *pcx_data; unsigned int line; } gfxoutputdrv_data_t; -STATIC_PROTOTYPE gfxoutputdrv_t pcx_drv; +static gfxoutputdrv_t pcx_drv; static int pcxdrv_write_file_header(screenshot_t *screenshot) { - BYTE header[128]; + uint8_t header[128]; memset(header, 0, sizeof(header)); @@ -62,14 +62,14 @@ static int pcxdrv_write_file_header(screenshot_t *screenshot) header[2] = 1; header[3] = 8; - util_word_to_le_buf(&header[8], (WORD)(screenshot->width - 1)); - util_word_to_le_buf(&header[10], (WORD)(screenshot->height - 1)); + util_word_to_le_buf(&header[8], (uint16_t)(screenshot->width - 1)); + util_word_to_le_buf(&header[10], (uint16_t)(screenshot->height - 1)); - util_word_to_le_buf(&header[12], (WORD)(screenshot->dpi_x)); - util_word_to_le_buf(&header[14], (WORD)(screenshot->dpi_x)); + util_word_to_le_buf(&header[12], (uint16_t)(screenshot->dpi_x)); + util_word_to_le_buf(&header[14], (uint16_t)(screenshot->dpi_x)); header[65] = 1; - util_word_to_le_buf(&header[66], (WORD)(screenshot->width)); + util_word_to_le_buf(&header[66], (uint16_t)(screenshot->width)); if (fwrite(header, sizeof(header), 1, screenshot->gfxoutputdrv_data->fd) < 1) { return -1; @@ -114,7 +114,7 @@ static int pcxdrv_open(screenshot_t *screenshot, const char *filename) static int pcxdrv_write(screenshot_t *screenshot) { gfxoutputdrv_data_t *sdata; - BYTE color, amount; + uint8_t color, amount; unsigned int i, j = 0; sdata = screenshot->gfxoutputdrv_data; @@ -187,8 +187,8 @@ static int pcxdrv_close(screenshot_t *screenshot) gfxoutputdrv_data_t *sdata; unsigned int i; int res = -1; - BYTE pcx_color_prefix[2] = "\x0c"; - BYTE pcx_colors[256 * 3]; + unsigned char pcx_color_prefix[2] = "\x0c"; + uint8_t pcx_colors[256 * 3]; sdata = screenshot->gfxoutputdrv_data; @@ -235,12 +235,12 @@ static int pcxdrv_save(screenshot_t *screenshot, const char *filename) #ifdef FEATURE_CPUMEMHISTORY static FILE *pcxdrv_memmap_fd; static char *pcxdrv_memmap_ext_filename; -static BYTE *pcxdrv_memmap_pcx_data; +static uint8_t *pcxdrv_memmap_pcx_data; -static int pcxdrv_close_memmap(BYTE *palette) +static int pcxdrv_close_memmap(uint8_t *palette) { int res = 0; - BYTE pcx_color_prefix[2] = "\x0c"; + uint8_t pcx_color_prefix[2] = "\x0c"; if (fwrite(pcx_color_prefix, 1, 1, pcxdrv_memmap_fd) != 1) { res = -1; @@ -255,9 +255,9 @@ static int pcxdrv_close_memmap(BYTE *palette) return res; } -static int pcxdrv_write_memmap(int line, int x_size, BYTE *gfx) +static int pcxdrv_write_memmap(int line, int x_size, uint8_t *gfx) { - BYTE color, amount; + uint8_t color, amount; int i, j = 0; color = gfx[(line * x_size)]; @@ -324,7 +324,7 @@ static int pcxdrv_write_memmap(int line, int x_size, BYTE *gfx) static int pcxdrv_write_file_header_memmap(int x_size, int y_size) { - BYTE header[128]; + uint8_t header[128]; memset(header, 0, sizeof(header)); @@ -333,14 +333,14 @@ static int pcxdrv_write_file_header_memmap(int x_size, int y_size) header[2] = 1; header[3] = 8; - util_word_to_le_buf(&header[8], (WORD)(x_size - 1)); - util_word_to_le_buf(&header[10], (WORD)(y_size - 1)); + util_word_to_le_buf(&header[8], (uint16_t)(x_size - 1)); + util_word_to_le_buf(&header[10], (uint16_t)(y_size - 1)); - util_word_to_le_buf(&header[12], (WORD)(0)); - util_word_to_le_buf(&header[14], (WORD)(0)); + util_word_to_le_buf(&header[12], (uint16_t)(0)); + util_word_to_le_buf(&header[14], (uint16_t)(0)); header[65] = 1; - util_word_to_le_buf(&header[66], (WORD)(x_size)); + util_word_to_le_buf(&header[66], (uint16_t)(x_size)); if (fwrite(header, sizeof(header), 1, pcxdrv_memmap_fd) < 1) { return -1; @@ -369,7 +369,7 @@ static int pcxdrv_open_memmap(const char *filename, int x_size, int y_size) return 0; } -static int pcxdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE *gfx, BYTE *palette) +static int pcxdrv_save_memmap(const char *filename, int x_size, int y_size, uint8_t *gfx, uint8_t *palette) { int line; @@ -391,6 +391,7 @@ static int pcxdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE static gfxoutputdrv_t pcx_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, "PCX", "PCX screenshot", "pcx", diff --git a/src/Emulators/vice/gfxoutputdrv/pcxdrv.h b/src/Emulators/vice/gfxoutputdrv/pcxdrv.h index 253b649c..60493634 100644 --- a/src/Emulators/vice/gfxoutputdrv/pcxdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/pcxdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_PCXDRV_H #define VICE_PCXDRV_H -extern void gfxoutput_init_pcx(int help); +void gfxoutput_init_pcx(int help); #endif diff --git a/src/Emulators/vice/drive/drive-overflow.h b/src/Emulators/vice/gfxoutputdrv/pngdrv.h similarity index 88% rename from src/Emulators/vice/drive/drive-overflow.h rename to src/Emulators/vice/gfxoutputdrv/pngdrv.h index 5e9352dc..6f88a21e 100644 --- a/src/Emulators/vice/drive/drive-overflow.h +++ b/src/Emulators/vice/gfxoutputdrv/pngdrv.h @@ -1,5 +1,5 @@ /* - * drive-overflow.h + * pngdrv.h - Create a PNG file. * * Written by * Andreas Boose @@ -24,9 +24,9 @@ * */ -#ifndef VICE_DRIVE_OVERFLOW_H -#define VICE_DRIVE_OVERFLOW_H +#ifndef VICE_PNGDRV_H +#define VICE_PNGDRV_H -extern void drive_overflow_init(void); +void gfxoutput_init_png(int help); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/ppmdrv.c b/src/Emulators/vice/gfxoutputdrv/ppmdrv.c index b6a85c48..0be0d4c9 100644 --- a/src/Emulators/vice/gfxoutputdrv/ppmdrv.c +++ b/src/Emulators/vice/gfxoutputdrv/ppmdrv.c @@ -44,11 +44,11 @@ typedef struct gfxoutputdrv_data_s { FILE *fd; char *ext_filename; - BYTE *data; + uint8_t *data; unsigned int line; } gfxoutputdrv_data_t; -STATIC_PROTOTYPE gfxoutputdrv_t ppm_drv; +static gfxoutputdrv_t ppm_drv; static int ppmdrv_write_file_header(screenshot_t *screenshot) { @@ -57,7 +57,7 @@ static int ppmdrv_write_file_header(screenshot_t *screenshot) if (fprintf(fd, "P6\012# VICE generated PPM screenshot\012") < 0) { return -1; } - if (fprintf(fd, "%d %d\012255\012", screenshot->width, screenshot->height) < 0) { + if (fprintf(fd, "%u %u\012255\012", screenshot->width, screenshot->height) < 0) { return -1; } @@ -150,10 +150,10 @@ static int ppmdrv_close_memmap(void) return 0; } -static int ppmdrv_write_memmap(int line, int x_size, BYTE *gfx, BYTE *palette) +static int ppmdrv_write_memmap(int line, int x_size, uint8_t *gfx, uint8_t *palette) { int i; - BYTE pixval; + uint8_t pixval; for (i = 0; i < x_size; i++) { pixval = gfx[(line * x_size) + i]; @@ -195,7 +195,7 @@ static int ppmdrv_open_memmap(const char *filename, int x_size, int y_size) return 0; } -static int ppmdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE *gfx, BYTE *palette) +static int ppmdrv_save_memmap(const char *filename, int x_size, int y_size, uint8_t *gfx, uint8_t *palette) { int line; @@ -217,6 +217,7 @@ static int ppmdrv_save_memmap(const char *filename, int x_size, int y_size, BYTE static gfxoutputdrv_t ppm_drv = { + GFXOUTPUTDRV_TYPE_SCREENSHOT_IMAGE, "PPM", "PPM screenshot", "ppm", diff --git a/src/Emulators/vice/gfxoutputdrv/ppmdrv.h b/src/Emulators/vice/gfxoutputdrv/ppmdrv.h index 2b9f3444..024dd3f9 100644 --- a/src/Emulators/vice/gfxoutputdrv/ppmdrv.h +++ b/src/Emulators/vice/gfxoutputdrv/ppmdrv.h @@ -27,6 +27,6 @@ #ifndef VICE_PPMDRV_H #define VICE_PPMDRV_H -extern void gfxoutput_init_ppm(int help); +void gfxoutput_init_ppm(int help); #endif diff --git a/src/Emulators/vice/gfxoutputdrv/zmbv.c b/src/Emulators/vice/gfxoutputdrv/zmbv.c new file mode 100644 index 00000000..cfb9ca9c --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/zmbv.c @@ -0,0 +1,767 @@ +/* + * Copyright (C) 2002-2013 The DOSBox Team + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * C translation by Ketmar // Invisible Vector + */ +#include "zmbv.h" + +#include +#include +#include +#include + +#ifndef ZMBV_USE_MINIZ +# include +# define mz_deflateInit deflateInit +# define mz_inflateInit inflateInit +# define mz_deflateEnd deflateEnd +# define mz_inflateEnd inflateEnd +# define mz_deflateReset deflateReset +# define mz_inflateReset inflateReset +# define mz_deflate deflate +# define mz_inflate inflate +# define mz_stream z_stream +# define MZ_OK Z_OK +# define MZ_SYNC_FLUSH Z_SYNC_FLUSH +#else +# ifdef MINIZ_NO_MALLOC +# undef MINIZ_NO_MALLOC +# endif +# ifdef MINIZ_NO_ZLIB_APIS +# undef MINIZ_NO_ZLIB_APIS +# endif +# include "miniz.c" +# define mz_inflateReset(_strm) ({ int res = mz_inflateEnd(_strm); if (res == MZ_OK) res = mz_inflateInit(_strm); res; }) +#endif + +#ifdef __clang__ +#define ATTR_PACKED __attribute__((packed)) +#elif defined(__GNUC__) +#define ATTR_PACKED __attribute__((packed,gcc_struct)) +#elif defined(_MSC_VER) +#define ATTR_PACKED +#else +#warn "make sure to define ATTR_PACKED for your compiler" +#define ATTR_PACKED +#endif + +/******************************************************************************/ +#define DBZV_VERSION_HIGH (0) +#define DBZV_VERSION_LOW (1) + +#define COMPRESSION_NONE (0) +#define COMPRESSION_ZLIB (1) + +#define MAX_VECTOR (16) + +enum { + FRAME_MASK_KEYFRAME = 0x01, + FRAME_MASK_DELTA_PALETTE = 0x02 +}; + + +/******************************************************************************/ +zmbv_format_t zmbv_bpp_to_format (int bpp) { + switch (bpp) { + case 8: return ZMBV_FORMAT_8BPP; + case 15: return ZMBV_FORMAT_15BPP; + case 16: return ZMBV_FORMAT_16BPP; + case 32: return ZMBV_FORMAT_32BPP; + } + return ZMBV_FORMAT_NONE; +} + + +int zmbv_work_buffer_size (int width, int height, zmbv_format_t fmt) { + if (width > 0 && height > 0 && width <= 16384 && height <= 16384) { + int f; + switch (fmt) { + case ZMBV_FORMAT_8BPP: f = 1; break; + case ZMBV_FORMAT_15BPP: case ZMBV_FORMAT_16BPP: f = 2; break; + case ZMBV_FORMAT_32BPP: f = 4; break; + default: return -1; + } + return f*width*height+2*(1+(width/8))*(1+(height/8))+1024; + } + return -1; +} + + +/******************************************************************************/ +typedef struct { + int start; + int dx, dy; +} zmbv_frame_block_t; + + +typedef struct { + int x, y; + int slot; +} zmbv_codec_vector_t; + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif + +typedef struct ATTR_PACKED { + uint8_t high_version; + uint8_t low_version; + uint8_t compression; + uint8_t format; + uint8_t blockwidth; + uint8_t blockheight; +} zmbv_keyframe_header_t; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +typedef struct { + int lines_done; + int outbuf_size; + int write_done; + uint8_t *outbuf; +} zmbv_compress_t; + + +typedef enum { + ZMBV_MODE_UNKNOWN, + ZMBV_MODE_ENCODER, + ZMBV_MODE_DECODER +} zmbv_codec_mode_t; + + +struct zmbv_codec_s { + zmvb_init_flags_t init_flags; + int complevel; + zmbv_codec_mode_t mode; + int unpack_compression; + + zmbv_compress_t compress; + + zmbv_codec_vector_t vector_table[512]; + int vector_count; + + uint8_t *oldframe, *newframe; + uint8_t *buf1, *buf2, *work; + int bufsize; + + int blockcount; + zmbv_frame_block_t *blocks; + + int workUsed, workPos; + + int palsize; + uint8_t palette[256*3]; + + int height, width, pitch; + + zmbv_format_t format; + int pixelsize; + + mz_stream zstream; + int zstream_inited; // <0: deflate; >0: inflate; 0: not inited +}; + + +/******************************************************************************/ +/* generate functions from templates */ +/* encoder templates */ +#define ZMBV_POSSIBLE_BLOCK_TPL(_pxtype,_pxsize) \ +static inline int zmbv_possible_block_##_pxsize (zmbv_codec_t zc, int vx, int vy, zmbv_frame_block_t *block) { \ + int ret = 0; \ + _pxtype *pold = ((_pxtype *)zc->oldframe)+block->start+(vy*zc->pitch)+vx; \ + _pxtype *pnew = ((_pxtype *)zc->newframe)+block->start; \ + for (int y = 0; y < block->dy; y += 4) { \ + for (int x = 0; x < block->dx; x += 4) { \ + int test = 0-((pold[x]-pnew[x])&0x00ffffff); \ + ret -= (test>>31); \ + } \ + pold += zc->pitch*4; \ + pnew += zc->pitch*4; \ + } \ + return ret; \ +} + + +#define ZMBV_COMPARE_BLOCK_TPL(_pxtype,_pxsize) \ +static inline int zmbv_compare_block_##_pxsize (zmbv_codec_t zc, int vx, int vy, zmbv_frame_block_t *block) { \ + int ret = 0; \ + _pxtype *pold = ((_pxtype *)zc->oldframe)+block->start+(vy*zc->pitch)+vx; \ + _pxtype *pnew = ((_pxtype *)zc->newframe)+block->start; \ + for (int y = 0; y < block->dy; ++y) { \ + for (int x = 0; x < block->dx; ++x) { \ + int test = 0-((pold[x]-pnew[x])&0x00ffffff); \ + ret -= (test>>31); \ + } \ + pold += zc->pitch; \ + pnew += zc->pitch; \ + } \ + return ret; \ +} + + +#define ZMBV_ADD_XOR_BLOCK_TPL(_pxtype,_pxsize) \ +static inline void zmbv_add_xor_block_##_pxsize (zmbv_codec_t zc, int vx, int vy, zmbv_frame_block_t *block) { \ + _pxtype *pold = ((_pxtype *)zc->oldframe)+block->start+(vy*zc->pitch)+vx; \ + _pxtype *pnew = ((_pxtype *)zc->newframe)+block->start; \ + for (int y = 0; y < block->dy; ++y) { \ + for (int x = 0; x < block->dx; ++x) { \ + *((_pxtype *)&zc->work[zc->workUsed]) = pnew[x]^pold[x]; \ + zc->workUsed += sizeof(_pxtype); \ + } \ + pold += zc->pitch; \ + pnew += zc->pitch; \ + } \ +} + + +#define ZMBV_ADD_XOR_FRAME_TPL(_pxtype,_pxsize) \ +static inline void zmbv_add_xor_frame_##_pxsize (zmbv_codec_t zc) { \ + int8_t *vectors = (int8_t *)&zc->work[zc->workUsed]; \ + /* align the following xor data on 4 byte boundary */ \ + zc->workUsed = (zc->workUsed+zc->blockcount*2+3)&~3; \ + for (int b = 0; b < zc->blockcount; ++b) { \ + zmbv_frame_block_t *block = &zc->blocks[b]; \ + int bestvx = 0; \ + int bestvy = 0; \ + int bestchange = zmbv_compare_block_##_pxsize(zc, 0, 0, block); \ + int possibles = 64; \ + for (int v = 0; v < zc->vector_count && possibles; ++v) { \ + if (bestchange < 4) break; \ + int vx = zc->vector_table[v].x; \ + int vy = zc->vector_table[v].y; \ + if (zmbv_possible_block_##_pxsize(zc, vx, vy, block) < 4) { \ + --possibles; \ + if (possibles < 0) abort(); \ + int testchange = zmbv_compare_block_##_pxsize(zc, vx, vy, block); \ + if (testchange < bestchange) { \ + bestchange = testchange; \ + bestvx = vx; \ + bestvy = vy; \ + } \ + } \ + } \ + vectors[b*2+0] = (bestvx << 1); \ + vectors[b*2+1] = (bestvy << 1); \ + if (bestchange) { \ + vectors[b*2+0] |= 1; \ + zmbv_add_xor_block_##_pxsize(zc, bestvx, bestvy, block); \ + } \ + } \ +} + +/* generate functions */ +ZMBV_POSSIBLE_BLOCK_TPL(uint8_t, 8) +ZMBV_POSSIBLE_BLOCK_TPL(uint16_t,16) +ZMBV_POSSIBLE_BLOCK_TPL(uint32_t,32) + +ZMBV_COMPARE_BLOCK_TPL(uint8_t, 8) +ZMBV_COMPARE_BLOCK_TPL(uint16_t,16) +ZMBV_COMPARE_BLOCK_TPL(uint32_t,32) + +ZMBV_ADD_XOR_BLOCK_TPL(uint8_t, 8) +ZMBV_ADD_XOR_BLOCK_TPL(uint16_t,16) +ZMBV_ADD_XOR_BLOCK_TPL(uint32_t,32) + +ZMBV_ADD_XOR_FRAME_TPL(uint8_t, 8) +ZMBV_ADD_XOR_FRAME_TPL(uint16_t,16) +ZMBV_ADD_XOR_FRAME_TPL(uint32_t,32) + + +/* decoder templates */ +#ifdef ZMBV_INCLUDE_DECODER + +#define ZMBV_UNXOR_BLOCK_TPL(_pxtype,_pxsize) \ +static inline void zmbv_unxor_block_##_pxsize (zmbv_codec_t zc, int vx, int vy, zmbv_frame_block_t *block) { \ + _pxtype *pold = ((_pxtype *)zc->oldframe)+block->start+(vy*zc->pitch)+vx; \ + _pxtype *pnew = ((_pxtype *)zc->newframe)+block->start; \ + for (int y = 0; y < block->dy; ++y) { \ + for (int x = 0; x < block->dx; ++x) { \ + pnew[x] = pold[x]^*((_pxtype *)&zc->work[zc->workPos]); \ + zc->workPos += sizeof(_pxtype); \ + } \ + pold += zc->pitch; \ + pnew += zc->pitch; \ + } \ +} + + +#define ZMBV_COPY_BLOCK_TPL(_pxtype,_pxsize) \ +static inline void zmbv_copy_block_##_pxsize (zmbv_codec_t zc, int vx, int vy, zmbv_frame_block_t *block) { \ + _pxtype *pold = ((_pxtype *)zc->oldframe)+block->start+(vy*zc->pitch)+vx; \ + _pxtype *pnew = ((_pxtype *)zc->newframe)+block->start; \ + for (int y = 0; y < block->dy; ++y) { \ + for (int x = 0; x < block->dx; ++x) { \ + pnew[x] = pold[x]; \ + } \ + pold += zc->pitch; \ + pnew += zc->pitch; \ + } \ +} + + +#define ZMBV_UNXOR_FRAME_TPL(_pxtype,_pxsize) \ +static inline void zmbv_unxor_frame_##_pxsize (zmbv_codec_t zc) { \ + int8_t *vectors = (int8_t *)&zc->work[zc->workPos]; \ + zc->workPos = (zc->workPos+zc->blockcount*2+3)&~3; \ + for (int b = 0; b < zc->blockcount; ++b) { \ + zmbv_frame_block_t *block = &zc->blocks[b]; \ + int delta = vectors[b*2+0]&1; \ + int vx = vectors[b*2+0]>>1; \ + int vy = vectors[b*2+1]>>1; \ + if (delta) zmbv_unxor_block_##_pxsize(zc, vx, vy, block); else zmbv_copy_block_##_pxsize(zc, vx, vy, block); \ + } \ +} + +/* generate functions */ +ZMBV_UNXOR_BLOCK_TPL(uint8_t, 8) +ZMBV_UNXOR_BLOCK_TPL(uint16_t,16) +ZMBV_UNXOR_BLOCK_TPL(uint32_t,32) + +ZMBV_COPY_BLOCK_TPL(uint8_t, 8) +ZMBV_COPY_BLOCK_TPL(uint16_t,16) +ZMBV_COPY_BLOCK_TPL(uint32_t,32) + +ZMBV_UNXOR_FRAME_TPL(uint8_t, 8) +ZMBV_UNXOR_FRAME_TPL(uint16_t,16) +ZMBV_UNXOR_FRAME_TPL(uint32_t,32) + +#endif /* ZMBV_INCLUDE_DECODER */ + +/******************************************************************************/ +static void zmbv_create_vector_table (zmbv_codec_t zc) { + if (zc != NULL) { + zc->vector_table[0].x = zc->vector_table[0].y = 0; + zc->vector_count = 1; + for (int s = 1; s <= 10; ++s) { + for (int y = 0-s; y <= 0+s; ++y) { + for (int x = 0-s; x <= 0+s; ++x) { + if (abs(x) == s || abs(y) == s) { + zc->vector_table[zc->vector_count].x = x; + zc->vector_table[zc->vector_count].y = y; + ++zc->vector_count; + } + } + } + } + } +} + + +zmbv_codec_t zmbv_codec_new (zmvb_init_flags_t flags, int complevel) { + zmbv_codec_t zc = malloc(sizeof(*zc)); + if (zc != NULL) { + /* + zc->blocks = NULL; + zc->buf1 = NULL; + zc->buf2 = NULL; + zc->work = NULL; + memset(&zc->zstream, 0, sizeof(zc->zstream)); + zc->zstream_inited = 0; + */ + memset(zc, 0, sizeof(*zc)); + zc->init_flags = flags; + if (complevel < 0) complevel = 4; + else if (complevel > 9) complevel = 9; + zc->complevel = complevel; + zmbv_create_vector_table(zc); + zc->mode = ZMBV_MODE_UNKNOWN; + } + return zc; +} + + +static void zmbv_free_buffers (zmbv_codec_t zc) { + if (zc != NULL) { + if (zc->blocks != NULL) free(zc->blocks); + if (zc->buf1 != NULL) free(zc->buf1); + if (zc->buf2 != NULL) free(zc->buf2); + if (zc->work != NULL) free(zc->work); + zc->blocks = NULL; + zc->buf1 = NULL; + zc->buf2 = NULL; + zc->work = NULL; + } +} + + +static void zmbv_zlib_deinit (zmbv_codec_t zc) { + if (zc != NULL) { + switch (zc->zstream_inited) { + case -1: mz_deflateEnd(&zc->zstream); break; + case 1: mz_inflateEnd(&zc->zstream); break; + } + zc->zstream_inited = 0; + } +} + + +void zmbv_codec_free (zmbv_codec_t zc) { + if (zc != NULL) { + zmbv_zlib_deinit(zc); + zmbv_free_buffers(zc); + free(zc); + } +} + + +/******************************************************************************/ +int zmbv_get_width (zmbv_codec_t zc) { + return (zc != NULL ? zc->width : -1); +} + + +int zmbv_get_height (zmbv_codec_t zc) { + return (zc != NULL ? zc->height : -1); +} + + +/******************************************************************************/ +static int zmbv_setup_buffers (zmbv_codec_t zc, zmbv_format_t format, int blockwidth, int blockheight) { + if (zc != NULL) { + int xblocks, xleft, yblocks, yleft, i; + + zmbv_free_buffers(zc); + zc->palsize = 0; + switch (format) { + case ZMBV_FORMAT_8BPP: zc->pixelsize = 1; zc->palsize = 256; break; + case ZMBV_FORMAT_15BPP: case ZMBV_FORMAT_16BPP: zc->pixelsize = 2; break; + case ZMBV_FORMAT_32BPP: zc->pixelsize = 4; break; + default: return -1; + }; + zc->bufsize = (zc->height+2*MAX_VECTOR)*zc->pitch*zc->pixelsize+2048; + + zc->buf1 = malloc(zc->bufsize); + zc->buf2 = malloc(zc->bufsize); + zc->work = malloc(zc->bufsize); + + if (zc->buf1 == NULL || zc->buf2 == NULL || zc->work == NULL) { zmbv_free_buffers(zc); return -1; } + + xblocks = (zc->width/blockwidth); + xleft = zc->width%blockwidth; + if (xleft) ++xblocks; + yblocks = (zc->height/blockheight); + yleft = zc->height%blockheight; + if (yleft) ++yblocks; + + zc->blockcount = yblocks*xblocks; + zc->blocks = malloc(sizeof(zmbv_frame_block_t)*zc->blockcount); + if (zc->blocks == NULL) { zmbv_free_buffers(zc); return -1; } + + i = 0; + for (int y = 0; y < yblocks; ++y) { + for (int x = 0; x < xblocks; ++x) { + zc->blocks[i].start = ((y*blockheight)+MAX_VECTOR)*zc->pitch+(x*blockwidth)+MAX_VECTOR; + zc->blocks[i].dx = (xleft && x == xblocks-1 ? xleft : blockwidth); + zc->blocks[i].dy = (yleft && y == yblocks-1 ? yleft : blockheight); + ++i; + } + } + + memset(zc->buf1, 0, zc->bufsize); + memset(zc->buf2, 0, zc->bufsize); + memset(zc->work, 0, zc->bufsize); + zc->oldframe = zc->buf1; + zc->newframe = zc->buf2; + zc->format = format; + return 0; + } + return -1; +} + + +/******************************************************************************/ +int zmbv_encode_setup (zmbv_codec_t zc, int width, int height) { + if (zc != NULL && width > 0 && height > 0 && width <= 16384 && height <= 16384) { + zc->width = width; + zc->height = height; + zc->pitch = width+2*MAX_VECTOR; + zc->format = ZMBV_FORMAT_NONE; + zmbv_zlib_deinit(zc); + if ((zc->init_flags&ZMBV_INIT_FLAG_NOZLIB) == 0) { + if (mz_deflateInit(&zc->zstream, zc->complevel) != MZ_OK) return -1; + zc->zstream_inited = -1; + } + zc->mode = ZMBV_MODE_ENCODER; + return 0; + } + return -1; +} + + +/******************************************************************************/ +int zmbv_encode_prepare_frame (zmbv_codec_t zc, zmvb_prepare_flags_t flags, zmbv_format_t fmt, const void *pal, void *outbuf, int outbuf_size) { + uint8_t *firstByte; + const uint8_t *plt = (const uint8_t *)pal; + + if (zc == NULL) return -1; + if (zc->mode != ZMBV_MODE_ENCODER) return -1; + + /* check for valid formats */ + switch (fmt) { + case ZMBV_FORMAT_8BPP: + case ZMBV_FORMAT_15BPP: + case ZMBV_FORMAT_16BPP: + case ZMBV_FORMAT_32BPP: + break; + default: return -1; + } + + if (fmt != zc->format) { + if (zmbv_setup_buffers(zc, fmt, 16, 16) < 0) return -1; + flags |= ZMBV_PREP_FLAG_KEYFRAME; /* force a keyframe */ + } + + /* replace oldframe with new frame */ + { + uint8_t *copyFrame = zc->newframe; + zc->newframe = zc->oldframe; + zc->oldframe = copyFrame; + } + + zc->compress.lines_done = 0; + zc->compress.outbuf_size = outbuf_size; + zc->compress.write_done = 1; + zc->compress.outbuf = (uint8_t *)outbuf; + /* set a pointer to the first byte which will contain info about this frame */ + firstByte = zc->compress.outbuf; + *firstByte = 0; /* frame flags */ + /* reset the work buffer */ + zc->workUsed = 0; + zc->workPos = 0; + if (flags&ZMBV_PREP_FLAG_KEYFRAME) { + /* make a keyframe */ + *firstByte |= FRAME_MASK_KEYFRAME; + zmbv_keyframe_header_t *header = (zmbv_keyframe_header_t *)(zc->compress.outbuf+zc->compress.write_done); + header->high_version = DBZV_VERSION_HIGH; + header->low_version = DBZV_VERSION_LOW; + header->compression = ((zc->init_flags&ZMBV_INIT_FLAG_NOZLIB) == 0 ? COMPRESSION_ZLIB : COMPRESSION_NONE); + header->format = zc->format; + header->blockwidth = 16; + header->blockheight = 16; + zc->compress.write_done += sizeof(zmbv_keyframe_header_t); + /* copy the new frame directly over */ + if (zc->palsize) { + if (plt != NULL) { + memcpy(&zc->palette, plt, sizeof(zc->palette)); + } else { + memset(&zc->palette, 0, sizeof(zc->palette)); + } + /* keyframes get the full palette */ + for (int i = 0; i < zc->palsize; ++i) { + zc->work[zc->workUsed++] = zc->palette[i*3+0]; + zc->work[zc->workUsed++] = zc->palette[i*3+1]; + zc->work[zc->workUsed++] = zc->palette[i*3+2]; + } + } + /* restart deflate */ + if ((zc->init_flags&ZMBV_INIT_FLAG_NOZLIB) == 0) { + if (mz_deflateReset(&zc->zstream) != MZ_OK) return -1; + } + } else { + if (zc->palsize && plt != NULL && memcmp(plt, zc->palette, zc->palsize*3) != 0) { + *firstByte |= FRAME_MASK_DELTA_PALETTE; + for (int i = 0; i < zc->palsize; ++i) { + zc->work[zc->workUsed++] = zc->palette[i*3+0]^plt[i*3+0]; + zc->work[zc->workUsed++] = zc->palette[i*3+1]^plt[i*3+1]; + zc->work[zc->workUsed++] = zc->palette[i*3+2]^plt[i*3+2]; + } + memcpy(&zc->palette, plt, zc->palsize*3); + } + } + return 0; +} + + +/******************************************************************************/ +int zmbv_encode_lines (zmbv_codec_t zc, int line_count, const void *const line_ptrs[]) { + if (zc != NULL && zc->mode == ZMBV_MODE_ENCODER) { + int line_pitch = zc->pitch*zc->pixelsize; + int line_width = zc->width*zc->pixelsize; + uint8_t *destStart = zc->newframe+zc->pixelsize*(MAX_VECTOR+(zc->compress.lines_done+MAX_VECTOR)*zc->pitch); + int i = 0; + if (line_count > 0 && line_ptrs == NULL) return -1; + while (i < line_count && zc->compress.lines_done < zc->height) { + if (line_ptrs[i] == NULL) return -1; + memcpy(destStart, line_ptrs[i], line_width); + destStart += line_pitch; + ++i; + ++zc->compress.lines_done; + } + return 0; + } + return -1; +} + + +/******************************************************************************/ +int zmvb_encode_finish_frame (zmbv_codec_t zc) { + if (zc != NULL && zc->mode == ZMBV_MODE_ENCODER) { + uint8_t firstByte = *zc->compress.outbuf; + if (firstByte&FRAME_MASK_KEYFRAME) { + int i; + /* add the full frame data */ + const uint8_t *readFrame = zc->newframe+zc->pixelsize*(MAX_VECTOR+MAX_VECTOR*zc->pitch); + for (i = 0; i < zc->height; ++i) { + memcpy(&zc->work[zc->workUsed], readFrame, zc->width*zc->pixelsize); + readFrame += zc->pitch*zc->pixelsize; + zc->workUsed += zc->width*zc->pixelsize; + } + } else { + /* add the delta frame data */ + switch (zc->format) { + case ZMBV_FORMAT_8BPP: zmbv_add_xor_frame_8(zc); break; + case ZMBV_FORMAT_15BPP: case ZMBV_FORMAT_16BPP: zmbv_add_xor_frame_16(zc); break; + case ZMBV_FORMAT_32BPP: zmbv_add_xor_frame_32(zc); break; + default: return -1; /* the thing that should not be */ + } + } + if ((zc->init_flags&ZMBV_INIT_FLAG_NOZLIB) == 0) { + /* create the actual frame with compression */ + zc->zstream.next_in = (void *)zc->work; + zc->zstream.avail_in = zc->workUsed; + zc->zstream.total_in = 0; + zc->zstream.next_out = (void *)(zc->compress.outbuf+zc->compress.write_done); + zc->zstream.avail_out = zc->compress.outbuf_size-zc->compress.write_done; + zc->zstream.total_out = 0; + if (mz_deflate(&zc->zstream, MZ_SYNC_FLUSH) != MZ_OK) return -1; /* the thing that should not be */ + return (int)(zc->compress.write_done+zc->zstream.total_out); + } else { + memcpy(zc->compress.outbuf+zc->compress.write_done, zc->work, zc->workUsed); + return zc->workUsed+zc->compress.write_done; + } + } + return -1; +} + + +#ifdef ZMBV_INCLUDE_DECODER +/******************************************************************************/ +int zmbv_decode_setup (zmbv_codec_t zc, int width, int height) { + if (zc != NULL && width > 0 && height > 0 && width <= 16384 && height <= 16384) { + zc->width = width; + zc->height = height; + zc->pitch = width+2*MAX_VECTOR; + zc->format = ZMBV_FORMAT_NONE; + zmbv_zlib_deinit(zc); + if (mz_inflateInit(&zc->zstream) != MZ_OK) return -1; + zc->zstream_inited = 1; + zc->mode = ZMBV_MODE_DECODER; + zc->unpack_compression = 0; + return 0; + } + return -1; +} + + +/******************************************************************************/ +const uint8_t *zmbv_get_palette (zmbv_codec_t zc) { + return (zc != NULL ? zc->palette : NULL); +} + + +const void *zmbv_get_decoded_line (zmbv_codec_t zc, int idx) { + if (zc != NULL && zc->mode == ZMBV_MODE_DECODER && idx >= 0 && idx < zc->height) { + return zc->newframe+zc->pixelsize*(MAX_VECTOR+MAX_VECTOR*zc->pitch)+zc->pitch*zc->pixelsize*idx; + } + return NULL; +} + + +zmbv_format_t zmbv_get_decoded_format (zmbv_codec_t zc) { + return (zc != NULL ? zc->format : ZMBV_FORMAT_NONE); +} + +int zmbv_decode_palette_changed (zmbv_codec_t zc, const void *framedata, int size) { + return (zc != NULL && framedata != NULL && size > 0 ? (((const uint8_t *)framedata)[0]&FRAME_MASK_DELTA_PALETTE) != 0 : 0); +} + +/******************************************************************************/ +int zmbv_decode_frame (zmbv_codec_t zc, const void *framedata, int size) { + if (zc != NULL && framedata != NULL && size > 1 && zc->mode == ZMBV_MODE_DECODER) { + uint8_t tag; + const uint8_t *data = (const uint8_t *)framedata; + tag = *data++; + if (tag > 2) return -1; /* for now we can have only 0, 1 or 2 in tag byte */ + if (--size <= 0) return -1; + if (tag&FRAME_MASK_KEYFRAME) { + const zmbv_keyframe_header_t *header = (const zmbv_keyframe_header_t *)data; + size -= sizeof(zmbv_keyframe_header_t); + data += sizeof(zmbv_keyframe_header_t); + if (size <= 0) return -1; + if (header->low_version != DBZV_VERSION_LOW || header->high_version != DBZV_VERSION_HIGH) return -1; + if (header->compression > COMPRESSION_ZLIB) return -1; /* invalid compression mode */ + if (zc->format != (zmbv_format_t)header->format && zmbv_setup_buffers(zc, (zmbv_format_t)header->format, header->blockwidth, header->blockheight) < 0) return -1; + zc->unpack_compression = header->compression; + if (zc->unpack_compression == COMPRESSION_ZLIB) { + if (mz_inflateReset(&zc->zstream) != MZ_OK) return -1; + } + } + if (size > zc->bufsize) return -1; /* frame too big */ + if (zc->unpack_compression == COMPRESSION_ZLIB) { + zc->zstream.next_in = (void *)data; + zc->zstream.avail_in = size; + zc->zstream.total_in = 0; + zc->zstream.next_out = (void *)zc->work; + zc->zstream.avail_out = zc->bufsize; + zc->zstream.total_out = 0; + if (mz_inflate(&zc->zstream, MZ_SYNC_FLUSH/*MZ_NO_FLUSH*/) != MZ_OK) return -1; /* the thing that should not be */ + zc->workUsed = zc->zstream.total_out; + } else { + if (size > 0) memcpy(zc->work, data, size); + zc->workUsed = size; + } + zc->workPos = 0; + if (tag&FRAME_MASK_KEYFRAME) { + if (zc->palsize) { + for (int i = 0; i < zc->palsize; ++i) { + zc->palette[i*3+0] = zc->work[zc->workPos++]; + zc->palette[i*3+1] = zc->work[zc->workPos++]; + zc->palette[i*3+2] = zc->work[zc->workPos++]; + } + } + zc->newframe = zc->buf1; + zc->oldframe = zc->buf2; + uint8_t *writeframe = zc->newframe+zc->pixelsize*(MAX_VECTOR+MAX_VECTOR*zc->pitch); + for (int i = 0; i < zc->height; ++i) { + memcpy(writeframe, &zc->work[zc->workPos], zc->width*zc->pixelsize); + writeframe += zc->pitch*zc->pixelsize; + zc->workPos += zc->width*zc->pixelsize; + } + } else { + uint8_t *tmp = zc->oldframe; + zc->oldframe = zc->newframe; + zc->newframe = tmp; + if (tag&FRAME_MASK_DELTA_PALETTE) { + for (int i = 0; i < zc->palsize; ++i) { + zc->palette[i*3+0] ^= zc->work[zc->workPos++]; + zc->palette[i*3+1] ^= zc->work[zc->workPos++]; + zc->palette[i*3+2] ^= zc->work[zc->workPos++]; + } + } + switch (zc->format) { + case ZMBV_FORMAT_8BPP: zmbv_unxor_frame_8(zc); break; + case ZMBV_FORMAT_15BPP: case ZMBV_FORMAT_16BPP: zmbv_unxor_frame_16(zc); break; + case ZMBV_FORMAT_32BPP: zmbv_unxor_frame_32(zc); break; + default: return -1; /* the thing that should not be */ + } + } + return 0; + } + return -1; +} +#endif /* ZMBV_INCLUDE_DECODER */ diff --git a/src/Emulators/vice/gfxoutputdrv/zmbv.h b/src/Emulators/vice/gfxoutputdrv/zmbv.h new file mode 100644 index 00000000..65e6792f --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/zmbv.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2002-2013 The DOSBox Team + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * C translation by Ketmar // Invisible Vector + */ +#ifndef ZMBVC_H +#define ZMBVC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef enum { + ZMBV_FORMAT_NONE = 0x00, + /*ZMBV_FORMAT_1BPP = 0x01,*/ + /*ZMBV_FORMAT_2BPP = 0x02,*/ + /*ZMBV_FORMAT_4BPP = 0x03,*/ + ZMBV_FORMAT_8BPP = 0x04, + ZMBV_FORMAT_15BPP = 0x05, + ZMBV_FORMAT_16BPP = 0x06, + /*ZMBV_FORMAT_24BPP = 0x07,*/ + ZMBV_FORMAT_32BPP = 0x08 +} zmbv_format_t; + + +/* opaque codec data */ +typedef struct zmbv_codec_s *zmbv_codec_t; + + +/* utilities */ +/* returns ZMBV_FORMAT_NONE for unknown bpp */ +extern zmbv_format_t zmbv_bpp_to_format (int bpp); +/* returns <0 on error; 0 on ok */ +extern int zmbv_work_buffer_size (int width, int height, zmbv_format_t fmt); + + +typedef enum { + ZMBV_INIT_FLAG_NONE = 0, + ZMBV_INIT_FLAG_NOZLIB = 0x01 /* note that this will not 'turn off' zlib initializing */ +} zmvb_init_flags_t; + +/* complevel values */ +enum { + ZMBV_NO_COMPRESSION = 0, + ZMBV_BEST_SPEED = 1, + ZMBV_BEST_COMPRESSION = 9, + ZMBV_DEFAULT_COMPRESSION = -1 /* level 4 */ +}; + +extern zmbv_codec_t zmbv_codec_new (zmvb_init_flags_t flags, int complevel); +extern void zmbv_codec_free (zmbv_codec_t zc); + + +typedef enum { + ZMBV_PREP_FLAG_NONE = 0, + ZMBV_PREP_FLAG_KEYFRAME = 0x01 +} zmvb_prepare_flags_t; + +/* return <0 on error; 0 on ok */ +extern int zmbv_encode_setup (zmbv_codec_t zc, int width, int height); +/* palette for ZMBV_FORMAT_8BPP: 256 8-bit (r,g,b) triplets */ +/* return <0 on error; 0 on ok */ +extern int zmbv_encode_prepare_frame (zmbv_codec_t zc, zmvb_prepare_flags_t flags, zmbv_format_t fmt, const void *pal, void *outbuf, int outbuf_size); +/* return <0 on error; 0 on ok */ +extern int zmbv_encode_lines (zmbv_codec_t zc, int line_count, const void *const line_ptrs[]); +/* return <0 on error; 0 on ok */ +static inline int zmbv_encode_line (zmbv_codec_t zc, const void *line_data) { return zmbv_encode_lines(zc, 1, &line_data); } +/* return # of bytes written in outbuf or <0 on error; NEVER returns 0 */ +extern int zmvb_encode_finish_frame (zmbv_codec_t zc); + + +#ifdef ZMBV_INCLUDE_DECODER +/* return <0 on error; 0 on ok */ +extern int zmbv_decode_setup (zmbv_codec_t zc, int width, int height); +/* return <0 on error; 0 on ok */ +extern int zmbv_decode_frame (zmbv_codec_t zc, const void *framedata, int size); +/* return !0 if palette was be changed on this frame */ +extern int zmbv_decode_is_palette_changed (zmbv_codec_t zc, const void *framedata, int size); + +/* this can be called after zmbv_decode_frame() */ +extern const uint8_t *zmbv_get_palette (zmbv_codec_t zc); +/* this can be called after zmbv_decode_frame() */ +extern const void *zmbv_get_decoded_line (zmbv_codec_t zc, int idx) ; +/* this can be called after zmbv_decode_frame() */ +extern zmbv_format_t zmbv_get_decoded_format (zmbv_codec_t zc); +#endif + + +/* <0: error; 0: never */ +extern int zmbv_get_width (zmbv_codec_t zc); +extern int zmbv_get_height (zmbv_codec_t zc); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/Emulators/vice/gfxoutputdrv/zmbv_avi.c b/src/Emulators/vice/gfxoutputdrv/zmbv_avi.c new file mode 100644 index 00000000..e24c5f41 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/zmbv_avi.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2002-2013 The DOSBox Team + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * C translation by Ketmar // Invisible Vector + */ +#include "zmbv_avi.h" + +#include +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif +#include + +#include +#include + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define AVI_HEADER_SIZE (500) + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define HTOBE32(x) __builtin_bswap32(x) +# define BETOH32(x) __builtin_bswap32(x) +# define HTOBE16(x) __builtin_bswap16(x) +# define BETOH16(x) __builtin_bswap16(x) +# define HTOLE32(x) (x) +# define LETOH32(x) (x) +# define HTOLE16(x) (x) +# define LETOH16(x) (x) +#else +# define HTOBE32(x) (x) +# define BETOH32(x) (x) +# define HTOBE16(x) (x) +# define BETOH16(x) (x) +# define HTOLE32(x) __builtin_bswap32(x) +# define LETOH32(x) __builtin_bswap32(x) +# define HTOLE16(x) __builtin_bswap16(x) +# define LETOH16(x) __builtin_bswap16(x) +#endif + + +#define CODEC_4CC "ZMBV" + + +typedef struct zmbv_avi_s *zmbv_avi_t; + +struct zmbv_avi_s { + int fd; + uint8_t *index; + uint32_t indexsize, indexused; + uint32_t width, height; + double fps; + uint32_t frames; + uint32_t written; + //uint32_t audioused; // always 0 for now + uint32_t audiowritten; + uint32_t audiorate; // 44100? + int was_file_error; +}; + + +zmbv_avi_t zmbv_avi_start (const char *fname, int width, int height, double fps, int audiorate) { + if (fname != NULL && fname[0] && width > 0 && height > 0 && width <= 16384 && height <= 16384 && fps > 0 && fps <= 100) { + zmbv_avi_t zavi = malloc(sizeof(*zavi)); + if (zavi == NULL) return NULL; + memset(zavi, 0, sizeof(*zavi)); + zavi->fd = -1; + zavi->indexsize = 16*4096; + zavi->indexused = 8; + zavi->index = malloc(zavi->indexsize); + if (zavi->index == NULL) goto error; + zavi->fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_BINARY, 0644); + if (zavi->fd < 0) goto error; + zavi->width = width; + zavi->height = height; + zavi->fps = fps; + { + uint8_t eh[AVI_HEADER_SIZE]; + memset(eh, 0, sizeof(eh)); + if (write(zavi->fd, eh, sizeof(eh)) != sizeof(eh)) goto error; + } + zavi->frames = 0; + zavi->written = 0; + //zavi->audioused = 0; + zavi->audiorate = audiorate; + zavi->audiowritten = 0; + return zavi; +error: + if (zavi->fd >= 0) { + close(zavi->fd); + unlink(fname); + } + if (zavi->index != NULL) free(zavi->index); + free(zavi); + } + return NULL; +} + + +#define AVIOUT4(_S_) do { memcpy(&avi_header[header_pos], _S_, 4); header_pos += 4; } while (0) +#define AVIOUTw(_S_) do { uint16_t w = HTOLE16(_S_); memcpy(&avi_header[header_pos], &w, 2); header_pos += 2; } while (0) +#define AVIOUTd(_S_) do { uint32_t d = HTOLE32(_S_); memcpy(&avi_header[header_pos], &d, 4); header_pos += 4; } while (0) + +int zmbv_avi_stop (zmbv_avi_t zavi) { + int res = -1; + if (zavi != NULL) { + if (!zavi->was_file_error && zavi->fd >= 0) { + uint8_t avi_header[AVI_HEADER_SIZE]; + uint32_t main_list; + uint32_t header_pos = 0; + /* try and write an avi header */ + AVIOUT4("RIFF"); // riff header + AVIOUTd(AVI_HEADER_SIZE+zavi->written-8+zavi->indexused); + AVIOUT4("AVI "); + AVIOUT4("LIST"); // list header + main_list = header_pos; + AVIOUTd(0); // TODO size of list + AVIOUT4("hdrl"); + + AVIOUT4("avih"); + AVIOUTd(56); // # of bytes to follow + AVIOUTd((uint32_t)round(1000000.0f/zavi->fps)); // microseconds per frame + AVIOUTd(0); + AVIOUTd(0); // PaddingGranularity (whatever that might be) + AVIOUTd(0x110); // Flags, 0x10 has index, 0x100 interleaved + AVIOUTd(zavi->frames); // TotalFrames + AVIOUTd(0); // InitialFrames + AVIOUTd(2); // Stream count + AVIOUTd(0); // SuggestedBufferSize + AVIOUTd(zavi->width); // Width + AVIOUTd(zavi->height); // Height + AVIOUTd(0); // TimeScale: Unit used to measure time + AVIOUTd(0); // DataRate: Data rate of playback + AVIOUTd(0); // StartTime: Starting time of AVI data + AVIOUTd(0); // DataLength: Size of AVI data chunk + + // video stream list + AVIOUT4("LIST"); + AVIOUTd(4+8+56+8+40); // size of the list + AVIOUT4("strl"); + // video stream header + AVIOUT4("strh"); + AVIOUTd(56); // # of bytes to follow + AVIOUT4("vids"); // type + AVIOUT4(CODEC_4CC); // handler */ + AVIOUTd(0); // Flags + AVIOUTd(0); // Reserved, MS says: wPriority, wLanguage + AVIOUTd(0); // InitialFrames + AVIOUTd(1000000); // Scale + AVIOUTd((uint32_t)round(1000000.0f*zavi->fps)); // Rate: Rate/Scale == samples/second + AVIOUTd(0); // Start + AVIOUTd(zavi->frames); // Length + AVIOUTd(0); // SuggestedBufferSize + AVIOUTd(~0); // Quality + AVIOUTd(0); // SampleSize + AVIOUTd(0); // Frame + AVIOUTd(0); // Frame + // the video stream format + AVIOUT4("strf"); + AVIOUTd(40); // # of bytes to follow + AVIOUTd(40); // Size + AVIOUTd(zavi->width); // Width + AVIOUTd(zavi->height); // Height + //OUTSHRT(1); OUTSHRT(24); // Planes, Count + AVIOUTd(0); + AVIOUT4(CODEC_4CC); // Compression + AVIOUTd(zavi->width*zavi->height*4); // SizeImage (in bytes?) + AVIOUTd(0); // XPelsPerMeter + AVIOUTd(0); // YPelsPerMeter + AVIOUTd(0); // ClrUsed: Number of colors used + AVIOUTd(0); // ClrImportant: Number of colors important + + if (zavi->audiowritten > 0) { + // audio stream list + AVIOUT4("LIST"); + AVIOUTd(4+8+56+8+16); // Length of list in bytes + AVIOUT4("strl"); + // the audio stream header + AVIOUT4("strh"); + AVIOUTd(56); // # of bytes to follow + AVIOUT4("auds"); + AVIOUTd(0); // Format (Optionally) + AVIOUTd(0); // Flags + AVIOUTd(0); // Reserved, MS says: wPriority, wLanguage + AVIOUTd(0); // InitialFrames + AVIOUTd(4); // Scale + AVIOUTd(zavi->audiorate*4); // rate, actual rate is scale/rate + AVIOUTd(0); // Start + if (!zavi->audiorate) zavi->audiorate = 1; + AVIOUTd(zavi->audiowritten/4); // Length + AVIOUTd(0); // SuggestedBufferSize + AVIOUTd(~0); // Quality + AVIOUTd(4); // SampleSize + AVIOUTd(0); // Frame + AVIOUTd(0); // Frame + // the audio stream format + AVIOUT4("strf"); + AVIOUTd(16); // # of bytes to follow + AVIOUTw(1); // Format, WAVE_ZMBV_FORMAT_PCM + AVIOUTw(2); // Number of channels + AVIOUTd(zavi->audiorate); // SamplesPerSec + AVIOUTd(zavi->audiorate*4); // AvgBytesPerSec + AVIOUTw(4); // BlockAlign + AVIOUTw(16); // BitsPerSample + } + int nmain = header_pos-main_list-4; + // finish stream list, i.e. put number of bytes in the list to proper pos + int njunk = AVI_HEADER_SIZE-8-12-header_pos; + AVIOUT4("JUNK"); + AVIOUTd(njunk); + // fix the size of the main list + header_pos = main_list; + AVIOUTd(nmain); + header_pos = AVI_HEADER_SIZE-12; + AVIOUT4("LIST"); + AVIOUTd(zavi->written+4); // Length of list in bytes + AVIOUT4("movi"); + // first add the index table to the end + memcpy(zavi->index, "idx1", 4); + { + uint32_t d = HTOLE32(zavi->indexused-8); + memcpy(zavi->index+4, &d, 4); + if (write(zavi->fd, zavi->index, zavi->indexused) != zavi->indexused) goto quit; + } + // now replace the header + if (lseek(zavi->fd, 0, SEEK_SET) == (off_t)-1) goto quit; + if (write(zavi->fd, &avi_header, AVI_HEADER_SIZE) != AVI_HEADER_SIZE) goto quit; + res = 0; + } +quit: + if (zavi->fd >= 0) { if (close(zavi->fd) < 0 && res == 0) res = -1; } + if (zavi->index != NULL) free(zavi->index); + free(zavi); + } + return -1; +} + +#undef AVIOUT4 +#undef AVIOUTw +#undef AVIOUTd + + +int zmbv_avi_write_chunk (zmbv_avi_t zavi, const char tag[4], uint32_t size, const void *data, uint32_t flags) { + if (zavi != NULL && zavi->fd >= 0 && !zavi->was_file_error && (size == 0 || data != NULL)) { + uint8_t chunk[8]; + uint8_t *index; + uint32_t pos, writesize, d; + chunk[0] = tag[0]; + chunk[1] = tag[1]; + chunk[2] = tag[2]; + chunk[3] = tag[3]; + d = HTOLE32(size); + memcpy(&chunk[4], &d, 4); + // write the actual data + if (write(zavi->fd, chunk, 8) != 8) goto error; + writesize = (size+1)&~1; + if (size > 0 && write(zavi->fd, data, size) != size) goto error; + if (writesize != size) { + uint8_t b; + if (writesize-size != 1) abort(); // just in case + b = 0; + if (write(zavi->fd, &b, 1) != 1) goto error; + } + pos = zavi->written+4; + zavi->written += writesize+8; + if (zavi->indexused+16 >= zavi->indexsize) { + uint8_t *ni = realloc(zavi->index, zavi->indexsize+16*4096); + if (ni == NULL) goto error; + zavi->index = ni; + zavi->indexsize += 16*4096; + } + index = zavi->index+zavi->indexused; + zavi->indexused += 16; + index[0] = tag[0]; + index[1] = tag[1]; + index[2] = tag[2]; + index[3] = tag[3]; + d = HTOLE32(flags); + memcpy(index+4, &d, 4); + d = HTOLE32(pos); + memcpy(index+8, &d, 4); + d = HTOLE32(size); + memcpy(index+12, &d, 4); + return 0; +error: + zavi->was_file_error = 1; + } + return -1; +} + + +int zmbv_avi_write_chunk_video (zmbv_avi_t zavi, const void *framedata, int size) { + int res = -1; + if (zavi != NULL && zavi->fd >= 0 && !zavi->was_file_error && size > 1 && framedata != NULL) { + uint8_t b; + memcpy(&b, framedata, 1); + res = zmbv_avi_write_chunk(zavi, "00dc", size, framedata, (b&0x01 ? 0x10 : 0)); + if (res == 0) ++zavi->frames; + } + return res; +} + + +int zmbv_avi_write_chunk_audio (zmbv_avi_t zavi, const void *data, int size) { + if (zavi != NULL && zavi->fd >= 0 && !zavi->was_file_error && (size == 0 || data != NULL)) { + if (size < 0) return -1; + if (size == 0) return 0; + //int res = zmbv_avi_write_chunk(zavi, "01wb", zavi->audioused*4, zavi->audiobuf, 0); + int res = zmbv_avi_write_chunk(zavi, "01wb", size, data, 0); + //zavi->audiowritten = zavi->audioused*4; + zavi->audiowritten = size; + //zavi->audioused = 0; + return res; + } + return -1; +} diff --git a/src/Emulators/vice/gfxoutputdrv/zmbv_avi.h b/src/Emulators/vice/gfxoutputdrv/zmbv_avi.h new file mode 100644 index 00000000..753afee4 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/zmbv_avi.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2002-2013 The DOSBox Team + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * C translation by Ketmar // Invisible Vector + */ +#ifndef ZMBVC_AVI_H +#define ZMBVC_AVI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +typedef struct zmbv_avi_s *zmbv_avi_t; + +extern zmbv_avi_t zmbv_avi_start (const char *fname, int width, int height, double fps, int audiorate); +extern int zmbv_avi_stop (zmbv_avi_t zavi); + +extern int zmbv_avi_write_chunk (zmbv_avi_t zavi, const char tag[4], uint32_t size, const void *data, uint32_t flags); + +extern int zmbv_avi_write_chunk_video (zmbv_avi_t zavi, const void *framedata, int size); +extern int zmbv_avi_write_chunk_audio (zmbv_avi_t zavi, const void *data, int size); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/Emulators/vice/gfxoutputdrv/zmbvdrv.c b/src/Emulators/vice/gfxoutputdrv/zmbvdrv.c new file mode 100644 index 00000000..0e6e1041 --- /dev/null +++ b/src/Emulators/vice/gfxoutputdrv/zmbvdrv.c @@ -0,0 +1,772 @@ +/** \file zmbvdrv.c + * \brief zmbv movie driver using screenshot API + * + * \author groepaz + */ + +/* + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +/* #define DEBUG_ZMBV */ +/* #define DEBUG_ZMBV_FRAMES */ + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "cmdline.h" +#include "gfxoutput.h" +#include "lib.h" +#include "log.h" +#include "machine.h" +#include "maincpu.h" +#include "math.h" +#include "palette.h" +#include "resources.h" +#include "screenshot.h" +#include "uiapi.h" +#include "util.h" +#include "soundmovie.h" +#include "zmbvdrv.h" + +#include "zmbv.h" +#include "zmbv_avi.h" + +#ifdef DEBUG_ZMBV +#define LOG(x) log_printf x +#else +#define LOG(x) +#endif + +#ifdef DEBUG_ZMBV_FRAMES +#define LOGFRAMES(x) log_printf x +#else +#define LOGFRAMES(x) +#endif + +/******************************************************************************/ + +#define PALETTE_NUM_COLORS 256 +#define PALETTE_COLORS_BPP (8 * 3) + +#define PALETTE_SIZE (PALETTE_NUM_COLORS * (PALETTE_COLORS_BPP / 8)) + +#define VIDEO_BPP 8 + +#define MAX_AUDIO_BUFFER_SIZE (((44800 * 2) / 50) * 2) + +/* each KEYFRAME_INTERVAL frame will be key one */ +#define KEYFRAME_INTERVAL (300) + +/******************************************************************************/ + +static int frameno = 0; + +static zmvb_init_flags_t iflg = ZMBV_INIT_FLAG_NONE; + +static int complevel = -1; /* compression level, -1 means default */ +static int no_zlib = 0; + +static uint8_t cur_pal[PALETTE_SIZE]; + +static int16_t cur_audio[MAX_AUDIO_BUFFER_SIZE]; + +static zmbv_avi_t zavi; +static zmbv_codec_t zcodec; +static zmbv_format_t fmt; + +static int work_buffer_size; +static void *video_work_buffer = NULL; + +static int video_codec; +static int audio_codec; + +static uint8_t *cur_screen = NULL; + +/* general */ +static int file_init_done = 1; + +/* audio */ +static soundmovie_buffer_t zmbvdrv_audio_in; +static int audio_init_done = 0; +static int audio_is_open = 0; + +/* video */ +static int video_init_done = 0; +static int video_is_open = 0; +static int video_width, video_height; /* initialized by zmbvdrv_init_video */ + +static unsigned int framecounter; + +/* resources */ +static int format_index = 0; +static char *zmbv_format = NULL; + +/* these are dictated by the emulator */ +static int audio_freq = 48000; /* initialized by zmbv_soundmovie_init */ +static int audio_channels = 1; /* initialized by zmbv_soundmovie_init */ + +static double video_framerate = 50.125f; /* initialized by zmbvdrv_init_video */ + +CLOCK clk_startframe; +CLOCK clk_frame_cycles; +CLOCK clk_last_audio_frame; +CLOCK clk_this_audio_frame; +CLOCK clk_last_video_frame; +CLOCK clk_this_video_frame; + +static int zmbvdrv_init_file(void); + +/******************************************************************************/ + +#define AV_CODEC_ID_NONE 0 +#define AV_CODEC_ID_ZMBV 1 +#define AV_CODEC_ID_PCM_S16LE 2 + +static gfxoutputdrv_codec_t avi_audio_codeclist[] = { + { AV_CODEC_ID_PCM_S16LE, "PCM uncompressed" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t raw_audio_codeclist[] = { + { AV_CODEC_ID_NONE, "none" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t avi_video_codeclist[] = { + { AV_CODEC_ID_ZMBV, "ZMBV (lossless)" }, + { 0, NULL } +}; + +static gfxoutputdrv_codec_t raw_video_codeclist[] = { + { AV_CODEC_ID_ZMBV, "ZMBV (lossless)" }, + { 0, NULL } +}; + +#define VIDEO_OPTIONS \ + (GFXOUTPUTDRV_HAS_AUDIO_CODECS | \ + GFXOUTPUTDRV_HAS_VIDEO_CODECS) + +#define RAW_VIDEO_OPTIONS \ + (GFXOUTPUTDRV_HAS_VIDEO_CODECS) + +/* formatlist is filled from with available formats and codecs at init time */ +gfxoutputdrv_format_t *zmbvdrv_formatlist = NULL; +static gfxoutputdrv_format_t formats_to_test[] = +{ + { "raw", raw_audio_codeclist, raw_video_codeclist, RAW_VIDEO_OPTIONS }, + { "avi", avi_audio_codeclist, avi_video_codeclist, VIDEO_OPTIONS }, + { NULL, NULL, NULL, 0 } +}; + +static int set_container_format(const char *val, void *param) +{ + int i; + + /* kludge to prevent crash at startup when using --help on the commandline */ + if (zmbvdrv_formatlist == NULL) { + return 0; + } + + format_index = -1; + + for (i = 0; zmbvdrv_formatlist[i].name != NULL; i++) { + if (strcmp(val, zmbvdrv_formatlist[i].name) == 0) { + format_index = i; + } + } + format_index = 0; + + if (format_index < 0) { + return -1; + } + + util_string_set(&zmbv_format, val); + + return 0; +} + +static int set_audio_codec(int val, void *param) +{ + audio_codec = val; + return 0; +} + +static int set_video_codec(int val, void *param) +{ + video_codec = val; + return 0; +} + +/*---------- Resources ------------------------------------------------*/ + +static const resource_string_t resources_string[] = { + { "ZMBVFormat", "avi", RES_EVENT_NO, NULL, + &zmbv_format, set_container_format, NULL }, + RESOURCE_STRING_LIST_END +}; + +static const resource_int_t resources_int[] = { + { "ZMBVAudioCodec", AV_CODEC_ID_PCM_S16LE, RES_EVENT_NO, NULL, + &audio_codec, set_audio_codec, NULL }, + { "ZMBVVideoCodec", AV_CODEC_ID_ZMBV, RES_EVENT_NO, NULL, + &video_codec, set_video_codec, NULL }, + RESOURCE_INT_LIST_END +}; + +static int zmbvdrv_resources_init(void) +{ + LOG(("zmbvdrv_resources_init")); + if (resources_register_string(resources_string) < 0) { + return -1; + } + + return resources_register_int(resources_int); +} + +/*---------- Commandline options --------------------------------------*/ + +static const cmdline_option_t cmdline_options[] = +{ + CMDLINE_LIST_END +}; + +static int zmbvdrv_cmdline_options_init(void) +{ + LOG(("zmbvdrv_cmdline_options_init")); + return cmdline_register_options(cmdline_options); +} + +/*---------------------------------------------------------------------*/ + +/*-----------------------*/ +/* audio stream encoding */ +/*-----------------------*/ + +/* called by zmbvdrv_init_video -> zmbvdrv_init_file */ +static int zmbvdrv_open_audio(int speed, int channels) +{ + LOG(("zmbvdrv_open_audio(speed:%d channels:%d", speed, channels)); + + zmbvdrv_audio_in.buffer = lib_malloc(MAX_AUDIO_BUFFER_SIZE); /* is this correct? */ + if (zmbvdrv_audio_in.buffer == NULL) { + log_error(LOG_DEFAULT, "zmbvdrv: Error allocating audio buffer (%u bytes)", (unsigned)MAX_AUDIO_BUFFER_SIZE); + return -1; + } + zmbvdrv_audio_in.size = round((double)audio_freq / video_framerate); + LOG(("zmbvdrv_open_audio freq:%d fps:%f bufsize:%d", audio_freq, video_framerate, zmbvdrv_audio_in.size)); +#if 0 + memset(cur_audio, 0, zmbvdrv_audio_in.size * 2); + if (zmbv_avi_write_chunk_audio(zavi, &cur_audio[0], zmbvdrv_audio_in.size) < 0) { + LOG(("FATAL: can't write audio frame for screen #%d", 0)); + } +#endif + return 0; +} + +static void zmbvdrv_close_audio(void) +{ + LOG(("zmbvdrv_close_audio()")); + + audio_is_open = 0; + if(zmbvdrv_audio_in.buffer != NULL) { + lib_free(zmbvdrv_audio_in.buffer); + } + zmbvdrv_audio_in.buffer = NULL; + zmbvdrv_audio_in.size = 0; +} + +/* Soundmovie API soundmovie_funcs_t.init */ +/* called via zmbvdrv_soundmovie_funcs->init */ +static int zmbv_soundmovie_init(int speed, int channels, soundmovie_buffer_t ** audio_in) +{ + LOG(("zmbv_soundmovie_init(speed:%d channels: %d)", speed, channels)); + + audio_init_done = 1; + + *audio_in = &zmbvdrv_audio_in; + + (*audio_in)->size = 0; /* not allocated yet */ + (*audio_in)->used = 0; + + /* we do not support resampling */ + audio_freq = speed; + audio_channels = channels; + + if (video_init_done) { + zmbvdrv_init_file(); + } + + return 0; +} + +/* Soundmovie API soundmovie_funcs_t.encode */ +/* called via zmbvdrv_soundmovie_funcs->encode */ +/* triggered by soundffmpegaudio->write */ +static int zmbv_soundmovie_encode(soundmovie_buffer_t *audio_in) +{ + int ret = 0; + + clk_last_audio_frame = clk_this_audio_frame; + clk_this_audio_frame = maincpu_clk; + + LOGFRAMES(("zmbv_soundmovie_encode(size:%d used:%d channels:%d) clk:%ld frame:%d", + audio_in->size, audio_in->used, audio_channels, clk_this_audio_frame, frameno)); + + /* FIXME: we might have an endianess problem here, we might have to swap lo/hi on BE machines */ + if (audio_channels == 1) { + int i, o; +#if 1 + /* convert mono -> stereo */ + for (i = o = 0; i < audio_in->used; i++, o+=2) { + cur_audio[o] = audio_in->buffer[i]; + cur_audio[o+1] = audio_in->buffer[i]; + } + /* write avi chunks */ + if (zmbv_avi_write_chunk_audio(zavi, &cur_audio[0], audio_in->used * 4) < 0) { + LOG(("FATAL: can't write audio frame for screen #%d", frameno)); + ret = -1; + } +#else + /* FIXME: we should write the mono stream into the avi instead */ +#endif + } else if (audio_channels == 2) { + int i, o; + for (i = o = 0; i < audio_in->used; i+=2, o+=2) { + cur_audio[o] = audio_in->buffer[i]; + cur_audio[o+1] = audio_in->buffer[i+1]; + } + /* write avi chunks */ + if (zmbv_avi_write_chunk_audio(zavi, &audio_in->buffer[0], audio_in->used * 2) < 0) { + LOG(("FATAL: can't write audio frame for screen #%d", frameno)); + ret = -1; + } + } else { + ret = -1; + } + + audio_in->used = 0; + return ret; +} + +/* Soundmovie API soundmovie_funcs_t.close */ +/* called via ffmpegexedrv_soundmovie_funcs->close */ +static void zmbv_soundmovie_close(void) +{ + LOG(("zmbv_soundmovie_close()")); + /* just stop the whole recording */ + screenshot_stop_recording(); +} + +static soundmovie_funcs_t zmbvdrv_soundmovie_funcs = { + zmbv_soundmovie_init, + zmbv_soundmovie_encode, + zmbv_soundmovie_close +}; + +/*-----------------------*/ +/* video stream encoding */ +/*-----------------------*/ +static int zmbvdrv_fill_rgb_image(screenshot_t *screenshot) +{ + int x, y; + int dx, dy; + int bufferoffset; + int x_dim = screenshot->width; + int y_dim = screenshot->height; + + if ((video_width == 0) || (video_height == 0)) { + return 0; + } + + /* center the screenshot in the video */ + dx = (video_width - x_dim) / 2; + dy = (video_height - y_dim) / 2; + bufferoffset = screenshot->x_offset + (dx < 0 ? -dx : 0) + + (screenshot->y_offset + (dy < 0 ? -dy : 0)) * screenshot->draw_buffer_line_size; + + for (x = 0; x < PALETTE_NUM_COLORS; x++) { + cur_pal[(x * (PALETTE_COLORS_BPP / 8)) + 0] = screenshot->palette->entries[x].red; + cur_pal[(x * (PALETTE_COLORS_BPP / 8)) + 1] = screenshot->palette->entries[x].green; + cur_pal[(x * (PALETTE_COLORS_BPP / 8)) + 2] = screenshot->palette->entries[x].blue; + } + + LOGFRAMES(("zmbvdrv_fill_rgb_image video_width/height: %dx%d", video_width, video_height)); + for (y = 0; y < video_height; y++) { + for (x = 0; x < video_width; x++) { + cur_screen[(y * video_width) + x] = screenshot->draw_buffer[bufferoffset + x]; + } + bufferoffset += screenshot->draw_buffer_line_size; + } + LOGFRAMES(("zmbvdrv_fill_rgb_image done")); + + return 0; +} + +static uint8_t *zmbvdrv_alloc_picture(int width, int height) +{ + /* the pixel format is always 8bpp, with a 256 entries, 24bit, palette */ + LOG(("zmbvdrv_alloc_picture width:%d height:%d", width, height)); + return lib_malloc(width * height); +} + +/* called by zmbvdrv_init_file() */ +static int zmbvdrv_open_video(int width, int height) +{ + LOG(("zmbvdrv_open_video width:%d height:%d", width, height)); + /* MOVE? open the codec */ + video_is_open = 1; + /* FIXME: allocate the encoded raw picture */ + cur_screen = zmbvdrv_alloc_picture(width, height); + if (cur_screen == NULL) { + return -1; + } + return 0; +} + +/* called by zmbvdrv_close() */ +static void zmbvdrv_close_video(void) +{ + LOG(("zmbvdrv_close_video")); + video_is_open = 0; + if (cur_screen != NULL) { + lib_free (cur_screen); + cur_screen = NULL; + } +} +/* called by zmbvdrv_save */ +static void zmbvdrv_init_video(screenshot_t *screenshot) +{ + video_width = screenshot->width; + video_height = screenshot->height; + LOG(("zmbvdrv_init_video w:%d h:%d", video_width, video_height)); + video_init_done = 1; + { + double time_base, fps; + clk_frame_cycles = machine_get_cycles_per_frame(); + time_base = ((double)machine_get_cycles_per_frame()) / ((double) machine_get_cycles_per_second()); + fps = 1.0f / time_base; + LOG(("zmbvdrv_init_video fps: %f timebase: %f", fps, time_base)); + video_framerate = fps; + } + + framecounter = 0; + if (audio_init_done) { + zmbvdrv_init_file(); + } +} + +/* called by zmbvdrv_init_video */ +static int zmbvdrv_init_file(void) +{ + LOG(("zmbvdrv_init_file() video_init_done:%d audio_init_done:%d", video_init_done, audio_init_done)); + if (!video_init_done || !audio_init_done) { + return 0; + } + + if (zmbvdrv_open_audio(audio_freq, audio_channels) < 0) { + ui_error("zmbvdrv: Cannot open audio stream"); + screenshot_stop_recording(); + return -1; + } + + if (zmbvdrv_open_video(video_width, video_height) < 0) { + ui_error("zmbvdrv: Cannot open video stream"); + screenshot_stop_recording(); + return -1; + } + + log_debug(LOG_DEFAULT, "zmbvdrv: Initialized file successfully"); + + file_init_done = 1; + + return 0; +} + +/* Driver API gfxoutputdrv_t.save */ +/* called once to start recording video+audio */ +static int zmbvdrv_save(screenshot_t *screenshot, const char *filename) +{ + LOG(("zmbvdrv_save(filename:'%s')", filename)); + + audio_init_done = 0; + video_init_done = 0; + file_init_done = 0; + + /* complevel = 9; */ + /* no_zlib = 0; */ + + clk_startframe = maincpu_clk; + clk_this_video_frame = clk_this_audio_frame = clk_startframe; + LOG(("zmbvdrv_save start clock: %ld", clk_startframe)); + + if (no_zlib) { + iflg |= ZMBV_INIT_FLAG_NOZLIB; + } + LOG(("zmbvdrv_save using compression level %d", complevel)); + + zmbvdrv_init_video(screenshot); + + zavi = zmbv_avi_start(filename, video_width, video_height, video_framerate, audio_freq); + if (zavi == NULL) { + LOG(("FATAL: can't create output file!")); + return -1; + } + + /* init encoder */ + zcodec = zmbv_codec_new(iflg, complevel); + if (zcodec == NULL) { + LOG(("FATAL: can't create codec!")); + return -1; + } + fmt = zmbv_bpp_to_format(VIDEO_BPP); + work_buffer_size = zmbv_work_buffer_size(video_width, video_height, fmt); + video_work_buffer = malloc(work_buffer_size); + if (video_work_buffer == NULL) { + LOG(("FATAL: can't init buffer!")); + return -1; + } + if (zmbv_encode_setup(zcodec, video_width, video_height) < 0) { + LOG(("FATAL: can't init encoder!")); + free(video_work_buffer); + video_work_buffer = NULL; + return -1; + } + + frameno = 0; + + soundmovie_start(&zmbvdrv_soundmovie_funcs); + + return 0; +} + +/* Driver API gfxoutputdrv_t.close */ +static int zmbvdrv_close(screenshot_t *screenshot) +{ + /* write the trailer, if any */ + + soundmovie_stop(); + + zmbvdrv_close_video(); + zmbvdrv_close_audio(); + + /* close the output file */ + + /* free the streams */ + if (video_work_buffer != NULL) { free(video_work_buffer); video_work_buffer = NULL; } + zmbv_codec_free(zcodec); + + zmbv_avi_stop(zavi); + + /* free the stream */ + log_debug(LOG_DEFAULT, "zmbvdrv: Closed successfully"); + + file_init_done = 0; + + return 0; +} + +/* Driver API gfxoutputdrv_t.record */ +/* triggered by screenshot_record, periodically called to output video data stream */ +static int zmbvdrv_record(screenshot_t *screenshot) +{ + int ret = -1; + int32_t written; + int flags; + CLOCK clk_diff; + + if (audio_init_done && video_init_done && !file_init_done) { + zmbvdrv_init_file(); + } + + clk_last_video_frame = clk_this_video_frame; + clk_this_video_frame = maincpu_clk; + + if (clk_this_video_frame > clk_this_audio_frame) { + /* video ahead of audio */ + clk_diff = clk_this_video_frame - clk_this_audio_frame; + if (clk_diff > clk_frame_cycles) { + LOG(("zmbvdrv_record video>audio %ld %ld frame:%ld diff:%ld", clk_this_video_frame, clk_this_audio_frame, clk_frame_cycles, clk_diff)); + /*return 0;*/ /* skip this frame? */ + } + } else if (clk_this_audio_frame > clk_this_video_frame) { + /* audio is ahead of video */ + clk_diff = clk_this_audio_frame - clk_this_video_frame; + if (clk_diff > clk_frame_cycles) { + LOG(("zmbvdrv_record video