📄 idefast.asm
字号:
; Somewhat faster communication with an IDE disk drive; see http://www.pjrc.com/tech/8051/ide/ for more info; This code is an original work by Paul Stoffregen, written; in December 1999. This code has been placed in the; public domain. You may use it without any restrictions.; You may include it in your own projects, even commercial; (for profit) products.; This code is distributed in the hope that they will be useful,; but without any warranty; without even the implied warranty of; merchantability or fitness for a particular purpose.; this code contains a modified copy of the code to read from an; IDE hard drive, which is optimized for speed. These routines; were used in a homebrew MP3 player, which was able to sustain; reads of 192 kbit/sec data while feeding it to a MAS3507D MP3; decoder chip, using the UART in sync mode. Reading 256 kbit/sec; did not not work. The 8051 was clocked with a 14.7456 MHz crystal.; there is no documentation specific to this modified version,; other than the comments within this code..equ location, 0x2000 ;where this program will exist.equ sect_buf, 0x2E00 ;512 byte buffer;------------------------------------------------------------------; Hardware Configuration;8255 chip. Change these to specify where the 8255 is addressed,;and which of the 8255's ports are connected to which ide signals.;The first three control which 8255 ports have the control signals,;upper and lower data bytes. The last two are mode setting for the;8255 to configure its ports, which must correspond to the way that;the first three lines define which ports are connected..equ ide_8255_lsb, 0x4000 ;lower 8 bits.equ ide_8255_msb, 0x4001 ;upper 8 bits.equ ide_8255_ctl, 0x4002 ;control lines.equ cfg_8255, 0x4003.equ rd_ide_8255, 10010010b ;ide_8255_ctl out, ide_8255_lsb/msb input.equ wr_ide_8255, 10000000b ;all three ports output;ide control lines for use with ide_8255_ctl. Change these 8;constants to reflect where each signal of the 8255 each of the;ide control signals is connected. All the control signals must;be on the same port, but these 8 lines let you connect them to;whichever pins on that port..equ ide_a0_line, 0x01 ;direct from 8255 to ide interface.equ ide_a1_line, 0x02 ;direct from 8255 to ide interface.equ ide_a2_line, 0x04 ;direct from 8255 to ide interface.equ ide_cs0_line, 0x08 ;inverter between 8255 and ide interface.equ ide_cs1_line, 0x10 ;inverter between 8255 and ide interface.equ ide_wr_line, 0x20 ;inverter between 8255 and ide interface.equ ide_rd_line, 0x40 ;inverter between 8255 and ide interface.equ ide_rst_line, 0x80 ;inverter between 8255 and ide interface;------------------------------------------------------------------; More symbolic constants... these should not be changed, unless of; course the IDE drive interface changes, perhaps when drives get; to 128G and the PC industry will do yet another kludge.;some symbolic constants for the ide registers, which makes the;code more readable than always specifying the address pins.equ ide_data, ide_cs0_line.equ ide_err, ide_cs0_line + ide_a0_line.equ ide_sec_cnt, ide_cs0_line + ide_a1_line.equ ide_sector, ide_cs0_line + ide_a1_line + ide_a0_line.equ ide_cyl_lsb, ide_cs0_line + ide_a2_line.equ ide_cyl_msb, ide_cs0_line + ide_a2_line + ide_a0_line.equ ide_head, ide_cs0_line + ide_a2_line + ide_a1_line.equ ide_command, ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line.equ ide_status, ide_cs0_line + ide_a2_line + ide_a1_line + ide_a0_line.equ ide_control, ide_cs1_line + ide_a2_line + ide_a1_line.equ ide_astatus, ide_cs1_line + ide_a2_line + ide_a1_line + ide_a0_line;IDE Command Constants. These should never change..equ ide_cmd_recal, 0x10.equ ide_cmd_read, 0x20.equ ide_cmd_write, 0x30.equ ide_cmd_init, 0x91.equ ide_cmd_id, 0xEC.equ ide_cmd_spindown, 0xE0.equ ide_cmd_spinup, 0xE1;------------------------------------------------------------------;internal ram usage.equ lba, 0x10 ;4 bytes, 28 bit Logical Block Address.equ stack, 0x40;------------------------------------------------------------------; Routines that talk with the IDE drive, these should be called by; the main program. ;read a sector, specified by the 4 bytes in "lba" ;Return, acc is zero on success, non-zero for an errorread_sector: acall wr_lba mov a, #ide_command mov r2, #ide_cmd_read acall ide_wr acall ide_drq jb acc.0, rs_err clr a retrs_err: mov a, #ide_err acall ide_rd mov a, r2 jz rs_err2 retrs_err2:mov a, #255 ret ;initialize the ide driveide_init: ;acall ide_hard_reset ;usually not necessary mov a, #ide_head mov r2, #10100000b acall ide_wr ;select the master device mov a, #ide_status acall ide_rd mov a, r2 ;should probably check for a timeout here jnb acc.6, ide_init ;wait for RDY bit to be set jb acc.7, ide_init ;wait for BSY bit to be clear mov a, #ide_head mov r2, #0xAF acall ide_wr ;what should this config parm be? mov a, #ide_sec_cnt mov r2, #64 acall ide_wr ;what should this config parm be? mov a, #ide_command mov r2, #ide_cmd_init acall ide_wr ;do init parameters command acall ide_busy mov a, #ide_command mov r2, #ide_cmd_recal ;do recal command (is this necessary?) acall ide_wr acall ide_busy ret;------------------------------------------------------------------; Not quite as low, low level I/O. These routines talk to the drive,; using the low level I/O. Normally a main program should not call; directly to these. ;This is the parts that's faster. Notice that it doesn't ;call to ide_rd and ide_wr, and it does less manipulation ;with the 8255. ;Read a block of 512 bytes (one sector) from the drive ;and store it in memory @ DPTRread_data: mov r0, #0 mov r1, #2 mov r2, dph mov p2, dph mov dptr, #cfg_8255 mov a, #rd_ide_8255 movx @dptr, a ;config 8255 chip, read moderdataloop: mov dptr, #ide_8255_ctl ;mov a, #ide_data ;movx @dptr, a ;drive address onto control lines mov a, #ide_data | ide_rd_line movx @dptr, a ;assert read pin mov dptr, #ide_8255_lsb clr a movc a, @a+dptr ;read the lower byte movx @r0, a inc r0 mov dptr, #ide_8255_msb clr a movc a, @a+dptr ;read the upper byte movx @r0, a inc r0 mov dptr, #ide_8255_ctl clr a movx @dptr, a ;deassert all control pins mov a, r0 jnz rdataloop mov a, r2 inc a mov p2, a djnz r1, rdataloop mov p2, #255 ret ;write the logical block address to the drive's registerswr_lba: mov a, lba+3 anl a, #0x0F orl a, #0xE0 mov r2, a mov a, #ide_head acall ide_wr mov a, #ide_cyl_msb mov r2, lba+2 acall ide_wr mov a, #ide_cyl_lsb mov r2, lba+1 acall ide_wr mov a, #ide_sector mov r2, lba+0 acall ide_wr ;mov a, #ide_sec_cnt ;mov r2, #1 ;acall ide_wr ret ;Wait for the ide drive to not be busy. ;Returns the drive's status in Accide_busy: mov a, #ide_status ;wait for RDY bit to be set acall ide_rd mov a, r2 ;should probably check for a timeout here jb acc.7, ide_busy ret ;note that this function is changed to have a call to an ;idle loop (commented out). ;Wait for the drive to be ready to transfer data. ;Returns the drive's status in Accide_drq: mov a, #ide_status ;wait for DRQ bit to be set acall ide_rd ;acall idle mov a, r2 ;should probably check for a timeout here jb acc.7, ide_drq ;wait for BSY to be clear jnb acc.3, ide_drq ;wait for DRQ to be set ret;------------------------------------------------------------------; Low Level I/O to the drive. These are the routines that talk; directly to the drive, via the 8255 chip. Normally a main; program would not call to these. ;Do a read bus cycle to the drive, using the 8255. This ;is slow, because we have to manipulate the 8255 and use ;the 8051's limited moxv and movx to do it (via dptr). ;Note that the drive is read using MOVC, to run on a board ;where the 8255 is read using PSEN. If your board uses ;RD instead of PSEN, chance the MOVC's to MOVX's. ;input acc = ide regsiter address ;output r2 = lower byte read from ide drive ;output r3 = upper byte read from ide drive ;dptr is changedide_rd: push acc mov dptr, #cfg_8255 mov a, #rd_ide_8255 movx @dptr, a ;config 8255 chip, read mode mov dptr, #ide_8255_ctl pop acc movx @dptr, a ;drive address onto control lines orl a, #ide_rd_line movx @dptr, a ;assert read pin mov dptr, #ide_8255_msb ;clr a ;movc a, @a+dptr ;read the upper byte ;mov r3, a mov dptr, #ide_8255_lsb clr a movc a, @a+dptr ;read the lower byte mov r2, a mov dptr, #ide_8255_ctl clr a movx @dptr, a ;deassert all control pins ret ;Do a write bus cycle to the drive, via the 8255 ;input acc = ide register address ;input r2 = lsb to write ;input r3 = msb to write ;dptr is changedide_wr: ;push acc mov r4, a mov dptr, #cfg_8255 mov a, #wr_ide_8255 movx @dptr, a ;config 8255 chip, write mode mov dptr, #ide_8255_lsb mov a, r2 movx @dptr, a ;drive lower lines with lsb (r2) ;mov dptr, #ide_8255_msb ;mov a, r3 ;movx @dptr, a ;drive upper lines with msb (r3) mov dptr, #ide_8255_ctl ;pop acc mov a, r4 movx @dptr, a ;drive address onto control lines orl a, #ide_wr_line movx @dptr, a ;assert write pin ;nop clr a movx @dptr, a ;deassert all control pins ;mov dptr, #cfg_8255 ;mov a, #rd_ide_8255 ;movx @dptr, a ;config 8255 chip, read mode ret ;do a hard reset on the drive, by pulsing its reset pin. ;this should usually be followed with a call to "ide_init".ide_hard_reset: mov dptr, #cfg_8255 mov a, #wr_ide_8255 movx @dptr, a ;config 8255 chip, write mode mov dptr, #ide_8255_ctl mov a, #ide_rst_line movx @dptr, a ;hard reset the disk drive mov r2, #250 djnz r2, * ;delay > 25 us (reset pulse width) clr a movx @dptr, a ;no ide control lines asserted ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -