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.

187 lines
3.8KB

  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. // initialize memory
  78. memset(m.mem, 0, 0x10000);
  79. FILE *bfp = fopen(FBIN_PATH, "r");
  80. if (!bfp) {
  81. fprintf(stderr, "Can't open forth.bin\n");
  82. return NULL;
  83. }
  84. int i = 0;
  85. int c = getc(bfp);
  86. while (c != EOF) {
  87. m.mem[i++] = c;
  88. c = getc(bfp);
  89. }
  90. fclose(bfp);
  91. m.ramstart = 0;
  92. m.minsp = 0xffff;
  93. m.maxix = 0;
  94. for (int i=0; i<0x100; i++) {
  95. m.iord[i] = NULL;
  96. m.iowr[i] = NULL;
  97. }
  98. Z80RESET(&m.cpu);
  99. m.cpu.memRead = mem_read;
  100. m.cpu.memWrite = mem_write;
  101. m.cpu.ioRead = io_read;
  102. m.cpu.ioWrite = io_write;
  103. m.iowr[BLK_PORT] = iowr_blk;
  104. m.iord[BLKDATA_PORT] = iord_blkdata;
  105. m.iowr[BLKDATA_PORT] = iowr_blkdata;
  106. return &m;
  107. }
  108. void emul_deinit()
  109. {
  110. fclose(blkfp);
  111. }
  112. bool emul_step()
  113. {
  114. if (!m.cpu.halted) {
  115. Z80Execute(&m.cpu);
  116. ushort newsp = m.cpu.R1.wr.SP;
  117. if (newsp != 0 && newsp < m.minsp) {
  118. m.minsp = newsp;
  119. }
  120. if (m.cpu.R1.wr.IX > m.maxix) {
  121. m.maxix = m.cpu.R1.wr.IX;
  122. }
  123. return true;
  124. } else {
  125. return false;
  126. }
  127. }
  128. bool emul_steps(unsigned int steps)
  129. {
  130. while (steps) {
  131. if (!emul_step()) {
  132. return false;
  133. }
  134. steps--;
  135. }
  136. return true;
  137. }
  138. void emul_loop()
  139. {
  140. while (emul_step());
  141. }
  142. void emul_trace(ushort addr)
  143. {
  144. ushort newval = m.mem[addr+1] << 8 | m.mem[addr];
  145. if (newval != traceval) {
  146. traceval = newval;
  147. fprintf(stderr, "trace: %04x PC: %04x\n", traceval, m.cpu.PC);
  148. }
  149. }
  150. void emul_memdump()
  151. {
  152. fprintf(stderr, "Dumping memory to memdump. PC %04x\n", m.cpu.PC);
  153. FILE *fp = fopen("memdump", "w");
  154. fwrite(m.mem, 0x10000, 1, fp);
  155. fclose(fp);
  156. }
  157. void emul_debugstr(char *s)
  158. {
  159. sprintf(s, "SP %04x (%04x) IX %04x (%04x)",
  160. m.cpu.R1.wr.SP, m.minsp, m.cpu.R1.wr.IX, m.maxix);
  161. }
  162. void emul_printdebug()
  163. {
  164. fprintf(stderr, "Min SP: %04x\n", m.minsp);
  165. fprintf(stderr, "Max IX: %04x\n", m.maxix);
  166. }