IDE bus interface circuit

IDE bus interface circuit

Hardware

IDE Bus interface circuit.

The connector on the top left of the diagram is from my own 6502 boards (see the sbc project) and is as it is for two reasons. It’s easy
to wire on a stripboard layout and I have a lot of 26 way ribbon, headers and plugs. All the signals are directly from the 6502 except /SEL0 and /SEL1 which are used to select the block $F1xx with /SEL0 = 1 and /SEL1 = 0.

A 40 pin IDC header, re-cycled from a PC motherboard, is used to connect to the IDE bus.

All the capacitors are low ESR electrolytics and are placed one near each chip. If you don’t have this type to hand you can use standard electrolytics with some low value
ceramic capacitor, say 0.1uF, in parallel.

The GAL16V8A is used to generate the read and write strobes for the buffers and latches and to generate the IOR and IOW strobes for the IDE bus. All are active low. The interface uses 32 bytes in the address range as it is a 16 bit port with 16 addresses. For anyone interested the equations for this chip are in ide_01.pld and can be compiled with WinCUPL. The fuse file, ide_01.jed and the compiler listing, ide_01.txt are also included.

IDE ATA Interface address map. High byte at address+1
Address Read Write Width
$00 Data 16 Bit
$02 Error Precomp 8 Bit
$04 Sector count 8 Bit
$06 LBA bits 0 to 8 / CHS Sector number 8 Bit
$08 LBA bits 8 to 15 / CHS Cylinder low 8 Bit
$0A LBA bits 16 to 23 / CHS Cylinder high 8 Bit
$0C Drive select & LBA bits 24 to 27 / CHS Head select 8 Bit
$0E Status Command 8 Bit
$1C Alternate status Device control 8 Bit
$1E Drive address Not used 8 Bit

For ATAPI devices some of the register names and functions change. Here is the ATAPI map.

IDE ATAPI Interface address map. High byte at
address+1
Address Read Write Width
$00 Data 16 Bit
$02 Error Feature 8 Bit
$04 Interrupt reason Not used 8 Bit
$06 Not used
$08 Byte count low 8 Bit
$0A Byte count high 8 Bit
$0C Device select 8 Bit
$0E Status Command 8 Bit
$1C Alternate status Device control 8 Bit
$1E Not used

All reads and writes to the IDE bus are sixteen bits wide. On write, first the lower eight bits are written to the even address (A0 = 0) and latched by one 74LS574, Then the upper eight bits are written to the corresponding odd address (A0 = 1) and are presented to the upper eight bits of the IDE bus by the 74LS245, a bi-directional buffer used here in the one direction only. These eight bits, along with the previously latched lower
eight bits, make up the sixteen bits needed for a write operation.
On read the lower eight bits are read from the IDE bus even address (A0 = 0) via the second 74LS245 and, as this read takes place the upper, eight bits from the IDE bus are latched by the second 74LS574. The upper eight bits can then be read from the 74LS574 latch.

The interface is arranged thus so that ..

  • All 16 bits are used, this allows us to utilise the full capacity of the drive.
  • Reads and writes are symmetrical, i.e. both are done low byte and then high byte.
  • The status registers on ATA devices are all on the low byte, fast polling is possible because only the low byte needs to be read.

The disadvantage is that every write must be sixteen bits, even if the top eight bits
aren’t used.

Other features are ..

  • An activity LED. Illuminates during ATA device activity. If required this could be wired off board.
  • A reset jumper. This ties the IDE bus reset to the CPU reset so both are reset together.
  • An IRQ jumper. This is to allow an interrupt based driver to be developed.

The finished board.

Close-up views.

Software.
At present only a BASIC demonstration program is available. It can be seen here.
Download this file

10 REM set disk interface values
20 REM enhanced BASIC version
30 REM supports ATA but not ATAPI devices
100 AD=$F100 : REM interface base address
110 IO=AD+$00 : REM input/output register - 16 bits
120 ER=AD+$02 : REM error/precomp register
130 SC=AD+$04 : REM sector count
140 SS=AD+$06 : REM LBA bits 0 to 7
150 CL=AD+$08 : REM LBA bits 8 to 15
160 CH=AD+$0A : REM LBA bits 26 to 23
170 HR=AD+$0C : REM drive/LBA bits 24 to 27
180 SR=AD+$0E : REM status/command
190 RR=AD+$0C+$10 : REM alternate status/device control
200 AS=AD+$0E+$10 : REM drive address
210 MD=%10100000 : REM these bits must always be set
220 BK=%01000000 : REM value to set LBA mode
1000 REM set parameters to defaults
1005 DOKE RR,6 : REM write device control
1010 DOKE SC,1 : REM sector count
1020 DOKE SS,0 : REM LBA bits 0 to 7
1030 DOKE CL,0 : REM LBA bits 8 to 15
1040 DOKE CH,0 : REM LBA bits 26 to 23
1050 DOKE HR,MD+BK : REM drive/LBA upper 4 bits
1055 DOKE RR,2 : REM write device control
1060 GOSUB 1300
1065 PRINT : GOSUB 3100
1070 PRINT
1080 PRINT "0  Select drive"
1090 PRINT "1  Reset device"
1100 PRINT "2  Identify device"
1110 PRINT "3  Sleep device"
1120 PRINT "4  Idle device"
1130 PRINT "5  Standby device"
1140 PRINT "6  Query power mode"
1150 PRINT "7  Execute diagnostics"
1160 PRINT "8  Recalibrate"
1170 PRINT "9  Test read"
1175 PRINT "10 Write BASIC""
1180 PRINT
1190 PRINT "Choose one";
1200 INPUT I
1210 I=I+1
1220 IF (I<1) OR (I>11) THEN 1200
1230 PRINT
1240 ON I GOSUB 3000,1300,6000,2200,2300,2400,2500,2600,2900,2700,20000
1250 GOTO 1065
1300 REM reset device(s)
1310 DOKE HR,(MD+BK) EOR 16 : REM select other drive
1320 CMD=8
1330 GOSUB 11020
1340 DOKE HR,MD+BK : REM select drive
1350 CMD=8
1360 GOSUB 11020
1370 RETURN
2200 REM go to sleep
2210 CMD=230
2220 DOKE SR,CMD : REM send command
2230 RETURN
2300 REM go to idle mode
2310 CMD=225
2320 GOTO 11000
2400 REM go to standby mode
2410 CMD=224
2420 GOTO 11000
2500 REM query device power mode
2510 CMD=229
2520 GOSUB 11000
2530 I=DEEK(SC) AND 255 : REM sector count
2540 PRINT "Device is in ";
2550 IF I=0 THEN PRINT "standby"; : GOTO 2590
2560 IF I=128 THEN PRINT "idle"; : GOTO 2590
2570 IF I=255 THEN PRINT "active"; : GOTO 2590
2580 PRINT "unknown";
2590 PRINT " mode"
2595 RETURN
2600 REM execute diagnostics
2610 CMD=144
2620 GOSUB 11000
2630 I=(DEEK(ER) AND 255) : REM read error register
2640 PRINT "Device 0 ";
2650 IF (I AND 127)=1 THEN PRINT "passed" : GOTO 2670
2660 PRINT "failed"
2670 PRINT "Device 1 ";
2680 IF (I AND 128) THEN PRINT "failed" : GOTO 2695
2690 PRINT "passed or not present"
2695 RETURN
2700 REM test read
2710 INPUT "Sector number";IX
2725 GOSUB 10000
2730 CMD=32
2740 GOSUB 11000
2750 REM display sector
2760 S$=""
2770 PRINT
2780 FOR WC=0 TO 255
2790 GOSUB 12000
2800 HH=(HI/256) AND 127
2810 IF HH < 32 THEN HH=46
2815 HL=HI AND 127
2820 IF HL <32 THEN HL=46
2825 S$=S$+CHR$(HL)
2830 S$=S$+CHR$(HH)
2865 PRINT " ";HEX$(HI,4);
2870 IF (WC AND 7)< >7 THEN 2885
2875 PRINT "    ";S$
2880 S$=""
2885 NEXT
2890 RETURN
2900 REM recalibrate device (seek to 0)
2910 IX=0
2920 GOSUB 10000
2930 CMD=16
2940 GOTO 11000
3000 REM change drive selection
3010 DO : INPUT "Which drive [0/1]";I
3020 LOOP WHILE (I AND -2)
3030 MD=MD AND 239
3040 IF I THEN MD=MD OR 16
3050 DOKE HR,MD+BK : REM select drive
3060 RETURN
3100 REM display allegedly selected drive
3110 PRINT "Drive ";
3120 IF (MD AND 16) THEN PRINT "1"; :GOTO 3140
3130 PRINT "0";
3140 PRINT " selected"
3150 RETURN
6000 REM read ID data and display drive parameters
6010 CMD=236
6020 GOSUB 11000
6030 GOSUB 12000
6035 REM will identify some ATAPI devices
6040 PRINT "ATA";
6050 IF (HI AND -32768) THEN PRINT "PI";
6060 PRINT " Device - ";
6070 IF (HI AND 128)=0 THEN PRINT "non";
6080 PRINT "removable media"
6085 PRINT
6090 GOSUB 12000 : CYL=HI
6100 GOSUB 12000
6110 GOSUB 12000 : HE=HI
6120 GOSUB 12000 : GOSUB 12000
6130 GOSUB 12000 : SPT=HI
6140 GOSUB 12000 : GOSUB 12000 : GOSUB 12000
6150 PRINT "Cylinders",CYL
6160 PRINT "Heads",HE
6170 PRINT "Sectors",SPT
6180 SIZE = CYL*HE*SPT/2048
6190 PRINT "Capacity",SIZE;" MB"
6195 PRINT
6200 PRINT "Serial # "," "; : CNT=10 : GOSUB 7000 : PRINT
6210 GOSUB 12000 : GOSUB 12000 : GOSUB 12000
6220 PRINT "Rev: "," "; : CNT=4 : GOSUB 7000 : PRINT
6230 PRINT "Model: "," "; : CNT=20 : GOSUB 7000 : PRINT
6240 PRINT
6250 FOR I=1 TO 7
6260 GOSUB 12000
6270 NEXT
6280 GOSUB 12000 : PRINT "Current logical cylinders",HI
6300 GOSUB 12000 : PRINT "Current logical heads",HI
6310 GOSUB 12000 : PRINT "Current logical sectors",HI
6320 GOSUB 12000 : CAP=HI
6330 GOSUB 12000 : CAP=HI*65536+CAP
6340 PRINT "Current capacity in sectors",CAP
6350 GOSUB 12000 : GOSUB 12000 : CAP=HI
6360 GOSUB 12000 : CAP=HI*65536+CAP
6370 PRINT "User addressable LBA sectors";CAP
6380 FOR I=62 TO 255 : GOSUB 12000 : NEXT
6400 RETURN
7000 REM read CNT words and output ASCII
7010 FOR I=1 TO CNT
7020 LO=PEEK(IO) : REM read data
7030 HI=PEEK(IO+1) : REM read data
7040 IF HI > 31 THEN PRINT CHR$(HI);
7050 IF LO > 31 THEN PRINT CHR$(LO);
7060 NEXT
7070 RETURN
10000 REM Set LBA block number and sector count of 1
10005 REM As BASIC only has 24 significant bits this
10006 REM routine will break if the block number is
10007 REM greater than 16777216 (just over 8GB limit!)
10010 I1=IX AND 255
10020 IX=IX/256 : I2=IX AND 255
10030 IX=IX/256 : I3=IX AND 255
10040 IX=IX/256 : I4=IX AND 15
10050 DOKE HR,I4+MD+BK : REM drive/LBA upper 4 bits
10060 DOKE SS,I1 : REM LBA bits 0 to 7
10070 DOKE CL,I2 : REM LBA bits 8 to 15
10080 DOKE CH,I3 : REM LBA bits 26 to 23
10090 DOKE SC,1 : REM sector count
10100 RETURN
11000 REM send command to drive, ensure ready
11010 DO : LOOP UNTIL (PEEK(SR) AND 192)=64 : REM get status
11020 DOKE SR,CMD : REM send command
11030 DO : I=PEEK(SR) : REM get status
11040 LOOP UNTIL (I AND 128)=0
11050 IF (I AND 1)=0 THEN RETURN
11060 I=PEEK(ER) : PRINT "IDE Error, command";CMD : REM read error register
11062 IF (I AND 2) THEN PRINT "No media"
11064 IF (I AND 4) THEN PRINT "Aborted"
11066 IF (I AND 8) THEN PRINT "Media change requested"
11068 IF (I AND 16) THEN PRINT "Sector ID not found"
11070 IF (I AND 32) THEN PRINT "Media changed"
11072 IF (I AND 64) THEN PRINT "Uncorrectable error"
11090 RETURN
12000 REM read one word, return it in HI
12010 WAIT SR,16 : REM wait status
12020 HI=DEEK(IO) : REM read data
12030 RETURN
20000 REM write C000h-DFFDh to disk
20010 AA=$C000
20030 FOR WX = 1 TO 16
20040 PRINT "Writing sector";WX
20050 IX=WX
20060 GOSUB 10000
20070 CMD=48
20080 GOSUB 11000
20090 FOR WC=1 TO 256
20120 HI=DEEK(AA)
20140 AA=AA+2
20150 GOSUB 22000
20160 NEXT
20190 NEXT
20999 RETURN
22000 REM write one word in HI
22010 DO : LOOP UNTIL (PEEK(SR) AND 144)=16 : REM get status
22020 DOKE IO,HI : REM write data
22030 RETURN