Last modified by Max on 2025/02/25 10:46

Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
4
5 = Controller concept =
6
7 The controller emulates up to 32 AZ® disk devices on a single microSD card. Each emulated disk (pseudo disk) is represented on the card by a file in terms of the FAT32 file system, so there are no questions about placing pseudo disks on a large-capacity storage device - just place the card in the card reader, connect it to the PC, copy files of the required size (and with the required content) to the card, move it to the controller, and that's it! Moreover, after working with the card on the PDP-11/DVK/BK/UKNC, you can remove it from the controller, place it back in the card reader and copy the resulting disk image files to the PC, where you can work with them by any means - for example, connect to the emulator, archive and put them somewhere for storage, send them to a conference, etc. It is also not particularly difficult to copy some material found on the Internet onto a card, move it to the controller and use this material on the PDP-11/DVK/UKNC.
8
9 == Controller registers ==
10
11 The controller has 4 registers on the QBUS
12
13 * 177220 - Command and Status Register (CSR)
14 * 177222 - Data Register (DR)
15 * 177224 - Primary Boot Register (BOOT1)
16 * 177226 - Alternate Boot Register (BOOT2)
17
18 The CSR register accepts commands in bits D0-D5 and the interrupt enable bit in bit D6, all write only, always zero is read. In bit D7, the readiness bit is read. One in it means that the previous command has been executed and the controller is ready for exchange. Zero means that the controller is busy executing the previous operation, the other registers are disabled, access to any of them will cause Trap to 4. If the execution of the previous command caused an error, bit D15 is set simultaneously with bit D7.
19 \\Writing to registers is done only in words; byte writing is not allowed.
20 \\All data exchange is conducted via DR. For commands with a single-word argument, this argument should be sent to DR, and then the command should be sent to CSR. For commands exchanging with the controller buffer, on the contrary, the command should be issued and only after it a data block of a certain length should be received or transmitted.
21
22 == Interruptions ==
23
24 Most commands are executed almost instantly - within the execution time of one or two CPU commands. But the commands for exchanging with the micro-SD card still take time. You can wait for these operations to complete either by polling the D7 CSR bit, or (for example, if you have a multitasking OS that has somewhere to utilize this time) - set the D6 CSR bit (interrupt enable) and do something else. When the operation is completed, an interrupt will occur and you can continue operations on it.
25
26 == Namespaces ==
27
28 As already mentioned, the disk device presented to the PDP-11 system is a physical file on some file system. Starting with the V17 firmware, network functionality has appeared, it allows using network drives provided by MAXIOL Landisk® technology. Accordingly, for complete unification and ensuring complete "transparency", all differences are reduced to the mount point, at the moment these are the following spaces:
29
30 * 0:/ - local files on the MicroSD card
31 * R:/ - network files in the file repository
32 * N:/ - network files in the archive [[https:~~/~~/mirrors.pdp-11.ru/>>https://mirrors.pdp-11.ru/]]
33
34 Planned network spaces (functionality will be implemented in the following firmware):
35
36 * P:/ - personal cloud, available only under one account
37 * S:/ - cloud that allows you to share your files with other members
38
39 == Buffers ==
40
41 The controller has several buffers for different purposes, all buffers have word sizes because they are transmitted through a 16-bit register.
42
43 * Main buffer - IOBUF [258]
44 * Non-volatile memory buffer - cmosmem_buffer[256]
45 * Clock buffer - output timestamp_out_buffer[14]
46 * Clock buffer - input timestamp_in_buffer [7]
47 * IP information buffer - ipdata
48 * Map size buffer - sizecard
49
50 = Main command block =
51
52 The command is sent to the CSR, to bits 5-0. It should be sent only as a word, byte writing is not allowed. The command bits are for writing only, always zero is read. The command codes are given in octal.
53
54 These commands use the main buffer for their operation (IOBUF [258]).
55
56 == 000: Controller reset ==
57
58 The command code is 000. The command stops all controller operations, if possible. Its completion should be waited for by polling. Example program:
59
60 {{code language="assembler"}}
61 ;.............................
62 MOV #AZ$CSR,R3
63 1$: CLR @R3; Send the "Reset" command
64 TSTB @R3; Check the controller's readiness
65 BPL 1$; If it's not ready, reset it again
66 ; and check again
67 TST (R3)+; Check for an error,
68 ; change the address at the same time
69 ; (will be useful later)
70 BMI ERR1
71 ;...............................
72 {{/code}}
73
74 Note on the reset command. In fact, it is instantaneous - if the controller is not busy executing an operation that cannot be interrupted, specifically - SD data exchange. While the SD data exchange is in progress, the controller does not accept any commands and the reset command can be skipped. Therefore, if the controller is busy (bit D7 is zero), the reset command is issued again. This happens quite rarely (for example, double-clicking Ctrl/C when rewriting), usually, during normal operations, the wait for writing or reading is performed in a special place and, upon completion of this operation, not a reset is performed, but completely different actions.
75
76
77 == 001: Select device ==
78
79 The controller supports up to 32 pseudo disks. The "device selection" command selects one of them for operation. Command code 001. To select a device, you should send the number of the drive you are going to work with to the data register (177222) and then send the code 001 to the CSR. The command is executed instantly, i.e. during the time the CPU sends the "device selection" code. When attempting to select an AZ disk that is not assigned an image file, an error is returned in bit D15 of the CSR register.
80
81 Пример программы:
82
83 {{code language="assembler"}}
84 ;.......................
85
86 SetUni = 001; Symbolic name of the command
87 ; "Device selection"
88
89 ; The address CSR+2=DR remained in R3 from the previous fragment
90
91 ; We assume that in R0 in bits 0-3 there is the number of the
92 ; device, the remaining bits are zeros, the procedure for ;calculating this number is not shown.
93
94 MOV R0,@R3; Let's send to DR the number of disk AZ, with
95 ; which we are going to work with
96
97 MOV #SetUni,-(R3); and send the command "Drive selection", with the correction of the address in R3, which
98 ; now points to CSR again.
99
100 TST (R3)+; Let's check for an error and again
101 ; move the address in R3 to DR
102 BMI ERR2
103
104 ;........................
105 {{/code}}
106
107
108 == 002: Set block number, low bits of block number ==
109
110 The controller provides the machine with QBUS as disks AZ0 - AZ7 file-images of the DSK type on the micro-SD card. The size of these file-images and, accordingly, pseudo-disks, can be any, up to 4G each. Addressing on these pseudo-disks is direct - the block number received via QBUS, after shifting, is used as an offset from the beginning of the corresponding file-image. In fact, this is something like LBA on a PC.
111 \\There are PDP-11 operating systems that support such disks - RSX-11, DIAMS, and some others. However, the most common OS - RT-11 - uses a WORD (16 bits) for the block number, and the code 0177777 is used in some places for special purposes and is not suitable as a disk size, so disks with a maximum number of blocks of 0177776, i.e. 65534 blocks (33553408 bytes or 32767 K bytes), can be used for RT-11. Therefore, there are two commands for setting the block number: to set the low-order bits of the block number - code 002 and to set the high-order bits of the block number - code 012. If the block number fits into 16 bits (for RT-11 - always), it is enough to use the command to set the low-order bits of the block number, the high-order bits are cleared. If the number does not fit into 16 digits, then first the lower bits must be output, and then the higher ones. If you try to immediately transmit the higher bits without first transmitting the lower ones, an error is returned. If the transmitted address goes beyond the file-image boundary, an error is also returned, no matter at what stage - either when transmitting the lower 16 bits of the block number, or when transmitting the higher ones.
112
113
114 To perform these actions, you must send the required part of the block number bits to DR and then send the command code to CSR, after which you must check for an error. The commands are instantaneous, i.e. they are executed in one QBUS access cycle.
115 \\Example of a program - 16-bit  version block number:
116
117 {{code language="assembler"}}
118 ;.......................................
119
120 SetBlk=002; Symbolic name of the command
121 ; "Set the lower 16 bits of the block number"
122
123 ; The address DR
124 ; (177222) remained in R3 from the previous fragment
125 ; We assume that the cell labeled BLCUR contains the 16-
126 ; bit disk address (the block number to be
127 ; input or output). The procedure for obtaining this number is not
128 ; shown
129
130 MOV BLCUR,@R3;We place the block number to be exchanged in DR.
131
132
133 MOV #SetBlk,-(R3); We send the command to the CSR
134 ; do not forget that the address in R3 will decrease by
135 ; 2 before sending and will remain so
136
137 TST @R3; We check for an error
138
139 BMI ERR3
140
141 ; In the 32-bit version, the same actions should be
142 ; repeat for the senior 16 bits (actually,
143 ; senior 7, the rest should be zeros, because the maximum
144 ; size of a pseudo disk is 4G) of the disk address.
145
146 ; Note that in R3 the CSR address remains, and not
147 ; DR, as in the two previous fragments. This is done
148 ; on purpose.
149
150 ;.......................................
151 {{/code}}
152
153
154 == 003: Open HFS Table of Contents ==
155
156 Sequence of actions:
157
158 • reset the controller
159 • send the command "Accept data block to buffer" to the CSR and transmit the entire line with the full path text (Full Path) to the required table of contents word by word. The line must end with a zero byte (0x00) and be no longer than 384 bytes (192 words).
160 • send the "Open table of contents" command code to the CSR
161 • wait for it to finish (the command is long)
162 • check for errors
163
164 [[Example utility - AZDIR>>url:https://forum.maxiol.com/index.php?s=&showtopic=5605&view=findpost&p=59418]]
165
166
167 Example program:
168
169 {{code language="assembler"}}
170 ;.............................
171 AZ$CSR = 177220
172 WrBuf = 016
173 OpnDir = 003
174
175 MOV #AZ$CSR,R3
176 ; The DirPtr cell contains a pointer to the beginning of the field with Full
177 ; Path. We assume that the string is terminated by three zero
178 ; bytes in order to recognize the end of the transfer of the
179 ; string word by word by zero. Indeed, if the number of
180 ; characters in the string is even, then the next two bytes of zeros
181 ; form a zero word; if it is odd, then one zero
182 ; will go away with the last character of the string, and the zero
183 ; word is formed by the second and third zero bytes,
184 ; ending the string. That is, such an end of the string,
185 ; transferred word by word, is quite reliable.
186 MOV DirPtr,R2
187
188 MOV #WrBuf,(R3)+; We issue the "Write to
189 ; buffer" command and transmit the string
190 11$: MOV (R2)+,@R3; word by word,
191 BNE 11$ ;until zero is sent,
192
193 MOV #OpnDir,-(R3); We issue the "Open
194 ; table of contents" command
195
196 12$: TSTB @R3; and wait for the controller to
197 BPL 12$; execute it,
198 TST @R3; after which we check for an error.
199 BMI Err10; Error -->
200 ;.............................
201 {{/code}}
202
203 == 004: Mount a disk ==
204
205 Sequence of actions:
206 • Reset the controller
207 • Send a line to the controller with a record similar to the lines describing the disks in the AZ.INI file
208 • Issue the "Mount disk" command
209 • Wait for it to finish (the command is long)
210 • Check for errors
211 The selected AZnn drive MUST NOT have a disk mounted. If it is mounted, the old disk should be unmounted before mounting a new one - command 014
212
213 Example program:
214
215 {{code language="assembler"}}
216 ;..................
217 AZMNT = 004
218 MDLEN = MDEND-MDTXT+2
219
220 MOV #AZ$CSR,R3
221
222 20$: CLR @R3;
223 TSTB @R3; Reset the controller
224 BPL 20$;
225
226 MOV #WrBuf,(R3)+; Send it a string
227 MOV #MDTXT,R2; with the assignment command
228 MOV #MDLEN/2,R1;
229 21$: MOV (R2)+,@R3;
230 SOB R1,21$;
231
232 MOV #AZMNT,-(R3); and pass it to
233 22$: TSTB @R3 ; execution
234 BPL 22$ ;
235
236 TST @R3; then check for an error
237 BMI Err11;
238 ;.........................
239
240 MDTXT: .ASCII "D04=0:/DISKS/SYSTEM/51SYS_DS.DSK"
241 MDEND: .BYTE 0,0
242 ;..................
243 {{/code}}
244
245 In this fragment, the 51SYS_DS.DSK image file is mounted on the AZ4 disk, located in the SYSTEM folder, which is located in the DISKS folder, which is located in the root directory of the micro-SD card.
246
247
248 == 005: Reading block into buffer ==
249
250 The controller has a built-in buffer for 256 words (512 bytes). In fact, this is part of the STM32 microcontroller's RAM, allocated in its program for this buffer. All exchange in the main command block goes through this buffer.
251 \\The AZ disk memory is represented as a set of blocks, each 512 bytes in size. Such a block is the only available unit for exchanging data with AZ disks. The blocks are numbered from zero to 65533 for the 16-bit version or up to 8388607 for the 32-bit version - this is when using AZ drives of the maximum permissible capacity. No one prevents you from using drives of a smaller capacity - the actual size of the drive is equal to the size of the file-image mounted on this drive. An error will be registered if you try to access beyond the file-image.
252 \\Command 005 - reading a block from MicroSD to the buffer. From the pseudo-disk AZn, previously selected by the command "Select device", the block whose number is transmitted by the command (commands) "Set block number" is started for reading. Long-term command.
253 \\In fact, a block from a MicroSD card is read in about 500-800 µs. During this time, the controller goes into a state that during the discussion of the project was called "I think, please do not interfere." Namely, for the entire time of its execution, all device registers are disabled, except for CSR, in which zero is read as long as the controller is busy executing this command. After the block is read, the remaining controller registers are connected to the QBUS, bit D7 (ready) is set in CSR and, if bit D6 (interrupt enable) was set in CSR, an interrupt with vector 0174 is generated.
254 \\An example without interruptions is trivial:
255
256 {{code language="assembler"}}
257 ;...................................
258
259 CmdRea=005; symbolic name of the "Read block" command
260
261 ; In R3 we have the CSR address left from the previous fragment.
262 ; We send the read command code there
263 MOV #CmdRea,@R3
264 2$: TSTB @R3 Let's check the ready bit
265 BPL 2$; Not ready -> we go to check again
266 ; once
267 TST @R3; Let's check for an error
268 BMI ERR4
269 ; Here again, unlike the fragments of pp. 3.1 and
270 ; 3.2, we have the CSR address left in R3, not DR.
271
272 ;...................................
273 {{/code}}
274
275
276 == 006: Write block from buffer to disk ==
277
278 Command code 006. The buffer contents are written to the selected pseudo-disk at the specified disk address (block number). Before writing, checks are performed (1) "was there a write to the buffer?", if not, an error is returned and (2) "is the buffer completely filled?", if not (for the last shortened block of the file), the rest of the buffer is cleared with zeros. Then the block is written to the media. The operation is lengthy, after it is started the controller, as with reading, goes into the "I think, please do not interfere" state. And just as with reading, you must wait for the end of this operation, by the same means as with reading.
279
280
281 Example of a program without interrupts:
282
283 {{code language="assembler"}}
284 ;...............................................................
285
286 CmdWri=006; symbolic name of the "Write
287 ; block" command
288
289 ; In R3 we have the DR address left over from the previous fragment.
290 ; We correct it to the CSR and send the
291 ; write command code there
292 MOV #CmdWri,-(R3)
293 5$: TSTB @R3 ; Let's check the ready bit
294 BPL 5$; Not ready -> we go and check again once
295 TST @R3; Let's check for an error
296 BMI ERR5
297
298 ;....................................................................
299 {{/code}}
300
301
302 == 007: Get disk size ==
303
304 There are two commands for obtaining the size of a pseudo-disk, i.e. the AZn file-image mounted on the selected pseudo-drive.
305 \\If the OS being used (or a program working with disks without an OS) can work with large (more than 32M) disks, you should use the command with the code 017. The sequence of actions: reset the controller (command 000), select the drive (p. 3.2) and send the code 017 to the CSR, and then, without any waiting, read from DR first the lower word, and then the higher word of the size of the selected drive (image file).
306 \\If the OS you are using cannot work with disks larger than 32M (RT-11), you should use the 007 command - get the pseudo-disk size with a limit of up to 32M. The steps are similar: reset the controller, select the disk, send the 007 code to the CSR and read one word of the pseudo-disk size from DR. If the size of the image file mounted on the selected pseudo-drive is larger than 65534 blocks, the controller returns the number 65534 instead of this "large" size. We remind you that the number 65535 is used in some places for special purposes and cannot be the disk size.
307 \\We also remind you that if the image file is not mounted on this drive, the sequence of actions will not work (command 001 select device) and the program execution will simply not reach this point. Therefore, these commands do not provide for errors.
308
309 Example of a program with "small" disks
310
311 {{code language="assembler"}}
312 ;......................................
313
314 GetSiz=007; Get the "small" disk size
315
316 ; From fragment 3.2 (disk selection) we have in R3
317 ; DR address (177222)
318
319 MOV #GetSiz,-(R3); send the command
320 TST (R3)+; return the address in R3 back to DR
321 MOV @R3,DskSiz
322 ;......................................
323 {{/code}}
324
325 == 010: Allow network operation ==
326
327 Command code 010. Having completed the sequence of actions for transferring the next portion of data, and expecting that the next request will not follow immediately, you can "utilize" the processor time of the STM32 microcontroller, which is the basis of AZ - occupy it with servicing the network. In the same RT-11, this can be done before exiting the AZ driver, before the .DRFIN macro command, which completes the execution of the input-output request.
328 \\Indeed, the I/O operation is completed, the CPU program in the system will prepare a new portion of data for output, or figure out (based on the previously read data) where it should read something else, or generally think about something of its own. smile.gif In other words, after the I/O request is completed, there is a fairly high probability that there will be a pause in working with the AZ disks. So, the time of this pause can be given to servicing the network. To do this, before executing the .DRFIN macro in RT-11 or its analogue in other OS, you should send code 110 (enable network plus enable interrupts) to the CSR.
329
330
331 In this case, the interrupt will not occur, it is activated only upon completion of "long" operations that transfer the controller to the "Thinking, please do not interfere" state, and the interrupt enable trigger set to "1" also enables network operation if it is activated. When the next input-output operation is started, the actions in paragraph 3.1 (controller reset) will also reset this trigger, after which the network service program, having detected the reset of this trigger, will stop (suspend) its work and return control to the main disk service program AZ. The maximum that can be noticed from the CPU side is a small (10-20 µs) delay in executing the reset command, but this is a very reasonable price for network capabilities.
332
333 == 011: Get AZn drive assignment table ==
334
335 Command code 011. Upon receiving this command, the controller switches from the block buffer to its internal assignment table (32 lines of 140 bytes each)*. Before issuing this command, the controller should be reset. After issuing this command, command 015 (read buffer) should be issued, but in this case it will not be the buffer that is read, but the same table, sequentially, word by word.
336 \\* starting with v17, the file name length is no longer 130 bytes, but 386 bytes (the last word is zero, to end the line)
337
338 [[AZSMNT utility example>>url:https://forum.maxiol.com/index.php?s=&showtopic=5605&view=findpost&p=59420]]
339
340
341 Example program:
342
343 {{code language="assembler"}}
344 ;...................................
345 AZ$CSR = 177220; Controller CSR
346 RdBuf = 012; Command "Read from controller memory"
347 RdTbl = 011; Command "Read assignment table"
348 TblSiz = 1120.; Table length in bytes (decimal)
349
350 ; We assume that R2 contains the address of the first word of the
351 ; memory area for the assignment table. We do not show the procedure for obtaining this address.
352
353 MOV #AZ$CSR,R3; Preparing the controller CSR
354 10$: CLR @R3;
355 TSTB @R3; Reset the controller
356 BPL 10$;
357
358 MOV #RdTbl,@R3;Command "Transfer
359 ; table"
360
361 MOV #RdBuf,(R3+); Command "Read from
362 ; controller memory. At the same time, move the address in R3
363 ; to the DR of the controller (177222).
364
365 MOV #TblSiz/2,R1; Prepare the word counter
366
367 11$: MOV @R3,(R2)+; Send the current word
368 SOB R1,11$; and repeat 560 times
369 ;...................................
370 {{/code}}
371
372 == 012: Setting the block number, block number high bits ==
373
374 The controller provides the machine with MPI as disks AZ0 - AZ7 file-images of the DSK type on the micro-SD card. The size of these file-images and, accordingly, pseudo-disks, can be any, up to 4G each. Addressing on these pseudo-disks is direct - the block number obtained by QBUS, after shifting, is used as an offset from the beginning of the corresponding file-image. In fact, this is something like LBA on a PC.
375
376
377 There are PDP-11 operating systems that support such disks - RSX-11, DIAMS, and some others. However, the most common OS - RT-11 - uses a WORD (16 bits) for the block number, and the code 0177777 is used in some places for special purposes and is not suitable as a disk size, so disks with a maximum number of blocks of 0177776, i.e. 65534 blocks (33553408 bytes or 32767 K bytes), can be used for RT-11. Therefore, there are two commands for setting the block number: to set the low-order bits of the block number - code 002 and to set the high-order bits of the block number - code 012. If the block number fits into 16 bits (for RT-11 - always), it is enough to use the command to set the low-order bits of the block number, the high-order bits are cleared. If the number does not fit into 16 digits, then first the lower bits must be output, and then the higher ones. If you try to immediately transmit the higher bits without first transmitting the lower ones, an error is returned. If the transmitted address goes beyond the file-image boundary, an error is also returned, no matter at what stage - either when transmitting the lower 16 bits of the block number, or when transmitting the higher ones.
378 \\To perform these actions, you should send the required part of the block number bits to DR and then send the command code to CSR, after which you should check for an error. The commands are instantaneous, i.e. they are executed in one cycle of access via MPI.
379
380 == 013: Read HFS TOC entry ==
381
382 Command code 013, the command reads the TOC record into the internal memory area and switches the pointer to it for data transfer via DR. The TOC must be open before this.
383
384 The procedure is as follows:
385 • Reset the controller.
386 • Issue the command "Read the table of contents entry" to the CSR and wait for it to finish.
387 • Issue the command "Read from controller memory" to the CSR
388 • Read 11 words of the table of contents entry from DR
389 \\The table of contents entry has the format:
390
391 (% style="width:686px" %)
392 |=(% style="width: 136px;" %)Offset (octal)|=(% style="width: 305px;" %)Name|=(% style="width: 242px;" %)Value
393 |(% style="width:136px" %)0|(% style="width:305px" %)fSize|(% style="width:242px" %)File size in bytes, low word
394 |(% style="width:136px" %)2|(% style="width:305px" %)fSize|(% style="width:242px" %)File size in bytes, high word
395 |(% style="width:136px" %)4|(% style="width:305px" %)fDate|(% style="width:242px" %)Date in MS-DOS format
396 |(% style="width:136px" %)6|(% style="width:305px" %)fTime|(% style="width:242px" %)Time in MS-DOS format
397 |(% style="width:136px" %)10|(% style="width:305px" %)fAttr|(% style="width:242px" %)Attributes 1 byte
398 |(% style="width:136px" %)10|(% style="width:305px" %)fName|(% style="width:242px" %)NAME.FILE TYPE, 8+1+3+1 = 13 bytes
399
400
401 The offsets are specified in octal. The formula in the fName line means that there must first be a name, maximum of eight characters, then a period, then a type, up to three characters, and a terminating zero byte 0x00. If the type is not specified, the period is also not needed.
402 \\File attributes in fAttr byte (octal):
403 \\001 - Read Only
404 002 - Hidden
405 004 - System
406 020 - Directory
407 040 - Archive
408 \\Example program
409
410 {{code language="assembler"}}
411 ;......................................
412 RdDir = 013; command code "Read table of contents entry"
413 RdBuf = 015
414
415 MOV #AZ$CSR,R3
416
417 15$: CLR @R3;
418 TSTB @R3; Reset the controller
419 BPL 15$;
420
421 MOV #RdDir,@R3; Ask the controller
422 16$: TSTB @R3; to read into its memory
423 BPL 16$; table of contents entry
424
425 MOV @RdBuf,(R3)+;
426 MOV DIRREC,R2; And transfer it to itself in
427 MOV #11.,R1; memory area, pointer
428 17$: MOV @R3,(R2)+; to which lies in cell
429 SOB R1,17$; DIRREC.
430
431 ;......................................
432 {{/code}}
433
434
435 == 014: Unmount disk ==
436
437 Command code 014, to unmount the disk, you should reset the controller, send the AZ drive number to the controller DR, which should be unmounted, and send the 014 code to the controller CSR, then wait for the operation to complete (it takes a long time) and check for an error. An error is issued if the drive has not been mounted.
438 [[AZUMNT utility example>>url:https://forum.maxiol.com/index.php?showtopic=5605&st=0&p=59418&#entry59418]]
439
440
441 == 015: Start transferring the read block ==
442
443 The command code is 015. Having received this command, the controller is configured to output word by word the contents of the same built-in buffer for 256 words, which will be output sequentially through the DR register. No waiting is required, we simply send a word from DR to sequential memory cells 256 times, and that's it. If less than 256 words are needed (the last shortened block of the file), then the remainder can simply be discarded without reading, resetting the controller at the beginning of the next operation will also reset this remainder.
444 \\Example program:
445
446 {{code language="assembler"}}
447 ;..................................
448 RdBuf=015; symbolic name of the command
449
450 ; In R3 from the previous fragment there is the address of the CSR
451 ; (177220)
452
453 ; We assume that in R2 we have the address of the first word
454 ; of memory, where the read block should be placed.
455 ; The program for obtaining this address is not given.
456
457 MOV #400,R1; Prepare the word counter
458 ; 0400 oct = 256 dec
459
460 MOV #RdBuf,(R3)+; and send the command
461 ; RdBuf to the CSR. The address in R3 will point to DR (177222).
462
463 3$: MOV @R3,(R2)+we will send the next word to
464 ; memory
465 SOB R1,3$; and repeat this 256 (0400)
466 ; times
467 ;..................................
468 {{/code}}
469
470 That's it, reading is complete.
471
472 To write the opposite way, you first need to transfer the entire data block from the CPU memory to the controller and then issue the command "Write the contents of the buffer to disk"
473
474
475 == 016: Receive data block into buffer ==
476
477 Command code 016. The command sets the controller to receive a block of data and place it in the buffer. The next 256 write cycles to DR will place the data transferred via the QBUS in the buffer.
478 \\Example program:
479
480 {{code language="assembler"}}
481 ;..................................
482
483 WrBuf=016; Symbolic name of the command
484
485 ; Before writing, you need to perform the same actions as in
486 ; pp. 3.1.-3.3. Usually, this is the same program,
487 ; just after point 3.3. a check is performed "What
488 ; is required: reading or writing?" and a branch is made to the
489 ; reading or writing program.
490
491 ; After the fragment in point 3.3., the CSR address
492 ; (177220) remains in R3. We will assume that R2 contains the address in the CPU
493 ; memory where the block to be written is located.
494 ; The program for obtaining this address is not shown.
495
496 MOV #400,R1; Preparing the counter
497
498 MOV #WrBuf,(R3)+; Let's forward the command to the CSR and
499 ; switch the address in R3 to
500 ; DR
501
502 4$: MOV (R2)+,@R3; Let's forward the next word
503 ; data
504 SOB R1,4$; and repeat this 256 times
505 ;..................................
506 {{/code}}
507
508 == 017: Get ramdisk size, large ==
509
510 There are two commands to get the size of a pseudo-disk, i.e. the AZn file-image mounted on the selected pseudo-drive.
511 \\If the OS being used (or a program working with disks without an OS) can work with large (more than 32M) disks, you should use the command with the code 017. The sequence of actions: reset the controller (p. 3.1), select the drive (p. 3.2) and send the code 017 to the CSR, and then, without any waiting, read from DR first the lower word, and then the higher word of the size of the selected drive (image file).
512 \\If the OS you are using cannot work with disks larger than 32M (RT-11), you should use the 007 command - get the pseudo-disk size with a limit of up to 32M. The steps are similar: reset the controller, select the disk, send the 007 code to the CSR and read one word of the pseudo-disk size from DR. If the size of the image file mounted on the selected pseudo-drive is larger than 65534 blocks, the controller returns the number 65534 instead of this "large" size. We remind you that the number 65535 is used in some places for special purposes and cannot be the disk size.
513 \\We also remind you that if the image file is not mounted on this drive, the sequence of actions will not work (command 001 select device) and the program execution will simply not reach this point. Therefore, these commands do not provide for errors.
514 \\Example of a program with large disks
515
516 {{code language="assembler"}}
517 ;......................................
518
519 GetBig=017; Get the "big" disk size
520
521 ; From fragment 3.2 (disk selection) we have in R3
522 ; DR address (177222)
523
524 MOV #GetBig,-(R3); send the command
525 TST (R3)+; return the address in R3 back to DR
526 MOV @R3,BigSiz
527 MOV @R3,BigSiz+2
528 ;......................................
529 {{/code}}
530
531
532 == 020: Get extended diagnostic code ==
533
534 Command code 020, after resetting the controller, you should issue this command in the CSR and then read two words of extended diagnostics from DR. The command is instant, no waiting is required.
535
536
537 == 027: Get firmware version AZ STM32 ==
538
539 Command code 027, returns 2 words
540 \\first word - 06404 = high byte 13. this is the firmware version, low byte 4. this is the hardware version - i.e. AZБК in this case second word - 037 = this is the maximum mountable disk - 31.
541
542
543 {{code language="assembler"}}
544 ;-------------------------------------------------------------
545 ; getting STM32 firmware version - result in R1 R1=0 error
546 GTSTMV: MOV #AZ$CSR,R1
547 1$: CLR (R1) ; Send "Reset" command
548 TSTB (R1) ;Check controller readinessконтроллера
549 BPL 1$ ; If not ready, reset again
550 mov #27,(R1)
551 TST (R1)+ ; Check for error
552 BMI 2$
553 mov (R1),R1
554 return
555 2$: CLR R1
556 return
557 ;-------------------------------------------------------------
558 {{/code}}
559
560
561 == 030: No operation ==
562
563 The main purpose of this command is to set the interrupt enable bit from the controller. The command transfers the interrupt enable bit, which is in the same word with it, but is not part of it (remember, the command is located in bits D0 - D5, and the interrupt enable bit is D6), to the corresponding trigger of the controller and does not affect the processes in the controller in any other way. Control of this trigger works even in the "Thinking, please do not interfere" state, and this is the main feature of the "no operation" command.
564 \\The command has the code 0030. Sending the code 0130 to the CSR will enable interrupts from the controller, sending the code 0030 will disable them. An example is not given due to its triviality.
565
566
567 = Command block for working with non-volatile memory =
568
569 The interface provides any AZ controller with access to 255 words of non-volatile memory, all commands set the ready bit upon completion. This allows you to save user settings in non-volatile memory, for example, this is used in AZBK ??- there are saved settings for more comfortable operation of the controller.
570
571 All commands in this block use a non-volatile memory buffer for their operation.
572
573 == 021: Read non-volatile memory block into buffer ==
574
575 (% class="wikigeneratedid" %)
576 Command code 021, this command causes a block of non-volatile memory to be read into the non-volatile memory buffer.
577
578
579 == 022: Transfer the read block of non-volatile memory from the buffer to the bus ==
580
581 (% class="wikigeneratedid" %)
582 Command code 022, this command ensures that the non-volatile memory buffer is transferred to the DR register for reading.
583
584 (% class="wikigeneratedid" %)
585 Example program
586
587 {{code language="assembler"}}
588 AZ$CSR = 177220; command and status register (CSR)
589 AZ$DR = 177222; data register (DR)
590
591
592 ; trap 50 - reset AZ
593 ; результат в R1 =0 ok
594 AZreset: MOV #AZ$CSR,R1
595 1$: CLR (R1); Send the "Reset" command
596 TSTB (R1); Check the controller readiness
597 BPL 1$; If not ready, reset again
598 ; once and check again
599 TST (R1); Check for an error,
600 BMI 0ERR$
601 CLR R1
602 return
603 0ERR$: CLR R1
604 COM R1
605 return
606
607
608 ; trap 54 - reading non-volatile memory of block 1 EEPROM to the buffer from the address ADREEPROMMEM
609 ; result R3 - address, if R3=0 error
610 ; read status in R1 0 - ok
611 ; 1 - size does not match saved
612 ; 2 - version error
613 ; 3 - checksum error
614 ReadEEPROM: push R2
615 call AZreset; reset
616 tst R1
617 bne 0ERR$
618 ; теперь читаем
619 MOV #AZ$CSR,R1
620 mov #21,(R1); read block 1 of non-volatile memory into buffer
621 0$: TSTB (R1); check execution result
622 BPL 0$; wait
623 mov #22,(R1); send read block of non-volatile memory from buffer to bus
624 1$: TSTB (R1); check execution result
625 BPL 1$; wait
626 TST (R1)+; increment
627 mov #ADREEPROMMEM,R3
628 mov #256.,R2; read 256. words; first word is reading result
629 2$: mov (R1),(R3)+; read block of words into memory
630 sob R2,2$
631 mov #ADREEPROMMEM,R3; successful
632 mov (R3),R1
633 br 0END$
634 0ERR$: CLR R3
635 0END$: pop R2
636 return
637 {{/code}}
638
639 obviously, after reading the memory, it is necessary to check the result code in the first word - see the decoding of error codes
640 \\Examples of returned data for commands
641 \\sequentially issuing the command 021 and then 022 will allow reading 256 words from non-volatile memory
642 Attention! The first word will be the reading success status
643
644 * 0 - ok
645 * 1 - size does not match saved
646 * 2 - version error
647 * 3 - checksum error
648
649 == 023: Receive data from the bus into the buffer for subsequent writing into the buffer ==
650
651 Command code 023, this command allows you to fill the non-volatile memory buffer
652
653 == 024: Write from buffer to non-volatile memory block ==
654
655 Command code 024, this command causes a non-volatile memory block to be written from the non-volatile memory buffer.
656
657 Example program
658
659 {{code language="assembler"}}
660 AZ$CSR = 177220; Command and Status Register (CSR)
661 AZ$DR = 177222; Data Register (DR)
662
663
664 ; trap 50 - reset AZ
665 ; результат в R1 =0 ok
666 AZreset: MOV #AZ$CSR,R1
667 1$: CLR (R1); Send the "Reset" command
668 TSTB (R1); Check the controller readiness
669 BPL 1$; If not ready, reset again
670 ; once and check again
671 TST (R1); Check for an error,
672 BMI 0ERR$
673 CLR R1
674 return
675 0ERR$: CLR R1
676 COM R1
677 return
678
679 ; trap 55 - write non-volatile memory from the buffer at address ADREEPROMMEM в блок 1 EEPROM
680 WriteEEPROM: push R1
681 push R2
682 push R3
683 call AZreset; reset
684 tst R1
685 bne 0ERR$
686
687 MOV #AZ$CSR,R1
688 mov #23,(R1);command that we will write data to the buffer
689 0$: TSTB (R1); check the result of executio
690 BPL 0$; wait
691 TST (R1)+; increment
692 mov #ADREEPROMMEM+2,R3
693 mov #255.,R2; write 255. words; skip the first word - the result of reading
694 1$: mov (R3)+,(R1); send to the controller
695 sob R2,1$
696 tst -(R1); decrement
697 mov #24,(R1); write from the buffer to block 1 of non-volatile memory
698 2$: TSTB (R1); check the result of execution
699 BPL 2$; we are waiting
700 br 0END$
701 0ERR$: CLR R3
702 0END$: pop R3
703 pop R2
704 pop R1
705 return
706 {{/code}}
707
708 **Please note** that when recording, the buffer immediately comes with the data, i.e. there is no first word with the statu
709
710
711
712 = Block of commands for working with RTC and NTP =
713
714 The AZ® controller has 2 sources of date-time, the first is the RTC built into the STM32, the second is the clock in the TCP/IP stack. The RTC clock works autonomously with a 2032 battery installed. The clock in the TCP/IP stack is set based on data from the NTP server.
715
716
717 == Buffer format timestamp (readable) ==
718
719 The controller API immediately prepares time in several formats, so that it can be conveniently used on the PDP-11 side
720
721 {{info}}
722 datetime buffer format octal offset - those words datetime buffer format
723 \\[0]=rtc_rt11date();
724 [2]=rt11 time 50Hz big word;
725 [4]=rt11 time 50Hz little word;
726 [6]=rt11 time 60Hz big word;
727 [10]=rt11 time 60Hz little word;
728 [12]=rtc_fat_date();
729 [14]=rtc_fat_time();
730 [16]=year+2000;
731 [20]=month;
732 [22]=day;
733 [24]=wday;
734 [26]=hour;
735 [30]=min;
736 [32]=sec;
737 {{/info}}
738
739
740 == SimpleIN buffer format (when writing) ==
741
742 the format is simplified as much as possible, for work with PDP-11
743
744 {{info}}
745 offset in octal - those words
746
747 [0]=year, the lower two digits are 22 and not 2022(!)
748 [2]=month; month
749 [4]=day; day
750 [6]=wday; day of the week =0 not set, 1 - Monday 2 - Tuesday etc.
751 [10]=hour; hour
752 [12]=min; minute
753 [14]=sec; second
754 {{/info}}
755
756
757 == 031: Get time from RTC to timestamp buffer ==
758
759 Command code 031, this command uses RTC clock as a source of filling the timestamp buffer
760
761 Example program:
762
763 {{code language="assembler"}}
764 ; trap 61 - reading clock data from autonomous RTC clock
765 ; R3 - buffer address where to read
766 ; result in R3 address if successful. R3=0 if error
767 GetDateFromRTC: push R0
768 push R1
769 push R2
770 call AZreset; reset
771 tst R1
772 bne G60ERR
773 MOV #AZ$CSR,R1
774 mov #31,(R1)
775 br G60; let's go there because further code is the same
776 {{/code}}
777
778 == 032: Get time from timestamp buffer ==
779
780 Command code 032, this command sends the contents of the timestamp buffer to the bus
781
782 {{code language="assembler"}}
783 ; working with clock
784 ; trap 60 - reading clock data from TCP/IP stack
785 ; R3 - buffer address where to read
786 ; result in R3 address if successful. R3=0 if error
787 GetDateFromLAN: push R0
788 push R1
789 push R2
790 call AZreset; reset
791 tst R1
792 bne G60ERR
793 MOV #AZ$CSR,R1
794 mov #42,(R1)
795 G60: TSTB (R1); check execution result
796 BPL G60; wait
797 mov #32,(R1)
798 1$: TSTB (R1); check execution result
799 BPL 1$; ждем
800 TST (R1)+; increment
801 mov R3,R0; remember R3 address
802 mov #10.,R2; read 10 words
803 2$: mov (R1),(R3)+; read block of words into memory
804 sob R2,2$
805 mov R0,R3; successful, return address to R3
806 br 0END$
807 G60ERR: CLR R3
808 0END$: pop R2
809 pop R1
810 pop R0
811 return
812 {{/code}}
813
814 It is worth checking the correctness of the received time:
815
816 {{code language="assembler"}}
817 ; trap 63 - check time correctness
818 ; R3 - buffer address, result in R3, if buffer address then OK, =0 error
819 CheckDateTime: Cmp 6(r3),#2021.
820 Blos 1err
821 Cmp 6(r3),#2100.
822 Bhi 1err
823 0ok$: return
824 1err$: clr R3
825 return
826 {{/code}}
827
828 == 033: Write time-date to SimpleIN buffer ==
829
830 Command code 033, this command receives data from the bus into the SimpleIN buffer
831
832 The operation of this command is similar to the operation of commands 023 and 016.
833
834 == 034: Set RTC based on buffer data ==
835
836 Command code 034, this command sets the RTC based on the data in the SimpleIN buffer
837
838 This command executes quickly, but to avoid problems, a wait loop is recommended.
839
840 == 035: Stimulate time request from NTP server, set based on response ==
841
842 Command code 035, this command sends a request to the NTP server (set in the AZ.INI file or received from DHCP) and sets the clock in the TCP/IP stack.
843
844 Example program: sending a request to set the time from an NTP server
845
846 {{code language="assembler"}}
847 ; trap 62 - sending a request to set the time from the NTP server
848 GetDateNTPtoNET:push R1
849 call AZreset; reset
850 tst R1
851 bne 0ERR$
852 MOV #AZ$CSR,R1
853 mov #35,(R1)
854 0$: TSTB (R1); check the result of execution
855 BPL 0$; wait
856 0ERR$: pop R1
857 return
858 {{/code}}
859
860 The command execution takes 1-2 seconds on average. This command requires the TCP/IP stack to work, so waiting cycles are needed when the stack is enabled.
861
862 An example of a polling cycle to get time from the network
863
864 {{code language="assembler"}}
865 ; date-time
866 mov #S_DateTime_0,R3; "Lan Date:"
867 trap 10
868 mov #20,R4; number of wait cycles
869 $datry: trap 62; sent a request to the NTP server
870 mov #110,@#AZ$CSR; enable the network
871 trap 47; waiting
872 trap 47; waiting
873 mov #ADRTMPSTR,R3
874 trap 60; read the date-time into the buffer
875 trap 63; checked the date-time
876 tst R3
877 bne $ok
878 $sob: sob R4,$datry
879 mov #S_DateTime_2,R3; print error
880 trap 7
881 br $go
882
883 $ok: mov #ADRTMPSTR,R3
884 trap 24; print date
885 trap 25; time
886 $go: mov #110,@#AZ$CSR; let's turn on the network
887 {{/code}}
888
889 Here we explicitly send a request to the NTP server, then turn on the network and wait for the result, periodically polling and checking the correctness of the result.
890
891 == 036: Setting RTC based on TCP/IP stack clock ==
892
893 Command code 036, this command sets the RTC based on the clock in the TCP/IP stack. You must first set the clock in TCP/IP - command 036.
894
895 Example program:
896
897 {{code language="assembler"}}
898 ; trap 64 - set RTC time based on stack time
899 ; R1 - result R1=0 - OK
900 SetDateNETtoRTC:call AZreset; reset
901 tst R1
902 bne 0ERR$
903 MOV #AZ$CSR,R1
904 mov #36,(R1)
905 0$: TSTB (R1); check execution result
906 BPL 0$; wait
907 clr R1
908 0ERR$: return
909 {{/code}}
910
911 == 042: Get time from TCP/IP stack clock into timestamp buffer ==
912
913 Command code 042, this command uses the TCP/IP stack clock as a source for filling the timestamp buffer.
914
915 Example program:
916
917 {{code language="assembler"}}
918 ; working with clock
919 ; trap 60 - reading clock data from TCP/IP stack
920 ; R3 - buffer address where to read
921 ; result in R3 address if successful. R3=0 if error
922 GetDateFromLAN: push R0
923 push R1
924 push R2
925 call AZreset; reset
926 tst R1
927 bne G60ERR
928 MOV #AZ$CSR,R1
929 mov #42,(R1)
930 G60: TSTB (R1); check execution result
931 BPL G60; wait
932 mov #32,(R1)
933 1$: TSTB (R1); check execution result
934 BPL 1$; wait
935 TST (R1)+; increment
936 mov R3,R0; remember R3 address
937 mov #10.,R2; читаем 10 слов
938 2$: mov (R1),(R3)+; read block of words into memory
939 sob R2,2$
940 mov R0,R3; successful, return address to R3
941 br 0END$
942 G60ERR: CLR R3
943 0END$: pop R2
944 pop R1
945 pop R0
946 return
947 {{/code}}
948
949 All commands set the ready bit upon completion.
950
951
952 = **[[AZБК®>>doc:Контроллеры AZБК® для компьютеров БК-0010 БК-0010\.01 БК-0011М.WebHome]] **specific commands =
953
954 These commands are intended for operation of the AZБК® controller, developed for the BK series of computers - BK-0010/BK-0010.01/BK-0011M.
955
956 Other AZ® controllers ignore these commands.
957
958 == 037: Restart of the** [[AZБК®>>doc:Контроллеры AZБК® для компьютеров БК-0010 БК-0010\.01 БК-0011М.WebHome]] **controller and the entire computer ==
959
960 Command code 037, this command restarts the AZ® microcontroller, which also causes a restart of the BK-0010/BK-0010.01/BK-0011M itself
961
962 Example program
963
964 {{code language="assembler"}}
965 AZ$CSR = 177220; command and status register (CSR)
966 AZ$DR = 177222; data register (DR)
967
968
969 ; trap 57 - full restart
970 AZcouldReboot: call AZreset; reset AZ so it is ready to receive
971 mov #037,@#AZ$CSR
972 return
973 {{/code}}
974
975 == 044: Saving a screenshot to a file ==
976
977 Command code 044, this command is designed to take a memory image of the specified size (or determined automatically based on saved parameters) technically, the command can serve as a debugging tool because it is capable of taking a memory image the general limitation on taking a memory image is 2MB per image
978 \\service memory page 76(8) is used as parameters
979
980 Structure of filling information about a screenshot
981
982 {{code language="c"}}
983 // screenshot header structure
984 typedef __packed struct screen_header
985 {
986 unsigned short int tag; // must be equal to 0240
987
988 unsigned int begin_adress; // start address in words - forward task in physical addresses
989 unsigned int length; // length in words - forward task in physical addresses
990
991 unsigned short int begin_page; // start page - number - forward task in page numbers
992 unsigned short int len_pages; // number of pages - forward task in page numbers
993
994 unsigned short int R177300; //
995 unsigned short int R177302; //
996 unsigned short int R177304; //
997 unsigned short int R177306; //
998 unsigned short int R177310; //
999 unsigned short int R177312; //
1000 unsigned short int R177314; //
1001 unsigned short int R177316; //
1002 unsigned short int R177320; //
1003 unsigned short int R177322; //
1004 unsigned short int R177324; //
1005 unsigned short int R177326; //
1006 unsigned short int R177330; //
1007 unsigned short int R177332; //
1008 unsigned short int R177334; //
1009 unsigned short int R177336; //
1010 unsigned short int R177340; // - Window activation control register - window masks
1011 unsigned short int R177342; // - Control register r/o per window
1012 unsigned short int R177344; // - Shadow window control register - window masks
1013 unsigned short int R177346; // - Mapper control register
1014 unsigned short int R177350; // - copy by record register 177130 in memory management write mode in SMK
1015 unsigned short int R177352; // - copy by record register 177716 in memory management write mode in BK11M
1016
1017 unsigned short int R177230; // - control register
1018 unsigned short int R177232; // - display start page number register - upper page (layer 0)
1019 unsigned short int R177240; // - display start page number register - upper page (layer 1)
1020 unsigned short int R177242; // - display start page number register - upper page (layer 2)
1021 unsigned short int R177244; // - vertical scroll register layer 2
1022 unsigned short int R177246; // - vertical scroll register layer 1
1023 unsigned short int R177250; // - vertical scroll register layer 0
1024 unsigned short int R177252; // - horizontal scroll register layer 0
1025 unsigned short int R177254; // - horizontal scroll register layer 1
1026 unsigned short int R177256; // - horizontal scroll register layer 2
1027
1028 unsigned short int paldata[338]; //
1029 } screen_header_t;
1030 {{/code}}
1031
1032 Example code for filling a memory page
1033
1034 {{code language="assembler"}}
1035 ;--------------------------------------------------
1036 ; 76th page map - we prepare data for the screenshot command there
1037 SCR_PAGE = 130000 ; we temporarily attach the 76th page to the 77th - that is, into the 130000 window
1038 SCR_TAG = SCR_PAGE+0 ; here is the input - 240 - 1 word
1039 SCR_ADDR_CONF = SCR_TAG+2 ; here is the command with addresses - address+length 24 bits - 4 words
1040 SCR_PAGE_CONF = SCR_ADDR_CONF+8. ; here is the command with pages - the starting page and the number of pages - 2 words
1041 SCR_MEM_CONF = SCR_PAGE_CONF+4. ; here is the memory configuration from the registers - 22 words
1042 SCR_VGA_CONF = SCR_MEM_CONF+44. ; here video controller configuration - 10 words
1043 SCR_PAL = SCR_VGA_CONF+20. ; here 338. values (words) of palette 338 words
1044 ;--------------------------------------------------
1045 ; trap 41 - preparation of default information for screenshot functionality
1046 PrepSRC: jsr R5, PUSHA ; batch saving of registers
1047 mov @#177326,-(SP) ; save page 130k which was before the call
1048 mov #76,@#177326 ; hook 76th page into window
1049
1050 mov #100377,R3 ; constant-filler
1051 mov #SCR_PAGE,R4
1052 mov #2047.,R2
1053 4$: mov R3,(R4)+
1054 sob R2,4$
1055
1056 mov #240,@#SCR_TAG ; put the tag
1057
1058 ; clean the address section - default is automatic address detection
1059 clr R3
1060 mov #SCR_ADDR_CONF,R4
1061 mov #10,R2
1062 2$: mov R3,(R4)+
1063 sob R2,2$
1064
1065 ; memory configuration - default
1066 mov #SCR_MEM_CONF,R4
1067 mov #30,(R4)+ ;177300
1068 mov #31,(R4)+ ;177302
1069 mov #32,(R4)+ ;177304
1070 mov #33,(R4)+ ;177306
1071 mov #04,(R4)+ ;177310
1072 mov #05,(R4)+ ;177312
1073 mov #06,(R4)+ ;177314
1074 mov #07,(R4)+ ;177316
1075 mov #20,(R4)+ ;177320
1076 mov #21,(R4)+ ;177322
1077 mov #22,(R4)+ ;177324
1078 mov #23,(R4)+ ;177326
1079 mov #120,(R4)+ ;177330
1080 mov #121,(R4)+ ;177332
1081 mov #110,(R4)+ ;177334
1082 mov #100,(R4)+ ;177336
1083
1084 mov #170000,(R4)+ ;177340
1085 mov R3,(R4)+ ;177342
1086 mov #7777,(R4)+ ;177344
1087 mov #40404,(R4)+ ;177346
1088 mov R3,(R4)+ ;177350
1089 mov #16000,(R4)+ ;177352
1090
1091 ;Video controller configuration - default
1092 ; 177230-177256
1093 mov #SCR_VGA_CONF,R4
1094
1095 mov #12201,(R4)+ ;177230
1096 mov #4,(R4)+ ;177232
1097 mov R3,(R4)+ ;177240
1098 mov R3,(R4)+ ;177242
1099 mov R3,(R4)+ ;177244
1100 mov R3,(R4)+ ;177246
1101 mov R3,(R4)+ ;177250
1102 mov R3,(R4)+ ;177252
1103 mov R3,(R4)+ ;177254
1104 mov R3,(R4)+ ;177256
1105
1106 ; download the palette - take the default one from this ROM
1107 mov #SCR_PAL,R4
1108 mov #PalData,R2
1109 mov #338.,R3
1110 1$: mov (R2)+,(R4)+
1111 sob R3,1$
1112
1113 mov (SP)+,@#177326; return the page from which the call was made
1114 return
1115 {{/code}}
1116
1117 There are three options for specifying memory areas.
1118
1119 1. specify the address and length 24-bit - see format, if they are not there - the system looks further
1120 1. specify the page number and page quantity, if they are not there
1121 1. the system looks further - that is, it makes a screenshot based on the data about registers 177230, etc.
1122
1123 The screenshot is saved in the format
1124 - page 76 - its first kilobyte
1125 - the memory image itself (if the mode is layered - then all three layers)
1126
1127
1128 Before calling the command, you can load the file name for saving the screenshot [in the cmosmem buffer], but if it is missing (there will be no name in the buffer - a line ending with 0), the system will generate its own name based on the following rule: default path for saving screenshots
1129 0:/SCREENS/
1130 name format - DDHHMISS.SCR
1131 where DD is two digits of the day of the month, HH is the hour, MI is the minute, SS is the second
1132 \\If an error occurs during the command execution, the name will be "ERROR *"
1133 for example
1134 "ERROR f_open 6"
1135
1136
1137 Example program
1138
1139 {{code language="assembler"}}
1140 ; update the information in the screenshot header
1141 ;--------------------------------------------------
1142 ; 76th page map - we prepare data for the screenshot command there
1143 SCR_PAGE = 130000 ; we temporarily attach the 76th page to the 77th - that is, into the 130000 window
1144 SCR_TAG = SCR_PAGE+0 ; here is the input - 240 - 1 word
1145 SCR_ADDR_CONF = SCR_TAG+2 ; here is the command with addresses - address+length 24 bits - 4 words
1146 SCR_PAGE_CONF = SCR_ADDR_CONF+8. ; here is the command with pages - the starting page and the number of pages - 2 words
1147 SCR_MEM_CONF = SCR_PAGE_CONF+4. ; here is the memory configuration from the registers - 22 words
1148 SCR_VGA_CONF = SCR_MEM_CONF+44. ; here video controller configuration - 10 words
1149 SCR_PAL = SCR_VGA_CONF+20. ; here 338. values (words) of palette 338 words
1150 ;--------------------------------------------------
1151 mov @#177326,R5 ; save page 130k which was before the call
1152 mov #76,@#177336 ; hook the 76th page into the window
1153
1154 ;video controller configuration
1155 ; 177230-177256
1156 mov #SVGAC,R4
1157
1158 mov @#177230,(R4)+;177230 - control register
1159 mov @#177232,(R4)+;177232 - register - top page (layer 0)
1160 mov @#177240,(R4)+;177240 - register - top page (layer 1)
1161 mov @#177242,(R4)+;177242 - register - top page (layer 2)
1162 mov @#177244,(R4)+;177244 - vertical scroll register layer 2
1163 mov @#177246,(R4)+;177246 - vertical scroll register layer 1
1164 mov @#177250,(R4)+;177250 - vertical scroll register layer 0
1165 mov @#177252,(R4)+;177252 - horizontal scroll register layer 0
1166 mov @#177254,(R4)+;177254 - horizontal scroll register layer 1
1167 mov @#177256,(R4)+;177256 - horizontal scroll register layer 2
1168
1169 mov R5,@#177336; return the page from which the call was made
1170
1171
1172 ;-------------------------
1173 MOV #AZ$CSR,R3 ; Preparing controller CSR
1174 MOV #AZ$DR,R4 ; Preparing controller DR
1175 20$: CLR (R3) ; Reset the controller
1176 TSTB (R3)
1177 BPL 20$
1178
1179 ; clear the memory block for the name - so that the system makes a default file name
1180 mov #23,(R3) ; command that we will write data to the buffer
1181 128$: TSTB (R3) ; check the result of execution
1182 BPL 128$ ; wait
1183 clr R1
1184
1185 mov #256.,R2 ;
1186 129$: mov R1,(R4) ; give to the controller
1187 sob R2,129$
1188
1189
1190 MOV #044,(R3) ; screenshot command
1191 22$: TSTB (R3) ;
1192 BPL 22$ ;
1193
1194 ; get the screenshot name
1195 mov #22,(R3) ; give the read memory block from the buffer to the bus
1196 121$: tstb (R3) ; check the result of execution
1197 bpl 121$ ; wait
1198
1199 mov #BUF,R1
1200 mov #256.,R2 ; read 256. words; the first word is the result of reading
1201 122$: mov (R4),(R1)+ ; read a block of words into memory
1202 sob R2,122$
1203
1204 .PRINT #RESOK
1205 .Print #BUF
1206
1207 mov #110,@#AZ$CSR; enable the network by default, the network should be constantly enabled
1208 .Exit
1209 {{/code}}
1210
1211 To unpack a screenshot, you can use this utility - [[https:~~/~~/master.pdp-11.ru/screen_unpack/>>https://master.pdp-11.ru/screen_unpack/]]
1212
1213
1214
1215 = Commands for working with the TCP/IP stack =
1216
1217 The following commands operate on the TCP/IP stack information buffer.
1218
1219 == 040: Get IP address and other TCP/IP stack settings to buffer ==
1220
1221 Command code 040, this command fills the buffer with information from the TCP/IP stack with current (actual) information.
1222
1223 == 041: Reading ip address buffer ==
1224
1225 Command code 041, this command transfers the buffer to the bus
1226
1227 This pair of commands allows you to get current information from the stack
1228
1229 * IP address
1230 * MASK mask
1231 * GW gateway
1232 * NTP address of the NTP server
1233 * DNS1 primary DNS address
1234 * DNS2 backup DNS address
1235
1236 accordingly it is 12 words
1237
1238 Example program:
1239
1240 {{code language="assembler"}}
1241 ; trap 52 - reading a block of IP addresses into the IPADDDBLOCK memory block (8 cells)
1242 ; result in R3 = 0 if error, otherwise the address where it was read (IPADDDBLOCK)
1243 GetIPaddrs: push R1
1244 push R2
1245 call AZreset; reset
1246 tst R1
1247 bne 0ERR$
1248 MOV #AZ$CSR,R1
1249 mov #40,(R1)
1250 0$: TSTB (R1); read addresses into its memory
1251 BPL 0$; wait
1252 mov #41,(R1)
1253 1$: TSTB (R1); prepare buffer
1254 BPL 1$; wait
1255 TST (R1)+; increment
1256 mov #IPADDDBLOCK,R3
1257 mov #12.,R2
1258 2$: mov (R1),(R3)+; read block of words into memory
1259 sob R2,2$
1260 mov #IPADDDBLOCK,R3; success
1261 br 0END$
1262 0ERR$: CLR R3
1263 0END$: pop R2
1264 pop R1
1265 return
1266
1267 {{/code}}
1268
1269 Example return data:
1270
1271 {{info}}
1272 Data examples - words returned in octal format
1273 124300 116400 - IP address 192.168.0.157
1274 177777 000377 - MASK mask 255.255.255.0
1275 124300 000400 - GW gateway 192.168.0.1
1276 124300 000400 - NTP address of NTP server 192.168.0.1
1277 124300 050000 - DNS1 address of primary DNS 192.168.0.90
1278 124300 055000 - DNS2 address of backup DNS 192.168.0.80
1279 {{/info}}
1280
1281 == 043: Read MAC address into ip buffer ==
1282
1283 Command code 043, this command reads the current actual MAC address into the IP address buffer i.e. first 043 and then 041 commands
1284
1285 Example program:
1286
1287 {{code language="assembler"}}
1288 ; trap 72 - reading the MAC address into the IPADDDBLOCK memory block (12 cells)
1289 ; result in R3 = 0 if error, otherwise the address where it was read (IPADDDBLOCK)
1290 GetMACaddrs: push R1
1291 push R2
1292 call AZreset ; reset
1293 tst R1
1294 bne 0ERR$
1295 MOV #AZ$CSR,R1
1296 mov #43,(R1)
1297 0$: TSTB (R1) ; read addresses into its memory
1298 BPL 0$ ; wait
1299 mov #41,(R1)
1300 1$: TSTB (R1) ; prepare buffer
1301 BPL 1$ ; wait
1302 TST (R1)+ ; increment
1303 mov #IPADDDBLOCK,R3
1304 mov #12.,R2
1305 2$: mov (R1),(R3)+ ; read block of words into memory
1306 sob R2,2$
1307 mov #IPADDDBLOCK,R3; success
1308 br 0END$
1309 0ERR$: CLR R3
1310 0END$: pop R2
1311 pop R1
1312 retur
1313
1314 {{/code}}
1315
1316
1317
1318 = Commands for working with a MicroSD card at the file level =
1319
1320
1321 These commands are designed to work with a MicroSD card at the file system level and allow you to read/write files without mounting files as disk images.
1322
1323 These commands use a 256-word buffer that is used in the interface for working with non-volatile memory (see commands 022 023 above)
1324
1325 Limitations - the length of the full path to the file is 256 bytes
1326
1327 == 050: Set the name of the file we will read ==
1328
1329 Command code 050, this command sets the name of the file that we will read, while opening the file for reading, and also obtaining its properties.
1330
1331 == 051: Get file size for reading (or its status) on BUS ==
1332
1333 Command code 051, this command transmits the file size or reading error to the MPI. The file size is 31 bits, the most significant bit is an error indicator. Accordingly, the maximum file size that can be worked with via this interface is limited to 2 ^ 31 bytes (2GB).
1334
1335 The error generation looks like this:
1336 sizeanyfile=1<<31 + FFres; ~/~/ if the most significant bit of a 32-bit word is set, then the error code is in the lower part
1337
1338 FFres = FatFS error
1339
1340 {{code language="c"}}
1341 typedef enum {
1342 FR_OK = 0, /* (0) Succeeded */
1343 FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
1344 FR_INT_ERR, /* (2) Assertion failed */
1345 FR_NOT_READY, /* (3) The physical drive cannot work */
1346 FR_NO_FILE, /* (4) Could not find the file */
1347 FR_NO_PATH, /* (5) Could not find the path */
1348 FR_INVALID_NAME, /* (6) The path name format is invalid */
1349 FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
1350 FR_EXIST, /* (8) Access denied due to prohibited access */
1351 FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
1352 FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
1353 FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
1354 FR_NOT_ENABLED, /* (12) The volume has no work area */
1355 FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
1356 FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
1357 FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
1358 FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
1359 FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
1360 FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
1361 FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
1362 } FRESULT;
1363 {{/code}}
1364
1365 [[http:~~/~~/elm-chan.org/fsw/ff/doc/open.html>>url:http://elm-chan.org/fsw/ff/doc/open.html]]
1366
1367 == 052: Read a block of a set file into a buffer ==
1368
1369 Command code 052, this command reads a file into a non-volatile memory buffer.
1370
1371 As a result, the file reading scheme looks like this
1372 **023** - fill the file name into the buffer
1373 **050 **- set the file for reading
1374 **051** - read the file length or file open error
1375 if there is an error - repeat 023 050 051 from the beginning
1376 if everything is ok - start reading the file
1377 **052** - read the file block into the buffer
1378 **022** - take data from the buffer
1379 repeat the **052 022** pairs the required number of times in order to read the entire file
1380 once the file is read - the last 052 command will close it automatically.
1381
1382 Example program:
1383
1384 {{code language="assembler"}}
1385 call AZRST; reset
1386
1387 ; load the file name into the buffer
1388 7$: mov #23,(R1); command to write data to the buffer
1389 5$: TSTB (R1); check execution result
1390 BPL 5$ ; wait
1391 TST (R1)+; increment
1392 mov #FILNM,R3
1393 1$: mov (R3),(R1); send to controller
1394 tst (R3)+
1395 bne 1$
1396 tst -(R1); decrement
1397
1398 ; set the file for reading
1399 mov #50,(R1); set file for reading
1400 2$: TSTB (R1); check execution result
1401 BPL 2$ ; wait
1402
1403 ; read the file length
1404 mov #51,(R1); set file for reading
1405 3$: TSTB (R1); check execution result
1406 BPL 3$ ; wait
1407 TST (R1)+; increment
1408 mov #FILSZ,R3
1409 mov (R1),(R3)+; read from controller
1410 mov (R1),(R3); read from controller
1411
1412 ; display the file length on the screen
1413 clr R0
1414 mov #FILSZ+2,R3
1415 mov (R3),R1
1416 call DNOZ
1417 mov -(R3),R1
1418 call DNOZ
1419 .print #STMS2
1420
1421 ; read the file
1422 mov R1,R4; R1 holds the file length
1423 MOV #AZ$CSR,R1
1424 mov #BUFFL,R5
1425
1426 bit #1,R4; if an odd number of bytes
1427 beq 47$
1428 inc R4; add 1 more byte as we read words
1429
1430 47$: tst R4
1431 beq 45$ ; nothing left to read - exit
1432
1433 mov #52,(R1); read block into buffer
1434 4$: TSTB (R1); check execution result
1435 BPL 4$ ; wait
1436 mov #22,(R1); start reading buffer
1437 51$: TSTB (R1); check execution result
1438 BPL 51$ ; wait
1439
1440 cmp R4,#512.; compare with buffer size in bytes
1441 Blos 44$ ; less than buffer size left
1442
1443 .print #STMS1
1444 mov #256.,R2
1445 TST (R1)+; move to data register
1446 46$: mov (R1),(R5)+; read into buffer
1447 sob R2,46$
1448 sub #512.,R4; subtract
1449 TST -(R1); move to command register
1450 br 47$
1451
1452 44$: .print #STMS3
1453 mov R4,R2
1454 asr R2 ; /2 since reading words
1455 TST (R1)+; move to data register
1456 43$: mov (R1),(R5)+; read into buffer
1457 sob R2,43$
1458
1459 45$: clr (R5); set end of file marker
1460
1461 ; file read - display on screen
1462 .print #STMS4
1463 .print #BUFFL
1464 .print #STMS5
1465
1466 mov #110,@#AZ$CSR; enable network
1467 .Exit
1468
1469 {{/code}}
1470
1471
1472
1473 == 053: set the name of the file that we will write ==
1474
1475 Command code 053, this command opens a file for writing, receives opening parameters (or errors).
1476
1477 == 054: Set file length ==
1478
1479 Command code 054, this command sets the expected file length, this is necessary for the correct formation of the file at the file level of the MicroSD card, as well as for organizing data transfer.
1480
1481 == 055: write data from buffer to file ==
1482
1483 Command code 055, this command writes data from the non-volatile memory buffer to an open file for writing. The last command 055 will automatically close the file when the declared file length is reached.
1484
1485 The command flow chart for writing is as follows
1486 **023** - fill the file name into the buffer
1487 **053** - set the file for reading
1488 **051** - file opening/creation status
1489 if an error - repeat from the beginning 023 053 051
1490 if everything is ok - move on
1491 **054** - set the file length, i.e. we must immediately declare what the file length will be
1492 **023** - fill the data block into the buffer
1493 **055** - write from the buffer to the file
1494 repeat the 023 055 pairs the required number of times in order to write the entire file
1495 once the file is written - the last 055 command will close it automatically
1496
1497
1498 Example program:
1499
1500 {{code language="assembler"}}
1501 ; load the file name into the buffer
1502 MOV #AZ$CSR,R1
1503 17$: mov #23,(R1); command to write data to the buffer
1504 15$: TSTB (R1) ; check execution result
1505 BPL 15$ ; wait
1506 TST (R1)+ ; move to data register
1507 mov #FILNM2,R3
1508 11$: mov (R3),(R1); send to controller
1509 tst (R3)+
1510 bne 11$
1511 tst -(R1) ; move to command register
1512
1513 ; set the file for writing
1514 mov #53,(R1); set file for writing
1515 12$: TSTB (R1) ; check execution result
1516 BPL 12$ ; wait
1517
1518 ; read file creation status
1519 mov #51,(R1)
1520 13$: TSTB (R1) ; check execution result
1521 BPL 13$ ; wait
1522 TST (R1)+ ; move to data register
1523 mov #STATS,R3
1524 mov (R1),(R3)+; read from controller
1525 mov (R1),(R3); read from controller
1526
1527 ; check here - if the file is created, both words should be zero
1528 mov #STATS,R3
1529 TST (R3)+
1530 BNE 66$
1531 TST (R3)
1532 BEQ 60$
1533 66$: .print #ERRMS1 ; print error
1534 .exit
1535
1536 60$: MOV #AZ$CSR,R1
1537 mov #54,(R1); set file length to be written
1538 23$: TSTB (R1) ; check execution result
1539 BPL 23$ ; wait
1540 TST (R1)+ ; move to data register
1541 mov #FILSZ,R3
1542 mov (R3)+,(R1); write to controller
1543 mov (R3),(R1); write to controller
1544
1545 tst -(R1) ; move to command register
1546
1547 ; write file
1548 mov @#FILSZ,R4; file length
1549 MOV #AZ$CSR,R1
1550 mov #BUFFL,R5; file buffer
1551
1552 bit #1,R4 ; if an odd number of bytes
1553 beq 147$
1554 inc R4 ; add 1 more byte since reading words
1555
1556 147$: tst R4 ; check length
1557 beq 145$ ; nothing left to write - exit
1558
1559 mov #23,(R1); write to buffer
1560 151$: TSTB (R1) ; check execution result
1561 BPL 151$ ; wait
1562
1563 cmp R4,#512.; compare with buffer size in bytes
1564 Blos 144$ ; less than buffer size left
1565
1566 .print #STMS6 ; writing full block
1567 mov #256.,R2
1568 TST (R1)+ ; move to data register
1569 146$: mov (R5)+,(R1); write to controller buffer
1570 sob R2,146$
1571 sub #512.,R4; subtract
1572 TST -(R1) ; move to command register
1573
1574 mov #55,(R1); write buffer to file
1575 104$: TSTB (R1) ; check execution result
1576 BPL 104$ ; wait
1577 br 147$ ; loop back
1578
1579 144$: .print #STMS7 ; writing last block
1580 TST (R1)+ ; move to data register
1581 mov R4,R2
1582 asr R2 ; /2 since writing words
1583 143$: mov (R5)+,(R1); write to controller buffer
1584 sob R2,143$
1585
1586 TST -(R1) ; move to command register
1587 mov #55,(R1); write last buffer to file
1588 105$: TSTB (R1) ; check execution result
1589 BPL 105$ ; wait
1590
1591 145$: .print #STMSE ; end
1592 mov #110,@#AZ$CSR; enable network
1593 .Exit ; exit
1594
1595 {{/code}}
1596
1597 **[[the example is completely in the form of the RT11 utility and is posted here>>url:https://forum.maxiol.com/index.php?s=&showtopic=5605&view=findpost&p=57055]]**
1598
1599
1600 == 056: Get data on the size of the map into the sizecard buffer ==
1601
1602 Command code 056, this command reads the parameters of the MicroSD card into the sizecard buffer
1603
1604 == 057: Reading sizecard buffer ==
1605
1606 Command code 057, this command returns the sizecard buffer (2 words)
1607
1608 sizecard buffer contains 2 words 16bit
1609 first word - total card size available for FAT in MB
1610 second word - free card size in MB
1611
1612 Example program:
1613
1614 {{code language="assembler"}}
1615 ; trap 51 - get the total/free size of the SD card in megabytes
1616 ; result in R1 - total; R2 - free
1617 GetSizeSD: call AZreset ; reset
1618 tst R1
1619 bne 0ERR$
1620 MOV #AZ$CSR,R1
1621 mov #56,(R1)
1622 1$: TSTB (R1) ; prepare buffer
1623 BPL 1$ ; wait
1624 mov #57,(R1)
1625 2$: TSTB (R1) ; prepare buffer
1626 BPL 2$ ; wait
1627 mov @#AZ$DR ,R1 ; total megabytes
1628 mov @#AZ$DR ,R2 ; free megabytes
1629 return
1630 clr R1
1631 clr R2
1632 return
1633
1634 {{/code}}
1635
1636 Example data
1637 035521 - total megabytes on the card - 15185.
1638 035417 - free megabytes - 15119.
1639
1640 = Hall of Fame API Command Block =
1641
1642 This block of commands is intended for interaction with the server [[Hall of Fame>>https://forum.maxiol.com/index.php?showtopic=5642]]
1643
1644 == **025: Инициализация Hall of Fame (HOF)** ==
1645
1646 Command code 025, this command establishes a connection to the Hall of Fame server, initializes the encrypted tunnel and prepares the API for work.
1647
1648 Example program:
1649
1650 {{code language="assembler"}}
1651 AZ$CSR = 177220 ; command and status register (CSR)
1652 AZ$DR = 177222 ; data register (DR)
1653
1654 ; buffers
1655 SNDBUF: .BLKW 256. ; send buffer
1656 RCVBUF: .BLKW 256. ; receive buffer
1657 SIDMEM: .BLKB 34. ; SID
1658 SIDCST: .ASCII \{"SID":"\ ; SID header
1659 .even
1660
1661 HOFINI: ; HOF initialization
1662 ; The result is a JSON response:
1663 ; {"SID":"session hash","RESULT":"OK"}
1664 ; or an error:
1665 ; {"RESULT":"ERROR","DESCRIPTION":"SERVER_ERROR"}
1666 ; {"RESULT":"ERROR","DESCRIPTION":"CONNECTION_ERROR"}
1667 ; The result is placed in SNDBUF
1668 ; R5 indicates success: 1 = SID exists, 0 = no SID
1669
1670 mov R5, -(SP)
1671 mov R4, -(SP)
1672 mov R3, -(SP)
1673 mov R2, -(SP)
1674 mov R1, -(SP)
1675 mov R0, -(SP)
1676
1677 mov #3,R5 ; number of attempts
1678
1679 220$: mov #AZ$CSR,R1
1680 clr (R1) ; Send "Reset" command
1681 221$: tstb (R1) ; Check controller readiness
1682 bpl 221$ ; If not ready, wait
1683
1684 mov #25,(R1) ; initialization - command 025
1685 20$: tstb (R1) ; check execution result
1686 bpl 20$ ; wait
1687
1688 ; Retrieve the result
1689 mov #22,(R1) ; output the read memory block from buffer to the bus
1690 21$: tstb (R1) ; check execution result
1691 bpl 21$ ; wait
1692 tst (R1)+ ; increment
1693 mov #SNDBUF,R3
1694 mov #256.,R2 ; read 256 words; first word is the read result
1695 22$: mov (R1),(R3)+ ; read block of words into memory
1696 sob R2,22$
1697
1698
1699 ; Determine if SID exists
1700 mov #4,R0
1701 mov #SNDBUF,R1
1702 mov #SIDCST,R2
1703 23$: cmp (R1)+,(R2)+
1704 bne 24$
1705 sob R0,23$
1706 clr R5
1707 inc R5
1708 br 26$ ; success
1709
1710 24$: ; SID not found!
1711 sob R5,220$
1712 clr R5 ; error - no SID
1713
1714 26$: mov (SP)+, R0
1715 mov (SP)+, R1
1716 mov (SP)+, R2
1717 mov (SP)+, R3
1718 mov (SP)+, R4
1719 mov (SP)+, R5
1720 return
1721
1722 {{/code}}
1723
1724 == 026: Exchange with Hall of Fame (HOF) ==
1725
1726 Command code 026, this command makes a direct exchange with Hall of Fame
1727
1728 Example program:
1729
1730 {{code language="assembler"}}
1731 ;4. user authentication
1732 ;technically, this is sending a JSON
1733 ;{"SID":"session hash","CMD":"AUTH_USER","NIKNAME":"user nickname","PASSWORD":"user password"}
1734 ;the response is also JSON
1735 ;{"SID":"session hash","RESULT":"OK","UID":"user hash"}
1736 ;or
1737 ;{"SID":"session hash","RESULT":"ERROR","DESCRIPTION":"USER_NOT_FOUND_OR_WRONG_PASSWORD"}
1738 ;{"SID":"session hash","RESULT":"ERROR","DESCRIPTION":"SERVER_ERROR"}
1739 ;{"SID":"session hash","RESULT":"ERROR","DESCRIPTION":"SESSION_NOT_EXISTS_OR_EXPIRED"}
1740
1741 ; load command CMD04
1742 mov #CMD04,R1
1743 mov #ADRMEM,R2
1744 add #42.,R2 ; shift the pointer to the SID block length
1745 33$: movb (R1)+,(R2)+
1746 bne 33$
1747
1748 .Print #ADRMEM
1749
1750 .Print #HOF05
1751 ; send the command and wait for a response
1752 ; load into buffer
1753 MOV #AZ$CSR,R1
1754 331$: TSTB (R1) ; Check controller readiness
1755 BPL 331$ ; If not ready, wait
1756 mov #23,(R1) ; command to write data into buffer
1757 34$: TSTB (R1) ; check execution result
1758 BPL 34$ ; wait
1759 TST (R1)+ ; increment
1760 mov #ADRMEM,R3
1761 mov #256.,R2 ;
1762 35$: mov (R3)+,(R1) ; send to controller
1763 sob R2,35$
1764 tst -(R1) ; decrement
1765
1766 ; exchange - command 026
1767 MOV #AZ$CSR,R1
1768 361$: TSTB (R1) ; Check controller readiness
1769 BPL 361$ ; If not ready, wait
1770 mov #26,(R1)
1771 36$: TSTB (R1) ; check execution result
1772 BPL 36$ ; wait
1773
1774 ; receive result
1775 371$: TSTB (R1) ; Check controller readiness
1776 BPL 371$ ; If not ready, wait
1777 mov #22,(R1) ; send buffer to the bus
1778 37$: TSTB (R1) ; check execution result
1779 BPL 37$ ; wait
1780 TST (R1)+ ; increment
1781 mov #ADRMEM,R3
1782 mov #256.,R2 ; read 256 words; first word is the read result
1783 38$: mov (R1),(R3)+ ; read block of words into memory
1784 sob R2,38$
1785
1786 {{/code}}
1787
1788