CP/M BDOS system calls
Вид для печати
Error404, как я уже говорил выше, хочу попытаться реализовать все обработчики прерываний в отдельной странице. Например, по сигналу "подтверждение прерывания" переключать специальную страницу памяти, где и будут расположены все обработчики прерываний. Выход из процедуры прерывания можно осуществить через специальный вектор, одинаковый на всех страницах и содержащий команду RET. Как-то так. Подробно этот механизм я еще не обдумывал, это пока просто идея, которую выношу на общее обсуждение. То же самое касается и наличия/отсутствия общего участка памяти. Его присутствие может дать как определенные преимущества, так и быть недостатком. Недостаток в том, что если он будет задан жестко, то он может стать помехой в плане совместимости, а если его положение и размер сделать программируемым, то это приведет к усложнению схемы. Так что если те же задачи можно будет решить при помощи копирования участков памяти между сегментами при помощи ПДП, я предпочту этот вариант, как более универсальный.
Еще одну проблему предвижу. При переходе по прерыванию в сегмент TSR все отлично, но вот где хранить информацию, из какого сегмента было передано управление? Наверное, придется это аппаратно в какой-то регистр записывать при переключении страниц. Как обрабатывать NMI - другая загадка. Например, подключать для обработки ПЗУ, которое и должно будет разруливать все вопросы. Хотя, если по RESET будет происходить то же самое, то и NMI вроде как и ненужно.
По этой теме у меня была идея использовать чип ОЗУ в качестве программируемого маппера памяти. Например быстродействующие ОЗУ из кэша старых материнок наиболее распространенные 8кб/32кб/64кб дают программируемый дешифратор "13/15/16 в 8". С помощью одной такой ОЗУ можно маппить старшие адреса шины адреса ЦП, адресные ноги выбора страничек памяти, выходы каких-нибудь регистров. При старте компьютера ЦПУ работает в ПЗУ и непереключаемом участке ОЗУ для стека и переменных, считывает с носителя (чтобы карты памяти были сменными) карту для заливки в маппер (в эту ОЗУ=дешифратор), и хоп - мы в любимом маппере. Хоть MSX, хоть в Z180, хоть в Орионовском, каком угодно, хоть в кошмарном от RK-86. :)
Тоже думал на эту тему. Лучше всего использовать ОЗУ с раздельными входами и выходами.
Да, с раздельными будет удобнее, если есть такая статика со словом нужной разрядности.
Или же из обычной (где DI и DO - одни и те же выводы) с добавлением двух буферов АП5 (для 8-битной ОЗУ) - первая АП5 активна когда идеть запись маппера процессором (ОЗУ маппера на запись), вторая при работе маппера в прочую схему (ОЗУ маппера на чтение).
Это вряд-ли. Если некоммутируемый участок выше кода BDOS, то туда вообще никто из CP/M не "лазиит". В качестве недостатка можно считать только, что на некоммутируемый участок расходуется TPA, поэтому не надо увлекаться размером этого некоммутируемого участка. 256 байт вполне достаточно для стека и для простейших подпрограмм чтения/записи байта и вызова п/п-ммы в соседней банке. Можно 256 самых старших адресов (FF00) отдать на порты (они тоже не коммутируются), а ниже (FE00) - 256 байт некоммутируемого ОЗУ из нулевой банки. ПЗУ 0...7FFF ставится в банке 0 и работает только при старте. Из него загружается ROM-BIOS и ПЗУ навсегда отключается. Такая архитектура идеально отвечает Вашим задачам, проще всех в реализации (и к тому же уже была применена 30 лет назад в самодельном ГДР-овском компьютере Bernd Hubler-а).Цитата:
Сообщение от Xrust
Ну так ссылку же на него сразу давать надобно ;), https://hc-ddr.hucki.net/wiki/lib/ex...ebler_buch.pdf
...а "дополнительный" килобайт в верхних адресах мне понравился, очень умно. Клаву, как у него, я испытывал, но в результате сделал проще... Неплохой комп, хотя можно кучу узлов заменить другими м/с, с упрощением...
Две 155РУ2 не подойдут? Правда всего 16 байт и инверсия на выходе, но хоть что-то...
Я имел ввиду совсем другой (графический, а не текстовый) компьютер Huebler-a, описанный в книжке "Mikroelectronik in der Amateurpraxis 3", Militaer Verlag DDR, 1986, которую я купил в магазинчике "Книги соц.стран" (на Литейном) в 1987 году. И приплёл я его только потому, что там используется идея стартового ПЗУ 0...7FFF, отключаемого после загрузки и режим FULL RAM (вся память ОЗУ), хотя как прототип для CP/M-компьютера это не годится, т.к это игрушка типа Синклера, разработанная в 1985. Там всего 1 банка ОЗУ, такт всего 1.5 МГЦ, экранчик мизерный 256*256, к тому же графический и без цвета и ОЗУ непрозрачное (т.е с WAIT, в отличие от СПЕЦИАЛИСТА). Единственное, что там ценного, это хороший бейсик. Книга не оцифрована, так что ссылки дать не мог.Цитата:
Сообщение от rw6hrm
А про компьютер, описанный в PDF-файле из Вашей ссылки, я знал только из списка литературы. Это комп ещё из 1984 года, описанный в книге B.Huebler, K.Evert. Ausbaufaehiger Mikrocomputer mit dem U880. Berlin, 1985. Не знал также, что Вы хорошо читаете по немецки. Клавиатура в моей книге о которой речь, использует 155ИД3 и матрицу 16*4, а какая клавиатура в компьютере из Вашей ссылки, я пока не разбирался.
Подойдут. Грамотные люди утверждали, что для таких целей нет ничего лучше, чем 555ИР26 и 8-ми окон с размером 8 кб каждый. Но ведь топик стартер решил, что цельнобанковая коммутация лучше, чем изощрённый диспетчер памяти, т.к его не поддержать программно, а использование создаёт лишние программные хлопоты.Цитата:
Сообщение от rw6hrm
Я еще ничего не решил. В процессе. Прежде чем браться решительно за дело, я собираюсь промоделировать несколько узлов, пощупать их. И в зависимости от результатов и буду выбирать вариант схемы.
Хотя насчет цельнобанковой схемы пока альтернатив не вижу.
Вот еще подумал и решил, что пока банк системы и TSR лучше объединить. Так проще разрулить, куда возвращаться после завершения обработки прерывания.
И все же, я пока не понимаю, как в системе со страницей TSR, включающейся поверх рабочего кода по аппаратному прерыванию, будет обрабатываться случай, когда TSR накрывает стек - его же ставит пользовательская программа (и как самый запущенный случай - накрывает частично: один байт накрыт, второй нет). Предполагается включать TSR по INTA, но это событие наступает раньше, чем процессор пишет на стек адрес возврата из прерывания. Он или пропилит включившийся код TSR в непредсказуемом месте (если TSR это ОЗУ) и вероятен последующий "улёт", или же потеряется (не запишется) адрес возврата если страница TSR в ПЗУ.
Error404, что тут скажешь. В этом моменте и заключается главная проблема. Самый оптимальный вариант - переключать страницы уже после сохранения адреса в стек. Реализовать это наверное достаточно сложно, особенно учитывая наличие контроллера прерываний и требование к совместимости с разными процессорами (8080, 8085, Z80). Но, возможно, не все так страшно. У меня правда нет исчерпывающей информации о том, как работает со стеком CP/M и приложения. Насколько я знаю, стек расположен в верхней части TPA и без большой необходимости его никто не перемещает. Конечно, приложения могут пользоваться стеком для быстрого перемещения данных. Но я не знаю, насколько часто и в каких случаях пользовались этим приемом. Для данной системы в этом нет необходимости, т.к. будет более быстрый и удобный способ - ПДП. Хорошим вариантом проверки будет построение стенда, моделирующего эту систему в упрощенном виде. Вот пожалуй и ТЗ для следующего этапа: построить тестовую систему с оперативной памятью 128к в виде 2х страниц и контроллером прерываний.
Стек CP/M и приложения ставят в любое место от ~60H до BDOS (CP/M ставит стек на 80H и он опускается до ~60H). Но драйверы загруженные на входы CP/M-BIOS могут переставлять стек на некоммутируемую область ОЗУ и затем переключать банку. Если прерывания организовать за счёт чтения с шины байта FF (т.е без контроллера прерываний), то удобнее всего, если в области 38H находится ПЗУ (как в Синклере). Если во всех банках в области 38H расположить один и тот же код, то не вижу никаких проблем со стеком из-за прерываний (если не допускать рекурсивности прерываний), тем более если есть некоммутируемое ОЗУ выше FE00.Цитата:
Сообщение от Xrust
По прерыванию сохраняем стек программы в некоммутируемой области, ставим стек на некоммутируемую область, считываем и сохраняем всю конфигурацию. Если коммутация цельно банковая, то это один байт в порту коммутации банок, а если многооконная, то считываем и сохраняем содержимое тех окон, которые использует код обработчика прерываний. Затем включаем банку или окно (окна) в которых расположен код обработчика прерываний и уходим на вход процедуры обработки прерываний. Если надо разрешить рекурсивность прерываний (т.е вызов очередного прерывания в момент пока обслуживание предыдущего прерывания ещё не закончено), то код усложнится, но это тоже решаемо.
Но встречный вопрос, а зачем Вам нужны прерывания?
Чтобы считать время по импульсам 50 Гц? - Для этого предназначена 512ВИ1. Или периодически проверять неактивную клавиатуру? Или по прерываниям мгновенно реагировать на клавиши, как в IBM PC, если клавиатура активная (т.е сама даёт сигнал и символ или скан-коды)? Но как раз в CP/M без этого прекрасно обходятся, т.к не волнуют затраты ресурса на опрос клавиатуры и нет процедур настолько надолго прерывающих опрос клавиатуры, что символы теряются. Некоторые программы CP/M, если они вынуждены надолго прервать опрос клавиатуры, сами берут на себя периодический опрос клавиш, так например редакторы, делая вывод (ролик экрана) после вывода каждой строки контроллируют STATUS (и делают ввод, если что-то нажато), и по окончании долгой процедуры, код клавиши нажатой в это время будет взят из буфера (хотя в отличие от MSDOS буфер только на 1 символ).
Поэтому, единственная вещь, ради чего стоит трахаться с прерываниями, это многозадачность, о чём я и упомянул, когда прочитал о TSR обслуживаемых по прерываниям. Вы отмахнулись, что многозадачность не нужна. Это и ежу понятно (если нет межпрограммного обмена или хотя-бы клип-боарда), но как ещё ранее я упоминал, имеется ввиду не многозадачность с равноправными задачами, а однозадачность, но с одновременно выполняемыми маленькими резидентными процессами, в основном предназначенными для контроля флагов, датчиков, событий и обслуживания периодических явлений, типа счёта времени, иными словами для обслуживания периферии в реальном времени.
Процесс это маленькая, короткая по времени прогона подпрограмма, которая должна прогоняться периодически (неважно, раз в 20 МСЕК или раз в 10 минут). Для обслуживания периферии достаточно одного прерывания. Резидентные процессы организованы в цепочку. По апп.прерыванию программа смотрит в таблицу загруженных процессов. В таблице зафиксированы адреса обслуживания загруженных процессов или 0000, если это последний процесс в цепочке. По очереди каждый из загруженных процессов получает управление. Ясно, что для однозадачности с процессами, рекурсивность прерываний абсолютно не нужна. Если надо (т.е процессы ресурсоёмкие или их очень много), можно за одно прерывание обслуживать только один процесс, а в следующем прерывании следующий.
Резидентный процесс может, например, регенерировать динамическую память, выводить текущее время в правом верхнем углу экрана, печатать на принтере в фоновом режиме (в CP/M есть программа для такой задачи, но там апп.прерывания эмулируются за счёт перехвата функций BIOS работающих с клавиатурой), обслуживать клавиатуру (не важно активную ли пассивную матричную), контроллировать запрос на начало передачи по линии, в общем обслуживать любую периферию, что работает в реальном времени. В любом случае, все процессы, вместе взятые, не должны занимать более 50% времени периода апп.прерываний. Если процессу нужно больше времени, он должен разделить задачу на куски и выполнять за одно прерывание только часть своей задачи.
Вот такую многозадачность я имел ввиду. Не стоит думать, что это сложно, объём кода вряд-ли превысит 256 байт. А практически это эквивалентно, как многоядерная ЭВМ, где есть основной процессор и несколько одновременно работающих очень медленных процессоров прогоняющих TSR-программы, обслуживающие периферию и не мешая при этом прогону основной программы.
Впрочем, как показала практика, удобно встроить в ДОС на машине с несколькими банками ещё одну основную задачу. А именно, так называемый Супервизор, (являющийся расширением драйвера клавиатуры). Это программа, которая всегда хранится в ОЗУ какой-либо банки, никому не мешая. Затем, по нажатию сочетания клавиш, прикладная программа прерывается, в центре экрана очищается окно и в нём стартует Супервизор. В простейшем случае это отладчик или многобанковый RAM-монитор. Я делал такое для ДОС ОРИОНА, оказалось очень удобно. Конечно не так, как в ПК11/16, где в процессоре есть второй набор регистров, что более просто позволяет реализовать отладку. Но и для Z80 это лучше, чем CP/M-отладчик, т.к не требует в TPA ОЗУ для него. У меня в Супервизоре был RAM-монитор и HELP по функциям ROM-BIOS, CP/M, упр.кодам консольного драйвера и кодам для рисования рамок, т.е вся та справочная информация, что постоянно нужна при разработке ПО. Супервизор просто запускался, как обычная программа, после чего становились доступны его функции.
В системе с TSR на прерываниях управлять ими удобно с помощью такого же Супервизора.
barsik, если вы это называете многозадачностью, то именно это я и хочу реализовать. Тем более, что для CP/M старших версий требуется прерывание от таймера.
Прерывания способны упрощать решение ряда задач, освободить процессор от ненужных действий, упростить работу с периферией.
Прерывания использовались в большинстве западных ЭВМ на Z80. Ничего плохого в том, чтобы их использовать в аналогичной ЭВМ и сейчас. Это выгодно и профессионально и топик стартер вполне разумно собрался их использовать. Я лишь изложил стандартный механизм использования TSR, используя современную терминологию. Да и почему не использовать, если это полезно и просто? Если подключать драйвера периферии без прерываний, то это тормозит намного больше, да и программирование сложнее. Например, попробуйте сделать загружаемый драйвер мыши в компьютер без прерываний и TSR.Цитата:
Сообщение от shurik-ua
Я как раз против неоправданных, бессмысленных усложнений архитектуры и ПО. Я всегда за простоту, потому что знаю, что только простые вещи реализуемы. Лучшее враг хорошего. Я часто убеждался, что если не довольствоваться простыми улучшениями, которые легкодоступны, а стремиться к более сложному и трудоёмкому идеалу, то вообще нет движения (или надо ждать ровно 5 лет). Потому-то ОЗУ РК86 до сих пор всего 32 кб. Потому и топик стартеру советую всё делать как можно проще.
Некоторым здесь прерывания явно не по душе. Это наверное признак РК головного мозга :) Это конечно шутка и я никого не хотел обидеть, но доля правды в этом есть.
Меня неправильно поняли - я как раз за прерывания - например крайне полезно получать прерывание при получении байта через COM порт.
Я про то что регенерацией должна заниматься какая-нибудь отдельная схема, но никак не программа )
Ну и к тому ещё что в современных чипах почти везде есть режим self-refresh - это я про SIMM-72.
p.s. С РК дел не имел если что )
Применительно к Z80 проблема регенерации вообще не стоит т.к в него это уже встроено. Если используется ОЗУ с вектором регенерации более 7-ми, например 11, то легко добавить счётчик, и даже это, возможно, будет проще, чем изобретать схему как использовать режим 'RAS before CAS'.Цитата:
Сообщение от shurik-ua
Я упомянул программную регенерацию, т.к топик стартер использует КР580 и оттого, что вспомнил, что прерывания в IBM PC XT и AT использовались именно для регенерации ОЗУ (и это тормозило CPU очень мало). Такая регенерация - это вариант для бедных, т.к схема для регенерации динамического ОЗУ обходится намного дороже, чем введение прерываний (например, смотрите, как громоздко это сделано в блоке динамического ОЗУ МИКРО-80).
А для богатых рекомендуется применение специальных БИС для динамических ОЗУ - Intel 8202, 8204, 8208, MC3242 и др. Они не только заменяют мультиплексоры, но и сами регенерируют ОЗУ в паузах доступа. Такой вариант лучше, т.к при использовании прерываний для регенерации, их нельзя запретить, отчего машина не может работать в реальном времени. А это создаёт большие проблемы при необходимости программно отмерять короткие задержки, в частности, при программной реализации передачи по последовательному интерфейсу или в формате МГ. Поэтому скорость программного обмена по линии между двумя 8-ми разрядками - 8-10 кб в секунду, а такой же точно обмен между IBM PC и 8-ми разрядкой составляет всего 150 байт в секунду.
Вроде же у ИР26 какой-то мизерный объем памяти, т.е. это как есть регистр, из него дешифратор на кучу состояний не сделаешь даже если несколько ИР26 поставить? Т.е. они годны именно как регистры в какую-то "фиксированную" схему где заранее известно какой порт (уже готов его селект) и сколько и каких страниц памяти будет (как будут соединены регистры через коммутаторы с адресами ОЗУшек). А не так чтобы можно было на лету перепрограммировать и адрес выборки порта/регистра, и количество портов (один/два...), и "схему соединения" между регистром и адресными ножками ОЗУ. В этом смысле, большое ОЗУ дает функционал приближающийся к CPLD.
Это же бубль-гум! В MSX (если не ошибаюсь, я еще не дошел) мапперы и строили на таких.
- - - Добавлено - - -
По поводу как конфигурировать на лету, это задача для энтузиастов. И потребует думаю какой-то доли рассыппухи.
Именно! Причем исключительной элегантности красота при своей простоте.
Ну тут нужно как то компромисс найти. Иначе может получится, что регистров маппера будет больше чем ячеек ОЗУ :D
А маппер тоже как-то адресовать нужно. ИР26 - это регистровый файл 4х4, другими словами две ИР26 - это четыре 8-ми битных регистра.
В MSX эта вся ерунда наращивается каскадно: слоты-субслоты-маппер(ы). И "в теле такая приятная гибкость образовалась" :)
Сподобился я тоже, и запилил тестовый стенд из платы принтера СМ6337, там и ВН59 и ВИ53 наличествует.
Погонял Ваши примеры и убедился, что и без прерываний, и с прерываниями в том виде как у Вас (с поправкой на мое железо), ожидаемо давится и не может прожевать поток символов. Нужен буфер. И основная Ваша ошибка, что долго "сидите" в обработчике прерывания.
Так нельзя делать, попав в прерывание нужно максимально быстро сделать необходимый минимум и выметаться оттудова. :)
В проекте с ВВ51 и клавиатурой, кстати, тоже самое.
Скрытый текст
Ахтунг! Для упрощения буфер обязательно должен быть выровнен по границе 256 байт.
Ну и никаких проверок переполнения и т.п. нет.
Код:include "8085.inc"
; ПРОГРАММА НАСТРОЙКИ И ПРОВЕРКИ УСАПП ВВ51А
;
;_______ВЕКТОРА ПРЕРЫВАНИЙ____________________________
org 00h ;int0 он же reset
DI
jmp INIT
org 04h
ret
nop
nop
nop
org 08h
ret
nop
nop
nop
org 0Ch
ret
nop
nop
nop
org 10h
ret
nop
nop
nop
org 14h
ret
nop
nop
nop
org 18h ;вектор int6 UART'a
jmp RXD_INT
nop
org 1Ch
ret
nop
nop
nop
org 20h
INIT:
;_______УСТАНОВКА СТЕКА____________________________
LXI SP, RAMTOP
;_______УСТАНОВКА КОНТРОЛЛЕРА ПРЕРЫВАНИЙ____________________________
MVI A, 00010110b ; (СКИ1) ICW1 = addr000xxxxx, edge, x4, single, no ICW4
; таблица векторов пока прибита гвоздями в ПЗУ
OUT PICa0
MVI A, 00000000b ; (СКИ2) ICW2 = addr00000000
OUT PICa1
MVI A, 10111111b ; (СКО1) OCW1 = mask
OUT PICa1
;_______УСТАНОВКА ТАЙМЕРА____________________________
MVI A, 00111110b ; Chanel 0, LSB then MSB, mode 3, Binary
OUT TIM2CMD
MVI A, 2000000 / 16 / 9600 ; Divider LSB (2Mhz / 16 / 9600)
OUT TIM2C0
MVI A, 0 ; Divider MSB
OUT TIM2C0
;_______УСТАНОВКА_УСАПП_В_ИСХ._СОСТОЯНИЕ________
MVI A, 01H
OUT CW51
OUT CW51
MVI A, IR
OUT CW51
;_______ЗАПИСЫВАЕМ_ИНСТРУКЦИЮ_РЕЖИМА____________
MVI A, 01001110b ;4Eh = 1stop, no parity, no control, 8 bit, 16x
OUT CW51
;_______ЗАПИСЫВАЕМ ИНСТРУКЦИЮ КОМАНДЫ___________
MVI A, TXEN+DTR+RXE+RTS
OUT CW51
;_______Обнуляем счетчик и указатель приемника___________
xra A
sta RXCNT
sta RXPNT
ei
;***********************************************************
; Основной цикл
;***********************************************************
LOOP:
CALL RXD ;получаем в акк символ из буфера или перенос
jc LOOP ;перенос? - буфер пуст
CALL TXD ;возвращаем символ обратно
cpi "@" ;спецсимвол?
jz LOOP1
MVI A,"#" ;выводим символ квитанции
CALL TXD
JMP LOOP
LOOP1:
lxi H, MSG ;в HL адрес сообщения
call TXHL ;выводим сообщ по HL
call PR_MSG ;выводим сообщение следующее непосредственно за
db "QWERTY",0
jmp LOOP
;***********************************************************
; ПОДПРОГРАММА ПЕРЕДАЧИ БАЙТА ИЗ АККУМУЛЯТОРА
TXD:
push PSW
;_______ЖДЕМ_ГОТОВНОСТИ_________________________
TX1:
IN CW51
ANI TXRDY+DSR
CPI TXRDY+DSR
JNZ TX1
;_______ПЕРЕДАЕМ_БАЙТ___________________________
pop PSW
OUT DAT51
RET
;***********************************************************
; ПОДПРОГРАММА ПРИЕМА БАЙТА В АККУМУЛЯТОР
; перенос - признак пустого буфера
RXD:
lda RXCNT ;загружаем позицию приема
push B
mov B, A
lda RXPNT ;загружаем позицию чтения
cmp B ;сравниваем
pop B
stc
RZ ;совпало - буфер пуст - выходим с переносом
push H
mov L, A ;не совпало...
mvi H, RXBUF ;в HL позиция чтения буфера
inr A ;увеличили
sta RXPNT ;обновили
mov A, M ;загружаем из буфера
cmc
pop H
ret
;***********************************************************
; ОБРАБОТЧИК ПРЕРЫВАНИЯ RXD
RXD_INT:
di
push PSW
push H
lda RXCNT ;загружаем текущую позицию
mov L, A
mvi H, RXBUF ;в HL позиция буфера
inr A ;увеличиваем
sta RXCNT ;обновляем
in DAT51 ;читаем принятый байт
mov M, A ;заносим в буфер
mvi A, 00100000b ; СКО2а обычный конец прерывания
out PICa0
pop H
pop PSW
ei
ret
;***********************************************************
; п/п вывода сообщения размещенного сразу после комманды "CALL PR_MSG"
; вход: [PC]-адрес начала сообщения
; выход: [PC]-адрес начала кода продолжения программы
PR_MSG:
pop H
call TXHL ; вызов п/п вывода строки по [HL]
pchl ; equivalent folowing 2 commands:
;PUSH H
;RET
;***********************************************************
; ПОДПРОГРАММА ПЕРЕДАЧИ Z-ended строки по [HL]
TXHL:
mov A, M
inx H ;увеличиваем HL перед проверкой для корректного возврата из PR_MSG
ora A ;проверка на конец строки
rz
call TXD
jmp TXHL
;***********************************************************
MSG:
db "ASDFH",0
;_____________ВНЕШНИЕ МЕТКИ И КОНСТАНТЫ_______
RAMTOP = 77FFH ; Верхушка стека
RXCNT = 6000H ; Счетчик принятых символов
RXPNT = 6001H ; Указатель буфера
RXBUF = 61H ; MSB адреса буфера приемника
;
;___АДРЕСА_РЕГИСТРОВ_УСАПП______________________
DAT51 = 48H ; РЕГИСТР ДАННЫХ
CW51 = 49H ; РЕГИСТР КОМАНД
;___АДРЕСА_РЕГИСТРОВ_ТАЙМЕРОВ______________________
TIM1C0 = 50H ; Timer c0
TIM1C1 = 51H ; Timer c1
TIM1C2 = 52H ; Timer c2
TIM1CMD = 53H ; Timer cmd
TIM2C0 = 58H ; Timer c0
TIM2C1 = 59H ; Timer c1
TIM2C2 = 5AH ; Timer c2
TIM2CMD = 5BH ; Timer cmd
;___АДРЕСА_РЕГИСТРОВ_КОНТРОЛЛЕРА_ПРЕРЫВАНИЙ_____
PICa0 = 78H ;
PICa1 = 79H ;
;
;___КОМАНДЫ ВВ51________________________________
TXEN = 01H ; ПЕРЕДАТЧИК ВКЛЮЧЕН
DTR = 02H ; УСТРОЙСТВО ГОТОВО
RXE = 04H ; ПРИЕМНИК ВКЛЮЧЕН
SBRK = 08H ; ПРЕРЫВАНИЕ ПЕРЕДАЧИ
ER = 10H ; СБРОС ОШИБОК ПРИЕМА
RTS = 20H ; ПЕРЕДАЧА РАЗРЕШЕНА
IR = 40H ; ПРОГР. СБРОС УСАПП
EH = 80H ; РАЗРЕШЕНИЕ ПОИСКА СИНХРОСИМВОЛА
;
;__РЕГИСТР СОСТОЯНИЯ ВВ51_______________________
TXRDY = 01H ; ПЕРЕДАТЧИК ГОТОВ
RXRDY = 02H ; ПРИЕМНИК ГОТОВ
TXE = 04H ; ПЕРЕДАЧА ЗАКОНЧЕНА
PE = 08H ; ОШИБКА ЧЕТНОСТИ
OE = 10H ; ПЕРЕПОЛНЕНИЕ ПРИЕМНИКА
FE = 20H ; ОШИБКА ФОРМАТА
SYNDET = 40H ; СИНХРОСИМВОЛ НАЙДЕН
DSR = 80H ; ПЕРЕДАТЧИК ДАННЫХ ГОТОВ
[свернуть]
Всё не читал, но видел что была дискуссия по поводу вывода на ВГ75... В 90-х делал как то эмулятор терминала на нём. Там штук 8 мс кажись всего, 80х25, поддерживалось несколько кодировок (КОИ-8, ALT в т.ч.) - переключение на лету, с клавиатуры. Ну а скроллинг был, ПУЛЯ! Не успевал кнопки жать.)) PC отдыхало.))
Вспоминаю, этот видео-терминал был прикручен к Ленинграду-2 в виде маленкой платки, с FDD контроллером. Что позволяло иметь полноценную CP/M и полноценный Синклер с FDD. И даже что то, кажись, отлаживалось из CP/M в Синклере...
Эх, молодость!
Терминалу и видеокарте на ВГшке вот тут кости мыли :) http://zx-pk.ru/threads/26455-chto-m...suzhdenie.html
Считаю что для CP/M подходит как нельзя лучше. Ну может несколько громоздко (кстати, без ВТ57!), зато вписывается в ту эпоху.)) А то как то Z80 и PIC24/32... не совсем, как по мне.))
С побился поюзать в ВГ75 в 80Г.. Видимо мой детский мозг отверг этот чудный девайс:)
Есть исходник, по нему можно понять что-куда. Схема не сохранилась, но могу объяснить на пальцах.) Нужно?
Хотя смотрю, сейчас люди делают терминал на одной меге328. Совсем просто.)
- - - Добавлено - - -
Коль тема о компьютере для CP/M, поделюсь своей реализацией.
Одна платка (в корпусе роутера, ~10х15 см), выпилил из устройства)).
Z80H 8 MHz, 64 RAM (2x 62256), 2x 256 Flash диск (2x AT29c020), RTC (DS12887), 2x RS232 38400 (2x 8251).
Поставил QP/M (та же CP/M 2.2 + RTC). Простенько, никаких движущихся частей.))
В том примере, мной приведенном, на самом деле есть грубая ошибка. Главный цикл отсутствует. Плюс еще была аппаратная ошибка с формированием сигнала прерывания. От того и работало все загадочно и неправильно. До "потока символов" там дело не дошло, помешал мой "поток сознания", прошитый во флешку :v2_dizzy_facepalm:
Надо было бы давно поправить пост, да руки не доходят. А с потерями символов я расправился аппаратным управлением. На время "пережевывания" символа я просто торможу прием.Ни одной потери символаНи единого разрыва! (С)
Это если есть возможность его организовать. Иногда бывает нежелательно, либо невозможно.
Или такой вариант оправдан когда имеется жесткое ограничение по памяти под буфер. Но тогда теряется смысл прерываний, можно и софтово зарулить.
Если есть возможность выделить буфер, то и прерывания, и процессорное время рационально используется. Можно и на передачу примерно также сделать.
Особенно ощутимо будет на низких скоростях и коротких сообщениях размером меньше буфера.
Какая нибудь сторонняя железяка, которая время от времени пуляет сообщениями в десяток другой символов, вроде сканера штрихкодов.
Ну а "тормоз" приема прикрутить уже к переполнению буфера.
TomaTLAB, со всем согласен, но мне неохота возиться было. Всему свое время. Теперь надо сочинить что-то вроде монитора, с командами файлообмена через порт, запуска и отладки программ. Когда этот монитор закончу, можно будет приступать к расширению аппаратной платформы.
Кстати, о птичках:
http://www.sinclairzxworld.com/viewtopic.php?t=1553
Вложение 62209
Ну вот, жизненный цикл макетки подошел к завершению. Свои задачи она выполнила и теперь ей на смену должна прийти другая, более сложная.
Вот простейший "монитор", который я для нее написал. Работает он через последовательный порт. Его основная функция - загрузка файлов через терминал в ОЗУ и запуск программ с адреса 8000h. Кроме того имеются подпрограммы ввода и вывода. Ввод с использованием прерываний и аппаратным управлением потоком.
Схема контроллера простейшая, включение компонентов типовое - КР580ВМ80, КР580ГФ24 с кварцем 22.1184 Мгц, КР580ВК28(38), В качестве ПЗУ используется AT28C64, начинается с адреса 0000h, ОЗУ статика КР537РУ10 2кб с адреса 8000h. "Дешифратор адреса" выполнен на ЛА3, тактовая частота процессора 2.4576 МГц подается и на тактовый вход КР580ВВ51. Поделенные на 16 при помощи ИЕ5 тактовые импульсы подаются на /TxC /RxC ВВ51, обеспечивая скорость порта 2400 и 9600.Код:include "8085.inc"
;----RST 0---------------------------------------------------------------------------------------------------------
di
lxi sp,ramtop
jmp init
nop
;----RST 1---Разрешение передачи /RTS вкл-----------------------------------------------------
mvi a,rxe+txen+dtr+rts
out cusart
ret
nop
nop
nop
;----RST 2---Вывод строки [HL] в терминал---------------------------------------------------
strout: mov a,m ; загрузка символа
ana a ; проверка конца сообщения
rz
rst 3 ; вывод символа
inx h
jmp strout ; к следующему символу
;----RST 3--Вывод символа в терминал---------------------------------------------------------
chout: push psw
sym1: in cusart ; загрузка слова состояния
ani txrdy+dsr ; проверочная маска
cpi txrdy+dsr ; проверка готовности передатчика
jnz sym1 ; если не готов то sym1
pop psw
out dusart ; вывод в порт
ret
nop
nop
;----RST 5--Вывод HEX в терминал---------------------------------------------------------------
hexout: push psw
rrc
rrc
rrc
rrc
call nibout
pop psw
call nibout
ret
nop
nop
nop
;----RST 7--Обработчик прерываний УСАПП------------------------------------------------
int: push psw
mvi a,rxe+txen+dtr
out cusart ; /RTS выкл
in dusart ; чтение из порта
sta lastch ; сохранение символа в переменной
pop psw
ei
ret
;------Главный цикл--------------------------------------------------------------------------------------
loop: hlt ; ожидание
lda lastch ; последний принятый символ
rst 3 ; вывод символа
cpi 6Ch ; если "L"
jz sload ; то переход к загрузке
cpi 67h ; если "G"
jz goto ; запуск программы в озу
rst 1 ; /RTS вкл
jmp loop
;------Загрузка через порт--------------------------------------------------------------------------
sload: lxi h,loadstr ; адрес строки
rst 2 ; вывод строки
lxi h,ramp ; загрузка указателя
rst 1 ; /RTS вкл
sload1: hlt
lda lastch ; загружаем байт в аккумулятор
mov m,a ; записываем в память
inx h ; HL+1
rst 3 ; вывод символа
rst 1 ; /RTS вкл
jmp sload1 ; цикл загрузки
;------Запуск программы с адреса 8000h---------------------------------------------------
goto: lxi h,gotostr ; адрес строки
rst 2 ; вывод строки
rst 1 ; /RTS вкл
call 8000h
lxi h,endstr ; адрес строки
rst 2 ; вывод строки
rst 1 ; /RTS вкл
ret
;------Инициализация-----------------------------------------------------------------------------------
init: call initusart
lxi h,introstr ; адрес строки
rst 2 ; вывод строки
ei
jmp loop
;---Установка ВВ51 в исходное состояние-----------------------------------------------
initusart: xra a
out cusart
out cusart
out cusart
mvi a,ir ; Сброс
out cusart
mvi a,s2400
out cusart ; Установка режима порта
rst 1 ; /RTS вкл
ret
;----печать HEX младшего полубайта----------------------------------------------------
nibout: ani 0Fh
cpi 0Ah
jm nib1
adi 7
nib1: adi 30h
rst 3 ; вывод символа
ret
;-------------------------------------Данные----------------------------------------------------------------
introstr: db 0dh,'Monitor nano:',0dh,00h
loadstr: db 0dh,'Loading:',0dh,00h
gotostr: db 0dh,'Go 8000h',0dh,00h
endstr: db 0dh,'End program.',0dh,00h
;--------------------Константы и указатели--------------------------------------------------------
ramtop= 087DFh ; Верхушка свободной памяти
ramp= 08000h ; Начало оперативной памяти
lastch= 087E1h ; Редактируемый символ
;---Адреса регистров УСАПП----------------------------------------------------------------------
dusart= 00h ; регистр данных
cusart= 01h ; регистр команд
;---Режимы УСАПП--------------------------------------------------------------------------------------
s9600= 04Eh ;9600_8_no_1
s2400= 04Fh ;2400_8_no_1
;---Команды УСАПП------------------------------------------------------------------------------------
txen= 01h ; Передатчик включен
dtr= 02h ; Устройство готово
rxe= 04h ; Приемник включен
sbrk= 08h ; Прерывание передачи
er= 10h ; Сброс ошибок приема
rts= 20h ; Передача разрешена
ir= 40h ; Программный сброс
eh= 80h ; Режим Hunt
;---Регистр состояния УСАПП-----------------------------------------------------------------------
txrdy= 01h ; Передатчик готов
rxrdy= 02h ; Приемник готов
txe= 04h ; Передача закончена
pe= 08h ; Ошибка четности
oe= 10h ; Ошибка переполнения
fe= 20h ; Ошибка формата
syndet= 40h ; Синхросимвол найден
dsr= 80h ; Передатчик терминала готов
Как то сурово всё - rst 2, rst 3, которые комментировать нужно... Какие то коды 0dh, 0ah, 30h. Неужто нагляднее нельзя? Нафига тогда макро люди придумали? Вывод текста тоже как-то простенько. Разве нельзя типа, PrintStr db CR, LF,'Hello',0, чем придумывать метки, а затем долго глядеть, а что ж там по этой метке? Или это стиль ТОГО времени? Не 80-х даже.))
Понятно, что "кто как хочет, так и...", но что мешает стремиться к лучшему? rst не несёт никакой смысловой информации, поэтому либо нужно помнить что оно делает, либо комментировать. Определив макрос, Вы уже можете вместо rst писать что то более осмысленное. Ну и в дальнейшем, если захотите изменить rst на другой (или на call, или на группу команд), просто меняете макро определения, а не все rst в тексте. Это простые примеры и это Ваше дело, применять их или нет. Макросредства ведь придумали для улучшения жизни. И с ними очень много чего можно намутить. И кроме наглядности, реально меньше текста нужно вводить. Но это так, мысли вслух.))
M80, видно, что вы нифига не педагог. Надо сначала похвалить, а потом указывать на недостатки :) Иначе никто не захочет стремиться к лучшему