roballoc.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. /* Code to allocate, deallocate, reallocate, and otherwise keep track of
  22. robot/scroll memory. (a 64k chunk in either EMS or main memory if there
  23. isn't enough room in EMS) */
  24. #include "beep.h"
  25. #include <dos.h>
  26. #include "meminter.h"
  27. #include <_null.h>
  28. #include "ems.h"
  29. #include "roballoc.h"
  30. #include "const.h"
  31. #include "struct.h"
  32. #include "data.h"
  33. #include "string.h"
  34. //Where robot memory is (W_NOWHERE, W_EMS, or W_MEMORY)
  35. char robot_mem_type=W_NOWHERE;
  36. unsigned char far *robot_mem=NULL;//Set into EMS or reg. memory
  37. unsigned char far *rm_mirror=NULL;//Mirror of above variable
  38. int robot_ems=0;
  39. int rob_global_ems=0;
  40. unsigned int robot_free_mem=0;
  41. char curr_rmem_status=-1;
  42. //Technique of storage- All robots are set to length of 2, all scrolls to
  43. //length of 3. Empty programs. Stored in memory in order of- scrolls 1-??,
  44. //robots 1-??, not including global robot. Minimum of 16 bytes allocated
  45. //to each, then increased in chunks of 16. Increasing one moves all others
  46. //forward. Decreasing moves all backwards. Another page of memory has scroll
  47. //0, robot 0, and global robot.
  48. //Returns non-0 for out of memory.
  49. int init_robot_mem(void) {
  50. unsigned int t1,t2;
  51. //First reset all scrolls, robots, counters, and sensors.
  52. for(t1=0;t1<=NUM_ROBOTS;t1++) {//Include global
  53. for(t2=0;t2<sizeof(Robot);t2++) {
  54. ((char far *)(&robots[t1]))[t2]=0;
  55. }
  56. robots[t1].program_length=2;
  57. robots[t1].robot_cycle=1;
  58. robots[t1].cur_prog_line=1;
  59. robots[t1].robot_char=2;
  60. robots[t1].bullet_type=1;
  61. }
  62. for(t1=0;t1<NUM_SCROLLS;t1++) {
  63. scrolls[t1].num_lines=1;
  64. scrolls[t1].mesg_location=scrolls[t1].used=0;
  65. scrolls[t1].mesg_size=3;
  66. }
  67. for(t1=0;t1<NUM_COUNTERS;t1++) {
  68. counters[t1].counter_name[0]=counters[t1].counter_value=0;
  69. }
  70. for(t1=0;t1<NUM_SENSORS;t1++) {
  71. sensors[t1].sensor_name[0]=sensors[t1].robot_to_mesg[0]=
  72. sensors[t1].sensor_char=sensors[t1].used=0;
  73. }
  74. //Allocate robot memory (2 pgs of 64k)
  75. //Try EMS first
  76. t1=alloc_EMS(4);//4 pages of 16k each
  77. if(t1) {
  78. robot_ems=t1;
  79. t1=alloc_EMS(4);
  80. if(t1) {
  81. //Got it! :)
  82. robot_mem_type=W_EMS;
  83. rob_global_ems=t1;
  84. robot_mem=(unsigned char far *)page_frame_EMS;
  85. }
  86. else {
  87. free_EMS(t1);
  88. goto try_conv;
  89. }
  90. }
  91. else {
  92. try_conv:
  93. //Try conventional memory.
  94. robot_mem=(unsigned char far *)farmalloc(131072L);
  95. if(robot_mem==NULL) return 1;//Out of memory
  96. //Conventional works.
  97. robot_mem_type=W_MEMORY;
  98. robot_ems=rob_global_ems=0;
  99. }
  100. rm_mirror=robot_mem;
  101. //Now we have to work with storage
  102. prepare_robot_mem();
  103. //Setup initial storage- scrolls[] and robots[].
  104. t1=0;//Current working location
  105. //Do this for each scroll
  106. for(t2=1;t2<NUM_SCROLLS;t2++) {
  107. scrolls[t2].mesg_location=t1;
  108. robot_mem[t1]=0x01;//Start code
  109. robot_mem[t1+1]='\n';//End of line code
  110. robot_mem[t1+2]=0x00;//End code
  111. t1+=16;
  112. }
  113. //Now do this for each robot
  114. for(t2=1;t2<NUM_ROBOTS;t2++) {
  115. robots[t2].program_location=t1;
  116. robot_mem[t1]=0xFF;//Start code
  117. robot_mem[t1+1]=0x00;//End code
  118. t1+=16;
  119. }
  120. //Now set free memory as 65536-t1
  121. robot_free_mem=(unsigned int)(65536L-(long)t1);
  122. //Let's now do global robotics
  123. prepare_robot_mem(1);
  124. //Setup robot 0, scroll 0, and global robot
  125. //Do this for a scroll
  126. scrolls[0].mesg_location=t1=0;//Current working location
  127. robot_mem[t1]=0x01;//Start code
  128. robot_mem[t1+1]='\n';//End of line code
  129. robot_mem[t1+2]=0x00;//End code
  130. t1+=16;
  131. //Now do this for 2 robots
  132. robots[0].program_location=t1;
  133. robot_mem[t1]=0xFF;//Start code
  134. robot_mem[t1+1]=0x00;//End code
  135. t1+=16;
  136. robots[NUM_ROBOTS].program_location=t1;
  137. robot_mem[t1]=0xFF;//Start code
  138. robot_mem[t1+1]=0x00;//End code
  139. //Done!
  140. return 0;
  141. }
  142. //Deallocate memory
  143. void exit_robot_mem(void) {
  144. if(robot_mem==NULL) return;
  145. if(robot_mem_type==W_EMS) {
  146. free_EMS(robot_ems);
  147. free_EMS(rob_global_ems);
  148. }
  149. else farfree(rm_mirror);
  150. robot_mem=rm_mirror=NULL;
  151. robot_ems=rob_global_ems=robot_free_mem=0;
  152. robot_mem_type=W_NOWHERE;
  153. }
  154. //If robot memory is in ems, loads the correct ems pages
  155. void prepare_robot_mem(char global) {
  156. if(robot_ems) {
  157. if(global) {
  158. map_page_EMS(rob_global_ems,0,0);
  159. map_page_EMS(rob_global_ems,1,1);
  160. map_page_EMS(rob_global_ems,2,2);
  161. map_page_EMS(rob_global_ems,3,3);
  162. }
  163. else {
  164. map_page_EMS(robot_ems,0,0);
  165. map_page_EMS(robot_ems,1,1);
  166. map_page_EMS(robot_ems,2,2);
  167. map_page_EMS(robot_ems,3,3);
  168. }
  169. }
  170. else {
  171. if(global) robot_mem=(unsigned char far *)
  172. MK_FP(FP_SEG(rm_mirror)+0x1000,FP_OFF(rm_mirror));
  173. else robot_mem=rm_mirror;
  174. }
  175. curr_rmem_status=global;
  176. }
  177. //Round up an unsigned int to a multiple of 16. Min. of 16.
  178. unsigned int _round16(unsigned int n) {
  179. if(!n) return 16;
  180. if(n&15) n+=16-(n&15);
  181. return n;
  182. }
  183. //Reallocate a robot or scroll to a different size of memory. Returns non-0
  184. //if there isn't enough room. Type is 0 for a scroll and 1 for a robot.
  185. char reallocate_robot_mem(char type,unsigned char id,unsigned int size) {
  186. unsigned int old_size,t1,t2,loc,dif,unr_size=size;//Save unrounded size
  187. int temp=curr_rmem_status;
  188. //Check size change
  189. if(!type) old_size=scrolls[id].mesg_size;
  190. else old_size=robots[id].program_length;
  191. size=_round16(size);
  192. old_size=_round16(old_size);
  193. if(old_size==size) {
  194. if(!type) scrolls[id].mesg_size=unr_size;
  195. else robots[id].program_length=unr_size;
  196. return 0;//Already proper size. (to the nearest 16th)
  197. }
  198. //If incrementing...
  199. if(size>old_size) {
  200. //...is there room?
  201. if((id==0)||(id==NUM_ROBOTS)) ;//Special- only limit is
  202. //the 31k one.
  203. else if((size-old_size)>robot_free_mem) return 1;//No room.
  204. //Verify <31k
  205. if(size>31744U) return 1;//Too big.
  206. }
  207. //Decreasing always works.
  208. //Change to new size and get location...
  209. if(!type) {
  210. scrolls[id].mesg_size=unr_size;
  211. loc=scrolls[id].mesg_location;
  212. }
  213. else {
  214. robots[id].program_length=unr_size;
  215. loc=robots[id].program_location;
  216. }
  217. //...move memory to compensate...
  218. prepare_robot_mem((id==0)||(id==NUM_ROBOTS));
  219. t1=1;//Code bit (1=getting bigger/moving up)
  220. if(size<old_size) t1=0;//Moving down
  221. dif=size-old_size;
  222. mem_mov((char far *)&robot_mem[loc+size],(char far *)&robot_mem[loc+old_size],
  223. (unsigned int)(65536L-loc-(t1?size:old_size)),t1);
  224. //...adjust free memory.
  225. if((id>0)&&(id<NUM_ROBOTS)) {
  226. robot_free_mem-=dif;
  227. //Now walk offsets, adjusting all those after the changed one.
  228. //Do scrolls first- if a scroll was resized other than the last one.
  229. if((type==0)&&(id<(NUM_SCROLLS-1))) {
  230. //Start at id+1
  231. for(t2=id+1;t2<NUM_SCROLLS;t2++) {
  232. //Increase or decrease
  233. scrolls[t2].mesg_location+=dif;
  234. }
  235. }
  236. //Now, unless the last robot was resized, do robots
  237. if(id<(NUM_ROBOTS-1)) {
  238. //Start at 1 unless robot was edited (then start at id+1)
  239. if(type<1) t2=1;
  240. else t2=id+1;
  241. for(;t2<NUM_ROBOTS;t2++) {
  242. //Increase or decrease
  243. robots[t2].program_location+=dif;
  244. }
  245. }
  246. }
  247. else {
  248. if(!type) {//Scroll 0 was changed- Change robot 0
  249. robots[0].program_location+=dif;
  250. }
  251. if(!id) {//Scroll 0 or robot 0 was changed- Change global robot
  252. robots[NUM_ROBOTS].program_location+=dif;
  253. }
  254. }
  255. //Done!
  256. prepare_robot_mem(temp);
  257. return 0;
  258. }
  259. //Clears a robot and sets it to use the minimum amount of memory.
  260. void clear_robot(unsigned char id) {
  261. unsigned int t1,t2;
  262. int temp=curr_rmem_status;
  263. //Reallocate
  264. reallocate_robot_mem(T_ROBOT,id,2);
  265. prepare_robot_mem((id==0)||(id==NUM_ROBOTS));
  266. //Clear struct
  267. t1=robots[id].program_location;
  268. for(t2=0;t2<sizeof(Robot);t2++) {
  269. ((char far *)(&robots[id]))[t2]=0;
  270. }
  271. robots[id].program_length=2;
  272. robots[id].robot_cycle=1;
  273. robots[id].program_location=t1;
  274. robots[id].cur_prog_line=1;
  275. robots[id].robot_char=2;
  276. robots[id].bullet_type=1;
  277. //Clear program (robot mem prepared from reallocate)
  278. robot_mem[t1]=0xFF;
  279. robot_mem[t1+1]=0x00;
  280. prepare_robot_mem(temp);
  281. }
  282. //Clears a scroll's struct and program.
  283. void clear_scroll(unsigned char id) {
  284. unsigned int t1;
  285. int temp=curr_rmem_status;
  286. //Reallocate
  287. reallocate_robot_mem(T_SCROLL,id,3);
  288. prepare_robot_mem(!id);
  289. //Clear struct
  290. t1=scrolls[id].mesg_location;
  291. scrolls[id].num_lines=1;
  292. scrolls[id].used=0;
  293. //Clear program (robot mem prepared from reallocate)
  294. robot_mem[t1]=0x01;
  295. robot_mem[t1+1]='\n';
  296. robot_mem[t1+2]=0x00;
  297. prepare_robot_mem(temp);
  298. }
  299. //Clears a sensor's struct
  300. void clear_sensor(unsigned char id) {
  301. sensors[id].sensor_name[0]=sensors[id].robot_to_mesg[0]=
  302. sensors[id].sensor_char=sensors[id].used=0;
  303. }
  304. //Finds the first available robot and marks it if asked. Returns 0 if none
  305. //available, otherwise returns the id.
  306. unsigned char find_robot(char mark) {
  307. int t1;
  308. //Don't stray into global robot territory!
  309. for(t1=1;t1<NUM_ROBOTS;t1++)
  310. if(!robots[t1].used) break;
  311. if(t1<NUM_ROBOTS) {
  312. if(mark) robots[t1].used=1;
  313. return t1;
  314. }
  315. return 0;
  316. }
  317. //Finds the first available scroll and marks it if asked. Returns 0 if none
  318. //available, otherwise returns the id.
  319. unsigned char find_scroll(char mark) {
  320. int t1;
  321. for(t1=1;t1<NUM_SCROLLS;t1++)
  322. if(!scrolls[t1].used) break;
  323. if(t1<NUM_SCROLLS) {
  324. if(mark) scrolls[t1].used=1;
  325. return t1;
  326. }
  327. return 0;
  328. }
  329. //Finds the first available sensor and marks it if asked. Returns 0 if none
  330. //available, otherwise returns the id.
  331. unsigned char find_sensor(char mark) {
  332. int t1;
  333. for(t1=1;t1<NUM_SENSORS;t1++)
  334. if(!sensors[t1].used) break;
  335. if(t1<NUM_SENSORS) {
  336. if(mark) sensors[t1].used=1;
  337. return t1;
  338. }
  339. return 0;
  340. }
  341. //Copies one robot to another. Returns non-0 for not enough memory.
  342. //DOESN'T copy robot[].used variable.
  343. char copy_robot(unsigned char dest,unsigned char source) {
  344. unsigned int t1;
  345. unsigned int sl,dl,size,pos;
  346. int temp=curr_rmem_status;
  347. char used=robots[dest].used;
  348. //Allocate
  349. if(reallocate_robot_mem(T_ROBOT,dest,robots[source].program_length))
  350. return 1;
  351. //From 0 -> # or # -> 0 ??
  352. if((dest==0)||(source==0)||(dest==GLOBAL_ROBOT)||(source==GLOBAL_ROBOT)) {
  353. //Non EMS?
  354. if(robot_mem_type==W_MEMORY) {
  355. prepare_robot_mem(1);
  356. //From #0
  357. if((source==0)||(source==GLOBAL_ROBOT)) {
  358. mem_cpy(&rm_mirror[t1=robots[dest].program_location],
  359. &robot_mem[robots[source].program_location],
  360. robots[source].program_length);
  361. }
  362. //To #0
  363. else {
  364. mem_cpy(&robot_mem[t1=robots[dest].program_location],
  365. &rm_mirror[robots[source].program_location],
  366. robots[source].program_length);
  367. }
  368. }
  369. else {
  370. //Within EMS
  371. dl=t1=robots[dest].program_location;
  372. sl=robots[source].program_location;
  373. size=robots[source].program_length;
  374. //Special code
  375. //From #0
  376. //Sixteen-byte copies, since (sl | dl) % 16 = 0 and size % 16 = 0
  377. pos=0;
  378. if((source==0)||(source==GLOBAL_ROBOT)) {
  379. do {
  380. //Copy 16 bytes, from sl+pos to dl+pos
  381. map_page_EMS(robot_ems,0,(dl+pos)>>14);
  382. map_page_EMS(rob_global_ems,1,(sl+pos)>>14);
  383. mem_cpy(&robot_mem[(dl+pos)&16383],
  384. &robot_mem[((sl+pos)&16383)+16384],16);
  385. pos+=16;
  386. } while(pos<size);
  387. }
  388. //To #0
  389. else {
  390. do {
  391. //Copy 16 bytes, from dl+pos to sl+pos
  392. map_page_EMS(rob_global_ems,0,(dl+pos)>>14);
  393. map_page_EMS(robot_ems,1,(sl+pos)>>14);
  394. mem_cpy(&robot_mem[(dl+pos)&16383],
  395. &robot_mem[((sl+pos)&16383)+16384],16);
  396. pos+=16;
  397. } while(pos<size);
  398. }
  399. }
  400. }
  401. else {
  402. //Copy
  403. prepare_robot_mem(0);
  404. mem_cpy(&robot_mem[t1=robots[dest].program_location],
  405. &robot_mem[robots[source].program_location],
  406. robots[dest].program_length);
  407. }
  408. //Copy struct, other than location
  409. mem_cpy((char far *)&robots[dest],(char far *)&robots[source],
  410. sizeof(Robot));
  411. robots[dest].program_location=t1;
  412. robots[dest].used=used;
  413. prepare_robot_mem(temp);
  414. //Done!
  415. return 0;
  416. }
  417. //Copies one scroll to another. Returns non-0 for not enough memory.
  418. //DOESN'T copy scroll[].used variable.
  419. char copy_scroll(unsigned char dest,unsigned char source) {
  420. unsigned int t1;
  421. unsigned int sl,dl,size,pos;
  422. int temp=curr_rmem_status;
  423. char used=scrolls[dest].used;
  424. //Allocate
  425. if(reallocate_robot_mem(T_SCROLL,dest,scrolls[source].mesg_size))
  426. return 1;
  427. //From 0 -> # or # -> 0 ??
  428. if((dest==0)||(source==0)) {
  429. //Non EMS?
  430. if(robot_mem_type==W_MEMORY) {
  431. prepare_robot_mem(1);
  432. //From #0
  433. if(source==0) {
  434. mem_cpy(&rm_mirror[t1=scrolls[dest].mesg_location],
  435. &robot_mem[scrolls[source].mesg_location],
  436. scrolls[source].mesg_size);
  437. }
  438. //To #0
  439. else {
  440. mem_cpy(&robot_mem[t1=scrolls[dest].mesg_location],
  441. &rm_mirror[scrolls[source].mesg_location],
  442. scrolls[source].mesg_size);
  443. }
  444. }
  445. else {
  446. //Within EMS
  447. dl=t1=scrolls[dest].mesg_location;
  448. sl=scrolls[source].mesg_location;
  449. size=scrolls[source].mesg_size;
  450. //Special code
  451. //From #0
  452. //Sixteen-byte copies, since (sl | dl) % 16 = 0 and size % 16 = 0
  453. pos=0;
  454. if(source==0) {
  455. do {
  456. //Copy 16 bytes, from sl+pos to dl+pos
  457. map_page_EMS(robot_ems,0,(dl+pos)>>14);
  458. map_page_EMS(rob_global_ems,1,(sl+pos)>>14);
  459. mem_cpy(&robot_mem[(dl+pos)&16383],
  460. &robot_mem[((sl+pos)&16383)+16384],16);
  461. pos+=16;
  462. } while(pos<size);
  463. }
  464. //To #0
  465. else {
  466. do {
  467. //Copy 16 bytes, from dl+pos to sl+pos
  468. map_page_EMS(rob_global_ems,0,(dl+pos)>>14);
  469. map_page_EMS(robot_ems,1,(sl+pos)>>14);
  470. mem_cpy(&robot_mem[(dl+pos)&16383],
  471. &robot_mem[((sl+pos)&16383)+16384],16);
  472. pos+=16;
  473. } while(pos<size);
  474. }
  475. }
  476. }
  477. else {
  478. //Copy
  479. prepare_robot_mem();
  480. mem_cpy(&robot_mem[t1=scrolls[dest].mesg_location],
  481. &robot_mem[scrolls[source].mesg_location],
  482. scrolls[source].mesg_size);
  483. }
  484. //Copy struct, other than location
  485. mem_cpy((char far *)&scrolls[dest],(char far *)&scrolls[source],
  486. sizeof(Scroll));
  487. scrolls[dest].mesg_location=t1;
  488. scrolls[dest].used=used;
  489. prepare_robot_mem(temp);
  490. //Done!
  491. return 0;
  492. }
  493. //Copies one sensor to another, NOT including sensor[].used variable.
  494. void copy_sensor(unsigned char dest,unsigned char source) {
  495. char used=sensors[dest].used;
  496. //Copy struct
  497. mem_cpy((char far *)&sensors[dest],(char far *)&sensors[source],
  498. sizeof(Sensor));
  499. sensors[dest].used=used;
  500. }