Mercurial > repos > blastem
comparison vdp.c @ 2227:eaaf28af3c94
Implement VDP read latency and invalid write delays revealed by Ti_'s instruction timing ROM
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 05 Sep 2022 22:18:25 -0700 |
parents | 1cccc57c069a |
children | 3888c7ed4e36 |
comparison
equal
deleted
inserted
replaced
2226:d15c68157288 | 2227:eaaf28af3c94 |
---|---|
38 #define LINE_CHANGE_H32 133 | 38 #define LINE_CHANGE_H32 133 |
39 #define LINE_CHANGE_MODE4 249 | 39 #define LINE_CHANGE_MODE4 249 |
40 #define VBLANK_START_H40 (LINE_CHANGE_H40+2) | 40 #define VBLANK_START_H40 (LINE_CHANGE_H40+2) |
41 #define VBLANK_START_H32 (LINE_CHANGE_H32+2) | 41 #define VBLANK_START_H32 (LINE_CHANGE_H32+2) |
42 #define FIFO_LATENCY 3 | 42 #define FIFO_LATENCY 3 |
43 #define READ_LATENCY 3 | |
43 | 44 |
44 #define BORDER_TOP_V24 27 | 45 #define BORDER_TOP_V24 27 |
45 #define BORDER_TOP_V28 11 | 46 #define BORDER_TOP_V28 11 |
46 #define BORDER_TOP_V24_PAL 54 | 47 #define BORDER_TOP_V24_PAL 54 |
47 #define BORDER_TOP_V28_PAL 38 | 48 #define BORDER_TOP_V28_PAL 38 |
1017 uint8_t buffer[3] = {((start->address/2) & 63) + 128, context->vsram[(start->address/2) & 63] >> 8, context->vsram[(start->address/2) & 63]}; | 1018 uint8_t buffer[3] = {((start->address/2) & 63) + 128, context->vsram[(start->address/2) & 63] >> 8, context->vsram[(start->address/2) & 63]}; |
1018 event_log(EVENT_VDP_INTRAM, context->cycles, sizeof(buffer), buffer); | 1019 event_log(EVENT_VDP_INTRAM, context->cycles, sizeof(buffer), buffer); |
1019 } | 1020 } |
1020 | 1021 |
1021 break; | 1022 break; |
1023 default: | |
1024 if (!(context->cd & 4) && !start->partial && (context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) != (BIT_128K_VRAM|BIT_MODE_5)) { | |
1025 start->partial = 1; | |
1026 return; | |
1027 } | |
1022 } | 1028 } |
1023 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); | 1029 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); |
1024 if (context->fifo_read == context->fifo_write) { | 1030 if (context->fifo_read == context->fifo_write) { |
1025 if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) { | 1031 if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) { |
1026 context->flags |= FLAG_DMA_RUN; | 1032 context->flags |= FLAG_DMA_RUN; |
1038 } else { | 1044 } else { |
1039 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; | 1045 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; |
1040 | 1046 |
1041 context->flags |= FLAG_READ_FETCHED; | 1047 context->flags |= FLAG_READ_FETCHED; |
1042 } | 1048 } |
1043 } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) { | 1049 } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING)) && context->read_latency <= context->cycles) { |
1044 switch(context->cd & 0xF) | 1050 switch(context->cd & 0xF) |
1045 { | 1051 { |
1046 case VRAM_READ: | 1052 case VRAM_READ: |
1047 if (context->flags2 & FLAG2_READ_PENDING) { | 1053 if (context->flags2 & FLAG2_READ_PENDING) { |
1048 context->prefetch |= context->vdpmem[context->address | 1]; | 1054 context->prefetch |= context->vdpmem[context->address | 1]; |
3783 hv |= get_ext_vcounter(context); | 3789 hv |= get_ext_vcounter(context); |
3784 | 3790 |
3785 return hv; | 3791 return hv; |
3786 } | 3792 } |
3787 | 3793 |
3788 int vdp_control_port_write(vdp_context * context, uint16_t value) | 3794 int vdp_control_port_write(vdp_context * context, uint16_t value, uint32_t cpu_cycle) |
3789 { | 3795 { |
3790 //printf("control port write: %X at %d\n", value, context->cycles); | 3796 //printf("control port write: %X at %d\n", value, context->cycles); |
3791 if (context->flags & FLAG_DMA_RUN) { | 3797 if (context->flags & FLAG_DMA_RUN) { |
3792 return -1; | 3798 return -1; |
3793 } | 3799 } |
3803 } | 3809 } |
3804 context->flags &= ~FLAG_PENDING; | 3810 context->flags &= ~FLAG_PENDING; |
3805 //Should these be taken care of here or after the first write? | 3811 //Should these be taken care of here or after the first write? |
3806 context->flags &= ~FLAG_READ_FETCHED; | 3812 context->flags &= ~FLAG_READ_FETCHED; |
3807 context->flags2 &= ~FLAG2_READ_PENDING; | 3813 context->flags2 &= ~FLAG2_READ_PENDING; |
3814 if (!(context->cd & 1)) { | |
3815 context->read_latency = cpu_cycle + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*READ_LATENCY; | |
3816 } | |
3808 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); | 3817 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); |
3809 if (context->cd & 0x20) { | 3818 if (context->cd & 0x20) { |
3810 // | 3819 // |
3811 if((context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { | 3820 if((context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { |
3812 //DMA copy or 68K -> VDP, transfer starts immediately | 3821 //DMA copy or 68K -> VDP, transfer starts immediately |
3916 { | 3925 { |
3917 if (context->flags2 & FLAG2_BYTE_PENDING) { | 3926 if (context->flags2 & FLAG2_BYTE_PENDING) { |
3918 uint16_t full_val = value << 8 | context->pending_byte; | 3927 uint16_t full_val = value << 8 | context->pending_byte; |
3919 context->flags2 &= ~FLAG2_BYTE_PENDING; | 3928 context->flags2 &= ~FLAG2_BYTE_PENDING; |
3920 //TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode | 3929 //TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode |
3921 vdp_control_port_write(context, full_val); | 3930 vdp_control_port_write(context, full_val, context->cycles); |
3922 if (context->cd == VRAM_READ) { | 3931 if (context->cd == VRAM_READ) { |
3923 context->cd = VRAM_READ8; | 3932 context->cd = VRAM_READ8; |
3924 } | 3933 } |
3925 } else { | 3934 } else { |
3926 context->pending_byte = value; | 3935 context->pending_byte = value; |
4054 } | 4063 } |
4055 //printf("status read at cycle %d returned %X\n", context->cycles, value); | 4064 //printf("status read at cycle %d returned %X\n", context->cycles, value); |
4056 return value; | 4065 return value; |
4057 } | 4066 } |
4058 | 4067 |
4059 uint16_t vdp_data_port_read(vdp_context * context) | 4068 uint16_t vdp_data_port_read(vdp_context * context, uint32_t *cpu_cycle, uint32_t cpu_divider) |
4060 { | 4069 { |
4061 if (context->flags & FLAG_PENDING) { | 4070 if (context->flags & FLAG_PENDING) { |
4062 context->flags &= ~FLAG_PENDING; | 4071 context->flags &= ~FLAG_PENDING; |
4063 //Should these be cleared here? | 4072 //Should these be cleared here? |
4064 context->flags &= ~FLAG_READ_FETCHED; | 4073 context->flags &= ~FLAG_READ_FETCHED; |
4079 default: | 4088 default: |
4080 warning("Read from VDP data port with invalid source, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); | 4089 warning("Read from VDP data port with invalid source, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); |
4081 context->system->enter_debugger = 1; | 4090 context->system->enter_debugger = 1; |
4082 return context->prefetch; | 4091 return context->prefetch; |
4083 } | 4092 } |
4093 uint32_t starting_cycle = context->cycles; | |
4084 while (!(context->flags & FLAG_READ_FETCHED)) { | 4094 while (!(context->flags & FLAG_READ_FETCHED)) { |
4085 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | 4095 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
4086 } | 4096 } |
4087 context->flags &= ~FLAG_READ_FETCHED; | 4097 context->flags &= ~FLAG_READ_FETCHED; |
4098 //TODO: Make some logic analyzer captures to better characterize what's happening with read latency here | |
4099 if (context->cycles != starting_cycle) { | |
4100 uint32_t delta = context->cycles - *cpu_cycle; | |
4101 uint32_t cpu_delta = delta / cpu_divider; | |
4102 if (delta % cpu_divider) { | |
4103 cpu_delta++; | |
4104 } | |
4105 *cpu_cycle += cpu_delta * cpu_divider; | |
4106 if (*cpu_cycle - context->cycles < 2) { | |
4107 context->read_latency = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*(READ_LATENCY - 1); | |
4108 } else { | |
4109 context->read_latency = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*READ_LATENCY; | |
4110 } | |
4111 } else { | |
4112 context->read_latency = *cpu_cycle + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*(READ_LATENCY - 1); | |
4113 } | |
4088 return context->prefetch; | 4114 return context->prefetch; |
4089 } | 4115 } |
4090 | 4116 |
4091 uint8_t vdp_data_port_read_pbc(vdp_context * context) | 4117 uint8_t vdp_data_port_read_pbc(vdp_context * context) |
4092 { | 4118 { |
4118 } else { | 4144 } else { |
4119 context->fifo[idx].cycle = 0; | 4145 context->fifo[idx].cycle = 0; |
4120 } | 4146 } |
4121 idx = (idx+1) & (FIFO_SIZE-1); | 4147 idx = (idx+1) & (FIFO_SIZE-1); |
4122 } while(idx != context->fifo_write); | 4148 } while(idx != context->fifo_write); |
4149 } | |
4150 if (context->read_latency >= deduction) { | |
4151 context->read_latency -= deduction; | |
4152 } else { | |
4153 context->read_latency = 0; | |
4123 } | 4154 } |
4124 } | 4155 } |
4125 | 4156 |
4126 static uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context) | 4157 static uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context) |
4127 { | 4158 { |