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.

390 lines
9.4KB

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