| |
| /* |
| * 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; |
| } |
| |
| } |