Subversion Repositories Spectranet

[/] [trunk/] [modules/] [basext/] [loader.asm] - Blame information for rev 255

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 221 winston
;The MIT License
2
;
3
;Copyright (c) 2009 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22
 
23
; TAP load/save functions
24
;------------------------------------------------------------------------
25
; F_tbas_readrawfile
26
; Reads a raw file off the filesystem, without looking to see if it has
27
; a header.
28
; Parameters: HL = pointer to filename
29
;             DE = memory location to place the result
30
; Returns with carry set and A=error number on error.
31
F_tbas_readrawfile
32
        push de                 ; save pointer
33
        ld e, O_RDONLY          ; LOADing is read only
34
        ld d, 0x00              ; No file flags
35
        call OPEN               ; Filename pointer is already in HL
36
        pop de
37
        ret c
38 235 winston
        ld (v_vfs_curfd), a     ; save the filehandle
39 221 winston
.readloop
40 235 winston
        ld a, (v_vfs_curfd)     ; restore filehandle
41 221 winston
        ld bc, 512              ; read max 512 bytes
42
        call READ
43
        jr nc, .readloop        ; keep going until nothing more can be read
44
        cp EOF                  ; End of file?
45
        jr nz, .failed          ; No - something went wrong
46 235 winston
        ld a, (v_vfs_curfd)     ; Close the file
47 221 winston
        jp VCLOSE
48
.failed
49
        push af                 ; preserve return code
50 235 winston
        ld a, (v_vfs_curfd)
51 221 winston
        call VCLOSE             ; close the file
52
        pop af                  ; but let the earlier return code have
53
        scf                     ; precedence over any errors that close throws
54
        ret                     ; up.
55
 
56
;--------------------------------------------------------------------------
57
; F_tbas_loader
58
; The BASIC LOAD command. Opens the named file, reads the header, then
59
; decides how to load the file from the header information contained.
60
; Parameters    HL = pointer to filename
61
;               DE = memory address to load to for CODE files
62
;               A  = type to expect
63
F_tbas_loader
64
        ld (INTERPWKSPC+21), a  ; save the type parameter
65
        ld (v_desave), de       ; save address
66
        ld e, O_RDONLY          ; Open file read only
67
        ld d, 0x00              ; with no flags
68
        call OPEN
69
        ret c                   ; return if the open operation fails
70 235 winston
        ld (v_vfs_curfd), a     ; save the returned filehandle
71 221 winston
        ld de, INTERPWKSPC      ; set destination pointer to workspace
72
        call F_tbas_getheader   ; Fetch the header
73
        jp c, J_cleanuperror    ; on error, clean up and return
74
        ld ix, INTERPWKSPC+3    ; start of "tape" header in a TAP file
75
        ld a, (INTERPWKSPC+21)  ; get the type byte
76
        cp (ix+0)               ; check that it's the right type
77
        jr nz, .wrongtype
78
        and a                   ; type 0? BASIC program
79
        jr nz, .testcode        ; No, test for CODE
80
        call F_tbas_loadbasic   ; Load a BASIC program
81
        jp c, J_cleanuperror    ; handle errors
82
.cleanup
83 235 winston
        ld a, (v_vfs_curfd)
84 221 winston
        call VCLOSE
85
        ret
86
.testcode
87
        cp 0x03                 ; type CODE
88
        jr nz, .unktype         ; not a type we know
89
        ld de, (INTERPWKSPC+OFFSET_PARAM1)      ; get the start address
90
        ld bc, (INTERPWKSPC+OFFSET_LENGTH)      ; and the expected length
91 255 winston
        call F_tbas_loadblock   ; and load the TAP block
92
        jr .cleanup
93 221 winston
.wrongtype
94
        ; TODO: handle CODE files
95
        ld a, TBADTYPE
96
        scf
97
        ret
98
.unktype
99
        ld a, TUNKTYPE
100
        scf
101
        ret
102
 
103
;--------------------------------------------------------------------------
104
; F_tbas_getheader
105 235 winston
; Reads a block header into memory from the file handle in v_vfs_curfd.
106 221 winston
; Spectranet files are the same format as TAP files, so each block has
107
; a 2 byte length, followed by data. This function reads the length
108
; and places the complete header into the memory address specified
109
; by DE. On error, it returns with carry set and A containing the error
110
; number. On success, the file type is returned in A.
111
F_tbas_getheader
112
        push de                 ; save pointer
113 235 winston
        ld a, (v_vfs_curfd)     ; get the current file descriptor
114 221 winston
        ld bc, TNFS_HDR_LEN     ; 19 bytes (length + ZX header block)
115
        call READ
116
        pop hl                  ; get the pointer back but in hl
117
        ret c                   ; error occurred in read
118
        ld a, (hl)
119
        cp 0x13                 ; first byte must be 0x13
120
        jr nz, .wronglen
121
        inc hl
122
        ld a, (hl)              ; second byte must be 0x00
123
        and a
124
        jr nz, .wronglen
125
        inc hl
126
        ld a, (hl)              ; type must be 0x00 - "header"
127
        and a
128
        jr nz, .wrongblktype
129
        inc hl
130
        ld a, (hl)              ; return the type byte
131
        ret                     ; TODO: Check the checksum etc.
132
.wronglen
133
        ld a, TBADLENGTH
134
        scf
135
        ret
136
.wrongblktype
137
        ld a, TBADTYPE
138
        scf
139
        ret
140
 
141
;----------------------------------------------------------------------------
142
; F_tbas_loadblock
143
; Loads a TAP block
144
; Parameters: DE = where to copy in memory
145
;             BC = expected length
146 235 winston
;             v_vfs_curfd contains the file descriptor
147 221 winston
F_tbas_loadblock
148
        push de                 ; save destination ptr
149
        push bc                 ; save length
150
        ld de, INTERPWKSPC      ; get the length from TAP block
151
        ld bc, 3                ; 3 bytes long (length + flags)
152 235 winston
        ld a, (v_vfs_curfd)
153 221 winston
        call READ               ; read the TAP header
154
        pop bc                  ; get the length
155
        pop de                  ; and destination pointer
156
        ret c                   ; and leave on read error
157
        ld hl, (INTERPWKSPC)    ; sanity check TAP length
158
        dec hl                  ; which should be length in ZX header + 2
159
        dec hl
160
        sbc hl, bc              ; zero flag is set if length is correct
161
        jr nz, .lengtherr
162
        ld h, b                 ; copy length remaining into HL
163
        ld l, c
164
.loadloop
165 235 winston
        ld a, (v_vfs_curfd)     ; get file descriptor
166 221 winston
        push hl                 ; save length remaining
167
        call READ
168
        pop hl                  ; get current length back into HL
169
        ret c                   ; bale out if we've got an error condition
170
        sbc hl, bc              ; decrement length remaining
171
        ld b, h                 ; and update data request
172
        ld c, l
173
        jr nz, .loadloop        ; continue until 0 bytes left
174
        ret
175
.lengtherr
176
        ld a, TMISMCHLENGTH     ; Length of data block doesn't match header
177
        scf
178
        ret
179
 
180
;----------------------------------------------------------------------------
181
; F_tbas_loadbasic
182
; Load a program written in BASIC.
183
; Parameters: IX points to the "tape" header (i.e. TAP block + 2)
184 235 winston
;             v_vfs_curfd contains the file descriptor
185 221 winston
; Much of this is modelled on the ZX ROM loader.
186
F_tbas_loadbasic
187
        ld hl, (ZX_E_LINE)      ; End marker of current variables area
188
        ld de, (ZX_PROG)        ; Destination address
189
        dec hl
190
        ld (v_ixsave), ix       ; save IX
191
        ld c, (ix+0x0b)         ; Length argument in "tape" header
192
        ld b, (ix+0x0c)
193
        push bc                 ; save the length
194
        rst CALLBAS
195
        defw ZX_RECLAIM_1       ; Reclaim present program/vars
196
        pop bc
197
        push hl                 ; Save program area pointer
198
        push bc                 ; and length
199
        rst CALLBAS
200
        defw ZX_MAKE_ROOM       ; Call MAKE_ROOM to make speace for program
201
        ld ix, (v_ixsave)       ; restore IX
202
        inc hl                  ; The system variable VARS
203
        ld c, (ix+0x0f)         ; needs to be set.
204
        ld b, (ix+0x10)
205
        add hl, bc
206
        ld (ZX_VARS), hl
207 225 winston
        ld h, (ix+0x0e)         ; Check for LINE number
208
        ld a, h
209
        and 0xC0
210
        jr nz, .loadblock       ; No line number - skip to loader
211
        ld l, (ix+0x0d)         ; HL = line number
212
        ld (ZX_NEWPPC), hl      ; set line number to jump to
213
        xor a
214
        ld (ZX_NSPPC), a        ; Statement number 0
215
 
216
.loadblock
217 221 winston
        pop bc                  ; fetch the length
218
        pop de                  ; fetch the start
219
 
220
        jp F_tbas_loadblock     ; load the block
221
 
222
;--------------------------------------------------------------------------
223
; F_tbas_mktapheader
224
; Create a TAP header with filename and type.
225
; Parameters            A = type
226
;                       DE = filename
227
;                       BC = filename length
228
F_tbas_mktapheader
229
        push de
230
        push bc
231
        ; Create the header
232
        ld hl, 0x13             ; length of header block in TAP format
233
        ld (INTERPWKSPC), hl
234
        ld (INTERPWKSPC+3), a   ; save the type byte
235
        xor a
236
        ld (INTERPWKSPC+2), a   ; is a header block, set to 0x00
237
        ld a, 10                ; > 10 chars in the filename?
238
        cp b
239
        jr nc, .continue
240
        ld c, 10                ; copy max of 10
241
.continue
242
        ld b, c                 ; prepare to copy string
243
        ld hl, INTERPWKSPC+4
244
.loop
245
        ld a, (de)              ; copy the string
246
        ld (hl), a
247
        inc de
248
        inc hl
249
        djnz .loop
250
        ld a, 10                ; find remaining bytes
251
        sub c
252
        jr z, .exit             ; nothing to do!
253
        ld b, a                 ; A now contains the loop count
254
.spaces
255
        ld (hl), 0x20           ; fill the rest with spaces
256
        inc hl
257
        djnz .spaces
258
.exit
259
        pop bc
260
        pop de
261
        ld hl, 0                ; make the parameters default to 0
262
        ld (INTERPWKSPC+OFFSET_PARAM1), hl
263
        ld h, 0x80              ; the default when no param2
264
        ld (INTERPWKSPC+OFFSET_PARAM2), hl
265
        ret
266
 
267
;---------------------------------------------------------------------------
268
; F_tbas_writefile
269
; Writes a file from a %SAVE command. The header must be complete and stored
270
; in INTERPWKSPC.
271
; Parameters:           DE = pointer to filename
272
;                       BC = length of filename (i.e. from ZX_STK_FETCH)
273
; On error returns with carry set and A = errno.
274
F_tbas_writefile
275
        ld hl, INTERPWKSPC+21   ; convert filename to a C string
276
        call F_basstrcpy
277
 
278
        ld hl, INTERPWKSPC+21   ; Open the file for write (the full C string
279
        ld e, O_WRONLY          ; for the filename is in mem after the header)
280
        ld d, O_CREAT           ; flags = CREATE
281
        call OPEN               ; Open the file.
282
        ret c
283 235 winston
        ld (v_vfs_curfd), a     ; store the file descriptor
284 221 winston
 
285
        ld hl, INTERPWKSPC+OFFSET_TYPE  ; checksum the header
286
        ld bc, ZX_HEADERLEN
287
        xor a                   ; start with 0x00 for header block
288
        call F_tbas_mkchecksum
289
        ld (INTERPWKSPC+OFFSET_CHKSUM), a
290
        ld hl, INTERPWKSPC      ; write the 21 byte TAP block
291 235 winston
        ld a, (v_vfs_curfd)
292 221 winston
        ld bc, 21
293
        call WRITE
294
        jp c, J_cleanuperror
295
 
296
        ld hl, (INTERPWKSPC+OFFSET_LENGTH)
297
        inc hl                  ; add 2 for the 0xFF data block byte
298
        inc hl                  ; and check byte
299
        ld (INTERPWKSPC), hl    ; create TAP header and ZX data block
300
        ld a, 0xFF              ; which consists of a 16 bit length
301
        ld (INTERPWKSPC+2), a   ; followed by 0xFF
302 235 winston
        ld a, (v_vfs_curfd)
303 221 winston
        ld hl, INTERPWKSPC
304
        ld bc, 3
305
 
306
        call WRITE              ; write it out
307
        jp c, J_cleanuperror
308
 
309
.writedata
310
        ld a, (INTERPWKSPC+OFFSET_TYPE) ; find the type of block we┬┤re saving
311
        and a                   ; if zero, it is BASIC
312
        jr nz, .testcode        ; if not jump forward
313
        ld hl, (ZX_PROG)        ; find the start of the program
314
        jr .save
315
.testcode
316
        cp 3                    ; type CODE
317
        jr nz, .badtype         ; TODO: character/number arrays
318
        ld hl, (INTERPWKSPC+OFFSET_PARAM1)      ; get the start address
319
.save
320
        ld bc, (INTERPWKSPC+OFFSET_LENGTH)      ; length
321
        push hl                 ; save values so we can calculate the
322
        push bc                 ; checksum (TODO optimize)
323
.saveloop
324
        push bc
325
        push hl                 ; save current position and length
326 235 winston
        ld a, (v_vfs_curfd)     ; get file descriptor
327 221 winston
        call WRITE
328
        pop hl                  ; retrieve start
329
        pop de                  ; retrieve length
330
        jr c, .cleanuperror     ; exit on error
331
        add hl, bc              ; increment the pointer
332
        ex de, hl
333
        sbc hl, bc              ; decrement the bytes remaining
334
        jr z, .done             ; and leave if we're finished.
335
        ld b, h                 ; and move to bc
336
        ld c, l
337
        ex de, hl
338
        jr .saveloop
339
.done
340
        pop bc                  ; retrieve original size
341
        pop hl                  ; and start address
342
        ld a, 0xFF              ; start with 0xFF for data block
343
        call F_tbas_mkchecksum
344
        ld (INTERPWKSPC), a     ; store result
345 235 winston
        ld a, (v_vfs_curfd)     ; TODO: checksum saving could do with
346 221 winston
        ld hl, INTERPWKSPC      ; being optimized!
347
        ld bc, 1
348
        call WRITE
349
        jp c, J_cleanuperror
350 235 winston
        ld a, (v_vfs_curfd)     ; close the file.
351 221 winston
        call VCLOSE
352
        ret
353
.badtype
354
        ld a, TBADTYPE
355
        scf
356
        jp J_cleanuperror
357
.cleanuperror
358
        pop bc                  ; restore stack
359
        pop hl
360
        jp J_cleanuperror
361
 
362
;---------------------------------------------------------------------------
363
; F_tbas_mkchecksum
364
; Make checksum for "tape" blocks.
365
; Parameters:           HL = pointer to block
366
;                       BC = size
367
;                       A = initial byte
368
; Result is returned in A.
369
F_tbas_mkchecksum
370
.loop
371
        xor (hl)                ; the checksum is made just by XORing each
372
        inc hl                  ; byte.
373
        dec bc
374
        ld e, a                 ; save A
375
        ld a, b
376
        or c                    ; BC = 0?
377
        ld a, e                 ; restore A
378
        jr nz, .loop
379
        ret
380
 
381
;----------------------------------------------------------------------------
382
; Generic 'clean up and leave'
383
J_cleanuperror
384
        push af                 ; save error code
385 235 winston
        ld a, (v_vfs_curfd)     ; and attempt to close the file
386 221 winston
        call VCLOSE
387
        pop af                  ; restore error and return with it.
388
        ret
389