Где {{ pis }}

Альтруизм в программировании

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Альтруизм в программировании » Экспроза


Экспроза

RC Piccolo, Датский компьютер RC702, выпускаемый с 1980 года.

Перевод статьи RC700 CP/M BIOS


Источник: RC700 CP/M BIOS

RC700 был в основном разработан как компьютер CP/M-80, хотя он мог быть использован с автономными системами, как RC COMAL-80 и UCSD Pascal. Наиболее распространенный вариант CP/M для RC700 была CP/M версии 2.2, в то время как исходный код для CP/M 2.2 был достоянием общественности - BIOS для RC700 была собственностью Regnecentralen и никогда официально не была выпущена. BIOS был заказом для RC700, и содержал код для сопряжения CP/M к аппаратным средствам RC700.


На основе информации из архивов DDHF, я восстановил оригинал для RC700 CP/M BIOS и хотел бы поблагодарить Dansk Datahistorisk Forening ( DDHF) за их поддержку. Я считаю, что сохранение и восстановление программного обеспечения для старых компьютеров так же важно, как и сохранение оборудования. Исходный BIOS-код RC700 CP/M дает уникальную возможность сравнить состояние самых современных систем программирования с микро-ЭВМ начала 80-х гг.



 

CP/M архитектура


 

Операционная система CP/M была разработана для множества различных микрокомпьютеров на базе 8080, поэтому был необходим интерфейс между операционной системой и аппаратными средствами.
CP/M была разделена на четыре части, называемой базовой системы ввода/вывода (BIOS), базовая операционная система Disk (BDOS), командная консоль процессора (КПК) и Переходная Программная область (ТПА).
BIOS модуль был аппаратно-зависимый, который определял интерфейс низкого уровня с аппаратными средствами RC700. BDOS был сопряжен с BIOS через таблицу переходов в начале BIOS.
КПК была использована для интерпретации и выполнения команд из командной строки, а ТФК была областью памяти, используемой для запуска прикладных программ.




RC700 автозагрузчик (см. ниже) загружает BIOS (включая код INIT) с диска в память и вызывает точку входа в коде INIT.
Это настраивает аппаратное обеспечение, а затем загружает BDOS в память.
После инициализации часть INIT больше не нужна и она переписывается BDOS.
Затем BDOS взаимодействует с аппаратным обеспечением через BIOS.



FFFFH
BIOS DA00H
BDOS INIT D480H
CC00H
CCP C400H
TPA 0100h
0000H

 

История


 

На одном из моих визитов в DDHF, я наткнулся на распечатку исходного кода для RC700 BIOS.
Это не оригинальная, но специальная версия, которая была исправлена, чтобы работать в RC700 с двумя дополнительными YD-380 гибкими дисками. Копия принадлежала Петру Heinrich, который получил её из техники RC. Слепки, кажется, были сделаны кем-то с инициалами "Тфл" в 1987 году. Хотя эта версия была исправлена, первоначальный исходный код сохранился в комментариях по всему коду, так что исходный код может быть восстановлен из исправленной версии.



 



RC700 BIOS изначально была реализована в 1982 году Карстен Dindorp и Уго К., но была изменена несколько раз, чтобы исправить ошибки и реализовать поддержку новых аппаратных средств, в частности поддержку RC703 компьютеров и жестких дисков RC763, людьми с инициалами SC, VN, FK и ЛО.
Пожалуйста, дайте мне знать, если вы знакомы с кем-либо из этих людей. Тогда я смогу обновить эту страницу с их реальными именами, чтобы они могли получить должное за их вклад. В распечатке, "Хьюго К." усекается, так что я не знаю полное имя Хьюго.


Бинарные версии RC700 BIOS сохранились на RC700 дискетах, а двоичный машинный код может быть считан из цилиндра 0 этих дискет, как описано в исходном коде.



 

Реконструкция


 

DDHF был очень добр и одолжил мне распечатку, чтобы я мог сделать её скан с высоким разрешением.
Я реализовал это через программу OCR, чтобы получить текст исходного кода, но программа OCR не сохраняет форматирование текста. Кроме того, качество OCR в исходном коде текста было довольно бедным и пришлось его редактировать, чтобы восстановить и сделать похожим на оригинал с распечатки.
После этого процесса я имел машиночитаемую версию исходного кода для RC700 CP/M BIOS. Копию не самого исходного кода, но выходной файл листинга (.LST) на ассемблере.
Это показывает, что она была собрана с помощью Microsoft MACRO-80 Ассемблера, поэтому я попытался собрать исходный код, восстановленный с помощью M80, но это дало много сообщений об ошибках, так что код источника был не совсем готов для изготовления RC700 CP/M BIOS.



 

Обратный инжиниринг


 

Так как у меня была бинарная версия машинного кода с образа дискеты, я знал точный результат, который ожидаемый на выходе ассемблера. Тем не менее, версия на образе дискеты для более ранней версии BIOS (RC700 56k CP/M vers.2.2 rel.2.1), в то время как распечатка основана на 'RC703 56k CP/M вар. 2.2 отн 1.1', так что для получения рабочей версии исходного кода BIOS, я решил реконструировать 'RC700 56k CP/M vers.2.2 rel.2.1 версию' из исходного кода.
Путем сборки исходного кода, сравнивая его байт за байтом с бинарной версией образа дискеты, я смог обнаружить все различия между оригинальной версией и версией, полученной из исходного кода.



Все патчи, сделанные Тфл были четко обозначены в тексте и оригинальный исходный код был сохранен в комментариях, так что его было легко вернуть. Тем не менее, все еще существует ряд различий между собранной и оригинальной бинарной версией, так что мне пришлось вручную отслеживать их и попытаться восстановить исходный код для оригинальной версии. В целях экономии места, абсолютные переходы были заменены относительными переходами, так что я вернул их.
Дифференциалы также выявили ряд ошибок распознавания, которые было легко исправить. Были также некоторые более существенные изменения, где я пытался восстановить исходный код. Это не точный процесс, но я стремился сохранить оригинальный стиль кода и добавлять комментарии в том же духе, что и остальная часть исходного кода, с сохранением ''Danglish комментариев в стиле 80-х годов.
Даже если я не смогу утверждать, что это 100% правильная реконструкция исходного кода, то считаю, что 97% или более исходного кода BIOS является оригинальным.



 

Исходный код

 

Теперь у меня есть версии исходного кода, по которым можно точно воспроизвести оригинальный BIOS от RC700 56k CP/M vers.2.2 rel.2.1.
Исходный код содержит перечень включаемых директив, которые указывают, что исходный код был разделен на несколько исходных файлов. Я разделил исходный код в эти файлы. Перечень не содержит каких-либо ключей к имени файла на ассемблере верхнего уровня, так что я назвал его BIOS.MAC.


BIOS может быть построен с использованием Microsoft MACRO-80 Ассемблер и CP/M линкером:


M80 BIOS.REL, BIOS.LST = BIOS.MAC
LINK BIOS.BIN = BIOS.REL [LD0000


Это создаст бинарный файл BIOS.BIN, который можно записать на цилиндр 0 на загрузочном диске.

Для того, чтобы построить это на основе гибких дисков, вам необходимо два диска: один - для исходного кода (B:), а другой - для ассемблера и компоновщика (A:). Вы можете использовать эмулятор, чтобы построить BIOS из исходного кода:

BIOS.MACГЛАВНАЯ исходный файл RC700 CP/M BIOS
BIOSTYPE.MACBIOS Кoнфигурация параметров
INIPARMS.MACHARDWARE параметры инициализации
DANISH.MACДатский INPUT/OUTPUT Конверсия ТАБЛИЦЫ
INIT.MACHARDWARE инициализирующий код
CPMBOOT.MACCP/M BIOS ДЖАМП Столик и BIOS Extentions
SIO.MACZ-80 Дисковод SIO
DISPLAY.MACДрайвер дисплея
FLOPPY.MACДисковод FLOPPY
HARDDSK.MACДисковод ВИНЧЕСТЕР
DISKTAB.MACDISK определение таблицы
INTTAB.MACТАБЛИЦА ПРЕРЫВАНИй
PIO.MACZ-80 дисковод PIO



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


 

Автозагрузчик


 

Бутстраповский загрузчик нужен для загрузки CP/M на RC700 компьютере. RC702 имеет 2KB диск с программой автозагрузчика для загрузки компьютера. Когда RC702 сбрасывается, нижние 2K памяти переносится на загрузочный диск, что позволяет системе запустить программу автозагрузчика. ROM можно отключить с помощью OUT 0x18, инструкции, делая полный 64K RAM доступными. Автозагрузчик отвечает за загрузку операционной системы с диска в память. Автозагрузчик инициализирует оборудование в известное состояние, а затем считывает первую дорожку дискеты (или жесткий диск) в память по адресу 0x0000.

На одном из дисков, которые я получил от DDHF, я нашел исходный код листинга автозагрузчика для RC700:


AUTOLOAD файл для RC700 и RC703 микрокомпьютер 
REGNECENTRALEN октября 1982 JOS 

Загрузочный диск ROB358 более новая версия, чем ROA375 я первоначально использовал в RC700 эмуляторе.
Я сделал диск сборки для загрузки ROB358, так что он может быть построен из исходного кода:


M80 ROB358.REL, ROB358.LST = ROB358.MAC 
LINK ROB358.ROM = ROB358.REL [LD000

ROB358 поддерживает загрузку с жесткого диска, так что эмулятор теперь может загружаться непосредственно с жесткого диска и теперь это загрузочный диск по умолчанию в моем RC700 эмуляторе.

 

 

; RC COMPUTER 23.04.83 25.06.82 15.09.82
;             23.10.82 05.01.83
;
; SUBJECT:                                      RC700 CP/M BASIS SOFTWARE
;
; AUTHOR:                                       KARSTEN DINDORP & HUGO K.
;
; HARD DISK CORRECTIONS:                        SC & VN JUNE 82
;
; This program consists of:
;
; 1. Hardware initiatization routines
;
; 2. CP/M BIOS
;
; and constitutes the basis software for the CP/M operating system
; on the RC700 micro computer.
;
; The program resides on cylinder 0 of a RC700 CP/M system discette,
; and is loaded into RAM from address 0000 and forward, when the ROM
; bootstrap loader is activated by a hardware reset.
;
; UPGRADES: 1: Support of 16 bit sector number.
;           2: Support of upto 4 Winchester drives.
;           3: Support all tracks on floppy disks.
;           4: Alternative register set not used.
;           5: Alternative hard disk configuration.
;           6: Warm boot from hard disk drive C
;
; The format of TRACK 0 is as follows:
;
; SECTOR    BYTE     CONTENTS
;     01 000-001     Start address. Entered from ROM bootstrap loader.
;     01 002-007     0
;     01 008-013     ' RC702'
;     01 014-127     not used. Reserved for ROM bootstrap loader.
;     02 000-127     configuration parameters.
;     03 000-127     output conversion table.
;  04-05 000-127     input conversion table.
;  06- and forward   Hardware initialization routines and CPM BIOS.
;
	.Z80
	TITLE RC702 CP/M BASIS SOFTWARE RELEASE 1.1  83.01.05
	SUBTTL GLOBAL CONSTANT DEFINITION
	PAGE

;========================================================
;= I/O ADDRESSES                                        =
;========================================================
PIOAC	EQU	12H	; PIO CHANNEL A CONTROL
PIOAD	EQU	10H	; PIO CHANNEL A DATA
PIOBC	EQU	13H	; PIO CHANNEL B CONTROL
PIOBD	EQU	11H	; PIO CHANNEL B DATA

CTCCH0	EQU	0CH	; CTC CHANNEL 0
CTCCH1	EQU	0DH	; CTC CHANNEL 1
CTCCH2	EQU	0EH	; CTC CHANNEL 2
CTCCH3	EQU	0FH	; CTC CHANNEL 3

SIOAC	EQU	0AH	; SIO CHANNEL A CONTROL
SIOAD	EQU	08H	; SIO CHANNEL A DATA
SIOBC	EQU	0BH	; SIO CHANNEL B CONTROL
SIOBD	EQU	09H	; SIO CHANNEL B DATA

CTC2C0	EQU	44H	; CTC 2 CHANNEL 0
CTC2C1	EQU	45H	; CTC 2 CHANNEL 1
CTC2C2	EQU	46H	; CTC 2 CHANNEL 2
CTC2C3	EQU	47H	; CTC 2 CHANNEL 3

HDDARG 	EQU	60H	; WD1000 DATA REGISTER
HDERRG	EQU	61H	; WD1000 ERROR REGISTER (READ ONLY)
HWPCMP	EQU	HDERRG	; WD1000 WRITE PRECOMP. REGISTER (WRITE ONLY)
HSECCT	EQU	62H	; WD1000 SECTOR COUNT
HSECNO	EQU	63H	; WD1000 SECTOR NUMBER
HCYLLO	EQU	64H	; WD1000 CYLINDER NO. LOW
HCYLHI	EQU	65H	; WD1000 CYLINDER NO. HIGH
HSZDHD	EQU	66H	; WD1000 SIZE/DRIVE/HEAD REGISTER
HDSTRG	EQU	67H	; WD1000 STATUS REGISTER (READ ONLY)
HCMDRG	EQU	HDSTRG	; WD1000 COMMAND REGISTER (WRITE ONLY)

	PAGE

DMAC	EQU	0F8H	; DMA CONTROL
DMAMOD	EQU	0FBH	; DMA MODE REGISTER
DMAMAS	EQU	0FAH	; DMA MASK REGISTER
DMAAD0	EQU	0F0H	; ADDRESS REGISTERS
DMAAD1	EQU	0F2H	;
DMAAD2	EQU	0F4H	;
DMAAD3	EQU	0F6H	;
DMACN0	EQU	0F1H	; WORD COUNT REGISTERS
DMACN1	EQU	0F3H	;
DMACN2	EQU	0F5H	;
DMACN3	EQU	0F7H	;
DMACBC	EQU	0FCH	; CLEAR BYTE COUNTER
DMAREQ	EQU	0F9H	;
DMAMSK	EQU	0FFH	;
DMATMP	EQU	0FDH	;

DSPLC	EQU	001H	; DISPLAY CONTROL
DSPLD	EQU	000H	; DISPLAY DATA

FDC	EQU	004H	; FLOPPY CONTROL
FDD	EQU	005H	; FLOPPY DATA

BELL	EQU	01CH	;
SW1	EQU	014H	;

	PAGE

;========================================================
;= RAM LAYOUT DEFINITION                                =
;========================================================
MSIZE	EQU	56		; AVAILABLE MEMORY EXCL. BIOS
BIAS	EQU	(MSIZE-20)*1024 ;
CPMB	EQU	3400H+BIAS	; CCP BASE
CCPCLR	EQU	CPMB+03H	; CCP-START ADDRESS +3
CPML	EQU	1600H		; LENGTH OF CCP AND BDOS
BDOS	EQU	CPMB+806H	; BDOS BASE
BIOS	EQU	CPMB+CPML	; BIOS BASE
BUFF	EQU	80H		; DMA BUFFER
IOBYTE	EQU	3		;
CDISK	EQU	4		; CURRENT LOGGED IN DISK
NSECTS	EQU	CPML/128	; LENGTH OF CCP AND BDOS IN 128 BYTES SECTORS
CBOOT	EQU	280H		; ROM BOOTSTRAP LOADER ENTRY POINT
PATCH1	EQU	CPMB+144CH	; FIRST PATCH ADDRESS TO WBOOT FROM HD
PATCH2	EQU	CPMB+149AH	; SECOND DO.
START	EQU	0D480H		; START OF CODE (INIT + BIOS)
BGSTAR	EQU	0F500H		; START OF BACKGROUND BITTABLE
ENDPRG	EQU	0EE80H		; RESERVED AREA FOR BIOS VARIABLES
ISTACK	EQU	BGSTAR+250+38	; STACK USED BY INTERRUPT ROUTINES
STACK	EQU	ISTACK+96	; STACK USED BY BIOS DRIVERS
OUTCON	EQU	0F680H		; OUTPUT CONVERSION TABLE
INCONV	EQU	OUTCON+128	; INPUT CONVERSION TABLE
DSPSTR	EQU	0F800H		; DISPLAY REFRESH MEMORY BASE
CCTAD	EQU	DSPSTR+2001	; COLUMN COUNT
RCTAD	EQU	CCTAD+1		; ROW COUNT
CURSY	EQU	RCTAD+2		; CURSUR Y POSITION
LOCBUF	EQU	CURSY+1		; DISPLAY BUFFER LOCATION
XFLG	EQU	LOCBUF+2	; XY ADDRESSING MODE FLAG
LOCAD	EQU	XFLG+1		; LOCATION OF CHAR
USHER	EQU	LOCAD+2		; OUTPUT CHARACTER POSITION
BGFLG	EQU	USHER+1		; BACKGROUND FLAG:
				; 0 - AFTER CLEAR SCREEN
				; 1 - AFTER SET FOREGROUND
				; 2 - AFTER SET BACKGROUND
LOCBBU	EQU	BGFLG+1		;
ADR0	EQU	LOCBBU+2	; FIRST BYTE OF ADDRESS IN XY ADDRESSING
EXCNT0	EQU	ADR0+1		; EXIT ROUTINE 0 COUNT
EXCNT1	EQU	EXCNT0+2	; EXIT ROUTINE 1 COUNT
DELCNT	EQU	EXCNT1+2	; DELAY COUNT
EXROUT	EQU	DELCNT+2	; JMP TO EXIT ROUTINE 1
FDTIMO	EQU	EXROUT+2	; LOAD VALUE OF EXCNT1
RTC0	EQU	0FFFCH		; REAL TIME CLOCK
RTC1	EQU	0FFFDH		;
RTC2	EQU	0FFFEH		;
RTC3	EQU	0FFFFH		;

	PAGE

;========================================================
;= FLOPPY DRIVER VARIABLES                              =
;========================================================
HSTBUF	EQU	ENDPRG+1	; HOST DISK DMA BUFFER
DIRBF	EQU	HSTBUF+512	; SCRATCH DIRECTORY AREA
ALL0	EQU	DIRBF+128	; ALLOCATION VECTOR DRIVE 0
CHK0	EQU	ALL0+71		; CHECK VECTOR DRIVE 0
ALL1	EQU	CHK0+32		; ALLOCATION VECTOR DRIVE 1
CHK1	EQU	ALL1+71		; CHECK VECTOR DRIVE 1
ALVHD	EQU	CHK1+32		; ALLOCATION VECTOR FOR 5 LOG.HARD DSK UNITS
SEKDSK	EQU	ALVHD+71+(4*63)	; SEEK DISK NUMBER
SEKTRK	EQU	SEKDSK+1	; SEEK TRACK NUMBER
SEKSEC	EQU	SEKTRK+2	; SEEK SECTOR NUMBER
HSTDSK	EQU	SEKSEC+2	; HOST DISK NUMBER
HSTTRK	EQU	HSTDSK+1	; HOST TRACK NUMBER
HSTSEC	EQU	HSTTRK+2	; HOST SECTOR NUMBER
LSTDSK	EQU	HSTSEC+2	; LAST DISK SEEKED
LSTTRK	EQU	LSTDSK+1	; LAST TRACK SEEKED
SEKHST	EQU	LSTTRK+2	; SEEK SHR SECSHF
HSTACT	EQU	SEKHST+2	; HOST ACTIVE FLAG
HSTWRT	EQU	HSTACT+1	; HOST WRITTEN FLAG
UNACNT	EQU	HSTWRT+1	; UNALLOCATED REC COUNT
UNADSK	EQU	UNACNT+1	; LAST UNALLOCATED DISK
UNATRK	EQU	UNADSK+1	; LAST UNALLOCATED TRACK
UNASEC	EQU	UNATRK+2	; LAST UNALLOCATED SECTOR
UNAMSK	EQU	UNASEC+2	; LAST UNALLOCATED SECTOR MASKED
ERFLAG	EQU	UNAMSK+1	; ERROR FLAG
RSFLAG	EQU	ERFLAG+1	; READ SECTOR FLAG
READOP	EQU	RSFLAG+1	; 1 IF READ OPERATION
WRTYPE	EQU	READOP+1	; WRITE OPERATION TYPE
DMAADR	EQU	WRTYPE+1	; LAST DMA ADDRESS
FORM	EQU	DMAADR+2	; POINTER TO FORMAT BLOCK
CFORM	EQU	FORM+2		; CURRENT FORMAT
EOTV	EQU	CFORM+1		; LAST SECTOR ON TRACK
DRNO	EQU	EOTV+1		; HIGHEST DRIVE NO
UNK1	EQU	DRNO+1		; ???
UNK2	EQU	UNK1+1		; ???
UNK3	EQU	UNK2+1		; ???
UNK4	EQU	UNK3+1		; ???
DSKNO	EQU	UNK4+1		; CURRENT DISK
DSKAD	EQU	DSKNO+1		; CURRENT DMA ADDRESS
ACTRA	EQU	DSKAD+2		; ACTUAL (NOT CPM) TRACK NO IN READ/WRITE
ACSEC	EQU	ACTRA+1		; ACTUAL (NOT CPM) SECTOR NO IN READ/WRITE
REPET	EQU	ACSEC+1		; REPEAT COUNTER IN READ/WRITE
RSTAB	EQU	REPET+1		; RESULT TABLE
MHDTSR	EQU	RSTAB+8		; MIRROW OF WD1000 STATUS REGISTER
MHDERR	EQU	MHDTSR+1	; MIRROW OF WD1000 ERROR REGISTER
HERRCT	EQU	MHDERR+1	; WD1000 ERROR COUNTER
SP_SAV	EQU	HERRCT+2	; SYSTEM STACK POINTER SAVE AREA
HD_FLG	EQU	SP_SAV+2	; WD1000 BUSY FLAG (0=BUSY)
HD_OFL	EQU	HD_FLG+1	; OFFLINE/ONLINE FLAG (1=OFFLINE)
FL_FLG	EQU	HD_OFL+1	; FLOPPY BUSY FLAG (0=BUSY)
WBFLAG	EQU	FL_FLG+1	; WARMBOOT FLAG

	PAGE

;========================================================
;= ACTUAL FLOPPY SYSTEM PARAMETERS                      =
;= INITIALIZED WHEN SELECT_DISK IS CALLED               =
;========================================================
DPBLCK	EQU	WBFLAG+1	; DISK PARAM BLOCK
CPMRBP	EQU	DPBLCK+2	; CP/M RECORDS PR. BLOCK
CPMSPT	EQU	CPMRBP+1	; CP/M SECTORS PR. TRACK
SECMSK	EQU	CPMSPT+2	; SECTOR MASK
SECSHF	EQU	SECMSK+1	; SECTOR SHIFT COUNT
TRANTB	EQU	SECSHF+1	; SECTOR TRANSLATION TABLE
DTLV	EQU	TRANTB+2	; DATA LENGTH
DSKTYP	EQU	DTLV+1 		; DISK TYPE (0:=FLP, FF:=HARD)
DUM	EQU	DSKTYP+6	; FILLER TO OBTAIN 16 BYTE LENGTH

;==============================================================================
;=	WD1000 MACRO COMMAND DEFINITIONS                                      =
;==============================================================================

RSTCMD	EQU	10H 		; RESTOTE COMMAND
RDCMD	EQU	28H 		; READ SECTOR WITH DMA COMMAND
WRTCMD	EQU	30H 		; WRITE SECTOR COMMAND
FMTCMD	EQU	50H 		; FORMAT TRACK COMMAND
SEEKCM	EQU	70H 		; SEEK COMMAND

	PAGE

	INCLUDE		BIOSTYPE.MAC
	INCLUDE		INIPARMS.MAC
CONVTA:
	INCLUDE		DANISH.MAC
	INCLUDE		INIT.MAC

	DS	(BIOS-$)	; ALIGN TO DA00H

	INCLUDE		CPMBOOT.MAC
	INCLUDE		SIO.MAC
	INCLUDE		DISPLAY.MAC
	INCLUDE		FLOPPY.MAC
	INCLUDE		HARDDSK.MAC
	INCLUDE		DISKTAB.MAC
	INCLUDE		INTTAB.MAC
	INCLUDE		PIO.MAC

END


 


Явление точки миру

Хотя в первую очередь ум свербит вовсе не точка, а современный "прообраз" Буля, родившегося бы где-нибудь у нас, в глубинке. (да хотя бы и у меня... - по соседству)))
- Мигом бы "освистали", раскритиковали, подняли бы на смех из-за невозможности "скоренько" применить на практике его "безумные" идеи, а все "беспочвенные" философствования по этому поводу посчитали бы "бредом выжившего из ума чудилы", наложив "вето" и предав забвению всё то, что связывает нас с его именем и его работами...

 

Вы здесь » Альтруизм в программировании » Экспроза