The program breaks down above input value 69, because of the limited memory that is available to an LMC. The highest possible address (mailbox) is 99.
This code uses memory space for the sieve, which needs to be as large as the input you give to it. The memory for the sieve starts at mailbox 31, which is defined at label LDINS
and STINS
in your code: 531 means LDA 31
, where 31 is a mailbox address. Similarly 331 means STA 31
. This defines the maximum size of the sieve: 31 to 99 gives a total of 69 mailboxes that can serve for the sieve.
The instruction STA WRINS
will dynamically change the code at label WRINS
so that it writes a value in the sieve array. The dynamic opcode written is 300 + 31 + [some dynamic offset]. The 300 stands for STA
, and 31 is where the sieve array starts. Now when the offset is 69 or more, this instruction becomes 400 or more, which no longer represents a STA
instruction, but an undefined opcode.
You can run your code in the snippet below, and when you give it 70 as input, you will see it stalls at that instruction saying that the opcode is invalid:
#input: 70
INP
STA INPUT
LDA C
OUT
ADD ONE
OUT
LOOP LDA A \\ first loop
ADD ONE
STA A
SUB INPUT
BRP END
LDA A
ADD LDINS
STA READINS
READINS DAT
BRZ PRIME
BRA LOOP
PRIME LDA A
OUT
STA B
WRITELOOP LDA B \\ second loop
SUB INPUT
BRP LOOP
LDA B \\ at this moment program breakdown when input is more than 69
ADD STINS
STA WRINS
LDA A
WRINS DAT
LDA B
ADD A
STA B
BRA WRITELOOP
END HLT
INPUT DAT 0
LDINS DAT 531 \\ this is working, but i think i might do a better code
STINS DAT 331
A DAT 1
ONE DAT 1
B DAT
C DAT 2
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>
So concluding, this behaviour is not really a bug in the program, but more a memory limitation of the LMC. An LMC implementation of the Sieve of Eratosthenes will always have a limitation somewhere around that size, depending how concise you can make the code -- leaving room for the array.
Remarks about the code
The above answers your question, but there are some comments to make about your code.
It seems you modified an existing program, adding some preliminary instructions to output 2 and 3 quickly, but you didn't adapt the starting address of the sieve memory in accordance. In your current program the address 31 points to the line (mailbox) with BRA WRITELOOP
, which cannot be your purpose. The first time the dynamic code at READINS
is executed, that location has instruction LDA INPUT
as INPUT
, corresponding to address 33.
This is also the reason why the program does not output 5 as a prime. The program should really point to free memory for its sieve, beyond the data you already have in use. To save space you could let the sieve address start at label ONE
, since the first two entries of the sieve are never accessed.
I think it is also better to use labels and mnemonics instead of hardcoded opcodes and addresses, so avoiding things like 331 and 531, which are quite cryptic, and (as demonstrated) are error prone when the program is modified.
Also, you should explicitly list the DAT
entries that your program will use.
Here is a corrected version, which obviously still has a limit on the input: 67 is the maximum value you can input without breaking the code.
#input: 67
INP
STA INPUT
LOOP LDA A \\ first loop
ADD ONE
STA A
SUB INPUT
BRP END
LDA A
ADD LDINS
STA READINS
READINS DAT
BRZ PRIME
BRA LOOP
PRIME LDA A
OUT
STA B
WRITELOOP LDA B \\ second loop
SUB INPUT
BRP LOOP
LDA B
ADD STINS
STA WRINS
LDA A
WRINS DAT
LDA B
ADD A
STA B
BRA WRITELOOP
END HLT
INPUT DAT
LDINS LDA ONE
STINS STA ONE
A DAT 1
ONE DAT 1 // also the start of the sieve
B DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc@v0.76/lmc.js"></script>