RUЭВМ
Вы хотите отреагировать на этот пост ? Создайте аккаунт всего в несколько кликов или войдите на форум.
Ноябрь 2020
ПнВтСрЧтПтСбВс
      1
2345678
9101112131415
16171819202122
23242526272829
30      

Календарь Календарь

Последние темы
» ПЭВМ "Ириша". Модуль контроллера графического дисплея (МКГД).
автор barsik Сегодня в 09:13

» Тупые вопросы по рк86
автор barsik Сегодня в 09:05

» Изучение Си, в применении к К210. Отличия, особенности и т. д...
автор Viktor2312 Сегодня в 05:39

» Программирование для РК86
автор barsik Вчера в 22:12

» Свёрточная нейронная сеть (CNN).
автор ведущий_специалист Вчера в 19:19

» Флейм только по теме "Радио-86РК".
автор ведущий_специалист Вчера в 18:09

» Разработка "Радио - РК2019М".
автор ведущий_специалист Вчера в 17:36

» Документация (3Com).
автор Viktor2312 Вчера в 15:35

» Улучшение видео возможностей РК86
автор barsik Сб Ноя 28 2020, 23:11

» ПЗУ F800 для РК86
автор barsik Пт Ноя 27 2020, 12:38

» "Ваш радиоприёмник". Р. Сворень 1963г.
автор Viktor2312 Пт Ноя 27 2020, 12:37

» Игровая консоль радиолюбителя по схеме РК86
автор barsik Ср Ноя 25 2020, 21:08

» Разное
автор Viktor2312 Ср Ноя 25 2020, 19:48

» Общие вопросы по ПЭВМ Ириша
автор Viktor2312 Ср Ноя 25 2020, 19:42

» Обсуждение желаемых новодельных плат расширения и мелких усовершенствований базовых плат
автор Viktor2312 Ср Ноя 25 2020, 00:18

» Разговоры не пойми о чём...
автор ведущий_специалист Вт Ноя 24 2020, 17:52

» Флейм касающийся ПЭВМ "Ириша".
автор Viktor2312 Пт Ноя 20 2020, 14:31

» Куплю телеграфный аппарат РТА-80.
автор Savoj Вс Ноя 15 2020, 19:55

» Разработка модуля МВК-МП-ВМ80 ver_0.01.
автор Viktor2312 Вс Ноя 15 2020, 02:43

» Сопроцессор в РК86
автор barsik Сб Ноя 14 2020, 18:20

» Усилитель класса D на TL494
автор freddy Чт Ноя 12 2020, 16:16

» К210. Общая тема по GPIO. Практика.
автор Viktor2312 Ср Ноя 11 2020, 21:55

» Бейсик интерпретатор ИРИШИ
автор barsik Ср Ноя 11 2020, 00:45

» Реанимирую симфонию
автор Viktor2312 Ср Ноя 11 2020, 00:23

» Клавиатура ИРИШИ
автор barsik Вт Ноя 10 2020, 16:29

Самые активные пользователи за месяц
Viktor2312
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
barsik
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
ведущий_специалист
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
RN1TZ
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
freddy
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
vital72
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
Microsha
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 
Savoj
BDS-C лучший компилятор для разработки игр РК86 Vote_l10BDS-C лучший компилятор для разработки игр РК86 Voting10BDS-C лучший компилятор для разработки игр РК86 Vote_r10 

Поиск
 
 

Результаты :
 


Rechercher Расширенный поиск


BDS-C лучший компилятор для разработки игр РК86

Перейти вниз

BDS-C лучший компилятор для разработки игр РК86 Empty BDS-C лучший компилятор для разработки игр РК86

Сообщение  barsik в Пт Окт 30 2020, 13:32

1
У меня возникло (ещё не подтверждённое фактами) подозрение, что BDS-C - это лучший компилятор ЯВУ для штамповки игр для РК86. Скажем спасибо за это Леору Золману (фото).

Лет 25 назад я уже немного программировал на Си для 8-ми разрядки (и как раз на BDS-C). Си ведь очень прост, чего не скажешь про C++. По счастью компилятора C++ для 8-ми разрядок нет (компилятор C++ невозможен на 8-ми разрядке ввиду малости адресного пространства, а выходной код из под C++ не уместился бы в ОЗУ).

Для хорошего инструмента плотность выходного кода конечно важна, но важнее скорость разработки (небольшую нехватку скорости можно выровнять заплатками на ассемблере). Во многом лучший инструмент для изготовления игр 8-ми разрядок это Турбо-Паскаль. Т.к это именно Паскаль, а не Си, то новичками он осваивается быстрее и даёт код ничуть не хуже, чем Си для Z80.

Никто не станет оспаривать, что для 8-ми разрядок, где многое делается по железу, как раз Си подходит лучше, чем Паскаль. С другой стороны, как учебный язык Паскаль лучше, т.к он строже, что сразу же дисциплинирует программиста не приучая к разной "химии", что легко делается на Си (по крайней мере в Си для 8-ми разрядок). Потому молодёжь как раз знает TP, а не СИ, т.к его преподают в местных школах. В изучении для новичка TP проще, чем Си (особенно, если он имел ранее дело с бейсиком).

Но увы, применительно к РК86 Турбо-Паскаль отпадает, т.к требует Z80, а в РК86, как назло, применён какой-то левый процессор. Это обстоятельство исключает TP из претендентов на инструмент для базового РК. Настоящие любители ретро программирования меняют неудачный процессор в РК86 на Z80 и даже не столько из-за его системы команд, сколько из-за большего быстродействия. Это бы не пришлось делать, если бы 4.0 или хотя-бы 3.1 мегагерцовые CPU 8080 были доступны.

Для КР580 есть ещё Aztec C, который тоже вполне профессиональный инструмент. Но всем кто сравнивал, Aztec нравится меньше, почему-то он менее популярен. Т.о BDC-C это и есть лучший инструмент программиста для РК86. Конечно для КР580 есть ещё и Паскаль МТ+, но он по моим данным даёт код чуть менее плотный, чем BDS-С, и сделан в стандартах 70-х годов, так что для наших целей он хуже. Впрочем, каким инструментом из подходящих для решения конкретной задачи лучше умеешь пользоваться, - тот для тебя и лучший.

А вот компиляторов Си для Z80 довольно много (можно посмотреть здесь). Есть и кросс компиляторы для PC, есть и для CP/M. Увы, для РК годятся только самые древние компиляторы предназначенные ещё для процессора 8080 (например).

Т.к на форуме много стало разговоров о Си, мне тоже захотелось оценить эффективность Си для разработки игр для РК86. Т.е что-то вспомнить про Си, а что забыл заново изучить. А то стало неудобно - даже оценить чужую программку на Си и чужой компилятор потестировать не могу.

Про сам BDS-C писать нечего, т.к имеющейся документации хватает. Так что возможно лишь напишу здесь о ходе моего освоения BDS, о том, какие учебные примеры пришлось писать, чтобы вспомнить. А затем возможно поделюсь опытом в разработке на этом Си простейшей игры уже конкретно для РК86.

К сожалению, мои исходники программ написанных на BDS-C в 90-тые (а их было и немного - текстов редактор и нортон) сейчас недоступны (т.к после множества крахов винтов они остались лишь на резервных дискетах в формате ОРИОНА, формат полу-HD нестандартный, читалками дискет не считать, теледиск тоже такой формат не берёт).

И всё же один пример программы на BDS-C на винте сохранился. Это исходник нортона для ОРИОНА. К сожалению, это лишь стартовая версия совсем без вкраплений ассемблера и вероятно далеко не полный функционал (размер кода всего 17 кб, а окончательная версия превысила 32 кб, причём из которых ~треть С-кода была переписана на ассемблере). В этой версии ещё и окон нет, ввод пользователя делается не в окне, а в нижней служебной строке (называемой bottom), кстати, в нижней строке даже нет подсказок и Бог знает чего ещё. Если найду энтузиазм починить ОРИОН и главное, КНГМД на ВГ93 (который сдох более 15 лет назад), то скачаю с дискет архивы своих программ для ОРИОНА на Турбо-Паскале и Си (но этим займусь вряд-ли вскоре, т.к это электротрах на много дней).

Это двухпанельный нортон, похоже он делался CP/M-корректным (т.е в железо машины не лезет). Еще не особо вникал, - он состоит всего из нескольких модулей. Основной модуль и набор ASM-подпрограмм (там интерфейс с ROM-BIOS и ассемблерная процедура рисования двух панелей, т.к их рисование кодом на Си в несколько раз тормознее). А при отладке при необходимости подключается модуль OTLAD.C, что позволяет просмотреть дамп.

Наличие исходника реальной программы очень кстати. Наличие всего единственного примера мне кардинально упрощает изучение BDS-C, это с'экономит десятки часов чтения документации. Лишь чуть пролистав исходник, я понял как в программы на BDS-C включаются фрагменты на ассемблере, а из SUB-файлов узнал команды трансляции. К сожалению, обнаружил, что BDS-C не только генерит код для КР580, но и исходники на ассемблере для него надо писать в мало кому понятных мнемониках ассемблера КР580, ведь большинству людей привычна более удобная мнемоника Z80.

Пока достал своего пожелтевшего "Кернигана и Ритчи" первое издание (1984), бумага некачественная, он пожелтел уже в начале 90-тых. Есть и второе издание (1992) (оно уже на хорошей глянцевой бумаге), но второе издание не для ретро CP/M-версий компилятора, а для компиляторов на IBM PC, т.к там описывается уже новый стандарт. А также достал распечатку документации к BDS-C. Но теперь, благодаря наличию примера программы на BDS-C, особо штудировать доки вряд-ли понадобится. Чтобы вспомнить что-то попробую разобраться в своей же программе 25-ти летней давности. Если кому интересно, вот основной модуль этого нортона.

основная программа:

#include <BDSCIO.H>

#define NOASM 0
#define OTLAD 0
#define F81B_DIRECT 1

#include <STCONST.H>

char posstr[5];
char fcb1[36], joker[16];
char *pstr, *fptr;
char last;                      /* для type */
int cpan;                       /* 0/1 текущая панель */
int pdone1, pdone2;             /* флаг что панель выведена */
int getfl1, getfl2;             /* флаг что кат. считан */
int fflag1, fflag2, fflag;      /* фл.первого обращения к панели */
int disk1, disk2, disk;
int user1, user2, user, in_user;
int files1, files2, files;
int ofs1, ofs2, offs;
int pos1, pos2, pos;
int pofs;
unsigned mszlow,mszhig;

char txt[48];
char fname[30];

int fd1,fd2;
int bufsects;                   /* сколько секторов в буфере */
unsigned bufsize;               /* размер буфера */
unsigned corebuf;               /* адрес начала буфера */
char sourname[30];
char destname[30];
char verify, *vbuf;

struct NREC {
 char NAME[8];
 char TYP[3];
 char MARK[1];
 char noneed[2];
 char RECS[1];
};

struct NREC kat1[MAXFILES];
struct NREC kat2[MAXFILES];

main()
{

char ch, *p;
int i, tmpcpan;
char ptitr[12];

fflag1=fflag2=0; disk1=1; disk2=2;
user1=in_user=bdos(fuser,0xFF); user2=0;
bios(4,27); bios(4,0x30); bios(4,27); bios(4,0x3a);

verify=1;

if (verify) vbuf = sbrk(SECSIZ);
    corebuf = sbrk(SECSIZ); /* адр.начала буфера */

/* получить буфер максимального размера */
for (bufsize = SECSIZ; sbrk(SECSIZ) != ERROR; bufsize += SECSIZ)
  ;
  bufsects = bufsize / SECSIZ;

clrscr();

pstr= &posstr;
*pstr =0x1B; *(pstr+1)=0x59; *(pstr+4)=0;

RESTAR:

pdone1=pdone2=0;
getfl1=getfl2=0;
dskreset();

RENEW:

fptr=fcb1;
if (!getfl1) if (!getkat(0,disk1)) error("Bad 1 FCB init");
if (!getfl2) if (!getkat(1,disk2)) error("Bad 2 FCB init");

LOO1:
#if    NOASM
rames();
#else
panel(0);
gotoxy(0,lp_ofs+7); printf(" %c:\\User %d ",'@'+disk1,user1);
panel(1);
gotoxy(0,rp_ofs+7); printf(" %c:\\User %d ",'@'+disk2,user2);
#endif

PLOOP:
setprm(cpan); tmpcpan=cpan;
if (pdone1==0)  { setprm(0); catout(); }
if (pdone2==0)  { setprm(1); catout(); }

setprm(tmpcpan); restbtm();
ch=select();
getprm();
switch(ch)
{
case 1: if (cpan) getfl2=pdone2=0; else getfl1=pdone1=0;
        goto RENEW;
case 2: if (cpan) getfl1=pdone1=0; else getfl2=pdone2=0;
        goto RENEW;
case 3: if (cpan==0) cpan=!cpan; else cpan=0; goto PLOOP;
case 4: if (cpan) getfl1=pdone1=pdone2=0;
           else getfl2=pdone2=pdone1=0;
        goto RENEW;
case 5: goto RESTAR;
case 6: pdone1=pdone2=0; goto LOO1;
case 27: goto M1;
}

M1:
gocpm();

}

/* -------------------------- */

setprm(panel)
int panel;
{ cpan=panel;
if (cpan==0)
  {
   disk=disk1; user=user1; pos=pos1; pofs=lp_ofs; fflag=fflag1;
   files=files1;
   if (!fflag) { offs=0; fflag1=-1; } else offs=ofs1;
  }
else
  {
   disk=disk2; user=user2; pos=pos2; pofs=rp_ofs; fflag=fflag2;
   files=files2;
   if (!fflag) { offs=0; fflag=-1; } else offs=ofs2;
  }
}

getprm()
{
if (cpan==0)
  {
   disk1=disk; user1=user; pos1=pos; fflag1=fflag; ofs1=offs;
  }
else
  {
   disk2=disk; user2=user; pos2=pos; fflag2=fflag; ofs2=offs;
  }
}

int getkat(np,nd) /* np=0/1   nd=1/2/3 */
int np,nd;
{ int usr,i;
char *p;

if (np==0) { usr=user1; files1=0; getfl1=pdone1=0; }
  else { usr=user2; files2=0; getfl2=pdone2=0; }
clrcat(np);

p=podgot(nd,usr);
/* p=&fcb1; */
if (setfcb(p,joker)!=0) return(0);

i=bdos(ffirst,fcb1);
if (i==0xFF) return(1);  else putname(i,np);
while ( (i=bdos(fnext,fcb1)) != 0xFF ) putname(i,np);
if (np==0) getfl1=1; else getfl2=1;
return(1);
}

char *podgot(disk,usr)   /* подготовить FCB для first/next */
int disk,usr;
{
switch(disk)
 {
 case 1: strcpy(&joker,"A"); break;
 case 2: strcpy(&joker,"B"); break;
 default: error("Wrong drive N");
 }
strcpy(&joker[1],":????????.???");

dma80(); bdos(fuser,usr);
fptr = &fcb1; fillmem(fptr,36,0);
return(&fcb1);
}

gotoxy(x, y)
char x,y;
{ char *pstr;
pstr = posstr;
*(pstr+2) = 32 + x;
*(pstr+3) = 32 + y;

#if     NOASM
  while (x = *pstr++) bios(4,x);
#else
  mssg(pstr);
#endif

}

inverse()
{ bios(4,0x1B); bios(4,0x36); }

normal()
{ bios(4,0x1B); bios(4,0x37); }

copymem(d,s,n)
char *d, *s;
int n;
{
 while (n!=0)
   { (*d++) = (*s++); n--; }
}

clrcat(n)
{
int i;
char *p;
if (n==0)
  { files1=0; for (i=0; i < MAXFILES; i++) { p=&kat1[i]; *p=0; }
  }
else
  { files2=0; for (i=0; i < MAXFILES; i++) { p=&kat2[i]; *p=0; }
  }
}

int putname(of,np)
int of,np;
{ char *d, *s;
if ((np==0) && (files1>=MAXFILES-1)) return(0);
if ((np) && (files2>=MAXFILES-1)) return(0);
s=0x80+(32*of)+1;
if (np==0) d=&kat1[files1]; else d=&kat2[files2];
copymem(d,s,15);
if (np==0) d=&kat1[files1++].MARK; else d=&kat2[files2++].MARK;
*d=0; return(1);
}

catout()
{
int n;
n=0;

if (cpan==0) pdone1=1; else pdone2=1;
if (files==0) { for (n=0; n<VSIZE-3; n++) blankout(n); return; }
for (n=0; n<VSIZE-3; n++)
  if (n+offs < files) filout(n,n+offs); else blankout(n);
}

filout(lin,n)
int n,lin;
{
int i;
unsigned len;
char *p;

gotoxy(1+lin,1+pofs);
if (cpan) p=&kat2[n].MARK; else p=&kat1[n].MARK;
if (*p) bios(4,'*'); else spc();
if (cpan) p=&kat2[n]; else p=&kat1[n];
if (*p==0) { blankout(lin); return; }
prfname(p,0);
if (cpan) p=&kat2[n].RECS; else p=&kat1[n].RECS;
len=(*p)*128; printf(" |%6d ",len);
}

balkout(lin,n)
int n,lin;
{
int i;
unsigned len;
char *p;

gotoxy(1+lin,1+pofs); inverse();
if (cpan) p=&kat2[n].MARK; else p=&kat1[n].MARK;
if (*p) bios(4,'*'); else spc();
if (cpan) p=&kat2[n]; else p=&kat1[n];
if (*p==0) { normal(); blankout(lin); return; }
prfname(p,1);
if (cpan) p=&kat2[n].RECS; else p=&kat1[n].RECS;
len=(*p)*128; printf(" |%6d ",len);
normal();
}

prfname(uk,balkflg)
char *uk;
int balkflg;
{ int i;
for (i=0; i<8; i++) prnmal(*uk++,balkflg);
bios(4,'.');
for (i=0; i<3; i++) prnmal(*uk++,balkflg);
}

prnmal(ch,prm)
char ch,prm;
{
 if ((prm) || (ch>0x80)) inverse(); else normal();
 ch &= 0x7F;
 if ((ch<='Z') && (ch>'@')) ch |= 0x20;
 if (ch<32) bios(4,'?'); else bios(4,ch);
 if (prm==0) normal();
}

blankout(n)
int n;
{
gotoxy(1+n,pofs+1);
nspc(14); bios(4,'|'); nspc(6);
}

cr()
{ bios(4,13); bios(4,10); }

spc()
{ bios(4,' '); }

nspc(n)
{
 while (n>0) { bios(4,' '); n--; }
}

select()
{
char *p, *d, ch;
int i;

if (fflag==0) { pos=0; fflag=!0; }
view();

while (1)
{
  if (kbhit()) getchar();
if (files==0) { pos=0; offs=0; inverse(); gotoxy(1,pofs+1);
printf(" No files     |       "); normal(); goto MMM; }
if (pos>VSIZE-4) pos=VSIZE-4;
if (pos+offs >= files)
   if (files>VSIZE-3) offs=files-(VSIZE-3);
    else { offs=0; pos=files-1; }
balkout(pos,pos+offs);
MMM:
ch=getkey(); if (ch!=32) ch &= 0x5F;
bios(4,7);
filout(pos,pos+offs);
switch(ch)
 {
 case K_UP: if (pos>0) pos--;
    else if (offs>0) { offs--; catout(); } else beep(); break;
 case 32:
      if (cpan) p=&kat2[pos+offs].MARK; else p=&kat1[pos+offs].MARK;
      if (*p==0) *p=0xff; else *p=0; filout(pos,pos+offs);
      view(); ch=K_DN;
 case K_DN: if ((pos<VSIZE-4) && (pos+offs < files-1)) pos++;
              else if (offs+VSIZE-3 < files) { offs++; catout(); }
                      else beep();
          break;
 case K_LF: if (pos==0) { offs=0; pos=0; catout(); }
               else pos=0; break;
 case K_RT: if (files >VSIZE-3)
              {
               if (VSIZE-3+offs < files)
                 if (pos!=VSIZE-4) pos=VSIZE-4;
                   else if (offs+VSIZE-3+VSIZE-3 < files)
                           { offs += VSIZE-3; catout(); }
                        else { offs=files-(VSIZE-3);
                               pos=VSIZE-4; catout(); }
               }
               else pos=files-1; break;
 case K_WK: return(0);
 case 10: return(0);
 case K_TB: return(3);
 case 'E':  i=getmarked(0);
         if (i) if (grera()==27) break; else return(1);

         bottom();
         if (getname(pos+offs))    /* если ф.R/O */
          { printf("File %s is R/O. Erase (Y/N) ? ",sourname+4);
            ch=getyes(); restbtm(); if (ch!='Y') break;

            strcpy(&joker,&sourname[2]);
            bdos(fuser,user);
            p = &fcb1; fillmem(p,36,0);
            if (setfcb(p,joker)!=0)
            error("setfcb");

            fcb1[9] &= 0x7F;
            bdos(fsetatr,fcb1);
            goto MTK_E1;
          }
         printf("Erase %s (Y/N) ? ",sourname+4);
         ch=getyes(); restbtm();
         if (ch!='Y') break;
MTK_E1:   erase(sourname); return(1);

 case 'D': case 'd': ch=askdisk(); if (ch==27) break;
           disk=ch; dskreset(); return(1);
 case 'U': case 'u': if ((i=askuser())==27) break;
           user=i; return(1);
 case 1: return(5);
 case 27: return(27);
 case 'C':

/* Проверка что не копирование "в себя" */

 if (cpan==0) { if ((disk==disk2) && (user=user2)) break; }
   else if ((disk==disk1) && (user==user1)) break;

   i=getmarked(0);
 if (i != 0) { grcopy(); restbtm(); return(4); }

 getname(offs+pos); formtarget(); copying(); restbtm();
 return(2);

case 'T': getname(offs+pos); typing(); clrscr(); return(6);
default: beep(); beep(); /* if (pos<VSIZE-4) pos++; */
 }
}
}

view()
{ int i;
 gotoxy(2,50); printf("Files:     ");
 gotoxy(2,50+8); printf("%d",files);
 i=cntmrk();
 gotoxy(3,50); printf("Marked:   ");
 gotoxy(3,50+8); printf("%d",i);
 gotoxy(4,50); printf("Size:         ");
 gotoxy(4,50+8);
 if (mszhig) printf("%d",mszhig);
 if (mszlow) printf("%03d",mszlow); else bios(4,'0');
}

int getname(n)  /* возвр. 0 если файл R/W */
int n;
{ char *p, *d, ch;

 if (cpan==0) p=&kat1[n]; else p=&kat2[n];
   d=&sourname[0];
   strcpy(d,"0/A:\0x00"); *d=user+'0'; *(d+2)='@'+disk;
   d=&sourname[4];
   d=copsym(d,p,8); *(d++) = '.'; copsym(d,p+8,3);
/*    if (sourname[13] & 0x80) return(1); else return(0);
       0/A:12345678.1
       0123456789012345 */

 if (cpan==0) p=&kat1[n]; else p=&kat2[n];
 ch = (*(p+8)) & 0x80; if (ch==0) return(0); else return(1);
}

formtarget()
{
 strcpy(destname,sourname);
 if (cpan==0) { destname[0]='0'+user2; destname[2]='@'+disk2; }
    else { destname[0]='0'+user1; destname[2]='@'+disk1; }
}

int grcopy()
{ int i;
 char ch;
 if (getmarked(0)==0) return(0);
 bottom();
 if (cpan) ch='@'+disk1; else ch='@'+disk2;
 printf("Copy %d files to %c: (Y/N) ? ",cntmrk(),ch);
 if (getyes() != 'Y') return(0);
 while (1)
  { if (getmarked(1)==0) break;
    formtarget(); i=copying(); restbtm();
    if (i==27) return(27);
/*     unmark(); */
  }
  return(0);
}

int grera()
{ int i;
 char ch;
 if ((i=cntmrk())==0) return(0);
 bottom(); printf("Erase %d files (Y/N) ? ",i);
 ch=getyes(); restbtm();
 if (ch != 'Y') return(27);
 while (1)
    { if (getmarked(1)==0) break; erase(sourname); }
 return(0);
}

unsigned getmarked(sbr_flg)
int sbr_flg;
{
 char *p1, *p2;
 unsigned i;
 for (i=0; i<files; i++)
   {
     if (cpan) { p1=&kat2[i]; p2=&kat2[i].MARK; }
          else { p1=&kat1[i]; p2=&kat1[i].MARK; }

     if (*p1==0) return(0);
     getname(i);
     if (*p2) { if (sbr_flg) *p2=0; return(1); }
   }
 return(0);
}

int cntmrk()
{
 char *p1, *p2, *p3;
 int i,n;
 unsigned sss;
 mszlow=0; mszhig=0;
 for (n=0,i=0; i<files; i++)
   {
     if (cpan) { p1=&kat2[i]; p2=&kat2[i].MARK; p3=&kat2[i].RECS; }
          else { p1=&kat1[i]; p2=&kat1[i].MARK; p3=&kat1[i].RECS; }

     if (*p1==0) break;
     if (*p2)
       {
         n++;
         sss=(*p3)*128; mszhig += sss/1000; mszlow += sss % 1000;
         if (mszlow >= 1000) { mszlow -= 1000; mszhig++; }
       }
   }
 return(n);
}

erase(name)
char *name;
{ if (unlink(name)) error("Bad erase");
   if ((disk1==disk2) && (user1==user2))
          getfl1=getfl2=pdone1=pdone2=0;
  return(0);
}

int copying()
{
int i,j,k;
char ch;
char *dest, *sour;

 dest=&destname; sour=&sourname;
 bottom(); printf("Copying file %s",sour+4);
AAA:
if ( (fd2=open(dest,0) ) != ERROR)
   {
     fabort(fd2);
     bottom(); printf("File %s exists ! Overwrite (Y/N) ? ",dest+4);
     ch = getyes(); restbtm();
     if ((ch==27) || (ch==3)) return(27);
     if (ch=='Y')
       {
         if (unlink(dest)== ERROR)
           { sprintf(txt,"Can't erase %s",dest);
             error(txt); }
         goto AAA;
       }
     return(0);
   }

 if ((fd1=open(sour,0)) == ERROR)
         { sprintf(txt,"Can't open %s",sour);
         error(txt); }
 if ((fd2=creat(dest)) == ERROR)
         { sprintf(txt,"Can't create %s",dest);
           error(txt); }

     /* May be out of directory space */

while (1)
 {
     if (kbhit()) getchar();
        if (!(i = read(fd1,corebuf,bufsects))) break;
        if (i == ERROR)
         {
          sprintf(txt,"Read error: tell(fd1) = %d, \"%s\"\n",
                                    tell(fd1), errmsg(errno()));
          error(txt);
         }

     if (kbhit()) getchar();
     if (write(fd2,corebuf,i) != i)
       {  sprintf(txt,"\nWrite error: %s\n",errmsg(errno()));
          error(txt);
       }

  if (verify)
    {
     seek(fd2, -i, 1);    /* отпозиционировать назад */
     for (j=0, k=corebuf; j<i; j++, k += SECSIZ)
       {
        if (read(fd2, vbuf, 1) != 1)
         { sprintf(txt,"\nVerify error on %s\n", destname);
           error(txt); }
        if (memcmp(vbuf, k, SECSIZ)) continue;
           else { sprintf(txt,"\nVerify error on %s\n", destname);
                  error(txt); }
       }
    }

 }  /* конец блока while(1) */

 if (close(fd2) == ERROR)
         { sprintf(txt,"Can't close file %s",dest);
           error(txt); }

 fabort(fd1); return(0);
}

typing()
{
int i,j,k,first;
char ch, *p;

TOTOP:
first=TRUE;
 p=&sourname;
 if ( (fd1=open(p,0) ) == ERROR)
       { bottom(); printf("Can't open %s",p);
         getkey(); restbtm(); return;
       }

fillmem(corebuf,bufsize,0x1A);
while (1)
 {
        if (!(i = read(fd1,corebuf,bufsects))) break;
        if (i == ERROR)
         {
           sprintf(txt,"Read error: tell(fd1) = %d, %s\n",
                                    tell(fd1), errmsg(errno()) );
           error(txt);
         }

     if (first) clrscr(); first=FALSE;
     if (isnotxt()) j=dumpbuf(corebuf,i); else j=print(corebuf,i);
     if (j==1) break;
     if (j==2) { fabort(fd1); goto TOTOP; }
 }
 fabort(fd1);
}


print(txbuf,sec)
char *txbuf;
int sec;
{ int i,j,py;
 char ch, ch2;
 unsigned u;

 py=0; u = (128 * sec);

 while (1)
 {
   if (*txbuf == 0x1A) { getchar(); return(1); }
   if (u==1) return(0);
/*    if (last!=0) { ch=last; u++; txbuf--; } else */
     ch = *txbuf & 0x7F;

/*
   if (ch==13)
    { cr(); py=0;
PR1:   txbuf++; u--; ch=last=*txbuf;
      if (u==1) return(0);
      if (ch==10) goto PR1;
      if (ch==0x1A) getchar(); return(1);
    }
   if (ch==10) goto PR2;
*/
   if (ch==13) if (kbhit())
                 { if ((ch2=getchar())==27) return(1);
                   free(); ch2=getkey();
                   if (ch2==27) return(1);
                   if ((ch2==K_UP) || (ch2 & 0x5F == 'B')) return(2);
                 }
   if (ch==13)
      { if (py<63) for (i=py; i<63; i++) bios(4,32);
      }
   if ((ch==10) || (ch==13)) py=0;
   if (ch==9)
     {
       i=py % 8;  if (i==0) i=8; else i= 8-i;

       for (j=0; j<i; j++)
          { py++; spc(); if (py>=63) break; }
       goto PR2;
     }
   if (py>=63) goto PR2;
  if ((ch!=13) && (ch!=10)) if (ch<32) ch=32;
   bios(4,ch); py++;
PR2: txbuf++; last = *txbuf;
 }
}

dumpbuf(dbuf,sec)
char *dbuf;
int sec;
{ int i,u,endflg;
 char ch2;

 if (kbhit()) { ch2=getchar(); if (ch2>=32) bios(4,8); }
 if (sec<bufsects) endflg=TRUE; else endflg=FALSE;
 u=0;
 while (sec)
  {
/*
   if (isfree()==FALSE)
                 { if ((ch2=getkey())==27) return(1);
                   free(); ch2=getkey();
                   if (ch2==27) return(1);
                   if ((ch2==K_UP) || (ch2 & 0x5F == 'B')) return(2);
                 }
*/
    if ( i=dump80(dbuf,u) ) return(i);
    dbuf += 128; u += 128; sec--;
  }
 if (endflg)
     { ch2=getyes(); if ((ch2==K_UP) || (ch2 =='B')) return(2); }
 return(0);
}

int isnotxt()
{ char *p;
 if (cpan) p=&kat2[pos+offs].TYP; else p=&kat1[pos+offs].TYP;
 if ( (memcmp(p,"COM",3)) || (memcmp(p,"DAT",3)) ||
      (memcmp(p,"SYS",3)) || (memcmp(p,"OVR",3)) ||
      (memcmp(p,"CRL",3)) || (memcmp(p,"REL",3)) ||
      (memcmp(p,"HEX",3)) || (memcmp(p,"O  ",3)) ||
      (memcmp(p,"OVL",3)) || (memcmp(p,"ORD",3)) ) return(TRUE);
return(FALSE);
}

error(txt)
char *txt;
{ gotoxy(VSIZE-1,0); printf("\nError '%s'",txt); gocpm(); }

char getkey()
{
#if     F81B_DIRECT

char ch;  while ((ch=f81b())==0xFF) ;
while (f81b() != 0xff) ;
return(ch);
#else
 while (bios(2)==0) ;
 return(bios(3));
#endif
}

int isfree()
{
#if     F81B_DIRECT
if (f81b() == 0xff) return(TRUE); else return(FALSE);
#else
 if (bios(2)==0) return(TRUE); else
   { getchar(); return(FALSE); }
#endif
}


free()
{
#if     F81B_DIRECT
while (f81b() != 0xff) ;
#else
 if (bios(2)==0) return();
 while (bios(2)!=0) ;
 getchar();
#endif
}

char getyes()
{ char ch;
 ch=getkey(); if (ch==13) ch='Y';
 return(0x5F & ch);
}

char* copsym(dest,sour,n)
char *dest, *sour;
char n;
{ char ch;
 while (n) if ((ch=*sour++) <= 32) break;
      else { *dest++=ch; n--; }
 *dest=0;
 return(dest);
}

fillmem(adr,siz,byt)
char *adr, byt;
unsigned siz;
{
 while (siz--) { *adr++ = byt; }
}

beep()
{ int i; for (i=0; i<5; i++) bios(4,7);
}

bottom()
{ int i; gotoxy(VSIZE-1,0); for (i=0; i<63; i++) bios(4,' ');
 gotoxy(VSIZE-1,0);
}

char askdisk()
{ char ch;
 while (1)
 {
  bottom(); printf("Select Disk (A..D) ? ");
  if ((ch=(getkey() & 0x5F))==27) break;
  ch=ch-'@'; if ((ch>0) && (ch<4)) break;
 }
  restbtm();   return(ch);
}

int askuser()
{ char ch;
 int i;
 while (1)
 {
  bottom(); printf("Select User (0..9,A..F) ? ");
  if ((ch=(getkey() & 0x5F))==27) break;
  if ((ch>='F') && (ch<'0')) continue;
  if (ch>='A') i=10+(ch-'A'); else
    i = ch-'0'; break;
 }
  restbtm();   return(i & 0xf);
}

restbtm()
{ int i;
 gotoxy(VSIZE-1,0);
 for (i=0; i<63; i++) bios(4,' ');
 gotoxy(VSIZE-1,0);
 bios(4,'@'+disk); bios(4,'>');
}

gocpm()
{
gotoxy(VSIZE-2,0);
bios(4,27); bios(4,0x31); bios(4,27); bios(4,0x3b);
bdos(fuser,in_user); exit();
}

int dump80(adr,padr)
unsigned padr;
char *adr;
{
 int i,j;
 char *tadr, ch2;

 if (kbhit()) getchar();

 for (j=0; j<8; j++)
  {
   printf("\n%04x ",padr);
   tadr=adr;
   for (i=0; i<16; i++) { hex(*adr++); spc(); }
   for (i=0; i<16; i++) prsym(*tadr++);
   padr += 16;

   if (isfree()==FALSE)
                 { if ((ch2=getkey())==27) return(1);
                   free(); ch2=getkey(); bios(4,8);
                   if (ch2==27) return(1);
                   if ((ch2==K_UP) || (ch2 & 0x5F == 'B')) return(2);
                 }
  }
 return(0);
}

#if !OTLAD

hex(ch)
char ch;
{
nibl((0xF0 & ch) >> 4);
nibl(0x0F & ch);
}

nibl(ch)
char ch;
{
if (ch<10) bios(4,'0'+ch);
  else bios(4,ch-10+'A');
}

prsym(k)
char k;
{ if (k<32) bios(4,'.'); else bios(4,k); }

#endif


#if     NOASM
#include "rama.c"
#endif

#if     OTLAD
#include "otlad.c"
#endif

Легко видеть, что реализованы лишь основные команды: D- выбор диска, U- выбор юзера, <ВК>- запуск COM-файла, <пробел>- отметка файлов (для копирования или удал.), C- копирование файлов, T- просмотр файлов (текстовых текстом, кодовых дампом), E- удаление файлов, F2- перечитать диск, <ТАБ>- скачки между панелями, <ESC>- выход в DOS. В ходе отладки программы в реале (без использования отладчика), нужна процедура вывода дампа (которая подключается к программе, если ключ OTLAD=1). Отладчиком я практически не пользовался, тем более для ЯВУ, где стандартный отладчик вообще бесполезен. Если часто перетранслировать в ходе разработки, то и без отладчика ясно в каком месте ошибка, и чтобы понять что не так достаточно просмотреть переменные, для чего и нужен дамп.

просмотр дампа в ходе отладки:

dump(adr,siz)
char *adr;
int siz;
{
int ad,i,j,lns,off,of2;
char *tadr, *adr2;

lns = siz / 16;
if ((siz % 16) != 0) lns++;

off=of2=0;
if (adr > 0x8000) goto M3;
ad = adr;
off = ad % 16; of2=off;
if (off != 0)
   for (i=off; i=0; i--) adr--;
M3:
for (j=0; j<lns; j++)
 {
   ad=adr; printf("\n%x ",adr);
   tadr=adr;
   for (i=0; i<16; i++)
   { if (off==0) hex(*adr++); else { spc(); spc(); off--; } spc(); }
   spc();
   for (i=0; i<16; i++)
      { if (of2==0) prsym(*tadr++); else { spc(); of2--; } }
 }
}

hex(ch)
char ch;
{
nibl((0xF0 & ch) >> 4);
nibl(0x0F & ch);
}

nibl(ch)
char ch;
{
if (ch<10) bios(4,'0'+ch);
  else bios(4,ch-10+'A');
}

prsym(k)
char k;
{ if (k<32) bios(4,'.'); else bios(4,k); }


А вот самое интересное, - то как подключаются ассемблерные функции. Ассемблерными функциями разумно заменять все достаточно простые для этого функции на Си - это сокращает объём. Но всё равно объём серъёзной программы растёт слишком быстро.

фнкции написанные на ассемблере:

       INCLUDE   <BDS.LIB>

LP$OFS: equ     0
RP$OFS: equ     24
V$SIZE: equ     25

       FUNCTION mssg

       call    MA1TOH
       push    b
       mov     c,l
       mov     b,h
       lhld    1
       lxi     d,9
       dad     d
       shld    execal +1
       mov     h,b
       mov     l,c
msgloo: mov     a,m
       ora     a
       jz      msgexi
       mov     c,a
execal: call    0
       inx     h
       jmp     msgloo
msgexi:
       pop     b
       ret

       ENDFUNC

       FUNCTION f81b

       push    b
       call    0f81bh
       mvi     h,0
       mov     l,a
       pop     b
       ret

       ENDFUNC

       FUNCTION panel
       EXTERNAL bottom

       call    ma1toh
       mov     a,L

       push    b
       lhld    1
       lxi     d,9
       dad     d
       shld    bio4c

       ora     a
       jnz     rpanel

lpanel:
       mvi     h,LP$OFS+1
       mvi     L,0
       call    horiz

       mvi     h,LP$OFS
       mvi     L,0
       call    vert

       mvi     h,LP$OFS+23
       mvi     L,0
       call    vert

       mvi     h,LP$OFS+1
       mvi     L,V$SIZE-2
       call    horiz

       mvi     h,LP$OFS+15
       mvi     L,0
       call    vert

       mvi     h,LP$OFS+7
       mvi     L,0

       pop     b
       ret

rpanel:
       mvi     h,RP$OFS+1
       mvi     L,0
       call    horiz

       mvi     h,RP$OFS
       mvi     L,0
       call    vert

       mvi     h,RP$OFS+23
       mvi     L,0
       call    vert

       mvi     h,RP$OFS+1
       mvi     L,V$SIZE-2
       call    horiz

       mvi     h,RP$OFS+15
       mvi     L,0
       call    vert

       mvi     h,RP$OFS+7
       mvi     L,0

       pop     b
       ret

vert:   shld    koo
       call    posit
       call    plus
       lda     koo
       inr     a
       sta     koo
vloop:  lhld    koo
       call    posit
       mvi     c,'|'
       call    cnout
       lda     koo
       inr     a
       sta     koo
       cpi     V$SIZE-2
       jnz     vloop
       lhld    koo
       call    posit
       jmp     plus

koo:    dw      0

horiz:  call    posit
       mvi     b,22
       mvi     c,'-'
hor02:  push    b
       call    cnout
       pop     b
       dcr     b
       jnz     hor02
       ret

plus:   mvi     c,'+'
       jmp     cnout

posit:  push    h               ; l-vert h-horiz
       mvi     c,27
       call    cnout
       mvi     c,59h
       call    cnout
       pop     h
       push    h
       mov     a,l
       adi     32
       mov     c,a
       call    cnout
       pop     h
       mov     a,h
       adi     32
       mov     c,a
cnout:
       db      0c3h
bio4c:  dw      0

       ENDFUNC

       FUNCTION f82a

       call    ma1toh
       shld    prm1
       call    ma2toh
       push    b
       mov     d,h
       mov     e,l
       db      21h
prm1:   dw      0
       call    0f82ah
       mov     h,b
       mov     l,c
       pop     b
       ret

       ENDFUNC


Обратите внимание, что функция MSSG (аналог п/п F818 в РК) использует вывод на экран через вход CONOUT в CP/M-BIOS. А т.к в разных CP/M (на разных машинах) адрес BIOS - разный, то сначала этот адрес CONOUT подпрограммой MSSG высчитывается и подставляется методом модификации кода. Так делают все грамотные программы CP/M. Ещё там есть функция рисующая на экране символами две панели нортона и также видно как просто ассемблерной функцией вызывать п/п-ммы ROM-BIOS компьютера (в данном случае вызывается подсчёт КС, вероятно это было надо для занесения КС файла в метку ORDOS-файлов).

А вот как панели нортона рисуются самим Си (тут похоже на Си делается то же самое, что делает ассеблерная функция PANEL). Эта функция, очевидно, была в теле основного модуля, но когда выяснилось, что это тормознуто, то было заменено на ассемблерную (но ключом NOASM тут можно выбрать - использовать эту подпрограмму на Си или на ассемблере).

отрисовка панелей кодом на Си:

rames()
{
rama(lp_ofs); rama(rp_ofs);
gotoxy(0,lp_ofs+7); printf(" %c:\\User %d ",'@'+disk1,user1);
gotoxy(0,rp_ofs+7); printf(" %c:\\User %d ",'@'+disk2,user2);
}

rama(p_ofs)
int p_ofs;
{
int i;
gotoxy(0,p_ofs); bios(4,'+');
for (i=0;i<22;i++) bios(4,'-'); bios(4,'+');
for (i=1;i<VSIZE-1;i++) { gotoxy(i,p_ofs+23); bios(4,'|'); }
gotoxy(VSIZE-1,p_ofs); bios(4,'+');
for (i=0;i<22;i++) bios(4,'-'); bios(4,'+');
for (i=VSIZE-2;i>0;i--) { gotoxy(i,p_ofs); bios(4,'|'); }

/* for (i=1; i<VSIZE-1; i++) { gotoxy(i,p_ofs+23); bios(4,'|'); } */

gotoxy(0,p_ofs+15); bios(4,'+');
for (i=1; i<VSIZE-1; i++) { gotoxy(i,p_ofs+15); bios(4,'|'); }
gotoxy(VSIZE-1,p_ofs+15); bios(4,'+');
}

Ассемблерные функции разумно поместить в один файл с расширением CSM, который затем транслируется с помощью программы CASM.COM (это компилятор с ассемблера в REL-формат принятый в BDS), на выходе получается странслированный файл с расширением CRL (что очевидно акроним от C и REL). Си-модули компилируются компилятором BDS-C (это CC.COM) также в формат CRL. Ну а далее, все оттранслированные CRL-модули линкуются вместе компоновщиком BDS.

Жаль, что BDS не берёт стандартный REL-формат, тогда бы ассемблерные куски можно было бы писать в нормальной мнемонике Z80. Но надо ещё почитать доки, может это всё-же можно (например я встречал компиляторы Паскаля и PL/M, которые могут использовать как свой REL-формат, так и майкрософтовский).

Вот здесь можно скачать BDS-C вместе с доками и примерами.

- - - Добавлено - - -

При трезвой оценке и из некоторого опыта применения компиляторов Си и Паскаля для 8-ми разрядок можно сделать вывод, что минимальные требования к железу при разработке программ на этих ЯВУ - это Z80 с реальным клоком от 5 МГЦ и CP/M с TPA от 62 кб (именно TPA - Transient Programm Area, а не free contiguous RAM). Тогда более-менее серъёзные программы из под ЯВУ будут умещаться в доступное ОЗУ и не особо тормозить. Да и при 5 МГЦ такта при написании динамичных игр останется резон критичные процедуры всё-равно писать на ассемблере, хотя благодаря изобилию ОЗУ исчезнет смысл (ради сжатия кода) всё, что можно, переписывать на ассемблер, т.к ОЗУ будет хватать. А это заметно ускорит программирование.

Естественно, при низких скоростях базового РК при нежелании трахаться с ассемблером напрашивается использование для трансляции высокодинамичных игр компилятора PLMX, т.к он даёт код раза в 2-3 более быстрый и компактный, чем более высокоуровневые ЯВУ. Но к сожалению у PL/M идиотическая лексика и переучиться на неё после Си и Паскаля тяжело, да и уровень этого языка самый низкий (близок к ассемблеру), что ненамного облегчает жизнь программисту.

И всё же мне известно, что в России произошло несколько случаев более-менее успешного написания игр для 8-ми разрядки на Си. Это использование убогого самодельного BEST C для написания нескольких графических игр для ОРИОНА и профессиональный программист В.Широков из Воронежа в 1992 году написал две игры (Xeno World и Ranger) для ОРИОНА используя именно BDS-C и граф.библиотеку, по функциям почти идентичную граф.функциям из Турбо Си MSDOS (эта библиотека есть в архиве по вышеприведённой ссылке). Возможно движения спрайтов в этих играх чуть скачкообразнее, чем в играх на ассемблере, но всё-же визуально эти игры не хуже тех, что написаны на ассемблере.

Если уж у графического ОРИОНА (только не помню в цвете или без) его мизерного такта в 2.5 МГЦ хватило, то это позволяет нам вполне обоснованно надеяться, что не всё настолько плохо с быстродействием кода из под Си и других ЯВУ и для менее требовательной к скорости CPU текстовой машины скоростей ЯВУ хватит.


Последний раз редактировалось: barsik (Сб Окт 31 2020, 01:41), всего редактировалось 1 раз(а)
barsik
barsik
Мастер++

Сообщения : 864
Дата регистрации : 2016-11-10
Откуда : С-Петербург

Вернуться к началу Перейти вниз

Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения