История изменений
Исправление PPP328, (текущая версия) :
Ты можешь на сишных макросах сделать статические проверки ассемблерного кода, не позволяющие сунуть неправильный операнд не в ту инструкцию?
Да.
Можно даже с проверкой самих передаваемый значений, там же опкод меняется в зависимости от того, что сунули, ZP, адрес, значение или сахарок в виде A,X
/A,Y
/(A),Y
/(A, X)
. Всё без проблем чекается. Мне даже в отличие от этой хаскеле-срани не нужно указывать какой тип передачи значения, я и сам могу задетектить:
// Concatenate
#define CAT__(x) x
#define CAT_(x, y) CAT__(x ## y)
#define CAT(x, y) CAT_(x, y)
// Count variadica arguments
#define ARGC(...) ARGC_(__VA_ARGS__, ARGC_RSEQ_N())
#define ARGC_(...) ARGC_N(__VA_ARGS__)
#define ARGC_N(_1, _2, N, ...) N
#define ARGC_RSEQ_N() 2, 1, 0
// Syntax routines
#define EXPAND(x) x
#define COMMA(x) ,
// OPCODES
#define OPCODE_LDA_ABSOLUTE 0xAD // LDA 0x0000..0xFFFF
#define OPCODE_LDA_ABSOLUTE_INDEXX 0xBD // LDA 0x0000..0xFFFF, X
#define OPCODE_LDA_ABSOLUTE_INDEXY 0xB9 // LDA 0x0000..0xFFFF, Y
#define OPCODE_LDA_IMMEDIATE 0xA9 // LDA #0x00..#0xFF
#define OPCODE_LDA_ZEROPAGE 0xA5 // LDA 0x00..0xFF
#define OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX 0xA1 // LDA (0x00..0xFF, X)
#define OPCODE_LDA_ZEROPAGE_INDEXX 0xB5 // LDA 0x00..0xFF, X
#define OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY 0xB1 // LDA (0x00..0xFF), Y
#define OPCODE_CPX_ABSOLUTE 0xEC // CPX 0x0000..0xFFFF
#define OPCODE_CPX_IMMEDIATE 0xE0 // CPX #0x00..0xFF
#define OPCODE_CPX_ZEROPAGE 0xE4 // CPX 0x00..0xFF
#define OPCODE_RTS 0x60 // RTS
// VALUE CONVERTERS
// ZP tester
#define VALUE_TEST_0x00 0
#define VALUE_TEST_0x01 0
#define VALUE_TEST_0x02 0
#define VALUE_TEST_0x03 0
#define VALUE_TEST_0x04 0
#define VALUE_TEST_0x05 0
// ... I'm too lazy, works for MVP
#define VALUE_TEST_0xFF 0
// ADDRESS tester
#define VALUE_TEST_0x0001 1
#define VALUE_TEST_0x0002 1
#define VALUE_TEST_0x0003 1
#define VALUE_TEST_0x0004 1
#define VALUE_TEST_0x0005 1
// .. I'm too lazy, works for MVP
#define VALUE_TEST_0xFFFF 1
// IMMEDIATE tester
#define VALUE_TEST__0x00 2
#define VALUE_TEST__0x01 2
#define VALUE_TEST__0x02 2
#define VALUE_TEST__0x03 2
#define VALUE_TEST__0x04 2
// .. I'm too lazy, works for MVP
#define VALUE_TEST__0x05 2
// Immediate marker remover
#define VALUE_DEIM_0x00 0x00
#define VALUE_DEIM_0x01 0x01
#define VALUE_DEIM_0x02 0x02
#define VALUE_DEIM_0x03 0x03
#define VALUE_DEIM_0x04 0x04
// .. I'm too lazy, works for MVP
#define VALUE_DEIM_0xFF 0xFF
// U16 splitter
#define U16_SPLIT_0x0000 0x00, 0x00
#define U16_SPLIT_0x0001 0x01, 0x00
#define U16_SPLIT_0x0002 0x02, 0x00
#define U16_SPLIT_0x0003 0x03, 0x00
#define U16_SPLIT_0x0004 0x04, 0x00
// .. I'm too lazy, works for MVP
#define U16_SPLIT_0xFFFF 0xFF, 0xFF
// INSTRUCTION: LDA
/* Allowed LDA notations:
* a | a, x | a, y | #
* zp | (zp, x) | zp, x | (zp), y */
#define LDA_CHECKZPX(...) CAT(LDA_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define LDA_PROCESSOR_ARG1_1_0(val) OPCODE_LDA_ZEROPAGE, val,
// a
#define LDA_PROCESSOR_ARG1_1_1(val) OPCODE_LDA_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define LDA_PROCESSOR_ARG1_1_2(val) OPCODE_LDA_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define LDA_PROCESSOR_ARG1_1(x) CAT(LDA_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define LDA_PROCESSOR_ARG1_2_(x, reg) OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX, x,
#define LDA_PROCESSOR_ARG1_2(x) LDA_PROCESSOR_ARG1_2_ x
// a | _ | zp | (zp, x)
#define LDA_ARGC_1(x) CAT(LDA_PROCESSOR_ARG1_,ARGC(LDA_CHECKZPX x))(x)
// a,x
#define LDA_PROCESSOR_AXY_X(val) OPCODE_LDA_ABSOLUTE_INDEXX, CAT(U16_SPLIT_, val),
// a,y
#define LDA_PROCESSOR_AXY_Y(val) OPCODE_LDA_ABSOLUTE_INDEXY, CAT(U16_SPLIT_, val),
// a,x | a, y
#define LDA_PREOCESSOR_AXYZP_1(val, reg) CAT(LDA_PROCESSOR_AXY_, reg)(val)
// zp, x
#define LDA_PREOCESSOR_AXYZP_0(val, reg) OPCODE_LDA_ZEROPAGE_INDEXX, val,
// a, x | a, y | zp, x
#define LDA_PROCESSOR_ARG2_1(val, reg) CAT(LDA_PREOCESSOR_AXYZP_, CAT(VALUE_TEST_, val))(val, reg)
// (zp), y
#define LDA_PROCESSOR_ARG2_2(val, reg) OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY, EXPAND val,
// a, x | a, y | zp, x | (zp), y
#define LDA_ARGC_2(val, reg) CAT(LDA_PROCESSOR_ARG2_, ARGC(LDA_CHECKINDIR COMMA val))(val, reg)
#define LDA(...) CAT(LDA_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// INSTRUCTION: RTS
// Implied only
#define RTS OPCODE_RTS,
// INSTRUCTION: CPX
// a, #, zp
#define CPX_ARGC_2(a, b) "CPX cannot be used with 2 arguments"
#define CPX_CHECKZPX(...) CAT(CPX_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define CPX_PROCESSOR_ARG1_1_0(val) OPCODE_CPX_ZEROPAGE, val,
// a
#define CPX_PROCESSOR_ARG1_1_1(val) OPCODE_CPX_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define CPX_PROCESSOR_ARG1_1_2(val) OPCODE_CPX_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define CPX_PROCESSOR_ARG1_1(x) CAT(CPX_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define CPX_PROCESSOR_ARG1_2_(x, reg) "CPX cannot be used with ZP-indirect syntax"
#define CPX_PROCESSOR_ARG1_2(x) CPX_PROCESSOR_ARG1_2_ x
#define CPX_ARGC_1(x) CAT(CPX_PROCESSOR_ARG1_,ARGC(CPX_CHECKZPX x))(x)
#define CPX(...) CAT(CPX_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
/* Notes:
* * Use C-like hex ("0x" prefix)
* * For immediate value use "_" prefix. */
const unsigned char binary[] = {
LDA (0x0001) // 0xAD, 0x01, 0x00,
LDA (0x0002, X) // 0xBD, 0x02, 0x00,
LDA (0x0003, Y) // 0xB9, 0x03, 0x00,
LDA (_0x04) // 0xA9, 0x04,
LDA (0x05) // 0xA5, 0x05,
LDA ((0x04, X)) // 0xA1, 0x06,
LDA (0x03, X) // 0xB5, 0x03,
LDA ((0x02), Y) // 0xB1, 0x02,
CPX (0x0001) // 0xEC, 0x01, 0x00,
CPX (0x0002, X) // <<<BAD
CPX (0x0003, Y) // <<<BAD
CPX (_0x04) // 0xE0, 0x04,
CPX (0x05) // 0xE4, 0x05,
CPX ((0x04, X)) // <<<BAD
CPX (0x03, X) // <<<BAD
CPX ((0x02), Y) // <<<BAD
RTS // 0x60
}
gcc -E main.c | grep -v "^#"
const unsigned char binary[] = {
0xAD, 0x01, 0x00,
0xBD, 0x02, 0x00,
0xB9, 0x03, 0x00,
0xA9, 0x04,
0xA5, 0x05,
0xA1, 0x04,
0xB5, 0x03,
0xB1, 0x02,
0xEC, 0x01, 0x00,
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0xE0, 0x04,
0xE4, 0x05,
"CPX cannot be used with ZP-indirect syntax"
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0x60,
}
На компиляции, соответственно, высветит строку с ошибкой
P.S. Мне лень генерить чиселки, там сейчас саппорт от 0x0000 до 0x0005. Кому нужно - тот сам сгенерит строчки.
Исправление PPP328, :
Ты можешь на сишных макросах сделать статические проверки ассемблерного кода, не позволяющие сунуть неправильный операнд не в ту инструкцию?
Да.
Можно даже с проверкой самих передаваемый значений, там же опкод меняется в зависимости от того, что сунули, ZP, адрес, значение или сахарок в виде A,X
/A,Y
/(A),Y
/(A, X)
. Всё без проблем чекается. Мне даже в отличие от этой хаскеле-срани не нужно указывать какой тип передачи значения, я и сам могу задетектить:
// Concatenate
#define CAT__(x) x
#define CAT_(x, y) CAT__(x ## y)
#define CAT(x, y) CAT_(x, y)
// Count variadica arguments
#define ARGC(...) ARGC_(__VA_ARGS__, ARGC_RSEQ_N())
#define ARGC_(...) ARGC_N(__VA_ARGS__)
#define ARGC_N(_1, _2, N, ...) N
#define ARGC_RSEQ_N() 2, 1, 0
// Syntax routines
#define EXPAND(x) x
#define COMMA(x) ,
// OPCODES
#define OPCODE_LDA_ABSOLUTE 0xAD // LDA 0x0000..0xFFFF
#define OPCODE_LDA_ABSOLUTE_INDEXX 0xBD // LDA 0x0000..0xFFFF, X
#define OPCODE_LDA_ABSOLUTE_INDEXY 0xB9 // LDA 0x0000..0xFFFF, Y
#define OPCODE_LDA_IMMEDIATE 0xA9 // LDA #0x00..#0xFF
#define OPCODE_LDA_ZEROPAGE 0xA5 // LDA 0x00..0xFF
#define OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX 0xA1 // LDA (0x00..0xFF, X)
#define OPCODE_LDA_ZEROPAGE_INDEXX 0xB5 // LDA 0x00..0xFF, X
#define OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY 0xB1 // LDA (0x00..0xFF), Y
#define OPCODE_CPX_ABSOLUTE 0xEC // CPX 0x0000..0xFFFF
#define OPCODE_CPX_IMMEDIATE 0xE0 // CPX #0x00..0xFF
#define OPCODE_CPX_ZEROPAGE 0xE4 // CPX 0x00..0xFF
#define OPCODE_RTS 0x60 // RTS
// VALUE CONVERTERS
// ZP tester
#define VALUE_TEST_0x00 0
#define VALUE_TEST_0x01 0
#define VALUE_TEST_0x02 0
#define VALUE_TEST_0x03 0
#define VALUE_TEST_0x04 0
#define VALUE_TEST_0x05 0
// ... I'm too lazy, works for MVP
#define VALUE_TEST_0xFF 0
// ADDRESS tester
#define VALUE_TEST_0x0001 1
#define VALUE_TEST_0x0002 1
#define VALUE_TEST_0x0003 1
#define VALUE_TEST_0x0004 1
#define VALUE_TEST_0x0005 1
// .. I'm too lazy, works for MVP
#define VALUE_TEST_0xFFFF 1
// IMMEDIATE tester
#define VALUE_TEST__0x00 2
#define VALUE_TEST__0x01 2
#define VALUE_TEST__0x02 2
#define VALUE_TEST__0x03 2
#define VALUE_TEST__0x04 2
// .. I'm too lazy, works for MVP
#define VALUE_TEST__0x05 2
// Immediate marker remover
#define VALUE_DEIM_0x00 0x00
#define VALUE_DEIM_0x01 0x01
#define VALUE_DEIM_0x02 0x02
#define VALUE_DEIM_0x03 0x03
#define VALUE_DEIM_0x04 0x04
// .. I'm too lazy, works for MVP
#define VALUE_DEIM_0xFF 0xFF
// U16 splitter
#define U16_SPLIT_0x0000 0x00, 0x00
#define U16_SPLIT_0x0001 0x01, 0x00
#define U16_SPLIT_0x0002 0x02, 0x00
#define U16_SPLIT_0x0003 0x03, 0x00
#define U16_SPLIT_0x0004 0x04, 0x00
// .. I'm too lazy, works for MVP
#define U16_SPLIT_0xFFFF 0xFF, 0xFF
// INSTRUCTION: LDA
/* Allowed LDA notations:
* a | a, x | a, y | #
* zp | (zp, x) | zp, x | (zp), y */
#define LDA_CHECKZPX(...) CAT(LDA_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define LDA_PROCESSOR_ARG1_1_0(val) OPCODE_LDA_ZEROPAGE, val,
// a
#define LDA_PROCESSOR_ARG1_1_1(val) OPCODE_LDA_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define LDA_PROCESSOR_ARG1_1_2(val) OPCODE_LDA_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define LDA_PROCESSOR_ARG1_1(x) CAT(LDA_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define LDA_PROCESSOR_ARG1_2_(x, reg) OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX, x,
#define LDA_PROCESSOR_ARG1_2(x) LDA_PROCESSOR_ARG1_2_ x
// a | _ | zp | (zp, x)
#define LDA_ARGC_1(x) CAT(LDA_PROCESSOR_ARG1_,ARGC(LDA_CHECKZPX x))(x)
// a,x
#define LDA_PROCESSOR_AXY_X(val) OPCODE_LDA_ABSOLUTE_INDEXX, CAT(U16_SPLIT_, val),
// a,y
#define LDA_PROCESSOR_AXY_Y(val) OPCODE_LDA_ABSOLUTE_INDEXY, CAT(U16_SPLIT_, val),
// a,x | a, y
#define LDA_PREOCESSOR_AXYZP_1(val, reg) CAT(LDA_PROCESSOR_AXY_, reg)(val)
// zp, x
#define LDA_PREOCESSOR_AXYZP_0(val, reg) OPCODE_LDA_ZEROPAGE_INDEXX, val,
// a, x | a, y | zp, x
#define LDA_PROCESSOR_ARG2_1(val, reg) CAT(LDA_PREOCESSOR_AXYZP_, CAT(VALUE_TEST_, val))(val, reg)
// (zp), y
#define LDA_PROCESSOR_ARG2_2(val, reg) OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY, EXPAND val,
// a, x | a, y | zp, x | (zp), y
#define LDA_ARGC_2(val, reg) CAT(LDA_PROCESSOR_ARG2_, ARGC(LDA_CHECKINDIR COMMA val))(val, reg)
#define LDA(...) CAT(LDA_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// INSTRUCTION: RTS
// Implied only
#define RTS OPCODE_RTS,
// INSTRUCTION: CPX
// a, #, zp
#define CPX_ARGC_2(a, b) "CPX cannot be used with 2 arguments"
#define CPX_CHECKZPX(...) CAT(CPX_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define CPX_PROCESSOR_ARG1_1_0(val) OPCODE_CPX_ZEROPAGE, val,
// a
#define CPX_PROCESSOR_ARG1_1_1(val) OPCODE_CPX_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define CPX_PROCESSOR_ARG1_1_2(val) OPCODE_CPX_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define CPX_PROCESSOR_ARG1_1(x) CAT(CPX_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define CPX_PROCESSOR_ARG1_2_(x, reg) "CPX cannot be used with ZP-indirect syntax"
#define CPX_PROCESSOR_ARG1_2(x) CPX_PROCESSOR_ARG1_2_ x
#define CPX_ARGC_1(x) CAT(CPX_PROCESSOR_ARG1_,ARGC(CPX_CHECKZPX x))(x)
#define CPX(...) CAT(CPX_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// -------------------------------------------------------------------------
/* Notes:
* * Use C-like hex ("0x" prefix)
* * For immediate value use "_" prefix. */
const unsigned char binary[] = {
LDA (0x0001) // 0xAD, 0x01, 0x00,
LDA (0x0002, X) // 0xBD, 0x02, 0x00,
LDA (0x0003, Y) // 0xB9, 0x03, 0x00,
LDA (_0x04) // 0xA9, 0x04,
LDA (0x05) // 0xA5, 0x05,
LDA ((0x04, X)) // 0xA1, 0x06,
LDA (0x03, X) // 0xB5, 0x03,
LDA ((0x02), Y) // 0xB1, 0x02,
CPX (0x0001) // 0xEC, 0x01, 0x00,
CPX (0x0002, X) // <<<BAD
CPX (0x0003, Y) // <<<BAD
CPX (_0x04) // 0xE0, 0x04,
CPX (0x05) // 0xE4, 0x05,
CPX ((0x04, X)) // <<<BAD
CPX (0x03, X) // <<<BAD
CPX ((0x02), Y) // <<<BAD
RTS // 0x60
}
gcc -E main.c | grep -v "^#"
const unsigned char binary[] = {
0xAD, 0x01, 0x00,
0xBD, 0x02, 0x00,
0xB9, 0x03, 0x00,
0xA9, 0x04,
0xA5, 0x05,
0xA1, 0x04,
0xB5, 0x03,
0xB1, 0x02,
0xEC, 0x01, 0x00,
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0xE0, 0x04,
0xE4, 0x05,
"CPX cannot be used with ZP-indirect syntax"
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0x60,
}
На компиляции, соответственно, высветит строку с ошибкой
P.S. Мне лень генерить чиселки, там сейчас саппорт от 0x0000 до 0x0005. Кому нужно - тот сам сгенерит строчки.
Исправление PPP328, :
Ты можешь на сишных макросах сделать статические проверки ассемблерного кода, не позволяющие сунуть неправильный операнд не в ту инструкцию?
Да.
Можно даже с проверкой самих передаваемый значений, там же опкод меняется в зависимости от того, что сунули, ZP, адрес, значение или сахарок в виде A,X
/A,Y
/(A),Y
/(A, X)
. Всё без проблем чекается:
// Concatenate
#define CAT__(x) x
#define CAT_(x, y) CAT__(x ## y)
#define CAT(x, y) CAT_(x, y)
// Count variadica arguments
#define ARGC(...) ARGC_(__VA_ARGS__, ARGC_RSEQ_N())
#define ARGC_(...) ARGC_N(__VA_ARGS__)
#define ARGC_N(_1, _2, N, ...) N
#define ARGC_RSEQ_N() 2, 1, 0
// Syntax routines
#define EXPAND(x) x
#define COMMA(x) ,
// OPCODES
#define OPCODE_LDA_ABSOLUTE 0xAD // LDA 0x0000..0xFFFF
#define OPCODE_LDA_ABSOLUTE_INDEXX 0xBD // LDA 0x0000..0xFFFF, X
#define OPCODE_LDA_ABSOLUTE_INDEXY 0xB9 // LDA 0x0000..0xFFFF, Y
#define OPCODE_LDA_IMMEDIATE 0xA9 // LDA #0x00..#0xFF
#define OPCODE_LDA_ZEROPAGE 0xA5 // LDA 0x00..0xFF
#define OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX 0xA1 // LDA (0x00..0xFF, X)
#define OPCODE_LDA_ZEROPAGE_INDEXX 0xB5 // LDA 0x00..0xFF, X
#define OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY 0xB1 // LDA (0x00..0xFF), Y
#define OPCODE_CPX_ABSOLUTE 0xEC // CPX 0x0000..0xFFFF
#define OPCODE_CPX_IMMEDIATE 0xE0 // CPX #0x00..0xFF
#define OPCODE_CPX_ZEROPAGE 0xE4 // CPX 0x00..0xFF
#define OPCODE_RTS 0x60 // RTS
// VALUE CONVERTERS
// ZP tester
#define VALUE_TEST_0x00 0
#define VALUE_TEST_0x01 0
#define VALUE_TEST_0x02 0
#define VALUE_TEST_0x03 0
#define VALUE_TEST_0x04 0
#define VALUE_TEST_0x05 0
// ... I'm too lazy, works for MVP
#define VALUE_TEST_0xFF 0
// ADDRESS tester
#define VALUE_TEST_0x0001 1
#define VALUE_TEST_0x0002 1
#define VALUE_TEST_0x0003 1
#define VALUE_TEST_0x0004 1
#define VALUE_TEST_0x0005 1
// .. I'm too lazy, works for MVP
#define VALUE_TEST_0xFFFF 1
// IMMEDIATE tester
#define VALUE_TEST__0x00 2
#define VALUE_TEST__0x01 2
#define VALUE_TEST__0x02 2
#define VALUE_TEST__0x03 2
#define VALUE_TEST__0x04 2
// .. I'm too lazy, works for MVP
#define VALUE_TEST__0x05 2
// Immediate marker remover
#define VALUE_DEIM_0x00 0x00
#define VALUE_DEIM_0x01 0x01
#define VALUE_DEIM_0x02 0x02
#define VALUE_DEIM_0x03 0x03
#define VALUE_DEIM_0x04 0x04
// .. I'm too lazy, works for MVP
#define VALUE_DEIM_0xFF 0xFF
// U16 splitter
#define U16_SPLIT_0x0000 0x00, 0x00
#define U16_SPLIT_0x0001 0x01, 0x00
#define U16_SPLIT_0x0002 0x02, 0x00
#define U16_SPLIT_0x0003 0x03, 0x00
#define U16_SPLIT_0x0004 0x04, 0x00
// .. I'm too lazy, works for MVP
#define U16_SPLIT_0xFFFF 0xFF, 0xFF
// INSTRUCTION: LDA
/* Allowed LDA notations:
* a | a, x | a, y | #
* zp | (zp, x) | zp, x | (zp), y */
#define LDA_CHECKZPX(...) CAT(LDA_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define LDA_PROCESSOR_ARG1_1_0(val) OPCODE_LDA_ZEROPAGE, val,
// a
#define LDA_PROCESSOR_ARG1_1_1(val) OPCODE_LDA_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define LDA_PROCESSOR_ARG1_1_2(val) OPCODE_LDA_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define LDA_PROCESSOR_ARG1_1(x) CAT(LDA_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define LDA_PROCESSOR_ARG1_2_(x, reg) OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX, x,
#define LDA_PROCESSOR_ARG1_2(x) LDA_PROCESSOR_ARG1_2_ x
// a | _ | zp | (zp, x)
#define LDA_ARGC_1(x) CAT(LDA_PROCESSOR_ARG1_,ARGC(LDA_CHECKZPX x))(x)
// a,x
#define LDA_PROCESSOR_AXY_X(val) OPCODE_LDA_ABSOLUTE_INDEXX, CAT(U16_SPLIT_, val),
// a,y
#define LDA_PROCESSOR_AXY_Y(val) OPCODE_LDA_ABSOLUTE_INDEXY, CAT(U16_SPLIT_, val),
// a,x | a, y
#define LDA_PREOCESSOR_AXYZP_1(val, reg) CAT(LDA_PROCESSOR_AXY_, reg)(val)
// zp, x
#define LDA_PREOCESSOR_AXYZP_0(val, reg) OPCODE_LDA_ZEROPAGE_INDEXX, val,
// a, x | a, y | zp, x
#define LDA_PROCESSOR_ARG2_1(val, reg) CAT(LDA_PREOCESSOR_AXYZP_, CAT(VALUE_TEST_, val))(val, reg)
// (zp), y
#define LDA_PROCESSOR_ARG2_2(val, reg) OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY, EXPAND val,
// a, x | a, y | zp, x | (zp), y
#define LDA_ARGC_2(val, reg) CAT(LDA_PROCESSOR_ARG2_, ARGC(LDA_CHECKINDIR COMMA val))(val, reg)
#define LDA(...) CAT(LDA_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// INSTRUCTION: RTS
// Implied only
#define RTS OPCODE_RTS,
// INSTRUCTION: CPX
// a, #, zp
#define CPX_ARGC_2(a, b) "CPX cannot be used with 2 arguments"
#define CPX_CHECKZPX(...) CAT(CPX_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define CPX_PROCESSOR_ARG1_1_0(val) OPCODE_CPX_ZEROPAGE, val,
// a
#define CPX_PROCESSOR_ARG1_1_1(val) OPCODE_CPX_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define CPX_PROCESSOR_ARG1_1_2(val) OPCODE_CPX_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define CPX_PROCESSOR_ARG1_1(x) CAT(CPX_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define CPX_PROCESSOR_ARG1_2_(x, reg) "CPX cannot be used with ZP-indirect syntax"
#define CPX_PROCESSOR_ARG1_2(x) CPX_PROCESSOR_ARG1_2_ x
#define CPX_ARGC_1(x) CAT(CPX_PROCESSOR_ARG1_,ARGC(CPX_CHECKZPX x))(x)
#define CPX(...) CAT(CPX_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// -------------------------------------------------------------------------
/* Notes:
* * Use C-like hex ("0x" prefix)
* * For immediate value use "_" prefix. */
const unsigned char binary[] = {
LDA (0x0001) // 0xAD, 0x01, 0x00,
LDA (0x0002, X) // 0xBD, 0x02, 0x00,
LDA (0x0003, Y) // 0xB9, 0x03, 0x00,
LDA (_0x04) // 0xA9, 0x04,
LDA (0x05) // 0xA5, 0x05,
LDA ((0x04, X)) // 0xA1, 0x06,
LDA (0x03, X) // 0xB5, 0x03,
LDA ((0x02), Y) // 0xB1, 0x02,
CPX (0x0001) // 0xEC, 0x01, 0x00,
CPX (0x0002, X) // <<<BAD
CPX (0x0003, Y) // <<<BAD
CPX (_0x04) // 0xE0, 0x04,
CPX (0x05) // 0xE4, 0x05,
CPX ((0x04, X)) // <<<BAD
CPX (0x03, X) // <<<BAD
CPX ((0x02), Y) // <<<BAD
RTS // 0x60
}
gcc -E main.c | grep -v "^#"
const unsigned char binary[] = {
0xAD, 0x01, 0x00,
0xBD, 0x02, 0x00,
0xB9, 0x03, 0x00,
0xA9, 0x04,
0xA5, 0x05,
0xA1, 0x04,
0xB5, 0x03,
0xB1, 0x02,
0xEC, 0x01, 0x00,
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0xE0, 0x04,
0xE4, 0x05,
"CPX cannot be used with ZP-indirect syntax"
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0x60,
}
На компиляции, соответственно, высветит строку с ошибкой
P.S. Мне лень генерить чиселки, там сейчас саппорт от 0x0000 до 0x0005. Кому нужно - тот сам сгенерит строчки.
Исходная версия PPP328, :
Ты можешь на сишных макросах сделать статические проверки ассемблерного кода, не позволяющие сунуть неправильный операнд не в ту инструкцию?
Да.
Можно даже с проверкой самих передаваемый значений, там же опкод меняется в зависимости от того, что сунули, ZP, адрес, значение или сахарок в виде A,X
/A,Y
/(A),Y
/(A, X)
. Всё без проблем чекается:
// Concatenate
#define CAT__(x) x
#define CAT_(x, y) CAT__(x ## y)
#define CAT(x, y) CAT_(x, y)
// Count variadica arguments
#define ARGC(...) ARGC_(__VA_ARGS__, ARGC_RSEQ_N())
#define ARGC_(...) ARGC_N(__VA_ARGS__)
#define ARGC_N(_1, _2, N, ...) N
#define ARGC_RSEQ_N() 2, 1, 0
// Syntax routines
#define EXPAND(x) x
#define COMMA(x) ,
// OPCODES
#define OPCODE_LDA_ABSOLUTE 0xAD // LDA 0x0000..0xFFFF
#define OPCODE_LDA_ABSOLUTE_INDEXX 0xBD // LDA 0x0000..0xFFFF, X
#define OPCODE_LDA_ABSOLUTE_INDEXY 0xB9 // LDA 0x0000..0xFFFF, Y
#define OPCODE_LDA_IMMEDIATE 0xA9 // LDA #0x00..#0xFF
#define OPCODE_LDA_ZEROPAGE 0xA5 // LDA 0x00..0xFF
#define OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX 0xA1 // LDA (0x00..0xFF, X)
#define OPCODE_LDA_ZEROPAGE_INDEXX 0xB5 // LDA 0x00..0xFF, X
#define OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY 0xB1 // LDA (0x00..0xFF), Y
#define OPCODE_CPX_ABSOLUTE 0xEC // CPX 0x0000..0xFFFF
#define OPCODE_CPX_IMMEDIATE 0xE0 // CPX #0x00..0xFF
#define OPCODE_CPX_ZEROPAGE 0xE4 // CPX 0x00..0xFF
#define OPCODE_RTS 0x60 // RTS
// VALUE CONVERTERS
// ZP tester
#define VALUE_TEST_0x00 0
#define VALUE_TEST_0x01 0
#define VALUE_TEST_0x02 0
#define VALUE_TEST_0x03 0
#define VALUE_TEST_0x04 0
#define VALUE_TEST_0x05 0
// ... I'm too lazy, works for MVP
#define VALUE_TEST_0xFF 0
// ADDRESS tester
#define VALUE_TEST_0x0001 1
#define VALUE_TEST_0x0002 1
#define VALUE_TEST_0x0003 1
#define VALUE_TEST_0x0004 1
#define VALUE_TEST_0x0005 1
// .. I'm too lazy, works for MVP
#define VALUE_TEST_0xFFFF 1
// IMMEDIATE tester
#define VALUE_TEST__0x00 2
#define VALUE_TEST__0x01 2
#define VALUE_TEST__0x02 2
#define VALUE_TEST__0x03 2
#define VALUE_TEST__0x04 2
// .. I'm too lazy, works for MVP
#define VALUE_TEST__0x05 2
// Immediate marker remover
#define VALUE_DEIM_0x00 0x00
#define VALUE_DEIM_0x01 0x01
#define VALUE_DEIM_0x02 0x02
#define VALUE_DEIM_0x03 0x03
#define VALUE_DEIM_0x04 0x04
// .. I'm too lazy, works for MVP
#define VALUE_DEIM_0xFF 0xFF
// U16 splitter
#define U16_SPLIT_0x0000 0x00, 0x00
#define U16_SPLIT_0x0001 0x01, 0x00
#define U16_SPLIT_0x0002 0x02, 0x00
#define U16_SPLIT_0x0003 0x03, 0x00
#define U16_SPLIT_0x0004 0x04, 0x00
// .. I'm too lazy, works for MVP
#define U16_SPLIT_0xFFFF 0xFF, 0xFF
// INSTRUCTION: LDA
/* Allowed LDA notations:
* a | a, x | a, y | #
* zp | (zp, x) | zp, x | (zp), y */
#define LDA_CHECKZPX(...) CAT(LDA_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define LDA_PROCESSOR_ARG1_1_0(val) OPCODE_LDA_ZEROPAGE, val,
// a
#define LDA_PROCESSOR_ARG1_1_1(val) OPCODE_LDA_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define LDA_PROCESSOR_ARG1_1_2(val) OPCODE_LDA_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define LDA_PROCESSOR_ARG1_1(x) CAT(LDA_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define LDA_PROCESSOR_ARG1_2_(x, reg) OPCODE_LDA_ZEROPAGE_INDIRECT_INDEXX, x,
#define LDA_PROCESSOR_ARG1_2(x) LDA_PROCESSOR_ARG1_2_ x
// a | _ | zp | (zp, x)
#define LDA_ARGC_1(x) CAT(LDA_PROCESSOR_ARG1_,ARGC(LDA_CHECKZPX x))(x)
// a,x
#define LDA_PROCESSOR_AXY_X(val) OPCODE_LDA_ABSOLUTE_INDEXX, CAT(U16_SPLIT_, val),
// a,y
#define LDA_PROCESSOR_AXY_Y(val) OPCODE_LDA_ABSOLUTE_INDEXY, CAT(U16_SPLIT_, val),
// a,x | a, y
#define LDA_PREOCESSOR_AXYZP_1(val, reg) CAT(LDA_PROCESSOR_AXY_, reg)(val)
// zp, x
#define LDA_PREOCESSOR_AXYZP_0(val, reg) OPCODE_LDA_ZEROPAGE_INDEXX, val,
// a, x | a, y | zp, x
#define LDA_PROCESSOR_ARG2_1(val, reg) CAT(LDA_PREOCESSOR_AXYZP_, CAT(VALUE_TEST_, val))(val, reg)
// (zp), y
#define LDA_PROCESSOR_ARG2_2(val, reg) OPCODE_LDA_ZEROPAGE_INDIRECTY_INDEXY, EXPAND val,
// a, x | a, y | zp, x | (zp), y
#define LDA_ARGC_2(val, reg) CAT(LDA_PROCESSOR_ARG2_, ARGC(LDA_CHECKINDIR COMMA val))(val, reg)
#define LDA(...) CAT(LDA_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// INSTRUCTION: RTS
// Implied only
#define RTS OPCODE_RTS,
// INSTRUCTION: CPX
// a, #, zp
#define CPX_ARGC_2(a, b) "CPX cannot be used with 2 arguments"
#define CPX_CHECKZPX(...) CAT(CPX_CHECKZPX_, ARGC(__VA_ARGS__)),
// zp
#define CPX_PROCESSOR_ARG1_1_0(val) OPCODE_CPX_ZEROPAGE, val,
// a
#define CPX_PROCESSOR_ARG1_1_1(val) OPCODE_CPX_ABSOLUTE, CAT(U16_SPLIT_, val),
// _
#define CPX_PROCESSOR_ARG1_1_2(val) OPCODE_CPX_IMMEDIATE, CAT(VALUE_DEIM, val),
// a | _ | zp
#define CPX_PROCESSOR_ARG1_1(x) CAT(CPX_PROCESSOR_ARG1_1_, CAT(VALUE_TEST_, x))(x)
// (zp, x)
#define CPX_PROCESSOR_ARG1_2_(x, reg) "CPX cannot be used with ZP-indirect syntax"
#define CPX_PROCESSOR_ARG1_2(x) CPX_PROCESSOR_ARG1_2_ x
#define CPX_ARGC_1(x) CAT(CPX_PROCESSOR_ARG1_,ARGC(CPX_CHECKZPX x))(x)
#define CPX(...) CAT(CPX_ARGC, CAT(_, ARGC(__VA_ARGS__)))(__VA_ARGS__)
// -------------------------------------------------------------------------
/* Notes:
* * Use C-like hex ("0x" prefix)
* * For immediate value use "_" prefix. */
const unsigned char binary[] = {
LDA (0x0001) // 0xAD, 0x01, 0x00,
LDA (0x0002, X) // 0xBD, 0x02, 0x00,
LDA (0x0003, Y) // 0xB9, 0x03, 0x00,
LDA (_0x04) // 0xA9, 0x04,
LDA (0x05) // 0xA5, 0x05,
LDA ((0x04, X)) // 0xA1, 0x06,
LDA (0x03, X) // 0xB5, 0x03,
LDA ((0x02), Y) // 0xB1, 0x02,
CPX (0x0001) // 0xEC, 0x01, 0x00,
CPX (0x0002, X) // <<<BAD
CPX (0x0003, Y) // <<<BAD
CPX (_0x04) // 0xE0, 0x04,
CPX (0x05) // 0xE4, 0x05,
CPX ((0x04, X)) // <<<BAD
CPX (0x03, X) // <<<BAD
CPX ((0x02), Y) // <<<BAD
RTS // 0x60
}
gcc -E main.c
| grep -v «^#»
const unsigned char binary[] = {
0xAD, 0x01, 0x00,
0xBD, 0x02, 0x00,
0xB9, 0x03, 0x00,
0xA9, 0x04,
0xA5, 0x05,
0xA1, 0x04,
0xB5, 0x03,
0xB1, 0x02,
0xEC, 0x01, 0x00,
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0xE0, 0x04,
0xE4, 0x05,
"CPX cannot be used with ZP-indirect syntax"
"CPX cannot be used with 2 arguments"
"CPX cannot be used with 2 arguments"
0x60,
}
На компиляции, соответственно, высветит строку с ошибкой
P.S. Мне лень генерить чиселки, там сейчас саппорт от 0x0000 до 0x0005. Кому нужно - тот сам сгенерит строчки.