From bec01f1540e932d0348d38758e0917d520972412 Mon Sep 17 00:00:00 2001 From: zinsser Date: Sun, 8 Apr 2018 12:11:09 -0700 Subject: [PATCH] Release v1.3 Mips_core extracted. --- README.txt | 9 +- src/core_memory_arbiter.v | 138 +++++++++ src/d_cache.v | 11 +- src/decoder.v | 21 +- src/hazard_detection_unit.v | 11 +- src/i_cache.v | 13 +- src/memory_arbiter.v | 212 +++++--------- src/mips_core.v | 654 +++++++++++++++++++++++++++++++++++++++++++ src/mips_cpu.v | 665 +++++--------------------------------------- 9 files changed, 973 insertions(+), 761 deletions(-) mode change 100644 => 100755 README.txt create mode 100644 src/core_memory_arbiter.v create mode 100644 src/mips_core.v diff --git a/README.txt b/README.txt old mode 100644 new mode 100755 index e2bc1a3..9174458 --- a/README.txt +++ b/README.txt @@ -1,8 +1,11 @@ -CSE148 Baseline Design v1.2 (1/11/11) -by Pravin Prabhu & Todor Mollov +CSE148 Baseline Design v1.3 (04/29/2017) +by Pravin Prabhu & Todor Mollov & Zinsser Zhang //============================================================================== Changelog: +(04/29/2017)v1.3 released + - Extracted mips_core from other FPGA related components + (1/11/11) v1.2 released - Now completely implementable in hardware! - Renamed some top-level signals to more closely match H&P @@ -159,4 +162,4 @@ Questions/Comments -- please contact me (Pravin Prabhu) via email (pprabhu@ucsd.edu) or through my office hours. - Happy hardware hacking! \ No newline at end of file + Happy hardware hacking! diff --git a/src/core_memory_arbiter.v b/src/core_memory_arbiter.v new file mode 100644 index 0000000..942614d --- /dev/null +++ b/src/core_memory_arbiter.v @@ -0,0 +1,138 @@ +/* core_memory_arbiter.v +* Author: Zinsser Zhang +* Last Revision: 04/29/2017 +* Based on Pravin P. Prabhu's memory_arbiter.v +* Abstract: +* Provides arbitration between i_cache and d_cache for request to memory. +* All addresses used in this scope are word addresses (32-bit/4-byte aligned) +* Will service sources in order of priority, which is: +* (high) +* imem +* dmem +* (low) +*/ +module core_memory_arbiter #( parameter DATA_WIDTH=32, + parameter ADDRESS_WIDTH=21 + ) + ( + // General + input i_Clk, + input i_Reset_n, + + // Requests to/from IMEM - Assume we always read + input i_IMEM_Valid, // If IMEM request is valid + input [ADDRESS_WIDTH-1:0] i_IMEM_Address, // IMEM request addr. + output reg o_IMEM_Valid, + output reg o_IMEM_Last, + output reg [DATA_WIDTH-1:0] o_IMEM_Data, + + // Requests to/from DMEM + input i_DMEM_Valid, + input i_DMEM_Read_Write_n, + input [ADDRESS_WIDTH-1:0] i_DMEM_Address, + input [DATA_WIDTH-1:0] i_DMEM_Data, + output reg o_DMEM_Valid, + output reg o_DMEM_Data_Read, + output reg o_DMEM_Last, + output reg [DATA_WIDTH-1:0] o_DMEM_Data, + + // Interface to outside of the core + output reg o_MEM_Valid, + output reg [ADDRESS_WIDTH-1:0] o_MEM_Address, + output reg o_MEM_Read_Write_n, + + // Write data interface + output reg [DATA_WIDTH-1:0] o_MEM_Data, + input i_MEM_Data_Read, + + // Read data interface + input [DATA_WIDTH-1:0] i_MEM_Data, + input i_MEM_Valid, + + input i_MEM_Last // If we're on the last piece of the transaction + ); + + // Consts + localparam TRUE = 1'b1; + localparam FALSE = 1'b0; + localparam READ = 1'b1; + localparam WRITE = 1'b0; + + // State of the arbiter + localparam STATE_READY = 4'd0; + localparam STATE_SERVICING_IMEM = 4'd1; + localparam STATE_SERVICING_DMEM = 4'd2; + + reg [3:0] State; + reg [3:0] NextState; + + always @(*) + begin + NextState <= State; + case(State) + STATE_READY: + begin + if (i_IMEM_Valid) + NextState <= STATE_SERVICING_IMEM; + else if (i_DMEM_Valid) + NextState <= STATE_SERVICING_DMEM; + end + + STATE_SERVICING_IMEM: + begin + if (i_MEM_Last) + NextState <= STATE_READY; + end + + STATE_SERVICING_DMEM: + begin + if (i_MEM_Last) + NextState <= STATE_READY; + end + endcase + + o_IMEM_Valid <= FALSE; + o_IMEM_Last <= FALSE; + o_IMEM_Data <= {32{1'bx}}; + o_DMEM_Valid <= FALSE; + o_DMEM_Data_Read <= FALSE; + o_DMEM_Last <= FALSE; + o_DMEM_Data <= {32{1'bx}}; + o_MEM_Valid <= FALSE; + o_MEM_Address <= {ADDRESS_WIDTH{1'bx}}; + o_MEM_Read_Write_n <= READ; + o_MEM_Data <= {32{1'bx}}; + + if (State == STATE_SERVICING_IMEM || NextState == STATE_SERVICING_IMEM) + begin + o_MEM_Valid <= TRUE; + o_MEM_Address <= i_IMEM_Address; + o_MEM_Read_Write_n <= READ; + o_IMEM_Valid <= i_MEM_Valid; + o_IMEM_Last <= i_MEM_Last; + o_IMEM_Data <= i_MEM_Data; + end + else if (State == STATE_SERVICING_DMEM || NextState == STATE_SERVICING_DMEM) + begin + o_MEM_Valid <= TRUE; + o_MEM_Address <= i_DMEM_Address; + o_MEM_Read_Write_n <= i_DMEM_Read_Write_n; + o_MEM_Data <= i_DMEM_Data; + o_DMEM_Valid <= i_MEM_Valid; + o_DMEM_Data_Read <= i_MEM_Data_Read; + o_DMEM_Last <= i_MEM_Last; + o_DMEM_Data <= i_MEM_Data; + end + end + + // State driver + always @(posedge i_Clk or negedge i_Reset_n) + begin + if( !i_Reset_n ) + // Defaults + State <= STATE_READY; + else + State <= NextState; + end + +endmodule \ No newline at end of file diff --git a/src/d_cache.v b/src/d_cache.v index 01ce658..43e0cdd 100644 --- a/src/d_cache.v +++ b/src/d_cache.v @@ -1,5 +1,5 @@ /* d_cache.v -* Sam Chan, Tony Medeiros, Dean Tullsen, Todor Mollov, and Pravin Prabhu +* Sam Chan, Tony Medeiros, Dean Tullsen, Todor Mollov, Pravin Prabhu, Zinsser Zhang * Abstract: * This is code for a direct-mapped cache, with 16-byte lines and 512 lines, for * an 8 KB DM cache. 16-byte cache lines are formed via four one-word (four byte) @@ -11,6 +11,7 @@ * changing the line size is very messy since it changes the number of banks. * If someone wants to clean this up (e.g., paramterize the number of banks), please * let me know. +* All addresses used in this scope are word addresses (32-bit/4-byte aligned). */ module d_cache #( @@ -37,7 +38,7 @@ module d_cache #( // Mem Transaction output reg o_MEM_Valid, output reg o_MEM_Read_Write_n, - output reg [(TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH):0] o_MEM_Address, // output 2-byte aligned addresses + output reg [(TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH)-1:0] o_MEM_Address, output reg [DATA_WIDTH-1:0] o_MEM_Data, input i_MEM_Valid, input i_MEM_Data_Read, @@ -240,14 +241,14 @@ always @(posedge i_Clk or negedge i_Reset_n) Gen_Count <= 0; State <= STATE_POPULATE; o_MEM_Read_Write_n <= READ; - o_MEM_Address <= {i_Tag,i_Index,{BLOCK_OFFSET_WIDTH+1{1'b0}}}; + o_MEM_Address <= {i_Tag,i_Index,{BLOCK_OFFSET_WIDTH{1'b0}}}; if(debug) $display("read miss on address %x", i_Address); end else if(Dirty_Array[i_Index]) begin //if its dirty write it to mem before populating! Gen_Count <= 0; State <= STATE_WRITEOUT; - o_MEM_Address <= {Tag_Array[i_Index],i_Index,{BLOCK_OFFSET_WIDTH+1{1'b0}}}; + o_MEM_Address <= {Tag_Array[i_Index],i_Index,{BLOCK_OFFSET_WIDTH{1'b0}}}; if(debug) $display("write miss %x to %x", i_Write_Data, i_Address); end @@ -270,7 +271,7 @@ always @(posedge i_Clk or negedge i_Reset_n) Gen_Count <= 0; State <= STATE_POPULATE; o_MEM_Valid <= TRUE; - o_MEM_Address <= {r_i_Tag,r_i_Index,{BLOCK_OFFSET_WIDTH+1{1'b0}}}; + o_MEM_Address <= {r_i_Tag,r_i_Index,{BLOCK_OFFSET_WIDTH{1'b0}}}; o_MEM_Read_Write_n <= READ; Dirty_Array[r_i_Index] <= FALSE; // Cache line was cleaned end else begin diff --git a/src/decoder.v b/src/decoder.v index ea94495..991baee 100644 --- a/src/decoder.v +++ b/src/decoder.v @@ -1,11 +1,12 @@ /* decoder.v -* Author: Pravin P. Prabhu -* Last Revision: 1/5/11 +* Author: Pravin P. Prabhu, and Zinsser Zhang +* Last Revision: 04/28/2017 * Abstract: * Provides decoding of instructions to control signals. +* All addresses used in this scope are word addresses (32-bit/4-byte aligned) */ module decoder #( - parameter ADDRESS_WIDTH = 32, + parameter ADDRESS_WIDTH = 21, parameter DATA_WIDTH = 32, parameter REG_ADDRESS_WIDTH = 5, parameter ALUCTL_WIDTH = 8, @@ -478,7 +479,7 @@ module decoder #( o_Uses_RT <= TRUE; o_RT_Addr <= i_Instruction[20:16]; o_ALUCTL <= ALUCTL_BEQ; - o_Branch_Target <= i_PC + 22'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; + o_Branch_Target <= i_PC + 21'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; if( !i_Stall && DEBUG ) $display("%x: %x (Branch on Equal)",i_PC,i_Instruction); end @@ -492,7 +493,7 @@ module decoder #( o_Uses_RT <= TRUE; o_RT_Addr <= i_Instruction[20:16]; o_ALUCTL <= ALUCTL_BNE; - o_Branch_Target <= i_PC + 22'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; + o_Branch_Target <= i_PC + 21'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; if( !i_Stall && DEBUG ) $display("%x: %x (Branch on Not Equal)",i_PC,i_Instruction); end @@ -506,7 +507,7 @@ module decoder #( o_Uses_RT <= TRUE; o_RT_Addr <= i_Instruction[20:16]; o_ALUCTL <= ALUCTL_BLEZ; - o_Branch_Target <= i_PC + 22'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; + o_Branch_Target <= i_PC + 21'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; if( !i_Stall && DEBUG ) $display("%x: %x (Branch on Less or Equal)",i_PC,i_Instruction); end @@ -532,7 +533,7 @@ module decoder #( $display("%x: %x (Branch on Less or Equal)",i_PC,i_Instruction); end //o_ALUCTL <= i_Instruction[16]? ALUCTL_BGEZ: ALUCTL_BLTZ; // 1 <=> bgez : 0 <=> bltz - o_Branch_Target <= i_PC + 22'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; + o_Branch_Target <= i_PC + 21'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; end 6'h07: //bgtz @@ -544,7 +545,7 @@ module decoder #( o_Uses_RT <= TRUE; o_RT_Addr <= i_Instruction[20:16]; o_ALUCTL <= ALUCTL_BGTZ; - o_Branch_Target <= i_PC + 22'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; + o_Branch_Target <= i_PC + 21'd1 + {{(ADDRESS_WIDTH-16){i_Instruction[15]}},i_Instruction[15:0]}; if( !i_Stall && DEBUG ) $display("%x: %x (Branch on Greater)",i_PC,i_Instruction); end @@ -555,7 +556,7 @@ module decoder #( o_Uses_ALU <= TRUE; o_ALUCTL <= ALUCTL_J; //o_Branch_Target <= {i_PC[31:26],i_Instruction[25:0]}; - o_Branch_Target <= i_Instruction[21:0]; + o_Branch_Target <= i_Instruction[20:0]; if( !i_Stall && DEBUG ) $display("%x: %x (Jump)",i_PC,i_Instruction); end @@ -566,7 +567,7 @@ module decoder #( o_Uses_ALU <= TRUE; o_ALUCTL <= ALUCTL_JAL; //o_Branch_Target <= {i_PC[31:26],i_Instruction[25:0]}; - o_Branch_Target <= i_Instruction[21:0]; + o_Branch_Target <= i_Instruction[20:0]; o_Uses_Immediate <= TRUE; o_Immediate <= (i_PC + 2); o_Writes_Back <= TRUE; diff --git a/src/hazard_detection_unit.v b/src/hazard_detection_unit.v index 3806638..c9b6de3 100644 --- a/src/hazard_detection_unit.v +++ b/src/hazard_detection_unit.v @@ -1,6 +1,6 @@ /* hazard_detection_unit.v -* Author: Pravin P. Prabhu -* Last Revision: 1/5/11 +* Author: Pravin P. Prabhu, and Zinsser Zhang +* Last Revision: 04/28/2017 * Abstract: * Contains all of the nightmarish logic for determining when the processor * should stall, and how it should stall. You are not expected to understand this. @@ -14,9 +14,8 @@ module hazard_detection_unit #( parameter DATA_WIDTH=32, input i_Reset_n, //============================================== - // Info about processor's overall state - input i_FlashLoader_Done, // Whether the flashloader has completed operation yet or not - input i_Done, // Whether we have observed the 'done' signal or not + // External stall issued by top level + input i_External_Stall, //============================================== // Hazard in DECODE? @@ -78,7 +77,7 @@ module hazard_detection_unit #( parameter DATA_WIDTH=32, localparam TRUE = 1'b1; // Internal wiring - wire Executing = i_FlashLoader_Done && !i_Done; // If 1, then we are currently executing code. + wire Executing = !i_External_Stall; // If 1, then we are currently executing code. // Registers for latching branches during stall periods reg r_Branch_IF_Hazard_Smash; // If 1, then we must smash the next inst coming out of IF -- there was a branch while it was busy. diff --git a/src/i_cache.v b/src/i_cache.v index 78b774e..ddcc87f 100644 --- a/src/i_cache.v +++ b/src/i_cache.v @@ -1,9 +1,10 @@ /* i_cache.v -* Author: Pravin P. Prabhu -* Last Revision: 1/5/11 +* Author: Pravin P. Prabhu, Zinsser Zhang +* Last Revision: 04/28/2017 * Abstract: * Provides caching of instructions from imem for quick access. Note that this * is a read only cache, and thus self-modifying code is not supported. +* All addresses used in this scope are word addresses (32-bit/4-byte aligned) */ module i_cache #( parameter DATA_WIDTH = 32, parameter TAG_WIDTH = 14, @@ -17,11 +18,11 @@ module i_cache #( parameter DATA_WIDTH = 32, // Requests input i_Valid, - input [TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH:0] i_Address, + input [TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH-1:0] i_Address, // DMEM Transaction - output reg o_MEM_Valid, // If request to DMEM is valid - output reg [TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH:0] o_MEM_Address, // Address request to DMEM + output reg o_MEM_Valid, // If request to MEM is valid + output reg [TAG_WIDTH+INDEX_WIDTH+BLOCK_OFFSET_WIDTH-1:0] o_MEM_Address, // Address request to MEM input i_MEM_Valid, // If data from main mem is valid input i_MEM_Last, // If main mem is sending the last piece of data input [DATA_WIDTH-1:0] i_MEM_Data, // Data from main mem @@ -121,7 +122,7 @@ module i_cache #( parameter DATA_WIDTH = 32, begin // Submit our request. o_MEM_Valid <= TRUE; - o_MEM_Address <= {r_i_Tag,r_i_Index,{BLOCK_OFFSET_WIDTH{1'b0}},1'b0}; + o_MEM_Address <= {r_i_Tag,r_i_Index,{BLOCK_OFFSET_WIDTH{1'b0}}}; // Mem is communicating? if( i_MEM_Valid ) diff --git a/src/memory_arbiter.v b/src/memory_arbiter.v index 2815c8f..adef51d 100644 --- a/src/memory_arbiter.v +++ b/src/memory_arbiter.v @@ -1,198 +1,136 @@ /* memory_arbiter.v -* Author: Pravin P. Prabhu -* Last Revision: 1/5/11 +* Author: Pravin P. Prabhu, Zinsser Zhang +* Last Revision: 04/29/2017 * Abstract: * Provides arbitration amongst sources that all wish to request from main * memory. Will service sources in order of priority, which is: * (high) * flashloader -* imem -* vga -- (to be included) -* dmem +* CORE * (low) */ module memory_arbiter #( parameter DATA_WIDTH=32, - parameter ADDRESS_WIDTH=22 + parameter ADDRESS_WIDTH=22, + parameter CORE_ADDRESS_WIDTH=21 ) ( // General input i_Clk, input i_Reset_n, - - // Requests to/from IMEM - Assume we always read - input i_IMEM_Valid, // If IMEM request is valid - input [ADDRESS_WIDTH-1:0] i_IMEM_Address, // IMEM request addr. - output reg o_IMEM_Valid, - output reg o_IMEM_Last, - output reg [DATA_WIDTH-1:0] o_IMEM_Data, - - // Requests to/from DMEM - input i_DMEM_Valid, - input i_DMEM_Read_Write_n, - input [ADDRESS_WIDTH-1:0] i_DMEM_Address, - input [DATA_WIDTH-1:0] i_DMEM_Data, - output reg o_DMEM_Valid, - output reg o_DMEM_Data_Read, - output reg o_DMEM_Last, - output reg [DATA_WIDTH-1:0] o_DMEM_Data, - + + // Requests to/from CORE + input i_CORE_Valid, + input i_CORE_Read_Write_n, + input [CORE_ADDRESS_WIDTH-1:0] i_CORE_Address, + input [DATA_WIDTH-1:0] i_CORE_Data, + output reg o_CORE_Valid, + output reg o_CORE_Data_Read, + output reg o_CORE_Last, + output reg [DATA_WIDTH-1:0] o_CORE_Data, + // Requests to/from FLASH - Assume we always write input i_Flash_Valid, input [DATA_WIDTH-1:0] i_Flash_Data, input [ADDRESS_WIDTH-1:0] i_Flash_Address, output reg o_Flash_Data_Read, output reg o_Flash_Last, - + // Interface with SDRAM Controller output reg o_MEM_Valid, output reg [ADDRESS_WIDTH-1:0] o_MEM_Address, output reg o_MEM_Read_Write_n, - + // Write data interface output reg [DATA_WIDTH-1:0] o_MEM_Data, input i_MEM_Data_Read, - + // Read data interface input [DATA_WIDTH-1:0] i_MEM_Data, input i_MEM_Data_Valid, - + input i_MEM_Last // If we're on the last piece of the transaction ); - + // Consts localparam TRUE = 1'b1; localparam FALSE = 1'b0; localparam READ = 1'b1; - localparam WRITE = 1'b0; - + localparam WRITE = 1'b0; + // State of the arbiter localparam STATE_READY = 4'd0; localparam STATE_SERVICING_FLASH = 4'd1; - localparam STATE_SERVICING_IMEM = 4'd2; - localparam STATE_SERVICING_DMEM = 4'd3; - localparam STATE_SERVICING_VGA = 4'd4; - + localparam STATE_SERVICING_CORE = 4'd2; + reg [3:0] State; + reg [3:0] NextState; always @(*) begin - o_IMEM_Valid <= FALSE; - o_IMEM_Last <= FALSE; - o_IMEM_Data <= {32{1'bx}}; - o_DMEM_Valid <= FALSE; - o_DMEM_Data_Read <= FALSE; - o_DMEM_Last <= FALSE; - o_DMEM_Data <= {32{1'bx}}; - o_Flash_Data_Read <= FALSE; - o_Flash_Last <= FALSE; - o_MEM_Valid <= FALSE; - o_MEM_Address <= {ADDRESS_WIDTH{1'bx}}; - o_MEM_Read_Write_n <= READ; - o_MEM_Data <= {32{1'bx}}; - + NextState <= State; case(State) - //======================= - // Accept State STATE_READY: begin + if (i_Flash_Valid) + NextState <= STATE_SERVICING_FLASH; + else if (i_CORE_Valid) + NextState <= STATE_SERVICING_CORE; end - - //======================= - // Services States + STATE_SERVICING_FLASH: begin - // Servicing flash: Bridge flash I/O - o_MEM_Valid <= TRUE; - o_MEM_Address <= i_Flash_Address; - o_MEM_Read_Write_n <= WRITE; - o_MEM_Data <= i_Flash_Data; - o_Flash_Data_Read <= i_MEM_Data_Read; - o_Flash_Last <= i_MEM_Last; - end - - STATE_SERVICING_IMEM: - begin - o_MEM_Valid <= TRUE; - o_MEM_Address <= i_IMEM_Address; - o_MEM_Read_Write_n <= READ; - o_IMEM_Valid <= i_MEM_Data_Valid; - o_IMEM_Last <= i_MEM_Last; - o_IMEM_Data <= i_MEM_Data; + if (i_MEM_Last) + NextState <= STATE_READY; end - - STATE_SERVICING_DMEM: + + STATE_SERVICING_CORE: begin - o_MEM_Valid <= TRUE; - o_MEM_Address <= i_DMEM_Address; - o_MEM_Read_Write_n <= i_DMEM_Read_Write_n; - o_MEM_Data <= i_DMEM_Data; - o_DMEM_Valid <= i_MEM_Data_Valid; - o_DMEM_Data_Read <= i_MEM_Data_Read; - o_DMEM_Last <= i_MEM_Last; - o_DMEM_Data <= i_MEM_Data; + if (i_MEM_Last) + NextState <= STATE_READY; end endcase + + o_CORE_Valid <= FALSE; + o_CORE_Data_Read <= FALSE; + o_CORE_Last <= FALSE; + o_CORE_Data <= {32{1'bx}}; + o_Flash_Data_Read <= FALSE; + o_Flash_Last <= FALSE; + o_MEM_Valid <= FALSE; + o_MEM_Address <= {ADDRESS_WIDTH{1'bx}}; + o_MEM_Read_Write_n <= READ; + o_MEM_Data <= {32{1'bx}}; + + if (State == STATE_SERVICING_FLASH || NextState == STATE_SERVICING_FLASH) + begin + // Servicing flash: Bridge flash I/O + o_MEM_Valid <= TRUE; + o_MEM_Address <= i_Flash_Address; + o_MEM_Read_Write_n <= WRITE; + o_MEM_Data <= i_Flash_Data; + o_Flash_Data_Read <= i_MEM_Data_Read; + o_Flash_Last <= i_MEM_Last; + end + else if (State == STATE_SERVICING_CORE || NextState == STATE_SERVICING_CORE) + begin + o_MEM_Valid <= TRUE; + o_MEM_Address <= {i_CORE_Address, 1'b0}; + o_MEM_Read_Write_n <= i_CORE_Read_Write_n; + o_MEM_Data <= i_CORE_Data; + o_CORE_Valid <= i_MEM_Data_Valid; + o_CORE_Data_Read <= i_MEM_Data_Read; + o_CORE_Last <= i_MEM_Last; + o_CORE_Data <= i_MEM_Data; + end end - + // State driver always @(posedge i_Clk or negedge i_Reset_n) begin if( !i_Reset_n ) - begin - // Defaults - State <= STATE_READY; - end + // Defaults + State <= STATE_READY; else - begin - case(State) - //======================= - // Accept State - STATE_READY: - begin - if( i_Flash_Valid ) - begin - State <= STATE_SERVICING_FLASH; - end - else if( i_IMEM_Valid ) - begin - State <= STATE_SERVICING_IMEM; - end - else if( i_DMEM_Valid ) - begin - State <= STATE_SERVICING_DMEM; - end - end - - //======================= - // Services States - STATE_SERVICING_FLASH: - begin - // See if we're done transacting - if( i_MEM_Last ) - State <= STATE_READY; - end - - STATE_SERVICING_IMEM: - begin - // See if we're done transacting - if( i_MEM_Last ) - State <= STATE_READY; - end - - STATE_SERVICING_DMEM: - begin - // See if we're done transacting - if( i_MEM_Last ) - State <= STATE_READY; - end - - // Remain in current state by default - default: - begin - end - endcase - end + State <= NextState; end - endmodule - \ No newline at end of file diff --git a/src/mips_core.v b/src/mips_core.v new file mode 100644 index 0000000..a59fef2 --- /dev/null +++ b/src/mips_core.v @@ -0,0 +1,654 @@ +/* mips_core.v +* Author: Pravin P. Prabhu, Dean Tullsen, and Zinsser Zhang +* Last Revision: 04/28/2017 +* Abstract: +* The core module for the MIPS32 processor. This is a classic 5-stage +* MIPS pipeline architecture which is intended to follow heavily from the model +* presented in Hennessy and Patterson's Computer Organization and Design. +* All addresses used in this scope are word addresses (32-bit/4-byte aligned) +*/ +module mips_core #( + parameter DATA_WIDTH = 32, + parameter WORD_ADDRESS_WIDTH = 21 + ) + ( // General + input i_Clk, + input i_Reset_n, + input i_External_Stall, // Global Stall issued by top level + + // Memory bus interface + output o_MEM_Valid, + output o_MEM_Read_Write_n, + output [WORD_ADDRESS_WIDTH-1:0] o_MEM_Address, + output [DATA_WIDTH-1:0] o_MEM_Data, + input i_MEM_Valid, + input i_MEM_Data_Read, + input i_MEM_Last, + input [DATA_WIDTH-1:0] i_MEM_Data, + + // Outputs for Done flag + output [15:0] o_Pass_Done_Value, // reports the value of a PASS/FAIL/DONE instruction + output [1:0] o_Pass_Done_Change, // indicates the above signal is meaningful + // 1 = pass, 2 = fail, 3 = done + + // Outputs for performance display + output [7:0] o_Num_Inst_Executed, + output [20:0] o_IMEM_i_Address + ); + +//=================================================================== +// Internal Wiring +//=================================================================== + +//=================================================================== +// General Signals +localparam FALSE = 1'b0; +localparam TRUE = 1'b1; +localparam BYTE_ADDRESS_WIDTH = WORD_ADDRESS_WIDTH + 2; + +//=================================================================== +// IFetch Signals + +wire IFetch_i_Flush; // Flush for IFetch +wire Hazard_Stall_IF; // Stall for IFetch +wire IFetch_i_Load; // Load signal - if high, load pc with vector +wire [WORD_ADDRESS_WIDTH-1:0] IFetch_i_PCSrc; // Vector to branch to + +wire [WORD_ADDRESS_WIDTH-1:0] IMEM_i_Address; // Current PC + + +wire IMEM_o_Ready; +wire IMEM_o_Valid; +wire [DATA_WIDTH-1:0] IMEM_o_Instruction; + + //============== + // Pipe signals: IF->ID +wire Hazard_Flush_IF; // 1st pipe flush +wire Hazard_Stall_DEC; // 1st pipe stall +wire imembubble_DEC; // set if instruction coming out of icache + // was not real instruction +//=================================================================== +// Decoder Signals +localparam ALU_CTLCODE_WIDTH = 8; +localparam REG_ADDR_WIDTH = 5; +localparam MEM_MASK_WIDTH = 3; +wire [WORD_ADDRESS_WIDTH-1:0] DEC_i_PC; // PC of inst +wire [DATA_WIDTH-1:0] DEC_i_Instruction; // Inst into decode +wire DEC_Noop = (DEC_i_Instruction == 32'd0); + +wire DEC_o_Uses_ALU; +wire [ALU_CTLCODE_WIDTH-1:0] DEC_o_ALUCTL; // ALU control code +wire DEC_o_Is_Branch; // If it's a branch +wire [WORD_ADDRESS_WIDTH-1:0] DEC_o_Branch_Target; // Where we will branch to +wire DEC_o_Jump_Reg; // If this is a special case where we jump TO a register value + +wire DEC_o_Mem_Valid; +wire DEC_o_Mem_Read_Write_n; +wire [MEM_MASK_WIDTH-1:0] DEC_o_Mem_Mask; // Used for masking individual memory ops - such as byte and halfword transactions + +wire DEC_o_Writes_Back; +wire [REG_ADDR_WIDTH-1:0] DEC_o_Write_Addr; +wire DEC_o_Uses_RS; +wire [REG_ADDR_WIDTH-1:0] DEC_o_Read_Register_1; +wire DEC_o_Uses_RT; +wire [REG_ADDR_WIDTH-1:0] DEC_o_Read_Register_2; + +wire [DATA_WIDTH-1:0] DEC_o_Read_Data_1; +wire [DATA_WIDTH-1:0] DEC_o_Read_Data_2; + +wire DEC_o_Uses_Immediate; +wire [DATA_WIDTH-1:0] DEC_o_Immediate; + +wire [DATA_WIDTH-1:0] FORWARD_o_Forwarded_Data_1,FORWARD_o_Forwarded_Data_2; // Looked up regs + + //============== + // Pipe signals: ID->EX +wire Hazard_Flush_DEC; // 2nd pipe flush +wire Hazard_Stall_EX; // 2nd pipe stall + +wire [WORD_ADDRESS_WIDTH-1:0] DEC_o_PC; +assign DEC_o_PC = DEC_i_PC; + +//=================================================================== +// Execute Signals + +wire [WORD_ADDRESS_WIDTH-1:0] ALU_i_PC; + +wire EX_i_Is_Branch; +wire EX_i_Mem_Valid; +wire [MEM_MASK_WIDTH-1:0] EX_i_Mem_Mask; +wire EX_i_Mem_Read_Write_n; +wire [DATA_WIDTH-1:0] EX_i_Mem_Write_Data; +wire EX_i_Writes_Back; +wire [REG_ADDR_WIDTH-1:0] EX_i_Write_Addr; + +wire ALU_i_Valid; // Whether input to ALU is valid or not +wire ALU_o_Valid; +wire [ALU_CTLCODE_WIDTH-1:0] ALU_i_ALUOp; // Control bus to ALU +wire [DATA_WIDTH-1:0] ALU_i_Operand1,ALU_i_Operand2; // Ops for ALU +wire [WORD_ADDRESS_WIDTH-1:0] EX_i_Branch_Target; +wire [DATA_WIDTH-1:0] ALU_o_Result; // Computation of ALU +wire ALU_o_Branch_Valid; // Whether branch is valid or not +wire ALU_o_Branch_Outcome; // Whether branch is taken or not +wire [15:0] ALU_o_Pass_Done_Value; // reports the value of a PASS/FAIL/DONE instruction +wire [1:0] ALU_o_Pass_Done_Change; // indicates the above signal is meaningful + // 1 = pass, 2 = fail, 3 = done + + // Cumulative signals +wire EX_Take_Branch = ALU_o_Valid && ALU_o_Branch_Valid && ALU_o_Branch_Outcome; // Whether we should branch or not. + + //============== + // Pipe signals: EX->MEM +wire Hazard_Flush_EX; // 3rd pipe flush +wire Hazard_Stall_MEM; // 3rd pipe stall + + +//=================================================================== +// Memory Signals +wire [DATA_WIDTH-1:0] DMEM_i_Result; // Result from the ALU +wire [DATA_WIDTH-1:0] DMEM_i_Mem_Write_Data; // What we will write back to mem (if applicable) +wire DMEM_i_Mem_Valid; // If the memory operation is valid +wire [MEM_MASK_WIDTH-1:0] DMEM_i_Mem_Mask; // Mem mask for sub-word operations +wire DMEM_i_Mem_Read_Write_n; // Type of memop +wire DMEM_i_Writes_Back; // If the result should be written back to regfile +wire [REG_ADDR_WIDTH-1:0] DMEM_i_Write_Addr; // Which reg in the regfile to write to +wire [DATA_WIDTH-1:0] DMEM_o_Read_Data; // The data READ from DMEM +wire DMEM_o_Mem_Ready; // If the DMEM is ready to service another request +wire DMEM_o_Mem_Valid; // If the value read from DMEM is valid +reg DMEM_o_Done; // If MEM's work is finalized +reg [DATA_WIDTH-1:0] DMEM_o_Write_Data; // Data we should write back to regfile + +wire MemToReg = DMEM_i_Mem_Valid; // Selects what we will write back -- mem or ALU result + + //============== + // Pipe signals: MEM->WB +wire Hazard_Flush_MEM; // 4th pipe flush +wire Hazard_Stall_WB; // 4th pipe stall + + +//=================================================================== +// Write-Back Signals +wire WB_i_Writes_Back; // If we will write back +wire [REG_ADDR_WIDTH-1:0] DEC_i_Write_Register; // Where we will write back to +wire [DATA_WIDTH-1:0] WB_i_Write_Data; // What we will write back +wire Hazard_Flush_WB; // Request to squash WB contents + +wire DEC_i_RegWrite = WB_i_Writes_Back && !Hazard_Flush_WB; + +//=================================================================== +// Core memory bus arbiter Signals +wire Arbiter_i_IMEM_Valid; +wire [WORD_ADDRESS_WIDTH-1:0] Arbiter_i_IMEM_Address; +wire Arbiter_o_IMEM_Valid; +wire Arbiter_o_IMEM_Last; +wire [DATA_WIDTH-1:0] Arbiter_o_IMEM_Data; + +wire Arbiter_i_DMEM_Valid; +wire Arbiter_i_DMEM_Read_Write_n; +wire [WORD_ADDRESS_WIDTH-1:0] Arbiter_i_DMEM_Address; +wire [DATA_WIDTH-1:0] Arbiter_i_DMEM_Data; +wire [DATA_WIDTH-1:0] Arbiter_o_DMEM_Data; +wire Arbiter_o_DMEM_Data_Read; +wire Arbiter_o_DMEM_Valid; +wire Arbiter_o_DMEM_Last; + +//=================================================================== +// Top-level Connections + + // Report number of instructions that is finishing up execution in Decode + // For this baseline this number can not exceed 1. + assign o_Num_Inst_Executed = !Hazard_Stall_DEC && !Hazard_Flush_DEC && !DEC_Noop; + + // Report current request address to i_cache + assign o_IMEM_i_Address = IMEM_i_Address; + + // Report Done flag/value + assign o_Pass_Done_Value = ALU_o_Pass_Done_Value; + assign o_Pass_Done_Change = ALU_o_Pass_Done_Change; + +//=================================================================== +// Structural Description - Pipeline stages +//=================================================================== + +//=================================================================== +// Instruction Fetch +fetch_unit #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH) + ) + IFETCH + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Stall(Hazard_Stall_IF), + + .i_Load(IFetch_i_Load), + .i_Load_Address(IFetch_i_PCSrc), + + // Outputs + .o_PC(IMEM_i_Address) + ); + +i_cache #( .DATA_WIDTH(DATA_WIDTH) + ) + I_CACHE + ( + // General + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + + // Requests + .i_Valid(!i_External_Stall), + .i_Address(IMEM_i_Address), + + // Mem Transaction + .o_MEM_Valid(Arbiter_i_IMEM_Valid), + .o_MEM_Address(Arbiter_i_IMEM_Address), + .i_MEM_Valid(Arbiter_o_IMEM_Valid), // If data from main mem is valid + .i_MEM_Last(Arbiter_o_IMEM_Last), // If main mem is sending the last piece of data + .i_MEM_Data(Arbiter_o_IMEM_Data), // Data from main mem + + // Outputs + .o_Ready(IMEM_o_Ready), + .o_Valid(IMEM_o_Valid), // If the output is correct. + .o_Data(IMEM_o_Instruction) // The data requested. + ); + +//=================================================================== +// Decode +pipe_if_dec #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH) + ) + PIPE_IF_DEC + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Flush(Hazard_Flush_IF), + .i_Stall(Hazard_Stall_DEC), + .i_imembubble(IMEM_o_Valid), + + // Pipe signals + .i_PC(IMEM_i_Address), + .o_PC(DEC_i_PC), + .i_Instruction(IMEM_o_Instruction), + .o_Instruction(DEC_i_Instruction), + .o_imembubble(imembubble_DEC) + ); + +decoder #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .REG_ADDRESS_WIDTH(REG_ADDR_WIDTH), + .ALUCTL_WIDTH(ALU_CTLCODE_WIDTH), + .MEM_MASK_WIDTH(MEM_MASK_WIDTH) + ) + DECODE + ( // Inputs + .i_PC(DEC_i_PC), + .i_Instruction(DEC_i_Instruction), + .i_Stall(Hazard_Stall_DEC), + + // Outputs + .o_Uses_ALU(DEC_o_Uses_ALU), + .o_ALUCTL(DEC_o_ALUCTL), + .o_Is_Branch(DEC_o_Is_Branch), + .o_Jump_Reg(DEC_o_Jump_Reg), + + .o_Mem_Valid(DEC_o_Mem_Valid), + .o_Mem_Read_Write_n(DEC_o_Mem_Read_Write_n), + .o_Mem_Mask(DEC_o_Mem_Mask), + + .o_Writes_Back(DEC_o_Writes_Back), + .o_Write_Addr(DEC_o_Write_Addr), + + .o_Uses_RS(DEC_o_Uses_RS), + .o_RS_Addr(DEC_o_Read_Register_1), + .o_Uses_RT(DEC_o_Uses_RT), + .o_RT_Addr(DEC_o_Read_Register_2), + .o_Uses_Immediate(DEC_o_Uses_Immediate), + .o_Immediate(DEC_o_Immediate), + .o_Branch_Target(DEC_o_Branch_Target) + ); + + +regfile #( .DATA_WIDTH(DATA_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH) + ) + REGFILE + ( // Inputs + .i_Clk(i_Clk), + + .i_RS_Addr(DEC_o_Read_Register_1), + .i_RT_Addr(DEC_o_Read_Register_2), + + .i_Write_Enable(DEC_i_RegWrite), // Account for squashing WB stage + .i_Write_Data(WB_i_Write_Data), + .i_Write_Addr(DEC_i_Write_Register), + + // Outputs + .o_RS_Data(DEC_o_Read_Data_1), + .o_RT_Data(DEC_o_Read_Data_2) + ); + +//=================================================================== +// Execute +pipe_dec_ex #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH), + .ALU_CTLCODE_WIDTH(ALU_CTLCODE_WIDTH), + .MEM_MASK_WIDTH(MEM_MASK_WIDTH) + ) + PIPE_DEC_EX + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Flush(Hazard_Flush_DEC), + .i_Stall(Hazard_Stall_EX), + + // Pipeline + .i_PC(DEC_o_PC), + .o_PC(ALU_i_PC), + .i_Uses_ALU(DEC_o_Uses_ALU), + .o_Uses_ALU(ALU_i_Valid), + .i_ALUCTL(DEC_o_ALUCTL), + .o_ALUCTL(ALU_i_ALUOp), + .i_Is_Branch(DEC_o_Is_Branch), + .o_Is_Branch(EX_i_Is_Branch), + .i_Mem_Valid(DEC_o_Mem_Valid), + .o_Mem_Valid(EX_i_Mem_Valid), + .i_Mem_Mask(DEC_o_Mem_Mask), + .o_Mem_Mask(EX_i_Mem_Mask), + .i_Mem_Read_Write_n(DEC_o_Mem_Read_Write_n), + .o_Mem_Read_Write_n(EX_i_Mem_Read_Write_n), + .i_Mem_Write_Data(FORWARD_o_Forwarded_Data_2), + .o_Mem_Write_Data(EX_i_Mem_Write_Data), + .i_Writes_Back(DEC_o_Writes_Back), + .o_Writes_Back(EX_i_Writes_Back), + .i_Write_Addr(DEC_o_Write_Addr), + .o_Write_Addr(EX_i_Write_Addr), + .i_Operand1(FORWARD_o_Forwarded_Data_1), + .o_Operand1(ALU_i_Operand1), + .i_Operand2(DEC_o_Uses_Immediate?DEC_o_Immediate:FORWARD_o_Forwarded_Data_2), // Convention - Operand2 mapped to immediates + .o_Operand2(ALU_i_Operand2), + .i_Branch_Target(DEC_o_Jump_Reg?FORWARD_o_Forwarded_Data_1[WORD_ADDRESS_WIDTH-1:0]:DEC_o_Branch_Target), + .o_Branch_Target(EX_i_Branch_Target) + ); + +alu #( .DATA_WIDTH(DATA_WIDTH), + .CTLCODE_WIDTH(ALU_CTLCODE_WIDTH) + ) + ALU + ( // Inputs + .i_Valid(ALU_i_Valid), + .i_ALUCTL(ALU_i_ALUOp), + .i_Operand1(ALU_i_Operand1), + .i_Operand2(ALU_i_Operand2), + + // Outputs + .o_Valid(ALU_o_Valid), + .o_Result(ALU_o_Result), + .o_Branch_Valid(ALU_o_Branch_Valid), + .o_Branch_Outcome(ALU_o_Branch_Outcome), + .o_Pass_Done_Value(ALU_o_Pass_Done_Value), + .o_Pass_Done_Change(ALU_o_Pass_Done_Change) + ); + +//=================================================================== +// Mem +pipe_ex_mem #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH), + .ALU_CTLCODE_WIDTH(ALU_CTLCODE_WIDTH) + ) + PIPE_EX_MEM + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Flush(Hazard_Flush_EX), + .i_Stall(Hazard_Stall_MEM), + + // Pipe in/out + .i_ALU_Result(ALU_o_Result), + .o_ALU_Result(DMEM_i_Result), + .i_Mem_Valid(EX_i_Mem_Valid), + .o_Mem_Valid(DMEM_i_Mem_Valid), + .i_Mem_Mask(EX_i_Mem_Mask), + .o_Mem_Mask(DMEM_i_Mem_Mask), + .i_Mem_Read_Write_n(EX_i_Mem_Read_Write_n), + .o_Mem_Read_Write_n(DMEM_i_Mem_Read_Write_n), + .i_Mem_Write_Data(EX_i_Mem_Write_Data), + .o_Mem_Write_Data(DMEM_i_Mem_Write_Data), + .i_Writes_Back(EX_i_Writes_Back), + .o_Writes_Back(DMEM_i_Writes_Back), + .i_Write_Addr(EX_i_Write_Addr), + .o_Write_Addr(DMEM_i_Write_Addr) + ); + +d_cache #( + .DATA_WIDTH(32), + .MEM_MASK_WIDTH(3) + ) + D_CACHE + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Valid(DMEM_i_Mem_Valid), + .i_Mem_Mask(DMEM_i_Mem_Mask), + .i_Address(DMEM_i_Result[BYTE_ADDRESS_WIDTH-1:2]), + .i_Read_Write_n(DMEM_i_Mem_Read_Write_n), //1=MemRead, 0=MemWrite + .i_Write_Data(DMEM_i_Mem_Write_Data), + + // Outputs + .o_Ready(DMEM_o_Mem_Ready), + .o_Valid(DMEM_o_Mem_Valid), + .o_Data(DMEM_o_Read_Data), + + // Mem Transaction + .o_MEM_Valid(Arbiter_i_DMEM_Valid), + .o_MEM_Read_Write_n(Arbiter_i_DMEM_Read_Write_n), + .o_MEM_Address(Arbiter_i_DMEM_Address), + .o_MEM_Data(Arbiter_i_DMEM_Data), + .i_MEM_Valid(Arbiter_o_DMEM_Valid), + .i_MEM_Data_Read(Arbiter_o_DMEM_Data_Read), + .i_MEM_Last(Arbiter_o_DMEM_Last), + .i_MEM_Data(Arbiter_o_DMEM_Data) + ); + + // Multiplexor - Select what we will write back +always @(*) +begin + if( MemToReg ) // If it was a memory operation + begin + DMEM_o_Write_Data <= DMEM_o_Read_Data; // We will write back value from memory + DMEM_o_Done <= DMEM_o_Mem_Valid; // Write back only if value is valid + end + else + begin + DMEM_o_Write_Data <= DMEM_i_Result; // Else we will write back value from ALU + DMEM_o_Done <= TRUE; + end +end + +//=================================================================== +// Write-Back +pipe_mem_wb #( .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH) + ) + PIPE_MEM_WB + ( // Inputs + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + .i_Flush(Hazard_Flush_MEM), + .i_Stall(Hazard_Stall_WB), + + // Pipe in/out + .i_WriteBack_Data(DMEM_o_Write_Data), + .o_WriteBack_Data(WB_i_Write_Data), + .i_Writes_Back(DMEM_i_Writes_Back), + .o_Writes_Back(WB_i_Writes_Back), + .i_Write_Addr(DMEM_i_Write_Addr), + .o_Write_Addr(DEC_i_Write_Register) + ); + + + // Write-Back is simply wires feeding back into regfile to perform writes + // (SEE REGFILE) + + + +//=================================================================== +// Arbitration Logic + +// Memory arbiter +core_memory_arbiter #( .DATA_WIDTH(DATA_WIDTH), + .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH) + ) + ARBITER + ( + // General + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + + // Requests to/from IMEM - Assume we always read + .i_IMEM_Valid(Arbiter_i_IMEM_Valid), // If IMEM request is valid + .i_IMEM_Address(Arbiter_i_IMEM_Address), // IMEM request addr. + .o_IMEM_Valid(Arbiter_o_IMEM_Valid), + .o_IMEM_Last(Arbiter_o_IMEM_Last), + .o_IMEM_Data(Arbiter_o_IMEM_Data), + + // Requests to/from DMEM + .i_DMEM_Valid(Arbiter_i_DMEM_Valid), + .i_DMEM_Read_Write_n(Arbiter_i_DMEM_Read_Write_n), + .i_DMEM_Address(Arbiter_i_DMEM_Address), + .i_DMEM_Data(Arbiter_i_DMEM_Data), + .o_DMEM_Valid(Arbiter_o_DMEM_Valid), + .o_DMEM_Data_Read(Arbiter_o_DMEM_Data_Read), + .o_DMEM_Last(Arbiter_o_DMEM_Last), + .o_DMEM_Data(Arbiter_o_DMEM_Data), + + + // Interface to outside of the core + .o_MEM_Valid(o_MEM_Valid), + .o_MEM_Address(o_MEM_Address), + .o_MEM_Read_Write_n(o_MEM_Read_Write_n), + + // Write data interface + .o_MEM_Data(o_MEM_Data), + .i_MEM_Data_Read(i_MEM_Data_Read), + + // Read data interface + .i_MEM_Data(i_MEM_Data), + .i_MEM_Valid(i_MEM_Valid), + + .i_MEM_Last(i_MEM_Last) + ); + +// Forwarding logic +forwarding_unit #( .DATA_WIDTH(DATA_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH) + ) + FORWARDING_UNIT + ( + // Feedback from DEC + .i_DEC_Uses_RS(DEC_o_Uses_RS), + .i_DEC_RS_Addr(DEC_o_Read_Register_1), + .i_DEC_Uses_RT(DEC_o_Uses_RT), // DEC wants to use RT + .i_DEC_RT_Addr(DEC_o_Read_Register_2), // RT request addr. + .i_DEC_RS_Data(DEC_o_Read_Data_1), + .i_DEC_RT_Data(DEC_o_Read_Data_2), + + // Feedback from EX + .i_EX_Writes_Back(EX_i_Writes_Back), // EX is valid for analysis + .i_EX_Valid(ALU_i_Valid), // If it's a valid ALU op or not + .i_EX_Write_Addr(EX_i_Write_Addr), // What EX will write to + .i_EX_Write_Data(ALU_o_Result), + + // Feedback from MEM + .i_MEM_Writes_Back(DMEM_i_Writes_Back), // MEM is valid for analysis + .i_MEM_Write_Addr(DMEM_i_Write_Addr), // What MEM will write to + .i_MEM_Write_Data(DMEM_o_Write_Data), + + // Feedback from WB + .i_WB_Writes_Back(WB_i_Writes_Back), // WB is valid for analysis + .i_WB_Write_Addr(DEC_i_Write_Register), // What WB will write to + .i_WB_Write_Data(WB_i_Write_Data), + + //=============================================== + // IFetch forwarding + + // None + + // DEC forwarding + .o_DEC_RS_Override_Data(FORWARD_o_Forwarded_Data_1), + .o_DEC_RT_Override_Data(FORWARD_o_Forwarded_Data_2) + ); + +// Hazard detection unit / Stall logic +hazard_detection_unit #( .DATA_WIDTH(DATA_WIDTH), + .ADDRESS_WIDTH(WORD_ADDRESS_WIDTH), + .REG_ADDR_WIDTH(REG_ADDR_WIDTH) + ) + HAZARD_DETECTION_UNIT + ( + .i_Clk(i_Clk), + .i_Reset_n(i_Reset_n), + + //============================================== + // Overall state + .i_External_Stall(i_External_Stall), + + //============================================== + // Hazard in DECODE? + .i_DEC_Uses_RS(DEC_o_Uses_RS), // DEC wants to use RS + .i_DEC_RS_Addr(DEC_o_Read_Register_1), // RS request addr. + .i_DEC_Uses_RT(DEC_o_Uses_RT), // DEC wants to use RT + .i_DEC_RT_Addr(DEC_o_Read_Register_2), // RT request addr. + .i_DEC_Branch_Instruction(DEC_o_Is_Branch), + + //=============================================== + // Feedback from IF + .i_IF_Done(IMEM_o_Valid), // If IF's value has reached steady state + + // Feedback from EX + .i_EX_Writes_Back(EX_i_Writes_Back), // EX is valid for data dependency analysis + .i_EX_Uses_Mem(EX_i_Mem_Valid), + .i_EX_Write_Addr(EX_i_Write_Addr), // What EX will write to + .i_EX_Branch(EX_Take_Branch), // If EX says we are branching + .i_EX_Branch_Target(EX_i_Branch_Target), + + // Feedback from MEM + .i_MEM_Uses_Mem(DMEM_i_Mem_Valid), // If it's a memop + .i_MEM_Writes_Back(DMEM_i_Writes_Back), // MEM is valid for analysis + .i_MEM_Write_Addr(DMEM_i_Write_Addr), // What MEM will write to + .i_MEM_Done(DMEM_o_Done), // If MEM's value has reached steady state + + // Feedback from WB + .i_WB_Writes_Back(WB_i_Writes_Back), + .i_WB_Write_Addr(DEC_i_Write_Register), + + //=============================================== + // Branch hazard handling + .o_IF_Branch(IFetch_i_Load), + .o_IF_Branch_Target(IFetch_i_PCSrc), + + //=============================================== + // IFetch validation + .o_IF_Stall(Hazard_Stall_IF), + .o_IF_Smash(Hazard_Flush_IF), + + // DECODE validation + .o_DEC_Stall(Hazard_Stall_DEC), + .o_DEC_Smash(Hazard_Flush_DEC), + + // EX validation + .o_EX_Stall(Hazard_Stall_EX), + .o_EX_Smash(Hazard_Flush_EX), + + // MEM validation + .o_MEM_Stall(Hazard_Stall_MEM), + .o_MEM_Smash(Hazard_Flush_MEM), + + .o_WB_Stall(Hazard_Stall_WB), + .o_WB_Smash(Hazard_Flush_WB) + ); + +endmodule diff --git a/src/mips_cpu.v b/src/mips_cpu.v index 44e576c..2165db8 100644 --- a/src/mips_cpu.v +++ b/src/mips_cpu.v @@ -1,10 +1,10 @@ /* mips_cpu.v -* Author: Pravin P. Prabhu and Dean Tullsen -* Last Revision: 1/5/11 +* Author: Pravin P. Prabhu, Dean Tullsen, and Zinsser Zhang +* Last Revision: 04/28/2017 * Abstract: -* The top level module for the MIPS32 processor. This is a classic 5-stage -* MIPS pipeline architecture which is intended to follow heavily from the model -* presented in Hennessy and Patterson's Computer Organization and Design. +* The top level module for the MIPS32 processor. This top level module +* handles loading data from flash to SDRAM and keep track of core's performance +* The main classic 5-stage MIPS pipeline is defined in mips_core module. */ module mips_cpu(// General input CLOCK_50, //These inputs are all pre-defined input/output pin names @@ -56,6 +56,7 @@ module mips_cpu(// General localparam FALSE = 1'b0; localparam TRUE = 1'b1; localparam ADDRESS_WIDTH = 22; +localparam CORE_ADDRESS_WIDTH = 21; localparam DATA_WIDTH = 32; //wire Global_Reset_n; // Global reset wire Global_Reset_n = KEY[0]; @@ -77,133 +78,25 @@ assign SRAM_OE_N = 0; assign SRAM_CE_N = 0; //=================================================================== -// IFetch Signals - -wire IFetch_i_Flush; // Flush for IFetch -wire Hazard_Stall_IF; // Stall for IFetch -wire IFetch_i_Load; // Load signal - if high, load pc with vector -wire [ADDRESS_WIDTH-1:0] IFetch_i_PCSrc; // Vector to branch to - -wire [ADDRESS_WIDTH-1:0] IMEM_i_Address; // Current PC - - -wire IMEM_o_Ready; -wire IMEM_o_Valid; -wire [DATA_WIDTH-1:0] IMEM_o_Instruction; - - //============== - // Pipe signals: IF->ID -wire Hazard_Flush_IF; // 1st pipe flush -wire Hazard_Stall_DEC; // 1st pipe stall -wire imembubble_DEC; // set if instruction coming out of icache - // was not real instruction -//=================================================================== -// Decoder Signals -localparam ALU_CTLCODE_WIDTH = 8; -localparam REG_ADDR_WIDTH = 5; -localparam MEM_MASK_WIDTH = 3; -wire [ADDRESS_WIDTH-1:0] DEC_i_PC; // PC of inst -wire [DATA_WIDTH-1:0] DEC_i_Instruction; // Inst into decode -wire DEC_Noop = (DEC_i_Instruction == 32'd0); - -wire DEC_o_Uses_ALU; -wire [ALU_CTLCODE_WIDTH-1:0] DEC_o_ALUCTL; // ALU control code -wire DEC_o_Is_Branch; // If it's a branch -wire [ADDRESS_WIDTH-1:0] DEC_o_Branch_Target; // Where we will branch to -wire DEC_o_Jump_Reg; // If this is a special case where we jump TO a register value - -wire DEC_o_Mem_Valid; -wire DEC_o_Mem_Read_Write_n; -wire [MEM_MASK_WIDTH-1:0] DEC_o_Mem_Mask; // Used for masking individual memory ops - such as byte and halfword transactions - -wire DEC_o_Writes_Back; -wire [REG_ADDR_WIDTH-1:0] DEC_o_Write_Addr; -wire DEC_o_Uses_RS; -wire [REG_ADDR_WIDTH-1:0] DEC_o_Read_Register_1; -wire DEC_o_Uses_RT; -wire [REG_ADDR_WIDTH-1:0] DEC_o_Read_Register_2; - -wire [DATA_WIDTH-1:0] DEC_o_Read_Data_1; -wire [DATA_WIDTH-1:0] DEC_o_Read_Data_2; - -wire DEC_o_Uses_Immediate; -wire [DATA_WIDTH-1:0] DEC_o_Immediate; - -wire [DATA_WIDTH-1:0] FORWARD_o_Forwarded_Data_1,FORWARD_o_Forwarded_Data_2; // Looked up regs - - //============== - // Pipe signals: ID->EX -wire Hazard_Flush_DEC; // 2nd pipe flush -wire Hazard_Stall_EX; // 2nd pipe stall - -wire [ADDRESS_WIDTH-1:0] DEC_o_PC; -assign DEC_o_PC = DEC_i_PC; - -//=================================================================== -// Execute Signals - -wire [ADDRESS_WIDTH-1:0] ALU_i_PC; - -wire EX_i_Is_Branch; -wire EX_i_Mem_Valid; -wire [MEM_MASK_WIDTH-1:0] EX_i_Mem_Mask; -wire EX_i_Mem_Read_Write_n; -wire [DATA_WIDTH-1:0] EX_i_Mem_Write_Data; -wire EX_i_Writes_Back; -wire [REG_ADDR_WIDTH-1:0] EX_i_Write_Addr; - -wire ALU_i_Valid; // Whether input to ALU is valid or not -wire ALU_o_Valid; -wire [ALU_CTLCODE_WIDTH-1:0] ALU_i_ALUOp; // Control bus to ALU -wire [DATA_WIDTH-1:0] ALU_i_Operand1,ALU_i_Operand2; // Ops for ALU -wire [ADDRESS_WIDTH-1:0] EX_i_Branch_Target; -wire [DATA_WIDTH-1:0] ALU_o_Result; // Computation of ALU -wire ALU_o_Branch_Valid; // Whether branch is valid or not -wire ALU_o_Branch_Outcome; // Whether branch is taken or not -wire [15:0] ALU_o_Pass_Done_Value; // reports the value of a PASS/FAIL/DONE instruction -wire [1:0] ALU_o_Pass_Done_Change; // indicates the above signal is meaningful - // 1 = pass, 2 = fail, 3 = done - - // Cumulative signals -wire EX_Take_Branch = ALU_o_Valid && ALU_o_Branch_Valid && ALU_o_Branch_Outcome; // Whether we should branch or not. - - //============== - // Pipe signals: EX->MEM -wire Hazard_Flush_EX; // 3rd pipe flush -wire Hazard_Stall_MEM; // 3rd pipe stall - - -//=================================================================== -// Memory Signals -wire [DATA_WIDTH-1:0] DMEM_i_Result; // Result from the ALU -wire [DATA_WIDTH-1:0] DMEM_i_Mem_Write_Data; // What we will write back to mem (if applicable) -wire DMEM_i_Mem_Valid; // If the memory operation is valid -wire [MEM_MASK_WIDTH-1:0] DMEM_i_Mem_Mask; // Mem mask for sub-word operations -wire DMEM_i_Mem_Read_Write_n; // Type of memop -wire DMEM_i_Writes_Back; // If the result should be written back to regfile -wire [REG_ADDR_WIDTH-1:0] DMEM_i_Write_Addr; // Which reg in the regfile to write to -wire [DATA_WIDTH-1:0] DMEM_o_Read_Data; // The data READ from DMEM -wire DMEM_o_Mem_Ready; // If the DMEM is ready to service another request -wire DMEM_o_Mem_Valid; // If the value read from DMEM is valid -reg DMEM_o_Done; // If MEM's work is finalized -reg [DATA_WIDTH-1:0] DMEM_o_Write_Data; // Data we should write back to regfile - -wire MemToReg = DMEM_i_Mem_Valid; // Selects what we will write back -- mem or ALU result - - //============== - // Pipe signals: MEM->WB -wire Hazard_Flush_MEM; // 4th pipe flush -wire Hazard_Stall_WB; // 4th pipe stall - - -//=================================================================== -// Write-Back Signals -wire WB_i_Writes_Back; // If we will write back -wire [REG_ADDR_WIDTH-1:0] DEC_i_Write_Register; // Where we will write back to -wire [DATA_WIDTH-1:0] WB_i_Write_Data; // What we will write back -wire Hazard_Flush_WB; // Request to squash WB contents - -wire DEC_i_RegWrite = WB_i_Writes_Back && !Hazard_Flush_WB; +// CORE Signals +wire CORE_i_External_Stall; +wire CORE_o_MEM_Valid; +wire CORE_o_MEM_Read_Write_n; +wire [CORE_ADDRESS_WIDTH-1:0] CORE_o_MEM_Address; +wire [DATA_WIDTH-1:0] CORE_o_MEM_Data; +wire CORE_i_MEM_Valid; +wire CORE_i_MEM_Data_Read; +wire CORE_i_MEM_Last; +wire [DATA_WIDTH-1:0] CORE_i_MEM_Data; + +// Outputs for Done flag +wire [15:0] CORE_o_Pass_Done_Value; // reports the value of a PASS/FAIL/DONE instruction +wire [1:0] CORE_o_Pass_Done_Change; // indicates the above signal is meaningful + // 1 = pass, 2 = fail, 3 = done + +// Outputs for performance display +wire [7:0] CORE_o_Num_Inst_Executed; +wire [20:0] CORE_o_IMEM_i_Address; //=================================================================== // Flash Signals @@ -232,20 +125,6 @@ assign FL_RST_N = o_FlashLoader_FL_Reset_n; // Flash reset //=================================================================== // Arbiter Signals -wire Arbiter_i_IMEM_Valid; -wire [ADDRESS_WIDTH-1:0] Arbiter_i_IMEM_Address; -wire Arbiter_o_IMEM_Valid; -wire Arbiter_o_IMEM_Last; -wire [DATA_WIDTH-1:0] Arbiter_o_IMEM_Data; - -wire Arbiter_i_DMEM_Valid; -wire Arbiter_i_DMEM_Read_Write_n; -wire [ADDRESS_WIDTH-1:0] Arbiter_i_DMEM_Address; -wire [DATA_WIDTH-1:0] Arbiter_i_DMEM_Data; -wire [DATA_WIDTH-1:0] Arbiter_o_DMEM_Data; -wire Arbiter_o_DMEM_Data_Read; -wire Arbiter_o_DMEM_Valid; -wire Arbiter_o_DMEM_Last; wire Arbiter_i_Flash_Valid; wire [DATA_WIDTH-1:0] Arbiter_i_Flash_Data; @@ -280,17 +159,11 @@ wire i_Clk; //=================================================================== // Top-level Connections // Clock handling for mem & processor -wire Done = (ALU_o_Pass_Done_Change == MTC0_DONE); +wire Done = (CORE_o_Pass_Done_Change == MTC0_DONE); wire Local_Clock; wire Internal_Reset_n; +assign CORE_i_External_Stall = !o_FlashLoader_Done || Done; -//integer file; -//initial -// begin -// file = $fopen("dumppcs"); -// end - - `ifdef MODEL_TECH assign Internal_Reset_n = Global_Reset_n; assign Local_Clock = CLOCK_50; @@ -330,21 +203,12 @@ begin // If we're currently executing instructions... if( o_FlashLoader_Done && !Done ) begin - // If we have a valid instruction that is finishing up execution in Decode, then count it - if( !Hazard_Stall_DEC && !Hazard_Flush_DEC && !DEC_Noop ) + if (!displaystop && InstructionsExecuted > 1000000000) begin - if (!displaystop) - begin - //$fwrite(file, "%h\n", (DEC_o_PC<<2) + 'h20240); - if (InstructionsExecuted > 1000000000) - begin - displaystop <= 1; -// $fflush(file); -// $fclose(file); - end - end - InstructionsExecuted <= InstructionsExecuted + 32'b1; + displaystop <= 1; end + InstructionsExecuted <= InstructionsExecuted + CORE_o_Num_Inst_Executed; + CycleCount <= CycleCount + 32'b1; // Always count another cycle end end @@ -370,10 +234,10 @@ begin case(SW[1:0]) 2'd0: // Default: Display Pass/Done/Fail, PC, and PDF Value information begin - HEX_Buf[0] <= ALU_o_Pass_Done_Value[3:0]; - HEX_Buf[1] <= ALU_o_Pass_Done_Value[7:4]; - HEX_Buf[6] <= IMEM_i_Address[3:0]; - HEX_Buf[7] <= IMEM_i_Address[7:4]; + HEX_Buf[0] <= CORE_o_Pass_Done_Value[3:0]; + HEX_Buf[1] <= CORE_o_Pass_Done_Value[7:4]; + HEX_Buf[6] <= CORE_o_IMEM_i_Address[3:0]; + HEX_Buf[7] <= CORE_o_IMEM_i_Address[7:4]; end 2'd1: // Cycle Count @@ -416,16 +280,16 @@ SevenSegmentDisplayDecoder SSD4 (i_Clk, HEX4, HEX_Buf[4]); SevenSegmentDisplayDecoder SSD5 (i_Clk, HEX5, HEX_Buf[5]); SevenSegmentDisplayDecoder SSD6 (i_Clk, HEX6, HEX_Buf[6]); SevenSegmentDisplayDecoder SSD7 (i_Clk, HEX7, HEX_Buf[7]); -SevenSegmentPFD PFD2 (i_Clk, HEX2_PFD, ALU_o_Pass_Done_Change); // display pass/done/fail status +SevenSegmentPFD PFD2 (i_Clk, HEX2_PFD, CORE_o_Pass_Done_Change); // display pass/done/fail status // Special case: If SW is 0, then HEX2 output comes from PFD. Else, comes from SSD. assign HEX2 = (SW[1:0]==2'd0 ? HEX2_PFD : HEX2_SSD); /* -SevenSegmentPFD SSD3 (i_Clk, HEX2, ALU_o_Pass_Done_Change); // display pass/done/fail status +SevenSegmentPFD SSD3 (i_Clk, HEX2, CORE_o_Pass_Done_Change); // display pass/done/fail status -SevenSegmentDisplayDecoder SSD0 (i_Clk, HEX0, ALU_o_Pass_Done_Value[3:0]); -SevenSegmentDisplayDecoder SSD1 (i_Clk, HEX1, ALU_o_Pass_Done_Value[7:4]); +SevenSegmentDisplayDecoder SSD0 (i_Clk, HEX0, CORE_o_Pass_Done_Value[3:0]); +SevenSegmentDisplayDecoder SSD1 (i_Clk, HEX1, CORE_o_Pass_Done_Value[7:4]); SevenSegmentDisplayDecoder SSD7 (i_Clk, HEX7, IMEM_i_Address[7:4]); SevenSegmentDisplayDecoder SSD6 (i_Clk, HEX6, IMEM_i_Address[3:0]); @@ -433,300 +297,33 @@ SevenSegmentDisplayDecoder SSD6 (i_Clk, HEX6, IMEM_i_Address[3:0]); */ //=================================================================== -// Structural Description - Overhead -//=================================================================== - - -//=================================================================== -// Structural Description - Pipeline stages +// Structural Description - CORE //=================================================================== - -//=================================================================== -// Instruction Fetch -fetch_unit #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH) - ) - IFETCH - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Stall(Hazard_Stall_IF), - - .i_Load(IFetch_i_Load), - .i_Load_Address(IFetch_i_PCSrc), - - // Outputs - .o_PC(IMEM_i_Address) - ); - -i_cache #( .DATA_WIDTH(DATA_WIDTH) - ) - I_CACHE - ( - // General - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - - // Requests - .i_Valid(o_FlashLoader_Done), - .i_Address(IMEM_i_Address), - - // Mem Transaction - .o_MEM_Valid(Arbiter_i_IMEM_Valid), - .o_MEM_Address(Arbiter_i_IMEM_Address), - .i_MEM_Valid(Arbiter_o_IMEM_Valid), // If data from main mem is valid - .i_MEM_Last(Arbiter_o_IMEM_Last), // If main mem is sending the last piece of data - .i_MEM_Data(Arbiter_o_IMEM_Data), // Data from main mem - - // Outputs - .o_Ready(IMEM_o_Ready), - .o_Valid(IMEM_o_Valid), // If the output is correct. - .o_Data(IMEM_o_Instruction) // The data requested. - ); - -//=================================================================== -// Decode -pipe_if_dec #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH) - ) - PIPE_IF_DEC - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Flush(Hazard_Flush_IF), - .i_Stall(Hazard_Stall_DEC), - .i_imembubble(IMEM_o_Valid), - - // Pipe signals - .i_PC(IMEM_i_Address), - .o_PC(DEC_i_PC), - .i_Instruction(IMEM_o_Instruction), - .o_Instruction(DEC_i_Instruction), - .o_imembubble(imembubble_DEC) - ); - -decoder #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH), - .REG_ADDRESS_WIDTH(REG_ADDR_WIDTH), - .ALUCTL_WIDTH(ALU_CTLCODE_WIDTH), - .MEM_MASK_WIDTH(MEM_MASK_WIDTH) - ) - DECODE - ( // Inputs - .i_PC(DEC_i_PC), - .i_Instruction(DEC_i_Instruction), - .i_Stall(Hazard_Stall_DEC), - - // Outputs - .o_Uses_ALU(DEC_o_Uses_ALU), - .o_ALUCTL(DEC_o_ALUCTL), - .o_Is_Branch(DEC_o_Is_Branch), - .o_Jump_Reg(DEC_o_Jump_Reg), - - .o_Mem_Valid(DEC_o_Mem_Valid), - .o_Mem_Read_Write_n(DEC_o_Mem_Read_Write_n), - .o_Mem_Mask(DEC_o_Mem_Mask), - - .o_Writes_Back(DEC_o_Writes_Back), - .o_Write_Addr(DEC_o_Write_Addr), - - .o_Uses_RS(DEC_o_Uses_RS), - .o_RS_Addr(DEC_o_Read_Register_1), - .o_Uses_RT(DEC_o_Uses_RT), - .o_RT_Addr(DEC_o_Read_Register_2), - .o_Uses_Immediate(DEC_o_Uses_Immediate), - .o_Immediate(DEC_o_Immediate), - .o_Branch_Target(DEC_o_Branch_Target) - ); - - -regfile #( .DATA_WIDTH(DATA_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH) - ) - REGFILE - ( // Inputs - .i_Clk(i_Clk), - - .i_RS_Addr(DEC_o_Read_Register_1), - .i_RT_Addr(DEC_o_Read_Register_2), - - .i_Write_Enable(DEC_i_RegWrite), // Account for squashing WB stage - .i_Write_Data(WB_i_Write_Data), - .i_Write_Addr(DEC_i_Write_Register), - - // Outputs - .o_RS_Data(DEC_o_Read_Data_1), - .o_RT_Data(DEC_o_Read_Data_2) - ); - -//=================================================================== -// Execute -pipe_dec_ex #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH), - .ALU_CTLCODE_WIDTH(ALU_CTLCODE_WIDTH), - .MEM_MASK_WIDTH(MEM_MASK_WIDTH) - ) - PIPE_DEC_EX - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Flush(Hazard_Flush_DEC), - .i_Stall(Hazard_Stall_EX), - - // Pipeline - .i_PC(DEC_o_PC), - .o_PC(ALU_i_PC), - .i_Uses_ALU(DEC_o_Uses_ALU), - .o_Uses_ALU(ALU_i_Valid), - .i_ALUCTL(DEC_o_ALUCTL), - .o_ALUCTL(ALU_i_ALUOp), - .i_Is_Branch(DEC_o_Is_Branch), - .o_Is_Branch(EX_i_Is_Branch), - .i_Mem_Valid(DEC_o_Mem_Valid), - .o_Mem_Valid(EX_i_Mem_Valid), - .i_Mem_Mask(DEC_o_Mem_Mask), - .o_Mem_Mask(EX_i_Mem_Mask), - .i_Mem_Read_Write_n(DEC_o_Mem_Read_Write_n), - .o_Mem_Read_Write_n(EX_i_Mem_Read_Write_n), - .i_Mem_Write_Data(FORWARD_o_Forwarded_Data_2), - .o_Mem_Write_Data(EX_i_Mem_Write_Data), - .i_Writes_Back(DEC_o_Writes_Back), - .o_Writes_Back(EX_i_Writes_Back), - .i_Write_Addr(DEC_o_Write_Addr), - .o_Write_Addr(EX_i_Write_Addr), - .i_Operand1(FORWARD_o_Forwarded_Data_1), - .o_Operand1(ALU_i_Operand1), - .i_Operand2(DEC_o_Uses_Immediate?DEC_o_Immediate:FORWARD_o_Forwarded_Data_2), // Convention - Operand2 mapped to immediates - .o_Operand2(ALU_i_Operand2), - .i_Branch_Target(DEC_o_Jump_Reg?FORWARD_o_Forwarded_Data_1[ADDRESS_WIDTH-1:0]:DEC_o_Branch_Target), - .o_Branch_Target(EX_i_Branch_Target) - ); - -alu #( .DATA_WIDTH(DATA_WIDTH), - .CTLCODE_WIDTH(ALU_CTLCODE_WIDTH) - ) - ALU - ( // Inputs - .i_Valid(ALU_i_Valid), - .i_ALUCTL(ALU_i_ALUOp), - .i_Operand1(ALU_i_Operand1), - .i_Operand2(ALU_i_Operand2), - - // Outputs - .o_Valid(ALU_o_Valid), - .o_Result(ALU_o_Result), - .o_Branch_Valid(ALU_o_Branch_Valid), - .o_Branch_Outcome(ALU_o_Branch_Outcome), - .o_Pass_Done_Value(ALU_o_Pass_Done_Value), - .o_Pass_Done_Change(ALU_o_Pass_Done_Change) +mips_core #( + .DATA_WIDTH(DATA_WIDTH), + .WORD_ADDRESS_WIDTH(CORE_ADDRESS_WIDTH) + ) CORE ( + .i_Clk(i_Clk), + .i_Reset_n(Internal_Reset_n), + .i_External_Stall(CORE_i_External_Stall), + + .o_MEM_Valid(CORE_o_MEM_Valid), + .o_MEM_Read_Write_n(CORE_o_MEM_Read_Write_n), + .o_MEM_Address(CORE_o_MEM_Address), + .o_MEM_Data(CORE_o_MEM_Data), + .i_MEM_Valid(CORE_i_MEM_Valid), + .i_MEM_Data_Read(CORE_i_MEM_Data_Read), + .i_MEM_Last(CORE_i_MEM_Last), + .i_MEM_Data(CORE_i_MEM_Data), + + .o_Pass_Done_Value(CORE_o_Pass_Done_Value), + .o_Pass_Done_Change(CORE_o_Pass_Done_Change), + + .o_Num_Inst_Executed(CORE_o_Num_Inst_Executed), + .o_IMEM_i_Address(CORE_o_IMEM_i_Address) ); //=================================================================== -// Mem -pipe_ex_mem #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH), - .ALU_CTLCODE_WIDTH(ALU_CTLCODE_WIDTH) - ) - PIPE_EX_MEM - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Flush(Hazard_Flush_EX), - .i_Stall(Hazard_Stall_MEM), - - // Pipe in/out - .i_ALU_Result(ALU_o_Result), - .o_ALU_Result(DMEM_i_Result), - .i_Mem_Valid(EX_i_Mem_Valid), - .o_Mem_Valid(DMEM_i_Mem_Valid), - .i_Mem_Mask(EX_i_Mem_Mask), - .o_Mem_Mask(DMEM_i_Mem_Mask), - .i_Mem_Read_Write_n(EX_i_Mem_Read_Write_n), - .o_Mem_Read_Write_n(DMEM_i_Mem_Read_Write_n), - .i_Mem_Write_Data(EX_i_Mem_Write_Data), - .o_Mem_Write_Data(DMEM_i_Mem_Write_Data), - .i_Writes_Back(EX_i_Writes_Back), - .o_Writes_Back(DMEM_i_Writes_Back), - .i_Write_Addr(EX_i_Write_Addr), - .o_Write_Addr(DMEM_i_Write_Addr) - ); - -d_cache #( - .DATA_WIDTH(32), - .MEM_MASK_WIDTH(3) - ) - D_CACHE - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Valid(DMEM_i_Mem_Valid), - .i_Mem_Mask(DMEM_i_Mem_Mask), - .i_Address(DMEM_i_Result[ADDRESS_WIDTH:2]), - .i_Read_Write_n(DMEM_i_Mem_Read_Write_n), //1=MemRead, 0=MemWrite - .i_Write_Data(DMEM_i_Mem_Write_Data), - - // Outputs - .o_Ready(DMEM_o_Mem_Ready), - .o_Valid(DMEM_o_Mem_Valid), - .o_Data(DMEM_o_Read_Data), - - // Mem Transaction - .o_MEM_Valid(Arbiter_i_DMEM_Valid), - .o_MEM_Read_Write_n(Arbiter_i_DMEM_Read_Write_n), - .o_MEM_Address(Arbiter_i_DMEM_Address), - .o_MEM_Data(Arbiter_i_DMEM_Data), - .i_MEM_Valid(Arbiter_o_DMEM_Valid), - .i_MEM_Data_Read(Arbiter_o_DMEM_Data_Read), - .i_MEM_Last(Arbiter_o_DMEM_Last), - .i_MEM_Data(Arbiter_o_DMEM_Data) - ); - - // Multiplexor - Select what we will write back -always @(*) -begin - if( MemToReg ) // If it was a memory operation - begin - DMEM_o_Write_Data <= DMEM_o_Read_Data; // We will write back value from memory - DMEM_o_Done <= DMEM_o_Mem_Valid; // Write back only if value is valid - end - else - begin - DMEM_o_Write_Data <= DMEM_i_Result; // Else we will write back value from ALU - DMEM_o_Done <= TRUE; - end -end - -//=================================================================== -// Write-Back -pipe_mem_wb #( .ADDRESS_WIDTH(ADDRESS_WIDTH), - .DATA_WIDTH(DATA_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH) - ) - PIPE_MEM_WB - ( // Inputs - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - .i_Flush(Hazard_Flush_MEM), - .i_Stall(Hazard_Stall_WB), - - // Pipe in/out - .i_WriteBack_Data(DMEM_o_Write_Data), - .o_WriteBack_Data(WB_i_Write_Data), - .i_Writes_Back(DMEM_i_Writes_Back), - .o_Writes_Back(WB_i_Writes_Back), - .i_Write_Addr(DMEM_i_Write_Addr), - .o_Write_Addr(DEC_i_Write_Register) - ); - - - // Write-Back is simply wires feeding back into regfile to perform writes - // (SEE REGFILE) - - - -//=================================================================== // Arbitration Logic // Memory arbiter @@ -738,23 +335,16 @@ memory_arbiter #( .DATA_WIDTH(DATA_WIDTH), // General .i_Clk(i_Clk), .i_Reset_n(Internal_Reset_n), - - // Requests to/from IMEM - Assume we always read - .i_IMEM_Valid(Arbiter_i_IMEM_Valid), // If IMEM request is valid - .i_IMEM_Address(Arbiter_i_IMEM_Address), // IMEM request addr. - .o_IMEM_Valid(Arbiter_o_IMEM_Valid), - .o_IMEM_Last(Arbiter_o_IMEM_Last), - .o_IMEM_Data(Arbiter_o_IMEM_Data), - // Requests to/from DMEM - .i_DMEM_Valid(Arbiter_i_DMEM_Valid), - .i_DMEM_Read_Write_n(Arbiter_i_DMEM_Read_Write_n), - .i_DMEM_Address(Arbiter_i_DMEM_Address), - .i_DMEM_Data(Arbiter_i_DMEM_Data), - .o_DMEM_Valid(Arbiter_o_DMEM_Valid), - .o_DMEM_Data_Read(Arbiter_o_DMEM_Data_Read), - .o_DMEM_Last(Arbiter_o_DMEM_Last), - .o_DMEM_Data(Arbiter_o_DMEM_Data), + // Requests to/from CORE + .i_CORE_Valid(CORE_o_MEM_Valid), + .i_CORE_Read_Write_n(CORE_o_MEM_Read_Write_n), + .i_CORE_Address(CORE_o_MEM_Address), + .i_CORE_Data(CORE_o_MEM_Data), + .o_CORE_Valid(CORE_i_MEM_Valid), + .o_CORE_Data_Read(CORE_i_MEM_Data_Read), + .o_CORE_Last(CORE_i_MEM_Last), + .o_CORE_Data(CORE_i_MEM_Data), // Requests to/from FLASH - Assume we always write .i_Flash_Valid(Arbiter_i_Flash_Valid), @@ -812,119 +402,6 @@ sdram_controller memory_controller( .o_Dqm({DRAM_UDQM,DRAM_LDQM}) ); - -// Forwarding logic -forwarding_unit #( .DATA_WIDTH(DATA_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH) - ) - FORWARDING_UNIT - ( - // Feedback from DEC - .i_DEC_Uses_RS(DEC_o_Uses_RS), - .i_DEC_RS_Addr(DEC_o_Read_Register_1), - .i_DEC_Uses_RT(DEC_o_Uses_RT), // DEC wants to use RT - .i_DEC_RT_Addr(DEC_o_Read_Register_2), // RT request addr. - .i_DEC_RS_Data(DEC_o_Read_Data_1), - .i_DEC_RT_Data(DEC_o_Read_Data_2), - - // Feedback from EX - .i_EX_Writes_Back(EX_i_Writes_Back), // EX is valid for analysis - .i_EX_Valid(ALU_i_Valid), // If it's a valid ALU op or not - .i_EX_Write_Addr(EX_i_Write_Addr), // What EX will write to - .i_EX_Write_Data(ALU_o_Result), - - // Feedback from MEM - .i_MEM_Writes_Back(DMEM_i_Writes_Back), // MEM is valid for analysis - .i_MEM_Write_Addr(DMEM_i_Write_Addr), // What MEM will write to - .i_MEM_Write_Data(DMEM_o_Write_Data), - - // Feedback from WB - .i_WB_Writes_Back(WB_i_Writes_Back), // WB is valid for analysis - .i_WB_Write_Addr(DEC_i_Write_Register), // What WB will write to - .i_WB_Write_Data(WB_i_Write_Data), - - //=============================================== - // IFetch forwarding - - // None - - // DEC forwarding - .o_DEC_RS_Override_Data(FORWARD_o_Forwarded_Data_1), - .o_DEC_RT_Override_Data(FORWARD_o_Forwarded_Data_2) - ); - -// Hazard detection unit / Stall logic -hazard_detection_unit #( .DATA_WIDTH(DATA_WIDTH), - .ADDRESS_WIDTH(ADDRESS_WIDTH), - .REG_ADDR_WIDTH(REG_ADDR_WIDTH) - ) - HAZARD_DETECTION_UNIT - ( - .i_Clk(i_Clk), - .i_Reset_n(Internal_Reset_n), - - //============================================== - // Overall state - .i_FlashLoader_Done(o_FlashLoader_Done), // Info about if flashloader is done - .i_Done(Done), // If we have observed the 'done' signal from the code yet - - //============================================== - // Hazard in DECODE? - .i_DEC_Uses_RS(DEC_o_Uses_RS), // DEC wants to use RS - .i_DEC_RS_Addr(DEC_o_Read_Register_1), // RS request addr. - .i_DEC_Uses_RT(DEC_o_Uses_RT), // DEC wants to use RT - .i_DEC_RT_Addr(DEC_o_Read_Register_2), // RT request addr. - .i_DEC_Branch_Instruction(DEC_o_Is_Branch), - - //=============================================== - // Feedback from IF - .i_IF_Done(IMEM_o_Valid), // If IF's value has reached steady state - - // Feedback from EX - .i_EX_Writes_Back(EX_i_Writes_Back), // EX is valid for data dependency analysis - .i_EX_Uses_Mem(EX_i_Mem_Valid), - .i_EX_Write_Addr(EX_i_Write_Addr), // What EX will write to - .i_EX_Branch(EX_Take_Branch), // If EX says we are branching - .i_EX_Branch_Target(EX_i_Branch_Target), - - // Feedback from MEM - .i_MEM_Uses_Mem(DMEM_i_Mem_Valid), // If it's a memop - .i_MEM_Writes_Back(DMEM_i_Writes_Back), // MEM is valid for analysis - .i_MEM_Write_Addr(DMEM_i_Write_Addr), // What MEM will write to - .i_MEM_Done(DMEM_o_Done), // If MEM's value has reached steady state - - // Feedback from WB - .i_WB_Writes_Back(WB_i_Writes_Back), - .i_WB_Write_Addr(DEC_i_Write_Register), - - //=============================================== - // Branch hazard handling - .o_IF_Branch(IFetch_i_Load), - .o_IF_Branch_Target(IFetch_i_PCSrc), - - //=============================================== - // IFetch validation - .o_IF_Stall(Hazard_Stall_IF), - .o_IF_Smash(Hazard_Flush_IF), - - // DECODE validation - .o_DEC_Stall(Hazard_Stall_DEC), - .o_DEC_Smash(Hazard_Flush_DEC), - - // EX validation - .o_EX_Stall(Hazard_Stall_EX), - .o_EX_Smash(Hazard_Flush_EX), - - // MEM validation - .o_MEM_Stall(Hazard_Stall_MEM), - .o_MEM_Smash(Hazard_Flush_MEM), - - .o_WB_Stall(Hazard_Stall_WB), - .o_WB_Smash(Hazard_Flush_WB) - ); - - - //=================================================================== // Initialization -- 1.9.1