Message-ID: <001301c0aac3$843cdde0$72272a42@james> From: "James Allan Ventura" To: Subject: Problem with __asm and far* keywords Date: Sun, 11 Mar 2001 23:10:11 -0800 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.2615.200 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2615.200 Reply-To: djgpp AT delorie DOT com Hi, I have a source code written in Microsoft C. I tried to compile it using the GCC compiler and I get an error in the __asm and far* keywords. Is there a way to modify the code so I can compile it in GCC? Below is the copy of the source code. The errors are line numbers 63 and 129 in the code. Regards, James 1. // NOPPP.C (Revised) - M. Covington 1997, 1998, 1999 2. // Software for the "No-Parts Pic Programmer" 3. // Inspired by David Tait's TOPIC; compatible therewith. 4. // This is Microsoft C. 5. // Be sure to compile for 8088 (not 286 or 386) for maximum portability. 6. // Command line arguments: 7. // None. 8. // Environment variable: 9. // PPLPT=n where n=1, 2, or 3 specifies which LPT port to use. 10. #define BANNER "NOPPP - \"No-Parts\" PIC Programmer" 11. #include 12. #include 13. #include 14. #include 15. #include 16. #include 17. typedef unsigned int word; 18. typedef unsigned char byte, bit; 19. // ********************************************************************* 20. // GLOBAL STATUS VARIABLES 21. // ********************************************************************* 22. int LPT = 0, // which LPT port we're using (1..3) 23. PORT = 0; // its port address 24. #define PIC16C84 1 25. #define PIC16F84 2 26. #define PIC16F83 3 27. int DEVICE = 0; // which PIC we're programming 28. #define PROGRAM 1 29. #define VERIFY 0 // desired action in main programming loop 30. char FNAME[255]; // name of file currently loaded 31. char CHOICE = 0; // user's most recent menu choice 32. // ********************************************************************* 33. // I/O UTILITIES 34. // ********************************************************************* 35. #define KBUFSIZE 256 36. char buf[KBUFSIZE]; // keyboard input buffer 37. char* cleanctrl(char *s){ // truncates string at first ctrl char, 38. int i=0; // cleaning up ^M or ^J left behind by fgets 39. while (s[i] >= ' ') i++; // if s[i] is greater than or equal to a space (' ') 40. s[i] = 0; 41. return s; 42. } 43. char* getstring() { // read string 44. fgets(buf,KBUFSIZE-1,stdin); 45. cleanctrl(buf); 46. return buf; 47. } 48. int getint() { return atoi(getstring()); }; // read integer 49. char getchoice(char *s) { // read menu choice 50. // prints prompt, then reads letters, uppercasing, 51. // until a letter that is in s is found 52. printf("\n\nYour choice (%s): ",s); 53. do { 54. CHOICE = _getch(); 55. CHOICE = toupper(CHOICE); 56. // toupper evals arg twice, so arg can't be _getch() 57. } 58. while ((CHOICE == ',') || (strchr(s,CHOICE) == NULL)); 59. printf("%c\n",CHOICE); 60. return CHOICE; 61. } 62. void clearscreen() { 63. __asm { 64. mov ax,0f00h 65. int 010h 66. mov ah,0 67. int 010h 68. } 69. } 70. void waitkey() { 71. while (_kbhit()) { _getch(); }; 72. puts("\nPress space bar to continue..."); 73. _getch(); 74. while (_kbhit()) { _getch(); }; 75. } 76. void errmsg(char *s) { 77. puts(s); 78. waitkey(); 79. } 80. // ********************************************************************* 81. // TIMING 82. // ********************************************************************* 83. #define IODELAY (_inp(0x61)) // allow time for timer to respond 84. void delay(int k) 85. // Delay at least k microseconds, possibly a good bit more. 86. // k must be less than 27304. 87. // Minimum delay on a 25-MHz 386 is about 100 microseconds; 88. // on a 133-MHz Pentium, about 18 microseconds. 89. // Uses system timer 2. 90. // When running in a DOS box under OS/2, set HW_TIMER ON in DOS settings. 91. unsigned int w; 92. unsigned char lo,hi; 93. _outp(0x61, (_inp(0x61) & 0xFD) | 1); // spkr off, tmr 2 gate on 94. w = (unsigned int)(k*1.2); 95. _outp(0x43, 0xB0); // tmr 2 mode 0 2-byte load 96. IODELAY; 97. _outp(0x42, (unsigned char)w); // low byte 98. IODELAY; 99. _outp(0x42, (unsigned char)(w>>8)); // high byte 100. IODELAY; 101. do { 102. _outp(0x43,0x80); // latch timer count 103. IODELAY; 104. lo = _inp(0x42); // discard low byte 105. IODELAY; 106. hi = _inp(0x42); // get high byte 107. IODELAY; 108. } 109. while ((hi & 0x80) == 0); // wait for a 1 there, signifying rollover 110. return; 111. } 112. // ********************************************************************* 113. // PARALLEL PORT HARDWARE INTERFACE 114. // ********************************************************************* 115. // Uses two-wire serial data communication through printer port. 116. // Pin 1, STROBE, is serial clock; 117. // Pin 14, AUTOFD, is serial data out to PIC; 118. // Pin 11, BUSY, is serial data in from PIC; 119. // Pin 17, SLCTIN, is low when writing, high to provide pull-up when reading; 120. // Pin 2, D0, is lowered to apply Vpp. 121. // SLCTIN and BUSY are tied together for pull-up and for hardware detection. 122. // (In current versions this is done through diodes or gates.) 123. // SLCTIN is an open-collector output with pull-up. 124. // If it is pulled down, some printer ports will latch it down. 125. // Accordingly, it and all the other control bits are asserted 126. // every time they are needed. 127. byte BITS = 0x0F; 128. word portaddr(int n) { // base address of port LPTn 129. return(*(word far*)(0x00000408+2*n-2)); 130. } 131. // Procedures to set and clear the data lines 132. void datawritable() { // SLCTIN, AUTOFD down 133. BITS |= 0x0A; _outp(PORT+2,BITS); 134. } 135. void datareadable() { // SLCTIN, AUTOFD up 136. BITS &= ~0x0A; _outp(PORT+2,BITS); 137. } 138. void datadown() { BITS |= 0x02; _outp(PORT+2, BITS); } // AUTOFD down 139. void dataup() { BITS &= ~0x02; _outp(PORT+2, BITS); } // AUTOFD up 140. void clockdown() { BITS |= 0x01; _outp(PORT+2, BITS); } // STROBE down 141. void clockup() { BITS &= ~0x01; _outp(PORT+2, BITS); } // STROBE up 142. void vppon() 143. BITS &= ~0x04; 144. _outp(PORT+2, BITS); // INIT down, D0 down 145. _outp(PORT, 0 ); 146. } 147. void vppoff() 148. BITS |= 0x04; 149. _outp(PORT+2, BITS); // INIT up, D0 up 150. _outp(PORT, 1 ); 151. } 152. bit datain() { return(((~(byte)_inp(PORT+1)) & 0x80) >> 7); } 153. void allpinslow() { 154. vppoff(); 155. file://datawritable(); 156. file://datadown(); 157. file://clockdown(); 158. BITS = 0x0F; 159. _outp(PORT+2, BITS); 160. } 161. bit detecthardware() { // True if BUSY and SLCTIN are tied together. 162. datawritable(); // SLCTIN down 163. dataup(); // AUTOFD up 164. delay(10); 165. if (datain() == 1) return(0); 166. datareadable(); // SLCTIN up 167. dataup(); // AUTOFD up 168. delay(10); 169. if (datain() == 0) return(0); 170. return(1); 171. } 172. // ********************************************************************* 173. // PIC COMMUNICATION ROUTINES 174. // ********************************************************************* 175. void sendbit(bit b) { // Sends out 1 bit to PIC 176. if (b) dataup(); else datadown(); 177. clockup(); 178. delay(1); // tset1 179. clockdown(); // data is clocked into PIC on this edge 180. delay(1); // thld1 181. datadown(); // idle with data line low 182. } 183. bit recvbit() { // Receives a bit from PIC 184. bit b; 185. clockup(); 186. delay(1); // tdly3 187. clockdown(); // data is ready just before this 188. b = datain(); 189. delay(1); // thld1 190. return b; 191. } 192. void sendcmd(byte b) { // Sends 6-bit command from bottom of b 193. int i; 194. datawritable(); 195. delay(2); // thld0 196. for (i=6; i>0; i--) { 197. sendbit((bit)(b & 1)); 198. b = b >> 1; 199. } 200. delay(2); // tdly2 201. } 202. void senddata(word w) { // Sends 14-bit word from bottom of w 203. int i; 204. datawritable(); 205. delay(2); // thld0 206. sendbit(0); // one garbage bit 207. for (i=14; i>0; i--) { 208. sendbit((bit)(w & 1)); // 14 data bits 209. w = w >> 1; 210. } 211. sendbit(0); // one garbage bit 212. delay(2); // tdly2 213. } 214. word recvdata() { // Receives 14-bit word, lsb first 215. int i; 216. bit b; 217. word w = 0; 218. datareadable(); // SLCTIN up for pull-up 219. delay(2); // thld0 220. recvbit(); // one garbage bit 221. for (i=0; i<14; i++) { 222. b = recvbit(); 223. w = w | ((word)b << i); // 14 data bits 224. } 225. recvbit(); // another garbage bit; 226. delay(2); // tdly2 227. return w; 228. } 229. // ********************************************************************* 230. // PIC PROGRAMMING ALGORITHMS 231. // ********************************************************************* 232. // PIC MEMORY MAP 233. // The PIC16F84 has four programmable memory areas 234. // (plus data RAM, which is not programmable). 235. // Config memory is only 1 byte, but is treated like the others. 236. #define PBASE 0 // Base address of each memory 237. #define IBASE 0x2000 238. #define CBASE 0x2007 239. #define DBASE 0x2100 240. #define PSIZEMAX 1024 // Max size of each memory 241. #define ISIZEMAX 4 242. #define CSIZEMAX 1 243. #define DSIZEMAX 64 244. word PSIZE = PSIZEMAX; // Actual size, can be set lower 245. word ISIZE = ISIZEMAX; // for particular CPUs 246. word CSIZE = CSIZEMAX; 247. word DSIZE = DSIZEMAX; 248. word PMEM[PSIZEMAX]; // Arrays representing the memories 249. word IMEM[ISIZEMAX]; 250. word CMEM[CSIZEMAX]; 251. word DMEM[DSIZEMAX]; 252. word PUSED = 0; // Number of valid words in array 253. word CUSED = 0; 254. word IUSED = 0; 255. word DUSED = 0; 256. #define PMASK 0x3fff // Which bits are used in each word 257. word CMASK = 0x001f; // (CMASK depends on processor) 258. #define IMASK 0x3fff 259. #define DMASK 0x00ff 260. word DEFAULTCONFIG = 0x1B; // Initialization for config word 261. void cleararrays () { // Mark the memory arrays as empty 262. PUSED = 263. IUSED = 264. CUSED = 265. DUSED = 0; 266. } 267. bit stuffarray (word address, // Stuff data into a memory array. 268. word array[], // Returns true if successful. 269. word base, 270. word size, 271. word *used, 272. word data[], 273. int count) { 274. int i; 275. if (address-base+count-1 > size) { 276. printf("Invalid address: %04XH\n",address+count-1); 277. return 0; 278. } 279. for (i=0; i 32) return(0); // Valid byte count 355. cksum = bytecount; 356. i = 3; 357. bytecount = bytecount+3; 358. while (bytecount>0) { 359. bytecount--; 360. sscanf(s+i,"%2x",&b); 361. cksum = cksum+b; // Compute checksum 362. i = i+2; 363. } 364. sscanf(s+i,"%2x",&b); 365. cksum = -cksum; 366. if (cksum == b) return 1; // Test checksum 367. return 0; 368. } 369. void loadhexfile(FILE *f) { // Loads a hex file into memory arrays 370. char s[256]; 371. word i,lo,hi; 372. word linetype = 0; // 0 for data, 1 for end of file 373. word wordcount; // number of 16 bit words on this line 374. word address; // address where they begin 375. word data[8]; // 16 bytes = 8 words max. per line of hex 376. cleararrays(); 377. while((!feof(f)) && (linetype != 1)) { 378. fgets(s,255,f); 379. cleanctrl(s); 380. if (!validhexline(s)) { // Syntax check 381. s[40] = 0; // Truncate invalid line for display 382. if (s[0] != ':') { 383. printf("Invalid line (skipped): '%s'...\n",s); 384. continue; 385. } 386. else { 387. printf("Unable to decode line: '%s'...\n",s); 388. goto bailout; 389. } 390. } 391. sscanf(s+1,"%2x",&wordcount); // Parse the line - Intel Hex8M 392. wordcount = wordcount/2; // (double bytes, addresses doubled) 393. sscanf(s+3,"%4x",&address); 394. address = address/2; 395. sscanf(s+7,"%2x",&linetype); 396. if (linetype==1) goto finished; 397. for (i=0; i= DBASE) { 403. if (!stuffarray(address,DMEM,DBASE,DSIZE,&DUSED,data,wordcount)) 404. goto bailout; 405. } 406. else if (address >= CBASE) { 407. if (!stuffarray(address,CMEM,CBASE,CSIZE,&CUSED,data,wordcount)) 408. goto bailout; 409. } 410. else if (address >= IBASE) { 411. if (!stuffarray(address,IMEM,IBASE,ISIZE,&IUSED,data,wordcount)) 412. goto bailout; 413. } 414. else { 415. if (!stuffarray(address,PMEM,PBASE,PSIZE,&PUSED,data,wordcount)) 416. goto bailout; 417. } 418. } // while 419. finished: 420. printf("Program memory loaded: %5d word(s)\n",PUSED); 421. printf("Configuration loaded: %5d word(s)\n",CUSED); 422. printf("ID memory loaded: %5d word(s)\n",IUSED); 423. printf("Data memory loaded: %5d byte(s)\n",DUSED); 424. return; 425. bailout: 426. cleararrays(); 427. errmsg("Unable to load file."); 428. FNAME[0] = 0; 429. return; 430. } 431. // ********************************************************************* 432. // USER INTERFACE 433. // ********************************************************************* 434. void banner() { 435. clearscreen(); 436. puts("---------------------------------"); 437. puts(BANNER); 438. puts("Michael A. Covington"); 439. puts("Version of " __DATE__ " " __TIME__); 440. puts("---------------------------------"); 441. if (LPT > 0) printf("Using LPT%d on %03XH\n",LPT,PORT); 442. puts("---------------------------------"); 443. switch (DEVICE) { 444. case PIC16C84: printf("PIC16C84"); break; 445. case PIC16F84: printf("PIC16F84"); break; 446. case PIC16F83: printf("PIC16F83"); break; 447. default: printf(" "); 448. } 449. printf(" %s\n",FNAME); 450. puts("---------------------------------\n"); 451. } 452. void selectport() { 453. char c; 454. c = (getenv("PPLPT"))[0]; 455. if ((c >= '1') && (c <= '3')) { 456. CHOICE = c; 457. } 458. else { 459. banner(); 460. printf("Which LPT port? "); 461. getchoice("1,2,3"); 462. puts("\nTo avoid having to make this selection"); 463. puts("every time, you can add the command\n"); 464. printf(" SET PPLPT=%c\n\n",CHOICE); 465. puts("to your AUTOEXEC.BAT file."); 466. errmsg(" "); 467. } 468. LPT = CHOICE - '0'; 469. PORT = portaddr(LPT); 470. banner(); 471. puts("Apply power to programmer now.\n"); 472. puts("If your programmer has adjustable Vcc,"); 473. errmsg("set it to 5.0 volts."); 474. if (!detecthardware()) { 475. banner(); 476. puts("Caution: Programmer hardware not found!\n\n"); 477. puts("With some versions of the circuit and some"); 478. puts("parallel ports, this may be normal.\n"); 479. puts("If you are sure you have chosen the correct"); 480. puts("parallel port, press space bar to proceed."); 481. puts("To cancel program, press Ctrl-C."); 482. errmsg(" "); 483. } 484. } 485. void troubleshoot() { 486. banner(); 487. puts("Ensure programmer is powered up now,"); 488. puts("with Vcc set to 5.0 V (if adjustable)"); 489. puts("and no PIC in the socket."); 490. errmsg(" "); 491. allpinslow(); 492. banner(); 493. puts("TEST A\n"); 494. puts("Connect negative voltmeter lead to pin 5"); 495. puts("of PIC socket and check the following voltages:\n"); 496. puts(" Socket pin 4 < 0.8 V"); 497. puts(" Socket pin 12 < 0.8 V"); 498. puts(" Socket pin 13 < 0.8 V"); 499. puts(" Socket pin 14 4.75 to 5.25 V"); 500. puts(" Junction of"); 501. puts(" D1, D2, and R1 < 0.8 V"); 502. errmsg(" "); 503. vppon(); 504. clockup(); 505. dataup(); 506. banner(); 507. puts("TEST B\n"); 508. puts("With negative voltmeter lead still"); 509. puts("connected to pin 5 in the PIC socket,"); 510. puts("check the following voltages:\n"); 511. puts(" Socket pin 4 12.0 - 14.0 V"); 512. puts(" Socket pin 12 > 4.0 V"); 513. puts(" Socket pin 13 > 4.0 V"); 514. puts(" Junction of"); 515. puts(" D1, D2, and R1 < 0.8 V"); 516. errmsg(" "); 517. vppoff(); 518. clockdown(); 519. datareadable(); // AUTOFD, SLCTIN high 520. file://banner(); 521. file://puts("TEST 3\n"); 522. file://puts("With negative voltmeter lead still"); 523. file://puts("connected to pin 5 in the PIC socket,"); 524. file://puts("verify that pin 13 > 4.0 V.\n"); 525. file://puts("Next, insert a 470-ohm resistor into the socket"); 526. file://puts("connecting pin 13 to pin 5 and verify that"); 527. file://puts("pin 13 drops to < 2.0 V with the resistor in place.\n"); 528. file://errmsg("Then remove the resistor."); 529. allpinslow(); 530. datawritable(); // SLCTIN down 531. dataup(); // AUTOFD up 532. banner(); 533. puts("TEST C\n"); 534. puts("With negative voltmeter lead still"); 535. puts("connected to pin 5 in the PIC socket,"); 536. puts("verify that the junction of D1, D2, and R1"); 537. puts("is < 0.8 V."); 538. errmsg(" "); 539. allpinslow(); 540. datareadable(); // SLCTIN up 541. dataup(); // AUTOFD up 542. banner(); 543. puts("TEST D\n"); 544. puts("With negative voltmeter lead still"); 545. puts("connected to pin 5 in the PIC socket,"); 546. puts("verify that the junction of D1, D2, and R1"); 547. puts("is now > 4 V.\n"); 548. errmsg(" "); 549. banner(); 550. puts("This completes the voltage test sequence.\n"); 551. puts("You should also check the cable from PC to programmer."); 552. puts("It should be relatively short (under 2 feet) and have"); 553. puts("all necessary pins connected (serial cables don't)."); 554. errmsg(" "); 555. allpinslow(); 556. exit(0); 557. } 558. void load() { 559. FILE *f; 560. banner(); 561. printf("File to load: "); 562. strcpy(FNAME,getstring()); 563. f = fopen(FNAME,"rt"); 564. if (f == NULL) { 565. errmsg("Unable to open file."); 566. FNAME[0] = 0; 567. return; 568. } 569. loadhexfile(f); 570. fclose(f); 571. errmsg("Loading complete."); 572. if (CUSED == 0) { 573. banner(); 574. puts("Caution: HEX file did not contain a configuration word.\n"); 575. puts("The following settings will be used:\n"); 576. puts(" RC oscillator"); 577. puts(" Watchdog timer disabled"); 578. puts(" Power-up timer enabled"); 579. puts(" Code not read-protected\n"); 580. errmsg("You can specify other settings in the assembler."); 581. } 582. else if (CMEM[0] != (CMEM[0] & CMASK)) { 583. banner(); 584. puts("Caution: Configuration word appears to contain invalid bits.\n"); 585. puts("Your program may have been assembled for a different"); 586. puts("type of PIC. Check device selection carefully."); 587. errmsg(""); 588. } 589. } 590. void selectdevice() { 591. banner(); 592. puts("Devices supported:\n"); 593. puts(" C PIC16C84"); 594. puts(" F PIC16F84"); 595. puts(" 3 PIC16F83\n\n"); 596. puts(" T Test the programmer circuit\n"); 597. getchoice("C,F,3,T"); 598. switch(CHOICE) { 599. case 'C': 600. DEVICE = PIC16C84; 601. PSIZE = 1024; 602. CMASK = 0x001F; 603. DEFAULTCONFIG = 0x001B; 604. break; 605. case 'F': 606. DEVICE = PIC16F84; 607. PSIZE = 1024; 608. CMASK = 0x3FFF; 609. DEFAULTCONFIG = 0x3FF3; 610. break; 611. case '3': 612. DEVICE = PIC16F83; 613. PSIZE = 512; 614. CMASK = 0x3FFF; 615. DEFAULTCONFIG = 0x3FF3; 616. break; 617. case 'T': 618. troubleshoot(); 619. } 620. } 621. void erase() { 622. int i; 623. vppreset(); 624. printf("Commanding PIC to erase ID, configuration, "); 625. sendcmd(LOADCONFIG); 626. senddata(0x3FFF); 627. for (i=7; i>0; i--) sendcmd(INCREMENTADDRESS); 628. sendcmd(1); 629. sendcmd(7); 630. sendcmd(BEGINPROGRAMMING); 631. delay(20000); 632. sendcmd(1); 633. sendcmd(7); 634. printf("program, "); 635. progcycle(ERASEPROGRAM,0x3FFF); // is the data word necessary? 636. printf("data..."); 637. progcycle(ERASEDATA,0x3FFF); // is the data word necessary? 638. allpinslow(); 639. puts(" Done."); 640. waitkey(); 641. } 642. void program(int mode) { 643. word i; 644. banner(); 645. if (PUSED+IUSED+CUSED+DUSED == 0) { 646. printf("Load a file first.\n"); 647. goto finish; 648. } 649. vppreset(); 650. printf("Program memory: "); 651. if (!programall(mode,PMASK,LOADPROGRAM,READPROGRAM,PMEM,PBASE,PUSED)) 652. goto finish; 653. sendcmd(LOADCONFIG); // from here on we're in config/ID memory 654. senddata(DEFAULTCONFIG); // loadconfig requires an arg, here it is 655. printf("ID memory: "); 656. if (!programall(mode,IMASK,LOADPROGRAM,READPROGRAM,IMEM,IBASE,IUSED)) 657. goto finish; 658. for (i=0; i < CBASE-IBASE-IUSED; i++) 659. sendcmd(INCREMENTADDRESS); // get to config memory 660. printf("Configuration memory: "); 661. if (!programall(mode,CMASK,LOADPROGRAM,READPROGRAM,CMEM,CBASE,CUSED)) 662. goto finish; 663. vppreset(); // Reset address counter in PIC to 0 664. printf("Data memory: "); 665. if (!programall(mode,DMASK,LOADDATA,READDATA,DMEM,DBASE,DUSED)) 666. goto finish; 667. puts("Programming complete.\n\n"); 668. puts("For production-grade work, you should now verify"); 669. puts("the PIC at the maximum and minimum values of Vcc."); 670. finish: 671. allpinslow(); 672. waitkey(); 673. } 674. void queryexit() { 675. banner(); 676. allpinslow(); 677. puts("Are you sure you want to exit?"); 678. getchoice("Y,N"); 679. if (CHOICE == 'Y') 680. banner(); 681. errmsg("You may remove the PIC from the socket now."); 682. exit(0); 683. } 684. } 685. void menu() { 686. allpinslow(); // Clean up after aberrant routines if any 687. banner(); 688. puts(" L Load HEX file"); 689. puts(" S Select type of PIC"); 690. puts(" E Erase PIC"); 691. puts(" P Program PIC"); 692. puts(" V Verify PIC\n"); 693. puts(" X Exit program"); 694. getchoice("L,S,E,P,V,X"); 695. switch(CHOICE) { 696. case 'L': load(); break; 697. case 'S': selectdevice(); break; 698. case 'E': erase(); break; 699. case 'P': program(PROGRAM); break; 700. case 'V': program(VERIFY); break; 701. case 'X': queryexit(); 702. } 703. } 704. main() { 705. FNAME[0] = 0; // no file is presently loaded 706. selectport(); 707. allpinslow(); 708. selectdevice(); // mandatory 709. banner(); 710. puts("You may insert the PIC in the socket now."); 711. errmsg("Be very careful not to insert it backward."); 712. while(1) menu(); 713. return 0; 714. } Shop online without a credit card http://www.rocketcash.com RocketCash, a NetZero subsidiary