Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@
},
{
"slug": "assemble",
"name": "assemble",
"name": "Assemble",
"uuid": "17337704-ef28-490b-bbdd-f8e3f51e326b",
"practices": [],
"prerequisites": [],
Expand Down
25 changes: 17 additions & 8 deletions exercises/practice/assemble/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Instructions

In this exercise, you will define the syntax and execution model for a small assembly-like language inspired by the `x86-64` assembly language.
In this exercise, you will define the syntax and execution model for a small language inspired by the `x86-64` assembly language.

The goal is to formalize how code is written, parsed, and executed within a constrained environment.

Expand Down Expand Up @@ -41,16 +41,18 @@ Your language must support the following registers:

Registers start with a default value of `0`, unless they are used to pass arguments to the function.

For example, in the following program, all registers have a value of `0` with the exception of `rdi`, which is initialized with `10`, and `rsi`. which is initialized with `-20`:
For example, in the following program, all registers have a value of `0` with the exception of `rdi`, which is initialized with `10`, and `rsi`, which is initialized with `-20`:

```lean
program(10, -20)
```

The return value of the program is always stored in `rax`.

Note that register names are _case-insensitive_.
~~~~exercism/note
Register names are _case-insensitive_.
This means that `rax`, `RAX` and `rAx` all refer to the same register.
~~~~

## Assembly code

Expand All @@ -70,10 +72,12 @@ Labels have the following syntax:
<label>:
```

They do not alter the values of any register or have any effect to the program other than marking specific places of the code so they can be used by instructions.
They do not alter the value of any register or have any effect on the program other than marking specific places of the code so they can be used by instructions.

Note that labels are _case-sensitive_.
~~~~exercism/note
Labels are _case-sensitive_.
This means that `Start`, `start` and `sTart` are all different labels.
~~~~

### Two-operand instructions

Expand Down Expand Up @@ -101,17 +105,17 @@ This is a list of instructions your program must support:
| `div` | destination := destination / source |
| `xor` | destination := destination ^^^ source |
| `and` | destination := destination &&& source |
| `or` | destination := destination ||| source |
| `or` | destination := destination \|\|\| source |
| `shl` | destination := destination <<< source |
| `shr` | destination := destination >>> source |

Other than those, your program must support the two-operand `cmp` instruction.

This instruction does not modify any register, but instead compares the `destination` and the `source` operands and sets an internal state of the program to one of three states:
This instruction does not modify any register, but instead compares the `destination` and the `source` operands and sets an internal state of the program to one of three options:

- _greater than_, if `destination` > `source`
- _equal_, if `destination` == `source`
- _lesser than_, if `destination` < `source`
- _less than_, if `destination` < `source`

How you keep track internally of this state is up to you.

Expand Down Expand Up @@ -139,3 +143,8 @@ Those are the jumping instructions your program must support:
| `je` | jumps if the internal state is _equal_ |
| `jl` | jumps if the internal state is _less than_ |
| `jg` | jumps if the internal state is _greater than_ |

~~~~exercism/note
Instruction opcodes, be they two-operand or one-operand, are _case-insensitive_.
This means that `add`, `ADD` and `aDd` all refer to the same instruction.
~~~~
63 changes: 40 additions & 23 deletions exercises/practice/assemble/.meta/extra.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@
"description": "Bitwise operations",
"property": "assemble",
"input": {
"args": [49, 16, 1, 255],
"args": [49, 16, 3, 255],
"code": [
"or rax, rcx",
"and rax, rdi",
"xor rax, rsi",
"shr rax, rdx"
"shr rax, 2",
"shl rax, rdx"
]
},
"expected": {
"rax": 16
"rax": 64
}
},
{
Expand Down Expand Up @@ -114,14 +115,30 @@
"input": {
"args": [4010, -3010],
"code": [
"mov RAX, rdi",
"SUB rax, Rsi"
"mov RAX, rDi",
"sub raX, RsI"
]
},
"expected": {
"rax": 7020
}
},
{
"description": "Instructions are case-insensitive",
"property": "assemble",
"input": {
"args": [-500, 10000, -80000],
"code": [
"MOV rax, rdi",
"mUl rax, rdx",
"diV rax, rsi",
"ShR rax, 2"
]
},
"expected": {
"rax": 1000
}
},
{
"description": "Labels are case-sensitive",
"property": "assemble",
Expand All @@ -147,12 +164,12 @@
"input": {
"args": [4, -75590, -10, 890, 435, -235],
"code": [
"mov rax, r8",
"add rax, r9",
"mul rax, rdx",
"sub rax, rcx",
"and rax, rdi",
"or rax, rsi"
"MOV RAX, R8",
"ADD RAX, R9",
"MUL RAX, RDX",
"SUB RAX, RCX",
"AND RAX, RDI",
"OR RAX, RSI"
]
},
"expected": {
Expand All @@ -165,13 +182,13 @@
"input": {
"args": [10],
"code": [
"sum_first_N:",
"cmp rdi, 0",
"je base_case",
"add rax, rdi",
"sub rdi, 1",
"jmp sum_first_N",
"base_case:"
"Sum_first_N:",
"Cmp Rdi, 0",
"Je Base_case",
"Add Rax, Rdi",
"Sub Rdi, 1",
"Jmp Sum_first_N",
"Base_case:"
]
},
"expected": {
Expand All @@ -186,13 +203,13 @@
"code": [
"pop_count:",
"cmp rdi, 0",
"je base_case",
"je EXIT",
"add rax, 1",
"mov rdx, rdi",
"sub rdx, 1",
"and rdi, rdx",
"jmp pop_count",
"base_case:"
"EXIT:"
]
},
"expected": {
Expand All @@ -208,7 +225,7 @@
"steps:",
"cmp rdi, 1",
"jl error",
"je base_case",
"je EXIT",
"loop:",
"add rax, 1",
"mov rdx, rdi",
Expand All @@ -221,11 +238,11 @@
"even:",
"shr rdi, 1",
"cmp rdi, 1",
"je base_case",
"je EXIT",
"jmp loop",
"error:",
"mov rax, -1",
"base_case:"
"EXIT:"
]
},
"expected": {
Expand Down
53 changes: 31 additions & 22 deletions exercises/practice/assemble/AssembleTest.lean
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ def assembleTests : TestSuite :=
or rax, rcx
and rax, rdi
xor rax, rsi
shr rax, rdx
shr rax, 2
shl rax, rdx
)
return assertEqual (16) (program(49, 16, 1, 255)))
return assertEqual (64) (program(49, 16, 3, 255)))
|>.addTest "Skip instructions" (do
let program := assemble!(
mov rax, rdi
Expand Down Expand Up @@ -60,10 +61,18 @@ def assembleTests : TestSuite :=
return assertEqual (-200) (program(400, -600)))
|>.addTest "Registers are case-insensitive" (do
let program := assemble!(
mov RAX, rdi
SUB rax, Rsi
mov RAX, rDi
sub raX, RsI
)
return assertEqual (7020) (program(4010, -3010)))
|>.addTest "Instructions are case-insensitive" (do
let program := assemble!(
MOV rax, rdi
mUl rax, rdx
diV rax, rsi
ShR rax, 2
)
return assertEqual (1000) (program(-500, 10000, -80000)))
|>.addTest "Labels are case-sensitive" (do
let program := assemble!(
mov rax, rdi
Expand All @@ -77,44 +86,44 @@ def assembleTests : TestSuite :=
return assertEqual (401) (program(4010, -3010, 10)))
|>.addTest "All registers are used" (do
let program := assemble!(
mov rax, r8
add rax, r9
mul rax, rdx
sub rax, rcx
and rax, rdi
or rax, rsi
MOV RAX, R8
ADD RAX, R9
MUL RAX, RDX
SUB RAX, RCX
AND RAX, RDI
OR RAX, RSI
)
return assertEqual (-75586) (program(4, -75590, -10, 890, 435, -235)))
|>.addTest "Calculate the sum of the first 10 natural numbers" (do
let program := assemble!(
sum_first_N:
cmp rdi, 0
je base_case
add rax, rdi
sub rdi, 1
jmp sum_first_N
base_case:
Sum_first_N:
Cmp Rdi, 0
Je Base_case
Add Rax, Rdi
Sub Rdi, 1
Jmp Sum_first_N
Base_case:
)
return assertEqual (55) (program(10)))
|>.addTest "Count how many bits are set in 2000000000" (do
let program := assemble!(
pop_count:
cmp rdi, 0
je base_case
je EXIT
add rax, 1
mov rdx, rdi
sub rdx, 1
and rdi, rdx
jmp pop_count
base_case:
EXIT:
)
return assertEqual (13) (program(2000000000)))
|>.addTest "Count steps in the Collatz Conjecture starting with 1000000, -1 indicates error" (do
let program := assemble!(
steps:
cmp rdi, 1
jl error
je base_case
je EXIT
loop:
add rax, 1
mov rdx, rdi
Expand All @@ -127,11 +136,11 @@ def assembleTests : TestSuite :=
even:
shr rdi, 1
cmp rdi, 1
je base_case
je EXIT
jmp loop
error:
mov rax, -1
base_case:
EXIT:
)
return assertEqual (152) (program(1000000)))

Expand Down
Loading