lynxit.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055
  1. /*
  2. lynxit.c - lynxit support for uCON64
  3. Copyright (c) 1997 - ???? K. Wilkins
  4. Copyright (c) 2002 NoisyB <noisyb@gmx.net>
  5. Copyright (c) 2004 dbjh
  6. This program 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 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include <fcntl.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #ifdef HAVE_UNISTD_H
  26. #include <unistd.h>
  27. #endif
  28. #include "misc/misc.h"
  29. #include "misc/itypes.h"
  30. #ifdef USE_ZLIB
  31. #include "misc/archive.h"
  32. #endif
  33. #include "misc/getopt2.h" // st_getopt2_t
  34. #include "ucon64.h"
  35. #include "ucon64_misc.h"
  36. #include "console/lynx.h"
  37. #include "lynxit.h"
  38. #include "misc/parallel.h"
  39. const st_getopt2_t lynxit_usage[] =
  40. {
  41. {
  42. NULL, 0, 0, 0,
  43. NULL, "Lynxit (Lynx cartridge backup board)"/*"1997 K.Wilkins (selfmade)"*/,
  44. NULL
  45. },
  46. #ifdef USE_PARALLEL
  47. {
  48. "xlit", 0, 0, UCON64_XLIT,
  49. NULL, "receive ROM from Lynxit interface; " OPTION_LONG_S "port=PORT",
  50. // " receives automatically when ROM does not exist\n"
  51. &ucon64_wf[WF_OBJ_LYNX_STOP_NO_ROM]
  52. },
  53. #endif
  54. {NULL, 0, 0, 0, NULL, NULL, NULL}
  55. };
  56. #ifdef USE_PARALLEL
  57. #define MAGIC_STRING "LYNX"
  58. #define FILE_FORMAT_VERSION 0x0001
  59. //
  60. // Some basic cartidge definitions
  61. //
  62. #define MAX_PAGE_SIZE 0x1000 // Must be 2x largest page
  63. #define CART_PAGE_64K 0x100 // 256 Bytes per page
  64. #define CART_PAGE_128K 0x200 // 512 Bytes per page
  65. #define CART_PAGE_256K 0x400 // 1024 Bytes per page
  66. #define CART_PAGE_512K 0x800 // 2048 Bytes per page
  67. #define BANK0 0
  68. #define BANK1 1
  69. //
  70. // DEFINE CENTRONICS PORT MASKS & PORTS
  71. //
  72. #define PORT_BASE 0x80 // Keep the power on 8-)
  73. #define CTRL_STB 0x01
  74. #define DATA_OUT 0x02
  75. #define DATA_CLK 0x04
  76. #define DATA_STB 0x08
  77. #define DATA_OE 0x10
  78. #define DATA_LOAD 0x20
  79. #define PAGE_STB 0x40
  80. unsigned int printer_port = 1, print_data = 0, print_ctrl = 0, print_stat = 0;
  81. char cartname[32], manufname[16];
  82. //
  83. // CONTROL REGISTER DEFINITIONS
  84. //
  85. #define CTRL_BANK0B 0x01
  86. #define CTRL_BANK1B 0x02
  87. #define CTRL_WR_EN 0x04
  88. #define CTRL_CTR_CLKB 0x40
  89. #define CTRL_CTR_RST 0x80
  90. #define CTRL_INACTIVE (CTRL_BANK0B|CTRL_BANK1B|CTRL_CTR_CLKB)
  91. // Make cart strobes inactive & counter clock & reset inactive
  92. unsigned char control_register = CTRL_INACTIVE;
  93. static void lynxit_write_control (unsigned char data);
  94. //
  95. // Global control vars
  96. //
  97. static int debug = FALSE, quiet = FALSE, verify = TRUE;
  98. #define MESSAGE(body) printf body
  99. #define INPUT(port) inportb((unsigned short) (port))
  100. #define OUTPUT(port, data) outportb((unsigned short) (port), (unsigned char) (data))
  101. #if 0
  102. void
  103. usage (void)
  104. {
  105. MESSAGE (("\nUsage: lynxit [-pX] [-d] [-q] <command> <filename> [cartname] [manuf]\n"));
  106. MESSAGE (("\n"));
  107. MESSAGE ((" Commands = read/write/verify/test\n"));
  108. MESSAGE ((" -pX = Use printer port LPTX: (Default LPT1:)\n"));
  109. MESSAGE ((" -d = Debug mode enable\n"));
  110. MESSAGE ((" -q = Quiet mode\n"));
  111. MESSAGE ((" -n = Don't verify read/write operations\n"));
  112. MESSAGE ((" -h = Print this text\n"));
  113. }
  114. #endif
  115. int
  116. ptr_port_init (unsigned int port)
  117. {
  118. #if 0
  119. if (port < 1 && port > 4)
  120. return FALSE;
  121. print_data = *(unsigned int far *) MK_FP (0x0040, 6 + (2 * port));
  122. if (!print_data)
  123. return FALSE;
  124. #else
  125. (void) port; // warning remover
  126. #endif
  127. print_stat = print_data + 1;
  128. print_ctrl = print_data + 2;
  129. #if 0
  130. DEBUG (("\nPrinter port initialised OK: LPT%d\n", port));
  131. DEBUG (("Data I/O 0x%04x\n", print_data));
  132. DEBUG (("Status I/O 0x%04x\n", print_stat));
  133. DEBUG (("Control I/O 0x%04x\n\n", print_ctrl));
  134. #endif
  135. lynxit_write_control (control_register);
  136. return TRUE;
  137. }
  138. void
  139. lynxit_shift_out_byte (unsigned char data)
  140. {
  141. unsigned int loop;
  142. unsigned char outbyte, dbgdata;
  143. dbgdata = data;
  144. OUTPUT (print_data, PORT_BASE); // Set inactive
  145. for (loop = 0; loop < 8; loop++)
  146. {
  147. outbyte = PORT_BASE;
  148. outbyte |= (data & 0x80) ? DATA_OUT : 0;
  149. OUTPUT (print_data, outbyte); // Output data; clock low
  150. data = data << 1;
  151. outbyte |= DATA_CLK;
  152. OUTPUT (print_data, outbyte); // clock high
  153. }
  154. OUTPUT (print_data, PORT_BASE); // Leave outputs low
  155. #if 0
  156. DEBUG (("lynxit_shift_out_byte() - Wrote %02x\n", dbgdata));
  157. #endif
  158. }
  159. unsigned char
  160. lynxit_shift_in_byte (void)
  161. {
  162. unsigned int loop;
  163. unsigned char data = 0;
  164. OUTPUT (print_data, PORT_BASE); // Set inactive
  165. for (loop = 0; loop < 8; loop++)
  166. {
  167. data |= (((INPUT (print_stat)) & 0x80) ? 0 : 1) << (7 - loop);
  168. #if 0
  169. DEBUG (("Status port returned %02x\n", INPUT (print_stat)));
  170. #endif
  171. OUTPUT (print_data, PORT_BASE | DATA_CLK); // clock high
  172. OUTPUT (print_data, PORT_BASE); // clock low
  173. }
  174. #if 0
  175. DEBUG (("lynxit_shift_in_byte() - Read %02x\n", data));
  176. #endif
  177. return (data);
  178. }
  179. void
  180. lynxit_write_control (unsigned char data)
  181. {
  182. #if 0
  183. DEBUG (("lynxit_write_control() - Set to %02x\n", data));
  184. #endif
  185. lynxit_shift_out_byte (data);
  186. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  187. OUTPUT (print_data, PORT_BASE | CTRL_STB); // clock low; strobe high
  188. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  189. control_register = data;
  190. }
  191. void
  192. lynxit_write_page (unsigned char page)
  193. {
  194. #if 0
  195. DEBUG (("lynxit_write_page() - Set to %02x\n", page));
  196. #endif
  197. lynxit_shift_out_byte (page);
  198. lynxit_shift_out_byte (0);
  199. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  200. OUTPUT (print_data, PORT_BASE | PAGE_STB); // clock low; strobe high
  201. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  202. }
  203. void
  204. lynxit_counter_reset (void)
  205. {
  206. lynxit_write_control ((unsigned char) (control_register | CTRL_CTR_RST));
  207. lynxit_write_control ((unsigned char) (control_register & (CTRL_CTR_RST ^ 0xff)));
  208. }
  209. void
  210. lynxit_counter_increment (void)
  211. {
  212. lynxit_write_control ((unsigned char) (control_register & (CTRL_CTR_CLKB ^ 0xff)));
  213. lynxit_write_control ((unsigned char) (control_register | CTRL_CTR_CLKB));
  214. }
  215. unsigned char
  216. cart_read_byte (unsigned int cart)
  217. {
  218. unsigned char data;
  219. // Clear relevant cart strobe to activate read
  220. if (cart == BANK0)
  221. {
  222. lynxit_write_control ((unsigned char) (control_register & (0xff ^ CTRL_BANK0B)));
  223. }
  224. else
  225. {
  226. lynxit_write_control ((unsigned char) (control_register & (0xff ^ CTRL_BANK1B)));
  227. }
  228. // Clock byte into shift register with load
  229. //
  230. // Note 500ns read cycle for ROM == 5x125ns out cycles
  231. OUTPUT (print_data, PORT_BASE); // clock low
  232. OUTPUT (print_data, PORT_BASE); // clock low
  233. OUTPUT (print_data, PORT_BASE); // clock low
  234. OUTPUT (print_data, PORT_BASE); // clock low
  235. OUTPUT (print_data, PORT_BASE | DATA_LOAD); // Parallel load
  236. OUTPUT (print_data, PORT_BASE | DATA_LOAD); // Parallel load
  237. OUTPUT (print_data, PORT_BASE); // Clear load
  238. // This must be done before strobe is cleared as data will be
  239. // destoryed bye setting control reg
  240. data = lynxit_shift_in_byte ();
  241. // Clear the cartridge strobe
  242. if (cart == BANK0)
  243. {
  244. lynxit_write_control ((unsigned char) (control_register | CTRL_BANK0B));
  245. }
  246. else
  247. {
  248. lynxit_write_control ((unsigned char) (control_register | CTRL_BANK1B));
  249. }
  250. #if 0
  251. DEBUG (("cart_read_byte() - Returning %02x\n", data));
  252. #endif
  253. // MESSAGE(("%c",data));
  254. return (data);
  255. }
  256. void
  257. cart_write_byte (unsigned int cart, unsigned char data)
  258. {
  259. #if 0
  260. DEBUG (("cart_write_byte() - Set to %02x\n", data));
  261. #endif
  262. // Shift data to correct position
  263. lynxit_shift_out_byte (data);
  264. lynxit_shift_out_byte (0);
  265. lynxit_shift_out_byte (0);
  266. // Strobe byte to be written into the data register
  267. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  268. OUTPUT (print_data, PORT_BASE | DATA_STB); // clock low; strobe high
  269. OUTPUT (print_data, PORT_BASE); // clock low; strobe low
  270. // Assert write enable (active low)
  271. lynxit_write_control ((unsigned char) (control_register & (0xff ^ CTRL_WR_EN)));
  272. // Assert output enable
  273. OUTPUT (print_data, PORT_BASE | DATA_OE);
  274. // Assert cartridge strobe LOW to write then HIGH
  275. if (cart == BANK0)
  276. {
  277. lynxit_write_control ((unsigned char) (control_register & (0xff ^ CTRL_BANK0B)));
  278. lynxit_write_control ((unsigned char) (control_register | CTRL_BANK0B));
  279. }
  280. else
  281. {
  282. lynxit_write_control ((unsigned char) (control_register & (0xff ^ CTRL_BANK1B)));
  283. lynxit_write_control ((unsigned char) (control_register | CTRL_BANK1B));
  284. }
  285. // Clear output enable
  286. OUTPUT (print_data, PORT_BASE);
  287. // Clear write enable
  288. lynxit_write_control ((unsigned char) (control_register | CTRL_WR_EN));
  289. }
  290. void
  291. cart_read_page (unsigned int cart, unsigned int page_number,
  292. unsigned int page_size, unsigned char *page_ptr)
  293. {
  294. unsigned int loop;
  295. lynxit_write_page ((unsigned char) page_number);
  296. lynxit_counter_reset ();
  297. for (loop = 0; loop < page_size; loop++)
  298. {
  299. *page_ptr = cart_read_byte (cart);
  300. page_ptr++;
  301. lynxit_counter_increment ();
  302. }
  303. }
  304. #if 0
  305. void
  306. cart_write_page (unsigned int cart, unsigned int page_number,
  307. unsigned int page_size, unsigned char *page_ptr)
  308. {
  309. }
  310. #endif
  311. int
  312. cart_analyse (int cart)
  313. {
  314. unsigned char image[MAX_PAGE_SIZE];
  315. unsigned int page = 0;
  316. unsigned char test = 0;
  317. unsigned int loop = 0;
  318. MESSAGE (("ANALYSE : BANK%d ", cart));
  319. for (;;)
  320. {
  321. // Read a page - start at zero, try a max of 8 pages
  322. if (page > 8)
  323. {
  324. MESSAGE (("N/A\n"));
  325. return FALSE;
  326. }
  327. cart_read_page (cart, page++, CART_PAGE_512K * 2, image);
  328. // Explicit check for no bank
  329. test = 0xff;
  330. for (loop = 0; loop < CART_PAGE_512K; loop++)
  331. test &= image[loop];
  332. if (test == 0xff)
  333. {
  334. MESSAGE (("N/A\n"));
  335. return FALSE;
  336. }
  337. // Check bytes are not all same
  338. for (loop = 1; loop < CART_PAGE_512K; loop++)
  339. {
  340. if (image[loop] != image[0])
  341. break;
  342. }
  343. // If we are at end of loop then buffer is all same
  344. if (loop != CART_PAGE_512K)
  345. break;
  346. }
  347. // {
  348. // FILE *fp;
  349. // fp=fopen("TEST.IMG","wb");
  350. // fwrite(image,sizeof(unsigned char),MAX_PAGE_SIZE,fp);
  351. // fclose(fp);
  352. // {
  353. // Check for 64K Cart
  354. for (loop = 0; loop < CART_PAGE_64K; loop++)
  355. {
  356. if (image[loop] != image[loop + CART_PAGE_64K])
  357. break;
  358. }
  359. if (loop == CART_PAGE_64K)
  360. {
  361. MESSAGE (("64K\n"));
  362. return CART_PAGE_64K;
  363. }
  364. // Check for 128K Cart
  365. for (loop = 0; loop < CART_PAGE_128K; loop++)
  366. {
  367. if (image[loop] != image[loop + CART_PAGE_128K])
  368. break;
  369. }
  370. if (loop == CART_PAGE_128K)
  371. {
  372. MESSAGE (("128K\n"));
  373. return CART_PAGE_128K;
  374. }
  375. // Check for 256K Cart
  376. for (loop = 0; loop < CART_PAGE_256K; loop++)
  377. {
  378. if (image[loop] != image[loop + CART_PAGE_256K])
  379. break;
  380. }
  381. if (loop == CART_PAGE_256K)
  382. {
  383. MESSAGE (("256K\n"));
  384. return CART_PAGE_256K;
  385. }
  386. // Check for 512K Cart
  387. for (loop = 0; loop < CART_PAGE_512K; loop++)
  388. {
  389. if (image[loop] != image[loop + CART_PAGE_512K])
  390. break;
  391. }
  392. if (loop == CART_PAGE_512K)
  393. {
  394. MESSAGE (("512K\n"));
  395. return CART_PAGE_512K;
  396. }
  397. // Must be no cart situation - floating data !!!)
  398. MESSAGE (("Bad cartridge\n"));
  399. return FALSE;
  400. }
  401. #define MAX_ERRORS 16
  402. int
  403. cart_verify (char *filename)
  404. {
  405. unsigned char image1[MAX_PAGE_SIZE], image2[MAX_PAGE_SIZE];
  406. int offset = 0;
  407. unsigned int loop = 0;
  408. FILE *fp;
  409. st_lnx_header_t header;
  410. unsigned int result0 = MAX_ERRORS, result1 = MAX_ERRORS;
  411. #if 0
  412. DEBUG (("cart_verify() called with <%s>\n\n", filename));
  413. #endif
  414. if ((fp = fopen (filename, "rb")) == NULL)
  415. {
  416. // MESSAGE (("ERROR : Could not open %s\n", filename));
  417. MESSAGE ((ucon64_msg[OPEN_READ_ERROR], filename));
  418. return FALSE;
  419. }
  420. if (fread (&header, sizeof (st_lnx_header_t), 1, fp) != 1)
  421. {
  422. MESSAGE (("ERROR : Disk read operation failed on %s\n", filename));
  423. fclose (fp);
  424. return FALSE;
  425. }
  426. if (strcmp (header.magic, "LYNX") != 0)
  427. {
  428. MESSAGE (("ERROR : %s is not a lynx image\n", filename));
  429. fclose (fp);
  430. return FALSE;
  431. }
  432. if (header.version != FILE_FORMAT_VERSION)
  433. {
  434. MESSAGE (("ERROR : %s has wrong version information\n", filename));
  435. fclose (fp);
  436. return FALSE;
  437. }
  438. if (header.page_size_bank0 != cart_analyse (BANK0))
  439. {
  440. MESSAGE (("ERROR : Cartridge BANK0 size mismatch\n"));
  441. fclose (fp);
  442. return FALSE;
  443. }
  444. if (header.page_size_bank1 != cart_analyse (BANK1))
  445. {
  446. MESSAGE (("ERROR : Cartridge BANK1 size mismatch\n"));
  447. fclose (fp);
  448. return FALSE;
  449. }
  450. if (header.page_size_bank0)
  451. {
  452. for (loop = 0; loop < 256; loop++)
  453. {
  454. MESSAGE (("Verifying BANK0: Page <%03d> of <256>", loop + 1));
  455. cart_read_page (BANK0, loop, header.page_size_bank0, image1);
  456. MESSAGE (("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"));
  457. if (fread (image2, sizeof (unsigned char), header.page_size_bank0, fp)
  458. != (size_t) header.page_size_bank0)
  459. {
  460. MESSAGE (("\nERROR : Disk read operation failed on %s\n",
  461. filename));
  462. fclose (fp);
  463. return FALSE;
  464. }
  465. for (offset = 0; offset < header.page_size_bank0; offset++)
  466. {
  467. if (image1[offset] != image2[offset])
  468. {
  469. MESSAGE (("VERIFY : Mismatch in BANK<0>:PAGE<%02x>:OFFSET<%03x>\n", loop, offset));
  470. if (!(--result0))
  471. {
  472. MESSAGE (("VERIFY : Too many errors in BANK0, aborting\n"));
  473. loop = 256;
  474. break;
  475. }
  476. }
  477. }
  478. }
  479. }
  480. if (header.page_size_bank1)
  481. {
  482. for (loop = 0; loop < 256; loop++)
  483. {
  484. MESSAGE (("Verifying BANK1: Page <%03d> of <256>", loop + 1));
  485. cart_read_page (BANK1, loop, header.page_size_bank1, image1);
  486. MESSAGE (("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"));
  487. if (fread (image2, sizeof (unsigned char), header.page_size_bank1, fp)
  488. != (size_t) header.page_size_bank1)
  489. {
  490. MESSAGE (("\nERROR : Disk read operation failed on %s\n",
  491. filename));
  492. fclose (fp);
  493. return FALSE;
  494. }
  495. for (offset = 0; offset < header.page_size_bank0; offset++)
  496. {
  497. if (image1[offset] != image2[offset])
  498. {
  499. MESSAGE (("VERIFY : Mismatch in BANK<1>:PAGE<%02x>:OFFSET<%03x>\n", loop, offset));
  500. if (!(--result1))
  501. {
  502. MESSAGE (("VERIFY : Too many errors in BANK1, aborting\n"));
  503. break;
  504. }
  505. }
  506. }
  507. }
  508. }
  509. fclose (fp);
  510. if (result0 != MAX_ERRORS || result1 != MAX_ERRORS)
  511. {
  512. MESSAGE (("VERIFY : FAILED \n"));
  513. return FALSE;
  514. }
  515. else
  516. {
  517. MESSAGE (("VERIFY : OK \n"));
  518. return TRUE;
  519. }
  520. }
  521. int
  522. cart_read (char *filename)
  523. {
  524. unsigned char image[MAX_PAGE_SIZE];
  525. // unsigned int page = 0;
  526. unsigned int loop = 0;
  527. FILE *fp;
  528. st_lnx_header_t header;
  529. #if 0
  530. DEBUG (("read_cart() called with <%s>\n\n", filename));
  531. #endif
  532. memset (&header, 0, sizeof (st_lnx_header_t));
  533. strcpy (header.magic, MAGIC_STRING);
  534. strcpy (header.cartname, cartname);
  535. strcpy (header.manufname, manufname);
  536. header.page_size_bank0 = cart_analyse (BANK0);
  537. header.page_size_bank1 = cart_analyse (BANK1);
  538. header.version = FILE_FORMAT_VERSION;
  539. if ((fp = fopen (filename, "wb")) == NULL)
  540. return FALSE;
  541. if (fwrite (&header, sizeof (st_lnx_header_t), 1, fp) != 1)
  542. {
  543. MESSAGE (("ERROR : Disk write operation failed on %s\n", filename));
  544. fclose (fp);
  545. return FALSE;
  546. }
  547. if (header.page_size_bank0)
  548. {
  549. for (loop = 0; loop < 256; loop++)
  550. {
  551. MESSAGE (("Reading BANK0: Page <%03d> of <256>", loop + 1));
  552. cart_read_page (BANK0, loop, header.page_size_bank0, image);
  553. MESSAGE (("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"));
  554. if (fwrite (image, sizeof (unsigned char), header.page_size_bank0, fp)
  555. != (size_t) header.page_size_bank0)
  556. {
  557. MESSAGE (("\nERROR : Disk write operation failed on %s\n",
  558. filename));
  559. fclose (fp);
  560. return FALSE;
  561. }
  562. }
  563. }
  564. if (header.page_size_bank1)
  565. {
  566. for (loop = 0; loop < 256; loop++)
  567. {
  568. MESSAGE (("Reading BANK1: Page <%03d> of <256>", loop + 1));
  569. cart_read_page (BANK1, loop, header.page_size_bank1, image);
  570. MESSAGE (("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"));
  571. if (fwrite (image, sizeof (unsigned char), header.page_size_bank1, fp)
  572. != (size_t) header.page_size_bank1)
  573. {
  574. MESSAGE (("\nERROR : Disk write operation failed on %s\n",
  575. filename));
  576. fclose (fp);
  577. return FALSE;
  578. }
  579. }
  580. }
  581. MESSAGE (("READ : OK \n"));
  582. fclose (fp);
  583. if (verify)
  584. return (cart_verify (filename));
  585. else
  586. return TRUE;
  587. }
  588. #if 0
  589. int
  590. cart_write (char *filename)
  591. {
  592. DEBUG (("write_cart() called with <%s>\n\n", filename));
  593. return TRUE;
  594. }
  595. #endif
  596. int
  597. perform_test (char *testname)
  598. {
  599. if (strcmp (testname, "LOOPBACK") == 0)
  600. {
  601. unsigned int loop;
  602. for (loop = 0; loop < 256; loop++)
  603. {
  604. lynxit_shift_out_byte ((unsigned char) loop);
  605. lynxit_shift_out_byte (0);
  606. lynxit_shift_out_byte (0);
  607. lynxit_shift_out_byte (0);
  608. if (lynxit_shift_in_byte () != (unsigned char) loop)
  609. {
  610. MESSAGE (("LOOPBACK : FAILED\n"));
  611. return FALSE;
  612. }
  613. }
  614. MESSAGE (("LOOPBACK : OK\n"));
  615. return TRUE;
  616. }
  617. else if (strncmp (testname, "SIZE", 4) == 0)
  618. {
  619. if (perform_test ("LOOPBACK") == FALSE)
  620. return FALSE;
  621. cart_analyse (BANK0);
  622. cart_analyse (BANK1);
  623. return TRUE;
  624. }
  625. else if (strncmp (testname, "CART", 4) == 0)
  626. {
  627. unsigned int page, offset;
  628. unsigned char image1[CART_PAGE_128K];
  629. unsigned char image2[CART_PAGE_128K];
  630. int result = TRUE;
  631. if (perform_test ("LOOPBACK") == FALSE)
  632. return FALSE;
  633. cart_analyse (BANK0);
  634. for (page = 0; page < 256; page++)
  635. {
  636. MESSAGE (("Testing BANK0: Page <%03d> of <256>", page + 1));
  637. cart_read_page (BANK0, page, CART_PAGE_128K, image1);
  638. cart_read_page (BANK0, page, CART_PAGE_128K, image2);
  639. MESSAGE (("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"));
  640. for (offset = 0; offset < CART_PAGE_128K; offset++)
  641. {
  642. if (image1[offset] != image2[offset])
  643. {
  644. MESSAGE (("CARTRIDGE: Bad read on PAGE %02x \n", page));
  645. result = FALSE;
  646. break;
  647. }
  648. }
  649. }
  650. if (!result)
  651. {
  652. MESSAGE (("CARTRIDGE: FAILED \n"));
  653. return FALSE;
  654. }
  655. else
  656. {
  657. MESSAGE (("CARTRIDGE: OK \n"));
  658. return TRUE;
  659. }
  660. }
  661. else if (strcmp (testname, "INPORT") == 0)
  662. {
  663. do
  664. {
  665. MESSAGE (("INPORT : Read %02x\n", INPUT (print_stat)));
  666. }
  667. while (!kbhit ());
  668. return TRUE;
  669. }
  670. else if (strcmp (testname, "PAGE") == 0)
  671. {
  672. do
  673. {
  674. lynxit_write_page (0xaa);
  675. MESSAGE (("PAGE : Wrote 0xAA to page\n"));
  676. getch ();
  677. lynxit_write_page (0x55);
  678. MESSAGE (("PAGE : Wrote 0x55 to page\n"));
  679. }
  680. while (getch () != 'q');
  681. return TRUE;
  682. }
  683. else if (strcmp (testname, "COUNTER") == 0)
  684. {
  685. int stepmode = TRUE;
  686. MESSAGE (("\nPress <space> key to step counter U5\n\n"));
  687. MESSAGE ((" 'q' - Quit to DOS\n"));
  688. MESSAGE ((" 's' - Step mode (default)\n"));
  689. MESSAGE ((" 'r' - Run mode\n"));
  690. MESSAGE ((" 'c' - Clear counter\n\n"));
  691. lynxit_counter_reset ();
  692. for (;;)
  693. {
  694. lynxit_counter_increment ();
  695. MESSAGE (("COUNTER : increment\n"));
  696. if (kbhit () || stepmode)
  697. {
  698. switch (getch ())
  699. {
  700. case 'q':
  701. return TRUE;
  702. case 's':
  703. stepmode = TRUE;
  704. break;
  705. case 'r':
  706. stepmode = FALSE;
  707. break;
  708. case 'c':
  709. lynxit_counter_reset ();
  710. MESSAGE (("COUNTER : reset\n"));
  711. break;
  712. default:
  713. break;
  714. }
  715. }
  716. }
  717. return TRUE;
  718. }
  719. else
  720. {
  721. return FALSE;
  722. }
  723. }
  724. //
  725. //
  726. // MAIN CODE
  727. //
  728. //
  729. static char buf[FILENAME_MAX];
  730. int
  731. lynxit_main (int argc, char **argv)
  732. {
  733. int loop;
  734. // Handle argument list
  735. #if 0
  736. for (loop = 0; loop < argc; loop++)
  737. strupr (argv[loop]);
  738. #endif
  739. for (loop = 1; loop < argc; loop++)
  740. {
  741. if (argv[loop][0] != '-')
  742. {
  743. break;
  744. }
  745. if (strlen (argv[loop]) > 3)
  746. {
  747. // usage ();
  748. printf ("\nInvalid argument %d <%s>\n", loop, argv[loop]);
  749. exit (FALSE);
  750. }
  751. switch (argv[loop][1])
  752. {
  753. case 'P':
  754. printer_port = (unsigned int) argv[loop][2] - '0';
  755. break;
  756. case 'D':
  757. debug = TRUE;
  758. break;
  759. case 'Q':
  760. quiet = FALSE;
  761. break;
  762. case 'N':
  763. verify = FALSE;
  764. break;
  765. case 'H':
  766. // usage ();
  767. exit (FALSE);
  768. default:
  769. // usage ();
  770. printf ("\nUnrecognised argument %d <%s>\n", loop, argv[loop]);
  771. exit (FALSE);
  772. }
  773. }
  774. // Check there are 2 spare arguments
  775. if (loop + 1 >= argc)
  776. {
  777. // usage ();
  778. MESSAGE (("\nERROR : Missing command/filename\n"));
  779. exit (FALSE);
  780. }
  781. // Initialise the printer port
  782. if (!ptr_port_init (printer_port))
  783. {
  784. MESSAGE (("ERROR : Couldn't initialise printer port LPT%d\n",
  785. printer_port));
  786. exit (FALSE);
  787. }
  788. // Perform loopback tests to prove operation
  789. if (!debug && strcmp (argv[loop], "TEST") != 0
  790. && !perform_test ("LOOPBACK"))
  791. {
  792. MESSAGE (("ERROR : LYNXIT doesn't appear to be working ????\n"));
  793. MESSAGE (("ERROR : (Check its plugged in and switched on)\n"));
  794. exit (FALSE);
  795. }
  796. if (strcmp (argv[loop], "READ") == 0)
  797. {
  798. if (loop + 3 >= argc)
  799. {
  800. MESSAGE (("ERROR : Missing Cartname/Manufacturer arguments\n"));
  801. exit (FALSE);
  802. }
  803. strcpy (cartname, argv[argc - 2]);
  804. strcpy (manufname, argv[argc - 1]);
  805. if (strlen (cartname) > 32 || strlen (manufname) > 16)
  806. {
  807. MESSAGE (("ERROR : Cartname/Manufacturer arguments too long (32/16)\n"));
  808. exit (FALSE);
  809. }
  810. strcpy (buf, argv[++loop]);
  811. if (cart_read (buf) == FALSE)
  812. {
  813. MESSAGE (("ERROR : Cartridge read failed\n"));
  814. exit (FALSE);
  815. }
  816. }
  817. else if (strcmp (argv[loop], "WRITE") == 0)
  818. {
  819. strcpy (buf, argv[++loop]);
  820. // cart_write (buf); // warning remover
  821. }
  822. else if (strcmp (argv[loop], "VERIFY") == 0)
  823. {
  824. cart_verify (argv[++loop]);
  825. }
  826. else if (strcmp (argv[loop], "TEST") == 0)
  827. {
  828. perform_test (argv[++loop]);
  829. }
  830. else
  831. {
  832. // usage ();
  833. printf ("\nInvalid command argument - Use READ/WRITE/VERIFY/TEST\n");
  834. exit (FALSE);
  835. }
  836. exit (TRUE);
  837. }
  838. int
  839. lynxit_read_rom (const char *filename, unsigned int parport)
  840. {
  841. char *argv[128];
  842. print_data = parport;
  843. parport_print_info ();
  844. argv[0] = "ucon64";
  845. argv[1] = "READ";
  846. strcpy (buf, filename);
  847. argv[2] = buf;
  848. if (lynxit_main (3, argv) != 0)
  849. {
  850. fprintf (stderr, ucon64_msg[PARPORT_ERROR]);
  851. exit (1);
  852. }
  853. return 0;
  854. }
  855. #endif // USE_PARALLEL