URL
https://opencores.org/ocsvn/cpu16/cpu16/trunk
Subversion Repositories cpu16
Compare Revisions
- This comparison shows the changes necessary to convert path
/cpu16/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/alu.v
0,0 → 1,68
module alu ( |
a, |
b, |
c_in, |
func, |
result, |
n, |
v, |
z, |
c |
); |
|
input [15:0] a,b; |
input c_in; |
input [2:0] func; |
output [15:0] result; |
output n,v,z,c; |
|
reg [15:0] addsub_result; |
reg addsub_c; |
reg addsub_v; |
always @(*) |
if ( func[1]) |
{ addsub_c, addsub_result } = a + b + (c_in&func[0]); |
else |
{ addsub_c, addsub_result } = a - b - (c_in&func[0]); |
|
// overflow calculation |
always @(*) |
addsub_v = a[15] ^ b[15] ^ addsub_c ^ addsub_result[15]; |
|
reg [15:0] logic_result; |
always @(*) |
case (func[1:0]) |
2'd0 : logic_result = a; // maps to subtract |
2'd1 : logic_result = a&b; |
2'd2 : logic_result = a|b; |
2'd3 : logic_result = a^b; |
endcase |
|
reg [15:0] result; |
always @(*) |
if ( func[2]) |
result = logic_result; |
else |
result = addsub_result; |
|
reg n,v,z,c; |
always @(*) |
casex (func) |
3'b0xx, // sub/sbc/add/adc |
3'b100 : begin // cmp |
n = addsub_result[15]; |
v = addsub_v; |
z = ~|addsub_result; |
c = addsub_c; |
end |
default : begin |
n = logic_result[15]; |
v = 1'b0; |
z = ~|logic_result; |
c = 1'b0; |
end |
endcase |
|
endmodule |
|
|
alu.v
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: cpu.v
===================================================================
--- cpu.v (nonexistent)
+++ cpu.v (revision 2)
@@ -0,0 +1,512 @@
+/*
+ * None pipelined, 3-state, 16-bit CPU
+ *
+ * Copyright (C) 2019, Yvo Zoer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+module cpu16 (
+ clk,
+ reset_n,
+ clk_en,
+ address,
+ din,
+ dout,
+ cs_n,
+ oe_n,
+ we_n,
+ ub_n,
+ lb_n,
+ irq, // combined interrupt request from intc
+ busreq,
+ busack
+ );
+
+ input clk;
+ input reset_n;
+ output [15:0] address;
+ input clk_en;
+ input [15:0] din;
+ output [15:0] dout;
+ output cs_n;
+ output oe_n;
+ output we_n;
+ output ub_n;
+ output lb_n;
+ input irq;
+ input busreq;
+ output busack;
+
+ // alu
+ parameter OP_SUB = 5'd0; // ok
+ parameter OP_SBC = 5'd1; // ok
+ parameter OP_ADD = 5'd2;
+ parameter OP_ADC = 5'd3;
+ parameter OP_CMP = 5'd4;
+ parameter OP_AND = 5'd5; // ok
+ parameter OP_OR = 5'd6; // ok
+ parameter OP_XOR = 5'd7; // ok
+
+ // alu immediate
+ parameter OP_SUBI = 5'd8; // ok
+ parameter OP_SBCI = 5'd9; // ok
+ parameter OP_ADDI = 5'd10; // ok
+ parameter OP_ADCI = 5'd11; // ok
+ parameter OP_CMPI = 5'd12;
+ parameter OP_ANDI = 5'd13; // ok
+ parameter OP_ORI = 5'd14; // ok
+ parameter OP_XORI = 5'd15; // ok
+
+ // shifter + load
+ parameter OP_MOV = 5'd16;
+ parameter OP_SRAV = 5'd17;
+ parameter OP_SLLV = 5'd18;
+ parameter OP_LD = 5'd19;
+
+ // shifter immediate + store
+ parameter OP_LUI = 5'd20;
+ parameter OP_SRA = 5'd21;
+ parameter OP_SLL = 5'd22;
+ parameter OP_ST = 5'd23;
+
+ // jump
+ parameter OP_J = 5'd24;
+ parameter OP_JAL = 5'd25;
+ parameter OP_JR = 5'd26;
+ parameter OP_JALR = 5'd27;
+
+ // conditional branch
+ parameter OP_BXX = 5'd28;
+ parameter OP_MSR = 5'd29;
+ parameter OP_RFE = 5'd30;
+ parameter OP_SWI = 5'd31;
+
+ // states
+ parameter STATE_FETCH = 4'h0;
+ parameter STATE_DECODE = 4'h1;
+ parameter STATE_ALU = 4'h2;
+ parameter STATE_SHIFT = 4'h3;
+ parameter STATE_LOAD = 4'h4;
+ parameter STATE_STORE = 4'h5;
+ parameter STATE_J = 4'h6;
+ parameter STATE_JAL = 4'h7;
+ parameter STATE_BRANCH = 4'h8;
+ parameter STATE_MOVSR = 4'h9;
+ parameter STATE_RFE = 4'ha;
+ parameter STATE_SWI = 4'hb;
+ parameter STATE_INTREQ = 4'hc;
+ parameter STATE_BUSREQ = 4'hd;
+
+ // instruction register wires
+ wire [4:0] ir_opcode = ir[15:11];
+ wire [2:0] ir_dst = ir[10:8];
+ wire [2:0] ir_src = ir[7:5];
+ wire ir_size = ir[4]; // byte/word flag
+ wire [3:0] ir_imm4 = ir[3:0]; // load/store offset
+ wire [7:0] ir_imm8 = ir[7:0]; // immediate value / relative conditional branch
+ wire [10:0] ir_imm11 = ir[10:0]; // unconditional branch
+
+ // busack valid once we're in the busreq state
+ reg busack;
+ always @(*)
+ if ( state == STATE_BUSREQ )
+ busack = 1'b1;
+ else
+ busack = 1'b0;
+
+// chip-select
+ reg cs_n;
+ always @(*)
+ case (state)
+ STATE_FETCH,
+ STATE_LOAD,
+ STATE_STORE : cs_n = 1'b0;
+ default : cs_n = 1'b1;
+ endcase
+
+ // output enable
+ reg oe_n;
+ always @(*)
+ case (state)
+ STATE_FETCH,
+ STATE_LOAD : oe_n = 1'b0;
+ default : oe_n = 1'b1;
+ endcase
+ // memory write signal
+ reg we_n;
+ always @(posedge clk)
+ if ( state == STATE_STORE )
+ we_n <= clk_en;
+ else
+ we_n <= 1'b1;
+
+ // upper / lower byte write/read enable
+ // NOTE: could integrate dout here as well..
+ reg ub_n;
+ reg lb_n;
+ always @(*)
+ if ( state == STATE_STORE )
+ begin
+ if ( ir_size )
+ begin // word
+ ub_n = 1'b0;
+ lb_n = 1'b0;
+ end
+ else
+ begin // byte
+ if ( address[0] )
+ begin
+ ub_n = 1'b1;
+ lb_n = 1'b0;
+ end
+ else
+ begin
+ ub_n = 1'b0;
+ lb_n = 1'b1;
+ end
+ end
+ end
+ else
+ begin // word access for everything else
+ ub_n = 1'b0;
+ lb_n = 1'b0;
+ end
+
+ // data output logic
+ reg [15:0] dout;
+ always @(*)
+ if ( ir_size )
+ dout = qa; // word
+ else
+ begin
+ if ( address[0] )
+ dout = { 8'h00, qa[7:0] };
+ else
+ dout = { qa[7:0], 8'h00 };
+ end
+
+ // address mux
+ reg [15:0] address;
+ always @(*)
+ case (state)
+ STATE_LOAD,
+ STATE_STORE : address = qb + ir_imm4;
+ default : address = pc; // { pc[15:1], 1'b0 };
+ endcase
+
+ // main state machine
+ reg [3:0] state, next_state;
+ always @(*)
+ case (state)
+ STATE_FETCH : next_state = STATE_DECODE;
+ STATE_DECODE : begin
+ casex (ir_opcode)
+ 5'b0xxxx : next_state = STATE_ALU; // sub/sbc/add/adc/and/or/xor/cmp
+ 5'b10x0x,
+ 5'b10x10 : next_state = STATE_SHIFT;
+ 5'b10011 : next_state = STATE_LOAD;
+ 5'b10111 : next_state = STATE_STORE;
+ 5'b110x0 : next_state = STATE_J; // 24/26
+ 5'b110x1 : next_state = STATE_JAL; // 25/27
+ 5'b11100 : next_state = STATE_BRANCH;
+ 5'b11101 : next_state = STATE_MOVSR;
+ 5'b11110 : next_state = STATE_RFE;
+ 5'b11111 : next_state = STATE_SWI;
+ default : next_state = STATE_FETCH;
+ endcase
+ end
+ STATE_INTREQ : next_state = STATE_FETCH;
+ STATE_BUSREQ : begin
+ if ( busreq )
+ next_state = STATE_BUSREQ;
+ else
+ next_state = STATE_FETCH; // will miss interrupt when coming out of busreq (STATE_NOP?)
+ end
+ default : begin
+ if ( busreq )
+ next_state = STATE_BUSREQ;
+ else if ( irq & i ) // only fires when interrupt enable is set (i = 1)
+ next_state = STATE_INTREQ;
+ else
+ next_state = STATE_FETCH;
+ end
+ endcase
+
+ // instruction register
+ reg [15:0] ir, next_ir;
+ always @(*)
+ if ( state == STATE_FETCH )
+ next_ir = din;
+ else
+ next_ir = ir;
+
+ // exception pc- and status register
+ reg [15:0] epc, next_epc;
+ reg [4:0] esr, next_esr;
+ always @(*)
+ case (state)
+ STATE_INTREQ : begin
+ next_epc = pc;
+ next_esr = { i,n,v,z,c };
+ end
+ default : begin
+ next_epc = epc;
+ next_esr = esr;
+ end
+ endcase
+
+ // source data for program counter ( register / immediate )
+ reg [15:0] pc_data;
+ always @(*)
+ if ( ir_opcode[1] ) // immediate for PC
+ pc_data = qb; //{ qb[15:1], 1'b0 }; // TEST: jr/jalr
+ else
+ pc_data = pc + { { 4 { ir_imm11[10] } }, ir_imm11[10:0], 1'b0 }; // TEST: j/jal doubled for jumps
+
+ // condition check
+ reg condition_true;
+ always @(*)
+ case (ir_dst)
+ 3'd0 : condition_true = z;
+ 3'd1 : condition_true = ~z;
+ 3'd2 : condition_true = ~n;
+ 3'd3 : condition_true = n;
+ 3'd4 : condition_true = ~c;
+ 3'd5 : condition_true = c;
+ 3'd6 : condition_true = ~v;
+ 3'd7 : condition_true = v;
+ endcase
+
+ // program counter
+ reg [15:0] pc, next_pc;
+ always @(*)
+ case (state)
+ STATE_FETCH : next_pc = pc + 16'd2;
+ STATE_SWI : next_pc = { ir_imm8, 1'b0 };
+ STATE_J,
+ STATE_JAL : next_pc = pc_data;
+ STATE_BRANCH : begin
+ if ( condition_true )
+ next_pc = pc + { { 7 { ir_imm8[7] } }, ir_imm8[7:0], 1'b0 };
+ else
+ next_pc = pc;
+ end
+ STATE_INTREQ : next_pc = 16'h0002; // interrupt vector appears at 0x0002
+ STATE_RFE : next_pc = epc;
+ default : next_pc = pc;
+ endcase
+
+ // alu data mux
+ reg [15:0] alu_data;
+ always @(*)
+ if (ir_opcode[3]) // immediate
+ alu_data = { 8'h00, ir_imm8 };
+ else
+ alu_data = qb; // register
+
+ // alu
+ wire [15:0] alu_result;
+ wire alu_n;
+ wire alu_v;
+ wire alu_z;
+ wire alu_c;
+ alu i_alu (
+ .a(qa),
+ .b(alu_data),
+ .c_in(c),
+ .func(ir_opcode[2:0]),
+ .result(alu_result),
+ .n(alu_n),
+ .v(alu_v),
+ .z(alu_z),
+ .c(alu_c)
+ );
+
+ // shifter data mux
+ reg [15:0] shifter_data;
+ always @(*)
+ if ( ir_opcode[2] ) // immediate
+ shifter_data = { ir_imm8, 8'h00 }; // lui from instruction word
+ else
+ shifter_data = qb; // mov
+
+ // shifter distance -- roll into b argument inside shifter?
+ reg [3:0] shift_distance;
+ always @(*)
+ if ( ir_opcode[2] )
+ shift_distance = ir_imm4;
+ else
+ shift_distance = qb[3:0];
+
+ // shifter
+ wire [15:0] shifter_result;
+ wire shift_n;
+ wire shift_z;
+ wire shift_c;
+ wire shift_v;
+ shifter i_shifter (
+ .a(qa),
+ .b(shifter_data),
+ .n_in(n),
+ .v_in(v),
+ .z_in(z),
+ .c_in(c),
+ .distance(shift_distance),
+ .func(ir_opcode[1:0]),
+ .result(shifter_result),
+ .n(shift_n),
+ .v(shift_v),
+ .z(shift_z),
+ .c(shift_c)
+ );
+
+ // memory data mux for lw/lb
+ reg [15:0] mem_data;
+ always @(*)
+ if ( ir_size )
+ mem_data = din;
+ else
+ begin
+ if ( address[0] )
+ mem_data = { 8'h00, din[7:0] };
+ else
+ mem_data = { 8'h00, din[15:8] };
+ end
+
+ // register data
+ reg [15:0] reg_data;
+ always @(*)
+ case (state)
+ STATE_ALU : reg_data = alu_result;
+ STATE_SHIFT : reg_data = shifter_result;
+ STATE_JAL,
+ STATE_SWI : reg_data = pc;
+ default : reg_data = mem_data;
+ endcase
+
+ // register writeback
+ reg reg_write;
+ always @(*)
+ case (state)
+ STATE_ALU,
+ STATE_SHIFT,
+ STATE_LOAD,
+ STATE_JAL,
+ STATE_SWI : reg_write = 1'b1;
+ default : reg_write = 1'b0;
+ endcase
+
+ // override dst address for JAL to save 3 bits
+ reg [2:0] ra_dst;
+ always @(*)
+ if ( state == STATE_JAL )
+ ra_dst = 3'd6; // hard linked register
+ else
+ ra_dst = ir_dst;
+
+ // register file
+ wire [15:0] qa, qb;
+ regfile8x16 i_regfile (
+ .clock(clk),
+ .data(reg_data),
+ .rdaddress_a(ir_dst),
+ .rdaddress_b(ir_src),
+ .wraddress(ra_dst),
+ .wren(reg_write&clk_en),
+ .qa(qa),
+ .qb(qb)
+ );
+
+ // flags
+ reg i, next_i;
+ reg n, next_n;
+ reg v, next_v;
+ reg z, next_z;
+ reg c, next_c;
+ always @(*)
+ case (state)
+ STATE_ALU : begin
+ next_i = i;
+ next_n = alu_n;
+ next_v = alu_v;
+ next_z = alu_z;
+ next_c = alu_c;
+ end
+ STATE_SHIFT : begin
+ next_i = i;
+ next_n = shift_n;
+ next_v = shift_v;
+ next_z = shift_z;
+ next_c = shift_c;
+ end
+ STATE_MOVSR : begin
+ next_i = (i & ~ir_imm8[4]) | ( ir_imm8[7] & ir_imm8[4]);
+ next_n = (n & ~ir_imm8[3]) | ( ir_imm8[7] & ir_imm8[3]);
+ next_v = (v & ~ir_imm8[2]) | ( ir_imm8[7] & ir_imm8[2]);
+ next_z = (z & ~ir_imm8[1]) | ( ir_imm8[7] & ir_imm8[1]);
+ next_c = (c & ~ir_imm8[0]) | ( ir_imm8[7] & ir_imm8[0]);
+ end
+ STATE_INTREQ : begin
+ next_i = 1'b0; // disable interrupts
+ next_n = n;
+ next_v = v;
+ next_z = z;
+ next_c = c;
+ end
+ STATE_RFE : begin
+ next_i = esr[4];
+ next_n = esr[3];
+ next_v = esr[2];
+ next_z = esr[1];
+ next_c = esr[0];
+ end
+ default : begin
+ next_i = i;
+ next_n = n;
+ next_v = v;
+ next_z = z;
+ next_c = c;
+ end
+ endcase
+
+ // synchronous writeback
+ always @(posedge clk or negedge reset_n)
+ if (!reset_n)
+ begin
+ state <= STATE_FETCH;
+ ir <= 16'd0;
+ pc <= 16'd0;
+ i <= 1'b1; // TEST: enable interrupts
+ n <= 1'b0;
+ v <= 1'b0;
+ z <= 1'b0;
+ c <= 1'b0;
+ epc <= 16'd0;
+ esr <= 5'd0;
+ end
+ else if ( clk_en )
+ begin
+ state <= next_state;
+ ir <= next_ir;
+ pc <= next_pc;
+ i <= next_i;
+ n <= next_n;
+ v <= next_v;
+ z <= next_z;
+ c <= next_c;
+ epc <= next_epc;
+ esr <= next_esr;
+ end
+endmodule
cpu.v
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: cpu16.v
===================================================================
--- cpu16.v (nonexistent)
+++ cpu16.v (revision 2)
@@ -0,0 +1,512 @@
+/*
+ * None pipelined, 3-state, 16-bit CPU
+ *
+ * Copyright (C) 2019, Yvo Zoer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+module cpu16 (
+ clk,
+ reset_n,
+ clk_en,
+ address,
+ din,
+ dout,
+ cs_n,
+ oe_n,
+ we_n,
+ ub_n,
+ lb_n,
+ irq, // combined interrupt request from intc
+ busreq,
+ busack
+ );
+
+ input clk;
+ input reset_n;
+ output [15:0] address;
+ input clk_en;
+ input [15:0] din;
+ output [15:0] dout;
+ output cs_n;
+ output oe_n;
+ output we_n;
+ output ub_n;
+ output lb_n;
+ input irq;
+ input busreq;
+ output busack;
+
+ // alu
+ parameter OP_SUB = 5'd0; // ok
+ parameter OP_SBC = 5'd1; // ok
+ parameter OP_ADD = 5'd2;
+ parameter OP_ADC = 5'd3;
+ parameter OP_CMP = 5'd4;
+ parameter OP_AND = 5'd5; // ok
+ parameter OP_OR = 5'd6; // ok
+ parameter OP_XOR = 5'd7; // ok
+
+ // alu immediate
+ parameter OP_SUBI = 5'd8; // ok
+ parameter OP_SBCI = 5'd9; // ok
+ parameter OP_ADDI = 5'd10; // ok
+ parameter OP_ADCI = 5'd11; // ok
+ parameter OP_CMPI = 5'd12;
+ parameter OP_ANDI = 5'd13; // ok
+ parameter OP_ORI = 5'd14; // ok
+ parameter OP_XORI = 5'd15; // ok
+
+ // shifter + load
+ parameter OP_MOV = 5'd16;
+ parameter OP_SRAV = 5'd17;
+ parameter OP_SLLV = 5'd18;
+ parameter OP_LD = 5'd19;
+
+ // shifter immediate + store
+ parameter OP_LUI = 5'd20;
+ parameter OP_SRA = 5'd21;
+ parameter OP_SLL = 5'd22;
+ parameter OP_ST = 5'd23;
+
+ // jump
+ parameter OP_J = 5'd24;
+ parameter OP_JAL = 5'd25;
+ parameter OP_JR = 5'd26;
+ parameter OP_JALR = 5'd27;
+
+ // conditional branch
+ parameter OP_BXX = 5'd28;
+ parameter OP_MSR = 5'd29;
+ parameter OP_RFE = 5'd30;
+ parameter OP_SWI = 5'd31;
+
+ // states
+ parameter STATE_FETCH = 4'h0;
+ parameter STATE_DECODE = 4'h1;
+ parameter STATE_ALU = 4'h2;
+ parameter STATE_SHIFT = 4'h3;
+ parameter STATE_LOAD = 4'h4;
+ parameter STATE_STORE = 4'h5;
+ parameter STATE_J = 4'h6;
+ parameter STATE_JAL = 4'h7;
+ parameter STATE_BRANCH = 4'h8;
+ parameter STATE_MOVSR = 4'h9;
+ parameter STATE_RFE = 4'ha;
+ parameter STATE_SWI = 4'hb;
+ parameter STATE_INTREQ = 4'hc;
+ parameter STATE_BUSREQ = 4'hd;
+
+ // instruction register wires
+ wire [4:0] ir_opcode = ir[15:11];
+ wire [2:0] ir_dst = ir[10:8];
+ wire [2:0] ir_src = ir[7:5];
+ wire ir_size = ir[4]; // byte/word flag
+ wire [3:0] ir_imm4 = ir[3:0]; // load/store offset
+ wire [7:0] ir_imm8 = ir[7:0]; // immediate value / relative conditional branch
+ wire [10:0] ir_imm11 = ir[10:0]; // unconditional branch
+
+ // busack valid once we're in the busreq state
+ reg busack;
+ always @(*)
+ if ( state == STATE_BUSREQ )
+ busack = 1'b1;
+ else
+ busack = 1'b0;
+
+// chip-select
+ reg cs_n;
+ always @(*)
+ case (state)
+ STATE_FETCH,
+ STATE_LOAD,
+ STATE_STORE : cs_n = 1'b0;
+ default : cs_n = 1'b1;
+ endcase
+
+ // output enable
+ reg oe_n;
+ always @(*)
+ case (state)
+ STATE_FETCH,
+ STATE_LOAD : oe_n = 1'b0;
+ default : oe_n = 1'b1;
+ endcase
+ // memory write signal
+ reg we_n;
+ always @(posedge clk)
+ if ( state == STATE_STORE )
+ we_n <= clk_en;
+ else
+ we_n <= 1'b1;
+
+ // upper / lower byte write/read enable
+ // NOTE: could integrate dout here as well..
+ reg ub_n;
+ reg lb_n;
+ always @(*)
+ if ( state == STATE_STORE )
+ begin
+ if ( ir_size )
+ begin // word
+ ub_n = 1'b0;
+ lb_n = 1'b0;
+ end
+ else
+ begin // byte
+ if ( address[0] )
+ begin
+ ub_n = 1'b1;
+ lb_n = 1'b0;
+ end
+ else
+ begin
+ ub_n = 1'b0;
+ lb_n = 1'b1;
+ end
+ end
+ end
+ else
+ begin // word access for everything else
+ ub_n = 1'b0;
+ lb_n = 1'b0;
+ end
+
+ // data output logic
+ reg [15:0] dout;
+ always @(*)
+ if ( ir_size )
+ dout = qa; // word
+ else
+ begin
+ if ( address[0] )
+ dout = { 8'h00, qa[7:0] };
+ else
+ dout = { qa[7:0], 8'h00 };
+ end
+
+ // address mux
+ reg [15:0] address;
+ always @(*)
+ case (state)
+ STATE_LOAD,
+ STATE_STORE : address = qb + ir_imm4;
+ default : address = pc; // { pc[15:1], 1'b0 };
+ endcase
+
+ // main state machine
+ reg [3:0] state, next_state;
+ always @(*)
+ case (state)
+ STATE_FETCH : next_state = STATE_DECODE;
+ STATE_DECODE : begin
+ casex (ir_opcode)
+ 5'b0xxxx : next_state = STATE_ALU; // sub/sbc/add/adc/and/or/xor/cmp
+ 5'b10x0x,
+ 5'b10x10 : next_state = STATE_SHIFT;
+ 5'b10011 : next_state = STATE_LOAD;
+ 5'b10111 : next_state = STATE_STORE;
+ 5'b110x0 : next_state = STATE_J; // 24/26
+ 5'b110x1 : next_state = STATE_JAL; // 25/27
+ 5'b11100 : next_state = STATE_BRANCH;
+ 5'b11101 : next_state = STATE_MOVSR;
+ 5'b11110 : next_state = STATE_RFE;
+ 5'b11111 : next_state = STATE_SWI;
+ default : next_state = STATE_FETCH;
+ endcase
+ end
+ STATE_INTREQ : next_state = STATE_FETCH;
+ STATE_BUSREQ : begin
+ if ( busreq )
+ next_state = STATE_BUSREQ;
+ else
+ next_state = STATE_FETCH; // will miss interrupt when coming out of busreq (STATE_NOP?)
+ end
+ default : begin
+ if ( busreq )
+ next_state = STATE_BUSREQ;
+ else if ( irq & i ) // only fires when interrupt enable is set (i = 1)
+ next_state = STATE_INTREQ;
+ else
+ next_state = STATE_FETCH;
+ end
+ endcase
+
+ // instruction register
+ reg [15:0] ir, next_ir;
+ always @(*)
+ if ( state == STATE_FETCH )
+ next_ir = din;
+ else
+ next_ir = ir;
+
+ // exception pc- and status register
+ reg [15:0] epc, next_epc;
+ reg [4:0] esr, next_esr;
+ always @(*)
+ case (state)
+ STATE_INTREQ : begin
+ next_epc = pc;
+ next_esr = { i,n,v,z,c };
+ end
+ default : begin
+ next_epc = epc;
+ next_esr = esr;
+ end
+ endcase
+
+ // source data for program counter ( register / immediate )
+ reg [15:0] pc_data;
+ always @(*)
+ if ( ir_opcode[1] ) // immediate for PC
+ pc_data = qb; //{ qb[15:1], 1'b0 }; // TEST: jr/jalr
+ else
+ pc_data = pc + { { 4 { ir_imm11[10] } }, ir_imm11[10:0], 1'b0 }; // TEST: j/jal doubled for jumps
+
+ // condition check
+ reg condition_true;
+ always @(*)
+ case (ir_dst)
+ 3'd0 : condition_true = z;
+ 3'd1 : condition_true = ~z;
+ 3'd2 : condition_true = ~n;
+ 3'd3 : condition_true = n;
+ 3'd4 : condition_true = ~c;
+ 3'd5 : condition_true = c;
+ 3'd6 : condition_true = ~v;
+ 3'd7 : condition_true = v;
+ endcase
+
+ // program counter
+ reg [15:0] pc, next_pc;
+ always @(*)
+ case (state)
+ STATE_FETCH : next_pc = pc + 16'd2;
+ STATE_SWI : next_pc = { ir_imm8, 1'b0 };
+ STATE_J,
+ STATE_JAL : next_pc = pc_data;
+ STATE_BRANCH : begin
+ if ( condition_true )
+ next_pc = pc + { { 7 { ir_imm8[7] } }, ir_imm8[7:0], 1'b0 };
+ else
+ next_pc = pc;
+ end
+ STATE_INTREQ : next_pc = 16'h0002; // interrupt vector appears at 0x0002
+ STATE_RFE : next_pc = epc;
+ default : next_pc = pc;
+ endcase
+
+ // alu data mux
+ reg [15:0] alu_data;
+ always @(*)
+ if (ir_opcode[3]) // immediate
+ alu_data = { 8'h00, ir_imm8 };
+ else
+ alu_data = qb; // register
+
+ // alu
+ wire [15:0] alu_result;
+ wire alu_n;
+ wire alu_v;
+ wire alu_z;
+ wire alu_c;
+ alu i_alu (
+ .a(qa),
+ .b(alu_data),
+ .c_in(c),
+ .func(ir_opcode[2:0]),
+ .result(alu_result),
+ .n(alu_n),
+ .v(alu_v),
+ .z(alu_z),
+ .c(alu_c)
+ );
+
+ // shifter data mux
+ reg [15:0] shifter_data;
+ always @(*)
+ if ( ir_opcode[2] ) // immediate
+ shifter_data = { ir_imm8, 8'h00 }; // lui from instruction word
+ else
+ shifter_data = qb; // mov
+
+ // shifter distance -- roll into b argument inside shifter?
+ reg [3:0] shift_distance;
+ always @(*)
+ if ( ir_opcode[2] )
+ shift_distance = ir_imm4;
+ else
+ shift_distance = qb[3:0];
+
+ // shifter
+ wire [15:0] shifter_result;
+ wire shift_n;
+ wire shift_z;
+ wire shift_c;
+ wire shift_v;
+ shifter i_shifter (
+ .a(qa),
+ .b(shifter_data),
+ .n_in(n),
+ .v_in(v),
+ .z_in(z),
+ .c_in(c),
+ .distance(shift_distance),
+ .func(ir_opcode[1:0]),
+ .result(shifter_result),
+ .n(shift_n),
+ .v(shift_v),
+ .z(shift_z),
+ .c(shift_c)
+ );
+
+ // memory data mux for lw/lb
+ reg [15:0] mem_data;
+ always @(*)
+ if ( ir_size )
+ mem_data = din;
+ else
+ begin
+ if ( address[0] )
+ mem_data = { 8'h00, din[7:0] };
+ else
+ mem_data = { 8'h00, din[15:8] };
+ end
+
+ // register data
+ reg [15:0] reg_data;
+ always @(*)
+ case (state)
+ STATE_ALU : reg_data = alu_result;
+ STATE_SHIFT : reg_data = shifter_result;
+ STATE_JAL,
+ STATE_SWI : reg_data = pc;
+ default : reg_data = mem_data;
+ endcase
+
+ // register writeback
+ reg reg_write;
+ always @(*)
+ case (state)
+ STATE_ALU,
+ STATE_SHIFT,
+ STATE_LOAD,
+ STATE_JAL,
+ STATE_SWI : reg_write = 1'b1;
+ default : reg_write = 1'b0;
+ endcase
+
+ // override dst address for JAL to save 3 bits
+ reg [2:0] ra_dst;
+ always @(*)
+ if ( state == STATE_JAL )
+ ra_dst = 3'd6; // hard linked register
+ else
+ ra_dst = ir_dst;
+
+ // register file
+ wire [15:0] qa, qb;
+ regfile8x16 i_regfile (
+ .clock(clk),
+ .data(reg_data),
+ .rdaddress_a(ir_dst),
+ .rdaddress_b(ir_src),
+ .wraddress(ra_dst),
+ .wren(reg_write&clk_en),
+ .qa(qa),
+ .qb(qb)
+ );
+
+ // flags
+ reg i, next_i;
+ reg n, next_n;
+ reg v, next_v;
+ reg z, next_z;
+ reg c, next_c;
+ always @(*)
+ case (state)
+ STATE_ALU : begin
+ next_i = i;
+ next_n = alu_n;
+ next_v = alu_v;
+ next_z = alu_z;
+ next_c = alu_c;
+ end
+ STATE_SHIFT : begin
+ next_i = i;
+ next_n = shift_n;
+ next_v = shift_v;
+ next_z = shift_z;
+ next_c = shift_c;
+ end
+ STATE_MOVSR : begin
+ next_i = (i & ~ir_imm8[4]) | ( ir_imm8[7] & ir_imm8[4]);
+ next_n = (n & ~ir_imm8[3]) | ( ir_imm8[7] & ir_imm8[3]);
+ next_v = (v & ~ir_imm8[2]) | ( ir_imm8[7] & ir_imm8[2]);
+ next_z = (z & ~ir_imm8[1]) | ( ir_imm8[7] & ir_imm8[1]);
+ next_c = (c & ~ir_imm8[0]) | ( ir_imm8[7] & ir_imm8[0]);
+ end
+ STATE_INTREQ : begin
+ next_i = 1'b0; // disable interrupts
+ next_n = n;
+ next_v = v;
+ next_z = z;
+ next_c = c;
+ end
+ STATE_RFE : begin
+ next_i = esr[4];
+ next_n = esr[3];
+ next_v = esr[2];
+ next_z = esr[1];
+ next_c = esr[0];
+ end
+ default : begin
+ next_i = i;
+ next_n = n;
+ next_v = v;
+ next_z = z;
+ next_c = c;
+ end
+ endcase
+
+ // synchronous writeback
+ always @(posedge clk or negedge reset_n)
+ if (!reset_n)
+ begin
+ state <= STATE_FETCH;
+ ir <= 16'd0;
+ pc <= 16'd0;
+ i <= 1'b1; // TEST: enable interrupts
+ n <= 1'b0;
+ v <= 1'b0;
+ z <= 1'b0;
+ c <= 1'b0;
+ epc <= 16'd0;
+ esr <= 5'd0;
+ end
+ else if ( clk_en )
+ begin
+ state <= next_state;
+ ir <= next_ir;
+ pc <= next_pc;
+ i <= next_i;
+ n <= next_n;
+ v <= next_v;
+ z <= next_z;
+ c <= next_c;
+ epc <= next_epc;
+ esr <= next_esr;
+ end
+endmodule
cpu16.v
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: regfile8x16.v
===================================================================
--- regfile8x16.v (nonexistent)
+++ regfile8x16.v (revision 2)
@@ -0,0 +1,192 @@
+// megafunction wizard: %RAM: 3-PORT%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: alt3pram
+
+// ============================================================
+// File Name: regfile8x16.v
+// Megafunction Name(s):
+// alt3pram
+//
+// Simulation Library Files(s):
+// altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 9.0 Build 235 06/17/2009 SP 2 SJ Web Edition
+// ************************************************************
+
+
+//Copyright (C) 1991-2009 Altera Corporation
+//Your use of Altera Corporation's design tools, logic functions
+//and other software and tools, and its AMPP partner logic
+//functions, and any output files from any of the foregoing
+//(including device programming or simulation files), and any
+//associated documentation or information are expressly subject
+//to the terms and conditions of the Altera Program License
+//Subscription Agreement, Altera MegaCore Function License
+//Agreement, or other applicable license agreement, including,
+//without limitation, that your use is for the sole purpose of
+//programming logic devices manufactured by Altera and sold by
+//Altera or its authorized distributors. Please refer to the
+//applicable agreement for further details.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module regfile8x16 (
+ clock,
+ data,
+ rdaddress_a,
+ rdaddress_b,
+ wraddress,
+ wren,
+ qa,
+ qb);
+
+ input clock;
+ input [15:0] data;
+ input [2:0] rdaddress_a;
+ input [2:0] rdaddress_b;
+ input [2:0] wraddress;
+ input wren;
+ output [15:0] qa;
+ output [15:0] qb;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_off
+`endif
+ tri0 wren;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_on
+`endif
+
+ wire [15:0] sub_wire0;
+ wire [15:0] sub_wire1;
+ wire [15:0] qa = sub_wire0[15:0];
+ wire [15:0] qb = sub_wire1[15:0];
+
+ alt3pram alt3pram_component (
+ .wren (wren),
+ .inclock (clock),
+ .data (data),
+ .rdaddress_a (rdaddress_a),
+ .wraddress (wraddress),
+ .rdaddress_b (rdaddress_b),
+ .qa (sub_wire0),
+ .qb (sub_wire1)
+ // synopsys translate_off
+ ,
+ .aclr (),
+ .inclocken (),
+ .outclock (),
+ .outclocken (),
+ .rden_a (),
+ .rden_b ()
+ // synopsys translate_on
+ );
+ defparam
+ alt3pram_component.indata_aclr = "OFF",
+ alt3pram_component.indata_reg = "INCLOCK",
+ alt3pram_component.intended_device_family = "Cyclone II",
+ alt3pram_component.lpm_type = "alt3pram",
+ alt3pram_component.outdata_aclr_a = "OFF",
+ alt3pram_component.outdata_aclr_b = "OFF",
+ alt3pram_component.outdata_reg_a = "UNREGISTERED",
+ alt3pram_component.outdata_reg_b = "UNREGISTERED",
+ alt3pram_component.rdaddress_aclr_a = "OFF",
+ alt3pram_component.rdaddress_aclr_b = "OFF",
+ alt3pram_component.rdaddress_reg_a = "INCLOCK",
+ alt3pram_component.rdaddress_reg_b = "INCLOCK",
+ alt3pram_component.rdcontrol_aclr_a = "OFF",
+ alt3pram_component.rdcontrol_aclr_b = "OFF",
+ alt3pram_component.rdcontrol_reg_a = "UNREGISTERED",
+ alt3pram_component.rdcontrol_reg_b = "UNREGISTERED",
+ alt3pram_component.width = 16,
+ alt3pram_component.widthad = 3,
+ alt3pram_component.write_aclr = "OFF",
+ alt3pram_component.write_reg = "INCLOCK";
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: BlankMemory NUMERIC "1"
+// Retrieval info: PRIVATE: CLRdata NUMERIC "0"
+// Retrieval info: PRIVATE: CLRqa NUMERIC "0"
+// Retrieval info: PRIVATE: CLRqb NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrdaddress_a NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrdaddress_b NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrren_a NUMERIC "0"
+// Retrieval info: PRIVATE: CLRrren_b NUMERIC "0"
+// Retrieval info: PRIVATE: CLRwrite NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "0"
+// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
+// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0"
+// Retrieval info: PRIVATE: JTAG_ID STRING "NONE"
+// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0"
+// Retrieval info: PRIVATE: MIFfilename STRING ""
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+// Retrieval info: PRIVATE: REGdata NUMERIC "1"
+// Retrieval info: PRIVATE: REGqa NUMERIC "0"
+// Retrieval info: PRIVATE: REGqb NUMERIC "0"
+// Retrieval info: PRIVATE: REGrdaddress_a NUMERIC "1"
+// Retrieval info: PRIVATE: REGrdaddress_b NUMERIC "1"
+// Retrieval info: PRIVATE: REGrren_a NUMERIC "0"
+// Retrieval info: PRIVATE: REGrren_b NUMERIC "0"
+// Retrieval info: PRIVATE: REGwrite NUMERIC "1"
+// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+// Retrieval info: PRIVATE: WidthAddr NUMERIC "3"
+// Retrieval info: PRIVATE: WidthData NUMERIC "16"
+// Retrieval info: PRIVATE: enable NUMERIC "0"
+// Retrieval info: PRIVATE: rden_a NUMERIC "0"
+// Retrieval info: PRIVATE: rden_b NUMERIC "0"
+// Retrieval info: CONSTANT: INDATA_ACLR STRING "OFF"
+// Retrieval info: CONSTANT: INDATA_REG STRING "INCLOCK"
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "alt3pram"
+// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "OFF"
+// Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "OFF"
+// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED"
+// Retrieval info: CONSTANT: OUTDATA_REG_B STRING "UNREGISTERED"
+// Retrieval info: CONSTANT: RDADDRESS_ACLR_A STRING "OFF"
+// Retrieval info: CONSTANT: RDADDRESS_ACLR_B STRING "OFF"
+// Retrieval info: CONSTANT: RDADDRESS_REG_A STRING "INCLOCK"
+// Retrieval info: CONSTANT: RDADDRESS_REG_B STRING "INCLOCK"
+// Retrieval info: CONSTANT: RDCONTROL_ACLR_A STRING "OFF"
+// Retrieval info: CONSTANT: RDCONTROL_ACLR_B STRING "OFF"
+// Retrieval info: CONSTANT: RDCONTROL_REG_A STRING "UNREGISTERED"
+// Retrieval info: CONSTANT: RDCONTROL_REG_B STRING "UNREGISTERED"
+// Retrieval info: CONSTANT: WIDTH NUMERIC "16"
+// Retrieval info: CONSTANT: WIDTHAD NUMERIC "3"
+// Retrieval info: CONSTANT: WRITE_ACLR STRING "OFF"
+// Retrieval info: CONSTANT: WRITE_REG STRING "INCLOCK"
+// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL data[15..0]
+// Retrieval info: USED_PORT: qa 0 0 16 0 OUTPUT NODEFVAL qa[15..0]
+// Retrieval info: USED_PORT: qb 0 0 16 0 OUTPUT NODEFVAL qb[15..0]
+// Retrieval info: USED_PORT: rdaddress_a 0 0 3 0 INPUT NODEFVAL rdaddress_a[2..0]
+// Retrieval info: USED_PORT: rdaddress_b 0 0 3 0 INPUT NODEFVAL rdaddress_b[2..0]
+// Retrieval info: USED_PORT: wraddress 0 0 3 0 INPUT NODEFVAL wraddress[2..0]
+// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT GND wren
+// Retrieval info: CONNECT: @data 0 0 16 0 data 0 0 16 0
+// Retrieval info: CONNECT: qa 0 0 16 0 @qa 0 0 16 0
+// Retrieval info: CONNECT: qb 0 0 16 0 @qb 0 0 16 0
+// Retrieval info: CONNECT: @wraddress 0 0 3 0 wraddress 0 0 3 0
+// Retrieval info: CONNECT: @rdaddress_a 0 0 3 0 rdaddress_a 0 0 3 0
+// Retrieval info: CONNECT: @rdaddress_b 0 0 3 0 rdaddress_b 0 0 3 0
+// Retrieval info: CONNECT: @wren 0 0 0 0 wren 0 0 0 0
+// Retrieval info: CONNECT: @inclock 0 0 0 0 clock 0 0 0 0
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16.inc TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16.cmp FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16.bsf FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16_inst.v FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL regfile8x16_bb.v TRUE
+// Retrieval info: LIB_FILE: altera_mf
regfile8x16.v
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: shifter.v
===================================================================
--- shifter.v (nonexistent)
+++ shifter.v (revision 2)
@@ -0,0 +1,59 @@
+module shifter (
+ a,
+ b,
+ n_in,
+ v_in,
+ z_in,
+ c_in,
+ distance,
+ func,
+ result,
+ n,
+ v,
+ z,
+ c
+ );
+
+ input signed [15:0] a,b;
+ input n_in;
+ input v_in;
+ input z_in;
+ input c_in;
+ input [3:0] distance;
+ input [1:0] func;
+ output [15:0] result;
+ output n,v,z,c;
+
+ // hack / workaround to make sure carry / msb gets propagated correctly
+ wire signed [16:0] x = { a, c_in };
+
+ reg [15:0] result;
+ reg result_c;
+ always @(*)
+ case(func)
+ 2'd0 : { result_c, result } = { c_in, b }; // mov / lui
+ 2'd1 : { result, result_c } = x >>> distance; // sra
+ default : { result_c, result } = { c_in, a } << distance; // sll
+ endcase
+
+ // flags
+ reg n,v,z,c;
+ always @(*)
+ begin
+ if ( func )
+ begin // shifts update accordingly
+ n = result[15];
+ z = ~|result;
+ c = result_c;
+ v = a[15] ^ result[15];
+ end
+ else // mov / lui don't change flags as they're frequently used to create literals / masks / addresses
+ begin
+ n = n_in;
+ v = v_in;
+ z = z_in;
+ c = c_in;
+ end
+ end
+
+endmodule
shifter.v
Property changes :
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property