Skip to content

Commit

Permalink
Enhance the jump instruction (use RRO like call)
Browse files Browse the repository at this point in the history
  • Loading branch information
semahawk committed Apr 6, 2019
1 parent 99627a5 commit 5ef285f
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 35 deletions.
26 changes: 19 additions & 7 deletions docs/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,21 +289,27 @@ shiftr <reg>, <imm>

Will effectively perform `reg = reg >> imm`. No side effects (at the moment).

### jump (immediate address)
### jump (using a register)

Format: RRO

Opcode: `7'h4`

```
jump <imm>
jump <reg> [, off <imm>]
```

This instruction will set register `pc` to the specified `<imm>` value.

### jump (using a register)
This instruction will set register `pc` to the value taken of `<reg> + <imm>` (`<imm>` can be negative, so backward jumps are possible)

```
jump <reg>
jump <imm>
```

This instruction will set register `pc` to the value taken from register `<reg>`.
The assembler also supports this syntactic sugar syntax (so you can eg. jump to a label etc). When this is used the assembler will calculate the proper offset and implicitly use the `pc` register, turning it into this call:

```
jump pc, off <offset from current pc>
```

### call (register, offset)

Expand All @@ -317,6 +323,12 @@ call <reg> off <imm>

This instruction will effectively decrement the `sp` register by 8, issue a bus write cycle to write value of `pc + 8` into address `sp`, and make a jump to `reg + imm`.

```
call <imm>
```

The assembler also supports this syntactic sugar syntax. In this case, just like in the `jump` case, the assembler will implicitly use the `pc` register, and calculate the correct offset.

### return

Format: I
Expand Down
16 changes: 7 additions & 9 deletions rtl/cpu.v
Original file line number Diff line number Diff line change
Expand Up @@ -401,16 +401,14 @@ module cpu (
end
end // `OP_LOAD
`OP_JUMP: begin
if (instr_format == `INSTR_FORMAT_I) begin
// $display("%g: jump 0h%01x", $time, instr_i_imm);

cpu_regs_in <= instr_i_imm;
end else if (instr_format == `INSTR_FORMAT_RIS) begin
// $display("%g: jump r%1d (h'%x)", $time, instr_ris_reg, instr_dst_reg_val);

cpu_regs_in <= instr_dst_reg_val;
end
if (instr_rro_off[40] == 1'b1)
$display("%g: jump r%1d (h'%x) off -0x%1x", $time,
instr_rro_dst, instr_dst_reg_val, ~instr_rro_off + 1);
else
$display("%g: jump r%1d (h'%x) off 0x%1x", $time,
instr_rro_dst, instr_dst_reg_val, instr_rro_off);

cpu_regs_in <= $signed(instr_dst_reg_val) + $signed(instr_rro_off);
cpu_regs_write <= 1'b1;
cpu_regs_id <= `REG_PC;
cpu_state <= `STATE_REG_WRITE;
Expand Down
17 changes: 10 additions & 7 deletions rtl/rom.v
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,16 @@ module rom (
16'h0008: r_dat_o = 64'h1687800000008000; // add r30, 0x400 0
16'h0010: r_dat_o = 64'h0286c01002000010; // set r27, 0x80100000 shl 16
16'h0018: r_dat_o = 64'h02804000000002a0; // set r1, 0x15
16'h0020: r_dat_o = 64'h1a07c00000000008; // call r31 off 8
16'h0028: r_dat_o = 64'h0c87c00000000200; // sub r31, 16
16'h0030: r_dat_o = 64'h0407360000000000; // load r28, r27
16'h0038: r_dat_o = 64'h0a87000000000000; // testbit r28, 0
16'h0040: r_dat_o = 64'h0948800000000030; // jump.nz 0x800000000030
16'h0048: r_dat_o = 64'h0606c20000000010; // store r1, r27 off 16
16'h0050: r_dat_o = 64'h1d00000000000000; // return
16'h0020: r_dat_o = 64'h1a07c00000000020; // call r31 off 32
16'h0028: r_dat_o = 64'h028680000004e200; // set r26, 0x2710
16'h0030: r_dat_o = 64'h0c86800000000020; // sub r26, 1
16'h0038: r_dat_o = 64'h084fc1fffffffff0; // jump.nz r31 off -16
16'h0040: r_dat_o = 64'hff00000000000000; // halt
16'h0048: r_dat_o = 64'h0407360000000000; // load r28, r27
16'h0050: r_dat_o = 64'h0a87000000000000; // testbit r28, 0
16'h0058: r_dat_o = 64'h084fc1ffffffffe8; // jump.nz r31 off -24
16'h0060: r_dat_o = 64'h0606c20000000010; // store r1, r27 off 16
16'h0068: r_dat_o = 64'h1d00000000000000; // return
default: r_dat_o = 64'hfe00000000000000; // halt by default
endcase
end
Expand Down
4 changes: 2 additions & 2 deletions tools/asm.lark
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
start: instr*
instr: /nop/ ["." cond] -> nop
| /jump/ ["." cond] expr -> jump_i
| /jump/ ["." cond] reg -> jump_ris
| /jump/ ["." cond] expr -> jump_expr
| /jump/ ["." cond] reg ["off" expr] -> jump_rro
| /call/ ["." cond] expr -> call_expr
| /call/ ["." cond] reg ["off" expr] -> call_rro
| /return/ ["." cond] -> return_
Expand Down
25 changes: 15 additions & 10 deletions tools/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,8 @@ def __init__(self, mnem, opcode, format, cond, **kwargs):
super().__init__(mnem, opcode, format, cond, **kwargs)

def __str__(self):
if self.format == Format.I:
return "jump{} 0x{:x}".format(self.cond, self.imm)
elif self.format == Format.RIS:
return "jump{} r{}".format(self.cond, self.dst_reg)
if self.format == Format.RRO:
return "jump{} r{} {}".format(self.cond, self.dst_reg, self.off)

class Call(Instr):
def __init__(self, mnem, opcode, format, cond, **kwargs):
Expand Down Expand Up @@ -339,20 +337,27 @@ def halt(self, op, cond):
self.inc_pc()
return Halt("halt", 0x7f, Cond(cond))

def jump_i(self, op, cond, imm):
def jump_expr(self, op, cond, imm):
self.inc_pc()
return Jump("jump", 0x04, Format.I, Cond(cond), imm = imm)
# this offset from pc must be calculated after it's been incremented
# since when the instruction is executed by the CPU, the pc register
# points to the next instruction, not current
offset_from_pc = imm - self.current_pc

return Jump("jump", 0x04, Format.RRO, Cond(cond),
dst_reg = 31, src_reg = 0x0, off = Off(offset_from_pc))

def jump_ris(self, op, cond, reg):
def jump_rro(self, op, cond, reg, off):
self.inc_pc()
return Jump("jump", 0x04, Format.RIS, Cond(cond), dst_reg = reg)
return Jump("jump", 0x04, Format.RRO, Cond(cond),
dst_reg = reg, src_reg = 0x0, off = Off(off))

def call_expr(self, op, cond, special_imm):
def call_expr(self, op, cond, imm):
self.inc_pc()
# this offset from pc must be calculated after it's been incremented
# since when the instruction is executed by the CPU, the pc register
# points to the next instruction, not current
offset_from_pc = special_imm - self.current_pc
offset_from_pc = imm - self.current_pc

return Call("call", 0x0d, Format.RRO, Cond(cond),
dst_reg = 31, src_reg = 0x0, off = Off(offset_from_pc))
Expand Down

0 comments on commit 5ef285f

Please sign in to comment.