mirror of
https://github.com/elliotnunn/NetBoot.git
synced 2024-12-11 05:49:19 +00:00
Initial commit, including vasm
This commit is contained in:
commit
9d4022b833
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.app
|
||||
edit.rom
|
||||
.DS_Store
|
39
NetBoot.py
Executable file
39
NetBoot.py
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Multicast client
|
||||
# Adapted from: http://chaos.weblogs.us/archives/164
|
||||
|
||||
import socket
|
||||
|
||||
ANY = "0.0.0.0"
|
||||
MCAST_ADDR = "239.192.76.84"
|
||||
MCAST_PORT = 1954
|
||||
|
||||
# Create a UDP socket
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # IPPROTO_UDP could just be 0
|
||||
|
||||
# Allow multiple sockets to use the same PORT number
|
||||
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
|
||||
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT,1)
|
||||
|
||||
# Bind to the port that we know will receive multicast data
|
||||
sock.bind((ANY,MCAST_PORT))
|
||||
|
||||
# Tell the kernel that we want to add ourselves to a multicast group
|
||||
# The address for the multicast group is the third param
|
||||
status = sock.setsockopt(socket.IPPROTO_IP,
|
||||
socket.IP_ADD_MEMBERSHIP,
|
||||
socket.inet_aton(MCAST_ADDR) + socket.inet_aton(ANY))
|
||||
|
||||
# setblocking(0) is equiv to settimeout(0.0) which means we poll the socket.
|
||||
# But this will raise an error if recv() or send() can't immediately find or send data.
|
||||
# sock.setblocking(0)
|
||||
|
||||
while 1:
|
||||
try:
|
||||
data, addr = sock.recvfrom(1024)
|
||||
except socket.error as e:
|
||||
pass
|
||||
else:
|
||||
print("From: ", addr)
|
||||
print("Data: ", data)
|
28
README.md
Normal file
28
README.md
Normal file
@ -0,0 +1,28 @@
|
||||
netBOOT for Old World Macs
|
||||
==========================
|
||||
Read this thread: https://mac68k.info/forums/thread.jspa?threadID=76&tstart=0
|
||||
|
||||
Now I'm trying to get it working! The dream is to boot all my Classics over PhoneNet.
|
||||
|
||||
|
||||
Progress so far
|
||||
---------------
|
||||
The best build options for Mini vMac are: `-br 37 -m Classic -lt -speed z -as 0 -chr 0`. Note that this requires the new (as of mid-2020) version of Mini vMac, with Rob Mitchelmore's clever LocalTalk-over-UDP tunneling.
|
||||
|
||||
The xo-rom-enable-netboot.py script can edit xo.rom (Macintosh Classic) to force-enable the netBOOT driver (essentially by editing PRAM). (It requires you to build vasm with a quick `make CPU=m68k SYNTAX=std`.) This enables quick iteration:
|
||||
|
||||
cp xo.rom edit.rom && ./xo-rom-enable-netboot.py edit.rom&& Mini\ vMac\ Classic.app/Co*/Ma*/* edit.rom
|
||||
|
||||
Running NetBoot.py simultaneously now shows the netBOOT driver sending DDP packets, and getting no response.
|
||||
|
||||
|
||||
Trivia
|
||||
------
|
||||
The Classic is the only non-IIci non-SuperMario ROM with .netBOOT and .ATBOOT drivers. They are part of the overpatch imposed on the SE ROM, and were essentially backported (see the SuperMario forXO.a file). I use the Classic ROM here because it can be emulated in Mini vMac, but the newer netBOOT-equipped ROMs should work.
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
To all the intrepid individuals on the mac68k forum thread. Join Freenode #mac68k to meet them.
|
||||
|
||||
Credit to bbraun http://synack.net/~bbraun/ for the contents of the "bbraun-pram" dir.
|
1
bbraun-pram/NBPRAM.c
Normal file
1
bbraun-pram/NBPRAM.c
Normal file
@ -0,0 +1 @@
|
||||
/*
* Initialize netboot pram
* - Rob Braun <bbraun@synack.net>
* 2012
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <Traps.h>
void get_netboot_pram(struct netboot *nb);
void set_netboot_pram(struct netboot *nb);
#pragma parameter __D0 ReadXPRam(__D0, __D1, __A0)
short ReadXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _ReadXPRam};
#pragma parameter __D0 WriteXPRam(__D0, __D1, __A0)
short WriteXPRam(short size, short offset, char *where) = {0x4840, 0x3001, _WriteXPRam};
struct netboot {
char machineID; /* this is used as part of the boot protocol */
char protocol;
char errors;
char flags; /* Used to enable netbooting, and allow guest netbooting */
char intervalCount; /* high nibble is the retry count, low nibble is the interval between retries */
char timeout;
unsigned long signature[4];
char userName[31];
char password[8];
short serverID; /* the value here will be translated to ascii encoded hex and used as the server name to boot from. */
char padding[7];
};
void get_netboot_pram(struct netboot *nb) {
char *i = (char*)nb;
ReadXPRam(4, 4, i);
i += 4;
ReadXPRam(3, 0xAB, i);
i += 3;
ReadXPRam(1, 0xBC, i);
i++;
ReadXPRam(0x20, 0x20, i);
i += 0x20;
ReadXPRam(0x20, 0x8B, i);
return;
}
void set_netboot_pram(struct netboot *nb) {
char *i = (char*)nb;
WriteXPRam(4, 4, i);
i += 4;
WriteXPRam(3, 0xAB, i);
i += 3;
WriteXPRam(1, 0xBC, i);
i++;
WriteXPRam(0x20, 0x20, i);
i += 0x20;
WriteXPRam(0x20, 0x8B, i);
return;
}
void main(void)
{
struct netboot nb;
char *i;
int n;
memset(&nb, 0, sizeof(nb));
get_netboot_pram(&nb);
for(i = (char*)&nb, n = 0; n < sizeof(nb); n++) {
printf("0x%x ", i[n]);
}
printf("\n");
#if 1
memset(&nb, 0, sizeof(nb));
nb.machineID = 1;
nb.protocol = 1;
nb.errors = 0;
nb.flags = 0xC0;
nb.intervalCount = 0x24; /* low nibble is interval, high nibble is count for lookups */
nb.timeout = 127;
nb.signature[0] = 'PWD ';
//nb.userName[0] = '\0';
strcpy(nb.userName, "bbraun");
nb.password[0] = '\0';
nb.serverID = 0xEBAB;
set_netboot_pram(&nb);
#endif
}
|
7
bbraun-pram/pram.c
Normal file
7
bbraun-pram/pram.c
Normal file
@ -0,0 +1,7 @@
|
||||
scal void read_extended_PRAM(char * where, const short size) =
|
||||
{ 0x4280, 0x301F, 0x4840, 0x205F, 0xA051 };
|
||||
|
||||
pascal void write_extended_PRAM
|
||||
(const char * where, const short offset, const short size) =
|
||||
{0x201F, 0x205F, 0xA052};
|
||||
|
0
bbraun-pram/pramtest
Normal file
0
bbraun-pram/pramtest
Normal file
BIN
bbraun-pram/pramtest.SYM
Normal file
BIN
bbraun-pram/pramtest.SYM
Normal file
Binary file not shown.
BIN
bbraun-pram/pramtest.proj
Normal file
BIN
bbraun-pram/pramtest.proj
Normal file
Binary file not shown.
18
vasm-1/Makefile
Normal file
18
vasm-1/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
# Unix
|
||||
# Define CC, when no compiler with the name "cc" exists.
|
||||
|
||||
TARGET =
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CCOUT = -o
|
||||
COPTS = -c -O2 -DUNIX $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.68k
Normal file
18
vasm-1/Makefile.68k
Normal file
@ -0,0 +1,18 @@
|
||||
# AmigaOS/68k
|
||||
|
||||
TARGET = _os3
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +aos68k
|
||||
CCOUT = -o
|
||||
COPTS = -c -c99 -cpu=68020 -DAMIGA $(OUTFMTS) -O1
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lmieee
|
||||
|
||||
RM = delete force quiet
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.Cygwin
Normal file
18
vasm-1/Makefile.Cygwin
Normal file
@ -0,0 +1,18 @@
|
||||
# Windows compiled with gcc
|
||||
|
||||
TARGET = _win32
|
||||
TARGETEXTENSION = .exe
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = gcc
|
||||
CCOUT = -o
|
||||
COPTS = -c -O2 -DUNIX $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.Haiku
Normal file
18
vasm-1/Makefile.Haiku
Normal file
@ -0,0 +1,18 @@
|
||||
# Unix
|
||||
|
||||
TARGET =
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = gcc
|
||||
CCOUT = -o
|
||||
COPTS = -c -O2 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS =
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.MOS
Normal file
18
vasm-1/Makefile.MOS
Normal file
@ -0,0 +1,18 @@
|
||||
# MorphOS
|
||||
|
||||
TARGET = _mos
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +morphos
|
||||
CCOUT = -o
|
||||
COPTS = -c -DAMIGA -O1 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = delete force quiet
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.MiNT
Normal file
18
vasm-1/Makefile.MiNT
Normal file
@ -0,0 +1,18 @@
|
||||
# Atari TOS/MiNT
|
||||
|
||||
TARGET = _MiNT
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +mint
|
||||
CCOUT = -o
|
||||
COPTS = -c -c99 -cpu=68020 -O1 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.OS4
Normal file
18
vasm-1/Makefile.OS4
Normal file
@ -0,0 +1,18 @@
|
||||
# AmigaOS 4.x/PPC
|
||||
|
||||
TARGET = _os4
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +aosppc
|
||||
CCOUT = -o
|
||||
COPTS = -c -DAMIGA -D__USE_INLINE__ -O1 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = delete force quiet
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.PUp
Normal file
18
vasm-1/Makefile.PUp
Normal file
@ -0,0 +1,18 @@
|
||||
# PowerUp
|
||||
|
||||
TARGET = _pup
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +powerup
|
||||
CCOUT = -o
|
||||
COPTS = -c -c99 -DAMIGA -O1 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm -lamiga
|
||||
|
||||
RM = delete force quiet
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.TOS
Normal file
18
vasm-1/Makefile.TOS
Normal file
@ -0,0 +1,18 @@
|
||||
# Atari TOS
|
||||
|
||||
TARGET = _TOS
|
||||
TARGETEXTENSION = .ttp
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +tos
|
||||
CCOUT = -o
|
||||
COPTS = -c -c99 -O1 -DATARI $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules
|
18
vasm-1/Makefile.WOS
Normal file
18
vasm-1/Makefile.WOS
Normal file
@ -0,0 +1,18 @@
|
||||
# WarpOS
|
||||
|
||||
TARGET = _wos
|
||||
TARGETEXTENSION =
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
CC = vc +warpos
|
||||
CCOUT = -o
|
||||
COPTS = -c -c99 -DAMIGA -O1 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm -lamiga
|
||||
|
||||
RM = delete force quiet
|
||||
|
||||
include make.rules
|
30
vasm-1/Makefile.Win32
Normal file
30
vasm-1/Makefile.Win32
Normal file
@ -0,0 +1,30 @@
|
||||
# Windows
|
||||
# Tested with Visual Studio 2017: works fine under the Developer Command Prompt for VS2017
|
||||
# Tested with Visual Studio 2005 Express Edition: works fine
|
||||
# Tested with Visual C++ Toolkit 2003: works fine, but needs an external make tool (nmake is not included)
|
||||
|
||||
TARGET = _win32
|
||||
TARGETEXTENSION = .exe
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
# If Visual Studio is unable to find <windows.h> when compiling vlink, try enabling the two
|
||||
# lines below, and point them to where you have installed the Win32 Platform SDK.
|
||||
|
||||
#WIN32_PLATFORMSDK_INCLUDE = "/IC:\Code\Win32 Platform SDK\Include"
|
||||
#WIN32_PLATFORMSDK_LIB = "/LIBPATH:C:\Code\Win32 Platform SDK\Lib"
|
||||
|
||||
CC = cl
|
||||
CCOUT = /Fo
|
||||
COPTS = $(OUTFMTS) /nologo /O2 /MT /c
|
||||
COPTS = $(COPTS) /wd4996 # Disable warning regarding deprecated functions
|
||||
# ("use strcpy_s instead of strcpy" etc)
|
||||
COPTS = $(COPTS) $(WIN32_PLATFORMSDK_INCLUDE)
|
||||
|
||||
LD = link
|
||||
LDOUT = /OUT:
|
||||
LDFLAGS = /NOLOGO $(WIN32_PLATFORMSDK_LIB)
|
||||
|
||||
RM = rem
|
||||
|
||||
include make.rules
|
22
vasm-1/Makefile.Win32FromLinux
Normal file
22
vasm-1/Makefile.Win32FromLinux
Normal file
@ -0,0 +1,22 @@
|
||||
# Windows compiled on a Linux machine with mingw
|
||||
|
||||
TARGET = _win32
|
||||
TARGETEXTENSION = .exe
|
||||
OUTFMTS = -DOUTAOUT -DOUTBIN -DOUTELF -DOUTHUNK -DOUTSREC -DOUTTOS -DOUTVOBJ \
|
||||
-DOUTXFIL
|
||||
|
||||
|
||||
#CC = /usr/bin/i586-mingw32msvc-gcc
|
||||
CC = /usr/bin/i686-w64-mingw32-gcc
|
||||
CCOUT = -o
|
||||
COPTS = -c -O2 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
|
||||
|
||||
include make.rules
|
672
vasm-1/atom.c
Normal file
672
vasm-1/atom.c
Normal file
@ -0,0 +1,672 @@
|
||||
/* atom.c - atomic objects from source */
|
||||
/* (c) in 2010-2020 by Volker Barthelmann and Frank Wille */
|
||||
|
||||
#include "vasm.h"
|
||||
|
||||
|
||||
/* searches mnemonic list and tries to parse (via the cpu module)
|
||||
the operands according to the mnemonic requirements; returns an
|
||||
instruction or 0 */
|
||||
instruction *new_inst(char *inst,int len,int op_cnt,char **op,int *op_len)
|
||||
{
|
||||
#if MAX_OPERANDS!=0
|
||||
operand ops[MAX_OPERANDS];
|
||||
int j,k,mnemo_opcnt,omitted,skipped;
|
||||
#endif
|
||||
int i,inst_found=0;
|
||||
hashdata data;
|
||||
instruction *new;
|
||||
|
||||
new = mymalloc(sizeof(*new));
|
||||
#if HAVE_INSTRUCTION_EXTENSION
|
||||
init_instruction_ext(&new->ext);
|
||||
#endif
|
||||
#if MAX_OPERANDS!=0 && NEED_CLEARED_OPERANDS!=0
|
||||
/* reset operands to allow the cpu-backend to parse them only once */
|
||||
memset(ops,0,sizeof(ops));
|
||||
#endif
|
||||
|
||||
if (find_namelen_nc(mnemohash,inst,len,&data)) {
|
||||
i = data.idx;
|
||||
|
||||
/* try all mnemonics with the same name until operands match */
|
||||
do {
|
||||
inst_found = 1;
|
||||
if (!MNEMONIC_VALID(i)) {
|
||||
i++;
|
||||
continue; /* try next */
|
||||
}
|
||||
|
||||
#if MAX_OPERANDS!=0
|
||||
|
||||
#if ALLOW_EMPTY_OPS
|
||||
mnemo_opcnt = op_cnt<MAX_OPERANDS ? op_cnt : MAX_OPERANDS;
|
||||
#else
|
||||
for (j=0; j<MAX_OPERANDS; j++)
|
||||
if (mnemonics[i].operand_type[j] == 0)
|
||||
break;
|
||||
mnemo_opcnt = j; /* number of expected operands for this mnemonic */
|
||||
#endif
|
||||
inst_found = 2;
|
||||
save_symbols(); /* make sure we can restore symbols to this point */
|
||||
|
||||
for (j=k=omitted=skipped=0; j<mnemo_opcnt; j++) {
|
||||
|
||||
if (op_cnt+omitted < mnemo_opcnt &&
|
||||
OPERAND_OPTIONAL(&ops[j],mnemonics[i].operand_type[j])) {
|
||||
omitted++;
|
||||
}
|
||||
else {
|
||||
int rc;
|
||||
|
||||
if (k >= op_cnt) /* missing mandatory operands */
|
||||
break;
|
||||
|
||||
rc = parse_operand(op[k],op_len[k],&ops[j],
|
||||
mnemonics[i].operand_type[j]);
|
||||
|
||||
if (rc == PO_CORRUPT) {
|
||||
myfree(new);
|
||||
restore_symbols();
|
||||
return 0;
|
||||
}
|
||||
if (rc == PO_NOMATCH)
|
||||
break;
|
||||
|
||||
/* MATCH, move to next parsed operand */
|
||||
k++;
|
||||
if (rc == PO_SKIP) { /* but skip next operand type from table */
|
||||
j++;
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if IGNORE_FIRST_EXTRA_OP
|
||||
if (mnemo_opcnt > 0)
|
||||
#endif
|
||||
if (j<mnemo_opcnt || k<op_cnt) {
|
||||
/* No match. Try next mnemonic. */
|
||||
i++;
|
||||
restore_symbols();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Matched! Copy operands. */
|
||||
mnemo_opcnt -= skipped;
|
||||
for (j=0; j<mnemo_opcnt; j++) {
|
||||
new->op[j] = mymalloc(sizeof(operand));
|
||||
*new->op[j] = ops[j];
|
||||
}
|
||||
for(; j<MAX_OPERANDS; j++)
|
||||
new->op[j] = 0;
|
||||
|
||||
#endif /* MAX_OPERANDS!=0 */
|
||||
|
||||
new->code = i;
|
||||
return new;
|
||||
}
|
||||
while (i<mnemonic_cnt && !strnicmp(mnemonics[i].name,inst,len)
|
||||
&& mnemonics[i].name[len]==0);
|
||||
}
|
||||
|
||||
switch (inst_found) {
|
||||
case 1:
|
||||
general_error(8); /* instruction not supported by cpu */
|
||||
break;
|
||||
case 2:
|
||||
general_error(0); /* illegal operand types */
|
||||
break;
|
||||
default:
|
||||
general_error(1,cnvstr(inst,len)); /* completely unknown mnemonic */
|
||||
break;
|
||||
}
|
||||
myfree(new);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
dblock *new_dblock(void)
|
||||
{
|
||||
dblock *new = mymalloc(sizeof(*new));
|
||||
|
||||
new->size = 0;
|
||||
new->data = 0;
|
||||
new->relocs = 0;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
sblock *new_sblock(expr *space,size_t size,expr *fill)
|
||||
{
|
||||
sblock *sb = mymalloc(sizeof(sblock));
|
||||
|
||||
sb->space = 0;
|
||||
sb->space_exp = space;
|
||||
sb->size = size;
|
||||
if (!(sb->fill_exp = fill))
|
||||
memset(sb->fill,0,MAXPADBYTES);
|
||||
sb->relocs = 0;
|
||||
sb->maxalignbytes = 0;
|
||||
sb->flags = 0;
|
||||
return sb;
|
||||
}
|
||||
|
||||
|
||||
static size_t space_size(sblock *sb,section *sec,taddr pc)
|
||||
{
|
||||
utaddr space=0;
|
||||
|
||||
if (eval_expr(sb->space_exp,&space,sec,pc) || !final_pass)
|
||||
sb->space = space;
|
||||
else
|
||||
general_error(30); /* expression must be constant */
|
||||
|
||||
if (final_pass && sb->fill_exp) {
|
||||
if (sb->size <= sizeof(taddr)) {
|
||||
/* space is filled with an expression which may also need relocations */
|
||||
symbol *base=NULL;
|
||||
taddr fill;
|
||||
utaddr i;
|
||||
|
||||
if (!eval_expr(sb->fill_exp,&fill,sec,pc)) {
|
||||
if (find_base(sb->fill_exp,&base,sec,pc)==BASE_ILLEGAL)
|
||||
general_error(38); /* illegal relocation */
|
||||
}
|
||||
copy_cpu_taddr(sb->fill,fill,sb->size);
|
||||
if (base && !sb->relocs) {
|
||||
/* generate relocations */
|
||||
for (i=0; i<space; i++)
|
||||
add_extnreloc(&sb->relocs,base,fill,REL_ABS,
|
||||
0,sb->size<<3,sb->size*i);
|
||||
}
|
||||
}
|
||||
else
|
||||
general_error(30); /* expression must be constant */
|
||||
}
|
||||
|
||||
return sb->size * space;
|
||||
}
|
||||
|
||||
|
||||
static size_t roffs_size(reloffs *roffs,section *sec,taddr pc)
|
||||
{
|
||||
taddr offs;
|
||||
|
||||
eval_expr(roffs->offset,&offs,sec,pc);
|
||||
offs = sec->org + offs - pc;
|
||||
return offs>0 ? offs : 0;
|
||||
}
|
||||
|
||||
|
||||
/* adds an atom to the specified section; if sec==0, the current
|
||||
section is used */
|
||||
void add_atom(section *sec,atom *a)
|
||||
{
|
||||
if (!sec) {
|
||||
sec = default_section();
|
||||
if (!sec) {
|
||||
general_error(3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
a->changes = 0;
|
||||
a->src = cur_src;
|
||||
a->line = cur_src!=NULL ? cur_src->line : 0;
|
||||
|
||||
if (sec->last) {
|
||||
atom *pa = sec->last;
|
||||
|
||||
pa->next = a;
|
||||
/* make sure that a label on the same line gets the same alignment */
|
||||
if (pa->type==LABEL && pa->line==a->line &&
|
||||
(a->type==INSTRUCTION || a->type==DATADEF || a->type==SPACE))
|
||||
pa->align = a->align;
|
||||
}
|
||||
else
|
||||
sec->first = a;
|
||||
a->next = 0;
|
||||
sec->last = a;
|
||||
|
||||
sec->pc = pcalign(a,sec->pc);
|
||||
a->lastsize = atom_size(a,sec,sec->pc);
|
||||
sec->pc += a->lastsize;
|
||||
if (a->align > sec->align)
|
||||
sec->align = a->align;
|
||||
|
||||
if (listena) {
|
||||
a->list = last_listing;
|
||||
if (last_listing) {
|
||||
if (!last_listing->atom)
|
||||
last_listing->atom = a;
|
||||
}
|
||||
}
|
||||
else
|
||||
a->list = 0;
|
||||
}
|
||||
|
||||
|
||||
size_t atom_size(atom *p,section *sec,taddr pc)
|
||||
{
|
||||
switch(p->type) {
|
||||
case VASMDEBUG:
|
||||
case LABEL:
|
||||
case LINE:
|
||||
case OPTS:
|
||||
case PRINTTEXT:
|
||||
case PRINTEXPR:
|
||||
case RORG:
|
||||
case RORGEND:
|
||||
case ASSERT:
|
||||
case NLIST: /* it has a size, but not in the current section */
|
||||
return 0;
|
||||
case DATA:
|
||||
return p->content.db->size;
|
||||
case INSTRUCTION:
|
||||
return p->content.inst->code>=0?
|
||||
instruction_size(p->content.inst,sec,pc):0;
|
||||
case SPACE:
|
||||
return space_size(p->content.sb,sec,pc);
|
||||
case DATADEF:
|
||||
return (p->content.defb->bitsize+7)/8;
|
||||
case ROFFS:
|
||||
return roffs_size(p->content.roffs,sec,pc);
|
||||
default:
|
||||
ierror(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_instruction(FILE *f,instruction *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("inst %d(%s) ",p->code,p->code>=0?mnemonics[p->code].name:"deleted");
|
||||
#if MAX_OPERANDS!=0
|
||||
for (i=0; i<MAX_OPERANDS; i++)
|
||||
printf("%p ",(void *)p->op[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void print_atom(FILE *f,atom *p)
|
||||
{
|
||||
size_t i;
|
||||
rlist *rl;
|
||||
|
||||
switch (p->type) {
|
||||
case VASMDEBUG:
|
||||
fprintf(f,"vasm debug directive");
|
||||
break;
|
||||
case LABEL:
|
||||
fprintf(f,"symbol: ");
|
||||
print_symbol(f,p->content.label);
|
||||
break;
|
||||
case DATA:
|
||||
fprintf(f,"data(%lu): ",(unsigned long)p->content.db->size);
|
||||
for (i=0;i<p->content.db->size;i++)
|
||||
fprintf(f,"%02x ",p->content.db->data[i]);
|
||||
for (rl=p->content.db->relocs; rl; rl=rl->next)
|
||||
print_reloc(f,rl->type,rl->reloc);
|
||||
break;
|
||||
case INSTRUCTION:
|
||||
print_instruction(f,p->content.inst);
|
||||
break;
|
||||
case SPACE:
|
||||
fprintf(f,"space(%lu,fill=",
|
||||
(unsigned long)(p->content.sb->space*p->content.sb->size));
|
||||
for (i=0; i<p->content.sb->size; i++)
|
||||
fprintf(f,"%02x%c",(unsigned char)p->content.sb->fill[i],
|
||||
(i==p->content.sb->size-1)?')':' ');
|
||||
for (rl=p->content.sb->relocs; rl; rl=rl->next)
|
||||
print_reloc(f,rl->type,rl->reloc);
|
||||
break;
|
||||
case DATADEF:
|
||||
fprintf(f,"datadef(%lu bits)",(unsigned long)p->content.defb->bitsize);
|
||||
break;
|
||||
case LINE:
|
||||
fprintf(f,"line: %d of %s",p->content.srcline,getdebugname());
|
||||
break;
|
||||
#if HAVE_CPU_OPTS
|
||||
case OPTS:
|
||||
print_cpu_opts(f,p->content.opts);
|
||||
break;
|
||||
#endif
|
||||
case PRINTTEXT:
|
||||
fprintf(f,"text: \"%s\"",p->content.ptext);
|
||||
break;
|
||||
case PRINTEXPR:
|
||||
fprintf(f,"expr: ");
|
||||
print_expr(f,p->content.pexpr->print_exp);
|
||||
break;
|
||||
case ROFFS:
|
||||
fprintf(f,"roffs: offset ");
|
||||
print_expr(f,p->content.roffs->offset);
|
||||
fprintf(f,",fill=");
|
||||
if (p->content.roffs->fillval)
|
||||
print_expr(f,p->content.roffs->fillval);
|
||||
else
|
||||
fprintf(f,"none");
|
||||
break;
|
||||
case RORG:
|
||||
fprintf(f,"rorg: relocate to 0x%llx",ULLTADDR(*p->content.rorg));
|
||||
break;
|
||||
case RORGEND:
|
||||
fprintf(f,"rorg end");
|
||||
break;
|
||||
case ASSERT:
|
||||
fprintf(f,"assert: %s (message: %s)\n",p->content.assert->expstr,
|
||||
p->content.assert->msgstr?p->content.assert->msgstr:emptystr);
|
||||
break;
|
||||
case NLIST:
|
||||
fprintf(f,"nlist: %s (type %d, other %d, desc %d) with value ",
|
||||
p->content.nlist->name!=NULL ? p->content.nlist->name : "<NULL>",
|
||||
p->content.nlist->type,p->content.nlist->other,
|
||||
p->content.nlist->desc);
|
||||
if (p->content.nlist->value != NULL)
|
||||
print_expr(f,p->content.nlist->value);
|
||||
else
|
||||
fprintf(f,"NULL");
|
||||
break;
|
||||
default:
|
||||
ierror(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* prints and formats an expression from a PRINTEXPR atom */
|
||||
void atom_printexpr(printexpr *pexp,section *sec,taddr pc)
|
||||
{
|
||||
taddr t;
|
||||
long long v;
|
||||
int i;
|
||||
|
||||
eval_expr(pexp->print_exp,&t,sec,pc);
|
||||
if (pexp->type==PEXP_SDEC && (t&(1LL<<(pexp->size-1)))!=0) {
|
||||
/* signed decimal */
|
||||
v = -1;
|
||||
v &= ~(long long)MAKEMASK(pexp->size);
|
||||
}
|
||||
else
|
||||
v = 0;
|
||||
v |= t & MAKEMASK(pexp->size);
|
||||
|
||||
switch (pexp->type) {
|
||||
case PEXP_HEX:
|
||||
printf("%llX",(unsigned long long)v);
|
||||
break;
|
||||
case PEXP_SDEC:
|
||||
printf("%lld",v);
|
||||
break;
|
||||
case PEXP_UDEC:
|
||||
printf("%llu",(unsigned long long)v);
|
||||
break;
|
||||
case PEXP_BIN:
|
||||
for (i=pexp->size-1; i>=0; i--)
|
||||
putchar((v & (1LL<<i)) ? '1' : '0');
|
||||
break;
|
||||
case PEXP_ASC:
|
||||
for (i=((pexp->size+7)>>3)-1; i>=0; i--) {
|
||||
unsigned char c = (v>>(i*8))&0xff;
|
||||
putchar(isprint(c) ? c : '.');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ierror(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
atom *clone_atom(atom *a)
|
||||
{
|
||||
atom *new = mymalloc(sizeof(atom));
|
||||
void *p;
|
||||
|
||||
memcpy(new,a,sizeof(atom));
|
||||
|
||||
switch (a->type) {
|
||||
/* INSTRUCTION and DATADEF have to be cloned as well, because they will
|
||||
be deallocated and transformed into DATA during assemble() */
|
||||
case INSTRUCTION:
|
||||
p = mymalloc(sizeof(instruction));
|
||||
memcpy(p,a->content.inst,sizeof(instruction));
|
||||
new->content.inst = p;
|
||||
break;
|
||||
case DATADEF:
|
||||
p = mymalloc(sizeof(defblock));
|
||||
memcpy(p,a->content.defb,sizeof(defblock));
|
||||
new->content.defb = p;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
new->next = 0;
|
||||
new->src = NULL;
|
||||
new->line = 0;
|
||||
new->list = NULL;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *add_data_atom(section *sec,size_t sz,taddr alignment,taddr c)
|
||||
{
|
||||
dblock *db = new_dblock();
|
||||
atom *a;
|
||||
|
||||
db->size = sz;
|
||||
db->data = mymalloc(sz);
|
||||
if (sz > 1)
|
||||
setval(BIGENDIAN,db->data,sz,c);
|
||||
else
|
||||
*(db->data) = c;
|
||||
|
||||
a = new_data_atom(db,alignment);
|
||||
add_atom(sec,a);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void add_leb128_atom(section *sec,taddr c)
|
||||
{
|
||||
taddr b;
|
||||
|
||||
do {
|
||||
b = c & 0x7f;
|
||||
if ((c >>= 7) != 0)
|
||||
b |= 0x80;
|
||||
add_data_atom(sec,1,1,b);
|
||||
} while (c != 0);
|
||||
}
|
||||
|
||||
|
||||
void add_sleb128_atom(section *sec,taddr c)
|
||||
{
|
||||
int done = 0;
|
||||
taddr b;
|
||||
|
||||
do {
|
||||
b = c & 0x7f;
|
||||
c >>= 7; /* assumes arithmetic shifts! */
|
||||
if ((c==0 && !(b&0x40)) || (c==-1 && (b&0x40)))
|
||||
done = 1;
|
||||
else
|
||||
b |= 0x80;
|
||||
add_data_atom(sec,1,1,b);
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
|
||||
atom *add_bytes_atom(section *sec,void *p,size_t sz)
|
||||
{
|
||||
dblock *db = new_dblock();
|
||||
atom *a;
|
||||
|
||||
db->size = sz;
|
||||
db->data = mymalloc(sz);
|
||||
memcpy(db->data,p,sz);
|
||||
a = new_data_atom(db,1);
|
||||
add_atom(sec,a);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
atom *new_atom(int type,taddr align)
|
||||
{
|
||||
atom *new = mymalloc(sizeof(*new));
|
||||
|
||||
new->next = NULL;
|
||||
new->type = type;
|
||||
new->align = align;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_inst_atom(instruction *p)
|
||||
{
|
||||
atom *new = new_atom(INSTRUCTION,inst_alignment);
|
||||
|
||||
new->content.inst = p;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_data_atom(dblock *p,taddr align)
|
||||
{
|
||||
atom *new = new_atom(DATA,align);
|
||||
|
||||
new->content.db = p;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_label_atom(symbol *p)
|
||||
{
|
||||
atom *new = new_atom(LABEL,1);
|
||||
|
||||
new->content.label = p;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_space_atom(expr *space,size_t size,expr *fill)
|
||||
{
|
||||
atom *new = new_atom(SPACE,1);
|
||||
int i;
|
||||
|
||||
if (size<1)
|
||||
ierror(0); /* usually an error in syntax-module */
|
||||
new->content.sb = new_sblock(space,size,fill);
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_datadef_atom(size_t bitsize,operand *op)
|
||||
{
|
||||
atom *new = new_atom(DATADEF,DATA_ALIGN(bitsize));
|
||||
|
||||
new->content.defb = mymalloc(sizeof(*new->content.defb));
|
||||
new->content.defb->bitsize = bitsize;
|
||||
new->content.defb->op = op;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_srcline_atom(int line)
|
||||
{
|
||||
atom *new = new_atom(LINE,1);
|
||||
|
||||
new->content.srcline = line;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_opts_atom(void *o)
|
||||
{
|
||||
atom *new = new_atom(OPTS,1);
|
||||
|
||||
new->content.opts = o;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_text_atom(char *txt)
|
||||
{
|
||||
atom *new = new_atom(PRINTTEXT,1);
|
||||
|
||||
new->content.ptext = txt ? txt : "\n";
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_expr_atom(expr *exp,int type,int size)
|
||||
{
|
||||
atom *new = new_atom(PRINTEXPR,1);
|
||||
|
||||
new->content.pexpr = mymalloc(sizeof(*new->content.pexpr));
|
||||
if (exp==NULL || type<PEXP_HEX || type>PEXP_ASC || size<1
|
||||
|| size>sizeof(long long)*8)
|
||||
ierror(0);
|
||||
new->content.pexpr->print_exp = exp;
|
||||
new->content.pexpr->type = type;
|
||||
new->content.pexpr->size = size;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_roffs_atom(expr *offs,expr *fill)
|
||||
{
|
||||
atom *new = new_atom(ROFFS,1);
|
||||
|
||||
new->content.roffs = mymalloc(sizeof(*new->content.roffs));
|
||||
new->content.roffs->offset = offs;
|
||||
new->content.roffs->fillval = fill;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_rorg_atom(taddr raddr)
|
||||
{
|
||||
atom *new = new_atom(RORG,1);
|
||||
taddr *newrorg = mymalloc(sizeof(taddr));
|
||||
|
||||
*newrorg = raddr;
|
||||
new->content.rorg = newrorg;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_rorgend_atom(void)
|
||||
{
|
||||
return new_atom(RORGEND,1);
|
||||
}
|
||||
|
||||
|
||||
atom *new_assert_atom(expr *aexp,char *exp,char *msg)
|
||||
{
|
||||
atom *new = new_atom(ASSERT,1);
|
||||
|
||||
new->content.assert = mymalloc(sizeof(*new->content.assert));
|
||||
new->content.assert->assert_exp = aexp;
|
||||
new->content.assert->expstr = exp;
|
||||
new->content.assert->msgstr = msg;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
atom *new_nlist_atom(char *name,int type,int other,int desc,expr *value)
|
||||
{
|
||||
atom *new = new_atom(NLIST,1);
|
||||
|
||||
new->content.nlist = mymalloc(sizeof(*new->content.nlist));
|
||||
new->content.nlist->name = name;
|
||||
new->content.nlist->type = type;
|
||||
new->content.nlist->other = other;
|
||||
new->content.nlist->desc = desc;
|
||||
new->content.nlist->value = value;
|
||||
return new;
|
||||
}
|
152
vasm-1/atom.h
Normal file
152
vasm-1/atom.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* atom.h - atomic objects from source */
|
||||
/* (c) in 2010-2020 by Volker Barthelmann and Frank Wille */
|
||||
|
||||
#ifndef ATOM_H
|
||||
#define ATOM_H
|
||||
|
||||
/* types of atoms */
|
||||
#define VASMDEBUG 0
|
||||
#define LABEL 1
|
||||
#define DATA 2
|
||||
#define INSTRUCTION 3
|
||||
#define SPACE 4
|
||||
#define DATADEF 5
|
||||
#define LINE 6
|
||||
#define OPTS 7
|
||||
#define PRINTTEXT 8
|
||||
#define PRINTEXPR 9
|
||||
#define ROFFS 10
|
||||
#define RORG 11
|
||||
#define RORGEND 12
|
||||
#define ASSERT 13
|
||||
#define NLIST 14
|
||||
|
||||
/* a machine instruction */
|
||||
typedef struct instruction {
|
||||
int code;
|
||||
#if MAX_QUALIFIERS!=0
|
||||
char *qualifiers[MAX_QUALIFIERS];
|
||||
#endif
|
||||
#if MAX_OPERANDS!=0
|
||||
operand *op[MAX_OPERANDS];
|
||||
#endif
|
||||
#if HAVE_INSTRUCTION_EXTENSION
|
||||
instruction_ext ext;
|
||||
#endif
|
||||
} instruction;
|
||||
|
||||
typedef struct defblock {
|
||||
size_t bitsize;
|
||||
operand *op;
|
||||
} defblock;
|
||||
|
||||
struct dblock {
|
||||
size_t size;
|
||||
unsigned char *data;
|
||||
rlist *relocs;
|
||||
};
|
||||
|
||||
struct sblock {
|
||||
size_t space;
|
||||
expr *space_exp; /* copied to space, when evaluated as constant */
|
||||
size_t size;
|
||||
uint8_t fill[MAXPADBYTES];
|
||||
expr *fill_exp; /* copied to fill, when evaluated - may be NULL */
|
||||
rlist *relocs;
|
||||
taddr maxalignbytes;
|
||||
uint32_t flags;
|
||||
};
|
||||
#define SPC_DATABSS 1 /* make sure no to allocate space in a data section */
|
||||
|
||||
typedef struct reloffs {
|
||||
expr *offset;
|
||||
expr *fillval;
|
||||
} reloffs;
|
||||
|
||||
typedef struct printexpr {
|
||||
expr *print_exp;
|
||||
short type; /* hex, signed, unsigned */
|
||||
short size; /* precision in bits */
|
||||
} printexpr;
|
||||
#define PEXP_HEX 0
|
||||
#define PEXP_SDEC 1
|
||||
#define PEXP_UDEC 2
|
||||
#define PEXP_BIN 3
|
||||
#define PEXP_ASC 4
|
||||
|
||||
typedef struct assertion {
|
||||
expr *assert_exp;
|
||||
char *expstr;
|
||||
char *msgstr;
|
||||
} assertion;
|
||||
|
||||
typedef struct aoutnlist {
|
||||
char *name;
|
||||
int type;
|
||||
int other;
|
||||
int desc;
|
||||
expr *value;
|
||||
} aoutnlist;
|
||||
|
||||
/* an atomic element of data */
|
||||
typedef struct atom {
|
||||
struct atom *next;
|
||||
int type;
|
||||
taddr align;
|
||||
size_t lastsize;
|
||||
unsigned changes;
|
||||
source *src;
|
||||
int line;
|
||||
listing *list;
|
||||
union {
|
||||
instruction *inst;
|
||||
dblock *db;
|
||||
symbol *label;
|
||||
sblock *sb;
|
||||
defblock *defb;
|
||||
void *opts;
|
||||
int srcline;
|
||||
char *ptext;
|
||||
printexpr *pexpr;
|
||||
reloffs *roffs;
|
||||
taddr *rorg;
|
||||
assertion *assert;
|
||||
aoutnlist *nlist;
|
||||
} content;
|
||||
} atom;
|
||||
|
||||
#define MAXSIZECHANGES 5 /* warning, when atom changed size so many times */
|
||||
|
||||
instruction *new_inst(char *inst,int len,int op_cnt,char **op,int *op_len);
|
||||
dblock *new_dblock();
|
||||
sblock *new_sblock(expr *,size_t,expr *);
|
||||
|
||||
atom *new_atom(int,taddr);
|
||||
void add_atom(section *,atom *);
|
||||
size_t atom_size(atom *,section *,taddr);
|
||||
void print_atom(FILE *,atom *);
|
||||
void atom_printexpr(printexpr *,section *,taddr);
|
||||
atom *clone_atom(atom *);
|
||||
|
||||
atom *add_data_atom(section *,size_t,taddr,taddr);
|
||||
void add_leb128_atom(section *,taddr);
|
||||
void add_sleb128_atom(section *,taddr);
|
||||
atom *add_bytes_atom(section *,void *,size_t);
|
||||
#define add_string_atom(s,p) add_bytes_atom(s,p,strlen(p)+1)
|
||||
|
||||
atom *new_inst_atom(instruction *);
|
||||
atom *new_data_atom(dblock *,taddr);
|
||||
atom *new_label_atom(symbol *);
|
||||
atom *new_space_atom(expr *,size_t,expr *);
|
||||
atom *new_datadef_atom(size_t,operand *);
|
||||
atom *new_srcline_atom(int);
|
||||
atom *new_opts_atom(void *);
|
||||
atom *new_text_atom(char *);
|
||||
atom *new_expr_atom(expr *,int,int);
|
||||
atom *new_roffs_atom(expr *,expr *);
|
||||
atom *new_rorg_atom(taddr);
|
||||
atom *new_rorgend_atom(void);
|
||||
atom *new_assert_atom(expr *,char *,char *);
|
||||
atom *new_nlist_atom(char *,int,int,int,expr *);
|
||||
|
||||
#endif
|
85
vasm-1/cond.c
Normal file
85
vasm-1/cond.c
Normal file
@ -0,0 +1,85 @@
|
||||
/* cond.c - conditional assembly support routines */
|
||||
/* (c) in 2015 by Frank Wille */
|
||||
|
||||
#include "vasm.h"
|
||||
|
||||
int clev; /* conditional level */
|
||||
|
||||
static char cond[MAXCONDLEV+1];
|
||||
static char *condsrc[MAXCONDLEV+1];
|
||||
static int condline[MAXCONDLEV+1];
|
||||
static int ifnesting;
|
||||
|
||||
|
||||
/* initialize conditional assembly */
|
||||
void cond_init(void)
|
||||
{
|
||||
cond[0] = 1;
|
||||
clev = ifnesting = 0;
|
||||
}
|
||||
|
||||
|
||||
/* return true, when current level allows assembling */
|
||||
int cond_state(void)
|
||||
{
|
||||
return cond[clev];
|
||||
}
|
||||
|
||||
|
||||
/* ensures that all conditional block are closed at the end of the source */
|
||||
void cond_check(void)
|
||||
{
|
||||
if (clev > 0)
|
||||
general_error(66,condsrc[clev],condline[clev]); /* "endc/endif missing */
|
||||
}
|
||||
|
||||
|
||||
/* establish a new level of conditional assembly */
|
||||
void cond_if(char flag)
|
||||
{
|
||||
if (++clev >= MAXCONDLEV)
|
||||
general_error(65,clev); /* nesting depth exceeded */
|
||||
|
||||
cond[clev] = flag;
|
||||
condsrc[clev] = cur_src->name;
|
||||
condline[clev] = cur_src->line;
|
||||
}
|
||||
|
||||
|
||||
/* handle skipped if statement */
|
||||
void cond_skipif(void)
|
||||
{
|
||||
ifnesting++;
|
||||
}
|
||||
|
||||
|
||||
/* handle else statement after skipped if-branch */
|
||||
void cond_else(void)
|
||||
{
|
||||
if (ifnesting == 0)
|
||||
cond[clev] = 1;
|
||||
}
|
||||
|
||||
|
||||
/* handle else statement after assembled if-branch */
|
||||
void cond_skipelse(void)
|
||||
{
|
||||
if (clev > 0)
|
||||
cond[clev] = 0;
|
||||
else
|
||||
general_error(63); /* else without if */
|
||||
}
|
||||
|
||||
|
||||
/* handle end-if statement */
|
||||
void cond_endif(void)
|
||||
{
|
||||
if (ifnesting == 0) {
|
||||
if (clev > 0)
|
||||
clev--;
|
||||
else
|
||||
general_error(64); /* unexpected endif without if */
|
||||
}
|
||||
else /* the whole conditional block was ignored */
|
||||
ifnesting--;
|
||||
}
|
25
vasm-1/cond.h
Normal file
25
vasm-1/cond.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* cond.h - conditional assembly support routines */
|
||||
/* (c) in 2015 by Frank Wille */
|
||||
|
||||
#ifndef COND_H
|
||||
#define COND_H
|
||||
|
||||
/* defines */
|
||||
#ifndef MAXCONDLEV
|
||||
#define MAXCONDLEV 63
|
||||
#endif
|
||||
|
||||
/* global variables */
|
||||
extern int clev;
|
||||
|
||||
/* functions */
|
||||
void cond_init(void);
|
||||
int cond_state(void);
|
||||
void cond_check(void);
|
||||
void cond_if(char);
|
||||
void cond_skipif(void);
|
||||
void cond_else(void);
|
||||
void cond_skipelse(void);
|
||||
void cond_endif(void);
|
||||
|
||||
#endif /* COND_H */
|
588
vasm-1/cpus/6502/cpu.c
Normal file
588
vasm-1/cpus/6502/cpu.c
Normal file
@ -0,0 +1,588 @@
|
||||
/*
|
||||
** cpu.c 650x/65C02/6510/6280 cpu-description file
|
||||
** (c) in 2002,2006,2008-2012,2014-2020 by Frank Wille
|
||||
*/
|
||||
|
||||
#include "vasm.h"
|
||||
|
||||
mnemonic mnemonics[] = {
|
||||
#include "opcodes.h"
|
||||
};
|
||||
|
||||
int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]);
|
||||
|
||||
char *cpu_copyright="vasm 6502 cpu backend 0.8c (c) 2002,2006,2008-2012,2014-2020 Frank Wille";
|
||||
char *cpuname = "6502";
|
||||
int bitsperbyte = 8;
|
||||
int bytespertaddr = 2;
|
||||
|
||||
static uint16_t cpu_type = M6502;
|
||||
static int branchopt = 0;
|
||||
static int modifier; /* set by find_base() */
|
||||
static utaddr dpage = 0; /* default zero/direct page - set with SETDP */
|
||||
static int bbcade; /* GMGM - set for BBC ADE compatibility */
|
||||
|
||||
|
||||
int ext_unary_type(char *s)
|
||||
{
|
||||
if (bbcade) /* GMGM - BBC ADE assembler swaps meaning of < and > */
|
||||
return *s=='<' ? HIBYTE : LOBYTE;
|
||||
return *s=='<' ? LOBYTE : HIBYTE;
|
||||
}
|
||||
|
||||
|
||||
int ext_unary_eval(int type,taddr val,taddr *result,int cnst)
|
||||
{
|
||||
switch (type) {
|
||||
case LOBYTE:
|
||||
*result = cnst ? (val & 0xff) : val;
|
||||
return 1;
|
||||
case HIBYTE:
|
||||
*result = cnst ? ((val >> 8) & 0xff) : val;
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0; /* unknown type */
|
||||
}
|
||||
|
||||
|
||||
int ext_find_base(symbol **base,expr *p,section *sec,taddr pc)
|
||||
{
|
||||
/* addr/256 equals >addr, addr%256 and addr&255 equal <addr */
|
||||
if (p->type==DIV || p->type==MOD) {
|
||||
if (p->right->type==NUM && p->right->c.val==256)
|
||||
p->type = p->type == DIV ? HIBYTE : LOBYTE;
|
||||
}
|
||||
else if (p->type==BAND && p->right->type==NUM && p->right->c.val==255)
|
||||
p->type = LOBYTE;
|
||||
|
||||
if (p->type==LOBYTE || p->type==HIBYTE) {
|
||||
modifier = p->type;
|
||||
return find_base(p->left,base,sec,pc);
|
||||
}
|
||||
return BASE_ILLEGAL;
|
||||
}
|
||||
|
||||
|
||||
int parse_operand(char *p,int len,operand *op,int required)
|
||||
{
|
||||
char *start = p;
|
||||
int indir = 0;
|
||||
|
||||
p = skip(p);
|
||||
if (len>0 && required!=DATAOP && check_indir(p,start+len)) {
|
||||
indir = 1;
|
||||
p = skip(p+1);
|
||||
}
|
||||
|
||||
switch (required) {
|
||||
case IMMED:
|
||||
if (*p++ != '#')
|
||||
return PO_NOMATCH;
|
||||
p = skip(p);
|
||||
break;
|
||||
case INDIR:
|
||||
case INDIRX:
|
||||
case INDX:
|
||||
case INDY:
|
||||
case DPINDIR:
|
||||
if (!indir)
|
||||
return PO_NOMATCH;
|
||||
break;
|
||||
case WBIT:
|
||||
if (*p == '#') /* # is optional */
|
||||
p = skip(p+1);
|
||||
default:
|
||||
if (indir)
|
||||
return PO_NOMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
op->dp = dpage;
|
||||
if (required < ACCU)
|
||||
op->value = parse_expr(&p);
|
||||
else
|
||||
op->value = NULL;
|
||||
|
||||
switch (required) {
|
||||
case INDX:
|
||||
case INDIRX:
|
||||
if (*p++ == ',') {
|
||||
p = skip(p);
|
||||
if (toupper((unsigned char)*p++) != 'X')
|
||||
return PO_NOMATCH;
|
||||
}
|
||||
else
|
||||
return PO_NOMATCH;
|
||||
break;
|
||||
case ACCU:
|
||||
if (len != 0) {
|
||||
if (len!=1 || toupper((unsigned char)*p++) != 'A')
|
||||
return PO_NOMATCH;
|
||||
}
|
||||
break;
|
||||
case DUMX:
|
||||
if (toupper((unsigned char)*p++) != 'X')
|
||||
return PO_NOMATCH;
|
||||
break;
|
||||
case DUMY:
|
||||
if (toupper((unsigned char)*p++) != 'Y')
|
||||
return PO_NOMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
if (required==INDIR || required==INDX || required==INDY
|
||||
|| required==DPINDIR || required==INDIRX) {
|
||||
p = skip(p);
|
||||
if (*p++ != ')') {
|
||||
cpu_error(2); /* missing closing parenthesis */
|
||||
return PO_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
p = skip(p);
|
||||
if (p-start < len)
|
||||
cpu_error(1); /* trailing garbage in operand */
|
||||
op->type = required;
|
||||
return PO_MATCH;
|
||||
}
|
||||
|
||||
|
||||
char *parse_cpu_special(char *start)
|
||||
{
|
||||
char *name=start,*s=start;
|
||||
|
||||
if (ISIDSTART(*s)) {
|
||||
s++;
|
||||
while (ISIDCHAR(*s))
|
||||
s++;
|
||||
|
||||
if (s-name==5 && !strnicmp(name,"setdp",5)) {
|
||||
s = skip(s);
|
||||
dpage = (utaddr)parse_constexpr(&s);
|
||||
eol(s) |