From 41ff458cd4916fa2396b57b1915f0af1850842d4 Mon Sep 17 00:00:00 2001 From: Tolik <85737314+Tolik-Trek@users.noreply.github.com> Date: Thu, 16 Jul 2026 22:06:01 +1000 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=BA=D0=B0=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82,=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B4=D0=BE=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20BigDir.=20=D0=97=D0=B0=D1=82=D0=B0=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=B7=20Master:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=B1=D0=B0=D0=B3=20=D1=81=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=BF=D1=83=D1=82=D1=8F=D0=BC=D0=B8.=20thx=20to?= =?UTF-8?q?=20@witchcraft2001=20IF,=20GOTO,=20GOSUB/RETURN=20in=20BAT=20fi?= =?UTF-8?q?les.=20=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20CLP=20-bug=20?= =?UTF-8?q?=D1=81=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=BE=D0=BC=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=B2=20BAT=20-bug=20M=5FINT:?= =?UTF-8?q?=20RFI=20is=20CH-A=20ONLY=20(per=20Z80=20SIO=20spec)=20-bug=20K?= =?UTF-8?q?EYINTER.ASM:=20russian=20chars=20fix=20Num=20Lock=20numbers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DSS/API/Ex_Path.asm | 7 +- DSS/API/Execute.ASM | 151 +++--- DSS/API/PutChar.asm | 4 - DSS/KEYINTER.ASM | 312 +++++++---- DSS/KNOWN.BUG | 101 +++- DSS/defines.inc | 3 +- DSS/drivers/DRV_TO_SYS_ERRORS.ASM | 76 +++ SHELL/BATCH.ASM | 44 +- SHELL/Commands/BREAK.ASM | 11 +- SHELL/Commands/GOTO.ASM | 277 ++++++++++ SHELL/Commands/IF.ASM | 241 +++++++++ SHELL/EDLINE.ASM | 36 +- SHELL/EXEC.ASM | 4 +- SHELL/Messages/main_txt.asm | 6 + SHELL/SHELL.ASM | 22 +- SHELL/structures.inc | 2 +- Shared_Includes | 2 +- keys.md | 828 ++++++++++++++++++++++++++++++ 18 files changed, 1913 insertions(+), 214 deletions(-) create mode 100644 DSS/drivers/DRV_TO_SYS_ERRORS.ASM create mode 100644 SHELL/Commands/GOTO.ASM create mode 100644 SHELL/Commands/IF.ASM create mode 100644 keys.md diff --git a/DSS/API/Ex_Path.asm b/DSS/API/Ex_Path.asm index 71142b5..6c3b554 100644 --- a/DSS/API/Ex_Path.asm +++ b/DSS/API/Ex_Path.asm @@ -155,6 +155,7 @@ EX_PATH: EXX .NAME_YEP: LD A,2 CP C JR Z,.NOFNAME + ; PUSH HL LD HL,TMPBUF LD DE,(NM_NAME) ; 䠩 @@ -200,7 +201,8 @@ EX_PATH: EXX PUSH HL LD HL,TMPBUF LD DE,(NM_DRIVE) - LD B,0 + ; A=0 + LD B,A LDIR POP HL EX AF,AF' @@ -219,7 +221,8 @@ EX_PATH: EXX EX DE,HL LD HL,TMPBUF ; 12 ஡ POP BC - LD B,0 + ; A=0 + LD B,A LDIR POP HL EX AF,AF' diff --git a/DSS/API/Execute.ASM b/DSS/API/Execute.ASM index 9583540..ad9cf3a 100644 --- a/DSS/API/Execute.ASM +++ b/DSS/API/Execute.ASM @@ -336,7 +336,7 @@ _TST_PROC: CALL GETMEM ;LD DE,CORE_BUFFERS.BUFFER+1 LD DE,CORE_BUFFERS.BUFFER_CLP + 1 CALL SCOPYS - LD A,#80 ;!HARDCODE cmd line size + LD A,low CLP_Buffer SUB B LD (CORE_BUFFERS.BUFFER_CLP),A ; @@ -378,15 +378,14 @@ _TST_PROC_2: ; ! ⥪ 㫥 ࠭! BIOS DSS-MAIN 뢠 LD SP,CORE_BUFFERS.EXEBUFF + _sEXE_HEADER CALL M_PSP - ; LD SP,(CORE_BUFFERS.EXEBUFF.SP_REG) - LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) - LD DE,#0080 ;!HARDCODE CLP_Buffer - XOR A - SBC HL,DE - EX DE,HL - LD XH,D - LD XL,E + ;LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) + ;LD DE,#0080 ;!HARDCODE CLP_Buffer + ;XOR A + ;SBC HL,DE + ;EX DE,HL + ;LD XH,D + ;LD XL,E LD DE,RETFAR ; / " 襭 " PUSH DE ; Current Dir 15/10/23 @@ -400,23 +399,29 @@ _TST_PROC_2: LD HL,CORE_BUFFERS.CurrentPath .set_path: CALL CHDIR_FN POP IX + ; ஢ઠ ९ CLP + LD A,(CORE_BUFFERS.BUFFER_CLP) + LD B,DSS_Error.sys.ENV_ITEM_OVERFLOW + INC A + JP Z,LEAVE ; - EI LD HL,(CORE_BUFFERS.EXEBUFF.PC_REG) + EI JP (HL) ;----------------------------------------------------------------------- ; ! 뢠 ⥪ 㫥 ࠭! M_PSP: LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) - DEC H + DEC H ;!FIXIT 256 (CLP buffer + data) LD_ADDR LD D,H LD E,L INC DE - LD BC,#00FF ;!FIXIT + LD BC,#00FF ;!FIXIT ࠧ CLP LD (HL),B LDIR EX DE,HL DEC H - LD DE,#0080 ;!FIXIT + ;LD DE,#0080 ;!FIXIT + LD DE,#0003 ;!FIXIT ADD HL,DE EX DE,HL LD XH,D @@ -427,67 +432,93 @@ M_PSP: LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) INC C LDIR EX DE,HL ;R06 - LD (HL),B + ;LD (HL),B LD A,(TASK) LD (IX-1),A LD A,(EXE_MEM) LD (IX-2),A LD A,(EXE_FM) LD (IX-3),A - ;R05 + ; ⠪ ᪨ ᫮, 0 ᫥ ࠬ஢ ப INC HL - LD (HL),B + ;LD (HL),B INC HL - ;!FIXIT ⠭ ࠢ ⠫ - CALL CURDISK - ADD A,'A' - LD (HL),A - INC HL - LD A,':' - LD (HL),A - INC HL - PUSH HL - CALL CURRDIR - ; - POP HL - XOR A - LD BC,#0100 ;!FIXIT ਢ離 CurrentDirectory.DEPTH - CPIR ;!FIXIT ஢ન 室 BC=0 - DEC HL - DEC HL - LD A,'\' ; - CP (HL) - INC HL - JR Z,.YP_ESLA - ; - LD (HL),A - INC HL -.YP_ESLA: EX DE,HL - LD HL,CORE_BUFFERS.TMPNAME -.loop: LD A,(HL) - LDI - CP ' '+1 - JR NC,.loop - ; - DEC DE - XOR A - LD (DE),A - LD (APPINFO.LAST_PSP_PTR),IX + ;!FIXIT ⠭ ࠢ ⠫ + CALL CURDISK + ADD A,'A' + LD (HL),A + INC HL + LD A,':' + LD (HL),A + INC HL + PUSH HL + ;!FIXIT CURRDIR ⤥ ஢ HL 室 ࠭ + LD HL,CORE_BUFFERS.BUFFER_CLP + CALL CURRDIR ; + POP DE + LD HL,(CORE_BUFFERS.EXEBUFF.LD_ADDR) + SBC HL,DE + ;!FIXIT ࠡ Z CF + LD B,H + LD C,L + ;EX DE,HL + JR Z,.error_CLP + JR C,.error_CLP + ; hl - CLP ਫ + ; bc - ⢮ ⠢襣 + ; + LD HL,CORE_BUFFERS.BUFFER_CLP +.copy_loop: CALL .copyAndCheck + JP PO,.error_CLP + ; + EX DE,HL + DEC HL + LD A,'\' ; + LD (HL),A + INC HL +.YP_ESLA: PUSH HL + PUSH BC + LD HL,CORE_BUFFERS.MASKARE + LD DE,CORE_BUFFERS.TMPNAME + CALL GetName + POP BC + POP DE + LD HL,CORE_BUFFERS.TMPNAME + ; + CALL .copyAndCheck + LD (APPINFO.LAST_PSP_PTR),IX ; !FIXIT ᤥ १ ⥪ ६? RET - ; -SCOPYS: LD BC,#80*256 + ' '+1 ;!HARDCODE cmd line size + ; +.copyAndCheck: LD A,(HL) + AND A + LDI + RET Z + JP PE,.copyAndCheck + ; ᫨ , 墠⨫ 㦭 뤠 訡 + POP HL ; ᭨ + ; +.error_CLP: LD A,#FF + LD (CORE_BUFFERS.BUFFER_CLP),A + RET + +SCOPYS: LD BC,256*(low CLP_Buffer) + ' '+1 .loop: LD A,(HL) CP C JR C,.copy + ; INC HL DJNZ .loop XOR A LD (DE),A - LD B,#80 + LD B,low CLP_Buffer RET ; -.copy: LD BC,#80*256 + ' ' ;!HARDCODE cmd line size +.copy: LD BC,256*(low CLP_Buffer) + ' ' + AND A + LD (DE),A + RET Z + ; .loop2: LD A,(HL) LD (DE),A INC HL @@ -495,7 +526,9 @@ SCOPYS: LD BC,#80*256 + ' '+1 ;!HARDCODE cmd line size CP C RET C DJNZ .loop2 - RET + ; 訡 - ᫨誮 ப ࠬ஢ + INC B + RET ;--------------------------------------------------------------------- ENVPATH: DB "PATH=",0 EXE_EXT: DB "EXE" @@ -563,9 +596,11 @@ LEAVE: ;LD A,R EX DE,HL LD A,(ErrorLevel) ;R12 - CP DSS_Error.sys.UNEXPECTED_APP_TRMN + CP DSS_Error.sys.UNEXPECTED_APP_TRMN ; #27 0010 0111 6 JR Z,.error_exit - CP DSS_Error.sys.USER_ABORT + CP DSS_Error.sys.USER_ABORT ; #25 0010 0101 4 + JR Z,.error_exit + CP DSS_Error.sys.ENV_ITEM_OVERFLOW ; #21 0010 0001 0 JR NZ,.norm_exit .error_exit: SCF JP (HL) diff --git a/DSS/API/PutChar.asm b/DSS/API/PutChar.asm index 74be50b..eeaace9 100644 --- a/DSS/API/PutChar.asm +++ b/DSS/API/PutChar.asm @@ -122,8 +122,4 @@ PUTCHAR: LD C,0 ; POP HL RET - -; .NO_SCROLL: - -; .CHAR: DZ "X" ;/////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/DSS/KEYINTER.ASM b/DSS/KEYINTER.ASM index 9149bf2..008bd11 100644 --- a/DSS/KEYINTER.ASM +++ b/DSS/KEYINTER.ASM @@ -1,4 +1,3 @@ - ; MODULE KEYINTER ;[BEGIN] ;//MODULE: KEYINTER Keyboard Scan Codes: Set 2 @@ -289,7 +288,7 @@ cursor_interrupt: LD A,(Cursor_Off.Flag) OR A RET Z -.timer+1: LD A,1 ; 㧠 +.timer+1: LD A,1 ; 㧠 DEC A CALL Z,Cursor LD (.timer),A @@ -301,27 +300,27 @@ SETUP_CURSORS: .buffer.size EQU 2048 ; in a,(SLOT3) - push af ; . - ld a,((#FF00 & BANKTBL) + TXTPAGE) ; 2- . ࠭ . + push af ; . + ld a,(BANKTBL+TXTPAGE) ; 2- . ࠭ . out (SLOT3),a ; ; . . -; ld de,.buffer ;!HARDCODE 2048 +; ld de,.buffer ;!HARDCODE 2048 ; push de -; ld c,BIOS.WIN_GET_ZG ; . +; ld c,BIOS.WIN_GET_ZG ; . ; rst ToBIOS ; ; #FF 2 -; ld hl,.buffer+(2048-(2*256)) ;!HARDCODE ᫥ 512 +; ld hl,.buffer+(2048-(2*256)) ;!HARDCODE ᫥ 512 ; ld bc,511 -; ld a,CURSOR_ZG; ; . "窠" +; ld a,CURSOR_ZG; ; . "窠" ; call .fill_data_font ; pop hl ; ; ⠫ 6 ( ) -; ld bc,2048-513 ;!HARDCODE -; ld a,INS_CUR_ZG ; . "" +; ld bc,2048-513 ;!HARDCODE +; ld a,INS_CUR_ZG ; . "" ; call .fill_data_font ; pop af -; out (SLOT3),a ; . +; out (SLOT3),a ; . ; ret ; ; ன . ॣ ; ; 室: a= . @@ -333,8 +332,8 @@ SETUP_CURSORS: ; ld (hl),#FF ; inc de ; ldir -; .set: ld de,.buffer ; . -; ld c,BIOS.WIN_SET_ZG ; . . +; .set: ld de,.buffer ; . +; ld c,BIOS.WIN_SET_ZG ; . . ; jp ToBIOS ; ; [ ] 31/03/2025 @@ -551,9 +550,18 @@ KEYSCAN: LD IX,KEYFLAG ; BIT FLAG_F0,(IX+KEYFLG) JR NZ,UN_KEY - ; + ;[ ]18/06/2026 ignore AT fake-shift (E0-12/E0-59) around extended keys + IF ENABLED_KEYBOARD_CONTROL + CALL FAKE_SHIFT + JR NC,.real_make + RES FLAG_E0,(IX+KEYFLG) + JP .RESCAN +.real_make: + ENDIF LD L,A CALL XLAT + CALL NUMPAD_KEY ; [ ]18/06/2026 keypad digit? CF=1 if emitted + JP C,.RESCAN ; emitted -> drain rest of SIO FIFO CALL SHIFTS RES FLAG_E0,(IX+KEYFLG) IF USE_E1_SCANCODE @@ -656,6 +664,13 @@ KEYSCAN: LD IX,KEYFLAG ; RET ; ELSE UN_KEY: RES FLAG_F0,(IX+KEYFLG) + IF ENABLED_KEYBOARD_CONTROL + CALL FAKE_SHIFT + JR NC,.uk_real + RES FLAG_E0,(IX+KEYFLG) + RET +.uk_real: + ENDIF LD L,A CALL XLAT CALL UNSHIFT @@ -665,6 +680,76 @@ UN_KEY: RES FLAG_F0,(IX+KEYFLG) RET ; ENDIF ; +;-------------------------------------------------------------------------------- +;[ ] 18/06/2026 NUMPAD: keypad key. DIGIT if (NumLock XOR Shift), else clean NAVIGATION. +; in : L = AT positional code (from XLAT), IX = KEYFLAG, FLAG_E0 still valid +; out: CF=1 -> keypad key fully handled and pushed via PUTSYM (caller drains FIFO) +; out: CF=0 -> not a keypad key; caller continues normal path (L preserved) +; NB: navigation is emitted as D=poscode (bit7=0), E=0 so EvComComb sees Del/arrows, +; NOT #XX|#80 which the editor reads as the Ctrl+key variant. +NUMPAD_KEY: BIT FLAG_E0,(IX+KEYFLG) ; E0 => dedicated Ins/Del/nav key -> normal path + JR NZ,.skip + LD A,L ; positional code + CP #4F ; keypad block = pos #4F..#59 (Del/. Ins/0 .. PgUp/9) + JR C,.skip ; below (keypad + - * /) -> normal path + CP #5A + JR NC,.skip ; above -> normal path + ; + ; mode: DIGIT if (NumLock XOR Shift), else NAVIGATION + LD A,(KEYCTRL) + AND 1<0 if Shift held + BIT NUM_L,(IX+K_LOCK) ; Z=0 if NumLock on + JR Z,.nl_off + AND A ; NumLock ON : digit unless Shift + JR NZ,.nav ; Shift -> navigation + JR .digit +.nl_off: AND A ; NumLock OFF: navigation unless Shift + JR Z,.nav ; no Shift -> navigation + ; +.digit: LD A,L + CP #4F ; keypad '.' + JR Z,.dot + SUB #50 ; #50..#59 -> 0..9 + ADD A,'0' ; -> '0'..'9' + LD E,A + LD A,L + OR #80 ; D = poscode | keystroke flag + LD D,A + JR .emit +.dot: LD E,'.' + LD D,#4F | #80 + JR .emit + ; +.nav: LD D,L ; clean position code, bit7=0 + LD E,0 ; ASCII=0 => navigation event (EvComComb) + LD A,L + CP #50 ; Ins toggles insert mode (like dedicated Ins) + CALL Z,INS_X +.emit: LD BC,(KEYFLAG) ; C=KEYFLAG B=KEYCTRL snapshot + CALL PUTSYM + SCF ; CF=1 -> handled + RET +.skip: OR A ; CF=0 -> not handled, normal path + RET +;-------------------------------------------------------------------------------- +;[ ]18/06/2026 AT fake-shift detector: E0 12 / E0 59 sent around extended keys +; when NumLock/Shift is active. MUST be ignored, else it sets L_SHIFT and the +; cursor key that follows gets bit7 set in D -> editor stops recognising it. +; in : A=scancode, IX=KEYFLAG, FLAG_E0 reflects prefix ; out: CF=1 if fake-shift + IF ENABLED_KEYBOARD_CONTROL +FAKE_SHIFT: BIT FLAG_E0,(IX+KEYFLG) + JR Z,.nofake + CP #12 ; fake Left Shift + JR Z,.isfake + CP #59 ; fake Right Shift + JR Z,.isfake +.nofake: OR A ; CF=0 -> real key + RET +.isfake: SCF ; CF=1 -> ignore it + RET + ENDIF +;-------------------------------------------------------------------------------- +; CAPS_X: LD A,(KEYFLAG) XOR 1< Error! This table has wrong size!!!' -SHIFTAB DB "~",Esc,"!","@","#","$","%","^","&","*","(",")","_","+",Bcs - DB Tab,"Q","W","E","R","T","Y","U","I","O","P","{","}" - DB Cps,"A","S","D","F","G","H","J","K","L",":",#22,Ent - DB #00,"Z","X","C","V","B","N","M","<",">","?",#00,"|" - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +SHIFT_ENG: DB "~",Esc,"!","@","#","$","%","^","&","*","(",")","_","+",Bcs + DB Tab,"Q","W","E","R","T","Y","U","I","O","P","{","}" + DB Cps,"A","S","D","F","G","H","J","K","L",":",#22,Ent + DB #00,"Z","X","C","V","B","N","M","<",">","?",#00,"|" + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-SHIFT_ENG : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' -CAPSTAB DB "`",Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs - DB Tab,"Q","W","E","R","T","Y","U","I","O","P","[","]" - DB Cps,"A","S","D","F","G","H","J","K","L",";","'",Ent - DB #00,"Z","X","C","V","B","N","M",#2C,".","/",#00,#5C - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +CAPS_ENG: DB "`",Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs + DB Tab,"Q","W","E","R","T","Y","U","I","O","P","[","]" + DB Cps,"A","S","D","F","G","H","J","K","L",";","'",Ent + DB #00,"Z","X","C","V","B","N","M",",",".","/",#00,'\' ; + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-CAPS_ENG : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' -SHF2TAB DB "~",Esc,"!","@","#","$","%","^","&","*","(",")","_","+",Bcs - DB Tab,"q","w","e","r","t","y","u","i","o","p","{","}" - DB Cps,"a","s","d","f","g","h","j","k","l",":",#22,Ent - DB #00,"z","x","c","v","b","n","m","<",">","?",#00,"|" - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +CAPS_SHIFT_ENG: DB "~",Esc,"!","@","#","$","%","^","&","*","(",")","_","+",Bcs + DB Tab,"q","w","e","r","t","y","u","i","o","p","{","}" + DB Cps,"a","s","d","f","g","h","j","k","l",":",#22,Ent + DB #00,"z","x","c","v","b","n","m","<",">","?",#00,"|" + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-CAPS_SHIFT_ENG : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' ;Standart Russian tables -NORMRUS DB #F1,Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs - DB Tab,#A9,#E6,#E3,#AA,#A5,#AD,#A3,#E8,#E9,#A7,#E5,#EA - DB Cps,#E4,#EB,#A2,#A0,#AF,#E0,#AE,#AB,#A4,#A6,#ED,Ent - DB #00,#EF,#E7,#E1,#AC,#A8,#E2,#EC,#A1,#EE,".",#00,#5C - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +RUSSIAN: DB #F1,Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs + DB Tab,#A9,#E6,#E3,#AA,#A5,#AD,#A3,#E8,#E9,#A7,#E5,#EA + DB Cps,#E4,#EB,#A2,#A0,#AF,#E0,#AE,#AB,#A4,#A6,#ED,Ent + DB #00,#EF,#E7,#E1,#AC,#A8,#E2,#EC,#A1,#EE,".",#00,'\' ; + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-RUSSIAN : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' -SHIFRUS DB #F0,Esc,"!",#22,"#","$",":",#2C,".",";","?","%","_","+",Bcs - DB Tab,#89,#96,#93,#8A,#85,#8D,#83,#98,#99,#87,#95,#9A - DB Cps,#94,#9B,#82,#80,#8F,#90,#8E,#8B,#84,#86,#9D,Ent - DB #00,#9F,#97,#91,#8C,#88,#92,#9C,#81,#9E,#2C,#00,"|" - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +SHIFT_RUS: DB #F0,Esc,"!",'"',"#",";","%",":","?","*","(",")","_","+",Bcs + DB Tab,#89,#96,#93,#8A,#85,#8D,#83,#98,#99,#87,#95,#9A + DB Cps,#94,#9B,#82,#80,#8F,#90,#8E,#8B,#84,#86,#9D,Ent + DB #00,#9F,#97,#91,#8C,#88,#92,#9C,#81,#9E,",",#00,"/" + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-SHIFT_RUS : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' -CAPSRUS DB #F0,Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs - DB Tab,#89,#96,#93,#8A,#85,#8D,#83,#98,#99,#87,#95,#9A - DB Cps,#94,#9B,#82,#80,#8F,#90,#8E,#8B,#84,#86,#9D,Ent - DB #00,#9F,#97,#91,#8C,#88,#92,#9C,#81,#9E,".",#00,#5C - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +CAPS_RUS: DB #F0,Esc,"1","2","3","4","5","6","7","8","9","0","-","=",Bcs + DB Tab,#89,#96,#93,#8A,#85,#8D,#83,#98,#99,#87,#95,#9A + DB Cps,#94,#9B,#82,#80,#8F,#90,#8E,#8B,#84,#86,#9D,Ent + DB #00,#9F,#97,#91,#8C,#88,#92,#9C,#81,#9E,".",#00,'\' ; + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-CAPS_RUS : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' -SHF2RUS DB #F1,Esc,"!",#22,"#","$",":",#2C,".",";","?","%","_","+",Bcs - DB Tab,#A9,#E6,#E3,#AA,#A5,#AD,#A3,#E8,#E9,#A7,#E5,#EA - DB Cps,#E4,#EB,#A2,#A0,#AF,#E0,#AE,#AB,#A4,#A6,#ED,Ent - DB #00,#EF,#E7,#E1,#AC,#A8,#E2,#EC,#A1,#EE,#2C,#00,"|" - DB #00,#00,Spc,#00,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 - DB #00,#00,#00,"/","*","-","+",Ent,#00 - DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +CAPS_SHIFT_RUS: DB #F1,Esc,"!",'"',"#",";","%",":","?","*","(",")","_","+",Bcs + DB Tab,#A9,#E6,#E3,#AA,#A5,#AD,#A3,#E8,#E9,#A7,#E5,#EA + DB Cps,#E4,#EB,#A2,#A0,#AF,#E0,#AE,#AB,#A4,#A6,#ED,Ent + DB #00,#EF,#E7,#E1,#AC,#A8,#E2,#EC,#A1,#EE,",",#00,"/" + DB #00,#00," ",#00,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00,#00 + DB #00,#00,#00,"/","*","-","+",Ent,#00 + DB #00,#00,#00,#00,#00,#00,#00,#00,#00,#00 +.Size EQU $-CAPS_SHIFT_RUS : ASSERT .Size = Size, '-> Error! This table has wrong size!!!' + ENDMODULE ; ASCII_TABLES ;================================ - ;//MODULE: KEYINTER ;[END] ; ENDMODULE \ No newline at end of file diff --git a/DSS/KNOWN.BUG b/DSS/KNOWN.BUG index e5f3ea4..f944d5e 100644 --- a/DSS/KNOWN.BUG +++ b/DSS/KNOWN.BUG @@ -7,7 +7,106 @@ FIXED: + 訡 ᬮ ⠫ 㭪 ⠭ ਡ⮢ ய᪠ ⥬ 䠩. / SEARCH MASK=#23 -- ஢ 訡 ⥬ ⥩ FAT/DIR, ࠡ 訡 write-protect, ⠪ ⪥ ⠫ . 訡 file not found ⠪ ࠧ ᫥ ᮧ ⥬ 뢠 䠩. +- ஢ 訡 ⥬ ⥩ FAT/DIR, ࠡ 訡 write-protect, + ⠪ ⪥ ⠫ . 訡 file not found + ⠪ ࠧ ᫥ ᮧ ⥬ 뢠 䠩. - 訡 ࠧ ⨬ 䠩, ᫨ ⮨ "." ⠪ ࠧ㬥 ஡ 窠 ஡. +======================================================= AI ======================================================= +1.1. CREATE (Create.asm) ? ⥢ ⠫ ᡮ + - ᫥ ᮧ ⠫ (WRT_HND, SAVEDIR) 뢠 + OPEN_FN.FILE. ᫨ ⨥ 䠩 㤠 (ਬ, + ᢮ ஢, 訡 ᪠), ⠫ + 䠩 㫥 ࠧ஬ . ᫥騥 + ⪨ ᮧ 䠩 ⥬ ਢ 訡 + FILE_EXISTS, 䠩 䠪᪨ . + - ࠢ: ᫨ OPEN_FN.FILE 頥 訡, 㦭 㤠 + ⮫쪮 ᮧ 맮 DELETE_REC_FAT. + +1.2. ATTRIB (Attribute.asm) ? ४ ० ਡ⮢ + - ⠭ ਡ (B=1) 뢠 .OPENATR, + 뢠 䠩 ० 㬮砭 (A=0 ? ⥭/). + ᫨ 䠩 㦥 㣨 ᮬ , + 訡 ஢. ஢ + ⥪騩 ० 㯠. + - ࠢ: 뢠 䠩 ० 0 (⥭/) ⮫쪮 + ᫨ ࠭; 室 ᯮ짮 + ⤥ ஢. + +1.3. LEAV (Execute.ASM) ? ⢨ ஢ન SP EXE- + - ᪥ EXE-䠩 祭 SP_REG 㦠 + SP ஢ப. ४⭮ 祭 (ਬ, 0x0000) + ਢ ⥪. ⥫쭮 ஢, + SP ⨬ , + ⠭ ᭮ 祭 訡. + +1.4. Read (Read.asm) ? ᡠ஢ ⥪ 訡 + ⢥ত ࢮ砫쭮 ? ᫥ + PUSH (BC,HL,DE) 믮 POP (HL,HL,BC), ⥪ + . DE ᯮ祭, ⨬ + ᮣ襭. ஡ ⥪ . + + , ⮬ 㫥 㣮 ⥭樠 䥪: + .ROV1 ᯥ譮 ⥭ ᯮ EXX 䨪 ⥪ + ୠ⨢ ॣ, ਢ ⠭, ᫨ + - ࠭ ॣ. ⥫쭮 + ஢ ᯮ짮 EXX ࠡ稪 訡. + +1.5. ENV_EX (Environ.asm) ? ஢ 訡 ९ + - 㭪 ENV_EX ⠭ CF=1, ᫨ 室 ப + 㦥 ᫨誮 , 뢠騥 楤 GETENV + SETENV 䫠. ६ ᮧ + ⠥ १ 祭 ।०, + ਢ 㤭㫮 訡 䨣樨. + - ࠢ: ஢ CF ᫥ 맮 ENV_EX + 訡 ENV_ITEM_OVERFLOW. + +1.6. diskINF GetFreeSpace (diskINF.asm) ? ᠭ + ०񭭮 FAT + - ᢮ ஢ ஢ READ_FROM_FAT, + ࠭稢 ᫮ 権. ᫨ 楯窠 ஢ + ⠡ FAT ᯮ祭, 横 ᪮. + - ࠢ: 稪 権, ࠢ 饬 + ஢, ᯮ짮 ⠩-. + + +================================================================ +2. +================================================================ + +2.2. ஢ ⠫ + - 㭪樨 (OPEN, DELETE, RENAME) ⭮ 㦠 + ⠫ १ LOADDIR. ஢, + ᮢ ⥪騩 ⠫ FM_BUF[0], + ୮ ⥭. + + +2.5. ⨬ WRITE_FAT_TABLE + - FAT ஢ 祭 CacheUpdated, + 뢠 ⮫쪮 . + ᫥⥫쭮 ஢ 뢠 + WRITE_FAT_TABLE. ⫮ 䠩 + . + +2.6. ୮ ⥭ BPB + - OPENDSK ࠧ 뢠 RD_BPB, ᫨ 㦥 + ⥬ ࠬࠬ. FS_Buffer, + ᨣ饥, BPB ४⥭, ய᪠ ୮ + ⥭ ⢨ ᬥ ᪠. + +================================================================ +3. +================================================================ + +3.3. ⢨ ஢ப ࠭ ஢ + - 拉 楤 (ਬ, EXEC Build PSP, Environ) ᯮ + 䨪஢ ⠭ ࠧ (#100, #80). ⥫쭮 + ஢, 室 ࠭ 뤥 . + +3.4. ॢ訩 + - 䠩 ஢ ॠ樨 + (ਬ, ECHOKEY ஬, PUTCHAR). + 㤠 㬥 室 ⥪ ⠥. + +================================================================ \ No newline at end of file diff --git a/DSS/defines.inc b/DSS/defines.inc index 377602f..51a98f3 100644 --- a/DSS/defines.inc +++ b/DSS/defines.inc @@ -44,7 +44,8 @@ MOUSE_BAUD: DEFINE CHANGE_LANG_CTRL_SHIFT 1 ; [x] 0: Ctrl + Space, 1: Ctrl + Shift. DEFINE BREAK_PROCESS_CODE #AC00 ; CTRL+C DEFINE USE_E1_SCANCODE 0 - ;DEFINE CLASSIC_CURSOR 0 + DEFINE ENABLED_KEYBOARD_CONTROL 0 ; 1=host can talk to kbd (0xED LEDs) => handle AT fake-shift (E0 12/59). +; ; HW is receive-only -> keep 0 ;; diff --git a/DSS/drivers/DRV_TO_SYS_ERRORS.ASM b/DSS/drivers/DRV_TO_SYS_ERRORS.ASM new file mode 100644 index 0000000..437136e --- /dev/null +++ b/DSS/drivers/DRV_TO_SYS_ERRORS.ASM @@ -0,0 +1,76 @@ +; 19/04/2025 ⮯ॢ 訡 DRV/BIOS SYS +DRV_ERROR_TO_SYS: + RET NC + RLA + JR NC,.no_correction + ; + PUSH HL + PUSH AF + ; + SRL A + CP .Size + LD HL,.TABLE + ADD A,L + JR NC,.no_inc + ; + INC H +.no_inc: LD L,A + LD L,(HL) + POP AF + LD A,L + POP HL + RET + ; +.no_correction: RRA + RET + +.TABLE: DB DSS_Error.sys.Unknown_Error ;BIOS.Error.NoErrors ; 0 + DB DSS_Error.sys.INVALID_FUNCTION ;BIOS.Error.InvalidSubFunction ; 1 + DB DSS_Error.sys.INVALID_DRIVE ;BIOS.Error.BadNumber ; 2 + DB DSS_Error.sys.UNKNOWN_FORMAT ;BIOS.Error.UnknownDevice ; 3 + DB DSS_Error.sys.NOT_READY ;BIOS.Error.NotReady ; 4 + DB DSS_Error.sys.SEEK_ERROR ;BIOS.Error.Seek ; 5 + DB DSS_Error.sys.SECTOR_NOT_FOUND ;BIOS.Error.SectorNotFound ; 6 + DB DSS_Error.sys.CRC_ERROR ;BIOS.Error.CRC ; 7 + DB DSS_Error.sys.WRITE_PROTECT ;BIOS.Error.WriteProtect ; 8 + DB DSS_Error.sys.READ_ERROR ;BIOS.Error.Read ; 9 + DB DSS_Error.sys.WRITE_ERROR ;BIOS.Error.Write ; 10 + DB DSS_Error.sys.DRIVE_FAILURE ;BIOS.Error.Failure ; 11 + DB DSS_Error.sys.BUSY_NO_MEDIA ;BIOS.Error.Busy ; 12 + DB DSS_Error.sys.Unknown_Error ;#8D ; 13 + DB DSS_Error.sys.Unknown_Error ;#8E ; 14 + DB DSS_Error.sys.Unknown_Error ;#8F ; 15 + DB DSS_Error.sys.Unknown_Error ;#90 ; 16 + DB DSS_Error.sys.Unknown_Error ;#91 ; 17 + DB DSS_Error.sys.Unknown_Error ;#92 ; 18 + DB DSS_Error.sys.Unknown_Error ;#93 ; 19 + DB DSS_Error.sys.Unknown_Error ;#94 ; 20 + DB DSS_Error.sys.Unknown_Error ;#95 ; 21 + DB DSS_Error.sys.Unknown_Error ;#96 ; 22 + DB DSS_Error.sys.Unknown_Error ;#97 ; 23 + DB DSS_Error.sys.Unknown_Error ;#98 ; 24 + DB DSS_Error.sys.Unknown_Error ;#99 ; 25 + DB DSS_Error.sys.Unknown_Error ;#9A ; 26 + DB DSS_Error.sys.Unknown_Error ;#9B ; 27 + DB DSS_Error.sys.Unknown_Error ;#9C ; 28 + DB DSS_Error.sys.Unknown_Error ;#9D ; 29 + DB DSS_Error.sys.Unknown_Error ;#9E ; 30 + DB DSS_Error.sys.NOT_SUPPORTED ;BIOS.Error.NotSupported ; 31 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI.NoSence ; 32 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI.RecoveredError; 33 + DB DSS_Error.sys.NOT_READY ;BIOS.Error.ATAPI.NotReady ; 34 + DB DSS_Error.sys.BUSY_NO_MEDIA ;BIOS.Error.ATAPI.MediumError ; 35 + DB DSS_Error.sys.DRIVE_FAILURE ;BIOS.Error.ATAPI.HardwareError ; 36 + DB DSS_Error.sys.INVALID_ACCESS ;BIOS.Error.ATAPI.IllegalRequest; 37 + DB DSS_Error.sys.MEDIA_CHANGED ;BIOS.Error.ATAPI.UnitAttention ; 38 + DB DSS_Error.sys.ACCESS_DENIED ;BIOS.Error.ATAPI.DataProtect ; 39 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 40 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 41 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 42 + DB DSS_Error.sys.NOT_READY ;BIOS.Error.ATAPI.AbortedCommand; 43 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 44 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 45 + DB DSS_Error.sys.WRITE_ERROR ;BIOS.Error.ATAPI.Miscompare ; 46 + DB DSS_Error.sys.Unknown_Error ;BIOS.Error.ATAPI; ; 47 + DB DSS_Error.sys.NOT_READY ;BIOS.Error.ATAPI.TimeOut ; 48 +.Size EQU .TABLE - $ \ No newline at end of file diff --git a/SHELL/BATCH.ASM b/SHELL/BATCH.ASM index c59c74a..1572683 100644 --- a/SHELL/BATCH.ASM +++ b/SHELL/BATCH.ASM @@ -42,7 +42,7 @@ MAKE_BATCH_PRM_ARRAY: ret z cp " " jr z,.loop - cp 9 ; Tab + cp "\t" ; Tab jr z,.loop ex de,hl ld (hl),e @@ -231,9 +231,11 @@ MOVWORD: ld b,a .loop: ld a,(hl) ld (de),a + cp "\t" ; TAB - in-line blank, keep it (MS-DOS bat) + jr z,.cont cp " " - jr c,.loop_ - inc hl + jr c,.loop_ ; <0x20 (CR/LF) -> end of line +.cont: inc hl inc de djnz .loop scf @@ -281,6 +283,8 @@ CMDMODE: ;ld (D96A6),a ; (inline.asm) call EVALCMD ; (batch.asm) RET C + call BAT_CHECK_LABEL ; GOTO labels / search + RET C ;ld ix,T96AC ; 㦭?? ਫ (inline.asm) ;ld hl,T96AE ;;256 (inline.asm) ld hl,Buffers.input_line.Path @@ -323,8 +327,10 @@ CMDMODE: ld b,a inc hl ;+5 push bc - ld c,BIOS.LP_PRINT_LINE2 ; 뢮 ப ਡ⮢ - RST ToBIOS + LD C,Dss.PChars + RST ToDSS + ;ld c,BIOS.LP_PRINT_LINE2 ; 뢮 ப ਡ⮢ + ;RST ToBIOS pop bc ; b= ப ld a,(width_inpline) ; ਭ (76..48) sub b @@ -364,8 +370,10 @@ CMDMODE: ;ld hl,Buffers.work.buffer+256;; .A826C: ld a,(hl) cp " " + jr z,.A826W + cp "\t" jr nz,.A8276 - inc hl +.A826W: inc hl dec c jr nz,.A826C ret @@ -377,10 +385,17 @@ CMDMODE: sbc hl,bc ld a,c ex af,af' - ld a," " - cpir - jr nz,.A8286 - inc c +.A827S: ld a,c + or a + jr z,.A8286 ; no blank -> whole line is the command + ld a,(hl) + cp " " + jr z,.A8286 + cp "\t" + jr z,.A8286 + inc hl + dec c + jr .A827S .A8286: ex af,af' sub c ld c,a ; ᫮ ப ? @@ -403,7 +418,7 @@ EVALCMD: xor a call EVALSTR ld hl,Buffers.work.buffer2 ;work_buffer+256 ld de,Buffers.input_line.Path ; 㤠 - ld bc,255 ;!HARDCODE + ld bc,max_len_comline+2 .loop: LD A,C DEC A JR Z,.error @@ -413,10 +428,11 @@ EVALCMD: xor a inc b or a jr nz,.loop + ; dec b ld a,b ld (Buffers.input_line.Symbols_Num),a ; ப (edline.asm) - and a + ;and a ret ; .error: LD (DE),A @@ -507,6 +523,10 @@ EVALSTR: ld a,(hl) BATLIST: DZ 'PAUSE' : DW cmd_pause DZ 'REM' : DW cmd_rem DZ 'EXIT' : DW cmd_break + DZ 'GOTO' : DW cmd_goto + DZ 'GOSUB' : DW cmd_gosub + DZ 'RETURN' : DW cmd_return + DZ 'IF' : DW cmd_if ; ; DSS- CMDLIST: DZ 'CD' : DW cmd_chdir diff --git a/SHELL/Commands/BREAK.ASM b/SHELL/Commands/BREAK.ASM index 55e7b69..1c57e98 100644 --- a/SHELL/Commands/BREAK.ASM +++ b/SHELL/Commands/BREAK.ASM @@ -2,7 +2,16 @@ cmd_break: .sp+1: LD SP,0 ;!TODO bat. । 訡 ⭮ 뢠騩 bat -.exit: ld a,(BAT_FM) ; . bat-䠩 +.exit: ld a,(goto_active) ; GOTO: label not found ? + or a + jr z,.close + xor a + ld (goto_active),a + ld de,MAIN_MSG.LABEL_NOT_FOUND + call ECHO_MESSAGE +.close: xor a + ld (gosub_sp),a ; reset GOSUB stack + ld a,(BAT_FM) ; . bat-䠩 ld c,Dss.Close ; 䠩 RST ToDSS xor a diff --git a/SHELL/Commands/GOTO.ASM b/SHELL/Commands/GOTO.ASM new file mode 100644 index 0000000..7750c08 --- /dev/null +++ b/SHELL/Commands/GOTO.ASM @@ -0,0 +1,277 @@ +; !FIXIT Vibe-code ஢ + +;/////////////////////////////////////////////////// +; +; GOTO / GOSUB / RETURN. Jumps inside a BAT-file by +; ":label", MS-DOS / 4DOS style. +; +; GOTO label - jump to ":label" +; GOSUB label - call subroutine at ":label" +; RETURN - return to the line after the GOSUB +; +;/////////////////////////////////////////////////// + +GOTO_LABEL_MAX EQU 15 ; max label name length +GOSUB_MAX EQU 16 ; max GOSUB nesting depth + +;------------------------------------------------- +; GOTO label +; in: de -> argument string (label, may start with ':') +;------------------------------------------------- +cmd_goto: + ex de,hl ; hl -> argument text + call GOTO_PARSE ; -> goto_label (upper, 0-term) + ld a,(goto_label) + or a + jp z,.empty ; no label name + jp GOTO_START ; rewind + start the label search +.empty: ld de,MAIN_MSG.LABEL_NOT_FOUND + jp gAbort + +;------------------------------------------------- +; GOSUB label +; in: de -> argument string (label, may start with ':') +;------------------------------------------------- +cmd_gosub: + ex de,hl ; hl -> argument text + call GOTO_PARSE ; -> goto_label (saved in memory) + ld a,(goto_label) + or a + jp z,cmd_goto.empty + call GOSUB_PUSH ; remember the return position + jp GOTO_START ; then jump like GOTO + +;------------------------------------------------- +; RETURN - resume after the matching GOSUB +;------------------------------------------------- +cmd_return: + ld a,(gosub_sp) + or a + jr z,.empty ; RETURN without GOSUB + dec a + ld (gosub_sp),a + add a,a + add a,a ; a = sp*4 (byte offset in stack) + ld e,a + ld d,0 + ld hl,gosub_stk + add hl,de + ld e,(hl) ; saved offset (low word) + inc hl + ld d,(hl) + inc hl + ld (gosub_lo),de + ld e,(hl) ; saved offset (high word) + inc hl + ld d,(hl) + ld (gosub_hi),de + ld a,(BAT_FM) ; bat-file handle + ld hl,(gosub_hi) ; HL = offset high 16 bits + ld ix,(gosub_lo) ; IX = offset low 16 bits + ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15 + RST ToDSS + jr c,.io + xor a + ld (MOVWORD.count),a ; force re-read from saved position + ret ; back to NEWLINE -> line after GOSUB +.empty: ld de,MAIN_MSG.RET_NO_GOSUB + jp gAbort +.io: call print_err_message + jp gAbort.silent + +;------------------------------------------------- +; Parse a label argument into goto_label +; in: hl -> text (optional spaces/TAB, optional ':') +; out: goto_label = upper-cased, 0-terminated token +;------------------------------------------------- +GOTO_PARSE: +.sp0: ld a,(hl) ; skip leading blanks (space / TAB) + cp " " + jr z,.sp0i + cp "\t" + jr nz,.nosp0 +.sp0i: inc hl + jr .sp0 +.nosp0: cp ":" ; allow "GOTO :label" + jr nz,.sp1 + inc hl +.sp1: ld a,(hl) ; skip blanks after ':' + cp " " + jr z,.sp1i + cp "\t" + jr nz,.copy +.sp1i: inc hl + jr .sp1 +.copy: ld de,goto_label + ld b,GOTO_LABEL_MAX +.cloop: ld a,(hl) + cp " "+1 ; a <= ' ' -> end of token + jr c,.cend + call COMPARE.cmp_AZ ; -> upper case + ld (de),a + inc hl + inc de + djnz .cloop +.cend: xor a + ld (de),a ; 0-terminate + ret + +;------------------------------------------------- +; Rewind the BAT-file and start the label search +;------------------------------------------------- +GOTO_START: + ld a,(BAT_FM) ; bat-file handle + ld hl,0 ; offset low + ld ix,0 ; offset high + ld bc,Dss.Move_FP.FrStart ; B=0 (from start), C=#15 + RST ToDSS + jr c,.io + xor a + ld (MOVWORD.count),a ; invalidate NEWLINE read buffer + ld a,1 + ld (goto_active),a ; activate the label search + ret +.io: call print_err_message + jp gAbort.silent + +;------------------------------------------------- +; Push the return position (file offset of the line +; that follows the current GOSUB) onto the stack. +;------------------------------------------------- +GOSUB_PUSH: + ld a,(gosub_sp) + cp GOSUB_MAX + jr nc,.deep ; stack overflow + ; current file pointer (tell): FrCurrent, offset 0 + ld a,(BAT_FM) + ld hl,0 + ld ix,0 + ld bc,Dss.Move_FP.FrCurrent ; B=1, C=#15 + RST ToDSS + jr c,.io + ; on return: IX = pointer low 16, HL = pointer high 16 + ld (gosub_hi),hl ; save high word + push ix + pop hl ; hl = pointer low 16 + ; offset = pointer - (bytes still unparsed in buffer1) + ld a,(MOVWORD.count) + ld e,a + ld d,0 + or a ; CF=0 + sbc hl,de ; hl = low - count + ld (gosub_lo),hl + jr nc,.nob + ld hl,(gosub_hi) ; borrow into high word + dec hl + ld (gosub_hi),hl +.nob: + ; store at gosub_stk[gosub_sp] + ld a,(gosub_sp) + ld c,a ; c = old depth + add a,a + add a,a ; a = sp*4 + ld e,a + ld d,0 + ld hl,gosub_stk + add hl,de + ld de,(gosub_lo) + ld (hl),e + inc hl + ld (hl),d + inc hl + ld de,(gosub_hi) + ld (hl),e + inc hl + ld (hl),d + ld a,c + inc a + ld (gosub_sp),a ; depth++ + ret +.deep: ld de,MAIN_MSG.GOSUB_DEEP + jp gAbort +.io: call print_err_message + jp gAbort.silent + +;------------------------------------------------- +; Print message (de=index) and abort the BAT-file +;------------------------------------------------- +gAbort: + call ECHO_MESSAGE +.silent: + xor a + ld (goto_active),a ; don't double-print in cmd_break.exit + jp cmd_break.exit + +;------------------------------------------------- +; Called from CMDMODE for every BAT-file line. +; Handles ":label" lines and the GOTO/GOSUB search. +; +; out: CF=1 - skip this line (label line, or searching) +; CF=0 - execute this line normally +;------------------------------------------------- +BAT_CHECK_LABEL: + ld hl,Buffers.input_line.Path +.sp: ld a,(hl) ; skip leading blanks (space / TAB) + cp " " + jr z,.spi + cp "\t" + jr nz,.first +.spi: inc hl + jr .sp +.first: cp ":" ; is it a label line ? + jr z,.label + ; not a label line + ld a,(goto_active) + or a + ret z ; CF=0 -> run normally + scf ; searching -> skip line + ret + ; +.label: ld a,(goto_active) + or a + jr nz,.match + ; not searching: ":label" -> skip (no echo, no exec) + scf + ret + ; searching: does this label match goto_label ? +.match: inc hl ; skip ':' +.msp: ld a,(hl) ; skip blanks after ':' + cp " " + jr z,.mspi + cp "\t" + jr nz,.mcmp +.mspi: inc hl + jr .msp +.mcmp: ld de,goto_label +.mlp: ld a,(de) ; target char (upper, 0-term) + or a + jr z,.mend ; target consumed + ld c,a + ld a,(hl) + cp " "+1 ; line token ended too early ? + jr c,.skip ; -> no match + call COMPARE.cmp_AZ + cp c + jr nz,.skip + inc hl + inc de + jr .mlp +.mend: ld a,(hl) ; target ended: line token must end here + cp " "+1 ; a <= ' ' -> full match + jr nc,.skip ; line label is longer -> no match + ; match ! stop searching, skip the label line itself + xor a + ld (goto_active),a + scf + ret + ; +.skip: scf ; keep searching, skip this line + ret + ; + +goto_active: db 0 ; 1 = searching for a label +goto_label: ds GOTO_LABEL_MAX+1,0 ; target label (upper, 0-term) +gosub_sp: db 0 ; GOSUB nesting depth +gosub_lo: dw 0 ; scratch (offset low) +gosub_hi: dw 0 ; scratch (offset high) +gosub_stk: ds GOSUB_MAX*4,0 ; return offsets (32-bit each) diff --git a/SHELL/Commands/IF.ASM b/SHELL/Commands/IF.ASM new file mode 100644 index 0000000..50e949f --- /dev/null +++ b/SHELL/Commands/IF.ASM @@ -0,0 +1,241 @@ +;/////////////////////////////////////////////////// +; +; IF - conditional command (MS-DOS style) +; +; IF [NOT] ERRORLEVEL number command +; IF [NOT] EXIST filename command +; IF [NOT] string1 == string2 command +; +; If the condition is true, the rest of the line is +; executed as an ordinary command (GOTO, ECHO, a +; program, another IF, ...). +; +;/////////////////////////////////////////////////// + +; in: de -> argument string (everything after "IF ") +cmd_if: + ex de,hl ; hl -> args + xor a + ld (.neg),a + call IF_SKIPB ; skip leading blanks + ; --- optional NOT --- + ld de,.kw_not + call IF_KW + jr nc,.noNOT + ld a,1 + ld (.neg),a +.noNOT: + ; --- ERRORLEVEL n ? --- + ld de,.kw_errlvl + call IF_KW + jr nc,.notErr + ld de,Buffers.work.buffer1 + ld c,Dss.GSwitch ; extract the number token + RST ToDSS + ld (.cmd),hl ; rest of line = command part + ld de,Buffers.work.buffer1 + call IF_ATOI8 ; a = number (0..255) + ld b,a ; b = threshold + ld c,Dss.Get_Err ; a = exit code of last program + RST ToDSS + cp b ; A >= n ? (NC = yes) + ld a,0 + jr c,.decide ; A < n -> false + inc a ; true + jr .decide +.notErr: + ; --- EXIST filename ? --- + ld de,.kw_exist + call IF_KW + jr nc,.strcmp + ld de,Buffers.work.buffer1 + ld c,Dss.GSwitch ; extract the filename token + RST ToDSS + ld (.cmd),hl ; rest of line = command part + ld a,FAT_ATTR.NoVolID ; any file/dir (not the volume label) + ld hl,Buffers.work.buffer1 ; filespec (NUL-term DOS name) + ld de,Buffers.work.buffer2 ; F_First work buffer + ld bc,Dss.F_First.DOSname ; B=1, C=#19 + RST ToDSS + ld a,0 + jr c,.decide ; CF=1 -> not found -> false + inc a ; exists -> true + jr .decide +.strcmp: + ; hl -> string1 "==" string2 [blank] command + push hl ; s1 start +.find: ld a,(hl) + or a + jr z,.bad ; no "==" -> malformed + cp "=" + jr nz,.fnext + inc hl + ld a,(hl) + cp "=" + jr z,.foundEq + dec hl +.fnext: inc hl + jr .find +.bad: pop hl + ret ; syntax error -> no-op +.foundEq: + dec hl ; hl -> first '=' of "==" + pop de ; de = s1 start + push de + or a + sbc hl,de ; hl = len1 (line < 256 -> h=0) + ld a,l + ld (.len1),a + pop de ; de = s1 start + ld hl,0 + ld l,a + add hl,de ; hl = s1 + len1 = first '=' + inc hl + inc hl ; hl = s2 start + ld (.s2),hl + ld b,0 ; len2 +.s2l: ld a,(hl) + cp " "+1 ; <=' ' (space/tab/CR/0) -> token end + jr c,.s2e + inc hl + inc b + jr .s2l +.s2e: ld (.cmd),hl ; command part starts here + ld a,(.len1) + cp b ; len1 == len2 ? + jr nz,.neq + or a + jr z,.eq ; both empty -> equal + ld c,a ; c = length + ld hl,(.s2) +.cl: ld a,(de) ; de = s1 + cp (hl) ; case-sensitive (MS-DOS) + jr nz,.neq + inc de + inc hl + dec c + jr nz,.cl +.eq: ld a,1 + jr .decide +.neq: xor a + ; +.decide: + ; a = raw condition (0/1) + ld b,a + ld a,(.neg) + xor b ; cond ^ NOT + and 1 + ret z ; false -> nothing to do + ld hl,(.cmd) + jp IF_RUN ; true -> run the command part + ; +.kw_not: db "NOT",0 +.kw_errlvl: db "ERRORLEVEL",0 +.kw_exist: db "EXIST",0 +.neg: db 0 +.cmd: dw 0 +.len1: db 0 +.s2: dw 0 + +;------------------------------------------------- +; Skip blanks (space / TAB) at (hl) +;------------------------------------------------- +IF_SKIPB: +.l: ld a,(hl) + cp " " + jr z,.i + cp "\t" + ret nz +.i: inc hl + jr .l + +;------------------------------------------------- +; Case-insensitive keyword test. +; in: hl -> text, de -> keyword (UPPER, 0-term) +; out: CF=1 - matched, hl past keyword + blanks +; CF=0 - no match, hl unchanged +;------------------------------------------------- +IF_KW: push hl +.l: ld a,(de) + or a + jr z,.kend ; keyword consumed + ld c,a + ld a,(hl) + call COMPARE.cmp_AZ ; -> upper + cp c + jr nz,.no + inc hl + inc de + jr .l +.kend: ld a,(hl) ; must be a blank delimiter + cp " " + jr z,.ok + cp "\t" + jr z,.ok +.no: pop hl ; restore, no match + or a ; CF=0 + ret +.ok: inc hl ; skip delimiter + following blanks +.ok2: ld a,(hl) + cp " " + jr z,.oki + cp "\t" + jr nz,.done +.oki: inc hl + jr .ok2 +.done: pop bc ; discard saved hl + scf + ret + +;------------------------------------------------- +; ASCII decimal -> A (0..255, saturating) +; in: de -> digits +;------------------------------------------------- +IF_ATOI8: + ld hl,0 +.l: ld a,(de) + sub "0" + jr c,.end + cp 10 + jr nc,.end + ld c,a ; c = digit + ld b,0 + push de + ld d,h + ld e,l + add hl,hl ; *2 + add hl,hl ; *4 + add hl,de ; *5 + add hl,hl ; *10 + add hl,bc ; + digit + pop de + inc de + jr .l +.end: ld a,h + or a + jr nz,.sat + ld a,l + ret +.sat: ld a,255 + ret + +;------------------------------------------------- +; Run the conditional command. +; in: hl -> command text (NUL-term at line end) +;------------------------------------------------- +IF_RUN: + call IF_SKIPB + ld a,(hl) + or a + ret z ; empty -> no-op + ld d,h + ld e,l ; de = command start + ld bc,0 ; b=0, c = token length +.tl: ld a,(hl) + cp " "+1 ; <=' ' -> end of command token + jr c,.tle + inc hl + inc c + jr .tl +.tle: ld hl,BATLIST ; bat + dos commands + jp COMP.start ; dispatch (recurses for nested IF) diff --git a/SHELL/EDLINE.ASM b/SHELL/EDLINE.ASM index fc778ee..d49ea6f 100644 --- a/SHELL/EDLINE.ASM +++ b/SHELL/EDLINE.ASM @@ -57,6 +57,7 @@ input_line: ld (cursor_position),de ; Y/X call clear_inpline ; ~input line~ call print_compath ; 뢥 + ਭ + call print_inpline jp event_input_line ; ࠡ. ப @@ -98,6 +99,7 @@ print_compath: ld a,">" ld bc,1*256 + BIOS.LP_PRINT_SYM ; ᨬ ਡ RST ToBIOS + RET ;jr print_inpline ; 뢮 ப ;------------------------------------------------- ; 뢮 ப ~input line~ ࠭ @@ -156,7 +158,7 @@ print_inpline: ld e,(iy + Input_Line.Cur_X) ;+2 ⥪. . ப add a,e cp width_inpline.MAX ; ਭ ࠭ - jr c,prne1__ + jr c,.prne1 ld b,width_inpline.MAX-1 sub b ld d,a ; "" ࠢ ࠩ @@ -164,7 +166,7 @@ print_inpline: sub d ld (iy + Input_Line.Cur_X),a ;+2 . ld a,b -prne1__:ld (cursor_position),a ; X . ࠭ +.prne1: ld (cursor_position),a ; X . ࠭ ret ; 室: HL - @@ -367,7 +369,7 @@ inpline_work: add a,(iy + Input_Line.Left_Shift) cp (iy + Input_Line.max_Len) ;ret nc - JR NC,LastChar_BEEP + JR NC,NoMoreChars_BEEP bit 7,(iy + Input_Line.ReadyString) ;ret nz JR NZ,NoMoreChars_BEEP @@ -424,22 +426,34 @@ no_insert: pop de ; . ⥪ input_line_done: ret -LastChar_BEEP: - ;!TODO ᫨ ᨬ ਢᨫ ᨬ쭮 ᫮, ࠭ - ; ப ⮩ , - ; । . ࠢ. - LD A,7 ;ASCII BELL - LD C,Dss.PutChar - JP ToDSS +; LastChar_BEEP: +; ; ᫨ ᨬ ਢᨫ ᨬ쭮 ᫮, ࠭ +; ; ப ⮩ , +; ; । . ࠢ. +; LD A,7 ;ASCII BELL +; LD C,Dss.PutChar +; JP ToDSS +;!FIXIT SCROLL ᤥ 㦥 㭪樨 ᮫ ஫ NoMoreChars_BEEP: ;!TODO ᫨ ᨬ ਢᨫ ᨬ쭮 ᫮, ࠭ ; ப ⮩ , ; । . ࠢ. - LD A,7 ;ASCII BELL + LD DE,(cursor_position) + LD C,Dss.Locate + RST ToDSS + PUSH DE + LD C,Dss.RdChar + RST ToDSS ; A - ᨬ, B - ਡ + POP DE + LD A,' ' ; ᨬ + LD C,Dss.WrChar ; #58 + RST ToDSS + LD A,7 ;ASCII BELL LD C,Dss.PutChar JP ToDSS + ; ⨥ - . 樨 EvComComb: ld b,(hl) ;+1 what diff --git a/SHELL/EXEC.ASM b/SHELL/EXEC.ASM index 24dbe3f..4239d78 100644 --- a/SHELL/EXEC.ASM +++ b/SHELL/EXEC.ASM @@ -8,8 +8,8 @@ SAVEHL: dw 0 ;------------------------------------------------------------- COMP: call EVALCMD ; (batch.asm) RET C - ld hl,Buffers.input_line.Path - dec hl + ld hl,Buffers.input_line.Path - 1 + ;dec hl ld c,(hl) ; ப ld b,0 inc hl ; Buffers.input_line.Path diff --git a/SHELL/Messages/main_txt.asm b/SHELL/Messages/main_txt.asm index 28a686b..2403d87 100644 --- a/SHELL/Messages/main_txt.asm +++ b/SHELL/Messages/main_txt.asm @@ -25,6 +25,9 @@ MAIN_MSG: .INFO_2 EQU .INFO_2_ .DIRPAUSE EQU .DIRPAUSE_ .CLSLINE EQU .CLSLINE_ +.LABEL_NOT_FOUND EQU .LBLNF_ +.RET_NO_GOSUB EQU .RNGSB_ +.GOSUB_DEEP EQU .GSBDP_ ; !txtCounter DEFL 0 ; ; ᤢ____ @@ -55,6 +58,9 @@ MAIN_MSG: stN .INFO_2_ : DZ " %9 \r\t %8\r\t\t\t %7\r\t\t\t\t\t %4\r\t\t\t\t\t\t\t %5\r\n" stN .DIRPAUSE_ : DZ "Press ESC to cancel or any other key to continue . . .\r" stN .CLSLINE_ : DZ " \r" + stN .LBLNF_ : DZ "Label not found\r\n" + stN .RNGSB_ : DZ "RETURN without GOSUB\r\n" + stN .GSBDP_ : DZ "GOSUB nesting too deep\r\n" ; ;R11 db 0 DZ "Unknown command" diff --git a/SHELL/SHELL.ASM b/SHELL/SHELL.ASM index 5090b2d..2102af7 100644 --- a/SHELL/SHELL.ASM +++ b/SHELL/SHELL.ASM @@ -1,17 +1,3 @@ -; ᫥ ।: 22.10.2006 -; - - -; - ࠢ . , ஬ ப bat-䠩, ਭ -; ࠭, १ ਭ ࠭ ⮪ ப 뢮. -; - ࠢ . , ஬ "dir" ப 뢮 -; . 15 ᨬ. -; - 䨪ᥭ ୮ ᪠/ ᫥ 訡 믮 . -; - "ECHO." ⠢ ⮩ ப. -; - DIR 뢮 ਩ ᪮. -; -; - ; SYSTEM.EXE /S /P ; ; /P Primary command processor @@ -535,6 +521,8 @@ T8C24: db "OFF",0 ; include 'Commands/exit.asm' ; 室 த. include 'Commands/break.asm' ; 室 bat + include 'Commands/goto.asm' ; GOTO - jump to a label in a bat + include 'Commands/if.asm' ; IF - conditional command include 'Commands/pause.asm' ; 㧠 include 'Commands/rem.asm' ; ਩ include 'Commands/ver.asm' ; 뢮 ᨨ @@ -553,6 +541,12 @@ T8C24: db "OFF",0 include 'Commands/set.asm' ; ६ 㦥 include 'Commands/reboot.asm' ; ; + DISPLAY "bat_params: ",/H,Buffers.bat_params, ". Size: ",/H, BAT_PARAMS, " End: ",/H, Buffers.bat_params + BAT_PARAMS - 1 + DISPLAY "screen_path: ",/H,Buffers.screen_path, ". Size: ",/H, 2 + max_screen_path + 1, " End: ",/H, Buffers.screen_path + (2 + max_screen_path + 1) - 1 + DISPLAY "sys_path: ",/H,Buffers.sys_path, ". Size: ",/H, 256, " End: ",/H, Buffers.sys_path + 255 + DISPLAY "input_line: ",/H,Buffers.input_line, ". Size: ",/H, Input_Line, " End: ",/H, Buffers.input_line + Input_Line - 1 + DISPLAY "history: ",/H,Buffers.history, ". Size: ",/H, history_size, " End: ",/H, Buffers.history + history_size - 1 + DISPLAY "work: ",/H,Buffers.work, ". Size: ",/H, Work, " End: ",/H, Buffers.work + Work - 1 DISPLAY "Empty space for buffers from ",/H,$ DISPLAY "Free space from ",/H,$ + Struc_Buffers assert ($ + Struc_Buffers) < (stack_point - stack_size), "Buffers can leack to stack!" diff --git a/SHELL/structures.inc b/SHELL/structures.inc index db0218f..26ae17f 100644 --- a/SHELL/structures.inc +++ b/SHELL/structures.inc @@ -1,5 +1,5 @@ STRUCT Input_Line -.max_Len BYTE 254 ;+0 254 . ᫮ . ᨬ +.max_Len BYTE max_len_comline ;+0 254 . ᫮ . ᨬ .ReadyString BYTE 0 ;+1 䫠 ReadyString .Cur_X BYTE 0 ;+2 X ⥪. . । ப .Left_Shift BYTE 0 ;+3 X ᬥ. ப ࠩ ( ᨬ) diff --git a/Shared_Includes b/Shared_Includes index d2ba40c..591d321 160000 --- a/Shared_Includes +++ b/Shared_Includes @@ -1 +1 @@ -Subproject commit d2ba40c4620459681fdc5eb8d4cadcb50eb79aa8 +Subproject commit 591d3212c9341f17d6dd034bf2b8da91bd2f6107 diff --git a/keys.md b/keys.md new file mode 100644 index 0000000..8fb7131 --- /dev/null +++ b/keys.md @@ -0,0 +1,828 @@ +# Промт для новой сессии: изучение и модификация клавиатурной подсистемы DSS + +## Задача +Изучить и при необходимости модифицировать алгоритмы работы с клавиатурой, +реализованные в [DSS/KEYINTER.ASM](DSS/KEYINTER.ASM) — модуле, который +включается в ядро DSS через `INCLUDE` из [DSS/DSS-MAIN.ASM](DSS/DSS-MAIN.ASM) +(строка 402, сразу после таблицы `DSS_API_TABLE`). Это код для компьютера +**Sprinter** (Z84C15), работающего как PS/2-хост для AT-клавиатуры через +встроенный в Z84C15 SIO канал A. + +Перед изменениями сверяй свои выводы с исходным кодом: в этом проекте уже +зафиксирована память о том, что **доверять разбору регистров/стека от +суб-агентов нельзя** — трассируй PUSH/POP/EX AF/EXX лично (см. +`[[verify-subagent-reg-flow-claims]]` в auto-memory). + +--- + +## 1. Рабочее окружение + +- **Основная директория проекта** (kernel + сборка): + `/Users/tolik/Documents/SP_Projects/ASM/GIT/Estex DSS` +- **Доп. директория** (архив/референс, не собирается): + `/Users/tolik/Documents/SP_Projects/ASM/Another` (подключена в + `Estex DSS.code-workspace` как второй корень) +- **Подмодуль git**: [Shared_Includes/](Shared_Includes/) — общие + константы/структуры/доки; ветка `main`, url `../Shared_Includes.git`. +- **Кодировка/переводы строк**: исходники в **CP866 (русский DOS)** с + **CRLF**. Это включает `DSS-MAIN.ASM`, `KEYINTER.ASM` и большинство + `Shared_Includes/constants/*.inc`. `grep -aI` нужен, если grep считает + файлы бинарными. +- **Ассемблер**: `sjasmplus --syntax=afw`. Сборка идёт через VS Code + ([.vscode/tasks.json](.vscode/tasks.json)) — Makefile нет. Полезные + задачи: `Build SYSTEM.DOS`, `Build SYSTEM.DOS [NEW]` + (`--define INCREASE_BUILD` → инкремент `DSS/build.txt`), + `Build SYSTEM.EXE`, `Build SYS.EXE`, `Copy all files to MAME` + (вызывает [RUN/Image.sh](RUN/Image.sh) → `hdfmonkey put` в + `/Users/tolik/Documents/MAME/IMG/test_2g.img`), `Run MAME`. +- **Выходы сборки**: + `Build/DSS/SYSTEM.DOS` (ядро), + `Build/DSS/SYSTEM.EXE` (шелл), + `Build/DSS/SYS.EXE` (бутлоадер), + `Build/DSS-MAIN.LST` (листинг ~1 МБ), + `Build/Variables.inc` (экспортированные символы через `--exp`). +- **Версия**: `VERS=1, MODF=71`, билд из `DSS/build.txt` (сейчас 68) → "DSS 1.71.68". + Логика в [DSS/VERSION.INC](DSS/VERSION.INC) + LUA в + [Shared_Includes/LUA/Functions.lua](Shared_Includes/LUA/Functions.lua). + +--- + +## 2. Архитектура DSS и место KEYINTER + +### 2.1. Точка входа ядра — [DSS/DSS-MAIN.ASM](DSS/DSS-MAIN.ASM) +- `ORG 0`, ядро располагается с адреса #0000 на странице ядра. +- **RST-векторы** (DSS-MAIN.ASM около строк 30-310): + - `RST 00` — RETFAR / реентри для дочерних процессов + - `RST 08` (`ToBIOS`) — портал в BIOS в SLOT0 + - `RST 10` (`ToDSS`) — DSS API gateway → `RST_10` диспетчер на строке 187 + - `RST 18` — портал в страницу драйверов + - `RST 20`, `RST 28` — NOPS + - `RST 30` (`ToDSS.Mouse`) — мышиный API + - `RST 38` (IM 1) — `INTx38_Handler` на строке 275: сохраняет все регистры + (главный набор + альтернативный + IX/IY), вызывает `CALL KEYSCAN`, + затем `RST ToDSS.Mouse GetPackets`, затем `cursor_interrupt`, `RETI`. +- **Диспетчер `RST_10`** (строка 187): `LD H,high DSS_API_TABLE / LD L,C` — + C=номер функции, индексирует таблицу адресов с раздельными байтами + (низкие байты строки 340-361, высокие 369-390). +- **Клавиатурные слоты в `DSS_API_TABLE`** (строки 344-345 / 373-374): + - `#30 WAITKEY`, `#31 SCANKEY`, `#32 ECHOKEY`, `#33 CTRLKEY`, + **`#34 NOPS`** (зарезервирован, не реализован — константа + `Dss.EDIT` есть, кода нет), `#35 K_CLEAR`, `#36 K_SETUP`, `#37 TESTKEY`. +- **INCLUDE KEYINTER.ASM** — строка 402. +- **Boot-флоу** `F_START` (строка 567): DEPLOY → `CALL KEYBOARD_INIT` + (строка 592) → PRINT_INIT → инициализация мыши → инициализация дисков → + `EI` → `CLEAR_BUFFER_AND_INIT_PROC`. +- **Карта памяти** ([DSS/DSS_MAP.TXT](DSS/DSS_MAP.TXT)): + - `#0000..#0038` — RESTARTS + - `#0200..#03FF` — `DSS_API_TABLE` + - `#0400..#043F` — **SBUF** (буфер клавиатуры, 64 байта) + - `#0440..#0BD1` — код KEYINTER (~1936 байт) + - `#0BD2..#0EF5` — драйвер экрана (для совместного использования с + `Cursor_On/Off`) + +### 2.2. Соседние модули +- [DSS/API.asm](DSS/API.asm) — агрегатор-INCLUDE для всех `DSS/API/*.asm`. +- [DSS/FS_Module.asm](DSS/FS_Module.asm) — `FS/FAT.asm` + `FS/CDFS.ASM`. +- [DSS/DOS_Proc.asm](DSS/DOS_Proc.asm) — DOS-уровневые помощники + (имена файлов, маски, `SET_FM`, `OPENDSK` и т.п.). +- [DSS/Procedures.asm](DSS/Procedures.asm) — общие хелперы + (`PUTCHAR` строка 103, `PUTCHAR.NO_SCROLL` строка 104, `MK_TIME` и др.). +- [DSS/DRV-MAIN.ASM](DSS/DRV-MAIN.ASM) — отдельная страница драйверов + (DISP/ENT-блок в `DSS-MAIN.ASM:695-699`), своя таблица RST по адресам + `#A0000..#A0038`. Клавиатура там НЕ живёт. +- [DSS/drivers/Input/MOUSE.ASM](DSS/drivers/Input/MOUSE.ASM) — мышь; + делит окно INT 38h с KEYINTER (сначала `KEYSCAN`, потом мышь). +- [DSS/defines.inc](DSS/defines.inc) — compile-time флаги (см. §5). +- [DSS/DSS_MACROSES.Z80](DSS/DSS_MACROSES.Z80) — макросы. Закомментированный + `BUFFER_KEYINTER` (строки 2-82) задокументирован как канонический layout + `SBUF/KEYFLAG/KEYCTRL/KEYFLG/SOUND_K`, но реальные определения сейчас + inline в `KEYINTER.ASM`. `SET_PAGE_X` (строки 137-143) — рабочий макрос + переключения страниц SLOT3. + +### 2.3. Внешние символы, на которые ссылается KEYINTER +| Символ | Что | Где определён | +|--------|-----|---------------| +| `PUTCHAR`, `PUTCHAR.NO_SCROLL` | вывод символа | `DSS/Procedures.asm:103-104` | +| `LOCATE` | установка курсора | `DSS/API/Locate.asm:8` | +| `VMODE` | байт текущего видеорежима | `DSS/API/SetVMod.asm:90` | +| `BANKTBL` | таблица логическая→физическая страница | `DSS/DSS-MAIN.ASM:423` | +| `RST_10` | диспетчер DSS | `DSS/DSS-MAIN.ASM:187` | +| `ToBIOS`, `BIOS.*` | BIOS API | `Shared_Includes/constants/BIOS_equ.inc` | +| `ToDSS`, `Dss.*`, `DSS_Error.*` | DSS константы | `Shared_Includes/constants/dss_equ.inc` | +| `Z84.SIO.Ch_A.{Data,Ctrl}`, `SP_SND.Beeper`, `SLOT3`, `TXTPAGE` | железо | `Shared_Includes/constants/SP2000.inc` (модуль `Z84`, строки 2111-2127); часть EQU может приходить из внешнего SP2000-инклюда не из снимка репо — проверять `Build/Variables.inc` | + +--- + +## 3. KEYINTER.ASM подробно + +Файл — 1371 строка, CRLF, CP866. Заголовок R01 (10.02.2003, DNS — добавлен +курсор в `ECHOKEY`) и R02 (13.04.2023, BAO — исправлен stack overflow в +`K_CLEAR`). + +### 3.1. Публичный API (вызывается через `RST 10` с `C=` номер функции) + +| C | Метка | Строки | Назначение | +|---|-------|--------|------------| +| #30 | `WAITKEY` | 112-119 | Блокирующее ожидание. Выход: `A=E=ASCII`, `D=` поз.код, `B=KEYCTRL`, `C=KEYFLAG` | +| #31 | `SCANKEY` | 122-128 | Неблокирующее. `ZF=1` если буфер пуст | +| #32 | `ECHOKEY` | 195-212 | `SCANKEY` + программный курсор (`Cursor_On`/`Off`), эхо через `PUTCHAR.NO_SCROLL` | +| #33 | `CTRLKEY` | 383-391 | Прочесть `BC=(KEYFLAG)` без извлечения; `A=0` если буфер пуст, `A=#FF` если есть | +| #34 | (NOPS) | — | `Dss.EDIT` определён, но функция не реализована в v1.71 | +| #35 | `K_CLEAR` | 431-445 | Очистить буфер (`HEAD:=HOST`), потом `JP RST_10` для повторной диспетчеризации, если `B ∈ [#30..#34]`. Иначе `A=#01 INVALID_FUNCTION`, `CF=1` | +| #36 | `K_SETUP` | 934-... | Мультиплексор: см. §3.6 | +| #37 | `TESTKEY` | 393-408 | Peek текущей записи без сдвига `HOST`. `ZF=1` если пуст | + +### 3.2. Кольцевой буфер +- **`SBUF`** (строка 14): `_mInfoALIGN 256,0` + `BLOCK 64,0` — 64 байта на + границе страницы. Поэтому high-byte адреса слота = `high SBUF`, а + `HEAD`/`HOST` — только low-byte (0..#3F). +- **`HEAD`** (строка 33) — указатель писателя. +- **`HOST`** (строка 34) — указатель читателя. +- **Слот = 4 байта**: `byte+0=E (ASCII)`, `byte+1=D (поз.код | #80)`, + `byte+2=B (KEYCTRL snapshot)`, `byte+3=C (KEYFLAG snapshot)`. +- Макс. 16 записей. +- Пуст: `HEAD == HOST`. Полон: `HEAD == (HOST-4) & #3F` (проверка + `PUTSYM` строки 450-453). +- **`GetSymAddr`** (строки 467-476) — общий помощник: `A := (HL)`, + `INC (HL)` ×4, `RES 6,(HL)` (wrap modulo 64), формирует + `HL = high SBUF : старый offset`. +- **`PUTSYM`** (448-464) — продьюсер. На переполнении прыгает в + `FULL_BF` (496-505): если `SF_BUFF` бит SOUND_K взведён — `BEEP` + с `DE=230, HL=50`, ключ отбрасывается. +- **`GETSYM`** (479-493) — консьюмер. + +### 3.3. Байты состояния (адресуются через `LD IX,KEYFLAG` на строке 519) + +**`KEYFLAG`** (offset 0, alias `K_LOCK`, строка 45, init `#02` — `INS_L` on): +| Бит | Имя | Значение | +|-----|-----|---------| +| 7 | `LANG_L` | язык RUS/LAT | +| 6 | `PAUSE_L` | Pause Lock | +| 5 | `RES5_L` | резерв (в комментариях помечено как историческое `X_SHIFT`) | +| 4 | `RES4_L` | резерв | +| 3 | `NUM_L` | Num Lock | +| 2 | `SCRL_L` | Scroll Lock | +| 1 | `INS_L` | Insert | +| 0 | `CAPS_L` | Caps Lock | + +Переключается: `CAPS_X` 668-671, `LANG_X` 674-690, `INS_X` 693-696, +`NUM_X` 699-702, `PAUSE_X` 705-718, `SCL_X` 721-724. + +**`KEYCTRL`** (offset 1, alias `K_SHIFT`, строка 56, init `#00`): +| Бит | Имя | +|-----|-----| +| 7 | `L_SHIFT` | +| 6 | `R_SHIFT` | +| 5 | `X_CTRL` (любой Ctrl) | +| 4 | `X_ALT` (любой Alt) | +| 3 | `L_CTRL` | +| 2 | `L_ALT` | +| 1 | `R_CTRL` | +| 0 | `R_ALT` | + +Устанавливаются в `SHIFTS` (799-836) на нажатии, сбрасываются в `UNSHIFT` +(738-797) на отпускании. Также чистятся в `KBD_Receiver_Overrun` (1240). + +**`KEY_FLG`** (offset 2, alias `KEYFLG`, строка 67, init `#00`): +| Бит | Имя | +|-----|-----| +| 7 | `FLAG_E0` — защёлкнут E0-префикс (extended) | +| 6 | `FLAG_F0` — защёлкнут F0-префикс (release) | +| 5 | `FLAG_E1` — E1-префикс (только если `USE_E1_SCANCODE`) | +| 4-1 | резерв | +| 0 | `CTRL_SHIFT` — Ctrl+Shift зафиксирован (для `LANG_X` при `CHANGE_LANG_CTRL_SHIFT`) | + +**`SOUND_K`** (offset 3, строка 78, init `#03` — оба звука включены): +| Бит | Имя | +|-----|-----| +| 7-2 | `FLAG_S7..S2`, резерв | +| 1 | `SF_ALT` — звук при смене языка | +| 0 | `SF_BUFF` — звук при переполнении буфера | + +**`UNCODE`** (offset 4, WORD, строка 81) — последний отпущенный скан-код +(пишется в `UN_KEY` строка 663). + +### 3.4. Таблица трансляции скан-кодов +- **`XLAT_T`** (строки 21-30) — сырая таблица 144 байта, + AT scancode (Set 2) → внутренний позиционный код 0..#5A. + `XLAT_T.Size = 144`. Bounds-check в `XLAT` на строке 860. +- **`XLAT`** (839-870) — собственно переводчик. Если защёлкнут `FLAG_E0`, + жёстко мапит специальные коды (`#11→#39 R-ALT`, `#14→#3A R-CTRL`, + `#5A→#4E numpad Enter`, `#4A→#4A /`, `#7C→#47 PrintScreen`); иначе + `L = XLAT_T[A]`. + +### 3.5. ASCII-таблицы (`MODULE ASCII_TABLES`, строки 1285-1368) +Все таблицы ровно 90 байт (`Size EQU 90`): +- `ASCII_TABLES.ENGLISH` (1287-1295) — без шифта, англ +- `ASCII_TABLES.SHIFT_ENG` (1297-1305) — с шифтом, англ +- `ASCII_TABLES.CAPS_ENG` (1307-1315) — Caps, англ +- `ASCII_TABLES.CAPS_SHIFT_ENG` (1317-1325) — Caps+Shift, англ +- `ASCII_TABLES.RUSSIAN` (1328-1336) — без шифта, рус CP866 +- `ASCII_TABLES.SHIFT_RUS` (1338-1346) +- `ASCII_TABLES.CAPS_RUS` (1348-1356) +- `ASCII_TABLES.CAPS_SHIFT_RUS` (1358-1366) + +Старые метки `NORMTAB / SHIFTAB / CAPSTAB / SHF2TAB / NORMRUS / SHIFRUS +/ CAPSRUS / SHF2RUS` сохранились ТОЛЬКО в закомментированной legacy-копии +`K_SETUP` (строки 1097-1167) и **не являются живыми**. Все +KEYMAP/READMAP используют `ASCII_TABLES.*`. + +### 3.6. K_SETUP подфункции (диспетчер на строке 934) +`INC B / DJNZ K_SND_R` — цепочка DJNZ: +| B | Метка | Поведение | +|---|-------|-----------| +| 0 | `KEYMAP` (937-972) / `READMAP` (974-1006) | Запись/чтение одной из 8 ASCII-таблиц. `HL=` буфер, `A bit7=0` запись, `bit7=1` чтение, биты0-2 = номер подтаблицы 0..7. Объём LDIR = `ASCII_TABLES.Size`=90 байт. Неверный A → `XOR A : SCF : RET` | +| 1 | `K_SND_R` (1019-1023) | `A := SOUND_K` | +| 2 | `K_SND_W` (1025-1030) | `SOUND_K := A` | +| 3 | `K_CURSOR_ON` (1034-1038) | Если `VMODE` показывает текстовый режим — `JP Cursor_On` | +| 4 | `K_CURSOR_OFF` (1042-1046) | То же → `JP Cursor_Off` | +| ≥5 | `K_SETUP.ERROR` (1015-1017) | `A = #0E INVALID_ACCESS, SCF, RET` | + +### 3.7. Сканер клавиатуры — `KEYSCAN` (519-629) +- `LD IX,KEYFLAG` — IX указывает на блок состояния. +- **В текущем билде сканер ПОЛЛИНГ** (`KEYBOARD_INT_ENABLED=0`): + IF-блок строк 521-526 (который бы делал `CALL .RESCAN`, выход из INT) + НЕ ассемблируется. `KEYSCAN` падает прямо в `.RESCAN`. На практике он + вызывается из `INTx38_Handler` (`DSS-MAIN.ASM:275-306`), который сам + висит на `IM 1` `RST 38h`. +- **Логика `.RESCAN`** (от строки 527): + 1. `IN A,(Z84.SIO.Ch_A.Ctrl)` — читаем RR0. + 2. Если `bit0` (Rx Character Available) = 0 → `RET`. + 3. Иначе пишем 1 в Ctrl (указать на регистр 1), читаем обратно, + тестируем `bit5` (Receiver Overrun) → ошибка → `JP KBD_Receiver_Overrun` + (1228) — дренаж FIFO, `OUT %00110000` в WR0 для error reset, + обнуление `KEYCTRL/KEY_FLG`. + 4. Иначе `IN A,(Z84.SIO.Ch_A.Data)` (строка 538) — байт скан-кода. + 5. Префиксы: + - `#F0` → `FULL_BF.F0_KEY`: устанавить `FLAG_F0`, `JP .RESCAN`. + - `#E0` → `FULL_BF.E0_KEY`: устанавить `FLAG_E0`, `JP .RESCAN`. + - `#E1` → если `USE_E1_SCANCODE=1` устанавить `FLAG_E1`, + иначе игнорировать. + 6. Обычный байт + `FLAG_F0` → `UN_KEY` (657-664): `XLAT` → `UNSHIFT` + модификаторов, `UNCODE := HL` (последний отпущенный). + 7. Обычный байт без `FLAG_F0` → `XLAT` → `SHIFTS` → сброс `FLAG_E0/E1` → + при `CHANGE_LANG_CTRL_SHIFT=1` опционально установить `CTRL_SHIFT` → + `INPCODE` → `PUTSYM` → `JP .RESCAN` (продолжать дренировать FIFO, + строка 628) — поскольку SIO имеет **3-байтовый Rx FIFO** (см. §6.4). + +### 3.8. INPCODE/RUSCODE/CONVERT (875-930) +- **`INPCODE`** (875-906) — выбор одной из 4 английских таблиц на основе + `KEYCTRL` бит шифта и `KEYFLAG.CAPS_L`. Если `LANG_L` взведён → `JP RUSCODE`. +- **`RUSCODE`** (908-930) — то же для русских. +- **`CONVERT`** (901-906): `SET 7,D` (флаг keystroke), `HL = таблица+L`, + `E := (HL)`. После этого `PUTSYM`. + +### 3.9. Курсор и звук +- **`Cursor`** (215-218) — переключатель: `CPL` `.Flag`, falls into + `Cursor_On`. +- **`Cursor_On`** (220-253): `BIOS.LP_GET_PLACE` (#8E) → DE=Y/X, сохранить; + `BIOS.WIN_GET_SYM` (#B4); вычислить глиф — `NORM_ZG=#1B` обычно, + `INS_CUR_ZG=#9B` при `INS_L`, `CURSOR_ZG=#5B` для фазы blink; + `BIOS.WIN_PUT_SYM.NoChangeZG` (`#01B5`); `LOCATE`. +- **`Cursor_Off`** (257-284): обратное действие; `JP LOCATE`. +- **`cursor_interrupt`** (287-295): тик. Если `.Flag != 0`, декрементировать + таймер; на нуле `CALL Cursor`. +- **`SETUP_CURSORS`** (298-375): один раз при старте подгружает кастомные + глифы (#5B блок и #9B инверт.) в страницу шрифта (`BANKTBL+TXTPAGE`) + через `BIOS.WIN_GET_ZG` (#B8) → CPL → `BIOS.WIN_SET_ZG` (#B6). +- **`BEEP`** (1173-1192): `DE=` период, `HL=` повторы. Тогглит A=#10/#00 в + `(SP_SND.Beeper)` = порт #FE бит 4. + +### 3.10. Инициализация — `KEYBOARD_INIT` (1194-1224) +Последовательность для SIO Ch_A (стандартная Z80 SIO init): +- `DI` +- WR0 := 0 (clear pointer) +- WR4 := парам. (clock, stop, parity) — точные байты в коде, ср. с + `Another/SPRINTER/TASM/Keybdrv.z80` (там 9 байт init) +- WR3 := `#C1` (Rx enable, 8 бит/символ) +- WR5 := `#62` (`0110'0010`: бит3 **Tx Enable = 0 → передатчик ВЫКЛЮЧЕН**; биты5-6 = 8 бит/символ). Передача данных клавиатуре аппаратно отключена — см. §6.5 +- WR1 := `%00011001` если `KEYBOARD_INT_ENABLED=1`, иначе 0 +- `EI : RET` + +--- + +## 4. Конвенция вызова DSS API + +- **DSS**: `LD C,Dss.Xxx` (номер функции из `Shared_Includes/constants/dss_equ.inc`, + модуль `Dss:`), `RST 10` (= `ToDSS`). Параметры — в регистрах согласно + спецификации (см. [Shared_Includes/Docs/DSS_1.71_Functions.asm](Shared_Includes/Docs/DSS_1.71_Functions.asm), + раздел 6). +- **Выход**: `CF=0` — успех (значения в регистрах согласно функции); + `CF=1` — ошибка, `A=` код ошибки (`DSS_Error.sys.*`). +- **BIOS**: `LD C,BIOS.XXX` (`Shared_Includes/constants/BIOS_equ.inc`, + модуль `BIOS:`), `RST 08` (= `ToBIOS`). Перед вызовом необходим `DI` и + `OUT (#7C),0` для переключения банка BIOS; стек должен быть в `#8000-#BFFF`. + Подробно — [Shared_Includes/Docs/BIOS functions.asm](Shared_Includes/Docs/BIOS%20functions.asm), строки 1-60. +- **Подфункции**: верхний байт BC (т.е. `B`) — индекс подфункции; константа + обычно собрана как `EQU subfn*256 + .Func`. Пример: `Dss.K_SETUP.SetSoundVars + EQU 2*256+#36`. + +--- + +## 5. Compile-time флаги ([DSS/defines.inc](DSS/defines.inc)) + +| Флаг | Текущее | Что переключает в KEYINTER | +|------|---------|-----------------------------| +| `KEYBOARD_INT_ENABLED` (стр. 21) | `0` | `0` = поллинг из `INT 38h`; `1` = SIO Ch_A прерывание (WR1 := `#19`), отдельный обработчик в начале `KEYSCAN` | +| `CHANGE_LANG_CTRL_SHIFT` (стр. 22) | `1` | `1` = переключение языка Ctrl+Shift (через `CTRL_SHIFT` бит и `UNSHIFT.CHECK_CTRL_SHIFT`); `0` = Ctrl+Space (legacy путь `IFN CHANGE_LANG_CTRL_SHIFT` строки 585-591) | +| `BREAK_PROCESS_CODE` (стр. 23) | `#AC00` | Cooked-код Ctrl+C для `WaitKey`/`EDIT` → `DSS_Error.sys.USER_ABORT` (#25) | +| `USE_E1_SCANCODE` (стр. 24) | `0` | `1` = обрабатывать E1 (Pause/Break), `0` = игнорировать | +| `ENABLED_KEYBOARD_CONTROL` (стр. 24) | `0` | `1` = компилировать `FAKE_SHIFT` (игнор AT fake-shift `E0 12`/`E0 59` вокруг серых nav-клавиш). `0` = выключено: на железе SIO Tx отключён (WR5=`#62`), хост не может слать `0xED`, клавиатура не знает NumLock → fake-shift не приходит. Включать, только если появится двунаправленный канал к клавиатуре. См. §6.5 | +| `SHORT_RSTx10_TABLE` (стр. 10) | `0` | Должен быть `0` (либо ≥#37), иначе клавиатурные слоты не войдут в API table | +| `COMPILE_UNUSED_CODE` (стр. 11) | `0` | Гейтит legacy/debug куски | + +Также в `defines.inc` — мышиные флаги (`MOUSE_INT_ENABLED`, ...) которые +делят с клавиатурой инфраструктуру SIO/IRQ. + +--- + +## 6. Аппаратура Sprinter / Z84C15 + +### 6.1. Карта внутренних портов Z84C15 +`Shared_Includes/constants/SP2000.inc`, `MODULE Z84` (строки 2111-2127): + +| Порт | Назначение | +|------|------------| +| `#10..#13` | `CTC.Ch_0..3` (таймеры) | +| **`#18`** | `Z84.SIO.Ch_A.Data` — **PS/2 клавиатура DAT_A** | +| **`#19`** | `Z84.SIO.Ch_A.Ctrl` — **PS/2 клавиатура COM_A** | +| `#1A` | `SIO.Ch_B.Data` (DMOUSE) | +| `#1B` | `SIO.Ch_B.Ctrl` (CMOUSE) | +| `#1C..#1D` | `PIO.Port_A` — LPT1 (принтер) | +| `#1E..#1F` | `PIO.Port_B` — LPT2 | +| `#F0..#F1` | WDT | +| `#F4` | `IntPrior_Reg` | +| `#EE/#EF` | `SYS.Control / SYS.Data` | + +Так что коммит `e334545 "M_INT: RFI is CH-A ONLY (per Z80 SIO spec)"` +относится к SIO Ch_A (клавиатура) — принтер на PIO, не на SIO. + +### 6.2. Порт бипера и банкование +- `SP_SND.Beeper` = порт `#FE`, бит 4 (`%00010000`). Прямая запись из + KEYINTER (нет BIOS-функции для звука). +- `SLOT0..SLOT3` = `#82, #A2, #C2, #E2` — внешние порты переключения + страниц памяти на окна `#0000/#4000/#8000/#C000`. `SET_PAGE_X` из + `DSS_MACROSES.Z80` (137-143) использует SLOT3 + `BANKTBL[page]`. +- `TXTPAGE` — индекс в `BANKTBL` для страницы шрифта (используется в + `SETUP_CURSORS` строка 304). Если EQU не определён в снимке репо, + он приходит из внешнего SP2000-инклюда (см. `Build/Variables.inc` + после первой сборки). + +### 6.3. Прерывания +- IM 1, единый вектор `#FF` для **кадрового И клавиатурного** прерывания. +- Различие: после входа в `INT 38h` ([DSS-MAIN.ASM:275](DSS/DSS-MAIN.ASM)), + читать порт `#19` (SIO Ch_A Ctrl/RR0); `bit0=1` → пришёл байт от + клавиатуры (в FIFO). Это и делает `KEYSCAN.RESCAN`. +- SIO Ch_A имеет **Rx FIFO на 3 байта** — `sp2000.pdf §9.4` явно + предписывает: «после обработки одного байта проверять, не пришло ли + ещё, и возвращаться только если FIFO пуст». +- Включение режима, при котором клавиатурный INT работает: + `Port_All_Mode` = `#204E`, биты `SPECTRUM_MODE_OFF=1` (бит 0) и + `STOP_KBD_INT_OFF=8` (бит 3) (см. `SP2000.inc`). +- Активный указатель ISR хранится в `SYS_PAGE.INT_ADRESS = #FEC124`, + `INT_PAGE = #FEC126`, `INT_ID = #FEC127` (сентинель `#AA` — установлено). + +### 6.4. Z80 SIO регистры (для модификаций инициализации) +- **WR0** — command + pointer на следующий WR/RR. +- **WR1** — interrupt enable (бит 0 ExtINT, биты 1-2 Tx Int, биты 3-4 Rx Int + mode `%01100` = INT_ON_RXBYTE), бит 5 Wait/Ready. +- **WR2** — Interrupt vector (только Ch_B по Z80 SIO spec — нерелевантно + для клавиатуры). +- **WR3** — Rx control: bit0 Rx Enable, биты 6-7 Rx bits/character. +- **WR4** — clock multiplier, stop bits, parity. +- **WR5** — Tx control: бит 3 Tx Enable, биты 5-6 Tx bits/character. +- **RR0** — статус: **бит 0 = Rx Character Available** (то что тестирует + KEYINTER), бит 1 = Int Pending (CH-A only), бит 2 = Tx Buffer Empty, + бит 5 = Sync/Hunt, бит 6 = CTS, бит 7 = Break. +- **RR1** — special Rx conditions: framing/parity/overrun errors. +- Полный datasheet — Zilog Z80 SIO Technical Manual (UM008); в репо его + нет, см. ссылки в §8. + +### 6.5. Команды PS/2 хост→клавиатура (host commands) +Если потребуется управлять светодиодами Caps/Num/Scroll или autorepeat, +то протокол описан в [/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/KBD.TXT](/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/KBD.TXT): +- `#FF` reset+self-test, `#FE` resend, `#F4` enable scanning, `#F5` disable+default, +- `#ED` set LEDs (bit0 Scroll, bit1 Num, bit2 Caps), +- `#F3` set typematic rate+delay (биты 6-5 delay 250/500/750/1000 ms, + биты 4-0 rate 6..30 cps), +- `#F2` read keyboard ID, +- `#FB-#FD`, `#F7-#FA` per-key/all-keys typematic. + +**Передача клавиатуре аппаратно невозможна в текущей конфигурации**: `KEYBOARD_INIT` +ставит WR5 = `#62` (бит3 Tx Enable = 0), т.е. передатчик SIO Ch_A выключен. +Поэтому host-команды (`0xED` Set LEDs, autorepeat и др.) не отправляются и не могут. + +Важное следствие про **fake-shift**: по стандарту AT/PS-2 клавиатура шлёт fake-shift +(`E0 12` / `E0 59` вокруг серых extended nav-клавиш — стрелки/Ins/Del/Home/End/PgUp/PgDn) +ТОЛЬКО когда её внутренний Num Lock-LED включён. А LED выставляет ТОЛЬКО хост командой +`0xED` (нажатие Num Lock для клавиатуры — обычный скан-код `0x77`, своё состояние она не +меняет). Раз `0xED` послать нельзя → клавиатура всегда считает Num Lock выключенным → +**fake-shift на реальном железе не генерируется**, выделенные стрелки всегда приходят +чисто (`E0 6B` и т.п.). Обработка fake-shift реализована в `FAKE_SHIFT`, но компилируется +только при `ENABLED_KEYBOARD_CONTROL=1` (§5) — на железе это мёртвый код, нужен лишь для +эмуляторов (MAME msnat сам моделирует Num Lock+fake-shift, чего на железе быть не может). +Чтобы реально слать команды — включить Tx (WR5 бит3=1) и писать в `#18` после проверки +готовности Tx Buffer (RR0 bit2). + +### 6.6. CMOS-привязка +- `CMOS_CELL.BootUpParams` = `#0E`, `.Mask.Language = %0000'0100` — пресет + языка при загрузке. +- `CMOS_CELL.Typematic` = `#0F`, маски `.Enabled %1000'0000`, + `.Delay %0110'0000`, `.Rate %0000'0111`. +- Доступ через `BIOS.CMOS_RD (#F6) / CMOS_WR (#F7)` или прямые порты + `CMOS.Port.{Data.Read=#FFBD, Data.Write=#BFBD, Address.Write=#DFBD}`. +- **Сейчас KEYINTER НЕ читает CMOS** — состояние локов и языка + сбрасывается на каждый boot к дефолтам. Если нужна persistence, + добавлять в `KEYBOARD_INIT` или в высокоуровневый `AUTOEXEC.BAT`. + +--- + +## 7. Reference материалы + +### 7.1. В репозитории +| Документ | Что искать | +|----------|------------| +| [Shared_Includes/Docs/sp2000.pdf](Shared_Includes/Docs/sp2000.pdf) | §1.1 Sp2000 hardware (p.4), §1.3 block diagram (p.5), §9 Внутренние порты Z84C15 (p.21), **§9.4 AT-Клавиатура p.25-26** (COM_A/DAT_A, sample code), §13.2 карта портов p.31 | +| [Shared_Includes/Docs/BIOS functions.asm](Shared_Includes/Docs/BIOS%20functions.asm) | Раздел 5 «Функции печати и управления режимом экрана» (стр. 628-1100): `LP_PRINT_SYM #82`, `LP_PRINT_ALL #81`, `LP_SET_PLACE #84`, `LP_GET_PLACE #8E`, `WIN_GET_SYM #B4`, `WIN_PUT_SYM #B5`, `WIN_GET_ZG #B8`, `WIN_SET_ZG #B6`, `LP_SCROLL_UD #8A`, `LP_PR_LINE_DIR #E0`. Конвенция вызова — стр. 1-60 | +| [Shared_Includes/Docs/DSS_1.71_Functions.asm](Shared_Includes/Docs/DSS_1.71_Functions.asm) | **Раздел 6 «Функции ввода с клавиатуры» (строки ~364-446)** — авторитетная спецификация на функции #30..#37 с корректировками из последней сессии (Pause Lock bit6, CTRLKey A=#FF/A=0, K_CLEAR INVALID_FUNCTION, K_SETUP B=0 это Get/Set table transfer) | +| [Shared_Includes/constants/dss_equ.inc](Shared_Includes/constants/dss_equ.inc) | `Dss.WaitKey..TestKey` (137-149), `Dss.K_SETUP.*` (144-148), `DSS_Error.sys.*` (280-336), **Приложение А — позиционные коды клавиш** (547-595) | +| [Shared_Includes/constants/BIOS_equ.inc](Shared_Includes/constants/BIOS_equ.inc) | `BIOS.*` функции (см. §7.1 ниже) | +| [Shared_Includes/constants/SP2000.inc](Shared_Includes/constants/SP2000.inc) | `MODULE Z84` (2111-2127), `SP_SND`, `ACEX.*`, `ZXKeys.Line_*` (#FEFE..#7FFE legacy ZX), `Port_All_Mode #204E`, `SYS_PAGE.INT_*`, `CMOS_CELL.*` | +| [Shared_Includes/constants/zx_char_codes.inc](Shared_Includes/constants/zx_char_codes.inc) | Control codes ZX: `.cursor_left=#08 (backspace)`, `.right=#09 (== TAB!)`, `.cursor_down=#0A`, `.cursor_up=#0B`, `.delete_left=#0C`, `.carriage_return=#0D`, и т.п. | +| [Shared_Includes/constants/dss_errors.z80](Shared_Includes/constants/dss_errors.z80) | Строки ошибок: #01 Invalid function, #0E Unknown operation, #13 Access denied, #20 Operation not supported, #25 User abort, #27 Unexpected app termination | +| [DSS/DSS_MAP.TXT](DSS/DSS_MAP.TXT) | Карта памяти ядра — #0400-#043F SBUF, #0440-#0BD1 KEYBOARD DRIVER | +| [DSS/CHANGES.LOG](DSS/CHANGES.LOG) | Хронология; ECHOKEY cursor 2003-02-10, txt 40x32 cursor bug, OVR cursor square | +| [DSS/KNOWN.BUG](DSS/KNOWN.BUG) | §3.3-3.4 — legacy ECHOKEY/PUTCHAR закомментированы, можно убирать; буферы #100/#80 без bounds-check | + +### 7.2. В `Another/` (референсы, не собираются) +| Файл | Зачем | +|------|-------| +| [/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Sprinter_Programming.pdf](/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Sprinter_Programming.pdf) | **p.22 «Прерывания»** (вектор #FF, бит 0 порта #19), **p.25-26 «Клавиатура»** (пример K_SETUP layout-table, 9×16=144 байта на подтаблицу, Ctrl+Space layout switch), p.27 коды ошибок | +| [/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/KBD.TXT](/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/KBD.TXT) | PS/2 host→keyboard команды (см. §6.5) | +| [/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/AT-Keyboard.pdf](/Users/tolik/Documents/SP_Projects/ASM/Another/Docs/Keyboard/AT-Keyboard.pdf) | Scan Code Set 2 на 3 страницах | +| [/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/TASM/Keybdrv.z80](/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/TASM/Keybdrv.z80) | Минималистский standalone-драйвер клавиатуры Дениса Паринова (517 строк): полная init-последовательность 9 байт WR0..WR5 на ComA=#19, чтение DataA=#18. Полезно при отладке железа отдельно от DSS | +| [/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/TASM/Scantabl.z80](/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/TASM/Scantabl.z80), [Scantabl2.z80](/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/TASM/Scantabl2.z80) | Альтернативные scancode→symbol таблицы (для сверки `XLAT_T`) | +| [/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/SRC/cpm3-s/SCAN.PLM](/Users/tolik/Documents/SP_Projects/ASM/Another/SPRINTER/SRC/cpm3-s/SCAN.PLM) | CP/M-3 Sprinter scan-логика на PL/M (третий независимый референс) | +| **НЕ нужно**: `Another/scancode.inc` | NASM/x86 BIOS INT16h (Sergey Kiselev Micro-8088). Другая архитектура, пропустить | + +### 7.3. Внешние (нужно скачать) +- **Zilog Z80 SIO Technical Manual (UM008)** — главы 3-4: полный layout + `WR0..WR7` / `RR0..RR2`. `sp2000.pdf §9` явно отсылает туда («Ссылка + на описание PIO, SIO и т.д. от Zilog»). +- **Zilog Z84C15 Product Specification** — карта внутренних портов, + CTC/PIO timing. + +--- + +## 8. История изменений KEYINTER (git log) + +`git log --oneline -- DSS/KEYINTER.ASM`: +- **9235af1** RUS keys fix +- **f5eacf4** KEYINTER.ASM: russian chars fix +- **e334545** M_INT: RFI is CH-A ONLY (per Z80 SIO spec) — **сохранять** + CH-A-only RFI семантику при правках ISR +- **73c7ab5** K_SETUP show/hide cursor sub-fns +- **12c0287** ECHOKEY scroll fix +- **eae2582** PutChar via BIOS LP_PR_LINE_DIR (#E0) +- **23fa77a** XLAT_T overflow + Ctrl+C +- **ff2f2b9** layout-switch combo (Ctrl+Space vs Shift+Ctrl) compile flag +- **54b1e80** SIO experiments + +При работе всегда смотреть `git log -p DSS/KEYINTER.ASM | head -200` — +часто старые комментарии R-номерами (R01, R02 ...) поясняют исторические +правки. + +--- + +## 9. Полезные команды на хост-системе + +- **Сборка ядра**: VS Code task `Build SYSTEM.DOS` (или `[NEW]` с + инкрементом билда). Из терминала примерно: + ``` + cd "/Users/tolik/Documents/SP_Projects/ASM/GIT/Estex DSS" + sjasmplus --syntax=afw --fullpath -Wno-shortblock \ + --lst=Build/DSS-MAIN.LST --raw=Build/DSS/SYSTEM.DOS \ + --exp=Build/Variables.inc DSS/DSS-MAIN.ASM + ``` +- **Деплой в MAME**: VS Code task `Copy all files to MAME` → запускает + [RUN/Image.sh](RUN/Image.sh) (zsh, `hdfmonkey`). +- **Запуск MAME**: VS Code task `Run MAME`. +- **Прочитать CP866-файл с правильной кодировкой**: + ``` + iconv -f CP866 -t UTF-8 DSS/KEYINTER.ASM | less + ``` +- **grep по бинарно-определяемым файлам** (CP866 ломает heuristic): + ``` + grep -anE "WAITKEY|KEYSCAN" DSS/KEYINTER.ASM + ``` + Флаг `-a` форсит text-режим. +- **Просмотр с табами**: + ``` + sed -n '519,540p' DSS/KEYINTER.ASM | tr -d '\r' | cat -tv + ``` +- **Дамп диспетч-таблицы**: + ``` + sed -n '337,396p' DSS/DSS-MAIN.ASM + ``` + +--- + +## 10. Стилевые соглашения + +- Кодировка CP866 (DOS Russian), переводы строк CRLF. Edit'ы должны их + сохранять. +- Отступы — табы. Комментарии справа от инструкции выровнены табами до + колонки `;`. При вставке новых комментариев-продолжений использовать + 4 таба + `;`. +- Рамки секций — `;████...████` (символ █ = U+2588). Не ломать. +- Стиль меток: метки целиком капсом (`KEYSCAN`, `WAITKEY`), вложенные + через `.` (`KEYSCAN.RESCAN`, `K_SETUP.ERROR`, `Cursor_Off.Flag`). +- Self-modifying code маркирован комментариями вроде `;R01`, `;R13` с + ревизионными номерами — НЕ удалять без причины (это история). +- Хроноразметка `[ ] DD/MM/YYYY` / `[x]` для done — в комментариях. + +--- + +## 10а. Работа с файлами CP866 + CRLF (практические рецепты) + +Это **главный источник тонких багов** при редактировании. Прочитай эту +секцию ДО первой правки. + +### 10а.1. Что именно в CP866 +- Все `DSS/*.asm`, `DSS/*.ASM`, `DSS/*.inc`, `DSS/*.Z80`. +- Все `Shared_Includes/constants/*.inc` и `Shared_Includes/Docs/*.asm`. +- `DSS/CHANGES.LOG`, `DSS/KNOWN.BUG`, `DSS/DSS_MAP.TXT`. +- `Another/SPRINTER/...`, `Another/Docs/Keyboard/KBD.TXT`. + +PDF в `Shared_Includes/Docs/sp2000.pdf` и `Another/Docs/*.pdf` — отдельная +история (текст внутри PDF в своей кодировке, см. `pdftotext`). + +UTF-8 в этом проекте бывает только в `*.md` (вроде этого файла), `*.json` +(VSCode-конфиги), `*.sh`, `*.lua` и `.gitmodules`. + +### 10а.2. Байтовая карта CP866 (минимум, который надо помнить) +| Байт(ы) | Что | +|---------|-----| +| `#80..#8F` | `А..О` (рус. заглавные, первая половина) | +| `#90..#9F` | `П..Я` (рус. заглавные, вторая половина) | +| `#A0..#AF` | `а..п` (рус. строчные, первая половина) | +| `#B0..#B2` | `░ ▒ ▓` (shading) | +| `#B3..#DA` | псевдографика `│ ─ ┌ ┐ ┘ └ ┤ ├ ┬ ┴ ┼ …` и двойные `║ ═` | +| **`#DB`** | **`█` — full block, из которого строятся рамки `;██..██` в этом проекте** | +| `#DC..#DF` | `▄ ▌ ▐ ▀` | +| `#E0..#EF` | `р..я` (рус. строчные, вторая половина) | +| `#F0, #F1` | `Ё ё` | +| `#FC` | `№` | +| `#FE` | `■` | + +Важно: +- **`█` = один байт `#DB` в CP866**, а в UTF-8 это **три байта `E2 96 88`**. + Поэтому строчка `;████████` длиной ~110 символов в CP866 занимает ~110 + байт, а в UTF-8 — ~330 байт. +- Если случайно конвертнуть файл в UTF-8 и забыть конвертнуть обратно, + размер файла резко вырастает, выравнивание комментариев плывёт, а + sjasmplus может выдать странные ошибки на строковых литералах. + +### 10а.3. Просмотр и поиск + +**Просмотр через тулзу Read**: русский текст может отображаться как +заполнители или мусор, потому что Read декодирует как UTF-8. Полагаться +на это для содержания комментариев **нельзя** — но для проверки кода +(меток, инструкций Z80, hex-литералов) подходит. + +**Просмотр в человеческой форме** — через Bash + iconv: +```sh +iconv -f CP866 -t UTF-8 DSS/KEYINTER.ASM | less +iconv -f CP866 -t UTF-8 DSS/KEYINTER.ASM | sed -n '519,540p' +``` + +**Просмотр с табами/CRLF**: +```sh +sed -n '519,540p' DSS/KEYINTER.ASM | iconv -f CP866 -t UTF-8 | cat -tev +# ^I = табы, $ = конец строки (CRLF будет показан как ^M$) +``` + +**grep по ASCII-меткам** — `-a` обязательно: +```sh +grep -an "WAITKEY\|KEYSCAN\|K_SETUP" DSS/KEYINTER.ASM +``` +Без `-a` grep с какого-то порога считает CP866 бинарным и молча выдаёт +только имя файла. + +**grep по русским словам** — через pipe iconv (номера строк сохраняются, +т.к. количество переводов строк не меняется): +```sh +iconv -f CP866 -t UTF-8 DSS/KEYINTER.ASM | grep -an "клавиш" +``` +Альтернатива: сконвертить запрос в CP866 и грепать байтами (но это +крайне неудобно — pipe-метод лучше). + +**Полный hex-дамп строки** (для разбора, что именно лежит в файле): +```sh +sed -n '519p' DSS/KEYINTER.ASM | xxd | head +``` + +### 10а.4. Редактирование — критическое + +**Главная проблема Edit-инструмента**: он работает на байтовом уровне. +Если файл в CP866, а `old_string` в твоей tool-call'е содержит русский +текст в UTF-8, то байты НЕ совпадут и Edit упадёт с `String not found`. +Если случайно `new_string` запишется UTF-8'ом в CP866-файл, файл +ломается локально (на конкретной строке). + +**Безопасные паттерны**: +1. **ASCII-only анкоры (90% случаев)**. Выбирай `old_string` так, чтобы он + состоял из инструкций Z80, меток, hex-литералов и английских/латинских + фрагментов. Кириллический хвост строки пройдёт «как есть» — Edit не + трогает то, что не в old_string. + ``` + old_string: " RST ToDSS\t\t\t; " + ``` + Это сработает, даже если справа после `; ` идёт русский комментарий. + +2. **Если кириллица обязана быть в old_string** (например, надо заменить + текст внутри русского комментария) — сначала **сконвертировать + фрагмент в CP866** через Bash: + ```sh + echo -n "максимальный номер диска" | iconv -f UTF-8 -t CP866 | xxd + ``` + получишь байты, и можешь искать/заменять через `sed` или `perl` с + `LC_ALL=C` (байтовый режим), а не через Edit. + +3. **Удобный трюк**: убедиться, что `old_string` уникально совпадает с + ASCII-частью комментария или ID: + ``` + old_string: " LD A,disk_num\t\t\t; " + new_string: " LD H,device_num\t\t; " + ``` + и оставить хвостовую кириллицу в покое. + +4. **Не вставляй русский текст напрямую через Edit**, если файл в CP866. + Если требуется добавить русский комментарий, сделай это через Bash: + ```sh + echo -n "; новый комментарий" | iconv -f UTF-8 -t CP866 >> /tmp/append + # затем вставляй байты через sed/perl + ``` + Или согласись писать новые комментарии на английском/латинице (ASCII) + — это безопаснее, и стиль файла это терпит. + +### 10а.5. Сохранение CRLF +- Файлы используют `\r\n` (Windows-стиль), не `\n`. +- При вставке новых строк через Edit убедись, что в `new_string` есть + `\r` перед `\n`. Если Edit-инструмент это съест и поставит только + `\n`, файл получит **смешанные line endings** — sjasmplus съест, но + `git diff` будет показывать всю окрестность как изменённую, и в + Windows-редакторах текст рассыпется. +- **Альтернатива**: после Edit-сессии нормализуй переводы строк: + ```sh + # Проверить: + file DSS/KEYINTER.ASM + # Должно быть: "with CRLF line terminators" + # Если стало "with CRLF, LF line terminators" — есть смесь, чинить: + perl -i -pe 's/\r?\n/\r\n/g' DSS/KEYINTER.ASM + ``` + +### 10а.6. Проверка после правки (обязательная) +```sh +file DSS/KEYINTER.ASM +# Ожидается: "Non-ISO extended-ASCII text, with CRLF line terminators" +# НЕ должно быть "UTF-8 Unicode text" или "with LF line terminators" + +# Проверка, что рамки █ не превратились в UTF-8 (3 байта): +grep -c $'\xDB\xDB\xDB' DSS/KEYINTER.ASM +# Должно быть положительное число (несколько штук). 0 = рамки сломаны. + +# git diff с пониманием бинарного представления: +git diff DSS/KEYINTER.ASM | cat -v | head -50 +# Cyrillic должен показываться как M-X M-X последовательности байт +``` + +### 10а.7. Откат, если что-то сломалось +```sh +# Один файл — мгновенный откат: +git checkout HEAD -- DSS/KEYINTER.ASM + +# Если уже закоммитил битый файл — посмотреть предыдущую версию: +git show HEAD~1:DSS/KEYINTER.ASM | iconv -f CP866 -t UTF-8 | less +``` + +### 10а.8. Конвертация всего файла «туда-обратно» (последнее средство) +Если правок очень много и проще править в UTF-8: +```sh +# 1. Конвертация в UTF-8 + переход на LF (так удобнее редактировать): +iconv -f CP866 -t UTF-8 DSS/KEYINTER.ASM | tr -d '\r' > /tmp/KEYINTER.utf8 + +# 2. Правки в /tmp/KEYINTER.utf8 любым инструментом (Edit/sed/perl). + +# 3. Обратно в CP866 + восстановление CRLF: +iconv -f UTF-8 -t CP866 /tmp/KEYINTER.utf8 | perl -pe 's/\r?\n/\r\n/g' > DSS/KEYINTER.ASM + +# 4. Проверка: +file DSS/KEYINTER.ASM +git diff --stat DSS/KEYINTER.ASM +``` +**Риск**: если в файле есть байты, не имеющие пары CP866↔UTF-8 (теоретически +вряд ли в этом проекте, но возможно при кривых правках в истории), iconv +ругнётся с `illegal input sequence`. Тогда `iconv -c` пропустит проблемные +байты — но они **потеряются**. Безопаснее в этом случае работать +ASCII-only анкорами через Edit. + +### 10а.9. VS Code как замена тулинга +Если хочется визуальной правки: +- VS Code: правый-нижний угол → `Reopen with Encoding → Cyrillic (CP866)`. +- Для постоянной ассоциации `.asm/.ASM/.inc` с CP866 добавить в + `.vscode/settings.json`: + ```json + { + "[asm]": { "files.encoding": "cp866" }, + "files.eol": "\r\n" + } + ``` +- При сохранении проверь нижнюю панель — индикатор должен показывать + «CP866» и «CRLF», а не «UTF-8» / «LF». + +### 10а.10. Чек-лист: «изменения сохранят кодировку» +- [ ] `file <изменённый.asm>` → `Non-ISO extended-ASCII text, with CRLF line terminators` +- [ ] `grep -c $'\xDB\xDB\xDB' <изменённый.asm>` > 0 (если в файле были рамки) +- [ ] `git diff <изменённый.asm> | wc -l` разумного размера (не в 3× больше ожидаемого — иначе UTF-8 раздувание) +- [ ] Сборка `Build SYSTEM.DOS` проходит без warning'ов вроде «invalid character in string literal» +- [ ] Открыть результат в VS Code с CP866 — комментарии читаются по-русски + +--- + +## 11. Что важно помнить, прежде чем менять KEYINTER + +1. **Файл подключается `INCLUDE`'ом** в `DSS-MAIN.ASM:402`, сборка идёт + как монолит. Все символы видны глобально. +2. **Состояние клавиатуры — RAM-only**: не персистится в CMOS. Любая + настройка (язык, локи, sound flags, ASCII-таблицы) теряется на + reset/power-off, если её не сохранить через AUTOEXEC.BAT. +3. **Клавиатура и мышь делят окно INT 38h** — мышь идёт после `KEYSCAN`. + Долгая работа в `KEYSCAN` задерживает мышь. +4. **SIO Ch_A FIFO = 3 байта** — `.RESCAN` должен дренировать его + полностью за один заход (текущая реализация это делает через + `JP .RESCAN` на строке 628). +5. **`KEYBOARD_INT_ENABLED=0`** — текущий билд поллит, не использует SIO + INT. Если хочется перейти на прерывания, нужно переключить флаг, + убедиться что `KEYBOARD_INIT` пишет WR1=`#19`, и проверить что + обработчик RFI в `DSS-MAIN.ASM` корректно настроен (Z80 SIO Ch_A only). +6. **При правке HEAD/HOST убедиться, что `RES 6,(HL)` сохранён** — это + обеспечивает wrap modulo 64. Если изменишь размер `SBUF`, поменяй и + маску (бит-логика `RES 6` работает только для 64 = #40). +7. **При правке `XLAT_T`** — длина 144 байта (`Size`), bounds-check + `CP XLAT_T.Size` на строке 860. Если расширяешь, проверь, что не + натыкаешься на следующую область (`CURRENT DIR NAME BUFFER` по + DSS_MAP.TXT идёт от #1343). +8. **Двойственность `D` в записях буфера**: D[7] = «keystroke flag», + D[6:0] = позиционный код 0..#5A. `INPCODE/CONVERT` ставит бит 7 через + `SET 7,D` — это видимый паттерн. +9. **При правке ASCII-таблиц** — каждая ровно 90 байт, проверяется + `ASSERT .Size = Size`. Если меняешь размер, меняй и `Size EQU 90` + на строке 1286. +10. **Звук работает в обход BIOS** — прямой `OUT (SP_SND.Beeper),A` + (порт #FE бит 4). Это запрещает звуковые эффекты, если процесс + держит порт #FE для других целей (ZX-режим). Учитывать при + модификациях `BEEP`/`FULL_BF`/`LANG_X`. + +--- + +## 12. Чек-лист первого подхода + +Сначала открой и прочитай (именно в таком порядке): +1. [DSS/KEYINTER.ASM](DSS/KEYINTER.ASM) целиком (1371 строка). +2. [DSS/DSS-MAIN.ASM](DSS/DSS-MAIN.ASM): строки 187-213 (`RST_10`), + 275-310 (`INTx38_Handler`), 337-396 (`DSS_API_TABLE`), 402 (INCLUDE), + 423 (`BANKTBL`), 567-600 (boot-флоу). +3. [DSS/defines.inc](DSS/defines.inc) (короткий). +4. [Shared_Includes/Docs/DSS_1.71_Functions.asm](Shared_Includes/Docs/DSS_1.71_Functions.asm), раздел 6. +5. [Shared_Includes/constants/dss_equ.inc](Shared_Includes/constants/dss_equ.inc), приложение А (позиционные коды). +6. `Another/Docs/Sprinter_Programming.pdf` p.22, p.25-26 (страницы 25-26 содержат + пример K_SETUP layout-table). +7. `sp2000.pdf` §9.4 (PDF, страница ~25-26). +8. Скачать Zilog Z80 SIO Technical Manual (UM008), если будешь трогать + `KEYBOARD_INIT` или `KBD_Receiver_Overrun`. + +Только после этого формулируй гипотезу и план правок. + +--- + +## 13. Контрольные вопросы перед коммитом + +- [ ] Тестовая сборка `Build SYSTEM.DOS` прошла без ошибок? +- [ ] Кодировка файлов сохранена CP866/CRLF? (`file DSS/KEYINTER.ASM` + должен показать `Non-ISO extended-ASCII text, with CRLF line terminators`) +- [ ] Табы и выравнивание комментариев не нарушены? +- [ ] Если изменён публичный API (#30..#37) — обновлён ли + [Shared_Includes/Docs/DSS_1.71_Functions.asm](Shared_Includes/Docs/DSS_1.71_Functions.asm)? +- [ ] Если изменены константы (`Dss.K_SETUP.*`, ASCII-таблица size, + коды ошибок) — обновлён ли `dss_equ.inc`? +- [ ] Если изменена инициализация SIO — проверено, что коммит совместим + с `e334545 "RFI is CH-A ONLY"`? +- [ ] MAME-прогон (`Run MAME` / `Copy all files to MAME`): клавиатура + реагирует, переключение языка работает, INS/CAPS/NUM/SCRL ведут себя + ожидаемо? +- [ ] Echo (`ECHOKEY`) рисует курсор корректно во всех текстовых режимах + (40×32, 80×32)? +- [ ] `XLAT_T` не вылез за `Size=144`? + +Удачи.