;                       ПРОГРАММА ЭМУЛЯТОРА ПЗУ
;порт данных принтера:

;d0 - SRD сигнал последовательной и параллельной синхронизации
;     буферного регистра данных DD4.

;d1 - SRA сигнал последовательной синхронизации сдвигающих
;     регистров адреса DD2 и DD3. Отсутствует  только в режиме
;     параллельной записи (в отличие от SRD).
;     ___                                                           __
;d2 - SWR сигнал синхронизации записи\чтения ОЗУ после того, как на WR/RD
;     установится сигнал либо записи, либо чтения.
;     __
;d3 - WR/RD сигнал установки режима записи (0) или чтения (1) микросхемы ОЗУ.
;     Он должен быть установлен до появления сигнала на d2.

;d4 - MODE сигнал установки регистра DD4 в режим параллельной записи (1)
;     для чтения данных из ОЗУ или в режим сдвига влево (0).

;d7 - DOUT выходные данные, поступающие из компьютера на
;     последовательный вход SI сдвигающего регистра DD2.

;порт статуса принтера:
;____
;BUSY - DIN входные данные, поступающие из сдвигающего регистра данных DD4
;       в порт компьютера.
;****************************************************************************

cod     segment para    'code'
	org     100h
	assume  cs:cod, ds:cod, es:cod, ss:cod

emul    proc

        mov     sp,offset newstk;установим указатель стека на новую вершину
                                ;для того, чтобы можно было освободить лишнюю
                                ;память
        mov     ah,4ah          ;Определяем размер данной программы и
        mov     bx,(newstk-emul+10Fh)/16        ;освобождаем всю лишнюю
        int     21h             ;память. Размер в параграфах будет
                                ;равен (newstk-emul+100h+0Fh)/16

        mov     ah,1            ;инициализация порта принтера
        mov     dx,0            ;LPT1
        int     17h             ;

        mov     ax,40h          ;загрузить в DX основной адрес порта
        mov     es,ax           ;принтера и сохранить его в ячейке Port
        mov     dx,es:[8]       ;
        mov     port,dx         ;

        mov     ax,ds           ;восстановим прежнее значение ES
        mov     es,ax

;Тестируем внешние регистры

        call    tst_rg          ;протестируем внешние регистры и, если нет
        je      k1              ;ошибок, то
                                ;даем сообщение об их подключении
                                ;к шинам ОЗУ

        mov     ax,meslen1      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes1         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

k1:     mov     ax,0600h        ;очистка экрана
        mov     bh,7h           ;
        mov     cx,0            ;
        mov     dx,184fh        ;
        int     10h             ;
        mov     ah,2            ;установка курсора в 0 строку на 0 столбец
        mov     bh,0            ;
        mov     dh,0            ;
        mov     dl,0            ;
        int     10h             ;
        mov     ah,9            ;вывод сообщения на дисплей
        mov     dx,offset soob  ;относительный адрес сообщения в DS:DX
        int     21h             ;

;Тестируем внешнее ОЗУ

        mov     al,00h          ;в AL - сигнатура
        mov     bx,0000h        ;в BX - начальный адрес
        mov     dx,1FFFh        ;в DX - конечный адрес
        call    tst_ram         ;
        je      k2
k3:     mov     ax,meslen2      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes2         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

k2:     mov     al,0Fh          ;
        mov     bx,0000h        ;
        mov     dx,1FFFh        ;
        call    tst_ram         ;
        jne     k3
        mov     al,0F0h         ;
        mov     bx,0000h        ;
        mov     dx,1FFFh        ;
        call    tst_ram         ;
        jne     k3
        mov     al,0AAh         ;
        mov     bx,0000h        ;
        mov     dx,1FFFh        ;
        call    tst_ram         ;
        jne     k3
        mov     al,55h          ;
        mov     bx,0000h        ;
        mov     dx,1FFFh        ;
        call    tst_ram         ;
        jne     k3
        mov     al,0FFh         ;
        mov     bx,0000h        ;
        mov     dx,1FFFh        ;
        call    tst_ram         ;
        jne     k3

;Загрузим в буфер двоичный файл *.bin.

        mov     ah,48h          ;выделим блок памяти,
        mov     bx,800h         ;объемом 32К
        int     21h             ;
        jnc     k5

        mov     ax,meslen4      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes4         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

k5:     mov     segbuf,ax       ;сохраним сегментный адрес буфера

        mov     ax,0600h        ;очистка экрана
        mov     bh,7h
        mov     cx,0
        mov     dx,184fh
        int     10h
        mov     ah,2            ;установка курсора в 0 строку на 0 столбец
	mov	bh,0
        mov     dh,0
        mov     dl,0
        int     10h

        ;вводим имя файла

        mov     ah,9            ;функция вывода сообщения на дисплей
        mov     dx,offset soob2 ;относительный адрес сообщения в DS:DX
        int     21h             ;
        mov     ah,0ah          ;ввод с клавиатуры в буфер kbrbuf, где
        mov     dx,offset kbrbuf;1-й байт=максимальная длина вводимой строки
        mov     bx,dx           ;2-й байт=реальная длина введеной строки
        mov     al,9            ;3-й и далее=символы строки, а последний байт
        mov     [bx],al         ;должен быть 0Dh (возврат каретки).
        int     21h             ;

        cmp     kbrbuf+1,0      ;если имя указано, значит продолжаем
        jne     n1              ;
        mov     ah,4ch          ;завершаем программу
        int     21h             ;

n1:     mov     cl,[kbrbuf+1]   ;формируем спецификацию файла в формате
        xor     ch,ch           ;ASCIIZ в буфере fname
        mov     bx,cx           ;
        lea     si,kbrbuf[bx+1] ;
        lea     di,[fname+7]    ;
        std                     ;
        rep     movsb           ;

        mov     ax,3d00h        ;откроем файл для чтения
        inc     di              ;загрузим в dx относительный адрес
        mov     dx,di           ;спецификации файла
        int     21h             ;
        jnc     k4              ;если файл открылся без ошибки, то на k4

        mov     ax,meslen3      ;подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes3         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

k4:     push    ax              ;сохраним дескриптор файла в стеке

        ;определим длину файла L с помощью функции 42h:
        ;       если L > 8000h, то выдать сообщение об ошибке и завершиться,
        ;       если L = или < 8000h, то читаем файл

        mov     bx,ax           ;получим длину файла в регистровой паре
        mov     ax,4202h        ;DX:AX и сохраним ее в ячейке lenf2:lenf1
        xor     cx,cx           ;
        xor     dx,dx           ;
        int     21h             ;
        mov     lenf1,ax        ;
        mov     lenf2,dx        ;

        mov     ax,4200h        ;установим указатель снова на начало файла
        xor     cx,cx           ;
        xor     dx,dx           ;
        int     21h             ;

        mov     ax,lenf1        ;загрузим в DX:AX значение длины файла
        mov     dx,lenf2        ;

        cmp     dx,0            ;
        je      dal1            ;если DX равен 0, то идем дальше
osh1:   mov     ax,meslen10     ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes10        ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

dal1:   cmp     ax,8000h        ;
        ja      osh1            ;если длина больше 8000h, то идем на ошибку
        mov     cx,ax           ;пересылаем в CX длину файла
        mov     ax,segbuf       ;
        mov     ds,ax           ;
        xor     dx,dx           ;DS:DX - адрес буфера
        pop     bx              ;восстановим дескриптор файла в ВХ
        mov     ah,3Fh          ;функция чтения файла
        int     21h             ;
        jnc     k6              ;если нет ошибки, идем на k6
        mov     ax,meslen5      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes5         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

k6:     mov     ax,es           ;восстановим указатель сегмента данных
        mov     ds,ax           ;

;***********************************************************************
;Выгрузить во внешнее ОЗУ содержимое буфера segbuf, предварительно задав
;начальный и конечный адреса загрузки внешнего ОЗУ
;***********************************************************************

        ;вводим начальный адрес ОЗУ

        mov     ah,9            ;функция вывода сообщения на дисплей
        mov     dx,offset soob3 ;относительный адрес сообщения в DS:DX
        int     21h             ;

        mov     ah,0ah          ;ввод с клавиатуры в буфер kbrbuf, где
        mov     dx,offset kbrbuf;1-й байт=максимальная длина вводимой строки
        mov     bx,dx           ;2-й байт=реальная длина введеной строки
        mov     al,5            ;3-й и далее=символы строки, а последний байт
        mov     [bx],al         ;должен быть 0Dh (возврат каретки).
        int     21h             ;

        cmp     kbrbuf+1,4      ;если адрес указан, то начинаем
        je      vv              ;преобразование,

        mov     ax,meslen6      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes6         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

vv:     mov     al,'0'          ;заполняем 4 байта номера в буфере
        mov     cx,4            ;нулями
        lea     di,dopbuf       ;
        cld                     ;
        rep     stosb           ;
        dec     di              ;установимся на последний байт номера
        xor     ch,ch           ;
        mov     cl,kbrbuf+1     ;в СХ - число введенных символов номера
        lea     si,kbrbuf+1     ;позиционируем SI на последний символ
        add     si,cx           ;в клавиатурном буфере пользователя и
        std                     ;пересылаем номер входа из клавиатурного
        rep     movsb           ;буфера в дополнительный

        mov     al,dopbuf       ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный

        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cont1           ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cont1:  mov     cl,12           ;сдвинем третий разряд 4хразрядного числа
        sal     ax,cl           ;в старший полубайт старшего байта и сохраним
        mov     st_adr,ax       ;в ячейке st_adr

        mov     al,dopbuf+1     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный

        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cont2           ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cont2:  mov     cl,8            ;сдвинем второй разряд 4хразрядного числа
        sal     ax,cl           ;в младший полубайт старшего байта и сохраним
        mov     bx,st_adr       ;
        or      ax,bx           ;
        mov     st_adr,ax       ;в ячейке st_adr

        mov     al,dopbuf+2     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный
        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cont3           ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cont3:  mov     cl,4            ;сдвинем первый разряд 4хразрядного числа
        sal     ax,cl           ;в старший полубайт младшего байта и сохраним
        mov     bx,st_adr       ;
        or      ax,bx           ;
        mov     st_adr,ax       ;в ячейке st_adr

        mov     al,dopbuf+3     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный
        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cont4           ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cont4:  mov     bx,st_adr       ;закончим преобразование числа
        or      ax,bx           ;и сохраним его
        mov     st_adr,ax       ;в ячейке st_adr

;***********************************************************************

        ;вводим конечный адрес ОЗУ

        mov     ax,0600h        ;очистка экрана
        mov     bh,7h           ;
        mov     cx,0            ;
        mov     dx,184fh        ;
        int     10h             ;
        mov     ah,9            ;функция вывода сообщения на дисплей
        mov     dx,offset soob4 ;относительный адрес сообщения в DS:DX
        int     21h             ;

        mov     ah,0ah          ;ввод с клавиатуры в буфер kbrbuf, где
        mov     dx,offset kbrbuf;1-й байт=максимальная длина вводимой строки
        mov     bx,dx           ;2-й байт=реальная длина введеной строки
        mov     al,5            ;3-й и далее=символы строки, а последний байт
        mov     [bx],al         ;должен быть 0Dh (возврат каретки).
        int     21h             ;

        cmp     kbrbuf+1,4      ;если адрес указан, то начинаем
        je      vv1             ;преобразование,

        mov     ax,meslen6      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes6         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

vv1:    mov     al,'0'          ;заполняем 4 байта номера в буфере
        mov     cx,4            ;нулями
        lea     di,dopbuf       ;
        cld                     ;
        rep     stosb           ;
        dec     di              ;установимся на последний байт номера
        xor     ch,ch           ;
        mov     cl,kbrbuf+1     ;в СХ - число введенных символов номера
        lea     si,kbrbuf+1     ;позиционируем SI на последний символ
        add     si,cx           ;в клавиатурном буфере пользователя и
        std                     ;пересылаем номер входа из клавиатурного
        rep     movsb           ;буфера в дополнительный

        mov     al,dopbuf       ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный

        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cnt1            ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cnt1:   mov     cl,12           ;сдвинем старший разряд 4хразрядного числа
        sal     ax,cl           ;в старший полубайт старшего байта и сохраним
        mov     end_adr,ax      ;в ячейке end_adr

        mov     al,dopbuf+1     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный

        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cnt2            ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cnt2:   mov     cl,8            ;сдвинем второй разряд 4хразрядного числа
        sal     ax,cl           ;в младший полубайт старшего байта и сохраним
        mov     bx,end_adr      ;
        or      ax,bx           ;
        mov     end_adr,ax      ;в ячейке end_adr

        mov     al,dopbuf+2     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный
        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cnt3            ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cnt3:   mov     cl,4            ;сдвинем первый разряд 4хразрядного числа
        sal     ax,cl           ;в старший полубайт младшего байта и сохраним
        mov     bx,end_adr      ;
        or      ax,bx           ;
        mov     end_adr,ax      ;в ячейке end_adr

        mov     al,dopbuf+3     ;в AL - символ шестнадцатиричной цифры
        call    hexbin          ;вызываем процедуру перевода из
                                ;символьного шестнадцатиричного вида в
                                ;двоичный
        cmp     ah,0            ;если перевод прошел без ошибки,
        je      cnt4            ;то продолжаем

        mov     ax,meslen7      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes7         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cnt4:   mov     bx,end_adr      ;закончим преобразование числа
        or      ax,bx           ;и сохраним его
        mov     end_adr,ax      ;в ячейке end_adr

;*************************************************************************

        ;проверяем соответствие адресного соотношения end_adr > = st_adr

        mov     bx,st_adr       ;
        cmp     ax,bx           ;
        jae     cn1             ;если больше или равно, то продолжим на cn1

        mov     ax,meslen8      ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes8         ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

cn1:    mov     ax,0600h        ;очистка экрана
        mov     bh,7h
        mov     cx,0
        mov     dx,184fh
        int     10h
        mov     ah,2            ;установка курсора в 0 строку на 0 столбец
        mov     bh,0            ;
        mov     dh,0            ;
        mov     dl,0            ;
        int     10h             ;
        mov     ah,40h          ;функция вывода сообщения на дисплей
        mov     bx,1            ;в ВХ - куда выводить сообщение (дисплей)
        mov     cx,lenwt        ;длина сообщения в СХ
        lea     dx,adrwt        ;относительный адрес сообщения в DX
        int     21h

        ;пересылаем данные из буфера с сегментным адресом segbuf и
        ;относительным адресом равным 0 во внешнее ОЗУ, начиная
        ;с адреса st_adr и заканчивая адресом end_adr.

        mov     bx,st_adr       ;
        mov     count,bx        ;
        mov     ax,segbuf       ;
        mov     es,ax           ;установим ES на сегмент буфера
        mov     ds,ax           ;установим указатель DS:SI на
        xor     si,si           ;начало буфера файла
        cld

per1:   lodsb                   ;читаем байт данных из буфера
        mov     dx,cs           ;
        mov     ds,dx           ;установим DS на кодовый сегмент
        call    wr_ram          ;запишем прочитанный байт в ячейку ОЗУ

        mov     bx,si           ;
        cmp     bl,255          ;
        jne     s1              ;
        mov     ah,9            ;вывод сообщения на дисплей
        mov     dx,offset soob5 ;относительный адрес сообщения в DS:DX
        int     21h             ;

s1:     mov     bx,count        ;
        cmp     bx,end_adr      ;весь блок записали?
        je      cn2             ;если да, то идем на проверку
        inc     bx              ;
        mov     count,bx        ;
        mov     ax,es           ;
        mov     ds,ax           ;установим DS на буфер
        jmp     per1            ;

;**********************************************************************
;Сравнить содержимое буфера и внешнего ОЗУ, и по результатам проверки
;выдать информацию на экран.
;**********************************************************************

cn2:    mov     ax,0600h        ;очистка экрана
        mov     bh,7h
        mov     cx,0
        mov     dx,184fh
        int     10h
        mov     ah,2            ;установка курсора в 0 строку на 0 столбец
        mov     bh,0            ;
        mov     dh,0            ;
        mov     dl,0            ;
        int     10h             ;
        mov     ah,40h          ;функция вывода сообщения на дисплей
        mov     bx,1            ;в ВХ - куда выводить сообщение (дисплей)
        mov     cx,lenwt1       ;длина сообщения в СХ
        lea     dx,adrwt1       ;относительный адрес сообщения в DX
        int     21h

        mov     bx,st_adr       ;
        mov     count,bx        ;
        mov     ax,es           ;
        mov     ds,ax           ;установим указатель DS:SI на
        xor     si,si           ;начало буфера файла
        cld

per2:   lodsb                   ;читаем байт данных из буфера
        mov     dx,cs           ;
        mov     ds,dx           ;установим DS на кодовый сегмент
        mov     var,al          ;сохраним байт из буфера в ячейке var
        call    rd_ram          ;читаем байт данных из внешней памяти
        cmp     al,var          ;
        jne     vih1            ;

        mov     bx,si           ;
        cmp     bl,255          ;
        jne     s2              ;
        mov     ah,9            ;вывод сообщения на дисплей
        mov     dx,offset soob5 ;относительный адрес сообщения в DS:DX
        int     21h             ;

s2:     mov     bx,count        ;
        cmp     bx,end_adr      ;
        je      okon            ;
        inc     bx              ;
        mov     count,bx        ;
        mov     ax,es           ;
        mov     ds,ax           ;установим DS на буфер
        jmp     per2            ;

vih1:   mov     ax,meslen11     ;иначе подготовим параметры для
        mov     meslen,ax       ;выдачи соответствующего сообщения
        lea     ax,mes11        ;об ошибке и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

okon:   mov     ax,meslen9      ;подготовим параметры для
        mov     meslen,ax       ;выдачи сообщения
        lea     ax,mes9         ;и завершения программы.
        mov     adrmes,ax       ;
        jmp     err             ;

;**********************************************************************

;Вывод сообщения об ошибке и завершение программы
;
err:
        mov     ax,0600h        ;очистка экрана
        mov     bh,7h
        mov     cx,0
        mov     dx,184fh
        int     10h
        mov     ah,2            ;установка курсора в 0 строку на 0 столбец
        mov     bh,0            ;
        mov     dh,0            ;
        mov     dl,0            ;
        int     10h             ;
        mov     ah,40h          ;функция вывода сообщения на дисплей
        mov     bx,1            ;в ВХ - куда выводить сообщение (дисплей)
        mov     cx,meslen       ;длина сообщения в СХ
        mov     dx,adrmes       ;относительный адрес сообщения в DX
        int     21h
        mov     ax,4c00h        ;функция завершения программы
        int     21h

emul    endp

;**********************************************************************

;Процедура перевода чисел из символьного шестнадцатиричного вида в двоичный
;       при вызове в AL - шестнадцатиричная символьная цифра
;       при возврате в AL - двоичное число
;                    в AH = 0, если цифра корректная и = FF, если ошибка
hexbin  proc    near

        xor     ah,ah           ;
        cmp     al,30h          ;
        jb      oshibka         ;если меньше, то ошибка
        cmp     al,39h          ;
        ja      simb1           ;если больше, то проверим на цифры A,B,C,D,E,F
        sub     al,30h          ;иначе - в AL двоичный код цифры от 0 до 9
        ret
simb1:  cmp     al,41h
        jb      oshibka         ;если меньше, то ошибка
        cmp     al,46h
        ja      simb2           ;если больше, то проверим на цифры a,b,c,d,e,f
        sub     al,37h          ;иначе - в AL двоичный код цифры от A до F
        ret
simb2:  cmp     al,61h
        jb      oshibka         ;если меньше, то ошибка
        cmp     al,66h
        ja      oshibka         ;если больше, то ошибка
        sub     al,57h          ;иначе - в AL двоичный код цифры от a до f
        ret
oshibka:mov     ah,0ffh         ;при вводе недопустимого числа в AH = 255
        ret

hexbin  endp

;Процедура тестирования внешних регистров и установка порта данных принтера
;в исходное состояние.
;Если окончание успешно, то установлен флаг - ZR
;                                иначе флаг - NZ
tst_rg  proc    near

        mov     dx,port         ;установить режим последовательного сдвига
        mov     al,00001100b
        out     dx,al

        mov     ah,signat1      ;загрузить в AH сигнатуру и переслать
        call    send            ;ее во все регистры эмулятора
        mov     ah,signat2      ;
        call    send            ;
        mov     ah,signat3      ;
        call    send            ;

        call    receive         ;принять данные из внешнего регистра DD4
        cmp     ah,signat1      ;в регистр AH
        jne     flag1           ;если сигнатуры не совпадают, то будет
        call    receive         ;установлен флаг NZ
        cmp     ah,signat2      ;
        jne     flag1           ;
        call    receive         ;
        cmp     ah,signat3      ;иначе, флаг ZR

flag1:  ret

tst_rg  endp

;Процедура тестирования внешнего ОЗУ
;       в AL - сигнатура
;       в BX - начальный 16разрядный адрес тестируемого блока памяти
;       в DX - конечный 16разрядный адрес тестируемого блока памяти
;Если окончание успешно, то установлен флаг ZR
;                              иначе - флаг NZ
;
tst_ram proc    near

        mov     st_adr,bx       ;
        mov     count,bx        ;
        mov     end_adr,dx      ;
        mov     var,al          ;

m4:     call    wr_ram          ;
        mov     bx,count        ;
        cmp     bx,end_adr      ;
        je      m3              ;
        inc     bx              ;
        mov     count,bx        ;
        mov     al,var          ;
        jmp     m4              ;

m3:     mov     bx,st_adr       ;
        mov     count,bx        ;

m5:     call    rd_ram          ;
        cmp     al,var          ;
        jne     vihod           ;
        mov     bx,count        ;
        cmp     bx,end_adr      ;
        je      vihod           ;
        inc     bx              ;
        mov     count,bx        ;
        jmp     m5              ;

vihod:  ret                     ;

tst_ram endp

;Процедура записи 1 байта информации во внешнее ОЗУ
;       при вызове: в AL - информационный байт
;                   в BX - 16разрядный адрес ячейки ОЗУ
;Модифицируемые регистры - AX, CX, DX
;
wr_ram  proc    near

        mov     ah,al           ;пересылаем в регистр DD4 байт данных,
        call    send            ;а в регистры DD2-DD3 адрес ячейки ОЗУ
        mov     ah,bh           ;
        call    send            ;
        mov     ah,bl           ;
        call    send            ;

        mov     dx,port         ;формируем сигнал записи данных из
        mov     al,00000100b    ;регистра DD4 в ОЗУ
        out     dx,al           ;
        mov     al,10000000b    ;выдаем в старший разряд DOUT - 1, т.к.
        out     dx,al           ;нужно заряжать конденсатор цепи питания C1
        mov     al,00000100b    ;
        out     dx,al           ;
        mov     al,00001100b    ;
        out     dx,al           ;

        ret

wr_ram  endp

;Процедура чтения 1 байта информации из внешнего ОЗУ
;       при вызове: в BX - 16разрядный адрес ячейки ОЗУ
;     при возврате: в AL - информационный байт
;
rd_ram  proc    near

        mov     ah,bh           ;пересылаем в регистры DD2-DD3 адрес
        call    send            ;ячейки внешней памяти
        mov     ah,bl           ;
        call    send            ;

        mov     dx,port         ;формируем сигнал чтения данных из
        mov     al,00011000b    ;ОЗУ в регистр DD4
        out     dx,al           ;
        mov     al,00011001b    ;
        out     dx,al           ;
        mov     al,00011000b    ;
        out     dx,al           ;
        mov     al,00001100b    ;
        out     dx,al           ;

        call    receive
        mov     al,ah

        ret

rd_ram  endp

;Процедура последовательной  пересылки 1 байта информации в регистр эмулятора
;в AH - пересылаемый байт
;модифицируемые регистры - AX, CX, DX
;
send    proc    near

        mov     dx,port         ;адрес порта данных принтера - в регистр DX
        mov     cx,8
m1:     mov     al,ah
        and     al,10000000b    ;обнулим все биты, кроме 7-го
        or      al,00001100b    ;установим биты в соответствии с маской
        out     dx,al
        or      al,00001111b    ;установим биты в соответствии с маской
        out     dx,al
        and     al,10001100b    ;установим биты в соответствии с маской
        out     dx,al
        sal     ah,1            ;свиг влево на 1 разряд
        loop    m1              ;повторить еще 7 раз
        ret

send    endp

;Процедура последовательного приема 1 байта информации из регистра эмулятора
;в регистр AH
;модифицируемые регистры - AX, CX, DX
;
receive proc    near

        mov     dx,port
        mov     cx,8
m2:     inc     dx              ;адрес порта статуса принтера в регистре DX
        in      al,dx
        sal     ax,1            ;свиг влево 16-разрядного AX на 1 разряд
        dec     dx              ;теперь DX указывает на порт данных
        and     al,0            ;обнулим все биты
        or      al,00001100b    ;установим биты в соответствии с маской
        out     dx,al
        or      al,00001111b    ;установим биты в соответствии с маской
        out     dx,al
        and     al,00001100b    ;установим биты в соответствии с маской
        out     dx,al
        loop    m2              ;повторить еще 7 раз
        not     ah              ;
        ret

receive endp

;Область данных и стека

port    dw      0               ;основной адрес порта принтера
signat1 db      0F5h            ;первая    сигнатура
signat2 db      5Ah             ;вторая    сигнатура
signat3 db      0A0h            ;третья    сигнатура
meslen  dw      0               ;длина текущего сообщения
adrmes  dw      0               ;адрес начала текущего сообщения
mes1    db      ' Ошибка операции регистров сдвига DD2, DD3 или DD4 !',10,13,10
        db      ' Устраните неисправность и запустите эмулятор снова.',10,13
        db      ' Грицаенко А.Н.              тлф.: (86547)-7-15-30',10,13
        db      ' Ставропольский край, г.Светлоград (86547)-7-15-38',10,13
meslen1 equ     $-mes1
mes2    db      ' Ошибка чтения\записи внешней памяти DD5 !',10,13,10
        db      ' Замените микросхему и запустите эмулятор снова.',10,13
        db      ' Грицаенко А.Н.              тлф.: (86547)-7-15-30',10,13
        db      ' Ставропольский край, г.Светлоград (86547)-7-15-38',10,13
meslen2 equ     $-mes2
mes3    db      ' Ошибка открытия файла !',10,13,10
meslen3 equ     $-mes3
mes4    db      ' Не достаточно памяти !',10,13,10
meslen4 equ     $-mes4
mes5    db      ' Ошибка чтения файла !',10,13,10
meslen5 equ     $-mes5
mes6    db      ' Укажите адрес в HEX формате из 4-х цифр !',10,13,10
meslen6 equ     $-mes6
mes7    db      ' Число не в HEX формате !',10,13,10
meslen7 equ     $-mes7
mes8    db      ' Несоответствие адресов !',10,13,10
meslen8 equ     $-mes8
mes9    db      ' Данные загружены в ОЗУ.',10,13
        db      ' Переведите эмулятор в режим ПЗУ.',10,13
meslen9 equ     $-mes9
mes10   db      ' Размер файла больше 32 Kбайт !',10,13,10
meslen10 equ    $-mes10
mes11   db      ' Ошибка верификации внешней памяти DD5 !',10,13,10
        db      ' Замените микросхему и запустите эмулятор снова.',10,13
        db      ' Грицаенко А.Н.              тлф.: (86547)-7-15-30',10,13
        db      ' Ставропольский край, г.Светлоград (86547)-7-15-38',10,13
meslen11 equ     $-mes11
adrwt   db      ' Идет загрузка. Ожидайте ...',10,13,10
lenwt   equ     $-adrwt
soob5   db      '.$'
adrwt1  db      ' Идет верификация. Ожидайте ...',10,13,10
lenwt1  equ     $-adrwt1
soob    db      ' Регистры в норме.',10,13
        db      ' Тестируется внешнее ОЗУ. Ожидайте ...',10,13,'$'
st_adr  dw      0               ;начальный адрес блока внешнего ОЗУ
count   dw      0               ;счетчик адресов
end_adr dw      0               ;конечный адрес блока внешнего ОЗУ
var     db      0               ;переменная для ОЗУ
soob2   db      ' Введите имя двоичного файла:','$'
soob3   db      ' Введите начальный адрес внешнего ОЗУ:','$'
soob4   db      ' Введите конечный адрес внешнего ОЗУ:','$'
kbrbuf  db      11 dup(0)       ;клавиатурный буфер
dopbuf  db      4 dup(0)        ;дополнительный буфер для преобразования
fname   db      '        .bin',0;спецификация файла *.bin в формате ASCIZ
segbuf  dw      0               ;сегментный адрес буфера файла
lenf1   dw      0               ;младшая половина длина открытого файла
lenf2   dw      0               ;старшая половина длина открытого файла

        dd      64 dup (?)     ;область стека
newstk=$
cod     ends

        end     emul
