📄 pic.v
字号:
//
// 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!
//
//
module picalu (
op,
a,
b,
y,
cin,
cout,
zout
);
input [3:0] op; // ALU Operation
input [7:0] a; // 8-bit Input a
input [7:0] b; // 8-bit Input b
output [7:0] y; // 8-bit Output
input cin;
output cout;
output zout;
// Reg declarations for outputs
reg cout;
reg zout;
reg [7:0] y;
// Internal declarations
reg addercout; // Carry out straight from the adder itself.
parameter [3:0] ALUOP_ADD = 4'b0000;
parameter [3:0] ALUOP_SUB = 4'b1000;
parameter [3:0] ALUOP_AND = 4'b0001;
parameter [3:0] ALUOP_OR = 4'b0010;
parameter [3:0] ALUOP_XOR = 4'b0011;
parameter [3:0] ALUOP_COM = 4'b0100;
parameter [3:0] ALUOP_ROR = 4'b0101;
parameter [3:0] ALUOP_ROL = 4'b0110;
parameter [3:0] ALUOP_SWAP = 4'b0111;
always @(a or b or cin or op) begin
case (op) // synopsys full_case parallel_case
ALUOP_ADD: {addercout, y} <= a + b;
ALUOP_SUB: {addercout, y} <= a - b; // Carry out is really "borrow"
ALUOP_AND: {addercout, y} <= {1'b0, a & b};
ALUOP_OR: {addercout, y} <= {1'b0, a | b};
ALUOP_XOR: {addercout, y} <= {1'b0, a ^ b};
ALUOP_COM: {addercout, y} <= {1'b0, ~a};
ALUOP_ROR: {addercout, y} <= {a[0], cin, a[7:1]};
ALUOP_ROL: {addercout, y} <= {a[7], a[6:0], cin};
ALUOP_SWAP: {addercout, y} <= {1'b0, a[3:0], a[7:4]};
default: {addercout, y} <= {1'b0, 8'h00};
endcase
end
always @(y)
zout <= (y == 8'h00);
always @(addercout or op)
if (op == ALUOP_SUB) cout <= ~addercout; // Invert adder's carry to get borrow
else cout <= addercout;
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!
//
//
module piccpu (
clk,
reset,
paddr,
pdata,
portain,
portbout,
portcout,
debugw,
debugpc,
debuginst,
debugstatus
);
input clk;
input reset;
output [8:0] paddr;
input [11:0] pdata;
input [7:0] portain;
output [7:0] portbout;
output [7:0] portcout;
output [7:0] debugw;
output [8:0] debugpc;
output [11:0] debuginst;
output [7:0] debugstatus;
// Register declarations for outputs
reg [8:0] paddr;
reg [7:0] portbout;
reg [7:0] portcout;
// This should be set to the ROM location where our restart vector is.
// As set here, we have 512 words of program space.
//
parameter RESET_VECTOR = 9'h1FF;
parameter INDF_ADDRESS = 3'h0,
TMR0_ADDRESS = 3'h1,
PCL_ADDRESS = 3'h2,
STATUS_ADDRESS = 3'h3,
FSR_ADDRESS = 3'h4,
PORTA_ADDRESS = 3'h5,
PORTB_ADDRESS = 3'h6,
PORTC_ADDRESS = 3'h7;
// Experimental custom peripheral, "Lil Adder (a 4-bit adder)" is at this address.
//
parameter EXPADDRESS_LILADDER = 7'h7F;
// ********* Special internal registers
// Instruction Register
reg [11:0] inst;
// Program Counter
reg [8:0] pc;
reg [8:0] pcplus1; // Output of the pc incrementer.
// Stack Registers and Stack "levels" register.
reg [ 1:0] stacklevel;
reg [ 8:0] stack1;
reg [ 8:0] stack2;
// W Register
reg [ 7:0] w;
// The STATUS register (#3) is 8 bits wide, however, we only currently use 2 bits
// of it; the C and Z bit.
//
// bit 0 - C
// bit 2 - Z
//
reg [ 7:0] status;
// The FSR register is the pointer register used for Indirect addressing (e.g. using INDF).
reg [ 7:0] fsr;
// Timer 0
reg [ 7:0] tmr0;
reg [ 7:0] prescaler;
// Option Register
reg [7:0] option;
// Tristate Control registers. We do not neccessarily support bidirectional ports, but
// will save a place for these registers and the TRIS instruction. Use for debug.
reg [7:0] trisa;
reg [7:0] trisb;
reg [7:0] trisc;
// I/O Port registers
//
reg [7:0] porta; // Input PORT
reg [7:0] portb; // Output PORT
reg [7:0] portc; // Output PORT
// ********** Instruction Related signals ******
reg skip; // When HI force a NOP (all zeros) into inst
reg [2:0] pcinsel;
// Derive special sub signals from inst register
wire [ 7:0] k;
wire [ 4:0] fsel;
wire [ 8:0] longk;
wire d;
wire [ 2:0] b;
// ********** File Address ************
//
// This is the 7-bit Data Address that includes the lower 5-bit fsel, the
// FSR bits and any indirect addressing.
// Use this bus to address the Register File as well as all special registers, etc.
//
reg [6:0] fileaddr;
// Address Selects
reg specialsel;
reg regfilesel;
reg expsel;
// ****** Instruction Decoder Outputs **************
// Write enable for the actual ZERO and CARRY bits within the status register.
// Generated by the Instruction Decoder.
//
wire [1:0] aluasel;
wire [1:0] alubsel;
wire [3:0] aluop;
wire zwe;
wire cwe;
wire isoption;
wire istris;
wire fwe; // High if any "register" is being written to at all.
wire wwe; // Write Enable for the W register. Produced by Instruction Decoder.
// ************* Internal Busses, mux connections, etc. ********************
// Bit decoder bits.
reg [7:0] bd; // Final decoder value after any polarity inversion.
reg [7:0] bdec; // e.g. "Bit Decoded"
// Data in and out of the and out of the register file
//
reg [7:0] regfilein; // Input into Register File, is connected to the dbus.
wire [7:0] regfileout; // Path leaving the register file, goes to SBUS Mux
reg regfilewe; // Write Enable
reg regfilere; // Read Enable
//
// The dbus (Destination Bus) comes out of the ALU. It is available to all
// writable registers.
//
// The sbus (Source Bus) comes from all readable registers as well as the output
// of the Register File. It is one of the primary inputs into the ALU muxes.
//
// The ebus (Expansion Bus) comes from any of our custom modules. They must
// all coordinate to place whoever's data onto ebus.
//
reg [7:0] dbus;
reg [7:0] sbus;
reg [7:0] ebus;
// ALU Signals
//
reg [7:0] alua;
reg [7:0] alub;
wire [7:0] aluout;
wire alucin;
wire alucout;
wire aluz;
// ALU A and B mux selects.
//
parameter [1:0] ALUASEL_W = 2'b00,
ALUASEL_SBUS = 2'b01,
ALUASEL_K = 2'b10,
ALUASEL_BD = 2'b11;
parameter [1:0] ALUBSEL_W = 2'b00,
ALUBSEL_SBUS = 2'b01,
ALUBSEL_K = 2'b10,
ALUBSEL_1 = 2'b11;
// ALU Operation codes.
//
parameter [3:0] ALUOP_ADD = 4'b0000;
parameter [3:0] ALUOP_SUB = 4'b1000;
parameter [3:0] ALUOP_AND = 4'b0001;
parameter [3:0] ALUOP_OR = 4'b0010;
parameter [3:0] ALUOP_XOR = 4'b0011;
parameter [3:0] ALUOP_COM = 4'b0100;
parameter [3:0] ALUOP_ROR = 4'b0101;
parameter [3:0] ALUOP_ROL = 4'b0110;
parameter [3:0] ALUOP_SWAP = 4'b0111;
// Instantiate each of our subcomponents
//
picregs regs (
.clk (clk),
.reset (reset),
.we (regfilewe),
.re (regfilere),
.bank (fileaddr[6:5]),
.location (fileaddr[4:0]),
.din (regfilein),
.dout (regfileout)
);
// Instatiate the ALU.
//
picalu alu (
.op (aluop),
.a (alua),
.b (alub),
.y (aluout),
.cin (status[0]),
.cout (alucout),
.zout (aluz)
);
// Instantiate the Instruction Decoder. This is really just a lookup table.
// Given the instruction, generate all the signals we need.
//
// For example, each instruction implies a specific ALU operation. Some of
// these are obvious such as the ADDW uses an ADD alu op. Less obvious is
// that a mov instruction uses an OR op which lets us do a simple copy.
//
// Data has to funnel through the ALU, which sometimes makes for contrived
// ALU ops.
//
picidec idec (
.inst (inst),
.aluasel (aluasel),
.alubsel (alubsel),
.aluop (aluop),
.wwe (wwe),
.fwe (fwe),
.zwe (zwe),
.cwe (cwe),
.bdpol (bdpol),
.option (isoption),
.tris (istris)
);
// *********** Debug ****************
assign debugw = w;
assign debugpc = pc;
assign debuginst = inst;
assign debugstatus = status;
// *********** REGISTER FILE Addressing ****************
//
// We implement the following:
// - The 5-bit fsel address is within a "BANK" which is 32 bytes.
// - The FSR bits 6:5 are the BANK select, so there are 4 BANKS, a
// total of 128 bytes. Minus the 8 special registers, that's
// really 120 bytes.
// - The INDF register is for indirect addressing. Referencing INDF
// uses FSR as the pointer. Therefore, using INDF/FSR you address
// 7-bits of memory.
// We DO NOT currently implement the PAGE for program (e.g. STATUS register
// bits 6:5)
//
// The fsel address *may* be zero in which case, we are to do indirect
// addressing, using FSR register as the 8-bit pointer.
//
// Otherwise, use the 5-bits of FSEL (from the Instruction itself) and
// 2 bank bits from the FSR register (bits 6:5).
//
always @(fsel or fsr) begin
if (fsel == INDF_ADDRESS) begin
// The INDEX register is addressed. There really is no INDEX register.
// Use the FSR as an index, e.g. the FSR contents are the fsel.
//
fileaddr <= fsr[6:0];
end
else begin
// Use FSEL field and status bank select bits
//
fileaddr <= {fsr[6:5], fsel};
end
end
// Write Enable to Register File.
// Assert this when the general fwe (write enable to *any* register) is true AND Register File
// address range is specified.
//
always @(regfilesel or fwe)
regfilewe <= regfilesel & fwe;
// Read Enable (this if nothing else, helps in debug.)
// Assert if Register File address range is specified AND the ALU is actually using some
// data off the SBUS.
//
always @(regfilesel or aluasel or alubsel)
regfilere <= regfilesel & ((aluasel == ALUASEL_SBUS) | (alubsel == ALUBSEL_SBUS));
// *********** Address Decodes **************
//
// Generate 3 selects: specialsel, regfilesel and expsel
always @(fileaddr) begin
casex (fileaddr)
7'bXX00XXX: // The SPECIAL Registers are lower 8 addresses, in ALL BANKS
begin
specialsel <= 1'b1;
regfilesel <= 1'b0;
expsel <= 1'b0;
end
7'b1111111: // EXPANSION Registers are the top (1) addresses
begin
specialsel <= 1'b0;
regfilesel <= 1'b0;
expsel <= 1'b1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -