{SCSI utility routines}

%include "ncr5380.inc"
%ownrecord(ncr5380)%name chip == chip0
%ownstring(255)reason = "nothing"
%ownstring(255)%name for == nil

%routinespec wait

%predicate eq(%integer a)
  %trueif a=0
  %false
%end

%predicate ne(%integer a)
  %trueif a#0
  %false
%end

%routine scsireset
  for == reason %if for==nil
  chip_icr = icr rst
  for = "cbs rst +"
  wait %until ne(chip_cbs&cbsrst)
  for = ""
  chip_dma[1] = 1
%end

%routine offerbyte(%integer x)
! Initiator offers byte to target (without DMA)
  x = x&255
{printstring("Offer "); phex2(x)
  for = "offer req +"
  wait %until ne(chip_cbs&cbsreq)  {wait for REQ
{space
  chip_icr = icrdata
  chip_odr = x<<8                  {write data
  chip_icr = icrdata!icrack        {assert ACK (and DATA)
  for = "offer req -"
  wait %until eq(chip_cbs&cbsreq)  {wait for REQ to drop
  chip_icr = icrdata               {drop ACK
{newline
%end

%integerfn acceptbyte
! Initiator accepts byte from target (without DMA)
%integer x
  chip_icr = 0                     {make sure we don't drive data
  for = "accept req +"
  wait %until ne(chip_cbs&cbsreq)  {wait for REQ
  x = chip_csd>>8                  {take data
  chip_icr = icrack                {assert ACK
  for = "accept req -"
  wait %until eq(chip_cbs&cbsreq)  {wait for REQ to drop
  chip_icr = 0                     {drop ACK
  %result = x
%end

%integerfn getbyte
! Target reads byte from Initiator (without DMA)
%integer k
  chip_icr = icrbsy                  {ensure DATA is off
  chip_tcr = chip_tcr!tcrreq         {assert REQ
  for = "get ack +"
  wait %until ne(chip_bsr&bsrack)    {wait for ACK
  k = chip_csd>>8                    {take data
  chip_tcr = chip_tcr&\tcrreq        {drop REQ
  for = "get ack -"
  wait %until eq(chip_bsr&bsrack)    {wait for ACK to drop
  %result = k
%end

%routine putbyte(%integer k)
! Target sends a byte to Initiator (without DMA)
  chip_icr = icrbsy!icrdata          {ensure DATA is on
  chip_odr = k<<8                    {write data
  chip_tcr = chip_tcr!tcrreq         {assert REQ
  for = "put ack +"
  wait %until ne(chip_bsr&bsrack)    {wait for ACK
  chip_tcr = chip_tcr&\tcrreq        {drop REQ
  for = "get ack -"
  wait %until eq(chip_bsr&bsrack)    {wait for ACK to drop
%end

%routine dmaput(%integer k)
! Initiator or target writes byte using Pseudo DMA
! (ICR must have been set up)
  for = "put drq"
  wait %until ne(chip_bsr&bsrdrq)  {wait for DRQ
  %returnif k<0                    {flushing only
  chip_dma = k                     {write data
%end

%integerfn dmaget
! Initiator or target reads a byte using Pseudo DMA
! (ICR assumed set up appropriately)
  for = "get drq"
  wait %until ne(chip_bsr&bsrdrq)  {wait for DRQ
  %result = chip_dma               {take data
%end

%routine acquire bus(%integer id)
! For selection or reselection
  id = 1<<(id+8)
  for == reason %if for==nil
  chip_tcr = 0
  chip_mode = 0
  chip_odr = id                      {write ID byte
  %cycle
    chip_icr = 0
    chip_mode = modearb              {request arbitration
    for = "aip"
    wait %until ne(chip_icr&icraip)  {wait till in progress
    %continueif ne(chip_icr&icrlost) {check LOST bit
    %continueif chip_csd&16_ff00>id  {check for higher priority ID
  %repeatuntil eq(chip_icr&icrlost)  {re-check LOST bit
  chip_icr = icrsel                  {assert SEL
%end

%routine select(%integer initiator,target)
  acquire bus(initiator)
  initiator = 1<<(initiator+8)
  target = 1<<(target+8)
  chip_odr = initiator!target        {write both IDs
  chip_ser = 0                       {prevent SEL int
  chip_icr = icrbsy!icrsel!icrdata   {add SEL to BSY
  chip_mode = 0                      {drop ARB bit
  chip_icr = icrsel!icrdata          {drop BSY
  for = "sel bsy +"
  wait %until ne(chip_cbs&cbsbsy)    {wait for BSY
  chip_mode = modebsy                {ensure BSY stays
  chip_icr = 0                       {drop SEL and IDs
%end

%routine reselect(%integer initiator,target)
  acquire bus(target)
  initiator = 1<<(initiator+8)
  target = 1<<(target+8)
  chip_odr = initiator!target        {write both IDs
  chip_mode = modetgt!modearb        {add TARGET bit
  chip_tcr = tcrio                   {assert IO bit
  chip_icr = icrbsy!icrsel!icrdata   {add SEL to BSY
  chip_mode = modetgt                {drop ARB bit
  chip_ser = 0                       {prevent SEL int
  chip_icr = icrsel!icrdata          {drop BSY
  for = "resel bsy +"
  wait %until ne(chip_cbs&cbsbsy)    {wait for BSY
  chip_icr = icrbsy!icrdata          {drop SEL and data and add BSY
%end

