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.

250 lines
5.8KB

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