есть исходник, который классно демонстирует логику работы с шиной SMBus.
SPD на SMBus шине. после запуска компа, биос выключает эту шину.
её отправили в хвост архитектуры к южному мосту. если мы хотим прочитать её, нужно чз южный мост регистры чипсета настроить. класс 0C5000h (см.Несвижский). приведу цитату из хакера..
1) Программирование конфигурационных регистров LPC Bridge.
Локализуем в конфигурационном пространстве блок регистров с координатами:
Его идентификаторы: Vendor ID = 8086h, Device ID = 24C0h.
В этом блоке, по адресу 00F2h расположен 8-битный регистр 'Function Disable Register'.
Бит 3 указанного регистра управляет разрешением доступа к конфигурационным регистрам контроллера SMBus: 0=доступ разрешен, 1=доступ запрещен. Устанавливаем указанный бит в "0", т.е. разрешаем доступ. Это необходимо, т.к. в некоторых платах, BIOS перед загрузкой ОС оставляет этот бит в состоянии "1", при этом доступ к контроллеру SMBus по умолчанию запрещен.
2) Программирование конфигурационных регистров контроллера SMBus.
Локализуем в конфигурационном пространстве блок регистров с координатами:
Его идентификаторы: Vendor ID = 8086h, Device ID = 24C3h.
Назначаем диапазон портов ввода-вывода для контроллера SMBus, для этого записываем значение базового адреса диапазона в регистр SMB_BASE по адресу 0020h. В регистре Command Register, расположенном по адресу 0004h устанавливаем бит 0 (I/O Space Enable bit) в "1", что обеспечивает разрешение доступа к диапазону портов ввода-вывода контроллера SMBus.
Разрешаем функционирование контроллера SMBus, для этого устанавливаем в "1" бит 0 регистра по адресу 0040h (это бит SMBus Host Enable регистра SMBus Host Configuration). Если BIOS, перед загрузкой ОС, оставил контроллер SMBus в разрешенном состоянии (это можно определить по состоянию разрешающих битов, описанных выше), программа не должна повторно выполнять его разрешение, в этом случае пропускаем данные действия. Подробности в [2].
3) Начинаем взаимодействие с контроллером SMBus через его диапазон портов ввода-вывода.
Базовый адрес этого диапазона, присвоенный контроллеру на шаге 2, ниже обозначен как SMB_Base. Если контроллер уже был включен на момент запуска программы и шаг 2 был пропущен, то в качестве SMB_Base используем исходное значение базового адреса (установленное процедурой BIOS POST).
Обнуляем статусные биты в регистре Host Status (SMB_Base+0) для подготовки контроллера к очередной операции. Биты этого регистра используют дисциплину Read/Write Clear, и обнуляются при записи "1" в них. Подробности в [2].
4) Передаем 8-битный адрес ячейки микросхемы SPD, которую требуется прочитать.
Он записывается в регистр Host Command (SMB_Base+3). При выполнении транзакции на шине SMBus, значение этого регистра передается в поле Command. Подробности в [11-12].
5) Передаем 8-битный адрес микросхемы SPD, к которой выполняется обращение.
Он записывается в регистр Transmit Slave Address (SMB_Base+4). При выполнении транзакции на шине SMBus, значение этого регистра передается в поле Slave Address. Формат адреса устройства: биты 7-4 при адресации SPD всегда равны 1010b. Биты 3-1 определяют номер микросхемы SPD для одного из восьми модулей DIMM: 000b=DIMM0 … 111b=DIMM7. Бит 0 определяет тип операции: 0=запись, 1=чтение.
Пример: для чтения SPD модуля DIMM2 необходимо установить 10100101b = A5h.
6) Запускаем выполнение транзакции, параметры которой были подготовлены на шагах 4 и 5.
Для этого необходимо записать код операции в регистр Host Control (SMB_Base+2). В соответствии с документом [2], для запуска операции передачи байта используется код 01001000b = 48h. Отметим, что направление передачи байта (чтение или запись), определяется битом 0 регистра Transmit Slave Address, установленного на шаге 5.
7) После выполнения шага 6, контроллер SMBus начинает операцию чтения байта из SPD.
Программа должна ожидать завершения операции. Опрашиваем состояние бита Host Busy, это бит 0 регистра Host Status (SMB_Base+0). По значению Host Busy=1 определяем момент начала операции, затем ожидаем Host Busy=0, то есть завершения операции. Отсутствие ожидаемого события в течение заданного интервала (около 50 мс) интерпретируется как ошибка – таймаут шины.
8) Считываем из регистра Host Data 0 (SMB_Base+5) байт, прочитанный из SPD.
Его значение достоверно только при отсутствии ошибок.
9) Проверяем отсутствие ошибок.
Для этого считываем регистр Host Status (SMB_Base+0) и анализируем статусные биты. Согласно документу [2], после успешного завершения транзакции, состояние битов 4-1 должно быть 0001b. Маскируем указанное битовое поле и проверяем его значение.
SPD на SMBus шине. после запуска компа, биос выключает эту шину.
её отправили в хвост архитектуры к южному мосту. если мы хотим прочитать её, нужно чз южный мост регистры чипсета настроить. класс 0C5000h (см.Несвижский). приведу цитату из хакера..
1) Программирование конфигурационных регистров LPC Bridge.
Локализуем в конфигурационном пространстве блок регистров с координатами:
Это устройство LPC Bridge, входящее в состав "южного моста" Intel ICH4.
Его идентификаторы: Vendor ID = 8086h, Device ID = 24C0h.
В этом блоке, по адресу 00F2h расположен 8-битный регистр 'Function Disable Register'.
Бит 3 указанного регистра управляет разрешением доступа к конфигурационным регистрам контроллера SMBus: 0=доступ разрешен, 1=доступ запрещен. Устанавливаем указанный бит в "0", т.е. разрешаем доступ. Это необходимо, т.к. в некоторых платах, BIOS перед загрузкой ОС оставляет этот бит в состоянии "1", при этом доступ к контроллеру SMBus по умолчанию запрещен.
2) Программирование конфигурационных регистров контроллера SMBus.
Локализуем в конфигурационном пространстве блок регистров с координатами:
Это устройство 'SMBus Controller', входящее в состав "южного моста" Intel ICH4.
Его идентификаторы: Vendor ID = 8086h, Device ID = 24C3h.
Назначаем диапазон портов ввода-вывода для контроллера SMBus, для этого записываем значение базового адреса диапазона в регистр SMB_BASE по адресу 0020h. В регистре Command Register, расположенном по адресу 0004h устанавливаем бит 0 (I/O Space Enable bit) в "1", что обеспечивает разрешение доступа к диапазону портов ввода-вывода контроллера SMBus.
Разрешаем функционирование контроллера SMBus, для этого устанавливаем в "1" бит 0 регистра по адресу 0040h (это бит SMBus Host Enable регистра SMBus Host Configuration). Если BIOS, перед загрузкой ОС, оставил контроллер SMBus в разрешенном состоянии (это можно определить по состоянию разрешающих битов, описанных выше), программа не должна повторно выполнять его разрешение, в этом случае пропускаем данные действия. Подробности в [2].
3) Начинаем взаимодействие с контроллером SMBus через его диапазон портов ввода-вывода.
Базовый адрес этого диапазона, присвоенный контроллеру на шаге 2, ниже обозначен как SMB_Base. Если контроллер уже был включен на момент запуска программы и шаг 2 был пропущен, то в качестве SMB_Base используем исходное значение базового адреса (установленное процедурой BIOS POST).
Обнуляем статусные биты в регистре Host Status (SMB_Base+0) для подготовки контроллера к очередной операции. Биты этого регистра используют дисциплину Read/Write Clear, и обнуляются при записи "1" в них. Подробности в [2].
4) Передаем 8-битный адрес ячейки микросхемы SPD, которую требуется прочитать.
Он записывается в регистр Host Command (SMB_Base+3). При выполнении транзакции на шине SMBus, значение этого регистра передается в поле Command. Подробности в [11-12].
5) Передаем 8-битный адрес микросхемы SPD, к которой выполняется обращение.
Он записывается в регистр Transmit Slave Address (SMB_Base+4). При выполнении транзакции на шине SMBus, значение этого регистра передается в поле Slave Address. Формат адреса устройства: биты 7-4 при адресации SPD всегда равны 1010b. Биты 3-1 определяют номер микросхемы SPD для одного из восьми модулей DIMM: 000b=DIMM0 … 111b=DIMM7. Бит 0 определяет тип операции: 0=запись, 1=чтение.
Пример: для чтения SPD модуля DIMM2 необходимо установить 10100101b = A5h.
6) Запускаем выполнение транзакции, параметры которой были подготовлены на шагах 4 и 5.
Для этого необходимо записать код операции в регистр Host Control (SMB_Base+2). В соответствии с документом [2], для запуска операции передачи байта используется код 01001000b = 48h. Отметим, что направление передачи байта (чтение или запись), определяется битом 0 регистра Transmit Slave Address, установленного на шаге 5.
7) После выполнения шага 6, контроллер SMBus начинает операцию чтения байта из SPD.
Программа должна ожидать завершения операции. Опрашиваем состояние бита Host Busy, это бит 0 регистра Host Status (SMB_Base+0). По значению Host Busy=1 определяем момент начала операции, затем ожидаем Host Busy=0, то есть завершения операции. Отсутствие ожидаемого события в течение заданного интервала (около 50 мс) интерпретируется как ошибка – таймаут шины.
8) Считываем из регистра Host Data 0 (SMB_Base+5) байт, прочитанный из SPD.
Его значение достоверно только при отсутствии ошибок.
9) Проверяем отсутствие ошибок.
Для этого считываем регистр Host Status (SMB_Base+0) и анализируем статусные биты. Согласно документу [2], после успешного завершения транзакции, состояние битов 4-1 должно быть 0001b. Маскируем указанное битовое поле и проверяем его значение.
Добавление от 12.09.2017 13:35:
001 | NEWIODELAY EQU OUT 0EBh, AL |
002 | |
003 | PCIAddr dd 0 |
004 | SMBusAddr dw 0 |
005 | |
006 | VDID_PIIX4 =71138086h; 82371AB/EB/MB PIIX4/E/M Power Management Controller. |
007 | VDID_VIA596A =30501106h; VT82C596/A/B Power Management Controller |
008 | VDID_VIA686A =30571106h; VT82C686/A/B Power Management Controller |
009 | |
010 | VDID_AMD756PM =740B1022h; AMD-756 Power Management Controller |
011 | VDID_AMD766PM =74131022h; AMD-766 Power Management Controller |
012 | VDID_AMD768PM =74431022h; AMD-768 ACPI Controller |
013 | VDID_AMD8111PM=746B1022h; AMD-8111 ACPI System Management Controller |
014 | |
015 | ;******************************************** |
016 | ;* Функция поиска адреса SMBus * |
017 | ;* Результат в SMBusAddr * |
018 | ;* В EAX PCI адрес * |
019 | ;******************************************** |
020 | |
021 | FindSMBusAddr: |
022 | PUSH EBX |
023 | PUSH ECX |
024 | PUSH EDX |
025 | |
026 | MOV EBX, 0C0500h ; Класс SMBus |
027 | MOV ECX, 80000000h ; Счетчик он же адрес |
028 | .Label1: |
029 | |
030 | AND ECX, 0FFFFFF00h ; Выравниваем |
031 | MOV EAX, ECX |
032 | MOV DX, 0CF8h |
033 | OUT DX, EAX ; Устанавливаем адрес |
034 | MOV DX, 0CFCh |
035 | IN EAX, DX ; Читаем регистр |
036 | CMP EAX, 0FFFFFFFFh ; Не существующее устройство. |
037 | JE .Label2 |
038 | |
039 | CMP EAX, VDID_VIA596A |
040 | JNE .Label9 |
041 | |
042 | ADD ECX, 80h ; Для VDID_VIA596A |
043 | MOV EAX, ECX |
044 | MOV DX, 0CF8h |
045 | OUT DX, EAX ; Устанавливаем адрес |
046 | MOV DX, 0CFCh |
047 | IN EAX, DX ; Читаем регистр |
048 | |
049 | JMP .Label3 |
050 | |
051 | .Label9: |
052 | CMP EAX, VDID_VIA686A |
053 | JE .Label7 |
054 | CMP EAX, VDID_PIIX4 |
055 | JNE .Label8 |
056 | .Label7: |
057 | |
058 | ADD ECX, 90h ; Для VDID_PIIX4 и VDID_VIA686A |
059 | MOV EAX, ECX |
060 | MOV DX, 0CF8h |
061 | OUT DX, EAX ; Устанавливаем адрес |
062 | MOV DX, 0CFCh |
063 | IN EAX, DX ; Читаем регистр |
064 | |
065 | JMP .Label3 |
066 | |
067 | .Label8: |
068 | CMP EAX, VDID_AMD756PM |
069 | JE .label5 |
070 | CMP EAX, VDID_AMD766PM |
071 | JE .label5 |
072 | CMP EAX, VDID_AMD768PM |
073 | JE .label5 |
074 | CMP EAX, VDID_AMD8111PM |
075 | JE .label5 |
076 | JMP .Label4 |
077 | .label5: |
078 | |
079 | ADD ECX, 58h ; Для VDID_AMD_PM |
080 | MOV EAX, ECX |
081 | MOV DX, 0CF8h |
082 | OUT DX, EAX ; Устанавливаем адрес |
083 | MOV DX, 0CFCh |
084 | IN EAX, DX ; Читаем регистр |
085 | |
086 | JMP .Label3 |
087 | |
088 | |
089 | .Label4: |
090 | ADD ECX, 08 ; Регистр отвечающий за класс устройства |
091 | MOV EAX, ECX |
092 | MOV DX, 0CF8h |
093 | OUT DX, EAX ; Устанавливаем адрес |
094 | MOV DX, 0CFCh |
095 | IN EAX, DX ; Читаем регистр |
096 | SHR EAX, 8 ; |
097 | CMP EAX, EBX |
098 | |
099 | JNE .Label2 |
100 | MOV CL, 10h-4h ; Ура нашли SMBus |
101 | |
102 | MOV EBX, 6 |
103 | .Label6: |
104 | |
105 | ADD ECX, 4h ; BAR1-BAR6 |
106 | MOV EAX, ECX |
107 | MOV DX, 0CF8h |
108 | OUT DX, EAX ; Устанавливаем адрес |
109 | MOV DX, 0CFCh |
110 | IN EAX, DX ; Читаем регистр |
111 | TEST AX, 0FFF0h |
112 | JNZ .Label3 ; Выходим |
113 | DEC EBX |
114 | JNZ .Label6 |
115 | |
116 | JMP .Label3 ; Выходим |
117 | |
118 | .Label2: |
119 | ADD ECX, 256 |
120 | |
121 | |
122 | CMP ECX, 80FFFF00h ; Максимум 256 шин. |
123 | JNE .Label1 |
124 | MOV ECX, 0FFFFFFFFh ; Не нашли |
125 | MOV EAX, 0 |
126 | .Label3: |
127 | AND AX, 0FFF0h ; Зануляим 4 бита. |
128 | MOV [SMBusAddr],AX ; сохроняем адресс SMBus |
129 | |
130 | XOR EAX, EAX ; Сбрасываем адрес PCI |
131 | MOV DX, 0CF8h ; Чтобы не было претензий. |
132 | OUT DX, EAX ; |
133 | |
134 | AND ECX, 0FFFFFF00h ; Сбрасываем индекс регистра |
135 | MOV EAX, ECX |
136 | POP EDX |
137 | POP ECX |
138 | POP EBX |
139 | RET |
Добавление от 12.09.2017 13:36:
001 | ORG 100h |
002 | CALL FindSMBusAddr |
003 | MOV AX,[SMBusAddr] |
004 | CMP AX,0 |
005 | JNZ .SMBusFound |
006 | MOV AH,9 |
007 | MOV DX,str_SMbusNotFound |
008 | INT 21h |
009 | RET ; Выход из программы |
010 | |
011 | .SMBusFound: |
012 | MOV ESI,str_SMBusAddr+11 |
013 | CALL WordToHEX |
014 | |
015 | MOV AH,9 |
016 | MOV DX,str_SMBusAddr |
017 | INT 21h |
018 | |
019 | MOV AH,9 |
020 | MOV DX,str_FoundDivece |
021 | INT 21h |
022 | |
023 | MOV ECX, 07Fh ; Всего 128 адреесов |
024 | .Loop: |
025 | MOV AL, CL |
026 | CALL TestSMBusDevice |
027 | TEST AL,1 |
028 | JZ .Next |
029 | MOV AL,CL |
030 | MOV ESI,str_Divece |
031 | CALL ByteToHEX |
032 | MOV AH,9 |
033 | MOV DX,str_Divece |
034 | INT 21h |
035 | |
036 | .Next: |
037 | LOOP .Loop |
038 | RET ; Выход из программы |
039 | |
040 | |
041 | str_FoundDivece db 'Found Divece :' ,0Dh,0Ah, '$' |
042 | str_Divece db ' ' ,0Dh,0Ah, '$' |
043 | str_SMBusAddr db 'SMBusAddr : ' ,0Dh,0Ah, '$' |
044 | str_SMbusNotFound db 'SMBusAddr : Not Found' ,0Dh,0Ah, '$' |
045 | |
046 | include "FindSMBus.inc" |
047 | |
048 | ;******************************************** |
049 | ;* Функция тестирования устройства * |
050 | ;* В AL, адрес устройства на SMBus * |
051 | ;* Результат в EAX =1 есть 0 нет * |
052 | ;******************************************** |
053 | TestSMBusDevice: |
054 | PUSH EDX |
055 | PUSH ECX |
056 | MOV DX, [SMBusAddr] |
057 | ADD DX, 4 ;+4 Адреес устройства XMIT_SLVA |
058 | SHL AL, 1 |
059 | OR AL, 1 ; Чтение |
060 | OUT DX, AL |
061 | |
062 | NEWIODELAY |
063 | DEC DX ;+3 HST_CMD Регистр команды, для EEPROM это адрес ячейки |
064 | XOR AL,AL |
065 | OUT DX,AL |
066 | NEWIODELAY |
067 | |
068 | DEC DX ;+2 Начать передачу HST_CNT |
069 | MOV AL, 01001000b ;START=1 SMB_CMD =010b Byte Data |
070 | OUT DX, AL |
071 | |
072 | XOR EAX,EAX |
073 | |
074 | SUB DX, 2 ;+0 Начать передачу HST_STS |
075 | ;MOV CX, 03D00h ; Время выполнения команды 0.0078125 секунд для передачи 128Бит в 2 конца 32768 бит/с |
076 | MOV CX, 0800h ; Время выполнения команды 0.0012207 секунд для передачи 40ит в 2 конца 32768 бит/с |
077 | .Loop: |
078 | NEWIODELAY |
079 | IN AL, DX |
080 | TEST AL, 2 |
081 | JNZ .ok |
082 | LOOP .Loop |
083 | ; Тайм аут истек |
084 | ADD DX,2 |
085 | MOV AL,2 ; Выставляем Kill бит |
086 | OUT DX,AL |
087 | |
088 | SUB DX,2 |
089 | IN AL, DX |
090 | |
091 | .ok: |
092 | NEWIODELAY |
093 | OUT DX, AL ; Очищаем выставленные биты |
094 | |
095 | AND AL, 02H ;INTR команда завершилась? |
096 | SHR AL, 1 ; Удачна завершилось ошибки не смотри |
097 | POP ECX |
098 | POP EDX |
099 | RET |
100 | |
101 | |
102 | |
103 | ;******************************************** |
104 | ;* Функции перевода числа в HEX строку * |
105 | ;* EAX - число * |
106 | ;* ESI адресс * |
107 | ;******************************************** |
108 | HEX_ASCII db '0123456789ABCDEF' |
109 | ByteToHEX: |
110 | PUSH EAX |
111 | PUSH EBX |
112 | ADD ESI, 1 |
113 | XOR EBX, EBX |
114 | MOV BL, AL |
115 | AND EBX, 0Fh |
116 | MOV BL, [HEX_ASCII+EBX] |
117 | MOV [ESI],BL |
118 | DEC ESI |
119 | |
120 | SHR EAX, 4 |
121 | MOV BL, AL |
122 | AND EBX, 0Fh |
123 | MOV BL, [HEX_ASCII+EBX] |
124 | MOV [ESI],BL |
125 | |
126 | POP EBX |
127 | POP EAX |
128 | RET |
129 | |
130 | WordToHEX: |
131 | PUSH EAX |
132 | PUSH EBX |
133 | ADD ESI, 3 |
134 | XOR EBX, EBX |
135 | MOV BL, AL |
136 | AND EBX, 0Fh |
137 | MOV BL, [HEX_ASCII+EBX] |
138 | MOV [ESI],BL |
139 | DEC ESI |
140 | |
141 | SHR EAX, 4 |
142 | MOV BL, AL |
143 | AND EBX, 0Fh |
144 | MOV BL, [HEX_ASCII+EBX] |
145 | MOV [ESI],BL |
146 | DEC ESI |
147 | |
148 | SHR EAX, 4 |
149 | MOV BL, AL |
150 | AND EBX, 0Fh |
151 | MOV BL, [HEX_ASCII+EBX] |
152 | MOV [ESI],BL |
153 | DEC ESI |
154 | |
155 | SHR EAX, 4 |
156 | MOV BL, AL |
157 | AND EBX, 0Fh |
158 | MOV BL, [HEX_ASCII+EBX] |
159 | MOV [ESI],BL |
160 | |
161 | POP EBX |
162 | POP EAX |
163 | RET |
Добавление от 12.09.2017 13:37:
001 | ORG 100h |
002 | CALL FindSMBusAddr |
003 | MOV AX,[SMBusAddr] |
004 | CMP AX,0 |
005 | JNZ .SMBusFound |
006 | MOV AH,9 |
007 | MOV DX,str_SMbusNotFound |
008 | INT 21h |
009 | RET ; Выход из программы |
010 | |
011 | .SMBusFound: |
012 | MOV ESI,str_SMBusAddr+11 |
013 | CALL WordToHEX |
014 | |
015 | MOV AH,9 |
016 | MOV DX,str_SMBusAddr |
017 | INT 21h |
018 | |
019 | MOV AH,9 |
020 | MOV DX,str_FoundDivece |
021 | INT 21h |
022 | |
023 | MOV ECX, 07Fh ; Всего 128 адреесов |
024 | .Loop: |
025 | MOV AL, CL |
026 | CALL TestSMBusDevice |
027 | TEST AL,1 |
028 | JZ .Next |
029 | MOV AL,CL |
030 | MOV ESI,str_Divece |
031 | CALL ByteToHEX |
032 | MOV AH,9 |
033 | MOV DX,str_Divece |
034 | INT 21h |
035 | |
036 | .Next: |
037 | LOOP .Loop |
038 | RET ; Выход из программы |
039 | |
040 | |
041 | str_FoundDivece db 'Found Divece :' ,0Dh,0Ah, '$' |
042 | str_Divece db ' ' ,0Dh,0Ah, '$' |
043 | str_SMBusAddr db 'SMBusAddr : ' ,0Dh,0Ah, '$' |
044 | str_SMbusNotFound db 'SMBusAddr : Not Found' ,0Dh,0Ah, '$' |
045 | |
046 | include "FindSMBus.inc" |
047 | |
048 | ;******************************************** |
049 | ;* Функция тестирования устройства * |
050 | ;* В AL, адрес устройства на SMBus * |
051 | ;* Результат в EAX =1 есть 0 нет * |
052 | ;******************************************** |
053 | TestSMBusDevice: |
054 | PUSH EDX |
055 | PUSH ECX |
056 | MOV DX, [SMBusAddr] |
057 | ADD DX, 4 ;+4 Адреес устройства XMIT_SLVA |
058 | SHL AL, 1 |
059 | OR AL, 1 ; Чтение |
060 | OUT DX, AL |
061 | |
062 | NEWIODELAY |
063 | DEC DX ;+3 HST_CMD Регистр команды, для EEPROM это адрес ячейки |
064 | XOR AL,AL |
065 | OUT DX,AL |
066 | NEWIODELAY |
067 | |
068 | DEC DX ;+2 Начать передачу HST_CNT |
069 | MOV AL, 01001000b ;START=1 SMB_CMD =010b Byte Data |
070 | OUT DX, AL |
071 | |
072 | XOR EAX,EAX |
073 | |
074 | SUB DX, 2 ;+0 Начать передачу HST_STS |
075 | ;MOV CX, 03D00h ; Время выполнения команды 0.0078125 секунд для передачи 128Бит в 2 конца 32768 бит/с |
076 | MOV CX, 0800h ; Время выполнения команды 0.0012207 секунд для передачи 40ит в 2 конца 32768 бит/с |
077 | .Loop: |
078 | NEWIODELAY |
079 | IN AL, DX |
080 | TEST AL, 2 |
081 | JNZ .ok |
082 | LOOP .Loop |
083 | ; Тайм аут истек |
084 | ADD DX,2 |
085 | MOV AL,2 ; Выставляем Kill бит |
086 | OUT DX,AL |
087 | |
088 | SUB DX,2 |
089 | IN AL, DX |
090 | |
091 | .ok: |
092 | NEWIODELAY |
093 | OUT DX, AL ; Очищаем выставленные биты |
094 | |
095 | AND AL, 02H ;INTR команда завершилась? |
096 | SHR AL, 1 ; Удачна завершилось ошибки не смотри |
097 | POP ECX |
098 | POP EDX |
099 | RET |
100 | |
101 | |
102 | |
103 | ;******************************************** |
104 | ;* Функции перевода числа в HEX строку * |
105 | ;* EAX - число * |
106 | ;* ESI адресс * |
107 | ;******************************************** |
108 | HEX_ASCII db '0123456789ABCDEF' |
109 | ByteToHEX: |
110 | PUSH EAX |
111 | PUSH EBX |
112 | ADD ESI, 1 |
113 | XOR EBX, EBX |
114 | MOV BL, AL |
115 | AND EBX, 0Fh |
116 | MOV BL, [HEX_ASCII+EBX] |
117 | MOV [ESI],BL |
118 | DEC ESI |
119 | |
120 | SHR EAX, 4 |
121 | MOV BL, AL |
122 | AND EBX, 0Fh |
123 | MOV BL, [HEX_ASCII+EBX] |
124 | MOV [ESI],BL |
125 | |
126 | POP EBX |
127 | POP EAX |
128 | RET |
129 | |
130 | WordToHEX: |
131 | PUSH EAX |
132 | PUSH EBX |
133 | ADD ESI, 3 |
134 | XOR EBX, EBX |
135 | MOV BL, AL |
136 | AND EBX, 0Fh |
137 | MOV BL, [HEX_ASCII+EBX] |
138 | MOV [ESI],BL |
139 | DEC ESI |
140 | |
141 | SHR EAX, 4 |
142 | MOV BL, AL |
143 | AND EBX, 0Fh |
144 | MOV BL, [HEX_ASCII+EBX] |
145 | MOV [ESI],BL |
146 | DEC ESI |
147 | |
148 | SHR EAX, 4 |
149 | MOV BL, AL |
150 | AND EBX, 0Fh |
151 | MOV BL, [HEX_ASCII+EBX] |
152 | MOV [ESI],BL |
153 | DEC ESI |
154 | |
155 | SHR EAX, 4 |
156 | MOV BL, AL |
157 | AND EBX, 0Fh |
158 | MOV BL, [HEX_ASCII+EBX] |
159 | MOV [ESI],BL |
160 | |
161 | POP EBX |
162 | POP EAX |
163 | RET |