Mirror of CollapseOS
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

216 рядки
4.7KB

  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. Each read or write has to be done in 5 IO writes:
  7. // 1 - r/w. 1 for read, 2 for write.
  8. // 2 - blkid MSB
  9. // 3 - blkid LSB
  10. // 4 - dest addr MSB
  11. // 5 - dest addr LSB
  12. #define BLK_PORT 0x03
  13. #ifndef BLKFS_PATH
  14. #error BLKFS_PATH needed
  15. #endif
  16. #ifndef FBIN_PATH
  17. #error FBIN_PATH needed
  18. #endif
  19. static Machine m;
  20. static ushort traceval = 0;
  21. static uint64_t blkop = 0; // 5 bytes
  22. static FILE *blkfp;
  23. static uint8_t io_read(int unused, uint16_t addr)
  24. {
  25. addr &= 0xff;
  26. IORD fn = m.iord[addr];
  27. if (fn != NULL) {
  28. return fn();
  29. } else {
  30. fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
  31. return 0;
  32. }
  33. }
  34. static void io_write(int unused, uint16_t addr, uint8_t val)
  35. {
  36. addr &= 0xff;
  37. IOWR fn = m.iowr[addr];
  38. if (fn != NULL) {
  39. fn(val);
  40. } else {
  41. fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val);
  42. }
  43. }
  44. static void iowr_blk(uint8_t val)
  45. {
  46. blkop <<= 8;
  47. blkop |= val;
  48. uint8_t rw = blkop >> 32;
  49. if (rw) {
  50. uint16_t blkid = (blkop >> 16);
  51. uint16_t dest = blkop & 0xffff;
  52. blkop = 0;
  53. fseek(blkfp, blkid*1024, SEEK_SET);
  54. if (rw==2) { // write
  55. fwrite(&m.mem[dest], 1024, 1, blkfp);
  56. } else { // read
  57. fread(&m.mem[dest], 1024, 1, blkfp);
  58. }
  59. }
  60. }
  61. static uint8_t mem_read(int unused, uint16_t addr)
  62. {
  63. return m.mem[addr];
  64. }
  65. static void mem_write(int unused, uint16_t addr, uint8_t val)
  66. {
  67. if (addr < m.ramstart) {
  68. fprintf(stderr, "Writing to ROM (%d)!\n", addr);
  69. emul_memdump();
  70. fprintf(stderr, "Press any key to continue...\n");
  71. while (getchar() > 0x100);
  72. }
  73. m.mem[addr] = val;
  74. }
  75. Machine* emul_init(char *binpath, ushort binoffset)
  76. {
  77. fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH);
  78. blkfp = fopen(BLKFS_PATH, "r+");
  79. if (!blkfp) {
  80. fprintf(stderr, "Can't open\n");
  81. return NULL;
  82. }
  83. fseek(blkfp, 0, SEEK_END);
  84. if (ftell(blkfp) < 100 * 1024) {
  85. fclose(blkfp);
  86. fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n");
  87. return NULL;
  88. }
  89. fseek(blkfp, 0, SEEK_SET);
  90. // initialize memory
  91. memset(m.mem, 0, 0x10000);
  92. if (binpath == NULL) {
  93. binpath = FBIN_PATH;
  94. }
  95. FILE *bfp = fopen(binpath, "r");
  96. if (!bfp) {
  97. fprintf(stderr, "Can't open %s\n", binpath);
  98. return NULL;
  99. }
  100. int i = binoffset;
  101. int c = getc(bfp);
  102. while (c != EOF) {
  103. #ifdef MAX_ROMSIZE
  104. if (i >= MAX_ROMSIZE) {
  105. fprintf(stderr, "ROM image too large.\n");
  106. fclose(fp);
  107. return NULL;
  108. }
  109. #endif
  110. m.mem[i++] = c;
  111. c = getc(bfp);
  112. }
  113. fclose(bfp);
  114. m.ramstart = 0;
  115. m.minsp = 0xffff;
  116. m.maxix = 0;
  117. for (int i=0; i<0x100; i++) {
  118. m.iord[i] = NULL;
  119. m.iowr[i] = NULL;
  120. }
  121. m.pchooks_cnt = 0;
  122. Z80RESET(&m.cpu);
  123. m.cpu.memRead = mem_read;
  124. m.cpu.memWrite = mem_write;
  125. m.cpu.ioRead = io_read;
  126. m.cpu.ioWrite = io_write;
  127. m.iowr[BLK_PORT] = iowr_blk;
  128. return &m;
  129. }
  130. void emul_deinit()
  131. {
  132. fclose(blkfp);
  133. }
  134. bool emul_step()
  135. {
  136. if (!m.cpu.halted) {
  137. Z80Execute(&m.cpu);
  138. ushort newsp = m.cpu.R1.wr.SP;
  139. if (newsp != 0 && newsp < m.minsp) {
  140. m.minsp = newsp;
  141. }
  142. if (m.cpu.R1.wr.IX > m.maxix) {
  143. m.maxix = m.cpu.R1.wr.IX;
  144. }
  145. for (int i=0; i<m.pchooks_cnt; i++) {
  146. if (m.cpu.PC == m.pchooks[i]) {
  147. m.pchookfunc(&m);
  148. break;
  149. }
  150. }
  151. return true;
  152. } else {
  153. return false;
  154. }
  155. }
  156. bool emul_steps(unsigned int steps)
  157. {
  158. while (steps) {
  159. if (!emul_step()) {
  160. return false;
  161. }
  162. steps--;
  163. }
  164. return true;
  165. }
  166. void emul_loop()
  167. {
  168. while (emul_step());
  169. }
  170. void emul_trace(ushort addr)
  171. {
  172. ushort newval = m.mem[addr+1] << 8 | m.mem[addr];
  173. if (newval != traceval) {
  174. traceval = newval;
  175. fprintf(stderr, "trace: %04x PC: %04x\n", traceval, m.cpu.PC);
  176. }
  177. }
  178. void emul_memdump()
  179. {
  180. fprintf(stderr, "Dumping memory to memdump. PC %04x\n", m.cpu.PC);
  181. FILE *fp = fopen("memdump", "w");
  182. fwrite(m.mem, 0x10000, 1, fp);
  183. fclose(fp);
  184. }
  185. void emul_debugstr(char *s)
  186. {
  187. sprintf(s, "SP %04x (%04x) IX %04x (%04x)",
  188. m.cpu.R1.wr.SP, m.minsp, m.cpu.R1.wr.IX, m.maxix);
  189. }
  190. void emul_printdebug()
  191. {
  192. fprintf(stderr, "Min SP: %04x\n", m.minsp);
  193. fprintf(stderr, "Max IX: %04x\n", m.maxix);
  194. }
  195. byte iord_noop() { return 0; }
  196. void iowr_noop(byte val) {}