;*************************************************************************** ;* vidgen.ASM ;* ;*************************************************************************** .DEVICE AT90S1200 ; 8.00 Mhz ;*************************************************************************** ;* a few, very useful macros ;*************************************************************************** .LISTMAC .MACRO ADDI subi @0, -@1 .ENDMACRO ;skip next instruction if not equal to zero .MACRO skipne ;.SET _skipne = PC+2 brne PC+2 ;_skipne .ENDMACRO ;skip next instruction if carry set .MACRO skipcs ;.SET _skipcs = PC+2 brcs PC+2 ;_skipcs .ENDMACRO ;skip next instruction if carry clear .MACRO skipcc ;.SET _skipcc = PC+2 brcc PC+2 ;_skipcc .ENDMACRO ;skip next instruction if equal to zero .MACRO skipeq ;.SET _skipeq = PC+2 breq PC+2 ;_skipeq .ENDMACRO ;skip next instruction if lower .MACRO skiplo ;.SET _skiplo = PC+2 brlo PC+2 ;_skiplo .ENDMACRO ;skip next instruction if half carry set .MACRO skiphs ;.SET _skiphs = PC+2 brhs PC+2 ;_skiphs .ENDMACRO ;skip next instruction if half carry clear .MACRO skiphc ;.SET _skiphc= PC+2 brhc PC+2 ;_skiphc .ENDMACRO ;skip next instruction if T set .MACRO skipts ;.SET _skipts = PC+2 brts PC+2 ;_skipts .ENDMACRO ;skip next instruction if T clear .MACRO skiptc ;.SET _skiptc = PC+2 brtc PC+2 ;_skiptc .ENDMACRO ;wait two cycles but waste only one instruction .MACRO doublenop ;.SET _doublenop = PC+1 rjmp PC+1 ;_doublenop .ENDMACRO ;include AT90S1200 registers definitions .include "1200def.inc" ;include font definitions ;fonts are stored in a EEPROM table, edit fonth.inc to modify it as you wish .include "fonth.inc" ;*************************************************************************** ;* VARIABLE ASSIGNEMENTS ;*************************************************************************** .CSEG .def SaveStatus = r0 ;status buffer during interrupts .def XX= r1 .def ct50hz = r14 ; .def PixelMask = r16 .def RowsModFour = r17 ;raster rows counter, split in two for .def RowsDivFour = r18 ;convenience of use. Counts up to 312 .def Arg1 = r19 ;Temp variable used by interrupt .def Arg2 = r20 ; " " " " .def Arg3 = r21 ; " " " " .def Arg4 = r22 ; .def Arg5 = r23 ; .def MiscFlags = r26 ;Assorted flags ;bit 0,1: position (0-1) of interrupt ;identifies wich of the two line position ;we are on (1=end of line, 0=sync pulse) when ;an interrupt occurs ;used by timer interrupt routine ;flags bit definition .equ Position1Bit = 0 .equ Position2Bit = 1 .equ POSITIONMASK = 1 ;3 .def CurrHeight = r30 ;character height (running counter) ;*************************************************************************** ;* Constants ;*************************************************************************** .equ DisplayRow = 150/4 ;counter value for display start .equ StartRetrace = (312/4)-1;counter value at wich retrace starts .equ StopRetrace = (312/4) ;maximum counter value ;*************************************************************************** ;* Port Pin Assignements ;*************************************************************************** ;port D bit definitions (OUTPUTS) .equ CSyncBit = 0 ;set video output to composite sync level when low .equ VideoBit = 1 ;set video level to white when high, black when low ;port B bit definitions (INPUTS) ;*************************************************************************** ;* VECTORS ;*************************************************************************** rjmp RESET ;Reset Handle rjmp RESET ;Ext. interrupt request 0 rjmp TIMER ;Timer ;*************************************************************************** ;* ;* MAIN PROGRAM ;* ;*************************************************************************** ;* INITAILIZATION ;*************************************************************************** RESET: clt ;clear T bit flag ;VERY important: ;clear T flag, here used to ;verify if we were sleeping ldi Arg1, 0b01111111 ;set port D bits to outputs out DDRD, Arg1 ldi Arg1, 0b00000001 ;preset output state out PortD, Arg1 ldi Arg1, 0b00000000 ;set port B to inputs out DDRB, Arg1 ldi Arg1, 0b11111111 ;turn on pullups on inputs out PortB, Arg1 ldi Arg1, 1 out TCCR0, Arg1 ;dont'use timer prescaler ldi Arg1, 32 out MCUCR, Arg1 ;enable sleep idle mode ldi Arg1, 2 out TIMSK, Arg1 ;enable timer interrupt ldi CurrHeight, 8 ldi MiscFlags, 1 clr PixelMask clr Arg1 ;and clear interrupt variables clr Arg2 clr Arg3 sei ;at last, allow interrupts ;*************************************************************************** ;* MAIN LOOP ;*************************************************************************** FOREVER: rjmp FOREVER ;**************************************************************************** ;* ;* Timer Interrupt: occurs four times in each video line. ;* The Position records which of four interrupt stages we are on. ;* At the third stage, we go in sleep mode, in order to have constant ;* servicing time for the fourth, crucial interrupt were we will output ;* the sync waveform. ;* This is the very heart of sync generation. ;* ;**************************************************************************** TIMER: ;if we were sleeping, then this is a synchronizing cycle: just return brtc TIMER_NOSLEEP ;if T cleared, do timer routine reti ;otherwise return (sync sleep) TIMER_NOSLEEP: in SaveStatus, SREG breq WAITNEWLINE ;if Position = 0 then wait (sleeping) for new line TIMER_EXIT: out SREG, SaveStatus ;otherwise do nothing reti WAITNEWLINE: set ;set T flag to tell we are sleeping sei ;re-enable interrupts, otherwise we sleep forever! sleep ;wait sleeping the next timer interrupt ;(during sleep we have constant interrupt recovery time) cli ;disable further interrupts NEWLINE: ;when awaken, we will restart here ori MiscFlags, 1 ;reset position index in Arg1, PortD ;read previous CSync level ldi Arg2, 0b00000001 ;load mask for toggle csync bit TOGGLESYNC: eor Arg1, Arg2 ;toggle CSync output out PortD, Arg1 ;now we are in the horizontal sync pulse HOUSEKEEPING: ;once in horizontal sync pulse space, we have ;enough time to do some housekeeping routines... inc RowsModFour ;increment row counters cpi RowsModFour, 4 ;if RowsModFour == 4 skipne inc RowsDivFour ;then increment RowsDivFour andi RowsModFour, 0b00000011 ;clear anyway bit 2 CHECKLASTLINE: ;when at last line, the sync pulse is stretched to half line cpi RowsDivFour, StopRetrace ;if at last line skiplo rjmp LASTLINE ;do a long pulse WAITSYNCEND: ;else wait sync pulse end in Arg1, TCNT0 ;note that now we are perfectly in cpi Arg1, 32 ;sync with timer. 64 = 4 uS brlo WAITSYNCEND ldi Arg2, 0b00000001 ;prepare mask for csync toggle VERTICALRETRACE: ldi Arg1, StartRetrace cpi RowsModFour, 0 ;if at start of vertical retrace pulse cpc RowsDivFour, Arg1 brne HSYNCEND ;then leave CSync low ldi Arg2, 0 HSYNCEND: in Arg1, PortD ; eor Arg1, Arg2 ;toggle CSync output out PortD, Arg1 ;now we are in the color burst space tup2: clt ;restore T to low level used by interrupt WAITVISIBLEPORTION: in Arg1, TCNT0 ;wait for start of visible area cpi Arg1, 85 ;increasing this moves display right brlo WAITVISIBLEPORTION rjmp BUILDSCREEN ;go to display building table LASTLINE: ;this is a good time to make slow (1/50 sec.) housekeepings, ;or to do things that are made once every screen picture mov arg1,ct50hz inc arg1 mov ct50hz,arg1 noend: clr RowsDivFour ;reset row counters clr RowsModFour WAITHALFLINE: in Arg1, TIFR ;wait for two timer overflows sbrs Arg1, TOV0 ;(each overflow is a quarter line) rjmp WAITHALFLINE ldi Arg1, EXP2(TOV0) ;reset timer overflow bit out TIFR, Arg1 SECONDQUARTER: in Arg1, TIFR ;wait second overflow sbrs Arg1, TOV0 ; rjmp SECONDQUARTER ldi Arg1, EXP2(TOV0) ;reset timer overflow bit out TIFR, Arg1 andi MiscFlags, 0b11111101 ori MiscFlags, 0b00000001 ;and align position counter (1) sbi PortD, CSyncBit ;and end composite sync rjmp TIMER_EXIT ;**************************************************************************** ;* SCREEN MAKEUP JUMP STRUCTURE ;* This compare and jump table determines the appearence of the display ;* at each step, the current line number is examinated to decide ;* which display routine to use ;**************************************************************************** BUILDSCREEN: ;it's time to decide what to display, depending on current line cpi RowsDivFour, 256/4 ;from line 256 on, blank display brlo _A1 rjmp VOIDLINE _A1: cpi RowsDivFour, 88/4 ;64 lines brlo _A2 rjmp VOIDLINE _A2: cpi RowsDivFour, 84/4 ;64 lines brne _A3 rcall eightnop rcall eightnop doublenop ldi Arg1,6 rjmp DISPLAYDIGITS _A3: cpi RowsDivFour, 80/4 ;64 lines brne _A4 rcall eightnop doublenop doublenop doublenop nop ldi Arg1,5 rjmp DISPLAYDIGITS _A4: cpi RowsDivFour, 76/4 ;64 lines brne _A5 rcall eightnop doublenop doublenop ldi Arg1,4 rjmp DISPLAYDIGITS _A5: cpi RowsDivFour, 72/4 ;64 lines brne _A6 rcall eightnop nop ldi Arg1,3 rjmp DISPLAYDIGITS _A6: cpi RowsDivFour, 68/4 ;64 lines brne _A7 doublenop doublenop doublenop ldi Arg1,2 rjmp DISPLAYDIGITS _A7: cpi RowsDivFour, 64/4 ;64 lines brne _A8 doublenop nop ldi Arg1,1 rjmp DISPLAYDIGITS _A8: cpi RowsDivFour, 60/4 ;64 lines brne _A9 ldi Arg1,0 rjmp DISPLAYDIGITS _A9: VOIDLINE: clr PixelMask ;reset pixel mask rjmp TIMER_EXIT eightnop: nop ret ;**************************************************************************** ;* ON SCREEN DISPLAY ROUTINES ;**************************************************************************** DISPLAYDIGITS: ldi Arg4,7 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR add Arg1,Arg4 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR add Arg1,Arg4 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR add Arg1,Arg4 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR add Arg1,Arg4 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR add Arg1,Arg4 out EEAR, Arg1 ;set eeprom address register sbi EECR, 0 ;send read command in Arg3, EEDR ;read font table in EEPROM rcall DISPLAYCHAR rjmp DISPLAYLINERESTART ;end line DISPLAYCHAR: mov Arg5,Arg3 andi Arg5,0b10000000 ;mask unwanted pixels skipeq sbi PortD, VideoBit ;...turn pixel off skipne ;according to table cbi PortD, VideoBit ;turn pixel on or... mov Arg5,Arg3 andi Arg5,0b01000000 ;mask unwanted pixels skipeq sbi PortD, VideoBit ;...turn pixel off skipne ;according to table cbi PortD, VideoBit ;turn pixel on or... mov Arg5,Arg3 andi Arg5,0b00100000 ;mask unwanted pixels skipeq sbi PortD, VideoBit ;...turn pixel off skipne ;according to table cbi PortD, VideoBit ;turn pixel on or... mov Arg5,Arg3 andi Arg5,0b00010000 ;mask unwanted pixels skipeq sbi PortD, VideoBit ;...turn pixel off skipne ;according to table cbi PortD, VideoBit ;turn pixel on or... mov Arg5,Arg3 andi Arg5,0b00001000 ;mask unwanted pixels skipeq sbi PortD, VideoBit ;...turn pixel off skipne ;according to table cbi PortD, VideoBit ;turn pixel on or... doublenop ;last pixel, waste time... doublenop cbi PortD, VideoBit ;turn pixel off ret ;**************************************************************************** ;* Official line exit point for all display routines ;**************************************************************************** DISPLAYLINERESTART: ldi Arg1, EXP2(TOV0) ;clear timer overflow bit out TIFR, Arg1 ; rjmp WAITNEWLINE