import risc8_pkg::*; import alu_pkg::*; module datapath8( input logic clk, rst, interrupt, risc8_cdi.datapath cdi, input word com_rd, input wire [23:0] immr, output word com_wr, com_addr, input [15:0] mem_rd, output [15:0] mem_wr, output reg [15:0] pc, output reg [23:0] mem_addr ); // regiser file outputs word r1, r2; // immidate override word imo0, imo1, imo2; reg imo0_en, imo1_en, imo2_en, imo_en, imo_reg; reg [23:0] imm; always_comb begin imo_reg = imo0_en | imo1_en | imo2_en; imo_en = imo_reg & (cdi.imoctl == IMO_NONE); imm[7:0] = (imo_en & imo2_en) ? imo2 : immr[7:0]; imm[15:8] = (imo_en & imo1_en) ? imo1 : immr[15:8]; imm[23:16] = (imo_en & imo0_en) ? imo0 : immr[23:16]; end always_ff@(posedge clk) begin if(imo_en | rst) begin imo0_en <= 0; imo1_en <= 0; imo2_en <= 0; end else case(cdi.imoctl) IMO_0: begin imo0 <= r1; imo0_en <= 1; end IMO_1: begin imo1 <= r1; imo1_en <= 1; end IMO_2: begin imo2 <= r1; imo2_en <= 1; end endcase end // ======================== // // ALU // // ======================== // word srcA, srcB, alu_rlo, alu_rhi, alu_rhit; logic cout, cinr, cin, alu_eq, alu_gt, alu_zero, alu_sign; assign cdi.alu_comp = {alu_eq, alu_gt, alu_zero}; assign alu_sign = 0; assign cin = (cdi.aluf[0]) ? cinr : 0; // Enable carry in always_ff@(posedge clk) begin if(rst) begin cinr <= '0; alu_rhi <= '0; end else begin if((cdi.alu_op == ALU_ADD)|(cdi.alu_op == ALU_SUB)) cinr <= cout; if((cdi.alu_op == ALU_MUL)|(cdi.alu_op == ALU_DIV)|(cdi.alu_op == ALU_SL)|(cdi.alu_op == ALU_SR)) alu_rhi <= alu_rhit; end end alu#(.WORD(8)) alu0( .a(srcA), .b(srcB), .op(cdi.alu_op), .r(alu_rlo), .r_high(alu_rhit), .zero(alu_zero), .eq(alu_eq), .gt(alu_gt), .cin(cin), .cout(cout), .sign(alu_sign) // TODO: missing overflow ); // ======================== // // Interrupt // // ======================== // word interrupt_flag, intre, intrr; always_ff@(posedge clk) begin if(rst) begin interrupt_flag <= 0; intre <= 0; intrr <= 0; end else begin if(interrupt) begin interrupt_flag <= com_rd; intrr <= pc; end if(cdi.intr_ctl == INTR_WE) intre <= imm[7:0]; end end // ======================== // // Program Counter // // ======================== // logic pc_halted, intr_re, pcs, pchf; // Use immediate to branch word pc_off; // Program counter offset reg [15:0] pcn, pch, pca, pcb, pcn0; // Program Counter Previous, to add assign pchf = (cdi.pcop == PC_MEM) & ~pc_halted; always_comb begin pc_off = { 5'b0000_0, cdi.isize[0]&cdi.isize[1], cdi.isize[0]^cdi.isize[1], (~cdi.isize[1]&~cdi.isize[0])|(cdi.isize[1]&~cdi.isize[0]) }; // Adding 1 to 2bit value. intr_re = cdi.intr_ctl == INTR_RE; casez({intr_re, interrupt, rst}) 3'b000: pcb = pch; 3'b100: pcb = intrr; 3'b?10: pcb = intre; 3'b??1: pcb = 16'h0000; endcase case(cdi.pcop) PC_NONE: pcn0 = pcb; PC_MEM : pcn0 = mem_rd; PC_IMM : pcn0 = {imm[7:0], imm[15:8]}; PC_IMM2: pcn0 = {imm[15:8], imm[23:16]}; default: pcn0 = pcb; endcase pcn = (cdi.pcop == PC_IMM | cdi.pcop == PC_IMM2) ? pcn0 : pcn0 + pc_off; pca = (pchf) ? pch : pcn; pcs = intr_re | interrupt | rst; pc = (pcs) ? pcb : pca; end always_ff@(posedge clk) begin if(rst) begin pch <= 0; pc_halted <= 0; end else begin pch <= pcn; pc_halted <= pchf; end end // ======================== // // Stack // // ======================== // logic [15:0] sp, sp_add, sp_next, st_wr; // Stack pointer word st_reg, st_rd; // Stack data low byte reg logic [23:0] sp_addr; always_comb begin sp_add = (cdi.stackop == ST_ADD) ? 'h0001 : 'hffff; sp_next = sp + sp_add; sp_addr = {8'b1111_1111, (cdi.stackop == ST_ADD) ? sp_next[15:0] : sp[15:0]}; st_rd = {mem_rd[7:0]}; st_wr = (cdi.pcop == PC_IMM) ? pch : {8'h00, r1}; //if(sp[0]) begin //st_wr = {'h00, r1}; //st_rd = {mem_rd[7:0]}; //end else begin //st_wr = {st_reg, r1}; //st_rd = {mem_rd[15:8]}; //end end always_ff@(posedge clk) begin if(rst) sp <= 'h0fff; // Highest memory address else begin if(cdi.stackop != ST_SKIP & ~pc_halted) sp <= sp_next; if(sp[0]) st_reg <= r1; end end // ======================== // // Memory // // ======================== // word mem_wr_hi; // High byte of memory store always_ff@(posedge clk) begin if(rst) mem_wr_hi <= '0; else if(cdi.selo == SO_MEMH) mem_wr_hi <= r1; end assign mem_wr = (cdi.stackop == ST_SUB) ? st_wr : {mem_wr_hi, r1}; assign mem_addr = (cdi.stackop != ST_SKIP) ? sp_addr : {imm[7:0], imm[15:8], imm[23:16]}; // COM Write assign com_wr = (cdi.selo == SO_COM) ? r1 : '0; assign com_addr = (cdi.selo == SO_COM) ? imm[7:0] : '0; //assign com_addr = 8'h06; //assign com_wr = pc[7:0]; assign srcA = r1; always_comb begin case(cdi.selb) SB_REG : srcB = r2; SB_0 : srcB = 8'h00; SB_1 : srcB = 8'h01; SB_IMM : srcB = imm[7:0]; default: srcB = r2; endcase end // ======================== // // Register File // // ======================== // word reg_wr, reg_wr1, reg_wr2; reg [1:0]reg_wra; reg reg_wr_en1; reg [1:0]reg_wr_mem; always_comb begin case(cdi.selr) SR_REG : reg_wr = r2; //SR_MEML: reg_wr = (cdi.stackop == ST_ADD) ? st_rd : mem_rd[7:0]; //SR_MEMH: reg_wr = mem_rd[15:8]; SR_ALUL: reg_wr = alu_rlo; SR_ALUH: reg_wr = alu_rhi; SR_IMM : reg_wr = imm[7:0]; SR_COM : reg_wr = com_rd; SR_INTR: reg_wr = interrupt_flag; default: reg_wr = alu_rlo; endcase end always_ff@(posedge clk) begin if(rst) begin reg_wr1 <= 0; reg_wr_en1 <= 0; reg_wr_mem <= 0; end else begin reg_wr1 <= reg_wr; reg_wr_en1 <= cdi.rw_en; reg_wra <= cdi.a3; reg_wr_mem <= {cdi.selr == SR_MEML, cdi.selr == SR_MEMH}; end end always_comb begin case(reg_wr_mem) 2'b10: reg_wr2 = mem_rd[7:0]; 2'b01: reg_wr2 = mem_rd[15:8]; default: reg_wr2 = reg_wr1; endcase end reg_file reg0(.clk(clk), .rst(rst), .rd_addr1(cdi.a1), .rd_addr2(cdi.a2), .rd_data1(r1), .rd_data2(r2), .wr_addr(reg_wra), .wr_data(reg_wr2), .wr_en(reg_wr_en1) ); endmodule