; *****************************************
;
; Вход * A3754
;
; Генератор наложения видеоизображений, используя avr2313
;
; 15 мая 2004 - 29 июня 2004
;
;
;
; *****************************************

.include "2313def.inc"

.equ RAMSTART=$60
.equ XChars=20; Символы в row
.equ YChars=6; Строки в экран
.equ ENDDISP=235; длитесь row, чтобы отобразить, это работает хорошо
.equ STARTDISP=ENDDISP-YChars*8; row start на, отступить
.equ MAXDISPADD = (XChars*YChars-1) +RAMSTART; последнее ОЗУ, используемое disp
.equ Fiveus=16; 4.8 нас задерживаются в 10 МГЦ
.equ Tenus=33; 9.9 нас задерживаются в 10 МГЦ
;. equ Fiveus=28; 5.8 нас задерживаются в 14.31818 МГЦ
;. equ Tenus=64; 13.4 нас задерживаются в 14.31818 МГЦ
.equ BPS96=64; 9600 битов в секунду в 10 МГЦ
;. equ BPS96=92; 9600 битов в секунду в 14.31818 МГЦ
.equ TMR80=100; переполнение в 80 нас
.equ RingStart=RAMSTART+XChars*YChars; НАЧАЛО Кольцевого Буфера
.equ RingLength=4; 4 байта
.equ HiAddBit = (1 <<2); set hi обращается к биту для поиска таблицы символа
.equ VideoBit=7; Бит PORTB, где видео выходит
.equ VideoOn=$80; включить видео вывод
.equ VideoOff=$00; на пустой дисплей
.equ BlnkBit=6; бит порта для кнопки гашения

.def VidOut=r0; видео регистр вывода
.def RingStatus=r1; Кольцевое Буферное состояние
	; полубайт low считает ptr к символу next вставлять
	; полубайт hi держит номер символов стыком in
.def CursorX=r2; Наш курсор дисплея X
.def CursorY =r3; и Y
.def TEMP3=r4; другой временный Редж
.def TEMP4=r5; и другой
.def TEMP5=r6
.def TEMP6=r7
.def TEMP7=r21
.def ScrollF=r9; мы листаем?
.def RowIncL=r13; держится low оценивает add к счету{графу} row
.def RowIncH=r14; размещать row в надлежащие биты адреса
.def SREG_Save=r15; разместите, чтобы поместить SREG
.def TEMP1=r16; Misc временный Редж
.def TEMP2=r17; Misc временный Редж

.def VSFlag=r18; пометьте синхронизацию vert
.def LineCnt=r19; счетчик строки
.def CharCnt=r20; символы на строке
.def RowCntLow=r23; row символа, чтобы отобразить
.def RowCntHi=r24; часть high

.org 0
rjmp RESET
.org OVF0addr; Таймер 0 переполнения int
rjmp TIM0INT
.org ACIaddr; прерывание компаратора
rjmp COMPINT

; **********************************************************************
; Вот - основная программа. После инициализации всего, мы входим 
; ждущий цикл. Мы будем идти, чтобы бездействовать и ждать запроса на прерывание. Это могло быть
; любой аналоговый компаратор (синхронизирующий обнаруженный импульс) or timer0 
; (переполнитесь, потому что никакая синхронизация не обнаруживала in 80 нас. Каждый запрос на прерывание обработан
; accoringly. После того, как irq обслуживается, мы проверим{отметим} универсальный асинхронный приемопередатчик и доберемся
; любой полученный символ. Тогда, если мы имеем время, мы обработаем символы
; in кольцевой буфер. Это только случается, являемся ли мы больше чем пара 
; строки далеко от видео поколения{порождения}, чтобы не вмешиваться.
; **********************************************************************

RESET:; Начало основной программы
ldi TEMP1, low (RAMEND)
SPL, TEMP1; стек set ptr
ldi TEMP1, VideoOn; pb7 vid, ввод других
ddrb, TEMP1
ldi TEMP1,$3e; pd1-5 hi, 6 (строб) low
PORTD, TEMP1
ldi TEMP1,$7e; pd1-6 выводы
ddrd, TEMP1
;;
; init row increment pointer
ldi TEMP1,$80; add 128 row каждый раз
mov RowIncL, TEMP1
clr RowIncH
; Буфер Кольца set, чтобы опустеть
clr temp1; numchars=0, next extract=0
clr ScrollF
; set экран буферизует и X pointer
ldi XL, low (RAMSTART); укажите на первый символ
clr XH
clr CursorX
clr CursorY
;
; и кольцевой буфер
clr RingStatus
;
; очистите экран, и дисплей входит в систему сообщение
ldi YL, low (RAMSTART)
clr YH
ldi TEMP1, (XChars*YChars); Заполните Экран
ldi TEMP2,32; с пространствами{пробелами}
LOADRAM:
C-Y +, TEMP2
dec TEMP1
brne LOADRAM

ldi YL, low (RAMSTART); дисплей входит в систему сообщение
clr YH
ldi ZL, low (SIGNONMSG <<1); получите сообщение
ldi ZH, high (SIGNONMSG <<1); <<1 из-за адресов слова
ВОЙДИТЕ В СИСТЕМУ: lpm
adiw ZL, 1
C-Y +, VidOut
 
tst VidOut; войдите в систему сообщение, закончился нулевым{пустым} байтом
brne ВХОДЯТ В СИСТЕМУ
clr CursorX
clr CursorY
; Мы закончили входящийся в систему
;
;
; Сначала, set timer0, чтобы прервать каждые 80 or так мкс
; случай{регистр} in там не никакой видео подарок{настоящее} сигнала. Тем путем, мы
; может все еще получать символы от универсального асинхронного приемопередатчика без синхронизации
; прерывание
ldi TEMP1,2; отделение 8 предмасштабов
TCCR0, TEMP1
ldi TEMP1, (256-TMR80); переполнение в 80uS, подсчитывает
TCNT0, TEMP1
; 
; Теперь set последовательный порт для 9600 битов в секунду, никакое прерывание, хотя
; Это опросится на каждом прерывании, синхронизация переполнение таймера or
ldi TEMP1, BPS96; последовательный порт set 9600 битов в секунду
UBRR, TEMP1
ldi TEMP1,$10; включите rcv, допускают
UCR, TEMP1
;
; Теперь мы set бездействуем режим и допускаем надлежащим прерываниям
ldi TEMP1, (1 <<SE); допустите режиму бездействия
MCUCR, TEMP1
ldi TEMP1,$03; включите аккомпанемент int на повышении
ACSR, TEMP1
sbi ACSR, ACIE; допустите аккомпанементу irq
ldi TEMP1, (1 <<TOIE0); и таймер irq
TIMSK, TEMP1
sei; включите irq, и ждать
; **********************************************************************
; Это - то, где волшебство случается. Все остальное переходит здесь, чтобы ждать
; для прерывания start это снова и снова.
;
; **********************************************************************
NEXT: бездействие; когда мы пробуждение, мы сделаем irq, затем возвращаемся
sbis USR, 7; если символ rcvd, процесс
; rjmp NEXT
rjmp ProcessChar; ни один add, не обработайте то, что мы имеем
;
; ************************************************
; Это - код для Кольцевого Буфера
; ************************************************
 
; ************************************************
; поместите символ в буфер
; ************************************************
;
; Сначала, возвратите видео на том, если это был blanked
sbi DDRB, VideoBit
; Теперь получите символ
in TEMP1, UDR; получите символ
mov XL, RingStatus; вычислите pointer
andi XL, 3; используйте только биты low
ldi TEMP2, RingStart; получите смещение
add XL, TEMP2; Вот - адрес, наконец
C-X, TEMP1; поместите символ там.
ldi TEMP1, (1 <<4) |1; add один к каждому полубайту
add TEMP1, RingStatus
andi TEMP1,$73; маскируйте неиспользованные биты
mov RingStatus, TEMP1
; теперь мы должны видеть, имеем ли мы время, чтобы обработать символ
; если мы - в пределах 2 строк стартового видео or видео in
; мы не будем start, мы возвратимся, чтобы бездействовать и ждать
; иначе, мы только позволим прерываниям доставлять и брать примечание
; из них. Прокрутка и запрос на прерывание не смешиваются хорошо. Не использовать 
; TEMP1 в течение прокрутки, это уничтожит видео.
; Иначе, время ожидания не будет иметь значение, пока мы не отображаем.
; самый длинный путь - прокрутка, которая возьмет циклы NNN.
; Это - то, где 2 строки исходят
ProcessChar:
mov TEMP1, LineCnt; где - мы?
cpi TEMP1, STARTDISP-2; Нуждайтесь в 2 окнах строки
brlo PC1; не там все же, сделайте это
cpi TEMP1, ENDDISP; мы закончены?
brsh PC1; да, сделайте это
rjmp NEXT
PC1:; так, мы имеем время, давайте обрабатывать символ
; *********************************************
; получите символ из кольцевого буфера теперь
; *********************************************
tst ScrollF; Если мы листаем
brne NEXT; не обработать
mov TEMP1, RingStatus
swap TEMP1; сколько символов стык in?
andi TEMP1,$0f; только полубайт low
breq NEXT; ничто, чтобы сделать
; здесь мы должны найти, где извлечь символ
; Мы будем использовать эту формулу: (nextins-numchars) %4
; показывать нам, где in буфер это
mov TEMP2, RingStatus
andi TEMP2,$03; получите только nextins
sub TEMP2, TEMP1; temp2 = (nextins-numchars)
andi TEMP2,$03; модуль 4
ldi XL, RingStart; Добавьте in адрес start
add XL, TEMP2
ld TEMP2, X; Гмм! Теперь мы имеем символ
mov TEMP1, RingStatus; счет{граф} символа update
subi TEMP1, (1 <<4);-1 in полубайт hi
mov RingStatus, TEMP1
TESTDEST:
; OK, теперь temp2 держит символ, что сделать с этим?
cpi TEMP2,$20; Если пространство{пробел} or выше, дисплей
brlo CNTLCHAR; иначе обработайте cntl символ
andi TEMP2,$7f; маскируйте бит high
mov TEMP1, CursorY; Куда это идет?
lsl TEMP1; y*20
lsl TEMP1
mov TEMP3, TEMP1
lsl TEMP1
lsl TEMP1
add TEMP1, TEMP3; = *4 +*16
add TEMP1, CursorX
ldi XL, RAMSTART
add XL, TEMP1
C-X, TEMP2; поместите символ там
inc CursorX
ldi TEMP1, XChars; курсор update
cpse CursorX, TEMP1
rjmp NEXT
clr CursorX; это было 20, так cr, lf
inc CursorY
ldi TEMP1, YChars
cp CursorY, TEMP1; проверьте{отметьте} номер строки, также
brsh SCROLL
rjmp NEXT
; ********************************************************************
; Эта подпрограмма листает дисплей одна строка
; Это использует X, Y, TEMP1,2,3,4,7
; Требуется приблизительно 700 циклов (70uS в 10MHZ) и получит int'd
; но нужно только назвать{вызвать} когда никакая опасность прибытия строки дисплея
; так что прерывания считают строку и возвращение
; ScrollF помечает метки, когда мы - scrollingso, не называет{не вызывает} себя
; ********************************************************************
SCROLL:
; Листайте дисплей одна строка
inc ScrollF; Позвольте каждому знать, что мы листаем
mov TEMP5, XL; сохраните{экономьте} эти regs
mov TEMP6, YL
ldi TEMP7, ((YChars-1) *XChars); переместите все кроме первого row
ldi XL, RAMSTART 	; start 1-ой строки
ldi YL, RAMSTART+XChars; start 2-ой строки
SCROLL1:
ld TEMP4, Y+; получите это
C-X +, TEMP4; память это
dec TEMP7 	; счет{граф} это
brne SCROLL1 	; цикл, если не последний
; законченное перемещение
; ясная нижняя строка
ldi TEMP7,32; пространство{пробел}
mov TEMP4, TEMP1
ldi TEMP7, XChars; это много пространств{пробелов}
SCROLL2:
C-X +, TEMP4
dec TEMP7
brne SCROLL2
; теперь восстановите и выход
ldi TEMP7, (YChars-1); курсор set, чтобы длиться строка
mov CursorY, TEMP7
mov XL, TEMP5; восстановите X и Y
mov YL, TEMP6
dec ScrollF 	; Не больше
rjmp NEXT
CNTLCHAR:
; закодируйте здесь для символов управления
; если мы добираемся здесь, символ - <32 (пространство{пробел})
; ***********************************
; если символ - 16 - 31 (0x1x), выводят low 4 бита к порту
; d [2-5] и строб d6
cpi TEMP2,16
brlo CCBS; если это - меньше чем 16, не вывести
lsl TEMP2
lsl TEMP2; поместите это место права in
andi TEMP2, ($0f <<2); маскируйте другие биты
PORTD, TEMP2; биты, строб low
nop 	; замедлитесь для медленных чипов
nop
sbi PORTD, 6; строб set hi (после того, как 300ns задержка)
nop
nop
cbi PORTD, 6; и ясный это (после того, как 300ns задержка)
rjmp NEXT
;
; BackSpace
CCBS: cpi TEMP2,8; backspace
brne CCTAB
tst CursorX
breq CCBS1; если уже в start, выйти
dec CursorX
CCBS1: rjmp NEXT
;
; Tab
CCTAB: cpi TEMP2,9; табулируйте: останавливается каждый 4 (0,4,8,12,16,0)
brne CCLF
ldi TEMP7,4; табуляторы
add CursorX, TEMP7
ldi TEMP7,0b11111100; маскируйте 2 бита (mod 4)
и CursorX, TEMP7
tst CursorX; мы start новая строка?
brlo CCTAB1; нет, выход
clr CursorX; да, сбросьте X
inc CursorY; и перемещение к строке next
ldi TEMP7, YChars; сделайте мы должны листать
cp CursorY, TEMP7
breq SCROLL
CCTAB1: rjmp NEXT
;
; Перевод строки
 
CCLF: cpi TEMP2,10; перевод строки
brne CCVT
inc CursorY
ldi TEMP1, YChars
cpse TEMP1, CursorY
rjmp NEXT
rjmp SCROLL
;
; Вертикальный Tab, продвиньте одну строку
CCVT:
cpi TEMP2,11; вертикальная позиция табуляции, продвиньте одну строку
brne CCFF
tst CursorY
breq CCVT1; если не нуль уже, line=line-1
dec CursorY
CCVT1: rjmp NEXT
;
; Перевод страницы, ясный дисплей
CCFF: cpi TEMP2,12; перевод страницы
brne CCCR
cli; выключите прерывания, дольше чем 1 строка, regs затертый
 
clr CursorX; дом курсор
clr CursorY
ldi XL, low (RAMSTART); и ясный экран
ldi TEMP1, (XChars*YChars)
ldi TEMP2,32; пространства{пробелы} каждый, пространства{пробелы}
CCFF1: C-X +, TEMP2
dec TEMP1
brne CCFF1
sei; получите irq, который мы пропустили!
rjmp NEXT
;
; Перевод каретки
CCCR: cpi TEMP2,13; возвращение
brne CCOTH
clr CursorX
rjmp NEXT
 
CCOTH:
rjmp NEXT; значение по умолчанию

; **********************************************************************
; Ниже - подпрограммы прерывания. Есть два: один для таймера 0 
; переполниться, если никакая синхронизация не получена в пределах приблизительно 80 нас, и один ни для кого
; синхронизирующие импульсы, обнаруженные аналоговым компаратором.
; **********************************************************************
;
; **********************************************************************
; запрос на прерывание ПЕРЕПОЛНЕНИЯ ТАЙМЕРА
;
; Если переполнение timer0, мы прибываем сюда. Это означает, что никакая синхронизация не была
; принятый in приблизительно 80 нас. Так что мы просто сбросим таймер и 
; возвращение, позволяя другую логику обрабатывать универсальный асинхронный приемопередатчик для прихода
; символы
; **********************************************************************
TIM0INT: ldi TEMP1, (256-TMR80); 80 нас
TCNT0, TEMP1
ldi LineCnt, 0; и start в вершине, также
reti
 
; **********************************************************************
; запрос на прерывание КОМПАРАТОРА
;
; Это - основное прерывание от датчика компаратора/синхронизации
; Каждый раз там - синхронизирующий импульс (H or V), это называют{вызывают}
; Если синхронизация "напоминает" V, это просто возвращает or, если это - не дисплей
; выровнять, это просто возвращается
; Иначе, это выкладывает строку точек
; Это использует:  
; **********************************************************************
COMPINT:
; Сначала! СБРОСЬТЕ таймер, так что мы не делаем interrup на этом
ldi TEMP1, (256-TMR80)
TCNT0, TEMP1
; OK, теперь продолжите это.
in SREG_Save, SREG; сохраните{экономьте} состояние Редж
ldi TEMP1, Fiveus; 5us = 16*3/10mhz
DLYLP: dec TEMP1; ждите 5uS
brne DLYLP; видеть если vsync
sbic ACSR, ACO; проверьте{отметьте} это снова
rjmp WAIT_VSYNC; бит все еще set, так vsync:return
inc LineCnt; новая строка horiz
cpi LineCnt, STARTDISP; не отобразите до строки 25
brlo NODISPLAY
cpi LineCnt, ENDDISP; or, если больше чем 200
brpl NODISPLAY
ldi TEMP1, Tenus; не vsync, ждите 10us
DLYLP3: dec TEMP1
brne DLYLP3
ldi CharCnt, XChars; 16 символов
mov YL, LineCnt; который row символов является ли это?
subi YL, STARTDISP; sub смещение
andi YL, $f8; маскируйте low 3 бита
lsr YL; держит экран row * 4
mov TEMP1, YL
lsl YL; mult 4
lsl YL
add YL, TEMP1; row *16+row*4 *** ТОЛЬКО ДЛЯ 20 COLUMBS ***
ldi TEMP1, low (RAMSTART); add in смещал
add YL, TEMP1
mov ZH, RowCntHi; получите биты high row
ori ZH, 4; set верхний бит add
CHAROUT: ld ZL, Y+; получите символ next
or ZL, RowCntLow;; получите бит low row
lpm
PORTB, VidOut
lsl VidOut
PORTB, VidOut
lsl VidOut
PORTB, VidOut
lsl VidOut
PORTB, VidOut
lsl VidOut
PORTB, VidOut
lsl VidOut; предыдущие 5 битов - наш символ
PORTB, VidOut; этот должен быть 0, vid прочь
;
dec CharCnt
brne CHAROUT
add RowCntLow, RowIncL; inc row
adc RowCntHi, RowIncH
cpi RowCntHi, 4
brne EXIT_IRQ; выйдите, если не переполняются
clr RowCntLow
clr RowCntHi
EXIT_IRQ: SREG, SREG_Save
reti
;
; **********************************************************************
; Если синхронизирующий импульс длится дольше чем H-синхронизация, мы перейдем здесь и 
; предположить, что это - V-синхронизация. Из-за импульсов уравнивания в течение V-синхронизации
; это будут называть приблизительно 3 разами in row, но не будет иметь значение.
; Счетчик строки станет сброшенным, 3 раза, пустой выключатель доберутся 
; читать 3 раза, и это - об этом...
; **********************************************************************
WAIT_VSYNC: ldi LineCnt, 0; start назад в вершине, точно так же как телевидение!!!
sbi PORTB, BlnkBit; включите pullup
		; внутренний не был достаточно силен
		; так что 10k добавлялся внешним
ldi TEMP1, (1 <<BlnkBit)
PORTB, TEMP1
in TEMP1, PINB
andi TEMP1, (1 <<BlnkBit)
brne dontblnk
cbi DDRB, 7; Выключите видео бит, пробел
dontblnk:;
clr RowCntLow; счетчик row
clr RowCntHi
ldi YL, low (RAMSTART); сбросьте ОЗУ ptr
clr YH
NODISPLAY: SREG, SREG_Save; мы сделаны, выходим
reti
 
SIGNONMSG: .db "AVR COG v1.0. Вход *A3754 May-June 2004 ", 0
 
; Начало Символьной таблицы
.include "charset.inc"
 