V-програмиране
Текстът по-долу разчита на общи познания в програмирането, малко опит в работата с операционни системи и идея за работа с някой асемблиращ език. Извинявам се за жаргона. Желанието ми е било повече разбираемост и по-малко обем. Някои очаквания няма да се сбъднат. Всичко за което съм работил е да бъде разбиран и управляван пътя от дъното до повърхността. Тъй като асемблерът е най-трудната част, обръщам му специално внимание. Това е препроцесор, тоест програма. Скоростта на изпълнение е доста (например 50 пъти) по-малка от тази на хардуерния процесор-домакин. Но е достатъчна за хода на практически задачи, защото ограниченията от мрежовия пренос са по-силни.

Предговор
V - процесорът изпълнява RVM-програми. Сорс на програмата е текстов тип файл с разширение ".RVA", а машинният код е с разширение ".RVM".
За да се получи от текста машинен код, се ползува компилатор C5.EXE - обикновена Windows програма.
В сървъра няма много видео-формалности, защото изображенията са в терминалите. Главните неща, които RVM-програмите извършват са посрещане и изпращане на заглавия (хедъри) за общуване с други програми, и мрежови пратки към терминала.
Програмният модел на V-процесора е от регистъри, оперативна памет, приемопредавател и групов механизъм. Дисковите действия са уредени в няколко директории на компютъра, където е инсталирана V-машината. На ниво "файл" работата с диска се извършва от операционната система-домакин.
Езикът на V-сървъра е вид асемблер. V-асемблерът е съставен от команди, които са били необходими при разработката на сегашните програми.
Процесите работят едновременно. Програмната организация се урежда от операционна програма и комплект програми за групово управление. При старта, груповите програми зареждат няколко бездейни процеса, чийто код е общ за по-късно използувани програми.

Обща представа за V-сървъра
Програмите разполагат с няколко регистъра и оперативна памет. Оперативната памет е с общ достъп. В нея всяка програма разполага своите променливи и стеково място. Кода на работещите програми не заема място в нея, той е в домакинската памет.

Приемопредавателя е съставен от TCP-сокет и UDP-сокет - предназначени за далечна връзка, а също и пощенска съобщителна система - преднзаначена за връзка с останалите процеси работещи едновременно с текущия.

Груповите процеси служат за координация на едновременния достъп от различни процеси до общи данни - текстове, таблици, карти - в оперативната памет, в база данни или в картова географска система. Освен това груповата машина стопанисва сложните даннови единици.

При старта на V се задействува операционната програма. Тя включва безлично програмите за групово управление, настройва приемопредавателя и остава в бездейно състояние, очаквайки заявка за връзка от терминал. При свързване на терминал възниква сесия, юзерът получава индивидуална операционна програма, както и своя десктоп-управляваща програма. Десктоп-програмата включва първия образ в терминала и по-нататък показва работещите юзерски прозорци.

Всяка програма обменя данни по три различни начина:
1. С други програми - това става чрез опашката на съобщенията;
2. С терминала - виж по-долу;
3. С груповите управители - виж по-долу;

Връзката с терминала става по следния начин: (виж фигурата вдясно)
Изпращането на данни става направо от програмата, през TCP-операционния сокет. Получаването на данни обаче не става така. Тъй като сокетът е един за всички юзерски процеси, изпратените от терминала данни се приемат първо от О-програмата на юзера. Тя решава на кой процес да достави пристигналите данни според написаното в тях и фокуса на програмните прозорци. Но това вече е вътрешен пренос и О-програмата го прави чрез съобщения (или чрез диска за по-големи порции), а не по TCP-канала.
Груповото общуване по принцип е вътрешно, тоест чрез съобщения. Но V-машината участвува на по-ниско ниво в тях и част от изпращаните съобщения идват направо от "хардуера", без да са били поръчани явно с команда.

Как работи една V-програма
Най-често V програмата се намира в бездейно състояние. V-машината я събужда когато в опашката има съобщение. По идея програмата трябва да вземе това съобщение, да направи съответното действие и да остане отново бездейна.

Етапи в работата на програмата
Всяка програма има стартов участък - в началото тя трябва да определи средата в която е стартирана - своята идентификация, операционното обкръжение и статуса на данните, с които ще работи. Обикновено програмата изпраща към терминала и началния си образ. При нормална работа, както беше споменато, програмата обработва пристигащите съобщения. Накрая тя има ангажимент да унищожи своя образ в терминала.

Строеж на програмата
Като текст програматa има няколко задължителни участъка - заглавна част, константи, променливи и код. Компилаторът оразмеряват автоматично променливите, но размера на стека се декларира с клауза "STACK 3400".
Нормалната програма се асоциира с прозорец, а прозоречната система не е много проста. Постепенно успях да изолирам задачата за прозорците в отделна програма, която по-късните програми включват чрез клауза "INCLUDE" заедно с нейните променливи и процедури. Сорсовете изглеждат големи, но полученият код не е обемист. Като правило той е около два пъти по-малък от размера на сорса. Например прозорец, който пита за отговор в стрингова линия заедно с бутони "Да/Не/Помощ" струва като код няколко кб.
Тук е дадено по-детайлно описание на V-асемблера и методиката на производство на програми (компилиране).
По-долният пример е реално работеща програма за избор на цвят в около 200 текстови линии.
Ето една програма COLOR1.RVA - Тя има следния вид /с добавени малко коментари/:
PROGRAM COLOR1 //color1 dialog
STACK 3400                                              //размер на стека
VEL  1                                                  //скорост на изпълнение на програмата
MAIN
jmp  @c_main                                            //прескочи включения код от W.RVA
INCLUDE W                  

CONS                                                    //константи - компилаторът ги замества в кода по-долу
 cmd_ttapp_ok         '0001'
 cmd_ttapp_no         '0012'

VARI                                                    //променливи - всъщност адреси в оперативната памет
 c_ready_state 0

 me_commandcode        0                                //този хедър е по уговорка с О-програмата,
 me_eident             0 _use                           //виж по долу как се оперира с него
 me_x                  0 _use
 me_y                  0 _use

 cline_stt_line          ''

 cline_cmd_num           64                             //Целият хедър (cline) се изпраща към терминала.
 cline_wid               0  _use                        //Терминалът съставя по него видимата цветна контрола   
 cline_id                11 _use
 cline_tp                0 _use
 cline_color             0 _use
 cline_initx             10 _use
 cline_inity             10 _use
 cline_dx                380  _use
 cline_dy                260  _use
 cline_contains          ''

 backline_variable       ''                            //Викащата програма получава тази команда при модален Ок

 itm_command_str        ''                             //команда постъпваща от терминала
 entry_line             ''                             //входна линия - виж по-долу read_entry_line

 object_pid_cmd_num      34                            //един хедър от 4 числа се праща към терминала, за да установи
 this_process_window_id  0                             //дъщерно отношение на този спрямо викащия прозорец.
 obj_process_pid         0
 calling_pid             0

CODE
@c_main
clf  0
cmp  c_ready_state,1                                   //c_ready_state е флаг, че програмата вече е инициализирана
jmf  @c_input_cycle,if_equal                           //if_ константите са известни чрез W.RVA
mov  c_ready_state,1
mov  entry_line,s                                      //при старт програмата получава в регистър S входна линия
jsu  @init_process_ident                               //@init_process_ident е адрес на подпрограма от W.RVA  
msg                                                    //това съобщение е уговорено, но в случая не се обработва
jsu  @asquire_terminal_sizes                           //подпрограма от W.RVA
mov  edit_rect_ident,123                               //edit_rect са позоречни променливи от W.RVA
mov  edit_rect_leadtext,'Цвят'
mov  normal_wdx,400                                    //normal_wdx/y са променливи от W.RVA 
mov  normal_wdy,305
mov  edit_rect_kind,wkind_closeonly                    //тип на прозореца - има значение за поведението в терминала 
jsu  @read_entry_line                                  //прочети входната линия 
jsu  @init_window_process                              //подпрограма от W.RVA 
jsu  @build_window_rect_command                        //подпрограма от W.RVA
jsu  @init_tcp_state                                   //подпрограма от W.RVA
jsu  @send_c_window_to_terminal                        //виж по-долу
jsu  @init_out_pointers                                //подпрограма от W.RVA
jsu  @build_setobjpid_command                          //команда към терминала, че този прозорец е модален 
jsu  @send_regs_to_terminal                            //подпрограма от UTILS.RVA - включено в W.RVA
idl                                                    //край на стартовия участък - остава в бездейно състояние

@c_input_cycle
clf  0
msg                                                    //ето тук се прочита всяко входящо съобщение
jmf  @c_have_msg,if_message_received
idl

@c_have_msg
mov  received_str,s                                   //received_str е от W.RVA
mov  i,w_icptr                                        //w_icptr е от W.RVA
str  soc_preparehjmp                                  //подготовка за скок в диспечера
jmf  @error_bad_command,if_differ                     //при неуспех се връща флаг v1fl_idiff
clf  w_incomming_cm                                   //флаговият регистър трябва да съдържа командата
mov  i,@base_point_c_commands                         //i регистър трябва да съдържа базовия командан адрес
@base_point_c_commands
sys  v1sq_jumptodispatcher                            //скочи на съответната линия по-долу

jmp  @error_bad_command            //icm=0000 error
jmp  @error_bad_command            //icm=0001 resize_terminal_window
jmp  @unfocus_window               //icm=0002
jmp  @focus_this_window            //icm=0003
jmp  @end_this_window              //icm=0004 otoa_die
jmp  @error_bad_command            //icm=0005 renew_tasklist=error
jmp  @move_window                  //icm=0006 move/resize window or change window state
jmp  @error_bad_command            //icm=0007 //file command=error
jmp  @exec_control_command         //icm=0008 //any control command
jmp  @exec_event_command           //icm=0009 //event command
jmp  @error_bad_command            //icm=0010 //tts file

//=============== message routines =========================
@focus_this_window
jsu  @sub_focus_window                              //@sub_focus_window е от W.RVA
jsu  @init_out_pointers                             //от W.RVA
jsu  @build_setobjpid_command                       //по-долу
jsu  @send_regs_to_terminal                         //от W.RVA
idl

@end_this_window
jmp  @end_window                                    //@end_window е от W.RVA

@exec_event_command                                 //тази точка присъствува само по уговорка, не е нужно да работи
jsu  @asquire_mousemove_line
idl

@exec_control_command
jsu  @asquire_input_command                         //получаваме команда
cmp  s,cmd_ttapp_ok                                 //бързите преходи са в началото на входящата команда
jmf  @exit_ok,if_equal
cmp  s,cmd_ttapp_no
jmf  @exit_cancel,if_equal
mov  s,itm_command_str                              //това е текстов тип указание - свободно както е написано в бутона
spo  'OKCOLOR',s
cmp  i,1
jmf  @receive_color,if_equal
jmp  @error_bad_command
idl

//=============== subroutines =========================

@asquire_input_command                              //анализ на входящата команда
mov  s,received_str
mov  d,245.0
mov  i,10
str  soc_getsubstr
mov  itm_command_str,s
mov  s,received_str
mov  d,254.0
mov  i,6
str  soc_getsubstr
ret  

@receive_color                                       //получаваме от терминала нов цвят
mov  i,2
str  soc_wordnum
str  soc_tointeger
mov  cline_color,i
jmp  @exit_ok

@send_c_window_to_terminal                           //изпращане на команда за пълен прозорец към терминала
mov  s,edit_rect_cmd_string                          //edit_rect_cmd_string от W.RVA пази последната команда за прозорец
jsu  @add_a_command                                  //добавяме командата в изходящия TCP-буфер /подпрограма от W.RVA
jsu  @build_colorboxline                             //построй команда за цветна кутийка на терминала
jsu  @add_a_command                                  //добави и нея в буфера
jsu  @send_buffer_to_terminal                        //изпрати всичко от буфера към терминала/подпрограма чрез W.RVA
ret

@asquire_mousemove_line
mov  s,received_str
mov  d,20.0
mov  i,6
str  soc_getsubstr
mov  i,16
mvm  me_commandcode,s
ret

@build_colorboxline                                   //съставяне на команда за цветна контрола към терминала
mov  cline_wid,edit_rect_ident
mov  s,cline_contains
str  soc_getlength
add  i,37
mvm  s,cline_cmd_num,S
mov  cline_stt_line,s
ret

@read_entry_line                                       //подпрограма за четене на входната линия
mov  s,entry_line
mov  i,1                                               //първата дума е номер на викащият процес
str  soc_wordnum
str  soc_tointeger
mov  calling_pid,i

mov  s,entry_line                                      //втората дума е част от обратната команда
mov  i,2
str  soc_wordnum
mov  backline_variable,s

mov  s,entry_line                                      //третата дума е цвета преди старта на тази програма
mov  i,3
str  soc_wordnum
str  soc_tointeger
mov  cline_color,i

mov  s,entry_line                                      //от четвърта дума надясно е известяващо съобщение
mov  i,4
str  soc_strfromw
mov  cline_contains,s
ret

@exit_ok                                               //юзерът е натиснал Enter или бутон Ok
mov  i,cline_color
str  soc_frominteger
add  '0008 0000SETCOLOR ',s
add  s,' '
add  s,backline_variable
add  s,' '
msp  calling_pid                                       //изпращаме съобщение на викащия процес с обратната команда 

@exit_cancel                                           //изход без последствия
mov  s,'0008 0000CHILDEXIT '
msp  calling_pid                                       //изпращаме съобщение на викащия процес
jmp  @end_window                                       //за да прекрати модалното изчакване

mov  s,atoo_close_sender_window                        //изпращаме съобщение на О-програмата
msp  parrent_osid                                      //че работата е приключена.
idl                                                    //О-програмат ще изпрати в отговор съобщение otoa_die 

@build_setobjpid_command                               //при тази команда терминалът свързава този прозорец
mov  this_process_window_id,edit_rect_ident            //и посочения викащ (calling_pid) в модална двойка
mov  obj_process_pid,this_process_pid
mov  i,16
mvm  s,object_pid_cmd_num,S
ret
Задължения и свобода в програмирането
Както става ясно, програмите имат доста ангажименти и това заема една значителна част от кода. Свободата е само където се изследват идващите съобщения и в поредицата на терминалните контроли.

Р.Ж. 11.05.2010

Никак не ми беше лесно да стигна до тук, но резулататите биват. С удоволствие бих съдействувал на всеки интересуващ се. Работя по въпроса асемблиращата част да бъде изяснена и изгладена. Всъщност по-голямата част от RVA-програмите вече ги написах и стабилизирах. Надявам да ги променям все по-рядко. Но засега това е начинът за уреждане на прозорци в терминала и за други преки действия.


Начална страница за V-машината
roncho.net