// Reference solution for 8-bit ALU
// Single-cycle combinational ALU with 12 operations and 4 flag outputs

module alu_8bit (
    input  wire [7:0] a,
    input  wire [7:0] b,
    input  wire [3:0] opcode,
    output reg  [7:0] result,
    output wire       zero,
    output wire       negative,
    output reg        carry,
    output reg        overflow
);

    // Opcode definitions
    localparam OP_ADD  = 4'b0000;
    localparam OP_SUB  = 4'b0001;
    localparam OP_AND  = 4'b0010;
    localparam OP_OR   = 4'b0011;
    localparam OP_XOR  = 4'b0100;
    localparam OP_NOT  = 4'b0101;
    localparam OP_SHL  = 4'b0110;
    localparam OP_SHR  = 4'b0111;
    localparam OP_INC  = 4'b1000;
    localparam OP_DEC  = 4'b1001;
    localparam OP_CMP  = 4'b1010;
    localparam OP_PASS = 4'b1011;
    
    // Internal signals for arithmetic operations
    reg [8:0] add_result;
    reg [8:0] sub_result;
    reg [8:0] inc_result;
    reg [8:0] dec_result;
    
    // Main ALU logic
    always @(*) begin
        // Default values
        result = 8'b0;
        carry = 1'b0;
        overflow = 1'b0;
        
        // Pre-compute arithmetic results
        add_result = {1'b0, a} + {1'b0, b};
        sub_result = {1'b0, a} - {1'b0, b};
        inc_result = {1'b0, a} + 1;
        dec_result = {1'b0, a} - 1;
        
        case (opcode)
            OP_ADD: begin
                result = add_result[7:0];
                carry = add_result[8];
                // Overflow: same sign inputs, different sign result
                overflow = (a[7] == b[7]) && (result[7] != a[7]);
            end
            
            OP_SUB: begin
                result = sub_result[7:0];
                carry = sub_result[8];  // Borrow out
                // Overflow: different sign inputs, result sign differs from A
                overflow = (a[7] != b[7]) && (result[7] != a[7]);
            end
            
            OP_AND: begin
                result = a & b;
            end
            
            OP_OR: begin
                result = a | b;
            end
            
            OP_XOR: begin
                result = a ^ b;
            end
            
            OP_NOT: begin
                result = ~a;
            end
            
            OP_SHL: begin
                result = a << 1;
                carry = a[7];  // Shifted-out bit
            end
            
            OP_SHR: begin
                result = a >> 1;
                carry = a[0];  // Shifted-out bit
            end
            
            OP_INC: begin
                result = inc_result[7:0];
                carry = inc_result[8];
            end
            
            OP_DEC: begin
                result = dec_result[7:0];
                carry = dec_result[8];  // Borrow
            end
            
            OP_CMP: begin
                result = (a == b) ? 8'b0 : 8'hFF;
            end
            
            OP_PASS: begin
                result = a;
            end
            
            default: begin
                result = 8'b0;
            end
        endcase
    end
    
    // Zero flag: set when result is zero
    assign zero = (result == 8'b0);
    
    // Negative flag: set when result MSB is 1
    assign negative = result[7];

endmodule
