;
; hello.video.44.asm
; 
; NTSC/RS170 video hello-world
;
; set fuse low byte to 0x76 for 20 MHz resonator
;
; Neil Gershenfeld
; CBA MIT 11/18/07
;
; (c) Massachusetts Institute of Technology 2007
; Permission granted for experimental and personal use;
; license for commercial sale available from MIT.
;
.include "tn44def.inc"
;
; definitions
;
.equ pin_499 = PA7 ; 499 ohm DAC pin
.equ pin_1000 = PA6 ; 1000 ohm DAC pin
;
; registers
;
.def zero = R0 ; 0V
.def black = R1 ; .306V for 499,1k DAC
.def gray = R2 ; .613V for 499,1k DAC
.def white = R3 ; .919V for 499,1k DAC
.def temp = R16 ; temp variable
.def temp1 = R17 ; temp variable
.def row_counter = R18 ; row counter
.def col_counter = R19 ; col counter
; R30, 31 used for z pointer
;
; macros
;
.macro count
   ;
   ; delay counter
   ;
   ldi temp, @0 ; set match count
   ldi temp1, @1 ;
   out OCR1AH, temp ;
   out OCR1AL, temp1 ;
   clr temp ; clear counter
   out TCNT1H, temp ;
   out TCNT1L, temp ;
   sbi TIFR1, OCF1A ; clear count match flag
   count_loop:
      sbis TIFR1, OCF1A
      rjmp count_loop
   .endmacro
.macro 0V
   ;
   ; output 0V
   ;
   out PORTA, zero
   .endmacro
.macro black
   ;
   ; output black level
   ;
   out PORTA, black
   .endmacro
.macro horizontal_sync
   ;
   ; 4.7us horizontal sync
   ;
   count 0,82
   .endmacro
.macro front_porch
   ;
   ; off-screen beginning of scan line
   ;
   count 0,130
   .endmacro
.macro scan_line
   ;
   ; 58.8us complete scan line
   ;
   count 4,142
   .endmacro
.macro back_porch
   ;
   ; off-screen end of scan line
   ;
   count 0,70
   .endmacro
.macro blank_line
   ;
   ; blank horizontal scan line
   ;
   0V
   horizontal_sync
   black
   scan_line
   .endmacro
.macro sync_line
   ;
   ; vertical sync line
   ;
   ; inverted horizontal sync
   ;
   black
   horizontal_sync
   ;
   ; inverted scan line
   ;
   0V
   scan_line
   .endmacro
;
; code segment
;
.cseg
.org 0
rjmp reset
;
; main program
;
reset:
   ;
   ; set clock divider to /1
   ;
   ldi temp, (1 << CLKPCE)
   ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0)
   out CLKPR, temp
   out CLKPR, temp1
   ; 
   ; set counter prescaler to /1
   ;
   ldi temp, (1 << CS10)
   out TCCR1B, temp
   ;
   ; set stack pointer to top of RAM
   ;
   ldi temp, high(RAMEND)
   out SPH, temp
   ldi temp, low(RAMEND)
   out SPL, temp
   ;
   ; init DAC pins
   ;
   cbi PORTA, pin_499
   sbi DDRA, pin_499
   cbi PORTA, pin_1000
   sbi DDRA, pin_1000
   ;
   ; set DAC value registers
   ;
   ldi temp, 0
   mov zero, temp
   ldi temp, (1 << pin_1000)
   mov black, temp
   ldi temp, (1 << pin_499)
   mov gray, temp
   ldi temp, ((1 << pin_499) | (1 << pin_1000))
   mov white, temp
   ;
   ; store test pattern in SRAM
   ;
   ldi zl, low(SRAM_START)
   ldi zh, high(SRAM_START)
   ldi col_counter, 40
   store_loop:
      st z+, black
      st z+, gray
      st z+, black
      st z+, white
      dec col_counter
      brne store_loop
   ;
   ; start main loop
   ;
   main_loop:
      ;
      ; 242 63.5us horizontal scan lines
      ;
      ldi row_counter, 242
      row_loop:
         0V
	 horizontal_sync
	 black
	 front_porch
	 ;
	 ; set z to point to test pattern
	 ;
         ldi zl, low(SRAM_START)
         ldi zh, high(SRAM_START)
	 ;
	 ;  column loop
	 ;
	 ldi col_counter, 160
	 col_loop:
	    ld temp, z+
	    out PORTA, temp
	    dec col_counter
	    brne col_loop
 	 black
	 back_porch
         dec row_counter
         breq row_loop_continue
	    rjmp row_loop
      row_loop_continue:
      ;
      ; 5 black lines
      ;
      ldi row_counter, 5
      black_loop:
         0V
	 horizontal_sync
         black
	 scan_line
         dec row_counter
         brne black_loop
      ;
      ; 3 vertical sync lines
      ;
      ldi row_counter, 3
      sync_loop:
         sync_line
         dec row_counter
         brne sync_loop
      ;
      ; 12 black lines
      ;
      ldi row_counter, 12
      black_loop1:
         0V
	 horizontal_sync
         black
	 scan_line
         dec row_counter
         brne black_loop1
      ;
      ; 60Hz main loop
      ;
      rjmp main_loop

