📄 pic.v
字号:
end
default: // Anything else must be in the Register File
begin
specialsel <= 1'b0;
regfilesel <= 1'b1;
expsel <= 1'b0;
end
endcase
end
// *********** SBUS **************
// The sbus (Source Bus) is the output of a multiplexor that takes
// inputs from the Register File, and all other special registers
// and input ports. The Source Bus then, one of the inputs to the ALU
// First MUX selects from all the special regsiters
//
always @(fsel or fsr or tmr0 or pc or status
or porta or portb or portc or regfileout or ebus
or specialsel or regfilesel or expsel) begin
// For our current mix of registers and peripherals, only the first 8 addresses
// are "special" registers (e.g. not in the Register File). As more peripheral
// registers are added, they must be muxed into this MUX as well.
//
// We currently prohibit tristates.
//
//
if (specialsel) begin
// Special register
case (fsel[2:0]) // synopsys parallel_case full_case
3'h0: sbus <= fsr;
3'h1: sbus <= tmr0;
3'h2: sbus <= pc[7:0];
3'h3: sbus <= status;
3'h4: sbus <= fsr;
3'h5: sbus <= porta; // PORTA is an input-only port
3'h6: sbus <= portb; // PORTB is an output-only port
3'h7: sbus <= portc; // PORTC is an output-only port
endcase
end
else begin
//
// Put whatever address equation is neccessary here. Remember to remove unnecessary
// memory elements from Register File (picregs.v). It'll still work, but they'd be
// wasted flip-flops.
//
if (expsel) begin
sbus <= ebus;
end
else begin
if (regfilesel) begin
// Final Priority is Choose the register file
sbus <= regfileout;
end
else begin
sbus <= 8'h00;
end
end
end
end
// ************** DBUS ******
// The Destination bus is just the output of the ALU.
//
always @(aluout)
dbus <= aluout;
always @(dbus)
regfilein <= dbus;
// Drive the ROM address bus straight from the PC
//
always @(pc)
paddr = pc;
// Define sub-signals out of inst
//
assign k = inst[7:0];
assign fsel = inst[4:0];
assign longk = inst[8:0];
assign d = inst[5];
assign b = inst[7:5];
// Bit Decoder.
//
// Simply take the 3-bit b field in the PIC instruction and create the
// expanded 8-bit decoder field, which is used as a mask.
//
always @(b) begin
case (b)
3'b000: bdec <= 8'b00000001;
3'b001: bdec <= 8'b00000010;
3'b010: bdec <= 8'b00000100;
3'b011: bdec <= 8'b00001000;
3'b100: bdec <= 8'b00010000;
3'b101: bdec <= 8'b00100000;
3'b110: bdec <= 8'b01000000;
3'b111: bdec <= 8'b10000000;
endcase
end
always @(bdec or bdpol)
bd <= bdec ^ bdpol;
// Instruction regsiter usually get the ROM data as its input, but
// sometimes for branching, the skip signal must cause a NOP.
//
always @(posedge clk) begin
if (reset) begin
inst <= 12'h000;
end
else begin
if (skip == 1'b1) begin
inst <= 12'b000000000000; // FORCE NOP
end
else begin
inst <= pdata;
end
end
end
// SKIP signal.
//
// We want to insert the NOP instruction for the following conditions:
// GOTO,CALL and RETLW instructions (All have inst[11:10] = 2'b10
// BTFSS instruction when aluz is HI (
// BTFSC instruction when aluz is LO
//
always @(inst or aluz) begin
casex ({inst, aluz})
13'b10??_????_????_?: // A GOTO, CALL or RETLW instructions
skip <= 1'b1;
13'b0110_????_????_1: // BTFSC instruction and aluz == 1
skip <= 1'b1;
13'b0111_????_????_0: // BTFSS instruction and aluz == 0
skip <= 1'b1;
13'b0010_11??_????_1: // DECFSZ instruction and aluz == 1
skip <= 1'b1;
13'b0011_11??_????_1: // INCFSZ instruction and aluz == 1
skip <= 1'b1;
default:
skip <= 1'b0;
endcase
end
// 4:1 Data MUX into alua
//
//
always @(aluasel or w or sbus or k or bd) begin
case (aluasel)
2'b00: alua <= w;
2'b01: alua <= sbus;
2'b10: alua <= k;
2'b11: alua <= bd;
endcase
end
// 4:1 Data MUX into alub
//
//
always @(alubsel or w or sbus or k) begin
case (alubsel)
2'b00: alub <= w;
2'b01: alub <= sbus;
2'b10: alub <= k;
2'b11: alub <= 8'b00000001;
endcase
end
// W Register
always @(posedge clk) begin
if (reset) begin
w <= 8'h00;
end
else begin
if (wwe) begin
w <= dbus;
end
end
end
// ************ Writes to various Special Registers (fsel between 0 and 7)
// INDF Register (Register #0)
//
// Not a real register. This is the Indirect Addressing mode register.
// See the regfileaddr logic.
// TMR0 Register (Register #1)
//
// Timer0 is currently only a free-running timer clocked by the main system clock.
//
always @(posedge clk) begin
if (reset) begin
tmr0 <= 8'h00;
end
else begin
// See if the status register is actually being written to
if (fwe & specialsel & (fsel == TMR0_ADDRESS)) begin
// Yes, so just update the register from the dbus
tmr0 <= dbus;
end
else begin
// Mask off the prescaler value based on desired divide ratio.
// Whenever this is zero, then that is our divided pulse. Increment
// the final timer value when it's zero.
//
case (option[2:0]) // synopsys parallel_case full_case
3'b000: if (~|(prescaler & 8'b00000001)) tmr0 <= tmr0 + 1;
3'b001: if (~|(prescaler & 8'b00000011)) tmr0 <= tmr0 + 1;
3'b010: if (~|(prescaler & 8'b00000111)) tmr0 <= tmr0 + 1;
3'b011: if (~|(prescaler & 8'b00001111)) tmr0 <= tmr0 + 1;
3'b100: if (~|(prescaler & 8'b00011111)) tmr0 <= tmr0 + 1;
3'b101: if (~|(prescaler & 8'b00111111)) tmr0 <= tmr0 + 1;
3'b110: if (~|(prescaler & 8'b01111111)) tmr0 <= tmr0 + 1;
3'b111: if (~|(prescaler & 8'b11111111)) tmr0 <= tmr0 + 1;
endcase
end
end
end
// The prescaler is always counting from 00 to FF
always @(posedge clk) begin
if (reset) begin
prescaler <= 8'h00;
end
else begin
// See if the status register is actually being written to
prescaler <= prescaler + 1;
end
end
// PCL Register (Register #2)
//
// PC Lower 8 bits. This is handled in the PC section below...
// STATUS Register (Register #3)
//
always @(posedge clk) begin
if (reset) begin
status <= 8'h00;
end
else begin
// See if the status register is actually being written to
if (fwe & specialsel & (fsel == STATUS_ADDRESS)) begin
// Yes, so just update the register from the dbus
status <= dbus;
end
else begin
// Update status register on a bit-by-bit basis.
//
// For the carry and zero flags, each instruction has its own rule as
// to whether to update this flag or not. The instruction decoder is
// providing us with an enable for C and Z. Use this to decide whether
// to retain the existing value, or update with the new alu status output.
//
status <= {
status[7], // BIT 7: Undefined.. (maybe use for debugging)
status[6], // BIT 6: Program Page, HI bit
status[5], // BIT 5: Program Page, LO bit
status[4], // BIT 4: Time Out bit (not implemented at this time)
status[3], // BIT 3: Power Down bit (not implemented at this time)
(zwe) ? aluz : status[2], // BIT 2: Z
status[1], // BIT 1: DC
(cwe) ? alucout : status[0] // BIT 0: C
};
end
end
end
// FSR Register (Register #4)
//
always @(posedge clk) begin
if (reset) begin
fsr <= 8'h00;
end
else begin
// See if the status register is actually being written to
if (fwe & specialsel & (fsel == FSR_ADDRESS)) begin
fsr <= dbus;
end
end
end
// OPTION Register
//
// The special OPTION instruction should move W into the OPTION register.
always @(posedge clk) begin
if (reset) begin
option <= 8'h00;
end
else begin
if (isoption)
option <= dbus;
end
end
// PORTA Input Port (Register #5)
//
// Register anything on the module's porta input on every single clock.
//
always @(posedge clk) begin
if (reset) begin
porta <= 8'h00;
end
else begin
porta <= portain;
end
end
// PORTB Output Port (Register #6)
always @(posedge clk) begin
if (reset) begin
portb <= 8'h00;
end
else begin
if (fwe & specialsel & (fsel == PORTB_ADDRESS) & ~istris) begin
portb <= dbus;
end
end
end
// Connect the output ports to the register output.
always @(portb)
portbout <= portb;
// PORTC Output Port (Register #7)
always @(posedge clk) begin
if (reset) begin
portc <= 8'h00;
end
else begin
if (fwe & specialsel & (fsel == PORTC_ADDRESS) & ~istris) begin
portc <= dbus;
end
end
end
// Connect the output ports to the register output.
always @(portc)
portcout <= portc;
// TRIS Registers
always @(posedge clk) begin
if (reset) begin
trisa <= 8'hff; // Default is to tristate them
end
else begin
if (fwe & specialsel & (fsel == PORTA_ADDRESS) & istris) begin
trisa <= dbus;
end
end
end
always @(posedge clk) begin
if (reset) begin
trisb <= 8'hff; // Default is to tristate them
end
else begin
if (fwe & specialsel & (fsel == PORTB_ADDRESS) & istris) begin
trisb <= dbus;
end
end
end
always @(posedge clk) begin
if (reset) begin
trisc <= 8'hff; // Default is to tristate them
end
else begin
if (fwe & specialsel & (fsel == PORTC_ADDRESS) & istris) begin
trisc <= dbus;
end
end
end
// ********** PC AND STACK *************************
//
// There are 4 ways to change the PC. They are:
// GOTO 101k_kkkk_kkkk
// CALL 1001_kkkk_kkkk
// RETLW 1000_kkkk_kkkk
// MOVF 0010_0010_0010 (e.g. a write to reg #2)
//
// Remember that the skip instructions work by inserting
// a NOP instruction or not into program stream and don't
// change the PC.
//
// We need pc + 1 in several places, so lets define this incrementor and
// its output signal it in one place so that we never get redundant adders.
//
always @(pc)
pcplus1 <= pc + 1;
parameter PC_SELECT_PCPLUS1 = 3'b000,
PC_SELECT_K = 3'b001,
PC_SELECT_STACK1 = 3'b010,
PC_SELECT_STACK2 = 3'b011,
PC_SELECT_DBUS = 3'b100,
PC_SELECT_RESET_VECTOR = 3'b101;
// 8:1 Data MUX into PC
always @(posedge clk) begin
case (pcinsel) // synopsys parallel_case full_case
3'b000: pc <= pcplus1;
3'b001: pc <= k;
3'b010: pc <= stack1;
3'b011: pc <= stack2;
3'b100: pc <= dbus;
3'b101: pc <= RESET_VECTOR;
// Don't really carry about these...
3'b110: pc <= pc;
3'b111: pc <= pc;
endcase
end
// Select for the MUX going into the PC.
//
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -