📄 piccore.v
字号:
// PICCORE.vhd// CPU core of CQPIC (PIC16F84/16F84A)// (1) Version 1.00a Nov 1 1999// (2) Version 1.00b Dec 10 2000 made a patch for BUG in MAX+plus2 VHDL compiler// (3) Version 1.00c Aug 07 2002 made a patch for carry flag operations at substraction operations// (4) Version 1.00d Aug 26 2004 debugged Z flag behavior (in case such that distinations are same as them)//// Copyright(c)1999-2004 Sumio Morioka// e-mail:morioka@fb3.so-net.ne.jp, URL:http://www02.so-net.ne.jp/~morioka/cqpic.htmmodule piccore(progdata, progadr, ramdtin, ramdtout, ramadr, readram, writeram, existeeprom, eepdtin, eepdtout, eepadr, readeepreq, readeepack, writeeepreq, writeeepack, porta_in, porta_out, porta_dir, portb_in, portb_out, portb_dir, rbpu, int0, int4, int5, int6, int7, t0cki, wdtena, wdtclk, wdtfull, powerdown, startclkin, ponrst_n, mclr_n, clkin, clkout); // program ROM data bus/address bus input [13:0] progdata; // ROM read data output [12:0] progadr; // ROM address // data RAM data bus/address bus/control signals input [7:0] ramdtin; // RAM read data output [7:0] ramdtout; // RAM write data output [8:0] ramadr; // RAM address; ramadr(8..7) indicates RAM-BANK output readram; // RAM read strobe (H active) output writeram; // RAM write strobe (H active) // EEPROM data bus/address bus input existeeprom;// Set to '1' if EEPROM is implemented. input [7:0] eepdtin; // EEPROM read data output [7:0] eepdtout; // EEPROM write data output [7:0] eepadr; // EEPROM address output readeepreq; // EEPROM read request (H active) input readeepack; // EEPROM read acknowledge (H active) output writeeepreq;// EEPROM write request (H active) input writeeepack;// EEPROM write acknowledge (H active) // I/O ports input [4:0] porta_in; // PORT-A input data output [4:0] porta_out; // PORT-A output data output [4:0] porta_dir; // TRISA: PORT-A signal direction (H:input, L:output) input [7:0] portb_in; // PORT-B input data output [7:0] portb_out; // PORT-B output data output [7:0] portb_dir; // TRISB: PORT-B signal direction (H:input, L:output) output rbpu; // PORT_B pull-up enable (usually not used) // PORT-B interrupt input input int0; // PORT-B(0) INT input int4; // PORT-B(4) INT input int5; // PORT-B(5) INT input int6; // PORT-B(6) INT input int7; // PORT-B(7) INT // TMR0 Control input t0cki; // T0CKI (PORT-A(4)) // Watch Dog Timer Control input wdtena; // WDT enable (H active) input wdtclk; // WDT clock output wdtfull; // WDT-full indicator (H active) // CPU clock stop/start indicators output powerdown; // SLEEP-mode; if H, you can stop system clock clkin output startclkin; // WAKEUP; if H, you should turn on clock for waking up from sleep-mode // CPU reset input ponrst_n; // Power-on reset (L active) input mclr_n; // Normal reset (L active) // CPU clock input clkin; // Clock input output clkout; // Clock output (clkin/4) // User registers reg [7:0] w_reg; // W reg [7:0] tmr0_reg; // TMR0 reg [12:0] pc_reg; // PCH/PCL reg [7:0] status_reg; // STATUS reg [7:0] fsr_reg; // FSR reg [4:0] portain_sync_reg; // PORTA IN (synchronizer) reg [4:0] portaout_reg; // PORTA OUT reg [7:0] portbin_sync_reg; // PORTB IN (synchronizer) reg [7:0] portbout_reg; // PORTB OUT reg [7:0] eedata_reg; // EEDATA reg [7:0] eeadr_reg; // EEADR reg [4:0] pclath_reg; // PCLATH reg [7:0] intcon_reg; // INTCON reg [7:0] option_reg; // OPTION reg [4:0] trisa_reg; // TRISA reg [7:0] trisb_reg; // TRISB reg [4:0] eecon1_reg; // EECON1 // Internal registers for controlling instruction execution reg [13:0] inst_reg; // Hold fetched op-code/operand reg [7:0] aluinp1_reg; // data source (1 of 2)//> changed ver1.00c, 2002/08/07 // reg [7:0] aluinp2_reg // data source (2 of 2) reg [8:0] aluinp2_reg; // data source (2 of 2)//< reg [7:0] aluout_reg; // result of calculation reg exec_op_reg; // if L (i.e. GOTO instruction etc), stall exec of instruction reg intstart_reg; // if H (i.e. interrupt), stall exec of instruction reg sleepflag_reg; // if H, sleeping // Stack reg [12:0] stack_reg [8 - 1:0]; // stack body (array of data-registers) reg [2:0] stack_pnt_reg; // stack pointer (binary encoded) wire [8 - 1:0] stack_pos_node; // same with stack pointer, but one-hot encoded reg [12:0] stacktop_node; // data value of stack-top // WDT register and its control reg [7:0] wdt_reg; // WDT counter reg wdt_full_reg; // WDT->CPU; hold WDT-full signal until CPU is reset reg [2:0] wdt_full_sync_reg; // CPU; synchronizer for wdt_full_reg reg wdt_clr_reg; // CPU->WDT; request to zero-clear wdt_reg reg wdt_clr_reqhold_reg; // CPU; hold a clear-request if previous request is still processing reg [1:0] wdtclr_req_reg; // WDT; synchronizer for wdt_clr_reg wire wdtclr_ack; // WDT->CPU; ack to wdt_clr_reg (same with wdtclr_req_reg(1)) reg wdtclr_ack_sync_reg; // CPU; synchronizer for wdtclr_ack reg wdtfull_clr_reg; // CPU->WDT; requst to clear wdt_full_reg reg [1:0] wdtfullclr_req_reg; // WDT; synchronizer for wdtfull_clr_reg // TMR0 prescaler wire psck; // clock for prescaler reg [7:0] pscale_reg; // prescaler reg ps_full_reg; // clock for TMR0, from prescaler wire inctmrck; // clock for TMR0 reg inctmrhold_reg; // hold TMR0 increment request // Interrupt registers/nodes reg [4:0] intrise_reg; // detect positive edge of PORT-B inputs reg [4:0] intdown_reg; // detect negative edge of PORT-B inputs wire rb0_int, rb4_int, rb5_int, rb6_int, rb7_int; // interrupt trigger wire rbint; // RB4-7 interrupt trigger wire inte; // RB0 interrupt trigger reg [4:0] intclr_reg; // CPU; clear intrise_reg and intdown_reg // State register parameter STATEBIT_SIZE = 3; reg [STATEBIT_SIZE - 1:0] state_reg; parameter Qreset = 3'b100; // reset state parameter Q1 = 3'b000; // state Q1 parameter Q2 = 3'b001; // state Q2 parameter Q3 = 3'b011; // state Q3 parameter Q4 = 3'b010; // state Q4 // Result of decoding instruction wire INST_ADDLW, INST_ADDWF, INST_ANDLW, INST_ANDWF, INST_BCF, INST_BSF, INST_BTFSC, INST_BTFSS; wire INST_CALL, INST_CLRF, INST_CLRW, INST_CLRWDT, INST_COMF, INST_DECF, INST_DECFSZ; wire INST_GOTO, INST_INCF, INST_INCFSZ, INST_IORLW, INST_IORWF, INST_MOVLW, INST_MOVF, INST_MOVWF; wire INST_RETFIE, INST_RETLW, INST_RET, INST_RLF, INST_RRF; wire INST_SLEEP, INST_SUBLW, INST_SUBWF, INST_SWAPF, INST_XORLW, INST_XORWF; // Result of calculating RAM access address wire [8:0] ramadr_node; // RAM access address wire ADDR_TMR0, ADDR_PCL, ADDR_STAT, ADDR_FSR, ADDR_PORTA, ADDR_PORTB; wire ADDR_EEDATA, ADDR_EEADR, ADDR_PCLATH, ADDR_INTCON, ADDR_OPTION, ADDR_TRISA, ADDR_TRISB; // wire ADDR_EECON1, ADDR_EECON2, ADDR_SRAM : std_logic; wire ADDR_EECON1, ADDR_SRAM; // Other output registers (for removing hazards) reg writeram_reg; // data-sram write strobe//> deleted ver1.00c, 2002/08/07 // reg [8:0] ramadr_reg // data-sram address//< reg clkout_reg; // clkout output // Synchronizers reg inte_sync_reg; reg rbint_sync_reg; reg [1:0] inctmr_sync_reg; reg rdeep_sync_reg; reg wreep_sync_reg; reg mclr_sync_reg; reg poweron_sync_reg;// CPU synchronizers always @(posedge clkin) begin inte_sync_reg <= inte; rbint_sync_reg <= rbint; wdtclr_ack_sync_reg <= wdtclr_ack; mclr_sync_reg <= mclr_n; poweron_sync_reg <= ponrst_n; rdeep_sync_reg <= readeepack; wreep_sync_reg <= writeeepack; inctmr_sync_reg[0] <= inctmrck; inctmr_sync_reg[1] <= inctmr_sync_reg[0]; if (poweron_sync_reg == 1'b0 || mclr_sync_reg == 1'b0) begin wdt_full_sync_reg <= 3'b000; end else begin wdt_full_sync_reg[0] <= wdt_full_reg; wdt_full_sync_reg[1] <= wdt_full_sync_reg[0]; // (remove meta-stable) wdt_full_sync_reg[2] <= wdt_full_sync_reg[1]; // (detect positive edge) end end// Decode OPcode (see pp.54 of PIC16F84 data sheet) // only 1 signal of the following signals will be '1' assign INST_CALL = (inst_reg[13:11] == 3'b100) ? 1'b1 : 1'b0; assign INST_GOTO = (inst_reg[13:11] == 3'b101) ? 1'b1 : 1'b0; assign INST_BCF = (inst_reg[13:10] == 4'b0100) ? 1'b1 : 1'b0; assign INST_BSF = (inst_reg[13:10] == 4'b0101) ? 1'b1 : 1'b0; assign INST_BTFSC = (inst_reg[13:10] == 4'b0110) ? 1'b1 : 1'b0; assign INST_BTFSS = (inst_reg[13:10] == 4'b0111) ? 1'b1 : 1'b0; assign INST_MOVLW = (inst_reg[13:10] == 4'b1100) ? 1'b1 : 1'b0; assign INST_RETLW = (inst_reg[13:10] == 4'b1101) ? 1'b1 : 1'b0; assign INST_SUBLW = (inst_reg[13:9] == 5'b11110) ? 1'b1 : 1'b0; assign INST_ADDLW = (inst_reg[13:9] == 5'b11111) ? 1'b1 : 1'b0; assign INST_IORLW = (inst_reg[13:8] == 6'b111000) ? 1'b1 : 1'b0; assign INST_ANDLW = (inst_reg[13:8] == 6'b111001) ? 1'b1 : 1'b0; assign INST_XORLW = (inst_reg[13:8] == 6'b111010) ? 1'b1 : 1'b0; assign INST_SUBWF = (inst_reg[13:8] == 6'b000010) ? 1'b1 : 1'b0; assign INST_DECF = (inst_reg[13:8] == 6'b000011) ? 1'b1 : 1'b0; assign INST_IORWF = (inst_reg[13:8] == 6'b000100) ? 1'b1 : 1'b0; assign INST_ANDWF = (inst_reg[13:8] == 6'b000101) ? 1'b1 : 1'b0; assign INST_XORWF = (inst_reg[13:8] == 6'b000110) ? 1'b1 : 1'b0; assign INST_ADDWF = (inst_reg[13:8] == 6'b000111) ? 1'b1 : 1'b0; assign INST_MOVF = (inst_reg[13:8] == 6'b001000) ? 1'b1 : 1'b0; assign INST_COMF = (inst_reg[13:8] == 6'b001001) ? 1'b1 : 1'b0; assign INST_INCF = (inst_reg[13:8] == 6'b001010) ? 1'b1 : 1'b0; assign INST_DECFSZ = (inst_reg[13:8] == 6'b001011) ? 1'b1 : 1'b0; assign INST_RRF = (inst_reg[13:8] == 6'b001100) ? 1'b1 : 1'b0; assign INST_RLF = (inst_reg[13:8] == 6'b001101) ? 1'b1 : 1'b0; assign INST_SWAPF = (inst_reg[13:8] == 6'b001110) ? 1'b1 : 1'b0; assign INST_INCFSZ = (inst_reg[13:8] == 6'b001111) ? 1'b1 : 1'b0; assign INST_MOVWF = (inst_reg[13:7] == 7'b0000001) ? 1'b1 : 1'b0; assign INST_CLRW = (inst_reg[13:7] == 7'b0000010) ? 1'b1 : 1'b0; assign INST_CLRF = (inst_reg[13:7] == 7'b0000011) ? 1'b1 : 1'b0; assign INST_RET = (inst_reg[13:0] == 14'b00000000001000) ? 1'b1 : 1'b0; assign INST_RETFIE = (inst_reg[13:0] == 14'b00000000001001) ? 1'b1 : 1'b0; assign INST_SLEEP = (inst_reg[13:0] == 14'b00000001100011) ? 1'b1 : 1'b0; assign INST_CLRWDT = (inst_reg[13:0] == 14'b00000001100100) ? 1'b1 : 1'b0;// Calculate RAM access address (see pp.19 of PIC16F84 data sheet) // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR // otherwise, RAM address is BANK+"d" // (see pp.19 of PIC16F84 data sheet) assign ramadr_node = (inst_reg[6:0] == 7'b0000000) ? {status_reg[7], fsr_reg[7:0]} : {status_reg[6:5], inst_reg[6:0]}; // check if this is an access to external RAM or not assign ADDR_SRAM = (ramadr_node[6:0] > 7'b0001011) ? 1'b1 // 0CH-7FH, 8CH-FFH : 1'b0; // check if this is an access to special register or not // only 1 signal of the following signals will be '1' assign ADDR_TMR0 = (ramadr_node[7:0] == 8'b00000001) ? 1'b1 // 01H : 1'b0; assign ADDR_PCL = (ramadr_node[6:0] == 7'b0000010) ? 1'b1 // 02H, 82H : 1'b0; assign ADDR_STAT = (ramadr_node[6:0] == 7'b0000011) ? 1'b1 // 03H, 83H : 1'b0; assign ADDR_FSR = (ramadr_node[6:0] == 7'b0000100) ? 1'b1 // 04H, 84H : 1'b0; assign ADDR_PORTA = (ramadr_node[7:0] == 8'b00000101) ? 1'b1 // 05H : 1'b0; assign ADDR_PORTB = (ramadr_node[7:0] == 8'b00000110) ? 1'b1 // 06H : 1'b0; assign ADDR_EEDATA = (ramadr_node[7:0] == 8'b00001000) ? 1'b1 // 08H : 1'b0; assign ADDR_EEADR = (ramadr_node[7:0] == 8'b00001001) ? 1'b1 // 09H : 1'b0; assign ADDR_PCLATH = (ramadr_node[6:0] == 7'b0001010) ? 1'b1 // 0AH, 8AH : 1'b0; assign ADDR_INTCON = (ramadr_node[6:0] == 7'b0001011) ? 1'b1 // 0BH, 8BH : 1'b0; assign ADDR_OPTION = (ramadr_node[7:0] == 8'b10000001) ? 1'b1 // 81H : 1'b0; assign ADDR_TRISA = (ramadr_node[7:0] == 8'b10000101) ? 1'b1 // 85H : 1'b0; assign ADDR_TRISB = (ramadr_node[7:0] == 8'b10000110) ? 1'b1 // 86H : 1'b0; assign ADDR_EECON1 = (ramadr_node[7:0] == 8'b10001000) ? 1'b1 // 88H : 1'b0; // assign ADDR_EECON2 = (ramadr_node[7:0] == 8'b10001001 ? 1'b1 : 1'b0; // 89H// Read value of PC-STACK top // convert binary value of stack pointer into onehot value (for reducing circuit) assign stack_pos_node[0] = (stack_pnt_reg == 0) ? 1'b1 : 1'b0; assign stack_pos_node[1] = (stack_pnt_reg == 1) ? 1'b1 : 1'b0; assign stack_pos_node[2] = (stack_pnt_reg == 2) ? 1'b1 : 1'b0; assign stack_pos_node[3] = (stack_pnt_reg == 3) ? 1'b1 : 1'b0; assign stack_pos_node[4] = (stack_pnt_reg == 4) ? 1'b1 : 1'b0; assign stack_pos_node[5] = (stack_pnt_reg == 5) ? 1'b1 : 1'b0; assign stack_pos_node[6] = (stack_pnt_reg == 6) ? 1'b1 : 1'b0; assign stack_pos_node[7] = (stack_pnt_reg == 7) ? 1'b1 : 1'b0; // pick up value of stack-top from stack cells reg [12:0] stack_cell; // value of each stack cell reg [12:0] top; // value of stack top wire [12:0] stack0_node; wire [12:0] stack1_node; wire [12:0] stack2_node; wire [12:0] stack3_node; wire [12:0] stack4_node; wire [12:0] stack5_node; wire [12:0] stack6_node; wire [12:0] stack7_node; assign stack0_node = stack_reg[0]; assign stack1_node = stack_reg[1]; assign stack2_node = stack_reg[2]; assign stack3_node = stack_reg[3]; assign stack4_node = stack_reg[4]; assign stack5_node = stack_reg[5]; assign stack6_node = stack_reg[6]; assign stack7_node = stack_reg[7]; always @(stack0_node or stack1_node or stack2_node or stack3_node or stack4_node or stack5_node or stack6_node or stack7_node or stack_pos_node) begin if (stack_pos_node[0] == 1'b1) begin // (if the position is stack top) stack_cell[0] = stack0_node; end else begin stack_cell[0] = 13'b0000000000000; end if (stack_pos_node[1] == 1'b1) begin stack_cell[1] = stack1_node; end else begin stack_cell[1] = 13'b0000000000000; end if (stack_pos_node[2] == 1'b1) begin stack_cell[2] = stack2_node; end else begin stack_cell[2] = 13'b0000000000000; end if (stack_pos_node[3] == 1'b1) begin stack_cell[3] = stack3_node; end else begin stack_cell[3] = 13'b0000000000000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -