diff options
-rw-r--r-- | asmmon.c | 23 | ||||
-rw-r--r-- | asmmon.h | 274 | ||||
-rw-r--r-- | assemble.c | 261 | ||||
-rw-r--r-- | disasm.c | 96 | ||||
-rw-r--r-- | disasm.h | 168 | ||||
-rw-r--r-- | enums.h | 370 | ||||
-rw-r--r-- | lexer.c | 36 | ||||
-rw-r--r-- | lexer.h | 38 | ||||
-rw-r--r-- | opcode.h | 3 | ||||
-rw-r--r-- | programs/sub-suite/print_char.s | 147 | ||||
-rw-r--r-- | programs/sub-suite/subeditor-new.s | 1119 | ||||
-rw-r--r-- | sux.c | 405 | ||||
-rw-r--r-- | sux.h | 804 | ||||
-rw-r--r-- | tables.h | 168 | ||||
-rw-r--r-- | test/base-ext.s | 19 |
15 files changed, 3177 insertions, 754 deletions
@@ -149,6 +149,7 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u uint8_t am_done = 1; uint8_t op_done = 1; uint16_t bline = s->bline; + const char *inst_name; for (; bline; bline--) { putchar('\n'); } @@ -169,7 +170,6 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u case INDY: putchar('('); am_done = 0; break; case ZMY : case ZMX : am_done = 0; break; - case BREG: putchar('b'); am_done = 1; break; } am = (am_done) ? 0xFF : am; } @@ -188,9 +188,14 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u switch (t->id) { case TOK_DIR : printf(".%s", dir_t[t->type]); break; case TOK_RS : printf("%s", rs_t[t->type]); break; + case TOK_EXTOP : case TOK_OPCODE: + switch (t->id) { + case TOK_EXTOP : inst_name = ext_mne[t->byte]; break; + case TOK_OPCODE: inst_name = /**/mne[t->byte]; break; + } for (; j < 3; j++) { - mne_lower[j] = tolower(mne[t->byte][j]); + mne_lower[j] = tolower(inst_name[j]); } mne_lower[j] = '\0'; j = 0; @@ -300,6 +305,12 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u if (t->next && !isopdone(t)) { op_done = isopdone(t->next); } + if (am != 0xFF && op_done && t->id != TOK_RS && !t->next) { + switch (am) { + case EIND: putchar('('); am_done = 0; break; + case BREG: putchar('b'); am_done = 1; break; + } + } if (am != 0xFF && !am_done && op_done) { switch (am) { case INDX: @@ -309,12 +320,18 @@ void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, u break; } /* Falls Through. */ + case EIND: + if (am == EIND) { + putchar('e'); + } + /* Falls Through. */ case INDY: case IND : putchar(')'); - if (am == IND) { + if (am == IND || am == EIND) { break; } + /* Falls Through. */ case ZMY : printf(", y"); break; } am = 0xFF; @@ -68,7 +68,7 @@ struct sym { }; struct inst { - uint16_t am; /* Addressing modes. */ + uint32_t am; /* Addressing modes. */ uint8_t op; /* Base value used to get the actual opcode. */ }; @@ -117,6 +117,7 @@ enum token { TOK_IMM, TOK_BREG, TOK_OPCODE, + TOK_EXTOP, TOK_RS, TOK_OF, TOK_COMMENT, @@ -144,6 +145,7 @@ enum pre_token { PTOK_RBRACK, PTOK_COMMA, PTOK_B, + PTOK_E, PTOK_X, PTOK_Y, PTOK_S, @@ -183,7 +185,14 @@ enum addrmode { AM_BREG = (1 << 9), AM_IMPL = (1 << 10), AM_INDX2 = (1 << 11), - AM_ZM2 = (1 << 12) + AM_ZM2 = (1 << 12), + AM_EIND = (1 << 13), + AM_EIND2 = (1 << 14), + AM_ABY = (1 << 15), + AM_ABX = (1 << 16), + AM_AIND = (1 << 17), + AM_AINDY = (1 << 18), + AM_AINDX = (1 << 19), }; enum ind { @@ -209,33 +218,59 @@ enum ind { STY_IND = 19 }; +enum eind { + DEC_EIND, + INC_EIND, + STY_EIND, + STA_EIND, + STB_EIND, + LDX_EIND, + STX_EIND, + CPB_EIND, + CPX_EIND, + CPY_EIND +}; + static const uint8_t ind_ops[20] = { - [CMP_IND] = 0x8C, - [CMP_IDY] = 0xF9, - [CMP_IDX] = 0xAA, - [CPB_IND] = 0x7C, - [CPB_IDY] = 0xFA, - [CPB_IDX] = 0xBA, - [JMP_IND] = 0xEC, - [JSR_IND] = 0xDC, - [LDA_IND] = 0xC4, - [LDA_IDY] = 0xD9, - [LDB_IND] = 0xE4, - [LDB_IDY] = 0xE9, - [LDX_IND] = 0xBC, - [LDY_IND] = 0xAC, - [STA_IND] = 0xD4, - [STA_IDY] = 0xCA, - [STB_IND] = 0xF4, - [STB_IDY] = 0xDA, - [STX_IND] = 0xCC, - [STY_IND] = 0x9C + [CMP_IND] = CMP_IN, + [CMP_IDY] = CMP_IY, + [CMP_IDX] = CMP_IX, + [CPB_IND] = CPB_IN, + [CPB_IDY] = CPB_IY, + [CPB_IDX] = CPB_IX, + [JMP_IND] = JMP_IN, + [JSR_IND] = JSR_IN, + [LDA_IND] = LDA_IN, + [LDA_IDY] = LDA_IY, + [LDB_IND] = LDB_IN, + [LDB_IDY] = LDB_IY, + [LDX_IND] = LDX_IN, + [LDY_IND] = LDY_IN, + [STA_IND] = STA_IN, + [STA_IDY] = STA_IY, + [STB_IND] = STB_IN, + [STB_IDY] = STB_IY, + [STX_IND] = STX_IN, + [STY_IND] = STY_IN +}; + +static const uint8_t eind_base_ops[10] = { + [DEC_EIND] = DEC_E, + [INC_EIND] = INC_E, + [STY_EIND] = STY_E, + [STA_EIND] = STA_E, + [STB_EIND] = STB_E, + [LDX_EIND] = LDX_E, + [STX_EIND] = STX_E, + [CPB_EIND] = CPB_E, + [CPX_EIND] = CPX_E, + [CPY_EIND] = CPY_E }; static const instruction inst[OPNUM] = { - [ADC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x01}, - [AND] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x41}, - [ASR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x62}, + [ADC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x01}, + [AND] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x41}, + [ASR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x62}, [BCC] = {(AM_REL), 0xA0}, [BCS] = {(AM_REL), 0x90}, [BEQ] = {(AM_REL), 0xB0}, @@ -249,31 +284,31 @@ static const instruction inst[OPNUM] = { [CLC] = {(AM_IMPL), 0x09}, [CLI] = {(AM_IMPL), 0x29}, [CLV] = {(AM_IMPL), 0x49}, - [CMP] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_BREG|AM_INDX2), 0x82}, - [CPB] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_INDX2), 0x04}, + [CMP] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_BREG|AM_INDX2|AM_EIND), 0x82}, + [CPB] = {(AM_IMM|AM_ZM|AM_IND|AM_INDY|AM_ABS|AM_INDX2|AM_EIND2), 0x04}, [CPS] = {(AM_IMPL), 0x00}, - [CPX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS), 0x24}, - [CPY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS), 0x44}, + [CPX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x24}, + [CPY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x44}, [DEB] = {(AM_IMPL), 0x99}, - [DEC] = {(AM_IMPL|AM_ZM|AM_ABS), 0x84}, + [DEC] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND2), 0x84}, [DEX] = {(AM_IMPL), 0xB9}, [DEY] = {(AM_IMPL), 0x79}, - [DIV] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x42}, + [DIV] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x42}, [INB] = {(AM_IMPL), 0xA9}, - [INC] = {(AM_IMPL|AM_ZM|AM_ABS), 0xA4}, + [INC] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND2), 0xA4}, [INX] = {(AM_IMPL), 0xC9}, [INY] = {(AM_IMPL), 0x89}, - [JMP] = {(AM_ABS|AM_IND|AM_ZM2), 0x00}, - [JSR] = {(AM_ABS|AM_IND|AM_ZM2), 0x20}, - [LDA] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS), 0xC2}, - [LDB] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS), 0xE2}, - [LDX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS), 0x64}, - [LDY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS), 0xA2}, - [LSL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0xA1}, - [LSR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0xC1}, - [MUL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x22}, + [JMP] = {(AM_ABS|AM_IND|AM_ZM2|AM_EIND), 0x00}, + [JSR] = {(AM_ABS|AM_IND|AM_ZM2|AM_EIND), 0x20}, + [LDA] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND), 0xC2}, + [LDB] = {(AM_IMM|AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND), 0xE2}, + [LDX] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x64}, + [LDY] = {(AM_IMM|AM_ZM|AM_IND|AM_ABS|AM_EIND), 0xA2}, + [LSL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0xA1}, + [LSR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0xC1}, + [MUL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x22}, [NOP] = {(AM_IMPL), 0xEA}, - [ORA] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x61}, + [ORA] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x61}, [PHA] = {(AM_IMPL), 0x8E}, [PHB] = {(AM_IMPL), 0xAE}, [PHP] = {(AM_IMPL), 0x6E}, @@ -284,29 +319,81 @@ static const instruction inst[OPNUM] = { [PLP] = {(AM_IMPL), 0x7E}, [PLX] = {(AM_IMPL), 0xFE}, [PLY] = {(AM_IMPL), 0xDE}, - [ROL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0xE1}, - [ROR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x02}, + [ROL] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0xE1}, + [ROR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x02}, [RTI] = {(AM_IMPL), 0x60}, [RTS] = {(AM_IMPL), 0x50}, - [SBC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x21}, + [SBC] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x21}, [SEC] = {(AM_IMPL), 0x19}, [SEI] = {(AM_IMPL), 0x39}, - [STA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS), 0x28}, - [STB] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS), 0x48}, - [STX] = {(AM_ZM|AM_IND|AM_ABS), 0x68}, - [STY] = {(AM_ZM|AM_IND|AM_ABS), 0x08}, + [STA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND2), 0x28}, + [STB] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_EIND2), 0x48}, + [STX] = {(AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x68}, + [STY] = {(AM_ZM|AM_IND|AM_ABS|AM_EIND2), 0x08}, [TAB] = {(AM_IMPL), 0x0A}, [TAX] = {(AM_IMPL), 0x4A}, [TAY] = {(AM_IMPL), 0x2A}, [TBA] = {(AM_IMPL), 0x1A}, [TSX] = {(AM_IMPL), 0x8A}, [TXA] = {(AM_IMPL), 0x5A}, - [TXS] = {(AM_IMPL|AM_IMM), 0x9A}, + [TXS] = {(AM_IMPL), 0x9A}, [TXY] = {(AM_IMPL), 0x7A}, [TYA] = {(AM_IMPL), 0x3A}, [TYX] = {(AM_IMPL), 0x6A}, [WAI] = {(AM_IMPL), 0x59}, - [XOR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG), 0x81} + [XOR] = {(AM_IMM|AM_ZM|AM_ABS|AM_BREG|AM_EIND), 0x81} +}; + +static const instruction ext_inst[EXT_OPNUM] = { + [LEA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_ABX|AM_ABY|AM_AIND|AM_AINDX|AM_AINDY), 0x03}, + [PEA] = {(AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_ABX|AM_ABY|AM_AIND|AM_AINDX|AM_AINDY), 0x23}, + [ADD] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x06}, + [SUB] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x26}, + [ADE] = {(AM_IMM|AM_ZM|AM_ABS), 0x46}, + [SBE] = {(AM_IMM|AM_ZM|AM_ABS), 0x66}, + [ADS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x86}, + [SBS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0xA6}, + [NOT] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND), 0xC6}, + [LLM] = {(AM_ZM|AM_ABS|AM_EIND), 0x48}, + [LRM] = {(AM_ZM|AM_ABS|AM_EIND), 0x68}, + [RLM] = {(AM_ZM|AM_ABS|AM_EIND), 0x88}, + [RRM] = {(AM_ZM|AM_ABS|AM_EIND), 0xA8}, + [ARM] = {(AM_ZM|AM_ABS|AM_EIND), 0xC8}, + [PHE] = {(AM_IMPL), 0x6B}, + [PLE] = {(AM_IMPL), 0x7B}, + [CPE] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x08}, + [ICE] = {(AM_ZM|AM_ABS|AM_EIND), 0x28}, + [LDS] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x40}, + [DEE] = {(AM_IMPL), 0x8B}, + [INE] = {(AM_IMPL), 0x9B}, + [DES] = {(AM_IMPL), 0xAB}, + [INS] = {(AM_IMPL), 0xBB}, + [STS] = {(AM_ZM|AM_ABS|AM_EIND), 0xA0}, + [STE] = {(AM_ZM|AM_ABS), 0xC0}, + [STZ] = {(AM_ZM|AM_ABS|AM_EIND), 0xE0}, + [SCO] = {(AM_IMM|AM_ZM|AM_ABS|AM_EIND), 0x60}, + [ECO] = {(AM_ZM|AM_ABS|AM_EIND), 0x80}, + [CLZ] = {(AM_ZM|AM_ABS|AM_EIND), 0x05}, + [CLO] = {(AM_ZM|AM_ABS|AM_EIND), 0x25}, + [BIT] = {(AM_ZM|AM_ABS|AM_EIND), 0x45}, + [MMV] = {(AM_IMPL), 0xCB}, + [SWP] = {(AM_IMPL|AM_ZM|AM_ABS|AM_EIND), 0xE6}, + [PCN] = {(AM_ZM|AM_ABS|AM_EIND), 0xE8}, + [REP] = {(AM_REL), 0xBD}, + [REQ] = {(AM_REL), 0xCD}, + [RNE] = {(AM_REL), 0xDD}, + [LNG] = {(AM_IMM|AM_EIND2), 0x0D}, + [LPO] = {(AM_IMM|AM_EIND2), 0x2D}, + [LCS] = {(AM_IMM|AM_EIND2), 0x4D}, + [LCC] = {(AM_IMM|AM_EIND2), 0x6D}, + [LEQ] = {(AM_IMM|AM_EIND2), 0x8D}, + [LNE] = {(AM_IMM|AM_EIND2), 0xAD}, + [SNG] = {(AM_EIND2), 0x1D}, + [SPO] = {(AM_EIND2), 0x3D}, + [SCS] = {(AM_EIND2), 0x5D}, + [SCC] = {(AM_EIND2), 0x7D}, + [SEQ] = {(AM_EIND2), 0x9D}, + [SNE] = {(AM_EIND2), 0xBD} }; static const char *dir_t[11] = { @@ -330,7 +417,7 @@ static const char *rs_t[4] = { [3] = ".q" }; -static const char *lex_tok[22] = { +static const char *lex_tok[23] = { [TOK_DIR ] = "TOK_DIR", [TOK_LOCAL ] = "TOK_LOCAL", [TOK_LABEL ] = "TOK_LABEL", @@ -343,6 +430,7 @@ static const char *lex_tok[22] = { [TOK_IMM ] = "TOK_IMM", [TOK_BREG ] = "TOK_BREG", [TOK_OPCODE ] = "TOK_OPCODE", + [TOK_EXTOP ] = "TOK_EXTOP", [TOK_RS ] = "TOK_RS", [TOK_OF ] = "TOK_OF", [TOK_COMMENT] = "TOK_COMMENT", @@ -355,18 +443,24 @@ static const char *lex_tok[22] = { [TOK_MEMBER ] = "TOK_MEMBER" }; -static const char *adrmode[11] = { - [IMM ] = "IMM", - [ZM ] = "ZM", - [ZMX ] = "ZMX", - [ZMY ] = "ZMY", - [IND ] = "IND", - [INDX] = "INDX", - [INDY] = "INDY", - [ABS ] = "ABS", - [REL ] = "REL", - [BREG] = "BREG", - [IMPL] = "IMPL" +static const char *adrmode[] = { + [IMM ] = "IMM", + [ZM ] = "ZM", + [ZMX ] = "ZMX", + [ZMY ] = "ZMY", + [IND ] = "IND", + [INDX ] = "INDX", + [INDY ] = "INDY", + [ABS ] = "ABS", + [REL ] = "REL", + [BREG ] = "BREG", + [IMPL ] = "IMPL", + [ABSX ] = "ABSX", + [ABSY ] = "ABSY", + [AIND ] = "AIND", + [AINDX] = "AINDX", + [AINDY] = "AINDY", + [EIND ] = "EIND" }; static const char *mne[OPNUM] = { @@ -446,6 +540,58 @@ static const char *mne[OPNUM] = { [XOR] = "XOR" }; +static const char *ext_mne[EXT_OPNUM] = { + [LEA] = "LEA", + [PEA] = "PEA", + [ADD] = "ADD", + [SUB] = "SUB", + [ADE] = "ADE", + [SBE] = "SBE", + [ADS] = "ADS", + [SBS] = "SBS", + [NOT] = "NOT", + [LLM] = "LLM", + [LRM] = "LRM", + [RLM] = "RLM", + [RRM] = "RRM", + [ARM] = "ARM", + [PHE] = "PHE", + [PLE] = "PLE", + [CPE] = "CPE", + [ICE] = "ICE", + [LDS] = "LDS", + [DEE] = "DEE", + [INE] = "INE", + [DES] = "DES", + [INS] = "INS", + [STS] = "STS", + [STE] = "STE", + [STZ] = "STZ", + [SCO] = "SCO", + [ECO] = "ECO", + [CLZ] = "CLZ", + [CLO] = "CLO", + [BIT] = "BIT", + [MMV] = "MMV", + [SWP] = "SWP", + [PCN] = "PCN", + [REP] = "REP", + [REQ] = "REQ", + [RNE] = "RNE", + [LNG] = "LNG", + [LPO] = "LPO", + [LCS] = "LCS", + [LCC] = "LCC", + [LEQ] = "LEQ", + [LNE] = "LNE", + [SNG] = "SNG", + [SPO] = "SPO", + [SCS] = "SCS", + [SCC] = "SCC", + [SEQ] = "SEQ", + [SNE] = "SNE" +}; + static const char *instdesc[OPNUM] = { [ADC] = "ADd accumulator, with operand, Carry if needed.", [AND] = "Bitwise AND accumulator, with operand.", @@ -1,5 +1,13 @@ #include "asmmon.h" +#define AM_ADDR (AM_ZM | AM_ZMX | AM_ZMY | \ + AM_IND | AM_INDX | AM_INDY | \ + AM_ABS | AM_ABX | AM_ABY | \ + AM_AIND | AM_AINDX | AM_AINDY | \ + AM_INDX2 | AM_ZM2) + +static const uint64_t mem_size = 0x04000000; /* Size of address space. */ + token *tok_global; uint8_t isexpr(uint8_t type, uint8_t dbg) { @@ -58,6 +66,38 @@ uint8_t get_ind(uint8_t mne, uint8_t am, uint8_t dbg) { return base_idx + offset; } +uint8_t get_eind(uint8_t mne, uint8_t dbg) { + switch (mne) { + case DEC: return DEC_EIND; + case INC: return INC_EIND; + case STY: return STY_EIND; + case STA: return STA_EIND; + case STB: return STB_EIND; + case LDX: return LDX_EIND; + case STX: return STX_EIND; + case CPB: return CPB_EIND; + case CPX: return CPX_EIND; + case CPY: return CPY_EIND; + } + return 0xFF; +} + +static void write_value(uint64_t value, uint64_t address, uint8_t size) { + if (address < mem_size) { + size = (size > 7) ? 7 : size; + #if 1 + if (size < 7) { + uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); + *(uint64_t *)(addr+address) = (*(uint64_t *)(addr+address) & ~mask) | (value & mask); + } else { + *(uint64_t *)(addr+address) = value; + } + #else + memcpy(addr+address, &value, size+1); + #endif + } +} + uint64_t get_val(token *t, uint64_t addr, uint8_t size, uint8_t dbg) { uint64_t value = 0; uint64_t tmp_val = 0; @@ -232,34 +272,14 @@ uint64_t handle_directive(token *t, bytecount *bc, uint8_t isasm, uint64_t addre case TOK_LABEL: val.u64 = get_val(t, tmpaddr, get_directivesize(type, dbg), dbg); switch (type) { - case DIR_QWORD: /* Falls through. */ - if (isasm) { - addr[tmpaddr+7] = val.u8[7]; - addr[tmpaddr+6] = val.u8[6]; - addr[tmpaddr+5] = val.u8[5]; - addr[tmpaddr+4] = val.u8[4]; - } - tmp += 4; - case DIR_DWORD: /* Falls through. */ - if (isasm) { - addr[tmpaddr+3] = val.u8[3]; - addr[tmpaddr+2] = val.u8[2]; - } - tmp += 2; - case DIR_WORD: /* Falls through. */ - if (isasm) { - addr[tmpaddr+1] = val.u8[1]; - } - tmp++; - case DIR_BYTE: - if (isasm) { - addr[tmpaddr ] = val.u8[0]; - } - tmp++; - tmpaddr += tmp; - bc->datasize += tmp; - break; + case DIR_QWORD: tmp = 8; break; + case DIR_DWORD: tmp = 4; break; + case DIR_WORD : tmp = 2; break; + case DIR_BYTE : tmp = 1; break; } + write_value(val.u64, tmpaddr, tmp-1); + tmpaddr += tmp; + bc->datasize += tmp; if (t->next && t->next->id == TOK_EXPR && isexpr(t->next->type, dbg)) { t = skip_expr(t, dbg); } @@ -303,21 +323,47 @@ uint64_t handle_directive(token *t, bytecount *bc, uint8_t isasm, uint64_t addre return tmpaddr; } +static uint8_t write_inst(uint8_t prefix, uint8_t ext_prefix, uint8_t opcode, uint64_t value, uint64_t address, uint8_t size, uint8_t isasm, uint8_t dbg) { + uint8_t inst_size = 0; + union reg ins; + if (prefix & 3) { + ins.u8[inst_size++] = prefix; + } + if ((ext_prefix & 0x0D) == 0x0D) { + ins.u8[inst_size++] = ext_prefix; + } + ins.u8[inst_size++] = opcode; + if (isasm) { + write_value(ins.u64, address, inst_size-1); + if (size) { + write_value(value, address+inst_size, size-1); + } + } + inst_size += size; + return inst_size; +} + uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, uint8_t dbg) { union reg val; uint8_t opsize; + uint8_t id; uint8_t instr; uint8_t opcode; + uint8_t ext_prefix = 0; uint8_t type; - uint16_t am = 0; + uint32_t am = 0; uint8_t tmp = 0; uint8_t prefix = 0; uint8_t rs = 0; uint8_t of = 0; uint8_t tmp_prefix = 0; + uint8_t inst_size = 0; + val.u64 = 0; + instruction ins; for (; t; t = t->next) { - if (t->id == TOK_OPCODE) { + if (t->id == TOK_OPCODE || t->id == TOK_EXTOP) { + id = t->id; instr = t->byte; type = t->type; } else { @@ -340,51 +386,47 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, } prefix = (tmp_prefix) ? ((tmp_prefix << 4) | 3) : 0; uint8_t isincdec = (instr == INC || instr == DEC); - uint8_t isimplied = (!t->next || (t->next->id == TOK_COMMENT)); - am = inst[instr].am; + uint8_t isimplied = ((!t->next || (t->next->id == TOK_COMMENT)) && type == 0xFF); + ins = (id == TOK_OPCODE) ? inst[instr] : ext_inst[instr]; + am = ins.am; + if (id == TOK_EXTOP || (id == TOK_OPCODE && type == EIND)) { + ext_prefix = 0x0D; + } if ((am & AM_IMPL) && isimplied) { type = IMPL; } else { - if (inst[instr].am & AM_REL) { + if (ins.am & AM_REL) { type = REL; } if (t->next) { t = t->next; } - val.u64 = get_val(t, address, (rs != 0xFF) ? rs : 0, dbg); - } - /* Special case for TXS. */ - if (instr == TXS) { - if (type == IMM) { - rs = 1; - } else { - type = IMPL; + if (type != BREG && type != EIND) { + val.u64 = get_val(t, address, (rs != 0xFF) ? rs : 0, dbg); } } - opcode = inst[instr].op; + opcode = ins.op; uint64_t saveaddr = address; uint64_t max_val = 0; uint8_t i = 0; uint8_t j = 1; + uint8_t type2 = 0xFF; switch (type) { case BREG: case IMPL: - if (instr == CPS) { + case EIND: + if (id == TOK_OPCODE && instr == CPS) { rs = 0; } - if ((am & (AM_IMPL|AM_BREG))) { - if ((am & AM_IMPL) && (prefix)) { - if (isasm) { - addr[address] = prefix; + if ((am & (AM_IMPL|AM_BREG|AM_EIND|AM_EIND2))) { + if ((type == EIND) && (am & AM_EIND|AM_EIND2)) { + int eind_type = ((am & AM_EIND2) != 0); + switch (eind_type) { + case 0: opcode = (id == TOK_EXTOP) ? opcode+0x14 : opcode+0x10; break; + case 1: opcode = (id == TOK_EXTOP) ? opcode+0x01 : eind_base_ops[get_eind(instr, dbg)]; break; } - address++; - bc->progsize++; } - if (isasm) { - addr[address] = (am & AM_BREG) ? opcode+0x14 : opcode; - } - address++; - bc->progsize++; + opcode = (am & AM_BREG) ? opcode+0x14 : opcode; } break; case REL: @@ -417,21 +459,6 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, } val.u64 = tmp_val; } - if (prefix) { - if (isasm) { - addr[address] = prefix; - } - address++; - bc->progsize++; - } - if (isasm) { - addr[address] = opcode; - } - address++; - bc->progsize++; - if (isasm) { - setreg(addr, +, address, val.u8, +, 0, tmp-1); - } } break; default: @@ -453,14 +480,32 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, } } } - if (type == 0xFF) { + type2 = type; + if (type == 0xFF || (id == TOK_EXTOP && type2 != 0xFF)) { switch (opsize-1) { case 0: case 2: case 5: case 3: type = ZM ; break; case 1: case 4: case 6: case 7: type = ABS; break; } } + switch (type2) { + case ZMX : type = (type == ABS) ? ABSX : type2; break; + case ZMY : type = (type == ABS) ? ABSY : type2; break; + case IND : type = (type == ABS) ? AIND : type2; break; + case INDX: type = (type == ABS) ? AINDX : type2; break; + case INDY: type = (type == ABS) ? AINDY : type2; break; + } if (opsize) { - if (type != ABS) { + uint8_t is_abs = 0; + switch (type) { + case ABS : + case ABSX : + case ABSY : + case AIND : + case AINDX: + case AINDY: is_abs = 1; break; + + } + if (!is_abs || (type2 != 0xFF && type == type2)) { switch (opsize) { case 2: opsize = 3; break; case 5: opsize = 6; break; @@ -468,7 +513,7 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, } prefix |= amp[opsize-1]; } - if (am & (AM_ZM|AM_ZMX|AM_ZMY|AM_IND|AM_INDX|AM_INDY|AM_ABS|AM_INDX2|AM_ZM2)) { + if (am & AM_ADDR) { switch (type) { case ZM: if (am & AM_ZM) { @@ -479,7 +524,7 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, break; case ZMX: if (am & AM_ZMX) { - opcode += 0x06; + opcode += (id == TOK_OPCODE) ? 0x06 : 0x54; } break; case ZMY: @@ -487,54 +532,59 @@ uint64_t handle_opcode(token *t, bytecount *bc, uint8_t isasm, uint64_t address, opcode += 0x14; } break; - case ABS: - if (am & AM_ABS) { - opcode += 0x10; - } - break; case INDX: if (am & AM_INDX) { - opcode += 0x16; + opcode += (id == TOK_OPCODE) ? 0x16 : 0x94; break; } /* Falls Through. */ case IND: case INDY: - if (am & (AM_IND|AM_INDY|AM_INDX2)) { + if ((id == TOK_OPCODE) && (am & (AM_IND|AM_INDY|AM_INDX2))) { opcode = ind_ops[get_ind(instr, type, dbg)]; + } else { + opcode += (type == IND) ? 0x44 : 0x84; } break; - } - if (prefix) { - if (isasm) { - addr[address] = prefix; - } - address++; - bc->progsize++; - } - if (isasm) { - addr[address] = opcode; - } - address++; - bc->progsize++; - if (isasm) { - switch (opsize-1) { - case 7: addr[address+7] = val.u8[7]; - case 6: addr[address+6] = val.u8[6]; - case 5: addr[address+5] = val.u8[5]; - case 4: addr[address+4] = val.u8[4]; - case 3: addr[address+3] = val.u8[3]; - case 2: addr[address+2] = val.u8[2]; - case 1: addr[address+1] = val.u8[1]; - case 0: addr[address ] = val.u8[0]; - } + case ABS: + if (am & AM_ABS) { + opcode += 0x10; + } + break; + case ABSX: + if (am & AM_ABX) { + opcode += 0x50; + } + break; + case ABSY: + if (am & AM_ABY) { + opcode += 0x00; + } + break; + case AIND: + if (am & AM_AIND) { + opcode += 0x40; + } + break; + case AINDX: + if (am & AM_AINDX) { + opcode += 0x90; + } + break; + case AINDY: + if (am & AM_AINDY) { + opcode += 0x80; + } + break; + } tmp = opsize; } break; } - address += tmp; - bc->progsize += tmp; + inst_size = write_inst(prefix, ext_prefix, opcode, val.u64, address, tmp, isasm, dbg); + address += inst_size; + bc->progsize += inst_size; } return address; } @@ -554,6 +604,7 @@ uint64_t parse_tokens(token *t, line **l, bytecount *bc, uint8_t isasm, uint64_t case DIR_QWORD: address = handle_directive(t, bc, isasm, address, dbg); break; } break; + case TOK_EXTOP : case TOK_OPCODE: address = handle_opcode(t, bc, isasm, address, dbg); break; case TOK_COMMENT: break; } @@ -10,10 +10,11 @@ void print_regs(struct sux *cpu, uint8_t lines, uint8_t thread) { wmove(scr, lines, 1); wclrtoeol(scr); wprintw(scr, "pc: $%04"PRIX64 , cpu->pc); - wprintw(scr, ", a: $%016"PRIX64, cpu->a); - wprintw(scr, ", b: $%016"PRIX64, cpu->b); - wprintw(scr, ", x: $%016"PRIX64, cpu->x); - wprintw(scr, ", y: $%016"PRIX64, cpu->y); + wprintw(scr, ", a: $%08"PRIX64, cpu->a); + wprintw(scr, ", b: $%08"PRIX64, cpu->b); + wprintw(scr, ", x: $%08"PRIX64, cpu->x); + wprintw(scr, ", y: $%08"PRIX64, cpu->y); + wprintw(scr, ", e: $%08"PRIX64, cpu->e); wprintw(scr, ", sp: $%"PRIX64, cpu->sp); wprintw(scr, ", ps: %c%c---%c%c%c", cpu->ps.u8[thread] & N ? 'N' : '-' , cpu->ps.u8[thread] & V ? 'V' : '-' @@ -23,9 +24,9 @@ void print_regs(struct sux *cpu, uint8_t lines, uint8_t thread) { wprintw(scr, ", inst: "); } -void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread) { +void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t thread) { uint64_t value; - uint64_t address = get_addr(cpu, opcode, prefix, 0, 0, thread); + uint64_t address = get_addr(cpu, opcode, prefix, ext_prefix, 0, 0, thread); uint8_t rs = (prefix >> 4) & 3; char *postfix; char *of; @@ -35,7 +36,17 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint uint8_t tmp = 0; union reg mask; mask.u64 = 0; - memcpy(op, opname[opcode], 3); + const char *inst_name; + uint8_t inst_type; + if ((ext_prefix & 0xD) == 0xD) { + switch (ext_prefix >> 4) { + case 0x0: inst_name = ext_opname[opcode]; inst_type = ext_optype[opcode]; break; + } + } else { + inst_name = opname[opcode]; + inst_type = optype[opcode]; + } + memcpy(op, inst_name, 3); op[3] = 0; switch (rs) { case 0: postfix = ""; break; @@ -53,28 +64,33 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint } uint8_t addrsize = 0; char *idx; - switch (optype[opcode]) { - case IND : idx = ")"; break; - case INDX: idx = ", x)"; break; - case INDY: idx = "), y"; break; - case ZMX : idx = ", x"; break; - case ZMY : idx = ", y"; break; - default : idx = ""; break; + switch (inst_type) { + case AIND : case IND : idx = ")"; break; + case AINDX: case INDX: idx = ", x)"; break; + case AINDY: case INDY: idx = "), y"; break; + case ABSX : case ZMX : idx = ", x"; break; + case ABSY : case ZMY : idx = ", y"; break; + default: idx = ""; break; } - switch (optype[opcode]) { - case ZM : - case ZMX : - case ZMY : - case IND : - case INDX: - case INDY: addrsize = get_addrsize(prefix, ZM); break; - case ABS : addrsize = get_addrsize(prefix, ABS); break; - case IMM : - case REL : addrsize = (1 << rs)-1; break; + switch (inst_type) { + case ZM : + case ZMX : + case ZMY : + case IND : + case INDX : + case INDY : addrsize = get_addrsize(prefix, ZM); break; + case ABS : + case AIND : + case AINDX: + case AINDY: + case ABSX : + case ABSY : addrsize = get_addrsize(prefix, ABS); break; + case IMM : + case REL : addrsize = (1 << rs)-1; break; } mask.u64 = (-(uint64_t)1 >> ((7 - addrsize) * 8)); value = read_value(cpu, 0, cpu->pc, addrsize, 0, 0); - if ((prefix >> 6) == 1 || (prefix >> 6) == 2 || optype[opcode] == REL) { + if ((prefix >> 6) == 1 || (prefix >> 6) == 2 || inst_type == REL) { switch (addrsize) { case 0 : sign = ((int8_t )value < 0) ? "-" : "+"; break; case 1 : sign = ((int16_t)value < 0) ? "-" : "+"; break; @@ -87,18 +103,24 @@ void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint } value = (sign[0] == '-') ? (~value + 1) & mask.u64 : value; } - switch (optype[opcode]) { - case BREG: - case IMPL: wprintw(scr, "%s%s" , opname[opcode], postfix); break; - case IMM : wprintw(scr, "%s%s #$%0*"PRIX64 , op, postfix, (addrsize+1) << 1, value); break; - case IND : - case INDX: - case INDY: ind = "("; /* Falls through. */ - case ZMX : - case ZMY : - case ZM : - case ABS : wprintw(scr, "%s%s %s%s%s$%0*" PRIX64"%s" , op, postfix, ind, of, sign, (addrsize+1) << 1, value, idx); break; - case REL : wprintw(scr, "%s%s %s$%0*"PRIX64 , op, postfix, sign, (addrsize+1) << 1, value); break; + switch (inst_type) { + case EIND : + case BREG : + case IMPL : wprintw(scr, "%s%s" , inst_name, postfix); break; + case IMM : wprintw(scr, "%s%s #$%0*"PRIX64 , op, postfix, (addrsize+1) << 1, value); break; + case AIND : + case AINDX: + case AINDY: + case IND : + case INDX : + case INDY : ind = "("; /* Falls through. */ + case ZMX : + case ZMY : + case ABSX : + case ABSY : + case ZM : + case ABS : wprintw(scr, "%s%s %s%s%s$%0*" PRIX64"%s" , op, postfix, ind, of, sign, (addrsize+1) << 1, value, idx); break; + case REL : wprintw(scr, "%s%s %s$%0*"PRIX64 , op, postfix, sign, (addrsize+1) << 1, value); break; } if (address == TX_ADDR || address == RX_ADDR) { @@ -102,7 +102,7 @@ static const char *opname[0x100] = { [XOR_B ] = "XOR B", [CMP_B ] = "CMP B", [DEB_IMP ] = "DEB", - [TXS_IMM ] = "TXS #", + [TXS_IMP ] = "TXS", [STY_IN ] = "STY ind", [PLA_IMP ] = "PLA", [BCC_REL ] = "BCC rel", @@ -169,3 +169,169 @@ static const char *opname[0x100] = { [CPB_IY ] = "CPB indy", [PLX_IMP ] = "PLX" }; + +static const char *ext_opname[0x100] = { + [LEA_AY ] = "LEA a, y", + [ADD_IMM] = "ADD #", + [LEA_Z ] = "LEA zm", + [CPE_IMM] = "CPE #", + [CLZ_Z ] = "CLZ zm", + [ADD_Z ] = "ADD zm", + [STB_E ] = "STB (E)", + [CPE_Z ] = "CPE zm", + [LNG_IMM] = "LNG #", + [LNG_E ] = "LNG (E)", + [JMP_E ] = "JMP (E)", + [ADC_E ] = "ADC (E)", + [ROR_E ] = "ROR (E)", + [LEA_AB ] = "LEA a", + [CLZ_AB ] = "CLZ a", + [ADD_AB ] = "ADD a", + [LEA_ZY ] = "LEA zm, y", + [CPE_AB ] = "CPE a", + [CLZ_E ] = "CLZ (E)", + [ADD_E ] = "ADD (E)", + [LDX_E ] = "LDX (E)", + [SNG_E ] = "SNG (E)", + [PEA_AY ] = "PEA a, y", + [SUB_IMM] = "SUB #", + [PEA_Z ] = "PEA zm", + [CLO_Z ] = "CLO zm", + [SUB_Z ] = "SUB zm", + [STX_E ] = "STX (E)", + [ICE_Z ] = "ICE (E)", + [LPO_IMM] = "LPO #", + [LPO_E ] = "LPO (E)", + [JSR_E ] = "JSR (E)", + [SBC_E ] = "SBC (E)", + [MUL_E ] = "MUL (E)", + [PEA_AB ] = "PEA a", + [CLO_AB ] = "CLO a", + [SUB_AB ] = "SUB a", + [PEA_ZY ] = "PEA zm, y", + [ICE_AB ] = "ICE a", + [CLO_E ] = "CLO (E)", + [SUB_E ] = "SUB (E)", + [CPB_E ] = "CPB (E)", + [ICE_E ] = "ICE (E)", + [SPO_E ] = "SPO (E)", + [LDS_IMM] = "LDS #", + [LEA_AI ] = "LEA (a)", + [LDS_Z ] = "LDS zm", + [ADE_IMM] = "ADE #", + [LEA_IN ] = "LEA (zm)", + [BIT_Z ] = "BIT zm", + [ADE_Z ] = "ADE zm", + [CPX_E ] = "CPX (E)", + [LLM_Z ] = "LLM zm", + [LCS_IMM] = "LCS #", + [LCS_E ] = "LCS (E)", + [LDS_AB ] = "LDS a", + [AND_E ] = "AND (E)", + [DIV_E ] = "DIV (E)", + [LEA_AX ] = "LEA a, x", + [LDS_E ] = "LDS (E)", + [BIT_AB ] = "BIT a", + [ADE_AB ] = "ADE a", + [LEA_ZX ] = "LEA zm, x", + [LLM_AB ] = "LLM a", + [BIT_E ] = "BIT (E)", + [CPY_E ] = "CPY (E)", + [LLM_E ] = "LLM (E)", + [SCS_E ] = "SCS (E)", + [SCO_IMM] = "SCO #", + [PEA_AI ] = "PEA (a)", + [SCO_Z ] = "SCO zm", + [SBE_IMM] = "SBE #", + [PEA_IN ] = "PEA (zm)", + [SBE_Z ] = "SBE zm", + [PHE_IMP] = "PHE", + [LRM_Z ] = "LRM zm", + [LCC_IMM] = "LCC #", + [LCC_E ] = "LCC (E)", + [SCO_AB ] = "SCO a", + [ORA_E ] = "ORA (E)", + [ASR_E ] = "ASR (E)", + [PEA_AX ] = "PEA a, x", + [SCO_E ] = "SCO (E)", + [SBE_AB ] = "SBE a", + [PEA_ZX ] = "PEA zm, x", + [LRM_AB ] = "LRM a", + [PLE_IMP] = "PLE", + [LRM_E ] = "LRM (E)", + [SCC_E ] = "SCC (E)", + [ECO_IMM] = "ECO #", + [DEC_E ] = "DEC (E)", + [LEA_AIY] = "LEA (a), y", + [ECO_Z ] = "ECO zm", + [ADS_IMM] = "ADS #", + [LEA_IY ] = "LEA (zm), y", + [ADS_Z ] = "ADS zm", + [DEE_IMP] = "DEE", + [RLM_Z ] = "RLM zm", + [LEQ_IMM] = "LEQ #", + [LEQ_E ] = "LEQ (E)", + [ECO_AB ] = "ECO a", + [XOR_E ] = "XOR (E)", + [CMP_E ] = "CMP (E)", + [LEA_AIX] = "LEA (a, x)", + [ECO_E ] = "ECO (E)", + [ADS_AB ] = "ADS a", + [LEA_IX ] = "LEA (zm, x)", + [RLM_AB ] = "RLM a", + [ADS_E ] = "ADS (E)", + [INE_IMP] = "INE", + [RLM_E ] = "RLM (E)", + [SEQ_E ] = "SEQ (E)", + [INC_E ] = "INC (E)", + [PEA_AIY] = "PEA (a), y", + [STS_Z ] = "STS zm", + [SBS_IMM] = "SBS #", + [PEA_IY ] = "PEA (zm), y", + [SBS_Z ] = "SBS zm", + [DES_IMP] = "DES", + [RRM_Z ] = "RRM zm", + [LNE_IMM] = "LNE #", + [LNE_E ] = "LNE (E)", + [STS_AB ] = "STS a", + [LSL_E ] = "LSL (E)", + [LDY_E ] = "LDY (E)", + [PEA_AIX] = "PEA (a, x)", + [STS_E ] = "STS (E)", + [SBS_AB ] = "SBS a", + [PEA_IX ] = "PEA (zm, x)", + [RRM_AB ] = "RRM a", + [SBS_E ] = "SBS (E)", + [INS_IMP] = "INS", + [RRM_E ] = "RRM (E)", + [REP_REL] = "REP rel", + [SNE_E ] = "SNE (E)", + [STY_E ] = "STY (E)", + [STE_Z ] = "STE zm", + [NOT_A ] = "NOT A", + [NOT_Z ] = "NOT zm", + [MMV_IMP] = "MMV", + [ARM_Z ] = "ARM zm", + [REQ_REL] = "REQ rel", + [STE_AB ] = "STE a", + [LSR_E ] = "LSR (E)", + [LDA_E ] = "LDA (E)", + [NOT_AB ] = "NOT a", + [ARM_AB ] = "ARM a", + [NOT_E ] = "NOT (E)", + [ARM_E ] = "ARM (E)", + [RNE_REL] = "RNE rel", + [STA_E ] = "STA (E)", + [STZ_Z ] = "STZ zm", + [SWP_A ] = "SWP A", + [SWP_Z ] = "SWP zm", + [PCN_Z ] = "PCN zm", + [STZ_AB ] = "STZ a", + [ROL_E ] = "ROL (E)", + [LDB_E ] = "LDB (E)", + [STZ_E ] = "STZ (E)", + [SWP_AB ] = "SWP a", + [PCN_AB ] = "PCN a", + [SWP_E ] = "SWP (E)", + [PCN_E ] = "PCN (E)" +}; @@ -1,26 +1,23 @@ enum am { /* Part of Base ISA. */ - IMM, /* Immediate Data. */ - ZM, /* Zero Matrix. */ - ZMX, /* Zero Matrix, indexed with X. */ - ZMY, /* Zero Matrix, indexed with Y. */ - IND, /* Indirect. */ - INDX, /* Indexed Indirect. */ - INDY, /* Indirect Indexed. */ - ABS, /* Absolute. */ - REL, /* Relative to Program Counter. */ - BREG, /* B Register. */ - IMPL, /* Implied. */ + IMM, /* Immediate Data. */ + ZM, /* Zero Matrix. */ + ZMX, /* Zero Matrix, indexed with X. */ + ZMY, /* Zero Matrix, indexed with Y. */ + IND, /* Indirect. */ + INDX, /* Indexed Indirect. */ + INDY, /* Indirect Indexed. */ + ABS, /* Absolute. */ + REL, /* Relative to Program Counter. */ + BREG, /* B Register. */ + IMPL, /* Implied. */ /* Part of Base Extension. */ - ABSX, /* Absolute, Indexed with X. */ - ABSY, /* Absolute, Indexed with Y. */ - SPI, /* Stack Pointer, Immediate Offset. */ - SPX, /* Stack Pointer, Offset with X. */ - SPY, /* Stack Pointer, Offset with Y. */ - INA, /* Absolute Indirect. */ - INAX, /* Absolute Indexed Indirect. */ - INAY, /* Absolute Indirect Indexed. */ - EIND, /* Effective Address Register, Indirect. */ + ABSX, /* Absolute, Indexed with X. */ + ABSY, /* Absolute, Indexed with Y. */ + AIND, /* Absolute Indirect. */ + AINDX, /* Absolute Indexed Indirect. */ + AINDY, /* Absolute Indirect Indexed. */ + EIND, /* Effective Address Register, Indirect. */ }; enum mne { @@ -100,6 +97,58 @@ enum mne { XOR }; +enum ext_mne { + LEA, + PEA, + ADD, + SUB, + ADE, + SBE, + ADS, + SBS, + NOT, + LLM, + LRM, + RLM, + RRM, + ARM, + PHE, + PLE, + CPE, + ICE, + LDS, + DEE, + INE, + DES, + INS, + STS, + STE, + STZ, + SCO, + ECO, + CLZ, + CLO, + BIT, + MMV, + SWP, + PCN, + REP, + REQ, + RNE, + LNG, + LPO, + LCS, + LCC, + LEQ, + LNE, + SNG, + SPO, + SCS, + SCC, + SEQ, + SNE +}; + enum base_isa { CPS_IMP = 0x00, /* Clear Processor Status. */ ADC_IMM = 0x01, /* ADd with Carry. */ @@ -204,7 +253,7 @@ enum base_isa { XOR_B = 0x95, /* XOR B Register. */ CMP_B = 0x96, /* CMP B Register. */ DEB_IMP = 0x99, /* Decrement B register. */ - TXS_IMM = 0x9A, /* Transfer X to Stack pointer. */ + TXS_IMP = 0x9A, /* Transfer X to Stack pointer. */ STY_IN = 0x9C, /* STY Indirect */ PLA_IMP = 0x9E, /* PuLl Accumulator from stack. */ BCC_REL = 0xA0, /* Branch if Carry Clear. */ @@ -273,122 +322,167 @@ enum base_isa { }; enum base_ext { - ADC_E = 0x01, /* ADC E Indirect. */ - LEA_ZX = 0x02, /* LEA Zero Matrix, indexed with X. */ - LEA_SX = 0x03, /* LEA Stack Pointer, offset with X. */ - ADD = 0x04, /* ADD without carry. */ - LLM = 0x05, /* Logical shift Left, on Memory. */ - PHE = 0x08, /* PusH Effective address register to stack. */ - CPB_E = 0x09, /* CPB E Indirect. */ - DEC_E = 0x0C, /* DEC E Indirect. */ + LEA_AY = 0x03, /* LEA Absolute, indexed with Y. */ + ADD_IMM = 0x06, /* ADD without carry. */ + LEA_Z = 0x07, /* Load Effective Address. */ + CPE_IMM = 0x08, /* ComPare Effective address register. */ + CLZ_Z = 0x09, /* Count Leading Zeros. */ + ADD_Z = 0x0A, /* ADD Zero Matrix. */ + STB_E = 0x0B, /* STB E Indirect. */ + CPE_Z = 0x0C, /* CPE Zero Matrix. */ + LNG_IMM = 0x0D, /* Load accumulator, if NeGative. */ + LNG_E = 0x0E, /* LNG E Indirect. */ JMP_E = 0x10, /* JMP E Indirect. */ - SBC_E = 0x11, /* SBC E Indirect. */ - LEA_ZY = 0x12, /* LEA Zero Matrix, indexed with Y. */ - LEA_SY = 0x13, /* LEA Stack Pointer, offset with Y. */ - ADD_E = 0x14, /* ADD E Indirect. */ - LLM_Z = 0x15, /* LLM Zero Matrix. */ - CPY_E = 0x19, /* CPY E Indirect. */ - INC_E = 0x1C, /* INC E Indirect. */ - JSR_E = 0x20, /* JSR E Indirect. */ - AND_E = 0x21, /* AND E Indirect. */ - PEA_ZX = 0x22, /* PEA Zero Matrix, indexed with X. */ - PEA_SX = 0x23, /* PEA Stack Pointer, offset with X. */ - SUB = 0x24, /* SUBtract without carry. */ - LLM_E = 0x25, /* LLM E Indirect. */ - PLE = 0x28, /* PuLl Effective address register from stack. */ - CPX_E = 0x29, /* CPX E Indirect. */ - DEE = 0x2C, /* DEcrement Effective address register. */ - BPO_E = 0x30, /* BPO E Indirect. */ - ORA_E = 0x31, /* ORA E Indirect. */ - PEA_ZY = 0x32, /* PEA Zero Matrix, indexed with Y. */ - PEA_SY = 0x33, /* PEA Stack Pointer, offset with Y. */ - SUB_E = 0x34, /* SUB E Indirect. */ - LRM = 0x35, /* Logical shift Right, on Memory. */ - CPE = 0x39, /* ComPare Effective address register. */ - INE = 0x3C, /* INcrement Effective address register. */ - BNG_E = 0x40, /* BNG E Indirect. */ - XOR_E = 0x41, /* XOR E Indirect. */ - LEA_AX = 0x42, /* LEA Absolute, indexed with X. */ - LEA_SI = 0x43, /* LEA Stack Pointer, Immediate offset. */ - ADE = 0x44, /* ADd Effective address register. */ - LRM_Z = 0x45, /* LRM Zero Matrix. */ - CPE_AB = 0x49, /* CPE Absolute. */ - DES = 0x4C, /* DEcrement Stack pointer. */ - BCS_E = 0x50, /* BCS E Indirect. */ - LSL_E = 0x51, /* LSL E Indirect. */ - LEA_AY = 0x52, /* LEA Absolute, indexed with Y. */ - LEA_RE = 0x53, /* LEA Relative. */ - ADE_A = 0x54, /* ADE with Accumulator. */ - LRM_E = 0x55, /* LRM E Indirect. */ - CPE_Z = 0x59, /* CPE Zero Matrix. */ - INS = 0x5C, /* INcrement Stack pointer. */ - BCC_E = 0x60, /* BCC E Indirect. */ - LSR_E = 0x61, /* LSR E Indirect. */ - PEA_AX = 0x62, /* PEA Absolute, indexed with X. */ - PEA_SI = 0x63, /* PEA Stack Pointer, Immediate offset. */ - SBE = 0x64, /* SuBtract Effective address register. */ - RLM = 0x65, /* Rotate Left, on Memory. */ - ICE = 0x69, /* Interlocked Compare, and Exchange. */ - BEQ_E = 0x70, /* BEQ E Indirect. */ - ROL_E = 0x71, /* ROL E Indirect. */ - PEA_AY = 0x72, /* PEA Absolute, indexed with Y. */ - PEA_RE = 0x73, /* PEA Relative. */ - RLM_Z = 0x75, /* RLM Zero Matrix. */ - ICE_Z = 0x79, /* ICE Zero Matrix. */ - STE = 0x7C, /* STore Effective address register. */ - BNE_E = 0x80, /* BNE E Indirect. */ - ROR_E = 0x81, /* ROR E Indirect. */ - LEA_IX = 0x82, /* LEA Indexed Indirect. */ - LEA_IN = 0x83, /* LEA Indirect. */ - ADS = 0x84, /* ADd Stack pointer. */ - RLM_E = 0x85, /* RLM E Indirect. */ - ICE_E = 0x89, /* ICE E Indirect. */ - STE_Z = 0x8C, /* STE Zero Matrix. */ - BVS_E = 0x90, /* BVS E Indirect. */ - MUL_E = 0x91, /* MUL E Indirect. */ - LEA_IY = 0x92, /* LEA Indirect Indexed. */ - LEA_AI = 0x93, /* LEA Absolute Indirect. */ - ADS_A = 0x94, /* ADS with Accumulator. */ - RRM = 0x95, /* Rotate Right, on Memory. */ - STZ = 0x9C, /* STore Zero. */ - BVC_E = 0xA0, /* BVC E Indirect. */ - DIV_E = 0xA1, /* DIV E Indirect. */ - PEA_IX = 0xA2, /* PEA Indexed Indirect. */ - PEA_IN = 0xA3, /* PEA Indirect. */ - SBS = 0xA4, /* SuBtract Stack pointer. */ - RRM_ZM = 0xA5, /* RRM Zero Matrix. */ - STZ_ZM = 0xAC, /* STZ Zero Matrix. */ - CMP_E = 0xB1, /* CMP E Indirect. */ - PEA_IY = 0xB2, /* PEA Indirect Indexed. */ - PEA_AI = 0xB3, /* PEA Absolute Indirect. */ - SBS_A = 0xB4, /* SBS with Accumulator. */ - RRM_E = 0xB5, /* RRM E Indirect. */ - LDX_E = 0xB9, /* LDX E Indirect. */ - STZ_E = 0xBC, /* STZ E Indirect. */ - LDA_E = 0xC1, /* LDA E Indirect. */ - LEA_AIX = 0xC2, /* LEA Absolute Indexed Indirect. */ - LEA_Z = 0xC3, /* LEA Zero Matrix. */ - NOT = 0xC4, /* bitwise NOT with accumulator. */ - ARM = 0xC5, /* Arithmetic shift Right, on Memory. */ - LDE = 0xC9, /* LoaD Effective address register. */ - STA_E = 0xCC, /* STA E Indirect. */ - LDB_E = 0xD1, /* LDB E Indirect. */ - LEA_AIY = 0xD2, /* LEA Absolute Indirect Indexed. */ - LEA = 0xD3, /* Load Effective Address. */ - NOT_AB = 0xD4, /* NOT Absolute. */ - ARM_Z = 0xD5, /* ARM Zero Matrix. */ - LDE_AB = 0xD9, /* LDE Absolute. */ - STB_E = 0xDC, /* STB E Indirect. */ - LDY_E = 0xE1, /* LDY E Indirect. */ - PEA_AIX = 0xE2, /* PEA Absolute Indexed Indirect. */ - PEA_Z = 0xE3, /* PEA Zero Matrix. */ - NOT_Z = 0xE4, /* NOT Zero Matrix. */ - ARM_E = 0xE5, /* ARM E Indirect. */ - LDE_Z = 0xE9, /* LDE Zero Matrix. */ - STY_E = 0xEC, /* STY E Indirect. */ - ASR_E = 0xF1, /* ASR E Indirect. */ - PEA_AIY = 0xF2, /* PEA Absolute Indirect Indexed. */ - PEA = 0xF3, /* Push Effective Address. */ - NOT_E = 0xF4, /* NOT E Indirect. */ - STX_E = 0xFC, /* STX E Indirect. */ + ADC_E = 0x11, /* ADC E Indirect. */ + ROR_E = 0x12, /* ROR E Indirect. */ + LEA_AB = 0x13, /* LEA Absolute. */ + CLZ_AB = 0x15, /* CLZ Absolute. */ + ADD_AB = 0x16, /* ADD Absolute. */ + LEA_ZY = 0x17, /* LEA Zero Matrix, indexed with Y. */ + CPE_AB = 0x18, /* CPE Absolute. */ + CLZ_E = 0x19, /* CLZ E Indirect. */ + ADD_E = 0x1A, /* ADD E Indirect. */ + LDX_E = 0x1B, /* LDX E Indirect. */ + SNG_E = 0x1E, /* Store accumulator, if NeGative. */ + PEA_AY = 0x23, /* PEA Absolute, indexed with Y. */ + SUB_IMM = 0x26, /* SUBtract without carry. */ + PEA_Z = 0x27, /* Push Effective Address. */ + CLO_Z = 0x29, /* Count Leading Ones. */ + SUB_Z = 0x2A, /* SUB Zero Matrix. */ + STX_E = 0x2B, /* STX E Indirect. */ + ICE_Z = 0x2C, /* Interlocked Compare, and Exchange. */ + LPO_IMM = 0x2D, /* Load accumulator, if POsitive. */ + LPO_E = 0x2E, /* LPO E Indirect. */ + JSR_E = 0x30, /* JSR E Indirect. */ + SBC_E = 0x31, /* SBC E Indirect. */ + MUL_E = 0x32, /* MUL E Indirect. */ + PEA_AB = 0x33, /* PEA Absolute. */ + CLO_AB = 0x34, /* CLO Absolute. */ + SUB_AB = 0x35, /* SUB Absolute. */ + PEA_ZY = 0x37, /* PEA Zero Matrix, indexed with Y. */ + ICE_AB = 0x38, /* ICE Absolute. */ + CLO_E = 0x39, /* CLO E Indirect. */ + SUB_E = 0x3A, /* SUB E Indirect. */ + CPB_E = 0x3B, /* CPB E Indirect. */ + ICE_E = 0x3C, /* ICE E Indirect. */ + SPO_E = 0x3E, /* Store accumulator, if POsitive. */ + LDS_IMM = 0x40, /* LoaD Stack pointer. */ + LEA_AI = 0x43, /* LEA Absolute Indirect. */ + LDS_Z = 0x44, /* LDS Zero Matrix. */ + ADE_IMM = 0x46, /* ADd Effective address register. */ + LEA_IN = 0x47, /* LEA Indirect. */ + BIT_Z = 0x49, /* BIt Test. */ + ADE_Z = 0x4A, /* ADE Zero Matrix. */ + CPX_E = 0x4B, /* CPX E Indirect. */ + LLM_Z = 0x4C, /* Logical shift Left, on Memory. */ + LCS_IMM = 0x4D, /* Load accumulator, if Carry Set. */ + LCS_E = 0x4E, /* LCS E Indirect. */ + LDS_AB = 0x50, /* LDS Absolute. */ + AND_E = 0x51, /* AND E Indirect. */ + DIV_E = 0x52, /* DIV E Indirect. */ + LEA_AX = 0x53, /* LEA Absolute, indexed with X. */ + LDS_E = 0x54, /* LDS E Indirect. */ + BIT_AB = 0x55, /* BIT Absolute. */ + ADE_AB = 0x56, /* ADE Absolute. */ + LEA_ZX = 0x57, /* LEA Zero Matrix, indexed with X. */ + LLM_AB = 0x58, /* LLM Absolute. */ + BIT_E = 0x59, /* BIT E Indirect. */ + CPY_E = 0x5B, /* CPY E Indirect. */ + LLM_E = 0x5C, /* LLM E Indirect. */ + SCS_E = 0x5E, /* Store accumulator, if Carry Set. */ + SCO_IMM = 0x60, /* Start one, or more COre(s). */ + PEA_AI = 0x63, /* PEA Absolute Indirect. */ + SCO_Z = 0x64, /* SCO Zero Matrix. */ + SBE_IMM = 0x66, /* SuBtract Effective address register. */ + PEA_IN = 0x67, /* PEA Indirect. */ + SBE_Z = 0x6A, /* SBE Zero Matrix. */ + PHE_IMP = 0x6B, /* PusH Effective address register to stack. */ + LRM_Z = 0x6C, /* Logical shift Right, on Memory. */ + LCC_IMM = 0x6D, /* Load accumulator, if Carry Clear. */ + LCC_E = 0x6E, /* LCC E Indirect. */ + SCO_AB = 0x70, /* SCO Absolute. */ + ORA_E = 0x71, /* ORA E Indirect. */ + ASR_E = 0x72, /* ASR E Indirect. */ + PEA_AX = 0x73, /* PEA Absolute, indexed with X. */ + SCO_E = 0x74, /* SCO E Indirect. */ + SBE_AB = 0x76, /* SBE Absolute. */ + PEA_ZX = 0x77, /* PEA Zero Matrix, indexed with X. */ + LRM_AB = 0x78, /* LRM Absolute. */ + PLE_IMP = 0x7B, /* PuLl Effective address register from stack. */ + LRM_E = 0x7C, /* LRM E Indirect. */ + SCC_E = 0x7E, /* Store accumulator, if Carry Clear. */ + ECO_IMM = 0x80, /* End one, or more COre(s). */ + DEC_E = 0x82, /* DEC E Indirect. */ + LEA_AIY = 0x83, /* LEA Absolute Indirect Indexed. */ + ECO_Z = 0x84, /* ECO Zero Matrix. */ + ADS_IMM = 0x86, /* ADd Stack pointer. */ + LEA_IY = 0x87, /* LEA Indirect Indexed. */ + ADS_Z = 0x8A, /* ADS Zero Matrix. */ + DEE_IMP = 0x8B, /* DEcrement Effective address register. */ + RLM_Z = 0x8C, /* Rotate Left, on Memory. */ + LEQ_IMM = 0x8D, /* Load accumulator, if EQual. */ + LEQ_E = 0x8E, /* LEQ E Indirect. */ + ECO_AB = 0x90, /* ECO Absolute. */ + XOR_E = 0x91, /* XOR E Indirect. */ + CMP_E = 0x92, /* CMP E Indirect. */ + LEA_AIX = 0x93, /* LEA Absolute Indexed Indirect. */ + ECO_E = 0x94, /* ECO E Indirect. */ + ADS_AB = 0x96, /* ADS Absolute. */ + LEA_IX = 0x97, /* LEA Indexed Indirect. */ + RLM_AB = 0x98, /* RLM Absolute. */ + ADS_E = 0x9A, /* ADS E Indirect. */ + INE_IMP = 0x9B, /* INcrement Effective address register. */ + RLM_E = 0x9C, /* RLM E Indirect. */ + SEQ_E = 0x9E, /* Store accumulator, if EQual. */ + INC_E = 0xA2, /* INC E Indirect. */ + PEA_AIY = 0xA3, /* PEA Absolute Indirect Indexed. */ + STS_Z = 0xA4, /* STore Stack pointer. */ + SBS_IMM = 0xA6, /* SuBtract Stack pointer. */ + PEA_IY = 0xA7, /* PEA Indirect Indexed. */ + SBS_Z = 0xAA, /* SBS Zero Matrix. */ + DES_IMP = 0xAB, /* DEcrement Stack pointer. */ + RRM_Z = 0xAC, /* Rotate Right, on Memory. */ + LNE_IMM = 0xAD, /* Load accumulator, if Not Equal. */ + LNE_E = 0xAE, /* LNE E Indirect. */ + STS_AB = 0xB0, /* STS Absolute. */ + LSL_E = 0xB1, /* LSL E Indirect. */ + LDY_E = 0xB2, /* LDY E Indirect. */ + PEA_AIX = 0xB3, /* PEA Absolute Indexed Indirect. */ + STS_E = 0xB4, /* STS E Indirect. */ + SBS_AB = 0xB6, /* SBS Absolute. */ + PEA_IX = 0xB7, /* PEA Indexed Indirect. */ + RRM_AB = 0xB8, /* RRM Absolute. */ + SBS_E = 0xBA, /* SBS E Indirect. */ + INS_IMP = 0xBB, /* INcrement Stack pointer. */ + RRM_E = 0xBC, /* RRM E Indirect. */ + REP_REL = 0xBD, /* REPeat until counter is zero. */ + SNE_E = 0xBE, /* Store accumulator, if Not Equal. */ + STY_E = 0xC2, /* STY E Indirect. */ + STE_Z = 0xC4, /* STore Effective address register. */ + NOT_A = 0xC6, /* bitwise NOT with accumulator. */ + NOT_Z = 0xCA, /* NOT Zero Matrix. */ + MMV_IMP = 0xCB, /* Memory MoVe. */ + ARM_Z = 0xCC, /* Arithmetic shift Right, on Memory. */ + REQ_REL = 0xCD, /* Repeat until either counter is zero, or zero flag isn't set. */ + STE_AB = 0xD0, /* STE Absolute. */ + LSR_E = 0xD1, /* LSR E Indirect. */ + LDA_E = 0xD2, /* LDA E Indirect. */ + NOT_AB = 0xD6, /* NOT Absolute. */ + ARM_AB = 0xD8, /* ARM Absolute. */ + NOT_E = 0xDA, /* NOT E Indirect. */ + ARM_E = 0xDC, /* ARM E Indirect. */ + RNE_REL = 0xDD, /* Repeat until either counter is zero, or zero flag is set. */ + STA_E = 0xE2, /* STA E Indirect. */ + STZ_Z = 0xE4, /* STore Zero. */ + SWP_A = 0xE6, /* SWaP lower half, with upper half. */ + SWP_Z = 0xEA, /* SWP Zero Matrix. */ + PCN_Z = 0xEC, /* Population CouNt. */ + STZ_AB = 0xF0, /* STZ Absolute. */ + ROL_E = 0xF1, /* ROL E Indirect. */ + LDB_E = 0xF2, /* LDB E Indirect. */ + STZ_E = 0xF4, /* STZ E Indirect. */ + SWP_AB = 0xF6, /* SWP Absolute. */ + PCN_AB = 0xF8, /* PCN Absolute. */ + SWP_E = 0xFA, /* SWP E Indirect. */ + PCN_E = 0xFC /* PCN E Indirect. */ }; @@ -242,6 +242,7 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { lex_type = 0xFF; uint8_t k = 0; + uint8_t k2 = 0; union reg ch; ch.u64 = 0; uint8_t rs = 0; @@ -324,12 +325,13 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { offset++; } switch (get_ptok(str[i+offset], dbg)) { - case PTOK_B : - case PTOK_X : - case PTOK_Y : - case PTOK_S : - case PTOK_P : - case PTOK_ALPHA : + case PTOK_B : + case PTOK_E : + case PTOK_X : + case PTOK_Y : + case PTOK_S : + case PTOK_P : + case PTOK_ALPHA : case PTOK_NUMBER: ptok = PTOK_ALPHA; break; } if ((ptok == PTOK_S && toupper(str[i+1]) != 'P') || (ptok == PTOK_P && toupper(str[i+1]) != 'C')) { @@ -584,6 +586,7 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { (t) ? (t->subspace = space) : (lt->subspace = space); (t) ? (t->subtab = tab) : (lt->subtab = tab); break; + case PTOK_E: case PTOK_X: case PTOK_Y: lexeme[j] = str[i++]; @@ -593,8 +596,9 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { break; } switch (ptok) { - case PTOK_X: l->tok->type = (lex_type == TOK_IND) ? INDX : ZMX; break; - case PTOK_Y: l->tok->type = (lex_type == TOK_IND) ? INDY : ZMY; break; + case PTOK_E: l->tok->type = (lex_type == TOK_IND) ? EIND : l->tok->type; break; + case PTOK_X: l->tok->type = (lex_type == TOK_IND) ? INDX : ZMX; break; + case PTOK_Y: l->tok->type = (lex_type == TOK_IND) ? INDY : ZMY; break; } break; case PTOK_S: @@ -697,13 +701,17 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { isch = 0; isop = 0; if (j == 3 && str[i] != ':' && !is_struct) { - for (k = 0; k < OPNUM; k++) { - if (toupper(lexeme[0]) == mne[k][0]) { - if (!strcasecmp(lexeme, mne[k])) { - lex_type = TOK_OPCODE; + for (k = 0, k2 = 0; k < OPNUM || k2 < EXT_OPNUM; k++, k2++) { + int find_ext = (k2 < EXT_OPNUM); + int upper = toupper(lexeme[0]); + if (upper == mne[k][0] || (find_ext && upper == ext_mne[k2][0])) { + int is_base = !strcasecmp(lexeme, mne[k]); + int is_ext = (find_ext && !strcasecmp(lexeme, ext_mne[k2])); + if (is_base || is_ext) { + lex_type = (is_base && !is_ext) ? TOK_OPCODE : TOK_EXTOP; isop = 1; l->count++; - t = make_token(lex_type, 0xFF, space, tab, k, "", NULL); + t = make_token(lex_type, 0xFF, space, tab, (is_base && !is_ext) ? k : k2, "", NULL); break; } } @@ -791,7 +799,7 @@ uint64_t lex(char *str, uint64_t address, uint16_t bline, uint8_t dbg) { printf("lex(): lexeme: %s, lex_type: %s\n", lexeme, (lex_type != 0xFF) ? lex_tok[lex_type] : "TOK_NONE"); } j = 0; - if (lex_type == TOK_OPCODE && !isop) { + if ((lex_type == TOK_OPCODE || lex_type == TOK_EXTOP) && !isop) { j = 0; } else if (lex_type == TOK_EXPR || (lex_type != TOK_MEMBER && !isdelm2(str[i], dbg))) { i++; @@ -34,28 +34,29 @@ static inline uint8_t isdelm2(char c, uint8_t dbg) { static inline uint8_t get_ptok(char c, uint8_t dbg) { switch (c) { - case '.' : return PTOK_DOT ; - case '@' : return PTOK_AT ; - case ':' : return PTOK_COLON ; - case '=' : return PTOK_EQU ; - case '+' : return PTOK_PLUS ; - case '-' : return PTOK_MINUS ; - case '>' : return PTOK_GT ; - case '<' : return PTOK_LT ; - case '|' : return PTOK_PIPE ; - case '(' : return PTOK_LBRACK ; - case ')' : return PTOK_RBRACK ; - case ',' : return PTOK_COMMA ; - case 'B': case 'b' : return PTOK_B ; + case '.' : return PTOK_DOT ; + case '@' : return PTOK_AT ; + case ':' : return PTOK_COLON ; + case '=' : return PTOK_EQU ; + case '+' : return PTOK_PLUS ; + case '-' : return PTOK_MINUS ; + case '>' : return PTOK_GT ; + case '<' : return PTOK_LT ; + case '|' : return PTOK_PIPE ; + case '(' : return PTOK_LBRACK ; + case ')' : return PTOK_RBRACK ; + case ',' : return PTOK_COMMA ; + case 'B': case 'b' : return PTOK_B ; + case 'E': case 'e' : return PTOK_E ; case 'X': case 'x' : return PTOK_X ; case 'Y': case 'y' : return PTOK_Y ; case 'S': case 's' : return PTOK_S ; case 'P': case 'p' : return PTOK_P ; - case '\"': return PTOK_DQUOTE ; - case '\'': return PTOK_SQUOTE ; - case '#' : return PTOK_HASH ; - case ';' : return PTOK_SCOLON ; - case '$' : return PTOK_DOLLAR ; + case '\"': return PTOK_DQUOTE ; + case '\'': return PTOK_SQUOTE ; + case '#' : return PTOK_HASH ; + case ';' : return PTOK_SCOLON ; + case '$' : return PTOK_DOLLAR ; case '%' : return PTOK_PERCENT; default : if (isdigit(c)) { @@ -71,6 +72,7 @@ static inline uint8_t get_ptok(char c, uint8_t dbg) { static inline uint8_t is_altok(uint8_t ptok, uint8_t dbg) { switch (ptok) { case PTOK_B: + case PTOK_E: case PTOK_X: case PTOK_Y: case PTOK_S: @@ -10,6 +10,7 @@ #define keypoll 0 #define OPNUM 74 +#define EXT_OPNUM 49 #define C (1 << 0) /* Carry flag. */ #define Z (1 << 1) /* Zero flag. */ @@ -55,10 +56,10 @@ union reg { struct sux { union reg ps; /* The processor status register. */ uint64_t a, b, y, x; /* Registers A, B, X, and Y. */ + uint64_t e; /* Effective address register. */ uint64_t pc; /* Program counter. */ uint64_t sp; /* Stack pointer. */ uint64_t clk; /* Number of clock cycles. */ - uint8_t crt; /* Current running threads. */ }; extern int asmmon(); diff --git a/programs/sub-suite/print_char.s b/programs/sub-suite/print_char.s new file mode 100644 index 0000000..e12461c --- /dev/null +++ b/programs/sub-suite/print_char.s @@ -0,0 +1,147 @@ +print_char: +; sta a ; Save the typed character for now. + pha ; Preserve the character. +; ldb #2 ; Make sure that set_ptr sets the third pointer. + lda.d #buffer ; Set the third pointer to the start of the screen buffer. + pha.q ; Push the pointer onto the stack. + lda sp+9 ; Get the character back. +; jsr set_ptr ; +; ldb #0 ; Set B to zero. +; tba ; Set the Accumulator to zero. +; lda a ; Get back the character. + cmp #$1B ; Did the user type an escape character? + beq esc ; Yes, so go check the escape code. + cmp #'\n' ; No, but did the user type a newline? + beq nl ; Yes, so handle the newline. + cmp #$C ; No, but did the user type Ctrl+L? + beq clr_scr ; Yes, so clear the screen. + cmp #19 ; No, but did the user type Ctrl+S? + beq en_step ; Yes, so enable clock/instruction stepping. + cmp #18 ; No, but did the user type Ctrl+R? + beq dis_step ; Yes, so disable clock/instruction stepping. + cmp #'\b' ; No, but did the user type a backspace? + beq bs ; Yes, so handle the backspace. + cmp #$7F ; No, but did they type Delete? + beq bs ; Yes, so treat it as a backspace. +printc: + lda #0 ; No, so start trying to print a character. + sta d ; + lda (sp+1), y ; Are we at the end of the string? + beq @save ; Yes, so just print the character. + lda b ; No, but was the flag set? + bne @save ; Yes, so don't shift the line. + sty.w scr_ptr ; No, so save the cursor index for later. + jsr fndend ; Find the end of the line. + bra @shift ; Start shifting the line right. +@update: + lda scr_col ; Save the current column position for later. + sta scr_tcol ; +@update1: + jsr findend ; Find the end of the line. + sta e ; Use it for redrawing the line. + sta scr_row ; Set the row position to to the end of the line. + jsr findst ; Find the start of the line. + lda scr_row ; Get the start of the line. +@update2: + sta f ; Set the starting line, to the start of the line. + jsr rdrw_ln ; Redraw the line. + lda scr_trow ; Get the real row position back. + sta scr_row ; + lda scr_tcol ; Get the real column position back. + sta scr_col ; + jsr update_pos ; Update the cursor's position. + dec d ; + bra @save1 ; +@shift: + ldy.w scr_ptr3 ; + inc scr_ptr3 ; + tyx ; + dey ; + ldb #1 ; + stb d ; + jsr shftln ; + ldb #1 ; + stb d ; +; lda a ; + lda sp+9 ; + sta (sp+1), y ; store typed character into the input buffer. + lda scr_row ; + sta scr_trow ; + bra @update ; +@save: + ldb d ; + bne @update ; +@save1: +; lda a ; + lda sp+9 ; + sta (sp+1), y ; store typed character into the input buffer. +@incr: + inc scr_col ; Increment the cursor's x coordinate. + iny ; +@wrapped: + ldb #1 ; + stb f ; + ldb scr_col ; + cpb #maxcol+1 ; + bcs @scrolled ; +@print: + sta scr ; Echo typed character. + ldb f ; + beq @wrap ; + bra printc_end ; +@scrolled: + ldb scr_row ; + cpb #maxrow ; + bcs @scroll ; +@wrapped2: + ldb #0 ; + stb f ; + bra @print ; +@scroll: + sta scr ; Echo typed character. + clc ; + lda #1 ; + sta wrapped ; + jsr scrl_down ; +@wrap: + ldb #0 + stb scr_col ; + ldb scr_row ; + cpb #maxrow ; + bcs @wrap2 ; +@wrap1: + inc scr_row ; +@wrap2: + phx.w ; + clc ; + lda scr_row ; + adc scr_str ; + tax ; + jsr setbit ; + plx.w ; + jsr update_pos ; +printc_end: + pla.q ; Pull the pointer off the stack. + pla ; Pull the character off the stack. + and #0 ; Reset A. + rts ; + +nl: + lda #0 ; Reset A. + ldb (sp+1), y ; Is this character not a null terminator? + bne @scroll ; Yes, so don't overwrite it. + sta (sp+1), y ; No, so overwrite it. +@scroll: + sta scr_col ; Move the cursor to the start of the next line. + lda scr_row ; Get the row position. + cmp #maxrow ; Are we at the bottom of the screen? + bcc @incr ; No, so move down one line. + jsr scrl_down ; Yes, so scroll down one line. + bra @end ; We are done. +@incr: + inc scr_row ; Move the cursor down by one line. + jsr update_pos ; Update the cursor's position. +@end: + lda #'\n' ; Print the newline. + sta a ; + rts ; diff --git a/programs/sub-suite/subeditor-new.s b/programs/sub-suite/subeditor-new.s new file mode 100644 index 0000000..6c1cfb1 --- /dev/null +++ b/programs/sub-suite/subeditor-new.s @@ -0,0 +1,1119 @@ +; SuBEditor. +; +; Writen in Sux assembly by +; mr b0nk 500 <b0nk@b0nk.xyz> + + +.org $8000 +reset: + cps ; Reset the processor status register. + ldx.w #$FFFF ; Reset the stack pointer. + txs ; + ldy #0 ; Reset the Y register. + sty end ; + tyx ; Reset the X register. + lda #maxrow ; Set the end of the screen to the screen's max row count. + sta scr_end ; + tya ; Reset the Accumulator. + sta scr_str ; Set the start of the screen back to zero. + sta.q bitabl ; Reset the first half of the linewrap table. + sta.q bitabl+8 ; Reset the second half of the linewrap table. + inc end ; + lda.w #$1FFF ; Set the clear count to $1FFF. + pha.w ; Push the clear count to the stack. + lda.d #buffer ; Set the array to be cleared to the screen buffer. + pha.q ; Push it on to the stack. + jsr clr_arr ; Clear the screen buffer. + pla.q ; Pull the pointer off of the stack. + pla.w ; Pull the clear count off of the stack. + and #0 ; Reset A. + jsr pnt_strt ; Print the starting message. + lda #$C ; Clear the screen. + sta scr ; + bra start ; Goto the start of the main program. + +clr_arr: + phb ; Preserve whatever was in B. + ldb #0 ; Clear B. + clc ; Prepare for a non carrying add. + adc #8 ; Set the second pointer to the parameter, plus eight. + pha.q ; Push it onto the stack. + tba ; +@loop: + cpy.w sp+26 ; Did we clear all of the array? + bcs @end ; Yes, so we're done. + sta.q (sp+18), y; No, so clear eight bytes. + sta.q (sp+1), y ; Clear eight more bytes. + tya ; Copy the array index. + adc #$10 ; Increment the index by 16. + tay ; Update the index. + tba ; Reset the Accumulator. + sta.q (sp+18), y; Do this one more time, to clear 32 bytes. + sta.q (sp+1), y ; + tya ; + adc #$10 ; + tay ; + tba ; + bra @loop ; Keep looping. +@end: + ldy.w zero ; Set the index back to zero. + pla.q ; Move the stack pointer back. + tba ; Reset A. + plb ; Get whatever was in the B register, back. + rts ; End of clr_arr. + +pnt_strt: + lda.w #ed_name ; Print the name of the editor. + jsr print_str ; + lda.w #ver_str ; Print the version text. + jsr print_str ; + lda.w #ed_ver ; Print the version number. + jsr print_str ; + lda.w #ed_sver ; Print the sub version number. + jsr print_str ; + lda #'\n' ; Print a newline. + jsr print_char ; + lda.w #made ; Print the "Created by" text. + jsr print_str ; + lda.w #author ; Print the name of the author. + jsr print_str ; + lda #'\n' ; Print a newline. + jsr print_char ; + rts ; End of pnt_strt. + +start: + lda #0 ; TODO: Update this for the Super VIA. + sta status ; Clear the control register of the I/O adapter. + tax ; Reset X. + phy.w ; Save the cursor index for later. + tay ; Reset the cursor index. + lda.w #$3FF ; Set the clear count to $3FF. + pha.w ; Push the clear count onto the stack. + lda.d #cmd_buf ; Set the array to be cleared to the command buffer. + pha.q ; Push the pointer onto the stack. + jsr clr_arr ; Clear the command buffer. + pla.q ; Pull the pointer off of the stack. + pla.w ; Pull the clear count off of the stack. + ply.w ; Get back the cursor index. + and #0 ; Reset the Accumulator. + sta end ; + bra read ; Start reading the keyboard. + +read: + lda #0 ; Reset the Accumulator. + sta end ; Disable the dummy flag. + inc end ; Enable the dummy flag. + lda status ; Did we get a key? + beq read ; No, so try again. + jsr getchar ; Yes, and was it a newline? + beq parse ; Yes, so start parsing the line. + bra read ; No, so keep looping. + +parse: + lda #0 ; + tax ; + jsr subasm ; + bra start ; + + +print_str: + ldx #0 ; Reset X. + pha.q ; Push the parameter onto the stack. +@loop: + ldb #1 ; Enable replace mode. + stb b ; + and #0 ; No, reset the accumulator. + phy.w ; Save the cursor index. + txy ; Copy the string index into Y. + lda (sp+3), y ; Are we at the end of the string? + ply.w ; Get the cursor index back. + beq @end ; Yes, so we're done. + inx ; No, so increment the string index. + jsr print_char ; Print the character. + bra @loop ; Keep looping. +@end: + pla.q ; Pull the parameter off the stack. + ldb #0 ; Enable insert mode. + stb b ; + tba ; Reset A. + rts ; End of print_str. + +getbit: + clc ; Clear the carry flag. + lda scr_str ; Has the screen been scrolled? + bne getbt0 ; Yes, so add the screen offset to the current line number. + ldx scr_row ; No, so just use the current line number. + bra getbt1 ; Start getting the bit. +getbt0: + lda scr_row ; Get the current line number. + adc scr_str ; Add the screen offset to it. + tax ; Use it as the wrap index. +getbt1: + tab ; Save the parameter. + lda.d #bitabl ; Set the second pointer to the linewrap table. + pha.q ; Push the pointer onto the stack. + tba ; Get the parameter back. + jsr bitpos ; Get the bit, and byte position. + phy.w ; Save the screen index. + txy ; Get the byte position. + ldb (sp+3), y ; Get one byte of the wrap table. + ply.w ; Get the screen index back. + aba ; Mask out the bit of the current line number. + cmp #1 ; Set the carry flag, if true. + bra bitout ; We are done. + +clrbit: + tab ; Save the parameter. + lda.d #bitabl ; Set the second pointer to the linewrap table. + pha.q ; Push the pointer onto the stack. + tba ; Get the parameter back. + jsr bitpos ; Get the bit, and byte position. + xor #$FF ; Invert the bitmask. + phy.w ; Save the screen index. + txy ; Get the byte position. + ldb (sp+3), y ; Get one byte of the wrap table. + aba ; Clear the bit of the current line number. +bitsav: + sta (sp+3), y ; Update the wrap table. + ply.w ; Get the screen index back. +bitout: + pla.q ; Pull the pointer off the stack. + and #0 ; Reset A. + ldx bitmask ; Return the bitmask. + rts ; We are done. + +setbit: + tab ; Save the parameter. + lda.d #bitabl ; Set the second pointer to the linewrap table. + pha.q ; Push the pointer onto the stack. + tba ; Get the parameter back. + jsr bitpos ; Get the bit, and byte position. + phy.w ; Save the screen index. + txy ; Get the byte position. + ldb (sp+3), y ; Get one byte of the wrap table. + oab ; Set the bit of the current line number. + bra bitsav ; Save the bit. + +bitpos: + tab ; Save the parameter. + lda.w #bits ; Set the first pointer to the bitmask table. + pha.q ; Push the pointer onto the stack. + tba ; Get the parameter back. + stx bitmask ; Make the line number the bitmask. + txa ; Copy it to the Accumulator. + and #7 ; Get the bit position. + phy.w ; Save the cursor index. + tay ; Use the bit position as the index. + tax ; Copy it into X. + lda (sp+3), y ; Get the bitmask. + ply.w ; Get back the cursor index. + pha ; Save the bitmask. + lda bitmask ; Get the line number. + lsr #3 ; Get the byte position. + tax ; Copy it into X. + pla ; Get back the bitmask. + tab ; Preserve the bitmask. + pla.q ; Pull the pointer off the stack. + tba ; Get the bitmask back. + rts ; End of bitpos. + +getchar: + lda kbd ; Get the character that was typed from the keyboard. + ldb #0 ; Reset the B register. + stb e ; Set the temporary row position to zero, in case we get a newline. + stb b ; Enable insert mode. + pha ; Save the character. + phy.w ; Save the cursor index. + cmp #'\n' ; Was the character that was typed, a newline? + bne @print ; No, so just print the character. + jsr cmd_cpy ; Yes, so start copying the line to the command buffer. +@print: + ply.w ; Get back the cursor index. + pla ; Get back the character. + ldb e ; Is the temporary row position non zero? + bne @row ; Yes, so reset the row positon. +@print1: + jsr print_char ; No, so print the character. + lda a ; Get the return value. + cmp #'\n' ; Is the return value, a newline? + beq @true ; Yes, so return true. + bra @false ; No, so return false. +@row: + ldb e ; Get the temporary row position. + cpb #maxrow ; Is temporary row position, at, or above the bottom of the screen? + beq @row2 ; Yes, so leave it as is. + bcs @row1 ; No, so set it to the bottom of the screen. + bra @row2 ; Yes, so leave it as is. +@row1: + ldb #maxrow ; Set the row position to the bottom of the screen. +@row2: + stb scr_row ; Set the row position. + bra @print1 ; Print the character. +@true: + lda #0 ; Return true. + bra @end ; We are done. +@false: + lda #1 ; Return false. +@end: + rts ; End of getchar. + + +cmd_cpy: + lda scr_row ; Get the row position. + sta scr_trow ; Save it for later. + jsr findend ; Find the end of the line. + ldb scr_str ; Has the screen been scrolled? + beq @start ; No, so don't subtract the screen's starting point from the line number. +@offset: + sec ; Yes, so make sure that we don't subtract by the starting point, plus one. + sbc scr_str ; Offset the row position, back by the screen's starting point. + clc ; Clear the carry flag, so that nothing odd occurs. +@start: + sta scr_row ; Set the row position to the end of the line. + sta e ; Save it into the temporary row posiition. + jsr findst ; Find the start of the line. + clc ; Clear the carry flag. + lda scr_row ; Get the row position. + adc scr_str ; Add it with the screen's starting row. + mul #maxcol+1 ; Multiply it with the width of the screen, plus one. + tay ; Place it into the index. + ldx.w #0 ; Reset the X register. + ldb #0 ; Make sure that set_ptr sets the first pointer. + lda.d #buffer ; Set the first pointer to the start of the screen buffer. + pha.q ; Push the pointer onto the stack. + lda.d #cmd_buf ; Set the second pointer to the start of the command buffer. + pha.q ; Push the pointer onto the stack. + tba ; Set the accumulator to zero. +@loop: + ldb #0 ; Reset the B register. + lda.q (sp+9), y ; Get eight bytes from the current line. +@loop1: + phy.w ; Save the screen index. + txy ; Get the command buffer index. + sta (sp+3), y ; Copy one byte from the screen buffer, to the command buffer. + inx ; Increment the command buffer index. + ply.w ; Get back the screen index. + cpx.w #$3FF ; Are we at the end of the command buffer? + bcs @end ; Yes, so we're done. + iny ; No, so increment the screen index. + inb ; Increment the byte count. + lsr #8 ; Shift in the next byte. + stb g ; Save the byte count. + tab ; Save the string buffer. + and #$FF ; Is this byte of the buffer, a null terminator? + beq @end1 ; Yes, so we're done. + tba ; No so get back the string buffer. + ldb g ; Get back the byte count. + cpb #7 ; Did we shift in eight bytes? + beq @loop ; Yes, so get eight more bytes. + bra @loop1 ; No, so keep shifting in more bytes. +@end: + ldb #0 ; Reset B. + phy.w ; Save the screen index. + txy ; Get the command buffer index. + stb (sp+3), y ; Terminate the command buffer. + ply.w ; Get back the screen index. +@end1: + pla.q ; Pull one of the pointers off the stack. + pla.q ; Pull the other pointer off the stack. + tba ; The B register is zero, so clear the Accumulator. + rts ; End of cmd_cpy. + + +findst: + lda #0 ; Reset A. +@loop: + pha ; Save the current line number. + jsr getbit ; Is this the start of the line? + pla ; Get the current line number back. + bcc @end ; Yes, so we're done. + inc ; No, so check the next physical line. + dec scr_row ; Are we at the top of the screen? + bpo @loop ; No, so keep looping. + dec ; Yes, so move back one line. + inc scr_row ; Put the row postiion back to zero. +@end: + cmp #0 ; Update all the flags. + rts ; End of findst. + + +fndend: + lda.d #buffer ; Set the first pointer to the start of the screen buffer. + pha.q ; Push the pointer onto the stack. + phb ; Save the contents of the B register. + ldb #0 ; Make sure that set_ptr sets the first pointer. + tba ; Set the Accumulator to zero. + plb ; Restore the contents of the B register. + phy.w ; +@loop: + lda (sp+3), y ; Are we at the end of the string? + beq @end ; Yes, so we're done. + iny ; No, so increment the cursor index. + bra @loop ; Keep looping. +@end: + sty.w scr_ptr3 ; + ply.w ; + pla.q ; Pull the pointer off the stack. + and #0 ; Reset A. + rts ; End of fndend. + +findend: + jsr fndend ; + lda.w scr_ptr3 ; + div #maxcol+1 ; + rts ; + + +print_char: + sta a ; Save the typed character for now. + ldb #2 ; Make sure that set_ptr sets the third pointer. + lda.d #buffer ; Set the third pointer to the start of the screen buffer. + jsr set_ptr ; + ldb #0 ; Set B to zero. + tba ; Set the Accumulator to zero. + lda a ; Get back the character. + cmp #$1B ; Did the user type an escape character? + beq esc ; Yes, so go check the escape code. + cmp #'\n' ; No, but did the user type a newline? + beq nl ; Yes, so handle the newline. + cmp #$C ; No, but did the user type Ctrl+L? + beq clr_scr ; Yes, so clear the screen. + cmp #19 ; No, but did the user type Ctrl+S? + beq en_step ; Yes, so enable clock/instruction stepping. + cmp #18 ; No, but did the user type Ctrl+R? + beq dis_step ; Yes, so disable clock/instruction stepping. + cmp #'\b' ; No, but did the user type a backspace? + beq bs ; Yes, so handle the backspace. + cmp #$7F ; No, but did they type Delete? + beq bs ; Yes, so treat it as a backspace. +printc: + lda #0 ; No, so start trying to print a character. + sta d ; + lda (ptr3), y ; Are we at the end of the string? + beq @save ; Yes, so just print the character. + lda b ; No, but was the flag set? + bne @save ; Yes, so don't shift the line. + sty.w scr_ptr ; No, so save the cursor index for later. + jsr fndend ; Find the end of the line. + bra @shift ; Start shifting the line right. +@update: + lda scr_col ; Save the current column position for later. + sta scr_tcol ; +@update1: + jsr findend ; Find the end of the line. + sta e ; Use it for redrawing the line. + sta scr_row ; Set the row position to to the end of the line. + jsr findst ; Find the start of the line. + lda scr_row ; Get the start of the line. +@update2: + sta f ; Set the starting line, to the start of the line. + jsr rdrw_ln ; Redraw the line. + lda scr_trow ; Get the real row position back. + sta scr_row ; + lda scr_tcol ; Get the real column position back. + sta scr_col ; + jsr update_pos ; Update the cursor's position. + dec d ; + bra @save1 ; +@shift: + ldy.w scr_ptr3 ; + inc scr_ptr3 ; + tyx ; + dey ; + ldb #1 ; + stb d ; + jsr shftln ; + ldb #1 ; + stb d ; + lda a ; + sta (ptr3), y ; store typed character into the input buffer. + lda scr_row ; + sta scr_trow ; + bra @update ; +@save: + ldb d ; + bne @update ; +@save1: + lda a ; + sta (ptr3), y ; store typed character into the input buffer. +@incr: + inc scr_col ; Increment the cursor's x coordinate. + iny ; +@wrapped: + ldb #1 ; + stb f ; + ldb scr_col ; + cpb #maxcol+1 ; + bcs @scrolled ; +@print: + sta scr ; Echo typed character. + ldb f ; + beq @wrap ; + bra printc_end ; +@scrolled: + ldb scr_row ; + cpb #maxrow ; + bcs @scroll ; +@wrapped2: + ldb #0 ; + stb f ; + bra @print ; +@scroll: + sta scr ; Echo typed character. + clc ; + lda #1 ; + sta wrapped ; + jsr scrl_down ; +@wrap: + ldb #0 + stb scr_col ; + ldb scr_row ; + cpb #maxrow ; + bcs @wrap2 ; +@wrap1: + inc scr_row ; +@wrap2: + phx.w ; + clc ; + lda scr_row ; + adc scr_str ; + tax ; + jsr setbit ; + plx.w ; + jsr update_pos ; +printc_end: + rts ; + +nl: + lda #0 ; Reset A. + ldb (ptr3), y ; Is this character not a null terminator? + bne @scroll ; Yes, so don't overwrite it. + sta (ptr3), y ; No, so overwrite it. +@scroll: + sta scr_col ; Move the cursor to the start of the next line. + lda scr_row ; Get the row position. + cmp #maxrow ; Are we at the bottom of the screen? + bcc @incr ; No, so move down one line. + jsr scrl_down ; Yes, so scroll down one line. + bra @end ; We are done. +@incr: + inc scr_row ; Move the cursor down by one line. + jsr update_pos ; Update the cursor's position. +@end: + lda #'\n' ; Print the newline. + sta a ; + rts ; + + +clr_scr: + lda #maxrow ; + sta scr_end ; + lda #0 ; + sta scr_str ; + sta.q bitabl ; + sta.q bitabl+8 ; + tay ; + lda.w #$1FFF ; Set the clear count to $1FFF. + pha.w ; Push the clear count onto the stack. +; sta.w scr_ptr ; + lda.d #buffer ; Set the array to be cleared to the screen buffer. + pha.q ; Push the pointer onto the stack. + jsr clr_arr ; Clear the screen buffer. + tay ; + pla.q ; Pull the pointer off of the stack. + pla.w ; Pull the clear count off of the stack. + lda.w #$3FF ; Set the clear count to $3FF. + pha.w ; Push the clear count onto the stack. +; sta.w scr_ptr ; + lda.d #cmd_buf ; Set the array to be cleared to the command buffer. + pha.q ; + jsr clr_arr ; Clear the screen buffer. + pla.q ; Pull the pointer off of the stack. + pla.w ; Pull the clear count off of the stack. + and #0 ; Reset A. + sta scr_col ; + sta scr_row ; + jsr update_pos ; + lda #$C ; + sta scr ; + rts ; + +en_step: + lda step ; + beq step_en ; + rts ; +step_en: + lda #1 ; + sta step ; + rts ; + +dis_step: + lda step ; + bne step_dis ; + rts ; +step_dis: + lda #0 ; + sta step ; + rts ; + + +bs: + lda scr_col ; Are we at the far left of the screen? + beq @wrap ; Yes, so check for a wrapped line. + bra back ; No, so add the backspace to the buffer. +@wrap: + jsr getbit ; Is this line, a wrapped line? + bcs @wrap1 ; Yes, so check if the cursor is at the top. + rts ; No, so we're done. +@wrap1: + lda scr_row ; Are we at the top of the screen? + beq @wrap2 ; Yes, so check if the screen is at the top of the buffer. + bra @wrap3 ; No, so start clearing the wrap bit. +@wrap2: + lda scr_str ; Are we at the top of the buffer? + bne @scroll ; Yes, so scroll up. + rts ; No, so we're done. +@scroll: + clc ; Clear the carry flag, so that we don't get odd behaviour. + jsr scrl_up ; Scroll up. + inc scr_row ; Move down by one row. +@wrap3: + clc ; Clear the carry flag. + lda scr_row ; Add the cursor's row position, + adc scr_str ; and the screen's starting row. + tax ; Transfer that into X. +@wrap4: + dec scr_row ; Move up by one row. + ldb #maxcol+1 ; Move the cursor to the absolute right of the screen. + stb scr_col ; + jsr update_pos ; Update the cursor's position. +back: + ldb #0 ; Reset B, and some flags. + stb e ; + stb f ; + lda scr_row ; Save the current row position for later. + sta scr_trow ; + jsr findend ; Find the end of the line. + sta scr_row ; Set our row position to the end of the line. +@find_st: + jsr findst ; Does this line take up more than one real line? + beq @shift ; No, so skip updating any other lines. + bcs @update ; Yes, so update the other lines. + lda scr_trow ; Get the real row position back. + sta scr_row ; +@shift: + dey ; Decrement the buffer's offset. + lda #0 ; Place a null terminator + sta (ptr3), y ; into the buffer. + tyx ; Copy the current cursor index to X. + iny ; Increment cursor index. + ldb #0 ; Set shifting direction to left. + stb d ; + jsr shftln ; Shift line back by one character. + lda #$7F ; Print a backspace to the screen. + sta scr ; + lda e ; Are we updating more than one line? + beq @load ; No, so skip to the next step. +@find_end: + jsr findend ; Yes, so find the end of the line. + sta e ; Set the end parameter to it. + lda scr_col ; Save the current column position for now. + sta scr_tcol ; + jsr rdrw_ln ; Start redrawing the line. + lda scr_tcol ; Get the real column position back. + sta scr_col ; +@load: + lda scr_trow ; Get the real row position back. + sta scr_row ; + dec scr_col ; Move the cursor back by one column, + jsr update_pos ; and update it's position. + rts ; We are done. +@update: + lda scr_row ; Set the line to start redrawing, to the start of the line. + sta f ; + inc e ; Set the redraw flag to true. + bra @shift ; Start shifting the line back. + + +shftln: + ldb d ; Is the flag not set? + beq @dec_loop ; Yes, so shift, and decrement. + ldb #0 ; Clear the B register. + bra @inc_loop ; No, so shift, and increment. +@neg: + ldy.w zero ; Set the source poition to 0. + stb (ptr3), y ; Clear the character that is in the source. + bra @end ; We are done. +@inc_loop: + sty.w scr_ptr2 ; Save the source position for later. + ldy.w scr_ptr ; Get the previous cursor index. + cpy.w scr_ptr2 ; Is the source position, at, or below the cursor index? + beq @inc_loop1 ; Yes, so keep looping. + bcs @end ; No, so we're done. +@inc_loop1: + ldy.w scr_ptr2 ; Get the source position. + lda (ptr3), y ; Get the character from the source position. + phy.w ; Save the source position for later. + txy ; Set our position to the destination. + sta (ptr3), y ; Place the character from the source position, to the destination position. + ply.w ; Set our position back to the source. + stb (ptr3), y ; Clear the character that is in the source. + bng @neg ; The source underflowed, so set it back to zero, + dey ; Decrement the source position. + dex ; Decrement the destination position. + bra @inc_loop ; Keep looping. +@dec_loop: + stx.w scr_ptr2 ; Save the destination position for later. + lda (ptr3), y ; Is the character at the source position, a null terminator? + beq @end3 ; Yes, so we're done. + phy.w ; No, so save the source position for later. + txy ; Set our position to the destination. + sta (ptr3), y ; Place the character from the source position, to the destination position. + inx ; Increment the destination position. + ply.w ; Set our position back to the source. + stb (ptr3), y ; Clear the character that is in the source. + iny ; Increment the source position. + bra @dec_loop ; Keep looping. +@wrap: + tax ; Use the ending line as a parameter for setbit. + jsr setbit ; Set the wrap bit of the ending line. + bra @end5 ; We are done. +@wrap1: + tax ; Use the ending line as a parameter for clrbit. + jsr clrbit ; Clear the wrap bit of the ending line. + bra @end5 ; We are done. +@end: + lda (ptr3), y ; Is this character a null terminator? + bne @end1 ; No, so just find the end of the line. + lda #$20 ; Yes, so convert it to a space for now. + sta (ptr3), y ; +@end1: + jsr findend ; Find the ending line. + sta d ; Save ending line for later. + lda (ptr3), y ; Is this character a space? + cmp #$20 ; + bne @end5 ; No, so skip the conversion. + lda #0 ; Yes, so convert it back to zero. + sta (ptr3), y ; +@end2: + lda d ; Get the ending line. + cmp scr_row ; Is the ending line greater than the starting line? + beq @end5 ; No, so we're done. + bcs @wrap ; Yes, so set the wrap bit. + bra @end5 ; No, so we're done. +@end3: + jsr findend ; Find the ending line. + cpb #0 ; Is the remainder zero? + beq @end4 ; Yes, so check if the ending line is greater than the starting line. + bra @end5 ; No, so we're done. +@end4: + cmp scr_row ; Is the ending line greater than the starting line? + beq @end5 ; No, so we're done. + bcs @wrap1 ; Yes, so clear the wrap bit. +@end5: + rts ; End of shftln. + +esc: + lda status ; Get the next character. + lda kbd ; + cmp #$1B ; Is this character an escape character? + beq shftesc ; Yes, so check the other set of escape routines. + lda status ; No, so wait for the next character. + beq @end ; We have an error, so discard it, and go back to getting user input. + lda kbd ; Get the escape code. + sta c ; Store the escape code, until we need it. + lda #0 ; Set the D pseudo register to zero. + sta d ; + jsr isup ; Check if the user pressed up. + lda d ; Did the user press up? + bne @end ; Yes, so we're done. + jsr isdown ; No, so check if the user pressed down. + lda d ; Did the user press down? + bne @end ; Yes, so we're done. + lda #0 ; No, so check if the user pressed left. + jsr isleft ; + lda d ; Did the user press left? + bne @end ; Yes, so we're done. + jsr isright ; No, so check if the user pressed right. +@end: + lda #0 ; Clear the D pseudo register. + sta d ; + rts ; We are done. + +shftesc: + lda status ; Skip the '['. + lda kbd ; + lda status ; Wait for the next character. + beq @end ; We have an error, so discard it, and go back to getting user input. + lda kbd ; Get the escape code. + sta c ; Store the escape code, until we need it. + lda #0 ; Use the D pseudo register as a skip flag. + sta d ; + jsr isshftup ; Check if the user pressed shift+up. + lda d ; Was it successful? + bne @end ; Yes, so we're done. + jsr isshftdown ; No, so check if the user pressed shift+down. +@end: + lda #0 ; Clear the D pseudo register. + sta d ; + rts ; We are done. + + +isup: + lda c ; Load the escape code into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + bne @end ; No, so we're done. + lda scr_row ; Yes, but is the cursor at the top of the screen? + beq @scroll ; Yes, so check if we need to scroll. +@check2: + lda c ; No, so load the escape code back into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + beq @up ; Yes, so move the cursor up. + bra @end ; No, so we're done. +@up: + dec scr_row ; Move the cursor up a line. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + rts ; We are done. +@scroll: + lda scr_str ; Are we at the top of the screen buffer? + beq @end ; Yes, so we're done. + jsr scrl_up ; No, so scroll up. + lda #1 ; Tell the escape routine that we were successful. + sta d ; +@end: + rts ; End of isup. + + +isdown: + lda c ; Load the escape code into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + bne @end ; No, so we're done. + lda scr_row ; Yes, so start checking the y coordinate of the cursor. + cmp #maxrow ; Is the cursor at the bottom of the screen? + beq @scroll ; Yes, so scroll down. + lda c ; No, so load the escape code back into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + beq @down ; Yes, so move the cursor down. + bra @end ; No, so we're done. +@down: + inc scr_row ; Move the cursor down a line. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + rts ; We are done. +@scroll: + lda scr_row ; Save the cursor's row number. + sta scr_trow ; + lda scr_col ; Save the cursor's column number. + sta scr_tcol ; + jsr scrl_down ; Scroll down. + lda scr_trow ; Load the cursor's row number. + sta scr_row ; + lda scr_tcol ; Load the cursor's column number. + sta scr_col ; + lda #1 ; Tell the escape routine that we were successful. + sta d ; +@end: + rts ; End of isdown. + + +isright: + lda c ; Load the escape code into the accumulator. + cmp #'C' ; Did the user press the right arrow key? + bne @end2 ; No, so we're done. + lda scr_col ; Yes, so start checking the x coordinate of the cursor. + cmp #maxcol ; Is the cursor at the far right of the screen? + beq @wrap ; Yes, so check if this is a wrapped line. + bra @right ; No, so move the cursor right, like normal. +@wrap: + inc scr_row ; Move down a row. + jsr getbit ; Is the current line, a wrapped line? + bcs @incr ; Yes, so leave the cursor where it is. + dec scr_row ; No, so move the cursor back up a row. + bra @end2 ; We are done. +@scroll: + lda scr_str ; Are we at the top of the screen buffer? + beq @end ; Yes, so we're done. + lda #1 ; No, so scroll down. + sta wrapped ; Set the wrapped flag. + jsr scrl_down ; Scroll down. + bra @end ; We are done. +@incr: + lda #0 ; Set the cursor to the far left of the screen. + sta scr_col ; + lda scr_row ; Get the current row number. + cmp #maxrow ; Are we at the bottom of the screen? + beq @end1 ; No, so we're done. + bcs @scroll ; Yes, so check if we are scrolling down. + bra @end1 ; No, so we're done. +@right: + inc scr_col ; Move the cursor right by one character. + jsr update_pos ; Update it's position. + rts ; End of isright. +@end: + dec scr_row ; Move back up a row. +@end1: + jsr update_pos ; Update the cursor position. +@end2: + lda #0 ; Unset the wrapped flag. + sta wrapped ; + rts ; End of isright. + + +isleft: + lda c ; Load the escape code into the accumulator. + cmp #'C' ; Did the user press right? + beq @end1 ; Yes, so we're done + lda scr_col ; No, but is the cursor at the far left of the screen? + beq @wrap ; Yes, so start checking if this is a wrapped line. + lda c ; No, so load the escape code back into the accumulator. + cmp #'D' ; Did the user press the left arrow key? + beq @left ; Yes, so move the cursor left. + bra @end1 ; No, so we're done. +@wrap: + jsr getbit ; Is the current line, a wrapped line? + bcs @decr ; Yes, so wrap back up a line. + bra @end1 ; No, so we're done. +@decr: + lda scr_row ; Is the cursor at the top of the screen? + beq @decr1 ; Yes, so don't move up a line. + lda #1 ; No, so set the wrapped flag. + sta wrapped ; + dec scr_row ; Move the cursor up one line. +@decr1: + lda #maxcol ; Move the Cursor to the far right of the screen. + sta scr_col ; + lda #1 ; Tell the escape routine that we were successful. + sta d ; + lda scr_row ; Are we at the top of the screen? + beq @scroll ; Yes, so check if we need to scroll. + bra @end ; No, so we're done. +@scroll: + lda wrapped ; Was the wrapped flag set somewhere else? + bne @end ; Yes so we're done. + lda scr_str ; No, but are we actually at the top of the screen buffer? + beq @end1 ; Yes, so we're done. + jsr scrl_up ; No, so scroll up. + bra @end1 ; We are done. +@left: + dec scr_col ; Move the cursor left a character. + jsr update_pos ; Update it's position. + lda #1 ; Tell the escape routine that we succeded. + sta d ; + rts ; We are done +@end: + jsr update_pos ; Update the cursor position. +@end1: + lda #0 ; Unset the wrapped flag. + sta wrapped ; + rts ; End of isleft. + + +isshftup: + lda c ; Load the escape code back into the accumulator. + cmp #'A' ; Did the user press the up arrow key? + bne @end ; + lda #1 ; + sta d ; + lda scr_str ; + beq @end ; +@shftup: + jsr scrl_up ; + lda #1 ; + sta d ; +@end: + rts ; + + +isshftdown: + lda c ; Load the escape code back into the accumulator. + cmp #'B' ; Did the user press the down arrow key? + bne @end ; + lda #1 ; + sta d ; + lda scr_end ; + cmp #71 ; + bcs @end ; +@shftdown: + jsr scrl_down ; + lda #1 ; + sta d ; +@end: + rts ; + + +update_pos: + ldb #1 ; Set the F pseudo register to one, to fix some bugs. + stb f ; + clc ; Clear the carry flag. + lda scr_row ; Add the cursor's line number, + adc scr_str ; with the starting line number to get the absolute line number. + tay ; Place it in the Y regster for now. + mul #maxcol+1 ; Multiply the line number by the screen's max column count, plus 1. + clc ; Clear the carry flag. + adc scr_col ; Add the cursor's column number to get the screen index. + tay ; Place the index into the Y register. + tba ; Reset A. + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + jsr getrow ; Start printing the row number to the screen. + jsr getcol ; Start printing the column number to the screen. + lda #'H' ; Print 'H' + sta scr ; to the screen. + rts ; End of update_pos. + +getrow: + lda scr_row ; Get the cursor's y coordinate. + bra bcd ; Convert it to BCD. +getcol: + lda #';' ; Print ';' + sta scr ; to the screen. + lda scr_col ; Get the cursor's x coordinate. +bcd: + div #10 ; Divide A by 10. + ora #'0' ; Convert it to ascii, and + sta scr ; print to the screen. + tba ; Get the remainder. + ora #'0' ; Convert it to ascii, and + sta scr ; print to the screen. + rts ; End of bcd. + +scrl_down: + inc scr_str ; Increment the starting line of the screen. + inc scr_end ; Increment the ending line of the screen. + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + lda #'T' ; Print 'T' + sta scr ; to the screen, and end the escape sequence. + lda scr_row ; Get the cursor's line number. + pha ; Save it in the stack. + lda wrapped ; Was the wrapped flag set? + beq @save ; Yes, so save the cursor position. +@redraw: + jsr rdrw_row ; No, so redraw this row. + lda wrapped ; Was the wrapped flag set? + beq @load ; Yes, so load the previous cursor position back. + bra @end ; No, so we're done. +@save: + lda scr_col ; Get the cursor's column number. + pha ; Save it in the stack. + bra @redraw ; Start redrawing the current row. +@load: + pla ; Get the cursor's previous column number back. + sta scr_col ; +@end: + pla ; Get the cursor's previous line number back. + sta scr_row ; + jsr update_pos ; Update the cursor's position. + lda #0 ; Clear the wrapped flag. + sta wrapped ; +@end1: + rts ; End of scrl_down. + +scrl_up: + dec scr_str ; + dec scr_end ; + lda #$1B ; Print an escape character + sta scr ; to the screen. + lda #'[' ; Print '[' + sta scr ; to the screen, and start the escape sequence. + lda #'S' ; Print 'S' + sta scr ; to the screen, and end the escape sequence. + lda scr_row ; + pha ; + lda scr_col ; + pha ; + lda #0 ; + sta scr_row ; + jsr rdrw_row ; + pla ; + sta scr_col ; + pla ; + sta scr_row ; + jsr update_pos ; +@end: + rts ; + +rdrw_row: + lda #0 ; + sta scr_col ; + jsr update_pos ; +@loop: + lda (ptr3), y ; + beq @incr ; + sta scr ; +@incr: + inc scr_col ; + lda (ptr3), y ; + beq @skip ; +@incr1: + iny ; +@incr2: + lda scr_col ; + cmp #maxcol+1 ; + bcs @end ; + bra @loop ; +@skip: + lda #' ' ; + sta scr ; to the screen. + bra @incr1 ; +@end: + lda #0 ; + sta scr_col ; + jsr update_pos ; +@end1: + rts ; + +rdrw_ln: + lda scr_row ; + pha ; + lda f ; + sta scr_row ; + lda scr_col ; + pha ; + jsr update_pos ; +@loop: + lda scr_row ; + cmp e ; + beq @loop1 ; + bcs @end ; +@loop1: + jsr rdrw_row ; +@incr: + inc scr_row ; + bra @loop ; +@end: + pla ; + sta scr_col ; + pla ; + sta scr_row ; + jsr update_pos ; + lda #0 ; + sta e ; + sta f ; + rts ; + +set_ptr: + cpb #1 ; Are we setting the second pointer? + beq @ptr2 ; Yes, so start setting it. + cpb #2 ; No, but are we setting the third pointer? + beq @ptr3 ; Yes, so start setting it. +@ptr1: + stb.q ptr ; Reset the first pointer. + sta.q ptr ; No, so set the first pointer. + bra @end ; We are done. +@ptr2: + stb.q ptr2 ; Reset the second pointer. + sta.q ptr2 ; Set the second pointer. + bra @end ; We are done. +@ptr3: + stb.q ptr3 ; Reset the third pointer. + sta.q ptr3 ; Set the third pointer. +@end: + rts ; End of set_ptr. @@ -70,11 +70,45 @@ void start_timer(int sec, int usec) { } #endif +uint8_t is_extop(uint8_t opcode, uint8_t dbg) { + switch (opcode) { + case ADC_E: + case SBC_E: + case AND_E: + case ORA_E: + case XOR_E: + case LSL_E: + case LSR_E: + case ROL_E: + case ROR_E: + case MUL_E: + case DIV_E: + case ASR_E: + case CMP_E: + case LDY_E: + case LDA_E: + case LDB_E: + case CPB_E: + case CPX_E: + case CPY_E: + case LDX_E: + case DEC_E: + case INC_E: + case STY_E: + case STA_E: + case STB_E: + case STX_E: return 0; + } + return 1; +} + void *run(void *args) { struct suxthr *thr = (void *)args; struct sux *cpu = &thr->sx; uint8_t thread = thr->th; uint8_t prefix = 0; + uint8_t ext_prefix = 0; + uint8_t prefix2 = 0; uint8_t opcode = 0; union reg address; union reg value; @@ -141,13 +175,58 @@ void *run(void *args) { pthread_mutex_unlock(&mutex); #endif #endif - uint16_t instr = read_value(cpu, 0, cpu->pc, 1, 1, 0); + uint32_t instr = read_value(cpu, 0, cpu->pc, 3, 1, 0); uint8_t *tmp_inst = (uint8_t *)&instr; prefix = ((instr & 3) == 3) ? *tmp_inst++ : 0; + ext_prefix = ((*tmp_inst & 0xD) == 0xD) ? *tmp_inst++ : 0; opcode = *tmp_inst; - cpu->pc += ((instr & 3) == 3)+1; + cpu->pc += ((instr & 3) == 3)+((ext_prefix & 0xD) == 0xD)+1; address.u64 = cpu->pc; - uint8_t am = optype[opcode]; + uint8_t am; + uint8_t ext_id = 0; + uint8_t tmp_opcode = opcode; + uint8_t tmp_ext_prefix = ext_prefix; + if (ext_prefix) { + ext_id = ((ext_prefix >> 4) & 0xF); + switch (ext_id) { + case 0x0: + am = ext_optype[opcode]; + if (!is_extop(opcode, 0)) { + tmp_ext_prefix = 0; + switch (opcode) { + case ADC_E: tmp_opcode = ADC_IMM; break; + case SBC_E: tmp_opcode = SBC_IMM; break; + case AND_E: tmp_opcode = AND_IMM; break; + case ORA_E: tmp_opcode = ORA_IMM; break; + case XOR_E: tmp_opcode = XOR_IMM; break; + case LSL_E: tmp_opcode = LSL_IMM; break; + case LSR_E: tmp_opcode = LSR_IMM; break; + case ROL_E: tmp_opcode = ROL_IMM; break; + case ROR_E: tmp_opcode = ROR_IMM; break; + case MUL_E: tmp_opcode = MUL_IMM; break; + case DIV_E: tmp_opcode = DIV_IMM; break; + case ASR_E: tmp_opcode = ASR_IMM; break; + case CMP_E: tmp_opcode = CMP_IMM; break; + case LDY_E: tmp_opcode = LDY_IMM; break; + case LDA_E: tmp_opcode = LDA_IMM; break; + case LDB_E: tmp_opcode = LDB_IMM; break; + case CPB_E: tmp_opcode = CPB_IMM; break; + case CPX_E: tmp_opcode = CPX_IMM; break; + case CPY_E: tmp_opcode = CPY_IMM; break; + case LDX_E: tmp_opcode = LDX_IMM; break; + case DEC_E: tmp_opcode = DEC_Z; break; + case INC_E: tmp_opcode = INC_Z; break; + case STY_E: tmp_opcode = STY_Z; break; + case STA_E: tmp_opcode = STA_Z; break; + case STB_E: tmp_opcode = STB_Z; break; + case STX_E: tmp_opcode = STX_Z; break; + } + } + break; + } + } else { + am = optype[opcode]; + } uint8_t rs = (prefix >> 4) & 3; uint8_t size = (/***/1 << rs) - 1; uint8_t check_io = (am != IMM); @@ -155,14 +234,14 @@ void *run(void *args) { #if keypoll pthread_mutex_lock(&mutex); #endif - disasm(cpu, lines, opcode, prefix, thread); + disasm(cpu, lines, opcode, prefix, ext_prefix, prefix2, thread); lines+=1; #if keypoll pthread_mutex_unlock(&mutex); #endif #endif if (am != IMPL && am != BREG) { - address.u64 = get_addr(cpu, opcode, prefix, 1, 1, thread); + address.u64 = get_addr(cpu, opcode, prefix, ext_prefix, 1, 1, thread); /*if (address.u64 > mem_size-1) { addr[STEP_ADDR] = 1; step = 1; @@ -172,314 +251,14 @@ void *run(void *args) { } } /*decode_microinst(&uc, &uc_test, prefix, 0);*/ - switch (opcode) { - case CPS_IMP: /* Clear Processor Status. */ - cpu->ps.u64 = 0; - break; - case ADC_B: /* ADC B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case ADC_IMM: /* ADC Immediate. */ - case ADC_AB: /* ADC Absolute. */ - case ADC_Z: /* ADC Zero Matrix. */ - cpu->a = adc(cpu, cpu->a, value.u64, thread); - break; - case PHP_IMP: push(cpu, cpu->ps.u8[thread], 0, thread); break; /* PusH Processor status to stack. */ - case PHA_IMP: push(cpu, cpu->a , size, thread); break; /* PusH Accumulator to stack. */ - case PHB_IMP: push(cpu, cpu->b , size, thread); break; /* PusH B register to stack. */ - case PHY_IMP: push(cpu, cpu->y , size, thread); break; /* PusH Y register to stack. */ - case PHX_IMP: push(cpu, cpu->x , size, thread); break; /* PusH X register to stack. */ - case TAY_IMP: cpu->y = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to Y. */ - case TAX_IMP: cpu->x = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to Y. */ - case TYX_IMP: cpu->x = transfer(cpu, cpu->y , value.u64, thread); break; /* Transfer Y to X. */ - case TYA_IMP: cpu->a = transfer(cpu, cpu->y , value.u64, thread); break; /* Transfer Y to Accumulator. */ - case TXA_IMP: cpu->a = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Accumulator. */ - case TXY_IMP: cpu->y = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Y. */ - case TAB_IMP: cpu->b = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to B. */ - case TSX_IMP: cpu->x = transfer(cpu, cpu->sp, value.u64, thread); break; /* Transfer Stack pointer to X. */ - case TBA_IMP: cpu->a = transfer(cpu, cpu->b , value.u64, thread); break; /* Transfer B to Accumulator. */ - case TXS_IMM: cpu->sp = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Stack pointer. */ - case BRA_REL: /* BRA Relative. */ - case JMP_AB: /* JMP Absolute. */ - case JMP_Z: /* JMP Zero Matrix. */ - case JMP_IN: /* JMP Indirect. */ - cpu->pc = address.u64; - break; - case SBC_B: /* SBC B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case SBC_IMM: /* SBC Immediate. */ - case SBC_AB: /* SBC Absolute. */ - case SBC_Z: /* SBC Zero Matrix. */ - cpu->a = adc(cpu, cpu->a, ~value.u64, thread); - break; - case PLP_IMP: cpu->ps.u8[thread] = pull(cpu, 0, thread); break; /* PuLl Processor status from stack. */ - case PLA_IMP: cpu->a = pull(cpu, size, thread); break; /* PuLl Accumulator from stack. */ - case PLB_IMP: cpu->b = pull(cpu, size, thread); break; /* PuLl B register from stack. */ - case PLY_IMP: cpu->y = pull(cpu, size, thread); break; /* PuLl Y register from stack. */ - case PLX_IMP: cpu->x = pull(cpu, size, thread); break; /* PuLl X register from stack. */ - break; - case AND_B: /* AND B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case AND_IMM: /* AND Immediate. */ - case AND_AB: /* AND Absolute. */ - case AND_Z: /* AND Zero Matrix. */ - cpu->a = and(cpu, cpu->a, value.u64, thread); - break; - case BPO_REL: /* BPO Relative. */ - if (!getflag(N)) { - cpu->pc = address.u64; - } - break; - case ORA_B: /* ORA B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case ORA_IMM: /* ORA Immediate. */ - case ORA_AB: /* ORA Absolute. */ - case ORA_Z: /* ORA Zero Matrix. */ - cpu->a = or(cpu, cpu->a, value.u64, thread); - break; - case SEI_IMP: /* SEt Interrupt. */ - setflag(1, I); - break; - case BNG_REL: /* BNG Relative. */ - if (getflag(N)) { - cpu->pc = address.u64; - } - break; - case XOR_B: /* XOR B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case XOR_IMM: /* XOR Immediate. */ - case XOR_AB: /* XOR Absolute. */ - case XOR_Z: /* XOR Zero Matrix. */ - cpu->a = xor(cpu, cpu->a, value.u64, thread); - break; - case CLI_IMP: /* CLear Interrupt. */ - setflag(0, I); - break; - case BCS_REL: /* BCS Relative. */ - if (getflag(C)) { - cpu->pc = address.u64; - } - break; - case LSL_B: /* LSL B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case LSL_IMM: /* LSL Immediate. */ - case LSL_AB: /* LSL Absolute. */ - case LSL_Z: /* LSL Zero Matrix. */ - cpu->a = lsl(cpu, cpu->a, value.u64, thread); - break; - case SEC_IMP: /* SEt Carry flag.*/ - setflag(1, C); - break; - case STA_AB: /* STA Absolute. */ - case STA_Z: /* STA Zero Matrix. */ - case STA_ZX: /* STA Zero Matrix, Indexed with X. */ - case STA_ZY: /* STA Zero Matrix, Indexed with Y. */ - case STA_IN: /* STA Indirect. */ - case STA_IX: /* STA Indexed Indirect. */ - case STA_IY: /* STA Indirect Indexed. */ - store(cpu, address.u64, cpu->a, prefix, thread); - break; - case STY_AB: /* STY Absolute. */ - case STY_Z: /* STY Zero Matrix. */ - case STY_IN: /* STY Indirect. */ - store(cpu, address.u64, cpu->y, prefix, thread); - break; - case STX_AB: /* STX Absolute. */ - case STX_Z: /* STX Zero Matrix. */ - case STX_IN: /* STX Indirect. */ - store(cpu, address.u64, cpu->x, prefix, thread); - break; - case STB_AB: /* STB Absolute. */ - case STB_Z: /* STB Zero Matrix. */ - case STB_ZX: /* STB Zero Matrix, Indexed with X. */ - case STB_ZY: /* STB Zero Matrix, Indexed with Y. */ - case STB_IN: /* STB Indirect. */ - case STB_IX: /* STB Indexed Indirect. */ - case STB_IY: /* STB Indirect Indexed. */ - store(cpu, address.u64, cpu->b, prefix, thread); - break; - case BCC_REL: /* BCC Relative. */ - if (!getflag(C)) { - cpu->pc = address.u64; - } - break; - case LSR_B: /* LSR B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case LSR_IMM: /* LSR Immediate. */ - case LSR_AB: /* LSR Absolute. */ - case LSR_Z: /* LSR Zero Matrix. */ - cpu->a = lsr(cpu, cpu->a, value.u64, thread); - break; - case ASR_B: /* ASR B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case ASR_IMM: /* ASR Immediate. */ - case ASR_AB: /* ASR Absolute. */ - case ASR_Z: /* ASR Zero Matrix. */ - cpu->a = asr(cpu, cpu->a, value.u64, thread); - break; - case CLC_IMP: /* CLear Carry flag. */ - setflag(0, C); - break; - case LDB_IMM: /* LDB Immediate. */ - case LDB_AB: /* LDB Absolute. */ - case LDB_Z: /* LDB Zero Matrix. */ - case LDB_ZX: /* LDB Zero Matrix, Indexed with X. */ - case LDB_ZY: /* LDB Zero Matrix, Indexed with Y. */ - case LDB_IN: /* LDB Indirect. */ - case LDB_IX: /* LDB Indexed Indirect. */ - case LDB_IY: /* LDB Indirect Indexed. */ - cpu->b = load(cpu, cpu->b, address.u64, size, thread); - break; - case LDA_IMM: /* LDA Immediate. */ - case LDA_AB: /* LDA Absolute. */ - case LDA_Z: /* LDA Zero Matrix. */ - case LDA_ZX: /* LDA Zero Matrix, Indexed with X. */ - case LDA_ZY: /* LDA Zero Matrix, Indexed with Y. */ - case LDA_IN: /* LDA Indirect. */ - case LDA_IX: /* LDA Indexed Indirect. */ - case LDA_IY: /* LDA Indirect Indexed. */ - cpu->a = load(cpu, cpu->a, address.u64, size, thread); - break; - case LDY_IMM: /* LDY Immediate. */ - case LDY_AB: /* LDY Absolute. */ - case LDY_Z: /* LDY Zero Matrix. */ - case LDY_IN: /* LDY Indirect. */ - cpu->y = load(cpu, cpu->y, address.u64, size, thread); - break; - case LDX_IMM: /* LDX Immediate. */ - case LDX_AB: /* LDX Absolute. */ - case LDX_Z: /* LDX Zero Matrix. */ - case LDX_IN: /* LDX Indirect. */ - cpu->x = load(cpu, cpu->x, address.u64, size, thread); - break; - case BEQ_REL: /* BEQ Relative. */ - if (getflag(Z)) { - cpu->pc = address.u64; - } - break; - case ROL_B: /* ROL B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case ROL_IMM: /* ROL Immediate. */ - case ROL_AB: /* ROL Absolute. */ - case ROL_Z: /* ROL Zero Matrix. */ - cpu->a = rol(cpu, cpu->a, value.u64, thread); - break; - case BNE_REL: /* BNE Relative. */ - if (!getflag(Z)) { - cpu->pc = address.u64; - } - break; - case ROR_B: /* ROR B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case ROR_IMM: /* ROR Immediate. */ - case ROR_AB: /* ROR Absolute. */ - case ROR_Z: /* ROR Zero Matrix. */ - cpu->a = ror(cpu, cpu->a, value.u64, thread); - break; - case BVS_REL: /* BVS Relative. */ - if (getflag(V)) { - cpu->pc = address.u64; - } - break; - case MUL_B: /* MUL B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case MUL_IMM: /* MUL Immediate. */ - case MUL_AB: /* MUL Absolute. */ - case MUL_Z: /* MUL Zero Matrix. */ - cpu->a = mul(cpu, cpu->a, value.u64, thread); - break; - case BVC_REL: /* BVC Relative. */ - if (!getflag(V)) { - cpu->pc = address.u64; - } - break; - case DIV_B: /* DIV B register. */ - case DIV_IMM: /* DIV Immediate. */ - case DIV_AB: /* DIV Absolute. */ - case DIV_Z: /* DIV Zero Matrix. */ - rem = (opcode != DIV_B) ? &cpu->b : &cpu->x; - cpu->a = divd(cpu, cpu->a, value.u64, rem, thread); - break; - case CLV_IMP: /* CLear oVerflow flag. */ - setflag(0, V); - break; - case CPB_IMM: /* CPB Immediate. */ - case CPB_AB: /* CPB Absolute. */ - case CPB_Z: /* CPB Zero Matrix. */ - case CPB_IN: /* CPB Indirect. */ - case CPB_IX: /* CPB Indexed Indirect. */ - case CPB_IY: /* CPB Indirect Indexed. */ - cmp(cpu, value.u64, cpu->b, thread); - break; - case CMP_B: /* CMP B register. */ - value.u64 = cpu->b; /* Falls Through. */ - case CMP_IMM: /* CMP Immediate. */ - case CMP_AB: /* CMP Absolute. */ - case CMP_Z: /* CMP Zero Matrix. */ - case CMP_IN: /* CMP Indirect. */ - case CMP_IX: /* CMP Indexed Indirect. */ - case CMP_IY: /* CMP Indirect Indexed. */ - cmp(cpu, value.u64, cpu->a, thread); - break; - case CPY_IMM: /* CPY Immediate. */ - case CPY_AB: /* CPY Absolute. */ - case CPY_Z: /* CPY Zero Matrix. */ - cmp(cpu, value.u64, cpu->y, thread); - break; - case CPX_IMM: /* CPX Immediate. */ - case CPX_AB: /* CPX Absolute. */ - case CPX_Z: /* CPX Zero Matrix. */ - cmp(cpu, value.u64, cpu->x, thread); - break; - case INC_IMP: cpu->a = idr(cpu, cpu->a, 1, thread); break; - case INB_IMP: cpu->b = idr(cpu, cpu->b, 1, thread); break; - case INY_IMP: cpu->y = idr(cpu, cpu->y, 1, thread); break; - case INX_IMP: cpu->x = idr(cpu, cpu->x, 1, thread); break; - case DEC_IMP: cpu->a = idr(cpu, cpu->a, 0, thread); break; - case DEB_IMP: cpu->b = idr(cpu, cpu->b, 0, thread); break; - case DEY_IMP: cpu->y = idr(cpu, cpu->y, 0, thread); break; - case DEX_IMP: cpu->x = idr(cpu, cpu->x, 0, thread); break; - case JSR_IN: /* JSR Indirect. */ - case JSR_AB: /* Jump to SubRoutine. */ - case JSR_Z: /* JSR Zero Matrix. */ - push(cpu, cpu->pc, (size) ? size : 7, thread); - cpu->pc = address.u64; - break; - case INC_AB: /* INC Absolute. */ - case INC_Z: /* INC Zero Matrix. */ - idm(cpu, address.u64, prefix, 1, thread); - break; - case NOP_IMP: /* No OPeration. */ - break; - case RTI_IMP: /* ReTurn from Interrupt routine. */ - cpu->ps.u8[thread] = pull(cpu, 0, thread); - size = 0; - case RTS_IMP: /* ReTurn from Subroutine. */ - cpu->pc = pull(cpu, (size) ? size : 7, thread); - break; - case DEC_AB: /* DEC Absolute. */ - case DEC_Z: /* DEC Zero Matrix. */ - idm(cpu, address.u64, prefix, 0, thread); - break; - case BRK_IMP: /* BReaK. */ - case WAI_IMP: /* WAit for Interrupt. */ - if (opcode == WAI_IMP) { - pthread_mutex_lock(&main_mutex); - pthread_cond_signal(&main_cond); - pthread_mutex_unlock(&main_mutex); - pthread_mutex_lock(&mutex); - pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - } - push(cpu, cpu->pc, 7, thread); - push(cpu, cpu->ps.u8[thread], 0, thread); - setflag(1, I); - setreg(value.u8, +, 0, addr, +, (opcode == BRK) ? 0xFFE0 : 0xFFA0, 7); - if (opcode == WAI_IMP) { - kbd_rdy &= (uint8_t)~(1 << thread); - } - cpu->pc = value.u64; - default: - break; + ext_prefix = tmp_ext_prefix; + opcode = tmp_opcode; + if (ext_prefix) { + switch (ext_id) { + case 0x0: exec_ext_inst(cpu, opcode, prefix, value, address, size, thread); break; + } + } else { + exec_base_inst(cpu, opcode, prefix, value, address, size, thread); } #if !IO ins++; @@ -44,7 +44,7 @@ extern pthread_cond_t main_cond; #if debug extern void print_regs(struct sux *cpu, uint8_t lines, uint8_t thread); -extern void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t thread); +extern void disasm(struct sux *cpu, uint8_t lines, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t prefix2, uint8_t thread); #endif /*#define KEYBUF_SIZE 0x40 @@ -59,6 +59,11 @@ static inline uint8_t get_addrsize(uint8_t prefix, uint8_t addrmode) { uint8_t id = (prefix & 0x0C) >> 2; switch (addrmode) { case ZM: + case ZMX: + case ZMY: + case IND: + case INDX: + case INDY: switch (id) { case 2: return 5; case 3: return 3; @@ -67,6 +72,11 @@ static inline uint8_t get_addrsize(uint8_t prefix, uint8_t addrmode) { } break; case ABS: + case ABSX: + case ABSY: + case AIND: + case AINDX: + case AINDY: switch (id) { case 3: return 7; case 2: return 6; @@ -75,7 +85,7 @@ static inline uint8_t get_addrsize(uint8_t prefix, uint8_t addrmode) { } break; } - return 0; + return 0xFF; } static inline uint8_t isrw(uint8_t opcode) { @@ -269,37 +279,26 @@ static inline uint64_t read_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_cl return address; } -static inline uint64_t zmx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { +static inline uint64_t idx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc, uint64_t idx_reg) { #if getclk cpu->clk += inc_clk; #endif - return read_addr(cpu, prefix, inc_clk, ZM, inc_pc) + cpu->x; + return read_addr(cpu, prefix, inc_clk, type, inc_pc) + idx_reg; } -static inline uint64_t zmy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { - #if getclk - cpu->clk += inc_clk; - #endif - return read_addr(cpu, prefix, inc_clk, ZM, inc_pc) + cpu->y; -} - - -static inline uint64_t ind_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { - return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, ZM, inc_pc), 7, inc_clk, 0); +static inline uint64_t ind_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc) { + return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, type, inc_pc), 7, inc_clk, 0); } -static inline uint64_t indx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { +static inline uint64_t ind_idx_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t type, uint8_t inc_pc, uint64_t idx_reg, uint8_t pre_idx) { #if getclk cpu->clk += inc_clk; #endif - return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, ZM, inc_pc)+cpu->x, 7, inc_clk, 0); -} - -static inline uint64_t indy_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { - #if getclk - cpu->clk += inc_clk; - #endif - return ind_addr(cpu, prefix, inc_clk, inc_pc) + cpu->y; + if (pre_idx) { + return read_value(cpu, 0, read_addr(cpu, prefix, inc_clk, type, inc_pc)+idx_reg, 7, inc_clk, 0); + } else { + return ind_addr(cpu, prefix, inc_clk, type, inc_pc) + idx_reg; + } } static inline uint64_t rel_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk, uint8_t inc_pc) { @@ -321,12 +320,21 @@ static inline uint64_t rel_addr(struct sux *cpu, uint8_t prefix, uint8_t inc_clk } } -static inline uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { +static inline uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, uint8_t ext_prefix, uint8_t inc_pc, uint8_t inc_clk, uint8_t thread) { uint64_t address = 0; - switch (optype[opcode]) { + uint8_t type; + if ((ext_prefix & 0xD) == 0xD) { + switch (ext_prefix >> 4) { + case 0x0: type = ext_optype[opcode]; break; + } + } else { + type = optype[opcode]; + } + switch (type) { case BREG: case IMPL: break; + case EIND: address = cpu->e; break; case IMM: address = imm_addr(cpu); switch (opcode) { @@ -335,34 +343,41 @@ static inline uint64_t get_addr(struct sux *cpu, uint8_t opcode, uint8_t prefix, case ROL_IMM: case ROR_IMM: case ASR_IMM: - if (inc_pc) { - ++cpu->pc; + if ((ext_prefix & 0xD) != 0xD) { + if (inc_pc) { + ++cpu->pc; + } + break; } - break; + /* Falls Through. */ default: if (inc_pc) { cpu->pc+=(1 << ((prefix >> 4) & 3)); } - /* Falls Through. */ - case TXS_IMM: break; + break; } break; - case ZM : return read_addr(cpu, prefix, inc_clk, ZM, inc_pc); - case ABS : return read_addr(cpu, prefix, inc_clk, ABS, inc_pc); - case ZMX : return zmx_addr(cpu, prefix, inc_clk, /**/ inc_pc); - case ZMY : return zmy_addr(cpu, prefix, inc_clk, /**/ inc_pc); - case IND : return ind_addr(cpu, prefix, inc_clk, /**/ inc_pc); - case INDX: return indx_addr(cpu, prefix, inc_clk, /**/ inc_pc); - case INDY: return indy_addr(cpu, prefix, inc_clk, /**/ inc_pc); - case REL : return rel_addr(cpu, prefix, inc_clk, /**/ inc_pc); + case ZM : return read_addr(cpu, prefix, inc_clk, ZM, inc_pc); + case ZMX : return idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->x); + case ZMY : return idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->y); + case IND : return ind_addr(cpu, prefix, inc_clk, ZM, inc_pc); + case INDX : return ind_idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->x, 1); + case INDY : return ind_idx_addr(cpu, prefix, inc_clk, ZM, inc_pc, cpu->y, 0); + case ABS : return read_addr(cpu, prefix, inc_clk, ABS, inc_pc); + case ABSX : return idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->x); + case ABSY : return idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->y); + case AIND : return ind_addr(cpu, prefix, inc_clk, ABS, inc_pc); + case AINDX: return ind_idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->x, 1); + case AINDY: return ind_idx_addr(cpu, prefix, inc_clk, ABS, inc_pc, cpu->y, 0); + case REL : return rel_addr(cpu, prefix, inc_clk, /**/ inc_pc); } return address; } -static inline uint64_t adc(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { - uint64_t sum = reg+value+getflag(C); +static inline uint64_t adc(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t carry, uint8_t thread) { + uint64_t sum = reg+value+carry; setflag(sum == 0, Z); setflag((sum >> 63), N); setflag(((reg^value) >> 63) && ((reg^sum) >> 63), V); @@ -406,55 +421,65 @@ static inline uint64_t xor(struct sux *cpu, uint64_t reg, uint64_t value, uint8_ return reg; } -static inline uint64_t lsl(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { - uint64_t sum = (value < 64) ? reg << value : 0; +static inline uint64_t lsl(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; + uint64_t sum = (value < msb) ? reg << value : 0; setflag(sum == 0, Z); - setflag(sum >> 63, N); - setflag(reg >> (64-value), C); + setflag(sum >> (msb-1), N); + setflag(reg >> (msb-value), C); return sum; } -static inline uint64_t lsr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { - uint64_t sum = (value < 64) ? reg >> value : 0; +static inline uint64_t lsr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; + uint64_t sum = (value < msb) ? reg >> value : 0; setflag(sum == 0, Z); - setflag(sum >> 63, N); + setflag(sum >> (msb-1), N); setflag(reg & 1, C); return sum; } -static inline uint64_t asr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { - uint8_t sign = reg >> 63; - uint64_t sum = (value < 64) ? (reg >> value) | ((uint64_t)sign << 63) : 0; +static inline uint64_t asr(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; + uint8_t sign = reg >> (msb-1); + uint64_t sum = (value < msb) ? (reg >> value) | ((uint64_t)sign << (msb-1)) : 0; setflag(sum == 0, Z); - setflag(sum >> 63, N); + setflag(sum >> (msb-1), N); setflag(reg & 1, C); return sum; } -static inline uint64_t rol(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { +static inline uint64_t rol(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; uint64_t sum; uint64_t c = getflag(C); switch (value & 0x3F) { case 0 : return reg; case 1 : sum = (reg << 1) | (c & 1); break; - default: sum = (reg << value) | (c << (value-1)) | (reg >> (65-value)); break; + default: sum = (reg << value) | (c << (value-1)) | (reg >> ((msb+1)-value)); break; } setflag(sum == 0, Z); - setflag(sum >> 63, N); - setflag((reg >> (64-value)) & 1, C); + setflag(sum >> (msb-1), N); + setflag((reg >> (msb-value)) & 1, C); return sum; } -static inline uint64_t ror(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { +static inline uint64_t ror(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; uint64_t sum; uint64_t c = getflag(C); switch (value & 0x3F) { case 0 : return reg; - case 1 : sum = (reg >> 1) | (c << 63); break; - default: sum = (reg >> value) | (c << (64-value)) | (reg << (65-value)); break; + case 1 : sum = (reg >> 1) | (c << (msb-1)); break; + default: sum = (reg >> value) | (c << (msb-value)) | (reg << ((msb+1)-value)); break; } setflag(sum == 0, Z); - setflag(sum >> 63, N); + setflag(sum >> (msb-1), N); setflag((reg >> (value-1)) & 1, C); return sum; } @@ -474,6 +499,7 @@ static inline uint64_t divd(struct sux *cpu, uint64_t reg, uint64_t value, uint6 setflag((sum >> 63), N); return sum; } + static inline void cmp(struct sux *cpu, uint64_t value, uint64_t reg, uint8_t thread) { uint64_t sum = reg-value; setflag(sum >> 63, N); @@ -490,6 +516,40 @@ static inline uint64_t idr(struct sux *cpu, uint64_t reg, uint8_t inc, uint8_t t return reg; } +static inline uint64_t lbcnt(struct sux *cpu, uint64_t value, uint8_t bit, uint8_t size, uint8_t thread) { + size = (size > 8) ? 8 : size; + uint8_t msb = size*8; + if ((!bit && !value) || (bit && value == -1)) { + return msb; + } + uint64_t j = 0; + for (int i = msb-1; ((value >> i) & 1) == bit; i--, j++); + setflag(j == 0, Z); + return j; +} + +static inline void bit_test(struct sux *cpu, uint64_t reg, uint64_t value, uint8_t thread) { + setflag((value >> 7) & 1, N); + setflag((value >> 6) & 1, V); + setflag((value & reg) == 0, Z); +} + +static inline uint64_t swap(struct sux *cpu, uint64_t reg, uint8_t size, uint8_t thread) { + size = (size > 7) ? 7 : size; + uint8_t half = ((size-1)*8) >> 1; + uint64_t mask = (-(uint64_t)1 >> ((7 - size) * 8)); + uint64_t lo_mask = mask >> half; + uint64_t hi_mask = (mask << half) & mask; + return (((reg >> half) & lo_mask) | ((reg << half) & hi_mask)); + +} + +static inline uint64_t popcnt(struct sux *cpu, uint64_t value, uint8_t thread) { + uint64_t count = 0; + for (; value; count++, value &= value - 1); + return count; +} + /* Increment, or Decrement memory. */ static inline void idm(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_t inc, uint8_t thread) { uint8_t size = (1 << ((prefix >> 4) & 3))-1; @@ -508,6 +568,47 @@ static inline void idm(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_ write_value(cpu, value, address, size, 1, 1); } +static inline void bitshft_mem(struct sux *cpu, uint8_t shft_type, uint64_t shft_cnt, uint64_t address, uint8_t prefix, uint8_t thread) { + uint8_t size = (1 << ((prefix >> 4) & 3))-1; + uint64_t value = read_value(cpu, 0, address, size, 1, 0); + switch (shft_type) { + case 0: value = lsl(cpu, value, shft_cnt, size+1, thread); break; + case 1: value = lsr(cpu, value, shft_cnt, size+1, thread); break; + case 2: value = rol(cpu, value, shft_cnt, size+1, thread); break; + case 3: value = ror(cpu, value, shft_cnt, size+1, thread); break; + case 4: value = asr(cpu, value, shft_cnt, size+1, thread); break; + } + write_value(cpu, value, address, size, 1, 1); +} + +static inline void not_mem(struct sux *cpu, uint64_t address, uint8_t prefix, uint8_t thread) { + uint8_t size = (1 << ((prefix >> 4) & 3))-1; + write_value(cpu, ~read_value(cpu, 0, address, size, 1, 0), address, size, 1, 1); +} + +static inline void lbcnt_mem(struct sux *cpu, uint64_t address, uint8_t bit, uint8_t size, uint8_t thread) { + uint64_t value = read_value(cpu, 0, address, size, 1, 0); + write_value(cpu, lbcnt(cpu, value, bit, size, thread), address, size, 1, 1); +} + +static inline void swap_mem(struct sux *cpu, uint64_t address, uint8_t size, uint8_t thread) { + uint64_t value = read_value(cpu, 0, address, size, 1, 0); + write_value(cpu, swap(cpu, value, size, thread), address, size, 1, 1); +} + +static inline uint64_t mem_move(struct sux *cpu, uint64_t n, uint64_t dst, uint64_t src, uint8_t rep, uint8_t size, uint8_t thread) { + if (!rep) { + uint64_t value = read_value(cpu, 0, src, size, 1, 1); + write_value(cpu, value, dst, size, 1, 1); + return n-(size+1); + } else { + if (src < mem_size && dst < mem_size) { + memcopy(addr+dst, addr+src, n*(size+1)); + } + return 0; + } +} + static inline uint64_t load(struct sux *cpu, uint64_t reg, uint64_t address, uint8_t size, uint8_t thread) { uint64_t value = read_value(cpu, reg, address, size, 1, 1); setflag(value == 0, Z); @@ -519,3 +620,588 @@ static inline void store(struct sux *cpu, uint64_t address, uint64_t reg, uint8_ uint8_t size = (1 << ((prefix >> 4) & 3))-1; write_value(cpu, reg, address, size, 1, 1); } + +static inline void exec_ext_inst(struct sux *cpu, uint8_t opcode, uint8_t prefix, union reg value, union reg address, uint8_t size, uint8_t thread) { + uint8_t addr_size = get_addrsize(ext_optype[opcode], prefix); + uint8_t tmp = 0; + switch (opcode) { + case LEA_AB : /* LEA Absolute. */ + case LEA_AX : /* LEA Absolute, Indexed with X. */ + case LEA_AY : /* LEA Absolute, Indexed with Y. */ + case LEA_AI : /* LEA Absolute Indirect. */ + case LEA_AIX: /* LEA Absolute Indexed Idirect. */ + case LEA_AIY: /* LEA Absolute Indirect Indexed. */ + case LEA_Z : /* LEA Zero Matrix. */ + case LEA_ZX : /* LEA Zero Matrix, Indexed with X. */ + case LEA_ZY : /* LEA Zero Matrix, Indexed with Y. */ + case LEA_IN : /* LEA Indirect. */ + case LEA_IX : /* LEA Indexed Idirect. */ + case LEA_IY : /* LEA Indirect Indexed. */ + cpu->e = address.u64; + break; + case PEA_AB : /* PEA Absolute. */ + case PEA_AX : /* PEA Absolute, Indexed with X. */ + case PEA_AY : /* PEA Absolute, Indexed with Y. */ + case PEA_AI : /* PEA Absolute Indirect. */ + case PEA_AIX: /* PEA Absolute Indexed Idirect. */ + case PEA_AIY: /* PEA Absolute Indirect Indexed. */ + case PEA_Z : /* PEA Zero Matrix. */ + case PEA_ZX : /* PEA Zero Matrix, Indexed with X. */ + case PEA_ZY : /* PEA Zero Matrix, Indexed with Y. */ + case PEA_IN : /* PEA Indirect. */ + case PEA_IX : /* PEA Indexed Idirect. */ + case PEA_IY : /* PEA Indirect Indexed. */ + push(cpu, address.u64, 7, thread); + break; + case ADD_IMM: /* ADD Immediate. */ + case ADD_AB : /* ADD Absolute. */ + case ADD_Z : /* ADD Zero Matrix. */ + case ADD_E : /* ADD E Indirect. */ + cpu->a = adc(cpu, cpu->a, value.u64, 0, thread); + break; + case SUB_IMM: /* SUB Immediate. */ + case SUB_AB : /* SUB Absolute. */ + case SUB_Z : /* SUB Zero Matrix. */ + case SUB_E : /* SUB E Indirect. */ + cpu->a = adc(cpu, cpu->a, ~value.u64, 1, thread); + break; + case ADE_IMM: /* ADE Immediate. */ + case ADE_AB : /* ADE Absolute. */ + case ADE_Z : /* ADE Zero Matrix. */ + cpu->e = adc(cpu, cpu->e, value.u64, 0, thread); + break; + case SBE_IMM: /* SBE Immediate. */ + case SBE_AB : /* SBE Absolute. */ + case SBE_Z : /* SBE Zero Matrix. */ + cpu->e = adc(cpu, cpu->e, ~value.u64, 1, thread); + break; + case ADS_IMM: /* ADS Immediate. */ + case ADS_AB : /* ADS Absolute. */ + case ADS_Z : /* ADS Zero Matrix. */ + case ADS_E : /* ADS E Indirect. */ + cpu->sp = adc(cpu, cpu->sp, value.u64, 0, thread); + break; + case SBS_IMM: /* SBS Immediate. */ + case SBS_AB : /* SBS Absolute. */ + case SBS_Z : /* SBS Zero Matrix. */ + case SBS_E : /* SBS E Indirect. */ + cpu->sp = adc(cpu, cpu->sp, ~value.u64, 1, thread); + break; + case NOT_A : /* NOT Accumulator. */ + cpu->a = ~cpu->a; + break; + case NOT_AB: /* NOT Absolute. */ + case NOT_Z : /* NOT Zero Matrix. */ + case NOT_E : /* NOT E Indirect. */ + not_mem(cpu, address.u64, prefix, thread); + break; + case LLM_AB: /* LLM Absolute. */ + case LLM_Z : /* LLM Zero Matrix. */ + case LLM_E : /* LLM E Indirect. */ + case LRM_AB: /* LRM Absolute. */ + case LRM_Z : /* LRM Zero Matrix. */ + case LRM_E : /* LRM E Indirect. */ + case RLM_AB: /* RLM Absolute. */ + case RLM_Z : /* RLM Zero Matrix. */ + case RLM_E : /* RLM E Indirect. */ + case RRM_AB: /* RRM Absolute. */ + case RRM_Z : /* RRM Zero Matrix. */ + case RRM_E : /* RRM E Indirect. */ + case ARM_AB: /* ARM Absolute. */ + case ARM_Z : /* ARM Zero Matrix. */ + case ARM_E : /* ARM E Indirect. */ + switch (opcode) { + case LLM_AB: + case LLM_Z : + case LLM_E : tmp = 0; break; + case LRM_AB: + case LRM_Z : + case LRM_E : tmp = 1; break; + case RLM_AB: + case RLM_Z : + case RLM_E : tmp = 2; break; + case RRM_AB: + case RRM_Z : + case RRM_E : tmp = 3; break; + case ARM_AB: + case ARM_Z : + case ARM_E : tmp = 4; break; + } + bitshft_mem(cpu, tmp, cpu->b, address.u64, prefix, thread); + break; + case PHE_IMP: push(cpu, cpu->e, size, thread); break; /* PusH E register. */ + case PLE_IMP: pull(cpu, size, thread); break; /* PuLl E register. */ + case CPE_IMM: /* CPE Immediate. */ + case CPE_AB : /* CPE Absolute. */ + case CPE_Z : /* CPE Zero Matrix. */ + adc(cpu, cpu->e, ~value.u64, 1, thread); + break; + case ICE_AB : /* ICE Absolute. */ + case ICE_Z : /* ICE Zero Matrix. */ + case ICE_E : /* ICE E Indirect. */ + break; + case LDS_IMM: /* LDS Immediate. */ + case LDS_AB : /* LDS Absolute. */ + case LDS_Z : /* LDS Zero Matrix. */ + case LDS_E : /* LDS E Indirect. */ + cpu->sp = load(cpu, cpu->sp, address.u64, size, thread); + break; + case DEE_IMP: cpu->e = idr(cpu, cpu->e, 0, thread); break; /* DEcrement E register. */ + case INE_IMP: cpu->e = idr(cpu, cpu->e, 1, thread); break; /* INcrement E register. */ + case DES_IMP: cpu->sp = idr(cpu, cpu->sp, 0, thread); break; /* DEcrement Stack pointer. */ + case INS_IMP: cpu->sp = idr(cpu, cpu->sp, 1, thread); break; /* INcrement Stack pointer. */ + case STS_AB: /* STS Absolute. */ + case STS_Z : /* STS Zero Matrix. */ + case STS_E : /* STS E Indirect. */ + store(cpu, address.u64, cpu->sp, prefix, thread); + break; + case STE_AB: /* STE Absolute. */ + case STE_Z : /* STE Zero Matrix. */ + store(cpu, address.u64, cpu->sp, prefix, thread); + break; + case STZ_AB: /* STZ Absolute. */ + case STZ_Z : /* STZ Zero Matrix. */ + case STZ_E : /* STZ E Indirect. */ + store(cpu, address.u64, 0, prefix, thread); + break; + case SCO_IMM: /* SCO Immediate. */ + case SCO_AB : /* SCO Absolute. */ + case SCO_Z : /* SCO Zero Matrix. */ + case SCO_E : /* SCO E Indirect. */ + break; + case ECO_IMM: /* ECO Immediate. */ + case ECO_AB : /* ECO Absolute. */ + case ECO_Z : /* ECO Zero Matrix. */ + case ECO_E : /* ECO E Indirect. */ + break; + case CLZ_AB: /* CLZ Absolute. */ + case CLZ_Z : /* CLZ Zero Matrix. */ + case CLZ_E : /* CLZ E Indirect. */ + cpu->a = lbcnt(cpu, value.u64, 0, size, thread); + break; + case CLO_AB: /* CLO Absolute. */ + case CLO_Z : /* CLO Zero Matrix. */ + case CLO_E : /* CLO E Indirect. */ + cpu->a = lbcnt(cpu, value.u64, 1, size, thread); + break; + case BIT_AB: /* BIT Absolute. */ + case BIT_Z : /* BIT Zero Matrix. */ + case BIT_E : /* BIT E Indirect. */ + bit_test(cpu, cpu->a, value.u64, thread); + break; + case MMV_IMP: /* Memory MoVe. */ + cpu->b = mem_move(cpu, cpu->b, cpu->x, cpu->y, 0, size, thread); + break; + case SWP_A : /* SWaP lower half, with upper half. */ + cpu->a = swap(cpu, cpu->a, size, thread); + break; + case SWP_AB: /* SWP Absolute. */ + case SWP_Z : /* SWP Zero Matrix. */ + case SWP_E : /* SWP E Indirect. */ + swap_mem(cpu, address.u64, size, thread); + break; + case PCN_AB: /* PCN Absolute. */ + case PCN_Z : /* PCN Zero Matrix. */ + case PCN_E : /* PCN E Indirect. */ + cpu->a = popcnt(cpu, value.u64, thread); + break; + case REP_REL: /* REP Relative. */ + if (cpu->b != 0) { + cpu->b--; + cpu->pc = address.u64; + } + break; + case REQ_REL: /* REQ Relative. */ + if (cpu->b != 0 && getflag(Z)) { + cpu->b--; + cpu->pc = address.u64; + } + break; + case RNE_REL: /* RNE Relative. */ + if (cpu->b != 0 && !getflag(Z)) { + cpu->b--; + cpu->pc = address.u64; + } + break; + case LNG_IMM: /* LNG Immediate. */ + case LNG_E : /* LNG E Indirect. */ + if (getflag(N)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case LPO_IMM: /* LPO Immediate. */ + case LPO_E : /* LPO E Indirect. */ + if (!getflag(N)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case LCS_IMM: /* LCS Immediate. */ + case LCS_E : /* LCS E Indirect. */ + if (getflag(C)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case LCC_IMM: /* LCC Immediate. */ + case LCC_E : /* LCC E Indirect. */ + if (!getflag(C)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case LEQ_IMM: /* LEQ Immediate. */ + case LEQ_E : /* LEQ E Indirect. */ + if (getflag(Z)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case LNE_IMM: /* LNE Immediate. */ + case LNE_E : /* LNE E Indirect. */ + if (!getflag(Z)) { + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + } + break; + case SNG_E : /* SNG E Indirect. */ + if (getflag(N)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + case SPO_E : /* SPO E Indirect. */ + if (!getflag(N)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + case SCS_E : /* SCS E Indirect. */ + if (getflag(C)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + case SCC_E : /* SCC E Indirect. */ + if (!getflag(C)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + case SEQ_E : /* SEQ E Indirect. */ + if (getflag(Z)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + case SNE_E : /* SNE E Indirect. */ + if (!getflag(Z)) { + store(cpu, address.u64, cpu->a, prefix, thread); + } + break; + + } +} + +static inline void exec_base_inst(struct sux *cpu, uint8_t opcode, uint8_t prefix, union reg value, union reg address, uint8_t size, uint8_t thread) { + uint64_t *rem = 0; + switch (opcode) { + case CPS_IMP: /* Clear Processor Status. */ + cpu->ps.u8[thread] = 0; + break; + case ADC_B: /* ADC B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case ADC_IMM: /* ADC Immediate. */ + case ADC_AB: /* ADC Absolute. */ + case ADC_Z: /* ADC Zero Matrix. */ + cpu->a = adc(cpu, cpu->a, value.u64, getflag(C), thread); + break; + case PHP_IMP: push(cpu, cpu->ps.u8[thread], 0, thread); break; /* PusH Processor status to stack. */ + case PHA_IMP: push(cpu, cpu->a , size, thread); break; /* PusH Accumulator to stack. */ + case PHB_IMP: push(cpu, cpu->b , size, thread); break; /* PusH B register to stack. */ + case PHY_IMP: push(cpu, cpu->y , size, thread); break; /* PusH Y register to stack. */ + case PHX_IMP: push(cpu, cpu->x , size, thread); break; /* PusH X register to stack. */ + case TAY_IMP: cpu->y = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to Y. */ + case TAX_IMP: cpu->x = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to Y. */ + case TYX_IMP: cpu->x = transfer(cpu, cpu->y , value.u64, thread); break; /* Transfer Y to X. */ + case TYA_IMP: cpu->a = transfer(cpu, cpu->y , value.u64, thread); break; /* Transfer Y to Accumulator. */ + case TXA_IMP: cpu->a = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Accumulator. */ + case TXY_IMP: cpu->y = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Y. */ + case TAB_IMP: cpu->b = transfer(cpu, cpu->a , value.u64, thread); break; /* Transfer Accumulator to B. */ + case TSX_IMP: cpu->x = transfer(cpu, cpu->sp, value.u64, thread); break; /* Transfer Stack pointer to X. */ + case TBA_IMP: cpu->a = transfer(cpu, cpu->b , value.u64, thread); break; /* Transfer B to Accumulator. */ + case TXS_IMP: cpu->sp = transfer(cpu, cpu->x , value.u64, thread); break; /* Transfer X to Stack pointer. */ + case BRA_REL: /* BRA Relative. */ + case JMP_AB: /* JMP Absolute. */ + case JMP_Z: /* JMP Zero Matrix. */ + case JMP_IN: /* JMP Indirect. */ + cpu->pc = address.u64; + break; + case SBC_B: /* SBC B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case SBC_IMM: /* SBC Immediate. */ + case SBC_AB: /* SBC Absolute. */ + case SBC_Z: /* SBC Zero Matrix. */ + cpu->a = adc(cpu, cpu->a, ~value.u64, getflag(C), thread); + break; + case PLP_IMP: cpu->ps.u8[thread] = pull(cpu, 0, thread); break; /* PuLl Processor status from stack. */ + case PLA_IMP: cpu->a = pull(cpu, size, thread); break; /* PuLl Accumulator from stack. */ + case PLB_IMP: cpu->b = pull(cpu, size, thread); break; /* PuLl B register from stack. */ + case PLY_IMP: cpu->y = pull(cpu, size, thread); break; /* PuLl Y register from stack. */ + case PLX_IMP: cpu->x = pull(cpu, size, thread); break; /* PuLl X register from stack. */ + break; + case AND_B: /* AND B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case AND_IMM: /* AND Immediate. */ + case AND_AB: /* AND Absolute. */ + case AND_Z: /* AND Zero Matrix. */ + cpu->a = and(cpu, cpu->a, value.u64, thread); + break; + case BPO_REL: /* BPO Relative. */ + if (!getflag(N)) { + cpu->pc = address.u64; + } + break; + case ORA_B: /* ORA B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case ORA_IMM: /* ORA Immediate. */ + case ORA_AB: /* ORA Absolute. */ + case ORA_Z: /* ORA Zero Matrix. */ + cpu->a = or(cpu, cpu->a, value.u64, thread); + break; + case SEI_IMP: /* SEt Interrupt. */ + setflag(1, I); + break; + case BNG_REL: /* BNG Relative. */ + if (getflag(N)) { + cpu->pc = address.u64; + } + break; + case XOR_B: /* XOR B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case XOR_IMM: /* XOR Immediate. */ + case XOR_AB: /* XOR Absolute. */ + case XOR_Z: /* XOR Zero Matrix. */ + cpu->a = xor(cpu, cpu->a, value.u64, thread); + break; + case CLI_IMP: /* CLear Interrupt. */ + setflag(0, I); + break; + case BCS_REL: /* BCS Relative. */ + if (getflag(C)) { + cpu->pc = address.u64; + } + break; + case LSL_B: /* LSL B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case LSL_IMM: /* LSL Immediate. */ + case LSL_AB: /* LSL Absolute. */ + case LSL_Z: /* LSL Zero Matrix. */ + cpu->a = lsl(cpu, cpu->a, value.u64, 8, thread); + break; + case SEC_IMP: /* SEt Carry flag.*/ + setflag(1, C); + break; + case STA_AB: /* STA Absolute. */ + case STA_Z: /* STA Zero Matrix. */ + case STA_ZX: /* STA Zero Matrix, Indexed with X. */ + case STA_ZY: /* STA Zero Matrix, Indexed with Y. */ + case STA_IN: /* STA Indirect. */ + case STA_IX: /* STA Indexed Indirect. */ + case STA_IY: /* STA Indirect Indexed. */ + store(cpu, address.u64, cpu->a, prefix, thread); + break; + case STY_AB: /* STY Absolute. */ + case STY_Z: /* STY Zero Matrix. */ + case STY_IN: /* STY Indirect. */ + store(cpu, address.u64, cpu->y, prefix, thread); + break; + case STX_AB: /* STX Absolute. */ + case STX_Z: /* STX Zero Matrix. */ + case STX_IN: /* STX Indirect. */ + store(cpu, address.u64, cpu->x, prefix, thread); + break; + case STB_AB: /* STB Absolute. */ + case STB_Z: /* STB Zero Matrix. */ + case STB_ZX: /* STB Zero Matrix, Indexed with X. */ + case STB_ZY: /* STB Zero Matrix, Indexed with Y. */ + case STB_IN: /* STB Indirect. */ + case STB_IX: /* STB Indexed Indirect. */ + case STB_IY: /* STB Indirect Indexed. */ + store(cpu, address.u64, cpu->b, prefix, thread); + break; + case BCC_REL: /* BCC Relative. */ + if (!getflag(C)) { + cpu->pc = address.u64; + } + break; + case LSR_B: /* LSR B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case LSR_IMM: /* LSR Immediate. */ + case LSR_AB: /* LSR Absolute. */ + case LSR_Z: /* LSR Zero Matrix. */ + cpu->a = lsr(cpu, cpu->a, value.u64, 8, thread); + break; + case ASR_B: /* ASR B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case ASR_IMM: /* ASR Immediate. */ + case ASR_AB: /* ASR Absolute. */ + case ASR_Z: /* ASR Zero Matrix. */ + cpu->a = asr(cpu, cpu->a, value.u64, 8, thread); + break; + case CLC_IMP: /* CLear Carry flag. */ + setflag(0, C); + break; + case LDB_IMM: /* LDB Immediate. */ + case LDB_AB: /* LDB Absolute. */ + case LDB_Z: /* LDB Zero Matrix. */ + case LDB_ZX: /* LDB Zero Matrix, Indexed with X. */ + case LDB_ZY: /* LDB Zero Matrix, Indexed with Y. */ + case LDB_IN: /* LDB Indirect. */ + case LDB_IX: /* LDB Indexed Indirect. */ + case LDB_IY: /* LDB Indirect Indexed. */ + cpu->b = load(cpu, cpu->b, address.u64, size, thread); + break; + case LDA_IMM: /* LDA Immediate. */ + case LDA_AB: /* LDA Absolute. */ + case LDA_Z: /* LDA Zero Matrix. */ + case LDA_ZX: /* LDA Zero Matrix, Indexed with X. */ + case LDA_ZY: /* LDA Zero Matrix, Indexed with Y. */ + case LDA_IN: /* LDA Indirect. */ + case LDA_IX: /* LDA Indexed Indirect. */ + case LDA_IY: /* LDA Indirect Indexed. */ + cpu->a = load(cpu, cpu->a, address.u64, size, thread); + break; + case LDY_IMM: /* LDY Immediate. */ + case LDY_AB: /* LDY Absolute. */ + case LDY_Z: /* LDY Zero Matrix. */ + case LDY_IN: /* LDY Indirect. */ + cpu->y = load(cpu, cpu->y, address.u64, size, thread); + break; + case LDX_IMM: /* LDX Immediate. */ + case LDX_AB: /* LDX Absolute. */ + case LDX_Z: /* LDX Zero Matrix. */ + case LDX_IN: /* LDX Indirect. */ + cpu->x = load(cpu, cpu->x, address.u64, size, thread); + break; + case BEQ_REL: /* BEQ Relative. */ + if (getflag(Z)) { + cpu->pc = address.u64; + } + break; + case ROL_B: /* ROL B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case ROL_IMM: /* ROL Immediate. */ + case ROL_AB: /* ROL Absolute. */ + case ROL_Z: /* ROL Zero Matrix. */ + cpu->a = rol(cpu, cpu->a, value.u64, 8, thread); + break; + case BNE_REL: /* BNE Relative. */ + if (!getflag(Z)) { + cpu->pc = address.u64; + } + break; + case ROR_B: /* ROR B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case ROR_IMM: /* ROR Immediate. */ + case ROR_AB: /* ROR Absolute. */ + case ROR_Z: /* ROR Zero Matrix. */ + cpu->a = ror(cpu, cpu->a, value.u64, 8, thread); + break; + case BVS_REL: /* BVS Relative. */ + if (getflag(V)) { + cpu->pc = address.u64; + } + break; + case MUL_B: /* MUL B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case MUL_IMM: /* MUL Immediate. */ + case MUL_AB: /* MUL Absolute. */ + case MUL_Z: /* MUL Zero Matrix. */ + cpu->a = mul(cpu, cpu->a, value.u64, thread); + break; + case BVC_REL: /* BVC Relative. */ + if (!getflag(V)) { + cpu->pc = address.u64; + } + break; + case DIV_B: /* DIV B register. */ + case DIV_IMM: /* DIV Immediate. */ + case DIV_AB: /* DIV Absolute. */ + case DIV_Z: /* DIV Zero Matrix. */ + rem = (opcode != DIV_B) ? &cpu->b : &cpu->x; + cpu->a = divd(cpu, cpu->a, value.u64, rem, thread); + break; + case CLV_IMP: /* CLear oVerflow flag. */ + setflag(0, V); + break; + case CPB_IMM: /* CPB Immediate. */ + case CPB_AB: /* CPB Absolute. */ + case CPB_Z: /* CPB Zero Matrix. */ + case CPB_IN: /* CPB Indirect. */ + case CPB_IX: /* CPB Indexed Indirect. */ + case CPB_IY: /* CPB Indirect Indexed. */ + adc(cpu, cpu->b, ~value.u64, 1, thread); + break; + case CMP_B: /* CMP B register. */ + value.u64 = cpu->b; /* Falls Through. */ + case CMP_IMM: /* CMP Immediate. */ + case CMP_AB: /* CMP Absolute. */ + case CMP_Z: /* CMP Zero Matrix. */ + case CMP_IN: /* CMP Indirect. */ + case CMP_IX: /* CMP Indexed Indirect. */ + case CMP_IY: /* CMP Indirect Indexed. */ + adc(cpu, cpu->a, ~value.u64, 1, thread); + break; + case CPY_IMM: /* CPY Immediate. */ + case CPY_AB: /* CPY Absolute. */ + case CPY_Z: /* CPY Zero Matrix. */ + adc(cpu, cpu->y, ~value.u64, 1, thread); + break; + case CPX_IMM: /* CPX Immediate. */ + case CPX_AB: /* CPX Absolute. */ + case CPX_Z: /* CPX Zero Matrix. */ + adc(cpu, cpu->x, ~value.u64, 1, thread); + break; + case INC_IMP: cpu->a = idr(cpu, cpu->a, 1, thread); break; + case INB_IMP: cpu->b = idr(cpu, cpu->b, 1, thread); break; + case INY_IMP: cpu->y = idr(cpu, cpu->y, 1, thread); break; + case INX_IMP: cpu->x = idr(cpu, cpu->x, 1, thread); break; + case DEC_IMP: cpu->a = idr(cpu, cpu->a, 0, thread); break; + case DEB_IMP: cpu->b = idr(cpu, cpu->b, 0, thread); break; + case DEY_IMP: cpu->y = idr(cpu, cpu->y, 0, thread); break; + case DEX_IMP: cpu->x = idr(cpu, cpu->x, 0, thread); break; + case JSR_IN: /* JSR Indirect. */ + case JSR_AB: /* Jump to SubRoutine. */ + case JSR_Z: /* JSR Zero Matrix. */ + push(cpu, cpu->pc, (size) ? size : 7, thread); + cpu->pc = address.u64; + break; + case INC_AB: /* INC Absolute. */ + case INC_Z: /* INC Zero Matrix. */ + idm(cpu, address.u64, prefix, 1, thread); + break; + case NOP_IMP: /* No OPeration. */ + break; + case RTI_IMP: /* ReTurn from Interrupt routine. */ + cpu->ps.u8[thread] = pull(cpu, 0, thread); + size = 0; + case RTS_IMP: /* ReTurn from Subroutine. */ + cpu->pc = pull(cpu, (size) ? size : 7, thread); + break; + case DEC_AB: /* DEC Absolute. */ + case DEC_Z: /* DEC Zero Matrix. */ + idm(cpu, address.u64, prefix, 0, thread); + break; + case BRK_IMP: /* BReaK. */ + case WAI_IMP: /* WAit for Interrupt. */ + if (opcode == WAI_IMP) { + pthread_mutex_lock(&main_mutex); + pthread_cond_signal(&main_cond); + pthread_mutex_unlock(&main_mutex); + pthread_mutex_lock(&mutex); + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + } + push(cpu, cpu->pc, 7, thread); + push(cpu, cpu->ps.u8[thread], 0, thread); + setflag(1, I); + value.u64 = read_value(cpu, 0, (opcode == BRK) ? 0xFFE0 : 0xFFA0, 7, 1, 0); + if (opcode == WAI_IMP) { + kbd_rdy &= (uint8_t)~(1 << thread); + } + cpu->pc = value.u64; + default: + break; + } +} @@ -104,7 +104,7 @@ static const uint8_t optype[0x100] = { [XOR_B ] = BREG, [CMP_B ] = BREG, [DEB_IMP ] = IMPL, - [TXS_IMM ] = IMM, + [TXS_IMP ] = IMPL, [STY_IN ] = IND, [PLA_IMP ] = IMPL, [BCC_REL ] = REL, @@ -171,3 +171,169 @@ static const uint8_t optype[0x100] = { [CPB_IY ] = INDY, [PLX_IMP ] = IMPL }; + +static const uint8_t ext_optype[0x100] = { + [LEA_AY ] = ABSY, + [ADD_IMM] = IMM, + [LEA_Z ] = ZM, + [CPE_IMM] = IMM, + [CLZ_Z ] = ZM, + [ADD_Z ] = ZM, + [STB_E ] = EIND, + [CPE_Z ] = ZM, + [LNG_IMM] = IMM, + [LNG_E ] = EIND, + [JMP_E ] = EIND, + [ADC_E ] = EIND, + [ROR_E ] = EIND, + [LEA_AB ] = ABS, + [CLZ_AB ] = ABS, + [ADD_AB ] = ABS, + [LEA_ZY ] = ZMY, + [CPE_AB ] = ABS, + [CLZ_E ] = EIND, + [ADD_E ] = EIND, + [LDX_E ] = EIND, + [SNG_E ] = EIND, + [PEA_AY ] = ABSY, + [SUB_IMM] = IMM, + [PEA_Z ] = ZM, + [CLO_Z ] = ZM, + [SUB_Z ] = ZM, + [STX_E ] = EIND, + [ICE_Z ] = ZM, + [LPO_IMM] = IMM, + [LPO_E ] = EIND, + [JSR_E ] = EIND, + [SBC_E ] = EIND, + [MUL_E ] = EIND, + [PEA_AB ] = ABS, + [CLO_AB ] = ABS, + [SUB_AB ] = ABS, + [PEA_ZY ] = ZMY, + [ICE_AB ] = ABS, + [CLO_E ] = EIND, + [SUB_E ] = EIND, + [CPB_E ] = EIND, + [ICE_E ] = EIND, + [SPO_E ] = EIND, + [LDS_IMM] = IMM, + [LEA_AI ] = AIND, + [LDS_Z ] = ZM, + [ADE_IMM] = IMM, + [LEA_IN ] = IND, + [BIT_Z ] = ZM, + [ADE_Z ] = ZM, + [CPX_E ] = EIND, + [LLM_Z ] = ZM, + [LCS_IMM] = IMM, + [LCS_E ] = EIND, + [LDS_AB ] = ABS, + [AND_E ] = EIND, + [DIV_E ] = EIND, + [LEA_AX ] = ABSX, + [LDS_E ] = EIND, + [BIT_AB ] = ABS, + [ADE_AB ] = ABS, + [LEA_ZX ] = ZMX, + [LLM_AB ] = ABS, + [BIT_E ] = EIND, + [CPY_E ] = EIND, + [LLM_E ] = EIND, + [SCS_E ] = EIND, + [SCO_IMM] = IMM, + [PEA_AI ] = AIND, + [SCO_Z ] = ZM, + [SBE_IMM] = IMM, + [PEA_IN ] = IND, + [SBE_Z ] = ZM, + [PHE_IMP] = IMPL, + [LRM_Z ] = ZM, + [LCC_IMM] = IMM, + [LCC_E ] = EIND, + [SCO_AB ] = ABS, + [ORA_E ] = EIND, + [ASR_E ] = EIND, + [PEA_AX ] = ABSX, + [SCO_E ] = EIND, + [SBE_AB ] = ABS, + [PEA_ZX ] = ZMX, + [LRM_AB ] = ABS, + [PLE_IMP] = IMPL, + [LRM_E ] = EIND, + [SCC_E ] = EIND, + [ECO_IMM] = IMM, + [DEC_E ] = EIND, + [LEA_AIY] = AINDY, + [ECO_Z ] = ZM, + [ADS_IMM] = IMM, + [LEA_IY ] = INDY, + [ADS_Z ] = ZM, + [DEE_IMP] = IMPL, + [RLM_Z ] = ZM, + [LEQ_IMM] = IMM, + [LEQ_E ] = EIND, + [ECO_AB ] = ABS, + [XOR_E ] = EIND, + [CMP_E ] = EIND, + [LEA_AIX] = AINDX, + [ECO_E ] = EIND, + [ADS_AB ] = ABS, + [LEA_IX ] = INDX, + [RLM_AB ] = ABS, + [ADS_E ] = EIND, + [INE_IMP] = IMPL, + [RLM_E ] = EIND, + [SEQ_E ] = EIND, + [INC_E ] = EIND, + [PEA_AIY] = AINDY, + [STS_Z ] = ZM, + [SBS_IMM] = IMM, + [PEA_IY ] = INDY, + [SBS_Z ] = ZM, + [DES_IMP] = IMPL, + [RRM_Z ] = ZM, + [LNE_IMM] = IMM, + [LNE_E ] = EIND, + [STS_AB ] = ABS, + [LSL_E ] = EIND, + [LDY_E ] = EIND, + [PEA_AIX] = AINDX, + [STS_E ] = EIND, + [SBS_AB ] = ABS, + [PEA_IX ] = INDX, + [RRM_AB ] = ABS, + [SBS_E ] = EIND, + [INS_IMP] = IMPL, + [RRM_E ] = EIND, + [REP_REL] = REL, + [SNE_E ] = EIND, + [STY_E ] = EIND, + [STE_Z ] = ZM, + [NOT_A ] = IMPL, + [NOT_Z ] = ZM, + [MMV_IMP] = IMPL, + [ARM_Z ] = ZM, + [REQ_REL] = REL, + [STE_AB ] = ABS, + [LSR_E ] = EIND, + [LDA_E ] = EIND, + [NOT_AB ] = ABS, + [ARM_AB ] = ABS, + [NOT_E ] = EIND, + [ARM_E ] = EIND, + [RNE_REL] = REL, + [STA_E ] = EIND, + [STZ_Z ] = ZM, + [SWP_A ] = IMPL, + [SWP_Z ] = ZM, + [PCN_Z ] = ZM, + [STZ_AB ] = ABS, + [ROL_E ] = EIND, + [LDB_E ] = EIND, + [STZ_E ] = EIND, + [SWP_AB ] = ABS, + [PCN_AB ] = ABS, + [SWP_E ] = EIND, + [PCN_E ] = EIND +}; diff --git a/test/base-ext.s b/test/base-ext.s new file mode 100644 index 0000000..8bf3d45 --- /dev/null +++ b/test/base-ext.s @@ -0,0 +1,19 @@ +.org $8000 +reset: + cps + lds.d #$3FFFF +loop: + lea $10 + inc (e) + lda (e) + lea ($FFC0) + bra loop + +.org $FFC0 +.qword reset +a +;l a +;.org reset +;v +;q +d |