*/
static inline void rogue_set_io_sel(rogue_instr_group_io_sel *map,
+ enum rogue_alu alu,
enum rogue_io io,
rogue_ref *ref,
bool is_dst)
{
- /* Hookup feedthrough outputs to W0 using IS4. */
- if (is_dst && rogue_io_is_ft(io)) {
- *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS4)) = rogue_ref_io(io);
- io = ROGUE_IO_W0;
- }
+ /* Skip unassigned I/Os. */
+ if (rogue_ref_is_io_none(ref))
+ return;
- /* Pack source */
- if (!is_dst && io == ROGUE_IO_IS3) {
- enum rogue_io src = ROGUE_IO_S0;
- *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
- *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS3)) =
- rogue_ref_io(ROGUE_IO_FTE);
- io = src;
- }
+ /* Early skip I/Os that have already been assigned (e.g. for grouping). */
+ if (rogue_ref_is_io(ref) && rogue_ref_get_io(ref) == io)
+ return;
+
+ /* Leave source feedthroughs in place. */
+ if (!is_dst && rogue_io_is_ft(io))
+ return;
+
+ if (alu == ROGUE_ALU_MAIN) {
+ /* Hookup feedthrough outputs to W0 using IS4. */
+ if (is_dst && rogue_io_is_ft(io)) {
+ if (io == ROGUE_IO_FTE) {
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS5)) =
+ rogue_ref_io(io);
+ io = ROGUE_IO_W1;
+ } else {
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS4)) =
+ rogue_ref_io(io);
+ io = ROGUE_IO_W0;
+ }
+ }
+
+ /* Pack source */
+ if (!is_dst && io == ROGUE_IO_IS3) {
+ enum rogue_io src = ROGUE_IO_S0;
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS3)) =
+ rogue_ref_io(ROGUE_IO_FTE);
+ io = src;
+ }
+
+ /* Movc sources. */
+ if (!is_dst && rogue_io_is_dst(io)) {
+ enum rogue_io dst_ft =
+ (io == ROGUE_IO_W0 ? ROGUE_IO_IS4 : ROGUE_IO_IS5);
+ enum rogue_io src = ROGUE_IO_S0;
+ *(rogue_instr_group_io_sel_ref(map, dst_ft)) =
+ rogue_ref_io(ROGUE_IO_FTE);
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
+ io = src;
+ }
+
+ /* ADD64 fourth source */
+ if (!is_dst && io == ROGUE_IO_IS0) {
+ enum rogue_io src = ROGUE_IO_S3;
+ *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(src);
+ io = src;
+ }
- if (!is_dst && rogue_io_is_dst(io)) {
- enum rogue_io dst_ft = (io == ROGUE_IO_W0 ? ROGUE_IO_IS4 : ROGUE_IO_IS5);
- enum rogue_io src = ROGUE_IO_S0;
- *(rogue_instr_group_io_sel_ref(map, dst_ft)) = rogue_ref_io(ROGUE_IO_FTE);
- *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
- io = src;
+ /* Test source(s). */
+ /* TODO: tidy up. */
+ if (!is_dst && io == ROGUE_IO_IS1) {
+ enum rogue_io src = ROGUE_IO_S0;
+ enum rogue_io ft = ROGUE_IO_FT0;
+
+ /* Already set up. */
+ if (io != ft)
+ *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(ft);
+
+ io = src;
+ }
+
+ if (!is_dst && io == ROGUE_IO_IS2) {
+ enum rogue_io src = ROGUE_IO_S3;
+ enum rogue_io ft = ROGUE_IO_FTE;
+
+ *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) =
+ rogue_ref_io(ROGUE_IO_S3);
+
+ /* Already set up. */
+ if (io != ft)
+ *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(ft);
+
+ io = src;
+ }
+ } else if (alu == ROGUE_ALU_BITWISE) {
+ /* TODO: This is temporary because we just have BYP0, do it properly. */
+ if (is_dst)
+ io = ROGUE_IO_W0;
}
- *(rogue_instr_group_io_sel_ref(map, io)) = *ref;
+ /* Set if not already set. */
+ if (rogue_ref_is_null(rogue_instr_group_io_sel_ref(map, io)))
+ *(rogue_instr_group_io_sel_ref(map, io)) = *ref;
}
/* TODO NEXT: Abort if anything in sel map is already set. */
continue;
rogue_set_io_sel(&group->io_sel,
+ group->header.alu,
info->phase_io[phase].dst[u],
&alu->dst[u].ref,
true);
continue;
rogue_set_io_sel(&group->io_sel,
+ group->header.alu,
info->phase_io[phase].src[u],
&alu->src[u].ref,
false);
continue;
rogue_set_io_sel(&group->io_sel,
+ group->header.alu,
info->phase_io.dst[u],
&backend->dst[u].ref,
true);
continue;
rogue_set_io_sel(&group->io_sel,
+ group->header.alu,
info->phase_io.src[u],
&backend->src[u].ref,
false);
group->size.instrs[phase] = 2;
break;
+ case ROGUE_ALU_OP_ADD64:
+ group->size.instrs[phase] = 1;
+
+ if (rogue_ref_is_io_p0(&alu->src[4].ref) ||
+ rogue_alu_src_mod_is_set(alu, 0, SM(ABS)) ||
+ rogue_alu_src_mod_is_set(alu, 0, SM(NEG)) ||
+ rogue_alu_src_mod_is_set(alu, 1, SM(ABS)) ||
+ rogue_alu_src_mod_is_set(alu, 1, SM(NEG)) ||
+ rogue_alu_src_mod_is_set(alu, 2, SM(ABS)))
+ group->size.instrs[phase] = 2;
+ break;
+
default:
unreachable("Unsupported alu op.");
}
return ref->io;
}
+static inline bool rogue_ref_is_io_p0(const rogue_ref *ref)
+{
+ return rogue_ref_get_io(ref) == ROGUE_IO_P0;
+}
+
+static inline bool rogue_ref_is_io_none(const rogue_ref *ref)
+{
+ /* Special case - never assert. */
+ if (!rogue_ref_is_io(ref))
+ return false;
+
+ return rogue_ref_get_io(ref) == ROGUE_IO_NONE;
+}
+
static inline unsigned rogue_ref_get_drc_index(const rogue_ref *ref)
{
assert(rogue_ref_is_drc(ref));
ROGUE_ALU_OP_FMUL,
ROGUE_ALU_OP_FMAD,
+ ROGUE_ALU_OP_ADD64,
+
ROGUE_ALU_OP_TST,
ROGUE_ALU_OP_PCK_U8888,
ROGUE_ALU_OP_FMAX,
ROGUE_ALU_OP_FMIN,
- ROGUE_ALU_OP_SEL,
-
ROGUE_ALU_OP_COUNT,
};
return info->has_dsts;
}
-/* ALU instructions have at most 3 sources. */
-#define ROGUE_ALU_OP_MAX_SRCS 3
-#define ROGUE_ALU_OP_MAX_DSTS 2
+/* ALU instructions have at most 5 sources. */
+#define ROGUE_ALU_OP_MAX_SRCS 5
+#define ROGUE_ALU_OP_MAX_DSTS 3
typedef struct rogue_alu_io_info {
enum rogue_io dst[ROGUE_ALU_OP_MAX_DSTS];
#define ROGUE_BUILDER_DEFINE_ALU22(...)
#endif /* ROGUE_BUILDER_DEFINE_ALU22 */
+#ifndef ROGUE_BUILDER_DEFINE_ALU35
+#define ROGUE_BUILDER_DEFINE_ALU35(...)
+#endif /* ROGUE_BUILDER_DEFINE_ALU35 */
+
ROGUE_BUILDER_DEFINE_ALU11(MOV)
ROGUE_BUILDER_DEFINE_ALU11(MBYP)
ROGUE_BUILDER_DEFINE_ALU12(FMIN)
ROGUE_BUILDER_DEFINE_ALU13(FMAD)
-ROGUE_BUILDER_DEFINE_ALU13(SEL)
ROGUE_BUILDER_DEFINE_ALU22(TST)
+ROGUE_BUILDER_DEFINE_ALU35(ADD64)
+
+#undef ROGUE_BUILDER_DEFINE_ALU35
#undef ROGUE_BUILDER_DEFINE_ALU22
#undef ROGUE_BUILDER_DEFINE_ALU13
#undef ROGUE_BUILDER_DEFINE_ALU12
return rogue_build_alu(b, op, 2, dsts, 2, srcs);
}
+static inline rogue_alu_instr *rogue_build_alu35(rogue_builder *b,
+ enum rogue_alu_op op,
+ rogue_ref dst0,
+ rogue_ref dst1,
+ rogue_ref dst2,
+ rogue_ref src0,
+ rogue_ref src1,
+ rogue_ref src2,
+ rogue_ref src3,
+ rogue_ref src4)
+{
+ rogue_ref dsts[] = { dst0, dst1, dst2 };
+ rogue_ref srcs[] = { src0, src1, src2, src3, src4 };
+ return rogue_build_alu(b, op, 3, dsts, 5, srcs);
+}
+
/* TODO: Static inline in rogue.h? */
#define ROGUE_BUILDER_DEFINE_ALU11(op) \
PUBLIC \
return rogue_build_alu22(b, ROGUE_ALU_OP_##op, dst0, dst1, src0, src1); \
}
+#define ROGUE_BUILDER_DEFINE_ALU35(op) \
+ PUBLIC \
+ rogue_alu_instr *rogue_##op(rogue_builder *b, \
+ rogue_ref dst0, \
+ rogue_ref dst1, \
+ rogue_ref dst2, \
+ rogue_ref src0, \
+ rogue_ref src1, \
+ rogue_ref src2, \
+ rogue_ref src3, \
+ rogue_ref src4) \
+ { \
+ assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_dsts == 3); \
+ assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 5); \
+ return rogue_build_alu35(b, \
+ ROGUE_ALU_OP_##op, \
+ dst0, \
+ dst1, \
+ dst2, \
+ src0, \
+ src1, \
+ src2, \
+ src3, \
+ src4); \
+ }
+
#include "rogue_alu_instrs.def"
static inline rogue_backend_instr *rogue_build_backend(rogue_builder *b,
rogue_ref src0, \
rogue_ref src1);
+#define ROGUE_BUILDER_DEFINE_ALU35(op) \
+ rogue_alu_instr *rogue_##op(rogue_builder *b, \
+ rogue_ref dst0, \
+ rogue_ref dst1, \
+ rogue_ref dst2, \
+ rogue_ref src0, \
+ rogue_ref src1, \
+ rogue_ref src2, \
+ rogue_ref src3, \
+ rogue_ref src4);
+
#include "rogue_alu_instrs.def"
/* Backend instructions. */
instr_encoding->alu.sngl.pck.pck.format = PCK_FMT_U8888;
break;
+ case ROGUE_ALU_OP_ADD64:
+ instr_encoding->alu.op = ALUOP_INT32_64;
+
+ instr_encoding->alu.int32_64.int32_64_op = INT32_64_OP_ADD64_NMX;
+ instr_encoding->alu.int32_64.s2neg =
+ rogue_alu_src_mod_is_set(alu, 2, SM(NEG));
+ instr_encoding->alu.int32_64.s = 0;
+
+ if (instr_size == 2) {
+ instr_encoding->alu.int32_64.ext = 1;
+ instr_encoding->alu.int32_64.s2abs =
+ rogue_alu_src_mod_is_set(alu, 2, SM(ABS));
+ instr_encoding->alu.int32_64.s1abs =
+ rogue_alu_src_mod_is_set(alu, 1, SM(ABS));
+ instr_encoding->alu.int32_64.s0abs =
+ rogue_alu_src_mod_is_set(alu, 0, SM(ABS));
+ instr_encoding->alu.int32_64.s0neg =
+ rogue_alu_src_mod_is_set(alu, 0, SM(NEG));
+ instr_encoding->alu.int32_64.s1neg =
+ rogue_alu_src_mod_is_set(alu, 1, SM(NEG));
+ instr_encoding->alu.int32_64.cin =
+ rogue_ref_is_io_p0(&alu->src[4].ref);
+ }
+ break;
+
default:
unreachable("Unsupported alu op.");
}
},
/* TODO: Implement */
[ROGUE_ALU_OP_TST] = { .str = "tst", .num_dsts = 2, .num_srcs = 2, },
+ [ROGUE_ALU_OP_ADD64] = { .str = "add64", .num_dsts = 3, .num_srcs = 5,
+ .supported_phases = P(0),
+ .phase_io[PH(0)] = { .dst[0] = IO(FT0), .dst[1] = IO(FTE), .src[0] = IO(S0), .src[1] = IO(S1), .src[2] = IO(S2), .src[3] = IO(IS0), },
+ .supported_src_mods = {
+ [0] = SM(ABS) | SM(NEG),
+ [1] = SM(ABS) | SM(NEG),
+ [2] = SM(ABS) | SM(NEG),
+ [3] = SM(ABS) | SM(NEG),
+ },
+ .supported_dst_types = { [0] = T(REG) | T(REGARRAY), [1] = T(REG) | T(REGARRAY) | T(IO), [2] = T(IO) },
+ .supported_src_types = {
+ [0] = T(REG) | T(REGARRAY),
+ [1] = T(REG) | T(REGARRAY),
+ [2] = T(REG) | T(REGARRAY),
+ [3] = T(REG) | T(REGARRAY)| T(IO),
+ [4] = T(IO),
+ },
+ },
[ROGUE_ALU_OP_PCK_U8888] = { .str = "pck.u8888", .num_dsts = 1, .num_srcs = 1,
.supported_phases = P(2_PCK),
.phase_io[PH(2_PCK)] = { .dst[0] = IO(FT2), .src[0] = IO(IS3), },
[ROGUE_ALU_OP_FMAX] = { .str = "fmax", .num_dsts = 1, .num_srcs = 2, }, /* TODO */
[ROGUE_ALU_OP_FMIN] = { .str = "fmin", .num_dsts = 1, .num_srcs = 2, }, /* TODO */
- [ROGUE_ALU_OP_SEL] = { .str = "sel", .num_dsts = 1, .num_srcs = 3, }, /* TODO */
};
#undef B
#undef T
static_assert(sizeof(rogue_alu_mov_encoding) == 2,
"sizeof(rogue_alu_mov_encoding) != 2");
+typedef struct rogue_alu_int32_64_encoding {
+ /* Byte 0 */
+ struct {
+ unsigned int32_64_op : 2;
+ unsigned s2neg : 1;
+ unsigned s : 1;
+ unsigned ext : 1;
+ unsigned : 3;
+ } PACKED;
+
+ /* Byte 1 */
+ struct {
+ unsigned s2abs : 1;
+ unsigned s1abs : 1;
+ unsigned s0abs : 1;
+ unsigned : 1;
+ unsigned s0neg : 1;
+ unsigned s1neg : 1;
+ unsigned cin : 1;
+ unsigned : 1;
+ } PACKED;
+} PACKED rogue_alu_int32_64_encoding;
+static_assert(sizeof(rogue_alu_int32_64_encoding) == 2,
+ "sizeof(rogue_alu_int32_64_encoding) != 2");
+
+enum int32_64_op {
+ INT32_64_OP_ADD6432 = 0b00,
+ /* No multiply or extension, only valid when s=0. */
+ INT32_64_OP_ADD64_NMX = 0b01,
+ INT32_64_OP_MADD32 = 0b10,
+ INT32_64_OP_MADD64 = 0b11,
+};
typedef struct rogue_alu_instr_encoding {
union {
/* Byte 0 */
rogue_alu_fmad_encoding fmad;
rogue_alu_tst_encoding tst;
rogue_alu_mov_encoding mov;
+ rogue_alu_int32_64_encoding int32_64;
} PACKED;
} PACKED rogue_alu_instr_encoding;
static_assert(sizeof(rogue_alu_instr_encoding) == 2,