ZX Spectrum для пользователей и программистов 1991 г.

MONS4 - монитор-отладчик MONS4, являясь составной частью пакета DEVPAC4, совместим с ассемблером GENS4. Описание программы.


Монитор-отладчик MONS4, являясь составной частью пакета DEVPAC4, совместим с ассемблером GENS4.
Программисты предпочитают его другим отладчикам, поскольку он обладает неплохими характеристиками:
перемещаем, имеет эффективные средства трассировки программ и занимает относительно небольшой объ-
ем памяти.

В предлагаемом описании рассматриваются кассетная версия MONS4 и версия, работающая с диском в
среде TR-DOS.

ЗАГРУЗКА MONS4

Поскольку MONS4 является перемещаемым, его можно загрузить с произвольного адреса. Первоначально
для его размещения требуется около 7К памяти, однако при первом запуске MONS4, настроившись для
работы по заданному адресу, освобождает примерно 1 К.
Загрузка с магнитофона:

CLEAR YYYYY-1

LOAD "MONS4"CODE YYYYY

здесь и ниже YYYYY — десятичный адрес загрузки.

регистровых пар PC, SP, IY, IX, HL, DE и ВС выводится содержимое семи последовательно распо-
ложенных ячеек памяти, первая из которых адресуется соответствующей регистровой парой. Рядом
с регистрами А и F индицируются установленные флаги, а рядом с регистрами I и R — состояние
триггера разрешения прерываний (ON — прерывания разрешены, OFF — запрещены*). В нижней час-
ти ФП в три столбца размещен дамп памяти — последовательность из 24 ячеек (адрес и содержи-
мое).

КОМАНДЫ MONS4

Управление отладчиком осуществляется с помощью команд, пользуясь которыми помните, что:

- команды могут вводиться с клавиатуры как в верхнем, так и в нижнем регистре;

- команды, не требующие числовых аргументов, выполняются при нажатии соответствующей кла-
виши, без подтверждения клавишей Enter;

- значения числовых аргументов вводятся только в шестнадцатиричной форме и требуют под-
тверждения клавишей Enter;

- неопознанные команды игнорируются;

- отмена выполнения команд производится клавишами Caps Shift/1 (Edit) или Caps Shift/5;

- если при выполнении команды произошло перемещение УА, то ФП обновляется.

Перемещение указателя адреcа

Enter

Переместить УА на следующую ячейку.
Caps Shift/7

Переместить УА на предыдущую ячейку.
Caps Shift/5

Переместить УА на 8 ячеек назад.
Caps Shift/8

Переместить УА на 8 ячеек вперед.

М

Переместить УА на заданный адрес. На подсказку введите шестнадцати ричный адрес ячейки
памяти, на которую необходимо установить УА.
Symbol Shift/N

Перейти по стеку. УА устанавливается на ячейку памяти, адрес которой находится на вершине
стека, при этом значение регистра указателя стека SP не изменяется. Команда используется
для определения адреса возврата из подпрограммы.

О

Выполнить относительный переход. УА сдвигается относительно

*)Триггер разрешения прерываний изменяет свое состояние только при выполнении команд отлаживаемой программы.
Средствами MONS4 его состояние изменить невозможно.

текущей ячейки памяти на величину содержимого этой ячейки, интерпретируемого как относи-
тельное смещение. Смещения более #7F (127) трактуются как отрицательные.

Пример:

Предположим, что при отладке программы встретилась команда

JR ^,#5В12, расположенная по адресам #5B3F и #5В40, при этом по адресу #5B3F находится
код #20 (JR NZ), а по адресу #5В40 — код #D1 (смещение). Если установить УА на ячейку
#5В40 и ввести команду О, то УА переместится на адрес #5В12.

U

Вернуться к исходной ячейке после относительного перехода. Позволяет вернуться к адресу, в
котором была выполнена команда О.

X

Выполнить прямой переход. УА устанавливается на ячейку памяти, адрес которой определяется
двумя байтами, расположенными в текущей и следующей за ней ячейках памяти.

Пример:

Предположим, что при отладке программы по адресу #5BCF встретилась команда вызова подпро-
граммы CALL #9Е12. При этом по адресу #5BCF находится код #CD (CALL), а по адресам #5BD0
и #5BD1 — коды #12 и #9Е соответственно (адрес подпрограммы). Если установить УА на адрес
# 5BD0 и ввести команду X, то УА переместится на ячейку с адресом #9Е12.

V

Вернуться к исходной ячейке после прямого перехода. Позволяет вернуться к адресу, в кото-
ром была выполнена команда X.

Поиск байт в памяти

G

Найти последовательность байт в памяти. На подсказку последовательно введите однобайтовые
шестнадцатиричные числа. Ввод любого нецифрового символа заканчивает последовательность и
запускает поиск. Поиск начинается с текущей ячейки памяти и продолжается до тех пор, пока
последовательность не будет найдена, после чего УА установится на адрес ее первого байта.

Во время поиска MONS4 просматривает также область, занимаемую им самим, и, поскольку об-
разец хранится в специальном буфере отладчика, находит последовательность и внутри себя.

Пример:

Предположим, Вы хотите исследовать память, начиная с адреса #5В00, на появление последо-
вательности #CD #B5 #03. Для этого введите следующие команды: *
M:5B00^ установка УА
G:CD^ ввод первого байта

:B5^ ввод второго байта

:03^ ввод третьего байта

завершение ввода

После завершения ввода, MONS4 начинает поиск заданной последовательности с адреса #5В00.
Когда она будет найдена, УА установится на ее первый байт.

N

Продолжить поиск последовательности байт, заданной командой G, начиная с ячейки, на кото-
рую указывает УА.

Просмотр программы

L

Вывести на экран дамп памяти. Начиная с текущего адреса, производится постраничное ото-
бражение содержимого памяти. В конце каждой строки кодов выводятся соответствующие им
символы. Для кодов от 32 (#20) до 127 (#7F) выводятся их ASCII-эквиваленты. Если код
меньше 32 (#20), он обозначается точкой. Если код больше 127 (#7F), то он будет представ-
лен ASCII-символом, соответствующим этому коду со сброшенным старшим битом. После вывода
очередной страницы, нажав клавишу отмены команды (Edit или Caps Shift/5), можно вернуться
к ФП. Любая другая клавиша продолжит вывод листинга.

Symbol Shift/P

Распечатать дамп памяти на принтере. Аналогично команде L.

Изменение содержимого ячеек памяти и регистров

Для того, чтобы изменить содержимое ячейки памяти, установите на нее УА, введите нуж-
ное значение (однобайтовое шестнадцатиричное число) и нажмите любую нецифровую клавишу.
Если эта клавиша вызывает выполнение какой-либо команды MONS4, то она будет выполнена по-
сле записи числа. Для изменения содержимого ячейки памяти без выполнения команды подтвер-
дите ввод клавишей Space или Enter: при записи по Space указатель адреса не меняет своего
положения, по Enter — перемещается на следующую ячейку.

Если нужно изменить содержимое регистра Z80, то ввод числа завершите нажатием Symbol
Shift/M — точкой. Число будет записано в регистр, на который установлен указатель регист-
ра (см. рис. 15). Первоначально он указывает на PC. Для

*) Здесь и ниже используются следующие обозначения: ^ — клавиша Enter, полужирным шрифтом выделяется
текст, вводимый с клавиатуры, нормальным — текст, выводимый на экран, курсивом — пояснения.

перемещения указателя регистра вводите точку без числа, при этом он будет циклически пе-
ремещаться вдоль регистров, минуя только SP, I и R, содержимое которых командами MONS4
изменить невозможно.

Y

Ввести в память символьную строку. Символ, вводимый с клавиатуры, отображается на экране,
а его код заносится в текущую ячейку памяти, после чего значение УА увеличивается на еди-
ницу. Клавиша Delete (Caps Shift/0) используется для удаления последнего символа строки,
при этом УА перемещается на ячейку назад. Следует отметить, что хотя символ и исчезает с
экрана, его код не удаляется из соответствующей ячейки памяти. Ввод строки завершается
нажатием клавиши отмены команды (Edit или Caps Shift/5).

I

Копировать блок памяти. На соответствующие запросы введите начальный (First:) и конечный
(Last:) адреса блока и адрес размещения его копии (То:). Если начальный адрес больше ко-
нечного, то команда игнорируется. MONS4 позволяет копировать с перекрытием исходного бло-
ка, то есть копия блока может располагаться поверх оригинала.

P

Заполнить область памяти заданным байтом. На запросы First:, Last:, With: введите, соот-
ветственно, значения начального и конечного адресов области памяти и байт-заполнитель.
Если начальный адрес больше конечного, команда игнорируется.

Например, введите:

M:9B10^ установка УА
P^

First: 9B00^
Last: 9В20^

With:AA^

Результат Ваших действий сразу отразится на экране.

Дизассемблирование программы

Symbol Shift/4

Дизассемблировать программу, начиная с текущей ячейки памяти. Про изводится постраничный
вывод на экран текста дизассемблированной программы. После вывода очередной страницы, на-
жав клавишу Edit или Symbol Shift/4, можно вернуться к ФП, любую другую — продолжить ди-
зассемблирование. Вывод текста приостанавливается клавишей Space.

Т

Дизассемблировать блок кодов. На запросы First: и Last: введите соответственно начальный
и конечный адреса блока кодов. Для вывода дизассемблированной программы на принтер, на
запрос Printer? ответьте Y (в верхнем регистре!), после чего на запрос Labels? укажите,
включать ли метки в

распечатку листинга (Y — Да). При отрицательном ответе на запрос Printer? листинг будет
выводиться на экран. На запрос Text: введите адрес размещения в памяти текстового файла
либо имя файла на диске, префиксированное номером устройства и двоеточием. Например:

Text: F000 сохранить тенет в памяти с адреса #F000;

Text: 2:DCODE сохранить текст на дисководе "В" в файле DCODE.

Если Вы хотите просмотреть дизассемблированную программу без создания текстового файла,
на запрос Text: нажмите Enter. На запрос Workspace: вводится начальный адрес рабочей
области, предназначенной для временного хранения информации о метках. По умолчанию на-
чальный адрес устанавливается равным адресу загрузки отладчика минус 4096 (YYYYY—4 096).
Запрос Workspace: не возникнет, если выбрано дизассемблирование без создания меток. Далее
задаются начальные (First:) и конечные (Last:) адреса областей (внутри заданного блока
кодов), не требующие дизассемблирования (данные, таблицы, тексты). При обработке этих об-
ластей MONS4 генерирует инструкции DEFB. Если значение байта данных лежит в пределах от
32 до 127 (#20...#7F), то байт интерпретируется как код ASCII и представляется соответст-
вующим символом. Адреса областей данных записываются в память непосредственно после
MONS4.

После завершения определения всех областей данных для запуска дизассемблирования на за-
просы First: и Last: введите пустые строки. В процессе дизассемблирования генерируются
метки формата LXXXX, где ХХХХ — абсолютный шестнадцатиричный адрес ячейки, на которую
указывает метка. Если адрес не попадает внутрь обрабатываемого блока кодов, метка не соз-
дается, а в мнемонике команды указывается абсолютный адрес. Например, последовательность
кодов #СЗ #00 #78 может быть дизассемблирована и как JP L7800, и как JP #7800, в зависи-
мости от того, входит ли ячейка с адресом #7800 в дизассемблируемый блок.
Если адрес ячейки памяти входит в дизассемблируемый блок, но является не первым байтом
многобайтовой команды, то метка не создается, хотя ссылки на нее в тексте будут присутст-
вовать.

Байт N, следующий за инструкцией RST 8, дизассемблируется как DEFB N, так как обычно
этот байт содержит данные (точнее, код сообщения для процедуры обработки ошибки).
Неопознанный код дизассемблируется как команда NOP и в листинге отмечается символом *.
Дизассемблирование может быть приостановлено клавишей Space. После чего, нажав клавишу
Edit или Caps Shift/5, можно прекратить дизассемблирование, либо, нажав любую другую,
продолжить.

Дизассемблирование прекратится, если при генерации текстового файла его граница достигнет
области памяти, занятой MONS4.

Если дизассемблирование сопровождалось созданием текстового файла в памяти, то по завер-
шении процесса будет выдано сообщение:

End of the text ZZZZZ

где ZZZZZ — адрес последнего байта файла.

Текстовый файл создается в формате ассемблера GENS4 и может быть загружен в него для ре-
дактирования. Для сохранения текстового файла запомните начальный (введенный на запрос
Text:) и конечный адреса (ZZZZZ) его размещения в памяти, вернитесь в Бейсик и запишите
текст на магнитный носитель как файл типа CODE.

Если в процессе дизассемблирования текстовый файл сохраняется на диске, то листинг на эк-
ран не выдается. При объеме текста более 16К создается несколько файлов. Файл или файлы с
диска могут быть загружены в GENS4 обычным способом.

В описываемой дисковой версии MONS4 поддержка дисковода реализована в оверлейном файле
MONSBETA*, который автоматически подгружается в память с текущего дисковода сразу после
ввода имени текстового файла. Если оверлей не найден, управление передается интерпретато-
ру Бейсика с сообщением 2 Variable not found. MONSBETA размещается вслед за областью ин-
формации о каналах, поэтому размер свободной памяти ниже RAMTOP должен быть не менее 512
байт.

Запуск и отладка программы

Symbol Shift/Z

Выполнить команду в пошаговом режиме (трассировка программы). По нажатию клавиши выполня-
ется команда, записанная в ячейке памяти, адресуемой счетчиком команд PC**. Обратите вни-
мание, что УА при этом может быть установлен на другую ячейку. Чтобы увидеть мнемонику
команды, с которой будет начато пошаговое выполнение программы, предварительно перемести-
те УА на ячейку, адресуемую счетчиком команд. После выполнения каждого шага ФП переписы-
вается в соответствии с новым состоянием регистров и памяти, УА устанавливается на ячей-
ку, адресуемую PC.

*) Такое решение позволяет в других режимах работы оставить размер отладчика небольшим.

**) При работе отладчик использует стандартный для операционной системы режим обработки прерываний (ре-
жим 1), изменение которого командами отлаживаемой программы может привести к «зависанию» компьютера.

Symbol Shift/T

Выполнить одну команду. Выполняется команда, размещенная по адресу, указанному счетчиком
команд PC. Если при отладке программы в пошаговом режиме встретилась команда вызова под-
программы, трассировать которую нет необходимости, то использование команды Symbol
Shift/T дает возможность выполнить подпрограмму за один шаг. После этого PC устанавлива-
ется на ячейку, следующую за инструкцией CALL.

Рекомендуется использовать только для выполнения инструкций вызова подпрограмм.

W

Установить точку останова по текущему адресу. Расставив точки останова, Вы сможете анали-
зировать ход выполнения программы, которая в нужных местах будет прерываться с передачей
управления отладчику. На ФП отобразится состояние памяти и регистров на момент прерыва-
ния программы.

При задании точки останова в память, начиная с текущей ячейки, записываются три байта ин-
струкции CALL. Предыдущее содержимое этих ячеек переписывается в буфер, расположенный за
MONS4. Команда CALL, помещенная в точку останова, прерывает выполнение программы и пере-
дает управление отладчику, при этом содержимое измененных ячеек памяти восстанавливается.
Например, рассмотрим следующий фрагмент программы:
5B0F 76 HALT

5В10 AF XOR А

5В11 D3FE OUT (#FE),A
5В13 F5 PUSH AF

5B14 01BE00 LD BC,#00BE

5B17 OB DEC BC

5B18 78 LD A,B

5B19 B1 OR С

5B1A 2 0FB JR NZ,#5B17
5B1C F1 POP AF

5B1D 3C INC A

. 5B1E FE07 CP #07

5B20 38EF JR C,#5B11
5B22 D3FE OUT (#FE),A
5B24 3E7F LD A,#7F

В пошаговом режиме процесс отладки этого фрагмента займет чрезвычайно много времени. Ус-
корить его можно, поставив точку останова после внешнего цикла (адрес #5В22). Для этого
установите УА на адрес #5В22 и выполните команду W. На место OUT (#FE)^ и LD A,#7F будет
записана инструкция CALL, вызывающая подпрограмму обработки точек останова. Командой от-
ладчика Symbol Shift/K (см. ниже) осуществляется запуск выполнения фрагмента программы с
адреса, записанного в счетчике команд. После выполнения фрагмента, управление будет пере-
дано отладчику, который восстановит программу в точке останова, произведет короткий зву-
ковой сигнал и будет ожидать нажатия любой клавиши, после чего вернет на экран ФП.
Точки останова изменяют программу, поэтому пользоваться ими нужно, с осторожностью. Если
в отлаживаемой программе есть обращения к ячейкам, занятым точками останова, то результат
ее выполнения непредсказуем.

Рассмотрим пример:

до установки после установки

9174 25 DEC H 25 DEC H

9175 20 JR NZ,#9178 20 JR NZ,#9178

9176 01 01

9177 С9 RET конец цикла CD CALL mons4 вызов

9178 2D DEC L XX п/п обработки

9179 28 JR Z,#9174 XX точек останова
917А F9 F9 LD SP,HL

917В 18 JR #9178 18 JR #9178

917С FB FB

Пусть в этом фрагменте программы точка останова (CALL mons4) установлена на конец цикла
(адрес #9177). Тогда при выполнении команды JR NZ,#9178 управление будет передано ячейке,
содержимое которой изменено, что неизбежно приведет к ошибке. В этом случае есть два вы-
хода — либо использовать для отладки программы пошаговый режим, либо установить точку ос-
танова по адресу вершины стека, то есть туда, куда вернется управление по команде RET.

Symbol Shift/К

Продолжить выполнение программы. Выполнение программы с адреса, находящегося в счетчике
команд PC. Команда применяется для отладки программ с использованием точек останова.

J

Запустить выполнение программы с заданного адреса. На подсказку введите адрес, с которого

необходимо запустить выполнение программы.

Для возврата в MONS4 можно использовать точки останова.

При запуске программы этой командой, в регистры не заносятся значения, отраженные на ФП,
поэтому пользоваться ею имеет смысл только для глобального запуска программ (например,
для запуска GENS4 без выхода в Бейсик).

_Другие команды

Q

Переключить набор регистров. При запуске отладчика на ФП отображается основной набор ре-
гистров (AF, HL, DE, ВС). После выполнения этой команды будет отображаться альтернативный
набор (AF', HL', DE', ВС') и все действия будут выполняться над ним. Для возврата к ос-
новному набору повторно выполните команду.

Symbol Shift/3

Изменить систему счисления, в которой отображаются адреса, с шестнадцатиричной на деся-
тичную и обратно. Содержимое ячеек памяти всегда выводится в шестнадцатиричном виде.

H

Перевести число из десятичной формы в шестнадцатиричную. Введите десятичное число в пре-
делах от 0 до 65535, нажмите любую нецифровую клавишу, и на экране появится его шестна-
дцатиричный эквивалент.

Symbol Shift/A

Возвратиться в Бейсик.

ПРИМЕР СЕАНСА РАБОТЫ

Рассмотрим пример отладки программы вывода чисел, приведенной в описании сеанса работы на
ассемблере GENS4. Предположим, что при наборе программы в GENS4 была допущена ошибка: в
строке с номером 330 в инструкции ADD A,"0" вместо символа «ноль» был вписан символ «О». В
процессе ассемблирования ошибка не будет найдена, и программа будет работать, но неправиль-
но: вместо ожидаемого числа 12345 при ее запуске на экран будет выведено WXYZ[.

В памяти ZX Spectrum должна находиться оттранслированная программа и MONS4, загруженный с
адреса 55000.

H:40000[SP] = 9C40[SP]

M:9C40^ установка УА

9C40[SS/M] установке начального значения PC

[SS/T] выполнение CALL #ODAF—очистка экрана

[SS/Z] выполнение LD А,#ОА

[SS/Z] выполнение CALL #9C74

[SS/Z] выполнение LD HL,#9C97

[SS/Z] выполнение PUSH HL

[SS/Z] выполнение LD DE,#0001

[SS/Z] выполнение LD B,A

[SS/Z] выполнение LD HL.O

[SS/Z] выполнение ADD HL,DE; HL=1, CY=0

[SS/Z] выполнение JR C,#9C85

[SS/Z] выполнение DJNZ #9C7F

[SS/Z] выполнение ADD HL,DE

[SS/Z] выполнение JR C,#9C85

^ пропуск команд—установка УА на #9С85

^ УА указывает на команду POP HL

W установка точки останова

[SS/K] выполнение программы с адреса PC

[SP] обновление ФП; DE=#OOOA

[SS/Z] выполнение POP HL

[SS/Z] выполнение LD (#9C91),HL

[SS/Z] выполнение RET С

[SS/Z] выполнение LD (HL),E

[SS/Z] выполнение INC HL

[SS/Z] выполнение LD (HL),D

[SS/Z] выполнение INC HL

[SS/Z] выполнение PUSH HL

[SS/Z] выполнение JR #9C7B

M:9C86 УА указывает на команду LD (#9C91),HL

W установка точки останова

[SS/K] выполнение программа: с адреса PC

[SP] обновление ФП; DЕ=#0064

[SS/z] выполнение LD (#9C91),HL

[SS/Z] выполнение RET С

[SS/N] установка УА на #9С4 8

W установка точки останова

[SS/K] выполнение подпрограммы

[SP] обновление ФП

М:9С91^ установка УА

L просмотр дампа памяти—таблицы степеней
9С91 9F 9С 00 00.... 9C9F — конец таблицы

9С95 01 00 ОА 00____ #000А = 10, #0064 = 100

9С99 64 00 Е8 03 d . h .#03Е8 = 1000
9C9D 10 27 00 00. '.. #2710=10000

[CS/1] обновление ФП

M:9C48^ установка УА

[SS/Z] выполнение LD HL,#3039

[SS/Z] выполнение PUSH HL

[SS/Z] выполнение PUSH HL

[SS/Z] выполнение LD HL,(#9C91)

[SS/Z] выполнение DEC HL

[SS/Z] выполнение LD D,(HL)

[SS/Z] выполнение DEC HL

[SS/Z] выполнение LD E,(HL); DE=#2710

[SS/Z] выполнение LD A, D

[SS/Z] выполнение OR E

[SS/Z] выполнение JR NZ,#9C5E; PC=#9C5E

[SS/Z] выполнение ЕХ (SP).HL

[SS/Z] выполнение XOR A

[SS/Z] выполнение SBC HL,DE

[SS/Z] выполнение JR C.#9C67

[SS/Z] выполнение INC A

[SS/Z] выполнение JR #9C60

[SS/Z] выполнение SBC HL,DE

[SS/Z] выполнение JR C,#9C67; PC=#9C67

[SS/Z] выполнение ADD HL,DE

A=1, т. е. первая цифра числа 12345

[SS/Z] выполнение ADD A,#4F

A=#50("W"),а должен быть равен #31 ("1"),
ошибка — в инструкции ADD A,#4F

[CS/7] установка УА на байт #4F

30^ занесение кода #30 в память

[SS/M] установка указателя на регистры AF
[SS/M]
[SS/M]
[SS/M]
[SS/M]
[SS/M]

3100[SS/M] занесение кода "1" в аккумулятор

[SS/Z] выполнение СР #ЗА

[SS/Z] выполнение JR С.#9С70; РС=#9С70

[SS/T] выполнение RST #10—вывод символа "1"

[SS/Z] выполнение ЕХ (SP),HL

[SS/Z] выполнение JR #9С50; РС=#9С50

[SS/4] просмотр части программы

9С5 0 2В DEC HL

9С51 56 LD D,(HL)

9С52 2В DEC HL

9С53 5Е LD E,(HL)

9С5 4 7А LD A, D

9C55 B3 OR Е

9C5 6 2006 JR NZ,#9C5E

9C5 8 El POP HL

9C5 9 El POP HL

9C5A 3E0D LD A,#0D

9C5C D7 RST #10

9C5D C9 RET

9C5E E3 ЕХ (SP),HL

9C5F AF XOR A

9C60 ED52 SBC HL,DE

9C62 3803 JR C,#9C67

[CS/l] обновление ФП

M:9C5A^ установка УА

W установка точки останова

[SS/K] выполнение программы с адреса PC

>+2345 вывод результата работы программы

[SP] обновление ФП

[SS/A] выход в Бейсик




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Scene - Insanity Zer0: "Реальных демомейкеров за всю историю спектрума - не больше десятка имен, с натяжкой можно назвать двадцать! Геймемйкеров - еще меньше..."
Вступление - О содержании газеты...
Миры 128 - Прохождение игры "TERMINATOR - 2".
мир пц - из жизни писишника.
BBS - список станций BBS ZXNet.

В этот день...   23 ноября