196 changed files with 61447 additions and 0 deletions
@ -0,0 +1,45 @@
|
||||
const char ADDR[] = {22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52}; |
||||
const char DATA[] = {39, 41, 43, 45, 47, 49, 51, 53}; |
||||
#define CLOCK 2 |
||||
#define READ_WRITE 3 |
||||
|
||||
void setup() { |
||||
for (int n = 0; n < 16; n += 1) { |
||||
pinMode(ADDR[n], INPUT); |
||||
} |
||||
for (int n = 0; n < 8; n += 1) { |
||||
pinMode(DATA[n], INPUT); |
||||
} |
||||
pinMode(CLOCK, INPUT); |
||||
pinMode(READ_WRITE, INPUT); |
||||
|
||||
attachInterrupt(digitalPinToInterrupt(CLOCK), onClock, RISING); |
||||
|
||||
Serial.begin(115200);sx |
||||
} |
||||
|
||||
void onClock() { |
||||
char output[15]; |
||||
|
||||
unsigned int address = 0; |
||||
for (int n = 0; n < 16; n += 1) { |
||||
int bit = digitalRead(ADDR[n]) ? 1 : 0; |
||||
Serial.print(bit); |
||||
address = (address << 1) + bit; |
||||
} |
||||
|
||||
Serial.print(" "); |
||||
|
||||
unsigned int data = 0; |
||||
for (int n = 0; n < 8; n += 1) { |
||||
int bit = digitalRead(DATA[n]) ? 1 : 0; |
||||
Serial.print(bit); |
||||
data = (data << 1) + bit; |
||||
} |
||||
|
||||
sprintf(output, " %04x %c %02x", address, digitalRead(READ_WRITE) ? 'r' : 'W', data); |
||||
Serial.println(output);
|
||||
} |
||||
|
||||
void loop() { |
||||
} |
@ -0,0 +1,168 @@
|
||||
PORTB = $6000 |
||||
PORTA = $6001 |
||||
DDRB = $6002 |
||||
DDRA = $6003 |
||||
|
||||
E = %10000000 |
||||
RW = %01000000 |
||||
RS = %00100000 |
||||
|
||||
.org $8000 |
||||
|
||||
reset: |
||||
lda #%11111111 ; Set all pins on port B to output
|
||||
sta DDRB |
||||
|
||||
lda #%11100000 ; Set top 3 pins on port A to output
|
||||
sta DDRA |
||||
|
||||
lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font
|
||||
sta PORTB |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
lda #E ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
|
||||
lda #%00001110 ; Display on; cursor on; blink off
|
||||
sta PORTB |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
lda #E ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
|
||||
lda #%00000110 ; Increment and shift cursor; don't shift display
|
||||
sta PORTB |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
lda #E ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #0 ; Clear RS/RW/E bits
|
||||
sta PORTA |
||||
|
||||
lda #"H" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"e" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"l" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"l" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"o" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"," |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #" " |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"w" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"o" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"r" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"l" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"d" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
lda #"!" |
||||
sta PORTB |
||||
lda #RS ; Set RS; Clear RW/E bits |
||||
sta PORTA |
||||
lda #(RS | E) ; Set E bit to send instruction |
||||
sta PORTA |
||||
lda #RS ; Clear E bits |
||||
sta PORTA |
||||
|
||||
loop: |
||||
jmp loop |
||||
|
||||
.org $fffc |
||||
.word reset
|
||||
.word $0000 |
@ -0,0 +1,25 @@
|
||||
# |
||||
# Please see this video for details: |
||||
# https://www.youtube.com/watch?v=yl8vPW5hydQ |
||||
# |
||||
code = bytearray([ |
||||
0xa9, 0xff, # lda #$ff # set output register B |
||||
0x8d, 0x02, 0x60, # sta $6002 |
||||
|
||||
0xa9, 0x00, # lda #$00 # Start at 0 |
||||
|
||||
0x8d, 0x00, 0x60, # sta $6000 # Latch out |
||||
0x69, 0x01, # add #$1 |
||||
|
||||
0x4c, 0x07, 0x80, # jmp $8005 # go back to first output |
||||
]) |
||||
|
||||
rom = code + bytearray([0xea] * (32768 - len(code))) |
||||
|
||||
|
||||
# Reset Vector |
||||
rom[0x7ffc] = 0x00 |
||||
rom[0x7ffd] = 0x80 |
||||
|
||||
with open("rom-counter.bin", "wb") as out_file: |
||||
out_file.write(rom) |
@ -0,0 +1,14 @@
|
||||
.org $8000 |
||||
reset:
|
||||
|
||||
lda $9000 |
||||
|
||||
|
||||
.org $9000 |
||||
.byte 18
|
||||
.byte 03
|
||||
.org $fffc |
||||
.word reset
|
||||
.word $0000 |
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
.org $8000 |
||||
reset:
|
||||
;; set output register
|
||||
lda #$ff |
||||
sta $6002 |
||||
|
||||
;; flash the lights
|
||||
;; lda #$50
|
||||
;; sta $6000
|
||||
|
||||
;; start at 0
|
||||
lda #$00
|
||||
|
||||
loop:
|
||||
sta $6000 |
||||
;; increment
|
||||
adc #$1 |
||||
|
||||
jmp loop |
||||
|
||||
|
||||
.org $fffc |
||||
.word reset
|
||||
.word $0000 |
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
.org $8000 |
||||
reset:
|
||||
|
||||
;; main program goes here
|
||||
|
||||
|
||||
.org $fffc |
||||
.word reset
|
||||
.word $0000 |
||||
|
||||
|
@ -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 |
@ -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 |
@ -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 -D_WIN32 $(OUTFMTS)
|
||||
|
||||
LD = $(CC)
|
||||
LDOUT = $(CCOUT)
|
||||
LDFLAGS = -lm
|
||||
|
||||
RM = rm -f
|
||||
|
||||
include make.rules |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 /Zp1 /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 |
@ -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 |
@ -0,0 +1,661 @@
|
||||
/* atom.c - atomic objects from source */ |
||||
/* (c) in 2010-2019 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(expr *offsexp,section *sec,taddr pc) |
||||
{ |
||||
taddr offs; |
||||
|
||||
eval_expr(offsexp,&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 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 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); |
||||
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; |
||||
} |
||||
|
||||
|
||||
static 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) |
||||
{ |
||||
atom *new = new_atom(ROFFS,1); |
||||
|
||||
new->content.roffs = offs; |
||||
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; |
||||
} |
@ -0,0 +1,145 @@
|
||||
/* atom.h - atomic objects from source */ |
||||
/* (c) in 2010-2019 by Volker Barthelmann and Frank Wille */ |
||||
|
||||
#ifndef ATOM_H |
||||
#define ATOM_H |
||||
|
||||
/* types of atoms */ |
||||
#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 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; |
||||
expr *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 *); |
||||
|
||||
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 *); |
||||