📄 pic.v
字号:
always @(inst or stacklevel or reset) begin
if (reset == 1'b1) begin
pcinsel <= PC_SELECT_RESET_VECTOR;
end
else begin
casex ({inst, stacklevel})
14'b101?_????_????_??: pcinsel <= PC_SELECT_K; // GOTO
14'b1001_????_????_??: pcinsel <= PC_SELECT_K; // CALL
14'b1000_????_????_00: pcinsel <= PC_SELECT_STACK1; // RETLW
14'b1000_????_????_01: pcinsel <= PC_SELECT_STACK1; // RETLW
14'b1000_????_????_10: pcinsel <= PC_SELECT_STACK2; // RETLW
14'b1000_????_????_11: pcinsel <= PC_SELECT_STACK2; // RETLW
14'b0010_0010_0010_??: pcinsel <= PC_SELECT_DBUS; // MOVF where f=PC
default:
pcinsel <= PC_SELECT_PCPLUS1;
endcase
end
end
// Implement STACK1 and STACK2 registers
//
// The Stack registers are only fed from the PC itself!
//
always @(posedge clk) begin
if (reset) begin
stack1 <= 9'h000;
end
else begin
// CALL instruction
if (inst[11:8] == 4'b1001) begin
case (stacklevel)
2'b00:
// No previous CALLs
begin
stack1 <= pc;
$display ("Write to STACK1: %0h", pc);
end
2'b01:
// ONE previous CALL
begin
stack2 <= pc;
$display ("Write to STACK2: %0h", pc);
end
2'b10:
// TWO previous CALLs -- This is illegal on the 16C5X!
begin
$display ("Too many CALLs!!");
end
2'b11:
begin
$display ("Too many CALLs!!");
end
endcase
end
end
end
// Write to stacklevel
//
// The stacklevel register keeps track of the current stack depth. On this
// puny processor, there are only 2 levels (you could fiddle with this and
// increase the stack depth). There are two stack registers, stack1 and stack2.
// The stack1 register is used first (e.g. the first time a call is performed),
// then stack2. As CALLs are done, stacklevel increments. Conversely, as
// RETs are done, stacklevel goes down.
always @(posedge clk) begin
if (reset == 1'b1) begin
stacklevel <= 2'b00; // On reset, there should be no CALLs in progress
end
else begin
casex ({inst, stacklevel})
// Call instructions
14'b1001_????_????_00: stacklevel <= 2'b01; // Record 1st CALL
14'b1001_????_????_01: stacklevel <= 2'b10; // Record 2nd CALL
14'b1001_????_????_10: stacklevel <= 2'b10; // Already 2! Ignore
14'b1001_????_????_11: stacklevel <= 2'b00; // {shouldn't happen}
// Return instructions
14'b1000_????_????_00: stacklevel <= 2'b00; // {shouldn't happen}
14'b1000_????_????_01: stacklevel <= 2'b00; // Go back to no CALL in progress
14'b1000_????_????_10: stacklevel <= 2'b01; // Go back to 1 CALL in progress
14'b1000_????_????_11: stacklevel <= 2'b10; // {shouldn't happen} sort of like, Go back to 2 calls in progress
default:
stacklevel <= stacklevel;
endcase
end
end
// ************ EXPANSION *************************
//
// The following is an example of customization.
//
// Example: Create a read/write port located at address 7F. It'll be 8-bits, where
// the upper 4 bits are outputs and the lower 4 bits are inputs.
// Use indirect addressing to access it (INDF/FSR). Just for fun, let's
// attach a special loop-back circuit between the outputs and inputs.
// Let's attach... say... a 4-bit adder.
//
reg [3:0] special_peripheral_writeable_bits;
reg [3:0] special_peripheral_readeable_bits;
// Implement the writeable bits.
//
always @(posedge clk) begin
if (reset) begin
special_peripheral_writeable_bits <= 4'b0000;
end
else begin
if (fwe & expsel & (fileaddr == EXPADDRESS_LILADDER)) begin
special_peripheral_writeable_bits <= dbus;
end
end
end
// Implement the special peripheral function (the 4-bit adder for this example).
always @(special_peripheral_writeable_bits) begin
special_peripheral_readeable_bits <= special_peripheral_writeable_bits + 1;
end
// Drive the ebus. With only one custom address, no more muxing needs to be
// done, but if there are multiple custom circuits, everyone needs to cooperate
// and drive ebus properly.
//
always @(fileaddr or special_peripheral_readeable_bits) begin
if (fileaddr == EXPADDRESS_LILADDER)
ebus <= special_peripheral_readeable_bits;
else
ebus <= 8'hff;
end
endmodule
//
// SYNTHETIC PIC 2.0 4/23/98
//
// This is a synthesizable Microchip 16C57 compatible
// microcontroller. This core is not intended as a high fidelity model of
// the PIC, but simply a way to offer a simple processor core to people
// familiar with the PIC who also have PIC tools.
//
// pictest.v - top-level testbench (NOT SYNTHESIZABLE)
// piccpu.v - top-level synthesizable module
// picregs.v - register file instantiated under piccpu
// picalu.v - ALU instantiated under piccpu
// picidec.v - Instruction Decoder instantiated under piccpu
// hex2rom.c - C program used to translate MPLAB's INTEL HEX output
// into the Verilog $readmemh compatible file
// test*.asm - (note the wildcard..) Several test programs used
// to help debug the verilog. I used MPLAB and the simulator
// to develop these programs and get the expected results.
// Then, I ran them on Verilog-XL where they appeared to
// match.
//
// Copyright, Tom Coonan, '97.
// Use freely, but not for resale as is. You may use this in your
// own projects as desired. Just don't try to sell it as is!
//
//
// This is the PIC Instruction Decoder.
//
// The 12-bit PIC instruction must result in a set of control
// signals to the ALU, register write enables and other wires.
// This is purely combinatorial. This can physically be
// implemented as a ROM, or, in this implementation a Verilog
// casex statement is used to directly synthesize the signals.
// This approach is more portable, and hopefully much reduction
// occurs in the equations.
//
// The Synthetic PIC Manual contains a table that better shows
// all the required signals per instruction. I basically
// took that table and created the Verilog implementation below.
//
module picidec (
inst,
aluasel,
alubsel,
aluop,
wwe,
fwe,
zwe,
cwe,
bdpol,
option,
tris
);
input [11:0] inst;
output [1:0] aluasel;
output [1:0] alubsel;
output [3:0] aluop;
output wwe;
output fwe;
output zwe;
output cwe;
output bdpol;
output option;
output tris;
reg [14:0] decodes;
// For reference, the ALU Op codes are:
//
// ADD 0000
// SUB 1000
// AND 0001
// OR 0010
// XOR 0011
// COM 0100
// ROR 0101
// ROL 0110
// SWAP 0111
assign { aluasel, // Select source for ALU A input. 00=W, 01=SBUS, 10=K, 11=BD
alubsel, // Select source for ALU B input. 00=W, 01=SBUS, 10=K, 11="1"
aluop, // ALU Operation (see comments above for these codes)
wwe, // W register Write Enable
fwe, // File Register Write Enable
zwe, // Status register Z bit update
cwe, // Status register Z bit update
bdpol, // Polarity on bit decode vector (0=no inversion, 1=invert)
tris, // Instruction is an TRIS instruction
option // Instruction is an OPTION instruction
} = decodes;
// This is a large combinatorial decoder.
// I use the casex statement.
always @(inst) begin
casex (inst)
// *** Byte-Oriented File Register Operations
//
// A A ALU W F Z C B T O
// L L O W W W W D R P
// U U P E E E E P I T
// A B O S
// L
12'b0000_0000_0000: decodes <= 15'b00_00_0000_0_0_0_0_0_0_0; // NOP
12'b0000_001X_XXXX: decodes <= 15'b00_00_0010_0_1_0_0_0_0_0; // MOVWF
12'b0000_0100_0000: decodes <= 15'b00_00_0011_1_0_1_0_0_0_0; // CLRW
12'b0000_011X_XXXX: decodes <= 15'b00_00_0011_0_1_1_0_0_0_0; // CLRF
12'b0000_100X_XXXX: decodes <= 15'b01_00_1000_1_0_1_1_0_0_0; // SUBWF (d=0)
12'b0000_101X_XXXX: decodes <= 15'b01_00_1000_0_1_1_1_0_0_0; // SUBWF (d=1)
12'b0000_110X_XXXX: decodes <= 15'b01_11_1000_1_0_1_0_0_0_0; // DECF (d=0)
12'b0000_111X_XXXX: decodes <= 15'b01_11_1000_0_1_1_0_0_0_0; // DECF (d=1)
12'b0001_000X_XXXX: decodes <= 15'b00_01_0010_1_0_1_0_0_0_0; // IORWF (d=0)
12'b0001_001X_XXXX: decodes <= 15'b00_01_0010_0_1_1_0_0_0_0; // IORWF (d=1)
12'b0001_010X_XXXX: decodes <= 15'b00_01_0001_1_0_1_0_0_0_0; // ANDWF (d=0)
12'b0001_011X_XXXX: decodes <= 15'b00_01_0001_0_1_1_0_0_0_0; // ANDWF (d=1)
12'b0001_100X_XXXX: decodes <= 15'b00_01_0011_1_0_1_0_0_0_0; // XORWF (d=0)
12'b0001_101X_XXXX: decodes <= 15'b00_01_0011_0_1_1_0_0_0_0; // XORWF (d=1)
12'b0001_110X_XXXX: decodes <= 15'b00_01_0000_1_0_1_1_0_0_0; // ADDWF (d=0)
12'b0001_111X_XXXX: decodes <= 15'b00_01_0000_0_1_1_1_0_0_0; // ADDWF (d=1)
12'b0010_000X_XXXX: decodes <= 15'b01_01_0010_1_0_1_0_0_0_0; // MOVF (d=0)
12'b0010_001X_XXXX: decodes <= 15'b01_01_0010_0_1_1_0_0_0_0; // MOVF (d=1)
12'b0010_010X_XXXX: decodes <= 15'b01_01_0100_1_0_1_0_0_0_0; // COMF (d=0)
12'b0010_011X_XXXX: decodes <= 15'b01_01_0100_0_1_1_0_0_0_0; // COMF (d=1)
12'b0010_100X_XXXX: decodes <= 15'b01_11_0000_1_0_1_0_0_0_0; // INCF (d=0)
12'b0010_101X_XXXX: decodes <= 15'b01_11_0000_0_1_1_0_0_0_0; // INCF (d=1)
12'b0010_110X_XXXX: decodes <= 15'b01_11_1000_1_0_0_0_0_0_0; // DECFSZ(d=0)
12'b0010_111X_XXXX: decodes <= 15'b01_11_1000_0_1_0_0_0_0_0; // DECFSZ(d=1)
12'b0011_000X_XXXX: decodes <= 15'b01_01_0101_1_0_0_1_0_0_0; // RRF (d=0)
12'b0011_001X_XXXX: decodes <= 15'b01_01_0101_0_1_0_1_0_0_0; // RRF (d=1)
12'b0011_010X_XXXX: decodes <= 15'b01_01_0110_1_0_0_1_0_0_0; // RLF (d=0)
12'b0011_011X_XXXX: decodes <= 15'b01_01_0110_0_1_0_1_0_0_0; // RLF (d=1)
12'b0011_100X_XXXX: decodes <= 15'b01_01_0111_1_0_0_0_0_0_0; // SWAPF (d=0)
12'b0011_101X_XXXX: decodes <= 15'b01_01_0111_0_1_0_0_0_0_0; // SWAPF (d=1)
12'b0011_110X_XXXX: decodes <= 15'b01_11_0000_1_0_0_0_0_0_0; // INCFSZ(d=0)
12'b0011_111X_XXXX: decodes <= 15'b01_11_0000_0_1_0_0_0_0_0; // INCFSZ(d=1)
// *** Bit-Oriented File Register Operations
//
// A A ALU W F Z C B T O
// L L O W W W W D R P
// U U P E E E E P I T
// A B O S
// L
12'b0100_XXXX_XXXX: decodes <= 15'b11_01_0001_0_1_0_0_1_0_0; // BCF
12'b0101_XXXX_XXXX: decodes <= 15'b11_01_0010_0_1_0_0_0_0_0; // BSF
12'b0110_XXXX_XXXX: decodes <= 15'b11_01_0001_0_0_0_0_0_0_0; // BTFSC
12'b0111_XXXX_XXXX: decodes <= 15'b11_01_0001_0_0_0_0_0_0_0; // BTFSS
// *** Literal and Control Operations
//
// A A ALU W F Z C B T O
// L L O W W W W D R P
// U U P E E E E P I T
// A B O S
// L
12'b0000_0000_0010: decodes <= 15'b00_00_0010_0_1_0_0_0_0_1; // OPTION
12'b0000_0000_0011: decodes <= 15'b00_00_0000_0_0_0_0_0_0_0; // SLEEP
12'b0000_0000_0100: decodes <= 15'b00_00_0000_0_0_0_0_0_0_0; // CLRWDT
12'b0000_0000_0101: decodes <= 15'b00_00_0000_0_1_0_0_0_1_0; // TRIS 5
12'b0000_0000_0110: decodes <= 15'b00_00_0010_0_1_0_0_0_1_0; // TRIS 6
12'b0000_0000_0111: decodes <= 15'b00_00_0010_0_1_0_0_0_1_0; // TRIS 7
//
// A A ALU W F Z C B T O
// L L O W W W W D R P
// U U P E E E E P I T
// A B O S
// L
12'b1000_XXXX_XXXX: decodes <= 15'b10_10_0010_1_0_0_0_0_0_0; // RETLW
12'b1001_XXXX_XXXX: decodes <= 15'b10_10_0010_0_0_0_0_0_0_0; // CALL
12'b101X_XXXX_XXXX: decodes <= 15'b10_10_0010_0_0_0_0_0_0_0; // GOTO
12'b1100_XXXX_XXXX: decodes <= 15'b10_10_0010_1_0_0_0_0_0_0; // MOVLW
12'b1101_XXXX_XXXX: decodes <= 15'b00_10_0010_1_0_1_0_0_0_0; // IORLW
12'b1110_XXXX_XXXX: decodes <= 15'b00_10_0001_1_0_1_0_0_0_0; // ANDLW
12'b1111_XXXX_XXXX: decodes <= 15'b00_10_0011_1_0_1_0_0_0_0; // XORLW
default:
decodes <= 15'b00_00_0000_0_0_0_0_0_0_0;
endcase
end
endmodule
//
// SYNTHETIC PIC 2.0 4/23/98
//
// This is a synthesizable Microchip 16C57 compatible
// microcontroller. This core is not intended as a high fidelity model of
// the PIC, but simply a way to offer a simple processor core to people
// familiar with the PIC who also have PIC tools.
//
// pictest.v - top-level testbench (NOT SYNTHESIZABLE)
// piccpu.v - top-level synthesizable module
// picregs.v - register file instantiated under piccpu
// picalu.v - ALU instantiated under piccpu
// picidec.v - Instruction Decoder instantiated under piccpu
// hex2rom.c - C program used to translate MPLAB's INTEL HEX output
// into the Verilog $readmemh compatible file
// test*.asm - (note the wildcard..) Several test programs used
// to help debug the verilog. I used MPLAB and the simulator
// to develop these programs and get the expected results.
// Then, I ran them on Verilog-XL where they appeared to
// match.
//
// Copyright, Tom Coonan, '97.
// Use freely, but not for resale as is. You may use this in your
// own projects as desired. Just don't try to sell it as is!
//
//
//`define DEBUG_SHOWREADS
//`define DEBUG_SHOWWRITES
// Memory Map:
//
// PIC Data Memory addressing is complicated. See the Data Book for full explanation..
//
// Basically, each BANK contains 32 locations. The lowest 16 locations in ALL Banks
// are really all mapped to the same bank (bank #0). The first 8 locations are the Special
// registers like the STATUS and PC registers. The upper 16 words in each bank, really are
// unique to each bank. The smallest PIC (16C54) only has the one bank #0.
//
// So, as a programmer, what you get is this. No matter what bank you are in (FSR[6:5])
// you always have access to your special registers and also to registers 8-15. You can
// change to a 1 of 4 banks by setting FSR[6:5] and get 4 different sets of registers
// 16-31.
//
// For numbering purposes, I've numbered the registers as if they are one linear memory
// space, just like in the Data Book (see Figure 4-15 "Direct/Indirect Addressing").
// So, the unique 16 registers in bank #1 are named r48 - r63 (I use decimal). The
// unique registers in bank #3 are therefore r112 - r127. There is no r111 because,
// remember, the lower 16 registers each each bank are all reall the same registers 0-15.
//
// Confused?! The Data Book explains it better than I can.
//
// bank location
// XX 00rrr - The special registers are not implemented in this register file.
// XX 01rrr - The 8 common words, just above the Special Regs, same for all Banks
// 00 1rrrr - The 16 words unique to Bank #0
// 01 1rrrr - The 16 words unique to Bank #1
// 10 1rrrr - The 16 words unique to Bank #2
// 11 1rrrr - The 16 words unique to Bank #3
//
// So,
// Special Regs are location[4:3] == 00
// Common Regs are location[4:3] == 01
// Words in banks location[4] == 1
//
//
// I had problems trying to use simple register file declarations that
// would always, always work right, were synthesizable and allowed
// me to easily remove locations from the memory space. SOOOooo... I
// did the brute force thing and enumerated all the locations..
//
// Much larger spaces will probably need a RAM and whatever I do would need
// custom hacking anyway.. I don't see an obvious solution to all this, but
// welcome suggestions..
//
module picregs (clk, reset, we, re, bank, location, din, dout);
input clk;
input reset;
input we;
input re;
input [1:0] bank; // Bank 0,1,2,3
input [4:0] location; // Location
input [7:0] din; // Input
output [7:0] dout; // Output
//parameter MAX_ADDRESS = 127;
reg [7:0] dout;
integer index;
// Declare the major busses in and out of each block.
//
reg [7:0] commonblockout; // Data Memory common across all banks
reg [7:0] highblock0out; // Upper 16 bytes in BANK #0
reg [7:0] highblock1out; // Upper 16 bytes in BANK #1
reg [7:0] highblock2out; // Upper 16 bytes in BANK #2
reg [7:0] highblock3out; // Upper 16 bytes in BANK #3
reg [7:0] commonblockin; // Data Memory common across all banks
reg [7:0] highblock0in; // Upper 16 bytes in BANK #0
reg [7:0] highblock1in; // Upper 16 bytes in BANK #1
reg [7:0] highblock2in; // Upper 16 bytes in BANK #2
reg [7:0] highblock3in; // Upper 16 bytes in BANK #3
reg commonblocksel; // Select
reg highblock0sel; // Select
reg highblock1sel; // Select
reg highblock2sel; // Select
reg highblock3sel; // Select
// synopsys translate_off
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -