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 Operation
BRA / 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 bit
General 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:0
NOP / 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:

CC
0 / 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 / 0
Neg / 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