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.

420 lines
10KB

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "vm.h"
  4. // Port for block reads. Each read or write has to be done in 5 IO writes:
  5. // 1 - r/w. 1 for read, 2 for write.
  6. // 2 - blkid MSB
  7. // 3 - blkid LSB
  8. // 4 - dest addr MSB
  9. // 5 - dest addr LSB
  10. #define BLK_PORT 0x03
  11. #ifndef BLKFS_PATH
  12. #error BLKFS_PATH needed
  13. #endif
  14. #ifndef FBIN_PATH
  15. #error FBIN_PATH needed
  16. #endif
  17. static VM vm;
  18. static uint64_t blkop = 0; // 5 bytes
  19. static FILE *blkfp;
  20. // Read single byte from I/O handler, if set. addr is a word only because of
  21. // Forth's cell size, but can't actually address more than a byte-ful of ports.
  22. static byte io_read(word addr)
  23. {
  24. addr &= 0xff;
  25. IORD fn = vm.iord[addr];
  26. if (fn != NULL) {
  27. return fn();
  28. } else {
  29. fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
  30. return 0;
  31. }
  32. }
  33. static void io_write(word addr, byte val)
  34. {
  35. addr &= 0xff;
  36. IOWR fn = vm.iowr[addr];
  37. if (fn != NULL) {
  38. fn(val);
  39. } else {
  40. fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val);
  41. }
  42. }
  43. // I/O hook to read/write a chunk of 1024 byte to blkfs at specified blkid.
  44. // This is used by EFS@ and EFS! in xcomp.fs.
  45. // See comment above BLK_PORT define for poking convention.
  46. static void iowr_blk(byte val)
  47. {
  48. blkop <<= 8;
  49. blkop |= val;
  50. byte rw = blkop >> 32;
  51. if (rw) {
  52. word blkid = (blkop >> 16);
  53. word dest = blkop & 0xffff;
  54. blkop = 0;
  55. fseek(blkfp, blkid*1024, SEEK_SET);
  56. if (rw==2) { // write
  57. fwrite(&vm.mem[dest], 1024, 1, blkfp);
  58. } else { // read
  59. fread(&vm.mem[dest], 1024, 1, blkfp);
  60. }
  61. }
  62. }
  63. // get/set word from/to memory
  64. static word gw(word addr) { return vm.mem[addr+1] << 8 | vm.mem[addr]; }
  65. static void sw(word addr, word val) {
  66. vm.mem[addr] = val;
  67. vm.mem[addr+1] = val >> 8;
  68. }
  69. // pop word from SP
  70. static word pop() {
  71. if (vm.uflw) return 0;
  72. if (vm.SP >= SP_ADDR) { vm.uflw = true; return 0; }
  73. return vm.mem[vm.SP++] | vm.mem[vm.SP++] << 8;
  74. }
  75. // push word to SP
  76. static void push(word x) {
  77. vm.SP -= 2;
  78. if (vm.SP <= vm.RS) {
  79. vm.oflw = true; vm.SP = SP_ADDR; vm.RS = RS_ADDR;
  80. return;
  81. }
  82. sw(vm.SP, x);
  83. if (vm.SP < vm.minSP) { vm.minSP = vm.SP; }
  84. }
  85. // pop word from RS
  86. static word popRS() {
  87. if (vm.uflw) return 0;
  88. if (vm.RS <= RS_ADDR) { vm.uflw = true; return 0; }
  89. word x = gw(vm.RS); vm.RS -= 2; return x;
  90. }
  91. // push word to RS
  92. static void pushRS(word val) {
  93. vm.RS += 2;
  94. if (vm.SP <= vm.RS) {
  95. vm.oflw = true; vm.SP = SP_ADDR; vm.RS = RS_ADDR;
  96. return;
  97. }
  98. sw(vm.RS, val);
  99. if (vm.RS > vm.maxRS) { vm.maxRS = vm.RS; }
  100. }
  101. // The functions below directly map to native forth words defined in the
  102. // dictionary (B30)
  103. static void execute(word wordref) {
  104. byte wtype = vm.mem[wordref];
  105. if (wtype == 0) { // native
  106. vm.nativew[vm.mem[wordref+1]]();
  107. } else if (wtype == 1) { // compiled
  108. pushRS(vm.IP);
  109. vm.IP = wordref+1;
  110. } else { // cell or does
  111. push(wordref+1);
  112. if (wtype == 3) {
  113. pushRS(vm.IP);
  114. vm.IP = gw(wordref+3);
  115. }
  116. }
  117. }
  118. static word find(word daddr, word waddr) {
  119. byte len = vm.mem[waddr];
  120. while (1) {
  121. if ((vm.mem[daddr-1] & 0x7f) == len) {
  122. if (strncmp(&vm.mem[waddr+1], &vm.mem[daddr-3-len], len) == 0) {
  123. return daddr;
  124. }
  125. }
  126. daddr -= 3;
  127. word offset = gw(daddr);
  128. if (offset) {
  129. daddr -= offset;
  130. } else {
  131. return 0;
  132. }
  133. }
  134. }
  135. static void EXIT() { vm.IP = popRS(); }
  136. static void _br_() {
  137. word off = vm.mem[vm.IP];
  138. if (off > 0x7f ) { off -= 0x100; }
  139. vm.IP += off;
  140. }
  141. static void _cbr_() { if (!pop()) { _br_(); } else { vm.IP++; } }
  142. static void _loop_() {
  143. word I = gw(vm.RS); I++; sw(vm.RS, I);
  144. if (I == gw(vm.RS-2)) { // don't branch
  145. popRS(); popRS();
  146. vm.IP++;
  147. } else { // branch
  148. _br_();
  149. }
  150. }
  151. static void SP_to_R_2() { word x = pop(); pushRS(pop()); pushRS(x); }
  152. static void nlit() { push(gw(vm.IP)); vm.IP += 2; }
  153. static void slit() { push(vm.IP); vm.IP += vm.mem[vm.IP] + 1; }
  154. static void SP_to_R() { pushRS(pop()); }
  155. static void R_to_SP() { push(popRS()); }
  156. static void R_to_SP_2() { word x = popRS(); push(popRS()); push(x); }
  157. static void EXECUTE() { execute(pop()); }
  158. static void ROT() { // a b c -- b c a
  159. word c = pop(); word b = pop(); word a = pop();
  160. push(b); push(c); push(a);
  161. }
  162. static void DUP() { // a -- a a
  163. word a = pop(); push(a); push(a);
  164. }
  165. static void CDUP() {
  166. word a = pop(); push(a); if (a) { push(a); }
  167. }
  168. static void DROP() { pop(); }
  169. static void SWAP() { // a b -- b a
  170. word b = pop(); word a = pop();
  171. push(b); push(a);
  172. }
  173. static void OVER() { // a b -- a b a
  174. word b = pop(); word a = pop();
  175. push(a); push(b); push(a);
  176. }
  177. static void PICK() {
  178. word x = pop();
  179. push(gw(vm.SP+x*2));
  180. }
  181. static void _roll_() { // "1 2 3 4 4 (roll)" --> "1 3 4 4"
  182. word x = pop();
  183. while (x) { vm.mem[vm.SP+x+2] = vm.mem[vm.SP+x]; x--; }
  184. }
  185. static void DROP2() { pop(); pop(); }
  186. static void DUP2() { // a b -- a b a b
  187. word b = pop(); word a = pop();
  188. push(a); push(b); push(a); push(b);
  189. }
  190. static void S0() { push(SP_ADDR); }
  191. static void Saddr() { push(vm.SP); }
  192. static void AND() { push(pop() & pop()); }
  193. static void OR() { push(pop() | pop()); }
  194. static void XOR() { push(pop() ^ pop()); }
  195. static void NOT() { push(!pop()); }
  196. static void PLUS() { push(pop() + pop()); }
  197. static void MINUS() {
  198. word b = pop(); word a = pop();
  199. push(a - b);
  200. }
  201. static void MULT() { push(pop() * pop()); }
  202. static void DIVMOD() {
  203. word b = pop(); word a = pop();
  204. push(a % b); push(a / b);
  205. }
  206. static void STORE() {
  207. word a = pop(); word val = pop();
  208. sw(a, val);
  209. }
  210. static void FETCH() { push(gw(pop())); }
  211. static void CSTORE() {
  212. word a = pop(); word val = pop();
  213. vm.mem[a] = val;
  214. }
  215. static void CFETCH() { push(vm.mem[pop()]); }
  216. static void IO_OUT() {
  217. word a = pop(); word val = pop();
  218. io_write(a, val);
  219. }
  220. static void IO_IN() { push(io_read(pop())); }
  221. static void RI() { push(gw(vm.RS)); }
  222. static void RI_() { push(gw(vm.RS-2)); }
  223. static void RJ() { push(gw(vm.RS-4)); }
  224. static void BYE() { vm.running = false; }
  225. static void _resSP_() { vm.SP = SP_ADDR; }
  226. static void _resRS_() { vm.RS = RS_ADDR; }
  227. static void Seq() {
  228. word s1 = pop(); word s2 = pop();
  229. byte len = vm.mem[s1];
  230. if (len == vm.mem[s2]) {
  231. s1++; s2++;
  232. push(strncmp(&vm.mem[s1], &vm.mem[s2], len) == 0);
  233. } else {
  234. push(0);
  235. }
  236. }
  237. static void CMP() {
  238. word b = pop(); word a = pop();
  239. if (a == b) { push(0); } else if (a > b) { push(1); } else { push(-1); }
  240. }
  241. static void _find() {
  242. word waddr = pop(); word daddr = pop();
  243. daddr = find(daddr, waddr);
  244. if (daddr) {
  245. push(daddr); push(1);
  246. } else {
  247. push(waddr); push(0);
  248. }
  249. }
  250. static void ZERO() { push(0); }
  251. static void ONE() { push(1); }
  252. static void MONE() { push(-1); }
  253. static void PLUS1() { push(pop()+1); }
  254. static void MINUS1() { push(pop()-1); }
  255. static void MINUS2() { push(pop()-2); }
  256. static void PLUS2() { push(pop()+2); }
  257. static void RSHIFT() { word u = pop(); push(pop()>>u); }
  258. static void LSHIFT() { word u = pop(); push(pop()<<u); }
  259. static void native(NativeWord func) {
  260. vm.nativew[vm.nativew_count++] = func;
  261. }
  262. VM* VM_init() {
  263. fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH);
  264. blkfp = fopen(BLKFS_PATH, "r+");
  265. if (!blkfp) {
  266. fprintf(stderr, "Can't open\n");
  267. return NULL;
  268. }
  269. fseek(blkfp, 0, SEEK_END);
  270. if (ftell(blkfp) < 100 * 1024) {
  271. fclose(blkfp);
  272. fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n");
  273. return NULL;
  274. }
  275. fseek(blkfp, 0, SEEK_SET);
  276. // initialize memory
  277. memset(vm.mem, 0, 0x10000);
  278. FILE *bfp = fopen(FBIN_PATH, "r");
  279. if (!bfp) {
  280. fprintf(stderr, "Can't open forth.bin\n");
  281. return NULL;
  282. }
  283. int i = 0;
  284. int c = getc(bfp);
  285. while (c != EOF) {
  286. vm.mem[i++] = c;
  287. c = getc(bfp);
  288. }
  289. fclose(bfp);
  290. vm.SP = SP_ADDR;
  291. vm.RS = RS_ADDR;
  292. vm.minSP = SP_ADDR;
  293. vm.maxRS = RS_ADDR;
  294. vm.nativew_count = 0;
  295. for (int i=0; i<0x100; i++) {
  296. vm.iord[i] = NULL;
  297. vm.iowr[i] = NULL;
  298. }
  299. vm.iowr[BLK_PORT] = iowr_blk;
  300. // Added in the same order as in xcomp.fs
  301. native(EXIT);
  302. native(_br_);
  303. native(_cbr_);
  304. native(_loop_);
  305. native(SP_to_R_2);
  306. native(nlit);
  307. native(slit);
  308. native(SP_to_R);
  309. native(R_to_SP);
  310. native(R_to_SP_2);
  311. native(EXECUTE);
  312. native(ROT);
  313. native(DUP);
  314. native(CDUP);
  315. native(DROP);
  316. native(SWAP);
  317. native(OVER);
  318. native(PICK);
  319. native(_roll_);
  320. native(DROP2);
  321. native(DUP2);
  322. native(S0);
  323. native(Saddr);
  324. native(AND);
  325. native(OR);
  326. native(XOR);
  327. native(NOT);
  328. native(PLUS);
  329. native(MINUS);
  330. native(MULT);
  331. native(DIVMOD);
  332. native(STORE);
  333. native(FETCH);
  334. native(CSTORE);
  335. native(CFETCH);
  336. native(IO_OUT);
  337. native(IO_IN);
  338. native(RI);
  339. native(RI_);
  340. native(RJ);
  341. native(BYE);
  342. native(_resSP_);
  343. native(_resRS_);
  344. native(Seq);
  345. native(CMP);
  346. native(_find);
  347. native(ZERO);
  348. native(ONE);
  349. native(MONE);
  350. native(PLUS1);
  351. native(MINUS1);
  352. native(PLUS2);
  353. native(MINUS2);
  354. native(RSHIFT);
  355. native(LSHIFT);
  356. vm.IP = gw(0x04) + 1; // BOOT
  357. sw(SYSVARS+0x02, gw(0x08)); // CURRENT
  358. sw(SYSVARS+0x04, gw(0x08)); // HERE
  359. vm.uflw = false;
  360. vm.oflw = false;
  361. vm.running = true;
  362. return &vm;
  363. }
  364. void VM_deinit()
  365. {
  366. fclose(blkfp);
  367. }
  368. bool VM_steps(int n) {
  369. if (!vm.running) {
  370. fprintf(stderr, "machine halted!\n");
  371. return false;
  372. }
  373. while (n && vm.running) {
  374. word wordref = gw(vm.IP);
  375. vm.IP += 2;
  376. execute(wordref);
  377. if (vm.uflw) {
  378. vm.uflw = false;
  379. execute(gw(0x06)); /* uflw */
  380. }
  381. if (vm.oflw) {
  382. vm.oflw = false;
  383. execute(gw(0x13)); /* oflw */
  384. }
  385. n--;
  386. }
  387. return vm.running;
  388. }
  389. void VM_memdump() {
  390. fprintf(stderr, "Dumping memory to memdump. IP %04x\n", vm.IP);
  391. FILE *fp = fopen("memdump", "w");
  392. fwrite(vm.mem, 0x10000, 1, fp);
  393. fclose(fp);
  394. }
  395. void VM_debugstr(char *s) {
  396. sprintf(s, "SP %04x (%04x) RS %04x (%04x)",
  397. vm.SP, vm.minSP, vm.RS, vm.maxRS);
  398. }
  399. void VM_printdbg() {
  400. char buf[0x100];
  401. VM_debugstr(buf);
  402. fprintf(stderr, "%s\n", buf);
  403. }