From 4caee041330c3336b395b98831187aff5cc3e2e4 Mon Sep 17 00:00:00 2001 From: Tolik <85737314+Tolik-Trek@users.noreply.github.com> Date: Sat, 5 Apr 2025 03:49:40 +1000 Subject: [PATCH] =?UTF-8?q?5x=20Read/Write=20=D0=BE=D1=82=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D0=BE=D1=82=20=20R/W=20?= =?UTF-8?q?Long=20=D1=82=D0=B5=D0=BC,=20=D1=87=D1=82=D0=BE=20R/W=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BF=D1=80=D0=B8=20HL=3D0=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B0=D1=8E=D1=82=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=D1=83.=20=D0=92=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=8D=D1=82?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=91=D1=82=D1=81?= =?UTF-8?q?=D1=8F=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0.=20=D0=92=20?= =?UTF-8?q?=D1=81=D0=BB=D1=83=D1=87=D0=B0=D0=B5=20=D0=B7=D0=B0=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B8=20=D0=BF=D0=B8=D1=88=D1=83=D1=82=D1=81=D1=8F=200?= =?UTF-8?q?=20=D0=B2=20=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D1=88=D0=B8=D0=B5?= =?UTF-8?q?=D1=81=D1=8F=20=D1=81=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=B0.=20?= =?UTF-8?q?=D0=9C=D0=B5=D0=BB=D0=BA=D0=B8=D0=B5=20=D1=84=D0=B8=D0=BA=D1=81?= =?UTF-8?q?=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bios/exp/EXP.asm | 96 ++-- src/bios/exp/EXTENDED/FDD_DRIVER_2.asm | 686 +++++++++++++----------- src/bios/exp/EXTENDED/IDE/ATAPI_DRV.ASM | 248 ++++++--- src/bios/exp/EXTENDED/IDE/ATA_DRV.ASM | 365 +++++++------ src/bios/exp/EXTENDED/IDE/shared.asm | 17 + src/bios/exp/FUNC_LOW_PRINT.ASM | 15 +- src/bios/shared/DEFINES.INC | 1 + src/bios/shared/RECOVERY.IMG | Bin 98304 -> 98304 bytes 8 files changed, 828 insertions(+), 600 deletions(-) diff --git a/src/bios/exp/EXP.asm b/src/bios/exp/EXP.asm index 06a6531..1f6a849 100644 --- a/src/bios/exp/EXP.asm +++ b/src/bios/exp/EXP.asm @@ -126,22 +126,22 @@ NOINT: POP AF ; any adress < #C0 with mask %xxxx0000 ; таблица для Sprinter POST-Tester-a TABLE_X: -.v0: DB 00101000b ; "0" -.v1: DB 10111101b ; "1" -.v2: DB 00110010b ; "2" -.v3: DB 00110100b ; "3" -.v4: DB 10100101b ; "4" -.v5: DB 01100100b ; "5" -.v6: DB 01100000b ; "6" -.v7: DB 00111101b ; "7" -.v8: DB 00100000b ; "8" -.v9: DB 00100100b ; "9" -.vA: DB 00100001b ; "A" -.vB: DB 11100000b ; "B" -.vC: DB 01101010b ; "C" -.vD: DB 10110000b ; "D" -.vE: DB 01100010b ; "E" -.vF: DB 01100011b ; "F" +.v0: DB %00101000 ; "0" a +.v1: DB %10111101 ; "1" ___ +.v2: DB %00110010 ; "2" f | g | b +.v3: DB %00110100 ; "3" |___| +.v4: DB %10100101 ; "4" e | | c +.v5: DB %01100100 ; "5" |___|. +.v6: DB %01100000 ; "6" d +.v7: DB %00111101 ; "7" +.v8: DB %00100000 ; "8" a - 7 +.v9: DB %00100100 ; "9" b - 6 +.vA: DB %00100001 ; "A" . - 5 +.vB: DB %11100000 ; "B" f - 4 +.vC: DB %01101010 ; "C" g - 3 +.vD: DB %10110000 ; "D" e - 2 +.vE: DB %01100010 ; "E" c - 1 +.vF: DB %01100011 ; "F" d - 0 ENDIF ;======================================= ; @@ -268,23 +268,23 @@ ROM_DISK.Pages: ; _mInfoALIGN #10,0 ; any adress < #C0 with mask %xxxx0000 ; таблица для Sprinter POST-Tester-a -TABLE_X: ; таблица для Sprinter POST-Tester-a +TABLE_X: .v0: DB %00101000 ; "0" a .v1: DB %10111101 ; "1" ___ .v2: DB %00110010 ; "2" f | g | b .v3: DB %00110100 ; "3" |___| .v4: DB %10100101 ; "4" e | | c -.v5: DB %01100100 ; "5" |___| -.v6: DB %01100000 ; "6" d +.v5: DB %01100100 ; "5" |___|. +.v6: DB %01100000 ; "6" d .v7: DB %00111101 ; "7" .v8: DB %00100000 ; "8" a - 7 .v9: DB %00100100 ; "9" b - 6 -.vA: DB %00100001 ; "A" f - 4 -.vB: DB %11100000 ; "B" g - 3 -.vC: DB %01101010 ; "C" e - 2 -.vD: DB %10110000 ; "D" c - 1 -.vE: DB %01100010 ; "E" d - 0 -.vF: DB %01100011 ; "F" +.vA: DB %00100001 ; "A" . - 5 +.vB: DB %11100000 ; "B" f - 4 +.vC: DB %01101010 ; "C" g - 3 +.vD: DB %10110000 ; "D" e - 2 +.vE: DB %01100010 ; "E" c - 1 +.vF: DB %01100011 ; "F" d - 0 ENDIF ;======================================= ; @@ -424,6 +424,25 @@ EXTINT: OR A ; ==== POST PROCs ================= +; LPT 0 - start +; post 1. TEST RAM BUS +; IF ERROR -> ERROR RAM BUS - CODE 'X'X'X'X... - высветить номер ошибочного бита +; LPT 1 - post 1 OK +; post 2 TEST ADRESS BUS +; IF ERROR -> ошибка адреса CODE 'XXXX - вывести старший байт с запятой, пауза, вывести младший без запятой +; LPT 2 - post 2 OK +; post 3 init DCP +; no errors +; LPT 3 - post 3 OK +; post 4 TEST RAM PAGES запись в порт страницы, чтение записанного +; IF ERROR -> ошибка переключения Port-а CODE 'XX - вывод байта записанного в порт +; LPT 4 - post 4 OK +; post 5 проверка чистоты шины данных Z84C15 +; IF ERROR -> ERROR CODE '_'XX - в биосе на ошибке не зависает, хз почему, может на случай конфы с грязной шиной спектрума +; LPT 5 - post 5 OK +; LPT 4 - post 5 error - старый биос +; LPT F - post 5 error - биос 05/04/2025))) +; MODULE POST_TEST START: ; ********************************* @@ -499,7 +518,7 @@ POST_1_RAM_BUS: ; бесконечный цикл INC L LD A,L - AND #AF + AND +(TABLE_X or #0F) ;%1010'1111 LD L,A JR .ERB_2 @@ -548,12 +567,12 @@ POST_2_ADRESS_BUS: .error: .TSAB_4: LD C,D - LD B,11011111b + LD B,%1101'1111 LD IX,.TSAB_3 JR OUT_C_BYTE ; вывести старший байт с запятой .TSAB_3: LD C,E - LD B,#FF + LD B,%1111'1111 LD IX,.TSAB_4 JR OUT_C_BYTE ; вывести младший без запятой @@ -663,7 +682,7 @@ POST_4_PAGES: .error: LD C,B LD IX,.error_out_ret .error_out_ret: - LD B,11011111b + LD B,%1101'1111 JP OUT_C_BYTE ; *********************************** @@ -679,11 +698,17 @@ POST_5_DATA_BUS: LD B,0 .loop: IN A,(0) CP #FF - ;JR NZ,.error ;!!!!! посмотреть - JR NZ,POST_5_ERROR + IF ERROR_POST_5 + JR NZ,.error ;!!!!! посмотреть + ELSE + JR NZ,POST_5_ERROR + ENDIF DJNZ .loop + LD A,(TABLE_X.v5) ;rdlow-ok JR POST_5_OK - + ; + ; + IF ERROR_POST_5 ; ERROR CODE '_'XX .error: LD C,A @@ -702,15 +727,18 @@ POST_5_DATA_BUS: OR E JR NZ,.LOOP_WTT4 JR .erb1 + ENDIF ; ********************************** ; ===== Point 5 ========= ; ********************************** + IFN ERROR_POST_5 +POST_5_ERROR: + LD A,(TABLE_X.vF) ;rdlow-ok + ENDIF POST_5_OK: - LD A,(TABLE_X.v5) ;rdlow-ok OUT (Z84.PIO.Port_A.Data),A ; вывести "5" -POST_5_ERROR: ; ********************************** ; POST завершен ENDMODULE diff --git a/src/bios/exp/EXTENDED/FDD_DRIVER_2.asm b/src/bios/exp/EXTENDED/FDD_DRIVER_2.asm index 7b86671..a8910dc 100644 --- a/src/bios/exp/EXTENDED/FDD_DRIVER_2.asm +++ b/src/bios/exp/EXTENDED/FDD_DRIVER_2.asm @@ -3,6 +3,10 @@ ;[]===========================================================[] +;!TODO +; объеденить процедуры FDD_5x_LONG_READ и FDD_5x_LONG_WRITE +; объеденить процедуры READ_SECTOR и WR_SEC + ; FDD.CHANGE: ; LD A,#01 @@ -178,10 +182,9 @@ FDD_5x_RESET: CALL SAVE_INTERRUPTS.switch_off ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;[]===========================================================[] -FDD_5x_READ: - EX AF,AF' - IN A,(SLOT3) - EX AF,AF' +FDD_5x_READ: EX AF,AF' + IN A,(SLOT3) + EX AF,AF' ;[]===========================================================[] ;Function: Long Read Sectors ; A - Disk @@ -194,7 +197,11 @@ FDD_5x_READ: ; DE - Address + (Sector counter * Size sector) ;[]===========================================================[] FDD_5x_LONG_READ: - CALL SAVE_INTERRUPTS.switch_off + EXX + LD B,#80 ; COMMAND READ + EXX + ; +.RW_Shared: CALL SAVE_INTERRUPTS.switch_off CALL .Start JP SAVE_INTERRUPTS.restore ; @@ -202,8 +209,9 @@ FDD_5x_LONG_READ: PUSH BC PUSH HL PUSH IX + ; EX AF,AF' - LD C,A + LD C,A ; Memory Page Number EX AF,AF' PUSH BC CALL SET_DOS_ON @@ -212,46 +220,53 @@ FDD_5x_LONG_READ: CALL NTRACK POP BC EX DE,HL -; LD A,B -; OR A -; JP Z,RETDOS IN A,(SLOT3) EX AF,AF' LD A,SYS_PAGE OUT (SLOT3),A LD IY,(FDD_INIT_TABLE.FDD_0.BytesPerSector) - LD XH,C + LD XH,C ; Memory Page Number LD A,(FDD_INIT_TABLE.FDD_0.SECTORS) LD C,A EX AF,AF' OUT (SLOT3),A .DSK_LP: LD A,D - EXX - CALL SEEK + EXX + PUSH BC + CALL SEEK + POP BC EXX PUSH DE PUSH BC PUSH HL - CALL READ_SECTOR + ;CALL READ_SECTOR + CALL FDD_RW_SECTOR JR C,ERRDOS - LD D,YH - LD E,YL + ; размер сектора + LD D,YH + LD E,YL + ; POP HL POP BC ADD HL,DE - JR NC,.THISRD - IN A,(SLOT3) - EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD D,#C2 - LD E,XH - LD A,(DE) - LD XH,A - EX AF,AF' - OUT (SLOT3),A - SET 7,H - SET 6,H + ; + CALL C,CHANGE_MEM_BLK + ; IN A,(SLOT3) + ; EX AF,AF' + ; LD A,SYS_PAGE + ; OUT (SLOT3),A + ; LD D,high SYS_PAGE.RAM_TABLE + ; LD E,XH + ; LD A,(DE) + ; LD XH,A + ; EX AF,AF' + ; OUT (SLOT3),A + ; ; SET 7,H + ; ; SET 6,H + ; LD A,%1100'0000 + ; OR H + ; LD H,A + ; .THISRD: POP DE LD A,C INC E @@ -261,7 +276,7 @@ FDD_5x_LONG_READ: INC D .NINC_T: DJNZ .DSK_LP .RETDOS: CALL SET_DOS_OFF - LD A,XH + LD A,XH ; Memory Page Number EX AF,AF' EX DE,HL POP IX @@ -276,12 +291,19 @@ FDD_5x_LONG_READ: JR NZ,.ADD8BIT INC B .ADD8BIT: ADD IX,BC - LD BC,0 - ADC HL,BC - LD B,A - XOR A - RET - ; + ;!TEST + ;LD BC,0 + ;ADC HL,BC + ;LD B,A + ;XOR A + ;RET + ; + LD B,A + RET NC + INC HL + XOR A + RET + ; ERRDOS: POP HL POP BC POP DE @@ -289,7 +311,7 @@ ERRDOS: POP HL EX DE,HL EX AF,AF' EXX - LD C,XH + LD C,XH ; Memory Page Number EXX LD A,B POP IX @@ -307,7 +329,7 @@ ERRDOS: POP HL ADC HL,BC POP BC EXX - LD A,C + LD A,C EXX EX AF,AF' SCF @@ -323,10 +345,9 @@ ERRDOS: POP HL ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;[]===========================================================[] -FDD_5x_WRITE: - EX AF,AF' - IN A,(SLOT3) - EX AF,AF' +FDD_5x_WRITE: EX AF,AF' + IN A,(SLOT3) + EX AF,AF' ;[]===========================================================[] ;Function: Long Write Sectors ; A - Disk @@ -340,6 +361,12 @@ FDD_5x_WRITE: ;?? B - Sector counter ;[]===========================================================[] FDD_5x_LONG_WRITE: + EXX + LD B,#A0 ;COMMAND WRITE + EXX + JP FDD_5x_LONG_READ.RW_Shared + +/* CALL SAVE_INTERRUPTS.switch_off CALL .Start JP SAVE_INTERRUPTS.restore @@ -348,8 +375,9 @@ FDD_5x_LONG_WRITE: PUSH BC PUSH HL PUSH IX + ; EX AF,AF' - LD C,A + LD C,A EX AF,AF' PUSH BC CALL SET_DOS_ON @@ -358,9 +386,6 @@ FDD_5x_LONG_WRITE: CALL NTRACK POP BC EX DE,HL -; LD A,B -; OR A -; JP Z,RETDOS IN A,(SLOT3) EX AF,AF' LD A,SYS_PAGE @@ -372,32 +397,41 @@ FDD_5x_LONG_WRITE: EX AF,AF' OUT (SLOT3),A .DSK_LP2: LD A,D - EXX - CALL SEEK + EXX + PUSH BC + CALL SEEK + POP BC EXX PUSH DE PUSH BC PUSH HL - CALL WR_SEC + CALL WR_SEC JR C,ERRDOS - LD D,YH - LD E,YL + ; размер сектора + LD D,YH + LD E,YL + ; POP HL POP BC ADD HL,DE - JR NC,.THISWR - IN A,(SLOT3) - EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD D,#C2 - LD E,XH - LD A,(DE) - LD XH,A - EX AF,AF' - OUT (SLOT3),A - SET 7,H - SET 6,H + ; + CALL C,CHANGE_MEM_BLK + ; IN A,(SLOT3) + ; EX AF,AF' + ; LD A,SYS_PAGE + ; OUT (SLOT3),A + ; LD D,high SYS_PAGE.RAM_TABLE + ; LD E,XH + ; LD A,(DE) + ; LD XH,A + ; EX AF,AF' + ; OUT (SLOT3),A + ; ; SET 7,H + ; ; SET 6,H + ; LD A,%1100'0000 + ; OR H + ; LD H,A + ; .THISWR: POP DE LD A,C INC E @@ -435,15 +469,16 @@ FDD_5x_LONG_WRITE: XOR A RET ; +*/ - - +/* ; ;------------------------------- ;READ SECTOR ;------------------------------- READ_SECTOR: LD D,5 ;RETRY COUNT -.RRETRY: ;DI +.HL_RETRY: ;DI + PUSH HL PUSH DE LD A,E INC A @@ -455,167 +490,203 @@ READ_SECTOR: LD D,5 ;RETRY COUNT ; LD B,4 ; счётчик LD C,FDC_93.Data - LD A,#80 ;!HARDCODE COMMAND READ + LD A,#80 ; COMMAND READ OUT (FDC_93.Command),A + ; .FDR001: IN A,(FDC_93.DrvCTRL) ;WAIT INTRQ or DRQ - AND #C0 - JR NZ,.FDR004 + AND %1100'0000 ;b6: DRQ (запрос данных = 1). b7: INTRQ (выполняется команда = 0). + JR NZ,.read_loop INC DE LD A,E OR D JR NZ,.FDR001 + ; DJNZ .FDR001 SCF JR .FDR005 + ;READ BYTE +.read_loop: INI +.wait_data: IN A,(FDC_93.DrvCTRL) + AND %1100'0000 ;b6: DRQ (запрос данных = 1). b7: INTRQ (выполняется команда = 0). + JR Z,.wait_data + JP P,.read_loop ; JUMP if "выполняется команда = 0" ; -.FDR004: INI ;READ BYTE -.FDR002: IN A,(FDC_93.DrvCTRL) - AND #C0 - JR Z,.FDR002 - JP P,.FDR004 .FDR005: EX AF,AF' - OUT (SLOT3),A + OUT (SLOT3),A EX AF,AF' ; POP DE + POP HL ;EI + LD A,BIOS.Error.NotReady + JR C,.ERR_XRD + ; IN A,(FDC_93.Command) LD C,A -;R01 ; JP C,ERRRD ;READ ERROR - ; [x] 29/06/2024 - ;JP C,.ERR_XRD - JR NC,.NO_ERR_XRD - DEC D - JR Z,.RSTOP - JR .RRETRY - ; -.NO_ERR_XRD: ; AND #7F - RET Z + RET Z ; Выход без ошибок + ; BIT 2,C JR NZ,.ERDATA + ; LD A,BIOS.Error.Seek - DEC D +.ERR_XRD: DEC D JR Z,.RSTOP + ; PUSH DE + PUSH HL CALL RESWG ; RESET_WG LD A,XL - CALL SEEK ; !!!!! посмотреть -.ERR_XRD: POP DE - JR .RRETRY + CALL SEEK ; !!!!! посмотреть + POP HL + POP DE + JR .HL_RETRY ; -.ERDATA: DEC D ; POTERIA DANNYH - JR NZ,.RRETRY +.ERDATA: DEC D ; потеря данных + JR NZ,.HL_RETRY + ; Error Read .ERRRD: LD A,BIOS.Error.Read .RSTOP: EX AF,AF' - LD A,#D0 - OUT (FDC_93.Command),A ;STOP OPERATION + LD A,#D0 + OUT (FDC_93.Command),A ;STOP OPERATION EX AF,AF' BIT 0,C SCF RET Z LD A,BIOS.Error.SectorNotFound - RET + RET ; ; ; +*/ ; ;------------------------------- ;WRITE SECTOR ;------------------------------- -WR_SEC: LD D,5 ;RETRY COUNT -.WRETRY: - ;DI - PUSH DE - LD A,E - INC A - OUT (FDC_93.Sector),A -.FDWRITE: - IN A,(SLOT3) - EX AF,AF' - LD A,XH - OUT (SLOT3),A - LD B,4 - LD C,FDC_93.Data - LD A,#A0 ;COMMAND WRITE - OUT (FDC_93.Command),A -.FDW001: - IN A,(FDC_93.DrvCTRL) ;WAIT INTRQ or DRQ - AND #C0 - JR NZ,.FDW004 - INC DE - LD A,E - OR D - JR NZ,.FDW001 - DJNZ .FDW001 - SCF - JR .FDW005 -.FDW004: - OUTI ;WRITE BYTE -.FDW002: - IN A,(FDC_93.DrvCTRL) - AND #C0 - JR Z,.FDW002 - JP P,.FDW004 -.FDW005: - EX AF,AF' - OUT (SLOT3),A - EX AF,AF' -;------------------------------- - POP DE - ;EI - IN A,(FDC_93.Command) - LD C,A -;R01 - JR C,.ERR_XWR - AND #7F - RET Z - BIT 6,C - LD A,BIOS.Error.WriteProtect - JR NZ,.WSTOP - BIT 2,C - JR NZ,.EWDATA - LD A,BIOS.Error.Seek - DEC D - JR Z,.WSTOP -.ERR_XWR: - PUSH DE - CALL RESWG ; RESET_WG - LD A,XL - CALL SEEK ; !!!!! посмотреть - POP DE - JR .WRETRY -.EWDATA: - DEC D ; POTERIA DANNYH - JR NZ,.WRETRY -.ERRWR: LD A,BIOS.Error.Write -.WSTOP: EX AF,AF' - LD A,#D0 - OUT (FDC_93.Command),A ;STOP OPERATION - EX AF,AF' - BIT 0,C - SCF - RET Z - LD A,BIOS.Error.SectorNotFound - RET - +FDD_RW_SECTOR: LD D,5 ;RETRY COUNT +.RETRY: DI + PUSH HL + PUSH DE + LD A,E + INC A + OUT (FDC_93.Sector),A + IN A,(SLOT3) + EX AF,AF' + LD A,XH + OUT (SLOT3),A + ; + LD B,4 + LD C,FDC_93.Data + EXX + LD A,B ; COMMAND read or write + EXX + OUT (FDC_93.Command),A + ; +.wait_loop: IN A,(FDC_93.DrvCTRL) ;WAIT INTRQ or DRQ + AND %1100'0000 ;b6: DRQ (запрос данных = 1). b7: INTRQ (выполняется команда = 0). + JR NZ,.RW_PROC + INC DE + LD A,E + OR D + JR NZ,.wait_loop + DJNZ .wait_loop + SCF + JR .after_rw ; error + ; +.RW_PROC: EXX + BIT 5,B + EXX + JR NZ,.write_loop + ;READ BYTE +.read_loop: INI +.wait_data_r: IN A,(FDC_93.DrvCTRL) + AND %1100'0000 ;b6: DRQ (запрос данных = 1). b7: INTRQ (выполняется команда = 0). + JR Z,.wait_data_r + JP P,.read_loop ; JUMP if "выполняется команда = 0" +.rw_return: ; +.after_rw: EX AF,AF' + OUT (SLOT3),A + EX AF,AF' + ; + POP DE + POP HL + ; прерывания + LD A,R + AND %1000'0000 + JR Z,.no_EI + EI +.no_EI: ; + LD A,BIOS.Error.NotReady + JR C,.CMD_ERROR + ; + IN A,(FDC_93.Command) + LD C,A + AND #7F + ; NORMAL EXIT + RET Z + ; + BIT 6,C + LD A,BIOS.Error.WriteProtect + JR NZ,.error_exit + ; + BIT 2,C + JR NZ,.data_lost + ; + LD A,BIOS.Error.Seek +.CMD_ERROR: DEC D + JR Z,.error_exit + ; + PUSH DE + PUSH HL + CALL RESWG ; RESET_WG + LD A,XL + CALL SEEK ; !!!!! посмотреть + POP HL + POP DE + JR .RETRY + ; +.data_lost: DEC D ; потеря данных + JR NZ,.RETRY + ; + EXX + BIT 5,B + EXX + LD A,BIOS.Error.Read ; Error Read + JR Z,.error_exit + ; + LD A,BIOS.Error.Write ; Error Write +.error_exit: EX AF,AF' + LD A,#D0 + OUT (FDC_93.Command),A ;STOP OPERATION + EX AF,AF' + BIT 0,C + SCF + RET Z + LD A,BIOS.Error.SectorNotFound + RET + ; + ;WRITE BYTE +.write_loop: OUTI +.wwait_data: IN A,(FDC_93.DrvCTRL) + AND %1100'0000 ;b6: DRQ (запрос данных = 1). b7: INTRQ (выполняется команда = 0). + JR Z,.wwait_data + JP P,.write_loop + JP .rw_return ; ; Врубает третью карту портов -SET_DOS_ON: - EX AF,AF' - LD A,CNF_PORT.CNF_3 + ROM.BIOS - OUT (SYS_PORT.ROM),A ; - OPEN - EX AF,AF' - RET +SET_DOS_ON: EX AF,AF' + LD A,CNF_PORT.CNF_3 + ROM.BIOS + OUT (SYS_PORT.ROM),A ; - OPEN + EX AF,AF' + RET ; Врубает нулевую карту портов -SET_DOS_OFF: - EX AF,AF' - LD A,CNF_PORT.CNF_0 + ROM.BIOS - OUT (SYS_PORT.ROM),A ; - CLOSE - EX AF,AF' - RET +SET_DOS_OFF: EX AF,AF' + LD A,CNF_PORT.CNF_0 + ROM.BIOS + OUT (SYS_PORT.ROM),A ; - CLOSE + EX AF,AF' + RET ; S_FDD: PUSH BC @@ -625,12 +696,12 @@ S_FDD: PUSH BC OUT (FDC_93.DrvCTRL),A IN A,(SLOT3) EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(FDD_INIT_TABLE.FDD_0.DISK) - AND #FE - OR B - LD (FDD_INIT_TABLE.FDD_0.DISK),A + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(FDD_INIT_TABLE.FDD_0.DISK) + AND #FE + OR B + LD (FDD_INIT_TABLE.FDD_0.DISK),A EX AF,AF' OUT (SLOT3),A POP BC @@ -672,10 +743,10 @@ FDD.SET1440: LD A,FDD_Density.SET_1440 ; SET_SPEED: IN A,(SLOT3) EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(FDD_INIT_TABLE.FDD_0.F144) - AND #80 + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(FDD_INIT_TABLE.FDD_0.F144) + AND #80 EX AF,AF' OUT (SLOT3),A EX AF,AF' @@ -687,116 +758,118 @@ FDD.SET720: LD A,FDD_Density.SET_720 ; прерывания должны быть отключены DISK_ID: EXX - CALL SET_SPEED - IN A,(FDC_93.Track) - OUT (FDC_93.Data),A - LD A,#18 ;!TODO выписать комманды ВГ ;SEARCH ; !HARDCODE - CALL EXECOM - LD C,4 ; счётчик -.loop_reg_C: LD A,#C0 - OUT (FDC_93.Command),A - LD HL,#F000 ; счётчик -.loop_reg_HL: IN A,(FDC_93.DrvCTRL) - AND #C0 - JR Z,.ID_LP4 - ; -.ID_LP2: IN A,(FDC_93.Data) -.ID_LP3: IN A,(FDC_93.DrvCTRL) - AND #C0 - JR Z,.ID_LP3 - JP P,.ID_LP2 + CALL SET_SPEED + IN A,(FDC_93.Track) + OUT (FDC_93.Data),A + LD A,#18 ;!TODO выписать комманды ВГ ;SEARCH ; !HARDCODE + CALL EXECOM + LD C,4 ; счётчик +.loop_reg_C: LD A,#C0 + OUT (FDC_93.Command),A + LD HL,#F000 ; счётчик +.loop_reg_HL: IN A,(FDC_93.DrvCTRL) + AND #C0 + JR Z,.ID_LP4 + ; +.ID_LP2: IN A,(FDC_93.Data) +.ID_LP3: IN A,(FDC_93.DrvCTRL) + AND #C0 + JR Z,.ID_LP3 + JP P,.ID_LP2 EXX IN A,(SLOT3) EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(FDD_INIT_TABLE.FDD_0.F144) + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(FDD_INIT_TABLE.FDD_0.F144) EX AF,AF' OUT (SLOT3),A EX AF,AF' AND #80 RET ; -.ID_LP4: DEC HL - LD A,H - OR L - JR NZ,.loop_reg_HL - CALL CHANGE_SPEED - DEC C - JR NZ,.loop_reg_C +.ID_LP4: DEC HL + LD A,H + OR L + JR NZ,.loop_reg_HL + CALL CHANGE_SPEED + DEC C + JR NZ,.loop_reg_C EXX SCF RET ; ; -SEEK: LD XL,A - LD C,A - IN A,(SLOT3) - EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(FDD_INIT_TABLE.FDD_0.DISK) - AND 1 - EX AF,AF' - OUT (SLOT3),A - EX AF,AF' - SRL C - JR C,.GT001 - OR #3C -.GT001: OR #2C - OUT (FDC_93.DrvCTRL),A - IN A,(FDC_93.Track) - CP C - PUSH BC - CALL NZ,P50ms - POP BC - LD A,C - OUT (FDC_93.Data),A - IN A,(FDC_93.Track) - CP C - EX AF,AF' ;R.TRACK==PHISICAL TRACK - LD A,#18 - CALL EXECOM - RET C - EX AF,AF' - LD A,C - OUT (FDC_93.Track),A - RET Z -.STOL: PUSH BC - CALL P50ms - POP BC - RET +SEEK: LD XL,A + LD C,A + IN A,(SLOT3) + EX AF,AF' + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(FDD_INIT_TABLE.FDD_0.DISK) + AND 1 + EX AF,AF' + OUT (SLOT3),A + EX AF,AF' + SRL C + JR C,.GT001 + ; + OR #3C +.GT001: OR #2C + OUT (FDC_93.DrvCTRL),A + IN A,(FDC_93.Track) + CP C + PUSH BC + CALL NZ,P50ms + ; + POP BC + LD A,C + OUT (FDC_93.Data),A + IN A,(FDC_93.Track) + CP C + EX AF,AF' ;R.TRACK==PHISICAL TRACK + LD A,#18 + CALL EXECOM + RET C + EX AF,AF' + LD A,C + OUT (FDC_93.Track),A + RET Z +.STOL: PUSH BC + CALL P50ms + POP BC + RET ; ;P750ms LD B,3 ;PMS2 LD A,255 ; CALL P1ms ; DJNZ PMS2 ; RET -P50ms: LD A,12 -.P1ms: LD C,255 -.PMS: DEC C - JR NZ,.PMS - DEC A - JR NZ,.P1ms - RET +P50ms: LD A,12 +.P1ms: LD C,255 +.PMS: DEC C + JR NZ,.PMS + DEC A + JR NZ,.P1ms + RET ; ; -RESWG: LD A,8 -EXECOM: OUT (FDC_93.Command),A - LD HL,#0000 ; счётчик -.WREST: DEC HL - LD A,H - OR L - SCF - RET Z - ; - IN A,(FDC_93.DrvCTRL) - AND #80 - JR Z,.WREST - ;AND A - RET +RESWG: LD A,8 + ; +EXECOM: OUT (FDC_93.Command),A + LD HL,#0000 ; счётчик +.WREST: DEC HL + LD A,H + OR L + SCF + RET Z + ; + IN A,(FDC_93.DrvCTRL) + AND #80 + JR Z,.WREST + RET ; ; @@ -804,35 +877,34 @@ EXECOM: OUT (FDC_93.Command),A ; HL:IX - SECTOR ; H - TRACK, L - SECTOR ;HL:IX/SECTOR_PER_TRACK -NTRACK: - PUSH HL - EX (SP),IX - POP HL - IN A,(SLOT3) - EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(FDD_INIT_TABLE.FDD_0.SECTORS) - LD C,A - LD B,0 - EX AF,AF' - OUT (SLOT3),A - XOR A -.NTRK: INC A - SBC HL,BC - JR NC,.NTRK - EX AF,AF' - LD A,XL - OR XH - JR Z,.NTRK3 - EX AF,AF' - DEC IX - JR .NTRK -.NTRK3: EX AF,AF' - ADD HL,BC - DEC A - LD H,A - RET +NTRACK: PUSH HL + EX (SP),IX + POP HL + IN A,(SLOT3) + EX AF,AF' + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(FDD_INIT_TABLE.FDD_0.SECTORS) + LD C,A + LD B,0 + EX AF,AF' + OUT (SLOT3),A + XOR A +.NTRK: INC A + SBC HL,BC + JR NC,.NTRK + EX AF,AF' + LD A,XL + OR XH + JR Z,.NTRK3 + EX AF,AF' + DEC IX + JR .NTRK +.NTRK3: EX AF,AF' + ADD HL,BC + DEC A + LD H,A + RET ; SAVE_INTERRUPTS: .switch_off: PUSH AF diff --git a/src/bios/exp/EXTENDED/IDE/ATAPI_DRV.ASM b/src/bios/exp/EXTENDED/IDE/ATAPI_DRV.ASM index b2455ed..c0115a7 100644 --- a/src/bios/exp/EXTENDED/IDE/ATAPI_DRV.ASM +++ b/src/bios/exp/EXTENDED/IDE/ATAPI_DRV.ASM @@ -151,9 +151,12 @@ ATAPI_5x_SET_PAR: ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;READ SECTOR(S) -ATAPI_5x_READ: EX AF,AF' +ATAPI_5x_READ: PUSH IY + LD C,0 ; признак short + EX AF,AF' IN A,(SLOT3) EX AF,AF' + JP ATAPI_5x_LONG_READ.main ;[]================================================================[#52] ;Function: Long Read Sectors ; A - Disk @@ -166,10 +169,11 @@ ATAPI_5x_READ: EX AF,AF' ; DE - Address + (Sector counter * Size sector) ;LONG READ SECTOR(S) ATAPI_5x_LONG_READ: - AND A + ;AND A ; PUSH IY - SAFE_PORTY_2 + LD C,1 ; признак long +.main: SAFE_PORTY_2 PUSH BC PUSH IX PUSH HL @@ -196,8 +200,10 @@ ATAPI_5x_LONG_READ: ; OUTPUT: ; RW_ATAPI_SECTORs: + PUSH BC LD C,IDE.Device.ATAPI CALL SELECT_DRIVE + POP BC RET C ; EXX @@ -232,16 +238,11 @@ RW_ATAPI_SECTORs: LD A,B LD (RAM_ATAPI_RW_CMD + ATAPI_PACKET.COUNTER+1),A ;R01 ; - ; EX AF,AF' - ; OUT (SLOT3),A - ; - ; POP AF - ; OUT (SLOT3),A + LD YL,C ; признак short/long из C в YL LD HL,RAM_ATAPI_RW_CMD CALL EXEC_PACKET_COMMAND.start ; .exit: POP BC - ;LD C,SLOT3 OUT (C),B RET ; @@ -262,9 +263,12 @@ RW_ATAPI_SECTORs: ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;WRITE SECTOR(S) -ATAPI_5x_WRITE: EX AF,AF' +ATAPI_5x_WRITE: PUSH IY + LD C,0 ; признак short + EX AF,AF' IN A,(SLOT3) EX AF,AF' + JP ATAPI_5x_LONG_WRITE.main ;[]================================================================[#53] ;Function: Long Write Sectors ; A - Disk @@ -277,10 +281,11 @@ ATAPI_5x_WRITE: EX AF,AF' ; DE - Address + (Sector counter * Size sector) ;WRITE SECTOR(S) ATAPI_5x_LONG_WRITE: - AND A + ;AND A ; PUSH IY - SAFE_PORTY_2 + LD C,1 ; признак long +.main: SAFE_PORTY_2 PUSH BC PUSH IX PUSH HL @@ -466,6 +471,7 @@ TRAY_FN: LD HL,ATAPI_CMD_PACKET.CLOSE ; #0B - ABORTED COMMAND ; #80 - TIME OUT EXEC_PACKET_COMMAND: +.error_ex: EX DE,HL .error: CP #FF .error_fail: SCF LD A,BIOS.Error.Failure @@ -475,14 +481,15 @@ EXEC_PACKET_COMMAND: RET ; .error_TimeOut: CP #FF + EX DE,HL JR Z,.error_fail LD A,BIOS.Error.ATAPI.TimeOut SCF RET ; -.start_sys_page: - LD A,SYS_PAGE - EX AF,AF' +; .start_sys_page: +; LD A,SYS_PAGE +; EX AF,AF' ; .start: XOR A ; признак того, что ошибка смены носителя должна обрабатываться в EXEC_PACKET_COMMAND .start_custom: EXX @@ -501,7 +508,7 @@ EXEC_PACKET_COMMAND: EXX CALL ATAPI_WAITPRT EXX - JR C,.error + JR C,.error_ex ; .READY: LD C,SLOT3 IN B,(C) @@ -534,7 +541,7 @@ EXEC_PACKET_COMMAND: LD C,H ; признак того, что ошибка смены носителя должна обрабатываться в EXEC_PACKET_COMMAND CALL ATAPI_WAITPRT EXX - JR C,.error + JR C,.error_ex ; EXX LD DE,256*(IDE.CtrlByte.DataRequest+IDE.CtrlByte.Error)+IDE.CtrlByte.DataRequest @@ -568,16 +575,133 @@ EXEC_PACKET_COMMAND: LD XH,A ; страница для R/W_LONG LD XL,0 EX AF,AF' - ; EX DE,HL -.AP_LOOP: EX DE,HL - ; IN A,(SLOT3) - ; EX AF,AF' ;>-----------> \ ; +.AP_LOOP: CALL ATAPI_CHECK_DRV + JP C,.error + RET Z + ;====== IF DATA REQUEST ===============================================; +.data_request: IN A,(SLOT3) + EX AF,AF' ;>-----------> \ + ; + LD A,XH + OUT (SLOT3),A + ; + ;LD BC,IDE.Read.ByteCountLow + ;IN E,(C) + ;INC C ;LD BC,IDE.Read.ByteCountHigh + ;IN D,(C) ;TRANSFER BLOCK SIZE + ;; + ;LD A,D + ;OR E + ;RET Z ;BLOCK = 0 + ;; уменьшаем счётчик загружаемых байтов в 2 раза. Читаем по 2 байта + ;SRL D + ;RR E + ;; + ;LD BC,IDE.Read.InterruptReason + ;IN A,(C) + ;AND IDE.InterruptReasonByte.IO + ;LD BC,IDE.Read.Data + CALL ATAPI_PREPARE_RW + RET NC + JR Z,.WRITE_DATA + ;READ +.read_loop: INI + INI + DEC DE + LD A,D + OR E + JR NZ,.read_loop + ; +.return_rw: EX AF,AF' ;<-----------< / + INC XL ;INC LOADED SECTORS + OUT (SLOT3),A + ; + LD A,H + OR L + JR NZ,.AP_LOOP + ; short/long + ; A = 0 + SUB YL + JR NC,.END_BUFFER + ; next page in mem block + CALL CHANGE_MEM_BLK + JR .AP_LOOP + ;WRITE +.WRITE_DATA: INC B ; LD BC,IDE.Write.Data +.write_loop: OUTI + OUTI + DEC DE + LD A,D + OR E + JR NZ,.write_loop + JR .return_rw + ; ; +.END_BUFFER: CALL ATAPI_CHECK_DRV + JP C,.error + JR NZ,ATAPI_IdlePasses.Enter + RET +;;;;;;;;;;;;;;;;; +ATAPI_IdlePasses: + CALL ATAPI_CHECK_DRV + JP C,EXEC_PACKET_COMMAND.error + JP Z,EXEC_PACKET_COMMAND.error_fail + ; +.Enter: ;LD BC,IDE.Read.ByteCountLow + ;IN E,(C) + ;INC C ;LD BC,IDE.Read.ByteCountHigh + ;IN D,(C) ;TRANSFER BLOCK SIZE + ;; + ;LD A,D + ;OR E + ;RET Z ;BLOCK = 0 + ;; + ;; уменьшаем счётчик загружаемых байтов в 2 раза. Читаем по 2 байта + ;SRL D + ;RR E + ;; + ;LD BC,IDE.Read.InterruptReason + ;IN A,(C) + ;AND IDE.InterruptReasonByte.IO + ;LD BC,IDE.Read.Data + CALL ATAPI_PREPARE_RW + RET NC + JR Z,.write_data + ; +.read_loop: IN F,(C) ; читаем по 1 разу с чётного адреса, читается WORD + DEC DE + LD A,D + OR E + JR NZ,.read_loop + JR ATAPI_IdlePasses + ; +.write_data: ; A = 0 + OUT (C),A ; кидаем 0 в регистр защёлку IDE + INC B +.write_loop: XOR A + OUT (C),A ; пишем по 1 разу в нечётный адрес, пишется WORD + DEC DE + LD A,D + OR E + JR NZ,.write_loop + JR ATAPI_IdlePasses +; + + +; выход: +; CF,ZF ATAPI_WAITPRT Error или Check Condition со внешней обработкой +; ZF No errors, no data request +; NZ,NC DATA REQUEST +; CF Error +ATAPI_CHECK_DRV: + ;EX DE,HL EXX CALL ATAPI_WAITPRT EXX - JP C,.error + ; ZF=1 + ;JP C,.error + RET C ; ; [ ] media change. а надо ли тут? ;!FIXIT лучше блокировать носитель LD A,high IDE.Read.Status @@ -586,21 +710,17 @@ EXEC_PACKET_COMMAND: AND IDE.CtrlByte.DataRequest + IDE.CtrlByte.Error RET Z ;NO DATA REQUEST. A = 0: BIOS.Error.NoErrors RRA ; Checking IDE.CtrlByte.CheckCondition - JR NC,.data_request + ;JR NC,.data_request + RET NC ; признак того, что ошибка смены носителя должна обрабатываться в EXEC_PACKET_COMMAND EXX DEC C ; признак того, что ошибка смены носителя должна обрабатываться в EXEC_PACKET_COMMAND EXX RET Z ; выход, если ошибка обрабатывается не в EXEC_PACKET_COMMAND + JP ATAPI_CHECK_ERROR ; - JP ATAPI_CHECK_ERROR -;====== IF DATA REQUEST ===============================================; -.data_request: IN A,(SLOT3) - EX AF,AF' ;>-----------> \ - ; - LD A,XH - OUT (SLOT3),A - EX DE,HL + +ATAPI_PREPARE_RW: LD BC,IDE.Read.ByteCountLow IN E,(C) INC C ;LD BC,IDE.Read.ByteCountHigh @@ -618,54 +738,17 @@ EXEC_PACKET_COMMAND: IN A,(C) AND IDE.InterruptReasonByte.IO LD BC,IDE.Read.Data - JR Z,.WRITE_DATA - ;READ - ; проверка на тупость кодера - ; CF=0 - ; ADC HL,DE - ; JR Z,.good_buffer - ; JR C,.error_buffer - ; -; .good_buffer: AND A -; SBC HL,DE + SCF + RET -.read_loop: INI - INI - DEC DE - LD A,D - OR E - JR NZ,.read_loop - ; -.return_rw: INC XL ;INC LOADED SECTORS - EX AF,AF' ;<-----------< / - OUT (SLOT3),A - ; - LD A,H - OR L - JR NZ,.AP_LOOP - ; next page in mem block - LD HL,#C000 - IN A,(SLOT3) - EX AF,AF' ;>-----------> \ - LD A,SYS_PAGE - OUT (SLOT3),A - LD D,high SYS_PAGE.RAM_TABLE - LD E,XH - LD A,(DE) - LD XH,A - EX AF,AF' ;<-----------< / - OUT (SLOT3),A - JR .AP_LOOP - ;WRITE -.WRITE_DATA: INC B ; LD BC,IDE.Write.Data -.write_loop: OUTI - OUTI - DEC DE - LD A,D - OR E - JR NZ,.write_loop - JR .return_rw - ; + +; .AddrOverflow: EX DE,HL +; AND A +; SBC HL,DE +; EX DE,HL +; RET + +; ; !TODO холостое чтение ; .error_buffer: AND A ; SBC HL,DE @@ -702,6 +785,8 @@ ATAPI_GET_ERROR_REG: ;----------------------------------------------------------------------; ; D - MASK, E - PATTERN +; !!! некоторые функции надеются, что на выходе всегда ZF +; не должна трогать рег. C ATAPI_WAITPRT: LD DE,256*IDE.CtrlByte.Busy + 0 .Custom: LD B,100 LD HL,#0000 @@ -762,7 +847,7 @@ ATAPI_READ_CAPACITY_DATA: JR NZ,.pause ; JP .loop - RET + ;RET ;----------------------------------------------------------------------; @@ -775,6 +860,9 @@ ATAPI_READ_CAPACITY_DATA: ;----------------------------------------------------------------------; ATAPI_MEDIA_ERROR: + PUSH IX + PUSH HL + ; IN A,(SLOT3) PUSH AF LD A,SYS_PAGE @@ -826,6 +914,8 @@ ATAPI_MEDIA_ERROR: LD (IY+IDE.HDD_INIT_TABLE.SectorSize + 1),L ; .exit: POP AF + POP HL + POP IX OUT (SLOT3),A LD A,C SCF diff --git a/src/bios/exp/EXTENDED/IDE/ATA_DRV.ASM b/src/bios/exp/EXTENDED/IDE/ATA_DRV.ASM index 9fa6952..826aec7 100644 --- a/src/bios/exp/EXTENDED/IDE/ATA_DRV.ASM +++ b/src/bios/exp/EXTENDED/IDE/ATA_DRV.ASM @@ -161,10 +161,12 @@ ATA_5x_SET_PAR: ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;READ SECTOR(S) -ATA_5x_READ: - EX AF,AF' - IN A,(SLOT3) - EX AF,AF' +ATA_5x_READ: PUSH IY + LD C,0 ; признак short + EX AF,AF' + IN A,(SLOT3) + EX AF,AF' + JP ATA_5x_LONG_READ.main ;[]================================================================[#52] ;Function: Long Read Sectors ; A - Disk @@ -179,7 +181,8 @@ ATA_5x_READ: ;LONG READ SECTOR(S) ATA_5x_LONG_READ: PUSH IY - SAFE_PORTY_2 + LD C,1 ; признак long +.main: SAFE_PORTY_2 PUSH BC PUSH IX PUSH HL @@ -222,8 +225,12 @@ ATA_5x_LONG_READ: PUSH BC LD B,0 ADD IX,BC - LD C,B - ADC HL,BC + ; + ;LD C,B + ;ADC HL,BC + JR NC,.no_inc_hl + INC HL +.no_inc_hl: ; POP BC POP AF SUB C @@ -245,10 +252,12 @@ ATA_5x_LONG_READ: ; HL:IX - Sector + Sector counter ; DE - Address + (Sector counter * Size sector) ;WRITE SECTOR(S) -ATA_5x_WRITE: - EX AF,AF' - IN A,(SLOT3) - EX AF,AF' +ATA_5x_WRITE: PUSH IY + LD C,0 ; признак short + EX AF,AF' + IN A,(SLOT3) + EX AF,AF' + JP ATA_5x_LONG_WRITE.main ;[]================================================================[#53] ;Function: Long Write Sectors ; A - Disk @@ -262,7 +271,8 @@ ATA_5x_WRITE: ;WRITE SECTOR(S) ATA_5x_LONG_WRITE: PUSH IY - SAFE_PORTY_2 + LD C,1 ; признак long +.main: SAFE_PORTY_2 PUSH BC PUSH IX PUSH HL @@ -273,70 +283,19 @@ ATA_5x_LONG_WRITE: CALL RW_ATA_SECTORs ; JP ATA_5x_LONG_READ.shared -/* - EX DE,HL - JP C,.error - LD A,XH - EX AF,AF' - ; - POP HL - POP IX - POP BC - XOR A - CP B - LD C,B - LD B,A - JR NZ,WNOT256 - ; - INC B - ADD IX,BC - LD B,C - ADC HL,BC - ;EX AF,AF' - JR RST8WRR - ; -WNOT256 ADD IX,BC - LD C,B - ADC HL,BC - JR RST8WRR - -.error: LD B,A - LD C,XL - LD A,XH - EX AF,AF' - POP HL - POP IX - PUSH BC - LD B,0 - ADD IX,BC - LD C,B - ADC HL,BC - POP BC - POP AF - SUB C - LD C,A - LD A,B - LD B,C - ;R03 - SCF ;R03 - ;EX AF,AF' ;R03 ;!FIXIT намудрил он чёт в этом R03 - ; -RST8WRR: RESTORE_PORTY - POP IY - ;EX AF,AF' - RET -*/ - ;███████████████████████████████████████████████████████████████████████████████████████████████████████; ; A - Disk ; HL:IX - Sector ; DE - Address ; B - Sector counter +; C - short/long ; A'- Memory Page Number ; CF'=1 - write, CF'=0 - read -RW_ATA_SECTORs: LD C,IDE.Device.HDD +RW_ATA_SECTORs: PUSH BC ; признак short/long в C + LD C,IDE.Device.HDD CALL SELECT_DRIVE + POP BC ; признак short/long в C RET C ; EXX @@ -346,12 +305,16 @@ RW_ATA_SECTORs: LD C,IDE.Device.HDD ; EX AF,AF' PUSH AF ; memory page number + PUSH BC ; признак short/long в C PUSH DE ; Address CALL PRESET + ; IY из SELECT_DRIVE больше не нужен + ; POP HL ; Address + POP IY ; признак short/long в YL POP AF ; memory page number LD XL,0 - LD XH,A + LD XH,A ; memory page number LD BC,IDE.Write.Command LD A,IDE.CMD.ATA.WriteSectorsWithRetry JR C,.set_command ; CF = r/w @@ -386,40 +349,43 @@ RW_ATA_SECTORs: LD C,IDE.Device.HDD ; ; ; ; ; ; CF=0 .return_rw: EX AF,AF' ;<-----------< / + INC XL ;INC LOADED SECTORS OUT (SLOT3),A ; LD A,H OR L - JR NZ,.W44 + JR NZ,.end_pass + ; short/long + ; A = 0 + SUB YL + JR NC,.END_BUFFER ; next page in mem block - ; сделать если не RW_LONG, то холостые чтение/запись и выход с ошибкой - LD HL,#C000 - IN A,(SLOT3) - EX AF,AF' ;>-----------> \ - LD A,SYS_PAGE - OUT (SLOT3),A - LD D,high SYS_PAGE.RAM_TABLE - LD E,XH - LD A,(DE) - LD XH,A - EX AF,AF' ;<-----------< / - OUT (SLOT3),A + CALL CHANGE_MEM_BLK + ; LD HL,#C000 + ; IN A,(SLOT3) + ; EX AF,AF' ;>-----------> \ + ; LD A,SYS_PAGE + ; OUT (SLOT3),A + ; LD D,high SYS_PAGE.RAM_TABLE + ; LD E,XH + ; LD A,(DE) + ; LD XH,A + ; EX AF,AF' ;<-----------< / + ; OUT (SLOT3),A ; -.W44: INC XL ;INC LOADED SECTORS +.end_pass: ;INC XL ;INC LOADED SECTORS EXX CALL WAITPRT EXX RET C + ; + ;INC XL ;INC LOADED SECTORS LD BC,IDE.Read.Status IN A,(C) BIT IDE.CtrlBit.DataRequest,A + RET Z ; - RET Z - JP .big_loop - ;JP NZ,.big_loop - ;XOR A - ;RET - ; + JP .big_loop ; .write_sector: ; WRITE SECTOR 512 bytes ;!HARDCODE sector size INC B ; LD BC,IDE.Write.Data @@ -431,9 +397,49 @@ RW_ATA_SECTORs: LD C,IDE.Device.HDD JR NZ,.loop SCF JP .return_rw - ; ; ; ; ; - - ;ENDIF + ; ; +.END_BUFFER: CALL ATA_IdlePasses.CHECK_DRV + JR NZ,ATA_IdlePasses.Enter + RET +;;;;;;;;;;;;;;;;; +ATA_IdlePasses: CALL .CHECK_DRV + JR NZ,.Enter + ; + RET C + LD A,BIOS.Error.Failure + SCF + RET + ; +.Enter: XOR A ; счётчик для READ_ZEROS, данные для .WrZeros + EX AF,AF' + LD BC,IDE.Read.Data + JR C,.WrZeros + ; READ > /dev/null + EX AF,AF' +.RdLoop: IN F,(C) ; читаем по 1 разу с чётного адреса, читается WORD + DEC A + JR NZ,.RdLoop + JR ATA_IdlePasses + ; WRITE ZEROS +.WrZeros: EX AF,AF' + ; +.WrLoop: OUT (C),A + DJNZ .WrLoop + ; +.WrLoop2: OUT (C),A + DJNZ .WrLoop2 + JR ATA_IdlePasses + ; +.CHECK_DRV: EXX + CALL WAITPRT + EXX + RET C + ; + LD BC,IDE.Read.Status + IN A,(C) + BIT IDE.CtrlBit.DataRequest,A + RET +;!TODO доделать эту же хурму для других устройств ;███████████████████████████████████████████████████████████████████████████████████████████████████████; /* IFN OPTIMIZE_RW_PROCEDURE @@ -523,7 +529,7 @@ WRITE_ATA_SECTORs: ; A - Disk ; HL:IX - Sector ; B - Sector counter -;Return: None +;Return: CF - error ;VERIFY SECTOR(S) ATA_5x_VERIFY: PUSH IY SAFE_PORTY_2 @@ -543,105 +549,119 @@ ATA_5x_VERIFY: PUSH IY CALL WAITPRT EXX RET C - PUSH DE + ;PUSH DE + ; IN A,(SLOT3) + ; PUSH AF CALL PRESET - POP HL + ; POP AF + ; OUT (SLOT3),A + ;POP HL LD BC,IDE.Write.Command LD A,IDE.CMD.ATA.ReadVerifySectorsWithRetry OUT (C),A LD BC,IDE.Read.Status IN A,(C) - ;BIT IDE.CtrlBit.Error,A RRA ;BIT IDE.CtrlBit.Error,A : SCF : RET NZ RET C ; - CALL WAITPRT - RET C - XOR A - RET + JP WAITPRT + ;RET C + ;XOR A + ;RET ;[]================================================================[#54] ; HL:IX - LBA SECTOR ; B - SECTOR COUNTER -PRESET: LD A,B - LD BC,IDE.Write.Counter - OUT (C),A - ; - IN A,(SLOT3) - EX AF,AF' - LD A,SYS_PAGE - OUT (SLOT3),A - LD A,(IY+IDE.HDD_INIT_TABLE.DRV_Flags) - LD BC,IDE.Write.DeviceHead - OUT (C),A - ;бит CHS/LBA ;!FIXIT сделать метками номера бит - AND %0100'0000 - LD E,XL - LD D,XH - CALL Z,LBA_CHS - LD BC,IDE.Write.Sector - OUT (C),E ;LBA 0..7 - ; - INC C ; LD BC,IDE.Write.CylinderLow - OUT (C),D ;LBA 8..15 - INC C ; LD BC,IDE.Write.CylinderHigh - OUT (C),L ;LBA 16..23 - LD BC,IDE.Read.Control - IN A,(C) - AND #F0 ;!HARDCODE DRIVE/HEAD REGISTER PHISICAL DISK bitmask - OR H ;LBA 24..27 - INC B ; LD BC,IDE.Write.DeviceHead - ; - OUT (C),A - EX AF,AF' - OUT (SLOT3),A - AND A - RET +; выход: SLOT3 = SYS_PAGE +PRESET: LD A,B + LD BC,IDE.Write.Counter + OUT (C),A + ; + IN A,(SLOT3) + EX AF,AF' + LD A,SYS_PAGE + OUT (SLOT3),A + LD A,(IY+IDE.HDD_INIT_TABLE.DRV_Flags) + LD BC,IDE.Write.DeviceHead + OUT (C),A + ;бит CHS/LBA ;!FIXIT сделать метками номера бит + AND %0100'0000 + LD E,XL + LD D,XH + CALL Z,LBA_CHS + LD BC,IDE.Write.Sector + OUT (C),E ;LBA 0..7 + ; + INC C ; LD BC,IDE.Write.CylinderLow + OUT (C),D ;LBA 8..15 + INC C ; LD BC,IDE.Write.CylinderHigh + OUT (C),L ;LBA 16..23 + LD BC,IDE.Read.Control + IN A,(C) + AND #F0 ;!HARDCODE DRIVE/HEAD REGISTER PHISICAL DISK bitmask + OR H ;LBA 24..27 + INC B ; LD BC,IDE.Write.DeviceHead + ; + OUT (C),A + EX AF,AF' + OUT (SLOT3),A + ;AND A + RET +;PRESET ; + ; HL:DE - SECTOR OFFSET -LBA_CHS: - LD C,(IY+IDE.HDD_INIT_TABLE.SectorsPerCylinderLow) - LD B,(IY+IDE.HDD_INIT_TABLE.SectorsPerCylinderHigh) -; HL:DE / BC => DE:IX HL-OSTATOK -DIV32X: LD XH,D - LD XL,E - EX DE,HL - LD HL,0 - LD A,#20 -DIV011: ADD IX,IX - EX DE,HL - ADC HL,HL - EX DE,HL - ADC HL,HL - SBC HL,BC - JR NC,DIV012 - ADD HL,BC - DEC A - JR NZ,DIV011 - JR DIV014 -DIV012: INC IX - DEC A - JR NZ,DIV011 -DIV014: LD E,(IY+IDE.HDD_INIT_TABLE.SectorsPerTrack) - LD D,0 - XOR A -CHS005: INC A - SBC HL,DE - JR NC,CHS005 - ADD HL,DE - DEC A - LD H,A - LD E,L - INC E - LD D,XL - LD A,XH - LD L,A - RET +LBA_CHS: LD C,(IY+IDE.HDD_INIT_TABLE.SectorsPerCylinderLow) + LD B,(IY+IDE.HDD_INIT_TABLE.SectorsPerCylinderHigh) + ; +DIV32X: ;HL:DE / BC => DE:IX HL-OSTATOK + LD XH,D + LD XL,E + EX DE,HL + LD HL,0 + LD A,#20 + ; +.loop: ADD IX,IX + EX DE,HL + ADC HL,HL + EX DE,HL + ADC HL,HL + SBC HL,BC + JR NC,.DIV012 + ; + ADD HL,BC + DEC A + JR NZ,.loop + ; + JR .DIV014 + ; +.DIV012: INC IX + DEC A + JR NZ,.loop + ; +.DIV014: LD E,(IY+IDE.HDD_INIT_TABLE.SectorsPerTrack) + LD D,0 + XOR A + ; +.loop2: INC A + SBC HL,DE + JR NC,.loop2 + ; + ADD HL,DE + DEC A + LD H,A + LD E,L + INC E + LD D,XL + LD A,XH + LD L,A + RET ;----------------------------------------------------------------------; ; D - MASK ; E - PATTERN +; !!! некоторые функции надеются, что на выходе всегда ZF WAITPRT: LD DE,256*(IDE.CtrlByte.Busy+IDE.CtrlByte.Ready+IDE.CtrlByte.Error)+IDE.CtrlByte.Ready .custom: LD BC,IDE.Read.Status LD HL,#0000 ; задержка ;!HARDCODE @@ -663,7 +683,8 @@ WAITPRT: LD DE,256*(IDE.CtrlByte.Busy+IDE.CtrlByte.Ready+IDE.CtrlByte.Error)+IDE ; .error: LD A,BIOS.Error.NotReady SCF - RET + RET + ; .ok: POP HL RET ;----------------------------------------------------------------------; diff --git a/src/bios/exp/EXTENDED/IDE/shared.asm b/src/bios/exp/EXTENDED/IDE/shared.asm index f83e1f6..d4dbc7e 100644 --- a/src/bios/exp/EXTENDED/IDE/shared.asm +++ b/src/bios/exp/EXTENDED/IDE/shared.asm @@ -68,6 +68,23 @@ SELECT_DRIVE: AND #0F ;======================================================================= +;======================================================================= +; next page in mem block +CHANGE_MEM_BLK: LD HL,#C000 + IN A,(SLOT3) + EX AF,AF' ;>-----------> \ + LD A,SYS_PAGE + OUT (SLOT3),A + LD D,high SYS_PAGE.RAM_TABLE + LD E,XH + LD A,(DE) + LD XH,A + EX AF,AF' ;<-----------< / + OUT (SLOT3),A + RET +;======================================================================= + + ;======================================================================= ;Function: Detect Disk ; A - Disk diff --git a/src/bios/exp/FUNC_LOW_PRINT.ASM b/src/bios/exp/FUNC_LOW_PRINT.ASM index fbfba05..5b72936 100644 --- a/src/bios/exp/FUNC_LOW_PRINT.ASM +++ b/src/bios/exp/FUNC_LOW_PRINT.ASM @@ -1659,28 +1659,27 @@ LP_PR_LINE_DIR: ; CF - XY-mode ; DE - место символа в окне, если CF=1 ; HL - адрес с выводимой строкой -; B - разделитель +; B - цвет консоли (используется при скролле и очистке окна) ; IY - два спец.символа для выхода с CF=1. Должны быть равны B, если не нужны -; A' - цвет консоли (используется при скролле и очистке окна) ; CF' - выводить символ с атрибутами ;;;;;;;;;;;;;;;;; .START: PUSH IX LD XL,A ; атрибуты выводимого символа ; EX AF,AF' - PUSH AF ; цвет консоли, attr-mode + PUSH AF ; attr-mode EX AF,AF' ; IN A,(SLOT3) LD C,A CALL LP_BEG_P CALL C,LP_SET_CUR ; mode for DE - POP AF ; цвет консоли, attr-mode + POP AF ; attr-mode + LD A,B + ; далее рег B свободен, можно задействовать LD (SYS_PAGE.SYS_WORK2),A ; цвет консоли EXX - LD C,0 - JR NC,.loop - INC C ; C' - attr flag. выводить атрибут + RL C ; C' - attr-mode. выводить атрибут .loop: LD A,D OUT (PORT_Y),A EXX @@ -1690,7 +1689,7 @@ LP_PR_LINE_DIR: LD A,(HL) LD XH,A INC HL - CP B + AND A JR Z,.EXIT CP YH JR Z,.EXIT_SpecSymbol diff --git a/src/bios/shared/DEFINES.INC b/src/bios/shared/DEFINES.INC index d619abc..2d4d0a2 100644 --- a/src/bios/shared/DEFINES.INC +++ b/src/bios/shared/DEFINES.INC @@ -17,6 +17,7 @@ BETA_RC EQU 0 ; DEFINE LOGO_DELAY_NORM 100 ; DEFINE LOGO_DELAY_MAX 130 ; ;----------------------------[ TEST ]---------------------------; + DEFINE ERROR_POST_5 0 ; виснуть на ошибке в POST 5 DEFINE TEST_INT 1 ; Тестовый обработчик пользовательского INT DEFINE NEW_FEATURE 0 ; !TODO пункты в сетап ;DEFINE HDDwriteProtect 0 ; старая фишка для функций 5x diff --git a/src/bios/shared/RECOVERY.IMG b/src/bios/shared/RECOVERY.IMG index b01f68cf518598b90ec8336cd393a3d8dc9b6673..aaec28689d929223a64255ecfbdceb98d9ce0bb6 100755 GIT binary patch delta 14060 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 Q_3QJNdFc4tIyCG50@MZ9J^%m! delta 13908 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 GUH=0gY;8FJ