I've never had a need to use the ($nn,x) addressing mode. What's an example of something it's useful for? - 6502

I've used ($nn),y plenty of times, it's pretty much the 6502's bread-and-butter method of iterating through arrays. But I've never found a use for ($nn,x). The only time I've ever thought about using it is when x = 0. It seems like any problem that can be solved with STA ($nn,x) can just as easily be done with hardcoded pointers like in this example with writing to the Konami VRC6 sound hardware:
LDX #2
loop:
LDA (musicptr),y
STA $9000,x ;pulse 1 channel regs
STA $A000,x ;pulse 2 channel regs
STA $B000,x ;sawtooth channel regs
DEX
BNE loop
Versus:
LDA #$00
STA $10
STA $12
STA $14
LDA #$90
STA $11
LDA #$A0
STA $13
LDA #$B0
STA $15
LDX #$00
loop:
LDA (musicptr),y
STA ($10,x) ;first pass: STA $9000. second pass: STA $A000. third pass: STA $B000
INX
INX
CPX #6
BNE loop
I know that not every tool needs to be used, but I just can't think of a purpose for this addressing mode at all.

Checking out some well-known source code of the era, from a system where the 6502 was used to build an actual OS with hardware abstraction, the BBC MOS uses ($nn,x) in only two instances:
OSWORD 5 and 6, which read and write bytes to IO addresses; and
to write teletext characters to the screen.
So:
this probably confirms that the addressing mode isn't especially useful — just three usages in 16kb of code, with two of those just being the read/write versions of the same operation; and
it demonstrates the main use case: reading or writing to somewhere via a table of pointers.
Despite your assertion as a comment above:
IO space cannot just be made into a table of bytes indexed by ($nn),y because it has fixed locations; and
video memory cannot just be made into a table of bytes indexed by ($nn),y because it has fixed locations.

Since there is no indirect mode without indexing in the original 6502, one use is to set x to 0 to emulate such a mode.
ldx #0
lda ($zp,x)
Yes you can do it with the y register and lda ($zp),y, but maybe y has got a value in it that you want to keep.
Other than that, I've got nothing.

Related

Divison in LMC with and without remainder

I need a bit of help to code how to divide a sum of numbers, divided by n numbers put in. For instance, the sum is 10, with 2 numbers, the answer should be 5. But if the sum is 14 and the total input (n numbers) are 3, it should write out 4, ignoring the 2 remainders, og for example, sum equals to 16 and total inputs equal to 3, the output should be 5, ignoring the 1 in remainder. But I don't know how to have these two in one code without interfering with each other.
This is my current code
START INP
BRZ SLUTT
ADD sum
STA sum
LDA antall
ADD en
STA antall
BRP START
SLUTT LDA sum
OUT
LDA linjeskift
OTC
OTC
OTC
LDA n
OTC
LDA likhetstegn
OTC
LDA antall
OUT
LDA linjeskift
OTC
OTC
OTC
LDA d
OTC
LDA likhetstegn
OTC
start LDA sum
BRZ slutt
SUB antall
STA sum
LDA resultat
ADD en
STA resultat
BRP start
slutt LDA resultat
OUT
HLT
sum DAT
resultat DAT 0
antall DAT 0
en DAT 1
a DAT 97
d DAT 100
n DAT 110
linjeskift DAT 13
likhetstegn DAT 61
The main problem is that your BRP instruction, in the division part of the code, comes too late. It is supposed to check whether the subtraction of antall from sum still was non-negative, but as your code continues first by loading the resultat into the accumulator, the detection of the negative result can no longer happen... BRP will find that the latest operation (the update of resultat) was non-negative.
In short, that second part of the code should perform a BRP right after SUB. In LMC this is a general rule for doing it right: always have a BRP immediately after a SUB.
Some other comments:
Once you make the above correction, the BRZ slutt isn't really necessary anymore, as surely the next SUB will then return a negative result and trigger the output anyway. (but see next point)
On the other hand, if the number of inputs (antall) is zero, we would be dividing by zero, which comes down to an infinite loop. This should be avoided by making an extra check.
I did not quite get why your code has the middle part, where you print characters using OTC. It seems unrelated to the goal of the challenge.
Labels should be unique. Although they work fine on Peter Higginson's simulator, some LMC simulators do not distinguish between uppercase and lowercase labels, so it is better practice to use really distinctive labels, irrespective of case.
LMC provides a way to reset the program counter, which does not clear the mailboxes to their initial values. So for instance, a reset would not set sum or resultat to zero. It is therefore good practice to start the program with the initialisation of such "variables", so that the program will still behave correctly when the user uses the reset feature.
The first part of the code has a BRP which really should always branch, so it would be more natural to use BRA. It also works with BRP, as antall will not get negative, but it seems more intuitive to use the unconditional jump instruction here.
Here is the updated code, with the above remarks taken into account:
init LDA zero # Initialise variables before starting
STA resultat
STA antall
STA sum
start INP
BRZ validate
ADD sum
STA sum
LDA antall
ADD en
STA antall
BRA start # use BRA instead of BRP
validate LDA antall # check against division by zero
BRZ slutt
divide LDA sum
SUB antall
BRP continue # Important: SUB followed by BRP!
slutt LDA resultat
OUT
zero HLT
continue STA sum
LDA resultat
ADD en
STA resultat
BRA divide
sum DAT
resultat DAT
antall DAT
en DAT 1
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>

How to check if a number is odd or even in little man computer

I need help with making my program produce the correct output.
I am currently working with this code:
INP
STA NUMBER
SUB DIVISOR
BRP VERIFY
BRA CHECK
LOOP STA NUMBER
LDA RESULT
ADD ONE
STA RESULT
VERIFY LDA NUMBER
SUB DIVISOR
BRP LOOP
LDA RESULT
ODD LDA ONE
STA RESULT
EVEN LDA 60
STA RESULT
CHECK LDA RESULT
BRP ODD
BRZ EVEN
OUT
HLT
NUMBER DAT
DIVISOR DAT 2
ONE DAT 1
RESULT DAT 0
When I run the code above on little man computer simulator, it just loops and loops and prints no output. What I wanted to do is divide the inputted number into two and check if it has a remainder. If it has a remainder, then it is an odd number, else it is an even number. I know that the code has errors but I can't pinpoint where the problem lies, maybe you can help me with it. Thanks in advance!
The infinite loop occurs at BRP ODD. Be aware that BRP also branches when the accumulator is zero. So it is a "branch when not negative" instruction. And when the execution continues at ODD, it falls through to EVEN, which makes the code at ODD irrelevant. At EVEN the accumulator is loaded with zero, and so the BRP will branch again... infinitely.
There is also a missing check for 0: when the input is zero, you should not perform the subtraction at all.
Not a problem, but having a reference to mailbox 60 can be better replaced with a reference to a label, like ZERO.
The code includes logic that really isn't necessary:
You have included code to calculate the quotient, since the code adds ONE to the RESULT every time you subtract the DIVISOR from the NUMBER. However, that RESULT is finally overwritten with either ONE or zero (address 60), so that quotient was calculated for nothing. As you only want to output whether the input was odd or even, you should drop the quotient calculation from your code.
Also avoid code repetition. You currently perform the SUB at two different places. This should not be necessary as the logic should be the same in both instances.
Here is the code reduced to its basics:
#input: 11
INP
STA NUMBER
LOOP BRZ OUTPUT # remainder is zero! so output a zero
SUB DIVISOR
BRP LOOP
LDA ONE # when result is negative, input was odd
OUTPUT OUT
HLT
NUMBER DAT
DIVISOR DAT 2
ONE DAT 1
ZERO DAT 0
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>
You can run the simulator in this snippet and then use the buttons to step through the code.

How to loop and encode as binary?

I am trying to get a program running in the LMC that converts any numerical to binary.
Normally I would just use the divide method, but I cannot do that since the Little Man Computer does not allow for divide or multiplication. The farthest I've gotten in this is only a simple INP. At this stage I do not know how to start loops in it, or how to even begin.
How can I start loops? And how do I stop them? I would somehow need a repeating loop that subtracts a value until it either reaches a 1 or 0. That will achieve my goal as I can just output it then.
For example: I enter 33 and it gives a 100 001 in the output.
I'm a total beginner. I just picked it up today, so keeping it simple would be greatly appreciated.
You write that for 33 the output should be 100 001. This may not work (depending on the LMC simulator), as the second value could be output without the prepadded zeroes, and so it would show 100 1. This can be confusing as it looks a lot like what you would expect for input 9.
I would suggest outputting each binary digit as a separate number: that way you ensure that all digits are visible in the output.
An algorithm to encode an input n like that, could be as follows:
Compare n with 512. If it is not less:
a. Output 1, and subtract 512 from n, otherwise:
b. Output 0
Double the value of n, i.e. add n to itself
Repeat the above 9 more times. Decrement a counter that starts with 10 and repeat as long as it does not set the negative flag.
How to loop
So you "start" a loop in a static way: set the initial value of a counter in a DAT instruction. In the above algorithm we want the counter to start at 10:
COUNTER DAT 10
Then when you need to loop, decrement the counter:
LDA COUNTER
SUB ONE
STA COUNTER
And (like many LMC programs), you need a constant ONE for this:
ONE DAT 1
Finally, to know whether the counter did not go below 0, you can check the "negative" flag. This is a flag that can be set by SUB, when there is a negative overflow (remember that the LMC cannot really store negative values, so you only have the flag as indication). The BRP instruction (branch when positive) will use that flag to decide whether to jump or not:
BRP LOOP
LOOP should be the label for where the code of your loop started.
Implementation
Note that in this practical case, it isn't useful to execute this loop more than 10 times, since the input in LMC cannot be more than 999, which in binary takes 10 digits.
Here is the implementation of the above described algorithm, with also a precaution that the counter will start at its initial value even when the program counter is reset after a first execution:
#input:13
INP
STA NUM
LDA NINE
LOOP STA COUNTER
LDA NUM
COMPARE SUB POW_9
BRP BIT1
BIT0 LDA ZERO
OUT
BRA DOUBLE
BIT1 STA NUM ; Reduce number with 512
LDA ONE
OUT
DOUBLE LDA NUM
ADD NUM
STA NUM
LDA COUNTER
SUB ONE
BRP LOOP
ZERO HLT
POW_9 DAT 512
ONE DAT 1
NINE DAT 9
NUM DAT
COUNTER DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.7/lmc.js"></script>
Alternative
There are several other ways to accomplish this task. For instance, we can hard-code the powers of 2 that we need for 10 binary digits: 1, 2, 4, ..., 512.
Then compare the input value with the greatest of those (with 29 = 512). If it is not less, then output a 1 bit, otherwise output 0. If 1, then subtract that power of 2 from the input number. In both cases, switch to the previous power of 2 (28) and repeat this process. Repeat this until you've done the job for 20.
You could try to implement this without a loop, but you'll have 10 times the same code, with just a different power of 2. This may even be a challenge to fit in the LMC's memory of 100 "mailboxes" (It would work however if you limited the input to like 64, so you would only need 6 binary digits).
To implement this with a loop (less code), you can use a technique of indirect addressing. In LMC there is no instruction for indirect addressing, but with self-modifying code it is possible.
Suppose you have the list of powers implemented as follows:
POW_9 DAT 512
POW_8 DAT 256
; ... etc
POW_0 DAT 1
Then you would do a comparison of the accumulator with POW_9 by:
COMPARE SUB POW_9
The label allows us to store a different instruction there, so that the next time it is executed it actually executes this:
COMPARE SUB POW_8
This is possible with the following manipulation:
LDA COMPARE
ADD ONE
STA COMPARE
This is a bit tricky because code is treated as data, and this modifies the code. Notice how changing SUB POW_9 is actually working as if you reference an element in an array, and increase the index in that array.
You need to have a stop-condition so that you don't make the code reference a power of 2 that is not in your DAT list. For that you could compare the modified code with a fixed piece of code (also a SUB, but which is never executed) that references the lowest power of 2.
Here is an implementation of this idea:
#input:13
INP
STA NUM
LDA FIRST
LOOP STA COMPARE ; self-modifying code!
SUB LAST ; Compare with "SUB ZERO"
BRP ZERO
LDA NUM
COMPARE SUB POW_9 ; Indirect addressing
BRP BIT1
BIT0 LDA ZERO
OUT
BRA NEXT
BIT1 STA NUM ; Reduce number with power
LDA ONE
OUT
NEXT LDA COMPARE ; Change power of 2
ADD ONE
BRA LOOP
FIRST SUB POW_9 ; Never executed
LAST SUB ZERO ; Never executed
POW_9 DAT 512
POW_8 DAT 256
POW_7 DAT 128
POW_6 DAT 64
POW_5 DAT 32
POW_4 DAT 16
POW_3 DAT 8
POW_2 DAT 4
POW_1 DAT 2
ONE DAT 1
ZERO HLT
NUM DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.7/lmc.js"></script>

6502 assembly get data from a block of memory

I've been learning 6502 assembly using the cbm programming studio. I’m reading a book by Jim Butterfield and Richard Mansfield. Both books discuss how one can use a method (I think it was indirect addressing) to get data from a block of memory (like messages) but there isn't an example could someone provide me one please? I don't care what method is used.
It's fairly straight forward. You set ups a pair of zero page addresses to hold the address of the start of the block and then use indirect indexing by Y to access bytes within the block. The instruction LDA ($80),Y reads the bytes at $80 and $81 as a 16 bit address ($81 contains the highest 8 bits) then adds Y on, then reads the byte at the resulting address.
Note that, if you know the address in advance, you do not need to use indirect addressing, you can use absolute indexed.
The following routine demos both address modes. It copies the 10 bytes at a location specified in the X and Y registers (Y is the high byte) to the locations following $0400
stx $80 ; Store the low byte of the source address in ZP
sty $81 ; Store the high byte of the source in ZP
ldy #0 ; zero the index
loop: lda ($80),y ; Get a byte from the source
sta $0400,y ; Store it at the destination
iny ; Increment the index
cpy #10 ; Have we done 10 bytes?
bne loop ; Go round again if not
Note that there is an obvious optimisation in the above, but I'll leave that as an exercise for the reader.
Edit OK here is the obvious optimisation as per i486's comment
stx $80 ; Store the low byte of the source address in ZP
sty $81 ; Store the high byte of the source in ZP
ldy #9 ; initialise to the highest index
loop: lda ($80),y ; Get a byte from the source
sta $0400,y ; Store it at the destination
dey ; Decrement the index
bpl loop ; Go round again if index is still >= 0

LMC Program (Using branch) to store values in different locations

So this is for a school project: I need to design a program (using a branch loop) that stores 1 in memory location 91, 2 in 92 etc... to 5 is stored in 95. I am not very knowledgable of LMC and would like some advice on it. I use peterhigginson.co.uk/LMC for my code (if that helps). The program cannot be as simple as store 1 in 91, it has to be done using a finite loop. I can easily ace this in any other coding console, just not LMC. Any help mucho appreciated.
Thanks!
It's not such an easy question. For code that writes to different addresses, you have to construct the correct STA instructions, using the encoding that STA xx is 3xx.
Here's one way of doing it:
L LDA COUNT
ADD INS
STA X
LDA COUNT
X HLT
LDA COUNT
ADD ONE
STA COUNT
LDA FIVE
SUB COUNT
BRP L
HLT
COUNT DAT 1
ONE DAT 1
FIVE DAT 5
INS STA 90
There's a counter (stored in COUNT) that goes from 1 to 5, and each time through the loop L, it's added to 390 (which is stored at INS) -- this constructs the instructions STA 91, STA 92, .., STA 95 on iterations 1, 2, 3, 4, 5. This instruction is written at X, and then executed with A having the value of COUNT. The rest is just incrementing COUNT, and stopping when it gets larger than 5.
Here's a live link, which you can see this code running on my own LMC emulator.