- switch (op.i.op) {
- case OP_SB:
- ops->sb(state, addr, (u8) data);
- return 0;
- case OP_SH:
- ops->sh(state, addr, (u16) data);
- return 0;
- case OP_SWL:
- case OP_SWR:
- case OP_SW:
- ops->sw(state, addr, data);
- return 0;
- case OP_LB:
- return (s32) (s8) ops->lb(state, addr);
- case OP_LBU:
- return ops->lb(state, addr);
- case OP_LH:
- return (s32) (s16) ops->lh(state, addr);
- case OP_LHU:
- return ops->lh(state, addr);
- case OP_LW:
- default:
- return ops->lw(state, addr);
- }
+ unsigned int shift = addr & 0x3;
+ unsigned int mask = GENMASK(31, (shift + 1) * 8);
+ u32 old_data;
+
+ /* Align to 32 bits */
+ addr &= ~3;
+ host = (void *)((uintptr_t)host & ~3);
+
+ old_data = ops->lw(state, opcode, host, addr);
+
+ data = (data >> ((3 - shift) * 8)) | (old_data & mask);
+
+ ops->sw(state, opcode, host, addr, data);
+}
+
+static void lightrec_swr(struct lightrec_state *state,
+ const struct lightrec_mem_map_ops *ops,
+ u32 opcode, void *host, u32 addr, u32 data)
+{
+ unsigned int shift = addr & 0x3;
+ unsigned int mask = (1 << (shift * 8)) - 1;
+ u32 old_data;
+
+ /* Align to 32 bits */
+ addr &= ~3;
+ host = (void *)((uintptr_t)host & ~3);
+
+ old_data = ops->lw(state, opcode, host, addr);
+
+ data = (data << (shift * 8)) | (old_data & mask);
+
+ ops->sw(state, opcode, host, addr, data);
+}
+
+static void lightrec_swc2(struct lightrec_state *state, union code op,
+ const struct lightrec_mem_map_ops *ops,
+ void *host, u32 addr)
+{
+ u32 data = state->ops.cop2_ops.mfc(state, op.opcode, op.i.rt);
+
+ ops->sw(state, op.opcode, host, addr, data);
+}
+
+static u32 lightrec_lwl(struct lightrec_state *state,
+ const struct lightrec_mem_map_ops *ops,
+ u32 opcode, void *host, u32 addr, u32 data)
+{
+ unsigned int shift = addr & 0x3;
+ unsigned int mask = (1 << (24 - shift * 8)) - 1;
+ u32 old_data;
+
+ /* Align to 32 bits */
+ addr &= ~3;
+ host = (void *)((uintptr_t)host & ~3);
+
+ old_data = ops->lw(state, opcode, host, addr);
+
+ return (data & mask) | (old_data << (24 - shift * 8));
+}
+
+static u32 lightrec_lwr(struct lightrec_state *state,
+ const struct lightrec_mem_map_ops *ops,
+ u32 opcode, void *host, u32 addr, u32 data)
+{
+ unsigned int shift = addr & 0x3;
+ unsigned int mask = GENMASK(31, 32 - shift * 8);
+ u32 old_data;
+
+ /* Align to 32 bits */
+ addr &= ~3;
+ host = (void *)((uintptr_t)host & ~3);
+
+ old_data = ops->lw(state, opcode, host, addr);
+
+ return (data & mask) | (old_data >> (shift * 8));
+}
+
+static void lightrec_lwc2(struct lightrec_state *state, union code op,
+ const struct lightrec_mem_map_ops *ops,
+ void *host, u32 addr)
+{
+ u32 data = ops->lw(state, op.opcode, host, addr);
+
+ state->ops.cop2_ops.mtc(state, op.opcode, op.i.rt, data);