CPE 626, Spring 2002: Modeling a Processor using Verilog
SISC – Small Instruction Set Computer
SISC Instruction Set
The SISC instruction set consists of 10 defined instructions:
NOP
/ No OperationBRA / Branch Absolute (conditional/unconditional)
LOAD / Load Register
(from indirect register or immediate to direct register)
STORE / Store Register
(to indirect register from direct register or immediate)
ADD / Addition (Rdst = Rdst + Rsrc)
MUL / Multiplication (Rdst = Rdst * Rsrc)
NOT / Bitwise Invert (Rdst = ~ Rsrc)
SHF / Logical Shift (Rdst = Rdst > Rn)
ROT / Logical Rotate (Rdst = Rdst > Rn)
HLT / Halt Processor
Block Diagram of Internal Structure
Machine Characteristics
Word length / 32 bitGeneral purpose registers / 16 * 32 bit
Address space / 2^12 = 4096 words = 16 KB
Addressing resolution / word
Instruction set / LOAD/STORE-architecture
Immediate operand lengths / 12 bit
Addressing modes / immediate
register-direct
register-indirect
SISC Encoding
31:28 / 27:24 / 23:12 / 11:0NOP / 0 / x / xxx / xxx
BRA / 1 / cc* / xxx / #addr
LOAD ind / 2 / 0 / (Rsrc) / Rdst
LOAD imm / 2 / 8 / #val / Rdst
STORE reg / 3 / 0 / Rsrc / (Rdst)
STORE imm / 3 / 8 / #val / (Rdst)
ADD / 4 / 0 / Rsrc / Rdst
4 / 8 / #val / Rdst
MUL / 5 / 0 / Rsrc / Rdst
5 / 8 / #val / Rdst
NOT / 6 / 0 / Rsrc / Rdst
6 / 8 / #val / Rdst
SHF / 7 / 0 / Rn / Rdst
7 / 8 / #n / Rdst
ROT / 8 / 0 / Rn / Rdst
8 / 8 / #n / Rdst
HLT / E / x / xxx / xxx
*cc can be one of the following values:
CC0 / unconditional branch
1 / branch on carry bit set
2 / branch on even value
3 / branch on odd parity
4 / branch on zero bit set
5 / branch on negative bit set
Status Register:
4 / 3 / 2 / 1 / 0Neg / Zero / Par / Even / Carry
SISC Structural Model
// The system module contains all the parts of the structural model.
// It initializes the processor and controls the length of the simulation.
module system ;
wire [11:0] pc_dataout, pc_datain;
wire [1:0] pc_cmd, ir_cmd, psr_cmd;
wire [31:0] ir_datain, ir_dataout;
wire rf_write, m_rw_;
wire [31:0] rf_dataw, rf_data1, rf_data2;
wire [3:0] rf_addrw, rf_addr1, rf_addr2;
wire [3:0] alu_function;
wire [31:0] alu_src1, alu_src2;
wire [32:0] alu_result;
wire [4:0] psr_datain, psr_dataout;
wire [31:0] m_data;
wire [11:0] m_addr;
wire [1:0] state;
wire ph1, ph2;
wire masterclk;
reg enable;
pla CNTRLR(pc_dataout, pc_datain, pc_cmd, ir_datain, ir_cmd,
ir_dataout, rf_write, rf_dataw, rf_addrw, rf_data1,
rf_addr1, rf_data2, rf_addr2, alu_function,
alu_src1, alu_src2, alu_result, psr_datain, psr_cmd,
psr_dataout, m_data, m_addr, m_rw_ , state);
alu ALU(alu_src1, alu_src2, alu_function, alu_result);
ram RAM(ph2, m_addr, m_rw_, m_data);
regfile REGS(ph2, rf_addr1, rf_addr2, rf_addrw, rf_write,
rf_dataw,rf_data1, rf_data2);
reg12 PC(ph2, pc_cmd, pc_datain, pc_dataout);
reg5 PSR(ph2, psr_cmd, psr_datain, psr_dataout);
reg32 IR(ph2, ir_cmd, ir_datain, ir_dataout);
clkgen CGEN(masterclk);
phasegen PGEN(masterclk, enable, ph1, ph2, state);
initial
begin
// $display("\t\tTIME\tPC RFILE[0] RFILE[1] RFILE[2]") ;
// $monitor("%d %d %h %h %h",$time,pc,RFILE[0],RFILE[1],RFILE[2]) ;
#5 enable = 1'b0;
#45 enable = 1'b1;
#500 enable = 1'b0;
#1 $stop;
#50 $finish;
end
endmodule
Clock Generator
// clkgen produces a single-phase clock with a 20-nanosecond
// cycle time.
module clkgen (masterclk);
`define masterclk_period 10
output masterclk;
reg masterclk;
initial
masterclk = 0;
always // oscillation at a
// given period
begin
# `masterclk_period
masterclk = ~masterclk;
end
endmodule
// phasegen produces a two-phase clock from the single-phase masterclk
// and controls the state of the processor.
module phasegen(masterclk, enable, ph1, ph2, state);
`define non_overlap 1
`define RESET 2'h0
`define FETCH 2'h1
`define EXECUTE 2'h2
`define WRITE 2'h3
input masterclk, enable;
output ph1, ph2;
output [1:0] state;
reg ph1, ph2;
reg [1:0] state;
initial
begin // reset all signals
ph1 = 0;
ph2 = 0;
state = `RESET;
end
always @(posedge masterclk)
begin
if(enable == 1)
state = next_state(state);
else
state = `RESET;
ph2 = 0;
# `non_overlap
ph1 = 1;
@(posedge masterclk)
begin
ph1 = 0;
# `non_overlap;
ph2 = 1;
end
end
function [1:0] next_state;
input [1:0] state;
case (state)
`RESET: next_state = `FETCH;
`FETCH: next_state = `EXECUTE;
`EXECUTE: next_state = `WRITE;
`WRITE: next_state = `FETCH;
endcase
endfunction
endmodule
ALU
// The alu module contains two sub-modules that perform different
// types of operations. The result_select function chooses the output
// of one of the sub-modules (or a zero value) to be the output of the ALU.
module alu (alu_src1, alu_src2, alu_function, alu_result);
`define ADD 4'h4
`define MUL 4'h5
`define CMP 4'h6
`define SHF 4'h7
`define ROT 4'h8
input [31:0] alu_src1, alu_src2; // operands
input [3:0] alu_function; // ALU operation on operands
output [32:0] alu_result;
wire bshf_type; // type of shift for barrel_shifter to perform
wire [32:0] amc_out; // output of add_mult_compl module
wire [32:0] bshf_out; // output of barrel_shifter module
assign alu_result = result_select(alu_function, amc_out, bshf_out);
assign bshf_type = (alu_function == `ROT) ? 1'b1 : 1'b0;
function [32:0] result_select;
input [3:0] func;
input [32:0] amc, bshf;
case (func)
`ADD, `MUL, `CMP:
result_select = amc;
`SHF, `ROT:
result_select = bshf;
default:
result_select = 33'h0;
endcase
endfunction
barrel_shifter BSHF(alu_src2, bshf_type, alu_src1[4:0], bshf_out);
add_mult_compl AMC(alu_src1, alu_src2, alu_function, amc_out);
endmodule
// barrel_shifter is a sub-module of alu. It does left and right
// shift and rotate operations.
module barrel_shifter(in, type, count, result);
`define LEFT 0
`define RIGHT 1
`define SHIFT 0
`define ROTATE 1
input [31:0] in;
input type;
input [4:0] count;
output [32:0] result;
wire [32:0] result = (type === `ROTATE) ?
(rotate(in , count)) :
(shift (in , count)) ;
function [32:0] shift;
input [31:0] in;
input [4:0] count;
shift = (count > 0) ? (in > count) : (in < (-count));
endfunction
function [32:0] rotate;
input [31:0] in;
input [4:0] count;
reg [31:0] reg_rotate;
begin: rotation
integer i;
reg t;
reg_rotate = in;
if (count > 0)
begin
for (i = 0; i < count; i = i + 1)
begin
t = reg_rotate[0];
reg_rotate[30:0] = reg_rotate[31:1];
reg_rotate[31] = t;
end
end
else if (count < 0)
begin
for (i = 0; i < (-count); i = i + 1)
begin
t = reg_rotate[31];
reg_rotate[31:1] = reg_rotate[30:0];
reg_rotate[0] = t;
end
end
rotate = {1'b0,reg_rotate};
end
endfunction
endmodule
// add_mult_compl does addition, multiplication and complement operations.
module add_mult_compl (alu_src1, alu_src2, alu_function, amc_out);
`define ADD 4'h4
`define MUL 4'h5
`define CMP 4'h6
input [31:0] alu_src1;
input [31:0] alu_src2;
input [3:0] alu_function;
input [32:0] amc_out;
assign amc_out = amc_func(alu_src1, alu_src2, alu_function);
function [32:0] amc_func;
input [31:0] src1, src2;
input [3:0] func;
case (func)
`ADD: amc_func = src1 + src2;
`MUL: amc_func = src1 * src2;
`CMP: amc_func = ~src1;
default: amc_func = 33'h0;
endcase
endfunction
endmodule
Registers
// reg5 is a 5-bit register representing the PSR (condition code register).
module reg5 (ph2, cmd, datain, dataout);
`define CLEAR_REG 2'h0
`define HOLD_VAL 2'h1
`define LOAD_REG 2'h2
`define COUNTUP 2'h3
input ph2;
input [1:0] cmd;
input [4:0] datain;
output [4:0] dataout;
reg [4:0] register;
assign dataout = register;
always @ (posedge ph2)
case (cmd)
`CLEAR_REG: register = 5'b00000;
`LOAD_REG: register = datain;
`COUNTUP: register = register + 1;
endcase
endmodule
// reg12 is a 12-bit register used as the Program Counter.
module reg12 (ph2, cmd, datain, dataout);
`define CLEAR_REG 2'h0
`define HOLD_VAL 2'h1
`define LOAD_REG 2'h2
`define COUNTUP 2'h3
input ph2;
input [1:0] cmd;
input [11:0] datain;
output [11:0] dataout;
reg [11:0] register;
assign dataout = register;
always @ (posedge ph2)
case (cmd)
`CLEAR_REG: register = 12'h000;
`LOAD_REG: register = datain;
`COUNTUP: register = register + 1;
endcase
endmodule
// reg32 is a 32-bit register used as the Instruction Register (IR).
module reg32 (ph2, cmd, datain, dataout);
`define CLEAR_REG 2'h0
`define HOLD_VAL 2'h1
`define LOAD_REG 2'h2
`define COUNTUP 2'h3
input ph2;
input [1:0] cmd;
input [31:0] datain;
output [31:0] dataout;
reg [31:0] register;
assign dataout = register;
always @ (posedge ph2)
case (cmd)
`CLEAR_REG: register = 32'h00000000;
`LOAD_REG: register = datain;
`COUNTUP: register = register + 1;
endcase
endmodule
// regfile contains the 16 data registers. The contents of any two
// registers can be read at any time, and any one register can be
// written on the rising edge of ph2, if writing is enabled.
module regfile(ph2, Aaddr, Baddr, Waddr, wrenable, datain, Adataout,
Bdataout);
input ph2, wrenable;
input [3:0] Aaddr, Baddr, Waddr; // address
input [31:0] datain; // input data
output [31:0] Adataout, Bdataout; // output data
reg [31:0] ram_data[15:0]; // ram as a register array
assign Adataout = ram_data[Aaddr];
assign Bdataout = ram_data[Baddr];
always @ (posedge ph2)
begin
if(wrenable == 1'b1)
ram_data[Waddr] = datain;
end
endmodule
/*****************************************************************/
// The ram module contains an array of 4096 32-bit registers.
// The data bus is bidirectional and controlled by m_rw_.
// Only one address can be read or written at a time.
/*****************************************************************/
module ram(ph2, addr, m_rw_, data);
input ph2;
input [11:0] addr; // address
input m_rw_; // 1 => read from ram, 0 => write to ram
inout [31:0] data; // data bus
reg [31:0] ram_data[4095:0]; // ram as a register array
assign data = (m_rw_ == 1'b1) ? ram_data[addr] : 32'hzzzzzzzz;
initial
$readmemb("sisc_prog.add",ram_data);
always @ (posedge ph2)
if (m_rw_ == 1'b0)
ram_data[addr] = data;
endmodule
PLA
// The pla module controls all major parts of the SISC system and
// coordinates operations between the parts.
// NOTE: The names pc_dataout, ir_dataout and psr_dataout
// have been changed to pc_out, ir_out and psr_out respectively
// for easier reading in the Cadence cWaves waveform display.
module pla (pc_out, pc_datain, pc_cmd, ir_datain, ir_cmd,
ir_out, rf_write, rf_dataw, rf_addrw, rf_data1,
rf_addr1, rf_data2, rf_addr2, alu_function,
alu_src1, alu_src2, alu_result, psr_datain, psr_cmd,
psr_out, m_data, m_addr, m_rw_ , state);
`define NOP 4'h0
`define BRA 4'h1
`define LOAD 4'h2
`define STORE 4'h3
`define ADD 4'h4
`define MUL 4'h5
`define CMP 4'h6
`define SHF 4'h7
`define ROT 4'h8
`define HALT 4'h9
`define RESET 2'h0
`define FETCH 2'h1
`define EXECUTE 2'h2
`define WRITE 2'h3
input [11:0] pc_out;
input [1:0] state;
input [4:0] psr_out;
input [31:0] ir_out, rf_data1, rf_data2;
input [32:0] alu_result;
inout [31:0] m_data;
reg [31:0] m_data_reg;
output rf_write, m_rw_;
output [1:0] pc_cmd, ir_cmd, psr_cmd;
output [3:0] rf_addrw, rf_addr1, rf_addr2, alu_function;
output [4:0] psr_datain;
output [11:0] pc_datain, m_addr;
output [31:0] ir_datain, rf_dataw, alu_src1, alu_src2;
`define CLEAR_REG 2'h0
`define HOLD_VAL 2'h1
`define LOAD_REG 2'h2
`define COUNTUP 2'h3
`define IR_OPCODE ir_out[31:28]
`define IR_SRC_TYP ir_out[27]
`define IR_DST_TYP ir_out[26]
`define IR_SRC ir_out[23:12]
`define IR_SRC32 {20'h00000,ir_out[23:12]}
`define IR_SRC_REG ir_out[15:12]
`define IR_DST ir_out[11:0]
`define IR_DST32 {20'h00000,ir_out[11:0]}
`define IR_DST_REG ir_out[3:0]
`define IMMEDIATE 1
`define MEM_READ 1
`define MEM_WRITE 0
`define REG_READ 0
`define REG_WRITE 1
`define IR_CCODES ir_out[27:23]
wire [31:0] m_data = (m_rw_ == 1'b0) ? m_data_reg : 32'hzzzzzzzz;
wire m_rw_ = (`IR_OPCODE === `STORE & state === `WRITE) ?
`MEM_WRITE : `MEM_READ;
wire [11:0] m_addr = (state === `FETCH) ? pc_out :
((`IR_OPCODE === `STORE) ? `IR_DST : `IR_SRC);
always @ (state)
begin
if(state === `EXECUTE || state === `WRITE)
begin
if(`IR_OPCODE === `STORE & `IR_SRC_TYP != `IMMEDIATE)
m_data_reg = rf_data1;
else if(`IR_OPCODE === `STORE & `IR_SRC_TYP === `IMMEDIATE)
m_data_reg = `IR_SRC32 ;
else m_data_reg = 32'hz;
end
else
m_data_reg = 32'hz;
end
wire [3:0] alu_function = (`IR_OPCODE >= `ADD & `IR_OPCODE <= `ROT) ?
`IR_OPCODE : `NOP;
wire [31:0] alu_src1 = (`IR_SRC_TYP != `IMMEDIATE) ? ((`IR_OPCODE !=
`ROT & `IR_OPCODE != `SHF) ? rf_data1 : `IR_SRC32) : `IR_SRC32 ;
wire [31:0] alu_src2 = rf_data2;
wire [3:0] rf_addr1 = `IR_SRC_REG ;
wire [3:0] rf_addr2 = `IR_DST_REG ;
wire [3:0] rf_addrw = `IR_DST_REG ;
wire rf_write = (`IR_OPCODE != `BRA & `IR_OPCODE != `STORE &
`IR_OPCODE != `NOP & `IR_OPCODE != `HALT & state === `WRITE)
? `REG_WRITE : `REG_READ;
wire [31:0] rf_dataw = (rf_write & `IR_OPCODE === `LOAD &
`IR_SRC_TYP != `IMMEDIATE) ? m_data :
((rf_write & `IR_OPCODE === `LOAD &
`IR_SRC_TYP === `IMMEDIATE) ? `IR_SRC32
: alu_result[31:0]);
wire [1:0] ir_cmd = (state === `FETCH) ? `LOAD_REG : ((state ===
`EXECUTE)
? `HOLD_VAL : ((`IR_OPCODE === `HALT) ? `CLEAR_REG :
`HOLD_VAL));
wire [31:0] ir_datain = (ir_cmd === `LOAD_REG) ? m_data :
((ir_cmd === `CLEAR_REG) ? 32'h0 : ir_out);
wire branch_taken = | ( `IR_CCODES & psr_out);
wire [1:0] pc_cmd = (state === `RESET) ? `CLEAR_REG :
((state === `WRITE) ? ((`IR_OPCODE === `HALT) ?
`CLEAR_REG : (branch_taken ? `LOAD_REG : `COUNTUP)) :
`HOLD_VAL);
wire [11:0] pc_datain = (state == `RESET) ? 12'h0 :
((state == `WRITE) ? ((`IR_OPCODE == `HALT) ?
12'h0 :
(branch_taken ? `IR_DST : (pc_out + 1))) : pc_out);
wire [1:0] psr_cmd = (state == `RESET) ? `CLEAR_REG :
((`IR_OPCODE >= `ADD & `IR_OPCODE <= `ROT &
state === `WRITE) ? `LOAD_REG :
((`IR_OPCODE === `HALT) ? `CLEAR_REG :
`HOLD_VAL));
wire zflag = ~(|alu_result[31:0]);
wire eflag = ~(alu_result[0]);
wire pflag = ^(alu_result[31:0]);
wire [4:0] psr_datain = (psr_cmd === `CLEAR_REG) ? 5'h0 :
((psr_cmd === `LOAD_REG) ? {alu_result[31], zflag,
pflag, eflag, alu_result[32]} : psr_out);
endmodule