esiop.ss revision 1.20
11.20Sbouyer;	$NetBSD: esiop.ss,v 1.20 2005/11/18 23:10:32 bouyer 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; 3. All advertising materials mentioning features or use of this software
151.1Sbouyer;    must display the following acknowledgement:
161.7Sbouyer;	This product includes software developed by Manuel Bouyer.
171.16Sbouyer; 4. The name of the author may not be used to endorse or promote products
181.16Sbouyer;    derived from this software without specific prior written permission.
191.1Sbouyer;
201.1Sbouyer; THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211.1Sbouyer; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221.1Sbouyer; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231.1Sbouyer; ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241.1Sbouyer; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251.1Sbouyer; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261.1Sbouyer; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271.1Sbouyer; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281.1Sbouyer; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291.1Sbouyer; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301.1Sbouyer; SUCH DAMAGE.
311.1Sbouyer;
321.1Sbouyer
331.1SbouyerARCH 825
341.1Sbouyer
351.5Sbouyer; offsets in siop_common_xfer
361.5SbouyerABSOLUTE t_id = 40;
371.5SbouyerABSOLUTE t_msg_in = 48;
381.5SbouyerABSOLUTE t_ext_msg_in = 56;
391.5SbouyerABSOLUTE t_ext_msg_data = 64;
401.5SbouyerABSOLUTE t_msg_out = 72;
411.5SbouyerABSOLUTE t_cmd = 80;
421.5SbouyerABSOLUTE t_status = 88;
431.5SbouyerABSOLUTE t_data = 96;
441.1Sbouyer
451.1Sbouyer; offsets in the per-target lun table
461.1SbouyerABSOLUTE target_id = 0x0;
471.1SbouyerABSOLUTE target_luntbl = 0x8;
481.10SbouyerABSOLUTE target_luntbl_tag = 0xc;
491.1Sbouyer
501.1Sbouyer;; interrupt codes
511.1Sbouyer; interrupts that needs a valid target/lun/tag
521.1SbouyerABSOLUTE int_done	= 0xff00;
531.1SbouyerABSOLUTE int_msgin	= 0xff01;
541.1SbouyerABSOLUTE int_extmsgin	= 0xff02;
551.1SbouyerABSOLUTE int_extmsgdata	= 0xff03;
561.1SbouyerABSOLUTE int_disc	= 0xff04;
571.1Sbouyer; interrupts that don't have a valid I/T/Q
581.19SperryABSOLUTE int_resfail	= 0xff80;
591.19SperryABSOLUTE int_err	= 0xffff;
601.1Sbouyer
611.1Sbouyer; We use the various scratch[a-j] registers to keep internal status:
621.1Sbouyer
631.1Sbouyer; scratchA1: offset in data DSA (for save data pointer)
641.1Sbouyer; scratchB: save/restore DSA in data loop
651.1Sbouyer; scratchC: current target/lun/tag
661.1Sbouyer; scratchC0: flags
671.1SbouyerABSOLUTE f_c_target	= 0x01 ; target valid
681.14SbouyerABSOLUTE f_c_lun	= 0x02 ; lun valid
691.1SbouyerABSOLUTE f_c_tag	= 0x04 ; tag valid
701.1SbouyerABSOLUTE f_c_data	= 0x08 ; data I/O in progress
711.1SbouyerABSOLUTE f_c_data_mask	= 0xf7 ; ~f_c_data
721.1SbouyerABSOLUTE f_c_sdp	= 0x10 ; got save data pointer message
731.1Sbouyer; scratchC[1-3]: target/lun/tag
741.1Sbouyer
751.1Sbouyer; scratchD: current DSA in start cmd ring
761.1Sbouyer; scratchE0: index in start cmd ring
771.8SbouyerABSOLUTE ncmd_slots	= 256 ; number of slots in CMD ring
781.8SbouyerABSOLUTE ncmd_slots_last = 0 ; == ncmd_slots in a 8bit counter
791.1Sbouyer; flags in a cmd slot
801.1SbouyerABSOLUTE f_cmd_free	= 0x01 ; this slot is free
811.2SbouyerABSOLUTE f_cmd_ignore	= 0x02 ; this slot is not free but don't start it
821.1Sbouyer; offsets in a cmd slot
831.2SbouyerABSOLUTE o_cmd_dsa	= 0; also holds f_cmd_*
841.9Sbouyer; size of a cmd slot (for DSA increments)
851.9SbouyerABSOLUTE cmd_slot_size	= 4;
861.1Sbouyer
871.1Sbouyer; SCRATCHE1: last status
881.1Sbouyer
891.11Sbouyer; SCRATCHE2: current command done slot
901.11SbouyerABSOLUTE ndone_slots	= 256 ; number of slots in CMD ring
911.11SbouyerABSOLUTE ndone_slots_last = 0 ; == ndonemd_slots in a 8bit counter
921.11Sbouyer; SCRATCHF: pointer in command done ring
931.11Sbouyer
941.1SbouyerENTRY cmdr0;
951.1SbouyerENTRY cmdr1;
961.1SbouyerENTRY cmdr2;
971.1SbouyerENTRY cmdr3;
981.11SbouyerENTRY doner0;
991.11SbouyerENTRY doner1;
1001.11SbouyerENTRY doner2;
1011.11SbouyerENTRY doner3;
1021.11SbouyerENTRY reselect;
1031.1SbouyerENTRY led_on1;
1041.1SbouyerENTRY led_on2;
1051.1SbouyerENTRY led_off;
1061.1SbouyerENTRY status;
1071.1SbouyerENTRY msgin;
1081.1SbouyerENTRY msgin_ack;
1091.1SbouyerENTRY get_extmsgdata;
1101.1SbouyerENTRY send_msgout;
1111.1SbouyerENTRY script_sched;
1121.1SbouyerENTRY load_targtable;
1131.1Sbouyer
1141.1SbouyerEXTERN tlq_offset;
1151.20SbouyerEXTERN saved_offset_offset;
1161.1SbouyerEXTERN abs_msgin2;
1171.1Sbouyer
1181.12SbouyerEXTERN abs_sem; a 32bits word used a semaphore between script and driver
1191.12SbouyerABSOLUTE sem_done = 0x01; there are pending done commands
1201.12SbouyerABSOLUTE sem_start = 0x02; a CMD slot was freed
1211.12Sbouyer
1221.1SbouyerPROC  esiop_script:
1231.1Sbouyer
1241.1Sbouyerno_cmd:
1251.12Sbouyer	LOAD SCRATCHB0, 4, abs_sem; pending done command ?
1261.12Sbouyer	MOVE SCRATCHB0 & sem_done TO SFBR;
1271.19Sperry	INTFLY 0, IF NOT 0x00;
1281.19Sperry	MOVE SCRATCHB0 | sem_start TO SCRATCHB0; we are there because the
1291.12Sbouyer	STORE NOFLUSH SCRATCHB0, 4, abs_sem;     cmd ring is empty
1301.1Sbouyerreselect:
1311.1Sbouyer	MOVE 0x00 TO SCRATCHA1;
1321.1Sbouyer	MOVE 0x00 TO SCRATCHC0;
1331.1Sbouyer	MOVE 0xff TO SCRATCHE1;
1341.1Sbouyer; a NOP by default; patched with MOVE GPREG | 0x01 to GPREG on compile-time
1351.1Sbouyer; option "SIOP_SYMLED"
1361.1Sbouyerled_off:
1371.1Sbouyer	NOP;
1381.1Sbouyer	WAIT RESELECT REL(reselect_fail);
1391.1Sbouyer; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time
1401.1Sbouyer; option "SIOP_SYMLED"
1411.1Sbouyerled_on2:
1421.1Sbouyer        NOP;
1431.1Sbouyer	MOVE SSID & 0x0f to SFBR;
1441.1Sbouyer	MOVE SFBR to SCRATCHC1;
1451.1Sbouyer	MOVE SCRATCHC0 | f_c_target to SCRATCHC0; save target
1461.1Sbouyer	CLEAR CARRY;
1471.1Sbouyer	MOVE SCRATCHC1 SHL SFBR;
1481.4Sbouyer	MOVE SFBR SHL DSA0; target * 4 in dsa
1491.1Sbouyer	MOVE 0x0 to DSA1;
1501.1Sbouyer	MOVE 0x0 to DSA2;
1511.1Sbouyer	MOVE 0x0 to DSA3;
1521.1Sbouyer; load DSA for the target table
1531.1Sbouyerload_targtable:
1541.4Sbouyer	MOVE DSA0 + 0x00 to DSA0; host will patch 0x0 with base of table
1551.1Sbouyer	MOVE DSA1 + 0x00 to DSA1 with carry;
1561.1Sbouyer	MOVE DSA2 + 0x00 to DSA2 with carry;
1571.4Sbouyer	MOVE DSA3 + 0x00 to DSA3 with carry; now dsa -> basetable + target * 4
1581.1Sbouyer	LOAD DSA0, 4, FROM 0; now load DSA for this target
1591.1Sbouyer	SELECT FROM target_id, REL(nextisn);
1601.1Sbouyernextisn:
1611.1Sbouyer	MOVE 1, abs_msgin2, WHEN MSG_IN;
1621.1Sbouyer	MOVE SFBR & 0x07 to SCRATCHC2;
1631.1Sbouyer	MOVE SCRATCHC0 | f_c_lun to SCRATCHC0; save LUN
1641.1Sbouyer	CLEAR ACK and CARRY;
1651.19Sperry	MOVE SCRATCHC2 SHL SFBR;
1661.10Sbouyer	MOVE SFBR SHL SFBR;
1671.10Sbouyer	MOVE SFBR SHL SFBR; lun * 8
1681.1Sbouyer	MOVE DSA0 + SFBR TO DSA0;
1691.1Sbouyer	MOVE DSA1 + 0x0 TO DSA1 with carry;
1701.1Sbouyer	MOVE DSA2 + 0x0 TO DSA2 with carry;
1711.1Sbouyer	MOVE DSA3 + 0x0 TO DSA3 with carry;
1721.10Sbouyer	LOAD SCRATCHB0, 4, from target_luntbl_tag; in case it's a tagged cmd
1731.2Sbouyer	LOAD DSA0, 4, from target_luntbl; load DSA for this LUN
1741.2Sbouyer	JUMP REL(waitphase), WHEN NOT MSG_IN;
1751.2Sbouyer	MOVE 1, abs_msgin2, WHEN MSG_IN;
1761.2Sbouyer	CLEAR ACK;
1771.15Sbouyer	JUMP REL(handle_msgin), IF NOT 0x20; not a simple tag message
1781.2Sbouyer	MOVE 1, abs_msgin2, WHEN MSG_IN; get tag
1791.4Sbouyer	MOVE SFBR to SCRATCHA2;
1801.2Sbouyer	MOVE SFBR to SCRATCHC3;
1811.2Sbouyer	MOVE SCRATCHC0 | f_c_tag to SCRATCHC0; save TAG
1821.10Sbouyer	CALL REL(restoredsa); switch to tag table DSA
1831.2Sbouyer	MOVE 0x0 to SCRATCHA3;
1841.2Sbouyer	CLEAR CARRY;
1851.4Sbouyer	MOVE SCRATCHA2 SHL SCRATCHA2;
1861.2Sbouyer	MOVE SCRATCHA3 SHL SCRATCHA3;
1871.4Sbouyer	MOVE SCRATCHA2 SHL SCRATCHA2;
1881.4Sbouyer	MOVE SCRATCHA3 SHL SCRATCHA3; TAG * 4 to SCRATCHA(2,3)
1891.2Sbouyer	MOVE SCRATCHA2 TO SFBR;
1901.2Sbouyer	MOVE DSA0 + SFBR TO DSA0;
1911.4Sbouyer	MOVE DSA1 + 0x00 TO DSA1 with CARRY;
1921.4Sbouyer	MOVE DSA2 + 0x00 TO DSA2 with CARRY;
1931.4Sbouyer	MOVE DSA3 + 0x00 TO DSA3 with CARRY;
1941.2Sbouyer	MOVE SCRATCHA3 TO SFBR;
1951.4Sbouyer	MOVE DSA1 + SFBR TO DSA1;
1961.2Sbouyer	MOVE DSA2 + 0x00 TO DSA2 with CARRY;
1971.2Sbouyer	MOVE DSA3 + 0x00 TO DSA3 with CARRY; SCRACHA(2,3) + DSA to DSA
1981.2Sbouyer	LOAD DSA0, 4, from 0; load DSA for this tag
1991.13Sbouyermsgin_ack:
2001.13Sbouyer	CLEAR ACK;
2011.13Sbouyerwaitphase:
2021.13Sbouyer	JUMP REL(msgout), WHEN MSG_OUT;
2031.13Sbouyer	JUMP REL(msgin), WHEN MSG_IN;
2041.13Sbouyer	JUMP REL(dataout), WHEN DATA_OUT;
2051.13Sbouyer	JUMP REL(datain), WHEN DATA_IN;
2061.13Sbouyer	JUMP REL(cmdout), WHEN CMD;
2071.13Sbouyer	JUMP REL(status), WHEN STATUS;
2081.13Sbouyer	INT int_err;
2091.13Sbouyer
2101.13Sbouyerhandle_cmpl:
2111.13Sbouyer	CALL REL(disconnect);
2121.20Sbouyer; update offset if we did some data transfer
2131.20Sbouyer	MOVE SCRATCHA1 TO SFBR;
2141.20Sbouyer	JUMP REL(handle_cmpl_noxfer), if 0x00;
2151.20Sbouyer	STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset;
2161.20Sbouyerhandle_cmpl_noxfer:
2171.13Sbouyer	MOVE SCRATCHE1 to SFBR;
2181.13Sbouyer	INT int_done, IF NOT 0x00; if status is not "done", let host handle it
2191.13Sbouyer	MOVE SCRATCHF0 to SFBR; load pointer in done ring
2201.13Sbouyer	MOVE SFBR to DSA0;
2211.13Sbouyer	MOVE SCRATCHF1 to SFBR;
2221.13Sbouyer	MOVE SFBR to DSA1;
2231.13Sbouyer	MOVE SCRATCHF2 to SFBR;
2241.13Sbouyer	MOVE SFBR to DSA2;
2251.13Sbouyer	MOVE SCRATCHF3 to SFBR;
2261.13Sbouyer	MOVE SFBR to DSA3;
2271.13Sbouyerwait_free:
2281.13Sbouyer	LOAD SCRATCHA0, 1, from 0;
2291.13Sbouyer	MOVE SCRATCHA0 to SFBR;
2301.13Sbouyer	JUMP REL(wait_free), if not 0; wait for slot to be free
2311.13Sbouyer	STORE NOFLUSH SCRATCHC0, 4, from 0; save current target/lun/flag
2321.13Sbouyer	MOVE SCRATCHF0 + 4 to SCRATCHF0; advance to next slot
2331.13Sbouyer	MOVE SCRATCHF1 + 0 to SCRATCHF1 with carry;
2341.13Sbouyer	MOVE SCRATCHF2 + 0 to SCRATCHF2 with carry;
2351.13Sbouyer	MOVE SCRATCHF3 + 0 to SCRATCHF3 with carry;
2361.13Sbouyer	MOVE SCRATCHE2 + 1 to SCRATCHE2;
2371.13Sbouyer	MOVE SCRATCHE2 to SFBR;
2381.13Sbouyer	JUMP REL(is_done), if not ndone_slots_last;
2391.13Sbouyerdoner0:
2401.13Sbouyer	MOVE 0xff to SCRATCHF0; driver will change 0xff to base of ring
2411.13Sbouyerdoner1:
2421.13Sbouyer	MOVE 0xff to SCRATCHF1;
2431.13Sbouyerdoner2:
2441.13Sbouyer	MOVE 0xff to SCRATCHF2;
2451.13Sbouyerdoner3:
2461.13Sbouyer	MOVE 0xff to SCRATCHF3;
2471.13Sbouyer	MOVE 0  to SCRATCHE2;
2481.13Sbouyeris_done:
2491.13Sbouyer	LOAD SCRATCHB0, 4, abs_sem; signal that a command is done
2501.13Sbouyer	MOVE SCRATCHB0 | sem_done TO SCRATCHB0;
2511.13Sbouyer	STORE NOFLUSH SCRATCHB0, 4, abs_sem;
2521.13Sbouyer; and attempt next command
2531.1Sbouyer
2541.1Sbouyerreselect_fail:
2551.13Sbouyer	; clear SIGP in ISTAT
2561.1Sbouyer	MOVE CTEST2 & 0x40 TO SFBR;
2571.1Sbouyerscript_sched:
2581.1Sbouyer; Load ring DSA
2591.1Sbouyer	MOVE SCRATCHD0 to SFBR;
2601.1Sbouyer	MOVE SFBR to DSA0;
2611.1Sbouyer	MOVE SCRATCHD1 to SFBR;
2621.1Sbouyer	MOVE SFBR to DSA1;
2631.1Sbouyer	MOVE SCRATCHD2 to SFBR;
2641.1Sbouyer	MOVE SFBR to DSA2;
2651.1Sbouyer	MOVE SCRATCHD3 to SFBR;
2661.1Sbouyer	MOVE SFBR to DSA3;
2671.9Sbouyer	LOAD DSA0,4, from o_cmd_dsa; get DSA and flags for this slot
2681.9Sbouyer	MOVE DSA0 & f_cmd_free to SFBR; check flags
2691.1Sbouyer	JUMP REL(no_cmd), IF NOT 0x0;
2701.9Sbouyer	MOVE DSA0 & f_cmd_ignore to SFBR;
2711.2Sbouyer	JUMP REL(ignore_cmd), IF NOT 0x0;
2721.10Sbouyer	LOAD SCRATCHC0, 4, FROM tlq_offset;
2731.1Sbouyer; this slot is busy, attempt to exec command
2741.9Sbouyer	SELECT ATN FROM t_id, REL(reselect);
2751.4Sbouyer; select either succeeded or timed out.
2761.1Sbouyer; if timed out the STO interrupt will be posted at the first SCSI bus access
2771.4Sbouyer; waiting for a valid phase, so we have to do it now. If not a MSG_OUT phase,
2781.4Sbouyer; this is an error anyway (we selected with ATN)
2791.4Sbouyer	INT int_err, WHEN NOT MSG_OUT;
2801.10Sbouyerignore_cmd:
2811.9Sbouyer	MOVE SCRATCHD0 to SFBR; restore scheduler DSA
2821.9Sbouyer	MOVE SFBR to DSA0;
2831.9Sbouyer	MOVE SCRATCHD1 to SFBR;
2841.9Sbouyer	MOVE SFBR to DSA1;
2851.9Sbouyer	MOVE SCRATCHD2 to SFBR;
2861.9Sbouyer	MOVE SFBR to DSA2;
2871.9Sbouyer	MOVE SCRATCHD3 to SFBR;
2881.9Sbouyer	MOVE SFBR to DSA3;
2891.4Sbouyer	MOVE SCRATCHE0 + 1 to SCRATCHE0;
2901.19Sperry	MOVE SCRATCHD0 + cmd_slot_size to SCRATCHD0;
2911.1Sbouyer	MOVE SCRATCHD1 + 0 to SCRATCHD1 WITH CARRY;
2921.1Sbouyer	MOVE SCRATCHD2 + 0 to SCRATCHD2 WITH CARRY;
2931.1Sbouyer	MOVE SCRATCHD3 + 0 to SCRATCHD3 WITH CARRY;
2941.4Sbouyer	MOVE SCRATCHE0 TO SFBR;
2951.8Sbouyer	JUMP REL(handle_cmd), IF  NOT ncmd_slots_last;
2961.4Sbouyer; reset pointers to beggining of area
2971.1Sbouyercmdr0:
2981.1Sbouyer	MOVE 0xff to SCRATCHD0; correct value will be patched by driver
2991.1Sbouyercmdr1:
3001.1Sbouyer	MOVE 0xff to SCRATCHD1;
3011.1Sbouyercmdr2:
3021.1Sbouyer	MOVE 0xff to SCRATCHD2;
3031.1Sbouyercmdr3:
3041.1Sbouyer	MOVE 0xff to SCRATCHD3;
3051.1Sbouyer	MOVE 0x00 to SCRATCHE0;
3061.1Sbouyerhandle_cmd:
3071.10Sbouyer; to avoid race condition we have to load the DSA value before setting the
3081.10Sbouyer; free flag, so we have to use a temp register.
3091.10Sbouyer; use SCRATCHB0 so that we can CALL restoredsa later
3101.10Sbouyer	LOAD SCRATCHB0, 4, FROM o_cmd_dsa; load DSA for this command in temp reg
3111.10Sbouyer	MOVE SCRATCHB0 | f_cmd_free to SCRATCHB0; mark slot as free
3121.10Sbouyer	STORE noflush SCRATCHB0, 4, FROM o_cmd_dsa;
3131.10Sbouyer	MOVE SCRATCHB0 & f_cmd_ignore to SFBR;
3141.9Sbouyer	JUMP REL(script_sched), IF NOT 0x00; next command if ignore
3151.10Sbouyer	MOVE SCRATCHB0 & 0xfc to SCRATCHB0; clear f_cmd_*
3161.10Sbouyer	CALL REL(restoredsa); and move SCRATCHB to DSA
3171.12Sbouyer	LOAD SCRATCHB0, 4, abs_sem;
3181.12Sbouyer	MOVE SCRATCHB0 | sem_start TO SCRATCHB0;
3191.12Sbouyer	STORE NOFLUSH SCRATCHB0, 4, abs_sem;
3201.2Sbouyer
3211.1Sbouyer; a NOP by default; patched with MOVE GPREG & 0xfe to GPREG on compile-time
3221.1Sbouyer; option "SIOP_SYMLED"
3231.1Sbouyerled_on1:
3241.1Sbouyer	NOP;
3251.1Sbouyer	MOVE 0x00 TO SCRATCHA1;
3261.1Sbouyer	MOVE 0xff TO SCRATCHE1;
3271.4Sbouyer;we can now send our identify message
3281.4Sbouyersend_msgout: ; entry point for msgout after a msgin or status phase
3291.4Sbouyer	SET ATN;
3301.4Sbouyer	CLEAR ACK;
3311.19Sperrymsgout:
3321.4Sbouyer        MOVE FROM t_msg_out, WHEN MSG_OUT;
3331.19Sperry	CLEAR ATN;
3341.4Sbouyer	JUMP REL(waitphase);
3351.4Sbouyer
3361.1Sbouyer
3371.1Sbouyerhandle_sdp:
3381.1Sbouyer	CLEAR ACK;
3391.1Sbouyer	MOVE SCRATCHC0 | f_c_sdp TO SCRATCHC0;
3401.1Sbouyer	; should get a disconnect message now
3411.1Sbouyermsgin:
3421.1Sbouyer	CLEAR ATN
3431.1Sbouyer	MOVE FROM t_msg_in, WHEN MSG_IN;
3441.1Sbouyerhandle_msgin:
3451.1Sbouyer	JUMP REL(handle_cmpl), IF 0x00	; command complete message
3461.1Sbouyer	JUMP REL(handle_sdp), IF 0x02	; save data pointer message
3471.1Sbouyer	JUMP REL(handle_extin), IF 0x01	; extended message
3481.1Sbouyer	INT int_msgin, IF NOT 0x04;
3491.1Sbouyer	CALL REL(disconnect)		; disconnect message
3501.18Sbouyer; if we didn't get sdp, no need to interrupt
3511.1Sbouyer	MOVE SCRATCHC0 & f_c_sdp TO SFBR;
3521.20Sbouyer	INT int_disc, IF not 0x00;
3531.20Sbouyer; update offset if we did some data transfer
3541.20Sbouyer	MOVE SCRATCHA1 TO SFBR;
3551.1Sbouyer	JUMP REL(script_sched), if 0x00;
3561.20Sbouyer	STORE NOFLUSH SCRATCHA0, 4, FROM saved_offset_offset;
3571.20Sbouyer	JUMP REL(script_sched);
3581.1Sbouyer
3591.1Sbouyercmdout:
3601.19Sperry        MOVE FROM t_cmd, WHEN CMD;
3611.1Sbouyer	JUMP REL(waitphase);
3621.19Sperrystatus:
3631.1Sbouyer        MOVE FROM t_status, WHEN STATUS;
3641.1Sbouyer	MOVE SFBR TO SCRATCHE1;
3651.1Sbouyer	JUMP REL(waitphase);
3661.1Sbouyerdatain:
3671.1Sbouyer        CALL REL(savedsa);
3681.1Sbouyer	MOVE SCRATCHC0 | f_c_data TO SCRATCHC0;
3691.1Sbouyer	datain_loop:
3701.1Sbouyer	MOVE FROM t_data, WHEN DATA_IN;
3711.1Sbouyer	MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset
3721.1Sbouyer	MOVE DSA0 + 8 to DSA0;
3731.1Sbouyer	MOVE DSA1 + 0 to DSA1 WITH CARRY;
3741.1Sbouyer	MOVE DSA2 + 0 to DSA2 WITH CARRY;
3751.1Sbouyer	MOVE DSA3 + 0 to DSA3 WITH CARRY;
3761.1Sbouyer	JUMP REL(datain_loop), WHEN DATA_IN;
3771.1Sbouyer	CALL REL(restoredsa);
3781.1Sbouyer	MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0;
3791.1Sbouyer	JUMP REL(waitphase);
3801.1Sbouyer
3811.1Sbouyerdataout:
3821.1Sbouyer        CALL REL(savedsa);
3831.1Sbouyer	MOVE SCRATCHC0 | f_c_data TO SCRATCHC0;
3841.1Sbouyerdataout_loop:
3851.1Sbouyer	MOVE FROM t_data, WHEN DATA_OUT;
3861.1Sbouyer	MOVE SCRATCHA1 + 1 TO SCRATCHA1 ; adjust offset
3871.1Sbouyer	MOVE DSA0 + 8 to DSA0;
3881.1Sbouyer	MOVE DSA1 + 0 to DSA1 WITH CARRY;
3891.1Sbouyer	MOVE DSA2 + 0 to DSA2 WITH CARRY;
3901.1Sbouyer	MOVE DSA3 + 0 to DSA3 WITH CARRY;
3911.1Sbouyer	JUMP REL(dataout_loop), WHEN DATA_OUT;
3921.1Sbouyer	CALL REL(restoredsa);
3931.1Sbouyer	MOVE SCRATCHC0 & f_c_data_mask TO SCRATCHC0;
3941.1Sbouyer	JUMP REL(waitphase);
3951.1Sbouyer
3961.1Sbouyersavedsa:
3971.1Sbouyer        MOVE DSA0 to SFBR;
3981.19Sperry	MOVE SFBR to SCRATCHB0;
3991.1Sbouyer	MOVE DSA1 to SFBR;
4001.19Sperry	MOVE SFBR to SCRATCHB1;
4011.1Sbouyer	MOVE DSA2 to SFBR;
4021.1Sbouyer	MOVE SFBR to SCRATCHB2;
4031.1Sbouyer	MOVE DSA3 to SFBR;
4041.1Sbouyer	MOVE SFBR to SCRATCHB3;
4051.1Sbouyer	RETURN;
4061.1Sbouyer
4071.1Sbouyerrestoredsa:
4081.1Sbouyer	MOVE SCRATCHB0 TO SFBR;
4091.1Sbouyer	MOVE SFBR TO DSA0;
4101.1Sbouyer	MOVE SCRATCHB1 TO SFBR;
4111.1Sbouyer	MOVE SFBR TO DSA1;
4121.1Sbouyer	MOVE SCRATCHB2 TO SFBR;
4131.1Sbouyer	MOVE SFBR TO DSA2;
4141.19Sperry	MOVE SCRATCHB3 TO SFBR;
4151.1Sbouyer	MOVE SFBR TO DSA3;
4161.1Sbouyer	RETURN;
4171.1Sbouyer
4181.1Sbouyerdisconnect:
4191.1Sbouyer        MOVE SCNTL2 & 0x7f TO SCNTL2;
4201.1Sbouyer	CLEAR ATN;
4211.1Sbouyer	CLEAR ACK;
4221.1Sbouyer	WAIT DISCONNECT;
4231.1Sbouyer	RETURN;
4241.1Sbouyer
4251.1Sbouyerhandle_extin:
4261.1Sbouyer	CLEAR ACK;
4271.1Sbouyer	MOVE FROM t_ext_msg_in, WHEN MSG_IN;
4281.1Sbouyer	INT int_extmsgin; /* let host fill in t_ext_msg_data */
4291.1Sbouyerget_extmsgdata:
4301.1Sbouyer	CLEAR ACK;
4311.1Sbouyer	MOVE FROM t_ext_msg_data, WHEN MSG_IN;
4321.19Sperry	INT int_extmsgdata;
4331.3Sbouyer
4341.4SbouyerPROC esiop_led_on:
4351.3Sbouyer	MOVE GPREG & 0xfe TO GPREG;
4361.3Sbouyer
4371.4SbouyerPROC esiop_led_off:
4381.3Sbouyer	MOVE GPREG | 0x01 TO GPREG;
439