OpenCores
URL https://opencores.org/ocsvn/sdhc-sc-core/sdhc-sc-core/trunk

Subversion Repositories sdhc-sc-core

[/] [sdhc-sc-core/] [trunk/] [grpSdVerification/] [unitSdCardModel/] [src/] [SdCardModel.sv] - Rev 185

Compare with Previous | Blame | View Log

// SDHC-SC-Core
// Secure Digital High Capacity Self Configuring Core
// 
// (C) Copyright 2010, Rainer Kastl
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// File        : SdCardModel.sv
// Owner       : Rainer Kastl
// Description : SD Card model
// Links       : 
// 

`ifndef SDCARDMODEL
`define SDCARDMODEL

const logic cActivated = 1;
const logic cInactivated = 0;

`include "Crc.sv";
`include "SdCommand.sv";
`include "SdBFM.sv";
`include "Logger.sv";
`include "RamAction.sv";

class RamModel;
        local bit[0:511][7:0] data[];
        RamActionMb RamActionOutMb;

        function new(int size);
                data = new[size];
        endfunction

        function int size();
                return data.size();
        endfunction

        task getDataBlock(logic[31:0] addr, output SdDataBlock block);
                RamAction action = new(RamAction::Read, addr, data[addr]);
                block = new();

                for (int i = 0; i < 512; i++) begin
                        for (int j = 7; j >= 0; j--) begin
                                block.data.push_back(data[addr][i][j]);
                        end
                end

                if (RamActionOutMb != null)     
                begin
                        RamActionOutMb.put(action);
                end
        endtask

        task setDataBlock(logic[31:0] addr, SdDataBlock block);
                for (int i = 0; i < 512; i++) begin
                        for (int j = 7; j >= 0; j--) begin
                                data[addr][i][j] = block.data.pop_front();
                        end
                end

                if (RamActionOutMb != null)     
                begin
                        RamAction action = new(RamAction::Write, addr, data[addr]);
                        RamActionOutMb.put(action);
                end
        endtask

endclass

class SdCardModel;
        
        SdBfmMb SdTransOutMb;
        SdBfmMb SdTransInMb;

        SdBFM bfm;
        local SdCardModelState state = new();
        local RCA_t rca;
        local logic CCS;
        local Mode_t mode;
        local DataMode_t datamode;
        local Logger log = new();
        RamModel ram;

        //local rand int datasize; // ram addresses = 2^datasize - 1; 512 byte blocks
        //constraint cdatasize {datasize == 32;}
        
        /*function void post_randomize() ;
                this.ram = new[datasize];
        endfunction*/

        function new();
                this.CCS = 1;
                rca = 0;
                mode = standard;
                ram = new(100);
        endfunction

        task start();
                fork
                        run();
                join_none
        endtask

        task reset();
        endtask

        task automatic init();
                SDCommandR7 voltageresponse;
                SDCommandR1 response;
                SDCommandR3 acmd41response;
                SDCommandR2 cidresponse;
                SDOCR ocr;
                SDCommandR6 rcaresponse;
                logic data[$];
                SdBusTransToken token;

                log.note("Expecting CMD0");
                // expect CMD0 so that state is clear
                this.bfm.receive(token);
                assert(token.id == cSdCmdGoIdleState) else log.error("Received invalid token.");
                
                // expect CMD8: voltage and SD 2.00 compatible
                log.note("Expecting CMD8");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSendIfCond) else log.error("Received invalid token."); 
                assert(token.arg[12:8] == 'b0001) else
                begin
                        string msg;
                        $swrite(msg, "Received invalid arg: %b", token.arg);
                        log.error(msg); // Standard voltage
                end;

                // respond with R7: we are SD 2.00 compatible and compatible to the
                // voltage
                voltageresponse = new(token.arg);
                this.bfm.send(voltageresponse);

                recvCMD55(0);

                // expect ACMD41 with HCS = 1
                log.note("Expect ACMD41 (with HCS = 1)");
                this.bfm.receive(token);
                assert(token.id == cSdCmdACMD41) else log.error("Received invalid token.\n");
                assert(token.arg == cSdArgACMD41HCS) else begin
                        string msg;
                        $swrite(msg, "Received invalid arg: %b, Expected: %b", token.arg, cSdArgACMD41HCS);
                        log.error(msg);
                end;
                state.AppCmd = 0;

                // respond with R3, not done
                ocr = new(CCS, cSdVoltageWindow);
                acmd41response = new(ocr);
                this.bfm.send(acmd41response);
                
                recvCMD55(0);

                // expect ACMD41 with HCS = 1
                log.note("Expect ACMD41 (with HCS = 1)");
                this.bfm.receive(token);
                assert(token.id == cSdCmdACMD41) else log.error("Received invalid token.\n");
                assert(token.arg == cSdArgACMD41HCS) else begin
                        string msg;
                        $swrite(msg, "Received invalid arg: %b, Expected: %b", token.arg, cSdArgACMD41HCS);
                        log.error(msg);
                end;
                state.AppCmd = 0;

                // respond with R3
                ocr.setBusy(cOCRDone);
                acmd41response = new(ocr);
                this.bfm.send(acmd41response);

                // expect CMD2
                log.note("Expect CMD2");
                this.bfm.receive(token);
                assert(token.id == cSdCmdAllSendCID) else log.error("Received invalid token.\n");

                // respond with R2
                cidresponse = new();
                this.bfm.send(cidresponse);

                // expect CMD3
                log.note("Expect CMD3");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSendRelAdr) else log.error("Received invalid token.\n");

                // respond with R3
                rcaresponse = new(rca, state);
                this.bfm.send(rcaresponse);

                // expect CMD7
                log.note("Expect CMD7");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSelCard);
                assert(token.arg[31:16] == rca);

                // respond with R1, no busy
                state.ReadyForData = 1;
                response = new(cSdCmdSelCard, state);
                this.bfm.send(response);

                // expect ACMD51
                recvCMD55(rca);
                log.note("Expect ACMD51");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSendSCR);

                // respond with R1 and dummy SCR
                response = new(cSdCmdSendSCR, state);
                response.DataBlocks = new[1];
                response.DataBlocks[0] = new();
                
                // send dummy SCR
                for (int i = 0; i < 64; i++)
                        response.DataBlocks[0].data.push_back(0);
                
                response.DataBlocks[0].data[63-50] = 1;
                response.DataBlocks[0].data[63-48] = 1;

                this.bfm.send(response);

                // expect ACMD6
                recvCMD55(rca);
                log.note("Expect ACMD6");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSetBusWidth);
                assert(token.arg == 'h00000002);

                response = new(cSdCmdSetBusWidth, state);
                this.bfm.send(response);

                this.bfm.Mode = wide;
                mode = wide;

                // expect CMD6
                log.note("Expect CMD6");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSwitchFuntion);
                assert(token.arg == 'h00FFFFF1);

                response.DataBlocks = new[1];
                response.DataBlocks[0] = new();
                
                for (int i = 0; i < 512; i++)
                        response.DataBlocks[0].data.push_back(0);

                response.DataBlocks[0].data[511-401] = 1;
                response.DataBlocks[0].data[511-376] = 1;

                this.bfm.send(response);

                // expect CMD6 with set
                log.note("Expect CMD6 with set");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSwitchFuntion);
                assert(token.arg == 'h80FFFFF1);
                this.bfm.send(response);

                // switch to 50MHz
                // expect CMD13
                log.note("Expect CMD13");
                this.bfm.receive(token);
                assert(token.id == cSdCmdSendStatus);
                assert(token.arg == rca);
                response = new(cSdCmdSendStatus, state);
                this.bfm.send(response);

                log.note("Card init done");
        endtask

        task run();
                this.init();

                forever begin
                        SdBusTransToken token;
                        this.bfm.receive(token);

                        case (token.id)
                                cSdCmdWriteSingleBlock: this.write(token);
                                cSdCmdReadSingleBlock: this.read(token);
                                default: begin
                                                string msg;
                                                $swrite(msg, "Token not handled, ID: %b", token.id);
                                                log.error(msg);
                                end
                        endcase
                end
        endtask

        task read(SdBusTransToken token);
                SDCommandR1 response;
                logic[31:0] addr;

                // expect Read
                assert(token.id == cSdCmdReadSingleBlock);
                addr = token.arg;
                assert(addr <= ram.size()) else log.error("Read outside of available RAM");
                response = new(cSdCmdReadSingleBlock, state);
                response.DataBlocks = new[1];
                
                //$display("Ram before read (%h):  %h", addr, ram[addr]);
                ram.getDataBlock(addr, response.DataBlocks[0]);

                this.bfm.send(response);
        endtask

        task write(SdBusTransToken token);
                SDCommandR1 response;
                SdDataBlock rdblock;
                logic[31:0] addr;

                // expect Write
                assert(token.id == cSdCmdWriteSingleBlock);
                addr = token.arg;
                assert(addr <= ram.size()) else log.error("Write outside of available RAM");
                response = new(cSdCmdWriteSingleBlock, state);
                this.bfm.send(response);

                // recv data
                this.bfm.receiveDataBlock(rdblock);
                ram.setDataBlock(addr, rdblock);
        
                this.bfm.waitUntilReady();
                this.bfm.sendBusy();
        
        endtask

        task recvCMD55(RCA_t rca);
                SDCommandR1 response;
                SdBusTransToken token;
                
                // expect CMD55
                this.bfm.receive(token);
                assert(token.id == cSdCmdNextIsACMD);
                assert(token.arg[31:16] == rca);
                state.recvCMD55();

                // respond with R1
                response = new(cSdCmdNextIsACMD, state);
                this.bfm.send(response);        
        endtask
        
endclass

class NoSdCardModel extends SdCardModel;

        function new();
                super.new();
        endfunction

        task automatic init();
        endtask

endclass

`endif

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.