Paguo-86PK wrote:Нe поверите! Написал Windows'86 за неделю
Paguo-86PK wrote:А Вы как к этому относитесь? Мартышкин труд?
Лично мне непонятна цель ваших доработок ПЗУ. И я бы не называл введение в ROM-BIOS оконных параметров, позволяющих делать вывод в окно, - Windows. Это вводит в заблуждение из-за явной параллели с ОС Windows.
В ПЗУ ОРИОНА М2 и М3 есть оконные параметры:
Code: Select all
HISCRN EQU 0F3CFH ; начальный адрес экрана
WDTSCR EQU 0F3D0H ; ширина экрана в байтах
FRSTLN EQU 0F3D4H ; номер первой строки экрана
SCHIGH EQU 0F3D5H ; количество строк
Все мои драйверы консоли для ОРИОНА управляются этими ячейками. Это позволяет иметь экран любого размера в любом месте ОЗУ. Если не считать задачи очистки окна (т.е задал окно и выкинул на вход CONOUT код $1F), практически никто эти ячейки не использовал. Т.к, во-первых, драйвер в ПЗУ слишком примитивен и не поддерживает цвет. А оконность нужна в первую очередь в цвете. А цвет предполагает байтовый шрифт, в то время, как в ПЗУ используется тормозной небайтовый шрифт (конфликтующий в цвете с железом ОРИОНА).
Это я к тому, что для РК86 при разработке его ROM-BIOS надо было так и сделать, потому что ВГ75 позволяет задать, как и в ОРИОНЕ, экран в любом месте ОЗУ и даже менять его размер (программно). Из-за того, что это не сделано, резидентный драйвер работает только на единственный экран 76D0 с жёстко фиксированным размером в 25 строк, а граф.операторы бейсика предназначенные для вывода псевдографики не работают в псевдографическом режиме с экраном 64+30.
Не хотел бы Вас расхолаживать и демотивировать, но в монохроме вывод в окно по сути не требует коррекции ПЗУ. Т.к достаточно добавлять в код программ всего несколько десятков байтов, чтобы корректировать координаты вывода в соответствии с заданным окном. Позиция вывода в РК и без того корректируется резидентным драйвером (к номеру строки прибавляется 3, а к номеру столбца 8 ). Что мешает эти числа смещений 3 и 8 хранить как параметры в ячейках, что позволит их оперативно менять, смещая тем самым начало окна вывода, а также дополнить ещё двумя служ.байтами в ОЗУ - размерами окна по вертикали и горизонтали. Получится оконность ценой всего в десяток байт.
Если бы мне понадобилось ввести оконность в ПЗУ РК, то я бы не стал корректировать стандартный код драйвера вывода. Потому что игры РК:
http://ruecm.forum2x2.ru/t1096-topic#13866. Из-за этого, чтобы осталась совместимость, код драйвера должен остаться тем же. Хотя сам код внутри ПЗУ вполне можно двигать (но надо знать на какие внутренние входы неграмотные РК-игры нагло лезут, их нельзя сдвигать).
Если надо доработать драйвер, то или вводят другие входы или имеющиеся входы векторизуют. Более грамотна векторизация. Это позволяет оперативно менять драйвер вывода и ввода. В РК надо (как и было сделано в ОРИОНЕ) векторизовать входы F809, F803, F81B и F812. В базовом ОРИОНЕ забыли векторизовать F81B (что мешает загрузить драйвер полностью иной физически клавиатуры). Я попытался это исправить, для чего занял 2 ячейки в системной области F3F0, но нашлись люди, которым вдруг (или из вредности) захотелось эти же ячейки использовать как рабочие для обычных программ (хотя в них для использования под раб.ячейки оставалось ещё ~48 кб ОЗУ, а ячейки F3F0 были резервированы именно для расширения ROM-BIOS).
Для вывода достаточно заменить только F809. Но для позиционирования курсора надо менять ещё и подрограммы клавиатурного ввода. Для размещения векторов есть много свободных ячеек в области раб.ячеек ПЗУ и выше экрана (7FF4...7FFF). Разумно векторизовать процедуры вывода курсора и процедуру настройки режима. Тогда можно менять не только позицию, но и форму курсора (форма курсора меняется при настройке ВГ75 подпрограммой F82D, хотя и адрес внутреннего входа п/п-ммы PUSKVG нельзя менять). Или можно ввести одну ячейку для байта параметра режима, который позволяет менять форму курсора - тонкий мигающий штрих на линии подчёркивания или мигающее знакоместо, что намного симпатичнее, в моих ПЗУ РК было так).
К тому же векторизация входов в ПЗУ удобна для отладки. В ходе разработки загружаем свой драйвер и тестируем его. Перешивать ПЗУ (или менять файл прошивки в эмуляторе) достаточно лишь раз. А результат тот же самый - ввод/вывод делает ваш код, а не код от автора РК С.Попова из 1986 года.
А если делать серъёзную доработку ROM-BIOS РК86 (хотя я не вижу в этом необходимости) разумно ориентироваться на полный объём ПЗУ в 8 кб. Или хотя бы на те 4 кб, что заложены в ПЗУ РК изначально его разработчиками. Они заложили возможность разместить во втором ПЗУ РФ2 (F000...F7FF) код расширения монитора.
В стандартном РК-мониторе, если первая буква директивы в командной строке не является базовой командой монитора, то делается JMP на F000, где должен располагаться командный интерпретатор пользователя. Который например, может обслуживать команды DOS. Хотя и это неправильно. Расширяющий резидентный CCP командный интерпретатор пользователя должен стартовать первым и только, если он не обслужил команду, лишь тогда приходит очередь резидентного интерпретатора команд.
Paguo-86PK wrote:В общем, интересно было бы в перспективе разработать адекватную прошивку нового МОНИТОР-а «Windows'86» и проверить её на реальной машине…
Для РК эмуляторы достаточно точные. Хотя точно эмулировать все нюансы ВГ75 им было очень сложно. Потому для РК нет разницы между реалом и эмулятором. Если не делать Демо-сцену с чтением статусного регистра ВГ75 очень точно привязанное к числу машинных команд.
Нет проблем переделать ПЗУ РК. Но так как это делаете Вы это делать неэффективно. Так Вы тратитите в многие разы больше трудов, чем если взять исходник и менять всё что надо в нём. Например, когда-то я за счёт более эффективного программирования выиграл в коде РК-шного ПЗУ для КР580 (не помню сейчас точно сколько) где-то ~180 ячеек (а для Z80 ещё больше). И на это у меня ушло всего несколько часов. А вашим методом на это же уйдут многие сотни часов.
Вот монитор РК, куда я добавил ещё две новые директивы, но всё-равно осталось ещё 153 свободные ячейки. Причём адреса всех внутренних точек куда лезут игры написанные "вредителями" сохранены (также сохранены те внутренние точки, что добавил эмулятор EMU от
b2m). Макро-ассемблер М80 резко увеличивает эффективность работы, а кто пользуется другими инструментами, тот просто не ценит своё время.
Есть программы конверторы мнемоник (во вложении), в том числе для конверсии из мнемоник Z80 в мнемоники КР580 (я ей успешно пользовался в прошлом году для Паскаля МТ+, - т.к в ассемблерных вставках он понимает только мнемоники КР580, но зато я их не понимаю). Это даже не лучший исходник (какой подвернулся, у меня их десятки версий, давно в них запутался). Для последующей модификации этот исходник ценен тем, что подписаны длины подпрограмм, т.е маленьких независимых фрагментов кода. Перемещая эти кусочки кода при всех модификациях мы должны добиться, чтобы адреса внутренних точек не сдвигались.
Т.к в этом форуме под спойлером тэг {code} не работает, а без него получается каша (форматирование текста гибнет), исходник по многочисленным просьбам трудящихся отсюда убран, его
можно просмотреть здесь.
Процедуры оконной коррекции это всего несколько десятков байтов. Это легко встроить. Хотя я и не понимаю, что это даёт. Какая от этого польза? Не имея альтернативного фонта дающего рамки и окна в инверсии это вообще бесполезно. К тому же, т.к это небольшой объём кода, то вывод в окно легко встраивается в любую программу. Потому нет смысла менять ПЗУ.
При этом остаются физические HPOS и VPOS (в 7602), есть логические координаты курсора в окне и есть параметры окна - обычно позиция левого верхнего угла окна и два байта задающие в символах размеры окна по вертикали и горизонтали (или экр.координаты двух углов окна). Тогда весь вывод попадает только в окно. Искейп-код для позиционирования, что попадает мимо окна игнорируется.
Вот смотрите, как просто реализуется оконность в программах на Паскале:
оконность в паскалеCode: Select all
procedure set_full;
begin
WX1:=1; WX2:=SCR_HSZ; WY1:=1; WY2:=SCR_VSZ;
end;
procedure goto_xy(x,y: Integer); { Здесь позиции x,y задаются от начала окна }
begin
if WX1+x <= WX2 then cur_x:=x
else cur_x:=WX2-WX1+1;
if WY1+y <= WY2 then cur_y:=y
else cur_y:=WY2-WY1+1;
gotoxy(WX1+cur_x-1,WY1+cur_y-1);
{
cout(#$1B); cout('Y');
cout(chr(30+WY1+cur_y));
cout(chr(30+WX1+cur_x));
}
end;
procedure cout(ch: char);
begin
{ if cur_x<SCR_HSZ then cur_x:=cur_x+1; }
write(ch);
end;
procedure mssgln(tx: txt_string);
begin
mssg(tx);
cur_x:=1;
if WY1+cur_y > WY2 then
begin
cur_y:=WY2-WY1+1;
cur_x:=WX2-WX1+1;
end
else
begin
cur_y:=cur_y+1;
end;
goto_xy(cur_x,cur_y);
end;
procedure mssg(tx: txt_string);
var
i: Integer;
begin
for i:=1 to length(tx) do cout(tx[i]);
end;
procedure cls_window;
var x,y: Integer;
begin
for x:=WX1 to WX2 do
begin
for y:=WY1 to WY2 do
begin
gotoxy(x,y);
if not ((x=SCR_HSZ) and (y=SCR_VSZ)) then {чтобы не случилось ролика}
cout(#32);
end;
end;
end;
procedure cls;
begin
if ((WX1=1) and (WY1=1) and (WX2>=SCR_HSZ) and (WY2>=SCR_VSZ))
then mssg(chr($1b+$45)) else cls_window;
end;
procedure w_ramka;
var i,x,y: Integer;
Left_Up, Left_Dn, Right_Up, Right_Dn, Vert , Horiz: char;
begin
Left_Up:= char($A5);
Left_Dn:= char($AB);
Right_Up:= char($A8);
Right_Dn:= char($AE);
Vert:= char($A1);
Horiz:= char($A0);
gotoxy(WX2,WY2); cout(#$99);
if (WX2=SCR_HSZ) and (WY2=SCR_VSZ) then
begin
gotoxy(1,1); insline;
end;
for x:=WX1+1 to WX2-1 do
begin
gotoxy(x,WY1); cout(Horiz); {верхняя горизонталь }
end;
gotoxy(WX2,WY1); cout(Right_Up);
for y:=WY1+1 to WY2-1 do
begin
gotoxy(WX2,y); cout(Vert); {правая вертикаль}
end;
gotoxy(WX2,WY2); cout(Right_Dn); {прав.нижний угол}
for i:=1 to WX2-WX1-1 do
begin
x:=WX2-i;
gotoxy(x,WY2);
cout(Horiz); {нижняя горизонталь}
end;
gotoxy(WX1,WY2); cout(Left_Dn);
for i:=1 to WY2-WY1-1 do
begin
y:=WY2-i; gotoxy(WX1,y); cout(Vert);
end;
gotoxy(WX1,WY1); cout(Left_Up);
end;
procedure Mwindow(x1,y1,x2,y2: Integer; flg: byte);
begin
if (x1>=x2-1) or (y1>=y2-1) or (y2>SCR_VSZ) or (x2>SCR_HSZ)
then avral('Window range out');
Inverse;
WX1:=x1; WX2:=x2; WY1:=y1; WY2:=y2; cls;
if (flg<>0) then
begin
w_ramka; WX1:=WX1+1; WX2:=WX2-1; WY1:=WY1+1; WY2:=WY2-1;
end;
cur_x:=1; cur_y:=1;
end;
procedure err_mssg(line: txt_string);
var
x1,y1: Integer;
begin
tmpx:=cur_x; tmpy:=cur_y;
Inverse;
i:=length(line)+10; if i mod 2 <>0 then i:=i+1;
x1:=(SCR_HSZ-i) div 2;
y1:=(SCR_VSZ - 5) div 2;
Mwindow(x1,y1,x1+i,y1+4,0); w_ramka;
tmplin:=' Fatal Error '; i:=(WX2-WX1+2-length(tmplin)) div 2;
goto_xy(i,1); mssg(tmplin);
WX1:=WX1+1; WX2:=WX2-1; WY1:=WY1+1; WY2:=WY2-1;
goto_xy(5,2); mssg(line); gotoxy(1,1); wait;
cur_x:=tmpx; cur_y:=tmpy; scr_out; Normal; scr_scrabled:=True;
end;
Вышеприведённый кусочек при трансляции увеличивает объём программы на ЯВУ всего на несколько сотен байт. В нём видно как я в середине 90-тых реализовал оконность в системе, в которой консольный вывод её не поддерживает. Для этого вводятся 4 параметра задающие окно координатами верхнего левого угла и правого нижнего угла окна (WX1,WY1 и WX2,WY2). После чего меняя эти 4 переменные мы можем делать вывод в окно, очищать его стандартным кодом очистки, выводить в окно рамку с титром окна и т.п.
Как пример использования посмотрите на процедуру вывода в окне сообщения об ошибке (err_mssg). Процедуре передаётся указатель на текст сообщения об ошибке. Процедура определяет его длину, открывает инверсное окно такого размера, чтобы это сообщение в него уместилось, открывает окно, чистит его, выводит рамку с титром и в окне выводит сообщение. Здесь по закрытию окно не восстанавливается из буфера сохранения (т.к в CP/M нет средств читать символы из экрана, да и негде окно сохранять), просто ставится флаг, что экран испорчен (окном), что значит, что после закрытия окна нужно восстанавливать исходный экран.
You do not have the required permissions to view the files attached to this post.