1
0

More than 3 years have passed since last update.

windowsでiverilog その18

Last updated at Posted at 2020-06-14

概要

windowsでiverilogやってみた。
cpuを書いてみる。

参考にしたページ

命令セットを作る。

俺cpuニーモニック

ニーモニック 意味 stackの状態 code
% stack-1,stackの剰余を求める。 1個減る
+ stack-1,stackの加算を求める。 1個減る f000
/ stack-1,stackの除算を求める。 1個減る
* stack-1,stackの乗算を求める。 1個減る f002
- stack-1,stackの減算を求める。 1個減る f001
= stack-1,stackの等しいを求める。 1個減る f00a
> stack-1,stackの大小を求める。 1個減る f00e
push 1 stackに整数1を積む。 1個増える 1001
set i 変数iにstackを入れる。 1個減る 300i
get i stackに、変数iの値を入れる。 1個増える 200i
out stackを数値で印字する。 1個減る e000
if i stackが真ならiへ飛ぶ。 1個減る 500i
if! i stackが偽ならiへ飛ぶ。 1個減る 600i
jp i 無条件でiへ飛ぶ。 変化無し 400i
end 停止 変化無し 0000

俺cpu命令セット

ニーモニック bit15 bit14 bit13 bit12 bit10 bit9 bit8 bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 16進
end 0 0 0 0 - - - - - - - - - - - 0000
push I 0 0 0 1 I I I I I I I I I I I 1000+I
get A 0 0 1 0 A A A A A A A A A A A 2000+A
set A 0 0 1 1 A A A A A A A A A A A 3000+A
jp A 0 1 0 0 A A A A A A A A A A A 4000+A
if A 0 1 0 1 A A A A A A A A A A A 5000+A
if! A 0 1 1 0 A A A A A A A A A A A 6000+A
IN 1 1 0 1 - - - - - - - - - - - D000
out 1 1 1 0 - - - - - - - - - - - E000
+ 1 1 1 1 - - - - - - 0 0 0 0 0 F000
- 1 1 1 1 - - - - - - 0 0 0 0 1 F001
* 1 1 1 1 - - - - - - 0 0 0 1 0 F002
SHL 1 1 1 1 - - - - - - 0 0 0 1 1 F003
SHR 1 1 1 1 - - - - - - 0 0 1 0 0 F004
BAND 1 1 1 1 - - - - - - 0 0 1 0 1 F005
BOR 1 1 1 1 - - - - - - 0 0 1 1 0 F006
BXOR 1 1 1 1 - - - - - - 0 0 1 1 1 F007
AND 1 1 1 1 - - - - - - 0 1 0 0 0 F008
OR 1 1 1 1 - - - - - - 0 1 0 0 1 F009
= 1 1 1 1 - - - - - - 0 1 0 1 0 F00A
NE 1 1 1 1 - - - - - - 0 1 0 1 1 F00B
GE 1 1 1 1 - - - - - - 0 1 1 0 0 F00C
LE 1 1 1 1 - - - - - - 0 1 1 0 1 F00D
> 1 1 1 1 - - - - - - 0 1 1 1 0 F00E
LT 1 1 1 1 - - - - - - 0 1 1 1 1 F00F
NEG 1 1 1 1 - - - - - - 1 0 0 0 0 F010
BNOT 1 1 1 1 - - - - - - 1 0 0 0 1 F011
NOT 1 1 1 1 - - - - - - 1 0 0 1 0 F012

サンプルコード

  push  0
  set  x
loop:
  get  x
  push  1
  +
  set  x
  get  x
  out    
  push  10
  >
  if  loop
  end
x:    

シミュレータ作る。

ハンドアセンブル

        mem[0] = 16'h1000;//push 0
        mem[1] = 16'h300e;//set x
        mem[2] = 16'h200e;//get x
        mem[3] = 16'h1001;//push 1
        mem[4] = 16'hf000;//+
        mem[5] = 16'h300e;//set x
        mem[6] = 16'h200e;//get x
        mem[7] = 16'he000;//out
        mem[8] = 16'h200e;//get x
        mem[9] = 16'h1009;//push 9
        mem[10] = 16'hf00e;//>
        mem[11] = 16'h5002;//if 2
        mem[12] = 16'h0000;//end
        mem[13] = 16'h400c;//jp 12
        mem[14] = 16'h0008;//x

iverilog実行結果



test
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10


俺cpuサンプルコード



`define     IDLE    3'b000
`define     FETCHA  3'b001
`define     FETCHB  3'b010
`define     EXECA   3'b011
`define     EXECB   3'b100

`define     ADD     5'b00000
`define     SUB     5'b00001
`define     MUL     5'b00010
`define     SHL     5'b00011
`define     SHR     5'b00100
`define     BAND    5'b00101
`define     BOR     5'b00110
`define     BXOR    5'b00111
`define     AND     5'b01000
`define     OR      5'b01001
`define     EQ      5'b01010
`define     NE      5'b01011
`define     GE      5'b01100
`define     LE      5'b01101
`define     GT      5'b01110
`define     LT      5'b01111
`define     NEG     5'b10000
`define     BNOT    5'b10001
`define     NOT     5'b10010

`define     HALT    4'b0000
`define     PUSHI   4'b0001
`define     PUSH    4'b0010
`define     POP     4'b0011
`define     JMP     4'b0100
`define     JZ      4'b0101
`define     JNZ     4'b0110
`define     IN      4'b1101
`define     OUT     4'b1110
`define     OP      4'b1111

module counter(clk, rst, load, inc, d, q);
    parameter N = 16;
    input clk,
        rst,
        load,
        inc;
    input [N - 1:0] d;
    output [N - 1:0] q;
    reg [N - 1:0] q;
    always @(posedge clk or negedge rst)
        if (!rst)
            q <= 0;
        else if (load)
            q <= d;
        else if (inc)
            q <= q + 1;
endmodule

module stack(clk, rst, load, push, pop, d, qtop, qnext);
    parameter N = 8;
    input clk,
        rst,
        load,
        push,
        pop;
    input [15:0] d;
    output [15:0] qtop,
        qnext;
    reg [15:0] q[0:N - 1];
    assign qtop = q[0];
    assign qnext = q[1];
    always @(posedge clk or negedge rst)
        if (!rst)
            q[0] <= 0;
        else if (load)
            q[0] <= d;
        else if (pop)
            q[0] <= q[1];
    integer i;
    always @(posedge clk or negedge rst)
        for (i = 1; i < N - 1; i = i + 1)
            if (!rst)
                q[i] <= 0;
            else if (push)
                q[i] <= q[i - 1];
            else if (pop)
                q[i] <= q[i + 1];
    always @(posedge clk or negedge rst)
        if (!rst)
            q[N - 1] <= 0;
        else if (push)
            q[N - 1] <= q[N - 2];
endmodule

module ram(clk, load, addr, d, q);
    parameter DWIDTH = 16,
        AWIDTH = 12,
        WORDS = 4096;
    input clk,
        load;
    input [AWIDTH - 1:0] addr;
    input [DWIDTH - 1:0] d;
    output [DWIDTH - 1:0] q;
    reg [DWIDTH - 1:0] q;
    reg [DWIDTH - 1:0] mem[WORDS - 1:0];
    always @(posedge clk)
    begin
        if (load)
            mem[addr] <= d;
        q <= mem[addr];
    end
    initial
    begin
        mem[0] = 16'h1000;//push 0
        mem[1] = 16'h300e;//set x
        mem[2] = 16'h200e;//get x
        mem[3] = 16'h1001;//push 1
        mem[4] = 16'hf000;//+
        mem[5] = 16'h300e;//set x
        mem[6] = 16'h200e;//get x
        mem[7] = 16'he000;//out
        mem[8] = 16'h200e;//get x
        mem[9] = 16'h1009;//push 9
        mem[10] = 16'hf00e;//>
        mem[11] = 16'h5002;//if 2
        mem[12] = 16'h0000;//end
        mem[13] = 16'h400c;//jp 12
        mem[14] = 16'h0008;//x
    end
endmodule

module alu(a, b, f, s);
    input [15:0] a,
        b;
    input [4:0] f;
    output [15:0] s;
    reg [15:0] s;
    wire [15:0] x,
        y;
    assign x = a + 16'h8000;
    assign y = b + 16'h8000;
    always @(a or b or x or y or f)
        case (f)
        `ADD:
            s = b + a;
        `SUB:
            s = b - a;
        `MUL:
            s = b * a;
        `SHL:
            s = b << a;
        `SHR:
            s = b >> a;
        `BAND:
            s = b & a;
        `BOR:
            s = b | a;
        `BXOR:
            s = b ^ a;
        `AND:
            s = b && a;
        `OR:
            s = b || a;
        `EQ:
            s = b == a;
        `NE:
            s = b != a;
        `GE:
            s = y >= x;
        `LE:
            s = y <= x;
        `GT:
            s = y > x;
        `LT:
            s = y < x;
        `NEG:
            s = -a;
        `BNOT:
            s = ~a;
        `NOT:
            s = !a;
        default:
            s = 16'hxxxx;
        endcase
endmodule

module state(clk, rst, cont, halt, cs);
    input clk,
        rst,
        run,
        cont,
        halt;
    output [2:0] cs;
    reg [2:0] cs;
    always @(posedge clk or negedge rst)
        if (!rst)
            cs <= `IDLE;
        else
            case (cs)
            `IDLE:
                cs <= `FETCHA;
            `FETCHA:
                cs <= `FETCHB;
            `FETCHB:
                cs <= `EXECA;
            `EXECA:
                if (halt)
                    cs <= `IDLE;
                else if (cont)
                    cs <= `EXECB;
                else
                    cs <= `FETCHA;
            `EXECB:
                cs <= `FETCHA;
            default:
                cs <= 3'bxxx;
            endcase
endmodule

module tinycpu(clk, rst, pcout, out);
    input clk,
        rst;
    output [15:0] out;
    reg [15:0] in;
    wire [2:0] cs;
    wire [15:0] irout,
        qtop,
        dbus;
    output [11:0] pcout;
    wire [15:0] qnext,
        ramout,
        aluout;
    reg [11:0] abus;
    reg halt,
        cont,
        pcinc,
        push,
        pop,
        abus2pc,
        dbus2ir,
        dbus2qtop,
        dbus2ram,
        dbus2obuf,
        pc2abus,
        ir2abus,
        ir2dbus,
        qtop2dbus,
        alu2dbus,
        ram2dbus,
        in2dbus;
    counter #(12) pc0(.clk(clk), .rst(rst), .load(abus2pc), .inc(pcinc), .d(abus), .q(pcout));
    counter #(16) obuf0(.clk(clk), .rst(rst), .load(dbus2obuf), .inc(0), .d(dbus), .q(out));
    counter #(16) ir0(.clk(clk), .rst(rst), .load(dbus2ir), .inc(0), .d(dbus), .q(irout));
    state state0(.clk(clk), .rst(rst), .cont(cont), .halt(halt), .cs(cs));
    stack stack0(.clk(clk), .rst(rst), .load(dbus2qtop), .push(push), .pop(pop), .d(dbus), .qtop(qtop), .qnext(qnext));
    alu alu0(.a(qtop), .b(qnext), .f(irout[4:0]), .s(aluout));
    ram ram0(.clk(clk), .load(dbus2ram), .addr(abus[11:0]), .d(dbus), .q(ramout));
    assign dbus = ir2dbus ? {{4{irout[11]}}, irout[11:0]} : 16'hzzzz;
    assign dbus = qtop2dbus ? qtop : 16'hzzzz;
    assign dbus = alu2dbus ? aluout : 16'hzzzz;
    assign dbus = ram2dbus ? ramout : 16'hzzzz;
    assign dbus = in2dbus ? in : 16'hzzzz;
    always @(pc2abus or ir2abus or pcout or irout)
        if (pc2abus)
            abus <= pcout;
        else if (ir2abus)
            abus <= irout[11:0];
        else
            abus <= 12'hxxx;
    always @(cs or irout or qtop)
    begin
        halt = 0;
        pcinc = 0;
        push = 0;
        pop = 0;
        cont = 0;
        abus2pc = 0;
        dbus2ir = 0;
        dbus2qtop = 0;
        dbus2ram = 0;
        dbus2obuf = 0;
        pc2abus = 0;
        ir2abus = 0;
        ir2dbus = 0;
        qtop2dbus = 0;
        alu2dbus = 0;
        ram2dbus = 0;
        in2dbus = 0;
        if (cs == `FETCHA)
        begin
            pcinc = 1;
            pc2abus = 1;
        end
        else if (cs == `FETCHB)
        begin
            ram2dbus = 1;
            dbus2ir = 1;
        end
        else if (cs == `EXECA)
            case (irout[15:12])
            `PUSHI:
            begin
                ir2dbus = 1;
                dbus2qtop = 1;
                push = 1;
            end
            `PUSH:
            begin
                ir2abus = 1;
                cont = 1;
            end
            `POP:
            begin
                ir2abus = 1;
                qtop2dbus = 1;
                dbus2ram = 1;
                pop = 1;
            end
            `JMP:
            begin
                ir2abus = 1;
                abus2pc = 1;
            end
            `JZ:
            begin
                if (qtop == 0)
                begin
                    ir2abus = 1;
                    abus2pc = 1;
                end
                pop = 1;
            end
            `JNZ:
            begin
                if (qtop != 0)
                begin
                    ir2abus = 1;
                    abus2pc = 1;
                end
                pop = 1;
            end
            `IN:
            begin
                in2dbus = 1;
                dbus2qtop = 1;
                push = 1;
            end
            `OUT:
            begin
                qtop2dbus = 1;
                dbus2obuf = 1;
                pop = 1;
            end
            `OP:
            begin
                alu2dbus = 1;
                dbus2qtop = 1;
                if (irout[4] == 0)
                    pop = 1;
            end
            default:
                halt = 1;
            endcase
        else if (cs == `EXECB)
            if (irout[15:12] == `PUSH)
            begin
                ram2dbus = 1;
                dbus2qtop = 1;
                push = 1;
            end
        end
endmodule

module test;
    reg clk,
        rst;
    wire [15:0] out;
    wire [11:0] pcout;
    tinycpu u(.clk(clk), .rst(rst), .pcout(pcout), .out(out));
    initial
    begin
        clk = 0;
        rst = 0;
        #10
            rst = 1;
        #4000
            $finish;
    end
    always
    begin
        #5
            clk = ~clk;
    end
    initial
    begin
        $display("test");
        //$monitor("%d %d", pcout, out);
        $monitor("%d", out);
    end
endmodule





以上。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0