| version 1.1, 2003/12/08 00:55:31 | version 1.5, 2005/02/08 09:57:26 | 
| Line 1 | Line 1 | 
 | #include        "compiler.h" |  | 
 | #include        "memory.h" |  | 
 | #include        "egcmem.h" |  | 
 | #include        "pccore.h" |  | 
 | #include        "iocore.h" |  | 
 | #include        "vram.h" |  | 
 |  |  | 
|  | #error  move: /mem/memegc.c | 
| // C版EGCのみ ROPの回数を記録する |  | 
| // #define              LOG_EGCROP |  | 
|  |  | 
|  |  | 
| enum { |  | 
| EGCADDR_L               = 0, |  | 
| EGCADDR_H               = 1 |  | 
| }; |  | 
| #define EGCADDR(a)      (a) |  | 
|  |  | 
|  |  | 
|  |  | 
| static  EGCQUAD         egc_src; |  | 
| static  EGCQUAD         data; |  | 
|  |  | 
| static const UINT planead[4] = {VRAM_B, VRAM_R, VRAM_G, VRAM_E}; |  | 
|  |  | 
|  |  | 
| static const BYTE bytemask_u0[64] =             // dir:right by startbit + (len-1)*8 |  | 
| {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, |  | 
| 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, |  | 
| 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x03, 0x01, |  | 
| 0xf0, 0x78, 0x3c, 0x1e, 0x0f, 0x07, 0x03, 0x01, |  | 
| 0xf8, 0x7c, 0x3e, 0x1f, 0x0f, 0x07, 0x03, 0x01, |  | 
| 0xfc, 0x7e, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, |  | 
| 0xfe, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, |  | 
| 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; |  | 
|  |  | 
| static const BYTE bytemask_u1[8] =              // dir:right by length |  | 
| {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; |  | 
|  |  | 
| static const BYTE bytemask_d0[64] =             // dir:left by startbit + (len-1)*8 |  | 
| {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, |  | 
| 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, |  | 
| 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xc0, 0x80, |  | 
| 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0xe0, 0xc0, 0x80, |  | 
| 0x1f, 0x3e, 0x7c, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, |  | 
| 0x3f, 0x7e, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, |  | 
| 0x7f, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, |  | 
| 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; |  | 
|  |  | 
| static const BYTE bytemask_d1[8] =              // dir:left by length |  | 
| {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; |  | 
|  |  | 
| #ifdef LOG_EGCROP |  | 
| static  int             egcropcnt[256]; |  | 
| #endif |  | 
|  |  | 
|  |  | 
| void egcshift(void) { |  | 
|  |  | 
| BYTE    src8, dst8; |  | 
|  |  | 
| egc.remain = LOW12(egc.leng) + 1; |  | 
| egc.func = (egc.sft >> 12) & 1; |  | 
| if (!egc.func) { |  | 
| egc.inptr = egc.buf; |  | 
| egc.outptr = egc.buf; |  | 
| } |  | 
| else { |  | 
| egc.inptr = egc.buf + 4096/8 + 3; |  | 
| egc.outptr = egc.buf + 4096/8 + 3; |  | 
| } |  | 
| egc.srcbit = egc.sft & 0x0f; |  | 
| egc.dstbit = (egc.sft >> 4) & 0x0f; |  | 
|  |  | 
| src8 = egc.srcbit & 0x07; |  | 
| dst8 = egc.dstbit & 0x07; |  | 
| if (src8 < dst8) { |  | 
|  |  | 
| // dir:inc |  | 
| // ****---4 -------8 -------- |  | 
| // ******-- -4------ --8----- -- |  | 
| // 1st -> data[0] >> (dst - src) |  | 
| // 2nd -> (data[0] << (8 - (dst - src))) | (data[1] >> (dst - src)) |  | 
|  |  | 
| // dir:dec |  | 
| //          -------- 8------- 6-----** |  | 
| //      --- -----8-- -----6-- ---***** |  | 
| // 1st -> data[0] << (dst - src) |  | 
| // 2nd -> (data[0] >> (8 - (dst - src))) | (data[1] << (dst - src)) |  | 
|  |  | 
| egc.func += 2; |  | 
| egc.sft8bitr = dst8 - src8; |  | 
| egc.sft8bitl = 8 - egc.sft8bitr; |  | 
| } |  | 
| else if (src8 > dst8) { |  | 
|  |  | 
| // dir:inc |  | 
| // ****---4 -------8 -------- |  | 
| // **---4-- -----8-- ------ |  | 
| // 1st -> (data[0] << (src - dst)) | (data[1] >> (8 - (src - dst)) |  | 
| // 2nd -> (data[0] << (src - dst)) | (data[1] >> (8 - (src - dst)) |  | 
|  |  | 
| // dir:dec |  | 
| //          -------- 8------- 3--***** |  | 
| //             ----- ---8---- ---3--** |  | 
| // 1st -> (data[0] >> (dst - src)) | (data[-1] << (8 - (src - dst)) |  | 
| // 2nd -> (data[0] >> (dst - src)) | (data[-1] << (8 - (src - dst)) |  | 
|  |  | 
| egc.func += 4; |  | 
| egc.sft8bitl = src8 - dst8; |  | 
| egc.sft8bitr = 8 - egc.sft8bitl; |  | 
| } |  | 
| egc.stack = 0; |  | 
| } |  | 
|  |  | 
|  |  | 
| static void egcsftb_upn_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| } |  | 
| egc_src._b[0][ext] = egc.outptr[0]; |  | 
| egc_src._b[1][ext] = egc.outptr[4]; |  | 
| egc_src._b[2][ext] = egc.outptr[8]; |  | 
| egc_src._b[3][ext] = egc.outptr[12]; |  | 
| egc.outptr++; |  | 
| } |  | 
|  |  | 
| static void egcsftb_dnn_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| } |  | 
| egc_src._b[0][ext] = egc.outptr[0]; |  | 
| egc_src._b[1][ext] = egc.outptr[4]; |  | 
| egc_src._b[2][ext] = egc.outptr[8]; |  | 
| egc_src._b[3][ext] = egc.outptr[12]; |  | 
| egc.outptr--; |  | 
| } |  | 
|  |  | 
|  |  | 
| // ****---4 -------8 -------- |  | 
| // ******-- -4------ --8----- -- |  | 
| // 1st -> data[0] >> (dst - src) |  | 
| // 2nd -> (data[0] << (8 - (dst - src))) | (data[1] >> (dst - src)) |  | 
|  |  | 
| static void egcsftb_upr_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| egc.dstbit = 0; |  | 
| egc_src._b[0][ext] = (egc.outptr[0] >> egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[4] >> egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[8] >> egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[12] >> egc.sft8bitr); |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| egc_src._b[0][ext] = (egc.outptr[0] << egc.sft8bitl) | |  | 
| (egc.outptr[1] >> egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[4] << egc.sft8bitl) | |  | 
| (egc.outptr[5] >> egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[8] << egc.sft8bitl) | |  | 
| (egc.outptr[9] >> egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[12] << egc.sft8bitl) | |  | 
| (egc.outptr[13] >> egc.sft8bitr); |  | 
| egc.outptr++; |  | 
| } |  | 
| } |  | 
|  |  | 
|  |  | 
| //          -------- 8------- 6-----** |  | 
| //      --- -----8-- -----6-- ---***** |  | 
| // 1st -> data[0] << (dst - src) |  | 
| // 2nd -> (data[0] >> (8 - (dst - src))) | (data[-1] << (dst - src)) |  | 
|  |  | 
| static void egcsftb_dnr_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| egc.dstbit = 0; |  | 
| egc_src._b[0][ext] = (egc.outptr[0] << egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[4] << egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[8] << egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[12] << egc.sft8bitr); |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| egc.outptr--; |  | 
| egc_src._b[0][ext] = (egc.outptr[1] >> egc.sft8bitl) | |  | 
| (egc.outptr[0] << egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[5] >> egc.sft8bitl) | |  | 
| (egc.outptr[4] << egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[9] >> egc.sft8bitl) | |  | 
| (egc.outptr[8] << egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[13] >> egc.sft8bitl) | |  | 
| (egc.outptr[12] << egc.sft8bitr); |  | 
| } |  | 
| } |  | 
|  |  | 
|  |  | 
| // ****---4 -------8 -------- |  | 
| // **---4-- -----8-- ------ |  | 
| // 1st -> (data[0] << (src - dst)) | (data[1] >> (8 - (src - dst)) |  | 
| // 2nd -> (data[0] << (src - dst)) | (data[1] >> (8 - (src - dst)) |  | 
|  |  | 
| static void egcsftb_upl_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_u1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| } |  | 
| egc_src._b[0][ext] = (egc.outptr[0] << egc.sft8bitl) | |  | 
| (egc.outptr[1] >> egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[4] << egc.sft8bitl) | |  | 
| (egc.outptr[5] >> egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[8] << egc.sft8bitl) | |  | 
| (egc.outptr[9] >> egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[12] << egc.sft8bitl) | |  | 
| (egc.outptr[13] >> egc.sft8bitr); |  | 
| egc.outptr++; |  | 
| } |  | 
|  |  | 
|  |  | 
| //          -------- 8------- 3--***** |  | 
| //             ----- ---8---- ---3--** |  | 
| // 1st -> (data[0] >> (dst - src)) | (data[-1] << (8 - (src - dst)) |  | 
| // 2nd -> (data[0] >> (dst - src)) | (data[-1] << (8 - (src - dst)) |  | 
|  |  | 
| static void egcsftb_dnl_sub(UINT ext) { |  | 
|  |  | 
| if (egc.dstbit >= 8) { |  | 
| egc.dstbit -= 8; |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| if (egc.dstbit) { |  | 
| if ((egc.dstbit + egc.remain) >= 8) { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + (7*8)]; |  | 
| egc.remain -= (8 - egc.dstbit); |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d0[egc.dstbit + |  | 
| (egc.remain - 1) * 8]; |  | 
| egc.remain = 0; |  | 
| egc.dstbit = 0; |  | 
| } |  | 
| } |  | 
| else { |  | 
| if (egc.remain >= 8) { |  | 
| egc.remain -= 8; |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[ext] = bytemask_d1[egc.remain - 1]; |  | 
| egc.remain = 0; |  | 
| } |  | 
| } |  | 
| egc.outptr--; |  | 
| egc_src._b[0][ext] = (egc.outptr[1] >> egc.sft8bitl) | |  | 
| (egc.outptr[0] << egc.sft8bitr); |  | 
| egc_src._b[1][ext] = (egc.outptr[5] >> egc.sft8bitl) | |  | 
| (egc.outptr[4] << egc.sft8bitr); |  | 
| egc_src._b[2][ext] = (egc.outptr[9] >> egc.sft8bitl) | |  | 
| (egc.outptr[8] << egc.sft8bitr); |  | 
| egc_src._b[3][ext] = (egc.outptr[13] >> egc.sft8bitl) | |  | 
| (egc.outptr[12] << egc.sft8bitr); |  | 
| } |  | 
|  |  | 
|  |  | 
| static void egcsftb_upn0(UINT32 adrs) { |  | 
|  |  | 
| UINT    ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_upn_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_upn0(UINT32 adrs) { |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_upn_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| egcsftb_upn_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_H] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
| static void egcsftb_dnn0(UINT32 adrs) { |  | 
|  |  | 
| UINT    ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_dnn_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_dnn0(UINT32 adrs) { |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_dnn_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| egcsftb_dnn_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_L] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
|  |  | 
| static void egcsftb_upr0(UINT32 adrs) {                 // dir:up srcbit < dstbit |  | 
|  |  | 
| int             ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_upr_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_upr0(UINT32 adrs) {                 // dir:up srcbit < dstbit |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_upr_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| egcsftb_upr_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_H] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
| static void egcsftb_dnr0(UINT32 adrs) {                 // dir:up srcbit < dstbit |  | 
|  |  | 
| UINT    ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_dnr_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_dnr0(UINT32 adrs) {                 // dir:up srcbit < dstbit |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_dnr_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| egcsftb_dnr_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_L] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
|  |  | 
| static void egcsftb_upl0(UINT32 adrs) {                 // dir:up srcbit > dstbit |  | 
|  |  | 
| UINT    ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_upl_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_upl0(UINT32 adrs) {                 // dir:up srcbit > dstbit |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_upl_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| egcsftb_upl_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_H] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
| static void egcsftb_dnl0(UINT32 adrs) {                 // dir:up srcbit > dstbit |  | 
|  |  | 
| UINT    ext; |  | 
|  |  | 
| ext = EGCADDR(adrs & 1); |  | 
| if (egc.stack < (UINT)(8 - egc.dstbit)) { |  | 
| egc.srcmask._b[ext] = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (8 - egc.dstbit); |  | 
| egcsftb_dnl_sub(ext); |  | 
| if (!egc.remain) { |  | 
| egcshift(); |  | 
| } |  | 
| } |  | 
|  |  | 
| static void egcsftw_dnl0(UINT32 adrs) {                 // dir:up srcbit > dstbit |  | 
|  |  | 
| if (egc.stack < (UINT)(16 - egc.dstbit)) { |  | 
| egc.srcmask.w = 0; |  | 
| return; |  | 
| } |  | 
| egc.stack -= (16 - egc.dstbit); |  | 
| egcsftb_dnl_sub(EGCADDR_H); |  | 
| if (egc.remain) { |  | 
| egcsftb_dnl_sub(EGCADDR_L); |  | 
| if (egc.remain) { |  | 
| return; |  | 
| } |  | 
| } |  | 
| else { |  | 
| egc.srcmask._b[EGCADDR_L] = 0; |  | 
| } |  | 
| egcshift(); |  | 
| (void)adrs; |  | 
| } |  | 
|  |  | 
|  |  | 
| static void (*egcsft_proc[])(UINT32 adrs) = { |  | 
| egcsftw_upn0,   egcsftw_dnn0, |  | 
| egcsftw_upr0,   egcsftw_dnr0, |  | 
| egcsftw_upl0,   egcsftw_dnl0, |  | 
|  |  | 
| egcsftb_upn0,   egcsftb_dnn0, |  | 
| egcsftb_upr0,   egcsftb_dnr0, |  | 
| egcsftb_upl0,   egcsftb_dnl0}; |  | 
|  |  | 
|  |  | 
| // --------------------------------------------------------------------------- |  | 
|  |  | 
| static void shiftinput_byte(UINT ext) { |  | 
|  |  | 
| if (egc.stack <= 16) { |  | 
| if (egc.srcbit >= 8) { |  | 
| egc.srcbit -= 8; |  | 
| } |  | 
| else { |  | 
| egc.stack += (8 - egc.srcbit); |  | 
| egc.srcbit = 0; |  | 
| } |  | 
| if (!(egc.sft & 0x1000)) { |  | 
| egc.inptr++; |  | 
| } |  | 
| else { |  | 
| egc.inptr--; |  | 
| } |  | 
| } |  | 
| egc.srcmask._b[ext] = 0xff; |  | 
| egcsft_proc[egc.func + 6](ext); |  | 
| } |  | 
|  |  | 
| static void shiftinput_incw(void) { |  | 
|  |  | 
| if (egc.stack <= 16) { |  | 
| egc.inptr += 2; |  | 
| if (egc.srcbit >= 8) { |  | 
| egc.outptr++; |  | 
| } |  | 
| egc.stack += (16 - egc.srcbit); |  | 
| egc.srcbit = 0; |  | 
| } |  | 
| egc.srcmask.w = 0xffff; |  | 
| egcsft_proc[egc.func](0); |  | 
| } |  | 
|  |  | 
| static void shiftinput_decw(void) { |  | 
|  |  | 
| if (egc.stack <= 16) { |  | 
| egc.inptr -= 2; |  | 
| if (egc.srcbit >= 8) { |  | 
| egc.outptr--; |  | 
| } |  | 
| egc.stack += (16 - egc.srcbit); |  | 
| egc.srcbit = 0; |  | 
| } |  | 
| egc.srcmask.w = 0xffff; |  | 
| egcsft_proc[egc.func](0); |  | 
| } |  | 
|  |  | 
|  |  | 
| #define EGCOPE_SHIFT {                                                                                          \ |  | 
| if (egc.ope & 0x400) {                                                                                  \ |  | 
| if (func < 6) {                                                                                         \ |  | 
| if (!(egc.sft & 0x1000)) {                                                              \ |  | 
| egc.inptr[ 0] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 1] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[ 4] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 5] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[ 8] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 9] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[12] = (BYTE)value;                                            \ |  | 
| egc.inptr[13] = (BYTE)(value >> 8);                                     \ |  | 
| shiftinput_incw();                                                                      \ |  | 
| }                                                                                                               \ |  | 
| else {                                                                                                  \ |  | 
| egc.inptr[-1] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 0] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[ 3] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 4] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[ 7] = (BYTE)value;                                            \ |  | 
| egc.inptr[ 8] = (BYTE)(value >> 8);                                     \ |  | 
| egc.inptr[11] = (BYTE)value;                                            \ |  | 
| egc.inptr[12] = (BYTE)(value >> 8);                                     \ |  | 
| shiftinput_decw();                                                                      \ |  | 
| }                                                                                                               \ |  | 
| }                                                                                                                       \ |  | 
| else {                                                                                                          \ |  | 
| egc.inptr[ 0] = (BYTE)value;                                                    \ |  | 
| egc.inptr[ 4] = (BYTE)value;                                                    \ |  | 
| egc.inptr[ 8] = (BYTE)value;                                                    \ |  | 
| egc.inptr[12] = (BYTE)value;                                                    \ |  | 
| shiftinput_byte(EGCADDR(ad & 1));                                               \ |  | 
| }                                                                                                                       \ |  | 
| }                                                                                                                               \ |  | 
| } |  | 
|  |  | 
|  |  | 
| static void gdc_ope(UINT32 ad, REG16 value, int func) { |  | 
|  |  | 
| EGCQUAD pat; |  | 
| EGCQUAD dst; |  | 
|  |  | 
| egc.mask2.w = egc.mask.w; |  | 
|  |  | 
| switch(egc.ope & 0x1800) { |  | 
| case 0x0800: |  | 
| EGCOPE_SHIFT; |  | 
| switch(egc.fgbg & 0x6000) { |  | 
| case 0x2000: |  | 
| pat.d[0] = egc.bgc.d[0]; |  | 
| pat.d[1] = egc.bgc.d[1]; |  | 
| break; |  | 
| case 0x4000: |  | 
| pat.d[0] = egc.fgc.d[0]; |  | 
| pat.d[1] = egc.fgc.d[1]; |  | 
| break; |  | 
| default: |  | 
| if ((egc.ope & 0x0300) == 0x0100) {     // ver0.29 |  | 
| pat.d[0] = egc_src.d[0]; |  | 
| pat.d[1] = egc_src.d[1]; |  | 
| } |  | 
| else { |  | 
| pat.d[0] = egc.patreg.d[0]; |  | 
| pat.d[1] = egc.patreg.d[1]; |  | 
| } |  | 
| break; |  | 
| } |  | 
| ad &= ~1; |  | 
| dst.w[0] = *(UINT16 *)(&mem[ad + VRAM_B]); |  | 
| dst.w[1] = *(UINT16 *)(&mem[ad + VRAM_R]); |  | 
| dst.w[2] = *(UINT16 *)(&mem[ad + VRAM_G]); |  | 
| dst.w[3] = *(UINT16 *)(&mem[ad + VRAM_E]); |  | 
|  |  | 
| #ifdef LOG_EGCROP |  | 
| egcropcnt[egc.ope & 0xff]++; |  | 
| #endif |  | 
| data.d[0] = 0; |  | 
| data.d[1] = 0; |  | 
| if (egc.ope & 0x80) { |  | 
| data.d[0] |= (pat.d[0] & egc_src.d[0] & dst.d[0]); |  | 
| data.d[1] |= (pat.d[1] & egc_src.d[1] & dst.d[1]); |  | 
| } |  | 
| if (egc.ope & 0x40) { |  | 
| data.d[0] |= ((~pat.d[0]) & egc_src.d[0] & dst.d[0]); |  | 
| data.d[1] |= ((~pat.d[1]) & egc_src.d[1] & dst.d[1]); |  | 
| } |  | 
| if (egc.ope & 0x20) { |  | 
| data.d[0] |= (pat.d[0] & egc_src.d[0] & (~dst.d[0])); |  | 
| data.d[1] |= (pat.d[1] & egc_src.d[1] & (~dst.d[1])); |  | 
| } |  | 
| if (egc.ope & 0x10) { |  | 
| data.d[0] |= ((~pat.d[0]) & egc_src.d[0] & (~dst.d[0])); |  | 
| data.d[1] |= ((~pat.d[1]) & egc_src.d[1] & (~dst.d[1])); |  | 
| } |  | 
| if (egc.ope & 0x08) { |  | 
| data.d[0] |= (pat.d[0] & (~egc_src.d[0]) & dst.d[0]); |  | 
| data.d[1] |= (pat.d[1] & (~egc_src.d[1]) & dst.d[1]); |  | 
| } |  | 
| if (egc.ope & 0x04) { |  | 
| data.d[0] |= ((~pat.d[0]) & (~egc_src.d[0]) & dst.d[0]); |  | 
| data.d[1] |= ((~pat.d[1]) & (~egc_src.d[1]) & dst.d[1]); |  | 
| } |  | 
| if (egc.ope & 0x02) { |  | 
| data.d[0] |= (pat.d[0] & (~egc_src.d[0]) & (~dst.d[0])); |  | 
| data.d[1] |= (pat.d[1] & (~egc_src.d[1]) & (~dst.d[1])); |  | 
| } |  | 
| if (egc.ope & 0x01) { |  | 
| data.d[0] |= ((~pat.d[0]) & (~egc_src.d[0]) & (~dst.d[0])); |  | 
| data.d[1] |= ((~pat.d[1]) & (~egc_src.d[1]) & (~dst.d[1])); |  | 
| } |  | 
| egc.mask2.w &= egc.srcmask.w; |  | 
| break; |  | 
| case 0x1000: |  | 
| switch(egc.fgbg & 0x6000) { |  | 
| case 0x2000:                                                    // ver0.29 |  | 
| data.d[0] = egc.bgc.d[0]; |  | 
| data.d[1] = egc.bgc.d[1]; |  | 
| break; |  | 
| case 0x4000:                                                    // ver0.29 |  | 
| data.d[0] = egc.fgc.d[0]; |  | 
| data.d[1] = egc.fgc.d[1]; |  | 
| break; |  | 
| default: |  | 
| #if 0 |  | 
| data.d[0] = egc.patreg.d[0]; |  | 
| data.d[1] = egc.patreg.d[1]; |  | 
| #else |  | 
| EGCOPE_SHIFT; |  | 
| data.d[0] = egc_src.d[0]; |  | 
| data.d[1] = egc_src.d[1]; |  | 
| egc.mask2.w &= egc.srcmask.w; |  | 
| #endif |  | 
| break; |  | 
| } |  | 
| break; |  | 
| default: |  | 
| #if defined(BYTESEX_LITTLE) |  | 
| data.w[0] = (UINT16)value; |  | 
| data.w[1] = (UINT16)value; |  | 
| data.w[2] = (UINT16)value; |  | 
| data.w[3] = (UINT16)value; |  | 
| #else |  | 
| data._b[0][0] = (BYTE)value; |  | 
| data._b[0][1] = (BYTE)(value >> 8); |  | 
| data.w[1] = data.w[0]; |  | 
| data.w[2] = data.w[0]; |  | 
| data.w[3] = data.w[0]; |  | 
| #endif |  | 
| break; |  | 
| } |  | 
| } |  | 
|  |  | 
| REG8 MEMCALL egc_read(UINT32 addr) { |  | 
|  |  | 
| UINT32  ad; |  | 
| UINT    ext; |  | 
|  |  | 
| if (gdcs.access) { |  | 
| addr += VRAM_STEP; |  | 
| } |  | 
| ad = VRAM_POS(addr); |  | 
| ext = EGCADDR(addr & 1); |  | 
| egc.lastvram._b[0][ext] = mem[ad + VRAM_B]; |  | 
| egc.lastvram._b[1][ext] = mem[ad + VRAM_R]; |  | 
| egc.lastvram._b[2][ext] = mem[ad + VRAM_G]; |  | 
| egc.lastvram._b[3][ext] = mem[ad + VRAM_E]; |  | 
|  |  | 
| // shift input |  | 
| if (!(egc.ope & 0x400)) { |  | 
| egc.inptr[0] = egc.lastvram._b[0][ext]; |  | 
| egc.inptr[4] = egc.lastvram._b[1][ext]; |  | 
| egc.inptr[8] = egc.lastvram._b[2][ext]; |  | 
| egc.inptr[12] = egc.lastvram._b[3][ext]; |  | 
| shiftinput_byte(ext); |  | 
| } |  | 
|  |  | 
| if ((egc.ope & 0x0300) == 0x0100) { |  | 
| egc.patreg._b[0][ext] = mem[ad + VRAM_B]; |  | 
| egc.patreg._b[1][ext] = mem[ad + VRAM_R]; |  | 
| egc.patreg._b[2][ext] = mem[ad + VRAM_G]; |  | 
| egc.patreg._b[3][ext] = mem[ad + VRAM_E]; |  | 
| } |  | 
| if (!(egc.ope & 0x2000)) { |  | 
| int pl = (egc.fgbg >> 8) & 3; |  | 
| if (!(egc.ope & 0x400)) { |  | 
| return(egc_src._b[pl][ext]); |  | 
| } |  | 
| else { |  | 
| return(mem[ad + planead[pl]]); |  | 
| } |  | 
| } |  | 
| return(mem[addr]); |  | 
| } |  | 
|  |  | 
|  |  | 
| void MEMCALL egc_write(UINT32 addr, REG8 value) { |  | 
|  |  | 
| UINT    ext; |  | 
| REG16   wvalue; |  | 
|  |  | 
| addr = LOW15(addr); |  | 
| ext = EGCADDR(addr & 1); |  | 
| if (!gdcs.access) { |  | 
| gdcs.grphdisp |= 1; |  | 
| vramupdate[addr] |= 0x01; |  | 
| } |  | 
| else { |  | 
| gdcs.grphdisp |= 2; |  | 
| vramupdate[addr] |= 0x02; |  | 
| addr += VRAM_STEP; |  | 
| } |  | 
| if ((egc.ope & 0x0300) == 0x0200) { |  | 
| egc.patreg._b[0][ext] = mem[addr + VRAM_B]; |  | 
| egc.patreg._b[1][ext] = mem[addr + VRAM_R]; |  | 
| egc.patreg._b[2][ext] = mem[addr + VRAM_G]; |  | 
| egc.patreg._b[3][ext] = mem[addr + VRAM_E]; |  | 
| } |  | 
|  |  | 
| value = (BYTE)value; |  | 
| wvalue = (value << 8) + value; |  | 
| if (!ext) { |  | 
| gdc_ope(addr, wvalue, egc.func + 6); |  | 
| } |  | 
| else { |  | 
| gdc_ope(addr, wvalue, egc.func + 6); |  | 
| } |  | 
| if (egc.mask2._b[ext]) { |  | 
| if (!(egc.access & 1)) { |  | 
| mem[addr + VRAM_B] &= ~egc.mask2._b[ext]; |  | 
| mem[addr + VRAM_B] |= data._b[0][ext] & egc.mask2._b[ext]; |  | 
| } |  | 
| if (!(egc.access & 2)) { |  | 
| mem[addr + VRAM_R] &= ~egc.mask2._b[ext]; |  | 
| mem[addr + VRAM_R] |= data._b[1][ext] & egc.mask2._b[ext]; |  | 
| } |  | 
| if (!(egc.access & 4)) { |  | 
| mem[addr + VRAM_G] &= ~egc.mask2._b[ext]; |  | 
| mem[addr + VRAM_G] |= data._b[2][ext] & egc.mask2._b[ext]; |  | 
| } |  | 
| if (!(egc.access & 8)) { |  | 
| mem[addr + VRAM_E] &= ~egc.mask2._b[ext]; |  | 
| mem[addr + VRAM_E] |= data._b[3][ext] & egc.mask2._b[ext]; |  | 
| } |  | 
| } |  | 
| } |  | 
|  |  | 
| REG16 MEMCALL egc_read_w(UINT32 addr) { |  | 
|  |  | 
| UINT32  ad; |  | 
|  |  | 
| if (!(addr & 1)) { |  | 
| if (gdcs.access) { |  | 
| addr += VRAM_STEP; |  | 
| } |  | 
| ad = VRAM_POS(addr); |  | 
| egc.lastvram.w[0] = *(UINT16 *)(&mem[ad + VRAM_B]); |  | 
| egc.lastvram.w[1] = *(UINT16 *)(&mem[ad + VRAM_R]); |  | 
| egc.lastvram.w[2] = *(UINT16 *)(&mem[ad + VRAM_G]); |  | 
| egc.lastvram.w[3] = *(UINT16 *)(&mem[ad + VRAM_E]); |  | 
|  |  | 
| // shift input |  | 
| if (!(egc.ope & 0x400)) { |  | 
| if (!(egc.sft & 0x1000)) { |  | 
| egc.inptr[ 0] = egc.lastvram._b[0][EGCADDR_L]; |  | 
| egc.inptr[ 1] = egc.lastvram._b[0][EGCADDR_H]; |  | 
| egc.inptr[ 4] = egc.lastvram._b[1][EGCADDR_L]; |  | 
| egc.inptr[ 5] = egc.lastvram._b[1][EGCADDR_H]; |  | 
| egc.inptr[ 8] = egc.lastvram._b[2][EGCADDR_L]; |  | 
| egc.inptr[ 9] = egc.lastvram._b[2][EGCADDR_H]; |  | 
| egc.inptr[12] = egc.lastvram._b[3][EGCADDR_L]; |  | 
| egc.inptr[13] = egc.lastvram._b[3][EGCADDR_H]; |  | 
| shiftinput_incw(); |  | 
| } |  | 
| else { |  | 
| egc.inptr[-1] = egc.lastvram._b[0][EGCADDR_L]; |  | 
| egc.inptr[ 0] = egc.lastvram._b[0][EGCADDR_H]; |  | 
| egc.inptr[ 3] = egc.lastvram._b[1][EGCADDR_L]; |  | 
| egc.inptr[ 4] = egc.lastvram._b[1][EGCADDR_H]; |  | 
| egc.inptr[ 7] = egc.lastvram._b[2][EGCADDR_L]; |  | 
| egc.inptr[ 8] = egc.lastvram._b[2][EGCADDR_H]; |  | 
| egc.inptr[11] = egc.lastvram._b[3][EGCADDR_L]; |  | 
| egc.inptr[12] = egc.lastvram._b[3][EGCADDR_H]; |  | 
| shiftinput_decw(); |  | 
| } |  | 
| } |  | 
|  |  | 
| if ((egc.ope & 0x0300) == 0x0100) { |  | 
| egc.patreg.d[0] = egc.lastvram.d[0]; |  | 
| egc.patreg.d[1] = egc.lastvram.d[1]; |  | 
| } |  | 
| if (!(egc.ope & 0x2000)) { |  | 
| int pl = (egc.fgbg >> 8) & 3; |  | 
| if (!(egc.ope & 0x400)) { |  | 
| return(LOADINTELWORD(egc_src._b[pl])); |  | 
| } |  | 
| else { |  | 
| return(LOADINTELWORD(mem + ad + planead[pl])); |  | 
| } |  | 
| } |  | 
| return(LOADINTELWORD(mem + addr)); |  | 
| } |  | 
| else if (!(egc.sft & 0x1000)) { |  | 
| REG16 ret; |  | 
| ret = egc_read(addr); |  | 
| ret |= egc_read(addr+1) << 8; |  | 
| return(ret); |  | 
| } |  | 
| else { |  | 
| REG16 ret; |  | 
| ret = egc_read(addr+1) << 8; |  | 
| ret |= egc_read(addr); |  | 
| return(ret); |  | 
| } |  | 
| } |  | 
|  |  | 
| void MEMCALL egc_write_w(UINT32 addr, REG16 value) { |  | 
|  |  | 
| if (!(addr & 1)) {                                                                                      // word access |  | 
| addr = LOW15(addr); |  | 
| if (!gdcs.access) { |  | 
| gdcs.grphdisp |= 1; |  | 
| *(UINT16 *)(vramupdate + addr) |= 0x0101; |  | 
| } |  | 
| else { |  | 
| gdcs.grphdisp |= 2; |  | 
| *(UINT16 *)(vramupdate + addr) |= 0x0202; |  | 
| addr += VRAM_STEP; |  | 
| } |  | 
| if ((egc.ope & 0x0300) == 0x0200) { |  | 
| egc.patreg.w[0] = *(UINT16 *)(&mem[addr + VRAM_B]); |  | 
| egc.patreg.w[1] = *(UINT16 *)(&mem[addr + VRAM_R]); |  | 
| egc.patreg.w[2] = *(UINT16 *)(&mem[addr + VRAM_G]); |  | 
| egc.patreg.w[3] = *(UINT16 *)(&mem[addr + VRAM_E]); |  | 
| } |  | 
| gdc_ope(addr, value, egc.func); |  | 
| if (egc.mask2.w) { |  | 
| if (!(egc.access & 1)) { |  | 
| *(UINT16 *)(&mem[addr + VRAM_B]) &= ~egc.mask2.w; |  | 
| *(UINT16 *)(&mem[addr + VRAM_B]) |= data.w[0] & egc.mask2.w; |  | 
| } |  | 
| if (!(egc.access & 2)) { |  | 
| *(UINT16 *)(&mem[addr + VRAM_R]) &= ~egc.mask2.w; |  | 
| *(UINT16 *)(&mem[addr + VRAM_R]) |= data.w[1] & egc.mask2.w; |  | 
| } |  | 
| if (!(egc.access & 4)) { |  | 
| *(UINT16 *)(&mem[addr + VRAM_G]) &= ~egc.mask2.w; |  | 
| *(UINT16 *)(&mem[addr + VRAM_G]) |= data.w[2] & egc.mask2.w; |  | 
| } |  | 
| if (!(egc.access & 8)) { |  | 
| *(UINT16 *)(&mem[addr + VRAM_E]) &= ~egc.mask2.w; |  | 
| *(UINT16 *)(&mem[addr + VRAM_E]) |= data.w[3] & egc.mask2.w; |  | 
| } |  | 
| } |  | 
| } |  | 
| else if (!(egc.sft & 0x1000)) { |  | 
| egc_write(addr, (REG8)value); |  | 
| egc_write(addr+1, (REG8)(value >> 8)); |  | 
| } |  | 
| else { |  | 
| egc_write(addr+1, (REG8)(value >> 8)); |  | 
| egc_write(addr, (REG8)value); |  | 
| } |  | 
| } |  | 
 |  |  |