📄 risc_core.v
字号:
// Byte Oriented RF Operations
I_ADDWF: alu_op <= #1 ALU_ADD; // ADDWF
I_ANDWF: alu_op <= #1 ALU_AND; // ANDWF
I_CLRF: alu_op <= #1 ALU_CLR; // CLRF
I_CLRW: alu_op <= #1 ALU_CLR; // CLRW
I_COMF: alu_op <= #1 ALU_NOT; // COMF
I_DEC: alu_op <= #1 ALU_DEC; // DEC
I_DECFSZ: alu_op <= #1 ALU_DEC; // DECFSZ
I_INCF: alu_op <= #1 ALU_INC; // INCF
I_INCFSZ: alu_op <= #1 ALU_INC; // INCFSZ
I_IORWF: alu_op <= #1 ALU_IOR; // IORWF
I_MOV: alu_op <= #1 ALU_MOV; // MOV
I_MOVWF: alu_op <= #1 ALU_MOVW; // MOVWF
I_RLF: alu_op <= #1 ALU_RLF; // RLF
I_RRF: alu_op <= #1 ALU_RRF; // RRF
I_SUBWF: alu_op <= #1 ALU_SUB; // SUBWF
I_SWAPF: alu_op <= #1 ALU_SWP; // SWAPF
I_XORWF: alu_op <= #1 ALU_XOR; // XORWF
// Bit Oriented RF Operations
I_BCF: alu_op <= #1 ALU_BCF; // BCF
I_BSF: alu_op <= #1 ALU_BSF; // BSF
// Literal & Controll Operations
I_ANDLW: alu_op <= #1 ALU_AND; // ANDLW
I_IORLW: alu_op <= #1 ALU_IOR; // IORLW
I_MOVLW: alu_op <= #1 ALU_MOV; // MOWLW
I_RETLW: alu_op <= #1 ALU_MOV; // RETLW
I_XORLW: alu_op <= #1 ALU_XOR; // XORLW
endcase
// Source Select
// This CPU source 1 can be one of: rf (or sfr) or k,
// second source (if any) is always w
always @(instr_0)
casex(instr_0) // synopsys full_case parallel_case
I_ANDLW: src1_sel_ = K_SEL;
I_CALL: src1_sel_ = K_SEL;
I_GOTO: src1_sel_ = K_SEL;
I_IORLW: src1_sel_ = K_SEL;
I_MOVLW: src1_sel_ = K_SEL;
I_RETLW: src1_sel_ = K_SEL;
I_XORLW: src1_sel_ = K_SEL;
default: src1_sel_ = ( (instr_0[4:3]==2'h0) & (instr_0[2:0] != 3'h0 )) ? SFR_SEL : RF_SEL;
endcase
always @(posedge clk)
src1_sel <= #1 src1_sel_[0];
// Destination Select
// Destination can be one of: rf, w, option, tris OR one of sfr registers:
// indf, tmr0, pc, status, fsr, porta, portb, portc, option, trisa, trisb, trisc
// Stage 1
// select w, pc, rf or sfr
reg w_we1, w_we1_;
always @(instr_0)
begin
casex(instr_0) // synopsys full_case parallel_case
I_ADDWF, I_ANDWF, I_COMF, I_DEC,
I_DECFSZ, I_INCF, I_INCFSZ, I_IORWF,
I_MOV, I_RLF, I_RRF, I_SUBWF,
I_SWAPF, I_XORWF: // w or f
w_we1_ = 1;
default: w_we1_ = 0;
endcase
end
always @(instr_0)
begin
w_we_ = 0;
rf_we_ = 0;
sfr_we_ = 0;
tris_we_= 0;
casex(instr_0) // synopsys full_case parallel_case
I_ADDWF, I_ANDWF, I_COMF, I_DEC,
I_DECFSZ, I_INCF, I_INCFSZ, I_IORWF,
I_MOV, I_RLF, I_RRF, I_SUBWF,
I_SWAPF, I_XORWF: // w or f
begin
rf_we_ = instr_0[5] & (instr_0[4] | instr_0[3]);
sfr_we_ = instr_0[5] & ~instr_0[4] & ~instr_0[3];
end
I_MOVWF, I_CLRF, I_BCF, I_BSF: // only f
begin
rf_we_ = instr_0[4] | instr_0[3];
sfr_we_ = ~instr_0[4] & ~instr_0[3];
end
I_CLRW, I_IORLW, I_MOVLW,
I_ANDLW, I_RETLW, I_XORLW: w_we_ = 1; // only w
I_TRIS: tris_we_ = 1; // trisa or trisb or trisc
endcase
end
assign indf_we_ = sfr_we_ & (instr_0[2:0] == INDF_ADDR);
assign pc_we_ = sfr_we_ & (instr_0[2:0] == PCL_ADDR);
// Stage 2 destination encoder
// write enable outputs are registered now
always @(posedge clk) w_we <= #1 w_we_; // working register write 0 enable
always @(posedge clk) w_we1 <= #1 w_we1_; // working register write 1 enable
// Register File Write Enable is composed of thee conditions: 1) direct register writing (0x10-0x1f);
// 2) Direct Global Register writing (0x08-0x0f), and 3) Indirect Register File Writing
// The logic has been partitioned and balanced between the decode and execute stage ...
assign rf_we = rf_we1 | (rf_we2 & rf_we3); // register file write enable Composite
always @(posedge clk)
rf_we1 <= #1 valid & rf_we_; // register file write enable 1
always @(posedge clk)
rf_we2 <= #1 valid & (fsr_next[4] | fsr_next[3]);// register file write enable 2
always @(posedge clk)
rf_we3 <= #1 indf_we_; // register file write enable 3
always @(posedge clk)
wdt_clr <= #1 instr_0[11:0] == I_CLRWDT;
always @(posedge clk)
opt_we <= #1 instr_0[11:0] == I_OPTION;
always @(posedge clk)
trisa_we <= #1 tris_we_ & (instr_0[2:0] == PORTA_ADDR);
always @(posedge clk)
trisb_we <= #1 tris_we_ & (instr_0[2:0] == PORTB_ADDR);
always @(posedge clk)
trisc_we <= #1 tris_we_ & (instr_0[2:0] == PORTC_ADDR);
always @(posedge clk)
begin
// SFR registers
tmr0_we <= #1 sfr_we_ & (instr_0[2:0] == TMR0_ADDR);
pc_we <= #1 valid & pc_we_;
stat_we <= #1 valid & sfr_we_ & (instr_0[2:0] == STAT_ADDR);
fsr_we <= #1 valid & sfr_we_ & (instr_0[2:0] == FSR_ADDR);
porta_we <= #1 sfr_we_ & (instr_0[2:0] == PORTA_ADDR);
portb_we <= #1 sfr_we_ & (instr_0[2:0] == PORTB_ADDR);
portc_we <= #1 sfr_we_ & (instr_0[2:0] == PORTC_ADDR);
end
// Instructions that directly modify PC
always @(instr_0)
begin
pc_skz_ = 0;
pc_bset_ = 0;
pc_bclr_ = 0;
pc_call_ = 0;
pc_goto_ = 0;
pc_retlw_ = 0;
casex(instr_0) // synopsys full_case parallel_case
// Byte Oriented RF Operations
I_DECFSZ,
I_INCFSZ: pc_skz_ = 1;
// Bit Oriented RF Operations
I_BTFSS: pc_bset_ = 1;
I_BTFSC: pc_bclr_ = 1;
// Literal & Controll Operations
I_CALL: pc_call_ = 1;
I_GOTO: pc_goto_ = 1;
I_RETLW: pc_retlw_ = 1;
endcase
end
always @(posedge clk)
begin
pc_skz <= #1 valid & pc_skz_;
pc_bset <= #1 valid & pc_bset_;
pc_bclr <= #1 valid & pc_bclr_;
pc_call <= #1 valid & pc_call_;
pc_goto <= #1 valid & pc_goto_;
pc_retlw <= #1 valid & pc_retlw_;
end
assign invalidate_0_ = (pc_call_ | pc_goto_ | pc_retlw_ | pc_we_);
always @(posedge clk)
invalidate_0 <= #1 invalidate_0_;
// Status bits WE
always @(posedge clk)
begin
stat_bwe <= #1 0;
if(valid)
casex(instr_0) // synopsys full_case parallel_case
// Byte Oriented RF Operations
I_ADDWF: stat_bwe <= #1 STAT_WR_C | STAT_WR_DC | STAT_WR_Z;
I_ANDWF: stat_bwe <= #1 STAT_WR_Z;
I_CLRF: stat_bwe <= #1 STAT_WR_Z;
I_CLRW: stat_bwe <= #1 STAT_WR_Z;
I_COMF: stat_bwe <= #1 STAT_WR_Z;
I_DEC: stat_bwe <= #1 STAT_WR_Z;
I_INCF: stat_bwe <= #1 STAT_WR_Z;
I_IORWF: stat_bwe <= #1 STAT_WR_Z;
I_MOV: stat_bwe <= #1 STAT_WR_Z;
I_RLF: stat_bwe <= #1 STAT_WR_C;
I_RRF: stat_bwe <= #1 STAT_WR_C;
I_SUBWF: stat_bwe <= #1 STAT_WR_C | STAT_WR_DC | STAT_WR_Z;
I_XORWF: stat_bwe <= #1 STAT_WR_Z;
// Literal & Controll Operations
I_ANDLW: stat_bwe <= #1 STAT_WR_Z;
//I_CLRWDT: // Modifies TO & PD *** FIX ME ***
I_IORLW: stat_bwe <= #1 STAT_WR_Z;
//I_SLEEP: // Modifies TO & PD *** FIX ME ***
I_XORLW: stat_bwe <= #1 STAT_WR_Z;
endcase
end
////////////////////////////////////////////////////////////////////////
// Wr & Execute Logic (including PC)
// Second Pipeline Stage
////////////////////////////////////////////////////////////////////////
// Source OP Sel
//assign src1 = src1_sel ? rf_rd_data : sfr_rd_data;
mux2_8 u3( .sel(src1_sel), .in0(sfr_rd_data), .in1(rf_rd_data), .out(src1) );
alu u4( .s1( src1 ),
.s2( w ),
.mask( mask ),
.out( dout ),
.op( alu_op ),
.c_in( status[0] ),
.c( c_out ),
.dc( dc_out ),
.z( z_out )
);
// Register file connections
assign rf_wr_bnk = fsr[6:5];
assign rf_wr_addr = (instr_1[4:0]==0) ? fsr[4:0] : instr_1[4:0];
assign rf_wr_data = dout;
wire [7:0] status_next2;
// Deal with all special registers (SFR) writes
/*
always @(rst or status or stat_we or stat_bwe or dout or c_out or dc_out or z_out)
if(rst) status_next = STAT_RST_VALUE;
else
begin
status_next = status; // Default Keep Value
if(stat_we) status_next = dout | 8'h18;
else
begin
if(stat_bwe[0]) status_next[0] = c_out;
if(stat_bwe[1]) status_next[1] = dc_out;
if(stat_bwe[2]) status_next[2] = z_out;
end
end
*/
assign status_next2[0] = stat_bwe[0] ? c_out : status[0];
assign status_next2[1] = stat_bwe[1] ? dc_out : status[1];
assign status_next2[2] = stat_bwe[2] ? z_out : status[2];
mux2_8 u21( .sel(stat_we), .in1( {dout | 8'h18} ), .in0( {status[7:3],status_next2[2:0]} ), .out(status_next) );
always @(posedge clk)
if(rst) status <= #1 STAT_RST_VALUE;
else status <= #1 status_next;
//assign fsr_next = fsr_we ? dout[6:0] : fsr;
mux2_7 u31( .sel(fsr_we), .in1(dout[6:0]), .in0(fsr), .out(fsr_next) );
always @(posedge clk)
if(rst) fsr <= #1 FSR_RST_VALUE;
else fsr <= #1 fsr_next;
always @(posedge clk)
if(valid_1 & (w_we | (w_we1 & ~instr_1[5])) ) w <= #1 dout;
always @(posedge clk)
if(rst) trisa <= #1 TRIS_RST_VALUE;
else
if(trisa_we & valid_1) trisa <= #1 w;
always @(posedge clk)
if(rst) trisb <= #1 TRIS_RST_VALUE;
else
if(trisb_we & valid_1) trisb <= #1 w;
always @(posedge clk)
if(rst) trisc <= #1 TRIS_RST_VALUE;
else
if(trisc_we & valid_1) trisc <= #1 w;
always @(posedge clk)
if(rst) option <= #1 OPT_RST_VALUE;
else
if(opt_we & valid_1) option <= #1 w[5:0];
always @(posedge clk)
if(porta_we & valid_1) portaout <= #1 dout;
always @(posedge clk)
if(portb_we & valid_1) portbout <= #1 dout;
always @(posedge clk)
if(portc_we & valid_1) portcout <= #1 dout;
always @(posedge clk)
begin
porta_r <= #1 portain;
portb_r <= #1 portbin;
portc_r <= #1 portcin;
end
///////////////////////////////////////////////////////////////////////
// Timer Logic
//assign tmr0_next = tmr0_we ? dout : tmr0_cnt_en ? tmr0_plus_1 : tmr0;
//assign tmr0_next = tmr0_we ? dout : tmr0_cnt_en ? (tmr0 + 1) : tmr0;
mux2_8 u5( .sel(tmr0_we & valid_1),
.in0(tmr0_next1), .in1(dout),
.out(tmr0_next) );
mux2_8 u6( .sel(tmr0_cnt_en),
.in0(tmr0), .in1(tmr0_plus_1),
.out(tmr0_next1) );
inc8 u7( .in(tmr0), .out(tmr0_plus_1) );
always @(posedge clk)
tmr0 <= #1 tmr0_next;
presclr_wdt u8( .clk( clk ),
.rst( rst ),
.tcki( tcki ),
.option( option[5:0] ),
.tmr0_we( tmr0_we & valid_1 ),
.tmr0_cnt_en( tmr0_cnt_en ),
.wdt_en( wdt_en ),
.wdt_clr( wdt_clr & valid_1 ),
.wdt_to( wdt_to )
);
////////////////////////////////////////////////////////////////////////
// Programm Counter Logic
always @(posedge clk)
pc_r2 <= #1 pc_r;
// 'inst_addr' is a duplication of the 'pc'. The only time when it is really needed
// is when the program memory is not on the chip and we want to place the registers
// directly in the IO pads to reduce Tcq (For example in a Xilinx FPGA implementation).
// If the program memory is on the chip or if the implmentation allows feedback from
// registers in the IO cells, this is not needed. Synopsys FPGA compiler appears to
// make the correct decission either way, and gett rid of unneded logic ...
always @(posedge clk)
if(rst) inst_addr <= #1 PC_RST_VECTOR;
else inst_addr <= #1 pc_next;
always @(posedge clk)
if(rst) pc <= #1 PC_RST_VECTOR;
else pc <= #1 pc_next;
/*
always @(pc_plus_1 or dout or pc_we or status or stack_out or
pc_call or pc_goto or pc_retlw or instr_1)
if(pc_we) pc_next = {status[6:5], 1'b0, dout};
else
if(!pc_call & !pc_goto & !pc_retlw) pc_next = pc_plus_1;
else
if(pc_call) pc_next = {status[6:5], 1'b0, instr_1[7:0]};
else
if(pc_goto) pc_next = {status[6:5], instr_1[8:0]};
else
if(pc_retlw) pc_next = stack_out;
*/
wire [10:0] pc_tmp1, pc_tmp2, pc_tmp3;
wire pc_sel1;
assign pc_tmp1 = {status[6:5], 1'b0, dout[7:0]};
assign pc_tmp2 = {status[6:5], 1'b0, instr_1[7:0]};
assign pc_tmp3 = {status[6:5], instr_1[8:0]};
assign pc_sel1 = (!pc_call & !pc_goto & !pc_retlw);
mux2_11 u9 ( .sel(pc_we), .in0(pc_next1), .in1(pc_tmp1), .out(pc_next) );
mux2_11 u10( .sel(pc_sel1), .in0(pc_next2), .in1(pc_plus_1), .out(pc_next1) );
mux2_11 u11( .sel(pc_call), .in0(pc_next3), .in1(pc_tmp2), .out(pc_next2) );
mux2_11 u12( .sel(pc_goto), .in0(stack_out), .in1(pc_tmp3), .out(pc_next3) );
inc11 u13( .in(pc), .out(pc_plus_1) );
reg invalidate_1_r1, invalidate_1_r2;
assign invalidate_1 = (pc_skz & z_out) | (pc_bset & bit_sel) |
(pc_bclr & !bit_sel) | (invalidate_0 & valid_1) | invalidate_1_r1;
always @(posedge clk)
begin
invalidate_1_r1 <= #1 (invalidate_0 & valid_1) | invalidate_1_r2;
invalidate_1_r2 <= #1 (invalidate_0 & valid_1);
end
//assign bit_sel = src1[ instr_1[7:5] ];
mux8_1 u22( .sel(instr_1[7:5]), .in(src1), .out(bit_sel) );
sfifo4x11 u14( .clk(clk), .push(pc_call), .din(pc_r2), .pop(pc_retlw), .dout(stack_out) );
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -