SVIPPI.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include "SVIPPI.hh"
  2. #include "MSXMotherBoard.hh"
  3. #include "Reactor.hh"
  4. #include "CassettePort.hh"
  5. #include "JoystickPort.hh"
  6. #include "GlobalSettings.hh"
  7. #include "serialize.hh"
  8. // Keyboard Matrix
  9. //
  10. // Column/ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  11. // Line | | | | | | | | |
  12. // --------+-----+-----+-----+-----+-----+-----+-----+-----|
  13. // 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  14. // 1 | 8 | 9 | : | ' | , | = | . | / |
  15. // 2 | - | A | B | C | D | E | F | G |
  16. // 3 | H | I | J | K | L | M | N | O |
  17. // 4 | P | Q | R | S | T | U | V | W |
  18. // 5 | X | Y | Z | [ | \ | ] | BS | UP |
  19. // 6 |SHIFT|CTRL |LGRAP|RGRAP| ESC |STOP |ENTER|LEFT |
  20. // 7 | F1 | F2 | F3 | F4 | F5 | CLS | INS |DOWN |
  21. // 8 |SPACE| TAB | DEL |CAPS | SEL |PRINT| |RIGHT|
  22. // 9* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  23. // 10* | 8 | 9 | + | - | * | / | . | , |
  24. // ---------------------------------------------------------
  25. // * Numerical keypad (SVI-328 only)
  26. // PPI Port A Input (98H)
  27. // Bit Name Description
  28. // 0 TA Paddle or tablet 1, /SENSE
  29. // 1 TB Paddle or tablet 1, EOC
  30. // 2 TC Paddle or tablet 2, /SENSE
  31. // 3 TD Paddle or tablet 2, EOC
  32. // 4 /TRIGGER1 Joystick 1, Trigger
  33. // 5 /TRIGGER2 Joystick 2, Trigger
  34. // 6 /READY Cassette, Ready
  35. // 7 CASR Cassette, Read data
  36. //
  37. // PPI Port B Input (99H)
  38. // Bit Name Description
  39. // 0 IN0 Keyboard, Column status of selected line
  40. // 1 IN1 Keyboard, Column status of selected line
  41. // 2 IN2 Keyboard, Column status of selected line
  42. // 3 IN3 Keyboard, Column status of selected line
  43. // 4 IN4 Keyboard, Column status of selected line
  44. // 5 IN5 Keyboard, Column status of selected line
  45. // 6 IN6 Keyboard, Column status of selected line
  46. // 7 IN7 Keyboard, Column status of selected line
  47. //
  48. // PPI Port C Output (96H)
  49. // Bit Name Description
  50. // 0 KB0 Keyboard, Line select 0
  51. // 1 KB1 Keyboard, Line select 1
  52. // 2 KB2 Keyboard, Line select 2
  53. // 3 KB3 Keyboard, Line select 3
  54. // 4 CASON Cassette, Motor relay control (0=on, 1=off)
  55. // 5 CASW Cassette, Write data
  56. // 6 CASAUD Cassette, Audio control (1=enable other channel in, 0=disable channel)
  57. // 7 SOUND Keyboard, Click sound bit (pulse)
  58. //
  59. // PPI Mode control, Output (97H)
  60. //
  61. // PPI Port C, Input (9AH)
  62. namespace openmsx {
  63. // MSXDevice
  64. SVIPPI::SVIPPI(const DeviceConfig& config)
  65. : MSXDevice(config)
  66. , cassettePort(getMotherBoard().getCassettePort())
  67. , i8255(*this, getCurrentTime(), config.getGlobalSettings().getInvalidPpiModeSetting())
  68. , click(config)
  69. , keyboard(
  70. config.getMotherBoard(),
  71. config.getMotherBoard().getScheduler(),
  72. config.getMotherBoard().getCommandController(),
  73. config.getMotherBoard().getReactor().getEventDistributor(),
  74. config.getMotherBoard().getMSXEventDistributor(),
  75. config.getMotherBoard().getStateChangeDistributor(),
  76. Keyboard::MATRIX_SVI, config)
  77. , prevBits(15)
  78. , selectedRow(0)
  79. {
  80. ports[0] = &getMotherBoard().getJoystickPort(0);
  81. ports[1] = &getMotherBoard().getJoystickPort(1);
  82. auto time = getCurrentTime();
  83. ports[0]->write(0, time); // TODO correct? Bit2 must be 0 otherwise
  84. ports[1]->write(0, time); // e.g. KeyJoystick doesn't work
  85. reset(time);
  86. }
  87. void SVIPPI::reset(EmuTime::param time)
  88. {
  89. i8255.reset(time);
  90. click.reset(time);
  91. }
  92. byte SVIPPI::readIO(word port, EmuTime::param time)
  93. {
  94. return i8255.read(port & 0x03, time);
  95. }
  96. byte SVIPPI::peekIO(word port, EmuTime::param time) const
  97. {
  98. return i8255.peek(port & 0x03, time);
  99. }
  100. void SVIPPI::writeIO(word port, byte value, EmuTime::param time)
  101. {
  102. i8255.write(port & 0x03, value, time);
  103. }
  104. // I8255Interface
  105. byte SVIPPI::readA(EmuTime::param time)
  106. {
  107. byte triggers = ((ports[0]->read(time) & 0x10) ? 0x10 : 0) |
  108. ((ports[1]->read(time) & 0x10) ? 0x20 : 0);
  109. //byte cassetteReady = cassettePort.Ready() ? 0 : 0x40;
  110. byte cassetteReady = 0; // ready
  111. byte cassetteInput = cassettePort.cassetteIn(time) ? 0x80 : 0x00;
  112. return triggers | cassetteReady | cassetteInput;
  113. }
  114. byte SVIPPI::peekA(EmuTime::param /*time*/) const
  115. {
  116. return 0; // TODO
  117. }
  118. void SVIPPI::writeA(byte /*value*/, EmuTime::param /*time*/)
  119. {
  120. }
  121. byte SVIPPI::readB(EmuTime::param time)
  122. {
  123. return peekB(time);
  124. }
  125. byte SVIPPI::peekB(EmuTime::param /*time*/) const
  126. {
  127. auto& keyb = const_cast<Keyboard&>(keyboard);
  128. return keyb.getKeys()[selectedRow];
  129. }
  130. void SVIPPI::writeB(byte /*value*/, EmuTime::param /*time*/)
  131. {
  132. }
  133. nibble SVIPPI::readC1(EmuTime::param time)
  134. {
  135. return peekC1(time);
  136. }
  137. nibble SVIPPI::peekC1(EmuTime::param /*time*/) const
  138. {
  139. return 15; // TODO check this
  140. }
  141. nibble SVIPPI::readC0(EmuTime::param time)
  142. {
  143. return peekC0(time);
  144. }
  145. nibble SVIPPI::peekC0(EmuTime::param /*time*/) const
  146. {
  147. return selectedRow;
  148. }
  149. void SVIPPI::writeC1(nibble value, EmuTime::param time)
  150. {
  151. if ((prevBits ^ value) & 1) {
  152. cassettePort.setMotor((value & 1) == 0, time); // 0=0n, 1=Off
  153. }
  154. if ((prevBits ^ value) & 2) {
  155. cassettePort.cassetteOut((value & 2) != 0, time);
  156. }
  157. //if ((prevBits ^ value) & 4) {
  158. // cassetteDevice.Mute(); // CASAUD, mute case speker (1=enable, 0=disable)
  159. //}
  160. if ((prevBits ^ value) & 8) {
  161. click.setClick((value & 8) != 0, time);
  162. }
  163. prevBits = value;
  164. }
  165. void SVIPPI::writeC0(nibble value, EmuTime::param /*time*/)
  166. {
  167. selectedRow = value;
  168. }
  169. template<typename Archive>
  170. void SVIPPI::serialize(Archive& ar, unsigned /*version*/)
  171. {
  172. ar.template serializeBase<MSXDevice>(*this);
  173. ar.serialize("i8255", i8255);
  174. // merge prevBits and selectedRow into one byte
  175. byte portC = (prevBits << 4) | (selectedRow << 0);
  176. ar.serialize("portC", portC);
  177. if (ar.isLoader()) {
  178. selectedRow = (portC >> 0) & 0xF;
  179. nibble bits = (portC >> 4) & 0xF;
  180. writeC1(bits, getCurrentTime());
  181. }
  182. ar.serialize("keyboard", keyboard);
  183. }
  184. INSTANTIATE_SERIALIZE_METHODS(SVIPPI);
  185. REGISTER_MSXDEVICE(SVIPPI, "SVI-328 PPI");
  186. } // namespace openmsx