mirror of
https://github.com/supleed2/ELEC70056-HSV-CW2.git
synced 2024-12-22 21:55:48 +00:00
Add VGA and GPIO checker
This commit is contained in:
parent
f9bd753cde
commit
f586cd95d9
67
rtl/AHB_GPIO/ahb_gpio_checker.sv
Normal file
67
rtl/AHB_GPIO/ahb_gpio_checker.sv
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
module ahb_gpio_checker
|
||||||
|
( input wire HCLK
|
||||||
|
, input wire HRESETn
|
||||||
|
, input wire [31:0] HADDR
|
||||||
|
, input wire [ 1:0] HTRANS
|
||||||
|
, input wire [31:0] HWDATA
|
||||||
|
, input wire HWRITE
|
||||||
|
, input wire HSEL
|
||||||
|
, input wire HREADY
|
||||||
|
, input wire [16:0] GPIOIN
|
||||||
|
, input wire PARITYSEL
|
||||||
|
, input wire INJECT_FAULT
|
||||||
|
, input wire HREADYOUT
|
||||||
|
, input wire [31:0] HRDATA
|
||||||
|
, input wire [16:0] GPIOOUT
|
||||||
|
, input wire PARITYERR
|
||||||
|
);
|
||||||
|
|
||||||
|
logic gpio_cmd = HSEL && HREADY && HTRANS[1];
|
||||||
|
logic gpio_dir;
|
||||||
|
localparam [7:0] gpio_data_addr = 8'h00;
|
||||||
|
localparam [7:0] gpio_dir_addr = 8'h04;
|
||||||
|
|
||||||
|
// defined properties
|
||||||
|
|
||||||
|
property gpio_write;
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
(HADDR[7:0] == gpio_data_addr) && gpio_cmd
|
||||||
|
##1
|
||||||
|
(gpio_dir=='1)
|
||||||
|
##1
|
||||||
|
(GPIOOUT[15:0] == $past(HWDATA,1));
|
||||||
|
endproperty
|
||||||
|
|
||||||
|
property gpio_read;
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
(HADDR[7:0] == gpio_data_addr) && gpio_cmd
|
||||||
|
&& (gpio_dir=='0)
|
||||||
|
##1
|
||||||
|
((HRDATA[15:0]==$past(GPIOIN[15:0],1)) && HREADYOUT);
|
||||||
|
endproperty
|
||||||
|
|
||||||
|
always_ff @(posedge HCLK)
|
||||||
|
begin
|
||||||
|
if(!HRESETn)
|
||||||
|
begin
|
||||||
|
gpio_dir <= '0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if($past((gpio_cmd && (HADDR == gpio_dir_addr)),1))
|
||||||
|
begin
|
||||||
|
gpio_dir <= HWDATA;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// check behaviour
|
||||||
|
assert_parity: assert property
|
||||||
|
( @(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
!PARITYERR
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_gpio_write: assert property (gpio_write);
|
||||||
|
assert_gpio_read: assert property (gpio_read);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -18,6 +18,6 @@ module VGACOMPARATOR
|
||||||
&& HSYNC1 == HSYNC2
|
&& HSYNC1 == HSYNC2
|
||||||
&& VSYNC1 == VSYNC2
|
&& VSYNC1 == VSYNC2
|
||||||
&& RGB1 == RGB2
|
&& RGB1 == RGB2
|
||||||
)
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
165
rtl/AHB_VGA/ahb_vgasys_checker.sv
Normal file
165
rtl/AHB_VGA/ahb_vgasys_checker.sv
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
module ahb_vgasys_checker(
|
||||||
|
input wire HCLK,
|
||||||
|
input wire HRESETn,
|
||||||
|
input wire [31:0] HADDR,
|
||||||
|
input wire [31:0] HWDATA,
|
||||||
|
input wire HREADY,
|
||||||
|
input wire HWRITE,
|
||||||
|
input wire [1:0] HTRANS,
|
||||||
|
input wire HSEL,
|
||||||
|
input wire [31:0] HRDATA,
|
||||||
|
input wire HREADYOUT,
|
||||||
|
input wire HSYNC,
|
||||||
|
input wire VSYNC,
|
||||||
|
input wire [7:0] RGB,
|
||||||
|
output wire [7:0] checker_rgb_out
|
||||||
|
);
|
||||||
|
import ahb_vga_font_map::*;
|
||||||
|
// NOTE: Due to a BUG in the VGA module, the first 2 pixels for each row in the visible region is invalid, the actual image starts 2 cycles later
|
||||||
|
localparam text_region_x_min = 48 + 2;
|
||||||
|
localparam text_region_x_max = text_region_x_min + 240 - 2;
|
||||||
|
localparam text_region_y_min = 29;
|
||||||
|
localparam text_region_y_max = text_region_y_min + 480;
|
||||||
|
localparam character_width = 8;
|
||||||
|
localparam character_height = 16;
|
||||||
|
localparam characters_per_row = 240/character_width;
|
||||||
|
localparam characters_per_col = 480/character_height;
|
||||||
|
|
||||||
|
logic [31:0] counter;
|
||||||
|
logic countup;
|
||||||
|
int pixel_x;
|
||||||
|
int pixel_y;
|
||||||
|
//local coords within the visible text region
|
||||||
|
int frame_x;
|
||||||
|
int frame_y;
|
||||||
|
//local coords within the tile
|
||||||
|
logic [2:0] character_x;
|
||||||
|
logic [3:0] character_y;
|
||||||
|
|
||||||
|
logic [7:0] checker_rgb;
|
||||||
|
logic [7:0] character_buffer[characters_per_row*characters_per_col];
|
||||||
|
string console_text_reg;
|
||||||
|
|
||||||
|
int hcounter;
|
||||||
|
int vcounter;
|
||||||
|
|
||||||
|
|
||||||
|
function logic inTextRegion(int x, int y);
|
||||||
|
return (x >= text_region_x_min && x <= text_region_x_max) && (y >= text_region_y_min && y <= text_region_y_max);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function int getStringIndex(int x, int y);
|
||||||
|
return (((y/character_height)*characters_per_row)+ (x/character_width));
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function logic[7:0] getRGBvalue(logic[2:0] x, logic[3:0] y, int char_index);
|
||||||
|
return font_lookup({char_index, y})[7-x] ? 8'h1c : 8'h00;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
always_ff @(posedge HCLK)
|
||||||
|
begin
|
||||||
|
if(!HRESETn || !VSYNC)
|
||||||
|
begin
|
||||||
|
pixel_x <= 0;
|
||||||
|
pixel_y <= 0;
|
||||||
|
console_text_reg <= "";
|
||||||
|
counter <= 0;
|
||||||
|
countup <= 0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
countup <= countup + 1;
|
||||||
|
if($past(HSEL && HREADY && HWRITE && (HADDR[23:0]== 12'h000000000000),1) && HREADYOUT)
|
||||||
|
begin
|
||||||
|
console_text_reg <= {console_text_reg,font_map[HWDATA]};
|
||||||
|
character_buffer[counter] <= HWDATA[7:0];
|
||||||
|
counter <= counter+1;
|
||||||
|
end
|
||||||
|
if($fell(vgaif.HSYNC))
|
||||||
|
begin
|
||||||
|
pixel_x <= 0;
|
||||||
|
pixel_y <= pixel_y + 1;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if(vgaif.HSYNC)
|
||||||
|
if(countup)
|
||||||
|
begin
|
||||||
|
pixel_x <= pixel_x + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge HCLK)
|
||||||
|
begin
|
||||||
|
if(!HRESETn)
|
||||||
|
begin
|
||||||
|
hcounter <= 0;
|
||||||
|
vcounter <= 0;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if($fell(VSYNC))
|
||||||
|
vcounter <= 0;
|
||||||
|
else
|
||||||
|
if($fell(HSYNC))
|
||||||
|
vcounter <= vcounter + 1;
|
||||||
|
if($fell(HSYNC))
|
||||||
|
hcounter <= 0;
|
||||||
|
else
|
||||||
|
hcounter <= hcounter + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb
|
||||||
|
begin
|
||||||
|
checker_rgb = 0;
|
||||||
|
frame_x = pixel_x - text_region_x_min;
|
||||||
|
frame_y = pixel_y - text_region_y_min;
|
||||||
|
character_x = frame_x % character_width;
|
||||||
|
character_y = frame_y % character_height;
|
||||||
|
if(inTextRegion(pixel_x,pixel_y))
|
||||||
|
begin
|
||||||
|
if(getStringIndex(frame_x,frame_y) < console_text_reg.len())
|
||||||
|
begin
|
||||||
|
checker_rgb = getRGBvalue(character_x,character_y,character_buffer[getStringIndex(frame_x,frame_y)]);
|
||||||
|
//$display("char: %s, x: 0x%0h, y: 0x%0h",console_text_reg.substr(getStringIndex(frame_x,frame_y),getStringIndex(frame_x,frame_y)), frame_x, frame_y);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign checker_rgb_out = checker_rgb;
|
||||||
|
|
||||||
|
//assertions
|
||||||
|
assert_text_region: assert property
|
||||||
|
(
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
(inTextRegion(pixel_x,pixel_y) && (frame_x > 1)) -> (checker_rgb == RGB)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_vsync_pulse_timer: assert property
|
||||||
|
(
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
$rose(VSYNC) -> (($past(vcounter,1) == 8'h1) || (vcounter == '0))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_hsync_pulse_timer: assert property
|
||||||
|
(
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
($rose(HSYNC) && !$rose(VSYNC) && VSYNC) -> ($past(hcounter,1)/2 == 8'd95)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_line_timer: assert property
|
||||||
|
(
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
($fell(HSYNC) && !$rose(VSYNC) && VSYNC) -> ($past(hcounter,1)/2 == 800)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_frame_timer: assert property
|
||||||
|
(
|
||||||
|
@(posedge HCLK) disable iff (!HRESETn)
|
||||||
|
$fell(VSYNC) -> (($past(vcounter,1) == (32'd480 + 32'd10 + 32'd2 + 32'd29)) || (vcounter == '0))
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
2316
tbench/ahb_vga_font_map.sv
Normal file
2316
tbench/ahb_vga_font_map.sv
Normal file
File diff suppressed because it is too large
Load diff
179
tbench/ahb_vga_tb.sv
Normal file
179
tbench/ahb_vga_tb.sv
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
// stub
|
||||||
|
interface ahb_vga_if;
|
||||||
|
|
||||||
|
typedef enum bit[1:0] {
|
||||||
|
IDLE = 2'b00,
|
||||||
|
BUSY = 2'b01,
|
||||||
|
NONSEQUENTIAL = 2'b10,
|
||||||
|
SEQUENTIAL = 2'b11
|
||||||
|
} htrans_types;
|
||||||
|
|
||||||
|
logic HCLK;
|
||||||
|
logic HRESETn;
|
||||||
|
logic [31:0] HADDR;
|
||||||
|
logic [ 1:0] HTRANS;
|
||||||
|
logic [31:0] HWDATA;
|
||||||
|
logic HWRITE;
|
||||||
|
logic HSEL;
|
||||||
|
logic HREADY;
|
||||||
|
logic HREADYOUT;
|
||||||
|
logic [31:0] HRDATA;
|
||||||
|
|
||||||
|
logic [7:0] RGB;
|
||||||
|
logic HSYNC;
|
||||||
|
logic VSYNC;
|
||||||
|
|
||||||
|
|
||||||
|
modport DUT
|
||||||
|
( input HCLK, HRESETn, HADDR, HTRANS, HWDATA, HWRITE, HSEL, HREADY,
|
||||||
|
output HREADYOUT, HRDATA, RGB, HSYNC, VSYNC
|
||||||
|
);
|
||||||
|
|
||||||
|
modport TB
|
||||||
|
( input HCLK, HREADYOUT, HRDATA, RGB, HSYNC, VSYNC,
|
||||||
|
output HRESETn, HREADY, HADDR, HTRANS, HWDATA, HWRITE, HSEL
|
||||||
|
);
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module ahb_vga_tb;
|
||||||
|
import ahb_vga_font_map::*;
|
||||||
|
localparam IMAGEADDR = 4'hA;
|
||||||
|
localparam CONSOLEADDR = 4'h0;
|
||||||
|
|
||||||
|
ahb_vga_if vgaif();
|
||||||
|
AHBVGA vga(
|
||||||
|
.HCLK(vgaif.HCLK),
|
||||||
|
.HRESETn(vgaif.HRESETn),
|
||||||
|
.HADDR(vgaif.HADDR),
|
||||||
|
.HWDATA(vgaif.HWDATA),
|
||||||
|
.HREADY(vgaif.HREADY),
|
||||||
|
.HWRITE(vgaif.HWRITE),
|
||||||
|
.HTRANS(vgaif.HTRANS),
|
||||||
|
.HSEL(vgaif.HSEL),
|
||||||
|
.HRDATA(vgaif.HRDATA),
|
||||||
|
.HREADYOUT(vgaif.HREADYOUT),
|
||||||
|
.HSYNC(vgaif.HSYNC),
|
||||||
|
.VSYNC(vgaif.VSYNC),
|
||||||
|
.RGB(vgaif.RGB)
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [7:0] checker_rgb;
|
||||||
|
ahb_vgasys_checker vga_checker(
|
||||||
|
.HCLK(vgaif.HCLK),
|
||||||
|
.HRESETn(vgaif.HRESETn),
|
||||||
|
.HADDR(vgaif.HADDR),
|
||||||
|
.HWDATA(vgaif.HWDATA),
|
||||||
|
.HREADY(vgaif.HREADY),
|
||||||
|
.HWRITE(vgaif.HWRITE),
|
||||||
|
.HTRANS(vgaif.HTRANS),
|
||||||
|
.HSEL(vgaif.HSEL),
|
||||||
|
.HRDATA(vgaif.HRDATA),
|
||||||
|
.HREADYOUT(vgaif.HREADYOUT),
|
||||||
|
.HSYNC(vgaif.HSYNC),
|
||||||
|
.VSYNC(vgaif.VSYNC),
|
||||||
|
.RGB(vgaif.RGB),
|
||||||
|
.checker_rgb_out(checker_rgb)
|
||||||
|
);
|
||||||
|
|
||||||
|
logic display_enable;
|
||||||
|
|
||||||
|
task deassert_reset();
|
||||||
|
begin
|
||||||
|
vgaif.HRESETn = 0;
|
||||||
|
@(posedge vgaif.HCLK);
|
||||||
|
@(posedge vgaif.HCLK);
|
||||||
|
vgaif.HRESETn = 1;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
initial begin
|
||||||
|
vgaif.HCLK = 0;
|
||||||
|
forever #20 vgaif.HCLK = ! vgaif.HCLK;
|
||||||
|
end
|
||||||
|
|
||||||
|
string line;
|
||||||
|
|
||||||
|
always @(posedge vgaif.HCLK) begin
|
||||||
|
if(display_enable)
|
||||||
|
if ($fell(vgaif.HSYNC)) begin
|
||||||
|
$display(line);
|
||||||
|
line = "";
|
||||||
|
end else if (vgaif.HSYNC)
|
||||||
|
if (checker_rgb == 8'd28)
|
||||||
|
line = {line, "#"};
|
||||||
|
else
|
||||||
|
line = {line, "."};
|
||||||
|
end
|
||||||
|
|
||||||
|
task setChar(input bit [7:0] c);
|
||||||
|
@(posedge vgaif.HCLK);
|
||||||
|
vgaif.HREADY = 1;
|
||||||
|
vgaif.HWRITE = 1;
|
||||||
|
vgaif.HTRANS = 2'b10;
|
||||||
|
vgaif.HSEL = 1;
|
||||||
|
vgaif.HADDR = 32'h50000000;
|
||||||
|
@(posedge(vgaif.HCLK));
|
||||||
|
vgaif.HWDATA = c;
|
||||||
|
vgaif.HWRITE = 0;
|
||||||
|
@(posedge (vgaif.HCLK && vgaif.HREADYOUT));
|
||||||
|
endtask
|
||||||
|
|
||||||
|
class vga_stimulus;
|
||||||
|
rand logic [31:0] HWDATA;
|
||||||
|
|
||||||
|
constraint c_hwdata
|
||||||
|
{0 <= HWDATA; HWDATA <= 8'h7f;}
|
||||||
|
endclass
|
||||||
|
|
||||||
|
vga_stimulus stimulus_vals;
|
||||||
|
|
||||||
|
covergroup cover_vga_chars;
|
||||||
|
cp_hwdata: coverpoint vgaif.HWDATA{
|
||||||
|
bins invalid = {[128:255]};
|
||||||
|
option.auto_bin_max = 128;
|
||||||
|
}
|
||||||
|
endgroup
|
||||||
|
|
||||||
|
|
||||||
|
integer char_index;
|
||||||
|
string test_value = "";
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
cover_vga_chars covvgachars;
|
||||||
|
covvgachars = new();
|
||||||
|
stimulus_vals = new();
|
||||||
|
deassert_reset();
|
||||||
|
display_enable = 0;
|
||||||
|
@(posedge vgaif.VSYNC);
|
||||||
|
display_enable = 1;
|
||||||
|
$display(test_value);
|
||||||
|
for(char_index = 0; char_index < 16; char_index++)
|
||||||
|
begin
|
||||||
|
|
||||||
|
assert (stimulus_vals.randomize) else $fatal;
|
||||||
|
setChar(stimulus_vals.HWDATA);
|
||||||
|
test_value = {test_value, font_map[stimulus_vals.HWDATA]};
|
||||||
|
end
|
||||||
|
setChar(8'h08);
|
||||||
|
// setChar(8'h54);
|
||||||
|
// setChar(8'h45);
|
||||||
|
// setChar(8'h53);
|
||||||
|
// setChar(8'h54);
|
||||||
|
// setChar(8'h21);
|
||||||
|
// setChar(8'h00);
|
||||||
|
vgaif.HREADY = '0;
|
||||||
|
vgaif.HWRITE = '0;
|
||||||
|
vgaif.HTRANS = '0;
|
||||||
|
vgaif.HSEL = '0;
|
||||||
|
vgaif.HADDR = '0;
|
||||||
|
vgaif.HWDATA = '0;
|
||||||
|
@(posedge vgaif.VSYNC);
|
||||||
|
$display(test_value);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
|
||||||
|
logic rgb_active;
|
||||||
|
assign rgb_active = (vgaif.RGB==8'h1c);
|
||||||
|
logic checker_rgb_active;
|
||||||
|
assign checker_rgb_active = (checker_rgb==8'h1c);
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in a new issue