;.DEVICE ATMEGA8 ; ; ; ; ;screen is 64 pixels wide, 3 colors (black, gray, white), 2 bits per pixel, 16 bytes per line ; .NOLIST .INCLUDE "m8def.inc" .LIST .LISTMAC ;--EQUs------------------------------------------------------------------------ .EQU videoport = PORTD .EQU videoport_dir = DDRD .EQU NTSC_sync_val = 0 .EQU NTSC_black_val = 1 .EQU NTSC_gray_val = 2 .EQU NTSC_white_val = 3 .DEF NTSC_sync = R16 .DEF NTSC_black = R17 .DEF NTSC_gray = R18 .DEF NTSC_white = R19 ;--MACROS---------------------------------------------------------------------- .MACRO outputOneVideoByte ld R0, Z+ ; (2 clocks) out videoport, R0 lsr R0 lsr R0 out videoport, R0 lsr R0 lsr R0 out videoport, R0 lsr R0 lsr R0 out videoport, R0 ; (block takes 3us) .ENDMACRO .MACRO delay1us nop nop nop nop .ENDMACRO .MACRO repeat2 @0 .SET repeatcounter = repeatcounter - 1 .IF repeatcounter != 0 repeat2 @0 .ENDIF .ENDMACRO .MACRO repeat .SET repeatcounter = @1 repeat2 @0 .ENDMACRO ;--CODE------------------------------------------------------------------------ .CSEG .ORG 0x0000 RJMP progstart progstart: ; setup stack ldi R16, high(stacktop) out SPH, R16 ldi R16, low(stacktop) out SPL, R16 ;rcall delay100us ;rcall delay1ms ;rcall delay10ms ; turn off all PORTC outputs clr R16 out videoport, R16 ; set PORTC.0 and PORTC.1 to outputs ldi R16, 0xFF out videoport_dir, R16 ; copy video data to screen memory ; dest ldi XH, high(vram) ldi XL, low(vram) ; src ldi ZH, high(videodata << 1) ; shift left since flash is accessed 16-bit ldi ZL, low(videodata << 1) ; low byte determines high or low byte of result ; copy 256 * 3 bytes clr R16 ldi R17, 3 copyloop: lpm R0, Z+ st X+, R0 dec R16 brne copyloop dec R17 brne copyloop ; initialize registers with values to save clocks later using "out" ldi NTSC_sync, NTSC_sync_val ; R16 ldi NTSC_black, NTSC_black_val ; R17 ldi NTSC_gray, NTSC_gray_val ; R18 ldi NTSC_white, NTSC_white_val ; R19 ; initialize individial line loop counter ldi R20, 4 ; initialize screen lines loop counter ldi R21, 192 ; initialize equalization/serration pulse counter ldi R22, 6 ; set video memory for upper portion of SRAM (needs 768 bytes) ldi ZH, high(vram) ldi ZL, low(vram) ;testloop: ;out videoport, NTSC_sync ;repeat rcall delay100ms, 10 ;out videoport, NTSC_black ;repeat rcall delay100ms, 10 ;out videoport, NTSC_gray ;repeat rcall delay100ms, 10 ;out videoport, NTSC_white ;repeat rcall delay100ms, 10 ;rjmp testloop field_start: ;equalization pulse ;------------------ ;(31.75us * 2) ;enable sync (takes 0.25us) ;4 nop, 4 nop, 1 nop(2.25us) ;disable sync, enable blanking (takes 0.25us) ;* 29us blanking * eqpulses1_start: out videoport, NTSC_sync rcall delay2us nop out videoport, NTSC_black rcall delay10us rcall delay10us rcall delay4us rcall delay4us dec R22 breq eqpulses1_complete ; (2 cycles if equal, 1 if not) rjmp eqpulses1_start ; (2 cycles) eqpulses1_complete: ldi R22, 6 ; (1 cycle) ;serration pulse ;--------------- ;(31.75us * 2) ;enable sync (takes 0.25us) ;* 29us sync * ;disable sync, enable blanking (takes 0.25us) ;4 nop, 4 nop, 1 nop (2.25us) serrpulses_start: out videoport, NTSC_sync rcall delay10us rcall delay10us rcall delay4us rcall delay4us delay1us out videoport, NTSC_black delay1us nop dec R22 breq serrpulses_complete ; (2 cycles if equal, 1 if not) rjmp serrpulses_start ; (2 cycles) serrpulses_complete: ldi R22, 6 ; (1 cycle) ;equalization pulse 2 ;-------------------- eqpulses2_start: out videoport, NTSC_sync rcall delay2us nop out videoport, NTSC_black rcall delay10us rcall delay10us rcall delay4us rcall delay4us dec R22 breq eqpulses2_complete ; (2 cycles if equal, 1 if not) rjmp eqpulses2_start ; (2 cycles) eqpulses2_complete: ldi R22, 6 ; (1 cycle) ; finish vsync/init ;------------------ ; start first line manually to reset some counters out videoport, NTSC_sync ; (hsync 4.75us) rcall delay4us repeat nop, 2 out videoport, NTSC_black ; (back porch 4.75us) rcall delay4us repeat nop, 2 ; do video (52.5us) rcall delay10us rcall delay10us rcall delay10us rcall delay10us rcall delay10us delay1us nop nop ; re-initialize individial line loop counter ldi R20, 4 ; re-initialize screen lines loop counter ldi R21, 192 ; reset video memory for upper portion of SRAM (needs 768 bytes) ldi ZH, high(vram) ldi ZL, low(vram) ; front porch (1.5us) nop nop nop ; stop 3 short for next rcall ; do other 10 lines of vsync repeat rcall drawblankline, 10 ; draw 25 overscan/border lines repeat rcall drawblankline, 10 repeat rcall drawblankline, 10 repeat rcall drawblankline, 5 ; nops to fill in the 3 missing in last drawblankline nop nop nop ;draw active video ;----------------- ;horizontal scanline ;------------------- ;enable sync (takes 0.25us) ;wait (4.5us) ;disable sync, enable blanking/black (takes 0.25us) ;wait (4.5us) ;* 52.5us of video * ;enable blanking (takes 0.25us) ;wait (1.25us) hline_start: ; do hsync out videoport, NTSC_sync delay1us delay1us nop ; used to reset Z pointer during horizontal retrace for repeated lines ; makes each pixel 4 lines tall cpi R20, 4 ; check if we're on 1st of 4 lines brne hline_resetZ nop rjmp hline_dopixelheight hline_resetZ: sbiw ZH:ZL, 16 ; if not, go back 16 bytes to repeat line hline_dopixelheight: ; used to reset line counter dec R20 breq hline_resetpixelheight ; 2 cycles if equal, 1 if not rjmp hline_backporch ; 2 cycles hline_resetpixelheight: ldi R20, 4 ; 1 cycle hline_backporch: ; do back porch out videoport, NTSC_black rcall delay4us nop nop ; do video portion (52.5us) nop ; left border/overscan delay1us delay1us repeat outputOneVideoByte, 8 repeat outputOneVideoByte, 8 out videoport, NTSC_black ; right border/overscan delay1us delay1us ; do front porch (1.5us) ;out videoport, NTSC_black ; check if on line 192, break out if so dec R21 breq video_endcontent nop nop rjmp hline_start video_endcontent: ; finishes the previous front porch ;nop ;nop ;nop ; do bottom border/overscan, 25 lines repeat rcall drawblankline, 15 repeat rcall drawblankline, 10 nop rjmp field_start ;------------------------------------------------------------------------------ drawblankline: ; do hsync out videoport, NTSC_sync rcall delay4us repeat nop, 2 out videoport, NTSC_black rcall delay4us repeat nop, 2 ; do video (normally 52.5us, cut short 0.5us) rcall delay10us rcall delay10us rcall delay10us rcall delay10us rcall delay10us rcall delay2us ; front porch (1.5us) nop ret ;nop ; omit these nops for the next rcall duration ;nop ;nop ;------------------------------------------------------------------------------ ; rcall these delay2us: nop ret delay4us: nop rcall delay2us ret delay10us: nop rcall delay4us rcall delay4us ret delay50us: nop repeat rcall delay10us, 4 rcall delay4us rcall delay4us ret delay100us: nop repeat rcall delay10us, 9 rcall delay4us rcall delay4us ret delay500us: nop repeat rcall delay100us, 4 rcall delay50us repeat rcall delay10us, 4 rcall delay4us rcall delay4us ret delay1ms: nop ; 1us so far repeat rcall delay100us, 9 ; + 900us rcall delay50us ; + 50us repeat rcall delay10us, 4 ; + 40us repeat rcall delay4us, 2 ; + 8us ret ; + 1us delay10ms: nop ; 1us so far repeat rcall delay1ms, 9 ; + 9000us rcall delay500us ; + 500us repeat rcall delay100us, 4 ; + 400us rcall delay50us ; + 50us repeat rcall delay10us, 4 ; + 40us (9991 so far) repeat rcall delay4us, 2 ; + 8us (9999 so far) ret delay100ms: nop repeat rcall delay10ms, 9 repeat rcall delay1ms, 9 rcall delay500us repeat rcall delay100us, 4 rcall delay50us repeat rcall delay10us, 4 repeat rcall delay4us, 2 ret ;------------------------------------------------------------------------------ videodata: .db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$F5,$77,$F7,$F5,$F7,$F5,$F7,$F7,$77,$57,$55,$55,$D5 .db $57,$55,$55,$75,$75,$77,$77,$75,$D7,$75,$75,$75,$57,$55,$55,$D5 .db $57,$55,$55,$F5,$F5,$F7,$F5,$F5,$D5,$F5,$75,$F5,$57,$55,$55,$D5 .db $57,$55,$55,$75,$D5,$75,$77,$75,$D7,$75,$75,$75,$57,$55,$55,$D5 .db $57,$55,$55,$75,$D5,$F5,$F5,$77,$D7,$F5,$F7,$77,$57,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$A5,$66,$A6,$A5,$A6,$A5,$A6,$A6,$66,$56,$55,$55,$D5 .db $57,$55,$55,$65,$65,$66,$66,$65,$96,$65,$65,$65,$56,$55,$55,$D5 .db $57,$55,$55,$A5,$A5,$A6,$A5,$A5,$95,$A5,$65,$A5,$56,$55,$55,$D5 .db $57,$55,$55,$65,$95,$65,$66,$65,$96,$65,$65,$65,$56,$55,$55,$D5 .db $57,$55,$55,$65,$95,$A5,$A5,$66,$96,$A5,$A6,$66,$56,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $57,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$55,$D5 .db $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ;------------------------------------------------------------------------------ .DSEG .ORG (0x0000 + 0x60) stackbottom: .byte 256 .ORG (0x00FF + 0x60) stacktop: .ORG (0x0100 + 0x60) vram: .byte 768