Emulator core geared towards emulating ZZT and Super ZZT.
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.

zzt.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /**
  2. * Copyright (c) 2018 Adrian Siekierka
  3. *
  4. * This file is part of Zeta.
  5. *
  6. * Zeta is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Zeta is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Zeta. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "zzt.h"
  20. #ifdef EMSCRIPTEN
  21. #define fprintf(...)
  22. #else
  23. #include <stdio.h>
  24. #endif
  25. typedef struct {
  26. cpu_state cpu;
  27. // keyboard
  28. int qch, qke, kmod;
  29. // joystick
  30. u8 joy_xstrobe_val, joy_ystrobe_val;
  31. u8 joy_xstrobes, joy_ystrobes;
  32. // mouse
  33. u16 mouse_buttons;
  34. u16 mouse_x, mouse_y;
  35. s16 mouse_xd, mouse_yd;
  36. // I/O
  37. u8 cga_status;
  38. u8 port_42_latch;
  39. u16 port_42;
  40. // u8 port_43[3]; (not actually used)
  41. u8 port_61;
  42. u8 port_201;
  43. // DOS
  44. u32 dos_dta;
  45. } zzt_state;
  46. zzt_state zzt;
  47. void zzt_kmod_set(int mod) {
  48. zzt.kmod |= mod;
  49. }
  50. void zzt_kmod_clear(int mod) {
  51. zzt.kmod &= ~mod;
  52. }
  53. void zzt_key(int c, int k) {
  54. zzt.qch = c >= 0 && c < 128 ? c : 0;
  55. zzt.qke = k;
  56. fprintf(stderr, "kbget %d %d\n", zzt.qch, zzt.qke);
  57. }
  58. void zzt_keyup(int k) {
  59. if (zzt.qke == k) {
  60. zzt.qch = -1;
  61. zzt.qke = -1;
  62. }
  63. }
  64. static void cpu_func_intr_0x10(cpu_state* cpu);
  65. static void cpu_func_intr_0x13(cpu_state* cpu);
  66. static void cpu_func_intr_0x16(cpu_state* cpu);
  67. static void cpu_func_intr_0x21(cpu_state* cpu);
  68. void zzt_mark_frame(void) {
  69. zzt.cga_status |= 0x8;
  70. }
  71. #define JOY_MIN 3
  72. #define JOY_MAX 51
  73. #define JOY_MID (JOY_MIN+JOY_MAX/2)
  74. #define JOY_RANGE (JOY_MAX-JOY_MIN)
  75. void zzt_joy_set(int button) {
  76. if (button < 2) zzt.port_201 &= ~(1 << (button + 4));
  77. }
  78. void zzt_joy_clear(int button) {
  79. if (button < 2) zzt.port_201 |= (1 << (button + 4));
  80. }
  81. void zzt_joy_axis(int axis, int value) {
  82. if (axis >= 2) return;
  83. value = ((value + 127) * JOY_RANGE / 254) + JOY_MIN;
  84. switch (axis) {
  85. case 0: zzt.joy_xstrobe_val = value; break;
  86. case 1: zzt.joy_ystrobe_val = value; break;
  87. }
  88. }
  89. static void zzt_joy_strobe(zzt_state* zzt) {
  90. if (zzt->joy_xstrobes == 0) zzt->cpu.keep_going++;
  91. if (zzt->joy_ystrobes == 0) zzt->cpu.keep_going++;
  92. zzt->joy_xstrobes = zzt->joy_xstrobe_val;
  93. zzt->joy_ystrobes = zzt->joy_ystrobe_val;
  94. }
  95. void zzt_mouse_set(int button) {
  96. zzt.mouse_buttons |= 1 << button;
  97. }
  98. void zzt_mouse_clear(int button) {
  99. zzt.mouse_buttons &= ~(1 << button);
  100. }
  101. static inline int m_clamp(int v, int min, int max) {
  102. return (v > min) ? ((v < max) ? v : max) : min;
  103. }
  104. void zzt_mouse_axis(int axis, int value) {
  105. switch (axis) {
  106. case 0:
  107. zzt.mouse_xd += value;
  108. zzt.mouse_x = m_clamp(zzt.mouse_x + value, 0, 639);
  109. break;
  110. case 1:
  111. zzt.mouse_yd += value;
  112. zzt.mouse_y = m_clamp(zzt.mouse_y + value, 0, 349);
  113. break;
  114. }
  115. }
  116. static u16 cpu_func_port_in_main(cpu_state* cpu, u16 addr) {
  117. zzt_state* zzt = (zzt_state*) cpu;
  118. switch (addr) {
  119. case 0x61:
  120. return zzt->port_61;
  121. case 0x201:
  122. if (!zeta_has_feature(FEATURE_JOY_CONNECTED))
  123. return 0xF0;
  124. zzt->port_201 &= 0xF0;
  125. if (zzt->joy_xstrobes > 0) {
  126. zzt->joy_xstrobes--;
  127. if (zzt->joy_xstrobes == 0) cpu->keep_going--;
  128. zzt->port_201 |= 1;
  129. }
  130. if (zzt->joy_ystrobes > 0) {
  131. zzt->joy_ystrobes--;
  132. if (zzt->joy_ystrobes == 0) cpu->keep_going--;
  133. zzt->port_201 |= 2;
  134. }
  135. return zzt->port_201;
  136. case 0x3DA: {
  137. int old_status = zzt->cga_status;
  138. zzt->cga_status = (old_status & (~0x8)) ^ 0x1;
  139. return old_status;
  140. }
  141. default:
  142. fprintf(stderr, "port in %04X\n", addr);
  143. return 0;
  144. }
  145. }
  146. static void cpu_func_port_out_main(cpu_state* cpu, u16 addr, u16 val) {
  147. zzt_state* zzt = (zzt_state*) cpu;
  148. switch (addr) {
  149. case 0x42:
  150. if (zzt->port_42_latch) zzt->port_42 = (zzt->port_42 & 0xFF) | ((val << 8) & 0xFF00);
  151. else zzt->port_42 = (zzt->port_42 & 0xFF00) | (val & 0xFF);
  152. zzt->port_42_latch ^= 1;
  153. // if (!port_42_latch && (port_43[2] & 0x04) == 0x04 && (port_61 & 3) == 3) {
  154. if (!(zzt->port_42_latch) && (zzt->port_61 & 3) == 3) {
  155. speaker_on(1193182.0 / zzt->port_42);
  156. }
  157. return;
  158. case 0x43: {
  159. /* int addr = (val >> 6) & 0x3;
  160. if (addr == 3) return;
  161. if ((val & 0x30) == 0) {
  162. zzt->port_43[addr] = val;
  163. } */
  164. } return;
  165. case 0x61:
  166. zzt->port_61 = val;
  167. if ((val & 3) != 3) {
  168. speaker_off();
  169. }
  170. return;
  171. case 0x201:
  172. zzt_joy_strobe(zzt);
  173. return;
  174. default:
  175. fprintf(stderr, "port out %04X = %04X\n", addr, val);
  176. }
  177. }
  178. static void cpu_func_intr_0x33(cpu_state* cpu) {
  179. zzt_state* zzt = (zzt_state*) cpu;
  180. switch (cpu->ax) {
  181. case 0:
  182. if (zeta_has_feature(FEATURE_MOUSE_CONNECTED)) {
  183. cpu->ax = 0xFFFF;
  184. cpu->bx = 0xFFFF;
  185. }
  186. break;
  187. case 3:
  188. cpu->bx = zzt->mouse_buttons;
  189. cpu->cx = zzt->mouse_x / 8;
  190. cpu->dx = zzt->mouse_y / 14;
  191. break;
  192. case 0xB:
  193. cpu->cx = zzt->mouse_xd;
  194. cpu->dx = zzt->mouse_yd;
  195. zzt->mouse_xd = 0;
  196. zzt->mouse_yd = 0;
  197. break;
  198. default:
  199. fprintf(stderr, "mouse %04X\n", cpu->ax);
  200. break;
  201. }
  202. }
  203. static int cpu_func_interrupt_main(cpu_state* cpu, u8 intr) {
  204. switch (intr) {
  205. case 0x11:
  206. cpu->al = cpu->ram[0x410];
  207. cpu->ah = cpu->ram[0x411];
  208. break;
  209. case 0x12:
  210. cpu->al = cpu->ram[0x413];
  211. cpu->ah = cpu->ram[0x414];
  212. break;
  213. case 0x08: {
  214. u32 time = cpu->ram[0x46c] | (cpu->ram[0x46d] << 8)
  215. | (cpu->ram[0x46e] << 16) | (cpu->ram[0x46f] << 24);
  216. time++;
  217. cpu->ram[0x46c] = time & 0xFF;
  218. cpu->ram[0x46d] = (time>>8) & 0xFF;
  219. cpu->ram[0x46e] = (time>>16) & 0xFF;
  220. cpu->ram[0x46f] = (time>>24) & 0xFF;
  221. cpu_emit_interrupt(cpu, 0x1C);
  222. } break;
  223. case 0x1C: break;
  224. case 0x10: cpu_func_intr_0x10(cpu); break;
  225. case 0x13: cpu_func_intr_0x13(cpu); break;
  226. case 0x16: cpu_func_intr_0x16(cpu); break;
  227. case 0x21: cpu_func_intr_0x21(cpu); break;
  228. case 0x33: cpu_func_intr_0x33(cpu); break;
  229. case 0x15:
  230. fprintf(stderr, "sysconf %04X\n", cpu->ax);
  231. cpu->ah = 0x86;
  232. cpu->flags |= FLAG_CARRY;
  233. break;
  234. default:
  235. fprintf(stderr, "interrupt %02X\n", intr);
  236. break;
  237. }
  238. return STATE_CONTINUE;
  239. }
  240. static void video_scroll_up(cpu_state* cpu, int lines, u8 empty_attr, int y1, int x1, int y2, int x2) {
  241. if (lines <= 0) {
  242. for (int y = y1; y <= y2; y++)
  243. for (int x = x1; x <= x2; x++) {
  244. cpu->ram[TEXT_ADDR(x,y)] = 0;
  245. cpu->ram[TEXT_ADDR(x,y)+1] = empty_attr;
  246. }
  247. } else {
  248. for (int y = y1+lines; y <= y2; y++)
  249. for (int x = x1; x <= x2; x++) {
  250. cpu->ram[TEXT_ADDR(x,y-lines)] = cpu->ram[TEXT_ADDR(x,y)];
  251. cpu->ram[TEXT_ADDR(x,y-lines)+1] = cpu->ram[TEXT_ADDR(x,y)+1];
  252. }
  253. for (int y = y2-lines+1; y <= y2; y++)
  254. for (int x = x1; x <= x2; x++) {
  255. cpu->ram[TEXT_ADDR(x,y)] = 0;
  256. cpu->ram[TEXT_ADDR(x,y)+1] = empty_attr;
  257. }
  258. }
  259. }
  260. static void cpu_0x10_output(cpu_state* cpu, u8 chr) {
  261. u8 cursor_width = cpu->ram[0x44A];
  262. u8 cursor_height = 25;
  263. switch (chr) {
  264. case 0x0D:
  265. cpu->ram[0x450] = 0;
  266. break;
  267. case 0x0A:
  268. if (cpu->ram[0x451] < (cursor_height - 1)) {
  269. cpu->ram[0x451]++;
  270. } else {
  271. video_scroll_up(cpu, 1, 0x07, 0, 0, cursor_height - 1, cursor_width - 1);
  272. }
  273. break;
  274. case 0x08:
  275. if (cpu->ram[0x450] > 0)
  276. cpu->ram[0x450]--;
  277. cpu->ram[TEXT_ADDR(cpu->ram[0x450], cpu->ram[0x451])] = 0;
  278. break;
  279. case 0x07:
  280. break;
  281. default:
  282. cpu->ram[TEXT_ADDR(cpu->ram[0x450], cpu->ram[0x451])] = chr;
  283. cpu->ram[0x450]++;
  284. if (cpu->ram[0x450] >= cursor_width) {
  285. cpu->ram[0x450] = 0;
  286. if (cpu->ram[0x451] < (cursor_height - 1)) {
  287. cpu->ram[0x451]++;
  288. } else {
  289. video_scroll_up(cpu, 1, 0x07, 0, 0, cursor_height - 1, cursor_width - 1);
  290. }
  291. }
  292. break;
  293. }
  294. }
  295. static int video_mode = 3;
  296. int zzt_video_mode(void) {
  297. return video_mode;
  298. }
  299. static void cpu_func_intr_0x10(cpu_state* cpu) {
  300. if (cpu->ah == 0x02) {
  301. cpu->ram[0x451] = cpu->dh;
  302. cpu->ram[0x450] = cpu->dl;
  303. } else if (cpu->ah == 0x03) {
  304. cpu->dh = cpu->ram[0x451];
  305. cpu->dl = cpu->ram[0x450];
  306. } else if (cpu->ah == 0x04) {
  307. cpu->ah = 0;
  308. } else if (cpu->ah == 0x06) {
  309. video_scroll_up(cpu, cpu->al, cpu->bh, cpu->ch, cpu->cl, cpu->dh, cpu->dl);
  310. } else if (cpu->ah == 0x08) {
  311. u32 addr = TEXT_ADDR(cpu->bl, cpu->bh);
  312. cpu->ah = 0x08;
  313. cpu->al = cpu->ram[addr];
  314. cpu->bh = cpu->ram[addr+1];
  315. } else if (cpu->ah == 0x09 || cpu->ah == 0x0A) {
  316. u32 addr = TEXT_ADDR(cpu->bl, cpu->bh);
  317. for (int i = 0; i < cpu->cx && addr < 160*25; i++, addr+=2) {
  318. cpu->ram[addr] = cpu->al;
  319. if (cpu->ah == 0x09) cpu->ram[addr + 1] = cpu->bl;
  320. }
  321. } else if (cpu->ah == 0x0E) {
  322. cpu_0x10_output(cpu, cpu->al);
  323. } else if (cpu->ah == 0x00) {
  324. video_mode = cpu->al & 0x7F;
  325. fprintf(stderr, "set video mode to %d\n", cpu->al);
  326. } else if (cpu->ah == 0x0F) {
  327. cpu->ah = cpu->ram[0x44A];
  328. cpu->al = video_mode;
  329. cpu->bh = 0;
  330. } else {
  331. fprintf(stderr, "int 0x10 AX=%04X AH=%02X AL=%02X BL=%02X\n",
  332. cpu->ax, cpu->ah, cpu->al, cpu->bl);
  333. cpu->flags |= FLAG_CARRY;
  334. }
  335. }
  336. static void cpu_func_intr_0x13(cpu_state* cpu) {
  337. fprintf(stderr, "int 0x13 AX=%04X\n", cpu->ax);
  338. }
  339. static void cpu_func_intr_0x16(cpu_state* cpu) {
  340. zzt_state* zzt = (zzt_state*) cpu;
  341. if (cpu->ah == 0x00) {
  342. if (zzt->qke >= 0) {
  343. cpu->flags &= ~FLAG_ZERO;
  344. cpu->ah = zzt->qke;
  345. cpu->al = zzt->qch;
  346. zzt->qch = -1;
  347. zzt->qke = -1;
  348. } else {
  349. cpu->flags |= FLAG_ZERO;
  350. }
  351. return;
  352. } else if (cpu->ah == 0x01) {
  353. if (zzt->qke >= 0) {
  354. cpu->flags &= ~FLAG_ZERO;
  355. cpu->ah = zzt->qke;
  356. cpu->al = zzt->qch;
  357. } else {
  358. cpu->flags |= FLAG_ZERO;
  359. }
  360. return;
  361. } else if (cpu->ah == 0x02) {
  362. cpu->al = zzt->kmod;
  363. return;
  364. }
  365. fprintf(stderr, "int 0x16 AX=%04X\n", cpu->ax);
  366. }
  367. #define STR_DS_DX (char*)(&cpu->ram[cpu->seg[SEG_DS]*16 + cpu->dx])
  368. static void cpu_func_intr_0x21(cpu_state* cpu) {
  369. zzt_state* zzt = (zzt_state*) cpu;
  370. switch (cpu->ah) {
  371. case 0x30: // DOS version
  372. cpu->al = 3;
  373. cpu->ah = 0;
  374. cpu->bh = 0;
  375. return;
  376. case 0x06: // d.c.output
  377. cpu_0x10_output(cpu, cpu->dl);
  378. cpu->al = cpu->dl;
  379. return;
  380. case 0x1A: // set dta
  381. zzt->dos_dta = (cpu->seg[SEG_DS]*16 + cpu->dx);
  382. return;
  383. case 0x25: // set ivt
  384. cpu->ram[cpu->al * 4] = cpu->dl;
  385. cpu->ram[cpu->al * 4 + 1] = cpu->dh;
  386. cpu->ram[cpu->al * 4 + 2] = cpu->seg[SEG_DS] & 0xFF;
  387. cpu->ram[cpu->al * 4 + 3] = cpu->seg[SEG_DS] >> 8;
  388. return;
  389. case 0x2C: { // systime
  390. long ms = zeta_time_ms();
  391. cpu->ch = (ms / 3600000) % 24;
  392. cpu->cl = (ms / 60000) % 60;
  393. cpu->dh = (ms / 1000) % 60;
  394. cpu->dl = (ms / 10) % 100;
  395. } return;
  396. case 0x35: // get ivt
  397. cpu->bl = cpu->ram[cpu->al * 4];
  398. cpu->bh = cpu->ram[cpu->al * 4 + 1];
  399. cpu->seg[SEG_ES] = cpu->ram[cpu->al * 4 + 2]
  400. | (cpu->ram[cpu->al * 4 + 3] << 8);
  401. return;
  402. case 0x3C: { // creat
  403. int handle = vfs_open(STR_DS_DX, 0x10001);
  404. if (handle < 0) {
  405. fprintf(stderr, "not found\n");
  406. cpu->ax = 0x02;
  407. cpu->flags |= FLAG_CARRY;
  408. } else {
  409. cpu->ax = handle;
  410. cpu->flags &= ~FLAG_CARRY;
  411. }
  412. } return;
  413. case 0x3D: { // open
  414. fprintf(stderr, "open %02X %s\n", cpu->al, STR_DS_DX);
  415. int handle = vfs_open(STR_DS_DX, cpu->al);
  416. if (handle < 0) {
  417. fprintf(stderr, "not found\n");
  418. cpu->ax = 0x02;
  419. cpu->flags |= FLAG_CARRY;
  420. } else {
  421. cpu->ax = handle;
  422. cpu->flags &= ~FLAG_CARRY;
  423. }
  424. } return;
  425. case 0x3E: { // close
  426. int res = vfs_close(cpu->bx);
  427. if (res < 0) {
  428. cpu->ax = 0x06;
  429. cpu->flags |= FLAG_CARRY;
  430. } else {
  431. cpu->flags &= ~FLAG_CARRY;
  432. }
  433. } return;
  434. case 0x3F: { // read
  435. fprintf(stderr, "read %04X\n", cpu->cx);
  436. int res = vfs_read(cpu->bx, (u8*)STR_DS_DX, cpu->cx);
  437. if (res < 0) {
  438. cpu->ax = 0x05;
  439. cpu->flags |= FLAG_CARRY;
  440. } else {
  441. cpu->ax = res;
  442. cpu->flags &= ~FLAG_CARRY;
  443. }
  444. } return;
  445. case 0x40: { // write
  446. fprintf(stderr, "write %04X\n", cpu->cx);
  447. if (cpu->cx == 0) {
  448. // we don't implement the special case
  449. cpu->ax = 0x05;
  450. cpu->flags |= FLAG_CARRY;
  451. return;
  452. }
  453. int res = vfs_write(cpu->bx, (u8*)STR_DS_DX, cpu->cx);
  454. if (res < 0) {
  455. cpu->ax = 0x05;
  456. cpu->flags |= FLAG_CARRY;
  457. } else {
  458. cpu->ax = res;
  459. cpu->flags &= ~FLAG_CARRY;
  460. }
  461. } return;
  462. case 0x42: { // lseek
  463. int res = vfs_seek(cpu->bx, (cpu->cx << 16) | cpu->dx, cpu->al);
  464. if (res < 0) {
  465. cpu->ax = 0x05;
  466. cpu->flags |= FLAG_CARRY;
  467. } else {
  468. cpu->ax = res;
  469. cpu->flags &= ~FLAG_CARRY;
  470. }
  471. } return;
  472. case 0x44: // 0x4400
  473. if (cpu->ax == 0x4400) {
  474. cpu->ax = 0x01;
  475. cpu->flags |= FLAG_CARRY;
  476. return;
  477. }
  478. break;
  479. case 0x4C:
  480. cpu->terminated = 1;
  481. break;
  482. case 0x4E: { // findfirst
  483. int res = vfs_findfirst(cpu->ram + zzt->dos_dta, cpu->cx, STR_DS_DX);
  484. if (res < 0) {
  485. cpu->ax = 0x12;
  486. cpu->flags |= FLAG_CARRY;
  487. } else {
  488. cpu->flags &= ~FLAG_CARRY;
  489. }
  490. break;
  491. };
  492. case 0x4F: { // findnext
  493. int res = vfs_findnext(cpu->ram + zzt->dos_dta);
  494. if (res < 0) {
  495. cpu->ax = 0x12;
  496. cpu->flags |= FLAG_CARRY;
  497. } else {
  498. cpu->flags &= ~FLAG_CARRY;
  499. }
  500. };
  501. default:
  502. fprintf(stderr, "int 0x21 AX=%04X\n", cpu->ax);
  503. break;
  504. }
  505. }
  506. /* #define MAX_ALLOC (639*64)
  507. static u32 seg_allocs[MAX_ALLOC];
  508. static int mem_alloc(u32 paragraphs, u8 simulate) {
  509. int offset = 0;
  510. while (offset < MAX_ALLOC) {
  511. fprintf(stderr, "offset = %d\n", offset);
  512. if (seg_allocs[offset] > 0) {
  513. offset += seg_allocs[offset];
  514. } else {
  515. int size = 0;
  516. while (seg_allocs[offset+size] == 0 && size < paragraphs) {
  517. size++;
  518. }
  519. fprintf(stderr, "size = %d/%d\n", size, paragraphs);
  520. if (size == paragraphs) {
  521. if (!simulate) {
  522. for (int i = 0; i < size; i++) {
  523. seg_allocs[offset+i] = (size-i);
  524. }
  525. }
  526. fprintf(stderr, "offset >= %d\n", offset);
  527. return offset;
  528. } else {
  529. offset += size;
  530. }
  531. }
  532. }
  533. return -1;
  534. }
  535. static int mem_free(u32 addr) {
  536. int v = seg_allocs[addr];
  537. if (v <= 0) return 0;
  538. if (addr > 0 && seg_allocs[addr - 1] > v) return 0;
  539. for (int i = 0; i < v; i++) {
  540. seg_allocs[addr+i] = 0;
  541. }
  542. return 1;
  543. } */
  544. static u8 vfs_read8(int handle, int pos) {
  545. u8 v;
  546. vfs_seek(handle, pos, VFS_SEEK_SET);
  547. vfs_read(handle, &v, 1);
  548. return v;
  549. }
  550. static u16 vfs_read16(int handle, int pos) {
  551. u8 v1, v2;
  552. vfs_seek(handle, pos, VFS_SEEK_SET);
  553. vfs_read(handle, &v1, 1);
  554. vfs_read(handle, &v2, 1);
  555. return v1 | (v2 << 8);
  556. }
  557. u32 zzt_init(void) {
  558. /* for (int i = 0; i < MAX_ALLOC; i++)
  559. seg_allocs[i] = (i < 256) ? (256-i) : 0; */
  560. zzt.qch = -1;
  561. zzt.qke = -1;
  562. zzt.joy_xstrobe_val = -1;
  563. zzt.joy_ystrobe_val = -1;
  564. zzt.joy_xstrobes = 0;
  565. zzt.joy_ystrobes = 0;
  566. zzt.mouse_buttons = 0;
  567. zzt.mouse_x = 640 / 2;
  568. zzt.mouse_y = 350 / 2;
  569. zzt.port_201 = 0xF0;
  570. cpu_init_globals();
  571. cpu_init(&(zzt.cpu));
  572. // sysconf constants
  573. zzt.cpu.ram[0x410] = 0x61;
  574. zzt.cpu.ram[0x411] = 0x00;
  575. zzt.cpu.ram[0x413] = (640) & 255;
  576. zzt.cpu.ram[0x414] = (640) >> 8;
  577. zzt.cpu.ram[0xFFFFE] = 0xFB;
  578. // video constants
  579. zzt.cpu.ram[0x44A] = 80;
  580. zzt.cpu.ram[0x463] = 0xD4;
  581. zzt.cpu.ram[0x464] = 0x03;
  582. zzt.cpu.func_port_in = cpu_func_port_in_main;
  583. zzt.cpu.func_port_out = cpu_func_port_out_main;
  584. zzt.cpu.func_interrupt = cpu_func_interrupt_main;
  585. // load exe
  586. // NOTE: relocation items are not handled, as the ZZT
  587. // .EXE does not need them
  588. int handle = vfs_open("zzt.exe", 0);
  589. if (handle < 0)
  590. handle = vfs_open("superz.exe", 0);
  591. int last_page_size = vfs_read16(handle, 2);
  592. int pages = vfs_read16(handle, 4);
  593. int hdr_offset = vfs_read16(handle, 8);
  594. // int minalloc = vfs_read16(handle, 0xA);
  595. // int maxalloc = vfs_read16(handle, 0xC);
  596. int filesize = (pages * 512) - ((last_page_size > 0) ? (512 - last_page_size) : 0) - (hdr_offset * 16);
  597. /* int size_pars = (filesize + 15) / 16;
  598. size_pars += 16; // PSP */
  599. // int size_pars = 40400;
  600. // int offset_pars = mem_alloc(size_pars, 0);
  601. int offset_pars = 0x100;
  602. int size_pars = 0xA000 - 0x100;
  603. // location
  604. zzt.cpu.seg[SEG_CS] = vfs_read16(handle, 0x16) + offset_pars + 0x10;
  605. zzt.cpu.seg[SEG_SS] = vfs_read16(handle, 0xE) + offset_pars + 0x10;
  606. zzt.cpu.seg[SEG_DS] = offset_pars;
  607. zzt.cpu.seg[SEG_ES] = offset_pars;
  608. zzt.cpu.ip = vfs_read16(handle, 0x14);
  609. zzt.cpu.sp = vfs_read16(handle, 0x10);
  610. // build faux psp
  611. int psp = offset_pars * 16;
  612. int seg_first = offset_pars + size_pars;
  613. fprintf(stderr, "seg_first %04X\n", seg_first);
  614. zzt.cpu.ram[psp + 0x02] = seg_first & 0xFF;
  615. zzt.cpu.ram[psp + 0x03] = seg_first >> 8;
  616. zzt.cpu.ram[psp + 0x80] = 1;
  617. zzt.cpu.ram[psp + 0x81] = 0x0D;
  618. // load file into memory
  619. vfs_seek(handle, hdr_offset * 16, VFS_SEEK_SET);
  620. vfs_read(handle, &(zzt.cpu.ram[(offset_pars * 16) + 256]), filesize);
  621. fprintf(stderr, "wrote %d bytes to %d\n", filesize, (offset_pars * 16 + 256));
  622. vfs_close(handle);
  623. return psp;
  624. }
  625. int zzt_execute(int opcodes) {
  626. return cpu_execute(&(zzt.cpu), opcodes);
  627. }
  628. void zzt_mark_timer(void) {
  629. cpu_emit_interrupt(&(zzt.cpu), 0x08);
  630. }
  631. u8* zzt_get_ram(void) {
  632. return zzt.cpu.ram;
  633. }