/* * Copyright (c) 1999-2005 Mark D. Hill and David A. Wood * 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 copyright holders 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 THE COPYRIGHT * OWNER OR CONTRIBUTORS 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. */ /* * $Id$ * */ machine(Directory, "MOSI Broadcast Optimized") { MessageBuffer addressFromDir, network="To", virtual_network="0", ordered="true"; MessageBuffer dataFromDir, network="To", virtual_network="1", ordered="false"; MessageBuffer addressToDir, network="From", virtual_network="0", ordered="true"; MessageBuffer dataToDir, network="From", virtual_network="1", ordered="false"; enumeration(State, desc="Directory states", default="Directory_State_C") { C, desc="Cold - no processor has requested this line"; I, desc="Idle"; S, desc="Shared"; SS, desc="Shared, 2 or more shares"; OS, desc="Owned by a cache"; OSS, desc="Owned by a cache, present in at least 3 caches"; M, desc="Modified", format="!b"; } // ** EVENTS ** enumeration(Event, desc="Directory events") { // From Address network OtherAddress, desc="We saw an address msg to someone else"; GETS, desc="A GETS arrives"; GET_INSTR, desc="A GETInstr arrives"; GETX, desc="A GETX arrives", format="!r"; PUTX_Owner, desc="A PUTX arrives, requestor is owner"; PUTX_NotOwner, desc="A PUTX arrives, requestor is not owner", format="!r"; Memory_Data, desc="Fetched data from memory arrives"; Memory_Ack, desc="Writeback Ack from memory arrives"; } // TYPES // DirectoryEntry structure(Entry, desc="...") { State DirectoryState, desc="Directory state"; bool DirOwner, default="true", desc="Is dir owner?"; MachineID ProcOwner, desc="Processor Owner"; DataBlock DataBlk, desc="data for the block"; } external_type(DirectoryMemory) { Entry lookup(Address); bool isPresent(Address); } // to simulate detailed DRAM external_type(MemoryControl, inport="yes", outport="yes") { } // ** OBJECTS ** DirectoryMemory directory, constructor_hack="i"; MemoryControl memBuffer, constructor_hack="i"; void profile_request(int cache_state, State directory_state, GenericRequestType request_type); State getState(Address addr) { if (directory.isPresent(addr)) { return directory[addr].DirectoryState; } return State:C; } void setState(Address addr, State state) { if (directory.isPresent(addr)) { directory[addr].DirectoryState := state; } } // ** OUT_PORTS ** out_port(dataNetwork_out, DataMsg, dataFromDir); out_port(addressNetwork_out, AddressMsg, addressFromDir); out_port(memQueue_out, MemoryMsg, memBuffer); // ** IN_PORTS ** // Address Network in_port(addressNetwork_in, AddressMsg, addressToDir) { if (addressNetwork_in.isReady()) { peek(addressNetwork_in, AddressMsg) { if(map_Address_to_Directory(in_msg.Address) != machineID) { trigger(Event:OtherAddress, in_msg.Address); } else if (in_msg.Type == CoherenceRequestType:GETS) { trigger(Event:GETS, in_msg.Address); } else if (in_msg.Type == CoherenceRequestType:GET_INSTR) { trigger(Event:GET_INSTR, in_msg.Address); } else if (in_msg.Type == CoherenceRequestType:GETX) { trigger(Event:GETX, in_msg.Address); } else if (in_msg.Type == CoherenceRequestType:PUTX) { if (in_msg.Requestor == directory[in_msg.Address].ProcOwner && directory[in_msg.Address].DirOwner == false) { trigger(Event:PUTX_Owner, in_msg.Address); } else { trigger(Event:PUTX_NotOwner, in_msg.Address); } } else { error("unexpected message"); } } } } // off-chip memory request/response is done in_port(memQueue_in, MemoryMsg, memBuffer) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { trigger(Event:Memory_Data, in_msg.Address); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { trigger(Event:Memory_Ack, in_msg.Address); } else { DEBUG_EXPR(in_msg.Type); error("Invalid message"); } } } } // *** ACTIONS *** action(d_sendDataMsg, "d", desc="Send data message to requestor") { peek(memQueue_in, MemoryMsg) { enqueue(dataNetwork_out, DataMsg, latency="1") { out_msg.Address := in_msg.Address; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.OriginalRequestorMachId); out_msg.DestMachine := MachineType:L1Cache; //out_msg.DataBlk := directory[in_msg.Address].DataBlk; out_msg.DataBlk := in_msg.DataBlk; out_msg.MessageSize := MessageSizeType:Data; DEBUG_EXPR(in_msg.OriginalRequestorMachId); DEBUG_EXPR(out_msg.DataBlk); } } } action(j_popAddressQueue, "j", desc="Pop address queue.") { addressNetwork_in.dequeue(); } action(l_popMemQueue, "q", desc="Pop off-chip request queue") { memQueue_in.dequeue(); } action(p_profile, "p", desc="Profile this transition.") { peek(addressNetwork_in, AddressMsg) { profile_request(in_msg.CacheState, getState(address), convertToGenericType(in_msg.Type)); } } action(m_setOwnerRequestor, "m", desc="Set owner = requestor") { peek(addressNetwork_in, AddressMsg) { directory[in_msg.Address].ProcOwner := in_msg.Requestor; directory[in_msg.Address].DirOwner := false; } } action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { peek(addressNetwork_in, AddressMsg) { enqueue(memQueue_out, MemoryMsg, latency="1") { out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_READ; out_msg.Sender := machineID; out_msg.OriginalRequestorMachId := in_msg.Requestor; out_msg.DataBlk := directory[in_msg.Address].DataBlk; out_msg.MessageSize := in_msg.MessageSize; //out_msg.Prefetch := in_msg.Prefetch; DEBUG_EXPR(out_msg); } } } action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") { peek(addressNetwork_in, AddressMsg) { enqueue(memQueue_out, MemoryMsg, latency="1") { out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; out_msg.Sender := machineID; out_msg.OriginalRequestorMachId := in_msg.Requestor; out_msg.DataBlk := in_msg.DataBlk; out_msg.MessageSize := in_msg.MessageSize; //out_msg.Prefetch := in_msg.Prefetch; DEBUG_EXPR(out_msg); } } } action(r_writeDataFromRequest, "r", desc="Write request data to memory") { peek(addressNetwork_in, AddressMsg) { directory[in_msg.Address].DataBlk := in_msg.DataBlk; DEBUG_EXPR(in_msg.Address); DEBUG_EXPR(in_msg.DataBlk); } } action(x_setOwnerToDirectory, "x", desc="Set owner equal to the directory"){ peek(addressNetwork_in, AddressMsg) { directory[in_msg.Address].DirOwner := true; } } // TRANSITIONS // Ignore all address and data messages not bound for us transition(C, OtherAddress) { j_popAddressQueue; } // PUTX_NotOwner Transitions transition({I, S, SS, OS, OSS, M}, PUTX_NotOwner) { p_profile; j_popAddressQueue; } // Transitions from Idle transition({C, I}, {GETS,GET_INSTR}, S) { //d_sendDataMsg; qf_queueMemoryFetchRequest; p_profile; j_popAddressQueue; } transition({C, I}, GETX, M) { //d_sendDataMsg; qf_queueMemoryFetchRequest; m_setOwnerRequestor; p_profile; j_popAddressQueue } // Transitions from Shared transition({S, SS}, {GETS,GET_INSTR}, SS) { //d_sendDataMsg; qf_queueMemoryFetchRequest; p_profile; j_popAddressQueue; } transition({S, SS}, GETX, M) { //d_sendDataMsg; qf_queueMemoryFetchRequest; m_setOwnerRequestor; p_profile; j_popAddressQueue; } // Transitions from Owned transition({OS, OSS}, {GETS,GET_INSTR}, OSS) { p_profile; j_popAddressQueue; } transition({OS, OSS}, GETX, M) { m_setOwnerRequestor; p_profile; j_popAddressQueue; } transition(OS, PUTX_Owner, S) { x_setOwnerToDirectory; r_writeDataFromRequest; qw_queueMemoryWBRequest; p_profile; j_popAddressQueue; } transition(OSS, PUTX_Owner, SS) { x_setOwnerToDirectory; r_writeDataFromRequest; qw_queueMemoryWBRequest; p_profile; j_popAddressQueue; } // Transitions from Modified transition(M, {GETS,GET_INSTR}, OS) { p_profile; j_popAddressQueue; } transition(M, GETX) { m_setOwnerRequestor; p_profile; j_popAddressQueue; } transition(M, PUTX_Owner, I) { x_setOwnerToDirectory; r_writeDataFromRequest; qw_queueMemoryWBRequest; p_profile; j_popAddressQueue; } transition({C, I, S, SS, OS, OSS, M}, Memory_Data) { d_sendDataMsg; l_popMemQueue; } transition({C, I, S, SS, OS, OSS, M}, Memory_Ack) { //a_sendAck; l_popMemQueue; } }