How can you reverse a list in LMC language? - arrays

I have a list in LMC and I would like to try to reverse it like so :
tab dat 111
dat 222
dat 333
dat 444
dat 555
tab dat 555
dat 444
dat 333
dat 222
dat 111
-I tried to find the right element first by using the table size
-Then I substracted 200 from that instruction so that the instructions it turns from 520 -> 320.
-Essentially I changed the instruction from LOAD what is currently in the accumulator to the 20th square in the RAM to STORE what is currently in the accumulator to the 20th sqaure in the RAM
-Then I loaded the content tab at index 0 into the accumulator (111) then saved it in the last index
-I dont know what I have to do afterwards
-I feel like my approche to the problem is somehow wrong
right_el lda size
sub one
sta size
lda load
add size
sub 2hund
sta save
load lda tab
bra save
inc lda load
add one
sto load
bra load
save dat
bra right_el
left_el dat
tab dat 111
dat 222
dat 333
dat 444
dat 555
one dat 1
size dat 5
temp dat
2hund dat 200
I tried to run the program step by step. I managed to turn the table into:
tab dat 111
dat 222
dat 333
dat 444
dat 111
but I dont know what to do afterwards

This is a good start. A few issues:
At save you will write the moved value, but thereby lose the value that was sitting there.
temp is not used, but you would need it for saving the original value before it is overwritten, so that you can then read it again from temp and write that back to the first half of the list.
When branching back to the top, you need size to be reduced by 2, not by 1, because the load address has increased by one, and the distance to the target reduced with 2, not 1. You could solve this by changing the start of your program to:
lda size
add one # to compensate for the minus 2
sta size
right_el lda size
sub two
sta size
... and define two as 2.
You need a stop condition. When the reduced size is zero or less, the program should stop.
The code at inc is never executed. It should be.
You need two more self-modifying instructions. You currently have them for:
Reading from the left side of the list
Writing to the right side of the list
But you also need two for:
Reading from the right side of the list
Writing to the left side of the list
Some other remarks:
Your code mixes two variants of mnemonics: sto and sta. I would stick with one flavour.
Instead of bra save, you could just move that targeted code block right there, so no branching is needed.
I would use twohund as label instead of 2hund. It is common practice to not start identifiers with digits, and some simulators might even have a problem with it.
I would use loop as label instead of right_el as surely the loop will have to cover the complete swap -- from left to right and vice versa.
The following three instructions:
sta size
lda load
add size
Can be written with just two:
sta size
add load
Here is the resulting code -- I suffixed a few of your labels with "left" and "right" so I could add my own and make the distinction:
start LDA size
ADD one # to compensate for the minus 2
STA size
loop LDA size
SUB two
BRP continue # check the loop-stop condition
quit HLT
continue BRZ quit
STA size
ADD loadleft # add size in one go
STA loadright # manage the other dynamic opcode
SUB twohund
STA saveright
SUB size
STA saveleft # and another dynamic code.
loadright DAT
STA temp # first save the value that is targeted
loadleft LDA tab
saveright DAT
LDA temp # copy in the other direction
saveleft DAT
inc LDA loadleft
ADD one
STA loadleft # use consistent mnemnonic
BRA loop
tab DAT 111
DAT 222
DAT 333
DAT 444
DAT 555
one DAT 1
two DAT 2
size DAT 5
temp DAT
twohund DAT 200
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>
You can run the code right here.

Related

How can I plot the last 20 points from a file in gnuplot?

I have a big file in gnuplot and I want to plot them as a gif. My file represents the trajectory of 20 particles. I have tried: do for [a=0:70000:10000] {plot 'posicion.dat' i 0:a u 2:3}. This one sohws the completed trajectory but I only want to show the last point of the trajectory of each particle.
How can I plot the last 20 points from a file in gnuplot?
Thank you!
To my knowledge there is no direct command to plot the last N lines.
If your data doesn't contain double empty lines you could do it with every (check help every).
You could also make a system call (e.g. under Linux using tail) to pass only the last N lines to gnuplot.
However, if you want a platform-independent gnuplot-only solution and if your data consists of lines which are all separated by two blank lines you could do the following:
determine the number of blocks via stats stored in the variable STATS_blocks
plot the last M blocks in a loop (keep in mind: numbering starts from 0)
Check help stats, help for and help index.
However, mind the difference: what is called "blocks" together with every is not the same what is called "blocks" together with stats.
The following example will plot the last 2 lines (blocks).
I hope you can adapt it to your data.
Script:
### plot the last N blocks
reset session
$Data <<EOD
1 10 11
2 20 21
3 30 31
4 40 41
5 50 51
6 60 61
EOD
stats $Data u 0 nooutput
N = STATS_blocks
M = 2 # M last values
set offset 10,10,10,10 # just to get some space to the border
plot for [i=1:M] $Data index N-M+i-1 u 2:3 w lp pt 7 lc i ti sprintf("Particle %d",i)
### end of script
Result:

Programming arrays in LMC

I am working on this challenge:
The program needs to accept a sequence of integers. It ends with number 999. The integers (except 999) are placed in a list.
The integers must be less than or equal to 99. Any inputs greater than 99 are not placed in the list.
If the input would have more than ten numbers, only the first ten are stored.
999 is not part of the output.
I don't know how to limit the list length to ten (10) numbers. Also I don't know how to output the list in reverse order.
This is my code:
start INP
STA temp
SUB big
BRZ doout
LDA temp
SUB hundred
BRP start
sub one
STA N
xx STA ARR
LDA xx
add one
sta xx
BRA start
doout HLT
temp dat 0
big dat 999
hundred dat 100
ARR dat
one dat 1
N dat 10
The xx in your program show that you haven't taken the hint from How can I store an unknown number of inputs in different addresses in LMC (little-man-computer)?
It explains how you can have self-modifying code to walk through an array -- either to store values or to load them.
In your attempt there is no section that deals with outputting.
For the start section of the program I would actually suggest to subtract first the 100 and then 899 (which amounts to 999). That way you can keep the (reducing) input in the accumulator without having to restore it.
Also, due to an ambiguity in the specification of LMC, it is not entirely "safe" to do a BRZ right after a SUB (this is because the content of the accumulator is undefined/unspecified when there is underflow, so in theory it could be 0). You should always first do a BRP before doing a BRZ in the branched code. However, as input cannot be greater than 999, a BRP is enough to detect equality.
For the self modifying part, you can set an end-marker in your array data section, and define the LDA and STA instructions that would read/store a value at the end of the array. Whenever your code has that exact instruction, you know you have reached the end.
Here is how it can work:
LDA store # Initialise dynamic store instruction
STA dyna1
loop INP
dyna1 STA array
SUB toobig
BRP skip
LDA dyna1
ADD one
STA dyna1
SUB staend
BRP print
BRA loop
skip SUB trailer
BRP print # Safer to do BRP than BRZ
BRA loop # Input was less than 999
print LDA dyna1 # Convert dynamic store instruction
SUB store # ... to index
ADD load # ... to load instruction
STA dyna2
loop2 LDA dyna2
SUB one
STA dyna2
SUB load
BRP dyna2
end HLT # all done
dyna2 LDA array
OUT
BRA loop2
store STA array
load LDA array
staend STA after
one DAT 1
toobig DAT 100
trailer DAT 899
array DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
DAT
after DAT
<script src="https://cdn.jsdelivr.net/gh/trincot/lmc#v0.816/lmc.js"></script>
As you can see (while running the script here), the instructions at dyna1 and dyna2 are modified during the execution of the loop they are in.

Branching when negative accumulator

I'm trying to create a loop that will print if a number given is odd or even (Par). How do I branch the loop when the accumulator value is -1?
START INP // int(input(""))
STA n // n =
LOOP LDA n //
BRZ END // while n !=0:
SUB En // n - 1
STA n // n =
INP // int(input(""))
ADD sum //
STA sum //
BRA LOOP //
END LDA sum
OUT
BRP PO
PO LDA sum
BRZ EXIT
LDA sum
SUB TO
STA sum
BRA PO
ODDE LDA O
OTC
LDA D
OTC
LDA D
OTC
LDA E
OTC
O DAT 79
D DAT 68
E DAT 69
HLT
EXIT BRP PAR
HLT
PAR LDA P
OTC
LDA A
OTC
LDA R
OTC
P DAT 80
A DAT 65
R DAT 82
HLT
TO DAT 2
n DAT 0
sum DAT 0
En DAT 1
Par DAT -1
How do I branch the loop when the accumulator value is -1?
The LMC defines mailboxes with values between 0 and 999. They cannot be negative. Even though you can subtract a bigger value from a smaller value, the accumulator's value is then undefined. According to Wikipedia:
SUBTRACT [...] the actions of the accumulator are not defined for subtract instructions that cause negative results - however, a negative flag will be set so that 7xx (BRZ) and 8xx (BRP) can be used properly.
So the only way to reliably detect a negative value is by using BRP: that branch instruction will jump to the provided target address unless a recent subtraction had set the negative flag.
Code review
There are the following issues in your code:
Par DAT -1: as stated above, you cannot store -1 in an LMC mailbox. Mailboxes can only store values between 000 and 999.
Par versus PAR: you have two labels that only differ in capitalisation. LMC implementations are usually not case sensitive, so this would make those two labels the same. Better use entirely different labels.
BRP PO: The label PO points to the very next instruction, so this means that code execution will always continue at that instruction, whether you branch or not. It makes this instruction useless.
O DAT 79: this line appears right after a set of instructions that ends with OTC. If ever that code is executed, it will run into this DAT line. That could lead to undefined behaviour. You don't want this to happen. So make sure that DAT mailboxes are shielded from code execution. Add a HLT before a block of DAT to avoid that they are ever executed as if they were code. You have a similar issue at P DAT 80.
BRZ EXIT: at the EXIT address, you have a BRP, but as you can only arrive there when the accumulator is zero, the negative flag will not be set, and so BRP will branch always. Note that BRP branches when the negative flag is not set.
ODDE: this label is never referenced, and that code block is never executed. You could consider changing the BRA -- that appears just before it -- to a BRP. Then the execution will fall through when the last subtraction led to a negative result (virtually -1 in your case, but the accumulator is undefined).
If you correct all these issues, you'll get to an implementation that will be very close to this working version

How to make a 2D array in LC3

I am trying to make a 2D array in LC3. So far I am thinking of initializing a block of memory using .BLKW and then loading into that another array into each entry. This doesn't seem like it will lead me on the right track though. Any suggestions?
You can definitely do it with .BLKW and also with .STRINGZ, though the latter is admittedly a bit unusual.
The bigger, usual question is around how you decide to "get" and "put" data into that specific area of memory. There are several ways to do that for sure (no one right answer).
Your initial thoughts are cool and valid, but definitely seem to me to be more complex, especially in LC3.
A more direct "row major" or "column major" form of storage - where successive memory locations represent the next entry in a row (row major), or alternatively the next entry in a column (column major)) - is the standard way to do this.
Basically you want to allocate that area of memory, and then write two functions: one to put an item at location (r, c), and get an item from location (r,c).
For this, you will hopefully only need to put an item that is small enough to fit into on 16bit memory location for LC3. That could be a number, or a character. (bigger than 16 bit is doable but adds more complexity for your program for sure).
If you want a fully roughed out sample, you can find that here: http://lc3tutor.org/#array2Dcolordersmp (or just go to lc3tutor.org and look at the 2D array sample).
If you are wanting to learn and try this on your own, you can just read the description there and ignore the sample code (best if you doing for homework and you want to be sure you learn it). Otherwise, the code there should run fine in the browser-based lc3 simulator you find referenced there.
Good luck!
Jeff
PS Here's the pre-amble to that code, if you want to just work from this... hopefully this example helps anchor the col major approach taken in the full code sample:
.ORIG x3000
BR MAIN; jump over storage below to the start of the main section
.STRINGZ "ABCDEFGHIJKLMNOPQRSTUVWZYZ"; slightly tricky - we are storing a sequence of letters in our 2D array for reference.
; The address of the above string STARTS AT x3001,
; which you will see is the same as the 2D_ARRAY label value below.
; This is essentially our 2D_ARRAY, starting at x3001 and taking up 26 locations,
; plus 1 (for the null terminator on the string).
; We will assume the 2D array has 13 rows and 2 columns.
; Two letters per row and 13 letters per column. 26 letters.
; So our NUM_ROW label will be 13 and our NUM_COL label will be 2. (see labels below)
; We will treat this array as a column-major stored array.
; Based on our string above, that means the cells of the first
; column (column #0 by our conventions) are: A-M.
; And the cells of the second column (column #1) are: N-Z.
; If we were storing the array in row-major form, then the cells of the first ROW
; would be A, B, and the second ROW would be C, D. Etc.
; Like this:
;
;R\C | 0 | 1
; ------------
; 0 | A | N
; 1 | B | O
; 2 | C | P
; 3 | D | Q
; 4 | E | R
; 5 | F | S
; 6 | G | T
; 7 | H | U
; 8 | I | V
; 9 | J | W
; 10 | K | X
; 11 | L | Y
; 12 | M | Z
; such that 2D_ARRAY[ROW=8, COL=1] would be the letter "V"

Get average of two consecutive values in a vector depending on logical vector

I am reading data from a file and I am trying to do some manipulation on the vector containing the data basically i want to check if the values come from consecutive lines and if so i want to average each two and put the value in a output vector
part of the data and lines
lines=[153 152 153 154 233 233 234 235 280 279 280 281];
Sail=[ 3 4 3 1.5 3 3 1 2 2.5 5 2.5 2 ];
here is what i am doing
Sail=S(lines);
Y=diff(lines)==1;
for ii=1:length(Y)
if Y(ii)
output(ceil(ii/2))=(Sail(ii)+Sail(ii+1))/2;
end
end
is this correct also is there a way to do that without a for loop
Thanks
My suggestion:
y = find(diff(lines)==1);
output = mean([Sail(y);Sail(y+1)]);
This assumes that when you have, say [233 234 235], you want one value averaging the values from lines [233 234] and one value averaging those from [234 245]. If you wanted to do something more complex when longer sets of consecutive lines exist in your data, then the problem becomes more complex.
Incidentally it's a bad idea to do something like (ceil(ii/2)) - you can't guarantee a unique index for each matching value of ii. If you did want an output the same size as Sail (will have zeros in non-matching areas) then you can do something like this:
output2 = zeros(size(Sail));
output2(y)=output;

Resources