⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 drivers.asm

📁 A MP3 Player Source Code, Enjoy it!
💻 ASM
📖 第 1 页 / 共 5 页
字号:
	;now we've got the range of blocks that'll be needed	;in the cache to satisfy this request.  Write them	;into the file_info for this file.	 mov	dptr, #msg_req_clusters1	 lcall	pstr_d	 mov	r0, #cluster_offset	 lcall	phex24_at_r0	 mov	dptr, #msg_to	 lcall	pstr_d	 mov	r0, #5	 lcall	phex24_at_r0	 lcall	newline_d	mov	a, file_desc	lcall	fd_to_ptr	movx	a, @dptr		;set "caching" bit in flags	orl	a, #00000010b	movx	@dptr, a	inc	dptr	inc	dptr			;skip unused byte	mov	a, cluster_offset+0	movx	@dptr, a		;store "fcache_first_cluster_offset"	inc	dptr	mov	a, cluster_offset+1	movx	@dptr, a	inc	dptr	mov	a, cluster_offset+2	movx	@dptr, a	inc	dptr	mov	a, r5	movx	@dptr, a		;store "fcache_last_cluster_offset"	inc	dptr	mov	a, r6	movx	@dptr, a	inc	dptr	mov	a, r7	movx	@dptr, a	inc	dptr	;fetch the block number of the first cluster that's	;already cached for this file (will be zero if none)	movx	a, @dptr	mov	r2, a	inc	dptr	movx	a, @dptr	mov	r3, a	;the goal now is the figure out "fcache_prev_cluster",	;which should be the block number holding the last	;already cached cluster that comes before	;"fcache_first_cluster_offset".	mov	r6, #0		;r6/r7 hold last block attempted	mov	r7, #0	mov	a, r3	jnz	fcache_find_prev_loop	mov	a, r2	jz	fcache_prev_knownfcache_find_prev_loop:	lcall	block_desc_addr		;get the block_info	inc	dptr			;skip "next_block"	inc	dptr	inc	dptr			;skip flags	inc	dptr			;skip unused byte	clr	c	movx	a, @dptr		;compare cluster offsets	subb	a, cluster_offset+0	inc	dptr	movx	a, @dptr	subb	a, cluster_offset+1	inc	dptr	movx	a, @dptr	subb	a, cluster_offset+2	jnc	fcache_prev_known	;if (file_info.cluster_offset >=					;        cluster_offset)	mov	a, r2	mov	r6, a			;this block is before the first	mov	a, r3			;cluster needed, so copy its	mov	r7, a			;number to r6/r7	inc	dptr	inc	dptr	movx	a, @dptr	mov	r2, a			;read next cluster location	inc	dptr	movx	a, @dptr	mov	r3, a	jnz	fcache_find_prev_loop	mov	a, r2	jnz	fcache_find_prev_loop	;when we get here, r6/r7 will hold the block number	;for the "fcache_prev_cluster" entry in file_info.fcache_prev_known:	 mov	dptr, #msg_prev_clust	 lcall	pstr_d	 mov	r0, #6	 lcall	phex16_at_r0	 lcall	newline_d	mov	a, file_desc	lcall	fd_to_ptr	mov	a, #10	lcall	add_a_to_dptr	mov	a, r6	movx	@dptr, a		;store "fcache_prev_cluster"	inc	dptr	mov	a, r7	movx	@dptr, a	clr	fcw_is_waiting	;hopefully everything that will be needed to get this	;file properly cached has been set up.	ljmp	return_addr	;this function actually does the work of loading a file	;into the cache.  Calling here will cause IDE read	;requests to be generated, which will make the drive	;start spinning if it was in sleep mode.  All that ius	;needed is the file descriptor (in r4).  The specifics	;of what is to be loaded must have been set up by calling	;"file_cache" before calling here.  Usually, this function	;will need to be called repetitively until it returns a	;status that the loading is complete, or an error (out	;of memory)	; return values:	;	DPL=0		some cached, keep calling	;	DPL=1		all requested data is cached	;	DPL=2		ran out of memoryfile_cache_work:	 mov	dptr, #msg_fcw1	 lcall	pstr_d	 mov	a, r4	 lcall	phex_d	 mov	a, #','	 lcall	cout_d	mov	a, r4	mov	file_desc, a	;check that the low priority request queue has enough space	;to add enough requests for an entire cluster, and if it	;doesn't, we need to stop now before malloc'ing the memory	;to hold this cluster.  This check was moved to be the very	;first thing, because in the common case where the main	;program called file_cache_work repetitively, the rreq queue	;is rapidly filled, so most of the calls will be returned	;right away by this function until there's at least enough	;room in the low priority rreq queue to hold the requests	;for another clusterfcache_queue_check:	mov	r0, blocks_per_cluster	inc	r0			;actually, make sure there's					;always one extra space available					;(ide_sleep doesn't properly handle					;a full queue case, yet....)	;- disable ide interrupt here	mov	r4, clust_rreq_head	mov	r5, clust_rreq_tail	;- reenable ide interrupt here	mov	a, r4	cpl	a	jz	fcache_qck_ok		;ok if queue complete empty	cpl	afcache_qck_1:	inc	a	cjne	a, #clust_rreq_size, fcache_qck_2	clr	afcache_qck_2:	cjne	a, 5, fcache_qck_nxt	;if we get here, there won't be enough room in the queue	 mov	dptr, #msg_queue_full	 lcall	pstr_d	mov	dpl, #0	ljmp	return_addrfcache_qck_nxt:	djnz	r0, fcache_qck_1fcache_qck_ok:	;the first thing we need to do is find a cluster number	;and it's cluster offset, that's at or before the first	;cluster offset required to be read.  There are two	;cases, either "file_info[fd].fcache_prev_cluster" will	;give us a block number where we get this, or if that	;fails, we've got to start at the beginning of the file.	mov	a, file_desc	lcall	fd_to_ptr	movx	a, @dptr		;read flags	jb	acc.1, fcache_start	;if we get here, this file isn't currently "caching", so	;return now with an indication that there's nothing to do	mov	dpl, #1	ljmp	return_addrfcache_start:	mov	a, #10	lcall	add_a_to_dptr	movx	a, @dptr	mov	prev_cluster_at_block+0, a	inc	dptr	movx	a, @dptr	mov	prev_cluster_at_block+1, a	jnz	fcache_prev	mov	a, prev_cluster_at_block+0	jnz	fcache_prev	;the file_info didn't have any indication of a previous	;cached cluster, so we'll just start at the beginningfcache_no_prev:	inc	dptr	movx	a, @dptr	mov	cluster+0, a	;get file_info.first_cluster_number	inc	dptr	movx	a, @dptr	mov	cluster+1, a	inc	dptr	movx	a, @dptr	mov	cluster+2, a	inc	dptr	movx	a, @dptr	mov	cluster+3, a	clr	a	mov	cluster_offset+0, a	;cluster_offset is zero	mov	cluster_offset+1, a	mov	cluster_offset+2, a	mov	a, file_desc	lcall	fd_to_ptr	mov	a, #8	lcall	add_a_to_dptr	movx	a, @dptr	mov	next_cluster_at_block+0, a	inc	dptr	movx	a, @dptr	mov	next_cluster_at_block+1, a	 mov	dptr, #msg_fcw2	 lcall	pstr_d	 mov	dptr, #msg_fcw3	 lcall	pstr_d	 lcall	newline_d	ljmp	fcache_seek_cluster	;the file_info had a previous cluster block number, so	;we'll look it up to get the info we need.fcache_prev:	 mov	dptr, #msg_fcw3	 lcall	pstr_d	 mov	a, #'='	 lcall	cout_d	 mov	r0, #prev_cluster_at_block	 lcall	phex16_at_r0	 lcall	newline_d	mov	r2, prev_cluster_at_block+0	mov	r3, prev_cluster_at_block+1	lcall	block_desc_addr		;get the block_info	inc	dptr			;skip "next_block"	inc	dptr	inc	dptr			;skip flags	inc	dptr			;skip unused byte	movx	a, @dptr	mov	cluster_offset+0, a	inc	dptr	movx	a, @dptr	mov	cluster_offset+1, a	inc	dptr	movx	a, @dptr	mov	cluster_offset+2, a	inc	dptr	inc	dptr			;skip "unused" byte	movx	a, @dptr	mov	next_cluster_at_block+0, a	inc	dptr	movx	a, @dptr	mov	next_cluster_at_block+1, a	inc	dptr	inc	dptr			;skip "number_of_bytes"	inc	dptr	movx	a, @dptr	mov	cluster+0, a	inc	dptr	movx	a, @dptr	mov	cluster+1, a	inc	dptr	movx	a, @dptr	mov	cluster+2, a	inc	dptr	movx	a, @dptr	mov	cluster+3, afcache_seek_cluster:	;we need to traverse the cluster chain until "cluster_offset"	;is equal to "file_info[fd].fcache_first_cluster_offset".	 mov	dptr, #msg_fcseek1	 lcall	pstr_d	 mov	r0, #cluster	 lcall	phex32_at_r0	 mov	dptr, #msg_fcseek2	 lcall	pstr_d	 mov	r0, #cluster_offset	 lcall	phex24_at_r0	 mov	dptr, #msg_fcseek3	 lcall	pstr_d	 mov	a, file_desc	 lcall	fd_to_ptr	 inc	dptr	 inc	dptr	 movx	a, @dptr	 push	acc	 inc	dptr	 movx	a, @dptr	 push	acc	 inc	dptr	 movx	a, @dptr	 lcall	phex_d	 pop	acc	 lcall	phex_d	 pop	acc	 lcall	phex_d	 lcall	newline_d	;check if the next cluster number is really an end of file mark.	mov	a, cluster+3	cjne	a, #0x0F, fcache_seek2	;Found EOF marker, which means we've read all of the file that	;there was to read.  The main program must have requested more	;than was actually available if we get here.	;technically, we ought to check for 0x0FFFFFF8 to 0x0FFFFFFF	;but no drive could have a cluster number that large.... using	;512 byte clusters (very unlikely to have a small cluster with	;such a large drive) would need to have 120 gig of clusters.	;It's probably safe to just check the upper byte and assume	;it's an end of file (or bad sector), and we need to stop.	;If we get here, the file has been completely read and we're done.	;does any cleanup need to be done?	mov	a, file_desc	lcall	fd_to_ptr	movx	a, @dptr	anl	a, #11111101b		;clear "caching" bit in flags	movx	@dptr, a	mov	dpl, #1	ljmp	return_addrfcache_seek2:	mov	a, file_desc	lcall	fd_to_ptr	inc	dptr	inc	dptr	mov	r6, dpl		;keep pointer to "fcache_first_cluster_offset"	mov	r7, dph	movx	a, @dptr	;get "fcache_first_cluster_offset"	cjne	a, cluster_offset+0, fcache_seek_fwd	inc	dptr	movx	a, @dptr	cjne	a, cluster_offset+1, fcache_seek_fwd	inc	dptr	movx	a, @dptr	cjne	a, cluster_offset+2, fcache_seek_fwd	ajmp	fcache_read_clusterfcache_seek_fwd:	;the comparison above only did an equality test of	;"cluster_offset" to the target offset stored in	;file_info[fd].fcache_first_cluster_offset.  We get here when	;they were not equal.  The values of "cluster_offset" will	;usually be a relatively small number (5 meg file with 4k	;clusters is 1221 clusters, relative to a 24 bit integer),	;and it should always be less than the target.  If something	;goes horribly wrong (memory corruption via DMA), it's quite	;likely to make its first appearance as "cluster_offset"	;being some unrealisticly large number, that's bigger than	;the target.  A test should be done here to see if the	;cluster_offset is larger than the target... and if it is	;something went very wrong and we probably need to abort	;back to paulmon2 right now, but maybe print a dump	;of the first 32 blocks (all the block_info) and perhaps	;8000 to 8FFF.	mov	dpl, r6		;dptr points to "target"	mov	dph, r7	clr	c	movx	a, @dptr	inc	dptr	subb	a, cluster_offset+0	;compute target - cluster_offset	movx	a, @dptr	inc	dptr	subb	a, cluster_offset+1	;compute target - cluster_offset	movx	a, @dptr	inc	dptr	subb	a, cluster_offset+2	;compute target - cluster_offset	jnc	fcache_seek_ok	;if we get here, cluster_offset was greater than the target	;(which was file_info[fd].fcache_first_cluster_offset), which	;makes something has gone horribly wrong.	mov	dptr, #msg_coffset_error	lcall	pstr	ljmp	serious_errorfcache_seek_ok:	mov	a, cluster_offset+0	add	a, #1	mov	cluster_offset+0, a	mov	a, cluster_offset+1	addc	a, #0	mov	cluster_offset+1, a	mov	a, cluster_offset+2	addc	a, #0	mov	cluster_offset+2, a	lcall	fat32_next_cluster	cjne	a, #1, fcache_seek_nope	ajmp	fcache_seek_clusterfcache_seek_nope:	;fat32_next_cluster returned either 0 (try again later) or	;2 (out of memory),	cjne	a, #2, fcache_seek_nope2	sjmp	fcache_out_of_memoryfcache_seek_nope2:	mov	dpl, a	ljmp	return_addrmsg_coffset_error:	.db	13,10,"Error: Cluster offset > target cluster offset",13,10,0	;when we get here, we've found a cluster that needs to	;be read.  We get both the "cluster" and "cluster_offset",	;and "prev_cluster_at_block" gives us the block that's	;holding the previous cluster, so we can link it to this	;one (or zero if none, so we'll have to link to the file_info).fcache_read_cluster:	 mov	dptr, #msg_read_clust1	 lcall	pstr_d	 mov	r0, #cluster	 lcall	phex32_at_r0	 mov	dptr, #msg_read_clust2	 lcall	pstr_d	 mov	r0, #cluster_offset	 lcall	phex24_at_r0	 mov	a, #')'	 lcall	cout_d	 lcall	newline_d	;TODO:  (this bug will show up someday....)	;actually, it's possible that this cluster is already	;in the cache, sitting as the next cluster in the linked	;list... it's be pretty silly to read it if it's already	;in the list.  Need to check for this case and jump to	;fcache_finishup if we don't actually need to read it.	;now call malloc to get the memory for this cluster	;this is the place that actually allocates the vast majority	;of memory used by the mp3 player.	mov	a, blocks_per_cluster	lcall	malloc_blocks	mov	reg6, r2			;save block # in r6/r7	mov	reg7, r3	jnc	fcache_rdclust2fcache_out_of_memory:	;if we get here, we're out of memory.	 mov	dptr, #msg_no_mem	 lcall	pstr	mov	a, file_desc	lcall	fd_to_ptr	movx	a, @dptr	anl	a, #11111101b		;clear "caching" bit in flags	movx	@dptr, a	mov	dpl, #2	ljmp	return_addrfcache_rdclust2:	;convert the cluster number into an LBA sector number	clr	c	mov	a, cluster+0	;first, subtract 2	subb	a, #2	mov	f32_sector+0, a	mov	a, cluster+1	subb	a, #0	mov	f32_sector+1, a	mov	a, cluster+2	subb	a, #0	mov	f32_sector+2, a	mov	a, cluster+3	anl	a, #15	subb	a, #0	mov	f32_sector+3, a				;now multiply by sectors_per_cluster				;always power of two, so use shifts	mov	r0, sectors_per_clusterf32_c2l_1:	mov	a, r0	clr	c	rrc	a	mov	r0, a	jz	f32_c2l_2	clr	c	mov	a, f32_sector+0	rlc	a	mov	f32_sector+0, a	mov	a, f32_sector+1	rlc	a	mov	f32_sector+1, a	mov	a, f32_sector+2	rlc	a	mov	f32_sector+2, a	mov	a, f32_sector+3	rlc	a	mov	f32_sector+3, a	sjmp	f32_c2l_1f32_c2l_2:	;now just add the LBA of the first data sector	mov	dptr, #first_data_sector	movx	a, @dptr	add	a, f32_sector+0	mov	f32_sector+0, a	inc	dptr	movx	a, @dptr	addc	a, f32_sector+1	mov	f32_sector+1, a	inc	dptr	movx	a, @dptr	addc	a, f32_sector+2	mov	f32_sector+2, a	inc	dptr	movx	a, @dptr	addc	a, f32_sector+3	mov	f32_sector+3, a		;now "f32_sector" has the LBA to read	;we need to do something with "prev_cluster_at_block".	;if it's zero, then there is no previous cluster and	;we need to update the file_info.  If there is a previous	;block, then we just write this number into its	;block_info.next_cluster field.	mov	a, prev_cluster_at_block+0	jnz	fcache_prev_fixup	mov	a, prev_cluster_at_block+1	jnz	fcache_prev_fixup	mov	a, file_desc	lcall	fd_to_ptr	mov	a, #8	lcall	add_a_to_dptr	mov	a, r6		;store r6/r7 as file_info.first_cached_cluster	movx	@dptr, a	inc	dptr	mov	a, r7	movx	@dptr, a	sjmp	fcache_rdc_rreqfcache_prev_fixup:	mov	r2, prev_cluster_at_block+0	mov	r3, prev_cluster_at_block+1fcache_prev_fixup_loop:	lcall	block_desc_addr	mov	a, #8	lcall	add_a_to_dptr	mov	a, r6	movx	@dptr, a	;store r6/r7 as block_info.next_cluster	inc	dptr	mov	a, r7	movx	@dptr, a	lcall	next_block	mov	a, r2		;write it into all blocks of that cluster	jnz	fcache_prev_fixup_loop	mov	a, r3	jnz	fcache_prev_fixup_loop	;now we'll 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -