OpenCores
URL https://opencores.org/ocsvn/pdp8/pdp8/trunk

Subversion Repositories pdp8

[/] [pdp8/] [trunk/] [pdp8/] [rk8e.vhd] - Rev 2

Compare with Previous | Blame | View Log

--------------------------------------------------------------------
--!
--! PDP-8 Processor
--!
--! \brief
--!      RK8E Disk Controller
--!
--! \file
--!      rk8e.vhd
--!
--! \details
--!      The RK8E Disk Controller is designed to be register
--!      compatible with real RK8E controller.  Instead of
--!      interfacing to 4 RK05 disk drives, this controller
--!      interfaces to a single Secure Digital memory chip
--!      which contains the storage equivalent of 4 RK05
--!      disk drives.
--!
--!      In this case, the term 'compatible' is a matter of
--!      opinion.  The Secure Digital chip does not have the
--!      delays associated with the rotational latency of a
--!      disk drive and does not have delays associated with
--!      head motion.  The Secure Digital chip also transfers
--!      data (read and write) faster than a RK05 disk.
--!
--!      The disk drive can be configured to emulated these
--!      latencies.  It is not well tested and fortunately it
--!      appears that most applications do not require this
--!      level of timing fidelity.  Alternately small delays
--!      can be used which seem to work.
--!
--!      The Cylinder, Head, and Sector (CHS) addressing of
--!      the Secure Digital chip  has been borrowed from the
--!      SIMH simulator.  This allows SIMH RK05 disk images
--!      which are readily available on the internet to be
--!      used without modification.
--!
--!      The details of this mapping is described in the RK05
--!      device where the RK05 CHS addressing is manipulated to
--!      form the 32-bit linear sector address used by the
--!      Secure Digial Chip.
--!
--!      Since an RK05 image is somewhat less than 4 MB, the four
--!      RK05 images are aligned on 4 MB addresses.  Therefore
--!      a 16 MB Secure Digital chip is suffient storage for four
--!      RK05 disk drives.  I used a 4 GB Secure Digital chip
--!      because it was the smallest I could find.
--!
--!      The Secure Digital disk image for four RK05 disks is
--!      built as follows:
--!
--! \code
--! dd if=advent.rk05            of=/dev/sdc seek=0     count=6496
--! dd if=diagpack2.rk05         of=/dev/sdc seek=8192  count=6496
--! dd if=diag-games-kermit.rk05 of=/dev/sdc seek=16384 count=6496
--! dd if=multos8.rk05           of=/dev/sdc seek=24576 count=6496
--! \endcode
--!
--!      Your choice of disk images may vary.
--!
--!      The VHDL Code below is organized as follows:
--!      -# Bus Interface
--!      -# RK8E Registers
--!      -# 4x RK05 Timing Simulators
--!      -# Secure Digital Interface.
--!
--!      The Bus Interface operates asynchronously as requried for
--!      the the bus operation.   The Bus Interface decodes the
--!      various IOTs and creates "rk8eOPs" that are passed to the
--!      "RK8E Registers" process for action.
--!
--!      The "RK8E Registers" process maintains the controller state.
--!      When a disk command is received, it dispatches the command
--!      to one of the four RK05 where the delays associated with
--!      the disk drive are simulated.  (Each RK05 maintains a
--!      a notion of head, cyclinder, and sector so rotational
--!      and head motion delays can be accurate simulated).  Once
--!      The RK05 has completed it's operation, the command is
--!      forwarded to the Secure Digial disk device where the
--!      read or write is actually performed.
--!
--!      How this all works:
--!
--!      When the unit is powered-up, it runs through the SD Card
--!      initialization sequence.   This takes 3 or 4 milliseconds.
--!
--!      When the SD interface is initializing, the SD device
--!      asserts the sdINIT output which holds the processor in
--!      RESET.  That prevents the processor from giving the Disk
--!      Controller a command before it is finished initializing
--!      the SD Interface and the SD Card.
--!
--!      Once the SD Card is initialized, the SD interface waits
--!      in the stateIDLE state for a read command or a write
--!      command.
--!
--! \todo
--!      -# Most the of RK8E diagnostics are not implemented.
--!      -# The DMAN register and most of it's functionality is
--!         not implemented.
--!
--! \author
--!      Rob Doyle - doyle (at) cox (dot) net
--!
--------------------------------------------------------------------
--
--  Copyright (C) 2009, 2010, 2011, 2012 Rob Doyle
--
-- This source file may be used and distributed without
-- restriction provided that this copyright statement is not
-- removed from the file and that any derivative work contains
-- the original copyright notice and the associated disclaimer.
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- version 2.1 of the License.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl.txt
--
--------------------------------------------------------------------
--
-- Comments are formatted for doxygen
--
 
library ieee;                                           --! IEEE Library
use ieee.std_logic_1164.all;                            --! IEEE 1164
use ieee.numeric_std.all;                               --! IEEE Numeric Standard
use work.sd_types.all;                                  --! SD Types
use work.sdspi_types.all;                               --! SPI Types
use work.rk8e_types.all;                                --! RK8E types
use work.rk05_types.all;                                --! RK05 types
use work.cpu_types.all;                                 --! CPU types
 
--
--! RK8E Disk Controller Entity
--
 
entity eRK8E is port (
    sys       : in  sys_t;                              --! Clock/Reset
    -- Config
    devNUM    : in  devNUM_t;                           --! Device Number
    rk05INH   : in  std_logic_vector(0 to 3);           --! Write Inhibit
    rk05MNT   : in  std_logic_vector(0 to 3);           --! Device is Mounted
    -- DMA
    cpu       : in  cpu_t;                              --! CPU Output
    dev       : out dev_t;                              --! Device Output
    -- SD Interface
    sdCD      : in  std_logic;                          --! CD
    sdWP      : in  std_logic;                          --! WP
    sdMISO    : in  std_logic;                          --! Data In
    sdMOSI    : out std_logic;                          --! Data Out
    sdSCLK    : out std_logic;                          --! Clock
    sdCS      : out std_logic;                          --! Chip Select
    -- RK8E Status
    rk8eINIT  : out std_logic;                          --! RK8E is initializing
    rk8eSTAT  : out rk8eSTAT_t                          --! RK8E Status
);
end eRK8E;
 
--
--! RK8E Disk Controller RTL
--
 
architecture rtl of eRK8E is
 
    --
    -- Command Register
    --
 
    signal   rkcm        : data_t;                      --! Command Register
    subtype  rkcmFUN_t   is std_logic_vector(0 to 2);   --! FUN field type
    subtype  rkcmDRV_t   is std_logic_vector(0 to 1);   --! DRV Field type
    alias    rkcmFUN     : rkcmFUN_t is rkcm(0 to 2);   --! Function
    alias    rkcmIOD     : std_logic is rkcm(3);        --! Interrupt On Done
    alias    rkcmDOSD    : std_logic is rkcm(4);        --! Assert Done on Seek Done
    alias    rkcmLEN     : std_logic is rkcm(5);        --! Block Length
    alias    rkcmEMA     : field_t   is rkcm(6 to 8);   --! Extended Memory Address
    alias    rkcmDRV     : rkcmDRV_t is rkcm(9 to 10);  --! Drive Select
    alias    rkcmCYL0    : std_logic is rkcm(11);       --! Cylinder MSB
    constant funREAD     : rkcmFUN_t := "000";          --! Read Data Command
    constant funREADALL  : rkcmFUN_t := "001";          --! Read All Command
    constant funWRPROT   : rkcmFUN_t := "010";          --! Set write protect Command
    constant funSEEK     : rkcmFUN_t := "011";          --! Seek Command
    constant funWRITE    : rkcmFUN_t := "100";          --! Write Data Command
    constant funWRITEALL : rkcmFUN_t := "101";          --! Write All Command
 
    --
    -- Status Register bits that are implemented
    --
 
    signal   rkst        : data_t;                      --! Status register
    signal   rkstDONE    : std_logic;                   --! Device is done
    signal   rkstMOT     : std_logic;                   --! Head in Motion (seeking)
    signal   rkstFNR     : std_logic;                   --! File not ready
    signal   rkstBUSY    : std_logic;                   --! Controller is busy
    signal   rkstTME     : std_logic;                   --! Timing Error
    signal   rkstWLE     : std_logic;                   --! Write Lock Error
    signal   rkstSTE     : std_logic;                   --! Status Error
 
    --
    -- Memory Address Register
    --
 
    signal   rkma        : addr_t;                      --! Memory Address Register
 
    --
    -- Disk Address Register
    --
 
    subtype  rkdaCYL_t   is std_logic_vector(0 to 6);   --! RKDA Cylinder type
    subtype  rkdaSECT_t  is std_logic_vector(0 to 3);   --! RKDA Sector type
    subtype  rkdaHEAD_t  is std_logic;                  --! RKDA Head type
    signal   rkda        : data_t;                      --! Disk Address Register
    alias    rkdaCYL     : rkdaCYL_t  is rkda(0 to 6);  --! Cylinder
    alias    rkdaHEAD    : rkdaHEAD_t is rkda(7);       --! Head
    alias    rkdaSECT    : rkdaSECT_t is rkda(8 to 11); --! Sector
 
    --
    -- Maintenance Mode Registers
    --
 
    signal  maintMODE    : std_logic;                   --! Maintenance Mode
    signal  shiftEN      : std_logic;                   --! Shifter Enable
    signal  shiftCNT     : unsigned(0 to 3);            --! Shift Count
 
    --
    -- Disk Operations
    --
 
    type     rk8eOP_t    is (rk8eopNOP,                 --! Nothing to do
                             rk8eopDCLS,                --! Disk Clear Status
                             rk8eopDCLC,                --! Disk Clear Control
                             rk8eopDCLD,                --! Disk Clear Drive
                             rk8eopDLAG,                --! Disk Load and Go
                             rk8eopDLCA,                --! Disk Load Current Address
                             rk8eopDLDC,                --! Disk Load Command
                             rk8eopDMAN);               --! Disk Maintenace Mode
    signal   rk8eOP      : rk8eOP_t;                    --! Disk Operation
 
    --
    -- Device OP Codes
    -- Normally Device is 7x
    --
 
    constant opDSKP      : devOP_t    := o"1";          --! 6xx1 : Disk Skip on Flag
    constant opDCLR      : devOP_t    := o"2";          --! 6xx2 : Disk Clear
    constant opDLAG      : devOP_t    := o"3";          --! 6xx3 : Disk Load Address and Go
    constant opDLCA      : devOP_t    := o"4";          --! 6xx4 : Disk Load Current Address
    constant opDRST      : devOP_t    := o"5";          --! 6xx5 : Disk Read Status
    constant opDLDC      : devOP_t    := o"6";          --! 6xx6 : Disk Load Command
    constant opDMAN      : devOP_t    := o"7";          --! 6xx6 : Disk Maintenance
 
    --
    -- Clear Commands
    --
 
    subtype  clrOP_t     is std_logic_vector(0 to 1);
    constant clropCLS    : clrOP_t    := "00";          --! Clear Status
    constant clropCLC    : clrOP_t    := "01";          --! Clear Control
    constant clropCLD    : clrOP_t    := "10";          --! Clear Drive
    constant clropCLSA   : clrOP_t    := "11";          --! Clear Status Alt
 
    --
    -- RK05 Interfaces
    --
 
    signal   rk05OP      : rk05OP_tt;                   --! Array of RK05 OPs
    signal   rk05STAT    : rk05STAT_tt;                 --! Array of RK05 Status
    signal   rk05CYL     : rk05CYL_t;                   --! Cylinder
 
    --
    -- Interface to SD Controller
    --
 
    signal   sdOP        : sdOP_t;                      --! SD Device Command
    signal   sdLEN       : sdLEN_t;                     --! 128/256 Word access
    signal   sdMEMaddr   : addr_t;                      --! Memory Address
    signal   sdDISKaddr  : sdDISKaddr_t;                --! Linear Disk Address
    signal   sdFAIL      : std_logic;                   --! SD Failed
    signal   sdSTAT      : sdSTAT_t;                    --! SD Device Status
 
    --
    -- DMA Interface
    --
 
    signal   dmaDOUT     : data_t;                      --! DMA Data Out
    signal   dmaADDR     : addr_t;                      --! DMA Address
    signal   dmaRD       : std_logic;                   --! DMA Read
    signal   dmaWR       : std_logic;                   --! DMA Write
    signal   dmaREQ      : std_logic;                   --! DMA Request
 
    --
    -- Misc
    --
 
    signal   skipFLAG    : std_logic;                   --! Skip Flag
 
    --
    -- Drives
    --
 
    signal   driveSelect : rk05drvNUM_t;
    signal   rk05BUSY    : rk05drvNUM_t;
 
    --
    -- Bit OPs
    --
 
    type     bitOP_t     is (bitopNOP,
                             bitopSET,
                             bitopCLR);
    signal   bitopDONE   : bitOP_t;
    signal   bitopMOT    : bitOP_t;
    signal   bitopFNR    : bitOP_t;
    signal   bitopBUSY   : bitOP_t;
    signal   bitopTME    : bitOP_t;
    signal   bitopWLE    : bitOP_t;
    signal   bitopSTE    : bitOP_t;
 
    --
    -- Configuration
    --
 
    constant simh        : std_logic := '1';
    constant test        : std_logic := '0';
    constant simtime     : std_logic := '0';            --! Simulate disk timing
 
    --
    --! isBUSY:
    --!  Returns true if the controller is busy, false otherwise.
    --
 
    function isBUSY(rk05BUSY : rk05drvNUM_t) return boolean is
    begin
        if ((rk05BUSY = DRIVE0) or (rk05BUSY = DRIVE1) or
            (rk05BUSY = DRIVE2) or (rk05BUSY = DRIVE3)) then
            return true;
        else
            return false;
        end if;
    end isBUSY;
 
begin
 
    --
    -- RK05 Drive Select
    --
 
    driveSelect <= to_integer(unsigned(rkcmDRV));
 
    --
    -- RK05 Cylinder
    --
 
    rk05CYL <= rkcmCYL0 & rkdaCYL;
 
    --
    -- SD Failure
    --
 
    sdFAIL    <= '1' when ((sdSTAT.state = sdstateINFAIL) or
                           (sdSTAT.state = sdstateRWFAIL)) else '0';
 
    --
    -- SD Initializing
    --
 
    rk8eINIT  <= '1' when sdSTAT.state = sdstateINIT else '0';
 
    --
    --! RK8E Bus Interface
    --!
    --! \details
    --!     The Bus Interface decodes the individual RK8E IOT instructions.
    --!     The various disk operations are encoded into the rk8eOP command
    --!     which is applied to the RK8E state machine.
    --!
    --! \note
    --!     The Bus Interface is totally asynchronous.  The dev.ack,
    --!     dev.skip, and dev.devc signals are combinationally derived from
    --!     CPU output bus signals.  These signals will be sampled by the
    --!     CPU on the device bus input on the next clock cycle.
    --
 
    RK8E_BUSINTF : process(cpu.buss, devNUM, rkst, rkcm, dmaRD, dmaWR, dmaREQ,
                           skipFLAG, dmaDOUT, dmaADDR, sdDISKaddr)
    begin
 
        dev.ack   <= '0';
        dev.data  <= (others => '0');
        dev.devc  <= devWR;
        dev.skip  <= '0';
        dev.cpreq <= '0';
        dev.intr  <= rkcmIOD and skipFLAG;
        rk8eOP    <= rk8eopNOP;
 
        if cpu.buss.addr(0 to 2) = opIOT and cpu.buss.addr(3 to 8) = devNUM and cpu.buss.lxdar = '1' then
 
            case cpu.buss.addr(9 to 11) is
 
                --
                -- IOT 6xx1: DSKP - Disk Skip on Flag
                --
 
                when opDSKP =>
                    dev.ack  <= '1';
                    dev.devc <= devWR;
                    dev.skip <= skipFLAG;
                    rk8eOP   <= rk8eopNOP;
 
                --
                -- IOT 6xx2: DCLR - Disk Clear
                --
 
                when opDCLR =>
                    dev.ack   <= '1';
                    dev.devc  <= devWRCLR;
                    dev.skip  <= '0';
 
                    case cpu.buss.data(10 to 11) is
 
                        --
                        -- DCLS: Clear AC and Status Register
                        --
 
                        when clropCLS =>
                            rk8eOP <= rk8eopDCLS;
 
                        --
                        -- DCLC: Clear AC, Control, everything.
                        --
 
                        when clropCLC =>
                            rk8eOP <= rk8eopDCLC;
 
                        --
                        -- DCLD: Clear AC, recalibrate to track 0,
                        -- and clear Status Register
                        --
 
                        when clropCLD =>
                            rk8eOP <= rk8eopDCLD;
 
                        --
                        -- DCLSA: Clear Status (Alt Decode of DCLS)
                        --
 
                        when clropCLSA =>
                            rk8eOP <= rk8eopDCLS;
 
                        --
                        -- Everything else
                        --
 
                        when others =>
                            rk8eOP <= rk8eopNOP;
 
                    end case;
 
                --
                -- IOT 6xx3: DLAG - Disk Load Address and Go
                --
 
                when opDLAG =>
                    dev.ack  <= '1';
                    dev.devc <= devWRCLR;
                    rk8eOP   <= rk8eopDLAG;
 
                --
                -- IOT 6xx4: DLCA - Disk Load Current Address
                --
 
                when opDLCA =>
                    dev.ack  <= '1';
                    dev.devc <= devWRCLR;
                    rk8eOP   <= rk8eopDLCA;
 
                --
                -- IOT 6xx5: DRST - Disk Read STatus
                --
 
                when opDRST =>
                    dev.ack  <= '1';
                    dev.devc <= devRDCLR;
                    dev.data <= rkst;
                    rk8eOP   <= rk8eopNOP;
 
                --
                -- IOT 6xx6: DLDC - Disk Load Disk Command
                --
 
                when opDLDC =>
                    dev.ack  <= '1';
                    dev.devc <= devWRCLR;
                    rk8eOP   <= rk8eopDLDC;
 
                --
                -- IOT 6xx7: DMAN - Maintenance Instruction
                --
 
                when opDMAN =>
                    dev.ack <= '1';
                    rk8eOP  <= rk8eopDMAN;
                    if cpu.buss.data(7) = '1' then
                        dev.devc <= devRDCLR;
                        dev.data <= o"5555";
                    else
                        dev.devc <= devWRCLR;
                    end if;
 
                --
                -- Everthing else
                --
 
                when others =>
                    rk8eOP <= rk8eopNOP;
 
            end case;
 
        --
        -- DMA Operation
        --
 
        else
 
            if dmaWR = '1' then
                dev.data(0 to 11) <= dmaDOUT;
            end if;
 
        end if;
 
        dev.dma.rd     <= dmaRD;
        dev.dma.wr     <= dmaWR;
        dev.dma.req    <= dmaREQ;
        dev.dma.memsel <= dmaRD or dmaWR;
        dev.dma.lxmar  <= dmaRD or dmaWR;
        dev.dma.lxpar  <= '0';
        dev.dma.addr   <= dmaADDR;
        dev.dma.eaddr  <= rkcmEMA;
 
    end process RK8E_BUSINTF;
 
    --
    --! RK8E Register Set and State Machine
    --!
    --! \details
    --!     The various rk8eOPs that were decoded by the Bus Interface
    --!     are dispatched and handled by this state machine.
 
    RK8E_REGS : process(sys)
 
    begin
 
        if sys.rst = '1' then
            rkcm           <= (others => '0');
            rkma           <= (others => '0');
            rkda           <= (others => '0');
            shiftCNT       <= (others => '0');
            maintMODE      <= '0';
            shiftEN        <= '0';
            skipFLAG       <= '0';
            bitopDONE      <= bitopCLR;
            bitopMOT       <= bitopCLR;
            bitopFNR       <= bitopCLR;
            bitopBUSY      <= bitopCLR;
            bitopTME       <= bitopCLR;
            bitopWLE       <= bitopCLR;
            bitopSTE       <= bitopCLR;
            rk05OP(DRIVE0) <= rk05opCLR;
            rk05OP(DRIVE1) <= rk05opCLR;
            rk05OP(DRIVE2) <= rk05opCLR;
            rk05OP(DRIVE3) <= rk05opCLR;
            rk05BUSY       <= DRIVENULL;
 
        elsif rising_edge(sys.clk) then
 
            bitopDONE      <= bitopNOP;
            bitopMOT       <= bitopNOP;
            bitopFNR       <= bitopNOP;
            bitopBUSY      <= bitopNOP;
            bitopTME       <= bitopNOP;
            bitopWLE       <= bitopNOP;
            bitopSTE       <= bitopNOP;
            rk05OP(DRIVE0) <= rk05opNOP;
            rk05OP(DRIVE1) <= rk05opNOP;
            rk05OP(DRIVE2) <= rk05opNOP;
            rk05OP(DRIVE3) <= rk05opNOP;
 
            if cpu.buss.ioclr = '1' then
 
                rkcm           <= (others => '0');
                rkma           <= (others => '0');
                rkda           <= (others => '0');
                shiftCNT       <= (others => '0');
                maintMODE      <= '0';
                shiftEN        <= '0';
                skipFLAG       <= '0';
                bitopDONE      <= bitopCLR;
                bitopMOT       <= bitopCLR;
                bitopFNR       <= bitopCLR;
                bitopBUSY      <= bitopCLR;
                bitopTME       <= bitopCLR;
                bitopWLE       <= bitopCLR;
                bitopSTE       <= bitopCLR;
                rk05OP(DRIVE0) <= rk05opCLR;
                rk05OP(DRIVE1) <= rk05opCLR;
                rk05OP(DRIVE2) <= rk05opCLR;
                rk05OP(DRIVE3) <= rk05opCLR;
                rk05BUSY       <= DRIVENULL;
 
            else
 
                case rk8eOP is
 
                    --
                    -- Nothing to do
                    --
 
                    when rk8eopNOP =>
                        null;
 
                    --
                    -- DCLS: Disk Clear Status - Clear AC and Status Register
                    --
 
                    when rk8eopDCLS =>
                        skipFLAG  <= '0';
                        bitopDONE <= bitopCLR;
                        bitopMOT  <= bitopCLR;
                        bitopFNR  <= bitopCLR;
                        bitopBUSY <= bitopCLR;
                        bitopTME  <= bitopCLR;
                        bitopWLE  <= bitopCLR;
                        bitopSTE  <= bitopCLR;
 
                        if simh = '1' then
                            if isBUSY(rk05BUSY) then
                                bitopBUSY <= bitopSET;
                            end if;
                        else
                            if rk05STAT(driveSelect).mounted = '0' then
                                bitopMOT <= bitopSET;
                                bitopFNR <= bitopSET;
                            end if;
                            if rk05STAT(driveSelect).recal = '1' then
                                bitopBUSY <= bitopSET;
                                bitopSTE  <= bitopSET;
                                skipFLAG  <= '1';
                            end if;
                        end if;
 
                    --
                    -- DCLC: Disk Clear Control - Clear AC, Control, and Major Registers
                    --
 
                    when rk8eopDCLC =>
                        skipFLAG       <= '0';
                        rkcm           <= (others => '0');
                        rkma           <= (others => '0');
                        rkda           <= (others => '0');
                        shiftCNT       <= (others => '0');
                        maintMODE      <= '0';
                        shiftEN        <= '0';
                        bitopDONE      <= bitopCLR;
                        bitopMOT       <= bitopCLR;
                        bitopFNR       <= bitopCLR;
                        bitopBUSY      <= bitopCLR;
                        bitopTME       <= bitopCLR;
                        bitopWLE       <= bitopCLR;
                        bitopSTE       <= bitopCLR;
                        rk05OP(DRIVE0) <= rk05opCLR;
                        rk05OP(DRIVE1) <= rk05opCLR;
                        rk05OP(DRIVE2) <= rk05opCLR;
                        rk05OP(DRIVE3) <= rk05opCLR;
                        rk05BUSY       <= DRIVENULL;
 
                        if simh = '0' then
                            if rk05STAT(DRIVE0).mounted = '0' then
                                bitopMOT <= bitopSET;
                                bitopFNR <= bitopSET;
                            end if;
                        end if;
 
                    --
                    -- DCLD: Disk Clear Drive - Clear AC, recalibrate selected
                    -- drive to track 0, and clear Status Register.
                    --
 
                    when rk8eopDCLD =>
                        bitopDONE <= bitopCLR;
                        bitopMOT  <= bitopCLR;
                        bitopFNR  <= bitopCLR;
                        bitopBUSY <= bitopCLR;
                        bitopTME  <= bitopCLR;
                        bitopWLE  <= bitopCLR;
                        bitopSTE  <= bitopCLR;
 
                        if simh = '1' then
                            if isBUSY(rk05BUSY) then
                                bitopBUSY <= bitopSET;
                            else
                                if rk05STAT(driveSelect).mounted = '0' then
                                    bitopDONE <= bitopSET;
                                    bitopFNR  <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                elsif isBUSY(rk05BUSY) then
                                    bitopDONE <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                else
                                    bitopDONE <= bitopSET;
                                    skipFLAG  <= '1';
                                    rk05OP(driveSelect) <= rk05opRECAL;
                                 end if;
                            end if;
                        else
                            if rk05STAT(driveSelect).mounted = '0' then
                                bitopMOT <= bitopSET;
                                bitopFNR <= bitopSET;
                                bitopSTE <= bitopSET;
                                if rk05STAT(driveSelect).recal = '1' then
                                    bitopBUSY <= bitopSET;
                                end if;
                                if maintMODE = '0' then
                                    skipFLAG  <= '1';
                                end if;
                            else
                                rk05OP(driveSelect) <= rk05opRECAL;
                                bitopDONE <= bitopSET;
                                skipFLAG  <= '1';
                            end if;
 
                        end if;
 
                    --
                    -- DLAG: Disk Load and Go.  If the disk is not already busy,
                    -- the contents of AC are loaded into the Disk Address
                    -- Register.  Run the command from the command register.
                    --
 
                    when rk8eopDLAG =>
 
                        if simh = '1' then
                            if isBUSY(rk05BUSY) then
                                bitopBUSY <= bitopSET;
                            else
                                rkda <= cpu.buss.data;
                                if rk05STAT(driveSelect).mounted = '0' then
                                    bitopDONE <= bitopSET;
                                    bitopFNR  <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                elsif rk05STAT(driveSelect).state = rk05stBUSY then
                                    bitopDONE <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                elsif unsigned(rkcmCYL0 & cpu.buss.data(0 to 6)) > 202 then
                                    bitopDONE <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                else
                                    case rkcmFUN is
 
                                        --
                                        -- Write Protect Command
                                        --
 
                                        when funWRPROT =>
                                            bitopDONE <= bitopSET;
                                            skipFLAG  <= '1';
                                            rk05OP(driveSelect) <= rk05opWRPROT;
 
                                        --
                                        -- Seek Command
                                        --
 
                                        when funSEEK =>
                                            bitopDONE <= bitopSET;
                                            bitopMOT  <= bitopSET;
                                            skipFLAG  <= '1';
                                            rk05OP(driveSelect) <= rk05opSEEK;
 
                                        --
                                        -- Read Command
                                        --
 
                                        when funREAD | funREADALL =>
                                            bitopBUSY <= bitopSET;
                                            bitopMOT  <= bitopSET;
                                            rk05BUSY  <= driveSelect;
                                            rk05OP(driveSelect) <= rk05opREAD;
 
                                        --
                                        -- Write Command
                                        --
 
                                        when funWRITE | funWRITEALL =>
                                            if rk05STAT(driveSelect).WRINH = '1' then
                                                bitopDONE <= bitopSET;
                                                bitopMOT  <= bitopSET;
                                                bitopWLE  <= bitopSET;
                                                skipFLAG  <= '1';
                                            else
                                                bitopBUSY <= bitopSET;
                                                bitopMOT  <= bitopSET;
                                                rk05BUSY  <= driveSelect;
                                                rk05OP(driveSelect) <= rk05opWRITE;
                                            end if;
 
                                        --
                                        -- Functions 6 and 7 are unused.
                                        --
 
                                        when others =>
                                            bitopDONE <= bitopSET;
                                            bitopTME  <= bitopSET;
                                            skipFLAG  <= '1';
 
                                    end case;
                                end if;
                            end if; --! BUSY
                        else -- !SIMH
                            if ((rk05STAT(driveSelect).recal = '0' and rk05STAT(driveSelect).WRINH = '0') or
                                (rk05STAT(driveSelect).recal = '0' and maintMODE = '1')) then
                                rkda <= cpu.buss.data;
                            end if;
                            if rk05STAT(driveSelect).mounted = '0' then
                                bitopMOT <= bitopSET;
                                bitopFNR <= bitopSET;
                                bitopSTE <= bitopSET;
                                skipFLAG <= '1';
                            else
                                null;
                            end if;
                        end if;
 
                    --
                    -- DLCA: Disk Load Current Address.  If the disk is not already
                    -- busy, the contents of AC are loaded into the Current Address
                    -- Register.
                    --
 
                    when rk8eopDLCA =>
 
                        if simh = '1' then
                            if isBUSY(rk05BUSY) then
                                bitopBUSY <= bitopSET;
                            else
                                rkma <= cpu.buss.data;
                            end if;
                        else
                            rkma <= cpu.buss.data;
                            if rk05STAT(driveSelect).recal = '1' then
                                bitopBUSY <= bitopSET;
                                skipFLAG <= '1';
                            end if;
                        end if;
 
                    --
                    -- DLDC: Load Command - The content of the AC is loaded
                    -- into the disk command register.  The AC and the Status
                    -- Register are cleared.
                    --
 
                    when rk8eopDLDC =>
                        bitopDONE <= bitopCLR;
                        bitopMOT  <= bitopCLR;
                        bitopFNR  <= bitopCLR;
                        bitopBUSY <= bitopCLR;
                        bitopTME  <= bitopCLR;
                        bitopWLE  <= bitopCLR;
                        bitopSTE  <= bitopCLR;
                        skipFLAG  <= '0';
 
                        if simh = '1' then
                            if isBUSY(rk05BUSY) then
                               bitopBUSY <= bitopSET;
                             else
                                rkcm <= cpu.buss.data;
                            end if;
                        else
                            if maintMODE = '0' or rk05STAT(driveSelect).recal = '0' then
                                rkcm <= cpu.buss.data;
                            end if;
                            if rk05STAT(driveSelect).mounted = '1' then
                                if isBUSY(rk05BUSY) then
                                    bitopMOT <= bitopSET;
                                end if;
                            else
                                bitopMOT <= bitopSET;
                                bitopFNR <= bitopSET;
                                if rk05STAT(driveSelect).recal = '1' then
                                    bitopBUSY <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    skipFLAG  <= '1';
                                end if;
                            end if;
                        end if;
 
                    --
                    -- DMAN: Disk Maintenance Mode - AC(0) Enables maintence mode.
                    --
 
                    when rk8eopDMAN =>
                        maintMODE <= cpu.buss.data(0);
                        shiftEN   <= '0';
                        shiftCNT  <= "0000";
                        if maintMODE = '1' then
 
                            --
                            -- Enable shift to data buffer (DB4)
                            --
 
                            if cpu.buss.data(1) = '1' then
 
                            --
                            --
                            --
 
                            elsif cpu.buss.data(2) = '1' then
 
                            elsif cpu.buss.data(3) = '1' then
 
 
 
                            end if;
                        end if;
 
                    --
                    -- Everthing else
                    --
 
                    when others =>
                        null;
 
                end case;
 
                --
                -- Handle RK05 completion events
                --
 
                sdOP <= sdopNOP;
                if isBUSY(rk05BUSY) then
 
                    if rk05STAT(rk05BUSY).state = rk05stDONE then
                        bitopMOT <= bitopCLR;
                        case rk05STAT(rk05BUSY).sdOP is
 
                            --
                            -- sdopNOP
                            --  This is asserted on a SEEK or RECALIBRATE completion.
                            --
 
                            when sdopNOP =>
                                if rkcmDOSD = '1' then
                                    bitopDONE <= bitopSET;
                                end if;
 
                            --
                            -- sdopABORT
                            --  This is asserted on a DCLC command
                            --
 
                            when sdopABORT =>
                                sdOP <= sdopABORT;
 
                            --
                            -- sdopRD
                            --
 
                            when sdopRD =>
                                if rk05STAT(rk05BUSY).mounted = '0' then
                                    bitopDONE <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    rk05BUSY  <= DRIVENULL;
                                else
                                    sdOP       <= rk05STAT(rk05BUSY).sdOP;
                                    sdLEN      <= rk05STAT(rk05BUSY).sdLEN;
                                    sdMEMaddr  <= rk05STAT(rk05BUSY).sdMEMaddr;
                                    sdDISKaddr <= rk05STAT(rk05BUSY).sdDISKaddr;
                                end if;
 
                            --
                            -- sdopWR
                            --
 
                            when sdopWR =>
                                if rk05STAT(rk05BUSY).mounted = '0' then
                                    bitopDONE <= bitopSET;
                                    bitopSTE  <= bitopSET;
                                    rk05BUSY  <= DRIVENULL;
                                elsif rk05STAT(driveSelect).WRINH = '1' then
                                    bitopWLE  <= bitopSET;
                                    bitopDONE <= bitopSET;
                                    rk05BUSY  <= DRIVENULL;
                                else
                                    sdOP       <= rk05STAT(rk05BUSY).sdOP;
                                    sdLEN      <= rk05STAT(rk05BUSY).sdLEN;
                                    sdMEMaddr  <= rk05STAT(rk05BUSY).sdMEMaddr;
                                    sdDISKaddr <= rk05STAT(rk05BUSY).sdDISKaddr;
                                end if;
 
                            --
                            -- Anything else
                            --
 
                            when others =>
                                null;
                        end case;
                    end if;
                end if;
 
                --
                -- Handle SD completion events
                --
 
                if sdSTAT.state = sdstateDONE then
                    bitopDONE <= bitopSET;
                    bitopBUSY <= bitopCLR;
                    skipFLAG  <= '1';
                    rk05BUSY  <= DRIVENULL;
                    rkma      <= dmaADDR;
                end if;
 
            end if;
        end if;
 
    end process RK8E_REGS;
 
    --
    --! RK8E Status Register
    --
 
    RK8E_STATUS : process(sys)
    begin
        if sys.rst = '1' then
 
            rkstDONE <= '0';
            rkstMOT  <= '0';
            rkstFNR  <= '0';
            rkstBUSY <= '0';
            rkstTME  <= '0';
            rkstWLE  <= '0';
            rkstSTE  <= '0';
 
        elsif rising_edge(sys.clk) then
 
            if cpu.buss.ioclr = '1' then
 
                rkstDONE <= '0';
                rkstMOT  <= '0';
                rkstFNR  <= '0';
                rkstBUSY <= '0';
                rkstTME  <= '0';
                rkstWLE  <= '0';
                rkstSTE  <= '0';
 
            else
 
                case bitopDONE is
                    when bitopSET => rkstDONE <= '1';
                    when bitopCLR => rkstDONE <= '0';
                    when others   => null;
                end case;
                case bitopMOT is
                    when bitopSET => rkstMOT <= '1';
                    when bitopCLR => rkstMOT <= '0';
                    when others   => null;
                end case;
                case bitopFNR is
                    when bitopSET => rkstFNR <= '1';
                    when bitopCLR => rkstFNR <= '0';
                    when others   => null;
                end case;
                case bitopBUSY is
                    when bitopSET => rkstBUSY <= '1';
                    when bitopCLR => rkstBUSY <= '0';
                    when others   => null;
                end case;
                case bitopTME  is
                    when bitopSET => rkstTME <= '1';
                    when bitopCLR => rkstTME <= '0';
                    when others   => null;
                end case;
                case bitopWLE  is
                    when bitopSET => rkstWLE <= '1';
                    when bitopCLR => rkstWLE <= '0';
                    when others   => null;
                end case;
                case bitopSTE is
                    when bitopSET => rkstSTE <= '1';
                    when bitopCLR => rkstSTE <= '0';
                    when others   => null;
                end case;
            end if;
        end if;
    end process RK8E_STATUS;
 
    --
    -- Status Register
    --
 
    rkst <= rkstDONE & rkstMOT & '0' & '0' & rkstFNR  & rkstBUSY &
            rkstTME  & rkstWLE & '0' & '0' & rkstSTE  & '0';
 
    --
    --! RK05 Device #0
    --
 
    iRK05_0 : entity work.eRK05 (rtl) port map (
        sys         => sys,
        ioclr       => cpu.buss.ioclr,
        simtime     => simtime,
        sdWP        => sdWP,
        sdCD        => sdCD,
        sdFAIL      => sdFAIL,
        rk05INH     => rk05INH(DRIVE0),
        rk05MNT     => rk05MNT(DRIVE0),
        rk05OP      => rk05OP(DRIVE0),
        rk05CYL     => rk05CYL,
        rk05HEAD    => rkdaHEAD,
        rk05SECT    => rkdaSECT,
        rk05DRIVE   => "00",
        rk05LEN     => rkcmLEN,
        rk05MEMaddr => rkma,
        rk05STAT    => rk05STAT(DRIVE0)
    );
 
    --
    --! RK05 Device #1
    --
 
    iRK05_1 : entity work.eRK05 (rtl) port map (
        sys         => sys,
        ioclr       => cpu.buss.ioclr,
        simtime     => simtime,
        sdWP        => sdWP,
        sdCD        => sdCD,
        sdFAIL      => sdFAIL,
        rk05INH     => rk05INH(DRIVE1),
        rk05MNT     => rk05MNT(DRIVE1),
        rk05OP      => rk05OP(DRIVE1),
        rk05CYL     => rk05CYL,
        rk05HEAD    => rkdaHEAD,
        rk05SECT    => rkdaSECT,
        rk05DRIVE   => "01",
        rk05LEN     => rkcmLEN,
        rk05MEMaddr => rkma,
        rk05STAT    => rk05STAT(DRIVE1)
    );
 
    --
    --! RK05 Device #2
    --
 
    iRK05_2 : entity work.eRK05 (rtl) port map (
        sys         => sys,
        ioclr       => cpu.buss.ioclr,
        simtime     => simtime,
        sdWP        => sdWP,
        sdCD        => sdCD,
        sdFAIL      => sdFAIL,
        rk05INH     => rk05INH(DRIVE2),
        rk05MNT     => rk05MNT(DRIVE2),
        rk05OP      => rk05OP(DRIVE2),
        rk05CYL     => rk05CYL,
        rk05HEAD    => rkdaHEAD,
        rk05SECT    => rkdaSECT,
        rk05DRIVE   => "10",
        rk05LEN     => rkcmLEN,
        rk05MEMaddr => rkma,
        rk05STAT    => rk05STAT(DRIVE2)
    );
 
    --
    --! RK05 Device #3
    --
 
    iRK05_3 : entity work.eRK05 (rtl) port map (
        sys         => sys,
        ioclr       => cpu.buss.ioclr,
        simtime     => simtime,
        sdWP        => sdWP,
        sdCD        => sdCD,
        sdFAIL      => sdFAIL,
        rk05INH     => rk05INH(DRIVE3),
        rk05MNT     => rk05MNT(DRIVE3),
        rk05OP      => rk05OP(DRIVE3),
        rk05CYL     => rk05CYL,
        rk05HEAD    => rkdaHEAD,
        rk05SECT    => rkdaSECT,
        rk05DRIVE   => "11",
        rk05LEN     => rkcmLEN,
        rk05MEMaddr => rkma,
        rk05STAT    => rk05STAT(DRIVE3)
    );
 
    --
    --! Secure Digital Interface
    --
 
    iSD : entity work.eSD (rtl) port map (
        sys        => sys,
        ioclr      => cpu.buss.ioclr,
        -- PDP8 Interface
        dmaDIN     => cpu.buss.data,
        dmaDOUT    => dmaDOUT,
        dmaADDR    => dmaADDR,
        dmaRD      => dmaRD,
        dmaWR      => dmaWR,
        dmaREQ     => dmaREQ,
        dmaGNT     => cpu.buss.dmagnt,
        -- Interface to SD Hardware
        sdMISO     => sdMISO,
        sdMOSI     => sdMOSI,
        sdSCLK     => sdSCLK,
        sdCS       => sdCS,
        -- Interface to SD Controller
        sdOP       => sdOP,
        sdDISKaddr => sdDISKaddr,
        sdMEMaddr  => sdMEMaddr,
        sdLEN      => sdLEN,
        sdSTAT     => sdSTAT
    );
 
    rk8eSTAT.sdCD     <= sdCD;
    rk8eSTAT.sdWP     <= sdWP;
    rk8eSTAT.sdSTAT   <= sdSTAT;
    rk8eSTAT.rk05STAT <= rk05STAT;
 
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.