diff --git a/Makefile b/Makefile index 61ff25e..fa20235 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ CXXFLAGS += $(INCFLAGS) -g -Wall --std=c++11 -O2 LDFLAGS += -L/opt/local/lib LDLIBS += -lglfw -lao -framework OpenGL -framework Cocoa -framework IOkit -OBJECTS = apple2e.o dis6502.o fake6502.o interface.o gl_utility.o +OBJECTS = apple2e.o dis6502.o interface.o gl_utility.o +# fake6502.o # keyboard.o diff --git a/apple2e.cpp b/apple2e.cpp index 07407f3..cb74225 100644 --- a/apple2e.cpp +++ b/apple2e.cpp @@ -14,11 +14,19 @@ #include #include +#ifndef M_PI +#define M_PI 3.14159 +#endif + // Brad's 6502 #include "cpu6502.h" +#undef SUPPORT_FAKE_6502 + // Mike Chambers' 6502 +#ifdef SUPPORT_FAKE_6502 #include "fake6502.h" +#endif using namespace std; @@ -28,14 +36,14 @@ using namespace std; #define LK_HACK 1 -const unsigned int DEBUG_ERROR = 0x01; -const unsigned int DEBUG_WARN = 0x02; -const unsigned int DEBUG_DECODE = 0x04; -const unsigned int DEBUG_STATE = 0x08; -const unsigned int DEBUG_RW = 0x10; -const unsigned int DEBUG_BUS = 0x20; -const unsigned int DEBUG_FLOPPY = 0x40; -const unsigned int DEBUG_SWITCH = 0x80; +constexpr unsigned int DEBUG_ERROR = 0x01; +constexpr unsigned int DEBUG_WARN = 0x02; +constexpr unsigned int DEBUG_DECODE = 0x04; +constexpr unsigned int DEBUG_STATE = 0x08; +constexpr unsigned int DEBUG_RW = 0x10; +constexpr unsigned int DEBUG_BUS = 0x20; +constexpr unsigned int DEBUG_FLOPPY = 0x40; +constexpr unsigned int DEBUG_SWITCH = 0x80; volatile unsigned int debug = DEBUG_ERROR | DEBUG_WARN ; // | DEBUG_DECODE | DEBUG_STATE | DEBUG_RW; bool delete_is_left_arrow = true; @@ -74,7 +82,7 @@ struct system_clock const int machine_clock_rate = 14318180; -bool read_blob(char *name, unsigned char *b, size_t sz) +bool read_blob(const char *name, unsigned char *b, size_t sz) { FILE *fp = fopen(name, "rb"); if(fp == NULL) { @@ -124,7 +132,7 @@ static void add_map_entry(char *line) /** * Read a map file generated by ld65. Puts symbols into the address_to_function_name map. */ -static bool read_map(char *name) +static bool read_map(const char *name) { char line[100]; FILE *fp = fopen(name, "r"); @@ -403,7 +411,7 @@ struct DISKIIboard : board_base int track_number = 0; // physical track number - DOS and ProDOS only use even tracks unsigned int track_byte = 0; - void set_floppy(int number, char *name) // number 0 or 1; name = NULL to eject + void set_floppy(int number, const char *name) // number 0 or 1; name = NULL to eject { floppy_present[number] = false; if(name) { @@ -425,7 +433,7 @@ struct DISKIIboard : board_base typedef std::function floppy_activity_func; floppy_activity_func floppy_activity; - DISKIIboard(unsigned char diskII_rom[256], char *floppy0_name, char *floppy1_name, floppy_activity_func floppy_activity_) : + DISKIIboard(const unsigned char diskII_rom[256], const char *floppy0_name, const char *floppy1_name, floppy_activity_func floppy_activity_) : floppy_activity(floppy_activity_) { std::copy(diskII_rom, diskII_rom + 0x100, rom_C600.memory.begin()); @@ -737,6 +745,20 @@ struct MAINboard : board_base backed_region ram_6000 = {"ram_6000", 0x6000, 0x6000, RAM, ®ions, read_from_main_ram, write_to_main_ram}; backed_region ram_6000_x = {"ram_6000_x", 0x6000, 0x6000, RAM, ®ions, read_from_aux_ram, write_to_aux_ram}; + bool C08X_read_RAM; + bool C08X_write_RAM; + enum {BANK1, BANK2} C08X_bank; + + backed_region rom_D000 = {"rom_D000", 0xD000, 0x1000, ROM, ®ions, [&]{return !C08X_read_RAM;}}; + backed_region rom_E000 = {"rom_E000", 0xE000, 0x2000, ROM, ®ions, [&]{return !C08X_read_RAM;}}; + + backed_region ram1_main_D000 = {"ram1_main_D000", 0xD000, 0x1000, RAM, ®ions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}}; + backed_region ram2_main_D000 = {"ram2_main_D000", 0xD000, 0x1000, RAM, ®ions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}}; + backed_region ram_main_E000 = {"ram1_main_E000", 0xE000, 0x2000, RAM, ®ions, [&]{return C08X_read_RAM;}, [&]{return !ALTZP && C08X_write_RAM;}}; + backed_region ram1_main_D000_x = {"ram1_main_D000_x", 0xD000, 0x1000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}}; + backed_region ram2_main_D000_x = {"ram2_main_D000_x", 0xD000, 0x1000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}}; + backed_region ram_main_E000_x = {"ram1_main_E000_x", 0xE000, 0x2000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM;}, [&]{return ALTZP && C08X_write_RAM;}}; + enabled_func read_from_aux_text1 = [&]{return (RAMRD && !STORE80) || (STORE80 && PAGE2);}; enabled_func write_to_aux_text1 = [&]{return (RAMWRT && !STORE80) || (STORE80 && PAGE2);}; enabled_func read_from_main_text1 = [&]{return !read_from_aux_text1();}; @@ -757,20 +779,6 @@ struct MAINboard : board_base backed_region hires_page2 = {"hires_page2", 0x4000, 0x2000, RAM, ®ions, read_from_main_ram, write_to_main_ram}; backed_region hires_page2x = {"hires_page2x", 0x4000, 0x2000, RAM, ®ions, read_from_aux_ram, write_to_aux_ram}; - enum {BANK1, BANK2} C08X_bank; - bool C08X_read_RAM; - bool C08X_write_RAM; - - backed_region rom_D000 = {"rom_D000", 0xD000, 0x1000, ROM, ®ions, [&]{return !C08X_read_RAM;}}; - backed_region rom_E000 = {"rom_E000", 0xE000, 0x2000, ROM, ®ions, [&]{return !C08X_read_RAM;}}; - - backed_region ram1_main_D000 = {"ram1_main_D000", 0xD000, 0x1000, RAM, ®ions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}}; - backed_region ram2_main_D000 = {"ram2_main_D000", 0xD000, 0x1000, RAM, ®ions, [&]{return !ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return !ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}}; - backed_region ram_main_E000 = {"ram1_main_E000", 0xE000, 0x2000, RAM, ®ions, [&]{return C08X_read_RAM;}, [&]{return !ALTZP && C08X_write_RAM;}}; - backed_region ram1_main_D000_x = {"ram1_main_D000_x", 0xD000, 0x1000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK1);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK1);}}; - backed_region ram2_main_D000_x = {"ram2_main_D000_x", 0xD000, 0x1000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM && (C08X_bank == BANK2);}, [&]{return ALTZP && C08X_write_RAM && (C08X_bank == BANK2);}}; - backed_region ram_main_E000_x = {"ram1_main_E000_x", 0xE000, 0x2000, RAM, ®ions, [&]{return ALTZP && C08X_read_RAM;}, [&]{return ALTZP && C08X_write_RAM;}}; - set ignore_mmio = {0xC058, 0xC05A, 0xC05D, 0xC05F, 0xC061, 0xC062}; set banking_read_switches = { 0xC080, 0xC081, 0xC082, 0xC083, 0xC084, 0xC085, 0xC086, 0xC087, @@ -872,7 +880,7 @@ struct MAINboard : board_base typedef std::function (int num)> get_paddle_func; get_paddle_func get_paddle; clk_t paddles_clock_out[4]; - MAINboard(system_clock& clk_, unsigned char rom_image[32768], display_write_func display_write_, audio_flush_func audio_flush_, get_paddle_func get_paddle_) : + MAINboard(system_clock& clk_, const unsigned char rom_image[32768], display_write_func display_write_, audio_flush_func audio_flush_, get_paddle_func get_paddle_) : clk(clk_), internal_C800_ROM_selected(true), speaker_level(waveform[0]), @@ -905,11 +913,11 @@ struct MAINboard : board_base old_mode_settings = convert_switches_to_mode_settings(); } - virtual ~MAINboard() + ~MAINboard() { } - virtual void reset() + void reset() { // Partially from Apple //e Technical Reference // XXX need to double-check these against the actual hardware @@ -925,7 +933,7 @@ struct MAINboard : board_base internal_C800_ROM_selected = true; } - virtual bool read(int addr, unsigned char &data) + bool read(int addr, unsigned char &data) { if(debug & DEBUG_RW) printf("MAIN board read\n"); for(auto b : boards) { @@ -933,6 +941,12 @@ struct MAINboard : board_base return true; } } + for(auto r : regions_by_page[addr / 256]) { + if(r->read(addr, data)) { + if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from %s\n", addr, data, r->name.c_str()); + return true; + } + } if(io_region.contains(addr)) { if(exit_on_banking && (banking_read_switches.find(addr) != banking_read_switches.end())) { printf("bank switch control %04X, aborting\n", addr); @@ -1089,12 +1103,6 @@ struct MAINboard : board_base printf("unhandled MMIO Read at %04X\n", addr); fflush(stdout); exit(0); } - for(auto r : regions_by_page[addr / 256]) { - if(r->read(addr, data)) { - if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from %s\n", addr, data, r->name.c_str()); - return true; - } - } if((addr & 0xFF00) == 0xC300) { if(debug & DEBUG_SWITCH) printf("read 0x%04X, enabling internal C800 ROM\n", addr); internal_C800_ROM_selected = true; @@ -1114,7 +1122,7 @@ struct MAINboard : board_base } return false; } - virtual bool write(int addr, unsigned char data) + bool write(int addr, unsigned char data) { #if LK_HACK if(addr == 0xBFFE) { @@ -1206,12 +1214,31 @@ struct MAINboard : board_base #endif { display_write(addr, write_to_aux_text1(), data); + if(false && (addr >= 0x2000) && (addr <= 0x3FFF)) { + static FILE* memoryWritesFile = NULL; + if(memoryWritesFile == NULL) { + memoryWritesFile = fopen("memorydump.bin", "wb"); + } + unsigned long long c = clk * 1000000 / 14318; + uint16_t a = addr; + uint16_t d = data; + fwrite(&c, sizeof(c), 1, memoryWritesFile); + fwrite(&a, sizeof(a), 1, memoryWritesFile); + fwrite(&d, sizeof(d), 1, memoryWritesFile); + // printf(" { %lld, 0x%04X, 0x%02X }\n", clk * 1000000 / 14318, addr, data); + } } for(auto b : boards) { if(b->write(addr, data)) { return true; } } + for(auto r : regions_by_page[addr / 256]) { + if(r->write(addr, data)) { + if(debug & DEBUG_RW) printf("wrote %02X to 0x%04X in %s\n", addr, data, r->name.c_str()); + return true; + } + } if(io_region.contains(addr)) { if(exit_on_banking && (banking_write_switches.find(addr) != banking_write_switches.end())) { printf("bank switch control %04X, exiting\n", addr); @@ -1263,12 +1290,6 @@ struct MAINboard : board_base printf("unhandled MMIO Write at %04X\n", addr); fflush(stdout); exit(0); } - for(auto r : regions_by_page[addr / 256]) { - if(r->write(addr, data)) { - if(debug & DEBUG_RW) printf("wrote %02X to 0x%04X in %s\n", addr, data, r->name.c_str()); - return true; - } - } if(debug & DEBUG_WARN) printf("unhandled memory write to %04X\n", addr); if(exit_on_memory_fallthrough) { printf("unhandled memory write to %04X, exiting\n", addr); @@ -1280,7 +1301,7 @@ struct MAINboard : board_base struct bus_frontend { - board_base* board; + MAINboard* board; map > writes; map > reads; @@ -1315,6 +1336,8 @@ struct bus_frontend bus_frontend bus; +#ifdef SUPPORT_FAKE_6502 + extern "C" { uint8_t read6502(uint16_t address) @@ -1329,7 +1352,9 @@ void write6502(uint16_t address, uint8_t value) }; -void usage(char *progname) +#endif /* SUPPORT_FAKE_6502 */ + +void usage(const char *progname) { printf("\n"); printf("usage: %s [options] ROM.bin\n", progname); @@ -1354,38 +1379,9 @@ void cleanup(void) fflush(stderr); } +#ifdef SUPPORT_FAKE_6502 bool use_fake6502 = false; - -struct saved_inst { - int pc; - unsigned char bytes[4]; -}; - -void disassemble_previous_instructions(deque& previous_instructions) -{ - for(auto it : previous_instructions) { - int bytes; - string dis; - tie(bytes, dis) = disassemble_6502(it.pc, it.bytes); - printf("%s\n", dis.c_str()); - } -} - -const int max_previous_instructions = 100; - -void read_instruction_and_save(bus_frontend &bus, int pc, deque& previous_instructions) -{ - saved_inst inst; - - inst.pc = pc; - inst.bytes[0] = bus.read(pc + 0); - inst.bytes[1] = bus.read(pc + 1); - inst.bytes[2] = bus.read(pc + 2); - inst.bytes[3] = bus.read(pc + 3); - if(previous_instructions.size() > max_previous_instructions) - previous_instructions.pop_front(); - previous_instructions.push_back(inst); -} +#endif string read_bus_and_disassemble(bus_frontend &bus, int pc) { @@ -1542,16 +1538,20 @@ enum APPLE2Einterface::EventType process_events(MAINboard *board, bus_frontend& } } if(e.type == APPLE2Einterface::RESET) { bus.reset(); +#ifdef SUPPORT_FAKE_6502 if(use_fake6502) reset6502(); else +#endif cpu.reset(); } else if(e.type == APPLE2Einterface::REBOOT) { bus.reset(); board->momentary_open_apple(machine_clock_rate / (5 * 14)); +#ifdef SUPPORT_FAKE_6502 if(use_fake6502) reset6502(); else +#endif cpu.reset(); } else if(e.type == APPLE2Einterface::PAUSE) { pause_cpu = e.value; @@ -1602,7 +1602,7 @@ struct averaged_sequence averaged_sequence() : where(-1) { - for(int i = 0; i < LENGTH; i++) + for(unsigned int i = 0; i < LENGTH; i++) list[i] = 0; sum = 0; } @@ -1610,7 +1610,7 @@ struct averaged_sequence void add(TYPE value) { if(where == -1) { - for(int i = 0; i < LENGTH; i++) + for(unsigned int i = 0; i < LENGTH; i++) list[i] = value; sum = value * LENGTH; where = 0; @@ -1630,11 +1630,11 @@ struct averaged_sequence int main(int argc, char **argv) { - char *progname = argv[0]; + const char *progname = argv[0]; argc -= 1; argv += 1; - char *diskII_rom_name = NULL, *floppy1_name = NULL, *floppy2_name = NULL; - char *map_name = NULL; + const char *diskII_rom_name = NULL, *floppy1_name = NULL, *floppy2_name = NULL; + const char *map_name = NULL; bool mute = false; while((argc > 0) && (argv[0][0] == '-')) { @@ -1699,7 +1699,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - char *romname = argv[0]; + const char *romname = argv[0]; unsigned char b[32768]; if(!read_blob(romname, b, sizeof(b))) @@ -1716,8 +1716,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - system_clock clk; - MAINboard* mainboard; MAINboard::display_write_func display = [](int addr, bool aux, unsigned char data)->bool{return APPLE2Einterface::write(addr, aux, data);}; @@ -1762,10 +1760,10 @@ int main(int argc, char **argv) atexit(cleanup); +#ifdef SUPPORT_FAKE_6502 if(use_fake6502) reset6502(); - - deque previous_instructions; +#endif APPLE2Einterface::start(run_fast, diskII_rom_name != NULL, floppy1_name != NULL, floppy2_name != NULL); @@ -1796,14 +1794,21 @@ int main(int argc, char **argv) clk_t prev_clock = clk; while(clk - prev_clock < clocks_per_slice) { if(debug & DEBUG_DECODE) { - string dis = read_bus_and_disassemble(bus, use_fake6502 ? pc : cpu.pc); + string dis = read_bus_and_disassemble(bus, +#ifdef SUPPORT_FAKE_6502 + use_fake6502 ? pc : +#endif + cpu.pc); printf("%s\n", dis.c_str()); } +#ifdef SUPPORT_FAKE_6502 if(use_fake6502) { clockticks6502 = 0; step6502(); clk.add_cpu_cycles(clockticks6502); - } else { + } else +#endif + { cpu.cycle(); if(debug & DEBUG_STATE) print_cpu_state(cpu); @@ -1828,8 +1833,10 @@ int main(int argc, char **argv) chrono::time_point now = std::chrono::system_clock::now(); auto elapsed_millis = chrono::duration_cast(now - then); - if(!run_fast || pause_cpu) + + if(!run_fast || pause_cpu) { this_thread::sleep_for(chrono::milliseconds(clocks_per_slice * 1000 / machine_clock_rate) - elapsed_millis); + } then = now; @@ -1873,15 +1880,22 @@ int main(int argc, char **argv) continue; } if(debug & DEBUG_DECODE) { - string dis = read_bus_and_disassemble(bus, use_fake6502 ? pc : cpu.pc); + string dis = read_bus_and_disassemble(bus, +#ifdef SUPPORT_FAKE_6502 + use_fake6502 ? pc : +#endif + cpu.pc); printf("%s\n", dis.c_str()); } +#ifdef SUPPORT_FAKE_6502 if(use_fake6502) { clockticks6502 = 0; step6502(); clk.add_cpu_cycles(clockticks6502); - } else { + } else +#endif + { cpu.cycle(); if(debug & DEBUG_STATE) print_cpu_state(cpu); @@ -1894,6 +1908,7 @@ int main(int argc, char **argv) } APPLE2Einterface::shutdown(); + return 0; } int hires_visible_address_base[262] = diff --git a/gl_utility.cpp b/gl_utility.cpp index 3e8b748..7a51e32 100644 --- a/gl_utility.cpp +++ b/gl_utility.cpp @@ -128,7 +128,7 @@ bool CheckProgramLink(GLuint program) return false; } -void opengl_texture::load(int w_, int h_, unsigned char *pixels) +void opengl_texture::load(int w_, int h_, const unsigned char *pixels) { w = w_; h = h_; @@ -137,7 +137,7 @@ void opengl_texture::load(int w_, int h_, unsigned char *pixels) glBindTexture(GL_TEXTURE_2D, GL_NONE); } -opengl_texture initialize_texture(int w, int h, unsigned char *pixels) +opengl_texture initialize_texture(int w, int h, const unsigned char *pixels) { GLuint tex; diff --git a/gl_utility.h b/gl_utility.h index 9d78b1e..419f725 100644 --- a/gl_utility.h +++ b/gl_utility.h @@ -98,10 +98,10 @@ struct opengl_texture int h; GLuint t; operator GLuint() const { return t; } - void load(int w, int h, unsigned char *pixels = NULL); + void load(int w, int h, const unsigned char *pixels = NULL); }; -opengl_texture initialize_texture(int w, int h, unsigned char *pixels = NULL); +opengl_texture initialize_texture(int w, int h, const unsigned char *pixels = NULL); GLuint GenerateProgram(const std::string& shader_name, const std::string& vertex_shader_text, const std::string& fragment_shader_text); diff --git a/interface.cpp b/interface.cpp index 899e6b4..ca47610 100644 --- a/interface.cpp +++ b/interface.cpp @@ -59,7 +59,7 @@ int joystick_button0 = -1; int joystick_button1 = -1; extern int font_offset; -extern unsigned char font_bytes[96 * 7 * 8]; +extern const unsigned char font_bytes[96 * 7 * 8]; static int gWindowWidth, gWindowHeight; @@ -184,7 +184,8 @@ static const char *hires_vertex_shader = R"( raster_coords = vertex_coords; vec3 screen_coords = to_screen * vec3(vertex_coords + vec2(x_offset, y_offset), 1); gl_Position = vec4(screen_coords.x, screen_coords.y, .5, 1); - })"; + } +)"; static const char *image_fragment_shader = R"( in vec2 raster_coords; @@ -198,7 +199,8 @@ static const char *image_fragment_shader = R"( ivec2 tc = ivec2(raster_coords.x, raster_coords.y); float pixel = texture(image, raster_coords * image_coord_scale).x; color = vec4(pixel, pixel, pixel, 1); - })"; + } +)"; static const char *hires_fragment_shader = R"( in vec2 raster_coords; @@ -1305,8 +1307,18 @@ static void start_record() floppy_icon *floppy0_icon; floppy_icon *floppy1_icon; +uint8_t hgr_page1[8192]; + +void save_hgr() +{ + FILE *fp = fopen("hgr.bin", "wb"); + fwrite(hgr_page1, sizeof(hgr_page1), 1, fp); + fclose(fp); +} + void initialize_widgets(bool run_fast, bool add_floppies, bool floppy0_inserted, bool floppy1_inserted) { + momentary *hgr_momentary = new momentary("SNAP HGR", [](){save_hgr();}); momentary *reset_momentary = new momentary("RESET", [](){event_queue.push_back({RESET, 0});}); momentary *reboot_momentary = new momentary("REBOOT", [](){event_queue.push_back({REBOOT, 0});}); toggle *fast_toggle = new toggle("FAST", run_fast, [](){event_queue.push_back({SPEED, 1});}, [](){event_queue.push_back({SPEED, 0});}); @@ -1315,7 +1327,7 @@ void initialize_widgets(bool run_fast, bool add_floppies, bool floppy0_inserted, toggle *pause_toggle = new toggle("PAUSE", false, [](){event_queue.push_back({PAUSE, 1});}, [](){event_queue.push_back({PAUSE, 0});}); record_toggle = new toggle("RECORD", false, [](){start_record();}, [](){stop_record();}); - vector controls = {reset_momentary, reboot_momentary, fast_toggle, caps_toggle, color_toggle, pause_toggle, record_toggle}; + vector controls = {hgr_momentary, reset_momentary, reboot_momentary, fast_toggle, caps_toggle, color_toggle, pause_toggle, record_toggle}; if(false) { speed_textbox = new textbox("X.YYY MHz"); @@ -1890,6 +1902,7 @@ void write2(int addr, bool aux, unsigned char data) int row = scanout_address / 40; int col = scanout_address % 40; glBindTexture(GL_TEXTURE_2D, hires_texture[page]); + if(page == 0) hgr_page1[addr - 0x2000] = data; // XXX hack unsigned char pixels[8]; for(int i = 0; i < 8 ; i++) pixels[i] = ((data & (1 << i)) ? 255 : 0); @@ -2000,7 +2013,7 @@ void initialize_memory_to_scanout() } int font_offset = 32; -unsigned char font_bytes[96 * 7 * 8] = { +const unsigned char font_bytes[96 * 7 * 8] = { // 32 : 0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,