| 1 | #include "common.h" |
| 2 | |
| 3 | void spin(int loops); |
| 4 | u16 read_frt(void); |
| 5 | |
| 6 | // comm area map: |
| 7 | // 00-01: cmd |
| 8 | // 02-03: error |
| 9 | // 04-07: arg0/response |
| 10 | // 08-0b: arg1 |
| 11 | // 0c: last_irq_vec_master |
| 12 | // 0d: last_irq_vec_slave |
| 13 | // 0e: exception_index_master |
| 14 | // 0f: exception_index_slave |
| 15 | static void do_cmd(u16 cmd, u16 r[6], u32 is_slave) |
| 16 | { |
| 17 | u32 *rl = (u32 *)r; |
| 18 | u32 a, d; |
| 19 | u16 v; |
| 20 | |
| 21 | switch (cmd) |
| 22 | { |
| 23 | case CMD_ECHO: |
| 24 | v = read16(&r[4/2]) ^ (is_slave << 15); |
| 25 | write16(&r[6/2], v); |
| 26 | break; |
| 27 | case CMD_READ_FRT: |
| 28 | v = read_frt(); |
| 29 | write16(&r[4/2], v); |
| 30 | break; |
| 31 | case CMD_READ8: |
| 32 | a = read32(&rl[4/4]); |
| 33 | d = read8(a); |
| 34 | write32(&rl[4/4], d); |
| 35 | break; |
| 36 | case CMD_READ16: |
| 37 | a = read32(&rl[4/4]); |
| 38 | d = read16(a); |
| 39 | write32(&rl[4/4], d); |
| 40 | break; |
| 41 | case CMD_READ32: |
| 42 | a = read32(&rl[4/4]); |
| 43 | d = read32(a); |
| 44 | write32(&rl[4/4], d); |
| 45 | break; |
| 46 | case CMD_WRITE8: |
| 47 | a = read32(&rl[4/4]); |
| 48 | d = read32(&rl[8/4]); |
| 49 | write8(a, d); |
| 50 | break; |
| 51 | case CMD_WRITE16: |
| 52 | a = read32(&rl[4/4]); |
| 53 | d = read32(&rl[8/4]); |
| 54 | write16(a, d); |
| 55 | break; |
| 56 | case CMD_WRITE32: |
| 57 | a = read32(&rl[4/4]); |
| 58 | d = read32(&rl[8/4]); |
| 59 | write32(a, d); |
| 60 | break; |
| 61 | case CMD_GETGBR: |
| 62 | asm("stc gbr, %0" : "=r"(d)); |
| 63 | write32(&rl[4/4], d); |
| 64 | break; |
| 65 | case CMD_GETVBR: |
| 66 | asm("stc vbr, %0" : "=r"(d)); |
| 67 | write32(&rl[4/4], d); |
| 68 | break; |
| 69 | default: |
| 70 | r[2/2]++; // error |
| 71 | mem_barrier(); |
| 72 | break; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | void main_c(u32 is_slave) |
| 77 | { |
| 78 | u16 *r = (u16 *)0x20004000; |
| 79 | |
| 80 | for (;;) |
| 81 | { |
| 82 | u16 cmd, cmdr; |
| 83 | |
| 84 | mem_barrier(); |
| 85 | cmd = read16(&r[0x20/2]); |
| 86 | mem_barrier(); |
| 87 | cmdr = read16(&r[0x20/2]); |
| 88 | if (cmd == 0 |
| 89 | || cmd != cmdr // documented as "normal" case |
| 90 | || ((cmd & 0x8000) ^ (is_slave << 15)) |
| 91 | || cmd == 0x4d5f) { // 'M_' from BIOS |
| 92 | spin(64); |
| 93 | continue; |
| 94 | } |
| 95 | cmd &= 0x7fff; |
| 96 | do_cmd(cmd, &r[0x20/2], is_slave); |
| 97 | write16(&r[0x20/2], 0); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | // vim:ts=4:sw=4:expandtab |