cpu32

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 0b4cfa6755e71fc2232cd42fdfd9976e9d0dbe6e
parent c6bc728efd877432ea8ec9236167eb89a32caf88
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun,  5 Feb 2012 08:30:16 -0800

cpu32: indirect branch instructions

- add support in the assembler for indirect branch instructions (asm/dis)
- add support in cpu32.v
- update isa.txt to make them core instructions (can't return from function calls otherwise...)

Diffstat:
Ma32.c | 26++++++++++++++++++++++++--
Misa.txt | 18++++++++++--------
Mverilog/cpu32.v | 24+++++++++++++++---------
3 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/a32.c b/a32.c @@ -406,6 +406,24 @@ void disassemble(char *buf, unsigned pc, unsigned instr) { case 0x4B: sprintf(buf, "BL 0x%08x", (pc + s16)); break; + case 0x51: + sprintf(buf, "BZ %s, %s", REG(a), REG(b)); + break; + case 0x52: + sprintf(buf, "BNZ %s, %s", REG(a), REG(b)); + break; + case 0x53: + sprintf(buf, "B %s", REG(b)); + break; + case 0x59: + sprintf(buf, "BLZ %s, %s", REG(a), REG(b)); + break; + case 0x5A: + sprintf(buf, "BLNZ %s, %s", REG(a), REG(b)); + break; + case 0x5B: + sprintf(buf, "BL %s", REG(b)); + break; default: if (op == 0) { sprintf(buf, "%-5s%s, %s, %s", @@ -469,7 +487,9 @@ void assemble_line(int n, unsigned *tok, unsigned *num, char **str) { } else { instr = 0x4B0F0000; } - if (tok[1] == tSTRING) { + if (is_register(tok[1])) { + emit(instr | 0x10000000 | TO_B(to_register(tok[1]))); + } else if (tok[1] == tSTRING) { emit(instr); uselabel(str[1], PC - 1, 16); } else if ((tok[1] == tNUMBER) || (tok[1] == tDOT)) { @@ -492,7 +512,9 @@ void assemble_line(int n, unsigned *tok, unsigned *num, char **str) { expect_register(tok[1]); expect(tCOMMA,tok[2]); instr |= TO_A(to_register(tok[1])); - if (tok[3] == tSTRING) { + if (is_register(tok[3])) { + emit(instr | 0x10000000 | TO_B(to_register(tok[3]))); + } else if (tok[3] == tSTRING) { emit(instr); uselabel(str[3], PC - 1, 16); } else if ((tok[3] == tNUMBER) || (tok[3] == tDOT)) { diff --git a/isa.txt b/isa.txt @@ -24,16 +24,16 @@ Core Instruction Set 4A BLNZ Ra, rel16 if Ra != 0: R15 = PC + 4, PC += I 4B BL rel16 R15 = PC + 4, PC += I +51 BZ Ra, Rb if Ra == 0: PC = Rb +52 BNZ Ra, Rb if Ra != 0: PC = Rb +53 B Rb PC = Rb +59 BNZ Ra, Rb if Ra == 0: R15 = PC, PC = Rb +5A BLNZ Ra, Rb if Ra != 0: R15 = PC, PC = Rb +5B BL Rb R15 = PC, PC = Rb + Extended Instruction Set ------------------------ -51 BZ Ra, [Rb] if Ra == 0: PC = Rb -52 BNZ Ra, [Rb] if Ra != 0: PC = Rb -53 B [Rb] PC = Rb -59 BNZ Ra, [Rb] if Ra == 0: R15 = PC, PC = Rb -5A BLNZ Ra, [Rb] if Ra != 0: R15 = PC, PC = Rb -5B BL [Rb] R15 = PC, PC = Rb - 60 J rel24 PC = PC + I 68 JL rel24 R15 = PC + 4, PC = PC + I @@ -63,4 +63,6 @@ Open Issues - should ALU IMM16 be signed? If so, how do we load unsigned data? - consider dropping REV in favor of MOVU or MOVS? - figure out func field coding for variant LW/SW instructions - +- syntax for conditional branches is confusing +- consider allowing B [Rx] as well as B Rx? +- allow # in front of constants diff --git a/verilog/cpu32.v b/verilog/cpu32.v @@ -29,13 +29,14 @@ assign opselb = ir[19:16]; assign opseld = ir[15:12]; assign opimm16 = ir[15:0]; -wire ctl_regs_we; // 1 = write back to register file -wire ctl_d_or_b; // 0 = write to R[opseld], 1 = R[opselb] -wire ctl_branch; // 1 = immediate branch +wire ctl_regs_we; // 1 = write back to register file +wire ctl_d_or_b; // 0 = write to R[opseld], 1 = R[opselb] +wire ctl_branch; // 1 = direct branch +wire ctl_branch_ind; // 1 = indirect branch +wire ctl_link_bit; // 1 if the link bit is set (only for branches) wire ctl_ram_op; -wire ctl_imm16; // 0 = bdata, 1 = imm16 -> alu right +wire ctl_imm16; // 0 = bdata, 1 = imm16 -> alu right wire ctl_adata_zero; -wire ctl_link_bit; // 1 if this is a branch instruction w/ link wire [3:0] ctl_alu_func; @@ -43,7 +44,8 @@ wire [3:0] ctl_alu_func; assign ctl_regs_we = (opcode[3:1] == 0) || (opcode == 2) || - (ctl_branch && ctl_link_bit); + (ctl_branch && ctl_link_bit) || + (ctl_branch_ind && ctl_link_bit); assign ctl_d_or_b = ((opcode == 1) || (opcode == 2) || (opcode == 4)); assign ctl_ram_rd = (opcode == 2); assign ctl_ram_we = (opcode == 3); @@ -57,6 +59,8 @@ assign ctl_adata_zero = (adata == 32'h0); // unconditional branches set both condition bits assign ctl_branch = (opcode == 4) & ((opfunc[0] & ctl_adata_zero) || (opfunc[1] & (!ctl_adata_zero))); +assign ctl_branch_ind = (opcode == 5) & + ((opfunc[0] & ctl_adata_zero) || (opfunc[1] & (!ctl_adata_zero))); register #(32) PC ( .clk(clk), @@ -87,10 +91,12 @@ assign pc_plus_4 = (pc + 32'h4); wire S; assign S = opimm16[15]; -mux2 #(32) pc_source( - .sel(ctl_branch), +mux4 #(32) pc_source( + .sel({ctl_branch_ind,ctl_branch}), .in0(pc_plus_4), - .in1( pc + {S,S,S,S,S,S,S,S,S,S,S,S,S,S,opimm16,2'h0} ), + .in1(pc + {S,S,S,S,S,S,S,S,S,S,S,S,S,S,opimm16,2'h0} ), + .in2(bdata), + .in3(bdata), .out(next_pc) );