processor.v
module processor (clock, interrupt, read, write, address, data, ready);
// PARAMETERS
// SMI INSTANCE NAME
parameter INSTANCE = "";
// ADDRESS AND DATA BUS WIDTHS
parameter ADDR_WIDTH = 16;
parameter DATA_WIDTH = 16;
// INTERFACE
input clock;
input interrupt;
output read;
output write;
output [ADDR_WIDTH-1:0] address;
inout [DATA_WIDTH-1:0] data;
input ready;
// CONSTANTS
// MESSAGE TYPE IDENTIFIERS
parameter CPU_CONFIGURE = 1;
parameter CPU_INSTRUCTION = 2;
parameter CPU_IDLE = 3;
parameter CPU_OUT = 4;
parameter CPU_IN = 5;
parameter CPU_DATA = 6;
parameter CPU_INTERRUPT = 7;
parameter CPU_IRET = 8;
// INTERNAL SIGNALS
// READ AND WRITE
reg rd, wr;
// INTERRUPT ENABLE
reg ie;
// ADDRESS BUS
reg [ADDR_WIDTH-1:0] addr;
// DATA BUS
reg [DATA_WIDTH-1:0] dout;
// CURRENT INSTRUCTION
integer instruction;
// SMI MODEL IDENTIFIER
integer id;
// IMPLEMENTATION
initial
begin
// SET DEFAULT OUTPUTS
addr <= 0;
dout <= 0;
{rd,wr,ie} <= 3'b001;
// REGISTER THE MODEL INSTANCE WITH SMI
$smi_initial(id, "processor", INSTANCE);
// CONFIGURE THE BUS DIMENSIONS BY SENDING A "Configure" MESSAGE
$smi_write(id, CPU_CONFIGURE, ADDR_WIDTH, DATA_WIDTH);
// PRINT THE CONFIGURATION
$display("MODEL-%d: processor(%s)[ADDRESS WIDTH=%d; DATA WIDTH=%d]", id, INSTANCE, ADDR_WIDTH, DATA_WIDTH);
end
always@(posedge clock)
begin
// IF INTERRUPTS ARE ENABLED AND AN INTERRUPT IS DETECTED
if (ie && interrupt)
begin
// SEND AN "Interrupt" MESSAGE
$smi_write(id, CPU_INTERRUPT);
// DISABLE INTERRUPTS
ie = 0;
end
// FETCH THE NEXT INSTRUCTION
$smi_read(id, CPU_INSTRUCTION, instruction);
// CHOOSE AND ACTION DEPENDING ON THE MESSAGE TYPE
case (instruction)
// IF THE MESSAGE TYPE IS "Idle"; DO NOTHING FOR A CLOCK CYCLE
CPU_IDLE: @(posedge clock);
// IF THE MESSAGE TYPE IS "IRet"; RE-ENABLE INTERRUPTS
CPU_IRET: ie = 1;
// IF THE MESSAGE TYPE IS "In"
CPU_IN:
begin
// READ AND SET THE ADDRESS BUS VALUE
$smi_data(id, addr);
addr <= addr;
// ASSERT THE READ SIGNAL
rd <= 1;
// CLOCK UNTIL THE OPERATION IS COMPLETE
@(posedge clock) while (!ready) @(posedge clock);
// RETURN THE DATA BUS VALUE BY SENDING A "Data" MESSAGE
$smi_write(id, CPU_DATA, data);
// DE-ASSERT THE READ SIGNAL
rd <= 0;
end
// IF THE MESSAGE TYPE IS "In"
CPU_OUT:
begin
// READ AND SET THE ADDRESS AND DATA BUS VALUES
$smi_data(id, addr, dout);
addr <= addr;
dout <= dout;
// ASSERT THE WRITE SIGNAL
wr <= 1;
// CLOCK UNTIL THE OPERATION IS COMPLETE
@(posedge clock) while (!ready) @(posedge clock);
// DE-ASSERT THE READ SIGNAL
wr <= 0;
end
endcase
end
// SET OUTPUT SIGNALS AND BUSSES
assign read = rd;
assign write = wr;
assign address = addr;
// ONLY DRIVE THE DATA BUS DURING BUS WRITE OPERATIONS
assign data = wr ? dout : 16'bz;
endmodule
© Copyright 2000-2001 Adrian Lewis