ZX-Forum №2 1993 г.

Авторская разработка - Встроенный монитор «Хаккер-93».


АВТОРСКАЯ РАЗРАБОТКА

Встроенный монитор «Хаккер-93»

© Владимир Корчагин, Кемеровская область, г. Тайга, 1994.

Краткое описание монитора.

Встроенный в ПЗУ монитор "Хаккер-93" является простым и достаточно удобным средством для работы с машинным кодом непосредственно в памяти компьютера ZX-Spectrum. Он рассчитан на тех, кто недавно приобрел компьютер и желает изучать программирование, взламывая готовые программы, но еще не имеет ни достаточных знаний для этого, ни программных и аппаратных средств. Монитор также может быть полезен и опытным программистам, как дополнение к имеющимся у них средствам.

К достоинствам "Хаккера-93" следует отнести возможность аппаратного вызова его кнопкой "NMI", полное восстановление состояния процессора после выхода из монитора, а также удобство ввода с клавиатуры программ в машинных кодах. Подпрограммы четко структурированы по сложности выполняемых функций и довольно универсальны, что позволяет пользователю применять их в своих процедурах. Недостатками программы являются ограниченный набор директив и несколько перегруженный стек. В состав программы входят следующие директивы:

Q - Вывод экрана на магнитофон в виде блока кодов без заголовка.

C - Директива копирования блоков.

P - Перенос (копирование) области стека.

E - Директива выхода из монитора.

M - Директива работы с магнитофоном: вывод, ввод и верификация блоков кодов без заголовка или заголовков.

N - Заполнение области памяти кодом.

I - Редактирование отдельных ячеек (POKES) с минимальной порчей экрана.

F - Поиск в памяти цепочки длиной до 3-х кодов.

V - Просмотр памяти в НЕХ-коде и символах; совмещен с редактированием.

Недостаточное количество директив частично компенсируется для пользователя тем, что он может составлять собственные директивы, вводить их в ОЗУ и запускать из директивы просмотра. При вызове директивы "Р" на экран выводится значение указателя стека - это позволяет в директиве "V" выше этого значения просмотреть (и изменить) записанное в стек состояние процессора, которое он имел при входе в монитор. Можно в директиве "F" задать область длиной 1 байт и поискать код, которого там нет (это очистит экран), а затем клавишей "Е" выйти в прерванную программу и посмотреть, как она формирует экран. Можно сразу после входа в монитор клавишей "Q" спасти (записать на магнитофон) картинку, а перед выходом - директивой "М" вернуть ее на место. Можно сделать полную копию памяти, можно легко снять защищенный загрузчик - одним словом, "Хаккер-93" дает широкие возможности для творчества.

Внесение изменений в схему компьютера.

Все изменения сводятся к установке в корпусе компьютера кнопки "NMI" любой конструкции, а также антидребезгового устройства (см. схему), собранного на двух логических элементах И-НЕ микросхемы серии К555 или К155. Возможно применение микросхем других серий.

Дамп изменений в ПЗУ "© 1982 Sinclair Research Ltd".

Подчеркиванием выделены неизменяемые ячейки ПЗУ.

002B 005F

F5 29

E5 29

87 29

18 29

3D B5

C5 6F

2A C9

61 00

31 F0

0067

F5

E5

3E

FE

DB

FE

21

00

77

006F

00

39

C3

6E

38

2A

5D

5C

F4

1539

2A

20

53

69

6E

63

6C

61

F2

1541

69

72

2D

38

32

20

2A

2A

3C

1549

20

58

61

6B

6B

65

70

2D

0F

1551

39

33

20

AA

3E

10

01

00

EB

3868

01

05

02

A1

38

C9

1F

ED

56

3870

5F

38

03

31

00

5B

F5

ED

B0

3878

57

F3

F5

E5

DD

E5

FD

E5

78

3880

C5

D5

08

F5

D9

C5

D5

E5

A7

3888

21

E0

A4

39

D4

F6

3C

3C

E0

3890

E 6

07

D3

FE

5F

01

20

00

06

3898

CD

DA

3C

57

3C

7B

28

EF

D8

38A0

7A

FE

25

20

0E

DD

21

00

A1

38A8

40

11

00

1B

3E

FF

CD

C6

1C

38B0

04

18

DC

FE

0F

20

1B

0E

36

38B8

03

CD

9D

3C

D1

C1

E1

ED

F9

38C0

52

19

38

04

ED

B0

18

E9

3D

38C8

0B

EB

09

EB

09

03

ED

B8

9B

38D0

18

F4

FE

22

20

11

21

00

86

38D8

00

39

E5

CD

94

3C

E1

D1

7D

38E0

F9

EB

01

28

00

18

DD

FE

18

38E8

15

20

20

E1

D1

C1

D9

F1

B2

38F0

08

D1

C1

FD

E1

DD

E1

E1

3F

38F8

F1

ED

47

F1

F9

E1

F3

E2

F5

3900

03

39

FB

07

D6

1A

0F

ED

63

3908

4 F

F1

C9

FE

10

20

23

CD

68

3910

9B

3C

CD

B5

3C

C1

D1

DD

4D

3918

E1

CD

5B

3A

FE

1E

20

03

D3

3920

79

18

8B

FE

07

28

05

FE

A5

3928

19

20

EE

37

79

CD

EA

3C

2B

3930

18

9E

FE

08

20

10

CD

9B

BD

3938

3C

CD

B5

3C

D1

C1

E1

73

51

3940

54

5D

13

0B

18

9F

FE

12

0F

3948

20

11

CD

94

3C

CD

83

3B

DA

3950

E1

46

E5

CD

B5

3C

C1

E1

F5

3958

71

18

D5

FE

0E

20

5E

CD

46

3960

9B

3C

0E

04

CD

B7

3C

E1

23

3968

D1

06

03

3E

FF

BD

28

05

A2

3970

05

BC

28

01

05

7A

D9

C1

AC

3978

E1

F5

CD

2C

3C

F1

ED

B1

4B

3980

20

D7

08

D9

48

0D

7B

D9

3A

3988

28

0E

BE

20

2A

D9

0D

7C

61

3990

D9

28

05

23

BE

2B

20

1F

1A

3998

2B

CD

B5

3A

23

CD

17

3B

FA

39A0

FE

17

20

0E

7B

E6

1F

FE

9A

3 9A8

1A

28

AE

C6

05

5F

16

40

51

39B0

18

05

E5

CD

92

3B

E1

08

6E

39B8

EA

7E

39

18

9C

FE

07

20

6B

39C0

FA

0E

01

CD

9D

3C

E1

CD

56

39C8

2C

3C

1E

07

79

E6

80

4F

BC

39D0

CD

E7

3B

28

E6

FE

21

CC

F1

39D8

C9

3B

28

F4

FE

1E

20

04

71

39E0

CB

F9

10

E3

FE

01

20

04

F3

39E8

CB

B9

18

DB

D5

CD

44

3B

B9

39F0

FE

0D

20

03

19

18

06

FE

8C

39F8

0A

20

12

ED

52

D1

08

CD

52

3 A00

59

3B

C5

CD

D7

3C

C1

3C

70

3 A08

20

C6

08

18

DF

11

C0

00

F8

3 A1 0

CB

79

28

03

11

80

01

FE

49

3 A1 8

22

20

03

19

18

06

FE

1A

E 6

3 A2 0

20

02

ED

52

D1

FE

06

20

B0

3 A2 8

01

E9

FE

09

20

0A

C5

7E

C0

3 A3 0

ED

A1

28

FC

2B

C1

18

98

B8

3 A3 8

CD

5C

3C

30

93

46

CD

4A

F7

3 A4 0

3C

70

18

8C

0E

04

AF

06

91

3 A4 8

20

10

FE

2F

F6

EF

D3

FE

95

3 A50

0D

20

F4

0E

C0

10

FE

0D

94

3 A58

20

FB

C9

E5

D5

C5

CD

8E

50

3 A60

02

20

FB

7B

FE

27

28

F6

75

3 A68

3E

FE

DB

FE

CB

47

7B

F5

39

3 A7 0

3C

C4

44

3A

F1

18

20

E5

36

3 A7 8

D5

FE

20

38

04

FE

80

38

97

3 A8 0

02

3E

2E

11

00

3C

63

6F

47

3 A8 8

29

29

29

19

D1

D5

C5

06

C7

3 A90

08

7E

12

23

14

10

FA

18

BB

3 A98

6C

C5

0E

02

78

07

07

07

A0

3AA0

07

47

E6

0F

FE

0A

38

02

5F

3AA8

C6

07

C6

30

CD

77

3A

1C

3F

3AB0

0D

20

E9

C1

C9

D5

C5

44

68

3AB8

CD

99

3A

45

CD

99

3A

C1

38

3AC0

D1

C9

CD

CD

3A

13

13

CD

5B

3AC8

CD

3A

1B

1B

C9

C5

CB

B9

51

3AD0

CD

D5

3A

C1

C9

E5

D5

F5

1F

3AD8

7A

0F

0F

0F

E6

03

57

21

1A

3AE0

00

58

19

F1

CB

79

20

02

E2

3AE8

77

23

77

18

27

E5

D5

C5

F1

3AF0

CD

B5

3A

3E

07

B3

5F

CB

08

3AF8

79

28

0C

06

10

7E

CD

77

B7

3B00

3A

23

1C

10

F8

18

0C

06

E 6

3B08

08

C5

46

CD

99

3A

23

1C

35

3B10

C1

10

F6

C1

D1

E1

C9

C5

13

3B18

7A

E6

18

47

7B

E6

E0

07

5A

3B20

07

07

B0

C1

C9

CD

17

3B

C2

3B28

A7

28

0B

3D

18

08

CD

17

7E

3B30

3B

FE

17

28

01

3C

5F

E6

65

3B38

18

C6

40

57

7B

E6

07

0F

5F

3B40

0F

0F

5F

C9

11

08

00

CB

A5

3B48

79

C8

1E

10

C9

E5

D5

21

96

3B50

05

02

16

00

5F

19

7E

18

B6

3B58

BB

E5

D5

C5

CD

17

3B

87

73

3B60

87

87

CB

79

28

04

87

30

D0

3B68

01

25

C5

CB

B9

81

C1

16

6A

3B70

00

5F

ED

52

11

01

40

06

A1

3B78

18

CD

ED

3A

CD

92

3B

10

69

3B80

F8

18

90

C5

D5

B7

CD

44

BD

3B88

3B

ED

52

D1

43

CD

25

3B

7E

3B90

18

0B

C5

D5

CD

44

3B

19

ED

3B98

D1

43

CD

2E

3B

78

E6

1F

9A

3BA0

B3

5F

AF

C1

C9

2B

79

E6

B0

3BA8

7 F

28

0A

0D

1D

CB

79

20

22

3BB0

02

1D

1D

AF

C9

CD

25

3B

CC

3BB8

CB

79

28

06

0E

8F

F6

16

0E

3BC0

18

04

0E

07

F6

1C

5F

AF

4C

3BC8

C9

23

79

FE

8F

28

0D

FE

28

3BD0

07

28

09

17

38

02

1C

1C

CC

3BD8

1C

0C

AF

C9

E6

80

4F

CD

35

3BE0

2E

3B

F6

07

5F

AF

C9

3E

96

3BE8

28

CD

D5

3A

CD

59

3B

CB

53

3BF0

79

28

09

D5

11

7B

48

46

C4

3BF8

CD

99

3A

D1

CD

5B

3A

F5

FB

3C00

3C

20

03

F1

18

E6

3E

38

00

3C08

CD

D5

3A

F1

C0

FE

03

CC

9E

3C10

92

3B

28

D3

FE

04

CC

A5

87

3C18

3B

28

F7

FE

0B

CC

83

3B

41

3C20

28

F7

FE

13

CC

C9

3B

28

84

3C28

F7

FE

20

C9

3E

38

E5

C5

62

3C30

11

FE

5A

01

FF

02

62

69

A2

3C38

77

ED

B8

AF

2B

1B

01

FF

85

3C40

17

77

ED

B8

11

01

40

C1

C2

3C48

E1

C9

CB

20

CB

20

CB

20

EF

3C50

CB

20

B0

47

C9

CD

5B

3A

99

3C58

FE

FF

28

F9

CD

4D

3B

FE

05

3C60

30

38

0B

FE

47

D0

FE

40

62

3C68

38

02

D6

07

D6

30

3F

C9

C9

3C70

3E

28

CD

C2

3A

CD

B5

3A

97

3C78

CD

55

3C

D0

CD

5F

00

18

26

3C80

EF

3E

28

CD

CD

3A

CD

99

4B

3C88

3A

1D

1D

CD

55

3C

D0

CD

33

3C90

4A

3C

18

ED

0E

01

11

01

78

3C98

40

18

05

0E

02

CD

2C

3C

76

3CA0

CD

70

3C

FE

0D

20

F9

E3

5C

3CA8

E5

3E

38

CD

C2

3A

CD

92

67

3CB0

3B

0D

20

EC

C9

0E

01

CD

E5

3CB8

81

3C

FE

0D

20

F9

78

CB

18

3CC0

41

D9

20

03

67

18

03

6F

2A

3CC8

E3

E5

D9

3E

38

CD

CD

3A

EF

3CD0

CD

92

3B

0D

20

E1

C9

01

7E

3CD8

08

00

F5

F1

CD

5B

3A

F5

59

3CE0

3C

20

05

10

F6

0D

20

F3

A3

3CE8

F1

C9

14

08

15

F3

3E

05

45

3CF0

D3

FE

CD

62

05

D8

CD

44

1A

3CF8

3A

CD

D7

3C

3C

28

F7

C9

72

Текст программы на Ассемблере.

Входной блок.

ORG

#002B

Короткий вход из точки прерывания.

PUSH

AF

PUSH

HL

ADD

A, A

Имитация нажатия CAPS SHIFT.

JR

L006D

ORG

#005F

IN HL

ADD

HL, HL

ADD

HL, HL

ADD

HL, HL

ADD

HL, HL

OR

L

LD

L, A

RET

L0066

NOP

;Инкремент

рег.R (вход по "NMI" - #0066).

L0067

PUSH

AF

PUSH

HL

LD

A, #FE

Если нажата CAPS SHIFT, то младший бит

IN

A, (#FE)

аккумулятора будет обнулен.

L006D

LD

HL,#0000

Фиксация

ADD

HL, SP

значения SP.

JP

L386E

ORG

#1539 ;

DEFM

"* Sinclair-

82 ** Xakkep-93 *"

ORG

#386E ;

L386E

RRA

;Устан.знач.флага С по состоянию CAPS SHIFT

LD

A, R

JR

C,L3876

Переход, если CAPS SHIFT не нажата.

LD

SP,#5B00

Переключить SP на область атрибутов.

L3876

PUSH

AF

Сохр. RF и сост. триггера прерываний.

LD

A, I

DI

Команда для случая входа из точки прерывания

PUSH

AF

Сохранить IF.

PUSH

HL

Сохранить SP.

PUSH

IX

Сохранить остальные регистры.

PUSH

IY

PUSH

BC

PUSH

DE

EX

AF,AF'

PUSH

AF

Сохранить альтернативные регистры.

EXX

PUSH

BC

PUSH

DE

PUSH

HL

LD

HL,#A4E0

Загрузить число минус #5B20.

ADD

HL, SP

CALL

NC,EXIT

Звук.сигнал, если SP указ. ниже, чем #5В20.

OUT

INC

A

Подготовить новый цвет бордюра.

AND

#07

Выключить остальные биты.

OUT

(#FE),A

Установить цвет бордюра.

LD

E, A

Сохранить значение цвета бордюра.

LD

BC,#0020

Задержка 2 сек.

CALL

T.SCAN

Сканировать клавиатуру 2 сек.

LD

D, A

Сохранить результат сканирования.

INC

A

Установить флаг Z, если клавиша не нажата.

LD

A, E

Восстановить цвет бордюра.

JR

Z, OUT

Возврат, если клавиша не нажата.

LD

A, D

Извлечь результат сканирования.

Блок директив.

CP

#25

Нажата клавиша "Q"?

JR

NZ,L38B3

Переход вперед, если НЕТ.

LD

IX,#4000

Начальный адрес экрана.

LD

DE,#1B00

Длина экрана.

LD

A, #FF

Флаговый байт.

L38AE

CALL

#04C6

Запись экрана на магнитофон.

L38B1

JR

OUT

Выход из директивы.

L38B3

CP

#0 F

Нажата клавиша "С"?

JR

NZ,L38D2

Переход вперед, если НЕТ.

LD

C,#03

Ввести три числа.

CALL

MEN4-A

Ввод 4-значных чисел (с очисткой экрана).

POP

DE

Извлечь введенные числа.

POP

BC

POP

HL

SBC

HL, DE

Установить флаг С и перейти

ADD

HL, DE

вперед, если блок копируется

JR

C,L38C8

вверх по адресам.

L38C4

LDIR

Скопировать блок.

L38C6

JR

L38B1

Выход из директивы.

L38C8

DEC

BC

Пересчет

EX

DE, HL

регистров

ADD

HL, BC

для

EX

DE, HL

копирования

ADD

HL, BC

блока кодов

INC

BC

с "хвоста".

LDDR

Скопировать блок.

L38D0

JR

L38C6

Выход из директивы.

L38D2

CP

#22

Нажата клавиша "Р"?

JR

NZ,L38E7

Переход вперед, если НЕТ.

LD

HL,#0000

Занести

ADD

HL, SP

SP в HL.

PUSH

HL

Сохранить SP.

CALL

MEN4

Ввод 4-значного числа (без очистки экрана).

POP

HL

Извлечь новое значение SP.

POP

DE

Извлечь старое значение SP.

LD

SP, HL

Загрузить в SP новое значение.

EX

DE, HL

Подготовка к

LD

BC,#0028

копированию 4 0 байтов.

L38E5

JR

L38C4

Копирование LDIR и выход из директивы.

L38E7

CP

#15

Нажата клавиша "Е"?

JR

NZ,L390B

Переход вперед, если НЕТ.

POP

HL

Извлечь альтернативные регистры.

POP

DE

POP

BC

EXX

POP

AF

EX

AF,AF'

POP

DE

Извлечь основные регистры.

POP

BC

POP

IY

POP

IX

POP

HL

Извлечь значение SP.

POP

AF

Извлечь значение IF.

LD

I,A

POP

AF

Извлечь значение RF (и триггера прерываний).

LD

SP, HL

Восстановить значение SP.

POP

HL

Извлечь значение HL.

DI

Восстановить

JP

PO,L3903

состояние триггера

EI

прерываний.

L3903

RLCA

Сохранить 7-й бит в нулевом разряде.

SUB

#1A

Скомпенсировать значение регистра R.

RRCA

Извлечь 7-й бит из нулевого разряда.

LD

R, A

POP

AF

Извлечь AF.

RET

Выход из монитора в вызывающую программу.

L390B

CP

#10

Нажата клавиша "М"?

JR

NZ,L3 932

Переход вперед, если НЕТ.

CALL

MEN4-D

Ввести два 4-значных числа (с очисткой экр.).

CALL

MEN2

Ввести 2-значное число.

POP

BC

Поместить флаговый байт в регистр С.

POP

DE

Извлечь длину блока.

POP

IX

Извлечь начальный адрес ввода (вывода).

L3919

CALL

SCAN

Сканировать клавиатуру.

CP

#1E

Нажата клавиша "S"?

JR

NZ,L3923

Переход вперед, если НЕТ.

LD

A, C

Поместить флаговый байт в аккумулятор.

JR

L3 8AE

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

L3923

CP

#07

Нажата клавиша "V"?

JR

Z,L392C

Переход вперед, если ДА (флаг С сброшен).

CP

#19

Нажата клавиша "L"?

JR

NZ,L3919

Возврат в сканирование, если НЕТ.

SCF

Установить флаг LOAD/VERIFY.

L392C

LD

A, C

Ввод флагового байта в аккумулятор.

CALL

LOAD

Ввод блока с ленты или верификация.

L3930

JR

L38D0

Выход из директивы.

L3932

CP

#08

Нажата клавиша "N"?

JR

NZ ,L3 94 6

Переход вперед, если НЕТ.

CALL

MEN4-D

Ввести два 4-значных числа (с очисткой экр.

CALL

MEN2

Ввести 2-значное число.

POP

DE

Поместить в регистр Е код заполнения.

POP

BC

Извлечь длину заполняемой области.

POP

HL

Извлечь начальный адрес области.

LD

(HL),E

Подготовка

LD

D, H

к заполнению

LD

E,L

с помощью

INC

DE

команды

DEC

BC

LDIR.

JR

L38E5

Переход на LDIR и выход из директивы.

L3946

CP

#12

Нажата клавиша "I"?

JR

NZ,L3 95B

Переход вперед, если НЕТ.

CALL

MEN4

Ввести 4-значное число (без стирания экрана

CALL

UP

Вернуть позицию печати назад.

POP

HL

Извлечь введенный адрес.

LD

B, (HL)

Извлечь байт из памяти.

PUSH

HL

Сохранить адрес.

CALL

MEN2

Ввести новый байт.

POP

BC

Поместить новый байт в регистр С.

POP

HL

Извлечь адрес ячейки.

LD

(HL) ,C

Загрузить новый байт в ячейку.

L3959

JR

L3930

Выход из директивы.

L395B

CP

#0E

Нажата клавиша "F"?

JR

NZ,L3 9BD

Переход вперед, если НЕТ.

CALL

MEN4-D

Ввести два 4-значных числа (с очисткой экр.

LD

C, #04

Ввести четыре

CALL

MEN2-A

2-значных числа.

POP

HL

Извлечь цепочку кодов

POP

DE

в регистры D',E',H',L'.

LD

B,#03

Полагаем длину цепочки три кода.

LD

A, #FF

Маркер конца цепочки.

CP

L

Маркер в регистре L'?

JR

Z,L3975

Переход вперед, если ДА.

DEC

B

Полагаем, что в цепочке два кода.

CP

H

Маркер в регистре Н?

JR

Z,L3975

Переход вперед, если ДА.

DEC

B

Будем искать только первый код.

L3975

LD EXX

A, D

Извлечь первый код цепочки.

POP

BC

Извлечь длину блока.

POP

HL

Извлечь начальный адрес блока.

PUSH

AF

Сохранить первый код цепочки.

CALL

CLS

Очистка экрана (INK 0; PAPER 7).

POP

AF

Извлечь первый код цепочки.

L397E

CPIR

Поиск кода.

JR

NZ ,L3 95 9

Выход из директивы, если весь блок просмотрен

EX

AF, AF'

Сохранить первый код и флаги.

EXX

LD

C, B

Поместить в регистр С' длину цепочки.

DEC

C

Контроль конца цепочки (флаг Z).

LD

A, E

Загрузить второй код цепочки.

EXX

JR

Z,L3998

Переход на печать адреса, если конец цепочки

CP

(HL)

Сверить второй код с содержимым ячейки.

JR

NZ,L3 9B7

Продолжить поиск в блоке, если не совпадает.

EXX

DEC

C

Контроль конца цепочки.

LD

A, H

Загрузить третий код из цепочки.

EXX

JR

Z,L3998

Переход на печать адреса, если конец цепочки

INC

HL

Сверить третий код

CP

(HL)

с содержимым

DEC

HL

ячейки.

JR

NZ,L39B7

Продолжить поиск в блоке, если не совпадает.

L3998

DEC

HL

Установить адрес первого кода цепочки.

CALL

PR.HL

Распечатать адрес на экране.

INC

HL

Восстановить HL.

CALL

AB.LIN

Получить номер строки экрана, где была печать

CP

#17

Это последняя строка?

JR

NZ,L3 9B2

Переход вперед, если НЕТ.

LD

A, E

Загрузить номера строки и колонки экрана.

AND

#1F

Выделить номер колонки.

CP

#1A

Это последняя колонка?

JR

Z,L3 95 9

Выход из директивы, если весь экран заполнен

ADD

A, #05

Задать адрес колонки следующего столбца.

LD

E, A

Младший байт позиции печати.

LD

D, #40

Старший байт позиции печати.

JR

L39B7

Переход на продолжение поиска.

L39B2

PUSH

HL

Перемещение позиции

CALL

DOWN

печати на одну

POP

HL

строку вниз.

L39B7

EX

AF,AF'

Извлечь первый код цепочки и флаги.

JP

PE,L397E

Продолжить поиск, если блок не кончился.

L39BB

JR

L3959

Выход из директивы.

L39BD

CP

#07

Нажата клавиша "V"?

JR

NZ,L3 9BB

Возврат, если НЕТ.

LD

C, #01

Ввод одного

CALL

MEN4-A

4-значного числа.

POP

HL

Извлечь введенный адрес.

L39C7

CALL

CLS

Осистить экран, печать с адреса #4001 (в DE)

LD

E, #07

Установить курсор в 7-ю колонку экрана.

LD

A, C

Сохранить бит 7 (флаг БАЙТЫ/СИМВОЛЫ)

AND

#80

и обнулить остальные

LD

C, A

(счетчик столбцов).

L39D0

CALL

WIND

Печать экрана с курсором.

JR

Z,L39BB

Выход из директивы, если нажата BREAK.

CP

#21

Нажата клавиша ENTER?

CALL

Z,RIGHT

Сдвинуть курсор вправо, если ДА.

JR

Z,L39D0

Возврат в "окно", если был сдвиг курсора.

CP

#1E

Нажата клавиша "S"?

JR

NZ,L39E4

Переход вперед, если НЕТ.

SET

7,C

Установить значение флага СИМВОЛЬНОГО режима.

DJNZ

L39C7

Возврат в "окно" со стиранием экрана.

L39E4

CP

#01

Нажата клавиша "Н"?

JR

NZ,L3 9EC

Переход вперед, если НЕТ.

RES

7,C

Установить значение флага БАЙТОВОГО режима.

JR

L39C7

Возврат в "окно" со стиранием экрана.

L39EC

PUSH

DE

Сохранить позицию курсора.

CALL

STEP

Занести в DE шаг по строке (8 или 16).

CP

#0D

Нажата клавиша "R"?

JR

NZ,L39F7

Переход вперед, если НЕТ.

ADD

HL, DE

Сместить распечатку экрана

JR

L39FD

на 1 строку вверх.

L39F7

CP

#0A

Нажата клавиша "U"?

JR

NZ,L3A0D

Переход вперед, если НЕТ.

SBC

HL, DE

Сместить распечатку экрана на 1 строку вниз.

L39FD

POP

DE

Восстановить позицию курсора.

EX

AF,AF'

Сохранить номер нажатой клавиши.

CALL

PR.SCR

Печать экрана.

PUSH

BC

Сканирование

CALL

T.SC.5

клавиатуры

POP

BC

в течение 0,5 сек.

INC

A

Установить флаг Z, если клавиша не нажата.

JR

NZ,L3 9D0

Возврат в "окно", если нажата любая клавиша.

EX

AF,AF'

Восстановить номер нажатой клавиши.

JR

L39EC

Возврат на начало роллинга.

L3A0D

LD

DE,#00C0

Занести в DE шаг по странице БАЙТОВ.

BIT

7,C

Проверить флаг режима (БАЙТЫ/СИМВОЛЫ).

JR

Z,L3A17

Переход вперед, если БАЙТОВЫЙ режим.

LD

DE,#0180

Занести в DE шаг по странице СИМВОЛОВ.

L3A17

CP

#22

Нажата клавиша "Р"?

JR

NZ,L3A1E

Переход вперед, если НЕТ.

ADD

HL, DE

Увеличить адрес курсора на шаг по странице.

JR

L3A2 4

Переход вперед.

L3A1E

CP

#1A

Нажата клавиша "О"?

JR

NZ,L3A2 4

Переход вперед, если НЕТ.

SBC

HL, DE

Уменьшить адрес курсора на шаг по странице.

L3A2 4

POP

DE

Восстановить позицию курсора.

CP

#06

Нажата клавиша "G"?

JR

NZ,L3A2A

Переход вперед, если НЕТ.

JP

(HL)

Запустить программу с адреса, указ.курсором.

L3A2A

CP

#09

Нажата клавиша "J"?

JR

NZ,L3A38

Переход вперед, если НЕТ.

PUSH

BC

Поиск вверх по адресам

LD

A,(HL)

первого байта,

L3A30

CPI

отличающегося от

JR

Z , L3 A3 0

указанного курсором.

DEC

HL ;Установка курсора на обнаруженный байт.

POP

BC ;Восстановление регистра С.

JR

L3 9D0 ;Возврат в "окно".

L3A38

CALL

F.CONT ;Перевод цифры в число с установкой флага С.

JR

NC,L39D0 ;Возврат в "окно", если нажата не цифра.

LD

B, (HL) ;Загрузить рег.В из ячейки, указ.курсором.

CALL

IN B ;Ввести в рег.В со сдвигом число из рег.А.

LD

(HL),B ;Вернуть в ячейку отредактированное число.

JR

L3 9D0 ;Возврат в "окно".

Блок подпрограмм.

TON

LD

C,#04

Динамик переключится 4 раза.

XOR

A

По окончании работы динамик выключить.

L3A47

LD

B, #20

Задержка времени между фронтами.

L3A4 9

DJNZ

L3A4 9

Цикл задержки.

CPL

Инверсия бита 4.

OR

#EF

Установка остальных битов.

OUT

(#FE),A

Переключить динамик (бордюр белый).

DEC

C

Контроль окончания цикла.

JR

NZ,L3A47

Возврат, если цикл не окончен.

LD

C, #C0

Задержка для подавления дребезга клавиши.

L3A55

DJNZ

L3A5 5

Цикл задержки.

DEC

C

Контроль окончания работы.

JR

NZ,L3A55

Возврат, если работа не окончена.

RET

SCAN

PUSH

HL

Сохранить регистры.

PUSH

DE

PUSH

BC

L3A5E

CALL

#028E

Сканирование клавиатуры вызовом KEY-SCAN.

JR

NZ,L3A5E

Возврат, если нажаты 2 и более клавиши.

LD

A, E

Извлечь номер нажатой клавиши.

CP

#27

Нажата только CAPS SHIFT?

JR

Z,L3A5E

Возврат, если ДА.

LD

A, #FE

Повторный

IN

A,(#FE)

опрос клавиши

BIT

0,A

CAPS SHIFT.

LD

A, E

Восстановить номер нажатой клавиши.

PUSH

AF

Сохранить номер клавиши и флаг Z.

INC

A

Установить флаг Z, если клавиша не нажата.

CALL

NZ,TON

Звуковой щелчок, если клавиша нажата.

POP

AF

Восстановить номер клавиши и флаг Z.

JR

L3A97

Восстановление регистров и завершение п/п.

P.SIM

PUSH

HL

Сохранить регистры.

PUSH

DE

CP

#20

Нижняя граница отображаемого набора 9 6 литер

JR

C,L3A81

Переход вперед, если управляющий код.

CP

#80

Верхняя граница отображ. набора 96 литер.

JR

C,L3A83

Переход вперед, если печатный код.

L3A81

LD

A, #2E

Загрузить код символа "точка".

L3A83

LD

DE,L3C00

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

LD

H, E

Поместить в HL

LD

L, A

код символа.

ADD

HL, HL

Получение адреса

ADD

HL, HL

первого байта

ADD

HL, HL

шаблона символа

ADD

HL, DE

в символьном наборе.

POP

DE

Восстановить

PUSH

DE

позицию печати.

PUSH

BC

Сохранить ВС.

LD

B, #08

Цикл для перенесения 8 байтов.

L3A91

LD

A, (HL)

Перенос байта шаблона символа

LD

(DE),A

из символьного набора в дисплейный файл.

INC

HL

Переход к следующему байту симв.набора.

INC

D

Переход к следующей линии знакоместа.

DJNZ

L3A91

Цикл переноса 8 байтов.

L3A97

JR

L3B05

Восстановление регистров и выход из п/п.

PR.B

PUSH

BC

Сохранить ВС.

LD

C, #02

Цикл для печати двух символов.

L3A9C

LD

A, B

Перенести байт в аккумулятор.

RLCA

Поменять

RLCA

местами

RLCA

тетрады.

RLCA

LD

B, A

Сохранить результат.

AND

#0 F

Выделить младшую тетраду.

CP

#0A

Получить код символа,

JR

C,L3AAA

соответствующий

ADD

A, #07

числу в

L3AAA

ADD

A, #30

аккумуляторе.

CALL

P.SIM

Печать символа на экране.

INC

E

Адрес следующего знакоместа.

DEC

C

Контроль окончания печати.

JR

NZ,L3A9C

Возврат, если печать не окончена.

POP

BC

RET

PR.HL

PUSH

DE

Сохранить

PUSH

BC

регистры.

LD

B, H

Печать содержимого

CALL

PR.B

регистра Н.

LD

B, L

Печать содержимого

CALL

PR.B

регистра L.

POP

BC

POP

DE

RET

P.ATR4

CALL

P.ATR2

Печать атрибутов (в А) в 2-х з/м по адр.в DE.

INC

DE

Позиция печати для

INC

DE

остальных знакомест.

CALL

P.ATR2

Печать атрибутов в двух знакоместах.

DEC

DE

Восстановить

DEC

DE

позицию печати.

RET

P.ATR2

PUSH

BC

RES

7,C

Установить флаг БАЙТОВОГО режима.

CALL

P.ATR

Печать атрибутов в двух знакоместах.

POP

BC

RET

P.ATR

PUSH

HL

Сохранить

PUSH

DE

регистры.

PUSH

AF

LD

A, D

Извлечь номер сегмента позиции печати.

RRCA

Сдвинуть номер

RRCA

сегмента в

RRCA

младшие биты.

AND

#03

Выделить номер сегмента.

LD

D, A

Теперь в DE абсолютный номер з/м поз.печати.

LD

HL,#5800

Начальный адрес области атрибутов.

ADD

HL, DE

Теперь в HL адрес атрибутов позиции печати.

POP

AF

Извлечь значение атрибутов.

BIT

7,C

Контроль режима (БАЙТЫ/СИМВОЛЫ).

JR

NZ,L3AEA

Переход вперед, если СИМВОЛЫ.

LD

(HL),A

Печать атрибутов.

INC

HL

Адрес атрибутов следующего знакоместа.

L3AEA

LD

(HL),A

Печать атрибутов.

JR

L3B14

Восстановление регистров и выход из п/п.

P.LIN

PUSH

HL

Сохранить

PUSH

DE

регистры.

PUSH

BC

CALL

PR.HL

Печать адреса в начале строки.

LD

A, #07

Следующая позиция печати: 7-я колонка.

OR

E

Соединить номер колонки с номером строки.

LD

E, A

Установить позицию печати.

BIT

7,C

Контроль режима.

JR

Z,L3B07

Переход вперед, если БАЙТОВЫЙ режим.

LD

B,#10

Будет напечатано 16 символов.

L3AFD

LD

A, (HL)

Извлечь код символа.

CALL

P.SIM

Печать символа на экране.

INC

HL

Адрес следующего символа.

INC

E

Адрес следующего знакоместа.

DJNZ

L3AFD

Цикл печати строки символов.

L3B05

JR

L3B13

Восстановление регистров и выход из п/п.

L3B07

LD

B, #08

Будет распечатано 8 байтов в HEX-коде.

L3B09

PUSH

BC

Сохранить регистр В.

LD

B,(HL)

Извлечь байт для печати.

CALL

PR.B

Распечатка байта на экране.

INC

HL

Адрес следующего отображаемого байта.

INC

E

Пробел между столбцами.

POP

BC

Извлечь регистр В.

DJNZ

L3B09

Цикл печати строки байтов в HEX-коде.

L3B13

POP

BC

Восстановление

L3B14

POP

DE

регистров

POP

HL

и выход из

RET

подпрограммы.

AB.LIN

PUSH

BC

LD

A, D

Извлечь номер сегмента экрана.

AND

#18

Выделить номер сегмента.

LD

B, A

Сохранить номер сегмента.

LD

A, E

Извлечь номер строки (позиции печати).

AND

#E0

Выделить номер строки.

RLCA

Сдвинуть номер

RLCA

строки в

RLCA

младшие биты.

OR

B

Получить абсолютный номер строки.

POP BC ;

RET ;

Z.LIN CALL AB.LIN ;Номер строки, в которой находится курсор.

AND A ; Определить флаг Z (лишняя команда).

JR Z,L.DE ;Переход вперед, если строка нулевая.

DEC A ;Задать курсор на одну строку выше.

JR L.DE ;Переход вперед.

L.LIN CALL AB.LIN ;Номер строки, в которой находится курсор.

CP #17 "Это последняя строка?

JR Z,L.DE ;Переход вперед, если ДА.

INC A ;Курсор - строкой ниже.

L.DE LD E,A ;Сохранить абсолютный номер строки.

AND #18 ;Выделить номер сегмента экрана.

ADD A,#4 0 ;Получить в регистре D

LD D,A ;старший байт адреса строки.

LD A, E ;Извлечь абсолютный номер строки.

AND #07 ;Выделить относительный номер строки.

RRCA ; Получить в регистре Е

RRCA ; младший байт

RRCA ; адреса строки

LD E,A ;(нулевая колонка).

RET ;

STEP LD DE,#0008 ;Курсор переместится на 8 байтов.

BIT 7,C ;Контроль режима.

RET Z ;Выход, если БАЙТОВЫЙ режим.

LD E,#10 ;Курсор переместится на 16 символов.

RET ;

C.NUM PUSH HL ; Сохранить

PUSH DE ;регистры.

LD HL,#02 05 ;Базовый адрес таблицы клавиатуры.

LD D,#00 ,"Занести в DE номер

LD E,A "нажатой клавиши.

ADD HL,DE "Получить адрес кода в таблице.

LD A,(HL) "Извлечь код из таблицы.

JR L3B14 "Восстановление регистров и выход из п/п.

PR.SCR PUSH HL "Сохранить адрес ячейки, указываемой курсором.

PUSH DE "Сохранить позицию курсора на экране.

PUSH BC "Сохр.рег.С (флаг режима и N столбца курсора).

CALL AB.LIN "Строка экрана, в которой находится курсор.

ADD A, A "Умножить число полных

ADD A, A " строк (до курсора) на

ADD A, A "число байтов в строке.

BIT 7,C "Контроль режима.

JR Z,L3B6A "Переход вперед, если БАЙТОВЫЙ режим.

ADD A, A "Удвоить значение для СИМВОЛЬНОЙ строки.

JR NC,L3B6A "Переход вперед, если результат меньше 256.

DEC H "Вычесть 25 6 из адреса ячейки в курсоре.

L3B6A PUSH BC " Сохранить регистр С.

RES 7,C "Выделить N столбца, в к-ром находится курсор.

ADD A, C "Число яч.от начала экр.до курсора (MOD 25 6).

POP BC " Восстановить регистр С.

LD D,#00 "Занести в DE число распечатываемых ячеек

LD E,A "памяти от нач.экр. до курсора (MOD 256).

SBC HL,DE "Получить адрес начальной ячейки распечатки.

LD DE,#4001 "Начальная позиция печати.

LD B,#18 "Будет распечатано 24 строки.

L3B7 9 CALL P.LIN "Печать строки байтов или символов.

CALL DOWN "Переместить позицию печати вниз на 1 строку.

DJNZ L3B79 "Цикл печати 24 строк.

JR L3B13 "Восстановление регистров и выход из п/п.

UP PUSH BC " Сохранить

PUSH DE "регистры.

OR A "Сбр.флаг С (лишняя команда, т.к.уже сброшен).

CALL STEP "Ввести в DE шаг по строке.

SBC HL,DE "Уменьшить адрес ячейки в курсоре на 1 шаг.

POP DE "Восстановить позицию курсора.

LD B,E "Сохранить номер колонки.

CALL Z.LIN "Переместить курсор вверх, если не 0 строка.

JR L3B9D "Переход на восстановление номера колонки.

DOWN PUSH BC " Сохранить

PUSH DE "регистры.

CALL STEP "Ввести в DE шаг по строке.

ADD HL,DE "Увеличить адрес ячейки в курсоре на 1 шаг.

POP DE "Восстановить позицию курсора.

LD B,E "Сохранить номер колонки.

CALL L.LIN ,• Перемест. курсор вниз, если строка не послед.

L3B9D LD A, B "Извлечь номер колонки.

AND #1F "Выделить номер колонки.

OR E "Соединить с новым номером строки.

LD E,A "Установить новую позицию курсора.

XOR A "Установить флаг Z.

POP BC "

RET "

LEFT DEC HL "Уменьшить адрес ячейки, указываемой курсором.

LD A, C "Извлечь номер столбца распечатки.

AND #7F "Выделить номер столбца.

JR Z,L3BB5 "Переход вперед, если нулевой столбец.

DEC C "Уменьшить номер столбца.

DEC E "Сдвинуть курсор влево на 1 экранную колонку.

BIT 7,C "Контроль режима.

JR NZ,L3BB3 "Переход вперед, если СИМВОЛЬНЫЙ режим.

DEC E " Сдвинуть курсор еще 2 раза, т. к. в БАЙТОВОМ

DEC E "режиме столбец занимает 3 колонки.

L3BB3 XOR A "Установить флаг Z.

RET "

L3BB5 CALL Z.LIN "Переместить курсор вверх, если не 0 строка.

BIT 7,C "Контроль режима.

JR Z,L3BC2 "Переход вперед, если БАЙТОВЫЙ режим.

LD C,#8F "Уст.счетчик на СИМВОЛЬНЫЙ режим и столбец 15.

OR #16 "Установить номер колонки для курсора.

JR L3BC6 "Переход вперед.

L3BC2 LD C,#07 "Уст.БАЙТОВЫЙ режим и столбец 7 (последний).

OR # 1C "Установить номер колонки для курсора.

L3BC6 LD E,A "Установить позицию курсора.

XOR A "Установить флаг Z.

RET "

RIGHT INC HL "Увеличить адрес ячейки, указываемой курсором.

LD A, C "Извлечь номер столбца.

CP #8F "Последний столбец в СИМВОЛЬНОМ режиме?

JR Z,L3BDC "Переход вперед, если ДА.

CP #07 "Последний столбец в БАЙТОВОМ режиме?

JR Z,L3BDC "Переход вперед, если ДА.

RLA "Контроль режима.

JR C,L3BD8 "Переход вперед, если СИМВОЛЬНЫЙ режим.

INC E " Сдвинуть позицию

INC E " курсора на один

L3BD8 INC E "столбец вправо.

INC C "Увеличить значение счетчика столбцов.

XOR A "Установить флаг Z.

RET "

L3BDC AND #8 0 "Обнулить

LD C,A "счетчик столбцов.

CALL L.LIN "Сдвинуть курсор вниз, если не послед.строка.

OR #07 "Начальный номер колонки для нулевого столбца.

LD E,A "Установить курсор в начало строки.

XOR A "Установить флаг Z.

RET "

WIND LD A,#2 8 "Атрибуты голубого фона и черных чернил.

CALL P.ATR "Печать атрибутов (курсор).

L3BEC CALL PR.SCR "Печать экрана (24 строки).

BIT 7,C "Контроль режима.

JR Z,L3BFC "Переход вперед, если БАЙТОВЫЙ режим.

PUSH DE "Сохранить позицию курсора.

LD DE,#487B "Позиция байта, дублирующего символ в курсоре.

LD B, (HL) "Загрузить код символа, указанного курсором.

CALL PR.B "Распечатать код символа в HEX-коде.

POP DE "Восстановить позицию курсора.

L3BFC CALL SCAN "Сканировать клавиатуру.

PUSH AF "Сохранить результаты сканирования.

L3C00 INC A "Установить флаг Z, если клавиша не нажата.

JR NZ,L3C06 "Переход вперед, если клавиша не нажата.

POP AF "Компенсация стека.

JR L3BEC "Возврат на печать экрана.

L3C06 LD A,#38 "Атрибуты белого фона и черных чернил.

CALL P.ATR "Стереть курсор.

POP AF "Извлечь результаты сканирования.

RET NZ "Вых.из п/п, если клав. нажата без CAPS SHIFT.

CP #03 "Нажата клавиша "DOWN"?

CALL Z,DOWN "Переместить курсор вниз, если ДА.

L3C12 JR Z,WIND "Возврат к началу, если курсор перемещен.

CP #04 "Нажата клавиша "LEFT"?

CALL Z,LEFT "Переместить курсор влево, если ДА.

L3C19 JR Z,L3C12 "Возврат к началу, если курсор перемещен.

CP #0B "Нажата клавиша "UP"?

CALL Z,UP "Переместить курсор вверх, если ДА.

L3C2 0 JR Z,L3C19 "Возврат к началу, если курсор перемещен.

CP #13 "Нажата клавиша "RIGHT"?

CALL Z, RIGHT "Переместить курсор вправо, если ДА.

JR Z,L3C2 0 "Возврат к началу, если курсор перемещен.

CP #20 "Установить флаг Z, если нажата BREAK.

RET "

CLS LD A,#38 "Атрибуты для всего экрана: PAPER 7" INK 0.

PUSH

HL

Сохранить

PUSH

BC

регистры.

LD

DE,#5AFE

Подготовить регистры

LD

BC,#02FF

к заполнению

LD

H, D

области

LD

L, C

атрибутов.

LD

(HL),A

Занести байт в послед. ячейку обл. атрибутов.

LDDR

Заполнить область атрибутов.

XOR

A

Код для заполнения дисплейного файла.

DEC

HL

Подготовить регистры

DEC

DE

к заполнению

LD

BC,#17FF

дисплейного файла.

LD

(HL),A

Занести байт в последнюю ячейку диспл.файла.

LDDR

Заполнить дисплейный файл.

LD

DE,#4001

Начальная позиция печати.

POP

BC

POP

HL

RET

IN B

SLA

B

Сдвиг

SLA

B

младшей

SLA

B

тетрады

SLA

B

в старшую.

OR

B

Соединить знач. рег. В с тетрадой в рег. А.

LD

B, A

Поместить чисто в регистр В.

RET

K.CONT

CALL

SCAN

Сканирование клавиатуры.

CP

#FF

Ни одна клавиша не нажата?

JR

Z,K.CONT

Возврат на начало, если ДА.

F.CONT

CALL

C.NUM

Преобразовать номер клавиши в код символа.

CP

#30

Нижняя граница кодов цифр.

JR

C,L3C6E

Переход вперед, если не цифра.

CP

#47

Верхняя граница кодов цифр.

RET

NC

Выход из п/п, если не цифра.

CP

#40

Преобразование

JR

C,L3C6C

кода цифры

SUB

#07

в соответствующее

L3C6C

SUB

#30

число.

L3C6E

CCF

Если код символа преобразован в число,

RET

то устанавливается флаг С.

IN4

LD

A,#28

Атрибуты голубого фона и черных чернил.

CALL

P.ATR4

Печать атрибутов в четырех знакоместах.

CALL

PR.HL

Распечатка рег.HL на экр. (случайное число).

CALL

K.CONT

Ожидание нажатия клавиши.

RET

NC

Выход, если нажата не цифра (в HEX-коде).

CALL

IN_HL

Ввести со сдвигом число в регистр HL.

JR

IN4

Возврат на начало п/п.

IN2

LD

A,#28

Атрибуты голубого фона и черных чернил.

CALL

P.ATR2

Печать атрибутов в двух знакоместах.

CALL

PR.B

Распечатка регистра В на экране (в HEX-коде).

DEC

E

Восстановить

DEC

E

позицию печати.

CALL

K.CONT

Ожидание нажатия клавиши.

RET

NC

Выход, если нажата не HEX-цифра.

CALL

IN_B

Ввести со сдвигом число в регистр В.

JR

IN2

Возврат на начало п/п.

MEN4

LD

C, #01

Будет введено одно 4-значное число.

LD

DE,#4001

Позиция печати.

JR

L3CA0

Переход вперед.

MEN4-D

LD

C, #02

Будет введено два 4-значных числа.

MEN4-A

CALL

CLS

Очистить экран.

L3CA0

CALL

IN4

Ввести 4-значное число с клавиатуры в рег.HL.

CP

#0D

Нажата клавиша ENTER?

JR

NZ,L3CA0

Возврат на ввод числа, если НЕТ.

EX

(SP),HL

Поместить введенное число в стек.

PUSH

HL

Вернуть в стек адрес возврата из п/п.

LD

A, #38

Атрибуты белого фона и черных чернил.

CALL

P.ATR4

Стереть голубой фон в поз. введенного числа.

CALL

DOWN

Переместить позицию печати вниз.

DEC

C

Контроль окончания ввода.

JR

NZ,L3CA0

Возврат, если ввод не окончен.

RET

MEN2

LD

C, #01

Будет введено одно 2-значное число.

MEN2-A

CALL

IN2

Ввести 2-значное число в регистр В.

CP

#0D

Нажата клавиша ENTER?

JR

NZ,MEN2-A

Возврат на ввод числа, если НЕТ.

LD

A, B

Извлечь введенное число.

BIT

0, C

Контроль четности номера вводимого числа.

EXX

JR

NZ,L3CC7

Переход вперед, если номер числа нечетный.

LD

H, A

Загрузить введенное число в регистр Н'.

JR

L3CCA

Переход вперед.

L3CC7

LD

L, A

Загрузить введенное число в регистр L'.

EX

(SP),HL

Поместить введенное число (числа) в стек.

PUSH

HL

Вернуть адрес возврата из п/п в стек.

L3CCA

EXX

LD

A, #38

Атрибуты белого фона и черных чернил.

CALL

P.ATR2

Стереть голубой фон в позиции печати.

CALL

DOWN

Переместить позицию печати вниз.

DEC

C

Контроль окончания ввода.

JR

NZ,MEN2-A

Возврат, если не окончен.

RET

T.SC.5

LD

BC,#0008

Установить задержку времени 0,5 сек.

T.SCAN

PUSH

AF

Компенсация стека в цикле.

L3CDB

POP

AF

CALL

SCAN

Сканирование клавиатуры.

PUSH

AF

Сохранить результат сканирования.

INC

A

Контроль нажатия клавиши.

JR

NZ,L3CE8

Переход вперед, если клавиша нажата.

DJNZ

L3CDB

Цикл задержки времени со сканированием.

DEC

C

Контроль истечения времени задержки.

JR

NZ,L3CDB

Возврат, если время не истекло.

L3CE8

POP

AF

Извлечь результат сканирования.

RET

LOAD

INC

D

Сбросить флаг Z.

EX

AF,AF'

Сохранить флаги и флаговый байт.

DEC

D

Восстановить регистр D.

DI

Запретить прерывания.

LD

A, #05

Задать голубой цвет для бордюра.

OUT

(#FE),A

"Установить цвет бордюра.

CALL

#0562

"LOAD/VERIFY без обработки ошибок и без EI

RET

C

"Выход из п/п, если нет ошибки ввода.

EXIT

CALL

TON

"Звуковой щелчок.

CALL

T.SC.5

"Сканирование клавиатуры в течение 0,5 сек

INC

A

"Контроль нажатия клавиши.

JR

Z,EXIT

"Возврат, если клавиша не нажата.

RET

"

Стандартная таблица клавиатуры (#0205).

HEX-

Сим

HEX-

Сим

HEX-

Сим

HEX-

Сим

клав.

код

вол

клав.

код

вол

клав.

код

вол

клав.

код

вол

#00

#42

B

#0A

#55

U

#14

#33

3

#1E

#53

S

#01

#48

H

#0B

#37

7

#15

#45

E

#1F

#5A

Z

#02

#59

Y

#0C

#34

4

#16

#44

D

#20

#20

SPC

#03

#36

6

#0D

#52

R

#17

#58

X

#21

#0D

ENT

#04

#35

5

#0E

#46

F

#18

#0E

SS

#22

#50

P

#05

#54

T

#0F

#43

C

#19

#4C

L

#23

#30

0

#06

#47

G

#10

#4D

M

#1A

#4F

O

#24

#31

1

#07

#56

V

#11

#4B

K

#1B

#39

9

#25

#51

Q

#08

#4E

N

#12

#49

I

#1C

#32

2

#26

#41

A

#09

#4A

J

#13

#38

8

#1D

#57

W

-

-

CS

Примечание. Номеру клавиши #27 соответствует CAPS SHIFT, но в таблице #0205 для нее не отведено места (таблица состоит из 39 байтов).

Описание работы программы.

Любая взламывающая программа должна как можно меньше "наследить" в ОЗУ, чтобы скрыть факт взлома от защитных процедур исследуемой программы, а также чтобы не повредить ее, поскольку она может занимать все ОЗУ. "Хаккер-93" для служебной работы использует только стек и, соответственно, имеет средства обхода защит, использующих стек. Наиболее неприятным защитным приемом является помещение стека в область дисплейного файла - тогда стирание экрана уничтожит стек. Может быть применен прием жесткого ограничения размеров стека - тогда монитор, записывая в стек свои данные, неизбежно уничтожит часть программы.

В первом случае монитор сразу после входа просигнализирует звуковыми щелчками, что нужно директивой "Р" скопировать стек в более подходящее место, но до этого обязательно нужно вывести картинку на магнитофон (вместе с расположенным в ней стеком) клавишей "Q", а перед возвратом в программу ввести картинку директивой "М".

Во втором случае нужно нажимать кнопку "NMI" вместе с клавишей CAPS SHIFT. Тогда монитор запишет в стек только три числа, а остальное "сбросит" в область цветовых атрибутов и даст знать щелчками, что стек нужно куда-то убрать.

Кроме кнопки "NMI", монитор можно вызвать из точек прерывания командами CALL #0067 и CALL #002B. В первом случае выполняется опрос клавиши CAPS SHIFT и прочие действия, как по вызову "NMI", а во втором ("короткий вход") нажатие CAPS SHIFT имитируется без опроса.

Входной блок.

Сразу после входа монитор записывает в стек (где уже имеется адрес возврата) значения AF и HL, после чего анализирует состояние клавиши CAPS SHIFT, фиксирует значение SP и регистра R.

47

Одновременно второй бит регистра флагов (флаг четности) фиксирует состояние триггера прерываний (0 - запрет, 1 - разрешение). Затем, если нажата клавиша CAPS SHIFT, в SP заносится адрес #5B00 (конец области атрибутов), и продолжается загрузка в стек значений регистров.

Вот полный перечень загружаемых значений: адрес возврата, AF, HL, RF, IF, SP, IX, IY, BC, DE, AF', BC', DE', HL'. Следует помнить, что помещенное в стек значение SP указывает на ячейку со значением регистра L, а то значение, которое выводится на экран директивой "Р", указывает адрес ячейки со значением регистра L'. А еще надо помнить, что при копировании стека из области атрибутов (после действия клавиши CAPS SHIFT) стек "рвется" и выше значения RF расположится "мусор", захваченный из области буфера ZX-принтера. Прерывания, кстати, запрещаются.

После загрузки в стек состояния процессора, контролируется значение указателя стека и, если оно ниже, чем #5B20, то выдаются звуковые щелчки, которые означают, что стек если и не в экране, то "въедет" туда при вызове директивы. Нажав любую клавишу, мы прекратим щелчки и попадем в точку OUT (#388F). В этой знаменитой точке начинается процедура ожидания ввода директив, сюда передается управление после окончания их работы. Эту точку можно использовать для входа в монитор, если не нужны описанные выше формальности и выход по директиве "Е". Если прерывания разрешены, то прямой вход в эту точку покажет жизнь системных переменных (естественно, в директиве "V"), бег системных часов, зоны "микрофонного эффекта" в экранной области, когда коды в ячейках забиваются шаблонами их символов, а шаблоны воспринимаются как коды и забиваются новыми шаблонами. Можно наблюдать деловитое мельтешение чисел в стеке, с дрожью глядеть на хлещущие в ОЗУ молнии сбоев... При запрещенных прерываниях системные переменные мертвы, а числа в стеке чинно изменяются при перемещениях курсора.

Блок директив.

Режим ожидания ввода директив легко узнается по последовательному изменению цвета бордюра через каждые 2 секунды. Как можно заметить, входной блок монитора не портит картинки, исключая вход с нажатием клавиши CAPS SHIFT.

Директива "Q" автоматически выведет картинку на магнитофон в виде стандартного блока кодов без заголовка. Если в ней что-то спрятано, то можно потом ввести ее в ОЗУ и просмотреть.

Директива "Р" портит только четыре знакоместа в левом верхнем углу экрана, где на голубом фоне выведет значение указателя стека. Кстати, числа в мониторе представляются только в HEX-коде. Значение SP можно редактировать цифровыми клавишами, а после утверждения клавишей ENTER 40 байтов из области стека копируются по новому значению указателя. Во избежание неприятностей с программой, следует копировать стек в свободную область памяти или, в крайнем случае, в область, где хранятся экраны.

Директива "С" стирает экран и входит в меню ввода трех 4-значных чисел - это начальный адрес копируемого блока, его длина в байтах и начальный адрес копии. Надо сказать, что меню в мониторе очень жесткое, оно не допускает изменения уже утвержденного числа, не предусматривает отмены директивы. Просто в левом верхнем углу на голубом поле распечатывается число, которое можно редактировать. После утверждения клавишей ENTER голубое поле смещается ниже, и в нем возникает другое число и т. д.

После набора всех чисел происходит переход к исполнению директивы. Следует помнить, что нулевая длина блока воспринимается монитором как 65536 байтов, то есть все поле памяти. Текстовых подсказок нет, поэтому надо помнить, какое именно число и в какой директиве вводится в данный момент. Итак, все числа введены, и утверждение последнего из них клавишей ENTER одновременно явится командой на исполнение директивы.

Директива "С" копирует блоки корректно при любых введенных значениях. Это достигается за счет того, что вниз по адресам копирует команда LDIR, а вверх - команда LDDR с соответствующим перерасчетом регистров. Пользователь может представить себе действие этой директивы так, как если бы блок, указанный первыми двумя числами копировался за пределы компьютера, а затем вписывался с адреса, указанного третьим числом. Данная директива весьма удобна, когда надо раздвинуть или сдвинуть части машинного кода, чтобы вставить или выбросить какие-то команды.

Директива "Е" извлекает из стека и загружает в регистры те значения, которые были в них на момент вызова монитора. При этом значение SP, записанное в стеке, используется таким образом, что даже в случае полного или частичного копирования стека директивой "Р" происходит возврат в прежний стек. Семь младших битов регистра R инкрементируются при чтении каждого кода операции (КОП), то есть 1-2 раза на каждой команде. Следовательно, чтобы программа по значению регистра R не обнаружила вмешательства в свою работу, нужно его скомпенсировать, то есть вычесть " лишние" инкременты. В мониторе от каждой из трех точек входа (#002B, #0066 и #0067) до захвата значения регистра R находится одинаковое количество команд (команда NOP по адресу #0066 компенсирует команды CALL в точках прерывания, так как при входе по "NMI" регистр R не инкрементируется). Это позволяет скомпенсировать регистр R одним числом. Также по значению флага Р регистра флагов восстанавливается состояние триггера прерываний. Выход в вызывающую программу происходит по команде RET.

Директива "М" вводит в меню начальный адрес блока, его длину, а также флаговый байт (стандартное значение - #00 для заголовка и #FF для блока кодов). Блок может быть введен с ленты только с тем флаговым байтом, с которым он выводился. После утверждения флагового байта директива ожидает нажатия клавиши "S" (SAVE), "L" (LOAD) или "V" (VERIFY). В первом случае происходит немедленный вывод блока или заголовка, а в других - бордюр становится голубым и ожидается блок с ленты. Подпрограммы "SAVE" и "LOAD/VERIFY" запрещают прерывания (и уже не разрешают). Клавиша BREAK прерывает действие этих подпрограмм. В случае корректной загрузки или верификации происходит выход из директивы, а при ошибке - Вы услышите щелчки.

Директива "N" вводит в меню начальный адрес, длину блока и код, которым будет заполнен этот блок.

Директива "I" без порчи экрана выведет слева вверху на голубом поле четырехзначное число, которое можно редактировать. Это адрес ячейки памяти. После утверждения адреса клавишей ENTER на месте старшего байта адреса распечатывается значение этой ячейки. Его тоже можно редактировать. После нажатия ENTER число запишется в ячейку и последует выход из директивы. Эта директива должна особенно понравиться любителям POKES.

Директива "F" вводит в меню начальный адрес и длину блока, а затем четыре одиночных байта. В этих байтах вводится разыскиваемая цепочка длиной 1-3 байта, после которой ставится маркер - код #FF. Директива сначала предполагает длину цепочки 3 байта и проверяет наличие маркера на 4-м месте. Если его там нет, то предполагается, что в цепочке два кода, и маркер ищется на 3-м месте. Если его и там нет, то без дальнейших проверок будет отыскиваться только первый код. После утверждения 4-го байта клавишей ENTER экран стирается, и на нем распечатываются адреса начала цепочки в памяти. К примеру, если отыскивается цепочка из трех кодов #FF, а в памяти обнаружится цепочка из пяти кодов #FF, то на экране распечатаются три первые адреса этой цепочки. Выход из директивы - по окончании просмотра блока, либо по заполнении экрана. На просмотр всей памяти уходит порядка 1,5 секунды.

Директива "V" стирает экран и вводит в меню только адрес входа в память. После утверждения на экране распечатываются 24 строки по 8 байтов в строке, начиная с утвержденного адреса. Информация из отображаемой области извлекается несколько сот раз в секунду, поэтому все изменения в этой области немедленно отображаются на экране. В основном, это сбои, но может быть и стек, и другие случаи. Причем, информация между столбцами и в свободных знакоместах экрана не регистрируется (то есть остается статичной), поэтому, попавшие туда сбойные байты останутся до переключения режимов.

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

Байт, находящийся в курсоре, редактируется цифровыми клавишами без утверждения, что требует осторожности, так как случайное нажатие цифровой клавиши обязательно испортит байт в ОЗУ. По этой причине неприятности гарантируются тем, у кого 40-клавишная клавиатура с плохо работающей клавишей CAPS SHIFT.

Автоматический роллинг экрана (непрерывный) вызывается клавишей "R", обратный роллинг - клавишей "U". Отменяется роллинг нажатием любой клавиши. Перелистать память за несколько минут можно, удерживая клавишу "Р", обратное перелистывание - клавиша "О".

Нажатие клавиши "G" запустит из экрана программу с адреса, указанного курсором. Если эта программа вся умещается в экране, сохраняет регистры C, DE, HL, а числовые результаты своей работы помещает в ячейки, присутствующие на экране, то командой перехода в точку #39D0 она вернется в этот же экран, на котором отобразятся и результаты ее работы. Кстати, в регистре HL содержится адрес байта в курсоре. Манипулируя этим значением, можно организовать и роллинг, и прыжки в любую область памяти.

Когда курсор попадает в область, заполненную одинаковыми байтами, клавиша "J" поможет " перепрыгнуть" эту область. Курсор остановится на первом отличающемся байте.

Клавиша "S" включит символьный режим отображения 24 строк по 16 символов в строке. Распечатка производится с адреса, указанного курсором. Коды, не входящие в набор 96 символов, отображаются в виде точек. Сервис здесь тот же, что и в байтовом режиме. HEX-код символа, находящегося в курсоре, отображается правее распечатки в 12-й экранной строке, что облегчает редактирование (только цифровыми клавишами!).

Перейти в байтовый режим можно нажатием клавиши "Н". Выход из директивы - клавиша BREAK. Клавиша ENTER дублирует клавишу RIGHT.

Блок подпрограмм.

TON (Звуковой щелчок). Посредством циклов, четырежды переключает динамик, выдавая щелчок при нажатии клавиши, после чего переходит в циклы задержки времени для подавления дребезга контактов. Общее время работы - 0,3 сек.

SCAN (Сканирование клавиатуры). Сканирует клавиатуру посредством стандартной подпрограммы KEY-SCAN (#028E). При нажатии только CAPS CHIFT или двойных клавиш - возврат в сканирование. Извлекает номер нажатой клавиши. Если при этом нажата CAPS SHIFT, устанавливает флаг

Z. Состояние CAPS CHIFT определяется после выхода из KEY-SCAN (см. ZX-РЕВЮ-94, N2, стр.52) отдельным опросом клавиши. Если клавиша (кроме CAPS SHIFT) нажата, выдается щелчок.

P.SIM (Печать символа на экране). Печатает символ из стандартного набора 96 литер, либо точку. В регистре DE - адрес нулевой линии нужного знакоместа.

PR.B (Распечатка регистра В на экране в HEX-коде). Преобразует тетрады из регистра В в коды символов цифр и распечатывает их. Позиция печати переходит на следующее знакоместо.

PR.HL (Распечатка регистра HL на экране в HEX-коде). Загружает в регистр В последовательно регистр H и регистр L, вызывая подпрограмму PR.B. Позиция печати сохраняется (нулевая линия начального знакоместа в DE).

P.ATR (Печать атрибутов в одном или двух знакоместах). Преобразует в регистре DE позицию печати в адрес атрибутов данного знакоместа, а затем загружает их (атрибуты) из аккумулятора в одно или два знакоместа, в зависимости от режима. Режим определяется старшим битом регистра C (0 - байты; 1 - символы) для печати курсора.

P.ATR2 (Печать атрибутов горизонтально в двух знакоместах). Сбрасывает флаг режима и вызывает подпрограмму P.ATR.

P.ATR4 (Печать атрибутов горизонтально в четырех знакоместах). Дважды вызывает подпрограмму P.ATR2.

P.LIN (Печать строки символов или байтов). С первой колонки экрана (адрес в DE) печатает содержимое HL (адрес начального кода распечатки), а затем распечатывает 8 байтов в HEX-коде или 16 символов, в зависимости от режима (флаг в регистре С).

AB.LIN (Абсолютный номер экранной строки). По значению позиции курсора (в DE) получает в регистре А значение абсолютного номера экранной строки от 0 до 23.

L.DE (Получение адреса в DE по номеру экранной строки). Выполняет действия, обратные подпрограмме AB.LIN, то есть по абсолютному номеру строки устанавливает в DE адрес ее нулевой линии нулевой колонки.

Z.LIN* (Контроль нулевой строки экрана). Декрементирует абсолютный номер строки, если она не нулевая, затем переходит в подпрограмму L.DE.

L.LIN* (Контроль последней строки экрана). Инкрементирует абсолютный номер строки, если она не последняя, затем переходит в подпрограмму L.DE.

STEP (Получение шага по строке для перемещения курсора). Заносит в DE шаг по строке (8 или 16) для вертикального перемещения курсора.

C.NUM (Определение кода символа по номеру нажатой клавиши). Заменяет в регистре А номер клавиши на код символа по таблице #0205.

P.SCR (Печать на экране 24 строк байтов или символов). По позиции курсора (в DE) и адресу ячейки памяти в курсоре (в HL) рассчитывает начальный адрес распечатки и выводит на экран 24 строки.

UP (Вверх). Перемещает курсор вверх, изменяя значения регистров HL и DE.

DOWN (Вниз). Полностью обратна подпрограмме UP. Подпрограммы UP и DOWN не изменяют DE, если не достигнут край экрана.

LEFT; RIGHT (Влево; вправо). Перемещают курсор назад или вперед на 1 адрес, изменяя DE и декрементируя (инкрементируя) регистр HL. По значению счетчика столбцов (7 битов регистра С) -переход в другую строку.

WIND (Окно). Распечатывает экран с курсором; сканирует клавиатуру, выполняя перемещение курсора. По нажатию других клавиш - выход из подпрограммы. Флаг Z=1, если нажата клавиша BREAK.

CLS (Очистка экрана). Устанавливает атрибуты INK 0; PAPER 7 посредством команды LDDR (см. ZX-РЕВЮ-92, № 9-10, стр. 208) заполняет область атрибутов и очищает дисплей. Устанавливает в DE #4001.

IN_B (Ввод числа в регистр В со сдвигом). Младшую тетраду в регистре B переносит в старшую, а на ее место вводит тетраду из рег. А.

IN_HL (Ввод числа в регистр HL со сдвигом). Выполняет операцию, аналогичную подпрограмме IN_B, с регистром HL.

K.CONT* (Сканирование клавиатуры до нажатия любой клавиши). При нажатии клавиши переходит в подпрограмму F.CONT.

F.CONT (Контроль нажатия цифровой клавиши в HEX-коде). Переводит номер клавиши в код символа. Код HEX-цифры заменяет числом с установленным флагом С.

IN2; IN4 (Ввод с клавиатуры 2- или 4-значного числа). Печатает на голубом фоне содержимое регистров В или HL. Редактирование - цифровыми клавишами. Выход из подпрограммы, если нажата не цифра.

MEN2; MEN4 (Меню для ввода 2- или 4-значных чисел с клавиатуры). Посредством подпрограммы IN2 или IN4 вводит количество чисел, заданное в регистре С и помещает в стек. Ввод в стек - по нажатию ENTER.

MEN4-D - точка для ввода в стек двух чисел плюс стирание экрана.

T.SCAN (Задержка времени со сканированием). Сканирует клавиатуру в течение времени, задаваемого в регистре ВС, затем выход из подпрограммы. По нажатию клавиши - выход немедленно.

T.SC.5 (Сканирование клавиатуры в течение 0,5 сек). Задает в регистре ВС задержку 0,5 сек., затем переходит в подпрограмму T.SCAN.

LOAD1 (Ввод блока кодов с магнитофона). Вводит через подпрограмму LD-BYTES (#0562) блок кодов с ленты. При ошибке переходит в подпрограмму EXIT.

EXIT (Подача щелчков в нештатной ситуации). Каждые 0,8 сек. выдает щелчок. По нажатию клавиши - выход из подпрограммы.

IN4 - Вход: DE - позиция печати. Выход: HL - введенное число; А - код символа нажатой клавиши (не цифры).

MEN2 - Вход: DE - позиция печати. Выход: число в стеке. Портит HL, B, DE, HL'. Обнуляет регистры А, С.

MEN4 - Вход: нет. Выход: число в стеке. Портит HL, DE. Обнуляет регистры C, A. MEN4-A Вход: С - количество вводимых чисел (до 24). Выход: число в стеке. Портит HL, DE. Обнуляет регистры С, А. Стирает экран.

T.SCAN - Вход: ВС - задержка времени. Выход: А - номер нажатой клавиши. Портит ВС. LOAD - Вход: IX - начальный адрес загрузки; DE - длина блока; A - флаговый байт; флаг C -LOAD/VERIFY. Выход: нет. Портит A, ВС, DE, HL. EXIT - Вход: нет. Выход: нет. Портит A, ВС.

Точки входа в подпрограммы.

Адрес

Обозначение

Входной блок.

#002B

"Короткий вход" -

имитация нажатия CS.

#005F

п/п IN_HL

#0066

Вход по нажатию

кнопки "NMI".

#0067

Вход из точки

прерывания.

#388F

п/п OUT - вход без сохранения регистров.

Блок директив.

#38A5

Вход в директиву "Q"

#38B7

Вход в директиву "C"

#38D6

Вход в директиву "P"

#38EB

Вход в директиву "E"

#390F

Вход в директиву "M"

#3936

Вход в директиву "N"

#394A

Вход в директиву "I"

#395F

Вход в директиву "F"

#39C1

Вход в директиву "V"

#39D0

Вход непосредственно в экран.

Блок подпрограмм.

#3A44

подпрограмма TON

#3A5B

подпрограмма SCAN

#3A77

подпрограмма P.SIM

#3A99

подпрограмма PR.B

#3AB5

подпрограмма PR.HL

#3AC2

подпрограмма P.ATR4

#3ACD

подпрограмма P.ATR2

#3AD5

подпрограмма P.ATR

#3AED

подпрограмма P.LIN

#3B17

подпрограмма AB.LIN

#3B25

подпрограмма Z.LIN

#3B2E

подпрограмма L.LIN

#3B36

подпрограмма L.DE

#3B44

подпрограмма STEP

#3B4D

подпрограмма C.NUM

Адрес

Обозначение

#3B59

подпрограмма P.SCR

#3B83

подпрограмма UP

#3B92

подпрограмма DOWN

#3BA5

подпрограмма LEFT

#3BC9

подпрограмма RIGHT

#3BE7

подпрограмма WIND

#3C2C

подпрограмма CLS

#3C2E

Очистка экрана с атрибутами, установкой в регистре A.

#3C4A

подпрограмма IN_B

#3C55

подпрограмма K.CONT

#3C5C

подпрограмма F.CONT

#3C70

подпрограмма IN4

#3C81

подпрограмма IN2

#3C94

подпрограмма MEN4

#3C9B

подпрограмма MEN4-D

#3C9D

подпрограмма MEN4-A

#3CB5

подпрограмма MEN2

#3CB7

подпрограмма MEN2-A

#3CD7

подпрограмма T.SC.5

#3CDA

подпрограмма T.SCAN

#3CEA

подпрограмма LOAD

#3CF6

подпрограмма EXIT




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Gamedev - 3D проецирование пола/трассы в играх.
Новости - ProTracker'а 3.4, First Association, подведение результатов Complex Compo, приостановке работ над ЧВ-2.
От авторов - Немного расскажу про оболочку нашей газеты.
Вступление - первый номер новой рекламно-информационной газеты Zx-World!
Хит-Парад - Десятка самых популярных программ в Чайковском.

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