| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- 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
|