Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
5.6KB

  1. /* RC2014 classic
  2. *
  3. * - 8K of ROM in range 0x0000-0x2000
  4. * - 32K of RAM in range 0x8000-0xffff
  5. * - ACIA in ports 0x80 (ctl) and 0x81 (data)
  6. *
  7. * ACIA is hooked to stdin/stdout. CTRL+D exits when in TTY mode.
  8. */
  9. #include <stdint.h>
  10. #include <stdio.h>
  11. #include <unistd.h>
  12. #include <termios.h>
  13. #define MAX_ROMSIZE 0x2000
  14. #include "emul.h"
  15. #include "acia.h"
  16. #include "sio.h"
  17. #include "sdc.h"
  18. #include "rc2014_spi.h"
  19. #include "at28.h"
  20. #define RAMSTART 0x8000
  21. #define ACIA_CTL_PORT 0x80
  22. #define ACIA_DATA_PORT 0x81
  23. #define SIO_ACTL_PORT 0x80
  24. #define SIO_ADATA_PORT 0x81
  25. #define SDC_CTL 0x05
  26. #define SDC_SPI 0x04
  27. bool use_sio = false;
  28. static ACIA acia;
  29. static SIO sio;
  30. static SDC sdc;
  31. static SPI spi;
  32. static AT28 at28;
  33. static uint8_t iord_acia_ctl()
  34. {
  35. return acia_ctl_rd(&acia);
  36. }
  37. static uint8_t iord_acia_data()
  38. {
  39. return acia_data_rd(&acia);
  40. }
  41. static void iowr_acia_ctl(uint8_t val)
  42. {
  43. acia_ctl_wr(&acia, val);
  44. }
  45. static void iowr_acia_data(uint8_t val)
  46. {
  47. acia_data_wr(&acia, val);
  48. }
  49. static uint8_t iord_sio_ctl()
  50. {
  51. return sio_actl_rd(&sio);
  52. }
  53. static uint8_t iord_sio_data()
  54. {
  55. return sio_adata_rd(&sio);
  56. }
  57. static void iowr_sio_ctl(uint8_t val)
  58. {
  59. sio_actl_wr(&sio, val);
  60. }
  61. static void iowr_sio_data(uint8_t val)
  62. {
  63. sio_adata_wr(&sio, val);
  64. }
  65. static uint8_t iord_spi()
  66. {
  67. return spi_rd(&spi);
  68. }
  69. static void iowr_spi(uint8_t val)
  70. {
  71. spi_wr(&spi, val);
  72. }
  73. byte spix_sdc(byte val) { return sdc_spix(&sdc, val); }
  74. // in emulation, exchanges are always instantaneous, so we
  75. // always report as ready.
  76. static uint8_t iord_spi_ctl()
  77. {
  78. return 0;
  79. }
  80. static void iowr_spi_ctl(uint8_t val)
  81. {
  82. spi_ctl_wr(&spi, val);
  83. }
  84. static bool has_irq()
  85. {
  86. return use_sio ? sio_has_irq(&sio) : acia_has_irq(&acia);
  87. }
  88. static bool hastx()
  89. {
  90. return use_sio ? sio_hastx(&sio) : acia_hastx(&acia);
  91. }
  92. static bool cantransmit()
  93. {
  94. return use_sio ? !sio_hasrx(&sio) : acia_cantransmit(&acia);
  95. }
  96. static uint8_t _read()
  97. {
  98. return use_sio ? sio_read(&sio) : acia_read(&acia);
  99. }
  100. static void _write(uint8_t val)
  101. {
  102. if (use_sio) { sio_write(&sio, val); } else { acia_write(&acia, val); }
  103. }
  104. static byte _at28_mem_read(int unused, ushort addr) {
  105. return at28_mem_read(&at28, addr);
  106. }
  107. static void _at28_mem_write(int unused, ushort addr, byte val) {
  108. at28_mem_write(&at28, addr, val);
  109. }
  110. static void usage()
  111. {
  112. fprintf(stderr, "Usage: ./rc2014 [-se] [-c sdcard.img] /path/to/rom\n");
  113. }
  114. int main(int argc, char *argv[])
  115. {
  116. FILE *fp = NULL;
  117. int ch;
  118. bool use_at28 = false;
  119. if (argc < 2) {
  120. usage();
  121. return 1;
  122. }
  123. acia_init(&acia);
  124. sio_init(&sio);
  125. sdc_init(&sdc);
  126. spi_init(&spi, spix_sdc);
  127. while ((ch = getopt(argc, argv, "sec:")) != -1) {
  128. switch (ch) {
  129. case 's':
  130. use_sio = true;
  131. break;
  132. case 'e':
  133. use_at28 = true;
  134. break;
  135. case 'c':
  136. fprintf(stderr, "Setting up SD card image with %s\n", optarg);
  137. sdc.fp = fopen(optarg, "r+");
  138. if (sdc.fp == NULL) {
  139. fprintf(stderr, "Can't open file\n");
  140. return 1;
  141. }
  142. break;
  143. }
  144. }
  145. if (optind != argc-1) {
  146. usage();
  147. return 1;
  148. }
  149. Machine *m = emul_init(argv[optind], 0);
  150. if (m == NULL) return 1;
  151. m->ramstart = RAMSTART;
  152. bool tty = isatty(fileno(stdin));
  153. struct termios term, saved_term;
  154. if (tty) {
  155. // Turn echo off: the shell takes care of its own echoing.
  156. if (tcgetattr(0, &term) == -1) {
  157. printf("Can't setup terminal.\n");
  158. return 1;
  159. }
  160. saved_term = term;
  161. term.c_lflag &= ~ECHO;
  162. term.c_lflag &= ~ICANON;
  163. term.c_cc[VMIN] = 0;
  164. term.c_cc[VTIME] = 0;
  165. tcsetattr(0, TCSADRAIN, &term);
  166. }
  167. if (use_sio) {
  168. m->iord[SIO_ACTL_PORT] = iord_sio_ctl;
  169. m->iord[SIO_ADATA_PORT] = iord_sio_data;
  170. m->iowr[SIO_ACTL_PORT] = iowr_sio_ctl;
  171. m->iowr[SIO_ADATA_PORT] = iowr_sio_data;
  172. } else {
  173. m->iord[ACIA_CTL_PORT] = iord_acia_ctl;
  174. m->iord[ACIA_DATA_PORT] = iord_acia_data;
  175. m->iowr[ACIA_CTL_PORT] = iowr_acia_ctl;
  176. m->iowr[ACIA_DATA_PORT] = iowr_acia_data;
  177. }
  178. m->iord[SDC_SPI] = iord_spi;
  179. m->iowr[SDC_SPI] = iowr_spi;
  180. m->iord[SDC_CTL] = iord_spi_ctl;
  181. m->iowr[SDC_CTL] = iowr_spi_ctl;
  182. if (use_at28) {
  183. at28_init(&at28, &m->cpu, 0x2000, 0x2000);
  184. m->cpu.memRead = _at28_mem_read;
  185. m->cpu.memWrite = _at28_mem_write;
  186. }
  187. char tosend = 0;
  188. while (emul_step()) {
  189. // Do we have an interrupt?
  190. if (has_irq()) {
  191. Z80INT(&m->cpu, 0);
  192. }
  193. // Is the RC2014 transmitting?
  194. if (hastx()) {
  195. putchar(_read());
  196. fflush(stdout);
  197. }
  198. // Do we have something to send?
  199. if (!tosend) {
  200. char c;
  201. if (read(fileno(stdin), &c, 1) == 1) {
  202. if (c == 5) {
  203. emul_memdump();
  204. c = 0; // don't send to RC2014
  205. }
  206. if (c == 4) { // CTRL+D
  207. // Stop here
  208. break;
  209. }
  210. tosend = c;
  211. } else if (!tty) {
  212. // This means we reached EOF
  213. break;
  214. }
  215. }
  216. if (tosend && cantransmit()) {
  217. _write(tosend);
  218. tosend = 0;
  219. }
  220. }
  221. if (tty) {
  222. printf("Done!\n");
  223. tcsetattr(0, TCSADRAIN, &saved_term);
  224. emul_printdebug();
  225. }
  226. if (sdc.fp) {
  227. fclose(sdc.fp);
  228. }
  229. return 0;
  230. }