177 lines
4.5 KiB
Verilog
177 lines
4.5 KiB
Verilog
/* Register bank and state machine */
|
|
`default_nettype none
|
|
`include "clockworks.v"
|
|
|
|
module SOC (
|
|
input clk,
|
|
input rst_i,
|
|
output [4:0] led,
|
|
input RXD,
|
|
output TXD
|
|
);
|
|
|
|
wire clk_i;
|
|
wire resetn;
|
|
|
|
reg [31:0] MEM [0:255];
|
|
reg [31:0] instr;
|
|
reg [31:0] PC;
|
|
|
|
|
|
initial begin
|
|
PC = 0;
|
|
|
|
// add x0, x0, x0
|
|
// rs2 rs1 add rd ALUREG
|
|
instr = 32'b0000000_00000_00000_000_00000_0110011;
|
|
// add x1, x0, x0
|
|
// rs2 rs1 add rd ALUREG
|
|
MEM[0] = 32'b0000000_00000_00000_000_00001_0110011;
|
|
// addi x1, x1, 1
|
|
// imm rs1 add rd ALUIMM
|
|
MEM[1] = 32'b000000000001_00001_000_00001_0010011;
|
|
// addi x1, x1, 1
|
|
// imm rs1 add rd ALUIMM
|
|
MEM[2] = 32'b000000000001_00001_000_00001_0010011;
|
|
// addi x1, x1, 1
|
|
// imm rs1 add rd ALUIMM
|
|
MEM[3] = 32'b000000000001_00001_000_00001_0010011;
|
|
// addi x1, x1, 1
|
|
// imm rs1 add rd ALUIMM
|
|
MEM[4] = 32'b000000000001_00001_000_00001_0010011;
|
|
|
|
// ebreak
|
|
// SYSTEM
|
|
MEM[5] = 32'b000000000001_00000_000_00000_1110011;
|
|
|
|
end
|
|
|
|
wire isALUreg = (instr[6:0] == 7'b011_0011);
|
|
wire isALUimm = (instr[6:0] == 7'b001_0011);
|
|
wire isLUI = (instr[6:0] == 7'b011_0111);
|
|
wire isAUIPC = (instr[6:0] == 7'b001_0111);
|
|
wire isJAL = (instr[6:0] == 7'b110_1111);
|
|
wire isJALR = (instr[6:0] == 7'b110_0111);
|
|
wire isBRANCH = (instr[6:0] == 7'b110_0011);
|
|
wire isLOAD = (instr[6:0] == 7'b000_0011);
|
|
wire isSTORE = (instr[6:0] == 7'b010_0011);
|
|
wire isSYSTEM = (instr[6:0] == 7'b111_0011);
|
|
|
|
// The 5 immediate formats
|
|
wire [31:0] Uimm={ instr[31], instr[30:12], {12{1'b0}}};
|
|
wire [31:0] Iimm={{21{instr[31]}}, instr[30:20]};
|
|
wire [31:0] Simm={{21{instr[31]}}, instr[30:25],instr[11:7]};
|
|
wire [31:0] Bimm={{20{instr[31]}}, instr[7],instr[30:25],instr[11:8],1'b0};
|
|
wire [31:0] Jimm={{12{instr[31]}}, instr[19:12],instr[20],instr[30:21],1'b0};
|
|
|
|
// Source and destination registers
|
|
wire [4:0] rs1Id = instr[19:15];
|
|
wire [4:0] rs2Id = instr[24:20];
|
|
wire [4:0] rdId = instr[11:7];
|
|
|
|
// function codes
|
|
wire [2:0] funct3 = instr[14:12];
|
|
wire [6:0] funct7 = instr[31:25];
|
|
|
|
//Register File
|
|
reg [31:0] RegisterFile [0:31];
|
|
reg [31:0] rs1;
|
|
reg [31:0] rs2;
|
|
wire [31:0] writeBackData;
|
|
wire writeBackEn;
|
|
//Initial value
|
|
assign writeBackData = 0;
|
|
assign writeBackEn = 0;
|
|
|
|
`ifdef BENCH
|
|
integer i;
|
|
initial begin
|
|
for(i=0; i<32; ++i) begin
|
|
RegisterFile[i] = 0;
|
|
end
|
|
end
|
|
`endif
|
|
|
|
//State Machine
|
|
localparam FETCH_INSTR = 0;
|
|
localparam FETCH_REGS = 1;
|
|
localparam EXECUTE = 2;
|
|
reg [1:0] state = FETCH_INSTR;
|
|
|
|
always @(posedge clk_i) begin
|
|
if(!resetn) begin
|
|
PC <= 0;
|
|
state <= FETCH_INSTR;
|
|
instr <= 32'b0000000_00000_00000_000_00000_0110011; //nop
|
|
end else begin
|
|
if (writeBackEn && rdId) begin
|
|
RegisterFile[rdId] <= writeBackData;
|
|
end
|
|
|
|
case(state)
|
|
FETCH_INSTR: begin
|
|
instr <= MEM[PC];
|
|
state <= FETCH_REGS;
|
|
end
|
|
FETCH_REGS: begin
|
|
rs1 <= RegisterFile[rs1Id];
|
|
rs2 <= RegisterFile[rs2Id];
|
|
state <= EXECUTE;
|
|
end
|
|
EXECUTE: begin
|
|
if(!isSYSTEM) begin
|
|
PC <= PC + 1;
|
|
end
|
|
state <= FETCH_INSTR;
|
|
`ifdef BENCH
|
|
if(isSYSTEM) $finish();
|
|
`endif
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
assign led = isSYSTEM ? 31 : (1 << state);
|
|
|
|
`ifdef BENCH
|
|
always @(posedge clk) begin
|
|
if(state == FETCH_REGS) begin
|
|
case (1'b1)
|
|
isALUreg: $display(
|
|
"ALUreg rd=%d rs1=%d rs2=%d funct3=%b",
|
|
rdId, rs1Id, rs2Id, funct3
|
|
);
|
|
isALUimm: $display(
|
|
"ALUimm rd=%d rs1=%d imm=%0d funct3=%b",
|
|
rdId, rs1Id, Iimm, funct3
|
|
);
|
|
isBranch: $display("BRANCH");
|
|
isJAL: $display("JAL");
|
|
isJALR: $display("JALR");
|
|
isAUIPC: $display("AUIPC");
|
|
isLUI: $display("LUI");
|
|
isLoad: $display("LOAD");
|
|
isStore: $display("STORE");
|
|
isSYSTEM: $display("SYSTEM");
|
|
endcase
|
|
if(isSYSTEM) begin
|
|
$finish();
|
|
end
|
|
end
|
|
end
|
|
`endif
|
|
|
|
// Gearbox and reset circuitry.
|
|
Clockworks #(
|
|
.SLOW(21) // Divide clock frequency by 2^21
|
|
)CW(
|
|
.CLK(clk),
|
|
.RESET(rst_i),
|
|
.clk(clk_i),
|
|
.resetn(resetn)
|
|
);
|
|
|
|
assign TXD = 1'b0; // not used for now
|
|
|
|
endmodule
|