Support more modes on `add` and `sub`.
Chris Pressey
3 years ago
11 | 11 | * `cmp` instruction can now perform a 16-bit unsigned comparison |
12 | 12 | of `word` memory locations and `word` literals (at the cost of |
13 | 13 | trashing the `a` register.) |
14 | * `add` (resp. `sub`) now support adding (resp. subtracting) a | |
15 | byte location or a byte literal from a byte location. | |
14 | 16 | * Fixed pathological memory use in the lexical scanner - should |
15 | 17 | be much less inefficient now when parsing large source files. |
16 | 18 | * Reorganized the examples in `eg/rudiments/` to make them |
332 | 332 | |
333 | 333 | Adds the contents of src to dest and stores the result in dest. |
334 | 334 | |
335 | * It is illegal if src OR dest OR c is uninitialized. | |
335 | * It is illegal if src OR dest OR `c` is uninitialized. | |
336 | 336 | * It is illegal if dest is read-only. |
337 | * It is illegal if dest is `x` or `y`. | |
337 | 338 | * It is illegal if dest does not occur in the WRITES of the current routine. |
338 | 339 | |
339 | 340 | Affects n, z, c, and v flags, requiring that they be in the WRITES, |
344 | 345 | In addition, if dest is of `word` type, then src must also be of `word` |
345 | 346 | type, and in this case this instruction trashes the `a` register. |
346 | 347 | |
348 | In fact, this instruction trashes the `a` register in all cases except | |
349 | when the dest is `a`. | |
350 | ||
347 | 351 | NOTE: If dest is a pointer, the addition does not check if the result of |
348 | 352 | the pointer arithmetic continues to be valid (within a buffer) or not. |
349 | 353 | |
366 | 370 | |
367 | 371 | Subtracts the contents of src from dest and stores the result in dest. |
368 | 372 | |
369 | * It is illegal if src OR dest OR c is uninitialized. | |
373 | * It is illegal if src OR dest OR `c` is uninitialized. | |
370 | 374 | * It is illegal if dest is read-only. |
375 | * It is illegal if dest is `x` or `y`. | |
371 | 376 | * It is illegal if dest does not occur in the WRITES of the current routine. |
372 | 377 | |
373 | 378 | Affects n, z, c, and v flags, requiring that they be in the WRITES, |
377 | 382 | |
378 | 383 | In addition, if dest is of `word` type, then src must also be of `word` |
379 | 384 | type, and in this case this instruction trashes the `a` register. |
385 | ||
386 | In fact, this instruction trashes the `a` register in all cases except | |
387 | when the dest is `a`. | |
380 | 388 | |
381 | 389 | ### dec ### |
382 | 390 |
532 | 532 | context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) |
533 | 533 | elif src.type == TYPE_BYTE: |
534 | 534 | self.assert_type(TYPE_BYTE, src, dest) |
535 | if dest != REG_A: | |
536 | context.set_touched(REG_A) | |
537 | context.set_unmeaningful(REG_A) | |
535 | 538 | else: |
536 | 539 | self.assert_type(TYPE_WORD, src) |
537 | 540 | if dest.type == TYPE_WORD: |
550 | 553 | context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE) |
551 | 554 | elif src.type == TYPE_BYTE: |
552 | 555 | self.assert_type(TYPE_BYTE, src, dest) |
556 | if dest != REG_A: | |
557 | context.set_touched(REG_A) | |
558 | context.set_unmeaningful(REG_A) | |
553 | 559 | else: |
554 | 560 | self.assert_type(TYPE_WORD, src, dest) |
555 | 561 | context.set_touched(REG_A) |
243 | 243 | raise UnsupportedOpcodeError(instr) |
244 | 244 | self.emitter.emit(op_cls(operand)) |
245 | 245 | elif opcode == 'add': |
246 | if dest == REG_X or dest == REG_Y: | |
247 | raise UnsupportedOpcodeError(instr) | |
246 | 248 | if dest == REG_A: |
247 | 249 | if isinstance(src, ConstantRef): |
248 | 250 | self.emitter.emit(ADC(Immediate(Byte(src.value)))) |
250 | 252 | self.emitter.emit(ADC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name)))) |
251 | 253 | else: |
252 | 254 | self.emitter.emit(ADC(Absolute(self.get_label(src.name)))) |
255 | elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE: | |
256 | if isinstance(src, ConstantRef): | |
257 | dest_label = self.get_label(dest.name) | |
258 | self.emitter.emit(LDA(Absolute(dest_label))) | |
259 | self.emitter.emit(ADC(Immediate(Byte(src.low_byte())))) | |
260 | self.emitter.emit(STA(Absolute(dest_label))) | |
261 | elif isinstance(src, LocationRef): | |
262 | src_label = self.get_label(src.name) | |
263 | dest_label = self.get_label(dest.name) | |
264 | self.emitter.emit(LDA(Absolute(dest_label))) | |
265 | self.emitter.emit(ADC(Absolute(src_label))) | |
266 | self.emitter.emit(STA(Absolute(dest_label))) | |
267 | else: | |
268 | raise UnsupportedOpcodeError(instr) | |
253 | 269 | elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD: |
254 | 270 | if isinstance(src, ConstantRef): |
255 | 271 | dest_label = self.get_label(dest.name) |
293 | 309 | else: |
294 | 310 | raise UnsupportedOpcodeError(instr) |
295 | 311 | elif opcode == 'sub': |
312 | if dest == REG_X or dest == REG_Y: | |
313 | raise UnsupportedOpcodeError(instr) | |
296 | 314 | if dest == REG_A: |
297 | 315 | if isinstance(src, ConstantRef): |
298 | 316 | self.emitter.emit(SBC(Immediate(Byte(src.value)))) |
300 | 318 | self.emitter.emit(SBC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name)))) |
301 | 319 | else: |
302 | 320 | self.emitter.emit(SBC(Absolute(self.get_label(src.name)))) |
321 | elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE: | |
322 | if isinstance(src, ConstantRef): | |
323 | dest_label = self.get_label(dest.name) | |
324 | self.emitter.emit(LDA(Absolute(dest_label))) | |
325 | self.emitter.emit(SBC(Immediate(Byte(src.low_byte())))) | |
326 | self.emitter.emit(STA(Absolute(dest_label))) | |
327 | elif isinstance(src, LocationRef): | |
328 | src_label = self.get_label(src.name) | |
329 | dest_label = self.get_label(dest.name) | |
330 | self.emitter.emit(LDA(Absolute(dest_label))) | |
331 | self.emitter.emit(SBC(Absolute(src_label))) | |
332 | self.emitter.emit(STA(Absolute(dest_label))) | |
333 | else: | |
334 | raise UnsupportedOpcodeError(instr) | |
303 | 335 | elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD: |
304 | 336 | if isinstance(src, ConstantRef): |
305 | 337 | dest_label = self.get_label(dest.name) |
869 | 869 | | byte lives |
870 | 870 | | define main routine |
871 | 871 | | inputs a, lives |
872 | | outputs lives | |
872 | | outputs a, lives | |
873 | 873 | | trashes c, z, v, n |
874 | 874 | | { |
875 | 875 | | st off, c |
876 | 876 | | add lives, 3 |
877 | | } | |
878 | ? UnmeaningfulOutputError: a | |
879 | ||
880 | You can `add` a byte memory location to another byte memory location. | |
881 | This trashes `a`. | |
882 | ||
883 | | byte lives | |
884 | | byte extra | |
885 | | define main routine | |
886 | | inputs a, lives, extra | |
887 | | outputs lives | |
888 | | trashes a, c, z, v, n | |
889 | | { | |
890 | | st off, c | |
891 | | add lives, extra | |
892 | | } | |
893 | = ok | |
894 | ||
895 | | byte lives | |
896 | | byte extra | |
897 | | define main routine | |
898 | | inputs a, lives, extra | |
899 | | outputs a, lives | |
900 | | trashes c, z, v, n | |
901 | | { | |
902 | | st off, c | |
903 | | add lives, extra | |
877 | 904 | | } |
878 | 905 | ? UnmeaningfulOutputError: a |
879 | 906 | |
1039 | 1066 | | byte lives |
1040 | 1067 | | define main routine |
1041 | 1068 | | inputs a, lives |
1042 | | outputs lives | |
1069 | | outputs a, lives | |
1043 | 1070 | | trashes c, z, v, n |
1044 | 1071 | | { |
1045 | 1072 | | st on, c |
1046 | 1073 | | sub lives, 3 |
1074 | | } | |
1075 | ? UnmeaningfulOutputError: a | |
1076 | ||
1077 | You can `sub` a byte memory location from another byte memory location. | |
1078 | This trashes `a`. | |
1079 | ||
1080 | | byte lives | |
1081 | | byte extra | |
1082 | | define main routine | |
1083 | | inputs a, lives, extra | |
1084 | | outputs lives | |
1085 | | trashes a, c, z, v, n | |
1086 | | { | |
1087 | | st on, c | |
1088 | | sub lives, extra | |
1089 | | } | |
1090 | = ok | |
1091 | ||
1092 | | byte lives | |
1093 | | byte extra | |
1094 | | define main routine | |
1095 | | inputs a, lives, extra | |
1096 | | outputs a, lives | |
1097 | | trashes c, z, v, n | |
1098 | | { | |
1099 | | st on, c | |
1100 | | sub lives, extra | |
1047 | 1101 | | } |
1048 | 1102 | ? UnmeaningfulOutputError: a |
1049 | 1103 |
1029 | 1029 | Various modes of `add`. |
1030 | 1030 | |
1031 | 1031 | | byte lives |
1032 | | byte extra | |
1032 | 1033 | | word score |
1033 | | define main routine | |
1034 | | inputs lives, score | |
1034 | | word bonus | |
1035 | | define main routine | |
1036 | | inputs lives, score, extra, bonus | |
1035 | 1037 | | outputs lives, score |
1036 | 1038 | | trashes a, x, y, c, z, v, n |
1037 | 1039 | | { |
1041 | 1043 | | st off, c |
1042 | 1044 | | add a, 7 |
1043 | 1045 | | add a, lives |
1044 | | // add x, 7 | |
1045 | | // add y, 7 | |
1046 | 1046 | | add lives, 2 |
1047 | | add lives, extra | |
1047 | 1048 | | add score, 1999 |
1048 | | } | |
1049 | = $080D CLC | |
1050 | = $080E LDA $081F | |
1051 | = $0811 ADC #$CF | |
1052 | = $0813 STA $081F | |
1053 | = $0816 LDA $0820 | |
1054 | = $0819 ADC #$07 | |
1055 | = $081B STA $0820 | |
1056 | = $081E RTS | |
1049 | | add score, bonus | |
1050 | | } | |
1051 | = $080D LDA #$00 | |
1052 | = $080F LDX #$00 | |
1053 | = $0811 LDY #$00 | |
1054 | = $0813 CLC | |
1055 | = $0814 ADC #$07 | |
1056 | = $0816 ADC $084D | |
1057 | = $0819 LDA $084D | |
1058 | = $081C ADC #$02 | |
1059 | = $081E STA $084D | |
1060 | = $0821 LDA $084D | |
1061 | = $0824 ADC $084E | |
1062 | = $0827 STA $084D | |
1063 | = $082A LDA $084F | |
1064 | = $082D ADC #$CF | |
1065 | = $082F STA $084F | |
1066 | = $0832 LDA $0850 | |
1067 | = $0835 ADC #$07 | |
1068 | = $0837 STA $0850 | |
1069 | = $083A LDA $084F | |
1070 | = $083D ADC $0851 | |
1071 | = $0840 STA $084F | |
1072 | = $0843 LDA $0850 | |
1073 | = $0846 ADC $0852 | |
1074 | = $0849 STA $0850 | |
1075 | = $084C RTS | |
1076 | ||
1077 | Various modes of `sub`. | |
1078 | ||
1079 | | byte lives | |
1080 | | byte extra | |
1081 | | word score | |
1082 | | word bonus | |
1083 | | define main routine | |
1084 | | inputs lives, score, extra, bonus | |
1085 | | outputs lives, score | |
1086 | | trashes a, x, y, c, z, v, n | |
1087 | | { | |
1088 | | ld a, 0 | |
1089 | | ld x, 0 | |
1090 | | ld y, 0 | |
1091 | | st on, c | |
1092 | | sub a, 7 | |
1093 | | sub a, lives | |
1094 | | sub lives, 2 | |
1095 | | sub lives, extra | |
1096 | | sub score, 1999 | |
1097 | | sub score, bonus | |
1098 | | } | |
1099 | = $080D LDA #$00 | |
1100 | = $080F LDX #$00 | |
1101 | = $0811 LDY #$00 | |
1102 | = $0813 SEC | |
1103 | = $0814 SBC #$07 | |
1104 | = $0816 SBC $084D | |
1105 | = $0819 LDA $084D | |
1106 | = $081C SBC #$02 | |
1107 | = $081E STA $084D | |
1108 | = $0821 LDA $084D | |
1109 | = $0824 SBC $084E | |
1110 | = $0827 STA $084D | |
1111 | = $082A LDA $084F | |
1112 | = $082D SBC #$CF | |
1113 | = $082F STA $084F | |
1114 | = $0832 LDA $0850 | |
1115 | = $0835 SBC #$07 | |
1116 | = $0837 STA $0850 | |
1117 | = $083A LDA $084F | |
1118 | = $083D SBC $0851 | |
1119 | = $0840 STA $084F | |
1120 | = $0843 LDA $0850 | |
1121 | = $0846 SBC $0852 | |
1122 | = $0849 STA $0850 | |
1123 | = $084C RTS | |
1057 | 1124 | |
1058 | 1125 | ### word operations |
1059 | 1126 |