Human68k CUI emulator with sound.
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.

v68human.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include <string.h>
  2. #include "v68human.h"
  3. #include "v68io.h"
  4. #include "v68.h"
  5. #include "musashi/m68kcpu.h"
  6. void v68_human_init() {
  7. verbose1("v68_human_init\n");
  8. v68.log_calls = 0;
  9. v68.cmd_queue_pos = 0;
  10. v68.running = 0;
  11. uint16_t fake_human[] = {
  12. #include "fake_human.inc"
  13. };
  14. for(int i = 0; i < sizeof(fake_human) / sizeof(fake_human[0]); i++) {
  15. v68.ram[HUMAN_HEAD + i * 2] = fake_human[i] >> 8;
  16. v68.ram[HUMAN_HEAD + i * 2 + 1] = fake_human[i] & 0xff;
  17. }
  18. v68.heap_start = v68.heap_top = STACK_TOP + STACK_SIZE;
  19. /* Init mem chain */
  20. m68k_write_memory_32(HUMAN_HEAD - 0x10 + 0x00, 0);
  21. m68k_write_memory_32(HUMAN_HEAD - 0x10 + 0x04, 0);
  22. m68k_write_memory_32(HUMAN_HEAD - 0x10 + 0x08, HUMAN_WORK);
  23. m68k_write_memory_32(HUMAN_HEAD - 0x10 + 0x0c, 0);
  24. }
  25. int v68_run_command(char *cmd) {
  26. verbose2("v68_run_command cmd=\"%s\"\n", cmd);
  27. // Find first space, or \0
  28. char *c = cmd;
  29. while(*c && !isspace(*c)) {
  30. c++;
  31. }
  32. if(*c)
  33. *c++ = 0;
  34. int cmd_len = strlen(cmd);
  35. // move past any space, on to the args
  36. if(c) while(*c && isspace(*c)) c++;
  37. int l = strlen(c);
  38. if(l > 255) l = 255;
  39. // cmdline args are copied here
  40. v68.ram[STACK_TOP] = l;
  41. strncpy((char *)&v68.ram[STACK_TOP + 1], c, 255);
  42. v68.ram[STACK_TOP + 1 + l] = 0;
  43. int fd = v68_io_open(cmd, O_RDONLY);
  44. if(fd < 0) {
  45. fprintf(stderr, "Could not open %s\n", cmd);
  46. return -1;
  47. }
  48. off_t o = v68_io_seek(fd, 0, SEEK_END);
  49. v68_io_seek(fd, 0, SEEK_SET);
  50. if(cmd_len > 2 && cmd[cmd_len - 2] == '.' && (cmd[cmd_len - 1] == 'x' || cmd[cmd_len - 1] == 'X')) {
  51. // .X files
  52. uint8_t xhead[0x40];
  53. v68_io_read(fd, xhead, sizeof(xhead));
  54. if(xhead[0] != 'H' && xhead[1] != 'U') {
  55. fprintf(stderr, "%s: X file signature invalid, not \"HU\"\n", cmd);
  56. v68_io_close(fd);
  57. return -1;
  58. }
  59. #define READ_LONG(x) ((xhead[x] << 24) | (xhead[x + 1] << 16) | (xhead[x + 2] << 8) | xhead[x + 3])
  60. #define READ_SHORT(x) ((xhead[x] << 8) | xhead[x + 1])
  61. uint8_t load_mode = xhead[3];
  62. (void)load_mode;
  63. uint32_t base_addr = READ_LONG(0x04);
  64. uint32_t entry_point = READ_LONG(0x08);
  65. verbose3("base_addr=%08x entry_point=%08x\n", base_addr, entry_point);
  66. uint32_t text_size = READ_LONG(0x0c);
  67. if(text_size > 0 && 0x40 + text_size > o) {
  68. fprintf(stderr, "%s: .text section size exceeds end of file.\n", cmd);
  69. v68_io_close(fd);
  70. return -1;
  71. }
  72. uint32_t data_size = READ_LONG(0x10);
  73. if(data_size > 0 && 0x40 + text_size + data_size > o) {
  74. fprintf(stderr, "%s: .data section size exceeds end of file.\n", cmd);
  75. v68_io_close(fd);
  76. return -1;
  77. }
  78. uint32_t bss_size = READ_LONG(0x14);
  79. uint32_t reloc_size = READ_LONG(0x18);
  80. if(reloc_size > 0 && 0x40 + text_size + data_size + reloc_size > o) {
  81. fprintf(stderr, "%s: Relocation data size exceeds end of file.\n", cmd);
  82. v68_io_close(fd);
  83. return -1;
  84. }
  85. uint32_t sym_table_size = READ_LONG(0x1c);
  86. if(sym_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size > o) {
  87. fprintf(stderr, "%s: Symbol table size exceeds end of file.\n", cmd);
  88. v68_io_close(fd);
  89. return -1;
  90. }
  91. uint32_t scd_line_num_table_size = READ_LONG(0x20);
  92. if(scd_line_num_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size > o) {
  93. fprintf(stderr, "%s: SCD line number table size exceeds end of file.\n", cmd);
  94. v68_io_close(fd);
  95. return -1;
  96. }
  97. uint32_t scd_sym_table_size = READ_LONG(0x24);
  98. if(scd_sym_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size + scd_sym_table_size > o) {
  99. fprintf(stderr, "%s: SCD symbol table size exceeds end of file.\n", cmd);
  100. v68_io_close(fd);
  101. return -1;
  102. }
  103. uint32_t scd_string_table_size = READ_LONG(0x28);
  104. if(scd_string_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size + scd_sym_table_size + scd_string_table_size > o) {
  105. fprintf(stderr, "%s: SCD string table size exceeds end of file.\n", cmd);
  106. v68_io_close(fd);
  107. return -1;
  108. }
  109. uint32_t bound_pos = READ_LONG(0x3c);
  110. if(bound_pos && bound_pos >= o) {
  111. fprintf(stderr, "Bound module list position exceeds end of file.\n");
  112. v68_io_close(fd);
  113. return -1;
  114. }
  115. uint32_t remaining = v68_mem_remaining();
  116. if(remaining < text_size + data_size + bss_size + 1024) {
  117. fprintf(stderr, "Not enough memory\n");
  118. v68_io_close(fd);
  119. return -1;
  120. }
  121. verbose2("Allocating %dB\n", remaining);
  122. uint32_t m = v68_mem_alloc(remaining, 0);
  123. if(m > 0x8000000) {
  124. verbose2("Failed to allocate %d remaining bytes\n", remaining);
  125. v68_io_close(fd);
  126. return -1;
  127. }
  128. v68_mem_dump();
  129. // Read text and data
  130. v68_io_read(fd, &v68.ram[m + 240], text_size + data_size);
  131. // /* Relocate */
  132. int reloc_adj = (m + 240) - base_addr;
  133. if(reloc_size > 0 && reloc_adj != 0) {
  134. verbose2("Relocating %dB\n", reloc_size);
  135. uint32_t text_loc = m + 240;
  136. for(int i = 0; i < reloc_size; i+=2) {
  137. uint8_t buf[4];
  138. v68_io_read(fd, buf, 2);
  139. uint32_t r = (buf[0] << 8) | buf[1];
  140. if(r == 1) {
  141. i += 2;
  142. v68_io_read(fd, buf, 4);
  143. r = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
  144. i += 2; // 4 total, with `for' increment
  145. }
  146. text_loc += r & 0xfffffffe;
  147. if(text_loc >= (m + 240) + text_size + data_size) {
  148. fprintf(stderr, "Relocation out of bounds %08x + %04x = %08x >= (%08x + 240) + %08x\n", text_loc - (r & 0xfffffffe), r, text_loc, m, text_size);
  149. break;
  150. } else {
  151. if(r & 1) {
  152. // word
  153. int prev = (v68.ram[text_loc] << 8) | v68.ram[text_loc + 1];
  154. prev += reloc_adj;
  155. if(prev > 0xffff || prev < 0) {
  156. fprintf(stderr, "Relocation word offset cannot fit adjustment.\n");
  157. v68_mem_free(m, 0);
  158. v68_io_close(fd);
  159. return -1;
  160. }
  161. m68k_write_memory_16(text_loc, prev);
  162. } else {
  163. // long
  164. int prev = (v68.ram[text_loc] << 24) | (v68.ram[text_loc + 1] << 16) | (v68.ram[text_loc + 2] << 8) | v68.ram[text_loc + 3];
  165. prev += reloc_adj;
  166. if(prev > 0x00ffffff || prev < 0) {
  167. fprintf(stderr, "Relocation word offset cannot fit adjustment.\n");
  168. v68_mem_free(m, 0);
  169. v68_io_close(fd);
  170. return -1;
  171. }
  172. verbose3(" @%04x: %04x -> %08x %08x -> %08x / %08lx\n", i, r, text_loc, prev - reloc_adj, prev, v68.ram_size);
  173. m68k_write_memory_32(text_loc, prev);
  174. }
  175. }
  176. }
  177. }
  178. memset(&v68.ram[m], 0, 240);
  179. /* 0x10: Environment vars pointer */
  180. m68k_write_memory_32(m + 0x00, ENV_TOP);
  181. /* 0x14: Return PC */
  182. if(v68.cur_prog_addr) {
  183. m68k_write_memory_32(m + 0x04, m68k_read_memory_32(v68.cur_prog_addr + 0x04));
  184. } else {
  185. m68k_write_memory_32(m + 0x04, m68k_get_reg(0, M68K_REG_PC));
  186. }
  187. /* 0x20: Command line pointer */
  188. m68k_write_memory_32(m + 0x10, STACK_TOP);
  189. /* 0x30: Start address of BSS */
  190. m68k_write_memory_32(m + 0x20, m + o + 240);
  191. /* 0x34: Start address of heap (same as BSS) */
  192. m68k_write_memory_32(m + 0x24, m + o + 240);
  193. /* 0x38: Initial stack address */
  194. m68k_write_memory_32(m + 0x28, m + remaining); /* Stack top is at end of heap */
  195. /* 0x44: Parent process SR */
  196. m68k_write_memory_32(m + 0x34, m68ki_get_sr());
  197. /* 0x60: Shell activtation flag */
  198. m68k_write_memory_32(m + 0x50, 0);
  199. /* Write drive, path and filename at 0x80, 0x82 and 0xc4 */
  200. // if ( set_fname( fname, ra [ 0 ] ) == FALSE )
  201. // return( FALSE );
  202. // set registers
  203. m68k_set_reg(M68K_REG_A0, m - 16); // memory management ptr
  204. m68k_set_reg(M68K_REG_A1, m + 240 + o + bss_size); // end of loaded program + 1
  205. m68k_set_reg(M68K_REG_A2, STACK_TOP); // cmdline
  206. m68k_set_reg(M68K_REG_A3, ENV_TOP); // env vars
  207. uint32_t pc = entry_point + reloc_adj;
  208. verbose2("Entry point: 0x%08x + 0x%08x = 0x%08x cmd_queue_pos=%d\n", entry_point, reloc_adj, pc, v68.cmd_queue_pos);
  209. m68k_set_reg(M68K_REG_PC, pc);
  210. m68k_set_reg(M68K_REG_A4, pc); // program start addr
  211. // REG_USP = STACK_TOP + STACK_SIZE;
  212. // REG_ISP = STACK_TOP + STACK_SIZE;
  213. // REG_MSP = STACK_TOP + STACK_SIZE;
  214. // m68k_set_reg(M68K_REG_SR, m68k_get_reg(0, M68K_REG_SR) & ~0x2000);
  215. m68k_set_reg(M68K_REG_A7, STACK_TOP + STACK_SIZE);
  216. v68.running = 1;
  217. v68.cur_prog_addr = m;
  218. } else {
  219. // .R file
  220. }
  221. v68_io_close(fd);
  222. return 0;
  223. }
  224. int v68_queue_command(char *cmdline) {
  225. verbose1("v68_queue_command \"%s\"\n", cmdline);
  226. if(v68.cmd_queue_pos > V68_CMD_QUEUE_LEN) return -1;
  227. strncpy(v68.cmd_queue[v68.cmd_queue_pos], cmdline, sizeof(v68.cmd_queue[0]));
  228. v68.cmd_queue_pos++;
  229. verbose2("v68_queue_command cmd_queue_pos=%d\n", v68.cmd_queue_pos);
  230. return 0;
  231. }
  232. void v68_queue_next_command() {
  233. verbose1("v68_queue_next_command cmd_queue_pos=%d\n", v68.cmd_queue_pos);
  234. while(v68.cmd_queue_pos > 0) {
  235. if(v68_run_command(v68.cmd_queue[0])) {
  236. fprintf(stderr, "Could not run command \"%s\"\n", v68.cmd_queue[0]);
  237. }
  238. v68.cmd_queue_pos--;
  239. memcpy(&v68.cmd_queue[0], &v68.cmd_queue[1], sizeof(v68.cmd_queue[0]) * v68.cmd_queue_pos);
  240. return;
  241. }
  242. verbose2("v68_queue_next_command last command cur_prog_addr=0x%08x\n", v68.cur_prog_addr);
  243. /* Last command, restore PC*/
  244. m68k_set_reg(M68K_REG_PC, m68k_read_memory_32(v68.cur_prog_addr + 0x04));
  245. v68.running = 0;
  246. }
  247. int v68_env_append(char *env) {
  248. return 0;
  249. int l = strlen((char *)&v68.ram[ENV_TOP + 4]);
  250. if(l + strlen(env) + 1 > ENV_SIZE) return -1;
  251. char *ptr = (char *)&v68.ram[ENV_TOP] + (l ? l + 1 : 0);
  252. strncat(ptr, env, ENV_SIZE - l - 1);
  253. return 0;
  254. }
  255. int v68_env_set(char *var, char *value) {
  256. return 0;
  257. char buf[1024];
  258. snprintf(buf, sizeof(buf), "%s=%s\n", var, value);
  259. return v68_env_append(buf);
  260. }
  261. uint32_t v68_mem_alloc(int size, uint32_t parent_addr) {
  262. /* Align to 4 bytes */
  263. size = (size + 3) & 0xfffffc;
  264. uint32_t first = m68k_read_memory_32(HUMAN_HEAD - 0x04);
  265. uint32_t prev = first;
  266. if(first) {
  267. for(uint32_t cur = first; cur; cur = m68k_read_memory_32(cur + 0x0c)) {
  268. uint32_t cur_size = m68k_read_memory_32(cur + 0x08) - cur;
  269. uint32_t cur_parent = m68k_read_memory_32(cur + 0x04);
  270. if(cur_parent == 0xffffffff) {
  271. if(cur_size >= size) {
  272. m68k_write_memory_32(cur + 0x04, parent_addr);
  273. if(cur_size - size > 0x20) {
  274. m68k_write_memory_32(cur + 0x08, cur + 16 + size);
  275. m68k_write_memory_32(cur + 0x0c, cur + 16 + size);
  276. m68k_write_memory_32(cur + 16 + size + 0x00, cur);
  277. m68k_write_memory_32(cur + 16 + size + 0x04, 0xffffffff);
  278. m68k_write_memory_32(cur + 16 + size + 0x08, cur + cur_size);
  279. m68k_write_memory_32(cur + 16 + size + 0x0c, cur + cur_size);
  280. }
  281. return cur + 16;
  282. }
  283. }
  284. prev = cur;
  285. }
  286. }
  287. // Check if there is room at the top of the heap
  288. if(v68.heap_top + size + 16 > v68.ram_size) {
  289. verbose1("Could not allocate %08x bytes ram_size=%08lx heap_top=%08x\n", size, v68.ram_size, v68.heap_top);
  290. return -2;
  291. }
  292. if(!prev) prev = HUMAN_HEAD - 0x10;
  293. uint32_t next = v68.heap_top;
  294. m68k_write_memory_32(prev + 0x0c, next);
  295. m68k_write_memory_32(next, prev);
  296. m68k_write_memory_32(next + 0x04, parent_addr);
  297. m68k_write_memory_32(next + 0x08, next + 16 + size);
  298. m68k_write_memory_32(next + 0x0c, 0);
  299. v68.heap_top += 16 + size;
  300. return next + 16;
  301. }
  302. int v68_mem_shrink(uint32_t addr, uint32_t new_size) {
  303. uint32_t first = m68k_read_memory_32(HUMAN_HEAD - 0x04);
  304. addr -= 16;
  305. if(first) {
  306. for(uint32_t cur = first; cur; cur = m68k_read_memory_32(cur + 0x0c)) {
  307. // Yup. Found it.
  308. // I found your sliz.
  309. if(addr == cur) {
  310. uint32_t old_size = m68k_read_memory_32(addr + 0x08) - addr;
  311. if(new_size >= old_size)
  312. return -1;
  313. new_size = (new_size + 3) & 0xfffffc;
  314. uint32_t next_addr = m68k_read_memory_32(addr + 0x0c);
  315. m68k_write_memory_32(addr + 0x08, addr + 0x10 + new_size);
  316. if(next_addr) {
  317. if(old_size - new_size > 0x20) {
  318. uint32_t next = addr + new_size;
  319. m68k_write_memory_32(addr + 0x0c, next);
  320. m68k_write_memory_32(next, addr);
  321. m68k_write_memory_32(next + 0x04, 0xffffffff);
  322. m68k_write_memory_32(next + 0x08, next_addr);
  323. m68k_write_memory_32(next + 0x0c, next_addr);
  324. m68k_write_memory_32(next_addr, next);
  325. }
  326. } else {
  327. v68.heap_top = addr + 0x10 + new_size;
  328. }
  329. return 0;
  330. }
  331. }
  332. }
  333. return -1;
  334. }
  335. int v68_mem_free(uint32_t addr, uint32_t parent_addr) {
  336. uint32_t first = m68k_read_memory_32(HUMAN_HEAD - 0x04);
  337. addr -= 16;
  338. if(first) {
  339. for(uint32_t cur = first; cur; cur = m68k_read_memory_32(cur + 0x0c)) {
  340. if(addr == cur) {
  341. // Last in line
  342. if(m68k_read_memory_32(cur + 0x0c) == 0) {
  343. uint32_t prev = m68k_read_memory_32(cur);
  344. if(prev != HUMAN_HEAD) {
  345. // Previous block is also freed
  346. if(m68k_read_memory_32(prev + 0x04) == 0xffffffff) {
  347. cur = prev;
  348. }
  349. }
  350. m68k_write_memory_32(m68k_read_memory_32(cur) + 0x0c, 0);
  351. v68.heap_top = cur;
  352. } else {
  353. uint32_t end = m68k_read_memory_32(cur + 0x08);
  354. uint32_t prev = m68k_read_memory_32(cur);
  355. uint32_t next = m68k_read_memory_32(cur + 0x0c);
  356. if(prev != HUMAN_HEAD) {
  357. // Previous block is also freed
  358. if(m68k_read_memory_32(prev + 0x04) == 0xffffffff) {
  359. cur = prev;
  360. }
  361. }
  362. if(next) {
  363. if(m68k_read_memory_32(next + 0x04) == 0xffffffff) {
  364. end = m68k_read_memory_32(next + 0x08);
  365. m68k_write_memory_32(end, cur);
  366. }
  367. }
  368. m68k_write_memory_32(cur + 0x04, 0xffffffff);
  369. m68k_write_memory_32(cur + 0x08, end);
  370. m68k_write_memory_32(cur + 0x0c, end);
  371. }
  372. return 0;
  373. }
  374. }
  375. }
  376. return -1;
  377. }
  378. uint32_t v68_mem_remaining() {
  379. uint32_t min = v68.heap_start;
  380. uint32_t first = m68k_read_memory_32(HUMAN_HEAD - 0x04);
  381. for(uint32_t cur = first; cur; cur = m68k_read_memory_32(cur + 0x0c)) {
  382. uint32_t end = m68k_read_memory_32(cur + 0x08);
  383. if(end > min) min = end;
  384. if(cur > min) min = cur;
  385. }
  386. return v68.ram_size - min - 0x200;
  387. }
  388. void v68_mem_dump() {
  389. for(uint32_t cur = HUMAN_HEAD - 0x10; cur; cur = m68k_read_memory_32(cur + 0x0c)) {
  390. verbose1("block @%06x addr=%06x prev=%06x parent=%06x end=%06x len=%d next=%06x\n",
  391. cur, cur + 16,
  392. m68k_read_memory_32(cur),
  393. m68k_read_memory_32(cur + 0x04),
  394. m68k_read_memory_32(cur + 0x08),
  395. m68k_read_memory_32(cur + 0x08) - cur - 16,
  396. m68k_read_memory_32(cur + 0x0c)
  397. );
  398. }
  399. }