Mirror of CollapseOS
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

452 satır
11KB

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