`include "timescale.v"
|
`include "timescale.v"
|
`include "gpio_defines.v"
|
`include "gpio_defines.v"
|
|
|
// -*- Mode: Verilog -*-
|
// -*- Mode: Verilog -*-
|
// Filename : wb_master.v
|
// Filename : wb_master.v
|
// Description : Wishbone Master Behavorial
|
// Description : Wishbone Master Behavorial
|
// Author : Winefred Washington
|
// Author : Winefred Washington
|
// Created On : Thu Jan 11 21:18:41 2001
|
// Created On : Thu Jan 11 21:18:41 2001
|
// Last Modified By: .
|
// Last Modified By: .
|
// Last Modified On: .
|
// Last Modified On: .
|
// Update Count : 0
|
// Update Count : 0
|
// Status : Unknown, Use with caution!
|
// Status : Unknown, Use with caution!
|
|
|
// Description Specification
|
// Description Specification
|
// General Description: 8, 16, 32-bit WISHBONE Master
|
// General Description: 8, 16, 32-bit WISHBONE Master
|
// Supported cycles: MASTER, READ/WRITE
|
// Supported cycles: MASTER, READ/WRITE
|
// MASTER, BLOCK READ/WRITE
|
// MASTER, BLOCK READ/WRITE
|
// MASTER, RMW
|
// MASTER, RMW
|
// Data port, size: 8, 16, 32-bit
|
// Data port, size: 8, 16, 32-bit
|
// Data port, granularity 8-bit
|
// Data port, granularity 8-bit
|
// Data port, Max. operand size 32-bit
|
// Data port, Max. operand size 32-bit
|
// Data transfer ordering: little endian
|
// Data transfer ordering: little endian
|
// Data transfer sequencing: undefined
|
// Data transfer sequencing: undefined
|
//
|
//
|
|
|
module wb_master(CLK_I, RST_I, TAG_I, TAG_O,
|
module wb_master(CLK_I, RST_I, TAG_I, TAG_O,
|
ACK_I, ADR_O, CYC_O, DAT_I, DAT_O, ERR_I, RTY_I, SEL_O, STB_O, WE_O);
|
ACK_I, ADR_O, CYC_O, DAT_I, DAT_O, ERR_I, RTY_I, SEL_O, STB_O, WE_O);
|
|
|
parameter aw = `GPIO_ADDRHH+1 ;
|
parameter aw = `GPIO_ADDRHH+1 ;
|
input CLK_I;
|
input CLK_I;
|
input RST_I;
|
input RST_I;
|
input [3:0] TAG_I;
|
input [3:0] TAG_I;
|
output [3:0] TAG_O;
|
output [3:0] TAG_O;
|
input ACK_I;
|
input ACK_I;
|
output [aw-1:0] ADR_O;
|
output [aw-1:0] ADR_O;
|
output CYC_O;
|
output CYC_O;
|
input [31:0] DAT_I;
|
input [31:0] DAT_I;
|
output [31:0] DAT_O;
|
output [31:0] DAT_O;
|
input ERR_I;
|
input ERR_I;
|
input RTY_I;
|
input RTY_I;
|
output [3:0] SEL_O;
|
output [3:0] SEL_O;
|
output STB_O;
|
output STB_O;
|
output WE_O;
|
output WE_O;
|
|
|
reg [aw-1:0] ADR_O;
|
reg [aw-1:0] ADR_O;
|
reg [3:0] SEL_O;
|
reg [3:0] SEL_O;
|
reg CYC_O;
|
reg CYC_O;
|
reg STB_O;
|
reg STB_O;
|
reg WE_O;
|
reg WE_O;
|
reg [31:0] DAT_O;
|
reg [31:0] DAT_O;
|
|
|
wire [15:0] mem_sizes; // determines the data width of an address range
|
wire [15:0] mem_sizes; // determines the data width of an address range
|
reg [31:0] write_burst_buffer[0:7];
|
reg [31:0] write_burst_buffer[0:7];
|
reg [31:0] read_burst_buffer[0:7];
|
reg [31:0] read_burst_buffer[0:7];
|
|
|
reg GO;
|
reg GO;
|
integer cycle_end;
|
integer cycle_end;
|
integer address;
|
integer address;
|
integer data;
|
integer data;
|
integer selects;
|
integer selects;
|
integer write_flag;
|
integer write_flag;
|
|
|
//
|
//
|
// mem_sizes determines the data widths of memory space
|
// mem_sizes determines the data widths of memory space
|
// The memory space is divided into eight regions. Each
|
// The memory space is divided into eight regions. Each
|
// region is controlled by a two bit field.
|
// region is controlled by a two bit field.
|
//
|
//
|
// Bits
|
// Bits
|
// 00 = 8 bit memory space
|
// 00 = 8 bit memory space
|
// 01 = 16 bit
|
// 01 = 16 bit
|
// 10 = 32 bit
|
// 10 = 32 bit
|
// 11 = 64 bit (not supported in this model
|
// 11 = 64 bit (not supported in this model
|
//
|
//
|
|
|
assign mem_sizes = 16'b10_01_10_11_00_01_10_11;
|
assign mem_sizes = 16'b10_01_10_11_00_01_10_11;
|
|
|
function [1:0] data_width;
|
function [1:0] data_width;
|
input [31:0] adr;
|
input [31:0] adr;
|
begin
|
begin
|
casex (adr[31:29])
|
casex (adr[31:29])
|
3'b000: data_width = mem_sizes[15:14];
|
3'b000: data_width = mem_sizes[15:14];
|
3'b001: data_width = mem_sizes[13:12];
|
3'b001: data_width = mem_sizes[13:12];
|
3'b010: data_width = mem_sizes[11:10];
|
3'b010: data_width = mem_sizes[11:10];
|
3'b011: data_width = mem_sizes[9:8];
|
3'b011: data_width = mem_sizes[9:8];
|
3'b100: data_width = mem_sizes[7:6];
|
3'b100: data_width = mem_sizes[7:6];
|
3'b101: data_width = mem_sizes[5:4];
|
3'b101: data_width = mem_sizes[5:4];
|
3'b110: data_width = mem_sizes[3:2];
|
3'b110: data_width = mem_sizes[3:2];
|
3'b111: data_width = mem_sizes[1:0];
|
3'b111: data_width = mem_sizes[1:0];
|
3'bxxx: data_width = 2'bxx;
|
3'bxxx: data_width = 2'bxx;
|
endcase // casex (adr[31:29])
|
endcase // casex (adr[31:29])
|
end
|
end
|
endfunction
|
endfunction
|
|
|
always @(posedge CLK_I or posedge RST_I)
|
always @(posedge CLK_I or posedge RST_I)
|
begin
|
begin
|
if (RST_I)
|
if (RST_I)
|
begin
|
begin
|
GO = 1'b0;
|
GO = 1'b0;
|
end
|
end
|
end
|
end
|
|
|
// read single
|
// read single
|
task rd;
|
task rd;
|
input [31:0] adr;
|
input [31:0] adr;
|
output [31:0] result;
|
output [31:0] result;
|
|
|
begin
|
begin
|
cycle_end = 1;
|
cycle_end = 1;
|
address = adr;
|
address = adr;
|
selects = 255;
|
selects = 255;
|
write_flag = 0;
|
write_flag = 0;
|
|
|
GO <= 1;
|
GO <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
// wait for cycle to start
|
// wait for cycle to start
|
while (~CYC_O)
|
while (~CYC_O)
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
// wait for cycle to end
|
// wait for cycle to end
|
while (CYC_O)
|
while (CYC_O)
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
result = data;
|
result = data;
|
// $display(" Reading %h from address %h", result, address);
|
// $display(" Reading %h from address %h", result, address);
|
|
|
end
|
end
|
endtask // read
|
endtask // read
|
|
|
task wr;
|
task wr;
|
input [31:0] adr;
|
input [31:0] adr;
|
input [31:0] dat;
|
input [31:0] dat;
|
input [3:0] sel;
|
input [3:0] sel;
|
begin
|
begin
|
cycle_end = 1;
|
cycle_end = 1;
|
address = adr;
|
address = adr;
|
selects = sel;
|
selects = sel;
|
write_flag = 1;
|
write_flag = 1;
|
data = dat;
|
data = dat;
|
|
|
GO <= 1;
|
GO <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
// wait for cycle to start
|
// wait for cycle to start
|
while (~CYC_O)
|
while (~CYC_O)
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
// wait for cycle to end
|
// wait for cycle to end
|
while (CYC_O)
|
while (CYC_O)
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// $display(" Writing %h to address %h", data, address);
|
// $display(" Writing %h to address %h", data, address);
|
|
|
end
|
end
|
endtask // wr
|
endtask // wr
|
|
|
// block read
|
// block read
|
task blkrd;
|
task blkrd;
|
input [31:0] adr;
|
input [31:0] adr;
|
input end_flag;
|
input end_flag;
|
output [31:0] result;
|
output [31:0] result;
|
|
|
begin
|
begin
|
write_flag = 0;
|
write_flag = 0;
|
cycle_end = end_flag;
|
cycle_end = end_flag;
|
address = adr;
|
address = adr;
|
GO <= 1;
|
GO <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
while (~(ACK_I & STB_O))
|
while (~(ACK_I & STB_O))
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
result = data;
|
result = data;
|
end
|
end
|
endtask // blkrd
|
endtask // blkrd
|
|
|
// block write
|
// block write
|
task blkwr;
|
task blkwr;
|
input [31:0] adr;
|
input [31:0] adr;
|
input [31:0] dat;
|
input [31:0] dat;
|
input [3:0] sel;
|
input [3:0] sel;
|
input end_flag;
|
input end_flag;
|
begin
|
begin
|
write_flag = 1;
|
write_flag = 1;
|
cycle_end = end_flag;
|
cycle_end = end_flag;
|
address = adr;
|
address = adr;
|
data = dat;
|
data = dat;
|
selects = sel;
|
selects = sel;
|
GO <= 1;
|
GO <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
while (~(ACK_I & STB_O))
|
while (~(ACK_I & STB_O))
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
end
|
end
|
endtask // blkwr
|
endtask // blkwr
|
|
|
// RMW
|
// RMW
|
task rmw;
|
task rmw;
|
input [31:0] adr;
|
input [31:0] adr;
|
input [31:0] dat;
|
input [31:0] dat;
|
input [3:0] sel;
|
input [3:0] sel;
|
output [31:0] result;
|
output [31:0] result;
|
|
|
begin
|
begin
|
// read phase
|
// read phase
|
write_flag = 0;
|
write_flag = 0;
|
cycle_end = 0;
|
cycle_end = 0;
|
address = adr;
|
address = adr;
|
GO <= 1;
|
GO <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
while (~(ACK_I & STB_O))
|
while (~(ACK_I & STB_O))
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
result = data;
|
result = data;
|
|
|
// write phase
|
// write phase
|
write_flag = 1;
|
write_flag = 1;
|
address = adr;
|
address = adr;
|
selects = sel;
|
selects = sel;
|
GO <= 1;
|
GO <= 1;
|
data <= dat;
|
data <= dat;
|
cycle_end <= 1;
|
cycle_end <= 1;
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
// GO <= 0;
|
// GO <= 0;
|
|
|
while (~(ACK_I & STB_O))
|
while (~(ACK_I & STB_O))
|
@(posedge CLK_I);
|
@(posedge CLK_I);
|
|
|
end
|
end
|
endtask // rmw
|
endtask // rmw
|
|
|
always @(posedge CLK_I)
|
always @(posedge CLK_I)
|
begin
|
begin
|
if (RST_I)
|
if (RST_I)
|
ADR_O <= 32'h0000_0000;
|
ADR_O <= 32'h0000_0000;
|
else
|
else
|
ADR_O <= address;
|
ADR_O <= address;
|
end
|
end
|
|
|
always @(posedge CLK_I)
|
always @(posedge CLK_I)
|
begin
|
begin
|
if (RST_I | ERR_I | RTY_I)
|
if (RST_I | ERR_I | RTY_I)
|
CYC_O <= 1'b0;
|
CYC_O <= 1'b0;
|
else if ((cycle_end == 1) & ACK_I)
|
else if ((cycle_end == 1) & ACK_I)
|
CYC_O <= 1'b0;
|
CYC_O <= 1'b0;
|
else if (GO | CYC_O) begin
|
else if (GO | CYC_O) begin
|
CYC_O <= 1'b1;
|
CYC_O <= 1'b1;
|
GO <= 1'b0;
|
GO <= 1'b0;
|
end
|
end
|
end
|
end
|
|
|
// stb control
|
// stb control
|
always @(posedge CLK_I)
|
always @(posedge CLK_I)
|
begin
|
begin
|
if (RST_I | ERR_I | RTY_I)
|
if (RST_I | ERR_I | RTY_I)
|
STB_O <= 1'b0;
|
STB_O <= 1'b0;
|
else if (STB_O & ACK_I)
|
else if (STB_O & ACK_I)
|
STB_O <= 1'b0;
|
STB_O <= 1'b0;
|
else if (GO | STB_O)
|
else if (GO | STB_O)
|
STB_O <= 1'b1;
|
STB_O <= 1'b1;
|
end
|
end
|
|
|
// selects & data
|
// selects & data
|
always @(posedge CLK_I)
|
always @(posedge CLK_I)
|
begin
|
begin
|
if (write_flag == 0) begin
|
if (write_flag == 0) begin
|
SEL_O <= 4'b1111;
|
SEL_O <= 4'b1111;
|
if (STB_O & ACK_I)
|
if (STB_O & ACK_I)
|
data <= DAT_I;
|
data <= DAT_I;
|
end
|
end
|
else begin
|
else begin
|
case (data_width(address))
|
case (data_width(address))
|
2'b00: begin
|
2'b00: begin
|
SEL_O <= {3'b000, selects[0]};
|
SEL_O <= {3'b000, selects[0]};
|
DAT_O <= {data[7:0], data[7:0], data[7:0], data[7:0]};
|
DAT_O <= {data[7:0], data[7:0], data[7:0], data[7:0]};
|
end
|
end
|
2'b01: begin
|
2'b01: begin
|
SEL_O <= {2'b00, selects[1:0]};
|
SEL_O <= {2'b00, selects[1:0]};
|
DAT_O <= {data[15:0], data[15:0]};
|
DAT_O <= {data[15:0], data[15:0]};
|
end
|
end
|
2'b10: begin
|
2'b10: begin
|
SEL_O <= selects;
|
SEL_O <= selects;
|
DAT_O <= data;
|
DAT_O <= data;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
always @(posedge CLK_I)
|
always @(posedge CLK_I)
|
begin
|
begin
|
if (RST_I)
|
if (RST_I)
|
WE_O <= 1'b0;
|
WE_O <= 1'b0;
|
else if (GO)
|
else if (GO)
|
WE_O <= write_flag;
|
WE_O <= write_flag;
|
end
|
end
|
|
|
endmodule
|
endmodule
|
|
|
|
|
|
|
|
|
|
|
|
|