Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [modules/] [basext/] [loader.asm] - Blame information for rev 380

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