APPENDIX // pe.v // Verilog-XL behavioral models of a reconfigurable-processing element // to be used as a submodule of a controlling system // for Dr. W. B. Ligon, E&CE Dept., Clemson U., 1992-4 // by Ken Winiecki module pe0 (p_clock, p_reset, p_instr, p_flags, n_in, s_in, e_in, w_in, r_in, n_out, s_out, e_out, w_out, r_out, m_clock, m_write, m_addr, m_in, m_out, dump_reg, dump_mem); parameter // defaults, should be overridden by instantiating module: ADDR_WIDTH = 10, // width of PE memory address, in bits WORD_WIDTH = 32, // width of PE word, in bits MEM_LENGTH = 1024, // length of PE memory, in words PE_NAME = "undefined"; // name of PE for dump identification input // (1 bit wide) p_clock, p_reset, // PE clock & reset, rising-edge triggered e_in, w_in, // east (lsb) & west (msb) communication m_clock, // PE memory clock for external access, rising-edge m_write, // PE memory read/write control for external access: // read = 0, write = 1 dump_reg, dump_mem; // PE register & memory dump clocks, rising-edge input [ADDR_WIDTH-1:0] m_addr; // PE memory address for external access input [WORD_WIDTH-1:0] n_in, s_in, r_in, // PE north & south & router (word) communication m_in; // PE memory data for external access input [ADDR_WIDTH+32-1:0] p_instr; // PE instruction (described below) output // (1 bit wide) e_out, w_out; // east (lsb) & west (msb) communication output [9:0] p_flags; // PE flags (described below) output [WORD_WIDTH-1:0] n_out, s_out, r_out, // PE north & south & router (word) communication m_out; // PE memory data for external access reg temp_dis; // (1 bit wide) reg [9:0] p_flags; reg [7:0] out_res, reg_res; reg [WORD_WIDTH-1:0] mem[0:MEM_LENGTH-1], regs[0:15], in_1, in_2, out, m_out, last_out, r_in2, r; reg [WORD_WIDTH:0] temp; wire e_out, w_out; wire [WORD_WIDTH-1:0] east, west; integer i, j, reg_dump_ct, mem_dump_ct, clock_ct; // PE instruction field definitions and content parameters: `define mem_addr p_instr[ADDR_WIDTH+32-1:32] `define mem_ctrl p_instr[31:30] parameter NO_OP = 2'b00, // no memory operation R_OUT = 2'b01, // read to memory at address from OUT register W_IN1 = 2'b10, // write from memory at address to IN1 register W_IN2 = 2'b11; // write from memory at address to IN2 register `define dest_reg p_instr[29:26] `define srce_reg p_instr[25:22] parameter R0 = 4'b0000, R1 = 4'b0001, R2 = 4'b0010, R3 = 4'b0011, R4 = 4'b0100, R5 = 4'b0101, R6 = 4'b0110, R7 = 4'b0111, R8 = 4'b1000, R9 = 4'b1001, DIS = 4'b1010, ROUT = 4'b1011, NORTH = 4'b1100, SOUTH = 4'b1101, EAST = 4'b1110, WEST = 4'b1111; `define outres p_instr[21:14] `define regres p_instr[13:6] `define carry p_instr[5:4] // Note: The PE only does EITHER a carry operation OR an ALU operation in // one instruction cycle. A carry word is computed using registers IN1 // and IN2 and the specified carry-in, and is made available at the input // from the router, r_in. The carry-out is placed in the carry flag of the // p_flags register. parameter C_DIS = 2'b00, // do not compute carry (do an ALU operation) C_CAR = 2'b01, // compute carry using carry flag for carry-in C_ZER = 2'b10, // compute carry using 0 for carry-in C_ONE = 2'b11; // compute carry using 1 for carry-in `define alu_dis p_instr[3] // allow disabling of ALU operation, 1=allow `define alu_dis_s p_instr[2] // sense of PE disable bit for ALU op, 1=invert `define mem_dis p_instr[1] // allow disabling of memory operation.... `define mem_dis_s p_instr[0] // sense of PE disable bit for memory op.... // PE flag definitions and bit positions: // Note that flags other than carry are not affected by a carry operation, // and the carry flag is not affected by an ALU operation. `define reg_msb_f p_flags[9] // m.s.b. of destination register `define reg_zer_f p_flags[8] // if destination register = 0 `define out_msb_f p_flags[7] // m.s.b. of register OUT `define out_zer_f p_flags[6] // if register OUT = 0 `define in2_msb_f p_flags[5] // m.s.b. of register IN2 `define in2_zer_f p_flags[4] // if register IN2 = 0 `define in1_msb_f p_flags[3] // m.s.b. of register IN1 `define in1_zer_f p_flags[2] // if register IN1 = 0 `define disable_f p_flags[1] // state of PE disable bit `define carry_f p_flags[0] // result of last carry operation assign n_out = regs[NORTH], s_out = regs[SOUTH], east = regs[EAST], // cannot access structure of regs[i]!!! e_out = east[WORD_WIDTH-1], west = regs[WEST], // cannot access structure of regs[i]!!! w_out = west[0], r_out = regs[ROUT]; initial begin reg_dump_ct = 0; mem_dump_ct = 0; clock_ct = 0; end always @ (posedge p_clock) begin // instruction cycle clock_ct = clock_ct + 1; last_out = out; // save OUT reg for mem op temp_dis = regs[DIS] || 0; // save disable reg for mem op // if ALU/carry operations not disabled, then perform one if ( ~(`alu_dis & (`alu_dis_s ^ temp_dis)) ) begin // carry setup or register read case (`carry) C_DIS: begin case (`srce_reg) ROUT: temp = r_in2; // should be temp = r_in (default) (port from router), but // router doesn't exist, but router supposed to produce // carry word, so PE will produce carry word and place in // register r_in2, thus r_in doesn't really work EAST: begin temp = regs[EAST] << 1; temp[0] = e_in; end WEST: begin temp = regs[WEST] >> 1; temp[WORD_WIDTH-1] = w_in; end default temp = regs[`srce_reg]; endcase out_res = `outres; // cannot access structure of `outres!!! reg_res = `regres; // cannot access structure of `regres!!! end C_CAR: temp = `carry_f; C_ZER: temp = 0; C_ONE: temp = 1; endcase // carry or ALU computation if (`carry) for (i=0; i> 1; temp[WORD_WIDTH-1] = w_in; end RR: temp = r_in2; // should be temp = r_in (port from router), but router // doesn't exist, but router supposed to produce carry // word, so PE will produce carry word and place in // register r_in2, thus r_in doesn't really work default temp = regs[`srce_reg]; endcase out_res = `outres; // cannot access structure of `outres!!! reg_res = `regres; // cannot access structure of `regres!!! end CC: temp = `carry_f; C0: temp = 0; C1: temp = 1; endcase // operation execution if (`carry) // carry operation for (i=0; i> `shift % WORD_WIDTH; if (w_in) for (i=0; i<`shift%WORD_WIDTH; i=i+1) temp[WORD_WIDTH-1-i] = 1; // since Verilog doesn't allow variable part-select!!! end RR: temp = r_in2; // should be temp = r_in (port from router), but router // doesn't exist, but router supposed to produce carry // word, so PE will produce carry word and place in // register r_in2, thus r_in doesn't really work default temp = regs[`srce_reg]; endcase out_res = `outres; // since cannot access bits of `outres!!! reg_res = `regres; // since cannot access bits of `regres!!! end CC: temp = `carry_f; C0: temp = 0; C1: temp = 1; endcase // operation execution if (`carry) // carry operation for (i=0; i> `shift % WORD_WIDTH; if (w_in) for (i=0; i<`shift%WORD_WIDTH; i=i+1) temp[WORD_WIDTH-1-i] = 1; // since Verilog doesn't allow variable part-select!!! end // note: should have... // RR: temp = r_in; // ...but router does not exist, but router supposed to pass // carry word through, so will let temp = regs[RR], thus r_in // will not work default temp = regs[`srce_reg]; endcase out_res = `outres; // since cannot access bits of `outres!!! reg_res = `regres; // since cannot access bits of `regres!!! end // operation execution if (`car_in1 || `car_in2) // carry operation for (i=0; i> `shift % WORD_WIDTH; // zeros shifted in if ( `ew_srce == EW1 || `ew_srce == EWIN && w_in || `ew_srce == EWOU && w_out ) // if source is a 1, for (i=0; i<`shift%WORD_WIDTH; i=i+1) // then "shift" it in alu_wrk[WORD_WIDTH-1-i] = 1; // use loop since Verilog doesn't allow variable part-select!!! end default: alu_wrk = regs[`srce_reg]; endcase if (`car_srce) car_wrk = `car_val; else car_wrk = `carry_f; reg_op = `regop; // needed since cannot access bits of `regop!!! out_op = `outop; // needed since cannot access bits of `outop!!! // Execute operation and store results if (`car_in1 || `car_in2) // carry operation begin for (i=0; i in_2 // 1: mem[1] -> in_2 instr_0 = { `M 0, MEM, F, T, F, NALU, CN, NDIS }; instr_1 = { `M 1, MEM, F, T, F, NALU, CN, NDIS }; clockem; // both: if in_2 negative, then out = ~in_2, in_2 = out, compute carry for // in_2 + 1; otherwise in_2 positive, so compute carry for in_2 + 0 if (flags_0[IN2_MSB_F]) condition_0 = 1; else condition_0 = 0; if (flags_1[IN2_MSB_F]) condition_1 = 1; else condition_1 = 0; if (condition_0^condition_1) negative = 1; else negative = 0; if (condition_0) instr_0 = { NMEM, R0, SRC, R0, NIN2, CN, NDIS }; else instr_0 = { NOOP }; if (condition_1) instr_1 = { NMEM, R0, SRC, R0, NIN2, CN, NDIS }; else instr_1 = { NOOP }; clockem; if (condition_0) instr_0 = { `M 0, OUT, F, T, F, NALU, CN, NDIS }; else instr_0 = { NOOP }; if (condition_1) instr_1 = { `M 0, OUT, F, T, F, NALU, CN, NDIS }; else instr_1 = { NOOP }; clockem; if (condition_0) instr_0 = { NMEM, NALU, C1, NDIS }; else instr_0 = { NMEM, NALU, C0, NDIS }; if (condition_1) instr_1 = { NMEM, NALU, C1, NDIS }; else instr_1 = { NMEM, NALU, C0, NDIS }; clockem; // 0: south & out = in_2 + c // 1: north & out = in_2 + c instr_0 = { NMEM, RR, SUM12S, RS, SUM12S, CN, NDIS }; instr_1 = { NMEM, RR, SUM12S, RN, SUM12S, CN, NDIS }; clockem; // 0: out -> in_2, east = south // 1: out -> in_2, west = north instr_0 = { `M 0, OUT, F, T, F, RS, SRC, RE, ZEROS, CN, NDIS }; instr_1 = { `M 0, OUT, F, T, F, RN, SRC, RW, ZEROS, CN, NDIS }; clockem; // 0: west = in_2 // 1: east = in_2 instr_0 = { NMEM, R0, IN2, RW, ZEROS, CN, NDIS }; instr_1 = { NMEM, R0, IN2, RE, ZEROS, CN, NDIS }; clockem; // 0: west = west rotated right // 1: do nothing instr_0 = { NMEM, RW, SRC, RW, ZEROS, CN, NDIS }; instr_1 = { NOOP }; clockem; // 0: check for upcoming overflow possibility, // east & out = east shifted left with 0 // 1: out = in_2 if (e_out_0) op_ov_0 = 1; else op_ov_0 = 0; instr_0 = { NMEM, RE, SRC, RE, SRC, CN, NDIS }; instr_1 = { NMEM, R0, ZEROS, R0, IN2, CN, NDIS }; clockem; op_ov_1 = 0; overflow = 0; repeat (WORD_WIDTH/2) begin // both: out -> in_2, west = west rotated right, clear out instr_0 = { `M 0, OUT, F, T, F, RW, SRC, RW, ZEROS, CN, NDIS }; instr_1 = { `M 0, OUT, F, T, F, RW, SRC, RW, ZEROS, CN, NDIS }; clockem; // 0: if op bit = 1, compute carry for in_1 + in_2, south & out // = in_1 + in_2, check overflow; otherwise, south & out = in_1 // 1: if op bit = 1, compute carry for in_1 + in_2, north & out // = in_1 + in_2, check overflow; otherwise, north & out = in_1 if (flags_0[REG_MSB_F]) condition_0 = 1; else condition_0 = 0; if (flags_1[REG_MSB_F]) condition_1 = 1; else condition_1 = 0; if (condition_0) instr_0 = { NMEM, NALU, C0, NDIS }; else instr_0 = { NOOP }; if (condition_1) instr_1 = { NMEM, NALU, C0, NDIS }; else instr_1 = { NOOP }; clockem; if (condition_0) instr_0 = { NMEM, RR, SUM12S, RS, SUM12S, CN, NDIS }; else instr_0 = { NMEM, RR, IN1, RS, IN1, CN, NDIS }; if (condition_1) instr_1 = { NMEM, RR, SUM12S, RN, SUM12S, CN, NDIS }; else instr_1 = { NMEM, RR, IN1, RN, IN1, CN, NDIS }; clockem; if ( condition_0 && (flags_0[CARRY_F] || op_ov_0) || condition_1 && (flags_1[CARRY_F] || op_ov_1) ) overflow = 1; // both: out -> in_1, west = west rotated right instr_0 = { `M 0, OUT, F, F, T, RW, SRC, RW, ZEROS, CN, NDIS }; instr_1 = { `M 0, OUT, F, F, T, RW, SRC, RW, ZEROS, CN, NDIS }; clockem; // both: east = east shifted left with zero instr_0 = { NMEM, RE, SRC, RE, ZEROS, CN, NDIS }; instr_1 = { NMEM, RE, SRC, RE, ZEROS, CN, NDIS }; clockem; // both: check for upcoming overflow possibility, // east & out = east shifted left with zero if (e_out_0) op_ov_0 = 1; if (e_out_1) op_ov_1 = 1; instr_0 = { NMEM, RE, SRC, RE, SRC, CN, NDIS }; instr_1 = { NMEM, RE, SRC, RE, SRC, CN, NDIS }; clockem; end // 0: out = south // 1: out = north instr_0 = { NMEM, RS, ZEROS, R0, SRC, CN, NDIS }; instr_1 = { NMEM, RN, ZEROS, R0, SRC, CN, NDIS }; clockem; // both: out -> in_2, clear out instr_0 = { `M 0, OUT, F, T, F, NALU, CN, NDIS }; instr_1 = { `M 0, OUT, F, T, F, NALU, CN, NDIS }; clockem; // both: compute carry for in_1 + in_2 instr_0 = { NMEM, NALU, C0, NDIS }; instr_1 = { NMEM, NALU, C0, NDIS }; clockem; // both: out = in_1 + in_2, clear in_2, check overflow instr_0 = { `M 0, OUT, F, T, F, RR, ZEROS, R0, SUM12S, CN, NDIS }; instr_1 = { `M 0, OUT, F, T, F, RR, ZEROS, R0, SUM12S, CN, NDIS }; clockem; if (flags_0[CARRY_F] || flags_1[CARRY_F]) overflow = 1; if (negative) begin // negate and save result // both: out -> in_1 instr_0 = { `M 0, OUT, F, F, T, NALU, CN, NDIS }; instr_1 = { `M 0, OUT, F, F, T, NALU, CN, NDIS }; clockem; // both: out = ~in_1 instr_0 = { NMEM, R0, SRC, R0, NIN1, CN, NDIS }; instr_1 = { NMEM, R0, SRC, R0, NIN1, CN, NDIS }; clockem; // both: out -> in_1 instr_0 = { `M 0, OUT, F, F, T, NALU, CN, NDIS }; instr_1 = { `M 0, OUT, F, F, T, NALU, CN, NDIS }; clockem; // both: compute carry for in_1 + 1 instr_0 = { NMEM, NALU, C1, NDIS }; instr_1 = { NMEM, NALU, C1, NDIS }; clockem; // both: out = in_1 + c instr_0 = { NMEM, RR, ZEROS, R0, SUM12S, CN, NDIS }; instr_1 = { NMEM, RR, ZEROS, R0, SUM12S, CN, NDIS }; clockem; // both: out -> mem[2] instr_0 = { `M 2, OUT, T, F, F, NALU, CN, NDIS }; instr_1 = { `M 2, OUT, T, F, F, NALU, CN, NDIS }; clockem; end else // positive begin // save result // both: out -> mem[2] instr_0 = { `M 2, OUT, T, F, F, NALU, CN, NDIS }; instr_1 = { `M 2, OUT, T, F, F, NALU, CN, NDIS }; clockem; // both: do nothing repeat (5) begin instr_0 = { NOOP }; instr_1 = { NOOP }; clockem; end end r_0_dump; m_0_dump; $display("unsigned: %0d x %0d = %0d, overflow = %0d", pe_0.mem[0], pe_0.mem[1], pe_0.mem[2], overflow); form_feed; r_1_dump; m_1_dump; $display("unsigned: %0d x %0d = %0d, overflow = %0d", pe_1.mem[0], pe_1.mem[1], pe_1.mem[2], overflow); $display("%0d clock cycles", clock_ct); end task reset_regs; begin #NS reset = 1; #NS reset = 0; end endtask task clockem; begin #NS clock = 1; #NS clock = 0; clock_ct = clock_ct + 1; end endtask task r_0_dump; begin #NS dump_r_0 = 1; #NS dump_r_0 = 0; end endtask task m_0_dump; begin #NS dump_m_0 = 1; #NS dump_m_0 = 0; end endtask task r_1_dump; begin #NS dump_r_1 = 1; #NS dump_r_1 = 0; end endtask task m_1_dump; begin #NS dump_m_1 = 1; #NS dump_m_1 = 0; end endtask task form_feed; $write("\14"); endtask endmodule Host command: verilog Command arguments: pe.v pc04-.v VERILOG-XL 1.6a.4 log file created Jul 14, 1994 19:13:20 * Copyright Cadence Design Systems, Inc. 1985, 1988. * * All Rights Reserved. Licensed Software. * * Confidential and proprietary information which is the * * property of Cadence Design Systems, Inc. * Compiling source file "pe.v" Compiling source file "pc04-.v" Highest level modules: pe0 pe2 pe3 pe4 pc4 2's-complement Integer 1x1=1-word Multiply with 2 PE's PE "PE_1" Reset, Clock Cycle # 0 PE "PE_0" Reset, Clock Cycle # 0 PE "PE_0" Port and Register Dump # 0, Clock Cycle # 115 PE_INSTR: mb_addr 0000 mb_srce mb_d_mem mb_d_in2 mb_d_in1 srce_reg reg_res dest_reg 1 0 0 0 0000 10101010 0000 out_res carry alu_dis alu_dis_