diff --git a/Makefile b/Makefile index 3de7bf8..0ccb678 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ SYSTEM_VVP=system/system.vvp BOOT_CODE=boot_code/brainfuck.txt GTKWSAVE=./gtkwave_savefile.gtkw -MICROCODE=system/ucode.hex +MICROCODE=system/ucode.txt include common.mk diff --git a/boot_code/brainfuck_compiler_v1.asm b/boot_code/brainfuck_compiler_v1.asm index cfd44c5..1296c07 100644 --- a/boot_code/brainfuck_compiler_v1.asm +++ b/boot_code/brainfuck_compiler_v1.asm @@ -17,6 +17,7 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . +mov sp,#STACK mov bx,#bootup_msg mov ah,#0x02 bootup_print: @@ -239,4 +240,6 @@ RET bootup_msg: .ASCII 'Native brainfuck compiler v1\n' DATA: .BLKB 560 + .BLKB 200 +STACK: output_program: .BLKB 600 diff --git a/gtkwave_savefile.gtkw b/gtkwave_savefile.gtkw index b54c00f..d034799 100644 --- a/gtkwave_savefile.gtkw +++ b/gtkwave_savefile.gtkw @@ -1,35 +1,37 @@ [*] [*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI -[*] Tue Feb 14 12:39:46 2023 +[*] Tue Feb 21 04:41:50 2023 [*] -[dumpfile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/cpu/test.lx2" -[dumpfile_mtime] "Tue Feb 14 12:37:32 2023" -[dumpfile_size] 1922 -[savefile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/cpu/gtkwave_savefile.gtkw" -[timestart] 0 -[size] 1438 1059 +[dumpfile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/boot_code/brainfuck_compiled.lx2" +[dumpfile_mtime] "Tue Feb 21 04:40:18 2023" +[dumpfile_size] 21374 +[savefile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/gtkwave_savefile.gtkw" +[timestart] 513190000 +[size] 1342 1059 [pos] -1 -1 -*-23.795050 41712000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-23.795050 802940000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] tb. [treeopen] tb.p. [sst_width] 221 [signals_width] 293 [sst_expanded] 1 -[sst_vpaned_height] 313 +[sst_vpaned_height] 312 @28 tb.p.clock[0] tb.p.reset[0] -tb.p.state[4:0] +tb.p.state[5:0] +@23 +tb.p.ucode_seq_addr[4:0] @22 tb.p.external_address_bus[19:0] tb.p.external_data_bus[15:0] tb.p.CIR[15:0] tb.p.PARAM1[15:0] tb.p.PARAM2[15:0] -@29 -tb.p.read[0] @28 +tb.p.read[0] tb.p.write[0] tb.p.ERROR[0] +tb.p.SIMPLE_MICRO[0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/system/Makefile b/system/Makefile index 52a1092..099d75c 100644 --- a/system/Makefile +++ b/system/Makefile @@ -16,11 +16,11 @@ # along with this program. If not, see . # SOURCES=processor.v testbench.v memory.v registers.v alu.v decoder.v general.v -INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v ucode.hex +INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v ${MICROCODE} SYSTEM_VVP=system.vvp BOOT_CODE=boot_code.txt GTKWSAVE=../gtkwave_savefile.gtkw -MICROCODE=ucode.hex +MICROCODE=ucode.txt include ../common.mk diff --git a/system/decoder.v b/system/decoder.v index 711906b..9640ad2 100644 --- a/system/decoder.v +++ b/system/decoder.v @@ -43,16 +43,31 @@ assign DATA=ucode[ADDR]; endmodule module decoder( - input wire [15:0] CIR,input wire [15:0] FLAGS, output reg Wbit, output reg Sbit, output reg unaligning ,output reg opcode_size, output reg ERROR,output reg [`PROC_STATE_BITS-1:0]next_state - ,output reg [1:0]MOD, output reg [2:0]RM, output reg [15:0] PARAM1,output reg [15:0] PARAM2,output reg HALT,output reg has_operands + input wire [15:0] CIR,input wire [15:0] FLAGS, output wire [4:0] INSTRUCTION_INFO, output wire [1:0]DECODER_SIGNALS,output reg [`PROC_STATE_BITS-1:0]next_state + ,output reg [1:0]MOD, output reg [2:0]RM, output reg [15:0] PARAM1,output reg [15:0] PARAM2 ,output reg [1:0]in_alu1_sel1,output reg [1:0]in_alu1_sel2,output reg [2:0]out_alu1_sel - ,output reg [3:0]reg_read_port1_addr, output reg [3:0]reg_write_addr + ,output wire [11:0]REGISTER_FILE_CONTROL ,output reg [2:0]ALU_1OP + ,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input ); +reg [3:0]reg_read_port1_addr; +reg [3:0]reg_read_port2_addr; +reg [3:0]reg_write_addr; +assign REGISTER_FILE_CONTROL={reg_write_addr,reg_read_port1_addr,reg_read_port2_addr}; + +/* For correct fetching of instructions and global options for the alu */ +reg Wbit,Sbit,unaligning,opcode_size,has_operands; +assign INSTRUCTION_INFO={Wbit,Sbit,unaligning,opcode_size,has_operands}; + +reg ERROR, HALT; +assign DECODER_SIGNALS={ERROR,HALT}; + + + wire [`UCODE_DATA_BITS-1:0] ucode_data; reg [`UCODE_ADDR_BITS-1:0] UCODE_ADDR; -microcode ucode(UCODE_ADDR,ucode_data); +microcode ucode(seq_addr_input,ucode_data); /* 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 */ @@ -61,325 +76,379 @@ microcode ucode(UCODE_ADDR,ucode_data); `define start_unaligning_instruction unaligning=1; -always @( CIR ) begin - ERROR=0;HALT=0; - casex({CIR[15:8],CIR[5:3]}) - 11'b0000_010x_xxx : begin - /* Add Immediate word/byte to accumulator */ - /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/ - opcode_size=0; - has_operands=1; - Wbit=CIR[8:8]; - if(Wbit) - `start_unaligning_instruction - else - `start_aligning_instruction - MOD=2'b11; - in_alu1_sel1=2'b00; - in_alu1_sel2=2'b01; - out_alu1_sel=3'b011; - reg_read_port1_addr={Wbit,3'b000}; - reg_write_addr={Wbit,3'b000}; - ALU_1OP=`ALU_OP_ADD; - if(Wbit==1) - next_state=`PROC_DE_LOAD_16_PARAM; - else begin - PARAM1[7:0]=CIR[7:0]; - next_state=`PROC_EX_STATE_ENTRY; - end - end - 11'b1000_00xx_000 : begin - /* Add Immediate word/byte to register/memory */ - /* 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 - opcode_size=1; - has_operands=1; - Wbit=CIR[8:8]; - Sbit=CIR[9:9]; - MOD=2'b11; - in_alu1_sel1=2'b00; - in_alu1_sel2=2'b01; - out_alu1_sel={1'b0,MOD}; - reg_read_port1_addr={Wbit,RM}; - reg_write_addr={Wbit,RM}; - ALU_1OP=`ALU_OP_ADD; - next_state=`PROC_DE_LOAD_16_PARAM; - if(Wbit==1) - next_state=`PROC_DE_LOAD_16_PARAM; - else begin - `invalid_instruction /*do 8bit loads*/ - end - end - 11'b1000_00xx_111 : begin - /* CMP - compare Immediate with register / memory */ - /* 1 0 0 0 0 0 S W | MOD 1 1 1 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */ - opcode_size=1; - has_operands=1; - Wbit=CIR[8:8]; - Sbit=CIR[9:9]; - MOD=CIR[7:6]; - RM=CIR[2:0]; - if(((Wbit==1)&&(Sbit==1))||Wbit==0)begin - `start_unaligning_instruction - end else begin - `invalid_instruction; - end - if(MOD==2'b11)begin +always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin + if (SIMPLE_MICRO==0)begin + ERROR=0;HALT=0; + casex({CIR[15:8],CIR[5:3]}) + 11'b0000_010x_xxx : begin + /* Add Immediate word/byte to accumulator */ + /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + opcode_size=0; + has_operands=1; + Wbit=CIR[8:8]; + if(Wbit) + `start_unaligning_instruction + else + `start_aligning_instruction + MOD=2'b11; in_alu1_sel1=2'b00; in_alu1_sel2=2'b01; - reg_read_port1_addr={Wbit,RM}; + out_alu1_sel=3'b011; + reg_read_port2_addr={Wbit,3'b000}; + reg_write_addr={Wbit,3'b000}; + ALU_1OP=`ALU_OP_ADD; + if(Wbit==1) + next_state=`PROC_DE_LOAD_16_PARAM; + else begin + PARAM1[7:0]=CIR[7:0]; + next_state=`PROC_EX_STATE_ENTRY; + end + end + 11'b1000_00xx_000 : begin + /* Add Immediate word/byte to register/memory */ + /* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + `start_aligning_instruction + opcode_size=1; + has_operands=1; + Wbit=CIR[8:8]; + Sbit=CIR[9:9]; + MOD=2'b11; + in_alu1_sel1=2'b00; + in_alu1_sel2=2'b01; + out_alu1_sel={1'b0,MOD}; + reg_read_port2_addr={Wbit,RM}; + reg_write_addr={Wbit,RM}; + ALU_1OP=`ALU_OP_ADD; + next_state=`PROC_DE_LOAD_16_PARAM; + if(Wbit==1) + next_state=`PROC_DE_LOAD_16_PARAM; + else begin + `invalid_instruction /*do 8bit loads*/ + end + end + 11'b1000_00xx_111 : begin + /* CMP - compare Immediate with register / memory */ + /* 1 0 0 0 0 0 S W | MOD 1 1 1 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + opcode_size=1; + has_operands=1; + Wbit=CIR[8:8]; + Sbit=CIR[9:9]; + MOD=CIR[7:6]; + RM=CIR[2:0]; + if(((Wbit==1)&&(Sbit==1))||Wbit==0)begin + `start_unaligning_instruction + end else begin + `invalid_instruction; + end + if(MOD==2'b11)begin + in_alu1_sel1=2'b00; + in_alu1_sel2=2'b01; + reg_read_port2_addr={Wbit,RM}; + out_alu1_sel=3'b100; + ALU_1OP=`ALU_OP_SUB; + next_state=`PROC_DE_LOAD_8_PARAM; + end else begin + `invalid_instruction + end + end + 11'b1011_0xxx_xxx : begin + /* MOV - Move Immediate byte to register */ + /* 1 0 1 1 W REG | DATA | DATA if W |*/ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + `start_aligning_instruction + has_operands=1; + Wbit=CIR[11:11]; /* IS 0 */ + opcode_size=0; + MOD=2'b11; + in_alu1_sel1=2'b00; + in_alu1_sel2=2'b00; + out_alu1_sel=3'b011; + reg_write_addr={1'b0,CIR[10:8]}; + PARAM1[7:0]=CIR[7:0]; + PARAM2=0; + ALU_1OP=`ALU_OP_ADD; + next_state=`PROC_EX_STATE_ENTRY; + end + 11'b1011_1xxx_xxx : begin + /*MOV - Move Immediate word to register*/ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + `start_unaligning_instruction + has_operands=1; + Wbit=CIR[11:11]; /*IS 1 */ + opcode_size=0; + MOD=2'b11; + in_alu1_sel1=2'b00; + in_alu1_sel2=2'b00; + out_alu1_sel=3'b011; + reg_write_addr={1'b1,CIR[10:8]}; + ALU_1OP=`ALU_OP_ADD; + PARAM2=0; + next_state=`PROC_DE_LOAD_16_PARAM; + end + + 11'b1000_10xx_xxx : begin + /* MOV - Reg/Mem to/from register */ + /* 1 0 0 0 1 0 D W | MOD REG RM | < DISP LO > | < DISP HI > |*/ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=0; + `start_aligning_instruction + opcode_size=1; + MOD=CIR[7:6]; + RM=CIR[2:0]; + Wbit=CIR[8:8]; + in_alu1_sel2=2'b00; + if(CIR[9:9] == 1)begin + /* Mem/Reg to reg */ + if(MOD==2'b11)begin + /*Reg to Reg*/ + in_alu1_sel1=2'b01; + reg_read_port1_addr={Wbit,RM}; + next_state=`PROC_EX_STATE_ENTRY; + end else begin + /*Mem to Reg*/ + in_alu1_sel1=2'b00; + next_state=`RPOC_MEMIO_READ; + end + out_alu1_sel=3'b011; + reg_write_addr={Wbit,CIR[5:3]}; + end else begin + /* Reg to Mem/Reg */ + if(MOD==2'b11)begin + /*Reg to Reg*/ + in_alu1_sel1=2'b01; + out_alu1_sel=3'b011; + reg_write_addr={Wbit,RM}; + next_state=`PROC_EX_STATE_ENTRY; + end else begin + /*Reg to Mem*/ + in_alu1_sel1=2'b00; + reg_read_port1_addr={Wbit,CIR[5:3]}; + out_alu1_sel={1'b0,MOD}; + next_state=`PROC_DE_LOAD_REG_TO_PARAM; + end + reg_read_port1_addr={Wbit,CIR[5:3]}; + end + + ALU_1OP=`ALU_OP_ADD; + PARAM2=0; + end + 11'b0100_xxxx_xxx:begin//DEC + /* DEC - Decrement Register */ + /* | 0 1 0 0 1 REG | */ + /* INC - Increment Register */ + /* | 0 1 0 0 0 REG | */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=0; + opcode_size=0; + `start_unaligning_instruction + Wbit=1; + in_alu1_sel1=2'b01; + in_alu1_sel2=2'b00; + out_alu1_sel=3'b011; + MOD=2'b11; + PARAM2=1; + reg_read_port1_addr={1'b1,CIR[10:8]}; + reg_write_addr={1'b1,CIR[10:8]}; + if(CIR[11:11]==0) + ALU_1OP=`ALU_OP_ADD; + else + ALU_1OP=`ALU_OP_SUB; + next_state=`PROC_EX_STATE_ENTRY; + end + 11'b1111_111x_00x : begin + /* INC - Register/Memory */ + /* 1 1 1 1 1 1 1 W | MOD 0 0 0 R/M | < DISP LO> | < DISP HI> */ + /* DEC - Register/Memory */ + /* 1 1 1 1 1 1 1 W | MOD 0 0 1 R/M | < DISP LO> | < DISP HI> */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=1; + opcode_size=1; + `start_aligning_instruction + Wbit=CIR[8:8]; + MOD=CIR[7:6]; + RM=CIR[2:0]; + in_alu1_sel1=(MOD==2'b11)? 2'b01 : 2'b00; + in_alu1_sel2=2'b00;/* number 1 */ + PARAM2=1; + out_alu1_sel={1'b0,MOD}; + + /*in case MOD=11 */ + reg_read_port1_addr={1'b0,RM}; + reg_write_addr={1'b0,RM}; + + ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB:`ALU_OP_ADD; + if ( MOD == 2'b11 ) + next_state=`PROC_EX_STATE_ENTRY; + else + next_state=`RPOC_MEMIO_READ; + end + 11'b1111_0100_xxx : begin + /* HLT - Halt */ + /* 1 1 1 1 0 1 0 0 | */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=0; + opcode_size=0; + `start_unaligning_instruction + MOD=2'b11; + HALT=1; + next_state=`PROC_HALT_STATE; + end + 11'b0011_110x_xxx : begin + /* CMP - Compare Immediate with accumulator */ + /* 0 0 1 1 1 1 0 W | DATA | DATA if W |*/ + /* */ + /* NOTE: 8086 doc doesn't show the third byte but the */ + /* W flag and my assembler seem to disagree */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + Wbit=CIR[8:8]; + opcode_size=0; + has_operands=1; + if(Wbit) + `start_unaligning_instruction + else + `start_aligning_instruction + MOD=2'b11; + in_alu1_sel1=2'b00; + in_alu1_sel2=2'b01; + reg_read_port2_addr={Wbit,3'b000}; out_alu1_sel=3'b100; ALU_1OP=`ALU_OP_SUB; - next_state=`PROC_DE_LOAD_8_PARAM; - end else begin + if(Wbit==1) + next_state=`PROC_DE_LOAD_16_PARAM; + else begin + PARAM1[7:0]=CIR[7:0]; + next_state=`PROC_EX_STATE_ENTRY; + end + end + 11'b0111_xxxx_xxx:begin + /* Conditional relative jumps */ + /* JE/JZ - Jump on Zero */ + /* 0 1 1 1 0 1 0 0 | IP-INC8 |*/ + /* JS - Jump on Sign */ + /* 0 1 1 1 1 0 0 0 | IP-INC8 |*/ + /* JNS -Jump on not Sign */ + /* 0 1 1 1 1 0 0 1 | IP-INC8 |*/ + /* .... */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=1; + `start_aligning_instruction + Wbit=1; + opcode_size=0; + in_alu1_sel1=2'b10; + in_alu1_sel2=2'b00; + PARAM2={{8{CIR[7:7]}},CIR[7:0]}; + ALU_1OP=`ALU_OP_ADD_SIGNED_B; + out_alu1_sel=3'b101; + case(CIR[11:9]) + 3'b000: begin + /* Jump on (not) Overflow */ + if(FLAGS[11:11]==CIR[8:8]) + next_state=`PROC_IF_STATE_ENTRY; + else begin + next_state=`PROC_EX_STATE_ENTRY; + end + end + 3'b010: begin + /* Jump on (not) Zero */ + if(FLAGS[6:6]==CIR[8:8]) + next_state=`PROC_IF_STATE_ENTRY; + else + next_state=`PROC_EX_STATE_ENTRY; + end + 3'b100: begin + /* Jump on (not) Sign */ + if(FLAGS[7:7]==CIR[8:8]) + next_state=`PROC_IF_STATE_ENTRY; + else + next_state=`PROC_EX_STATE_ENTRY; + end + 3'b101: begin + /* Jump on (not) Parity */ + if(FLAGS[2:2]==CIR[8:8]) + next_state=`PROC_IF_STATE_ENTRY; + else + next_state=`PROC_EX_STATE_ENTRY; + end + default:begin + `invalid_instruction; /*We don't support that condition*/ + end + endcase + end + 11'b1110_1011_xxx:begin + /* JMP - Unconditional jump direct within segment (short) */ + /* | 1 1 1 0 1 0 1 1 | IP-INC-LO | */ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + `start_aligning_instruction + opcode_size=0; + has_operands=1; + Wbit=1; + in_alu1_sel1=2'b10; + in_alu1_sel2=2'b00; + PARAM2={{8{CIR[7:7]}},CIR[7:0]}; + ALU_1OP=`ALU_OP_ADD_SIGNED_B; + out_alu1_sel=3'b101; + next_state=`PROC_EX_STATE_ENTRY; + end + 11'b1100_1101_xxx:begin + /* INT - execute interrupt handler */ + /* 1 1 0 0 1 1 0 1 | DATA |*/ + seq_addr_entry=`UCODE_NO_INSTRUCTION; + has_operands=1; + opcode_size=0; + `start_aligning_instruction + /* Emulate MS-DOS print routines */ + if(CIR[7:0]==8'h21 && register_file.registers[0][15:8]==8'h02)begin + $write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/ + end + next_state=`PROC_IF_STATE_ENTRY; + end + 11'b11101000_xxx:begin + /* CALL - Direct call within segment */ + /* 1 1 1 0 1 0 0 0 | IP-INC-LO | IP-INC-HI |*/ + + // Microcode instruction + `start_unaligning_instruction + opcode_size=0; + has_operands=1; + Wbit=1; + Sbit=1; + PARAM2=2; //substract from sp + seq_addr_entry=`UCODE_CALL_ENTRY; + end + default:begin `invalid_instruction end - end - 11'b1011_0xxx_xxx : begin - /* MOV - Move Immediate byte to register */ - /* 1 0 1 1 W REG | DATA | DATA if W |*/ - `start_aligning_instruction - has_operands=1; - Wbit=CIR[11:11]; /* IS 0 */ - opcode_size=0; - MOD=2'b11; - in_alu1_sel1=2'b00; - in_alu1_sel2=2'b00; - out_alu1_sel=3'b011; - reg_write_addr={1'b0,CIR[10:8]}; - PARAM1[7:0]=CIR[7:0]; - PARAM2=0; - ALU_1OP=`ALU_OP_ADD; - next_state=`PROC_EX_STATE_ENTRY; - end - 11'b1011_1xxx_xxx : begin - /*MOV - Move Immediate word to register*/ - `start_unaligning_instruction - has_operands=1; - Wbit=CIR[11:11]; /*IS 1 */ - opcode_size=0; - MOD=2'b11; - in_alu1_sel1=2'b00; - in_alu1_sel2=2'b00; - out_alu1_sel=3'b011; - reg_write_addr={1'b1,CIR[10:8]}; - ALU_1OP=`ALU_OP_ADD; - PARAM2=0; - next_state=`PROC_DE_LOAD_16_PARAM; - end - - 11'b1000_10xx_xxx : begin - /* MOV - Reg/Mem to/from register */ - /* 1 0 0 0 1 0 D W | MOD REG RM | < DISP LO > | < DISP HI > |*/ - has_operands=0; - `start_aligning_instruction - opcode_size=1; - MOD=CIR[7:6]; - RM=CIR[2:0]; - Wbit=CIR[8:8]; - in_alu1_sel2=2'b00; - if(CIR[9:9] == 1)begin - /* Mem/Reg to reg */ - if(MOD==2'b11)begin - /*Reg to Reg*/ - in_alu1_sel1=2'b01; - reg_read_port1_addr={Wbit,RM}; - next_state=`PROC_EX_STATE_ENTRY; - end else begin - /*Mem to Reg*/ - in_alu1_sel1=2'b00; - next_state=`RPOC_MEMIO_READ; - end - out_alu1_sel=3'b011; - reg_write_addr={Wbit,CIR[5:3]}; - end else begin - /* Reg to Mem/Reg */ - if(MOD==2'b11)begin - /*Reg to Reg*/ - in_alu1_sel1=2'b01; - out_alu1_sel=3'b011; - reg_write_addr={Wbit,RM}; - next_state=`PROC_EX_STATE_ENTRY; - end else begin - /*Reg to Mem*/ - in_alu1_sel1=2'b00; - reg_read_port1_addr={Wbit,CIR[5:3]}; - out_alu1_sel={1'b0,MOD}; - next_state=`PROC_DE_LOAD_REG_TO_PARAM; - end - reg_read_port1_addr={Wbit,CIR[5:3]}; - end - - ALU_1OP=`ALU_OP_ADD; - PARAM2=0; - end - 11'b0100_xxxx_xxx:begin//DEC - /* DEC - Decrement Register */ - /* | 0 1 0 0 1 REG | */ - /* INC - Increment Register */ - /* | 0 1 0 0 0 REG | */ - has_operands=0; - opcode_size=0; - `start_unaligning_instruction - Wbit=1; - in_alu1_sel1=2'b01; - in_alu1_sel2=2'b00; - out_alu1_sel=3'b011; - MOD=2'b11; - PARAM2=1; - reg_read_port1_addr={1'b1,CIR[10:8]}; - reg_write_addr={1'b1,CIR[10:8]}; - if(CIR[11:11]==0) - ALU_1OP=`ALU_OP_ADD; - else - ALU_1OP=`ALU_OP_SUB; - next_state=`PROC_EX_STATE_ENTRY; - end - 11'b1111_111x_00x : begin - /* INC - Register/Memory */ - /* 1 1 1 1 1 1 1 W | MOD 0 0 0 R/M | < DISP LO> | < DISP HI> */ - /* DEC - Register/Memory */ - /* 1 1 1 1 1 1 1 W | MOD 0 0 1 R/M | < DISP LO> | < DISP HI> */ - has_operands=1; - opcode_size=1; - `start_aligning_instruction - Wbit=CIR[8:8]; - MOD=CIR[7:6]; - RM=CIR[2:0]; - in_alu1_sel1=(MOD==2'b11)? 2'b01 : 2'b00; - in_alu1_sel2=2'b00;/* number 1 */ - PARAM2=1; - out_alu1_sel={1'b0,MOD}; - - /*in case MOD=11 */ - reg_read_port1_addr={1'b0,RM}; - reg_write_addr={1'b0,RM}; - - ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB:`ALU_OP_ADD; - if ( MOD == 2'b11 ) - next_state=`PROC_EX_STATE_ENTRY; - else - next_state=`RPOC_MEMIO_READ; - end - 11'b1111_0100_xxx : begin - /* HLT - Halt */ - /* 1 1 1 1 0 1 0 0 | */ - has_operands=0; - opcode_size=0; - `start_unaligning_instruction - MOD=2'b11; - HALT=1; - next_state=`PROC_HALT_STATE; - end - 11'b0011_110x_xxx : begin - /* CMP - Compare Immediate with accumulator */ - /* 0 0 1 1 1 1 0 W | DATA | DATA if W |*/ - /* */ - /* NOTE: 8086 doc doesn't show the third byte but the */ - /* W flag and my assembler seem to disagree */ - Wbit=CIR[8:8]; - opcode_size=0; - has_operands=1; - if(Wbit) - `start_unaligning_instruction - else - `start_aligning_instruction - MOD=2'b11; - in_alu1_sel1=2'b00; - in_alu1_sel2=2'b01; - reg_read_port1_addr={Wbit,3'b000}; - out_alu1_sel=3'b100; - ALU_1OP=`ALU_OP_SUB; - if(Wbit==1) - next_state=`PROC_DE_LOAD_16_PARAM; - else begin - PARAM1[7:0]=CIR[7:0]; - next_state=`PROC_EX_STATE_ENTRY; - end - end - 11'b0111_xxxx_xxx:begin - /* Conditional relative jumps */ - /* JE/JZ - Jump on Zero */ - /* 0 1 1 1 0 1 0 0 | IP-INC8 |*/ - /* JS - Jump on Sign */ - /* 0 1 1 1 1 0 0 0 | IP-INC8 |*/ - /* JNS -Jump on not Sign */ - /* 0 1 1 1 1 0 0 1 | IP-INC8 |*/ - /* .... */ - has_operands=1; - `start_aligning_instruction - Wbit=1; - opcode_size=0; - in_alu1_sel1=2'b10; - in_alu1_sel2=2'b00; - PARAM2={{8{CIR[7:7]}},CIR[7:0]}; - ALU_1OP=`ALU_OP_ADD_SIGNED_B; - out_alu1_sel=3'b101; - case(CIR[11:9]) - 3'b000: begin - /* Jump on (not) Overflow */ - if(FLAGS[11:11]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; - else begin - next_state=`PROC_EX_STATE_ENTRY; - end - end - 3'b010: begin - /* Jump on (not) Zero */ - if(FLAGS[6:6]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; - else - next_state=`PROC_EX_STATE_ENTRY; - end - 3'b100: begin - /* Jump on (not) Sign */ - if(FLAGS[7:7]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; - else - next_state=`PROC_EX_STATE_ENTRY; - end - 3'b101: begin - /* Jump on (not) Parity */ - if(FLAGS[2:2]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; - else - next_state=`PROC_EX_STATE_ENTRY; - end - default:begin - `invalid_instruction; /*We don't support that condition*/ - end - endcase - end - 11'b1110_1011_xxx:begin - /* JMP - Unconditional jump direct within segment (short) */ - /* | 1 1 1 0 1 0 1 1 | IP-INC-LO | */ - `start_aligning_instruction - opcode_size=0; - has_operands=1; - Wbit=1; - in_alu1_sel1=2'b10; - in_alu1_sel2=2'b00; - PARAM2={{8{CIR[7:7]}},CIR[7:0]}; - ALU_1OP=`ALU_OP_ADD_SIGNED_B; - out_alu1_sel=3'b101; - next_state=`PROC_EX_STATE_ENTRY; - end - 11'b1100_1101_xxx:begin - /* INT - execute interrupt handler */ - /* 1 1 0 0 1 1 0 1 | DATA |*/ - has_operands=1; - opcode_size=0; - `start_aligning_instruction - /* Emulate MS-DOS print routines */ - if(CIR[7:0]==8'h21 && register_file.registers[0][15:8]==8'h02)begin - $write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/ - end - next_state=`PROC_IF_STATE_ENTRY; - end - default:begin - `invalid_instruction - end - endcase + endcase + end else begin + /*Microcode output*/ + //Sbit, Wbit, opcode_size and the others are still latched + //from when we ordered the switch to microcode + seq_addr_entry=ucode_data[5:0]; + case(ucode_data[7:6]) + 2'b00: next_state=`PROC_EX_STATE_ENTRY; + 2'b01: next_state=`PROC_DE_LOAD_16_PARAM; + 2'b10: next_state=`PROC_DE_LOAD_8_PARAM; + 2'b11: next_state=`PROC_DE_LOAD_REG_TO_PARAM; + endcase + reg_write_addr=ucode_data[11:8 ]; + in_alu1_sel1 =ucode_data[13:12]; + in_alu1_sel2 =ucode_data[15:14]; + out_alu1_sel =ucode_data[18:16]; + /*1:1 map essentially but I want to keep the spec for these bits seperate + * from the alu op select bits*/ + case(ucode_data[21:19]) + 3'b000: ALU_1OP=`ALU_OP_ADD; + 3'b001: ALU_1OP=`ALU_OP_SUB; + 3'b010: ALU_1OP=`ALU_OP_AND; + 3'b011: ALU_1OP=`ALU_OP_OR; + 3'b100: ALU_1OP=`ALU_OP_XOR; + 3'b101: ALU_1OP=`ALU_OP_ADD_SIGNED_B; + endcase + reg_read_port1_addr=ucode_data[25:22]; + end end endmodule diff --git a/system/proc_state_def.v b/system/proc_state_def.v index a747d89..9fa542a 100644 --- a/system/proc_state_def.v +++ b/system/proc_state_def.v @@ -18,49 +18,51 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -`define PROC_STATE_BITS 5 +`define PROC_STATE_BITS 6 -`define PROC_HALT_STATE 5'b00000 +`define PROC_HALT_STATE 6'b000000 /*INSTRUCTION FETCH STATE*/ -`define PROC_IF_STATE_ENTRY 5'b00001 -`define PROC_IF_WRITE_CIR 5'b00010 -`define PROC_IF_STATE_EXTRA_FETCH_SET 5'b00011 -`define PROC_IF_STATE_EXTRA_FETCH 5'b00100 +`define PROC_IF_STATE_ENTRY 6'b000001 +`define PROC_IF_WRITE_CIR 6'b000010 +`define PROC_IF_STATE_EXTRA_FETCH_SET 6'b000011 +`define PROC_IF_STATE_EXTRA_FETCH 6'b000100 /*DECODE SATE*/ -`define PROC_DE_STATE_ENTRY 5'b01000 -`define PROC_DE_LOAD_16_PARAM 5'b01001 -`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 5'b01010 -`define PROC_DE_LOAD_16_EXTRA_FETCH 5'b01011 -`define PROC_DE_LOAD_REG_TO_PARAM 5'b11011 /****/ +`define PROC_DE_STATE_ENTRY 6'b001000 +`define PROC_DE_LOAD_16_PARAM 6'b001001 +`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 6'b001010 +`define PROC_DE_LOAD_16_EXTRA_FETCH 6'b001011 +`define PROC_DE_LOAD_REG_TO_PARAM 6'b001100 /*MEM/IO READ*/ -`define RPOC_MEMIO_READ 5'b10000 -`define PROC_MEMIO_READ_SETADDR 5'b10001 -`define PROC_MEMIO_GET_ALIGNED_DATA 5'b10010 /* :) */ -`define PROC_MEMIO_GET_UNALIGNED_DATA 5'b10011 /* :( */ -`define PROC_MEMIO_GET_SECOND_BYTE 5'b11100 /******/ -`define PROC_MEMIO_GET_SECOND_BYTE1 5'b11101 /******/ -`define PROC_DE_LOAD_8_PARAM 5'b00110 /******/ -`define PROC_DE_LOAD_8_PARAM_UNALIGNED 5'b00111 /******/ +`define RPOC_MEMIO_READ 6'b010000 +`define PROC_MEMIO_READ_SETADDR 6'b010001 +`define PROC_MEMIO_GET_ALIGNED_DATA 6'b010010 /* :) */ +`define PROC_MEMIO_GET_UNALIGNED_DATA 6'b010011 /* :( */ +`define PROC_MEMIO_GET_SECOND_BYTE 6'b010100 +`define PROC_MEMIO_GET_SECOND_BYTE1 6'b010101 +`define PROC_DE_LOAD_8_PARAM 6'b010110 +`define PROC_DE_LOAD_8_PARAM_UNALIGNED 6'b010111 /*EXECUTE STATE*/ -`define PROC_EX_STATE_ENTRY 5'b11000 -`define PROC_EX_STATE_EXIT 5'b11001 +`define PROC_EX_STATE_ENTRY 6'b100000 +`define PROC_EX_STATE_EXIT 6'b100001 /*MEM/IO WRITE*/ -`define PROC_MEMIO_WRITE 5'b10100 -//`define PROC_MEMIO_WRITE_SETADDR 5'b10101 -`define PROC_MEMIO_PUT_ALIGNED_DATA 5'b10101 -`define PROC_MEMIO_PUT_UNALIGNED_DATA 5'b10110 -`define PROC_MEMIO_PUT_BYTE 5'b10111 -`define PROC_MEMIO_PUT_BYTE_STOP_READ 5'b11110 /****/ -`define PROC_MEMIO_WRITE_EXIT 5'b11111 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_FIRST_BYTE 5'b00101 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT 5'b01100 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT1 5'b01101 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2 5'b01110 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT3 5'b01111 /****/ -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT4 5'b11010 /****/ +`define PROC_MEMIO_WRITE 6'b101000 +//`define PROC_MEMIO_WRITE_SETADDR 6'b010101 +`define PROC_MEMIO_PUT_ALIGNED_DATA 6'b101001 +`define PROC_MEMIO_PUT_UNALIGNED_DATA 6'b101010 +`define PROC_MEMIO_PUT_BYTE 6'b101011 +`define PROC_MEMIO_PUT_BYTE_STOP_READ 6'b101100 +`define PROC_MEMIO_WRITE_EXIT 6'b101101 +`define PROC_MEMIO_PUT_UNALIGNED_FIRST_BYTE 6'b101110 +`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT 6'b101111 +`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT1 6'b110001 +`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2 6'b110010 +`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT3 6'b110011 +`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT4 6'b110100 + +`define PROC_NEXT_MICROCODE 6'b111000 diff --git a/system/processor.v b/system/processor.v index e3da91b..f3ad4e8 100644 --- a/system/processor.v +++ b/system/processor.v @@ -20,6 +20,7 @@ `include "proc_state_def.v" `include "alu_header.v" `include "config.v" +`include "ucode_header.v" module processor ( input clock, input reset, output reg [19:0] external_address_bus, inout [15:0] external_data_bus,output reg read, output reg write, output reg HALT,output reg ERROR); @@ -31,63 +32,68 @@ assign external_data_bus=read?data_bus_output_register:16'hz; reg [`PROC_STATE_BITS-1:0] state; -/* Decoder */ -wire Wbit, Sbit, unaligning_instruction; +/*############ Decoder ########################################################## */ +wire Wbit, Sbit, unaligning_instruction,opcode_size, has_operands; wire [`PROC_STATE_BITS-1:0] next_state; wire [1:0]MOD; wire [2:0]RM; -wire [15:0]DE_PARAM1; +wire [15:0]DE_PARAM1;// Input param1 form decoder to alu wire [15:0]DE_PARAM2; wire DE_ERROR,DE_HALT; -wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr; -wire opcode_size; -wire has_operands; +wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr,DE_reg_read_port2_addr; +wire [11:0]DE_REGISTER_CONTROL; +wire [4:0]INSTRUCTION_INFO; +wire [1:0]DECODER_SIGNALS; +wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; + +reg SIMPLE_MICRO; /* otuput simple decodings (=0) or microcode data (=1) */ + decoder decoder( - CIR,FLAGS,Wbit,Sbit,unaligning_instruction,opcode_size,DE_ERROR,next_state - ,MOD,RM,DE_PARAM1,DE_PARAM2,DE_HALT,has_operands + CIR,FLAGS,INSTRUCTION_INFO,DECODER_SIGNALS,next_state + ,MOD,RM,DE_PARAM1,DE_PARAM2 ,in_alu1_sel1,in_alu1_sel2,out_alu1_sel - ,DE_reg_read_port1_addr,DE_reg_write_addr + ,DE_REGISTER_CONTROL ,ALU_1OP + ,ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr ); -// Registers -reg [19:0] ProgCount; /*TODO consider having single circuit to increment PC instead of having possible lots of adders all over the code*/ +assign Wbit=INSTRUCTION_INFO[4:4]; +assign Sbit=INSTRUCTION_INFO[3:3]; +assign unaligning_instruction=INSTRUCTION_INFO[2:2]; +assign opcode_size=INSTRUCTION_INFO[1:1]; +assign has_operands=INSTRUCTION_INFO[0:0]; + +assign DE_reg_write_addr=DE_REGISTER_CONTROL[11:8]; +assign DE_reg_read_port1_addr=DE_REGISTER_CONTROL[7:4]; +assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0]; + +assign DE_HALT=DECODER_SIGNALS[0:0]; +assign DE_ERROR=DECODER_SIGNALS[1:1]; + +reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; + +/*############ REGISTERS ########################################################## */ + +reg [19:0] ProgCount; //TODO: do i create a lot of adders each place i increment it? reg [15:0] CIR; reg [15:0] PARAM1; reg [15:0] PARAM2; reg one_byte_instruction; reg unaligned_access; +reg we_jumped; /*Only used to signify that a microcoded instruction jumped and we should not update the unaligned_access bit after the end of the instruction*/ reg [15:0]FLAGS; reg [15:0] BYTE_WRITE_TEMP_REG;//we read 16bits here if we want to change just 8 and leave the rest - -/*** RESET LOGIC ***/ -always @(negedge reset) begin - if (reset==0) begin - @(posedge clock); - state=`PROC_HALT_STATE; - ProgCount=0;//TODO: Reset Vector - HALT=0; - reg_write_we=1; - unaligned_access=0; - @(posedge reset) - @(negedge clock); - state=`PROC_IF_STATE_ENTRY; - one_byte_instruction=0; - ERROR=0; - end -end - -/*** ALU and EXEC stage logic ***/ - //Architectural Register file reg [3:0] reg_write_addr; wire [15:0] reg_write_data; reg reg_write_we; reg [3:0] reg_read_port1_addr; reg [15:0] reg_read_port1_data; +reg [3:0] reg_read_port2_addr; +reg [15:0] reg_read_port2_data; reg [1:0] reg_write_in_sel; mux4 #(.WIDTH(16)) REG_FILE_WRITE_IN_MUX( ALU_1O, @@ -96,9 +102,10 @@ mux4 #(.WIDTH(16)) REG_FILE_WRITE_IN_MUX( 16'hz, reg_write_in_sel, reg_write_data); -register_file register_file(reg_write_addr,reg_write_data,reg_write_we,reg_read_port1_addr,reg_read_port1_data); +register_file register_file(reg_write_addr,reg_write_data,reg_write_we,reg_read_port1_addr,reg_read_port1_data,reg_read_port2_addr,reg_read_port2_data); -/**** ALU 1 ******/ +/*############ ALU / Execution units ########################################################## */ +// ALU 1 reg [1:0] in_alu1_sel1; reg [1:0] in_alu1_sel2; /* out_alu1_sel : { EXTRA_FUNCTIONS_BIT[0:0], MOD_OR_EXTRA_FUNCTION[1:0] } */ @@ -107,16 +114,16 @@ reg [2:0] out_alu1_sel; mux4 #(.WIDTH(16)) MUX16_1A( PARAM1, reg_read_port1_data, - {ProgCount[14:0],unaligned_access}, - 16'b0, + {ProgCount[14:0],unaligned_access^unaligning_instruction}, + 16'b0000000000000000, /*0 Constant*/ in_alu1_sel1, ALU_1A); mux4 #(.WIDTH(16)) MUX16_1B( PARAM2, - reg_read_port1_data, - {ProgCount[14:0],unaligned_access}, - 16'b0, + reg_read_port2_data, + {ProgCount[14:0],unaligned_access^unaligning_instruction}, + 16'b0000000000000001, /*1 Constant*/ in_alu1_sel2, ALU_1B); @@ -127,6 +134,27 @@ reg [`ALU_OP_BITS-1:0]ALU_1OP; wire [7:0] ALU_1FLAGS; ALU ALU1(ALU_1A,ALU_1B,ALU_1O,ALU_1OP,ALU_1FLAGS,Wbit); +/*############ Processor state machine ########################################################## */ + +/*** RESET LOGIC ***/ +always @(negedge reset) begin + if (reset==0) begin + @(posedge clock); + state=`PROC_HALT_STATE; + ucode_seq_addr=`UCODE_NO_INSTRUCTION; + ProgCount=0;//TODO: Reset Vector + HALT=0; + reg_write_we=1; + unaligned_access=0; + @(posedge reset) + @(negedge clock); + state=`PROC_IF_STATE_ENTRY; + one_byte_instruction=0; + ERROR=0; + SIMPLE_MICRO=0; + end +end + /*** Processor stages ***/ `define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1; @@ -152,7 +180,11 @@ always @(negedge clock) begin state=`PROC_DE_STATE_ENTRY; end `PROC_EX_STATE_EXIT:begin - unaligned_access=unaligning_instruction^unaligned_access; + /*Don't update the unaligned_access for Instruction + * Fetch if we are doing microcode execution, it will + * be done by decode at the end*/ + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + unaligned_access=unaligning_instruction^unaligned_access; case(out_alu1_sel) /*TODO: use RM*/ 3'b000, 3'b001, @@ -197,15 +229,31 @@ always @(negedge clock) begin end 3'b011:begin reg_write_we=0; - state=`PROC_IF_STATE_ENTRY; + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + state=`PROC_IF_STATE_ENTRY; + else + state=`PROC_NEXT_MICROCODE; end - 3'b101:begin + 3'b100:begin /*No output*/ + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + state=`PROC_IF_STATE_ENTRY; + else + state=`PROC_NEXT_MICROCODE; + end + 3'b101:begin /* Program Counter*/ + //if(SIMPLE_MICRO==1) + // ERROR=1; ProgCount={5'b00000,ALU_1O[15:1]}; unaligned_access=ALU_1O[0:0]; - state=`PROC_IF_STATE_ENTRY; + we_jumped=1; + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + state=`PROC_IF_STATE_ENTRY; + else + state=`PROC_NEXT_MICROCODE; end - 3'b100:begin - state=`PROC_IF_STATE_ENTRY; + 3'b110:begin /* Indirect write on SP */ + reg_read_port1_addr=4'b1100; + state=`PROC_MEMIO_WRITE; end default:begin `invalid_instruction @@ -226,7 +274,10 @@ always @(negedge clock) begin end `PROC_MEMIO_WRITE_EXIT:begin write=0; - state=`PROC_IF_STATE_ENTRY; + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + state=`PROC_IF_STATE_ENTRY; + else + state=`PROC_NEXT_MICROCODE; end `PROC_MEMIO_PUT_ALIGNED_DATA:begin read=1; @@ -283,6 +334,7 @@ always @(posedge clock) begin reg_write_we=1; state=`PROC_IF_WRITE_CIR; reg_write_in_sel=2'b00; + we_jumped=0; end `PROC_IF_STATE_EXTRA_FETCH_SET:begin ProgCount=ProgCount+1; @@ -300,13 +352,28 @@ always @(posedge clock) begin * external_data_bus contains at least some unknown data */ one_byte_instruction=(!has_operands)&&(!opcode_size); external_address_bus = ProgCount; - state=next_state; - PARAM1=DE_PARAM1; - PARAM2=DE_PARAM2; + if(SIMPLE_MICRO==0)begin + /* We cannot set these directly within + * microcode so don't overwirte useful values + * each time the next microcode is executed. + * Note this still allows to set initial values + * at the start of the microcode */ + PARAM1=DE_PARAM1; + PARAM2=DE_PARAM2; + end ERROR=DE_ERROR; HALT=DE_HALT; reg_read_port1_addr=DE_reg_read_port1_addr; + reg_read_port2_addr=DE_reg_read_port2_addr; reg_write_addr=DE_reg_write_addr; + if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin + /*switch to microcode decoding*/ + ucode_seq_addr=ucode_seq_addr_entry; + SIMPLE_MICRO=1; + /*keep state the same and rerun decode this time with all the data from the microcode rom*/ + end else begin + state=next_state; + end end `PROC_DE_LOAD_REG_TO_PARAM:begin PARAM1=reg_read_port1_data; @@ -459,6 +526,21 @@ always @(posedge clock) begin PARAM1[15:8]=external_data_bus[15:8]; state=`PROC_EX_STATE_ENTRY; end + `PROC_NEXT_MICROCODE:begin + read=0; + write=1; // maybe we are coming from MEMIO_WRITE + ucode_seq_addr=ucode_seq_addr_entry; /*Reused for next address*/ + if( ucode_seq_addr == `UCODE_NO_INSTRUCTION )begin + /*Finished microcode*/ + if(we_jumped==0) + unaligned_access=unaligning_instruction^unaligned_access; + SIMPLE_MICRO=0; + state=`PROC_IF_STATE_ENTRY; + end else begin + state=`PROC_DE_STATE_ENTRY; + end + + end default:begin end endcase diff --git a/system/registers.v b/system/registers.v index f75d8d6..d6d36cb 100644 --- a/system/registers.v +++ b/system/registers.v @@ -21,10 +21,13 @@ /* Register address format: * [W-bit] [ 3-bit address] */ -module register_file (write_port1_addr,write_port1_data,write_port1_we,read_port1_addr,read_port1_data); -input [3:0] write_port1_addr,read_port1_addr; +module register_file (write_port1_addr,write_port1_data,write_port1_we,read_port1_addr,read_port1_data,read_port2_addr,read_port2_data); +input [3:0] write_port1_addr; +input [3:0] read_port1_addr; +input [3:0] read_port2_addr; input [15:0] write_port1_data; output [15:0] read_port1_data; +output [15:0] read_port2_data; input write_port1_we; reg [15:0] registers [7:0]; @@ -32,6 +35,9 @@ reg [15:0] registers [7:0]; assign read_port1_data = ( read_port1_addr[3:3] ? registers[read_port1_addr[2:0]] : ( read_port1_addr[2:2] ? {8'b0,registers[read_port1_addr[2:0]][15:8]} : {8'b0,registers[read_port1_addr[2:0]][7:0]} ) ); +assign read_port2_data = ( read_port2_addr[3:3] ? registers[read_port2_addr[2:0]] : + ( read_port2_addr[2:2] ? {8'b0,registers[read_port2_addr[2:0]][15:8]} : {8'b0,registers[read_port2_addr[2:0]][7:0]} ) ); + `ifdef DEBUG_REG_WRITES string debug_name; `endif diff --git a/system/ucode.hex b/system/ucode.hex deleted file mode 100644 index 1609230..0000000 --- a/system/ucode.hex +++ /dev/null @@ -1,9 +0,0 @@ - -//s : Opcode size 0:8bit 1:16bit -//h : Has operands as part of the instruction: 0: No 1: Yes - -// |sh -@000 01_11 -@001 11_10 -@002 1000 -@003 0010 diff --git a/system/ucode.txt b/system/ucode.txt new file mode 100644 index 0000000..c5ec9dc --- /dev/null +++ b/system/ucode.txt @@ -0,0 +1,32 @@ + +//a1f: ALU 1 operation (function) +// 000:ALU_OP_ADD +// 001:ALU_OP_SUB +// 010:ALU_OP_AND +// 011:ALU_OP_OR +// 100:ALU_OP_XOR +// 101:ALU_OP_ADD_SIGNED_B +// +//a1o: out_alu1_sel. Handled in `PROC_EX_STATE_EXIT +// +//a12: In ALU 1 sel 2 +// +//a11: In ALU 1 sel 1 +// +//rwa: Register Write Address +// +//nxs: Next State +// 00: PROC_EX_STATE_ENTRY +// 01: PROC_DE_LOAD_16_PARAM +// 10: PROC_DE_LOAD_8_PARAM +// 11: PROC_DE_LOAD_REG_TO_PARAM +// +//Nxt M: Next microcode address + + +// 24 21 18 15 13 11 7 5 0 +// rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M | +@000 0000_000_000__00__00_0000__00_000000 +@001 zzzz_000_110__10__11_0111__01_000010 // ALU_1: 0 ALU_2: PC ALU_OP:ADD ALU_out: [SP] (also fetch the opcode argument to PARAM1) +@002 1100_001_011__00__01_1100__00_000011 // ALU_1: SP ALU_2: PARAM2 (2) ALU_OP:SUB ALU_out: SP +@003 zzzz_000_101__10__00_zzzz__00_000000 // ALU_1: PARAM1 (arg) ALU_2: PC ALU_OP:ADD ALU_out: PC diff --git a/system/ucode_header.v b/system/ucode_header.v index 83a9b3a..bcb098e 100644 --- a/system/ucode_header.v +++ b/system/ucode_header.v @@ -1,6 +1,7 @@ -`define UCODE_ADDR_BITS 9 +`define UCODE_ADDR_BITS 5 `define UCODE_DATA_BITS 32 `define UCODE_SIZE 4 -`define ADD_AL_IB 0 -`define ADD_AX_IW 1 +/* DEFINE ADDRESSES IN THE MICROCODE */ +`define UCODE_NO_INSTRUCTION 5'b00000 +`define UCODE_CALL_ENTRY 5'b00001