Skip to content

Instantly share code, notes, and snippets.

@wohali
Created February 29, 2024 00:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wohali/25a44181564e16b70d7c0fe6dd30da21 to your computer and use it in GitHub Desktop.
Save wohali/25a44181564e16b70d7c0fe6dd30da21 to your computer and use it in GitHub Desktop.
1 .title PDP11GUI RK05 sector loader/writer for RK11 controller
2
3 ; This code reads or writes one sector from a RK05 into memory
4 ; It is used by PDP11GUI to access a RK05 disc
5 ;
6 ; See
7 ; RK11-D and RK11-E moving head disk drive controller manual (Aug 1973, DEC-11-HRKDA-B-D).pdf
8 ;
9 ; !!! DO NOT CHANGE file name,
10 ; !!! entry labels,
11 ; !!! sector buffer address, or
12 ; !!! register meaning
13 ;
14 ; call conventions, stack, entry points: see "pdp11gui_main.mac"
15
16 ; framework
17 .include pdp11gui_main.mac
1 .title pdp11gui_main
2
3 .asect
4
5 ;
6 ; ----------------------------------------------------
7 ; Common main entry point for all PDP11GUI drivers
8 ;
9
10 ; Communication between PDP11GUI and driver
11 ;
12 ; 1. Principal operation
13 ; ===============
14 ; Working cycle is always:
15 ; - request: tramsit buffer to driver
16 ; operation
17 ; response: send another buffer back to pdp11gui
18 ; "request" is transmission PDP11GUI -> driver
19 ; "response" is transmission driver -> PDP11GUI
20 ;
21 ; 2. Format of data transmission
22 ; ==========================================
23 ;
24 ; 2.1. Generic transmission container format:
25 ; ===========================================
26 ; Entity for transmission and addressing is always word.
27 ; transmission :== <transmission_word_count> <checksum> <opcode> <block0>, <block1>, ...
28 ; block := <block_word_count> <data0, ..data 1,,, data>
29 ; <transmission_word_count> = len(checksum) + len (opcode) + len(block1) + len(block2) ....
30 ; = 2 + blockcount * (1 + block word count)
31 ;
32 ; - opcode: "command" on pdp11gui -> driver; "status" on driver -> pdp11gui
33 ; - "transmitted data maybe more then "<transmission_word_len>", because only whole tripletts can be transmitted.
34 ; - blockcount depends on opcode: 0, 1 or 2 blocks are used
35 ; requests: block 0 = parameters
36 ; block 1= drive data (if opcode = write)
37 ; response: block 0 = error status (if opcode != 0)
38 ; block 0 = driver data (if opcode = 0)
39 ;
40 ; - memory layout of transmission buffer:
41 ; xmbffr: = . ; base for buffer frame
42 ; xmwc: .blkw 1 ; transmission wordcount: exact wordcount, excluding len itself and checksum, but including opcode
43 ; xmcs: .blkw 1 ; transmission checksumbuffer-2: buffer checksum. checksum of all data words in rxbuff
44 ; xmbuff: = . ; base for buffer payload
45 ; ; buffer is max 2 blocks: 1st = 8 parameters, 2nd = 16kwords drive data long
46 ; ; Buffer is located at end of code, can grow up tu 48kbyte boundary
47 014004 xmopcd = xmbuff ; transmission opcode = word 0 of buffer
48 ;
49 ;
50 ; 2.2 Data buffer layouts for requests:
51 ; ======================================
52 ;
53 ; 2.2.1 Layout
54 ; ===============
55 ;
56 ; For data transfer requests, block 0 contains parameters, these are shadowed to "reqprm"
57 ; (so results can be written into transmission buffer without overwriting parameters
58 ;
59 000100 . = 100 ; do not use trap vector space
60 000100 reqprm: .blkw 10 ; copy of parameters: longest parameter block is 8 words
61
62 ; The parameter layout is almost the same same for all disk types and
63 ; disk operations.
64 ; pdp11gui must transmit these 7 words in block 0!
65 000100 prcba = reqprm+0 ; xmbuff+4: controller base address
66 000102 prunit = reqprm+2 ; xmbuff+6 ; parameter 1: unit number of disc: 0 or 1
67 000104 prflags = reqprm+4 ; xmbuff+10 ; parameter 5: flags
68 ; bit 0 = #1 = "suppress data transmission after read"
69 ; bits 1:3 are "PDP11GUI "DriverDeviceType"
70 ; bit 1 = #2 =
71 ; RX02 driver: 0 = single, 1 = double density
72 ; RK611: 0= RK06, 1 = RK07
73 ; bit 2 = #4 =
74 ; RX02 driver: 0 = RX01, 1 = RX02
75 000106 prwlen = reqprm+6 ; xmbuff+12 count of word to read/write
76 000110 prcyl = reqprm+10 ; xbuff+14 ; parameter 2: cylinder, always starting with 0
77 000112 prhead = reqprm+12 ; xbuff+16 ; parameter 3: head, always starting with 0
78 000114 prsect = reqprm+14 ; xbuff+20 ; parameter 4: sector. always starting with 0
79 ; MSCP is different: starting block # instead of cyl/head/sector
80 000110 prstb0 = reqprm+10 ; start block number lo word
81 000112 prstb1 = reqprm+12 ; start block number hi word
82
83
84 ; for Halt, 1st param is monitor entry address, or 0.
85 000100 prmnea = reqprm+0 ; xmbuff+4: MoNitor Entry Address
86
87
88
89
90
91 ; <param0,param1, ...>
92 ; block 1 contains drive data (on disk write)
93 000120 req0wc: .blkw 1 ; addr of len word of block0/1
94 000122 req0dt: .blkw 1 ; address of 1st data word for block 0/1, depending on opcode
95 ; - reqdat: "request disk data", start adress of block 1, including len
96 000124 req1wc: .blkw 1
97 000126 req1dt: .blkw 1
98 ;
99 ; 2.2.2 request opcodes:
100 ; ======================
101 ; addr = xmopcd
102 000001 opecho = 1 ; echo block, with inverted data.
103 000002 opinit = 2 ;
104 000003 opread = 3 ; read multiple sectors in one track
105 000004 opchek = 4 ; check multiple sectors in one track
106 000005 opwrite = 5 ; write " " "
107 000006 ophalt = 6 ; halt driver, or jump back to monitor (M9312 console emulator)
108 000007 oprest = 7 ; execute Bus RESET
109
110 ;
111 ; 2.2.3 parameters
112 ; ===============
113 ; 2.2.3.1 opcode opinit
114 ; +0 <controller_addr>
115 ; +1 <unitnr>
116 ;
117 ; 2.2.3.2 opcodes opread,opwrite,opchek
118 ; RL02,RX02,RM03:
119 ;
120 ; reqprm
121 ; word offset parameter
122 ; +0 <controller_addr>
123 ; +1 <unitnr>
124 ; +2 <flags>
125 ; +3 <count of words to read/write>
126 ; +4 <cylinder>
127 ; +5 <head>
128 ; +6 <sector>
129
130 ; MSCP is slightly different:
131 ; +4 <start block lo word>
132 ; +5 <start block hi word>
133 ; +6 0
134 ;
135 ;
136 ; 2.3 Data buffer layouts for responses:
137 ; ======================================
138 ;
139 ; 2.3.1 Layout
140 ; ===============
141 ; only block 0 and opcode ist used.
142 ; - rspsta: opcode, as "response status"
143 014004 rspsta = xmopcd ; status (0=OK; else error location)
144
145 ; - rspwc: wordcount for response is calculated in "doresp"
146 ; rspwc = xmbuff+2 ; len of data, driver codes counts data here
147 ; - rspdat: start adress of block 0 for response, including len. used for error and result disk data
148 014010 rspdat = xmbuff+4 ; 1st data word of block 0; data: error vector, or disk data
149 ; on jump to "doresp", r3 must contain next unwritten addr in resdat
150 ; this is used to calculate len of whole transmission
151
152
153 ;
154 ; 2.3.2 Response status
155 ; ===============
156 ; 2.3.2.1 Error
157 ; status != 0: Error. error code contains "location" in driver source code
158 ; data are additional info (controller registers)
159 ; len is fixed as symbol "errwcnt", but depends on disk controller hardware
160 ;
161 ; 2.3.2.1 opcode "opinit"
162 ; status = 0: OK.
163 ; + 0 drive sub type. Is interpreted depending on driver type.
164 ; 2.3.2.1.1 RL01,2, RM03, RX02:
165 ; disk sub type is transmitted back.
166 ; 2.3.2.1.2 MSCP
167 ; [0] unit identifer 1st lo (from ONLINE)
168 ; [1] unit identifer 1st hi (from ONLINE)
169 ; [2] unit identifer 2nd lo (from ONLINE)
170 ; [3] unit identifer 2nd hi (from ONLINE)
171 ; [4] media type identifier lo (from ONLINE)
172 ; [5] media type identifier hi (from ONLINE)
173 ; [6] reserved (from ONLINE)
174 ; [7] reserved (from ONLINE)
175 ; [8] blockcount lo (from ONLINE)
176 ; [9] blockcount hi (from ONLINE)
177 ; [10] volume serial num lo (from ONLINE)
178 ; [11] volume serial num hi (from ONLINE)
179 ; [12] cylinder size (from GET UNIT STATUS)
180 ; [13] group size (from GET UNIT STATUS)
181 ; [14] cylinder size (from GET UNIT STATUS)
182 ; [15] reserved (from GET UNIT STATUS)
183 ; [16] RCT size (from GET UNIT STATUS)
184 ; [17] RBNS/copies (from GET UNIT STATUS)
185
186 ; 2.3.2.2 opread, opcheck
187 ; status = 0: OK.
188 ; 2.3.2.3 opwrite
189 ; status = 0: OK.
190 ; + 0..len-1 disk data
191
192 ;
193 ; 3. Code modules
194 ; ===============
195 ; Code is split in common code (block transfer for request and responses)
196 ; and disk specfic implementation of read, write and error
197 ;
198 ; 3.1 Common code:
199 ; ===============
200 ; 3.1.1 main entry
201 ; label "dofunc" at 10000 is main entry point
202 ; label "doresp" is called bei each driver function to transmit response back
203 ; to pdp11gui and to terminate
204 ;
205 ; 3.1.2 Register usage
206 ; ====================
207 ; R0 working accumulator
208 ; R3 is pointer in data buffer for read/write
209 ; R4 is the controller base register
210 ; R5 is always an "location mark" for a certain code postion
211 ; on error it is the error reason.
212 ; Carry-flag C is error indicator, see below
213 ;
214 ; 3.1.3 Error handling
215 ; ====================
216 ; The Carry flag "C" is used as a error indicator
217 ; if C is set after a sub routine call, an error occured,
218 ; and reqsta, reqwc and reqdata contains already error information. r3 points to end of data
219 ; The caller must return then immediately
220 ; Example:
221 ;
222 ; sub1:
223 ; ...
224 ; tst something
225 ; bne 9$ ; error detected: create Exception
226 ; ...
227 ; clc ; no error, clear carry
228 ; return
229 ;
230 ; 9$ ; ERROR
231 ; call @#chkerr ; prepare block buffer wit herror data, sets carry with "sec
232 ; return
233 ;
234 ; caller:
235 ; ...
236 ; call @#sub1
237 ; bcs 9$ ; error: R0..R5 contain error codes, exit
238 ; ....
239 ; 9$: return
240
241
242
243 ; --------------------------------------------------------
244 ; catch vectors. halting here means error!
245 000000 . = 0
246 000000 000002 .word trprv ;Reserved vector
247 000002 000000 trprv: halt
248
249 000004 . = 004 ; Time-out/system error vector
250 000004 000006 .word trpbe ; Bus Error trap
251 000006 000000 trpbe: halt
252
253 000010 . = 010 ; Illegal and reserved instruction vector
254 000010 000012 .word trpri ; Reserved instruction trap
255 000012 000000 trpri: halt
256
257 000014 . = 014 ; BPT instruction vector
258 000014 000016 .word trpbpt
259 000016 000000 trpbpt: halt
260
261 000020 . = 020 ; IOT instruction vector
262 000020 000022 .word trpiot
263 000022 000000 trpiot: halt
264
265 000024 . = 024 ; Power fail vector
266 000024 000026 .word trppf
267 000026 000000 trppf: halt
268
269 000030 . = 030 ; EMT instruction vector
270 000030 000032 .word trpwmt
271 000032 000000 trpwmt: halt
272
273 000034 . = 034 ; TRAP instruction vector
274 000034 000036 .word trptrp
275 000036 000000 trptrp: halt
276
277
278
279 ; --------------------------------------------------------
280 010000 . = 10000
281
282 010000 stack = .
283
284 ; main entry point
285 dofunc:
286 010000 012706 010000 mov #stack,sp ; setup stack
287 ; 1) receive data. only register values are evaluated
288 010004 004737 011206 call @#blkrcv ; todo: do not ignore errors
289
290
291 ; checksum ?
292 010010 004737 012250 call @#calccs ; calculate checksum to R0
293 010014 020037 014002 cmp r0,@#xmcs ; compare with received checksum
294 010020 001414 beq 1$
295 010022 012703 014004 mov #rspsta,r3 ; write into block 0: status, wordcount,len val0, val1, val ,,,
296 010026 012723 000001 mov #1,(r3)+ ; set opcode = error location #1
297 010032 012723 000002 mov #2,(r3)+ ; word count: 2 more result words
298 010036 010023 mov r0,(r3)+ ; calculated checksum
299 010040 013723 014002 mov @#xmcs,(r3)+ ; received checksum
300 010044 000261 sec ; set error exception flag
301 010046 000137 010272 jmp @#doresp ; r3 = end of transmission buffer
302
303 1$:
304 ; calculate addresses of wordcount and data for block 0
305 010052 012703 014006 mov #xmbuff+2,r3
306 010056 010337 000120 mov r3,@#req0wc ; addr of len of block 0 = "ptr to len"
307 010062 062703 000002 add #2,r3
308 010066 010337 000122 mov r3,@#req0dt ; addr of data in block 0
309
310
311 ; eval opcodes
312 ; 1) opcodes without parameters in block 0
313 010072 013700 014004 mov @#xmopcd,r0
314
315 010076 020027 000007 cmp r0,#oprest
316 010102 001006 bne 10$
317 010104 000005 reset
318 ; now return "OK" without data
319 010106 012703 014010 mov #rspdat,r3 ; point to data start = no data
320 010112 000241 clc ; clear error exception flag
321 010114 000137 010272 jmp @#doresp
322
323 010120 020027 000001 10$: cmp r0,#opecho
324 010124 001002 bne 20$
325 010126 000137 012436 jmp @#doecho ; echo block, implemented by serialxfer
326
327
328 20$: ; 2) opcodes with parameters in block 0, and optional data in block 1
329 ; copy driver parameters from buffer to shadow
330 010132 013703 000120 mov @#req0wc,r3 ; point to len of block 0
331 010136 004737 010336 call @#dupprm ; on exit: r3 = start of block 1, if any
332 ; calculate addresses wordcount and data for block 1 (used only for "write")
333 010142 010337 000124 mov r3,@#req1wc ; addr of len of block 1
334 010146 062703 000002 add #2,r3
335 010152 010337 000126 mov r3,@#req1dt ; addr of start of block 1
336
337 010156 020027 000006 30$: cmp r0,#ophalt
338 010162 001005 bne 40$
339 ; exit driver with HALT or jump to monitor
340 010164 013700 000100 mov @#prmnea,r0 ; load argument for HALT
341 010170 001001 bne 31$
342 010172 000000 halt ; if 0: execute HALT
343 010174 010007 31$: mov r0,pc ; if address: jump to MoNitor Entry Address
344
345 010176 020027 000002 40$: cmp r0,#opinit
346 010202 001002 bne 50$
347 010204 000137 010360 jmp @#doinit ; "initialize disk" implemented by driver
348 010210 020027 000003 50$: cmp r0,#opread
349 010214 001002 bne 60$
350 010216 000137 010452 jmp @#doread ; "read sectors" implemented by driver
351 010222 020027 000004 60$: cmp r0,#opchek
352 010226 001002 bne 70$
353 010230 000137 010460 jmp @#dochek ; "check sectors" implemented by driver
354 010234 020027 000005 70$: cmp r0,#opwrit
355 010240 001002 bne 80$ ; unknown opcode
356 010242 000137 010554 jmp @#dowrit ; "write sectors" implemented by driver
357
358 80$: ; illegal opcode: generate error
359 010246 012703 014004 mov #rspsta,r3 ; write into buffer: status, wordcount,len val0, val1, val ,,,
360 010252 012723 000002 mov #2,(r3)+ ; set error location #2
361 010256 012723 000001 mov #1,(r3)+ ; word count: 1 result words
362 010262 010023 mov r0,(r3)+ ; the illegal opcode
363 010264 000261 sec ; set error exception flag
364 010266 000137 010272 jmp @#doresp
365
366
367 ; --- doresp - end current operation and send result in response transmission
368 ; rspsta, rspdat are filled with error data or regular disk data. rspwc is calulated
369 ; r3: points to word after result buffer, is used to calculated
370 ; len of block 0 and transmission buffer word count. If noting is sent back, r3 == rspdat
371 ; Carry C = error flag.
372 ; Carry set: return exception, do not clear rspsta
373 ; Carry clear: return normal result
374 ; rspsta is cleared ("OK")
375 ; data is transmitted
376
377 doresp:
378 ; in case of error, buffer is already filled with error data
379 010272 103001 bcc 8$ ; no carry, no error
380 ; -- error! error information is already in buffer
381 ; halt ; option to stop on error
382 010274 000402 br 9$
383
384 ; -- no error. data buffer and len is filled
385 010276 005037 014004 8$: clr @#rspsta ; clear status = OK
386 9$: ; transmit buffer back
387 ; r3 = buffer end: calculate transmission buffer count
388 ; transmission buffer: checksum + opcode + len + data
389 010302 162703 014010 sub #rspdat,r3 ; subtract buffer base. r3 = bytes in response data
390 010306 000241 clc
391 010310 006003 ror r3 ; bytes-> word: (unsigned)r3 /= 2
392 ; asr r3 ; r3 = words in response data
393 010312 010337 014006 mov r3,@#rspdat-2 ; save data count in len field of block 0
394 010316 062703 000003 add #3,r3 ; include response len (block 0) and checksum+opcode
395 010322 010337 014000 mov r3,@#xmwc
396 010326 004737 011536 call @#blkxmt ; transmit data, checksum is also calculated
397
398 ; now wait for next command
399 010332 000137 010000 jmp @#dofunc
400
401 ; halt ; only regular halt
402
403
404
405
406 ; --- dupprm
407 ; parameters in input block 0 must be copied to global variables area "reqprm"
408 ; since request buffer content may be overwritten bei read/error operation
409 ; driver must define global variables for parameter
410 ; framework uses "prmsta" and "prmlen" to copy parameters from transmission
411 ; input: r3 on len of block 0
412 ; Exit: r3 is after block 0. if block0 is empty
413 dupprm:
414 ; copy input params from buffer to
415 010336 012702 000100 mov #reqprm,r2 : start of parameter buffer
416 010342 012301 mov (r3)+,r1 ; r1: word count := word len of block 0
417 010344 001403 beq 9$ ; r1 = 0: stop
418 1$:
419 010346 012322 mov (r3)+,(r2)+ ; { *dst++ = *src++
420 010350 005301 dec r1
421 010352 001375 bne 1$ ; } while (--r1)
422 ; sob r1,1$ ; SOB not standard! (11/45?)
423 9$:
424 010354 000207 return ; r3 points to next word after block 0
425
426
427
428 ;
429 ;
430 ; 3.2 Driver specific code:
431 ; ========================
432 ;
433 ; map parameters to buffer positions. example pdp11gui_rl02.mac
434 ; prcba = reqprm+2 ; parameter 0: controller base address
435 ; prunit = reqprm+4 ; parameter 1: unit number of disc: 0 or 1
436 ; prcyl = reqprm+6 ; parameter 2: cylinder
437 ; prhead = reqprm+10 ; parameter 3: head, always 0
438 ; prsect = reqprm+12 ; parameter 4: sector: 0..25 (not: 1..26!)
439 ; prflags = reqprm+14 ; parameter 5: flags
440 ; ; bit 0 = #1 = "suppress data transmission after read"
441 ; ; bit 1 = #2 = double density
442 ; ; bit 2 = #4 = RX02
443 ; ....
444 ; map error registers to buffer
445 ; ;ressta = rxbuff+0 ; result status. common to all drivers, already defined
446 ; ;reswc = rxbuff+2 ; 2nd word is len. common to all drivers. here always "1", only RXES is returned
447 ; errcs = rspdat+0 ; param 0: RXCS register
448 ;
449 ; .include pdp11gui_main.mac
450 ; doinit:
451 ; ...
452 ; doread:
453 ; ...
454 ; dochek:
455 ; ...
456 ; dowrit:
457 ; ...
458 ;
459 ; ; -- error routine: check Hardware for error.
460 ; ; r5: "location mark"
461 ; X if ok: Carry clear
462 ; ; if error: Carry set, and buffer positions "err*" already set.
463 ; ; Transmission buffer and input parmeters are overwritten !
464 ; on exit: R3 points to end of error buffer!
465 ; ;chkerr:
466 ; tst .... ; test a bit 15
467 ; bpl 1$ ; no error
468 ; ; error!
469 ; ; input parameter in transmission buffer are now overwritten !
470 ; mov r5,@#ressta ; set error code
471 ; mov #rspdat,r3
472 ; mov #error_wordcount,@#reswc ; set word count. alwys the sameset error code
473 ; ... query "error_wordcount" controller registers and save in buffer locations "(r3)+"
474 ; sec ; set error flag
475 ; return ; r3 points to next word after error data
476 ; 1$: ; no error. do not overwrite transmission buffer
477 ; clc ; clear error flag
478 ; return
479 ;
480 ;
481 ;
481
18
19 ; Flags in parameter "prflags": not used
20 ; prtrack is 0..202
21 ; prhead is 0..1
22 ; prsector is 0..11
23
24 ; controller register offsets against base address
25
26 000000 rkds =+0 ; drive status register
27 000002 rker =+2 ; error register
28 000004 rkcs =+4 ; control status register
29 000006 rkwc =+6 ; word count register
30 000010 rkba =+10 ; current bus address register
31 000012 rkda =+12 ; disk address register
32 000016 rkdb =+16 ; data buffer register
33
34
35 ; function opcodes (Bit 3:1 in rkcs), with GO bit set
36 000001 fncrst =0*2+1 ; Control Reset
37 000003 fnwrit =1*2+1 ; Write
38 000005 fnread =2*2+1 ; Read
39 000007 fnwchk =3*2+1 ; Write Check
40 000011 fnseek =4*2+1 ; Seek
41 000013 fnrchk =5*2+1 ; Read Check
42 000015 fndrst =6*2+1 ; Drive Reset
43 000017 fnwlck =7*2+1 ; Write Lock
44
45
46 ; global variables for this driver
47 010356 flgchk: .blkw 1 ; 1 = do not transmit read data back (= do "check operation")
48
49 ; --------------- entry for "get drive information --------------------
50 ; reset drive and reset controller
51
52 doinit: ; RK11 executes "Control Reset", then "Drive Reset"
53 010360 013704 000100 mov @#prcba,r4 ; r4 = always controller base address
54 010364 012764 000001 000004 mov #fncrst,rkcs(r4) ; reset controller
55
56 010372 105764 000004 1$: tstb rkcs(r4) ; check controller ready
57 010376 100375 bpl 1$ ; loop while 0
58
59 ; select drive
60 010400 005002 clr r2
61 010402 005003 clr r3
62 010404 004737 010704 call @#setreg ; set all data, only drive selectin rkda matters here
63 010410 012764 000015 000004 mov #fndrst,rkcs(r4) ; reset drive
64
65 010416 032764 000100 000000 2$: bit #100,rkds(r4) ; wait for Read/Write/seek READY
66 010424 001774 beq 2$
67
68
69 010426 012703 014010 mov #rspdat,r3 ; if no error: return no data
70 010432 012705 000101 mov #101,r5 ; error location #101
71 010436 004737 010626 call @#chkerr ; wait and check
72 010442 004737 010626 call @#chkerr ; permanent errors ?
73
74
75 ; carry is error flag
76 010446 000137 010272 jmp @#doresp
77
78
79 ; --------------- entry for read and / check--------------------
80
81 doread:
82 010452 005037 010356 clr @#flgchk ;
83 010456 000403 br dordch
84 dochek:
85 010460 012737 000001 010356 mov #1,@#flgchk ; set flag to inhibit data transmission
86 dordch:
87
88 010466 013704 000100 mov @#prcba,r4 ; r4 = always controller base address
89
90 010472 012705 000102 mov #102,r5 ; error location
91
92 010476 012703 014010 mov #rspdat,r3 ; r3 = start of result block
93 010502 013702 000106 mov @#prwlen,r2 ; wordcount to read
94
95 010506 004737 010704 call @#setreg ; setup registers for read/write. input=r2,r3,unit/track/gead/sector
96
97 010512 004737 011020 call @#readsc ; read one or many sectors
98 010516 103414 bcs 9$ ; error exit
99 ; now "prwlen" words have been read into "rspdat". advance r3
100 010520 012703 014010 mov #rspdat,r3 ; reset r3 to begin of data of block 0 = "empty"
101 010524 013702 000106 mov @#prwlen,r2 ; wordcount to read
102 010530 060203 add r2,r3
103 010532 060203 add r2,r3 ; r3 += byte count
104
105 ; exit without error, but optionally suppress data
106 ; -- writing output params destroys input params!
107 010534 005737 010356 tst @#flgchk
108 010540 001402 beq 1$
109 010542 012703 014010 mov #rspdat,r3 ; reset r3 to begin of data of block 0 = "empty"
110 1$:
111 010546 000241 clc ; clear error flag
112 9$:
113 010550 000137 010272 jmp @#doresp ; r3 = end of buffer
114
115
116 ; --------------- entry for write --------------------
117
118 dowrit:
119 010554 013704 000100 mov @#prcba,r4 ; r4 = always controller base address
120
121 ; r3 = pointer in result buffer = data area of request block 1
122
123 010560 012705 000105 mov #105,r5 ; error location
124 010564 013703 000126 mov @#req1dt,r3 ; r3 = data of request data block 1
125 010570 013702 000124 mov @#req1wc,r2 ; r2 = word count to write
126 010574 011202 mov (r2),r2 ; r2 is addr of len
127 010576 004737 010704 call @#setreg ; setup registers for read/write. input=r2,r3
128
129 010602 012705 000107 mov #107,r5 ; error location
130 010606 004737 011052 call @#writsc ; write one or many sectors
131 010612 103403 bcs 9$ ; error exit
132
133 ; exit without error and without response data
134 010614 012703 014010 mov #rspdat,r3 ; r3 = start of result block 0 = no data
135 010620 000241 clc ; clear error flag
136 9$:
137 010622 000137 010272 jmp @#doresp
138
139
140
141 ; -------- check for error
142 ; 1) checks error bits in rkcs
143 ; 2) if error: return 4 registers
144 ; r5 must contain error location
145 ; result: 1st word = rkds, 2nd word=rker. 3rd= rkcs, 4th=rkda
146 chkerr:
147 ; verify controller ready
148 010626 105764 000004 0$: tstb rkcs(r4) ; test for "controller ready"
149 010632 100375 bpl 0$ ; wait
150
151 010634 016400 000004 mov rkcs(r4),r0
152 010640 100402 bmi 1$ ; bit 15 = Any error
153
154 010642 000241 clc
155 010644 000207 return ; CSR = R1 = 0: no error
156
157 1$: ; error!
158 010646 012703 014004 mov #rspsta,r3 ; r3 = pointer to response block 0
159 010652 010523 mov r5,(r3)+ ; result status = error location
160 010654 012723 000004 mov #4,(r3)+ ; 4 error words following
161
162 010660 016423 000000 mov rkds(r4),(r3)+ ; 1st word = rkds
163 010664 016423 000002 mov rker(r4),(r3)+ ; 2nd word=rker.
164 010670 016423 000004 mov rkcs(r4),(r3)+ ;3rd= rkcs,
165 010674 016423 000012 mov rkda(r4),(r3)+ ; 4th=rkda
166 010700 000261 sec ; error flag
167 010702 000207 return
168
169
170 ; --------------------------------------------------
171 ; setreg
172 ; set up controller registers:
173 ; fills DA with cylinder, head, sector
174 ; sets BA with address R3
175 ; sets WC
176 ;
177 ; r2 = word count (not complemented)
178 ; r3 = buffer address
179 ; read: r3 = response buffer
180 ; write: r3 = request buffer 1
181 ; r4 = controller base
182 ; r5 = error location
183 setreg:
184 ; --- setup disk address
185 010704 013701 000102 mov @#prunit,r1 ; 3 bit drive select -> bits <15:13>
186 010710 042701 177770 bic #177770,r1 ; r1 &= 07
187 010714 000241 clc
188 010716 006001 ror r1 ; rotate <2:0> into <15:13> through carry
189 010720 006001 ror r1
190 010722 006001 ror r1
191 010724 006001 ror r1
192 010726 013700 000110 mov @#prcyl,r0 ; 8bit cylinder addr -> bits <12:5>
193 010732 042700 177400 bic #177400,r0 ; r0 &= 0377
194 010736 006300 asl r0
195 010740 006300 asl r0
196 010742 006300 asl r0
197 010744 006300 asl r0
198 010746 006300 asl r0
199 010750 050001 bis r0,r1
200 010752 013700 000112 mov @#prhead,r0
201 010756 001402 beq 1$
202 010760 052701 000020 bis #20,r1 ; head 1: set bit 4 "SUR"
203 1$:
204 010764 013700 000114 mov @#prsect,r0
205 010770 042700 177760 bic #177760,r0 ; r0 &= 017
206 010774 050001 bis r0,r1 ; add to result
207 010776 010164 000012 mov r1,rkda(r4)
208
209 ; --- setup word count
210 011002 010201 mov r2,r1 ; r1 = word count
211 011004 005401 neg r1
212 011006 010164 000006 mov r1,rkwc(r4) ; 2s complement
213
214 ; --- setup data bus address
215 011012 010364 000010 mov r3,rkba(r4)
216 ; address extension bits <5:4> MEX in rkcs must be 0
217
218 011016 000207 return
219
220
221
222 ;-----------------------------------------------------------------------
223 ; readsc - read sectors
224 ; r4 is controller base addr
225 ; r5 is error location
226 ; setreg must have been run
227 readsc: ; read sectors
228 011020 012764 000005 000004 mov #fnread,rkcs(r4) ; read and GO
229
230 011026 105764 000004 0$: tstb rkcs(r4) ; check controller ready
231 011032 100375 bpl 0$ ; loop while 0
232
233 011034 032764 000100 000000 1$: bit #100,rkds(r4) ; wait for Read/Write/seek READY
234 011042 001774 beq 1$
235
236 011044 004737 010626 call @#chkerr ; carry = error
237 011050 000207 return
238
239
240 ;-----------------------------------------------------------------------
241 ; writsc -write sectors
242 ; r4 is controller base addr
243 ; R5 = error location
244 writsc: ; write sectors
245 011052 012764 000003 000004 mov #fnwrit,rkcs(r4) ; write and GO
246
247 011060 105764 000004 0$: tstb rkcs(r4) ; check controller ready
248 011064 100375 bpl 0$ ; loop while 0
249
250 011066 032764 000100 000000 1$: bit #100,rkds(r4) ; wait for Read/Write/seek READY
251 011074 001774 beq 1$
252
253 011076 004737 010626 call @#chkerr ; carry = error
254 011102 000207 return
255
256
257 .include pdp11gui_aux.mac
1 .title aux
2
3 ; utilities
4
5 ; memclr
6 ; clears r0..r5
7 regclr:
8 011104 005000 clr r0
9 011106 005001 clr r1
10 011110 005002 clr r2
11 011112 005003 clr r3
12 011114 005004 clr r4
13 011116 005005 clr r5
14 011120 000207 return
15
16 ; memclr
17 ; clears R2 words from R0
18 ; Return: R2 is 0, R0 is incremeneted
19 memclr:
20 1$:
21 011122 005702 tst r2 ; while(n) {
22 011124 001403 beq 2$
23 011126 005020 clr (r0)+ ; *dst++ = 0
24 011130 005302 dec r2 ; n--
25 011132 000773 br 1$ ; }
26 2$:
27 011134 000207 return
28
29 ; memset
30 ; fills memory with double-word pattern
31 ; sets R3 words from R0 to value in R1,R2
32 ; r3 must be even!
33 ; Return: R3 is 0, R0 is incremented
34 ; Speed is essential for RLE decoding
35 ; Speed calculation: n*3 cycles
36 memset:
37 011136 005703 tst r3
38 011140 001404 beq 9$ ; already 0
39 1$:
40 011142 010120 mov r1,(r0)+ ; *dst++ = pattern_1
41 011144 005303 dec r3
42 011146 010220 mov r2,(r0)+ ; *dst++ = pattern_2
43 011150 077304 sob r3,1$
44 9$:
45 011152 000207 return
46
47
48 ; memcpy
49 ; copy R2 words from R0 to R1
50 ; Return: R0, R1 are incremented, R2 is 0
51 memcpy:
52 1$:
53 011154 005702 tst r2 ; while(n) {
54 011156 001403 beq 2$
55 011160 012021 mov (r0)+,(r1)+ ; *dst++ = *src++
56 011162 005302 dec r2 ; n--
57 011164 000773 br 1$ ; }
58 2$:
59 011166 000207 return
60
61 ; warte 64k cpu cycles
62 wait64k:
63 011170 010046 mov r0,-(sp)
64 011172 012700 100000 mov #100000,r0 r0 ; loop hat 2 cycles: load with 32k
65 011176 005300 1$: dec r0
66 011200 001376 bne 1$
67 011202 012600 mov (sp)+,r0
68 011204 000207 return
69
69
258
259 .include pdp11gui_serialxfer.mac
1 .title serialxfer
2
3 ; high speed buffer access over serial port 0
4 ;
5 ; Compression:
6 ; like uuencode / base64
7 ; Each serial char defines 6 bits, char is in range 0x20 .. 0x5f
8 ; 8 chars defines 3 words
9 ; Char # : <.0..> <..1..> <..2..> <.3..> <.4..> <..5..> <..6..> <.7..>
10 ; Char Bits : 543210 54 3210 5432 10 543210 543210 54 3210 5432 10 543210
11 ; bytes : 765432 10 7654 3210 76 543210 765432 10 7654 3210 76 543210
12 ; byte # : <...0...> <...1...> <...2...> <..3....> <...4...> <...5...>
13 ; word # : <...msb0....lsb0..> <...msb1....lsb1..> <..msb2.....lsb2..>
14 ;
15 ; bytes : 000000 00 0000 0000 76 543210 765432 10 7654 3210 76 543210
16
17 ; Layer1: Complete transmission format, encodes a list of 16 bit words
18 ; <STARTCHAR> [<RLECHAR>] <char octet> ... <ENDCHAR>
19 ;
20 ; - characters ' ' = 0x20 = 040 to '_' = 0x5F = 0137 encode data
21 ; - characters below #$20 are to be ignored
22 ; - '{' = 0x7b = 0173 is STARTCHAR, '}' = 0x7D = 0175 is ENDCHAR
23 ; - all other chars instead of START are ignored. '~' is used as delay char.
24 ; - RLE encoding: a repeating pattern of 2 words is recognized.
25 ; The indicator char RLECHAR '|' before char[0] modifies the meaning of
26 ; the next 8 char/3 word block:
27 ; '|', char[0], ... char[7] => RLE, word[0], word[1], word[2]
28 ; with word[0] = block_len, word[1] = pattern_1, word[2] = pattern_2
29 ; ! Number of encoded words = block_len => block_len always even !
30 ; - RLE Block length processing time:
31 ; PDP-11 CPU must copy <blocklen> words within one character transmission time.
32 ; blocklen is limited by high baudrates and slow CPUs.
33 ; processing time per RLE block: 100 cycles fix, + 6 micros per word copy
34 ; Time of one char transmission:
35 ; 38400 baud , 10 bit/char: t = 1000000/38400*10 = 260 micro sec per char
36 ; - after { and before first data char, the 16 bit sum of all data words
37 ; in buffer is send
38 ; - transmit
39 ; 1. send <CR> {
40 ; 2. send data octets
41 ; 3. send "} <CR>"
42 ; - receive:
43 ; 1. discard characters, until "{" is received
44 ; 3. receive and decode char-octets, until '}' is received
45 ; 4. discard "}"
46 ;
47 ; For blockread,write, this convention is used:
48 ; - Operation is always
49 ; 1. receive data
50 ; 2. execute code
51 ; 3. transmit data
52 ;
53 ; BlockRead:
54 ; 1. receive checksum word
55 ; 2. receive block of 6 words, wich contain values for R0..R5
56 ; 3. start BlockRead-Procedure with R0..R5
57 ; 4. send block of checksum + 6 + bufferlen words.
58 ; word[0] is checksum, words[1..6] contain exit values for R0..R5
59 ; BlockWrite
60 ; 1. receive block of 1 +6 + bufferlen words,
61 ; 2. start BlockWrite-Procedure with R0..R5 and write buffer
62
63 ; This source get's .INCLUded, so define no offset!
64 ;
65
66 ; .asect
67 ; .=1400
68
69 ; --------------------------------------------------
70
71
72
73
74 ; --------------------------------------------------
75 ; BLKRCV - block receive
76 ; Receive coded characters, and save resulting words in buffer
77 ; Input
78 ; Result: buffer at "rxbffr" filled with triplets
79 ; rxbfcs checksum as transmitted
80 ; rxbfln = word count as received
81 blkrcv:
82 ; mov #100000,r2 ; trace rcv chars
83
84 011206 012700 014000 mov #xmbffr,r0 ; start of buffer frame
85 011212 005001 clr r1 ; counter
86 ; test daten
87 ; mov #201,r1 ; test data word count = 129 = 0x81
88 ; mov #rcvtst,r2 ; ptr to test data
89
90 ; wait for '{' == 173
91 0$:
92 011214 004737 012612 call @#rcvchr
93 011220 122705 000173 cmpb #'{,r5
94 011224 001373 bne 0$
95
96 1$: ; do {
97 011226 005002 clr r2 ; clear RLE indicator
98 011230 005004 clr r4 ; assemble word[0]
99 011232 004737 012530 call @#rcvbit ; r5 = char[0]
100 011236 103534 bcs 3$ ; carry set: end
101 011240 102004 bvc 2$ ; overflow not set: receive 3 literal words
102 ; RLE indicator: next 3 words are <repeat> <value> <don't care>
103 011242 005202 inc r2 ; set RLE indicator
104 011244 004737 012530 call @#rcvbit ; receive again: r5 = char[0]
105 011250 103527 bcs 3$ ; carry set: end
106 2$:
107 011252 012703 000012 mov #12,r3
108 011256 004737 012120 call @#sl5or4 ; r4 |= (r5 << 10)
109 011262 004737 012530 call @#rcvbit ; r5 = char[1]
110 011266 103520 bcs 3$ ; carry set: end
111 011270 012703 000004 mov #4,r3
112 011274 004737 012120 call @#sl5or4 ; r4 |= (r5 << 4)
113 011300 004737 012530 call @#rcvbit ; r5 = char[2]
114 011304 103511 bcs 3$ ; carry set: end
115 011306 012703 000002 mov #2,r3
116 011312 004737 012144 call @#sr5or4 ; r4 |= (r5 >> 2)
117 011316 010420 mov r4,(r0)+ ; word[0] fertig
118 011320 005201 inc r1
119
120 011322 005004 clr r4 ; assemble word[1]
121 011324 012703 000016 mov #16,r3
122 011330 004737 012120 call @#sl5or4 ; r4 |= (r5 << 14)
123 011334 004737 012530 call @#rcvbit ; r5 = char[3]
124 011340 103473 bcs 3$ ; carry set: end
125 011342 012703 000010 mov #10,r3
126 011346 004737 012120 call @#sl5or4 ; r4 |= (r5 << 8)
127 011352 004737 012530 call @#rcvbit ; r5 = char[4]
128 011356 103464 bcs 3$ ; carry set: end
129 011360 012703 000002 mov #2,r3
130 011364 004737 012120 call @#sl5or4 ; r4 |= (r5 << 2)
131 011370 004737 012530 call @#rcvbit ; r5 = char[5]
132 011374 103455 bcs 3$ ; carry set: end
133 011376 012703 000004 mov #4,r3
134 011402 004737 012144 call @#sr5or4 ; r4 |= (r5 >> 4)
135 011406 010420 mov r4,(r0)+ ; word[1] fertig
136 011410 005201 inc r1
137
138 011412 005004 clr r4 ; assemble word[2]
139 011414 012703 000014 mov #14,r3
140 011420 004737 012120 call @#sl5or4 ; r4 |= (r5 << 12)
141 011424 004737 012530 call @#rcvbit ; r5 = char[6]
142 011430 103437 bcs 3$ ; carry set: end
143 011432 012703 000006 mov #6,r3
144 011436 004737 012120 call @#sl5or4 ; r4 |= (r5 << 6)
145 011442 004737 012530 call @#rcvbit ; r5 = char[7]
146 011446 103430 bcs 3$ ; carry set: end
147 011450 012703 000000 mov #0,r3
148 011454 004737 012120 call @#sl5or4 ; r4 |= (r5 << 0)
149
150 011460 010420 mov r4,(r0)+
151 011462 005201 inc r1
152
153 ; 3 words received. Interpret as RLE?
154 011464 005702 tst r2 ; if (!is_rle)
155 011466 001657 beq 1$ ; continue ;
156 ; last triplett was RLE block, not 3 data words
157 011470 162700 000006 sub #6,r0 ; remove last triplett from data buffer
158 011474 162701 000003 sub #3,r1
159 011500 010105 mov r1,r5 ; save r1=word count
160 011502 011004 mov (r0),r4 ; r4 = rle_count
161 011504 016001 000002 mov 2(r0),r1 ; rle pattern_1
162 011510 016002 000004 mov 4(r0),r2 ; rle pattern 2
163 011514 010403 mov r4,r3 ; count=rle_block_len. Must be even!
164 011516 004737 011136 call @#memset ; r0=ptr, r1 = value1, r2=value2, r3=count.
165 ; r0 is now at next unwritten buffer pos, r2=0
166 011522 010501 mov r5,r1 ; restore word count
167 011524 060401 add r4,r1 ; word count += rel_count
168 011526 000637 br 1$ ; } while(! aborted)
169
170 3$: ; end of transmission
171 ; r1 is actual word count, it could be
172 ; checked here against transmitted word count
173
174 ; checksum must be processed by caller
175 011530 000241 clc ; clear error flag
176
177 011532 000207 return
178
179
180
181
182
183 ; --------------------------------------------------
184 ; BLKXMT - block transmit
185 ; Get words from buffer and send as coded characters
186 ; Input:
187 ; rxbfwc = total size (len+checksum+opcode+params+data)
188 ; Result:
189 ; R0: buffer address (overwritten)
190 ; R1: word count (multiple of 3)
191
192 011534 rsp0en: .blkw 1 ; pointer to word after nd of block 0
193
194 blkxmt:
195 ; clear out fill words at buffer end
196 011536 013700 014000 mov @#xmwc,r0 ; wordcount without len
197 011542 005200 inc r0
198 011544 006300 asl r0 ; r0 = byte len of buffer without fill chars
199 011546 062700 014000 add #xmbffr,r0 ; r0 = bufferend
200 011552 010037 011534 mov r0,@#rsp0en ; save end of buffer
201 011556 005020 clr (r0)+ ; clear next 3 words
202 011560 005020 clr (r0)+
203 011562 005020 clr (r0)+
204
205 ; calculate and save checksum
206 011564 004737 012250 call @#calccs
207 011570 010037 014002 mov r0,@#xmcs
208
209 011574 012700 014000 mov #xmbffr,r0 ; transmit
210 011600 013701 014000 mov @#xmwc,r1
211 011604 062701 000002 add #2,r1 ; transmit word count, checksum, rxbuff
212
213 ; sende <cr>,{
214 011610 012705 000015 mov #15,r5
215 011614 004737 012476 call @#xmtchr ; send cr
216 011620 012705 000173 mov #'{,r5 ; 173
217 011624 004737 012476 call @#xmtchr ; send start character '{'
218
219 1$: ; do {
220
221 ; try rle compression of next data words
222 ; r5 = word after buffer end
223 011630 013705 011534 mov @#rsp0en,r5 ; r5 = ptr to word after data buffer end
224 011634 004737 012300 call @#encrle ; encode rle compression, data r0, count = r1, r5 = limit
225 011640 103406 bcs 2$ ; if not successful: r0, r1 unchanged, carry not set
226 ; rle compression successful.
227 ; r0 += blocklen-3 (last 3 word in buffer at rle end are used as buffer
228 ; for rle triplett.
229 ; triplett[r0] contains rle triplett.
230 ; r1 -= rle_count
231 011642 062701 000003 add #3,r1 ; // subroutine trpxmt decrements r1
232
233
234 ; rle triplett was written into data buffer at r0.
235 011646 012705 000174 mov #'|,r5
236 011652 004737 012476 call @#xmtchr ; transmit '|': rle indicator
237
238 2$: ; send next simple data triplett, or rle triplet
239
240 011656 004737 011702 call @#trpxmt ; transmit triple (= 3 words) from r0
241
242 3$: ; simple triplett or rle triplett send
243 011662 005701 tst r1
244 011664 003361 bgt 1$ ; } while(count > 0)
245
246 011666 012705 000175 mov #'},r5 ; 175
247 011672 004737 012476 call @#xmtchr ; send end character '}'
248
249 ; Wartepause, damit bei kommendem HALT der serial xmt buffer frei ist?
250 ; bewirkt receive timeout??
251 ; call @#wait64k ; wait ca. 64 millisek
252 011676 000241 clc ; clear error flag
253 011700 000207 return
254
255 ; --------------------------------------------------
256 ; trpxmt - TRiPle TransMT
257 ; encode and transmit next triple = 3 words from r0
258 ; globals: r0: dta ptr, inkremented += 3
259 ; r1: count, -= 3
260 ; r3,r4,r5 : changed, scratch
261 ;
262 trpxmt:
263 011702 012004 mov (r0)+,r4 ; r4 = word[0]
264 011704 005301 dec r1 ; count--
265 011706 012703 000012 mov #12,r3
266 011712 005005 clr r5
267 011714 004737 012170 call @#sr4or5 ; r5 = (r4 >> 10) & 0x3f
268 011720 004737 012466 call @#xmtbit ; send char[0]
269 011724 012703 000004 mov #4,r3
270 011730 005005 clr r5
271 011732 004737 012170 call @#sr4or5 ; r5 = (r4 >> 4) & 0x3f
272 011736 004737 012466 call @#xmtbit ; send char[1]
273 011742 012703 000002 mov #2,r3
274 011746 005005 clr r5
275 011750 004737 012220 call @#sl4or5 ; r5 = (r4 << 4) & 0x3f // set upper 4 bits of r5
276
277 011754 012004 mov (r0)+,r4 ; r4 = word[1]
278 011756 005301 dec r1 ; count--
279 011760 012703 000016 mov #16,r3
280 011764 004737 012170 call @#sr4or5 ; r5 |= (r4 >> 14) & 0x3f // set lower 2 bits of r5
281 011770 004737 012466 call @#xmtbit ; send char[2]
282 011774 012703 000010 mov #10,r3
283 012000 005005 clr r5
284 012002 004737 012170 call @#sr4or5 ; r5 = (r4 >> 8) & 0x3f
285 012006 004737 012466 call @#xmtbit ; send char[3]
286 012012 012703 000002 mov #2,r3
287 012016 005005 clr r5
288 012020 004737 012170 call @#sr4or5 ; r5 = (r4 >> 2) & 0x3f
289 012024 004737 012466 call @#xmtbit ; send char[4]
290 012030 012703 000004 mov #4,r3
291 012034 005005 clr r5
292 012036 004737 012220 call @#sl4or5 ; r5 = (r4 << 4) & 0x3f // set upper 2 bits of r5
293 012042 012004 mov (r0)+,r4 ; r4 = word[2]
294 012044 005301 dec r1 ; count--
295 012046 012703 000014 mov #14,r3
296 012052 004737 012170 call @#sr4or5 ; r5 |= (r4 >> 12) & 0x3f
297 012056 004737 012466 call @#xmtbit ; send char[5]
298 012062 012703 000006 mov #6,r3
299 012066 005005 clr r5
300 012070 004737 012170 call @#sr4or5 ; r5 = (r4 >> 6) & 0x3f
301 012074 004737 012466 call @#xmtbit ; send char[6]
302 012100 012703 000000 mov #0,r3
303 012104 005005 clr r5
304 012106 004737 012170 call @#sr4or5 ; r5 = r4 & 0x3f
305 012112 004737 012466 call @#xmtbit ; send char[7]
306 012116 000207 return
307
308
309 ; --------------------------------------------------
310 ; sr5or4
311 ; sl5or4
312 ; shift r5 by r3 left/right and OR to r4
313 ; r5 not changed
314 sl5or4:
315 012120 010546 mov r5,-(sp)
316 012122 005703 tst r3 ; while(r3) {
317 1$:
318 012124 001404 beq 2$
319 012126 000241 clc ; clr carry
320 012130 006105 rol r5 ; r5 <<=1
321 012132 005303 dec r3
322 012134 000773 br 1$ ; }
323 2$:
324 012136 050504 bis r5,r4 ; r4 |= r5
325 012140 012605 mov (sp)+,r5
326 012142 000207 return
327
328 sr5or4:
329 012144 010546 mov r5,-(sp)
330 012146 005703 tst r3 ; while(r3) {
331 1$:
332 012150 001404 beq 2$
333 012152 000241 clc ; clr carry
334 012154 006005 ror r5 ; r5 >>=1
335 012156 005303 dec r3
336 012160 000773 br 1$ ; }
337 2$:
338 012162 050504 bis r5,r4 ; r4 |= r5
339 012164 012605 mov (sp)+,r5
340 012166 000207 return
341
342
343 ; --------------------------------------------------
344 ; sr4or5
345 ; sl4or5
346 ; shift r4 by r3 left/right and OR bits 5..0 to r5
347 ; r4 not changed
348 sr4or5:
349 012170 010446 mov r4,-(sp)
350 012172 005703 tst r3 ; while(r3) {
351 1$:
352 012174 001404 beq 2$
353 012176 000241 clc ; clr carry
354 012200 006004 ror r4 ; r4 >>= r3
355 012202 005303 dec r3
356 012204 000773 br 1$ ; }
357 2$:
358 012206 042704 000300 bic #300,r4
359 012212 050405 bis r4,r5 ; r5 |= (r4 & 0x3f)
360 012214 012604 mov (sp)+,r4
361 012216 000207 return
362
363 sl4or5:
364 012220 010446 mov r4,-(sp)
365 012222 005703 tst r3 ; while(r3) {
366 012224 001404 1$: beq 2$
367 012226 000241 clc ; clr carry
368 012230 006104 rol r4 ; r4 <<= r3
369 012232 005303 dec r3
370 012234 000773 br 1$ ; }
371 2$:
372 012236 042704 000300 bic #300,r4
373 012242 050405 bis r4,r5 ; r5 |= (r4 & 0x3f)
374 012244 012604 mov (sp)+,r4
375 012246 000207 return
376
377
378
379 ; ---------------------------------------------------
380 ; calccs
381 ; calculate sum of all data words in buffer "rxbuff"
382 ; (without checksum itself)
383 ; and return in r0
384 ; changes r0, r1, r2
385 calccs:
386 012250 005000 clr r0
387 012252 012702 014004 mov #xmbuff,r2 ; r2 point to second word of buffer, after checksum
388 012256 013701 014000 mov @#xmwc,r1 ; r1 = word counter, includes checksum
389 012262 005301 dec r1
390 012264 001403 beq 9$ ; r1 == 0: exit
391 1$:
392 012266 062200 add (r2)+,r0 ;
393 012270 005301 dec r1
394 012272 001375 bne 1$ ; loop while r1 > 0
395 9$:
396 012274 000207 return
397
398
399 ; ---------------------------------------------------------
400 ; encrle
401 ; try to ENCode data at r0 as RLE block
402 ; r0: pointer into buffer
403 ; r1: word count
404 ; r5: pointer to word after buffer end
405 ; return
406 ; carry clear: compression succesfull
407 ; r0 points to
408 ; rle triplett: <repeat> <pattern_1> <pattern_2> is written
409 ; directly before the next uncompressable word in data buffer:
410 ; r0 points to rle triplett.
411 ; r1 is decremented by rle block len
412 ; carry set : compression unsuccessful:
413 ; less than 3 equal data words.
414 ; data and r0, r1 unchanged
415 ;
416 ; Since buffer data is overwritten with rle triplett,
417 ; rle must find at least 4 equal data words.
418 ; original buffer w w w
419 ; Over written with repeat pattern_1 pattern_2
420 012276 encrl1: .blkw 1 ; backup r0
421
422 encrle: ; encode rle compression, data r0, count = r1
423 ; sec ; disable RLE encoding
424 ; return
425
426 ; limit: rle block len max 256
427 012300 010037 012276 mov r0,@#encrl1 ; backup original r0
428 012304 010002 mov r0,r2 ; r2 = data ptr
429 012306 010004 mov r0,r4 ; r4 = ptr to repeated pattern
430 012310 012703 000002 mov #2,r3 ; block_len
431 012314 062702 000004 add #4,r2 ; skip to word behind pattern
432 ; loop, until
433 1$:
434 ; r2 still two words before buffer end?
435 012320 010200 mov r2,r0
436 012322 062700 000002 add #2,r0
437 012326 020005 cmp r0,r5 ; if (r2+1) < r5 then ....
438 012330 103017 bhis 2$ ; stop, if r2 reached end of buffer
439
440 ; are the 2 words at r2 identical to the pattern at r4 ?
441 012332 021214 cmp (r2),(r4)
442 012334 001015 bne 2$ ; not identical
443 012336 026264 000002 000002 cmp 2(r2),2(r4)
444 012344 001011 bne 2$ ; not identical
445 012346 060227 000004 add r2,#4 ; skip compressed words
446
447 012352 062703 000002 add #2,r3 ; inc block_len by 2 words
448 012356 062702 000004 add #4,r2 ; inc data pointer by 2 words
449 ; limit len of rle blocks. PC CPU must decompress whole block within
450 ; one character receive time. PD11 CPU can 32 loops, modern x86 surely > 1000
451 012362 020327 000377 cmp r3,#377 ; more than 256 encoded words?
452 012366 003754 ble 1$ ; no: try again
453
454 2$: ; end of compression loop
455 012370 020327 000004 cmp r3,#4
456 012374 003414 ble 4$ ; to few data compressed: compression failure
457
458 ; compression success:
459 ; overwrite data buffer with rle triplett: <block_len> <pattern_1> <pattern_2>
460 012376 010200 mov r2,r0
461 012400 162700 000006 sub #6,r0 ; point r0 to triplet directly before end of block in data buffer
462 ; sub #6: triplett len
463 012404 160301 sub r3,r1 ;r1 = words left in buffer
464
465 012406 010310 mov r3,(r0) ; repeat count
466 012410 011460 000002 mov (r4),2(r0) ; pattern_1
467 012414 016460 000002 000004 mov 2(r4),4(r0) ; pattern_2
468 012422 000241 clc ; clear carry
469 012424 000403 br 9$
470 4$: ;compression failure. restore r0
471 012426 013700 012276 mov @#encrl1,r0 ; restore original r0
472 012432 000261 sec ; set carry
473 9$: ; exit
474 012434 000207 return
475
476
477 ; ----------------------------------------
478 ; doecho - block transfer test
479 ; empfang, bufferwords um 1 erhöhen, senden
480 ; works on block 0, which has format <len> <data ...>
481 ; before
482 doecho:
483 ; called by framework, buffer is received and checked
484 012436 013703 000122 mov @#req0dt,r3 ; buffer base of block 0
485 012442 013701 000120 mov @#req0wc,r1 ; len of block 0
486 012446 011101 mov (r1),r1 ; req0wc is address of len
487 012450 001403 beq 9$ ; buffer len = 0?: exit
488 ; complement every word in buffer (checksum is recalculated)
489 1$:
490 012452 005123 com (r3)+
491 012454 005301 dec r1
492 012456 001375 bne 1$
493 9$:
494 ; response buffer = request buffer
495 012460 000241 clc ; no error.
496 ; r3 = point to word after result buffer
497 012462 000137 010272 jmp @#doresp
498
499
500 ; ---------------------------------------------------
501 ; Select serial low level I/O driver
502 .include pdp11gui_serialio_dl11.mac
1 .title serialio_dl11
2
3 ; Low level serial I/O for DEC DL11 at standard address.
4 ; To be included by "pdp11gui_serialxfer.mac"
5 ; Implements the functions:
6 ; xmtbit
7 ; xmtchr
8 ; rcvbit
9 ; rcvchr
10 ;
11
12 177560 kbs = 177560
13
14 ; --------------------------------------------------
15 ; xmtbit: transmit 6 bits in r5
16 ; xmtchr: transmit character in r5
17 xmtbit:
18 ; ; send CR every 64 characters
19 ; mov r1,-(sp) ; save r1
20 ; bic #177677,r1 ; bit #100 set?
21 ; bne 0$
22 ; mov r5,-(sp)
23 ; mov #15,r5
24 ; call @#xmtchr
25 ; mov (sp)+,r5
26 ;0$:
27 ; mov (sp)+,r1 ; restore r1
28
29 012466 042705 000300 bic #300,r5 ; r5 &= 0x3f
30 012472 062705 000040 add #40,r5 ; offset 0x20 = octal 40
31 xmtchr:
32 012476 010046 mov r0,-(sp)
33 012500 012700 177560 mov #kbs,r0 ; r0 points to serial port #0
34
35 1$:
36 012504 105760 000004 tstb 4(r0) ; ready to transmit?
37 012510 100375 bpl 1$ ; no, loop
38 012512 110560 000006 movb r5,6(r0) ; transmit data
39 ; wait until it is out (so char is out even if next char is HALT)
40 2$:
41 012516 105760 000004 tstb 4(r0) ; ready to transmit?
42 012522 100375 bpl 2$ ; no, loop
43
44 012524 012600 mov (sp)+,r0
45 012526 000207 return
46
47 ; --------------------------------------------------
48 ; rcvbit: 6 bit code empfangen
49 ; carry set: END OF BLOCK empfangen '}', test with "bcs"
50 ; overflow set: REPEAT empfangen '|' , test with "bvs"
51 ; delay char '~' is implicitely ignored
52 ; rcvchr: character empfangen
53 ; modifies only R5!
54 rcvbit:
55 1$:
56 012530 004737 012612 call @#rcvchr
57 012534 000242 clv ; clear overflow
58 012536 122705 000175 cmpb #'},r5 ; '}' = 175
59 012542 001417 beq 2$
60 012544 122705 000174 cmpb #'|,r5 ; '|' = 174
61 012550 001416 beq 3$
62 012552 120527 000040 cmpb r5,#40 ; char below 0x20?
63 012556 103764 blo 1$ ; yes: receive next char
64 012560 120527 000140 cmpb r5,#140 ; other chars above 0x60 (delay)?
65 012564 103361 bhis 1$ ; ignore
66 ; mov r5,(r2)+ ; to diag buffer
67 012566 162705 000040 sub #40,r5 ; subtract offset
68 012572 042705 000300 bic #300,r5 ; r5 &= 0x3f
69 012576 000241 clc ; clr carry = valid char
70 012600 000207 return
71 2$:
72 012602 000261 sec ; set carry = end of block
73 012604 000207 return
74 3$: ; set Overflow
75 012606 000262 sev
76 012610 000207 return
77
78 ; modifies only R5!
79 ; halts with error if overrun
80 rcvchr:
81 012612 010046 mov r0,-(sp)
82 012614 012700 177560 mov #kbs, r0 ; r0 points to serial port #0
83 ; TEST: r2 zeigt auf byte aus testdata
84 ; clr r5 ; TEST
85 ; movb (r2),r5 ; TEST
86 ; inc r2 ; TEST
87 ; br 2$ ; TEST
88 012620 005760 000002 tst 2(r0) ; test bit 15 = error
89 012624 100005 bpl 1$ ; no error
90 012626 012705 000015 mov #15,r5 ; error location
91 012632 016005 000002 mov 2(r0),r5 ; receiver = error
92 ; An error in the serial interface means: loss of contact.
93 ; So return of error result is impossible.
94 ; Use the only remaining option is:
95 012636 000000 halt
96 1$:
97 012640 105710 tstb (r0) ; character received?
98 012642 100376 bpl 1$ ; no, loop
99 012644 116005 000002 movb 2(r0),r5 ; read rcv buffer
100 2$:
101
102 012650 042705 177600 bic #177600,r5 ; mask to 7 bits
103 012654 012600 mov (sp)+,r0
104 012656 000207 return
105
105
503 ; .include pdp11gui_serialio_k8060.mac
504
505
506
507 ; ---------------------------------------------------
508 ; rxbuff - receive transmit buffer
509 ; - data part are remaining words.
510
511 ; debugging: buffer immer an der selben adresse
512 014000 . = 014000
513
514 ; ------- transmission buffer header ---------------------------
515 014000 xmbffr = . ; base for buffer frame
516 014000 xmwc: .blkw 1 ; transmission wordcount: exact wordcount, excluding len itself and checksum, but including opcode
517 014002 xmcs: .blkw 1 ; transmission checksumbuffer-2: buffer checksum. checksum of all data words in rxbuff
518 014004 xmbuff = . ; base for buffer payload
519 ; buffer is max 2 blocks: 1st = 8 parameters, 2nd = 16kwords drive data long
520 ; Buffer is located at end of code, can grow up tu 48kbyte boundary
521 ; ------- transmission buffer data ---------------------------
522 014004 .blkw 10 ; approx space for opcode + parameters, maybe more or less
523 014024 .blkw 40000
524 ; data part of buffer for 16 kWords = 32 kBytes
525 ; addr is approx 13000
526 ; if machine has only 32kBytes, mem end is at word addr 40000,
527 ; and buffer can keep 040000-013000 = 025000 = 10752d words
528 114024 xmbufe = . ; End address
529 114024 .blkw 10 ; extra space, to fill triplets
530
530
260
261 .end
261
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment