mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-06 20:35:28 +00:00
Merge pull request #18 from catseye/more-modes-on-add-and-sub
More modes on add and sub
This commit is contained in:
commit
75449d7271
@ -15,6 +15,8 @@ History of SixtyPical
|
||||
* `cmp` instruction can now perform a 16-bit unsigned comparison
|
||||
of `word` memory locations and `word` literals (at the cost of
|
||||
trashing the `a` register.)
|
||||
* `add` (resp. `sub`) now support adding (resp. subtracting) a
|
||||
byte location or a byte literal from a byte location.
|
||||
* Fixed pathological memory use in the lexical scanner - should
|
||||
be much less inefficient now when parsing large source files.
|
||||
* Reorganized the examples in `eg/rudiments/` to make them
|
||||
|
@ -333,8 +333,9 @@ this mode is used.
|
||||
|
||||
Adds the contents of src to dest and stores the result in dest.
|
||||
|
||||
* It is illegal if src OR dest OR c is uninitialized.
|
||||
* It is illegal if src OR dest OR `c` is uninitialized.
|
||||
* It is illegal if dest is read-only.
|
||||
* It is illegal if dest is `x` or `y`.
|
||||
* It is illegal if dest does not occur in the WRITES of the current routine.
|
||||
|
||||
Affects n, z, c, and v flags, requiring that they be in the WRITES,
|
||||
@ -345,6 +346,9 @@ dest and src continue to be initialized afterwards.
|
||||
In addition, if dest is of `word` type, then src must also be of `word`
|
||||
type, and in this case this instruction trashes the `a` register.
|
||||
|
||||
In fact, this instruction trashes the `a` register in all cases except
|
||||
when the dest is `a`.
|
||||
|
||||
NOTE: If dest is a pointer, the addition does not check if the result of
|
||||
the pointer arithmetic continues to be valid (within a buffer) or not.
|
||||
|
||||
@ -367,8 +371,9 @@ and initializing them afterwards.
|
||||
|
||||
Subtracts the contents of src from dest and stores the result in dest.
|
||||
|
||||
* It is illegal if src OR dest OR c is uninitialized.
|
||||
* It is illegal if src OR dest OR `c` is uninitialized.
|
||||
* It is illegal if dest is read-only.
|
||||
* It is illegal if dest is `x` or `y`.
|
||||
* It is illegal if dest does not occur in the WRITES of the current routine.
|
||||
|
||||
Affects n, z, c, and v flags, requiring that they be in the WRITES,
|
||||
@ -379,6 +384,9 @@ dest and src continue to be initialized afterwards.
|
||||
In addition, if dest is of `word` type, then src must also be of `word`
|
||||
type, and in this case this instruction trashes the `a` register.
|
||||
|
||||
In fact, this instruction trashes the `a` register in all cases except
|
||||
when the dest is `a`.
|
||||
|
||||
### dec ###
|
||||
|
||||
dec <dest-memory-location>
|
||||
|
@ -533,6 +533,9 @@ class Analyzer(object):
|
||||
context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE)
|
||||
elif src.type == TYPE_BYTE:
|
||||
self.assert_type(TYPE_BYTE, src, dest)
|
||||
if dest != REG_A:
|
||||
context.set_touched(REG_A)
|
||||
context.set_unmeaningful(REG_A)
|
||||
else:
|
||||
self.assert_type(TYPE_WORD, src)
|
||||
if dest.type == TYPE_WORD:
|
||||
@ -551,6 +554,9 @@ class Analyzer(object):
|
||||
context.assert_types_for_read_table(instr, src, dest, TYPE_BYTE)
|
||||
elif src.type == TYPE_BYTE:
|
||||
self.assert_type(TYPE_BYTE, src, dest)
|
||||
if dest != REG_A:
|
||||
context.set_touched(REG_A)
|
||||
context.set_unmeaningful(REG_A)
|
||||
else:
|
||||
self.assert_type(TYPE_WORD, src, dest)
|
||||
context.set_touched(REG_A)
|
||||
|
@ -244,6 +244,8 @@ class Compiler(object):
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
self.emitter.emit(op_cls(operand))
|
||||
elif opcode == 'add':
|
||||
if dest == REG_X or dest == REG_Y:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(ADC(Immediate(Byte(src.value))))
|
||||
@ -251,6 +253,20 @@ class Compiler(object):
|
||||
self.emitter.emit(ADC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name))))
|
||||
else:
|
||||
self.emitter.emit(ADC(Absolute(self.get_label(src.name))))
|
||||
elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE:
|
||||
if isinstance(src, ConstantRef):
|
||||
dest_label = self.get_label(dest.name)
|
||||
self.emitter.emit(LDA(Absolute(dest_label)))
|
||||
self.emitter.emit(ADC(Immediate(Byte(src.low_byte()))))
|
||||
self.emitter.emit(STA(Absolute(dest_label)))
|
||||
elif isinstance(src, LocationRef):
|
||||
src_label = self.get_label(src.name)
|
||||
dest_label = self.get_label(dest.name)
|
||||
self.emitter.emit(LDA(Absolute(dest_label)))
|
||||
self.emitter.emit(ADC(Absolute(src_label)))
|
||||
self.emitter.emit(STA(Absolute(dest_label)))
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD:
|
||||
if isinstance(src, ConstantRef):
|
||||
dest_label = self.get_label(dest.name)
|
||||
@ -294,6 +310,8 @@ class Compiler(object):
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'sub':
|
||||
if dest == REG_X or dest == REG_Y:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(SBC(Immediate(Byte(src.value))))
|
||||
@ -301,6 +319,20 @@ class Compiler(object):
|
||||
self.emitter.emit(SBC(self.addressing_mode_for_index(src.index)(self.get_label(src.ref.name))))
|
||||
else:
|
||||
self.emitter.emit(SBC(Absolute(self.get_label(src.name))))
|
||||
elif isinstance(dest, LocationRef) and src.type == TYPE_BYTE and dest.type == TYPE_BYTE:
|
||||
if isinstance(src, ConstantRef):
|
||||
dest_label = self.get_label(dest.name)
|
||||
self.emitter.emit(LDA(Absolute(dest_label)))
|
||||
self.emitter.emit(SBC(Immediate(Byte(src.low_byte()))))
|
||||
self.emitter.emit(STA(Absolute(dest_label)))
|
||||
elif isinstance(src, LocationRef):
|
||||
src_label = self.get_label(src.name)
|
||||
dest_label = self.get_label(dest.name)
|
||||
self.emitter.emit(LDA(Absolute(dest_label)))
|
||||
self.emitter.emit(SBC(Absolute(src_label)))
|
||||
self.emitter.emit(STA(Absolute(dest_label)))
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif isinstance(dest, LocationRef) and src.type == TYPE_WORD and dest.type == TYPE_WORD:
|
||||
if isinstance(src, ConstantRef):
|
||||
dest_label = self.get_label(dest.name)
|
||||
|
@ -852,6 +852,59 @@ Can't `add` to a memory location that isn't writeable.
|
||||
| }
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `add` a byte constant to a byte memory location.
|
||||
|
||||
| byte lives
|
||||
| define main routine
|
||||
| inputs a, lives
|
||||
| outputs lives
|
||||
| trashes a, c, z, v, n
|
||||
| {
|
||||
| st off, c
|
||||
| add lives, 3
|
||||
| }
|
||||
= ok
|
||||
|
||||
`add`ing a byte constant to a byte memory location trashes `a`.
|
||||
|
||||
| byte lives
|
||||
| define main routine
|
||||
| inputs a, lives
|
||||
| outputs a, lives
|
||||
| trashes c, z, v, n
|
||||
| {
|
||||
| st off, c
|
||||
| add lives, 3
|
||||
| }
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
You can `add` a byte memory location to another byte memory location.
|
||||
This trashes `a`.
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| define main routine
|
||||
| inputs a, lives, extra
|
||||
| outputs lives
|
||||
| trashes a, c, z, v, n
|
||||
| {
|
||||
| st off, c
|
||||
| add lives, extra
|
||||
| }
|
||||
= ok
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| define main routine
|
||||
| inputs a, lives, extra
|
||||
| outputs a, lives
|
||||
| trashes c, z, v, n
|
||||
| {
|
||||
| st off, c
|
||||
| add lives, extra
|
||||
| }
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
You can `add` a word constant to a word memory location.
|
||||
|
||||
| word score
|
||||
@ -996,6 +1049,59 @@ Can't `sub` to a memory location that isn't writeable.
|
||||
| }
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `sub` a byte constant from a byte memory location.
|
||||
|
||||
| byte lives
|
||||
| define main routine
|
||||
| inputs a, lives
|
||||
| outputs lives
|
||||
| trashes a, c, z, v, n
|
||||
| {
|
||||
| st on, c
|
||||
| sub lives, 3
|
||||
| }
|
||||
= ok
|
||||
|
||||
`sub`ing a byte constant from a byte memory location trashes `a`.
|
||||
|
||||
| byte lives
|
||||
| define main routine
|
||||
| inputs a, lives
|
||||
| outputs a, lives
|
||||
| trashes c, z, v, n
|
||||
| {
|
||||
| st on, c
|
||||
| sub lives, 3
|
||||
| }
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
You can `sub` a byte memory location from another byte memory location.
|
||||
This trashes `a`.
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| define main routine
|
||||
| inputs a, lives, extra
|
||||
| outputs lives
|
||||
| trashes a, c, z, v, n
|
||||
| {
|
||||
| st on, c
|
||||
| sub lives, extra
|
||||
| }
|
||||
= ok
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| define main routine
|
||||
| inputs a, lives, extra
|
||||
| outputs a, lives
|
||||
| trashes c, z, v, n
|
||||
| {
|
||||
| st on, c
|
||||
| sub lives, extra
|
||||
| }
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
You can `sub` a word constant from a word memory location.
|
||||
|
||||
| word score
|
||||
|
@ -1025,6 +1025,104 @@ Copying to and from a vector table.
|
||||
= $0842 JMP ($0846)
|
||||
= $0845 RTS
|
||||
|
||||
### add, sub
|
||||
|
||||
Various modes of `add`.
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| word score
|
||||
| word bonus
|
||||
| define main routine
|
||||
| inputs lives, score, extra, bonus
|
||||
| outputs lives, score
|
||||
| trashes a, x, y, c, z, v, n
|
||||
| {
|
||||
| ld a, 0
|
||||
| ld x, 0
|
||||
| ld y, 0
|
||||
| st off, c
|
||||
| add a, 7
|
||||
| add a, lives
|
||||
| add lives, 2
|
||||
| add lives, extra
|
||||
| add score, 1999
|
||||
| add score, bonus
|
||||
| }
|
||||
= $080D LDA #$00
|
||||
= $080F LDX #$00
|
||||
= $0811 LDY #$00
|
||||
= $0813 CLC
|
||||
= $0814 ADC #$07
|
||||
= $0816 ADC $084D
|
||||
= $0819 LDA $084D
|
||||
= $081C ADC #$02
|
||||
= $081E STA $084D
|
||||
= $0821 LDA $084D
|
||||
= $0824 ADC $084E
|
||||
= $0827 STA $084D
|
||||
= $082A LDA $084F
|
||||
= $082D ADC #$CF
|
||||
= $082F STA $084F
|
||||
= $0832 LDA $0850
|
||||
= $0835 ADC #$07
|
||||
= $0837 STA $0850
|
||||
= $083A LDA $084F
|
||||
= $083D ADC $0851
|
||||
= $0840 STA $084F
|
||||
= $0843 LDA $0850
|
||||
= $0846 ADC $0852
|
||||
= $0849 STA $0850
|
||||
= $084C RTS
|
||||
|
||||
Various modes of `sub`.
|
||||
|
||||
| byte lives
|
||||
| byte extra
|
||||
| word score
|
||||
| word bonus
|
||||
| define main routine
|
||||
| inputs lives, score, extra, bonus
|
||||
| outputs lives, score
|
||||
| trashes a, x, y, c, z, v, n
|
||||
| {
|
||||
| ld a, 0
|
||||
| ld x, 0
|
||||
| ld y, 0
|
||||
| st on, c
|
||||
| sub a, 7
|
||||
| sub a, lives
|
||||
| sub lives, 2
|
||||
| sub lives, extra
|
||||
| sub score, 1999
|
||||
| sub score, bonus
|
||||
| }
|
||||
= $080D LDA #$00
|
||||
= $080F LDX #$00
|
||||
= $0811 LDY #$00
|
||||
= $0813 SEC
|
||||
= $0814 SBC #$07
|
||||
= $0816 SBC $084D
|
||||
= $0819 LDA $084D
|
||||
= $081C SBC #$02
|
||||
= $081E STA $084D
|
||||
= $0821 LDA $084D
|
||||
= $0824 SBC $084E
|
||||
= $0827 STA $084D
|
||||
= $082A LDA $084F
|
||||
= $082D SBC #$CF
|
||||
= $082F STA $084F
|
||||
= $0832 LDA $0850
|
||||
= $0835 SBC #$07
|
||||
= $0837 STA $0850
|
||||
= $083A LDA $084F
|
||||
= $083D SBC $0851
|
||||
= $0840 STA $084F
|
||||
= $0843 LDA $0850
|
||||
= $0846 SBC $0852
|
||||
= $0849 STA $0850
|
||||
= $084C RTS
|
||||
|
||||
### word operations
|
||||
|
||||
Adding a constant word to a word memory location.
|
||||
|
Loading…
Reference in New Issue
Block a user