Программируем порты

Советский компьютер Радио-86РК (1986) и его клоны

Moderator: Shaos

User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Программируем порты

Post by Lavr »

VituZz wrote:
Lavr wrote:Здесь лишь приведу пример элегантного обращения к порту К580ВВ55,
который недоступен по IN/OUT.

Предположим, что 16 линий портов А и В К580ВВ55 управляют каким-то устройством.
И хорошо бы выдавать сигналы этому устройству в один момент времени.
По IN/OUT - не выйдет никак. :-?

А когда порты в памяти - элегантное решение есть:
1) управляющее слово собираем в HL.
2) выдаём его практически одновременно в порты А и В К580ВВ55:
SHLD ADDR_PORT_A.
Разве не элегантно? :wink:
Может, я не понял идеи, но "практически одновременно" в данном случае не означает "совершенно одновременно", а лишь в несколько раз быстрее, чем с IN/OUT. Если бы мне нужно было вывести сразу слово одновременно, то я бы просто использовал три регистра, в первый (промежуточный) писал бы первый байт, и этот первый байт переписывался бы во второй регистр стробом, который пишет второй байт в третий регистр. Таким образом была бы достигнута одновременность выдачи двух байт (из второго и третьего регистра), и такое решение мне кажется более элегантным. Но это, несомненно, дело вкуса, и каждое решение имеет право на жизнь, если оно достигает целей, заложенных при проектировании.
Да нет - ты всё верно понял. Конечно, совершенно одновременного в природе
просто ничего не бывает.
Но я тебе показал просто пример элегантного решения простой, но красивой
задачи с портом К580ВВ55.
На языке процессора К580ВМ80 я решил её одной командой практически одновременно.
Я подчеркнул преимущестово проецирования регистров порта на память в то же время
ты сам признал, что оно "в несколько раз быстрее, чем с IN/OUT".

Второй положительный пример привёл Хардыч, и ты его тоже обсуждал:
MOV M,A; где в HL - адрес порта.
Можно также элегантно косвенным образом обращаться к портам.

У К580ВМ80 не было ведь более гибкой команды OUT DX,REG ?
Даже у Z80 - работа с портами гибче! :lol:

Ну а то, что любую проблему в микропроцессоорной системе можно решить
как программно, так и аппаратно - я даже пытаться оспорить не буду.

Да - можно приделать 3 регистра, и ещё что-то приделать. Но порт К580ВВ55
тем и интересен, что настривается гибко.
Оттого его и используют до сих пор как неплохое параллельное УВВ на 24-линии.
Мы же не угадаем заранее, чем надумает поуправлять владелец копьютера
общего назначения?
Ну а если у него не сростается на встроенном К580ВВ55 - ему и дают адреса
под плату-прототим, как в IBM-совместимых! :wink:

Но многие любят управлять и через LPT, хотя он совсем не гибок и не для этого
был исторически введен в состав компьютера.
Last edited by Lavr on 29 Sep 2012 08:29, edited 2 times in total.
iLavr
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:
Lavr wrote:
HardWareMan wrote:
Lavr wrote:Здесь лишь приведу пример элегантного обращения к порту К580ВВ55, который недоступен по IN/OUT.

Предположим, что 16 линий портов А и В К580ВВ55 управляют каким-то устройством. И хорошо бы выдавать сигналы этому устройству в один момент времени.
По IN/OUT - не выйдет никак. :-?
А когда порты в памяти - элегантное решение есть:
1) управляющее слово собираем в HL.
2) выдаём его практически одновременно в порты А и В К580ВВ55:
SHLD ADDR_PORT_A.
Разве не элегантно? :wink:
Только так и делали, когда работали с ROM диском на порту! Нам SHLD IOP_B/LDA IOP_A фактически заменяло MOV A,M, который только для памяти работает. ;)
Слегка не понял: если порты в пространстве памяти, то с ними сработает
и SHLD IOP_B/LDA IOP_A, и MOV A,M.

Что же тогда и что "фактически заменяло"?
Чем LDA IOP_A отличается от MOV A,M, если HL = IOP_A?
Или ты имеешь ввиду, что байты самого ROM диска не доступны по MOV A,M?
А если внимательно посмотреть? Ладно, танкистам срачного фронта объясняю: команда MOV A,M позволяет удобно работать с куском памяти, пользуя [HL] как указатель. Когда твой ROM диск подключен к IOP, то MOV А,M уже не сработает. А тут просто бедер и делаем SHLD в порт IOP_B ([L] упадет в IOP_B, а [H] упадет в IOP_C), а потом LDA IOP_A - и получаем фактически команду MOV A,M, только для внешнего оборудования.
Ну очевидное ты мог бы старому танкисту не повторять.

Неясно вот что: когда твой ROM диск подключен к IOP, то стробы
/CS и /RD мы делаем программно через IOP, так?
Если я правильно угадываю по твоему примеру - /CS формируется
дешифратором выбора конкретной ROM, а /RD у всех ROM
подключен всегда активным?

Я не вижу схемы твоего ROM-диска, поэтому могу только предполагать...



PS. И, кстати, что такое "бедер" ?
iLavr
aav8
Maniac
Posts: 287
Joined: 05 Nov 2008 19:47
Location: 81.28.208.238

Post by aav8 »

Еще хорощий пример преимущества отображения
портов В/В в память - в процедуре инициализации
ВГ75, ВТ57 в том-же РК86.
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

aav8 wrote:Еще хорощий пример преимущества отображения
портов В/В в память - в процедуре инициализации
ВГ75, ВТ57 в том-же РК86.
Если не трудно - напомни... У меня под рукой только от "Микроши":

Code: Select all

; Пpогpаммиpование CCRT и CDMA  ;
;    КР580ВГ75  и  КР580ВТ57    ;
; тест настpойки  -  вывод  на  ;
; экpан символов  с клавиатуpы  ;

        ORG  0000H

        CALL CLSSCR;   очистим экp. ОЗУ
        CALL INICRT;   инициализация CCRT и CDMA
K01:
        LXI  H,BEGSCR; начало экp. ОЗУ
        LXI  D,ENDSCR; конец  экp. ОЗУ
        LXI  B,CURPOS; поз.куpсоpа C-столбец, B-стpока
KSC:
        CALL SETCUR;   установим куpсоp
K02:
        CALL GETKEY;   опpос клавиатуpы
        CPI  1BH;      'ESC' - ?
        JZ   SYSTEM;   да - выход в систему
        CPI  80H;      меньше кода 129 ASCII
        JC   K0A;      да - выводим на экpан
        ANI  7FH;      иначе сбpосит ст.бит
        ORA  A;        если A не pавно 00H
        JNZ  K0A;      да - выводим на экpан
        MVI  A,20H;    иначе заменим 00H на 20H
K0A:
        MOV  M,A;      выводим на экpан символ клавиши
        INX  H;        сдвиг в экp. ОЗУ на байт
        CALL CPHLDE;   достигли конца экp. ОЗУ ?
        JNZ  K03;      нет - выводим куpсоp в след.поз.
        JMP  K01;      достигли конца -> повтоpим сначала
K03:
        INR  C;        сдвинем куpсоp по стpоке
        MOV  A,C;      пpовеpим, не пpевысил ли он
        CPI  78;       pазмеp стpоки ?
        JC   KSC;      не пpевысил -> куpсоp на экpан
        MVI  C,00H;    иначе - куpсоp в начало стpоки
        INR  B;        пеpеход на стpоку ниже
        MOV  A,B;      пpовеpим, не пpевысили ли
        CPI  31;       количество стpок на экpане ?
        JC   KSC;      не пpевысил -> куpсоp на экpан
        MVI  B,00H;    иначе - куpсоp в начало экpана
        JMP  KSC;      куpсоp на экpан
SETCUR:
        MVI  A,0C0H;   команда 'Установка Куpсоpа' -
        STA  CMDREG;   в pегистp команд CCRT
        MOV  A,C;      установим позицию столбца
        STA  PRMREG;   в pегистp параметров
        MOV  A,B;      установим позицию стpоки
        STA  PRMREG;   в pегистp параметров
        RET

;======= Инициализация CCRT и CDMA ===============
INICRT:
        LXI  H,CMDREG; в pегистp команд CCRT
        MVI  M,00H;    запишем команду 'СБРОС'
        DCX  H;        в pегистp параметров
        MVI  M,4DH;    нормальные символы, 78 в строке (0-77)
        MVI  M,1DH;    1 строка в кадровом синхроимпульсе,
;                      30 строк на экране
        MVI  M,99H;    высота символа - 10
;                      линия подчеркивания в 10 стpоке,
        MVI  M,93H;    режим MODE1, формат курсора - мигающий
;                      штрих под символом,
;                      8 символов в строчном синхроимпульсе
        LXI  H,CMDREG; в pегистp команд CCRT
        MVI  M,27H;    Команда начать отображение:
;                      7 тактов между запросами ПДП,
;                      8 циклов ПДП за один сеанс
        MVI  M,0E0H;   внутренние счетчики - в соответствии с
;                      положением курсора в верхнем левом углу.
K05:
        MOV  A,M;      Читаем регистр статуса CCRT
        ANI  20H;      в цикле и выходим из него
        JZ   K05;      по условию IR=1
;--------------------- Настpоим контpоллеp ПДП
        MVI  A,80H;    10000000b = 80H флаг автозагрузки
        STA  REGRJM;   занесли в регистр режима РгР
        LXI  H,RGDMA2; указали на рег.адреса через M=([HL])
        MVI  M,0D0H;   загружаем младший байт адреса
        MVI  M,76H;    загружаем старший байт адреса
        INX  H;        указали на регистр счета
        MVI  M,23H;    заносим младший байт количества циклов,
;                      76D0H-7FF3H=923H
        MVI  M,49H;    заносим старший байт количества циклов,
;                      и D14=1 - чтение: 4.923H
        MVI  A,0A4H;   установили флаги: автозагрузка, удлиненная
;                      запись и разрешение работы канала 2 (D3=1),
        STA  REGRJM;   записываем в РгР.
        RET
;--------------------- Очистка экp. ОЗУ
CLSSCR:
        LXI  H,BEGSCR
        LXI  D,ENDSCR
K07:
        MVI  M,20H;    символом 'пpобел'
        INX  H
        CALL CPHLDE
        JNZ  K07
        RET
;--------------------- Сpавнение HL=DE ?
CPHLDE:
        MOV  A,D
        CMP  H
        RNZ
        MOV  A,E
        CMP  L
        RET

CURPOS:EQU  0000H
BEGSCR:EQU  76D0H
ENDSCR:EQU  7FF4H
PRMREG:EQU  0D000H
CMDREG:EQU  0D001H
SYSTEM:EQU  0F800H
RGDMA2:EQU  0F804H
REGRJM:EQU  0F808H
GETKEY:EQU  0F803H
       END
В "РК86" - аналогично?
iLavr
User avatar
Shaos
Admin
Posts: 24081
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

А кстати есть лазить во внешний ROM-драйв, то старший байт адреса на каждые 256 байт будет одинаковым - тогда нафига каждый раз засылать туда "одновременно" оба байта адреса? В таком случае один OUT N (10 тактов) будет быстрее одного SHLD Nadr (16 тактов)...
Я тут за главного - если что шлите мыло на me собака shaos точка net
aav8
Maniac
Posts: 287
Joined: 05 Nov 2008 19:47
Location: 81.28.208.238

Post by aav8 »

Вот этот кусочек - занесли в HL адрес,
и стали кидать в порты команды/данные

Code: Select all

;======= Инициализация CCRT и CDMA =============== 
INICRT: 
        LXI  H,CMDREG; в pегистp команд CCRT 
        MVI  M,00H;    запишем команду 'СБРОС' 
        DCX  H;        в pегистp параметров 
        MVI  M,4DH;    нормальные символы, 78 в строке (0-77) 
        MVI  M,1DH;    1 строка в кадровом синхроимпульсе, 
                         ;                      30 строк на экране 
        MVI  M,99H;    высота символа - 10 
                        ;                      линия подчеркивания в 10 стpоке, 
        MVI  M,93H;    режим MODE1, формат курсора - мигающий 
                       ;                      штрих под символом, 
                       ;                      8 символов в строчном синхроимпульсе 
        LXI  H,CMDREG; в pегистp команд CCRT 
        MVI  M,27H;    Команда начать отображение: 
                        ;                      7 тактов между запросами ПДП, 
                         ;                      8 циклов ПДП за один сеанс 
        MVI  M,0E0H;   внутренние счетчики - в соответствии с 
                            ;                      положением курсора в верхнем левом углу. 
K05: 
        MOV  A,M;      Читаем регистр статуса CCRT 
        ANI  20H;      в цикле и выходим из него 
        JZ   K05;      по условию IR=1 
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

aav8 wrote:Вот этот кусочек - занесли в HL адрес,
и стали кидать в порты команды/данные...
Конечно, яйцо было раньше курицы, но это типичный приём в IBM-совместимых...

Указать в DX базовый адрес контроллера, и по DX кидать
в порты команды/данные, изменяя значение DX.
Как мы делаем через псевдо-регистр М.

Тем более, что в IBM-совместимых базовый адрес всегда можно взять из служебной
области BIOS.

Но у нас в 580ВМ80 не было IN/OUT по адресу в регистре. Хотя, с учетом
того, что нам никто не запрещал писать в область команд, есть изощренный
приём похожей работы с IN/OUT.

Но уже в Z80 IN/OUT по адресу в регистре появился.
iLavr
User avatar
HardWareMan
Banned
Posts: 2139
Joined: 20 Mar 2005 13:41
Location: От туда

Post by HardWareMan »

Lavr wrote:PS. И, кстати, что такое "бедер" ?
Фиг его знает, как так получилось. Имелось в виду "берем".
Lavr wrote:Но уже в Z80 IN/OUT по адресу в регистре появился.
Конечно, они сделали IN R,(C) и OUR (C),R, но поломали простой IN/OUT, которые у них записаны как IN A,(N) и OUT (N),A. Ибо, если заюзать 16 бит адреса порта, то использовать их получится только через расширенную префиксом #ED команду, где адресом выступает [BC], ибо формирование адреса в обычном IN/OUT теперь формируется так: AN. Т.е., N так и остался младшим адресом, а [A] стал старшим. И если в случае с IN еще можно задать любой нужный адрес, результат чтения с которого затрет [A], то при выводе OUT старшим байтом адреса будет аргумент записи, который в [A]. Что нужно было курить, чтобы так сделать? Уж лучше бы оставили совместимую с i8080 модель поведения, а именно [NN], т.е. копирование младшего в старший.
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:
Lavr wrote:PS. И, кстати, что такое "бедер" ?
Фиг его знает, как так получилось. Имелось в виду "берем".
Но ты ничего не сказал про стробы ROM-ов за IOP-ом... :-?
iLavr
User avatar
HardWareMan
Banned
Posts: 2139
Joined: 20 Mar 2005 13:41
Location: От туда

Post by HardWareMan »

Lavr wrote:
HardWareMan wrote:
Lavr wrote:PS. И, кстати, что такое "бедер" ?
Фиг его знает, как так получилось. Имелось в виду "берем".
Но ты ничего не сказал про стробы ROM-ов за IOP-ом... :-?
А зачем стробы? Все по классике: ПЗУ на 64КБ в сумме (была такая коробочка с МРН32 разъемом, в которой была платка на РФ8), постоянно выбранное и подключенное по классической схеме: IOP_A это шина данных на ввод и IOP_B/IOP_C шина адреса на вывод. Изначально, в свете нашего треда, я писал про прошедшее время, имея ввиду мое посещение кружка и работу на Специалисте в далёких 90х. ROM диск для MX^2 с его 2МБ на борту даже не планируется вводить в обсуждение.
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

HardWareMan wrote:Все по классике: ПЗУ на 64КБ в сумме (была такая коробочка с МРН32 разъемом, в которой
была платка на РФ8 ), постоянно выбранное и подключенное по классической схеме:
IOP_A это шина данных на ввод и IOP_B/IOP_C шина адреса на вывод.
Lavr wrote:Я не вижу схемы твоего ROM-диска, поэтому могу только предполагать...
iLavr
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Lavr wrote:...
Но у нас в 580ВМ80 не было IN/OUT по адресу в регистре. Хотя, с учетом
того, что нам никто не запрещал писать в область команд, есть изощренный
приём похожей работы с IN/OUT..
Хочу уточнить у многоуважаемых коллег, верно ли я понимаю следуещее :
Если дешифруем байт состояния "по полной программе" так сказать, ( смещаясь от "фон-Неймана" к "Гарварду" частично,) то есть не только, (как Вы изволиили назвать) "мешок памяти" - 64К - отдельный "слой" адресного пространства при обращении через SP , но и ещё "слой" адресного пространства ну допустим верхние 32К ( нижние 32К не трогаю, ибо с клоном РК-86 экспериментирую ) - по названию цикла и обзовём - M1-"слой" адресного пространства будет использоваться ,
то тогда получается, что при PC=x и К.оп.=^[PC=x]=0D3h в слое M1 ,( т.е. OUT ) при значаении байта в основном слое в ячейке с adr=x+1 например 0FEh произойдёт именно пересыл содержимого A в порт по адресу 0FEh .
Так или не так ?

Это я к чему собственно - если в слое M1 будет ПЗУ-шка, то там, ясный пень, могут быть только подпрограммы, состоящие исключительно из однобайтовых комманд, если только не захочется применить такой вот изящный "спецэффект" со вторым байтом команды ( или со вторым и третьим байтами ), подверженным произвольному изменению.
(Это второе направление, как позабавляться с РК-шкой - про первое - с "прикольной" дешифрацией на "сп"-шке я в другой теме уже консультировался. )
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

Ну раз ты "наживую" делаешь эксперименты, может ты нам и расскажешь? :wink:

Я в своей практике отлавливал только байты, нужные для организации
IN/OUT в триггеры ТМ2.
И, честно говоря, я бы не стал делать "мешок", ориентируясь на выделение
обращения к стеку, по той простой причине, что в этом мешке будет, как
ни крути, шариться сам стек.

А стековые команды удобны и в обычном пространстве.
В "Специалисте" через PUSH, к примеру, чистят экран,
и делают это гораздо быстрее, чем:

Code: Select all

   XRA  A
   LXI  H,SCR_BEGIN
   LXI  B,SCR_LENGTH
MT0:
   MOV  M,A
   INX  H
   DCR  C
   JNZ  MT0
   DCR  B
   JNZ  MT0
iLavr
petrenko
Doomed
Posts: 598
Joined: 10 Mar 2012 16:21
Location: РФ

Post by petrenko »

Насчёт "мешка памяти"- чтоб по возможности не "пересекаться" стекам программ и "мешку"- можно сделать оный не 64К ,а 32К верхних.
Ну а как "поместить в стек сам указатель стека"- это Вы полагаю знаете.
Кто нашу беседу читает и не знает, подскажу :
после DI ; PUSH PSW ; PUSH B ; PUSH D ; PUSH H ; надо :
FIXSP EQU 0xxxxh ; где xxxx- адрес ячейки-указателя адреса хранения предыдущего значения SP (SP_for_SP так сказать )
LXI D , 00h
LHLD FIXSP ;
XCHG ; теперь SP_for_SP лежит в DE ,а HL=0
DAD SP ; по сути как бы перемещение из SP в HL получается
XCHG ; теперь значение SP уже в DE ,а SP_for_SP в HL
INX H ;
INX H ;
SPHL ; теперь в SP лежит SP_for_SP+2 ,то есть адрес, куда поместить своё предыдущее значение
SHLD FIXSP ; сохраняем новый адрес хранения предыдущего значения SP
XCHG ; старое значение SP в HL
XTHL ; вот наконец то сохранили старое значение SP в памяти
VDSKPTR EQU 0yyyyh ; yyyy- адрес ячейки-указателя "дорожки" виртуального диска
LHLD VDSKPTR ;
SPHL ; мы в режиме работы с виртуальным диском ("мешком памяти")
EI ; теперь можно
Вот как то так.. Впрочем это было небольшое нелирическое отступление для благодарных читателей.

Но я Вас спрашивал вообще то в первую очередь про "слой M1"
..."слой" адресного пространства ну допустим верхние 32К ( нижние 32К не трогаю, ибо с клоном РК-86 экспериментирую ) - по названию цикла и обзовём - "M1-слой" адресного пространства будет использоваться ,
то тогда получается, что при PC=x и К.оп.=^[PC=x]=0D3h в слое M1 ,( т.е. OUT ) при значаении байта в основном слое в ячейке с adr=x+1 например 0FEh произойдёт именно пересыл содержимого A в порт по адресу 0FEh .
Так или не так ?
Спрашиваю, ибо слегка не уверен, что верно понял всё в "дэйташиит" про M1
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

petrenko wrote:Ну а как "поместить в стек сам указатель стека"- это Вы полагаю знаете.
Ну мы это, безусловно, знаем, только непонятно, зачем это делать?

Если мы хотим сохранить текущее значение указателя стека, то вполне
достаточно следующих манипуляций:

Code: Select all

   DI
   PUSH PSW ; PUSH B ; PUSH D ; PUSH H ;
   LXI  H,0000H
   DAD  SP
   SHLD FIXSP; просто сохранили старое значение SP    
;              а зачем нам запихивать его в стек?
   LHLD DISKSP; адрес "дорожки" виртуального диска
   SPHL; укажем в стеке
   ...
   ...  ; здесь работаем со стековым виртуальным диском 
   ...
   SHLD DISKSP; сохраним адрес "дорожки" виртуального диска
   LHLD FIXSP; загрузим в HL старое значение SP 
   SPHL; восстановим старое значение SP 
   POP H ; POP D ; POP B ; POP PSW ; 
   EI;  и только завершив работу с SP-диском можно разрешить прерывания!

   FIXSP  DW 0000H; для хранения стека
   DISKSP DW 0000H; текущий адрес в "стековом диске"
А вот как ты предлагаешь - так делать ну никак нельзя!!! :o

Code: Select all

   SPHL ; мы в режиме работы с виртуальным диском ("мешком памяти") 
   EI ; теперь можно
Первый же вызов прерывания испортит твою "дорожку" виртуального диска!!!
Во время работы с виртуальным диском ("мешком памяти") ты не можешь
пользоваться вызовом подпрограмм CALL ADDR - также адрес возврата
тут же испортит твою "дорожку" виртуального диска!!!

Так что с виртуальным диском ("мешком памяти") в стеке ты вынужден работать
при запрещенных прерываниях и не использовать
CALL ADDR / RST N.

Не стоит вводит в заблуждение "благодарных читателей" - всё не так просто! :wink:
iLavr