Урок 3. Плата в слоте: компьютер рисует

В картинках

После этого урока плоттер подключён к Apple ][ платой в слоте 1, как настоящий. Тумблер REMOTE отдаёт управление компьютеру: POKE двигает перья и выбирает цвет, PEEK читает концевики и BUSY. Выключил REMOTE — снова работает пульт.


3.1. Идея: у платы три адреса

Процессор Apple разговаривает со всем вокруг через адреса: память, клавиатура, диск. Слоту 1 отведены адреса $C090…$C09F; плата плоттера берёт четыре из них:

АдресBASICЧто
$C09049296запись: шаг X, куда X, шаг Y, куда Y, перо
$C09149297чтение: концевики XL0 XL1 YL0 YL1 и BUSY
$C09249298запись: цвет 0–3
$C09349299не занят
1A151A140A130A120A110A100A90A81A70A60A51A40A30A2xA1xA0$C09xбит должен быть 1 → «не тот», если 0: берём НЕ (CD4069) — NA15, NA14, NA7, NA4бит должен быть 0 → «не тот», если 1: берём как естьG1 … G4CD4072 · OR4ANYBCD4071SELPНЕ ANYBA1 A0:00 — $C09001 — $C09110 — $C092
Дешифратор адреса: 14 старших бит должны совпасть с $C09x. Проще искать «хоть один не тот» — четыре ИЛИ на 4 входа, ИЛИ, и НЕ: SELP = 1, только если не отличается ни один.

3.2. Идея: дешифратор — «ни один бит не отличается»

$C090…$C093 в двоичном виде — 1100 0000 1001 00xx: 14 старших бит заданы, два младших выбирают регистр. Проверить 14 бит разом проще наоборот: найти хоть один не тот. Бит, который должен быть 1, — не тот, когда он 0 (берём его инверсию с CD4069: NA15, NA14, NA7, NA4); бит, который должен быть 0, — не тот, когда он 1 (берём как есть). Все 14 «не тех» — на ИЛИ:

  • G1 = NA15 ИЛИ NA14 ИЛИ ADDR13 ИЛИ ADDR12, G2 = ADDR11 ИЛИ … ИЛИ ADDR8 — CD4072 (ИЛИ на 4 входа);
  • G3 = NA7 ИЛИ ADDR6 ИЛИ ADDR5 ИЛИ NA4, G4 = ADDR3 ИЛИ ADDR2;
  • ANYB = G1 ИЛИ G2 ИЛИ G3 ИЛИ G4 (CD4071) — «хоть один бит не тот»;
  • SELP = НЕ ANYB — адрес наш.

3.3. Идея: запись в регистр

Регистр — D-триггеры CD4013: по фронту такта CL запоминают то, что на D. На D — данные процессора DOUT0…DOUT4, а такт должен прийти, только когда процессор пишет именно по этому адресу:

  • SELW = SELP И НЕ ADDR0 — $C090 или $C092;
  • WR = SELW И write — и это запись;
  • WE0 = WR И НЕ ADDR1 — $C090, WE2 = WR И ADDR1 — $C092;
  • такты регистров: LCK0 = WE0 И CLK, LCK2 = WE2 И CLK — фронт такта машины, когда данные на шине уже стоят.

$C090 — пять триггеров (AXS, AXD, AYS, AYD, APEN), $C092 — два (AC0, AC1). RST машины сбрасывает их: перо поднято, цвет чёрный.

3.4. Идея: чтение $C091 — на ту же шину

Когда процессор читает $C091, плата должна выставить свои биты на шину данных DIN0…DIN4, а в остальное время — не мешать машине:

  • SELR1 = SELP И ADDR0 И НЕ ADDR1 — $C091; OEP = SELR1 И RnW — и это чтение;
  • бит платы на шину: PRD0 = XL0 И OEP, … PRD4 = BUSY И OEP — при чужом адресе все PRD = 0;
  • шина к процессору: DIN = MUX ИЛИ PRD (CD4071). MUX — то, что выдаёт сама машина (чип DataInMux); по адресу $C091 у неё ничего нет — там нули, и проходят биты платы. По чужим адресам PRD = 0 — проходят данные машины.

Поэтому у машины выходы DataInMux переименовываются в MUX0…MUX4: имя DIN теперь у выхода ИЛИ.

3.5. Идея: кто управляет — CD4019

У CD4019 четыре ячейки «И-ИЛИ»: D = A И KA ИЛИ B И KB. Если KA = REMOTE, а KB = НЕ REMOTE, ячейка — переключатель:

REMOTEKAKBD
110A — регистр компьютера
001B — пульт

Две CD4019 — семь переключателей: шаг и направление X и Y, перо, два бита цвета. Их выходы XSTEP, XDIR, YSTEP, YDIR, PEN, COL0, COL1 теперь ведут плоттер — поэтому ноги осей, пера и сравнения цвета перецепляются на них. Револьвер, BUSY и концевики работают как прежде — им всё равно, кто назвал цвет.

3.6. Сборка

Поверх урока 2. Плата — в слот 1 машины: она слушает шину Apple (адрес ADDR0…ADDR15, данные DOUT0…DOUT4, write, RnW, CLK, RST — метки машины) и отвечает на DIN0…DIN4. Тумблер REMOTE выбирает, кто управляет плоттером: компьютер или пульт.

Шаг 1. Дешифратор адреса

ДетальНога / действиеМетка / куда
TI CD4069UBA
G
B
H
C
I
D
J
E
K
F
L
ADDR15
NA15
ADDR14
NA14
ADDR7
NA7
ADDR4
NA4
ANYB
SELP
ADDR0
NA0
TI CD4072BA
B
C
D
J
E
F
G
H
K
NA15
NA14
ADDR13
ADDR12
G1
ADDR11
ADDR10
ADDR9
ADDR8
G2
TI CD4072BA
B
C
D
J
E
F
G
H
K
NA7
ADDR6
ADDR5
NA4
G3
ADDR3
ADDR2
GND
GND
G4
TI CD4071BA
B
J
C
D
K
E
F
L
G
H
M
G1
G2
H1
G3
G4
H2
H1
H2
ANYB
MUX0
PRD0
DIN0
ДетальНогаОтцепить отПрицепить к
TI CD4069UB, выход которой = NBUSYAGNDADDR1
TI CD4069UB, выход которой = NBUSYG— (не подключена)NA1
TI CD4069UB, выход которой = NBUSYBGNDREMOTE
TI CD4069UB, выход которой = NBUSYH— (не подключена)NREM

Шаг 2. Запись и чтение

ДетальНога / действиеМетка / куда
TI CD4081BA
B
J
C
D
K
E
F
L
G
H
M
SELP
NA0
SELW
SELW
write
WR
WR
NA1
WE0
WR
ADDR1
WE2
TI CD4081BA
B
J
C
D
K
E
F
L
G
H
M
WE0
CLK
LCK0
WE2
CLK
LCK2
SELP
ADDR0
SELR
SELR
NA1
SELR1
TI CD4081BA
B
J
C
D
K
E
F
L
G
H
M
SELR1
RnW
OEP
XL0
OEP
PRD0
XL1
OEP
PRD1
YL0
OEP
PRD2
TI CD4071BA
B
J
C
D
K
E
F
L
G
H
M
MUX1
PRD1
DIN1
MUX2
PRD2
DIN2
MUX3
PRD3
DIN3
MUX4
PRD4
DIN4
ДетальНогаОтцепить отПрицепить к
TI CD4081B, выход которой = LXSAGNDYL1
TI CD4081B, выход которой = LXSBGNDOEP
TI CD4081B, выход которой = LXSJ— (не подключена)PRD3
TI CD4081B, выход которой = LXSCGNDBUSYH
TI CD4081B, выход которой = LXSDGNDOEP
TI CD4081B, выход которой = LXSK— (не подключена)PRD4

Шаг 3. Регистры

ДетальНога / действиеМетка / куда
TI CD4013BS1
R1
D1
CL1
Q1
S2
R2
D2
CL2
Q2
GND
RST
DOUT0
LCK0
AXS
GND
RST
DOUT1
LCK0
AXD
TI CD4013BS1
R1
D1
CL1
Q1
S2
R2
D2
CL2
Q2
GND
RST
DOUT2
LCK0
AYS
GND
RST
DOUT3
LCK0
AYD
TI CD4013BS1
R1
D1
CL1
Q1
S2
R2
D2
CL2
Q2
GND
RST
DOUT4
LCK0
APEN
GND
RST
DOUT0
LCK2
AC0
ДетальНогаОтцепить отПрицепить к
TI CD4013B, выход которой = MOVEDR1GNDRST
TI CD4013B, выход которой = MOVEDD1GNDDOUT1
TI CD4013B, выход которой = MOVEDCL1GNDLCK2
TI CD4013B, выход которой = MOVEDQ1— (не подключена)AC1

Не подключать: QN1, QN2 у каждой из трёх CD4013B.

Шаг 4. REMOTE и CD4019

Тумблер — Input из палитры.

ДетальНога / действиеМетка / куда
Input (тумблер)выходREMOTE
TI CD4019BKA
KB
A1
B1
D1
A2
B2
D2
A3
B3
D3
A4
B4
D4
REMOTE
NREM
AXS
LXS
XSTEP
AXD
RIGHT
XDIR
AYS
LYS
YSTEP
AYD
DOWN
YDIR
TI CD4019BKA
KB
A1
B1
D1
A2
B2
D2
A3
B3
D3
A4
B4
REMOTE
NREM
APEN
LPEN
PEN
AC0
LC0
COL0
AC1
LC1
COL1
GND
GND

Не подключать: D4 у CD4019B.

Шаг 5. Оси, перо и цвет — от CD4019

Ноги механики переименовать так же: двойной клик по метке на ноге.

ДетальНогаОтцепить отПрицепить к
Linear axis — ось XSTEPLXSXSTEP
Linear axis — ось XDIRRIGHTXDIR
Linear axis — ось YSTEPLYSYSTEP
Linear axis — ось YDIRDOWNYDIR
TI CD4081B, выход которой = STEPTCLPENPEN
TI CD4070B, выход которой = X0ALC0COL0
TI CD4070B, выход которой = X0CLC1COL1

Шаг 6. Шина данных Apple

У чипа машины DataInMux метки DIN0…DIN4 на его выходах переименуй в MUX0…MUX4 (у процессора MOS6502 метки DIN0…DIN4 остаются). Теперь данные к процессору идут через плату: CD4071 складывает биты чтения платы с данными машины.

ДетальНогаОтцепить отПрицепить к
DataInMux (чип машины), выход которого = DIN0DIN0DIN0MUX0
DataInMux (чип машины), выход которого = DIN1DIN1DIN1MUX1
DataInMux (чип машины), выход которого = DIN2DIN2DIN2MUX2
DataInMux (чип машины), выход которого = DIN3DIN3DIN3MUX3
DataInMux (чип машины), выход которого = DIN4DIN4DIN4MUX4

3.7. Проверка

  1. Режим Turbo, включи питание. REMOTE выключен — плоттер слушается пульта, как в уроке 2.
  2. Включи REMOTE. Машина загрузилась — набери в BASIC (Return после каждой строки):
PRINT PEEK(49297)POKE 49298,2PRINT PEEK(49297)
  1. Первое число — 5, если обе каретки у моторов (горят концевики XL0 и YL0); если каретки ты отвёл пультом — другое. POKE 49298,2 — компьютер назвал зелёный: загорается BUSY, головка поворачивается. Пока крутится, PEEK даёт число на 16 больше (бит BUSY); когда встала — снова прежнее.
  2. Короткая программа — квадрат зелёным:
10 FOR I = 1 TO 40: POKE 49296,19: POKE 49296,18: NEXT20 FOR I = 1 TO 40: POKE 49296,28: POKE 49296,24: NEXT30 FOR I = 1 TO 40: POKE 49296,17: POKE 49296,16: NEXT40 FOR I = 1 TO 40: POKE 49296,20: POKE 49296,16: NEXT50 POKE 49296,0RUN
КомандаЧто делает плоттер
POKE 49296,V$C090: биты V — шаг X, куда X, шаг Y,
куда Y, перо (1, 2, 4, 8, 16)
POKE 49298,C$C092: цвет 0–3 — головка доворачивает
PEEK(49297)$C091: XL0 1, XL1 2, YL0 4, YL1 8, BUSY 16
REMOTE выключенпульт, как в уроках 1–2

Вставка урока 3 (Cmd+I)

Вставлять в машину Apple ][ (кнопка DEMO) вместо уроков 1–3: ставит всё устройство, переименовывает выходы DataInMux.

# Урок 3 — плата в слоте: дешифратор $C090–$C093, регистры, чтение концевиков и BUSY; REMOTE/LOCAL на CD4019.# $C090 запись: 0 XSTEP 1 XDIR 2 YSTEP 3 YDIR 4 PEN. $C091 чтение: 0 XL0 1 XL1 2 YL0 3 YL1 4 BUSY. $C092 запись: 0–1 цвет.# ---------- механика: ось X, ось Y на её каретке, головка на каретке Y, чёрное перо, бумага ----------maxis ax{len=400}(STEP=XSTEP, DIR=XDIR, L0=XL0, L1=XL1, STALL=XSTALL)maxis ay{len=300, ang=90}(STEP=YSTEP, DIR=YDIR, L0=YL0, L1=YL1, STALL=YSTALL)mount(ay, ax.car)mtable tt(A=NJ1, B=NJ2, C=J1, D=J2)mount(tt, ay.car)mpen k0{color=black}(DOWN=DOWN0)mount(k0, tt.d0)mpaper p{w=460, h=360}at(p, 0, 0)at(ax, p, -41, -138)# ---------- пульт: генератор шагов, стрелки, PEN UP/DOWN ----------clock{rt=60}(CKL)button{label="LEFT"}(LEFT)button{label="RIGHT"}(RIGHT)button{label="UP"}(UP)button{label="DOWN"}(DOWN)button{label="PEN UP/DOWN"}(PENB)# ---------- CD4071: нажата стрелка по X, по Y; ERROR — каретка упёрлась ----------"TI CD4071B"(A=LEFT, B=RIGHT, J=LR, C=UP, D=DOWN, K=UD, E=XSTALL, F=YSTALL, L=ERROR, G=Q6, H=RST, M=QR)# ---------- CD4081: шаги — такт 60 Гц, пока нажата стрелка ----------"TI CD4081B"(A=YL1, B=OEP, C=BUSYH, D=OEP, E=CKL, F=LR, L=LXS, G=CKL, H=UD, M=LYS, J=PRD3, K=PRD4)# ---------- CD4013: PEN UP/DOWN — триггер-переключатель ----------"TI CD4013B"(S1=GND, R1=RST, D1=NLPEN, CL1=PENB, Q1=LPEN, QN1=NLPEN, S2=GND, R2=RST, D2=NLC0, CL2=SELB, Q2=LC0, QN2=NLC0)# ---------- лампы POWER и ERROR ----------led{color=green}(VCC)led{color=red}(ERROR)# ---------- кнопка SELECT ----------button{label="SELECT"}(SELB)# ---------- CD4013: старший бит цвета ----------"TI CD4013B"(S1=GND, R1=RST, D1=NLC1, CL1=NLC0, Q1=LC1, QN1=NLC1, S2=GND, R2=GND, D2=GND, CL2=GND)# ---------- генератор мотора револьвера ----------clock{rt=10}(CKT)# ---------- CD4070: цвет ≠ перо у рабочей точки ----------"TI CD4070B"(A=COL0, B=CP0, J=X0, C=COL1, D=CP1, K=X1, E=GND, F=GND, G=GND, H=GND)# ---------- CD4071: MOVE — крутить; BUSY — крутит или только что докрутил ----------"TI CD4071B"(A=X0, B=X1, J=MOVE, C=MOVE, D=MOVED, K=BUSYH, E=GND, F=GND, G=GND, H=GND)# ---------- CD4013: MOVED — MOVE полтакта назад (второй триггер; первый — в уроке 3) ----------"TI CD4013B"(S1=GND, R1=RST, D1=DOUT1, CL1=LCK2, S2=GND, R2=RST, D2=MOVE, CL2=NCKT, Q2=MOVED, Q1=AC1)# ---------- CD4069: НЕ BUSY, НЕ такта (входы A и B — в уроке 3) ----------"TI CD4069UB"(A=ADDR1, B=REMOTE, C=BUSYH, I=NBUSY, D=CKT, J=NCKT, E=GND, F=GND, G=NA1, H=NREM)# ---------- CD4081: шаг мотора, перо можно опустить, пара перьев ----------"TI CD4081B"(A=CKT, B=MOVE, J=STEPT, C=PEN, D=NBUSY, K=PDN, E=PDN, F=NCP1, L=E0, G=PDN, H=CP1, M=E1)# ---------- CD4081: какое перо опустить ----------"TI CD4081B"(A=E0, B=NCP0, J=DOWN0, C=E0, D=CP0, K=DOWN1, E=E1, F=NCP0, L=DOWN2, G=E1, H=CP0, M=DOWN3)# ---------- CD4013: фазы мотора — два триггера по кругу ----------"TI CD4013B"(S1=GND, R1=RST, D1=NJ2, CL1=STEPT, Q1=J1, QN1=NJ1, S2=GND, R2=RST, D2=J1, CL2=STEPT, Q2=J2, QN2=NJ2)# ---------- CD4017: четверть оборота = 6 шагов ----------"TI CD4017B"(CLOCK=STEPT, RESET=QR, INH=GND, O6=Q6, CO=QCO)# ---------- CD4013: номер пера у рабочей точки ----------"TI CD4013B"(S1=GND, R1=RST, D1=NCP0, CL1=QCO, Q1=CP0, QN1=NCP0, S2=GND, R2=RST, D2=NCP1, CL2=NCP0, Q2=CP1, QN2=NCP1)# ---------- лампа BUSY ----------led{color=yellow}(BUSYH)# ---------- перья: красное, зелёное, синее ----------mpen k1{color=red}(DOWN=DOWN1)mount(k1, tt.d3)mpen k2{color=green}(DOWN=DOWN2)mount(k2, tt.d2)mpen k3{color=blue}(DOWN=DOWN3)mount(k3, tt.d1)# ---------- дешифратор адреса $C090–$C093 ----------"TI CD4069UB"(A=ADDR15, G=NA15, B=ADDR14, H=NA14, C=ADDR7, I=NA7, D=ADDR4, J=NA4, E=ANYB, K=SELP, F=ADDR0, L=NA0)"TI CD4072B"(A=NA15, B=NA14, C=ADDR13, D=ADDR12, J=G1, E=ADDR11, F=ADDR10, G=ADDR9, H=ADDR8, K=G2)"TI CD4072B"(A=NA7, B=ADDR6, C=ADDR5, D=NA4, J=G3, E=ADDR3, F=ADDR2, G=GND, H=GND, K=G4)"TI CD4071B"(A=G1, B=G2, J=H1, C=G3, D=G4, K=H2, E=H1, F=H2, L=ANYB, G=MUX0, H=PRD0, M=DIN0)# ---------- CD4081: запись в $C090 и в $C092 ----------"TI CD4081B"(A=SELP, B=NA0, J=SELW, C=SELW, D=write, K=WR, E=WR, F=NA1, L=WE0, G=WR, H=ADDR1, M=WE2)# ---------- CD4081: такт регистров, чтение $C091 ----------"TI CD4081B"(A=WE0, B=CLK, J=LCK0, C=WE2, D=CLK, K=LCK2, E=SELP, F=ADDR0, L=SELR, G=SELR, H=NA1, M=SELR1)# ---------- CD4081: биты чтения ----------"TI CD4081B"(A=SELR1, B=RnW, J=OEP, C=XL0, D=OEP, K=PRD0, E=XL1, F=OEP, L=PRD1, G=YL0, H=OEP, M=PRD2)# ---------- CD4071: биты чтения — на шину данных ----------"TI CD4071B"(A=MUX1, B=PRD1, J=DIN1, C=MUX2, D=PRD2, K=DIN2, E=MUX3, F=PRD3, L=DIN3, G=MUX4, H=PRD4, M=DIN4)# ---------- регистр $C090: шаги, направления, перо ----------"TI CD4013B"(S1=GND, R1=RST, D1=DOUT0, CL1=LCK0, Q1=AXS, S2=GND, R2=RST, D2=DOUT1, CL2=LCK0, Q2=AXD)"TI CD4013B"(S1=GND, R1=RST, D1=DOUT2, CL1=LCK0, Q1=AYS, S2=GND, R2=RST, D2=DOUT3, CL2=LCK0, Q2=AYD)"TI CD4013B"(S1=GND, R1=RST, D1=DOUT4, CL1=LCK0, Q1=APEN, S2=GND, R2=RST, D2=DOUT0, CL2=LCK2, Q2=AC0)# ---------- тумблер REMOTE ----------input(REMOTE)# ---------- CD4019: кто управляет — компьютер (REMOTE = 1) или пульт ----------"TI CD4019B"(KA=REMOTE, KB=NREM, A1=AXS, B1=LXS, D1=XSTEP, A2=AXD, B2=RIGHT, D2=XDIR, A3=AYS, B3=LYS, D3=YSTEP, A4=AYD, B4=DOWN, D4=YDIR)"TI CD4019B"(KA=REMOTE, KB=NREM, A1=APEN, B1=LPEN, D1=PEN, A2=AC0, B2=LC0, D2=COL0, A3=AC1, B3=LC1, D3=COL1, A4=GND, B4=GND)reconnect(DIN0.DIN0 = MUX0)reconnect(DIN1.DIN1 = MUX1)reconnect(DIN2.DIN2 = MUX2)reconnect(DIN3.DIN3 = MUX3)reconnect(DIN4.DIN4 = MUX4)

Не получается? Что-то не работает →