MegaSCSI.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * MEGA-SCSI and ESE-RAM cartridge:
  3. * The mapping does SRAM and MB89352A(MEGA-SCSI) to ASCII8 or
  4. * an interchangeable bank controller.
  5. *
  6. * Specification:
  7. * SRAM(MegaROM) controller: ASCII8 type
  8. * SRAM capacity : 128, 256, 512 and 1024KB
  9. * SCSI Protocol Controller: Fujitsu MB89352A
  10. *
  11. * Bank changing address:
  12. * bank 4(0x4000-0x5fff): 0x6000 - 0x67FF (0x6000 used)
  13. * bank 6(0x6000-0x7fff): 0x6800 - 0x6FFF (0x6800 used)
  14. * bank 8(0x8000-0x9fff): 0x7000 - 0x77FF (0x7000 used)
  15. * bank A(0xa000-0xbfff): 0x7800 - 0x7FFF (0x7800 used)
  16. *
  17. * ESE-RAM Bank Map:
  18. * BANK 00H-7FH (read only)
  19. * BANK 80H-FFH (write and read. mirror of 00H-7FH)
  20. *
  21. * MEGA-SCSI Bank Map:
  22. * BANK 00H-3FH (sram read only. mirror of 80H-BFH)
  23. * BANK 40H-7EH (mirror of 7FH. Use is prohibited)
  24. * BANK 7FH (SPC)
  25. * BANK 80H-FFH (sram write and read)
  26. *
  27. * SPC Bank:
  28. * 0x0000 - 0x0FFF :
  29. * SPC Data register r/w (mirror of all 0x1FFA)
  30. * 0x1000 - 0x1FEF :
  31. * mirror of 0x1FF0 - 0x1FFF
  32. * Use is prohibited about the image
  33. * 0x1FF0 - 0x1FFE :
  34. * SPC register
  35. * 0x1FFF :
  36. * un mapped
  37. *
  38. * Note:
  39. * It is possible to access it by putting it out to 8000H - BFFFH
  40. * though the SPC bank is arranged in chiefly 4000H-5FFF.
  41. */
  42. #include "MegaSCSI.hh"
  43. #include "MSXException.hh"
  44. #include "one_of.hh"
  45. #include "serialize.hh"
  46. #include <cassert>
  47. namespace openmsx {
  48. constexpr byte SPC = 0x7F;
  49. unsigned MegaSCSI::getSramSize() const
  50. {
  51. unsigned sramSize = getDeviceConfig().getChildDataAsInt("sramsize", 1024); // size in kb
  52. if (sramSize != one_of(1024u, 512u, 256u, 128u)) {
  53. throw MSXException(
  54. "SRAM size for ", getName(),
  55. " should be 128, 256, 512 or 1024kB and not ",
  56. sramSize, "kB!");
  57. }
  58. return sramSize * 1024; // in bytes
  59. }
  60. MegaSCSI::MegaSCSI(const DeviceConfig& config)
  61. : MSXDevice(config)
  62. , mb89352(config)
  63. , sram(getName() + " SRAM", getSramSize(), config)
  64. , romBlockDebug(*this, mapped, 0x4000, 0x8000, 13)
  65. , blockMask((sram.getSize() / 0x2000) - 1)
  66. {
  67. }
  68. void MegaSCSI::reset(EmuTime::param /*time*/)
  69. {
  70. for (int i = 0; i < 4; ++i) {
  71. setSRAM(i, 0);
  72. }
  73. mb89352.reset(true);
  74. }
  75. byte MegaSCSI::readMem(word address, EmuTime::param /*time*/)
  76. {
  77. byte result;
  78. if ((0x4000 <= address) && (address < 0xC000)) {
  79. unsigned page = (address / 0x2000) - 2;
  80. word addr = address & 0x1FFF;
  81. if (mapped[page] == SPC) {
  82. // SPC read
  83. if (addr < 0x1000) {
  84. // Data Register
  85. result = mb89352.readDREG();
  86. } else {
  87. result = mb89352.readRegister(addr & 0x0F);
  88. }
  89. } else {
  90. result = sram[0x2000 * mapped[page] + addr];
  91. }
  92. } else {
  93. result = 0xFF;
  94. }
  95. return result;
  96. }
  97. byte MegaSCSI::peekMem(word address, EmuTime::param /*time*/) const
  98. {
  99. if (const byte* cacheline = MegaSCSI::getReadCacheLine(address)) {
  100. return *cacheline;
  101. } else {
  102. address &= 0x1FFF;
  103. if (address < 0x1000) {
  104. return mb89352.peekDREG();
  105. } else {
  106. return mb89352.peekRegister(address & 0x0F);
  107. }
  108. }
  109. }
  110. const byte* MegaSCSI::getReadCacheLine(word address) const
  111. {
  112. if ((0x4000 <= address) && (address < 0xC000)) {
  113. unsigned page = (address / 0x2000) - 2;
  114. address &= 0x1FFF;
  115. if (mapped[page] == SPC) {
  116. return nullptr;
  117. } else {
  118. return &sram[0x2000 * mapped[page] + address];
  119. }
  120. } else {
  121. return unmappedRead;
  122. }
  123. }
  124. void MegaSCSI::writeMem(word address, byte value, EmuTime::param /*time*/)
  125. {
  126. if ((0x6000 <= address) && (address < 0x8000)) {
  127. byte region = ((address >> 11) & 3);
  128. setSRAM(region, value);
  129. } else if ((0x4000 <= address) && (address < 0xC000)) {
  130. unsigned page = (address / 0x2000) - 2;
  131. address &= 0x1FFF;
  132. if (mapped[page] == SPC) {
  133. if (address < 0x1000) {
  134. mb89352.writeDREG(value);
  135. } else {
  136. mb89352.writeRegister(address & 0x0F, value);
  137. }
  138. } else if (isWriteable[page]) {
  139. sram.write(0x2000 * mapped[page] + address, value);
  140. }
  141. }
  142. }
  143. byte* MegaSCSI::getWriteCacheLine(word address) const
  144. {
  145. if ((0x6000 <= address) && (address < 0x8000)) {
  146. return nullptr;
  147. } else if ((0x4000 <= address) && (address < 0xC000)) {
  148. unsigned page = (address / 0x2000) - 2;
  149. if (mapped[page] == SPC) {
  150. return nullptr;
  151. } else if (isWriteable[page]) {
  152. return nullptr;
  153. }
  154. }
  155. return unmappedWrite;
  156. }
  157. void MegaSCSI::setSRAM(unsigned region, byte block)
  158. {
  159. invalidateDeviceRWCache(region * 0x2000 + 0x4000, 0x2000);
  160. assert(region < 4);
  161. isWriteable[region] = (block & 0x80) != 0;
  162. mapped[region] = ((block & 0xC0) == 0x40) ? 0x7F : (block & blockMask);
  163. }
  164. template<typename Archive>
  165. void MegaSCSI::serialize(Archive& ar, unsigned /*version*/)
  166. {
  167. ar.serialize("SRAM", sram,
  168. "MB89352", mb89352,
  169. "isWriteable", isWriteable,
  170. "mapped", mapped);
  171. }
  172. INSTANTIATE_SERIALIZE_METHODS(MegaSCSI);
  173. REGISTER_MSXDEVICE(MegaSCSI, "MegaSCSI");
  174. } // namespace openmsx