Mini RISC Advanced Materials
Mini RISC Advanced Materials
(ADAC)
SEMESTER - 4
Module - 1
Microcontroller Programming
(ADAC LAB CODE: S1M4L01)
Assembly Level Language for Microprocessors
Table of Content
// Opcode definitions
parameter ADD = 4'b0000;
parameter SUB = 4'b0001;
parameter AND = 4'b0010;
parameter OR = 4'b0011;
parameter XOR = 4'b0100;
parameter NOT = 4'b0101;
parameter SHL = 4'b0110;
parameter SHR = 4'b0111;
parameter CMP = 4'b1000;
case (opcode)
ADD: begin
result = add_result[7:0];
carry_out = add_result[8]; // Overflow
end
SUB: begin
result = sub_result[7:0];
carry_out = sub_result[8]; // Borrow
end
SHL: begin
result = shl_result;
carry_out = operand_a[7]; // MSB carries out
end
SHR: begin
result = shr_result;
carry_out = operand_a[0]; // LSB carries out
end
CMP: begin
result = operand_a - operand_b;
carry_out = (operand_a < operand_b) ? 1'b1 : 1'b0;
end
// Flag generation
zero_out = (result == 8'b0) ? 1'b1 : 1'b0;
sign_out = result[7];
end
endmodule
integer i;
endmodule
endmodule
integer i;
// Asynchronous read
assign read_data = (read_enable) ? memory[address] : 8'bz;
// Synchronous write
always @(posedge clk) begin
if (write_enable)
memory[address] <= write_data;
end
endmodule
PART 2: Control Unit & FSM
Implementation
2.1 6-Stage Pipeline Control Unit (Complete)
module control_unit (
input clk,
input reset,
input [3:0] opcode,
input zero_flag,
input carry_flag,
// State definitions
parameter RESET = 3'b000;
parameter FETCH = 3'b001;
parameter DECODE = 3'b010;
parameter EXECUTE = 3'b011;
parameter MEMORY = 3'b100;
parameter WRITEBACK = 3'b101;
FETCH: begin
// Fetch instruction from memory
mem_read_enable = 1'b1;
pc_increment = 1'b1;
end
DECODE: begin
// Decode instruction (combinational)
// No outputs - just preparing signals
end
EXECUTE: begin
// Execute ALU operation
alu_enable = 1'b1;
MEMORY: begin
// Access memory for LOAD/STORE
case (opcode)
4'b0101: mem_read_enable = 1'b1; // LOAD
4'b0110: mem_write_enable = 1'b1; // STORE
default: mem_read_enable = 1'b0;
endcase
end
WRITEBACK: begin
// Write result back to register
case (opcode)
4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100: // ALU ops
reg_write_enable = 1'b1;
4'b0101: // LOAD
reg_write_enable = 1'b1;
default:
reg_write_enable = 1'b0;
endcase
end
default: begin
pc_increment = 1'b0;
end
endcase
end
endmodule
endmodule
PART 3: Complete CPU Top-Level
Module
3.1 CPU Top-Level (Full Integration)
module cpu_top (
input clk,
input reset,
// Debugging outputs
output [7:0] pc_out,
output [15:0] instruction_out,
output [7:0] alu_result_out,
output [2:0] cpu_state_out
);
// Internal signals
wire [7:0] pc;
wire [7:0] next_pc;
wire [15:0] instruction;
// Program Counter
program_counter pc_inst (
.clk(clk),
.reset(reset),
.increment(pc_increment),
.jump_enable(pc_jump),
.jump_target(immediate),
.pc(pc)
);
// Instruction Memory
instruction_memory imem (
.address(pc),
.instruction(instruction)
);
// Instruction Decoder
instruction_decoder decoder (
.instruction(instruction),
.opcode(opcode),
.dest_reg(dest_reg),
.src_reg(src_reg),
.immediate(immediate)
);
// Register File
register_file regfile (
.clk(clk),
.reset(reset),
.read_addr_a(src_reg),
.read_addr_b(dest_reg),
.write_addr(dest_reg),
.write_data(alu_result),
.write_enable(reg_write_en),
.read_data_a(reg_read_a),
.read_data_b(reg_read_b)
);
// ALU
alu_8bit alu_inst (
.operand_a(alu_input_a),
.operand_b(alu_input_b),
.opcode(opcode),
.result(alu_result),
.carry_out(alu_carry),
.zero_out(alu_zero),
.sign_out(alu_sign)
);
// Data Memory
data_memory dmem (
.clk(clk),
.address(alu_result),
.write_data(reg_read_b),
.write_enable(mem_write_en),
.read_enable(mem_read_en),
.read_data(mem_read_data)
);
// Control Unit
control_unit ctrl (
.clk(clk),
.reset(reset),
.opcode(opcode),
.zero_flag(alu_zero),
.carry_flag(alu_carry),
.pc_increment(pc_increment),
.pc_jump(pc_jump),
.reg_write_enable(reg_write_en),
.mem_read_enable(mem_read_en),
.mem_write_enable(mem_write_en),
.alu_enable(alu_en),
.state(ctrl_state)
);
endmodule
PART 4: Comprehensive Testbench
4.1 Complete CPU Testbench
module cpu_tb;
// Test signals
reg clk, reset;
wire [7:0] pc_out;
wire [15:0] instr_out;
wire [7:0] alu_out;
wire [2:0] state_out;
// CPU instance
cpu_top cpu (
.clk(clk),
.reset(reset),
.pc_out(pc_out),
.instruction_out(instr_out),
.alu_result_out(alu_out),
.cpu_state_out(state_out)
);
// Main test
initial begin
$dumpfile("cpu_simulation.vcd");
$dumpvars(0, cpu_tb);
// Test 1: Reset
reset_cpu();
$finish;
end
task reset_cpu;
begin
reset = 1;
@(posedge clk);
@(posedge clk);
reset = 0;
@(posedge clk);
$display("[%t] CPU Reset Complete", $time);
end
endtask
task check_registers;
integer i;
begin
$display("\n=== Register File Contents ===");
for (i = 0; i < 8; i = i + 1)
$display("R%d = 0x%02h", i, [Link][i]);
end
endtask
task check_memory;
integer i;
begin
$display("\n=== Data Memory (first 32 locations) ===");
for (i = 0; i < 32; i = i + 1)
$display("MEM[0x%02h] = 0x%02h", i, [Link][i]);
end
endtask
endmodule
PART 5: Example Test Programs & Hex
Files
5.1 Assembly Program Examples
Program 1: Simple Addition
// Simple Addition Test Program
// Expected: R1=5, R2=10, R3=15
// [Link]:
@0000
1045
128A
0312
FFFF
// [Link]:
@0000
1045
1203
0312
9005
144D
FFFF
Program 3: Memory Load/Store
// Test memory operations
// Store value to memory
// Load value back
// Expected: MEM[20]=15, R4=15
// [Link]:
@0000
104F
1414
0612
0512
FFFF
LOOP:
ADD R3, R3, R1 // Sum += Counter
ADD R1, R1, 1 // Counter++
CMP R1, R4 // Compare Counter to Limit
JNZ LOOP // Jump if not zero
HALT
// [Link]:
@0000
1000
1800
1405
0301
0101
0104
9000
FFFF
PART 6: SystemVerilog Verification
Environment
6.1 SystemVerilog Transaction-Based Testbench
// SystemVerilog CPU Verification Environment
constraint valid_opcode {
opcode inside {[4'b0000:4'b1000]};
}
constraint valid_regs {
dest_reg inside {[3'b000:3'b111]};
src_reg inside {[3'b000:3'b111]};
}
endclass
repeat(100) begin
cpu_transaction trans = gen.get_instruction();
if (trans != null) begin
scoreboard.add_expected(trans);
monitor.collect_transaction();
scoreboard.add_observed(monitor.observed_trans);
end
end
[Link]();
endfunction
endclass
initial begin
$dumpfile("cpu_debug.vcd");
$dumpvars(0, cpu_tb);
// Detailed logging
$display("\n===== CPU SIMULATION START =====");
$display("Time | PC | Opcode | State | ALU_Result");
$display("-----|----| -------|-------|----------");
reset_cpu();
end
if (state == EXECUTE)
$display("%t | %02h | %04h | EXEC | %02h",
$time, pc, instruction, alu_result);
end
// Assert: Memory
address valid
property mem_addr_valid;
@(posedge clk) (mem_write_enable) |->
(mem_addr <= 8'hFF);
endproperty
assert property (mem_addr_valid) else
$error("Memory address out of range");
endmodule
PART 8: Synthesis and FPGA Deployment
8.1 Synthesis-Ready Checklist
Before Synthesis:
• ✓ Remove all testbench files ($display, $readmemh, etc.)
• ✓ Verify all $readmemh calls use synthesis-safe patterns
• ✓ Ensure all arrays are properly sized (powers of 2)
• ✓ Check for combinational loops (can cause glitches)
• ✓ Verify all outputs have drivers
• ✓ Check for multiple drivers on same wire
Increase Speed:
• • Add pipeline stages for deep combinational paths
• • Use registered outputs
• • Keep logic between registers simple
• • Example: pipeline[15:0] <= raw_instruction
PART 9: Performance Analysis &
Optimization
9.1 Critical Path Analysis
After synthesis, identify the critical path:
• Open timing report in Vivado/Quartus
• Look for longest combinational path
• Example critical paths in CPU:
• • PC increment to register write
• • ALU input selection to output
• • Memory address decode to data valid