📄 drivers.asm
字号:
mov dpl, a ljmp return_addr;*************************************************************;** **;** MP3 Playback (DMA Request Queue) **;** **;************************************************************* ;add a block (r2/r3) to the playback request queue ;c=0 for success, c=1 if request queue is full. The ;application calls here to cause MP3 data to be played ;r4/r5 pass the number of bytesplay_block_c: push flags2 ;setb debug mov dptr, #msg_play_block lcall pstr_d mov a, r3 lcall phex_d mov a, r2 lcall phex_d lcall space_d mov a, r5 lcall phex_d mov a, r4 lcall phex_d lcall space_d lcall block_desc_addr inc dptr inc dptr inc dptr inc dptr movx a, @dptr inc dptr push acc movx a, @dptr inc dptr push acc movx a, @dptr inc dptr lcall phex_d pop acc lcall phex_d pop acc lcall phex_d lcall space_d inc dptr inc dptr inc dptr inc dptr inc dptr movx a, @dptr inc dptr push acc movx a, @dptr inc dptr push acc movx a, @dptr inc dptr push acc movx a, @dptr lcall phex_d pop acc lcall phex_d pop acc lcall phex_d pop acc lcall phex_d lcall newline_d pop flags2 clr c mov a, r5 ;convert # bytes into 16 bit words rrc a mov r5, a mov a, r4 rrc a addc a, #0 mov r4, a mov a, r5 addc a, #0 mov r5, a clr ex0 ; -- disable STA013 interrupt here mov a, play_req_head cjne a, #255, play_block2 ;kickstart the playing, since we're not expecting an interrupt push flags2 ;setb debug mov dptr, #msg_play_block lcall pstr_d lcall pstr_d pop flags2 clr a mov play_req_head, a mov play_req_tail, a lcall play_dma setb ex0 jb mute_is_on, turn_mute_off mov dpl, #0 ljmp return_addrturn_mute_off: mov r4, #20 mov r3, #0 lcall sta013_write ;mute off mov r0, #100 ;brief delay, to transfer enough djnz r0, * ;mp3 data to get the sta013 to ;move from "init" to "decode" mode mov r4, #20 mov r3, #0 lcall sta013_write ;mute off mov r4, #114 mov r3, #1 lcall sta013_write ;start playing clr mute_is_on mov dpl, #0 ljmp return_addrplay_block2: inc a cjne a, #play_req_size, play_block3 clr aplay_block3: cjne a, play_req_tail, play_block4 ;if we get here, the play request queue is full, so we ;can't add this block setb ex0 ; -- reenable STA013 interrupt here mov dpl, #1 ljmp return_addrplay_block4: mov play_req_head, a rl a rl a add a, #play_req & 255 mov dpl, a clr a addc a, #play_req >> 8 mov dph, a ;now DPTR points to new request mov a, r2 movx @dptr, a ;write block number to queue inc dptr mov a, r3 movx @dptr, a inc dptr mov a, r4 ;write data length to queue movx @dptr, a inc dptr mov a, r5 movx @dptr, a setb ex0 ; -- reenable STA013 interrupt here mov dpl, #0 ljmp return_addrplay_abort_c: clr ex0 ;disable STA013 interrupt mov dptr, #dma_mp3_count+1 clr a movx @dptr, a ;stop current DMA transfer, if any mov dptr, #dma_mp3_count ;actually set it so that just one inc a ;more word is to be transfered movx @dptr, a ;by tweaking "dma_mp3_count". mov a, play_req_head cpl a jz play_abort3play_abort2: clr a mov play_req_tail, a ;flush play request queue mov play_req_head, aplay_abort3: setb ex0 ;reenable STA013 interrupt ;should tell the STA013 to flush its input buffer, if ;that can be done somehow ljmp return_addr ;normally this is done by the interrupt routine, but for ;the very first block played, we're not expecting an ;interrupt, so we have to start it manually. ; TODO: it would be cleaner if the FPGA had a feature ; to manually set the interrupt... then we could just ; set it and let "isr.asm" handle this task.play_dma: ;let's map the block with the MP3 data to 0x9000 mov dptr, #dram_page_cfg + (0x09 * 2) mov a, r2 movx @dptr, a inc dptr mov a, r3 movx @dptr, a ;finally, we're done with the memory management stuff, and ;we can now set up the DMA transfer and start it. mov dptr, #dma_mp3_src clr a movx @dptr, a ;write LSB of src addr inc dptr mov a, #0x90 movx @dptr, a ;write MSB of src addr mov dptr, #dma_mp3_count mov a, r4 movx @dptr, a ;write LSB of length inc dptr mov a, r5 movx @dptr, a ;write MSB of length clr a mov dptr, #dma_mp3_go movx @dptr, a ;begin the transfer ;now the DMA is happening... in all likelyhood, the STA013 has ;already asserted its DATA_REQ signal by the time we could get ;through all that work to set up the DMA transfer. If the ;latency of this code ever gets to be a problem, the FPGA ;will probably have to be changed to double buffer STA013 ;DMA requests, which would allow 0.1 second latency for the ;fastest MP3 (320 kbps) !! mov dptr, #num_blks_played movx a, @dptr add a, #1 ;increment "num_blks_played" movx @dptr, a inc dptr movx a, @dptr addc a, #0 movx @dptr, a retplay_dma_irq_enable: clr a mov dptr, #irq_dma_ide_ack movx @dptr, a mov dptr, #irq_dma_mp3_ack movx @dptr, a mov dptr, #irq_memcpy_ack movx @dptr, a mov dptr, #irq_mask mov a, #00000010b movx @dptr, a mov play_req_head, #255 mov play_req_tail, #255 anl tcon, #0xF0 ;low level trigger interrupts setb ex0 clr es ;shouldn't be here setb ea ljmp return_addr ;return the number of available position in the play ;queue. If it's zero, the playback queue is full and ;an attempt to call "play_block" will return with C=1 ; (perhaps there's a more efficient way to do this math?)play_queue_avail_c: clr ex0 ;disable STA013 interrupt here mov r0, play_req_tail mov a, play_req_head setb ex0 ;reenable STA013 interrupt here cjne a, #255, pqav2 mov a, #play_req_size-1 mov dpl, a ljmp return_addrpqav2: clr c subb a, r0 jnc pqav3 add a, #play_req_sizepqav3: ;now acc has the number that are in the queue mov r0, a mov a, #play_req_size clr c subb a, r0 ;now acc has the number of avaiable slots, but ;one is never used, so we need to subtract 1 jz pqav4 add a, #255pqav4: mov dpl, a ljmp return_addr ; TODO: simplify this function ;return C=1 if the playback queue is completely emptyis_play_queue_empty_c: mov dptr, #msg_play_queue_empty lcall pstr_d clr ex0 mov r0, play_req_head mov r1, play_req_tail setb ex0 mov a, r0 lcall phex_d mov a, #'-' lcall cout_d mov a, r1 lcall phex_d lcall newline_d mov a, r0 cpl a jz pqempty2 clr c mov dpl, #0 ljmp return_addrpqempty2: setb c mov dpl, #1 ljmp return_addrplay_suspend_c: clr ea ;clr ex0 mov dptr, #irq_mask ;movx a, @dptr ;anl a, #11111101b ;movx @dptr, a mov a, #00000000b ;turns off IDE interrupt movx @dptr, a ;setb ex0 setb ea ljmp return_addrplay_resume_c: clr ea ;clr ex0 mov dptr, #irq_mask ;movx a, @dptr ;orl a, #00000010b ;movx @dptr, a mov a, #00000010b ;turns off IDE interrupt movx @dptr, a ;setb ex0 setb ea ljmp return_addr ;return the number of blocks played (since the last call ;to this function). This will allow the appication to track ;the status of playback, perhaps to print elapsed/remaining ;time on the LCD display.play_num_sent: mov dptr, #num_blks_played clr ex0 ;disable STA013 interrupt here movx a, @dptr mov r4, a clr a movx @dptr, a inc dptr movx a, @dptr mov r5, a clr a movx @dptr, a setb ex0 ;reenable STA013 interrupt here ret;this test may seem extreemly paranoid, but there have been problems;initializing some STA013 chips, where the problem basically shows;up as the data request pin being stuck either high or low and the;chip produces no sound. The chip otherwise appears to be working,;so the only good way to detect the problem is to send a short clip;of MP3 data, larger than the STA013's input buffer, that is a known;length of time, and measure how long it takes the STA013 to consume;all the input data. This code sends a 1/2 second clip of silent;MP3 (1046 bytes long), and measures the elapsed time with a simple;delay loop. DPL=0 is the correct time elapses, of DPL=1 if the STA013;consumes the data too quickly or too slowly (including timeout).test_sta013_c: ;grab a block and map it at 0x9000.... this code is used ;before the memory manager is initialized, so we can not ;call malloc to get a block. We'll just grab a block and ;use it. mov r2, #34 mov r3, #0 mov a, #9 lcall map_block ;fill it with a null mp3 data that represents ;approximately 0.26 seconds of silence mov dptr, #0x9000 mov r1, #16 acall fill_null_mp3 mov dptr, #msg_test_sta013 lcall pm2_pstr mov dptr, #dma_mp3_src clr a movx @dptr, a ;write LSB of src addr inc dptr mov a, #0x90 movx @dptr, a ;write MSB of src addr mov dptr, #dma_mp3_count mov a, #0x40 movx @dptr, a ;write LSB of length inc dptr mov a, #0x03 movx @dptr, a ;write MSB of length clr a mov dptr, #irq_dma_mp3_ack movx @dptr, a ;make sure dma intr bit clear mov dptr, #dma_mp3_go movx @dptr, a ;begin the transfer ;time how long it take for the STA013 to consume this data mov r7, #0 ;r7 to count # of loopstest_mp3_wait: mov r6, #0test_mp3_wait2: mov dptr, #irq_ident ;2 movx a, @dptr ;2 jb acc.1, test_play_done ;2 djnz r6, test_mp3_wait2 ;2 inc r7 cjne r7, #80, test_mp3_wait2 ;now r7 will have an integer which represents how long we ;had to wait for the sta013 to completely consume this data ; ... it should take r7 == 0x4Etest_play_done: mov dptr, #msg_play_len lcall pm2_pstr mov a, r7 lcall pm2_phex mov a, #' ' lcall pm2_cout mov a, #' ' lcall pm2_cout ;did we pass the test... mov a, r7 add a, #190 jnc test_sta013_fail mov a, r7 add a, #166 jc test_sta013_fail mov dptr, #mesg_ok lcall pm2_pstr mov dpl, #0 ljmp return_addrtest_sta013_fail: mov dptr, #mesg_error lcall pm2_pstr mov dpl, #1 ljmp return_addrfill_null_mp3_c: mov dpl, r2 mov dph, r3 lcall fill_null_mp3 ljmp return_addr ;create silent MP3 bitstream data @ DPTR. R1 specifies ;the number of frames to create. Each frame is 104 bytes. ;the resulting mp3 data is 44.1 kHz mono samples encoded ;at 32 kbps (no padding, so bitrate is actually 31.9 kbps). ;each frame should play for 26 ms.fill_null_mp3: mov r0, #0f_null_loop1: inc r0 lcall f_null_lookup movx @dptr, a inc dptr cjne r0, #18, f_null_loop1 mov r0, #86 clr af_null_loop2: movx @dptr, a inc dptr djnz r0, f_null_loop2 djnz r1, fill_null_mp3 retf_null_lookup: mov a, r0 movc a, @a+pc ret .db 0xFF, 0xFB, 0x10, 0xC4, 0x00, 0x03, 0xC0, 0x00, 0x01 .db 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x80 sta013_get_attenuation: mov r4, #0x46 lcall sta013_read mov dpl, r3 ljmp return_addrsta013_set_attenuation: mov a, r3 add a, #256 - max_attenuation jnc sta013_set_atn2 mov r3, #max_attenuationsta013_set_atn2: ;mov dptr, #mesg_sta013_vol ;lcall pstr ;mov a, r3 ;lcall phex ;lcall newline mov r4, #0x46 ;write left attenuation lcall sta013_write mov r4, #0x48 lcall sta013_write ;write right attenuation ljmp return_addrmesg_sta013_vol: .db "STA013 attenuation = ",0;*************************************************************;** **;** Detect Partitions and FAT32 Filesystem Info **;** **;************************************************************* ;detect what type of filesystem we're using, and initialize ;all the filesystem variables for it. Return DPL=0 if the ;filesystem could not be detected, of DPL=non-zero if it was ;properly detected. Perhaps someday the non-zero code would ;represent what type of filesystem... but today we can only ;handle FAT32 on hard drives. .equ sector_buffer, 0x7000detect_filesystem: mov a, #1 lcall malloc_blocks mov a, #7 lcall map_blockread_mbr: mov f32_sector+3, #0 mov f32_sector+2, #0 mov f32_sector+1, #0 mov f32_sector+0, #0 mov dptr, #mesg_read_mbr lcall pstr mov dptr, #sector_buffer lcall ide_read_sector mov dptr, #sector_buffer + 0x1FE movx a, @dptr cjne a, #0x55, bad_mbr inc dptr movx a, @dptr cjne a, #0xAA, bad_mbr mov dptr, #sector_buffer + 0x1C2 movx a, @dptr mov r2, #1 lcall partition_type jc found_partition mov dptr, #sector_buffer + 0x1D2 movx a, @dptr mov r2, #1 lcall partition_type jc found_partition mov dptr, #sector_buffer + 0x1E2 movx a, @dptr mov r2, #1 lcall partition_type jc found_partition mov dptr, #sector_buffer + 0x1F2 movx a, @dptr mov r2, #1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -