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
 
}
 
 
 | 	 
  | 
			 
		  |