Skip to content

Commit f6bbb12

Browse files
authored
Merge pull request #11 from markdryan/markdryan/v8
Specasm v8
2 parents 99590f3 + 5859ca0 commit f6bbb12

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2005
-460
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ COMMON =\
88
line_common.c
99

1010
SRCS =\
11+
clipboard.c \
1112
editor.c \
1213
editor_tests.c \
1314
editor_test_content.c \

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,4 @@ make -j
174174
make tests
175175
```
176176

177-
This will create a folder called tests in the unit folder. Inside this folder are 3 files that need to be copied to the same directory on your spectrum. The unitnext file is a dotn file which needs to be copied to the /dot directory. Then make sure you are in the folder containing the test_bad and test_op files and type .unitnext.
177+
This will create a folder called tests in the unit folder. Inside this folder are 3 files that need to be copied to the same directory on your Next. Enter the folder and then type ../unitnext from the command line to launch the tests.

build/48/specasm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SPECASM = \
1717
line_parse.o \
1818
line_parse_common.o \
1919
error.o \
20+
specasm_mainloop.o \
2021
state_base.o \
2122
state_dump.o \
2223
state_parse.o \

build/next/specasm/Make.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ peer_file_next.o: peer_file_next.c error.h peer_file.h
5656
util_print_next.o: util_print_next.c util_print_zx.h
5757
samake.o: samake.c peer.h error.h peer_zx.h line.h \
5858
salink.h peer_file.h state_base.h strings.h
59+
clipboard_banked.o: clipboard.c clipboard.h line.h error.h
5960

6061
%.o: %.c
6162
zcc $(CFLAGS) -o $@ -c $<

build/next/specasm/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ line_dump_banked.o: line_dump.c
1616
ld_parse_banked.o: ld_parse.c
1717
$(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_45_H --constsegBANK_45_H --datasegBANK_45_H -c $<
1818

19+
clipboard_banked.o: clipboard.c
20+
$(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_46_H --constsegBANK_46_H --datasegBANK_46_H -c $<
21+
1922
expression_banked.o: expression.c
2023
$(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_43_H --constsegBANK_43_H --datasegBANK_43_H -c $<
2124

@@ -30,12 +33,14 @@ include Make.include
3033
SPECASM = \
3134
specasm_next.o \
3235
specasm_trampolines.o \
36+
clipboard_banked.o \
3337
line_common.o \
3438
ld_parse_banked.o \
3539
line_dump_banked.o \
3640
line_dump_common.o \
3741
line_parse_banked.o \
3842
line_parse_common.o \
43+
specasm_mainloop.o \
3944
error.o \
4045
state_base.o \
4146
state_dump.o \

build/next/unit/Make.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ peer_file_next.o: peer_file_next.c error.h peer_file.h
4141
util_print_next.o: util_print_next.c util_print_zx.h
4242
samake.o: samake.c peer.h error.h peer_zx.h line.h \
4343
salink.h peer_file.h state_base.h strings.h
44+
clipboard_banked.o: clipboard.c clipboard.h line.h error.h
4445

4546
unittests_zx.o: ../src/unittests_zx.c ../src/error.h ../src/line.h \
4647
../src/state.h ../src/state_base.h ../src/strings.h ../src/test_content.h ../src/test_content_zx.h \

build/next/unit/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ line_dump_banked.o: line_dump.c
1616
ld_parse_banked.o: ld_parse.c
1717
$(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_45_H --constsegBANK_45_H --datasegBANK_45_H -c $<
1818

19+
clipboard_banked.o: clipboard.c
20+
$(CC) $(CFLAGS) -DSPECASM_NEXT_BANKED -o $@ --codesegBANK_46_H --constsegBANK_46_H --datasegBANK_46_H -c $<
21+
1922
include Make.include
2023

2124
UNITNEXT = \
2225
error.o \
2326
state_base.o \
2427
specasm_trampolines.o \
2528
line_common.o \
29+
clipboard_banked.o \
2630
ld_parse_banked.o \
2731
line_dump_banked.o \
2832
line_dump_common.o \

docs/specasm.md

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Specasm is a Z80 assembler designed to run on the 48k and 128k ZX Spectrums with
66

77
The editor can be launched from the command line using the .specasm command. Specasm is an integrated editor/assembler.
88

9+
> [!TIP]
10+
> The ZX Spectrum Next version of Specasm allows the name of a single .x file to be passed on the command line. This file will be automatically loaded into the editor on startup, e.g., .specasm game.x.
11+
912
The editor allows one single source, .x, file to be edited at any one time. Each such file can contain a maximum of 512 lines. Each line can be
1013

1114
- An empty line
@@ -60,11 +63,19 @@ On entering command mode, a '>' prompt appears at the bottom of the screen. Fro
6063
| g *line number* | Moves the cursor to the specified line number|
6164
| f *string* | Searches for the first instance of *string* starting from the current line. There's no wrap around. |
6265

66+
The Next version of Specasm uses one of the Next's 8Kb memory banks to implement a clipboard. This provides a more traditional copy, cut and paste mechanism than the copy and move commands described above, and allows code to be copied from one file to another. Clipboard support is provided via three new Next specific commands.
67+
68+
| Command | Description |
69+
|---------|-------------|
70+
| x | Replaces the contents of the clipboard with the selected code and deletes the code from the current file |
71+
| cc | Replaces the contents of the clipboard with the selected code |
72+
| v | Pastes the contents of the clipboard into the selected code at the cursor position |
73+
6374
#### Selecting Mode
6475

65-
The *sel* command switches the editor into selection mode. In selection mode the user can press the up and down keys to select a block of code. They can also press the 'a' key to select the entire file. Only whole lines can be selected. To cancel the selection and return to editor mode, press SPACE. To delete the selected lines and return to editor mode, press DELETE. To confirm the selection and return to editor mode, press ENTER. Once the selection has been confirmed an '*' will appear in the status row at the bottom of the screen to the right of 'INS' or 'OVR'. This indicates that some lines are currently selected. These lines can be manipulated using the 'd', 'm', 'c' and 'b' commands described above. For example, to count the number of machine code bytes in the selected line, type SYMSHIFT+w followed by 'b' and ENTER. The editor is capable of computing the exact size in bytes of the machine code associated with the instructions and data in the selected region as it has already assembled these instructions and knows exactly how much space they will consume.
76+
The *sel* command switches the editor into selection mode. In selection mode the user can press the up and down keys to select a block of code. They can also press the 'a' key to select the entire file. Only whole lines can be selected. To cancel the selection and return to editor mode, press SPACE. To delete the selected lines and return to editor mode, press DELETE. On the Next, the selected lines may be cut to the clipboard by typing 'x'. To confirm the selection and return to editor mode, press ENTER. Once the selection has been confirmed an '*' will appear in the status row at the bottom of the screen to the right of 'INS' or 'OVR'. This indicates that some lines are currently selected. These lines can be manipulated using the 'd', 'm', 'c','b', 'x' and 'cc' commands described above. For example, to count the number of machine code bytes in the selected line, type SYMSHIFT+w followed by 'b' and ENTER. The editor is capable of computing the exact size in bytes of the machine code associated with the instructions and data in the selected region as it has already assembled these instructions and knows exactly how much space they will consume.
6677

67-
All of the four commands that manipulate selections, cancel the selection once they have finished executing. So if you select a block of text, and then issue the 'b' command to count the number of bytes it consumes, you'll need to reselect the text once more to copy it. In addition, the current selection is cancelled if you make any changes to the contents of the editor, e.g., edit an existing line or insert a new one.
78+
All of the six commands that manipulate selections, cancel the selection once they have finished executing. So if you select a block of text, and then issue the 'b' command to count the number of bytes it consumes, you'll need to reselect the text once more to copy it. In addition, the current selection is cancelled if you make any changes to the contents of the editor, e.g., edit an existing line or insert a new one.
6879

6980
#### The Status Row
7081

@@ -578,15 +589,23 @@ The reverse process can be performed using the .saexport command. Note the use
578589

579590
## Program structure
580591

581-
A Specasm program is comprised of one or more .x files that occupy the same directory. When you build a Specasm program with the .salink command it looks for all the .x files in the folder in which it is run, and links them all together, concatenating them all into one single file and resolving any addresses, e.g., jump targets. One of the .x files in the current folder must contain a label called **Main**, .e.g, it must have the following statement somewhere within one of the files
592+
A Specasm program is comprised of one or more .x files. When you build a Specasm program with the .salink command it looks for all the .x files in the folder in which it is run, and links them all together, concatenating them all into one single file and resolving any addresses, e.g., jump targets.
593+
594+
> [!TIP]
595+
> Specasm programs can actually span multiple directories. See the +, - and ! directives below.
596+
597+
598+
One of the .x files must contain a label called **Main**, .e.g, it must have the following statement somewhere within one of the files
582599

583600
```
584601
.Main
585602
```
586603

587604
The name of the resulting binary will be derived from the name of the .x file that contains the **Main** label. So if a project places the Main label in a file called **game.x**, the name of the resulting binary created by salink will be **game**.
588605

589-
The salink command will place the code from the .x file that declares the Main label first in the newly created binary. The order in which the rest of the code is written to the binary is arbitrary and the user has no control over this. They can however, ask the linker to generate a map file to figure out where all the symbols ended up. This is done by specifying the **map** directive on one line of one .x file, e.g.,
606+
The salink command will place the code from the .x file that declares the Main label first in the newly created binary. In Specasm versions v7 and eearlier, the order in which the rest of the code is written to the binary is arbitrary and the user has no control over this. In Specasm v8 and above, the order in which the code from the remaining .x files is written to the target binary is defined by the alphabetical order (ascending) of their names. Suppose our program consisted of 3 files, main.x, 02_code.x, 01_data.x, the data/code in main.x would be written first, followed by the contents of 01_data.x, and finally, by the contents of 02_code.x.
607+
608+
You can ask the linker to generate a map file to figure out where all the symbols ended up. This is done by specifying the **map** directive on one line of one .x file, e.g.,
590609

591610
```
592611
map
@@ -621,9 +640,12 @@ org 23760
621640

622641
will cause the linked program to be assembled at 23760.
623642

624-
The linker doesn't currently create a loader program or a tap file. This can however be done using the samake command.
643+
The linker only creates pure binary files. It isn't capable of creating a loader program or a tap file. This is the task of the samake program, introduced in Specasm v7. See below for more details.
625644

626-
### Libraries
645+
Specasm projects are not limited to the .x files in the main directory. The '-' and '+' directives can be used to include .x files in other directories, allowing a Specasm project to span multiple directories. See below for more details.
646+
647+
648+
### Multi-directory Projects and Libraries
627649

628650
Specasm supports two directives that allow the user to include .x files from other directories in the final executable.
629651

@@ -634,15 +656,70 @@ Specasm supports two directives that allow the user to include .x files from oth
634656

635657
These are both linker directives rather than assembler directives. The target of these directives are not included directly into the current source file. Instead they are added to the final binary when it is linked. The '-' directive is intended to be used to create custom libraries or to split your program into multiple folders. The '+' directive is intended to be used to include .x files from a future Specasm standard library. The trailing '.x' extension in <filename> is optional.
636658

637-
Here are some examples of their use
659+
If the path passed to a '-' or a '+' directive is itself a directory, Specasm (v8 and above) will add all the .x files it can find in that directory, and only that directory, to the final binary.
660+
661+
Here are some examples of '-' and '+'
638662

639663
```
640664
; include /specasm/gr/rows.x
641665
+gr/rows
642666
643667
; include ./lib/math.x
644668
-lib/math.x
669+
670+
; include all .x files in mylib
671+
; Specasm v8 and above.
672+
-mylib
673+
```
674+
675+
The '-' and '+' directives will not add .x files located in any sub-directory of an included directory. For example,
676+
677+
```
678+
-mylib
679+
```
680+
681+
will add mylib/peqnp.x but it will not add mylib/tests/binpack.x. If mylib/tests/binpack.x is needed in the project it will need to be included separately, either with a
682+
645683
```
684+
-mylib/tests/binpack.x
685+
```
686+
687+
or
688+
689+
```
690+
-mylib/tests
691+
```
692+
693+
if all the .x files in mylib/tests are to be part of the project.
694+
695+
### Binary files
696+
697+
Specasm supports one directive that allows a file to be inserted directly into the final binary at the position at which the directive appears. This is useful when including binary data directly into your final executable rather than shipping it as a separate file and reading it in at runtime, or encoding it using db or dw statements, which isn't really practical when there's a lot of data.
698+
699+
| Directive | Description |
700+
|--------------|--------------------------------------------------------------------------------------------|
701+
| ! <filename> | Filename is either an absolute or a relative path (relative to the current .x file) |
702+
703+
For example,
704+
705+
```
706+
; load pointer to sprite data into hl
707+
708+
ld hl, sprites
709+
710+
; Load size of sprite file into bc
711+
712+
ld bc, =sprite_end-sprites
713+
714+
; do something with the sprites
715+
716+
ret
717+
.sprites
718+
! spritefile
719+
.sprite_end
720+
```
721+
722+
The data in spritefile will be inserted between the .sprites and .sprite_end label in the final binary by the linker. The register bc will contain the size of that file.
646723

647724
## Creating Loaders with SAMAKE
648725

src/clipboard.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright contributors to Specasm
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifdef SPECASM_TARGET_NEXT_OPCODES
18+
19+
#include <stdlib.h>
20+
#include <string.h>
21+
22+
#include "clipboard.h"
23+
#include "line.h"
24+
25+
#define SPECASM_CLIP_MAX_SIZE (15 * 512)
26+
27+
static uint8_t clip_buffer[SPECASM_CLIP_MAX_SIZE];
28+
29+
static uint16_t clip_end_ptr;
30+
static uint16_t clip_lines;
31+
32+
#ifdef SPECASM_NEXT_BANKED
33+
void specasm_clip_reset_banked(void)
34+
#else
35+
void specasm_clip_reset(void)
36+
#endif
37+
{
38+
clip_end_ptr = 0;
39+
clip_lines = 0;
40+
}
41+
42+
#ifdef SPECASM_NEXT_BANKED
43+
void specasm_clip_add_line_banked_e(const char *line)
44+
#else
45+
void specasm_clip_add_line_e(const char *line)
46+
#endif
47+
{
48+
uint8_t len;
49+
const char *end_ptr;
50+
51+
/*
52+
* Skip leading and trailing white space. We don't need to store this.
53+
*/
54+
55+
end_ptr = &line[SPECASM_LINE_MAX_LEN - 1];
56+
while ((end_ptr >= line) && (*end_ptr == ' '))
57+
end_ptr--;
58+
end_ptr++;
59+
60+
if (line == end_ptr) {
61+
clip_buffer[clip_end_ptr++] = 0;
62+
} else {
63+
while (*line == ' ')
64+
line++;
65+
66+
len = end_ptr - line;
67+
if (len + clip_end_ptr >= SPECASM_CLIP_MAX_SIZE) {
68+
err_type = SPECASM_ERROR_TOO_MANY_LINES;
69+
return;
70+
}
71+
72+
clip_buffer[clip_end_ptr++] = len;
73+
memcpy(&clip_buffer[clip_end_ptr], line, len);
74+
clip_end_ptr += len;
75+
}
76+
clip_lines++;
77+
}
78+
79+
#ifdef SPECASM_NEXT_BANKED
80+
uint16_t specasm_clip_get_line_banked(uint16_t ptr, char *buffer)
81+
#else
82+
uint16_t specasm_clip_get_line(uint16_t ptr, char *buffer)
83+
#endif
84+
{
85+
uint8_t len;
86+
uint8_t spaces;
87+
88+
if (ptr >= clip_end_ptr)
89+
return 0;
90+
91+
len = clip_buffer[ptr++];
92+
if (len > 0) {
93+
memcpy(buffer, &clip_buffer[ptr], len);
94+
ptr += len;
95+
}
96+
97+
spaces = SPECASM_LINE_MAX_LEN - len;
98+
if (spaces > 0)
99+
memset(&buffer[len], ' ', spaces);
100+
buffer[len + spaces] = 0;
101+
102+
return ptr;
103+
}
104+
105+
#ifdef SPECASM_NEXT_BANKED
106+
uint16_t specasm_clip_get_line_count_banked(void)
107+
#else
108+
uint16_t specasm_clip_get_line_count(void)
109+
#endif
110+
{
111+
return clip_lines;
112+
}
113+
114+
#endif

src/clipboard.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright contributors to Specasm
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef CLIPBOARD_H
18+
#define CLIPBOARD_H
19+
20+
#include <stdint.h>
21+
22+
void specasm_clip_reset(void);
23+
void specasm_clip_add_line_e(const char *line);
24+
uint16_t specasm_clip_get_line(uint16_t ptr, char *buffer);
25+
uint16_t specasm_clip_get_line_count(void);
26+
27+
#endif

0 commit comments

Comments
 (0)