comparison vdp.c @ 2223:1cccc57c069a

Admit defeat on VDP address latching theory and implement it the way GPGX does. Fixes regression in VDP FIFO Testing and SMS VDPTEST
author Michael Pavone <pavone@retrodev.com>
date Sun, 04 Sep 2022 23:29:37 -0700
parents 90297f1fb3fe
children eaaf28af3c94
comparison
equal deleted inserted replaced
2222:bb1bcdb027e0 2223:1cccc57c069a
1038 } else { 1038 } else {
1039 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; 1039 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1];
1040 1040
1041 context->flags |= FLAG_READ_FETCHED; 1041 context->flags |= FLAG_READ_FETCHED;
1042 } 1042 }
1043 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)) { 1043 } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) {
1044 switch(context->cd & 0xF) 1044 switch(context->cd & 0xF)
1045 { 1045 {
1046 case VRAM_READ: 1046 case VRAM_READ:
1047 if (context->flags2 & FLAG2_READ_PENDING) { 1047 if (context->flags2 & FLAG2_READ_PENDING) {
1048 context->prefetch |= context->vdpmem[context->address | 1]; 1048 context->prefetch |= context->vdpmem[context->address | 1];
3783 hv |= get_ext_vcounter(context); 3783 hv |= get_ext_vcounter(context);
3784 3784
3785 return hv; 3785 return hv;
3786 } 3786 }
3787 3787
3788 static void clear_pending(vdp_context *context)
3789 {
3790 context->flags &= ~FLAG_PENDING;
3791 context->address = context->address_latch;
3792 //It seems like the DMA enable bit doesn't so much enable DMA so much
3793 //as it enables changing CD5 from control port writes
3794 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) {
3795 context->cd = context->cd_latch;
3796 } else {
3797 context->cd = (context->cd & 0x20) | (context->cd_latch & 0x1F);
3798 }
3799 }
3800
3801 int vdp_control_port_write(vdp_context * context, uint16_t value) 3788 int vdp_control_port_write(vdp_context * context, uint16_t value)
3802 { 3789 {
3803 //printf("control port write: %X at %d\n", value, context->cycles); 3790 //printf("control port write: %X at %d\n", value, context->cycles);
3804 if (context->flags & FLAG_DMA_RUN) { 3791 if (context->flags & FLAG_DMA_RUN) {
3805 return -1; 3792 return -1;
3806 } 3793 }
3807 if (context->flags & FLAG_PENDING) { 3794 if (context->flags & FLAG_PENDING) {
3808 context->address_latch = (context->address_latch & 0x3FFF) | (value << 14 & 0x1C000); 3795 context->address_latch = value << 14 & 0x1C000;
3809 context->cd_latch = (context->cd_latch & 0x3) | ((value >> 2) & ~0x3 & 0xFF); 3796 context->address = (context->address & 0x3FFF) | context->address_latch;
3810 clear_pending(context); 3797 //It seems like the DMA enable bit doesn't so much enable DMA so much
3798 //as it enables changing CD5 from control port writes
3799 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) {
3800 context->cd = (context->cd & 0x3) | ((value >> 2) & ~0x3 & 0xFF);
3801 } else {
3802 context->cd = (context->cd & 0x23) | ((value >> 2) & ~0x23 & 0xFF);
3803 }
3804 context->flags &= ~FLAG_PENDING;
3811 //Should these be taken care of here or after the first write? 3805 //Should these be taken care of here or after the first write?
3812 context->flags &= ~FLAG_READ_FETCHED; 3806 context->flags &= ~FLAG_READ_FETCHED;
3813 context->flags2 &= ~FLAG2_READ_PENDING; 3807 context->flags2 &= ~FLAG2_READ_PENDING;
3814 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); 3808 //printf("New Address: %X, New CD: %X\n", context->address, context->cd);
3815 if (context->cd & 0x20) { 3809 if (context->cd & 0x20) {
3834 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); 3828 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd);
3835 } 3829 }
3836 } 3830 }
3837 } else { 3831 } else {
3838 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 3832 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3839 context->address_latch = (context->address_latch & 0x1C000) | (value & 0x3FFF); 3833 context->address = context->address_latch | (value & 0x3FFF);
3840 context->cd_latch = (context->cd_latch & 0x3C) | (value >> 14); 3834 context->cd = (context->cd & 0x3C) | (value >> 14);
3841 if ((value & 0xC000) == 0x8000) { 3835 if ((value & 0xC000) == 0x8000) {
3842 //Register write 3836 //Register write
3843 uint8_t reg = (value >> 8) & 0x1F; 3837 uint8_t reg = (value >> 8) & 0x1F;
3844 // The fact that this is needed seems to pour some cold water on my theory
3845 // about how the address latch actually works. Needs more search to definitively confirm
3846 context->address = (context->address & 0x1C000) | (value & 0x3FFF);
3847 context->cd = (context->cd & 0x3C) | (value >> 14);
3848 if (reg < (mode_5 ? VDP_REGS : 0xB)) { 3838 if (reg < (mode_5 ? VDP_REGS : 0xB)) {
3849 //printf("register %d set to %X\n", reg, value & 0xFF); 3839 //printf("register %d set to %X\n", reg, value & 0xFF);
3850 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) { 3840 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) {
3851 vdp_latch_hv(context); 3841 vdp_latch_hv(context);
3852 } else if (reg == REG_BG_COLOR) { 3842 } else if (reg == REG_BG_COLOR) {
3913 context->flags |= FLAG_PENDING; 3903 context->flags |= FLAG_PENDING;
3914 //Should these be taken care of here or after the second write? 3904 //Should these be taken care of here or after the second write?
3915 //context->flags &= ~FLAG_READ_FETCHED; 3905 //context->flags &= ~FLAG_READ_FETCHED;
3916 //context->flags2 &= ~FLAG2_READ_PENDING; 3906 //context->flags2 &= ~FLAG2_READ_PENDING;
3917 } else { 3907 } else {
3918 clear_pending(context);
3919 context->flags &= ~FLAG_READ_FETCHED; 3908 context->flags &= ~FLAG_READ_FETCHED;
3920 context->flags2 &= ~FLAG2_READ_PENDING; 3909 context->flags2 &= ~FLAG2_READ_PENDING;
3921 } 3910 }
3922 } 3911 }
3923 return 0; 3912 return 0;
3944 //printf("data port write: %X at %d\n", value, context->cycles); 3933 //printf("data port write: %X at %d\n", value, context->cycles);
3945 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { 3934 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3946 return -1; 3935 return -1;
3947 } 3936 }
3948 if (context->flags & FLAG_PENDING) { 3937 if (context->flags & FLAG_PENDING) {
3949 clear_pending(context); 3938 context->flags &= ~FLAG_PENDING;
3950 //Should these be cleared here? 3939 //Should these be cleared here?
3951 context->flags &= ~FLAG_READ_FETCHED; 3940 context->flags &= ~FLAG_READ_FETCHED;
3952 context->flags2 &= ~FLAG2_READ_PENDING; 3941 context->flags2 &= ~FLAG2_READ_PENDING;
3953 } 3942 }
3954 /*if (context->fifo_cur == context->fifo_end) { 3943 /*if (context->fifo_cur == context->fifo_end) {
3979 } 3968 }
3980 3969
3981 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) 3970 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value)
3982 { 3971 {
3983 if (context->flags & FLAG_PENDING) { 3972 if (context->flags & FLAG_PENDING) {
3984 clear_pending(context); 3973 context->flags &= ~FLAG_PENDING;
3985 //Should these be cleared here? 3974 //Should these be cleared here?
3986 context->flags &= ~FLAG_READ_FETCHED; 3975 context->flags &= ~FLAG_READ_FETCHED;
3987 context->flags2 &= ~FLAG2_READ_PENDING; 3976 context->flags2 &= ~FLAG2_READ_PENDING;
3988 } 3977 }
3989 context->flags2 &= ~FLAG2_BYTE_PENDING; 3978 context->flags2 &= ~FLAG2_BYTE_PENDING;
4018 context->test_port = value; 4007 context->test_port = value;
4019 } 4008 }
4020 4009
4021 uint16_t vdp_control_port_read(vdp_context * context) 4010 uint16_t vdp_control_port_read(vdp_context * context)
4022 { 4011 {
4023 if (context->flags & FLAG_PENDING) { 4012 context->flags &= ~FLAG_PENDING;
4024 clear_pending(context);
4025 }
4026 context->flags2 &= ~FLAG2_BYTE_PENDING; 4013 context->flags2 &= ~FLAG2_BYTE_PENDING;
4027 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch 4014 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch
4028 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; 4015 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00;
4029 if (context->fifo_read < 0) { 4016 if (context->fifo_read < 0) {
4030 value |= 0x200; 4017 value |= 0x200;
4070 } 4057 }
4071 4058
4072 uint16_t vdp_data_port_read(vdp_context * context) 4059 uint16_t vdp_data_port_read(vdp_context * context)
4073 { 4060 {
4074 if (context->flags & FLAG_PENDING) { 4061 if (context->flags & FLAG_PENDING) {
4075 clear_pending(context); 4062 context->flags &= ~FLAG_PENDING;
4076 //Should these be cleared here? 4063 //Should these be cleared here?
4077 context->flags &= ~FLAG_READ_FETCHED; 4064 context->flags &= ~FLAG_READ_FETCHED;
4078 context->flags2 &= ~FLAG2_READ_PENDING; 4065 context->flags2 &= ~FLAG2_READ_PENDING;
4079 } 4066 }
4080 if (context->cd & 1) { 4067 if (context->cd & 1) {
4101 return context->prefetch; 4088 return context->prefetch;
4102 } 4089 }
4103 4090
4104 uint8_t vdp_data_port_read_pbc(vdp_context * context) 4091 uint8_t vdp_data_port_read_pbc(vdp_context * context)
4105 { 4092 {
4106 if (context->flags & FLAG_PENDING) { 4093 context->flags &= ~(FLAG_PENDING | FLAG_READ_FETCHED);
4107 clear_pending(context);
4108 }
4109 context->flags &= ~FLAG_READ_FETCHED;
4110 context->flags2 &= ~FLAG2_BYTE_PENDING; 4094 context->flags2 &= ~FLAG2_BYTE_PENDING;
4111 4095
4112 context->cd = VRAM_READ8; 4096 context->cd = VRAM_READ8;
4113 return context->prefetch; 4097 return context->prefetch;
4114 } 4098 }
4484 4468
4485 save_int32(buf, context->cycles); 4469 save_int32(buf, context->cycles);
4486 save_int32(buf, context->pending_vint_start); 4470 save_int32(buf, context->pending_vint_start);
4487 save_int32(buf, context->pending_hint_start); 4471 save_int32(buf, context->pending_hint_start);
4488 save_int32(buf, context->address_latch); 4472 save_int32(buf, context->address_latch);
4489 save_int8(buf, context->cd_latch); 4473 //was cd_latch, for compatibility with older builds that expect it
4474 save_int8(buf, context->cd);
4490 } 4475 }
4491 4476
4492 void vdp_deserialize(deserialize_buffer *buf, void *vcontext) 4477 void vdp_deserialize(deserialize_buffer *buf, void *vcontext)
4493 { 4478 {
4494 vdp_context *context = vcontext; 4479 vdp_context *context = vcontext;
4621 context->cycles = load_int32(buf); 4606 context->cycles = load_int32(buf);
4622 context->pending_vint_start = load_int32(buf); 4607 context->pending_vint_start = load_int32(buf);
4623 context->pending_hint_start = load_int32(buf); 4608 context->pending_hint_start = load_int32(buf);
4624 if (version > 2) { 4609 if (version > 2) {
4625 context->address_latch = load_int32(buf); 4610 context->address_latch = load_int32(buf);
4626 context->cd_latch = load_int8(buf); 4611 //was cd_latch, no longer used
4612 load_int8(buf);
4627 } else { 4613 } else {
4628 context->address_latch = context->address; 4614 context->address_latch = context->address;
4629 context->cd_latch = context->cd;
4630 } 4615 }
4631 update_video_params(context); 4616 update_video_params(context);
4632 } 4617 }
4633 4618
4634 static vdp_context *current_vdp; 4619 static vdp_context *current_vdp;