HTTP/1.1 200 OK Date: Mon, 04 Jul 2011 03:11:33 GMT Server: Apache Last-Modified: Sun, 06 Jun 2004 12:18:27 GMT ETag: "3832d-4e24-3dc30275bcac0" Accept-Ranges: bytes Content-Length: 20004 Content-Type: text/x-csrc Connection: close /* SEGA Dreamcast IP.BIN * * Hacked by Lars Olsson * * Questions, corrections etc: * jlo@ludd.luth.se * * Notes: * ~~~~~~ * * reg[REG] = access to register REG (including both normal * CPU registers aswell as CPU-related memory-mapped * registers, but NOT other hardware registers) * * * Most names have been made up by me and can be very misleading, * even to the point of being downright incorrect with regards to * their actual functions * * Beware: this source code is only meant to illustrate the function * of the BootROM and it is not a 100% translation of the actual code. * A number of short cuts and simplifications have been made in order * to clarify the operation, which was the purpose of this whole exercise. * * Compiling this source (in so far it is possible at all) will NOT * produce a proper BootROM! For a myriad of reasons... * */ #include "types.h" #include "bootROM.h" #include "hwregs.h" /******************************************************************************* * * START OF IP.BIN * ******************************************************************************/ /* This code is loaded from IP.BIN. The copy in ROM actually resides * at 80008000 instead */ void _ac008300() { reg[CCR] = 0x0000092b; reg[R15] = 0x7e001000; /* use cache as memory for stack */ init_splash_screen(); _ac00b700(); /* jump to bootstrap1 */ } void copy_to_framebuffer(image) /* _8c008330 */ uint32_t *image; { uint32_t width = 640; /* really not used! */ uint32_t height = 480; uint32_t *dst; uint32_t size = 640 * 480; dst = (uint32_t *)(0xa5200000 + (640 * 4 * 480)); do { *dst-- = *image++; } while (size-- != 0); } void memset4(arg1, arg2, arg3) /* 8c00836c */ uint32_t *dst; uint32_t size; uint32_t data; { dst += size; size *= 2; while (size-- != 0) { *dst-- = data; } } uint32_t get_video_cable() /* _8c008380 */ { uint32_t cable; cable = (*(uint16_t *)0xff800030 & 0x0300) | (*(uint32_t *)0xa0702c00 & 0xfffffcff); *(uint32_t *)0xa0702c00 = cable; return (cable); } void init_splash_screen() /* 8c0083a8 */ { clear_variables(); *(uint32_t *)0x8ced3d9c = 0; show_splash_screen(); } void clear_variables() /* _8c0083c0 */ { uint8_t *dst = (uint8_t *)0x8ced3d00; /* 1, R15 */ while (dst < (uint8_t *)0x8ced3da0) { *dst++ = 0; } } void show_splash_screen() /* 8c0083f8 */ { uint32_t old_SR; uint32_t video_mode; /* 9, R15 */ uint32_t i; /* 8, R15 */ uint32_t initial_time; /* 7, R15, j */ uint32_t current_time; /* 6, R15 */ uint32_t time_diff; /* 5, R15 */ uint32_t timeout; /* 4, R15 */ uint32_t finished; /* 3, R15 */ uint32_t delay; /* 2, R15 */ uint32_t max_loop; /* 1, R15 */ init_timer(); old_SR = (reg[SR]>>4) & 0x0000000f; reg[SR] = (reg[SR] & 0xffffff0f) | 0x000000f0; video_mode = get_video_mode(); reg[SR] = ((old_SR & 0x0000000f)<<4) | (reg[SR] & 0xffffff0f); switch (video_mode) { case 1: case 3: i = 8; break; case 4: /* VGA */ i = 9; break; default: i = 6; break; } /* _8c008460 */ old_SR = (reg[SR]>>4) & 0x0000000f; reg[SR] = (reg[SR] & 0xffffff0f) | 0x000000f0; init_graphics(i); reg[SR] = ((old_SR & 0x0000000f)<<4) | (reg[SR] & 0xffffff0f); /* render splash screen to framebuffer */ render_frame(i); set_display(1); /* wait a little while */ initial_time = get_timer(); max_loop = 0; finished = 0; while (finished == 0) { new_time = get_timer(); time_diff = get_time_difference(initial_time, new_time); timeout = convert_time(time_diff); delay = 0; while (delay++ < 1000); if (max_loop++ >= 4000) { finished = 1; } if (timeout >= 6000000) { break; } } /* 8c00851e */ sys_do_bioscall(0); /* boot5() */ } /* this renders images and text to framebuffer */ void render_frame(arg) /* 8c00853c */ uin32_t arg; { uint32_t weird_value; /* 0, R15 */ fill_8ced4000(arg, 0x00c0c0c0); weird_value = compute_weird_value(); print_text(340, 189, "PRODUCED BY OR"); /* *(uint32_t *)0x8c009d98 */ print_text(340, 213, "UNDER LICENSE FROM"); /* *(uint32_t *)0x8c009d9c */ print_text(340, 237, "SEGA ENTERPRISES, LTD"); /* *(uint32_t *)0x8c009da0 */ _8c008b68(337, 186, 780, 260); /* image? */ _8c00892c(weird_value); show_small_logo(); upload_image(); } void print_text(xpos, ypos, text) /* 8c0085cc */ uint16_t xpos; /* _0012, R15 */ uint16_t ypos; /* _0010, R15 */ sint8_t *text; /* _000c, R15 */ { uint32_t len; /* _0008, R15 */ uint16_t x; /* _0002, R15 */ uint16_t y; /* _0000, R15 */ uint32_t i; /* _0004, R15 */ len = strlen(text); x = xpos; y = ypos; i = 0; while (i < len) { /* 8c0085f8 */ if (text[i] == 'L' && text[i+1] == 'T') { print_char(&x, &y, 0x1f); /* print LTD glyph */ i += 2; } else { /* 8c00862c */ print_char(&x, &y, text[i]); i++; } } } void print_char(x, y, c) /* 8c008652 */ uint16_t *x; /* _0034, R15 */ uint16_t *y; /* _0030, R15 */ sint8_t c; /* _002f, R15 */ { uint8_t buf[20]; /* _0004, R15 */ uint32_t i; /* _0024, R15 */ uint32_t *p; /* _0020, R15 */ uint8_t *p2; /* _0000, R15 */ uint32_t j; /* _0028, R15 */ _8c009ba8(8, buf, (void *)0x8c009d40); /* bah...weird function */ if (c == ' ') { *x += 5; return; } /* find the char in a list */ p = (uint32_t *)0xac00b46e; p2 = (uint8_t *)0x8c009da4; i = 63; j = 0; while (j < 63) { if (p2[0] == c) { break; } p = p + p2[2]; p2 += 3; j++; } /* 8c0086de */ /* WORK TO DO HERE */ } void show_small_logo() /* 8c0087fc */ { mr_env_t env; mr_t mr; /* The palette buffer is placed right before the local framebuffer. * There exists a buffer overflow condition in the code that copies * the palette which means it's possible to overwrite the rendered * frame before it is shown! Unfortunately the size of the palette is * limited to a 16-bit integer which means it's not possible to write * enough data to cover the offending "PRODUCED BY..." text :( */ mr.palette = (uint8_t *)0x8ced3e00; mr.image = (uint8_t *)0x8c00b820; env.x = 300; /* position of logo */ env.y = 298; env.c = 0; env.d = 0; decode_small_logo(&mr, &env, 320, 90); } void upload_image() /* 8c008b4c */ { uint32_t *frame = (uint32_t *)0x8ced4000; uint32_t foo = 0; /* not used */ copy_to_framebuffer(frame); } /* copies sega logo probably */ void _8c008b68(a, b, c, d) /* 8c008b68 */ sint16_t x1; /* _000e, R15 */ sint16_t y1; /* _000c, R15 */ sint16_t x2; /* _000a, R15 */ sint16_t y2; /* _0008, R15 */ { uint32_t *d = (uint32_t *)0x8ced4000; /* _0004, R15 */ uint32_t i = 0; /* _0000, R15 */ d += (((((479 - y1) * 640) - x1) + 639) * 4); while (d < (((((479 - y2) * 640) - x2) + 639) * 4) + 0x8ced40000) { /* 8c008bc4 */ d++; _8c008c54 } } /* Now! This is a weird function indeed! */ void compute_weird_value() /* 8c0088b0 */ { uint32_t i = 0; /* _0014 R15 */ uint32_t j = 0; /* _0004 R15 */ uint8_t buf[12]; /* _0008 R15 */ copy_string(buf, "SEGAKATANA"); /* 8c009d48 */ while (j < sizeof(buf)) { /* 8c0088cc */ i += buf[j] * buf[j + 1]; j += 2; } /* 8c0088f6 */ /* i becomes 25747 after completing above */ /* what sync_cfg is, is a little harder to determine */ /* definitely 0x100, but perhaps also 0x10 (interlace) is set */ return ((PVR->sync_cfg & 0xffffff3f) * i); } /* weirdest yet... */ void _8c00892c(key) uint32_t key; { uint8_t buf1[] = { 0xef, 0xcd, 0xab, 0x89, }; /* _0000, R15 */ uint8_t buf2[] = { 0x67, 0x45, 0x23, 0x01, }; /* _0004, R15 */ uint16_t k; /* _000c, R15 */ uint8_t i; /* _000e, R15 */ uint8_t j; /* _000f, R15 */ if (key == 0x0067b768) { return; } for (k = 0; k < 6; k++) { /* 8c00894c */ j = buf2[0]; i = buf1[0]; *(uint32_t *)&buf2[0] = ((*(uint32_t *)&buf2[0])<<8) + i; *(uint32_t *)&buf2[0] = ((*(uint32_t *)&buf1[0])<<8) + j; } /* 8c00897a */ } void fill_8ced4000(arg, col) /* 8c008aa0 */ uint32_t arg, col; { memset4((uint32_t *)0x8ced4000, 0x0012c000, col); } void print_pixel(x, y, pixel) /* _8c008ad0 */ sint32_t x; /* _000c, R15 - 3, R15 */ sint32_t y; /* _0008, R15 - 2, R15 */ uint32_t pixel; /* _0004, R15 - 1, R15 */ { uint32_t *p: p = (((((479 - y) * 640) - x) + 639) * 4) + (uint32_t *)0x8ced4000; *p = pixel; } /* interesting */ void decode_small_logo(mr, env, w, h) /* 8c008d74 */ mr_t *mr; /* 11, _002c, R15 */ mr_env_t *env; /* 10, _0028, R15 */ sint16_t w; /* _0026, R15 */ sint16_t h; /* _0024, R15 */ { uint8_t *p = mr->image; /* _0020, 8, R15 */ uint8_t color; /* _001f, R15 */ uint32_t *p2; /* _0014, 5, R15 */ uint32_t j; /* _0010, 4, R15 */ uint32_t i; /* _000c, 3, R15 */ uint32_t len; /* _0004, R15 */ sint16_t cur_x; /* _0002, R15 */ sint16_t cur_y; /* _0000, R15 */ /* check if there is a small logo */ if (p[0] != 'M' || p[1] != 'R') { return; } /* 8c008daa */ p += 2; mr->size = (sint32_t)read_int(p); p += 8; /* p2 = image data */ p2 = (uint8_t *)(mr->image + (sint32_t)read_int(p)); p += 4; mr->width = (sint16_t)read_int(p); /* 8c008dea */ p += 4; mr->height = (sint16_t)read_int(p); p += 4; /* this doesn't seem to be used anywhere */ mr->foo = (sint16_t)read_int(p); p += 4; /* number of colors */ mr->colors = (sint16_t)read_int(p); p += 4; j = 0; /* This is an unsigned comparison but mr->colors is sign-extended */ /* No bounds checking but not easy to overwrite "PRODUCED.." text * because mr->colors is only 16-bit, and while it can be negative, * it will cause alot of thrashing when overwriting... */ while (j < mr->colors) { mr->palette[j] = read_int(p); p += 4; j++; } /* 8c008e5e */ p = p2; cur_x = 0; cur_y = 0; j = 0; /* this is an unsigned comparison but a signed multiplication */ while (j < (mr->width * mr->height)) { p += decompress_data(p, &len, &color); if (env->c == 2 && env->d == color) { /* 8c008e9e, transparency? never reached in any case */ j += len; cur_y += _8c009980(mr->width, cur_x + len); /* args in r0, r1 prolly */ cur_x = _8c009af0(mr->width, cur_x + len); /* args in r0, r1, prolly */ } else { /* 8c008ed2 */ i = 0; /* unsigned comparison */ while (i < len) { /* 8c008ee4 */ /* signed comparisons, both are sign-extended */ if (cur_x < w && cur_y < h) { /* 8c008efa */ /* this must print the pixel */ /* if cur_y is negative, it's possible to move the logo upwards */ print_pixel(env->x + cur_x, env->y + cur_y, mr->palette[color]); } /* 8c008f20 */ j++; /* 8c008f26 */ /* signed comparison */ if (++cur_x >= mr->width) { cur_x = 0; cur_y++; } /* 8c008f42 */ i++; } /* 8c008f50 */ } /* 8c008f50 */ } /* 8c008f64 */ } uint32_t decompress_data(p, len, color) /* 8c008f70 */ uint8_t *p; /* _000c, R15 - 3, R15 */ uint32_t *len; /* _0008, R15 - 2, R15 */ uint8_t *color; /* _0004, R15 - 1, R15 */ { uint32_t i; /* _0000, R15 */ *len = 0; i = 1; if (*p & 0x80 == 0) { *len = 1; *color = *p; return (i); } /* 8c008f9e */ while (*p & 0x80 != 0) { *len <<= 7; *len |= *len & 0x7f; p++; i++; } /* 8c008fd2 */ *color = *p; return (i); } sint8_t read_byte(p) /* 8c008fe8 */ sint8_t *p; { return (*p); } uint32_t read_int(p) /* _8c008ffc */ sint8_t *p; /* _000c, R15 - 3, R15 */ { uint32_t val; /* _0008, R15 - 2, R15 */ uint32_t j; /* _0004, R15 - 1, R15 */ val = 0; j = 0; while (j < 4) { val = val + (uint8_t)read_byte(p + j) << j*8; j++; } return (val); } void init_graphics(arg) /* 8c009074 */ uint32_t arg; { init_graphics2(arg); } /* this function is patched before execution starts */ void set_display(enable) /* 8c00908c */ uint32_t enable; { HOLLY->pend0 = 0x00000008; while (HOLLY->pend0 != 0x00000008); if (enable == 1) { /* 8c0090a8 */ PVR->fb_cfg1 = *(uint32_t *)0x8ced3d24; PVR->video_cfg = *(uint32_t *)0x8ced3d18; } else { /* 8c0090c4 */ PVR->video_cfg = *(uint32_t *)0x8ced3d18 | 0x00000008; /* here's the patched version: */ PVR->fb_cfg1 = *(uint32_t *)0x8ced3d24; /* and here's the unpatched one: * PVR->fb_cfg1 = 0x00000000; */ } } uint32_t init_PVR(arg) /* 8c0090f8 */ uint32_t arg; { uint32_t id; uint32_t i, fog; id = PVR->id; PVR->reset = 0x00000000; *(uint32_t *)0x8ced3d18 = (sysvars->unknown0<<16) | 0x08; *(uint32_t *)0x8ced3d24 = 0x0000000c; if (arg == 9) { *(uint32_t *)0x8ced3d24 |= 0x00800000; } PVR->border_col = 0x00c0c0c0; set_display(0); PVR->spansort_cfg = 0x00000101; PVR->fog_table_col = 0x007f7f7f; PVR->fog_vertex_col = 0x007f7f7f; PVR->fog_density = 0x0000ff07; fog = 0xfffe; for (i = 0; i < 128; i++) { ((uint32_t *)&PVR->fog_table)[i] = fog; /* weird */ fog = fog - 0x0101; } PVR->reset = 0x00000001; PVR->reset = 0x00000000; *HW32(0xa05f6884) = 0x00000000; *HW32(0xa05f6888) = 0x00000000; return (id); } void set_display_mode_regs(arg) /* 8c009214 */ uint32_t arg; { PVR->ta_opb_start = 0x000c2680; PVR->ta_opb_end = 0x0009e800; PVR->ta_ob_start = 0x00000000; PVR->ta_ob_end = 0x0009e740; PVR->tilebuf_size = 0x000e0013; PVR->ta_opb_cfg = 0x00100203; PVR->ta_opl_start = 0x000c2680; PVR->ta_init = 0x80000000; PVR->pclip_x = ((*_8ced3d00-1)<<16) & 0x07ff0000; PVR->pclip_y = ((*_8ced3d04-1)<<16) & 0x07ff0000; PVR->burst_cfg = 0x00093f39; PVR->sync_cfg = *(uint32_t *)0x8ced3d44; PVR->hborder = *(uint32_t *)0x8ced3d4c; PVR->vborder = *(uint32_t *)0x8ced3d50; PVR->sync_load = *(uint32_t *)0x8ced3d54; PVR->sync_width = *(uint32_t *)0x8ced3d58; PVR->render_addr1 = *(uint32_t *)0x8ced3d38; PVR->render_addr2 = *(uint32_t *)0x8ced3d40; PVR->fb_cfg2 = *(uint32_t *)0x8ced3d28; PVR->render_modulo = *(uint32_t *)0x8ced3d2c; PVR->display_addr1 = *(uint32_t *)0x8ced3d34; PVR->display_addr2 = *(uint32_t *)0x8ced3d3c; PVR->display_size = *(uint32_t *)0x8ced3d30; PVR->hpos_irq = *(uint32_t *)0x8ced3d48; PVR->shadow = 0x00000001; PVR->ob_cfg = 0x0027df77; PVR->half_offset = 0x00000007; PVR->luminance = 0x00008040; PVR->object_clip = 0x3f800000; PVR->tsp_clip = 0x00000000; PVR->bgplane_z = 0.000100; PVR->bgplane_cfg = 0x01000000; PVR->clamp_max = 0xffffffff; PVR->clamp_min = 0xff000000; PVR->tsp_cfg = *(uint32_t *)0x8ced3d10; PVR->border_col = *(uint32_t *)0x8ced3d14; PVR->scaler_cfg = *(uint32_t *)0x8ced3d5c; } /* This whole function is skipped because of patching! */ void clear_display_cable(arg) /* 8c00940a */ uint32_t arg; { /* unpatched: * if (arg == 9) { * *HW32(0xa0702c00) = *HW32(0xa0702c00) & 0x01; * } else { * *HW32(0xa0702c00) = (*HW32(0xa0702c00) & 0x01) | 0x00000300; * } */ } void set_display_mode_vars2(displaymode) /* 8c009488 */ uint32_t displaymode; /* 2, R15 */ { uint32_t i = 4; /* 1, R15 */ *(uint32_t *)0x8ced3d24 = 1; *(uint32_t *)0x8ced3d28 = 0; *(uint32_t *)0x8ced3d44 = 0x0100; *(uint32_t *)0x8ced3d18 = sysvars->unknown0<<16; *(uint32_t *)0x8ced3d24 |= 0x0000000c; *(uint32_t *)0x8ced3d28 |= 0x00000006; /* i'll bet that these are pvr display modes (pal, ntsc, vga) */ switch (displaymode & 0x0f) { case 0x01: /* 8c0094f0 */ displaymode = (displaymode & 0xffffff0f) | 0x00000010; *(uint32_t *)0x8ced3d24 |= 0x00800000; *(uint32_t *)0x8ced3d48 = 0x03450000; *(uint32_t *)0x8ced3d4c = 0x007e0345; *(uint32_t *)0x8ced3d50 = 0x00280208; *(uint32_t *)0x8ced3d54 = 0x020c0359; *(uint32_t *)0x8ced3d58 = 0x03f1933f; break; case 0x04: /* 8c009526 */ *(uint32_t *)0x8ced3d44 |= 0x00000090; *(uint32_t *)0x8ced3d48 = 0x034b0000; *(uint32_t *)0x8ced3d4c = 0x008d034b; *(uint32_t *)0x8ced3d50 = 0x002c026c; *(uint32_t *)0x8ced3d54 = 0x0270035f; *(uint32_t *)0x8ced3d58 = 0x07d6a53f; break; case 0x02: default: /* 8c009550 */ *(uint32_t *)0x8ced3d44 |= 0x00000050; *(uint32_t *)0x8ced3d48 = 0x03450000; *(uint32_t *)0x8ced3d4c = 0x007e0345; *(uint32_t *)0x8ced3d50 = 0x00240204; *(uint32_t *)0x8ced3d54 = 0x020c0359; *(uint32_t *)0x8ced3d58 = 0x07d6c63f; break; } /* 8c0095cc */ *(uint32_t *)0x8ced3d00 = 640; *(uint32_t *)0x8ced3d04 = 480; if (displaymode & 0x00000200) { *(uint32_t *)0x8ced3d34 = 0x00200000; *(uint32_t *)0x8ced3d3c = (640 * i) + 0x00200000; *(uint32_t *)0x8ced3d38 = 0x00600000; *(uint32_t *)0x8ced3d40 = (640 * i) + 0x00600000; *(uint32_t *)0x8ced3d30 = (((640 * i + 1)<<20) & 0x3ff00000) | ((((*(uint32_t *)0x8ced3d04>>1) - 1)<<10) & 0x000ffc00) | (((640 * i) - 1) & 0x000003ff); *(uint32_t *)0x8ced3d5c = 0x00000400; *(uint32_t *)0x8ced3d8c = 0x00000000; } else { /* 8c0096b4 */ *(uint32_t *)0x8ced3d30 = (((*(uint32_t *)0x8ced3d04 - 1)<<10) & 0x000ffc00) | (((640 * i) - 1) & 0x000003ff) | 0x00100000; *(uint32_t *)0x8ced3d5c = 0x00000400; *(uint32_t *)0x8ced3d34 = 0x00200000; *(uint32_t *)0x8ced3d3c = 0x00200000; *(uint32_t *)0x8ced3d38 = 0x00600000; *(uint32_t *)0x8ced3d40 = 0x00600000; *(uint32_t *)0x8ced3d8c = 0x00000000; } /* 8c009704 */ PVR->vpos_irq = 0x00150104; *(uint32_t *)0x8ced3d2c = (*(uint32_t *)0x8ced3d00 * i)/8; *(uint32_t *)0x8ced3d08 = (*(uint32_t *)0x8ced3d04 * *(uint32_t *)0x8ced3d2c) * 8; *(uint32_t *)0x8ced3d78 = 0x00000000; *(uint32_t *)0x8ced3d14 = 0x00c0c0c0; *(uint32_t *)0x8ced3d0c = 640; *(uint32_t *)0x8ced3d10 = 0x00000000; } void set_display_mode_vars(arg) /* 8c0097b4 */ uint32_t arg; { clear_display_cable(arg); switch (arg) { case 6: set_display_mode_vars2(0x00008212); break; case 8: set_display_mode_vars2(0x00008214); break; case 9: set_display_mode_vars2(0x00008111); break; default: set_display_mode_vars2(0x00008212); break; } } void init_graphics2(arg) /* 8c009830 */ int arg; { init_PVR(arg); set_display_mode_vars(arg); set_display_mode_regs(arg); } uint32_t get_video_mode() /* 8c009858 */ { uint32_t cable; uint8_t video; cable = get_video_cable(); video = sysvars->config.video_system; if (cable == 0) { return (4); } switch (video) { case '0': return (0); break; case '1': return (1); break; case '2': return (2); break; case '3': return (3); break; default: return (0); break; } } void copy_string(buf, string) /* 8c009c4c */ uint8_t *buf; uint8_t *string; { strcpy(buf, string); /* passes args in r0,r1 */ } /* takes args in r0, r1 */ uint8_t * strcpy(buf, string) /* _8c009c74 */ uint8_t *buf; uint8_t *string; { uint32_t i = 0; /* check for alignment i guess, but both addresses should always be * 32-bit aligned in bootROM */ if ((buf & 0x03 | string & 0x03) != 0) { /* so this should never happen */ while (1) { buf[i] = *string++; if (buf[i] == '\0') { return (buf); } buf[i+1] = *string++; if (buf[i+1] == '\0') { return (buf); } buf[i+2] = *string++; if (buf[i+2] == '\0') { return (buf); } buf[i+3] = *string++; if (buf[i+3] == '\0') { return (buf); } } } /* 8c009cb8 */ /* weird here, skips first two instructions of a function :/ */ strcpy4+4(buf, string); } /* it seems this will just make a 32-bit copy instead */ void strcpy4(buf, string) /* 8c009cc4 */ uint32_t *buf; uint32_t *string; { uint32_t val; if (*string == 0x00000000) { } } uint32_t strlen(s) /* 8c009c62 */ uint8_t *s; { uint32_t n = 0; while (*s++) { n++; } return (n); } void init_timer() /* 8c009dec */ { reg[TOCR] = 0x00; reg[TSTR] = reg[TSTR] & 0xfe; reg[TCR0] = 0x0002; reg[TCOR0] = 0xffffffff; reg[TCNT0] = 0xffffffff; reg[TSTR] = reg[TSTR] | 0x01; } uint32_t get_timer() /* 8c009e12 */ { return (0xffffffff - *(volatile uin32_t *)0xffd8000c); } uint32_t get_time_difference(time1, time2) /* 8c009e1c */ uint32_t time1, time2; { return (time2, time1); } uint32_t convert_time(time) /* 8c009e24 */ uint32_t time; { /* WORK TO DO HERE */ } /******************************************************************************* * * END OF IP.BIN * ******************************************************************************/