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.

194 lines
4.0KB

  1. /* Common code between forth and stage binaries.
  2. They all run on the same kind of virtual machine: A z80 CPU, 64K of RAM/ROM.
  3. */
  4. #include <string.h>
  5. #include "emul.h"
  6. // Port for block reads. Write 2 bytes, MSB first, on that port and then
  7. // read 1024 bytes from the DATA port.
  8. #define BLK_PORT 0x03
  9. #define BLKDATA_PORT 0x04
  10. #ifndef BLKFS_PATH
  11. #error BLKFS_PATH needed
  12. #endif
  13. #ifndef FBIN_PATH
  14. #error FBIN_PATH needed
  15. #endif
  16. static Machine m;
  17. static ushort traceval = 0;
  18. static uint16_t blkid = 0;
  19. static FILE *blkfp;
  20. static uint8_t io_read(int unused, uint16_t addr)
  21. {
  22. addr &= 0xff;
  23. IORD fn = m.iord[addr];
  24. if (fn != NULL) {
  25. return fn();
  26. } else {
  27. fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
  28. return 0;
  29. }
  30. }
  31. static void io_write(int unused, uint16_t addr, uint8_t val)
  32. {
  33. addr &= 0xff;
  34. IOWR fn = m.iowr[addr];
  35. if (fn != NULL) {
  36. fn(val);
  37. } else {
  38. fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val);
  39. }
  40. }
  41. static void iowr_blk(uint8_t val)
  42. {
  43. blkid <<= 8;
  44. blkid |= val;
  45. fseek(blkfp, blkid*1024, SEEK_SET);
  46. }
  47. static uint8_t iord_blkdata()
  48. {
  49. return getc(blkfp);
  50. }
  51. static void iowr_blkdata(uint8_t val)
  52. {
  53. putc(val, blkfp);
  54. }
  55. static uint8_t mem_read(int unused, uint16_t addr)
  56. {
  57. return m.mem[addr];
  58. }
  59. static void mem_write(int unused, uint16_t addr, uint8_t val)
  60. {
  61. if (addr < m.ramstart) {
  62. fprintf(stderr, "Writing to ROM (%d)!\n", addr);
  63. emul_memdump();
  64. fprintf(stderr, "Press any key to continue...\n");
  65. while (getchar() > 0x100);
  66. }
  67. m.mem[addr] = val;
  68. }
  69. Machine* emul_init()
  70. {
  71. fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH);
  72. blkfp = fopen(BLKFS_PATH, "r+");
  73. if (!blkfp) {
  74. fprintf(stderr, "Can't open\n");
  75. return NULL;
  76. }
  77. fseek(blkfp, 0, SEEK_END);
  78. if (ftell(blkfp) < 100 * 1024) {
  79. fclose(blkfp);
  80. fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n");
  81. return NULL;
  82. }
  83. fseek(blkfp, 0, SEEK_SET);
  84. // initialize memory
  85. memset(m.mem, 0, 0x10000);
  86. FILE *bfp = fopen(FBIN_PATH, "r");
  87. if (!bfp) {
  88. fprintf(stderr, "Can't open forth.bin\n");
  89. return NULL;
  90. }
  91. int i = 0;
  92. int c = getc(bfp);
  93. while (c != EOF) {
  94. m.mem[i++] = c;
  95. c = getc(bfp);
  96. }
  97. fclose(bfp);
  98. m.ramstart = 0;
  99. m.minsp = 0xffff;
  100. m.maxix = 0;
  101. for (int i=0; i<0x100; i++) {
  102. m.iord[i] = NULL;
  103. m.iowr[i] = NULL;
  104. }
  105. Z80RESET(&m.cpu);
  106. m.cpu.memRead = mem_read;
  107. m.cpu.memWrite = mem_write;
  108. m.cpu.ioRead = io_read;
  109. m.cpu.ioWrite = io_write;
  110. m.iowr[BLK_PORT] = iowr_blk;
  111. m.iord[BLKDATA_PORT] = iord_blkdata;
  112. m.iowr[BLKDATA_PORT] = iowr_blkdata;
  113. return &m;
  114. }
  115. void emul_deinit()
  116. {
  117. fclose(blkfp);
  118. }
  119. bool emul_step()
  120. {
  121. if (!m.cpu.halted) {
  122. Z80Execute(&m.cpu);
  123. ushort newsp = m.cpu.R1.wr.SP;
  124. if (newsp != 0 && newsp < m.minsp) {
  125. m.minsp = newsp;
  126. }
  127. if (m.cpu.R1.wr.IX > m.maxix) {
  128. m.maxix = m.cpu.R1.wr.IX;
  129. }
  130. return true;
  131. } else {
  132. return false;
  133. }
  134. }
  135. bool emul_steps(unsigned int steps)
  136. {
  137. while (steps) {
  138. if (!emul_step()) {
  139. return false;
  140. }
  141. steps--;
  142. }
  143. return true;
  144. }
  145. void emul_loop()
  146. {
  147. while (emul_step());
  148. }
  149. void emul_trace(ushort addr)
  150. {
  151. ushort newval = m.mem[addr+1] << 8 | m.mem[addr];
  152. if (newval != traceval) {
  153. traceval = newval;
  154. fprintf(stderr, "trace: %04x PC: %04x\n", traceval, m.cpu.PC);
  155. }
  156. }
  157. void emul_memdump()
  158. {
  159. fprintf(stderr, "Dumping memory to memdump. PC %04x\n", m.cpu.PC);
  160. FILE *fp = fopen("memdump", "w");
  161. fwrite(m.mem, 0x10000, 1, fp);
  162. fclose(fp);
  163. }
  164. void emul_debugstr(char *s)
  165. {
  166. sprintf(s, "SP %04x (%04x) IX %04x (%04x)",
  167. m.cpu.R1.wr.SP, m.minsp, m.cpu.R1.wr.IX, m.maxix);
  168. }
  169. void emul_printdebug()
  170. {
  171. fprintf(stderr, "Min SP: %04x\n", m.minsp);
  172. fprintf(stderr, "Max IX: %04x\n", m.maxix);
  173. }