Previously, ast transformations were performed informally as ad-hoc modifications to the generated C source code. In this commit, the same transformations are performed by rewriting the ast prior to code generation time. The most significant new transformer is transform_assignment_list. This transforms assignments such as: a, b, c = f(b, c, d) To: a = f(&b, &c, d) The former syntax is used frequently in the manual's description of FPU-related instructions.
93 lines
2.7 KiB
C
93 lines
2.7 KiB
C
#pragma once
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "status_bits.h"
|
|
|
|
#define SR__RB (1 << 29)
|
|
#define SR__MD (1 << 30)
|
|
|
|
#define BANK(sr) (((sr) & SR__RB) && ((sr) & SR__MD))
|
|
#define REGN(sr, x) (((x) & (1 << 3)) ? (x) : ((x) ^ (BANK(sr) << 4)))
|
|
#define REG(state, x) ((state)->general_register[REGN((state)->sr.value, (x))])
|
|
#define REGN_BANK(sr, x) (((x) & (1 << 3)) ? (x) : ((x) ^ ((!BANK(sr)) << 4)))
|
|
#define REG_BANK(state, x) ((state)->general_register[REGN_BANK((state)->sr.value, (x))])
|
|
|
|
static_assert(REGN(0, 0 ) == 0 );
|
|
static_assert(REGN(0, 7 ) == 7 );
|
|
static_assert(REGN(0, 8 ) == 8 );
|
|
static_assert(REGN(0, 15) == 15);
|
|
static_assert(REGN(SR__MD | SR__RB, 0 ) == 16);
|
|
static_assert(REGN(SR__MD | SR__RB, 7 ) == 23);
|
|
static_assert(REGN(SR__MD | SR__RB, 8 ) == 8 );
|
|
static_assert(REGN(SR__MD | SR__RB, 15) == 15);
|
|
|
|
static_assert(REGN_BANK(0, 0 ) == 16);
|
|
static_assert(REGN_BANK(0, 7 ) == 23);
|
|
static_assert(REGN_BANK(0, 8 ) == 8 );
|
|
static_assert(REGN_BANK(0, 15) == 15);
|
|
static_assert(REGN_BANK(SR__MD | SR__RB, 0 ) == 0 );
|
|
static_assert(REGN_BANK(SR__MD | SR__RB, 7 ) == 7 );
|
|
static_assert(REGN_BANK(SR__MD | SR__RB, 8 ) == 8 );
|
|
static_assert(REGN_BANK(SR__MD | SR__RB, 15) == 15);
|
|
|
|
union floating_point_registers {
|
|
uint32_t fr[32];
|
|
uint32_t fp[16][2];
|
|
uint64_t dr[16];
|
|
uint32_t fv[8][4];
|
|
uint32_t fm[2][16];
|
|
};
|
|
|
|
static_assert((sizeof (union floating_point_registers)) == 32 * 4);
|
|
|
|
#define FR_N(state, x) ((x) ^ ((state)->fpscr.fr << 4))
|
|
#define FR_(state, x) ((state)->floating_point_register.fr[FR_N(state, x)])
|
|
#define FP_N(state, x) ((x) ^ ((state)->fpscr.fr << 3))
|
|
#define FP_(state, x) ((state)->floating_point_register.fp[FP_N(state, x)])
|
|
#define DR2_N(state, x) ((x) ^ ((state)->fpscr.fr << 3))
|
|
#define DR2_(state, x) ((state)->floating_point_register.dr[DR2_N(state, x)])
|
|
#define XD2_N(state, x) ((x) ^ ((!(state)->fpscr.fr) << 3))
|
|
#define XD2_(state, x) ((state)->floating_point_register.dr[XD2_N(state, x)])
|
|
#define FV4_N(state, x) ((x) ^ ((state)->fpscr.fr << 2))
|
|
#define FV4_(state, x) ((state)->floating_point_register.dr[FV4_N(state, x)])
|
|
#define XMTRX_N(state) (!(state)->fpscr.fr)
|
|
#define XMTRX(state) ((state)->floating_point_register.fm[XMTRX_N(state)])
|
|
|
|
struct architectural_state {
|
|
uint32_t general_register[24];
|
|
|
|
// system_register
|
|
uint32_t mach;
|
|
uint32_t macl;
|
|
uint32_t pr[3];
|
|
uint32_t pc[3];
|
|
union {
|
|
struct fpscr_bits bits;
|
|
uint32_t value;
|
|
} fpscr;
|
|
uint32_t fpul;
|
|
//
|
|
|
|
// control_register
|
|
union {
|
|
struct sr_bits bits;
|
|
uint32_t value;
|
|
} sr;
|
|
uint32_t ssr;
|
|
uint32_t spc;
|
|
uint32_t gbr;
|
|
uint32_t vbr;
|
|
uint32_t sgr;
|
|
uint32_t dbr;
|
|
//
|
|
|
|
union floating_point_registers floating_point_register;
|
|
|
|
bool is_delay_slot;
|
|
};
|
|
|
|
//
|