Architecture Verilog An Extended Example: Always @ (Posedge CLK) Begin
Architecture Verilog An Extended Example: Always @ (Posedge CLK) Begin
ILL JT O dr P XA L4 SE PC 3
1 PC
0 00
+4
1> 5:2 : <2 EL Rc 2S RA 1> 5:1 0 1 : <1 D EF Rb WR A2 W > R 6 0:1 WE ter : <2 2 gis Ra RD Re ile L F SE RA1 WA A W WA 1 1 RD JT EL XP:21> BS 5 0 + 0 : <2 Rc 1 Wr Z ) :0> R/W C: (<15 0 WD T ry 1 (C) SX mo XT EL Me 4*S ta AS B Da +4+ Z RD PC U Adr IRQ ic AL og A lL tro on L C N SE UF PC SEL AL 2 RA EL AS L E BS SEL L D WD FN W SE +4 U PC 2 AL r 01 W RF WE EL AS W
09/11/02
Inpu
:0] m t [31
en dm
od ul e
; data em_
If (done) $finish;
HDL description is first step in a mostly automated process to build an implementation directly from the behavioral model
Gate netlist
Verilog
Logic Synthesis
HDL logic map to target library optimize speed, area
Mask
09/11/02
Beta redux!
ILL XAdr OP
JT
2 1 0
PCSEL
PC
Instruction Memory
D
+4
Ra: <20:16>
Rb: <15:11>
0 1
Rc: <25:21>
RA2SEL
+
XP
WASEL 1
RA1 WA WA RD1
Rc: <25:21> 0
Z
Register File
JT
PC+4+4*SXT(C) IRQ Z
C: SXT(<15:0>)
ASEL
BSEL
Control Logic
PCSEL RA2SEL ASEL BSEL WDSEL ALUFN Wr WERF WASEL
A ALUFN
ALU
B WD R/W
Wr
Data Memory
Adr RD
PC+4
0 1 2
WDSEL
09/11/02
09/11/02
JT
2 1 0
PCSEL
1
A
PC
00
Instruction Memory
D
Step 1: identify memories Step 2: identify datapaths Whats left is random logic
Ra: <20:16> Rb: <15:11>
0 WASEL 1
+4
Rc: <25:21>
RA2SEL
2 PC
+
XP
Rc: <25:21> 0
Z
RA1 WA WA RD1
Register File
JT
RA2 WD RD2 WE
1
WERF
PC+4+4*SXT(C) IRQ Z
C: SXT(<15:0>)
ASEL
BSEL
Control Logic
PCSEL RA2SEL ASEL BSEL WDSEL ALUFN Wr WERF WASEL
A ALUFN
ALU
B WD R/W
Wr
Data Memory
Adr RD
PC+4
1
0 1 2
Main Datapath
6.371 Fall 2002
2
09/11/02
WDSEL
Use to model state elements (e.g., registers) Sometimes useful for combinational logic expressed using for or case statements Simulates much faster than dataflow statements since no waveforms are produced for signals internal to behavioral block. Heres where you can make the tradeoff between simulation speed and debugability.
6.371 Fall 2002 09/11/02
Beta verilog can be found in /mit/6.371/examples/beta.vl or Handouts webpage Beta verilog can be found in /mit/6.371/examples/beta.vl or Handouts webpage
6.371 Fall 2002 09/11/02 L03 More Verilog 9
Register File
// 2-read, 1-write 32-location register file module regfile(ra1,rd1,ra2,rd2,clk,werf,wa,wd); input [4:0] ra1; // address for read port 1 (Reg[RA]) output [31:0] rd1; // read data for port 1 input [4:0] ra2; // address for read port 2 (Reg[RB], Reg[RC] for ST) output [31:0] rd2; // read data for port 2 input clk; input werf; // write enable, active high input [4:0] wa; // address for write port (Reg[RC]) input [31:0] wd; // write data reg [31:0] registers[31:0]; // the register file itself (local)
// read paths are combinational // logic to ensure R31 reads as zero is in main datapath assign rd1 = registers[ra1]; assign rd2 = registers[ra2]; // write port is active only when WERF is asserted always @(posedge clk) if (werf) registers[wa] <= wd; endmodule
09/11/02
C
initial begin clk = 0; a = 0; b = 1; D #10 clk = 1; #10 $display("a=%d b=%d\n",a,b); $finish; E end endmodule
Rule: always change state using <= (e.g., inside always @(posedge clk))) Rule: always change state using <= (e.g., inside always @(posedge clk)
6.371 Fall 2002 09/11/02 L03 More Verilog 11
module pc(clk,reset,pcsel,offset,jump_addr, branch_addr,pc,pc_plus_4); input clk; input reset; // forces PC to 0x80000000 input [2:0] pcsel; // selects source of next PC input [15:0] offset; // inst[15:0] input [31:0] jump_addr; // from Reg[RA], used in JMP instruction output [31:0] branch_addr; // send to datapath for LDR instruction output [31:0] pc; // used as address for instruction fetch output [31:0] pc_plus_4; // saved in regfile during branches, JMP, traps
PC
reg [31:0] pc; wire [30:0] pcinc; wire [31:0] npc; // the Beta PC increments by 4, but wont change supervisor bit assign pcinc = pc + 4; assign pc_plus_4 = {pc[31],pcinc}; // branch address = PC + 4 + 4*sxt(offset) assign branch_addr = {0,pcinc + {{13{offset[15]}},offset[15:0],2'b00}}; assign npc = reset ? 32'h80000000 : (pcsel == 0) ? {pc[31],pcinc} : // normal (pcsel == 1) ? {pc[31],branch_addr[30:0]} : // branch (pcsel == 2) ? {pc[31] & jump_addr[31],jump_addr[30:0]} : // jump (pcsel == 3) ? 32'h80000004 : 32'h80000008; // illop, trap // pc register, pc[31] is supervisor bit and gets special treatment always @(posedge clk) pc <= npc; endmodule
09/11/02
module datapath(inst,rd1,rd2,pc_plus_4,branch_addr,mem_data, rd1zero,rd2zero,asel,bsel,wdsel,alufn, wdata,mem_addr,mem_wdata,z); input [15:0] inst; // constant field from instruction input [31:0] rd1; // Reg[RA] from register file input [31:0] rd2; // Reg[RB] from register file (Reg[RC] for ST) input [31:0] pc_plus_4; // incremented PC input [31:0] branch_addr; // PC + 4 + 4*sxt(inst[15:0]) input [31:0] mem_data; // memory read data (for LD) input rd1zero; // RA == R31, so treat RD1 as 0 input rd2zero; // RB/RC == R31, so treat RD2 as 0 input asel; // select A operand for ALU input bsel; // select B operand for ALU input [1:0] wdsel; // select regfile write data input [5:0] alufn; // operation to be performed by alu output [31:0] wdata; // regfile write data (output of WDSEL mux) output [31:0] mem_addr; // alu output, doubles as data memory address output [31:0] mem_wdata; // data memory write data output z; // true if Reg[RA] is zero, used during branches wire [31:0] alu_a,alu_b; // A and B inputs to ALU
Main Datapath
// compute A and B inputs into alu, also Z bit for control logic dp_misc misc(rd1zero,rd2zero,asel,bsel,inst,rd1,rd2,branch_addr, alu_a,alu_b,mem_wdata,z); // where all the heavy-lifting happens dp_alu alu(alufn,alu_a,alu_b,mem_addr); // select regfile write data from PC+4, alu output, and memory data dp_wdata wdata(wdsel,mem_data,mem_addr,pc_plus_4,wdata); endmodule
6.371 Fall 2002 09/11/02 L03 More Verilog 13
module dp_addsub(fn,alu_a,alu_b,result,n,v,z); input fn; // 0 for add, 1 for subtract input [31:0] alu_a; // A operand input [31:0] alu_b; // B operand output [31:0] result; // result output n,v,z; // condition codes computed from result reg n,v,z; reg [31:0] result;
Adder
Whats wrong with: Whats wrong with: assign result == fn ?? aa bb :: aa ++ b; assign result fn b;
always @(fn or alu_a or alu_b) begin: ripple integer i; // FOR loop index, not in hardware reg cin,p,g; // expanded at compile time into many signals reg [31:0] xb; // hold's complement of ALU_B during subtract // simple ripple-carry adder for now xb = fn ? ~alu_b : alu_b; // a - b == a + ~b + 1 cin = fn; // carry-in is 0 for add, 1 for sub // remember: this FOR is expanded at *compile* time for (i = 0; i < 32; i = i + 1) begin p = alu_a[i] ^ xb[i]; // carry propagate g = alu_a[i] & xb[i]; // carry generate result[i] = p ^ cin; cin = g | (p & cin); // carry into next stage end n = result[31]; // negative z = ~|result; // zero v = (alu_a[31] & xb[31] & !n) | (~alu_a[31] & ~xb[31] & n); end endmodule
6.371 Fall 2002 09/11/02
// overflow
reg [17:0] ctl; // local always @(inst or interrupt) begin if (interrupt) ctl = 16'b0100100000000000; else case (inst[31:26]) // ppp aaaaaaww // bcccw lllllldd // tsssaabuuuuuuss // eeeesssffffffeex // sllleeennnnnnllw // t210lll54321010r default: ctl = 16'b0011100000000000; 6'b011000: ctl = 16'b0000001000000100; 6'b011001: ctl = 16'b0000001000000101; 6'b011011: ctl = 16'b0010000000000000; 6'b111101: ctl = 16'b0000001100001010; 6'b111110: ctl = 16'b0000001100011010; endcase end assign assign assign assign assign assign assign assign
// // // //
// SHRC // SRAC
werf = ~ctl[0]; mem_we = !reset & ctl[0]; wdsel = ctl[2:1]; alufn = ctl[8:3]; bsel = ctl[9]; asel = ctl[10]; wa = ctl[11] ? 5'b11110 : inst[25:21]; pcsel = ((ctl[14:12] == 3'b001) & (ctl[15] ^ z)) ? 3'b000 : ctl[14:12];
09/11/02 L03 More Verilog 15
module main; reg clk,reset,irq; wire [31:0] inst_addr,inst_data; wire [31:0] mem_addr,mem_rd_data,mem_wr_data; wire mem_we; reg [31:0] memory[1023:0]; beta beta(clk,reset,irq,inst_addr,inst_data, mem_addr,mem_rd_data,mem_we,mem_wr_data); // main memory (2 async read ports, 1 sync write port) assign inst_data = memory[inst_addr[13:2]]; assign mem_rd_data = memory[mem_addr[13:2]]; always @(posedge clk) if (mem_we) memory[mem_addr[13:2]] <= mem_wr_data; always #5 clk = ~clk; initial begin $dumpfile("beta_checkoff.vcd"); $dumpvars; $readmemh("beta_checkoff",memory); clk = 0; irq = 0; reset = 1; #10 reset = 0; #3000 // 300 cycles $finish; end endmodule
6.371 Fall 2002 09/11/02
Test Jig
About 20 megabytes for 300 cycles! @0 // starting address @0 // starting address 77df000a 77df000a 77ff0003 77ff0003 6ffe0000 6ffe0000 c3e00000 c3e00000 77fffffe 77fffffe d01e0004 d01e0004 77e00002 77e00002
L03 More Verilog 16