《从0开始设计和实现CPU》总线设计(一)之总线仲裁器的实现

《从0开始设计和实现CPU》总线设计(一)之总线仲裁器的实现,第1张

(一)总线的实现
  1. 总线由总线仲裁器,总线主控多路复用器,地址解码器,总线从属多路复用器组成,本文记录总线仲裁器的实现。




    原理请看书《CPU自制入门》,书中通俗易懂,图文并茂。

(二)程序源码

1.定义bus_arbiter.h(书中定义为bus.h)

`ifndef __BUS_ARBITER_HEADER__
`define __BUS_ARBITER_HEADER__


`define BUS_MASTER_CH       4     //总线主控通道数
`define BUS_MASTER_INDEX_W  2     //总线主控索引宽度
 
`define BusOwnerBus         1:0   //总线所有权状态总线

`define BUS_OWNER_MASTER_0  2'h0  //总线使用权所有者:0号总线主控
`define BUS_OWNER_MASTER_1  2'h1  //总线使用权所有者:1号总线主控
`define BUS_OWNER_MASTER_2  2'h2  //总线使用权所有者:2号总线主控
`define BUS_OWNER_MASTER_3  2'h3  //总线使用权所有者:3号总线主控

`define BUS_SLAVE_CH        8     //总线从属通道数
`define BUS_SLAVE_INDEX_W   3     //总线主控索引宽度
`define BusSlaveLndexBus    2:0   //总线从属索引总线
`define BusSlaveLndexLoc    29:27 //总线从属索引总线

`define BUS_SLAVE_0         0     //0号总线从属
`define BUS_SLAVE_1         1     //1号总线从属
`define BUS_SLAVE_2         2     //2号总线从属
`define BUS_SLAVE_3         3     //3号总线从属
`define BUS_SLAVE_4         4     //4号总线从属
`define BUS_SLAVE_5         5     //5号总线从属
`define BUS_SLAVE_6         6     //6号总线从属
`define BUS_SLAVE_7         7     //7号总线从属

`endif

对比:C语言(#define ) Verilog HDL(`define)

Verilog HDL中的预处理命令和在使用宏时,前面都应该加上(`)

2.定义bus_arbiter.v

`timescale 1ns/1ns   //单位时间为1ns,时间精度1ns

`include "stddef.h"
`include "bus_arbiter.h"
`include "global_config.h"

module bus_arbiter(
     
	  input  wire     clk,     //时钟
     input  wire     reset,   //异步复位 
   
	  input  wire     m0_req_,   //0号总线主控_请求总线
     output reg      m0_grnt_,  //0号总线主控_赋予总线
     
	  input  wire     m1_req_,   //1号总线主控_请求总线
     output reg      m1_grnt_,  //1号总线主控_赋予总线
     
	  input  wire     m2_req_,   //2号总线主控_请求总线
     output reg      m2_grnt_,  //2号总线主控_赋予总线
	  
	  input  wire     m3_req_,   //3号总线主控_请求总线
     output reg      m3_grnt_   //3号总线主控_赋予总线

);

/****内部信号****/
  reg[1:0]     owner;

/****赋予总线使用权****/ 
always @(*) begin
   /****赋予总线使用权的初始化****/ 
	m0_grnt_ = `DISABLE_;
   m1_grnt_ = `DISABLE_;
	m2_grnt_ = `DISABLE_;
	m3_grnt_ = `DISABLE_;
	
   /****赋予总线使用权****/ 
   case(owner)
	    `BUS_OWNER_MASTER_0 : begin
		    m0_grnt_ = `ENABLE_;    
	    end
		 
		 `BUS_OWNER_MASTER_1 : begin
		    m1_grnt_ = `ENABLE_;    
	    end
		 
		 `BUS_OWNER_MASTER_2 : begin
		    m2_grnt_ = `ENABLE_;
		 end 
			 
		 `BUS_OWNER_MASTER_3 : begin
		    m3_grnt_ = `ENABLE_; 
		 end	 
	endcase

 end

 
   /****总线使用权的仲裁****/ 
 
 always @(posedge clk or `RESET_EDGE reset) begin
 
       if(reset==`RESET_ENABLE)begin
		 //异步复位
		 owner <= #1 `BUS_OWNER_MASTER_0;
		 end else begin
		   //仲裁
			 case(owner)
			`BUS_OWNER_MASTER_0:begin
			   if(m0_req_ == `ENABLE_)begin
               owner <= #1 `BUS_OWNER_MASTER_0;
			   end else if(m1_req_ == `ENABLE_)begin
			      owner <= #1 `BUS_OWNER_MASTER_1;
			   end else if(m2_req_ == `ENABLE_)begin
			      owner <= #1 `BUS_OWNER_MASTER_2;
			   end else if(m3_req_ == `ENABLE_)begin
			      owner <= #1 `BUS_OWNER_MASTER_3;
		      end
				
         end 
		 
		   `BUS_OWNER_MASTER_1:begin
			   if(m1_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_1;
				end else if(m2_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_2;
		   	end else if(m3_req_ == `ENABLE_)begin
		        owner <= #1 `BUS_OWNER_MASTER_3;
			   end else if(m0_req_ == `ENABLE_)begin
			     owner <= #1 `BUS_OWNER_MASTER_0;
				end 
			
			end
			
		  `BUS_OWNER_MASTER_2:begin
			   if(m2_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_2;
				end else if(m3_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_3;
		   	end else if(m0_req_ == `ENABLE_)begin
		        owner <= #1 `BUS_OWNER_MASTER_0;
			   end else if(m1_req_ == `ENABLE_)begin
			     owner <= #1 `BUS_OWNER_MASTER_1;
				end 
			
			end
			
		 `BUS_OWNER_MASTER_3:begin
			   if(m3_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_3;
				end else if(m0_req_ == `ENABLE_)begin
				  owner <= #1 `BUS_OWNER_MASTER_0;
		   	end else if(m1_req_ == `ENABLE_)begin
		        owner <= #1 `BUS_OWNER_MASTER_1;
			   end else if(m2_req_ == `ENABLE_)begin
			     owner <= #1 `BUS_OWNER_MASTER_2;
				end 
			
			end
	  endcase
	end	
	
end 

endmodule

编译只能检查基本的语法错误,我们采用仿真来验证电路功能,我们开始制作Testbench,由于书中未给出代码,只能自己写。


命名风格主要有两种:bus_arbiter_test.v 和 bus_arbiter_tb.v 。

见名知意告诉我:这是bus_arbiter.v的Testbench文件。

这里我选择第一种风格。

3.定义bus_arbiter_test.v


`timescale 1ns/1ns   //单位时间为1ns,时间精度1ns

`include "stddef.h"
`include "bus_arbiter.h"
`include "global_config.h"

module bus_arbiter_test;   

   reg       clk;
   reg       reset;
	
	reg       m0_req_;     //0号总线主控_请求总线
	wire      m0_grnt_;    //0号总线主控_赋予总线
	
	reg       m1_req_;
	wire      m1_grnt_;
	
	reg       m2_req_;
	wire      m2_grnt_;
	
	reg       m3_req_;
	wire      m3_grnt_;
	reg         owner;
	

	
parameter      STEP = 100.0000;  //10MHZ_100ns

  	/******生成时钟******/
	always #(STEP/2)begin 
	  clk <= ~clk;
	end
	
	/******实例化bus_arbiter该模块******/
   bus_arbiter bus_arbiter(
	.clk         (clk),
	.reset     (reset),
	.m0_req_   (m0_req_),
	.m1_req_   (m1_req_),
    .m2_req_   (m2_req_),
    .m3_req_   (m3_req_),

    .m0_grnt_  (m0_grnt_),
	.m1_grnt_  (m1_grnt_),
	.m2_grnt_  (m2_grnt_),
    .m3_grnt_  (m3_grnt_)
   );
	

/******测试用例******/
initial begin   //初始化信号
     #0 begin
	  clk <= `HIGH;
	  reset <= `RESET_ENABLE;  //在0时刻复位一下
	  m0_req_ <= `DISABLE_;
	  m1_req_ <= `DISABLE_;
      m2_req_ <= `DISABLE_;
      m3_req_ <= `DISABLE_; 
		//	owner   <= `BUS_OWNER_MASTER_0;  //复位开始后,默认开始为0号主控
	  end  
	  
	   # (STEP*3/4)
		# STEP begin
		  reset <= `RESET_DISABLE;  //解除复位
		end 
		
		$display( "Test start!");  //测试开始
		# STEP begin
		m0_req_ <= `ENABLE_;    //0号总线主控_请求总线使用权
		end 
			
		# STEP begin
		m0_req_ <= `DISABLE_;   //0号总线主控_释放总线使用权
		m1_req_ <= `ENABLE_;    //1号总线主控_请求总线使用权
		end 
			
		# STEP begin
		m1_req_ <= `DISABLE_;   //1号总线主控_释放总线使用权
		m2_req_ <= `ENABLE_;    //2号总线主控_请求总线使用权
	   end
			
		# STEP begin
		m2_req_ <= `DISABLE_;   //2号总线主控_释放总线使用权
		m3_req_ <= `ENABLE_;    //3号总线主控_请求总线使用权
		end 
		
		# STEP begin
		m3_req_  <= `DISABLE_; //3号总线主控_释放总线使用权
		m0_req_  <= `ENABLE_;  //0号总线主控_请求总线使用权
		end 

# STEP begin
		    $finish;   //结束仿真
		end 
	  
end

	/******输出波形文件******/
initial begin
  $dumpfile("bus_arbiter.vcd");	//将波形输出到test.vcd文件
  $dumpvars(0 , bus_arbiter);   //从时刻0开始输出模块bus_arbiter的波形
end 

endmodule
	

可以学一下Icarus Verilog + GTKWave–>http://iverilog.icarus.com/开源轻量型工具,建议是以视频为主来学习。

(三)程序说明
$display( "Test start!");  //测试开始

$display作用相当于C语言中的打印函数printf

 $dumpfile("bus_arbiter.vcd");	//将波形输出到test.vcd文件
 $dumpvars(0 , bus_arbiter);   //从时刻0开始输出模块bus_arbiter的波形

$dumpfile 和 $dumpvars叫做系统任务(现阶段会用就行),可以将仿真时的信号变化输出到波形文件,我们将用GTKWave这个软件来查看波形,支持的波形格式为vcd格式。

(四)仿真开始

打开window的cmd命令窗口,cd切换到该工程文件所在目录(我的:F:\fpga_code\03_bus_arbiter)。


1.仿真文件

iverilog -s bus_arbiter_test -o bus_arbiter_test.out bus_arbiter_test.v bus_arbiter.v
vvp bus_arbiter_test.out

2.GTKWave查看波形

gtkwave bus_arbiter.vcd


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/662134.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-18
下一篇 2022-04-18

发表评论

登录后才能评论

评论列表(0条)

保存