From 0901af23dbcacf138a8427c79412f9bae03a8eb4 Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sat, 11 Feb 2023 20:27:28 +0000 Subject: [PATCH] Added support for some register indirect addressing modes. Also added documentation comments and did some general cleanup --- cpu/proc_state_def.v | 6 ++ cpu/processor.v | 191 +++++++++++++++++++++++++++++++++++-------- cpu/registers.v | 6 +- 3 files changed, 164 insertions(+), 39 deletions(-) diff --git a/cpu/proc_state_def.v b/cpu/proc_state_def.v index 708fb83..d2626e2 100644 --- a/cpu/proc_state_def.v +++ b/cpu/proc_state_def.v @@ -12,6 +12,12 @@ `define PROC_DE_LOAD_16_EXTRA_FETCH_SET 4'b0110 `define PROC_DE_LOAD_16_EXTRA_FETCH 4'b0111 +/*MEM/IO READ*/ +`define RPOC_MEMIO_READ 4'b1100 +`define PROC_MEMIO_SETADDR 4'b1101 +`define PROC_MEMIO_GET_ALIGNED_DATA 4'b1110 /* :) */ +`define PROC_MEMIO_GET_UNALIGNED_DATA 4'b1010 /* :( */ + /*EXECUTE STATE*/ `define PROC_EX_STATE_ENTRY 4'b1000 `define PROC_EX_STATE_EXIT 4'b1001 diff --git a/cpu/processor.v b/cpu/processor.v index f8b8053..b3043ff 100644 --- a/cpu/processor.v +++ b/cpu/processor.v @@ -24,6 +24,9 @@ reg [15:0] CIR; reg [15:0] PARAM1; reg [15:0] PARAM2; reg unaligned_access; +reg [1:0]IN_MOD; +reg [2:0]IN_RM; +reg Wbit; // Execution units reg [1:0] in1_sel; @@ -44,6 +47,7 @@ always @(negedge reset) begin @(posedge reset) @(negedge clock); state=`PROC_IF_STATE_ENTRY; + IN_MOD=2'b11; end end @@ -80,12 +84,13 @@ wire [15:0] ALU_1B; wire [15:0] ALU_1O; reg [`ALU_OP_BITS-1:0]ALU_1OP; reg ALU_1OE; -//reg [15:0] temp_out; ALU ALU(ALU_1A,ALU_1B,ALU_1OE,ALU_1O,ALU_1OP); /*** Processor stages ***/ -`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1; +`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;IN_MOD=2'b11; +`define start_aligning_instruction if(unaligned_access==0)begin ProgCount=ProgCount+1; external_address_bus <= ProgCount; end /*we normally don't advance PC in case of singly byte unaligning instructions leasving us with two instructions in one read so do that here*/ +`define start_unaligning_instruction unaligned_access=~unaligned_access; always @(negedge clock) begin case(state) @@ -118,6 +123,10 @@ always @(negedge clock) begin external_address_bus = ProgCount; state=`PROC_DE_LOAD_16_EXTRA_FETCH; end + `PROC_MEMIO_SETADDR:begin + external_address_bus = {1'b0,reg_read_data[15:1]}; + state=reg_read_data[0:0]?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA; + end endcase end @@ -139,6 +148,7 @@ always @(posedge clock) begin external_address_bus <= ProgCount; state=`PROC_IF_STATE_EXTRA_FETCH; end + /* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */ /* AFTER THE IF STAGE WE HAVE THE FRIST BYTE OF THE * INSTRUCTION ADN THE ONE FOLLOWING, ALLIGNED CORRECTLY TO * CIR */ @@ -147,8 +157,14 @@ always @(posedge clock) begin 6'b000001 : begin /* ADD, ... */ if ( CIR[9:9] == 0 )begin - /* Add Immediate word/byte to accumulator */ - unaligned_access=~unaligned_access; + /* Add Immediate word/byte to accumulator */ + /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/ + Wbit=CIR[8:8]; + if(Wbit) + `start_unaligning_instruction + else + `start_aligning_instruction + IN_MOD=2'b11; in1_sel=2'b00; in2_sel=2'b01; out_sel=2'b11; @@ -171,10 +187,9 @@ always @(posedge clock) begin case (CIR[5:3]) 3'b000 : begin /* Add Immediate word/byte to register/memory */ - if(unaligned_access==0)begin - ProgCount=ProgCount+1; - external_address_bus <= ProgCount; - end + /* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */ + `start_aligning_instruction + IN_MOD=2'b11; in1_sel=2'b00; in2_sel=2'b01; out_sel=CIR[7:6]; @@ -197,12 +212,14 @@ always @(posedge clock) begin end 6'b101100, 6'b101101:begin - /*Move Immediate byte to register*/ - if(unaligned_access==0)begin - ProgCount=ProgCount+1; - external_address_bus <= ProgCount; - end - unaligned_access=~unaligned_access; + /* MOV - Move Immediate byte to register */ + /* 1 0 1 1 W REG | DATA | DATA if W |*/ + Wbit=CIR[11:11]; + if(Wbit) + `start_unaligning_instruction + else + `start_aligning_instruction + IN_MOD=2'b11; in1_sel=2'b00; in2_sel=2'b00; out_sel=2'b11; @@ -215,8 +232,13 @@ always @(posedge clock) begin end 6'b101110, 6'b101111 : begin - /*Move Immediate word to register*/ - unaligned_access=~unaligned_access; + /*MOV - Move Immediate word to register*/ + Wbit=CIR[11:11]; + if(Wbit) + `start_unaligning_instruction + else + `start_aligning_instruction + IN_MOD=2'b11; in1_sel=2'b00; in2_sel=2'b00; out_sel=2'b11; @@ -226,15 +248,52 @@ always @(posedge clock) begin PARAM2=0; state=`PROC_DE_LOAD_16_PARAM; end + + 6'b100010 : begin + /* MOV - Reg/Mem to/from register */ + /* 1 0 0 0 1 0 D W | MOD REG REG | < DISP LO > | < DISP HI > |*/ + `start_aligning_instruction + IN_MOD=CIR[7:6]; + IN_RM=CIR[2:0]; + Wbit=CIR[8:8]; + if(CIR[9:9] == 1)begin + /* to reg */ + IN_MOD=CIR[7:6]; + if(IN_MOD==2'b11)begin + in1_sel=2'b01; + reg_read_addr=CIR[2:0]; + end else begin + in1_sel=2'b00; + end + in2_sel=2'b00; + out_sel=2'b11; + reg_write_addr={CIR[8:8],CIR[5:3]}; + end else begin + `invalid_instruction + end + + ALU_1OE=0; + ALU_1OP=`ALU_OP_ADD; + PARAM2=0; + state=`PROC_DE_LOAD_16_PARAM; + if ( IN_MOD == 2'b11 ) + state=`PROC_EX_STATE_ENTRY; + else + state=`RPOC_MEMIO_READ; + end 6'b010000,//INC 6'b010001,//INC 6'b010010,//DEC 6'b010011:begin//DEC - /*INC/DEC Register*/ - unaligned_access=~unaligned_access; + /* DEC - Decrement Register */ + /* | 0 1 0 0 1 REG | */ + /* INC - Increment Register */ + /* | 0 1 0 0 0 REG | */ + `start_unaligning_instruction in1_sel=2'b01; in2_sel=2'b00; out_sel=2'b11; + IN_MOD=2'b11; PARAM2=1; reg_read_addr={1'b1,CIR[10:8]}; reg_write_addr={1'b1,CIR[10:8]}; @@ -251,13 +310,12 @@ always @(posedge clock) begin if (CIR[9:9] == 1 ) begin case (CIR[5:3]) 3'b000 :begin - /* Increment Register or Memmory */ - if(unaligned_access==0)begin - ProgCount=ProgCount+1; - external_address_bus <= ProgCount; - end - in1_sel=2'b00; - in2_sel=2'b01; + /* INC - Register/Memory */ + /* 1 1 1 1 1 1 1 W | MOD 0 0 0 R/M | < DISP LO> | < DISP HI> */ + `start_aligning_instruction + IN_MOD=CIR[7:6]; + in1_sel=2'b00;/* number 1 */ + in2_sel=(CIR[7:6]==2'b11)? 2'b01 : 2'b00; out_sel=CIR[7:6]; PARAM1=1; reg_read_addr={1'b0,CIR[2:0]}; @@ -265,7 +323,10 @@ always @(posedge clock) begin reg_read_oe=0; ALU_1OE=0; ALU_1OP=`ALU_OP_ADD; - state=`PROC_EX_STATE_ENTRY; + if ( CIR[7:6] == 2'b11 ) + state=`PROC_EX_STATE_ENTRY; + else + state=`RPOC_MEMIO_READ; end default:begin `invalid_instruction @@ -279,8 +340,10 @@ always @(posedge clock) begin /*HLT, CMC, TEST, NOT, NEG, MUL, IMUL, .... */ case (CIR[9:8]) 2'b00:begin - /* HLT*/ - unaligned_access=~unaligned_access; + /* HLT - Halt */ + /* 1 1 1 1 0 1 0 0 | */ + `start_unaligning_instruction + IN_MOD=2'b11; HALT=1; state=`PROC_HALT_STATE; end @@ -311,12 +374,72 @@ always @(posedge clock) begin PARAM1[15:8] = external_data_bus[15:8]; state=`PROC_EX_STATE_ENTRY; end - `PROC_EX_STATE_ENTRY:begin - reg_write_data=ALU_1O; - state=`PROC_EX_STATE_EXIT; - ERROR=0; - end - endcase + `RPOC_MEMIO_READ:begin + /*Decode MOD R/M, read the data and place it to PARAM1*/ + case (IN_RM) + 3'b000:begin + /*[BX]+[SI]*/ + `invalid_instruction + end + 3'b001:begin + /*[BX]+[SI]*/ + `invalid_instruction + end + 3'b010:begin + /*[BP]+[SI]*/ + `invalid_instruction + end + 3'b011:begin + /*[BP]+[DI]*/ + `invalid_instruction + end + 3'b100:begin + /*[SI]*/ + reg_read_addr=4'b1110; + reg_read_oe=0; + state=`PROC_MEMIO_SETADDR; + end + 3'b101:begin + /*[DI]*/ + reg_read_addr=4'b1111; + reg_read_oe=0; + state=`PROC_MEMIO_SETADDR; + end + 3'b110:begin + /*d16 */ + `invalid_instruction + end + 3'b111:begin + /*[BX]*/ + reg_read_addr=4'b1011; + reg_read_oe=0; + state=`PROC_MEMIO_SETADDR; + end + endcase + if(IN_MOD!=2'b00)begin + /*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/ + `invalid_instruction; + end + + end + `PROC_MEMIO_GET_ALIGNED_DATA:begin + PARAM1=(Wbit==1)? external_data_bus : {8'b00000000,external_data_bus[15:8]} ; + state=`PROC_EX_STATE_ENTRY; + end + `PROC_MEMIO_GET_UNALIGNED_DATA:begin + if(Wbit==1) begin + `invalid_instruction //easy to implement, get the other byte from the next address + end else begin + PARAM1={8'b00000000,external_data_bus[7:0]}; + state=`PROC_EX_STATE_ENTRY; + end + end + `PROC_EX_STATE_ENTRY:begin + reg_write_data=ALU_1O; + state=`PROC_EX_STATE_EXIT; + ERROR=0; + end + endcase end diff --git a/cpu/registers.v b/cpu/registers.v index a382f21..e004c04 100644 --- a/cpu/registers.v +++ b/cpu/registers.v @@ -18,7 +18,6 @@ assign read_port1_data = !read_port1_oe ? `ifdef DEBUG_REG_WRITES string debug_name; - logic[15:0] debug_value; `endif always @(negedge write_port1_we) begin @@ -44,7 +43,6 @@ always @(negedge write_port1_we) begin 2'b10: debug_name="si"; 2'b11: debug_name="di"; endcase - debug_value=registers[write_port1_addr[2:0]]; end else begin case(write_port1_addr[1:0]) 2'b00: debug_name="ax"; @@ -52,11 +50,9 @@ always @(negedge write_port1_we) begin 2'b10: debug_name="dx"; 2'b11: debug_name="bx"; endcase - debug_value=registers[write_port1_addr[2:0]]; end - - $display("register %%%s update to $0x%04x",debug_name,debug_value); + $display("register %%%s update to $0x%04x",debug_name,registers[write_port1_addr[2:0]]); `endif end endmodule