// // // File Name : module_block.v // Used on : Reliable 8051 Project // Author : Ted Fried, MicroCore Labs // Creation : 7/13/2016 // Code Type : Synthesizable // // Description: // ============ // // Module for a LockStep Quad Modular Redundant processor // //------------------------------------------------------------------------ // // Modification History: // ===================== // // Revision 1.0 7/13/16 // Initial revision // // //------------------------------------------------------------------------ // // Copyright (c) 2020 Ted Fried // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // //------------------------------------------------------------------------ `timescale 1ns/100ps module module_block ( input CORE_CLK, input RST_n, input KILL, input [3:0] KILL_MODE, input [1:0] MODULE_ID, output BROADCAST_OK, output [7:0] BROADCAST_STROBE, output [15:0] BROADCAST_ADDRESS, output [7:0] BROADCAST_DATA, output [15:0] BROADCAST_IP, output BROADCAST_SYNC, output BROADCAST_IDSBL, input BROADCAST_OK_IN0, input [7:0] BROADCAST_STROBE_IN0, input [15:0] BROADCAST_ADDRESS_IN0, input [7:0] BROADCAST_DATA_IN0, input [15:0] BROADCAST_IP_IN0, input BROADCAST_SYNC_IN0, input BROADCAST_IDSBL_IN0, input BROADCAST_OK_IN1, input [7:0] BROADCAST_STROBE_IN1, input [15:0] BROADCAST_ADDRESS_IN1, input [7:0] BROADCAST_DATA_IN1, input [15:0] BROADCAST_IP_IN1, input BROADCAST_SYNC_IN1, input BROADCAST_IDSBL_IN1, input BROADCAST_OK_IN2, input [7:0] BROADCAST_STROBE_IN2, input [15:0] BROADCAST_ADDRESS_IN2, input [7:0] BROADCAST_DATA_IN2, input [15:0] BROADCAST_IP_IN2, input BROADCAST_SYNC_IN2, input BROADCAST_IDSBL_IN2, input INT2, // Interrupts input INT3, input[7:0] PROXY_RD_DATA ); //------------------------------------------------------------------------ // Internal Signals for EU reg eu_add_carry; reg eu_add_carry16; reg eu_add_aux_carry; reg eu_add_overflow; reg eu_stall_pipeline; reg core_interrupt_disable; wire eu_opcode_jump_call; wire eu_jump_gate; wire biu_sfr_select; wire acc_parity; wire biu_timer_wr_strobe; wire biu_uart_rd_strobe; wire biu_uart_wr_strobe; wire biu_interrupt_int; wire rebuild_wr; wire voter_good; wire rebuild_wr0; wire rebuild_wr1; wire rebuild_wr2; wire rebuild_wr3; wire rebuild_sync_in; reg [9:0] eu_rom_address; reg [19:0] eu_calling_address; reg [15:0] eu_register_r0; reg [15:0] eu_register_r1; reg [15:0] eu_register_r2; reg [15:0] eu_register_r3; reg [15:0] eu_register_ip; reg [7:0] eu_biu_strobe; reg [7:0] eu_biu_dataout; reg [15:0] eu_alu_last_result; reg [15:0] eu_register_r3_d1; reg [7:0] biu_sfr_dpl_int; reg [7:0] biu_sfr_dph_int; reg [7:0] biu_sfr_ie_int; reg [7:0] biu_sfr_psw_int; reg [7:0] biu_sfr_acc_int; reg [7:0] biu_sfr_sp_int; reg [7:0] biu_sfr_b_int; reg [15:0] rebuild_addr_out; reg [15:0] rebuild_addr_out_d; reg [2:0] rebuild_cross_zero; wire [15:0] adder_out; wire [16:0] carry; wire [2:0] eu_opcode_type; wire [2:0] eu_opcode_dst_sel; wire [3:0] eu_opcode_op0_sel; wire [2:0] eu_opcode_op1_sel; wire [15:0] eu_opcode_immediate; wire [2:0] eu_opcode_jump_src; wire [2:0] eu_opcode_jump_cond; wire [15:0] eu_alu2; wire [15:0] eu_alu3; wire [15:0] eu_alu4; wire [15:0] eu_alu5; wire [15:0] eu_alu6; wire [15:0] eu_alu7; wire [15:0] eu_alu_out; wire [15:0] eu_operand0; wire [15:0] eu_operand1; wire [31:0] eu_rom_data; wire [15:0] eu_flags_r; wire [15:0] rebuild_addr; wire [7:0] biu_return_data_int; wire [7:0] biu_sfr_dataout; wire [7:0] biu_sfr_is_int; wire [7:0] biu_program_data; wire [2:0] eu_biu_strobe_mode; wire [2:0] eu_biu_strobe_int; wire [7:0] biu_ram_dataout; wire [7:0] biu_timer_dataout; wire [7:0] biu_uart_dataout; wire [7:0] rebuild_data_in; wire [15:0] neighbor_address; wire [7:0] neighbor_data; wire [15:0] neighbor_ip; wire [7:0] neighbor_strobe; wire [7:0] rebuild_data_out; wire [7:0] rebuild_data_out0; wire [7:0] rebuild_data_out1; wire [7:0] rebuild_data_out2; wire [7:0] rebuild_data_out3; wire [7:0] rebuild_strobe_in; wire [15:0] rebuild_ip_in; reg kill_d1; reg kill_d2; reg kill_d3; reg kill_d4; reg rebuild_sync_in_d1; reg rebuild_sync_in_d2; reg rebuild_sync_in_d3; wire neighbor_idsbl; wire kill_microcode; reg [1:0] run_level; //------------------------------------------------------------------------ // // EU Microcode ROM. 1Kx32x8 // //------------------------------------------------------------------------ assign kill_microcode = (KILL_MODE==4'h0 && kill_d4==1'b1) ? 1'b1 : 1'b0; dpram_1Kx32x8 EU_1Kx32x8 ( .clka (CORE_CLK), // .wea (1'b0), .wea (kill_microcode), .addra (eu_rom_address[9:0]), .dina ({ MODULE_ID , 30'h0000_0000 }), .douta (eu_rom_data), .clkb (CORE_CLK), .web (rebuild_wr0), .addrb (rebuild_addr[11:0]), .dinb (rebuild_data_in), .doutb (rebuild_data_out0) ); //------------------------------------------------------------------------ // // User Program ROM. 4Kx8x8 // //------------------------------------------------------------------------ dpram_4Kx8x8 BIU_4Kx8x8 ( .clka (CORE_CLK), .wea (1'b0), .addra (eu_register_ip[11:0]), .dina (8'h00), .douta (biu_program_data), .clkb (CORE_CLK), .web (rebuild_wr1), .addrb (rebuild_addr[11:0]), .dinb (rebuild_data_in), .doutb (rebuild_data_out1) ); //------------------------------------------------------------------------ // // User Data RAM. 512x8x8 // //------------------------------------------------------------------------ dpram_512x8x8 BIU_512x8x8 ( .clka (CORE_CLK), .wea (biu_ram_wr), .addra (eu_register_r3_d1[8:0]), .dina (eu_biu_dataout), .douta (biu_ram_dataout), .clkb (CORE_CLK), .web (rebuild_wr2), .addrb (rebuild_addr[8:0]), .dinb (rebuild_data_in), .doutb (rebuild_data_out2) ); //------------------------------------------------------------------------ // // Broadcast logic // //------------------------------------------------------------------------ // When registers/flags are updated, the STROBE is assrted along with the new data // Otherwise the module continously broadcasts the contents of their RAMS so // listening modules can rebuild their local RAMS. // assign BROADCAST_OK = ((RST_n==1'b0 || run_level==2'h3) && voter_good==1'b1) ? 1'b1 : 1'b0; assign BROADCAST_ADDRESS = (run_level!=2'h3) ? { 14'h0, MODULE_ID } : (eu_biu_strobe==8'h00) ? rebuild_addr_out_d : eu_register_r3; assign BROADCAST_DATA = ((KILL_MODE==4'h2 && kill_d4==1'b1) || (run_level!=2'h3)) ? { 6'h0 , MODULE_ID } : (eu_biu_strobe==8'h00) ? rebuild_data_out : (eu_biu_strobe[2:0]==3'h1) ? eu_biu_dataout : 8'hAA; assign BROADCAST_IP = eu_register_ip; assign BROADCAST_STROBE = (run_level!=2'h3) ? { 6'h0 , MODULE_ID } : eu_biu_strobe; assign BROADCAST_SYNC = (eu_rom_address==9'h103) ? 1'b1 : 1'b0; assign BROADCAST_IDSBL = core_interrupt_disable; //------------------------------------------------------------------------ // // Voter and neighboring module data steering logic // //------------------------------------------------------------------------ // Voter reports module data is OK if it matches at least one other neighbor module. // assign voter_good = ( ((BROADCAST_ADDRESS == BROADCAST_ADDRESS_IN0) && (BROADCAST_DATA == BROADCAST_DATA_IN0) && (BROADCAST_SYNC == BROADCAST_SYNC_IN0)) || ((BROADCAST_ADDRESS == BROADCAST_ADDRESS_IN1) && (BROADCAST_DATA == BROADCAST_DATA_IN1) && (BROADCAST_SYNC == BROADCAST_SYNC_IN1)) || ((BROADCAST_ADDRESS == BROADCAST_ADDRESS_IN2) && (BROADCAST_DATA == BROADCAST_DATA_IN2) && (BROADCAST_SYNC == BROADCAST_SYNC_IN2)) ) ? 1'b1 : 1'b0; assign neighbor_address = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_ADDRESS_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_ADDRESS_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_ADDRESS_IN2 : 16'hEEEE; assign neighbor_data = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_DATA_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_DATA_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_DATA_IN2 : 8'hEE; assign neighbor_ip = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_IP_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_IP_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_IP_IN2 : 16'hEEEE; assign neighbor_strobe = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_STROBE_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_STROBE_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_STROBE_IN2 : 8'hEE; assign neighbor_sync = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_SYNC_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_SYNC_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_SYNC_IN2 : 1'b0; assign neighbor_idsbl = (BROADCAST_OK_IN0==1'b1) ? BROADCAST_IDSBL_IN0 : (BROADCAST_OK_IN1==1'b1) ? BROADCAST_IDSBL_IN1 : (BROADCAST_OK_IN2==1'b1) ? BROADCAST_IDSBL_IN2 : 1'b0; //------------------------------------------------------------------------ // // Rebuilding logic // //------------------------------------------------------------------------ assign rebuild_data_out3 = (rebuild_addr_out_d[7:0]==8'h81) ? biu_sfr_sp_int : (rebuild_addr_out_d[7:0]==8'h82) ? biu_sfr_dpl_int : (rebuild_addr_out_d[7:0]==8'h83) ? biu_sfr_dph_int : (rebuild_addr_out_d[7:0]==8'hA8) ? biu_sfr_ie_int : (rebuild_addr_out_d[7:0]==8'hD0) ? biu_sfr_psw_int : (rebuild_addr_out_d[7:0]==8'hE0) ? biu_sfr_acc_int : (rebuild_addr_out_d[7:0]==8'hF0) ? biu_sfr_b_int : 8'h77; // Select which RAM to output when broadcasting rebuilding addresses // assign rebuild_data_out = (rebuild_addr_out_d[13:12]==2'h0) ? rebuild_data_out0 : (rebuild_addr_out_d[13:12]==2'h1) ? rebuild_data_out1 : (rebuild_addr_out_d[13:12]==2'h2) ? rebuild_data_out2 : rebuild_data_out3 ; // Mux the inputs to the RAMS when rebuilding from neighbor cores. // assign rebuild_addr = (run_level[1]==1'b1) ? rebuild_addr_out : neighbor_address; assign rebuild_data_in = neighbor_data; assign rebuild_ip_in = neighbor_ip; assign rebuild_strobe_in = neighbor_strobe; assign rebuild_sync_in = neighbor_sync; assign rebuild_wr0 = (run_level[1]==1'b0 && neighbor_strobe==8'h00 && neighbor_address[13:12]==2'h0) ? 1'b1 : 1'b0; assign rebuild_wr1 = (run_level[1]==1'b0 && neighbor_strobe==8'h00 && neighbor_address[13:12]==2'h1) ? 1'b1 : 1'b0; assign rebuild_wr2 = (run_level[1]==1'b0 && neighbor_strobe==8'h00 && neighbor_address[13:12]==2'h2) ? 1'b1 : (run_level[1]==1'b0 && neighbor_strobe==8'h11 && neighbor_address[15:7] ==9'b0000_0000_0) ? 1'b1 : 1'b0; assign rebuild_wr3 = (run_level[1]==1'b0 && neighbor_strobe==8'h00 && neighbor_address[13:12]==2'h3) ? 1'b1 : (run_level[1]==1'b0 && neighbor_strobe==8'h11 && neighbor_address[15:7] ==9'b0000_0000_1) ? 1'b1 : 1'b0; //------------------------------------------------------------------------ // // EU Combinationals // //------------------------------------------------------------------------ // EU ROM opcode decoder assign eu_opcode_type = (KILL_MODE==4'h3 && kill_d4==1'b1) ? 'h0 :eu_rom_data[30:28]; assign eu_opcode_dst_sel = eu_rom_data[26:24]; assign eu_opcode_op0_sel = eu_rom_data[23:20]; assign eu_opcode_op1_sel = eu_rom_data[18:16]; assign eu_opcode_immediate = eu_rom_data[15:0]; assign eu_opcode_jump_call = eu_rom_data[24]; assign eu_opcode_jump_src = eu_rom_data[22:20]; assign eu_opcode_jump_cond = eu_rom_data[18:16]; assign eu_operand0 = (eu_opcode_op0_sel==4'h0) ? eu_register_r0 : (eu_opcode_op0_sel==4'h1) ? eu_register_r1 : (eu_opcode_op0_sel==4'h2) ? eu_register_r2 : (eu_opcode_op0_sel==4'h3) ? eu_register_r3 : (eu_opcode_op0_sel==4'h4) ? { 8'h00 , biu_return_data_int } : (eu_opcode_op0_sel==4'h5) ? { eu_flags_r[15:0] } : (eu_opcode_op0_sel==4'h6) ? { 8'h00 , biu_sfr_acc_int } : (eu_opcode_op0_sel==4'h7) ? eu_register_ip : 16'h0000 ; assign eu_operand1 = (eu_opcode_op1_sel==3'h0) ? eu_register_r0 : (eu_opcode_op1_sel==3'h1) ? eu_register_r1 : (eu_opcode_op1_sel==3'h2) ? eu_register_r2 : (eu_opcode_op1_sel==3'h3) ? eu_register_r3 : (eu_opcode_op1_sel==3'h4) ? { 8'h00 , biu_sfr_sp_int } : //(eu_opcode_op1_sel==3'h5) ? eu_alu_last_result : (eu_opcode_op1_sel==3'h6) ? { biu_sfr_dph_int , biu_sfr_dpl_int } : eu_opcode_immediate ; // JUMP condition codes assign eu_jump_gate = (eu_opcode_jump_cond==4'h0) ? 1'b1 : // unconditional jump (eu_opcode_jump_cond==4'h1 && eu_alu_last_result!=16'h0) ? 1'b1 : (eu_opcode_jump_cond==4'h2 && eu_alu_last_result==16'h0) ? 1'b1 : 1'b0 ; // ** Flags must be written to the PSW through the BIU assign eu_flags_r[15] = eu_add_carry; assign eu_flags_r[14] = eu_add_aux_carry; assign eu_flags_r[13] = eu_add_carry16; //assign eu_flags_r[12] = //assign eu_flags_r[11] = assign eu_flags_r[10] = eu_add_overflow; //assign eu_flags_r[9] = assign eu_flags_r[8] = biu_interrupt_int; assign eu_flags_r[7] = biu_sfr_psw_int[7]; // C assign eu_flags_r[6] = biu_sfr_psw_int[6]; // AC assign eu_flags_r[5] = biu_sfr_psw_int[5]; // F0 assign eu_flags_r[4] = biu_sfr_psw_int[4]; // RS1 assign eu_flags_r[3] = biu_sfr_psw_int[3]; // RS0 assign eu_flags_r[2] = biu_sfr_psw_int[2]; // Overflow assign eu_flags_r[1] = biu_sfr_psw_int[1]; // User Defined Flag assign eu_flags_r[0] = acc_parity; // ACC Parity generated in the BIU // EU ALU Operations // ------------------------------------------ // eu_alu0 = NOP // eu_alu1 = JUMP assign eu_alu2 = adder_out; // ADD assign eu_alu3 = eu_operand0 ^ eu_operand1; // XOR assign eu_alu4 = eu_operand0 | eu_operand1; // OR assign eu_alu5 = eu_operand0 & eu_operand1; // AND assign eu_alu6 = { eu_operand0[7:0] , eu_operand0[15:8] }; // BYTESWAP assign eu_alu7 = (eu_opcode_immediate[1:0]==2'h0) ? { 8'h00 , eu_operand0[0] , eu_operand0[7:1] } : // Rotate in bit[0] (eu_opcode_immediate[1:0]==2'h1) ? { 8'h00 , biu_sfr_psw_int[7] , eu_operand0[7:1] } : // Rotate in Carry bit { eu_add_carry16 , eu_operand0[15:1] } ; // 16-bit shift-right // Mux the ALU operations assign eu_alu_out = (eu_opcode_type==3'h2) ? eu_alu2 : (eu_opcode_type==3'h3) ? eu_alu3 : (eu_opcode_type==3'h4) ? eu_alu4 : (eu_opcode_type==3'h5) ? eu_alu5 : (eu_opcode_type==3'h6) ? eu_alu6 : (eu_opcode_type==3'h7) ? eu_alu7 : 16'hEEEE; // Generate 16-bit full adder for the EU assign carry[0] = 1'b0; genvar i; generate for (i=0; i < 16; i=i+1) begin : GEN_ADDER assign adder_out[i] = eu_operand0[i] ^ eu_operand1[i] ^ carry[i]; assign carry[i+1] = (eu_operand0[i] & eu_operand1[i]) | (eu_operand0[i] & carry[i]) | (eu_operand1[i] & carry[i]); end endgenerate //------------------------------------------------------------------------ // // BIU Combinationals // //------------------------------------------------------------------------ // Outputs to the EU // assign biu_return_data_int = (KILL_MODE==4'h4 && kill_d4==1'b1) ? { MODULE_ID, MODULE_ID, MODULE_ID, MODULE_ID } : (eu_biu_strobe_mode==2'h0) ? biu_program_data : (biu_sfr_select==1'b1) ? biu_sfr_dataout : biu_ram_dataout ; // Parity for the Accumulator // This can be removed if parity is not used in firmware. assign acc_parity = (biu_sfr_acc_int[0]^biu_sfr_acc_int[1]^biu_sfr_acc_int[2]^biu_sfr_acc_int[3]^biu_sfr_acc_int[4]^biu_sfr_acc_int[5]^biu_sfr_acc_int[6]^biu_sfr_acc_int[7]); // EU strobes to request BIU processing. assign eu_biu_strobe_mode[2:0] = eu_biu_strobe[6:4]; assign eu_biu_strobe_int[2:0] = eu_biu_strobe[2:0]; // Select the SFR range if the address is 0x0080 to 0x00FF and addressing mode is Direct assign biu_sfr_select = ( eu_register_r3_d1[15:7]==9'b0000_0000_1 && eu_biu_strobe_mode[1:0]==3'h1) ? 1'b1 : 1'b0; // Decode the write enable to the RAM block assign biu_ram_wr = (biu_sfr_select==1'b0 && eu_biu_strobe_int==3'h1) ? 1'b1 : 1'b0; // Mux the SFR data outputs assign biu_sfr_dataout = (eu_register_r3_d1[7:0]==8'h81) ? biu_sfr_sp_int : (eu_register_r3_d1[7:0]==8'h82) ? biu_sfr_dpl_int : (eu_register_r3_d1[7:0]==8'h83) ? biu_sfr_dph_int : (eu_register_r3_d1[7:0]==8'hA8) ? biu_sfr_ie_int : (eu_register_r3_d1[7:0]==8'hA9) ? biu_sfr_is_int : (eu_register_r3_d1[7:0]==8'hC0) ? PROXY_RD_DATA : (eu_register_r3_d1[7:0]==8'hD0) ? biu_sfr_psw_int : (eu_register_r3_d1[7:0]==8'hE0) ? biu_sfr_acc_int : (eu_register_r3_d1[7:0]==8'hF0) ? biu_sfr_b_int : 8'hEE ; // Simple fixed priority interrupt controller // biu_sfr_ie_int[7] is the global_intr_enable // biu_sfr_is_int[3:0] contains the interrupt source // Interrupt 2 = Timer Interrupt Vector at address 0x4 // 3 = UART-RX Interrupt Vector at address 0x6 // assign biu_interrupt_int = (core_interrupt_disable==1'b0 && biu_sfr_ie_int[7]==1'b1 && INT2==1'b1) ? 1'b1 : (core_interrupt_disable==1'b0 && biu_sfr_ie_int[7]==1'b1 && INT3==1'b1) ? 1'b1 : 1'b0; // (core_interrupt_disable==1'b0 && biu_sfr_ie_int[7]==1'b1 && INT4==1'b1) ? 1'b1 : // 1'b0 ; // Decode the vector address of the interrupt // assign biu_sfr_is_int = (INT2==1'b1) ? 8'h02 : (INT3==1'b1) ? 8'h03 : 8'h0F; // 8'h04 ; //------------------------------------------------------------------------------------------ // // EU Microsequencer // //------------------------------------------------------------------------------------------ always @(posedge CORE_CLK) begin : EU_MICROSEQUENCER if (RST_n==1'b0) begin eu_add_carry16 <= 'h0; eu_add_carry <= 'h0; eu_add_aux_carry <= 'h0; eu_add_overflow <= 'h0; eu_alu_last_result <= 'h0; eu_register_r0 <= 'h0; eu_register_r1 <= 'h0; eu_register_r2 <= 'h0; eu_register_r3 <= 'h0; eu_register_ip <= 16'hFFFF; // User Program code starts at 0x0000 after reset. Main loop does initial increment. eu_biu_strobe <= 'h0; eu_biu_dataout <= 'h0; eu_stall_pipeline <= 'h0; eu_rom_address <= 9'h100; // Microcode starts here after reset eu_calling_address <= 'h0; end else begin kill_d1 <= KILL; kill_d2 <= kill_d1; kill_d3 <= kill_d2; kill_d4 <= kill_d3; // Generate and store flags for addition if (eu_stall_pipeline==1'b0 && eu_opcode_type==3'h2) begin eu_add_carry16 <= carry[16]; eu_add_carry <= carry[8]; eu_add_aux_carry <= carry[4]; eu_add_overflow <= carry[8] ^ carry[7]; end // Register writeback if (run_level==2'h1) begin eu_register_ip <= rebuild_ip_in; eu_biu_strobe <= 'h0; end else if (eu_stall_pipeline==1'b0 && eu_opcode_type!=3'h0 && eu_opcode_type!=3'h1) begin eu_alu_last_result <= eu_alu_out[15:0]; case (eu_opcode_dst_sel) // synthesis parallel_case 3'h0 : eu_register_r0 <= eu_alu_out[15:0]; 3'h1 : eu_register_r1 <= eu_alu_out[15:0]; 3'h2 : eu_register_r2 <= eu_alu_out[15:0]; 3'h3 : eu_register_r3 <= eu_alu_out[15:0]; 3'h4 : eu_biu_dataout <= eu_alu_out[7:0]; 3'h6 : eu_biu_strobe <= eu_alu_out[7:0]; 3'h7 : eu_register_ip <= eu_alu_out[15:0]; default : ; endcase end // JUMP Opcode if (run_level[1]==1'b0) begin eu_rom_address[9:0] <= 10'h104; // Hold at microcode between instruction decodes while rebuilding eu_stall_pipeline <= 1'b0; end else if (eu_stall_pipeline==1'b0 && eu_opcode_type==3'h1 && eu_jump_gate==1'b1) begin eu_stall_pipeline <= 1'b1; // For subroutine CALLs, store next opcode address if (eu_opcode_jump_call==1'b1) begin eu_calling_address[19:0] <= {eu_calling_address[9:0] , eu_rom_address[9:0] }; // Two deep calling addresses end case (eu_opcode_jump_src) // synthesis parallel_case 3'h0 : eu_rom_address <= eu_opcode_immediate[9:0]; 3'h1 : eu_rom_address <= { 2'h0 , biu_return_data_int }; // Initial opcode jump decoding 3'h2 : eu_rom_address <= { eu_opcode_immediate[9:4] , eu_register_r0[11:8] }; // EA decoding 3'h3 : begin // CALL Return eu_rom_address <= eu_calling_address[9:0]; eu_calling_address[9:0] <= eu_calling_address[19:10]; end 3'h4 : eu_rom_address <= { eu_opcode_immediate[5:0] , biu_return_data_int[2:0] , 1'b0 }; // Bit Mask decoding table default : ; endcase end else begin eu_stall_pipeline <= 1'b0; // Debounce the pipeline stall if (KILL_MODE==4'h1 && kill_d4==1'b1) begin eu_rom_address <= 'h0; end else begin eu_rom_address <= eu_rom_address + 1'b1; end end end end // EU Microsequencer //------------------------------------------------------------------------ // // BIU Controller // //------------------------------------------------------------------------ // always @(posedge CORE_CLK) begin : BIU_CONTROLLER if (RST_n==1'b0) begin biu_sfr_dpl_int <= 'h0; biu_sfr_dph_int <= 'h0; biu_sfr_ie_int <= 'h0; biu_sfr_psw_int <= 'h0; biu_sfr_acc_int <= 'h0; biu_sfr_b_int <= 8'h00; biu_sfr_sp_int <= 'h07; eu_register_r3_d1 <= 'h0; core_interrupt_disable <= 'h0; rebuild_addr_out <= 'h0; rebuild_addr_out_d <= 'h0; rebuild_cross_zero <= 'h0; run_level <= 'h3; end else begin // Delay address out by one clock to line up with the broadcast data if (KILL_MODE==4'h5 && kill_d4==1'b1) begin rebuild_addr_out_d <= 'h0; end else begin rebuild_addr_out_d <= rebuild_addr_out; end // Pipeline the neighboring code SYNC pulse rebuild_sync_in_d1 <= rebuild_sync_in; rebuild_sync_in_d2 <= rebuild_sync_in_d1; rebuild_sync_in_d3 <= rebuild_sync_in_d2; // When in rebuilding run-level 1, synchronize the broadcast address with the other modules if (run_level==2'h1) begin rebuild_addr_out <= rebuild_addr + 2'h2; end // When biu_strobe is asserted, back-off the address so it can restart with no missed locations else if (eu_biu_strobe!=8'h00) begin rebuild_addr_out <= rebuild_addr_out - 16'h0002; end else begin rebuild_addr_out <= rebuild_addr_out + 1'b1; end // Allow four passes of the full range or memory and register addresses when rebuilding a module if (run_level==2'h3) begin rebuild_cross_zero <= 'h0; end else if (run_level==2'h0 && rebuild_addr=='h0) begin rebuild_cross_zero <= rebuild_cross_zero + 1'b1; end // If Voter has detected a failure and module is not currently in rebuilding mode, then enter rebuilding mode. if ( run_level==2'h3 && voter_good==1'b0) begin run_level <= 2'h0; end // When the local RAM is refreshed multiple times, then go to run-level 1 else if (run_level==2'h0 && rebuild_cross_zero==3'b010) begin run_level <= 2'h1; end // When the SYNC pulse fron neighboring modules is seen, then go to run-level 2 else if (run_level==2'h1 && rebuild_sync_in==1'b1) begin run_level <= 2'h2; end // After a few clocks this module's broadcast should be pipelined out, so we can rejoin the lockstep at run-level 3 else if (run_level==2'h2 && rebuild_sync_in_d3==1'b1) begin run_level <= 2'h3; end eu_register_r3_d1 <= eu_register_r3; if (run_level==2'h2) begin core_interrupt_disable <= neighbor_idsbl; end else if (eu_biu_strobe_int==3'h3) begin core_interrupt_disable <= 1'b1; end else if (eu_biu_strobe_int==3'h4) begin core_interrupt_disable <= 1'b0; end // Writes to SFR's during rebuilding if (run_level!=2'h3) begin if (rebuild_wr3==1'b1) begin case (rebuild_addr[7:0]) // synthesis parallel_case 8'h81 : biu_sfr_sp_int <= rebuild_data_in[7:0]; 8'h82 : biu_sfr_dpl_int <= rebuild_data_in[7:0]; 8'h83 : biu_sfr_dph_int <= rebuild_data_in[7:0]; 8'hA8 : biu_sfr_ie_int <= rebuild_data_in[7:0]; 8'hD0 : biu_sfr_psw_int <= rebuild_data_in[7:0]; 8'hE0 : biu_sfr_acc_int <= rebuild_data_in[7:0]; 8'hF0 : biu_sfr_b_int <= rebuild_data_in[7:0]; default : ; endcase end end // Writes to SFR's else if (biu_sfr_select==1'b1 && eu_biu_strobe_int==3'h1) begin case (eu_register_r3_d1[7:0]) // synthesis parallel_case 8'h81 : biu_sfr_sp_int <= eu_biu_dataout[7:0]; 8'h82 : biu_sfr_dpl_int <= eu_biu_dataout[7:0]; 8'h83 : biu_sfr_dph_int <= eu_biu_dataout[7:0]; 8'hA8 : biu_sfr_ie_int <= eu_biu_dataout[7:0]; 8'hD0 : biu_sfr_psw_int <= eu_biu_dataout[7:0]; 8'hE0 : biu_sfr_acc_int <= eu_biu_dataout[7:0]; 8'hF0 : biu_sfr_b_int <= eu_biu_dataout[7:0]; default : ; endcase end end end // BIU Controller endmodule // module_block.v