Add jump encodings to RISC-V.
Fix a bug in gen_encoding.py when dealing with non-polymorphic instructions where the type variable is None in Python, VOID in Rust.
This commit is contained in:
@@ -75,7 +75,8 @@ ebb0:
|
|||||||
[-,%x7] v140 = iconst.i32 0x12345000 ; bin: 123453b7
|
[-,%x7] v140 = iconst.i32 0x12345000 ; bin: 123453b7
|
||||||
[-,%x16] v141 = iconst.i32 0xffffffff_fedcb000 ; bin: fedcb837
|
[-,%x16] v141 = iconst.i32 0xffffffff_fedcb000 ; bin: fedcb837
|
||||||
|
|
||||||
jump ebb1
|
brz v1, ebb3
|
||||||
|
fallthrough ebb1
|
||||||
|
|
||||||
; Control Transfer Instructions
|
; Control Transfer Instructions
|
||||||
|
|
||||||
@@ -110,10 +111,15 @@ ebb1:
|
|||||||
fallthrough ebb2
|
fallthrough ebb2
|
||||||
|
|
||||||
ebb2:
|
ebb2:
|
||||||
; beq x, %x0
|
; jal %x0, 0x00000
|
||||||
brz v1, ebb2 ; bin: 00050063
|
jump ebb2 ; bin: 0000006f
|
||||||
; bne x, %x0
|
|
||||||
brnz v1, ebb2 ; bin: fe051ee3
|
|
||||||
|
|
||||||
return
|
ebb3:
|
||||||
|
; beq x, %x0
|
||||||
|
brz v1, ebb3 ; bin: 00050063
|
||||||
|
; bne x, %x0
|
||||||
|
brnz v1, ebb3 ; bin: fe051ee3
|
||||||
|
|
||||||
|
; jal %x0, 0x1ffff4
|
||||||
|
jump ebb2 ; bin: ff5ff06f
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ class Level2Table(object):
|
|||||||
level2_doc[self.hash_table_offset].append(
|
level2_doc[self.hash_table_offset].append(
|
||||||
'{:06x}: {}, {} entries'.format(
|
'{:06x}: {}, {} entries'.format(
|
||||||
self.hash_table_offset,
|
self.hash_table_offset,
|
||||||
self.ty.name,
|
self.ty,
|
||||||
self.hash_table_len))
|
self.hash_table_len))
|
||||||
level2_hashtables.extend(hash_table)
|
level2_hashtables.extend(hash_table)
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ def emit_level1_hashtable(cpumode, level1, offt, fmt):
|
|||||||
"""
|
"""
|
||||||
def hash_func(level2):
|
def hash_func(level2):
|
||||||
# type: (Level2Table) -> int
|
# type: (Level2Table) -> int
|
||||||
return level2.ty.number
|
return level2.ty.number if level2.ty is not None else 0
|
||||||
hash_table = compute_quadratic(level1.tables.values(), hash_func)
|
hash_table = compute_quadratic(level1.tables.values(), hash_func)
|
||||||
|
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
@@ -415,11 +415,12 @@ def emit_level1_hashtable(cpumode, level1, offt, fmt):
|
|||||||
if level2:
|
if level2:
|
||||||
l2l = int(math.log(level2.hash_table_len, 2))
|
l2l = int(math.log(level2.hash_table_len, 2))
|
||||||
assert l2l > 0, "Hash table too small"
|
assert l2l > 0, "Hash table too small"
|
||||||
|
tyname = level2.ty.name if level2.ty is not None else 'void'
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'Level1Entry ' +
|
'Level1Entry ' +
|
||||||
'{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
|
'{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
|
||||||
.format(
|
.format(
|
||||||
level2.ty.name.upper(),
|
tyname.upper(),
|
||||||
l2l,
|
l2l,
|
||||||
level2.hash_table_offset))
|
level2.hash_table_offset))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from __future__ import absolute_import
|
|||||||
from base import instructions as base
|
from base import instructions as base
|
||||||
from base.immediates import intcc
|
from base.immediates import intcc
|
||||||
from .defs import RV32, RV64
|
from .defs import RV32, RV64
|
||||||
from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH
|
from .recipes import OPIMM, OPIMM32, OP, OP32, LUI, BRANCH, JALR, JAL
|
||||||
from .recipes import JALR, R, Rshamt, Ricmp, I, Iicmp, Iret, U, SB, SBzero
|
from .recipes import R, Rshamt, Ricmp, I, Iicmp, Iret, U, UJ, SB, SBzero
|
||||||
from .settings import use_m
|
from .settings import use_m
|
||||||
from cdsl.ast import Var
|
from cdsl.ast import Var
|
||||||
|
|
||||||
@@ -81,6 +81,10 @@ RV64.enc(base.imul.i32, R, OP32(0b000, 0b0000001), isap=use_m)
|
|||||||
|
|
||||||
# Control flow.
|
# Control flow.
|
||||||
|
|
||||||
|
# Unconditional branches.
|
||||||
|
RV32.enc(base.jump, UJ, JAL())
|
||||||
|
RV64.enc(base.jump, UJ, JAL())
|
||||||
|
|
||||||
# Conditional branches.
|
# Conditional branches.
|
||||||
for cond, f3 in [
|
for cond, f3 in [
|
||||||
(intcc.eq, 0b000),
|
(intcc.eq, 0b000),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from __future__ import absolute_import
|
|||||||
from cdsl.isa import EncRecipe
|
from cdsl.isa import EncRecipe
|
||||||
from cdsl.predicates import IsSignedInt
|
from cdsl.predicates import IsSignedInt
|
||||||
from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm
|
from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm
|
||||||
from base.formats import UnaryImm, BranchIcmp, Branch
|
from base.formats import UnaryImm, BranchIcmp, Branch, Jump
|
||||||
from .registers import GPR
|
from .registers import GPR
|
||||||
|
|
||||||
# The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit
|
# The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit
|
||||||
@@ -47,6 +47,11 @@ def JALR(funct3=0):
|
|||||||
return 0b11001 | (funct3 << 5)
|
return 0b11001 | (funct3 << 5)
|
||||||
|
|
||||||
|
|
||||||
|
def JAL():
|
||||||
|
# type: () -> int
|
||||||
|
return 0b11011
|
||||||
|
|
||||||
|
|
||||||
def OPIMM(funct3, funct7=0):
|
def OPIMM(funct3, funct7=0):
|
||||||
# type: (int, int) -> int
|
# type: (int, int) -> int
|
||||||
assert funct3 <= 0b111
|
assert funct3 <= 0b111
|
||||||
@@ -112,6 +117,9 @@ U = EncRecipe(
|
|||||||
'U', UnaryImm, size=4, ins=(), outs=GPR,
|
'U', UnaryImm, size=4, ins=(), outs=GPR,
|
||||||
instp=IsSignedInt(UnaryImm.imm, 32, 12))
|
instp=IsSignedInt(UnaryImm.imm, 32, 12))
|
||||||
|
|
||||||
|
# UJ-type unconditional branch instructions.
|
||||||
|
UJ = EncRecipe('UJ', Jump, size=4, ins=(), outs=(), branch_range=(0, 21))
|
||||||
|
|
||||||
# SB-type branch instructions.
|
# SB-type branch instructions.
|
||||||
# TODO: These instructions have a +/- 4 KB branch range. How to encode that
|
# TODO: These instructions have a +/- 4 KB branch range. How to encode that
|
||||||
# constraint?
|
# constraint?
|
||||||
|
|||||||
@@ -279,3 +279,42 @@ fn recipe_sbzero<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut
|
|||||||
panic!("Expected Branch format: {:?}", func.dfg[inst]);
|
panic!("Expected Branch format: {:?}", func.dfg[inst]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// UJ-type jump instructions.
|
||||||
|
///
|
||||||
|
/// 31 11 6
|
||||||
|
/// imm rd opcode
|
||||||
|
/// 12 7 0
|
||||||
|
///
|
||||||
|
/// Encoding bits: `opcode[6:2]`
|
||||||
|
fn put_uj<CS: CodeSink + ?Sized>(bits: u16, imm: i64, rd: RegUnit, sink: &mut CS) {
|
||||||
|
let bits = bits as u32;
|
||||||
|
let opcode5 = bits & 0x1f;
|
||||||
|
let rd = rd as u32 & 0x1f;
|
||||||
|
|
||||||
|
assert!(is_signed_int(imm, 21, 1), "UJ out of range {:#x}", imm);
|
||||||
|
let imm = imm as u32;
|
||||||
|
|
||||||
|
// 0-6: opcode
|
||||||
|
let mut i = 0x3;
|
||||||
|
i |= opcode5 << 2;
|
||||||
|
i |= rd << 7;
|
||||||
|
|
||||||
|
// The displacement is completely hashed up.
|
||||||
|
i |= imm & 0xff000;
|
||||||
|
i |= ((imm >> 11) & 0x1) << 20;
|
||||||
|
i |= ((imm >> 1) & 0x3ff) << 21;
|
||||||
|
i |= ((imm >> 20) & 0x1) << 31;
|
||||||
|
|
||||||
|
sink.put4(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recipe_uj<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
||||||
|
if let InstructionData::Jump { destination, .. } = func.dfg[inst] {
|
||||||
|
let dest = func.offsets[destination] as i64;
|
||||||
|
let disp = dest - sink.offset() as i64;
|
||||||
|
put_uj(func.encodings[inst].bits(), disp, 0, sink);
|
||||||
|
} else {
|
||||||
|
panic!("Expected Jump format: {:?}", func.dfg[inst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user