`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Jürgen Böhm // // Create Date: 02:08:39 02/18/2007 // Design Name: // Module Name: cpu // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module comp_lt ( a, b, is_lt ); input[31:0] a,b; output reg is_lt; always @(a,b) begin if (a[31]==b[31]) is_lt <= (a[30:0] < b[30:0]); else is_lt <= a[31]; end endmodule module alu ( opcode, opAin, opBin, opCin, aluOut, overflow, carry, zero, freeze, clk ); input[31:0] opAin, opBin, opCin; output[31:0] aluOut; input[5:0] opcode; output overflow, carry, zero; input freeze; input clk; reg[31:0] aluOut; assign zero = (aluOut == 0); // experiment in staging the ALU: /* reg[31:0] opA, opB, opC; always @(posedge clk) begin opA <= opAin; opB <= opBin; opC <= opCin; end */ wire[31:0] opA = opAin; wire[31:0] opB = opBin; wire[31:0] opC = opCin; // the comparators wire aLTb; wire aGTb; comp_lt comp_lt0 (opA, opB, aLTb ); comp_lt comp_lt1 (opB, opA, aGTb ); wire aEQb; wire aLTEb; wire aGTEb; assign aEQb = (opA == opB); assign aLTEb = aLTb | aEQb; assign aGTEb = aGTb | aEQb; // the main alu wire[31:0] lenVect = 32'd12 + {opA[29:0], 2'b0}; always @(posedge clk) begin if (~freeze) begin case (opcode) 0: aluOut <= opA + opB; 1: aluOut <= opA - opB; 2: aluOut <= aLTEb ? 4 : opC; 3: aluOut <= aGTEb ? 4 : opC; 4: aluOut <= aLTb ? 4 : opC; 5: aluOut <= aGTb ? 4 : opC; 6: aluOut <= aEQb ? 4: opC; 11: aluOut <= opA | opB; 12: aluOut <= opA & opB; // 13: aluOut <= ~(opA | opB); /* 14: begin case (opB[6:2]) 0: aluOut <= opA >> 0; 1: aluOut <= opA >> 1; 2: aluOut <= opA >> 2; 3: aluOut <= opA >> 3; 4: aluOut <= opA >> 4; 5: aluOut <= opA >> 5; 6: aluOut <= opA >> 6; 7: aluOut <= opA >> 7; 8: aluOut <= opA >> 8; 9: aluOut <= opA >> 9; 10: aluOut <= opA >> 10; 11: aluOut <= opA >> 11; 12: aluOut <= opA >> 12; 13: aluOut <= opA >> 13; 14: aluOut <= opA >> 14; 15: aluOut <= opA >> 15; 16: aluOut <= opA >> 16; 17: aluOut <= opA >> 17; 18: aluOut <= opA >> 18; 19: aluOut <= opA >> 19; 20: aluOut <= opA >> 20; 21: aluOut <= opA >> 21; 22: aluOut <= opA >> 22; 23: aluOut <= opA >> 23; 24: aluOut <= opA >> 24; 25: aluOut <= opA >> 25; 26: aluOut <= opA >> 26; 27: aluOut <= opA >> 27; 28: aluOut <= opA >> 28; 29: aluOut <= opA >> 29; 30: aluOut <= opA >> 30; 31: aluOut <= opA >> 31; endcase end 15: begin case (opB[6:2]) 0: aluOut <= opA << 0; 1: aluOut <= opA << 1; 2: aluOut <= opA << 2; 3: aluOut <= opA << 3; 4: aluOut <= opA << 4; 5: aluOut <= opA << 5; 6: aluOut <= opA << 6; 7: aluOut <= opA << 7; 8: aluOut <= opA << 8; 9: aluOut <= opA << 9; 10: aluOut <= opA << 10; 11: aluOut <= opA << 11; 12: aluOut <= opA << 12; 13: aluOut <= opA << 13; 14: aluOut <= opA << 14; 15: aluOut <= opA << 15; 16: aluOut <= opA << 16; 17: aluOut <= opA << 17; 18: aluOut <= opA << 18; 19: aluOut <= opA << 19; 20: aluOut <= opA << 20; 21: aluOut <= opA << 21; 22: aluOut <= opA << 22; 23: aluOut <= opA << 23; 24: aluOut <= opA << 24; 25: aluOut <= opA << 25; 26: aluOut <= opA << 26; 27: aluOut <= opA << 27; 28: aluOut <= opA << 28; 29: aluOut <= opA << 29; 30: aluOut <= opA << 30; 31: aluOut <= opA << 31; endcase end */ 16: aluOut <= {opA[31:2], opA[1:0] & opB[3:2]}; 17: aluOut <= {opA[31:2], opA[1:0] | opB[3:2]}; 18: aluOut <= {opA[31:2], opA[1:0] ^ opB[3:2]}; 19: aluOut <= (opA[1:0] == opB[1:0]) ? 4 : opC; 20: aluOut <= {28'b0,opB[1:0],2'b0}; 21: aluOut <= {opA[31:2],opB[3:2]}; 24,25: aluOut <= (opA[31:2] == opB[31:2]) ? 4 : opC; 26: aluOut <= {opA[31:2] & opB[31:2], opA[1:0]}; 27: aluOut <= {opA[31:2] | opB[31:2], opA[1:0]}; 28: aluOut <= {opB[31:2],2'b0}; 32: if (|(opB[2:0])) begin aluOut <= {opB[31:3],3'b0} + 32'd8; end else begin aluOut <= opB; end 33: aluOut <= lenVect; 34: aluOut <= {opB[31:2],2'b10}; 35: aluOut <= {opB[31:2],2'b00} + opA; 36: aluOut <= opA + {2'b0, opB[31:2]}; 37: aluOut <= {opA[17:2],opB[17:2]}; 38: aluOut <= opA + {opB[31],opB[31],opB[31:2]}; 39: aluOut <= {opB[30:0],1'b0}; 40: aluOut <= {1'b0,opB[31:1]}; default : aluOut <= opB; endcase end else begin aluOut <= aluOut; end end endmodule module cpu( addr, data, readmem, writemem, waitrq, irq, type, rst, clk, tosout, debugout ); output[31:0] tosout; reg[31:0] tosout; output[31:0] debugout; reg[31:0] debugout; output[31:0] addr; inout[31:0] data; output readmem; output writemem; input waitrq; input[2:0] irq; output[1:0] type; input rst; input clk; //registered output lines reg readmem; reg writemem; reg[1:0] type; // special provision for data in/out reg[31:0] datao; reg dataeno; // assign data = dataeno ? datao : 32'bz; // registers reg[31:0] addro; assign addr = addro; reg[31:0] csp, dsp; // code stack pointer , data stack pointer reg[31:0] ir; reg[31:0] pc; wire[31:0] datamem; // data input buffer; wire[31:0] datamem2 = {datamem[29:0],2'b0}; reg[31:0] litbase; reg[31:0] template; // regA to regE reg[31:0] regA; reg[31:0] regB; reg[31:0] regC; reg[31:0] regD; reg[31:0] regE; reg[31:0] tos; // status word reg[31:0] status; // irq mask wire[2:0] irq_akt; assign irq_akt = status[5:3]; wire irq_enabled; assign irq_enabled = status[2]; // right shifted regA wire[31:0] regA2 = {2'b0,regA[31:2]}; // the ALU wire[31:0] aluOut; wire[5:0] aluOp; wire overflow, carry, zero; wire[31:0] opA; reg[31:0] aluOpA; alu alu0 (.opcode(aluOp),.opAin(aluOpA),.opBin(tos),.opCin(regC), .aluOut(aluOut),.overflow(overflow),.carry(carry),.zero(zero), .freeze(waitrq),.clk(clk)); wire[5:0] aluOp_h; wire use_aluOp_h; assign aluOp = use_aluOp_h ? aluOp_h : ir[29:24]; wire is_nil = (tos == regC); // the bus structures and multiplexors // data bus // derived signal d from ir wire[31:0] d; wire[15:0] d1; assign d1 = ir[15:0]; assign d = {{14{d1[15]}},d1,1'b0,1'b0}; wire[31:0] litbase_plus_d = litbase + d; wire[31:0] litbase_addr = template + 32'd16; wire[31:0] tp_4 = template + 32'd4; wire[31:0] pc_4 = pc + 32'd4; wire[31:0] regA_8 = regA + 32'd8; // some constants: `define vect_header_tag 32'd5 `define clos_header_tag 32'd13 `define val_3 32'd3 `define val_4 32'd4 `define val_8 32'd8 `define val_12 32'd12 `define val_16 32'd16 // aluOpA wire[2:0] alu_source; always @(alu_source, datamem, regA, regB, dsp) begin case (alu_source) 0: aluOpA <= datamem; 1: aluOpA <= regA; 2: aluOpA <= regB; 3: aluOpA <= `val_8; 4: aluOpA <= `val_12; 5: aluOpA <= `val_16; 6: aluOpA <= `val_3; 7: aluOpA <= dsp - 32'd4; default: aluOpA <= regA; endcase end // dat reg[31:0] datbus; assign opA = datbus; wire[4:0] dat_source; always @(regA, regB, regC, regD, regE, litbase, datamem, aluOut, dat_source, tos, litbase_addr, template, pc_4, d, datamem2, regA2) begin case (dat_source) 0: begin datbus <= datamem; end 1: begin datbus <= aluOut; end 2: begin datbus <= regA; end 3: begin datbus <= regB; end 4: begin datbus <= regC; end 5: begin datbus <= regD; end 6: begin datbus <= litbase; end 7: begin datbus <= tos; end 8: begin datbus <= litbase_addr; end 9: begin datbus <= template; end 10: begin datbus <= regE; end 11: begin datbus <= pc_4; end 12: begin datbus <= d; end 13: begin datbus <= datamem2; end 14: begin datbus <= regA2; end 15: begin datbus <= `val_4; end 16: begin datbus <= `val_8; end 17: begin datbus <= `val_12; end 18: begin datbus <= `val_16; end 19: begin datbus <= `val_3; end 20: begin datbus <= `vect_header_tag; end 21: begin datbus <= `clos_header_tag; end 22: begin datbus <= status; end 23: begin datbus <= 32'h0; end 24: begin datbus <= pc; end 25: begin datbus <= dsp; end 26: begin datbus <= csp; end default: begin datbus <= regA; end endcase end wire[4:0] dat_dest; reg[31:0] dummy; always @(posedge clk) begin case (dat_dest) 1: ir <= datbus; 2: status <= datbus; 3: tos <= datbus; 4: regA <= datbus; 5: regB <= datbus; 6: regC <= datbus; 7: regD <= datbus; 8: litbase <= datbus; 9: template <= datbus; 10: regA <= regA + 4; 11: regE <= datbus; 12: tos <= tos + 4; 13: tos <= tos - 4; 14: regB <= regB + 4; default: dummy <= datbus; endcase end // data out bus assign datamem = ~dataeno ? data : 32'bz; assign data = dataeno ? datbus : 32'bz; // addr wire[4:0] addr_source; `define niladdr 32'h0000 // ab hier wird experimentiert... reg[31:0] asa1; reg[31:0] asa2; reg[31:0] asa3; wire[31:0] asasum = asa1 + asa2 + asa3; always @(addr_source, csp, dsp) begin case (addr_source) 1,2,3, 15: asa1 <= dsp; 5,6,7: asa1 <= csp; default: asa1 <= 0; endcase end always @(addr_source, d) begin case (addr_source) 1, 5: asa2 <= 32'd4; 2, 6: asa2 <= 32'hfffffffc; 3, 7: asa2 <= d; // 15: asa2 <= d - 32'd4; 15: asa2 <= d; default: asa2 <= 0; endcase end always @(addr_source) begin case (addr_source) 1,5, 2,6, 3, 7: asa3 <= 0; 15: asa3 <= 32'hfffffffc; default: asa3 <= 0; endcase end // hier gehts normal weiter always @(asasum, dsp, csp, pc, aluOut, litbase, regA, regB, regD, addr_source, litbase_plus_d, litbase_addr, tos, regA_8, tp_4) begin case (addr_source) 5'd0: addro <= dsp; 5'd1: addro <= asasum; 5'd2: addro <= asasum; 5'd3: addro <= asasum; 5'd4: addro <= csp; 5'd5: addro <= asasum; 5'd6: addro <= asasum; 5'd7: addro <= asasum; 5'd8: addro <= pc; 5'd9: addro <= aluOut; 5'd10: addro <= regA; 5'd11: addro <= regB; 5'd12: addro <= regD; 5'd13: addro <= litbase_plus_d; 5'd14: addro <= litbase_addr; 5'd15: addro <= asasum; 5'd16: addro <= tos; 5'd17: addro <= regA_8; 5'd18: addro <= tp_4; 5'd29: addro <= 32'h40; 5'd30: addro <= `niladdr; default: addro <= 32'bz; endcase end // cdsp wire[2:0] cdsp_dest; wire[2:0] cdsp_source; reg[31:0] cdspbus; // ab hier wird experimentiert... reg[31:0] csa1; reg[31:0] csa2; wire[31:0] csasum = csa1 + csa2; always @(csasum) begin cdspbus <= csasum; end always @(cdsp_source, csp, dsp) begin case (cdsp_source) 0,2,4,6: csa1 <= csp; 1,3,5,7: csa1 <= dsp; endcase end always @(cdsp_source, d) begin case (cdsp_source) 0,1: csa2 <= d; 2,3: csa2 <= -d; 4,5: csa2 <= 32'd4; 6,7: csa2 <= 32'hfffffffc; endcase end always @(posedge clk or posedge rst) if (rst) begin csp <= 32'h0800; dsp <= 32'h0ffc; end else begin case (cdsp_dest) 3'd0: csp <= cdspbus; 3'd1: dsp <= cdspbus; 3'd2: csp <= datbus; 3'd3: dsp <= datbus; default: begin dsp <= dsp; csp <= csp; end endcase end // pcb wire[2:0] pcb_source; always @(posedge clk) begin case (pcb_source) 3'd0: pc <= pc_4; 3'd1: pc <= pc + d; 3'd2: pc <= datbus; 3'd3: begin if (is_nil) begin pc <= pc + d; end else begin pc <= pc_4; end end default: pc <= pc; endcase end // control ir read reg irRead; // miscellaneous always @(dataeno) begin writemem <= dataeno; end // micro program control wire[31:0] mic_inst_raw; wire[31:0] mic_inst_h_raw; reg[31:0] mic_inst; reg[31:0] mic_inst_h; reg[9:0] micr_pc; reg[9:0] micr_pc_new; wire[9:0] next_micr_pc; assign next_micr_pc = micr_pc + 1; assign addr_source = mic_inst[31:27]; assign dat_source = mic_inst[26:22]; assign dat_dest = mic_inst[21:17]; assign cdsp_source = mic_inst[16:14]; assign cdsp_dest = mic_inst[13:11]; assign pcb_source = mic_inst[10:8]; wire data_eno_mic = mic_inst[6:6]; wire read_mem = mic_inst[7:7]; wire[3:0] mic_next = mic_inst[3:0]; wire dispatch = mic_inst_h[6:6]; wire to_page_zero = mic_inst_h[7:7]; wire[1:0] mtyp = mic_inst_h[9:8]; assign aluOp_h = mic_inst_h[5:0]; assign use_aluOp_h = mic_inst_h[10:10]; assign alu_source = mic_inst_h[13:11]; wire[1:0] start_interrupt; assign start_interrupt = mic_inst_h[15:14]; always @(mtyp) begin type <= mtyp; end always @(read_mem) begin readmem <= read_mem; end always @(data_eno_mic) begin dataeno <= data_eno_mic; end wire irq_pending = (irq > irq_akt); wire cycle_start = (micr_pc == 10'b0); wire irq_cycle_start = cycle_start && irq_enabled && irq_pending; always @(posedge clk or posedge rst) begin if (rst) begin status <= 32'h4; // start with interrupts enabled (status[2] = 1) end else begin if (start_interrupt == 2'b01) begin $display ( "setting priority, new is = %h", irq ); status[8:6] <= status[5:3]; status[5:3] <= irq; status[2] <= 1'b0; // irq disabled end else if ((start_interrupt == 2'b10) & status[9]) // status[9] is the switch that transforms an ordinary RET into a // RET from interrupt begin $display ( "resetting priority, new is = %h", status[8:6] ); status[9] <= 1'b0; status[5:3] <= status[8:6]; status[2] <= 1'b1; // irq reenabled end end end always @(mic_next, datamem, dispatch, waitrq, micr_pc, micr_pc_new, rst, ir, tos, to_page_zero, irq_cycle_start) begin if (rst) begin micr_pc_new <= 62* 8; tosout <= 0; end else begin if (~waitrq) begin debugout <= {16'b0,ir[31:16]}; if (ir[23:16] == 8'd60) tosout <= tos; if (to_page_zero) begin micr_pc_new <= {6'b0, mic_next}; end else if (irq_cycle_start) begin micr_pc_new <= {1'b0, 6'd14, 3'b0}; end else if (dispatch) begin micr_pc_new <= {1'b0,datamem[21:16],mic_next[2:0]}; end else begin micr_pc_new <= {micr_pc[9:4],mic_next}; end end else begin micr_pc_new <= micr_pc; end end end always @(posedge clk or posedge rst) begin if (rst) begin $display ( "cpu rst = %h", rst ); micr_pc <= 62* 8; end else begin if ((micr_pc_new[8:3] == 14) || (micr_pc_new[8:3] == 15)) begin $display ("in irq : micr_pc_new = %h", micr_pc_new ); end micr_pc <= micr_pc_new; end end `define mic_inst_wait {5'd31, 5'd7, 5'd31, 3'd7, 3'd4, 3'd4, 1'd0, 1'd0, 2'd0, 4'd0} `define mic_inst_wait_h {18'd0, 3'd1, 1'd0, 2'd0, 1'd0, 1'd0, 6'd63} always @(waitrq, rst, mic_inst_raw, mic_inst_h_raw) begin if (~waitrq & ~rst) begin mic_inst <= mic_inst_raw; mic_inst_h <= mic_inst_h_raw; end else begin mic_inst <= `mic_inst_wait; mic_inst_h <= `mic_inst_wait_h; end end micro_store mcs0 ( .address({micr_pc_new[9:0]}), .data(mic_inst_raw), .read_en(1'b1), .ce(1'b1), .clk(clk)); micro_store_1 mcs1 ( .address({micr_pc_new[9:0]}), .data(mic_inst_h_raw), .read_en(1'b1), .ce(1'b1), .clk(clk)); endmodule