📄 ide_old.asm
字号:
; Simple communication with an IDE disk drive; see http://www.pjrc.com/tech/8051/ide/ for more info; This old code was designed and tested on the old rev 2 board,; which is no longer available. If you use this code for a; modern hard drive, there may be a bug in the ide_wr routine; where the WR signal is deasserted. See the newer code if you; are unable to control the drive (but able to read the status; register); 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..equ location, 0x2100 ;where this program will exist.equ buffer, 0x3000 ;a 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 within paulmon2. To make this code stand-alone, just copy;and paste these bits of code from the paulmon2.asm file..equ cout, 0x0030 ;Send Acc to serial port.equ cin, 0x0032 ;Get Acc from serial port.equ phex, 0x0034 ;Print Hex value of Acc.equ pstr, 0x0038 ;Print string pointed to by DPTR,.equ upper, 0x0040 ;Convert Acc to uppercase.equ newline, 0x0048 ;print CR/LF (13 and 10).equ pint8u, 0x004D ;print Acc at an integer, 0 to 255.equ pint16u, 0x0053 ;print DPTR as an integer, 0 to 65535.equ cin_filter, 0x0062 ;get a character, but look for esc sequences;------------------------------------------------------------------; Main Program, a simple menu driven interface..org location.db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes.db 35,255,0,0 ;id, 35=program.db 0,0,0,0 ;reserved.db 0,0,0,0 ;reserved.db 0,0,0,0 ;reserved.db 0,0,0,0 ;reserved.db 0,0,0,0 ;user defined.db 255,255,255,255 ;length and checksum (255=unused).db "IDE Disk Drive Test",0.org location+64 ;executable code begins herebegin: mov sp, #stack mov dptr, #msg_1 ;print a welcome message lcall pstr ;initialize the drive. If there is no drive, this may hang acall ide_init ;get the drive id info. If there is no drive, this may hang acall drive_id ; print the drive's model number mov dptr, #msg_mdl lcall pstr mov dptr, #buffer + 60 mov r0, #40 acall print_name lcall newline ; print the drive's serial number mov dptr, #msg_sn lcall pstr mov dptr, #buffer + 20 mov r0, #20 acall print_name lcall newline ; print the drive's cylinder, head, and sector specs mov dptr, #msg_cy lcall pstr mov dptr, #buffer + 2 acall print_parm mov dptr, #msg_hd lcall pstr mov dptr, #buffer + 6 acall print_parm mov dptr, #msg_sc lcall pstr mov dptr, #buffer + 12 acall print_parm lcall newline lcall newline ; default position will be first block (master boot record) clr a mov lba+0, a mov lba+1, a mov lba+2, a mov lba+3, amain_loop: ;print a 1-line prompt mov dptr, #msg_l lcall pstr mov a, lba+3 lcall phex mov a, lba+2 lcall phex mov a, lba+1 lcall phex mov a, lba+0 lcall phex mov dptr, #msg_pmt lcall pstr lcall cin lcall uppermain1: cjne a, #'R', main2 ;read a sector acall read_sector jz main1b push acc mov dptr, #msg_err lcall pstr pop acc lcall phex lcall newline ajmp main_loopmain1b: mov dptr, #msg_rd lcall pstr ajmp main_loopmain2: cjne a, #'W', main3 ;write a sector mov dptr, #msg_sure lcall pstr lcall cin lcall upper cjne a, #'Y', main2c acall write_sector jz main2b push acc mov dptr, #msg_err lcall pstr pop acc lcall phex lcall newline ajmp main_loopmain2b: mov dptr, #msg_wr lcall pstrmain2c: ajmp main_loopmain3: cjne a, #'L', main4 ;set the logical block address mov dptr, #msg_cyh lcall pstr lcall ghex32_lba jc main3b mov lba+0, r3 mov lba+1, r4 mov lba+2, r5 mov lba+3, r6main3b: lcall newline ajmp main_loopmain4: cjne a, #'U', main5 ;cause the drive to spin up acall spinup ajmp main_loopmain5: cjne a, #'D', main6 ;cause the drive to spin down acall spindown ajmp main_loopmain6: cjne a, #'Q', main7 ;quit ljmp 0main7: cjne a, #'H', main8 acall hexdump ajmp main_loopmain8: ajmp main_loopmsg_1: .db "IDE Disk Drive Test Program",13,10,13,10,0msg_mdl:.db "Model: ",0msg_sn: .db "S/N: ",0msg_cy: .db "Cylinders: ", 0msg_hd: .db ", Heads: ", 0msg_sc: .db ", Sectors: ", 0msg_cyh:.db "Enter LBA (in hex): ", 0msg_l: .db "LBA=0x",0msg_pmt:.db ", (R)ead (W)rite (L)BA (U)p (D)own (H)exdump (Q)uit",13,10,0msg_sure:.db "Warning: this will change data on the drive, are you sure?",13,10,0msg_rd: .db "Sector Read OK",13,10,0msg_wr: .db "Sector Write OK",13,10,0msg_err:.db "Error, code = ",0;------------------------------------------------------------------; 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 ide_busy ;make sure drive is ready acall wr_lba ;tell it which sector we want mov a, #ide_command mov r2, #ide_cmd_read acall ide_wr ;ask the drive to read it acall ide_drq ;wait until it's got the data jb acc.0, get_err mov dptr, #buffer acall read_data ;grab the data clr a ret ;when an error occurs, we get acc.0 set from a call to ide_drq ;or ide_busy (which read the drive's status register). If ;that error bit is set, we should jump here to read the drive's ;explaination of the error, to be returned to the user. If for ;some reason the error code is zero (shouldn't happen), we'll ;return 255, so that the main program can always depend on a ;return of zero to indicate success.get_err:mov a, #ide_err acall ide_rd mov a, r2 jz gerr2 retgerr2: mov a, #255 ret ;write a sector, specified by the 4 bytes in "lba", ;whatever is in the buffer gets written to the drive! ;Return, acc is zero on success, non-zero for an errorwrite_sector: acall ide_busy ;make sure drive is ready acall wr_lba ;tell it which sector we want mov a, #ide_command mov r2, #ide_cmd_write acall ide_wr ;tell drive to write a sector acall ide_drq ;wait unit it wants the data jb acc.0, get_err mov dptr, #buffer acall write_data ;give the data to the drive acall ide_busy ;wait until the write is complete jb acc.0, get_err clr a ret ;do the identify drive command, and return with the buffer ;filled with info about the drivedrive_id: acall ide_busy mov a, #ide_command mov r2, #ide_cmd_id acall ide_wr acall ide_drq mov dptr, #buffer acall read_data ret ;tell the drive to spin upspinup: mov r2, #ide_cmd_spinupspup2: mov a, #ide_command acall ide_wr acall ide_busy ret ;tell the drive to spin downspindown: acall ide_busy mov r2, #ide_cmd_spindown sjmp spup2 ;initialize the ide driveide_init: mov a, #ide_head mov r2, #10100000b acall ide_wr ;select the master device mov a, #ide_status acall ide_rd ;mov a, #'*' ;lcall cout 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, #0x20 acall ide_wr ;what should this config parm be? mov a, #ide_sec_cnt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -