Subversion Repositories Spectranet

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

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 399 winston
.include        "fcntl.inc"
23
.include        "spectranet.inc"
24
.include        "zxrom.inc"
25
.include        "defs.inc"
26
.include        "sysvars.inc"
27
.include        "zxsysvars.inc"
28 442 winston
.include        "errno.inc"
29 399 winston
.text
30 221 winston
; TAP load/save functions
31
;------------------------------------------------------------------------
32
; F_tbas_readrawfile
33
; Reads a raw file off the filesystem, without looking to see if it has
34
; a header.
35
; Parameters: HL = pointer to filename
36
;             DE = memory location to place the result
37
; Returns with carry set and A=error number on error.
38 399 winston
.globl F_tbas_readrawfile
39
F_tbas_readrawfile:
40 221 winston
        push de                 ; save pointer
41
        ld e, O_RDONLY          ; LOADing is read only
42
        ld d, 0x00              ; No file flags
43
        call OPEN               ; Filename pointer is already in HL
44
        pop de
45
        ret c
46 235 winston
        ld (v_vfs_curfd), a     ; save the filehandle
47 399 winston
.readloop1:
48 235 winston
        ld a, (v_vfs_curfd)     ; restore filehandle
49 221 winston
        ld bc, 512              ; read max 512 bytes
50
        call READ
51 399 winston
        jr nc, .readloop1       ; keep going until nothing more can be read
52 221 winston
        cp EOF                  ; End of file?
53 399 winston
        jr nz, .failed1         ; No - something went wrong
54 235 winston
        ld a, (v_vfs_curfd)     ; Close the file
55 221 winston
        jp VCLOSE
56 399 winston
.failed1:
57 221 winston
        push af                 ; preserve return code
58 235 winston
        ld a, (v_vfs_curfd)
59 221 winston
        call VCLOSE             ; close the file
60
        pop af                  ; but let the earlier return code have
61
        scf                     ; precedence over any errors that close throws
62
        ret                     ; up.
63
 
64
;--------------------------------------------------------------------------
65
; F_tbas_loader
66
; The BASIC LOAD command. Opens the named file, reads the header, then
67
; decides how to load the file from the header information contained.
68
; Parameters    HL = pointer to filename
69
;               DE = memory address to load to for CODE files
70
;               A  = type to expect
71 399 winston
.globl F_tbas_loader
72
F_tbas_loader:
73 221 winston
        ld (INTERPWKSPC+21), a  ; save the type parameter
74
        ld (v_desave), de       ; save address
75
        ld e, O_RDONLY          ; Open file read only
76
        ld d, 0x00              ; with no flags
77
        call OPEN
78
        ret c                   ; return if the open operation fails
79 235 winston
        ld (v_vfs_curfd), a     ; save the returned filehandle
80 221 winston
        ld de, INTERPWKSPC      ; set destination pointer to workspace
81
        call F_tbas_getheader   ; Fetch the header
82
        jp c, J_cleanuperror    ; on error, clean up and return
83
        ld ix, INTERPWKSPC+3    ; start of "tape" header in a TAP file
84
        ld a, (INTERPWKSPC+21)  ; get the type byte
85
        cp (ix+0)               ; check that it's the right type
86 399 winston
        jr nz, .wrongtype2
87 221 winston
        and a                   ; type 0? BASIC program
88 399 winston
        jr nz, .testcode2       ; No, test for CODE
89 221 winston
        call F_tbas_loadbasic   ; Load a BASIC program
90
        jp c, J_cleanuperror    ; handle errors
91 399 winston
.cleanup2:
92 235 winston
        ld a, (v_vfs_curfd)
93 221 winston
        call VCLOSE
94
        ret
95 399 winston
.testcode2:
96 221 winston
        cp 0x03                 ; type CODE
97 399 winston
        jr nz, .unktype2                ; not a type we know
98 221 winston
        ld de, (INTERPWKSPC+OFFSET_PARAM1)      ; get the start address
99
        ld bc, (INTERPWKSPC+OFFSET_LENGTH)      ; and the expected length
100 255 winston
        call F_tbas_loadblock   ; and load the TAP block
101 399 winston
        jr .cleanup2
102
.wrongtype2:
103 221 winston
        ; TODO: handle CODE files
104
        ld a, TBADTYPE
105
        scf
106
        ret
107 399 winston
.unktype2:
108 221 winston
        ld a, TUNKTYPE
109
        scf
110
        ret
111
 
112
;--------------------------------------------------------------------------
113
; F_tbas_getheader
114 235 winston
; Reads a block header into memory from the file handle in v_vfs_curfd.
115 221 winston
; Spectranet files are the same format as TAP files, so each block has
116
; a 2 byte length, followed by data. This function reads the length
117
; and places the complete header into the memory address specified
118
; by DE. On error, it returns with carry set and A containing the error
119
; number. On success, the file type is returned in A.
120 399 winston
.globl F_tbas_getheader
121
F_tbas_getheader:
122 221 winston
        push de                 ; save pointer
123 235 winston
        ld a, (v_vfs_curfd)     ; get the current file descriptor
124 221 winston
        ld bc, TNFS_HDR_LEN     ; 19 bytes (length + ZX header block)
125
        call READ
126
        pop hl                  ; get the pointer back but in hl
127
        ret c                   ; error occurred in read
128
        ld a, (hl)
129
        cp 0x13                 ; first byte must be 0x13
130 399 winston
        jr nz, .wronglen3
131 221 winston
        inc hl
132
        ld a, (hl)              ; second byte must be 0x00
133
        and a
134 399 winston
        jr nz, .wronglen3
135 221 winston
        inc hl
136
        ld a, (hl)              ; type must be 0x00 - "header"
137
        and a
138 399 winston
        jr nz, .wrongblktype3
139 221 winston
        inc hl
140
        ld a, (hl)              ; return the type byte
141
        ret                     ; TODO: Check the checksum etc.
142 399 winston
.wronglen3:
143 221 winston
        ld a, TBADLENGTH
144
        scf
145
        ret
146 399 winston
.wrongblktype3:
147 221 winston
        ld a, TBADTYPE
148
        scf
149
        ret
150
 
151
;----------------------------------------------------------------------------
152
; F_tbas_loadblock
153
; Loads a TAP block
154
; Parameters: DE = where to copy in memory
155
;             BC = expected length
156 235 winston
;             v_vfs_curfd contains the file descriptor
157 399 winston
.globl F_tbas_loadblock
158
F_tbas_loadblock:
159 221 winston
        push de                 ; save destination ptr
160
        push bc                 ; save length
161
        ld de, INTERPWKSPC      ; get the length from TAP block
162
        ld bc, 3                ; 3 bytes long (length + flags)
163 235 winston
        ld a, (v_vfs_curfd)
164 221 winston
        call READ               ; read the TAP header
165
        pop bc                  ; get the length
166
        pop de                  ; and destination pointer
167
        ret c                   ; and leave on read error
168
        ld hl, (INTERPWKSPC)    ; sanity check TAP length
169
        dec hl                  ; which should be length in ZX header + 2
170
        dec hl
171
        sbc hl, bc              ; zero flag is set if length is correct
172 399 winston
        jr nz, .lengtherr4
173
.loadloop4:
174 235 winston
        ld a, (v_vfs_curfd)     ; get file descriptor
175 221 winston
        call READ
176
        ret
177 399 winston
.lengtherr4:
178 221 winston
        ld a, TMISMCHLENGTH     ; Length of data block doesn't match header
179
        scf
180
        ret
181
 
182
;----------------------------------------------------------------------------
183
; F_tbas_loadbasic
184
; Load a program written in BASIC.
185 399 winston
; Parameters: IX points to the "tape" header (i.e4. TAP block + 2)
186 235 winston
;             v_vfs_curfd contains the file descriptor
187 221 winston
; Much of this is modelled on the ZX ROM loader.
188 399 winston
.globl F_tbas_loadbasic
189
F_tbas_loadbasic:
190 221 winston
        ld hl, (ZX_E_LINE)      ; End marker of current variables area
191
        ld de, (ZX_PROG)        ; Destination address
192
        dec hl
193
        ld (v_ixsave), ix       ; save IX
194
        ld c, (ix+0x0b)         ; Length argument in "tape" header
195
        ld b, (ix+0x0c)
196
        push bc                 ; save the length
197
        rst CALLBAS
198
        defw ZX_RECLAIM_1       ; Reclaim present program/vars
199
        pop bc
200
        push hl                 ; Save program area pointer
201
        push bc                 ; and length
202
        rst CALLBAS
203
        defw ZX_MAKE_ROOM       ; Call MAKE_ROOM to make speace for program
204
        ld ix, (v_ixsave)       ; restore IX
205
        inc hl                  ; The system variable VARS
206
        ld c, (ix+0x0f)         ; needs to be set.
207
        ld b, (ix+0x10)
208
        add hl, bc
209
        ld (ZX_VARS), hl
210 225 winston
        ld h, (ix+0x0e)         ; Check for LINE number
211
        ld a, h
212
        and 0xC0
213 399 winston
        jr nz, .loadblock5      ; No line number - skip to loader
214 225 winston
        ld l, (ix+0x0d)         ; HL = line number
215
        ld (ZX_NEWPPC), hl      ; set line number to jump to
216
        xor a
217
        ld (ZX_NSPPC), a        ; Statement number 0
218
 
219 399 winston
.loadblock5:
220 221 winston
        pop bc                  ; fetch the length
221
        pop de                  ; fetch the start
222
 
223
        jp F_tbas_loadblock     ; load the block
224
 
225
;--------------------------------------------------------------------------
226
; F_tbas_mktapheader
227
; Create a TAP header with filename and type.
228
; Parameters            A = type
229
;                       DE = filename
230
;                       BC = filename length
231 399 winston
.globl F_tbas_mktapheader
232
F_tbas_mktapheader:
233 221 winston
        push de
234
        push bc
235
        ; Create the header
236
        ld hl, 0x13             ; length of header block in TAP format
237
        ld (INTERPWKSPC), hl
238
        ld (INTERPWKSPC+3), a   ; save the type byte
239
        xor a
240
        ld (INTERPWKSPC+2), a   ; is a header block, set to 0x00
241
        ld a, 10                ; > 10 chars in the filename?
242
        cp b
243 399 winston
        jr nc, .continue6
244 221 winston
        ld c, 10                ; copy max of 10
245 399 winston
.continue6:
246 221 winston
        ld b, c                 ; prepare to copy string
247
        ld hl, INTERPWKSPC+4
248 399 winston
.loop6:
249 221 winston
        ld a, (de)              ; copy the string
250
        ld (hl), a
251
        inc de
252
        inc hl
253 399 winston
        djnz .loop6
254 221 winston
        ld a, 10                ; find remaining bytes
255
        sub c
256 399 winston
        jr z, .exit6            ; nothing to do!
257 221 winston
        ld b, a                 ; A now contains the loop count
258 399 winston
.spaces6:
259 221 winston
        ld (hl), 0x20           ; fill the rest with spaces
260
        inc hl
261 399 winston
        djnz .spaces6
262
.exit6:
263 221 winston
        pop bc
264
        pop de
265
        ld hl, 0                ; make the parameters default to 0
266
        ld (INTERPWKSPC+OFFSET_PARAM1), hl
267
        ld h, 0x80              ; the default when no param2
268
        ld (INTERPWKSPC+OFFSET_PARAM2), hl
269
        ret
270
 
271
;---------------------------------------------------------------------------
272
; F_tbas_writefile
273
; Writes a file from a %SAVE command. The header must be complete and stored
274
; in INTERPWKSPC.
275
; Parameters:           DE = pointer to filename
276 399 winston
;                       BC = length of filename (i.e6. from ZX_STK_FETCH)
277 221 winston
; On error returns with carry set and A = errno.
278 399 winston
.globl F_tbas_writefile
279
F_tbas_writefile:
280 221 winston
        ld hl, INTERPWKSPC+21   ; convert filename to a C string
281
        call F_basstrcpy
282
 
283
        ld hl, INTERPWKSPC+21   ; Open the file for write (the full C string
284
        ld e, O_WRONLY          ; for the filename is in mem after the header)
285
        ld d, O_CREAT           ; flags = CREATE
286
        call OPEN               ; Open the file.
287
        ret c
288 235 winston
        ld (v_vfs_curfd), a     ; store the file descriptor
289 221 winston
 
290
        ld hl, INTERPWKSPC+OFFSET_TYPE  ; checksum the header
291
        ld bc, ZX_HEADERLEN
292
        xor a                   ; start with 0x00 for header block
293
        call F_tbas_mkchecksum
294
        ld (INTERPWKSPC+OFFSET_CHKSUM), a
295
        ld hl, INTERPWKSPC      ; write the 21 byte TAP block
296 235 winston
        ld a, (v_vfs_curfd)
297 221 winston
        ld bc, 21
298
        call WRITE
299
        jp c, J_cleanuperror
300
 
301
        ld hl, (INTERPWKSPC+OFFSET_LENGTH)
302
        inc hl                  ; add 2 for the 0xFF data block byte
303
        inc hl                  ; and check byte
304
        ld (INTERPWKSPC), hl    ; create TAP header and ZX data block
305
        ld a, 0xFF              ; which consists of a 16 bit length
306
        ld (INTERPWKSPC+2), a   ; followed by 0xFF
307 235 winston
        ld a, (v_vfs_curfd)
308 221 winston
        ld hl, INTERPWKSPC
309
        ld bc, 3
310
 
311
        call WRITE              ; write it out
312
        jp c, J_cleanuperror
313
 
314 399 winston
.writedata7:
315 221 winston
        ld a, (INTERPWKSPC+OFFSET_TYPE) ; find the type of block we┬┤re saving
316
        and a                   ; if zero, it is BASIC
317 399 winston
        jr nz, .testcode7       ; if not jump forward
318 221 winston
        ld hl, (ZX_PROG)        ; find the start of the program
319 399 winston
        jr .save7
320
.testcode7:
321 221 winston
        cp 3                    ; type CODE
322 399 winston
        jr nz, .badtype7                ; TODO: character/number arrays
323 221 winston
        ld hl, (INTERPWKSPC+OFFSET_PARAM1)      ; get the start address
324 399 winston
.save7:
325 221 winston
        ld bc, (INTERPWKSPC+OFFSET_LENGTH)      ; length
326
        push hl                 ; save values so we can calculate the
327
        push bc                 ; checksum (TODO optimize)
328 399 winston
.saveloop7:
329 235 winston
        ld a, (v_vfs_curfd)     ; get file descriptor
330 221 winston
        call WRITE
331 399 winston
        jr c, .cleanuperror7    ; exit on error
332
.done7:
333 221 winston
        pop bc                  ; retrieve original size
334
        pop hl                  ; and start address
335
        ld a, 0xFF              ; start with 0xFF for data block
336
        call F_tbas_mkchecksum
337
        ld (INTERPWKSPC), a     ; store result
338 235 winston
        ld a, (v_vfs_curfd)     ; TODO: checksum saving could do with
339 221 winston
        ld hl, INTERPWKSPC      ; being optimized!
340
        ld bc, 1
341
        call WRITE
342
        jp c, J_cleanuperror
343 235 winston
        ld a, (v_vfs_curfd)     ; close the file.
344 221 winston
        call VCLOSE
345
        ret
346 399 winston
.badtype7:
347 221 winston
        ld a, TBADTYPE
348
        scf
349
        jp J_cleanuperror
350 399 winston
.cleanuperror7:
351 221 winston
        pop bc                  ; restore stack
352
        pop hl
353
        jp J_cleanuperror
354
 
355
;---------------------------------------------------------------------------
356
; F_tbas_mkchecksum
357
; Make checksum for "tape" blocks.
358
; Parameters:           HL = pointer to block
359
;                       BC = size
360
;                       A = initial byte
361
; Result is returned in A.
362 399 winston
.globl F_tbas_mkchecksum
363
F_tbas_mkchecksum:
364
.loop8:
365 221 winston
        xor (hl)                ; the checksum is made just by XORing each
366
        inc hl                  ; byte.
367
        dec bc
368
        ld e, a                 ; save A
369
        ld a, b
370
        or c                    ; BC = 0?
371
        ld a, e                 ; restore A
372 399 winston
        jr nz, .loop8
373 221 winston
        ret
374
 
375
;----------------------------------------------------------------------------
376
; Generic 'clean up and leave'
377 399 winston
J_cleanuperror:
378 221 winston
        push af                 ; save error code
379 235 winston
        ld a, (v_vfs_curfd)     ; and attempt to close the file
380 221 winston
        call VCLOSE
381
        pop af                  ; restore error and return with it.
382
        ret
383