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 {