Mercurial > repos > blastem
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; |