TVG.c
上传用户:super_houu
上传日期:2008-09-21
资源大小:4099k
文件大小:53k
源码类别:

DVD

开发平台:

Others

  1. #include "Config.h" // Global Configuration - do not remove!
  2. #ifdef TV_GUARDIAN_ENABLE
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include "Playcoretvgtvg.h"
  7. #include "Playcoretvgtvglo.h"
  8. #include "Playcoretvgtvgcode.h"
  9. #define TV_GUARDIAN_ENABLE
  10. #include "Playcoretvgtvgapi.h"
  11.              
  12. //**********************************************************************
  13. //                        RAM global registers 
  14. //**********************************************************************
  15. #include "Playcoretvgtvgram.c"
  16. //**********************************************************************
  17. //****                        ROM Constants
  18. //**********************************************************************
  19. #include "Playcoretvgtvgdict.c"
  20. #include "Playcoretvgtvgpar.c"
  21. //**********************************************************************
  22. //****                  Internal Function Prototypes
  23. //**********************************************************************
  24. // Internal TVG Functions
  25. // BUFF  ccbuff routines
  26. void next_ccbuff_pos( void );
  27. void next_ccbuff_char( void );
  28. void cussword_right( void );
  29. void cussword_left( void );
  30. // CCUTIL  gen purpose cc routines
  31. uchar chk_if_cmd( void );
  32. uchar chk_if_letter( void );
  33. void chk_case( void );
  34. uchar chk_if_punct( void );
  35. void chk_plural( void );
  36. void chk_cc_char( void );
  37. // CUSS  cussword routines
  38. void chkforcuss( void );
  39. uchar find_word( void );
  40. void find_word_nextltr( void );
  41. void chk_grammar( void );
  42. void cussword_watch( void );
  43. void cussword_len( void );
  44. // IOUTIL  i/o routines
  45. void send2chars( void );
  46. void insert2spaces( void );
  47. void process_cc( void );
  48. // Simulated EEPROM Dictionary Routines
  49. void get_ee_char( void );
  50. void get_ee_char_next( void );
  51. void get_ee_addr( void );
  52. // HWUTIL  hardware routines
  53. //**********************************************************************
  54. //**********************************************************************
  55. //***
  56. //***  TVG Specific Functions
  57. //***
  58. //**********************************************************************
  59. //**********************************************************************
  60. #define CMD_POWER_ON 0
  61. #define CMD_REINIT   1
  62. #ifdef DEC14TEST
  63. FILE *dbug;
  64. #endif
  65. void tvg_init( uchar cmd ) {
  66.   uchar i;
  67.   
  68. // Zero out all TVG memory locations from SIMRAM.H
  69.   tvg_flags=0;
  70.   ee_addr=0;
  71.   dummy=0; dummy2=0;
  72.   io_map=0; 
  73.   timer_mute=0; timer_tvg=0;
  74.   counter=0; 
  75.   r0=0; r1=0; prev_c1=0; prev_c2=0;
  76.   replace_index=0;
  77.   start_of_word=0; first_char=0; last_char=0;
  78.   words_found=0; word_length=0;
  79.   errors_cc=0; 
  80.   cc_buffer_in=0; cc_buffer_out=0; cc_buffer_pos=0;
  81.   for(i=0;i<CC_BUFFER_LEN;i++) cc_buffer[i]=0;
  82. // Zero out all TVG memory locations from this file
  83.   w=0; fsr=(uchar*)NULL;
  84.   brtemp=0;
  85.   for(i=0;i<CCMAXFIFO;i++) ccfifo[i]=0;
  86.   iccfifo=0;
  87.   occfifo=0;
  88. /*** INITIALIZE THINGS *****/
  89.   cc_buffer_in=0;
  90.   cc_buffer_out=0;
  91.   cc_buffer_pos=0;
  92.   for(i=0;i<CC_BUFFER_LEN;i++) cc_buffer[i]=0;
  93.   if(cmd==CMD_POWER_ON) {
  94.     tvg_flags |= POWER_ON; // Indicate first time loop for tvg_process()
  95. #ifdef DEC14TEST
  96.     dbug=fopen("debug.dat","w");
  97. #endif
  98.   }
  99.   if(cmd==CMD_REINIT) {
  100.     tvg_flags |= TVG_MUTE;   
  101.     timer_mute = 2 * 30; // Load mute timer w/2 seconds
  102.   }
  103.   tvg_flags |= FIRST_LOOP; // Indicate first time loop for tvg_process()
  104.   tvg_process_modes();
  105. /* OTHERS...?????  */
  106.   timer_tvg=0;  //  so proccc() will be called
  107.   return;
  108. }
  109. void tvg_process( uchar *ccdata, uchar *ccdata_out, uchar field ) {
  110.   uchar c1,c2;
  111.   uchar i,j;
  112.   tvg_process_modes();
  113.   if(tvg_flags & FORCE_NULLS) { //  force nulls, no processing
  114.     ccdata_out[0]=0x80;
  115.     ccdata_out[1]=0x80;
  116.     return;
  117.   }
  118.   if(tvg_flags & POWER_ON) {
  119.     // this is where we would display a long message
  120.     // show_tvg_bug(BUG_TVG_VERSION);
  121.     tvg_flags &= ~POWER_ON;
  122.   }
  123.   if(io_map & TVG_OFF) { // just pass data thru - no processing
  124.     ccdata_out[0]=ccdata[0];
  125.     ccdata_out[1]=ccdata[1];
  126.     return;
  127.   }
  128. //****************************************************************
  129. //****              THE MAIN TVG PROCESSING LOOP              ****
  130. //****************************************************************
  131.   if(tvg_flags & FIRST_LOOP) {
  132.     chkforcuss();             // check if next word is a cussword
  133.     goto MAIN_0;
  134.   }
  135. MAIN_ENTRY:
  136.   tvg_process_timers();
  137. //Save incoming pair of CC characters
  138. //formerly get2chars function...
  139.   c1=ccdata[0] & 0x7F;
  140.   c2=ccdata[1] & 0x7F;
  141.   if(ccdata[0] != mkpar[c1]) c1=0x7C; // parity err -> block char TEST - really should be 0x7F
  142.   if(ccdata[1] != mkpar[c2]) c2=0x7C; // parity err -> block char
  143.   fsr=cc_buffer+cc_buffer_in;
  144.   *fsr=c1;
  145.   fsr++;
  146.   *fsr=c2;
  147.   cc_buffer_in += 2;
  148.   cc_buffer_in %= CC_BUFFER_LEN;
  149. //end get2chars
  150. MAIN_0:
  151.   if(errors_cc > MAX_CCERRORS ) {       /* check if too many cc errors */
  152.     tvg_flags &= ~IN_POPON;  //clr
  153.   }
  154. MAIN_1:  /*** SEND/EXTRACT CC DATA (FILL BUFFER UP TO CURRENT POSITION) ***/
  155. #if 0
  156.   w = cc_buffer_pos - cc_buffer_out;
  157.   if((char)w<0) w+=CC_BUFFER_LEN;       /* buffer wrap-around??? */
  158.   if(w<2) {                             /* else, check next word */
  159.     chkforcuss();                       /* check if next word is a cussword */
  160.     goto MAIN_0;
  161.   }
  162. #endif
  163.   sw = cc_buffer_pos - cc_buffer_out;
  164.   if(sw<0) sw+=CC_BUFFER_LEN;       /* buffer wrap-around??? */
  165.   if(sw<2) {                             /* else, check next word */
  166.     chkforcuss();                       /* check if next word is a cussword */
  167.     goto MAIN_0;
  168.   }
  169.   send2chars();                         // put oldest 2 CC chars to OSD
  170.   transmit2chars(ccdata_out, field);
  171.   if(tvg_flags & FIRST_LOOP) {
  172.     tvg_flags &= ~FIRST_LOOP;
  173.     goto MAIN_ENTRY;
  174.   }
  175. }
  176. void chkforcuss( void ) {
  177.   uchar i,j;
  178.   if(!(tvg_flags & IN_POPON)) {      /* are we in a pop-on? */
  179.     next_ccbuff_pos();                  /* no, don't search for cuss */
  180.     return;
  181.   }
  182.   counter=CC_BUFFER_LEN - 2;
  183.   fsr = cc_buffer + cc_buffer_pos;      /* point to current buffer posn */
  184. CHKFORCUSS_FS:                          /* (2) FIND START OF NEXT WORD */
  185.   w=*fsr;
  186.   if(chk_if_cmd()) {
  187.     next_ccbuff_pos();                  /* skip whole CC cmd pair */
  188.     next_ccbuff_pos();                  /* advance to next buffer posn */
  189.     return;
  190.   }
  191. CHKFORCUSS_NL:                          /* next letter */
  192.   chk_case();                           /* convert lowercase chars if necessary */
  193.   if(!chk_if_letter()) {
  194.     next_ccbuff_pos();                  /* advance to next buffer posn */
  195.     return;
  196.   }
  197. CHKFORCUSS_SS:                          /* (3) SAVE START OF WORD POSITION */
  198.   start_of_word = cc_buffer_pos;        /* save start of word posn */
  199.   first_char = *fsr;                    /* save first character, too */
  200. CHKFORCUSS_FE:                          /* (4) FIND END OF WORD */
  201.   do {
  202.     w=*fsr;                             /* char @current posn */
  203.     chk_case();
  204.     if(!chk_if_letter()) goto CHKFORCUSS_SE;
  205.     last_char=*fsr;                     /* SAVE CHAR AS LAST CHAR OF WORD */
  206.     next_ccbuff_pos();
  207.   } while( --counter > 0 );
  208.   return;
  209. CHKFORCUSS_SE:                          /* (5) END OF WORD FOUND */
  210.   // Eliminate this; check for TVG off is done at start of tvg_process
  211.   //  if(io_map & TVG_OFF) return;      /* return - no need to check */
  212.   ee_addr = 0;                          /* point to beg section of dict */
  213.   w=first_char;
  214.   if( w<'D') goto CHKFORCUSS_CW;
  215.   ee_addr += 0x010;   // 0x010
  216.   if( w<'G') goto CHKFORCUSS_CW;
  217.   ee_addr += 0x010;   // 0x020
  218.   if( w<'J') goto CHKFORCUSS_CW;
  219.   ee_addr += 0x010;   // 0x030
  220.   if( w<'P') goto CHKFORCUSS_CW;
  221.   ee_addr += 0x010;   // 0x040
  222.   if( w<'T') goto CHKFORCUSS_CW;
  223.   ee_addr += 0x010;   // 0x050
  224. CHKFORCUSS_CW:                          /* (7) CHECK IF WORD IS CUSSWORD */
  225.   get_ee_addr();           //Get offest to start of desired section
  226.   replace_index=0xff;
  227. #if 0
  228.   if(find_word()) goto CUSSWORDFOUND_RET;  /* not a cussword (note neg logic */
  229. #endif
  230.   j=find_word();
  231. #if 1
  232. #ifdef DEC14TEST
  233.   fprintf(dbug,"LOOKING FOR WORD:===============n" );
  234.   fprintf(dbug,"start of word.......> %02xn", start_of_word );
  235.   fprintf(dbug,"first char..........> %cn", first_char );
  236.   fprintf(dbug,"last char...........> %cn", last_char );
  237.   fprintf(dbug,"counter.............> %02xn", counter );
  238.   fprintf(dbug,"words found.........> %02xn", words_found );
  239.   fprintf(dbug,"word length.........> %02xn", word_length );
  240.   fprintf(dbug,"eow_flags...........> %02xn", eow_flags );
  241.   fprintf(dbug,"word_toler..........> %02xn", word_toler );
  242.   fprintf(dbug,"replace_index.......> %02xn", replace_index );
  243.   fprintf(dbug,"tvg_flags...........> %08lxn", tvg_flags );
  244.   fprintf(dbug,"cc_buffer...........>" );
  245.   for(i=0;i<16;i++) fprintf(dbug," %02x", cc_buffer[i] );
  246.   fprintf(dbug,"n                     " );
  247.   for(i=0;i<16;i++) {
  248.     if(isprint(cc_buffer[i])) fprintf(dbug,"  %c", cc_buffer[i] );
  249.     else                      fprintf(dbug,"  ." );
  250.   }
  251.   fprintf(dbug,"n" );
  252. #endif
  253. #endif
  254.   if(tvg_flags & WORD_FOUND) cussword_len();
  255.   if(j) goto CUSSWORDFOUND_RET;  /* not a cussword (note neg logic */
  256.   if(tvg_flags & GCHK_FLAG) chk_grammar(); /* check grammar if needed */
  257.   if(!(eow_flags & DICT_WATCHWD)) goto CUSSWORDFOUND; /* process found words */
  258. //  cussword_len();
  259.   goto CUSSWORDFOUND_RET;               /* goto process watch word and return */
  260. CUSSWORDFOUND:                          /**** CUSS WORD FOUND ****/
  261. #ifdef DEC14TEST
  262.   fprintf(dbug,"CUSSWORDFOUND:===============n" );
  263.   fprintf(dbug,"start of word.......> %02xn", start_of_word );
  264.   fprintf(dbug,"first char..........> %cn", first_char );
  265.   fprintf(dbug,"last char...........> %cn", last_char );
  266.   fprintf(dbug,"words found.........> %02xn", words_found );
  267.   fprintf(dbug,"word length.........> %02xn", word_length );
  268.   fprintf(dbug,"eow_flags...........> %02xn", eow_flags );
  269.   fprintf(dbug,"word_toler..........> %02xn", word_toler );
  270.   fprintf(dbug,"replace_index.......> %02xn", replace_index );
  271.   fprintf(dbug,"ee_addr.............> %04xn", ee_addr );
  272.   fprintf(dbug,"cc_buffer...........>" );
  273.   for(i=0;i<16;i++) fprintf(dbug," %02x", cc_buffer[i] );
  274.   fprintf(dbug,"n                     " );
  275.   for(i=0;i<16;i++) {
  276.     if(isprint(cc_buffer[i])) fprintf(dbug,"  %c", cc_buffer[i] );
  277.     else                      fprintf(dbug,"  ." );
  278.   }
  279.   fprintf(dbug,"n" );
  280. #endif
  281.   mute_audio();                         /* mute audio */
  282.   tvg_flags |= CUSSING;              /* set flag that cussing detected */
  283.   words_found++;                        /* incr cussword counter */
  284. //  cussword_len();
  285. #ifdef DEC14TEST
  286.   fprintf(dbug,"CUSSWORD_LEN:===============n" );
  287.   fprintf(dbug,"start of word.......> %02xn", start_of_word );
  288.   fprintf(dbug,"first char..........> %cn", first_char );
  289.   fprintf(dbug,"last char...........> %cn", last_char );
  290.   fprintf(dbug,"word length.........> %02xn", word_length );
  291. #endif
  292.   chk_plural();                         /* check for plural words */
  293. #ifdef DEC14TEST
  294.   fprintf(dbug,"CHK_PLURAL:===============n" );
  295.   fprintf(dbug,"start of word.......> %02xn", start_of_word );
  296.   fprintf(dbug,"first char..........> %cn", first_char );
  297.   fprintf(dbug,"last char...........> %cn", last_char );
  298.   fprintf(dbug,"word length.........> %02xn", word_length );
  299.   fprintf(dbug,"n" );
  300. #endif
  301. CUSSWORDFOUND_0:                        /* (4) LOCATE REPLACEMENT WORD */
  302.   ee_addr=0x060;                        /* offset to replacement table stored here */
  303.   get_ee_addr();                        /* Get it */
  304.   get_ee_char();                        /* access beg of niceword table */
  305.   dummy=w;                              /* save first char in dummy */
  306.   w=replace_index & INDEX;              /* get offset into nice word table */
  307.   if(w==0) goto CUSSWORDFOUND_2;        /* skip locate word if zero index */
  308.   counter=w;                            /* replacement index -> counter */
  309. CUSSWORDFOUND_1:
  310.   get_ee_char_next();                   /* get next niceword letter -> W */
  311.   if(w!=0) goto CUSSWORDFOUND_1;        /* keep looking for end of word */
  312.   counter--;
  313.   if(counter !=0) goto CUSSWORDFOUND_1; /* keep looking for indexed word */
  314.   get_ee_char_next();                   /* move to 1st ltr of niceword */
  315.   dummy=w;                              /* save in dummy */
  316. CUSSWORDFOUND_2:                        /* (5) POINT TO CUSSWORD */
  317.   fsr=cc_buffer+start_of_word;          /* point start of cussword in buff */
  318. CUSSWORDFOUND_3:                        /* (6) REPLACE CUSSWORD W/ NICEWORD */
  319.   *fsr=w;                               /* replace cuss ltr w/nice ltr */
  320.   next_ccbuff_char();                   /* next cussword ltr posn */
  321.   /* NOTE: return value is ignored in original assy code */
  322.   if(w==0) goto CUSSWORDFOUND_3A;       /* chk if done replacing */
  323.   get_ee_char_next();                   /* get next niceword letter */
  324.   dummy=w;
  325. CUSSWORDFOUND_3A:
  326.   word_length--;
  327.   if(word_length!=0) goto CUSSWORDFOUND_3; /* keep replacing cuss word */
  328.   if(w==0) goto CUSSWORDFOUND_RET;      /* return if niceword compl (NULL) */
  329.                                         /**** INSERT REST OF NICEWORD ****/
  330. CUSSWORDFOUND_4:                        /* (1) START AT IN_POSITION - 1 */
  331.   counter=cc_buffer_in;
  332.   w=cc_buffer_in;
  333.                                         /* (2) SEND OLDEST 2 CHARS */
  334.   send2chars();                         /* SEND NEXT 2 CHARS TO OSD */
  335.   cc_buffer_in=cc_buffer_out;
  336.   ee_addr--;                            /* dec eeprom addr, read char */
  337.   get_ee_char();
  338.   dummy=w;
  339. CUSSWORDFOUND_5:                        /* (4) GET CHAR AT CURRENT POSITION */
  340.   w=1;
  341.   cussword_left();                      /* move pointer left one */
  342.   fsr=cc_buffer+counter;                /* point to cc buffer in posn */
  343.   w=*fsr;                               /* get char */
  344.   dummy2=w;                             /* save it in dummy2 */
  345.   w=2;                                  /* (5) MOVE POINTER + 2 */
  346.   cussword_right();                     /* move pointer right by two */
  347.                                         /* (6) PUT CHAR AT NEW LOCATION */
  348.   fsr=cc_buffer+w;                      /* point to new location */
  349.   *fsr=dummy2;                          /* put char in new posn */
  350.   w=2;                                  /* (7) MOVE POINTER - 2 */
  351.   cussword_left();                      /* move pointer left two */
  352.                                         /* (8) CHECK IF ENOUGH CHARS MOVED */
  353.   if(cc_buffer_pos!=counter)            /* keep shifting chars until */
  354.     goto CUSSWORDFOUND_5;               /* pointer = posn */
  355.                                         /* (9) INSERT 2 NICEWORD CHARS */
  356.   fsr=cc_buffer+cc_buffer_pos;          /* point to where we left off */
  357.   dummy2=2;                             /* save 2 -> dummy2??? */
  358.   w=dummy;                              /* restore niceword letter */
  359. CUSSWORDFOUND_6:
  360.   dummy=w;                              /* save nice letter */
  361.   *fsr=w;                               /* put niceword letters at pos */
  362.   next_ccbuff_pos();                    /* next cussword letter posn */
  363.   w=1;
  364.   cussword_right();                     /* move pointer right 1 */
  365.   get_ee_char_next();                   /* get next niceword letter */
  366.   dummy2--;
  367.   if(dummy2!=0) goto CUSSWORDFOUND_6;   /* do one more character */
  368.                                         /* (10) CHECK IF DONE INSERTING */
  369.   if(dummy==0) goto CUSSWORDFOUND_RET;  /* done if null */
  370.   dummy=w;                              /* save nice letter -> dummy */
  371.   if(dummy==0) goto CUSSWORDFOUND_RET;  /* done if null */
  372.   goto CUSSWORDFOUND_4;                 /* else, go do two more chars */
  373. CUSSWORDFOUND_RET:                      /**** RETURN FROM CHKFORCUSS ****/
  374.   cussword_watch();                     /* process watch words */
  375.   return;
  376. }
  377. /******************************************************************************
  378. ;* FUNCTION:    CHK_IF_CMD
  379. ;* DESC:        CHECK IF CURRENT CHAR IS A CC CMD PREFIX
  380. ;* INPUT:       W = CHAR
  381. ;* OUTPUT:      W = INPUT CHAR, C = STATUS (0=NOT A CMD CHAR,1=CMD CHAR)
  382. */
  383. uchar chk_if_cmd( void ) {
  384.   if( (w>0x09) && (w<=0x17) ) return 1;
  385.   else return 0;
  386. }
  387. /******************************************************************************
  388. ;* FUNCTION:    CHK_IF_LETTER
  389. ;* DESC:        CHECK IF CURRENT CHAR IS A LETTER
  390. ;* INPUT:       W = CHAR
  391. ;* OUTPUT:      W = INPUT CHAR, CARRY = STATUS (0=NOT A LETTER,1=LETTER)
  392. */
  393. uchar chk_if_letter( void ) {
  394.   if( (w>='A') && (w<='Z') ) return 1;
  395.   else return 0;
  396. }
  397. /******************************************************************************
  398. ;* FUNCTION:    CHK_CASE
  399. ;* DESC:        IF LETTER IS LOWER CASE, CONVERT TO UPPER
  400. ;* INPUT:       FSR = POINTER TO CHAR
  401. ;* OUTPUT:      W = INPUT CHAR (CONVERTED TO UPPER IF NECESSARY)
  402. */
  403. void chk_case( void ) {
  404.   w=*fsr;
  405.   if( (w>='a') && (w<='z') ) {
  406.     w -= ('a' - 'A');
  407.     *fsr=w;
  408.   }
  409.   return;
  410. }
  411. /******************************************************************************
  412. ;* FUNCTION:    CHK_IF_PUNCT
  413. ;* DESC:        CHECK IF CURRENT CHAR IS NOT ACCEPTABLE PUCTUATION TO
  414. ;*              PRECEDE LETTERS ON A LINE
  415. ;* INPUT:       W = CHAR
  416. ;* OUTPUT:      W = INPUT CHAR, CARRY = STATUS (SET=NOT OK,CLEAR=OK)
  417. */
  418. uchar chk_if_punct( void ) {
  419.   if(w==' ') return 1;
  420.   if(w=='!') return 1;
  421.   if(w==''') return 1;
  422.   if(w=='.') return 1;
  423.   if(w==',') return 1;
  424.   if(w=='?') return 1;
  425.   return 0;
  426. }
  427. /******************************************************************************
  428. ;* FUNCTION:    FIND_WORD
  429. ;* DESC:        SEARCH FOR WORD IN CUSSWORD DICTIONARY
  430. ;* OUTPUT:      Z = STATUS (1=NOT FOUND,0=FOUND), REPLACE_INDEX
  431. */
  432. uchar find_word( void ) {
  433.   tvg_flags &= ~WORD_FOUND;
  434. FIND_WORD:
  435.   get_ee_char();
  436.   dummy=w;
  437.   tvg_flags &= ~NR_FLAG;             /* CLEAR "NON-ROOT CUSS WORD" FLAG */
  438. FIND_WORD_0:                            /* (1) POINT TO START OF WORD */
  439.   fsr=cc_buffer+start_of_word;
  440.   counter=0;                            /* 0 --> CUSS WORD LETTER COUNTER */
  441.   tvg_flags &= ~TEMP_GC;             /* CLEAR "GRAMMAR CHECK NEEDED" FLAG */
  442.   tvg_flags |= DUMMY_FLAG;           /* ASSUME PLURALS ARE OK */
  443. FIND_WORD_1:                            /* (2) GET DICTIONARY LETTER */
  444.   if(dummy==0xff) goto FIND_WORD_DONE;  /* if end of table, done searching */
  445.   brtemp=dummy;
  446.   if(brtemp & BIT_EOW) goto FIND_WORD_FOUND; /* WORD FOUND !!! */
  447. #if 0
  448. // This section from legacy v1 dictionary code
  449.   if(dummy==0) {                        /* (3) CHECK IF AT END OF A NON-ROOT */
  450.     tvg_flags |= NR_FLAG;            /* SET "NON-ROOT CUSS WORD" FLAG */
  451.     goto FIND_WORD_NC;                  /* skip to next CC char */
  452.   }
  453. FIND_WORD_2:                            /* (4) CHECK IF GRAMMAR CHECK NEEDED */
  454.   if(dummy==1) {
  455.     tvg_flags |= TEMP_GC;            /* SET "GRAMMAR CHECK NEEDED" FLAG */
  456.     goto FIND_WORD_NC;                  /* skip to next CC char */
  457.   }
  458. FIND_WORD_3:                            /* (5) CHECK IF PLURALS ARE ALLOWED */
  459.   if(dummy==2) {
  460.     tvg_flags &= ~DUMMY_FLAG;         /* DON'T ALLOW TO BE PLURAL */
  461.     goto FIND_WORD_NC;                  /* skip to next CC char */
  462.   }
  463. // End of legacy flags section
  464. #endif
  465. FIND_WORD_CMP:                          /* (6) COMPARE CC AND DICT. LETTERS */
  466.   chk_case();                           /* conv lowercase chars if necessary */
  467.   w=dummy;                              /* save dictionary letter in W */
  468.   if((*fsr)<w) {
  469.     goto FIND_WORD_DONE;     /* done searching if DictLtr < CCchar */
  470.   }
  471.   if((*fsr)>w) {
  472.     goto FIND_WORD_NEXTWORD; /* else goto next dictionary word  */
  473.   }
  474.                                         /* else... DictLtr==CCchar */
  475.                                         /* (7) PREPARE FOR NEXT CHAR */
  476.   counter++;                            /* CUSSWORD LETTER COUNTER ++ */
  477.   next_ccbuff_char();                   /* NEXT LETTER OF CC WORD */
  478.   /* NOTE: return value is ignored in original assy code */
  479. FIND_WORD_NC:
  480.   find_word_nextltr();                  /* NEXT DICTIONARY LETTER --> DUMMY */
  481.   goto  FIND_WORD_1;                    /* KEEP COMPARING LETTERS */
  482. FIND_WORD_NEXTWORD:                     /**** MOVE TO NEXT DICT. WORD ****/
  483.   find_word_nextltr();                  /* NEXT DICTIONARY LETTER --> DUMMY */
  484.   brtemp=dummy;
  485.   if(brtemp & BIT_EOW) {                /* end of dictionary word? */
  486.     find_word_nextltr();                /* skip over tolerance*/
  487.     find_word_nextltr();                /* skip over replacement index */
  488.     find_word_nextltr();                /* next dictionary letter --> dummy */
  489.     goto FIND_WORD_0;                   /* continue searching */
  490.   } else goto FIND_WORD_NEXTWORD;       /* keep looking for end of word */
  491. FIND_WORD_FOUND:
  492.   // dummy is holding EOW flags
  493.   eow_flags=dummy;
  494.   if(eow_flags & DICT_NONROOT) tvg_flags |= NR_FLAG;
  495.   if(eow_flags & DICT_GRCHECK) tvg_flags |= TEMP_GC;
  496.   if(eow_flags & DICT_PLURALS) tvg_flags &= ~DUMMY_FLAG;
  497.   tvg_flags |= WORD_FOUND;
  498.   // read cuss word tolerance
  499.   get_ee_char();
  500.   word_toler = w;
  501.   // read replacement word index
  502.   get_ee_char();
  503.   replace_index = w;
  504.                                         /**** WORD FOUND ****/
  505.                                         /* (1) CHECK IF AT END OF A NON-ROOT */
  506.   if(!(tvg_flags & NR_FLAG)) goto FIND_WORD_FOUND_0; /* Cuss Word Found */
  507.                                         /* else, Non-Root Cuss Word found */
  508.   tvg_flags &= ~NR_FLAG;             /* CLEAR "NON-ROOT CUSS WORD" FLAG */
  509.   w=*fsr;                               /* next cc char -> w */
  510.   if(chk_if_letter()) {
  511.     replace_index=0xff;            /* "no words found" -> replace_index */
  512.     goto FIND_WORD_FOUND_1;             /*(skip replacement word assignment)*/
  513.   }
  514. FIND_WORD_FOUND_0:
  515.   // This isn't needed any more with version 2 dictionary
  516.   // replace_index=dummy;             /* (2) store replacement index */
  517. FIND_WORD_FOUND_1:
  518.   next_ccbuff_char();                   /* (3) next letter of CC word */
  519.                                         /* (4) continue searching */
  520.   find_word_nextltr();                  /* next dictionary letter -> dummy */
  521.   word_length=counter;                  /* (5) save cussword length */
  522.                                         /* (6) save plural and grammar flags */
  523.   if(tvg_flags & DUMMY_FLAG) tvg_flags |= PLURAL;
  524.   else tvg_flags &= ~PLURAL;         /* save plural flag */
  525.   if(tvg_flags & TEMP_GC) tvg_flags |= GCHK_FLAG;
  526.   else tvg_flags &= ~GCHK_FLAG;      /* save grammar chk flag */
  527.   goto FIND_WORD_0;                     /* continue looking */
  528. FIND_WORD_DONE:                         /**** DONE SEARCHING ****/
  529.   if(eow_flags & DICT_WATCHWD)          /* indicate WORD FOUND... */
  530.     goto FIND_WORD_DONE_0;              /* ...if word isn't watch word */
  531. // Blocking Logic
  532. // WAS:
  533. //  if(io_map & TVG_STRICT)
  534. //    goto FIND_WORD_DONE_0;              /* ...if in STRICT mode */
  535. //  if(!(replace_index & BIT_TLRNT))
  536. //    goto FIND_WORD_DONE_0;              /* ...if not TOLERANT mode */
  537.   if( word_toler & iomap2 )
  538.     goto FIND_WORD_DONE_0;              /* check for blocking or not... */
  539.     
  540.   return 1;                             /* return 1 = no cussword found */
  541. FIND_WORD_DONE_0:
  542.   w=replace_index+1;               /* check replacement index */
  543.   if(w==0) return 1;                    /* return 1 if no cussword found */
  544.   else     return 0;                    /* return 0 if cussword found */
  545. }
  546. void find_word_nextltr( void ) {
  547.   get_ee_char_next();             /* NEXT DICTIONARY LETTER --> DUMMY */
  548.   dummy=w;
  549.   return;
  550. }
  551. /******************************************************************************
  552. ;* FUNCTION:    GET_EE_CHAR
  553. ;* DESC:        READ CHAR FROM EEPROM
  554. ;* INPUT:       OUT_BUFFER, OUT_BUFFER2 = EEPROM ADDRESS TO READ, (L,H)
  555. **              ^^^^^^^^^^  ^^^^^^^^^^^
  556. **     really:  ee_add_lo   ee_add_hi   ?????
  557. ;* OUTPUT:      W = BYTE READ
  558. **       also:  IN_BUFFER holds the character read
  559. ;* NOTE:        SEQUENTIAL READS POSSIBLE BY CALLING GET_EE_CHAR_NEXT
  560. ;*              BUT MUST BE DONE WHILE SPI_SEL HELD LOW
  561. *  In this C-Language simulation, the EEPROM data is in a large 2K array - no
  562. *  need to manipulate clock and data lines to fetch a data byte - just index
  563. *  into the array.  NOTE: Because of this, there is no difference between the
  564. *  functions get_ee_char and get_ee_char_next.
  565. */
  566. void get_ee_char( void ) {
  567.   w=tvg_dict[ee_addr];           /* fetch word, store into */
  568.   ee_addr++;                            /* increment address      */
  569.   return;
  570. }
  571. void get_ee_char_next( void ) {
  572.   w=tvg_dict[ee_addr];           /* fetch word, store into */
  573.   ee_addr++;                            /* increment address      */
  574.   return;
  575. }
  576. // This function for version 2 dictionary, fetches two-byte address from
  577. // the indicated offset, and re-loads the ee_addr variable.
  578. // Assume that section offsets are stored in the little-endian Intel
  579. // format.  This is safe assumption on any machine, because we dictate
  580. // how dictionary is generated and stored.
  581. void get_ee_addr( void ) {      
  582.   w=tvg_dict[ee_addr];
  583.   ee_addr++;
  584.   dummy=tvg_dict[ee_addr];
  585.   ee_addr = w + (dummy << 8);
  586. }
  587. /******************************************************************************
  588. ;* FUNCTION:    CHK_GRAMMAR
  589. ;* DESC:        CHECK SPECIAL WORD/GRAMMAR SITUATIONS
  590. ;* NOTES:       BASIC RULE: DID WATCH WORD PRECEDE WORD?
  591. ;*              YES -->
  592. */
  593. void chk_grammar( void ) {
  594.   if(tvg_flags & DW_0) return;  /* was prev word a watch word? */
  595.   if(tvg_flags & DW_1) return;  /* was two words ago a watch word? */
  596.   replace_index=0xff;      /* return "no words found" */
  597.   return;
  598. }
  599. /* FUNCTION:    CUSSWORDLEN
  600.  * DESC:        GET LENGTH OF WORD/PHRASE
  601. */
  602. void cussword_len( void ) {
  603.   uchar i;
  604.   counter=word_length;
  605.   cc_buffer_pos=start_of_word;
  606.   fsr=cc_buffer+cc_buffer_pos;          /* point to start of word */
  607. CUSSWORD_LEN_0:
  608.   do {
  609.     next_ccbuff_pos();                  /* next buffer posn */
  610.   } while( --counter > 0 );
  611. CUSSWORD_LEN_1:                         /* advance over any add'l letters */
  612.   chk_case();                           /* CONVERT LOWERCASE CHARS IF NECESSARY */
  613.   last_char=w;                          /* save char -> last char */
  614.   if(!chk_if_letter()) return;          /* return w/len if not letter */
  615.   // last_char=w;                          /* save char -> last char */
  616.   word_length++;                        /* incr word lenght */
  617.   next_ccbuff_pos();                    /* next buffer position */
  618.   goto CUSSWORD_LEN_1;
  619. }
  620. /******************************************************************************
  621. ;* FUNCTION:    CHK_PLURAL
  622. ;* DESC:        CHECK FOR PLURAL WORDS
  623. */
  624. void chk_plural( void ) {
  625.   if(!(tvg_flags & PLURAL)) return;
  626.   if(last_char=='S') word_length--;     /* adjust word length if plural */
  627.   return;
  628. }
  629. /******************************************************************************
  630. ;* FUNCTION:    NEXT_CCBUFF_POS
  631. ;* DESC:        MOVE TO THE NEXT CC_BUFFER POSITION
  632. ;* OUTPUTS:     CC_BUFFER_POS, FSR
  633. */
  634. void next_ccbuff_pos( void ) {
  635.   cc_buffer_pos++;                      /* increment buffer pointer */
  636.   cc_buffer_pos %= CC_BUFFER_LEN;       /* handle buffer rollover */
  637.   fsr=cc_buffer + cc_buffer_pos;
  638. }
  639. /******************************************************************************
  640. ;* FUNCTION:    NEXT_CCBUFF_CHAR
  641. ;* DESC:        MOVE TO THE NEXT CC_BUFFER CHAR
  642. ;* OUTPUT:      ZERO FLAG: 0=CHARS LEFT TO CHECK,1=NO MORE CHARS
  643. ;*
  644. * NOTE: Return value appears to be ignored everywhere, so it has been omitted
  645. */
  646. void next_ccbuff_char( void ) {
  647.   uchar zeroflag;
  648. NEXT_CCBUFF_CHAR:
  649.   zeroflag=0;
  650.   fsr++;
  651.   if( (fsr-cc_buffer) >= CC_BUFFER_LEN) {
  652.     fsr=cc_buffer;
  653.     zeroflag=1;
  654.   }
  655.   return;
  656. }
  657. void cussword_right( void ) {
  658. CUSSWORD_RIGHT:                         /**** MOVE BUFFER POINTER RIGHT ****/
  659.                                         /* (INPUT: W = # POSITIONS TO MOVE) */
  660.                                         /* (OUTPUT: W = NEW POSITION) */
  661.   counter += w;                         /* incr counter */
  662.   counter%=CC_BUFFER_LEN;               /* handle rollover */
  663.   w=counter;
  664.   return;
  665. }
  666. void cussword_left( void ) {
  667. CUSSWORD_LEFT:                          /**** MOVE BUFFER POINTER LEFT ****/
  668.                                         /* (INPUT: W = # POSITIONS TO MOVE) */
  669.                                         /* (OUTPUT: W = NEW POSITION) */
  670. #if 0
  671.   counter -= w;                         /* decr counter */
  672.   if((char)counter<0) counter += CC_BUFFER_LEN; /* adj for past start of buffer */
  673.   w=counter;
  674. #endif
  675.   scounter = (char)counter - w;                         /* decr counter */
  676.   if(scounter<0) scounter += CC_BUFFER_LEN; /* adj for past start of buffer */
  677.   w=(uchar)scounter;
  678.   counter=w;
  679.   return;
  680. }
  681. void cussword_watch( void ) {
  682. CUSSWORD_WATCH:                         /**** PROCESS WATCH WORDS IF ANY ****/
  683.   if(tvg_flags & DW_0) tvg_flags |= DW_1;
  684.   else tvg_flags &= ~DW_1;           /* shift last word to 2-words ago flag */
  685.   tvg_flags &= ~DW_0;          /* assume new word isn't a D/W watch word */
  686.   if(replace_index==0xff) return;  /* return if no replacement word */
  687.   if(!(eow_flags & DICT_WATCHWD)) return;  /* return if not watch word */
  688.   if(!(eow_flags & DICT_USAGEWW)) return;  /* return if not D/W watch word */
  689.   tvg_flags |= DW_0;                 /* flag that new word is D/W watch */
  690.   return;
  691. }
  692. /******************************************************************************
  693. ;* FUNCTION:    SEND2CHARS
  694. ;* DESC:        SEND OLDEST 2 CLOSED CAPTION CHARS TO OSD
  695. ;
  696. */
  697. // For DVD Project, we are going to implement a FIFO buffer into which the
  698. // character pairs are placed.  They will ordinarily be immediately
  699. // removed from the buffer for transmission.  In the case of a substitute
  700. // niceword which is longer than the cussword, this buffer will be filled
  701. // briefly with more than one pair of characters.
  702. void send2chars( void ) {
  703.   // if we are "marking time", i.e., sending a pair of NULLs, and there
  704.   // are already some character pairs in the transmit fifo, dont bother
  705.   // to send the NULLs.
  706.  
  707.   fsr=cc_buffer + cc_buffer_out;
  708.   if( (fsr[0]==0) && (fsr[1]==0) && (iccfifo!=occfifo) ) {
  709.     cc_buffer_out += 2;
  710.     cc_buffer_out %= CC_BUFFER_LEN;
  711.   } else {
  712.     r0=fsr[0];
  713.     r1=fsr[1];
  714.     if(timer_tvg==0) process_cc();
  715.     ccfifo[iccfifo++]=fsr[0];
  716.     ccfifo[iccfifo++]=fsr[1];
  717.     iccfifo %= CCMAXFIFO;  //FIFO even size, can only rollover here
  718.     cc_buffer_out += 2;
  719.     cc_buffer_out %= CC_BUFFER_LEN;
  720.   }
  721.   return;
  722. }
  723. // this routine used to insert two spaces into the outgoing
  724. // FIFO.  Doesn't adjust CC_BUFFER pointers
  725. void insert2spaces( void ) {
  726.   ccfifo[iccfifo++]=0x11; // transparent space
  727.   ccfifo[iccfifo++]=0x39;
  728.   iccfifo %= CCMAXFIFO;  //FIFO even size, can only rollover here
  729.   ccfifo[iccfifo++]=0x11; // transparent space
  730.   ccfifo[iccfifo++]=0x39;
  731.   iccfifo %= CCMAXFIFO;  //FIFO even size, can only rollover here
  732.   return;
  733. }
  734. // for DVD implementation, we only call PROCCC() in order to enable and
  735. // disable various mode flags, which will be set/cleared depending on
  736. // the control codes in the CC data stream.  In the stand-alone TVG unit,
  737. // this function also sent commands to the OSD chip.
  738. /******************************************************************************
  739. ;* FUNCTION:    PROCESS_CC
  740. ;* DESC:        TRANSLATE CLOSED CAPTION DATA AND DISPLAY VIA OSD
  741. ;* INPUT:       R0,R1 : CC CHAR PAIR
  742. ;*/
  743. void process_cc( void ) {
  744. PROCESS_CC:
  745. // (1) CHECK IF IN POP-ON STYLE CC
  746. // BRANCH IF CC MODE IS NOT ACTIVE
  747. // ELSE, PROCESS CC CHARS
  748.   if(tvg_flags & CC_ACTIVE) goto PROCESS_CC_0;
  749. // (2) WAIT FOR POP-ON CMD
  750. // CHECK FOR MISC PAC CMD
  751. // BRANCH IF MISC PAC CMD FOUND
  752. //  ELSE, NOTHING TO DO -- RETURN
  753.   if(r0!=CCCMD_MISC) goto PROCESS_CC_RET;
  754.   else               goto PROCESS_CC_MISC;      // GOTO PROCESS PAC COMMAND
  755. PROCESS_CC_0:
  756.   if(r0<0x10)  goto PROCESS_CC_CHAR;  // (4) CHECK IF CC CHARS ARE CTRL CODES
  757.   if(r0>0x17)  goto PROCESS_CC_CHAR;  // 0x10 <= c1 <=0x17
  758.   if((prev_c1==r0)&&(prev_c2==r1))    // (5) CHECK FOR REDUNDANT CTRL CODES
  759.     goto  PROCESS_CC_RET;             // ELSE, SKIP REDUNDANT CTRL CODES
  760. PROCESS_CC_1:                         // (6) CHECK FOR PAC CODES
  761.   if(r1<0x40) goto PROCESS_CC_CMDS;   // ELSE, PROBABLY MISC CTRL CODE
  762.                                       // (7) "NO WIERD CHARS TILL 1ST LETTER"
  763.   tvg_flags |= NO_LETTERS;            // FLAG TO SEND NOTHING TILL 1ST LETTER
  764.   tvg_flags |= IN_POPON;              // (8) DO IMPLIED POP-ON STUFF
  765.                                          // FLAG THAT WE RE IN A POP-ON CC
  766.   errors_cc=0;                           // RESET CC ERRORS COUNTER
  767.   // Old TVG code actually processed these codes, to determine what had
  768.   // to be sent to the OSD chip for proper formatting of the text -
  769.   // things like indention, italics, underline, etc.  In the DVD appl,
  770.   // we only need to note the occurence of certain key control codes
  771.   // so we can go into/leave TVG operation as a function of POPUP
  772.   // closed captioning mode.  Further simplification would be possible
  773.   // if we assumed that only POPUP style CC would be found on a DVD.
  774.     // (9) SET OSD ROW
  775.     // PAC command, row obtained from it
  776.     //  ANDLW   0FH                     ;MASK FOR LOWER BYTE
  777.     //  MOVWF   TABLE_INDEX             ;W --> TABLE_INDEX
  778.     //  CALL    CC_ROW                  ;RETREIVE BASE ROW FROM (PAC:1 LOW NIBBLE)
  779.     //  BTFSC   R1,5                    ;BRANCH IF BIT 5 OF PAC:2 IS NOT SET
  780.     //  ADDLW   1                       ; ELSE, ROW ++
  781.     //  CALL    PUT_TO_OSD
  782.     //                                  ;(10) CHECK TO SET UNDERLINE MODE
  783.     //  BTFSC   R1,0                    ;BRANCH IF BIT 0 OF PAC:2 IS NOT SET
  784.     //  CALL    PROCESS_CC_UNDLN        ; ELSE, GOTO UNDERLINE
  785.     // Note: Original code CALLed UNDERLINE function - since it was
  786.     // only invoked from one place, it has been moved to here and simply
  787.     // enclosed in an IF block.  But since no action associated with the
  788.     // DVD player takes place, the whole thing is commented out.
  789.     //
  790.     // (10) CHECK TO SET UNDERLINE MODE
  791. //  if(r1 & 0x01) {
  792. PROCESS_CC_UNDLN:                       // *** SET OSD UNDERLINE ***
  793.     //  MOVLW   OSDCMD_WRCHR            ;OSD WRITE CHARACTER MODE
  794.     //  CALL    PUT_TO_OSD
  795.     //  MOVLW   OSDCHAR_UNDLN           ;OSD SET UNDERLINE MODE
  796.     //  CALL    PUT_TO_OSD
  797.     //  RETURN                          ;RETURN
  798. //  }
  799.     //                                  ;(11) CHECK TO INDENT CURSOR
  800.     //  BTFSC   R1,4                    ;BRANCH IF BIT 4 OF PAC:2 IS NOT SET
  801.     //  GOTO    PROCESS_CC_INDENT       ; ELSE, GOTO INDENT
  802.   if(r1 & 0x10) goto PROCESS_CC_INDENT;
  803.     //                                  ;(12) CHECK TO SET ITALICS MODE
  804.     //                                  ; (INTALICS PAC2 = 4EH OR 6EH)
  805.     //  MOVF    R1,W                    ;2ND CC CHAR --> W
  806.     //  ANDLW   11011110B               ;MASK FOR BITS 7,6,4,3,2,1
  807.     //  SUBLW   CCCMD_ITALIC            ;CHECK IF PAC:2 = ITALICS
  808.     //  BTFSS   STATUS,Z                ;BRANCH IF PAC:2 = ITALICS
  809.     //  GOTO    PROCESS_CC_RET          ; ELSE, NOTHING MORE TO DO
  810.   if( (r1 & 0xde) != CCCMD_ITALIC )
  811.       goto PROCESS_CC_RET;
  812. PROCESS_CC_ITALICS:                     // (13) SET OSD ITALICS
  813.     //  MOVLW   OSDCMD_WRCHR            ;OSD WRITE CHARACTER MODE
  814.     //  CALL    PUT_TO_OSD
  815.     //  MOVF    R1,W                    ;2ND CC CHAR --> W
  816.     //  ANDLW   0FH                     ;MASK FOR LOWER 4 BITS
  817.     //  CALL    PUT_TO_OSD              ;ITALICS OR UNDRLN+ITALICS --> OSD
  818.     //  GOTO    PROCESS_CC_RET          ;RETURN TO TOP OF PROCESS_CC LOOP
  819.   goto PROCESS_CC_RET;
  820. PROCESS_CC_CHAR:                        // *** SEND CC CHAR TO OSD ***
  821. // BRANCH IF WITHIN A POP-ON CC
  822. // ELSE, DON T ALLOW ANY OUTPUT
  823. //
  824.   if(!(tvg_flags & IN_POPON)) goto PROCESS_CC_RET;
  825. //ACTUALLY SEND CHAR OUT HERE
  826. // Check need to insert extra spaces
  827. #ifdef INDADJ
  828.   if(r0 || r1) { // only check if not pair of nulls
  829.     if(tvg_flags & INDENT_ADJ) {
  830.       insert2spaces();
  831.       tvg_flags &= ~INDENT_ADJ;
  832.     }
  833.   }
  834. #endif
  835.   if(r0) {
  836.     w=r0;
  837.     chk_cc_char();
  838.     if(w!=dummy) {
  839.       r0=dummy;
  840.       fsr[0]=dummy;
  841.     }
  842.   }
  843.   if(r1) {
  844.     w=r1;
  845.     chk_cc_char();
  846.     if(w!=dummy) {
  847.       r1=dummy;
  848.       fsr[1]=dummy;
  849.     }
  850.   }
  851.   goto  PROCESS_CC_RET;         // RETURN TO TOP OF PROCESS_CC LOOP
  852. // Here again were many special sections in the original TVG code that
  853. // allowed the software to control the formatting of the OSD - not needed
  854. // for the DVD program, but for some mode control commands.
  855. //
  856. PROCESS_CC_INDENT:                      // *** INDENT CURSOR ***
  857.     //                                  ;(CODE REWORK - 2/28/98 JMW)
  858.     //  MOVLW   OSDCMD_SETCOL           ;OSD SET COLUMN MODE
  859.     //  CALL    PUT_TO_OSD
  860.     //  RLF     R1,W                    ;MULTIPLY PAC:2 BY 2 --> W
  861.     //  ANDLW   1CH                     ;MASK FOR FOR VALID BITS OF W
  862.     //  ADDLW   1                       ;ADD IN LEADING SPACE FOR COLUMN 0
  863.     //  CALL    PUT_TO_OSD              ;SEND COLUMN TO OSD
  864.     //  GOTO    PROCESS_CC_RET          ;RETURN TO TOP  OF PROCESS_CC LOOP
  865. #ifdef INDADJ
  866.   tvg_flags &= ~INDENT_ADJ;
  867.   if((r1 & 0x0E)==0) goto PROCESS_CC_RET; // do not process if indent 0
  868.   tvg_flags |= INDENT_ADJ;
  869.   fsr[1] = r1 - 2;                  // Adjust indent to be one stop back
  870. #endif
  871.   // For Zoran/Sanyo Jan 2002 Release, only adjust indent back by 1 tab
  872.   // stop (4 spaces).  Memory problem associated with subsequent insertion
  873.   // of two transparent spaces.
  874.   if((r1 & 0x0E)==0) goto PROCESS_CC_RET; // do not process if indent 0
  875.   fsr[1] = r1 - 2;              // Adjust indent to be one stop back
  876.   goto  PROCESS_CC_RET;         // RETURN TO TOP OF PROCESS_CC LOOP
  877. PROCESS_CC_CMDS:                        // *** PROCESS MISC CTRL CODES ***
  878.     //  MOVF    R0,W                    ;1ST CC CHAR --> W
  879.     //  SUBLW   017H                    ;CHECK FOR TAB OFFSET CODE
  880.     //  BTFSS   STATUS,Z                ;BRANCH IF TAB OFFSET CODE
  881.     //  GOTO    PROCESS_CC_CMDS_1       ; ELSE, CHECK FOR OTHER CODES
  882.   if(r0!=0x17) goto PROCESS_CC_CMDS_1;
  883.     //                                  ;< PROCESS TABS >
  884.     //  MOVLW   020H                    ;20H --> W
  885.     //  SUBWF   R1,ITSELF               ;PAC:2 - 20H --> R1
  886.     //  BTFSC   STATUS,Z                ;BRANCH IF #TABS != 0
  887.     //  GOTO    PROCESS_CC_RET          ; ELSE, SKIP BECAUSE INVALID
  888.     //  BTFSS   STATUS,C                ;BRANCH IF #TABS > 0
  889.     //  GOTO    PROCESS_CC_RET          ; ELSE, SKIP BECAUSE INVALID
  890.   if( r1 <= 0x20 ) goto PROCESS_CC_RET;
  891. PROCESS_CC_CMDS_0:
  892.     //  MOVLW   OSDCMD_WRCHR            // OSD WRITE CHARACTER MODE
  893.     //  CALL    PUT_TO_OSD
  894.     //  MOVLW   0B8H                    ;OSD TRANSPARENT SPACE --> W
  895.     //  CALL    PUT_TO_OSD
  896.     //  DECFSZ  R1,ITSELF               ;TABS --, BRANCH IF DONE
  897.     //  GOTO    PROCESS_CC_CMDS_0       ; ELSE, KEEP TABBING
  898.     //  GOTO    PROCESS_CC_RET          ;RETURN TO TOP OF PROCESS_CC LOOP
  899.   goto PROCESS_CC_RET;
  900. PROCESS_CC_CMDS_1:                      // CHECK FOR OTHER CTRL CODES
  901.     //  MOVF    R0,W                    ;1ST CC CHAR --> W
  902.     //  SUBLW   014H                    ;CHECK FOR MISC CTRL CODE
  903.     //  BTFSC   STATUS,Z                ;BRANCH IF NOT MISC CTRL CODE
  904.     //  GOTO    PROCESS_CC_MISC         ; ELSE, PROCESS MISC CTRL CODE
  905.   if(r0==0x14) goto PROCESS_CC_MISC;
  906.     //                                  ;*** CHECK FOR SPECIAL CHARACTERS ***
  907.     //                                  ; ** AND MID-ROW CODES            **
  908.     //  MOVF    R0,W                    ;1ST CC CHAR --> W
  909.     //  SUBLW   011H                    ;CHECK FOR SPECIAL CHARS/MID-ROW CODES
  910.     //  BTFSS   STATUS,Z                ;BRANCH IF SPECIAL CHAR OR MID-ROW...
  911.     //  GOTO    PROCESS_CC_RET          ; ELSE, CODE UNRECOGNIZED - SKIP IT
  912.   if(r0!=0x11) goto PROCESS_CC_RET;
  913.     //                                  ;(1) CHECK IF TRANSPARENT SPACE CODE
  914.     //  MOVF    R1,W                    ;2ND CC CHAR --> W
  915.     //  SUBLW   039H                    ;CHECK FOR TRANSPARENT SPACE CHAR
  916.     //  BTFSS   STATUS,Z                ;BRANCH IF TRANSPARENT SPACE CHAR
  917.     //  GOTO    PROCESS_CC_CMDS_2       ; ELSE, CHECK IF SPECIAL CHAR
  918.   if(r1!=0x39) goto PROCESS_CC_CMDS_2;
  919.     //  MOVLW   1                       ;1 --> R1 (1 TRANS. SPACE)
  920.     //  MOVWF   R1
  921.     //  GOTO    PROCESS_CC_CMDS_0       ;SEND ONE TRANSPARENT CHAR
  922.   goto  PROCESS_CC_CMDS_0;
  923. PROCESS_CC_CMDS_2:                      // (2) CHECK IF SPECIAL CHAR
  924.     //  MOVLW   30H                     ;30H --> W
  925.     //  SUBWF   R1,W                    ;2ND CC CHAR - 30H --> W
  926.     //  BTFSS   STATUS,C                ;BRANCH IF SPECIAL CHAR
  927.     //  GOTO    PROCESS_CC_ITALICS      ; ELSE, ASSUME MID-ROW CODE (ITALICS)
  928.   if(r1!=0x30) goto PROCESS_CC_ITALICS;
  929.     //                                  ;(3) PROCESS SPECIAL CHARACTERS
  930.     //  MOVLW   OSDCMD_WRCHR            ;OSD WRITE CHARACTER MODE
  931.     //  CALL    PUT_TO_OSD
  932.     //  MOVF    R1,W                    ;2ND CC CHAR --> W
  933.     //  ANDLW   0FH                     ;MASK FOR LOWER NIBBLE OF W
  934.     //  ADDLW   10H                     ;W += 20H (CHAR MUST BE: >20H,<2FH)
  935.     //  CALL    PUT_TO_OSD              ;SPECIAL CHAR --> OSD
  936.     //  GOTO    PROCESS_CC_RET          ;NEXT CHARS
  937.   goto PROCESS_CC_RET;
  938. PROCESS_CC_MISC:                        // *** PROCESS MISC CTRL CODES ***
  939.     //  MOVLW   CCCMD_POPON             ;CHECK IF 2ND CC CHAR >= POPON CMD
  940.     //  SUBWF   R1,W                    ;2ND CC CHAR - POPON --> W
  941.     //  BTFSS   STATUS,C                ;BRANCH IF CC CHAR >= POPON CMD
  942.     //  GOTO    PROCESS_CC_RET          ; ELSE, DON'T RECOGNIZE CMD, DON'T USE
  943.   if(r1 < CCCMD_POPON) goto PROCESS_CC_RET;
  944.     //  MOVF    R1,W                    ;2ND CC CHAR --> W
  945.     //  SUBLW   CCCMD_EOC               ;CHECK IF 2ND CC CHAR <= POPOFF CMD
  946.     //  BTFSS   STATUS,C                ;BRANCH IF CC CHAR <= POPOFF CMD
  947.     //  GOTO    PROCESS_CC_RET          ; ELSE, DON'T RECOGNIZE CMD, DON'T USE
  948.     //  GOTO    PROCESS_CC_JUMP         ;GO PROCESS CONTROL CHARACTER VIA
  949.     //                                  ;A GOTO TABLE
  950.     //                                  ;NOTE:
  951.   if(r1 <= CCCMD_EOC) goto PROCESS_CC_JUMP;
  952.   goto PROCESS_CC_RET;
  953. PROCESS_CC_POPON:                       // *** PROCESS "POPON" MODE ***
  954.   tvg_flags &= ~CMD_SUBST;  // Always clear Command Substitute flag upon 
  955.                             // receipt of POPON command
  956. #ifdef INDADJ                            
  957.   tvg_flags &= ~INDENT_ADJ;  // Always clear Indent Adjust flag upon
  958.                             // receipt of POPON command
  959. #endif
  960.     //                                  ;(1) CHECK IF POP-ON CC STYLE ACTIVE
  961.     //  BTFSC   PRG_STATUS_2,CC_ACTIVE  ;BRANCH IF POP-ON NOT ALREADY ACTIVE
  962.     //  GOTO    PROCESS_CC_POPON_0      ; ELSE, GOTO RETURN
  963.   if(tvg_flags & CC_ACTIVE) goto PROCESS_CC_POPON_0;
  964.     //  BSF     PRG_STATUS_2,CC_ACTIVE  ;(2) FLAG THAT POP-ON STYLE ACTIVE
  965.   tvg_flags |= CC_ACTIVE;
  966.     //                                  ;(3) DISPLAY "TVG"
  967.     //  MOVLW   TVG-VER                 ;LOCATION OF "TVG" --> W
  968.     //  CALL    SHOW_TVG_BUG            ;DISPLAY "TVG"
  969.   show_tvg_bug(BUG_TVG);
  970.     //  CALL    CHECK_TO_UNMUTE         ;(4) CHECK TO UNMUTE AUDIO
  971.   check_to_unmute();
  972. PROCESS_CC_POPON_0:
  973.     //  BSF     PRG_STATUS_5,IN_POPON   ;(5) FLAG THAT WE RE IN A POP-ON CC
  974.   tvg_flags |= IN_POPON;
  975.     //  CLRF    ERRORS_CC               ;(6) RESET CC ERRORS COUNTER
  976.   errors_cc=0;
  977.     //  GOTO    PROCESS_CC_RET          ;RETURN
  978.   goto PROCESS_CC_RET;
  979. PROCESS_CC_RDC:                         // *** PROCESS PAINT-ON CAPTIONS ***
  980.                                         //  ** RDC --> PAINT-ON COMMAND  **
  981. PROCESS_CC_RU2:                         // *** SEND "RU2" COMMAND TO OSD ***
  982. PROCESS_CC_RU3:                         // *** SEND "RU3" COMMAND TO OSD ***
  983. PROCESS_CC_RU4:                         // *** SEND "RU4" COMMAND TO OSD ***
  984. PROCESS_CC_ROLLUP:                      // *** PROCESS ROLLUP CAPTIONS ***
  985.     //  BCF     PRG_STATUS_5,IN_POPON   ;(1) FLAG "NOT IN A POP-ON CC"
  986.     //  MOVLW   OSDCMD_OEDM             ;(2) ERASE DISPLAYED MEMORY
  987.     //  CALL    PUT_TO_OSD
  988.   tvg_flags &= ~IN_POPON;
  989.     //                                  ;(3) CHECK IS CHANGING FROM POP-ON
  990.     //  BTFSC   PRG_STATUS_2,CC_ACTIVE  ;BRANCH IF NOT IN POP-ON STYLE CC
  991.     //  GOTO    PROCESS_CC_ROLLUP_0     ; ELSE, SHOW "NO TVG"
  992.   if(tvg_flags & CC_ACTIVE) goto PROCESS_CC_ROLLUP_0;
  993.     //                                  ;(4) CHECK IF ALREADY KNOW "NO TVG"
  994.     //  BTFSC   PRG_STATUS_4,TVG_STATUS ;BRANCH IF TVG STATUS IS UNKNOWN
  995.     //  GOTO    PROCESS_CC_ROLLUP_RET   ; ELSE, GOTO RETURN
  996.   if(tvg_flags & TVG_STATUS) goto PROCESS_CC_ROLLUP_RET;
  997. PROCESS_CC_ROLLUP_0:                    // (5) DISPLAY "NO TVG"
  998.     //  MOVLW   NOTVG-VER               ;LOCATION OF "NO TVG" --> W
  999.     //  CALL    SHOW_TVG_BUG            ;DISPLAY "NO TVG"
  1000.   show_tvg_bug(BUG_NOTVG);
  1001. PROCESS_CC_ROLLUP_RET:
  1002.     //  BCF     PRG_STATUS_2,CC_ACTIVE  ;(6) DISABLE POP-ON CAPTIONS
  1003.     //  CALL    CHECK_TO_UNMUTE         ;(7) CHECK TO UNMUTE AUDIO
  1004.     //  GOTO    PROCESS_CC_RET          ;(8) GOTO RETURN
  1005.   tvg_flags &= ~CC_ACTIVE;
  1006.   check_to_unmute();
  1007.   goto PROCESS_CC_RET;
  1008. PROCESS_CC_EDM:                         // *** SEND "EDM" COMMAND TO OSD ***
  1009.     //  BTFSS   PRG_STATUS_2,CUSSING    ;BRANCH IF CUSSING DETECTED
  1010.     //  CALL    CHECK_TO_UNMUTE         ;CHECK TO UNMUTE AUDIO
  1011.     //  MOVLW   OSDCMD_OEDM             ;ERASE DISPLAYED MEMORY
  1012.     //  CALL    PUT_TO_OSD
  1013.     //  GOTO    PROCESS_CC_RET          ;GOTO RETURN
  1014.   if(!(tvg_flags & CUSSING)) check_to_unmute();
  1015.   goto PROCESS_CC_RET;
  1016. PROCESS_CC_CR:                          // *** SEND "CR" COMMAND TO OSD ***
  1017.     //  MOVLW   OSDCMD_CR               ;SEND CARRIAGE RETURN TO OSD
  1018.     //  CALL    PUT_TO_OSD
  1019.     //  GOTO    PROCESS_CC_RET          ;GOTO RETURN
  1020.   goto PROCESS_CC_RET;
  1021. PROCESS_CC_ENM:                         // *** SEND "ENM" COMMAND TO OSD ***
  1022.     //  MOVLW   OSDCMD_OENM             ;ERASE NON-DISPLAYED MEMORY
  1023.     //  CALL    PUT_TO_OSD
  1024.     //  GOTO    PROCESS_CC_RET          ;GOTO RETURN
  1025.   goto PROCESS_CC_RET;
  1026. PROCESS_CC_POPOFF:                      // *** SEND "POPOFF" COMMAND TO OSD ***
  1027.   // aaa=10; while(aaa) VCX_service();
  1028.     //  BTFSS   PRG_STATUS_2,CC_ACTIVE  ;(1) BRANCH IF POP-ON STYLE ACTIVE
  1029.     //  GOTO    PROCESS_CC_POPON        ; ELSE, PROCESS "IMPLIED POPON"
  1030. #ifdef INDADJ
  1031.   tvg_flags &= ~INDENT_ADJ;  // Always clear Indent Adjust flag upon
  1032.                             // receipt of POPOFF command
  1033. #endif
  1034.  
  1035.   if(!(tvg_flags & CC_ACTIVE)) goto PROCESS_CC_POPON;
  1036.   if(tvg_flags & CMD_SUBST) {
  1037.     fsr[0]=CCCMD_MISC;           // replace POPOFF with Erase
  1038.     fsr[1]=CCCMD_ENM;            // non-displayed memory command
  1039.     tvg_flags &= ~CMD_SUBST;
  1040.   }
  1041.     //                                  ;(2) CHECK IF WITHIN A POP-ON CC
  1042.     //  BTFSS   PRG_STATUS_5,IN_POPON   ;BRANCH IF WITHIN A POP-ON CC
  1043.     //  GOTO    PROCESS_CC_RET          ; ELSE, GOTO RETURN (MAY BE REDUNDANT)
  1044.   if(!(tvg_flags & IN_POPON)) goto PROCESS_CC_RET;
  1045.     //  GOTO    CLOSE_POPON             ;(3) CHECK TO END POP-ON CC
  1046.   goto CLOSE_POPON;
  1047. PROCESS_CC_POPOFF_0:
  1048.     //  BCF     PRG_STATUS_5,IN_POPON   ;FLAG THAT WE RE NOT IN A POP-ON CC
  1049.     //  MOVLW   OSDCMD_FLIP             ;EXIT OSD POPSET MODE (FLIP TO OSD)
  1050.     //  CALL    PUT_TO_OSD
  1051.     //  GOTO    PROCESS_CC_RET          ;GOTO RETURN
  1052.   tvg_flags &= ~IN_POPON;
  1053.   goto PROCESS_CC_RET;
  1054. PROCESS_CC_BKSP:                        // *** SEND "BKSP" COMMAND TO OSD ***
  1055. PROCESS_CC_DER:                         // *** SEND "DER" COMMAND TO OSD ***
  1056. PROCESS_CC_FON:                         // *** SEND "FON" COMMAND TO OSD ***
  1057. PROCESS_CC_TR:                          // *** SEND "TR" COMMAND TO OSD ***
  1058. PROCESS_CC_RTD:                         // *** SEND "RTD" COMMAND TO OSD ***
  1059.     //  GOTO    PROCESS_CC_RET          ;NOT IMPLEMENTED FOR NOW
  1060.   goto PROCESS_CC_RET;
  1061. PROCESS_CC_RET:                         // *** RETURN FROM PROCESS_CC ***
  1062.     //  MOVF    R0,W                    ;SAVE LAST TWO CC CHARS
  1063.     //  MOVWF   PREV_C1
  1064.     //  MOVF    R1,W
  1065.     //  MOVWF   PREV_C2
  1066.   prev_c1=fsr[0];   // use fsr[] so that we will properly replace
  1067.   prev_c2=fsr[1];   // the two sequential POPOFF commmands in CC-CUSS mode
  1068.     //  RETURN
  1069.   return;
  1070. //******************************************************************************
  1071. //* FUNCTION:   CLOSE_POPON
  1072. //* DESC:       CLOSE POP-ON CAPTIONS INCLUDING:
  1073. //*             1) CHECK TO UNMUTE AUDIO BASED ON MUTE TIMER
  1074. //*             2) CHECK TO ERASE NON-DISPLAYED MEMORY IF CAPTIONS NOT
  1075. //*                TO BE DISPLAYED (INCLUDING TOO MANY CC ERRORS)
  1076. CLOSE_POPON:
  1077.   // aaa=11; while(aaa) VCX_service();
  1078.                                         //*** IF TVG CC IS OFF, DON'T CC ***
  1079.      // BTFSC   PRG_STATUS_1,TVG_CAPS   ;BRANCH IF TVG CAPS SHOULD BE "OFF"
  1080.      // GOTO    CLOSE_POPON_0           ; ELSE, NO TVG CAPTIONS
  1081.   if(tvg_flags & TVG_CAPS) goto CLOSE_POPON_0;
  1082.     fsr[0]=CCCMD_MISC;           // replace POPOFF with Erase
  1083.     fsr[1]=CCCMD_ENM;            // non-displayed memory command
  1084.     tvg_flags |= CMD_SUBST;
  1085.      // MOVLW   OSDCMD_OENM             ;ERASE NON-DISPLAYED MEMORY
  1086.      // CALL    PUT_TO_OSD
  1087. CLOSE_POPON_0:
  1088.      // BTFSC   PRG_STATUS_2,CUSSING    ;BRANCH IF NO CUSSING DETECTED
  1089.      // GOTO    CLOSE_POPON_RET         ; ELSE, RETURN
  1090.   if(tvg_flags & CUSSING) goto CLOSE_POPON_RET;
  1091.      //                                 ;*** UNMUTE AUDIO ***
  1092.      // CALL    CHECK_TO_UNMUTE         ;CHECK TO UNMUTE AUDIO
  1093.   check_to_unmute();
  1094.      //                                 ;*** CHECK TO TURN OFF CAPTIONS ***
  1095.      // BTFSS   IO_MAP,CC_CUSSING       ;BRANCH IF "CC ONLY ON CUSSING"
  1096.      // GOTO    CLOSE_POPON_RET         ; ELSE, GOTO RETURN
  1097.   if(!(io_map & CC_CUSSING)) goto CLOSE_POPON_RET;
  1098.     fsr[0]=CCCMD_MISC;           // replace POPOFF with Erase
  1099.     fsr[1]=CCCMD_ENM;            // non-displayed memory command
  1100.     tvg_flags |= CMD_SUBST;
  1101.     // MOVLW   OSDCMD_OENM             ;ERASE NON-DISPLAYED MEMORY
  1102.     // CALL    PUT_TO_OSD
  1103. CLOSE_POPON_RET:                        // PREPARE TO RETURN FROM CLOSE_POPON
  1104.      // BCF     PRG_STATUS_2,CUSSING    ;ASSUME NEXT CAPTION HAS NO CUSSING
  1105.      // GOTO    PROCESS_CC_POPOFF_0     ;GO BACK TO PROCESS_POPOFF
  1106.      tvg_flags &= ~CUSSING;
  1107.      goto PROCESS_CC_POPOFF_0;
  1108. //******************************************************************************
  1109. //* TABLE       PROCESS_CC_JUMP
  1110. //* DESC                GOTO TABLE OF CLOSED CAPTION CONTROL CODE
  1111. //* INPUT:      R1 LS-NIBBLE = TABLE INDEX
  1112. //* WARNING:     MUST NOT CROSS PAGE
  1113. PROCESS_CC_JUMP:
  1114.      // MOVLW   HIGH PROCESS_CC_JUMP    ;HIGH BYTE OF JUMP TABLE --> PCLATH
  1115.      // MOVWF   PCLATH
  1116.      // MOVLW   0FH                     ;MASK FOR LOWER 4 BITS --> W
  1117.      // ANDWF   R1,W                    ;LOWER NIBBLE OF R1 --> W
  1118.      // ADDWF   PCL,ITSELF              ;JUMP TO PROCESS CTRL CODES VIA PAC:2
  1119.      //                                 ;(SEE FCC15.119 MISC CTRL CODES)
  1120.   switch(r1) {
  1121.     case 0x20: goto PROCESS_CC_POPON;   // 20: JUMP TO POPON CODE
  1122.     case 0x21: goto PROCESS_CC_BKSP;    // 21: JUMP TO BKSP CODE
  1123.     case 0x22: goto PROCESS_CC_RET;     // 22: NOT USED - SKIP IT
  1124.     case 0x23: goto PROCESS_CC_RET;     // 23: NOT USED - SKIP IT
  1125.     case 0x24: goto PROCESS_CC_DER;     // 24: JUMP TO DER CODE
  1126.     case 0x25: goto PROCESS_CC_RU2;     // 25: JUMP TO RU2 CODE
  1127.     case 0x26: goto PROCESS_CC_RU3;     // 26: JUMP TO RU3 CODE
  1128.     case 0x27: goto PROCESS_CC_RU4;     // 27: JUMP TO RU4 CODE
  1129.     case 0x28: goto PROCESS_CC_FON;     // 28: JUMP TO FON CODE
  1130.     case 0x29: goto PROCESS_CC_RDC;     // 29: JUMP TO RDC CODE
  1131.     case 0x2A: goto PROCESS_CC_TR;      // 2A: JUMP TO TR CODE
  1132.     case 0x2B: goto PROCESS_CC_RTD;     // 2B: JUMP TO RTD CODE
  1133.     case 0x2C: goto PROCESS_CC_EDM;     // 2C: JUMP TO EDM CODE
  1134.     case 0x2D: goto PROCESS_CC_CR;      // 2D: JUMP TO CR CODE
  1135.     case 0x2E: goto PROCESS_CC_ENM;     // 2E: JUMP TO ENM CODE
  1136.     case 0x2F: goto PROCESS_CC_POPOFF;  // 2F: JUMP TO POPOFF CODE
  1137.   }
  1138. }
  1139. // Variation od original SEND_CC_CHAR
  1140. // Simply performs check on cc char
  1141. // *** TRY NOT TO SEND LONE PUNCT. ***  
  1142. //
  1143. //  IN:  W       Input CC Char
  1144. // OUT:  DUMMY   Output CC Char, modified if necessary
  1145. //
  1146. void chk_cc_char( void ) {
  1147. CHK_CC_CHAR:
  1148.   dummy=w;            // SAVE CC CHAR --> DUMMY
  1149.   if( !(tvg_flags & NO_LETTERS ) ) goto CHK_CC_CHAR_0;
  1150.   if(chk_if_punct()) {
  1151.     dummy=0;
  1152.     return;
  1153.   }
  1154.   tvg_flags &= ~NO_LETTERS; // FLAG THAT 1ST GOOD CHAR IS FOUND
  1155. CHK_CC_CHAR_0:
  1156.   if(w < ' ') {
  1157.     dummy=0;
  1158.     return;
  1159.   }
  1160. }
  1161. #endif //TV_GUARDIAN_ENABLE