Skip to content

State Machines

mbtaylor1982 edited this page Nov 22, 2024 · 8 revisions

SCSI FSM - DMAC SCSI Interface state machine

Summary

This FSM (Finite State Machine) controls the access cycles used to transfer data to and from the WDC33C93A SCSI controller. It is responsible for accessing the WDC33C93A registers and for responding to DMA cycles in coordination with the CPU FSM.

INPUTS

Signal Description
DREQ_ data request from SCSI chip
FIFOFULL FIFOCNT = 8
FIFOEMPTY FIFOCNT = 0
BOEQ3 byte offset = 3
DMADIR DMA direction (low=write to DISK)
CPUREQ CPU request. Cpu wants to read/write a SCSI register
DSACK_ DSACK to CPU
RIFIFO_o Request to Increment FIFO counter (when this becomes invalid, then the increment was done)
RDFIFO_o Request to Decrement FIFO counter (when this becomes invalid, then the decrement was done)
RW Read/Write line from 68030.

OUTPUTS

Signal Description
DACK Data Acknowledge to SCSI chip
INCBO increment byte offset
INCNI increment pointer to next longword in
INCNO increment pointer to next longword out
RE read enable to SCSI chip
WE write enable to SCSI chip
SCSI_CS Chip select to SCSI chip
SET_DSACK Make DSACK active
RIFIFO_d Request to Increment FIFO counter (out to CPU state machine)
RDFIFO_d Request to decrement FIFO counter (out to CPU state machine)
S2F Turn input buffers on so data can be read from SCSI chip (SCSI to FIFO)
F2S Turn output buffers on so data can be written to SCSI chip (FIFO to SCSI)
S2CPU Turn internal data buffers on to route data to be read from SCSI to the CPU
CPU2S Turn internal data buffers on to route data to be written to SCSI from the CPU

Schematic

image

Timing diagram

--              |<-------- 5 clocks per byte ------- >|

--              S0,7  | S1,8  | S2,9  | S3,10 | S6,13 | S0,7  | S1,8  | S2,9  |
--                  ___     ___     ___     ___     ___     ___     ___     ___
-- CPUCLK       ___/   \___/   \___/   \___/   \___/   \___/   \___/   \___/
--                          _____________________                   ___________
-- *DREQ        ___________/_________/   \_______\_________________/_________/
--              ___                 _______________________                 ___
-- *DSACK          \_______________/                       \_______________/
--              ___                 _______________________                 ___
-- *WE             \_______________/                       \_______________/
--              ___                 _______________________                 ___
-- *RE             \_______________/                       \_______________/

State Diagram

---
title: SCSI FSM
---
stateDiagram-v2
    
    [*] --> IDLE_DMA_RD
    
    IDLE_DMA_RD --> S2F_1 :SCSI to FIFO       
    IDLE_DMA_RD --> CPUREQ
    IDLE_DMA_RD --> IDLE_DMA_WR
    IDLE_DMA_RD --> IDLE_DMA_RD

    
    IDLE_DMA_WR --> CPUREQ
    IDLE_DMA_WR --> F2S_1 :FIFO to SCSI


    CPUREQ --> S2C_1 :SCSI to CPU
    CPUREQ --> C2S_1 :CPU to SCSI

    C2S_1 --> C2S_2
    C2S_2 --> C2S_3
    C2S_3 --> C2S_4
    C2S_4 --> C2S_5
    C2S_5 --> C2S_5  : wait for DSACK



    S2C_1 --> S2C_2
    S2C_2 --> S2C_3
    S2C_3 --> S2C_4
    S2C_4 --> S2C_5
    S2C_5 --> S2C_6
    S2C_6 --> S2C_6 : wait for DSACK



    F2S_1 --> F2S_2
    F2S_2 --> F2S_3
    F2S_3 --> F2S_4
    F2S_4 --> IDLE_DMA_WR

    S2F_1 --> S2F_2
    S2F_2 --> S2F_3
    S2F_3 --> S2F_4

    state end <<join>>
    IDLE_DMA_WR --> end
    C2S_5 --> end
    S2C_6 --> end
    S2F_4 --> end
    end --> IDLE_DMA_RD
Loading
  • s0 = IDLE_DMA_RD

  • s1 = S2F_1

  • s2 = S2F_2

  • s3 = S2F_3

  • s6 = S2F_4

  • s7 = IDLE_DMA_WR

  • s8 = F2S_1

  • s9 = F2S_2

  • s10 = F2S_3

  • s13 = F2S_4

  • s50 = CPUREQ

  • s51 = C2S_1

  • s52 = C2S_2

  • s53 = C2S_3

  • s54 = C2S_4

  • s55 = C2S_5

  • s60 = S2C_1

  • s61 = S2C_2

  • s62 = S2C_3

  • s63 = S2C_4

  • s64 = S2C_5

  • s65 = S2C_6

DMA read from SCSI device

s0: 
    case (CPUREQ DREQ_ FIFOFULL DMADIR RIFIFO_o)
        0 1 ? 1 ? => s0; -- no data to get.
        0 0 0 1 0 => s1( RE DACK S2F); -- data ready, & room, & no incr. req. pending, so read it
        0 0 0 1 1 => s0; -- data ready, and room, but increment req is pending, so wait
        0 0 1 1 ? => s0; -- data ready, but no place to put it.
        0 ? ? 0 ? => s7; -- go to DMA write mode
        1 ? ? ? ? => s50; -- CPU wants access to a SCSI register
    endcase => ANY;

s1: 
    if FIFOFULL then s2 (INCNI INCNO) -- This can NEVER happen! It is here to keep INCNI/RIFIFO_d & INCNO/RDFIFO_d -- output logic different (gfl to dfd converter would eliminate one).
    else s2(RE DACK S2F); -- RE to scsi chip (This is the only line really necessary)

-- NOTE: Ending edge of RE is used to latch data in. SCSI spec says that it holds
-- read data valid for min of 5 nsecs, which SHOULD be enough hold time to latch it in.
-- Also, ensure BYTE OFFSET ptr & NEXT IN ptr don't change before data is latched in.

s2: 
    goto s3(S2F);

s3: 
    if BOEQ3 then s6(RIFIFO_d INCBO INCNI) -- if last byte in lword, increment the pointer
    else s6(INCBO);

s6: 
    goto s0;

DMA write to SCSI device

s7: 
    case (CPUREQ DREQ_ FIFOEMPTY DMADIR RDFIFO_o)
        0 1 ? 0 ? => s7; -- SCSI chip doesn't want data yet.
        0 0 1 0 ? => s7; -- SCSI ready for data, but nothing in FIFO yet.
        0 0 0 0 0 => s8(DACK WE F2S); -- Data to send to SCSI, & no decrement pending, so send it
        0 0 0 0 1 => s7; -- Data to send to SCSI, but decrement is pending, so wait
        0 ? ? 1 ? => s0; -- go to DMA read mode
        1 ? ? ? ? => s50; -- CPU wants access to a SCSI register
    endcase => ANY;

s8: 
    goto s9(DACK WE F2S);

s9: 
    goto s10(F2S);

s10: 
    if BOEQ3 then s13(RDFIFO_d INCBO INCNO) -- if last byte in lword, increment the pointer
    else s13(INCBO);

s13: 
    goto s7;

CPU access to the SCSI internal registers

s50:    
    case (RW)
        0 => s51(SCSI_CS WE CPU2S); -- Write to SCSI chip register.
        1 => s60(SCSI_CS RE S2CPU); -- Read from SCSI chip register.
    endcase => ANY;

Write to SCSI chip register

s51: 
    goto s52(SCSI_CS WE CPU2S); -- Write to SCSI register
s52: 
    goto s53(SCSI_CS WE CPU2S);
s53: 
    goto s54(SCSI_CS CPU2S SET_DSACK);
s54: 
    goto s55;
s55: 
    if NOT DSACK_ then s55 -- Wait for write cycle to finish
    else s0;

Read from SCSI chip register

s60: 
    goto s61(SCSI_CS RE S2CPU); -- Read from SCSI register
s61: 
    goto s62(SCSI_CS RE S2CPU); -- Read from SCSI register
s62: 
    goto s63(SCSI_CS RE S2CPU); -- Read from SCSI register
s63: 
    goto s64(SCSI_CS RE S2CPU SET_DSACK);
s64: 
    goto s65( S2CPU );
s65: 
    if NOT DSACK_ then s65(S2CPU) -- Wait for read cycle to finish
    else s0;

CPU FSM