-
Notifications
You must be signed in to change notification settings - Fork 10
/
chapter-next-ports.tex
395 lines (317 loc) · 23.1 KB
/
chapter-next-ports.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
\section{Ports and Registers}
\label{zx_next_ports}
% ────────────────────────────────────────────────────────────────────────────────
% ─██████████████─██████████████─████████████████───██████████████─██████████████─
% ─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░░░██───██░░░░░░░░░░██─██░░░░░░░░░░██─
% ─██░░██████░░██─██░░██████░░██─██░░████████░░██───██████░░██████─██░░██████████─
% ─██░░██──██░░██─██░░██──██░░██─██░░██────██░░██───────██░░██─────██░░██─────────
% ─██░░██████░░██─██░░██──██░░██─██░░████████░░██───────██░░██─────██░░██████████─
% ─██░░░░░░░░░░██─██░░██──██░░██─██░░░░░░░░░░░░██───────██░░██─────██░░░░░░░░░░██─
% ─██░░██████████─██░░██──██░░██─██░░██████░░████───────██░░██─────██████████░░██─
% ─██░░██─────────██░░██──██░░██─██░░██──██░░██─────────██░░██─────────────██░░██─
% ─██░░██─────────██░░██████░░██─██░░██──██░░██████─────██░░██─────██████████░░██─
% ─██░░██─────────██░░░░░░░░░░██─██░░██──██░░░░░░██─────██░░██─────██░░░░░░░░░░██─
% ─██████─────────██████████████─██████──██████████─────██████─────██████████████─
% ────────────────────────────────────────────────────────────────────────────────
\newcommand{\ZXSee}[1]{(see section \PortXRef{#1})}
\subsection{Mapped Spectrum Ports}
\begingroup
\newcommand{\zxport}[4]{
\tt {#1} &
{\tt \$#2} &
\IfEq{#3}{}{}{\tt \%#3} &
#4\\
}
\setlength{\extrarowheight}{5pt} % a bit more spacing between items for clearer visuals
\begin{tabularx}{\textwidth}{lllX}
{\tt RW} & Addr & Mask & Description \\
\hline
\zxport{RW}{103B}{0001 0000 0011 1011}{Sets and reads the I2C SCL line}
\zxport{RW}{113B}{0001 0001 0011 1011}{Sets and reads the I2C SDA line}
\zxport{RW}{123B}{0001 0010 0011 1011}{Enables layer 2 and controls paging of layer 2 screen into lower memory \ZXSee{123B}}
\zxport{RW}{133B}{0001 0011 0011 1011}{Sends byte to serial port. Read tells if data is available in RX buffer}
\zxport{RW}{143B}{0001 0100 0011 1011}{Reads data from serial port, write sets the baud rate}
\zxport{RW}{153B}{0001 0101 0011 1011}{Configuration of UART interfaces}
\zxport{-W}{1FFD}{0001 ---- ---- --0-}{Controls ROM paging and special paging options from the +2a/+3 \ZXSee{1FFD}}
\zxport{RW}{243B}{0010 0100 0011 1011}{Selects active port for TBBlue/Next feature configuration \ZXSee{243B}}
\zxport{RW}{253B}{0010 0101 0011 1011}{Reads and/or writes the selected TBBlue control register \ZXSee{253B}}
\zxport{RW}{303B}{0011 0000 0011 1011}{Sets active sprite-attribute index and pattern-slot index, reads sprite status \ZXSee{303B}}
\zxport{-W}{7FFD}{01-- ---- ---- --0-}{Selects active RAM, ROM, and displayed screen \ZXSee{7FFD}}
\zxport{-W}{BFFD}{10-- ---- ---- --0-}{Writes to the selected register of the selected sound chip \ZXSee{BFFD}}
\zxport{-W}{DFFD}{1101 1111 1111 1101}{Provides additional bank select bits for extended memory \ZXSee{DFFD}}
\zxport{R-}{FADF}{---- ---0 --0- ----}{Reads buttons on Kempston Mouse}
\zxport{R-}{FBDF}{---- -0-1 --0- ----}{X coordinate of Kempston Mouse, 0-255}
\zxport{R-}{FFDF}{---- -1-1 --0- ----}{Y coordinate of Kempston Mouse, 0-192}
\zxport{-W}{FFFD}{11-- ---- ---- --0-}{Controls stereo channels and selects active sound chip and sound chip channel \ZXSee{FFFD}}
\end{tabularx}
\pagebreak
\vspace*{9ex}
\begin{tabularx}{\textwidth}{lllX}
{\tt RW} & Addr & Mask & Description \\
\hline
\zxport{RW}{xx0B}{---- ---- 0000 1011}{Controls Z8410 DMA chip via MB02 standard \ZXSee{xx0B}}
\zxport{R-}{xx1F}{---- ---- 0001 1111}{Reads movement of joysticks using Kempston interface}
\zxport{RW}{xx37}{---- ---- ---- ----}{Kempston interface second joystick variant and controls joystick I/O}
\zxport{-W}{xx57}{---- ---- 0101 0111}{Uploads sprite positions, visibility, colour type and effect flags \ZXSee{xx5B}}
\zxport{-W}{xx5B}{---- ---- 0101 1011}{Used to upload the pattern of the selected sprite \ZXSee{xx5B}}
\zxport{RW}{xx6B}{---- ---- 0110 1011}{Controls zxnDMA chip \ZXSee{xx6B}}
\zxport{-W}{xxDF}{---- ---- --01 1111}{Output to SpecDrum DAC}
\zxport{RW}{xxFE}{xxxx xxxx ---- ---0}{Reading with particular high bytes returns keyboard status \ZXSee{xxFE}, write changes border colour and base Spectrum audio settings \ZXSee{xxFEWrite}}
\zxport{RW}{xxFF}{---- ---- ---- ----}{Controls Timex Sinclair video modes and colours in hi-res mode. Readable when bit 2 of \PortTextXRef{08} is set}
\end{tabularx}
\endgroup
\pagebreak
\subsection{Next/TBBlue Feature Control Registers}
\label{zx_next_tbblue_registers}
Specific features of the Next are controlled via these register numbers, accessed through ports \PortTextXRef[]{243B} and \PortTextXRef[]{253B} (see page \PortPage{243B} for details). All registers can also be written to directly with the {\tt NEXTREG} instruction.
\begingroup
\NewDocumentEnvironment{tbbluereg}{ +b }{
\begin{tabularx}{\textwidth}{llX}
{\tt RW} & Port & Description \\
\hline
#1
\end{tabularx}
}{}
\newcommand{\nextport}[3]{
{\tt #1} &
{\tt \$#2} &
#3 \\
}
\setlength{\extrarowheight}{2pt}
\begin{tbbluereg}
\nextport{R-}{0}{Identifies TBBlue board type. Should always be {\tt 10} on Next}
\nextport{R-}{1}{Identifies core (FPGA image) version}
\nextport{RW}{2}{Identifies type of last reset. Can be written to force reset}
\nextport{RW}{3}{Identifies timing and machine type}
\nextport{-W}{4}{In config mode, allows RAM to be mapped to ROM area}
\nextport{RW}{5}{Sets joystick mode, video frequency and Scandoubler}
\nextport{RW}{6}{Enables CPU Speed key, DivMMC, Multiface, Mouse and AY audio \ZXSee{06}}
\nextport{RW}{7}{Sets CPU Speed, reads actual speed}
\nextport{RW}{8}{ABC/ACB Stereo, Internal Speaker, SpecDrum, Timex Video Modes, Turbo Sound Next, RAM contention and (un)lock 128k paging \ZXSee{08}}
\nextport{RW}{9}{Sets scanlines, AY mono output, sprite-id lockstep, resets DivMMC mapram and disables HDMI audio \ZXSee{09}}
\nextport{RW}{0A}{Mouse buttons and DPI config}
\nextport{R-}{0E}{Identifies core (FPGA image) version (sub minor number)}
\nextport{RW}{10}{Used within the Anti-brick system}
\nextport{RW}{11}{Sets video output timing variant \ZXSee{11}}
\nextport{RW}{12}{Sets the bank number where Layer 2 video memory begins \ZXSee{12}}
\nextport{RW}{13}{Sets the bank number where the Layer 2 shadow screen begins}
\nextport{RW}{14}{Sets the transparent colour for Layer 2, ULA and LoRes pixel data}
\nextport{RW}{15}{Enables/disables sprites and Lores Layer, and chooses priority of sprites and Layer 2 \ZXSee{15}}
\nextport{RW}{16}{Sets X pixel offset used for drawing Layer 2 graphics on the screen \ZXSee{16}}
\nextport{RW}{17}{Sets Y offset used when drawing Layer 2 graphics on the screen \ZXSee{17}}
\nextport{RW}{18}{Sets and reads clip-window for Layer 2 \ZXSee{18}}
\nextport{RW}{19}{Sets and reads clip-window for Sprites \ZXSee{19}}
\nextport{RW}{1A}{Sets and reads clip-window for ULA/LoRes layer}
\nextport{RW}{1B}{Sets and reads clip-window for Tilemap \ZXSee{1B}}
\nextport{RW}{1C}{Controls (resets) the clip-window registers indices \ZXSee{1C}}
\nextport{R-}{1E}{Holds the MSB of the raster line currently being drawn}
\nextport{R-}{1F}{Holds the eight LSBs of the raster line currently being drawn}
\end{tbbluereg}
\pagebreak
\vspace*{11.8ex} % this aligns content with previous page vertically
\begin{tbbluereg}
\nextport{RW}{22}{Controls the timing of raster interrupts and the ULA frame interrupt \ZXSee{22}}
\nextport{RW}{23}{Holds the eight LSBs of the line on which a raster interrupt should occur \ZXSee{23}}
\nextport{RW}{26}{Pixel X offset ({\tt 0-255}) to use when drawing ULA Layer}
\nextport{RW}{27}{Pixel Y offset ({\tt 0-191}) to use when drawing ULA Layer}
\nextport{RW}{28}{PS/2 Keymap address MSB, read (pending) first byte of palette colour}
\nextport{-W}{29}{PS/2 Keymap address LSB}
\nextport{-W}{2A}{High data to PS/2 Keymap (MSB of data in bit 0)}
\nextport{-W}{2B}{Low eight LSBs of PS/2 Keymap data}
\nextport{RW}{2C}{DAC B mirror, read current I2S left MSB}
\nextport{RW}{2D}{SpecDrum port 0xDF / DAC A+D mirror, read current I2S LSB}
\nextport{RW}{2E}{DAC C mirror, read current I2S right MSB}
\nextport{RW}{2F}{Sets the pixel offset (two high bits) used for drawing Tilemap graphics on the screen \ZXSee{2F}}
\nextport{RW}{30}{Sets the pixel offset (eight low bits) used for drawing Tilemap graphics on the screen \ZXSee{30}}
\nextport{RW}{31}{Sets the pixel offset used for drawing Tilemap graphics on the screen \ZXSee{31}}
\nextport{RW}{32}{Pixel X offset ({\tt 0-255}) to use when drawing LoRes Layer}
\nextport{RW}{33}{Pixel Y offset ({\tt 0-191}) to use when drawing LoRes Layer}
\nextport{RW}{34}{Selects sprite index {\tt 0-127} to be affected by writes to other Sprite ports (and mirrors) \ZXSee{34}}
\nextport{-W}{35}{Writes directly into byte 1 of port \PortAddr{xx57}~\ZXSee{35}}
\nextport{-W}{36}{Writes directly into byte 2 of port \PortAddr{xx57}~\ZXSee{36}}
\nextport{-W}{37}{Writes directly into byte 3 of port \PortAddr{xx57}~\ZXSee{37}}
\nextport{-W}{38}{Writes directly into byte 4 of port \PortAddr{xx57}~\ZXSee{38}}
\nextport{-W}{39}{Writes directly into byte 5 of port \PortAddr{xx57}~\ZXSee{39}}
\nextport{RW}{40}{Chooses a palette element (index) to manipulate with \ZXSee{40}}
\nextport{RW}{41}{Use to set/read 8-bit colours of the ULANext palette \ZXSee{41}}
\nextport{RW}{42}{Specifies mask to extract ink colour from attribute cell value in ULANext mode}
\nextport{RW}{43}{Enables or disables Enhanced ULA interpretation of attribute values and toggles active palette \ZXSee{43}}
\nextport{RW}{44}{Sets 9-bit (2-byte) colours of the Enhanced ULA palette, or to read second byte of colour \ZXSee{44}}
\end{tbbluereg}
\pagebreak
\begin{tbbluereg}
\nextport{RW}{4A}{8-bit colour to be used when all layers contain transparent pixel \ZXSee{4A}}
\nextport{RW}{4B}{Index of transparent colour in sprite palette \ZXSee{4B}}
\nextport{RW}{4C}{Index of transparent colour in Tilemap palette \ZXSee{4C}}
\nextport{RW}{50}{Selects the 8k-bank stored in 8k-slot 0 \ZXSee{50}}
\nextport{RW}{51}{Selects the 8k-bank stored in 8k-slot 1 \ZXSee{51}}
\nextport{RW}{52}{Selects the 8k-bank stored in 8k-slot 2 \ZXSee{52}}
\nextport{RW}{53}{Selects the 8k-bank stored in 8k-slot 3 \ZXSee{53}}
\nextport{RW}{54}{Selects the 8k-bank stored in 8k-slot 4 \ZXSee{54}}
\nextport{RW}{55}{Selects the 8k-bank stored in 8k-slot 5 \ZXSee{55}}
\nextport{RW}{56}{Selects the 8k-bank stored in 8k-slot 6 \ZXSee{56}}
\nextport{RW}{57}{Selects the 8k-bank stored in 8k-slot 7 \ZXSee{57}}
\nextport{-W}{60}{Used to upload code to the Copper \ZXSee{60}}
\nextport{RW}{61}{Holds low byte of Copper control bits \ZXSee{61}}
\nextport{RW}{62}{Holds high byte of Copper control flags \ZXSee{62}}
\nextport{-W}{63}{Used to upload code to the Copper in 16-bit chunks \ZXSee{63}}
\nextport{RW}{64}{Offset numbering of raster lines in copper/interrupt/active register \ZXSee{64}}
\nextport{RW}{68}{Disable ULA, controls ULA mixing/blending, enable ULA+ \ZXSee{68}}
\nextport{RW}{69}{Layer2, ULA shadow, Timex \MemAddr{FF} port \ZXSee{69}}
\nextport{RW}{6A}{LoRes Radastan mode}
\nextport{RW}{6B}{Controls Tilemap mode \ZXSee{6B}}
\nextport{RW}{6C}{Default tile attribute for 8-bit only maps \ZXSee{6C}}
\nextport{RW}{6E}{Base address of the 40x32 or 80x32 tile map \ZXSee{6E}}
\nextport{RW}{6F}{Base address of the tiles' graphics \ZXSee{6F}}
\nextport{RW}{70}{Layer 2 resolution, palette offset \ZXSee{70}}
\nextport{RW}{71}{Sets pixel offset for drawing Layer 2 graphics on the screen \ZXSee{61}}
\nextport{-W}{75}{Same as register \PortAddr{35}~plus increments \PortAddr{34}~\ZXSee{75}}
\nextport{-W}{76}{Same as register \PortAddr{36}~plus increments \PortAddr{34}~\ZXSee{76}}
\nextport{-W}{77}{Same as register \PortAddr{37}~plus increments \PortAddr{34}~\ZXSee{77}}
\nextport{-W}{78}{Same as register \PortAddr{38}~plus increments \PortAddr{34}~\ZXSee{78}}
\nextport{-W}{79}{Same as register \PortAddr{39}~plus increments \PortAddr{34}~\ZXSee{79}}
\nextport{RW}{7F}{8-bit storage for user}
\nextport{RW}{80}{Expansion bus enable/config}
\nextport{RW}{81}{Expansion bus controls}
\end{tbbluereg}
\pagebreak
\begin{tbbluereg}
\nextport{RW}{82}{Enabling internal ports decoding bits 0-7 register}
\nextport{RW}{83}{Enabling internal ports decoding bits 8-15 register}
\nextport{RW}{84}{Enabling internal ports decoding bits 16-23 register}
\nextport{RW}{85}{Enabling internal ports decoding bits 24-31 register}
\nextport{RW}{86}{When expansion bus is enabled: internal ports decoding mask bits 0-7}
\nextport{RW}{87}{When expansion bus is enabled: internal ports decoding mask bits 8-15}
\nextport{RW}{88}{When expansion bus is enabled: internal ports decoding mask bits 16-23}
\nextport{RW}{89}{When expansion bus is enabled: internal ports decoding mask bits 24-31}
\nextport{RW}{8A}{Monitoring internal I/O or adding external keyboard}
\nextport{RW}{8C}{Enable alternate ROM or lock 48k ROM}
\nextport{RW}{8E}{Control classic Spectrum memory mapping}
\nextport{RW}{90-93}{Enables GPIO pins output}
\nextport{RW}{98-9B}{GPIO pins mapped to Next Register}
\nextport{RW}{A0}{Enable Pi peripherals: UART, Pi hats, I2C, SPI}
\nextport{RW}{A2}{Pi I2S controls}
\nextport{RW}{A3}{Pi I2S clock divide in master mode}
\nextport{RW}{A8}{ESP WiFi GPIO output}
\nextport{RW}{A9}{ESP WiFi GPIO read/write}
\nextport{R-}{B0}{Read Next keyboard compound keys separately \ZXSee{B0}}
\nextport{R-}{B1}{Read Next keyboard compound keys separately \ZXSee{B1}}
\nextport{RW}{B2}{DivMMC trap configuration}
\nextport{RW}{B4}{DivMMC trap configuration}
\nextport{RW}{C0}{Interrupt Control \ZXSee{C0}}
\nextport{RW}{C2}{NMI Return Address LSB \ZXSee{C2}}
\nextport{RW}{C3}{NMI Return Address MSB \ZXSee{C3}}
\nextport{RW}{C4}{Interrupt Enable 0 \ZXSee{C4}}
\nextport{RW}{C5}{Interrupt Enable 1 \ZXSee{C5}}
\nextport{RW}{C6}{Interrupt Enable 2 \ZXSee{C6}}
\nextport{RW}{C8}{Interrupt Status 0 \ZXSee{C8}}
\nextport{RW}{C9}{Interrupt Status 1 \ZXSee{C9}}
\nextport{RW}{CA}{Interrupt Status 2 \ZXSee{CA}}
\nextport{RW}{CC}{DMA Interrupt Enable 0 \ZXSee{CC}}
\nextport{RW}{CD}{DMA Interrupt Enable 1 \ZXSee{CD}}
\nextport{RW}{CE}{DMA Interrupt Enable 2 \ZXSee{CE}}
\nextport{-W}{FF}{Turns debug LEDs on and off on TBBlue implementations that have them}
\end{tbbluereg}
\endgroup
\pagebreak
\subsection{Accessing Registers}
\label{zx_next_ports_examples}
% note: this section results in full 2 pages (there's 1 paragraph available in first 2 sub sections); if adding substantial text make sure it still fits 2 pages! If not possible otherwise, space can be found by combining more Next registers in tables above - so that they fill full pages, and then continuing directly with this subsection, without pagebreak... Current layout is nice though - left page describes read/write to Spectrum ports, right one for Next registers...
\subsubsection{Writing to Spectrum Ports}
When writing to one of the lower 256 ports, {\tt OUT (n),A} instruction is used. For example to write the value of {\tt 43} to peripheral device mapped to port \MemAddr{15}:
\begin{tcblisting}{}
LD A, 43 ; we want to write 43
OUT (&15), A ; writes value of A to port &15
\end{tcblisting}
To write using full 16-bit address, {\tt OUT (C),r} instruction is used instead. Example of writing a byte to serial port using \PortText{133B}:
\begin{tcblisting}{}
LD A, 42 ; we want to write 42
LD BC, &133B ; we want to write to port &133B
OUT (C), A
\end{tcblisting}
The difference between the two speed-wise is tangible: first example requires only 18 t-states (7+11) while second 29 (7+10+12).
\subsubsection{Reading from Spectrum Ports}
Reading also uses the same approach as on original Spectrums - for the lower 256 ports {\tt IN A,(n)} is used. For example reading a byte from port \MemAddr{15}:
\begin{tcblisting}{}
LD A, 0 ; perhaps not strictly required, but good idea
IN A, (&15) ; read byte from port &15 to A
\end{tcblisting}
Note how the accumulator {\tt A} is cleared before accessing the port. With {\tt IN A,(n)}, the 16-bit address is composed from {\tt A} forming high byte and {\tt n} low byte.
Let's see how we can use this for reading from 16-bit ports - we have two options: we can either use {\tt IN A,(n)} or {\tt IN r,(C)}. Example of both, reading a byte from serial port:
\begin{multicols}{2}
\begin{tcblisting}{right skip=1em}
LD BC, &143B ; read &143B port
IN A, (C) ; read byte to A
\end{tcblisting}
\columnbreak
\begin{tcblisting}{}
LD A, &14 ; high byte
IN A, (&3B) ; read byte to A
\end{tcblisting}
\end{multicols}
\vspace*{-0.7em} % multicols creates additional space below, we want next text to be closer up...
Both have the same result. The difference speed-wise is 22 t-states (10+12) vs 18 (7+11). Not by a lot, but it may add up if used frequently. However, the intent of the first code is clearer as the port address is provided in full instead of being split between two instructions.
This example nicely demonstrates a common dilemma when programming: frequently we can have readable but not as optimal code, or vice versa. But I also thought this was worth pointing out to avoid possible confusion in case you will encounter different ways in someone else's code.
\subsubsection{Writing to Next registers}
% note: at the moment we don't have ports 243B and 253B declared elsewhere, so we label them here; this was cross references will lead to this place. Since this **IS** the declaration, we don't use XRefs when mentioning both ports below.
\label{\PortReference{243B}}
\label{\PortReference{253B}}
Writing values to Next/TBBlue registers occurs through \PortText{243B}~and \PortText{253B}~ports. It's composed from 2 steps: first we select the register via write to port \MemAddr{243B}, then write the value through port \MemAddr{253B}. For example writing value of {\tt 5} to Next register \MemAddr{16}:
\begin{multicols}{2}
\begin{tcblisting}{right skip=1em}
LD A, &16 ; register &16
LD BC, &243B ; port &243B
OUT (C), A
LD A, 5 ; write 5
LD BC, &253B ; to port &254B
OUT (C), A
\end{tcblisting}
\columnbreak
\begin{tcblisting}{}
LD A, &16 ; register &16
LD BC, &243B ; port &243B
OUT (C), A
LD A, 5 ; write 5
INC B ; to port &253B
OUT (C), A
\end{tcblisting}
\end{multicols}
\vspace*{-0.7em} % multicols creates additional space below, we want next text to be closer up...
Quite involving, isn't it? Speed-wise, first example requires 58 t-states ((7+10+12)$\times$2) and second 6 t-states less: 52 ((7+10+12)+(7+4+12)).
The second code relies on the fact that the only difference between two port addresses is the high byte (\MemAddr{24} vs \MemAddr{25}). So given we already assigned \MemAddr{243B} to {\tt BC}, we can simply increment {\tt B} to get \MemAddr{253B}. Again, the intent of the first example is clearer. And again, I thought it was worth pointing out in case you will encounter both approaches and wonder...
However, we can do better. Much better, in fact, using Next {\tt NEXTREG} instruction, which allows direct writes to given Next registers. So above examples could simply be changed to either:
\begin{multicols}{2}
\begin{tcblisting}{{right skip=1em}}
LD A, 5 ; write 5
NEXTREG &16, A ; to reg &16
\end{tcblisting}
\columnbreak
\begin{tcblisting}{}
NEXTREG &16, 5 ; write 5 to reg &16
\end{tcblisting}
\end{multicols}
\vspace*{-0.7em} % multicols creates additional space below, we want next text to be closer up...
The first example requires 24 t-states (7+17) while the second 20. So less than half compared to using ports. In fact, using {\tt NEXTREG} is the preferred method of writing to Next registers!
\subsubsection{Reading from Next Registers}
Reading values from Next/TBBlue registers also occurs through \MemAddr{243B} and \MemAddr{253B} ports. Similar to write, read is also composed from 2 steps: first select the register with port \MemAddr{243B}, then read the value from port \MemAddr{253B}. For example reading a byte from Next register \MemAddr{B0}:
\begin{multicols}{2}
\begin{tcblisting}{right skip=1em}
LD A, &16 ; register &16
LD BC, &243B ; port &243B
OUT (C), A ; set port
LD BC, &253B ; port &253B
IN A, (C) ; read to A
\end{tcblisting}
\columnbreak
\begin{tcblisting}{}
LD A, &16 ; register &16
LD BC, &243B ; port &243B
OUT (C), A ; set port
INC B ; port &253B
IN A, (C) ; read to A
\end{tcblisting}
\end{multicols}
\vspace*{-0.7em} % multicols creates additional space below, we want next text to be closer up...
The difference is small: 51 t-states ((7+10+12)+(10+12)) vs 45 ((7+10+12)+(4+12)).
Unfortunately, we don't have faster means of reading Next registers directly as we do for writing; there is no {\tt NEXTREG} alternative for reads.
\pagebreak