Source File 1 : 'prucode0.p' (617 Instructions Generated) 1 : : #define MEASURE_QUEUE_FULL_WRITEx 2 : : #define MEASURE_QUEUE_FULL_READx 3 : : // TODO: Allow operation of one drive in parallel with seek on other. 4 : : // 5 : : // This code is for emulating a MFM disk. The ARM puts into the 6 : : // shared DRAM a cylinder of MFM clock and data bits for each drive. 7 : : // PRU1 converts that data to PWM control values which this PRU writes 8 : : // to the ECAP peripheral to generate the MFM waveform. This PRU also handles 9 : : // the control signals from the disk controller as discussed below. 10 : : // 11 : : // The MFM bits the emulator processes are the bits labled MFM encoded idn 12 : : // http://en.wikipedia.org/wiki/Modified_Frequency_Modulation 13 : : // The emulator does not know the meaning of those bits, it just generates 14 : : // the waveform they correspond to. The most general format would be just 15 : : // storing the bit timing (transition data) but that would be much larger 16 : : // and the number of transitions varies with the data written. Just the 17 : : // data bits could be stored but disk formats use intentional encoding "error" 18 : : // to mark the start of sectors which would require special handling. This 19 : : // format was choosen since it was easy to implement and should support most 20 : : // disk formats though at the expense of larger files. 21 : : // 22 : : // Writes are handled by converting the transition timing into the clock and 23 : : // data bits and overwriting the proper spot in the track data. 24 : : // 25 : : // This code` processes the following comamnds: 26 : : // CMD_START: Start emulation 27 : : // 28 : : // Commands are read from PRU0_CMD and we then write to the same 29 : : // location the status of the command. 30 : : // If the command needs a single word of data or returns one it is in 31 : : // PRU0_CMD_DATA 32 : : // 33 : : // Time is in nominally 200 MHz clocks. The clock rate is adjusted by ARM to 34 : : // generate desired mfm clock and data bit rate. 35 : : // 36 : : // Head and select lines are on external GPIO0 module. We set up an interrupt 37 : : // so we can tell when they change without polling slow read of the GPIO0 pin 38 : : // register 39 : : // 40 : : // This PRU handles the Pulse Width Modulation (PWM) generation of 41 : : // read data to the disk controller using PWM data words from PRU 1. It also 42 : : // handles capturing the controller write data as delta time between pulses and 43 : : // sends as delta transition time words to PRU 1. 44 : : // This PRU also handles the head and drive select lines. Head select is 45 : : // handled by stopping the MFM output data, and telling PRU 1 to start 46 : : // generating data from the new head. Select is similar, when we are 47 : : // selected we tell PRU 1 to start generating data and we turn off all 48 : : // control signals when select goes away. 49 : : // 50 : : // We also handle seeks. We count the number of step pulses and update 51 : : // the cylinder number. After the steps are done we interrupt the ARM so 52 : : // it can write out the current buffer if it's dirty and fetch the new 53 : : // cylinder. It sends START command after the data is updated. 54 : : // 55 : : // TODO: The code has been sigificantly changed to use DMA to allow more 56 : : // accurate timing of the data. Some of the comments are out of date. 57 : : // 58 : : // The write data is inserted 59 : : // within a couple bits of the "proper" position using bit counts, not the 60 : : // cycle counter. The cycle counter is used so we can track rotation while 61 : : // not selected when we aren't generating bits. 62 : : // 63 : : // Don't trust the following comments. 64 : : // 65 : : // Synchronization between the two PRU's is via XFER bank 10. 66 : : // r8.w0 PRU1_BUF_OFFSET 67 : : // Transfers from PRU 1 the offset in the shared memory of the word it 68 : : // has last written or read. Set to 0 at the start of a track. 69 : : // Entire register is PRU1_BUF_STATE 70 : : // r8.b3 PRU1_STATE 71 : : // Transfers from PRU 1 the current operation state machine state. Used 72 : : // to synchronize operation of the two PRU's. 73 : : // r9.w0 PRU0_BUF_OFFSET 74 : : // Transfers from PRU 0 the offset in the shared memory of the word it 75 : : // has last written or read. Set to 0 at the start of a track. 76 : : // Entire register is PRU0_BUF_STATE 77 : : // r9.b3 PRU0_STATE 78 : : // Transfers from PRU 0 the current operation state machine state. Used 79 : : // to synchronize operation of the two PRU's. 80 : : // r18 TRACK_BIT 81 : : // Transfers from PRU 1 the bit count of the first PWM word written to 82 : : // the shared memory. Transfers from PRU 0 at start of write the bit time 83 : : // write went active to determine where PRU 1 updates track bits. 84 : : // 85 : : // Summary of state/operation transition. See code for full details of 86 : : // operation 87 : : // 88 : : // TODO: Redo this as a diagram. This isn't understandable. 89 : : // 0: Initialize PRU0_STATE(STATE_IDLE) 90 : : // 0: Wait for go command 91 : : // 0: 0track_loop: 92 : : // 0: Write PRU0_BUF_OFFSET, PRU0_STATE(STATE_READ) 93 : : // 1: 1track_loop: 94 : : // 1: Write PRU1_STATE(STATE_READ_DONE) 95 : : // 1: Wait PRU0_STATE(STATE_READ) 96 : : // 0: Wait PRU1_STATE(STATE_READ_FILLED) 97 : : // 1: Write TRACK_BIT, PRU1_STATE(STATE_READ) 98 : : // 1: 1PWM_word_loop: 99 : : // 1: Convert track word and write to shared memory and update PRU1_BUF_OFFSET 100 : : // 1: If buffer full send PRU1_STATE(STATE_READ_FILLED) 101 : : // 0: 0PWM_word_loop: 102 : : // 0: Read PWM words, update PRU0_BUF_OFFSET and send to PWM hardware 103 : : // 0: If write_gate goes active goto 0write 104 : : // 0: If seek or head change goto 0state_change 105 : : // 1: If PRU0_STATE != STATE_READ goto 1handle_state_change 106 : : // 1: If not end of data goto 1PWM_word_loop: 107 : : // 1: Write PRU word of zero (setting STATE_READ_FILLED) 108 : : // 0: If PWM word 0 not zero goto 0PWM_word_loop 109 : : // 0: Write PRU0_STATE(STATE_READ_DONE) 110 : : // 1: Wait PRU0_STATE(STATE_READ_DONE) 111 : : // 1: Write PRU1_STATE(STATE_READ_DONE) 112 : : // 1: goto 1track_loop: 113 : : // 0: Wait PRU1_STATE(STATE_READ_DONE) 114 : : // 0: Goto 0track_loop 115 : : // 116 : : // 0: 0write: 117 : : // 0: Write TRACK_BIT, PRU0_STATE(STATE_WRITE_WAIT) 118 : : // 1: 1handle_state_change: 119 : : // 1: If PRU0_STATE(STATE_READ_DONE) goto 1restart_read 120 : : // 1: IF PRU0_STATE not STATE_WRITE_WAIT halt 121 : : // 1: Read TRACK_BIT, set PRU1_STATE(STATE_WRITE_WAIT) 122 : : // 0: Wait PRU1_STATE(STATE_WRITE_WAIT) 123 : : // 0: 0write_word_loop: 124 : : // 0: Read ecap DELTA time, write to shared memory & update PRU0_BUF_OFFSET 125 : : // 0: If write not inactive goto 0write_word_loop: 126 : : // 0: goto 0write_done 127 : : // 1: 1write_word_loop: 128 : : // 1: If word available read it and update PRU1_BUF_OFFSET 129 : : // 1: If word zero goto 1write_done: 130 : : // 1: Decode and update track bits 131 : : // 1: goto 1write_word_loop: 132 : : // 0: 0write_done: 133 : : // 0: write zero delta word 134 : : // 0: wait for PRU1_STATE(STATE_WRITE_DONE) 135 : : // 0: goto 0track_loop 136 : : // 1: 1write_done: 137 : : // 1: Write PRU1_STATE(STATE_WRITE_DONE) 138 : : // 1: Wait PRU0_STATE(STATE_READ) 139 : : // 1: Goto special start track from end location of write 140 : : // 141 : : // 0: 0state_change: (handling seek/head change not show) 142 : : // 0: Write PRU0_STATE(STATE_READ_DONE) 143 : : // 0: Wait PRU1_STATE(STATE_READ_DONE) 144 : : // 0: goto 0track_loop 145 : : // 1: 1restart_read: 146 : : // 1: Write PRU1_STATE(STATE_READ_DONE) 147 : : // 1: Wait PRU0_STATE(STATE_READ_DONE) 148 : : // 1: goto 1track_loop 149 : : // 150 : : // 01/13/16 DHG Speed up select to try to make work with Symbolics 3640. 151 : : // Speedup was insufficient but may be useful for other systems. 152 : : // 01/07/16 DJG Move picking up initial select and head until after head mask 153 : : // calculated. 154 : : // initialized, detect reversed J2. 155 : : // 01/06/16 DJG Fix determining head mask, make sure head and select are 156 : : // initialized, detect reversed J2. 157 : : // 12/31/15 DJG Add additional step pulse checks to work with Symbolics 158 : : // 1 microsecond step pulse width. 159 : : // 07/12/15 DJG Added additional check for step pulse to prevent missing 160 : : // step when it occurs right after change in head select. 161 : : // 06/29/15 DJG Handle unbuffered/ST506 step pulses while waiting for 162 : : // ARM to send data for previous cylinder requested. 163 : : // 05/20/15 DJG Significant change to switch to DMA (on PRU1) for reading 164 : : // from DRAM and how data is syncronized to simulated rotation time. 165 : : // also some fixes for head select and MFM 422 chip control. 166 : : // The code as a number of internal consistency checks where it will halt 167 : : // if it detects problems. Added igoring upper head selelect lines if 168 : : // they aren't needed to address heads (Fixed Northstar). Assert seek 169 : : // complete if step is held active too long (Fixed Northstar). Allow 170 : : // drive to be deselected immediatly after step pulse done. 171 : : // 01/04/15 DJG Added logic to allow bit rate to be varied and the 172 : : // index pulse shifted relative to the start of the data. The index pulse 173 : : // shift compensates for the start_time_ns delay in starting read in mfm_read. 174 : : // Fixed not turning track0 off when not selected. Cleared wrap flag in ECLFG 175 : : // so transition loss will be deteced. 176 : : // 177 : : // 09/06/14 DJG Fixed deadlock between shutting down and seeking to 178 : : // next cylinder. 179 : : // 180 : : // Copyright 2014 David Gesswein. 181 : : // This file is part of MFM disk utilities. 182 : : // 183 : : // MFM disk utilities is free software: you can redistribute it and/or modify 184 : : // it under the terms of the GNU General Public License as published by 185 : : // the Free Software Foundation, either version 3 of the License, or 186 : : // (at your option) any later version. 187 : : // 188 : : // MFM disk utilities is distributed in the hope that it will be useful, 189 : : // but WITHOUT ANY WARRANTY; without even the implied warranty of 190 : : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 191 : : // GNU General Public License for more details. 192 : : // 193 : : // You should have received a copy of the GNU General Public License 194 : : // along with MFM disk utilities. If not, see . 195 : : // Code will need to change if this is changed 196 : : 197 : : .setcallreg r29.w0 198 : : #define RETREG r29 199 : : 200 : : .origin 0 201 : : .entrypoint START 202 : : 203 : : #include "prucode.hp" 204 : : 205 : : #include "inc/cmd.h" 206 : : 207 : : // These are registers that are used globally. Check registers defined in 208 : : // cmd.h if looking for free registers. 209 : : 210 : : // PWM word from PRU 1 in various forms 211 : : #define PWM_WORD r5 212 : : 213 : : // Cycle counter time to turn on index pulse 214 : : #define START_INDEX_TIME r11 215 : : // Cycle counter time to turn off index pulse 216 : : #define END_INDEX_TIME r12 217 : : 218 : : // Address of cycle counter 219 : : #define CYCLE_CNTR r17 220 : : 221 : : // r18 is TRACK_BIT defined in cmd.h 222 : : 223 : : // Register value 0 224 : : #define RZERO r19 225 : : 226 : : 227 : : // r20 is currently selected drive data memory pointer, Defined 228 : : // as DRIVE_DATA in cmd.h 229 : : // Value is 0 for drive 0, 4 for drive 1, and 1 if no drive is selected 230 : : 231 : : // Minimum space left in queue from/to PRU 1. Only set if 232 : : // MEASURE_QUEUE_FULL read/write defined 233 : : #define MIN_QUEUE_LEFT r21 234 : : 235 : : // Address and size of DDR memory region. Both not currently used 236 : : //#define DDR_SIZE r22 237 : : // Bit in GPIO or R31 for currently selected drive 238 : : #define CUR_DRIVE_SEL r22 239 : : #define DDR_ADDR r23 240 : : // r24 and r25 used by subroutines and not restored 241 : : 242 : : // 100 nanoseconds, Settle time for head/select lines after change 243 : : #define SETTLE_TIME 20 244 : : // 250 microsecond max interval between step pulses for buffered seek 245 : : // Pulses should be within 200 us 246 : : #define SEEK_FINISH_TIME 50000 247 : : // Maximum low time for step is 500 us. We allow 550. 248 : : #define STEP_MAX_LOW_TIME 110000 249 : : 250 : : // Maximum time offset between bit time from PRU 1 and time counter 251 : : // 8 microseconds in PRU clocks 252 : : #define MAX_TIME_OFFSET 8500/5 253 : : 254 : : START: 255 : 0x0000 0x240000f3 : MOV RZERO, 0 256 : : // Enable OCP master port 257 : 0x0001 0x91042480 : LBCO r0, CONST_PRUCFG, 4, 4 258 : : // Clear SYSCFG[STANDBY_INIT] to enable OCP master port 259 : 0x0002 0x1d04e0e0 : CLR r0, r0, 4 260 : 0x0003 0x81042480 : SBCO r0, CONST_PRUCFG, 4, 4 261 : : 262 : : // Configure the programmable pointer register for PRU0 by setting 263 : : // c28_pointer[15:0]field to 0x0100. This will make C28 point 264 : : // to 0x00010000 (PRU shared RAM). 265 : 0x0004 0x240100e0 : MOV r0, 0x00000100 266 : 0x0005 0x240002c1 : MOV r1, PRU0_CONTROL | CTPPR_0 : 0x0006 0x24202881 : 267 : 0x0007 0xe1002180 : SBBO r0, r1, 0, 4 268 : : 269 : : // Configure the programmable pointer register for PRU0 by 270 : : // setting c31_pointer[15:0] field to 0x0010. This will make C31 point 271 : : // to 0x80001000 (DDR memory). 272 : 0x0008 0x240010c0 : MOV r0, 0x00100000 : 0x0009 0x24000080 : 273 : 0x000a 0x240002c1 : MOV r1, PRU0_CONTROL | CTPPR_1 : 0x000b 0x24202c81 : 274 : 0x000c 0xe1002180 : SBBO r0, r1, 0, 4 275 : : 276 : : // Global enable of all host interrupts 277 : 0x000d 0x240001e0 : LDI r0, 1 278 : 0x000e 0x81100080 : SBCO r0, CONST_PRUSSINTC, GER_OFFSET, 2 279 : : 280 : : // Enable host interrupt 0 281 : 0x000f 0x240000e0 : MOV r0, HOST_NUM 282 : 0x0010 0x81342080 : SBCO r0, CONST_PRUSSINTC, HIESR_OFFSET, 4 283 : : 284 : : // Map channel 0 to host 0 285 : 0x0011 0x240800e1 : MOV r1, (INTC_HOSTMAP_REGS_OFFSET + HOST_NUM) 286 : 0x0012 0x240000e0 : MOV r0, CHN_NUM 287 : 0x0013 0x80e10000 : SBCO r0, CONST_PRUSSINTC, r1, 1 288 : : 289 : : // Map GPIO 0 interrupt to channel 0 290 : 0x0014 0x240439e1 : MOV r1, (INTC_CHNMAP_REGS_OFFSET + GPIO0_EVT) 291 : 0x0015 0x240000e0 : MOV r0, CHN_NUM 292 : 0x0016 0x80e10000 : SBCO r0, CONST_PRUSSINTC, r1, 1 293 : : 294 : : // Set to positive polarity 295 : 0x0017 0x244d00e1 : MOV r1, (INTC_REGS_BASE + INTC_SYS_INT_REGS_OFFSET) 296 : 0x0018 0x24ffffc0 : MOV r0, 0xFFFFFFFF : 0x0019 0x24ffff80 : 297 : 0x001a 0xe1002180 : SBBO r0, r1, 0, 4 298 : 0x001b 0xe1042180 : SBBO r0, r1, 4, 4 299 : : 300 : : // Set to positive edge trigger 301 : 0x001c 0xe1802193 : SBBO RZERO, r1, 0x80, 4 302 : 0x001d 0xe1842193 : SBBO RZERO, r1, 0x84, 4 303 : : 304 : : // Make sure the GPIO 0 system interrupt is cleared 305 : 0x001e 0x240039e0 : MOV r0, GPIO0_EVT 306 : 0x001f 0x81242080 : SBCO r0, CONST_PRUSSINTC, SICR_OFFSET, 4 307 : : 308 : : // Enable GPIO 0 system interrupt 309 : 0x0020 0x81282080 : SBCO r0, CONST_PRUSSINTC, EISR_OFFSET, 4 310 : : 311 : : // Enable cycle counter. We use this for timing the track/index 312 : : // 4 cycles to read 313 : 0x0021 0x240002d1 : MOV CYCLE_CNTR, PRU0_CONTROL | CYCLE : 0x0022 0x24200c91 : 314 : 0x0023 0x240002c3 : MOV r3, PRU0_CONTROL | CONTROL : 0x0024 0x24200083 : 315 : 0x0025 0xf1002382 : LBBO r2, r3, 0, 4 // Read reg 316 : 0x0026 0x1f03e2e2 : SET r2, r2, 3 317 : 0x0027 0xe1002382 : SBBO r2, r3, 0, 4 // Write reg 318 : 0x0028 0xe1003193 : SBBO RZERO, CYCLE_CNTR, 0, 4 // Clear timer 319 : : 320 : : // Enable Industrial ethernet counter. We use this for delays etc 321 : : // It is slow (12 cycles) to read. TODO Might be able to use compare regs 322 : 0x0029 0x240011e0 : MOV r0, 0x011 // Enable and set increment to 1 323 : 0x002a 0x240001e1 : MOV r1, 1 // Clear overflow 324 : 0x002b 0x240000e2 : MOV r2, 0 // Compensation disabled 325 : 0x002c 0x240000e3 : MOV r3, 0 // Clear count 326 : 0x002d 0x8100fa80 : SBCO r0, CONST_IEP, 0, 16 327 : : 328 : : // Get DDR address and size. 329 : 0x002e 0x91003897 : LBCO DDR_ADDR, CONST_PRURAM, PRU_DDR_ADDR, 4 330 : : //LBCO DDR_SIZE, CONST_PRURAM, PRU_DDR_SIZE, 4 331 : : 332 : : 333 : : // No drive selected 334 : 0x002f 0x240001f4 : MOV DRIVE_DATA, 1 335 : : // Clear various variable 336 : 0x0030 0x81883893 : SBCO RZERO, CONST_PRURAM, PRU0_EXIT, 4 337 : 0x0031 0x813c3893 : SBCO RZERO, CONST_PRURAM, PRU0_HEAD_SELECT_GLITCH_VALUE, 4 338 : 0x0032 0x81403893 : SBCO RZERO, CONST_PRURAM, PRU0_HEAD_SELECT_GLITCH_COUNT, 4 339 : 0x0033 0x81803893 : SBCO RZERO, CONST_PRURAM, PRU0_DRIVE0_CUR_CYL, 4 340 : 0x0034 0x81843893 : SBCO RZERO, CONST_PRURAM, PRU0_DRIVE1_CUR_CYL, 4 341 : 0x0035 0x81a43893 : SBCO RZERO, CONST_PRURAM, PRU0_DRIVE0_LAST_ARM_CYL, 4 342 : 0x0036 0x81a83893 : SBCO RZERO, CONST_PRURAM, PRU0_DRIVE1_LAST_ARM_CYL, 4 343 : 0x0037 0x81483893 : SBCO RZERO, CONST_PRURAM, PRU0_CUR_HEAD, 4 344 : 0x0038 0x814c3893 : SBCO RZERO, CONST_PRURAM, PRU0_CUR_SELECT_HEAD, 4 345 : 0x0039 0x816c3893 : SBCO RZERO, CONST_PRURAM, PRU0_RQUEUE_UNDERRUN, 4 346 : 0x003a 0x81703893 : SBCO RZERO, CONST_PRURAM, PRU0_WQUEUE_OVERRUN, 4 347 : 0x003b 0x81503893 : SBCO RZERO, CONST_PRURAM, PRU0_SEEK_TIME, 4 348 : 0x003c 0x810c3893 : SBCO RZERO, CONST_PRURAM, PRU_TEST0, 4 349 : 0x003d 0x81103893 : SBCO RZERO, CONST_PRURAM, PRU_TEST1, 4 350 : 0x003e 0x81143893 : SBCO RZERO, CONST_PRURAM, PRU_TEST2, 4 351 : 0x003f 0x81183893 : SBCO RZERO, CONST_PRURAM, PRU_TEST3, 4 352 : 0x0040 0x811c3893 : SBCO RZERO, CONST_PRURAM, PRU_TEST4, 4 353 : 0x0041 0x81683893 : SBCO RZERO, CONST_PRURAM, PRU0_ECAP_OVERRUN, 4 354 : 0x0042 0x240000f6 : MOV CUR_DRIVE_SEL, 0 355 : : 356 : : // Set multiply only mode. Only needs to be done once 357 : 0x0043 0x240000f9 : MOV r25, 0 358 : 0x0044 0x2f000019 : XOUT 0, r25, 1 359 : : 360 : : // Set the initial state of the various control lines. Inactive is high 361 : : // for drive signals. 362 : 0x0045 0x1d02fefe : CLR r30, R30_SEEK_COMPLETE_BIT 363 : 0x0046 0x1d04fefe : CLR r30, R30_READY_BIT 364 : 0x0047 0x1d01fefe : CLR r30, R30_DRIVE0_SEL 365 : 0x0048 0x248000c0 : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) : 0x0049 0x24000080 : 366 : 0x004a 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x004b 0x24719081 : 367 : 0x004c 0xe1002180 : SBBO r0, r1, 0, 4 368 : 0x004d 0x244000c0 : MOV r0, (1 << GPIO0_DRIVE0_LED) | (1 << GPIO0_DRIVE1_LED) : 0x004e 0x24400080 : 369 : 0x004f 0x2444e0c1 : MOV r1, GPIO0 | GPIO_SETDATAOUT : 0x0050 0x24719481 : 370 : 0x0051 0xe1002180 : SBBO r0, r1, 0, 4 371 : 0x0052 0x1d03fefe : CLR r30, R30_WRITE_FAULT_BIT 372 : 0x0053 0x1d05fefe : CLR r30, R30_INDEX_BIT 373 : : #ifdef REVC 374 : 0x0054 0x1f03fefe : SET r30, R30_TRACK_0_BIT 375 : : #else 376 : : MOV r0, 1 << GPIO0_TRACK_0 377 : : MOV r1, GPIO0 | GPIO_CLEARDATAOUT 378 : : SBBO r0, r1, 0, 4 379 : : #endif 380 : : // Turn off receiving MFM write data in so we can send data out 381 : 0x0055 0x1f0ffefe : SET r30, R30_MFM0_IN_ENABLE 382 : 0x0056 0x1f0efefe : SET r30, R30_MFM1_IN_ENABLE 383 : : 384 : 0x0057 0x240000e9 : MOV PRU0_BUF_STATE, 0 385 : 0x0058 0x24000169 : MOV PRU0_STATE, STATE_IDLE 386 : 0x0059 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 387 : : 388 : 0x005a 0x240001d8 : MOV r24, (1 << GPIO1_TEST) : 0x005b 0x24000098 : 389 : 0x005c 0x244804d9 : MOV r25, GPIO1 | GPIO_CLEARDATAOUT : 0x005d 0x24c19099 : 390 : 0x005e 0xe1003998 : SBBO r24, r25, 0, 4 391 : : 392 : : #ifdef MEASURE_QUEUE_FULL_READ 393 : : MOV MIN_QUEUE_LEFT, (SHARED_PWM_READ_MASK+1) 394 : : SBCO MIN_QUEUE_LEFT, CONST_PRURAM, PRU_TEST3, 4 395 : : #endif 396 : : #ifdef MEASURE_QUEUE_FULL_WRITE 397 : : MOV MIN_QUEUE_LEFT, (SHARED_DELTAS_WRITE_MASK+1) 398 : : SBCO MIN_QUEUE_LEFT, CONST_PRURAM, PRU_TEST3, 4 399 : : #endif 400 : : 401 : 0x005f 0x2400ffe0 : MOV r0, CMD_STATUS_OK 402 : 0x0060 0x81303880 : SBCO r0, CONST_PRURAM, PRU0_CMD, 4 403 : 0x0061 0x81383893 : SBCO RZERO, CONST_PRURAM, PRU0_STATUS, 4 404 : : 405 : : // Wait for initial go from the ARM before we start acting like a drive 406 : : // We need various data set up by it before we can start 407 : : wait_initial_cmd: 408 : : // Keep our time cleared. Cycle counter stops if it overflows 409 : 0x0062 0xe1003193 : SBBO RZERO, CYCLE_CNTR, 0, 4 410 : 0x0063 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 411 : 0x0064 0x91883881 : LBCO r1, CONST_PRURAM, PRU0_EXIT, 4 412 : 0x0065 0x6b00e1e4 : QBNE EXIT, r1, 0 413 : 0x0066 0x91303881 : LBCO r1, CONST_PRURAM, PRU0_CMD, 4 414 : 0x0067 0x5101e102 : QBEQ mfm_setup, r1, CMD_START 415 : 0x0068 0x21006200 : JMP wait_initial_cmd 416 : : 417 : : mfm_setup: 418 : : // Enable GPIO lines to interrupt on rising and falling edge. 419 : : // We want to know when they change. 420 : : // Get which select line is ours and set only it to interrupt. 421 : : // Set all the head select lines to interrupt 422 : : // We OR our bits with current register contents to avoid interfering 423 : : // with other users. Minor race conditions between read and write. 424 : 0x0069 0x240000e0 : MOV r0, 0 425 : 0x006a 0x91743881 : LBCO r1, CONST_PRURAM, PRU0_DRIVE0_SELECT, 4 426 : 0x006b 0x1ee1e0e0 : SET r0, r1 427 : 0x006c 0x91783881 : LBCO r1, CONST_PRURAM, PRU0_DRIVE1_SELECT, 4 428 : 0x006d 0x5100e102 : QBEQ no_drive1, r1, 0 429 : 0x006e 0x1ee1e0e0 : SET r0, r1 430 : : no_drive1: 431 : 0x006f 0x240f00e2 : MOV r2, GPIO_DRIVE_HEAD_LINES 432 : 0x0070 0x915c3881 : LBCO r1, CONST_PRURAM, PRU0_DRIVE0_NUM_HEAD, 4 433 : 0x0071 0x91603883 : LBCO r3, CONST_PRURAM, PRU0_DRIVE1_NUM_HEAD, 4 434 : : // Use maximum for the two drives. We don't support one drive using 435 : : // reduced write and the other not 436 : 0x0072 0x1ae3e1e1 : MAX r1, r1, r3 437 : : // If greater than 8 use all head select. Otherwise ignore MSB which 438 : : // is reduced write current on earlier drives 439 : 0x0073 0x240000e3 : MOV r3, 0 440 : 0x0074 0x4908e103 : QBLT headok, r1, 8 // If 8 < heads branch, we need all lines 441 : 0x0075 0x1d0be2e2 : CLR r2, GPIO_HEAD3 442 : 0x0076 0x1f0be3e3 : SET r3, GPIO_HEAD3 443 : : headok: 444 : 0x0077 0x4904e103 : QBLT headok2, r1, 4 // If 4 < heads then we only need 3 lines else 2 445 : 0x0078 0x1d0ae2e2 : CLR r2, GPIO_HEAD2 446 : 0x0079 0x1f0ae3e3 : SET r3, GPIO_HEAD2 447 : : headok2: 448 : 0x007a 0x817c3883 : SBCO r3, CONST_PRURAM, PRU0_HEAD_MASK, 4 449 : 0x007b 0x12e2e0e0 : OR r0, r0, r2 450 : 0x007c 0x2444e0c1 : MOV r1, GPIO0 | GPIO_RISINGDETECT : 0x007d 0x24714881 : 451 : 0x007e 0xf1002182 : LBBO r2, r1, 0, 4 452 : : // Combine with what's already in the register 453 : 0x007f 0x12e2e0e2 : OR r2, r0, r2 454 : 0x0080 0xe1002182 : SBBO r2, r1, 0, 4 455 : 0x0081 0x2444e0c1 : MOV r1, GPIO0 | GPIO_FALLINGDETECT : 0x0082 0x24714c81 : 456 : 0x0083 0xf1002182 : LBBO r2, r1, 0, 4 457 : 0x0084 0x12e2e0e2 : OR r2, r0, r2 458 : 0x0085 0xe1002182 : SBBO r2, r1, 0, 4 459 : : // AND CLEAR INTERRUPT 0 460 : 0x0086 0x2444e0c1 : MOV r1, GPIO0 | GPIO_IRQSTATUS_0 : 0x0087 0x24702c81 : 461 : 0x0088 0xe1002180 : SBBO r0, r1, 0, 4 462 : : // AND ENABLE INTERRUPT 0 463 : 0x0089 0x2444e0c1 : MOV r1, GPIO0 | GPIO_IRQSTATUS_SET_0 : 0x008a 0x24703481 : 464 : 0x008b 0xe1002180 : SBBO r0, r1, 0, 4 465 : : 466 : : // Now start emulating a drive 467 : 0x008c 0x2400ffe0 : MOV r0, CMD_STATUS_OK 468 : 0x008d 0x81303880 : SBCO r0, CONST_PRURAM, PRU0_CMD, 4 469 : 0x008e 0x9194388b : LBCO START_INDEX_TIME, CONST_PRURAM, PRU0_START_INDEX_TIME, 4 470 : 0x008f 0x9198388c : LBCO END_INDEX_TIME, CONST_PRURAM, PRU0_END_INDEX_TIME, 4 471 : : // Make sure we can't trigger glitch logic in select_head 472 : 0x0090 0x241234c1 : MOV r1, 0x12345678 : 0x0091 0x24567881 : 473 : 0x0092 0x81ac3881 : SBCO r1, CONST_PRURAM, PRU0_LAST_SELECT_HEAD, 4 474 : : // Not waiting a command 475 : 0x0093 0x81643893 : SBCO RZERO, CONST_PRURAM, PRU0_WAITING_CMD, 4 476 : : // Make sure we have the current head select etc. 477 : : #ifdef REVC 478 : 0x0094 0x2301cd9d : CALL get_select_head 479 : 0x0095 0x21011100 : JMP select 480 : : #else 481 : : JMP select_head 482 : : #endif 483 : : 484 : : wait_cmd: 485 : : // Let select_head & step know we are waiting for a command 486 : 0x0096 0x240001e0 : MOV r0, 1 487 : 0x0097 0x81643880 : SBCO r0, CONST_PRURAM, PRU0_WAITING_CMD, 4 488 : : // If needed handle select or head line change interrupt? 489 : : #ifdef REVC 490 : 0x0098 0xd0f6ff79 : QBBS select, r31, CUR_DRIVE_SEL 491 : 0x0099 0xd11effca : QBBS handle_head, r31, 30 492 : : #else 493 : : QBBS select_head, r31, 30 494 : : #endif 495 : : // Got a step pulse? Only unbuffered/ST506 should do this. 496 : 0x009a 0xc907ffe9 : QBBC step, r31, R31_STEP_BIT // Doing a seek? 497 : : // Check for time wrap and if index pulse needs updating 498 : 0x009b 0x2301c19d : CALL check_rotation 499 : 0x009c 0x2301b59d : CALL set_index 500 : : // Get command and branch to correct routine. 501 : 0x009d 0x91303881 : LBCO r1, CONST_PRURAM, PRU0_CMD, 4 502 : 0x009e 0x6f01e1f8 : QBNE wait_cmd, r1, CMD_START 503 : 0x009f 0x2300a59d : CALL do_cmd_start 504 : : // If the cylinder hasn't changed start sending MFM data otherwise 505 : : // tell the arm to fetch us the correct data 506 : 0x00a0 0xf1803480 : LBBO r0, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 507 : 0x00a1 0xf1a43483 : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_LAST_ARM_CYL, 4 508 : 0x00a2 0x50e3e009 : QBEQ next_mfm, r0, r3 509 : 0x00a3 0x2301b09d : CALL send_arm_cyl 510 : 0x00a4 0x21009600 : JMP wait_cmd 511 : : 512 : : do_cmd_start: 513 : 0x00a5 0x81643893 : SBCO RZERO, CONST_PRURAM, PRU0_WAITING_CMD, 4 514 : : // This measures time from when we signaled the ARM we needed a different 515 : : // cylinder to when we got it. For performance monitoring. 516 : 0x00a6 0x910c3a80 : LBCO r0, CONST_IEP, IEP_COUNT, 4 517 : 0x00a7 0x81503880 : SBCO r0, CONST_PRURAM, PRU0_SEEK_TIME, 4 518 : 0x00a8 0x2400ffe0 : MOV r0, CMD_STATUS_OK 519 : 0x00a9 0x81303880 : SBCO r0, CONST_PRURAM, PRU0_CMD, 4 520 : 0x00aa 0x209d0000 : RET 521 : : 522 : : next_mfm: 523 : : // Turn on signals (active low) driven by inverter. These are turned 524 : : // off if drive not selected which then goes here when selected again 525 : 0x00ab 0x2301c79d : CALL set_track0 526 : 0x00ac 0x1f04fefe : SET r30, R30_READY_BIT 527 : 0x00ad 0x1f02fefe : SET r30, R30_SEEK_COMPLETE_BIT 528 : : next_mfmb: 529 : : #ifdef REVC 530 : 0x00ae 0xd0f6ff63 : QBBS select, r31, CUR_DRIVE_SEL 531 : 0x00af 0xd11effb4 : QBBS handle_head, r31, 30 532 : : #else 533 : : QBBS select_head, r31, 30 534 : : #endif 535 : 0x00b0 0xc907ffd3 : QBBC step, r31, R31_STEP_BIT // Got step pulse? 536 : : // Switch to PWM mode 537 : 0x00b1 0x81282393 : SBCO RZERO, CONST_ECAP, ECCTL1, 4 538 : : // Default width for a 1 at current data rate 539 : 0x00b2 0x91903880 : LBCO r0, CONST_PRURAM, PRU0_DEFAULT_PULSE_WIDTH, 4 540 : 0x00b3 0x81082380 : SBCO r0, CONST_ECAP, CAP1, 4 541 : 0x00b4 0x81102380 : SBCO r0, CONST_ECAP, CAP3, 4 542 : 0x00b5 0x810c2393 : SBCO RZERO, CONST_ECAP, CAP2, 4 543 : 0x00b6 0x81142393 : SBCO RZERO, CONST_ECAP, CAP4, 4 544 : 0x00b7 0x81002393 : SBCO RZERO, CONST_ECAP, TSCTR, 4 545 : : // Set APWM mode output high 546 : 0x00b8 0x240210c0 : MOV r0, 0x02100000 // low 16 is ECCTL1, upper ECCTL2 : 0x00b9 0x24000080 : 547 : 0x00ba 0x81282380 : SBCO r0, CONST_ECAP, ECCTL1, 4 548 : 0x00bb 0x1f0ffefe : SET r30, R30_MFM0_IN_ENABLE // Turn off receiving write data 549 : : 550 : : sendtrack: 551 : 0x00bc 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 // Prevent timer overflow 552 : 0x00bd 0xf1003180 : LBBO r0, CYCLE_CNTR, 0, 4 // get time 553 : 0x00be 0x81f43880 : SBCO r0, CONST_PRURAM, 0xf4, 4 554 : 0x00bf 0x24000269 : MOV PRU0_STATE, STATE_READ 555 : 0x00c0 0x24000089 : MOV PRU0_BUF_OFFSET, 0 556 : 0x00c1 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 557 : : wait_bit_set: 558 : 0x00c2 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 559 : 0x00c3 0xc907ffc0 : QBBC step, r31, R31_STEP_BIT // Got step pulse? 560 : 0x00c4 0x6f0368fe : QBNE wait_bit_set, PRU1_STATE, STATE_READ_BIT_SET 561 : : 562 : 0x00c5 0x2e850192 : XIN 10, TRACK_BIT, 4 563 : 0x00c6 0x81f83892 : SBCO TRACK_BIT, CONST_PRURAM, 0xf8, 4 564 : : 565 : 0x00c7 0x10f2f2fd : MOV r29, TRACK_BIT 566 : 0x00c8 0x918c389c : LBCO r28, CONST_PRURAM, PRU0_BIT_PRU_CLOCKS, 4 // data-rate dependent 567 : 0x00c9 0x10fcfcfc : MOV r28, r28 // NOP, multiply has one cycle latency 568 : 0x00ca 0x2e80039a : XIN 0, r26, 8 // Get multiply results (27,26=28*29) 569 : : // r26 = TRACK_BIT converted to clocks 570 : 0x00cb 0xf1003181 : LBBO r1, CYCLE_CNTR, 0, 4 // Get current time 571 : 0x00cc 0x04e1fae0 : SUB r0, r26, r1 // Offset between current time and bit time 572 : 0x00cd 0xc91fe010 : QBBC nowrap, r0, 31 573 : 0x00ce 0x919c3882 : LBCO r2, CONST_PRURAM, PRU0_ROTATION_TIME, 4 574 : 0x00cf 0x00e2e0e0 : ADD r0, r0, r2 575 : : // DUP, not needed 576 : 0x00d0 0x2406a4e2 : MOV r2, MAX_TIME_OFFSET 577 : 0x00d1 0x48e0e207 : QBLT wait_wrap, r2, r0 578 : 0x00d2 0x240001d8 : MOV r24, (1 << GPIO1_TEST) : 0x00d3 0x24000098 : 579 : 0x00d4 0x244804d9 : MOV r25, GPIO1 | GPIO_SETDATAOUT : 0x00d5 0x24c19499 : 580 : 0x00d6 0xe1003998 : SBBO r24, r25, 0, 4 581 : 0x00d7 0x2a000000 : HALT 582 : : wait_wrap: 583 : 0x00d8 0xc907ffab : QBBC step, r31, R31_STEP_BIT // Got step pulse? 584 : 0x00d9 0x2301c19d : CALL check_rotation 585 : 0x00da 0x2301b59d : CALL set_index 586 : : // Loop until CYCLE counter wraps (less than previous read in r1) 587 : 0x00db 0xf1003182 : LBBO r2, CYCLE_CNTR, 0, 4 // Get current time 588 : 0x00dc 0x76e2e1fc : QBGE wait_wrap, r1, r2 589 : : nowrap: 590 : 0x00dd 0x2406a4e2 : MOV r2, MAX_TIME_OFFSET 591 : 0x00de 0x48e0e207 : QBLT no_time_err, r2, r0 592 : 0x00df 0x240001d8 : MOV r24, (1 << GPIO1_TEST) : 0x00e0 0x24000098 : 593 : 0x00e1 0x244804d9 : MOV r25, GPIO1 | GPIO_SETDATAOUT : 0x00e2 0x24c19499 : 594 : 0x00e3 0xe1003998 : SBBO r24, r25, 0, 4 595 : 0x00e4 0x2a000000 : HALT 596 : : no_time_err: 597 : 0x00e5 0xc907ff9e : QBBC step, r31, R31_STEP_BIT // Got step pulse? 598 : 0x00e6 0x2301c19d : CALL check_rotation 599 : 0x00e7 0x2301b59d : CALL set_index 600 : : // Loop until CYCLE counter is greater than data start time (r26) 601 : 0x00e8 0xf1003182 : LBBO r2, CYCLE_CNTR, 0, 4 // Get current time 602 : 0x00e9 0x76fae2fc : QBGE no_time_err, r2, r26 603 : : 604 : : // Verify queue filled 605 : : #ifdef bolix 606 : : XIN 10, PRU1_BUF_STATE, 4 607 : : QBEQ filled, PRU1_STATE, STATE_READ_FILLED 608 : : MOV r24, (1 << GPIO1_TEST) 609 : : MOV r25, GPIO1 | GPIO_SETDATAOUT 610 : : SBBO r24, r25, 0, 4 611 : : HALT 612 : : #endif 613 : : 614 : : filled: 615 : : 616 : : // Send read MFM data to the controller. 617 : : // This reads the PWM words representing the bits from PRU 1 and 618 : : // writes them to the PWM controller. Bits 31-28 are the number 619 : : // of MFM bit times the word generates. Bits 27-24 should be ignored. 620 : : // Needs to be less than 40. currently around 27 cycles 621 : : read: 622 : 0x00ea 0x90893c85 : LBCO PWM_WORD, CONST_PRUSHAREDRAM, PRU0_BUF_OFFSET, 4 // 3 cycles 623 : : // Increment and wrap if needed 624 : 0x00eb 0x01048989 : ADD PRU0_BUF_OFFSET, PRU0_BUF_OFFSET, 4 625 : 0x00ec 0x111f8989 : AND PRU0_BUF_OFFSET, PRU0_BUF_OFFSET, SHARED_PWM_READ_MASK 626 : 0x00ed 0x5100e518 : QBEQ end_track, PWM_WORD, 0 // Time 0 marks end of data 627 : 0x00ee 0x0b1ce5e3 : LSR r3, PWM_WORD, 28 // Save bit count for loadit: 628 : 0x00ef 0x24000065 : MOV PWM_WORD.b3, 0 // Clear count 629 : : // Send our read offset into shared memory to PRU 1 and get its write offset 630 : 0x00f0 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 631 : 0x00f1 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 632 : : // Either calculate how much space is in queue or simple did it wrap check 633 : : #ifdef MEASURE_QUEUE_FULL_READ 634 : : // MSB set indicates writer done so don't check 635 : : QBBS chke, PRU1_BUF_STATE, 16 636 : : // Calculate words in queue handling queue wrap 637 : : SUB r0, PRU1_BUF_OFFSET, PRU0_BUF_OFFSET 638 : : QBBC notneg, r0, 31 639 : : ADD r0, r0, (SHARED_PWM_READ_MASK+1) 640 : : notneg: 641 : : QBGE chke, MIN_QUEUE_LEFT, r0 642 : : MOV MIN_QUEUE_LEFT, r0 643 : : SBCO MIN_QUEUE_LEFT, CONST_PRURAM, PRU_TEST3, 4 644 : : SBCO PRU0_BUF_STATE, CONST_PRURAM, PRU_TEST1, 4 645 : : SBCO PRU1_BUF_STATE, CONST_PRURAM, PRU_TEST2, 4 646 : : #else 647 : 0x00f2 0x68888906 : QBNE notfullr, PRU0_BUF_OFFSET, PRU1_BUF_OFFSET 648 : 0x00f3 0x916c3880 : LBCO r0, CONST_PRURAM, PRU0_RQUEUE_UNDERRUN, 4 649 : 0x00f4 0x0101e0e0 : ADD r0, r0, 1 650 : 0x00f5 0x816c3880 : SBCO r0, CONST_PRURAM, PRU0_RQUEUE_UNDERRUN, 4 651 : 0x00f6 0x81103889 : SBCO PRU0_BUF_STATE, CONST_PRURAM, PRU_TEST1, 4 652 : 0x00f7 0x81143888 : SBCO PRU1_BUF_STATE, CONST_PRURAM, PRU_TEST2, 4 653 : : notfullr: 654 : : #endif 655 : : 656 : : chke: 657 : 0x00f8 0x912e0380 : LBCO r0, CONST_ECAP, ECFLG, 2 // did PWM read shadow regs? 4 cycles 658 : 0x00f9 0xd106e007 : QBBS loadit, r0, 6 // Yes, load a new one 659 : 0x00fa 0xc900ffe9 : QBBC write, r31, R31_WRITE_GATE // If write gate active handle it 660 : : #ifdef REVC 661 : 0x00fb 0xd0f6ff16 : QBBS select, r31, CUR_DRIVE_SEL 662 : 0x00fc 0xd11eff67 : QBBS handle_head, r31, 30 663 : : #else 664 : : QBBS select_head, r31, 30 665 : : #endif 666 : 0x00fd 0xc907ff86 : QBBC step, r31, R31_STEP_BIT // Doing a seek? 667 : 0x00fe 0x2301b59d : CALL set_index // Keep index pulse updated 668 : 0x00ff 0x2100f800 : JMP chke // Check PWM again 669 : : loadit: 670 : 0x0100 0x81100385 : SBCO PWM_WORD.w0, CONST_ECAP, CAP3, 2 // Update shadow period, 2 cycles 671 : 0x0101 0x811403c5 : SBCO PWM_WORD.w2, CONST_ECAP, CAP4, 2 // Update shadow width, 2 cycles 672 : 0x0102 0x81300380 : SBCO r0, CONST_ECAP, ECCLR, 2 // Clear flag, 2 cycles 673 : : // Moved here since this is when the word actually loaded into 674 : : // hardware and to prevent write seeing an updated count that is 675 : : // past end of data. If this increments past last bit the next 676 : : // word we see in read should be a zero which will reset 677 : 0x0103 0x00e3f2f2 : ADD TRACK_BIT, TRACK_BIT, r3 // Update bit count 678 : 0x0104 0x2100ea00 : JMP read 679 : : end_track: 680 : : // Starting a new track at the beginning. Reset time and counters to 681 : : // beginning. 682 : 0x0105 0x240000f2 : MOV TRACK_BIT, 0 683 : 0x0106 0xf1003181 : LBBO r1, CYCLE_CNTR, 0, 4 684 : 0x0107 0x81f03881 : SBCO r1, CONST_PRURAM, 0xf0, 4 685 : 0x0108 0x240032c2 : MOV r2, 165000*20 : 0x0109 0x245aa082 : 686 : 0x010a 0x58e2e102 : QBLE clrok, r1, r2 687 : 0x010b 0x2a000000 : halt 688 : : clrok: 689 : : #ifdef ignore 690 : : MOV r24, (1 << GPIO1_TEST) 691 : : MOV r25, GPIO1 | GPIO_SETDATAOUT 692 : : SBBO r24, r25, 0, 4 693 : : SBBO r24, r25, 0, 4 694 : : #endif 695 : 0x010c 0xe1003193 : SBBO RZERO, CYCLE_CNTR, 0, 4 // Set time to beginning of track 696 : 0x010d 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 // Prevent overflow and halt 697 : : #ifdef ignore 698 : : MOV r24, (1 << GPIO1_TEST) 699 : : MOV r25, GPIO1 | GPIO_CLEARDATAOUT 700 : : SBBO r24, r25, 0, 4 701 : : #endif 702 : 0x010e 0x91883881 : LBCO r1, CONST_PRURAM, PRU0_EXIT, 4 703 : 0x010f 0x5700e1db : QBEQ read, r1, 0 704 : 0x0110 0x21024900 : JMP EXIT 705 : : 706 : : #ifdef REVC 707 : : select: 708 : : // Stop PRU 1. We will check stopped later 709 : 0x0111 0x24000569 : MOV PRU0_STATE, STATE_READ_DONE 710 : 0x0112 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 711 : : // Special case of step will restart here when it started 712 : : // a step but didn't actually need to. 713 : : step_restart: 714 : : // If we we aren't selected anymore handle it 715 : 0x0113 0x91743896 : LBCO CUR_DRIVE_SEL, CONST_PRURAM, PRU0_DRIVE0_SELECT, 4 716 : 0x0114 0x5100f61b : QBEQ selected0, CUR_DRIVE_SEL, 0 // If zero always selected (radial select) 717 : 0x0115 0xc8f6ff1a : QBBC selected0, r31, CUR_DRIVE_SEL // Branch if matches drive 0 select 718 : 0x0116 0x91783896 : LBCO CUR_DRIVE_SEL, CONST_PRURAM, PRU0_DRIVE1_SELECT, 4 719 : 0x0117 0x5100f632 : QBEQ notsel, CUR_DRIVE_SEL, 0 // If zero no second drive 720 : 0x0118 0xd0f6ff31 : QBBS notsel, r31, CUR_DRIVE_SEL 721 : : 722 : : // If this drive is currently selected we don't have to do anything 723 : 0x0119 0x5104f42a : QBEQ selected, DRIVE_DATA, DRIVE_DATA_BYTES 724 : 0x011a 0x240004f4 : MOV DRIVE_DATA, DRIVE_DATA_BYTES // Offset of drive 1 data 725 : 0x011b 0x1f04fefe : SET r30, R30_READY_BIT 726 : 0x011c 0x1f02fefe : SET r30, R30_SEEK_COMPLETE_BIT 727 : : // Cylinder of currently selected drive 728 : 0x011d 0xf1803483 : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 729 : 0x011e 0x5100e303 : QBEQ track0a, r3, 0 730 : 0x011f 0x1d03fefe : CLR r30, R30_TRACK_0_BIT 731 : 0x0120 0x21012200 : JMP finish1 732 : : track0a: 733 : 0x0121 0x1f03fefe : SET r30, R30_TRACK_0_BIT 734 : : finish1: 735 : : // Turn on drive 1 select and LED and off drive 0 736 : 0x0122 0x248000c0 : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) | (1 << GPIO0_DRIVE0_LED) : 0x0123 0x24400080 : 737 : 0x0124 0x2444e0c1 : MOV r1, GPIO0 | GPIO_SETDATAOUT : 0x0125 0x24719481 : 738 : 0x0126 0xe1002180 : SBBO r0, r1, 0, 4 739 : 0x0127 0x244000c0 : MOV r0, (1 << GPIO0_DRIVE1_LED) : 0x0128 0x24000080 : 740 : 0x0129 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x012a 0x24719081 : 741 : 0x012b 0xe1002180 : SBBO r0, r1, 0, 4 742 : 0x012c 0x1d01fefe : CLR r30, R30_DRIVE0_SEL 743 : 0x012d 0x21014300 : JMP selected 744 : : 745 : : selected_always: 746 : : // Point to a bit that will always be zero to prevent calling 747 : : // select 748 : 0x012e 0x240014f6 : MOV CUR_DRIVE_SEL, 20 749 : : selected0: 750 : : // If this drive is currently selected we don't have to do anything 751 : 0x012f 0x5100f414 : QBEQ selected, DRIVE_DATA, 0 752 : 0x0130 0x240000f4 : MOV DRIVE_DATA, 0 753 : 0x0131 0x1f04fefe : SET r30, R30_READY_BIT 754 : 0x0132 0x1f02fefe : SET r30, R30_SEEK_COMPLETE_BIT 755 : : // Cylinder of currently selected drive 756 : 0x0133 0xf1803483 : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 757 : 0x0134 0x5100e303 : QBEQ track0b, r3, 0 758 : 0x0135 0x1d03fefe : CLR r30, R30_TRACK_0_BIT 759 : 0x0136 0x21013800 : JMP finish2 760 : : track0b: 761 : 0x0137 0x1f03fefe : SET r30, R30_TRACK_0_BIT 762 : : finish2: 763 : : // Turn on drive 0 select and LED and off drive 1 764 : 0x0138 0x248000c0 : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) | (1 << GPIO0_DRIVE0_LED) : 0x0139 0x24400080 : 765 : 0x013a 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x013b 0x24719081 : 766 : 0x013c 0xe1002180 : SBBO r0, r1, 0, 4 767 : 0x013d 0x244000c0 : MOV r0, (1 << GPIO0_DRIVE1_LED) : 0x013e 0x24000080 : 768 : 0x013f 0x2444e0c1 : MOV r1, GPIO0 | GPIO_SETDATAOUT : 0x0140 0x24719481 : 769 : 0x0141 0xe1002180 : SBBO r0, r1, 0, 4 770 : 0x0142 0x1f01fefe : SET r30, R30_DRIVE0_SEL 771 : : selected: 772 : : restart_lp: 773 : 0x0143 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 774 : 0x0144 0x6f0568ff : QBNE selected, PRU1_STATE, STATE_READ_DONE 775 : 0x0145 0x2f050194 : XOUT 10, DRIVE_DATA, 4 // Send currently selected drive offset. 776 : : // We are selected so turn on selected signal 777 : : // If we are not waiting for a command start outputting MFM data else 778 : : // return to waiting for a command 779 : 0x0146 0x91643880 : LBCO r0, CONST_PRURAM, PRU0_WAITING_CMD, 4 780 : 0x0147 0x5700e067 : QBEQ next_mfmb, r0, 0 781 : 0x0148 0x21009600 : JMP wait_cmd 782 : : 783 : : 784 : : // We aren't selected, turn off signals and wait for select again 785 : : notsel: 786 : : // Indicate no drive selected 787 : 0x0149 0x240001f4 : MOV DRIVE_DATA, 1 788 : : // Turn off all the control signals since we aren't selected 789 : 0x014a 0x1d02fefe : CLR r30, R30_SEEK_COMPLETE_BIT 790 : 0x014b 0x1d04fefe : CLR r30, R30_READY_BIT 791 : 0x014c 0x1d01fefe : CLR r30, R30_DRIVE0_SEL 792 : 0x014d 0x1d05fefe : CLR r30, R30_INDEX_BIT 793 : 0x014e 0x1d03fefe : CLR r30, R30_TRACK_0_BIT 794 : 0x014f 0x244000c0 : MOV r0, (1 << GPIO0_DRIVE0_LED) | (1 << GPIO0_DRIVE1_LED) : 0x0150 0x24400080 : 795 : 0x0151 0x2444e0c1 : MOV r1, GPIO0 | GPIO_SETDATAOUT : 0x0152 0x24719481 : 796 : 0x0153 0xe1002180 : SBBO r0, r1, 0, 4 797 : 0x0154 0x248000c0 : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) : 0x0155 0x24000080 : 798 : 0x0156 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x0157 0x24719081 : 799 : 0x0158 0xe1002180 : SBBO r0, r1, 0, 4 800 : 0x0159 0x810c2393 : SBCO RZERO, CONST_ECAP, CAP2, 4 // Turn off data 801 : 0x015a 0x240000f6 : MOV CUR_DRIVE_SEL, 0 802 : : 803 : : waitsel: 804 : : // Check if we should exit 805 : 0x015b 0x91883881 : LBCO r1, CONST_PRURAM, PRU0_EXIT, 4 806 : 0x015c 0x6900e1ed : QBNE EXIT, r1, 0 807 : 0x015d 0x91303881 : LBCO r1, CONST_PRURAM, PRU0_CMD, 4 808 : 0x015e 0x5101e117 : QBEQ handle_start, r1, CMD_START // And start, update seek time 809 : : // Keep track of drive rotation while waiting 810 : 0x015f 0x2301c19d : CALL check_rotation 811 : : // Are we selected? 812 : 0x0160 0xcf0effb1 : QBBC select, r31, R31_SEL1_BIT 813 : 0x0161 0xcf10ffb0 : QBBC select, r31, R31_SEL2_BIT 814 : 0x0162 0x21015b00 : JMP waitsel 815 : : 816 : : handle_head: 817 : : // Stop PRU 1. We will check stopped later 818 : 0x0163 0x24000569 : MOV PRU0_STATE, STATE_READ_DONE 819 : 0x0164 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 820 : : // Clear GPIO 0 interrupt before reading value so if it changes we will 821 : : // get a new interrupt and not miss a change 822 : 0x0165 0x2444e0c1 : MOV r1, GPIO0 | GPIO_IRQSTATUS_0 : 0x0166 0x24702c81 : 823 : : // Clear all the lines we use 824 : 0x0167 0x240f00e4 : MOV r4, GPIO_DRIVE_HEAD_LINES 825 : 0x0168 0xe1002184 : SBBO r4, r1, 0, 4 826 : : // This read is needed to prevent extra interrupts. Since 827 : : // writes are posted the actual register write may happen after 828 : : // we clear the flag in int controller below unless we read it 829 : : // back to make sure the write is done. Is glitch logic really 830 : : // needed? Replaced by getting head 831 : : //LBBO r4, r1, 0, 4 832 : : // Copy current value and get new head and select 833 : 0x0169 0x2301cd9d : CALL get_select_head 834 : : 835 : : // Clear interrupt status flag in interrupt controller 836 : 0x016a 0x240039e0 : MOV r0, GPIO0_EVT 837 : 0x016b 0x81242080 : SBCO r0, CONST_PRUSSINTC, SICR_OFFSET, 4 838 : : 839 : 0x016c 0x91ac3881 : LBCO r1, CONST_PRURAM, PRU0_LAST_SELECT_HEAD, 4 840 : 0x016d 0x81ac3898 : SBCO r24, CONST_PRURAM, PRU0_LAST_SELECT_HEAD, 4 // Update 841 : : // If they are the same report a glitch for debugging 842 : 0x016e 0x50e1f802 : QBEQ glitch, r24, r1 843 : 0x016f 0x21014300 : JMP selected 844 : : 845 : : #else 846 : : 847 : : // Handle GPIO interrupt from head or select lines changing 848 : : // This routine needs to be under 1us from head change to 849 : : // reatching next_mfm where we check for step pulses to prevent 850 : : // loosing pulses. We currently are around .7 us 851 : : // Must set valid head and select before leaving routine 852 : : select_head: 853 : : // Stop PRU 1. We will check stopped later 854 : : MOV PRU0_STATE, STATE_READ_DONE 855 : : XOUT 10, PRU0_BUF_STATE, 4 856 : : // Removed to try to speed up select. Doesn't seem to be needed. 857 : : // // Wait a little bit for the lines to settle 858 : : // LBCO r1, CONST_IEP, IEP_COUNT, 4 // Get time 859 : : // ADD r1, r1, SETTLE_TIME // How long to wait 860 : : //settle_lp: 861 : : // LBCO r4, CONST_IEP, IEP_COUNT, 4 // Get time 862 : : // QBLT settle_lp, r1, r4 // Did we reach settle time, no 863 : : // Clear GPIO 0 interrupt before reading value so if it changes we will 864 : : // get a new interrupt and not miss a change 865 : : MOV r1, GPIO0 | GPIO_IRQSTATUS_0 866 : : // Clear all the lines we use 867 : : MOV r4, GPIO_DRIVE_SELECT_HEAD_LINES 868 : : SBBO r4, r1, 0, 4 869 : : // This read is needed to prevent extra interrupts. Since 870 : : // writes are posted the actual register write may happen after 871 : : // we clear the flag in int controller below unless we read it 872 : : // back to make sure the write is done. Is glitch logic really 873 : : // needed? Replaced by getting head 874 : : //LBBO r4, r1, 0, 4 875 : : // Copy current value and get new head and select 876 : : CALL get_select_head 877 : : 878 : : // Clear interrupt status flag in interrupt controller 879 : : MOV r0, GPIO0_EVT 880 : : SBCO r0, CONST_PRUSSINTC, SICR_OFFSET, 4 881 : : 882 : : LBCO r1, CONST_PRURAM, PRU0_LAST_SELECT_HEAD, 4 883 : : SBCO r24, CONST_PRURAM, PRU0_LAST_SELECT_HEAD, 4 // Update 884 : : // If they are the same report a glitch for debugging 885 : : QBEQ glitch, r24, r1 886 : : 887 : : // Glitch comes back here after handling it 888 : : restart_lp: 889 : : XIN 10, PRU1_BUF_STATE, 4 890 : : QBNE restart_lp, PRU1_STATE, STATE_READ_DONE 891 : : // Special case of step will restart here when it started 892 : : // a step but didn't actually need to. 893 : : step_restart: 894 : : // If we we aren't selected anymore handle it 895 : : LBCO CUR_DRIVE_SEL, CONST_PRURAM, PRU0_DRIVE0_SELECT, 4 896 : : QBEQ selected0, CUR_DRIVE_SEL, 0 // If zero always selected (radial select) 897 : : QBBC selected0, r24, CUR_DRIVE_SEL // Branch if matches drive 0 select 898 : : LBCO CUR_DRIVE_SEL, CONST_PRURAM, PRU0_DRIVE1_SELECT, 4 899 : : QBEQ notsel, CUR_DRIVE_SEL, 0 // If zero no second drive 900 : : QBBS notsel, r24, CUR_DRIVE_SEL 901 : : // If this drive is currently selected we don't have to do anything 902 : : QBEQ selected, DRIVE_DATA, DRIVE_DATA_BYTES 903 : : MOV DRIVE_DATA, DRIVE_DATA_BYTES // Offset of drive 1 data 904 : : SET r30, R30_READY_BIT 905 : : SET r30, R30_SEEK_COMPLETE_BIT 906 : : // Cylinder of currently selected drive 907 : : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 908 : : // Turn on drive 1 select and LED and off drive 0 909 : : MOV r0, (1 << GPIO0_DRIVE1_LED) 910 : : QBEQ track0a, r3, 0 911 : : SET r0, GPIO0_TRACK_0 912 : : track0a: 913 : : MOV r1, GPIO0 | GPIO_CLEARDATAOUT 914 : : SBBO r0, r1, 0, 4 915 : : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) | (1 << GPIO0_DRIVE0_LED) 916 : : QBNE not_track0a, r3, 0 917 : : SET r0, GPIO0_TRACK_0 918 : : not_track0a: 919 : : MOV r1, GPIO0 | GPIO_SETDATAOUT 920 : : SBBO r0, r1, 0, 4 921 : : CLR r30, R30_DRIVE0_SEL 922 : : JMP selected 923 : : selected0: 924 : : // If this drive is currently selected we don't have to do anything 925 : : QBEQ selected, DRIVE_DATA, 0 926 : : MOV DRIVE_DATA, 0 927 : : SET r30, R30_READY_BIT 928 : : SET r30, R30_SEEK_COMPLETE_BIT 929 : : // Cylinder of currently selected drive 930 : : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 931 : : // Turn on drive 0 select and LED and off drive 1 932 : : MOV r0, (1 << GPIO0_DRIVE1_SEL_RECOVERY) | (1 << GPIO0_DRIVE0_LED) 933 : : QBEQ track0b, r3, 0 934 : : SET r0, GPIO0_TRACK_0 935 : : track0b: 936 : : MOV r1, GPIO0 | GPIO_CLEARDATAOUT 937 : : SBBO r0, r1, 0, 4 938 : : MOV r0, (1 << GPIO0_DRIVE1_LED) 939 : : QBNE not_track0b, r3, 0 940 : : SET r0, GPIO0_TRACK_0 941 : : not_track0b: 942 : : MOV r1, GPIO0 | GPIO_SETDATAOUT 943 : : SBBO r0, r1, 0, 4 944 : : SET r30, R30_DRIVE0_SEL 945 : : selected: 946 : : XOUT 10, DRIVE_DATA, 4 // Send currently selected drive offset. 947 : : // We are selected so turn on selected signal 948 : : // If we are not waiting for a command start outputting MFM data else 949 : : // return to waiting for a command 950 : : LBCO r0, CONST_PRURAM, PRU0_WAITING_CMD, 4 951 : : QBEQ next_mfmb, r0, 0 952 : : JMP wait_cmd 953 : : 954 : : 955 : : // We aren't selected, turn off signals and wait for select again 956 : : notsel: 957 : : // Indicate no drive selected 958 : : MOV DRIVE_DATA, 1 959 : : // Turn off all the control signals since we aren't selected 960 : : CLR r30, R30_SEEK_COMPLETE_BIT 961 : : CLR r30, R30_READY_BIT 962 : : CLR r30, R30_DRIVE0_SEL 963 : : CLR r30, R30_INDEX_BIT 964 : : MOV r0, (1 << GPIO0_DRIVE0_LED) | (1 << GPIO0_DRIVE1_LED) 965 : : MOV r1, GPIO0 | GPIO_SETDATAOUT 966 : : SBBO r0, r1, 0, 4 967 : : MOV r0, (1 << GPIO0_TRACK_0) | (1 << GPIO0_DRIVE1_SEL_RECOVERY) 968 : : MOV r1, GPIO0 | GPIO_CLEARDATAOUT 969 : : SBBO r0, r1, 0, 4 970 : : SBCO RZERO, CONST_ECAP, CAP2, 4 // Turn off data 971 : : MOV CUR_DRIVE_SEL, 0 972 : : 973 : : // Turn on receiving write data to turn off data output 974 : : CLR r30, R30_MFM0_IN_ENABLE 975 : : // switch to capture mode to prevent fighting over pin 976 : : SBCO RZERO, CONST_ECAP, ECCTL1, 4 // Stop capture/pwm 977 : : SBCO RZERO, CONST_ECAP, TSCTR, 4 // Clear counter 978 : : MOV r0, 0x1e01aa // ECCTL1 = 0x01aa & ECCTL2 = 0x1e 979 : : MOV r1, 0 // ECEINT and ECFLG 980 : : MOV r2, 0x1e // ECCLR = 0x1e, ECFRC 981 : : SBCO r0, CONST_ECAP, ECCTL1, 12 // Load above registers 982 : : waitsel: 983 : : // Check if we should exit 984 : : LBCO r1, CONST_PRURAM, PRU0_EXIT, 4 985 : : QBNE EXIT, r1, 0 986 : : LBCO r1, CONST_PRURAM, PRU0_CMD, 4 987 : : QBEQ handle_start, r1, CMD_START // And start, update seek time 988 : : // Keep track of drive rotation while waiting 989 : : CALL check_rotation 990 : : QBBS select_head, r31, 30 991 : : JMP waitsel 992 : : 993 : : #endif 994 : : 995 : : 996 : : glitch: 997 : 0x0170 0x813c3898 : SBCO r24, CONST_PRURAM, PRU0_HEAD_SELECT_GLITCH_VALUE, 4 998 : 0x0171 0x91403881 : LBCO r1, CONST_PRURAM, PRU0_HEAD_SELECT_GLITCH_COUNT, 4 999 : 0x0172 0x0101e1e1 : ADD r1, r1, 1 1000 : 0x0173 0x81403881 : SBCO r1, CONST_PRURAM, PRU0_HEAD_SELECT_GLITCH_COUNT, 4 1001 : 0x0174 0x21014300 : JMP restart_lp 1002 : : 1003 : : handle_start: 1004 : 0x0175 0x2300a59d : CALL do_cmd_start 1005 : : // For unbuffered seeks if after we started the first seek we get 1006 : : // more step pulses and then the drive is deselected this logic will 1007 : : // fetch the correct cylinder. We check both drives in case the 1008 : : // other drive was selected for a short time. 1009 : 0x0176 0x240000f4 : MOV DRIVE_DATA, 0 1010 : 0x0177 0xf1803480 : LBBO r0, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1011 : 0x0178 0xf1a43483 : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_LAST_ARM_CYL, 4 1012 : 0x0179 0x68e3e007 : QBNE handle_cyl_change, r0, r3 1013 : 0x017a 0x240004f4 : MOV DRIVE_DATA, DRIVE_DATA_BYTES 1014 : 0x017b 0xf1803480 : LBBO r0, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1015 : 0x017c 0xf1a43483 : LBBO r3, DRIVE_DATA, PRU0_DRIVE0_LAST_ARM_CYL, 4 1016 : 0x017d 0x68e3e003 : QBNE handle_cyl_change, r0, r3 1017 : 0x017e 0x240001f4 : MOV DRIVE_DATA, 1 // Mark as not selected to reset DRIVE_DATA 1018 : 0x017f 0x21015b00 : JMP waitsel 1019 : : handle_cyl_change: 1020 : 0x0180 0x2301b09d : CALL send_arm_cyl 1021 : 0x0181 0x240001f4 : MOV DRIVE_DATA, 1 // Mark as not selected to reset DRIVE_DATA 1022 : 0x0182 0x21015b00 : JMP waitsel 1023 : : 1024 : : // Handle seeks. We count the number of step pulses that are within 1025 : : // SEEK_FINISH_TIME and add/subtract from current cylinder based on 1026 : : // direction signal. After we have final cylinder we tell the ARM to 1027 : : // get us the cylinder data. 1028 : : step: 1029 : 0x0183 0x810c2393 : SBCO RZERO, CONST_ECAP, CAP2, 4 // Turn off data 1030 : 0x0184 0x1d02fefe : CLR r30, R30_SEEK_COMPLETE_BIT // Indicate seek in progress 1031 : : 1032 : : // Get current cylinder for selected drive 1033 : 0x0185 0xf1803481 : LBBO r1, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1034 : 0x0186 0xd106ff06 : QBBS step_out, R31, R31_SEEK_DIR_BIT // Which direction 1035 : : // Direction is in, higher cyl, Limit cylinder value to number of cyl-1 1036 : 0x0187 0xf1543480 : LBBO r0, DRIVE_DATA, PRU0_DRIVE0_NUM_CYL, 4 1037 : 0x0188 0x0501e0e0 : SUB r0, r0, 1 1038 : 0x0189 0x50e0e105 : QBEQ step_done, r1, r0 // At limit, ignore 1039 : 0x018a 0x0101e1e1 : ADD r1, r1, 1 1040 : 0x018b 0x21018e00 : JMP step_done 1041 : : step_out: 1042 : 0x018c 0x5100e102 : QBEQ step_done, r1, 0 // At limit, ignore 1043 : 0x018d 0x0501e1e1 : SUB r1, r1, 1 1044 : : step_done: 1045 : 0x018e 0x10e1e1e3 : MOV r3, r1 // Save for later 1046 : : // Tell other PRU read done and wait for other PRU to acknowledge 1047 : 0x018f 0x24000569 : MOV PRU0_STATE, STATE_READ_DONE 1048 : 0x0190 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 1049 : : step_done_lp: 1050 : 0x0191 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 1051 : 0x0192 0x6f0568ff : QBNE step_done_lp, PRU1_STATE, STATE_READ_DONE 1052 : : // Reset timer for step pulse timeout 1053 : 0x0193 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 1054 : : // Wait this long for step to go inactive 1055 : 0x0194 0x240001c1 : MOV r1, STEP_MAX_LOW_TIME : 0x0195 0x24adb081 : 1056 : : waitstephigh: 1057 : : // Keep our time and index signal updated while waiting 1058 : 0x0196 0x2301c19d : CALL check_rotation 1059 : 0x0197 0x2301b59d : CALL set_index 1060 : 0x0198 0xd107ff0a : QBBS stephigh, r31, R31_STEP_BIT 1061 : 0x0199 0x910c3a80 : LBCO r0, CONST_IEP, IEP_COUNT, 4 1062 : 0x019a 0x4ee0e1fc : QBLT waitstephigh, r1, r0 1063 : : // The Northstar controller waits for drive ready with step low. 1064 : : // This is ok for ST506 which don't indicate seek in progress until 1065 : : // step goes inactive. Later drives and this code set seek in progress 1066 : : // when step goes active. 1067 : : // If step is active greater than the limit we set seek in 1068 : : // progress inactive and wait for step to go high to restart operation, 1069 : : // or drive to not be selected. No seek is performed in these cases. It 1070 : : // probably would be better to output data but that is difficult with 1071 : : // current logic. 1072 : 0x019b 0x1f02fefe : SET r30, R30_SEEK_COMPLETE_BIT // Indicate seek not in progress 1073 : : waitstephigh2: 1074 : : // Keep our time and index signal updated while waiting 1075 : 0x019c 0x2301c19d : CALL check_rotation 1076 : 0x019d 0x2301b59d : CALL set_index 1077 : : #ifdef REVC 1078 : 0x019e 0xd6f6ff73 : QBBS select, r31, CUR_DRIVE_SEL 1079 : 0x019f 0xd71effc4 : QBBS handle_head, r31, 30 1080 : : #else 1081 : : QBBS select_head, r31, 30 1082 : : #endif 1083 : 0x01a0 0xcf07fffc : QBBC waitstephigh2, r31, R31_STEP_BIT 1084 : : // Restart outputting with data we already have. 1085 : 0x01a1 0x21011300 : JMP step_restart 1086 : : stephigh: 1087 : : // Good seek, update cylinder 1088 : 0x01a2 0xe1803483 : SBBO r3, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1089 : : // Reset timer for step pulse timeout 1090 : 0x01a3 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 1091 : : // Wait this long for more pulse for buffered seek 1092 : 0x01a4 0x24c350e1 : MOV r1, SEEK_FINISH_TIME 1093 : : seek_lp: 1094 : 0x01a5 0xcf07ffde : QBBC step, r31, R31_STEP_BIT // Got another pulse 1095 : 0x01a6 0x2301c19d : CALL check_rotation 1096 : 0x01a7 0x2301b59d : CALL set_index 1097 : : #ifdef REVC 1098 : : // If we are no longer selected finish seek, bit low when selected 1099 : 0x01a8 0xd0f6ff03 : QBBS seek_wait_done, r31, CUR_DRIVE_SEL 1100 : : #else 1101 : : CALL get_select_head 1102 : : // If we are no longer selected finish seek, bit low when selected 1103 : : QBBS seek_wait_done, r24, CUR_DRIVE_SEL 1104 : : #endif 1105 : 0x01a9 0x910c3a80 : LBCO r0, CONST_IEP, IEP_COUNT, 4 1106 : 0x01aa 0x4ee0e1fb : QBLT seek_lp, r1, r0 1107 : : 1108 : : seek_wait_done: 1109 : : // Update track zero signal in case it changed 1110 : 0x01ab 0x2301c79d : CALL set_track0 1111 : : // If we were waiting for a command don't send interrupt, go back 1112 : : // to waiting for command 1113 : 0x01ac 0x91643880 : LBCO r0, CONST_PRURAM, PRU0_WAITING_CMD, 4 1114 : 0x01ad 0x6d00e0e9 : QBNE wait_cmd, r0, 0 1115 : : // Update data and send interrupt to ARM 1116 : 0x01ae 0x2301b09d : CALL send_arm_cyl 1117 : 0x01af 0x21009600 : JMP wait_cmd 1118 : : 1119 : : send_arm_cyl: 1120 : : // Save cylinder we sent to ARN so we can detect if more seeks done 1121 : : // while waiting. 1122 : 0x01b0 0xf1803499 : LBBO r25, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1123 : 0x01b1 0xe1a43499 : SBBO r25, DRIVE_DATA, PRU0_DRIVE0_LAST_ARM_CYL, 4 1124 : : // Send notification to Host to read next cylinder 1125 : 0x01b2 0x2400231f : MOV r31.b0, PRU0_ARM_INTERRUPT+16 1126 : : 1127 : : // Reset timer for seek time measurement 1128 : 0x01b3 0x810c3a93 : SBCO RZERO, CONST_IEP, IEP_COUNT, 4 1129 : 0x01b4 0x209d0000 : RET 1130 : : 1131 : : // Set/clear index signal based on rotation time 1132 : : set_index: 1133 : 0x01b5 0xf1003199 : LBBO r25, CYCLE_CNTR, 0, 4 1134 : : // Handle both cases, normal start and end are both before time 1135 : : // wrap and other where index starts before time wraps back to 0 and 1136 : : // ends after 1137 : 0x01b6 0x60eceb05 : QBGT indnorm, START_INDEX_TIME, END_INDEX_TIME 1138 : : // If greater than start or less than end then bit should be set 1139 : 0x01b7 0x60f9eb06 : QBGT setind, START_INDEX_TIME, r25 1140 : 0x01b8 0x48f9ec05 : QBLT setind, END_INDEX_TIME, r25 1141 : 0x01b9 0x1d05fefe : CLR r30, R30_INDEX_BIT // Turn off index 1142 : 0x01ba 0x209d0000 : RET 1143 : : indnorm: 1144 : 0x01bb 0x48f9eb04 : QBLT clrind, START_INDEX_TIME, r25 1145 : 0x01bc 0x60f9ec03 : QBGT clrind, END_INDEX_TIME, r25 1146 : : setind: 1147 : : #ifdef ignore 1148 : : MOV r24, (1 << GPIO1_TEST) 1149 : : MOV r25, GPIO1 | GPIO_SETDATAOUT 1150 : : SBBO r24, r25, 0, 4 1151 : : #endif 1152 : : 1153 : 0x01bd 0x1f05fefe : SET r30, R30_INDEX_BIT // Turn on index 1154 : : 1155 : : #ifdef ignore 1156 : : MOV r24, (1 << GPIO1_TEST) 1157 : : MOV r25, GPIO1 | GPIO_CLEARDATAOUT 1158 : : SBBO r24, r25, 0, 4 1159 : : #endif 1160 : : 1161 : 0x01be 0x209d0000 : RET 1162 : : clrind: 1163 : 0x01bf 0x1d05fefe : CLR r30, R30_INDEX_BIT // Turn off index 1164 : 0x01c0 0x209d0000 : RET 1165 : : 1166 : : // Reset timer if we passed end of track time 1167 : : check_rotation: 1168 : 0x01c1 0x919c3898 : LBCO r24, CONST_PRURAM, PRU0_ROTATION_TIME, 4 1169 : 0x01c2 0xf1003199 : LBBO r25, CYCLE_CNTR, 0, 4 // Get time 1170 : 0x01c3 0x60f9f802 : QBGT clr_time, r24, r25 // If at disk rotation time reset time 1171 : 0x01c4 0x209d0000 : RET 1172 : : clr_time: 1173 : : #ifdef ignore 1174 : : MOV r24, (1 << GPIO1_TEST) 1175 : : MOV r25, GPIO1 | GPIO_SETDATAOUT 1176 : : SBBO r24, r25, 0, 4 1177 : : #endif 1178 : : 1179 : 0x01c5 0xe1003193 : SBBO RZERO, CYCLE_CNTR, 0, 4 // Clear time 1180 : : 1181 : : #ifdef ignore 1182 : : MOV r24, (1 << GPIO1_TEST) 1183 : : MOV r25, GPIO1 | GPIO_CLEARDATAOUT 1184 : : SBBO r24, r25, 0, 4 1185 : : #endif 1186 : 0x01c6 0x209d0000 : RET 1187 : : 1188 : : // Set track 0 signal based on current cylinder 1189 : : #ifdef REVC 1190 : : set_track0: 1191 : 0x01c7 0xf1803499 : LBBO r25, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1192 : 0x01c8 0x5100f903 : QBEQ track0, r25, 0 1193 : 0x01c9 0x1d03fefe : CLR r30, R30_TRACK_0_BIT 1194 : 0x01ca 0x209d0000 : RET 1195 : : track0: 1196 : 0x01cb 0x1f03fefe : SET r30, R30_TRACK_0_BIT 1197 : 0x01cc 0x209d0000 : RET 1198 : : #else 1199 : : set_track0: 1200 : : MOV r24, 1 << GPIO0_TRACK_0 1201 : : // Cylinder of currently selected drive 1202 : : LBBO r25, DRIVE_DATA, PRU0_DRIVE0_CUR_CYL, 4 1203 : : QBEQ track0, r25, 0 1204 : : MOV r25, GPIO0 | GPIO_CLEARDATAOUT 1205 : : JMP settrack0 1206 : : track0: 1207 : : MOV r25, GPIO0 | GPIO_SETDATAOUT 1208 : : settrack0: 1209 : : SBBO r24, r25, 0, 4 1210 : : RET 1211 : : #endif 1212 : : 1213 : : // Get select and head value 1214 : : // Returns PRU0_CUR_SELECT_HEAD in r24 1215 : : get_select_head: 1216 : 0x01cd 0x2444e0d9 : MOV r25, GPIO0 | GPIO_DATIN : 0x01ce 0x24713899 : 1217 : 0x01cf 0xf1003998 : LBBO r24, r25, 0, 4 // Read bits 1218 : 0x01d0 0x240f01f9 : MOV r25, GPIO_DRIVE_SELECT_HEAD_LINES 1219 : 0x01d1 0x10f9f8f8 : AND r24, r24, r25 // Our bits 1220 : 0x01d2 0x917c3899 : LBCO r25, CONST_PRURAM, PRU0_HEAD_MASK, 4 1221 : 0x01d3 0x12f9f8f8 : OR r24, r24, r25 // Set head lines we are ignoring 1222 : : // If both write and step active things aren't correct 1223 : 0x01d4 0xd100ff03 : QBBS nowrite, r31, R31_WRITE_GATE 1224 : 0x01d5 0xd107ff02 : QBBS nowrite, r31, R31_STEP_BIT 1225 : 0x01d6 0x1f1ff8f8 : SET r24, CUR_SELECT_HEAD_WRITE_ERR 1226 : : nowrite: 1227 : 0x01d7 0x814c3898 : SBCO r24, CONST_PRURAM, PRU0_CUR_SELECT_HEAD, 4 1228 : 0x01d8 0x240f00f9 : MOV r25, GPIO_DRIVE_HEAD_LINES 1229 : 0x01d9 0x10f9f8f8 : AND r24, r24, r25 // Our head bits 1230 : 0x01da 0x14f9f8f8 : XOR r24, r24, r25 // All high is head 0 so invert 1231 : 0x01db 0x0b08f8f8 : LSR r24, r24, GPIO_HEAD0 // Move to low bits 1232 : 0x01dc 0xf15c3499 : LBBO r25, DRIVE_DATA, PRU0_DRIVE0_NUM_HEAD, 4 1233 : 0x01dd 0x0501f9f9 : SUB r25, r25, 1 // Convert to maximum value 1234 : 0x01de 0x58f8f902 : QBLE storeh1, r25, r24 1235 : 0x01df 0x10f9f9f8 : MOV r24, r25 // Greater than max so set to max 1236 : : storeh1: 1237 : 0x01e0 0x81483898 : SBCO r24, CONST_PRURAM, PRU0_CUR_HEAD, 4 1238 : 0x01e1 0x914c3898 : LBCO r24, CONST_PRURAM, PRU0_CUR_SELECT_HEAD, 4 1239 : 0x01e2 0x209d0000 : RET 1240 : : 1241 : : // Capture write data from the controller. 1242 : : // We switch the ECAP from PWM mode to capture mode 1243 : : write: 1244 : 0x01e3 0x2f050192 : XOUT 10, TRACK_BIT, 4 // Send current bit count. 1245 : 0x01e4 0x81e03892 : SBCO TRACK_BIT, CONST_PRURAM, 0xe0, 4 1246 : 0x01e5 0xf1003180 : LBBO r0, CYCLE_CNTR, 0, 4 // Get time 1247 : 0x01e6 0x81e43880 : SBCO r0, CONST_PRURAM, 0xe4, 4 1248 : 0x01e7 0x24000669 : MOV PRU0_STATE, STATE_WRITE_WAIT 1249 : 0x01e8 0x24000089 : MOV PRU0_BUF_OFFSET, 0 1250 : 0x01e9 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 1251 : : wait_pru1_write: 1252 : : // Loop until PRU1 switches to ready to take write data 1253 : 0x01ea 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 1254 : 0x01eb 0x6f0668ff : QBNE wait_pru1_write, PRU1_STATE, STATE_WRITE_WAIT 1255 : 0x01ec 0x24000769 : MOV PRU0_STATE, STATE_WRITE 1256 : 0x01ed 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 1257 : : 1258 : : // Trigger cap1 on rising edges. Reset count on trigger to get delta time 1259 : : //Enable cap1-4 buffer registers. Divide by 1, stop on emulation suspend 1260 : : // continuous mode, wrap after 4, no rearm, counter free run, no sync 1261 : : // capture mode. Reset sequencer 1262 : 0x01ee 0x6900f403 : QBNE drive1, DRIVE_DATA, 0 1263 : 0x01ef 0x1d0ffefe : CLR r30, R30_MFM0_IN_ENABLE // Turn on receiving write data 1264 : 0x01f0 0x2101f200 : JMP stop_pwm 1265 : : drive1: 1266 : 0x01f1 0x1d0efefe : CLR r30, R30_MFM1_IN_ENABLE // Turn on receiving write data 1267 : : stop_pwm: 1268 : : // Trigger positive edges only, reset ECAP CAP counter 1269 : : // This sequence of resetting ECAP and flags seems necessary to 1270 : : // get capture to start with CAP1 register which the code needs. 1271 : 0x01f2 0x81282393 : SBCO RZERO, CONST_ECAP, ECCTL1, 4 // Stop capture/pwm 1272 : 0x01f3 0x81002393 : SBCO RZERO, CONST_ECAP, TSCTR, 4 // Clear counter 1273 : 0x01f4 0x24001ec0 : MOV r0, 0x1e01aa // ECCTL1 = 0x01aa & ECCTL2 = 0x1e : 0x01f5 0x2401aa80 : 1274 : 0x01f6 0x240000e1 : MOV r1, 0 // ECEINT and ECFLG 1275 : 0x01f7 0x24001ee2 : MOV r2, 0x1e // ECCLR = 0x1e, ECFRC 1276 : 0x01f8 0x8128a380 : SBCO r0, CONST_ECAP, ECCTL1, 12 // Load above registers 1277 : : caploop: 1278 : 0x01f9 0x912e0380 : LBCO r0, CONST_ECAP, ECFLG, 2 // Read flags 1279 : : // If all flags set we may have lost a transition 1280 : 0x01fa 0x691ee002 : QBNE cnext1, r0, 0x1e 1281 : 0x01fb 0x81683880 : SBCO r0, CONST_PRURAM, PRU0_ECAP_OVERRUN, 4 1282 : : cnext1: 1283 : 0x01fc 0xd101e003 : QBBS get1, r0, 1 // Branch if cap1 has data 1284 : 0x01fd 0x2302359d : CALL checkstuff 1285 : 0x01fe 0x2101f900 : JMP caploop 1286 : : get1: 1287 : 0x01ff 0x9108238a : LBCO r10, CONST_ECAP, CAP1, 4 // Get count 1288 : 0x0200 0x0101eaea : ADD r10, r10, 1 // Count is 1 less than delta time 1289 : : // Clear overflow flag so check for flag 0x1e works 1290 : 0x0201 0x240022e0 : MOV r0, 0x22 1291 : 0x0202 0x81300380 : SBCO r0, CONST_ECAP, ECCLR, 2 // Clear flag 1292 : 0x0203 0x2302299d : CALL sendwrite 1293 : : // Repeat above for the other 3 capture registers 1294 : : chk2: 1295 : 0x0204 0x912e0380 : LBCO r0, CONST_ECAP, ECFLG, 2 1296 : 0x0205 0x691ee002 : QBNE cnext2, r0, 0x1e 1297 : 0x0206 0x81683880 : SBCO r0, CONST_PRURAM, PRU0_ECAP_OVERRUN, 4 1298 : : cnext2: 1299 : 0x0207 0xd102e003 : QBBS get2, r0, 2 1300 : 0x0208 0x2302359d : CALL checkstuff 1301 : 0x0209 0x21020400 : JMP chk2 1302 : : get2: 1303 : 0x020a 0x910c238a : LBCO r10, CONST_ECAP, CAP2, 4 1304 : 0x020b 0x0101eaea : ADD r10, r10, 1 1305 : 0x020c 0x240024e0 : MOV r0, 0x24 1306 : 0x020d 0x81300380 : SBCO r0, CONST_ECAP, ECCLR, 2 1307 : 0x020e 0x2302299d : CALL sendwrite 1308 : : chk3: 1309 : 0x020f 0x912e0380 : LBCO r0, CONST_ECAP, ECFLG, 2 1310 : 0x0210 0x691ee002 : QBNE cnext3, r0, 0x1e 1311 : 0x0211 0x81683880 : SBCO r0, CONST_PRURAM, PRU0_ECAP_OVERRUN, 4 1312 : : cnext3: 1313 : 0x0212 0xd103e003 : QBBS get3, r0, 3 1314 : 0x0213 0x2302359d : CALL checkstuff 1315 : 0x0214 0x21020f00 : JMP chk3 1316 : : get3: 1317 : 0x0215 0x9110238a : LBCO r10, CONST_ECAP, CAP3, 4 1318 : 0x0216 0x0101eaea : ADD r10, r10, 1 1319 : 0x0217 0x240028e0 : MOV r0, 0x28 1320 : 0x0218 0x81300380 : SBCO r0, CONST_ECAP, ECCLR, 2 1321 : 0x0219 0x2302299d : CALL sendwrite 1322 : : chk4: 1323 : 0x021a 0x912e0380 : LBCO r0, CONST_ECAP, ECFLG, 2 1324 : 0x021b 0x691ee002 : QBNE cnext4, r0, 0x1e 1325 : 0x021c 0x81683880 : SBCO r0, CONST_PRURAM, PRU0_ECAP_OVERRUN, 4 1326 : : cnext4: 1327 : 0x021d 0xd104e003 : QBBS get4, r0, 4 1328 : 0x021e 0x2302359d : CALL checkstuff 1329 : 0x021f 0x21021a00 : JMP chk4 1330 : : get4: 1331 : 0x0220 0x9114238a : LBCO r10, CONST_ECAP, CAP4, 4 1332 : 0x0221 0x0101eaea : ADD r10, r10, 1 1333 : 0x0222 0x240030e0 : MOV r0, 0x30 1334 : 0x0223 0x81300380 : SBCO r0, CONST_ECAP, ECCLR, 2 1335 : 0x0224 0x2302299d : CALL sendwrite 1336 : : 1337 : 0x0225 0x2301c19d : CALL check_rotation // These are slow so only do once per loop 1338 : 0x0226 0x2301b59d : CALL set_index 1339 : : // All the checkstuff above will be skipped if all capture registers 1340 : : // used. Make sure we check once. 1341 : 0x0227 0x2302359d : CALL checkstuff 1342 : 0x0228 0x2101f900 : JMP caploop 1343 : : 1344 : : // Send write delta times to PRU 1 1345 : : // r10 is word to write in 1346 : : // *** Changes r1 *** 1347 : : sendwrite: 1348 : : // Store word and update pointer 1349 : 0x0229 0x80893c8a : SBCO r10, CONST_PRUSHAREDRAM, PRU0_BUF_OFFSET, 4 1350 : 0x022a 0x01048989 : ADD PRU0_BUF_OFFSET, PRU0_BUF_OFFSET, 4 1351 : 0x022b 0x117f8989 : AND PRU0_BUF_OFFSET, PRU0_BUF_OFFSET, SHARED_DELTAS_WRITE_MASK 1352 : 0x022c 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 // Send offset to PRU 1 1353 : 0x022d 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 // Get PRU 1 offset 1354 : : // See READ version for description 1355 : : #ifdef MEASURE_QUEUE_FULL_WRITE 1356 : : QBBS chke, PRU1_BUF_STATE, 16 1357 : : SUB r24, PRU0_BUF_OFFSET, PRU1_BUF_OFFSET 1358 : : QBBC notneg, r24, 31 1359 : : ADD r24, r24, SHARED_DELTAS_WRITE_MASK 1360 : : ADD r24, r24, 1 1361 : : notneg: 1362 : : QBGE chke, MIN_QUEUE_LEFT, r24 1363 : : MOV MIN_QUEUE_LEFT, r24 1364 : : SBCO MIN_QUEUE_LEFT, CONST_PRURAM, PRU_TEST3, 4 1365 : : SBCO PRU0_BUF_STATE, CONST_PRURAM, PRU_TEST1, 4 1366 : : SBCO PRU1_BUF_STATE, CONST_PRURAM, PRU_TEST2, 4 1367 : : #else 1368 : 0x022e 0x68888906 : QBNE notfullw, PRU0_BUF_OFFSET, PRU1_BUF_OFFSET 1369 : 0x022f 0x91703898 : LBCO r24, CONST_PRURAM, PRU0_WQUEUE_OVERRUN, 4 1370 : 0x0230 0x0101f8f8 : ADD r24, r24, 1 1371 : 0x0231 0x81703898 : SBCO r24, CONST_PRURAM, PRU0_WQUEUE_OVERRUN, 4 1372 : 0x0232 0x81103889 : SBCO PRU0_BUF_STATE, CONST_PRURAM, PRU_TEST1, 4 1373 : 0x0233 0x81143888 : SBCO PRU1_BUF_STATE, CONST_PRURAM, PRU_TEST2, 4 1374 : : notfullw: 1375 : : #endif 1376 : 0x0234 0x209d0000 : RET 1377 : : 1378 : : // Check any stuff we need to at each delta. 1379 : : checkstuff: 1380 : : // Assume they will turn off write gate if they change select or head 1381 : 0x0235 0xd100ff02 : QBBS write_done, r31, R31_WRITE_GATE // Branch if write gate inactive 1382 : 0x0236 0x209d0000 : RET 1383 : : 1384 : : // Done write, switch back to read 1385 : : write_done: 1386 : : // If it writes only zeros at the end we don't handle it. Halt if this occurs 1387 : 0x0237 0x91002380 : LBCO r0, CONST_ECAP, TSCTR, 4 // Get time since last edge on MFM data 1388 : 0x0238 0x240190e1 : MOV r1, 2000/5 // Check if more than 10 microseconds 1389 : 0x0239 0x58e0e107 : QBLE noextra, r1, r0 1390 : 0x023a 0x240001d8 : MOV r24, (1 << GPIO1_TEST) : 0x023b 0x24000098 : 1391 : 0x023c 0x244804d9 : MOV r25, GPIO1 | GPIO_SETDATAOUT : 0x023d 0x24c19499 : 1392 : 0x023e 0xe1003998 : SBBO r24, r25, 0, 4 1393 : 0x023f 0x2a000000 : HALT 1394 : : noextra: 1395 : : // Just turn off both, no need to see which was on 1396 : 0x0240 0x1f0ffefe : SET r30, R30_MFM0_IN_ENABLE // Turn off receiving write data 1397 : 0x0241 0x1f0efefe : SET r30, R30_MFM1_IN_ENABLE // Turn off receiving write data 1398 : 0x0242 0x240000ea : MOV r10, 0 // Send zero to indicate end of data 1399 : 0x0243 0x2302299d : CALL sendwrite 1400 : 0x0244 0xf1003180 : LBBO r0, CYCLE_CNTR, 0, 4 // Get time 1401 : 0x0245 0x81e83880 : SBCO r0, CONST_PRURAM, 0xe8, 4 1402 : : write_done_lp: 1403 : 0x0246 0x2e850188 : XIN 10, PRU1_BUF_STATE, 4 1404 : 0x0247 0x6f0868ff : QBNE write_done_lp, PRU1_STATE, STATE_WRITE_DONE 1405 : 0x0248 0x2100ab00 : JMP next_mfm 1406 : : 1407 : : // ARM has requested us to exit 1408 : : EXIT: 1409 : 0x0249 0x1d02fefe : CLR r30, R30_SEEK_COMPLETE_BIT 1410 : 0x024a 0x1d04fefe : CLR r30, R30_READY_BIT 1411 : 0x024b 0x1d01fefe : CLR r30, R30_DRIVE0_SEL 1412 : 0x024c 0x248000c0 : MOV r0, 1 << GPIO0_DRIVE1_SEL_RECOVERY : 0x024d 0x24000080 : 1413 : 0x024e 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x024f 0x24719081 : 1414 : 0x0250 0xe1002180 : SBBO r0, r1, 0, 4 1415 : 0x0251 0x1d03fefe : CLR r30, R30_WRITE_FAULT_BIT 1416 : 0x0252 0x1d05fefe : CLR r30, R30_INDEX_BIT 1417 : 0x0253 0x244000c0 : MOV r0, 1 << GPIO0_TRACK_0 : 0x0254 0x24000080 : 1418 : 0x0255 0x2444e0c1 : MOV r1, GPIO0 | GPIO_CLEARDATAOUT : 0x0256 0x24719081 : 1419 : 0x0257 0xe1002180 : SBBO r0, r1, 0, 4 1420 : 0x0258 0x2400ffe1 : MOV r1, CMD_STATUS_OK 1421 : 0x0259 0x81303881 : SBCO r1, CONST_PRURAM, PRU0_CMD, 4 // Indicate command completed ok 1422 : : // Tell PRU 1 to exit. 1423 : 0x025a 0x24000a69 : MOV PRU0_STATE, STATE_EXIT 1424 : 0x025b 0x2f050189 : XOUT 10, PRU0_BUF_STATE, 4 1425 : 0x025c 0x24ffffc0 : MOV r0, -1 // -1 tells seek task to exit on ARM : 0x025d 0x24ffff80 : 1426 : 0x025e 0x81803880 : SBCO r0, CONST_PRURAM, PRU0_DRIVE0_CUR_CYL, 4 1427 : 0x025f 0x81843880 : SBCO r0, CONST_PRURAM, PRU0_DRIVE1_CUR_CYL, 4 1428 : : // Tell ARM to read CYL 1429 : 0x0260 0x2400231f : MOV r31.b0, PRU0_ARM_INTERRUPT+16 1430 : : wait_arm: 1431 : : // Wait for ARM to service the previous interrupt before we 1432 : : // send one for exiting. ARM sets DRIVE0_CUR_CYL to zero. 1433 : 0x0261 0x91803880 : LBCO r0, CONST_PRURAM, PRU0_DRIVE0_CUR_CYL, 4 1434 : 0x0262 0x57ff60ff : QBEQ wait_arm, r0.b3, 0xff 1435 : : // Send notification to Host for program completion 1436 : 0x0263 0x2400231f : MOV r31.b0, PRU0_ARM_INTERRUPT+16 1437 : 0x0264 0x810c2393 : SBCO RZERO, CONST_ECAP, CAP2, 4 // Turn off data 1438 : : 1439 : : // Halt the processor 1440 : 0x0265 0x2a000000 : HALT 1441 : : 1442 : : // Restarted here if the ARM wishes to abort an operation. Any needed 1443 : : // cleanup should be here to restore to a good state. Currently none 1444 : : .ORIGIN RESTART_ADDR 1445 : 0x0400 0x2400ffe0 : MOV r0, CMD_STATUS_OK 1446 : 0x0401 0x81303880 : SBCO r0, CONST_PRURAM, PRU0_CMD, 4 1447 : 0x0402 0x21009600 : JMP wait_cmd 1448 : : Source File 2 : 'prucode.hp' (No Output Generated) 1 : : // prucode.hp 2 : : 3 : : #ifndef __PRUCODE_HP__ 4 : : #define __PRUCODE_HP__ 5 : : 6 : : // Definitions 7 : : 8 : : // Refer to this mapping in the file - pruss_intc_mapping.h 9 : : #define PRU0_PRU1_INTERRUPT 17 10 : : #define PRU1_PRU0_INTERRUPT 18 11 : : #define PRU0_ARM_INTERRUPT 19 12 : : #define PRU1_ARM_INTERRUPT 20 13 : : #define ARM_PRU0_INTERRUPT 21 14 : : #define ARM_PRU1_INTERRUPT 22 15 : : 16 : : #define CONST_PRUSSINTC C0 17 : : #define CONST_DMTIMER2 C1 18 : : #define CONST_ECAP C3 19 : : #define CONST_PRUCFG C4 20 : : #define CONST_PRURAM C24 21 : : #define CONST_PRURAM_OTHER C25 22 : : #define CONST_IEP C26 23 : : #define CONST_PRUSHAREDRAM C28 24 : : #define CONST_DDR C31 25 : : 26 : : // Base addresses for the following control registers 27 : : #define PRU0_CONTROL 0x00022000 28 : : #define PRU1_CONTROL 0x00024000 29 : : // Address for the control register (CONTROL) 30 : : #define CONTROL 0x0 31 : : // Address for the cycle counter register (CYCLE) 32 : : #define CYCLE 0x0c 33 : : // Address for the Constant table Block Index Register (CTBIR) 34 : : #define CTBIR 0x20 35 : : // Address for the Constant table Block Index Register (CTBIR1) 36 : : #define CTBIR1 0x24 37 : : // Address for the Constant table Programmable Pointer Register 0(CTPPR_0) 38 : : #define CTPPR_0 0x28 39 : : // Address for the Constant table Programmable Pointer Register 1(CTPPR_1) 40 : : #define CTPPR_1 0x2C 41 : : 42 : : 43 : : // Interrupt controller registers 44 : : #define GER_OFFSET 0x10 45 : : #define HIESR_OFFSET 0x34 46 : : #define SICR_OFFSET 0x24 47 : : #define SISR_OFFSET 0x20 48 : : #define EISR_OFFSET 0x28 49 : : #define GPIR_OFFSET 0x80 50 : : #define HOST_NUM 0 51 : : #define CHN_NUM 0 52 : : 53 : : #define ECAP0_EVT 31 54 : : #define GPIO0_EVT 57 55 : : // Enhanced capture registers 56 : : #define TSCTR 0x00 57 : : #define CAP1 0x08 58 : : #define CAP2 0x0c 59 : : #define CAP3 0x10 60 : : #define CAP4 0x14 61 : : #define ECCTL1 0x28 62 : : #define ECCTL2 0x2a 63 : : #define ECFLG 0x2e 64 : : #define ECCLR 0x30 65 : : 66 : : // IEP 67 : : #define IEP_COUNT 0x0c 68 : : #define INTC_REGS_BASE 0x00004000 69 : : #define INTC_CHNMAP_REGS_OFFSET 0x0400 70 : : #define INTC_HOSTMAP_REGS_OFFSET 0x0800 71 : : #define INTC_HOSTINTPRIO_REGS_OFFSET 0x0900 72 : : #define INTC_SYS_INT_REGS_OFFSET 0x0D00 73 : : #define INTC_HOSTNEST_REGS_OFFSET 0x1100 74 : : 75 : : #define GPIO0 0x44e07000 76 : : #define GPIO1 0x4804c000 77 : : #define GPIO2 0x481Ac000 78 : : #define GPIO_IRQSTATUS_0 0x02c 79 : : #define GPIO_IRQSTATUS_1 0x030 80 : : #define GPIO_IRQSTATUS_RAW_0 0x024 81 : : #define GPIO_IRQSTATUS_RAW_1 0x028 82 : : #define GPIO_IRQSTATUS_SET_0 0x034 83 : : #define GPIO_IRQSTATUS_SET_1 0x038 84 : : #define GPIO_DATIN 0x138 85 : : #define GPIO_LEVELDECTECT0 0x140 86 : : #define GPIO_LEVELDECTECT1 0x144 87 : : #define GPIO_RISINGDETECT 0x148 88 : : #define GPIO_FALLINGDETECT 0x14c 89 : : #define GPIO_CLEARDATAOUT 0x190 90 : : #define GPIO_SETDATAOUT 0x194 91 : : 92 : : 93 : : //EDMA registers 94 : : #define EDMA0_CC_BASE 0x49000000 95 : : #define DMAQNUM0 0x0240 96 : : #define QUEPRI 0x0284 97 : : #define EMR 0x0300 98 : : #define EMCR 0x0308 99 : : #define EMCRH 0x030C 100 : : #define QEMCR 0x0314 101 : : #define CCERRCLR 0x031C 102 : : #define DRAE0 0x0340 103 : : #define DRAE1 0x0348 104 : : #define DRAE2 0x0350 105 : : #define DRAE3 0x0358 106 : : #define QWMTHRA 0x0620 107 : : #define GLOBAL_ESR 0x1010 108 : : #define GLOBAL_CER 0x1018 109 : : #define GLOBAL_EECR 0x1028 110 : : #define GLOBAL_SECR 0x1040 111 : : #define GLOBAL_IER 0x1050 112 : : #define GLOBAL_IECR 0x1058 113 : : #define GLOBAL_IESR 0x1060 114 : : #define GLOBAL_ICR 0x1070 115 : : // 0x1000 + 0x200 * region, we use region 1 116 : : #define DRAE_OFFSET 0x1200 117 : : //#define DRAE_OFFSET 0x0000 118 : : #define ESR (0x1010+DRAE_OFFSET) 119 : : #define EECR (0x1028+DRAE_OFFSET) 120 : : #define SECR (0x1040+DRAE_OFFSET) 121 : : #define IER (0x1050+DRAE_OFFSET) 122 : : #define IPR (0x1068+DRAE_OFFSET) 123 : : #define ICR (0x1070+DRAE_OFFSET) 124 : : #define IESRL (0x1060+DRAE_OFFSET) 125 : : #define IEVAL (0x1078+DRAE_OFFSET) 126 : : #define IECR (0x1058+DRAE_OFFSET) 127 : : 128 : : 129 : : //EDMA PARAM registers 130 : : #define PARAM_OFFSET 0x4000 131 : : #define OPT 0x00 132 : : #define SRC 0x04 133 : : #define A_B_CNT 0x08 134 : : #define DST 0x0C 135 : : #define SRC_DST_BIDX 0x10 136 : : #define LINK_BCNTRLD 0x14 137 : : #define SRC_DST_CIDX 0x18 138 : : #define CCNT 0x1C 139 : : 140 : : #endif // __PRUCODE_HP__ 141 : : Source File 3 : 'cmd.h' (No Output Generated) 1 : : // These defines are used in both the PRU assembly language and in the C 2 : : // code so they can only be simple defines. 3 : : 4 : : // The commands to the PRU 5 : : #define CMD_NONE 0 6 : : #define CMD_START 1 7 : : 8 : : // The command status. All commands other than CMD_READ_TRACK 9 : : // return their status when done. CMD_READ_TRACK returns 10 : : // CMD_STATUS_READ_STARTED when the read has started and CMD_STATUS_OK 11 : : // or an error status when the read is finished. 12 : : #define CMD_STATUS_OK 0x0ff 13 : : #define CMD_STATUS_READ_STARTED 0x100 14 : : 15 : : 16 : : // Registers used locally and XFER bank 10 to communicate with PRU0 17 : : #define PRU1_BUF_OFFSET r8.w0 18 : : #define PRU1_STATE r8.b3 19 : : #define PRU1_BUF_STATE r8 20 : : #define PRU0_BUF_OFFSET r9.w0 21 : : #define PRU0_STATE r9.b3 22 : : #define PRU0_BUF_STATE r9 23 : : #define TRACK_BIT r18 24 : : // 0 for first drive, 4 for second to access variables that depend on selected drive 25 : : #define DRIVE_DATA r20 26 : : 27 : : #define STATE_IDLE 1 28 : : #define STATE_READ 2 29 : : #define STATE_READ_BIT_SET 3 30 : : #define STATE_READ_FILLED 4 31 : : #define STATE_READ_DONE 5 32 : : #define STATE_WRITE_WAIT 6 33 : : #define STATE_WRITE 7 34 : : #define STATE_WRITE_DONE 8 35 : : #define STATE_RESTART_READ 9 36 : : #define STATE_EXIT 10 37 : : 38 : : // All these are the memory address to communicate with the PRU code 39 : : 40 : : // These are on both PRUs. 41 : : // Physical address and size of shared DDR memory 42 : : #define PRU_DDR_ADDR 0x00 43 : : #define PRU_DDR_SIZE 0x04 44 : : // Physical address of PRU dataram 45 : : #define PRU_DATARAM_ADDR 0x08 46 : : 47 : : #define PRU_TEST0 0x0c 48 : : #define PRU_TEST1 0x10 49 : : #define PRU_TEST2 0x14 50 : : #define PRU_TEST3 0x18 51 : : #define PRU_TEST4 0x1c 52 : : 53 : : // Command location, command data, and status 54 : : #define PRU0_CMD 0x30 55 : : #define PRU0_CMD_DATA 0x34 56 : : #define PRU0_STATUS 0x38 57 : : // Count and register value if we got a GPIO interrupt without data changing 58 : : #define PRU0_HEAD_SELECT_GLITCH_VALUE 0x3c 59 : : #define PRU0_HEAD_SELECT_GLITCH_COUNT 0x40 60 : : // Decoded head and raw bits from GPIO register. See PRU0_DRIVE#_CUR_CYL 61 : : // for current cylinder 62 : : #define PRU0_CUR_HEAD 0x48 63 : : #define PRU0_CUR_SELECT_HEAD 0x4c 64 : : // Time in 200 MHz clocks from ARM interrupt to data returned 65 : : #define PRU0_SEEK_TIME 0x50 66 : : // Number of bytes in each drive# value. 67 : : #define DRIVE_DATA_BYTES 4 68 : : // Parameters of simulated disk 69 : : #define PRU0_DRIVE0_NUM_CYL 0x54 70 : : #define PRU0_DRIVE1_NUM_CYL 0x58 71 : : #define PRU0_DRIVE0_NUM_HEAD 0x5c 72 : : #define PRU0_DRIVE1_NUM_HEAD 0x60 73 : : // Internal variable 74 : : #define PRU0_WAITING_CMD 0x64 75 : : // Overrun on ECAP if non zero 76 : : #define PRU0_ECAP_OVERRUN 0x68 77 : : // PRU 0-1 queue underrun count 78 : : #define PRU0_RQUEUE_UNDERRUN 0x6c 79 : : #define PRU0_WQUEUE_OVERRUN 0x70 80 : : // Drive select numbers we should respond to. 0 or bit number in GPIO 81 : : // register that is our drive select. Keep adjacent. 82 : : #define PRU0_DRIVE0_SELECT 0x74 83 : : #define PRU0_DRIVE1_SELECT 0x78 84 : : // The select and head lines we are looking at. If < 8 cyl then only low 3 85 : : #define PRU0_HEAD_MASK 0x7c 86 : : 87 : : // Current cylinder 88 : : #define PRU0_DRIVE0_CUR_CYL 0x80 89 : : #define PRU0_DRIVE1_CUR_CYL 0x84 90 : : 91 : : // 0 normal, 1 to command PRU to exit 92 : : #define PRU0_EXIT 0x88 93 : : 94 : : // Used to convert bit-count to cycles at current rate (4 bytes) 95 : : #define PRU0_BIT_PRU_CLOCKS 0x8c 96 : : 97 : : // Cycle count for PWM logic 1 at current data rate (4 bytes) 98 : : #define PRU0_DEFAULT_PULSE_WIDTH 0x90 99 : : 100 : : // Start and end time for generating index pulse in PRU clocks 101 : : #define PRU0_START_INDEX_TIME 0x94 102 : : #define PRU0_END_INDEX_TIME 0x98 103 : : 104 : : // Time for a disk rotation in PRU clocks 105 : : #define PRU0_ROTATION_TIME 0x9c 106 : : 107 : : // 0xa0 unused 108 : : 109 : : // Last cylinder requested from ARM 110 : : #define PRU0_DRIVE0_LAST_ARM_CYL 0xa4 111 : : #define PRU0_DRIVE1_LAST_ARM_CYL 0xa8 112 : : #define PRU0_LAST_SELECT_HEAD 0xac 113 : : 114 : : // Bits 0-n indicate track 0-n been modified in cylinder data 115 : : #define PRU1_DRIVE0_TRK_DIRTY 0x30 116 : : // Bits 0-n indicate track 0-n been modified in cylinder data 117 : : #define PRU1_DRIVE1_TRK_DIRTY 0x34 118 : : // Non zero indicates error in converting bits to PWM words 119 : : #define PRU1_BAD_PATTERN_COUNT 0x38 120 : : #define PRU1_DRIVE0_TRACK_HEADER_BYTES 0x50 121 : : #define PRU1_DRIVE1_TRACK_HEADER_BYTES 0x54 122 : : #define PRU1_DRIVE0_TRACK_DATA_BYTES 0x58 123 : : #define PRU1_DRIVE1_TRACK_DATA_BYTES 0x5c 124 : : 125 : : // inverse bit period scaled 2^32, 2^32/bit_period 126 : : #define PRU1_INV_BIT_PERIOD_S32 0x60 127 : : 128 : : // If we don't see a transition by this number of cycles, 129 : : // assume zero. 130 : : #define PRU1_ZERO_BIT_THRESHOLD 0x64 131 : : // Nominal bit cell cycles 132 : : #define PRU1_BIT_PRU_CLOCKS 0x68 133 : : // DMA channel to use 134 : : #define PRU1_DMA_CHANNEL 0x6c 135 : : // Last DMA RAM and DDR offset, internal PRU use 136 : : #define PRU1_NEXT_DMA_RAM_OFFSET 0x70 137 : : #define PRU1_NEXT_DMA_DDR_OFFSET 0x74 138 : : 139 : : #define PRU_WORD_SIZE_BYTES 4 140 : : 141 : : // Location bit lookup table stored 142 : : #define PRU1_BIT_TABLE 0x80 143 : : 144 : : // Maximum size of cylinder buffer. 145 : : #define DDR_DRIVE_BUFFER_MAX_SIZE (16*32768) 146 : : // PRU queues are in shared memory locations 0 to mask 147 : : #define SHARED_PWM_READ_MASK 0x1f 148 : : #define SHARED_DELTAS_WRITE_MASK 0x7f 149 : : 150 : : // Bits in registers for the control lines 151 : : #define R30_DRIVE0_SEL 1 152 : : #define R30_SEEK_COMPLETE_BIT 2 153 : : // Rev A,B 154 : : #define R30_WRITE_FAULT_BIT 3 155 : : // Rev C 156 : : #define GPIO1_WRITE_FAULT_BIT 19 157 : : #define R30_READY_BIT 4 158 : : #define R30_INDEX_BIT 5 159 : : #define R30_MFM0_IN_ENABLE 15 160 : : #define R30_MFM1_IN_ENABLE 14 161 : : 162 : : #define R31_WRITE_GATE 0 163 : : #define R31_SEEK_DIR_BIT 6 164 : : #define R31_STEP_BIT 7 165 : : // Rev C 166 : : #define R31_SEL1_BIT 14 167 : : #define R31_SEL2_BIT 16 168 : : 169 : : #define REVB_DETECT_PIN 46 // GPIO 1_14 170 : : #define REVC_DETECT_PIN 61 // GPIO 1_29 171 : : 172 : : // Rev A,B 173 : : #define GPIO0_TRACK_0 30 174 : : // Rev C 175 : : #define R30_TRACK_0_BIT 3 176 : : #define GPIO0_DRIVE0_LED 14 177 : : // Rev A,B 178 : : #ifndef REVC 179 : : #define GPIO0_DRIVE1_LED 15 180 : : #else 181 : : // Rev C 182 : : #define GPIO0_DRIVE1_LED 30 183 : : #endif 184 : : #define GPIO0_DRIVE1_SEL_RECOVERY 31 185 : : 186 : : #define GPIO1_TEST 16 187 : : 188 : : #define GPIO_SELECT1 22 189 : : #define GPIO_SELECT2 23 190 : : #ifdef REVC 191 : : #define GPIO_HEAD0 8 192 : : #define GPIO_HEAD1 9 193 : : #define GPIO_HEAD2 10 194 : : #define GPIO_HEAD3 11 195 : : #define GPIO_DRIVE_SELECT_LINES 196 : : #else 197 : : #ifdef REVB 198 : : #define GPIO_HEAD0 8 199 : : #define GPIO_HEAD1 9 200 : : #define GPIO_HEAD2 10 201 : : #define GPIO_HEAD3 11 202 : : #define GPIO_DRIVE_SELECT_LINES (1 << GPIO_SELECT1) | (1 << GPIO_SELECT2) 203 : : #else 204 : : #define GPIO_HEAD0 2 205 : : #define GPIO_HEAD1 3 206 : : #define GPIO_HEAD2 4 207 : : #define GPIO_HEAD3 5 208 : : #define GPIO_SELECT3 26 209 : : #define GPIO_SELECT4 27 210 : : #define GPIO_DRIVE_SELECT_LINES (1 << GPIO_SELECT1) | (1 << GPIO_SELECT2) | (1 << GPIO_SELECT3) | (1 << GPIO_SELECT4) 211 : : #endif 212 : : #endif 213 : : #define CUR_SELECT_HEAD_WRITE_ERR 31 214 : : 215 : : #define GPIO_DRIVE_HEAD_LINES (1 << GPIO_HEAD0) | (1 << GPIO_HEAD1) | (1 << GPIO_HEAD2) | (1 << GPIO_HEAD3) 216 : : #define GPIO_DRIVE_SELECT_HEAD_LINES (GPIO_DRIVE_HEAD_LINES | GPIO_DRIVE_SELECT_LINES) 217 : : 218 : : // Address in PRU code for stopping current operation 219 : : #define RESTART_ADDR 0x400 220 : : // Offset from start of PRU0_DATARAM to the PRU control register 221 : : #define PRU_CONTROL_REG 0x22000 222 : : #define PRU_STATUS_REG 0x22004 223 : : #define PRU_DEBUG 0x22400 224 : : 225 : : // TODO, these should be common 226 : : #define CLOCK_BASE 0x44e00000 227 : : #define CM_AUTOIDEL_DPLL_DISP 0x448 228 : : #define CM_IDLEST_DPLL_DISP 0x448 229 : : #define CM_SSC_DELTAMSTEP_DPLL_DISP 0x44c 230 : : #define CM_SSC_MODFREQDIV_DPLL_DISP 0x450 231 : : #define CM_CLKSEL_DPLL_DISP 0x454 232 : : #define CM_CLKMODE_DPLL_DISP 0x498 233 : : #define CM_DIV_M2_DPLL_DISP 0x4a4 234 : : #define CLKSEL_PRU_ICSS_OCP_CLK 0x530 235 : :