|
14 | 14 | #include "stdclass.h" |
15 | 15 | #include "emulator.h" |
16 | 16 | #include "oslib/storage.h" |
| 17 | +#include "naomi_regs.h" |
| 18 | +#include "hw/holly/sb.h" |
| 19 | +#include "hw/holly/holly_intc.h" |
| 20 | +#include "hw/mem/addrspace.h" |
| 21 | +#include "serialize.h" |
| 22 | +#include "hw/sh4/sh4_sched.h" |
| 23 | +#include "naomi.h" |
17 | 24 |
|
18 | 25 | /* |
19 | 26 |
|
@@ -642,3 +649,235 @@ bool GDCartridge::Read(u32 offset, u32 size, void *dst) |
642 | 649 | memcpy(dst, &dimm_data[addr], std::min(size, dimm_data_size - addr)); |
643 | 650 | return true; |
644 | 651 | } |
| 652 | + |
| 653 | +GDCartridge::GDCartridge(u32 size) : NaomiCartridge(size) |
| 654 | +{ |
| 655 | + schedId = sh4_sched_register(0, [](int tag, int sch_cycl, int jitter, void *arg){ |
| 656 | + return ((GDCartridge *)arg)->schedCallback(); |
| 657 | + }, this); |
| 658 | +} |
| 659 | + |
| 660 | +GDCartridge::~GDCartridge() |
| 661 | +{ |
| 662 | + free(dimm_data); |
| 663 | + sh4_sched_unregister(schedId); |
| 664 | +} |
| 665 | + |
| 666 | +u32 GDCartridge::ReadMem(u32 address, u32 size) |
| 667 | +{ |
| 668 | + switch (address) |
| 669 | + { |
| 670 | + case NAOMI_DIMM_COMMAND: |
| 671 | + DEBUG_LOG(NAOMI, "DIMM COMMAND read -> %x", dimm_command); |
| 672 | + return dimm_command; |
| 673 | + case NAOMI_DIMM_OFFSETL: |
| 674 | + DEBUG_LOG(NAOMI, "DIMM OFFSETL read -> %x", dimm_offsetl); |
| 675 | + return dimm_offsetl; |
| 676 | + case NAOMI_DIMM_PARAMETERL: |
| 677 | + DEBUG_LOG(NAOMI, "DIMM PARAMETERL read -> %x", dimm_parameterl); |
| 678 | + return dimm_parameterl; |
| 679 | + case NAOMI_DIMM_PARAMETERH: |
| 680 | + DEBUG_LOG(NAOMI, "DIMM PARAMETERH read -> %x", dimm_parameterh); |
| 681 | + return dimm_parameterh; |
| 682 | + case NAOMI_DIMM_STATUS: |
| 683 | + { |
| 684 | + u32 rc = DIMM_STATUS & ~(((SB_ISTEXT >> 3) & 1) << 8); |
| 685 | + static u32 lastRc; |
| 686 | + if (rc != lastRc) |
| 687 | + DEBUG_LOG(NAOMI, "DIMM STATUS read -> %x", rc); |
| 688 | + lastRc = rc; |
| 689 | + return rc; |
| 690 | + } |
| 691 | + default: |
| 692 | + return NaomiCartridge::ReadMem(address, size); |
| 693 | + } |
| 694 | +} |
| 695 | + |
| 696 | +void GDCartridge::WriteMem(u32 address, u32 data, u32 size) |
| 697 | +{ |
| 698 | + switch (address) |
| 699 | + { |
| 700 | + case NAOMI_DIMM_COMMAND: |
| 701 | + dimm_command = data; |
| 702 | + DEBUG_LOG(NAOMI, "DIMM COMMAND Write<%d>: %x", size, data); |
| 703 | + return; |
| 704 | + |
| 705 | + case NAOMI_DIMM_OFFSETL: |
| 706 | + dimm_offsetl = data; |
| 707 | + DEBUG_LOG(NAOMI, "DIMM OFFSETL Write<%d>: %x", size, data); |
| 708 | + return; |
| 709 | + case NAOMI_DIMM_PARAMETERL: |
| 710 | + dimm_parameterl = data; |
| 711 | + DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write<%d>: %x", size, data); |
| 712 | + return; |
| 713 | + case NAOMI_DIMM_PARAMETERH: |
| 714 | + dimm_parameterh = data; |
| 715 | + DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write<%d>: %x", size, data); |
| 716 | + return; |
| 717 | + |
| 718 | + case NAOMI_DIMM_STATUS: |
| 719 | + DEBUG_LOG(NAOMI, "DIMM STATUS Write<%d>: %x", size, data); |
| 720 | + if (data & 0x100) |
| 721 | + // write 0 seems ignored |
| 722 | + asic_CancelInterrupt(holly_EXP_PCI); |
| 723 | + if ((data & 1) == 0) |
| 724 | + // irq to dimm |
| 725 | + process(); |
| 726 | + return; |
| 727 | + |
| 728 | + default: |
| 729 | + NaomiCartridge::WriteMem(address, data, size); |
| 730 | + return; |
| 731 | + } |
| 732 | +} |
| 733 | + |
| 734 | +void GDCartridge::process() |
| 735 | +{ |
| 736 | + INFO_LOG(NAOMI, "NetDIMM cmd %04x sock %d offset %04x paramh/l %04x %04x", (dimm_command >> 9) & 0x3f, |
| 737 | + dimm_command & 0xff, dimm_offsetl, dimm_parameterh, dimm_parameterl); |
| 738 | + |
| 739 | + int cmdGroup = (dimm_command >> 13) & 3; |
| 740 | + int cmd = (dimm_command >> 9) & 0xf; |
| 741 | + switch (cmdGroup) |
| 742 | + { |
| 743 | + case 0: // system commands |
| 744 | + systemCmd(cmd); |
| 745 | + break; |
| 746 | + case 1: // network commands |
| 747 | + WARN_LOG(NAOMI, "Network command received cmd %x. Need full NetDIMM?", cmd); |
| 748 | + returnToNaomi(true, 0, -1); |
| 749 | + break; |
| 750 | + default: |
| 751 | + WARN_LOG(NAOMI, "Unknown DIMM command group %d cmd %x", cmdGroup, cmd); |
| 752 | + returnToNaomi(true, 0, -1); |
| 753 | + break; |
| 754 | + } |
| 755 | +} |
| 756 | + |
| 757 | +void GDCartridge::returnToNaomi(bool failed, u16 offsetl, u32 parameter) |
| 758 | +{ |
| 759 | + dimm_command = ((dimm_command & 0x7e00) + 0x400) | (failed ? 0xff : 0x4); |
| 760 | + dimm_offsetl = offsetl; |
| 761 | + dimm_parameterh = parameter >> 16; |
| 762 | + dimm_parameterl = parameter; |
| 763 | + verify(((SB_ISTEXT >> 3) & 1) == 0); |
| 764 | + asic_RaiseInterrupt(holly_EXP_PCI); |
| 765 | +} |
| 766 | + |
| 767 | +void GDCartridge::systemCmd(int cmd) |
| 768 | +{ |
| 769 | + switch (cmd) |
| 770 | + { |
| 771 | + case 0xf: // startup |
| 772 | + INFO_LOG(NAOMI, "NetDIMM startup"); |
| 773 | + // bit 16,17: dimm0 size (none, 128, 256, 512) |
| 774 | + // bit 18,19: dimm1 size |
| 775 | + // bit 28: network enabled (network settings appear in bios menu) |
| 776 | + // bit 29: set |
| 777 | + // bit 30: gd-rom connected |
| 778 | + // bit 31: mobile/ppp network? |
| 779 | + // (| 30, 70, F0, 1F0, 3F0, 7F0) |
| 780 | + // | offset >> 20 (dimm buffers offset @ size - 16MB) |
| 781 | + // offset = (64MB << 0-5) - 16MB |
| 782 | + // vf4 forces this value to 0f000000 (256MB) if != 1f000000 (512MB) |
| 783 | + if (dimm_data_size == 512_MB) |
| 784 | + addrspace::write32(0xc01fc04, (3 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 512 MB |
| 785 | + else if (dimm_data_size == 256_MB) |
| 786 | + addrspace::write32(0xc01fc04, (2 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 256 MB |
| 787 | + else |
| 788 | + addrspace::write32(0xc01fc04, (1 << 16) | 0x60000000 | (dimm_data_size >> 20)); // dimm board config 1 x 128 MB |
| 789 | + addrspace::write32(0xc01fc0c, 0x1020000 | 0x264); // fw version 1.02 |
| 790 | + // DIMM board serial Id |
| 791 | + { |
| 792 | + const u32 *serial = (u32 *)(getGameSerialId() + 0x20); // get only the serial id |
| 793 | + addrspace::write32(0xc01fc40, *serial++); |
| 794 | + addrspace::write32(0xc01fc44, *serial++); |
| 795 | + addrspace::write32(0xc01fc48, *serial++); |
| 796 | + addrspace::write32(0xc01fc4c, *serial++); |
| 797 | + } |
| 798 | + // SET_BASE_ADDRESS(0c000000, 0) |
| 799 | + dimm_command = 0x8600; |
| 800 | + dimm_offsetl = 0; |
| 801 | + dimm_parameterl = 0; |
| 802 | + dimm_parameterh = 0x0c00; |
| 803 | + asic_RaiseInterrupt(holly_EXP_PCI); |
| 804 | + sh4_sched_request(schedId, SH4_MAIN_CLOCK); |
| 805 | + |
| 806 | + break; |
| 807 | + |
| 808 | + case 0: // nop |
| 809 | + case 1: // control read |
| 810 | + case 3: // set base address |
| 811 | + case 4: // peek8 |
| 812 | + case 5: // peek16 |
| 813 | + case 6: // peek32 |
| 814 | + case 8: // poke8 |
| 815 | + case 9: // poke16 |
| 816 | + case 10: // poke32 |
| 817 | + // These are callbacks from naomi |
| 818 | + INFO_LOG(NAOMI, "System callback command %x", cmd); |
| 819 | + break; |
| 820 | + |
| 821 | + default: |
| 822 | + WARN_LOG(NAOMI, "Unknown system command %x", cmd); |
| 823 | + break; |
| 824 | + } |
| 825 | +} |
| 826 | + |
| 827 | +void GDCartridge::Serialize(Serializer &ser) const |
| 828 | +{ |
| 829 | + NaomiCartridge::Serialize(ser); |
| 830 | + ser << dimm_command; |
| 831 | + ser << dimm_offsetl; |
| 832 | + ser << dimm_parameterl; |
| 833 | + ser << dimm_parameterh; |
| 834 | + sh4_sched_serialize(ser, schedId); |
| 835 | +} |
| 836 | + |
| 837 | +void GDCartridge::Deserialize(Deserializer &deser) |
| 838 | +{ |
| 839 | + NaomiCartridge::Deserialize(deser); |
| 840 | + if (deser.version() >= Deserializer::V53) |
| 841 | + { |
| 842 | + deser >> dimm_command; |
| 843 | + deser >> dimm_offsetl; |
| 844 | + deser >> dimm_parameterl; |
| 845 | + deser >> dimm_parameterh; |
| 846 | + sh4_sched_deserialize(deser, schedId); |
| 847 | + } |
| 848 | +} |
| 849 | + |
| 850 | +int GDCartridge::schedCallback() |
| 851 | +{ |
| 852 | + if (SB_ISTEXT & 8) // holly_EXP_PCI |
| 853 | + return SH4_MAIN_CLOCK; |
| 854 | + |
| 855 | + // regularly peek the test request address |
| 856 | + peek<u32>(0xc01fc08); |
| 857 | + asic_RaiseInterrupt(holly_EXP_PCI); |
| 858 | + |
| 859 | + u32 testRequest = addrspace::read32(0xc01fc08); |
| 860 | + if (testRequest & 1) |
| 861 | + { |
| 862 | + // bios dimm (fake) test |
| 863 | + addrspace::write32(0xc01fc08, testRequest & ~1); |
| 864 | + bool isMem; |
| 865 | + char *p = (char *)addrspace::writeConst(0xc01fd00, isMem, 4); |
| 866 | + strcpy(p, "CHECKING DIMM BD"); |
| 867 | + p = (char *)addrspace::writeConst(0xc01fd10, isMem, 4); |
| 868 | + strcpy(p, "DIMM0 - GOOD"); |
| 869 | + p = (char *)addrspace::writeConst(0xc01fd20, isMem, 4); |
| 870 | + strcpy(p, "DIMM1 - GOOD"); |
| 871 | + p = (char *)addrspace::writeConst(0xc01fd30, isMem, 4); |
| 872 | + strcpy(p, "--- COMPLETED---"); |
| 873 | + addrspace::write32(0xc01fc0c, 0x0102a264); |
| 874 | + } |
| 875 | + else if (testRequest != 0) |
| 876 | + { |
| 877 | + addrspace::write32(0xc01fc08, 0); |
| 878 | + addrspace::write32(0xc01fc0c, 0x03170100); |
| 879 | + INFO_LOG(NAOMI, "TEST REQUEST %x", testRequest); |
| 880 | + } |
| 881 | + |
| 882 | + return SH4_MAIN_CLOCK; |
| 883 | +} |
0 commit comments