lynxit.c 25 KB

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