;****************************************************************************** ; NTSC/PAL Video Generation Code (16MHZ System Clock) ; ; Originally designed and written by Daryl Rictor (c)2003-2004 ; ; Modified by Grant Searle 2007-13 ; - Multi size fonts ; - Now uses a single clock interrupt ; - Supports 40 chars or 80 chars per line ;****************************************************************************** push acc push accH push ZL push ZH push J in J,SREG push J ;Get exact sync with clock (remove jitter) lds J, TCNT1L cpi J, 0x14 breq clkSync0 cpi J, 0x15 breq clkSync1 cpi J, 0x16 breq clkSync2 cpi J, 0x17 breq clkSync3 cpi J, 0x18 breq clkSync4 nop nop nop clkSync0: nop nop nop clkSync1: nop nop nop clkSync2: nop nop nop clkSync3: nop nop nop clkSync4: ; Timer now always 0x24 at this point cbi portb, syncpin ; drop the csync pin LINECHECK: cpi vlineh, 0x00 brne NOTFIRST256 cpi vline, 0x04 brlo VSYNC ; no, wait for hsync end rjmp CHECKTOPBLANK VSYNC: rjmp EOL ; line 0 is a VSYNC line, we're done CHECKTOPBLANK: cp vline, line1 brlo TOPBLANK rjmp CHECKFIRSTLINE TOPBLANK: rjmp BLANK CHECKFIRSTLINE: cp vline, line1 brne CHECKLASTLINE FIRSTLINE: ldi chrln, 0x00 ; sync chrlin with first active line rjmp DISPLAY CHECKLASTLINE: cpi chrln, 0xC8 ; have we passed line 200? brlo DISPLAY ; no, get ready for active display line rjmp BLANK NOTFIRST256: cpi chrln, 0xC8 ; have we passed line 200? brlo DISPLAY ; no, get ready for active display line cp vline, lastline brne BLANK ; no, wait for hsync end ldi vlineh, 0x00 ; yes, reset vert counters ldi vline, 0x00 ; cpi cursorClk, 0xff ; breq vs1 ; inc cursorClk ; inc cursor clock vs1: BLANK: ldi chrln, 0xFF ; reset pointer rjmp WAITSYNCEND ; graphics: ori ZH,0x28 rjmp WAITSYNCEND DISPLAY: mov J, chrln ; Get current display line lsr J ; divide by 8 lsr J ; lsr J ; J now contains the text line number (0..24) ; get attribute definition for current line ldi XL, 0xD0 ldi XH, 0x08 ; set to start of attribute SRAM add XL, J ld currLineAtt,X ; set the SRAM character pointer (X) to the start of the current line (chrln) ldi XL, 0x50 ; # chrs per line mul XL, J ; multiply by chrs per line ldi J, 0x01 ; offset to start of display add R1, J movw XL, R0 ; mov it to X reg ; set Z to point to base of font row ldi ZL, 0x00 ; ZL=0, ASCII code will be added for each character mov ZH, chrln ; ZH= current display line andi ZH, 0x07 ; do ZH MOD 8 ; If graphics then point to the graphics block font sbrc currLineAtt,ATT_GRAPHICS rjmp graphics ; Check if single or double height to be drawn sbrc currLineAtt,ATT_DBL_TOP lsr ZH ; If double height top then linecounter incremented at half speed sbrc currLineAtt,ATT_DBL_BOTTOM lsr ZH ; If double height bottom then linecounter incremented at half speed sbrc currLineAtt,ATT_DBL_BOTTOM ori ZH,0x04 ; Display bottom 4 lines if bottom of a double line ; Check if bold or normal font sbrs currLineAtt,ATT_BOLD ori ZH,0x20 ;0x20 (Normal) or 0x40 (Bold) sbrc currLineAtt,ATT_BOLD ori ZH,0x40 ;0x20 (Normal) or 0x40 (Bold) ; Check if 40 or 80 chars sbrs currLineAtt,ATT_80_CHAR_PER_LINE ori ZH, 0x10 ; add $1000 for offset to start of wide font table WAITSYNCEND: ; else wait sync pulse end lds J, TCNT1L ; cpi J, 0x5A brlo WAITSYNCEND ; no, look again ; Get exact sync with clock (remove jitter) lds J, TCNT1L cpi J, 0x5C breq syncEnd0 cpi J, 0x5D breq syncEnd1 cpi J, 0x5E breq syncEnd2 cpi J, 0x5F breq syncEnd3 cpi J, 0x60 breq syncEnd4 cpi J, 0x61 breq syncEnd5 cpi J, 0x62 breq HSYNCEND nop nop nop syncEnd0: nop nop nop syncEnd1: nop nop nop syncEnd2: nop nop nop syncEnd3: nop nop nop syncEnd4: nop nop nop syncEnd5: nop nop nop ; Timer now always 0x72 at this point HSYNCEND: sbi portb, syncpin ; raise sync (approx 4.7uS hsync pulse) cpi chrln, 0xFF ; are we on an active display line? brne WAITVISIBLEPORTION ; yes, active display line rjmp EOL ; no, blank line, we're done WAITVISIBLEPORTION: ldi J,0 leftBlank: inc J cpi J,42 brlo leftBlank in J,PORTC ; read current port C mov temp1s,J ; store in temp andi J, 0xF7 ; Clear sh/ld bit mov temp0s,J ; store in temp ; Check if 40 or 80 chars per line to be drawn sbrs currLineAtt,ATT_80_CHAR_PER_LINE rjmp DRAWLINE40 rjmp DRAWLINE80 DRAWLINE80: ; ; each line consists of 80 macro calls, each 8 clocks long. Here is the macro: .macro DispChr ; ; gets the font byte of the current character and outputs it to the shift register ; ; 8 clocks ld ZL, X+ ; 2 move curr chr in ZL lpm J, Z ; 3 get font byte for current chr on curr line out PORTD, J ; 1 out PORTC, temp0s ; 1 lower load pin out PORTC, temp1s ; 1 raise load pin .endmacro DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr DispChr ; display 1 chr jmp EndOfChars DRAWLINE40: nop ; Exact sync with 80 char lines ; ; each line consists of 40 macro calls, each 16 clocks long. Here is the macro: .macro DispChrWide ; ; gets the two font bytes of the current character and output them to the shift register ; ; 16 clocks ld ZL, X+ ; 2 move curr chr in ZL lpm J, Z ; 3 get left half font byte for current chr on curr line out PORTD, J ; 1 out PORTC, temp0s ; 1 lower load pin out PORTC, temp1s ; 1 raise load pin ori ZH, 0x08 ; 1 get next font page lpm J, Z ; 3 get right half font byte for current chr on curr line andi ZH, 0xF7 ; 1 get back to first font page out PORTD, J ; 1 out PORTC, temp0s ; 1 lower load pin out PORTC, temp1s ; 1 raise load pin .endmacro DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr DispChrWide ; display 1 wide chr EndOfChars: inc chrln ; inc line counter EOL: ; end of line, we're done inc vline ; inc vertical line counter brne eol1 inc vlineh ; eol1: pop J out SREG,J pop J pop ZH pop ZL pop accH pop acc reti ; all done, go back to main program