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:
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)
);