Merge pull request #18 from catseye/more-modes-on-add-and-sub
More modes on add and sub
Chris Pressey authored 3 years ago
GitHub committed 3 years ago
14 | 14 | * `cmp` instruction can now perform a 16-bit unsigned comparison |
15 | 15 | of `word` memory locations and `word` literals (at the cost of |
16 | 16 | trashing the `a` register.) |
17 | * `add` (resp. `sub`) now support adding (resp. subtracting) a | |
18 | byte location or a byte literal from a byte location. | |
17 | 19 | * Fixed pathological memory use in the lexical scanner - should |
18 | 20 | be much less inefficient now when parsing large source files. |
19 | 21 | * 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) |
851 | 851 | | } |
852 | 852 | ? ForbiddenWriteError: a |
853 | 853 | |
854 | You can `add` a byte constant to a byte memory location. | |
855 | ||
856 | | byte lives | |
857 | | define main routine | |
858 | | inputs a, lives | |
859 | | outputs lives | |
860 | | trashes a, c, z, v, n | |
861 | | { | |
862 | | st off, c | |
863 | | add lives, 3 | |
864 | | } | |
865 | = ok | |
866 | ||
867 | `add`ing a byte constant to a byte memory location trashes `a`. | |
868 | ||
869 | | byte lives | |
870 | | define main routine | |
871 | | inputs a, lives | |
872 | | outputs a, lives | |
873 | | trashes c, z, v, n | |
874 | | { | |
875 | | st off, c | |
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 | |
904 | | } | |
905 | ? UnmeaningfulOutputError: a | |
906 | ||
854 | 907 | You can `add` a word constant to a word memory location. |
855 | 908 | |
856 | 909 | | word score |
994 | 1047 | | sub a, 0 |
995 | 1048 | | } |
996 | 1049 | ? ForbiddenWriteError: a |
1050 | ||
1051 | You can `sub` a byte constant from a byte memory location. | |
1052 | ||
1053 | | byte lives | |
1054 | | define main routine | |
1055 | | inputs a, lives | |
1056 | | outputs lives | |
1057 | | trashes a, c, z, v, n | |
1058 | | { | |
1059 | | st on, c | |
1060 | | sub lives, 3 | |
1061 | | } | |
1062 | = ok | |
1063 | ||
1064 | `sub`ing a byte constant from a byte memory location trashes `a`. | |
1065 | ||
1066 | | byte lives | |
1067 | | define main routine | |
1068 | | inputs a, lives | |
1069 | | outputs a, lives | |
1070 | | trashes c, z, v, n | |
1071 | | { | |
1072 | | st on, c | |
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 | |
1101 | | } | |
1102 | ? UnmeaningfulOutputError: a | |
997 | 1103 | |
998 | 1104 | You can `sub` a word constant from a word memory location. |
999 | 1105 |
1024 | 1024 | = $0842 JMP ($0846) |
1025 | 1025 | = $0845 RTS |
1026 | 1026 | |
1027 | ### add, sub | |
1028 | ||
1029 | Various modes of `add`. | |
1030 | ||
1031 | | byte lives | |
1032 | | byte extra | |
1033 | | word score | |
1034 | | word bonus | |
1035 | | define main routine | |
1036 | | inputs lives, score, extra, bonus | |
1037 | | outputs lives, score | |
1038 | | trashes a, x, y, c, z, v, n | |
1039 | | { | |
1040 | | ld a, 0 | |
1041 | | ld x, 0 | |
1042 | | ld y, 0 | |
1043 | | st off, c | |
1044 | | add a, 7 | |
1045 | | add a, lives | |
1046 | | add lives, 2 | |
1047 | | add lives, extra | |
1048 | | add score, 1999 | |
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 | |
1124 | ||
1027 | 1125 | ### word operations |
1028 | 1126 | |
1029 | 1127 | Adding a constant word to a word memory location. |