This time, I implemented a new class of instructions: MOV, for setting a register to a value of another register.

I have also changed all instances of blocking assignment "=" to the non-blocking assignment, "<=" -- to betterĀ simulateĀ behavior of real registers. This way the display statements printing the values of registers A, B, C, etc. will more closely correspond to the actual value of the register during that tick, and the new value will not be printed until the next tick.

Last but not least, if you look at the code you will notice how messy and unreadable it became. So far, to keep the story simple, I kept the code structure as flat as possible. Next time I should split things up in more manageable logic blocks. Specifically, the case statements on register specifier fields in the instruction, should become a reusable function or perhaps even a separate module.

As always, I removed the old comments and commented the new and updated code lines:

    module CPU(input iClk, input iRst, output [7:0] oAddressBus, input [7:0] i

    localparam MVI=2'b00, MOV=2'b01, ALU=2'b10, ALI=2'b11;

    localparam B = 3'b000, C = 3'b001, D = 3'b010, E = 3'b011,
               H = 3'b100, L = 3'b101, M = 3'b110, A = 3'b111;

    reg [7:0] _pc;

    reg _mode;
    localparam NORMAL=1'b0, READ_IMMED=1'b1;

    reg [7:0] _instruction;
    reg [7:0] _a, _b, _c, _d, _e, _h, _l;

    always @(posedge iClk, posedge iRst)
    begin
        if(iRst)
            begin
                $display("resetting...");
                //In real life registers don't take new value
                //until the raising edge of the next clock tick.
                //In Verilog, such behavior is simulated
                //with non-blocking assignment, "&lt;="
                _pc &lt;= 8'h0;
                _mode &lt;= NORMAL;
                //setting all registers to zero on reset
                _a &lt;= 8'h0;
                _b &lt;= 8'h0;
                _c &lt;= 8'h0;
                _d &lt;= 8'h0;
                _e &lt;= 8'h0;
                _h &lt;= 8'h0;
                _l &lt;= 8'h0;
            end

        else begin
            $display("PC:%d", _pc);
            $display("mem:%d", iMemoryValue);

            case(_mode)
                NORMAL:
                    if(iMemoryValue == 8'h0) $display("NOP");
                    else case(iMemoryValue[7:6])
                        MVI: if(iMemoryValue[2:0] == M) begin
                                $display("initiating MVI");
                                _mode &lt;= READ_IMMED;
                                _instruction &lt;= iMemoryValue;
                             end
                             else $display("unknown instruction");
                        //detecting a MOV-class instruction
                        MOV:
                            //register fields of the instruction
                            //specify source and destination
                            case(iMemoryValue[5:0])
                                //using {} syntaxis to concatenate
                                //the constants A and B
                                {A, B}: begin
                                    $display("MOV A, B");
                                    _a &lt;= _b;
                                end
                                {B, A}: begin
                                    $display("MOV B, A");
                                    _b &lt;= _a;
                                end
                                //TODO: add {A, C} etc.
                                //not supporting other combinations yet
                                default: $display("unknown instruction");
                            endcase
                        default:
                            $display("unknown instruction");
                    endcase

                READ_IMMED: begin
                    case(_instruction[5:3])
                        B: begin
                            $display("MVI B, %d", iMemoryValue);
                            _b &lt;= iMemoryValue;
                        end
                        C: begin
                            $display("MVI C, %d", iMemoryValue);
                            _c &lt;= iMemoryValue;
                        end
                        D: begin
                            $display("MVI D, %d", iMemoryValue);
                            _d &lt;= iMemoryValue;
                        end
                        E: begin
                            $display("MVI E, %d", iMemoryValue);
                            _e &lt;= iMemoryValue;
                        end
                        H: begin
                            $display("MVI H, %d", iMemoryValue);
                            _h &lt;= iMemoryValue;
                        end
                        L: begin
                            $display("MVI L, %d", iMemoryValue);
                            _l &lt;= iMemoryValue;
                        end
                        M: $display("unknown instruction");
                        A: begin
                            $display("MVI A, %d", iMemoryValue);
                            _a &lt;= iMemoryValue;
                        end
                    endcase
                    _mode &lt;= NORMAL;
                end
            endcase

            //more debug prints
            $display("A=%d", _a);
            $display("B=%d", _b);
            $display("C=%d", _c);
            $display("D=%d", _d);
            $display("E=%d", _e);
            $display("H=%d", _h);
            $display("L=%d", _l);

            _pc &lt;= _pc + 1'b1;
        end
    end

    assign oAddressBus = _pc;

endmodule

module ROM(input [7:0] iAddress, output [7:0] oReadPort);

    reg [7:0] _rom [0:255];

    initial
    begin
        _rom[0] = 0;                //NOP
        //verilog allows underscores in numeric literals,
        //to improve readability
        _rom[1] = 8'b00_000_110;    //MVI B, 55
        _rom[2] = 55;
        _rom[3] = 8'b00_001_110;    //MVI C, 255
        _rom[4] = 255;
        _rom[5] = 8'b01_111_000;    //MOV A, B
        //etc.
    end

    assign oReadPort = _rom[iAddress];

endmodule  

And here's the printout (only showing clock ticks 3 to 10):

--------------Tick           3---------------
PC:  x  
mem:  x  
A=  x  
B=  x  
C=  x  
D=  x  
E=  x  
H=  x  
L=  x  
resetting...  
--------------Tick           4---------------
PC:  0  
mem:  0  
executing NOP!  
A=  0  
B=  0  
C=  0  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick           5---------------
PC:  1  
mem:  6  
initiating MVI  
A=  0  
B=  0  
C=  0  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick           6---------------
PC:  2  
mem: 55  
MVI B,  55  
A=  0  
B=  0  
C=  0  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick           7---------------
PC:  3  
mem: 14  
initiating MVI  
A=  0  
B= 55  
C=  0  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick           8---------------
PC:  4  
mem:255  
MVI C, 255  
A=  0  
B= 55  
C=  0  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick           9---------------
PC:  5  
mem:120  
MOV A, B  
A=  0  
B= 55  
C=255  
D=  0  
E=  0  
H=  0  
L=  0  
--------------Tick          10---------------
PC:  6  
mem:  x  
unknown instruction  
A= 55  
B= 55  
C=255  
D=  0  
E=  0  
H=  0  
L=  0