URL
https://opencores.org/ocsvn/thor/thor/trunk
Subversion Repositories thor
[/] [thor/] [trunk/] [FT64/] [rtl/] [seq/] [FT64seq.v] - Rev 48
Go to most recent revision | Compare with Previous | Blame | View Log
// ============================================================================ // __ // \\__/ o\ (C) 2017-2018 Robert Finch, Waterloo // \ __ / All rights reserved. // \/_// robfinch<remove>@finitron.ca // || // // FT64seq.v // - FT64 processing core - sequential version // // This source file is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This source file 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, see <http://www.gnu.org/licenses/>. // // ============================================================================ // // Comment out the following line to exclude AMO operations from the core. `define EXT_A 1'b1 // Comment out the following line to exclude multiply/divide operations from the core. `define EXT_M 1'b1 `define BRK 6'h00 `define R2 6'h02 `define R1 6'h01 `define ABS 5'h04 `define NOT 5'h05 `define SUB 6'h05 `define Scc 6'h06 `define Sccu 6'h07 `define SHIFTW 6'h0F `define SHIFTB 6'h1F `define LEAX 6'h18 `define SYNC 6'h22 `define SHIFTC 6'h2F `define SEI 6'h30 `define WAIT 6'h31 `define RTI 6'h32 `define RTE 6'h32 `define DIVMODU 6'h3C `define DIVMODSU 6'h3D `define DIVMOD 6'h3E `define SHIFTH 6'h3F `define BccR 6'h03 `define ADD 6'h04 `define CMP 6'h06 `define CMPU 6'h07 `define AND 6'h08 `define OR 6'h09 `define XOR 6'h0A `define REX 6'h0D `define CSR 6'h0E `define LH 6'h10 `define LHU 6'h11 `define LW 6'h12 `define LB 6'h13 `define SH 6'h14 `define SB 6'h15 `define SW 6'h16 `define SWC 6'h17 `define JAL 6'h18 `define CALL 6'h19 `define QOPI 6'h1A `define QOR 3'd0 `define QADD 3'd1 `define QAND 3'd2 `define QXOR 3'd3 `define SccI 6'h1B `define NOP 6'h1C `define LWR 6'h1D `define LC 6'h20 `define LCU 6'h21 `define BITFLD 6'h22 `define LBU 6'h23 `define SC 6'h24 `define BBc0 6'h26 `define BBc1 6'h27 `define JMP 6'h28 `define LINK 6'h2A `define MODUI 6'h2C `define MODSUI 6'h2D `define MODI 6'h2E `define AMO 6'h2F `define AMOSWAP 6'h00 `define AMOADD 6'h04 `define AMOAND 6'h08 `define AMOOR 6'h09 `define AMOXOR 6'h0A `define AMOSHL 6'h0C `define AMOSHR 6'h0D `define AMOASR 6'h0E `define AMOROL 6'h0F `define AMOMIN 6'h1C `define AMOMAX 6'h1D `define AMOMINU 6'h1E `define AMOMAXU 6'h1F `define AMOSWAPI 6'h20 `define AMOADDI 6'h24 `define AMOANDI 6'h28 `define AMOORI 6'h29 `define AMOXORI 6'h2A `define AMOSHLI 6'h2C `define AMOSHRI 6'h2D `define AMOASRI 6'h2E `define AMOROLI 6'h2F `define AMOMINI 6'h3C `define AMOMAXI 6'h3D `define AMOMINUI 6'h3E `define AMOMAXUI 6'h3F `define Bcc0 6'h30 `define Bcc1 6'h31 `define BEQ0 6'h32 `define BEQ1 6'h33 `define MULU 6'h38 `define MULSU 6'h39 `define MUL 6'h3A `define DIVUI 6'h3C `define DIVSUI 6'h3D `define DIVI 6'h3E `define SHL 4'h0 `define SHR 4'h1 `define ASL 4'h2 `define ASR 4'h3 `define ROL 4'h4 `define ROR 4'h5 `define SHLI 4'h8 `define SHRI 4'h9 `define ASLI 4'hA `define ASRI 4'hB `define ROLI 4'hC `define RORI 4'hD `define BEQ 4'h0 `define BNE 4'h1 `define BLT 4'h2 `define BGE 4'h3 `define BLTU 4'h4 `define BGEU 4'h5 `define FBEQ 4'h8 `define FBNE 4'h9 `define FBLT 4'hA `define FBGE 4'hB `define HARTID 11'h001 `define TICK 11'h002 `define CAUSE 11'h006 `define SCRATCH 11'h009 `define SEMA 11'h00C `define TVEC 11'b000_0011_0??? `define TIME 11'h7E0 `define INSTRET 11'h7E1 module FT64seq(hartid_i, sig_i, rst_i, clk_i, tm_clk_i, irq_i, cause_i, cyc_o, stb_o, ack_i, sel_o, we_o, adr_o, dat_i, dat_o, sr_o, cr_o, rb_i, state); input [63:0] hartid_i; input [63:0] sig_i; input rst_i; input clk_i; input tm_clk_i; // 100 MHz input [2:0] irq_i; input [8:0] cause_i; output reg cyc_o; output reg stb_o; input ack_i; output reg [15:0] sel_o; output reg we_o; output reg [31:0] adr_o; input [127:0] dat_i; output reg [127:0] dat_o; output reg sr_o; output reg cr_o; input rb_i; output reg [7:0] state; // Wall clock timing parameter. Number of tm_clk_i cycles for 1s interval parameter WCTIME1S = 32'd100000000; parameter RST_ADDR = 32'hFFFC0100; parameter RESET = 8'd0; parameter IFETCH = 8'd1; parameter IFETCH_ACK = 8'd2; parameter IFETCH_NACK = 8'd3; parameter REGFETCH = 8'd4; parameter DECODE = 8'd5; parameter EXECUTE = 8'd6; parameter MEMORY = 8'd7; parameter MEMORY_NACK = 8'd8; parameter MULDIV2 = 8'd9; parameter AMOOP = 8'd10; parameter AMOMEM = 8'd11; parameter word = 2'd3; parameter half = 2'd2; parameter char = 2'd1; parameter byt_ = 2'd0; integer n, m; reg [63:0] sema; reg [43:0] brkstack [0:4]; reg [31:0] tvec [0:7]; reg [2:0] ol; reg [2:0] im; reg [7:0] pl; reg [31:0] pc,opc; reg [31:0] ir; wire [5:0] opcode = ir[5:0]; wire [5:0] funct = ir[31:26]; wire [4:0] func5 = ir[25:21]; wire [3:0] func4 = ir[25:22]; reg [1:0] opsize; reg [31:0] ibuf_adr [0:7]; reg [31:0] ibuf [0:7]; reg [2:0] ibuf_cnt; reg rfwr; reg [4:0] Ra, Rb, Rc, Rt; reg [63:0] regfile [0:31]; wire [63:0] rfoa = regfile[Ra]; wire [63:0] rfob = regfile[Rb]; wire [63:0] rfoc = regfile[Rc]; reg [63:0] a,b,c,res,amores; reg [31:0] rasstack [0:511]; reg [8:0] rassp; reg [4:0] regLR = 5'd29; // CSR's reg [8:0] cause; reg [63:0] scratch; reg [63:0] tick; reg [63:0] wctime, times; reg [63:0] instret; wire [127:0] produ;// = a * b; wire [127:0] prods;// = $signed(a) * $signed(b); wire [127:0] prodsu;// = $signed(a) * b; wire [2:0] npl = ir[23:16] | a; wire [63:0] sum = a + b; wire [63:0] dif = a - b; wire [31:0] eandx = a + (b << ir[22:21]); wire [63:0] am8 = a - 32'd8; // for link wire [31:0] xIncea = ir[25] ? a + {{59{ir[25]}},ir[25:21]} : a; // for POP / PUSH reg [63:0] opimp; reg [63:0] fnimp; function [23:0] regname; input [4:0] regno; case(regno) 5'd0: regname = "r0"; 5'd1: regname = "r1"; 5'd2: regname = "r2"; 5'd3: regname = "r3"; 5'd4: regname = "r4"; 5'd5: regname = "r5"; 5'd6: regname = "r6"; 5'd7: regname = "r7"; 5'd8: regname = "r8"; 5'd9: regname = "r9"; 5'd10: regname = "r10"; 5'd11: regname = "r11"; 5'd12: regname = "r12"; 5'd13: regname = "r13"; 5'd14: regname = "r14"; 5'd15: regname = "r15"; 5'd16: regname = "r16"; 5'd17: regname = "r17"; 5'd18: regname = "r18"; 5'd19: regname = "r19"; 5'd20: regname = "r20"; 5'd21: regname = "r21"; 5'd22: regname = "r22"; 5'd23: regname = "r23"; 5'd24: regname = "r24"; 5'd25: regname = "r25"; 5'd26: regname = "r26"; 5'd27: regname = "r27"; 5'd28: regname = "r28"; 5'd29: regname = "lr"; 5'd30: regname = "bp"; 5'd31: regname = "sp"; endcase endfunction always @* begin m <= 4'hF; for (n = 0; n < 8; n = n + 1) if (pc==ibuf_adr[n]) m <= n; end reg [127:0] din; // input data latch reg [3:0] dshift; wire [7:0] byte_in = din >> {dshift[3:0],3'b0}; wire [15:0] char_in = din >> {dshift[3:1],4'h0}; wire [31:0] half_in = din >> {dshift[3:2],5'h0}; wire [63:0] word_in = din >> {dshift[3],6'h0}; wire [127:0] shlo = {64'd0,a} << b[5:0]; wire [127:0] shro = {a,64'd0} >> b[5:0]; wire [31:0] asro32 = a[31] ? ~(32'hFFFFFFFFFFFFFFFF >> b[5:0]) | shro[95:64] : shro[95:64]; wire [63:0] bfo; wire [63:0] shiftwo; wire [31:0] shiftho; FT64_shift uws1 ( .instr(ir), .a(a), .b(b), .res(shiftwo), .ov() ); FT64_shifth uhws1 ( .instr(ir), .a(a[31:0]), .b(b[31:0]), .res(shiftho), .ov() ); FT64_bitfield ubf1 ( .inst(ir), .a(a), .b(b), .o(bfo), .masko() ); reg div_ld, mul_ld; reg [4:0] mul_cnt; wire div_done; wire [63:0] div_qo, div_ro; wire div_sgn = opcode==`DIVI || opcode==`MODI || (opcode==`R2 && (funct==`DIVMOD)); wire div_sgnus = opcode==`DIVSUI || opcode==`MODSUI || (opcode==`R2 && (funct==`DIVMODSU)); `ifdef EXT_M FT64_divider udiv1 ( .rst(rst_i), .clk(clk_i), .ld(div_ld), .abort(), .sgn(div_sgn), .sgnus(div_sgnus), .a(a), .b(b), .qo(div_qo), .ro(div_ro), .dvByZr(), .done(div_done), .idle() ); FT64_mul umul1 ( .CLK(clk_i), .A(a), .B(b), .P(prods) ); FT64_mulu umul2 ( .CLK(clk_i), .A(a), .B(b), .P(produ) ); FT64_mulsu umul3 ( .CLK(clk_i), .A(a), .B(b), .P(prodsu) ); `endif wire takb; FT64_EvalBranch ube1 ( .instr(ir), .a(a), .b(b), .takb(takb) ); always @(posedge clk_i) if (rst_i) mul_cnt <= 5'd19; else begin if (mul_ld) mul_cnt <= 5'd1; else if (mul_cnt < 5'd19) mul_cnt <= mul_cnt + 5'd1; end wire mul_done = mul_cnt==5'd19; always @(posedge clk_i) if (ack_i) din <= dat_i; always @(posedge clk_i) if (ack_i) dshift <= adr_o[3:0]; reg rbl; always @(posedge clk_i) if (ack_i) rbl <= rb_i; always @(posedge clk_i) if (rst_i) tick <= 63'd0; else tick <= tick + 64'd1; always @(posedge clk_i) if (rst_i) state <= RESET; else begin // Cause these signals to pulse for just one clock cycle. They are set // active below. div_ld <= `FALSE; mul_ld <= `FALSE; rfwr <= `FALSE; case(state) // RESET: // Reset only the signals critical to the proper operation of the core. // This includes setting the PC address and deactivating the bus // controls. RESET: begin im <= 3'd7; ol <= 3'd0; pl <= 8'h00; pc <= RST_ADDR; cyc_o <= `LOW; stb_o <= `LOW; we_o <= `LOW; sel_o <= 16'h0000; adr_o <= 32'hFFFFFFFF; instret <= 64'd0; opimp <= 64'h000F_F1FF_3FFF_67DD; `ifdef EXT_A opimp[47] <= 1'b1; `endif `ifdef EXT_M opimp[63:55] <= 8'h77; `endif fnimp <= 64'h8005_701F_A1FF_87F4; `ifdef EXT_M fnimp[63:55] <= 8'h77; `endif goto(IFETCH); end // IFETCH: // Fetch instructions from memory located by the program counter. A fully // associative buffer (cache) of the most recently used eight instructions // is maintained. A memory access won't be required if the instruction can // be found in the buffer. // Also update the register file for the previous instruction. Rather than // have another state in the state machine to perform the register update // it is done here to improve performance. IFETCH: begin opc <= pc; instret <= instret + 64'd1; if (irq_i > im) begin ir <= {13'd0,irq_i,1'b0,cause_i,`BRK}; goto(DECODE); end else if (m[3]) begin cyc_o <= `HIGH; stb_o <= `HIGH; sel_o <= 16'hF << {pc[3:2],2'b0}; adr_o <= pc; goto(IFETCH_ACK); end else begin ir <= ibuf[m]; pc <= pc + 32'd4; $display("ir: %h (from ibuf)", ibuf[m]); goto(DECODE); end end IFETCH_ACK: if (ack_i) begin cyc_o <= `LOW; stb_o <= `LOW; sel_o <= 16'h0000; //adr_o <= 32'hFFFFFFFF; goto(IFETCH_NACK); end IFETCH_NACK: if (~ack_i) begin ir <= half_in; ibuf[ibuf_cnt] <= half_in; ibuf_adr[ibuf_cnt] <= pc; ibuf_cnt <= ibuf_cnt + 3'd1; pc <= pc + 32'd4; $display("ir: %h", half_in); goto(DECODE); end // DECODE: // Setup for register file access. Ra, Rb, Rc are almost always decoded from // the same spot in the instruction register to keep the decoding simple and // access to the register file fast. For the call instruction Ra is forced to // r31 since it doesn't come from the ir. Rt tends to float around depending on // the instruction. // Several instructions which do not have register operands (JMP,NOP,RTI, and // BRK) are executed directly in the decode stage to improve performance. DECODE: begin goto(REGFETCH); Ra <= ir[10:6]; Rb <= ir[15:11]; Rc <= ir[20:16]; Rt <= 5'd0; opsize <= word; if (!opimp[opcode]) exe_brk(9'd485); // unimplemented case(opcode) `BRK: exe_brk(ir[14:6]); `R2: begin if (!fnimp[opcode]) exe_brk(9'd485); // unimplemented Rt <= ir[20:16]; case(funct) `R1: case(func5) `ABS,`NOT: Rt <= ir[15:11]; endcase `ADD,`SUB: opsize <= ir[22:21]; `AND,`OR,`XOR: Rt <= ir[25:21]; `SHIFTB,`SHIFTC,`SHIFTH,`SHIFTW: Rt <= ir[25] ? ir[15:11] : ir[20:16]; // The SYNC instruction is treated as a NOP since this machine // is strictly in order. `SYNC: goto(IFETCH); `SB,`SC,`SH,`SW,`SWC: Rt <= 5'd0; endcase end `NOP: goto(IFETCH); `JMP: begin pc <= {pc[31:28],ir[31:6],2'b00}; goto(IFETCH); end `CALL: Rt <= regLR; `JAL: Rt <= ir[15:11]; `CSR: Rt <= ir[15:11]; `QOPI: begin Ra <= ir[15:11]; Rt <= ir[15:11]; end `BITFLD: Rt <= ir[15:11]; `ADD,`CMP,`CMPU,`AND,`OR,`XOR, `ifdef EXT_M `MULU,`MUL,`MULSU, `DIVI,`DIVUI,`DIVSUI,`MODI,`MODUI,`MODSUI, `endif `LB,`LBU,`LC,`LCU,`LH,`LHU,`LW,`LWR: Rt <= ir[15:11]; `SB,`SC,`SH,`SW,`SWC: Rt <= 5'd0; `ifdef EXT_A `AMO: Rt <= ir[31] ? ir[15:11] : ir[20:16]; `endif default: ; endcase end // REGFETCH: // Set operands from the register file, or the instruction register for // immediate operands. REGFETCH: begin goto(EXECUTE); a <= rfoa; b <= rfob; case(opcode) `R2: case(funct) `SHIFTW,`SHIFTB,`SHIFTC,`SHIFTH: if (ir[25]) b <= ir[21:16]; `AND,`OR,`XOR: c <= rfoc; `ifdef EXT_M `MUL,`MULU,`MULSU: mul_ld <= `TRUE; `DIVMOD,`DIVMODU,`DIVMODSU: div_ld <= `TRUE; `endif `LB,`LBU,`LH,`LHU,`LC,`LCU,`LW,`LWR, `SB,`SC,`SH,`SW,`SWC: c <= rfoc; endcase `ADD,`CMP,`CMPU,`AND,`OR,`XOR: b <= {{48{ir[31]}},ir[31:16]}; `SccI: b <= {{52{ir[27]}},ir[27:16]}; `ifdef EXT_M `MUL,`MULU,`MULSU: begin b <= {{48{ir[31]}},ir[31:16]}; mul_ld <= `TRUE; end `DIVI,`MODI,`DIVUI,`DIVSUI,`MODUI,`MODSUI: begin b <= {{48{ir[31]}},ir[31:16]}; div_ld <= `TRUE; end `endif `QOPI: begin case(ir[10:8]) 3'd0,3'd3: // OR, XOR case(ir[7:6]) 2'd0: b <= {{48{1'b0}},ir[31:16]}; 2'd1: b <= {{32{1'b0}},ir[31:16]} << 16; 2'd2: b <= {{16{1'b0}},ir[31:16]} << 32; 2'd3: b <= {ir[31:16]} << 48; endcase 3'd1: // ADD case(ir[7:6]) 2'd0: b <= {{48{ir[31]}},ir[31:16]}; 2'd1: b <= {{32{ir[31]}},ir[31:16]} << 16; 2'd2: b <= {{16{ir[31]}},ir[31:16]} << 32; 2'd3: b <= {ir[31:16]} << 48; endcase 3'd2: // AND case(ir[7:6]) 2'd0: b <= {{48{1'b1}},ir[31:16]}; 2'd1: b <= {{32{1'b1}},ir[31:16],16'hFFFF}; 2'd2: b <= {{16{1'b1}},ir[31:16],32'hFFFFFFFF}; 2'd3: b <= {ir[31:16],48'hFFFFFFFFFFFF}; endcase default: b <= 64'd0; endcase end `Bcc0,`Bcc1,`BccR,`BBc0,`BBc1: c <= rfoc; `BEQ0,`BEQ1: b <= {{55{ir[19]}},ir[19:11]}; `JAL: b <= {{48{ir[31]}},ir[31:16]}; `LB,`LBU,`LH,`LHU,`LC,`LCU,`LW,`LWR, `SB,`SC,`SH,`SW,`SWC: begin b <= {{48{ir[31]}},ir[31:16]}; c <= rfob; end `ifdef EXT_A `AMO: if (ir[31]) b <= {{59{ir[20]}},ir[20:16]}; `endif endcase end // EXECUTE: // Execute the instruction. Compute results and begin any memory access. EXECUTE: begin goto(IFETCH); case(opcode) `R2: case(funct) `RTE: begin pc <= {brkstack[0][43:14],2'b00}; pl <= brkstack[0][13:6]; ol <= brkstack[0][5:3]; im <= brkstack[0][2:0]; for (n = 0; n < 4; n = n + 1) brkstack[n] <= brkstack[n+1]; sema[0] <= 1'b0; sema[ir[21:16]|a[5:0]] <= 1'b0; end `R1: case(func5) `ABS: begin res <= a[63] ? -a : a; rfwr <= `TRUE; end `NOT: begin res <= a!=0 ? 64'd0 : 64'd1; rfwr <= `TRUE; end endcase `SEI: im <= a[2:0] | ir[18:16]; `SHIFTW: begin rfwr <= `TRUE; res <= shiftwo; end `SHIFTH: begin rfwr <= `TRUE; case(func4) `SHL,`SHLI: res <= {32'd0,shiftho}; `SHR,`SHRI: res <= {32'd0,shiftho}; `ASL,`ASLI: res <= {{32{shiftho[31]}},shiftho}; `ASR,`ASRI: res <= {{32{shiftho[31]}},shiftho}; `ROL,`ROLI: begin res[31:0] <= shiftho; res[63:32] <= {32{shiftho[31]}}; end `ROR,`RORI: begin res[31:0] <= shiftho; res[63:32] <= {32{shiftho[31]}}; end endcase end `ADD: begin rfwr <= `TRUE; case(opsize) word: res <= sum; half: res <= {{32{sum[31]}},sum[31:0]}; char: res <= {{48{sum[15]}},sum[15:0]}; byt_: res <= {{56{sum[7]}},sum[7:0]}; endcase end `SUB: begin rfwr <= `TRUE; case(opsize) word: res <= dif; half: res <= {{32{dif[31]}},dif[31:0]}; char: res <= {{48{dif[15]}},dif[15:0]}; byt_: res <= {{56{dif[7]}},dif[7:0]}; endcase end `Scc: begin rfwr <= `TRUE; case(ir[25:23]) 3'd0: res <= $signed(a) < $signed(b) ? 64'hFFFFFFFFFFFFFFFF : a==b ? 64'h0 : 64'h1; 3'd2: res <= a==b; 3'd3: res <= a!=b; 3'd4: res <= $signed(a) < $signed(b); 3'd5: res <= $signed(a) >= $signed(b); 3'd6: res <= $signed(a) <= $signed(b); 3'd7: res <= $signed(a) > $signed(b); endcase end `Sccu: begin rfwr <= `TRUE; case(ir[25:23]) 3'd0: res <= a < b ? 64'hFFFFFFFFFFFFFFFF : a==b ? 64'h0 : 64'h1; 3'd2: res <= a==b; 3'd3: res <= a!=b; 3'd4: res <= a < b; 3'd5: res <= a >= b; 3'd6: res <= a <= b; 3'd7: res <= a > b; endcase end `ifdef EXT_M `MULU: if (mul_done) begin res <= ir[25:23]==3'd0 ? produ[63:0] : produ[127:64]; rfwr <= `TRUE; goto(IFETCH); end else goto(EXECUTE); `MUL: if (mul_done) begin res <= ir[25:23]==3'd0 ? prods[63:0] : prods[127:64]; rfwr <= `TRUE; goto(IFETCH); end else goto(EXECUTE); `MULSU: if (mul_done) begin res <= ir[25:23]==3'd0 ? prodsu[63:0] : prodsu[127:64]; rfwr <= `TRUE; goto(IFETCH); end else goto(EXECUTE); // For divide stay in the EXECUTE state until the divide is done. `DIVMOD,`DIVMODU,`DIVMODSU: if (div_done) begin res <= ir[25:23]==3'd0 ? div_qo : div_ro; rfwr <= `TRUE; goto(IFETCH); end else goto(EXECUTE); `endif `AND: begin res <= a & b & c; rfwr <= `TRUE; end `OR: begin res <= a | b | c; rfwr <= `TRUE; end `XOR: begin res <= a ^ b ^ c; rfwr <= `TRUE; end `LEAX: begin rfwr <= `TRUE; res <= eandx; end `LB,`LBU: wb_read(16'h01 << eandx[3:0], eandx); `LC,`LCU: wb_read(16'h03 << {eandx[3:1],1'b0}, eandx); `LH,`LHU: wb_read(16'h0F << {eandx[3:2],2'b0}, eandx); `LW: wb_read(16'hFF << {eandx[3],3'b0}, eandx); `LWR: begin wb_read(16'hFF << {eandx[3],3'b0}, eandx); sr_o <= `HIGH; end `SB: wb_write(16'h01 << eandx[3:0],eandx,{8{c[7:0]}}); `SC: wb_write(16'h03 << {eandx[3:1],1'b0},eandx,{4{c[15:0]}}); `SH: wb_write(16'h0F << {eandx[3:2],2'b0},eandx,{2{c[31:0]}}); `SW: wb_write(16'hFF << {eandx[3],3'b0},eandx,c); `SWC: begin cr_o <= `HIGH; wb_write(16'hFF << {eandx[3],3'b0},eandx,c); end endcase `ADD: begin res <= sum; rfwr <= `TRUE; end `CMP: begin res <= $signed(a) < $signed(b) ? 64'hFFFFFFFFFFFFFFFF : a==b ? 64'h0 : 64'h1; rfwr <= `TRUE; end `CMPU: begin res <= a < b ? 64'hFFFFFFFFFFFFFFFF : a==b ? 64'h0 : 64'h1; rfwr <= `TRUE; end `SccI: begin rfwr <= `TRUE; case(ir[31:28]) 4'd2: res <= a==b; 4'd3: res <= a!=b; 4'd4: res <= $signed(a) < $signed(b); 4'd5: res <= $signed(a) >= $signed(b); 4'd6: res <= $signed(a) <= $signed(b); 4'd7: res <= $signed(a) > $signed(b); 4'd12: res <= a < b; 4'd13: res <= a >= b; 4'd14: res <= a <= b; 4'd15: res <= a > b; endcase end `ifdef EXT_M `MULU: if (mul_done) begin res <= produ[63:0]; rfwr <= `TRUE; end else goto(EXECUTE); `MUL: if (mul_done) begin res <= prods[63:0]; rfwr <= `TRUE; end else goto(EXECUTE); `MULSU: if (mul_done) begin res <= prodsu[63:0]; rfwr <= `TRUE; end else goto(EXECUTE); // Stay in execute state until divide is done. `DIVI,`DIVUI,`DIVSUI: if (div_done) begin res <= div_qo; rfwr <= `TRUE; end else goto(EXECUTE); `MODI,`MODUI,`MODSUI: if (div_done) begin res <= div_ro; rfwr <= `TRUE; end else goto(EXECUTE); `endif `BITFLD: begin res <= bfo; rfwr <= `TRUE; end `AND: begin res <= a & b; rfwr <= `TRUE; end `OR: begin res <= a | b; rfwr <= `TRUE; end `XOR: begin res <= a ^ b; rfwr <= `TRUE; end `QOPI: begin rfwr <= `TRUE; case(ir[10:8]) 3'd0: res <= a | b; 3'd1: res <= a + b; 3'd2: res <= a & b; 3'd3: res <= a ^ b; endcase end `Bcc0,`Bcc1,`BEQ0,`BEQ1,`BBc0,`BBc1: begin if (takb) pc <= pc + {{21{ir[31]}},ir[31:22],ir[0],2'b00}; $display("%h: br %h", opc, pc + {{21{ir[31]}},ir[31:22],ir[0],2'b00}); end `BccR: begin if (takb) pc <= c; $display("%h: br %h", opc, c); end `JAL: begin pc <= {sum[31:2],2'b00}; rfwr <= `TRUE; res <= pc; end `CALL: begin pc <= {pc[31:28],ir[31:6],2'b00}; res <= pc; rfwr <= `TRUE; $display("%h: jal %h", opc, {pc[31:28],ir[31:6],2'b00}); end `REX: begin ol <= ir[13:11]; case(ir[13:11]) 3'd0: pl <= 8'h00; 3'd1: pl <= 8'h01; default: pl <= (npl < 2) ? {5'd0,ir[13:11]} : npl; endcase if (ir[13:11]!=3'd0) pc <= tvec[ir[13:11]]; im <= ir[26:24]; end `CSR: begin case(ir[31:30]) 2'd0: begin read_csr(ir[26:16],res); rfwr <= `TRUE; end default:begin rfwr <= `TRUE; read_csr(ir[26:16],res); write_csr(ir[26:16],ir[31:30],a); end endcase end `LB,`LBU: wb_read(16'h01 << sum[3:0],sum); `LC,`LCU: wb_read(16'h03 << {sum[3:1],1'b0},sum); `LH,`LHU: wb_read(16'h0F << {sum[3:2],2'b0},sum); `LW: wb_read(16'hFF << {sum[3],3'b0},sum); `LWR: begin wb_read(16'hFF << {sum[3],3'b0},sum); sr_o <= `HIGH; end `SB: wb_write(16'h01 << sum[3:0],sum,{8{c[7:0]}}); `SC: wb_write(16'h03 << {sum[3:1],1'b0},sum,{4{c[15:0]}}); `SH: wb_write(16'h0F << {sum[3:2],2'b0},sum,{2{c[31:0]}}); `SW: wb_write(16'hFF << {sum[3],3'b0},sum,c); `SWC: begin cr_o <= `HIGH; wb_write(16'hFF << {sum[3],3'b0},sum,c); end `ifdef EXT_A `AMO: case(ir[22:21]) byt_: wb_read(16'h01 << sum[3:0],a); char: wb_read(16'h03 << {sum[3:1],1'b0},a); half: wb_read(16'h0F << {sum[3:2],2'b0},a); word: wb_read(16'hFF << {sum[3],3'b0},a); endcase `endif endcase end // MEMORY: // Finish memory cycle started in EXECUTE by waiting for an ack. Latch input // data. The data is registered here before subsequent use because it's likely // coming from a large mux. We don't want to cascade the mux and the shift // operation required to align the data into a single clock cycle. // If an AMO operation is in progress keep the cycle active. MEMORY: if (ack_i) begin goto(MEMORY_NACK); `ifdef EXT_A if (opcode!=`AMO) `endif cyc_o <= `LOW; stb_o <= `LOW; we_o <= `LOW; sel_o <= 16'h0000; sr_o <= `LOW; cr_o <= `LOW; end // Wait for ack to go back low again. Nomrally ack should go low immediately // when the bus cycle is terminated within the same clock cycle. However some // bus slaves don't put ack low until the clock edge when seeing the // terminated bus cycle. We want to ensure that a second bus cycle isn't // started until ack is low or the ack could be mistakenly accepted. MEMORY_NACK: if (~ack_i) begin goto(IFETCH); case(opcode) `R2: case(funct) `LB: begin res <= {{56{byte_in[7]}},byte_in}; rfwr <= `TRUE; end `LBU: begin res <= {{56{1'b0}},byte_in}; rfwr <= `TRUE; end `LC: begin res <= {{48{char_in[15]}},char_in}; rfwr <= `TRUE; end `LCU: begin res <= {{48{1'b0}},char_in}; rfwr <= `TRUE; end `LH: begin res <= {{32{half_in[31]}},half_in}; rfwr <= `TRUE; end `LHU: begin res <= {{32{1'b0}},half_in}; rfwr <= `TRUE; end `LW: begin res <= word_in; rfwr <= `TRUE; end `SWC: sema[0] <= rbl; endcase `LB: begin res <= {{56{byte_in[7]}},byte_in}; rfwr <= `TRUE; end `LBU: begin res <= {{56{1'b0}},byte_in}; rfwr <= `TRUE; end `LC: begin res <= {{48{char_in[15]}},char_in}; rfwr <= `TRUE; end `LCU: begin res <= {{48{1'b0}},char_in}; rfwr <= `TRUE; end `LH: begin res <= {{32{half_in[31]}},half_in}; rfwr <= `TRUE; end `LHU: begin res <= {{32{1'b0}},half_in}; rfwr <= `TRUE; end `LW: begin res <= word_in; rfwr <= `TRUE; end `SWC: sema[0] <= rbl; `ifdef EXT_A `AMO: begin goto(AMOOP); case(ir[22:21]) byt_: begin res <= {{56{byte_in[7]}},byte_in}; a <= {{56{byte_in[7]}},byte_in}; rfwr <= `TRUE; end char: begin res <= {{48{char_in[15]}},char_in}; a <= {{48{char_in[15]}},char_in}; rfwr <= `TRUE; end half: begin res <= {{32{half_in[31]}},half_in}; a <= {{32{half_in[31]}},half_in}; rfwr <= `TRUE; end word: begin res <= word_in; a <= word_in; rfwr <= `TRUE; end endcase end `endif endcase end `ifdef EXT_A AMOOP: begin goto(AMOMEM); case(funct) `AMOSWAP,`AMOSWAPI: amores <= b; `AMOADD,`AMOADDI: amores <= a + b; `AMOAND,`AMOANDI: amores <= a & b; `AMOOR,`AMOORI: amores <= a | b; `AMOXOR,`AMOXORI: amores <= a ^ b; `AMOSHL,`AMOSHLI, `AMOSHR,`AMOSHRI, `AMOASR,`AMOASRI, `AMOROL,`AMOROLI: case(ir[22:21]) half: amores <= shiftho; default: amores <= shiftwo; endcase `AMOMIN,`AMOMINI: amores <= $signed(a) < $signed(b) ? a : b; `AMOMAX,`AMOMAXI: amores <= $signed(a) > $signed(b) ? a : b; `AMOMINU,`AMOMINUI: amores <= a < b ? a : b; `AMOMAXU,`AMOMAXUI: amores <= a > b ? a : b; default: ; endcase end AMOMEM: begin goto(MEMORY); ir[5:0] <= `NOP; // <- force memory nack back to ifetch case(ir[22:21]) byt_: wb_write(16'h01 << adr_o[3:0],adr_o,{8{amores[7:0]}}); char: wb_write(16'h03 << {adr_o[3:1],1'b0},adr_o,{4{amores[15:0]}}); half: wb_write(16'h0F << {adr_o[3:2],2'b0},adr_o,{2{amores[31:0]}}); word: wb_write(16'hFF << {adr_o[3],3'b0},adr_o,amores); endcase end `endif endcase // Handle the register file update. The update is caused in a couple of // different states. There may be two updates for a single instruction. // Note that r0 is always forced to zero. A write to r0 may be needed // before it's used anywhere. if (rfwr) begin regfile[Rt] <= |Rt ? res : 64'd0; if (|Rt) $display("%s=%h",regname(Rt),res); end $display("Time: %d", $time); $display("Tick: %d Instret: %d", tick, instret); end always @(posedge tm_clk_i) if (rst_i) wctime <= 64'd1; else begin if (wctime[31:0]==WCTIME1S) begin wctime[31:0] <= 32'd1; wctime[63:32] <= wctime[63:32] + 32'd1; end else wctime[31:0] <= wctime[31:0] + 32'd1; end always @(posedge clk_i) times <= wctime; task exe_brk; input [8:0] caus; begin for (n = 0; n < 4; n = n + 1) brkstack[n+1] <= brkstack[n]; brkstack[0] <= {pc[31:2],pl,ol,im}; if (ir[15]==1'b0) im <= ir[18:16]; ol <= 3'd0; pl <= 8'h00; pc <= tvec[0]; cause <= caus; goto(IFETCH); end endtask task read_csr; input [11:0] regno; output [63:0] val; begin casez(regno) `HARTID: val <= hartid_i; `TICK: val <= tick; `CAUSE: val <= {55'd0,cause}; `SCRATCH: val <= scratch; `SEMA: val <= sema; `TVEC: val <= tvec[regno[2:0]]; `TIME: val <= times; `INSTRET: val <= instret; endcase end endtask task write_csr; input [11:0] regno; input [1:0] op; input [63:0] val; begin case(op) 2'd0: ; // read only 2'd1: casez(regno) `CAUSE: cause <= val[8:0]; `SCRATCH: scratch <= val; `SEMA: sema <= val; `TVEC: tvec[regno[2:0]] <= val; endcase 2'd2: casez(regno) `SEMA: sema <= sema | val; endcase 2'd3: casez(regno) `SEMA: sema <= sema & ~val; endcase endcase end endtask task wb_read; input [15:0] sel; input [31:0] adr; begin cyc_o <= `HIGH; stb_o <= `HIGH; sel_o <= sel; adr_o <= adr; $display("%h: l?[u] %h", opc, adr); goto(MEMORY); end endtask task wb_write; input [15:0] sel; input [31:0] adr; input [63:0] dat; begin cyc_o <= `HIGH; stb_o <= `HIGH; we_o <= `HIGH; sel_o <= sel; adr_o <= adr; dat_o <= {2{dat}}; goto(MEMORY); $display("%h: s? %h <= %h", opc, adr, dat); end endtask task goto; input [7:0] st; begin state <= st; end endtask endmodule
Go to most recent revision | Compare with Previous | Blame | View Log