| equack 
 
 
 Joined: 21 Sep 2009
 Posts: 21
 
 
 
			    
 
 | 
			
				| 80 column video display on your HDTV (480i) |  
				|  Posted: Sun Sep 05, 2010 4:53 pm |   |  
				| 
 |  
				| You can get an 80x25 character video display out of a PIC18F26K20. All you need is a suitable crystal and two resistors. 
 Minimal hardware setup:
 
 1. Run the PIC at 3.3 volts.
2. Use a 14.31818 mHz crystal (4x NTSC colorburst)
 3. Connect pin C2 to a video output connector via a 680 ohm resistor.
 4. Connect pin C7 to a video output connector via a 330 ohm resistor.
 5. Connect the video output connector to the composite input of a TV or monitor. Make sure you have both signal and ground connections.
 
 
 For the complete project details including schematic, board layout, and hex files please visit my web page:
 
 http://www.quackenbush.com/lab/picvideo.html
 
 
 Notes:
 
 1. The PIC18F26K20 is rated at 64mHz. With a 4X PLL we run it at 57.3 mHz. You might be able to overclock a slower (48mHz) PIC.
2. Change to #define CRYSTAL13 if you have a 13.5 mHz crystal. This gives you CCIR-601 square pixels.
 3. You can use the internal 16mhz oscillator but the display will be wavy. A 16mhz crystal works OK but there is a large right hand border.
 2. You need a PIC with ~3800 bytes of RAM because an 80 column video display takes 2000 bytes. 40 column mode still takes more than 1536 so you can't use an 18F25K20.
 3. For better results use the luma channel of an S-video connection.
 4. For best results use the component video "Y" input on your HDTV (the green plug)
 5. Uncomment the line "#define COLUMN40" if you want a 40 column video display instead.
 6. The entire video generation is run inside a global interrupt handler leaving the processor free to run your own code without polling or timing restrictions.
 7. The code uses the EUSART in master synchronous mode as a video shift register. This means no UART. If you need a serial port you could try get get your hands on a PIC 18F26J22 which has a second EUSART.
 8. The PIC 18F26K20 has hardware slew rate control of its output pins. Changing the slew rate affects the quality of the video. The best setting depends on the display device you are using.
 9. This was compiled using version 4.112 of the CCS compiler. It will not work correctly on version 4.095, so make sure you have the latest version of the compiler.
 10. The ROM font is 8X8 pixel ASCII. The upper 128 characters are inverse video. There are some special symbols in the lower 32 characters.
 
 
 
  	  | Code: |  	  | /*
 40/80 Column Video Display using a PIC18F26K20.
 
 Copyright (c) 2010 Erik C. Quackenbush
 Non-commercial distribution permitted.
 
 CPU Crystal is:
 14.318180 mHz which is 4X NTSC colorburst giving 69.84 nanosecond pixels
 13.5 mHz which is CCIR-601 square pixels 74.07 nanoseconds
 16 mHz which is the maximum clock rate (4X=64mhz) with 62.5 nanosecond pixels
 
 hardware details:
 
 connect the video output to PIN_C2 through a 680 ohm resistor
 connect the video output to PIN_C7 through a 330 ohm resistor
 run the chip at 3.3 volts
 optionally connect an LED to PIN_A5
 optionally connect a transistor driven speak to pin C1
 
 we're using EUSART as our video shift register.
 baud rate divisor is 0 so it outputs one pixel per CPU clock (Fosc/4)
 which should be 14.318 mHz or ~70ns
 
 we use timer 2 to generate an interrupt at the beginning of each scan line.
 We use a divide by 4 prescaler and set the period register to 227. This
 gives us 908 cycles per line at 14.31818 mHz
 
 we are only generating odd fields- not a true interlaced signal
 
 */
 #include <18F26K20.H>
 
 //#define CRYSTAL13       // 13.5mHz crystal CCIR-601 square pixels
 #define CRYSTAL14     // 14.31818 mHz crystal NTSC pixels (4X color burst)
 //#define CRYSTAL16     // 16mHz internal oscillator works but the display
 // is wavy. You really need an HS crystal.
 
 //#define  COLUMN40       // define COLUMN40 if you want a 40 column display
 // comment it out if you want an 80 column display
 // 40 columns looks good on standard TV sets.
 // 80 columns looks good on most flat panel TVs.
 
 
 /**************************************************************************/
 
 #ifdef CRYSTAL14
 #use     delay(clock=57272720)
 #endif
 
 #ifdef CRYSTAL13
 #use  delay(clock=54000000)
 #endif
 
 #ifdef CRYSTAL16
 #use  delay(clock=64000000)
 #endif
 
 #fuses   H4,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
 
 //#include <string.h>
 //#include <stdio.h>
 #define ROMFONT 0x2000
 #rom int8 ROMFONT={
 0x00, 0x3c, 0x03, 0xff, 0xff, 0x03, 0xc0, 0x03, // 0
 0x03, 0x00, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3c,
 0x00, 0x08, 0x12, 0x14, 0x1c, 0x26, 0x0c, 0x10,
 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
 0x1c, 0x08, 0x1c, 0x1c, 0x10, 0x3e, 0x18, 0x3e,
 0x1c, 0x1c, 0x00, 0x00, 0x20, 0x00, 0x04, 0x1c,
 0x1c, 0x08, 0x1e, 0x1c, 0x0e, 0x3e, 0x3e, 0x1c,
 0x22, 0x1c, 0x38, 0x22, 0x04, 0x22, 0x22, 0x1c,
 0x1e, 0x1c, 0x1e, 0x1c, 0x3e, 0x22, 0x22, 0x41,
 0x22, 0x22, 0x3e, 0x1c, 0x02, 0x1c, 0x00, 0x00,
 0x08, 0x00, 0x02, 0x00, 0x20, 0x00, 0x10, 0x00,
 0x02, 0x08, 0x10, 0x04, 0x0c, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x00, 0x00,
 0xff, 0xc3, 0xfc, 0x00, 0x00, 0xfc, 0x3f, 0xfc,
 0xfc, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xc3,
 0xff, 0xf7, 0xed, 0xeb, 0xe3, 0xd9, 0xf3, 0xef,
 0xef, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf,
 0xe3, 0xf7, 0xe3, 0xe3, 0xef, 0xc1, 0xe7, 0xc1,
 0xe3, 0xe3, 0xff, 0xff, 0xdf, 0xff, 0xfb, 0xe3,
 0xe3, 0xf7, 0xe1, 0xe3, 0xf1, 0xc1, 0xc1, 0xe3,
 0xdd, 0xe3, 0xc7, 0xdd, 0xfb, 0xdd, 0xdd, 0xe3,
 0xe1, 0xe3, 0xe1, 0xe3, 0xc1, 0xdd, 0xdd, 0xbe,
 0xdd, 0xdd, 0xc1, 0xe3, 0xfd, 0xe3, 0xff, 0xff,
 0xf7, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0xef, 0xff,
 0xfd, 0xf7, 0xef, 0xfb, 0xf3, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xef, 0xf7, 0xfb, 0xff, 0xff,
 0x00, 0x7e, 0x03, 0xff, 0xff, 0x03, 0xc0, 0x03, // 1
 0x03, 0x00, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
 0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
 0x00, 0x18, 0x10, 0x08, 0x18, 0x18, 0x44, 0x66,
 0x00, 0x08, 0x12, 0x14, 0x2a, 0x26, 0x12, 0x10,
 0x08, 0x08, 0x14, 0x08, 0x00, 0x00, 0x00, 0x20,
 0x22, 0x0c, 0x22, 0x22, 0x18, 0x02, 0x04, 0x20,
 0x22, 0x22, 0x00, 0x00, 0x10, 0x00, 0x08, 0x22,
 0x22, 0x14, 0x22, 0x22, 0x12, 0x02, 0x02, 0x22,
 0x22, 0x08, 0x10, 0x12, 0x04, 0x36, 0x22, 0x22,
 0x22, 0x22, 0x22, 0x22, 0x08, 0x22, 0x22, 0x41,
 0x22, 0x22, 0x20, 0x04, 0x02, 0x10, 0x08, 0x00,
 0x08, 0x00, 0x02, 0x00, 0x20, 0x00, 0x28, 0x00,
 0x02, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x4c, 0x38,
 0xff, 0x81, 0xfc, 0x00, 0x00, 0xfc, 0x3f, 0xfc,
 0xfc, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
 0xff, 0xe7, 0xef, 0xf7, 0xe7, 0xe7, 0xbb, 0x99,
 0xff, 0xf7, 0xed, 0xeb, 0xd5, 0xd9, 0xed, 0xef,
 0xf7, 0xf7, 0xeb, 0xf7, 0xff, 0xff, 0xff, 0xdf,
 0xdd, 0xf3, 0xdd, 0xdd, 0xe7, 0xfd, 0xfb, 0xdf,
 0xdd, 0xdd, 0xff, 0xff, 0xef, 0xff, 0xf7, 0xdd,
 0xdd, 0xeb, 0xdd, 0xdd, 0xed, 0xfd, 0xfd, 0xdd,
 0xdd, 0xf7, 0xef, 0xed, 0xfb, 0xc9, 0xdd, 0xdd,
 0xdd, 0xdd, 0xdd, 0xdd, 0xf7, 0xdd, 0xdd, 0xbe,
 0xdd, 0xdd, 0xdf, 0xfb, 0xfd, 0xef, 0xf7, 0xff,
 0xf7, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0xd7, 0xff,
 0xfd, 0xff, 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xf7, 0xf7, 0xf7, 0xb3, 0xc7,
 0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 2
 0x03, 0x18, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
 0x00, 0x18, 0x30, 0x0c, 0x3c, 0x18, 0x04, 0x66,
 0x00, 0x08, 0x12, 0x3e, 0x0a, 0x10, 0x0a, 0x08,
 0x04, 0x10, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x10,
 0x32, 0x08, 0x20, 0x20, 0x14, 0x02, 0x02, 0x10,
 0x22, 0x22, 0x08, 0x00, 0x08, 0x3c, 0x10, 0x20,
 0x3a, 0x22, 0x22, 0x02, 0x22, 0x02, 0x02, 0x02,
 0x22, 0x08, 0x10, 0x0a, 0x04, 0x2a, 0x26, 0x22,
 0x22, 0x22, 0x22, 0x02, 0x08, 0x22, 0x22, 0x41,
 0x14, 0x22, 0x10, 0x04, 0x04, 0x10, 0x14, 0x00,
 0x10, 0x18, 0x1a, 0x18, 0x2c, 0x18, 0x08, 0x18,
 0x1a, 0x08, 0x18, 0x24, 0x08, 0x37, 0x1e, 0x1c,
 0x1e, 0x3c, 0x1a, 0x38, 0x1c, 0x22, 0x22, 0x22,
 0x22, 0x24, 0x3c, 0x08, 0x08, 0x08, 0x32, 0x04,
 0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
 0xfc, 0xe7, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
 0xff, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
 0xff, 0xe7, 0xcf, 0xf3, 0xc3, 0xe7, 0xfb, 0x99,
 0xff, 0xf7, 0xed, 0xc1, 0xf5, 0xef, 0xf5, 0xf7,
 0xfb, 0xef, 0xd5, 0xf7, 0xff, 0xff, 0xff, 0xef,
 0xcd, 0xf7, 0xdf, 0xdf, 0xeb, 0xfd, 0xfd, 0xef,
 0xdd, 0xdd, 0xf7, 0xff, 0xf7, 0xc3, 0xef, 0xdf,
 0xc5, 0xdd, 0xdd, 0xfd, 0xdd, 0xfd, 0xfd, 0xfd,
 0xdd, 0xf7, 0xef, 0xf5, 0xfb, 0xd5, 0xd9, 0xdd,
 0xdd, 0xdd, 0xdd, 0xfd, 0xf7, 0xdd, 0xdd, 0xbe,
 0xeb, 0xdd, 0xef, 0xfb, 0xfb, 0xef, 0xeb, 0xff,
 0xef, 0xe7, 0xe5, 0xe7, 0xd3, 0xe7, 0xf7, 0xe7,
 0xe5, 0xf7, 0xe7, 0xdb, 0xf7, 0xc8, 0xe1, 0xe3,
 0xe1, 0xc3, 0xe5, 0xc7, 0xe3, 0xdd, 0xdd, 0xdd,
 0xdd, 0xdb, 0xc3, 0xf7, 0xf7, 0xf7, 0xcd, 0xfb,
 0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 3
 0xff, 0x3c, 0xff, 0x1f, 0x1f, 0xf8, 0xf8, 0xff,
 0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0xff,
 0xff, 0x18, 0x7e, 0x7e, 0x7e, 0x18, 0x1f, 0x3c,
 0x00, 0x08, 0x00, 0x14, 0x1c, 0x08, 0x04, 0x00,
 0x04, 0x10, 0x1c, 0x3e, 0x00, 0x3e, 0x00, 0x08,
 0x2a, 0x08, 0x18, 0x18, 0x12, 0x1c, 0x1e, 0x08,
 0x1c, 0x3c, 0x00, 0x08, 0x04, 0x00, 0x20, 0x10,
 0x2a, 0x22, 0x1e, 0x02, 0x22, 0x1e, 0x1e, 0x1a,
 0x3e, 0x08, 0x10, 0x06, 0x04, 0x2a, 0x2a, 0x22,
 0x1e, 0x22, 0x1e, 0x1c, 0x08, 0x22, 0x22, 0x49,
 0x08, 0x14, 0x08, 0x04, 0x08, 0x10, 0x22, 0x00,
 0x00, 0x20, 0x26, 0x24, 0x32, 0x24, 0x1c, 0x24,
 0x26, 0x08, 0x10, 0x14, 0x08, 0x49, 0x22, 0x22,
 0x22, 0x22, 0x26, 0x04, 0x08, 0x22, 0x22, 0x22,
 0x14, 0x24, 0x20, 0x04, 0x08, 0x10, 0x00, 0x1e,
 0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
 0x00, 0xc3, 0x00, 0xe0, 0xe0, 0x07, 0x07, 0x00,
 0xff, 0x00, 0x00, 0xff, 0xff, 0x07, 0xe0, 0x00,
 0x00, 0xe7, 0x81, 0x81, 0x81, 0xe7, 0xe0, 0xc3,
 0xff, 0xf7, 0xff, 0xeb, 0xe3, 0xf7, 0xfb, 0xff,
 0xfb, 0xef, 0xe3, 0xc1, 0xff, 0xc1, 0xff, 0xf7,
 0xd5, 0xf7, 0xe7, 0xe7, 0xed, 0xe3, 0xe1, 0xf7,
 0xe3, 0xc3, 0xff, 0xf7, 0xfb, 0xff, 0xdf, 0xef,
 0xd5, 0xdd, 0xe1, 0xfd, 0xdd, 0xe1, 0xe1, 0xe5,
 0xc1, 0xf7, 0xef, 0xf9, 0xfb, 0xd5, 0xd5, 0xdd,
 0xe1, 0xdd, 0xe1, 0xe3, 0xf7, 0xdd, 0xdd, 0xb6,
 0xf7, 0xeb, 0xf7, 0xfb, 0xf7, 0xef, 0xdd, 0xff,
 0xff, 0xdf, 0xd9, 0xdb, 0xcd, 0xdb, 0xe3, 0xdb,
 0xd9, 0xf7, 0xef, 0xeb, 0xf7, 0xb6, 0xdd, 0xdd,
 0xdd, 0xdd, 0xd9, 0xfb, 0xf7, 0xdd, 0xdd, 0xdd,
 0xeb, 0xdb, 0xdf, 0xfb, 0xf7, 0xef, 0xff, 0xe1,
 0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 4
 0xff, 0x3c, 0xff, 0x1f, 0x1f, 0xf8, 0xf8, 0xff,
 0x00, 0x00, 0xff, 0xff, 0x00, 0xf8, 0x1f, 0xff,
 0xff, 0x18, 0x7e, 0x7e, 0x18, 0x7e, 0x04, 0x00,
 0x00, 0x08, 0x00, 0x3e, 0x28, 0x04, 0x2a, 0x00,
 0x04, 0x10, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x04,
 0x26, 0x08, 0x04, 0x20, 0x3e, 0x20, 0x22, 0x04,
 0x22, 0x20, 0x08, 0x00, 0x08, 0x3c, 0x10, 0x08,
 0x1a, 0x3e, 0x22, 0x02, 0x22, 0x02, 0x02, 0x22,
 0x22, 0x08, 0x10, 0x0a, 0x04, 0x22, 0x32, 0x22,
 0x02, 0x2a, 0x0a, 0x20, 0x08, 0x22, 0x14, 0x2a,
 0x14, 0x08, 0x04, 0x04, 0x10, 0x10, 0x00, 0x00,
 0x00, 0x38, 0x22, 0x04, 0x22, 0x3c, 0x08, 0x24,
 0x22, 0x08, 0x10, 0x0c, 0x08, 0x49, 0x22, 0x22,
 0x22, 0x22, 0x02, 0x18, 0x08, 0x22, 0x22, 0x2a,
 0x08, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00, 0x1e,
 0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
 0x00, 0xc3, 0x00, 0xe0, 0xe0, 0x07, 0x07, 0x00,
 0xff, 0xff, 0x00, 0x00, 0xff, 0x07, 0xe0, 0x00,
 0x00, 0xe7, 0x81, 0x81, 0xe7, 0x81, 0xfb, 0xff,
 0xff, 0xf7, 0xff, 0xc1, 0xd7, 0xfb, 0xd5, 0xff,
 0xfb, 0xef, 0xd5, 0xf7, 0xff, 0xff, 0xff, 0xfb,
 0xd9, 0xf7, 0xfb, 0xdf, 0xc1, 0xdf, 0xdd, 0xfb,
 0xdd, 0xdf, 0xf7, 0xff, 0xf7, 0xc3, 0xef, 0xf7,
 0xe5, 0xc1, 0xdd, 0xfd, 0xdd, 0xfd, 0xfd, 0xdd,
 0xdd, 0xf7, 0xef, 0xf5, 0xfb, 0xdd, 0xcd, 0xdd,
 0xfd, 0xd5, 0xf5, 0xdf, 0xf7, 0xdd, 0xeb, 0xd5,
 0xeb, 0xf7, 0xfb, 0xfb, 0xef, 0xef, 0xff, 0xff,
 0xff, 0xc7, 0xdd, 0xfb, 0xdd, 0xc3, 0xf7, 0xdb,
 0xdd, 0xf7, 0xef, 0xf3, 0xf7, 0xb6, 0xdd, 0xdd,
 0xdd, 0xdd, 0xfd, 0xe7, 0xf7, 0xdd, 0xdd, 0xd5,
 0xf7, 0xdb, 0xe7, 0xf7, 0xf7, 0xf7, 0xff, 0xe1,
 0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 5
 0x03, 0x18, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
 0x00, 0x00, 0x00, 0xff, 0x00, 0x18, 0x18, 0x00,
 0x18, 0x18, 0x30, 0x0c, 0x18, 0x3c, 0x1e, 0x00,
 0x00, 0x00, 0x00, 0x14, 0x2a, 0x32, 0x12, 0x00,
 0x08, 0x08, 0x14, 0x08, 0x08, 0x00, 0x00, 0x02,
 0x22, 0x08, 0x02, 0x22, 0x10, 0x22, 0x22, 0x04,
 0x22, 0x10, 0x00, 0x08, 0x10, 0x00, 0x08, 0x00,
 0x02, 0x22, 0x22, 0x22, 0x12, 0x02, 0x02, 0x32,
 0x22, 0x08, 0x12, 0x12, 0x04, 0x22, 0x22, 0x22,
 0x02, 0x12, 0x12, 0x22, 0x08, 0x22, 0x14, 0x2a,
 0x22, 0x08, 0x02, 0x04, 0x20, 0x10, 0x00, 0x00,
 0x00, 0x24, 0x26, 0x24, 0x32, 0x04, 0x08, 0x38,
 0x22, 0x08, 0x10, 0x14, 0x08, 0x49, 0x22, 0x22,
 0x1e, 0x3c, 0x02, 0x20, 0x08, 0x32, 0x14, 0x2a,
 0x14, 0x38, 0x04, 0x08, 0x08, 0x08, 0x00, 0x04,
 0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
 0xfc, 0xe7, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
 0xff, 0xff, 0xff, 0x00, 0xff, 0xe7, 0xe7, 0xff,
 0xe7, 0xe7, 0xcf, 0xf3, 0xe7, 0xc3, 0xe1, 0xff,
 0xff, 0xff, 0xff, 0xeb, 0xd5, 0xcd, 0xed, 0xff,
 0xf7, 0xf7, 0xeb, 0xf7, 0xf7, 0xff, 0xff, 0xfd,
 0xdd, 0xf7, 0xfd, 0xdd, 0xef, 0xdd, 0xdd, 0xfb,
 0xdd, 0xef, 0xff, 0xf7, 0xef, 0xff, 0xf7, 0xff,
 0xfd, 0xdd, 0xdd, 0xdd, 0xed, 0xfd, 0xfd, 0xcd,
 0xdd, 0xf7, 0xed, 0xed, 0xfb, 0xdd, 0xdd, 0xdd,
 0xfd, 0xed, 0xed, 0xdd, 0xf7, 0xdd, 0xeb, 0xd5,
 0xdd, 0xf7, 0xfd, 0xfb, 0xdf, 0xef, 0xff, 0xff,
 0xff, 0xdb, 0xd9, 0xdb, 0xcd, 0xfb, 0xf7, 0xc7,
 0xdd, 0xf7, 0xef, 0xeb, 0xf7, 0xb6, 0xdd, 0xdd,
 0xe1, 0xc3, 0xfd, 0xdf, 0xf7, 0xcd, 0xeb, 0xd5,
 0xeb, 0xc7, 0xfb, 0xf7, 0xf7, 0xf7, 0xff, 0xfb,
 0x00, 0x7e, 0x03, 0x03, 0xc0, 0xff, 0xff, 0x03, // 6
 0x03, 0x00, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x00,
 0x18, 0x18, 0x10, 0x08, 0x18, 0x18, 0x65, 0x00,
 0x00, 0x08, 0x00, 0x14, 0x1c, 0x32, 0x2c, 0x00,
 0x10, 0x04, 0x00, 0x00, 0x08, 0x00, 0x08, 0x02,
 0x1c, 0x1c, 0x3e, 0x1c, 0x10, 0x1c, 0x1c, 0x04,
 0x1c, 0x0c, 0x00, 0x08, 0x20, 0x00, 0x04, 0x08,
 0x3c, 0x22, 0x1e, 0x1c, 0x0e, 0x3e, 0x02, 0x2c,
 0x22, 0x1c, 0x0c, 0x22, 0x3c, 0x22, 0x22, 0x1c,
 0x02, 0x2c, 0x22, 0x1c, 0x08, 0x1c, 0x08, 0x14,
 0x22, 0x08, 0x3e, 0x1c, 0x20, 0x1c, 0x00, 0xff,
 0x00, 0x38, 0x1a, 0x18, 0x2c, 0x38, 0x08, 0x20,
 0x22, 0x10, 0x10, 0x24, 0x08, 0x49, 0x22, 0x1c,
 0x02, 0x20, 0x02, 0x1c, 0x10, 0x2c, 0x08, 0x14,
 0x22, 0x20, 0x3c, 0x10, 0x08, 0x04, 0x00, 0x38,
 0xff, 0x81, 0xfc, 0xfc, 0x3f, 0x00, 0x00, 0xfc,
 0xfc, 0xff, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
 0xff, 0xff, 0xff, 0xff, 0x00, 0xe7, 0xe7, 0xff,
 0xe7, 0xe7, 0xef, 0xf7, 0xe7, 0xe7, 0x9a, 0xff,
 0xff, 0xf7, 0xff, 0xeb, 0xe3, 0xcd, 0xd3, 0xff,
 0xef, 0xfb, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xfd,
 0xe3, 0xe3, 0xc1, 0xe3, 0xef, 0xe3, 0xe3, 0xfb,
 0xe3, 0xf3, 0xff, 0xf7, 0xdf, 0xff, 0xfb, 0xf7,
 0xc3, 0xdd, 0xe1, 0xe3, 0xf1, 0xc1, 0xfd, 0xd3,
 0xdd, 0xe3, 0xf3, 0xdd, 0xc3, 0xdd, 0xdd, 0xe3,
 0xfd, 0xd3, 0xdd, 0xe3, 0xf7, 0xe3, 0xf7, 0xeb,
 0xdd, 0xf7, 0xc1, 0xe3, 0xdf, 0xe3, 0xff, 0x00,
 0xff, 0xc7, 0xe5, 0xe7, 0xd3, 0xc7, 0xf7, 0xdf,
 0xdd, 0xef, 0xef, 0xdb, 0xf7, 0xb6, 0xdd, 0xe3,
 0xfd, 0xdf, 0xfd, 0xe3, 0xef, 0xd3, 0xf7, 0xeb,
 0xdd, 0xdf, 0xc3, 0xef, 0xf7, 0xfb, 0xff, 0xc7,
 0x00, 0x3c, 0x03, 0x03, 0xc0, 0xff, 0xff, 0x03, // 7
 0x03, 0x00, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x00,
 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0xff, 0xc3, 0xfc, 0xfc, 0x3f, 0x00, 0x00, 0xfc,
 0xfc, 0xff, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
 0xff, 0xff, 0xff, 0xff, 0x00, 0xe7, 0xe7, 0xff,
 0xe7, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3,
 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xfd, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 }
 
 #define  SYNC_BIT          2
 #define  SYNC_PIN          PIN_C2      // pin 13
 #define  CLOCK_PIN         PIN_C6      // pin 17
 #define  PIXEL_PIN         PIN_C7      // pin 18
 #define  SOUND_PIN         PIN_C1
 #define  LED_PIN           PIN_A5
 
 const char copyright[]="Copyright (C) 2010 Erik C. Quackenbush, Inc.\r\nNon-commercial distribution permitted\r\nVERSION 1";
 
 #ifdef COLUMN40
 #define CONSOLECOLS   40
 #else
 #define CONSOLECOLS   80
 #endif
 #define CONSOLEROWS   25
 #define CONSOLERAM   (CONSOLEROWS*CONSOLECOLS+2) //2082  // why waste 48 bytes of RAM at the end?
 #define CONSOLELAST  (CONSOLECOLS*(CONSOLEROWS-1) )
 // so don't change it.
 
 
 // These definitions depend upon the oscillator frequency.
 // Note that while we can use the chip's internal 16mhz oscillator it is not
 // stable. the video signal it generates wiggles around a lot.
 // Use a crystal.
 
 #ifdef CRYSTAL14
 #define  HLINEPERIOD    227         // period of timer 2 which is pixels per hline divided by 4.
 #define  HALFLINE       102         // during VSYNC we emit two pulses per line. this time between them in 4 pixel units
 #define  HSyncHChars    8           // duration of HSYNC pulse in 4 pixel units
 #define  VSyncHChars    4           // duration of VSYNC pulse in 4 pixel units
 #ifdef COLUMN40
 #define  HBackPorch     20          // horizontal backporch in 4 pixel units
 #else
 #define  HBackPorch     25
 #endif
 #endif                              // change the backporch to adjust the
 // horizontal (overscan) position.
 #ifdef CRYSTAL13
 #define  HLINEPERIOD    215
 #define  HALFLINE       96
 #define  HSyncHChars    7
 #define  VSyncHChars    4
 #define  HBackPorch     16
 #endif
 
 #ifdef CRYSTAL16
 #define  HLINEPERIOD    254
 #define  HALFLINE       115
 #define  HSyncHChars    8
 #define  VSyncHChars    4
 #define  HBackPorch     27
 #endif
 
 #define  VSYNCLINE      220            // change this to adjust the top margin (overscan area)
 #define  ACTIVE         CONSOLEROWS*8  // 200 active lines.
 #define  FIELDLINES     262            // We're off by a half line but we're not interlaced.
 #define  OVERSCANLINES  10
 
 //
 // EUSART
 // we're using the EUSART as a high speed shift register to
 // output pixels. Master synchronous transmit mode.
 //
 
 #define  SPEN_BIT  7
 #define  SPEN      0x80  // serial port enable
 #define  CSRC      0x80  // master mode/slave
 #define  SYNC      0x20  // synchronous/asynchronous
 #define  TXEN      0x10  // transmit/receive
 
 #byte    RCSTA=   0xFAB
 #byte    TXSTA=   0xFAC // transmit control and status
 #byte    TXREG=   0xFAD
 #byte    RCREG=   0xFAE
 #byte    SPBRG=   0xFAF // baud rate
 #byte    SPBRGH=  0xFB0 // high byte
 
 // CCP
 
 #define CCP1IF    2
 #define CCP2IF    1
 
 #byte CCPR1H=0xFBF
 #byte CCPR1L=0xFBE
 
 #byte CCPR2H=0xFBC
 #byte CCPR2L=0xFBB
 
 // interrupts
 
 #byte PIE1=0xF9D
 #byte PIR1=0xF9E
 #byte PIR1=       0xF9E
 #byte PIR2=       0xFA1
 #byte INTCON3=    0xFF0
 
 #define INT2IF    1  // bit 1 of INTCON3 is external interrupt #2
 #define INT2MASK (1<<INT2IF)
 #define TMR2IF    1  // bit 1 (not bit 0)
 #define TMR2IE    1  // bit 1 (not bit 0)
 
 // PORT C latch
 #byte    LATC=    0xF8B
 
 // indirect addressing
 #byte    INDF0=   0xFEF
 #byte    POSTINC0=0xFEE
 #byte    POSTDEC0=0xFED
 
 #byte    FSR0H=   0xFEA
 #byte    FSR0L=   0xFE9
 
 #byte    INDF1=   0xFE7
 #byte    POSTINC1=0xFE6
 #byte    FSR1H=   0xFE2
 #byte    FSR1L=   0xFE1
 
 
 #byte    INDF2=   0xFDF
 #byte    POSTINC2=0xFDE
 #byte    FSR2H=   0xFDA
 #byte    FSR2L=   0xFD9
 
 #byte    PRODH=   0xFF4
 #byte    PRODL=   0xFF3
 
 // table access to ROM
 #byte    TBLPTRU= 0xFF8
 #byte    TBLPTRH= 0xFF7
 #byte    TBLPTRL= 0xFF6
 #byte    TABLAT=  0xFF5
 
 
 // Slew rate control
 
 #byte    SLRCON=  0xF78    // this PIC allows you to decrease the
 #define  PORTC_SLEW  0x04  // slew rate of the output ports under software control
 
 
 // global
 
 #byte    STATUS=  0xFD8
 #byte    BSR=     0xFE0
 #byte    PCLATH=  0xFFA
 
 
 /******************** GLOBAL VARIABLES *************************/
 
 unsigned char console[CONSOLERAM];
 #locate console=0x100      // this address is hard coded because
 // it must be at the start of a page (256).
 // You could change it to 0x200, 0x300, etc.
 // but not 0x180, 0x317, etc.
 
 int conX=0,conY=0;     // position of cursor
 #define CURSOR (32+128) // reverse video space cursor
 
 
 
 int seconds=0,minutes=0,hours=0,fields=0,blankscreen=0;
 unsigned int32 ticks=0; // number of horizontal video lines since powerup
 
 //#include "ps2.c"      // PS/2 keyboard support coming soon
 
 // this is our offset into console memory
 
 #ifdef COLUMN40
 
 unsigned char Dubs[256];
 unsigned char Dubs2[256];
 #locate Dubs=0x500
 #locate Dubs2=0x600
 
 long DubW=0x500; // just past the end of the 40 column console RAM
 int DubL,DubH;
 #locate DubW=0x56
 #locate DubH=DubW+1
 #locate DubL=DubW
 
 long Dub2W=0x600; // one page past the end of the 40 column console RAM
 int Dub2L,Dub2H;
 #locate Dub2W=0x58
 #locate Dub2H=Dub2W+1
 #locate Dub2L=Dub2W
 
 #endif
 
 
 /*************** end of globals ***********************/
 
 /*************** start of video interrupt code ********/
 
 #INLINE
 void UpdateClock(void)
 {
 if(fields==60)
 {
 fields=0;
 seconds++;
 if(seconds==60)
 {
 seconds=0;
 minutes++;
 if(minutes==60)
 {
 minutes=0;
 hours++;
 }
 }
 }
 }
 
 unsigned int safety[0x15]; // this stores our registers during ISR
 #locate safety=0x004
 
 #INT_GLOBAL
 void HScan(void)
 {
 static int hloop,hcount;
 static long hline=0;       // this holds our current scanline
 static int hlinel,hlineh;
 static long charW=console;// this is our pointer into console RAM
 static int charL,charH;
 static int syncpos=0;      // positive sync pulse
 static int syncshort=0;    // two short sync pulses instead of one long one
 static int syncneg=0;
 static int activeline=0;
 #locate hline=0x50
 #locate hlineh=hline+1
 #locate hlinel=hline
 #locate charW=0x52
 #locate charH=charW+1
 #locate charL=charW
 // static variables we preserve between interrupts (no need to make them global)
 #asm
 // we have not enabled high priority interrupts so we don't need to
 // pad out interrupt vector with NOPs to get us to 0x018
 
 // we rely on the shadow status,w,&BSR registers to keep track of our
 // state. we don't save them manually
 
 MOVLB  0x00             // set Bank zero
 BTFSC    syncpos,0      // are we positive sync?
 BCF      LATC,SYNC_BIT  // yes, turn off the sync pin output_low(SYNC_PIN);
 MOVFF    FSR0L,0x0C     // saving the registers takes
 MOVFF    FSR0H,0x07     // 28 instructions
 MOVFF    FSR1L,0x08     // which is almost exactly our 4 microsecond
 MOVFF    FSR1H,0x09     // sync pulse width
 MOVFF    FSR2L,0x0A
 MOVFF    FSR2H,0x0B
 MOVFF    PCLATH,0x14
 BTFSC    syncshort,0    // short sync pulse?
 BSF      LATC,SYNC_BIT  // clear the sync pin early
 MOVFF    TABLAT,0x15
 MOVFF    TBLPTRL,0x16
 MOVFF    TBLPTRH,0x17
 MOVFF    0x00,0x0E
 MOVFF    0x01,0x0F
 MOVFF    0x02,0x10
 MOVFF    0x03,0x11
 //    MOVFF    PRODL,0x12   // we don't use the multiplier
 //    MOVFF    PRODH,0x13
 EndSync:
 BTFSC    syncpos,0      // are we normal sync?
 BSF      LATC,SYNC_BIT  // yes- turn on the sync pin
 
 BTFSS    PIE1,TMR2IE    // where should this live? earlier?
 GOTO     SkipInt
 // no actual interrupt pending? that
 // should never happen but if it does we
 // just go quietly
 scanout:
 BTFSS    activeline,0
 BRA      notactiveline
 backporch:
 MOVLW    HBackPorch   // back porch delay
 MOVWF    hcount
 chardelay:
 NOP            // four instructions per half character
 DECFSZ   hcount
 BRA      chardelay
 
 MOVF   hlinel,W
 ANDLW  0x07
 BZ     topofline        // if((hlinel&0x07)!=0)
 
 MOVLW  CONSOLECOLS//
 SUBWF  charL,F
 MOVLW  0x00
 SUBWFB charH,F  // this is a 16 bit subtract so undercarry
 BRA    setloop    //else
 
 topofline:
 NOP               // it takes 8 scan lines to draw a character. we subtract
 NOP               // charW to the beginning of the line each time except
 NOP               // when we're on the first line (top of char).
 NOP               // The NOPs are here to ensure the same number of cycles
 NOP               // until the first pixel whether we branch or not.
 
 setloop:
 MOVLW    40          // loops per line. we do 2 chars per loop in 80 column mode
 MOVWF    hloop
 
 MOVFF    charL,FSR0L // load our offset into console character memory
 MOVFF    charH,FSR0H
 #ifdef COLUMN40
 MOVFF    Dub2H,FSR1H
 MOVFF    DubH,FSR2H
 #endif
 MOVLW    0x07
 ANDWF    hlinel,w
 ADDLW    ROMFONT/256        // assumes font starts at 0x2000, add the line offset
 MOVWF    TBLPTRH
 MOVLW    0
 BSF      RCSTA,SPEN_BIT // turn on the shift register
 overscan:
 MOVWF   TXREG
 #ifdef COLUMN40
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 MOVWF    TXREG
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 MOVWF    TXREG
 NOP
 NOP
 NOP
 NOP
 NOP
 MOVFF    POSTINC0,TBLPTRL
 CLRF    TXREG
 NOP
 //      NOP
 pixels:
 TBLRD    *                   // read our font data
 MOVFF    TABLAT,FSR1L
 MOVFF    INDF2,TXREG
 DECF     hloop,F
 NOP                        // we need this NOP
 
 MOVFF    TABLAT,FSR2L
 MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
 MOVFF    INDF1,TXREG
 BNZ      pixels          // are we done with the line?
 endpixels:
 NOP
 NOP
 NOP
 NOP
 MOVFF    INDF2,TXREG
 MOVF     POSTDEC0
 NOP
 NOP
 #else
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 MOVWF    TXREG
 NOP
 pixels:
 MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
 TBLRD    *                   // read our font data
 MOVFF    TABLAT,TXREG
 DECF     hloop,F
 NOP                        // we need this NOP
 MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
 TBLRD    *                 // read our font data
 MOVFF    TABLAT,TXREG
 BNZ      pixels
 endpixels:
 NOP   // we need these in 80 column mode
 NOP
 NOP
 #endif
 
 MOVFF    FSR0L,charL  // save our character position
 MOVFF    FSR0H,charH
 
 CLRF     RCSTA       // OK, shut off the shift register now
 
 BRA      postvideo
 notactiveline:
 
 BTFSS    syncpos,0
 BRA      vsynccode
 // do a back porch but do not emit video
 topbackporch:
 MOVLW    HBackPorch   // back porch delay
 MOVWF    hcount
 topchardelay:
 NOP            // four instructions per half character
 DECFSZ   hcount
 BRA      topchardelay
 
 idletime:
 MOVLW    5        // number of instructions div 3- aligns our sync
 MOVWF    hcount
 idleloop:
 DECFSZ   hcount
 BRA      idleloop
 
 #ifdef COLUMN40
 NOP
 NOP
 NOP
 NOP
 #endif
 MOVLW    0
 BSF      RCSTA,SPEN_BIT // turn on the shift register
 MOVWF    TXREG
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 CLRF  RCSTA
 BRA   postvideo
 vsynccode:
 
 halfporch:
 MOVLW    HALFLINE // back porch delay
 MOVWF    hcount
 halfdelay:
 NOP            // four instructions per half character
 DECFSZ   hcount
 BRA      halfdelay
 
 BTFSS    syncpos,0
 BRA      vsyncold
 
 positivesecond:
 BCF      LATC,SYNC_BIT  // yes, turn off the sync pin output_low(SYNC_PIN);
 MOVLW    VSyncHChars
 MOVWF    hcount
 secondsyncpos:
 NOP
 DECFSZ    hcount
 BRA       secondsyncpos
 BSF      LATC,SYNC_BIT  // clear the sync pin early
 BRA      vsyncold
 
 
 halfsyncstart:
 BSF      LATC,SYNC_BIT
 MOVLW VSyncHChars
 MOVWF hcount
 halfsyncdelay:
 NOP            // four instructions per loop == 1/2 character at 80 columns (1 character at 40 columns)
 DECFSZ   hcount
 BRA   halfsyncdelay
 BCF      LATC,SYNC_BIT
 
 vsyncold:
 
 BTFSS    syncneg,0
 BRA      postvideo
 
 BSF      LATC,SYNC_BIT
 MOVLW VSyncHChars
 MOVWF hcount
 halfsyncnegdelay:
 NOP            // four instructions per loop == 1/2 character at 80 columns (1 character at 40 columns)
 DECFSZ   hcount
 BRA   halfsyncnegdelay
 BCF      LATC,SYNC_BIT
 
 BTFSS    syncshort,0
 BRA      postvideo
 MOVLW 2
 MOVWF hcount
 delay4:
 NOP
 DECFSZ hcount,F
 BRA    delay4
 BSF    LATC,SYNC_BIT
 
 postvideo:
 #endasm
 
 hline++;
 
 if(hline>FIELDLINES)
 {
 hline=0;
 }
 
 // here we set some flags to determine what the next video line will
 // look like. will it have active pixels? will it have negative sync?
 
 syncpos=1;     // normal sync
 activeline=0;  // not active video
 syncshort=0;   // full width sync pulse
 syncneg=0;     // end with a negative sync pulse
 
 if(hline<ACTIVE)
 {
 if(blankscreen==0)activeline=1; // the next line is active video
 }
 else if(HLINE==VSYNCLINE+9)
 {
 fields++;
 ticks++;
 //if(ticks%16==0) console[CONSOLERAM-CONSOLECOLS-2]^=0x80; // blink the cursor
 UpdateClock();
 syncpos=0;
 }
 else
 {
 if(hline==ACTIVE)
 {
 charW=console;// this is 0x100 at the end of each active field we reset the pointer into character memory
 syncpos=0;
 }
 else if(hline==VSYNCLINE)     syncshort=1;
 else if(hline==VSYNCLINE+1)   syncshort=1;
 else if(hline==VSYNCLINE+2)   syncshort=1;
 else if(hline==VSYNCLINE+3)   { syncpos=0; syncneg=1; }
 else if(hline==VSYNCLINE+4)   { syncpos=0; syncneg=1; }
 else if(hline==VSYNCLINE+5)   { syncshort=1; syncneg=1; }
 else if(hline==VSYNCLINE+6)   syncshort=1;
 else if(hline==VSYNCLINE+7)   syncshort=1;
 
 }
 
 
 // restore our registers before returning
 #asm
 BCF      PIR1,TMR2IF
 
 SkipInt:
 
 //#endasm
 //      KBint();
 //#asm
 BTFSC  PIR1,TMR2IF
 MOVFF  0x0E,0x00
 MOVFF  0x0F,0x01
 MOVFF  0x10,0x02
 MOVFF  0x11,0x03
 MOVFF  0x0C,FSR0L
 MOVFF  0x07,FSR0H
 MOVFF  0x08,FSR1L
 MOVFF  0x09,FSR1H
 MOVFF  0x0A,FSR2L
 MOVFF  0x0B,FSR2H
 //      MOVFF  0x12,PRODL
 //      MOVFF  0x13,PRODH
 MOVFF  0x14,PCLATH
 MOVFF  0x15,TABLAT
 MOVFF  0x16,TBLPTRL
 MOVFF  0x17,TBLPTRH
 RETFIE 1             // restore shadow registers
 
 #endasm
 
 }
 
 /**************** end of video generation ***************************/
 
 /************ start of console/ video terminal handling functions***/
 
 void CursorOn()
 {
 //console[conX+conY*CONSOLECOLS]|=0x80;
 }
 
 void CursorOff()
 {
 //console[conX+conY*CONSOLECOLS]^=0x80;
 }
 
 void ScrollUp(int CR)
 {
 long index;
 
 CursorOff();
 for(index=0;index<CONSOLERAM-CONSOLECOLS;index++)
 {
 console[index]=console[index+CONSOLECOLS];
 }
 
 for(index=CONSOLELAST;index<CONSOLELAST+CONSOLECOLS;index++) console[index]=32;
 
 if(CR) conX=0;
 CursorOn();
 }
 
 void ScreenChar(char symbol)
 {
 CursorOff();
 switch(symbol)
 {
 case 8: // backspace
 if(ConX) ConX--;
 break;
 case '\n':// line feed
 ConY++;
 if(ConY==CONSOLEROWS)
 {
 ScrollUp(0);// no carriage return- just a line feed
 ConY--;
 }
 break;
 case '\r': // carriage return
 ConX=0;
 break;
 default:
 console[CONSOLECOLS*ConY+ConX++]=symbol;
 if(ConX>=CONSOLECOLS)
 {
 ConY++;
 if(ConY>CONSOLEROWS)
 {
 ConY=CONSOLEROWS;
 ScrollUp(1);
 }
 }
 }
 CursorOn();
 }
 
 void StringWrite(char *dest,char *source) // write a string without writing the terminating NULL
 {
 int index=0;
 
 while(source[index]!=0)
 {
 if(dest<CONSOLERAM) *dest++=source[index++];
 }
 }
 
 void InitConsoleRAM1(void)
 {
 long index;
 
 for(index=0;index<CONSOLERAM;index+=CONSOLECOLS) // fill the screen with a test pattern
 {
 //123456789-123456789-12345678-123456789-123456789-123456789-123456789-123456789-
 #ifdef COLUMN40
 // 123456789-123456xx789-123456789-123456789-
 sprintf(&console[index],"%2ld THIS IS LINE %2ld          30        40",index/CONSOLECOLS,index/CONSOLECOLS);
 //      sprintf(safetemp,"%2ld THIS IS LINE %2ld          30        40",index/CONSOLECOLS,index/CONSOLECOLS);
 
 #else
 sprintf(&console[index],"%2ld THIS IS LINE %2ld          30        40        50        60        70        80",index/CONSOLECOLS,index/CONSOLECOLS);
 #endif
 //      sprintf(&console[index],"%2ld THIS IS LINE %2ld 123456789-123456789-123456789-123456789-123456789-1234567890",index/80-1,index/80-1);
 
 //this overwrites our 2000 characters by 1: it adds a null terminator past the end of the thing.
 }
 
 for(index=0;index<256;index++)
 {
 console[index+160]=index;
 }
 
 sprintf(&console[CONSOLECOLS/2-4],"EQUACK %d",CONSOLECOLS); // centered at the top of the screen
 strcpy(&console[CONSOLECOLS*12],"The quick brown fox jumped over the lazy dogs.");
 }
 
 #ifdef COLUMN40
 void Init40Double(void)
 {
 long index;
 int dubleft,dubright;
 const unsigned char convert[16]={0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF};
 
 
 for(index=0;index<256;index++)
 {
 dubleft=convert[index/16];
 Dubs[index]=dubleft;
 }
 
 for(index=0;index<256;index++)
 {
 dubright=convert[index%16];
 Dubs2[index]=dubright;
 }
 }
 #endif //COLUMN40
 
 
 void InitConsoleRAM2(void)
 {
 long index,line;
 long offset;
 
 for(line=1;line<CONSOLEROWS;line++)
 {
 for(index=0;index<CONSOLECOLS;index+=4)
 {
 offset=index+(line*CONSOLECOLS);
 //         console[offset]='@'+line;
 console[offset]='A';
 console[offset+1]='B';
 console[offset+2]='C';
 console[offset+3]='D';
 
 }
 }
 
 
 strcpy(&console[CONSOLECOLS*10],"This is a test of the emergency broadcasting system.");
 strcpy(&console[CONSOLECOLS*14],"AND NOW FOR SOMETHING COMPLETELY DIFFERENT.");
 
 }
 
 void InvertScreen(void)
 {
 long index;
 
 for(index=CONSOLECOLS;index<CONSOLERAM;index++)
 {
 console[index]^=0x80;
 }
 }
 
 void EraseConsoleRAM(void)
 {
 long index;
 
 for(index=0;index<CONSOLERAM;index++)
 {
 console[index]=0;
 }
 }
 
 void InitSystem(void)
 {
 EraseConsoleRAM();
 
 InitConsoleRAM1();
 
 #ifdef COLUMN40
 Init40Double();
 #endif
 
 output_drive(PIXEL_PIN); // this is our video output
 output_drive(CLOCK_PIN); // we could shut this off for RFU.
 
 SLRCON=0;      //PORTC_SLEW;   // decrease the slew rate of port C for nicer pixels
 SPBRG=0;       // we always set the baud rate to 0, one pixel per Tcy.
 SPBRGH=0;      // in 40 column mode we double our pixels
 TXSTA=CSRC | SYNC | TXEN; // master synchronous transmit mode
 
 output_high(SYNC_PIN); // sync pin goes LOW to drop below IRE 0.3 volts
 
 setup_timer_2(T2_DIV_BY_4,HLINEPERIOD,1);
 
 /*
 setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
 setup_ccp2(CCP_COMPARE_RESET_TIMER ); // note that we do not actually enable the interrupt for this.
 
 #define BAUDDIV   1491
 
 CCPR2H=BAUDDIV/256;
 CCPR2L=BAUDDIV%256;
 */
 enable_interrupts(INT_TIMER2);   // horizontal sync interrupt
 enable_interrupts(GLOBAL);
 }
 
 
 void delay_fields(long interval) // delay a number of vertical blank intervals, 16.7 milliseconds each.
 {
 int32 wait;
 
 // If the system runs for 2.25 years this function
 // could hang if called at exactly the wrong time.
 //
 // This function it has an inherent error because the first field will be a partial field
 // which could last between 1 and 261 scan lines.
 //
 wait=ticks+interval;
 for(;;)
 {
 if(ticks>=wait) return;
 }
 }
 
 //const char mystring[]={"blah"};
 
 
 void ScrollOff(void)
 {
 int index;
 
 for(index=0;index<25;index++)
 {
 ScrollUp(1);
 
 #ifdef COLUMN40
 sprintf(&console[CONSOLELAST],"Elapsed time %d:%02d:%02d.%02d 56789-123456789-",hours,minutes,seconds,fields);
 #else
 sprintf(&console[CONSOLELAST],"Elapsed time %d:%02d:%02d.%02d 56789-123456789-123456789-12345789-123456789-123456789-",hours,minutes,seconds,fields);
 #endif
 delay_fields(30); //
 }
 
 }
 
 void Beep(void)
 {
 long index;
 
 for(index=0;index<250;index++)
 {
 output_low(SOUND_PIN);
 delay_us(500);
 output_high(SOUND_PIN);
 delay_us(500);
 }
 }
 
 void Typewriter(void)
 {
 int symbol;
 for(;;)
 {
 if(kbhit())
 {
 blankscreen=1;
 //         disable_interrupts(GLOBAL);
 symbol=getc();
 console[CONSOLELAST+ConX++]=symbol&0x7F;
 if(ConX>=CONSOLECOLS)
 {
 ScrollUp(1);
 }
 blankscreen=0;
 }
 }
 }
 
 #define RX_PIN PIN_B1
 
 void TypeReader(void)
 {
 char symbol;
 int index;
 char hexit[3];
 
 while(input(RX_PIN)==0) ; // wait for idle
 for(;;)
 {
 symbol=0;
 
 while(input(RX_PIN)) ;   // wait for start bit falling edge
 PIR2^=CCP2IF; // clear the CCP2 interrupt flag
 
 for(index=0;index<8;index++)
 {
 while((PIR2 & CCP2IF) ==0) ; // wait for a CCP2 event
 PIR2^=CCP2IF; // clear the CCP2 event
 if(input(RX_PIN))
 {
 symbol|=0x80;
 }
 symbol>>=1;
 }
 while((PIR2 & CCP2IF) ==0) ; // wait for a CCP2 event
 PIR2^=CCP2IF; // clear the CCP2 event (stop bit)
 
 sprintf(hexit,"%02X",symbol);
 ScreenChar(hexit[0]);
 ScreenChar(hexit[1]);
 ScreenChar(symbol);
 ScreenChar(' ');
 }
 }
 
 
 //---------------Main() entry point--------------------------------
 void main( void )
 {
 char *right;
 right=copyright;
 
 output_high(LED_PIN);
 
 Beep();
 
 InitSystem();
 // InitKeyboard();
 // KeyRead();
 //   ScrollOff();
 
 for(;;) ; // just wait
 }
 
 
 | 
 |  |