Еще один простой компилятор для PDP-11. Альтернативная история

Довольно давно я сделал версию компилятора языка TinyContext для миникомпьютера PDP-11. Это практически дословный перевод версии для MS-DOS и он может быть скомпилирован с ее помощью. Для тестирования использовался эмулятор simh и основной тест - компиляция собственного исходного кода был выполнен.

Но это совсем не равно созданию компилятора на реальной машине, тем более с нуля. Если есть машина без систем программирования и даже без операционной системы, то начать придется с ручной компиляции компилятора и ручной же пробивки перфолент или перфокарт с кодом компилятора и его исходным текстом. При этом неизбежно будут допущены ошибки и их надо будет как-то искать и исправлять. И второй вопрос - как сделать перфоленты, особенно перфоленту с кодом?

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

Я никогда не работал на PDP-11, разве что когда-то проходил мимо машины СМ-4, поэтому прехде чем что-то делать спросил у искуственного интеллекта, как задачу можно решить. Ответ был следующий:

Оценки затрат времени на кодирование и ввод следующие:

Делать это придется дваджы и затем сравнивать результаты. Для сравнения лент можно использовать машину.

Скорее всего нужна возможность разбивки и кода и исходного текста на несколько лент.

Я попробовал перевести в код самую первую функцию компилятора (mul), длина кода 83 слова, это заняло 100 минут. Сравнение со сгенерированным кодом заняло еще 11 минут. Если экстраполировать, то получится примерно 5000 минут на все - больше восемьдесяти часов. Но может быть, дальше будет быстрее? Перевести еще одну-две функции вполне возможно, переводить весь текст я не готов.

Начал я с ошибки - при кодировании первой же строки M:=0; пропустил команду записи переменной M (010037/117226). При кодировании перехода в начало вложенного цикла я это заметил, сделал вставку двух команд, написанные на бумаге адреса решил не менять. Поскольку все переходы относительные, неверные адреса не должны были привести к ошибкам, но привели:

При сравнении со сгенерированным кодом я пропустил еще одну ошибку - неправильный код инструкции копирования содержимого регистра R0 в R1. На бумаге был написан код 0100001 вместо 10001. Обнаружилось после ввода инструкций в файл и сравнения файлов с помощью diff.

К слову, код функции значительно больше, чем он мог бы быть. При ручном кодировании можно уложиться в 22 слова. Длина кода функции init() 710 слов, ее я не переводил целиком, но чтобы оценить минимально необходимый размер достаточно перевести в код три команды. Получится 271 слово.

Примитивный распределитель регистров позволяет уменьшить длину кода init() до 541 слова, но смысла в нем нет. Он сокращает код компилятора меньше чем на 5 процентов, а возможность сделать ошибку наверняка увеличивает. Самый первый вариант компилятора содержал одну незначительную оптимизацию (исключение выдачи повторных команд возврата из функции) и она была сделана неправильно.

В принципе можно выполнять оптимальную компиляцию вручную, это сократит затраты на ввод кода, но не факт, что сократит затраты на компиляцию.

Пробивка ленты занимает меньше времени, на первую попытку ввода 85 инструкций (83 слова функции mul и 2 слова перехода к главной функции) я потратил 7 минут и понял, что запутался. Вторая попытка тоже оказалась неудачной. Четыре ошибки были замечены сразу при вводе и исправлены (BACKSPACE+RUBOUT), один код введен неверно из-за ошибки при компиляции (не при вводе!). И все это было впустую, поскольку в начале я забыл пробить стартовый адрес.

Третья попытка выполнялась на модифицированном эмуляторе телепринтера github.com/progs-n-things/asr33emu. Модификация состояла в замене кодов символов для клавиш 'закрывающая квадратная скобка', 'обратный слеш' и 'кавычка' на 'перевод строки', 'возврат каретки' и 'удаление' (DELETE/RUBOUT) соответственно. Это сделало клавиатуру ПК похожей на клавиатуру телепринтера и дало естественный способ ввода символа 'перевод строки' (при нажатии клавиши Enter вводится 'возврат каретки', чтобы ввести символ 'перевод строки' есть комбинация клавиш Ctrl-J, но это путь к лишним ошибкам). При отключенной печати на бумаге (т.е. только при пробикве прфоленты) на ввод тех же 85 инструкций я потратил 17 минут. Наверное, отверстия на перфоленте читаются хуже, чем символы на бумаге (и наверное, на реальном устройстве они читаются еще хуже). Я сделал пять ошибок, которые заметил и исправил. В итоге одна ошибка - в самом конце кода ввел 1777<DELETE/RUBOUT>17755213700 (нет возрата каретки между 177552 и 13700).

Общие затраты на пробивку лент примерно 850 минут - чуть больше четырнадцати часов. Тоже не быстро.

Стало ясно, что процесс компиляции и ввода должен быть изменен:

Перед кодированием функции необходимо было вычислить адреса глобальных переменных, на что ушло 19 минут, 11 минут собственно на вычисления и 8 минут на проверку. Но это разовые затраты, при переводе каждой следующей функции нужно вычислять адреса только ее переременных.

Перед этим я сделал еще две ошибки:

Обшие затраты на компиляцию и ввод примерно 98 часов. И для выявления ошибок сделать это придется дважды. И не факт, что все заработает сразу.

Для компиляции в среде MS-DOS (теперь для этого нужен DOSBox/86Box или какой-нибудь другой эмулятор) нужно заменить все функции ввода-вывода от open() до halt() их аналогами, увеличить размер массива Text c 2048 символов до 16384 символов (ЭТО ВАЖНО!) и получить работающий в той же среде MS-DOS кросс-компилятор. С его помощью получить образ перфоленты с компилятором, работающим на PDP-11 без операционной системы.

Итак, нужно добавить возможность смены ленты с исходным текстом и вывод текстовых представлений кодов. Исходный текст компилятора, пока не окончательный. Результат компляции выводится на телепринтер:

char Text [ 2048]; word pText; word nText; word nLine; word Code [ 8192]; word nCode; word hFile; char Heap [ 2048]; word nHeap; word Name [ 256]; word Cls [ 256]; word Sub [ 256]; word Type [ 256]; word Size [ 256]; word Ofs [ 256]; word nName; word nData; word Stk [ 128]; word pStk; char Buff [ 128]; word mul (word A, word B) is word M:=0; while B >0 do word T :=A; word I :=1; while B-I>=I do T:=T+T; I:=I+I; end M:=M+T; B:=B-I; end return M; end word div (word A, word B) is word D:=0; while A>=B do word T :=B; word I :=1; while A-T>=T do T:=T+T; I:=I+I; end A:=A-T; D:=D+I; end return D; end word mod (word A, word B) is return A-mul(div(A,B),B); end word open() is return 0; end word create() is return 0; end word getc() is inline 0x15C1, 0xFF68; // 012701 177550 // mov #TRS, R1 inline 0x0A89; // 005211 // inc (R1) inline 0x35C9, 0x8080; // 032711 100200 // bit #100200, (R1) inline 0x8104; // 100404 // bmi inline 0x03FC; // 001774 // beq inline 0x9C40, 0x0002; // 116100 000002 // movb 2(R1), R0 inline 0x0102; // 000402 // br inline 0x15C0, 0xFF00; // 012700 177400 // mov #ERR, R0 end word read() is word P:=0; word W:=getc(); while W!=0xFF00 do Text[P]:=char(W); P :=P+1; if P>=2048 then return P; end W:=getc(); end return P; end char punch(word B) is word B1:=B; inline 0x15C1, 0xFF6C; // 012701 177554 // mov #TPS, R1 inline 0x9031, 0x0002; // 110061 000002 // movb R0, 2(R1) inline 0x15C0, 0x0000; // 012700 000000 // mov #0, R0 inline 0x35C9, 0x8080; // 032711 100200 // bit #100200, (R1) inline 0x8102; // 100402 // bmi inline 0x03FC; // 001774 // beq inline 0x0102; // 000402 // br inline 0x15C0, 0x0001; // 012700 000001 // mov #1, R0 end word write() is word pCode:=0; while pCode<nCode do punch(mod(Code[pCode],256)); punch(div(Code[pCode],256)); pCode:=pCode+1; end end word close() is return 0; end char putc(char C) is char C1:=C; inline 0x15C1, 0xFF74; // 012701 177564 // mov #serial, R1 inline 0x9031, 0x0002; // 110061 000002 // movb R0, 2(R1) inline 0x8BC9; // 105711 // tstb (R1) inline 0x80FE; // 100376 // bpl end char wait() is putc('?'); inline 0x15C1, 0xFF70; // 012701 177560 // mov #RCSR, R1 inline 0x0A89; // 005211 // inc (R1) inline 0x8BC9; // 105711 // tstb (R1) inline 0x80FE; // 100376 // bpl inline 0x9C40, 0x0002; // 116100 000002 // movb 2(R1), R0 //inline 0x0A9F, 0xFF70; // 005237 177560 // inc (#RCSR) //inline 0x8BDF, 0xFF70; // 105737 177560 // tstb (#RCSR) //inline 0x80FD; // 100375 // bpl //inline 0x97C0, 0xFF72; // 113700 177562 // movb (177562), R0 putc(char(13)); putc(char(10)); end word halt() is inline 0x0000; end word Init() is Heap[ 0]:='0'; Heap[ 1]:='1'; Heap[ 2]:='2'; Heap[ 3]:='3'; Heap[ 4]:='4'; Heap[ 5]:='5'; Heap[ 6]:='6'; Heap[ 7]:='7'; Heap[ 8]:='8'; Heap[ 9]:='9'; Heap[10]:='A'; Heap[11]:='B'; Heap[12]:='C'; Heap[13]:='D'; Heap[14]:='E'; Heap[15]:='F'; Heap[16]:='c'; Heap[17]:='h'; Heap[18]:='a'; Heap[19]:='r'; Heap[20]:= char(0); Heap[21]:='b'; Heap[22]:='y'; Heap[23]:='t'; Heap[24]:='e'; Heap[25]:= char(0); Heap[26]:='w'; Heap[27]:='o'; Heap[28]:='r'; Heap[29]:='d'; Heap[30]:= char(0); Heap[31]:='b'; Heap[32]:='e'; Heap[33]:='g'; Heap[34]:='i'; Heap[35]:='n'; Heap[36]:= char(0); Heap[37]:='i'; Heap[38]:='f'; Heap[39]:= char(0); Heap[40]:='w'; Heap[41]:='h'; Heap[42]:='i'; Heap[43]:='l'; Heap[44]:='e'; Heap[45]:= char(0); Heap[46]:='i'; Heap[47]:='n'; Heap[48]:='l'; Heap[49]:='i'; Heap[50]:='n'; Heap[51]:='e'; Heap[52]:= char(0); Heap[53]:='r'; Heap[54]:='e'; Heap[55]:='t'; Heap[56]:='u'; Heap[57]:='r'; Heap[58]:='n'; Heap[59]:= char(0); Heap[60]:='e'; Heap[61]:='n'; Heap[62]:='d'; Heap[63]:= char(0); Heap[64]:='c'; Heap[65]:='.'; Heap[66]:='p'; Heap[67]:='r'; Heap[68]:='g'; Heap[69]:= char(0); Heap[70]:='c'; Heap[71]:='.'; Heap[72]:='c'; Heap[73]:='o'; Heap[74]:='m'; Heap[75]:= char(0); nHeap :=76; Name[ 0]:=16; Cls [ 0]:= 1; Size[ 0]:= 1; Name[ 1]:=21; Cls [ 1]:= 1; Size[ 1]:= 1; Name[ 2]:=26; Cls [ 2]:= 1; Size[ 2]:= 2; nName := 3; pStk := 0; nCode := 0; nData := 16640; end word Push(word V) is Stk[pStk]:=V; pStk:=pStk+1; end word Pop () is pStk:=pStk-1; return Stk[pStk]; end word putn(word N) is pStk:=0; while N!=0 do Push (mod(N,10)); N :=div(N,10); end while pStk!=0 do putc(char(Pop()+48)); end end word Stop() is putn (nLine); close(); halt (); end word val () is word E:=10; word I:= 0; if Buff[0]='0' then if Buff[1]='c' then E:= 8; I:= 2; end if Buff[1]='x' then E:=16; I:= 2; end end word N:=0; while Buff[I]!=char(0) do word K:=0; while Heap[K]!=Buff[I] do if K=E then Stop(); end K:=K+1; end N:=mul(E,N); N:=N+K; I:=I+1; end return N; end char Look() is char DEL:=char(255); char Ch :=DEL; //FIXME Sign extension! //while Ch =char(255) do while Ch =DEL do if pText>=nText then pText :=0; nText :=read(); if nText=0 then wait(); nText :=read(); end //if pText>=nText then if nText=0 then //return char(0); Stop(); end end Ch:=Text[pText]; //if Ch=char(255) then if Ch=DEL then pText:=pText+1; end end //return Text[pText]; return Ch; end char Read() is char Ch:=Look(); if Ch =char(10) then nLine :=nLine+1; end pText :=pText+1; putc (Ch); return Ch; end word isalnum() is if 'A'<=Look() then if Look()<='Z' then return 0; end end if 'a'<=Look() then if Look()<='z' then return 0; end end if '0'<=Look() then if Look()<='9' then return 0; end end return 1; end word Digraph(char C1, char C2) is if Buff[0]=C1 then if Look()=C2 then Buff[1]:=Read(); Buff[2]:=char(0); end end end char Scan() is word pBuff:=0; while pBuff =0 do word sFlag:=0; while sFlag =0 do if Look()!=char( 0) then if Look()!=char( 9) then if Look()!=char(10) then if Look()!=char(13) then if Look()!=char(32) then sFlag:=1; end end end end end if sFlag=0 then Read(); end end while isalnum()=0 do Buff[pBuff]:= Read(); pBuff :=pBuff+1; end if pBuff=0 then Buff[pBuff]:= Read(); pBuff :=pBuff+1; end Buff[pBuff] :=char(0); Digraph('<', '='); Digraph('!', '='); Digraph('>', '='); Digraph(':', '='); if Buff[0]='/' then if Look()='/' then while Look()!=char(10) do if Read()=char(0) then Stop(); end end pBuff:=0; end end end end word Comp(word pHeap) is word pBuff:=0; while Buff[pBuff]=Heap[pHeap] do if Buff[pBuff]=char(0) then return 0; end pHeap:=pHeap+1; pBuff:=pBuff+1; end return 1; end word Find(word fFlag) is word pName:=0; while pName< nName do if Comp(Name[pName])=0 then return pName; end pName:=pName+1; end if fFlag=0 then Stop(); end return pName; end word Emi2(word W) is Code[nCode]:=W; nCode:=nCode+1; end word Assign(word I) is if Size[I]>1 then Emi2(0x1581); // 012601 // mov (SP)+, R1 if Size[Type[I]]=1 then Emi2(0x9031); // 110061 // movb R0, Adr(R1) end if Size[Type[I]]=2 then Emi2(0x1031); // 010061 // mov R0, Adr(R1) end end if Size[I]=1 then if Size[Type[I]]=1 then Emi2(0x901F); // 110037 // movb R0, @#Adr end if Size[Type[I]]=2 then Emi2(0x101F); // 010037 // mov R0, @#Adr end end Emi2(Ofs[I]); end word Expr() is word eFlag:=0; //if eFlag =0 then if '0'<=Buff[0] then if Buff[0]<='9' then Emi2(0x15C0); // 012700 // mov #Val, R0 Emi2(val()); eFlag:=1; end end if Buff[0]=''' then //TODO 128..255 Emi2(0x15C0); // 012700 // mov #Val, R0 Emi2(word(Read())); Read(); eFlag:=1; end if Buff[0]='(' then Scan(); Expr(); eFlag:=1; end //end if eFlag =0 then word I:=Find(0); if Cls[I]=1 then Push(I); Scan(); // ( Scan(); Expr(); I:=Pop(); end if Cls[I]=2 then if Size[I]>1 then Push(I); Scan(); // [ Scan(); Expr(); I:=Pop(); if Size[Type[I]]=1 then //TODO Use CLR/BISB Emi2(0x9C00); // 116000 // movb Adr(R0), R0 end if Size[Type[I]]=2 then Emi2(0x0CC0); // 006300 // asl R0 Emi2(0x1C00); // 016000 // mov Adr(R0), R0 end end if Size[I]=1 then if Size[Type[I]]=1 then //TODO Use CLR/BISB Emi2(0x97C0); // 113700 // movb @#Adr, R0 end if Size[Type[I]]=2 then Emi2(0x17C0); // 013700 // mov @#Adr, R0 end end Emi2(Ofs[I]); //INFO Added 22.03.2026 if Size[Type[I]]=1 then Emi2(0x45C0); // 042700 // bic #177400, R0 Emi2(0xFF00); end end if Cls[I]=3 then Scan(); // ( Push(I); Sub[nName]:= 0; word J:=I+1; while Sub[J]=1 do Push(J); Scan(); Expr(); J:=Pop(); Assign(J); J:=J+1; end I:=Pop(); if J=I+1 then Scan(); // ) end word W:=(0xFFFF-(((nCode+nCode)+4)-Ofs[I]))+1; Emi2(0x09F7); // 004767 // jsr Ofs Emi2(W); end end Scan(); word I:=0; if Buff[0]='+' then I:=1; end if Buff[0]='-' then I:=2; end if I!=0 then Emi2(0x1026); // 010046 // mov R0, -(SP) Push(I); Scan(); Expr(); I:=Pop(); if I=1 then Emi2(0x1581); // 012601 // mov (SP)+, R1 Emi2(0x6040); // 060100 // add R0, R1 end if I=2 then Emi2(0x1001); // 010001 // mov R0, R1 Emi2(0x1580); // 012600 // mov (SP)+, R0 Emi2(0xE040); // 160100 // sub R0, R1 end end end word Cond() is Scan(); Expr(); //TODO word jCode:=0; if Buff[0]='<' then jCode:=0x8700; // 1034XX // blo Ofs if Buff[1]='=' then jCode:=0x8300; // 1014XX // blos Ofs end end if Buff[0]='=' then jCode:=0x0300; // 0014XX // beq Ofs end if Buff[0]='!' then jCode:=0x0200; // 0010XX // bne Ofs end if Buff[0]='>' then jCode:=0x8200; // 1010XX // bhi Ofs if Buff[1]='=' then jCode:=0x8600; // 1030XX // bhis Ofs end end if jCode=0 then Stop(); end Emi2(0x1026); // 010046 // mov R0, -(SP) Scan(); Expr(); Emi2(0x1581); // 012601 // mov (SP)+, R1 Emi2(0xE001); // 160001 // sub R1, R0 Emi2(jCode+2); // bxx 2 Push(nCode); Emi2(0x0077); // 000167 // jmp ? //nCode:=nCode+1; Emi2(0); end word Obj (word T) is if Cls[T]!=1 then Stop(); end Name[nName]:=nHeap; Type[nName]:= T; Scan(); if Find(1)<nName then Stop(); end word pBuff:=0; char Ch :=char(1); while Ch !=char(0) do Ch := Buff[pBuff]; Heap[nHeap]:= Ch; nHeap :=nHeap+1; pBuff :=pBuff+1; end Scan(); return nName; end char Var (word Subclass) is Cls [nName]:= 2; Sub [nName]:= Subclass; Size[nName]:= 1; Ofs [nName]:=nData; if Buff[0]='[' then if Subclass!=0 then Stop(); end Scan(); Size[nName]:=val(); Scan(); // ] Scan(); // ; end nData :=nData+(mul(Size[Type[nName]],Size[nName])); if mod(nData,2)!=0 then nData :=nData+1; end nName :=nName+1; return Buff[0]; end word Hide() is word I:=Pop(); while I< nName do Heap[Name[I]]:=char(0); I :=I+1; end end word ReserveInt() is while mod(nCode+nCode,16)!=0 do Emi2(0); end end word Reserve() is ReserveInt(); Emi2(0); ReserveInt(); end word Patch(word pCode) is Code[pCode+1]:=(nCode+nCode)-((pCode+pCode)+4); end //word rFlag; word Ctrl() is word cFlag:=0; //if cFlag =0 then if Comp(37)=0 then // if Cond(); //Push(nCode); //Emi2(0x0077); // 000167 // jmp ? //nCode:=nCode+1; Push(nName); Scan(); Ctrl(); while Comp(60)!=0 do // !end Ctrl(); end Hide(); //word pSkip:=Pop(); //Emi3 (pSkip+1, (nCode+nCode)-((pSkip+pSkip)+4)); //Code [pCode+1]:=(nCode+nCode)-((pCode+pCode)+4); Patch(Pop()); //rFlag:=1; // 14.05.2006 cFlag:=1; end //end if cFlag =0 then if Comp(40)=0 then // while Push(nCode); Cond(); //Push(nCode); //Emi2(0x0077); // 000167 // jmp ? //nCode:=nCode+1; Push(nName); Scan(); Ctrl(); while Comp(60)!=0 do // !end Ctrl(); end Hide(); word pExit:=Pop(); word pLoop:=Pop(); Emi2 (0x0077); // 000167 // jmp Ofs Emi2 ((0xFFFF-((nCode+nCode+2)-(pLoop+pLoop)))+1); //Emi3 (pExit+1, (nCode+nCode)-((pExit+pExit)+4)); //Code [pCode+1]:=(nCode+nCode)-((pCode+pCode)+4); Patch(pExit); //rFlag:=1; // 14.05.2006 cFlag:=1; end end if cFlag =0 then if Comp(46)=0 then // inline Buff[0]:=','; while Buff[0]=',' do Scan(); Emi2(val()); // dw Val Scan(); end //rFlag:=1; // 14.05.2006 cFlag:=1; end end if cFlag =0 then if Comp(53)=0 then // return Scan(); Expr(); Emi2(0x0087); // 000207 // rts //rFlag:=0; // 14.05.2006 cFlag:=1; end end if cFlag =0 then word I:=Find(0); if Cls[I]=1 then word N:=Obj(I); if Var(2)=':' then Scan(); Expr(); Assign(N); end end if Cls[I]=2 then if Size[I]>1 then Scan(); // [ Scan(); Expr(); if Size[Type[I]]=2 then Emi2(0x0CC0); // 006300 // asl R0 end Emi2(0x1026); // 010046 // mov R0, -(SP) end Scan(); // := Scan(); Expr(); Assign(I); end if Cls[I]=3 then Expr(); end //rFlag:=1; // 14.05.2006 end Scan(); end word Func(word Rts) is Scan(); Ctrl(); while Comp(60)!=0 do // !end Ctrl(); end //if rFlag!=0 then // 14.05.2006 // if rFlag=0 then //Emi2(0x0087); // 000207 // rts Emi2(Rts); //end end word Temp[8]; word oct(word W) is word pTemp:=0; word X :=1; while X!=0 do Temp[pTemp]:=mod(W,8); pTemp :=pTemp+1; W :=div(W,8); X :=W; end while pTemp>0 do pTemp:=pTemp-1; putc(char(Temp[pTemp]+48)); end end word dump() is putc(char(10)); oct (256); putc(' '); word pCode:=0; while pCode<nCode do oct (Code[pCode]); putc(char(10)); pCode:=pCode+1; end end begin Init(); hFile:=open(); pText:=0; nText:=0; nLine:=1; Emi2(0x0077); // 000167 // jmp ? //nCode:=nCode+1; Emi2(0); Scan(); while Comp(31)!=0 do // !begin Obj (Find(0)); char Ch:=Buff[0]; if Ch ='(' then Cls [nName]:= 3; Sub [nName]:= 0; Ofs [nName]:=nCode+nCode; nName :=nName+1; Push(nName); Scan(); if Buff[0]!=')' then Obj (Find(0)); while Var(1)=',' do Scan(); Obj (Find(0)); end end Scan(); // is Func(0x0087); Reserve(); Hide(); end if Ch!='(' then Var(0); end Scan(); end //Emi3 (1, (nCode+nCode)-4); //Code [pCode+1]:=(nCode+nCode)-((pCode+pCode)+4); Patch(0); Emi2 (0x15C6); // 012706 137640 // mov #012706, SP Emi2 (0xBFA0); Func (0x0000); close(); //hFile:=create(); //write(); //close(); dump (); end

функции ввода-вывода для кросс-компилятора:

word open() is inline 0xB4, 0x3D; // mov AH, 3DH inline 0xB0, 0x00; // mov AL, 00H inline 0xBA, 0x4A, 0xC1; // mov DX, @@Data+Ofs(Heap[64]) inline 0xCD, 0x21; // int 21H end word create() is inline 0xB4, 0x3C; // mov AH, 03CH inline 0xB9, 0x00, 0x00; // mov CX, 00H inline 0xBA, 0x50, 0xC1; // mov DX, @@Data+Ofs(Heap[70]) inline 0xCD, 0x21; // int 21H end word read() is inline 0xB4, 0x3F; // mov AH, 3FH inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)] inline 0xB9, 0x00, 0x40; // mov CX, 16384 inline 0xBA, 0x00, 0x41; // mov DX, @@DATA+Ofs(Text) inline 0xCD, 0x21; // int 21H end word write() is inline 0xB4, 0x40; // mov AH, 40H inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)] inline 0x8B, 0x0E, 0x06, 0xC1; // mov CX, word [@@DATA+Ofs(nCode)] inline 0x03, 0xC9; // add CX, CX inline 0xBA, 0x06, 0x81; // mov DX, @@DATA+Ofs(Code) inline 0xCD, 0x21; // int 21H end word close() is inline 0xB4, 0x3E; // mov AH, 3EH inline 0x8B, 0x1E, 0x08, 0xC1; // mov BX, word [@@DATA+Ofs(hFile)] inline 0xCD, 0x21; // int 21H end char putc(char C) is char C1:=C; inline 0x92; // xchg DX, AX inline 0xB4, 0x02; // mov AH, 2 inline 0xCD, 0x21; // int 21H end char wait() is inline 0x90; end word halt() is inline 0xB8, 0x00, 0x4C; // mov AX, 4C00H inline 0xCD, 0x21; // int 21H end

Top.Mail.Ru

Сайт создан в системе uCoz