# HG changeset patch # User Mike Pavone # Date 1355825802 28800 # Node ID 3b79cbcf68469e5e7839a0d277394f1bac6608a1 # Parent 44e661913a5152c14f61afbc42dbf1556c87ee40 Get Flavio's color bar demo kind of sort of working diff -r 44e661913a51 -r 3b79cbcf6846 68kinst.c --- a/68kinst.c Sun Dec 16 22:25:29 2012 -0800 +++ b/68kinst.c Tue Dec 18 02:16:42 2012 -0800 @@ -1223,7 +1223,11 @@ strcpy(dst+ret, cond_mnem[decoded->extra.cond]); ret = strlen(dst); if (decoded->op != M68K_SCC) { - ret += sprintf(dst+ret, " #%d <%X>", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed); + if (decoded->op == M68K_DBCC) { + ret += sprintf(dst+ret, " d%d, #%d <%X>", decoded->dst.params.regs.pri, decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed); + } else { + ret += sprintf(dst+ret, " #%d <%X>", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed); + } return ret; } break; diff -r 44e661913a51 -r 3b79cbcf6846 Makefile --- a/Makefile Sun Dec 16 22:25:29 2012 -0800 +++ b/Makefile Tue Dec 18 02:16:42 2012 -0800 @@ -1,6 +1,9 @@ LIBS=sdl -all : dis trans stateview +all : dis trans stateview blastem + +blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o vdp.o render_sdl.o + $(CC) -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o runtime.o mem.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)` dis : dis.o 68kinst.o $(CC) -o dis dis.o 68kinst.o diff -r 44e661913a51 -r 3b79cbcf6846 m68k_to_x86.c --- a/m68k_to_x86.c Sun Dec 16 22:25:29 2012 -0800 +++ b/m68k_to_x86.c Tue Dec 18 02:16:42 2012 -0800 @@ -151,6 +151,30 @@ ea->mode = MODE_REG_DIRECT; ea->base = SCRATCH1; break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + if (inst->src.addr_mode == MODE_ABSOLUTE) { + out = cycles(out, BUS*2); + } else { + out = cycles(out, BUS); + } + out = mov_ir(out, inst->src.params.immed, SCRATCH1, SZ_D); + out = check_cycles(out); + switch (inst->extra.size) + { + case OPSIZE_BYTE: + out = call(out, (char *)m68k_read_byte_scratch1); + break; + case OPSIZE_WORD: + out = call(out, (char *)m68k_read_word_scratch1); + break; + case OPSIZE_LONG: + out = call(out, (char *)m68k_read_long_scratch1); + break; + } + ea->mode = MODE_REG_DIRECT; + ea->base = SCRATCH1; + break; case MODE_IMMEDIATE: if (inst->variant != VAR_QUICK) { if (inst->extra.size == OPSIZE_LONG) { @@ -332,6 +356,10 @@ x86_ea src; dst = translate_m68k_src(inst, &src, dst, opts); reg = native_reg(&(inst->dst), opts); + //update statically set flags + dst = mov_ir(dst, 0, FLAG_V, SZ_B); + dst = mov_ir(dst, 0, FLAG_C, SZ_B); + if (src.mode == MODE_REG_DIRECT) { flags_reg = src.base; } else { @@ -362,6 +390,9 @@ } else { dst = mov_irdisp8(dst, src.disp, CONTEXT, reg_offset(&(inst->dst)), inst->extra.size); } + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); break; case MODE_AREG_PREDEC: dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : 1); @@ -386,6 +417,9 @@ } else { dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); } + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); switch (inst->extra.size) { case OPSIZE_BYTE: @@ -407,6 +441,40 @@ } } break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + if (src.mode == MODE_REG_DIRECT) { + if (src.base != SCRATCH1) { + dst = mov_rr(dst, src.base, SCRATCH1, inst->extra.size); + } + } else if (src.mode == MODE_REG_DISPLACE8) { + dst = mov_rdisp8r(dst, src.base, src.disp, SCRATCH1, inst->extra.size); + } else { + dst = mov_ir(dst, src.disp, SCRATCH1, inst->extra.size); + } + if (inst->dst.addr_mode == MODE_ABSOLUTE) { + dst = cycles(dst, BUS*2); + } else { + dst = cycles(dst, BUS); + } + dst = mov_ir(dst, inst->dst.params.immed, SCRATCH2, SZ_D); + dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); + dst = setcc_r(dst, CC_Z, FLAG_Z); + dst = setcc_r(dst, CC_S, FLAG_N); + dst = check_cycles(dst); + switch (inst->extra.size) + { + case OPSIZE_BYTE: + dst = call(dst, (char *)m68k_write_byte); + break; + case OPSIZE_WORD: + dst = call(dst, (char *)m68k_write_word); + break; + case OPSIZE_LONG: + dst = call(dst, (char *)m68k_write_long_highfirst); + break; + } + break; default: printf("address mode %d not implemented (move dst)\n", inst->dst.addr_mode); exit(1); @@ -414,12 +482,6 @@ //add cycles for prefetch dst = cycles(dst, BUS); - //update flags - dst = mov_ir(dst, 0, FLAG_V, SZ_B); - dst = mov_ir(dst, 0, FLAG_C, SZ_B); - dst = cmp_ir(dst, 0, flags_reg, inst->extra.size); - dst = setcc_r(dst, CC_Z, FLAG_Z); - dst = setcc_r(dst, CC_S, FLAG_N); dst = check_cycles(dst); return dst; } diff -r 44e661913a51 -r 3b79cbcf6846 m68k_to_x86.h --- a/m68k_to_x86.h Sun Dec 16 22:25:29 2012 -0800 +++ b/m68k_to_x86.h Tue Dec 18 02:16:42 2012 -0800 @@ -35,6 +35,8 @@ uint32_t target_cycle; uint32_t current_cycle; uint16_t *mem_pointers[NUM_MEM_AREAS]; + void *next_context; + uint16_t value; native_map_slot *native_code_map; void *options; } m68k_context; @@ -44,3 +46,5 @@ void start_68k_context(m68k_context * context, uint32_t address); void init_x86_68k_opts(x86_68k_options * opts); void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); +void m68k_reset(m68k_context * context); + diff -r 44e661913a51 -r 3b79cbcf6846 render.h --- a/render.h Sun Dec 16 22:25:29 2012 -0800 +++ b/render.h Tue Dec 18 02:16:42 2012 -0800 @@ -5,6 +5,7 @@ void render_init(int width, int height); void render_context(vdp_context * context); void render_wait_quit(vdp_context * context); +void wait_render_frame(vdp_context * context); #endif //RENDER_SDL_H_ diff -r 44e661913a51 -r 3b79cbcf6846 render_sdl.c --- a/render_sdl.c Sun Dec 16 22:25:29 2012 -0800 +++ b/render_sdl.c Tue Dec 18 02:16:42 2012 -0800 @@ -6,6 +6,8 @@ SDL_Surface *screen; uint8_t render_dbg = 0; +uint32_t last_frame = 0; + void render_init(int width, int height) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { @@ -31,6 +33,7 @@ uint16_t *buf_16; uint32_t *buf_32; uint8_t b,g,r; + last_frame = SDL_GetTicks(); if (SDL_MUSTLOCK(screen)) { if (SDL_LockSurface(screen) < 0) { return; @@ -43,7 +46,6 @@ } else { repeat_y = repeat_x; } - printf("w: %d, h: %d, repeat_x: %d, repeat_y: %d\n", screen->clip_rect.w, screen->clip_rect.h, repeat_x, repeat_y); switch (screen->format->BytesPerPixel) { case 2: buf_16 = (uint16_t *)screen->pixels; @@ -151,3 +153,38 @@ } } +#define FRAME_DELAY 16 +#define MIN_DELAY 10 + +void wait_render_frame(vdp_context * context) +{ + SDL_Event event; + while(SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + //TODO: Update emulated gamepads + if (event.key.keysym.sym == SDLK_LEFTBRACKET) { + render_dbg = !render_dbg; + render_context(context); + } + break; + case SDL_QUIT: + exit(0); + } + } + //TODO: Adjust frame delay so we actually get 60 FPS rather than 62.5 FPS + uint32_t current = SDL_GetTicks(); + uint32_t desired = last_frame + FRAME_DELAY; + if (current < desired) { + uint32_t delay = last_frame + FRAME_DELAY - current; + //TODO: Calculate MIN_DELAY at runtime + if (delay > MIN_DELAY) { + SDL_Delay((delay/MIN_DELAY)*MIN_DELAY); + } + while ((desired) < SDL_GetTicks()) { + } + } + render_context(context); +} + + diff -r 44e661913a51 -r 3b79cbcf6846 runtime.S --- a/runtime.S Sun Dec 16 22:25:29 2012 -0800 +++ b/runtime.S Tue Dec 18 02:16:42 2012 -0800 @@ -1,15 +1,42 @@ .global handle_cycle_limit handle_cycle_limit: + call m68k_save_context + mov %rsi, %rdi + call sync_components + mov %rax, %rsi + call m68k_load_context + ret + +do_vdp_port_write: + call m68k_save_context + mov %rcx, %rdx + call vdp_port_write + mov %rax, %rsi + call m68k_load_context + ret + +do_vdp_port_read: + call m68k_save_context + call vdp_port_read + mov %rax, %rsi + call m68k_load_context + mov 120(%rsi), %cx ret +bad_access_msg: + .asciz "Program tried to access illegal 68K address %X\n" + .global m68k_write_word + .global vdp_psg_w m68k_write_word: and $0xFFFFFF, %rdi cmp $0x400000, %edi jle cart_w cmp $0xE00000, %edi jge workram_w + cmp $0xC00000, %edi + jge vdp_psg_w jmp inccycles workram_w: and $0xFFFF, %rdi @@ -18,6 +45,48 @@ cart_w: mov %cx, (%r8, %rdi) jmp inccycles +vdp_psg_w: + test $0x2700E0, %edi + jnz crash + and $0x1F, %edi + cmp $4, %edi + jl try_fifo_write + jmp do_vdp_port_write +try_fifo_write: + push %rdx + push %rbx + /* fetch VDP context pointer from 68K context */ + mov 112(%rsi), %rdx + /* get fifo_cur and compare it to fifo_end */ + mov (%rdx), %rbx + cmp %rbx, 8(%rdx) + /* bail out if fifo is full */ + je fifo_fallback + /* populate FIFO entry */ + mov %cx, 4(%rbx) /* value */ + movb $0, 6(%rbx) /* partial */ + mov %eax, %ecx + shl $3, %ecx /* multiply by 68K cycle by 7 to get MCLK cycle */ + sub %eax, %ecx + mov %ecx, (%rbx) /* cycle */ + /* update fifo_cur and store back in 68K context */ + add $8, %rbx + mov %rbx, (%rdx) + /* clear pending flag */ + andb $0xEF, 19(%rdx) + pop %rbx + pop %rdx + jmp inccycles +fifo_fallback: + pop %rbx + pop %rdx + jmp do_vdp_port_write +crash: + mov %edi, %esi + lea bad_access_msg(%rip), %rdi + call printf + mov $1, %rdi + call exit .global m68k_write_byte m68k_write_byte: @@ -64,20 +133,26 @@ jle cart cmp $0xE00000, %ecx jge workram + cmp $0xC00000, %edi + jge vdp_psg xor %cx, %cx + dec %cx jmp inccycles workram: and $0xFFFF, %rcx mov (%r9, %rcx), %cx jmp inccycles +vdp_psg: + test $0x2700E0, %edi + jnz crash + and $0x1F, %edi + jmp do_vdp_port_read cart: mov (%r8, %rcx), %cx inccycles: add $4, %rax cmp %rbp, %rax - jge sync - ret -sync: + jge handle_cycle_limit ret .global m68k_read_long_scratch1 @@ -103,6 +178,7 @@ cmp $0xE00000, %ecx jge workram_b xor %cl, %cl + dec %cl jmp inccycles workram_b: and $0xFFFF, %rcx @@ -146,6 +222,7 @@ mov %r13d, 40(%rsi) /* a0 */ mov %r14d, 44(%rsi) /* a1 */ mov %r15d, 68(%rsi) /* a7 */ + mov %eax, 76(%rsi) /* current cycle count */ ret .global m68k_load_context diff -r 44e661913a51 -r 3b79cbcf6846 vdp.c --- a/vdp.c Sun Dec 16 22:25:29 2012 -0800 +++ b/vdp.c Tue Dec 18 02:16:42 2012 -0800 @@ -2,7 +2,6 @@ #include #include -#define MCLKS_LINE 3420 #define NTSC_ACTIVE 225 #define PAL_ACTIVE 241 #define BUF_BIT_PRIORITY 0x40 @@ -20,16 +19,24 @@ #define FLAG_CAN_MASK 0x2 #define FLAG_MASKED 0x4 #define FLAG_WINDOW 0x8 +#define FLAG_PENDING 0x10 +#define FLAG_UNUSED_SLOT 0x20 + +#define FIFO_SIZE 4 void init_vdp_context(vdp_context * context) { memset(context, 0, sizeof(context)); context->vdpmem = malloc(VRAM_SIZE); context->framebuf = malloc(FRAMEBUF_SIZE); + memset(context->framebuf, 0, FRAMEBUF_SIZE); context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); + memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; context->sprite_draws = MAX_DRAWS; + context->fifo_cur = malloc(sizeof(fifo_entry) * FIFO_SIZE); + context->fifo_end = context->fifo_cur + FIFO_SIZE; } void render_sprite_cells(vdp_context * context) @@ -168,9 +175,52 @@ } } +#define VRAM_READ 0 +#define VRAM_WRITE 1 +#define CRAM_READ 8 +#define CRAM_WRITE 3 +#define VSRAM_READ 4 +#define VSRAM_WRITE 5 + void external_slot(vdp_context * context) { - //TODO: Implement me + fifo_entry * start = (context->fifo_end - FIFO_SIZE); + //TODO: Implement DMA + if (context->fifo_cur != start && start->cycle <= context->cycles) { + switch (context->cd & 0x7) + { + case VRAM_WRITE: + if (start->partial) { + printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1); + context->vdpmem[context->address ^ 1] = start->value; + } else { + printf("VRAM Write: %X to %X\n", start->value >> 8, context->address); + context->vdpmem[context->address] = start->value >> 8; + start->partial = 1; + //skip auto-increment and removal of entry from fifo + return; + } + break; + case CRAM_WRITE: + printf("CRAM Write: %X to %X\n", start->value, context->address); + context->cram[context->address & (CRAM_SIZE-1)] = start->value; + break; + case VSRAM_WRITE: + if ((context->address & 63) < VSRAM_SIZE) { + printf("VSRAM Write: %X to %X\n", start->value, context->address); + context->vsram[context->address & 63] = start->value; + } + break; + } + context->address += context->regs[REG_AUTOINC]; + fifo_entry * cur = start+1; + if (cur < context->fifo_cur) { + memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur)); + } + context->fifo_cur -= 1; + } else { + context->flags |= FLAG_UNUSED_SLOT; + } } #define WINDOW_RIGHT 0x80 @@ -213,7 +263,7 @@ } offset = address + line_offset + (((column - 2) * 2) & mask); context->col_1 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1]; - printf("Window | top: %d, bot: %d, left: %d, right: %d, base: %X, line: %X offset: %X, tile: %X, reg: %X\n", top_line, bottom_line, left_col, right_col, address, line_offset, offset, ((context->col_1 & 0x3FF) << 5), context->regs[REG_WINDOW]); + //printf("Window | top: %d, bot: %d, left: %d, right: %d, base: %X, line: %X offset: %X, tile: %X, reg: %X\n", top_line, bottom_line, left_col, right_col, address, line_offset, offset, ((context->col_1 & 0x3FF) << 5), context->regs[REG_WINDOW]); offset = address + line_offset + (((column - 1) * 2) & mask); context->col_2 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1]; context->v_offset = (line) & 0x7; @@ -524,7 +574,7 @@ address += line * 4; context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; - printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); + //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); break; case 36: //!HSYNC high @@ -743,16 +793,58 @@ context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); } +#define DISPLAY_ENABLE 0x40 + +int is_refresh(vdp_context * context) +{ + uint32_t linecyc = context->cycles % MCLKS_LINE; + if (context->latched_mode & BIT_H40) { + linecyc = linecyc/16; + return (linecyc == 73 || linecyc == 105 || linecyc == 137 || linecyc == 169 || linecyc == 201); + } else { + linecyc = linecyc/20; + return (linecyc == 66 || linecyc == 98 || linecyc == 130 || linecyc == 162); + } +} + +void check_render_bg(vdp_context * context, int32_t line) +{ + if (line > 0) { + line -= 1; + uint16_t * start = NULL, *end = NULL; + uint32_t linecyc = (context->cycles % MCLKS_LINE); + if (context->latched_mode & BIT_H40) { + linecyc /= 16; + if (linecyc >= 55 && linecyc <= 207 && !((linecyc-55) % 8)) { + uint32_t x = ((linecyc-55)&(~0xF))*2; + start = context->framebuf + line * 320 + x; + end = start + 16; + } + } else { + linecyc /= 20; + if (linecyc >= 48 && linecyc <= 168 && !((linecyc-48) % 8)) { + uint32_t x = ((linecyc-48)&(~0xF))*2; + start = context->framebuf + line * 256 + x; + end = start + 16; + } + } + while (start != end) { + *start = context->regs[REG_BG_COLOR] & 0x3F; + ++start; + } + } +} + void vdp_run_context(vdp_context * context, uint32_t target_cycles) { while(context->cycles < target_cycles) { uint32_t line = context->cycles / MCLKS_LINE; uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - if (line < active_lines) { - if (!line) { - latch_mode(context); - } + if (!line) { + latch_mode(context); + } + if (line < active_lines && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { //first sort-of active line is treated as 255 internally //it's used for gathering sprite info for line line = (line - 1) & 0xFF; @@ -762,15 +854,26 @@ if (context->latched_mode & BIT_H40){ //TODO: Deal with nasty clock switching during HBLANK linecyc = linecyc/16; + vdp_h40(line, linecyc, context); context->cycles += 16; - vdp_h40(line, linecyc, context); } else { linecyc = linecyc/20; + vdp_h32(line, linecyc, context); context->cycles += 20; - vdp_h32(line, linecyc, context); } } else { - //TODO: Empty FIFO + if (!is_refresh(context)) { + external_slot(context); + } + if (line < active_lines) { + check_render_bg(context, line); + } + if (context->latched_mode & BIT_H40){ + //TODO: Deal with nasty clock switching during HBLANK + context->cycles += 16; + } else { + context->cycles += 20; + } } } } @@ -782,6 +885,94 @@ return context->cycles; } +void vdp_control_port_write(vdp_context * context, uint16_t value) +{ + printf("control port write: %X\n", value); + if (context->flags & FLAG_PENDING) { + context->address = (context->address & 0x3FFF) | (value << 14); + context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); + context->flags &= ~FLAG_PENDING; + } else { + if ((value & 0xC000) == 0x8000) { + //Register write + uint8_t reg = (value >> 8) & 0x1F; + if (reg < VDP_REGS) { + printf("register %d set to %X\n", reg, value); + context->regs[reg] = value; + } + } else { + context->flags |= FLAG_PENDING; + context->address = (context->address &0xC000) | (value & 0x3FFF); + context->cd = (context->cd &0x3C) | (value >> 14); + } + } +} + +void vdp_data_port_write(vdp_context * context, uint16_t value) +{ + printf("data port write: %X\n", value); + context->flags &= ~FLAG_PENDING; + if (context->fifo_cur == context->fifo_end) { + printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); + } + while (context->fifo_cur == context->fifo_end) { + vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + } + context->fifo_cur->cycle = context->cycles; + context->fifo_cur->value = value; + context->fifo_cur->partial = 0; + context->fifo_cur++; +} + +uint16_t vdp_control_port_read(vdp_context * context) +{ + context->flags &= ~FLAG_PENDING; + uint16_t value = 0x3400; + if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) { + value |= 0x200; + } + if (context->fifo_cur == context->fifo_end) { + value |= 0x100; + } + //TODO: Lots of other bits in status port + return value; +} + +uint16_t vdp_data_port_read(vdp_context * context) +{ + context->flags &= ~FLAG_PENDING; + if (!(context->cd & 1)) { + return 0; + } + //Not sure if the FIFO should be drained before processing a read or not, but it would make sense + context->flags &= ~FLAG_UNUSED_SLOT; + while (!(context->flags & FLAG_UNUSED_SLOT)) { + vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + } + uint16_t value = 0; + switch (context->cd & 0x7) + { + case VRAM_READ: + value = context->vdpmem[context->address] << 8; + context->flags &= ~FLAG_UNUSED_SLOT; + while (!(context->flags & FLAG_UNUSED_SLOT)) { + vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + } + value |= context->vdpmem[context->address ^ 1]; + break; + case CRAM_READ: + value = context->cram[(context->address/2) & (CRAM_SIZE-1)]; + break; + case VSRAM_READ: + if (((context->address / 2) & 63) < VSRAM_SIZE) { + value = context->vsram[context->address & 63]; + } + break; + } + context->address += context->regs[REG_AUTOINC]; + return value; +} + #define GST_VDP_REGS 0xFA #define GST_VDP_MEM 0x12478 @@ -802,3 +993,4 @@ fseek(state_file, GST_VDP_MEM, SEEK_SET); fread(context->vdpmem, 1, VRAM_SIZE, state_file); } + diff -r 44e661913a51 -r 3b79cbcf6846 vdp.h --- a/vdp.h Sun Dec 16 22:25:29 2012 -0800 +++ b/vdp.h Tue Dec 18 02:16:42 2012 -0800 @@ -26,6 +26,8 @@ #define FBUF_SRC_S 0x6000 #define FBUF_SRC_BG 0x8000 +#define MCLKS_LINE 3420 + enum { REG_MODE_1=0, REG_MODE_2, @@ -58,6 +60,17 @@ } sprite_info; typedef struct { + uint32_t cycle; + uint16_t value; + uint8_t partial; +} fifo_entry; + +typedef struct { + fifo_entry *fifo_cur; + fifo_entry *fifo_end; + uint16_t address; + uint8_t cd; + uint8_t flags; //cycle count in MCLKs uint32_t cycles; uint8_t *vdpmem; @@ -80,7 +93,6 @@ uint16_t col_1; uint16_t col_2; uint8_t v_offset; - uint8_t flags; uint8_t *tmp_buf_a; uint8_t *tmp_buf_b; } vdp_context; @@ -90,5 +102,9 @@ //runs from current cycle count to VBLANK for the current mode, returns ending cycle count uint32_t vdp_run_to_vblank(vdp_context * context); void vdp_load_savestate(vdp_context * context, FILE * state_file); +void vdp_control_port_write(vdp_context * context, uint16_t value); +void vdp_data_port_write(vdp_context * context, uint16_t value); +uint16_t vdp_control_port_read(vdp_context * context); +uint16_t vdp_data_port_read(vdp_context * context); #endif //VDP_H_