11.22Sandvar; $NetBSD: esiop.ss,v 1.22 2022/05/23 19:21:30 andvar Exp $ 21.1Sbouyer 31.1Sbouyer; 41.1Sbouyer; Copyright (c) 2002 Manuel Bouyer. 51.1Sbouyer; 61.1Sbouyer; Redistribution and use in source and binary forms, with or without 71.1Sbouyer; modification, are permitted provided that the following conditions 81.1Sbouyer; are met: 91.1Sbouyer; 1. Redistributions of source code must retain the above copyright 101.1Sbouyer; notice, this list of conditions and the following disclaimer. 111.1Sbouyer; 2. Redistributions in binary form must reproduce the above copyright 121.1Sbouyer; notice, this list of conditions and the following disclaimer in the 131.1Sbouyer; documentation and/or other materials provided with the distribution. 141.1Sbouyer; 151.1Sbouyer; THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 161.1Sbouyer; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171.1Sbouyer; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181.1Sbouyer; ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 191.1Sbouyer; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201.1Sbouyer; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211.1Sbouyer; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221.1Sbouyer; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231.1Sbouyer; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241.1Sbouyer; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251.1Sbouyer; SUCH DAMAGE. 261.1Sbouyer; 271.1Sbouyer 281.1SbouyerARCH 825 291.1Sbouyer 301.5Sbouyer; offsets in siop_common_xfer 311.5SbouyerABSOLUTE t_id = 40; 321.5SbouyerABSOLUTE t_msg_in = 48; 331.5SbouyerABSOLUTE t_ext_msg_in = 56; 341.5SbouyerABSOLUTE t_ext_msg_data = 64; 351.5SbouyerABSOLUTE t_msg_out = 72; 361.5SbouyerABSOLUTE t_cmd = 80; 371.5SbouyerABSOLUTE t_status = 88; 381.5SbouyerABSOLUTE t_data = 96; 391.1Sbouyer 401.1Sbouyer; offsets in the per-target lun table 411.1SbouyerABSOLUTE target_id = 0x0; 421.1SbouyerABSOLUTE target_luntbl = 0x8; 431.10SbouyerABSOLUTE target_luntbl_tag = 0xc; 441.1Sbouyer 451.1Sbouyer;; interrupt codes 461.1Sbouyer; interrupts that needs a valid target/lun/tag 471.1SbouyerABSOLUTE int_done = 0xff00; 481.1SbouyerABSOLUTE int_msgin = 0xff01; 491.1SbouyerABSOLUTE int_extmsgin = 0xff02; 501.1SbouyerABSOLUTE int_extmsgdata = 0xff03; 511.1SbouyerABSOLUTE int_disc = 0xff04; 521.1Sbouyer; interrupts that don't have a valid I/T/Q 531.19SperryABSOLUTE int_resfail = 0xff80; 541.19SperryABSOLUTE int_err = 0xffff; 551.1Sbouyer 561.1Sbouyer; We use the various scratch[a-j] registers to keep internal status: 571.1Sbouyer 581.1Sbouyer; scratchA1: offset in data DSA (for save data pointer) 591.1Sbouyer; scratchB: save/restore DSA in data loop 601.1Sbouyer; scratchC: current target/lun/tag 611.1Sbouyer; scratchC0: flags 621.1SbouyerABSOLUTE f_c_target = 0x01 ; target valid 631.14SbouyerABSOLUTE f_c_lun = 0x02 ; lun valid 641.1SbouyerABSOLUTE f_c_tag = 0x04 ; tag valid 651.1SbouyerABSOLUTE f_c_data = 0x08 ; data I/O in progress 661.1SbouyerABSOLUTE f_c_data_mask = 0xf7 ; ~f_c_data 671.1SbouyerABSOLUTE f_c_sdp = 0x10 ; got save data pointer message 681.1Sbouyer; scratchC[1-3]: target/lun/tag 691.1Sbouyer 701.1Sbouyer; scratchD: current DSA in start cmd ring 711.1Sbouyer; scratchE0: index in start cmd ring 721.8SbouyerABSOLUTE ncmd_slots = 256 ; number of slots in CMD ring 731.8SbouyerABSOLUTE ncmd_slots_last = 0 ; == ncmd_slots in a 8bit counter 741.1Sbouyer; flags in a cmd slot 751.1SbouyerABSOLUTE f_cmd_free = 0x01 ; this slot is free 761.2SbouyerABSOLUTE f_cmd_ignore = 0x02 ; this slot is not free but don't start it 771.1Sbouyer; offsets in a cmd slot 781.2SbouyerABSOLUTE o_cmd_dsa = 0; also holds f_cmd_* 791.9Sbouyer; size of a cmd slot (for DSA increments) 801.9SbouyerABSOLUTE cmd_slot_size = 4; 811.1Sbouyer 821.1Sbouyer; SCRATCHE1: last status 831.1Sbouyer 841.11Sbouyer; SCRATCHE2: current command done slot 851.11SbouyerABSOLUTE ndone_slots = 256 ; number of slots in CMD ring 861.11SbouyerABSOLUTE ndone_slots_last = 0 ; == ndonemd_slots in a 8bit counter 871.11Sbouyer; SCRATCHF: pointer in command done ring 881.11Sbouyer 891.1SbouyerENTRY cmdr0; 901.1SbouyerENTRY cmdr1; 911.1SbouyerENTRY cmdr2; 921.1SbouyerENTRY cmdr3; 931.11SbouyerENTRY doner0; 941.11SbouyerENTRY doner1; 951.11SbouyerENTRY doner2; 961.11SbouyerENTRY doner3; 971.11SbouyerENTRY reselect; 981.1SbouyerENTRY led_on1; 991.1SbouyerENTRY led_on2; 1001.1SbouyerENTRY led_off; 1011.1SbouyerENTRY status; 1021.1SbouyerENTRY msgin; 1031.1SbouyerENTRY msgin_ack; 1041.1SbouyerENTRY get_extmsgdata; 1051.1SbouyerENTRY send_msgout; 1061.1SbouyerENTRY script_sched; 1071.1SbouyerENTRY load_targtable; 1081.1Sbouyer 1091.1SbouyerEXTERN tlq_offset; 1101.20SbouyerEXTERN saved_offset_offset; 1111.1SbouyerEXTERN abs_msgin2; 1121.1Sbouyer 1131.12SbouyerEXTERN abs_sem; a 32bits word used a semaphore between script and driver 1141.12SbouyerABSOLUTE sem_done = 0x01; there are pending done commands 1151.12SbouyerABSOLUTE sem_start = 0x02; a CMD slot was freed 1161.12Sbouyer 1171.1SbouyerPROC esiop_script: 1181.1Sbouyer 1191.1Sbouyerno_cmd: 1201.12Sbouyer LOAD SCRATCHB0, 4, abs_sem; pending done command ? 1211.12Sbouyer MOVE SCRATCHB0 & sem_done TO SFBR; 1221.19Sperry INTFLY 0, IF NOT 0x00; 1231.19Sperry MOVE SCRATCHB0 | sem_start TO SCRATCHB0; we are there because the 1241.12Sbouyer STORE NOFLUSH SCRATCHB0, 4, abs_sem; cmd ring is empty 1251.1Sbouyerreselect: 1261.1Sbouyer MOVE 0x00 TO SCRATCHA1; 1271.1Sbouyer MOVE 0x00 TO SCRATCHC0; 1281.1Sbouyer MOVE 0xff TO SCRATCHE1; 1291.1Sbouyer; a NOP by default; patched with MOVE GPREG | 0x01 to GPREG on compile-time 1301.1Sbouyer; option "SIOP_SYMLED" 1311.1Sbouyerled_off: 1321.1Sbouyer NOP; 1331.1Sbouyer WAIT RESELECT REL(reselect_fail); 1341.1Sbouyer; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time 1351.1Sbouyer; option "SIOP_SYMLED" 1361.1Sbouyerled_on2: 1371.1Sbouyer NOP; 1381.1Sbouyer MOVE SSID & 0x0f to SFBR; 1391.1Sbouyer MOVE SFBR to SCRATCHC1; 1401.1Sbouyer MOVE SCRATCHC0 | f_c_target to SCRATCHC0; save target 1411.1Sbouyer CLEAR CARRY; 1421.1Sbouyer MOVE SCRATCHC1 SHL SFBR; 1431.4Sbouyer MOVE SFBR SHL DSA0; target * 4 in dsa 1441.1Sbouyer MOVE 0x0 to DSA1; 1451.1Sbouyer MOVE 0x0 to DSA2; 1461.1Sbouyer MOVE 0x0 to DSA3; 1471.1Sbouyer; load DSA for the target table 1481.1Sbouyerload_targtable: 1491.4Sbouyer MOVE DSA0 + 0x00 to DSA0; host will patch 0x0 with base of table 1501.1Sbouyer MOVE DSA1 + 0x00 to DSA1 with carry; 1511.1Sbouyer MOVE DSA2 + 0x00 to DSA2 with carry; 1521.4Sbouyer MOVE DSA3 + 0x00 to DSA3 with carry; now dsa -> basetable + target * 4 1531.1Sbouyer LOAD DSA0, 4, FROM 0; now load DSA for this target 1541.1Sbouyer SELECT FROM target_id, REL(nextisn); 1551.1Sbouyernextisn: 1561.1Sbouyer MOVE 1, abs_msgin2, WHEN MSG_IN; 1571.1Sbouyer MOVE SFBR & 0x07 to SCRATCHC2; 1581.1Sbouyer MOVE SCRATCHC0 | f_c_lun to SCRATCHC0; save LUN 1591.1Sbouyer CLEAR ACK and CARRY; 1601.19Sperry MOVE SCRATCHC2 SHL SFBR; 1611.10Sbouyer MOVE SFBR SHL SFBR; 1621.10Sbouyer MOVE SFBR SHL SFBR; lun * 8 1631.1Sbouyer MOVE DSA0 + SFBR TO DSA0; 1641.1Sbouyer MOVE DSA1 + 0x0 TO DSA1 with carry; 1651.1Sbouyer MOVE DSA2 + 0x0 TO DSA2 with carry; 1661.1Sbouyer MOVE DSA3 + 0x0 TO DSA3 with carry; 1671.10Sbouyer LOAD SCRATCHB0, 4, from target_luntbl_tag; in case it's a tagged cmd 1681.2Sbouyer LOAD DSA0, 4, from target_luntbl; load DSA for this LUN 1691.2Sbouyer JUMP REL(waitphase), WHEN NOT MSG_IN; 1701.2Sbouyer MOVE 1, abs_msgin2, WHEN MSG_IN; 1711.2Sbouyer CLEAR ACK; 1721.15Sbouyer JUMP REL(handle_msgin), IF NOT 0x20; not a simple tag message 1731.2Sbouyer MOVE 1, abs_msgin2, WHEN MSG_IN; get tag 1741.4Sbouyer MOVE SFBR to SCRATCHA2; 1751.2Sbouyer MOVE SFBR to SCRATCHC3; 1761.2Sbouyer MOVE SCRATCHC0 | f_c_tag to SCRATCHC0; save TAG 1771.10Sbouyer CALL REL(restoredsa); switch to tag table DSA 1781.2Sbouyer MOVE 0x0 to SCRATCHA3; 1791.2Sbouyer CLEAR CARRY; 1801.4Sbouyer MOVE SCRATCHA2 SHL SCRATCHA2; 1811.2Sbouyer MOVE SCRATCHA3 SHL SCRATCHA3; 1821.4Sbouyer MOVE SCRATCHA2 SHL SCRATCHA2; 1831.4Sbouyer MOVE SCRATCHA3 SHL SCRATCHA3; TAG * 4 to SCRATCHA(2,3) 1841.2Sbouyer MOVE SCRATCHA2 TO SFBR; 1851.2Sbouyer MOVE DSA0 + SFBR TO DSA0; 1861.4Sbouyer MOVE DSA1 + 0x00 TO DSA1 with CARRY; 1871.4Sbouyer MOVE DSA2 + 0x00 TO DSA2 with CARRY; 1881.4Sbouyer MOVE DSA3 + 0x00 TO DSA3 with CARRY; 1891.2Sbouyer MOVE SCRATCHA3 TO SFBR; 1901.4Sbouyer MOVE DSA1 + SFBR TO DSA1; 1911.2Sbouyer MOVE DSA2 + 0x00 TO DSA2 with CARRY; 1921.2Sbouyer MOVE DSA3 + 0x00 TO DSA3 with CARRY; SCRACHA(2,3) + DSA to DSA 1931.2Sbouyer LOAD DSA0, 4, from 0; load DSA for this tag 1941.13Sbouyermsgin_ack: 1951.13Sbouyer CLEAR ACK; 1961.13Sbouyerwaitphase: 1971.13Sbouyer JUMP REL(msgout), WHEN MSG_OUT; 1981.13Sbouyer JUMP REL(msgin), WHEN MSG_IN; 1991.13Sbouyer JUMP REL(dataout), WHEN DATA_OUT; 2001.13Sbouyer JUMP REL(datain), WHEN DATA_IN; 2011.13Sbouyer JUMP REL(cmdout), WHEN CMD; 2021.13Sbouyer JUMP REL(status), WHEN STATUS; 2031.13Sbouyer INT int_err; 2041.13Sbouyer 2051.13Sbouyerhandle_cmpl: 2061.13Sbouyer CALL REL(disconnect); 2071.20Sbouyer; update offset if we did some data transfer 2081.20Sbouyer MOVE SCRATCHA1 TO SFBR; 2091.20Sbouyer JUMP REL(handle_cmpl_noxfer), if 0x00; 2101.20Sbouyer STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset; 2111.20Sbouyerhandle_cmpl_noxfer: 2121.13Sbouyer MOVE SCRATCHE1 to SFBR; 2131.13Sbouyer INT int_done, IF NOT 0x00; if status is not "done", let host handle it 2141.13Sbouyer MOVE SCRATCHF0 to SFBR; load pointer in done ring 2151.13Sbouyer MOVE SFBR to DSA0; 2161.13Sbouyer MOVE SCRATCHF1 to SFBR; 2171.13Sbouyer MOVE SFBR to DSA1; 2181.13Sbouyer MOVE SCRATCHF2 to SFBR; 2191.13Sbouyer MOVE SFBR to DSA2; 2201.13Sbouyer MOVE SCRATCHF3 to SFBR; 2211.13Sbouyer MOVE SFBR to DSA3; 2221.13Sbouyerwait_free: 2231.13Sbouyer LOAD SCRATCHA0, 1, from 0; 2241.13Sbouyer MOVE SCRATCHA0 to SFBR; 2251.13Sbouyer JUMP REL(wait_free), if not 0; wait for slot to be free 2261.13Sbouyer STORE NOFLUSH SCRATCHC0, 4, from 0; save current target/lun/flag 2271.13Sbouyer MOVE SCRATCHF0 + 4 to SCRATCHF0; advance to next slot 2281.13Sbouyer MOVE SCRATCHF1 + 0 to SCRATCHF1 with carry; 2291.13Sbouyer MOVE SCRATCHF2 + 0 to SCRATCHF2 with carry; 2301.13Sbouyer MOVE SCRATCHF3 + 0 to SCRATCHF3 with carry; 2311.13Sbouyer MOVE SCRATCHE2 + 1 to SCRATCHE2; 2321.13Sbouyer MOVE SCRATCHE2 to SFBR; 2331.13Sbouyer JUMP REL(is_done), if not ndone_slots_last; 2341.13Sbouyerdoner0: 2351.13Sbouyer MOVE 0xff to SCRATCHF0; driver will change 0xff to base of ring 2361.13Sbouyerdoner1: 2371.13Sbouyer MOVE 0xff to SCRATCHF1; 2381.13Sbouyerdoner2: 2391.13Sbouyer MOVE 0xff to SCRATCHF2; 2401.13Sbouyerdoner3: 2411.13Sbouyer MOVE 0xff to SCRATCHF3; 2421.13Sbouyer MOVE 0 to SCRATCHE2; 2431.13Sbouyeris_done: 2441.13Sbouyer LOAD SCRATCHB0, 4, abs_sem; signal that a command is done 2451.13Sbouyer MOVE SCRATCHB0 | sem_done TO SCRATCHB0; 2461.13Sbouyer STORE NOFLUSH SCRATCHB0, 4, abs_sem; 2471.13Sbouyer; and attempt next command 2481.1Sbouyer 2491.1Sbouyerreselect_fail: 2501.13Sbouyer ; clear SIGP in ISTAT 2511.1Sbouyer MOVE CTEST2 & 0x40 TO SFBR; 2521.1Sbouyerscript_sched: 2531.1Sbouyer; Load ring DSA 2541.1Sbouyer MOVE SCRATCHD0 to SFBR; 2551.1Sbouyer MOVE SFBR to DSA0; 2561.1Sbouyer MOVE SCRATCHD1 to SFBR; 2571.1Sbouyer MOVE SFBR to DSA1; 2581.1Sbouyer MOVE SCRATCHD2 to SFBR; 2591.1Sbouyer MOVE SFBR to DSA2; 2601.1Sbouyer MOVE SCRATCHD3 to SFBR; 2611.1Sbouyer MOVE SFBR to DSA3; 2621.9Sbouyer LOAD DSA0,4, from o_cmd_dsa; get DSA and flags for this slot 2631.9Sbouyer MOVE DSA0 & f_cmd_free to SFBR; check flags 2641.1Sbouyer JUMP REL(no_cmd), IF NOT 0x0; 2651.9Sbouyer MOVE DSA0 & f_cmd_ignore to SFBR; 2661.2Sbouyer JUMP REL(ignore_cmd), IF NOT 0x0; 2671.10Sbouyer LOAD SCRATCHC0, 4, FROM tlq_offset; 2681.1Sbouyer; this slot is busy, attempt to exec command 2691.9Sbouyer SELECT ATN FROM t_id, REL(reselect); 2701.4Sbouyer; select either succeeded or timed out. 2711.1Sbouyer; if timed out the STO interrupt will be posted at the first SCSI bus access 2721.4Sbouyer; waiting for a valid phase, so we have to do it now. If not a MSG_OUT phase, 2731.4Sbouyer; this is an error anyway (we selected with ATN) 2741.4Sbouyer INT int_err, WHEN NOT MSG_OUT; 2751.10Sbouyerignore_cmd: 2761.9Sbouyer MOVE SCRATCHD0 to SFBR; restore scheduler DSA 2771.9Sbouyer MOVE SFBR to DSA0; 2781.9Sbouyer MOVE SCRATCHD1 to SFBR; 2791.9Sbouyer MOVE SFBR to DSA1; 2801.9Sbouyer MOVE SCRATCHD2 to SFBR; 2811.9Sbouyer MOVE SFBR to DSA2; 2821.9Sbouyer MOVE SCRATCHD3 to SFBR; 2831.9Sbouyer MOVE SFBR to DSA3; 2841.4Sbouyer MOVE SCRATCHE0 + 1 to SCRATCHE0; 2851.19Sperry MOVE SCRATCHD0 + cmd_slot_size to SCRATCHD0; 2861.1Sbouyer MOVE SCRATCHD1 + 0 to SCRATCHD1 WITH CARRY; 2871.1Sbouyer MOVE SCRATCHD2 + 0 to SCRATCHD2 WITH CARRY; 2881.1Sbouyer MOVE SCRATCHD3 + 0 to SCRATCHD3 WITH CARRY; 2891.4Sbouyer MOVE SCRATCHE0 TO SFBR; 2901.8Sbouyer JUMP REL(handle_cmd), IF NOT ncmd_slots_last; 2911.22Sandvar; reset pointers to beginning of area 2921.1Sbouyercmdr0: 2931.1Sbouyer MOVE 0xff to SCRATCHD0; correct value will be patched by driver 2941.1Sbouyercmdr1: 2951.1Sbouyer MOVE 0xff to SCRATCHD1; 2961.1Sbouyercmdr2: 2971.1Sbouyer MOVE 0xff to SCRATCHD2; 2981.1Sbouyercmdr3: 2991.1Sbouyer MOVE 0xff to SCRATCHD3; 3001.1Sbouyer MOVE 0x00 to SCRATCHE0; 3011.1Sbouyerhandle_cmd: 3021.10Sbouyer; to avoid race condition we have to load the DSA value before setting the 3031.10Sbouyer; free flag, so we have to use a temp register. 3041.10Sbouyer; use SCRATCHB0 so that we can CALL restoredsa later 3051.10Sbouyer LOAD SCRATCHB0, 4, FROM o_cmd_dsa; load DSA for this command in temp reg 3061.10Sbouyer MOVE SCRATCHB0 | f_cmd_free to SCRATCHB0; mark slot as free 3071.10Sbouyer STORE noflush SCRATCHB0, 4, FROM o_cmd_dsa; 3081.10Sbouyer MOVE SCRATCHB0 & f_cmd_ignore to SFBR; 3091.9Sbouyer JUMP REL(script_sched), IF NOT 0x00; next command if ignore 3101.10Sbouyer MOVE SCRATCHB0 & 0xfc to SCRATCHB0; clear f_cmd_* 3111.10Sbouyer CALL REL(restoredsa); and move SCRATCHB to DSA 3121.12Sbouyer LOAD SCRATCHB0, 4, abs_sem; 3131.12Sbouyer MOVE SCRATCHB0 | sem_start TO SCRATCHB0; 3141.12Sbouyer STORE NOFLUSH SCRATCHB0, 4, abs_sem; 3151.2Sbouyer 3161.1Sbouyer; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time 3171.1Sbouyer; option "SIOP_SYMLED" 3181.1Sbouyerled_on1: 3191.1Sbouyer NOP; 3201.1Sbouyer MOVE 0x00 TO SCRATCHA1; 3211.1Sbouyer MOVE 0xff TO SCRATCHE1; 3221.4Sbouyer;we can now send our identify message 3231.4Sbouyersend_msgout: ; entry point for msgout after a msgin or status phase 3241.4Sbouyer SET ATN; 3251.4Sbouyer CLEAR ACK; 3261.19Sperrymsgout: 3271.4Sbouyer MOVE FROM t_msg_out, WHEN MSG_OUT; 3281.19Sperry CLEAR ATN; 3291.4Sbouyer JUMP REL(waitphase); 3301.4Sbouyer 3311.1Sbouyer 3321.1Sbouyerhandle_sdp: 3331.1Sbouyer CLEAR ACK; 3341.1Sbouyer MOVE SCRATCHC0 | f_c_sdp TO SCRATCHC0; 3351.1Sbouyer ; should get a disconnect message now 3361.1Sbouyermsgin: 3371.1Sbouyer CLEAR ATN 3381.1Sbouyer MOVE FROM t_msg_in, WHEN MSG_IN; 3391.1Sbouyerhandle_msgin: 3401.1Sbouyer JUMP REL(handle_cmpl), IF 0x00 ; command complete message 3411.1Sbouyer JUMP REL(handle_sdp), IF 0x02 ; save data pointer message 3421.1Sbouyer JUMP REL(handle_extin), IF 0x01 ; extended message 3431.1Sbouyer INT int_msgin, IF NOT 0x04; 3441.1Sbouyer CALL REL(disconnect) ; disconnect message 3451.18Sbouyer; if we didn't get sdp, no need to interrupt 3461.1Sbouyer MOVE SCRATCHC0 & f_c_sdp TO SFBR; 3471.20Sbouyer INT int_disc, IF not 0x00; 3481.20Sbouyer; update offset if we did some data transfer 3491.20Sbouyer MOVE SCRATCHA1 TO SFBR; 3501.1Sbouyer JUMP REL(script_sched), if 0x00; 3511.20Sbouyer STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset; 3521.20Sbouyer JUMP REL(script_sched); 3531.1Sbouyer 3541.1Sbouyercmdout: 3551.19Sperry MOVE FROM t_cmd, WHEN CMD; 3561.1Sbouyer JUMP REL(waitphase); 3571.19Sperrystatus: 3581.1Sbouyer MOVE FROM t_status, WHEN STATUS; 3591.1Sbouyer MOVE SFBR TO SCRATCHE1; 3601.1Sbouyer JUMP REL(waitphase); 3611.1Sbouyerdatain: 3621.1Sbouyer CALL REL(savedsa); 3631.1Sbouyer MOVE SCRATCHC0 | f_c_data TO SCRATCHC0; 3641.1Sbouyer datain_loop: 3651.1Sbouyer MOVE FROM t_data, WHEN DATA_IN; 3661.1Sbouyer MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset 3671.1Sbouyer MOVE DSA0 + 8 to DSA0; 3681.1Sbouyer MOVE DSA1 + 0 to DSA1 WITH CARRY; 3691.1Sbouyer MOVE DSA2 + 0 to DSA2 WITH CARRY; 3701.1Sbouyer MOVE DSA3 + 0 to DSA3 WITH CARRY; 3711.1Sbouyer JUMP REL(datain_loop), WHEN DATA_IN; 3721.1Sbouyer CALL REL(restoredsa); 3731.1Sbouyer MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0; 3741.1Sbouyer JUMP REL(waitphase); 3751.1Sbouyer 3761.1Sbouyerdataout: 3771.1Sbouyer CALL REL(savedsa); 3781.1Sbouyer MOVE SCRATCHC0 | f_c_data TO SCRATCHC0; 3791.1Sbouyerdataout_loop: 3801.1Sbouyer MOVE FROM t_data, WHEN DATA_OUT; 3811.1Sbouyer MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset 3821.1Sbouyer MOVE DSA0 + 8 to DSA0; 3831.1Sbouyer MOVE DSA1 + 0 to DSA1 WITH CARRY; 3841.1Sbouyer MOVE DSA2 + 0 to DSA2 WITH CARRY; 3851.1Sbouyer MOVE DSA3 + 0 to DSA3 WITH CARRY; 3861.1Sbouyer JUMP REL(dataout_loop), WHEN DATA_OUT; 3871.1Sbouyer CALL REL(restoredsa); 3881.1Sbouyer MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0; 3891.1Sbouyer JUMP REL(waitphase); 3901.1Sbouyer 3911.1Sbouyersavedsa: 3921.1Sbouyer MOVE DSA0 to SFBR; 3931.19Sperry MOVE SFBR to SCRATCHB0; 3941.1Sbouyer MOVE DSA1 to SFBR; 3951.19Sperry MOVE SFBR to SCRATCHB1; 3961.1Sbouyer MOVE DSA2 to SFBR; 3971.1Sbouyer MOVE SFBR to SCRATCHB2; 3981.1Sbouyer MOVE DSA3 to SFBR; 3991.1Sbouyer MOVE SFBR to SCRATCHB3; 4001.1Sbouyer RETURN; 4011.1Sbouyer 4021.1Sbouyerrestoredsa: 4031.1Sbouyer MOVE SCRATCHB0 TO SFBR; 4041.1Sbouyer MOVE SFBR TO DSA0; 4051.1Sbouyer MOVE SCRATCHB1 TO SFBR; 4061.1Sbouyer MOVE SFBR TO DSA1; 4071.1Sbouyer MOVE SCRATCHB2 TO SFBR; 4081.1Sbouyer MOVE SFBR TO DSA2; 4091.19Sperry MOVE SCRATCHB3 TO SFBR; 4101.1Sbouyer MOVE SFBR TO DSA3; 4111.1Sbouyer RETURN; 4121.1Sbouyer 4131.1Sbouyerdisconnect: 4141.1Sbouyer MOVE SCNTL2 & 0x7f TO SCNTL2; 4151.1Sbouyer CLEAR ATN; 4161.1Sbouyer CLEAR ACK; 4171.1Sbouyer WAIT DISCONNECT; 4181.1Sbouyer RETURN; 4191.1Sbouyer 4201.1Sbouyerhandle_extin: 4211.1Sbouyer CLEAR ACK; 4221.1Sbouyer MOVE FROM t_ext_msg_in, WHEN MSG_IN; 4231.1Sbouyer INT int_extmsgin; /* let host fill in t_ext_msg_data */ 4241.1Sbouyerget_extmsgdata: 4251.1Sbouyer CLEAR ACK; 4261.1Sbouyer MOVE FROM t_ext_msg_data, WHEN MSG_IN; 4271.19Sperry INT int_extmsgdata; 4281.3Sbouyer 4291.4SbouyerPROC esiop_led_on: 4301.3Sbouyer MOVE GPREG & 0xfe TO GPREG; 4311.3Sbouyer 4321.4SbouyerPROC esiop_led_off: 4331.3Sbouyer MOVE GPREG | 0x01 TO GPREG; 434