Skip to content

Commit

Permalink
Merge pull request rouge-ruby#317 from Razer6/verilog-lexer
Browse files Browse the repository at this point in the history
Implement Verilog and SystemVerilog lexer
  • Loading branch information
jneen committed Jun 3, 2016
2 parents 1958cea + 321fe8b commit 7e9dd9b
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/rouge/demos/verilog
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Verilog Lexer
*/
module Foo(
input logic Clk_CI,
input logic Rst_RBI,
input logic A,
input logic B,
output logic C
);
logic C_DN, C_DP;

assign C = C_DP;

always_comb begin : proc_next_state
C_DN = A + B;
end

// Clocked process
always_ff @(posedge Clk_CI, negedge Rst_RBI) begin
if(~Rst_RBI) begin
C_DP <= 1'b0;
end else begin
C_DP <= C_DN;
end
end
endmodule
164 changes: 164 additions & 0 deletions lib/rouge/lexers/verilog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# -*- coding: utf-8 -*- #

module Rouge
module Lexers
class Verilog < RegexLexer
title "Verilog and System Verilog"
desc "The System Verilog hardware description language"
tag 'verilog'
filenames '*.v', '*.sv', '*.svh'
mimetypes 'text/x-verilog', 'text/x-systemverilog'

# optional comment or whitespace
ws = %r((?:\s|//.*?\n|/[*].*?[*]/)+)
id = /[a-zA-Z_][a-zA-Z0-9_]*/

def self.keywords
@keywords ||= Set.new %w(
alias always always_comb always_ff always_latch assert assert_strobe
assign assume automatic attribute before begin bind bins binsof break
case casex casez clocking config constraint context continue cover
covergroup coverpoint cross deassign defparam default design dist do
else end endattribute endcase endclass endclocking endconfig
endfunction endgenerate endgroup endinterface endmodule endpackage
endprimitive endprogram endproperty endspecify endsequence endtable
endtask expect export extends extern final first_match for force
foreach fork forkjoin forever function generate genvar if iff ifnone
ignore_bins illegal_bins import incdir include initial inside instance
interface intersect join join_any join_none liblist library local
localparam matches module modport new noshowcancelled null package
parameter primitive priority program property protected
pulsestyle_onevent pulsestyle_ondetect pure rand randc randcase
randsequence release return sequence showcancelled solve specify super
table task this throughout timeprecision timeunit type typedef unique
use wait wait_order while wildcard with within
)
end

def self.keywords_type
@keywords_type ||= Set.new %w(
and bit buf bufif0 bufif1 byte cell chandle class cmos const disable
edge enum event highz0 highz1 initial inout input int integer join
logic longint macromodule medium nand negedge nmos nor not
notif0 notif1 or output packed parameter pmos posedge pull0 pull1
pulldown pullup rcmos real realtime ref reg repeat rnmos rpmos rtran
rtranif0 rtranif1 scalared shortint shortreal signed specparam
static string strength strong0 strong1 struct supply0 supply1 tagged
time tran tranif0 tranif1 tri tri0 tri1 triand trior trireg union
unsigned uwire var vectored virtual void wait wand weak[01] wire wor
xnor xor
)
end

def self.keywords_system_task
@keyword_system_task ||= Set.new %w(
acos acosh asin asinh assertfailoff assertfailon assertkill
assertnonvacuouson assertoff asserton assertpassoff assertpasson
assertvacuousoff atan atan2 atanh bits bitstoreal bitstoshortreal
cast ceil changed changed_gclk changing_gclk clog2 cos cosh countones
coverage_control coverage_get coverage_get_max coverage_merge
coverage_save dimensions display displayb displayh displayo
dist_chi_square dist_erlang dist_exponential dist_normal dist_poisson
dist_t dist_uniform dumpall dumpfile dumpflush dumplimit dumpoff
dumpon dumpports dumpportsall dumpportsflush dumpportslimit
dumpportsoff dumpportson dumpvars error exit exp falling_gclk fclose
fdisplay fdisplayb fdisplayh fdisplayo fell fell_gclk feof ferror
fflush fgetc fgets finish floor fmonitor fmonitorb fmonitorh fmonitoro
fopen fread fscanf fseek fstrobe fstrobeb fstrobeh fstrobeo ftell
future_gclk fwrite fwriteb fwriteh fwriteo get_coverage high hypot
increment info isunbounded isunknown itor left ln load_coverage_db
log10 low monitor monitorb monitorh monitoro monitoroff monitoron
onehot onehot0 past past_gclk pow printtimescale q_add q_exam q_full
q_initialize q_remove random readmemb readmemh realtime realtobits
rewind right rising_gclk rose rose_gclk rtoi sampled
set_coverage_db_name sformat sformatf shortrealtobits signed sin sinh
size sqrt sscanf stable stable_gclk steady_gclk stime stop strobe
strobeb strobeh strobeo swrite swriteb swriteh swriteo system tan tanh
time timeformat typename ungetc unpacked_dimensions unsigned warning
write writeb writeh writememb writememh writeo
)
end

state :expr_bol do
mixin :inline_whitespace
rule /`define/, Comment::Preproc, :macro

rule(//) { pop! }
end

# :expr_bol is the same as :bol but without labels, since
# labels can only appear at the beginning of a statement.
state :bol do
rule /#{id}:(?!:)/, Name::Label
mixin :expr_bol
end

state :inline_whitespace do
rule /[ \t\r]+/, Text
rule /\\\n/, Text # line continuation
rule %r(/(\\\n)?[*].*?[*](\\\n)?/)m, Comment::Multiline
end

state :whitespace do
rule /\n+/m, Text, :bol
rule %r(//(\\.|.)*?\n), Comment::Single, :bol
mixin :inline_whitespace
end

state :expr_whitespace do
rule /\n+/m, Text, :expr_bol
mixin :whitespace
end

state :string do
rule /"/, Str, :pop!
rule /\\([\\abfnrtv"']|x[a-fA-F0-9]{2,4}|[0-7]{1,3})/, Str::Escape
rule /[^\\"\n]+/, Str
rule /\\\n/, Str
rule /\\/, Str # stray backslash
end

state :statement do
mixin :whitespace
rule /L?"/, Str, :string
rule /(\d+\.\d*|\d*\.\d+)(e[+-]?[0-9]+)?/i, Num::Float
rule /\d+e[+-]?[0-9]+/i, Num::Float
rule /[0-9]*'h[0-9a-fA-F]+/, Num::Hex
rule /[0-9]*'b?[01xz]+/, Num::Bin
rule /[0-9]*'d[0-9]+/, Num::Integer
rule /\d+[lu]*/i, Num::Integer
rule %r([~!%^&*+-=\|?:<>/@{}]), Operator
rule /[()\[\],.$\#]/, Punctuation
rule /`(\w+)/, Comment::Preproc

rule id do |m|
name = m[0]

if self.class.keywords.include? name
token Keyword
elsif self.class.keywords_type.include? name
token Keyword::Type
elsif self.class.keywords_system_task.include? name
token Name::Builtin
else
token Name
end
end
end

state :root do
mixin :expr_whitespace
rule(//) { push :statement }
end

state :macro do
rule /\n/, Comment::Preproc, :pop!
mixin :inline_whitespace
rule /;/, Punctuation
rule /\=/, Operator
rule /(\w+)/, Text
end

end
end
end
20 changes: 20 additions & 0 deletions spec/lexers/verilog_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*- #

describe Rouge::Lexers::Verilog do
let(:subject) { Rouge::Lexers::Verilog.new }

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'foo.v'
assert_guess :filename => 'foo.sv'
assert_guess :filename => 'foo.svh'
end

it 'guesses by mimetype' do
assert_guess :mimetype => 'text/x-verilog'
assert_guess :mimetype => 'text/x-systemverilog'
end
end
end
170 changes: 170 additions & 0 deletions spec/visual/samples/verilog
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/**
* Verilog Lexer
*/
class C #(parameter int N = 1) extends BaseClass;
int x;
protected int data;

constraint cq { message.data inside {[0:8]}; }

task set (int i);
x = i;
endtask

function int get;
return x;
endfunction

endclass

/*
Register module
*/
class Register #(parameter type T = int);
T data;
endclass

virtual class Register;
endclass

typedef struct {
rand bit [10:0] ID; // 11-bit identifier
bit [1:0] rsvd; // "reserved for expansion" bits
rand byte data[]; // data payload
} message_t;

class CAN_Message;
rand message_t message;

task getbits(ref bit data_o, input int delay=1);
bit [17:0] header;
bit [14:0] tail;
header = {message.ID,message.RTR,message.rsvd,message.DLC};
tail = message.CRC;
$display("tail=%0b",tail);
//step through message and output each bit (from left to right)
foreach(header[i]) #delay data_o = header[i];
foreach(message.data[i,j]) #delay data_o = message.data[i][j];
foreach(tail[i]) #delay data_o = tail[i];
endtask
endclass

enum {Red, Green, Blue} Colour;

covergroup cg_Colour @(posedge Clock);
coverpoint Colour;
endgroup

cg_Colour = new cg_inst;

covergroup cg_Short @(posedge Clock);
coverpoint i {
bins zero = { 0 };
bins small = { [1:100] };
bins hunds[3] = { 200,300,400,500,600,700,800,900 };
bins large = { [1000:$] };
bins others[] = default;
};
endgroup

module Bus(input In1, output Out1);
import "DPI" function void slave_write(input int address,
input int data);
export "DPI" function write; // Note – not a function prototype

// This SystemVerilog function could be called from C
function void write(int address, int data);
// Call C function
slave_write(address, data); // Arguments passed by copy
endfunction
...
endmodule

// Verilog code for AND-OR-INVERT gate
module AOI (input A, B, C, D, output F);
assign F = ~((A & B) | (C & D));
reg f;
always @(sel or a or b)
reg f, g; // a new reg variable, g
always @(sel or a or b)
begin
if (sel == 1)
begin
f = a;
g = ~a;
end
else
begin
f = b;
g = a & b;
end

casez(A)
4'b1???: Y<=4'b1000;
4'b01??: Y<=4'b0100;
4'b001?: Y<=4'b0010;
4'b0001: Y<=4'b0001;
default: Y<=4'b0000;
endcase

for (i = 0; i < 16; i = i +1) begin
$display ("Current value of i is %d", i);
end

repeat (16) begin
$display ("Current value of i is %d", i);
i = i + 1;
end
end

parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
temp <= '0; // fill with 0
end
end

parameter ROWBITS = 4;
reg [ROWBITS-1:0] temp;
always @(posedge sysclk) begin
for (integer c=0; c<ROWBITS; c=c+1) begin: test
temp[c] <= 1'b0;
end
end

genvar index;
generate
for (index=0; index < 8; index=index+1)
begin: gen_code_label
BUFR BUFR_inst (
.O(clk_o(index)), // Clock buffer ouptput
.CE(ce), // Clock enable input
.CLR(clear), // Clock buffer reset input
.I(clk_i(index)) // Clock buffer input
);
end
endgenerate

always_latch begin
if (enable) begin
a_latch = something;
end
//No else clause so a_latch's value
//is not always defined, so it holds its value
end

always @* begin
if (enable) begin
a_latch = something;
end
//No else clause so a_latch's value
//is not always defined, so it holds its value
end

always_ff @(posedge clk) begin
a <= b;
end

endmodule
// end of Verilog code
//

0 comments on commit 7e9dd9b

Please sign in to comment.