URL
https://opencores.org/ocsvn/theia_gpu/theia_gpu/trunk
Subversion Repositories theia_gpu
[/] [theia_gpu/] [trunk/] [test_bench/] [TestBench_THEIA.v] - Rev 72
Go to most recent revision | Compare with Previous | Blame | View Log
/********************************************************************************** Theia, Ray Cast Programable graphic Processing Unit. Copyright (C) 2010 Diego Valverde (diego.valverde.g@gmail.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***********************************************************************************/ /******************************************************************************* Module Description: This is the Main test bench of the GPU. It simulates the behavior of an external control unit or CPU that sends configuration information into DUT. It also implements a second processs that simulates a Wishbone slave that sends data from an external memory. These blocks are just behavioral CTE and therefore are not meant to be synthethized. *******************************************************************************/ `timescale 1ns / 1ps `include "aDefinitions.v" `define CONFIGURATION_PHASE 0 `define CTE_INITIAL_STATE 0 `define CTE_IDLE 1 `define CTE_START_EU_CONFIGURATION_SEQUENCE 2 `define CTE_SEND_CONFIGURATION_PACKET 3 `define CTE_ACK_CONFIGURATION_PACKET 8 `define CTE_SEND_LIGHT_PACKET 13 `define CTE_ACK_LIGTH_PACKET 14 `define CTE_SEND_RAY_I_TASK 15 `define CTE_WAIT_FOR_TASK_ACK 16 `define WAIT_FOR_TASK_COMPLETE 17 `define CTE_PREPARE_NEW_TASK 18 `define CTE_RENDER_DONE 19 `define CTE_READ_COLOR_DATA 20 `define CTE_GRANT_BUS_WRITE_PERMISION 21 `define CTE_ACK_GRANT_BUS_PERMISION 22 `define CTE_ACK_READ_COLOR_DATA 23 `define CTE_SEND_TEXTURE_DIMENSIONS 24 `define CTE_ACK_TEXTURE_DIMENSIONS 25 `define RESOLUTION_WIDTH (rSceneParameters[12] >> `SCALE) `define RESOLUTION_HEIGHT (rSceneParameters[13] >> `SCALE) `define RAYI_TASK 1 `define DELTA_ROW (32'h1 << `SCALE) `define DELTA_COL (32'h1 << `SCALE) module TestBench_Theia; //------------------------------------------------------------------------ //**WARNING: Declare all of your varaibles at the begining //of the file. I hve noticed that sometimes the verilog //simulator allows you to use some regs even if they have not been //previously declared, leadeing to crahses or unexpected behavior // Inputs reg Clock; reg Reset; reg ExternalBus_DataReady; // Outputs wire ExternalBus_Acknowledge; wire TaskCompleted; //CTE state machin logic reg[31:0] CurrentState,NextState; reg[3:0] LightCount; reg[31:0] rLaneA,rLaneB,rLaneC,rLaneD; reg[16:0] CurrentTaskId; reg[31:0] CurrentPixelRow, CurrentPixelCol,CurrentRayType; reg CTE_WriteEnable; wire [`WB_WIDTH-1:0] DAT_O; reg ACK_O; wire ACK_I; wire [`WB_WIDTH-1:0] ADR_I,ADR_O; wire WE_I,STB_I,CYC_I; reg CYC_O,WE_O,TGC_O,STB_O; wire [1:0] TGC_I; reg [1:0] TGA_O; wire [1:0] TGA_I; wire [31:0] DAT_I; integer ucode_file; reg [31:0] rInitialCol,rInitialRow; reg [31:0] rControlRegister[2:0]; integer file, log, r, a, b; reg [31:0] rSceneParameters[31:0]; reg [31:0] rVertexBuffer[6000:0]; reg [31:0] rInstructionBuffer[512:0]; `define TEXTURE_BUFFER_SIZE (256*256*3) reg [31:0] rTextures[`TEXTURE_BUFFER_SIZE:0]; //Lets asume we use 256*256 textures //------------------------------------------------------------------------ //Debug registers `define TASK_TIMEOUTMAX 150000//50000 //------------------------------------------------------------------------ reg MST_O; //--------------------------------------------------------------- THEIACORE THEIA ( .CLK_I( Clock ), .RST_I( Reset ), .DAT_I( DAT_O ), .ADR_O( ADR_I ), .ACK_I( ACK_O ), .WE_O ( WE_I ), .STB_O( STB_I ), .CYC_O( CYC_I ), .CYC_I( CYC_O ), .TGC_O( TGC_I ), .MST_I( MST_O ), .TGA_I( TGA_O ), .ACK_O( ACK_I ), .ADR_I( ADR_O ), .DAT_O( DAT_I ), .WE_I( WE_O ), .STB_I( STB_O ), .TGA_O(TGA_I), //Control register .CREG_I( rControlRegister[0][15:0] ) //Other stuff ); //& //--------------------------------------------------------------- //--------------------------------------------- //generate the clock signal here always begin #`CLOCK_CYCLE Clock = ! Clock; end //--------------------------------------------- reg [15:0] rTimeOut; `define MAX_INSTRUCTIONS 2 initial begin // Initialize Inputs Clock = 0; Reset = 0; CTE_WriteEnable = 0; rLaneA = 32'b0; rLaneB = 32'b0; rLaneC = 32'b0; rLaneD = 32'b0; ExternalBus_DataReady = 0; rTimeOut = 0; `ifdef DUMP_CODE $write("Opening TestBench.log.... "); ucode_file = $fopen("TestBench.log","w"); $display("Done"); `endif //Read Config register values $write("Loading control register.... "); $readmemh("Creg.mem",rControlRegister); $display("Done"); //Read configuration Data $write("Loading scene parameters.... "); $readmemh("Params.mem", rSceneParameters ); $display("Done"); rInitialRow = rSceneParameters[18]; rInitialCol = rSceneParameters[19]; //Read Scene Data $write("Loading scene geometry.... "); $readmemh("Vertex.mem",rVertexBuffer); $display("Done"); //Read Texture Data $write("Loading scene texture.... "); $readmemh("Textures.mem",rTextures); $display("Done"); //Read instruction data $write("Loading code allocation table and user shaders.... "); $readmemh("Instructions.mem",rInstructionBuffer); $display("Done"); $display("Control Register : %b",rControlRegister[0]); $display("Initial Row : %h",rInitialRow); $display("Initial Column : %h",rInitialCol); $display("Resolution : %d X %d",`RESOLUTION_WIDTH, `RESOLUTION_HEIGHT ); //Open output file file = $fopen("Output.ppm"); log = $fopen("Simulation.log"); $fwrite(log, "Simulation start time : %dns\n",$time); $fwrite(log, "Width : %d\n",`RESOLUTION_WIDTH); $fwrite(log, "Height : %d\n",`RESOLUTION_HEIGHT); $fwrite(file,"P3\n"); $fwrite(file,"#This file was generated by Theia's RTL simulation\n"); $fwrite(file,"%d %d\n",`RESOLUTION_WIDTH, `RESOLUTION_HEIGHT ); $fwrite(file,"255\n"); CurrentPixelRow = 0; CurrentPixelCol = 0; #10 Reset = 1; ExternalBus_DataReady = 0; // Wait 100 ns for global reset to finish #100 Reset = 0; end reg [5:0] DataIndex; reg [31:0] ConfigurationPacketSize; reg [7:0] R,G,B; //--------------------------------------------- always @ (posedge Clock) begin rTimeOut = rTimeOut+1'b1; if (rTimeOut > `TASK_TIMEOUTMAX) begin $display("%dns ERROR: THEIA Timed out after %d of inactivity\n", $time(),rTimeOut); $stop(); end end reg [31:0] rSlaveData_O; //reg [31:0] rOutputFrameBuffer[39000:0]; reg [31:0] rColor; reg [7:0] Thingy; //Wish-Bone Slave logic. // //This logic represents a WBS FSM. It will provide //the memory for Vertex and Texture data. //Vertex/Tetxure data is stored in a 4GB RAM. //Vertex data starts at address 0 and ends at address 0x80_000_000. //Texture data starts at address 0x80_000_000 and ends at address //0xFFFFFFFF. //The Bit 31, indcates wheather we look for vertex (b=0) //or texture (b=1) `define WBS_AFTER_RESET 0 `define WBS_MOINTOR_STB_I 1 `define WBS_ACK_O 2 `define WBS_MOINTOR_STB_I_NEG 3 `define WBS_DONE 4 reg [7:0] WBSCurrentState,WBSNextState; reg [31:0] rAddress; always @(negedge Clock) begin if( Reset!=1 ) WBSCurrentState = WBSNextState; else WBSCurrentState = `WBS_AFTER_RESET; end reg [31:0] rConvertedTextureAddress; //---------------------------------------------------------- always @(posedge Clock) begin case (WBSCurrentState) //---------------------------------------- `WBS_AFTER_RESET: begin ACK_O = 0; rSlaveData_O = 32'b0; WBSNextState = `WBS_MOINTOR_STB_I; end //---------------------------------------- `WBS_MOINTOR_STB_I: begin if ( STB_I == 1 ) WBSNextState = `WBS_ACK_O; else WBSNextState = `WBS_MOINTOR_STB_I; end //---------------------------------------- `WBS_ACK_O: begin if (WE_I == 0) begin rAddress = ADR_I; if (TGA_I == 2'b01) //replace this by TGA_I begin //Multiply pithc (3), Add 2 because the first 2 bytes are text Width, Height rConvertedTextureAddress = {1'b0,rAddress[30:0]} + 2; if (rConvertedTextureAddress >= `TEXTURE_BUFFER_SIZE) rConvertedTextureAddress = `TEXTURE_BUFFER_SIZE-1; rSlaveData_O = rTextures[ rConvertedTextureAddress ]; `ifdef DEBUG `LOGME"WB SLAVE: MASTER Requested read from texture address: %h (%d)Data = %h \n",rAddress, rConvertedTextureAddress,DAT_O ); `endif end else begin Thingy = 0; rSlaveData_O = rVertexBuffer[ rAddress ]; `ifdef DEBUG `LOGME"WB SLAVE: MASTER Requested read from vertex address: %h Data = %h\n",rAddress,DAT_O); `endif end end else begin // $display("Theia Writes value: %h @ %h (Time to process pixel %d Clock cycle)",DAT_I,ADR_I,rTimeOut); if (Thingy == 0) begin $fwrite(file,"\n# %d %d\n",CurrentPixelRow,CurrentPixelCol); $write("."); end Thingy = Thingy + 1; if (CurrentPixelRow >= `RESOLUTION_WIDTH) begin CurrentPixelRow = 0; CurrentPixelCol = CurrentPixelCol + 1; $display("]- %d (%d)",CurrentPixelCol,ADR_I); $write("["); end if (Thingy == 3) begin CurrentPixelRow = CurrentPixelRow + 1; Thingy = 0; end rTimeOut = 0; R = ((DAT_I >> (`SCALE-8)) > 255) ? 255 : (DAT_I >> (`SCALE-8)); $fwrite(file,"%d " , R ); end ACK_O = 1; if (CurrentPixelCol >= `RESOLUTION_HEIGHT) WBSNextState = `WBS_DONE; else WBSNextState = `WBS_MOINTOR_STB_I_NEG; end //---------------------------------------- `WBS_MOINTOR_STB_I_NEG: begin if ( STB_I == 0 ) begin ACK_O = 0; WBSNextState = `WBS_MOINTOR_STB_I; end else WBSNextState = `WBS_MOINTOR_STB_I_NEG; end //---------------------------------------- `WBS_DONE: begin $display("RESOLUTION_WIDTH = %d,RESOLUTION_HEIGHT= %d", `RESOLUTION_WIDTH,`RESOLUTION_HEIGHT); $display("ADR_I = %d\n",ADR_I); `LOGME"RENDER COMPLETE"); `LOGME"Closing File"); $fclose(file); $fwrite(log, "Simulation end time : %dns\n",$time); $fclose(log); `LOGME"File Closed"); $stop(); $fclose(ucode_file); end //---------------------------------------- default: begin $display("WBS Undefined state"); end endcase end //end always //---------------------------------------------------------- `define TAG_BLOCK_WRITE_CYCLE 2'b01 `define TAG_INSTRUCTION_ADDRESS_TYPE 2'b01 `define TAG_DATA_ADDRESS_TYPE 2'b10 `define WBM_AFTER_RESET 0 `define WBM_WRITE_INSTRUCTION_PHASE1 1 `define WBM_ACK_INSTRUCTION_PHASE1 2 `define WBM_WRITE_INSTRUCTION_PHASE2 3 `define WBM_ACK_INSTRUCTION_PHASE2 4 `define WBM_END_INSTRUCTION_WRITE_CYCLE 5 `define WBM_SEND_DATA_PHASE1 6 `define WBM_ACK_DATA_PHASE1 7 `define WBM_SEND_DATA_PHASE2 8 `define WBM_ACK_DATA_PHASE2 9 `define WBM_SEND_DATA_PHASE3 10 `define WBM_ACK_DATA_PHASE3 11 `define WBM_END_DATA_WRITE_CYCLE 12 `define WBM_DONE 13 reg[31:0] rInstructionPointer; reg[31:0] rAddressToSend; reg[31:0] rDataAddress; reg[31:0] rDataPointer; reg IncIP,IncIA,IncDP; reg rClearOutAddress; //----------------------------------------------------- always @ (posedge Clock or posedge rClearOutAddress) begin if ( IncIA && ~rClearOutAddress) rAddressToSend = rAddressToSend + 1; else if (rClearOutAddress) begin if (TGA_O == `TAG_INSTRUCTION_ADDRESS_TYPE) rAddressToSend = {16'd1,16'd0}; else rAddressToSend = 0; end end //----------------------------------------------------- always @ (posedge ACK_I or posedge Reset ) begin if ( ACK_I && ~Reset) rInstructionPointer = rInstructionPointer + 1; else if (Reset) rInstructionPointer = 0; end //----------------------------------------------------- reg rResetDp; always @ (posedge Clock or posedge rResetDp ) begin if ( ACK_I && ~rResetDp)//IncDP && ~Reset) rDataPointer = rDataPointer + 1; else if (rResetDp) rDataPointer = 32'b0; end //----------------------------------------------------- assign DAT_O = ( MST_O == 1'b1 ) ? wMasteData_O : rSlaveData_O; wire[31:0] wMasteData_O; assign wMasteData_O = (TGA_O == `TAG_INSTRUCTION_ADDRESS_TYPE) ? rInstructionBuffer[rInstructionPointer+1] : rSceneParameters[ rDataPointer ]; always @ (posedge STB_O) begin if (TGA_O == `TAG_INSTRUCTION_ADDRESS_TYPE) begin //$display("-- %x\n",wMasteData_O); end end assign ADR_O = rAddressToSend; reg [7:0] WBMCurrentState,WBMNextState; reg [31:0] rWriteAddress; always @(posedge Clock or posedge Reset) begin if( Reset!=1 ) WBMCurrentState = WBMNextState; else WBMCurrentState = `WBM_AFTER_RESET; end wire[31:0] wConfigurationPacketSize; assign wConfigurationPacketSize = rSceneParameters[2]; reg [31:0] InstructionIndex; reg [31:0] InstructionWriteAddress; //Send the instructions now... //---------------------------------------------------------- always @(posedge Clock) begin case (WBMCurrentState) //---------------------------------------- //Wait until the reset secuence is complete to //begin sending stuff. `WBM_AFTER_RESET: begin WE_O <= 0; CYC_O <= 0; TGC_O <= 0; TGA_O <= `TAG_INSTRUCTION_ADDRESS_TYPE; STB_O <= 0; // IncIP <= 0; IncIA <= 0; MST_O <= 0; IncDP <= 0; rResetDp <= 1; rClearOutAddress <= 1; if (Reset == 0) WBMNextState <= `WBM_WRITE_INSTRUCTION_PHASE1; else WBMNextState <= `WBM_AFTER_RESET; end //---------------------------------------- //CLOCK EDGE 0: MASTER presents a valid address on [ADR_O()] //MASTER presents valid data on [DAT_O()] //MASTER asserts [WE_O] to indicate a WRITE cycle. //MASTER asserts [CYC_O] and [TGC_O()] to indicate the start of the cycle. //MASTER asserts [STB_O] to indicate the start of the phase. `WBM_WRITE_INSTRUCTION_PHASE1: begin WE_O <= 1; //Indicate write cycle CYC_O <= 1; //Start of the cycle TGC_O <= `TAG_BLOCK_WRITE_CYCLE; //TAG CYCLE: 10 indicated multiple write Cycle TGA_O <= `TAG_INSTRUCTION_ADDRESS_TYPE; //TAG Address: 01 means instruction address type. STB_O <= ~ACK_I; //Start of phase (you put this in zero to introduce wait cycles) // IncIP <= 0; IncIA <= 0; MST_O <= 1; IncDP <= 0; rResetDp <= 1; rClearOutAddress <= 0; if ( ACK_I ) WBMNextState <= `WBM_ACK_INSTRUCTION_PHASE1; else WBMNextState <= `WBM_WRITE_INSTRUCTION_PHASE1; end //---------------------------------------- `WBM_ACK_INSTRUCTION_PHASE1: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_INSTRUCTION_ADDRESS_TYPE; STB_O <= 0; //* //Negate STB_O in response to ACK_I // IncIP <= 1; //* //Increment local inst pointer to send the next 32 bits IncIA <= 0; //leave the instruction write address the same MST_O <= 1; IncDP <= 0; rResetDp <= 1; rClearOutAddress <= 0; if (ACK_I == 0) WBMNextState <= `WBM_WRITE_INSTRUCTION_PHASE2; else WBMNextState <= `WBM_ACK_INSTRUCTION_PHASE1; end //---------------------------------------- `WBM_WRITE_INSTRUCTION_PHASE2: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_INSTRUCTION_ADDRESS_TYPE; STB_O <= ~ACK_I; // IncIP <= 0; IncIA <= 0; MST_O <= 1; IncDP <= 0; rResetDp <= 1; rClearOutAddress <= 0; if ( ACK_I ) WBMNextState <= `WBM_ACK_INSTRUCTION_PHASE2; else WBMNextState <= `WBM_WRITE_INSTRUCTION_PHASE2; end //---------------------------------------- `WBM_ACK_INSTRUCTION_PHASE2: begin WE_O <= 1; CYC_O <= 0; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_INSTRUCTION_ADDRESS_TYPE; STB_O <= 0; //* MST_O <= 1; IncDP <= 0; rResetDp <= 1; if (rInstructionPointer >= rInstructionBuffer[0]) begin IncIA <= 0;//* rClearOutAddress <= 1; WBMNextState <= `WBM_SEND_DATA_PHASE1; end else begin IncIA <= 1;//* rClearOutAddress <= 0; WBMNextState <= `WBM_WRITE_INSTRUCTION_PHASE1; end end //**************************************** `WBM_SEND_DATA_PHASE1: begin WE_O <= 1; //Indicate write cycle CYC_O <= 1; //Start of the cycle TGC_O <= `TAG_BLOCK_WRITE_CYCLE; //TAG CYCLE: 10 indicated multiple write Cycle TGA_O <= `TAG_DATA_ADDRESS_TYPE; //TAG Address: 01 means instruction address type. STB_O <= ~ACK_I; //Start of phase (you put this in zero to introduce wait cycles) // IncIP <= 0; IncIA <= 0; MST_O <= 1; IncDP <= 0; rResetDp <= 0; rClearOutAddress <= 0; if ( ACK_I ) WBMNextState <= `WBM_ACK_DATA_PHASE1; else WBMNextState <= `WBM_SEND_DATA_PHASE1; end //---------------------------------------- `WBM_ACK_DATA_PHASE1: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_DATA_ADDRESS_TYPE; STB_O <= 0; //* //Negate STB_O in response to ACK_I // IncIP <= 1; //* //Increment local inst pointer to send the next 32 bits IncIA <= 0; //leave the instruction write address the same MST_O <= 1; IncDP <= 0; rResetDp <= 0; rClearOutAddress <= 0; if (ACK_I == 0) WBMNextState <= `WBM_SEND_DATA_PHASE2; else WBMNextState <= `WBM_ACK_DATA_PHASE1; end //---------------------------------------- `WBM_SEND_DATA_PHASE2: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_DATA_ADDRESS_TYPE; STB_O <= ~ACK_I; // IncIP <= 0; IncIA <= 0; MST_O <= 1; IncDP <= 0; rResetDp <= 0; rClearOutAddress <= 0; if ( ACK_I ) WBMNextState <= `WBM_ACK_DATA_PHASE2; else WBMNextState <= `WBM_SEND_DATA_PHASE2; end //---------------------------------------- `WBM_ACK_DATA_PHASE2: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_DATA_ADDRESS_TYPE; STB_O <= 0; //* IncIA <= 0; MST_O <= 1; IncDP <= 0;//* rResetDp <= 0; rClearOutAddress <= 0; if (ACK_I == 0) WBMNextState <= `WBM_SEND_DATA_PHASE3; else WBMNextState <= `WBM_ACK_DATA_PHASE2; end //---------------------------------------- `WBM_SEND_DATA_PHASE3: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_DATA_ADDRESS_TYPE; STB_O <= ~ACK_I; // IncIP <= 0; IncIA <= 0; MST_O <= 1; IncDP <= 0; rResetDp <= 0; rClearOutAddress <= 0; if ( ACK_I ) WBMNextState <= `WBM_ACK_DATA_PHASE3; else WBMNextState <= `WBM_SEND_DATA_PHASE3; end //---------------------------------------- `WBM_ACK_DATA_PHASE3: begin WE_O <= 1; CYC_O <= 1; TGC_O <= `TAG_BLOCK_WRITE_CYCLE; TGA_O <= `TAG_DATA_ADDRESS_TYPE; STB_O <= 0; //* IncIA <= 0; MST_O <= 1; IncDP <= 1;//* rResetDp <= 0; rClearOutAddress <= 0; WBMNextState <= `WBM_END_DATA_WRITE_CYCLE; end //---------------------------------------- `WBM_END_DATA_WRITE_CYCLE: begin WE_O <= 0; CYC_O <= 0; //* TGC_O <= 0; TGA_O <= 0; STB_O <= 0; IncIA <= 1;//* MST_O <= 1; IncDP <= 0; rResetDp <= 0; rClearOutAddress <= 0; if (rDataPointer > wConfigurationPacketSize*3) WBMNextState <= `WBM_DONE; else WBMNextState <= `WBM_SEND_DATA_PHASE1; end //---------------------------------------- //Here everything is ready so just start! `WBM_DONE: begin WE_O <= 0; CYC_O <= 0; TGC_O <= 0; TGA_O <= 0; STB_O <= 0; IncIA <= 0; MST_O <= 0; IncDP <= 0; rResetDp <= 1; rClearOutAddress <= 1; WBMNextState <= `WBM_DONE; end //---------------------------------------- endcase end //end always //---------------------------------------------------------- endmodule
Go to most recent revision | Compare with Previous | Blame | View Log