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.

231 lines
5.7KB

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include "../libz80/z80.h"
  4. #include "kernel-bin.h"
  5. #include "zasm-bin.h"
  6. /* zasm reads from a specified blkdev, assemble the file and writes the result
  7. * in another specified blkdev. In our emulator layer, we use stdin and stdout
  8. * as those specified blkdevs.
  9. *
  10. * This executable takes one argument: the path to a .cfs file to use for
  11. * includes.
  12. *
  13. * Because the input blkdev needs support for Seek, we buffer it in the emulator
  14. * layer.
  15. *
  16. * Memory layout:
  17. *
  18. * 0x0000 - 0x3fff: ROM code from zasm_glue.asm
  19. * 0x4000 - 0x47ff: RAM for kernel and stack
  20. * 0x4800 - 0x57ff: Userspace code
  21. * 0x5800 - 0xffff: Userspace RAM
  22. *
  23. * I/O Ports:
  24. *
  25. * 0 - stdin / stdout
  26. * 1 - When written to, rewind stdin buffer to the beginning.
  27. */
  28. // in sync with zasm_glue.asm
  29. #define USER_CODE 0x4800
  30. #define STDIO_PORT 0x00
  31. #define STDIN_SEEK_PORT 0x01
  32. #define FS_DATA_PORT 0x02
  33. #define FS_SEEK_PORT 0x03
  34. #define STDERR_PORT 0x04
  35. // Other consts
  36. #define STDIN_BUFSIZE 0x8000
  37. // When defined, we dump memory instead of dumping expected stdout
  38. //#define MEMDUMP
  39. //#define DEBUG
  40. // By default, we don't spit what zasm prints. Too noisy. Define VERBOSE if
  41. // you want to spit this content to stderr.
  42. //#define VERBOSE
  43. static Z80Context cpu;
  44. static uint8_t mem[0x10000];
  45. // STDIN buffer, allows us to seek and tell
  46. static uint8_t inpt[STDIN_BUFSIZE];
  47. static int inpt_size;
  48. static int inpt_ptr;
  49. static uint8_t middle_of_seek_tell = 0;
  50. static uint8_t fsdev[0x40000] = {0};
  51. static uint32_t fsdev_size = 0;
  52. static uint32_t fsdev_ptr = 0;
  53. static uint8_t fsdev_seek_tell_cnt = 0;
  54. static uint8_t io_read(int unused, uint16_t addr)
  55. {
  56. addr &= 0xff;
  57. if (addr == STDIO_PORT) {
  58. if (inpt_ptr < inpt_size) {
  59. return inpt[inpt_ptr++];
  60. } else {
  61. return 0;
  62. }
  63. } else if (addr == STDIN_SEEK_PORT) {
  64. if (middle_of_seek_tell) {
  65. middle_of_seek_tell = 0;
  66. return inpt_ptr & 0xff;
  67. } else {
  68. #ifdef DEBUG
  69. fprintf(stderr, "tell %d\n", inpt_ptr);
  70. #endif
  71. middle_of_seek_tell = 1;
  72. return inpt_ptr >> 8;
  73. }
  74. } else if (addr == FS_DATA_PORT) {
  75. if (fsdev_ptr < fsdev_size) {
  76. return fsdev[fsdev_ptr++];
  77. } else {
  78. return 0;
  79. }
  80. } else if (addr == FS_SEEK_PORT) {
  81. if (fsdev_seek_tell_cnt != 0) {
  82. return fsdev_seek_tell_cnt;
  83. } else if (fsdev_ptr >= fsdev_size) {
  84. return 1;
  85. } else {
  86. return 0;
  87. }
  88. } else {
  89. fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
  90. return 0;
  91. }
  92. }
  93. static void io_write(int unused, uint16_t addr, uint8_t val)
  94. {
  95. addr &= 0xff;
  96. if (addr == STDIO_PORT) {
  97. // When mem-dumping, we don't output regular stuff.
  98. #ifndef MEMDUMP
  99. putchar(val);
  100. #endif
  101. } else if (addr == STDIN_SEEK_PORT) {
  102. if (middle_of_seek_tell) {
  103. inpt_ptr |= val;
  104. middle_of_seek_tell = 0;
  105. #ifdef DEBUG
  106. fprintf(stderr, "seek %d\n", inpt_ptr);
  107. #endif
  108. } else {
  109. inpt_ptr = (val << 8) & 0xff00;
  110. middle_of_seek_tell = 1;
  111. }
  112. } else if (addr == FS_DATA_PORT) {
  113. if (fsdev_ptr < fsdev_size) {
  114. fsdev[fsdev_ptr++] = val;
  115. }
  116. } else if (addr == FS_SEEK_PORT) {
  117. if (fsdev_seek_tell_cnt == 0) {
  118. fsdev_ptr = val << 16;
  119. fsdev_seek_tell_cnt = 1;
  120. } else if (fsdev_seek_tell_cnt == 1) {
  121. fsdev_ptr |= val << 8;
  122. fsdev_seek_tell_cnt = 2;
  123. } else {
  124. fsdev_ptr |= val;
  125. fsdev_seek_tell_cnt = 0;
  126. #ifdef DEBUG
  127. fprintf(stderr, "FS seek %d\n", fsdev_ptr);
  128. #endif
  129. }
  130. } else if (addr == STDERR_PORT) {
  131. #ifdef VERBOSE
  132. fputc(val, stderr);
  133. #endif
  134. } else {
  135. fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val);
  136. }
  137. }
  138. static uint8_t mem_read(int unused, uint16_t addr)
  139. {
  140. return mem[addr];
  141. }
  142. static void mem_write(int unused, uint16_t addr, uint8_t val)
  143. {
  144. mem[addr] = val;
  145. }
  146. int main(int argc, char *argv[])
  147. {
  148. if (argc > 2) {
  149. fprintf(stderr, "Too many args\n");
  150. return 1;
  151. }
  152. // initialize memory
  153. for (int i=0; i<sizeof(KERNEL); i++) {
  154. mem[i] = KERNEL[i];
  155. }
  156. for (int i=0; i<sizeof(USERSPACE); i++) {
  157. mem[i+USER_CODE] = USERSPACE[i];
  158. }
  159. fsdev_size = 0;
  160. if (argc == 2) {
  161. FILE *fp = fopen(argv[1], "r");
  162. if (fp == NULL) {
  163. fprintf(stderr, "Can't open file %s\n", argv[1]);
  164. return 1;
  165. }
  166. int c = fgetc(fp);
  167. while (c != EOF) {
  168. fsdev[fsdev_size] = c;
  169. fsdev_size++;
  170. c = fgetc(fp);
  171. }
  172. fclose(fp);
  173. }
  174. // read stdin in buffer
  175. inpt_size = 0;
  176. inpt_ptr = 0;
  177. int c = getchar();
  178. while (c != EOF) {
  179. inpt[inpt_ptr] = c & 0xff;
  180. inpt_ptr++;
  181. if (inpt_ptr == STDIN_BUFSIZE) {
  182. break;
  183. }
  184. c = getchar();
  185. }
  186. inpt_size = inpt_ptr;
  187. inpt_ptr = 0;
  188. Z80RESET(&cpu);
  189. cpu.ioRead = io_read;
  190. cpu.ioWrite = io_write;
  191. cpu.memRead = mem_read;
  192. cpu.memWrite = mem_write;
  193. while (!cpu.halted) {
  194. Z80Execute(&cpu);
  195. }
  196. #ifdef MEMDUMP
  197. for (int i=0; i<0x10000; i++) {
  198. putchar(mem[i]);
  199. }
  200. #endif
  201. fflush(stdout);
  202. int res = cpu.R1.br.A;
  203. if (res != 0) {
  204. int lineno = cpu.R1.wr.HL;
  205. int inclineno = cpu.R1.wr.DE;
  206. if (inclineno) {
  207. fprintf(
  208. stderr,
  209. "Error %d on line %d, include line %d\n",
  210. res,
  211. lineno,
  212. inclineno);
  213. } else {
  214. fprintf(stderr, "Error %d on line %d\n", res, lineno);
  215. }
  216. }
  217. return res;
  218. }