-
Notifications
You must be signed in to change notification settings - Fork 1
/
mssave.asm
413 lines (378 loc) · 14.3 KB
/
mssave.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
;
; Slowdos Source Code
;
;
; $Id: mssave.asm,v 1.2 2003/06/15 21:02:12 dom Exp $
; $Author: dom $
; $Date: 2003/06/15 21:02:12 $
;
; Routines concerned with saving files from disc
MODULE save
INCLUDE "slowdos.def"
INCLUDE "syntaxdefs.def"
;; Routines that are external to this module
EXTERN r_hxfer
EXTERN uftofin
EXTERN ckchar
EXTERN errorn
EXTERN discan
EXTERN cksub
EXTERN seccle
EXTERN wrnxft
EXTERN link_clusters
EXTERN getsec
EXTERN sros
EXTERN swos
EXTERN file_signature
EXTERN mslog
EXTERN clfil0
EXTERN wrcopy
EXTERN rdini1
EXTERN rdcop1
EXTERN pdconv
EXTERN getdiroffset
EXTERN wrifat
;; Labels that we export
PUBLIC hook_wropen
PUBLIC wropen
PUBLIC wrblok
PUBLIC wrbyte
PUBLIC wrinit
PUBLIC wrclos
wrflen: defw 0,0 ; VARIABLE - writing file length
wrdsec: defw 0 ; VARIABLE - sector for first free dir slot
wrdpos: defb 0 ; VARIABLE - directory position for free slot
wrclco: defb 0 ; VARIABLE - sectors to go in cluster
wrtogo: defw 0 ; VARIABLE - bytes left in write sector
wrsepo: defw 0 ; VARIABLE - current position in sector
wrclus: defw 0 ; VARIABLE - current writing cluster
wrclse: defw 0 ; VARIABLE - current writing sector
hook_wropen:
call r_hxfer
ld hl,(ufia+16)
ld (wrflen),hl
ld hl,0
ld (wrflen+2),hl
ld hl,flags
res 5,(hl)
ld a,(ufia+15)
cp 5
jr nz,wropen
set 5,(hl)
;; Fall into wropen
; Open a file to be write
; Entry: ix=ufia
wropen: call uftofin ; Copy ufia to filen, exit hl = ufia+2
call ckchar ; Check filename and uppercase it
jp c,error_filename
ld hl,flags3
bit 1,(hl) ; Writing to a .TAP file?
jp nz,wropetap ; If so, then go there
call discan ; Scan for the file on disc
ld hl,(dirsec) ; Save sector containing first free dir entry
ld (wrdsec),hl
jr nc,wrope1 ; If filename doesn't exist then dont error
call errorn
defb 48 ;file already exists
wrope1: ld a,(frepos) ; Get the free directory slot
and a
jr nz,wrope2 ; We have a free slot
call cksub ; Check to see if we're in subdirectory
jr z,error_dirfull ; We're not in subdir, so we need to error
; We're in a subdirectory, try to allocate more space
call seccle ; Clear the write sector
call wrnxft ; Find a free cluster, de = new cluster
jp nz,dfull ; No free cluster so error
ld c,e ; Move new cluster into bc
ld b,d
ld de,(curfat) ; Pick up the last cluster of the subdirectory
; we have access to this since we searched the
; directory for the filename
push bc ; Save new cluster
call link_clusters ; Link the two clusters together
pop de ; Get new cluster back
ld bc,0FFFh ; Set next cluster to be "end of chain"
push de ; Save new cluster
call link_clusters ; Terminate the cluster chain
pop de ; Get new cluster back
call getsec ; Convert to DOS sector number
ld (wrdsec),de ; Save it for later
ld a,(diskif+13) ; Sectors in a cluster
ld b,a
.blank_subdir_lp
push bc
push de
call swos ; Write a blank directory sector
pop de
pop bc
inc de ; BUG!! Go to next sector in cluster
djnz blank_subdir_lp
ld a,1
jr wrope2
error_dirfull:
call errorn ; No space left in diretory
defb 51
; Clear the directory setup
; Entry: a = free directory slot
wrope2: ld (wrdpos),a ; Save the directory slot
xor a ; Blank out our temporary directory entry
ld b,32
ld hl,dirmse
wrope3: ld (hl),a
inc hl
djnz wrope3
call seccle ; Clear the write sector
push ix ; ix = ufia
pop hl ; Copy the filename to our directory entry
inc hl
inc hl
ld de,dirmse
ld c,8 ; We know that b = 0 from seccle
ldir
inc hl ; Now copy extension and file type
ld c,4 ; We know that b = 0
ldir
call wnfse5 ; Set (wrsepo),wrisec; (wrtogo),512
ld a,(diskif+13) ; Number of sectors per cluster
ld (wrclco),a ; And save it
ld hl,flags
bit 5,(hl) ; Check to see if we want a header or not
jr nz,wrope5 ; If we don't skip over header writing
ld hl,file_signature ; Copy over the +3DOS file header
ld de,wrisec
ld bc,11
ldir
ld l,(ix+16) ; Pick up file length
ld h,(ix+17)
ld c,128 ; We know b = 0
and a
adc hl,bc
ex af,af' ; Save overflow flag
ex de,hl ; de = file length, hl = where to write filelength
ld (hl),e ; Write file length into
inc hl
ld (hl),d
inc hl
ex de,hl ; de = where to write
ld hl,0
ld c,0 ; We know b = 0
ex af,af' ; Get overflow back
adc hl,bc ; Add in the overflow
ex de,hl ; de = top word of file length, hl = write place
ld (hl),e
inc hl
ld (hl),d
inc hl
ex de,hl
push ix ; ix = ufia
pop hl
ld c,15 ; We know b = 0. Move to fileinfo section of ufia
add hl,bc
ld c,7 ; We know b = 0
ldir ; Copy the file header into the sector
ld hl,wrisec ; Now calculate the header checksum
ld b,127
xor a
wrope4: add a,(hl)
inc hl
djnz wrope4
ld (hl),a ; And write it
inc hl
ld (wrsepo),hl ; Save first writing position
ld hl,384 ; And how much length is still available
ld (wrtogo),hl
wrope5: ld hl,(wrsepo) ; Set up the file length byte counter
ld de,wrisec ; See how much we've written so far
and a
sbc hl,de
ld (wrflen),hl ; And save it
ld hl,0
ld (wrflen+2),hl
call wrnxft ; Try to get a free cluster
jr z,wrope6 ; We succeeded
dfull: call errorn
defb 50 ;Disc full
wrope6: ld (dirmse+26),de ; Save the first cluster into the directory entry
ld (wrclus),de ; Set up the current cluster
call getsec ; Convert to DOS sector
ld (wrclse),de ; And save that too
ret
; We're writing to a .TAP file. The .TAP file is already open
; Entry: ix = ufia
wropetap: push ix ; Stack the ufia
call mslog ; Ensure that this is a MSDOS disc
pop ix ; Get the ufia back
ld hl,19 ; Length of header
call wropeta9 ; Write word to file
ld h,0 ; .TAP filetype
call wropeta8 ; Write byte and set parity
ld a,(ix+15)
call wrbyte ; Write a byte to disc
ld hl,intafil ; A temporary buffer
ld b,20 ; Length of buffer
call clfil0 ; Clear it, returns hl = intafil
push hl
call pdconv ; Convert filename in ufia and place in intafil
pop hl ;hl=intafil
ld b,10 ; Length of filename
call wropeta7 ; Write filename to disc
push ix ; Get ufia into hl
pop hl
ld bc,16 ; Step to header information
add hl,bc
ld b,6 ; Header to write is 6 bytes long
call wropeta7 ; And so write this to disc
ld a,(parity+1) ; Get the parity byte
call wrbyte ; And write it to disc
ld l,(ix+16) ; Get file length
ld h,(ix+17)
inc hl ; Cover for parity
inc hl ; Cover for .TAP filetype
call wropeta9 ; Write word
ld h,255 ; .TAP filetype
jp wropeta8 ; Write filetype and initialise parity
; Write a stream of bytes to disc
; Entry: hl = buffer
; b = number of bytes to write
wropeta7: ld a,(hl)
call wrbyte
inc hl
djnz wropeta7
ret
; Write the .TAP filetype out. also initialises parity
; Entry: h = .TAP filetype
wropeta8: xor a
ld (parity+1),a
ld a,h
jp wrbyte
; Write a 16 bit number to disc
; Entry: hl = 16 bit number
wropeta9: ld a,l
call wrbyte
ld a,h
jp wrbyte
;Write a string of bytes
;Entry: de=addr
; bc=length
wrblok: call wrinit ; Copy the write code to somewhere in printer buf
wrblo1: ld a,b ; Check for number of bytes left
or c
ret z ; We're done
call wrcopy ; Pick up the byte
call wrbyte ; Write it to DOS
inc de
dec bc
jr wrblo1
;Changing these routines to reference the read ones...
; Copy the code snippet for picking up values from BASIC memory
; to 23420
wrinit: ld hl,wrcopr ; The routine we use
jp rdini1 ; Copy it
wrcopr: out (c),l
ld a,(de)
out (c),h
jp rdcop1
;Write a byte to the file
;Entry: a=byte
wrbyte: push de ; Save registers that we use
push bc
push hl
push af ; Save the byte we want to write
ld hl,(wrtogo) ; Bytes left in the sector
ld a,h
or l
call z,wnfsec ; Get the next sector
wrbyt1: pop af ; Get the byte back
ld hl,(wrsepo) ; Position within sector
ld (hl),a ; Store the byte
inc hl ; Increment sector position
ld (wrsepo),hl
ld hl,(wrtogo) ; Decrement amount of space left in sector
dec hl
ld (wrtogo),hl
ld h,a ; Update the parity
parity: ld a,0
xor h
ld (parity+1),a
ld hl,(wrflen) ; Increment the file length
inc hl
ld (wrflen),hl
ld a,h ; Check for overflow
or l
jr nz,wrbyt2
ld hl,(wrflen+2) ; If overflowed increment high word
inc hl
ld (wrflen+2),hl
wrbyt2: pop hl ; Restore registers
pop bc
pop de
ret
;Find the next file sector (writing)
wnfsec: ld hl,wrclco ; Decrement number of sectors in cluster
dec (hl)
jr z,wnfse2 ; Jump if we reached the end of the cluster
wnfse1: ld de,(wrclse) ; Pick up the current sector
push de ; Stack it
call swos ; Write sector to disc
pop de ; Get sector back
inc de ; Increment sector number
wnfse6: ld (wrclse),de ; Save it
wnfse5: ld hl,wrisec ; Set up writing variables
ld (wrsepo),hl
ld hl,512
ld (wrtogo),hl
ret
; Completed our cluster, get a new one
wnfse2: ld de,(wrclse) ; Write out the current sector
call swos
ld de,(wrclus) ; Pick up the current cluster
ld bc,1 ; A fake cluster
push de ; Save current cluster
call link_clusters ; Fake lock so we don't get the same cluster again
call wrnxft ; Get a new cluster
jp nz,dfull ; No new cluster, disc full
wnfse3: ld (wrclus),de ; Save the new cluster
ld c,e ; Get new cluster into de
ld b,d
pop de ; Get back the old cluster
push bc ; Stack the new cluster
call link_clusters ; Link the two together
pop de ; Get back the new cluster
call getsec ; Convert to DOS sector
ld a,(diskif+13) ; Number of sectors in cluster
ld (wrclco),a ; Save them
jr wnfse6 ; Set up sector number and writing variables
;Close a file being written to the DOS disc
wrclos: ld hl,flags3
bit 1,(hl) ; Check for writing to a .TAP file
jr z,wrclos0 ; Not writing to .TAP file
ld a,(parity+1) ; Pick up the parity byte
call wrbyte ; And write it to disc
jp wrifat ; Save the FAT to disc (not too sure why!)
wrclos0: ld bc,0FFFh ; End of cluster chain marker
ld de,(wrclus) ; Current cluster
call link_clusters ; Link together
ld de,(wrclse) ; Pick up last cluster
call swos ; And write it to disc
ld de,(wrdsec) ; Get directory cluster
call sros ; Read it in
ld hl,sector ; Copy the directory from read to write memory
ld de,wrisec
ld bc,512
ldir
ld hl,(wrflen) ; Update dir entry with the real file length
ld (dirmse+28),hl
ld hl,(wrflen+2)
ld (dirmse+30),hl
ld a,(wrdpos) ; Pick up free directory entry indicator
dec a ; Decrement it
call getdiroffset ; And pick up offset
ld de,wrisec ; Add to start of sector
add hl,de
ld de,dirmse ; Copy our directory entry into the dir sector
ex de,hl
ld bc,32
ldir
ld de,(wrdsec) ; And write directory sector to disc
call swos
jp wrifat ; Write the updated FAT table to disc